Update googleurl to 9cf3e054c83f943c3bf8a87e6f75cab19b3e08c1

The upstream Chromium revision is of Fri Apr 29 00:14:16 2022 +0000

Change-Id: I91e2af9b25b0489738b8a0126630abae1c06fda2
diff --git a/AUTHORS b/AUTHORS
index 364df55..5941416 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -47,7 +47,9 @@
 Alec Petridis <alecthechop@gmail.com>
 Aleksandar Stojiljkovic <aleksandar.stojiljkovic@intel.com>
 Aleksei Gurianov <gurianov@gmail.com>
+Aleksey Khoroshilov <akhoroshilov@brave.com>
 Alesandro Ortiz <alesandro@alesandroortiz.com>
+Alessandro Astone <ales.astone@gmail.com>
 Alex Chronopoulos <achronop@gmail.com>
 Alex Gabriel <minilogo@gmail.com>
 Alex Gartrell <agartrell@cmu.edu>
@@ -90,6 +92,7 @@
 Ancil George <ancilgeorge@samsung.com>
 Andra Paraschiv <andra.paraschiv@intel.com>
 Andras Tokodi <a.tokodi@eyeo.com>
+Andreas Nazlidis <andreas221b@gmail.com>
 Andreas Papacharalampous <andreas@apap04.com>
 Andrei Borza <andrei.borza@gmail.com>
 Andrei Parvu <andrei.prv@gmail.com>
@@ -113,11 +116,13 @@
 Anshul Jain <anshul.jain@samsung.com>
 Anssi Hannula <anssi.hannula@iki.fi>
 Anthony Halliday <anth.halliday12@gmail.com>
-Anton Bershanskiy <bershanskiy@pm.me>
+Anton Bershanskiy <8knots@protonmail.com>
 Anton Obzhirov <a.obzhirov@samsung.com>
 Antonin Hildebrand <antonin.hildebrand@gmail.com>
 Antonio Gomes <a1.gomes@sisa.samsung.com>
 Anuj Kumar Sharma <anujk.sharma@samsung.com>
+Ao Sun <ntusunao@gmail.com>
+Ao Wang <wangao.james@bytedance.com>
 Arjun Karthik <arjunkar@amazon.com>
 Arman Ghotb <armanghotb@gmail.com>
 Armin Burgmeier <aburgmeier@bloomberg.net>
@@ -167,6 +172,7 @@
 Brendan Long <self@brendanlong.com>
 Brendon Tiszka <btiszka@gmail.com>
 Brian Clifton <clifton@brave.com>
+Brian Dunn <brian@theophil.us>
 Brian G. Merrell <bgmerrell@gmail.com>
 Brian Konzman, SJ <b.g.konzman@gmail.com>
 Brian Luft <brian@electroly.com>
@@ -245,6 +251,7 @@
 Daniel Carvalho Liedke <dliedke@gmail.com>
 Daniel Charles <daniel.charles@intel.com>
 Daniel Imms <daniimms@amazon.com>
+Daniel Izquierdo <daniel.izquierdo@gmail.com>
 Daniel Johnson <danielj41@gmail.com>
 Daniel Lockyer <thisisdaniellockyer@gmail.com>
 Daniel Nishi <dhnishi@gmail.com>
@@ -346,6 +353,7 @@
 Evgeny Agafonchikov <evgeny.agafonchikov@akvelon.com>
 Fabian Henneke <fabian.henneke@gmail.com>
 Fabien Tassin <fta@sofaraway.org>
+Feifei Wang <alexswang@tencent.com>
 Felipe Erias Morandeira <felipeerias@gmail.com>
 Felix H. Dahlke <fhd@ubercode.de>
 Felix Weilbach <feweilbach@gmail.com>
@@ -413,6 +421,7 @@
 Hautio Kari <khautio@gmail.com>
 Heejin R. Chung <heejin.r.chung@samsung.com>
 Heeyoun Lee <heeyoun.lee@samsung.com>
+Henrique de Carvalho <decarv.henrique@gmail.com>
 Henrique Limas <henrique.ramos.limas@gmail.com>
 Himanshu Joshi <h.joshi@samsung.com>
 Hiroyuki Matsuda <gsittyz@gmail.com>
@@ -572,6 +581,7 @@
 Joone Hur <joone.hur@intel.com>
 Joonghun Park <pjh0718@gmail.com>
 Jorge Villatoro <jorge@tomatocannon.com>
+Jorrit Jongma <jorrit@jongma.org>
 Joseph Gentle <josephg@gmail.com>
 Joseph Lolak <joseph.lolak@samsung.com>
 Josh Triplett <josh.triplett@intel.com>
@@ -599,6 +609,7 @@
 Jungkee Song <jungkee.song@samsung.com>
 Junmin Zhu <junmin.zhu@intel.com>
 Junsong Li <ljs.darkfish@gmail.com>
+Jun Wang <wangjuna@uniontech.com>
 Jun Zeng <hjunzeng6@gmail.com>
 Justin Okamoto <justmoto@amazon.com>
 Justin Ribeiro <justin@justinribeiro.com>
@@ -708,6 +719,7 @@
 Luke Zarko <lukezarko@gmail.com>
 Luoxi Pan <l.panpax@gmail.com>
 Lu Yahan <yahan@iscas.ac.cn>
+Ma Aiguo <maaiguo@uniontech.com>
 Maarten Lankhorst <m.b.lankhorst@gmail.com>
 Maciej Pawlowski <m.pawlowski@eyeo.com>
 Magnus Danielsson <fuzzac@gmail.com>
@@ -813,6 +825,7 @@
 Mohammed Wajahat Ali Siddiqui <wajahat.s@samsung.com>
 Mohan Reddy <mohan.reddy@samsung.com>
 Mohit Bhalla <bhallam@amazon.com>
+Moiseanu Rares-Marian <moiseanurares@gmail.com>
 Momoka Yamamoto <momoka.my6@gmail.com>
 Momoko Hattori <momohatt10@gmail.com>
 Mostafa Sedaghat joo <mostafa.sedaghat@gmail.com>
@@ -880,6 +893,7 @@
 Pavel Ivanov <paivanof@gmail.com>
 Pawel Forysiuk <p.forysiuk@samsung.com>
 Paweł Hajdan jr <phajdan.jr@gmail.com>
+Paweł Stanek <pawel@gener8ads.com>
 Piotr Zarycki <piotr.zarycki@gmail.com>
 Payal Pandey <payal.pandey@samsung.com>
 Pedro Tôrres <t0rr3s.p3dr0@gmail.com>
@@ -887,6 +901,7 @@
 Peng Jiang <leiyi.jp@gmail.com>
 Peng Xinchao <pxinchao@gmail.com>
 Peng-Yu Chen <pengyu@libstarrify.so>
+Pei Wang <wangpei@uniontech.com>
 Peter Bright <drpizza@quiscalusmexicanus.org>
 Peter Brophy <pbrophy@adobe.com>
 Peter Collingbourne <peter@pcc.me.uk>
@@ -942,6 +957,7 @@
 Ravi Phaneendra Kasibhatla <r.kasibhatla@samsung.com>
 Ravi Phaneendra Kasibhatla <ravi.kasibhatla@motorola.com>
 Raviraj Sitaram <raviraj.p.sitaram@intel.com>
+Rebecca Chang Swee Fun <rebecca.chang@starfivetech.com>
 Reda Tawfik <redatawfik@noogler.google.com>
 Réda Housni Alaoui <alaoui.rda@gmail.com>
 Refael Ackermann <refack@gmail.com>
@@ -995,6 +1011,7 @@
 Samuel Attard <samuel.r.attard@gmail.com>
 Sanggi Hong <sanggi.hong11@gmail.com>
 Sanghee Lee <sanghee.lee1992@gmail.com>
+Sangheon Kim <sangheon77.kim@samsung.com>
 Sanghyun Park <sh919.park@samsung.com>
 Sanghyup Lee <sh53.lee@samsung.com>
 Sangjoon Je <htamop@gmail.com>
@@ -1041,6 +1058,7 @@
 ShankarGanesh K <blr.bmlab@gmail.com>
 Shanmuga Pandi M <shanmuga.m@samsung.com>
 Shaobo Yan <shaobo.yan@intel.com>
+Shaotang Zhu <zhushaotang@uniontech.com>
 Shashi Kumar <sk.kumar@samsung.com>
 Shawn Anastasio <shawnanastasio@gmail.com>
 Shelley Vohr <shelley.vohr@gmail.com>
@@ -1064,6 +1082,7 @@
 Shubham Agrawal <shubag@amazon.com>
 Shubham Gupta <shubh.gupta@samsung.com>
 Siba Samal <siba.samal@samsung.com>
+Sida Zhu <zhusida@bytedance.com>
 Siddharth Bagai <b.siddharth@samsung.com>
 Siddharth Shankar <funkysidd@gmail.com>
 Simeon Kuran <simeon.kuran@gmail.com>
@@ -1151,6 +1170,7 @@
 Tibor Dusnoki <tdusnoki@inf.u-szeged.hu>
 Tim Ansell <mithro@mithis.com>
 Tim Niederhausen <tim@rnc-ag.de>
+Tim Steiner <twsteiner@gmail.com>
 Timo Gurr <timo.gurr@gmail.com>
 Timo Reimann <ttr314@googlemail.com>
 Timo Witte <timo.witte@gmail.com>
@@ -1200,6 +1220,7 @@
 Waihung Fu <fufranci@amazon.com>
 wafuwafu13 <mariobaske@i.softbank.jp>
 Wojciech Bielawski <wojciech.bielawski@gmail.com>
+Wang Weiwei <wangww@dingdao.com>
 Wanming Lin <wanming.lin@intel.com>
 Wei Li <wei.c.li@intel.com>
 Wen Fan <fanwen1@huawei.com>
@@ -1214,6 +1235,7 @@
 Will Watts <willwatts.ww@googlemail.com>
 William Xie <william.xie@intel.com>
 Winston Chen <winston.c1@samsung.com>
+Xialei Qin <qinxialei@uniontech.com>
 Xiang Long <xiang.long@intel.com>
 XiangYang <yangxiang12@huawei.com>
 Xiangze Zhang <xiangze.zhang@intel.com>
@@ -1223,6 +1245,7 @@
 Xiaoshu Zhang <xiaoshu@amazon.com>
 Xiaoyin Liu <xiaoyin.l@outlook.com>
 Xinchao He <hexinchao@gmail.com>
+Xinchao Tian <tianxinchao@360.cn>
 Xing Zhang <xzhang@adobe.com>
 Xinghua Cao <xinghua.cao@intel.com>
 Xu Samuel <samuel.xu@intel.com>
@@ -1236,6 +1259,7 @@
 Yael Aharon <yael.aharon@intel.com>
 Yan Wang <yan0422.wang@samsung.com>
 Yang Gu <yang.gu@intel.com>
+Yang Liu <jd9668954@gmail.com>
 Yannic Bonenberger <yannic.bonenberger@gmail.com>
 Yarin Kaul <yarin.kaul@gmail.com>
 Yash Vempati <vempatiy@amazon.com>
@@ -1250,6 +1274,7 @@
 Yizhou Jiang <yizhou.jiang@intel.com>
 Yoav Weiss <yoav@yoav.ws>
 Yoav Zilberberg <yoav.zilberberg@gmail.com>
+Yong Ling <yongling@tencent.com>
 Yong Shin <sy3620@gmail.com>
 Yong Wang <ccyongwang@tencent.com>
 Yongha Lee <yongha78.lee@samsung.com>
@@ -1321,6 +1346,7 @@
 CoSMo Software pvt ltd <*@cosmosoftware.io>
 Cosium <*@cosium.com>
 Dell Technologies Inc. <*@dell.corp-partner.google.com>
+Ding (Beijing) Intelligent Technology Co. Ltd <*@dingdao.com>
 Duck Duck Go, Inc. <*@duckduckgo.com>
 Endless Mobile, Inc. <*@endlessm.com>
 EngFlow, Inc. <*@engflow.com>
diff --git a/base/BUILD b/base/BUILD
index 9de3117..c77528b 100644
--- a/base/BUILD
+++ b/base/BUILD
@@ -38,7 +38,6 @@
         "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",
diff --git a/base/containers/contains.h b/base/containers/contains.h
index 55b1fb5..559ff2c 100644
--- a/base/containers/contains.h
+++ b/base/containers/contains.h
@@ -10,7 +10,6 @@
 
 #include "base/ranges/algorithm.h"
 #include "base/ranges/ranges.h"
