Skip to content

Commit 7df3c71

Browse files
committed
[clang] Fix 2 bugs with parenthesized aggregate initialization
* Fix an issue where temporaries initialized via parenthesized aggregate initialization don't get destroyed. * Fix an issue where aggregate initialization omits calls to class members' move constructors after a TreeTransform. This occurs because the CXXConstructExpr wrapping the call to the move constructor gets unboxed during a TreeTransform of the wrapping FunctionalCastExpr (as with a InitListExpr), but unlike InitListExpr, we dont reperform the InitializationSequence for the list's expressions to regenerate the CXXConstructExpr. This patch fixes this bug by treating CXXParenListInitExpr identically to InitListExpr in this regard. Fixes #61145 Reviewed By: rsmith Differential Revision: https://reviews.llvm.org/D146465
1 parent 3b11e40 commit 7df3c71

File tree

5 files changed

+90
-15
lines changed

5 files changed

+90
-15
lines changed

clang/lib/AST/Expr.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1963,6 +1963,10 @@ Expr *ignoreImplicitSemaNodes(Expr *E) {
19631963
if (auto *Full = dyn_cast<FullExpr>(E))
19641964
return Full->getSubExpr();
19651965

1966+
if (auto *CPLIE = dyn_cast<CXXParenListInitExpr>(E);
1967+
CPLIE && CPLIE->getInitExprs().size() == 1)
1968+
return CPLIE->getInitExprs()[0];
1969+
19661970
return E;
19671971
}
19681972
} // namespace

clang/lib/Sema/SemaInit.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9180,6 +9180,8 @@ ExprResult InitializationSequence::Perform(Sema &S,
91809180
/*VerifyOnly=*/false, &CurInit);
91819181
if (CurInit.get() && ResultType)
91829182
*ResultType = CurInit.get()->getType();
9183+
if (shouldBindAsTemporary(Entity))
9184+
CurInit = S.MaybeBindToTemporary(CurInit.get());
91839185
break;
91849186
}
91859187
}

clang/lib/Sema/TreeTransform.h

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3173,6 +3173,13 @@ class TreeTransform {
31733173
Expr *Sub,
31743174
SourceLocation RParenLoc,
31753175
bool ListInitialization) {
3176+
// If Sub is a ParenListExpr, then Sub is the syntatic form of a
3177+
// CXXParenListInitExpr. Pass its expanded arguments so that the
3178+
// CXXParenListInitExpr can be rebuilt.
3179+
if (auto *PLE = dyn_cast<ParenListExpr>(Sub))
3180+
return getSema().BuildCXXTypeConstructExpr(
3181+
TInfo, LParenLoc, MultiExprArg(PLE->getExprs(), PLE->getNumExprs()),
3182+
RParenLoc, ListInitialization);
31763183
return getSema().BuildCXXTypeConstructExpr(TInfo, LParenLoc,
31773184
MultiExprArg(&Sub, 1), RParenLoc,
31783185
ListInitialization);
@@ -3902,16 +3909,6 @@ class TreeTransform {
39023909
return getSema().BuildEmptyCXXFoldExpr(EllipsisLoc, Operator);
39033910
}
39043911

3905-
ExprResult RebuildCXXParenListInitExpr(ArrayRef<Expr *> Args, QualType T,
3906-
unsigned NumUserSpecifiedExprs,
3907-
SourceLocation InitLoc,
3908-
SourceLocation LParenLoc,
3909-
SourceLocation RParenLoc) {
3910-
return CXXParenListInitExpr::Create(getSema().Context, Args, T,
3911-
NumUserSpecifiedExprs, InitLoc,
3912-
LParenLoc, RParenLoc);
3913-
}
3914-
39153912
/// Build a new atomic operation expression.
39163913
///
39173914
/// By default, performs semantic analysis to build the new expression.
@@ -14134,9 +14131,8 @@ TreeTransform<Derived>::TransformCXXParenListInitExpr(CXXParenListInitExpr *E) {
1413414131
TransformedInits))
1413514132
return ExprError();
1413614133

14137-
return getDerived().RebuildCXXParenListInitExpr(
14138-
TransformedInits, E->getType(), E->getUserSpecifiedInitExprs().size(),
14139-
E->getInitLoc(), E->getBeginLoc(), E->getEndLoc());
14134+
return getDerived().RebuildParenListExpr(E->getBeginLoc(), TransformedInits,
14135+
E->getEndLoc());
1414014136
}
1414114137

1414214138
template<typename Derived>

clang/test/CodeGen/paren-list-agg-init.cpp

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,27 @@ union U {
6969
char b;
7070
};
7171

