@@ -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) {
@@ -309,8 +355,31 @@ StmtResult Sema::BuildNonEnumeratingCXXExpansionStmtPattern(
309355 Data.EndDecl , LParenLoc, ColonLoc, RParenLoc);
310356 }
311357
312- Diag (ESD->getLocation (), diag::err_expansion_statements_todo);
313- return StmtError ();
358+ // If not, try destructuring.
359+ StmtResult DecompDeclStmt = BuildDestructuringCXXExpansionStmt (
360+ *this , ExpansionInitializer, ColonLoc, ExpansionVar->isConstexpr (),
361+ LifetimeExtendTemps);
362+ if (DecompDeclStmt.isInvalid ()) {
363+ ActOnInitializerError (ExpansionVar);
364+ return StmtError ();
365+ }
366+
367+ auto *DS = DecompDeclStmt.getAs <DeclStmt>();
368+ auto *DD = cast<DecompositionDecl>(DS->getSingleDecl ());
369+ if (DD->isInvalidDecl ())
370+ return StmtError ();
371+
372+ ExprResult Select = BuildCXXDestructuringExpansionSelectExpr (DD, Index);
373+ if (Select.isInvalid ()) {
374+ ActOnInitializerError (ExpansionVar);
375+ return StmtError ();
376+ }
377+
378+ if (FinaliseExpansionVar (*this , ExpansionVar, Select))
379+ return StmtError ();
380+
381+ return new (Context) CXXDestructuringExpansionStmtPattern (
382+ ESD, Init, ExpansionVarStmt, DS, LParenLoc, ColonLoc, RParenLoc);
314383}
315384
316385StmtResult Sema::FinishCXXExpansionStmt (Stmt *Exp, Stmt *Body) {
@@ -339,8 +408,9 @@ StmtResult Sema::FinishCXXExpansionStmt(Stmt *Exp, Stmt *Body) {
339408 Shared.push_back (Iter->getRangeVarStmt ());
340409 Shared.push_back (Iter->getBeginVarStmt ());
341410 Shared.push_back (Iter->getEndVarStmt ());
342- } else {
343- assert (isa<CXXEnumeratingExpansionStmtPattern>(Expansion) && " TODO" );
411+ } else if (auto *Destructuring =
412+ dyn_cast<CXXDestructuringExpansionStmtPattern>(Expansion)) {
413+ Shared.push_back (Destructuring->getDecompositionDeclStmt ());
344414 }
345415
346416 // Return an empty statement if the range is empty.
@@ -409,6 +479,23 @@ Sema::BuildCXXExpansionInitListSelectExpr(CXXExpansionInitListExpr *Range,
409479 return Range->getExprs ()[I];
410480}
411481
482+ ExprResult Sema::BuildCXXDestructuringExpansionSelectExpr (DecompositionDecl *DD,
483+ Expr *Idx) {
484+ if (Idx->isValueDependent ())
485+ return new (Context) CXXDestructuringExpansionSelectExpr (Context, DD, Idx);
486+
487+ Expr::EvalResult ER;
488+ if (!Idx->EvaluateAsInt (ER, Context))
489+ llvm_unreachable (" Failed to evaluate expansion index" );
490+
491+ uint64_t I = ER.Val .getInt ().getZExtValue ();
492+ MarkAnyDeclReferenced (Idx->getBeginLoc (), DD, true );
493+ if (auto *BD = DD->bindings ()[I]; auto *HVD = BD->getHoldingVar ())
494+ return HVD->getInit ();
495+ else
496+ return BD->getBinding ();
497+ }
498+
412499std::optional<uint64_t >
413500Sema::ComputeExpansionSize (CXXExpansionStmtPattern *Expansion) {
414501 assert (!Expansion->hasDependentSize ());
@@ -468,5 +555,9 @@ Sema::ComputeExpansionSize(CXXExpansionStmtPattern *Expansion) {
468555 return ER.Val .getInt ().getZExtValue ();
469556 }
470557
471- llvm_unreachable (" TODO" );
558+ if (auto *Destructuring =
559+ dyn_cast<CXXDestructuringExpansionStmtPattern>(Expansion))
560+ return Destructuring->getDecompositionDecl ()->bindings ().size ();
561+
562+ llvm_unreachable (" Invalid expansion statement class" );
472563}
0 commit comments