Skip to content

Commit e718403

Browse files
authored
[Clang] Implement C++26 P2748R5 "Disallow Binding a Returned Glvalue to a Temporary" (llvm#89942)
Implement P2748R5 "Disallow Binding a Returned Glvalue to a Temporary" https://wg21.link/P2748R5 --------- Signed-off-by: yronglin <[email protected]>
1 parent 37ae4ad commit e718403

File tree

7 files changed

+69
-4
lines changed

7 files changed

+69
-4
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ C++2c Feature Support
145145

146146
- Implemented `P0609R3: Attributes for Structured Bindings <https://wg21.link/P0609R3>`_
147147

148+
- Implemented `P2748R5 Disallow Binding a Returned Glvalue to a Temporary <https://wg21.link/P2748R5>`_.
148149

149150
Resolutions to C++ Defect Reports
150151
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9950,6 +9950,8 @@ def warn_ret_stack_addr_ref : Warning<
99509950
def warn_ret_local_temp_addr_ref : Warning<
99519951
"returning %select{address of|reference to}0 local temporary object">,
99529952
InGroup<ReturnStackAddress>;
9953+
def err_ret_local_temp_ref : Error<
9954+
"returning reference to local temporary object">;
99539955
def warn_ret_addr_label : Warning<
99549956
"returning address of label, which is local">,
99559957
InGroup<ReturnStackAddress>;

clang/lib/Sema/SemaInit.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8340,8 +8340,17 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
83408340
<< Entity.getType()->isReferenceType() << CLE->getInitializer() << 2
83418341
<< DiagRange;
83428342
} else {
8343-
Diag(DiagLoc, diag::warn_ret_local_temp_addr_ref)
8344-
<< Entity.getType()->isReferenceType() << DiagRange;
8343+
// P2748R5: Disallow Binding a Returned Glvalue to a Temporary.
8344+
// [stmt.return]/p6: In a function whose return type is a reference,
8345+
// other than an invented function for std::is_convertible ([meta.rel]),
8346+
// a return statement that binds the returned reference to a temporary
8347+
// expression ([class.temporary]) is ill-formed.
8348+
if (getLangOpts().CPlusPlus26 && Entity.getType()->isReferenceType())
8349+
Diag(DiagLoc, diag::err_ret_local_temp_ref)
8350+
<< Entity.getType()->isReferenceType() << DiagRange;
8351+
else
8352+
Diag(DiagLoc, diag::warn_ret_local_temp_addr_ref)
8353+
<< Entity.getType()->isReferenceType() << DiagRange;
83458354
}
83468355
break;
83478356
}

clang/test/CXX/drs/cwg650.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// RUN: %clang_cc1 -std=c++17 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK
55
// RUN: %clang_cc1 -std=c++20 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK
66
// RUN: %clang_cc1 -std=c++23 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK
7-
// RUN: %clang_cc1 -std=c++2c %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK
7+
// We aren't testing this since C++26 because of P2748R5 "Disallow Binding a Returned Glvalue to a Temporary".
88

99
#if __cplusplus == 199711L
1010
#define NOTHROW throw()
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// RUN: %clang_cc1 -std=c++26 -fsyntax-only -verify %s
2+
3+
auto&& f1() {
4+
return 42; // expected-error{{returning reference to local temporary object}}
5+
}
6+
const double& f2() {
7+
static int x = 42;
8+
return x; // expected-error{{returning reference to local temporary object}}
9+
}
10+
auto&& id(auto&& r) {
11+
return static_cast<decltype(r)&&>(r);
12+
}
13+
auto&& f3() {
14+
return id(42); // OK, but probably a bug
15+
}
16+
17+
void unevaluated() {
18+
using a = decltype ([] () -> const int & {
19+
const int &i = 0; // expected-note {{binding reference variable 'i' here}}
20+
return i; // expected-error{{returning reference to local temporary object}}
21+
} ());
22+
}
23+
24+
static_assert(__is_convertible(int, const int &));
25+
static_assert(__is_nothrow_convertible(int, const int &));

clang/test/SemaCXX/type-traits.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2509,6 +2509,20 @@ void is_convertible()
25092509
static_assert(__is_convertible(FloatWrapper, IntWrapper));
25102510
static_assert(__is_convertible(FloatWrapper, float));
25112511
static_assert(__is_convertible(float, FloatWrapper));
2512+
static_assert(__is_convertible(IntWrapper, IntWrapper&&));
2513+
static_assert(__is_convertible(IntWrapper, const IntWrapper&));
2514+
static_assert(__is_convertible(IntWrapper, int&&));
2515+
static_assert(__is_convertible(IntWrapper, const int&));
2516+
static_assert(__is_convertible(int, IntWrapper&&));
2517+
static_assert(__is_convertible(int, const IntWrapper&));
2518+
static_assert(__is_convertible(IntWrapper, FloatWrapper&&));
2519+
static_assert(__is_convertible(IntWrapper, const FloatWrapper&));
2520+
static_assert(__is_convertible(FloatWrapper, IntWrapper&&));
2521+
static_assert(__is_convertible(FloatWrapper, const IntWrapper&&));
2522+
static_assert(__is_convertible(FloatWrapper, float&&));
2523+
static_assert(__is_convertible(FloatWrapper, const float&));
2524+
static_assert(__is_convertible(float, FloatWrapper&&));
2525+
static_assert(__is_convertible(float, const FloatWrapper&));
25122526
}
25132527

25142528
void is_nothrow_convertible()
@@ -2521,6 +2535,20 @@ void is_nothrow_convertible()
25212535
static_assert(!__is_nothrow_convertible(FloatWrapper, IntWrapper));
25222536
static_assert(!__is_nothrow_convertible(FloatWrapper, float));
25232537
static_assert(__is_nothrow_convertible(float, FloatWrapper));
2538+
static_assert(__is_nothrow_convertible(IntWrapper, IntWrapper&&));
2539+
static_assert(__is_nothrow_convertible(IntWrapper, const IntWrapper&));
2540+
static_assert(__is_nothrow_convertible(IntWrapper, int&&));
2541+
static_assert(__is_nothrow_convertible(IntWrapper, const int&));
2542+
static_assert(!__is_nothrow_convertible(int, IntWrapper&&));
2543+
static_assert(!__is_nothrow_convertible(int, const IntWrapper&));
2544+
static_assert(!__is_nothrow_convertible(IntWrapper, FloatWrapper&&));
2545+
static_assert(!__is_nothrow_convertible(IntWrapper, const FloatWrapper&));
2546+
static_assert(!__is_nothrow_convertible(FloatWrapper, IntWrapper&&));
2547+
static_assert(!__is_nothrow_convertible(FloatWrapper, const IntWrapper&));
2548+
static_assert(!__is_nothrow_convertible(FloatWrapper, float&&));
2549+
static_assert(!__is_nothrow_convertible(FloatWrapper, const float&));
2550+
static_assert(__is_nothrow_convertible(float, FloatWrapper&&));
2551+
static_assert(__is_nothrow_convertible(float, const FloatWrapper&));
25242552
}
25252553

25262554
struct FromInt { FromInt(int); };

clang/www/cxx_status.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ <h2 id="cxx26">C++2c implementation status</h2>
167167
<tr>
168168
<td>Disallow Binding a Returned Glvalue to a Temporary</td>
169169
<td><a href="https://wg21.link/P2748R5">P2748R5</a></td>
170-
<td class="none" align="center">No</td>
170+
<td class="full" align="center">Clang 19</td>
171171
</tr>
172172
<tr>
173173
<td>Clarifying rules for brace elision in aggregate initialization</td>

0 commit comments

Comments
 (0)