Skip to content

Commit 13fb7c8

Browse files
committed
[Clang] [C++26] Expansion Statements (Part 6)
1 parent 51e1552 commit 13fb7c8

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
@@ -3700,6 +3700,8 @@ def err_conflicting_codeseg_attribute : Error<
37003700
def warn_duplicate_codeseg_attribute : Warning<
37013701
"duplicate code segment specifiers">, InGroup<Section>;
37023702

3703+
def err_expansion_stmt_invalid_init : Error<
3704+
"cannot expand expression of type %0">;
37033705
def err_expansion_stmt_vla : Error<
37043706
"cannot expand variable length array type %0">;
37053707
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
@@ -15714,6 +15714,9 @@ class Sema final : public SemaBase {
1571415714
BuildCXXExpansionInitListSelectExpr(CXXExpansionInitListExpr *Range,
1571515715
Expr *Idx);
1571615716

15717+
ExprResult BuildCXXDestructuringExpansionSelectExpr(DecompositionDecl *DD,
15718+
Expr *Idx);
15719+
1571715720
std::optional<uint64_t>
1571815721
ComputeExpansionSize(CXXExpansionStmtPattern *Expansion);
1571915722
///@}

clang/lib/Sema/SemaExpand.cpp

Lines changed: 96 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,52 @@ TryBuildIterableExpansionStmtInitializer(Sema &S, Expr *ExpansionInitializer,
191191
return Data;
192192
}
193193

194+
static StmtResult BuildDestructuringCXXExpansionStmt(
195+
Sema &S, Expr *ExpansionInitializer, SourceLocation ColonLoc,
196+
bool VarIsConstexpr,
197+
ArrayRef<MaterializeTemporaryExpr *> LifetimeExtendTemps) {
198+
auto Ctx = Sema::ExpressionEvaluationContext::PotentiallyEvaluated;
199+
if (VarIsConstexpr)
200+
Ctx = Sema::ExpressionEvaluationContext::ImmediateFunctionContext;
201+
EnterExpressionEvaluationContext ExprEvalCtx(S, Ctx);
202+
203+
// The declarations should be attached to the parent decl context.
204+
Sema::ContextRAII CtxGuard(
205+
S, S.CurContext->getEnclosingNonExpansionStatementContext(),
206+
/*NewThis=*/false);
207+
208+
UnsignedOrNone Arity =
209+
S.GetDecompositionElementCount(ExpansionInitializer->getType(), ColonLoc);
210+
211+
if (!Arity) {
212+
S.Diag(ExpansionInitializer->getBeginLoc(),
213+
diag::err_expansion_stmt_invalid_init)
214+
<< ExpansionInitializer->getType()
215+
<< ExpansionInitializer->getSourceRange();
216+
return StmtError();
217+
}
218+
219+
QualType AutoRRef = S.Context.getAutoRRefDeductType();
220+
SmallVector<BindingDecl *> Bindings;
221+
for (unsigned I = 0; I < *Arity; ++I)
222+
Bindings.push_back(BindingDecl::Create(
223+
S.Context, S.CurContext, ColonLoc,
224+
S.getPreprocessor().getIdentifierInfo("__u" + std::to_string(I)),
225+
AutoRRef));
226+
227+
TypeSourceInfo *TSI = S.Context.getTrivialTypeSourceInfo(AutoRRef);
228+
auto *DD =
229+
DecompositionDecl::Create(S.Context, S.CurContext, ColonLoc, ColonLoc,
230+
AutoRRef, TSI, SC_Auto, Bindings);
231+
232+
if (VarIsConstexpr)
233+
DD->setConstexpr(true);
234+
235+
S.ApplyForRangeOrExpansionStatementLifetimeExtension(DD, LifetimeExtendTemps);
236+
S.AddInitializerToDecl(DD, ExpansionInitializer, false);
237+
return S.ActOnDeclStmt(S.ConvertDeclToDeclGroup(DD), ColonLoc, ColonLoc);
238+
}
239+
194240
CXXExpansionStmtDecl *
195241
Sema::ActOnCXXExpansionStmtDecl(unsigned TemplateDepth,
196242
SourceLocation TemplateKWLoc) {
@@ -339,8 +385,31 @@ StmtResult Sema::BuildNonEnumeratingCXXExpansionStmtPattern(
339385
Data.EndDecl, LParenLoc, ColonLoc, RParenLoc);
340386
}
341387

342-
Diag(ESD->getLocation(), diag::err_expansion_statements_todo);
343-
return StmtError();
388+
// If not, try destructuring.
389+
StmtResult DecompDeclStmt = BuildDestructuringCXXExpansionStmt(
390+
*this, ExpansionInitializer, ColonLoc, ExpansionVar->isConstexpr(),
391+
LifetimeExtendTemps);
392+
if (DecompDeclStmt.isInvalid()) {
393+
ActOnInitializerError(ExpansionVar);
394+
return StmtError();
395+
}
396+
397+
auto *DS = DecompDeclStmt.getAs<DeclStmt>();
398+
auto *DD = cast<DecompositionDecl>(DS->getSingleDecl());
399+
if (DD->isInvalidDecl())
400+
return StmtError();
401+
402+
ExprResult Select = BuildCXXDestructuringExpansionSelectExpr(DD, Index);
403+
if (Select.isInvalid()) {
404+
ActOnInitializerError(ExpansionVar);
405+
return StmtError();
406+
}
407+
408+
if (FinaliseExpansionVar(*this, ExpansionVar, Select))
409+
return StmtError();
410+
411+
return new (Context) CXXDestructuringExpansionStmtPattern(
412+
ESD, Init, ExpansionVarStmt, DS, LParenLoc, ColonLoc, RParenLoc);
344413
}
345414

