Skip to content

Commit c821cc3

Browse files
authored
[Clang] Correctly finds subexpressions of immediate invocations (#106055)
We were not correctly ignoring implicit casts. Fixes #105558
1 parent 2e0583e commit c821cc3

File tree

4 files changed

+46
-26
lines changed

4 files changed

+46
-26
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ Bug Fixes to C++ Support
317317
- Clang now rebuilds the template parameters of out-of-line declarations and specializations in the context
318318
of the current instantiation in all cases.
319319
- Fix evaluation of the index of dependent pack indexing expressions/types specifiers (#GH105900)
320-
320+
- Correctly handle subexpressions of an immediate invocation in the presence of implicit casts. (#GH105558)
321321

322322
Bug Fixes to AST Handling
323323
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/Sema/SemaExpr.cpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17463,11 +17463,22 @@ static void RemoveNestedImmediateInvocation(
1746317463
ExprResult TransformInitializer(Expr *Init, bool NotCopyInit) {
1746417464
if (!Init)
1746517465
return Init;
17466+
17467+
// We cannot use IgnoreImpCasts because we need to preserve
17468+
// full expressions.
17469+
while (true) {
17470+
if (auto *ICE = dyn_cast<ImplicitCastExpr>(Init))
17471+
Init = ICE->getSubExpr();
17472+
else if (auto *ICE = dyn_cast<MaterializeTemporaryExpr>(Init))
17473+
Init = ICE->getSubExpr();
17474+
else
17475+
break;
17476+
}
1746617477
/// ConstantExpr are the first layer of implicit node to be removed so if
1746717478
/// Init isn't a ConstantExpr, no ConstantExpr will be skipped.
17468-
if (auto *CE = dyn_cast<ConstantExpr>(Init))
17469-
if (CE->isImmediateInvocation())
17470-
RemoveImmediateInvocation(CE);
17479+
if (auto *CE = dyn_cast<ConstantExpr>(Init);
17480+
CE && CE->isImmediateInvocation())
17481+
RemoveImmediateInvocation(CE);
1747117482
return Base::TransformInitializer(Init, NotCopyInit);
1747217483
}
1747317484
ExprResult TransformDeclRefExpr(DeclRefExpr *E) {

clang/test/AST/ByteCode/new-delete.cpp

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ constexpr typename std::remove_reference<T>::type&& move(T &&t) noexcept {
404404

405405
namespace cxx2a {
406406
struct A {
407-
int* p = new int(42); // both-note 7{{heap allocation performed here}}
407+
int* p = new int(42); // both-note 3{{heap allocation performed here}}
408408
consteval int ret_i() const { return p ? *p : 0; }
409409
consteval A ret_a() const { return A{}; }
410410
constexpr ~A() { delete p; }
@@ -433,9 +433,7 @@ void test() {
433433
{ A k = to_lvalue_ref(A()); } // both-error {{'cxx2a::to_lvalue_ref' is not a constant expression}} \
434434
// both-note {{reference to temporary is not a constant expression}} \
435435
// both-note {{temporary created here}}
436-
{ A k = to_lvalue_ref(A().ret_a()); } // both-error {{'cxx2a::A::ret_a' is not a constant expression}} \
437-
// both-note {{heap-allocated object is not a constant expression}} \
438-
// both-error {{'cxx2a::to_lvalue_ref' is not a constant expression}} \
436+
{ A k = to_lvalue_ref(A().ret_a()); } // both-error {{'cxx2a::to_lvalue_ref' is not a constant expression}} \
439437
// both-note {{reference to temporary is not a constant expression}} \
440438
// both-note {{temporary created here}}
441439
{ int k = A().ret_a().ret_i(); } // both-error {{'cxx2a::A::ret_a' is not a constant expression}} \
@@ -445,19 +443,15 @@ void test() {
445443
{ int k = const_a_ref(a); }
446444
{ int k = rvalue_ref(A()); }
447445
{ int k = rvalue_ref(std::move(a)); }
448-
{ int k = const_a_ref(A().ret_a()); } // both-error {{'cxx2a::A::ret_a' is not a constant expression}} \
449-
// both-note {{is not a constant expression}}
450-
{ int k = const_a_ref(to_lvalue_ref(A().ret_a())); } // both-error {{'cxx2a::A::ret_a' is not a constant expression}} \
451-
// both-note {{is not a constant expression}}
446+
{ int k = const_a_ref(A().ret_a()); }
447+
{ int k = const_a_ref(to_lvalue_ref(A().ret_a())); }
452448
{ int k = const_a_ref(to_lvalue_ref(std::move(a))); }
453449
{ int k = by_value_a(A().ret_a()); }
454450
{ int k = by_value_a(to_lvalue_ref(static_cast<const A&&>(a))); }
455451
{ int k = (A().ret_a(), A().ret_i()); } // both-error {{'cxx2a::A::ret_a' is not a constant expression}} \
456452
// both-note {{is not a constant expression}} \
457453
// both-warning {{left operand of comma operator has no effect}}
458-
{ int k = (const_a_ref(A().ret_a()), A().ret_i()); } // both-error {{'cxx2a::A::ret_a' is not a constant expression}} \
459-
// both-note {{is not a constant expression}} \
460-
// both-warning {{left operand of comma operator has no effect}}
454+
{ int k = (const_a_ref(A().ret_a()), A().ret_i()); } // both-warning {{left operand of comma operator has no effect}}
461455
}
462456
}
463457

clang/test/SemaCXX/cxx2a-consteval.cpp

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -380,11 +380,9 @@ void test() {
380380
{ A k = to_lvalue_ref(A()); } // expected-error {{is not a constant expression}}
381381
// expected-note@-1 {{is not a constant expression}} expected-note@-1 {{temporary created here}}
382382
{ A k = to_lvalue_ref(A().ret_a()); }
383-
// expected-error@-1 {{'alloc::A::ret_a' is not a constant expression}}
384-
// expected-note@-2 {{heap-allocated object is not a constant expression}}
385-
// expected-error@-3 {{'alloc::to_lvalue_ref' is not a constant expression}}
386-
// expected-note@-4 {{reference to temporary is not a constant expression}}
387-
// expected-note@-5 {{temporary created here}}
383+
// expected-note@-1 {{reference to temporary is not a constant expression}}
384+
// expected-error@-2 {{'alloc::to_lvalue_ref' is not a constant expression}}
385+
// expected-note@-3 {{temporary created here}}
388386
{ int k = A().ret_a().ret_i(); }
389387
// expected-error@-1 {{'alloc::A::ret_a' is not a constant expression}}
390388
// expected-note@-2 {{heap-allocated object is not a constant expression}}
@@ -394,19 +392,13 @@ void test() {
394392
{ int k = rvalue_ref(A()); }
395393
{ int k = rvalue_ref(std::move(a)); }
396394
{ int k = const_a_ref(A().ret_a()); }
397-
// expected-error@-1 {{'alloc::A::ret_a' is not a constant expression}}
398-
// expected-note@-2 {{is not a constant expression}}
399395
{ int k = const_a_ref(to_lvalue_ref(A().ret_a())); }
400-
// expected-error@-1 {{'alloc::A::ret_a' is not a constant expression}}
401-
// expected-note@-2 {{is not a constant expression}}
402396
{ int k = const_a_ref(to_lvalue_ref(std::move(a))); }
403397
{ int k = by_value_a(A().ret_a()); }
404398
{ int k = by_value_a(to_lvalue_ref(static_cast<const A&&>(a))); }
405399
{ int k = (A().ret_a(), A().ret_i()); }// expected-error {{is not a constant expression}}
406400
// expected-note@-1 {{is not a constant expression}}
407401
{ int k = (const_a_ref(A().ret_a()), A().ret_i()); }
408-
// expected-error@-1 {{'alloc::A::ret_a' is not a constant expression}}
409-
// expected-note@-2 {{is not a constant expression}}
410402
}
411403

412404
}
@@ -1232,4 +1224,27 @@ consteval void immediate() {
12321224
}
12331225

12341226

1227+
}
1228+
1229+
namespace GH105558 {
1230+
1231+
consteval int* alloc() { return new int(0); }
1232+
consteval void f(int* p) { delete p; }
1233+
consteval void g1(int*&& p) { delete p; }
1234+
consteval void g2(const int* p) { delete p; }
1235+
consteval void g3(int*const& p) { delete p; }
1236+
struct X {
1237+
int* p;
1238+
explicit(false) constexpr X(int* p) : p(p) {}
1239+
};
1240+
consteval void g4(X x) { delete x.p; }
1241+
1242+
void test() {
1243+
f(alloc());
1244+
g1(alloc());
1245+
g2(alloc());
1246+
g3(alloc());
1247+
g4(alloc());
1248+
}
1249+
12351250
}

0 commit comments

Comments
 (0)