Index: include/tuple =================================================================== --- include/tuple +++ include/tuple @@ -173,16 +173,24 @@ template static constexpr bool __can_bind_reference() { +#if !__has_keyword(__reference_binds_to_temporary) using _RawTp = typename remove_reference<_Tp>::type; using _RawHp = typename remove_reference<_Hp>::type; + using _CheckLValueArg = integral_constant::value || is_same<_RawTp, reference_wrapper<_RawHp>>::value || is_same<_RawTp, reference_wrapper::type>>::value + // Allow "int&&" to bind to 'int const&' + || (is_rvalue_reference<_Tp>::value && is_const<_RawHp>::value && + is_same<_RawHp, const _RawTp>::value) >; return !is_reference<_Hp>::value || (is_lvalue_reference<_Hp>::value && _CheckLValueArg::value) || (is_rvalue_reference<_Hp>::value && !is_lvalue_reference<_Tp>::value); +#else + return !__reference_binds_to_temporary(_Hp, _Tp); +#endif } __tuple_leaf& operator=(const __tuple_leaf&); @@ -224,14 +232,14 @@ _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>(), + {static_assert(__can_bind_reference<_Tp&&>(), "Attempted to construct a reference element in a tuple with an rvalue");} template _LIBCPP_INLINE_VISIBILITY explicit __tuple_leaf(integral_constant, const _Alloc&, _Tp&& __t) : __value_(_VSTD::forward<_Tp>(__t)) - {static_assert(__can_bind_reference<_Tp>(), + {static_assert(__can_bind_reference<_Tp&&>(), "Attempted to construct a reference element in a tuple with an rvalue");} template Index: test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.fail.cpp =================================================================== --- /dev/null +++ test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.fail.cpp @@ -0,0 +1,54 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// See llvm.org/PR20855 + +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wdangling-field" +#endif + +#include +#include +#include "test_macros.h" + + +#if !TEST_HAS_BUILTIN_IDENTIFIER(__reference_binds_to_temporary) +#else +# define ASSERT_REFERENCE_BINDS_TEMPORARY(...) static_assert(true, "") +# define ASSERT_NOT_REFERENCE_BINDS_TEMPORARY(...) static_assert(true, "") +#endif + +template struct CannotDeduce { + using type = T; +}; + +template +void F(typename CannotDeduce>::type const&) {} + + +int main() { + // expected-error@tuple:* 1 {{"Attempted to construct a reference element in a tuple with an rvalue"}} + { + F(std::make_tuple(1, "abc")); // expected-note 1 {{requested here}} + } +#if TEST_HAS_BUILTIN_IDENTIFIER(__reference_binds_to_temporary) + // expected-error@tuple:* 2 {{"Attempted to construct a reference element in a tuple with an rvalue"}} + { + std::tuple t(1, "a"); // expected-note 1 {{requested here}} + } + { + F(std::tuple(1, "abc")); // expected-note 1 {{requested here}} + } +#endif +} Index: test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.pass.cpp @@ -0,0 +1,47 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// See llvm.org/PR20855 + +#include +#include +#include "test_macros.h" + +#if TEST_HAS_BUILTIN_IDENTIFIER(__reference_binds_to_temporary) +# define ASSERT_REFERENCE_BINDS_TEMPORARY(...) static_assert(__reference_binds_to_temporary(__VA_ARGS__), "") +# define ASSERT_NOT_REFERENCE_BINDS_TEMPORARY(...) static_assert(!__reference_binds_to_temporary(__VA_ARGS__), "") +#else +# define ASSERT_REFERENCE_BINDS_TEMPORARY(...) static_assert(true, "") +# define ASSERT_NOT_REFERENCE_BINDS_TEMPORARY(...) static_assert(true, "") +#endif + +static_assert(std::is_same::value, ""); +ASSERT_REFERENCE_BINDS_TEMPORARY(std::string const&, decltype("abc")); +ASSERT_REFERENCE_BINDS_TEMPORARY(std::string const&, decltype(("abc"))); +ASSERT_REFERENCE_BINDS_TEMPORARY(std::string const&, const char*&&); + +template > +void F(Tup const&) {} + +int main() { + { + F(std::make_tuple(42, 42)); + std::tuple t(std::make_tuple(42, 42)); + } + { + auto fn = &F; + fn(std::tuple(42, std::string("a"))); + fn(std::make_tuple(42, std::string("a"))); + } +}