Skip to content

[Clang] Implement LWG3819 for __reference_meows_from_temporary #142554

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,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
Expand Down
15 changes: 14 additions & 1 deletion clang/lib/Sema/SemaTypeTraits.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1343,12 +1343,21 @@ static bool EvaluateBooleanTypeTrait(Sema &S, TypeTrait Kind,
if (RD && RD->isAbstract())
return false;

// LWG3819: For reference_meows_from_temporary traits, && is not added to
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I see reference_meows_from_temporary in LWG3819 but I don't get it. Maybe this require some explanation or at least a pointer to an issues that explains it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Formerly, reference_meows_from_temporary requires is_constructible, which in turn depends on declval ([meta.rel]/5). And for each object type U, the return type of declval<U> is U&&. As a result, both binding to U (prvalue) and binding to U&& (xvalue) were required.

LWG3819 removed such dependency, and then reference_meows_from_temporary traits only rely on binding to U prvalue when U is an object type.

Do we want to expand the whole story in the comments?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I apologize, maybe I am just being dense but is this some sort of inside joke or word play? Within the draft I do not find reference_meows_from_temporary or is_meowible. So there reference is quite opaque.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After some offline discussion I now get that meow is basically an X which can be replaced a series of terms, this case converts/constructs.

I still think this will confusing to anyone not already familiar w/ LWG but I don't have a good replacement suggestion.

// 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);
for (unsigned I = 1, N = Args.size(); I != N; ++I) {
QualType ArgTy = Args[I]->getType();
if (ArgTy->isObjectType() || ArgTy->isFunctionType())
if ((ArgTy->isObjectType() && !UseRawObjectType) ||
ArgTy->isFunctionType())
ArgTy = S.Context.getRValueReferenceType(ArgTy);
ArgExprs.push_back(
new (OpaqueExprAllocator.Allocate<OpaqueValueExpr>())
Expand Down Expand Up @@ -1386,6 +1395,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;

Expand Down
32 changes: 32 additions & 0 deletions clang/test/SemaCXX/type-traits.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()));
}


Expand All @@ -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 &&));
Expand Down Expand Up @@ -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) == __cplusplus >= 201703L);
// 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));
Expand Down Expand Up @@ -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) == __cplusplus >= 201703L);
// 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));
Expand Down
Loading