Skip to content

Commit 2db2d6d

Browse files
committed
[Clang] [C++26] Expansion Statements (Part 6)
1 parent 576f888 commit 2db2d6d

File tree

4 files changed

+153
-16
lines changed

4 files changed

+153
-16
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3702,6 +3702,8 @@ def err_conflicting_codeseg_attribute : Error<
37023702
def warn_duplicate_codeseg_attribute : Warning<
37033703
"duplicate code segment specifiers">, InGroup<Section>;
37043704

3705+
def err_expansion_stmt_invalid_init : Error<
3706+
"cannot expand expression of type %0">;
37053707
def err_expansion_stmt_vla : Error<
37063708
"cannot expand variable length array type %0">;
37073709
def err_expansion_stmt_incomplete : Error<

clang/include/clang/Sema/Sema.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15703,6 +15703,9 @@ class Sema final : public SemaBase {
1570315703
BuildCXXExpansionInitListSelectExpr(CXXExpansionInitListExpr *Range,
1570415704
Expr *Idx);
1570515705

15706+
ExprResult BuildCXXDestructuringExpansionSelectExpr(DecompositionDecl *DD,
15707+
Expr *Idx);
15708+
1570615709
std::optional<uint64_t>
1570715710
ComputeExpansionSize(CXXExpansionStmtPattern *Expansion);
1570815711
///@}

clang/lib/Sema/SemaExpand.cpp

Lines changed: 96 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,52 @@ TryBuildIterableExpansionStmtInitializer(Sema &S, Expr *ExpansionInitializer,
173173
return Data;
174174
}
175175

176+
static StmtResult BuildDestructuringCXXExpansionStmt(
177+
Sema &S, Expr *ExpansionInitializer, SourceLocation ColonLoc,
178+
bool VarIsConstexpr,
179+
ArrayRef<MaterializeTemporaryExpr *> LifetimeExtendTemps) {
180+
auto Ctx = Sema::ExpressionEvaluationContext::PotentiallyEvaluated;
181+
if (VarIsConstexpr)
182+
Ctx = Sema::ExpressionEvaluationContext::ImmediateFunctionContext;
183+
EnterExpressionEvaluationContext ExprEvalCtx(S, Ctx);
184+
185+
// The declarations should be attached to the parent decl context.
186+
Sema::ContextRAII CtxGuard(
187+
S, S.CurContext->getEnclosingNonExpansionStatementContext(),
188+
/*NewThis=*/false);
189+
190+
UnsignedOrNone Arity =
191+
S.GetDecompositionElementCount(ExpansionInitializer->getType(), ColonLoc);
192+
193+
if (!Arity) {
194+
S.Diag(ExpansionInitializer->getBeginLoc(),
195+
diag::err_expansion_stmt_invalid_init)
196+
<< ExpansionInitializer->getType()
197+
<< ExpansionInitializer->getSourceRange();
198+
return StmtError();
199+
}
200+
201+
QualType AutoRRef = S.Context.getAutoRRefDeductType();
202+
SmallVector<BindingDecl *> Bindings;
203+
for (unsigned I = 0; I < *Arity; ++I)
204+
Bindings.push_back(BindingDecl::Create(
205+
S.Context, S.CurContext, ColonLoc,
206+
S.getPreprocessor().getIdentifierInfo("__u" + std::to_string(I)),
207+
AutoRRef));
208+
209+
TypeSourceInfo *TSI = S.Context.getTrivialTypeSourceInfo(AutoRRef);
210+
auto *DD =
211+
DecompositionDecl::Create(S.Context, S.CurContext, ColonLoc, ColonLoc,
212+
AutoRRef, TSI, SC_Auto, Bindings);
213+
214+
if (VarIsConstexpr)
215+
DD->setConstexpr(true);
216+
217+
S.ApplyForRangeOrExpansionStatementLifetimeExtension(DD, LifetimeExtendTemps);
218+
S.AddInitializerToDecl(DD, ExpansionInitializer, false);
219+
return S.ActOnDeclStmt(S.ConvertDeclToDeclGroup(DD), ColonLoc, ColonLoc);
220+
}
221+
176222
CXXExpansionStmtDecl *
177223
Sema::ActOnCXXExpansionStmtDecl(unsigned TemplateDepth,
178224
SourceLocation TemplateKWLoc) {
@@ -317,8 +363,31 @@ StmtResult Sema::BuildNonEnumeratingCXXExpansionStmtPattern(
317363
Data.EndDecl, LParenLoc, ColonLoc, RParenLoc);
318364
}
319365

320-
Diag(ESD->getLocation(), diag::err_expansion_statements_todo);
321-
return StmtError();
366+
// If not, try destructuring.
367+
StmtResult DecompDeclStmt = BuildDestructuringCXXExpansionStmt(
368+
*this, ExpansionInitializer, ColonLoc, ExpansionVar->isConstexpr(),
369+
LifetimeExtendTemps);
370+
if (DecompDeclStmt.isInvalid()) {
371+
ActOnInitializerError(ExpansionVar);
372+
return StmtError();
373+
}
374+
375+
auto *DS = DecompDeclStmt.getAs<DeclStmt>();
376+
auto *DD = cast<DecompositionDecl>(DS->getSingleDecl());
377+
if (DD->isInvalidDecl())
378+
return StmtError();
379+
380+
ExprResult Select = BuildCXXDestructuringExpansionSelectExpr(DD, Index);
381+
if (Select.isInvalid()) {
382+
ActOnInitializerError(ExpansionVar);
383+
return StmtError();
384+
}
385+
386+
if (FinaliseExpansionVar(*this, ExpansionVar, Select))
387+
return StmtError();
388+
389+
return new (Context) CXXDestructuringExpansionStmtPattern(
390+
ESD, Init, ExpansionVarStmt, DS, LParenLoc, ColonLoc, RParenLoc);
322391
}
323392

324393
StmtResult Sema::FinishCXXExpansionStmt(Stmt *Exp, Stmt *Body) {
@@ -347,8 +416,9 @@ StmtResult Sema::FinishCXXExpansionStmt(Stmt *Exp, Stmt *Body) {
347416
Shared.push_back(Iter->getRangeVarStmt());
348417
Shared.push_back(Iter->getBeginVarStmt());
349418
Shared.push_back(Iter->getEndVarStmt());
350-
} else {
351-
assert(isa<CXXEnumeratingExpansionStmtPattern>(Expansion) && "TODO");
419+
} else if (auto *Destructuring =
420+
dyn_cast<CXXDestructuringExpansionStmtPattern>(Expansion)) {
421+
Shared.push_back(Destructuring->getDecompositionDeclStmt());
352422
}
353423

354424
// Return an empty statement if the range is empty.
@@ -417,6 +487,23 @@ Sema::BuildCXXExpansionInitListSelectExpr(CXXExpansionInitListExpr *Range,
417487
return Range->getExprs()[I];
418488
}
419489

490+
ExprResult Sema::BuildCXXDestructuringExpansionSelectExpr(DecompositionDecl *DD,
491+
Expr *Idx) {
492+
if (Idx->isValueDependent())
493+
return new (Context) CXXDestructuringExpansionSelectExpr(Context, DD, Idx);
494+
495+
Expr::EvalResult ER;
496+
if (!Idx->EvaluateAsInt(ER, Context))
497+
llvm_unreachable("Failed to evaluate expansion index");
498+
499+
uint64_t I = ER.Val.getInt().getZExtValue();
500+
MarkAnyDeclReferenced(Idx->getBeginLoc(), DD, true);
501+
if (auto *BD = DD->bindings()[I]; auto *HVD = BD->getHoldingVar())
502+
return HVD->getInit();
503+
else
504+
return BD->getBinding();
505+
}
506+
420507
std::optional<uint64_t>
421508
Sema::ComputeExpansionSize(CXXExpansionStmtPattern *Expansion) {
422509
assert(!Expansion->hasDependentSize());
@@ -476,5 +563,9 @@ Sema::ComputeExpansionSize(CXXExpansionStmtPattern *Expansion) {
476563
return ER.Val.getInt().getZExtValue();
477564
}
478565

479-
llvm_unreachable("TODO");
566+
if (auto *Destructuring =
567+
dyn_cast<CXXDestructuringExpansionStmtPattern>(Expansion))
568+
return Destructuring->getDecompositionDecl()->bindings().size();
569+
570+
llvm_unreachable("Invalid expansion statement class");
480571
}

clang/lib/Sema/TreeTransform.h

Lines changed: 52 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9383,20 +9383,35 @@ StmtResult TreeTransform<Derived>::TransformCXXDependentExpansionStmtPattern(
93839383
CXXDependentExpansionStmtPattern *S) {
93849384
TransformCXXExpansionStmtPatternResult Common;
93859385
ExprResult ExpansionInitializer;
9386+
SmallVector<MaterializeTemporaryExpr *, 8> LifetimeExtendTemps;
93869387

9387-
Common = TransformCXXExpansionStmtPatternCommonParts(S);
9388-
if (!Common.isValid())
9389-
return StmtError();
9388+
// Collect lifetime-extended temporaries in case this ends up being a
9389+
// destructuring expansion statement (for other kinds of expansion statements,
9390+
// this should make no difference since we ignore 'LifetimeExtendTemps' for
9391+
// those).
9392+
{
9393+
EnterExpressionEvaluationContext ExprEvalCtx(
9394+
SemaRef, SemaRef.currentEvaluationContext().Context);
9395+
SemaRef.currentEvaluationContext().InLifetimeExtendingContext = true;
9396+
SemaRef.currentEvaluationContext().RebuildDefaultArgOrDefaultInit = true;
93909397

9391-
ExpansionInitializer =
9392-
getDerived().TransformExpr(S->getExpansionInitializer());
9393-
if (ExpansionInitializer.isInvalid())
9394-
return StmtError();
9398+
Common = TransformCXXExpansionStmtPatternCommonParts(S);
9399+
if (!Common.isValid())
9400+
return StmtError();
9401+
9402+
ExpansionInitializer =
9403+
getDerived().TransformExpr(S->getExpansionInitializer());
9404+
if (ExpansionInitializer.isInvalid())
9405+
return StmtError();
9406+
9407+
LifetimeExtendTemps =
9408+
SemaRef.currentEvaluationContext().ForRangeLifetimeExtendTemps;
9409+
}
93959410

93969411
StmtResult Expansion = SemaRef.BuildNonEnumeratingCXXExpansionStmtPattern(
93979412
Common.NewESD, Common.NewInit, Common.NewExpansionVarDecl,
93989413
ExpansionInitializer.get(), S->getLParenLoc(), S->getColonLoc(),
9399-
S->getRParenLoc(), /*LifetimeExtendTemps=*/{});
9414+
S->getRParenLoc(), LifetimeExtendTemps);
94009415
if (Expansion.isInvalid())
94019416
return StmtError();
94029417

@@ -9455,8 +9470,23 @@ StmtResult TreeTransform<Derived>::TransformCXXExpansionStmtInstantiation(
94559470
SmallVector<Stmt *> SharedStmts;
94569471
SmallVector<Stmt *> Instantiations;
94579472

9458-
if (TransformStmts(SharedStmts, S->getSharedStmts()))
9459-
return StmtError();
9473+
// Apply lifetime extension to the shared statements if this was a
9474+
// destructuring expansion statement.
9475+
{
9476+
EnterExpressionEvaluationContext ExprEvalCtx(
9477+
SemaRef, SemaRef.currentEvaluationContext().Context);
9478+
SemaRef.currentEvaluationContext().InLifetimeExtendingContext = true;
9479+
SemaRef.currentEvaluationContext().RebuildDefaultArgOrDefaultInit = true;
9480+
if (TransformStmts(SharedStmts, S->getSharedStmts()))
9481+
return StmtError();
9482+
9483+
if (S->shouldApplyLifetimeExtensionToSharedStmts()) {
9484+
auto *VD =
9485+
cast<VarDecl>(cast<DeclStmt>(SharedStmts.front())->getSingleDecl());
9486+
SemaRef.ApplyForRangeOrExpansionStatementLifetimeExtension(
9487+
VD, SemaRef.currentEvaluationContext().ForRangeLifetimeExtendTemps);
9488+
}
9489+
}
94609490

94619491
if (TransformStmts(Instantiations, S->getInstantiations()))
94629492
return StmtError();
@@ -9488,7 +9518,18 @@ ExprResult TreeTransform<Derived>::TransformCXXExpansionInitListSelectExpr(
94889518
template <typename Derived>
94899519
ExprResult TreeTransform<Derived>::TransformCXXDestructuringExpansionSelectExpr(
94909520
CXXDestructuringExpansionSelectExpr *E) {
9491-
llvm_unreachable("TOOD");
9521+
Decl *DD = getDerived().TransformDecl(
9522+
E->getDecompositionDecl()->getLocation(), E->getDecompositionDecl());
9523+
ExprResult Idx = getDerived().TransformExpr(E->getIndexExpr());
9524+
if (!DD || Idx.isInvalid())
9525+
return ExprError();
9526+
9527+
if (!getDerived().AlwaysRebuild() && DD == E->getDecompositionDecl() &&
9528+
Idx.get() == E->getIndexExpr())
9529+
return E;
9530+
9531+
return SemaRef.BuildCXXDestructuringExpansionSelectExpr(
9532+
cast<DecompositionDecl>(DD), Idx.get());
94929533
}
94939534

94949535
template<typename Derived>

0 commit comments

Comments
 (0)