diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -339,11 +339,30 @@ /// yet. llvm::DenseMap DeferredDecls; + /// Decls that were DeferredDecls and have now been emitted. + llvm::DenseMap EmittedDeferredDecls; + + void addEmittedDeferredDecl(GlobalDecl GD) { + bool IsAFunction = isa(GD.getDecl()); + const VarDecl *VD = IsAFunction ? nullptr : dyn_cast(GD.getDecl()); + assert((IsAFunction || VD) && "Unexpected Decl type!"); + llvm::GlobalValue::LinkageTypes L = + IsAFunction + ? getFunctionLinkage(GD) + : getLLVMLinkageVarDefinition( + VD, isTypeConstant(VD->getType(), /*ExcludeCtor=*/false)); + if (llvm::GlobalValue::isLinkOnceLinkage(L) || + llvm::GlobalValue::isWeakLinkage(L)) { + EmittedDeferredDecls[getMangledName(GD)] = GD; + } + } + /// This is a list of deferred decls which we have seen that *are* actually /// referenced. These get code generated when the module is done. std::vector DeferredDeclsToEmit; void addDeferredDeclToEmit(GlobalDecl GD) { DeferredDeclsToEmit.emplace_back(GD); + addEmittedDeferredDecl(GD); } /// List of alias we have emitted. Used to make sure that what they point to @@ -1477,6 +1496,34 @@ void printPostfixForExternalizedDecl(llvm::raw_ostream &OS, const Decl *D) const; + llvm::SmallPtrSetImpl &getEmittedDeferredDecls() { + return EmittedModuleInitializers; + } + + llvm::DenseMap &getDeferredDecls() { + return DeferredDecls; + } + + std::vector &getDeferredDeclsToEmit() { + return DeferredDeclsToEmit; + } + + std::vector &getDeferredVTables() { + return DeferredVTables; + } + + llvm::MapVector &getMangledDeclNames() { + return MangledDeclNames; + } + + llvm::StringMap &getManglings() { + return Manglings; + } + + llvm::SmallPtrSetImpl &getWeakRefReferences() { + return WeakRefReferences; + } + private: llvm::Constant *GetOrCreateLLVMFunction( StringRef MangledName, llvm::Type *Ty, GlobalDecl D, bool ForVTable, diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -446,6 +446,7 @@ void CodeGenModule::clear() { DeferredDeclsToEmit.clear(); + EmittedDeferredDecls.clear(); if (OpenMPRuntime) OpenMPRuntime->clear(); } @@ -511,6 +512,9 @@ void CodeGenModule::Release() { EmitDeferred(); + DeferredDecls.insert(EmittedDeferredDecls.begin(), + EmittedDeferredDecls.end()); + EmittedDeferredDecls.clear(); EmitVTablesOpportunistically(); applyGlobalValReplacements(); applyReplacements(); @@ -3160,6 +3164,7 @@ if (MustBeEmitted(Global) && MayBeEmittedEagerly(Global)) { // Emit the definition if it can't be deferred. EmitGlobalDefinition(GD); + addEmittedDeferredDecl(GD); return; } diff --git a/clang/lib/CodeGen/ModuleBuilder.cpp b/clang/lib/CodeGen/ModuleBuilder.cpp --- a/clang/lib/CodeGen/ModuleBuilder.cpp +++ b/clang/lib/CodeGen/ModuleBuilder.cpp @@ -133,8 +133,38 @@ llvm::Module *StartModule(llvm::StringRef ModuleName, llvm::LLVMContext &C) { assert(!M && "Replacing existing Module?"); + + std::unique_ptr OldBuilder; + OldBuilder.swap(Builder); + + assert(OldBuilder->getEmittedDeferredDecls().empty() && + "Still have (unmerged) EmittedDeferredDecls deferred decls"); + M.reset(new llvm::Module(ExpandModuleName(ModuleName, CodeGenOpts), C)); Initialize(*Ctx); + + assert(OldBuilder->getDeferredDeclsToEmit().empty() && + "Should have emitted all decls deferred to emit."); + assert(Builder->getDeferredDecls().empty() && + "Newly created module should not have deferred decls"); + + Builder->getDeferredDecls().swap(OldBuilder->getDeferredDecls()); + + assert(Builder->getDeferredVTables().empty() && + "Newly created module should not have deferred vtables"); + + Builder->getDeferredVTables().swap(OldBuilder->getDeferredVTables()); + + assert(Builder->getMangledDeclNames().empty() && + "Newly created module should not have mangled decl names"); + assert(Builder->getManglings().empty() && + "Newly created module should not have manglings"); + + Builder->getManglings() = std::move(OldBuilder->getManglings()); + + assert(OldBuilder->getWeakRefReferences().empty() && + "Not all WeakRefRefs have been applied"); + return M.get(); } 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 @@ -248,4 +248,22 @@ EXPECT_EQ(42, fn(NewA)); } +TEST(InterpreterTest, InlineDecls) { + Args ExtraArgs = {"-Xclang", "-diagnostic-log-file", "-Xclang", "-"}; + + // Create the diagnostic engine with unowned consumer. + std::string DiagnosticOutput; + llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput); + auto DiagPrinter = std::make_unique( + DiagnosticsOS, new DiagnosticOptions()); + + auto Interp = createInterpreter(ExtraArgs, DiagPrinter.get()); + + auto R1 = Interp->Parse("inline int foo() { return 42;}"); + EXPECT_TRUE(!!R1); + + auto R2 = Interp->Parse("int x = foo();"); + EXPECT_TRUE(!!R2); +} + } // end anonymous namespace