[clang] 550fa4e - [clang] Do not discard cleanups while processing immediate invocation
Mariya Podchishchaeva via cfe-commits
cfe-commits at lists.llvm.org
Fri Jun 30 01:52:12 PDT 2023
Author: Mariya Podchishchaeva
Date: 2023-06-30T04:50:08-04:00
New Revision: 550fa4eabd83d133595c7a5a07d54fc029b73733
URL: https://github.com/llvm/llvm-project/commit/550fa4eabd83d133595c7a5a07d54fc029b73733
DIFF: https://github.com/llvm/llvm-project/commit/550fa4eabd83d133595c7a5a07d54fc029b73733.diff
LOG: [clang] Do not discard cleanups while processing immediate invocation
Since an immediate invocation is a full expression itself - it requires
an additional ExprWithCleanups node, but it can participate to a bigger
full expression which actually requires cleanups to be run after.
Thanks @ilya-biryukov for helping reducing the reproducer and confirming
that the analysis is correct.
Fixes https://github.com/llvm/llvm-project/issues/60709
Reviewed By: ilya-biryukov
Differential Revision: https://reviews.llvm.org/D153962
Added:
clang/test/CodeGenCXX/consteval-cleanup.cpp
clang/test/SemaCXX/consteval-cleanup.cpp
Modified:
clang/docs/ReleaseNotes.rst
clang/lib/Sema/SemaExpr.cpp
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index da4ddff93c1f95..4a9a0305b7e140 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -557,6 +557,10 @@ Bug Fixes in This Version
attempting to see if it could be type template for class template argument
deduction. This fixes
(`Issue 57495 <https://github.com/llvm/llvm-project/issues/57495>`_)
+- Fix missing destructor calls and therefore memory leaks in generated code
+ when an immediate invocation appears as a part of an expression that produces
+ temporaries.
+ (`#60709 <https://github.com/llvm/llvm-project/issues/60709>`_).
Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 528b76518ff3a7..4d6414eed99cd2 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -18183,7 +18183,25 @@ ExprResult Sema::CheckForImmediateInvocation(ExprResult E, FunctionDecl *Decl) {
return E;
}
- E = MaybeCreateExprWithCleanups(E);
+ if (Cleanup.exprNeedsCleanups()) {
+ // Since an immediate invocation is a full expression itself - it requires
+ // an additional ExprWithCleanups node, but it can participate to a bigger
+ // full expression which actually requires cleanups to be run after so
+ // create ExprWithCleanups without using MaybeCreateExprWithCleanups as it
+ // may discard cleanups for outer expression too early.
+
+ // Note that ExprWithCleanups created here must always have empty cleanup
+ // objects:
+ // - compound literals do not create cleanup objects in C++ and immediate
+ // invocations are C++-only.
+ // - blocks are not allowed inside constant expressions and compiler will
+ // issue an error if they appear there.
+ //
+ // Hence, in correct code any cleanup objects created inside current
+ // evaluation context must be outside the immediate invocation.
+ E = ExprWithCleanups::Create(getASTContext(), E.get(),
+ Cleanup.cleanupsHaveSideEffects(), {});
+ }
ConstantExpr *Res = ConstantExpr::Create(
getASTContext(), E.get(),
diff --git a/clang/test/CodeGenCXX/consteval-cleanup.cpp b/clang/test/CodeGenCXX/consteval-cleanup.cpp
new file mode 100644
index 00000000000000..e6fdd50df6cb04
--- /dev/null
+++ b/clang/test/CodeGenCXX/consteval-cleanup.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -std=c++20 -Wno-unused-value -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s
+
+struct P {
+ consteval P() {}
+};
+
+struct A {
+ A(int v) { this->data = new int(v); }
+ ~A() { delete data; }
+private:
+ int *data;
+};
+
+void foo() {
+ for (;A(1), P(), false;);
+ // CHECK: foo
+ // CHECK: for.cond:
+ // CHECK: call void @_ZN1AC1Ei
+ // CHECK: call void @_ZN1AD1Ev
+ // CHECK: for.body
+}
diff --git a/clang/test/SemaCXX/consteval-cleanup.cpp b/clang/test/SemaCXX/consteval-cleanup.cpp
new file mode 100644
index 00000000000000..ddc56174b484f4
--- /dev/null
+++ b/clang/test/SemaCXX/consteval-cleanup.cpp
@@ -0,0 +1,61 @@
+// RUN: %clang_cc1 -fblocks -Wno-unused-value -std=c++20 -ast-dump -verify %s -ast-dump | FileCheck %s
+
+// expected-no-diagnostics
+
+struct P {
+ consteval P() {}
+};
+
+struct A {
+ A(int v) { this->data = new int(v); }
+ const int& get() const {
+ return *this->data;
+ }
+ ~A() { delete data; }
+private:
+ int *data;
+};
+
+void foo() {
+ for (;A(1), P(), false;);
+ // CHECK: foo
+ // CHECK: ExprWithCleanups
+ // CHECK-NEXT: BinaryOperator {{.*}} 'bool' ','
+ // CHECK-NEXT: BinaryOperator {{.*}} 'P':'P' ','
+ // CHECK-NEXT: CXXFunctionalCastExpr {{.*}} 'A':'A'
+ // CHECK-NEXT: CXXBindTemporaryExpr {{.*}} 'A':'A'
+ // CHECK-NEXT: CXXConstructExpr {{.*}} 'A':'A'
+ // CHECK: ConstantExpr {{.*}} 'P':'P'
+ // CHECK-NEXT: value:
+ // CHECK-NEXT: ExprWithCleanups
+}
+
+void foobar() {
+ A a(1);
+ for (; ^{ auto ptr = &a.get(); }(), P(), false;);
+ // CHECK: ExprWithCleanups
+ // CHECK-NEXT: cleanup Block
+ // CHECK-NEXT: BinaryOperator {{.*}} 'bool' ','
+ // CHECK-NEXT: BinaryOperator {{.*}} 'P':'P' ','
+ // CHECK-NEXT: CallExpr
+ // CHECK-NEXT: BlockExpr
+ // CHECK: ConstantExpr {{.*}} 'P':'P'
+ // CHECK-NEXT: value:
+ // CHECK-NEXT: ExprWithCleanups
+ // CHECK-NOT: cleanup Block
+}
+
+struct B {
+ int *p = new int(38);
+ consteval int get() { return *p; }
+ constexpr ~B() { delete p; }
+};
+
+void bar() {
+ // CHECK: bar
+ // CHECK: ExprWithCleanups
+ // CHECK: ConstantExpr
+ // CHECK-NEXT: value:
+ // CHECK-NEXT: ExprWithCleanups
+ int k = B().get();
+}
More information about the cfe-commits
mailing list