Update googleurl to the latest version from Chromium

Version used is cabce318aaa096f18dee72eb09b0bddf1565cd2b from
Tue Feb 22 09:08:34 2022 +0000.

Change-Id: Ia8646e29a6780b3d8f3dab275c2513e012b3546f
diff --git a/AUTHORS b/AUTHORS
index 012e246..364df55 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -47,6 +47,7 @@
 Alec Petridis <alecthechop@gmail.com>
 Aleksandar Stojiljkovic <aleksandar.stojiljkovic@intel.com>
 Aleksei Gurianov <gurianov@gmail.com>
+Alesandro Ortiz <alesandro@alesandroortiz.com>
 Alex Chronopoulos <achronop@gmail.com>
 Alex Gabriel <minilogo@gmail.com>
 Alex Gartrell <agartrell@cmu.edu>
@@ -88,10 +89,12 @@
 anatoly techtonik <techtonik@gmail.com>
 Ancil George <ancilgeorge@samsung.com>
 Andra Paraschiv <andra.paraschiv@intel.com>
+Andras Tokodi <a.tokodi@eyeo.com>
 Andreas Papacharalampous <andreas@apap04.com>
 Andrei Borza <andrei.borza@gmail.com>
 Andrei Parvu <andrei.prv@gmail.com>
 Andrei Parvu <parvu@adobe.com>
+Andres Salomon <dilinger@queued.net>
 Andreu Botella <andreu@andreubotella.com>
 Andrew Boyarshin <andrew.boyarshin@gmail.com>
 Andrew Brampton <me@bramp.net>
@@ -183,6 +186,7 @@
 Caio Marcelo de Oliveira Filho <caio.de.oliveira.filho@intel.com>
 Caitlin Potter <caitpotter88@gmail.com>
 Calvin Mei <calvimei@amazon.com>
+Calvin Watford <watfordcalvin@gmail.com>
 Cameron Gutman <aicommander@gmail.com>
 Camille Viot <viot.camille@outlook.com>
 Carlos Santa <carlos.santa@intel.com>
@@ -251,8 +255,10 @@
 Daniel Waxweiler <daniel.waxweiler@gmail.com>
 Dániel Bátyai <dbatyai@inf.u-szeged.hu>
 Dániel Vince <vinced@inf.u-szeged.hu>
+Daniil Suvorov <severecloud@gmail.com>
 Daoming Qiu <daoming.qiu@intel.com>
 Darik Harter <darik.harter@gmail.com>
+Darshan Sen <raisinten@gmail.com>
 Darshini KN <kn.darshini@samsung.com>
 Dave Vandyke <kzar@kzar.co.uk>
 David Benjamin <davidben@mit.edu>
@@ -342,6 +348,7 @@
 Fabien Tassin <fta@sofaraway.org>
 Felipe Erias Morandeira <felipeerias@gmail.com>
 Felix H. Dahlke <fhd@ubercode.de>
+Felix Weilbach <feweilbach@gmail.com>
 Fengrong Fang <fr.fang@samsung.com>
 Fernando Jiménez Moreno <ferjmoreno@gmail.com>
 Finbar Crago <finbar.crago@gmail.com>
@@ -408,6 +415,7 @@
 Heeyoun Lee <heeyoun.lee@samsung.com>
 Henrique Limas <henrique.ramos.limas@gmail.com>
 Himanshu Joshi <h.joshi@samsung.com>
+Hiroyuki Matsuda <gsittyz@gmail.com>
 Hodol Han <bab6ting@gmail.com>
 Holger Kraus <kraush@amazon.com>
 Hong Zheng <hong.zheng@intel.com>
@@ -476,6 +484,7 @@
 James Wei <james.wei@intel.com>
 James Willcox <jwillcox@litl.com>
 Jan Grulich <grulja@gmail.com>
+Jan Keitel <jan.keitel@gmail.com>
 Jan Rucka <ruckajan10@gmail.com>
 Jan Sauer <jan@jansauer.de>
 Janusz Majnert <jmajnert@gmail.com>
@@ -535,6 +544,7 @@
 Jinyoung Hur <hur.ims@navercorp.com>
 Jinyoung Hur <hurims@gmail.com>
 Jitendra Kumar Sahoo <jitendra.ks@samsung.com>
+Jitesh Pareek <j1.pareek@samsung.com>
 Joachim Bauch <jbauch@webrtc.org>
 Joachim Bauch <mail@joachim-bauch.de>
 Joanmarie Diggs <joanmarie.diggs@gmail.com>
@@ -553,6 +563,7 @@
 Jonathan Garbee <jonathan@garbee.me>
 Jonathan Hacker <jhacker@arcanefour.com>
 Jonathan Kingston <kingstonmailbox@gmail.com>
+Jonathan Shimonovich <jonathans@talon-sec.com>
 Jongdeok Kim <jongdeok.kim@navercorp.com>
 Jongheon Kim <sapzape@gmail.com>
 JongKwon Lee <jongkwon.lee@navercorp.com>
@@ -592,6 +603,7 @@
 Justin Okamoto <justmoto@amazon.com>
 Justin Ribeiro <justin@justinribeiro.com>
 Jüri Valdmann <juri.valdmann@qt.io>
+Juyoung Kim <chattank05@gmail.com>
 Kai Jiang <jiangkai@gmail.com>
 Kai Köhne <kai.koehne@qt.io>
 Kai Uwe Broulik <kde@privat.broulik.de>
@@ -610,6 +622,7 @@
 Kaustubh Atrawalkar <kaustubh.a@samsung.com>
 Kaustubh Atrawalkar <kaustubh.ra@gmail.com>
 Ke He <ke.he@intel.com>
+Keeley Hammond <vertedinde@electronjs.org>
 Keene Pan <keenepan@linpus.com>
 Keiichiro Nagashima <n4ag3a2sh1i@gmail.com>
 Keita Suzuki <keitasuzuki.park@gmail.com>
@@ -645,6 +658,7 @@
 Kui Tan <tk1061178@gmail.com>
 Kunal Thakar <kunalt@gmail.com>
 Kushal Pisavadia <kushi.p@gmail.com>
+Kwanghee Lee <ekwange@gmail.com>
 Kwangho Shin <k_h.shin@samsung.com>
 Kyle Nahrgang <kpn24@drexel.edu>
 Kyle Plumadore <kyle.plumadore@amd.com>
@@ -682,6 +696,7 @@
 Lorenzo Stoakes <lstoakes@gmail.com>
 Lu Guanqun <guanqun.lu@gmail.com>
 Luc Shi <lei.a.shi@intel.com>
+Luca Casonato <luccasonato@gmail.com>
 Luca Di Domenico <luca94dd@gmail.com>
 Lucie Brozkova <lucinka.brozkova@gmail.com>
 Luiz Von Dentz <luiz.von.dentz@intel.com>
@@ -790,6 +805,7 @@
 Miran Karic <miran.karic@imgtec.com>
 Mirela Budaes <mbudaes@adobe.com>
 Mirela Budaes <mbudaes@gmail.com>
+Mitchell Cohen <mitchell@agilebits.com>
 Miyoung Shin <myid.shin@navercorp.com>
 Mohamed I. Hammad <ibraaaa@gmail.com>
 Mohamed Mansour <m0.interactive@gmail.com>
@@ -797,6 +813,7 @@
 Mohammed Wajahat Ali Siddiqui <wajahat.s@samsung.com>
 Mohan Reddy <mohan.reddy@samsung.com>
 Mohit Bhalla <bhallam@amazon.com>
+Momoka Yamamoto <momoka.my6@gmail.com>
 Momoko Hattori <momohatt10@gmail.com>
 Mostafa Sedaghat joo <mostafa.sedaghat@gmail.com>
 Mrunal Kapade <mrunal.kapade@intel.com>
@@ -954,6 +971,7 @@
 Rosen Dash <rosen.dash@gmail.com>
 Ross Kirsling <rkirsling@gmail.com>
 Ross Wollman <ross.wollman@gmail.com>
+Roy Le <royle0502@gmail.com>
 Ruan Beihong <ruanbeihong@gmail.com>
 ruben <chromium@hybridsource.org>
 Ruben Bridgewater <ruben@bridgewater.de>
@@ -1013,6 +1031,7 @@
 Sergio Carlos Morales Angeles <carloschilazo@gmail.com>
 Sergio Garcia Murillo <sergio.garcia.murillo@gmail.com>
 Sergiy Belozorov <rryk.ua@gmail.com>
+Serhii Matrunchyk <sergiy.matrunchyk@gmail.com>
 Seshadri Mahalingam <seshadri.mahalingam@gmail.com>
 Seungkyu Lee <zx6658@gmail.com>
 Sevan Janiyan <venture37@geeklan.co.uk>
@@ -1100,6 +1119,7 @@
 Sylvestre Ledru <sylvestre.ledru@gmail.com>
 Synthia Islam <synthia.is@samsung.com>
 Szabolcs David <davidsz@inf.u-szeged.hu>
+Szilard Szaloki <szilardszaloki@gmail.com>
 Szymon Piechowicz <szymonpiechowicz@o2.pl>
 Taeheon Kim <skyrabbits1@gmail.com>
 Taeho Nam <thn7440@gmail.com>
@@ -1108,7 +1128,9 @@
 Taeyeon Kim <ssg9732@gmail.com>
 Tae Shin <taeshindev@gmail.com>
 Takaaki Suzuki <takaakisuzuki.14@gmail.com>
+Takahiro Aoyagi <hogehoge@gachapin.jp>
 Takashi Fujita <tgfjt.mail@gmail.com>
+Takashi Mima <tks.m1205@gmail.com>
 Takeshi Kurosawa <taken.spc@gmail.com>
 Tanay Chowdhury <tanay.c@samsung.com>
 Tanvir Rizvi <tanvir.rizvi@samsung.com>
@@ -1133,6 +1155,7 @@
 Timo Reimann <ttr314@googlemail.com>
 Timo Witte <timo.witte@gmail.com>
 Ting Shao <ting.shao@intel.com>
+Tobias Lippert <tobias.lippert@fastmail.com>
 Tobias Soppa <tobias@soppa.me>
 Tobias Soppa <tobias.soppa@code.berlin>
 Tom Callaway <tcallawa@redhat.com>
@@ -1150,6 +1173,7 @@
 U. Artie Eoff <ullysses.a.eoff@intel.com>
 Umar Hansa <umar.hansa@gmail.com>
 Upendra Gowda <upendrag.gowda@gmail.com>
+UwU UwU <uwu7586@gmail.com>
 Uzair Jaleel <uzair.jaleel@samsung.com>
 Vadim Gorbachev <bmsdave@gmail.com>
 Vaibhav Agrawal <vaibhav1.a@samsung.com>
@@ -1174,6 +1198,7 @@
 Vivek Galatage <vivek.vg@samsung.com>
 Volker Sorge <volker.sorge@gmail.com>
 Waihung Fu <fufranci@amazon.com>
+wafuwafu13 <mariobaske@i.softbank.jp>
 Wojciech Bielawski <wojciech.bielawski@gmail.com>
 Wanming Lin <wanming.lin@intel.com>
 Wei Li <wei.c.li@intel.com>
@@ -1186,6 +1211,7 @@
 Will Cohen <wwcohen@gmail.com>
 Will Hirsch <chromium@willhirsch.co.uk>
 Will Shackleton <w.shackleton@gmail.com>
+Will Watts <willwatts.ww@googlemail.com>
 William Xie <william.xie@intel.com>
 Winston Chen <winston.c1@samsung.com>
 Xiang Long <xiang.long@intel.com>
@@ -1239,7 +1265,9 @@
 Youngsun Suh <zard17@gmail.com>
 Yuan-Pin Yu <yjames@uber.com>
 Yuhong Sha <yuhong.sha@samsung.com>
+Yuki Osaki <yuki.osaki7@gmail.com>
 Yuki Tsuchiya <Yuki.Tsuchiya@sony.com>
+Yuma Takai <tara20070827@gmail.com>
 Yumikiyo Osanai <yumios.art@gmail.com>
 Yunchao He <yunchao.he@intel.com>
 Yupei Lin <yplam@yplam.com>
@@ -1251,6 +1279,7 @@
 Yuta Kasai <kasai.yuta0810@gmail.com>
 Yuvanesh Natarajan <yuvanesh.n1@samsung.com>
 Zach Bjornson <zbbjornson@gmail.com>
+Zachary Capalbo <zach.geek@gmail.com>
 Zeno Albisser <zeno.albisser@digia.com>
 Zeqin Chen <talonchen@tencent.com>
 Zhang Hao <15686357310a@gmail.com>
@@ -1267,6 +1296,7 @@
 Zoltan Czirkos <czirkos.zoltan@gmail.com>
 Zoltan Herczeg <zherczeg.u-szeged@partner.samsung.com>
 Zoltan Kuscsik <zoltan.kuscsik@linaro.org>
+Zoru Lee <donzoru@gmail.com>
 Zsolt Borbely <zsborbely.u-szeged@partner.samsung.com>
 方觉 (Fang Jue) <fangjue23303@gmail.com>
 迷渡 <justjavac@gmail.com>
@@ -1276,6 +1306,7 @@
 # BEGIN organizations section.
 Accenture <*@accenture.com>
 ACCESS CO., LTD. <*@access-company.com>
+Ada Logics Ltd. <*@adalogics.com>
 Akamai Inc. <*@akamai.com>
 ARM Holdings <*@arm.com>
 BlackBerry Limited <*@blackberry.com>
@@ -1318,11 +1349,13 @@
 Mozilla Corporation <*@mozilla.com>
 Neverware Inc. <*@neverware.com>
 NIKE, Inc. <*@nike.com>
+Nutanix Inc. <*nutanix.com>
 NVIDIA Corporation <*@nvidia.com>
 OpenFin Inc. <*@openfin.co>
 Opera Software ASA <*@opera.com>
 Optical Tone Ltd <*@opticaltone.com>
 Pengutronix e.K. <*@pengutronix.de>
+Quality First Software GmbH <*@qf-software.com>
 Rakuten Kobo Inc. <*@kobo.com>
 Rakuten Kobo Inc. <*@rakuten.com>
 Red Hat Inc. <*@redhat.com>
@@ -1332,15 +1365,18 @@
 Spotify AB <*@spotify.com>
 Synaptics <*@synaptics.com>
 Tableau Software <*@tableau.com>
+Talon Cyber Security Ltd. <*@talon-sec.com>
 TeamSpeak Systems GmbH <*@teamspeak.com>
 The Chromium Authors <*@chromium.org>
 The MathWorks, Inc. <binod.pant@mathworks.com>
+THEO Technologies <*@theoplayer.com>
 Torchmobile Inc.
 Upwork <*@cloud.upwork.com>
 Venture 3 Systems LLC <*@venture3systems.com>
 Vewd Software AS <*@vewd.com>
 Vivaldi Technologies AS <*@vivaldi.com>
 Wacom <*@wacom.com>
+Xperi Corporation <*@xperi.com>
 Yandex LLC <*@yandex-team.ru>
 # Please DO NOT APPEND here. See comments at the top of the file.
 # END organizations section.
diff --git a/base/BUILD b/base/BUILD
index e2da292..d31df3e 100644
--- a/base/BUILD
+++ b/base/BUILD
@@ -6,6 +6,14 @@
 
 cc_library(
     name = "base",
+    srcs = [
+        "debug/crash_logging.cc",
+        "strings/string_piece.cc",
+        "strings/string_util.cc",
+        "strings/string_util_constants.cc",
+        "strings/utf_string_conversion_utils.cc",
+        "strings/utf_string_conversions.cc",
+    ],
     hdrs = [
         "compiler_specific.h",
         "containers/checked_iterators.h",
@@ -15,22 +23,33 @@
         "containers/util.h",
         "cxx17_backports.h",
         "cxx20_to_address.h",
+        "debug/crash_logging.h",
         "debug/leak_annotations.h",
         "functional/identity.h",
         "functional/invoke.h",
         "functional/not_fn.h",
-        "macros.h",
+        "memory/raw_ptr.h",
         "no_destructor.h",
         "ranges/algorithm.h",
         "ranges/functional.h",
         "ranges/ranges.h",
         "stl_util.h",
         "template_util.h",
-    ],
+        "strings/char_traits.h",
+        "strings/string_piece_forward.h",
+        "strings/string_piece.h",
+        "strings/string_util.h",
+        "strings/string_util_internal.h",
+        "strings/string_number_conversions.h",
+        "strings/utf_string_conversions.h",
+        "strings/utf_string_conversion_utils.h",
+    ] + build_config.strings_hdrs,
     copts = build_config.default_copts,
     visibility = ["//visibility:public"],
     deps = [
+        "//base/third_party/icu",
         "//build:build_config",
+        "//build:buildflag",
         "//polyfills",
         "@com_google_absl//absl/types:optional",
     ],
diff --git a/base/compiler_specific.h b/base/compiler_specific.h
index 58a7d0d..3a85453 100644
--- a/base/compiler_specific.h
+++ b/base/compiler_specific.h
@@ -31,23 +31,6 @@
 #define HAS_BUILTIN(x) 0
 #endif
 
-// Annotate a variable indicating it's ok if the variable is not used.
-// (Typically used to silence a compiler warning when the assignment
-// is important for some other reason.)
-// Use like:
-//   int x = ...;
-//   ALLOW_UNUSED_LOCAL(x);
-#define ALLOW_UNUSED_LOCAL(x) (void)x
-
-// Annotate a typedef or function indicating it's ok if it's not used.
-// Use like:
-//   typedef Foo Bar ALLOW_UNUSED_TYPE;
-#if defined(COMPILER_GCC) || defined(__clang__)
-#define ALLOW_UNUSED_TYPE __attribute__((unused))
-#else
-#define ALLOW_UNUSED_TYPE
-#endif
-
 // Annotate a function indicating it should not be inlined.
 // Use like:
 //   NOINLINE void DoStuff() { ... }
@@ -108,17 +91,6 @@
 #define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
 #endif
 
-// Annotate a function indicating the caller must examine the return value.
-// Use like:
-//   int foo() WARN_UNUSED_RESULT;
-// To explicitly ignore a result, see |ignore_result()| in base/macros.h.
-#undef WARN_UNUSED_RESULT
-#if defined(COMPILER_GCC) || defined(__clang__)
-#define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
-#else
-#define WARN_UNUSED_RESULT
-#endif
-
 // In case the compiler supports it NO_UNIQUE_ADDRESS evaluates to the C++20
 // attribute [[no_unique_address]]. This allows annotating data members so that
 // they need not have an address distinct from all other non-static data members
@@ -164,7 +136,7 @@
 #endif
 
 // MemorySanitizer annotations.
-#if defined(MEMORY_SANITIZER) && !defined(OS_NACL)
+#if defined(MEMORY_SANITIZER) && !BUILDFLAG(IS_NACL)
 #include <sanitizer/msan_interface.h>
 
 // Mark a memory region fully initialized.
@@ -194,7 +166,7 @@
 
 // DISABLE_CFI_ICALL -- Disable Control Flow Integrity indirect call checks.
 #if !defined(DISABLE_CFI_ICALL)
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 // Windows also needs __declspec(guard(nocf)).
 #define DISABLE_CFI_ICALL NO_SANITIZE("cfi-icall") __declspec(guard(nocf))
 #else
@@ -207,11 +179,11 @@
 
 // Macro useful for writing cross-platform function pointers.
 #if !defined(CDECL)
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 #define CDECL __cdecl
-#else  // defined(OS_WIN)
+#else  // BUILDFLAG(IS_WIN)
 #define CDECL
-#endif  // defined(OS_WIN)
+#endif  // BUILDFLAG(IS_WIN)
 #endif  // !defined(CDECL)
 
 // Macro for hinting that an expression is likely to be false.
@@ -239,13 +211,6 @@
 #define HAS_FEATURE(FEATURE) 0
 #endif
 
-// Macro for telling -Wimplicit-fallthrough that a fallthrough is intentional.
-#if defined(__clang__)
-#define FALLTHROUGH [[clang::fallthrough]]
-#else
-#define FALLTHROUGH
-#endif
-
 #if defined(COMPILER_GCC)
 #define PRETTY_FUNCTION __PRETTY_FUNCTION__
 #elif defined(COMPILER_MSVC)
@@ -354,13 +319,11 @@
 
 #define ANALYZER_ASSUME_TRUE(arg) ::AnalyzerAssumeTrue(!!(arg))
 #define ANALYZER_SKIP_THIS_PATH() static_cast<void>(::AnalyzerNoReturn())
-#define ANALYZER_ALLOW_UNUSED(var) static_cast<void>(var);
 
 #else  // !defined(__clang_analyzer__)
 
 #define ANALYZER_ASSUME_TRUE(arg) (arg)
 #define ANALYZER_SKIP_THIS_PATH()
-#define ANALYZER_ALLOW_UNUSED(var) static_cast<void>(var);
 
 #endif  // defined(__clang_analyzer__)
 
@@ -419,4 +382,12 @@
 #define CONSTINIT
 #endif
 
+#if defined(__clang__)
+#define GSL_OWNER [[gsl::Owner]]
+#define GSL_POINTER [[gsl::Pointer]]
+#else
+#define GSL_OWNER
+#define GSL_POINTER
+#endif
+
 #endif  // BASE_COMPILER_SPECIFIC_H_
diff --git a/base/containers/checked_iterators.h b/base/containers/checked_iterators.h
index b5fe925..c4e1e69 100644
--- a/base/containers/checked_iterators.h
+++ b/base/containers/checked_iterators.h
@@ -30,7 +30,7 @@
 
   // Required for certain libc++ algorithm optimizations that are not available
   // for NaCl.
-#if defined(_LIBCPP_VERSION) && !defined(OS_NACL)
+#if defined(_LIBCPP_VERSION) && !BUILDFLAG(IS_NACL)
   template <typename Ptr>
   friend struct std::pointer_traits;
 #endif
@@ -185,10 +185,10 @@
     return current_[rhs];
   }
 
