[clang] [Clang] Implement LWG3819 for `__reference_meows_from_temporary` (PR #142554)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Jun 3 00:33:23 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: A. Jiang (frederick-vs-ja)
<details>
<summary>Changes</summary>
Also fix use cases for function reference binding (`__reference_binds_to_temporary` is also affected despite being deprecated).
Fixes #<!-- -->114344. Towards #<!-- -->105079.
---
Full diff: https://github.com/llvm/llvm-project/pull/142554.diff
3 Files Affected:
- (modified) clang/docs/ReleaseNotes.rst (+9)
- (modified) clang/lib/Sema/SemaTypeTraits.cpp (+20-6)
- (modified) clang/test/SemaCXX/type-traits.cpp (+32)
``````````diff
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 536525da8a628..e6d4309d7ddb3 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -698,6 +698,15 @@ Bug Fixes to Compiler Builtins
are ``__builtin_is_cpp_trivially_relocatable``. It is recommended to use
``__builtin_trivially_relocate`` instead.
+- ``__reference_binds_to_temporary``, ``__reference_constructs_from_temporary``
+ and ``__reference_converts_from_temporary`` intrinsics no longer consider
+ function references can bind to temporary objects. (#GH114344)
+
+- ``__reference_constructs_from_temporary`` and
+ ``__reference_converts_from_temporary`` intrinsics detect reference binding
+ to prvalue instead of xvalue now if the second operand is an object type, per
+ `LWG3819 <https://cplusplus.github.io/LWG/issue3819>`_.
+
Bug Fixes to Attribute Support
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed crash when a parameter to the ``clang::annotate`` attribute evaluates to ``void``. See #GH119125
diff --git a/clang/lib/Sema/SemaTypeTraits.cpp b/clang/lib/Sema/SemaTypeTraits.cpp
index 04f54d7044e4f..8578521e59cd7 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -1183,9 +1183,14 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT,
const TypeSourceInfo *Rhs,
SourceLocation KeyLoc);
+namespace {
+enum class ConvertibilityFrom { RawType, RefType };
+} // namespace
+
static ExprResult CheckConvertibilityForTypeTraits(
Sema &Self, const TypeSourceInfo *Lhs, const TypeSourceInfo *Rhs,
- SourceLocation KeyLoc, llvm::BumpPtrAllocator &OpaqueExprAllocator) {
+ SourceLocation KeyLoc, llvm::BumpPtrAllocator &OpaqueExprAllocator,
+ ConvertibilityFrom ConvChk) {
QualType LhsT = Lhs->getType();
QualType RhsT = Rhs->getType();
@@ -1224,8 +1229,11 @@ static ExprResult CheckConvertibilityForTypeTraits(
Self.isAbstractType(Rhs->getTypeLoc().getBeginLoc(), RhsT))
return ExprError();
- // Compute the result of add_rvalue_reference.
- if (LhsT->isObjectType() || LhsT->isFunctionType())
+ // LWG3819: For reference_meows_from_temporary traits, && is not added to the
+ // source object type.
+ // Otherwise, compute the result of add_rvalue_reference.
+ if ((LhsT->isObjectType() && ConvChk == ConvertibilityFrom::RefType) ||
+ LhsT->isFunctionType())
LhsT = Self.Context.getRValueReferenceType(LhsT);
// Build a fake source and destination for initialization.
@@ -1386,6 +1394,10 @@ static bool EvaluateBooleanTypeTrait(Sema &S, TypeTrait Kind,
if (!T->isReferenceType())
return false;
+ // A function reference never binds to a temporary object.
+ if (T.getNonReferenceType()->isFunctionType())
+ return false;
+
if (!Init.isDirectReferenceBinding())
return true;
@@ -1401,7 +1413,8 @@ static bool EvaluateBooleanTypeTrait(Sema &S, TypeTrait Kind,
TypeSourceInfo *UPtr = S.Context.CreateTypeSourceInfo(
S.Context.getPointerType(U.getNonReferenceType()));
return !CheckConvertibilityForTypeTraits(S, UPtr, TPtr, RParenLoc,
- OpaqueExprAllocator)
+ OpaqueExprAllocator,
+ ConvertibilityFrom::RawType)
.isInvalid();
}
@@ -1654,8 +1667,9 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT,
if (RhsT->isVoidType())
return LhsT->isVoidType();
llvm::BumpPtrAllocator OpaqueExprAllocator;
- ExprResult Result = CheckConvertibilityForTypeTraits(Self, Lhs, Rhs, KeyLoc,
- OpaqueExprAllocator);
+ ExprResult Result = CheckConvertibilityForTypeTraits(
+ Self, Lhs, Rhs, KeyLoc, OpaqueExprAllocator,
+ ConvertibilityFrom::RefType);
if (Result.isInvalid())
return false;
diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp
index 56cca05402f45..15fe99c86f30e 100644
--- a/clang/test/SemaCXX/type-traits.cpp
+++ b/clang/test/SemaCXX/type-traits.cpp
@@ -3143,6 +3143,10 @@ void reference_binds_to_temporary_checks() {
static_assert(!(__reference_binds_to_temporary(int, long)));
static_assert((__reference_binds_to_temporary(const int &, long)));
+
+ // 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()));
}
@@ -3156,6 +3160,14 @@ struct ExplicitConversionRef {
explicit operator int&();
};
+struct NonMovable {
+ NonMovable(NonMovable&&) = delete;
+};
+
+struct ConvertsFromNonMovable {
+ ConvertsFromNonMovable(NonMovable);
+};
+
void reference_constructs_from_temporary_checks() {
static_assert(!__reference_constructs_from_temporary(int &, int &));
static_assert(!__reference_constructs_from_temporary(int &, int &&));
@@ -3193,6 +3205,16 @@ void reference_constructs_from_temporary_checks() {
static_assert(__reference_constructs_from_temporary(const int &, long));
+ // Test that function references are never considered bound to temporaries.
+ static_assert(!__reference_constructs_from_temporary(void(&&)(), void()));
+ static_assert(!__reference_constructs_from_temporary(void(&)(), void()));
+
+ // LWG3819: reference_meows_from_temporary should not use is_meowible
+ static_assert(__reference_constructs_from_temporary(ConvertsFromNonMovable&&, NonMovable));
+ // For scalar types, cv-qualifications are dropped first for prvalues.
+ static_assert(__reference_constructs_from_temporary(int&&, const int));
+ static_assert(__reference_constructs_from_temporary(int&&, volatile int));
+
// Additional checks
static_assert(__reference_constructs_from_temporary(POD const&, Derives));
static_assert(__reference_constructs_from_temporary(int&&, int));
@@ -3250,6 +3272,16 @@ void reference_converts_from_temporary_checks() {
static_assert(__reference_converts_from_temporary(const int &, long));
+ // Test that function references are never considered bound to temporaries.
+ static_assert(!__reference_converts_from_temporary(void(&)(), void()));
+ static_assert(!__reference_converts_from_temporary(void(&&)(), void()));
+
+ // LWG3819: reference_meows_from_temporary should not use is_meowible
+ static_assert(__reference_converts_from_temporary(ConvertsFromNonMovable&&, NonMovable));
+ // For scalar types, cv-qualifications are dropped first for prvalues.
+ static_assert(__reference_converts_from_temporary(int&&, const int));
+ static_assert(__reference_converts_from_temporary(int&&, volatile int));
+
// Additional checks
static_assert(__reference_converts_from_temporary(POD const&, Derives));
static_assert(__reference_converts_from_temporary(int&&, int));
``````````
</details>
https://github.com/llvm/llvm-project/pull/142554
More information about the cfe-commits
mailing list