This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG6775fc6ffa3c: [clang-repl] Implement partial translation 
units and error recovery. (authored by v.g.vassilev).
Herald added a project: clang.

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D104918

Files:
  clang/include/clang/AST/ASTContext.h
  clang/include/clang/AST/Decl.h
  clang/include/clang/AST/Redeclarable.h
  clang/include/clang/Basic/LangOptions.h
  clang/include/clang/Interpreter/Interpreter.h
  clang/include/clang/Interpreter/PartialTranslationUnit.h
  clang/include/clang/Interpreter/Transaction.h
  clang/include/clang/Lex/Preprocessor.h
  clang/include/clang/Sema/Sema.h
  clang/lib/AST/ASTContext.cpp
  clang/lib/AST/Decl.cpp
  clang/lib/AST/DeclBase.cpp
  clang/lib/Frontend/ASTUnit.cpp
  clang/lib/Frontend/CompilerInstance.cpp
  clang/lib/Interpreter/IncrementalParser.cpp
  clang/lib/Interpreter/IncrementalParser.h
  clang/lib/Interpreter/Interpreter.cpp
  clang/lib/Sema/Sema.cpp
  clang/lib/Serialization/ASTReader.cpp
  clang/tools/clang-import-test/clang-import-test.cpp
  clang/unittests/AST/ASTVectorTest.cpp
  clang/unittests/Interpreter/IncrementalProcessingTest.cpp
  clang/unittests/Interpreter/InterpreterTest.cpp
  clang/unittests/Lex/PPCallbacksTest.cpp

Index: clang/unittests/Lex/PPCallbacksTest.cpp
===================================================================
--- clang/unittests/Lex/PPCallbacksTest.cpp
+++ clang/unittests/Lex/PPCallbacksTest.cpp
@@ -323,7 +323,7 @@
     // according to LangOptions, so we init Parser to register opencl
     // pragma handlers
     ASTContext Context(OpenCLLangOpts, SourceMgr, PP.getIdentifierTable(),
-                       PP.getSelectorTable(), PP.getBuiltinInfo());
+                       PP.getSelectorTable(), PP.getBuiltinInfo(), PP.TUKind);
     Context.InitBuiltinTypes(*Target);
 
     ASTConsumer Consumer;
Index: clang/unittests/Interpreter/InterpreterTest.cpp
===================================================================
--- clang/unittests/Interpreter/InterpreterTest.cpp
+++ clang/unittests/Interpreter/InterpreterTest.cpp
@@ -37,34 +37,41 @@
   return cantFail(clang::Interpreter::create(std::move(CI)));
 }
 
+static size_t DeclsSize(TranslationUnitDecl *PTUDecl) {
+  return std::distance(PTUDecl->decls().begin(), PTUDecl->decls().end());
+}
+
 TEST(InterpreterTest, Sanity) {
   std::unique_ptr<Interpreter> Interp = createInterpreter();
-  Transaction &R1(cantFail(Interp->Parse("void g(); void g() {}")));
-  EXPECT_EQ(2U, R1.Decls.size());
 
-  Transaction &R2(cantFail(Interp->Parse("int i;")));
-  EXPECT_EQ(1U, R2.Decls.size());
+  using PTU = PartialTranslationUnit;
+
+  PTU &R1(cantFail(Interp->Parse("void g(); void g() {}")));
+  EXPECT_EQ(2U, DeclsSize(R1.TUPart));
+
+  PTU &R2(cantFail(Interp->Parse("int i;")));
+  EXPECT_EQ(1U, DeclsSize(R2.TUPart));
 }
 
-static std::string DeclToString(DeclGroupRef DGR) {
-  return llvm::cast<NamedDecl>(DGR.getSingleDecl())->getQualifiedNameAsString();
+static std::string DeclToString(Decl *D) {
+  return llvm::cast<NamedDecl>(D)->getQualifiedNameAsString();
 }
 
 TEST(InterpreterTest, IncrementalInputTopLevelDecls) {
   std::unique_ptr<Interpreter> Interp = createInterpreter();
-  auto R1OrErr = Interp->Parse("int var1 = 42; int f() { return var1; }");
+  auto R1 = Interp->Parse("int var1 = 42; int f() { return var1; }");
   // gtest doesn't expand into explicit bool conversions.
-  EXPECT_TRUE(!!R1OrErr);
-  auto R1 = R1OrErr->Decls;
-  EXPECT_EQ(2U, R1.size());
-  EXPECT_EQ("var1", DeclToString(R1[0]));
-  EXPECT_EQ("f", DeclToString(R1[1]));
-
-  auto R2OrErr = Interp->Parse("int var2 = f();");
-  EXPECT_TRUE(!!R2OrErr);
-  auto R2 = R2OrErr->Decls;
-  EXPECT_EQ(1U, R2.size());
-  EXPECT_EQ("var2", DeclToString(R2[0]));
+  EXPECT_TRUE(!!R1);
+  auto R1DeclRange = R1->TUPart->decls();
+  EXPECT_EQ(2U, DeclsSize(R1->TUPart));
+  EXPECT_EQ("var1", DeclToString(*R1DeclRange.begin()));
+  EXPECT_EQ("f", DeclToString(*(++R1DeclRange.begin())));
+
+  auto R2 = Interp->Parse("int var2 = f();");
+  EXPECT_TRUE(!!R2);
+  auto R2DeclRange = R2->TUPart->decls();
+  EXPECT_EQ(1U, DeclsSize(R2->TUPart));
+  EXPECT_EQ("var2", DeclToString(*R2DeclRange.begin()));
 }
 
 TEST(InterpreterTest, Errors) {
@@ -83,9 +90,8 @@
               HasSubstr("error: unknown type name 'intentional_error'"));
   EXPECT_EQ("Parsing failed.", llvm::toString(std::move(Err)));
 
-#ifdef GTEST_HAS_DEATH_TEST
-  EXPECT_DEATH((void)Interp->Parse("int var1 = 42;"), "");
-#endif
+  auto RecoverErr = Interp->Parse("int var1 = 42;");
+  EXPECT_TRUE(!!RecoverErr);
 }
 
 // Here we test whether the user can mix declarations and statements. The