-  static bool IsRangeMoveSafe(const CheckedContiguousIterator& from_begin,
-                              const CheckedContiguousIterator& from_end,
-                              const CheckedContiguousIterator& to)
-      WARN_UNUSED_RESULT {
+  [[nodiscard]] static bool IsRangeMoveSafe(
+      const CheckedContiguousIterator& from_begin,
+      const CheckedContiguousIterator& from_end,
+      const CheckedContiguousIterator& to) {
     if (from_end < from_begin)
       return false;
     const auto from_begin_uintptr = get_uintptr(from_begin.current_);
@@ -217,7 +217,7 @@
 
 }  // namespace base
 
-#if defined(_LIBCPP_VERSION) && !defined(OS_NACL)
+#if defined(_LIBCPP_VERSION) && !BUILDFLAG(IS_NACL)
 // Specialize both std::__is_cpp17_contiguous_iterator and std::pointer_traits
 // for CCI in case we compile with libc++ outside of NaCl. The former is
 // required to enable certain algorithm optimizations (e.g. std::copy can be a
diff --git a/base/containers/span.h b/base/containers/span.h
index 550eec8..1ba60b1 100644
--- a/base/containers/span.h
+++ b/base/containers/span.h
@@ -15,6 +15,7 @@
 #include <utility>
 
 #include "polyfills/base/check_op.h"
+#include "base/compiler_specific.h"
 #include "base/containers/checked_iterators.h"
 #include "base/containers/contiguous_iterator.h"
 #include "base/cxx17_backports.h"
@@ -225,10 +226,6 @@
 //   sized container (e.g. std::vector) requires an explicit conversion (in the
 //   C++20 draft this is simply UB)
 //
-// Differences from [span.obs]:
-// - empty() is marked with WARN_UNUSED_RESULT instead of [[nodiscard]]
-//   ([[nodiscard]] is a C++17 feature)
-//
 // Furthermore, all constructors and methods are marked noexcept due to the lack
 // of exceptions in Chromium.
 //
@@ -237,7 +234,7 @@
 
 // [span], class template span
 template <typename T, size_t Extent>
-class span : public internal::ExtentStorage<Extent> {
+class GSL_POINTER span : public internal::ExtentStorage<Extent> {
  private:
   using ExtentStorage = internal::ExtentStorage<Extent>;
 
@@ -408,9 +405,7 @@
   // [span.obs], span observers
   constexpr size_t size() const noexcept { return ExtentStorage::size(); }
   constexpr size_t size_bytes() const noexcept { return size() * sizeof(T); }
-  constexpr bool empty() const noexcept WARN_UNUSED_RESULT {
-    return size() == 0;
-  }
+  [[nodiscard]] constexpr bool empty() const noexcept { return size() == 0; }
 
   // [span.elem], span element access
   constexpr T& operator[](size_t idx) const noexcept {
diff --git a/base/debug/crash_logging.cc b/base/debug/crash_logging.cc
new file mode 100644
index 0000000..f6bad4f
--- /dev/null
+++ b/base/debug/crash_logging.cc
@@ -0,0 +1,64 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/crash_logging.h"
+
+namespace gurl_base {
+namespace debug {
+
+namespace {
+
+CrashKeyImplementation* g_crash_key_impl = nullptr;
+
+}  // namespace
+
+CrashKeyString* AllocateCrashKeyString(const char name[],
+                                       CrashKeySize value_length) {
+  if (!g_crash_key_impl)
+    return nullptr;
+
+  return g_crash_key_impl->Allocate(name, value_length);
+}
+
+void SetCrashKeyString(CrashKeyString* crash_key, gurl_base::StringPiece value) {
+  if (!g_crash_key_impl || !crash_key)
+    return;
+
+  g_crash_key_impl->Set(crash_key, value);
+}
+
+void ClearCrashKeyString(CrashKeyString* crash_key) {
+  if (!g_crash_key_impl || !crash_key)
+    return;
+
+  g_crash_key_impl->Clear(crash_key);
+}
+
+BASE_EXPORT void OutputCrashKeysToStream(std::ostream& out) {
+  if (!g_crash_key_impl)
+    return;
+
+  g_crash_key_impl->OutputCrashKeysToStream(out);
+}
+
+ScopedCrashKeyString::ScopedCrashKeyString(CrashKeyString* crash_key,
+                                           gurl_base::StringPiece value)
+    : crash_key_(crash_key) {
+  SetCrashKeyString(crash_key_, value);
+}
+
+ScopedCrashKeyString::ScopedCrashKeyString(ScopedCrashKeyString&& other)
+    : crash_key_(std::exchange(other.crash_key_, nullptr)) {}
+
+ScopedCrashKeyString::~ScopedCrashKeyString() {
+  ClearCrashKeyString(crash_key_);
+}
+
+void SetCrashKeyImplementation(std::unique_ptr<CrashKeyImplementation> impl) {
+  delete g_crash_key_impl;
+  g_crash_key_impl = impl.release();
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/crash_logging.h b/base/debug/crash_logging.h
new file mode 100644
index 0000000..fdc5343
--- /dev/null
+++ b/base/debug/crash_logging.h
@@ -0,0 +1,204 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_DEBUG_CRASH_LOGGING_H_
+#define BASE_DEBUG_CRASH_LOGGING_H_
+
+#include <stddef.h>
+
+#include <iosfwd>
+#include <memory>
+#include <type_traits>
+
+#include "polyfills/base/base_export.h"
+#include "base/cxx17_backports.h"
+#include "base/memory/raw_ptr.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
+
+namespace gurl_base {
+namespace debug {
+
+// A crash key is an annotation that is carried along with a crash report, to
+// provide additional debugging information beyond a stack trace. Crash keys
+// have a name and a string value.
+//
+// The preferred API is //components/crash/core/common:crash_key, however not
+// all clients can hold a direct dependency on that target. The API provided
+// in this file indirects the dependency and adds some convenience helpers that
+// make the API a bit less clunky.
+//
+// TODO(dcheng): Some of the nicer APIs should probably be upstreamed into
+// //components/crash.
+//
+// Preferred usage when a crash key value only needs to be set within a scope:
+//
+//   SCOPED_CRASH_KEY_STRING32("category", "name", "value");
+//   gurl_base::debug::DumpWithoutCrashing();
+//
+// If the crash key is pre-allocated elsewhere, but the value only needs to be
+// set within a scope:
+//
+//   gurl_base::debug::ScopedCrashKeyString scoper(
+//       GetCrashKeyForComponent(),
+//       "value");
+//
+// Otherwise, if the crash key needs to persist (e.g. the actual crash dump is
+// triggered some time later asynchronously):
+//
+//   static auto* const crash_key = gurl_base::debug::AllocateCrashKeyString(
+//       "name", gurl_base::debug::CrashKeySize::Size32);
+//   gurl_base::debug::SetCrashKeyString(crash_key);
+//
+//   // Do other work before calling `gurl_base::debug::DumpWithoutCrashing()` later.
+//
+// ***WARNING***
+//
+// Do *not* write this:
+//
+//   gurl_base::debug::SetCrashKeyString(
+//       gurl_base::debug::AllocateCrashKeyString(
+//           "name", gurl_base::debug::CrashKeySize::Size32),
+//       "value");
+//
+// As this will leak a heap allocation every time the crash key is set!
+
+// The maximum length for a crash key's value must be one of the following
+// pre-determined values.
+enum class CrashKeySize {
+  Size32 = 32,
+  Size64 = 64,
+  Size256 = 256,
+};
+
+struct CrashKeyString;
+
+// Allocates a new crash key with the specified |name| with storage for a
+// value up to length |size|. This will return null if the crash key system is
+// not initialized.
+//
+// Note: this internally allocates, so the returned pointer should always
+// be cached in a variable with static storage duration, e.g.:
+//   static auto* const crash_key = gurl_base::debug::AllocateCrashKeyString(...);
+BASE_EXPORT CrashKeyString* AllocateCrashKeyString(const char name[],
+                                                   CrashKeySize size);
+
+// Stores |value| into the specified |crash_key|. The |crash_key| may be null
+// if AllocateCrashKeyString() returned null. If |value| is longer than the
+// size with which the key was allocated, it will be truncated.
+BASE_EXPORT void SetCrashKeyString(CrashKeyString* crash_key,
+                                   gurl_base::StringPiece value);
+
+// Clears any value that was stored in |crash_key|. The |crash_key| may be
+// null.
+BASE_EXPORT void ClearCrashKeyString(CrashKeyString* crash_key);
+
+// Outputs current (i.e. allocated and non-empty) crash keys to `out`.
+BASE_EXPORT void OutputCrashKeysToStream(std::ostream& out);
+
+// A scoper that sets the specified key to value for the lifetime of the
+// object, and clears it on destruction.
+class BASE_EXPORT ScopedCrashKeyString {
+ public:
+  ScopedCrashKeyString(CrashKeyString* crash_key, gurl_base::StringPiece value);
+  ScopedCrashKeyString(ScopedCrashKeyString&& other);
+  ~ScopedCrashKeyString();
+
+  // Disallow copy and assign.
+  ScopedCrashKeyString(const ScopedCrashKeyString&) = delete;
+  ScopedCrashKeyString& operator=(const ScopedCrashKeyString&) = delete;
+
+  // Disallow move assign to keep the time at which the crash key is cleared
+  // easy to reason about. Assigning over an existing instance would
+  // automatically clear the key instead of at the destruction of the object.
+  ScopedCrashKeyString& operator=(ScopedCrashKeyString&&) = delete;
+
+ private:
+  raw_ptr<CrashKeyString> crash_key_;
+};
+
+// Internal helpers for the SCOPED_CRASH_KEY_... helper macros defined below.
+//
+// The static_assert that checks the length of |key_name| is a compile-time
+// equivalent of the GURL_DCHECK in crash_reporter::internal::CrashKeyStringImpl::Set
+// that restricts the name of a crash key to 40 characters.
+#define SCOPED_CRASH_KEY_STRING_INTERNAL2(category, name, nonce, data,  \
+                                          key_size)                     \
+  static_assert(::gurl_base::size(category "-" name) < 40,                   \
+                "Crash key names must be shorter than 40 characters."); \
+  ::gurl_base::debug::ScopedCrashKeyString scoped_crash_key_helper##nonce(   \
+      [] {                                                              \
+        static auto* const key = ::gurl_base::debug::AllocateCrashKeyString( \
+            category "-" name, key_size);                               \
+        return key;                                                     \
+      }(),                                                              \
+      (data))
+
+// This indirection is needed to expand __COUNTER__.
+#define SCOPED_CRASH_KEY_STRING_INTERNAL(category, name, nonce, data, \
+                                         key_size)                    \
+  SCOPED_CRASH_KEY_STRING_INTERNAL2(category, name, nonce, data, key_size)
+
+// Helper macros for putting a local variable crash key on the stack before
+// causing a crash or calling CrashWithoutDumping(). `category` and `name`
+// should be string literals.
+//
+//   SCOPED_CRASH_KEY_STRING32("MyCategory", "key_name", "value");
+//
+// will set the crash key annotation named "MyCategory-key_name" to "value"
+// while in scope.
+#define SCOPED_CRASH_KEY_STRING32(category, name, data)                 \
+  SCOPED_CRASH_KEY_STRING_INTERNAL(category, name, __COUNTER__, (data), \
+                                   ::gurl_base::debug::CrashKeySize::Size32)
+
+#define SCOPED_CRASH_KEY_STRING64(category, name, data)                 \
+  SCOPED_CRASH_KEY_STRING_INTERNAL(category, name, __COUNTER__, (data), \
+                                   ::gurl_base::debug::CrashKeySize::Size64)
+
+#define SCOPED_CRASH_KEY_STRING256(category, name, data)                \
+  SCOPED_CRASH_KEY_STRING_INTERNAL(category, name, __COUNTER__, (data), \
+                                   ::gurl_base::debug::CrashKeySize::Size256)
+
+#define SCOPED_CRASH_KEY_BOOL(category, name, data)                       \
+  static_assert(std::is_same<std::decay_t<decltype(data)>, bool>::value,  \
+                "SCOPED_CRASH_KEY_BOOL must be passed a boolean value."); \
+  SCOPED_CRASH_KEY_STRING32(category, name, (data) ? "true" : "false")
+
+#define SCOPED_CRASH_KEY_NUMBER(category, name, data) \
+  SCOPED_CRASH_KEY_STRING32(category, name, ::gurl_base::NumberToString(data))
+
+////////////////////////////////////////////////////////////////////////////////
+// The following declarations are used to initialize the crash key system
+// in //base by providing implementations for the above functions.
+
+// The virtual interface that provides the implementation for the crash key
+// API. This is implemented by a higher-layer component, and the instance is
+// set using the function below.
+class CrashKeyImplementation {
+ public:
+  virtual ~CrashKeyImplementation() = default;
+
+  virtual CrashKeyString* Allocate(const char name[], CrashKeySize size) = 0;
+  virtual void Set(CrashKeyString* crash_key, gurl_base::StringPiece value) = 0;
+  virtual void Clear(CrashKeyString* crash_key) = 0;
+  virtual void OutputCrashKeysToStream(std::ostream& out) = 0;
+};
+
+// Initializes the crash key system in base by replacing the existing
+// implementation, if it exists, with |impl|. The |impl| is copied into base.
+BASE_EXPORT void SetCrashKeyImplementation(
+    std::unique_ptr<CrashKeyImplementation> impl);
+
+// The base structure for a crash key, storing the allocation metadata.
+struct CrashKeyString {
+  constexpr CrashKeyString(const char name[], CrashKeySize size)
+      : name(name), size(size) {}
+  const char* const name;
+  const CrashKeySize size;
+};
+
+}  // namespace debug
+}  // namespace base
+
+#endif  // BASE_DEBUG_CRASH_LOGGING_H_
diff --git a/base/debug/leak_annotations.h b/base/debug/leak_annotations.h
index b551552..89f47f4 100644
--- a/base/debug/leak_annotations.h
+++ b/base/debug/leak_annotations.h
@@ -18,7 +18,7 @@
 // ANNOTATE_LEAKING_OBJECT_PTR(X): the heap object referenced by pointer X will
 // be annotated as a leak.
 
-#if defined(LEAK_SANITIZER) && !defined(OS_NACL)
+#if defined(LEAK_SANITIZER) && !BUILDFLAG(IS_NACL)
 
 #include <sanitizer/lsan_interface.h>
 
diff --git a/base/macros.h b/base/macros.h
deleted file mode 100644
index 19d15ca..0000000
--- a/base/macros.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// This file contains macros and macro-like constructs (e.g., templates) that
-// are commonly used throughout Chromium source. (It may also contain things
-// that are closely related to things that are commonly used that belong in this
-// file.)
-
-#ifndef BASE_MACROS_H_
-#define BASE_MACROS_H_
-
-// ALL DISALLOW_xxx MACROS ARE DEPRECATED; DO NOT USE IN NEW CODE.
-// Use explicit deletions instead.  See the section on copyability/movability in
-// //styleguide/c++/c++-dos-and-donts.md for more information.
-
-// DEPRECATED: See above. Makes a class uncopyable.
-#define DISALLOW_COPY(TypeName) \
-  TypeName(const TypeName&) = delete
-
-// DEPRECATED: See above. Makes a class unassignable.
-#define DISALLOW_ASSIGN(TypeName) TypeName& operator=(const TypeName&) = delete
-
-// DEPRECATED: See above. Makes a class uncopyable and unassignable.
-#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
-  DISALLOW_COPY(TypeName);                 \
-  DISALLOW_ASSIGN(TypeName)
-
-// DEPRECATED: See above. Disallow all implicit constructors, namely the
-// default constructor, copy constructor and operator= functions.
-#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
-  TypeName() = delete;                           \
-  DISALLOW_COPY_AND_ASSIGN(TypeName)
-
-// Used to explicitly mark the return value of a function as unused. If you are
-// really sure you don't want to do anything with the return value of a function
-// that has been marked WARN_UNUSED_RESULT, wrap it with this. Example:
-//
-//   std::unique_ptr<MyType> my_var = ...;
-//   if (TakeOwnership(my_var.get()) == SUCCESS)
-//     ignore_result(my_var.release());
-//
-template<typename T>
-inline void ignore_result(const T&) {
-}
-
-#endif  // BASE_MACROS_H_
diff --git a/base/memory/raw_ptr.h b/base/memory/raw_ptr.h
new file mode 100644
index 0000000..379c0d8
--- /dev/null
+++ b/base/memory/raw_ptr.h
@@ -0,0 +1,910 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_RAW_PTR_H_
+#define BASE_MEMORY_RAW_PTR_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <cstddef>
+#include <functional>
+#include <type_traits>
+#include <utility>
+
+#include "polyfills/base/allocator/buildflags.h"
+#include "polyfills/base/check.h"
+#include "base/compiler_specific.h"
+#include "polyfills/base/dcheck_is_on.h"
+#include "build/build_config.h"
+#include "build/buildflag.h"
+
+#if BUILDFLAG(USE_BACKUP_REF_PTR)
+// USE_BACKUP_REF_PTR implies USE_PARTITION_ALLOC, needed for code under
+// allocator/partition_allocator/ to be built.
+#include "base/allocator/partition_allocator/address_pool_manager_bitmap.h"
+#include "base/allocator/partition_allocator/partition_address_space.h"
+#include "base/allocator/partition_allocator/partition_alloc_config.h"
+#include "base/allocator/partition_allocator/partition_alloc_constants.h"
+#include "polyfills/base/base_export.h"
+#endif  // BUILDFLAG(USE_BACKUP_REF_PTR)
+
+#if BUILDFLAG(IS_WIN)
+#include "base/win/windows_types.h"
+#endif
+
+// Marks a field as excluded from the raw_ptr usage enforcement clang plugin.
+// Example: RAW_PTR_EXCLUSION Foo* foo_;
+#define RAW_PTR_EXCLUSION __attribute__((annotate("raw_ptr_exclusion")))
+
+namespace cc {
+class Scheduler;
+}
+namespace gurl_base::internal {
+class DelayTimerBase;
+}
+namespace content::responsiveness {
+class Calculator;
+}
+
+namespace gurl_base {
+
+// NOTE: All methods should be `ALWAYS_INLINE NO_STACK_PROTECTOR`.
+// ALWAYS_INLINE: raw_ptr is meant to be a lightweight replacement of a raw
+// pointer, hence performance is critical.
+// NO_STACK_PROTECTOR: This annotation is required to avoid failures when a
+// raw_ptr is inside a NO_STACK_PROTECTOR function.
+// TODO(https://crbug.com/1274129): Remove NO_STACK_PROTECTOR.
+#define RAW_PTR_FUNC_ATTRIBUTES ALWAYS_INLINE NO_STACK_PROTECTOR
+
+namespace internal {
+// These classes/structures are part of the raw_ptr implementation.
+// DO NOT USE THESE CLASSES DIRECTLY YOURSELF.
+
+struct RawPtrNoOpImpl {
+  // Wraps a pointer.
+  template <typename T>
+  static RAW_PTR_FUNC_ATTRIBUTES T* WrapRawPtr(T* ptr) {
+    return ptr;
+  }
+
+  // Notifies the allocator when a wrapped pointer is being removed or replaced.
+  template <typename T>
+  static RAW_PTR_FUNC_ATTRIBUTES void ReleaseWrappedPtr(T*) {}
+
+  // Unwraps the pointer, while asserting that memory hasn't been freed. The
+  // function is allowed to crash on nullptr.
+  template <typename T>
+  static RAW_PTR_FUNC_ATTRIBUTES T* SafelyUnwrapPtrForDereference(
+      T* wrapped_ptr) {
+    return wrapped_ptr;
+  }
+
+  // Unwraps the pointer, while asserting that memory hasn't been freed. The
+  // function must handle nullptr gracefully.
+  template <typename T>
+  static RAW_PTR_FUNC_ATTRIBUTES T* SafelyUnwrapPtrForExtraction(
+      T* wrapped_ptr) {
+    return wrapped_ptr;
+  }
+
+  // Unwraps the pointer, without making an assertion on whether memory was
+  // freed or not.
+  template <typename T>
+  static RAW_PTR_FUNC_ATTRIBUTES T* UnsafelyUnwrapPtrForComparison(
+      T* wrapped_ptr) {
+    return wrapped_ptr;
+  }
+
+  // Upcasts the wrapped pointer.
+  template <typename To, typename From>
+  static RAW_PTR_FUNC_ATTRIBUTES constexpr To* Upcast(From* wrapped_ptr) {
+    static_assert(std::is_convertible<From*, To*>::value,
+                  "From must be convertible to To.");
+    // Note, this cast may change the address if upcasting to base that lies in
+    // the middle of the derived object.
+    return wrapped_ptr;
+  }
+
+  // Advance the wrapped pointer by |delta| bytes.
+  template <typename T>
+  static RAW_PTR_FUNC_ATTRIBUTES T* Advance(T* wrapped_ptr,
+                                            ptrdiff_t delta_elems) {
+    return wrapped_ptr + delta_elems;
+  }
+
+  // Returns a copy of a wrapped pointer, without making an assertion on whether
+  // memory was freed or not.
+  template <typename T>
+  static RAW_PTR_FUNC_ATTRIBUTES T* Duplicate(T* wrapped_ptr) {
+    return wrapped_ptr;
+  }
+
+  // This is for accounting only, used by unit tests.
+  static RAW_PTR_FUNC_ATTRIBUTES void IncrementSwapCountForTest() {}
+  static RAW_PTR_FUNC_ATTRIBUTES void
+  IncrementPointerToMemberOperatorCountForTest() {}
+};
+
+#if BUILDFLAG(USE_BACKUP_REF_PTR)
+
+#if GURL_DCHECK_IS_ON() || BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS)
+BASE_EXPORT void CheckThatAddressIsntWithinFirstPartitionPage(
+    uintptr_t address);
+#endif
+
+struct BackupRefPtrImpl {
+  // Note that `BackupRefPtrImpl` itself is not thread-safe. If multiple threads
+  // modify the same smart pointer object without synchronization, a data race
+  // will occur.
+
+  static RAW_PTR_FUNC_ATTRIBUTES bool IsSupportedAndNotNull(uintptr_t address) {
+    // This covers the nullptr case, as address 0 is never in GigaCage.
+    bool is_in_brp_pool = IsManagedByPartitionAllocBRPPool(address);
+
+    // There are many situations where the compiler can prove that
+    // ReleaseWrappedPtr is called on a value that is always nullptr, but the
+    // way the check above is written, the compiler can't prove that nullptr is
+    // not managed by PartitionAlloc; and so the compiler has to emit a useless
+    // check and dead code.
+    // To avoid that without making the runtime check slower, explicitly promise
+    // to the compiler that is_in_brp_pool will always be false for nullptr.
+    //
+    // This condition would look nicer and might also theoretically be nicer for
+    // the optimizer if it was written as "if (!address) { ... }", but
+    // LLVM currently has issues with optimizing that away properly; see:
+    // https://bugs.llvm.org/show_bug.cgi?id=49403
+    // https://reviews.llvm.org/D97848
+    // https://chromium-review.googlesource.com/c/chromium/src/+/2727400/2/base/memory/checked_ptr.h#120
+#if GURL_DCHECK_IS_ON() || BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS)
+    GURL_CHECK(address || !is_in_brp_pool);
+#endif
+#if HAS_BUILTIN(__builtin_assume)
+    __builtin_assume(address || !is_in_brp_pool);
+#endif
+
+    // There may be pointers immediately after the allocation, e.g.
+    //   {
+    //     // Assume this allocation happens outside of PartitionAlloc.
+    //     raw_ptr<T> ptr = new T[20];
+    //     for (size_t i = 0; i < 20; i ++) { ptr++; }
+    //   }
+    //
+    // Such pointers are *not* at risk of accidentally falling into BRP pool,
+    // because:
+    // 1) On 64-bit systems, BRP pool is preceded by a forbidden region.
+    // 2) On 32-bit systems, the guard pages and metadata of super pages in BRP
+    //    pool aren't considered to be part of that pool.
+    //
+    // This allows us to make a stronger assertion that if
+    // IsManagedByPartitionAllocBRPPool returns true for a valid pointer,
+    // it must be at least partition page away from the beginning of a super
+    // page.
+#if GURL_DCHECK_IS_ON() || BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS)
+    if (is_in_brp_pool) {
+      CheckThatAddressIsntWithinFirstPartitionPage(address);
+    }
+#endif
+
+    return is_in_brp_pool;
+  }
+
+  // Wraps a pointer.
+  template <typename T>
+  static RAW_PTR_FUNC_ATTRIBUTES T* WrapRawPtr(T* ptr) {
+    uintptr_t address = reinterpret_cast<uintptr_t>(ptr);
+    if (IsSupportedAndNotNull(address)) {
+#if GURL_DCHECK_IS_ON() || BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS)
+      GURL_CHECK(ptr != nullptr);
+#endif
+      AcquireInternal(address);
+    }
+#if !defined(PA_HAS_64_BITS_POINTERS)
+    else {
+      AddressPoolManagerBitmap::BanSuperPageFromBRPPool(address);
+    }
+#endif
+
+    return ptr;
+  }
+
+  // Notifies the allocator when a wrapped pointer is being removed or replaced.
+  template <typename T>
+  static RAW_PTR_FUNC_ATTRIBUTES void ReleaseWrappedPtr(T* wrapped_ptr) {
+    uintptr_t address = reinterpret_cast<uintptr_t>(wrapped_ptr);
+    if (IsSupportedAndNotNull(address)) {
+#if GURL_DCHECK_IS_ON() || BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS)
+      GURL_CHECK(wrapped_ptr != nullptr);
+#endif
+      ReleaseInternal(address);
+    }
+    // We are unable to counteract BanSuperPageFromBRPPool(), called from
+    // WrapRawPtr(). We only use one bit per super-page and, thus can't tell if
+    // there's more than one associated raw_ptr<T> at a given time. The risk of
+    // exhausting the entire address space is minuscule, therefore, we couldn't
+    // resist the perf gain of a single relaxed store (in the above mentioned
+    // function) over much more expensive two CAS operations, which we'd have to
+    // use if we were to un-ban a super-page.
+  }
+
+  // Unwraps the pointer, while asserting that memory hasn't been freed. The
+  // function is allowed to crash on nullptr.
+  template <typename T>
+  static RAW_PTR_FUNC_ATTRIBUTES T* SafelyUnwrapPtrForDereference(
+      T* wrapped_ptr) {
+#if GURL_DCHECK_IS_ON() || BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS)
+    uintptr_t address = reinterpret_cast<uintptr_t>(wrapped_ptr);
+    if (IsSupportedAndNotNull(address)) {
+      GURL_CHECK(wrapped_ptr != nullptr);
+      GURL_CHECK(IsPointeeAlive(address));
+    }
+#endif
+    return wrapped_ptr;
+  }
+
+  // Unwraps the pointer, while asserting that memory hasn't been freed. The
+  // function must handle nullptr gracefully.
+  template <typename T>
+  static RAW_PTR_FUNC_ATTRIBUTES T* SafelyUnwrapPtrForExtraction(
+      T* wrapped_ptr) {
+    return wrapped_ptr;
+  }
+
+  // Unwraps the pointer, without making an assertion on whether memory was
+  // freed or not.
+  template <typename T>
+  static RAW_PTR_FUNC_ATTRIBUTES T* UnsafelyUnwrapPtrForComparison(
+      T* wrapped_ptr) {
+    return wrapped_ptr;
+  }
+
+  // Upcasts the wrapped pointer.
+  template <typename To, typename From>
+  static RAW_PTR_FUNC_ATTRIBUTES constexpr To* Upcast(From* wrapped_ptr) {
+    static_assert(std::is_convertible<From*, To*>::value,
+                  "From must be convertible to To.");
+    // Note, this cast may change the address if upcasting to base that lies in
+    // the middle of the derived object.
+    return wrapped_ptr;
+  }
+
+  // Advance the wrapped pointer by |delta| bytes.
+  template <typename T>
+  static RAW_PTR_FUNC_ATTRIBUTES T* Advance(T* wrapped_ptr,
+                                            ptrdiff_t delta_elem) {
+#if GURL_DCHECK_IS_ON() || BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS)
+    uintptr_t address = reinterpret_cast<uintptr_t>(wrapped_ptr);
+    if (IsSupportedAndNotNull(address))
+      GURL_CHECK(IsValidDelta(address, delta_elem * sizeof(T)));
+#endif
+    T* new_wrapped_ptr = WrapRawPtr(wrapped_ptr + delta_elem);
+    ReleaseWrappedPtr(wrapped_ptr);
+    return new_wrapped_ptr;
+  }
+
+  // Returns a copy of a wrapped pointer, without making an assertion on whether
+  // memory was freed or not.
+  // This method increments the reference count of the allocation slot.
+  template <typename T>
+  static RAW_PTR_FUNC_ATTRIBUTES T* Duplicate(T* wrapped_ptr) {
+    return WrapRawPtr(wrapped_ptr);
+  }
+
+  // This is for accounting only, used by unit tests.
+  static RAW_PTR_FUNC_ATTRIBUTES void IncrementSwapCountForTest() {}
+  static RAW_PTR_FUNC_ATTRIBUTES void
+  IncrementPointerToMemberOperatorCountForTest() {}
+
+ private:
+  // We've evaluated several strategies (inline nothing, various parts, or
+  // everything in |Wrap()| and |Release()|) using the Speedometer2 benchmark
+  // to measure performance. The best results were obtained when only the
+  // lightweight |IsManagedByPartitionAllocBRPPool()| check was inlined.
+  // Therefore, we've extracted the rest into the functions below and marked
+  // them as NOINLINE to prevent unintended LTO effects.
+  static BASE_EXPORT NOINLINE void AcquireInternal(uintptr_t address);
+  static BASE_EXPORT NOINLINE void ReleaseInternal(uintptr_t address);
+  static BASE_EXPORT NOINLINE bool IsPointeeAlive(uintptr_t address);
+  static BASE_EXPORT NOINLINE bool IsValidDelta(uintptr_t address,
+                                                ptrdiff_t delta_in_bytes);
+};
+
+#endif  // BUILDFLAG(USE_BACKUP_REF_PTR)
+
+// Implementation that allows us to detect BackupRefPtr problems in ASan builds.
+struct AsanBackupRefPtrImpl {
+  // Wraps a pointer.
+  template <typename T>
+  static RAW_PTR_FUNC_ATTRIBUTES T* WrapRawPtr(T* ptr) {
+    AsanCheckIfValidInstantiation(ptr);
+    return ptr;
+  }
+
+  // Notifies the allocator when a wrapped pointer is being removed or replaced.
+  template <typename T>
+  static RAW_PTR_FUNC_ATTRIBUTES void ReleaseWrappedPtr(T*) {}
+
+  // Unwraps the pointer, while asserting that memory hasn't been freed. The
+  // function is allowed to crash on nullptr.
+  template <typename T>
+  static RAW_PTR_FUNC_ATTRIBUTES T* SafelyUnwrapPtrForDereference(
+      T* wrapped_ptr) {
+    AsanCheckIfValidDereference(wrapped_ptr);
+    return wrapped_ptr;
+  }
+
+  // Unwraps the pointer, while asserting that memory hasn't been freed. The
+  // function must handle nullptr gracefully.
+  template <typename T>
+  static RAW_PTR_FUNC_ATTRIBUTES T* SafelyUnwrapPtrForExtraction(
+      T* wrapped_ptr) {
+    AsanCheckIfValidExtraction(wrapped_ptr);
+    return wrapped_ptr;
+  }
+
+  // Unwraps the pointer, without making an assertion on whether memory was
+  // freed or not.
+  template <typename T>
+  static RAW_PTR_FUNC_ATTRIBUTES T* UnsafelyUnwrapPtrForComparison(
+      T* wrapped_ptr) {
+    return wrapped_ptr;
+  }
+
+  // Upcasts the wrapped pointer.
+  template <typename To, typename From>
+  static RAW_PTR_FUNC_ATTRIBUTES constexpr To* Upcast(From* wrapped_ptr) {
+    static_assert(std::is_convertible<From*, To*>::value,
+                  "From must be convertible to To.");
+    // Note, this cast may change the address if upcasting to base that lies in
+    // the middle of the derived object.
+    return wrapped_ptr;
+  }
+
+  // Advance the wrapped pointer by |delta| bytes.
+  template <typename T>
+  static RAW_PTR_FUNC_ATTRIBUTES T* Advance(T* wrapped_ptr,
+                                            ptrdiff_t delta_elems) {
+    return wrapped_ptr + delta_elems;
+  }
+
+  // Returns a copy of a wrapped pointer, without making an assertion on whether
+  // memory was freed or not.
+  template <typename T>
+  static RAW_PTR_FUNC_ATTRIBUTES T* Duplicate(T* wrapped_ptr) {
+    return wrapped_ptr;
+  }
+
+  // This is for accounting only, used by unit tests.
+  static RAW_PTR_FUNC_ATTRIBUTES void IncrementSwapCountForTest() {}
+  static RAW_PTR_FUNC_ATTRIBUTES void
+  IncrementPointerToMemberOperatorCountForTest() {}
+
+ private:
+  static BASE_EXPORT NOINLINE void AsanCheckIfValidInstantiation(
+      void const volatile* ptr);
+  static BASE_EXPORT NOINLINE void AsanCheckIfValidDereference(
+      void const volatile* ptr);
+  static BASE_EXPORT NOINLINE void AsanCheckIfValidExtraction(
+      void const volatile* ptr);
+};
+
+}  // namespace internal
+
+namespace raw_ptr_traits {
+
+// IsSupportedType<T>::value answers whether raw_ptr<T> 1) compiles and 2) is
+// always safe at runtime.  Templates that may end up using `raw_ptr<T>` should
+// use IsSupportedType to ensure that raw_ptr is not used with unsupported
+// types.  As an example, see how gurl_base::internal::StorageTraits uses
+// IsSupportedType as a condition for using gurl_base::internal::UnretainedWrapper
+// (which has a `ptr_` field that will become `raw_ptr<T>` after the Big
+// Rewrite).
+template <typename T, typename SFINAE = void>
+struct IsSupportedType {
+  static constexpr bool value = true;
+};
+
+// raw_ptr<T> is not compatible with function pointer types. Also, they don't
+// even need the raw_ptr protection, because they don't point on heap.
+template <typename T>
+struct IsSupportedType<T, std::enable_if_t<std::is_function<T>::value>> {
+  static constexpr bool value = false;
+};
+
+// This section excludes some types from raw_ptr<T> to avoid them from being
+// used inside gurl_base::Unretained in performance sensitive places. These were
+// identified from sampling profiler data. See crbug.com/1287151 for more info.
+template <>
+struct IsSupportedType<cc::Scheduler> {
+  static constexpr bool value = false;
+};
+template <>
+struct IsSupportedType<gurl_base::internal::DelayTimerBase> {
+  static constexpr bool value = false;
+};
+template <>
+struct IsSupportedType<content::responsiveness::Calculator> {
+  static constexpr bool value = false;
+};
+
+#if __OBJC__
+// raw_ptr<T> is not compatible with pointers to Objective-C classes for a
+// multitude of reasons. They may fail to compile in many cases, and wouldn't
+// work well with tagged pointers. Anyway, Objective-C objects have their own
+// way of tracking lifespan, hence don't need the raw_ptr protection as much.
+//
+// Such pointers are detected by checking if they're convertible to |id| type.
+template <typename T>
+struct IsSupportedType<T,
+                       std::enable_if_t<std::is_convertible<T*, id>::value>> {
+  static constexpr bool value = false;
+};
+#endif  // __OBJC__
+
+#if BUILDFLAG(IS_WIN)
+// raw_ptr<HWND__> is unsafe at runtime - if the handle happens to also
+// represent a valid pointer into a PartitionAlloc-managed region then it can
+// lead to manipulating random memory when treating it as BackupRefPtr
+// ref-count.  See also https://crbug.com/1262017.
+//
+// TODO(https://crbug.com/1262017): Cover other handle types like HANDLE,
+// HLOCAL, HINTERNET, or HDEVINFO.  Maybe we should avoid using raw_ptr<T> when
+// T=void (as is the case in these handle types).  OTOH, explicit,
+// non-template-based raw_ptr<void> should be allowed.  Maybe this can be solved
+// by having 2 traits: IsPointeeAlwaysSafe (to be used in templates) and
+// IsPointeeUsuallySafe (to be used in the static_assert in raw_ptr).  The
+// upside of this approach is that it will safely handle gurl_base::Bind closing over
+// HANDLE.  The downside of this approach is that gurl_base::Bind closing over a
+// void* pointer will not get UaF protection.
+#define CHROME_WINDOWS_HANDLE_TYPE(name)   \
+  template <>                              \
+  struct IsSupportedType<name##__, void> { \
+    static constexpr bool value = false;   \
+  };
+#include "base/win/win_handle_types_list.inc"
+#undef CHROME_WINDOWS_HANDLE_TYPE
+#endif
+
+}  // namespace raw_ptr_traits
+
+// `raw_ptr<T>` is a non-owning smart pointer that has improved memory-safety
+// over raw pointers.  It behaves just like a raw pointer on platforms where
+// USE_BACKUP_REF_PTR is off, and almost like one when it's on (the main
+// difference is that it's zero-initialized and cleared on destruction and
+// move). Unlike `std::unique_ptr<T>`, `gurl_base::scoped_refptr<T>`, etc., it
+// doesn’t manage ownership or lifetime of an allocated object - you are still
+// responsible for freeing the object when no longer used, just as you would
+// with a raw C++ pointer.
+//
+// Compared to a raw C++ pointer, on platforms where USE_BACKUP_REF_PTR is on,
+// `raw_ptr<T>` incurs additional performance overhead for initialization,
+// destruction, and assignment (including `ptr++` and `ptr += ...`).  There is
+// no overhead when dereferencing a pointer.
+//
+// `raw_ptr<T>` is beneficial for security, because it can prevent a significant
+// percentage of Use-after-Free (UaF) bugs from being exploitable.  `raw_ptr<T>`
+// has limited impact on stability - dereferencing a dangling pointer remains
+// Undefined Behavior.  Note that the security protection is not yet enabled by
+// default.
+//
+// raw_ptr<T> is marked as [[gsl::Pointer]] which allows the compiler to catch
+// some bugs where the raw_ptr holds a dangling pointer to a temporary object.
+// However the [[gsl::Pointer]] analysis expects that such types do not have a
+// non-default move constructor/assignment. Thus, it's possible to get an error
+// where the pointer is not actually dangling, and have to work around the
+// compiler. We have not managed to construct such an example in Chromium yet.
+template <typename T,
+#if BUILDFLAG(USE_BACKUP_REF_PTR)
+          typename Impl = internal::BackupRefPtrImpl>
+#elif BUILDFLAG(USE_ASAN_BACKUP_REF_PTR)
+          typename Impl = internal::AsanBackupRefPtrImpl>
+#else
+          typename Impl = internal::RawPtrNoOpImpl>
+#endif
+class TRIVIAL_ABI GSL_POINTER raw_ptr {
+ public:
+  static_assert(raw_ptr_traits::IsSupportedType<T>::value,
+                "raw_ptr<T> doesn't work with this kind of pointee type T");
+
+#if BUILDFLAG(USE_BACKUP_REF_PTR)
+  // BackupRefPtr requires a non-trivial default constructor, destructor, etc.
+  constexpr RAW_PTR_FUNC_ATTRIBUTES raw_ptr() noexcept
+      : wrapped_ptr_(nullptr) {}
+
+  RAW_PTR_FUNC_ATTRIBUTES raw_ptr(const raw_ptr& p) noexcept
+      : wrapped_ptr_(Impl::Duplicate(p.wrapped_ptr_)) {}
+
+  RAW_PTR_FUNC_ATTRIBUTES raw_ptr(raw_ptr&& p) noexcept {
+    wrapped_ptr_ = p.wrapped_ptr_;
+    p.wrapped_ptr_ = nullptr;
+  }
+
+  RAW_PTR_FUNC_ATTRIBUTES raw_ptr& operator=(const raw_ptr& p) {
+    // Duplicate before releasing, in case the pointer is assigned to itself.
+    T* new_ptr = Impl::Duplicate(p.wrapped_ptr_);
+    Impl::ReleaseWrappedPtr(wrapped_ptr_);
+    wrapped_ptr_ = new_ptr;
+    return *this;
+  }
+
+  RAW_PTR_FUNC_ATTRIBUTES raw_ptr& operator=(raw_ptr&& p) {
+    if (LIKELY(this != &p)) {
+      Impl::ReleaseWrappedPtr(wrapped_ptr_);
+      wrapped_ptr_ = p.wrapped_ptr_;
+      p.wrapped_ptr_ = nullptr;
+    }
+    return *this;
+  }
+
+  RAW_PTR_FUNC_ATTRIBUTES ~raw_ptr() noexcept {
+    Impl::ReleaseWrappedPtr(wrapped_ptr_);
+    // Work around external issues where raw_ptr is used after destruction.
+    wrapped_ptr_ = nullptr;
+  }
+
+#else  // BUILDFLAG(USE_BACKUP_REF_PTR)
+
+  // raw_ptr can be trivially default constructed (leaving |wrapped_ptr_|
+  // uninitialized).  This is needed for compatibility with raw pointers.
+  //
+  // TODO(lukasza): Always initialize |wrapped_ptr_|.  Fix resulting build
+  // errors.  Analyze performance impact.
+  constexpr RAW_PTR_FUNC_ATTRIBUTES raw_ptr() noexcept = default;
+
+  // In addition to nullptr_t ctor above, raw_ptr needs to have these
+  // as |=default| or |constexpr| to avoid hitting -Wglobal-constructors in
+  // cases like this:
+  //     struct SomeStruct { int int_field; raw_ptr<int> ptr_field; };
+  //     SomeStruct g_global_var = { 123, nullptr };
+  RAW_PTR_FUNC_ATTRIBUTES raw_ptr(const raw_ptr&) noexcept = default;
+  RAW_PTR_FUNC_ATTRIBUTES raw_ptr(raw_ptr&&) noexcept = default;
+  RAW_PTR_FUNC_ATTRIBUTES raw_ptr& operator=(const raw_ptr&) noexcept = default;
+  RAW_PTR_FUNC_ATTRIBUTES raw_ptr& operator=(raw_ptr&&) noexcept = default;
+
+  RAW_PTR_FUNC_ATTRIBUTES ~raw_ptr() = default;
+
+#endif  // BUILDFLAG(USE_BACKUP_REF_PTR)
+
+  // Deliberately implicit, because raw_ptr is supposed to resemble raw ptr.
+  // NOLINTNEXTLINE(google-explicit-constructor)
+  constexpr RAW_PTR_FUNC_ATTRIBUTES raw_ptr(std::nullptr_t) noexcept
+      : wrapped_ptr_(nullptr) {}
+
+  // Deliberately implicit, because raw_ptr is supposed to resemble raw ptr.
+  // NOLINTNEXTLINE(google-explicit-constructor)
+  RAW_PTR_FUNC_ATTRIBUTES raw_ptr(T* p) noexcept
+      : wrapped_ptr_(Impl::WrapRawPtr(p)) {}
+
+  // Deliberately implicit in order to support implicit upcast.
+  template <typename U,
+            typename Unused = std::enable_if_t<
+                std::is_convertible<U*, T*>::value &&
+                !std::is_void<typename std::remove_cv<T>::type>::value>>
+  // NOLINTNEXTLINE(google-explicit-constructor)
+  RAW_PTR_FUNC_ATTRIBUTES raw_ptr(const raw_ptr<U, Impl>& ptr) noexcept
+      : wrapped_ptr_(
+            Impl::Duplicate(Impl::template Upcast<T, U>(ptr.wrapped_ptr_))) {}
+  // Deliberately implicit in order to support implicit upcast.
+  template <typename U,
+            typename Unused = std::enable_if_t<
+                std::is_convertible<U*, T*>::value &&
+                !std::is_void<typename std::remove_cv<T>::type>::value>>
+  // NOLINTNEXTLINE(google-explicit-constructor)
+  RAW_PTR_FUNC_ATTRIBUTES raw_ptr(raw_ptr<U, Impl>&& ptr) noexcept
+      : wrapped_ptr_(Impl::template Upcast<T, U>(ptr.wrapped_ptr_)) {
+#if BUILDFLAG(USE_BACKUP_REF_PTR)
+    ptr.wrapped_ptr_ = nullptr;
+#endif
+  }
+
+  RAW_PTR_FUNC_ATTRIBUTES raw_ptr& operator=(std::nullptr_t) noexcept {
+    Impl::ReleaseWrappedPtr(wrapped_ptr_);
+    wrapped_ptr_ = nullptr;
+    return *this;
+  }
+  RAW_PTR_FUNC_ATTRIBUTES raw_ptr& operator=(T* p) noexcept {
+    Impl::ReleaseWrappedPtr(wrapped_ptr_);
+    wrapped_ptr_ = Impl::WrapRawPtr(p);
+    return *this;
+  }
+
+  // Upcast assignment
+  template <typename U,
+            typename Unused = std::enable_if_t<
+                std::is_convertible<U*, T*>::value &&
+                !std::is_void<typename std::remove_cv<T>::type>::value>>
+  RAW_PTR_FUNC_ATTRIBUTES raw_ptr& operator=(
+      const raw_ptr<U, Impl>& ptr) noexcept {
+    // Make sure that pointer isn't assigned to itself (look at pointer address,
+    // not its value).
+#if GURL_DCHECK_IS_ON() || BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS)
+    GURL_CHECK(reinterpret_cast<uintptr_t>(this) !=
+          reinterpret_cast<uintptr_t>(&ptr));
+#endif
+    Impl::ReleaseWrappedPtr(wrapped_ptr_);
+    wrapped_ptr_ =
+        Impl::Duplicate(Impl::template Upcast<T, U>(ptr.wrapped_ptr_));
+    return *this;
+  }
+  template <typename U,
+            typename Unused = std::enable_if_t<
+                std::is_convertible<U*, T*>::value &&
+                !std::is_void<typename std::remove_cv<T>::type>::value>>
+  RAW_PTR_FUNC_ATTRIBUTES raw_ptr& operator=(raw_ptr<U, Impl>&& ptr) noexcept {
+    // Make sure that pointer isn't assigned to itself (look at pointer address,
+    // not its value).
+#if GURL_DCHECK_IS_ON() || BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS)
+    GURL_CHECK(reinterpret_cast<uintptr_t>(this) !=
+          reinterpret_cast<uintptr_t>(&ptr));
+#endif
+    Impl::ReleaseWrappedPtr(wrapped_ptr_);
+    wrapped_ptr_ = Impl::template Upcast<T, U>(ptr.wrapped_ptr_);
+#if BUILDFLAG(USE_BACKUP_REF_PTR)
+    ptr.wrapped_ptr_ = nullptr;
+#endif
+    return *this;
+  }
+
+  // Avoid using. The goal of raw_ptr is to be as close to raw pointer as
+  // possible, so use it only if absolutely necessary (e.g. for const_cast).
+  RAW_PTR_FUNC_ATTRIBUTES T* get() const { return GetForExtraction(); }
+
+  explicit RAW_PTR_FUNC_ATTRIBUTES operator bool() const {
+    return !!wrapped_ptr_;
+  }
+
+  template <typename U = T,
+            typename Unused = std::enable_if_t<
+                !std::is_void<typename std::remove_cv<U>::type>::value>>
+  RAW_PTR_FUNC_ATTRIBUTES U& operator*() const {
+    return *GetForDereference();
+  }
+  RAW_PTR_FUNC_ATTRIBUTES T* operator->() const { return GetForDereference(); }
+
+  // Disables `(my_raw_ptr->*pmf)(...)` as a workaround for
+  // the ICE in GCC parsing the code, reported at
+  // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103455
+  template <typename PMF>
+  void operator->*(PMF) const = delete;
+
+  // Deliberately implicit, because raw_ptr is supposed to resemble raw ptr.
+  // NOLINTNEXTLINE(runtime/explicit)
+  RAW_PTR_FUNC_ATTRIBUTES operator T*() const { return GetForExtraction(); }
+  template <typename U>
+  explicit RAW_PTR_FUNC_ATTRIBUTES operator U*() const {
+    // This operator may be invoked from static_cast, meaning the types may not
+    // be implicitly convertible, hence the need for static_cast here.
+    return static_cast<U*>(GetForExtraction());
+  }
+
+  RAW_PTR_FUNC_ATTRIBUTES raw_ptr& operator++() {
+    wrapped_ptr_ = Impl::Advance(wrapped_ptr_, 1);
+    return *this;
+  }
+  RAW_PTR_FUNC_ATTRIBUTES raw_ptr& operator--() {
+    wrapped_ptr_ = Impl::Advance(wrapped_ptr_, -1);
+    return *this;
+  }
+  RAW_PTR_FUNC_ATTRIBUTES raw_ptr operator++(int /* post_increment */) {
+    raw_ptr result = *this;
+    ++(*this);
+    return result;
+  }
+  RAW_PTR_FUNC_ATTRIBUTES raw_ptr operator--(int /* post_decrement */) {
+    raw_ptr result = *this;
+    --(*this);
+    return result;
+  }
+  RAW_PTR_FUNC_ATTRIBUTES raw_ptr& operator+=(ptrdiff_t delta_elems) {
+    wrapped_ptr_ = Impl::Advance(wrapped_ptr_, delta_elems);
+    return *this;
+  }
+  RAW_PTR_FUNC_ATTRIBUTES raw_ptr& operator-=(ptrdiff_t delta_elems) {
+    return *this += -delta_elems;
+  }
+
+  // Stop referencing the underlying pointer and free its memory. Compared to
+  // raw delete calls, this avoids the raw_ptr to be temporarily dangling
+  // during the free operation, which will lead to taking the slower path that
+  // involves quarantine.
+  RAW_PTR_FUNC_ATTRIBUTES void ClearAndDelete() noexcept {
+    T* ptr = wrapped_ptr_;
+    operator=(nullptr);
+    delete ptr;
+  }
+  RAW_PTR_FUNC_ATTRIBUTES void ClearAndDeleteArray() noexcept {
+    T* ptr = wrapped_ptr_;
+    operator=(nullptr);
+    delete[] ptr;
+  }
+
+  // Comparison operators between raw_ptr and raw_ptr<U>/U*/std::nullptr_t.
+  // Strictly speaking, it is not necessary to provide these: the compiler can
+  // use the conversion operator implicitly to allow comparisons to fall back to
+  // comparisons between raw pointers. However, `operator T*`/`operator U*` may
+  // perform safety checks with a higher runtime cost, so to avoid this, provide
+  // explicit comparison operators for all combinations of parameters.
+
+  // Comparisons between `raw_ptr`s. This unusual declaration and separate
+  // definition below is because `GetForComparison()` is a private method. The
+  // more conventional approach of defining a comparison operator between
+  // `raw_ptr` and `raw_ptr<U>` in the friend declaration itself does not work,
+  // because a comparison operator defined inline would not be allowed to call
+  // `raw_ptr<U>`'s private `GetForComparison()` method.
+  template <typename U, typename V, typename I>
+  friend RAW_PTR_FUNC_ATTRIBUTES bool operator==(const raw_ptr<U, I>& lhs,
+                                                 const raw_ptr<V, I>& rhs);
+  template <typename U>
+  friend RAW_PTR_FUNC_ATTRIBUTES bool operator!=(const raw_ptr& lhs,
+                                                 const raw_ptr<U, Impl>& rhs) {
+    return !(lhs == rhs);
+  }
+  template <typename U, typename V, typename I>
+  friend RAW_PTR_FUNC_ATTRIBUTES bool operator<(const raw_ptr<U, I>& lhs,
+                                                const raw_ptr<V, I>& rhs);
+  template <typename U, typename V, typename I>
+  friend RAW_PTR_FUNC_ATTRIBUTES bool operator>(const raw_ptr<U, I>& lhs,
+                                                const raw_ptr<V, I>& rhs);
+  template <typename U, typename V, typename I>
+  friend RAW_PTR_FUNC_ATTRIBUTES bool operator<=(const raw_ptr<U, I>& lhs,
+                                                 const raw_ptr<V, I>& rhs);
+  template <typename U, typename V, typename I>
+  friend RAW_PTR_FUNC_ATTRIBUTES bool operator>=(const raw_ptr<U, I>& lhs,
+                                                 const raw_ptr<V, I>& rhs);
+
+  // Comparisons with U*. These operators also handle the case where the RHS is
+  // T*.
+  template <typename U>
+  friend RAW_PTR_FUNC_ATTRIBUTES bool operator==(const raw_ptr& lhs, U* rhs) {
+    return lhs.GetForComparison() == rhs;
+  }
+  template <typename U>
+  friend RAW_PTR_FUNC_ATTRIBUTES bool operator!=(const raw_ptr& lhs, U* rhs) {
+    return !(lhs == rhs);
+  }
+  template <typename U>
+  friend RAW_PTR_FUNC_ATTRIBUTES bool operator==(U* lhs, const raw_ptr& rhs) {
+    return rhs == lhs;  // Reverse order to call the operator above.
+  }
+  template <typename U>
+  friend RAW_PTR_FUNC_ATTRIBUTES bool operator!=(U* lhs, const raw_ptr& rhs) {
+    return rhs != lhs;  // Reverse order to call the operator above.
+  }
+  template <typename U>
+  friend RAW_PTR_FUNC_ATTRIBUTES bool operator<(const raw_ptr& lhs, U* rhs) {
+    return lhs.GetForComparison() < rhs;
+  }
+  template <typename U>
+  friend RAW_PTR_FUNC_ATTRIBUTES bool operator<=(const raw_ptr& lhs, U* rhs) {
+    return lhs.GetForComparison() <= rhs;
+  }
+  template <typename U>
+  friend RAW_PTR_FUNC_ATTRIBUTES bool operator>(const raw_ptr& lhs, U* rhs) {
+    return lhs.GetForComparison() > rhs;
+  }
+  template <typename U>
+  friend RAW_PTR_FUNC_ATTRIBUTES bool operator>=(const raw_ptr& lhs, U* rhs) {
+    return lhs.GetForComparison() >= rhs;
+  }
+  template <typename U>
+  friend RAW_PTR_FUNC_ATTRIBUTES bool operator<(U* lhs, const raw_ptr& rhs) {
+    return lhs < rhs.GetForComparison();
+  }
+  template <typename U>
+  friend RAW_PTR_FUNC_ATTRIBUTES bool operator<=(U* lhs, const raw_ptr& rhs) {
+    return lhs <= rhs.GetForComparison();
+  }
+  template <typename U>
+  friend RAW_PTR_FUNC_ATTRIBUTES bool operator>(U* lhs, const raw_ptr& rhs) {
+    return lhs > rhs.GetForComparison();
+  }
+  template <typename U>
+  friend RAW_PTR_FUNC_ATTRIBUTES bool operator>=(U* lhs, const raw_ptr& rhs) {
+    return lhs >= rhs.GetForComparison();
+  }
+
+  // Comparisons with `std::nullptr_t`.
+  friend RAW_PTR_FUNC_ATTRIBUTES bool operator==(const raw_ptr& lhs,
+                                                 std::nullptr_t) {
+    return !lhs;
+  }
+  friend RAW_PTR_FUNC_ATTRIBUTES bool operator!=(const raw_ptr& lhs,
+                                                 std::nullptr_t) {
+    return !!lhs;  // Use !! otherwise the costly implicit cast will be used.
+  }
+  friend RAW_PTR_FUNC_ATTRIBUTES bool operator==(std::nullptr_t,
+                                                 const raw_ptr& rhs) {
+    return !rhs;
+  }
+  friend RAW_PTR_FUNC_ATTRIBUTES bool operator!=(std::nullptr_t,
+                                                 const raw_ptr& rhs) {
+    return !!rhs;  // Use !! otherwise the costly implicit cast will be used.
+  }
+
+  friend RAW_PTR_FUNC_ATTRIBUTES void swap(raw_ptr& lhs,
+                                           raw_ptr& rhs) noexcept {
+    Impl::IncrementSwapCountForTest();
+    std::swap(lhs.wrapped_ptr_, rhs.wrapped_ptr_);
+  }
+
+ private:
+  // This getter is meant for situations where the pointer is meant to be
+  // dereferenced. It is allowed to crash on nullptr (it may or may not),
+  // because it knows that the caller will crash on nullptr.
+  RAW_PTR_FUNC_ATTRIBUTES T* GetForDereference() const {
+    return Impl::SafelyUnwrapPtrForDereference(wrapped_ptr_);
+  }
+  // This getter is meant for situations where the raw pointer is meant to be
+  // extracted outside of this class, but not necessarily with an intention to
+  // dereference. It mustn't crash on nullptr.
+  RAW_PTR_FUNC_ATTRIBUTES T* GetForExtraction() const {
+    return Impl::SafelyUnwrapPtrForExtraction(wrapped_ptr_);
+  }
+  // This getter is meant *only* for situations where the pointer is meant to be
+  // compared (guaranteeing no dereference or extraction outside of this class).
+  // Any verifications can and should be skipped for performance reasons.
+  RAW_PTR_FUNC_ATTRIBUTES T* GetForComparison() const {
+    return Impl::UnsafelyUnwrapPtrForComparison(wrapped_ptr_);
+  }
+
+  T* wrapped_ptr_;
+
+  template <typename U, typename V>
+  friend class raw_ptr;
+};
+
+template <typename U, typename V, typename I>
+RAW_PTR_FUNC_ATTRIBUTES bool operator==(const raw_ptr<U, I>& lhs,
+                                        const raw_ptr<V, I>& rhs) {
+  return lhs.GetForComparison() == rhs.GetForComparison();
+}
+
+template <typename U, typename V, typename I>
+RAW_PTR_FUNC_ATTRIBUTES bool operator<(const raw_ptr<U, I>& lhs,
+                                       const raw_ptr<V, I>& rhs) {
+  return lhs.GetForComparison() < rhs.GetForComparison();
+}
+
+template <typename U, typename V, typename I>
+RAW_PTR_FUNC_ATTRIBUTES bool operator>(const raw_ptr<U, I>& lhs,
+                                       const raw_ptr<V, I>& rhs) {
+  return lhs.GetForComparison() > rhs.GetForComparison();
+}
+
+template <typename U, typename V, typename I>
+RAW_PTR_FUNC_ATTRIBUTES bool operator<=(const raw_ptr<U, I>& lhs,
+                                        const raw_ptr<V, I>& rhs) {
+  return lhs.GetForComparison() <= rhs.GetForComparison();
+}
+
+template <typename U, typename V, typename I>
+RAW_PTR_FUNC_ATTRIBUTES bool operator>=(const raw_ptr<U, I>& lhs,
+                                        const raw_ptr<V, I>& rhs) {
+  return lhs.GetForComparison() >= rhs.GetForComparison();
+}
+
+}  // namespace base
+
+using gurl_base::raw_ptr;
+
+namespace std {
+
+// Override so set/map lookups do not create extra raw_ptr. This also allows
+// dangling pointers to be used for lookup.
+template <typename T, typename I>
+struct less<raw_ptr<T, I>> {
+  using is_transparent = void;
+
+  bool operator()(const raw_ptr<T, I>& lhs, const raw_ptr<T, I>& rhs) const {
+    return lhs < rhs;
+  }
+
+  bool operator()(T* lhs, const raw_ptr<T, I>& rhs) const { return lhs < rhs; }
+
+  bool operator()(const raw_ptr<T, I>& lhs, T* rhs) const { return lhs < rhs; }
+};
+
+}  // namespace std
+
+#endif  // BASE_MEMORY_RAW_PTR_H_
diff --git a/base/stl_util.h b/base/stl_util.h
index 46e91b9..a9c627d 100644
--- a/base/stl_util.h
+++ b/base/stl_util.h
@@ -10,9 +10,7 @@
 #include <algorithm>
 #include <forward_list>
 #include <iterator>
-#include <tuple>
 #include <type_traits>
-#include <utility>
 
 #include "polyfills/base/check.h"
 #include "base/ranges/algorithm.h"
@@ -111,166 +109,6 @@
   return begin(c) + (it - cbegin(c));
 }
 
-namespace internal {
-
-template <typename Map, typename Key, typename Value>
-std::pair<typename Map::iterator, bool> InsertOrAssignImpl(Map& map,
-                                                           Key&& key,
-                                                           Value&& value) {
-  auto lower = map.lower_bound(key);
-  if (lower != map.end() && !map.key_comp()(key, lower->first)) {
-    // key already exists, perform assignment.
-    lower->second = std::forward<Value>(value);
-    return {lower, false};
-  }
-
-  // key did not yet exist, insert it.
-  return {map.emplace_hint(lower, std::forward<Key>(key),
-                           std::forward<Value>(value)),
-          true};
-}
-
-template <typename Map, typename Key, typename Value>
-typename Map::iterator InsertOrAssignImpl(Map& map,
-                                          typename Map::const_iterator hint,
-                                          Key&& key,
-                                          Value&& value) {
-  auto&& key_comp = map.key_comp();
-  if ((hint == map.begin() || key_comp(std::prev(hint)->first, key))) {
-    if (hint == map.end() || key_comp(key, hint->first)) {
-      // *(hint - 1) < key < *hint => key did not exist and hint is correct.
-      return map.emplace_hint(hint, std::forward<Key>(key),
-                              std::forward<Value>(value));
-    }
-
-    if (!key_comp(hint->first, key)) {
-      // key == *hint => key already exists and hint is correct.
-      auto mutable_hint = ConstCastIterator(map, hint);
-      mutable_hint->second = std::forward<Value>(value);
-      return mutable_hint;
-    }
-  }
-
-  // hint was not helpful, dispatch to hintless version.
-  return InsertOrAssignImpl(map, std::forward<Key>(key),
-                            std::forward<Value>(value))
-      .first;
-}
-
-template <typename Map, typename Key, typename... Args>
-std::pair<typename Map::iterator, bool> TryEmplaceImpl(Map& map,
-                                                       Key&& key,
-                                                       Args&&... args) {
-  auto lower = map.lower_bound(key);
-  if (lower != map.end() && !map.key_comp()(key, lower->first)) {
-    // key already exists, do nothing.
-    return {lower, false};
-  }
-
-  // key did not yet exist, insert it.
-  return {map.emplace_hint(lower, std::piecewise_construct,
-                           std::forward_as_tuple(std::forward<Key>(key)),
-                           std::forward_as_tuple(std::forward<Args>(args)...)),
-          true};
-}
-
-template <typename Map, typename Key, typename... Args>
-typename Map::iterator TryEmplaceImpl(Map& map,
-                                      typename Map::const_iterator hint,
-                                      Key&& key,
-                                      Args&&... args) {
-  auto&& key_comp = map.key_comp();
-  if ((hint == map.begin() || key_comp(std::prev(hint)->first, key))) {
-    if (hint == map.end() || key_comp(key, hint->first)) {
-      // *(hint - 1) < key < *hint => key did not exist and hint is correct.
-      return map.emplace_hint(
-          hint, std::piecewise_construct,
-          std::forward_as_tuple(std::forward<Key>(key)),
-          std::forward_as_tuple(std::forward<Args>(args)...));
-    }
-
-    if (!key_comp(hint->first, key)) {
-      // key == *hint => no-op, return correct hint.
-      return ConstCastIterator(map, hint);
-    }
-  }
-
-  // hint was not helpful, dispatch to hintless version.
-  return TryEmplaceImpl(map, std::forward<Key>(key),
-                        std::forward<Args>(args)...)
-      .first;
-}
-
-}  // namespace internal
-
-// Implementation of C++17's std::map::insert_or_assign as a free function.
-template <typename Map, typename Value>
-std::pair<typename Map::iterator, bool>
-InsertOrAssign(Map& map, const typename Map::key_type& key, Value&& value) {
-  return internal::InsertOrAssignImpl(map, key, std::forward<Value>(value));
-}
-
-template <typename Map, typename Value>
-std::pair<typename Map::iterator, bool>
-InsertOrAssign(Map& map, typename Map::key_type&& key, Value&& value) {
-  return internal::InsertOrAssignImpl(map, std::move(key),
-                                      std::forward<Value>(value));
-}
-
-// Implementation of C++17's std::map::insert_or_assign with hint as a free
-// function.
-template <typename Map, typename Value>
-typename Map::iterator InsertOrAssign(Map& map,
-                                      typename Map::const_iterator hint,
-                                      const typename Map::key_type& key,
-                                      Value&& value) {
-  return internal::InsertOrAssignImpl(map, hint, key,
-                                      std::forward<Value>(value));
-}
-
-template <typename Map, typename Value>
-typename Map::iterator InsertOrAssign(Map& map,
-                                      typename Map::const_iterator hint,
-                                      typename Map::key_type&& key,
-                                      Value&& value) {
-  return internal::InsertOrAssignImpl(map, hint, std::move(key),
-                                      std::forward<Value>(value));
-}
-
-// Implementation of C++17's std::map::try_emplace as a free function.
-template <typename Map, typename... Args>
-std::pair<typename Map::iterator, bool>
-TryEmplace(Map& map, const typename Map::key_type& key, Args&&... args) {
-  return internal::TryEmplaceImpl(map, key, std::forward<Args>(args)...);
-}
-
-template <typename Map, typename... Args>
-std::pair<typename Map::iterator, bool> TryEmplace(Map& map,
-                                                   typename Map::key_type&& key,
-                                                   Args&&... args) {
-  return internal::TryEmplaceImpl(map, std::move(key),
-                                  std::forward<Args>(args)...);
-}
-
-// Implementation of C++17's std::map::try_emplace with hint as a free
-// function.
-template <typename Map, typename... Args>
-typename Map::iterator TryEmplace(Map& map,
-                                  typename Map::const_iterator hint,
-                                  const typename Map::key_type& key,
-                                  Args&&... args) {
-  return internal::TryEmplaceImpl(map, hint, key, std::forward<Args>(args)...);
-}
-
-template <typename Map, typename... Args>
-typename Map::iterator TryEmplace(Map& map,
-                                  typename Map::const_iterator hint,
-                                  typename Map::key_type&& key,
-                                  Args&&... args) {
-  return internal::TryEmplaceImpl(map, hint, std::move(key),
-                                  std::forward<Args>(args)...);
-}
-
 // Returns a new ResultType containing the difference of two sorted containers.
 template <typename ResultType, typename Arg1, typename Arg2>
 ResultType STLSetDifference(const Arg1& a1, const Arg2& a2) {
diff --git a/base/strings/BUILD b/base/strings/BUILD
deleted file mode 100644
index 257f8f9..0000000
--- a/base/strings/BUILD
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-load("//build_config:build_config.bzl", "build_config")
-load("@rules_cc//cc:defs.bzl", "cc_library")
-
-cc_library(
-    name = "strings",
-    srcs = [
-        "string_piece.cc",
-        "string_util.cc",
-        "string_util_constants.cc",
-        "utf_string_conversion_utils.cc",
-        "utf_string_conversions.cc",
-    ],
-    hdrs = [
-        "char_traits.h",
-        "string_piece_forward.h",
-        "string_piece.h",
-        "string_util.h",
-        "string_util_internal.h",
-        "utf_string_conversions.h",
-        "utf_string_conversion_utils.h",
-    ] + build_config.strings_hdrs,
-    copts = build_config.default_copts,
-    visibility = ["//visibility:public"],
-    deps = [
-        "//base",
-        "//base/third_party/icu",
-        "//build:build_config",
-        "//polyfills",
-    ],
-)
diff --git a/base/strings/abseil_string_number_conversions.cc b/base/strings/abseil_string_number_conversions.cc
new file mode 100644
index 0000000..9ab1303
--- /dev/null
+++ b/base/strings/abseil_string_number_conversions.cc
@@ -0,0 +1,17 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/abseil_string_number_conversions.h"
+
+#include "base/strings/string_number_conversions_internal.h"
+#include "base/strings/string_piece.h"
+#include "absl/numeric/int128.h"
+
+namespace gurl_base {
+
+bool HexStringToUInt128(StringPiece input, absl::uint128* output) {
+  return internal::HexStringToIntImpl(input, *output);
+}
+
+}  // namespace base
diff --git a/base/strings/abseil_string_number_conversions.h b/base/strings/abseil_string_number_conversions.h
new file mode 100644
index 0000000..7eb927d
--- /dev/null
+++ b/base/strings/abseil_string_number_conversions.h
@@ -0,0 +1,24 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRINGS_ABSEIL_STRING_NUMBER_CONVERSIONS_H_
+#define BASE_STRINGS_ABSEIL_STRING_NUMBER_CONVERSIONS_H_
+
+#include "polyfills/base/base_export.h"
+#include "base/strings/string_piece_forward.h"
+
+namespace absl {
+class uint128;
+}  // namespace absl
+
+namespace gurl_base {
+
+// Best effort conversion, see `gurl_base::StringToInt()` for restrictions.
+// Will only successfully parse hex values that will fit into |output|.
+// The string is not required to start with 0x.
+BASE_EXPORT bool HexStringToUInt128(StringPiece input, absl::uint128* output);
+
+}  // namespace base
+
+#endif  // BASE_STRINGS_ABSEIL_STRING_NUMBER_CONVERSIONS_H_
diff --git a/base/strings/abseil_string_number_conversions_unittest.cc b/base/strings/abseil_string_number_conversions_unittest.cc
new file mode 100644
index 0000000..3c68cde
--- /dev/null
+++ b/base/strings/abseil_string_number_conversions_unittest.cc
@@ -0,0 +1,102 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/abseil_string_number_conversions.h"
+
+#include <stdint.h>
+
+#include <limits>
+
+#include "base/cxx17_backports.h"
+#include "base/strings/string_piece.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "absl/numeric/int128.h"
+
+namespace gurl_base {
+
+TEST(AbseilStringNumberConversionsTest, HexStringToUInt128) {
+  // Test cases adapted from `StringNumberConversionsTest.HexStringToUint64`.
+  static const struct {
+    std::string input;
+    absl::uint128 output;
+    bool success;
+  } cases[] = {
+      {"0", 0, true},
+      {"42", 66, true},
+      {"-42", 0, false},
+      {"+42", 66, true},
+      {"ffffffffffffffff",
+       absl::MakeUint128(/*high=*/0,
+                         /*low=*/std::numeric_limits<uint64_t>::max()),
+       true},
+      {"1ffffffffffffffff",
+       absl::MakeUint128(/*high=*/1,
+                         /*low=*/std::numeric_limits<uint64_t>::max()),
+       true},
+      {"7fffffff", INT_MAX, true},
+      {"-80000000", 0, false},
+      {"ffffffff", 0xffffffff, true},
+      {"DeadBeef", 0xdeadbeef, true},
+      {"0x42", 66, true},
+      {"-0x42", 0, false},
+      {"+0x42", 66, true},
+      {"0xffffffffffffffff",
+       absl::MakeUint128(/*high=*/0,
+                         /*low=*/std::numeric_limits<uint64_t>::max()),
+       true},
+      {"0x1ffffffffffffffff",
+       absl::MakeUint128(/*high=*/1,
+                         /*low=*/std::numeric_limits<uint64_t>::max()),
+       true},
+      {"0x7fffffff", INT_MAX, true},
+      {"-0x80000000", 0, false},
+      {"0xffffffff", 0xffffffff, true},
+      {"0XDeadBeef", 0xdeadbeef, true},
+      {"0x7fffffffffffffffffffffffffffffff",
+       std::numeric_limits<absl::int128>::max(), true},
+      {"-0x8000000000000000", 0, false},
+      {"0x8000000000000000",
+       absl::MakeUint128(/*high=*/0, UINT64_C(0x8000000000000000)), true},
+      {"-0x8000000000000001", 0, false},
+      {"0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
+       std::numeric_limits<absl::uint128>::max(), true},
+      {"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
+       std::numeric_limits<absl::uint128>::max(), true},
+      {"0x0000000000000000", 0, true},
+      {"0000000000000000", 0, true},
+      {"1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
+       std::numeric_limits<absl::uint128>::max(), false},  // Overflow test.
+      {"0x0f", 15, true},
+      {"0f", 15, true},
+      {" 45", 0x45, false},
+      {"\t\n\v\f\r 0x45", 0x45, false},
+      {" 45", 0x45, false},
+      {"45 ", 0x45, false},
+      {"45:", 0x45, false},
+      {"efgh", 0xef, false},
+      {"0xefgh", 0xef, false},
+      {"hgfe", 0, false},
+      {"-", 0, false},
+      {"", 0, false},
+      {"0x", 0, false},
+  };
+
+  for (const auto& i : cases) {
+    absl::uint128 output = 0;
+    EXPECT_EQ(i.success, HexStringToUInt128(i.input, &output)) << i.input;
+    EXPECT_EQ(i.output, output) << i.input;
+  }
+  // One additional test to verify that conversion of numbers in strings with
+  // embedded NUL characters.  The NUL and extra data after it should be
+  // interpreted as junk after the number.
+  const char input[] =
+      "0xc0ffee\0"
+      "9";
+  std::string input_string(input, gurl_base::size(input) - 1);
+  absl::uint128 output;
+  EXPECT_FALSE(HexStringToUInt128(input_string, &output));
+  EXPECT_EQ(0xc0ffeeU, output);
+}
+
+}  // namespace base
diff --git a/base/strings/safe_sprintf.cc b/base/strings/safe_sprintf.cc
index c9a69ec..6c9aa19 100644
--- a/base/strings/safe_sprintf.cc
+++ b/base/strings/safe_sprintf.cc
@@ -10,7 +10,7 @@
 #include <algorithm>
 #include <limits>
 
-#include "base/macros.h"
+#include "base/memory/raw_ptr.h"
 #include "build/build_config.h"
 
 #if !defined(NDEBUG)
@@ -117,7 +117,7 @@
 // MSVS2013's standard library doesn't mark max() as constexpr yet. cl.exe
 // supports static_cast but doesn't really implement constexpr yet so it doesn't
 // complain, but clang does.
-#if __cplusplus >= 201103 && !(defined(__clang__) && defined(OS_WIN))
+#if __cplusplus >= 201103 && !(defined(__clang__) && BUILDFLAG(IS_WIN))
     static_assert(kSSizeMaxConst ==
                       static_cast<size_t>(std::numeric_limits<ssize_t>::max()),
                   "kSSizeMaxConst should be the max value of an ssize_t");
@@ -263,7 +263,7 @@
   }
 
   // User-provided buffer that will receive the fully formatted output string.
-  char* buffer_;
+  raw_ptr<char> buffer_;
 
   // Number of bytes that are available in the buffer excluding the trailing
   // NUL byte that will be added by the destructor.
diff --git a/base/strings/safe_sprintf.h b/base/strings/safe_sprintf.h
index 40cddc5..478275e 100644
--- a/base/strings/safe_sprintf.h
+++ b/base/strings/safe_sprintf.h
@@ -11,7 +11,7 @@
 
 #include "build/build_config.h"
 
-#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
 // For ssize_t
 #include <unistd.h>
 #endif
diff --git a/base/strings/safe_sprintf_unittest.cc b/base/strings/safe_sprintf_unittest.cc
index be8af13..71814b3 100644
--- a/base/strings/safe_sprintf_unittest.cc
+++ b/base/strings/safe_sprintf_unittest.cc
@@ -13,14 +13,13 @@
 #include <memory>
 
 #include "polyfills/base/check_op.h"
-#include "base/macros.h"
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 // Death tests on Android are currently very flaky. No need to add more flaky
 // tests, as they just make it hard to spot real problems.
 // TODO(markus): See if the restrictions on Android can eventually be lifted.
-#if defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
+#if defined(GTEST_HAS_DEATH_TEST) && !BUILDFLAG(IS_ANDROID)
 #define ALLOW_DEATH_TEST
 #endif
 
diff --git a/base/strings/strcat.h b/base/strings/strcat.h
index fe35447..1cdd708 100644
--- a/base/strings/strcat.h
+++ b/base/strings/strcat.h
@@ -8,12 +8,11 @@
 #include <initializer_list>
 
 #include "polyfills/base/base_export.h"
-#include "base/compiler_specific.h"
 #include "base/containers/span.h"
 #include "base/strings/string_piece.h"
 #include "build/build_config.h"
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 // Guard against conflict with Win32 API StrCat macro:
 // check StrCat wasn't and will not be redefined.
 #define StrCat StrCat
@@ -59,14 +58,12 @@
 // for this call and generate slightly less code. This is something we can
 // explore more in the future.
 
-BASE_EXPORT std::string StrCat(span<const StringPiece> pieces)
-    WARN_UNUSED_RESULT;
-BASE_EXPORT std::u16string StrCat(span<const StringPiece16> pieces)
-    WARN_UNUSED_RESULT;
-BASE_EXPORT std::string StrCat(span<const std::string> pieces)
-    WARN_UNUSED_RESULT;
-BASE_EXPORT std::u16string StrCat(span<const std::u16string> pieces)
-    WARN_UNUSED_RESULT;
+[[nodiscard]] BASE_EXPORT std::string StrCat(span<const StringPiece> pieces);
+[[nodiscard]] BASE_EXPORT std::u16string StrCat(
+    span<const StringPiece16> pieces);
+[[nodiscard]] BASE_EXPORT std::string StrCat(span<const std::string> pieces);
+[[nodiscard]] BASE_EXPORT std::u16string StrCat(
+    span<const std::u16string> pieces);
 
 // Initializer list forwards to the array version.
 inline std::string StrCat(std::initializer_list<StringPiece> pieces) {
@@ -105,7 +102,7 @@
 
 }  // namespace base
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 #include "base/strings/strcat_win.h"
 #endif
 
diff --git a/base/strings/strcat_win.h b/base/strings/strcat_win.h
index 70926bc..e32a7e5 100644
--- a/base/strings/strcat_win.h
+++ b/base/strings/strcat_win.h
@@ -9,7 +9,6 @@
 #include <string>
 
 #include "polyfills/base/base_export.h"
-#include "base/compiler_specific.h"
 #include "base/containers/span.h"
 #include "base/strings/string_piece.h"
 
@@ -25,10 +24,8 @@
   StrAppend(dest, make_span(pieces));
 }
 
-BASE_EXPORT std::wstring StrCat(span<const WStringPiece> pieces)
-    WARN_UNUSED_RESULT;
-BASE_EXPORT std::wstring StrCat(span<const std::wstring> pieces)
-    WARN_UNUSED_RESULT;
+[[nodiscard]] BASE_EXPORT std::wstring StrCat(span<const WStringPiece> pieces);
+[[nodiscard]] BASE_EXPORT std::wstring StrCat(span<const std::wstring> pieces);
 
 inline std::wstring StrCat(std::initializer_list<WStringPiece> pieces) {
   return StrCat(make_span(pieces));
diff --git a/base/strings/string_number_conversions.h b/base/strings/string_number_conversions.h
index d2f8af3..1ef1733 100644
--- a/base/strings/string_number_conversions.h
+++ b/base/strings/string_number_conversions.h
@@ -149,7 +149,7 @@
 
 }  // namespace base
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 #include "base/strings/string_number_conversions_win.h"
 #endif
 
diff --git a/base/strings/string_piece.h b/base/strings/string_piece.h
index f01722d..8d7f2c5 100644
--- a/base/strings/string_piece.h
+++ b/base/strings/string_piece.h
@@ -31,6 +31,7 @@
 
 #include "polyfills/base/base_export.h"
 #include "polyfills/base/check_op.h"
+#include "base/compiler_specific.h"
 #include "base/strings/char_traits.h"
 #include "base/strings/string_piece_forward.h"
 #include "build/build_config.h"
@@ -96,7 +97,7 @@
 // Mirrors the C++17 version of std::basic_string_view<> as closely as possible,
 // except where noted below.
 template <typename CharT, typename Traits>
-class BasicStringPiece {
+class GSL_POINTER BasicStringPiece {
  public:
   using traits_type = Traits;
   using value_type = CharT;
@@ -185,9 +186,7 @@
     return std::numeric_limits<size_type>::max() / sizeof(CharT);
   }
 
-  constexpr bool empty() const noexcept WARN_UNUSED_RESULT {
-    return size() == 0;
-  }
+  [[nodiscard]] constexpr bool empty() const noexcept { return size() == 0; }
 
   constexpr void remove_prefix(size_type n) {
     // Intentional STL deviation: Bounds-check instead of UB.
diff --git a/base/strings/string_piece_forward.h b/base/strings/string_piece_forward.h
index ce7e489..e257528 100644
--- a/base/strings/string_piece_forward.h
+++ b/base/strings/string_piece_forward.h
@@ -7,7 +7,7 @@
 #ifndef BASE_STRINGS_STRING_PIECE_FORWARD_H_
 #define BASE_STRINGS_STRING_PIECE_FORWARD_H_
 
-#include <string>
+#include <iosfwd>
 
 namespace gurl_base {
 
diff --git a/base/strings/string_piece_rust.h b/base/strings/string_piece_rust.h
new file mode 100644
index 0000000..1542c17
--- /dev/null
+++ b/base/strings/string_piece_rust.h
@@ -0,0 +1,38 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRINGS_STRING_PIECE_RUST_H_
+#define BASE_STRINGS_STRING_PIECE_RUST_H_
+
+#include <stdint.h>
+
+#include "base/strings/string_piece.h"
+#include "third_party/rust/cxx/v1/crate/include/cxx.h"
+
+namespace gurl_base {
+
+// Create a Rust str from a gurl_base::BasicStringPiece. This will call std::abort
+// if there is any invalid UTF8. If you're concerned about this, then
+// instead use StringPieceToRustSlice and convert the data to a string on
+// the Rust side (or pass in a std::string).
+inline rust::Str StringPieceToRustStrUTF8(StringPiece string_piece) {
+  return rust::Str(string_piece.data(), string_piece.size());
+}
+
+// Create a Rust slice from a StringPiece. No UTF8 check is performed.
+inline rust::Slice<const uint8_t> StringPieceToRustSlice(
+    StringPiece string_piece) {
+  return rust::Slice<const uint8_t>(
+      reinterpret_cast<const uint8_t*>(string_piece.data()),
+      string_piece.length() * sizeof(StringPiece::value_type));
+}
+
+// Create a StringPiece from a Rust str.
+inline StringPiece RustStrToStringPiece(rust::Str str) {
+  return StringPiece(str.data(), str.size());
+}
+
+}  // namespace base
+
+#endif  // BASE_STRINGS_STRING_PIECE_RUST_H_
diff --git a/base/strings/string_piece_rust_unittest.cc b/base/strings/string_piece_rust_unittest.cc
new file mode 100644
index 0000000..bf860fb
--- /dev/null
+++ b/base/strings/string_piece_rust_unittest.cc
@@ -0,0 +1,30 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/string_piece_rust.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gurl_base {
+namespace {
+
+TEST(BaseStringPieceRustTest, StrRoundTrip) {
+  std::string data = "hello";
+  StringPiece data_piece(data);
+  rust::Str rust_str = StringPieceToRustStrUTF8(data_piece);
+  EXPECT_EQ(5ul, rust_str.length());
+  StringPiece data_piece2 = RustStrToStringPiece(rust_str);
+  EXPECT_EQ(data_piece, data_piece2);
+}
+
+TEST(BaseStringPieceRustTest, StrToSlice) {
+  std::string data = "hello";
+  StringPiece data_piece(data);
+  rust::Slice<const uint8_t> rust_slice = StringPieceToRustSlice(data_piece);
+  EXPECT_EQ(5ul, rust_slice.length());
+  EXPECT_EQ('e', rust_slice[1]);
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/strings/string_split.h b/base/strings/string_split.h
index d7f56a6..b464f08 100644
--- a/base/strings/string_split.h
+++ b/base/strings/string_split.h
@@ -45,16 +45,16 @@
 //
 //   std::vector<std::string> tokens = gurl_base::SplitString(
 //       input, ",;", gurl_base::KEEP_WHITESPACE, gurl_base::SPLIT_WANT_ALL);
-BASE_EXPORT std::vector<std::string> SplitString(StringPiece input,
-                                                 StringPiece separators,
-                                                 WhitespaceHandling whitespace,
-                                                 SplitResult result_type)
-    WARN_UNUSED_RESULT;
-BASE_EXPORT std::vector<std::u16string> SplitString(
+[[nodiscard]] BASE_EXPORT std::vector<std::string> SplitString(
+    StringPiece input,
+    StringPiece separators,
+    WhitespaceHandling whitespace,
+    SplitResult result_type);
+[[nodiscard]] BASE_EXPORT std::vector<std::u16string> SplitString(
     StringPiece16 input,
     StringPiece16 separators,
     WhitespaceHandling whitespace,
-    SplitResult result_type) WARN_UNUSED_RESULT;
+    SplitResult result_type);
 
 // Like SplitString above except it returns a vector of StringPieces which
 // reference the original buffer without copying. Although you have to be
@@ -70,16 +70,16 @@
 //                               gurl_base::KEEP_WHITESPACE,
 //                               gurl_base::SPLIT_WANT_NONEMPTY)) {
 //     ...
-BASE_EXPORT std::vector<StringPiece> SplitStringPiece(
+[[nodiscard]] BASE_EXPORT std::vector<StringPiece> SplitStringPiece(
     StringPiece input,
     StringPiece separators,
     WhitespaceHandling whitespace,
-    SplitResult result_type) WARN_UNUSED_RESULT;
-BASE_EXPORT std::vector<StringPiece16> SplitStringPiece(
+    SplitResult result_type);
+[[nodiscard]] BASE_EXPORT std::vector<StringPiece16> SplitStringPiece(
     StringPiece16 input,
     StringPiece16 separators,
     WhitespaceHandling whitespace,
-    SplitResult result_type) WARN_UNUSED_RESULT;
+    SplitResult result_type);
 
 using StringPairs = std::vector<std::pair<std::string, std::string>>;
 
@@ -102,16 +102,16 @@
 
 // Similar to SplitString, but use a substring delimiter instead of a list of
 // characters that are all possible delimiters.
-BASE_EXPORT std::vector<std::u16string> SplitStringUsingSubstr(
+[[nodiscard]] BASE_EXPORT std::vector<std::u16string> SplitStringUsingSubstr(
     StringPiece16 input,
     StringPiece16 delimiter,
     WhitespaceHandling whitespace,
-    SplitResult result_type) WARN_UNUSED_RESULT;
-BASE_EXPORT std::vector<std::string> SplitStringUsingSubstr(
+    SplitResult result_type);
+[[nodiscard]] BASE_EXPORT std::vector<std::string> SplitStringUsingSubstr(
     StringPiece input,
     StringPiece delimiter,
     WhitespaceHandling whitespace,
-    SplitResult result_type) WARN_UNUSED_RESULT;
+    SplitResult result_type);
 
 // Like SplitStringUsingSubstr above except it returns a vector of StringPieces
 // which reference the original buffer without copying. Although you have to be
@@ -125,20 +125,20 @@
 //                                     gurl_base::KEEP_WHITESPACE,
 //                                     gurl_base::SPLIT_WANT_NONEMPTY)) {
 //     ...
-BASE_EXPORT std::vector<StringPiece16> SplitStringPieceUsingSubstr(
-    StringPiece16 input,
-    StringPiece16 delimiter,
-    WhitespaceHandling whitespace,
-    SplitResult result_type) WARN_UNUSED_RESULT;
-BASE_EXPORT std::vector<StringPiece> SplitStringPieceUsingSubstr(
+[[nodiscard]] BASE_EXPORT std::vector<StringPiece16>
+SplitStringPieceUsingSubstr(StringPiece16 input,
+                            StringPiece16 delimiter,
+                            WhitespaceHandling whitespace,
+                            SplitResult result_type);
+[[nodiscard]] BASE_EXPORT std::vector<StringPiece> SplitStringPieceUsingSubstr(
     StringPiece input,
     StringPiece delimiter,
     WhitespaceHandling whitespace,
-    SplitResult result_type) WARN_UNUSED_RESULT;
+    SplitResult result_type);
 
 }  // namespace base
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 #include "base/strings/string_split_win.h"
 #endif
 
diff --git a/base/strings/string_split_win.h b/base/strings/string_split_win.h
index 850d2ca..74efb5d 100644
--- a/base/strings/string_split_win.h
+++ b/base/strings/string_split_win.h
@@ -9,7 +9,6 @@
 #include <vector>
 
 #include "polyfills/base/base_export.h"
-#include "base/compiler_specific.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_split.h"
 
@@ -17,29 +16,29 @@
 
 // The following section contains overloads of the cross-platform APIs for
 // std::wstring and gurl_base::WStringPiece.
-BASE_EXPORT std::vector<std::wstring> SplitString(WStringPiece input,
-                                                  WStringPiece separators,
-                                                  WhitespaceHandling whitespace,
-                                                  SplitResult result_type)
-    WARN_UNUSED_RESULT;
-
-BASE_EXPORT std::vector<WStringPiece> SplitStringPiece(
+[[nodiscard]] BASE_EXPORT std::vector<std::wstring> SplitString(
     WStringPiece input,
     WStringPiece separators,
     WhitespaceHandling whitespace,
-    SplitResult result_type) WARN_UNUSED_RESULT;
+    SplitResult result_type);
 
-BASE_EXPORT std::vector<std::wstring> SplitStringUsingSubstr(
+[[nodiscard]] BASE_EXPORT std::vector<WStringPiece> SplitStringPiece(
+    WStringPiece input,
+    WStringPiece separators,
+    WhitespaceHandling whitespace,
+    SplitResult result_type);
+
+[[nodiscard]] BASE_EXPORT std::vector<std::wstring> SplitStringUsingSubstr(
     WStringPiece input,
     WStringPiece delimiter,
     WhitespaceHandling whitespace,
-    SplitResult result_type) WARN_UNUSED_RESULT;
+    SplitResult result_type);
 
-BASE_EXPORT std::vector<WStringPiece> SplitStringPieceUsingSubstr(
+[[nodiscard]] BASE_EXPORT std::vector<WStringPiece> SplitStringPieceUsingSubstr(
     WStringPiece input,
     WStringPiece delimiter,
     WhitespaceHandling whitespace,
-    SplitResult result_type) WARN_UNUSED_RESULT;
+    SplitResult result_type);
 
 }  // namespace base
 
diff --git a/base/strings/string_tokenizer_fuzzer.cc b/base/strings/string_tokenizer_fuzzer.cc
index 3aaee7b..b3b046b 100644
--- a/base/strings/string_tokenizer_fuzzer.cc
+++ b/base/strings/string_tokenizer_fuzzer.cc
@@ -6,12 +6,13 @@
 #include <stdint.h>
 
 #include <string>
+#include <tuple>
 
 #include "base/strings/string_tokenizer.h"
 
 void GetAllTokens(gurl_base::StringTokenizer& t) {
   while (t.GetNext()) {
-    (void)t.token();
+    std::ignore = t.token();
   }
 }
 
diff --git a/base/strings/string_util.h b/base/strings/string_util.h
index 5995c2d..5d570e2 100644
--- a/base/strings/string_util.h
+++ b/base/strings/string_util.h
@@ -505,9 +505,9 @@
 
 }  // namespace base
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 #include "base/strings/string_util_win.h"
-#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
 #include "base/strings/string_util_posix.h"
 #else
 #error Define string operations appropriately for your platform
diff --git a/base/strings/stringprintf.cc b/base/strings/stringprintf.cc
index 3f74e07..aed9b04 100644
--- a/base/strings/stringprintf.cc
+++ b/base/strings/stringprintf.cc
@@ -33,7 +33,7 @@
   return gurl_base::vsnprintf(buffer, buf_size, format, argptr);
 }
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 inline int vsnprintfT(wchar_t* buffer,
                       size_t buf_size,
                       const wchar_t* format,
@@ -77,7 +77,7 @@
   int mem_length = gurl_base::size(stack_buf);
   while (true) {
     if (result < 0) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
       // On Windows, vsnprintfT always returns the number of characters in a
       // fully-formatted string, so if we reach this point, something else is
       // wrong and no amount of buffer-doubling is going to fix it.
@@ -128,7 +128,7 @@
   return result;
 }
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 std::wstring StringPrintf(const wchar_t* format, ...) {
   va_list ap;
   va_start(ap, format);
@@ -163,7 +163,7 @@
   return *dst;
 }
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 const std::wstring& SStringPrintf(std::wstring* dst,
                                   const wchar_t* format, ...) {
   va_list ap;
@@ -193,7 +193,7 @@
   va_end(ap);
 }
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 void StringAppendF(std::wstring* dst, const wchar_t* format, ...) {
   va_list ap;
   va_start(ap, format);
@@ -213,7 +213,7 @@
   StringAppendVT(dst, format, ap);
 }
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 void StringAppendV(std::wstring* dst, const wchar_t* format, va_list ap) {
   StringAppendVT(dst, format, ap);
 }
diff --git a/base/strings/stringprintf.h b/base/strings/stringprintf.h
index 5768bcc..b0d473b 100644
--- a/base/strings/stringprintf.h
+++ b/base/strings/stringprintf.h
@@ -16,28 +16,29 @@
 namespace gurl_base {
 
 // Return a C++ string given printf-like input.
-BASE_EXPORT std::string StringPrintf(const char* format, ...)
-    PRINTF_FORMAT(1, 2) WARN_UNUSED_RESULT;
-#if defined(OS_WIN)
+[[nodiscard]] BASE_EXPORT std::string StringPrintf(const char* format, ...)
+    PRINTF_FORMAT(1, 2);
+#if BUILDFLAG(IS_WIN)
 // Note: Unfortunately compile time checking of the format string for UTF-16
 // strings is not supported by any compiler, thus these functions should be used
 // carefully and sparingly. Also applies to SStringPrintf and StringAppendV
 // below.
-BASE_EXPORT std::wstring StringPrintf(const wchar_t* format, ...)
-    WPRINTF_FORMAT(1, 2) WARN_UNUSED_RESULT;
-BASE_EXPORT std::u16string StringPrintf(const char16_t* format, ...)
-    WPRINTF_FORMAT(1, 2) WARN_UNUSED_RESULT;
+[[nodiscard]] BASE_EXPORT std::wstring StringPrintf(const wchar_t* format, ...)
+    WPRINTF_FORMAT(1, 2);
+[[nodiscard]] BASE_EXPORT std::u16string StringPrintf(const char16_t* format,
+                                                      ...) WPRINTF_FORMAT(1, 2);
 #endif
 
 // Return a C++ string given vprintf-like input.
-BASE_EXPORT std::string StringPrintV(const char* format, va_list ap)
-    PRINTF_FORMAT(1, 0) WARN_UNUSED_RESULT;
+[[nodiscard]] BASE_EXPORT std::string StringPrintV(const char* format,
+                                                   va_list ap)
+    PRINTF_FORMAT(1, 0);
 
 // Store result into a supplied string and return it.
 BASE_EXPORT const std::string& SStringPrintf(std::string* dst,
                                              const char* format,
                                              ...) PRINTF_FORMAT(2, 3);
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 BASE_EXPORT const std::wstring& SStringPrintf(std::wstring* dst,
                                               const wchar_t* format,
                                               ...) WPRINTF_FORMAT(2, 3);
@@ -49,7 +50,7 @@
 // Append result to a supplied string.
 BASE_EXPORT void StringAppendF(std::string* dst, const char* format, ...)
     PRINTF_FORMAT(2, 3);
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 BASE_EXPORT void StringAppendF(std::wstring* dst, const wchar_t* format, ...)
     WPRINTF_FORMAT(2, 3);
 BASE_EXPORT void StringAppendF(std::u16string* dst, const char16_t* format, ...)
@@ -60,7 +61,7 @@
 // string.  All other routines are just convenience wrappers around it.
 BASE_EXPORT void StringAppendV(std::string* dst, const char* format, va_list ap)
     PRINTF_FORMAT(2, 0);
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 BASE_EXPORT void StringAppendV(std::wstring* dst,
                                const wchar_t* format,
                                va_list ap) WPRINTF_FORMAT(2, 0);
diff --git a/base/strings/stringprintf_unittest.cc b/base/strings/stringprintf_unittest.cc
index 9da8861..334d0ba 100644
--- a/base/strings/stringprintf_unittest.cc
+++ b/base/strings/stringprintf_unittest.cc
@@ -35,7 +35,7 @@
 
 TEST(StringPrintfTest, StringPrintfMisc) {
   EXPECT_EQ("123hello w", StringPrintf("%3d%2s %1c", 123, "hello", 'w'));
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
   EXPECT_EQ(L"123hello w", StringPrintf(L"%3d%2ls %1lc", 123, L"hello", 'w'));
   EXPECT_EQ(u"123hello w", StringPrintf(u"%3d%2ls %1lc", 123, u"hello", 'w'));
 #endif
@@ -46,7 +46,7 @@
   StringAppendF(&value, "%s", "");
   EXPECT_EQ("Hello", value);
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
   std::wstring valuew(L"Hello");
   StringAppendF(&valuew, L"%ls", L"");
   EXPECT_EQ(L"Hello", valuew);
@@ -62,7 +62,7 @@
   StringAppendF(&value, " %s", "World");
   EXPECT_EQ("Hello World", value);
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
   std::wstring valuew(L"Hello");
   StringAppendF(&valuew, L" %ls", L"World");
   EXPECT_EQ(L"Hello World", valuew);
@@ -78,7 +78,7 @@
   StringAppendF(&value, " %d", 123);
   EXPECT_EQ("Hello 123", value);
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
   std::wstring valuew(L"Hello");
   StringAppendF(&valuew, L" %d", 123);
   EXPECT_EQ(L"Hello 123", valuew);
@@ -108,7 +108,7 @@
     SStringPrintf(&out, "%s", src);
     EXPECT_STREQ(src, out.c_str());
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
     srcw[kSrcLen - i] = 0;
     std::wstring outw;
     SStringPrintf(&outw, L"%ls", srcw);
@@ -139,9 +139,9 @@
 
   const int kRefSize = 320000;
   char* ref = new char[kRefSize];
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
   sprintf_s(ref, kRefSize, fmt, src, src, src, src, src, src, src);
-#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
   snprintf(ref, kRefSize, fmt, src, src, src, src, src, src, src);
 #endif
 
@@ -154,7 +154,7 @@
   StringAppendVTestHelper(&out, "%d foo %s", 1, "bar");
   EXPECT_EQ("1 foo bar", out);
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
   std::wstring outw;
   StringAppendVTestHelper(&outw, L"%d foo %ls", 1, L"bar");
   EXPECT_EQ(L"1 foo bar", outw);
@@ -184,7 +184,7 @@
   EXPECT_STREQ(src, out.c_str());
 }
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 TEST(StringPrintfTest, Invalid) {
   wchar_t invalid[2];
   invalid[0] = 0xffff;
diff --git a/base/strings/sys_string_conversions.h b/base/strings/sys_string_conversions.h
index 51977fe..d80b178 100644
--- a/base/strings/sys_string_conversions.h
+++ b/base/strings/sys_string_conversions.h
@@ -17,79 +17,76 @@
 #include "base/strings/string_piece.h"
 #include "build/build_config.h"
 
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
 #include <CoreFoundation/CoreFoundation.h>
 
 #include "base/mac/scoped_cftyperef.h"
 
 #ifdef __OBJC__
 @class NSString;
-#else
-class NSString;
 #endif
-#endif  // OS_APPLE
+#endif  // BUILDFLAG(IS_APPLE)
 
 namespace gurl_base {
 
 // Converts between wide and UTF-8 representations of a string. On error, the
 // result is system-dependent.
-BASE_EXPORT std::string SysWideToUTF8(const std::wstring& wide)
-    WARN_UNUSED_RESULT;
-BASE_EXPORT std::wstring SysUTF8ToWide(StringPiece utf8) WARN_UNUSED_RESULT;
+[[nodiscard]] BASE_EXPORT std::string SysWideToUTF8(const std::wstring& wide);
+[[nodiscard]] BASE_EXPORT std::wstring SysUTF8ToWide(StringPiece utf8);
 
 // Converts between wide and the system multi-byte representations of a string.
 // DANGER: This will lose information and can change (on Windows, this can
 // change between reboots).
-BASE_EXPORT std::string SysWideToNativeMB(const std::wstring& wide)
-    WARN_UNUSED_RESULT;
-BASE_EXPORT std::wstring SysNativeMBToWide(StringPiece native_mb)
-    WARN_UNUSED_RESULT;
+[[nodiscard]] BASE_EXPORT std::string SysWideToNativeMB(
+    const std::wstring& wide);
+[[nodiscard]] BASE_EXPORT std::wstring SysNativeMBToWide(StringPiece native_mb);
 
 // Windows-specific ------------------------------------------------------------
 
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
 
 // Converts between 8-bit and wide strings, using the given code page. The
 // code page identifier is one accepted by the Windows function
 // MultiByteToWideChar().
-BASE_EXPORT std::wstring SysMultiByteToWide(StringPiece mb, uint32_t code_page)
-    WARN_UNUSED_RESULT;
-BASE_EXPORT std::string SysWideToMultiByte(const std::wstring& wide,
-                                           uint32_t code_page)
-    WARN_UNUSED_RESULT;
+[[nodiscard]] BASE_EXPORT std::wstring SysMultiByteToWide(StringPiece mb,
+                                                          uint32_t code_page);
+[[nodiscard]] BASE_EXPORT std::string SysWideToMultiByte(
+    const std::wstring& wide,
+    uint32_t code_page);
 
-#endif  // defined(OS_WIN)
+#endif  // BUILDFLAG(IS_WIN)
 
 // Mac-specific ----------------------------------------------------------------
 
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
 
-// Converts between STL strings and CFStringRefs/NSStrings.
+// Converts between strings and CFStringRefs/NSStrings.
 
-// Creates a string, and returns it with a refcount of 1. You are responsible
-// for releasing it. Returns NULL on failure.
-BASE_EXPORT ScopedCFTypeRef<CFStringRef> SysUTF8ToCFStringRef(StringPiece utf8)
-    WARN_UNUSED_RESULT;
-BASE_EXPORT ScopedCFTypeRef<CFStringRef> SysUTF16ToCFStringRef(
-    StringPiece16 utf16) WARN_UNUSED_RESULT;
+// Converts a string to a CFStringRef. Returns null on failure.
+[[nodiscard]] BASE_EXPORT ScopedCFTypeRef<CFStringRef> SysUTF8ToCFStringRef(
+    StringPiece utf8);
+[[nodiscard]] BASE_EXPORT ScopedCFTypeRef<CFStringRef> SysUTF16ToCFStringRef(
+    StringPiece16 utf16);
 
-// Same, but returns an autoreleased NSString.
-BASE_EXPORT NSString* SysUTF8ToNSString(StringPiece utf8) WARN_UNUSED_RESULT;
-BASE_EXPORT NSString* SysUTF16ToNSString(StringPiece16 utf16)
-    WARN_UNUSED_RESULT;
+// Converts a CFStringRef to a string. Returns an empty string on failure. It is
+// not valid to call these with a null `ref`.
+[[nodiscard]] BASE_EXPORT std::string SysCFStringRefToUTF8(CFStringRef ref);
+[[nodiscard]] BASE_EXPORT std::u16string SysCFStringRefToUTF16(CFStringRef ref);
 
-// Converts a CFStringRef to an STL string. Returns an empty string on failure.
-BASE_EXPORT std::string SysCFStringRefToUTF8(CFStringRef ref)
-    WARN_UNUSED_RESULT;
-BASE_EXPORT std::u16string SysCFStringRefToUTF16(CFStringRef ref)
-    WARN_UNUSED_RESULT;
+#ifdef __OBJC__
 
-// Same, but accepts NSString input. Converts nil NSString* to the appropriate
-// string type of length 0.
-BASE_EXPORT std::string SysNSStringToUTF8(NSString* ref) WARN_UNUSED_RESULT;
-BASE_EXPORT std::u16string SysNSStringToUTF16(NSString* ref) WARN_UNUSED_RESULT;
+// Converts a string to an autoreleased NSString. Returns nil on failure.
+[[nodiscard]] BASE_EXPORT NSString* SysUTF8ToNSString(StringPiece utf8);
+[[nodiscard]] BASE_EXPORT NSString* SysUTF16ToNSString(StringPiece16 utf16);
 
-#endif  // defined(OS_APPLE)
+// Converts an NSString to a string. Returns an empty string on failure or if
+// `ref` is nil.
+[[nodiscard]] BASE_EXPORT std::string SysNSStringToUTF8(NSString* ref);
+[[nodiscard]] BASE_EXPORT std::u16string SysNSStringToUTF16(NSString* ref);
+
+#endif  // __OBJC__
+
+#endif  // BUILDFLAG(IS_APPLE)
 
 }  // namespace base
 
diff --git a/base/strings/sys_string_conversions_posix.cc b/base/strings/sys_string_conversions_posix.cc
index f9f7312..02535ed 100644
--- a/base/strings/sys_string_conversions_posix.cc
+++ b/base/strings/sys_string_conversions_posix.cc
@@ -27,7 +27,7 @@
   return out;
 }
 
-#if defined(SYSTEM_NATIVE_UTF8) || defined(OS_ANDROID)
+#if defined(SYSTEM_NATIVE_UTF8) || BUILDFLAG(IS_ANDROID)
 // TODO(port): Consider reverting the OS_ANDROID when we have wcrtomb()
 // support and a better understanding of what calls these routines.
 
@@ -116,7 +116,7 @@
       case 0:
         // We hit an embedded null byte, keep going.
         i += 1;
-        FALLTHROUGH;
+        [[fallthrough]];
       default:
         i += res;
         ++num_out_chars;
@@ -154,6 +154,6 @@
   return out;
 }
 
-#endif  // defined(SYSTEM_NATIVE_UTF8) || defined(OS_ANDROID)
+#endif  // defined(SYSTEM_NATIVE_UTF8) || BUILDFLAG(IS_ANDROID)
 
 }  // namespace base
diff --git a/base/strings/sys_string_conversions_unittest.cc b/base/strings/sys_string_conversions_unittest.cc
index 95995c6..01bceb0 100644
--- a/base/strings/sys_string_conversions_unittest.cc
+++ b/base/strings/sys_string_conversions_unittest.cc
@@ -75,7 +75,7 @@
 }
 
 // Tests depend on setting a specific Linux locale.
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
 TEST(SysStrings, SysWideToNativeMB) {
 #if !defined(SYSTEM_NATIVE_UTF8)
   ScopedLocale locale("en_US.UTF-8");
@@ -190,6 +190,6 @@
     EXPECT_EQ(wide, trip);
   }
 }
-#endif  // defined(OS_LINUX) || defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
 
 }  // namespace base
