[committed] libstdc++: Implement LWG issues 3398, 3379, 3304, 3321, 3280, 3335

Message ID 20200219124722.GM9441@redhat.com
State New
Headers show
Series
  • [committed] libstdc++: Implement LWG issues 3398, 3379, 3304, 3321, 3280, 3335
Related show

Commit Message

Jonathan Wakely Feb. 19, 2020, 12:47 p.m.
Add ranges_size_t and rename all_view (LWG 3335)
Remove converting constructors from views (LWG 3280)
uninitialized_construct_using_allocator should use construct_at (LWG 3321)
Add nodiscard to polymorphic_allocator members (LWG 3304)
"safe" in several library names is misleading (LWG 3379)
tuple_element_t is also wrong for const subrange (LWG 3398)

Tested powerpc64le-linux, committed to master.

Comments

Jonathan Wakely Feb. 19, 2020, 1 p.m. | #1
On 19/02/20 12:47 +0000, Jonathan Wakely wrote:
>Add ranges_size_t and rename all_view (LWG 3335)

>Remove converting constructors from views (LWG 3280)

>uninitialized_construct_using_allocator should use construct_at (LWG 3321)

>Add nodiscard to polymorphic_allocator members (LWG 3304)

>"safe" in several library names is misleading (LWG 3379)

>tuple_element_t is also wrong for const subrange (LWG 3398)

>

>Tested powerpc64le-linux, committed to master.


Oops, the attached patch also included three other commits that
weren't mine (but were already committed).

Patch

commit aca60ecff35837a1af9383cf67ee7d1c0a718b28
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed Feb 19 12:30:10 2020 +0000

    libstdc++: Add ranges_size_t and rename all_view (LWG 3335)
    
            * include/bits/range_access.h (range_size_t): Define alias template.
            * include/std/ranges (all_view): Rename to views::all_t (LWG 3335).
            * testsuite/std/ranges/adaptors/filter.cc: Adjust to new name.

diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index 9ccba4345d5..f01b78da118 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,5 +1,9 @@ 
 2020-02-19  Jonathan Wakely  <jwakely@redhat.com>
 
+	* include/bits/range_access.h (range_size_t): Define alias template.
+	* include/std/ranges (all_view): Rename to views::all_t (LWG 3335).
+	* testsuite/std/ranges/adaptors/filter.cc: Adjust to new name.
+
 	* include/std/ranges (filter_view, transform_view, take_view)
 	(join_view, split_view, reverse_view): Remove commented-out converting
 	constructors (LWG 3280).
diff --git a/libstdc++-v3/include/bits/range_access.h b/libstdc++-v3/include/bits/range_access.h
index e2a2c28c7d2..e7a19305d23 100644
--- a/libstdc++-v3/include/bits/range_access.h
+++ b/libstdc++-v3/include/bits/range_access.h
@@ -905,6 +905,9 @@  namespace ranges
     concept sized_range = range<_Tp>
       && requires(_Tp& __t) { ranges::size(__t); };
 
+  template<sized_range _Range>
+    using range_size_t = decltype(ranges::size(std::declval<_Range&>()));
+
   // [range.refinements]
 
   /// A range for which ranges::begin returns an output iterator.
diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index cf4c19ffaab..b0806750a08 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -1236,10 +1236,11 @@  namespace views
 	else
 	  return subrange{std::forward<_Range>(__r)};
       };
-  } // namespace views
 
-  template<viewable_range _Range>
-    using all_view = decltype(views::all(declval<_Range>()));
+    template<viewable_range _Range>
+      using all_t = decltype(all(std::declval<_Range>()));
+
+  } // namespace views
 
   // XXX: the following algos are copied from ranges_algo.h to avoid a circular
   // dependency with that header.
@@ -1503,7 +1504,7 @@  namespace views
     };
 
   template<typename _Range, typename _Pred>
-    filter_view(_Range&&, _Pred) -> filter_view<all_view<_Range>, _Pred>;
+    filter_view(_Range&&, _Pred) -> filter_view<views::all_t<_Range>, _Pred>;
 
   namespace views
   {
@@ -1836,7 +1837,7 @@  namespace views
     };
 
   template<typename _Range, typename _Fp>
-    transform_view(_Range&&, _Fp) -> transform_view<all_view<_Range>, _Fp>;
+    transform_view(_Range&&, _Fp) -> transform_view<views::all_t<_Range>, _Fp>;
 
   namespace views
   {
@@ -1974,7 +1975,7 @@  namespace views
 
   template<range _Range>
     take_view(_Range&&, range_difference_t<_Range>)
-      -> take_view<all_view<_Range>>;
+      -> take_view<views::all_t<_Range>>;
 
   namespace views
   {
@@ -2066,7 +2067,7 @@  namespace views
 
   template<typename _Range, typename _Pred>
     take_while_view(_Range&&, _Pred)
-      -> take_while_view<all_view<_Range>, _Pred>;
+      -> take_while_view<views::all_t<_Range>, _Pred>;
 
   namespace views
   {
@@ -2143,7 +2144,7 @@  namespace views
 
   template<typename _Range>
     drop_view(_Range&&, range_difference_t<_Range>)
-      -> drop_view<all_view<_Range>>;
+      -> drop_view<views::all_t<_Range>>;
 
   namespace views
   {
@@ -2199,7 +2200,7 @@  namespace views
 
   template<typename _Range, typename _Pred>
     drop_while_view(_Range&&, _Pred)
-      -> drop_while_view<all_view<_Range>, _Pred>;
+      -> drop_while_view<views::all_t<_Range>, _Pred>;
 
   namespace views
   {
@@ -2450,7 +2451,7 @@  namespace views
       // XXX: _M_inner is "present only when !is_reference_v<_InnerRange>"
       [[no_unique_address]]
 	conditional_t<!is_reference_v<_InnerRange>,
-		      all_view<_InnerRange>, __detail::_Empty> _M_inner;
+		      views::all_t<_InnerRange>, __detail::_Empty> _M_inner;
 
     public:
       join_view() = default;
@@ -2514,7 +2515,7 @@  namespace views
     };
 
   template<typename _Range>
-    explicit join_view(_Range&&) -> join_view<all_view<_Range>>;
+    explicit join_view(_Range&&) -> join_view<views::all_t<_Range>>;
 
   namespace views
   {
@@ -2838,7 +2839,7 @@  namespace views
       { }
 
       template<input_range _Range>
-	requires constructible_from<_Vp, all_view<_Range>>
+	requires constructible_from<_Vp, views::all_t<_Range>>
 	  && constructible_from<_Pattern, single_view<range_value_t<_Range>>>
 	constexpr
 	split_view(_Range&& __r, range_value_t<_Range> __e)
@@ -2893,11 +2894,11 @@  namespace views
 
   template<typename _Range, typename _Pred>
     split_view(_Range&&, _Pred&&)
-      -> split_view<all_view<_Range>, all_view<_Pred>>;
+      -> split_view<views::all_t<_Range>, views::all_t<_Pred>>;
 
   template<input_range _Range>
     split_view(_Range&&, range_value_t<_Range>)
-      -> split_view<all_view<_Range>, single_view<range_value_t<_Range>>>;
+      -> split_view<views::all_t<_Range>, single_view<range_value_t<_Range>>>;
 
   namespace views
   {
@@ -2945,7 +2946,7 @@  namespace views
       /* XXX: LWG 3280 didn't remove this constructor, but I think it should?
       template<viewable_range _Range>
 	requires (!common_range<_Range>)
-	  && constructible_from<_Vp, all_view<_Range>>
+	  && constructible_from<_Vp, views::all_t<_Range>>
 	constexpr explicit
 	common_view(_Range&& __r)
 	  : _M_base(views::all(std::forward<_Range>(__r)))
@@ -3010,7 +3011,7 @@  namespace views
     };
 
   template<typename _Range>
-    common_view(_Range&&) -> common_view<all_view<_Range>>;
+    common_view(_Range&&) -> common_view<views::all_t<_Range>>;
 
   namespace views
   {
@@ -3083,7 +3084,7 @@  namespace views
     };
 
   template<typename _Range>
-    reverse_view(_Range&&) -> reverse_view<all_view<_Range>>;
+    reverse_view(_Range&&) -> reverse_view<views::all_t<_Range>>;
 
   namespace views
   {
@@ -3356,10 +3357,10 @@  namespace views
     };
 
   template<typename _Range>
-    using keys_view = elements_view<all_view<_Range>, 0>;
+    using keys_view = elements_view<views::all_t<_Range>, 0>;
 
   template<typename _Range>
-    using values_view = elements_view<all_view<_Range>, 1>;
+    using values_view = elements_view<views::all_t<_Range>, 1>;
 
   namespace views
   {
@@ -3367,7 +3368,8 @@  namespace views
     inline constexpr __adaptor::_RangeAdaptorClosure elements
       = [] <viewable_range _Range> (_Range&& __r)
       {
-	return elements_view<all_view<_Range>, _Nm>{std::forward<_Range>(__r)};
+	using _El = elements_view<views::all_t<_Range>, _Nm>;
+	return _El{std::forward<_Range>(__r)};
       };
 
     inline constexpr __adaptor::_RangeAdaptorClosure keys = elements<0>;
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/filter.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/filter.cc
index 4edbf0b657d..4e41232cd5c 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/filter.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/filter.cc
@@ -43,7 +43,7 @@  test01()
   static_assert(!ranges::sized_range<R>);
   static_assert(ranges::bidirectional_range<R>);
   static_assert(!ranges::random_access_range<R>);
-  static_assert(ranges::range<ranges::all_view<R>>);
+  static_assert(ranges::range<views::all_t<R>>);
   VERIFY( ranges::equal(v, (int[]){1,3,5}) );
   VERIFY( ranges::equal(v | views::reverse, (int[]){5,3,1}) );
   VERIFY( v.pred()(3) == true );

commit 4cc3b275d310dbf5982544cb88c11630349f414c
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed Feb 19 12:26:19 2020 +0000

    libstdc++: Remove converting constructors from views (LWG 3280)
    
            * include/std/ranges (filter_view, transform_view, take_view)
            (join_view, split_view, reverse_view): Remove commented-out converting
            constructors (LWG 3280).

diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index 5408a89c7fb..9ccba4345d5 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,5 +1,9 @@ 
 2020-02-19  Jonathan Wakely  <jwakely@redhat.com>
 
+	* include/std/ranges (filter_view, transform_view, take_view)
+	(join_view, split_view, reverse_view): Remove commented-out converting
+	constructors (LWG 3280).
+
 	* include/std/memory (uninitialized_construct_using_allocator): Use
 	std::construct_at (LWG 3321).
 
diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 4bfda88c319..cf4c19ffaab 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -1470,17 +1470,6 @@  namespace views
 	: _M_base(std::move(__base)), _M_pred(std::move(__pred))
       { }
 
-      /* XXX: P3280 removes this constructor
-      template<input_range _Range>
-	requires viewable_range<_Range>
-	  && constructible_from<_Vp, all_view<_Range>>
-	constexpr
-	filter_view(_Range&& __r, _Pred __pred)
-	  : _M_base(views::all(std::forward<_Range>(__r))),
-	    _M_pred(std::move(__pred))
-	{ }
-      */
-
       constexpr _Vp
       base() const& requires copy_constructible<_Vp>
       { return _M_base; }
@@ -1799,17 +1788,6 @@  namespace views
 	: _M_base(std::move(__base)), _M_fun(std::move(__fun))
       { }
 
-      /* XXX: P3280 removes this constructor
-      template<input_range _Range>
-	requires viewable_range<_Range>
-	  && constructible_from<_Vp, all_view<_Range>>
-	constexpr
-	transform_view(_Range&& __r, _Fp __fun)
-	  : _M_base(views::all(std::forward<_Range>(__r)))
-	{
-	}
-	*/
-
       constexpr _Vp
       base() const& requires copy_constructible<_Vp>
       { return _M_base ; }
@@ -1915,15 +1893,6 @@  namespace views
 	: _M_base(std::move(base)), _M_count(std::move(__count))
       { }
 
-      /* XXX: P3280 removes this constructor
-      template<viewable_range _Range>
-	requires constructible_from<_Vp, all_view<_Range>>
-      constexpr
-      take_view(_Range&& __r, range_difference_t<_Vp> __count)
-	: _M_base(views::all(std::forward<_Range>(__r))), _M_count(__count)
-      { }
-      */
-
       constexpr _Vp
       base() const& requires copy_constructible<_Vp>
       { return _M_base; }
@@ -2491,16 +2460,6 @@  namespace views
 	: _M_base(std::move(__base))
       { }
 
-      /* XXX: P3280 removes this constructor
-      template<input_range _Range>
-	requires viewable_range<_Range>
-	  && constructible_from<_Vp, all_view<_Range>>
-      constexpr explicit
-      join_view(_Range&& __r)
-	: _M_base(views::all(std::forward<_Range>(__r)))
-      { }
-      */
-
       constexpr _Vp
       base() const& requires copy_constructible<_Vp>
       { return _M_base; }
@@ -2878,17 +2837,6 @@  namespace views
 	: _M_base(std::move(__base)), _M_pattern(std::move(__pattern))
       { }
 
-      /* XXX: P3280 removes this constructor
-      template<input_range _Range, forward_range _Pred>
-	requires constructible_from<_Vp, all_view<_Range>>
-	  && constructible_from<_Pattern, all_view<_Pred>>
-	constexpr
-	split_view(_Range&& __r, _Pred&& __p)
-	  : _M_base(views::all(std::forward<_Range>(__r))),
-	    _M_pattern(views::all(std::forward<_Pred>(__p)))
-      { }
-      */
-
       template<input_range _Range>
 	requires constructible_from<_Vp, all_view<_Range>>
 	  && constructible_from<_Pattern, single_view<range_value_t<_Range>>>
@@ -2994,14 +2942,15 @@  namespace views
 	: _M_base(std::move(__r))
       { }
 
-      /* XXX: P3280 doesn't remove this constructor, but I think it should?
+      /* XXX: LWG 3280 didn't remove this constructor, but I think it should?
       template<viewable_range _Range>
-	requires (!common_range<_Range>) && constructible_from<_Vp, all_view<_Range>>
+	requires (!common_range<_Range>)
+	  && constructible_from<_Vp, all_view<_Range>>
 	constexpr explicit
 	common_view(_Range&& __r)
 	  : _M_base(views::all(std::forward<_Range>(__r)))
 	{ }
-	*/
+      */
 
       constexpr _Vp
       base() const& requires copy_constructible<_Vp>
@@ -3092,15 +3041,6 @@  namespace views
 	: _M_base(std::move(__r))
 	{ }
 
-      /* XXX: P3280 removes this constructor
-      template<viewable_range _Range>
-	requires bidirectional_range<_Range> && constructible_from<_Vp, all_view<_Range>>
-	constexpr explicit
-	reverse_view(_Range&& __r)
-	  : _M_base(views::all(std::forward<_Range>(__r)))
-	{ }
-	*/
-
       constexpr _Vp
       base() const& requires copy_constructible<_Vp>
       { return _M_base; }

commit 5f3641d0c430523d839298a6876f907523811485
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed Feb 19 12:14:54 2020 +0000

    libstdc++: uninitialized_construct_using_allocator should use construct_at (LWG 3321)
    
            * include/std/memory (uninitialized_construct_using_allocator): Use
            std::construct_at (LWG 3321).

diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index eb83c632adc..5408a89c7fb 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,5 +1,8 @@ 
 2020-02-19  Jonathan Wakely  <jwakely@redhat.com>
 
+	* include/std/memory (uninitialized_construct_using_allocator): Use
+	std::construct_at (LWG 3321).
+
 	* include/std/memory_resource (polymorphic_allocator::allocate_bytes)
 	(polymorphic_allocator::allocate_object)
 	(polymorphic_allocator::new_object): Add nodiscard attribute (LWG3304).
diff --git a/libstdc++-v3/include/std/memory b/libstdc++-v3/include/std/memory
index 14aedb70dac..aaee6e42c1a 100644
--- a/libstdc++-v3/include/std/memory
+++ b/libstdc++-v3/include/std/memory
@@ -387,9 +387,10 @@  get_pointer_safety() noexcept { return pointer_safety::relaxed; }
     uninitialized_construct_using_allocator(_Tp* __p, const _Alloc& __a,
 					    _Args&&... __args)
     {
-      void* __vp = const_cast<void*>(static_cast<const volatile void*>(__p));
-      return ::new(__vp) _Tp(std::make_obj_using_allocator<_Tp>(__a,
-	    std::forward<_Args>(__args)...));
+      return std::apply([&](auto&&... __xs) {
+	return std::construct_at(__p, std::forward<decltype(__xs)>(__xs)...);
+      }, std::uses_allocator_construction_args<_Tp>(__a,
+	std::forward<_Args>(__args)...));
     }
 // @}
 

commit 020a03eec7054adb10396067fab69d0ace00aada
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed Feb 19 12:04:53 2020 +0000

    libstdc++: Add nodiscard to polymorphic_allocator members (LWG 3304)
    
            * include/std/memory_resource (polymorphic_allocator::allocate_bytes)
            (polymorphic_allocator::allocate_object)
            (polymorphic_allocator::new_object): Add nodiscard attribute (LWG3304).

diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index 045f0badfae..eb83c632adc 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,5 +1,9 @@ 
 2020-02-19  Jonathan Wakely  <jwakely@redhat.com>
 
+	* include/std/memory_resource (polymorphic_allocator::allocate_bytes)
+	(polymorphic_allocator::allocate_object)
+	(polymorphic_allocator::new_object): Add nodiscard attribute (LWG3304).
+
 	LWG 3379. "safe" in several library names is misleading
 	* include/bits/range_access.h (enable_safe_range): Rename to
 	enable_borrowed_range.
diff --git a/libstdc++-v3/include/std/memory_resource b/libstdc++-v3/include/std/memory_resource
index 70c56d1d7e6..73f77bdcadf 100644
--- a/libstdc++-v3/include/std/memory_resource
+++ b/libstdc++-v3/include/std/memory_resource
@@ -178,7 +178,7 @@  namespace pmr
       { _M_resource->deallocate(__p, __n * sizeof(_Tp), alignof(_Tp)); }
 
 #if __cplusplus > 201703L
-      void*
+      [[nodiscard]] void*
       allocate_bytes(size_t __nbytes,
 		     size_t __alignment = alignof(max_align_t))
       { return _M_resource->allocate(__nbytes, __alignment); }
@@ -189,7 +189,7 @@  namespace pmr
       { _M_resource->deallocate(__p, __nbytes, __alignment); }
 
       template<typename _Up>
-	_Up*
+	[[nodiscard]] _Up*
 	allocate_object(size_t __n = 1)
 	{
 	  if ((__detail::__int_limits<size_t>::max() / sizeof(_Up)) < __n)
@@ -204,7 +204,7 @@  namespace pmr
 	{ deallocate_bytes(__p, __n * sizeof(_Up), alignof(_Up)); }
 
       template<typename _Up, typename... _CtorArgs>
-	_Up*
+	[[nodiscard]] _Up*
 	new_object(_CtorArgs&&... __ctor_args)
 	{
 	  _Up* __p = allocate_object<_Up>();

commit 15411a6453444ef49940822380e39e6a1d174fac
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed Feb 19 11:54:19 2020 +0000

    libstdc++: "safe" in several library names is misleading (LWG 3379)
    
            * include/bits/range_access.h (enable_safe_range): Rename to
            enable_borrowed_range.
            (__detail::__maybe_safe_range): Rename to __maybe_borrowed_range.
            (safe_range): Rename to borrowed_range.
            * include/bits/ranges_algo.h: Adjust to use new names.
            * include/bits/ranges_algobase.h: Likewise.
            * include/bits/ranges_uninitialized.h: Likewise.
            * include/std/ranges: Likewise.
            (safe_iterator_t): Rename to borrowed_iterator_t.
            (safe_subrange_t): Rename to borrowed_subrange_t.
            * include/std/span: Adjust to use new names.
            * include/std/string_view: Likewise.
            * include/experimental/string_view: Likewise.
            * testsuite/std/ranges/access/begin.cc: Likewise.
            * testsuite/std/ranges/access/cbegin.cc: Likewise.
            * testsuite/std/ranges/access/cdata.cc: Likewise.
            * testsuite/std/ranges/access/cend.cc: Likewise.
            * testsuite/std/ranges/access/crbegin.cc: Likewise.
            * testsuite/std/ranges/access/crend.cc: Likewise.
            * testsuite/std/ranges/access/data.cc: Likewise.
            * testsuite/std/ranges/access/end.cc: Likewise.
            * testsuite/std/ranges/access/rbegin.cc: Likewise.
            * testsuite/std/ranges/access/rend.cc: Likewise.
            * testsuite/std/ranges/safe_range.cc: Likewise.
            * testsuite/std/ranges/safe_range_types.cc: Likewise.
            * testsuite/util/testsuite_iterators.h: Likewise.

diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index f69507d667f..045f0badfae 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,5 +1,33 @@ 
 2020-02-19  Jonathan Wakely  <jwakely@redhat.com>
 
+	LWG 3379. "safe" in several library names is misleading
+	* include/bits/range_access.h (enable_safe_range): Rename to
+	enable_borrowed_range.
+	(__detail::__maybe_safe_range): Rename to __maybe_borrowed_range.
+	(safe_range): Rename to borrowed_range.
+	* include/bits/ranges_algo.h: Adjust to use new names.
+	* include/bits/ranges_algobase.h: Likewise.
+	* include/bits/ranges_uninitialized.h: Likewise.
+	* include/std/ranges: Likewise.
+	(safe_iterator_t): Rename to borrowed_iterator_t.
+	(safe_subrange_t): Rename to borrowed_subrange_t.
+	* include/std/span: Adjust to use new names.
+	* include/std/string_view: Likewise.
+	* include/experimental/string_view: Likewise.
+	* testsuite/std/ranges/access/begin.cc: Likewise.
+	* testsuite/std/ranges/access/cbegin.cc: Likewise.
+	* testsuite/std/ranges/access/cdata.cc: Likewise.
+	* testsuite/std/ranges/access/cend.cc: Likewise.
+	* testsuite/std/ranges/access/crbegin.cc: Likewise.
+	* testsuite/std/ranges/access/crend.cc: Likewise.
+	* testsuite/std/ranges/access/data.cc: Likewise.
+	* testsuite/std/ranges/access/end.cc: Likewise.
+	* testsuite/std/ranges/access/rbegin.cc: Likewise.
+	* testsuite/std/ranges/access/rend.cc: Likewise.
+	* testsuite/std/ranges/safe_range.cc: Likewise.
+	* testsuite/std/ranges/safe_range_types.cc: Likewise.
+	* testsuite/util/testsuite_iterators.h: Likewise.
+
 	* include/std/ranges (tuple_element<0, const subrange<I, S, K>>)
 	(tuple_element<1, const subrange<I, S, K>>): Add partial
 	specializations (LWG 3398).
diff --git a/libstdc++-v3/include/bits/range_access.h b/libstdc++-v3/include/bits/range_access.h
index 8bac0efc6ed..e2a2c28c7d2 100644
--- a/libstdc++-v3/include/bits/range_access.h
+++ b/libstdc++-v3/include/bits/range_access.h
@@ -344,7 +344,7 @@  namespace ranges
     inline constexpr bool disable_sized_range = false;
 
   template<typename _Tp>
-    inline constexpr bool enable_safe_range = false;
+    inline constexpr bool enable_borrowed_range = false;
 
   namespace __detail
   {
@@ -357,16 +357,17 @@  namespace ranges
       using __make_unsigned_like_t
 	= conditional_t<_MaxDiff, __max_size_type, make_unsigned_t<_Tp>>;
 
-    // Part of the constraints of ranges::safe_range
+    // Part of the constraints of ranges::borrowed_range
     template<typename _Tp>
-      concept __maybe_safe_range
-	= is_lvalue_reference_v<_Tp> || enable_safe_range<remove_cvref_t<_Tp>>;
+      concept __maybe_borrowed_range
+	= is_lvalue_reference_v<_Tp>
+	  || enable_borrowed_range<remove_cvref_t<_Tp>>;
 
   } // namespace __detail
 
   namespace __cust_access
   {
-    using std::ranges::__detail::__maybe_safe_range;
+    using std::ranges::__detail::__maybe_borrowed_range;
     using std::__detail::__class_or_enum;
 
     template<typename _Tp>
@@ -407,7 +408,7 @@  namespace ranges
 	}
 
     public:
-      template<__maybe_safe_range _Tp>
+      template<__maybe_borrowed_range _Tp>
 	requires is_array_v<remove_reference_t<_Tp>> || __member_begin<_Tp>
 	  || __adl_begin<_Tp>
 	constexpr auto
@@ -459,7 +460,7 @@  namespace ranges
 	}
 
     public:
-      template<__maybe_safe_range _Tp>
+      template<__maybe_borrowed_range _Tp>
 	requires is_array_v<remove_reference_t<_Tp>> || __member_end<_Tp>
 	|| __adl_end<_Tp>
 	constexpr auto
@@ -559,7 +560,7 @@  namespace ranges
 	}
 
     public:
-      template<__maybe_safe_range _Tp>
+      template<__maybe_borrowed_range _Tp>
 	requires __member_rbegin<_Tp> || __adl_rbegin<_Tp> || __reversable<_Tp>
 	constexpr auto
 	operator()(_Tp&& __t) const
@@ -616,7 +617,7 @@  namespace ranges
 	}
 
     public:
-      template<__maybe_safe_range _Tp>
+      template<__maybe_borrowed_range _Tp>
 	requires __member_rend<_Tp> || __adl_rend<_Tp> || __reversable<_Tp>
 	constexpr auto
 	operator()(_Tp&& __t) const
@@ -875,9 +876,10 @@  namespace ranges
 	ranges::end(__t);
       };
 
-  /// [range.range] The safe_range concept.
+  /// [range.range] The borrowed_range concept.
   template<typename _Tp>
-    concept safe_range = range<_Tp> && __detail::__maybe_safe_range<_Tp>;
+    concept borrowed_range
+      = range<_Tp> && __detail::__maybe_borrowed_range<_Tp>;
 
   template<range _Range>
     using iterator_t = decltype(ranges::begin(std::declval<_Range&>()));
diff --git a/libstdc++-v3/include/bits/ranges_algo.h b/libstdc++-v3/include/bits/ranges_algo.h
index a69181e12cb..7de1072abf0 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -190,7 +190,7 @@  namespace ranges
     template<input_range _Range, typename _Proj = identity,
 	     indirectly_unary_invocable<projected<iterator_t<_Range>, _Proj>>
 	       _Fun>
-      constexpr for_each_result<safe_iterator_t<_Range>, _Fun>
+      constexpr for_each_result<borrowed_iterator_t<_Range>, _Fun>
       operator()(_Range&& __r, _Fun __f, _Proj __proj = {}) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r),
@@ -253,7 +253,7 @@  namespace ranges
       requires indirect_binary_predicate<ranges::equal_to,
 					 projected<iterator_t<_Range>, _Proj>,
 					 const _Tp*>
-      constexpr safe_iterator_t<_Range>
+      constexpr borrowed_iterator_t<_Range>
       operator()(_Range&& __r, const _Tp& __value, _Proj __proj = {}) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r),
@@ -281,7 +281,7 @@  namespace ranges
     template<input_range _Range, typename _Proj = identity,
 	     indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>>
 	       _Pred>
-      constexpr safe_iterator_t<_Range>
+      constexpr borrowed_iterator_t<_Range>
       operator()(_Range&& __r, _Pred __pred, _Proj __proj = {}) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r),
@@ -309,7 +309,7 @@  namespace ranges
     template<input_range _Range, typename _Proj = identity,
 	     indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>>
 	       _Pred>
-      constexpr safe_iterator_t<_Range>
+      constexpr borrowed_iterator_t<_Range>
       operator()(_Range&& __r, _Pred __pred, _Proj __proj = {}) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r),
