[libc++] Fix PR20855 -- libc++ incorrectly diagnoses illegal reference binding in std::tuple.
Summary:
See https://bugs.llvm.org/show_bug.cgi?id=20855
Libc++ goes out of it's way to diagnose `std::tuple` constructions which are UB due to lifetime bugs caused by reference creation. For example:
```
// The 'const std::string&' is created *inside* the tuple constructor, and its lifetime is over before the end of the constructor call.
std::tuple<int, const std::string&> t(std::make_tuple(42, "abc"));
```
However, we are over-aggressive and we incorrectly diagnose cases such as:
```
void foo(std::tuple<int const&, int const&> const&);
foo(std::make_tuple(42, 42));
```
This patch fixes the incorrectly diagnosed cases, as well as converting the diagnostic to use the newly added Clang trait `__reference_binds_to_temporary`. The new trait allows us to diagnose cases we previously couldn't such as:
```
std::tuple<int, const std::string&> t(42, "abc");
```
Reviewers: rsmith, mclow.lists
Reviewed By: rsmith
Subscribers: cfe-commits
Differential Revision: https://reviews.llvm.org/D41977
llvm-svn: 323380
Cr-Mirrored-From: sso://chromium.googlesource.com/_direct/external/github.com/llvm/llvm-project
Cr-Mirrored-Commit: 292617e7003efdbc4dd84bc49423dc662f856fb6
diff --git a/include/tuple b/include/tuple
index 31578d1..1accb9c 100644
--- a/include/tuple
+++ b/include/tuple
@@ -173,16 +173,9 @@
template <class _Tp>
static constexpr bool __can_bind_reference() {
- using _RawTp = typename remove_reference<_Tp>::type;
- using _RawHp = typename remove_reference<_Hp>::type;
- using _CheckLValueArg = integral_constant<bool,
- is_lvalue_reference<_Tp>::value
- || is_same<_RawTp, reference_wrapper<_RawHp>>::value
- || is_same<_RawTp, reference_wrapper<typename remove_const<_RawHp>::type>>::value
- >;
- return !is_reference<_Hp>::value
- || (is_lvalue_reference<_Hp>::value && _CheckLValueArg::value)
- || (is_rvalue_reference<_Hp>::value && !is_lvalue_reference<_Tp>::value);
+#if __has_keyword(__reference_binds_to_temporary)
+ return !__reference_binds_to_temporary(_Hp, _Tp);
+#endif
}
__tuple_leaf& operator=(const __tuple_leaf&);
@@ -224,15 +217,15 @@
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
explicit __tuple_leaf(_Tp&& __t) _NOEXCEPT_((is_nothrow_constructible<_Hp, _Tp>::value))
: __value_(_VSTD::forward<_Tp>(__t))
- {static_assert(__can_bind_reference<_Tp>(),
- "Attempted to construct a reference element in a tuple with an rvalue");}
+ {static_assert(__can_bind_reference<_Tp&&>(),
+ "Attempted construction of reference element binds to a temporary whose lifetime has ended");}
template <class _Tp, class _Alloc>
_LIBCPP_INLINE_VISIBILITY
explicit __tuple_leaf(integral_constant<int, 0>, const _Alloc&, _Tp&& __t)
: __value_(_VSTD::forward<_Tp>(__t))
- {static_assert(__can_bind_reference<_Tp>(),
- "Attempted to construct a reference element in a tuple with an rvalue");}
+ {static_assert(__can_bind_reference<_Tp&&>(),
+ "Attempted construction of reference element binds to a temporary whose lifetime has ended");}
template <class _Tp, class _Alloc>
_LIBCPP_INLINE_VISIBILITY