diff --git a/base/strings/utf_offset_string_conversions.h b/base/strings/utf_offset_string_conversions.h
index aa4e59e..3b2904d 100644
--- a/base/strings/utf_offset_string_conversions.h
+++ b/base/strings/utf_offset_string_conversions.h
@@ -96,9 +96,9 @@
     size_t src_len,
     std::u16string* output,
     gurl_base::OffsetAdjuster::Adjustments* adjustments);
-BASE_EXPORT std::u16string UTF8ToUTF16WithAdjustments(
+[[nodiscard]] BASE_EXPORT std::u16string UTF8ToUTF16WithAdjustments(
     const gurl_base::StringPiece& utf8,
-    gurl_base::OffsetAdjuster::Adjustments* adjustments) WARN_UNUSED_RESULT;
+    gurl_base::OffsetAdjuster::Adjustments* adjustments);
 // As above, but instead internally examines the adjustments and applies them
 // to |offsets_for_adjustment|.  Input offsets greater than the length of the
 // input string will be set to std::u16string::npos.  See comments by
diff --git a/base/strings/utf_string_conversion_utils.cc b/base/strings/utf_string_conversion_utils.cc
index da68dd3..9a4b4ca 100644
--- a/base/strings/utf_string_conversion_utils.cc
+++ b/base/strings/utf_string_conversion_utils.cc
@@ -122,7 +122,7 @@
 }
 
 // Instantiate versions we know callers will need.
