Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -3700,6 +3700,8 @@ def err_conflicting_codeseg_attribute : Error<
def warn_duplicate_codeseg_attribute : Warning<
"duplicate code segment specifiers">, InGroup<Section>;

def err_expansion_stmt_invalid_init : Error<
"cannot expand expression of type %0">;
def err_expansion_stmt_vla : Error<
"cannot expand variable length array type %0">;
def err_expansion_stmt_incomplete : Error<
Expand Down
96 changes: 90 additions & 6 deletions clang/lib/Sema/SemaExpand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ static bool HasDependentSize(const CXXExpansionStmtPattern *Pattern) {
return true;

case CXXExpansionStmtPattern::ExpansionStmtKind::Destructuring:
llvm_unreachable("TODO");
return false;
}

llvm_unreachable("invalid pattern kind");
Expand Down Expand Up @@ -220,6 +220,52 @@ TryBuildIterableExpansionStmtInitializer(Sema &S, Expr *ExpansionInitializer,
return Data;
}

static StmtResult BuildDestructuringDecompositionDecl(
Sema &S, Expr *ExpansionInitializer, SourceLocation ColonLoc,
bool VarIsConstexpr,
ArrayRef<MaterializeTemporaryExpr *> LifetimeExtendTemps) {
auto Ctx = Sema::ExpressionEvaluationContext::PotentiallyEvaluated;
if (VarIsConstexpr)
Ctx = Sema::ExpressionEvaluationContext::ImmediateFunctionContext;
EnterExpressionEvaluationContext ExprEvalCtx(S, Ctx);

// The declarations should be attached to the parent decl context.
Sema::ContextRAII CtxGuard(
S, S.CurContext->getEnclosingNonExpansionStatementContext(),
/*NewThis=*/false);

UnsignedOrNone Arity =
S.GetDecompositionElementCount(ExpansionInitializer->getType(), ColonLoc);

if (!Arity) {
S.Diag(ExpansionInitializer->getBeginLoc(),
diag::err_expansion_stmt_invalid_init)
<< ExpansionInitializer->getType()
<< ExpansionInitializer->getSourceRange();
return StmtError();
}

QualType AutoRRef = S.Context.getAutoRRefDeductType();
SmallVector<BindingDecl *> Bindings;
for (unsigned I = 0; I < *Arity; ++I)
Bindings.push_back(BindingDecl::Create(
S.Context, S.CurContext, ColonLoc,
S.getPreprocessor().getIdentifierInfo("__u" + std::to_string(I)),
AutoRRef));

TypeSourceInfo *TSI = S.Context.getTrivialTypeSourceInfo(AutoRRef);
auto *DD =
DecompositionDecl::Create(S.Context, S.CurContext, ColonLoc, ColonLoc,
AutoRRef, TSI, SC_Auto, Bindings);

if (VarIsConstexpr)
DD->setConstexpr(true);

S.ApplyForRangeOrExpansionStatementLifetimeExtension(DD, LifetimeExtendTemps);
S.AddInitializerToDecl(DD, ExpansionInitializer, false);
return S.ActOnDeclStmt(S.ConvertDeclToDeclGroup(DD), ColonLoc, ColonLoc);
}

CXXExpansionStmtDecl *
Sema::ActOnCXXExpansionStmtDecl(unsigned TemplateDepth,
SourceLocation TemplateKWLoc) {
Expand Down Expand Up @@ -368,8 +414,43 @@ StmtResult Sema::BuildNonEnumeratingCXXExpansionStmtPattern(
Data.EndDecl, LParenLoc, ColonLoc, RParenLoc);
}

Diag(ESD->getLocation(), diag::err_expansion_statements_todo);
return StmtError();
// If not, try destructuring.
StmtResult DecompDeclStmt = BuildDestructuringDecompositionDecl(
*this, ExpansionInitializer, ColonLoc, ExpansionVar->isConstexpr(),
LifetimeExtendTemps);
if (DecompDeclStmt.isInvalid()) {
ActOnInitializerError(ExpansionVar);
return StmtError();
}

