Author: Richard Smith Date: 2020-03-05T19:03:05-08:00 New Revision: a95cc77be154433c37a3110ac9af394b7447fcba
URL: https://github.com/llvm/llvm-project/commit/a95cc77be154433c37a3110ac9af394b7447fcba DIFF: https://github.com/llvm/llvm-project/commit/a95cc77be154433c37a3110ac9af394b7447fcba.diff LOG: PR45083: Mark statement expressions as being dependent if they contain dependent constructs. We previously assumed they were neither value- nor instantiation-dependent under any circumstances, which would lead to crashes and other misbehavior. This doesn't match GCC's behavior (where statement expressions appear to be treated as value-dependent if they appear in a dependent context), but seems to be the best thing we can do in the short term: it turns out to be remarkably difficult for us to correctly determine whether we are in a dependent context (and it's not even possible in some cases, such as in a generic lambda where we might not have seen the 'auto' yet). Added: Modified: clang/include/clang/AST/Expr.h clang/lib/AST/Expr.cpp clang/test/SemaTemplate/dependent-expr.cpp Removed: ################################################################################ diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 7271dbb830a2..75b7a5f6ecd3 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -3959,14 +3959,8 @@ class StmtExpr : public Expr { Stmt *SubStmt; SourceLocation LParenLoc, RParenLoc; public: - // FIXME: Does type-dependence need to be computed diff erently? - // FIXME: Do we need to compute instantiation instantiation-dependence for - // statements? (ugh!) - StmtExpr(CompoundStmt *substmt, QualType T, - SourceLocation lp, SourceLocation rp) : - Expr(StmtExprClass, T, VK_RValue, OK_Ordinary, - T->isDependentType(), false, false, false), - SubStmt(substmt), LParenLoc(lp), RParenLoc(rp) { } + StmtExpr(CompoundStmt *SubStmt, QualType T, + SourceLocation LParen, SourceLocation RParen); /// Build an empty statement expression. explicit StmtExpr(EmptyShell Empty) : Expr(StmtExprClass, Empty) { } diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 79f9f42224d0..78fd96fd76e6 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -4097,6 +4097,53 @@ void ExtVectorElementExpr::getEncodedElementAccess( } } +StmtExpr::StmtExpr(CompoundStmt *SubStmt, QualType T, SourceLocation LParen, + SourceLocation RParen) + : Expr(StmtExprClass, T, VK_RValue, OK_Ordinary, T->isDependentType(), + false, false, false), + SubStmt(SubStmt), LParenLoc(LParen), RParenLoc(RParen) { + llvm::SmallVector<Stmt*, 16> Queue(1, SubStmt); + while (!Queue.empty()) { + Stmt *S = Queue.pop_back_val(); + if (!S) + continue; + + // If any subexpression is dependent, the statement expression is dependent + // in the same way. + if (Expr *E = dyn_cast<Expr>(S)) { + addDependence(E->getDependence()); + continue; + } + + // FIXME: Need to properly compute whether DeclStmts contain unexpanded + // parameter packs. + if (DeclStmt *DS = dyn_cast<DeclStmt>(S)) { + for (Decl *D : DS->decls()) { + // If any contained declaration is in a dependent context, then it + // needs to be instantiated, so the statement expression itself is + // instantiation-dependent. + // + // Note that we don't need to worry about the case where the context is + // non-dependent but contains dependent entities here (eg, inside a + // variable template or alias template): that can only happen at file + // scope, where statement expressions are prohibited. + if (D->getLexicalDeclContext()->isDependentContext()) + addDependence(ExprDependence::Instantiation); + + // If any contained variable declaration has a dependent type, we can't + // evaluate that declaration. + if (auto *VD = dyn_cast<VarDecl>(D)) + if (VD->getType()->isDependentType()) + addDependence(ExprDependence::Value); + } + } + + // Recurse to substatements. + // FIXME: Should we skip the unchosen side of 'if constexpr' if known? + Queue.insert(Queue.end(), S->child_begin(), S->child_end()); + } +} + ShuffleVectorExpr::ShuffleVectorExpr(const ASTContext &C, ArrayRef<Expr*> args, QualType Type, SourceLocation BLoc, SourceLocation RP) diff --git a/clang/test/SemaTemplate/dependent-expr.cpp b/clang/test/SemaTemplate/dependent-expr.cpp index bb1e239c3490..12a99acc21cd 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 +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++2a %s // PR5908 template <typename Iterator> @@ -108,3 +107,42 @@ namespace PR18152 { }; template struct A<0>; } + +template<typename T> void stmt_expr_1() { + // GCC doesn't check this: it appears to treat statement-expressions as being + // value-dependent if they appear in a dependent context, regardless of their + // contents. + static_assert( ({ false; }), "" ); // expected-error {{failed}} +} +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(); + + template<typename> void f() { + decltype(({})) x; // expected-error {{incomplete type}} + } + template void f<int>(); + + template<typename> auto g() { + auto c = [](auto, int) -> decltype(({})) {}; + using T = decltype(c(0.0, 0)); + using T = void; + return c(0, 0); + } + using U = decltype(g<int>()); // expected-note {{previous}} + using U = float; // expected-error {{ diff erent types ('float' vs 'decltype(g<int>())' (aka 'void'))}} + + void h(auto a, decltype(g<char>())*) {} // expected-note {{previous}} + void h(auto a, void*) {} // expected-error {{redefinition}} +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits