Skip to content

Commit ff9dc9c

Browse files
alanzhao1tstellar
authored andcommitted
[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 (cherry picked from commit 7df3c71)
1 parent 3cc0a56 commit ff9dc9c

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
@@ -9181,6 +9181,8 @@ ExprResult InitializationSequence::Perform(Sema &S,
91819181
/*VerifyOnly=*/false, &CurInit);
91829182
if (CurInit.get() && ResultType)
91839183
*ResultType = CurInit.get()->getType();
9184+
if (shouldBindAsTemporary(Entity))
9185+
CurInit = S.MaybeBindToTemporary(CurInit.get());
91849186
break;
91859187
}
91869188
}

clang/lib/Sema/TreeTransform.h

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3137,6 +3137,13 @@ class TreeTransform {
31373137
Expr *Sub,
31383138
SourceLocation RParenLoc,
31393139
bool ListInitialization) {
3140+
// If Sub is a ParenListExpr, then Sub is the syntatic form of a
3141+
// CXXParenListInitExpr. Pass its expanded arguments so that the
3142+
// CXXParenListInitExpr can be rebuilt.
3143+
if (auto *PLE = dyn_cast<ParenListExpr>(Sub))
3144+
return getSema().BuildCXXTypeConstructExpr(
3145+
TInfo, LParenLoc, MultiExprArg(PLE->getExprs(), PLE->getNumExprs()),
3146+
RParenLoc, ListInitialization);
31403147
return getSema().BuildCXXTypeConstructExpr(TInfo, LParenLoc,
31413148
MultiExprArg(&Sub, 1), RParenLoc,
31423149
ListInitialization);
@@ -3866,16 +3873,6 @@ class TreeTransform {
38663873
return getSema().BuildEmptyCXXFoldExpr(EllipsisLoc, Operator);
38673874
}
38683875

3869-
ExprResult RebuildCXXParenListInitExpr(ArrayRef<Expr *> Args, QualType T,
3870-
unsigned NumUserSpecifiedExprs,
3871-
SourceLocation InitLoc,
3872-
SourceLocation LParenLoc,
3873-
SourceLocation RParenLoc) {
3874-
return CXXParenListInitExpr::Create(getSema().Context, Args, T,
3875-
NumUserSpecifiedExprs, InitLoc,
3876-
LParenLoc, RParenLoc);
3877-
}
3878-
38793876
/// Build a new atomic operation expression.
38803877
///
38813878
/// By default, performs semantic analysis to build the new expression.
@@ -14075,9 +14072,8 @@ TreeTransform<Derived>::TransformCXXParenListInitExpr(CXXParenListInitExpr *E) {
1407514072
TransformedInits))
1407614073
return ExprError();
1407714074

14078-
return getDerived().RebuildCXXParenListInitExpr(
14079-
TransformedInits, E->getType(), E->getUserSpecifiedInitExprs().size(),
14080-
E->getInitLoc(), E->getBeginLoc(), E->getEndLoc());
14075+
return getDerived().RebuildParenListExpr(E->getBeginLoc(), TransformedInits,
14076+
E->getEndLoc());
1408114077
}
1408214078

1408314079
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)