[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 2: Parsing and Parser Tests) (PR #169681)

Erich Keane via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Tue Mar 31 08:54:31 PDT 2026


================
@@ -1895,8 +1938,56 @@ bool Parser::isForRangeIdentifier() {
   return false;
 }
 
-StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc,
-                                     LabelDecl *PrecedingLabel) {
+void Parser::ParseForRangeInitializerAfterColon(ForRangeInit &FRI,
+                                                ParsingDeclSpec *VarDeclSpec) {
+  // Use an immediate function context if this is the initializer for a
+  // constexpr variable in an expansion statement.
+  auto Ctx = Sema::ExpressionEvaluationContext::PotentiallyEvaluated;
+  if (FRI.ExpansionStmt && VarDeclSpec && VarDeclSpec->hasConstexprSpecifier())
+    Ctx = Sema::ExpressionEvaluationContext::ImmediateFunctionContext;
+
+  EnterExpressionEvaluationContext InitContext(
+      Actions, Ctx,
+      /*LambdaContextDecl=*/nullptr,
+      Sema::ExpressionEvaluationContextRecord::EK_Other,
+      getLangOpts().CPlusPlus23);
+
+  // P2718R0 - Lifetime extension in range-based for loops.
+  if (getLangOpts().CPlusPlus23) {
+    auto &LastRecord = Actions.currentEvaluationContext();
+    LastRecord.InLifetimeExtendingContext = true;
+    LastRecord.RebuildDefaultArgOrDefaultInit = true;
+  }
+
+  if (FRI.ExpansionStmt) {
+    // The expansion-initializer is not in a dependent context and should
+    // thus be parsed in the parent context of the expansion statement.
+    assert(Actions.CurContext->isExpansionStmt());
+    Sema::ContextRAII CtxGuard(Actions, Actions.CurContext->getParent(),
+                               /*NewThis=*/false);
+    FRI.RangeExpr =
+        Tok.is(tok::l_brace) ? ParseExpansionInitList() : ParseExpression();
+    FRI.RangeExpr = Actions.MaybeCreateExprWithCleanups(FRI.RangeExpr);
+  } else if (Tok.is(tok::l_brace)) {
+    FRI.RangeExpr = ParseBraceInitializer();
+  } else {
+    FRI.RangeExpr = ParseExpression();
+  }
+
+  // Before c++23, ForRangeLifetimeExtendTemps should be empty.
+  assert(getLangOpts().CPlusPlus23 ||
+         Actions.ExprEvalContexts.back().ForRangeLifetimeExtendTemps.empty());
+
+  // Move the collected materialized temporaries into ForRangeInit before
+  // ForRangeInitContext exit.
+  FRI.LifetimeExtendTemps =
+      std::move(Actions.ExprEvalContexts.back().ForRangeLifetimeExtendTemps);
+}
+
+StmtResult
+Parser::ParseForStatement(SourceLocation *TrailingElseLoc,
+                          LabelDecl *PrecedingLabel,
+                          CXXExpansionStmtDecl *CXXExpansionStmtDecl) {
----------------
erichkeane wrote:

This naming of the variable might actually be problematic.  IIRC MSVC gets confused sometimes if the variable and type share the same name.

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


More information about the llvm-branch-commits mailing list