[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

Erich Keane via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Tue Mar 31 09:14:45 PDT 2026


================
@@ -65,13 +104,138 @@ StmtResult Sema::ActOnCXXExpansionStmtPattern(
     Expr *ExpansionInitializer, SourceLocation LParenLoc,
     SourceLocation ColonLoc, SourceLocation RParenLoc,
     ArrayRef<MaterializeTemporaryExpr *> LifetimeExtendTemps) {
+  if (!ExpansionInitializer || !ExpansionVarStmt)
+    return StmtError();
+
+  assert(CurContext->isExpansionStmt());
+  auto *DS = cast<DeclStmt>(ExpansionVarStmt);
+  if (!DS->isSingleDecl()) {
+    Diag(DS->getBeginLoc(), diag::err_type_defined_in_for_range);
+    return StmtError();
+  }
+
+  VarDecl *ExpansionVar = dyn_cast<VarDecl>(DS->getSingleDecl());
+  if (!ExpansionVar || ExpansionVar->isInvalidDecl() ||
+      ExpansionInitializer->containsErrors())
+    return StmtError();
+
+  // This is an enumerating expansion statement.
+  if (auto *ILE = dyn_cast<InitListExpr>(ExpansionInitializer)) {
+    assert(ILE->isSyntacticForm());
+    ExprResult Initializer =
+        BuildCXXExpansionSelectExpr(ILE, BuildIndexDRE(*this, ESD));
+    if (FinalizeExpansionVar(*this, ExpansionVar, Initializer))
+      return StmtError();
+
+    // Note that lifetime extension only applies to destructuring expansion
+    // statements, so we just ignore 'LifetimeExtendedTemps' entirely for other
+    // types of expansion statements (this is CWG 3043).
+    return BuildCXXEnumeratingExpansionStmtPattern(ESD, Init, DS, LParenLoc,
+                                                   ColonLoc, RParenLoc);
+  }
+
   Diag(ESD->getLocation(), diag::err_expansion_statements_todo);
   return StmtError();
 }
 
+StmtResult Sema::BuildCXXEnumeratingExpansionStmtPattern(
+    Decl *ESD, Stmt *Init, Stmt *ExpansionVar, SourceLocation LParenLoc,
+    SourceLocation ColonLoc, SourceLocation RParenLoc) {
+  return CXXExpansionStmtPattern::CreateEnumerating(
+      Context, cast<CXXExpansionStmtDecl>(ESD), Init,
+      cast<DeclStmt>(ExpansionVar), LParenLoc, ColonLoc, RParenLoc);
+}
+
 StmtResult Sema::FinishCXXExpansionStmt(Stmt *Exp, Stmt *Body) {
   if (!Exp || !Body)
     return StmtError();
 
+  auto *Expansion = cast<CXXExpansionStmtPattern>(Exp);
+  assert(!Expansion->getDecl()->getInstantiations() &&
+         "should not rebuild expansion statement after instantiation");
+
+  Expansion->setBody(Body);
+  if (HasDependentSize(Expansion))
+    return Expansion;
+
+  // This can fail if this is an iterating expansion statement.
+  std::optional<uint64_t> NumInstantiations = ComputeExpansionSize(Expansion);
+  if (!NumInstantiations)
+    return StmtError();
+
+  // Collect shared statements.
+  SmallVector<Stmt *, 1> Shared;
----------------
erichkeane wrote:

Why is this a vector if we only ever create 1 here? 

https://github.com/llvm/llvm-project/pull/169682


More information about the llvm-branch-commits mailing list