@@ -101,21 +107,21 @@
       DiagnosticsOS, new DiagnosticOptions());
 
   auto Interp = createInterpreter(ExtraArgs, DiagPrinter.get());
-  auto R1OrErr = Interp->Parse(
+  auto R1 = Interp->Parse(
       "int var1 = 42; extern \"C\" int printf(const char*, ...);");
   // gtest doesn't expand into explicit bool conversions.
-  EXPECT_TRUE(!!R1OrErr);
+  EXPECT_TRUE(!!R1);
 
-  auto R1 = R1OrErr->Decls;
-  EXPECT_EQ(2U, R1.size());
+  auto *PTU1 = R1->TUPart;
+  EXPECT_EQ(2U, DeclsSize(PTU1));
 
   // FIXME: Add support for wrapping and running statements.
-  auto R2OrErr = Interp->Parse("var1++; printf(\"var1 value %d\\n\", var1);");
-  EXPECT_FALSE(!!R2OrErr);
+  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 = R2OrErr.takeError();
+  auto Err = R2.takeError();
   EXPECT_EQ("Parsing failed.", llvm::toString(std::move(Err)));
 }
 
Index: clang/unittests/Interpreter/IncrementalProcessingTest.cpp
===================================================================
--- clang/unittests/Interpreter/IncrementalProcessingTest.cpp
+++ clang/unittests/Interpreter/IncrementalProcessingTest.cpp
@@ -55,23 +55,23 @@
   auto CI = llvm::cantFail(IncrementalCompilerBuilder::create(ClangArgv));
   auto Interp = llvm::cantFail(Interpreter::create(std::move(CI)));
 
-  std::array<clang::Transaction *, 2> Transactions;
+  std::array<clang::PartialTranslationUnit *, 2> PTUs;
 
-  Transactions[0] = &llvm::cantFail(Interp->Parse(TestProgram1));
-  ASSERT_TRUE(Transactions[0]->TheModule);
-  ASSERT_TRUE(Transactions[0]->TheModule->getFunction("funcForProg1"));
+  PTUs[0] = &llvm::cantFail(Interp->Parse(TestProgram1));
+  ASSERT_TRUE(PTUs[0]->TheModule);
+  ASSERT_TRUE(PTUs[0]->TheModule->getFunction("funcForProg1"));
 
-  Transactions[1] = &llvm::cantFail(Interp->Parse(TestProgram2));
-  ASSERT_TRUE(Transactions[1]->TheModule);
-  ASSERT_TRUE(Transactions[1]->TheModule->getFunction("funcForProg2"));
+  PTUs[1] = &llvm::cantFail(Interp->Parse(TestProgram2));
+  ASSERT_TRUE(PTUs[1]->TheModule);
+  ASSERT_TRUE(PTUs[1]->TheModule->getFunction("funcForProg2"));
   // First code should not end up in second module:
-  ASSERT_FALSE(Transactions[1]->TheModule->getFunction("funcForProg1"));
+  ASSERT_FALSE(PTUs[1]->TheModule->getFunction("funcForProg1"));
 
   // Make sure global inits exist and are unique:
-  const Function *GlobalInit1 = getGlobalInit(Transactions[0]->TheModule.get());
+  const Function *GlobalInit1 = getGlobalInit(PTUs[0]->TheModule.get());
   ASSERT_TRUE(GlobalInit1);
 
-  const Function *GlobalInit2 = getGlobalInit(Transactions[1]->TheModule.get());
+  const Function *GlobalInit2 = getGlobalInit(PTUs[1]->TheModule.get());
   ASSERT_TRUE(GlobalInit2);
 
   ASSERT_FALSE(GlobalInit1->getName() == GlobalInit2->getName());