@@ -345,7 +345,7 @@  namespace ranges
 	     typename _Proj1 = identity, typename _Proj2 = identity>
       requires indirectly_comparable<iterator_t<_Range1>, iterator_t<_Range2>,
 				     _Pred, _Proj1, _Proj2>
-      constexpr safe_iterator_t<_Range1>
+      constexpr borrowed_iterator_t<_Range1>
       operator()(_Range1&& __r1, _Range2&& __r2, _Pred __pred = {},
 		 _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const
       {
@@ -536,7 +536,7 @@  namespace ranges
 	     typename _Proj1 = identity, typename _Proj2 = identity>
       requires indirectly_comparable<iterator_t<_Range1>, iterator_t<_Range2>,
 				     _Pred, _Proj1, _Proj2>
-      constexpr safe_subrange_t<_Range1>
+      constexpr borrowed_subrange_t<_Range1>
       operator()(_Range1&& __r1, _Range2&& __r2, _Pred __pred = {},
 		 _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const
       {
@@ -625,7 +625,7 @@  namespace ranges
 	     typename _Pred = ranges::equal_to, typename _Proj = identity>
       requires indirectly_comparable<iterator_t<_Range>, const _Tp*,
 				     _Pred, _Proj>
-      constexpr safe_subrange_t<_Range>
+      constexpr borrowed_subrange_t<_Range>
       operator()(_Range&& __r, range_difference_t<_Range> __count,
 	       const _Tp& __value, _Pred __pred = {}, _Proj __proj = {}) const
       {
@@ -701,7 +701,7 @@  namespace ranges
 	     typename _Proj1 = identity, typename _Proj2 = identity>
       requires indirectly_comparable<iterator_t<_Range1>, iterator_t<_Range2>,
 				     _Pred, _Proj1, _Proj2>
-      constexpr safe_subrange_t<_Range1>
+      constexpr borrowed_subrange_t<_Range1>
       operator()(_Range1&& __r1, _Range2&& __r2, _Pred __pred = {},
 		 _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const
       {
@@ -742,7 +742,7 @@  namespace ranges
 	     indirect_binary_predicate<
 	       projected<iterator_t<_Range>, _Proj>,
 	       projected<iterator_t<_Range>, _Proj>> _Pred = ranges::equal_to>
-      constexpr safe_iterator_t<_Range>
+      constexpr borrowed_iterator_t<_Range>
       operator()(_Range&& __r, _Pred __pred = {}, _Proj __proj = {}) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r),
@@ -866,7 +866,7 @@  namespace ranges
 	     indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>>
 	       _Pred>
       requires indirectly_copyable<iterator_t<_Range>, _Out>
-      constexpr copy_if_result<safe_iterator_t<_Range>, _Out>
+      constexpr copy_if_result<borrowed_iterator_t<_Range>, _Out>
       operator()(_Range&& __r, _Out __result,
 		 _Pred __pred, _Proj __proj = {}) const
       {
@@ -898,8 +898,8 @@  namespace ranges
 
     template<input_range _Range1, input_range _Range2>
       requires indirectly_swappable<iterator_t<_Range1>, iterator_t<_Range2>>
-      constexpr swap_ranges_result<safe_iterator_t<_Range1>,
-				   safe_iterator_t<_Range2>>
+      constexpr swap_ranges_result<borrowed_iterator_t<_Range1>,
+				   borrowed_iterator_t<_Range2>>
       operator()(_Range1&& __r1, _Range2&& __r2) const
       {
 	return (*this)(ranges::begin(__r1), ranges::end(__r1),
@@ -961,7 +961,7 @@  namespace ranges
       requires indirectly_writable<_Out,
 				   indirect_result_t<_Fp&,
 				     projected<iterator_t<_Range>, _Proj>>>
-      constexpr unary_transform_result<safe_iterator_t<_Range>, _Out>
+      constexpr unary_transform_result<borrowed_iterator_t<_Range>, _Out>
       operator()(_Range&& __r, _Out __result, _Fp __op, _Proj __proj = {}) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r),
@@ -998,8 +998,8 @@  namespace ranges
 				   indirect_result_t<_Fp&,
 				     projected<iterator_t<_Range1>, _Proj1>,
 				     projected<iterator_t<_Range2>, _Proj2>>>
-      constexpr binary_transform_result<safe_iterator_t<_Range1>,
-					safe_iterator_t<_Range2>, _Out>
+      constexpr binary_transform_result<borrowed_iterator_t<_Range1>,
+					borrowed_iterator_t<_Range2>, _Out>
       operator()(_Range1&& __r1, _Range2&& __r2, _Out __result, _Fp __binary_op,
 		 _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const
       {
@@ -1036,7 +1036,7 @@  namespace ranges
 	&& indirect_binary_predicate<ranges::equal_to,
 				     projected<iterator_t<_Range>, _Proj>,
 				     const _Tp1*>
-      constexpr safe_iterator_t<_Range>
+      constexpr borrowed_iterator_t<_Range>
       operator()(_Range&& __r,
 		 const _Tp1& __old_value, const _Tp2& __new_value,
 		 _Proj __proj = {}) const
@@ -1068,7 +1068,7 @@  namespace ranges
 	     indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>>
 	       _Pred>
       requires indirectly_writable<iterator_t<_Range>, const _Tp&>
-      constexpr safe_iterator_t<_Range>
+      constexpr borrowed_iterator_t<_Range>
       operator()(_Range&& __r,
 		 _Pred __pred, const _Tp& __new_value, _Proj __proj = {}) const
       {
@@ -1109,7 +1109,7 @@  namespace ranges
 	&& indirect_binary_predicate<ranges::equal_to,
 				     projected<iterator_t<_Range>, _Proj>,
 				     const _Tp1*>
-      constexpr replace_copy_result<safe_iterator_t<_Range>, _Out>
+      constexpr replace_copy_result<borrowed_iterator_t<_Range>, _Out>
       operator()(_Range&& __r, _Out __result,
 		 const _Tp1& __old_value, const _Tp2& __new_value,
 		 _Proj __proj = {}) const
@@ -1150,7 +1150,7 @@  namespace ranges
 	     indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>>
 	       _Pred>
       requires indirectly_copyable<iterator_t<_Range>, _Out>
-      constexpr replace_copy_if_result<safe_iterator_t<_Range>, _Out>
+      constexpr replace_copy_if_result<borrowed_iterator_t<_Range>, _Out>
       operator()(_Range&& __r, _Out __result,
 		 _Pred __pred, const _Tp& __new_value, _Proj __proj = {}) const
       {
@@ -1194,7 +1194,7 @@  namespace ranges
 
     template<typename _Range, copy_constructible _Fp>
       requires invocable<_Fp&> && output_range<_Range, invoke_result_t<_Fp&>>
-      constexpr safe_iterator_t<_Range>
+      constexpr borrowed_iterator_t<_Range>
       operator()(_Range&& __r, _Fp __gen) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r), std::move(__gen));
@@ -1232,7 +1232,7 @@  namespace ranges
 	     indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>>
 	       _Pred>
       requires permutable<iterator_t<_Range>>
-      constexpr safe_subrange_t<_Range>
+      constexpr borrowed_subrange_t<_Range>
       operator()(_Range&& __r, _Pred __pred, _Proj __proj = {}) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r),
@@ -1265,7 +1265,7 @@  namespace ranges
 	&& indirect_binary_predicate<ranges::equal_to,
 				     projected<iterator_t<_Range>, _Proj>,
 				     const _Tp*>
-      constexpr safe_subrange_t<_Range>
+      constexpr borrowed_subrange_t<_Range>
       operator()(_Range&& __r, const _Tp& __value, _Proj __proj = {}) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r),
@@ -1302,7 +1302,7 @@  namespace ranges
 	     indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>>
 	       _Pred>
       requires indirectly_copyable<iterator_t<_Range>, _Out>
-      constexpr remove_copy_if_result<safe_iterator_t<_Range>, _Out>
+      constexpr remove_copy_if_result<borrowed_iterator_t<_Range>, _Out>
       operator()(_Range&& __r, _Out __result,
 		 _Pred __pred, _Proj __proj = {}) const
       {
@@ -1344,7 +1344,7 @@  namespace ranges
 	&& indirect_binary_predicate<ranges::equal_to,
 				     projected<iterator_t<_Range>, _Proj>,
 				     const _Tp*>
-      constexpr remove_copy_result<safe_iterator_t<_Range>, _Out>
+      constexpr remove_copy_result<borrowed_iterator_t<_Range>, _Out>
       operator()(_Range&& __r, _Out __result,
 		 const _Tp& __value, _Proj __proj = {}) const
       {
@@ -1383,7 +1383,7 @@  namespace ranges
 	     indirect_equivalence_relation<
 	       projected<iterator_t<_Range>, _Proj>> _Comp = ranges::equal_to>
       requires permutable<iterator_t<_Range>>
-      constexpr safe_subrange_t<_Range>
+      constexpr borrowed_subrange_t<_Range>
       operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r),
@@ -1467,7 +1467,7 @@  namespace ranges
 	    || (input_iterator<_Out>
 		&& same_as<range_value_t<_Range>, iter_value_t<_Out>>)
 	    || indirectly_copyable_storable<iterator_t<_Range>, _Out>)
-      constexpr unique_copy_result<safe_iterator_t<_Range>, _Out>
+      constexpr unique_copy_result<borrowed_iterator_t<_Range>, _Out>
       operator()(_Range&& __r, _Out __result,
 		 _Comp __comp = {}, _Proj __proj = {}) const
       {
@@ -1519,7 +1519,7 @@  namespace ranges
 
     template<bidirectional_range _Range>
       requires permutable<iterator_t<_Range>>
-      constexpr safe_iterator_t<_Range>
+      constexpr borrowed_iterator_t<_Range>
       operator()(_Range&& __r) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r));
@@ -1552,7 +1552,7 @@  namespace ranges
 
     template<bidirectional_range _Range, weakly_incrementable _Out>
       requires indirectly_copyable<iterator_t<_Range>, _Out>
-      constexpr reverse_copy_result<safe_iterator_t<_Range>, _Out>
+      constexpr reverse_copy_result<borrowed_iterator_t<_Range>, _Out>
       operator()(_Range&& __r, _Out __result) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r),
@@ -1699,7 +1699,7 @@  namespace ranges
 
     template<forward_range _Range>
       requires permutable<iterator_t<_Range>>
-      constexpr safe_subrange_t<_Range>
+      constexpr borrowed_subrange_t<_Range>
       operator()(_Range&& __r, iterator_t<_Range> __middle) const
       {
 	return (*this)(ranges::begin(__r), std::move(__middle),
@@ -1732,7 +1732,7 @@  namespace ranges
 
     template<forward_range _Range, weakly_incrementable _Out>
       requires indirectly_copyable<iterator_t<_Range>, _Out>
-      constexpr rotate_copy_result<safe_iterator_t<_Range>, _Out>
+      constexpr rotate_copy_result<borrowed_iterator_t<_Range>, _Out>
       operator()(_Range&& __r, iterator_t<_Range> __middle, _Out __result) const
       {
 	return (*this)(ranges::begin(__r), std::move(__middle),
@@ -1818,7 +1818,7 @@  namespace ranges
     template<random_access_range _Range, typename _Gen>
       requires permutable<iterator_t<_Range>>
 	&& uniform_random_bit_generator<remove_reference_t<_Gen>>
-      safe_iterator_t<_Range>
+      borrowed_iterator_t<_Range>
       operator()(_Range&& __r, _Gen&& __g) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r),
@@ -1847,7 +1847,7 @@  namespace ranges
     template<random_access_range _Range,
 	     typename _Comp = ranges::less, typename _Proj = identity>
       requires sortable<iterator_t<_Range>, _Comp, _Proj>
-      constexpr safe_iterator_t<_Range>
+      constexpr borrowed_iterator_t<_Range>
       operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r),
@@ -1875,7 +1875,7 @@  namespace ranges
     template<random_access_range _Range,
 	     typename _Comp = ranges::less, typename _Proj = identity>
       requires sortable<iterator_t<_Range>, _Comp, _Proj>
-      constexpr safe_iterator_t<_Range>
+      constexpr borrowed_iterator_t<_Range>
       operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r),
@@ -1903,7 +1903,7 @@  namespace ranges
     template<random_access_range _Range,
 	     typename _Comp = ranges::less, typename _Proj = identity>
       requires sortable<iterator_t<_Range>, _Comp, _Proj>
-      constexpr safe_iterator_t<_Range>
+      constexpr borrowed_iterator_t<_Range>
       operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r),
@@ -1931,7 +1931,7 @@  namespace ranges
     template<random_access_range _Range,
 	     typename _Comp = ranges::less, typename _Proj = identity>
       requires sortable<iterator_t<_Range>, _Comp, _Proj>
-      constexpr safe_iterator_t<_Range>
+      constexpr borrowed_iterator_t<_Range>
       operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r),
@@ -1968,7 +1968,7 @@  namespace ranges
 	     typename _Proj = identity,
 	     indirect_strict_weak_order<projected<iterator_t<_Range>, _Proj>>
 	       _Comp = ranges::less>
-      constexpr safe_iterator_t<_Range>
+      constexpr borrowed_iterator_t<_Range>
       operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r),
@@ -2026,7 +2026,7 @@  namespace ranges
     template<random_access_range _Range,
 	     typename _Comp = ranges::less, typename _Proj = identity>
       requires sortable<iterator_t<_Range>, _Comp, _Proj>
-      constexpr safe_iterator_t<_Range>
+      constexpr borrowed_iterator_t<_Range>
       operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r),
@@ -2054,7 +2054,7 @@  namespace ranges
     template<random_access_range _Range,
 	     typename _Comp = ranges::less, typename _Proj = identity>
       requires sortable<iterator_t<_Range>, _Comp, _Proj>
-      safe_iterator_t<_Range>
+      borrowed_iterator_t<_Range>
       operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r),
@@ -2095,7 +2095,7 @@  namespace ranges
     template<random_access_range _Range,
 	     typename _Comp = ranges::less, typename _Proj = identity>
       requires sortable<iterator_t<_Range>, _Comp, _Proj>
-      constexpr safe_iterator_t<_Range>
+      constexpr borrowed_iterator_t<_Range>
       operator()(_Range&& __r, iterator_t<_Range> __middle,
 		 _Comp __comp = {}, _Proj __proj = {}) const
       {
@@ -2168,8 +2168,8 @@  namespace ranges
 	&& indirect_strict_weak_order<_Comp,
 				      projected<iterator_t<_Range1>, _Proj1>,
 				      projected<iterator_t<_Range2>, _Proj2>>
-      constexpr partial_sort_copy_result<safe_iterator_t<_Range1>,
-					 safe_iterator_t<_Range2>>
+      constexpr partial_sort_copy_result<borrowed_iterator_t<_Range1>,
+					 borrowed_iterator_t<_Range2>>
       operator()(_Range1&& __r, _Range2&& __out, _Comp __comp = {},
 		 _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const
       {
@@ -2207,7 +2207,7 @@  namespace ranges
     template<forward_range _Range, typename _Proj = identity,
 	     indirect_strict_weak_order<projected<iterator_t<_Range>, _Proj>>
 	       _Comp = ranges::less>
-      constexpr safe_iterator_t<_Range>
+      constexpr borrowed_iterator_t<_Range>
       operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r),
@@ -2270,7 +2270,7 @@  namespace ranges
     template<random_access_range _Range,
 	     typename _Comp = ranges::less, typename _Proj = identity>
       requires sortable<iterator_t<_Range>, _Comp, _Proj>
-      constexpr safe_iterator_t<_Range>
+      constexpr borrowed_iterator_t<_Range>
       operator()(_Range&& __r, iterator_t<_Range> __nth,
 		 _Comp __comp = {}, _Proj __proj = {}) const
       {
@@ -2314,7 +2314,7 @@  namespace ranges
 	     indirect_strict_weak_order<const _Tp*,
 					projected<iterator_t<_Range>, _Proj>>
 	       _Comp = ranges::less>
-      constexpr safe_iterator_t<_Range>
+      constexpr borrowed_iterator_t<_Range>
       operator()(_Range&& __r,
 		 const _Tp& __value, _Comp __comp = {}, _Proj __proj = {}) const
       {
@@ -2358,7 +2358,7 @@  namespace ranges
 	     indirect_strict_weak_order<const _Tp*,
 					projected<iterator_t<_Range>, _Proj>>
 	       _Comp = ranges::less>
-      constexpr safe_iterator_t<_Range>
+      constexpr borrowed_iterator_t<_Range>
       operator()(_Range&& __r,
 		 const _Tp& __value, _Comp __comp = {}, _Proj __proj = {}) const
       {
@@ -2418,7 +2418,7 @@  namespace ranges
 	     indirect_strict_weak_order<const _Tp*,
 					projected<iterator_t<_Range>, _Proj>>
 	       _Comp = ranges::less>
-      constexpr safe_subrange_t<_Range>
+      constexpr borrowed_subrange_t<_Range>
       operator()(_Range&& __r, const _Tp& __value,
 		 _Comp __comp = {}, _Proj __proj = {}) const
       {
@@ -2554,7 +2554,7 @@  namespace ranges
 	     indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>>
 	       _Pred>
       requires permutable<iterator_t<_Range>>
-      constexpr safe_subrange_t<_Range>
+      constexpr borrowed_subrange_t<_Range>
       operator()(_Range&& __r, _Pred __pred, _Proj __proj = {}) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r),
@@ -2585,7 +2585,7 @@  namespace ranges
 	     indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>>
 	       _Pred>
       requires permutable<iterator_t<_Range>>
-      safe_subrange_t<_Range>
+      borrowed_subrange_t<_Range>
       operator()(_Range&& __r, _Pred __pred, _Proj __proj = {}) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r),
@@ -2658,7 +2658,7 @@  namespace ranges
 	       _Pred>
       requires indirectly_copyable<iterator_t<_Range>, _Out1>
 	&& indirectly_copyable<iterator_t<_Range>, _O2>
-      constexpr partition_copy_result<safe_iterator_t<_Range>, _Out1, _O2>
+      constexpr partition_copy_result<borrowed_iterator_t<_Range>, _Out1, _O2>
       operator()(_Range&& __r, _Out1 out_true, _O2 out_false,
 		 _Pred __pred, _Proj __proj = {}) const
       {
@@ -2701,7 +2701,7 @@  namespace ranges
     template<forward_range _Range, typename _Proj = identity,
 	     indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>>
 	       _Pred>
-      constexpr safe_iterator_t<_Range>
+      constexpr borrowed_iterator_t<_Range>
       operator()(_Range&& __r, _Pred __pred, _Proj __proj = {}) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r),
@@ -2756,8 +2756,8 @@  namespace ranges
 	     typename _Proj1 = identity, typename _Proj2 = identity>
       requires mergeable<iterator_t<_Range1>, iterator_t<_Range2>, _Out,
 			 _Comp, _Proj1, _Proj2>
-      constexpr merge_result<safe_iterator_t<_Range1>,
-			     safe_iterator_t<_Range2>,
+      constexpr merge_result<borrowed_iterator_t<_Range1>,
+			     borrowed_iterator_t<_Range2>,
 			     _Out>
       operator()(_Range1&& __r1, _Range2&& __r2, _Out __result,
 		 _Comp __comp = {},
@@ -2791,7 +2791,7 @@  namespace ranges
     template<bidirectional_range _Range,
 	     typename _Comp = ranges::less, typename _Proj = identity>
       requires sortable<iterator_t<_Range>, _Comp, _Proj>
-      safe_iterator_t<_Range>
+      borrowed_iterator_t<_Range>
       operator()(_Range&& __r, iterator_t<_Range> __middle,
 		 _Comp __comp = {}, _Proj __proj = {}) const
       {
@@ -2906,8 +2906,8 @@  namespace ranges
 	     typename _Proj1 = identity, typename _Proj2 = identity>
       requires mergeable<iterator_t<_Range1>, iterator_t<_Range2>, _Out,
 			 _Comp, _Proj1, _Proj2>
-      constexpr set_union_result<safe_iterator_t<_Range1>,
-				 safe_iterator_t<_Range2>, _Out>
+      constexpr set_union_result<borrowed_iterator_t<_Range1>,
+				 borrowed_iterator_t<_Range2>, _Out>
       operator()(_Range1&& __r1, _Range2&& __r2,
 		 _Out __result, _Comp __comp = {},
 		 _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const
@@ -2964,8 +2964,8 @@  namespace ranges
 	     typename _Proj1 = identity, typename _Proj2 = identity>
       requires mergeable<iterator_t<_Range1>, iterator_t<_Range2>, _Out,
 			 _Comp, _Proj1, _Proj2>
-      constexpr set_intersection_result<safe_iterator_t<_Range1>,
-					safe_iterator_t<_Range2>, _Out>
+      constexpr set_intersection_result<borrowed_iterator_t<_Range1>,
+					borrowed_iterator_t<_Range2>, _Out>
       operator()(_Range1&& __r1, _Range2&& __r2, _Out __result,
 		 _Comp __comp = {},
 		 _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const
@@ -3022,7 +3022,7 @@  namespace ranges
 	     typename _Proj1 = identity, typename _Proj2 = identity>
       requires mergeable<iterator_t<_Range1>, iterator_t<_Range2>, _Out,
 			 _Comp, _Proj1, _Proj2>
-      constexpr set_difference_result<safe_iterator_t<_Range1>, _Out>
+      constexpr set_difference_result<borrowed_iterator_t<_Range1>, _Out>
       operator()(_Range1&& __r1, _Range2&& __r2, _Out __result,
 		 _Comp __comp = {},
 		 _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const
@@ -3088,8 +3088,8 @@  namespace ranges
 	     typename _Proj1 = identity, typename _Proj2 = identity>
       requires mergeable<iterator_t<_Range1>, iterator_t<_Range2>, _Out,
 			 _Comp, _Proj1, _Proj2>
-      constexpr set_symmetric_difference_result<safe_iterator_t<_Range1>,
-						safe_iterator_t<_Range2>,
+      constexpr set_symmetric_difference_result<borrowed_iterator_t<_Range1>,
+						borrowed_iterator_t<_Range2>,
 						_Out>
       operator()(_Range1&& __r1, _Range2&& __r2, _Out __result,
 		 _Comp __comp = {},
@@ -3343,7 +3343,7 @@  namespace ranges
     template<forward_range _Range, typename _Proj = identity,
 	     indirect_strict_weak_order<projected<iterator_t<_Range>, _Proj>>
 	       _Comp = ranges::less>
-      constexpr safe_iterator_t<_Range>
+      constexpr borrowed_iterator_t<_Range>
       operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r),
@@ -3380,7 +3380,7 @@  namespace ranges
     template<forward_range _Range, typename _Proj = identity,
 	     indirect_strict_weak_order<projected<iterator_t<_Range>, _Proj>>
 	       _Comp = ranges::less>
-      constexpr safe_iterator_t<_Range>
+      constexpr borrowed_iterator_t<_Range>
       operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r),
@@ -3425,7 +3425,7 @@  namespace ranges
     template<forward_range _Range, typename _Proj = identity,
 	     indirect_strict_weak_order<projected<iterator_t<_Range>, _Proj>>
 	       _Comp = ranges::less>
-      constexpr minmax_element_result<safe_iterator_t<_Range>>
+      constexpr minmax_element_result<borrowed_iterator_t<_Range>>
       operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r),
@@ -3610,7 +3610,7 @@  namespace ranges
     template<bidirectional_range _Range, typename _Comp = ranges::less,
 	     typename _Proj = identity>
       requires sortable<iterator_t<_Range>, _Comp, _Proj>
-      constexpr next_permutation_result<safe_iterator_t<_Range>>
+      constexpr next_permutation_result<borrowed_iterator_t<_Range>>
       operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r),
@@ -3672,7 +3672,7 @@  namespace ranges
     template<bidirectional_range _Range, typename _Comp = ranges::less,
 	     typename _Proj = identity>
       requires sortable<iterator_t<_Range>, _Comp, _Proj>
-      constexpr prev_permutation_result<safe_iterator_t<_Range>>
+      constexpr prev_permutation_result<borrowed_iterator_t<_Range>>
       operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r),
diff --git a/libstdc++-v3/include/bits/ranges_algobase.h b/libstdc++-v3/include/bits/ranges_algobase.h
index 7424766f053..807822e99c8 100644
--- a/libstdc++-v3/include/bits/ranges_algobase.h
+++ b/libstdc++-v3/include/bits/ranges_algobase.h
@@ -310,7 +310,7 @@  namespace ranges
 
     template<input_range _Range, weakly_incrementable _Out>
       requires indirectly_copyable<iterator_t<_Range>, _Out>
-      constexpr copy_result<safe_iterator_t<_Range>, _Out>
+      constexpr copy_result<borrowed_iterator_t<_Range>, _Out>
       operator()(_Range&& __r, _Out __result) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r),
@@ -335,7 +335,7 @@  namespace ranges
 
     template<input_range _Range, weakly_incrementable _Out>
       requires indirectly_movable<iterator_t<_Range>, _Out>
-      constexpr move_result<safe_iterator_t<_Range>, _Out>
+      constexpr move_result<borrowed_iterator_t<_Range>, _Out>
       operator()(_Range&& __r, _Out __result) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r),
@@ -452,7 +452,7 @@  namespace ranges
 
     template<bidirectional_range _Range, bidirectional_iterator _Iter>
       requires indirectly_copyable<iterator_t<_Range>, _Iter>
-      constexpr copy_backward_result<safe_iterator_t<_Range>, _Iter>
+      constexpr copy_backward_result<borrowed_iterator_t<_Range>, _Iter>
       operator()(_Range&& __r, _Iter __result) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r),
@@ -477,7 +477,7 @@  namespace ranges
 
     template<bidirectional_range _Range, bidirectional_iterator _Iter>
       requires indirectly_movable<iterator_t<_Range>, _Iter>
-      constexpr move_backward_result<safe_iterator_t<_Range>, _Iter>
+      constexpr move_backward_result<borrowed_iterator_t<_Range>, _Iter>
       operator()(_Range&& __r, _Iter __result) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r),
@@ -577,7 +577,7 @@  namespace ranges
       }
 
     template<typename _Tp, output_range<const _Tp&> _Range>
-      constexpr safe_iterator_t<_Range>
+      constexpr borrowed_iterator_t<_Range>
       operator()(_Range&& __r, const _Tp& __value) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r), __value);