-#if !defined(OS_WIN)
+#if !BUILDFLAG(IS_WIN)
 // wchar_t and char16_t are the same thing on Windows.
 template void PrepareForUTF8Output(const wchar_t*, size_t, std::string*);
 #endif
@@ -146,7 +146,7 @@
 }
 
 // Instantiate versions we know callers will need.
-#if !defined(OS_WIN)
+#if !BUILDFLAG(IS_WIN)
 // std::wstring and std::u16string are the same thing on Windows.
 template void PrepareForUTF16Or32Output(const char*, size_t, std::wstring*);
 #endif
diff --git a/base/strings/utf_string_conversions.h b/base/strings/utf_string_conversions.h
index ffb56e4..77dc194 100644
--- a/base/strings/utf_string_conversions.h
+++ b/base/strings/utf_string_conversions.h
@@ -23,45 +23,45 @@
 // possible.
 BASE_EXPORT bool WideToUTF8(const wchar_t* src, size_t src_len,
                             std::string* output);
-BASE_EXPORT std::string WideToUTF8(WStringPiece wide) WARN_UNUSED_RESULT;
+[[nodiscard]] BASE_EXPORT std::string WideToUTF8(WStringPiece wide);
 BASE_EXPORT bool UTF8ToWide(const char* src, size_t src_len,
                             std::wstring* output);
