diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -1548,7 +1548,7 @@ // conversion expression is equivalent (in definedness, and if defined in // meaning) to the corresponding cast expression. if (Exprs.size() == 1 && !ListInitialization && - !isa(Exprs[0])) { + !isa(Exprs[0]) && !isa(Exprs[0])) { Expr *Arg = Exprs[0]; return BuildCXXFunctionalCastExpr(TInfo, Ty, LParenOrBraceLoc, Arg, RParenOrBraceLoc); @@ -1579,10 +1579,28 @@ diag::err_invalid_incomplete_type_use, FullRange)) return ExprError(); - // Otherwise, the expression is a prvalue of the specified type whose - // result object is direct-initialized (11.6) with the initializer. - InitializationSequence InitSeq(*this, Entity, Kind, Exprs); - ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Exprs); + MultiExprArg ExprsToPass; + if (Exprs.size() == 1 && isa(Exprs[0])) { + // C++20 [expr.static.cast]p4: + // An expression E can be explicitly converted to a type T...if T is an + // aggregate type ([dcl.init.aggr]) having a first element x and there is + // an implicit conversion sequence from E to the type of x + // + // Unlike for InitListExprs, InitializationSequence(..) doesn't take the + // overall CXXParenListInitExpr as the first element, so we instead pass + // it the elements of the CXXParenListInitExpr and have it deduce the + // initialization type and generate a new CXXParenListInitExpr. + auto *CPLIE = cast(Exprs[0]); + ExprsToPass = + MultiExprArg(const_cast(CPLIE->getInitExprs().begin()), + CPLIE->getInitExprs().size()); + } else { + // Otherwise, the expression is a prvalue of the specified type whose + // result object is direct-initialized (11.6) with the initializer. + ExprsToPass = Exprs; + } + InitializationSequence InitSeq(*this, Entity, Kind, ExprsToPass); + ExprResult Result = InitSeq.Perform(*this, Entity, Kind, ExprsToPass); if (Result.isInvalid()) return Result; 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 @@ -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/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,21 @@ char b; }; + +namespace gh61145 { + // CHECK-DAG: [[STRUCT_VEC:%.*]] = type { i8 } + struct Vec { + Vec(); + Vec(Vec&&); + ~Vec(); + }; + + // CHECK-DAG: [[STRUCT_S:%.*]] = type { [[STRUCT_VEC]] } + struct S { + Vec v; + }; +} + // 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 +364,30 @@ void foo19() { G g(2); } + +namespace gh61145 { + // a.k.a. void make<1>() + // CHECK: define {{.*}} void @_ZN7gh611454makeILi0EEEvv + // CHECK-NEXT: entry: + // CHECK-NEXT: [[V:%.*v.*]] = alloca [[STRUCT_VEC]], align 1 + // CHECK-NEXT: [[AGG_TMP_ENSURED:%.*agg.tmp.ensured.*]] = alloca [[STRUCT_S]], align 1 + // CHECK-NEXT: call void @_ZN7gh611453VecC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[V]]) + // a.k.a. Vec::Vec() + // CHECK-NEXT: [[V1:%.*v1.*]] = getelementptr inbounds [[STRUCT_S]], 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. S::~S(); + // CHECK-NEXT: call void @_ZN7gh611451SD1Ev(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 make() { + Vec v; + S((Vec&&) v); + } + + void foo() { + make<0>(); + } +}