Skip to content

Commit 8f3b0b4

Browse files
committed
[clang] adds __reference_constructs_from_temporary
This is information that the compiler already has, and should be exposed so that the library doesn't need to reimplement the exact same functionality. Differential Revision: https://reviews.llvm.org/D135341
1 parent daa5da0 commit 8f3b0b4

File tree

8 files changed

+77
-10
lines changed

8 files changed

+77
-10
lines changed

clang/docs/LanguageExtensions.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1621,6 +1621,10 @@ The following type trait primitives are supported by Clang. Those traits marked
16211621
materialized temporary object. If ``T`` is not a reference type the result
16221622
is false. Note this trait will also return false when the initialization of
16231623
``T`` from ``U`` is ill-formed.
1624+
Deprecated, use ``__reference_constructs_from_temporary``.
1625+
* ``__reference_constructs_from_temporary(T, U)`` (C++)
1626+
Returns true if a reference ``T`` can be constructed from a temporary of type
1627+
a non-cv-qualified ``U``.
16241628
* ``__underlying_type`` (C++, GNU, Microsoft)
16251629

16261630
In addition, the following expression traits are supported:

clang/include/clang/Basic/TokenKinds.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,7 @@ TYPE_TRAIT_1(__is_scoped_enum, IsScopedEnum, KEYCXX)
531531
TYPE_TRAIT_1(__is_referenceable, IsReferenceable, KEYCXX)
532532
TYPE_TRAIT_1(__can_pass_in_regs, CanPassInRegs, KEYCXX)
533533
TYPE_TRAIT_2(__reference_binds_to_temporary, ReferenceBindsToTemporary, KEYCXX)
534+
TYPE_TRAIT_2(__reference_constructs_from_temporary, ReferenceConstructsFromTemporary, KEYCXX)
534535

535536
// Embarcadero Expression Traits
536537
EXPRESSION_TRAIT(__is_lvalue_expr, IsLValueExpr, KEYCXX)

clang/lib/Lex/PPMacroExpansion.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1695,6 +1695,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
16951695
.Case("__array_rank", true)
16961696
.Case("__array_extent", true)
16971697
.Case("__reference_binds_to_temporary", true)
1698+
.Case("__reference_constructs_from_temporary", true)
16981699
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) .Case("__" #Trait, true)
16991700
#include "clang/Basic/TransformTypeTraits.def"
17001701
.Default(false);

clang/lib/Parse/ParseDeclCXX.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1655,7 +1655,9 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
16551655
tok::kw___is_union,
16561656
tok::kw___is_unsigned,
16571657
tok::kw___is_void,
1658-
tok::kw___is_volatile))
1658+
tok::kw___is_volatile,
1659+
tok::kw___reference_binds_to_temporary,
1660+
tok::kw___reference_constructs_from_temporary))
16591661
// GNU libstdc++ 4.2 and libc++ use certain intrinsic names as the
16601662
// name of struct templates, but some are keywords in GCC >= 4.3
16611663
// and Clang. Therefore, when we see the token sequence "struct

clang/lib/Parse/ParseExpr.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1128,6 +1128,8 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
11281128
REVERTIBLE_TYPE_TRAIT(__is_unsigned);
11291129
REVERTIBLE_TYPE_TRAIT(__is_void);
11301130
REVERTIBLE_TYPE_TRAIT(__is_volatile);
1131+
REVERTIBLE_TYPE_TRAIT(__reference_binds_to_temporary);
1132+
REVERTIBLE_TYPE_TRAIT(__reference_constructs_from_temporary);
11311133
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) \
11321134
REVERTIBLE_TYPE_TRAIT(RTT_JOIN(__, Trait));
11331135
#include "clang/Basic/TransformTypeTraits.def"

clang/lib/Sema/SemaExprCXX.cpp

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5410,14 +5410,15 @@ static bool EvaluateBooleanTypeTrait(Sema &S, TypeTrait Kind,
54105410
if (Kind <= UTT_Last)
54115411
return EvaluateUnaryTypeTrait(S, Kind, KWLoc, Args[0]->getType());
54125412

5413-
// Evaluate BTT_ReferenceBindsToTemporary alongside the IsConstructible
5414-
// traits to avoid duplication.
5415-
if (Kind <= BTT_Last && Kind != BTT_ReferenceBindsToTemporary)
5413+
// Evaluate ReferenceBindsToTemporary and ReferenceConstructsFromTemporary
5414+
// alongside the IsConstructible traits to avoid duplication.
5415+
if (Kind <= BTT_Last && Kind != BTT_ReferenceBindsToTemporary && Kind != BTT_ReferenceConstructsFromTemporary)
54165416
return EvaluateBinaryTypeTrait(S, Kind, Args[0]->getType(),
54175417
Args[1]->getType(), RParenLoc);
54185418

54195419
switch (Kind) {
54205420
case clang::BTT_ReferenceBindsToTemporary:
5421+
case clang::BTT_ReferenceConstructsFromTemporary:
54215422
case clang::TT_IsConstructible:
54225423
case clang::TT_IsNothrowConstructible:
54235424
case clang::TT_IsTriviallyConstructible: {
@@ -5494,11 +5495,23 @@ static bool EvaluateBooleanTypeTrait(Sema &S, TypeTrait Kind,
54945495
if (Kind == clang::TT_IsConstructible)
54955496
return true;
54965497

5497-
if (Kind == clang::BTT_ReferenceBindsToTemporary) {
5498+
if (Kind == clang::BTT_ReferenceBindsToTemporary || Kind == clang::BTT_ReferenceConstructsFromTemporary) {
54985499
if (!T->isReferenceType())
54995500
return false;
55005501

5501-
return !Init.isDirectReferenceBinding();
5502+
if (!Init.isDirectReferenceBinding())
5503+
return true;
5504+
5505+
if (Kind == clang::BTT_ReferenceBindsToTemporary)
5506+
return false;
5507+
5508+
QualType U = Args[1]->getType();
5509+
if (U->isReferenceType())
5510+
return false;
5511+
5512+
QualType TPtr = S.Context.getPointerType(S.BuiltinRemoveReference(T, UnaryTransformType::RemoveCVRef, {}));
5513+
QualType UPtr = S.Context.getPointerType(S.BuiltinRemoveReference(U, UnaryTransformType::RemoveCVRef, {}));
5514+
return EvaluateBinaryTypeTrait(S, TypeTrait::BTT_IsConvertibleTo, UPtr, TPtr, RParenLoc);
55025515
}
55035516

55045517
if (Kind == clang::TT_IsNothrowConstructible)

clang/test/SemaCXX/type-traits.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2542,6 +2542,51 @@ void reference_binds_to_temporary_checks() {
25422542
{ int arr[T((__reference_binds_to_temporary(const int &, long)))]; }
25432543
}
25442544

2545+
void reference_constructs_from_temporary_checks() {
2546+
static_assert(!__reference_constructs_from_temporary(int &, int &), "");
2547+
static_assert(!__reference_constructs_from_temporary(int &, int &&), "");
2548+
2549+
static_assert(!__reference_constructs_from_temporary(int const &, int &), "");
2550+
static_assert(!__reference_constructs_from_temporary(int const &, int const &), "");
2551+
static_assert(!__reference_constructs_from_temporary(int const &, int &&), "");
2552+
2553+
static_assert(!__reference_constructs_from_temporary(int &, long &), ""); // doesn't construct
2554+
2555+
static_assert(__reference_constructs_from_temporary(int const &, long &), "");
2556+
static_assert(__reference_constructs_from_temporary(int const &, long &&), "");
2557+
static_assert(__reference_constructs_from_temporary(int &&, long &), "");
2558+
2559+
using LRef = ConvertsToRef<int, int &>;
2560+
using RRef = ConvertsToRef<int, int &&>;
2561+
using CLRef = ConvertsToRef<int, const int &>;
2562+
using LongRef = ConvertsToRef<long, long &>;
2563+
static_assert(__is_constructible(int &, LRef), "");
2564+
static_assert(!__reference_constructs_from_temporary(int &, LRef), "");
2565+
2566+
static_assert(__is_constructible(int &&, RRef), "");
2567+
static_assert(!__reference_constructs_from_temporary(int &&, RRef), "");
2568+
2569+
static_assert(__is_constructible(int const &, CLRef), "");
2570+
static_assert(!__reference_constructs_from_temporary(int &&, CLRef), "");
2571+
2572+
static_assert(__is_constructible(int const &, LongRef), "");
2573+
static_assert(__reference_constructs_from_temporary(int const &, LongRef), "");
2574+
2575+
// Test that it doesn't accept non-reference types as input.
2576+
static_assert(!__reference_constructs_from_temporary(int, long), "");
2577+
2578+
static_assert(__reference_constructs_from_temporary(const int &, long), "");
2579+
2580+
// Additional checks
2581+
static_assert(__reference_constructs_from_temporary(POD const&, Derives), "");
2582+
static_assert(__reference_constructs_from_temporary(int&&, int), "");
2583+
static_assert(__reference_constructs_from_temporary(const int&, int), "");
2584+
static_assert(!__reference_constructs_from_temporary(int&&, int&&), "");
2585+
static_assert(!__reference_constructs_from_temporary(const int&, int&&), "");
2586+
static_assert(__reference_constructs_from_temporary(int&&, long&&), "");
2587+
static_assert(__reference_constructs_from_temporary(int&&, long), "");
2588+
}
2589+
25452590
void array_rank() {
25462591
int t01[T(__array_rank(IntAr) == 1)];
25472592
int t02[T(__array_rank(ConstIntArAr) == 2)];

clang/www/cxx_status.html

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -292,10 +292,9 @@ <h2 id="cxx23">C++23 implementation status</h2>
292292
<td><a href="https://wg21.link/P2255R2">P2255R2</a></td>
293293
<td class="partial" align="center">
294294
<details><summary>Partial</summary>
295-
Clang provides a <tt>__reference_binds_to_temporary</tt> type trait
296-
builtin, with which the library facility can be partially implemented.
297-
Both <tt>__reference_constructs_from_temporary</tt> and
298-
<tt>__reference_converts_from_temporary</tt> builtins should be
295+
Clang provides <tt>__reference_constructs_from_temporary</tt> type
296+
trait builtin, with which <tt>std::reference_constructs_from_temporary</tt>
297+
is implemented. <tt>__reference_converts_from_temporary</tt> needs to be
299298
provided, following the normal cross-vendor convention to implement
300299
traits requiring compiler support directly.
301300
</details></td>

0 commit comments

Comments
 (0)