Index: docs/LanguageExtensions.rst =================================================================== --- docs/LanguageExtensions.rst +++ docs/LanguageExtensions.rst @@ -1067,6 +1067,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 @@ -462,6 +462,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 @@ -18,87 +18,85 @@ namespace clang { /// \brief Names for traits that operate specifically on types. - enum TypeTrait { - UTT_HasNothrowAssign, - UTT_HasNothrowMoveAssign, - UTT_HasNothrowCopy, - UTT_HasNothrowConstructor, - UTT_HasTrivialAssign, - UTT_HasTrivialMoveAssign, - UTT_HasTrivialCopy, - UTT_HasTrivialDefaultConstructor, - UTT_HasTrivialMoveConstructor, - UTT_HasTrivialDestructor, - UTT_HasVirtualDestructor, - UTT_IsAbstract, - UTT_IsAggregate, - UTT_IsArithmetic, - UTT_IsArray, - UTT_IsClass, - UTT_IsCompleteType, - UTT_IsCompound, - UTT_IsConst, - UTT_IsDestructible, - UTT_IsEmpty, - UTT_IsEnum, - UTT_IsFinal, - UTT_IsFloatingPoint, - UTT_IsFunction, - UTT_IsFundamental, - UTT_IsIntegral, - UTT_IsInterfaceClass, - UTT_IsLiteral, - UTT_IsLvalueReference, - UTT_IsMemberFunctionPointer, - UTT_IsMemberObjectPointer, - UTT_IsMemberPointer, - UTT_IsNothrowDestructible, - UTT_IsObject, - UTT_IsPOD, - UTT_IsPointer, - UTT_IsPolymorphic, - UTT_IsReference, - UTT_IsRvalueReference, - UTT_IsScalar, - UTT_IsSealed, - UTT_IsSigned, - UTT_IsStandardLayout, - UTT_IsTrivial, - UTT_IsTriviallyCopyable, - UTT_IsTriviallyDestructible, - UTT_IsUnion, - UTT_IsUnsigned, - UTT_IsVoid, - UTT_IsVolatile, - UTT_HasUniqueObjectRepresentations, - UTT_Last = UTT_HasUniqueObjectRepresentations, - BTT_IsBaseOf, - BTT_IsConvertible, - BTT_IsConvertibleTo, - BTT_IsSame, - BTT_TypeCompatible, - BTT_IsAssignable, - BTT_IsNothrowAssignable, - BTT_IsTriviallyAssignable, - BTT_Last = BTT_IsTriviallyAssignable, - TT_IsConstructible, - TT_IsNothrowConstructible, - TT_IsTriviallyConstructible - }; +enum TypeTrait { + UTT_HasNothrowAssign, + UTT_HasNothrowMoveAssign, + UTT_HasNothrowCopy, + UTT_HasNothrowConstructor, + UTT_HasTrivialAssign, + UTT_HasTrivialMoveAssign, + UTT_HasTrivialCopy, + UTT_HasTrivialDefaultConstructor, + UTT_HasTrivialMoveConstructor, + UTT_HasTrivialDestructor, + UTT_HasVirtualDestructor, + UTT_IsAbstract, + UTT_IsAggregate, + UTT_IsArithmetic, + UTT_IsArray, + UTT_IsClass, + UTT_IsCompleteType, + UTT_IsCompound, + UTT_IsConst, + UTT_IsDestructible, + UTT_IsEmpty, + UTT_IsEnum, + UTT_IsFinal, + UTT_IsFloatingPoint, + UTT_IsFunction, + UTT_IsFundamental, + UTT_IsIntegral, + UTT_IsInterfaceClass, + UTT_IsLiteral, + UTT_IsLvalueReference, + UTT_IsMemberFunctionPointer, + UTT_IsMemberObjectPointer, + UTT_IsMemberPointer, + UTT_IsNothrowDestructible, + UTT_IsObject, + UTT_IsPOD, + UTT_IsPointer, + UTT_IsPolymorphic, + UTT_IsReference, + UTT_IsRvalueReference, + UTT_IsScalar, + UTT_IsSealed, + UTT_IsSigned, + UTT_IsStandardLayout, + UTT_IsTrivial, + UTT_IsTriviallyCopyable, + UTT_IsTriviallyDestructible, + UTT_IsUnion, + UTT_IsUnsigned, + UTT_IsVoid, + UTT_IsVolatile, + UTT_HasUniqueObjectRepresentations, + UTT_Last = UTT_HasUniqueObjectRepresentations, + BTT_IsBaseOf, + BTT_IsConvertible, + BTT_IsConvertibleTo, + BTT_IsSame, + BTT_TypeCompatible, + BTT_IsAssignable, + BTT_IsNothrowAssignable, + BTT_IsTriviallyAssignable, + BTT_ReferenceBindsToTemporary, + BTT_Last = BTT_ReferenceBindsToTemporary, + TT_IsConstructible, + TT_IsNothrowConstructible, + TT_IsTriviallyConstructible +}; - /// \brief Names for the array type traits. - enum ArrayTypeTrait { - ATT_ArrayRank, - ATT_ArrayExtent - }; +/// \brief Names for the array type traits. +enum ArrayTypeTrait { ATT_ArrayRank, ATT_ArrayExtent }; - /// \brief Names for the "expression or type" traits. - enum UnaryExprOrTypeTrait { - UETT_SizeOf, - UETT_AlignOf, - UETT_VecStep, - UETT_OpenMPRequiredSimdAlign, - }; +/// \brief Names for the "expression or type" traits. +enum UnaryExprOrTypeTrait { + UETT_SizeOf, + UETT_AlignOf, + UETT_VecStep, + UETT_OpenMPRequiredSimdAlign, +}; } #endif Index: lib/Parse/ParseDeclCXX.cpp =================================================================== --- lib/Parse/ParseDeclCXX.cpp +++ lib/Parse/ParseDeclCXX.cpp @@ -1404,61 +1404,32 @@ // C++11 attributes SourceLocation AttrFixitLoc = Tok.getLocation(); - if (TagType == DeclSpec::TST_struct && - Tok.isNot(tok::identifier) && - !Tok.isAnnotation() && - Tok.getIdentifierInfo() && - Tok.isOneOf(tok::kw___is_abstract, - tok::kw___is_aggregate, - tok::kw___is_arithmetic, - tok::kw___is_array, - tok::kw___is_assignable, - tok::kw___is_base_of, - tok::kw___is_class, - tok::kw___is_complete_type, - tok::kw___is_compound, - tok::kw___is_const, - tok::kw___is_constructible, - tok::kw___is_convertible, - tok::kw___is_convertible_to, - tok::kw___is_destructible, - tok::kw___is_empty, - tok::kw___is_enum, - tok::kw___is_floating_point, - tok::kw___is_final, - tok::kw___is_function, - tok::kw___is_fundamental, - tok::kw___is_integral, - tok::kw___is_interface_class, - tok::kw___is_literal, - tok::kw___is_lvalue_expr, - tok::kw___is_lvalue_reference, - tok::kw___is_member_function_pointer, - tok::kw___is_member_object_pointer, - tok::kw___is_member_pointer, - tok::kw___is_nothrow_assignable, - tok::kw___is_nothrow_constructible, - tok::kw___is_nothrow_destructible, - tok::kw___is_object, - tok::kw___is_pod, - tok::kw___is_pointer, - tok::kw___is_polymorphic, - tok::kw___is_reference, - tok::kw___is_rvalue_expr, - tok::kw___is_rvalue_reference, - tok::kw___is_same, - tok::kw___is_scalar, - tok::kw___is_sealed, - tok::kw___is_signed, - tok::kw___is_standard_layout, - tok::kw___is_trivial, - tok::kw___is_trivially_assignable, - tok::kw___is_trivially_constructible, - tok::kw___is_trivially_copyable, - tok::kw___is_union, - tok::kw___is_unsigned, - tok::kw___is_void, - tok::kw___is_volatile)) + if (TagType == DeclSpec::TST_struct && Tok.isNot(tok::identifier) && + !Tok.isAnnotation() && Tok.getIdentifierInfo() && + Tok.isOneOf( + tok::kw___is_abstract, tok::kw___is_aggregate, + tok::kw___is_arithmetic, tok::kw___is_array, tok::kw___is_assignable, + tok::kw___is_base_of, tok::kw___is_class, tok::kw___is_complete_type, + tok::kw___is_compound, tok::kw___is_const, tok::kw___is_constructible, + tok::kw___is_convertible, tok::kw___is_convertible_to, + tok::kw___is_destructible, tok::kw___is_empty, tok::kw___is_enum, + tok::kw___is_floating_point, tok::kw___is_final, + tok::kw___is_function, tok::kw___is_fundamental, + tok::kw___is_integral, tok::kw___is_interface_class, + tok::kw___is_literal, tok::kw___is_lvalue_expr, + tok::kw___is_lvalue_reference, tok::kw___is_member_function_pointer, + tok::kw___is_member_object_pointer, tok::kw___is_member_pointer, + tok::kw___is_nothrow_assignable, tok::kw___is_nothrow_constructible, + tok::kw___is_nothrow_destructible, tok::kw___is_object, + tok::kw___is_pod, tok::kw___is_pointer, tok::kw___is_polymorphic, + tok::kw___is_reference, tok::kw___is_rvalue_expr, + tok::kw___is_rvalue_reference, tok::kw___is_same, tok::kw___is_scalar, + tok::kw___is_sealed, tok::kw___is_signed, + tok::kw___is_standard_layout, tok::kw___is_trivial, + tok::kw___is_trivially_assignable, + tok::kw___is_trivially_constructible, tok::kw___is_trivially_copyable, + tok::kw___is_union, tok::kw___is_unsigned, tok::kw___is_void, + 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 @@ -900,6 +900,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 @@ -4629,11 +4629,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: { @@ -4710,6 +4713,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: test/SemaCXX/type-traits.cpp =================================================================== --- test/SemaCXX/type-traits.cpp +++ 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)];