v.g.vassilev updated this revision to Diff 447098.
v.g.vassilev added a comment.

Keep the patch minimal, exclude opencl, etc for now.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D127284/new/

https://reviews.llvm.org/D127284

Files:
  clang/include/clang/AST/ASTConsumer.h
  clang/include/clang/Parse/Parser.h
  clang/lib/CodeGen/CodeGenAction.cpp
  clang/lib/CodeGen/ModuleBuilder.cpp
  clang/lib/Interpreter/IncrementalParser.cpp
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Parse/ParseTentative.cpp
  clang/lib/Parse/Parser.cpp
  clang/test/Interpreter/execute-stmts.cpp
  clang/unittests/Interpreter/InterpreterTest.cpp

Index: clang/unittests/Interpreter/InterpreterTest.cpp
===================================================================
--- clang/unittests/Interpreter/InterpreterTest.cpp
+++ clang/unittests/Interpreter/InterpreterTest.cpp
@@ -120,12 +120,7 @@
 
   // FIXME: Add support for wrapping and running statements.
   auto R2 = Interp->Parse("var1++; printf(\"var1 value %d\\n\", var1);");
-  EXPECT_FALSE(!!R2);
-  using ::testing::HasSubstr;
-  EXPECT_THAT(DiagnosticsOS.str(),
-              HasSubstr("error: unknown type name 'var1'"));
-  auto Err = R2.takeError();
-  EXPECT_EQ("Parsing failed.", llvm::toString(std::move(Err)));
+  EXPECT_TRUE(!!R2);
 }
 
 TEST(InterpreterTest, UndoCommand) {
Index: clang/test/Interpreter/execute-stmts.cpp
===================================================================
--- /dev/null
+++ clang/test/Interpreter/execute-stmts.cpp
@@ -0,0 +1,20 @@
+// REQUIRES: host-supports-jit
+// UNSUPPORTED: system-aix
+// RUN: cat %s | clang-repl | FileCheck %s
+
+int i = 12;
+++i;
+extern "C" int printf(const char*,...);
+printf("i = %d\n", i);
+// CHECK: i = 13
+
+namespace Ns { int f(){ return i++; } }
+Ns::f();
+
+int g() { return ++i; }
+g();
+
+printf("i = %d\n", i);
+// CHECK: i = 15
+
+%quit
Index: clang/lib/Parse/Parser.cpp
===================================================================
--- clang/lib/Parse/Parser.cpp
+++ clang/lib/Parse/Parser.cpp
@@ -582,13 +582,14 @@
 ///
 /// Note that in C, it is an error if there is no first declaration.
 bool Parser::ParseFirstTopLevelDecl(DeclGroupPtrTy &Result,
-                                    Sema::ModuleImportState &ImportState) {
+                                    Sema::ModuleImportState &ImportState,
+                                    StmtVector *Stmts) {
   Actions.ActOnStartOfTranslationUnit();
 
   // For C++20 modules, a module decl must be the first in the TU.  We also
   // need to track module imports.
   ImportState = Sema::ModuleImportState::FirstDecl;
-  bool NoTopLevelDecls = ParseTopLevelDecl(Result, ImportState);
+  bool NoTopLevelDecls = ParseTopLevelDecl(Result, ImportState, Stmts);
 
   // C11 6.9p1 says translation units must have at least one top-level
   // declaration. C++ doesn't have this restriction. We also don't want to
@@ -609,7 +610,8 @@
 ///           declaration
 /// [C++20]   module-import-declaration
 bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result,
-                               Sema::ModuleImportState &ImportState) {
+                               Sema::ModuleImportState &ImportState,
+                               StmtVector *Stmts /*=nullptr*/) {
   DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(*this);
 
   // Skip over the EOF token, flagging end of previous input for incremental
@@ -724,6 +726,23 @@
   ParsedAttributes attrs(AttrFactory);
   MaybeParseCXX11Attributes(attrs);
 
+  // FIXME: Remove the incremental processing pre-condition and verify clang
+  // still can pass its test suite, which will harden `isDeclarationStatement`.
+  // It is known to have several weaknesses, for example in
+  // isConstructorDeclarator, infinite loop in c-index-test, etc..
+  // Parse a block of top-level-stmts.
+  while (PP.isIncrementalProcessingEnabled() && Stmts &&
+         !isDeclarationStatement(/*IsParsingDecl=*/false)) {
+    // isStmtExpr ? ParsedStmtContext::InStmtExpr : ParsedStmtContext()
+    ParsedStmtContext SubStmtCtx = ParsedStmtContext();
+    auto R = ParseStatementOrDeclaration(*Stmts, SubStmtCtx);
+    if (!R.isUsable())
+      return true;
+    Stmts->push_back(R.get());
+    if (Tok.is(tok::eof))
+      return false;
+  }
+
   Result = ParseExternalDeclaration(attrs);
   // An empty Result might mean a line with ';' or some parsing error, ignore
   // it.
Index: clang/lib/Parse/ParseTentative.cpp
===================================================================
--- clang/lib/Parse/ParseTentative.cpp
+++ clang/lib/Parse/ParseTentative.cpp
@@ -46,7 +46,8 @@
 ///           'using' 'namespace' '::'[opt] nested-name-specifier[opt]
 ///                 namespace-name ';'
 ///
-bool Parser::isCXXDeclarationStatement() {
+bool Parser::isCXXDeclarationStatement(
+    bool DisambiguatingWithExpression /*=false*/) {
   switch (Tok.getKind()) {
     // asm-definition
   case tok::kw_asm:
@@ -59,7 +60,20 @@
   case tok::kw_static_assert:
   case tok::kw__Static_assert:
     return true;
+
+  case tok::identifier:
+    if (DisambiguatingWithExpression && getLangOpts().CPlusPlus) {
+      if (isConstructorDeclarator(/*Unqualified=*/false,
+                                  /*DeductionGuide=*/false,
+                                  DisambiguatingWithExpression))
+        return true;
+      // Check if this is a dtor.
+      if (!TryAnnotateTypeOrScopeToken() && Tok.is(tok::annot_cxxscope) &&
+          NextToken().is(tok::tilde))
+        return true;
+    }
     // simple-declaration
+    LLVM_FALLTHROUGH;
   default:
     return isCXXSimpleDeclaration(/*AllowForRangeDecl=*/false);
   }
Index: clang/lib/Parse/ParseDecl.cpp
===================================================================
--- clang/lib/Parse/ParseDecl.cpp
+++ clang/lib/Parse/ParseDecl.cpp
@@ -5513,7 +5513,9 @@
   }
 }
 
-bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide) {
+bool Parser::isConstructorDeclarator(
+    bool IsUnqualified, bool DeductionGuide,
+    bool DisambiguatingWithExpression /*=false*/) {
   TentativeParsingAction TPA(*this);
 
   // Parse the C++ scope specifier.
@@ -5550,11 +5552,12 @@
 
   // A right parenthesis, or ellipsis followed by a right parenthesis signals
   // that we have a constructor.
-  if (Tok.is(tok::r_paren) ||
-      (Tok.is(tok::ellipsis) && NextToken().is(tok::r_paren))) {
-    TPA.Revert();
-    return true;
-  }
+  if (!DisambiguatingWithExpression)
+    if (Tok.is(tok::r_paren) ||
+        (Tok.is(tok::ellipsis) && NextToken().is(tok::r_paren))) {
+      TPA.Revert();
+      return true;
+    }
 
   // A C++11 attribute here signals that we have a constructor, and is an
   // attribute on the first constructor parameter.
Index: clang/lib/Interpreter/IncrementalParser.cpp
===================================================================
--- clang/lib/Interpreter/IncrementalParser.cpp
+++ clang/lib/Interpreter/IncrementalParser.cpp
@@ -168,11 +168,17 @@
 
   Parser::DeclGroupPtrTy ADecl;
   Sema::ModuleImportState ImportState;
-  for (bool AtEOF = P->ParseFirstTopLevelDecl(ADecl, ImportState); !AtEOF;
-       AtEOF = P->ParseTopLevelDecl(ADecl, ImportState)) {
+  Parser::StmtVector Stmts;
+  for (bool AtEOF = P->ParseFirstTopLevelDecl(ADecl, ImportState, &Stmts);
+       !AtEOF; AtEOF = P->ParseTopLevelDecl(ADecl, ImportState, &Stmts)) {
     // If we got a null return and something *was* parsed, ignore it.  This
     // is due to a top-level semicolon, an action override, or a parse error
     // skipping something.
+    if (!Stmts.empty() && !Consumer->HandleTopLevelStmts(Stmts))
+      return llvm::make_error<llvm::StringError>("Parsing failed. "
+                                                 "The consumer rejected a stmt",
+                                                 std::error_code());
+
     if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get()))
       return llvm::make_error<llvm::StringError>("Parsing failed. "
                                                  "The consumer rejected a decl",
Index: clang/lib/CodeGen/ModuleBuilder.cpp
===================================================================
--- clang/lib/CodeGen/ModuleBuilder.cpp
+++ clang/lib/CodeGen/ModuleBuilder.cpp
@@ -175,7 +175,30 @@
       Builder->HandleCXXStaticMemberVarInstantiation(VD);
     }
 
+    bool
+    HandleTopLevelStmts(const llvm::SmallVectorImpl<Stmt *> &Stmts) override {
+      if (Diags.hasErrorOccurred())
+        return false; // Abort parsing.
+
+      // FIXME: We should reimplement this in a proper way where we append the
+      // statements to the global init function.
+      static unsigned id = 0;
+      // Make sure to emit all elements of a Decl.
+      for (Stmt *S : Stmts) {
+        Expr *E = cast<Expr>(S);
+        IdentifierInfo *name = &Ctx->Idents.get("_stmt" + std::to_string(id++));
+        VarDecl *VD = VarDecl::Create(*Ctx, Ctx->getTranslationUnitDecl(),
+                                      E->getBeginLoc(), SourceLocation(), name,
+                                      E->getType(), /*TSI*/ nullptr, SC_None);
+        VD->setInit(E);
+        HandleTopLevelDecl(DeclGroupRef(VD));
+      }
+
+      return true;
+    }
+
     bool HandleTopLevelDecl(DeclGroupRef DG) override {
+      // FIXME: Why not return false and abort parsing?
       if (Diags.hasErrorOccurred())
         return true;
 
Index: clang/lib/CodeGen/CodeGenAction.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenAction.cpp
+++ clang/lib/CodeGen/CodeGenAction.cpp
@@ -237,6 +237,10 @@
 
       return true;
     }
+    bool
+    HandleTopLevelStmts(const llvm::SmallVectorImpl<Stmt *> &Stmts) override {
+      return Gen->HandleTopLevelStmts(Stmts);
+    }
 
     void HandleInlineFunctionDefinition(FunctionDecl *D) override {
       PrettyStackTraceDecl CrashInfo(D, SourceLocation(),
Index: clang/include/clang/Parse/Parser.h
===================================================================
--- clang/include/clang/Parse/Parser.h
+++ clang/include/clang/Parse/Parser.h
@@ -462,6 +462,10 @@
 
   typedef Sema::FullExprArg FullExprArg;
 
+  /// A SmallVector of statements, with stack size 32 (as that is the only one
+  /// used.)
+  typedef SmallVector<Stmt *, 32> StmtVector;
+
   // Parsing methods.
 
   /// Initialize - Warm up the parser.
@@ -470,12 +474,14 @@
 
   /// Parse the first top-level declaration in a translation unit.
   bool ParseFirstTopLevelDecl(DeclGroupPtrTy &Result,
-                              Sema::ModuleImportState &ImportState);
+                              Sema::ModuleImportState &ImportState,
+                              StmtVector *Stmts = nullptr);
 
   /// ParseTopLevelDecl - Parse one top-level declaration. Returns true if
   /// the EOF was encountered.
   bool ParseTopLevelDecl(DeclGroupPtrTy &Result,
-                         Sema::ModuleImportState &ImportState);
+                         Sema::ModuleImportState &ImportState,
+                         StmtVector *Stmts = nullptr);
   bool ParseTopLevelDecl() {
     DeclGroupPtrTy Result;
     Sema::ModuleImportState IS = Sema::ModuleImportState::NotACXX20Module;
@@ -2061,9 +2067,6 @@
   //===--------------------------------------------------------------------===//
   // C99 6.8: Statements and Blocks.
 
-  /// A SmallVector of statements, with stack size 32 (as that is the only one
-  /// used.)
-  typedef SmallVector<Stmt*, 32> StmtVector;
   /// A SmallVector of expressions, with stack size 12 (the maximum used.)
   typedef SmallVector<Expr*, 12> ExprVector;
   /// A SmallVector of types.
@@ -2410,10 +2413,13 @@
 
   /// isDeclarationStatement - Disambiguates between a declaration or an
   /// expression statement, when parsing function bodies.
+  ///
+  /// \param DisambiguatingWithExpression - True to indicate that the purpose of
+  /// this check is to disambiguate between an expression and a declaration.
   /// Returns true for declaration, false for expression.
-  bool isDeclarationStatement() {
+  bool isDeclarationStatement(bool DisambiguatingWithExpression = false) {
     if (getLangOpts().CPlusPlus)
-      return isCXXDeclarationStatement();
+      return isCXXDeclarationStatement(DisambiguatingWithExpression);
     return isDeclarationSpecifier(true);
   }
 
@@ -2440,7 +2446,8 @@
   /// Starting with a scope specifier, identifier, or
   /// template-id that refers to the current class, determine whether
   /// this is a constructor declarator.
-  bool isConstructorDeclarator(bool Unqualified, bool DeductionGuide = false);
+  bool isConstructorDeclarator(bool Unqualified, bool DeductionGuide = false,
+                               bool DisambiguatingWithExpression = false);
 
   /// Specifies the context in which type-id/expression
   /// disambiguation will occur.
@@ -2478,7 +2485,7 @@
   /// isCXXDeclarationStatement - C++-specialized function that disambiguates
   /// between a declaration or an expression statement, when parsing function
   /// bodies. Returns true for declaration, false for expression.
-  bool isCXXDeclarationStatement();
+  bool isCXXDeclarationStatement(bool DisambiguatingWithExpression = false);
 
   /// isCXXSimpleDeclaration - C++-specialized function that disambiguates
   /// between a simple-declaration or an expression-statement.
Index: clang/include/clang/AST/ASTConsumer.h
===================================================================
--- clang/include/clang/AST/ASTConsumer.h
+++ clang/include/clang/AST/ASTConsumer.h
@@ -13,6 +13,10 @@
 #ifndef LLVM_CLANG_AST_ASTCONSUMER_H
 #define LLVM_CLANG_AST_ASTCONSUMER_H
 
+namespace llvm {
+template <typename T> class SmallVectorImpl;
+}
+
 namespace clang {
   class ASTContext;
   class CXXMethodDecl;
@@ -22,6 +26,7 @@
   class ASTMutationListener;
   class ASTDeserializationListener; // layering violation because void* is ugly
   class SemaConsumer; // layering violation required for safe SemaConsumer
+  class Stmt;
   class TagDecl;
   class VarDecl;
   class FunctionDecl;
@@ -46,6 +51,15 @@
   /// ASTContext.
   virtual void Initialize(ASTContext &Context) {}
 
+  /// HandleTopLevelStmts - Handle the specified top-level statements. This is
+  /// called by the parser to process every top-level Stmt* in incremental
+  /// compilation mode.
+  ///
+  /// \returns true to continue parsing, or false to abort parsing.
+  virtual bool HandleTopLevelStmts(const llvm::SmallVectorImpl<Stmt *> &Stmts) {
+    return true;
+  }
+
   /// HandleTopLevelDecl - Handle the specified top-level declaration.  This is
   /// called by the parser to process every top-level Decl*.
   ///
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to