[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 2: Parsing and Parser Tests) (PR #169681)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Wed Nov 26 09:46:24 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-codegen
Author: None (Sirraide)
<details>
<summary>Changes</summary>
[Clang] [C++26] Expansion Statements (Part 2)
Add Sema for CXXExpansionStmtDecl
Add parser tests
---
Patch is 34.81 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/169681.diff
14 Files Affected:
- (modified) clang/include/clang/Basic/DiagnosticCommonKinds.td (+4)
- (modified) clang/include/clang/Basic/DiagnosticParseKinds.td (+11-2)
- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+3-3)
- (modified) clang/include/clang/Parse/Parser.h (+37-4)
- (modified) clang/include/clang/Sema/Sema.h (+32-1)
- (modified) clang/lib/Parse/ParseDecl.cpp (+6-31)
- (modified) clang/lib/Parse/ParseExpr.cpp (+11-2)
- (modified) clang/lib/Parse/ParseInit.cpp (+20)
- (modified) clang/lib/Parse/ParseStmt.cpp (+128-15)
- (modified) clang/lib/Sema/CMakeLists.txt (+1)
- (modified) clang/lib/Sema/SemaDecl.cpp (+4-3)
- (added) clang/lib/Sema/SemaExpand.cpp (+81)
- (added) clang/test/Parser/cxx2c-expansion-statements-not-backported.cpp (+5)
- (added) clang/test/Parser/cxx2c-expansion-statements.cpp (+63)
``````````diff
diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td
index 6e50e225a8cc1..0b9225980e826 100644
--- a/clang/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td
@@ -22,6 +22,10 @@ def select_constexpr_spec_kind : TextSubstitution<
def fatal_too_many_errors
: Error<"too many errors emitted, stopping now">, DefaultFatal;
+// TODO: Remove this.
+def err_expansion_statements_todo : Error<
+ "TODO (expansion statements)">;
+
def warn_stack_exhausted : Warning<
"stack nearly exhausted; compilation time may suffer, and "
"crashes due to stack overflow are likely">,
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index aa0ccb0c05101..55234ebab3fe4 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -16,6 +16,10 @@ let CategoryName = "Parse Issue" in {
defm enum_fixed_underlying_type : CXX11Compat<
"enumeration types with a fixed underlying type are",
/*ext_warn=*/false>;
+
+// C++26 compatibility with C++23.
+defm expansion_statements : CXX26Compat<
+ "expansion statements are">;
}
def err_asm_qualifier_ignored : Error<
@@ -419,9 +423,10 @@ def warn_cxx98_compat_for_range : Warning<
"range-based for loop is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def err_for_range_identifier : Error<
- "range-based for loop requires type for loop variable">;
+ "%select{range-based for loop|expansion statement}0 requires "
+ "type for %select{loop|expansion}0 variable">;
def err_for_range_expected_decl : Error<
- "for range declaration must declare a variable">;
+ "%select{for range|expansion statement}0 declaration must declare a variable">;
def err_argument_required_after_attribute : Error<
"argument required after attribute">;
def err_missing_param : Error<"expected parameter declarator">;
@@ -448,6 +453,10 @@ def err_unspecified_size_with_static : Error<
"'static' may not be used without an array size">;
def err_expected_parentheses_around_typename : Error<
"expected parentheses around type name in %0 expression">;
+def err_expansion_stmt_requires_range : Error<
+ "expansion statement must be a range-based for loop">;
+def err_expansion_stmt_requires_cxx2c : Error<
+ "expansion statements are only supported in C++2c">;
def err_expected_case_before_expression: Error<
"expected 'case' keyword before expression">;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 53aa86a7dabde..ca862316a2f27 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2900,10 +2900,10 @@ def note_which_delegates_to : Note<"which delegates to">;
// C++11 range-based for loop
def err_for_range_decl_must_be_var : Error<
- "for range declaration must declare a variable">;
+ "%select{for range|expansion statement}0 declaration must declare a variable">;
def err_for_range_storage_class : Error<
- "loop variable %0 may not be declared %select{'extern'|'static'|"
- "'__private_extern__'|'auto'|'register'|'constexpr'|'thread_local'}1">;
+ "%select{loop|expansion}0 variable %1 may not be declared %select{'extern'|'static'|"
+ "'__private_extern__'|'auto'|'register'|'constexpr'|'thread_local'}2">;
def err_type_defined_in_for_range : Error<
"types may not be defined in a for range declaration">;
def err_for_range_deduction_failure : Error<
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 58eb1c0a7c114..ff4f7b4e1dd2d 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -1700,11 +1700,13 @@ class Parser : public CodeCompletionHandler {
}
/// Information on a C++0x for-range-initializer found while parsing a
- /// declaration which turns out to be a for-range-declaration.
+ /// declaration which turns out to be a for-range-declaration. Also used
+ /// for C++26's expansion statements.
struct ForRangeInit {
SourceLocation ColonLoc;
ExprResult RangeExpr;
SmallVector<MaterializeTemporaryExpr *, 8> LifetimeExtendTemps;
+ bool ExpansionStmt = false;
bool ParsedForRangeDecl() { return !ColonLoc.isInvalid(); }
};
struct ForRangeInfo : ForRangeInit {
@@ -4186,7 +4188,8 @@ class Parser : public CodeCompletionHandler {
bool ParseExpressionList(SmallVectorImpl<Expr *> &Exprs,
llvm::function_ref<void()> ExpressionStarts =
llvm::function_ref<void()>(),
- bool FailImmediatelyOnInvalidExpr = false);
+ bool FailImmediatelyOnInvalidExpr = false,
+ bool StopAtRBraceAfterComma = false);
/// ParseSimpleExpressionList - A simple comma-separated list of expressions,
/// used for misc language extensions.
@@ -5246,6 +5249,16 @@ class Parser : public CodeCompletionHandler {
///
ExprResult ParseBraceInitializer();
+ /// ParseExpansionInitList - Called when the initializer of an expansion
+ /// statement starts with an open brace.
+ ///
+ /// \verbatim
+ /// expansion-init-list: [C++26 [stmt.expand]]
+ /// '{' expression-list ','[opt] '}'
+ /// '{' '}'
+ /// \endverbatim
+ ExprResult ParseExpansionInitList();
+
struct DesignatorCompletionInfo {
SmallVectorImpl<Expr *> &InitExprs;
QualType PreferredBaseType;
@@ -7452,8 +7465,12 @@ class Parser : public CodeCompletionHandler {
/// [C++0x] expression
/// [C++0x] braced-init-list [TODO]
/// \endverbatim
- StmtResult ParseForStatement(SourceLocation *TrailingElseLoc,
- LabelDecl *PrecedingLabel);
+ StmtResult ParseForStatement(
+ SourceLocation *TrailingElseLoc, LabelDecl *PrecedingLabel,
+ CXXExpansionStmtDecl *CXXExpansionStmtDeclaration = nullptr);
+
+ void ParseForRangeInitializerAfterColon(ForRangeInit &FRI,
+ ParsingDeclSpec *VarDeclSpec);
/// ParseGotoStatement
/// \verbatim
@@ -7500,6 +7517,22 @@ class Parser : public CodeCompletionHandler {
StmtResult ParseBreakOrContinueStatement(bool IsContinue);
+ /// ParseExpansionStatement - Parse a C++26 expansion
+ /// statement ('template for').
+ ///
+ /// \verbatim
+ /// expansion-statement:
+ /// 'template' 'for' '(' init-statement[opt]
+ /// for-range-declaration ':' expansion-initializer ')'
+ /// compound-statement
+ ///
+ /// expansion-initializer:
+ /// expression
+ /// expansion-init-list
+ /// \endverbatim
+ StmtResult ParseExpansionStatement(SourceLocation *TrailingElseLoc,
+ LabelDecl *PrecedingLabel);
+
StmtResult ParsePragmaLoopHint(StmtVector &Stmts, ParsedStmtContext StmtCtx,
SourceLocation *TrailingElseLoc,
ParsedAttributes &Attrs,
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index ae500139ee6f7..786e53a2e179a 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -893,6 +893,7 @@ class Sema final : public SemaBase {
// 33. Types (SemaType.cpp)
// 34. FixIt Helpers (SemaFixItUtils.cpp)
// 35. Function Effects (SemaFunctionEffects.cpp)
+ // 36. C++ Expansion Statements (SemaExpand.cpp)
/// \name Semantic Analysis
/// Implementations are in Sema.cpp
@@ -4097,7 +4098,7 @@ class Sema final : public SemaBase {
/// complete.
void ActOnInitializerError(Decl *Dcl);
- void ActOnCXXForRangeDecl(Decl *D);
+ void ActOnCXXForRangeDecl(Decl *D, bool InExpansionStmt);
StmtResult ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc,
IdentifierInfo *Ident,
ParsedAttributes &Attrs);
@@ -15613,6 +15614,36 @@ class Sema final : public SemaBase {
void performFunctionEffectAnalysis(TranslationUnitDecl *TU);
///@}
+
+ //
+ //
+ // -------------------------------------------------------------------------
+ //
+ //
+
+ /// \name Expansion Statements
+ /// Implementations are in SemaExpand.cpp
+ ///@{
+public:
+ CXXExpansionStmtDecl *ActOnCXXExpansionStmtDecl(unsigned TemplateDepth,
+ SourceLocation TemplateKWLoc);
+
+ CXXExpansionStmtDecl *
+ BuildCXXExpansionStmtDecl(DeclContext *Ctx, SourceLocation TemplateKWLoc,
+ NonTypeTemplateParmDecl *NTTP);
+
+ ExprResult ActOnCXXExpansionInitList(MultiExprArg SubExprs,
+ SourceLocation LBraceLoc,
+ SourceLocation RBraceLoc);
+
+ StmtResult ActOnCXXExpansionStmtPattern(
+ CXXExpansionStmtDecl *ESD, Stmt *Init, Stmt *ExpansionVarStmt,
+ Expr *ExpansionInitializer, SourceLocation LParenLoc,
+ SourceLocation ColonLoc, SourceLocation RParenLoc,
+ ArrayRef<MaterializeTemporaryExpr *> LifetimeExtendTemps);
+
+ StmtResult FinishCXXExpansionStmt(Stmt *Expansion, Stmt *Body);
+ ///@}
};
DeductionFailureInfo
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 8688ccf41acb5..5e1ff2be28f38 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -2304,43 +2304,18 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
// Handle the Objective-C for-in loop variable similarly, although we
// don't need to parse the container in advance.
if (FRI && (Tok.is(tok::colon) || isTokIdentifier_in())) {
- bool IsForRangeLoop = false;
+ bool IsForRangeLoopOrExpansionStmt = false;
if (TryConsumeToken(tok::colon, FRI->ColonLoc)) {
- IsForRangeLoop = true;
- EnterExpressionEvaluationContext ForRangeInitContext(
- Actions, Sema::ExpressionEvaluationContext::PotentiallyEvaluated,
- /*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 (getLangOpts().OpenMP)
+ IsForRangeLoopOrExpansionStmt = true;
+ if (getLangOpts().OpenMP && !FRI->ExpansionStmt)
Actions.OpenMP().startOpenMPCXXRangeFor();
- 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);
+ ParseForRangeInitializerAfterColon(*FRI, &DS);
}
Decl *ThisDecl = Actions.ActOnDeclarator(getCurScope(), D);
- if (IsForRangeLoop) {
- Actions.ActOnCXXForRangeDecl(ThisDecl);
+ if (IsForRangeLoopOrExpansionStmt) {
+ Actions.ActOnCXXForRangeDecl(ThisDecl, FRI->ExpansionStmt);
} else {
// Obj-C for loop
if (auto *VD = dyn_cast_or_null<VarDecl>(ThisDecl))
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index 3515343202de1..902afcaeed987 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -3166,7 +3166,8 @@ void Parser::injectEmbedTokens() {
bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs,
llvm::function_ref<void()> ExpressionStarts,
- bool FailImmediatelyOnInvalidExpr) {
+ bool FailImmediatelyOnInvalidExpr,
+ bool StopAtRBraceAfterComma) {
bool SawError = false;
while (true) {
if (ExpressionStarts)
@@ -3195,7 +3196,11 @@ bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs,
SawError = true;
if (FailImmediatelyOnInvalidExpr)
break;
- SkipUntil(tok::comma, tok::r_paren, StopAtSemi | StopBeforeMatch);
+
+ if (StopAtRBraceAfterComma)
+ SkipUntil(tok::comma, tok::r_brace, StopAtSemi | StopBeforeMatch);
+ else
+ SkipUntil(tok::comma, tok::r_paren, StopAtSemi | StopBeforeMatch);
} else {
Exprs.push_back(Expr.get());
}
@@ -3205,6 +3210,10 @@ bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs,
// Move to the next argument, remember where the comma was.
Token Comma = Tok;
ConsumeToken();
+
+ if (StopAtRBraceAfterComma && Tok.is(tok::r_brace))
+ break;
+
checkPotentialAngleBracketDelimiter(Comma);
}
return SawError;
diff --git a/clang/lib/Parse/ParseInit.cpp b/clang/lib/Parse/ParseInit.cpp
index 0e86c4c48d5e4..11c4e983cdcd3 100644
--- a/clang/lib/Parse/ParseInit.cpp
+++ b/clang/lib/Parse/ParseInit.cpp
@@ -516,6 +516,26 @@ ExprResult Parser::ParseBraceInitializer() {
return ExprError(); // an error occurred.
}
+ExprResult Parser::ParseExpansionInitList() {
+ BalancedDelimiterTracker T(*this, tok::l_brace);
+ T.consumeOpen();
+
+ ExprVector InitExprs;
+
+ // CWG 3061: Accept a trailing comma here.
+ if (!Tok.is(tok::r_brace) &&
+ ParseExpressionList(InitExprs, /*ExpressionStarts=*/{},
+ /*FailImmediatelyOnInvalidExpr=*/false,
+ /*StopAtRBraceAfterComma=*/true)) {
+ T.consumeClose();
+ return ExprError();
+ }
+
+ T.consumeClose();
+ return Actions.ActOnCXXExpansionInitList(InitExprs, T.getOpenLocation(),
+ T.getCloseLocation());
+}
+
bool Parser::ParseMicrosoftIfExistsBraceInitializer(ExprVector &InitExprs,
bool &InitExprsOk) {
bool trailingComma = false;
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 7e73d89c2a18c..39751c79c6852 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -260,6 +260,20 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
}
case tok::kw_template: {
+ if (NextToken().is(tok::kw_for)) {
+ // Expansion statements are not backported for now.
+ if (!getLangOpts().CPlusPlus26) {
+ Diag(Tok.getLocation(), diag::err_expansion_stmt_requires_cxx2c);
+
+ // Trying to parse this as a regular 'for' statement instead yields
+ // better error recovery.
+ ConsumeToken();
+ return ParseForStatement(TrailingElseLoc, PrecedingLabel);
+ }
+
+ return ParseExpansionStatement(TrailingElseLoc, PrecedingLabel);
+ }
+
SourceLocation DeclEnd;
ParseTemplateDeclarationOrSpecialization(DeclaratorContext::Block, DeclEnd,
getAccessSpecifierIfPresent());
@@ -1884,8 +1898,55 @@ 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) {
+ Sema::ContextRAII CtxGuard(
+ Actions, Actions.CurContext->getEnclosingNonExpansionStatementContext(),
+ /*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) {
assert(Tok.is(tok::kw_for) && "Not a for stmt!");
SourceLocation ForLoc = ConsumeToken(); // eat the 'for'.
@@ -1920,6 +1981,8 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc,
unsigned ScopeFlags = 0;
if (C99orCXXorObjC)
ScopeFlags = Scope::DeclScope | Scope::ControlScope;
+ if (CXXExpansionStmtDecl)
+ ScopeFlags |= Scope::TemplateParamScope;
ParseScope ForScope(this, ScopeFlags);
@@ -1934,6 +1997,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc,
ExprResult Collection;
ForRangeInfo ForRangeInfo;
FullExprArg ThirdPart(Actions);
+ ForRangeInfo.ExpansionStmt = CXXExpansionStmtDecl != nullptr;
if (Tok.is(tok::code_completion)) {
cutOffParsing();
@@ -1964,18 +2028,17 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc,
MaybeParseCXX11Attributes(attrs);
ForRangeInfo.ColonLoc = ConsumeToken();
- if (Tok.is(tok::l_brace))
- ForRangeInfo.RangeExpr = ParseBraceInitializer();
- else
- ForRangeInfo.RangeExpr = ParseExpression();
+ ParseForRangeInitializerAfterColon(ForRangeInfo, /*VarDeclSpec=*/nullptr);
Diag(Loc, diag::err_for_range_identifier)
- << ((getLangOpts().CPlusPlus11 && !getLangOpts().CPlusPlus17)
- ? FixItHint::CreateInsertion(Loc, "auto &&")
- : FixItHint());
-
- ForRangeInfo.LoopVar =
- Actions.ActOnCXXForRangeIdentifier(getCurScope(), Loc, Name, attrs);
+ << ForRangeInfo.ExpansionStmt
+ << ((getLangOpts().CPlusPlus11 && !getLangOpts().CPlusPlus17)
+ ? FixItHint::CreateInsertion(Loc, "auto &&")
+ : FixItHint());
+
+ if (!ForRangeInfo.ExpansionStmt)
+ ForRangeInfo.LoopVar =
+ Actions.ActOnCXXForRangeIdentifier(getCurScope(), Loc, Name, attrs);
} else if (isForInitDeclaration()) { // for (int X = 4;
ParenBraceBracketBalancer BalancerRAIIObj(*this);
@@ -2067,7 +2130,8 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc,
// User tried to write the reasonable, but ill-formed, for-range-statement
// for (expr : expr) { ... }
Diag(Tok, diag::err_for_range_expected_decl)
- << FirstPart.get()->getSourceRange();
+ << (CXXExpansionStmtDecl != nullptr)
+ << FirstPart.get()->getSourceRange();
SkipUntil(tok::r_paren, StopBeforeMatch);
SecondPart = Sema::ConditionError();
} else {
@@ -2189,7 +2253,13 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc,
StmtResult ForRangeStmt;
StmtResult ForEachStmt;
- if (ForRangeInfo.ParsedForRangeDecl()) {
+ if (CXXExpansionStmtDecl) {
+ ForRangeStmt = Actions.ActOnCXXExpansionStmtPattern(
+ CXXExpansionStmt...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/169681
More information about the llvm-branch-commits
mailing list