Skip to content

Commit 5c845c1

Browse files
committed
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.
1 parent 200b206 commit 5c845c1

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
@@ -3959,14 +3959,18 @@ class StmtExpr : public Expr {
39593959
Stmt *SubStmt;
39603960
SourceLocation LParenLoc, RParenLoc;
39613961
public:
3962-
// FIXME: Does type-dependence need to be computed differently?
3963-
// FIXME: Do we need to compute instantiation instantiation-dependence for
3964-
// statements? (ugh!)
3965-
StmtExpr(CompoundStmt *substmt, QualType T,
3966-
SourceLocation lp, SourceLocation rp) :
3967-
Expr(StmtExprClass, T, VK_RValue, OK_Ordinary,
3968-
T->isDependentType(), false, false, false),
3969-
SubStmt(substmt), LParenLoc(lp), RParenLoc(rp) { }
3962+
StmtExpr(CompoundStmt *SubStmt, QualType T, SourceLocation LParenLoc,
3963+
SourceLocation RParenLoc, unsigned TemplateDepth)
3964+
: // We treat a statement-expression in a dependent context as
3965+
// always being value- and instantiation-dependent. This matches the
3966+
// behavior of lambda-expressions and GCC.
3967+
Expr(StmtExprClass, T, VK_RValue, OK_Ordinary, T->isDependentType(),
3968+
TemplateDepth != 0, TemplateDepth != 0, false),
3969+
SubStmt(SubStmt), LParenLoc(LParenLoc), RParenLoc(RParenLoc) {
3970+
// FIXME: A templated statement expression should have an associated
3971+
// DeclContext so that nested declarations always have a dependent context.
3972+
StmtExprBits.TemplateDepth = TemplateDepth;
3973+
}
39703974

39713975
/// Build an empty statement expression.
39723976
explicit StmtExpr(EmptyShell Empty) : Expr(StmtExprClass, Empty) { }
@@ -3983,6 +3987,8 @@ class StmtExpr : public Expr {
39833987
SourceLocation getRParenLoc() const { return RParenLoc; }
39843988
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
39853989

3990+
unsigned getTemplateDepth() const { return StmtExprBits.TemplateDepth; }
3991+
39863992
static bool classof(const Stmt *T) {
39873993
return T->getStmtClass() == StmtExprClass;
39883994
}

clang/include/clang/AST/Stmt.h

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

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

594606
class CXXOperatorCallExprBitfields {
@@ -997,6 +1009,9 @@ class alignas(void *) Stmt {
9971009
PseudoObjectExprBitfields PseudoObjectExprBits;
9981010
SourceLocExprBitfields SourceLocExprBits;
9991011

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

clang/include/clang/Sema/Sema.h

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

633+
/// The index of the first FunctionScope that corresponds to the current
634+
/// context.
635+
unsigned FunctionScopesStart = 0;
636+
637+
ArrayRef<sema::FunctionScopeInfo*> getFunctionScopes() const {
638+
return llvm::makeArrayRef(FunctionScopes.begin() + FunctionScopesStart,
639+
FunctionScopes.end());
640+
}
641+
633642
/// Stack containing information needed when in C++2a an 'auto' is encountered
634643
/// in a function declaration parameter type specifier in order to invent a
635644
/// corresponding template parameter in the enclosing abbreviated function
636645
/// template. This information is also present in LambdaScopeInfo, stored in
637646
/// the FunctionScopes stack.
638647
SmallVector<InventedTemplateParameterInfo, 4> InventedParameterInfos;
639648

649+
/// The index of the first InventedParameterInfo that refers to the current
650+
/// context.
651+
unsigned InventedParameterInfosStart = 0;
652+
653+
ArrayRef<InventedTemplateParameterInfo> getInventedParameterInfos() const {
654+
return llvm::makeArrayRef(InventedParameterInfos.begin() +
655+
InventedParameterInfosStart,
656+
InventedParameterInfos.end());
657+
}
658+
640659
typedef LazyVector<TypedefNameDecl *, ExternalSemaSource,
641660
&ExternalSemaSource::ReadExtVectorDecls, 2, 2>
642661
ExtVectorDeclsType;
@@ -810,24 +829,33 @@ class Sema final {
810829
DeclContext *SavedContext;
811830
ProcessingContextState SavedContextState;
812831
QualType SavedCXXThisTypeOverride;
832+
unsigned SavedFunctionScopesStart;
833+
unsigned SavedInventedParameterInfosStart;
813834

814835
public:
815836
ContextRAII(Sema &S, DeclContext *ContextToPush, bool NewThisContext = true)
816837
: S(S), SavedContext(S.CurContext),
817838
SavedContextState(S.DelayedDiagnostics.pushUndelayed()),
818-
SavedCXXThisTypeOverride(S.CXXThisTypeOverride)
839+
SavedCXXThisTypeOverride(S.CXXThisTypeOverride),
840+
SavedFunctionScopesStart(S.FunctionScopesStart),
841+
SavedInventedParameterInfosStart(S.InventedParameterInfosStart)
819842
{
820843
assert(ContextToPush && "pushing null context");
821844
S.CurContext = ContextToPush;
822845
if (NewThisContext)
823846
S.CXXThisTypeOverride = QualType();
847+
// Any saved FunctionScopes do not refer to this context.
848+
S.FunctionScopesStart = S.FunctionScopes.size();
849+
S.InventedParameterInfosStart = S.InventedParameterInfos.size();
824850
}
825851

826852
void pop() {
827853
if (!SavedContext) return;
828854
S.CurContext = SavedContext;
829855
S.DelayedDiagnostics.popUndelayed(SavedContextState);
830856
S.CXXThisTypeOverride = SavedCXXThisTypeOverride;
857+
S.FunctionScopesStart = SavedFunctionScopesStart;
858+
S.InventedParameterInfosStart = SavedInventedParameterInfosStart;
831859
SavedContext = nullptr;
832860
}
833861

@@ -4963,8 +4991,10 @@ class Sema final {
49634991
LabelDecl *TheDecl);
49644992

49654993
void ActOnStartStmtExpr();
4966-
ExprResult ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
4967-
SourceLocation RPLoc); // "({..})"
4994+
ExprResult ActOnStmtExpr(Scope *S, SourceLocation LPLoc, Stmt *SubStmt,
4995+
SourceLocation RPLoc);
4996+
ExprResult BuildStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
4997+
SourceLocation RPLoc, unsigned TemplateDepth);
49684998
// Handle the final expression in a statement expression.
49694999
ExprResult ActOnStmtExprResult(ExprResult E);
49705000
void ActOnStmtExprError();
@@ -12020,6 +12050,13 @@ class Sema final {
1202012050
return DC;
1202112051
}
1202212052

12053+
/// Determine the number of levels of enclosing template parameters. This is
12054+
/// only usable while parsing. Note that this does not include dependent
12055+
/// contexts in which no template parameters have yet been declared, such as
12056+
/// in a terse function template or generic lambda before the first 'auto' is
12057+
/// encountered.
12058+
unsigned getTemplateDepth(Scope *S) const;
12059+
1202312060
/// To be used for checking whether the arguments being passed to
1202412061
/// function exceeds the number of parameters expected for it.
1202512062
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
@@ -6635,8 +6635,9 @@ ExpectedStmt ASTNodeImporter::VisitStmtExpr(StmtExpr *E) {
66356635
if (Err)
66366636
return std::move(Err);
66376637

6638-
return new (Importer.getToContext()) StmtExpr(
6639-
ToSubStmt, ToType, ToLParenLoc, ToRParenLoc);
6638+
return new (Importer.getToContext())
6639+
StmtExpr(ToSubStmt, ToType, ToLParenLoc, ToRParenLoc,
6640+
E->getTemplateDepth());
66406641
}
66416642

66426643
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
@@ -13921,9 +13921,13 @@ void Sema::ActOnStmtExprError() {
1392113921
PopExpressionEvaluationContext();
1392213922
}
1392313923

13924-
ExprResult
13925-
Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
13926-
SourceLocation RPLoc) { // "({..})"
13924+
ExprResult Sema::ActOnStmtExpr(Scope *S, SourceLocation LPLoc, Stmt *SubStmt,
13925+
SourceLocation RPLoc) {
13926+
return BuildStmtExpr(LPLoc, SubStmt, RPLoc, getTemplateDepth(S));
13927+
}
13928+
13929+
ExprResult Sema::BuildStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
13930+
SourceLocation RPLoc, unsigned TemplateDepth) {
1392713931
assert(SubStmt && isa<CompoundStmt>(SubStmt) && "Invalid action invocation!");
1392813932
CompoundStmt *Compound = cast<CompoundStmt>(SubStmt);
1392913933

@@ -13954,7 +13958,8 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
1395413958

1395513959
// FIXME: Check that expression type is complete/non-abstract; statement
1395613960
// expressions are not lvalues.
13957-
Expr *ResStmtExpr = new (Context) StmtExpr(Compound, Ty, LPLoc, RPLoc);
13961+
Expr *ResStmtExpr =
13962+
new (Context) StmtExpr(Compound, Ty, LPLoc, RPLoc, TemplateDepth);
1395813963
if (StmtExprMayBindToTemp)
1395913964
return MaybeBindToTemporary(ResStmtExpr);
1396013965
return ResStmtExpr;

clang/lib/Sema/SemaExprCXX.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6946,8 +6946,9 @@ Stmt *Sema::MaybeCreateStmtWithCleanups(Stmt *SubStmt) {
69466946
// a new AsmStmtWithTemporaries.
69476947
CompoundStmt *CompStmt = CompoundStmt::Create(
69486948
Context, SubStmt, SourceLocation(), SourceLocation());
6949-
Expr *E = new (Context) StmtExpr(CompStmt, Context.VoidTy, SourceLocation(),
6950-
SourceLocation());
6949+
Expr *E = new (Context)
6950+
StmtExpr(CompStmt, Context.VoidTy, SourceLocation(), SourceLocation(),
6951+
/*FIXME TemplateDepth=*/0);
69516952
return MaybeCreateExprWithCleanups(E);
69526953
}
69536954

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)