@@ -173,6 +173,52 @@ TryBuildIterableExpansionStmtInitializer(Sema &S, Expr *ExpansionInitializer,
173173 return Data;
174174}
175175
176+ static StmtResult BuildDestructuringCXXExpansionStmt (
177+ Sema &S, Expr *ExpansionInitializer, SourceLocation ColonLoc,
178+ bool VarIsConstexpr,
179+ ArrayRef<MaterializeTemporaryExpr *> LifetimeExtendTemps) {
180+ auto Ctx = Sema::ExpressionEvaluationContext::PotentiallyEvaluated;
181+ if (VarIsConstexpr)
182+ Ctx = Sema::ExpressionEvaluationContext::ImmediateFunctionContext;
183+ EnterExpressionEvaluationContext ExprEvalCtx (S, Ctx);
184+
185+ // The declarations should be attached to the parent decl context.
186+ Sema::ContextRAII CtxGuard (
187+ S, S.CurContext ->getEnclosingNonExpansionStatementContext (),
188+ /* NewThis=*/ false );
189+
190+ UnsignedOrNone Arity =
191+ S.GetDecompositionElementCount (ExpansionInitializer->getType (), ColonLoc);
192+
193+ if (!Arity) {
194+ S.Diag (ExpansionInitializer->getBeginLoc (),
195+ diag::err_expansion_stmt_invalid_init)
196+ << ExpansionInitializer->getType ()
197+ << ExpansionInitializer->getSourceRange ();
198+ return StmtError ();
199+ }
200+
201+ QualType AutoRRef = S.Context .getAutoRRefDeductType ();
202+ SmallVector<BindingDecl *> Bindings;
203+ for (unsigned I = 0 ; I < *Arity; ++I)
204+ Bindings.push_back (BindingDecl::Create (
205+ S.Context , S.CurContext , ColonLoc,
206+ S.getPreprocessor ().getIdentifierInfo (" __u" + std::to_string (I)),
207+ AutoRRef));
208+
209+ TypeSourceInfo *TSI = S.Context .getTrivialTypeSourceInfo (AutoRRef);
210+ auto *DD =
211+ DecompositionDecl::Create (S.Context , S.CurContext , ColonLoc, ColonLoc,
212+ AutoRRef, TSI, SC_Auto, Bindings);
213+
214+ if (VarIsConstexpr)
215+ DD->setConstexpr (true );
216+
217+ S.ApplyForRangeOrExpansionStatementLifetimeExtension (DD, LifetimeExtendTemps);
218+ S.AddInitializerToDecl (DD, ExpansionInitializer, false );
219+ return S.ActOnDeclStmt (S.ConvertDeclToDeclGroup (DD), ColonLoc, ColonLoc);
220+ }
221+
176222CXXExpansionStmtDecl *
177223Sema::ActOnCXXExpansionStmtDecl (unsigned TemplateDepth,
178224 SourceLocation TemplateKWLoc) {
@@ -317,8 +363,31 @@ StmtResult Sema::BuildNonEnumeratingCXXExpansionStmtPattern(
317363 Data.EndDecl , LParenLoc, ColonLoc, RParenLoc);
318364 }
319365
320- Diag (ESD->getLocation (), diag::err_expansion_statements_todo);
321- return StmtError ();
366+ // If not, try destructuring.
367+ StmtResult DecompDeclStmt = BuildDestructuringCXXExpansionStmt (
368+ *this , ExpansionInitializer, ColonLoc, ExpansionVar->isConstexpr (),
369+ LifetimeExtendTemps);
370+ if (DecompDeclStmt.isInvalid ()) {
371+ ActOnInitializerError (ExpansionVar);
372+ return StmtError ();
373+ }
374+
375+ auto *DS = DecompDeclStmt.getAs <DeclStmt>();
376+ auto *DD = cast<DecompositionDecl>(DS->getSingleDecl ());
377+ if (DD->isInvalidDecl ())
378+ return StmtError ();
379+
380+ ExprResult Select = BuildCXXDestructuringExpansionSelectExpr (DD, Index);
381+ if (Select.isInvalid ()) {
382+ ActOnInitializerError (ExpansionVar);
383+ return StmtError ();
384+ }
385+
386+ if (FinaliseExpansionVar (*this , ExpansionVar, Select))
387+ return StmtError ();
388+
389+ return new (Context) CXXDestructuringExpansionStmtPattern (
390+ ESD, Init, ExpansionVarStmt, DS, LParenLoc, ColonLoc, RParenLoc);
322391}
323392
324393StmtResult Sema::FinishCXXExpansionStmt (Stmt *Exp, Stmt *Body) {
@@ -347,8 +416,9 @@ StmtResult Sema::FinishCXXExpansionStmt(Stmt *Exp, Stmt *Body) {
347416 Shared.push_back (Iter->getRangeVarStmt ());
348417 Shared.push_back (Iter->getBeginVarStmt ());
349418 Shared.push_back (Iter->getEndVarStmt ());
350- } else {
351- assert (isa<CXXEnumeratingExpansionStmtPattern>(Expansion) && " TODO" );
419+ } else if (auto *Destructuring =
420+ dyn_cast<CXXDestructuringExpansionStmtPattern>(Expansion)) {
421+ Shared.push_back (Destructuring->getDecompositionDeclStmt ());
352422 }
353423
354424 // Return an empty statement if the range is empty.
@@ -417,6 +487,23 @@ Sema::BuildCXXExpansionInitListSelectExpr(CXXExpansionInitListExpr *Range,
417487 return Range->getExprs ()[I];
418488}
419489
490+ ExprResult Sema::BuildCXXDestructuringExpansionSelectExpr (DecompositionDecl *DD,
491+ Expr *Idx) {
492+ if (Idx->isValueDependent ())
493+ return new (Context) CXXDestructuringExpansionSelectExpr (Context, DD, Idx);
494+
495+ Expr::EvalResult ER;
496+ if (!Idx->EvaluateAsInt (ER, Context))
497+ llvm_unreachable (" Failed to evaluate expansion index" );
498+
499+ uint64_t I = ER.Val .getInt ().getZExtValue ();
500+ MarkAnyDeclReferenced (Idx->getBeginLoc (), DD, true );
501+ if (auto *BD = DD->bindings ()[I]; auto *HVD = BD->getHoldingVar ())
502+ return HVD->getInit ();
503+ else
504+ return BD->getBinding ();
505+ }
506+
420507std::optional<uint64_t >
421508Sema::ComputeExpansionSize (CXXExpansionStmtPattern *Expansion) {
422509 assert (!Expansion->hasDependentSize ());
@@ -476,5 +563,9 @@ Sema::ComputeExpansionSize(CXXExpansionStmtPattern *Expansion) {
476563 return ER.Val .getInt ().getZExtValue ();
477564 }
478565
479- llvm_unreachable (" TODO" );
566+ if (auto *Destructuring =
567+ dyn_cast<CXXDestructuringExpansionStmtPattern>(Expansion))
568+ return Destructuring->getDecompositionDecl ()->bindings ().size ();
569+
570+ llvm_unreachable (" Invalid expansion statement class" );
480571}
0 commit comments