diff --git a/libstdc++-v3/include/bits/ranges_uninitialized.h b/libstdc++-v3/include/bits/ranges_uninitialized.h
index 881bf39d5f8..01e1cad646c 100644
--- a/libstdc++-v3/include/bits/ranges_uninitialized.h
+++ b/libstdc++-v3/include/bits/ranges_uninitialized.h
@@ -88,7 +88,7 @@  namespace ranges
 
     template<__detail::__nothrow_input_range _Range>
       requires destructible<range_value_t<_Range>>
-      constexpr safe_iterator_t<_Range>
+      constexpr borrowed_iterator_t<_Range>
       operator()(_Range&& __r) const noexcept;
   };
 
@@ -159,7 +159,7 @@  namespace ranges
 
     template<__detail::__nothrow_forward_range _Range>
       requires default_initializable<range_value_t<_Range>>
-      safe_iterator_t<_Range>
+      borrowed_iterator_t<_Range>
       operator()(_Range&& __r) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r));
@@ -217,7 +217,7 @@  namespace ranges
 
     template<__detail::__nothrow_forward_range _Range>
       requires default_initializable<range_value_t<_Range>>
-      safe_iterator_t<_Range>
+      borrowed_iterator_t<_Range>
       operator()(_Range&& __r) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r));
