@@ -128,17 +128,34 @@ TryBuildIterableExpansionStmtInitializer(Sema &S, Expr *ExpansionInitializer,
128128 Data.TheState = IterableExpansionStmtData::State::Error;
129129 Scope *Scope = S.getCurScope ();
130130
131- // TODO: CWG 3131 changes how this range is declared.
132- StmtResult Var = S.BuildCXXForRangeRangeVar (Scope, ExpansionInitializer,
133- /* ForExpansionStmt=*/ true );
131+ // CWG 3131: The declaration of 'range' is of the form
132+ //
133+ // constexpr[opt] decltype(auto) range = (expansion-initializer);
134+ //
135+ // where 'constexpr' is present iff the for-range-declaration is 'constexpr'.
136+ StmtResult Var = S.BuildCXXForRangeRangeVar (
137+ Scope, S.ActOnParenExpr (ColonLoc, ColonLoc, ExpansionInitializer).get (),
138+ S.Context .getAutoType (QualType (), AutoTypeKeyword::DecltypeAuto,
139+ /* IsDependent*/ false ),
140+ VarIsConstexpr);
134141 if (Var.isInvalid ())
135142 return Data;
136143
144+ // CWG 3131: Discussion around this core issue (though as of the time of
145+ // writing not the resolution itself) suggests that the other variables we
146+ // create here should likewise be 'constexpr' iff the range variable is
147+ // declared 'constexpr'.
148+ //
149+ // FIXME: As of CWG 3131, 'end' is no longer used outside the lambda that
150+ // performs the size calculation (despite that, CWG 3131 currently still
151+ // lists it in the generated code, but this is likely an oversight). Ideally,
152+ // we should only create 'begin' here instead, but that requires another
153+ // substantial refactor of the for-range code.
137154 auto *RangeVar = cast<DeclStmt>(Var.get ());
138155 Sema::ForRangeBeginEndInfo Info = S.BuildCXXForRangeBeginEndVars (
139156 Scope, cast<VarDecl>(RangeVar->getSingleDecl ()), ColonLoc,
140157 /* CoawaitLoc=*/ {},
141- /* LifetimeExtendTemps=*/ {}, Sema::BFRK_Build, /* ForExpansionStmt= */ true );
158+ /* LifetimeExtendTemps=*/ {}, Sema::BFRK_Build, VarIsConstexpr );
142159
143160 if (!Info.isValid ())
144161 return Data;
@@ -240,6 +257,10 @@ StmtResult Sema::ActOnCXXExpansionStmtPattern(
240257 // Note that lifetime extension only applies to destructuring expansion
241258 // statements, so we just ignore 'LifetimeExtendedTemps' entirely for other
242259 // types of expansion statements (this is CWG 3043).
260+ //
261+ // TODO: CWG 3131 makes it so the 'range' variable of an iterating
262+ // expansion statement need no longer be 'constexpr'... so do we want
263+ // lifetime extension for iterating expansion statements after all?
243264 return BuildCXXEnumeratingExpansionStmtPattern (ESD, Init, DS, LParenLoc,
244265 ColonLoc, RParenLoc);
245266 }
@@ -436,14 +457,15 @@ Sema::ComputeExpansionSize(CXXExpansionStmtPattern *Expansion) {
436457 ->getExprs ()
437458 .size ();
438459
439- // By [stmt.expand]5.2, N is the result of evaluating the expression
460+ // CWG 3131: N is the result of evaluating the expression
440461 //
441- // [] consteval {
462+ // [& ] consteval {
442463 // std::ptrdiff_t result = 0;
443- // for (auto i = begin; i != end; ++i) ++result;
464+ // auto b = begin-expr;
465+ // auto e = end-expr;
466+ // for (; b != e; ++b) ++result;
444467 // return result;
445468 // }()
446- // TODO: CWG 3131 changes this lambda a bit.
447469 if (auto *Iterating = dyn_cast<CXXIteratingExpansionStmtPattern>(Expansion)) {
448470 SourceLocation Loc = Expansion->getColonLoc ();
449471 EnterExpressionEvaluationContext ExprEvalCtx (
@@ -506,32 +528,32 @@ Sema::ComputeExpansionSize(CXXExpansionStmtPattern *Expansion) {
506528 // Start the for loop.
507529 ParseScope ForScope (*this , Scope::DeclScope | Scope::ControlScope);
508530
509- // auto i = begin;
510- VarDecl *IterationVar = VarDecl::Create (
511- Context, CurContext, Loc, Loc, &PP.getIdentifierTable ().get (" __i" ),
512- Context.getAutoDeductType (),
513- Context.getTrivialTypeSourceInfo (Context.getAutoDeductType (), Loc),
514- SC_None);
515- DeclRefExpr *Begin = BuildDeclRefExpr (
516- Iterating->getBeginVar (),
517- Iterating->getBeginVar ()->getType ().getNonReferenceType (), VK_LValue,
518- Loc);
519- AddInitializerToDecl (IterationVar, Begin, false );
520- StmtResult IterationVarStmt =
521- ActOnDeclStmt (ConvertDeclToDeclGroup (IterationVar), Loc, Loc);
522- if (IterationVarStmt.isInvalid () || IterationVar->isInvalidDecl ())
531+ // auto b = begin-expr;
532+ // auto e = end-expr;
533+ ForRangeBeginEndInfo Info = BuildCXXForRangeBeginEndVars (
534+ getCurScope (), Iterating->getRangeVar (), Loc,
535+ /* CoawaitLoc=*/ {},
536+ /* LifetimeExtendTemps=*/ {}, BFRK_Build, /* Constexpr=*/ false );
537+ if (!Info.isValid ())
523538 return std::nullopt ;
524539
525- // i != end
526- DeclRefExpr *IterationVarDeclRef = BuildDeclRefExpr (
527- IterationVar, IterationVar->getType ().getNonReferenceType (), VK_LValue,
528- Loc);
529- DeclRefExpr *End = BuildDeclRefExpr (
530- Iterating->getEndVar (),
531- Iterating->getEndVar ()->getType ().getNonReferenceType (), VK_LValue,
532- Loc);
533- ExprResult NotEqual = ActOnBinOp (getCurScope (), Loc, tok::exclaimequal,
534- IterationVarDeclRef, End);
540+ StmtResult BeginStmt =
541+ ActOnDeclStmt (ConvertDeclToDeclGroup (Info.BeginVar ), Loc, Loc);
542+ StmtResult EndStmt =
543+ ActOnDeclStmt (ConvertDeclToDeclGroup (Info.EndVar ), Loc, Loc);
544+ if (BeginStmt.isInvalid () || EndStmt.isInvalid ())
545+ return std::nullopt ;
546+
547+ // b != e
548+ auto GetDeclRef = [&](VarDecl *VD) -> DeclRefExpr * {
549+ return BuildDeclRefExpr (VD, VD->getType ().getNonReferenceType (),
550+ VK_LValue, Loc);
551+ };
552+
553+ DeclRefExpr *Begin = GetDeclRef (Info.BeginVar );
554+ DeclRefExpr *End = GetDeclRef (Info.EndVar );
555+ ExprResult NotEqual =
556+ ActOnBinOp (getCurScope (), Loc, tok::exclaimequal, Begin, End);
535557 if (NotEqual.isInvalid ())
536558 return std::nullopt ;
537559 ConditionResult Condition = ActOnCondition (
@@ -540,12 +562,10 @@ Sema::ComputeExpansionSize(CXXExpansionStmtPattern *Expansion) {
540562 if (Condition.isInvalid ())
541563 return std::nullopt ;
542564
543- // ++i
544- IterationVarDeclRef = BuildDeclRefExpr (
545- IterationVar, IterationVar->getType ().getNonReferenceType (), VK_LValue,
546- Loc);
565+ // ++b
566+ Begin = GetDeclRef (Info.BeginVar );
547567 ExprResult Increment =
548- ActOnUnaryOp (getCurScope (), Loc, tok::plusplus, IterationVarDeclRef );
568+ ActOnUnaryOp (getCurScope (), Loc, tok::plusplus, Begin );
549569 if (Increment.isInvalid ())
550570 return std::nullopt ;
551571 FullExprArg ThirdPart = MakeFullDiscardedValueExpr (Increment.get ());
@@ -568,9 +588,8 @@ Sema::ComputeExpansionSize(CXXExpansionStmtPattern *Expansion) {
568588 // Exit the for loop.
569589 InnerScope.Exit ();
570590 ForScope.Exit ();
571- StmtResult ForLoop =
572- ActOnForStmt (Loc, Loc, IterationVarStmt.get (), Condition, ThirdPart,
573- Loc, IncrementStmt.get ());
591+ StmtResult ForLoop = ActOnForStmt (Loc, Loc, /* First=*/ nullptr , Condition,
592+ ThirdPart, Loc, IncrementStmt.get ());
574593 if (ForLoop.isInvalid ())
575594 return std::nullopt ;
576595
@@ -582,9 +601,11 @@ Sema::ComputeExpansionSize(CXXExpansionStmtPattern *Expansion) {
582601 return std::nullopt ;
583602
584603 // Finally, we can build the compound statement that is the lambda body.
585- StmtResult LambdaBody = ActOnCompoundStmt (
586- Loc, Loc, {ResultVarStmt.get (), ForLoop.get (), Return.get ()},
587- /* isStmtExpr=*/ false );
604+ StmtResult LambdaBody =
605+ ActOnCompoundStmt (Loc, Loc,
606+ {ResultVarStmt.get (), BeginStmt.get (), EndStmt.get (),
607+ ForLoop.get (), Return.get ()},
608+ /* isStmtExpr=*/ false );
588609 if (LambdaBody.isInvalid ())
589610 return std::nullopt ;
590611
0 commit comments