-#include "base/template_util.h"
 
 namespace gurl_base {
 
@@ -22,7 +21,7 @@
 struct HasKeyType : std::false_type {};
 
 template <typename T>
-struct HasKeyType<T, void_t<typename T::key_type>> : std::true_type {};
+struct HasKeyType<T, std::void_t<typename T::key_type>> : std::true_type {};
 
 // Probe whether a `contains` member function exists and return the result of
 // `container.contains(value)` if this is a valid expression. This is the
diff --git a/base/containers/contiguous_iterator.h b/base/containers/contiguous_iterator.h
index ca8e7b3..f17a8ed 100644
--- a/base/containers/contiguous_iterator.h
+++ b/base/containers/contiguous_iterator.h
@@ -12,7 +12,6 @@
 #include <vector>
 
 #include "base/containers/checked_iterators.h"
-#include "base/template_util.h"
 
 namespace gurl_base {
 
@@ -28,8 +27,8 @@
 
 template <typename T, typename StringT = std::basic_string<iter_value_t<T>>>
 struct IsStringIterImpl
-    : disjunction<std::is_same<T, typename StringT::const_iterator>,
-                  std::is_same<T, typename StringT::iterator>> {};
+    : std::disjunction<std::is_same<T, typename StringT::const_iterator>,
+                       std::is_same<T, typename StringT::iterator>> {};
 
 // An iterator to std::basic_string is contiguous.
 // Reference: https://wg21.link/basic.string.general#2
@@ -38,22 +37,24 @@
 // `static_assert(is_trivial_v<value_type>)` inside libc++'s std::basic_string.
 template <typename T>
 struct IsStringIter
-    : conjunction<std::is_trivial<iter_value_t<T>>, IsStringIterImpl<T>> {};
+    : std::conjunction<std::is_trivial<iter_value_t<T>>, IsStringIterImpl<T>> {
+};
 
 // An iterator to std::array is contiguous.
 // Reference: https://wg21.link/array.overview#1
 template <typename T, typename ArrayT = std::array<iter_value_t<T>, 1>>
 struct IsArrayIter
-    : disjunction<std::is_same<T, typename ArrayT::const_iterator>,
-                  std::is_same<T, typename ArrayT::iterator>> {};
+    : std::disjunction<std::is_same<T, typename ArrayT::const_iterator>,
+                       std::is_same<T, typename ArrayT::iterator>> {};
 
 // An iterator to a non-bool std::vector is contiguous.
 // Reference: https://wg21.link/vector.overview#2
 template <typename T, typename VectorT = std::vector<iter_value_t<T>>>
 struct IsVectorIter
-    : conjunction<negation<std::is_same<iter_value_t<T>, bool>>,
-                  disjunction<std::is_same<T, typename VectorT::const_iterator>,
-                              std::is_same<T, typename VectorT::iterator>>> {};
+    : std::conjunction<
+          std::negation<std::is_same<iter_value_t<T>, bool>>,
+          std::disjunction<std::is_same<T, typename VectorT::const_iterator>,
+                           std::is_same<T, typename VectorT::iterator>>> {};
 
 // The result of passing a std::valarray to std::begin is a contiguous iterator.
 // Note: Since all common standard library implementations (i.e. libc++,
@@ -67,20 +68,21 @@
 // base's CheckedContiguousIterator is a contiguous iterator.
 template <typename T, typename ValueT = iter_value_t<T>>
 struct IsCheckedContiguousIter
-    : disjunction<std::is_same<T, gurl_base::CheckedContiguousConstIterator<ValueT>>,
-                  std::is_same<T, gurl_base::CheckedContiguousIterator<ValueT>>> {};
+    : std::disjunction<
+          std::is_same<T, gurl_base::CheckedContiguousConstIterator<ValueT>>,
+          std::is_same<T, gurl_base::CheckedContiguousIterator<ValueT>>> {};
 
 // Check that the iterator points to an actual object, and is one of the
 // iterator types mentioned above.
 template <typename T>
 struct IsContiguousIteratorImpl
-    : conjunction<PointsToObject<T>,
-                  disjunction<IsPointer<T>,
-                              IsStringIter<T>,
-                              IsArrayIter<T>,
-                              IsVectorIter<T>,
-                              IsValueArrayIter<T>,
-                              IsCheckedContiguousIter<T>>> {};
+    : std::conjunction<PointsToObject<T>,
+                       std::disjunction<IsPointer<T>,
+                                        IsStringIter<T>,
+                                        IsArrayIter<T>,
+                                        IsVectorIter<T>,
+                                        IsValueArrayIter<T>,
+                                        IsCheckedContiguousIter<T>>> {};
 
 }  // namespace internal
 
diff --git a/base/containers/span.h b/base/containers/span.h
index 1ba60b1..c0fb0b6 100644
--- a/base/containers/span.h
+++ b/base/containers/span.h
@@ -14,13 +14,11 @@
 #include <type_traits>
 #include <utility>
 
-#include "polyfills/base/check_op.h"
+#include "polyfills/base/check.h"
 #include "base/compiler_specific.h"
 #include "base/containers/checked_iterators.h"
 #include "base/containers/contiguous_iterator.h"
-#include "base/cxx17_backports.h"
 #include "base/cxx20_to_address.h"
-#include "base/template_util.h"
 
 namespace gurl_base {
 
@@ -57,7 +55,7 @@
 struct IsSpanImpl<span<T, Extent>> : std::true_type {};
 
 template <typename T>
-using IsNotSpan = negation<IsSpanImpl<std::decay_t<T>>>;
+using IsNotSpan = std::negation<IsSpanImpl<std::decay_t<T>>>;
 
 template <typename T>
 struct IsStdArrayImpl : std::false_type {};
@@ -66,10 +64,10 @@
 struct IsStdArrayImpl<std::array<T, N>> : std::true_type {};
 
 template <typename T>
-using IsNotStdArray = negation<IsStdArrayImpl<std::decay_t<T>>>;
+using IsNotStdArray = std::negation<IsStdArrayImpl<std::decay_t<T>>>;
 
 template <typename T>
-using IsNotCArray = negation<std::is_array<std::remove_reference_t<T>>>;
+using IsNotCArray = std::negation<std::is_array<std::remove_reference_t<T>>>;
 
 template <typename From, typename To>
 using IsLegalDataConversion = std::is_convertible<From (*)[], To (*)[]>;
@@ -80,17 +78,17 @@
 
 template <typename Iter, typename T>
 using EnableIfCompatibleContiguousIterator = std::enable_if_t<
-    conjunction<IsContiguousIterator<Iter>,
-                IteratorHasConvertibleReferenceType<Iter, T>>::value>;
+    std::conjunction<IsContiguousIterator<Iter>,
+                     IteratorHasConvertibleReferenceType<Iter, T>>::value>;
 
 template <typename Container, typename T>
 using ContainerHasConvertibleData = IsLegalDataConversion<
-    std::remove_pointer_t<decltype(gurl_base::data(std::declval<Container>()))>,
+    std::remove_pointer_t<decltype(std::data(std::declval<Container>()))>,
     T>;
 
 template <typename Container>
 using ContainerHasIntegralSize =
-    std::is_integral<decltype(gurl_base::size(std::declval<Container>()))>;
+    std::is_integral<decltype(std::size(std::declval<Container>()))>;
 
 template <typename From, size_t FromExtent, typename To, size_t ToExtent>
 using EnableIfLegalSpanConversion =
@@ -107,11 +105,11 @@
 // SFINAE check if Container can be converted to a span<T>.
 template <typename Container, typename T>
 using IsSpanCompatibleContainer =
-    conjunction<IsNotSpan<Container>,
-                IsNotStdArray<Container>,
-                IsNotCArray<Container>,
-                ContainerHasConvertibleData<Container, T>,
-                ContainerHasIntegralSize<Container>>;
+    std::conjunction<IsNotSpan<Container>,
+                     IsNotStdArray<Container>,
+                     IsNotCArray<Container>,
+                     ContainerHasConvertibleData<Container, T>,
+                     ContainerHasIntegralSize<Container>>;
 
 template <typename Container, typename T>
 using EnableIfSpanCompatibleContainer =
@@ -297,7 +295,7 @@
   template <
       size_t N,
       typename = internal::EnableIfSpanCompatibleArray<T (&)[N], T, Extent>>
-  constexpr span(T (&array)[N]) noexcept : span(gurl_base::data(array), N) {}
+  constexpr span(T (&array)[N]) noexcept : span(std::data(array), N) {}
 
   template <
       typename U,
@@ -305,17 +303,17 @@
       typename =
           internal::EnableIfSpanCompatibleArray<std::array<U, N>&, T, Extent>>
   constexpr span(std::array<U, N>& array) noexcept
-      : span(gurl_base::data(array), N) {}
+      : span(std::data(array), N) {}
 
   template <typename U,
             size_t N,
             typename = internal::
                 EnableIfSpanCompatibleArray<const std::array<U, N>&, T, Extent>>
   constexpr span(const std::array<U, N>& array) noexcept
-      : span(gurl_base::data(array), N) {}
+      : span(std::data(array), N) {}
 
-  // Conversion from a container that has compatible gurl_base::data() and integral
-  // gurl_base::size().
+  // Conversion from a container that has compatible std::data() and integral
+  // std::size().
   template <
       typename Container,
       typename =
@@ -323,7 +321,7 @@
                                                                     T,
                                                                     Extent>>
   constexpr span(Container& container) noexcept
-      : span(gurl_base::data(container), gurl_base::size(container)) {}
+      : span(std::data(container), std::size(container)) {}
 
   template <
       typename Container,
@@ -332,7 +330,7 @@
           T,
           Extent>>
   constexpr span(const Container& container) noexcept
-      : span(gurl_base::data(container), gurl_base::size(container)) {}
+      : span(std::data(container), std::size(container)) {}
 
   constexpr span(const span& other) noexcept = default;
 
@@ -485,7 +483,7 @@
 template <int&... ExplicitArgumentBarrier, typename Container>
 constexpr auto make_span(Container&& container) noexcept {
   using T =
-      std::remove_pointer_t<decltype(gurl_base::data(std::declval<Container>()))>;
+      std::remove_pointer_t<decltype(std::data(std::declval<Container>()))>;
   using Extent = internal::Extent<Container>;
   return span<T, Extent::value>(std::forward<Container>(container));
 }
@@ -510,8 +508,8 @@
 template <size_t N, int&... ExplicitArgumentBarrier, typename Container>
 constexpr auto make_span(Container&& container) noexcept {
   using T =
-      std::remove_pointer_t<decltype(gurl_base::data(std::declval<Container>()))>;
-  return span<T, N>(gurl_base::data(container), gurl_base::size(container));
+      std::remove_pointer_t<decltype(std::data(std::declval<Container>()))>;
+  return span<T, N>(std::data(container), std::size(container));
 }
 
 }  // namespace base
@@ -520,7 +518,7 @@
 // with definite extent, i.e. everything that is a contiguous storage of some
 // sort with static size. Specifically, this works for std::array in a constexpr
 // context. Note:
-//   * |gurl_base::size| should be preferred for plain arrays.
+//   * |std::size| should be preferred for plain arrays.
 //   * In run-time contexts, functions such as |std::array::size| should be
 //     preferred.
 #define EXTENT(x)                                        \
diff --git a/base/cxx17_backports.h b/base/cxx17_backports.h
index 81e573f..86976d4 100644
--- a/base/cxx17_backports.h
+++ b/base/cxx17_backports.h
@@ -5,11 +5,7 @@
 #ifndef BASE_CXX17_BACKPORTS_H_
 #define BASE_CXX17_BACKPORTS_H_
 
-#include <array>
 #include <functional>
-#include <initializer_list>
-#include <memory>
-#include <string>
 #include <tuple>
 #include <type_traits>
 #include <utility>
@@ -19,83 +15,6 @@
 
 namespace gurl_base {
 
-// C++14 implementation of C++17's std::size():
-// http://en.cppreference.com/w/cpp/iterator/size
-template <typename Container>
-constexpr auto size(const Container& c) -> decltype(c.size()) {
-  return c.size();
-}
-
-template <typename T, size_t N>
-constexpr size_t size(const T (&array)[N]) noexcept {
-  return N;
-}
-
-// C++14 implementation of C++17's std::empty():
-// http://en.cppreference.com/w/cpp/iterator/empty
-template <typename Container>
-constexpr auto empty(const Container& c) -> decltype(c.empty()) {
-  return c.empty();
-}
-
-template <typename T, size_t N>
-constexpr bool empty(const T (&array)[N]) noexcept {
-  return false;
-}
-
-template <typename T>
-constexpr bool empty(std::initializer_list<T> il) noexcept {
-  return il.size() == 0;
-}
-
-// C++14 implementation of C++17's std::data():
-// http://en.cppreference.com/w/cpp/iterator/data
-template <typename Container>
-constexpr auto data(Container& c) -> decltype(c.data()) {
-  return c.data();
-}
-
-// std::basic_string::data() had no mutable overload prior to C++17 [1].
-// Hence this overload is provided.
-// Note: str[0] is safe even for empty strings, as they are guaranteed to be
-// null-terminated [2].
-//
-// [1] http://en.cppreference.com/w/cpp/string/basic_string/data
-// [2] http://en.cppreference.com/w/cpp/string/basic_string/operator_at
-template <typename CharT, typename Traits, typename Allocator>
-CharT* data(std::basic_string<CharT, Traits, Allocator>& str) {
-  return std::addressof(str[0]);
-}
-
-template <typename Container>
-constexpr auto data(const Container& c) -> decltype(c.data()) {
-  return c.data();
-}
-
-template <typename T, size_t N>
-constexpr T* data(T (&array)[N]) noexcept {
-  return array;
-}
-
-template <typename T>
-constexpr const T* data(std::initializer_list<T> il) noexcept {
-  return il.begin();
-}
-
-// std::array::data() was not constexpr prior to C++17 [1].
-// Hence these overloads are provided.
-//
-// [1] https://en.cppreference.com/w/cpp/container/array/data
-template <typename T, size_t N>
-constexpr T* data(std::array<T, N>& array) noexcept {
-  return !array.empty() ? &array[0] : nullptr;
-}
-
-template <typename T, size_t N>
-constexpr const T* data(const std::array<T, N>& array) noexcept {
-  return !array.empty() ? &array[0] : nullptr;
-}
-
 // C++14 implementation of C++17's std::clamp():
 // https://en.cppreference.com/w/cpp/algorithm/clamp
 // Please note that the C++ spec makes it undefined behavior to call std::clamp
diff --git a/base/debug/crash_logging.cc b/base/debug/crash_logging.cc
index f6bad4f..a6e3719 100644
--- a/base/debug/crash_logging.cc
+++ b/base/debug/crash_logging.cc
@@ -35,7 +35,7 @@
   g_crash_key_impl->Clear(crash_key);
 }
 
-BASE_EXPORT void OutputCrashKeysToStream(std::ostream& out) {
+void OutputCrashKeysToStream(std::ostream& out) {
   if (!g_crash_key_impl)
     return;
 
diff --git a/base/debug/crash_logging.h b/base/debug/crash_logging.h
index fdc5343..98f40c1 100644
--- a/base/debug/crash_logging.h
+++ b/base/debug/crash_logging.h
@@ -12,7 +12,6 @@
 #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"
@@ -125,7 +124,7 @@
 // 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,                   \
+  static_assert(::std::size(category "-" name) < 40,                    \
                 "Crash key names must be shorter than 40 characters."); \
   ::gurl_base::debug::ScopedCrashKeyString scoped_crash_key_helper##nonce(   \
       [] {                                                              \
diff --git a/base/memory/raw_ptr.h b/base/memory/raw_ptr.h
index 16094d3..ad53dc5 100644
--- a/base/memory/raw_ptr.h
+++ b/base/memory/raw_ptr.h
@@ -14,29 +14,44 @@
 #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 "polyfills/third_party/perfetto/include/perfetto/tracing/traced_value.h"
 #include "build/build_config.h"
 #include "build/buildflag.h"
 
-#if BUILDFLAG(USE_BACKUP_REF_PTR)
+#if BUILDFLAG(USE_BACKUP_REF_PTR) || \
+    defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS)
 // 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)
+#endif  // BUILDFLAG(USE_BACKUP_REF_PTR) ||
+        // defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS)
+
+#if defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS)
+#include "base/allocator/partition_allocator/partition_tag.h"
+#include "base/allocator/partition_allocator/tagging.h"
+#endif  // defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS)
 
 #if BUILDFLAG(IS_WIN)
 #include <windows.h>
 #endif
 
+#if defined(OFFICIAL_BUILD)
+// The annotation changed compiler output and increased binary size so disable
+// for official builds.
+// TODO(crbug.com/1320670): Remove when issue is resolved.
+#define RAW_PTR_EXCLUSION
+#else
 // 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")))
+#endif
 
 namespace cc {
 class Scheduler;
@@ -50,13 +65,8 @@
 
 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
+// NOTE: All methods should be `ALWAYS_INLINE`. raw_ptr is meant to be a
+// lightweight replacement of a raw pointer, hence performance is critical.
 
 namespace internal {
 // These classes/structures are part of the raw_ptr implementation.
@@ -65,41 +75,38 @@
 struct RawPtrNoOpImpl {
   // Wraps a pointer.
   template <typename T>
-  static RAW_PTR_FUNC_ATTRIBUTES T* WrapRawPtr(T* ptr) {
+  static ALWAYS_INLINE 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*) {}
+  static ALWAYS_INLINE 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) {
+  static ALWAYS_INLINE 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) {
+  static ALWAYS_INLINE 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) {
+  static ALWAYS_INLINE 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 ALWAYS_INLINE 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
@@ -109,24 +116,180 @@
 
   // Advance the wrapped pointer by |delta| bytes.
   template <typename T>
-  static RAW_PTR_FUNC_ATTRIBUTES T* Advance(T* wrapped_ptr,
-                                            ptrdiff_t delta_elems) {
+  static ALWAYS_INLINE 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) {
+  static ALWAYS_INLINE 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() {}
+  static ALWAYS_INLINE void IncrementSwapCountForTest() {}
+  static ALWAYS_INLINE void IncrementPointerToMemberOperatorCountForTest() {}
 };
 
+#if defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS)
+
+constexpr int kValidAddressBits = 48;
+constexpr uintptr_t kAddressMask = (1ull << kValidAddressBits) - 1;
+constexpr int kTagBits = sizeof(uintptr_t) * 8 - kValidAddressBits;
+
+// MTECheckedPtr has no business with the topmost bits reserved for the
+// tag used by true ARM MTE, so we strip it out here.
+constexpr uintptr_t kTagMask =
+    ~kAddressMask & partition_alloc::internal::kMemTagUnmask;
+
+constexpr int kTopBitShift = 63;
+constexpr uintptr_t kTopBit = 1ull << kTopBitShift;
+static_assert(kTopBit << 1 == 0, "kTopBit should really be the top bit");
+static_assert((kTopBit & kTagMask) > 0,
+              "kTopBit bit must be inside the tag region");
+
+// This functionality is outside of MTECheckedPtrImpl, so that it can be
+// overridden by tests.
+struct MTECheckedPtrImplPartitionAllocSupport {
+  // Checks if the necessary support is enabled in PartitionAlloc for `ptr`.
+  template <typename T>
+  static ALWAYS_INLINE bool EnabledForPtr(T* ptr) {
+    auto as_uintptr =
+        partition_alloc::internal::UnmaskPtr(reinterpret_cast<uintptr_t>(ptr));
+    // MTECheckedPtr algorithms work only when memory is
+    // allocated by PartitionAlloc, from normal buckets pool.
+    //
+    // TODO(crbug.com/1307514): Allow direct-map buckets.
+    return IsManagedByPartitionAlloc(as_uintptr) &&
+           IsManagedByNormalBuckets(as_uintptr);
+  }
+
+  // Returns pointer to the tag that protects are pointed by |ptr|.
+  static ALWAYS_INLINE void* TagPointer(uintptr_t ptr) {
+    return partition_alloc::PartitionTagPointer(ptr);
+  }
+};
+
+template <typename PartitionAllocSupport>
+struct MTECheckedPtrImpl {
+  // This implementation assumes that pointers are 64 bits long and at least 16
+  // top bits are unused. The latter is harder to verify statically, but this is
+  // true for all currently supported 64-bit architectures (GURL_DCHECK when wrapping
+  // will verify that).
+  static_assert(sizeof(void*) >= 8, "Need 64-bit pointers");
+
+  // Wraps a pointer, and returns its uintptr_t representation.
+  template <typename T>
+  static ALWAYS_INLINE T* WrapRawPtr(T* ptr) {
+    uintptr_t addr = reinterpret_cast<uintptr_t>(ptr);
+    GURL_DCHECK_EQ(ExtractTag(addr), 0ull);
+
+    // Return a not-wrapped |addr|, if it's either nullptr or if the protection
+    // for this pointer is disabled.
+    if (!PartitionAllocSupport::EnabledForPtr(ptr)) {
+      return reinterpret_cast<T*>(addr);
+    }
+
+    // Read the tag and place it in the top bits of the address.
+    // Even if PartitionAlloc's tag has less than kTagBits, we'll read
+    // what's given and pad the rest with 0s.
+    static_assert(sizeof(partition_alloc::PartitionTag) * 8 <= kTagBits, "");
+    uintptr_t tag = *(static_cast<volatile partition_alloc::PartitionTag*>(
+        PartitionAllocSupport::TagPointer(addr)));
+
+    tag <<= kValidAddressBits;
+    addr |= tag;
+    return reinterpret_cast<T*>(addr);
+  }
+
+  // Notifies the allocator when a wrapped pointer is being removed or replaced.
+  // No-op for MTECheckedPtrImpl.
+  template <typename T>
+  static ALWAYS_INLINE void ReleaseWrappedPtr(T*) {}
+
+  // Unwraps the pointer's uintptr_t representation, while asserting that memory
+  // hasn't been freed. The function is allowed to crash on nullptr.
+  template <typename T>
+  static ALWAYS_INLINE T* SafelyUnwrapPtrForDereference(T* wrapped_ptr) {
+    uintptr_t wrapped_addr = reinterpret_cast<uintptr_t>(wrapped_ptr);
+    uintptr_t tag = ExtractTag(wrapped_addr);
+    if (tag > 0) {
+      // Read the tag provided by PartitionAlloc.
+      //
+      // Cast to volatile to ensure memory is read. E.g. in a tight loop, the
+      // compiler could cache the value in a register and thus could miss that
+      // another thread freed memory and changed tag.
+      uintptr_t read_tag =
+          *static_cast<volatile partition_alloc::PartitionTag*>(
+              PartitionAllocSupport::TagPointer(ExtractAddress(wrapped_addr)));
+      if (UNLIKELY(tag != read_tag))
+        IMMEDIATE_CRASH();
+      return reinterpret_cast<T*>(ExtractAddress(wrapped_addr));
+    }
+    return wrapped_ptr;
+  }
+
+  // Unwraps the pointer's uintptr_t representation, while asserting that memory
+  // hasn't been freed. The function must handle nullptr gracefully.
+  template <typename T>
+  static ALWAYS_INLINE T* SafelyUnwrapPtrForExtraction(T* wrapped_ptr) {
+    // SafelyUnwrapPtrForDereference handles nullptr case well.
+    return SafelyUnwrapPtrForDereference(wrapped_ptr);
+  }
+
+  // Unwraps the pointer's uintptr_t representation, without making an assertion
+  // on whether memory was freed or not.
+  template <typename T>
+  static ALWAYS_INLINE T* UnsafelyUnwrapPtrForComparison(T* wrapped_ptr) {
+    return ExtractPtr(wrapped_ptr);
+  }
+
+  // Upcasts the wrapped pointer.
+  template <typename To, typename From>
+  static ALWAYS_INLINE constexpr To* Upcast(From* wrapped_ptr) {
+    static_assert(std::is_convertible<From*, To*>::value,
+                  "From must be convertible to To.");
+
+    // The top-bit tag must not affect the result of upcast.
+    return static_cast<To*>(wrapped_ptr);
+  }
+
+  // Advance the wrapped pointer by |delta| bytes.
+  template <typename T>
+  static ALWAYS_INLINE T* Advance(T* wrapped_ptr, ptrdiff_t delta_elem) {
+    return wrapped_ptr + delta_elem;
+  }
+
+  // Returns a copy of a wrapped pointer, without making an assertion
+  // on whether memory was freed or not.
+  template <typename T>
+  static ALWAYS_INLINE T* Duplicate(T* wrapped_ptr) {
+    return wrapped_ptr;
+  }
+
+  // This is for accounting only, used by unit tests.
+  static ALWAYS_INLINE void IncrementSwapCountForTest() {}
+  static ALWAYS_INLINE void IncrementPointerToMemberOperatorCountForTest() {}
+
+ private:
+  static ALWAYS_INLINE uintptr_t ExtractAddress(uintptr_t wrapped_ptr) {
+    return wrapped_ptr & kAddressMask;
+  }
+
+  template <typename T>
+  static ALWAYS_INLINE T* ExtractPtr(T* wrapped_ptr) {
+    return reinterpret_cast<T*>(
+        ExtractAddress(reinterpret_cast<uintptr_t>(wrapped_ptr)));
+  }
+
+  static ALWAYS_INLINE uintptr_t ExtractTag(uintptr_t wrapped_ptr) {
+    return (wrapped_ptr & kTagMask) >> kValidAddressBits;
+  }
+};
+
+#endif  // defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS)
+
 #if BUILDFLAG(USE_BACKUP_REF_PTR)
 
 #if GURL_DCHECK_IS_ON() || BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS)
@@ -134,12 +297,13 @@
     uintptr_t address);
 #endif
 
+template <bool AllowDangling = false>
 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) {
+  static ALWAYS_INLINE bool IsSupportedAndNotNull(uintptr_t address) {
     // This covers the nullptr case, as address 0 is never in GigaCage.
     bool is_in_brp_pool = IsManagedByPartitionAllocBRPPool(address);
 
@@ -192,7 +356,7 @@
 
   // Wraps a pointer.
   template <typename T>
-  static RAW_PTR_FUNC_ATTRIBUTES T* WrapRawPtr(T* ptr) {
+  static ALWAYS_INLINE 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)
@@ -211,7 +375,7 @@
 
   // 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) {
+  static ALWAYS_INLINE 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)
@@ -231,8 +395,7 @@
   // 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) {
+  static ALWAYS_INLINE 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)) {
@@ -246,22 +409,20 @@
   // 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) {
+  static ALWAYS_INLINE 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) {
+  static ALWAYS_INLINE 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 ALWAYS_INLINE 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
@@ -271,8 +432,7 @@
 
   // Advance the wrapped pointer by |delta| bytes.
   template <typename T>
-  static RAW_PTR_FUNC_ATTRIBUTES T* Advance(T* wrapped_ptr,
-                                            ptrdiff_t delta_elem) {
+  static ALWAYS_INLINE 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))
@@ -287,14 +447,13 @@
   // 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) {
+  static ALWAYS_INLINE 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() {}
+  static ALWAYS_INLINE void IncrementSwapCountForTest() {}
+  static ALWAYS_INLINE void IncrementPointerToMemberOperatorCountForTest() {}
 
  private:
   // We've evaluated several strategies (inline nothing, various parts, or
@@ -316,20 +475,19 @@
 struct AsanBackupRefPtrImpl {
   // Wraps a pointer.
   template <typename T>
-  static RAW_PTR_FUNC_ATTRIBUTES T* WrapRawPtr(T* ptr) {
+  static ALWAYS_INLINE 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*) {}
+  static ALWAYS_INLINE 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) {
+  static ALWAYS_INLINE T* SafelyUnwrapPtrForDereference(T* wrapped_ptr) {
     AsanCheckIfValidDereference(wrapped_ptr);
     return wrapped_ptr;
   }
@@ -337,8 +495,7 @@
   // 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) {
+  static ALWAYS_INLINE T* SafelyUnwrapPtrForExtraction(T* wrapped_ptr) {
     AsanCheckIfValidExtraction(wrapped_ptr);
     return wrapped_ptr;
   }
@@ -346,14 +503,13 @@
   // 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) {
+  static ALWAYS_INLINE 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 ALWAYS_INLINE 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
@@ -363,22 +519,20 @@
 
   // Advance the wrapped pointer by |delta| bytes.
   template <typename T>
-  static RAW_PTR_FUNC_ATTRIBUTES T* Advance(T* wrapped_ptr,
-                                            ptrdiff_t delta_elems) {
+  static ALWAYS_INLINE 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) {
+  static ALWAYS_INLINE 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() {}
+  static ALWAYS_INLINE void IncrementSwapCountForTest() {}
+  static ALWAYS_INLINE void IncrementPointerToMemberOperatorCountForTest() {}
 
  private:
   static BASE_EXPORT NOINLINE void AsanCheckIfValidInstantiation(
@@ -494,14 +648,24 @@
 // 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>
+using RawPtrMayDangle = internal::BackupRefPtrImpl</*AllowDangling=*/true>;
+using RawPtrBanDanglingIfSupported =
+    internal::BackupRefPtrImpl</*AllowDangling=*/false>;
 #elif BUILDFLAG(USE_ASAN_BACKUP_REF_PTR)
-          typename Impl = internal::AsanBackupRefPtrImpl>
+using RawPtrMayDangle = internal::AsanBackupRefPtrImpl;
+using RawPtrBanDanglingIfSupported = internal::AsanBackupRefPtrImpl;
+#elif defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS)
+using RawPtrMayDangle = internal::MTECheckedPtrImpl<
+    internal::MTECheckedPtrImplPartitionAllocSupport>;
+using RawPtrBanDanglingIfSupported = internal::MTECheckedPtrImpl<
+    internal::MTECheckedPtrImplPartitionAllocSupport>;
 #else
-          typename Impl = internal::RawPtrNoOpImpl>
+using RawPtrMayDangle = internal::RawPtrNoOpImpl;
+using RawPtrBanDanglingIfSupported = internal::RawPtrNoOpImpl;
 #endif
+
+template <typename T, typename Impl = RawPtrBanDanglingIfSupported>
 class TRIVIAL_ABI GSL_POINTER raw_ptr {
  public:
   static_assert(raw_ptr_traits::IsSupportedType<T>::value,
@@ -509,18 +673,17 @@
 
 #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) {}
+  constexpr ALWAYS_INLINE raw_ptr() noexcept : wrapped_ptr_(nullptr) {}
 
-  RAW_PTR_FUNC_ATTRIBUTES raw_ptr(const raw_ptr& p) noexcept
+  ALWAYS_INLINE raw_ptr(const raw_ptr& p) noexcept
       : wrapped_ptr_(Impl::Duplicate(p.wrapped_ptr_)) {}
 
-  RAW_PTR_FUNC_ATTRIBUTES raw_ptr(raw_ptr&& p) noexcept {
+  ALWAYS_INLINE 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) {
+  ALWAYS_INLINE 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_);
@@ -528,7 +691,7 @@
     return *this;
   }
 
-  RAW_PTR_FUNC_ATTRIBUTES raw_ptr& operator=(raw_ptr&& p) {
+  ALWAYS_INLINE raw_ptr& operator=(raw_ptr&& p) {
     if (LIKELY(this != &p)) {
       Impl::ReleaseWrappedPtr(wrapped_ptr_);
       wrapped_ptr_ = p.wrapped_ptr_;
@@ -537,7 +700,7 @@
     return *this;
   }
 
-  RAW_PTR_FUNC_ATTRIBUTES ~raw_ptr() noexcept {
+  ALWAYS_INLINE ~raw_ptr() noexcept {
     Impl::ReleaseWrappedPtr(wrapped_ptr_);
     // Work around external issues where raw_ptr is used after destruction.
     wrapped_ptr_ = nullptr;
@@ -550,31 +713,30 @@
   //
   // TODO(lukasza): Always initialize |wrapped_ptr_|.  Fix resulting build
   // errors.  Analyze performance impact.
-  constexpr RAW_PTR_FUNC_ATTRIBUTES raw_ptr() noexcept = default;
+  constexpr ALWAYS_INLINE 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;
+  ALWAYS_INLINE raw_ptr(const raw_ptr&) noexcept = default;
+  ALWAYS_INLINE raw_ptr(raw_ptr&&) noexcept = default;
+  ALWAYS_INLINE raw_ptr& operator=(const raw_ptr&) noexcept = default;
+  ALWAYS_INLINE raw_ptr& operator=(raw_ptr&&) noexcept = default;
 
-  RAW_PTR_FUNC_ATTRIBUTES ~raw_ptr() = default;
+  ALWAYS_INLINE ~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
+  constexpr ALWAYS_INLINE 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)) {}
+  ALWAYS_INLINE raw_ptr(T* p) noexcept : wrapped_ptr_(Impl::WrapRawPtr(p)) {}
 
   // Deliberately implicit in order to support implicit upcast.
   template <typename U,
@@ -582,7 +744,7 @@
                 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
+  ALWAYS_INLINE 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.
@@ -591,19 +753,19 @@
                 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
+  ALWAYS_INLINE 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 {
+  ALWAYS_INLINE 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 {
+  ALWAYS_INLINE raw_ptr& operator=(T* p) noexcept {
     Impl::ReleaseWrappedPtr(wrapped_ptr_);
     wrapped_ptr_ = Impl::WrapRawPtr(p);
     return *this;
@@ -614,8 +776,7 @@
             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 {
+  ALWAYS_INLINE 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)
@@ -631,7 +792,7 @@
             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 {
+  ALWAYS_INLINE 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)
@@ -648,19 +809,17 @@
 
   // 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(); }
+  ALWAYS_INLINE T* get() const { return GetForExtraction(); }
 
-  explicit RAW_PTR_FUNC_ATTRIBUTES operator bool() const {
-    return !!wrapped_ptr_;
-  }
+  explicit ALWAYS_INLINE 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 {
+  ALWAYS_INLINE U& operator*() const {
     return *GetForDereference();
   }
-  RAW_PTR_FUNC_ATTRIBUTES T* operator->() const { return GetForDereference(); }
+  ALWAYS_INLINE T* operator->() const { return GetForDereference(); }
 
   // Disables `(my_raw_ptr->*pmf)(...)` as a workaround for
   // the ICE in GCC parsing the code, reported at
@@ -670,37 +829,37 @@
 
   // Deliberately implicit, because raw_ptr is supposed to resemble raw ptr.
   // NOLINTNEXTLINE(runtime/explicit)
-  RAW_PTR_FUNC_ATTRIBUTES operator T*() const { return GetForExtraction(); }
+  ALWAYS_INLINE operator T*() const { return GetForExtraction(); }
   template <typename U>
-  explicit RAW_PTR_FUNC_ATTRIBUTES operator U*() const {
+  explicit ALWAYS_INLINE 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++() {
+  ALWAYS_INLINE raw_ptr& operator++() {
     wrapped_ptr_ = Impl::Advance(wrapped_ptr_, 1);
     return *this;
   }
-  RAW_PTR_FUNC_ATTRIBUTES raw_ptr& operator--() {
+  ALWAYS_INLINE raw_ptr& operator--() {
     wrapped_ptr_ = Impl::Advance(wrapped_ptr_, -1);
     return *this;
   }
-  RAW_PTR_FUNC_ATTRIBUTES raw_ptr operator++(int /* post_increment */) {
+  ALWAYS_INLINE raw_ptr operator++(int /* post_increment */) {
     raw_ptr result = *this;
     ++(*this);
     return result;
   }
-  RAW_PTR_FUNC_ATTRIBUTES raw_ptr operator--(int /* post_decrement */) {
+  ALWAYS_INLINE raw_ptr operator--(int /* post_decrement */) {
     raw_ptr result = *this;
     --(*this);
     return result;
   }
-  RAW_PTR_FUNC_ATTRIBUTES raw_ptr& operator+=(ptrdiff_t delta_elems) {
+  ALWAYS_INLINE 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) {
+  ALWAYS_INLINE raw_ptr& operator-=(ptrdiff_t delta_elems) {
     return *this += -delta_elems;
   }
 
@@ -708,13 +867,25 @@
   // 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 {
+  ALWAYS_INLINE void ClearAndDelete() noexcept {
+#if defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS)
+    // We cannot directly `delete` a wrapped pointer, since the tag bits
+    // atop will lead PA totally astray.
+    T* ptr = Impl::SafelyUnwrapPtrForExtraction(wrapped_ptr_);
+#else
     T* ptr = wrapped_ptr_;
+#endif  // defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS)
     operator=(nullptr);
     delete ptr;
   }
-  RAW_PTR_FUNC_ATTRIBUTES void ClearAndDeleteArray() noexcept {
+  ALWAYS_INLINE void ClearAndDeleteArray() noexcept {
+#if defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS)
+    // We cannot directly `delete` a wrapped pointer, since the tag bits
+    // atop will lead PA totally astray.
+    T* ptr = Impl::SafelyUnwrapPtrForExtraction(wrapped_ptr_);
+#else
     T* ptr = wrapped_ptr_;
+#endif  // defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS)
     operator=(nullptr);
     delete[] ptr;
   }
@@ -733,118 +904,121 @@
   // 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);
+  friend ALWAYS_INLINE 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) {
+  friend ALWAYS_INLINE 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);
+  friend ALWAYS_INLINE 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);
+  friend ALWAYS_INLINE 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);
+  friend ALWAYS_INLINE 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);
+  friend ALWAYS_INLINE 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) {
+  friend ALWAYS_INLINE 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) {
+  friend ALWAYS_INLINE 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) {
+  friend ALWAYS_INLINE 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) {
+  friend ALWAYS_INLINE 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) {
+  friend ALWAYS_INLINE 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) {
+  friend ALWAYS_INLINE 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) {
+  friend ALWAYS_INLINE 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) {
+  friend ALWAYS_INLINE 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) {
+  friend ALWAYS_INLINE 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) {
+  friend ALWAYS_INLINE 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) {
+  friend ALWAYS_INLINE 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) {
+  friend ALWAYS_INLINE 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) {
+  friend ALWAYS_INLINE 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) {
+  friend ALWAYS_INLINE 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) {
+  friend ALWAYS_INLINE 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) {
+  friend ALWAYS_INLINE 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 {
+  friend ALWAYS_INLINE void swap(raw_ptr& lhs, raw_ptr& rhs) noexcept {
     Impl::IncrementSwapCountForTest();
     std::swap(lhs.wrapped_ptr_, rhs.wrapped_ptr_);
   }
 
+  // If T can be serialised into trace, its alias is also
+  // serialisable.
+  template <class U = T>
+  typename perfetto::check_traced_value_support<U>::type WriteIntoTrace(
+      perfetto::TracedValue&& context) const {
+    perfetto::WriteIntoTracedValue(std::move(context), get());
+  }
+
  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 {
+  ALWAYS_INLINE 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 {
+  ALWAYS_INLINE 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 {
+  ALWAYS_INLINE T* GetForComparison() const {
     return Impl::UnsafelyUnwrapPtrForComparison(wrapped_ptr_);
   }
 
@@ -855,32 +1029,32 @@
 };
 
 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) {
+ALWAYS_INLINE 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) {
+ALWAYS_INLINE 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) {
+ALWAYS_INLINE 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) {
+ALWAYS_INLINE 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) {
+ALWAYS_INLINE bool operator>=(const raw_ptr<U, I>& lhs,
+                              const raw_ptr<V, I>& rhs) {
   return lhs.GetForComparison() >= rhs.GetForComparison();
 }
 
@@ -888,6 +1062,17 @@
 
 using gurl_base::raw_ptr;
 
+// DisableDanglingPtrDetection option for raw_ptr annotates
+// "intentional-and-safe" dangling pointers. It is meant to be used at the
+// margin, only if there is no better way to re-architecture the code.
+//
+// Usage:
+// raw_ptr<T, DisableDanglingPtrDetection> dangling_ptr;
+//
+// When using it, please provide a justification about what guarantees it will
+// never be dereferenced after becoming dangling.
+using DisableDanglingPtrDetection = gurl_base::RawPtrMayDangle;
+
 namespace std {
 
 // Override so set/map lookups do not create extra raw_ptr. This also allows
diff --git a/base/ranges/algorithm.h b/base/ranges/algorithm.h
index b405d2f..f7a23c4 100644
--- a/base/ranges/algorithm.h
+++ b/base/ranges/algorithm.h
@@ -63,9 +63,9 @@
 
  private:
   template <typename ProjT, typename ProjU, typename T, typename U>
-  using InvokeResult = invoke_result_t<Pred&,
-                                       invoke_result_t<ProjT&, T&&>,
-                                       invoke_result_t<ProjU&, U&&>>;
+  using InvokeResult = std::invoke_result_t<Pred&,
+                                            std::invoke_result_t<ProjT&, T&&>,
+                                            std::invoke_result_t<ProjU&, U&&>>;
 
   template <typename T, typename U, typename = InvokeResult<Proj1, Proj2, T, U>>
   constexpr std::pair<Proj1&, Proj2&> GetProjs(priority_tag<3>) const {
diff --git a/base/strings/abseil_string_number_conversions.cc b/base/strings/abseil_string_number_conversions.cc
index 9ab1303..aab4905 100644
--- a/base/strings/abseil_string_number_conversions.cc
+++ b/base/strings/abseil_string_number_conversions.cc
@@ -10,6 +10,10 @@
 
 namespace gurl_base {
 
+bool StringToUint128(StringPiece input, absl::uint128* output) {
+  return internal::StringToIntImpl(input, *output);
+}
+
 bool HexStringToUInt128(StringPiece input, absl::uint128* output) {
   return internal::HexStringToIntImpl(input, *output);
 }
diff --git a/base/strings/abseil_string_number_conversions.h b/base/strings/abseil_string_number_conversions.h
index 7eb927d..85d6d29 100644
--- a/base/strings/abseil_string_number_conversions.h
+++ b/base/strings/abseil_string_number_conversions.h
@@ -15,7 +15,11 @@
 namespace gurl_base {
 
 // Best effort conversion, see `gurl_base::StringToInt()` for restrictions.
-// Will only successfully parse hex values that will fit into |output|.
+// Will only successfully parse values that will fit into `output`.
+BASE_EXPORT bool StringToUint128(StringPiece input, absl::uint128* output);
+
+// 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);
 
diff --git a/base/strings/abseil_string_number_conversions_unittest.cc b/base/strings/abseil_string_number_conversions_unittest.cc
index 3c68cde..5873e79 100644
--- a/base/strings/abseil_string_number_conversions_unittest.cc
+++ b/base/strings/abseil_string_number_conversions_unittest.cc
@@ -8,13 +8,89 @@
 
 #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, StringToUint128) {
+  // Test cases adapted from `StringNumberConversionsTest.StringToUint64`.
+  static const struct {
+    std::string input;
+    absl::uint128 output;
+    bool success;
+  } cases[] = {
+      {"0", 0, true},
+      {"42", 42, true},
+      {"-2147483648", 0, false},
+      {"2147483647", INT_MAX, true},
+      {"-2147483649", 0, false},
+      {"-99999999999", 0, false},
+      {"2147483648", UINT64_C(2147483648), true},
+      {"99999999999", UINT64_C(99999999999), true},
+      {"9223372036854775807", std::numeric_limits<int64_t>::max(), true},
+      {"-9223372036854775808", 0, false},
+      {"09", 9, true},
+      {"-09", 0, false},
+      {"", 0, false},
+      {" 42", 42, false},
+      {"42 ", 42, false},
+      {"0x42", 0, false},
+      {"\t\n\v\f\r 42", 42, false},
+      {"blah42", 0, false},
+      {"42blah", 42, false},
+      {"blah42blah", 0, false},
+      {"-273.15", 0, false},
+      {"+98.6", 98, false},
+      {"--123", 0, false},
+      {"++123", 0, false},
+      {"-+123", 0, false},
+      {"+-123", 0, false},
+      {"-", 0, false},
+      {"-9223372036854775809", 0, false},
+      {"-99999999999999999999", 0, false},
+      {"9223372036854775808", UINT64_C(9223372036854775808), true},
+      {"99999999999999999999",
+       absl::MakeUint128(/*high=*/5, /*low=*/UINT64_C(7766279631452241919)),
+       true},
+      {"18446744073709551615", std::numeric_limits<uint64_t>::max(), true},
+      {"18446744073709551616", absl::MakeUint128(/*high=*/1, /*low=*/0), true},
+      {"123456789012345678901234567890123456789",
+       absl::MakeUint128(/*high=*/UINT64_C(6692605942763486917),
+                         /*low=*/UINT64_C(12312739301371248917)),
+       true},
+      {"-170141183460469231731687303715884105728", 0, false},
+      {"-170141183460469231731687303715884105729", 0, false},
+      {"-999999999999999999999999999999999999999", 0, false},
+      {"170141183460469231731687303715884105727",
+       std::numeric_limits<absl::int128>::max(), true},
+      {"340282366920938463463374607431768211455",
+       std::numeric_limits<absl::uint128>::max(), true},
+      {"340282366920938463463374607431768211456",
+       std::numeric_limits<absl::uint128>::max(), false},
+      {"999999999999999999999999999999999999999",
+       std::numeric_limits<absl::uint128>::max(), false},
+  };
+
+  for (const auto& i : cases) {
+    absl::uint128 output = 0;
+    EXPECT_EQ(i.success, StringToUint128(i.input, &output)) << i.input;
+    EXPECT_EQ(i.output, output);
+  }
+
+  // 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[] =
+      "6\0"
+      "6";
+  std::string input_string(input, std::size(input) - 1);
+  absl::uint128 output;
+  EXPECT_FALSE(StringToUint128(input_string, &output));
+  EXPECT_EQ(6U, output);
+}
+
 TEST(AbseilStringNumberConversionsTest, HexStringToUInt128) {
   // Test cases adapted from `StringNumberConversionsTest.HexStringToUint64`.
   static const struct {
@@ -93,7 +169,7 @@
   const char input[] =
       "0xc0ffee\0"
       "9";
-  std::string input_string(input, gurl_base::size(input) - 1);
+  std::string input_string(input, std::size(input) - 1);
   absl::uint128 output;
   EXPECT_FALSE(HexStringToUInt128(input_string, &output));
   EXPECT_EQ(0xc0ffeeU, output);
diff --git a/base/strings/char_traits.h b/base/strings/char_traits.h
deleted file mode 100644
index fe01c53..0000000
--- a/base/strings/char_traits.h
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright 2018 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_CHAR_TRAITS_H_
-#define BASE_STRINGS_CHAR_TRAITS_H_
-
-#include <stddef.h>
-
-#include <string>
-
-#include "base/compiler_specific.h"
-
-namespace gurl_base {
-
-// constexpr version of http://en.cppreference.com/w/cpp/string/char_traits.
-// This currently just implements the bits needed to support a (mostly)
-// constexpr StringPiece.
-//
-// TODO(dcheng): Once we switch to C++17, most methods will become constexpr and
-// we can switch over to using the one in the standard library.
-template <typename T>
-struct CharTraits {
-  // Performs a lexographical comparison of the first N characters of |s1| and
-  // |s2|. Returns 0 if equal, -1 if |s1| is less than |s2|, and 1 if |s1| is
-  // greater than |s2|.
-  static constexpr int compare(const T* s1, const T* s2, size_t n) noexcept;
-
-  // Returns the length of |s|, assuming null termination (and not including the
-  // terminating null).
-  static constexpr size_t length(const T* s) noexcept;
-
-  // Searches for character |c| within the first |n| characters of the sequence
-  // pointed to by |s|.
-  static constexpr const T* find(const T* s, size_t n, T c);
-};
-
-template <typename T>
-constexpr int CharTraits<T>::compare(const T* s1,
-                                     const T* s2,
-                                     size_t n) noexcept {
-  // Comparison with operator < fails, because of signed/unsigned
-  // mismatch, https://crbug.com/941696
-  // std::char_traits<T>::lt is guaranteed to be constexpr in C++14:
-  // https://timsong-cpp.github.io/cppwp/n4140/char.traits.specializations#char
-  for (; n; --n, ++s1, ++s2) {
-    if (std::char_traits<T>::lt(*s1, *s2))
-      return -1;
-    if (std::char_traits<T>::lt(*s2, *s1))
-      return 1;
-  }
-  return 0;
-}
-
-template <typename T>
-constexpr size_t CharTraits<T>::length(const T* s) noexcept {
-  size_t i = 0;
-  for (; *s; ++s)
-    ++i;
-  return i;
-}
-
-template <typename T>
-constexpr const T* CharTraits<T>::find(const T* s, size_t n, T c) {
-  for (; n; --n, ++s) {
-    if (std::char_traits<T>::eq(*s, c))
-      return s;
-  }
-  return nullptr;
-}
-
-// char and wchar_t specialization of CharTraits that can use clang's constexpr
-// instrinsics, where available.
-#if HAS_FEATURE(cxx_constexpr_string_builtins)
-template <>
-struct CharTraits<char> {
-  static constexpr int compare(const char* s1,
-                               const char* s2,
-                               size_t n) noexcept {
-    return __builtin_memcmp(s1, s2, n);
-  }
-
-  static constexpr size_t length(const char* s) noexcept {
-    return __builtin_strlen(s);
-  }
-
-  static constexpr const char* find(const char* s, size_t n, char c) {
-    return __builtin_char_memchr(s, c, n);
-  }
-};
-
-template <>
-struct CharTraits<wchar_t> {
-  static constexpr int compare(const wchar_t* s1,
-                               const wchar_t* s2,
-                               size_t n) noexcept {
-    return __builtin_wmemcmp(s1, s2, n);
-  }
-
-  static constexpr size_t length(const wchar_t* s) noexcept {
-    return __builtin_wcslen(s);
-  }
-
-  static constexpr const wchar_t* find(const wchar_t* s, size_t n, wchar_t c) {
-    return __builtin_wmemchr(s, c, n);
-  }
-};
-#endif
-
-}  // namespace base
-
-#endif  // BASE_STRINGS_CHAR_TRAITS_H_
diff --git a/base/strings/char_traits_unittest.cc b/base/strings/char_traits_unittest.cc
deleted file mode 100644
index d735d4a..0000000
--- a/base/strings/char_traits_unittest.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2018 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/char_traits.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace gurl_base {
-
-TEST(CharTraitsTest, CharCompare) {
-  static_assert(CharTraits<char>::compare("abc", "def", 3) == -1, "");
-  static_assert(CharTraits<char>::compare("def", "def", 3) == 0, "");
-  static_assert(CharTraits<char>::compare("ghi", "def", 3) == 1, "");
-}
-
-TEST(CharTraitsTest, CharLength) {
-  static_assert(CharTraits<char>::length("") == 0, "");
-  static_assert(CharTraits<char>::length("abc") == 3, "");
-}
-
-TEST(CharTraitsTest, Char16TCompare) {
-  static_assert(CharTraits<char16_t>::compare(u"abc", u"def", 3) == -1, "");
-  static_assert(CharTraits<char16_t>::compare(u"def", u"def", 3) == 0, "");
-  static_assert(CharTraits<char16_t>::compare(u"ghi", u"def", 3) == 1, "");
-}
-
-TEST(CharTraitsTest, Char16TLength) {
-  static_assert(CharTraits<char16_t>::length(u"abc") == 3, "");
-}
-
-}  // namespace base
diff --git a/base/strings/escape.cc b/base/strings/escape.cc
index ff6f6d8..8324aae 100644
--- a/base/strings/escape.cc
+++ b/base/strings/escape.cc
@@ -4,15 +4,145 @@
 
 #include "base/strings/escape.h"
 
+#include <ostream>
+
+#include "polyfills/base/check_op.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversion_utils.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/third_party/icu/icu_utf.h"
 
 namespace gurl_base {
 
 namespace {
 
+const char kHexString[] = "0123456789ABCDEF";
+inline char IntToHex(int i) {
+  GURL_DCHECK_GE(i, 0) << i << " not a hex value";
+  GURL_DCHECK_LE(i, 15) << i << " not a hex value";
+  return kHexString[i];
+}
+
+// A fast bit-vector map for ascii characters.
+//
+// Internally stores 256 bits in an array of 8 ints.
+// Does quick bit-flicking to lookup needed characters.
+struct Charmap {
+  bool Contains(unsigned char c) const {
+    return ((map[c >> 5] & (1 << (c & 31))) != 0);
+  }
+
+  uint32_t map[8];
+};
+
+// Given text to escape and a Charmap defining which values to escape,
+// return an escaped string.  If use_plus is true, spaces are converted
+// to +, otherwise, if spaces are in the charmap, they are converted to
+// %20. And if keep_escaped is true, %XX will be kept as it is, otherwise, if
+// '%' is in the charmap, it is converted to %25.
+std::string Escape(StringPiece text,
+                   const Charmap& charmap,
+                   bool use_plus,
+                   bool keep_escaped = false) {
+  std::string escaped;
+  escaped.reserve(text.length() * 3);
+  for (unsigned int i = 0; i < text.length(); ++i) {
+    unsigned char c = static_cast<unsigned char>(text[i]);
+    if (use_plus && ' ' == c) {
+      escaped.push_back('+');
+    } else if (keep_escaped && '%' == c && i + 2 < text.length() &&
+               IsHexDigit(text[i + 1]) && IsHexDigit(text[i + 2])) {
+      escaped.push_back('%');
+    } else if (charmap.Contains(c)) {
+      escaped.push_back('%');
+      escaped.push_back(IntToHex(c >> 4));
+      escaped.push_back(IntToHex(c & 0xf));
+    } else {
+      escaped.push_back(c);
+    }
+  }
+  return escaped;
+}
+
+// Convert a character |c| to a form that will not be mistaken as HTML.
+template <class str>
+void AppendEscapedCharForHTMLImpl(typename str::value_type c, str* output) {
+  static constexpr struct {
+    char key;
+    StringPiece replacement;
+  } kCharsToEscape[] = {
+      {'<', "&lt;"},   {'>', "&gt;"},   {'&', "&amp;"},
+      {'"', "&quot;"}, {'\'', "&#39;"},
+  };
+  for (const auto& char_to_escape : kCharsToEscape) {
+    if (c == char_to_escape.key) {
+      output->append(std::begin(char_to_escape.replacement),
+                     std::end(char_to_escape.replacement));
+      return;
+    }
+  }
+  output->push_back(c);
+}
+
+// Convert |input| string to a form that will not be interpreted as HTML.
+template <typename T, typename CharT = typename T::value_type>
+std::basic_string<CharT> EscapeForHTMLImpl(T input) {
+  std::basic_string<CharT> result;
+  result.reserve(input.size());  // Optimize for no escaping.
+
+  for (auto c : input) {
+    AppendEscapedCharForHTMLImpl(c, &result);
+  }
+
+  return result;
+}
+
+// Everything except alphanumerics and -._~
+// See RFC 3986 for the list of unreserved characters.
+static const Charmap kUnreservedCharmap = {
+    {0xffffffffL, 0xfc009fffL, 0x78000001L, 0xb8000001L, 0xffffffffL,
+     0xffffffffL, 0xffffffffL, 0xffffffffL}};
+
+// Everything except alphanumerics and !'()*-._~
+// See RFC 2396 for the list of reserved characters.
+static const Charmap kQueryCharmap = {{0xffffffffL, 0xfc00987dL, 0x78000001L,
+                                       0xb8000001L, 0xffffffffL, 0xffffffffL,
+                                       0xffffffffL, 0xffffffffL}};
+
+// non-printable, non-7bit, and (including space)  "#%:<>?[\]^`{|}
+static const Charmap kPathCharmap = {{0xffffffffL, 0xd400002dL, 0x78000000L,
+                                      0xb8000001L, 0xffffffffL, 0xffffffffL,
+                                      0xffffffffL, 0xffffffffL}};
+
+#if BUILDFLAG(IS_APPLE)
+// non-printable, non-7bit, and (including space)  "#%<>[\]^`{|}
+static const Charmap kNSURLCharmap = {{0xffffffffL, 0x5000002dL, 0x78000000L,
+                                       0xb8000001L, 0xffffffffL, 0xffffffffL,
+                                       0xffffffffL, 0xffffffffL}};
+#endif  // BUILDFLAG(IS_APPLE)
+
+// non-printable, non-7bit, and (including space) ?>=<;+'&%$#"![\]^`{|}
+static const Charmap kUrlEscape = {{0xffffffffL, 0xf80008fdL, 0x78000001L,
+                                    0xb8000001L, 0xffffffffL, 0xffffffffL,
+                                    0xffffffffL, 0xffffffffL}};
+
+// non-7bit, as well as %.
+static const Charmap kNonASCIICharmapAndPercent = {
+    {0x00000000L, 0x00000020L, 0x00000000L, 0x00000000L, 0xffffffffL,
+     0xffffffffL, 0xffffffffL, 0xffffffffL}};
+
+// non-7bit
+static const Charmap kNonASCIICharmap = {{0x00000000L, 0x00000000L, 0x00000000L,
+                                          0x00000000L, 0xffffffffL, 0xffffffffL,
+                                          0xffffffffL, 0xffffffffL}};
+
+// Everything except alphanumerics, the reserved characters(;/?:@&=+$,) and
+// !'()*-._~#[]
+static const Charmap kExternalHandlerCharmap = {
+    {0xffffffffL, 0x50000025L, 0x50000000L, 0xb8000001L, 0xffffffffL,
+     0xffffffffL, 0xffffffffL, 0xffffffffL}};
+
 // Contains nonzero when the corresponding character is unescapable for normal
 // URLs. These characters are the ones that may change the parsing of a URL, so
 // we don't want to unescape them sometimes. In many case we won't want to
@@ -96,7 +226,7 @@
     // reach max character length number of bytes, or hit an unescaped
     // character. No need to check length of escaped_text, as
     // UnescapeUnsignedByteAtIndex checks lengths.
-    while (num_bytes < size(bytes) &&
+    while (num_bytes < std::size(bytes) &&
            UnescapeUnsignedByteAtIndex(escaped_text, index + num_bytes * 3,
                                        &bytes[num_bytes]) &&
            CBU8_IS_TRAIL(bytes[num_bytes])) {
@@ -331,6 +461,52 @@
 
 }  // namespace
 
+std::string EscapeAllExceptUnreserved(StringPiece text) {
+  return Escape(text, kUnreservedCharmap, false);
+}
+
+std::string EscapeQueryParamValue(StringPiece text, bool use_plus) {
+  return Escape(text, kQueryCharmap, use_plus);
+}
+
+std::string EscapePath(StringPiece path) {
+  return Escape(path, kPathCharmap, false);
+}
+
+#if BUILDFLAG(IS_APPLE)
+std::string EscapeNSURLPrecursor(StringPiece precursor) {
+  return Escape(precursor, kNSURLCharmap, false, true);
+}
+#endif  // BUILDFLAG(IS_APPLE)
+
+std::string EscapeUrlEncodedData(StringPiece path, bool use_plus) {
+  return Escape(path, kUrlEscape, use_plus);
+}
+
+std::string EscapeNonASCIIAndPercent(StringPiece input) {
+  return Escape(input, kNonASCIICharmapAndPercent, false);
+}
+
+std::string EscapeNonASCII(StringPiece input) {
+  return Escape(input, kNonASCIICharmap, false);
+}
+
+std::string EscapeExternalHandlerValue(StringPiece text) {
+  return Escape(text, kExternalHandlerCharmap, false, true);
+}
+
+void AppendEscapedCharForHTML(char c, std::string* output) {
+  AppendEscapedCharForHTMLImpl(c, output);
+}
+
+std::string EscapeForHTML(StringPiece input) {
+  return EscapeForHTMLImpl(input);
+}
+
+std::u16string EscapeForHTML(StringPiece16 input) {
+  return EscapeForHTMLImpl(input);
+}
+
 std::string UnescapeURLComponent(StringPiece escaped_text,
                                  UnescapeRule::Type rules) {
   return UnescapeURLWithAdjustmentsImpl(escaped_text, rules, nullptr);
@@ -441,4 +617,39 @@
   return false;
 }
 
-}  // namespace base
\ No newline at end of file
+std::u16string UnescapeForHTML(StringPiece16 input) {
+  static const struct {
+    const char* ampersand_code;
+    const char replacement;
+  } kEscapeToChars[] = {
+      {"&lt;", '<'},   {"&gt;", '>'},   {"&amp;", '&'},
+      {"&quot;", '"'}, {"&#39;", '\''},
+  };
+  constexpr size_t kEscapeToCharsCount = std::size(kEscapeToChars);
+
+  if (input.find(u"&") == std::string::npos)
+    return std::u16string(input);
+
+  std::u16string ampersand_chars[kEscapeToCharsCount];
+  std::u16string text(input);
+  for (std::u16string::iterator iter = text.begin(); iter != text.end();
+       ++iter) {
+    if (*iter == '&') {
+      // Potential ampersand encode char.
+      size_t index = iter - text.begin();
+      for (size_t i = 0; i < std::size(kEscapeToChars); i++) {
+        if (ampersand_chars[i].empty()) {
+          ampersand_chars[i] = ASCIIToUTF16(kEscapeToChars[i].ampersand_code);
+        }
+        if (text.find(ampersand_chars[i], index) == index) {
+          text.replace(iter, iter + ampersand_chars[i].length(), 1,
+                       kEscapeToChars[i].replacement);
+          break;
+        }
+      }
+    }
+  }
+  return text;
+}
+
+}  // namespace base
diff --git a/base/strings/escape.h b/base/strings/escape.h
index 96ce110..57f2f9a 100644
--- a/base/strings/escape.h
+++ b/base/strings/escape.h
@@ -16,6 +16,58 @@
 
 namespace gurl_base {
 
+// Escaping --------------------------------------------------------------------
+
+// Escapes all characters except unreserved characters. Unreserved characters,
+// as defined in RFC 3986, include alphanumerics and -._~
+BASE_EXPORT std::string EscapeAllExceptUnreserved(StringPiece text);
+
+// Escapes characters in text suitable for use as a query parameter value.
+// We %XX everything except alphanumerics and -_.!~*'()
+// Spaces change to "+" unless you pass usePlus=false.
+// This is basically the same as encodeURIComponent in javascript.
+BASE_EXPORT std::string EscapeQueryParamValue(StringPiece text, bool use_plus);
+
+// Escapes a partial or complete file/pathname.  This includes:
+// non-printable, non-7bit, and (including space)  "#%:<>?[\]^`{|}
+BASE_EXPORT std::string EscapePath(StringPiece path);
+
+#if BUILDFLAG(IS_APPLE)
+// Escapes characters as per expectations of NSURL. This includes:
+// non-printable, non-7bit, and (including space)  "#%<>[\]^`{|}
+BASE_EXPORT std::string EscapeNSURLPrecursor(StringPiece precursor);
+#endif  // BUILDFLAG(IS_APPLE)
+
+// Escapes application/x-www-form-urlencoded content.  This includes:
+// non-printable, non-7bit, and (including space)  ?>=<;+'&%$#"![\]^`{|}
+// Space is escaped as + (if use_plus is true) and other special characters
+// as %XX (hex).
+BASE_EXPORT std::string EscapeUrlEncodedData(StringPiece path, bool use_plus);
+
+// Escapes all non-ASCII input, as well as escaping % to %25.
+BASE_EXPORT std::string EscapeNonASCIIAndPercent(StringPiece input);
+
+// Escapes all non-ASCII input. Note this function leaves % unescaped, which
+// means the unescaping the resulting string will not give back the original
+// input.
+BASE_EXPORT std::string EscapeNonASCII(StringPiece input);
+
+// Escapes characters in text suitable for use as an external protocol handler
+// command.
+// We %XX everything except alphanumerics and -_.!~*'() and the restricted
+// characters (;/?:@&=+$,#[]) and a valid percent escape sequence (%XX).
+BASE_EXPORT std::string EscapeExternalHandlerValue(StringPiece text);
+
+// Appends the given character to the output string, escaping the character if
+// the character would be interpreted as an HTML delimiter.
+BASE_EXPORT void AppendEscapedCharForHTML(char c, std::string* output);
+
+// Escapes chars that might cause this text to be interpreted as HTML tags.
+BASE_EXPORT std::string EscapeForHTML(StringPiece text);
+BASE_EXPORT std::u16string EscapeForHTML(StringPiece16 text);
+
+// Unescaping ------------------------------------------------------------------
+
 class UnescapeRule {
  public:
   // A combination of the following flags that is passed to the unescaping
@@ -115,6 +167,10 @@
 BASE_EXPORT bool ContainsEncodedBytes(StringPiece escaped_text,
                                       const std::set<unsigned char>& bytes);
 
+// Unescapes the following ampersand character codes from |text|:
+// &lt; &gt; &amp; &quot; &#39;
+BASE_EXPORT std::u16string UnescapeForHTML(StringPiece16 text);
+
 }  // namespace base
 
 #endif  // BASE_STRINGS_ESCAPE_H_
diff --git a/base/strings/escape_unittest.cc b/base/strings/escape_unittest.cc
index 923eb5a..182e83f 100644
--- a/base/strings/escape_unittest.cc
+++ b/base/strings/escape_unittest.cc
@@ -8,10 +8,22 @@
 #include "base/strings/escape.h"
 
 #include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace gurl_base {
+namespace {
+
+struct EscapeCase {
+  const char* input;
+  const char* output;
+};
+
+struct EscapeForHTMLCase {
+  const char* input;
+  const char* expected_output;
+};
 
 struct UnescapeURLCase {
   const char* input;
@@ -38,6 +50,155 @@
   size_t output_offset;
 };
 
+TEST(EscapeTest, EscapeTextForFormSubmission) {
+  const EscapeCase escape_cases[] = {
+      {"foo", "foo"}, {"foo bar", "foo+bar"}, {"foo++", "foo%2B%2B"}};
+  for (const auto& escape_case : escape_cases) {
+    EXPECT_EQ(escape_case.output,
+              EscapeQueryParamValue(escape_case.input, true));
+  }
+
+  const EscapeCase escape_cases_no_plus[] = {
+      {"foo", "foo"}, {"foo bar", "foo%20bar"}, {"foo++", "foo%2B%2B"}};
+  for (const auto& escape_case : escape_cases_no_plus) {
+    EXPECT_EQ(escape_case.output,
+              EscapeQueryParamValue(escape_case.input, false));
+  }
+
+  // Test all the values in we're supposed to be escaping.
+  const std::string no_escape(
+      "abcdefghijklmnopqrstuvwxyz"
+      "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+      "0123456789"
+      "!'()*-._~");
+  for (int i = 0; i < 256; ++i) {
+    std::string in;
+    in.push_back(i);
+    std::string out = EscapeQueryParamValue(in, true);
+    if (0 == i) {
+      EXPECT_EQ(out, std::string("%00"));
+    } else if (32 == i) {
+      // Spaces are plus escaped like web forms.
+      EXPECT_EQ(out, std::string("+"));
+    } else if (no_escape.find(in) == std::string::npos) {
+      // Check %hex escaping
+      std::string expected = StringPrintf("%%%02X", i);
+      EXPECT_EQ(expected, out);
+    } else {
+      // No change for things in the no_escape list.
+      EXPECT_EQ(out, in);
+    }
+  }
+}
+
+TEST(EscapeTest, EscapePath) {
+  ASSERT_EQ(
+      // Most of the character space we care about, un-escaped
+      EscapePath("\x02\n\x1d !\"#$%&'()*+,-./0123456789:;"
+                 "<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                 "[\\]^_`abcdefghijklmnopqrstuvwxyz"
+                 "{|}~\x7f\x80\xff"),
+      // Escaped
+      "%02%0A%1D%20!%22%23$%25&'()*+,-./0123456789%3A;"
+      "%3C=%3E%3F@ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+      "%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz"
+      "%7B%7C%7D~%7F%80%FF");
+}
+
+TEST(EscapeTest, EscapeUrlEncodedData) {
+  ASSERT_EQ(
+      // Most of the character space we care about, un-escaped
+      EscapeUrlEncodedData("\x02\n\x1d !\"#$%&'()*+,-./0123456789:;"
+                           "<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                           "[\\]^_`abcdefghijklmnopqrstuvwxyz"
+                           "{|}~\x7f\x80\xff",
+                           true),
+      // Escaped
+      "%02%0A%1D+!%22%23%24%25%26%27()*%2B,-./0123456789:%3B"
+      "%3C%3D%3E%3F%40ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+      "%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz"
+      "%7B%7C%7D~%7F%80%FF");
+}
+
+TEST(EscapeTest, EscapeUrlEncodedDataSpace) {
+  ASSERT_EQ(EscapeUrlEncodedData("a b", true), "a+b");
+  ASSERT_EQ(EscapeUrlEncodedData("a b", false), "a%20b");
+}
+
+TEST(EscapeTest, EscapeForHTML) {
+  const EscapeForHTMLCase tests[] = {
+      {"hello", "hello"},
+      {"<hello>", "&lt;hello&gt;"},
+      {"don\'t mess with me", "don&#39;t mess with me"},
+  };
+  for (const auto& test : tests) {
+    std::string result = EscapeForHTML(std::string(test.input));
+    EXPECT_EQ(std::string(test.expected_output), result);
+  }
+}
+
+TEST(EscapeTest, UnescapeForHTML) {
+  const EscapeForHTMLCase tests[] = {
+      {"", ""},
+      {"&lt;hello&gt;", "<hello>"},
+      {"don&#39;t mess with me", "don\'t mess with me"},
+      {"&lt;&gt;&amp;&quot;&#39;", "<>&\"'"},
+      {"& lt; &amp ; &; '", "& lt; &amp ; &; '"},
+      {"&amp;", "&"},
+      {"&quot;", "\""},
+      {"&#39;", "'"},
+      {"&lt;", "<"},
+      {"&gt;", ">"},
+      {"&amp; &", "& &"},
+  };
+  for (const auto& test : tests) {
+    std::u16string result = UnescapeForHTML(ASCIIToUTF16(test.input));
+    EXPECT_EQ(ASCIIToUTF16(test.expected_output), result);
+  }
+}
+
+TEST(EscapeTest, EscapeExternalHandlerValue) {
+  ASSERT_EQ(
+      // Escaped
+      "%02%0A%1D%20!%22#$%25&'()*+,-./0123456789:;"
+      "%3C=%3E?@ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+      "[%5C]%5E_%60abcdefghijklmnopqrstuvwxyz"
+      "%7B%7C%7D~%7F%80%FF",
+      // Most of the character space we care about, un-escaped
+      EscapeExternalHandlerValue("\x02\n\x1d !\"#$%&'()*+,-./0123456789:;"
+                                 "<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                                 "[\\]^_`abcdefghijklmnopqrstuvwxyz"
+                                 "{|}~\x7f\x80\xff"));
+
+  ASSERT_EQ(
+      "!#$&'()*+,-./0123456789:;=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]_"
+      "abcdefghijklmnopqrstuvwxyz~",
+      EscapeExternalHandlerValue(
+          "!#$&'()*+,-./0123456789:;=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]_"
+          "abcdefghijklmnopqrstuvwxyz~"));
+
+  ASSERT_EQ("%258k", EscapeExternalHandlerValue("%8k"));
+  ASSERT_EQ("a%25", EscapeExternalHandlerValue("a%"));
+  ASSERT_EQ("%25a", EscapeExternalHandlerValue("%a"));
+  ASSERT_EQ("a%258", EscapeExternalHandlerValue("a%8"));
+  ASSERT_EQ("%ab", EscapeExternalHandlerValue("%ab"));
+  ASSERT_EQ("%AB", EscapeExternalHandlerValue("%AB"));
+
+  ASSERT_EQ("http://example.com/path/sub?q=a%7Cb%7Cc&q=1%7C2%7C3#ref%7C",
+            EscapeExternalHandlerValue(
+                "http://example.com/path/sub?q=a|b|c&q=1|2|3#ref|"));
+  ASSERT_EQ("http://example.com/path/sub?q=a%7Cb%7Cc&q=1%7C2%7C3#ref%7C",
+            EscapeExternalHandlerValue(
+                "http://example.com/path/sub?q=a%7Cb%7Cc&q=1%7C2%7C3#ref%7C"));
+  ASSERT_EQ("http://[2001:db8:0:1]:80",
+            EscapeExternalHandlerValue("http://[2001:db8:0:1]:80"));
+}
+
+TEST(EscapeTest, EscapeNonASCII) {
+  EXPECT_EQ("abc\n%2580%80", EscapeNonASCIIAndPercent("abc\n%80\x80"));
+  EXPECT_EQ("abc\n%80%80", EscapeNonASCII("abc\n%80\x80"));
+}
+
 TEST(EscapeTest, DataURLWithAccentedCharacters) {
   const std::string url =
       "text/html;charset=utf-8,%3Chtml%3E%3Cbody%3ETonton,%20ton%20th%C3"
@@ -427,4 +588,5 @@
       ContainsEncodedBytes("caf%C3%A9", {static_cast<uint8_t>('\xe9')}));
 }
 
+}  // namespace
 }  // namespace base
diff --git a/base/strings/string_number_conversions_internal.h b/base/strings/string_number_conversions_internal.h
index 8c45d1b..6de9e2e 100644
--- a/base/strings/string_number_conversions_internal.h
+++ b/base/strings/string_number_conversions_internal.h
@@ -12,7 +12,7 @@
 
 #include <limits>
 
-#include "polyfills/base/check_op.h"
+#include "polyfills/base/check.h"
 #include "polyfills/base/logging.h"
 #include "base/numerics/safe_math.h"
 #include "base/strings/string_util.h"
diff --git a/base/strings/string_number_conversions_unittest.cc b/base/strings/string_number_conversions_unittest.cc
index b5a23a1..34f811e 100644
--- a/base/strings/string_number_conversions_unittest.cc
+++ b/base/strings/string_number_conversions_unittest.cc
@@ -14,7 +14,6 @@
 #include <limits>
 
 #include "base/bit_cast.h"
-#include "base/cxx17_backports.h"
 #include "base/format_macros.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
@@ -154,8 +153,10 @@
   // 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[] = "6\06";
-  std::string input_string(input, gurl_base::size(input) - 1);
+  const char input[] =
+      "6\0"
+      "6";
+  std::string input_string(input, std::size(input) - 1);
   int output;
   EXPECT_FALSE(StringToInt(input_string, &output));
   EXPECT_EQ(6, output);
@@ -220,8 +221,10 @@
   // 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[] = "6\06";
-  std::string input_string(input, gurl_base::size(input) - 1);
+  const char input[] =
+      "6\0"
+      "6";
+  std::string input_string(input, std::size(input) - 1);
   unsigned output;
   EXPECT_FALSE(StringToUint(input_string, &output));
   EXPECT_EQ(6U, output);
@@ -290,8 +293,10 @@
   // 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[] = "6\06";
-  std::string input_string(input, gurl_base::size(input) - 1);
+  const char input[] =
+      "6\0"
+      "6";
+  std::string input_string(input, std::size(input) - 1);
   int64_t output;
   EXPECT_FALSE(StringToInt64(input_string, &output));
   EXPECT_EQ(6, output);
@@ -357,8 +362,10 @@
   // 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[] = "6\06";
-  std::string input_string(input, gurl_base::size(input) - 1);
+  const char input[] =
+      "6\0"
+      "6";
+  std::string input_string(input, std::size(input) - 1);
   uint64_t output;
   EXPECT_FALSE(StringToUint64(input_string, &output));
   EXPECT_EQ(6U, output);
@@ -426,8 +433,10 @@
   // 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[] = "6\06";
-  std::string input_string(input, gurl_base::size(input) - 1);
+  const char input[] =
+      "6\0"
+      "6";
+  std::string input_string(input, std::size(input) - 1);
   size_t output;
   EXPECT_FALSE(StringToSizeT(input_string, &output));
   EXPECT_EQ(6U, output);
@@ -486,7 +495,7 @@
   const char input[] =
       "0xc0ffee\0"
       "9";
-  std::string input_string(input, gurl_base::size(input) - 1);
+  std::string input_string(input, std::size(input) - 1);
   int output;
   EXPECT_FALSE(HexStringToInt(input_string, &output));
   EXPECT_EQ(0xc0ffee, output);
@@ -553,7 +562,7 @@
   const char input[] =
       "0xc0ffee\0"
       "9";
-  std::string input_string(input, gurl_base::size(input) - 1);
+  std::string input_string(input, std::size(input) - 1);
   uint32_t output;
   EXPECT_FALSE(HexStringToUInt(input_string, &output));
   EXPECT_EQ(0xc0ffeeU, output);
@@ -614,7 +623,7 @@
   const char input[] =
       "0xc0ffee\0"
       "9";
-  std::string input_string(input, gurl_base::size(input) - 1);
+  std::string input_string(input, std::size(input) - 1);
   int64_t output;
   EXPECT_FALSE(HexStringToInt64(input_string, &output));
   EXPECT_EQ(0xc0ffee, output);
@@ -679,7 +688,7 @@
   const char input[] =
       "0xc0ffee\0"
       "9";
-  std::string input_string(input, gurl_base::size(input) - 1);
+  std::string input_string(input, std::size(input) - 1);
   uint64_t output;
   EXPECT_FALSE(HexStringToUInt64(input_string, &output));
   EXPECT_EQ(0xc0ffeeU, output);
@@ -712,7 +721,7 @@
        11, true},
   };
 
-  for (size_t test_i = 0; test_i < gurl_base::size(cases); ++test_i) {
+  for (size_t test_i = 0; test_i < std::size(cases); ++test_i) {
     const auto& test = cases[test_i];
 
     std::string expected_output(test.output, test.output_len);
@@ -855,7 +864,7 @@
        -1.0000000000000001e-259, true},
   };
 
-  for (size_t i = 0; i < gurl_base::size(cases); ++i) {
+  for (size_t i = 0; i < std::size(cases); ++i) {
     SCOPED_TRACE(
         StringPrintf("case %" PRIuS " \"%s\"", i, cases[i].input.c_str()));
     double output;
@@ -872,7 +881,7 @@
   const char input[] =
       "3.14\0"
       "159";
-  std::string input_string(input, gurl_base::size(input) - 1);
+  std::string input_string(input, std::size(input) - 1);
   double output;
   EXPECT_FALSE(StringToDouble(input_string, &output));
   EXPECT_DOUBLE_EQ(3.14, output);
@@ -901,12 +910,12 @@
   // The following two values were seen in crashes in the wild.
   const char input_bytes[8] = {0, 0, 0, 0, '\xee', '\x6d', '\x73', '\x42'};
   double input = 0;
-  memcpy(&input, input_bytes, gurl_base::size(input_bytes));
+  memcpy(&input, input_bytes, std::size(input_bytes));
   EXPECT_EQ("1.335179083776e+12", NumberToString(input));
   const char input_bytes2[8] = {0,      0,      0,      '\xa0',
                                 '\xda', '\x6c', '\x73', '\x42'};
   input = 0;
-  memcpy(&input, input_bytes2, gurl_base::size(input_bytes2));
+  memcpy(&input, input_bytes2, std::size(input_bytes2));
   EXPECT_EQ("1.33489033216e+12", NumberToString(input));
 }
 
diff --git a/base/strings/string_piece.h b/base/strings/string_piece.h
index 8d7f2c5..21ee624 100644
--- a/base/strings/string_piece.h
+++ b/base/strings/string_piece.h
@@ -30,9 +30,9 @@
 #include <type_traits>
 
 #include "polyfills/base/base_export.h"
+#include "polyfills/base/check.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"
 
@@ -118,10 +118,8 @@
       default;
   constexpr BasicStringPiece(const CharT* s, size_type count)
       : ptr_(s), length_(count) {}
-  // Note: This doesn't just use traits_type::length(), since that
-  // isn't constexpr until C++17.
   constexpr BasicStringPiece(const CharT* s)
-      : ptr_(s), length_(s ? CharTraits<CharT>::length(s) : 0) {
+      : ptr_(s), length_(s ? traits_type::length(s) : 0) {
     // Intentional STL deviation: Null-check instead of UB.
     GURL_CHECK(s);
   }
@@ -229,7 +227,7 @@
 
   constexpr int compare(BasicStringPiece v) const noexcept {
     const size_type rlen = std::min(size(), v.size());
-    const int result = CharTraits<CharT>::compare(data(), v.data(), rlen);
+    const int result = traits_type::compare(data(), v.data(), rlen);
     if (result != 0)
       return result;
     if (size() == v.size())
@@ -282,7 +280,7 @@
       return npos;
 
     const const_pointer result =
-        gurl_base::CharTraits<CharT>::find(data() + pos, size() - pos, ch);
+        traits_type::find(data() + pos, size() - pos, ch);
     return result ? static_cast<size_type>(result - data()) : npos;
   }
   constexpr size_type find(const CharT* s,
diff --git a/base/strings/string_tokenizer.h b/base/strings/string_tokenizer.h
index 14db1e1..e85bf45 100644
--- a/base/strings/string_tokenizer.h
+++ b/base/strings/string_tokenizer.h
@@ -8,6 +8,7 @@
 #include <algorithm>
 #include <string>
 
+#include "polyfills/base/check.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
 
diff --git a/base/strings/string_util.cc b/base/strings/string_util.cc
index 2adfa94..937c603 100644
--- a/base/strings/string_util.cc
+++ b/base/strings/string_util.cc
@@ -22,7 +22,6 @@
 #include <vector>
 
 #include "polyfills/base/check_op.h"
-#include "base/cxx17_backports.h"
 #include "base/no_destructor.h"
 #include "base/strings/string_util_internal.h"
 #include "base/strings/utf_string_conversion_utils.h"
@@ -336,17 +335,17 @@
   size_t dimension = 0;
   const int kKilo = 1024;
   while (unit_amount >= kKilo &&
-         dimension < gurl_base::size(kByteStringsUnlocalized) - 1) {
+         dimension < std::size(kByteStringsUnlocalized) - 1) {
     unit_amount /= kKilo;
     dimension++;
   }
 
   char buf[64];
   if (bytes != 0 && dimension > 0 && unit_amount < 100) {
-    gurl_base::snprintf(buf, gurl_base::size(buf), "%.1lf%s", unit_amount,
+    gurl_base::snprintf(buf, std::size(buf), "%.1lf%s", unit_amount,
                    kByteStringsUnlocalized[dimension]);
   } else {
-    gurl_base::snprintf(buf, gurl_base::size(buf), "%.0lf%s", unit_amount,
+    gurl_base::snprintf(buf, std::size(buf), "%.0lf%s", unit_amount,
                    kByteStringsUnlocalized[dimension]);
   }
 
diff --git a/base/strings/string_util.h b/base/strings/string_util.h
index 5d570e2..cd90a94 100644
--- a/base/strings/string_util.h
+++ b/base/strings/string_util.h
@@ -18,6 +18,7 @@
 #include <vector>
 
 #include "polyfills/base/base_export.h"
+#include "polyfills/base/check_op.h"
 #include "base/compiler_specific.h"
 #include "base/containers/span.h"
 #include "base/cxx20_to_address.h"
diff --git a/base/strings/string_util_internal.h b/base/strings/string_util_internal.h
index 07f4930..2497c8d 100644
--- a/base/strings/string_util_internal.h
+++ b/base/strings/string_util_internal.h
@@ -7,6 +7,8 @@
 
 #include <algorithm>
 
+#include "polyfills/base/check.h"
+#include "polyfills/base/check_op.h"
 #include "polyfills/base/logging.h"
 #include "polyfills/base/notreached.h"
 #include "base/ranges/algorithm.h"
@@ -523,7 +525,7 @@
           typename T,
           typename CharT = typename T::value_type>
 static std::basic_string<CharT> JoinStringT(list_type parts, T sep) {
-  if (gurl_base::empty(parts))
+  if (std::empty(parts))
     return std::basic_string<CharT>();
 
   // Pre-allocate the eventual size of the string. Start with the size of all of
diff --git a/base/strings/string_util_unittest.cc b/base/strings/string_util_unittest.cc
index 231c3c8..b5d9a67 100644
--- a/base/strings/string_util_unittest.cc
+++ b/base/strings/string_util_unittest.cc
@@ -14,7 +14,6 @@
 #include <type_traits>
 
 #include "base/bits.h"
-#include "base/cxx17_backports.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
@@ -218,14 +217,14 @@
 
   {
     const char array[] = "\x00\x00\xc2\x81\xc2\x81";
-    const std::string array_string(array, gurl_base::size(array));
+    const std::string array_string(array, std::size(array));
     EXPECT_TRUE(Truncated(array_string, 4, &output));
     EXPECT_EQ(output.compare(std::string("\x00\x00\xc2\x81", 4)), 0);
   }
 
   {
     const char array[] = "\x00\xc2\x81\xc2\x81";
-    const std::string array_string(array, gurl_base::size(array));
+    const std::string array_string(array, std::size(array));
     EXPECT_TRUE(Truncated(array_string, 4, &output));
     EXPECT_EQ(output.compare(std::string("\x00\xc2\x81", 3)), 0);
   }
@@ -292,7 +291,7 @@
 
   {
     const char array[] = "\x00\x00\xfe\xff";
-    const std::string array_string(array, gurl_base::size(array));
+    const std::string array_string(array, std::size(array));
     EXPECT_TRUE(Truncated(array_string, 4, &output));
     EXPECT_EQ(output.compare(std::string("\x00\x00", 2)), 0);
   }
@@ -306,7 +305,7 @@
   }
   {
     const char array[] = "\xff\x00\x00\xfe";
-    const std::string array_string(array, gurl_base::size(array));
+    const std::string array_string(array, std::size(array));
     EXPECT_TRUE(Truncated(array_string, 4, &output));
     EXPECT_EQ(output.compare(std::string("\xff\x00\x00", 3)), 0);
   }
@@ -536,7 +535,7 @@
   // Also, test that a non-ASCII character will be detected regardless of its
   // position inside the string.
   {
-    const size_t string_length = gurl_base::size(char_ascii) - 1;
+    const size_t string_length = std::size(char_ascii) - 1;
     for (size_t offset = 0; offset < 8; ++offset) {
       for (size_t len = 0, max_len = string_length - offset; len < max_len;
            ++len) {
@@ -551,7 +550,7 @@
   }
 
   {
-    const size_t string_length = gurl_base::size(char16_ascii) - 1;
+    const size_t string_length = std::size(char16_ascii) - 1;
     for (size_t offset = 0; offset < 4; ++offset) {
       for (size_t len = 0, max_len = string_length - offset; len < max_len;
            ++len) {
@@ -605,7 +604,7 @@
     L"0123ABCDwxyz \a\b\t\r\n!+,.~"
   };
 
-  for (size_t i = 0; i < gurl_base::size(char_cases); ++i) {
+  for (size_t i = 0; i < std::size(char_cases); ++i) {
     EXPECT_TRUE(IsStringASCII(char_cases[i]));
     std::u16string utf16 = ASCIIToUTF16(char_cases[i]);
     EXPECT_EQ(WideToUTF16(wchar_cases[i]), utf16);
@@ -624,7 +623,7 @@
 
   // Convert strings with an embedded NUL character.
   const char chars_with_nul[] = "test\0string";
-  const int length_with_nul = gurl_base::size(chars_with_nul) - 1;
+  const int length_with_nul = std::size(chars_with_nul) - 1;
   std::string string_with_nul(chars_with_nul, length_with_nul);
   std::u16string string16_with_nul = ASCIIToUTF16(string_with_nul);
   EXPECT_EQ(static_cast<std::u16string::size_type>(length_with_nul),
@@ -1219,9 +1218,9 @@
   {
     char dst[10];
     wchar_t wdst[10];
-    EXPECT_EQ(7U, strlcpy(dst, "abcdefg", gurl_base::size(dst)));
+    EXPECT_EQ(7U, strlcpy(dst, "abcdefg", std::size(dst)));
     EXPECT_EQ(0, memcmp(dst, "abcdefg", 8));
-    EXPECT_EQ(7U, wcslcpy(wdst, L"abcdefg", gurl_base::size(wdst)));
+    EXPECT_EQ(7U, wcslcpy(wdst, L"abcdefg", std::size(wdst)));
     EXPECT_EQ(0, memcmp(wdst, L"abcdefg", sizeof(wchar_t) * 8));
   }
 
@@ -1242,9 +1241,9 @@
   {
     char dst[8];
     wchar_t wdst[8];
-    EXPECT_EQ(7U, strlcpy(dst, "abcdefg", gurl_base::size(dst)));
+    EXPECT_EQ(7U, strlcpy(dst, "abcdefg", std::size(dst)));
     EXPECT_EQ(0, memcmp(dst, "abcdefg", 8));
-    EXPECT_EQ(7U, wcslcpy(wdst, L"abcdefg", gurl_base::size(wdst)));
+    EXPECT_EQ(7U, wcslcpy(wdst, L"abcdefg", std::size(wdst)));
     EXPECT_EQ(0, memcmp(wdst, L"abcdefg", sizeof(wchar_t) * 8));
   }
 
@@ -1252,9 +1251,9 @@
   {
     char dst[7];
     wchar_t wdst[7];
-    EXPECT_EQ(7U, strlcpy(dst, "abcdefg", gurl_base::size(dst)));
+    EXPECT_EQ(7U, strlcpy(dst, "abcdefg", std::size(dst)));
     EXPECT_EQ(0, memcmp(dst, "abcdef", 7));
-    EXPECT_EQ(7U, wcslcpy(wdst, L"abcdefg", gurl_base::size(wdst)));
+    EXPECT_EQ(7U, wcslcpy(wdst, L"abcdefg", std::size(wdst)));
     EXPECT_EQ(0, memcmp(wdst, L"abcdef", sizeof(wchar_t) * 7));
   }
 
@@ -1262,9 +1261,9 @@
   {
     char dst[3];
     wchar_t wdst[3];
-    EXPECT_EQ(7U, strlcpy(dst, "abcdefg", gurl_base::size(dst)));
+    EXPECT_EQ(7U, strlcpy(dst, "abcdefg", std::size(dst)));
     EXPECT_EQ(0, memcmp(dst, "ab", 3));
-    EXPECT_EQ(7U, wcslcpy(wdst, L"abcdefg", gurl_base::size(wdst)));
+    EXPECT_EQ(7U, wcslcpy(wdst, L"abcdefg", std::size(wdst)));
     EXPECT_EQ(0, memcmp(wdst, L"ab", sizeof(wchar_t) * 3));
   }
 }
@@ -1504,7 +1503,7 @@
     // Using std::string(buffer.c_str()) instead of |buffer| truncates the
     // string at the first \0.
     EXPECT_EQ(
-        std::string(kOriginal, std::min(num_chars, gurl_base::size(kOriginal) - 1)),
+        std::string(kOriginal, std::min(num_chars, std::size(kOriginal) - 1)),
         std::string(buffer.c_str()));
     EXPECT_EQ(num_chars, buffer.size());
   }
diff --git a/base/strings/stringprintf.cc b/base/strings/stringprintf.cc
index aed9b04..e0c5e20 100644
--- a/base/strings/stringprintf.cc
+++ b/base/strings/stringprintf.cc
@@ -9,11 +9,9 @@
 
 #include <vector>
 
-#include "base/cxx17_backports.h"
 #include "polyfills/base/logging.h"
 #include "base/scoped_clear_last_error.h"
 #include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 
 namespace gurl_base {
@@ -64,17 +62,17 @@
   va_copy(ap_copy, ap);
 
   gurl_base::ScopedClearLastError last_error;
-  int result = vsnprintfT(stack_buf, gurl_base::size(stack_buf), format, ap_copy);
+  int result = vsnprintfT(stack_buf, std::size(stack_buf), format, ap_copy);
   va_end(ap_copy);
 
-  if (result >= 0 && result < static_cast<int>(gurl_base::size(stack_buf))) {
+  if (result >= 0 && result < static_cast<int>(std::size(stack_buf))) {
     // It fit.
     dst->append(stack_buf, result);
     return;
   }
 
   // Repeatedly increase buffer size until it fits.
-  int mem_length = gurl_base::size(stack_buf);
+  int mem_length = std::size(stack_buf);
   while (true) {
     if (result < 0) {
 #if BUILDFLAG(IS_WIN)
diff --git a/base/strings/utf_offset_string_conversions_unittest.cc b/base/strings/utf_offset_string_conversions_unittest.cc
index f50fa3f..83bbc35 100644
--- a/base/strings/utf_offset_string_conversions_unittest.cc
+++ b/base/strings/utf_offset_string_conversions_unittest.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/strings/utf_offset_string_conversions.h"
+
 #include <stddef.h>
 
 #include <algorithm>
 
-#include "base/cxx17_backports.h"
 #include "base/strings/string_piece.h"
-#include "base/strings/utf_offset_string_conversions.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace gurl_base {
@@ -66,7 +66,7 @@
       {{'A', 0xd800, 0xdf00, 'z'}, 3, 5},
       {{'A', 0xd800, 0xdf00, 'z'}, 4, 6},
   };
-  for (size_t i = 0; i < gurl_base::size(utf16_to_utf8_cases); ++i) {
+  for (size_t i = 0; i < std::size(utf16_to_utf8_cases); ++i) {
     size_t offset = utf16_to_utf8_cases[i].input_offset;
     std::vector<size_t> offsets;
     offsets.push_back(offset);
@@ -117,8 +117,8 @@
     adjustments.push_back(OffsetAdjuster::Adjustment(3, 3, 1));
     OffsetAdjuster::AdjustOffsets(adjustments, &offsets);
     size_t expected_1[] = {0, 1, 2, 3, kNpos, kNpos, 4, 5, 6, 7};
-    EXPECT_EQ(offsets.size(), gurl_base::size(expected_1));
-    for (size_t i = 0; i < gurl_base::size(expected_1); ++i)
+    EXPECT_EQ(offsets.size(), std::size(expected_1));
+    for (size_t i = 0; i < std::size(expected_1); ++i)
       EXPECT_EQ(expected_1[i], offsets[i]);
   }
 
@@ -137,8 +137,8 @@
       0, kNpos, kNpos, 1, 2, kNpos, kNpos, kNpos, 4, 5, 6, kNpos, kNpos, kNpos,
       kNpos, kNpos, kNpos, 10, 11, 12, 13, kNpos, kNpos, 14
     };
-    EXPECT_EQ(offsets.size(), gurl_base::size(expected_2));
-    for (size_t i = 0; i < gurl_base::size(expected_2); ++i)
+    EXPECT_EQ(offsets.size(), std::size(expected_2));
+    for (size_t i = 0; i < std::size(expected_2); ++i)
       EXPECT_EQ(expected_2[i], offsets[i]);
   }
 
@@ -157,8 +157,8 @@
       0, kNpos, kNpos, 0, 1, kNpos, kNpos, kNpos, 5, 6, 7, 8, kNpos, kNpos, 11,
       12, kNpos, 12
     };
-    EXPECT_EQ(offsets.size(), gurl_base::size(expected_3));
-    for (size_t i = 0; i < gurl_base::size(expected_3); ++i)
+    EXPECT_EQ(offsets.size(), std::size(expected_3));
+    for (size_t i = 0; i < std::size(expected_3); ++i)
       EXPECT_EQ(expected_3[i], offsets[i]);
   }
 }
@@ -175,8 +175,8 @@
     adjustments.push_back(OffsetAdjuster::Adjustment(3, 3, 1));
     OffsetAdjuster::UnadjustOffsets(adjustments, &offsets);
     size_t expected_1[] = {0, 1, 2, 3, 6, 7, 8, 9};
-    EXPECT_EQ(offsets.size(), gurl_base::size(expected_1));
-    for (size_t i = 0; i < gurl_base::size(expected_1); ++i)
+    EXPECT_EQ(offsets.size(), std::size(expected_1));
+    for (size_t i = 0; i < std::size(expected_1); ++i)
       EXPECT_EQ(expected_1[i], offsets[i]);
   }
 
@@ -194,8 +194,8 @@
     size_t expected_2[] = {
       0, 3, 4, kNpos, 8, 9, 10, kNpos, kNpos, kNpos, 17, 18, 19, 20, 23
     };
-    EXPECT_EQ(offsets.size(), gurl_base::size(expected_2));
-    for (size_t i = 0; i < gurl_base::size(expected_2); ++i)
+    EXPECT_EQ(offsets.size(), std::size(expected_2));
+    for (size_t i = 0; i < std::size(expected_2); ++i)
       EXPECT_EQ(expected_2[i], offsets[i]);
   }
 
@@ -215,8 +215,8 @@
       4, kNpos, kNpos, kNpos, 8, 9, 10, 11, kNpos, kNpos, 14,
       15  // this could just as easily be 17
     };
-    EXPECT_EQ(offsets.size(), gurl_base::size(expected_3));
-    for (size_t i = 0; i < gurl_base::size(expected_3); ++i)
+    EXPECT_EQ(offsets.size(), std::size(expected_3));
+    for (size_t i = 0; i < std::size(expected_3); ++i)
       EXPECT_EQ(expected_3[i], offsets[i]);
   }
 }
diff --git a/base/strings/utf_string_conversions_unittest.cc b/base/strings/utf_string_conversions_unittest.cc
index 3b26fa8..f738da4 100644
--- a/base/strings/utf_string_conversions_unittest.cc
+++ b/base/strings/utf_string_conversions_unittest.cc
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/strings/utf_string_conversions.h"
+
 #include <stddef.h>
 
-#include "base/cxx17_backports.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -189,14 +189,14 @@
     '\0'
   };
   std::u16string multistring16;
-  memcpy(WriteInto(&multistring16, gurl_base::size(multi16)), multi16,
+  memcpy(WriteInto(&multistring16, std::size(multi16)), multi16,
          sizeof(multi16));
-  EXPECT_EQ(gurl_base::size(multi16) - 1, multistring16.length());
+  EXPECT_EQ(std::size(multi16) - 1, multistring16.length());
   std::string expected;
-  memcpy(WriteInto(&expected, gurl_base::size(multi)), multi, sizeof(multi));
-  EXPECT_EQ(gurl_base::size(multi) - 1, expected.length());
+  memcpy(WriteInto(&expected, std::size(multi)), multi, sizeof(multi));
+  EXPECT_EQ(std::size(multi) - 1, expected.length());
   const std::string& converted = UTF16ToUTF8(multistring16);
-  EXPECT_EQ(gurl_base::size(multi) - 1, converted.length());
+  EXPECT_EQ(std::size(multi) - 1, converted.length());
   EXPECT_EQ(expected, converted);
 }
 
diff --git a/base/template_util.h b/base/template_util.h
index 3d954fd..c00791b 100644
--- a/base/template_util.h
+++ b/base/template_util.h
@@ -13,32 +13,6 @@
 
 #include "base/compiler_specific.h"
 
-#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ <= 7
-#include <vector>
-#endif
-
-// Some versions of libstdc++ have partial support for type_traits, but misses
-// a smaller subset while removing some of the older non-standard stuff. Assume
-// that all versions below 5.0 fall in this category, along with one 5.0
-// experimental release. Test for this by consulting compiler major version,
-// the only reliable option available, so theoretically this could fail should
-// you attempt to mix an earlier version of libstdc++ with >= GCC5. But
-// that's unlikely to work out, especially as GCC5 changed ABI.
-#define CR_GLIBCXX_5_0_0 20150123
-#if (defined(__GNUC__) && __GNUC__ < 5) || \
-    (defined(__GLIBCXX__) && __GLIBCXX__ == CR_GLIBCXX_5_0_0)
-#define CR_USE_FALLBACKS_FOR_OLD_EXPERIMENTAL_GLIBCXX
-#endif
-
-// This hacks around using gcc with libc++ which has some incompatibilies.
-// - is_trivially_* doesn't work: https://llvm.org/bugs/show_bug.cgi?id=27538
-// TODO(danakj): Remove this when android builders are all using a newer version
-// of gcc, or the android ndk is updated to a newer libc++ that works with older
-// gcc versions.
-#if !defined(__clang__) && defined(_LIBCPP_VERSION)
-#define CR_USE_FALLBACKS_FOR_GCC_WITH_LIBCXX
-#endif
-
 namespace gurl_base {
 
 template <class T> struct is_non_const_reference : std::false_type {};
@@ -47,25 +21,6 @@
 
 namespace internal {
 
-// Implementation detail of gurl_base::void_t below.
-template <typename...>
-struct make_void {
-  using type = void;
-};
-
-}  // namespace internal
-
-// gurl_base::void_t is an implementation of std::void_t from C++17.
-//
-// We use |gurl_base::internal::make_void| as a helper struct to avoid a C++14
-// defect:
-//   http://en.cppreference.com/w/cpp/types/void_t
-//   http://open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#1558
-template <typename... Ts>
-using void_t = typename ::gurl_base::internal::make_void<Ts...>::type;
-
-namespace internal {
-
 // Uses expression SFINAE to detect whether using operator<< would work.
 template <typename T, typename = void>
 struct SupportsOstreamOperator : std::false_type {};
@@ -88,8 +43,9 @@
 struct is_iterator : std::false_type {};
 
 template <typename T>
-struct is_iterator<T,
-                   void_t<typename std::iterator_traits<T>::iterator_category>>
+struct is_iterator<
+    T,
+    std::void_t<typename std::iterator_traits<T>::iterator_category>>
     : std::true_type {};
 
 // Helper to express preferences in an overload set. If more than one overload
@@ -103,67 +59,6 @@
 
 }  // namespace internal
 
-// is_trivially_copyable is especially hard to get right.
-// - Older versions of libstdc++ will fail to have it like they do for other
-//   type traits. This has become a subset of the second point, but used to be
-//   handled independently.
-// - An experimental release of gcc includes most of type_traits but misses
-//   is_trivially_copyable, so we still have to avoid using libstdc++ in this
-//   case, which is covered by CR_USE_FALLBACKS_FOR_OLD_EXPERIMENTAL_GLIBCXX.
-// - When compiling libc++ from before r239653, with a gcc compiler, the
-//   std::is_trivially_copyable can fail. So we need to work around that by not
-//   using the one in libc++ in this case. This is covered by the
-//   CR_USE_FALLBACKS_FOR_GCC_WITH_LIBCXX define, and is discussed in
-//   https://llvm.org/bugs/show_bug.cgi?id=27538#c1 where they point out that
-//   in libc++'s commit r239653 this is fixed by libc++ checking for gcc 5.1.
-// - In both of the above cases we are using the gcc compiler. When defining
-//   this ourselves on compiler intrinsics, the __is_trivially_copyable()
-//   intrinsic is not available on gcc before version 5.1 (see the discussion in
-//   https://llvm.org/bugs/show_bug.cgi?id=27538#c1 again), so we must check for
-//   that version.
-// - When __is_trivially_copyable() is not available because we are on gcc older
-//   than 5.1, we need to fall back to something, so we use __has_trivial_copy()
-//   instead based on what was done one-off in bit_cast() previously.
-
-// TODO(crbug.com/554293): Remove this when all platforms have this in the std
-// namespace and it works with gcc as needed.
-#if defined(CR_USE_FALLBACKS_FOR_OLD_EXPERIMENTAL_GLIBCXX) || \
-    defined(CR_USE_FALLBACKS_FOR_GCC_WITH_LIBCXX)
-template <typename T>
-struct is_trivially_copyable {
-// TODO(danakj): Remove this when android builders are all using a newer version
-// of gcc, or the android ndk is updated to a newer libc++ that does this for
-// us.
-#if _GNUC_VER >= 501
-  static constexpr bool value = __is_trivially_copyable(T);
-#else
-  static constexpr bool value =
-      __has_trivial_copy(T) && __has_trivial_destructor(T);
-#endif
-};
-#else
-template <class T>
-using is_trivially_copyable = std::is_trivially_copyable<T>;
-#endif
-
-#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ <= 7
-// Workaround for g++7 and earlier family.
-// Due to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80654, without this
-// absl::optional<std::vector<T>> where T is non-copyable causes a compile
-// error.  As we know it is not trivially copy constructible, explicitly declare
-// so.
-template <typename T>
-struct is_trivially_copy_constructible
-    : std::is_trivially_copy_constructible<T> {};
-
-template <typename... T>
-struct is_trivially_copy_constructible<std::vector<T...>> : std::false_type {};
-#else
-// Otherwise use std::is_trivially_copy_constructible as is.
-template <typename T>
-using is_trivially_copy_constructible = std::is_trivially_copy_constructible<T>;
-#endif
-
 // gurl_base::in_place_t is an implementation of std::in_place_t from
 // C++17. A tag type used to request in-place construction in template vararg
 // constructors.
@@ -193,102 +88,6 @@
   static constexpr bool value = true;
 };
 
-// C++14 implementation of C++17's std::bool_constant.
-//
-// Reference: https://en.cppreference.com/w/cpp/types/integral_constant
-// Specification: https://wg21.link/meta.type.synop
-template <bool B>
-using bool_constant = std::integral_constant<bool, B>;
-
-// C++14 implementation of C++17's std::conjunction.
-//
-// Reference: https://en.cppreference.com/w/cpp/types/conjunction
-// Specification: https://wg21.link/meta.logical#1.itemdecl:1
-template <typename...>
-struct conjunction : std::true_type {};
-
-template <typename B1>
-struct conjunction<B1> : B1 {};
-
-template <typename B1, typename... Bn>
-struct conjunction<B1, Bn...>
-    : std::conditional_t<static_cast<bool>(B1::value), conjunction<Bn...>, B1> {
-};
-
-// C++14 implementation of C++17's std::disjunction.
-//
-// Reference: https://en.cppreference.com/w/cpp/types/disjunction
-// Specification: https://wg21.link/meta.logical#itemdecl:2
-template <typename...>
-struct disjunction : std::false_type {};
-
-template <typename B1>
-struct disjunction<B1> : B1 {};
-
-template <typename B1, typename... Bn>
-struct disjunction<B1, Bn...>
-    : std::conditional_t<static_cast<bool>(B1::value), B1, disjunction<Bn...>> {
-};
-
-// C++14 implementation of C++17's std::negation.
-//
-// Reference: https://en.cppreference.com/w/cpp/types/negation
-// Specification: https://wg21.link/meta.logical#itemdecl:3
-template <typename B>
-struct negation : bool_constant<!static_cast<bool>(B::value)> {};
-
-// Implementation of C++17's invoke_result.
-//
-// This implementation adds references to `Functor` and `Args` to work around
-// some quirks of std::result_of. See the #Notes section of [1] for details.
-//
-// References:
-// [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::invoke_result<Functor, Args...>;
-
-// Implementation of C++17's std::invoke_result_t.
-//
-// Reference: https://wg21.link/meta.type.synop#lib:invoke_result_t
-template <typename Functor, typename... Args>
-using invoke_result_t = typename invoke_result<Functor, Args...>::type;
-
-namespace internal {
-
-// Base case, `InvokeResult` does not have a nested type member. This means `F`
-// could not be invoked with `Args...` and thus is not invocable.
-template <typename InvokeResult, typename R, typename = void>
-struct IsInvocableImpl : std::false_type {};
-
-// Happy case, `InvokeResult` does have a nested type member. Now check whether
-// `InvokeResult::type` is convertible to `R`. Short circuit in case
-// `std::is_void<R>`.
-template <typename InvokeResult, typename R>
-struct IsInvocableImpl<InvokeResult, R, void_t<typename InvokeResult::type>>
-    : disjunction<std::is_void<R>,
-                  std::is_convertible<typename InvokeResult::type, R>> {};
-
-}  // namespace internal
-
-// Implementation of C++17's std::is_invocable_r.
-//
-// Returns whether `F` can be invoked with `Args...` and the result is
-// convertible to `R`.
-//
-// Reference: https://wg21.link/meta.rel#lib:is_invocable_r
-template <typename R, typename F, typename... Args>
-struct is_invocable_r
-    : internal::IsInvocableImpl<invoke_result<F, Args...>, R> {};
-
-// Implementation of C++17's std::is_invocable.
-//
-// Returns whether `F` can be invoked with `Args...`.
-//
-// Reference: https://wg21.link/meta.rel#lib:is_invocable
-template <typename F, typename... Args>
-struct is_invocable : is_invocable_r<void, F, Args...> {};
-
 namespace internal {
 
 // The indirection with std::is_enum<T> is required, because instantiating
@@ -298,7 +97,7 @@
 
 template <typename T>
 struct IsScopedEnumImpl<T, /*std::is_enum<T>::value=*/true>
-    : negation<std::is_convertible<T, std::underlying_type_t<T>>> {};
+    : std::negation<std::is_convertible<T, std::underlying_type_t<T>>> {};
 
 }  // namespace internal
 
@@ -363,7 +162,8 @@
 //
 // Reference: https://wg21.link/iterator.synopsis#:~:text=indirect_result_t
 template <typename Func, typename... Iters>
-using indirect_result_t = invoke_result_t<Func, iter_reference_t<Iters>...>;
+using indirect_result_t =
+    std::invoke_result_t<Func, iter_reference_t<Iters>...>;
 
 // Simplified implementation of C++20's std::projected. As opposed to
 // std::projected, this implementation does not explicitly restrict the type of
@@ -383,7 +183,4 @@
 
 }  // namespace base
 
-#undef CR_USE_FALLBACKS_FOR_GCC_WITH_LIBCXX
-#undef CR_USE_FALLBACKS_FOR_OLD_EXPERIMENTAL_GLIBCXX
-
 #endif  // BASE_TEMPLATE_UTIL_H_
diff --git a/copy.bara.sky b/copy.bara.sky
index 44173d6..9741b8b 100644
--- a/copy.bara.sky
+++ b/copy.bara.sky
@@ -103,6 +103,8 @@
 
     core.replace("#include \"base/win/windows_types.h\"", "#include <windows.h>"),
     core.replace("#include \"base/strings/string_number_conversions_win.h\"", ""),
+    core.replace("#include \"base/allocator/partition_allocator/partition_alloc_config.h\"", ""),
+    core.replace("base/trace_event/base_tracing_forward.h", "polyfills/third_party/perfetto/include/perfetto/tracing/traced_value.h"),
 
     # Use system ICU.
     core.replace(
diff --git a/polyfills/third_party/perfetto/include/perfetto/tracing/traced_value.h b/polyfills/third_party/perfetto/include/perfetto/tracing/traced_value.h
index b2f0286..6d059f7 100644
--- a/polyfills/third_party/perfetto/include/perfetto/tracing/traced_value.h
+++ b/polyfills/third_party/perfetto/include/perfetto/tracing/traced_value.h
@@ -12,6 +12,15 @@
   void WriteString(const std::string&) && {}
 };
 
+template <typename T>
+void WriteIntoTracedValue(TracedValue context, T&& value) {}
+
+template <typename T, typename ResultType = void, class = void>
+struct check_traced_value_support {
+  static constexpr bool value = true;
+  using type = ResultType;
+};
+
 }  // namespace perfetto
 
 #endif  // POLYFILLS_THIRD_PARTY_PERFETTO_INCLUDE_PERFETTO_TRACING_TRACED_VALUE_H_
diff --git a/url/gurl.cc b/url/gurl.cc
index 3dd0228..5c6b76c 100644
--- a/url/gurl.cc
+++ b/url/gurl.cc
@@ -110,17 +110,17 @@
       // removed from a "foo:hello #ref" URL (see http://crbug.com/291747).
       GURL test_url(spec_, RETAIN_TRAILING_PATH_WHITEPACE);
 
-      GURL_DCHECK(test_url.is_valid_ == is_valid_);
-      GURL_DCHECK(test_url.spec_ == spec_);
+      GURL_DCHECK_EQ(test_url.is_valid_, is_valid_);
+      GURL_DCHECK_EQ(test_url.spec_, spec_);
 
-      GURL_DCHECK(test_url.parsed_.scheme == parsed_.scheme);
-      GURL_DCHECK(test_url.parsed_.username == parsed_.username);
-      GURL_DCHECK(test_url.parsed_.password == parsed_.password);
-      GURL_DCHECK(test_url.parsed_.host == parsed_.host);
-      GURL_DCHECK(test_url.parsed_.port == parsed_.port);
-      GURL_DCHECK(test_url.parsed_.path == parsed_.path);
-      GURL_DCHECK(test_url.parsed_.query == parsed_.query);
-      GURL_DCHECK(test_url.parsed_.ref == parsed_.ref);
+      GURL_DCHECK_EQ(test_url.parsed_.scheme, parsed_.scheme);
+      GURL_DCHECK_EQ(test_url.parsed_.username, parsed_.username);
+      GURL_DCHECK_EQ(test_url.parsed_.password, parsed_.password);
+      GURL_DCHECK_EQ(test_url.parsed_.host, parsed_.host);
+      GURL_DCHECK_EQ(test_url.parsed_.port, parsed_.port);
+      GURL_DCHECK_EQ(test_url.parsed_.path, parsed_.path);
+      GURL_DCHECK_EQ(test_url.parsed_.query, parsed_.query);
+      GURL_DCHECK_EQ(test_url.parsed_.ref, parsed_.ref);
     }
   }
 #endif
@@ -223,8 +223,7 @@
 }
 
 // Note: code duplicated below (it's inconvenient to use a template here).
-GURL GURL::ReplaceComponents(
-    const url::Replacements<char>& replacements) const {
+GURL GURL::ReplaceComponents(const Replacements& replacements) const {
   GURL result;
 
   // Not allowed for invalid URLs.
@@ -243,8 +242,7 @@
 }
 
 // Note: code duplicated above (it's inconvenient to use a template here).
-GURL GURL::ReplaceComponents(
-    const url::Replacements<char16_t>& replacements) const {
+GURL GURL::ReplaceComponents(const ReplacementsW& replacements) const {
   GURL result;
 
   // Not allowed for invalid URLs.
@@ -281,7 +279,7 @@
   if (SchemeIsFileSystem())
     return inner_url_->DeprecatedGetOriginAsURL();
 
-  url::Replacements<char> replacements;
+  Replacements replacements;
   replacements.ClearUsername();
   replacements.ClearPassword();
   replacements.ClearPath();
@@ -298,7 +296,7 @@
   if (!has_ref() && !has_username() && !has_password())
     return GURL(*this);
 
-  url::Replacements<char> replacements;
+  Replacements replacements;
   replacements.ClearRef();
   replacements.ClearUsername();
   replacements.ClearPassword();
diff --git a/url/gurl.h b/url/gurl.h
index ee009de..63729ee 100644
--- a/url/gurl.h
+++ b/url/gurl.h
@@ -164,10 +164,10 @@
   // It is an error to replace components of an invalid URL. The result will
   // be the empty URL.
   //
-  // Note that we use the more general url::Replacements type to give
-  // callers extra flexibility rather than our override.
-  GURL ReplaceComponents(const url::Replacements<char>& replacements) const;
-  GURL ReplaceComponents(const url::Replacements<char16_t>& replacements) const;
+  // Note that this intentionally disallows direct use of url::Replacements,
+  // which is harder to use correctly.
+  GURL ReplaceComponents(const Replacements& replacements) const;
+  GURL ReplaceComponents(const ReplacementsW& replacements) const;
 
   // A helper function that is equivalent to replacing the path with a slash
   // and clearing out everything after that. We sometimes need to know just the
diff --git a/url/gurl_unittest.cc b/url/gurl_unittest.cc
index e793542..6dd1fc0 100644
--- a/url/gurl_unittest.cc
+++ b/url/gurl_unittest.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "url/gurl.h"
+
 #include <stddef.h>
 
-#include "base/cxx17_backports.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
 #include "url/gurl_abstract_tests.h"
 #include "url/origin.h"
 #include "url/url_canon.h"
@@ -222,7 +222,7 @@
       "http:/path",
       "http:path",
   };
-  for (size_t i = 0; i < gurl_base::size(valid_cases); i++) {
+  for (size_t i = 0; i < std::size(valid_cases); i++) {
     EXPECT_TRUE(GURL(valid_cases[i]).is_valid())
         << "Case: " << valid_cases[i];
   }
@@ -237,7 +237,7 @@
       "://google.com",
       "path",
   };
-  for (size_t i = 0; i < gurl_base::size(invalid_cases); i++) {
+  for (size_t i = 0; i < std::size(invalid_cases); i++) {
     EXPECT_FALSE(GURL(invalid_cases[i]).is_valid())
         << "Case: " << invalid_cases[i];
   }
@@ -346,7 +346,7 @@
       {"file:///some/dir/", "://host", true, "file:///some/dir/://host"},
   };
 
-  for (size_t i = 0; i < gurl_base::size(resolve_cases); i++) {
+  for (size_t i = 0; i < std::size(resolve_cases); i++) {
     // 8-bit code path.
     GURL input(resolve_cases[i].base);
     GURL output = input.Resolve(resolve_cases[i].relative);
@@ -383,7 +383,7 @@
       {"blob:null/guid-goes-here", ""},
       {"blob:http://origin/guid-goes-here", "" /* should be http://origin/ */},
   };
-  for (size_t i = 0; i < gurl_base::size(cases); i++) {
+  for (size_t i = 0; i < std::size(cases); i++) {
     GURL url(cases[i].input);
     GURL origin = url.DeprecatedGetOriginAsURL();
     EXPECT_EQ(cases[i].expected, origin.spec());
@@ -406,7 +406,7 @@
     {"file:///tmp/test.html", ""},
     {"https://www.google.com", "https://www.google.com/"},
   };
-  for (size_t i = 0; i < gurl_base::size(cases); i++) {
+  for (size_t i = 0; i < std::size(cases); i++) {
     GURL url(cases[i].input);
     GURL origin = url.GetAsReferrer();
     EXPECT_EQ(cases[i].expected, origin.spec());
@@ -425,7 +425,7 @@
     {"filesystem:file:///temporary/bar.html?baz=22", "filesystem:file:///temporary/"},
   };
 
-  for (size_t i = 0; i < gurl_base::size(cases); i++) {
+  for (size_t i = 0; i < std::size(cases); i++) {
     GURL url(cases[i].input);
     GURL empty_path = url.GetWithEmptyPath();
     EXPECT_EQ(cases[i].expected, empty_path.spec());
@@ -471,7 +471,7 @@
     {"foobar", ""},
   };
 
-  for (size_t i = 0; i < gurl_base::size(cases); i++) {
+  for (size_t i = 0; i < std::size(cases); i++) {
     GURL url(cases[i].input);
     GURL without_filename = url.GetWithoutFilename();
     EXPECT_EQ(cases[i].expected, without_filename.spec()) << i;
@@ -636,7 +636,7 @@
        "/foo/bar.html?query", "/temporary"},
   };
 
-  for (size_t i = 0; i < gurl_base::size(cases); i++) {
+  for (size_t i = 0; i < std::size(cases); i++) {
     GURL url(cases[i].input);
     EXPECT_EQ(cases[i].expected, url.PathForRequest());
     EXPECT_EQ(cases[i].expected, url.PathForRequestPiece());
@@ -682,7 +682,7 @@
     {"filesystem:file:///t/foo", PORT_UNSPECIFIED},
   };
 
-  for (size_t i = 0; i < gurl_base::size(port_tests); i++) {
+  for (size_t i = 0; i < std::size(port_tests); i++) {
     GURL url(port_tests[i].spec);
     EXPECT_EQ(port_tests[i].expected_int_port, url.EffectiveIntPort());
   }
@@ -703,7 +703,7 @@
     {"some random input!", false},
   };
 
-  for (size_t i = 0; i < gurl_base::size(ip_tests); i++) {
+  for (size_t i = 0; i < std::size(ip_tests); i++) {
     GURL url(ip_tests[i].spec);
     EXPECT_EQ(ip_tests[i].expected_ip, url.HostIsIPAddress());
   }
@@ -728,7 +728,7 @@
     {"http://]/", "]", "]"},
     {"", "", ""},
   };
-  for (size_t i = 0; i < gurl_base::size(cases); i++) {
+  for (size_t i = 0; i < std::size(cases); i++) {
     GURL url(cases[i].input);
     EXPECT_EQ(cases[i].expected_host, url.host());
     EXPECT_EQ(cases[i].expected_plainhost, url.HostNoBrackets());
diff --git a/url/origin.cc b/url/origin.cc
index e943d4f..b17591d 100644
--- a/url/origin.cc
+++ b/url/origin.cc
@@ -8,21 +8,23 @@
 
 #include <algorithm>
 #include <ostream>
-#include <vector>
+#include <string>
+#include <tuple>
+#include <utility>
 
 #include "base/base64.h"
+#include "polyfills/base/check.h"
 #include "polyfills/base/check_op.h"
 #include "base/containers/contains.h"
 #include "base/containers/span.h"
+#include "base/debug/crash_logging.h"
 #include "base/pickle.h"
 #include "base/strings/strcat.h"
-#include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
-#include "base/strings/string_util.h"
+#include "base/unguessable_token.h"
 #include "polyfills/third_party/perfetto/include/perfetto/tracing/traced_value.h"
 #include "url/gurl.h"
-#include "url/url_canon.h"
-#include "url/url_canon_stdstring.h"
+#include "url/scheme_host_port.h"
 #include "url/url_constants.h"
 #include "url/url_util.h"
 
@@ -150,11 +152,8 @@
   return tuple_.GetURL();
 }
 
-absl::optional<gurl_base::UnguessableToken> Origin::GetNonceForSerialization()
-    const {
-  // TODO(nasko): Consider not making a copy here, but return a reference to
-  // the nonce.
-  return nonce_ ? absl::make_optional(nonce_->token()) : absl::nullopt;
+const gurl_base::UnguessableToken* Origin::GetNonceForSerialization() const {
+  return nonce_ ? &nonce_->token() : nullptr;
 }
 
 bool Origin::IsSameOriginWith(const Origin& other) const {
diff --git a/url/origin.h b/url/origin.h
index c1ad177..1b0a407 100644
--- a/url/origin.h
+++ b/url/origin.h
@@ -13,17 +13,15 @@
 #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 "base/strings/string_piece_forward.h"
 #include "base/strings/string_util.h"
 #include "base/unguessable_token.h"
 #include "build/build_config.h"
+#include "build/buildflag.h"
 #include "ipc/ipc_param_traits.h"
 #include "absl/types/optional.h"
 #include "polyfills/third_party/perfetto/include/perfetto/tracing/traced_value.h"
 #include "url/scheme_host_port.h"
-#include "url/third_party/mozilla/url_parse.h"
-#include "url/url_canon.h"
-#include "url/url_constants.h"
 
 #if BUILDFLAG(IS_ANDROID)
 #include <jni.h>
@@ -403,9 +401,10 @@
   // given |nonce|.
   Origin(const Nonce& nonce, SchemeHostPort precursor);
 
-  // Get the nonce associated with this origin, if it is opaque. This should be
-  // used only when trying to send an Origin across an IPC pipe.
-  absl::optional<gurl_base::UnguessableToken> GetNonceForSerialization() const;
+  // Get the nonce associated with this origin, if it is opaque, or nullptr
+  // otherwise. This should be used only when trying to send an Origin across an
+  // IPC pipe.
+  const gurl_base::UnguessableToken* GetNonceForSerialization() const;
 
   // Serializes this Origin, including its nonce if it is opaque. If an opaque
   // origin's |tuple_| is invalid nullopt is returned. If the nonce is not
diff --git a/url/origin_unittest.cc b/url/origin_unittest.cc
index 755d2e3..bd9ee7e 100644
--- a/url/origin_unittest.cc
+++ b/url/origin_unittest.cc
@@ -69,7 +69,7 @@
     return Origin::Nonce(nonce);
   }
 
-  absl::optional<gurl_base::UnguessableToken> GetNonce(const Origin& origin) {
+  const gurl_base::UnguessableToken* GetNonce(const Origin& origin) {
     return origin.GetNonceForSerialization();
   }
 
@@ -364,7 +364,7 @@
       << "UnsafelyCreateOpaqueOriginWithoutNormalization, so long as it is "
       << "the canonical form of the invalid tuple.";
   EXPECT_TRUE(anonymous_opaque->opaque());
-  EXPECT_EQ(GetNonce(anonymous_opaque.value()), token);
+  EXPECT_EQ(*GetNonce(anonymous_opaque.value()), token);
   EXPECT_EQ(anonymous_opaque->GetTupleOrPrecursorTupleIfOpaque(),
             url::SchemeHostPort());
 }
diff --git a/url/scheme_host_port_unittest.cc b/url/scheme_host_port_unittest.cc
index e55c9d5..f49bd59 100644
--- a/url/scheme_host_port_unittest.cc
+++ b/url/scheme_host_port_unittest.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "url/scheme_host_port.h"
+
 #include <stddef.h>
 #include <stdint.h>
 
-#include "base/cxx17_backports.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
-#include "url/scheme_host_port.h"
 #include "url/url_util.h"
 
 namespace {
@@ -262,10 +262,10 @@
       {"https", "b", 81},
   };
 
-  for (size_t i = 0; i < gurl_base::size(tuples); i++) {
+  for (size_t i = 0; i < std::size(tuples); i++) {
     url::SchemeHostPort current(tuples[i].scheme, tuples[i].host,
                                 tuples[i].port);
-    for (size_t j = i; j < gurl_base::size(tuples); j++) {
+    for (size_t j = i; j < std::size(tuples); j++) {
       url::SchemeHostPort to_compare(tuples[j].scheme, tuples[j].host,
                                      tuples[j].port);
       EXPECT_EQ(i < j, current < to_compare) << i << " < " << j;
diff --git a/url/third_party/mozilla/url_parse.cc b/url/third_party/mozilla/url_parse.cc
index 8edb7f3..2500fc6 100644
--- a/url/third_party/mozilla/url_parse.cc
+++ b/url/third_party/mozilla/url_parse.cc
@@ -692,6 +692,11 @@
 
 }  // namespace
 
+COMPONENT_EXPORT(URL)
+std::ostream& operator<<(std::ostream& os, const Component& component) {
+  return os << '{' << component.begin << ", " << component.len << "}";
+}
+
 Parsed::Parsed() : potentially_dangling_markup(false), inner_parsed_(NULL) {}
 
 Parsed::Parsed(const Parsed& other)
diff --git a/url/third_party/mozilla/url_parse.h b/url/third_party/mozilla/url_parse.h
index 1ec0ef8..c3535ba 100644
--- a/url/third_party/mozilla/url_parse.h
+++ b/url/third_party/mozilla/url_parse.h
@@ -5,6 +5,8 @@
 #ifndef URL_THIRD_PARTY_MOZILLA_URL_PARSE_H_
 #define URL_THIRD_PARTY_MOZILLA_URL_PARSE_H_
 
+#include <iosfwd>
+
 #include "polyfills/base/component_export.h"
 
 namespace url {
@@ -47,6 +49,10 @@
   int len;    // Will be -1 if the component is unspecified.
 };
 
+// Permit printing Components by GURL_CHECK macros.
+COMPONENT_EXPORT(URL)
+std::ostream& operator<<(std::ostream& os, const Component& component);
+
 // Helper that returns a component created with the given begin and ending
 // points. The ending point is non-inclusive.
 inline Component MakeRange(int begin, int end) {
diff --git a/url/url_canon.h b/url/url_canon.h
index 32e7b15..e935d7f 100644
--- a/url/url_canon.h
+++ b/url/url_canon.h
@@ -8,8 +8,6 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <string>
-
 #include "polyfills/base/component_export.h"
 #include "polyfills/base/export_template.h"
 #include "url/third_party/mozilla/url_parse.h"
@@ -299,7 +297,7 @@
 // Piece-by-piece canonicalizers ----------------------------------------------
 //
 // These individual canonicalizers append the canonicalized versions of the
-// corresponding URL component to the given std::string. The spec and the
+// corresponding URL component to the given CanonOutput. The spec and the
 // previously-identified range of that component are the input. The range of
 // the canonicalized component will be written to the output component.
 //
diff --git a/url/url_canon_icu_unittest.cc b/url/url_canon_icu_unittest.cc
index 702b1d3..cb74f64 100644
--- a/url/url_canon_icu_unittest.cc
+++ b/url/url_canon_icu_unittest.cc
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "url/url_canon_icu.h"
+
 #include <stddef.h>
 
-#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"
-#include "url/url_canon_icu.h"
 #include "url/url_canon_stdstring.h"
 #include "url/url_test_utils.h"
 
@@ -60,7 +60,7 @@
       "hello\xa7\x41%26%231758%3B\xa6\x6eworld"},
   };
 
-  for (size_t i = 0; i < gurl_base::size(icu_cases); i++) {
+  for (size_t i = 0; i < std::size(icu_cases); i++) {
     UConvScoper conv(icu_cases[i].encoding);
     ASSERT_TRUE(conv.converter() != NULL);
     ICUCharsetConverter converter(conv.converter());
@@ -118,7 +118,7 @@
       "?q=Chinese%26%2365319%3B"},
   };
 
-  for (size_t i = 0; i < gurl_base::size(query_cases); i++) {
+  for (size_t i = 0; i < std::size(query_cases); i++) {
     Component out_comp;
 
     UConvScoper conv(query_cases[i].encoding);
diff --git a/url/url_canon_unittest.cc b/url/url_canon_unittest.cc
index 2dd5075..0170e00 100644
--- a/url/url_canon_unittest.cc
+++ b/url/url_canon_unittest.cc
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "url/url_canon.h"
+
 #include <errno.h>
 #include <stddef.h>
 
-#include "base/cxx17_backports.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/gtest_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/third_party/mozilla/url_parse.h"
-#include "url/url_canon.h"
 #include "url/url_canon_internal.h"
 #include "url/url_canon_stdstring.h"
 #include "url/url_test_utils.h"
@@ -116,7 +116,7 @@
     {0x10FFFF, "\xF4\x8F\xBF\xBF"},
   };
   std::string out_str;
-  for (size_t i = 0; i < gurl_base::size(utf_cases); i++) {
+  for (size_t i = 0; i < std::size(utf_cases); i++) {
     out_str.clear();
     StdStringCanonOutput output(&out_str);
     AppendUTF8Value(utf_cases[i].input, &output);
@@ -168,7 +168,7 @@
   };
 
   std::string out_str;
-  for (size_t i = 0; i < gurl_base::size(utf_cases); i++) {
+  for (size_t i = 0; i < std::size(utf_cases); i++) {
     if (utf_cases[i].input8) {
       out_str.clear();
       StdStringCanonOutput output(&out_str);
@@ -239,7 +239,7 @@
 
   std::string out_str;
 
-  for (size_t i = 0; i < gurl_base::size(scheme_cases); i++) {
+  for (size_t i = 0; i < std::size(scheme_cases); i++) {
     int url_len = static_cast<int>(strlen(scheme_cases[i].input));
     Component in_comp(0, url_len);
     Component out_comp;
@@ -504,7 +504,7 @@
 
   // CanonicalizeHost() non-verbose.
   std::string out_str;
-  for (size_t i = 0; i < gurl_base::size(host_cases); i++) {
+  for (size_t i = 0; i < std::size(host_cases); i++) {
     // Narrow version.
     if (host_cases[i].input8) {
       int host_len = static_cast<int>(strlen(host_cases[i].input8));
@@ -552,7 +552,7 @@
   }
 
   // CanonicalizeHostVerbose()
-  for (size_t i = 0; i < gurl_base::size(host_cases); i++) {
+  for (size_t i = 0; i < std::size(host_cases); i++) {
     // Narrow version.
     if (host_cases[i].input8) {
       int host_len = static_cast<int>(strlen(host_cases[i].input8));
@@ -869,7 +869,7 @@
     {"[::1 hello]", L"[::1 hello]", "", Component(), CanonHostInfo::BROKEN, -1, ""},
   };
 
-  for (size_t i = 0; i < gurl_base::size(cases); i++) {
+  for (size_t i = 0; i < std::size(cases); i++) {
     // 8-bit version.
     Component component(0, static_cast<int>(strlen(cases[i].input8)));
 
@@ -995,7 +995,7 @@
     {"ftp://me\\mydomain:pass@foo.com/", "", Component(0, -1), Component(0, -1), true},
   };
 
-  for (size_t i = 0; i < gurl_base::size(user_info_cases); i++) {
+  for (size_t i = 0; i < std::size(user_info_cases); i++) {
     int url_len = static_cast<int>(strlen(user_info_cases[i].input));
     Parsed parsed;
     ParseStandardURL(user_info_cases[i].input, url_len, &parsed);
@@ -1064,7 +1064,7 @@
     {"80", PORT_UNSPECIFIED, ":80", Component(1, 2), true},
   };
 
-  for (size_t i = 0; i < gurl_base::size(port_cases); i++) {
+  for (size_t i = 0; i < std::size(port_cases); i++) {
     int url_len = static_cast<int>(strlen(port_cases[i].input));
     Component in_comp(0, url_len);
     Component out_comp;
@@ -1249,7 +1249,7 @@
 }
 
 TEST(URLCanonTest, Path) {
-  DoPathTest(kCommonPathCases, gurl_base::size(kCommonPathCases), CanonicalizePath,
+  DoPathTest(kCommonPathCases, std::size(kCommonPathCases), CanonicalizePath,
              CanonicalizePath);
 
   // Manual test: embedded NULLs should be escaped and the URL should be marked
@@ -1272,9 +1272,9 @@
       {"", L"", "", Component(0, 0), true},
   };
 
-  DoPathTest(kCommonPathCases, gurl_base::size(kCommonPathCases),
+  DoPathTest(kCommonPathCases, std::size(kCommonPathCases),
              CanonicalizePartialPath, CanonicalizePartialPath);
-  DoPathTest(partial_path_cases, gurl_base::size(partial_path_cases),
+  DoPathTest(partial_path_cases, std::size(partial_path_cases),
              CanonicalizePartialPath, CanonicalizePartialPath);
 }
 
@@ -1304,7 +1304,7 @@
     {"q=\"asdf\"", L"q=\"asdf\"", "?q=%22asdf%22"},
   };
 
-  for (size_t i = 0; i < gurl_base::size(query_cases); i++) {
+  for (size_t i = 0; i < std::size(query_cases); i++) {
     Component out_comp;
 
     if (query_cases[i].input8) {
@@ -1376,7 +1376,7 @@
       {"#asdf", L"#asdf", "##asdf", Component(1, 5), true},
   };
 
-  for (size_t i = 0; i < gurl_base::size(ref_cases); i++) {
+  for (size_t i = 0; i < std::size(ref_cases); i++) {
     // 8-bit input
     if (ref_cases[i].input8) {
       int len = static_cast<int>(strlen(ref_cases[i].input8));
@@ -1491,7 +1491,7 @@
       {R"(HTTP:S/5%\../>%41)", "http://s/%3EA", true},
   };
 
-  for (size_t i = 0; i < gurl_base::size(cases); i++) {
+  for (size_t i = 0; i < std::size(cases); i++) {
     int url_len = static_cast<int>(strlen(cases[i].input));
     Parsed parsed;
     ParseStandardURL(cases[i].input, url_len, &parsed);
@@ -1532,7 +1532,7 @@
        "filesystem://a:b@google.com:22/foo?baz@cat"},
   };
 
-  for (size_t i = 0; i < gurl_base::size(replace_cases); i++) {
+  for (size_t i = 0; i < std::size(replace_cases); i++) {
     const ReplaceCase& cur = replace_cases[i];
     int base_len = static_cast<int>(strlen(cur.base));
     Parsed parsed;
@@ -1632,7 +1632,7 @@
        nullptr, nullptr, nullptr, "file:///C:/gaba?query#ref"},
   };
 
-  for (size_t i = 0; i < gurl_base::size(replace_cases); i++) {
+  for (size_t i = 0; i < std::size(replace_cases); i++) {
     const ReplaceCase& cur = replace_cases[i];
     SCOPED_TRACE(cur.base);
     int base_len = static_cast<int>(strlen(cur.base));
@@ -1701,7 +1701,7 @@
        "filesystem:http://bar.com:40/t/gaba?query#ref"},
   };
 
-  for (size_t i = 0; i < gurl_base::size(replace_cases); i++) {
+  for (size_t i = 0; i < std::size(replace_cases); i++) {
     const ReplaceCase& cur = replace_cases[i];
     int base_len = static_cast<int>(strlen(cur.base));
     Parsed parsed;
@@ -1745,7 +1745,7 @@
        nullptr, nullptr, "data:"},
   };
 
-  for (size_t i = 0; i < gurl_base::size(replace_cases); i++) {
+  for (size_t i = 0; i < std::size(replace_cases); i++) {
     const ReplaceCase& cur = replace_cases[i];
     int base_len = static_cast<int>(strlen(cur.base));
     Parsed parsed;
@@ -1796,7 +1796,7 @@
     {"mailto:addr1", NULL, NULL, NULL, NULL, NULL, NULL, NULL, "BLAH", "mailto:addr1"},
   };
 
-  for (size_t i = 0; i < gurl_base::size(replace_cases); i++) {
+  for (size_t i = 0; i < std::size(replace_cases); i++) {
     const ReplaceCase& cur = replace_cases[i];
     int base_len = static_cast<int>(strlen(cur.base));
     Parsed parsed;
@@ -1909,7 +1909,7 @@
 #endif  // _WIN32
   };
 
-  for (size_t i = 0; i < gurl_base::size(cases); i++) {
+  for (size_t i = 0; i < std::size(cases); i++) {
     int url_len = static_cast<int>(strlen(cases[i].input));
     Parsed parsed;
     ParseFileURL(cases[i].input, url_len, &parsed);
@@ -1958,7 +1958,7 @@
       {"FilEsysteM:htTp:E=/.", "filesystem:http://e%3D//", false},
   };
 
-  for (size_t i = 0; i < gurl_base::size(cases); i++) {
+  for (size_t i = 0; i < std::size(cases); i++) {
     int url_len = static_cast<int>(strlen(cases[i].input));
     Parsed parsed;
     ParseFileSystemURL(cases[i].input, url_len, &parsed);
@@ -1997,7 +1997,7 @@
       {"javascript:\uFFFF", "javascript:%EF%BF%BD"},
   };
 
-  for (size_t i = 0; i < gurl_base::size(path_cases); i++) {
+  for (size_t i = 0; i < std::size(path_cases); i++) {
     int url_len = static_cast<int>(strlen(path_cases[i].input));
     Parsed parsed;
     ParsePathURL(path_cases[i].input, url_len, true, &parsed);
@@ -2035,7 +2035,7 @@
       {"\uFFFF", L"\uFFFF", "%EF%BF%BD"},
   };
 
-  for (size_t i = 0; i < gurl_base::size(path_cases); i++) {
+  for (size_t i = 0; i < std::size(path_cases); i++) {
     // 8-bit string input
     std::string out_str;
     StdStringCanonOutput output(&out_str);
@@ -2129,7 +2129,7 @@
   Parsed parsed;
   Parsed out_parsed;
 
-  for (size_t i = 0; i < gurl_base::size(cases); i++) {
+  for (size_t i = 0; i < std::size(cases); i++) {
     int url_len = static_cast<int>(strlen(cases[i].input));
     if (i == 0) {
       // The first test case purposely has a '\0' in it -- don't count it
@@ -2399,7 +2399,7 @@
     {"about:blank", false, false, "content://content.Provider/", true, false, true, ""},
   };
 
-  for (size_t i = 0; i < gurl_base::size(rel_cases); i++) {
+  for (size_t i = 0; i < std::size(rel_cases); i++) {
     const RelativeCase& cur_case = rel_cases[i];
 
     Parsed parsed;
diff --git a/url/url_parse_unittest.cc b/url/url_parse_unittest.cc
index 7cd3fe8..9a8bb57 100644
--- a/url/url_parse_unittest.cc
+++ b/url/url_parse_unittest.cc
@@ -2,11 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "url/third_party/mozilla/url_parse.h"
-
 #include <stddef.h>
 
-#include "base/cxx17_backports.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/third_party/mozilla/url_parse.h"
 
@@ -137,7 +134,7 @@
     "http://user@",
     "http:",
   };
-  for (size_t i = 0; i < gurl_base::size(length_cases); i++) {
+  for (size_t i = 0; i < std::size(length_cases); i++) {
     int true_length = static_cast<int>(strlen(length_cases[i]));
 
     Parsed parsed;
@@ -196,7 +193,7 @@
     {"file:///c:/foo", Parsed::HOST, true, 7},
     {"file:///c:/foo", Parsed::PATH, true, 7},
   };
-  for (size_t i = 0; i < gurl_base::size(count_cases); i++) {
+  for (size_t i = 0; i < std::size(count_cases); i++) {
     int length = static_cast<int>(strlen(count_cases[i].url));
 
     // Simple test to distinguish file and standard URLs.
@@ -314,7 +311,7 @@
   // Declared outside for loop to try to catch cases in init() where we forget
   // to reset something that is reset by the constructor.
   Parsed parsed;
-  for (size_t i = 0; i < gurl_base::size(cases); i++) {
+  for (size_t i = 0; i < std::size(cases); i++) {
     const char* url = cases[i].input;
     ParseStandardURL(url, static_cast<int>(strlen(url)), &parsed);
     int port = ParsePort(url, parsed.port);
@@ -349,7 +346,7 @@
   // Declared outside for loop to try to catch cases in init() where we forget
   // to reset something that is reset by the constructor.
   Parsed parsed;
-  for (size_t i = 0; i < gurl_base::size(path_cases); i++) {
+  for (size_t i = 0; i < std::size(path_cases); i++) {
     const char* url = path_cases[i].input;
     ParsePathURL(url, static_cast<int>(strlen(url)), false, &parsed);
 
@@ -448,7 +445,7 @@
   // Declared outside for loop to try to catch cases in init() where we forget
   // to reset something that is reset by the construtor.
   Parsed parsed;
-  for (size_t i = 0; i < gurl_base::size(file_cases); i++) {
+  for (size_t i = 0; i < std::size(file_cases); i++) {
     const char* url = file_cases[i].input;
     ParseFileURL(url, static_cast<int>(strlen(url)), &parsed);
     int port = ParsePort(url, parsed.port);
@@ -509,7 +506,7 @@
       {"http://www.google.com/foo;bar;html", "foo"},
   };
 
-  for (size_t i = 0; i < gurl_base::size(extract_cases); i++) {
+  for (size_t i = 0; i < std::size(extract_cases); i++) {
     const char* url = extract_cases[i].input;
     int len = static_cast<int>(strlen(url));
 
@@ -617,7 +614,7 @@
   // Declared outside for loop to try to catch cases in init() where we forget
   // to reset something that is reset by the constructor.
   Parsed parsed;
-  for (size_t i = 0; i < gurl_base::size(mailto_cases); ++i) {
+  for (size_t i = 0; i < std::size(mailto_cases); ++i) {
     const char* url = mailto_cases[i].input;
     ParseMailtoURL(url, static_cast<int>(strlen(url)), &parsed);
     int port = ParsePort(url, parsed.port);
@@ -649,7 +646,7 @@
   // Declared outside for loop to try to catch cases in init() where we forget
   // to reset something that is reset by the constructor.
   Parsed parsed;
-  for (size_t i = 0; i < gurl_base::size(filesystem_cases); i++) {
+  for (size_t i = 0; i < std::size(filesystem_cases); i++) {
     const FileSystemURLParseCase* parsecase = &filesystem_cases[i];
     const char* url = parsecase->input;
     ParseFileSystemURL(url, static_cast<int>(strlen(url)), &parsed);
diff --git a/url/url_util.cc b/url/url_util.cc
index 3162fdf..26657f7 100644
--- a/url/url_util.cc
+++ b/url/url_util.cc
@@ -438,6 +438,13 @@
     // ref).
     Replacements<CHAR> replacements_no_scheme = replacements;
     replacements_no_scheme.SetScheme(NULL, Component());
+    // If the input URL has potentially dangling markup, set the flag on the
+    // output too. Note that in some cases the replacement gets rid of the
+    // potentially dangling markup, but this ok since the check will fail
+    // closed.
+    if (parsed.potentially_dangling_markup) {
+      out_parsed->potentially_dangling_markup = true;
+    }
     return DoReplaceComponents(recanonicalized.data(), recanonicalized.length(),
                                recanonicalized_parsed, replacements_no_scheme,
                                charset_converter, output, out_parsed);
diff --git a/url/url_util_unittest.cc b/url/url_util_unittest.cc
index 5255817..53aab7d 100644
--- a/url/url_util_unittest.cc
+++ b/url/url_util_unittest.cc
@@ -6,7 +6,6 @@
 
 #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"
@@ -251,7 +250,7 @@
       {"%e4%bd%a0%e5%a5%bd", "\xe4\xbd\xa0\xe5\xa5\xbd"},
   };
 
-  for (size_t i = 0; i < gurl_base::size(decode_cases); i++) {
+  for (size_t i = 0; i < std::size(decode_cases); i++) {
     const char* input = decode_cases[i].input;
     RawCanonOutputT<char16_t> output;
     DecodeURLEscapeSequences(input, strlen(input),
@@ -333,7 +332,7 @@
      "pqrstuvwxyz%7B%7C%7D~%7F"},
   };
 
-  for (size_t i = 0; i < gurl_base::size(encode_cases); i++) {
+  for (size_t i = 0; i < std::size(encode_cases); i++) {
     const char* input = encode_cases[i].input;
     RawCanonOutputT<char> buffer;
     EncodeURIComponent(input, strlen(input), &buffer);
@@ -410,7 +409,7 @@
       // adding the requested dot doesn't seem wrong either.
       {"aaa://a\\", "aaa:.", true, "aaa://a\\."}};
 
-  for (size_t i = 0; i < gurl_base::size(resolve_non_standard_cases); i++) {
+  for (size_t i = 0; i < std::size(resolve_non_standard_cases); i++) {
     const ResolveRelativeCase& test_data = resolve_non_standard_cases[i];
     Parsed base_parsed;
     ParsePathURL(test_data.base, strlen(test_data.base), false, &base_parsed);
@@ -518,6 +517,26 @@
   EXPECT_TRUE(replaced_parsed.potentially_dangling_markup);
 }
 
+TEST_F(URLUtilTest, PotentiallyDanglingMarkupAfterSchemeOnlyReplacement) {
+  // Parse a URL with potentially dangling markup.
+  Parsed original_parsed;
+  RawCanonOutput<32> original;
+  const char* url = "http://example.com/\n/<path";
+  Canonicalize(url, strlen(url), false, nullptr, &original, &original_parsed);
+  ASSERT_TRUE(original_parsed.potentially_dangling_markup);
+
+  // Perform a replacement, and validate that the potentially_dangling_markup
+  // flag carried over to the new Parsed object.
+  Replacements<char> replacements;
+  const char* new_scheme = "https";
+  replacements.SetScheme(new_scheme, Component(0, strlen(new_scheme)));
+  Parsed replaced_parsed;
+  RawCanonOutput<32> replaced;
+  ReplaceComponents(original.data(), original.length(), original_parsed,
+                    replacements, nullptr, &replaced, &replaced_parsed);
+  EXPECT_TRUE(replaced_parsed.potentially_dangling_markup);
+}
+
 TEST_F(URLUtilTest, TestDomainIs) {
   const struct {
     const char* canonicalized_host;