@@ -290,8 +290,8 @@  namespace ranges
     template<input_range _IRange, __detail::__nothrow_forward_range _ORange>
       requires constructible_from<range_value_t<_ORange>,
 				  range_reference_t<_IRange>>
-      uninitialized_copy_result<safe_iterator_t<_IRange>,
-				safe_iterator_t<_ORange>>
+      uninitialized_copy_result<borrowed_iterator_t<_IRange>,
+				borrowed_iterator_t<_ORange>>
       operator()(_IRange&& __inr, _ORange&& __outr) const
       {
 	return (*this)(ranges::begin(__inr), ranges::end(__inr),
@@ -377,8 +377,8 @@  namespace ranges
     template<input_range _IRange, __detail::__nothrow_forward_range _ORange>
       requires constructible_from<range_value_t<_ORange>,
 	       range_rvalue_reference_t<_IRange>>
-      uninitialized_move_result<safe_iterator_t<_IRange>,
-				safe_iterator_t<_ORange>>
+      uninitialized_move_result<borrowed_iterator_t<_IRange>,
+				borrowed_iterator_t<_ORange>>
       operator()(_IRange&& __inr, _ORange&& __outr) const
       {
 	return (*this)(ranges::begin(__inr), ranges::end(__inr),
@@ -450,7 +450,7 @@  namespace ranges
 
     template<__detail::__nothrow_forward_range _Range, typename _Tp>
       requires constructible_from<range_value_t<_Range>, const _Tp&>
-      safe_iterator_t<_Range>
+      borrowed_iterator_t<_Range>
       operator()(_Range&& __r, const _Tp& __x) const
       {
 	return (*this)(ranges::begin(__r), ranges::end(__r), __x);
@@ -531,7 +531,7 @@  namespace ranges
 
   template<__detail::__nothrow_input_range _Range>
     requires destructible<range_value_t<_Range>>
-    constexpr safe_iterator_t<_Range>
+    constexpr borrowed_iterator_t<_Range>
     __destroy_fn::operator()(_Range&& __r) const noexcept
     {
       return (*this)(ranges::begin(__r), ranges::end(__r));
diff --git a/libstdc++-v3/include/experimental/string_view b/libstdc++-v3/include/experimental/string_view
index 4d4615c94e7..439650154ae 100644
--- a/libstdc++-v3/include/experimental/string_view
+++ b/libstdc++-v3/include/experimental/string_view
@@ -694,11 +694,11 @@  namespace experimental
 #if __cpp_lib_concepts
   namespace ranges
   {
-    template<typename> extern inline const bool enable_safe_range;
-    // Opt-in to safe_range concept
+    template<typename> extern inline const bool enable_borrowed_range;
+    // Opt-in to borrowed_range concept
     template<typename _CharT, typename _Traits>
       inline constexpr bool
-	enable_safe_range<experimental::basic_string_view<_CharT, _Traits>>
+	enable_borrowed_range<experimental::basic_string_view<_CharT, _Traits>>
 	  = true;
   }
 #endif
diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 4e50206fb61..4bfda88c319 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -93,7 +93,7 @@  namespace ranges
   /// A range which can be safely converted to a view.
   template<typename _Tp>
     concept viewable_range = range<_Tp>
-      && (safe_range<_Tp> || view<remove_cvref_t<_Tp>>);
+      && (borrowed_range<_Tp> || view<remove_cvref_t<_Tp>>);
 
   namespace __detail
   {
@@ -294,7 +294,7 @@  namespace ranges
       }
 
       template<__detail::__not_same_as<subrange> _Rng>
-	requires safe_range<_Rng>
+	requires borrowed_range<_Rng>
 	  && convertible_to<iterator_t<_Rng>, _It>
 	  && convertible_to<sentinel_t<_Rng>, _Sent>
 	constexpr
@@ -305,7 +305,7 @@  namespace ranges
 	    _M_size._M_size = ranges::size(__r);
 	}
 
-      template<safe_range _Rng>
+      template<borrowed_range _Rng>
 	requires convertible_to<iterator_t<_Rng>, _It>
 	  && convertible_to<sentinel_t<_Rng>, _Sent>
 	constexpr
@@ -417,14 +417,14 @@  namespace ranges
       -> subrange<tuple_element_t<0, _Pr>, tuple_element_t<1, _Pr>,
 		  subrange_kind::sized>;
 
-  template<safe_range _Rng>
+  template<borrowed_range _Rng>
     subrange(_Rng&&)
       -> subrange<iterator_t<_Rng>, sentinel_t<_Rng>,
 		 (sized_range<_Rng>
 		  || sized_sentinel_for<sentinel_t<_Rng>, iterator_t<_Rng>>)
 		 ? subrange_kind::sized : subrange_kind::unsized>;
 
-  template<safe_range _Rng>
+  template<borrowed_range _Rng>
     subrange(_Rng&&,
 	     __detail::__make_unsigned_like_t<range_difference_t<_Rng>>)
       -> subrange<iterator_t<_Rng>, sentinel_t<_Rng>, subrange_kind::sized>;
@@ -454,7 +454,7 @@  namespace ranges
   template<input_or_output_iterator _It, sentinel_for<_It> _Sent,
 	   subrange_kind _Kind>
     inline constexpr bool
-      enable_safe_range<subrange<_It, _Sent, _Kind>> = true;
+      enable_borrowed_range<subrange<_It, _Sent, _Kind>> = true;
 
 } // namespace ranges
 
@@ -471,14 +471,14 @@  namespace ranges
   };
 
   template<range _Range>
-    using safe_iterator_t = conditional_t<safe_range<_Range>,
-					  iterator_t<_Range>,
-					  dangling>;
+    using borrowed_iterator_t = conditional_t<borrowed_range<_Range>,
+					      iterator_t<_Range>,
+					      dangling>;
 
   template<range _Range>
-    using safe_subrange_t = conditional_t<safe_range<_Range>,
-					  subrange<iterator_t<_Range>>,
-					  dangling>;
+    using borrowed_subrange_t = conditional_t<borrowed_range<_Range>,
+					      subrange<iterator_t<_Range>>,
+					      dangling>;
 
   template<typename _Tp> requires is_object_v<_Tp>
     class empty_view
@@ -493,7 +493,7 @@  namespace ranges
     };
 
   template<typename _Tp>
-    inline constexpr bool enable_safe_range<empty_view<_Tp>> = true;
+    inline constexpr bool enable_borrowed_range<empty_view<_Tp>> = true;
 
   namespace __detail
   {
@@ -919,7 +919,8 @@  namespace ranges
     iota_view(_Winc, _Bound) -> iota_view<_Winc, _Bound>;
 
   template<weakly_incrementable _Winc, semiregular _Bound>
-    inline constexpr bool enable_safe_range<iota_view<_Winc, _Bound>> = true;
+    inline constexpr bool
+      enable_borrowed_range<iota_view<_Winc, _Bound>> = true;
 
 namespace views
 {
@@ -1221,7 +1222,7 @@  namespace views
     ref_view(_Range&) -> ref_view<_Range>;
 
   template<typename _Tp>
-    inline constexpr bool enable_safe_range<ref_view<_Tp>> = true;
+    inline constexpr bool enable_borrowed_range<ref_view<_Tp>> = true;
 
   namespace views
   {
diff --git a/libstdc++-v3/include/std/span b/libstdc++-v3/include/std/span
index a8c69796e5e..63dc2515b25 100644
--- a/libstdc++-v3/include/std/span
+++ b/libstdc++-v3/include/std/span
@@ -207,7 +207,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       template<typename _Range>
 	requires ranges::contiguous_range<_Range> && ranges::sized_range<_Range>
-	  && (ranges::safe_range<_Range> || is_const_v<element_type>)
+	  && (ranges::borrowed_range<_Range> || is_const_v<element_type>)
 	  && (!__detail::__is_std_span<remove_cvref_t<_Range>>::value)
 	  && (!__detail::__is_std_array<remove_cvref_t<_Range>>::value)
 	  && (!is_array_v<remove_cvref_t<_Range>>)
@@ -465,11 +465,11 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   namespace ranges
   {
-    template<typename> extern inline const bool enable_safe_range;
-    // Opt-in to safe_range concept
+    template<typename> extern inline const bool enable_borrowed_range;
+    // Opt-in to borrowed_range concept
     template<typename _ElementType, size_t _Extent>
       inline constexpr bool
-	enable_safe_range<span<_ElementType, _Extent>> = true;
+	enable_borrowed_range<span<_ElementType, _Extent>> = true;
   }
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
diff --git a/libstdc++-v3/include/std/string_view b/libstdc++-v3/include/std/string_view
index bedad24979e..16687f6c352 100644
--- a/libstdc++-v3/include/std/string_view
+++ b/libstdc++-v3/include/std/string_view
@@ -727,11 +727,11 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #if __cpp_lib_concepts
   namespace ranges
   {
-    template<typename> extern inline const bool enable_safe_range;
-    // Opt-in to safe_range concept
+    template<typename> extern inline const bool enable_borrowed_range;
+    // Opt-in to borrowed_range concept
     template<typename _CharT, typename _Traits>
       inline constexpr bool
-	enable_safe_range<basic_string_view<_CharT, _Traits>> = true;
+	enable_borrowed_range<basic_string_view<_CharT, _Traits>> = true;
   }
 #endif
 _GLIBCXX_END_NAMESPACE_VERSION
diff --git a/libstdc++-v3/testsuite/std/ranges/access/begin.cc b/libstdc++-v3/testsuite/std/ranges/access/begin.cc
index 882dffb4877..b6801552c60 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/begin.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/begin.cc
@@ -85,7 +85,7 @@  struct RV // view on an R
 };
 
 // Allow ranges::begin to work with RV&&
-template<> constexpr bool std::ranges::enable_safe_range<RV> = true;
+template<> constexpr bool std::ranges::enable_borrowed_range<RV> = true;
 
 void
 test03()
@@ -102,7 +102,7 @@  test03()
   VERIFY( std::ranges::begin(c) == begin(c) );
 
   RV v{r};
-  // enable_safe_range<RV> allows ranges::begin to work for rvalues,
+  // enable_borrowed_range<RV> allows ranges::begin to work for rvalues,
   // but it will call v.begin() or begin(v) on an lvalue:
   static_assert(same_as<decltype(std::ranges::begin(std::move(v))),
 		decltype(begin(v))>);
@@ -132,7 +132,7 @@  struct RR
 };
 
 // N.B. this is a lie, begin on an RR rvalue will return a dangling pointer.
-template<> constexpr bool std::ranges::enable_safe_range<RR> = true;
+template<> constexpr bool std::ranges::enable_borrowed_range<RR> = true;
 
 void
 test04()
diff --git a/libstdc++-v3/testsuite/std/ranges/access/cbegin.cc b/libstdc++-v3/testsuite/std/ranges/access/cbegin.cc
index 981f88d3b5d..6e994210c6b 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/cbegin.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/cbegin.cc
@@ -54,7 +54,7 @@  struct RV // view on an R
 };
 
 // Allow ranges::begin to work with RV&&
-template<> constexpr bool std::ranges::enable_safe_range<RV> = true;
+template<> constexpr bool std::ranges::enable_borrowed_range<RV> = true;
 
 void
 test03()
@@ -86,7 +86,7 @@  struct RR
 };
 
 // N.B. this is a lie, cbegin on an RR rvalue will return a dangling pointer.
-template<> constexpr bool std::ranges::enable_safe_range<RR> = true;
+template<> constexpr bool std::ranges::enable_borrowed_range<RR> = true;
 
 void
 test04()
diff --git a/libstdc++-v3/testsuite/std/ranges/access/cdata.cc b/libstdc++-v3/testsuite/std/ranges/access/cdata.cc
index c8489dd1ab9..8e68514bfad 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/cdata.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/cdata.cc
@@ -57,7 +57,7 @@  struct R
 };
 
 // This is a lie, ranges::begin(R&&) returns a dangling iterator.
