diff options
author | Richard Smith <richard@metafoo.co.uk> | 2020-03-03 15:19:13 -0800 |
---|---|---|
committer | Hans Wennborg <hans@chromium.org> | 2020-03-04 09:20:30 +0100 |
commit | 3a843031a5ad83a00d2603f623881cb2b2bf719d (patch) | |
tree | e41bf3bd9709fcde6adac546c900fa1752755d61 | |
parent | bca373f73fc82728a8335e7d6cd164e8747139ec (diff) | |
download | llvm-llvmorg-10.0.0-rc3.zip llvm-llvmorg-10.0.0-rc3.tar.gz llvm-llvmorg-10.0.0-rc3.tar.bz2 |
PR45083: Mark statement expressions as being dependent if they appear inllvmorg-10.0.0-rc3
dependent contexts.
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 bdad0a1b79273733df9acc1be4e992fa5d70ec56)
-rw-r--r-- | clang/include/clang/AST/Expr.h | 12 | ||||
-rw-r--r-- | clang/include/clang/Sema/Sema.h | 2 | ||||
-rw-r--r-- | clang/lib/AST/ASTImporter.cpp | 5 | ||||
-rw-r--r-- | clang/lib/Parse/ParseExpr.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 16 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExprCXX.cpp | 5 | ||||
-rw-r--r-- | clang/lib/Sema/TreeTransform.h | 9 | ||||
-rw-r--r-- | clang/test/SemaTemplate/dependent-expr.cpp | 20 |
8 files changed, 51 insertions, 21 deletions
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 16956c2..bcb9605 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -3955,14 +3955,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) { } diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 697d191..2b5f7c1 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -4923,7 +4923,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); diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 1f2ce30..f423615 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -6724,8 +6724,9 @@ ExpectedStmt ASTNodeImporter::VisitStmtExpr(StmtExpr *E) { SourceLocation ToLParenLoc, ToRParenLoc; std::tie(ToSubStmt, ToType, ToLParenLoc, ToRParenLoc) = *Imp; - 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) { diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 1eb3ad6..ad9627a 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -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(); } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 2956261..63d8d75 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -13908,9 +13908,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); @@ -13939,9 +13938,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; diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 98af7fb..705abdb 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -6800,8 +6800,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); } diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index d610535..0892f96 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -2526,10 +2526,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. @@ -11801,6 +11800,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(), diff --git a/clang/test/SemaTemplate/dependent-expr.cpp b/clang/test/SemaTemplate/dependent-expr.cpp index bb1e239..e333ed9 100644 --- a/clang/test/SemaTemplate/dependent-expr.cpp +++ b/clang/test/SemaTemplate/dependent-expr.cpp @@ -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(); +} |