Index: cfe/trunk/docs/LanguageExtensions.rst =================================================================== --- cfe/trunk/docs/LanguageExtensions.rst +++ cfe/trunk/docs/LanguageExtensions.rst @@ -1096,6 +1096,11 @@ * ``__is_constructible`` (MSVC 2013, clang) * ``__is_nothrow_constructible`` (MSVC 2013, clang) * ``__is_assignable`` (MSVC 2015, clang) +* ``__reference_binds_to_temporary(T, U)`` (Clang): Determines whether a + reference of type ``T`` bound to an expression of type ``U`` would bind to a + materialized temporary object. If ``T`` is not a reference type the result + is false. Note this trait will also return false when the initialization of + ``T`` from ``U`` is ill-formed. Blocks ====== Index: cfe/trunk/include/clang/Basic/TokenKinds.def =================================================================== --- cfe/trunk/include/clang/Basic/TokenKinds.def +++ cfe/trunk/include/clang/Basic/TokenKinds.def @@ -464,6 +464,7 @@ TYPE_TRAIT_N(__is_trivially_constructible, IsTriviallyConstructible, KEYCXX) TYPE_TRAIT_1(__is_trivially_copyable, IsTriviallyCopyable, KEYCXX) TYPE_TRAIT_2(__is_trivially_assignable, IsTriviallyAssignable, KEYCXX) +TYPE_TRAIT_2(__reference_binds_to_temporary, ReferenceBindsToTemporary, KEYCXX) KEYWORD(__underlying_type , KEYCXX) // Embarcadero Expression Traits Index: cfe/trunk/include/clang/Basic/TypeTraits.h =================================================================== --- cfe/trunk/include/clang/Basic/TypeTraits.h +++ cfe/trunk/include/clang/Basic/TypeTraits.h @@ -80,7 +80,8 @@ BTT_IsAssignable, BTT_IsNothrowAssignable, BTT_IsTriviallyAssignable, - BTT_Last = BTT_IsTriviallyAssignable, + BTT_ReferenceBindsToTemporary, + BTT_Last = BTT_ReferenceBindsToTemporary, TT_IsConstructible, TT_IsNothrowConstructible, TT_IsTriviallyConstructible Index: cfe/trunk/lib/Sema/SemaExprCXX.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaExprCXX.cpp +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp @@ -4645,11 +4645,14 @@ if (Kind <= UTT_Last) return EvaluateUnaryTypeTrait(S, Kind, KWLoc, Args[0]->getType()); - if (Kind <= BTT_Last) + // Evaluate BTT_ReferenceBindsToTemporary alongside the IsConstructible + // traits to avoid duplication. + if (Kind <= BTT_Last && Kind != BTT_ReferenceBindsToTemporary) return EvaluateBinaryTypeTrait(S, Kind, Args[0]->getType(), Args[1]->getType(), RParenLoc); switch (Kind) { + case clang::BTT_ReferenceBindsToTemporary: case clang::TT_IsConstructible: case clang::TT_IsNothrowConstructible: case clang::TT_IsTriviallyConstructible: { @@ -4726,6 +4729,13 @@ if (Kind == clang::TT_IsConstructible) return true; + if (Kind == clang::BTT_ReferenceBindsToTemporary) { + if (!T->isReferenceType()) + return false; + + return !Init.isDirectReferenceBinding(); + } + if (Kind == clang::TT_IsNothrowConstructible) return S.canThrow(Result.get()) == CT_Cannot; Index: cfe/trunk/test/SemaCXX/type-traits.cpp =================================================================== --- cfe/trunk/test/SemaCXX/type-traits.cpp +++ cfe/trunk/test/SemaCXX/type-traits.cpp @@ -2225,6 +2225,7 @@ // PR25513 { int arr[F(__is_constructible(int(int)))]; } + { int arr[T(__is_constructible(int const &, long))]; } { int arr[T(__is_constructible(ACompleteType))]; } { int arr[T(__is_nothrow_constructible(ACompleteType))]; } @@ -2275,6 +2276,47 @@ { int arr[F(__is_trivially_constructible(const volatile void))]; } } +template +struct ConvertsToRef { + operator RefType() const { return static_cast(obj); } + mutable T obj = 42; +}; + +void reference_binds_to_temporary_checks() { + { int arr[F((__reference_binds_to_temporary(int &, int &)))]; } + { int arr[F((__reference_binds_to_temporary(int &, int &&)))]; } + + { int arr[F((__reference_binds_to_temporary(int const &, int &)))]; } + { int arr[F((__reference_binds_to_temporary(int const &, int const &)))]; } + { int arr[F((__reference_binds_to_temporary(int const &, int &&)))]; } + + { int arr[F((__reference_binds_to_temporary(int &, long &)))]; } // doesn't construct + { int arr[T((__reference_binds_to_temporary(int const &, long &)))]; } + { int arr[T((__reference_binds_to_temporary(int const &, long &&)))]; } + { int arr[T((__reference_binds_to_temporary(int &&, long &)))]; } + + using LRef = ConvertsToRef; + using RRef = ConvertsToRef; + using CLRef = ConvertsToRef; + using LongRef = ConvertsToRef; + { int arr[T((__is_constructible(int &, LRef)))]; } + { int arr[F((__reference_binds_to_temporary(int &, LRef)))]; } + + { int arr[T((__is_constructible(int &&, RRef)))]; } + { int arr[F((__reference_binds_to_temporary(int &&, RRef)))]; } + + { int arr[T((__is_constructible(int const &, CLRef)))]; } + { int arr[F((__reference_binds_to_temporary(int &&, CLRef)))]; } + + { int arr[T((__is_constructible(int const &, LongRef)))]; } + { int arr[T((__reference_binds_to_temporary(int const &, LongRef)))]; } + + // Test that it doesn't accept non-reference types as input. + { int arr[F((__reference_binds_to_temporary(int, long)))]; } + + { int arr[T((__reference_binds_to_temporary(const int &, long)))]; } +} + void array_rank() { int t01[T(__array_rank(IntAr) == 1)]; int t02[T(__array_rank(ConstIntArAr) == 2)];