diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -1963,6 +1963,10 @@ if (auto *Full = dyn_cast(E)) return Full->getSubExpr(); + if (auto *CPLIE = dyn_cast(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 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -5465,7 +5465,7 @@ CPLIE->setInitializedFieldInUnion(InitializedFieldInUnion); *Result = CPLIE; S.Diag(Kind.getLocation(), - diag::warn_cxx17_compat_aggregate_init_paren_list) + diag::warn_cxx17_compat_aggregate_init_paren_list) << Kind.getLocation() << SR << ResultType; } @@ -9180,6 +9180,8 @@ /*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 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -3173,6 +3173,13 @@ 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(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 @@ return getSema().BuildEmptyCXXFoldExpr(EllipsisLoc, Operator); } - ExprResult RebuildCXXParenListInitExpr(ArrayRef 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. @@ -14135,9 +14132,8 @@ 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 diff --git a/clang/test/CodeGen/paren-list-agg-init.cpp b/clang/test/CodeGen/paren-list-agg-init.cpp --- a/clang/test/CodeGen/paren-list-agg-init.cpp +++ b/clang/test/CodeGen/paren-list-agg-init.cpp @@ -69,6 +69,27 @@ 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 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 + 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 + 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 --- a/clang/test/SemaCXX/paren-list-agg-init.cpp +++ b/clang/test/SemaCXX/paren-list-agg-init.cpp @@ -65,7 +65,7 @@ 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 @@ -139,7 +139,8 @@ 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(); + bar(); + // beforecxx20-note@-1 {{in instantiation of function template specialization 'bar' requested here}} G g('b', 'b'); // beforecxx20-warning@-1 {{aggregate initialization of type 'G' from a parenthesized list of values is a C++20 extension}}