diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -524,6 +524,10 @@ type by the default argument promotions, and thus this is UB. Clang's behavior now matches GCC's behavior in C++. (`#38717 _`). +- 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 _`). Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -18170,13 +18170,11 @@ return E; } - E = MaybeCreateExprWithCleanups(E); - ConstantExpr *Res = ConstantExpr::Create( getASTContext(), E.get(), ConstantExpr::getStorageKind(Decl->getReturnType().getTypePtr(), getASTContext()), - /*IsImmediateInvocation*/ true); + /*IsImmediateInvocation=*/true); if (Cached.hasValue()) Res->MoveIntoResult(Cached, getASTContext()); /// Value-dependent constant expressions should not be immediately diff --git a/clang/test/CodeGenCXX/consteval-cleanup.cpp b/clang/test/CodeGenCXX/consteval-cleanup.cpp new file mode 100644 --- /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 --- /dev/null +++ b/clang/test/SemaCXX/consteval-cleanup.cpp @@ -0,0 +1,40 @@ +// RUN: %clang_cc1 -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); } + ~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-NOT: ExprWithCleanups +} + +struct B { + int *p = new int(38); + consteval int get() { return *p; } + constexpr ~B() { delete p; } +}; + +void bar() { + // CHECK: bar + // CHECK: ExprWithCleanups + // CHECK-NEXT: ConstantExpr + int k = B().get(); +}