@@ -191,6 +191,52 @@ TryBuildIterableExpansionStmtInitializer(Sema &S, Expr *ExpansionInitializer,
191191 return Data;
192192}
193193
194+ static StmtResult BuildDestructuringCXXExpansionStmt (
195+ Sema &S, Expr *ExpansionInitializer, SourceLocation ColonLoc,
196+ bool VarIsConstexpr,
197+ ArrayRef<MaterializeTemporaryExpr *> LifetimeExtendTemps) {
198+ auto Ctx = Sema::ExpressionEvaluationContext::PotentiallyEvaluated;
199+ if (VarIsConstexpr)
200+ Ctx = Sema::ExpressionEvaluationContext::ImmediateFunctionContext;
201+ EnterExpressionEvaluationContext ExprEvalCtx (S, Ctx);
202+
203+ // The declarations should be attached to the parent decl context.
204+ Sema::ContextRAII CtxGuard (
205+ S, S.CurContext ->getEnclosingNonExpansionStatementContext (),
206+ /* NewThis=*/ false );
207+
208+ UnsignedOrNone Arity =
209+ S.GetDecompositionElementCount (ExpansionInitializer->getType (), ColonLoc);
210+
211+ if (!Arity) {
212+ S.Diag (ExpansionInitializer->getBeginLoc (),
213+ diag::err_expansion_stmt_invalid_init)
214+ << ExpansionInitializer->getType ()
215+ << ExpansionInitializer->getSourceRange ();
216+ return StmtError ();
217+ }
218+
219+ QualType AutoRRef = S.Context .getAutoRRefDeductType ();
220+ SmallVector<BindingDecl *> Bindings;
221+ for (unsigned I = 0 ; I < *Arity; ++I)
222+ Bindings.push_back (BindingDecl::Create (
223+ S.Context , S.CurContext , ColonLoc,
224+ S.getPreprocessor ().getIdentifierInfo (" __u" + std::to_string (I)),
225+ AutoRRef));
226+
227+ TypeSourceInfo *TSI = S.Context .getTrivialTypeSourceInfo (AutoRRef);
228+ auto *DD =
229+ DecompositionDecl::Create (S.Context , S.CurContext , ColonLoc, ColonLoc,
230+ AutoRRef, TSI, SC_Auto, Bindings);
231+
232+ if (VarIsConstexpr)
233+ DD->setConstexpr (true );
234+
235+ S.ApplyForRangeOrExpansionStatementLifetimeExtension (DD, LifetimeExtendTemps);
236+ S.AddInitializerToDecl (DD, ExpansionInitializer, false );
237+ return S.ActOnDeclStmt (S.ConvertDeclToDeclGroup (DD), ColonLoc, ColonLoc);
238+ }
239+
194240CXXExpansionStmtDecl *
195241Sema::ActOnCXXExpansionStmtDecl (unsigned TemplateDepth,
196242 SourceLocation TemplateKWLoc) {
@@ -339,8 +385,31 @@ StmtResult Sema::BuildNonEnumeratingCXXExpansionStmtPattern(
339385 Data.EndDecl , LParenLoc, ColonLoc, RParenLoc);
340386 }
341387
342- Diag (ESD->getLocation (), diag::err_expansion_statements_todo);
343- return StmtError ();
388+ // If not, try destructuring.
389+ StmtResult DecompDeclStmt = BuildDestructuringCXXExpansionStmt (
390+ *this , ExpansionInitializer, ColonLoc, ExpansionVar->isConstexpr (),
391+ LifetimeExtendTemps);
392+ if (DecompDeclStmt.isInvalid ()) {
393+ ActOnInitializerError (ExpansionVar);
394+ return StmtError ();
395+ }
396+
397+ auto *DS = DecompDeclStmt.getAs <DeclStmt>();
398+ auto *DD = cast<DecompositionDecl>(DS->getSingleDecl ());
399+ if (DD->isInvalidDecl ())
400+ return StmtError ();
401+
402+ ExprResult Select = BuildCXXDestructuringExpansionSelectExpr (DD, Index);
403+ if (Select.isInvalid ()) {
404+ ActOnInitializerError (ExpansionVar);
405+ return StmtError ();
406+ }
407+
408+ if (FinaliseExpansionVar (*this , ExpansionVar, Select))
409+ return StmtError ();
410+
411+ return new (Context) CXXDestructuringExpansionStmtPattern (
412+ ESD, Init, ExpansionVarStmt, DS, LParenLoc, ColonLoc, RParenLoc);
344413}
345414
346415StmtResult Sema::FinishCXXExpansionStmt (Stmt *Exp, Stmt *Body) {
@@ -381,8 +450,9 @@ StmtResult Sema::FinishCXXExpansionStmt(Stmt *Exp, Stmt *Body) {
381450 Shared.push_back (Iter->getRangeVarStmt ());
382451 Shared.push_back (Iter->getBeginVarStmt ());
383452 Shared.push_back (Iter->getEndVarStmt ());
384- } else {
385- assert (isa<CXXEnumeratingExpansionStmtPattern>(Expansion) && " TODO" );
453+ } else if (auto *Destructuring =
454+ dyn_cast<CXXDestructuringExpansionStmtPattern>(Expansion)) {
455+ Shared.push_back (Destructuring->getDecompositionDeclStmt ());
386456 }
387457
388458 // Return an empty statement if the range is empty.
@@ -446,6 +516,23 @@ Sema::BuildCXXExpansionInitListSelectExpr(CXXExpansionInitListExpr *Range,
446516 return Range->getExprs ()[I];
447517}
448518
519+ ExprResult Sema::BuildCXXDestructuringExpansionSelectExpr (DecompositionDecl *DD,
520+ Expr *Idx) {
521+ if (Idx->isValueDependent ())
522+ return new (Context) CXXDestructuringExpansionSelectExpr (Context, DD, Idx);
523+
524+ Expr::EvalResult ER;
525+ if (!Idx->EvaluateAsInt (ER, Context))
526+ llvm_unreachable (" Failed to evaluate expansion index" );
527+
528+ uint64_t I = ER.Val .getInt ().getZExtValue ();
529+ MarkAnyDeclReferenced (Idx->getBeginLoc (), DD, true );
530+ if (auto *BD = DD->bindings ()[I]; auto *HVD = BD->getHoldingVar ())
531+ return HVD->getInit ();
532+ else
533+ return BD->getBinding ();
534+ }
535+
449536std::optional<uint64_t >
450537Sema::ComputeExpansionSize (CXXExpansionStmtPattern *Expansion) {
451538 assert (!Expansion->hasDependentSize ());
@@ -639,5 +726,9 @@ Sema::ComputeExpansionSize(CXXExpansionStmtPattern *Expansion) {
639726 return ER.Val .getInt ().getZExtValue ();
640727 }
641728
642- llvm_unreachable (" TODO" );
729+ if (auto *Destructuring =
730+ dyn_cast<CXXDestructuringExpansionStmtPattern>(Expansion))
731+ return Destructuring->getDecompositionDecl ()->bindings ().size ();
732+
733+ llvm_unreachable (" Invalid expansion statement class" );
643734}
0 commit comments