PR45083: Mark statement expressions as being dependent if they appear in

dependent contexts.

We previously assumed they were neither value- nor
instantiation-dependent under any circumstances, which would lead to
crashes and other misbehavior.
This commit is contained in:
Richard Smith 2020-03-03 15:19:13 -08:00
parent 8cf76e913b
commit bdad0a1b79
8 changed files with 51 additions and 21 deletions

View File

@ -3960,14 +3960,14 @@ class StmtExpr : public Expr {
Stmt *SubStmt;
SourceLocation LParenLoc, RParenLoc;
public:
// FIXME: Does type-dependence need to be computed differently?
// FIXME: Do we need to compute instantiation instantiation-dependence for
// statements? (ugh!)
StmtExpr(CompoundStmt *substmt, QualType T,
SourceLocation lp, SourceLocation rp) :
SourceLocation lp, SourceLocation rp, bool InDependentContext) :
// Note: we treat a statement-expression in a dependent context as always
// being value- and instantiation-dependent. This matches the behavior of
// lambda-expressions and GCC.
Expr(StmtExprClass, T, VK_RValue, OK_Ordinary,
T->isDependentType(), false, false, false),
SubStmt(substmt), LParenLoc(lp), RParenLoc(rp) { }
T->isDependentType(), InDependentContext, InDependentContext, false),
SubStmt(substmt), LParenLoc(lp), RParenLoc(rp) {}
/// Build an empty statement expression.
explicit StmtExpr(EmptyShell Empty) : Expr(StmtExprClass, Empty) { }

View File

@ -4964,7 +4964,7 @@ public:
LabelDecl *TheDecl);
void ActOnStartStmtExpr();
ExprResult ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
ExprResult ActOnStmtExpr(Scope *S, SourceLocation LPLoc, Stmt *SubStmt,
SourceLocation RPLoc); // "({..})"
// Handle the final expression in a statement expression.
ExprResult ActOnStmtExprResult(ExprResult E);

View File

@ -6631,8 +6631,9 @@ ExpectedStmt ASTNodeImporter::VisitStmtExpr(StmtExpr *E) {
if (Err)
return std::move(Err);
return new (Importer.getToContext()) StmtExpr(
ToSubStmt, ToType, ToLParenLoc, ToRParenLoc);
return new (Importer.getToContext())
StmtExpr(ToSubStmt, ToType, ToLParenLoc, ToRParenLoc,
E->isInstantiationDependent());
}
ExpectedStmt ASTNodeImporter::VisitUnaryOperator(UnaryOperator *E) {

View File

@ -2655,7 +2655,8 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
// If the substmt parsed correctly, build the AST node.
if (!Stmt.isInvalid()) {
Result = Actions.ActOnStmtExpr(OpenLoc, Stmt.get(), Tok.getLocation());
Result = Actions.ActOnStmtExpr(getCurScope(), OpenLoc, Stmt.get(),
Tok.getLocation());
} else {
Actions.ActOnStmtExprError();
}

View File

@ -13911,9 +13911,8 @@ void Sema::ActOnStmtExprError() {
PopExpressionEvaluationContext();
}
ExprResult
Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
SourceLocation RPLoc) { // "({..})"
ExprResult Sema::ActOnStmtExpr(Scope *S, SourceLocation LPLoc, Stmt *SubStmt,
SourceLocation RPLoc) { // "({..})"
assert(SubStmt && isa<CompoundStmt>(SubStmt) && "Invalid action invocation!");
CompoundStmt *Compound = cast<CompoundStmt>(SubStmt);
@ -13942,9 +13941,18 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
}
}
bool IsDependentContext = false;
if (S)
IsDependentContext = S->getTemplateParamParent() != nullptr;
else
// FIXME: This is not correct when substituting inside a templated
// context that isn't a DeclContext (such as a variable template).
IsDependentContext = CurContext->isDependentContext();
// FIXME: Check that expression type is complete/non-abstract; statement
// expressions are not lvalues.
Expr *ResStmtExpr = new (Context) StmtExpr(Compound, Ty, LPLoc, RPLoc);
Expr *ResStmtExpr =
new (Context) StmtExpr(Compound, Ty, LPLoc, RPLoc, IsDependentContext);
if (StmtExprMayBindToTemp)
return MaybeBindToTemporary(ResStmtExpr);
return ResStmtExpr;

View File

@ -6955,8 +6955,9 @@ Stmt *Sema::MaybeCreateStmtWithCleanups(Stmt *SubStmt) {
// a new AsmStmtWithTemporaries.
CompoundStmt *CompStmt = CompoundStmt::Create(
Context, SubStmt, SourceLocation(), SourceLocation());
Expr *E = new (Context) StmtExpr(CompStmt, Context.VoidTy, SourceLocation(),
SourceLocation());
Expr *E = new (Context)
StmtExpr(CompStmt, Context.VoidTy, SourceLocation(), SourceLocation(),
CurContext->isDependentContext());
return MaybeCreateExprWithCleanups(E);
}

View File

@ -2549,10 +2549,9 @@ public:
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
ExprResult RebuildStmtExpr(SourceLocation LParenLoc,
Stmt *SubStmt,
SourceLocation RParenLoc) {
return getSema().ActOnStmtExpr(LParenLoc, SubStmt, RParenLoc);
ExprResult RebuildStmtExpr(SourceLocation LParenLoc, Stmt *SubStmt,
SourceLocation RParenLoc) {
return getSema().ActOnStmtExpr(nullptr, LParenLoc, SubStmt, RParenLoc);
}
/// Build a new __builtin_choose_expr expression.
@ -11888,6 +11887,8 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
NewTrailingRequiresClause = getDerived().TransformExpr(TRC);
// Create the local class that will describe the lambda.
// FIXME: KnownDependent below is wrong when substituting inside a templated
// context that isn't a DeclContext (such as a variable template).
CXXRecordDecl *OldClass = E->getLambdaClass();
CXXRecordDecl *Class
= getSema().createLambdaClosureType(E->getIntroducerRange(),

View File

@ -1,5 +1,4 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// expected-no-diagnostics
// PR5908
template <typename Iterator>
@ -108,3 +107,22 @@ namespace PR18152 {
};
template struct A<0>;
}
template<typename T> void stmt_expr_1() {
static_assert( ({ false; }), "" );
}
void stmt_expr_2() {
static_assert( ({ false; }), "" ); // expected-error {{failed}}
}
namespace PR45083 {
struct A { bool x; };
template<typename> struct B : A {
void f() {
const int n = ({ if (x) {} 0; });
}
};
template void B<int>::f();
}