@@ -220,6 +220,52 @@ TryBuildIterableExpansionStmtInitializer(Sema &S, Expr *ExpansionInitializer,
220220 return Data;
221221}
222222
223+ static StmtResult BuildDestructuringCXXExpansionStmt (
224+ Sema &S, Expr *ExpansionInitializer, SourceLocation ColonLoc,
225+ bool VarIsConstexpr,
226+ ArrayRef<MaterializeTemporaryExpr *> LifetimeExtendTemps) {
227+ auto Ctx = Sema::ExpressionEvaluationContext::PotentiallyEvaluated;
228+ if (VarIsConstexpr)
229+ Ctx = Sema::ExpressionEvaluationContext::ImmediateFunctionContext;
230+ EnterExpressionEvaluationContext ExprEvalCtx (S, Ctx);
231+
232+ // The declarations should be attached to the parent decl context.
233+ Sema::ContextRAII CtxGuard (
234+ S, S.CurContext ->getEnclosingNonExpansionStatementContext (),
235+ /* NewThis=*/ false );
236+
237+ UnsignedOrNone Arity =
238+ S.GetDecompositionElementCount (ExpansionInitializer->getType (), ColonLoc);
239+
240+ if (!Arity) {
241+ S.Diag (ExpansionInitializer->getBeginLoc (),
242+ diag::err_expansion_stmt_invalid_init)
243+ << ExpansionInitializer->getType ()
244+ << ExpansionInitializer->getSourceRange ();
245+ return StmtError ();
246+ }
247+
248+ QualType AutoRRef = S.Context .getAutoRRefDeductType ();
249+ SmallVector<BindingDecl *> Bindings;
250+ for (unsigned I = 0 ; I < *Arity; ++I)
251+ Bindings.push_back (BindingDecl::Create (
252+ S.Context , S.CurContext , ColonLoc,
253+ S.getPreprocessor ().getIdentifierInfo (" __u" + std::to_string (I)),
254+ AutoRRef));
255+
256+ TypeSourceInfo *TSI = S.Context .getTrivialTypeSourceInfo (AutoRRef);
257+ auto *DD =
258+ DecompositionDecl::Create (S.Context , S.CurContext , ColonLoc, ColonLoc,
259+ AutoRRef, TSI, SC_Auto, Bindings);
260+
261+ if (VarIsConstexpr)
262+ DD->setConstexpr (true );
263+
264+ S.ApplyForRangeOrExpansionStatementLifetimeExtension (DD, LifetimeExtendTemps);
265+ S.AddInitializerToDecl (DD, ExpansionInitializer, false );
266+ return S.ActOnDeclStmt (S.ConvertDeclToDeclGroup (DD), ColonLoc, ColonLoc);
267+ }
268+
223269CXXExpansionStmtDecl *
224270Sema::ActOnCXXExpansionStmtDecl (unsigned TemplateDepth,
225271 SourceLocation TemplateKWLoc) {
@@ -368,8 +414,31 @@ StmtResult Sema::BuildNonEnumeratingCXXExpansionStmtPattern(
368414 Data.EndDecl , LParenLoc, ColonLoc, RParenLoc);
369415 }
370416
371- Diag (ESD->getLocation (), diag::err_expansion_statements_todo);
372- return StmtError ();
417+ // If not, try destructuring.
418+ StmtResult DecompDeclStmt = BuildDestructuringCXXExpansionStmt (
419+ *this , ExpansionInitializer, ColonLoc, ExpansionVar->isConstexpr (),
420+ LifetimeExtendTemps);
421+ if (DecompDeclStmt.isInvalid ()) {
422+ ActOnInitializerError (ExpansionVar);
423+ return StmtError ();
424+ }
425+
426+ auto *DS = DecompDeclStmt.getAs <DeclStmt>();
427+ auto *DD = cast<DecompositionDecl>(DS->getSingleDecl ());
428+ if (DD->isInvalidDecl ())
429+ return StmtError ();
430+
431+ ExprResult Select = BuildCXXDestructuringExpansionSelectExpr (DD, Index);
432+ if (Select.isInvalid ()) {
433+ ActOnInitializerError (ExpansionVar);
434+ return StmtError ();
435+ }
436+
437+ if (FinaliseExpansionVar (*this , ExpansionVar, Select))
438+ return StmtError ();
439+
440+ return new (Context) CXXDestructuringExpansionStmtPattern (
441+ ESD, Init, ExpansionVarStmt, DS, LParenLoc, ColonLoc, RParenLoc);
373442}
374443
375444StmtResult Sema::FinishCXXExpansionStmt (Stmt *Exp, Stmt *Body) {
@@ -409,8 +478,8 @@ StmtResult Sema::FinishCXXExpansionStmt(Stmt *Exp, Stmt *Body) {
409478 Shared.push_back (Expansion->getRangeVarStmt ());
410479 Shared.push_back (Expansion->getBeginVarStmt ());
411480 Shared.push_back (Expansion->getEndVarStmt ());
412- } else {
413- assert (Expansion->isEnumerating () && " TODO " );
481+ } else if (Expansion-> isDestructuring ()) {
482+ Shared. push_back (Expansion->getDecompositionDeclStmt () );
414483 }
415484
416485 // Return an empty statement if the range is empty.
@@ -471,6 +540,23 @@ ExprResult Sema::BuildCXXExpansionSelectExpr(InitListExpr *Range, Expr *Idx) {
471540 return Range->getInit (I);
472541}
473542
543+ ExprResult Sema::BuildCXXDestructuringExpansionSelectExpr (DecompositionDecl *DD,
544+ Expr *Idx) {
545+ if (Idx->isValueDependent ())
546+ return new (Context) CXXDestructuringExpansionSelectExpr (Context, DD, Idx);
547+
548+ Expr::EvalResult ER;
549+ if (!Idx->EvaluateAsInt (ER, Context))
550+ llvm_unreachable (" Failed to evaluate expansion index" );
551+
552+ uint64_t I = ER.Val .getInt ().getZExtValue ();
553+ MarkAnyDeclReferenced (Idx->getBeginLoc (), DD, true );
554+ if (auto *BD = DD->bindings ()[I]; auto *HVD = BD->getHoldingVar ())
555+ return HVD->getInit ();
556+ else
557+ return BD->getBinding ();
558+ }
559+
474560std::optional<uint64_t >
475561Sema::ComputeExpansionSize (CXXExpansionStmtPattern *Expansion) {
476562 assert (!HasDependentSize (Expansion));
@@ -663,5 +749,9 @@ Sema::ComputeExpansionSize(CXXExpansionStmtPattern *Expansion) {
663749 return ER.Val .getInt ().getZExtValue ();
664750 }
665751
666- llvm_unreachable (" TODO" );
752+ if (auto *Destructuring =
753+ dyn_cast<CXXDestructuringExpansionStmtPattern>(Expansion))
754+ return Destructuring->getDecompositionDecl ()->bindings ().size ();
755+
756+ llvm_unreachable (" Invalid expansion statement class" );
667757}
0 commit comments