Skip to content

Commit d9bd6e3

Browse files
zygoloidzmodem
authored andcommitted
PR45083: Mark statement expressions as being dependent if they appear in
a dependent context. This matches the GCC behavior. We track the enclosing template depth when determining whether a statement expression is within a dependent context; there doesn't appear to be any other reliable way to determine this. We previously assumed they were neither value- nor instantiation-dependent under any circumstances, which would lead to crashes and other misbehavior. (cherry picked from commit 5c845c1)
1 parent 5e06281 commit d9bd6e3

File tree

14 files changed

+231
-30
lines changed

14 files changed

+231
-30
lines changed

clang/include/clang/AST/Expr.h

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3955,14 +3955,18 @@ class StmtExpr : public Expr {
39553955
Stmt *SubStmt;
39563956
SourceLocation LParenLoc, RParenLoc;
39573957
public:
3958-
// FIXME: Does type-dependence need to be computed differently?
3959-
// FIXME: Do we need to compute instantiation instantiation-dependence for
3960-
// statements? (ugh!)
3961-
StmtExpr(CompoundStmt *substmt, QualType T,
3962-
SourceLocation lp, SourceLocation rp) :
3963-
Expr(StmtExprClass, T, VK_RValue, OK_Ordinary,
3964-
T->isDependentType(), false, false, false),
3965-
SubStmt(substmt), LParenLoc(lp), RParenLoc(rp) { }
3958+
StmtExpr(CompoundStmt *SubStmt, QualType T, SourceLocation LParenLoc,
3959+
SourceLocation RParenLoc, unsigned TemplateDepth)
3960+
: // We treat a statement-expression in a dependent context as
3961+
// always being value- and instantiation-dependent. This matches the
3962+
// behavior of lambda-expressions and GCC.
3963+
Expr(StmtExprClass, T, VK_RValue, OK_Ordinary, T->isDependentType(),
3964+
TemplateDepth != 0, TemplateDepth != 0, false),
3965+
SubStmt(SubStmt), LParenLoc(LParenLoc), RParenLoc(RParenLoc) {
3966+
// FIXME: A templated statement expression should have an associated
3967+
// DeclContext so that nested declarations always have a dependent context.
3968+
StmtExprBits.TemplateDepth = TemplateDepth;
3969+
}
39663970

39673971
/// Build an empty statement expression.
39683972
explicit StmtExpr(EmptyShell Empty) : Expr(StmtExprClass, Empty) { }
@@ -3979,6 +3983,8 @@ class StmtExpr : public Expr {
39793983
SourceLocation getRParenLoc() const { return RParenLoc; }
39803984
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
39813985

3986+
unsigned getTemplateDepth() const { return StmtExprBits.TemplateDepth; }
3987+
39823988
static bool classof(const Stmt *T) {
39833989
return T->getStmtClass() == StmtExprClass;
39843990
}

clang/include/clang/AST/Stmt.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,18 @@ class alignas(void *) Stmt {
588588
unsigned Kind : 2;
589589
};
590590

591+
class StmtExprBitfields {
592+
friend class ASTStmtReader;
593+
friend class StmtExpr;
594+
595+
unsigned : NumExprBits;
596+
597+
/// The number of levels of template parameters enclosing this statement
598+
/// expression. Used to determine if a statement expression remains
599+
/// dependent after instantiation.
600+
unsigned TemplateDepth;
601+
};
602+
591603
//===--- C++ Expression bitfields classes ---===//
592604

593605
class CXXOperatorCallExprBitfields {
@@ -996,6 +1008,9 @@ class alignas(void *) Stmt {
9961008
PseudoObjectExprBitfields PseudoObjectExprBits;
9971009
SourceLocExprBitfields SourceLocExprBits;
9981010

1011+
// GNU Extensions.
1012+
StmtExprBitfields StmtExprBits;
1013+
9991014
// C++ Expressions
10001015
CXXOperatorCallExprBitfields CXXOperatorCallExprBits;
10011016
CXXRewrittenBinaryOperatorBitfields CXXRewrittenBinaryOperatorBits;

clang/include/clang/Sema/Sema.h

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -620,13 +620,32 @@ class Sema final {
620620
/// function, block, and method scopes that are currently active.
621621
SmallVector<sema::FunctionScopeInfo *, 4> FunctionScopes;
622622

623+
/// The index of the first FunctionScope that corresponds to the current
624+
/// context.
625+
unsigned FunctionScopesStart = 0;
626+
627+
ArrayRef<sema::FunctionScopeInfo*> getFunctionScopes() const {
628+
return llvm::makeArrayRef(FunctionScopes.begin() + FunctionScopesStart,
629+
FunctionScopes.end());
630+
}
631+
623632
/// Stack containing information needed when in C++2a an 'auto' is encountered
624633
/// in a function declaration parameter type specifier in order to invent a
625634
/// corresponding template parameter in the enclosing abbreviated function
626635
/// template. This information is also present in LambdaScopeInfo, stored in
627636
/// the FunctionScopes stack.
628637
SmallVector<InventedTemplateParameterInfo, 4> InventedParameterInfos;
629638

639+
/// The index of the first InventedParameterInfo that refers to the current
640+
/// context.
641+
unsigned InventedParameterInfosStart = 0;
642+
643+
ArrayRef<InventedTemplateParameterInfo> getInventedParameterInfos() const {
644+
return llvm::makeArrayRef(InventedParameterInfos.begin() +
645+
InventedParameterInfosStart,
646+
InventedParameterInfos.end());
647+
}
648+
630649
typedef LazyVector<TypedefNameDecl *, ExternalSemaSource,
631650
&ExternalSemaSource::ReadExtVectorDecls, 2, 2>
632651
ExtVectorDeclsType;
@@ -800,24 +819,33 @@ class Sema final {
800819
DeclContext *SavedContext;
801820
ProcessingContextState SavedContextState;
802821
QualType SavedCXXThisTypeOverride;
822+
unsigned SavedFunctionScopesStart;
823+
unsigned SavedInventedParameterInfosStart;
803824

804825
public:
805826
ContextRAII(Sema &S, DeclContext *ContextToPush, bool NewThisContext = true)
806827
: S(S), SavedContext(S.CurContext),
807828
SavedContextState(S.DelayedDiagnostics.pushUndelayed()),
808-
SavedCXXThisTypeOverride(S.CXXThisTypeOverride)
829+
SavedCXXThisTypeOverride(S.CXXThisTypeOverride),
830+
SavedFunctionScopesStart(S.FunctionScopesStart),
831+
SavedInventedParameterInfosStart(S.InventedParameterInfosStart)
809832
{
810833
assert(ContextToPush && "pushing null context");
811834
S.CurContext = ContextToPush;
812835
if (NewThisContext)
813836
S.CXXThisTypeOverride = QualType();
837+
// Any saved FunctionScopes do not refer to this context.
838+
S.FunctionScopesStart = S.FunctionScopes.size();
839+
S.InventedParameterInfosStart = S.InventedParameterInfos.size();
814840
}
815841

816842
void pop() {
817843
if (!SavedContext) return;
818844
S.CurContext = SavedContext;
819845
S.DelayedDiagnostics.popUndelayed(SavedContextState);
820846
S.CXXThisTypeOverride = SavedCXXThisTypeOverride;
847+
S.FunctionScopesStart = SavedFunctionScopesStart;
848+
S.InventedParameterInfosStart = SavedInventedParameterInfosStart;
821849
SavedContext = nullptr;
822850
}
823851

@@ -4923,8 +4951,10 @@ class Sema final {
49234951
LabelDecl *TheDecl);
49244952

49254953
void ActOnStartStmtExpr();
4926-
ExprResult ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
4927-
SourceLocation RPLoc); // "({..})"
4954+
ExprResult ActOnStmtExpr(Scope *S, SourceLocation LPLoc, Stmt *SubStmt,
4955+
SourceLocation RPLoc);
4956+
ExprResult BuildStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
4957+
SourceLocation RPLoc, unsigned TemplateDepth);
49284958
// Handle the final expression in a statement expression.
49294959
ExprResult ActOnStmtExprResult(ExprResult E);
49304960
void ActOnStmtExprError();
@@ -11924,6 +11954,13 @@ class Sema final {
1192411954
return DC;
1192511955
}
1192611956

11957+
/// Determine the number of levels of enclosing template parameters. This is
11958+
/// only usable while parsing. Note that this does not include dependent
11959+
/// contexts in which no template parameters have yet been declared, such as
11960+
/// in a terse function template or generic lambda before the first 'auto' is
11961+
/// encountered.
11962+
unsigned getTemplateDepth(Scope *S) const;
11963+
1192711964
/// To be used for checking whether the arguments being passed to
1192811965
/// function exceeds the number of parameters expected for it.
1192911966
static bool TooManyArguments(size_t NumParams, size_t NumArgs,

clang/include/clang/Sema/Template.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,16 @@ class VarDecl;
9595
return TemplateArgumentLists.size();
9696
}
9797

98+
/// Determine how many of the \p OldDepth outermost template parameter
99+
/// lists would be removed by substituting these arguments.
100+
unsigned getNewDepth(unsigned OldDepth) const {
101+
if (OldDepth < NumRetainedOuterLevels)
102+
return OldDepth;
103+
if (OldDepth < getNumLevels())
104+
return NumRetainedOuterLevels;
105+
return OldDepth - TemplateArgumentLists.size();
106+
}
107+
98108
/// Retrieve the template argument at a given depth and index.
99109
const TemplateArgument &operator()(unsigned Depth, unsigned Index) const {
100110
assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels());

clang/lib/AST/ASTImporter.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6724,8 +6724,9 @@ ExpectedStmt ASTNodeImporter::VisitStmtExpr(StmtExpr *E) {
67246724
SourceLocation ToLParenLoc, ToRParenLoc;
67256725
std::tie(ToSubStmt, ToType, ToLParenLoc, ToRParenLoc) = *Imp;
67266726

6727-
return new (Importer.getToContext()) StmtExpr(
6728-
ToSubStmt, ToType, ToLParenLoc, ToRParenLoc);
6727+
return new (Importer.getToContext())
6728+
StmtExpr(ToSubStmt, ToType, ToLParenLoc, ToRParenLoc,
6729+
E->getTemplateDepth());
67296730
}
67306731

67316732
ExpectedStmt ASTNodeImporter::VisitUnaryOperator(UnaryOperator *E) {

clang/lib/Parse/ParseExpr.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2655,7 +2655,8 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
26552655

26562656
// If the substmt parsed correctly, build the AST node.
26572657
if (!Stmt.isInvalid()) {
2658-
Result = Actions.ActOnStmtExpr(OpenLoc, Stmt.get(), Tok.getLocation());
2658+
Result = Actions.ActOnStmtExpr(getCurScope(), OpenLoc, Stmt.get(),
2659+
Tok.getLocation());
26592660
} else {
26602661
Actions.ActOnStmtExprError();
26612662
}

clang/lib/Sema/SemaExpr.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13908,9 +13908,13 @@ void Sema::ActOnStmtExprError() {
1390813908
PopExpressionEvaluationContext();
1390913909
}
1391013910

13911-
ExprResult
13912-
Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
13913-
SourceLocation RPLoc) { // "({..})"
13911+
ExprResult Sema::ActOnStmtExpr(Scope *S, SourceLocation LPLoc, Stmt *SubStmt,
13912+
SourceLocation RPLoc) {
13913+
return BuildStmtExpr(LPLoc, SubStmt, RPLoc, getTemplateDepth(S));
13914+
}
13915+
13916+
ExprResult Sema::BuildStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
13917+
SourceLocation RPLoc, unsigned TemplateDepth) {
1391413918
assert(SubStmt && isa<CompoundStmt>(SubStmt) && "Invalid action invocation!");
1391513919
CompoundStmt *Compound = cast<CompoundStmt>(SubStmt);
1391613920

@@ -13941,7 +13945,8 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
1394113945

1394213946
// FIXME: Check that expression type is complete/non-abstract; statement
1394313947
// expressions are not lvalues.
13944-
Expr *ResStmtExpr = new (Context) StmtExpr(Compound, Ty, LPLoc, RPLoc);
13948+
Expr *ResStmtExpr =
13949+
new (Context) StmtExpr(Compound, Ty, LPLoc, RPLoc, TemplateDepth);
1394513950
if (StmtExprMayBindToTemp)
1394613951
return MaybeBindToTemporary(ResStmtExpr);
1394713952
return ResStmtExpr;

clang/lib/Sema/SemaExprCXX.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6800,8 +6800,9 @@ Stmt *Sema::MaybeCreateStmtWithCleanups(Stmt *SubStmt) {
68006800
// a new AsmStmtWithTemporaries.
68016801
CompoundStmt *CompStmt = CompoundStmt::Create(
68026802
Context, SubStmt, SourceLocation(), SourceLocation());
6803-
Expr *E = new (Context) StmtExpr(CompStmt, Context.VoidTy, SourceLocation(),
6804-
SourceLocation());
6803+
Expr *E = new (Context)
6804+
StmtExpr(CompStmt, Context.VoidTy, SourceLocation(), SourceLocation(),
6805+
/*FIXME TemplateDepth=*/0);
68056806
return MaybeCreateExprWithCleanups(E);
68066807
}
68076808

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,48 @@ clang::getTemplateParamsRange(TemplateParameterList const * const *Ps,
4646
return SourceRange(Ps[0]->getTemplateLoc(), Ps[N-1]->getRAngleLoc());
4747
}
4848

49+
unsigned Sema::getTemplateDepth(Scope *S) const {
50+
unsigned Depth = 0;
51+
52+
// Each template parameter scope represents one level of template parameter
53+
// depth.
54+
for (Scope *TempParamScope = S->getTemplateParamParent();
55+
TempParamScope && !Depth;
56+
TempParamScope = TempParamScope->getParent()->getTemplateParamParent()) {
57+
++Depth;
58+
}
59+
60+
// Note that there are template parameters with the given depth.
61+
auto ParamsAtDepth = [&](unsigned D) { Depth = std::max(Depth, D + 1); };
62+
63+
// Look for parameters of an enclosing generic lambda. We don't create a
64+
// template parameter scope for these.
65+
for (FunctionScopeInfo *FSI : getFunctionScopes()) {
66+
if (auto *LSI = dyn_cast<LambdaScopeInfo>(FSI)) {
67+
if (!LSI->TemplateParams.empty()) {
68+
ParamsAtDepth(LSI->AutoTemplateParameterDepth);
69+
break;
70+
}
71+
if (LSI->GLTemplateParameterList) {
72+
ParamsAtDepth(LSI->GLTemplateParameterList->getDepth());
73+
break;
74+
}
75+
}
76+
}
77+
78+
// Look for parameters of an enclosing terse function template. We don't
79+
// create a template parameter scope for these either.
80+
for (const InventedTemplateParameterInfo &Info :
81+
getInventedParameterInfos()) {
82+
if (!Info.TemplateParams.empty()) {
83+
ParamsAtDepth(Info.AutoTemplateParameterDepth);
84+
break;
85+
}
86+
}
87+
88+
return Depth;
89+
}
90+
4991
/// \brief Determine whether the declaration found is acceptable as the name
5092
/// of a template and, if so, return that template declaration. Otherwise,
5193
/// returns null.

clang/lib/Sema/SemaTemplateInstantiate.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -922,6 +922,10 @@ namespace {
922922
this->Entity = Entity;
923923
}
924924

925+
unsigned TransformTemplateDepth(unsigned Depth) {
926+
return TemplateArgs.getNewDepth(Depth);
927+
}
928+
925929
bool TryExpandParameterPacks(SourceLocation EllipsisLoc,
926930
SourceRange PatternRange,
927931
ArrayRef<UnexpandedParameterPack> Unexpanded,

0 commit comments

Comments
 (0)