[clang] a95cc77 - PR45083: Mark statement expressions as being dependent if they contain

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Thu Mar 5 19:03:20 PST 2020


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}}
+}


        


More information about the cfe-commits mailing list