[clang] 7df3c71 - [clang] Fix 2 bugs with parenthesized aggregate initialization
Alan Zhao via cfe-commits
cfe-commits at lists.llvm.org
Thu Mar 30 15:06:44 PDT 2023
Author: Alan Zhao
Date: 2023-03-30T15:06:37-07:00
New Revision: 7df3c71b508b65284483225685f1ba19777f2bbb
URL: https://github.com/llvm/llvm-project/commit/7df3c71b508b65284483225685f1ba19777f2bbb
DIFF: https://github.com/llvm/llvm-project/commit/7df3c71b508b65284483225685f1ba19777f2bbb.diff
LOG: [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
Added:
Modified:
clang/lib/AST/Expr.cpp
clang/lib/Sema/SemaInit.cpp
clang/lib/Sema/TreeTransform.h
clang/test/CodeGen/paren-list-agg-init.cpp
clang/test/SemaCXX/paren-list-agg-init.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index f82587df0d70b..98b57966343be 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 46517c9dde06a..569024551d559 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -9180,6 +9180,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 5de8cd9e3e343..94e1cec18053d 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -3173,6 +3173,13 @@ class TreeTransform {
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);
@@ -3902,16 +3909,6 @@ class TreeTransform {
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.
@@ -14134,9 +14131,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 a7534fb907d2b..a860196d8f500 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 ec577e74509b8..a5f39ff6c477d 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 at -1 {{aggregate initialization of type 'A' from a parenthesized list of values is a C++20 extension}}
+ // beforecxx20-warning at -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 at -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 at -1 {{in instantiation of function template specialization 'bar<int, 'a'>' requested here}}
G<char> g('b', 'b');
// beforecxx20-warning at -1 {{aggregate initialization of type 'G<char>' from a parenthesized list of values is a C++20 extension}}
More information about the cfe-commits
mailing list