Author: Yihan Wang Date: 2026-06-30T13:05:18+08:00 New Revision: aba63c572000e14a6ad24f403c50e90f0001dd05
URL: https://github.com/llvm/llvm-project/commit/aba63c572000e14a6ad24f403c50e90f0001dd05 DIFF: https://github.com/llvm/llvm-project/commit/aba63c572000e14a6ad24f403c50e90f0001dd05.diff LOG: [clang] The `__reference_meows_from_temporary` builtins should SFINAE friendly when the 1st type is not a reference type (#206527) Suppose that `__reference_constructs_from_temporary` is defined as: ```cpp __reference_constructs_from_temporary(_Tp, _Up); ``` A non-reference type can never bind to a temporary, so the result is always `false` for such a `_Tp`. We should short-circuit before reaching the instantiations by check the type of `_Tp`. But clang's `__reference_constructs_from_temporary` eagerly instantiates the construction of `_Up` (including the element's constructor exception specification) even when `_Tp` is not a reference, which can hard-error on misbehaved types. The following code should be accepted, but clang raise a hard error: ```cpp struct NoConv {}; struct Bad { template<class T> Bad(T v) noexcept(noexcept(member_ = v)) {} int member_; }; static_assert(!__reference_constructs_from_temporary(Bad, NoConv&&)); static_assert(!__reference_converts_from_temporary(Bad, NoConv&&)); static_assert(!__reference_binds_to_temporary(Bad, NoConv&&)); ``` The PR refine the implementation of these builtins by short-circuits on a non-reference first operand. Fixes https://github.com/llvm/llvm-project/issues/206524. --------- Signed-off-by: yronglin <[email protected]> Added: Modified: clang/docs/ReleaseNotes.md clang/lib/Sema/SemaTypeTraits.cpp clang/test/SemaCXX/type-traits.cpp Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 09ec3594ab31f..b372e5b58068b 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -729,6 +729,9 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the crash when using it with `-fms-extensions` on other platforms. (#GH184318) - Fixed a compiler crash due to an unresolved overloaded function type when calling `__builtin_bit_cast`. (#GH200112) +- Clang now SFINAE friendly when the ``__reference_meows_from_temporary`` builtins + should SFINAE friendly when the 1st type is not a reference type. (#GH206524) + #### Bug Fixes to Attribute Support diff --git a/clang/lib/Sema/SemaTypeTraits.cpp b/clang/lib/Sema/SemaTypeTraits.cpp index c79b3f7045ca6..4de73601e273d 100644 --- a/clang/lib/Sema/SemaTypeTraits.cpp +++ b/clang/lib/Sema/SemaTypeTraits.cpp @@ -1285,6 +1285,16 @@ static bool EvaluateBooleanTypeTrait(Sema &S, TypeTrait Kind, // T t(create<Args>()...); assert(!Args.empty()); + // LWG3819: For reference_meows_from_temporary traits, && is not added to + // the source object type. + // Otherwise, compute the result of add_rvalue_reference_t. + bool UseRawObjectType = + Kind == clang::BTT_ReferenceBindsToTemporary || + Kind == clang::BTT_ReferenceConstructsFromTemporary || + Kind == clang::BTT_ReferenceConvertsFromTemporary; + if (UseRawObjectType && !Args[0]->getType()->isReferenceType()) + return false; + // Precondition: T and all types in the parameter pack Args shall be // complete types, (possibly cv-qualified) void, or arrays of // unknown bound. @@ -1308,14 +1318,6 @@ static bool EvaluateBooleanTypeTrait(Sema &S, TypeTrait Kind, if (RD && RD->isAbstract()) return false; - // LWG3819: For reference_meows_from_temporary traits, && is not added to - // the source object type. - // Otherwise, compute the result of add_rvalue_reference_t. - bool UseRawObjectType = - Kind == clang::BTT_ReferenceBindsToTemporary || - Kind == clang::BTT_ReferenceConstructsFromTemporary || - Kind == clang::BTT_ReferenceConvertsFromTemporary; - llvm::BumpPtrAllocator OpaqueExprAllocator; SmallVector<Expr *, 2> ArgExprs; ArgExprs.reserve(Args.size() - 1); diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp index 8decb1f61395e..ff74461308fb1 100644 --- a/clang/test/SemaCXX/type-traits.cpp +++ b/clang/test/SemaCXX/type-traits.cpp @@ -3203,6 +3203,8 @@ class ConvertsToRefPrivate { mutable T obj = 42; }; +struct NoConv {}; +struct Bad { template<class T> Bad(T v) noexcept(noexcept(member_ = v)) {} int member_; }; void reference_binds_to_temporary_checks() { static_assert(!(__reference_binds_to_temporary(int &, int &))); @@ -3243,6 +3245,10 @@ void reference_binds_to_temporary_checks() { // Test that function references are never considered bound to temporaries. static_assert(!__reference_binds_to_temporary(void(&)(), void())); static_assert(!__reference_binds_to_temporary(void(&&)(), void())); + + // Make sure we don't emit "assigning to 'int' from incompatible type 'NoConv'" in SFINAE context. + static_assert(!__reference_binds_to_temporary(Bad, NoConv&&)); + } @@ -3325,7 +3331,8 @@ void reference_constructs_from_temporary_checks() { static_assert(!__reference_constructs_from_temporary(const int&, ExplicitConversionRef)); static_assert(!__reference_constructs_from_temporary(int&&, ExplicitConversionRvalueRef)); - + // Make sure we don't emit "assigning to 'int' from incompatible type 'NoConv'" in SFINAE context. + static_assert(!__reference_constructs_from_temporary(Bad, NoConv&&)); } template<typename A, typename B, bool result = __reference_converts_from_temporary(A, B)> @@ -3394,6 +3401,9 @@ void reference_converts_from_temporary_checks() { static_assert(!__reference_converts_from_temporary(AllPrivate, AllPrivate)); // Make sure we don't emit "calling a private constructor" in SFINAE context. static_assert(!reference_converts_from_temporary_sfinae<AllPrivate, AllPrivate>()); + + // Make sure we don't emit "assigning to 'int' from incompatible type 'NoConv'" in SFINAE context. + static_assert(!__reference_converts_from_temporary(Bad, NoConv&&)); } void array_rank() { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