-template<> constexpr bool std::ranges::enable_safe_range<R> = true;
+template<> constexpr bool std::ranges::enable_borrowed_range<R> = true;
 
 void
 test03()
diff --git a/libstdc++-v3/testsuite/std/ranges/access/cend.cc b/libstdc++-v3/testsuite/std/ranges/access/cend.cc
index 4172932118e..f3a00863a78 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/cend.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/cend.cc
@@ -60,7 +60,7 @@  struct RV // view on an R
 };
 
 // Allow ranges::end to work with RV&&
-template<> constexpr bool std::ranges::enable_safe_range<RV> = true;
+template<> constexpr bool std::ranges::enable_borrowed_range<RV> = true;
 
 void
 test03()
@@ -98,7 +98,7 @@  struct RR
 };
 
 // N.B. this is a lie, begin/end on an RR rvalue will return a dangling pointer.
-template<> constexpr bool std::ranges::enable_safe_range<RR> = true;
+template<> constexpr bool std::ranges::enable_borrowed_range<RR> = true;
 
 void
 test04()
diff --git a/libstdc++-v3/testsuite/std/ranges/access/crbegin.cc b/libstdc++-v3/testsuite/std/ranges/access/crbegin.cc
index 61724c8ba05..50d8eb43e75 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/crbegin.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/crbegin.cc
@@ -40,7 +40,7 @@  struct R1V // view on an R1
 };
 
 // Allow ranges::end to work with R1V&&
-template<> constexpr bool std::ranges::enable_safe_range<R1V> = true;
+template<> constexpr bool std::ranges::enable_borrowed_range<R1V> = true;
 
 void
 test01()
@@ -69,7 +69,7 @@  struct R2
 };
 
 // N.B. this is a lie, rbegin on an R2 rvalue will return a dangling pointer.
-template<> constexpr bool std::ranges::enable_safe_range<R2> = true;
+template<> constexpr bool std::ranges::enable_borrowed_range<R2> = true;
 
 void
 test02()
diff --git a/libstdc++-v3/testsuite/std/ranges/access/crend.cc b/libstdc++-v3/testsuite/std/ranges/access/crend.cc
index 85fecf1221c..4d50f4a0965 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/crend.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/crend.cc
@@ -34,7 +34,7 @@  struct R1
 };
 
 // N.B. this is a lie, rend on an R1 rvalue will return a dangling pointer.
-template<> constexpr bool std::ranges::enable_safe_range<R1> = true;
+template<> constexpr bool std::ranges::enable_borrowed_range<R1> = true;
 
 void
 test01()
@@ -60,7 +60,7 @@  struct R2
 };
 
 // N.B. this is a lie, rend on an R2 rvalue will return a dangling pointer.
-template<> constexpr bool std::ranges::enable_safe_range<R2> = true;
+template<> constexpr bool std::ranges::enable_borrowed_range<R2> = true;
 
 void
 test02()
@@ -85,7 +85,7 @@  struct R3
 };
 
 // N.B. this is a lie, rend on an R3 rvalue will return a dangling pointer.
-template<> constexpr bool std::ranges::enable_safe_range<R3> = true;
+template<> constexpr bool std::ranges::enable_borrowed_range<R3> = true;
 
 void
 test03()
diff --git a/libstdc++-v3/testsuite/std/ranges/access/data.cc b/libstdc++-v3/testsuite/std/ranges/access/data.cc
index b7f04929f92..bcd564b75c8 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/data.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/data.cc
@@ -61,7 +61,7 @@  struct R3
 };
 
 // N.B. this is a lie, begin on an R3 rvalue will return a dangling pointer.
-template<> constexpr bool std::ranges::enable_safe_range<R3> = true;
+template<> constexpr bool std::ranges::enable_borrowed_range<R3> = true;
 
 void
 test03()
@@ -69,7 +69,7 @@  test03()
   R3 r;
   const R3& c = r;
   // r.data() can only be used on an lvalue, but ranges::begin(R3&&) is OK
-  // because R3 satisfies ranges::safe_range.
+  // because R3 satisfies ranges::borrowed_range.
   VERIFY( std::ranges::data(std::move(r)) == std::to_address(std::ranges::begin(std::move(r))) );
   VERIFY( std::ranges::data(std::move(c)) == std::to_address(std::ranges::begin(std::move(c))) );
 }
diff --git a/libstdc++-v3/testsuite/std/ranges/access/end.cc b/libstdc++-v3/testsuite/std/ranges/access/end.cc
index c3a1028dc14..245f246c517 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/end.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/end.cc
@@ -90,7 +90,7 @@  struct RV // view on an R
 };
 
 // Allow ranges::begin to work with RV&&
-template<> constexpr bool std::ranges::enable_safe_range<RV> = true;
+template<> constexpr bool std::ranges::enable_borrowed_range<RV> = true;
 
 void
 test03()
@@ -146,7 +146,7 @@  struct RR
 };
 
 // N.B. this is a lie, end on an RR rvalue will return a dangling pointer.
-template<> constexpr bool std::ranges::enable_safe_range<RR> = true;
+template<> constexpr bool std::ranges::enable_borrowed_range<RR> = true;
 
 void
 test04()
diff --git a/libstdc++-v3/testsuite/std/ranges/access/rbegin.cc b/libstdc++-v3/testsuite/std/ranges/access/rbegin.cc
index e92e5bc69ac..bc49a10a734 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/rbegin.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/rbegin.cc
@@ -32,7 +32,7 @@  struct R1
 };
 
 // N.B. this is a lie, rbegin on an R1 rvalue will return a dangling pointer.
-template<> constexpr bool std::ranges::enable_safe_range<R1> = true;
+template<> constexpr bool std::ranges::enable_borrowed_range<R1> = true;
 
 void
 test01()
@@ -56,7 +56,7 @@  struct R2
 };
 
 // N.B. this is a lie, begin/end on an R2 rvalue will return a dangling pointer.
-template<> constexpr bool std::ranges::enable_safe_range<R2> = true;
+template<> constexpr bool std::ranges::enable_borrowed_range<R2> = true;
 
 void
 test02()
diff --git a/libstdc++-v3/testsuite/std/ranges/access/rend.cc b/libstdc++-v3/testsuite/std/ranges/access/rend.cc
index f6909b8340c..e80b5526f84 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/rend.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/rend.cc
@@ -34,7 +34,7 @@  struct R1
 };
 
 // N.B. this is a lie, rend on an R1 rvalue will return a dangling pointer.
-template<> constexpr bool std::ranges::enable_safe_range<R1> = true;
+template<> constexpr bool std::ranges::enable_borrowed_range<R1> = true;
 
 void
 test01()
@@ -87,7 +87,7 @@  struct R3
 };
 
 // N.B. this is a lie, begin/end on an R3 rvalue will return a dangling pointer.
-template<> constexpr bool std::ranges::enable_safe_range<R3> = true;
+template<> constexpr bool std::ranges::enable_borrowed_range<R3> = true;
 
 void
 test03()
diff --git a/libstdc++-v3/testsuite/std/ranges/safe_range.cc b/libstdc++-v3/testsuite/std/ranges/safe_range.cc
index 6e50bf579c3..ec43f7884dc 100644
--- a/libstdc++-v3/testsuite/std/ranges/safe_range.cc
+++ b/libstdc++-v3/testsuite/std/ranges/safe_range.cc
@@ -21,21 +21,21 @@ 
 #include <ranges>
 #include <testsuite_iterators.h>
 
-static_assert( std::ranges::safe_range<int(&)[1]> );
-static_assert( std::ranges::safe_range<const int(&)[1]> );
-static_assert( !std::ranges::safe_range<int[1]> );
-static_assert( !std::ranges::safe_range<int*> );
+static_assert( std::ranges::borrowed_range<int(&)[1]> );
+static_assert( std::ranges::borrowed_range<const int(&)[1]> );
+static_assert( !std::ranges::borrowed_range<int[1]> );
+static_assert( !std::ranges::borrowed_range<int*> );
 
 using __gnu_test::test_contiguous_range;
 
-static_assert( !std::ranges::safe_range<test_contiguous_range<int>> );
-static_assert( std::ranges::safe_range<test_contiguous_range<int>&> );
-static_assert( !std::ranges::safe_range<test_contiguous_range<int>&&> );
+static_assert( !std::ranges::borrowed_range<test_contiguous_range<int>> );
+static_assert( std::ranges::borrowed_range<test_contiguous_range<int>&> );
+static_assert( !std::ranges::borrowed_range<test_contiguous_range<int>&&> );
 
 template<>
 constexpr bool
-  std::ranges::enable_safe_range<test_contiguous_range<long>> = true;
+  std::ranges::enable_borrowed_range<test_contiguous_range<long>> = true;
 
-static_assert( std::ranges::safe_range<test_contiguous_range<long>> );
-static_assert( std::ranges::safe_range<test_contiguous_range<long>&> );
-static_assert( std::ranges::safe_range<test_contiguous_range<long>&&> );
+static_assert( std::ranges::borrowed_range<test_contiguous_range<long>> );
+static_assert( std::ranges::borrowed_range<test_contiguous_range<long>&> );
+static_assert( std::ranges::borrowed_range<test_contiguous_range<long>&&> );
diff --git a/libstdc++-v3/testsuite/std/ranges/safe_range_types.cc b/libstdc++-v3/testsuite/std/ranges/safe_range_types.cc
index 3f0b52404a1..2835babfd82 100644
--- a/libstdc++-v3/testsuite/std/ranges/safe_range_types.cc
+++ b/libstdc++-v3/testsuite/std/ranges/safe_range_types.cc
@@ -25,35 +25,35 @@ 
 
 template<typename T>
 constexpr bool
-rvalue_is_safe_range()
+rvalue_is_borrowed_range()
 {
-  using std::ranges::safe_range;
+  using std::ranges::borrowed_range;
 
-  // An lvalue range always models safe_range
-  static_assert( safe_range<T&> );
-  static_assert( safe_range<const T&> );
+  // An lvalue range always models borrowed_range
+  static_assert( borrowed_range<T&> );
+  static_assert( borrowed_range<const T&> );
 
   // Result should not depend on addition of const or rvalue-reference.
-  static_assert( safe_range<T&&> == safe_range<T> );
-  static_assert( safe_range<const T> == safe_range<T> );
-  static_assert( safe_range<const T&&> == safe_range<T> );
+  static_assert( borrowed_range<T&&> == borrowed_range<T> );
+  static_assert( borrowed_range<const T> == borrowed_range<T> );
+  static_assert( borrowed_range<const T&&> == borrowed_range<T> );
 
-  return std::ranges::safe_range<T>;
+  return std::ranges::borrowed_range<T>;
 }
 
-static_assert( rvalue_is_safe_range<std::ranges::subrange<int*, int*>>() );
-static_assert( rvalue_is_safe_range<std::ranges::empty_view<int>>() );
-static_assert( rvalue_is_safe_range<std::ranges::iota_view<int>>() );
-static_assert( rvalue_is_safe_range<std::ranges::iota_view<int, int>>() );
+static_assert( rvalue_is_borrowed_range<std::ranges::subrange<int*, int*>>() );
+static_assert( rvalue_is_borrowed_range<std::ranges::empty_view<int>>() );
+static_assert( rvalue_is_borrowed_range<std::ranges::iota_view<int>>() );
+static_assert( rvalue_is_borrowed_range<std::ranges::iota_view<int, int>>() );
 
-static_assert( rvalue_is_safe_range<std::span<int>>() );
-static_assert( rvalue_is_safe_range<std::span<int, 99>>() );
+static_assert( rvalue_is_borrowed_range<std::span<int>>() );
+static_assert( rvalue_is_borrowed_range<std::span<int, 99>>() );
 
-static_assert( ! rvalue_is_safe_range<std::string>() );
-static_assert( ! rvalue_is_safe_range<std::wstring>() );
+static_assert( ! rvalue_is_borrowed_range<std::string>() );
+static_assert( ! rvalue_is_borrowed_range<std::wstring>() );
 
-static_assert( rvalue_is_safe_range<std::string_view>() );
-static_assert( rvalue_is_safe_range<std::wstring_view>() );
+static_assert( rvalue_is_borrowed_range<std::string_view>() );
+static_assert( rvalue_is_borrowed_range<std::wstring_view>() );
 
