diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -459,6 +459,7 @@ friend class ASTWriter; template 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 ExternalSource; ASTMutationListener *Listener = nullptr; @@ -1022,7 +1024,18 @@ /// Get the initializations to perform when importing a module, if any. ArrayRef 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 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(); diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h --- a/clang/include/clang/AST/Decl.h +++ b/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 { + using redeclarable_base = Redeclarable; + + 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; } diff --git a/clang/include/clang/AST/Redeclarable.h b/clang/include/clang/AST/Redeclarable.h --- a/clang/include/clang/AST/Redeclarable.h +++ b/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)), diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h --- a/clang/include/clang/Basic/LangOptions.h +++ b/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 diff --git a/clang/include/clang/Interpreter/Interpreter.h b/clang/include/clang/Interpreter/Interpreter.h --- a/clang/include/clang/Interpreter/Interpreter.h +++ b/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> create(std::unique_ptr CI); const CompilerInstance *getCompilerInstance() const; - llvm::Expected Parse(llvm::StringRef Code); - llvm::Error Execute(Transaction &T); + llvm::Expected 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(); } }; diff --git a/clang/include/clang/Interpreter/Transaction.h b/clang/include/clang/Interpreter/PartialTranslationUnit.h rename from clang/include/clang/Interpreter/Transaction.h rename to clang/include/clang/Interpreter/PartialTranslationUnit.h --- a/clang/include/clang/Interpreter/Transaction.h +++ b/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 -#include 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 Decls; +struct PartialTranslationUnit { + TranslationUnitDecl *TUPart = nullptr; /// The llvm IR produced for the input. std::unique_ptr TheModule; }; } // namespace clang -#endif // LLVM_CLANG_INTERPRETER_TRANSACTION_H +#endif // LLVM_CLANG_INTERPRETER_PARTIALTRANSLATIONUNIT_H diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h --- a/clang/include/clang/Lex/Preprocessor.h +++ b/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; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/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; diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp --- a/clang/lib/AST/ASTContext.cpp +++ b/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; diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp --- a/clang/lib/AST/Decl.cpp +++ b/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 diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp --- a/clang/lib/AST/DeclBase.cpp +++ b/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(this)->getFirstDecl(); case Decl::Namespace: // The original namespace is our primary context. return static_cast(this)->getOriginalNamespace(); @@ -1285,21 +1286,25 @@ } } -void -DeclContext::collectAllContexts(SmallVectorImpl &Contexts){ - Contexts.clear(); +template +void collectAllContextsImpl(T *Self, SmallVectorImpl &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(this); - for (NamespaceDecl *N = Self->getMostRecentDecl(); N; - N = N->getPreviousDecl()) - Contexts.push_back(N); +void DeclContext::collectAllContexts(SmallVectorImpl &Contexts) { + Contexts.clear(); - std::reverse(Contexts.begin(), Contexts.end()); + Decl::Kind Kind = getDeclKind(); + + if (Kind == Decl::TranslationUnit) + collectAllContextsImpl(static_cast(this), Contexts); + else if (Kind == Decl::Namespace) + collectAllContextsImpl(static_cast(this), Contexts); + else + Contexts.push_back(this); } std::pair diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp --- a/clang/lib/Frontend/ASTUnit.cpp +++ b/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; diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/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); } diff --git a/clang/lib/Interpreter/IncrementalParser.h b/clang/lib/Interpreter/IncrementalParser.h --- a/clang/lib/Interpreter/IncrementalParser.h +++ b/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 Transactions; + std::list PTUs; public: IncrementalParser(std::unique_ptr 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 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 Parse(llvm::StringRef Input); private: - llvm::Expected ParseOrWrapTopLevelDecl(); + llvm::Expected ParseOrWrapTopLevelDecl(); }; } // end namespace clang diff --git a/clang/lib/Interpreter/IncrementalParser.cpp b/clang/lib/Interpreter/IncrementalParser.cpp --- a/clang/lib/Interpreter/IncrementalParser.cpp +++ b/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 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 +IncrementalParser::ParseOrWrapTopLevelDecl() { // Recover resources if we crash before exiting this method. Sema &S = CI->getSema(); llvm::CrashRecoveryContextCleanupRegistrar 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("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("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("Parsing failed.", - std::error_code()); + Consumer->HandleTranslationUnit(C); - return LastTransaction; + return LastPTU; } static CodeGenerator *getCodeGen(FrontendAction *Act) { @@ -191,7 +225,8 @@ return static_cast(WrappedAct)->getCodeGenerator(); } -llvm::Expected IncrementalParser::Parse(llvm::StringRef input) { +llvm::Expected +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 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 diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp --- a/clang/lib/Interpreter/Interpreter.cpp +++ b/clang/lib/Interpreter/Interpreter.cpp @@ -198,11 +198,12 @@ return IncrParser->getCI(); } -llvm::Expected Interpreter::Parse(llvm::StringRef Code) { +llvm::Expected +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 = diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp --- a/clang/lib/Sema/Sema.cpp +++ b/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; diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -7176,6 +7176,11 @@ return; } + if (!D->getDeclContext()) { + assert(isa(D) && "Not a TU?"); + return; + } + const DeclContext *DC = D->getDeclContext()->getRedeclContext(); // If this is a named declaration, complete it by looking it up diff --git a/clang/tools/clang-import-test/clang-import-test.cpp b/clang/tools/clang-import-test/clang-import-test.cpp --- a/clang/tools/clang-import-test/clang-import-test.cpp +++ b/clang/tools/clang-import-test/clang-import-test.cpp @@ -218,9 +218,10 @@ std::unique_ptr BuildASTContext(CompilerInstance &CI, SelectorTable &ST, Builtin::Context &BC) { + auto &PP = CI.getPreprocessor(); auto AST = std::make_unique( CI.getLangOpts(), CI.getSourceManager(), - CI.getPreprocessor().getIdentifierTable(), ST, BC); + PP.getIdentifierTable(), ST, BC, PP.TUKind); AST->InitBuiltinTypes(CI.getTarget()); return AST; } diff --git a/clang/unittests/AST/ASTVectorTest.cpp b/clang/unittests/AST/ASTVectorTest.cpp --- a/clang/unittests/AST/ASTVectorTest.cpp +++ b/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; diff --git a/clang/unittests/Interpreter/IncrementalProcessingTest.cpp b/clang/unittests/Interpreter/IncrementalProcessingTest.cpp --- a/clang/unittests/Interpreter/IncrementalProcessingTest.cpp +++ b/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 Transactions; + std::array 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()); diff --git a/clang/unittests/Interpreter/InterpreterTest.cpp b/clang/unittests/Interpreter/InterpreterTest.cpp --- a/clang/unittests/Interpreter/InterpreterTest.cpp +++ b/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 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(DGR.getSingleDecl())->getQualifiedNameAsString(); +static std::string DeclToString(Decl *D) { + return llvm::cast(D)->getQualifiedNameAsString(); } TEST(InterpreterTest, IncrementalInputTopLevelDecls) { std::unique_ptr 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))); } diff --git a/clang/unittests/Lex/PPCallbacksTest.cpp b/clang/unittests/Lex/PPCallbacksTest.cpp --- a/clang/unittests/Lex/PPCallbacksTest.cpp +++ b/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;