Skip to content

Commit 2a23de0

Browse files
committed
[Clang] Switch from TransformExpr to TransformInitializer in places we need to revert initializer to it syntactic form for Sema
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: #62818 Differential Revision: https://reviews.llvm.org/D151235
1 parent 047e7ff commit 2a23de0

File tree

3 files changed

+38
-15
lines changed

3 files changed

+38
-15
lines changed

clang/lib/Sema/TreeTransform.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11402,7 +11402,8 @@ TreeTransform<Derived>::TransformBinaryOperator(BinaryOperator *E) {
1140211402
if (LHS.isInvalid())
1140311403
return ExprError();
1140411404

11405-
ExprResult RHS = getDerived().TransformExpr(E->getRHS());
11405+
ExprResult RHS =
11406+
getDerived().TransformInitializer(E->getRHS(), /*NotCopyInit=*/false);
1140611407
if (RHS.isInvalid())
1140711408
return ExprError();
1140811409

@@ -11950,7 +11951,8 @@ TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
1195011951

1195111952
ExprResult Second;
1195211953
if (E->getNumArgs() == 2) {
11953-
Second = getDerived().TransformExpr(E->getArg(1));
11954+
Second =
11955+
getDerived().TransformInitializer(E->getArg(1), /*NotCopyInit=*/false);
1195411956
if (Second.isInvalid())
1195511957
return ExprError();
1195611958
}

clang/test/Analysis/missing-bind-temporary.cpp

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ void clang_analyzer_eval(bool);
77
int global;
88

99
namespace variant_0 {
10-
// This variant of the code works correctly. Function foo() is not a template
11-
// function. Note that there are two destructors within foo().
1210

1311
class A {
1412
public:
@@ -46,9 +44,6 @@ void bar() {
4644
} // end namespace variant_0
4745

4846
namespace variant_1 {
49-
// Suddenly, if we turn foo() into a template, we are missing a
50-
// CXXBindTemporaryExpr in the AST, and therefore we're missing a
51-
// temporary destructor in the CFG.
5247

5348
class A {
5449
public:
@@ -59,19 +54,19 @@ class B {
5954
A a;
6055
};
6156

62-
// FIXME: Find the construction context for {} and enforce the temporary
63-
// destructor.
6457
// CHECK: template<> void foo<int>(int)
6558
// CHECK: [B1]
6659
// CHECK-NEXT: 1: (CXXConstructExpr, [B1.2], B)
6760
// CHECK-NEXT: 2: B i;
6861
// CHECK-NEXT: 3: operator=
6962
// CHECK-NEXT: 4: [B1.3] (ImplicitCastExpr, FunctionToPointerDecay, B &(*)(B &&) noexcept)
7063
// CHECK-NEXT: 5: i
71-
// CHECK-NEXT: 6: {} (CXXConstructExpr, B)
72-
// CHECK-NEXT: 7: [B1.6]
73-
// CHECK-NEXT: 8: [B1.5] = [B1.7] (OperatorCall)
74-
// CHECK-NEXT: 9: [B1.2].~B() (Implicit destructor)
64+
// CHECK-NEXT: 6: {} (CXXConstructExpr, [B1.7], [B1.8], B)
65+
// CHECK-NEXT: 7: [B1.6] (BindTemporary)
66+
// CHECK-NEXT: 8: [B1.7]
67+
// CHECK-NEXT: 9: [B1.5] = [B1.8] (OperatorCall)
68+
// CHECK-NEXT: 10: ~B() (Temporary object destructor)
69+
// CHECK-NEXT: 11: [B1.2].~B() (Implicit destructor)
7570
template <typename T> void foo(T) {
7671
B i;
7772
i = {};
@@ -80,8 +75,7 @@ template <typename T> void foo(T) {
8075
void bar() {
8176
global = 0;
8277
foo(1);
83-
// FIXME: Should be TRUE, i.e. we should call (and inline) two destructors.
84-
clang_analyzer_eval(global == 2); // expected-warning{{UNKNOWN}}
78+
clang_analyzer_eval(global == 2); // expected-warning{{TRUE [debug.ExprInspection]}}
8579
}
8680

8781
} // end namespace variant_1

clang/test/CodeGenCXX/gh62818.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// RUN: %clang_cc1 -std=c++17 -emit-llvm -triple x86_64-linux-gnu -o - %s | FileCheck %s
2+
3+
void doSomething();
4+
5+
struct A {
6+
A() {};
7+
~A() noexcept {
8+
doSomething();
9+
}
10+
11+
A & operator=(A a) & noexcept {
12+
return *this;
13+
}
14+
};
15+
16+
template<typename T>
17+
struct B {
18+
void test() {a = {};}
19+
// CHECK: define linkonce_odr void @_ZN1BIiE4testEv
20+
// CHECK: call void @_ZN1AC1Ev(ptr noundef nonnull align 1 dereferenceable(1)
21+
// CHECK: [[CALL:%.*]] = call noundef nonnull align 1 dereferenceable(1) ptr @_ZNR1AaSES_
22+
// CHECK: call void @_ZN1AD2Ev(ptr noundef nonnull align 1 dereferenceable(1)
23+
24+
A a;
25+
};
26+
27+
void client(B<int> &f) {f.test();}

0 commit comments

Comments
 (0)