Index: clang/unittests/AST/ASTVectorTest.cpp
===================================================================
--- clang/unittests/AST/ASTVectorTest.cpp
+++ clang/unittests/AST/ASTVectorTest.cpp
@@ -29,7 +29,7 @@
       : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
         Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
         SourceMgr(Diags, FileMgr), Idents(LangOpts, nullptr),
-        Ctxt(LangOpts, SourceMgr, Idents, Sels, Builtins) {}
+        Ctxt(LangOpts, SourceMgr, Idents, Sels, Builtins, TU_Complete) {}
 
   FileSystemOptions FileMgrOpts;
   FileManager FileMgr;
Index: clang/tools/clang-import-test/clang-import-test.cpp
===================================================================
--- clang/tools/clang-import-test/clang-import-test.cpp
+++ clang/tools/clang-import-test/clang-import-test.cpp
@@ -218,9 +218,10 @@
 
 std::unique_ptr<ASTContext>
 BuildASTContext(CompilerInstance &CI, SelectorTable &ST, Builtin::Context &BC) {
+  auto &PP = CI.getPreprocessor();
   auto AST = std::make_unique<ASTContext>(
       CI.getLangOpts(), CI.getSourceManager(),
-      CI.getPreprocessor().getIdentifierTable(), ST, BC);
+      PP.getIdentifierTable(), ST, BC, PP.TUKind);
   AST->InitBuiltinTypes(CI.getTarget());
   return AST;
 }
Index: clang/lib/Serialization/ASTReader.cpp
===================================================================
--- clang/lib/Serialization/ASTReader.cpp
+++ clang/lib/Serialization/ASTReader.cpp
@@ -7176,6 +7176,11 @@
     return;
   }
 
+  if (!D->getDeclContext()) {
+    assert(isa<TranslationUnitDecl>(D) && "Not a TU?");
+    return;
+  }
+
   const DeclContext *DC = D->getDeclContext()->getRedeclContext();
 
   // If this is a named declaration, complete it by looking it up
Index: clang/lib/Sema/Sema.cpp
===================================================================
--- clang/lib/Sema/Sema.cpp
+++ clang/lib/Sema/Sema.cpp
@@ -183,6 +183,7 @@
       DisableTypoCorrection(false), TyposCorrected(0), AnalysisWarnings(*this),
       ThreadSafetyDeclCache(nullptr), VarDataSharingAttributesStack(nullptr),
       CurScope(nullptr), Ident_super(nullptr), Ident___float128(nullptr) {
+  assert(pp.TUKind == TUKind);
   TUScope = nullptr;
   isConstantEvaluatedOverride = false;
 
Index: clang/lib/Interpreter/Interpreter.cpp
===================================================================
--- clang/lib/Interpreter/Interpreter.cpp
+++ clang/lib/Interpreter/Interpreter.cpp
@@ -198,11 +198,12 @@
   return IncrParser->getCI();
 }
 