-static_assert( rvalue_is_safe_range<std::experimental::string_view>() );
-static_assert( rvalue_is_safe_range<std::experimental::wstring_view>() );
+static_assert( rvalue_is_borrowed_range<std::experimental::string_view>() );
+static_assert( rvalue_is_borrowed_range<std::experimental::wstring_view>() );
diff --git a/libstdc++-v3/testsuite/util/testsuite_iterators.h b/libstdc++-v3/testsuite/util/testsuite_iterators.h
index 6887d806a31..7b7093919b7 100644
--- a/libstdc++-v3/testsuite/util/testsuite_iterators.h
+++ b/libstdc++-v3/testsuite/util/testsuite_iterators.h
@@ -765,8 +765,8 @@  namespace __gnu_test
       = test_sized_range<T, output_iterator_wrapper>;
 
 // test_range and test_sized_range do not own their elements, so they model
-// std::ranges::safe_range.  This file does not define specializations of
-// std::ranges::enable_safe_range, so that individual tests can decide
+// std::ranges::borrowed_range.  This file does not define specializations of
+// std::ranges::enable_borrowed_range, so that individual tests can decide
 // whether or not to do so.
 // This is also true for test_container, although only when it has forward
 // iterators (because output_iterator_wrapper and input_iterator_wrapper are

commit fa89adaa979093936d8f148ef5496db05ad308e5
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed Feb 19 11:37:54 2020 +0000

    libstdc++: tuple_element_t is also wrong for const subrange (LWG 3398)
    
            * include/std/ranges (tuple_element<0, const subrange<I, S, K>>)
            (tuple_element<1, const subrange<I, S, K>>): Add partial
            specializations (LWG 3398).
            * testsuite/std/ranges/subrange/tuple_like.cc: New test.

diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index a8fcd7cb475..f69507d667f 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,5 +1,10 @@ 
 2020-02-19  Jonathan Wakely  <jwakely@redhat.com>
 
+	* include/std/ranges (tuple_element<0, const subrange<I, S, K>>)
+	(tuple_element<1, const subrange<I, S, K>>): Add partial
+	specializations (LWG 3398).
+	* testsuite/std/ranges/subrange/tuple_like.cc: New test.
+
 	* include/bits/ranges_algo.h (__find_fn, __find_first_of_fn)
 	(__adjacent_find_fn, __remove_if_fn, __remove_copy_if_fn)
 	(__unique_fn, __unique_copy_fn): Remove redundant conversions to bool.
diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index e0eb84748a2..4e50206fb61 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -3193,7 +3193,6 @@  namespace views
 	typename tuple_size<_Tp>::type;
 	requires _Nm < tuple_size_v<_Tp>;
 	typename tuple_element_t<_Nm, _Tp>;
-	// XXX: we applied P3323 here
 	{ std::get<_Nm>(__t) }
 	  -> convertible_to<const tuple_element_t<_Nm, _Tp>&>;
       };
@@ -3451,6 +3450,14 @@  namespace views
     struct tuple_element<1, ranges::subrange<_Iter, _Sent, _Kind>>
     { using type = _Sent; };
 
+  template<typename _Iter, typename _Sent, ranges::subrange_kind _Kind>
+    struct tuple_element<0, const ranges::subrange<_Iter, _Sent, _Kind>>
+    { using type = _Iter; };
+
+  template<typename _Iter, typename _Sent, ranges::subrange_kind _Kind>
+    struct tuple_element<1, const ranges::subrange<_Iter, _Sent, _Kind>>
+    { using type = _Sent; };
+
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace
 #endif // library concepts
diff --git a/libstdc++-v3/testsuite/std/ranges/subrange/tuple_like.cc b/libstdc++-v3/testsuite/std/ranges/subrange/tuple_like.cc
new file mode 100644
index 00000000000..a3020d21d29
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/ranges/subrange/tuple_like.cc
@@ -0,0 +1,52 @@ 
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <ranges>
+
+using S1 = std::ranges::subrange<int*>;
+using S2 = std::ranges::subrange<long*, void*>;
+
+static_assert( std::tuple_size_v<S1> == 2 );
+static_assert( std::tuple_size_v<S2> == 2 );
+
+static_assert( std::same_as<std::tuple_element_t<0, S1>, int*> );
+static_assert( std::same_as<std::tuple_element_t<1, S1>, int*> );
+// LWG 3398
+static_assert( std::same_as<std::tuple_element_t<0, const S1>, int*> );
+static_assert( std::same_as<std::tuple_element_t<1, const S1>, int*> );
+
+static_assert( std::same_as<std::tuple_element_t<0, S2>, long*> );
+static_assert( std::same_as<std::tuple_element_t<1, S2>, void*> );
+// LWG 3398
+static_assert( std::same_as<std::tuple_element_t<0, const S2>, long*> );
+static_assert( std::same_as<std::tuple_element_t<1, const S2>, void*> );
+
+S1 s1;
+static_assert( std::same_as<decltype(std::get<0>(s1)), int*> );
+static_assert( std::same_as<decltype(std::get<1>(s1)), int*> );
+const S1 c1;
+static_assert( std::same_as<decltype(std::get<0>(c1)), int*> );
+static_assert( std::same_as<decltype(std::get<1>(c1)), int*> );
+S2 s2;
+static_assert( std::same_as<decltype(std::get<0>(s2)), long*> );
+static_assert( std::same_as<decltype(std::get<1>(s2)), void*> );
+const S2 c2;
+static_assert( std::same_as<decltype(std::get<0>(c2)), long*> );
+static_assert( std::same_as<decltype(std::get<1>(c2)), void*> );

commit a45fb21a10f486f6596b648e2c64bd1c7d808f18
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed Feb 19 10:40:24 2020 +0000

    libstdc++: Remove redundant bool casts in ranges algorithms
    
    Some of these casts were added by me the other day, but some were
    already present. I think they are all redundant following the
    introduction of the boolean-testable concept in P1964R2.
    
            * include/bits/ranges_algo.h (__find_fn, __find_first_of_fn)
            (__adjacent_find_fn, __remove_if_fn, __remove_copy_if_fn)
            (__unique_fn, __unique_copy_fn): Remove redundant conversions to bool.

diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index b60f5c301b4..a8fcd7cb475 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,3 +1,9 @@ 
+2020-02-19  Jonathan Wakely  <jwakely@redhat.com>
+
+	* include/bits/ranges_algo.h (__find_fn, __find_first_of_fn)
+	(__adjacent_find_fn, __remove_if_fn, __remove_copy_if_fn)
+	(__unique_fn, __unique_copy_fn): Remove redundant conversions to bool.
+
 2020-02-18  Patrick Palka  <ppalka@redhat.com>
 
 	P1983R0 Wording for GB301, US296, US292, US291, and US283
diff --git a/libstdc++-v3/include/bits/ranges_algo.h b/libstdc++-v3/include/bits/ranges_algo.h
index 31b1bf0d448..a69181e12cb 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -244,7 +244,7 @@  namespace ranges
 		 const _Tp& __value, _Proj __proj = {}) const
       {
 	while (__first != __last
-	    && !(bool)(std::__invoke(__proj, *__first) == __value))
+	    && !(std::__invoke(__proj, *__first) == __value))
 	  ++__first;
 	return __first;
       }
@@ -333,9 +333,9 @@  namespace ranges
       {
 	for (; __first1 != __last1; ++__first1)
 	  for (auto __iter = __first2; __iter != __last2; ++__iter)
-	    if ((bool)std::__invoke(__pred,
-				    std::__invoke(__proj1, *__first1),
-				    std::__invoke(__proj2, *__iter)))
+	    if (std::__invoke(__pred,
+			      std::__invoke(__proj1, *__first1),
+			      std::__invoke(__proj2, *__iter)))
 	      return __first1;
 	return __first1;
       }
@@ -730,9 +730,9 @@  namespace ranges
 	auto __next = __first;
 	for (; ++__next != __last; __first = __next)
 	  {
-	    if ((bool)std::__invoke(__pred,
-				    std::__invoke(__proj, *__first),
-				    std::__invoke(__proj, *__next)))
+	    if (std::__invoke(__pred,
+			      std::__invoke(__proj, *__first),
+			      std::__invoke(__proj, *__next)))
 	      return __first;
 	  }
 	return __next;
@@ -1219,7 +1219,7 @@  namespace ranges
 	auto __result = __first;
 	++__first;
 	for (; __first != __last; ++__first)