346415
StmtResult Sema::FinishCXXExpansionStmt(Stmt *Exp, Stmt *Body) {
@@ -381,8 +450,9 @@ StmtResult Sema::FinishCXXExpansionStmt(Stmt *Exp, Stmt *Body) {
381450
Shared.push_back(Iter->getRangeVarStmt());
382451
Shared.push_back(Iter->getBeginVarStmt());
383452
Shared.push_back(Iter->getEndVarStmt());
384-
} else {
385-
assert(isa<CXXEnumeratingExpansionStmtPattern>(Expansion) && "TODO");
453+
} else if (auto *Destructuring =
454+
dyn_cast<CXXDestructuringExpansionStmtPattern>(Expansion)) {
455+
Shared.push_back(Destructuring->getDecompositionDeclStmt());
386456
}
387457

388458
// Return an empty statement if the range is empty.
@@ -446,6 +516,23 @@ Sema::BuildCXXExpansionInitListSelectExpr(CXXExpansionInitListExpr *Range,
446516
return Range->getExprs()[I];
447517
}
448518

519+
ExprResult Sema::BuildCXXDestructuringExpansionSelectExpr(DecompositionDecl *DD,
520+
Expr *Idx) {
521+
if (Idx->isValueDependent())
522+
return new (Context) CXXDestructuringExpansionSelectExpr(Context, DD, Idx);
523+
524+
Expr::EvalResult ER;
525+
if (!Idx->EvaluateAsInt(ER, Context))
526+
llvm_unreachable("Failed to evaluate expansion index");
527+
528+
uint64_t I = ER.Val.getInt().getZExtValue();
529+
MarkAnyDeclReferenced(Idx->getBeginLoc(), DD, true);
530+
if (auto *BD = DD->bindings()[I]; auto *HVD = BD->getHoldingVar())
531+
return HVD->getInit();
532+
else
533+
return BD->getBinding();
534+
}
535+
449536
std::optional<uint64_t>
450537
Sema::ComputeExpansionSize(CXXExpansionStmtPattern *Expansion) {
451538
assert(!Expansion->hasDependentSize());
@@ -639,5 +726,9 @@ Sema::ComputeExpansionSize(CXXExpansionStmtPattern *Expansion) {
639726
return ER.Val.getInt().getZExtValue();
640727
}
641728

642-
llvm_unreachable("TODO");
729+
if (auto *Destructuring =
730+
dyn_cast<CXXDestructuringExpansionStmtPattern>(Expansion))
731+
return Destructuring->getDecompositionDecl()->bindings().size();
732+
733+
llvm_unreachable("Invalid expansion statement class");
643734
}

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)