-llvm::Expected<Transaction &> Interpreter::Parse(llvm::StringRef Code) {
+llvm::Expected<PartialTranslationUnit &>
+Interpreter::Parse(llvm::StringRef Code) {
   return IncrParser->Parse(Code);
 }
 
-llvm::Error Interpreter::Execute(Transaction &T) {
+llvm::Error Interpreter::Execute(PartialTranslationUnit &T) {
   assert(T.TheModule);
   if (!IncrExecutor) {
     const llvm::Triple &Triple =
Index: clang/lib/Interpreter/IncrementalParser.h
===================================================================
--- clang/lib/Interpreter/IncrementalParser.h
+++ clang/lib/Interpreter/IncrementalParser.h
@@ -13,7 +13,7 @@
 #ifndef LLVM_CLANG_LIB_INTERPRETER_INCREMENTALPARSER_H
 #define LLVM_CLANG_LIB_INTERPRETER_INCREMENTALPARSER_H
 
-#include "clang/Interpreter/Transaction.h"
+#include "clang/Interpreter/PartialTranslationUnit.h"
 
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/StringRef.h"
@@ -55,7 +55,7 @@
 
   /// List containing every information about every incrementally parsed piece
   /// of code.
-  std::list<Transaction> Transactions;
+  std::list<PartialTranslationUnit> PTUs;
 
 public:
   IncrementalParser(std::unique_ptr<CompilerInstance> Instance,
@@ -65,12 +65,12 @@
   const CompilerInstance *getCI() const { return CI.get(); }
 
   /// Parses incremental input by creating an in-memory file.
-  ///\returns a \c Transaction which holds information about the \c Decls and
-  /// \c llvm::Module corresponding to the input.
-  llvm::Expected<Transaction &> Parse(llvm::StringRef Input);
+  ///\returns a \c PartialTranslationUnit which holds information about the
+  /// \c TranslationUnitDecl and \c llvm::Module corresponding to the input.
+  llvm::Expected<PartialTranslationUnit &> Parse(llvm::StringRef Input);
 
 private:
-  llvm::Expected<Transaction &> ParseOrWrapTopLevelDecl();
+  llvm::Expected<PartialTranslationUnit &> ParseOrWrapTopLevelDecl();
 };
 } // end namespace clang
 
Index: clang/lib/Interpreter/IncrementalParser.cpp
===================================================================
--- clang/lib/Interpreter/IncrementalParser.cpp
+++ clang/lib/Interpreter/IncrementalParser.cpp
@@ -12,6 +12,7 @@
 
 #include "IncrementalParser.h"
 
+#include "clang/AST/DeclContextInternals.h"
 #include "clang/CodeGen/BackendUtil.h"
 #include "clang/CodeGen/CodeGenAction.h"
 #include "clang/CodeGen/ModuleBuilder.h"
@@ -75,6 +76,9 @@
           return Act;
         }()) {}
   FrontendAction *getWrapped() const { return WrappedAction.get(); }
+  TranslationUnitKind getTranslationUnitKind() override {
+    return TU_Incremental;
+  }
   void ExecuteAction() override {
     CompilerInstance &CI = getCompilerInstance();
     assert(CI.hasPreprocessor() && "No PP!");
@@ -130,26 +134,32 @@
 
 IncrementalParser::~IncrementalParser() { Act->FinalizeAction(); }
 
-llvm::Expected<Transaction &> IncrementalParser::ParseOrWrapTopLevelDecl() {
-  DiagnosticsEngine &Diags = getCI()->getDiagnostics();
-
-  if (Diags.hasErrorOccurred())
-    llvm::report_fatal_error("Previous input had errors, "
-                             "recovery not yet supported",
-                             /*GenCrashDiag=*/false);
-
+llvm::Expected<PartialTranslationUnit &>
+IncrementalParser::ParseOrWrapTopLevelDecl() {
   // Recover resources if we crash before exiting this method.
   Sema &S = CI->getSema();
   llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(&S);
   Sema::GlobalEagerInstantiationScope GlobalInstantiations(S, /*Enabled=*/true);
   Sema::LocalEagerInstantiationScope LocalInstantiations(S);
 
+  PTUs.emplace_back(PartialTranslationUnit());
+  PartialTranslationUnit &LastPTU = PTUs.back();
+  // Add a new PTU.
+  ASTContext &C = S.getASTContext();
+  C.addTranslationUnitDecl();
+  LastPTU.TUPart = C.getTranslationUnitDecl();
+
   // Skip previous eof due to last incremental input.
-  if (P->getCurToken().is(tok::eof))
+  if (P->getCurToken().is(tok::eof)) {
     P->ConsumeToken();
-
-  Transactions.emplace_back(Transaction());
-  Transaction &LastTransaction = Transactions.back();
+    // FIXME: Clang does not call ExitScope on finalizing the regular TU, we
+    // might want to do that around HandleEndOfTranslationUnit.
+    P->ExitScope();
+    S.CurContext = nullptr;
+    // Start a new PTU.
+    P->EnterScope(Scope::DeclScope);
+    S.ActOnTranslationUnitScope(P->getCurScope());
+  }
 
   Parser::DeclGroupPtrTy ADecl;
   for (bool AtEOF = P->ParseFirstTopLevelDecl(ADecl); !AtEOF;
@@ -161,26 +171,50 @@
       return llvm::make_error<llvm::StringError>("Parsing failed. "
                                                  "The consumer rejected a decl",
                                                  std::error_code());
-    LastTransaction.Decls.push_back(ADecl.get());
+  }
+
+  DiagnosticsEngine &Diags = getCI()->getDiagnostics();
+  if (Diags.hasErrorOccurred()) {
+    TranslationUnitDecl *MostRecentTU = C.getTranslationUnitDecl();
+    TranslationUnitDecl *PreviousTU = MostRecentTU->getPreviousDecl();
+    assert(PreviousTU && "Must have a TU from the ASTContext initialization!");
+    TranslationUnitDecl *FirstTU = MostRecentTU->getFirstDecl();
+    assert(FirstTU);
+    FirstTU->RedeclLink.setLatest(PreviousTU);
+    C.TUDecl = PreviousTU;
+    S.TUScope->setEntity(PreviousTU);
+
+    // Clean up the lookup table
+    if (StoredDeclsMap *Map = PreviousTU->getLookupPtr()) {
+      for (auto I = Map->begin(); I != Map->end(); ++I) {
+        StoredDeclsList &List = I->second;
+        DeclContextLookupResult R = List.getLookupResult();
+        for (NamedDecl *D : R)
+          if (D->getTranslationUnitDecl() == MostRecentTU)
+            List.remove(D);
+        if (List.isNull())
+          Map->erase(I);
+      }
+    }
+
+    // FIXME: Do not reset the pragma handlers.
+    Diags.Reset();
+    return llvm::make_error<llvm::StringError>("Parsing failed.",
+                                               std::error_code());
   }
 
   // Process any TopLevelDecls generated by #pragma weak.
   for (Decl *D : S.WeakTopLevelDecls()) {
     DeclGroupRef DGR(D);
-    LastTransaction.Decls.push_back(DGR);
     Consumer->HandleTopLevelDecl(DGR);
   }
 
   LocalInstantiations.perform();
   GlobalInstantiations.perform();
 
-  Consumer->HandleTranslationUnit(S.getASTContext());
-
-  if (Diags.hasErrorOccurred())
-    return llvm::make_error<llvm::StringError>("Parsing failed.",
-                                               std::error_code());
+  Consumer->HandleTranslationUnit(C);
 
-  return LastTransaction;
+  return LastPTU;
 }
 
 static CodeGenerator *getCodeGen(FrontendAction *Act) {
@@ -191,7 +225,8 @@
   return static_cast<CodeGenAction *>(WrappedAct)->getCodeGenerator();
 }
 
-llvm::Expected<Transaction &> IncrementalParser::Parse(llvm::StringRef input) {
+llvm::Expected<PartialTranslationUnit &>
+IncrementalParser::Parse(llvm::StringRef input) {
   Preprocessor &PP = CI->getPreprocessor();
   assert(PP.isIncrementalProcessingEnabled() && "Not in incremental mode!?");
 
@@ -224,9 +259,9 @@
                                                "Cannot enter source file.",
                                                std::error_code());
 
-  auto ErrOrTransaction = ParseOrWrapTopLevelDecl();
-  if (auto Err = ErrOrTransaction.takeError())
-    return std::move(Err);
+  auto PTU = ParseOrWrapTopLevelDecl();
+  if (!PTU)
+    return PTU.takeError();
 
   if (PP.getLangOpts().DelayedTemplateParsing) {
     // Microsoft-specific:
@@ -246,12 +281,12 @@
 
   if (CodeGenerator *CG = getCodeGen(Act.get())) {
     std::unique_ptr<llvm::Module> M(CG->ReleaseModule());
-    CG->StartModule("incr_module_" + std::to_string(Transactions.size()),
+    CG->StartModule("incr_module_" + std::to_string(PTUs.size()),
                     M->getContext());
 
-    ErrOrTransaction->TheModule = std::move(M);
+    PTU->TheModule = std::move(M);
   }
 
-  return ErrOrTransaction;
+  return PTU;
 }
 } // end namespace clang
Index: clang/lib/Frontend/CompilerInstance.cpp
===================================================================
--- clang/lib/Frontend/CompilerInstance.cpp
+++ clang/lib/Frontend/CompilerInstance.cpp
@@ -551,7 +551,7 @@
   Preprocessor &PP = getPreprocessor();
   auto *Context = new ASTContext(getLangOpts(), PP.getSourceManager(),
                                  PP.getIdentifierTable(), PP.getSelectorTable(),
-                                 PP.getBuiltinInfo());
+                                 PP.getBuiltinInfo(), PP.TUKind);
   Context->InitBuiltinTypes(getTarget(), getAuxTarget());
   setASTContext(Context);
 }
Index: clang/lib/Frontend/ASTUnit.cpp
===================================================================
--- clang/lib/Frontend/ASTUnit.cpp
+++ clang/lib/Frontend/ASTUnit.cpp
@@ -807,7 +807,8 @@
   if (ToLoad >= LoadASTOnly)
     AST->Ctx = new ASTContext(*AST->LangOpts, AST->getSourceManager(),
                               PP.getIdentifierTable(), PP.getSelectorTable(),
-                              PP.getBuiltinInfo());
+                              PP.getBuiltinInfo(),
+                              AST->getTranslationUnitKind());
 
   DisableValidationForModuleKind disableValid =
       DisableValidationForModuleKind::None;
Index: clang/lib/AST/DeclBase.cpp
===================================================================
--- clang/lib/AST/DeclBase.cpp
+++ clang/lib/AST/DeclBase.cpp
@@ -1219,7 +1219,6 @@
 
 DeclContext *DeclContext::getPrimaryContext() {
   switch (getDeclKind()) {
-  case Decl::TranslationUnit:
   case Decl::ExternCContext:
   case Decl::LinkageSpec:
   case Decl::Export:
@@ -1231,6 +1230,8 @@
     // There is only one DeclContext for these entities.
     return this;
 
+  case Decl::TranslationUnit:
+    return static_cast<TranslationUnitDecl *>(this)->getFirstDecl();
   case Decl::Namespace:
     // The original namespace is our primary context.
     return static_cast<NamespaceDecl *>(this)->getOriginalNamespace();
@@ -1285,21 +1286,25 @@
   }
 }
 
-void
-DeclContext::collectAllContexts(SmallVectorImpl<DeclContext *> &Contexts){
-  Contexts.clear();
+template <typename T>
+void collectAllContextsImpl(T *Self, SmallVectorImpl<DeclContext *> &Contexts) {
+  for (T *D = Self->getMostRecentDecl(); D; D = D->getPreviousDecl())
+    Contexts.push_back(D);
 
-  if (getDeclKind() != Decl::Namespace) {
-    Contexts.push_back(this);
-    return;
-  }
+  std::reverse(Contexts.begin(), Contexts.end());
+}
 
-  auto *Self = static_cast<NamespaceDecl *>(this);
-  for (NamespaceDecl *N = Self->getMostRecentDecl(); N;
-       N = N->getPreviousDecl())
-    Contexts.push_back(N);
+void DeclContext::collectAllContexts(SmallVectorImpl<DeclContext *> &Contexts) {
+  Contexts.clear();
 
-  std::reverse(Contexts.begin(), Contexts.end());
+  Decl::Kind Kind = getDeclKind();
+
+  if (Kind == Decl::TranslationUnit)
+    collectAllContextsImpl(static_cast<TranslationUnitDecl *>(this), Contexts);
+  else if (Kind == Decl::Namespace)
+    collectAllContextsImpl(static_cast<NamespaceDecl *>(this), Contexts);
+  else
+    Contexts.push_back(this);
 }
 
 std::pair<Decl *, Decl *>
Index: clang/lib/AST/Decl.cpp
===================================================================
--- clang/lib/AST/Decl.cpp
+++ clang/lib/AST/Decl.cpp
@@ -102,7 +102,7 @@
 
 TranslationUnitDecl::TranslationUnitDecl(ASTContext &ctx)
     : Decl(TranslationUnit, nullptr, SourceLocation()),
-      DeclContext(TranslationUnit), Ctx(ctx) {}
+      DeclContext(TranslationUnit), redeclarable_base(ctx), Ctx(ctx) {}
 
 //===----------------------------------------------------------------------===//
 // NamedDecl Implementation
Index: clang/lib/AST/ASTContext.cpp
===================================================================
--- clang/lib/AST/ASTContext.cpp
+++ clang/lib/AST/ASTContext.cpp
@@ -966,7 +966,7 @@
 
 ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM,
                        IdentifierTable &idents, SelectorTable &sels,
-                       Builtin::Context &builtins)
+                       Builtin::Context &builtins, TranslationUnitKind TUKind)
     : ConstantArrayTypes(this_()), FunctionProtoTypes(this_()),
       TemplateSpecializationTypes(this_()),
       DependentTemplateSpecializationTypes(this_()), AutoTypes(this_()),
