[libcxx-commits] [libcxx] [libc++] Simplify the implementation of __tuple_leaf (PR #115729)

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Sat Nov 16 05:28:51 PST 2024


https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/115729

>From b887fec9fc962fecc9e7399b6ef6d710b8dd21c1 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Mon, 11 Nov 2024 16:52:40 +0100
Subject: [PATCH] [libc++] Simplify the implementation of __tuple_leaf

---
 libcxx/include/CMakeLists.txt                 |  1 +
 libcxx/include/__expected/expected.h          | 50 +---------
 .../__utility/conditional_no_unique_address.h | 87 +++++++++++++++++
 libcxx/include/module.modulemap               | 47 ++++-----
 libcxx/include/tuple                          | 97 +++++--------------
 ...5_tuple_ref_binding_diagnostics.verify.cpp |  7 +-
 6 files changed, 136 insertions(+), 153 deletions(-)
 create mode 100644 libcxx/include/__utility/conditional_no_unique_address.h

diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 1610d1ee848a5f..7c3acae4095a21 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -863,6 +863,7 @@ set(files
   __utility/as_lvalue.h
   __utility/auto_cast.h
   __utility/cmp.h
+  __utility/conditional_no_unique_address.h
   __utility/convert_to_integral.h
   __utility/declval.h
   __utility/empty.h
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 3d3f11967ee746..2c7bd90fa03784 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -40,6 +40,7 @@
 #include <__type_traits/remove_cv.h>
 #include <__type_traits/remove_cvref.h>
 #include <__utility/as_const.h>
+#include <__utility/conditional_no_unique_address.h>
 #include <__utility/exception_guard.h>
 #include <__utility/forward.h>
 #include <__utility/in_place.h>
@@ -81,55 +82,6 @@ _LIBCPP_HIDE_FROM_ABI void __throw_bad_expected_access(_Arg&& __arg) {
 #  endif
 }
 
-// If parameter type `_Tp` of `__conditional_no_unique_address` is neither
-// copyable nor movable, a constructor with this tag is provided. For that
-// constructor, the user has to provide a function and arguments. The function
-// must return an object of type `_Tp`. When the function is invoked by the
-// constructor, guaranteed copy elision kicks in and the `_Tp` is constructed
-// in place.
-struct __conditional_no_unique_address_invoke_tag {};
-
-// This class implements an object with `[[no_unique_address]]` conditionally applied to it,
-// based on the value of `_NoUnique`.
-//
-// A member of this class must always have `[[no_unique_address]]` applied to
-// it. Otherwise, the `[[no_unique_address]]` in the "`_NoUnique == true`" case
-// would not have any effect. In the `false` case, the `__v` is not
-// `[[no_unique_address]]`, so nullifies the effects of the "outer"
-// `[[no_unique_address]]` regarding data layout.
-//
-// If we had a language feature, this class would basically be replaced by `[[no_unique_address(condition)]]`.
-template <bool _NoUnique, class _Tp>
-struct __conditional_no_unique_address;
-
-template <class _Tp>
-struct __conditional_no_unique_address<true, _Tp> {
-  template <class... _Args>
-  _LIBCPP_HIDE_FROM_ABI constexpr explicit __conditional_no_unique_address(in_place_t, _Args&&... __args)
-      : __v(std::forward<_Args>(__args)...) {}
-
-  template <class _Func, class... _Args>
-  _LIBCPP_HIDE_FROM_ABI constexpr explicit __conditional_no_unique_address(
-      __conditional_no_unique_address_invoke_tag, _Func&& __f, _Args&&... __args)
-      : __v(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
-
-  _LIBCPP_NO_UNIQUE_ADDRESS _Tp __v;
-};
-
-template <class _Tp>
-struct __conditional_no_unique_address<false, _Tp> {
-  template <class... _Args>
-  _LIBCPP_HIDE_FROM_ABI constexpr explicit __conditional_no_unique_address(in_place_t, _Args&&... __args)
-      : __v(std::forward<_Args>(__args)...) {}
-
-  template <class _Func, class... _Args>
-  _LIBCPP_HIDE_FROM_ABI constexpr explicit __conditional_no_unique_address(
-      __conditional_no_unique_address_invoke_tag, _Func&& __f, _Args&&... __args)
-      : __v(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
-
-  _Tp __v;
-};
-
 // This function returns whether the type `_Second` can be stuffed into the tail padding
 // of the `_First` type if both of them are given `[[no_unique_address]]`.
 template <class _First, class _Second>
diff --git a/libcxx/include/__utility/conditional_no_unique_address.h b/libcxx/include/__utility/conditional_no_unique_address.h
new file mode 100644
index 00000000000000..fbb9bf103af515
--- /dev/null
+++ b/libcxx/include/__utility/conditional_no_unique_address.h
@@ -0,0 +1,87 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___UTILITY_CONDITIONAL_NO_UNIQUE_ADDRESS_H
+#define _LIBCPP___UTILITY_CONDITIONAL_NO_UNIQUE_ADDRESS_H
+
+#include <__config>
+#include <__type_traits/invoke.h>
+#include <__type_traits/is_swappable.h>
+#include <__utility/forward.h>
+#include <__utility/in_place.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+// If parameter type `_Tp` of `__conditional_no_unique_address` is neither
+// copyable nor movable, a constructor with this tag is provided. For that
+// constructor, the user has to provide a function and arguments. The function
+// must return an object of type `_Tp`. When the function is invoked by the
+// constructor, guaranteed copy elision kicks in and the `_Tp` is constructed
+// in place.
+struct __conditional_no_unique_address_invoke_tag {};
+
+// This class implements an object with `[[no_unique_address]]` conditionally applied to it,
+// based on the value of `_NoUnique`.
+//
+// A member of this class must always have `[[no_unique_address]]` applied to
+// it. Otherwise, the `[[no_unique_address]]` in the "`_NoUnique == true`" case
+// would not have any effect. In the `false` case, the `__v` is not
+// `[[no_unique_address]]`, so nullifies the effects of the "outer"
+// `[[no_unique_address]]` regarding data layout.
+//
+// If we had a language feature, this class would basically be replaced by `[[no_unique_address(condition)]]`.
+template <bool _NoUnique, class _Tp>
+struct __conditional_no_unique_address;
+
+template <class _Tp>
+struct __conditional_no_unique_address<true, _Tp> {
+  template <class... _Args>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __conditional_no_unique_address(in_place_t, _Args&&... __args)
+      : __v(std::forward<_Args>(__args)...) {}
+
+  template <class _Func, class... _Args>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __conditional_no_unique_address(
+      __conditional_no_unique_address_invoke_tag, _Func&& __f, _Args&&... __args)
+      : __v(std::__invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
+
+  _LIBCPP_NO_UNIQUE_ADDRESS _Tp __v;
+};
+
+template <class _Tp>
+struct __conditional_no_unique_address<false, _Tp> {
+  template <class... _Args>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __conditional_no_unique_address(in_place_t, _Args&&... __args)
+      : __v(std::forward<_Args>(__args)...) {}
+
+  template <class _Func, class... _Args>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __conditional_no_unique_address(
+      __conditional_no_unique_address_invoke_tag, _Func&& __f, _Args&&... __args)
+      : __v(std::__invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
+
+  _Tp __v;
+};
+
+template <bool _NoUnique, class _Tp>
+void swap(__conditional_no_unique_address<_NoUnique, _Tp>& __lhs,
+          __conditional_no_unique_address<_NoUnique, _Tp>& __rhs) _NOEXCEPT_(__is_swappable_v<_Tp>) {
+  using std::swap;
+  swap(__lhs.__v, __rhs.__v);
+}
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___UTILITY_CONDITIONAL_NO_UNIQUE_ADDRESS_H
diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index cd08b2810e437b..ac11ea532eb806 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -1988,36 +1988,37 @@ module std [system] {
   }
 
   module utility {
-    module as_const                   { header "__utility/as_const.h" }
-    module as_lvalue                  { header "__utility/as_lvalue.h" }
-    module auto_cast                  {
+    module as_const                      { header "__utility/as_const.h" }
+    module as_lvalue                     { header "__utility/as_lvalue.h" }
+    module auto_cast                     {
       header "__utility/auto_cast.h"
       export std_core.type_traits.decay // the macro expansion uses that trait
     }
-    module cmp                        { header "__utility/cmp.h" }
-    module convert_to_integral        { header "__utility/convert_to_integral.h" }
-    module exception_guard            { header "__utility/exception_guard.h" }
-    module exchange                   { header "__utility/exchange.h" }
-    module forward_like               { header "__utility/forward_like.h" }
+    module cmp                           { header "__utility/cmp.h" }
+    module conditional_no_unique_address { header "__utility/conditional_no_unique_address.h" }
+    module convert_to_integral           { header "__utility/convert_to_integral.h" }
+    module exception_guard               { header "__utility/exception_guard.h" }
+    module exchange                      { header "__utility/exchange.h" }
+    module forward_like                  { header "__utility/forward_like.h" }
     module in_place {
       header "__utility/in_place.h"
       export std_core.type_traits.integral_constant
     }
-    module integer_sequence           { header "__utility/integer_sequence.h" }
-    module is_pointer_in_range        { header "__utility/is_pointer_in_range.h" }
-    module is_valid_range             { header "__utility/is_valid_range.h" }
-    module move                       { header "__utility/move.h" }
-    module no_destroy                 { header "__utility/no_destroy.h" }
-    module pair                       { header "__utility/pair.h" }
-    module piecewise_construct        { header "__utility/piecewise_construct.h" }
-    module priority_tag               { header "__utility/priority_tag.h" }
-    module private_constructor_tag    { header "__utility/private_constructor_tag.h" }
-    module rel_ops                    { header "__utility/rel_ops.h" }
-    module scope_guard                { header "__utility/scope_guard.h" }
-    module small_buffer               { header "__utility/small_buffer.h" }
-    module swap                       { header "__utility/swap.h" }
-    module to_underlying              { header "__utility/to_underlying.h" }
-    module unreachable                { header "__utility/unreachable.h" }
+    module integer_sequence              { header "__utility/integer_sequence.h" }
+    module is_pointer_in_range           { header "__utility/is_pointer_in_range.h" }
+    module is_valid_range                { header "__utility/is_valid_range.h" }
+    module move                          { header "__utility/move.h" }
+    module no_destroy                    { header "__utility/no_destroy.h" }
+    module pair                          { header "__utility/pair.h" }
+    module piecewise_construct           { header "__utility/piecewise_construct.h" }
+    module priority_tag                  { header "__utility/priority_tag.h" }
+    module private_constructor_tag       { header "__utility/private_constructor_tag.h" }
+    module rel_ops                       { header "__utility/rel_ops.h" }
+    module scope_guard                   { header "__utility/scope_guard.h" }
+    module small_buffer                  { header "__utility/small_buffer.h" }
+    module swap                          { header "__utility/swap.h" }
+    module to_underlying                 { header "__utility/to_underlying.h" }
+    module unreachable                   { header "__utility/unreachable.h" }
 
     header "utility"
     export *
diff --git a/libcxx/include/tuple b/libcxx/include/tuple
index c3f7b8041686d1..47ca7bc02f163c 100644
--- a/libcxx/include/tuple
+++ b/libcxx/include/tuple
@@ -257,8 +257,10 @@ template <class... Types>
 #include <__type_traits/remove_cvref.h>
 #include <__type_traits/remove_reference.h>
 #include <__type_traits/unwrap_ref.h>
+#include <__utility/conditional_no_unique_address.h>
 #include <__utility/declval.h>
 #include <__utility/forward.h>
+#include <__utility/in_place.h>
 #include <__utility/integer_sequence.h>
 #include <__utility/move.h>
 #include <__utility/piecewise_construct.h>
@@ -283,25 +285,26 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 // __tuple_leaf
 
-template <size_t _Ip, class _Hp, bool = is_empty<_Hp>::value && !__libcpp_is_final<_Hp>::value >
+template <size_t _Ip, class _Hp>
 class __tuple_leaf;
 
-template <size_t _Ip, class _Hp, bool _Ep>
+template <size_t _Ip, class _Hp>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void
-swap(__tuple_leaf<_Ip, _Hp, _Ep>& __x, __tuple_leaf<_Ip, _Hp, _Ep>& __y) noexcept(__is_nothrow_swappable_v<_Hp>) {
+swap(__tuple_leaf<_Ip, _Hp>& __x, __tuple_leaf<_Ip, _Hp>& __y) noexcept(__is_nothrow_swappable_v<_Hp>) {
   swap(__x.get(), __y.get());
 }
 
-template <size_t _Ip, class _Hp, bool _Ep>
+template <size_t _Ip, class _Hp>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void
-swap(const __tuple_leaf<_Ip, _Hp, _Ep>& __x,
-     const __tuple_leaf<_Ip, _Hp, _Ep>& __y) noexcept(__is_nothrow_swappable_v<const _Hp>) {
+swap(const __tuple_leaf<_Ip, _Hp>& __x,
+     const __tuple_leaf<_Ip, _Hp>& __y) noexcept(__is_nothrow_swappable_v<const _Hp>) {
   swap(__x.get(), __y.get());
 }
 
-template <size_t _Ip, class _Hp, bool>
+template <size_t _Ip, class _Hp>
 class __tuple_leaf {
-  _Hp __value_;
+  _LIBCPP_NO_UNIQUE_ADDRESS __conditional_no_unique_address<is_empty<_Hp>::value && !__libcpp_is_final<_Hp>::value, _Hp>
+      __value_;
 
   template <class _Tp>
   static _LIBCPP_HIDE_FROM_ABI constexpr bool __can_bind_reference() {
@@ -315,23 +318,24 @@ class __tuple_leaf {
 public:
   _LIBCPP_CONSTEXPR_SINCE_CXX14 __tuple_leaf& operator=(const __tuple_leaf&) = delete;
 
-  _LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf() noexcept(is_nothrow_default_constructible<_Hp>::value) : __value_() {
+  _LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf() noexcept(is_nothrow_default_constructible<_Hp>::value)
+      : __value_(in_place) {
     static_assert(!is_reference<_Hp>::value, "Attempted to default construct a reference element in a tuple");
   }
 
   template <class _Alloc>
-  _LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf(integral_constant<int, 0>, const _Alloc&) : __value_() {
+  _LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf(integral_constant<int, 0>, const _Alloc&) : __value_(in_place) {
     static_assert(!is_reference<_Hp>::value, "Attempted to default construct a reference element in a tuple");
   }
 
   template <class _Alloc>
   _LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf(integral_constant<int, 1>, const _Alloc& __a)
-      : __value_(allocator_arg_t(), __a) {
+      : __value_(in_place, allocator_arg_t(), __a) {
     static_assert(!is_reference<_Hp>::value, "Attempted to default construct a reference element in a tuple");
   }
 
   template <class _Alloc>
-  _LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf(integral_constant<int, 2>, const _Alloc& __a) : __value_(__a) {
+  _LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf(integral_constant<int, 2>, const _Alloc& __a) : __value_(in_place, __a) {
     static_assert(!is_reference<_Hp>::value, "Attempted to default construct a reference element in a tuple");
   }
 
@@ -340,7 +344,7 @@ public:
       __enable_if_t<_And<_IsNotSame<__remove_cvref_t<_Tp>, __tuple_leaf>, is_constructible<_Hp, _Tp> >::value, int> = 0>
   _LIBCPP_HIDE_FROM_ABI
   _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit __tuple_leaf(_Tp&& __t) noexcept(is_nothrow_constructible<_Hp, _Tp>::value)
-      : __value_(std::forward<_Tp>(__t)) {
+      : __value_(in_place, std::forward<_Tp>(__t)) {
     static_assert(__can_bind_reference<_Tp&&>(),
                   "Attempted construction of reference element binds to a temporary whose lifetime has ended");
   }
@@ -348,7 +352,7 @@ public:
   template <class _Tp, class _Alloc>
   _LIBCPP_HIDE_FROM_ABI
   _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit __tuple_leaf(integral_constant<int, 0>, const _Alloc&, _Tp&& __t)
-      : __value_(std::forward<_Tp>(__t)) {
+      : __value_(in_place, std::forward<_Tp>(__t)) {
     static_assert(__can_bind_reference<_Tp&&>(),
                   "Attempted construction of reference element binds to a temporary whose lifetime has ended");
   }
@@ -356,14 +360,14 @@ public:
   template <class _Tp, class _Alloc>
   _LIBCPP_HIDE_FROM_ABI
   _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit __tuple_leaf(integral_constant<int, 1>, const _Alloc& __a, _Tp&& __t)
-      : __value_(allocator_arg_t(), __a, std::forward<_Tp>(__t)) {
+      : __value_(in_place, allocator_arg_t(), __a, std::forward<_Tp>(__t)) {
     static_assert(!is_reference<_Hp>::value, "Attempted to uses-allocator construct a reference element in a tuple");
   }
 
   template <class _Tp, class _Alloc>
   _LIBCPP_HIDE_FROM_ABI
   _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit __tuple_leaf(integral_constant<int, 2>, const _Alloc& __a, _Tp&& __t)
-      : __value_(std::forward<_Tp>(__t), __a) {
+      : __value_(in_place, std::forward<_Tp>(__t), __a) {
     static_assert(!is_reference<_Hp>::value, "Attempted to uses-allocator construct a reference element in a tuple");
   }
 
@@ -382,65 +386,8 @@ public:
     return 0;
   }
 
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Hp& get() _NOEXCEPT { return __value_; }
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const _Hp& get() const _NOEXCEPT { return __value_; }
-};
-
-template <size_t _Ip, class _Hp>
-class __tuple_leaf<_Ip, _Hp, true> : private _Hp {
-public:
-  _LIBCPP_CONSTEXPR_SINCE_CXX14 __tuple_leaf& operator=(const __tuple_leaf&) = delete;
-
-  _LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf() noexcept(is_nothrow_default_constructible<_Hp>::value) {}
-
-  template <class _Alloc>
-  _LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf(integral_constant<int, 0>, const _Alloc&) {}
-
-  template <class _Alloc>
-  _LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf(integral_constant<int, 1>, const _Alloc& __a)
-      : _Hp(allocator_arg_t(), __a) {}
-
-  template <class _Alloc>
-  _LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf(integral_constant<int, 2>, const _Alloc& __a) : _Hp(__a) {}
-
-  template <class _Tp,
-            __enable_if_t< _And< _IsNotSame<__remove_cvref_t<_Tp>, __tuple_leaf>, is_constructible<_Hp, _Tp> >::value,
-                           int> = 0>
-  _LIBCPP_HIDE_FROM_ABI
-  _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit __tuple_leaf(_Tp&& __t) noexcept(is_nothrow_constructible<_Hp, _Tp>::value)
-      : _Hp(std::forward<_Tp>(__t)) {}
-
-  template <class _Tp, class _Alloc>
-  _LIBCPP_HIDE_FROM_ABI constexpr explicit __tuple_leaf(integral_constant<int, 0>, const _Alloc&, _Tp&& __t)
-      : _Hp(std::forward<_Tp>(__t)) {}
-
-  template <class _Tp, class _Alloc>
-  _LIBCPP_HIDE_FROM_ABI constexpr explicit __tuple_leaf(integral_constant<int, 1>, const _Alloc& __a, _Tp&& __t)
-      : _Hp(allocator_arg_t(), __a, std::forward<_Tp>(__t)) {}
-
-  template <class _Tp, class _Alloc>
-  _LIBCPP_HIDE_FROM_ABI constexpr explicit __tuple_leaf(integral_constant<int, 2>, const _Alloc& __a, _Tp&& __t)
-      : _Hp(std::forward<_Tp>(__t), __a) {}
-
-  __tuple_leaf(__tuple_leaf const&) = default;
-  __tuple_leaf(__tuple_leaf&&)      = default;
-
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int
-  swap(__tuple_leaf& __t) noexcept(__is_nothrow_swappable_v<__tuple_leaf>) {
-    std::swap(*this, __t);
-    return 0;
-  }
-
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int swap(const __tuple_leaf& __rhs) const
-      noexcept(__is_nothrow_swappable_v<const __tuple_leaf>) {
-    std::swap(*this, __rhs);
-    return 0;
-  }
-
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Hp& get() _NOEXCEPT { return static_cast<_Hp&>(*this); }
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const _Hp& get() const _NOEXCEPT {
-    return static_cast<const _Hp&>(*this);
-  }
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Hp& get() _NOEXCEPT { return __value_.__v; }
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const _Hp& get() const _NOEXCEPT { return __value_.__v; }
 };
 
 template <class... _Tp>
diff --git a/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.verify.cpp b/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.verify.cpp
index 4a6e3095c10198..205d88858be142 100644
--- a/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.verify.cpp
+++ b/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.verify.cpp
@@ -40,12 +40,11 @@ void F(typename CannotDeduce<std::tuple<Args...>>::type const&) {}
 
 
 void f() {
-#if TEST_HAS_BUILTIN_IDENTIFIER(__reference_binds_to_temporary)
   // Test that we emit our diagnostic from the library.
   // expected-error at tuple:* 8 {{Attempted construction of reference element binds to a temporary whose lifetime has ended}}
 
   // Good news everybody! Clang now diagnoses this for us!
-  // expected-error at tuple:* 0+ {{reference member '__value_' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
+  // expected-error at tuple:* 0+ {{reference member '__v' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
 
   {
     F<int, const std::string&>(std::make_tuple(1, "abc")); // expected-note 1 {{requested here}}
@@ -73,8 +72,4 @@ void f() {
     std::tuple<std::string &&> t2("hello"); // expected-note {{requested here}}
     std::tuple<std::string &&> t3(std::allocator_arg, alloc, "hello"); // expected-note {{requested here}}
   }
-#else
-#error force failure
-// expected-error at -1 {{force failure}}
-#endif
 }



More information about the libcxx-commits mailing list