summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Zhao <ayzhao@google.com>2023-03-20 14:53:53 -0700
committerTom Stellard <tstellar@redhat.com>2023-05-01 21:25:36 -0700
commitff9dc9c4fb113de9619fad6a77f4888277579718 (patch)
treeb2e45b98dc5ce9503cb16d2d0ac501ae0a184d5e
parent3cc0a562969b1183836ef17cce913644db76de9b (diff)
downloadllvm-ff9dc9c4fb113de9619fad6a77f4888277579718.tar.gz
[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 7df3c71b508b65284483225685f1ba19777f2bbb)
-rw-r--r--clang/lib/AST/Expr.cpp4
-rw-r--r--clang/lib/Sema/SemaInit.cpp2
-rw-r--r--clang/lib/Sema/TreeTransform.h22
-rw-r--r--clang/test/CodeGen/paren-list-agg-init.cpp72
-rw-r--r--clang/test/SemaCXX/paren-list-agg-init.cpp5
5 files changed, 90 insertions, 15 deletions
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 67862a8692ac..e45ae68cd5fe 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -1963,6 +1963,10 @@ Expr *ignoreImplicitSemaNodes(Expr *E) {
if (auto *Full = dyn_cast<FullExpr>(E))
return Full->getSubExpr();
+ if (auto *CPLIE = dyn_cast<CXXParenListInitExpr>(E);
+ CPLIE && CPLIE->getInitExprs().size() == 1)
+ return CPLIE->getInitExprs()[0];
+
return E;
}
} // namespace
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index d27641f4c0c0..99801a88e3ed 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -9181,6 +9181,8 @@ ExprResult InitializationSequence::Perform(Sema &S,
/*VerifyOnly=*/false, &CurInit);
if (CurInit.get() && ResultType)
*ResultType = CurInit.get()->getType();
+ if (shouldBindAsTemporary(Entity))
+ CurInit = S.MaybeBindToTemporary(CurInit.get());
break;
}
}
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 48bb28b56cd3..4244bbc1e4b1 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -3137,6 +3137,13 @@ public:
Expr *Sub,
SourceLocation RParenLoc,
bool ListInitialization) {
+ // If Sub is a ParenListExpr, then Sub is the syntatic form of a
+ // CXXParenListInitExpr. Pass its expanded arguments so that the
+ // CXXParenListInitExpr can be rebuilt.
+ if (auto *PLE = dyn_cast<ParenListExpr>(Sub))
+ return getSema().BuildCXXTypeConstructExpr(
+ TInfo, LParenLoc, MultiExprArg(PLE->getExprs(), PLE->getNumExprs()),
+ RParenLoc, ListInitialization);
return getSema().BuildCXXTypeConstructExpr(TInfo, LParenLoc,
MultiExprArg(&Sub, 1), RParenLoc,
ListInitialization);
@@ -3866,16 +3873,6 @@ public:
return getSema().BuildEmptyCXXFoldExpr(EllipsisLoc, Operator);
}
- ExprResult RebuildCXXParenListInitExpr(ArrayRef<Expr *> Args, QualType T,
- unsigned NumUserSpecifiedExprs,
- SourceLocation InitLoc,
- SourceLocation LParenLoc,
- SourceLocation RParenLoc) {
- return CXXParenListInitExpr::Create(getSema().Context, Args, T,
- NumUserSpecifiedExprs, InitLoc,
- LParenLoc, RParenLoc);
- }
-
/// Build a new atomic operation expression.
///
/// By default, performs semantic analysis to build the new expression.
@@ -14075,9 +14072,8 @@ TreeTransform<Derived>::TransformCXXParenListInitExpr(CXXParenListInitExpr *E) {
TransformedInits))
return ExprError();
- return getDerived().RebuildCXXParenListInitExpr(
- TransformedInits, E->getType(), E->getUserSpecifiedInitExprs().size(),
- E->getInitLoc(), E->getBeginLoc(), E->getEndLoc());
+ return getDerived().RebuildParenListExpr(E->getBeginLoc(), TransformedInits,
+ E->getEndLoc());
}
template<typename Derived>
diff --git a/clang/test/CodeGen/paren-list-agg-init.cpp b/clang/test/CodeGen/paren-list-agg-init.cpp
index a7534fb907d2..a860196d8f50 100644
--- a/clang/test/CodeGen/paren-list-agg-init.cpp
+++ b/clang/test/CodeGen/paren-list-agg-init.cpp
@@ -69,6 +69,27 @@ union U {
char b;
};
+
+namespace gh61145 {
+ // CHECK-DAG: [[STRUCT_VEC:%.*]] = type { i8 }
+ struct Vec {
+ Vec();
+ Vec(Vec&&);
+ ~Vec();
+ };
+
+ // CHECK-DAG: [[STRUCT_S1:%.*]] = type { [[STRUCT_VEC]] }
+ struct S1 {
+ Vec v;
+ };
+
+ // CHECK-DAG: [[STRUCT_S2:%.*]] = type { [[STRUCT_VEC]], i8 }
+ struct S2 {
+ Vec v;
+ char c;
+ };
+}
+
// CHECK-DAG: [[A1:@.*a1.*]] = internal constant [[STRUCT_A]] { i8 3, double 2.000000e+00 }, align 8
constexpr A a1(3.1, 2.0);
// CHECK-DAG: [[A2:@.*a2.*]] = internal constant [[STRUCT_A]] { i8 99, double 0.000000e+00 }, align 8
@@ -349,3 +370,54 @@ void foo18() {
void foo19() {
G g(2);
}
+
+namespace gh61145 {
+ // a.k.a. void make1<0>()
+ // CHECK: define {{.*}} void @_ZN7gh611455make1ILi0EEEvv
+ // CHECK-NEXT: entry:
+ // CHECK-NEXT: [[V:%.*v.*]] = alloca [[STRUCT_VEC]], align 1
+ // CHECK-NEXT: [[AGG_TMP_ENSURED:%.*agg.tmp.ensured.*]] = alloca [[STRUCT_S1]], align 1
+ // a.k.a. Vec::Vec()
+ // CHECK-NEXT: call void @_ZN7gh611453VecC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[V]])
+ // CHECK-NEXT: [[V1:%.*v1.*]] = getelementptr inbounds [[STRUCT_S1]], ptr [[AGG_TMP_ENSURED]], i32 0, i32 0
+ // a.k.a. Vec::Vec(Vec&&)
+ // CHECK-NEXT: call void @_ZN7gh611453VecC1EOS0_(ptr noundef nonnull align 1 dereferenceable(1) [[V1]], ptr noundef nonnull align 1 dereferenceable(1) [[V]])
+ // a.k.a. S1::~S1()
+ // CHECK-NEXT: call void @_ZN7gh611452S1D1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_TMP_ENSURED]])
+ // a.k.a.Vec::~Vec()
+ // CHECK-NEXT: call void @_ZN7gh611453VecD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[V]])
+ // CHECK-NEXT: ret void
+ template <int I>
+ void make1() {
+ Vec v;
+ S1((Vec&&) v);
+ }
+
+ // a.k.a. void make1<0>()
+ // CHECK: define {{.*}} void @_ZN7gh611455make2ILi0EEEvv
+ // CHECK-NEXT: entry:
+ // CHECK-NEXT: [[V:%.*v.*]] = alloca [[STRUCT_VEC]], align 1
+ // CHECK-NEXT: [[AGG_TMP_ENSURED:%.*agg.tmp.ensured.*]] = alloca [[STRUCT_S2]], align 1
+ // a.k.a. Vec::Vec()
+ // CHECK-NEXT: call void @_ZN7gh611453VecC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[V]])
+ // CHECK-NEXT: [[V1:%.*v1.*]] = getelementptr inbounds [[STRUCT_S2]], ptr [[AGG_TMP_ENSURED]], i32 0, i32 0
+ // a.k.a. Vec::Vec(Vec&&)
+ // CHECK-NEXT: call void @_ZN7gh611453VecC1EOS0_(ptr noundef nonnull align 1 dereferenceable(1) [[V1]], ptr noundef nonnull align 1 dereferenceable(1) [[V]])
+ // CHECK-NEXT: [[C:%.*c.*]] = getelementptr inbounds [[STRUCT_S2]], ptr [[AGG_TMP_ENSURED]], i32 0, i32
+ // CHECK-NEXT: store i8 0, ptr [[C]], align 1
+ // a.k.a. S2::~S2()
+ // CHECK-NEXT: call void @_ZN7gh611452S2D1Ev(ptr noundef nonnull align 1 dereferenceable(2) [[AGG_TMP_ENSURED]])
+ // a.k.a. Vec::~Vec()
+ // CHECK-NEXT: call void @_ZN7gh611453VecD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[V]])
+ // CHECK-NEXT: ret void
+ template <int I>
+ void make2() {
+ Vec v;
+ S2((Vec&&) v, 0);
+ }
+
+ void foo() {
+ make1<0>();
+ make2<0>();
+ }
+}
diff --git a/clang/test/SemaCXX/paren-list-agg-init.cpp b/clang/test/SemaCXX/paren-list-agg-init.cpp
index 0a150d64a749..c9d73327025c 100644
--- a/clang/test/SemaCXX/paren-list-agg-init.cpp
+++ b/clang/test/SemaCXX/paren-list-agg-init.cpp
@@ -65,7 +65,7 @@ template <typename T, char CH>
void bar() {
T t = 0;
A a(CH, 1.1); // OK; C++ paren list constructors are supported in semantic tree transformations.
- // beforecxx20-warning@-1 {{aggregate initialization of type 'A' from a parenthesized list of values is a C++20 extension}}
+ // beforecxx20-warning@-1 2{{aggregate initialization of type 'A' from a parenthesized list of values is a C++20 extension}}
}
template <class T, class... Args>
@@ -139,7 +139,8 @@ void foo() {
constexpr F f2(1, 1); // OK: f2.b is initialized by a constant expression.
// beforecxx20-warning@-1 {{aggregate initialization of type 'const F' from a parenthesized list of values is a C++20 extension}}
- bar<char, 1>();
+ bar<int, 'a'>();
+ // beforecxx20-note@-1 {{in instantiation of function template specialization 'bar<int, 'a'>' requested here}}
G<char> g('b', 'b');
// beforecxx20-warning@-1 {{aggregate initialization of type 'G<char>' from a parenthesized list of values is a C++20 extension}}