@@ -978,11 +978,10 @@
                                         LangOpts.XRayAttrListFiles, SM)),
       ProfList(new ProfileList(LangOpts.ProfileListFiles, SM)),
       PrintingPolicy(LOpts), Idents(idents), Selectors(sels),
-      BuiltinInfo(builtins), DeclarationNames(*this), Comments(SM),
-      CommentCommandTraits(BumpAlloc, LOpts.CommentOpts),
+      BuiltinInfo(builtins), TUKind(TUKind), DeclarationNames(*this),
+      Comments(SM), CommentCommandTraits(BumpAlloc, LOpts.CommentOpts),
       CompCategories(this_()), LastSDM(nullptr, 0) {
-  TUDecl = TranslationUnitDecl::Create(*this);
-  TraversalScope = {TUDecl};
+  addTranslationUnitDecl();
 }
 
 ASTContext::~ASTContext() {
@@ -1196,9 +1195,10 @@
 BuiltinTemplateDecl *
 ASTContext::buildBuiltinTemplateDecl(BuiltinTemplateKind BTK,
                                      const IdentifierInfo *II) const {
-  auto *BuiltinTemplate = BuiltinTemplateDecl::Create(*this, TUDecl, II, BTK);
+  auto *BuiltinTemplate =
+      BuiltinTemplateDecl::Create(*this, getTranslationUnitDecl(), II, BTK);
   BuiltinTemplate->setImplicit();
-  TUDecl->addDecl(BuiltinTemplate);
+  getTranslationUnitDecl()->addDecl(BuiltinTemplate);
 
   return BuiltinTemplate;
 }
@@ -1485,7 +1485,7 @@
   // MSVC predeclares struct _GUID, and we need it to create MSGuidDecls.
   if (LangOpts.MicrosoftExt || LangOpts.Borland) {
     MSGuidTagDecl = buildImplicitRecord("_GUID");
-    TUDecl->addDecl(MSGuidTagDecl);
+    getTranslationUnitDecl()->addDecl(MSGuidTagDecl);
   }
 }
 