-BASE_EXPORT std::wstring UTF8ToWide(StringPiece utf8) WARN_UNUSED_RESULT;
+[[nodiscard]] BASE_EXPORT std::wstring UTF8ToWide(StringPiece utf8);
 
 BASE_EXPORT bool WideToUTF16(const wchar_t* src,
                              size_t src_len,
                              std::u16string* output);
-BASE_EXPORT std::u16string WideToUTF16(WStringPiece wide) WARN_UNUSED_RESULT;
+[[nodiscard]] BASE_EXPORT std::u16string WideToUTF16(WStringPiece wide);
 BASE_EXPORT bool UTF16ToWide(const char16_t* src,
                              size_t src_len,
                              std::wstring* output);
-BASE_EXPORT std::wstring UTF16ToWide(StringPiece16 utf16) WARN_UNUSED_RESULT;
+[[nodiscard]] BASE_EXPORT std::wstring UTF16ToWide(StringPiece16 utf16);
 
 BASE_EXPORT bool UTF8ToUTF16(const char* src,
                              size_t src_len,
                              std::u16string* output);
-BASE_EXPORT std::u16string UTF8ToUTF16(StringPiece utf8) WARN_UNUSED_RESULT;
+[[nodiscard]] BASE_EXPORT std::u16string UTF8ToUTF16(StringPiece utf8);
 BASE_EXPORT bool UTF16ToUTF8(const char16_t* src,
                              size_t src_len,
                              std::string* output);
