[clang] [Clang] Correctly finds subexpressions of immediate invocations (PR #106055)

via cfe-commits cfe-commits at lists.llvm.org
Mon Aug 26 12:43:06 PDT 2024


https://github.com/cor3ntin updated https://github.com/llvm/llvm-project/pull/106055

>From 33ff4f03257c9af03192b92cbd425b731e0f238c Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Mon, 26 Aug 2024 12:28:07 +0200
Subject: [PATCH 1/2] [Clang] Correctly finds subexpressions of immediate
 invocations

We were not correctly ignoring implicit casts.

Fixes #105558
---
 clang/docs/ReleaseNotes.rst            |  1 +
 clang/lib/Sema/SemaExpr.cpp            | 17 ++++++++++++++---
 clang/test/AST/ByteCode/new-delete.cpp | 16 +++++-----------
 clang/test/SemaCXX/cxx2a-consteval.cpp | 23 +++++++++++++++++++++++
 4 files changed, 43 insertions(+), 14 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 8f98167dff31ef..7d3eebb604a244 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -292,6 +292,7 @@ Bug Fixes to C++ Support
 - Correctly check constraints of explicit instantiations of member functions. (#GH46029)
 - Fixed an assertion failure about a constraint of a friend function template references to a value with greater
   template depth than the friend function template. (#GH98258)
+- Correctly handle subexpressions of an immediate invocation in the presence of implicit casts. (#GH105558)
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index c67183df335dd5..1dd0f4bd717c3f 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -17464,11 +17464,22 @@ static void RemoveNestedImmediateInvocation(
     ExprResult TransformInitializer(Expr *Init, bool NotCopyInit) {
       if (!Init)
         return Init;
+
+      // We cannot use IgnoreImpCasts because we need to preserve
+      // full expressions.
+      while (true) {
+        if (auto *ICE = dyn_cast<ImplicitCastExpr>(Init))
+          Init = ICE->getSubExpr();
+        else if (auto *ICE = dyn_cast<MaterializeTemporaryExpr>(Init))
+          Init = ICE->getSubExpr();
+        else
+          break;
+      }
       /// ConstantExpr are the first layer of implicit node to be removed so if
       /// Init isn't a ConstantExpr, no ConstantExpr will be skipped.
-      if (auto *CE = dyn_cast<ConstantExpr>(Init))
-        if (CE->isImmediateInvocation())
-          RemoveImmediateInvocation(CE);
+      if (auto *CE = dyn_cast<ConstantExpr>(Init);
+          CE && CE->isImmediateInvocation())
+        RemoveImmediateInvocation(CE);
       return Base::TransformInitializer(Init, NotCopyInit);
     }
     ExprResult TransformDeclRefExpr(DeclRefExpr *E) {
diff --git a/clang/test/AST/ByteCode/new-delete.cpp b/clang/test/AST/ByteCode/new-delete.cpp
index 6bb30bc19f110c..b90897d66795f3 100644
--- a/clang/test/AST/ByteCode/new-delete.cpp
+++ b/clang/test/AST/ByteCode/new-delete.cpp
@@ -404,7 +404,7 @@ constexpr typename std::remove_reference<T>::type&& move(T &&t) noexcept {
 
 namespace cxx2a {
 struct A {
-  int* p = new int(42); // both-note 7{{heap allocation performed here}}
+  int* p = new int(42); // both-note 3{{heap allocation performed here}}
   consteval int ret_i() const { return p ? *p : 0; }
   consteval A ret_a() const { return A{}; }
   constexpr ~A() { delete p; }
@@ -433,9 +433,7 @@ void test() {
   { A k = to_lvalue_ref(A()); } // both-error {{'cxx2a::to_lvalue_ref' is not a constant expression}} \
                                 // both-note {{reference to temporary is not a constant expression}} \
                                 // both-note {{temporary created here}}
-  { A k = to_lvalue_ref(A().ret_a()); } // both-error {{'cxx2a::A::ret_a' is not a constant expression}} \
-                                        // both-note {{heap-allocated object is not a constant expression}} \
-                                        // both-error {{'cxx2a::to_lvalue_ref' is not a constant expression}} \
+  { A k = to_lvalue_ref(A().ret_a()); } // both-error {{'cxx2a::to_lvalue_ref' is not a constant expression}} \
                                         // both-note {{reference to temporary is not a constant expression}} \
                                         // both-note {{temporary created here}}
   { int k = A().ret_a().ret_i(); } // both-error {{'cxx2a::A::ret_a' is not a constant expression}} \
@@ -445,19 +443,15 @@ void test() {
   { int k = const_a_ref(a); }
   { int k = rvalue_ref(A()); }
   { int k = rvalue_ref(std::move(a)); }
-  { int k = const_a_ref(A().ret_a()); } // both-error {{'cxx2a::A::ret_a' is not a constant expression}} \
-                                        // both-note {{is not a constant expression}}
-  { int k = const_a_ref(to_lvalue_ref(A().ret_a())); } // both-error {{'cxx2a::A::ret_a' is not a constant expression}} \
-                                                       // both-note {{is not a constant expression}}
+  { int k = const_a_ref(A().ret_a()); }
+  { int k = const_a_ref(to_lvalue_ref(A().ret_a())); }
   { int k = const_a_ref(to_lvalue_ref(std::move(a))); }
   { int k = by_value_a(A().ret_a()); }
   { int k = by_value_a(to_lvalue_ref(static_cast<const A&&>(a))); }
   { int k = (A().ret_a(), A().ret_i()); } // both-error {{'cxx2a::A::ret_a' is not a constant expression}} \
                                           // both-note {{is not a constant expression}} \
                                           // both-warning {{left operand of comma operator has no effect}}
-  { int k = (const_a_ref(A().ret_a()), A().ret_i()); }  // both-error {{'cxx2a::A::ret_a' is not a constant expression}} \
-                                                        // both-note {{is not a constant expression}} \
-                                                        // both-warning {{left operand of comma operator has no effect}}
+  { int k = (const_a_ref(A().ret_a()), A().ret_i()); } // both-warning {{left operand of comma operator has no effect}}
 }
 }
 
diff --git a/clang/test/SemaCXX/cxx2a-consteval.cpp b/clang/test/SemaCXX/cxx2a-consteval.cpp
index 6b0609a26c5882..f96be6cf0424a9 100644
--- a/clang/test/SemaCXX/cxx2a-consteval.cpp
+++ b/clang/test/SemaCXX/cxx2a-consteval.cpp
@@ -1232,4 +1232,27 @@ consteval void immediate() {
 }
 
 
+}
+
+namespace GH105558 {
+
+consteval int* alloc() { return new int(0); }
+consteval void f(int* p) { delete p; }
+consteval void g1(int*&& p) { delete p; }
+consteval void g2(const int* p) { delete p; }
+consteval void g3(int*const& p) { delete p; }
+struct X {
+  int* p;
+  explicit(false) constexpr X(int* p) : p(p) {}
+};
+consteval void g4(X x) { delete x.p; }
+
+void test() {
+  f(alloc());
+  g1(alloc());
+  g2(alloc());
+  g3(alloc());
+  g4(alloc());
+}
+
 }

>From 52a6a267a932ae820e8fc8edd7554d0d07408ac6 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Mon, 26 Aug 2024 13:18:40 +0200
Subject: [PATCH 2/2] fix tests

---
 clang/test/SemaCXX/cxx2a-consteval.cpp | 14 +++-----------
 1 file changed, 3 insertions(+), 11 deletions(-)

diff --git a/clang/test/SemaCXX/cxx2a-consteval.cpp b/clang/test/SemaCXX/cxx2a-consteval.cpp
index f96be6cf0424a9..81923617f637e8 100644
--- a/clang/test/SemaCXX/cxx2a-consteval.cpp
+++ b/clang/test/SemaCXX/cxx2a-consteval.cpp
@@ -380,11 +380,9 @@ void test() {
   { A k = to_lvalue_ref(A()); } // expected-error {{is not a constant expression}}
   // expected-note at -1 {{is not a constant expression}} expected-note at -1 {{temporary created here}}
   { A k = to_lvalue_ref(A().ret_a()); }
-  // expected-error at -1 {{'alloc::A::ret_a' is not a constant expression}}
-  // expected-note at -2 {{heap-allocated object is not a constant expression}}
-  // expected-error at -3 {{'alloc::to_lvalue_ref' is not a constant expression}}
-  // expected-note at -4 {{reference to temporary is not a constant expression}}
-  // expected-note at -5 {{temporary created here}}
+  // expected-note at -1 {{reference to temporary is not a constant expression}}
+  // expected-error at -2 {{'alloc::to_lvalue_ref' is not a constant expression}}
+  // expected-note at -3 {{temporary created here}}
   { int k = A().ret_a().ret_i(); }
   // expected-error at -1 {{'alloc::A::ret_a' is not a constant expression}}
   // expected-note at -2 {{heap-allocated object is not a constant expression}}
@@ -394,19 +392,13 @@ void test() {
   { int k = rvalue_ref(A()); }
   { int k = rvalue_ref(std::move(a)); }
   { int k = const_a_ref(A().ret_a()); }
-  // expected-error at -1 {{'alloc::A::ret_a' is not a constant expression}}
-  // expected-note at -2 {{is not a constant expression}}
   { int k = const_a_ref(to_lvalue_ref(A().ret_a())); }
-  // expected-error at -1 {{'alloc::A::ret_a' is not a constant expression}}
-  // expected-note at -2 {{is not a constant expression}}
   { int k = const_a_ref(to_lvalue_ref(std::move(a))); }
   { int k = by_value_a(A().ret_a()); }
   { int k = by_value_a(to_lvalue_ref(static_cast<const A&&>(a))); }
   { int k = (A().ret_a(), A().ret_i()); }// expected-error {{is not a constant expression}}
   // expected-note at -1 {{is not a constant expression}}
   { int k = (const_a_ref(A().ret_a()), A().ret_i()); }
-  // expected-error at -1 {{'alloc::A::ret_a' is not a constant expression}}
-  // expected-note at -2 {{is not a constant expression}}
 }
 
 }



More information about the cfe-commits mailing list