72+
73+
namespace gh61145 {
74+
// CHECK-DAG: [[STRUCT_VEC:%.*]] = type { i8 }
75+
struct Vec {
76+
Vec();
77+
Vec(Vec&&);
78+
~Vec();
79+
};
80+
81+
// CHECK-DAG: [[STRUCT_S1:%.*]] = type { [[STRUCT_VEC]] }
82+
struct S1 {
83+
Vec v;
84+
};
85+
86+
// CHECK-DAG: [[STRUCT_S2:%.*]] = type { [[STRUCT_VEC]], i8 }
87+
struct S2 {
88+
Vec v;
89+
char c;
90+
};
91+
}
92+
7293
// CHECK-DAG: [[A1:@.*a1.*]] = internal constant [[STRUCT_A]] { i8 3, double 2.000000e+00 }, align 8
7394
constexpr A a1(3.1, 2.0);
7495
// CHECK-DAG: [[A2:@.*a2.*]] = internal constant [[STRUCT_A]] { i8 99, double 0.000000e+00 }, align 8
@@ -349,3 +370,54 @@ void foo18() {
349370
void foo19() {
350371
G g(2);
351372
}
373+
374+
namespace gh61145 {
375+
// a.k.a. void make1<0>()
376+
// CHECK: define {{.*}} void @_ZN7gh611455make1ILi0EEEvv
377+
// CHECK-NEXT: entry:
378+
// CHECK-NEXT: [[V:%.*v.*]] = alloca [[STRUCT_VEC]], align 1
379+
// CHECK-NEXT: [[AGG_TMP_ENSURED:%.*agg.tmp.ensured.*]] = alloca [[STRUCT_S1]], align 1
380+
// a.k.a. Vec::Vec()
381+
// CHECK-NEXT: call void @_ZN7gh611453VecC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[V]])
382+
// CHECK-NEXT: [[V1:%.*v1.*]] = getelementptr inbounds [[STRUCT_S1]], ptr [[AGG_TMP_ENSURED]], i32 0, i32 0
383+
// a.k.a. Vec::Vec(Vec&&)
384+
// CHECK-NEXT: call void @_ZN7gh611453VecC1EOS0_(ptr noundef nonnull align 1 dereferenceable(1) [[V1]], ptr noundef nonnull align 1 dereferenceable(1) [[V]])
385+
// a.k.a. S1::~S1()
386+
// CHECK-NEXT: call void @_ZN7gh611452S1D1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_TMP_ENSURED]])
387+
// a.k.a.Vec::~Vec()
388+
// CHECK-NEXT: call void @_ZN7gh611453VecD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[V]])
389+
// CHECK-NEXT: ret void
390+
template <int I>
391+
void make1() {
392+
Vec v;
393+
S1((Vec&&) v);
394+
}
395+
396+
// a.k.a. void make1<0>()
397+
// CHECK: define {{.*}} void @_ZN7gh611455make2ILi0EEEvv
398+
// CHECK-NEXT: entry:
399+
// CHECK-NEXT: [[V:%.*v.*]] = alloca [[STRUCT_VEC]], align 1
400+
// CHECK-NEXT: [[AGG_TMP_ENSURED:%.*agg.tmp.ensured.*]] = alloca [[STRUCT_S2]], align 1
401+
// a.k.a. Vec::Vec()
402+
// CHECK-NEXT: call void @_ZN7gh611453VecC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[V]])
403+
// CHECK-NEXT: [[V1:%.*v1.*]] = getelementptr inbounds [[STRUCT_S2]], ptr [[AGG_TMP_ENSURED]], i32 0, i32 0
404+
// a.k.a. Vec::Vec(Vec&&)
405+
// CHECK-NEXT: call void @_ZN7gh611453VecC1EOS0_(ptr noundef nonnull align 1 dereferenceable(1) [[V1]], ptr noundef nonnull align 1 dereferenceable(1) [[V]])
406+
// CHECK-NEXT: [[C:%.*c.*]] = getelementptr inbounds [[STRUCT_S2]], ptr [[AGG_TMP_ENSURED]], i32 0, i32
407+
// CHECK-NEXT: store i8 0, ptr [[C]], align 1
408+
// a.k.a. S2::~S2()
409+
// CHECK-NEXT: call void @_ZN7gh611452S2D1Ev(ptr noundef nonnull align 1 dereferenceable(2) [[AGG_TMP_ENSURED]])
410+
// a.k.a. Vec::~Vec()
411+
// CHECK-NEXT: call void @_ZN7gh611453VecD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[V]])
412+
// CHECK-NEXT: ret void
413+
template <int I>
414+
void make2() {
415+
Vec v;
416+
S2((Vec&&) v, 0);
417+
}
418+
419+
void foo() {
420+
make1<0>();
421+
make2<0>();
422+
}
423+
}

clang/test/SemaCXX/paren-list-agg-init.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ template <typename T, char CH>
6565
void bar() {
6666
T t = 0;
6767
A a(CH, 1.1); // OK; C++ paren list constructors are supported in semantic tree transformations.
68-
// beforecxx20-warning@-1 {{aggregate initialization of type 'A' from a parenthesized list of values is a C++20 extension}}
68+
// beforecxx20-warning@-1 2{{aggregate initialization of type 'A' from a parenthesized list of values is a C++20 extension}}
6969
}
7070

7171
template <class T, class... Args>
@@ -139,7 +139,8 @@ void foo() {
139139
constexpr F f2(1, 1); // OK: f2.b is initialized by a constant expression.
140140
// beforecxx20-warning@-1 {{aggregate initialization of type 'const F' from a parenthesized list of values is a C++20 extension}}
141141

142-
bar<char, 1>();
142+
bar<int, 'a'>();
143+
// beforecxx20-note@-1 {{in instantiation of function template specialization 'bar<int, 'a'>' requested here}}
143144

144145
G<char> g('b', 'b');
145146
// beforecxx20-warning@-1 {{aggregate initialization of type 'G<char>' from a parenthesized list of values is a C++20 extension}}

0 commit comments

Comments
 (0)