-BASE_EXPORT std::string UTF16ToUTF8(StringPiece16 utf16) WARN_UNUSED_RESULT;
+[[nodiscard]] BASE_EXPORT std::string UTF16ToUTF8(StringPiece16 utf16);
 
 // This converts an ASCII string, typically a hardcoded constant, to a UTF16
 // string.
-BASE_EXPORT std::u16string ASCIIToUTF16(StringPiece ascii) WARN_UNUSED_RESULT;
+[[nodiscard]] BASE_EXPORT std::u16string ASCIIToUTF16(StringPiece ascii);
 
 // Converts to 7-bit ASCII by truncating. The result must be known to be ASCII
 // beforehand.
-BASE_EXPORT std::string UTF16ToASCII(StringPiece16 utf16) WARN_UNUSED_RESULT;
+[[nodiscard]] BASE_EXPORT std::string UTF16ToASCII(StringPiece16 utf16);
 
 #if defined(WCHAR_T_IS_UTF16)
 // This converts an ASCII string, typically a hardcoded constant, to a wide
 // string.
-BASE_EXPORT std::wstring ASCIIToWide(StringPiece ascii) WARN_UNUSED_RESULT;
+[[nodiscard]] BASE_EXPORT std::wstring ASCIIToWide(StringPiece ascii);
 
 // Converts to 7-bit ASCII by truncating. The result must be known to be ASCII
 // beforehand.
-BASE_EXPORT std::string WideToASCII(WStringPiece wide) WARN_UNUSED_RESULT;
+[[nodiscard]] BASE_EXPORT std::string WideToASCII(WStringPiece wide);
 #endif  // defined(WCHAR_T_IS_UTF16)
 
 // The conversion functions in this file should not be used to convert string
diff --git a/base/strings/utf_string_conversions_fuzzer.cc b/base/strings/utf_string_conversions_fuzzer.cc
index 932012a..7bae707 100644
--- a/base/strings/utf_string_conversions_fuzzer.cc
+++ b/base/strings/utf_string_conversions_fuzzer.cc
@@ -2,7 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/macros.h"
+#include <tuple>
+
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 
@@ -15,10 +16,10 @@
   gurl_base::StringPiece string_piece_input(reinterpret_cast<const char*>(data),
                                        size);
 
-  ignore_result(gurl_base::UTF8ToWide(string_piece_input));
+  std::ignore = gurl_base::UTF8ToWide(string_piece_input);
   gurl_base::UTF8ToWide(reinterpret_cast<const char*>(data), size,
                    &output_std_wstring);
-  ignore_result(gurl_base::UTF8ToUTF16(string_piece_input));
+  std::ignore = gurl_base::UTF8ToUTF16(string_piece_input);
   gurl_base::UTF8ToUTF16(reinterpret_cast<const char*>(data), size,
                     &output_string16);
 
@@ -26,10 +27,10 @@
   if (size % 2 == 0) {
     gurl_base::StringPiece16 string_piece_input16(
         reinterpret_cast<const char16_t*>(data), size / 2);
-    ignore_result(gurl_base::UTF16ToWide(output_string16));
+    std::ignore = gurl_base::UTF16ToWide(output_string16);
     gurl_base::UTF16ToWide(reinterpret_cast<const char16_t*>(data), size / 2,
                       &output_std_wstring);
-    ignore_result(gurl_base::UTF16ToUTF8(string_piece_input16));
+    std::ignore = gurl_base::UTF16ToUTF8(string_piece_input16);
     gurl_base::UTF16ToUTF8(reinterpret_cast<const char16_t*>(data), size / 2,
                       &output_std_string);
   }
@@ -37,10 +38,10 @@
   // Test for wchar_t.
   size_t wchar_t_size = sizeof(wchar_t);
   if (size % wchar_t_size == 0) {
-    ignore_result(gurl_base::WideToUTF8(output_std_wstring));
+    std::ignore = gurl_base::WideToUTF8(output_std_wstring);
     gurl_base::WideToUTF8(reinterpret_cast<const wchar_t*>(data),
                      size / wchar_t_size, &output_std_string);
-    ignore_result(gurl_base::WideToUTF16(output_std_wstring));
+    std::ignore = gurl_base::WideToUTF16(output_std_wstring);
     gurl_base::WideToUTF16(reinterpret_cast<const wchar_t*>(data),
                       size / wchar_t_size, &output_string16);
   }
@@ -50,7 +51,7 @@
   if (gurl_base::IsStringASCII(string_piece_input)) {
     output_string16 = gurl_base::ASCIIToUTF16(string_piece_input);
     gurl_base::StringPiece16 string_piece_input16(output_string16);
-    ignore_result(gurl_base::UTF16ToASCII(string_piece_input16));
+    std::ignore = gurl_base::UTF16ToASCII(string_piece_input16);
   }
 
   return 0;
diff --git a/base/template_util.h b/base/template_util.h
index d0803f8..3d954fd 100644
--- a/base/template_util.h
+++ b/base/template_util.h
@@ -12,7 +12,6 @@
 #include <utility>
 
 #include "base/compiler_specific.h"
-#include "build/build_config.h"
 
 #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ <= 7
 #include <vector>
@@ -247,7 +246,7 @@
 // [1] https://en.cppreference.com/w/cpp/types/result_of
 // [2] https://wg21.link/meta.trans.other#lib:invoke_result
 template <typename Functor, typename... Args>
-using invoke_result = std::result_of<Functor && (Args && ...)>;
+using invoke_result = std::invoke_result<Functor, Args...>;
 
 // Implementation of C++17's std::invoke_result_t.
 //
diff --git a/build/BUILD b/build/BUILD
index 79fa1dd..5b560c9 100644
--- a/build/BUILD
+++ b/build/BUILD
@@ -10,3 +10,10 @@
     copts = build_config.default_copts,
     visibility = ["//visibility:public"],
 )
+
+cc_library(
+    name = "buildflag",
+    hdrs = ["buildflag.h"],
+    copts = build_config.default_copts,
+    visibility = ["//visibility:public"],
+)
diff --git a/build/build_config.h b/build/build_config.h
index 63cec87..0102a93 100644
--- a/build/build_config.h
+++ b/build/build_config.h
@@ -2,33 +2,46 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// This file adds defines about the platform we're currently building on.
+// This file doesn't belong to any GN target by design for faster build and
+// less developer overhead.
+
+// This file adds build flags about the OS we're currently building on. They are
+// defined directly in this file instead of via a `buildflag_header` target in a
+// GN file for faster build. They are defined using the corresponding OS defines
+// (e.g. OS_WIN) which are also defined in this file (except for OS_CHROMEOS,
+// which is set by the build system). These defines are deprecated and should
+// NOT be used directly. For example:
+//    Please Use: #if BUILDFLAG(IS_WIN)
+//    Deprecated: #if defined(OS_WIN)
 //
 //  Operating System:
-//    OS_AIX / OS_ANDROID / OS_ASMJS / OS_FREEBSD / OS_FUCHSIA / OS_IOS /
-//    OS_LINUX / OS_MAC / OS_NACL (SFI or NONSFI) / OS_NETBSD / OS_OPENBSD /
-//    OS_QNX / OS_SOLARIS / OS_WIN
+//    IS_AIX / IS_ANDROID / IS_ASMJS / IS_CHROMEOS / IS_FREEBSD / IS_FUCHSIA /
+//    IS_IOS / IS_LINUX / IS_MAC / IS_NACL / IS_NETBSD / IS_OPENBSD / IS_QNX /
+//    IS_SOLARIS / IS_WIN
 //  Operating System family:
-//    OS_APPLE: IOS or MAC
-//    OS_BSD: FREEBSD or NETBSD or OPENBSD
-//    OS_POSIX: AIX or ANDROID or ASMJS or CHROMEOS or FREEBSD or IOS or LINUX
+//    IS_APPLE: IOS or MAC
+//    IS_BSD: FREEBSD or NETBSD or OPENBSD
+//    IS_POSIX: AIX or ANDROID or ASMJS or CHROMEOS or FREEBSD or IOS or LINUX
 //              or MAC or NACL or NETBSD or OPENBSD or QNX or SOLARIS
-//
-//  /!\ Note: OS_CHROMEOS is set by the build system, not this file
+
+// This file also adds defines specific to the platform, architecture etc.
 //
 //  Compiler:
 //    COMPILER_MSVC / COMPILER_GCC
 //
 //  Processor:
-//    ARCH_CPU_ARM64 / ARCH_CPU_ARMEL / ARCH_CPU_MIPS / ARCH_CPU_MIPS64 /
-//    ARCH_CPU_MIPS64EL / ARCH_CPU_MIPSEL / ARCH_CPU_PPC64 / ARCH_CPU_S390 /
-//    ARCH_CPU_S390X / ARCH_CPU_X86 / ARCH_CPU_X86_64
+//    ARCH_CPU_ARM64 / ARCH_CPU_ARMEL / ARCH_CPU_LOONG32 / ARCH_CPU_LOONG64 /
+//    ARCH_CPU_MIPS / ARCH_CPU_MIPS64 / ARCH_CPU_MIPS64EL / ARCH_CPU_MIPSEL /
+//    ARCH_CPU_PPC64 / ARCH_CPU_S390 / ARCH_CPU_S390X / ARCH_CPU_X86 /
+//    ARCH_CPU_X86_64 / ARCH_CPU_RISCV64
 //  Processor family:
 //    ARCH_CPU_ARM_FAMILY: ARMEL or ARM64
+//    ARCH_CPU_LOONG_FAMILY: LOONG32 or LOONG64
 //    ARCH_CPU_MIPS_FAMILY: MIPS64EL or MIPSEL or MIPS64 or MIPS
 //    ARCH_CPU_PPC64_FAMILY: PPC64
 //    ARCH_CPU_S390_FAMILY: S390 or S390X
 //    ARCH_CPU_X86_FAMILY: X86 or X86_64
+//    ARCH_CPU_RISCV_FAMILY: Riscv64
 //  Processor features:
 //    ARCH_CPU_31_BITS / ARCH_CPU_32_BITS / ARCH_CPU_64_BITS
 //    ARCH_CPU_BIG_ENDIAN / ARCH_CPU_LITTLE_ENDIAN
@@ -36,18 +49,12 @@
 #ifndef BUILD_BUILD_CONFIG_H_
 #define BUILD_BUILD_CONFIG_H_
 
+#include "build/buildflag.h"
+
 // A set of macros to use for platform detection.
 #if defined(__native_client__)
 // __native_client__ must be first, so that other OS_ defines are not set.
 #define OS_NACL 1
-// OS_NACL comes in two sandboxing technology flavors, SFI or Non-SFI.
-// PNaCl toolchain defines __native_client_nonsfi__ macro in Non-SFI build
-// mode, while it does not in SFI build mode.
-#if defined(__native_client_nonsfi__)
-#define OS_NACL_NONSFI
-#else
-#define OS_NACL_SFI
-#endif
 #elif defined(ANDROID)
 #define OS_ANDROID 1
 #elif defined(__APPLE__)
@@ -67,7 +74,7 @@
 #define OS_LINUX 1
 #endif  // !defined(OS_CHROMEOS)
 // Include a system header to pull in features.h for glibc/uclibc macros.
-#include <unistd.h>
+#include <assert.h>
 #if defined(__GLIBC__) && !defined(__UCLIBC__)
 // We really are using glibc, not uClibc pretending to be glibc.
 #define LIBC_GLIBC 1
@@ -118,6 +125,115 @@
 #define OS_POSIX 1
 #endif
 
+// OS build flags
+#if defined(OS_AIX)
+#define BUILDFLAG_INTERNAL_IS_AIX() (1)
+#else
+#define BUILDFLAG_INTERNAL_IS_AIX() (0)
+#endif
+
+#if defined(OS_ANDROID)
+#define BUILDFLAG_INTERNAL_IS_ANDROID() (1)
+#else
+#define BUILDFLAG_INTERNAL_IS_ANDROID() (0)
+#endif
+
+#if defined(OS_APPLE)
+#define BUILDFLAG_INTERNAL_IS_APPLE() (1)
+#else
+#define BUILDFLAG_INTERNAL_IS_APPLE() (0)
+#endif
+
+#if defined(OS_ASMJS)
+#define BUILDFLAG_INTERNAL_IS_ASMJS() (1)
+#else
+#define BUILDFLAG_INTERNAL_IS_ASMJS() (0)
+#endif
+
+#if defined(OS_BSD)
+#define BUILDFLAG_INTERNAL_IS_BSD() (1)
+#else
+#define BUILDFLAG_INTERNAL_IS_BSD() (0)
+#endif
+
+#if defined(OS_CHROMEOS)
+#define BUILDFLAG_INTERNAL_IS_CHROMEOS() (1)
+#else
+#define BUILDFLAG_INTERNAL_IS_CHROMEOS() (0)
+#endif
+
+#if defined(OS_FREEBSD)
+#define BUILDFLAG_INTERNAL_IS_FREEBSD() (1)
+#else
+#define BUILDFLAG_INTERNAL_IS_FREEBSD() (0)
+#endif
+
+#if defined(OS_FUCHSIA)
+#define BUILDFLAG_INTERNAL_IS_FUCHSIA() (1)
+#else
+#define BUILDFLAG_INTERNAL_IS_FUCHSIA() (0)
+#endif
+
+#if defined(OS_IOS)
+#define BUILDFLAG_INTERNAL_IS_IOS() (1)
+#else
+#define BUILDFLAG_INTERNAL_IS_IOS() (0)
+#endif
+
+#if defined(OS_LINUX)
+#define BUILDFLAG_INTERNAL_IS_LINUX() (1)
+#else
+#define BUILDFLAG_INTERNAL_IS_LINUX() (0)
+#endif
+
+#if defined(OS_MAC)
+#define BUILDFLAG_INTERNAL_IS_MAC() (1)
+#else
+#define BUILDFLAG_INTERNAL_IS_MAC() (0)
+#endif
+
+#if defined(OS_NACL)
+#define BUILDFLAG_INTERNAL_IS_NACL() (1)
+#else
+#define BUILDFLAG_INTERNAL_IS_NACL() (0)
+#endif
+
+#if defined(OS_NETBSD)
+#define BUILDFLAG_INTERNAL_IS_NETBSD() (1)
+#else
+#define BUILDFLAG_INTERNAL_IS_NETBSD() (0)
+#endif
+
+#if defined(OS_OPENBSD)
+#define BUILDFLAG_INTERNAL_IS_OPENBSD() (1)
+#else
+#define BUILDFLAG_INTERNAL_IS_OPENBSD() (0)
+#endif
+
+#if defined(OS_POSIX)
+#define BUILDFLAG_INTERNAL_IS_POSIX() (1)
+#else
+#define BUILDFLAG_INTERNAL_IS_POSIX() (0)
+#endif
+
+#if defined(OS_QNX)
+#define BUILDFLAG_INTERNAL_IS_QNX() (1)
+#else
+#define BUILDFLAG_INTERNAL_IS_QNX() (0)
+#endif
+
+#if defined(OS_SOLARIS)
+#define BUILDFLAG_INTERNAL_IS_SOLARIS() (1)
+#else
+#define BUILDFLAG_INTERNAL_IS_SOLARIS() (0)
+#endif
+
+#if defined(OS_WIN)
+#define BUILDFLAG_INTERNAL_IS_WIN() (1)
+#else
+#define BUILDFLAG_INTERNAL_IS_WIN() (0)
+#endif
+
 // Compiler detection. Note: clang masquerades as GCC on POSIX and as MSVC on
 // Windows.
 #if defined(__GNUC__)
@@ -199,6 +315,21 @@
 #define ARCH_CPU_32_BITS 1
 #define ARCH_CPU_BIG_ENDIAN 1
 #endif
+#elif defined(__loongarch32)
+#define ARCH_CPU_LOONG_FAMILY 1
+#define ARCH_CPU_LOONG32 1
+#define ARCH_CPU_32_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
+#elif defined(__loongarch64)
+#define ARCH_CPU_LOONG_FAMILY 1
+#define ARCH_CPU_LOONG64 1
+#define ARCH_CPU_64_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
+#elif defined(__riscv) && (__riscv_xlen == 64)
+#define ARCH_CPU_RISCV_FAMILY 1
+#define ARCH_CPU_RISCV64 1
+#define ARCH_CPU_64_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
 #else
 #error Please add support for your architecture in build/build_config.h
 #endif
diff --git a/build/buildflag.h b/build/buildflag.h
new file mode 100644
index 0000000..5776a75
--- /dev/null
+++ b/build/buildflag.h
@@ -0,0 +1,47 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BUILD_BUILDFLAG_H_
+#define BUILD_BUILDFLAG_H_
+
+// These macros un-mangle the names of the build flags in a way that looks
+// natural, and gives errors if the flag is not defined. Normally in the
+// preprocessor it's easy to make mistakes that interpret "you haven't done
+// the setup to know what the flag is" as "flag is off". Normally you would
+// include the generated header rather than include this file directly.
+//
+// This is for use with generated headers. See build/buildflag_header.gni.
+
+// This dance of two macros does a concatenation of two preprocessor args using
+// ## doubly indirectly because using ## directly prevents macros in that
+// parameter from being expanded.
+#define BUILDFLAG_CAT_INDIRECT(a, b) a ## b
+#define BUILDFLAG_CAT(a, b) BUILDFLAG_CAT_INDIRECT(a, b)
+
+// Accessor for build flags.
+//
+// To test for a value, if the build file specifies:
+//
+//   ENABLE_FOO=true
+//
+// Then you would check at build-time in source code with:
+//
+//   #include "foo_flags.h"  // The header the build file specified.
+//
+//   #if BUILDFLAG(ENABLE_FOO)
+//     ...
+//   #endif
+//
+// There will no #define called ENABLE_FOO so if you accidentally test for
+// whether that is defined, it will always be negative. You can also use
+// the value in expressions:
+//
+//   const char kSpamServerName[] = BUILDFLAG(SPAM_SERVER_NAME);
+//
+// Because the flag is accessed as a preprocessor macro with (), an error
+// will be thrown if the proper header defining the internal flag value has
+// not been included.
+#define BUILDFLAG(flag) (BUILDFLAG_CAT(BUILDFLAG_INTERNAL_, flag)())
+
+#endif  // BUILD_BUILDFLAG_H_
diff --git a/build_config/build_config.bzl b/build_config/build_config.bzl
index 117bc96..3deb9d1 100644
--- a/build_config/build_config.bzl
+++ b/build_config/build_config.bzl
@@ -11,8 +11,8 @@
 })
 
 _strings_hdrs = select({
-    "//build_config:windows_x86_64": ["string_util_win.h"],
-    "//conditions:default": ["string_util_posix.h"],
+    "//build_config:windows_x86_64": ["strings/string_util_win.h"],
+    "//conditions:default": ["strings/string_util_posix.h"],
 })
 
 _url_linkopts = select({
diff --git a/copy.bara.sky b/copy.bara.sky
index ffe4f61..6bf0772 100644
--- a/copy.bara.sky
+++ b/copy.bara.sky
@@ -20,10 +20,12 @@
         "base/containers/util.h",
         "base/cxx17_backports.h",
         "base/cxx20_to_address.h",
+        "base/debug/crash_logging.cc",
+        "base/debug/crash_logging.h",
         "base/debug/leak_annotations.h",
         "base/functional/*.h",
         "base/i18n/uchar.h",
-        "base/macros.h",
+        "base/memory/raw_ptr.h",
         "base/no_destructor.h",
         "base/ranges/*.h",
         "base/stl_util.h",
@@ -32,6 +34,7 @@
         "base/template_util.h",
         "base/third_party/icu/**",
         "build/build_config.h",
+        "build/buildflag.h",
         "url/*.cc",
         "url/*.h",
         "url/third_party/mozilla/**",
@@ -57,10 +60,13 @@
 # Those headers are pulled from //polyfill instead of copied from Chromium.
 # Should be in sync with //polyfill/BUILD.
 polyfilled_headers = [
+    "base/allocator/buildflags.h",
     "base/base_export.h",
     "base/check.h",
     "base/check_op.h",
     "base/component_export.h",
+    "base/cpu_reduction_experiment.h",
+    "base/dcheck_is_on.h",
     "base/debug/alias.h",
     "base/export_template.h",
     "base/logging.h",
diff --git a/polyfills/BUILD b/polyfills/BUILD
index 9bf74f4..6a58eec 100644
--- a/polyfills/BUILD
+++ b/polyfills/BUILD
@@ -6,10 +6,13 @@
 cc_library(
     name = "polyfills",
     hdrs = [
+        "base/allocator/buildflags.h",
         "base/base_export.h",
         "base/check.h",
         "base/check_op.h",
         "base/component_export.h",
+        "base/cpu_reduction_experiment.h",
+        "base/dcheck_is_on.h",
         "base/debug/alias.h",
         "base/export_template.h",
         "base/logging.h",
diff --git a/polyfills/base/allocator/buildflags.h b/polyfills/base/allocator/buildflags.h
new file mode 100644
index 0000000..54e240c
--- /dev/null
+++ b/polyfills/base/allocator/buildflags.h
@@ -0,0 +1,18 @@
+#ifndef POLYFILLS_BASE_ALLOCATOR_BUILDFLAGS_H_
+#define POLYFILLS_BASE_ALLOCATOR_BUILDFLAGS_H_
+
+#include "build/buildflag.h"
+
+#define BUILDFLAG_INTERNAL_USE_ALLOCATOR_SHIM() (1)
+#define BUILDFLAG_INTERNAL_USE_PARTITION_ALLOC() (1)
+#define BUILDFLAG_INTERNAL_USE_PARTITION_ALLOC_AS_MALLOC() (0)
+#define BUILDFLAG_INTERNAL_USE_BACKUP_REF_PTR() (0)
+#define BUILDFLAG_INTERNAL_USE_ASAN_BACKUP_REF_PTR() (0)
+#define BUILDFLAG_INTERNAL_ENABLE_BACKUP_REF_PTR_SLOW_CHECKS() (0)
+#define BUILDFLAG_INTERNAL_ENABLE_DANGLING_RAW_PTR_CHECKS() (0)
+#define BUILDFLAG_INTERNAL_PUT_REF_COUNT_IN_PREVIOUS_SLOT() (0)
+#define BUILDFLAG_INTERNAL_NEVER_REMOVE_FROM_BRP_POOL_BLOCKLIST() (0)
+#define BUILDFLAG_INTERNAL_USE_FAKE_BINARY_EXPERIMENT() (0)
+#define BUILDFLAG_INTERNAL_RECORD_ALLOC_INFO() (0)
+
+#endif  // POLYFILLS_BASE_ALLOCATOR_BUILDFLAGS_H_
diff --git a/polyfills/base/check.h b/polyfills/base/check.h
index 15de08b..5c4168d 100644
--- a/polyfills/base/check.h
+++ b/polyfills/base/check.h
@@ -5,6 +5,7 @@
 #ifndef POLYFILLS_BASE_CHECK_H_
 #define POLYFILLS_BASE_CHECK_H_
 
+#include "polyfills/base/base_export.h"
 #include "polyfills/base/logging.h"
 
 #endif /* POLYFILLS_BASE_CHECK_H_ */
diff --git a/polyfills/base/cpu_reduction_experiment.h b/polyfills/base/cpu_reduction_experiment.h
new file mode 100644
index 0000000..db2ea65
--- /dev/null
+++ b/polyfills/base/cpu_reduction_experiment.h
@@ -0,0 +1,20 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef POLYFILLS_BASE_CPU_REDUCTION_EXPERIMENT_H_
+#define POLYFILLS_BASE_CPU_REDUCTION_EXPERIMENT_H_
+
+namespace base {
+
+inline bool IsRunningCpuReductionExperiment() { return false; }
+
+class CpuReductionExperimentFilter {
+ public:
+  bool ShouldLogHistograms() { return false; }
+};
+
+}  // namespace base
+
+
+#endif  /* POLYFILLS_BASE_CPU_REDUCTION_EXPERIMENT_H_ */
diff --git a/polyfills/base/dcheck_is_on.h b/polyfills/base/dcheck_is_on.h
new file mode 100644
index 0000000..814f0d2
--- /dev/null
+++ b/polyfills/base/dcheck_is_on.h
@@ -0,0 +1,11 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef POLYFILLS_BASE_DCHECK_IS_ON_H_
+#define POLYFILLS_BASE_DCHECK_IS_ON_H_
+
+#define DCHECK_IS_ON() false
+#define EXPENSIVE_DCHECKS_ARE_ON() false
+
+#endif  // POLYFILLS_BASE_DCHECK_IS_ON_H_
diff --git a/url/BUILD b/url/BUILD
index f2ec8da..24fd97e 100644
--- a/url/BUILD
+++ b/url/BUILD
@@ -48,7 +48,6 @@
     visibility = ["//visibility:public"],
     deps = [
         "//base",
-        "//base/strings",
         "//polyfills",
     ] + build_config.icuuc_deps,
 )
diff --git a/url/gurl.cc b/url/gurl.cc
index 474919a..3dd0228 100644
--- a/url/gurl.cc
+++ b/url/gurl.cc
@@ -349,7 +349,7 @@
   GURL_DCHECK(gurl_base::IsStringASCII(lower_ascii_scheme));
   GURL_DCHECK(gurl_base::ToLowerASCII(lower_ascii_scheme) == lower_ascii_scheme);
 
-  if (parsed_.scheme.len <= 0)
+  if (!has_scheme())
     return lower_ascii_scheme.empty();
   return scheme_piece() == lower_ascii_scheme;
 }
@@ -363,7 +363,7 @@
 }
 
 bool GURL::SchemeIsCryptographic() const {
-  if (parsed_.scheme.len <= 0)
+  if (!has_scheme())
     return false;
   return SchemeIsCryptographic(scheme_piece());
 }
@@ -376,6 +376,13 @@
          lower_ascii_scheme == url::kWssScheme;
 }
 
+bool GURL::SchemeIsLocal() const {
+  // The `filesystem:` scheme is not in the Fetch spec, but Chromium still
+  // supports it in large part. It should be treated as a local scheme too.
+  return SchemeIs(url::kAboutScheme) || SchemeIs(url::kBlobScheme) ||
+         SchemeIs(url::kDataScheme) || SchemeIs(url::kFileSystemScheme);
+}
+
 int GURL::IntPort() const {
   if (parsed_.port.is_nonempty())
     return url::ParsePort(spec_.data(), parsed_.port);
@@ -546,3 +553,15 @@
 bool operator!=(const gurl_base::StringPiece& spec, const GURL& x) {
   return !(x == spec);
 }
+
+namespace url::debug {
+
+ScopedUrlCrashKey::ScopedUrlCrashKey(gurl_base::debug::CrashKeyString* crash_key,
+                                     const GURL& url)
+    : scoped_string_value_(
+          crash_key,
+          url.is_empty() ? "<empty url>" : url.possibly_invalid_spec()) {}
+
+ScopedUrlCrashKey::~ScopedUrlCrashKey() = default;
+
+}  // namespace url::debug
diff --git a/url/gurl.h b/url/gurl.h
index 64a2ee3..ee009de 100644
--- a/url/gurl.h
+++ b/url/gurl.h
@@ -13,6 +13,7 @@
 
 #include "polyfills/base/component_export.h"
 #include "polyfills/base/debug/alias.h"
+#include "base/debug/crash_logging.h"
 #include "base/strings/string_piece.h"
 #include "polyfills/third_party/perfetto/include/perfetto/tracing/traced_value.h"
 #include "url/third_party/mozilla/url_parse.h"
@@ -265,6 +266,10 @@
     return SchemeIs(url::kBlobScheme);
   }
 
+  // Returns true if the scheme is a local scheme, as defined in Fetch:
+  // https://fetch.spec.whatwg.org/#local-scheme
+  bool SchemeIsLocal() const;
+
   // For most URLs, the "content" is everything after the scheme (skipping the
   // scheme delimiting colon) and before the fragment (skipping the fragment
   // delimiting octothorpe). For javascript URLs the "content" also includes the
@@ -516,4 +521,20 @@
 #define DEBUG_ALIAS_FOR_GURL(var_name, url) \
   DEBUG_ALIAS_FOR_CSTR(var_name, (url).possibly_invalid_spec().c_str(), 128)
 
+namespace url::debug {
+
+class COMPONENT_EXPORT(URL) ScopedUrlCrashKey {
+ public:
+  ScopedUrlCrashKey(gurl_base::debug::CrashKeyString* crash_key, const GURL& value);
+  ~ScopedUrlCrashKey();
+
+  ScopedUrlCrashKey(const ScopedUrlCrashKey&) = delete;
+  ScopedUrlCrashKey& operator=(const ScopedUrlCrashKey&) = delete;
+
+ private:
+  gurl_base::debug::ScopedCrashKeyString scoped_string_value_;
+};
+
+}  // namespace url::debug
+
 #endif  // URL_GURL_H_
diff --git a/url/gurl_unittest.cc b/url/gurl_unittest.cc
index 68817af..e793542 100644
--- a/url/gurl_unittest.cc
+++ b/url/gurl_unittest.cc
@@ -18,19 +18,6 @@
 
 namespace {
 
-template<typename CHAR>
-void SetupReplacement(
-    void (Replacements<CHAR>::*func)(const CHAR*, const Component&),
-    Replacements<CHAR>* replacements,
-    const CHAR* str) {
-  if (str) {
-    Component comp;
-    if (str[0])
-      comp.len = static_cast<int>(strlen(str));
-    (replacements->*func)(str, comp);
-  }
-}
-
 // Returns the canonicalized string for the given URL string for the
 // GURLTest.Types test.
 std::string TypesTestCase(const char* src) {
@@ -496,60 +483,102 @@
   // The most important thing to do here is to check that the proper
   // canonicalizer gets called based on the scheme of the input.
   struct ReplaceCase {
+    using ApplyReplacementsFunc = GURL(const GURL&);
+
     const char* base;
-    const char* scheme;
-    const char* username;
-    const char* password;
-    const char* host;
-    const char* port;
-    const char* path;
-    const char* query;
-    const char* ref;
+    ApplyReplacementsFunc* apply_replacements;
     const char* expected;
   } replace_cases[] = {
-      {"http://www.google.com/foo/bar.html?foo#bar", nullptr, nullptr, nullptr,
-       nullptr, nullptr, "/", "", "", "http://www.google.com/"},
-      {"http://www.google.com/foo/bar.html?foo#bar", "javascript", "", "", "",
-       "", "window.open('foo');", "", "", "javascript:window.open('foo');"},
-      {"file:///C:/foo/bar.txt", "http", nullptr, nullptr, "www.google.com",
-       "99", "/foo", "search", "ref",
-       "http://www.google.com:99/foo?search#ref"},
+      {.base = "http://www.google.com/foo/bar.html?foo#bar",
+       .apply_replacements =
+           +[](const GURL& url) {
+             GURL::Replacements replacements;
+             replacements.SetPathStr("/");
+             replacements.ClearQuery();
+             replacements.ClearRef();
+             return url.ReplaceComponents(replacements);
+           },
+       .expected = "http://www.google.com/"},
+      {.base = "http://www.google.com/foo/bar.html?foo#bar",
+       .apply_replacements =
+           +[](const GURL& url) {
+             GURL::Replacements replacements;
+             replacements.SetSchemeStr("javascript");
+             replacements.ClearUsername();
+             replacements.ClearPassword();
+             replacements.ClearHost();
+             replacements.ClearPort();
+             replacements.SetPathStr("window.open('foo');");
+             replacements.ClearQuery();
+             replacements.ClearRef();
+             return url.ReplaceComponents(replacements);
+           },
+       .expected = "javascript:window.open('foo');"},
+      {.base = "file:///C:/foo/bar.txt",
+       .apply_replacements =
+           +[](const GURL& url) {
+             GURL::Replacements replacements;
+             replacements.SetSchemeStr("http");
+             replacements.SetHostStr("www.google.com");
+             replacements.SetPortStr("99");
+             replacements.SetPathStr("/foo");
+             replacements.SetQueryStr("search");
+             replacements.SetRefStr("ref");
+             return url.ReplaceComponents(replacements);
+           },
+       .expected = "http://www.google.com:99/foo?search#ref"},
 #ifdef WIN32
-      {"http://www.google.com/foo/bar.html?foo#bar", "file", "", "", "", "",
-       "c:\\", "", "", "file:///C:/"},
+      {.base = "http://www.google.com/foo/bar.html?foo#bar",
+       .apply_replacements =
+           +[](const GURL& url) {
+             GURL::Replacements replacements;
+             replacements.SetSchemeStr("file");
+             replacements.ClearUsername();
+             replacements.ClearPassword();
+             replacements.ClearHost();
+             replacements.ClearPort();
+             replacements.SetPathStr("c:\\");
+             replacements.ClearQuery();
+             replacements.ClearRef();
+             return url.ReplaceComponents(replacements);
+           },
+       .expected = "file:///C:/"},
 #endif
-      {"filesystem:http://www.google.com/foo/bar.html?foo#bar", nullptr,
-       nullptr, nullptr, nullptr, nullptr, "/", "", "",
-       "filesystem:http://www.google.com/foo/"},
+      {.base = "filesystem:http://www.google.com/foo/bar.html?foo#bar",
+       .apply_replacements =
+           +[](const GURL& url) {
+             GURL::Replacements replacements;
+             replacements.SetPathStr("/");
+             replacements.ClearQuery();
+             replacements.ClearRef();
+             return url.ReplaceComponents(replacements);
+           },
+       .expected = "filesystem:http://www.google.com/foo/"},
       // Lengthen the URL instead of shortening it, to test creation of
       // inner_url.
-      {"filesystem:http://www.google.com/foo/", nullptr, nullptr, nullptr,
-       nullptr, nullptr, "bar.html", "foo", "bar",
-       "filesystem:http://www.google.com/foo/bar.html?foo#bar"},
+      {.base = "filesystem:http://www.google.com/foo/",
+       .apply_replacements =
+           +[](const GURL& url) {
+             GURL::Replacements replacements;
+             replacements.SetPathStr("bar.html");
+             replacements.SetQueryStr("foo");
+             replacements.SetRefStr("bar");
+             return url.ReplaceComponents(replacements);
+           },
+       .expected = "filesystem:http://www.google.com/foo/bar.html?foo#bar"},
   };
 
-  for (size_t i = 0; i < gurl_base::size(replace_cases); i++) {
-    const ReplaceCase& cur = replace_cases[i];
-    GURL url(cur.base);
-    GURL::Replacements repl;
-    SetupReplacement(&GURL::Replacements::SetScheme, &repl, cur.scheme);
-    SetupReplacement(&GURL::Replacements::SetUsername, &repl, cur.username);
-    SetupReplacement(&GURL::Replacements::SetPassword, &repl, cur.password);
-    SetupReplacement(&GURL::Replacements::SetHost, &repl, cur.host);
-    SetupReplacement(&GURL::Replacements::SetPort, &repl, cur.port);
-    SetupReplacement(&GURL::Replacements::SetPath, &repl, cur.path);
-    SetupReplacement(&GURL::Replacements::SetQuery, &repl, cur.query);
-    SetupReplacement(&GURL::Replacements::SetRef, &repl, cur.ref);
-    GURL output = url.ReplaceComponents(repl);
+  for (const ReplaceCase& c : replace_cases) {
+    GURL output = c.apply_replacements(GURL(c.base));
 
-    EXPECT_EQ(replace_cases[i].expected, output.spec());
+    EXPECT_EQ(c.expected, output.spec());
 
     EXPECT_EQ(output.SchemeIsFileSystem(), output.inner_url() != NULL);
     if (output.SchemeIsFileSystem()) {
       // TODO(mmenke): inner_url()->spec() is currently the same as the spec()
       // for the GURL itself.  This should be fixed.
       // See https://crbug.com/619596
-      EXPECT_EQ(replace_cases[i].expected, output.inner_url()->spec());
+      EXPECT_EQ(c.expected, output.inner_url()->spec());
     }
   }
 }
@@ -847,6 +876,20 @@
   EXPECT_FALSE(GURL("http://bar/").SchemeIsBlob());
 }
 
+TEST(GURLTest, SchemeIsLocal) {
+  EXPECT_TRUE(GURL("BLOB://BAR/").SchemeIsLocal());
+  EXPECT_TRUE(GURL("blob://bar/").SchemeIsLocal());
+  EXPECT_TRUE(GURL("DATA:TEXT/HTML,BAR").SchemeIsLocal());
+  EXPECT_TRUE(GURL("data:text/html,bar").SchemeIsLocal());
+  EXPECT_TRUE(GURL("ABOUT:BAR").SchemeIsLocal());
+  EXPECT_TRUE(GURL("about:bar").SchemeIsLocal());
+  EXPECT_TRUE(GURL("FILESYSTEM:HTTP://FOO.EXAMPLE/BAR").SchemeIsLocal());
+  EXPECT_TRUE(GURL("filesystem:http://foo.example/bar").SchemeIsLocal());
+
+  EXPECT_FALSE(GURL("http://bar/").SchemeIsLocal());
+  EXPECT_FALSE(GURL("file:///bar").SchemeIsLocal());
+}
+
 // Tests that the 'content' of the URL is properly extracted. This can be
 // complex in cases such as multiple schemes (view-source:http:) or for
 // javascript URLs. See GURL::GetContent for more details.
diff --git a/url/origin.cc b/url/origin.cc
index 6c7915f..e943d4f 100644
--- a/url/origin.cc
+++ b/url/origin.cc
@@ -60,7 +60,7 @@
 }
 
 Origin Origin::Resolve(const GURL& url, const Origin& base_origin) {
-  if (url.SchemeIs(kAboutScheme))
+  if (url.SchemeIs(kAboutScheme) || url.is_empty())
     return base_origin;
   Origin result = Origin::Create(url);
   if (!result.opaque())
@@ -163,6 +163,20 @@
   return std::tie(tuple_, nonce_) == std::tie(other.tuple_, other.nonce_);
 }
 
+bool Origin::IsSameOriginWith(const GURL& url) const {
+  if (opaque())
+    return false;
+
+  // The `url::Origin::Create` call here preserves how IsSameOriginWith was used
+  // historically, even though in some scenarios it is not clearly correct:
+  // - Origin of about:blank and about:srcdoc cannot be correctly
+  //   computed/recovered.
+  // - Ideally passing an invalid `url` would be a caller error (e.g. a GURL_DCHECK).
+  // - The caller intent is not always clear wrt handling the outer-vs-inner
+  //   origins/URLs in blob: and filesystem: schemes.
+  return IsSameOriginWith(url::Origin::Create(url));
+}
+
 bool Origin::CanBeDerivedFrom(const GURL& url) const {
   GURL_DCHECK(url.is_valid());
 
@@ -456,7 +470,7 @@
 ScopedOriginCrashKey::ScopedOriginCrashKey(
     gurl_base::debug::CrashKeyString* crash_key,
     const url::Origin* value)
-    : gurl_base::debug::ScopedCrashKeyString(
+    : scoped_string_value_(
           crash_key,
           value ? value->GetDebugString(false /* include_nonce */)
                 : "nullptr") {}
diff --git a/url/origin.h b/url/origin.h
index bfd3b36..c1ad177 100644
--- a/url/origin.h
+++ b/url/origin.h
@@ -25,7 +25,7 @@
 #include "url/url_canon.h"
 #include "url/url_constants.h"
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
 #include <jni.h>
 
 namespace gurl_base {
@@ -36,12 +36,13 @@
 class JavaRef;
 }  // namespace android
 }  // namespace base
-#endif  // OS_ANDROID
+#endif  // BUILDFLAG(IS_ANDROID)
 
 class GURL;
 
 namespace blink {
 class SecurityOrigin;
+class SecurityOriginTest;
 }  // namespace blink
 
 namespace ipc_fuzzer {
@@ -222,6 +223,15 @@
     return !IsSameOriginWith(other);
   }
 
+  // Non-opaque origin is "same-origin" with `url` if their schemes, hosts, and
+  // ports are exact matches.  Opaque origin is never "same-origin" with any
+  // `url`.  about:blank, about:srcdoc, and invalid GURLs are never
+  // "same-origin" with any origin.  This method is a shorthand for
+  // `origin.IsSameOriginWith(url::Origin::Create(url))`.
+  //
+  // See also CanBeDerivedFrom.
+  bool IsSameOriginWith(const GURL& url) const;
+
   // This method returns true for any |url| which if navigated to could result
   // in an origin compatible with |this|.
   bool CanBeDerivedFrom(const GURL& url) const;
@@ -289,16 +299,17 @@
   // and precursor information.
   std::string GetDebugString(bool include_nonce = true) const;
 
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
   gurl_base::android::ScopedJavaLocalRef<jobject> CreateJavaObject() const;
   static Origin FromJavaObject(
       const gurl_base::android::JavaRef<jobject>& java_origin);
-#endif  // OS_ANDROID
+#endif  // BUILDFLAG(IS_ANDROID)
 
   void WriteIntoTrace(perfetto::TracedValue context) const;
 
  private:
   friend class blink::SecurityOrigin;
+  friend class blink::SecurityOriginTest;
   // SchemefulSite needs access to the serialization/deserialization logic which
   // includes the nonce.
   friend class net::SchemefulSite;
@@ -440,8 +451,7 @@
 
 namespace debug {
 
-class COMPONENT_EXPORT(URL) ScopedOriginCrashKey
-    : public gurl_base::debug::ScopedCrashKeyString {
+class COMPONENT_EXPORT(URL) ScopedOriginCrashKey {
  public:
   ScopedOriginCrashKey(gurl_base::debug::CrashKeyString* crash_key,
                        const url::Origin* value);
@@ -449,6 +459,9 @@
 
   ScopedOriginCrashKey(const ScopedOriginCrashKey&) = delete;
   ScopedOriginCrashKey& operator=(const ScopedOriginCrashKey&) = delete;
+
+ private:
+  gurl_base::debug::ScopedCrashKeyString scoped_string_value_;
 };
 
 }  // namespace debug
diff --git a/url/origin_unittest.cc b/url/origin_unittest.cc
index cb78bb6..755d2e3 100644
--- a/url/origin_unittest.cc
+++ b/url/origin_unittest.cc
@@ -5,7 +5,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
-#include "base/macros.h"
+#include "base/memory/raw_ptr.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
@@ -172,6 +172,7 @@
   EXPECT_LT(opaque_a, url::Origin::Create(GURL("http://www.google.com")));
   EXPECT_LT(opaque_b, url::Origin::Create(GURL("http://www.google.com")));
 
+  EXPECT_EQ(opaque_b, url::Origin::Resolve(GURL(), opaque_b));
   EXPECT_EQ(opaque_b, url::Origin::Resolve(GURL("about:blank"), opaque_b));
   EXPECT_EQ(opaque_b, url::Origin::Resolve(GURL("about:srcdoc"), opaque_b));
   EXPECT_EQ(opaque_b,
@@ -495,7 +496,7 @@
   // and ensure that it returns |expected_value|
   const struct {
     const char* url;
-    Origin* origin;
+    raw_ptr<Origin> origin;
     bool expected_value;
   } kTestCases[] = {
       {"https://a.com", &regular_origin, true},
@@ -746,6 +747,29 @@
   EXPECT_EQ(opaque.GetDebugString(), deserialized.value().GetDebugString());
 }
 
+TEST_F(OriginTest, IsSameOriginWith) {
+  url::Origin opaque_origin;
+  GURL foo_url = GURL("https://foo.com/path");
+  url::Origin foo_origin = url::Origin::Create(foo_url);
+  GURL bar_url = GURL("https://bar.com/path");
+  url::Origin bar_origin = url::Origin::Create(bar_url);
+
+  EXPECT_FALSE(opaque_origin.IsSameOriginWith(foo_origin));
+  EXPECT_FALSE(opaque_origin.IsSameOriginWith(foo_url));
+
+  EXPECT_TRUE(foo_origin.IsSameOriginWith(foo_origin));
+  EXPECT_TRUE(foo_origin.IsSameOriginWith(foo_url));
+
+  EXPECT_FALSE(foo_origin.IsSameOriginWith(bar_origin));
+  EXPECT_FALSE(foo_origin.IsSameOriginWith(bar_url));
+
+  // Documenting legacy behavior.  This doesn't necessarily mean that the legacy
+  // behavior is correct (or desirable in the long-term).
+  EXPECT_FALSE(foo_origin.IsSameOriginWith(GURL("about:blank")));
+  EXPECT_FALSE(foo_origin.IsSameOriginWith(GURL()));  // Invalid GURL.
+  EXPECT_TRUE(foo_origin.IsSameOriginWith(GURL("blob:https://foo.com/guid")));
+}
+
 INSTANTIATE_TYPED_TEST_SUITE_P(UrlOrigin,
                                AbstractOriginTest,
                                UrlOriginTestTraits);
diff --git a/url/run_all_unittests.cc b/url/run_all_unittests.cc
index 0f6a431..cf408d4 100644
--- a/url/run_all_unittests.cc
+++ b/url/run_all_unittests.cc
@@ -10,14 +10,14 @@
 #include "base/test/test_suite.h"
 #include "build/build_config.h"
 
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
 #include "mojo/core/embedder/embedder.h"  // nogncheck
 #endif
 
 int main(int argc, char** argv) {
   gurl_base::TestSuite test_suite(argc, argv);
 
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
   mojo::core::Init();
 #endif
 
diff --git a/url/scheme_host_port.cc b/url/scheme_host_port.cc
index c337da3..854c6f6 100644
--- a/url/scheme_host_port.cc
+++ b/url/scheme_host_port.cc
@@ -7,6 +7,7 @@
 #include <stdint.h>
 #include <string.h>
 
+#include <ostream>
 #include <tuple>
 
 #include "polyfills/base/check_op.h"
diff --git a/url/url_canon.h b/url/url_canon.h
index 457f58a..32e7b15 100644
--- a/url/url_canon.h
+++ b/url/url_canon.h
@@ -139,6 +139,8 @@
     return true;
   }
 
+  // `buffer_` is not a raw_ptr<...> for performance reasons (based on analysis
+  // of sampling profiler data).
   T* buffer_;
   int buffer_len_;
 
diff --git a/url/url_canon_host.cc b/url/url_canon_host.cc
index 7a97522..370dd77 100644
--- a/url/url_canon_host.cc
+++ b/url/url_canon_host.cc
@@ -2,10 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <unordered_set>
-
 #include "polyfills/base/check.h"
-#include "polyfills/base/metrics/histogram_macros.h"
+#include "polyfills/base/cpu_reduction_experiment.h"
 #include "url/url_canon.h"
 #include "url/url_canon_internal.h"
 
@@ -132,8 +130,6 @@
                   bool* has_non_ascii) {
   *has_non_ascii = false;
 
-  std::unordered_set<char> escaped_chars_to_measure;
-
   bool success = true;
   for (int i = 0; i < host_len; ++i) {
     unsigned int source = host[i];
@@ -161,7 +157,6 @@
       } else if (replacement == kEsc) {
         // This character is valid but should be escaped.
         AppendEscapedChar(source, output);
-        escaped_chars_to_measure.insert(source);
       } else {
         // Common case, the given character is valid in a hostname, the lookup
         // table tells us the canonical representation of that character (lower
@@ -176,16 +171,6 @@
       *has_non_ascii = true;
     }
   }
-  if (success) {
-    bool did_escape = !escaped_chars_to_measure.empty();
-    UMA_HISTOGRAM_BOOLEAN("URL.Host.DidEscape", did_escape);
-    if (did_escape) {
-      for (char c : escaped_chars_to_measure) {
-        UMA_HISTOGRAM_ENUMERATION("URL.Host.EscapeChar",
-                                  EscapedHostCharToEnum(c));
-      }
-    }
-  }
   return success;
 }
 
diff --git a/url/url_canon_icu.cc b/url/url_canon_icu.cc
index b4f8f81..3a6b9be 100644
--- a/url/url_canon_icu.cc
+++ b/url/url_canon_icu.cc
@@ -9,6 +9,7 @@
 #include <string.h>
 
 #include "polyfills/base/check.h"
+#include "base/memory/raw_ptr.h"
 #include <unicode/ucnv.h>
 #include <unicode/ucnv_cb.h>
 #include <unicode/utypes.h>
@@ -66,7 +67,7 @@
   }
 
  private:
-  UConverter* converter_;
+  raw_ptr<UConverter> converter_;
 
   UConverterFromUCallback old_callback_;
   const void* old_context_;
diff --git a/url/url_canon_icu.h b/url/url_canon_icu.h
index 34bb99e..b861f7a 100644
--- a/url/url_canon_icu.h
+++ b/url/url_canon_icu.h
@@ -9,6 +9,7 @@
 
 #include "base/compiler_specific.h"
 #include "polyfills/base/component_export.h"
+#include "base/memory/raw_ptr.h"
 #include "url/url_canon.h"
 
 typedef struct UConverter UConverter;
@@ -32,7 +33,7 @@
 
  private:
   // The ICU converter, not owned by this class.
-  UConverter* converter_;
+  raw_ptr<UConverter> converter_;
 };
 
 }  // namespace url
