[clang] aba63c5 - [clang] The `__reference_meows_from_temporary` builtins should SFINAE friendly when the 1st type is not a reference type (#206527)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Jun 29 22:05:22 PDT 2026
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 <yronglin777 at gmail.com>
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() {
More information about the cfe-commits
mailing list