@@ -6622,7 +6622,7 @@
 QualType ASTContext::getObjCSuperType() const {
   if (ObjCSuperType.isNull()) {
     RecordDecl *ObjCSuperTypeDecl = buildImplicitRecord("objc_super");
-    TUDecl->addDecl(ObjCSuperTypeDecl);
+    getTranslationUnitDecl()->addDecl(ObjCSuperTypeDecl);
     ObjCSuperType = getTagDeclType(ObjCSuperTypeDecl);
   }
   return ObjCSuperType;
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -1377,7 +1377,7 @@
   /// initializers for tentative definitions in C) once parsing has
   /// completed. Modules and precompiled headers perform different kinds of
   /// checks.
-  TranslationUnitKind TUKind;
+  const TranslationUnitKind TUKind;
 
   llvm::BumpPtrAllocator BumpAlloc;
 
Index: clang/include/clang/Lex/Preprocessor.h
===================================================================
--- clang/include/clang/Lex/Preprocessor.h
+++ clang/include/clang/Lex/Preprocessor.h
@@ -264,9 +264,11 @@
   /// avoid tearing the Lexer and etc. down).
   bool IncrementalProcessing = false;
 
+public:
   /// The kind of translation unit we are processing.
-  TranslationUnitKind TUKind;
+  const TranslationUnitKind TUKind;
 
+private:
   /// The code-completion handler.
   CodeCompletionHandler *CodeComplete = nullptr;
 
Index: clang/include/clang/Interpreter/PartialTranslationUnit.h
===================================================================
--- clang/include/clang/Interpreter/PartialTranslationUnit.h
+++ clang/include/clang/Interpreter/PartialTranslationUnit.h
@@ -11,11 +11,10 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef LLVM_CLANG_INTERPRETER_TRANSACTION_H
-#define LLVM_CLANG_INTERPRETER_TRANSACTION_H
+#ifndef LLVM_CLANG_INTERPRETER_PARTIALTRANSLATIONUNIT_H
+#define LLVM_CLANG_INTERPRETER_PARTIALTRANSLATIONUNIT_H
 
 #include <memory>
-#include <vector>
 
 namespace llvm {
 class Module;
@@ -23,17 +22,16 @@
 
 namespace clang {
 
-class DeclGroupRef;
+class TranslationUnitDecl;
 
 /// The class keeps track of various objects created as part of processing
 /// incremental inputs.
-struct Transaction {
-  /// The decls created for the input.
-  std::vector<clang::DeclGroupRef> Decls;
+struct PartialTranslationUnit {
+  TranslationUnitDecl *TUPart = nullptr;
 
   /// The llvm IR produced for the input.
   std::unique_ptr<llvm::Module> TheModule;
 };
 } // namespace clang
 
-#endif // LLVM_CLANG_INTERPRETER_TRANSACTION_H
+#endif // LLVM_CLANG_INTERPRETER_PARTIALTRANSLATIONUNIT_H
Index: clang/include/clang/Interpreter/Interpreter.h
===================================================================
--- clang/include/clang/Interpreter/Interpreter.h
+++ clang/include/clang/Interpreter/Interpreter.h
@@ -14,7 +14,7 @@
 #ifndef LLVM_CLANG_INTERPRETER_INTERPRETER_H
 #define LLVM_CLANG_INTERPRETER_INTERPRETER_H
 
-#include "clang/Interpreter/Transaction.h"
+#include "clang/Interpreter/PartialTranslationUnit.h"
 
 #include "llvm/Support/Error.h"
 
@@ -55,14 +55,14 @@
   static llvm::Expected<std::unique_ptr<Interpreter>>
   create(std::unique_ptr<CompilerInstance> CI);
   const CompilerInstance *getCompilerInstance() const;
-  llvm::Expected<Transaction &> Parse(llvm::StringRef Code);
-  llvm::Error Execute(Transaction &T);
+  llvm::Expected<PartialTranslationUnit &> Parse(llvm::StringRef Code);
+  llvm::Error Execute(PartialTranslationUnit &T);
   llvm::Error ParseAndExecute(llvm::StringRef Code) {
-    auto ErrOrTransaction = Parse(Code);
-    if (auto Err = ErrOrTransaction.takeError())
-      return Err;
-    if (ErrOrTransaction->TheModule)
-      return Execute(*ErrOrTransaction);
+    auto PTU = Parse(Code);
+    if (!PTU)
+      return PTU.takeError();
+    if (PTU->TheModule)
+      return Execute(*PTU);
     return llvm::Error::success();
   }
 };
Index: clang/include/clang/Basic/LangOptions.h
===================================================================
--- clang/include/clang/Basic/LangOptions.h
+++ clang/include/clang/Basic/LangOptions.h
@@ -697,7 +697,11 @@
   TU_Prefix,
 
   /// The translation unit is a module.
-  TU_Module
+  TU_Module,
+
+  /// The translation unit is a is a complete translation unit that we might
+  /// incrementally extend later.
+  TU_Incremental
 };
 
 } // namespace clang
