Index: docs/LanguageExtensions.rst =================================================================== --- docs/LanguageExtensions.rst +++ docs/LanguageExtensions.rst @@ -1023,6 +1023,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: include/clang/Basic/TokenKinds.def =================================================================== --- include/clang/Basic/TokenKinds.def +++ include/clang/Basic/TokenKinds.def @@ -452,6 +452,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: include/clang/Basic/TypeTraits.h =================================================================== --- include/clang/Basic/TypeTraits.h +++ include/clang/Basic/TypeTraits.h @@ -77,7 +77,8 @@ BTT_IsAssignable, BTT_IsNothrowAssignable, BTT_IsTriviallyAssignable, - BTT_Last = BTT_IsTriviallyAssignable, + BTT_ReferenceBindsToTemporary, + BTT_Last = BTT_ReferenceBindsToTemporary, TT_IsConstructible, TT_IsNothrowConstructible, TT_IsTriviallyConstructible Index: lib/Parse/ParseDeclCXX.cpp =================================================================== --- lib/Parse/ParseDeclCXX.cpp +++ lib/Parse/ParseDeclCXX.cpp @@ -1431,7 +1431,8 @@ tok::kw___is_union, tok::kw___is_unsigned, tok::kw___is_void, - tok::kw___is_volatile)) + tok::kw___is_volatile, + tok::kw___reference_binds_to_temporary)) // GNU libstdc++ 4.2 and libc++ use certain intrinsic names as the // name of struct templates, but some are keywords in GCC >= 4.3 // and Clang. Therefore, when we see the token sequence "struct Index: lib/Parse/ParseExpr.cpp =================================================================== --- lib/Parse/ParseExpr.cpp +++ lib/Parse/ParseExpr.cpp @@ -847,6 +847,7 @@ REVERTIBLE_TYPE_TRAIT(__is_unsigned); REVERTIBLE_TYPE_TRAIT(__is_void); REVERTIBLE_TYPE_TRAIT(__is_volatile); + REVERTIBLE_TYPE_TRAIT(__reference_binds_to_temporary); #undef REVERTIBLE_TYPE_TRAIT #undef RTT_JOIN } Index: lib/Sema/SemaExprCXX.cpp =================================================================== --- lib/Sema/SemaExprCXX.cpp +++ lib/Sema/SemaExprCXX.cpp @@ -4564,11 +4564,14 @@ if (Kind <= UTT_Last) return EvaluateUnaryTypeTrait(S, Kind, KWLoc, Args[0]->getType()); - if (Kind <= BTT_Last) + // Evaluate BTT_ReferenceBindsToTemporary along side 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: { @@ -4644,6 +4647,15 @@ if (Kind == clang::TT_IsConstructible) return true; + if (Kind == clang::BTT_ReferenceBindsToTemporary) { + if (!T->isReferenceType()) + return false; + + assert(isa(Result.get()) + == !Init.isDirectReferenceBinding()); + return !Init.isDirectReferenceBinding(); + } + if (Kind == clang::TT_IsNothrowConstructible) return S.canThrow(Result.get()) == CT_Cannot; Index: test/SemaCXX/type-traits.cpp =================================================================== --- test/SemaCXX/type-traits.cpp +++ test/SemaCXX/type-traits.cpp @@ -2048,6 +2048,8 @@ // PR25513 { int arr[F(__is_constructible(int(int)))]; } + + { int arr[T(__is_constructible(int const&, long))]; } } // Instantiation of __is_trivially_constructible @@ -2078,6 +2080,46 @@ { int arr[F((is_trivially_constructible::value))]; } // PR19178 } +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)))]; } + +} + void array_rank() { int t01[T(__array_rank(IntAr) == 1)]; int t02[T(__array_rank(ConstIntArAr) == 2)];