shafik created this revision.
shafik added reviewers: rsmith, aaron.ballman, erichkeane.
Herald added a project: All.
shafik requested review of this revision.
In some cases we are using `TransformExpr` instead of `TransformInitializer`,
this results in `ExprWithCleanups` being dropped and we are not emitting a
destructor as a result.
This fixes: https://github.com/llvm/llvm-project/issues/62818
https://reviews.llvm.org/D151235
Files:
clang/lib/Sema/TreeTransform.h
clang/test/Analysis/missing-bind-temporary.cpp
clang/test/CodeGenCXX/gh62818.cpp
Index: clang/test/CodeGenCXX/gh62818.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGenCXX/gh62818.cpp
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -no-opaque-pointers -std=c++17 -emit-llvm -triple x86_64-linux-gnu -o - %s | FileCheck %s
+
+void doSomething();
+
+struct A {
+ A() {};
+ ~A() noexcept {
+ doSomething();
+ }
+
+ A & operator=(A a) & noexcept {
+ return *this;
+ }
+};
+
+template<typename T>
+struct B {
+ void test() {a = {};}
+ // CHECK: define{{.*}} @_ZN1BIiE4testEv(%struct.B*{{.*}} align 1 dereferenceable(1) %[[THIS_PARM:.+]])
+ // CHECK: %[[THIS:.+]] = alloca %struct.B*, align 8
+ // CHECK: %[[LHS:.+]] = alloca %struct.A, align 1
+ // CHECK: store %struct.B* %[[THIS_PARM]], %struct.B** %[[THIS]], align 8
+ // CHECK: %[[THIS_LOAD:.+]] = load %struct.B*, %struct.B** %[[THIS]], align 8
+ // CHECK: call{{.*}} @_ZN1AC1Ev(%struct.A* noundef nonnull align 1 dereferenceable(1) %[[LHS]])
+ // CHECK: %[[MEMBER_A:.+]] = getelementptr inbounds %struct.B, %struct.B* %[[THIS_LOAD]], i32 0, i32 0
+ // CHECK: %[[ASSIGN:.+]] = call noundef nonnull align 1 dereferenceable(1) %struct.A* @_ZNR1AaSES_(%struct.A* noundef nonnull align 1 dereferenceable(1) %[[MEMBER_A]], %struct.A* noundef %[[LHS]])
+ // CHECK: call void @_ZN1AD1Ev(%struct.A* noundef nonnull align 1 dereferenceable(1) %[[LHS]])
+
+ A a;
+};
+
+void client(B<int> &f) {f.test();}
Index: clang/test/Analysis/missing-bind-temporary.cpp
===================================================================
--- clang/test/Analysis/missing-bind-temporary.cpp
+++ clang/test/Analysis/missing-bind-temporary.cpp
@@ -7,8 +7,6 @@
int global;
namespace variant_0 {
-// This variant of the code works correctly. Function foo() is not a template
-// function. Note that there are two destructors within foo().
class A {
public:
@@ -46,9 +44,6 @@
} // end namespace variant_0
namespace variant_1 {
-// Suddenly, if we turn foo() into a template, we are missing a
-// CXXBindTemporaryExpr in the AST, and therefore we're missing a
-// temporary destructor in the CFG.
class A {
public:
@@ -59,8 +54,6 @@
A a;
};
-// FIXME: Find the construction context for {} and enforce the temporary
-// destructor.
// CHECK: template<> void foo<int>(int)
// CHECK: [B1]
// CHECK-NEXT: 1: (CXXConstructExpr, [B1.2], B)
@@ -68,10 +61,12 @@
// CHECK-NEXT: 3: operator=
// CHECK-NEXT: 4: [B1.3] (ImplicitCastExpr, FunctionToPointerDecay, B &(*)(B &&) noexcept)
// CHECK-NEXT: 5: i
-// CHECK-NEXT: 6: {} (CXXConstructExpr, B)
-// CHECK-NEXT: 7: [B1.6]
-// CHECK-NEXT: 8: [B1.5] = [B1.7] (OperatorCall)
-// CHECK-NEXT: 9: [B1.2].~B() (Implicit destructor)
+// CHECK-NEXT: 6: {} (CXXConstructExpr, [B1.7], [B1.8], B)
+// CHECK-NEXT: 7: [B1.6] (BindTemporary)
+// CHECK-NEXT: 8: [B1.7]
+// CHECK-NEXT: 9: [B1.5] = [B1.8] (OperatorCall)
+// CHECK-NEXT: 10: ~B() (Temporary object destructor)
+// CHECK-NEXT: 11: [B1.2].~B() (Implicit destructor)
template <typename T> void foo(T) {
B i;
i = {};
@@ -80,8 +75,7 @@
void bar() {
global = 0;
foo(1);
- // FIXME: Should be TRUE, i.e. we should call (and inline) two destructors.
- clang_analyzer_eval(global == 2); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(global == 2); // expected-warning{{TRUE [debug.ExprInspection]}}
}
} // end namespace variant_1
Index: clang/lib/Sema/TreeTransform.h
===================================================================
--- clang/lib/Sema/TreeTransform.h
+++ clang/lib/Sema/TreeTransform.h
@@ -11402,7 +11402,8 @@
if (LHS.isInvalid())
return ExprError();
- ExprResult RHS = getDerived().TransformExpr(E->getRHS());
+ ExprResult RHS =
+ getDerived().TransformInitializer(E->getRHS(), /*NotCopyInit=*/false);
if (RHS.isInvalid())
return ExprError();
@@ -11950,7 +11951,8 @@
ExprResult Second;
if (E->getNumArgs() == 2) {
- Second = getDerived().TransformExpr(E->getArg(1));
+ Second =
+ getDerived().TransformInitializer(E->getArg(1), /*NotCopyInit=*/false);
if (Second.isInvalid())
return ExprError();
}
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits