Skip to content

Commit 43c4a23

Browse files
committed
[Clang] [C++26] Expansion Statements (Part 6)
1 parent 2ec657b commit 43c4a23

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_lambda : Error<
37063708
"cannot expand lambda closure type">;
37073709

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) {
@@ -309,8 +355,31 @@ StmtResult Sema::BuildNonEnumeratingCXXExpansionStmtPattern(
309355
Data.EndDecl, LParenLoc, ColonLoc, RParenLoc);
310356
}
311357

312-
Diag(ESD->getLocation(), diag::err_expansion_statements_todo);
313-
return StmtError();
358+
// If not, try destructuring.
359+
StmtResult DecompDeclStmt = BuildDestructuringCXXExpansionStmt(
360+
*this, ExpansionInitializer, ColonLoc, ExpansionVar->isConstexpr(),
361+
LifetimeExtendTemps);
362+
if (DecompDeclStmt.isInvalid()) {
363+
ActOnInitializerError(ExpansionVar);
364+
return StmtError();
365+
}
366+
367+
auto *DS = DecompDeclStmt.getAs<DeclStmt>();
368+
auto *DD = cast<DecompositionDecl>(DS->getSingleDecl());
369+
if (DD->isInvalidDecl())
370+
return StmtError();
371+
372+
ExprResult Select = BuildCXXDestructuringExpansionSelectExpr(DD, Index);
373+
if (Select.isInvalid()) {
374+
ActOnInitializerError(ExpansionVar);
375+
return StmtError();
376+
}
377+
378+
if (FinaliseExpansionVar(*this, ExpansionVar, Select))
379+
return StmtError();
380+
381+
return new (Context) CXXDestructuringExpansionStmtPattern(
382+
ESD, Init, ExpansionVarStmt, DS, LParenLoc, ColonLoc, RParenLoc);
314383
}
315384

316385
StmtResult Sema::FinishCXXExpansionStmt(Stmt *Exp, Stmt *Body) {
@@ -339,8 +408,9 @@ StmtResult Sema::FinishCXXExpansionStmt(Stmt *Exp, Stmt *Body) {
339408
Shared.push_back(Iter->getRangeVarStmt());
340409
Shared.push_back(Iter->getBeginVarStmt());
341410
Shared.push_back(Iter->getEndVarStmt());
342-
} else {
343-
assert(isa<CXXEnumeratingExpansionStmtPattern>(Expansion) && "TODO");
411+
} else if (auto *Destructuring =
412+
dyn_cast<CXXDestructuringExpansionStmtPattern>(Expansion)) {
413+
Shared.push_back(Destructuring->getDecompositionDeclStmt());
344414
}
345415

346416
// Return an empty statement if the range is empty.
@@ -409,6 +479,23 @@ Sema::BuildCXXExpansionInitListSelectExpr(CXXExpansionInitListExpr *Range,
409479
return Range->getExprs()[I];
410480
}
411481

482+
ExprResult Sema::BuildCXXDestructuringExpansionSelectExpr(DecompositionDecl *DD,
483+
Expr *Idx) {
484+
if (Idx->isValueDependent())
485+
return new (Context) CXXDestructuringExpansionSelectExpr(Context, DD, Idx);
486+
487+
Expr::EvalResult ER;
488+
if (!Idx->EvaluateAsInt(ER, Context))
489+
llvm_unreachable("Failed to evaluate expansion index");
490+
491+
uint64_t I = ER.Val.getInt().getZExtValue();
492+
MarkAnyDeclReferenced(Idx->getBeginLoc(), DD, true);
493+
if (auto *BD = DD->bindings()[I]; auto *HVD = BD->getHoldingVar())
494+
return HVD->getInit();
495+
else
496+
return BD->getBinding();
497+
}
498+
412499
std::optional<uint64_t>
413500
Sema::ComputeExpansionSize(CXXExpansionStmtPattern *Expansion) {
414501
assert(!Expansion->hasDependentSize());
@@ -468,5 +555,9 @@ Sema::ComputeExpansionSize(CXXExpansionStmtPattern *Expansion) {
468555
return ER.Val.getInt().getZExtValue();
469556
}
470557

471-
llvm_unreachable("TODO");
558+
if (auto *Destructuring =
559+
dyn_cast<CXXDestructuringExpansionStmtPattern>(Expansion))
560+
return Destructuring->getDecompositionDecl()->bindings().size();
561+
562+
llvm_unreachable("Invalid expansion statement class");
472563
}

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)