auto *DS = DecompDeclStmt.getAs<DeclStmt>();
auto *DD = cast<DecompositionDecl>(DS->getSingleDecl());
if (DD->isInvalidDecl())
return StmtError();

// Synthesise an InitListExpr to store the bindings; this essentially lets us
// desugar the expansion of a destructuring expansion statement to that of an
// enumerating expansion statement.
SmallVector<Expr *> Bindings;
for (BindingDecl *BD : DD->bindings()) {
auto *HVD = BD->getHoldingVar();
Bindings.push_back(HVD ? HVD->getInit() : BD->getBinding());
}

ExprResult Select = BuildCXXExpansionSelectExpr(
new (Context) InitListExpr(Context, ColonLoc, Bindings, ColonLoc),
Index);

if (Select.isInvalid()) {
ActOnInitializerError(ExpansionVar);
return StmtError();
}

if (FinaliseExpansionVar(*this, ExpansionVar, Select))
return StmtError();

return CXXExpansionStmtPattern::CreateDestructuring(
Context, ESD, Init, ExpansionVarStmt, DS, LParenLoc, ColonLoc, RParenLoc);
}

StmtResult Sema::FinishCXXExpansionStmt(Stmt *Exp, Stmt *Body) {
Expand Down Expand Up @@ -409,8 +490,10 @@ StmtResult Sema::FinishCXXExpansionStmt(Stmt *Exp, Stmt *Body) {
Shared.push_back(Expansion->getRangeVarStmt());
Shared.push_back(Expansion->getBeginVarStmt());
Shared.push_back(Expansion->getEndVarStmt());
} else {
assert(Expansion->isEnumerating() && "TODO");
} else if (Expansion->isDestructuring()) {
Shared.push_back(Expansion->getDecompositionDeclStmt());
MarkAnyDeclReferenced(Exp->getBeginLoc(), Expansion->getDecompositionDecl(),
true);
}

// Return an empty statement if the range is empty.
Expand Down Expand Up @@ -663,5 +746,6 @@ Sema::ComputeExpansionSize(CXXExpansionStmtPattern *Expansion) {
return ER.Val.getInt().getZExtValue();
}

llvm_unreachable("TODO");
assert(Expansion->isDestructuring());
return Expansion->getDecompositionDecl()->bindings().size();
}
88 changes: 63 additions & 25 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -9295,28 +9295,51 @@ TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) {
template <typename Derived>
StmtResult TreeTransform<Derived>::TransformCXXExpansionStmtPattern(
CXXExpansionStmtPattern *S) {
ExprResult ExpansionInitializer;
SmallVector<MaterializeTemporaryExpr *, 8> LifetimeExtendTemps;
CXXExpansionStmtDecl *NewESD = nullptr;
Stmt *Init = nullptr;
DeclStmt *ExpansionVarStmt = nullptr;
Decl *ESD =
getDerived().TransformDecl(S->getDecl()->getLocation(), S->getDecl());
if (!ESD || ESD->isInvalidDecl())
return StmtError();
NewESD = cast<CXXExpansionStmtDecl>(ESD);

Init = S->getInit();
if (Init) {
StmtResult SR = getDerived().TransformStmt(Init);
if (SR.isInvalid())
// Collect lifetime-extended temporaries in case this ends up being a
// destructuring expansion statement (for other kinds of expansion statements,
// this should make no difference since we ignore 'LifetimeExtendTemps' for
// those).
{
EnterExpressionEvaluationContext ExprEvalCtx(
SemaRef, SemaRef.currentEvaluationContext().Context);
SemaRef.currentEvaluationContext().InLifetimeExtendingContext = true;
SemaRef.currentEvaluationContext().RebuildDefaultArgOrDefaultInit = true;
Decl *ESD =
getDerived().TransformDecl(S->getDecl()->getLocation(), S->getDecl());
if (!ESD || ESD->isInvalidDecl())
return StmtError();
Init = SR.get();
}
NewESD = cast<CXXExpansionStmtDecl>(ESD);

StmtResult ExpansionVar =
getDerived().TransformStmt(S->getExpansionVarStmt());
if (ExpansionVar.isInvalid())
return StmtError();
ExpansionVarStmt = cast<DeclStmt>(ExpansionVar.get());
Init = S->getInit();
if (Init) {
StmtResult SR = getDerived().TransformStmt(Init);
if (SR.isInvalid())
return StmtError();
Init = SR.get();
}

StmtResult ExpansionVar =
getDerived().TransformStmt(S->getExpansionVarStmt());
if (ExpansionVar.isInvalid())
return StmtError();
ExpansionVarStmt = cast<DeclStmt>(ExpansionVar.get());

if (S->isDependent()) {
ExpansionInitializer =
getDerived().TransformExpr(S->getExpansionInitializer());
if (ExpansionInitializer.isInvalid())
return StmtError();

LifetimeExtendTemps =
SemaRef.currentEvaluationContext().ForRangeLifetimeExtendTemps;
}
}

CXXExpansionStmtPattern *NewPattern = nullptr;
if (S->isEnumerating()) {
Expand All @@ -9338,22 +9361,22 @@ StmtResult TreeTransform<Derived>::TransformCXXExpansionStmtPattern(
Range.getAs<DeclStmt>(), Begin.getAs<DeclStmt>(), End.getAs<DeclStmt>(),
S->getLParenLoc(), S->getColonLoc(), S->getRParenLoc());
} else if (S->isDependent()) {
ExprResult ExpansionInitializer =
getDerived().TransformExpr(S->getExpansionInitializer());
if (ExpansionInitializer.isInvalid())
return StmtError();

StmtResult Res = SemaRef.BuildNonEnumeratingCXXExpansionStmtPattern(
NewESD, Init, ExpansionVarStmt, ExpansionInitializer.get(),
S->getLParenLoc(), S->getColonLoc(), S->getRParenLoc(),
/*LifetimeExtendTemps=*/{});
LifetimeExtendTemps);

if (Res.isInvalid())
return StmtError();

NewPattern = cast<CXXExpansionStmtPattern>(Res.get());
} else {
llvm_unreachable("TODO");
// The only time we instantiate an expansion statement is if its expansion
// size is dependent (otherwise, we only instantiate the expansions and
// leave the underlying CXXExpansionStmtPattern as-is). Since destructuring
// expansion statements never have a dependent size, we should never get
// here.
llvm_unreachable("destructuring pattern should never be instantiated");
}

StmtResult Body = getDerived().TransformStmt(S->getBody());
Expand Down Expand Up @@ -9384,8 +9407,23 @@ StmtResult TreeTransform<Derived>::TransformCXXExpansionStmtInstantiation(
SmallVector<Stmt *> SharedStmts;
SmallVector<Stmt *> Instantiations;

if (TransformStmts(SharedStmts, S->getSharedStmts()))
return StmtError();
// Apply lifetime extension to the shared statements if this was a
// destructuring expansion statement.
{
EnterExpressionEvaluationContext ExprEvalCtx(
SemaRef, SemaRef.currentEvaluationContext().Context);
SemaRef.currentEvaluationContext().InLifetimeExtendingContext = true;
SemaRef.currentEvaluationContext().RebuildDefaultArgOrDefaultInit = true;
if (TransformStmts(SharedStmts, S->getSharedStmts()))
return StmtError();

if (S->shouldApplyLifetimeExtensionToSharedStmts()) {
auto *VD =
cast<VarDecl>(cast<DeclStmt>(SharedStmts.front())->getSingleDecl());
SemaRef.ApplyForRangeOrExpansionStatementLifetimeExtension(
VD, SemaRef.currentEvaluationContext().ForRangeLifetimeExtendTemps);
}
}

if (TransformStmts(Instantiations, S->getInstantiations()))
return StmtError();
Expand Down
Loading