* ``__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
======
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
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: {
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;
// 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))]; }
{ int arr[F(__is_trivially_constructible(const volatile void))]; }
}
+template <class T, class RefType = T &>
+struct ConvertsToRef {
+ operator RefType() const { return static_cast<RefType>(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<int, int &>;
+ using RRef = ConvertsToRef<int, int &&>;
+ using CLRef = ConvertsToRef<int, const int &>;
+ using LongRef = ConvertsToRef<long, long &>;
+ { 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)];