-	  if (!(bool)std::__invoke(__pred, std::__invoke(__proj, *__first)))
+	  if (!std::__invoke(__pred, std::__invoke(__proj, *__first)))
 	    {
 	      *__result = std::move(*__first);
 	      ++__result;
@@ -1289,7 +1289,7 @@  namespace ranges
 		 _Pred __pred, _Proj __proj = {}) const
       {
 	for (; __first != __last; ++__first)
-	  if (!(bool)std::__invoke(__pred, std::__invoke(__proj, *__first)))
+	  if (!std::__invoke(__pred, std::__invoke(__proj, *__first)))
 	    {
 	      *__result = *__first;
 	      ++__result;
@@ -1372,9 +1372,9 @@  namespace ranges
 	auto __dest = __first;
 	++__first;
 	while (++__first != __last)
-	  if (!(bool)std::__invoke(__comp,
-				   std::__invoke(__proj, *__dest),
-				   std::__invoke(__proj, *__first)))
+	  if (!std::__invoke(__comp,
+			     std::__invoke(__proj, *__dest),
+			     std::__invoke(__proj, *__first)))
 	    *++__dest = std::move(*__first);
 	return {++__dest, __first};
       }
@@ -1420,9 +1420,9 @@  namespace ranges
 	    auto __next = __first;
 	    *__result = *__next;
 	    while (++__next != __last)
-	      if (!(bool)std::__invoke(__comp,
-				       std::__invoke(__proj, *__first),
-				       std::__invoke(__proj, *__next)))
+	      if (!std::__invoke(__comp,
+				 std::__invoke(__proj, *__first),
+				 std::__invoke(__proj, *__next)))
 		{
 		  __first = __next;
 		  *++__result = *__first;
@@ -1434,9 +1434,9 @@  namespace ranges
 	  {
 	    *__result = *__first;
 	    while (++__first != __last)
-	      if (!(bool)std::__invoke(__comp,
-				       std::__invoke(__proj, *__result),
-				       std::__invoke(__proj, *__first)))
+	      if (!std::__invoke(__comp,
+				 std::__invoke(__proj, *__result),
+				 std::__invoke(__proj, *__first)))
 		  *++__result = *__first;
 	    return {std::move(__first), std::move(++__result)};
 	  }

commit 73d531205083eaf19934b516b37b1cf4940895c7
Author: Bernd Edlinger <bernd.edlinger@hotmail.de>
Date:   Mon Feb 17 17:40:07 2020 +0100

    Fix -save-temp leaking files in /tmp
    
    And avoid signal handler calling signal unsafe functions,
    and/or calling unlink with uninitialized memory pointer.
    
    2020-02-19  Bernd Edlinger  <bernd.edlinger@hotmail.de>
    
            * collect2.c (c_file, o_file): Make const again.
            (ldout,lderrout, dump_ld_file): Remove.
            (tool_cleanup): Avoid calling not signal-safe functions.
            (maybe_run_lto_and_relink): Avoid possible signal handler
            access to unintialzed memory (lto_o_files).
            (main): Avoid leaking temp files in $TMPDIR.
            Initialize c_file/o_file with concat, which avoids exposing
            uninitialized memory to signal handler, which calls unlink(!).
            Avoid calling maybe_unlink when the main function returns,
            since the atexit handler is already doing this.
            * collect2.h (dump_ld_file, ldout, lderrout): Remove.

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 7ebeaed89e0..6cd941a5ff8 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,17 @@ 
+2020-02-19  Bernd Edlinger  <bernd.edlinger@hotmail.de>
+
+	* collect2.c (c_file, o_file): Make const again.
+	(ldout,lderrout, dump_ld_file): Remove.
+	(tool_cleanup): Avoid calling not signal-safe functions.
+	(maybe_run_lto_and_relink): Avoid possible signal handler
+	access to unintialzed memory (lto_o_files).
+	(main): Avoid leaking temp files in $TMPDIR.
+	Initialize c_file/o_file with concat, which avoids exposing
+	uninitialized memory to signal handler, which calls unlink(!).
+	Avoid calling maybe_unlink when the main function returns,
+	since the atexit handler is already doing this.
+	* collect2.h (dump_ld_file, ldout, lderrout): Remove.
+
 2020-02-19  Martin Jambor  <mjambor@suse.cz>
 
 	PR tree-optimization/93776
diff --git a/gcc/collect2.c b/gcc/collect2.c
index 502d629141c..f7d9f103ddc 100644
--- a/gcc/collect2.c
+++ b/gcc/collect2.c
@@ -205,14 +205,12 @@  bool helpflag;			/* true if --help */
 static int shared_obj;			/* true if -shared */
 static int static_obj;			/* true if -static */
 
-static char *c_file;		/* <xxx>.c for constructor/destructor list.  */
-static char *o_file;		/* <xxx>.o for constructor/destructor list.  */
+static const char *c_file;		/* <xxx>.c for constructor/destructor list.  */
+static const char *o_file;		/* <xxx>.o for constructor/destructor list.  */
 #ifdef COLLECT_EXPORT_LIST
 static const char *export_file;		/* <xxx>.x for AIX export list.  */
 #endif
 static char **lto_o_files;		/* Output files for LTO.  */
-const char *ldout;			/* File for ld stdout.  */
-const char *lderrout;			/* File for ld stderr.  */
 static const char *output_file;		/* Output file for ld.  */
 static const char *nm_file_name;	/* pathname of nm */
 #ifdef LDD_SUFFIX
@@ -384,6 +382,10 @@  static void scan_prog_file (const char *, scanpass, scanfilter);
 void
 tool_cleanup (bool from_signal)
 {
+  /* maybe_unlink may call notice, which is not signal safe.  */
+  if (from_signal)
+    verbose = false;
+
   if (c_file != 0 && c_file[0])
     maybe_unlink (c_file);
 
@@ -397,20 +399,6 @@  tool_cleanup (bool from_signal)
 
   if (lto_o_files)
     maybe_unlink_list (lto_o_files);
-
-  if (ldout != 0 && ldout[0])
-    {
-      if (!from_signal)
-	dump_ld_file (ldout, stdout);
-      maybe_unlink (ldout);
-    }
-
-  if (lderrout != 0 && lderrout[0])
-    {
-      if (!from_signal)
-	dump_ld_file (lderrout, stderr);
-      maybe_unlink (lderrout);
-    }
 }
 
 static void
@@ -476,77 +464,6 @@  extract_string (const char **pp)
   return XOBFINISH (&temporary_obstack, char *);
 }
 
-void
-dump_ld_file (const char *name, FILE *to)
-{
-  FILE *stream = fopen (name, "r");
-
-  if (stream == 0)
-    return;
-  while (1)
-    {
-      int c;
-      while (c = getc (stream),
-	     c != EOF && (ISIDNUM (c) || c == '$' || c == '.'))
-	obstack_1grow (&temporary_obstack, c);
-      if (obstack_object_size (&temporary_obstack) > 0)
-	{
-	  const char *word, *p;
-	  char *result;
-	  obstack_1grow (&temporary_obstack, '\0');
-	  word = XOBFINISH (&temporary_obstack, const char *);
-
-	  if (*word == '.')
-	    ++word, putc ('.', to);
-	  p = word;
-	  if (!strncmp (p, USER_LABEL_PREFIX, strlen (USER_LABEL_PREFIX)))
-	    p += strlen (USER_LABEL_PREFIX);
-
-#ifdef HAVE_LD_DEMANGLE
-	  result = 0;
-#else
-	  if (no_demangle)
-	    result = 0;
-	  else
-	    result = cplus_demangle (p, DMGL_PARAMS | DMGL_ANSI | DMGL_VERBOSE);
-#endif
-
-	  if (result)
-	    {
-	      int diff;
-	      fputs (result, to);
-
-	      diff = strlen (word) - strlen (result);
-	      while (diff > 0 && c == ' ')
-		--diff, putc (' ', to);
-	      if (diff < 0 && c == ' ')
-		{
-		  while (diff < 0 && c == ' ')
-		    ++diff, c = getc (stream);
-		  if (!ISSPACE (c))
-		    {
-		      /* Make sure we output at least one space, or
-			 the demangled symbol name will run into
-			 whatever text follows.  */
-		      putc (' ', to);
-		    }
-		}
-
-	      free (result);
-	    }
-	  else
-	    fputs (word, to);
-
-	  fflush (to);
-	  obstack_free (&temporary_obstack, temporary_firstobj);
-	}
-      if (c == EOF)
-	break;
-      putc (c, to);
-    }
-  fclose (stream);
-}
-
 /* Return the kind of symbol denoted by name S.  */
 
 static symkind
@@ -744,7 +661,10 @@  maybe_run_lto_and_relink (char **lto_ld_argv, char **object_lst,
 	      ++num_files;
 	  }
 
-	lto_o_files = XNEWVEC (char *, num_files + 1);
+	/* signal handler may access uninitialized memory
+	   and delete whatever it points to, if lto_o_files
+	   is not allocatted with calloc.  */
+	lto_o_files = XCNEWVEC (char *, num_files + 1);
 	lto_o_files[num_files] = NULL;
 	start = XOBFINISH (&temporary_obstack, char *);
 	for (i = 0; i < num_files; ++i)
@@ -1262,27 +1182,19 @@  main (int argc, char **argv)
   /* Make temp file names.  */
   if (save_temps)
     {
-      c_file = (char *) xmalloc (strlen (output_file)
-				  + sizeof (".cdtor.c") + 1);
-      strcpy (c_file, output_file);
-      strcat (c_file, ".cdtor.c");
-      o_file = (char *) xmalloc (strlen (output_file)
-				  + sizeof (".cdtor.o") + 1);
-      strcpy (o_file, output_file);
-      strcat (o_file, ".cdtor.o");
+      c_file = concat (output_file, ".cdtor.c", NULL);
+      o_file = concat (output_file, ".cdtor.o", NULL);
+#ifdef COLLECT_EXPORT_LIST
+      export_file = concat (output_file, ".x", NULL);
+#endif
     }
   else
     {
       c_file = make_temp_file (".cdtor.c");
       o_file = make_temp_file (".cdtor.o");
-    }
 #ifdef COLLECT_EXPORT_LIST
-  export_file = make_temp_file (".x");
+      export_file = make_temp_file (".x");
 #endif
-  if (!debug)
-    {
-      ldout = make_temp_file (".ld");
-      lderrout = make_temp_file (".le");
     }
   /* Build the command line to compile the ctor/dtor list.  */
   *c_ptr++ = c_file_name;
@@ -1811,9 +1723,6 @@  main (int argc, char **argv)
       maybe_unlink (export_file);
 #endif
       post_ld_pass (/*temp_file*/false);
-
-      maybe_unlink (c_file);
-      maybe_unlink (o_file);
       return 0;
     }
 
@@ -1912,13 +1821,6 @@  main (int argc, char **argv)
   scan_prog_file (output_file, PASS_SECOND, SCAN_ALL);
 #endif
 
-  maybe_unlink (c_file);
-  maybe_unlink (o_file);
-
-#ifdef COLLECT_EXPORT_LIST
-  maybe_unlink (export_file);
-#endif
-
   return 0;
 }
 
diff --git a/gcc/collect2.h b/gcc/collect2.h
index ab5fcdf0ed8..aa8a03e7d87 100644
--- a/gcc/collect2.h
+++ b/gcc/collect2.h
@@ -25,12 +25,8 @@  extern struct pex_obj *collect_execute (const char *, char **, const char *,
 
 extern int collect_wait (const char *, struct pex_obj *);
 
-extern void dump_ld_file (const char *, FILE *);
-
 extern int file_exists (const char *);
 
-extern const char *ldout;
-extern const char *lderrout;
 extern const char *c_file_name;
 extern struct obstack temporary_obstack;
 extern char *temporary_firstobj;

commit 51faf07cef9293af544bfacc7d0b320ab90d7d60
Author: Martin Jambor <mjambor@suse.cz>
Date:   Wed Feb 19 11:13:52 2020 +0100

    sra: Do not create zero sized accesses  (PR 93776)
    
    SRA can get a bit confused with zero-sized accesses like the one in
    the testcase.  Since there is nothing in the access, nothing is
    scalarized, but we can get order of the structures wrong, which the
    verifier is not happy about.
    
    Fixed by simply ignoring such accesses.
    
    2020-02-19  Martin Jambor  <mjambor@suse.cz>
    
            PR tree-optimization/93776
            * tree-sra.c (create_access): Do not create zero size accesses.
            (get_access_for_expr): Do not search for zero sized accesses.
    
            testsuite/
            * gcc.dg/tree-ssa/pr93776.c: New test.

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 6b53f9a2f07..7ebeaed89e0 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@ 
+2020-02-19  Martin Jambor  <mjambor@suse.cz>
+
+	PR tree-optimization/93776
+	* tree-sra.c (create_access): Do not create zero size accesses.
+	(get_access_for_expr): Do not search for zero sized accesses.
+
 2020-02-19  Martin Jambor  <mjambor@suse.cz>
 
 	PR tree-optimization/93667
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 8033fa0a3bb..df79951b6cc 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@ 
+2020-02-19  Martin Jambor  <mjambor@suse.cz>
+
+	PR tree-optimization/93776
+	* gcc.dg/tree-ssa/pr93776.c: New test.
+
 2020-02-19  Martin Jambor  <mjambor@suse.cz>
 
 	PR tree-optimization/93667
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr93776.c b/gcc/testsuite/gcc.dg/tree-ssa/pr93776.c
new file mode 100644
index 00000000000..c407a627718
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr93776.c
@@ -0,0 +1,27 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O1" } */
+
+struct empty {};
+struct s { int i; };
+struct z
+{
+  int j;
+  struct empty e;
+  struct s s;
+  int k;
+};
+
+void bar (struct z);
+void baz (int);
+
+void foo (void)
+{
+  struct z z, z2;
+
+  z.k = 8;
+  z2.s.i = 1;
+  z = z2;
+  bar (z);
+  z.e = (struct empty) {};
+  baz (z.k);
+}
diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c
index 4c7d651e6b9..49f9001f7fb 100644
--- a/gcc/tree-sra.c
+++ b/gcc/tree-sra.c
@@ -926,6 +926,8 @@  create_access (tree expr, gimple *stmt, bool write)
       size = max_size;
       unscalarizable_region = true;
     }
+  if (size == 0)
+    return NULL;
   if (size < 0)
     {
       disqualify_candidate (base, "Encountered an unconstrained access.");
@@ -3643,7 +3645,8 @@  get_access_for_expr (tree expr)
 	return NULL;
     }
 
-  if (!bitmap_bit_p (candidate_bitmap, DECL_UID (base)))
+  if (max_size == 0
+      || !bitmap_bit_p (candidate_bitmap, DECL_UID (base)))
     return NULL;
 
   return get_var_base_offset_size_access (base, offset, max_size);

commit 665c5bad168ab63629b29ed2ce08ed042c088dc2
Author: Martin Jambor <mjambor@suse.cz>
Date:   Wed Feb 19 11:08:40 2020 +0100

    sra: Avoid totally scalarizing overallping field_decls (PR 93667)
    
    [[no_unique_address]] C++ attribute can cause two fields of a
    RECORD_TYPE overlap, which currently confuses the totally scalarizing
    code into creating invalid access tree.  For GCC 10, I'd like to
    simply disable total scalarization of types where this happens.
    
    For GCC 11 I'll write down a TODO item to enable total scalarization
    of cases like this where the problematic fields are basically empty -
    despite having a non-zero size - i.e. when they are just RECORD_TYPEs
    without any data fields.
    
    2020-02-19  Martin Jambor  <mjambor@suse.cz>
    
            gcc/
    
            PR tree-optimization/93667
            * tree-sra.c (scalarizable_type_p): Return false if record fields
            do not follow wach other.
    
            gcc/testsuite/
    
            PR tree-optimization/93667
            * g++.dg/tree-ssa/pr93667.C: New test.

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 77c2a9ad810..6b53f9a2f07 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@ 
+2020-02-19  Martin Jambor  <mjambor@suse.cz>
+
+	PR tree-optimization/93667
+	* tree-sra.c (scalarizable_type_p): Return false if record fields
+	do not follow wach other.
+
 2020-01-21  Kito Cheng  <kito.cheng@sifive.com>
 
 	* config/riscv/riscv.c (riscv_output_move) Using fmv.x.w/fmv.w.x
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 9b4fe11a6f6..8033fa0a3bb 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@ 
+2020-02-19  Martin Jambor  <mjambor@suse.cz>
+
+	PR tree-optimization/93667
+	* g++.dg/tree-ssa/pr93667.C: New test.
+
 2020-02-19  Hongtao Liu  <hongtao.liu@intel.com>
 
 	* g++.dg/other/i386-2.C: add -mavx512vbmi2
diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr93667.C b/gcc/testsuite/g++.dg/tree-ssa/pr93667.C
new file mode 100644
index 00000000000..d875f53d9ec
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/pr93667.C
@@ -0,0 +1,11 @@ 
+// { dg-do compile }
+// { dg-options "-O2 -std=c++2a" } */
+
+struct a {};
+struct b { [[no_unique_address]] a aq; };
+struct c {
+  int d;
+  [[no_unique_address]] b e;
+};
+c f() {return {};}
+void g() { f(); }
diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c
index 0cfac0a8192..4c7d651e6b9 100644
--- a/gcc/tree-sra.c
+++ b/gcc/tree-sra.c
@@ -958,6 +958,9 @@  scalarizable_type_p (tree type, bool const_decl)
   if (type_contains_placeholder_p (type))
     return false;
 
+  bool have_predecessor_field = false;
+  HOST_WIDE_INT prev_pos = 0;
+
   switch (TREE_CODE (type))
   {
   case RECORD_TYPE:
@@ -966,6 +969,17 @@  scalarizable_type_p (tree type, bool const_decl)
 	{
 	  tree ft = TREE_TYPE (fld);
 
+	  if (zerop (DECL_SIZE (fld)))
+	    continue;
+
+	  HOST_WIDE_INT pos = int_bit_position (fld);
+	  if (have_predecessor_field
+	      && pos <= prev_pos)
+	    return false;
+
+	  have_predecessor_field = true;
+	  prev_pos = pos;
+
 	  if (DECL_BIT_FIELD (fld))
 	    return false;