Index: clang/include/clang/AST/Redeclarable.h
===================================================================
--- clang/include/clang/AST/Redeclarable.h
+++ clang/include/clang/AST/Redeclarable.h
@@ -193,6 +193,7 @@
 public:
   friend class ASTDeclReader;
   friend class ASTDeclWriter;
+  friend class IncrementalParser;
 
   Redeclarable(const ASTContext &Ctx)
       : RedeclLink(LatestDeclLink(Ctx)),
Index: clang/include/clang/AST/Decl.h
===================================================================
--- clang/include/clang/AST/Decl.h
+++ clang/include/clang/AST/Decl.h
@@ -79,7 +79,23 @@
 class VarTemplateDecl;
 
 /// The top declaration context.
-class TranslationUnitDecl : public Decl, public DeclContext {
+class TranslationUnitDecl : public Decl,
+                            public DeclContext,
+                            public Redeclarable<TranslationUnitDecl> {
+  using redeclarable_base = Redeclarable<TranslationUnitDecl>;
+
+  TranslationUnitDecl *getNextRedeclarationImpl() override {
+    return getNextRedeclaration();
+  }
+
+  TranslationUnitDecl *getPreviousDeclImpl() override {
+    return getPreviousDecl();
+  }
+
+  TranslationUnitDecl *getMostRecentDeclImpl() override {
+    return getMostRecentDecl();
+  }
+
   ASTContext &Ctx;
 
   /// The (most recently entered) anonymous namespace for this
@@ -91,6 +107,16 @@
   virtual void anchor();
 
 public:
+  using redecl_range = redeclarable_base::redecl_range;
+  using redecl_iterator = redeclarable_base::redecl_iterator;
+
+  using redeclarable_base::getMostRecentDecl;
+  using redeclarable_base::getPreviousDecl;
+  using redeclarable_base::isFirstDecl;
+  using redeclarable_base::redecls;
+  using redeclarable_base::redecls_begin;
+  using redeclarable_base::redecls_end;
+
   ASTContext &getASTContext() const { return Ctx; }
 
   NamespaceDecl *getAnonymousNamespace() const { return AnonymousNamespace; }
Index: clang/include/clang/AST/ASTContext.h
===================================================================
--- clang/include/clang/AST/ASTContext.h
+++ clang/include/clang/AST/ASTContext.h
@@ -459,6 +459,7 @@
   friend class ASTWriter;
   template <class> friend class serialization::AbstractTypeReader;
   friend class CXXRecordDecl;
+  friend class IncrementalParser;
 
   /// A mapping to contain the template or declaration that
   /// a variable declaration describes or was instantiated from,
@@ -567,7 +568,7 @@
   ImportDecl *FirstLocalImport = nullptr;
   ImportDecl *LastLocalImport = nullptr;
 
-  TranslationUnitDecl *TUDecl;
+  TranslationUnitDecl *TUDecl = nullptr;
   mutable ExternCContextDecl *ExternCContext = nullptr;
   mutable BuiltinTemplateDecl *MakeIntegerSeqDecl = nullptr;
   mutable BuiltinTemplateDecl *TypePackElementDecl = nullptr;
@@ -624,6 +625,7 @@
   IdentifierTable &Idents;
   SelectorTable &Selectors;
   Builtin::Context &BuiltinInfo;
+  const TranslationUnitKind TUKind;
   mutable DeclarationNameTable DeclarationNames;
   IntrusiveRefCntPtr<ExternalASTSource> ExternalSource;
   ASTMutationListener *Listener = nullptr;
@@ -1022,7 +1024,18 @@
   /// Get the initializations to perform when importing a module, if any.
   ArrayRef<Decl*> getModuleInitializers(Module *M);
 
-  TranslationUnitDecl *getTranslationUnitDecl() const { return TUDecl; }
+  TranslationUnitDecl *getTranslationUnitDecl() const {
+    return TUDecl->getMostRecentDecl();
+  }
+  void addTranslationUnitDecl() {
+    assert(!TUDecl || TUKind == TU_Incremental);
+    TranslationUnitDecl *NewTUDecl = TranslationUnitDecl::Create(*this);
+    if (TraversalScope.empty() || TraversalScope.back() == TUDecl)
+      TraversalScope = {NewTUDecl};
+    if (TUDecl)
+      NewTUDecl->setPreviousDecl(TUDecl);
+    TUDecl = NewTUDecl;
+  }
 
   ExternCContextDecl *getExternCContextDecl() const;
   BuiltinTemplateDecl *getMakeIntegerSeqDecl() const;
@@ -1099,7 +1112,8 @@
   llvm::DenseSet<const VarDecl *> CUDADeviceVarODRUsedByHost;
 
   ASTContext(LangOptions &LOpts, SourceManager &SM, IdentifierTable &idents,
-             SelectorTable &sels, Builtin::Context &builtins);
+             SelectorTable &sels, Builtin::Context &builtins,
+             TranslationUnitKind TUKind);
   ASTContext(const ASTContext &) = delete;
   ASTContext &operator=(const ASTContext &) = delete;
   ~ASTContext();
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to