diff --git a/url/url_canon_icu_unittest.cc b/url/url_canon_icu_unittest.cc
index ca13427..702b1d3 100644
--- a/url/url_canon_icu_unittest.cc
+++ b/url/url_canon_icu_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/cxx17_backports.h"
 #include "polyfills/base/logging.h"
+#include "base/memory/raw_ptr.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include <unicode/ucnv.h>
 #include "url/url_canon.h"
@@ -38,7 +39,7 @@
   UConverter* converter() const { return converter_; }
 
  private:
-  UConverter* converter_;
+  raw_ptr<UConverter> converter_;
 };
 
 TEST(URLCanonIcuTest, ICUCharsetConverter) {
diff --git a/url/url_canon_internal.cc b/url/url_canon_internal.cc
index 961a3be..99541bd 100644
--- a/url/url_canon_internal.cc
+++ b/url/url_canon_internal.cc
@@ -435,49 +435,4 @@
 
 #endif  // !WIN32
 
-EscapedHostChar EscapedHostCharToEnum(char c) {
-  switch (c) {
-    case ' ':
-      return EscapedHostChar::kSpace;
-    case '!':
-      return EscapedHostChar::kBang;
-    case '"':
-      return EscapedHostChar::kDoubleQuote;
-    case '#':
-      return EscapedHostChar::kHash;
-    case '$':
-      return EscapedHostChar::kDollar;
-    case '&':
-      return EscapedHostChar::kAmpersand;
-    case '\'':
-      return EscapedHostChar::kSingleQuote;
-    case '(':
-      return EscapedHostChar::kLeftParen;
-    case ')':
-      return EscapedHostChar::kRightParen;
-    case '*':
-      return EscapedHostChar::kAsterisk;
-    case ',':
-      return EscapedHostChar::kComma;
-    case '<':
-      return EscapedHostChar::kLeftAngle;
-    case '=':
-      return EscapedHostChar::kEquals;
-    case '>':
-      return EscapedHostChar::kRightAngle;
-    case '@':
-      return EscapedHostChar::kAt;
-    case '`':
-      return EscapedHostChar::kBackTick;
-    case '{':
-      return EscapedHostChar::kLeftCurly;
-    case '|':
-      return EscapedHostChar::kPipe;
-    case '}':
-      return EscapedHostChar::kRightCurly;
-    default:
-      return EscapedHostChar::kUnknown;
-  }
-}
-
 }  // namespace url
diff --git a/url/url_canon_internal.h b/url/url_canon_internal.h
index 6601587..d674976 100644
--- a/url/url_canon_internal.h
+++ b/url/url_canon_internal.h
@@ -456,35 +456,6 @@
 
 #endif  // WIN32
 
-// These values are logged to UMA. Entries should not be renumbered and
-// numeric values should never be reused. Please keep in sync with
-// "URLHostEscapedHostChar" in src/tools/metrics/histograms/enums.xml.
-enum class EscapedHostChar {
-  kUnknown = 0,
-  kSpace = 1,
-  kBang = 2,
-  kDoubleQuote = 3,
-  kHash = 4,
-  kDollar = 5,
-  kAmpersand = 6,
-  kSingleQuote = 7,
-  kLeftParen = 8,
-  kRightParen = 9,
-  kAsterisk = 10,
-  kComma = 11,
-  kLeftAngle = 12,
-  kEquals = 13,
-  kRightAngle = 14,
-  kAt = 15,
-  kBackTick = 16,
-  kLeftCurly = 17,
-  kPipe = 18,
-  kRightCurly = 19,
-  kMaxValue = kRightCurly,
-};
-
-COMPONENT_EXPORT(URL) EscapedHostChar EscapedHostCharToEnum(char c);
-
 }  // namespace url
 
 #endif  // URL_URL_CANON_INTERNAL_H_
diff --git a/url/url_canon_stdstring.h b/url/url_canon_stdstring.h
index cef33cd..e9adc43 100644
--- a/url/url_canon_stdstring.h
+++ b/url/url_canon_stdstring.h
@@ -13,7 +13,6 @@
 
 #include "base/compiler_specific.h"
 #include "polyfills/base/component_export.h"
-#include "base/macros.h"
 #include "base/strings/string_piece.h"
 #include "url/url_canon.h"
 
@@ -49,6 +48,8 @@
   void Resize(int sz) override;
 
  protected:
+  // `str_` is not a raw_ptr<...> for performance reasons (based on analysis of
+  // sampling profiler data and tab_search:top100:2020).
   std::string* str_;
 };
 
@@ -82,30 +83,47 @@
   void SetUsernameStr(const CharT* str) { SetImpl(&ParentT::SetUsername, str); }
   void SetUsernameStr(StringPieceT str) { SetImpl(&ParentT::SetUsername, str); }
   void SetUsernameStr(const StringT&&) = delete;
+  using ParentT::ClearUsername;
 
   void SetPasswordStr(const CharT* str) { SetImpl(&ParentT::SetPassword, str); }
   void SetPasswordStr(StringPieceT str) { SetImpl(&ParentT::SetPassword, str); }
   void SetPasswordStr(const StringT&&) = delete;
+  using ParentT::ClearPassword;
 
   void SetHostStr(const CharT* str) { SetImpl(&ParentT::SetHost, str); }
   void SetHostStr(StringPieceT str) { SetImpl(&ParentT::SetHost, str); }
   void SetHostStr(const StringT&&) = delete;
+  using ParentT::ClearHost;
 
   void SetPortStr(const CharT* str) { SetImpl(&ParentT::SetPort, str); }
   void SetPortStr(StringPieceT str) { SetImpl(&ParentT::SetPort, str); }
   void SetPortStr(const StringT&&) = delete;
+  using ParentT::ClearPort;
 
   void SetPathStr(const CharT* str) { SetImpl(&ParentT::SetPath, str); }
   void SetPathStr(StringPieceT str) { SetImpl(&ParentT::SetPath, str); }
   void SetPathStr(const StringT&&) = delete;
+  using ParentT::ClearPath;
 
   void SetQueryStr(const CharT* str) { SetImpl(&ParentT::SetQuery, str); }
   void SetQueryStr(StringPieceT str) { SetImpl(&ParentT::SetQuery, str); }
   void SetQueryStr(const StringT&&) = delete;
+  using ParentT::ClearQuery;
 
   void SetRefStr(const CharT* str) { SetImpl(&ParentT::SetRef, str); }
   void SetRefStr(StringPieceT str) { SetImpl(&ParentT::SetRef, str); }
   void SetRefStr(const StringT&&) = delete;
+  using ParentT::ClearRef;
+
+ private:
+  using ParentT::SetHost;
+  using ParentT::SetPassword;
+  using ParentT::SetPath;
+  using ParentT::SetPort;
+  using ParentT::SetQuery;
+  using ParentT::SetRef;
+  using ParentT::SetScheme;
+  using ParentT::SetUsername;
 };
 
 }  // namespace url
diff --git a/url/url_canon_unittest.cc b/url/url_canon_unittest.cc
index d7dc876..2dd5075 100644
--- a/url/url_canon_unittest.cc
+++ b/url/url_canon_unittest.cc
@@ -9,7 +9,6 @@
 #include "base/strings/string_piece.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/gtest_util.h"
-#include "base/test/metrics/histogram_tester.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/third_party/mozilla/url_parse.h"
 #include "url/url_canon.h"
@@ -2609,49 +2608,4 @@
   output.set_length(0);
 }
 
-TEST(URLCanonTest, EscapedHostCharToEnum) {
-  EXPECT_EQ(EscapedHostChar::kSpace, EscapedHostCharToEnum(' '));
-  EXPECT_EQ(EscapedHostChar::kBang, EscapedHostCharToEnum('!'));
-  EXPECT_EQ(EscapedHostChar::kDoubleQuote, EscapedHostCharToEnum('"'));
-  EXPECT_EQ(EscapedHostChar::kHash, EscapedHostCharToEnum('#'));
-  EXPECT_EQ(EscapedHostChar::kDollar, EscapedHostCharToEnum('$'));
-  EXPECT_EQ(EscapedHostChar::kAmpersand, EscapedHostCharToEnum('&'));
-  EXPECT_EQ(EscapedHostChar::kSingleQuote, EscapedHostCharToEnum('\''));
-  EXPECT_EQ(EscapedHostChar::kLeftParen, EscapedHostCharToEnum('('));
-  EXPECT_EQ(EscapedHostChar::kRightParen, EscapedHostCharToEnum(')'));
-  EXPECT_EQ(EscapedHostChar::kAsterisk, EscapedHostCharToEnum('*'));
-  EXPECT_EQ(EscapedHostChar::kComma, EscapedHostCharToEnum(','));
-  EXPECT_EQ(EscapedHostChar::kLeftAngle, EscapedHostCharToEnum('<'));
-  EXPECT_EQ(EscapedHostChar::kEquals, EscapedHostCharToEnum('='));
-  EXPECT_EQ(EscapedHostChar::kRightAngle, EscapedHostCharToEnum('>'));
-  EXPECT_EQ(EscapedHostChar::kAt, EscapedHostCharToEnum('@'));
-  EXPECT_EQ(EscapedHostChar::kBackTick, EscapedHostCharToEnum('`'));
-  EXPECT_EQ(EscapedHostChar::kLeftCurly, EscapedHostCharToEnum('{'));
-  EXPECT_EQ(EscapedHostChar::kPipe, EscapedHostCharToEnum('|'));
-  EXPECT_EQ(EscapedHostChar::kRightCurly, EscapedHostCharToEnum('}'));
-
-  EXPECT_EQ(EscapedHostChar::kUnknown, EscapedHostCharToEnum('a'));
-  EXPECT_EQ(EscapedHostChar::kUnknown, EscapedHostCharToEnum('\\'));
-}
-
-TEST(URLCanonTest, EscapedHostCharHistograms) {
-  std::string input("foo  <bar>");
-
-  Component in_comp(0, input.size());
-  Component out_comp;
-  std::string out_str;
-  StdStringCanonOutput output(&out_str);
-
-  gurl_base::HistogramTester histogram_tester;
-  bool success = CanonicalizeHost(input.data(), in_comp, &output, &out_comp);
-  ASSERT_TRUE(success);
-  histogram_tester.ExpectBucketCount("URL.Host.DidEscape", 1, 1);
-  histogram_tester.ExpectBucketCount("URL.Host.EscapeChar",
-                                     EscapedHostChar::kSpace, 1);
-  histogram_tester.ExpectBucketCount("URL.Host.EscapeChar",
-                                     EscapedHostChar::kLeftAngle, 1);
-  histogram_tester.ExpectBucketCount("URL.Host.EscapeChar",
-                                     EscapedHostChar::kRightAngle, 1);
-}
-
 }  // namespace url
diff --git a/url/url_constants.cc b/url/url_constants.cc
index d7a5de7..9685098 100644
--- a/url/url_constants.cc
+++ b/url/url_constants.cc
@@ -7,33 +7,56 @@
 namespace url {
 
 const char kAboutBlankURL[] = "about:blank";
+const char16_t kAboutBlankURL16[] = u"about:blank";
 const char kAboutSrcdocURL[] = "about:srcdoc";
+const char16_t kAboutSrcdocURL16[] = u"about:srcdoc";
 
 const char kAboutBlankPath[] = "blank";
+const char16_t kAboutBlankPath16[] = u"blank";
 const char kAboutSrcdocPath[] = "srcdoc";
+const char16_t kAboutSrcdocPath16[] = u"srcdoc";
 
 const char kAboutScheme[] = "about";
+const char16_t kAboutScheme16[] = u"about";
 const char kBlobScheme[] = "blob";
+const char16_t kBlobScheme16[] = u"blob";
 const char kContentScheme[] = "content";
+const char16_t kContentScheme16[] = u"content";
 const char kContentIDScheme[] = "cid";
+const char16_t kContentIDScheme16[] = u"cid";
 const char kDataScheme[] = "data";
+const char16_t kDataScheme16[] = u"data";
 const char kFileScheme[] = "file";
+const char16_t kFileScheme16[] = u"file";
 const char kFileSystemScheme[] = "filesystem";
+const char16_t kFileSystemScheme16[] = u"filesystem";
 const char kFtpScheme[] = "ftp";
+const char16_t kFtpScheme16[] = u"ftp";
 const char kHttpScheme[] = "http";
+const char16_t kHttpScheme16[] = u"http";
 const char kHttpsScheme[] = "https";
+const char16_t kHttpsScheme16[] = u"https";
 const char kJavaScriptScheme[] = "javascript";
+const char16_t kJavaScriptScheme16[] = u"javascript";
 const char kMailToScheme[] = "mailto";
+const char16_t kMailToScheme16[] = u"mailto";
 // This is for QuicTransport (https://wicg.github.io/web-transport/).
 // See also: https://www.iana.org/assignments/uri-schemes/prov/quic-transport
 const char kQuicTransportScheme[] = "quic-transport";
+const char16_t kQuicTransportScheme16[] = u"quic-transport";
 const char kTelScheme[] = "tel";
+const char16_t kTelScheme16[] = u"tel";
 const char kUrnScheme[] = "urn";
+const char16_t kUrnScheme16[] = u"urn";
 const char kUuidInPackageScheme[] = "uuid-in-package";
+const char16_t kUuidInPackageScheme16[] = u"uuid-in-package";
 const char kWsScheme[] = "ws";
+const char16_t kWsScheme16[] = u"ws";
 const char kWssScheme[] = "wss";
+const char16_t kWssScheme16[] = u"wss";
 
 const char kStandardSchemeSeparator[] = "://";
+const char16_t kStandardSchemeSeparator16[] = u"://";
 
 const size_t kMaxURLChars = 2 * 1024 * 1024;
 
diff --git a/url/url_constants.h b/url/url_constants.h
index 69a72f5..b4a5889 100644
--- a/url/url_constants.h
+++ b/url/url_constants.h
@@ -12,33 +12,56 @@
 namespace url {
 
 COMPONENT_EXPORT(URL) extern const char kAboutBlankURL[];
+COMPONENT_EXPORT(URL) extern const char16_t kAboutBlankURL16[];
 COMPONENT_EXPORT(URL) extern const char kAboutSrcdocURL[];
+COMPONENT_EXPORT(URL) extern const char16_t kAboutSrcdocURL16[];
 
 COMPONENT_EXPORT(URL) extern const char kAboutBlankPath[];
+COMPONENT_EXPORT(URL) extern const char16_t kAboutBlankPath16[];
 COMPONENT_EXPORT(URL) extern const char kAboutSrcdocPath[];
+COMPONENT_EXPORT(URL) extern const char16_t kAboutSrcdocPath16[];
 
 COMPONENT_EXPORT(URL) extern const char kAboutScheme[];
+COMPONENT_EXPORT(URL) extern const char16_t kAboutScheme16[];
 COMPONENT_EXPORT(URL) extern const char kBlobScheme[];
+COMPONENT_EXPORT(URL) extern const char16_t kBlobScheme16[];
 // The content scheme is specific to Android for identifying a stored file.
 COMPONENT_EXPORT(URL) extern const char kContentScheme[];
+COMPONENT_EXPORT(URL) extern const char16_t kContentScheme16[];
 COMPONENT_EXPORT(URL) extern const char kContentIDScheme[];
+COMPONENT_EXPORT(URL) extern const char16_t kContentIDScheme16[];
 COMPONENT_EXPORT(URL) extern const char kDataScheme[];
+COMPONENT_EXPORT(URL) extern const char16_t kDataScheme16[];
 COMPONENT_EXPORT(URL) extern const char kFileScheme[];
+COMPONENT_EXPORT(URL) extern const char16_t kFileScheme16[];
 COMPONENT_EXPORT(URL) extern const char kFileSystemScheme[];
+COMPONENT_EXPORT(URL) extern const char16_t kFileSystemScheme16[];
 COMPONENT_EXPORT(URL) extern const char kFtpScheme[];
+COMPONENT_EXPORT(URL) extern const char16_t kFtpScheme16[];
 COMPONENT_EXPORT(URL) extern const char kHttpScheme[];
+COMPONENT_EXPORT(URL) extern const char16_t kHttpScheme16[];
 COMPONENT_EXPORT(URL) extern const char kHttpsScheme[];
+COMPONENT_EXPORT(URL) extern const char16_t kHttpsScheme16[];
 COMPONENT_EXPORT(URL) extern const char kJavaScriptScheme[];
+COMPONENT_EXPORT(URL) extern const char16_t kJavaScriptScheme16[];
 COMPONENT_EXPORT(URL) extern const char kMailToScheme[];
+COMPONENT_EXPORT(URL) extern const char16_t kMailToScheme16[];
 COMPONENT_EXPORT(URL) extern const char kQuicTransportScheme[];
+COMPONENT_EXPORT(URL) extern const char16_t kQuicTransportScheme16[];
 COMPONENT_EXPORT(URL) extern const char kTelScheme[];
+COMPONENT_EXPORT(URL) extern const char16_t kTelScheme16[];
 COMPONENT_EXPORT(URL) extern const char kUrnScheme[];
+COMPONENT_EXPORT(URL) extern const char16_t kUrnScheme16[];
 COMPONENT_EXPORT(URL) extern const char kUuidInPackageScheme[];
+COMPONENT_EXPORT(URL) extern const char16_t kUuidInPackageScheme16[];
 COMPONENT_EXPORT(URL) extern const char kWsScheme[];
+COMPONENT_EXPORT(URL) extern const char16_t kWsScheme16[];
 COMPONENT_EXPORT(URL) extern const char kWssScheme[];
+COMPONENT_EXPORT(URL) extern const char16_t kWssScheme16[];
 
 // Used to separate a standard scheme and the hostname: "://".
 COMPONENT_EXPORT(URL) extern const char kStandardSchemeSeparator[];
+COMPONENT_EXPORT(URL) extern const char16_t kStandardSchemeSeparator16[];
 
 COMPONENT_EXPORT(URL) extern const size_t kMaxURLChars;
 
diff --git a/url/url_util_unittest.cc b/url/url_util_unittest.cc
index a455ff6..5255817 100644
--- a/url/url_util_unittest.cc
+++ b/url/url_util_unittest.cc
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "url/url_util.h"
+
 #include <stddef.h>
 
 #include "base/cxx17_backports.h"
 #include "base/strings/string_piece.h"
+#include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest-message.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "absl/types/optional.h"
@@ -13,7 +16,6 @@
 #include "url/url_canon.h"
 #include "url/url_canon_stdstring.h"
 #include "url/url_test_utils.h"
-#include "url/url_util.h"
 
 namespace url {
 
@@ -574,7 +576,7 @@
 }
 }  // namespace
 
-#ifdef OS_WIN
+#if BUILDFLAG(IS_WIN)
 // Regression test for https://crbug.com/1252658.
 TEST_F(URLUtilTest, TestCanonicalizeWindowsPathWithLeadingNUL) {
   auto PrefixWithNUL = [](std::string&& s) -> std::string { return '\0' + s; };