Index: docs/LanguageExtensions.rst =================================================================== --- docs/LanguageExtensions.rst +++ docs/LanguageExtensions.rst @@ -996,6 +996,12 @@ * ``__is_base_of`` (GNU, Microsoft) * ``__is_class`` (GNU, Microsoft) * ``__is_convertible_to`` (Microsoft) +* ``__is_direct_constructible(type, argtypes...)`` (Clang): Determines whether a + value of type ``type`` can be direct-initialized with arguments of types + ``argtypes...`` with the added condition that if ``type`` is a reference type + it cannot be initialized from a materialized temporary. This trait is used + to check if construction of a reference is safe in contexts where lifetime + extensions doesn't apply. * ``__is_empty`` (GNU, Microsoft) * ``__is_enum`` (GNU, Microsoft) * ``__is_interface_class`` (Microsoft) Index: include/clang/Basic/TokenKinds.def =================================================================== --- include/clang/Basic/TokenKinds.def +++ include/clang/Basic/TokenKinds.def @@ -415,6 +415,7 @@ TYPE_TRAIT_2(__is_nothrow_assignable, IsNothrowAssignable, KEYCXX) TYPE_TRAIT_N(__is_constructible, IsConstructible, KEYCXX) TYPE_TRAIT_N(__is_nothrow_constructible, IsNothrowConstructible, KEYCXX) +TYPE_TRAIT_N(__is_direct_constructible, IsDirectConstructible, KEYCXX) // MSVC14.0 / VS2015 Type Traits TYPE_TRAIT_2(__is_assignable, IsAssignable, KEYCXX) Index: include/clang/Basic/TypeTraits.h =================================================================== --- include/clang/Basic/TypeTraits.h +++ include/clang/Basic/TypeTraits.h @@ -79,6 +79,7 @@ BTT_IsTriviallyAssignable, BTT_Last = BTT_IsTriviallyAssignable, TT_IsConstructible, + TT_IsDirectConstructible, TT_IsNothrowConstructible, TT_IsTriviallyConstructible }; Index: lib/Parse/ParseDeclCXX.cpp =================================================================== --- lib/Parse/ParseDeclCXX.cpp +++ lib/Parse/ParseDeclCXX.cpp @@ -1394,6 +1394,7 @@ tok::kw___is_constructible, tok::kw___is_convertible, tok::kw___is_convertible_to, + tok::kw___is_direct_constructible, tok::kw___is_destructible, tok::kw___is_empty, tok::kw___is_enum, Index: lib/Parse/ParseExpr.cpp =================================================================== --- lib/Parse/ParseExpr.cpp +++ lib/Parse/ParseExpr.cpp @@ -809,6 +809,7 @@ REVERTIBLE_TYPE_TRAIT(__is_constructible); REVERTIBLE_TYPE_TRAIT(__is_convertible); REVERTIBLE_TYPE_TRAIT(__is_convertible_to); + REVERTIBLE_TYPE_TRAIT(__is_direct_constructible); REVERTIBLE_TYPE_TRAIT(__is_destructible); REVERTIBLE_TYPE_TRAIT(__is_empty); REVERTIBLE_TYPE_TRAIT(__is_enum); Index: lib/Sema/SemaExprCXX.cpp =================================================================== --- lib/Sema/SemaExprCXX.cpp +++ lib/Sema/SemaExprCXX.cpp @@ -4570,6 +4570,7 @@ switch (Kind) { case clang::TT_IsConstructible: + case clang::TT_IsDirectConstructible: case clang::TT_IsNothrowConstructible: case clang::TT_IsTriviallyConstructible: { // C++11 [meta.unary.prop]: @@ -4644,6 +4645,13 @@ if (Kind == clang::TT_IsConstructible) return true; + if (Kind == clang::TT_IsDirectConstructible) { + if (!T->isReferenceType()) + return true; + + 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,29 @@ { int arr[F((is_trivially_constructible::value))]; } // PR19178 } +struct MultiInit { + template + MultiInit(Args&&...) {} +}; + +void direct_constructible_checks() { + { int arr[T((__is_direct_constructible(int&, int&)))]; } + { int arr[F((__is_direct_constructible(int&, int&&)))]; } + + { int arr[T((__is_direct_constructible(int const&, int&)))]; } + { int arr[T((__is_direct_constructible(int const&, int const&)))]; } + { int arr[T((__is_direct_constructible(int const&, int&&)))]; } + + { int arr[F((__is_direct_constructible(int&, long &)))]; } + { int arr[F((__is_direct_constructible(int &&, long &)))]; } + { int arr[F((__is_direct_constructible(MultiInit&&, long, int, void*)))]; } + { int arr[F((__is_direct_constructible(MultiInit&&, MultiInit const&)))]; } + + // Test that it works like __is_constructible on object types. + { int arr[T((__is_direct_constructible(int, long)))]; } + { int arr[T((__is_direct_constructible(MultiInit, long, int, void*)))]; } +} + void array_rank() { int t01[T(__array_rank(IntAr) == 1)]; int t02[T(__array_rank(ConstIntArAr) == 2)];