summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
Diffstat (limited to 'clang')
-rw-r--r--clang/include/clang/AST/ASTContext.h2
-rw-r--r--clang/include/clang/AST/ExternalASTSource.h5
-rw-r--r--clang/include/clang/Basic/LangOptions.def1
-rw-r--r--clang/include/clang/Basic/Module.h2
-rw-r--r--clang/include/clang/Driver/CC1Options.td4
-rw-r--r--clang/include/clang/Sema/MultiplexExternalSemaSource.h2
-rw-r--r--clang/include/clang/Serialization/ASTBitCodes.h2
-rw-r--r--clang/include/clang/Serialization/ASTReader.h4
-rw-r--r--clang/include/clang/Serialization/ASTWriter.h1
-rw-r--r--clang/lib/AST/ASTContext.cpp25
-rw-r--r--clang/lib/AST/ExternalASTSource.cpp5
-rw-r--r--clang/lib/Basic/Module.cpp2
-rw-r--r--clang/lib/CodeGen/CodeGenModule.cpp2
-rw-r--r--clang/lib/Frontend/CompilerInvocation.cpp1
-rw-r--r--clang/lib/Lex/ModuleMap.cpp13
-rw-r--r--clang/lib/Sema/MultiplexExternalSemaSource.cpp9
-rw-r--r--clang/lib/Serialization/ASTReader.cpp30
-rw-r--r--clang/lib/Serialization/ASTWriter.cpp22
-rw-r--r--clang/lib/Serialization/ASTWriterDecl.cpp9
-rw-r--r--clang/test/Modules/Inputs/codegen/bar.h2
-rw-r--r--clang/test/Modules/Inputs/codegen/bar.modulemap1
-rw-r--r--clang/test/Modules/Inputs/codegen/foo.h10
-rw-r--r--clang/test/Modules/Inputs/codegen/foo.modulemap1
-rw-r--r--clang/test/Modules/Inputs/codegen/use.cpp2
-rw-r--r--clang/test/Modules/codegen.test64
25 files changed, 199 insertions, 22 deletions
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 95429bf8cee..e6287dc0659 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -2494,7 +2494,7 @@ public:
///
/// \returns true if the function/var must be CodeGen'ed/deserialized even if
/// it is not used.
- bool DeclMustBeEmitted(const Decl *D);
+ bool DeclMustBeEmitted(const Decl *D, bool ForModularCodegen = false);
const CXXConstructorDecl *
getCopyConstructorForExceptionObject(CXXRecordDecl *RD);
diff --git a/clang/include/clang/AST/ExternalASTSource.h b/clang/include/clang/AST/ExternalASTSource.h
index 2e99f395f49..9e48a6a2f31 100644
--- a/clang/include/clang/AST/ExternalASTSource.h
+++ b/clang/include/clang/AST/ExternalASTSource.h
@@ -16,6 +16,7 @@
#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclBase.h"
+#include "clang/Basic/Module.h"
#include "llvm/ADT/DenseMap.h"
namespace clang {
@@ -169,6 +170,10 @@ public:
/// Return a descriptor for the corresponding module, if one exists.
virtual llvm::Optional<ASTSourceDescriptor> getSourceDescriptor(unsigned ID);
+ enum ExtKind { EK_Always, EK_Never, EK_ReplyHazy };
+
+ virtual ExtKind hasExternalDefinitions(unsigned ID);
+
/// \brief Finds all declarations lexically contained within the given
/// DeclContext, after applying an optional filter predicate.
///
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index d944a9d78ab..d02909eb07e 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -201,6 +201,7 @@ LANGOPT(SizedDeallocation , 1, 0, "sized deallocation")
LANGOPT(AlignedAllocation , 1, 0, "aligned allocation")
LANGOPT(NewAlignOverride , 32, 0, "maximum alignment guaranteed by '::operator new(size_t)'")
LANGOPT(ConceptsTS , 1, 0, "enable C++ Extensions for Concepts")
+BENIGN_LANGOPT(ModularCodegen , 1, 0, "Modular codegen")
BENIGN_LANGOPT(ElideConstructors , 1, 1, "C++ copy constructor elision")
BENIGN_LANGOPT(DumpRecordLayouts , 1, 0, "dumping the layout of IRgen'd records")
BENIGN_LANGOPT(DumpRecordLayoutsSimple , 1, 0, "dumping the layout of IRgen'd records in a simple form")
diff --git a/clang/include/clang/Basic/Module.h b/clang/include/clang/Basic/Module.h
index 31c5c7ec9ca..da74d0be86e 100644
--- a/clang/include/clang/Basic/Module.h
+++ b/clang/include/clang/Basic/Module.h
@@ -205,6 +205,8 @@ public:
/// and headers from used modules.
unsigned NoUndeclaredIncludes : 1;
+ unsigned WithCodegen : 1;
+
/// \brief Describes the visibility of the various names within a
/// particular module.
enum NameVisibilityKind {
diff --git a/clang/include/clang/Driver/CC1Options.td b/clang/include/clang/Driver/CC1Options.td
index 11ab274bff0..35475b4f1eb 100644
--- a/clang/include/clang/Driver/CC1Options.td
+++ b/clang/include/clang/Driver/CC1Options.td
@@ -432,6 +432,10 @@ def fmodules_local_submodule_visibility :
Flag<["-"], "fmodules-local-submodule-visibility">,
HelpText<"Enforce name visibility rules across submodules of the same "
"top-level module.">;
+def fmodule_codegen :
+ Flag<["-"], "fmodules-codegen">,
+ HelpText<"Generate code for uses of this module that assumes an explicit "
+ "object file will be built for the module">;
def fmodule_format_EQ : Joined<["-"], "fmodule-format=">,
HelpText<"Select the container format for clang modules and PCH. "
"Supported options are 'raw' and 'obj'.">;
diff --git a/clang/include/clang/Sema/MultiplexExternalSemaSource.h b/clang/include/clang/Sema/MultiplexExternalSemaSource.h
index 37157204ea1..93e83dc026d 100644
--- a/clang/include/clang/Sema/MultiplexExternalSemaSource.h
+++ b/clang/include/clang/Sema/MultiplexExternalSemaSource.h
@@ -90,6 +90,8 @@ public:
/// initializers themselves.
CXXCtorInitializer **GetExternalCXXCtorInitializers(uint64_t Offset) override;
+ ExtKind hasExternalDefinitions(unsigned ID) override;
+
/// \brief Find all declarations with the given name in the
/// given context.
bool FindExternalVisibleDeclsByName(const DeclContext *DC,
diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h
index 3a4adc0c0b8..32322b59baf 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -591,6 +591,8 @@ namespace clang {
/// \brief Record code for declarations associated with OpenCL extensions.
OPENCL_EXTENSION_DECLS = 59,
+
+ MODULAR_CODEGEN_DECLS = 60,
};
/// \brief Record types used within a source manager block.
diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h
index aacabb16ca9..5a57911c1b2 100644
--- a/clang/include/clang/Serialization/ASTReader.h
+++ b/clang/include/clang/Serialization/ASTReader.h
@@ -715,6 +715,8 @@ private:
/// the consumer eagerly.
SmallVector<uint64_t, 16> EagerlyDeserializedDecls;
+ SmallVector<uint64_t, 16> ModularCodegenDecls;
+
/// \brief The IDs of all tentative definitions stored in the chain.
///
/// Sema keeps track of all tentative definitions in a TU because it has to
@@ -1968,6 +1970,8 @@ public:
/// \brief Return a descriptor for the corresponding module.
llvm::Optional<ASTSourceDescriptor> getSourceDescriptor(unsigned ID) override;
+ ExtKind hasExternalDefinitions(unsigned ID) override;
+
/// \brief Retrieve a selector from the given module with its local ID
/// number.
Selector getLocalSelector(ModuleFile &M, unsigned LocalID);
diff --git a/clang/include/clang/Serialization/ASTWriter.h b/clang/include/clang/Serialization/ASTWriter.h
index 0d6b0268109..23afa639ded 100644
--- a/clang/include/clang/Serialization/ASTWriter.h
+++ b/clang/include/clang/Serialization/ASTWriter.h
@@ -365,6 +365,7 @@ private:
/// IDs, since they will be written out to an EAGERLY_DESERIALIZED_DECLS
/// record.
SmallVector<uint64_t, 16> EagerlyDeserializedDecls;
+ SmallVector<uint64_t, 16> ModularCodegenDecls;
/// \brief DeclContexts that have received extensions since their serialized
/// form.
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 07721b2ba7c..1539a52e7fd 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -8882,8 +8882,22 @@ static GVALinkage adjustGVALinkageForAttributes(const ASTContext &Context,
}
GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) const {
- return adjustGVALinkageForAttributes(
+ auto L = adjustGVALinkageForAttributes(
*this, basicGVALinkageForFunction(*this, FD), FD);
+ auto EK = ExternalASTSource::EK_ReplyHazy;
+ if (auto *Ext = getExternalSource())
+ EK = Ext->hasExternalDefinitions(FD->getOwningModuleID());
+ switch (EK) {
+ case ExternalASTSource::EK_Never:
+ if (L == GVA_DiscardableODR)
+ return GVA_StrongODR;
+ break;
+ case ExternalASTSource::EK_Always:
+ return GVA_AvailableExternally;
+ case ExternalASTSource::EK_ReplyHazy:
+ break;
+ }
+ return L;
}
static GVALinkage basicGVALinkageForVariable(const ASTContext &Context,
@@ -8968,7 +8982,7 @@ GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) {
*this, basicGVALinkageForVariable(*this, VD), VD);
}
-bool ASTContext::DeclMustBeEmitted(const Decl *D) {
+bool ASTContext::DeclMustBeEmitted(const Decl *D, bool ForModularCodegen) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (!VD->isFileVarDecl())
return false;
@@ -9032,10 +9046,15 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
}
}
+ GVALinkage Linkage = GetGVALinkageForFunction(FD);
+
+ if (Linkage == GVA_DiscardableODR && ForModularCodegen)
+ return true;
+
// static, static inline, always_inline, and extern inline functions can
// always be deferred. Normal inline functions can be deferred in C99/C++.
// Implicit template instantiations can also be deferred in C++.
- return !isDiscardableGVALinkage(GetGVALinkageForFunction(FD));
+ return !isDiscardableGVALinkage(Linkage);
}
const VarDecl *VD = cast<VarDecl>(D);
diff --git a/clang/lib/AST/ExternalASTSource.cpp b/clang/lib/AST/ExternalASTSource.cpp
index e3de8c5fefa..26b1aef0a8f 100644
--- a/clang/lib/AST/ExternalASTSource.cpp
+++ b/clang/lib/AST/ExternalASTSource.cpp
@@ -28,6 +28,11 @@ ExternalASTSource::getSourceDescriptor(unsigned ID) {
return None;
}
+ExternalASTSource::ExtKind
+ExternalASTSource::hasExternalDefinitions(unsigned ID) {
+ return EK_ReplyHazy;
+}
+
ExternalASTSource::ASTSourceDescriptor::ASTSourceDescriptor(const Module &M)
: Signature(M.Signature), ClangModule(&M) {
if (M.Directory)
diff --git a/clang/lib/Basic/Module.cpp b/clang/lib/Basic/Module.cpp
index 80bbc24f3db..719ff6709ff 100644
--- a/clang/lib/Basic/Module.cpp
+++ b/clang/lib/Basic/Module.cpp
@@ -33,7 +33,7 @@ Module::Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent,
IsExplicit(IsExplicit), IsSystem(false), IsExternC(false),
IsInferred(false), InferSubmodules(false), InferExplicitSubmodules(false),
InferExportWildcard(false), ConfigMacrosExhaustive(false),
- NoUndeclaredIncludes(false), NameVisibility(Hidden) {
+ NoUndeclaredIncludes(false), WithCodegen(false), NameVisibility(Hidden) {
if (Parent) {
if (!Parent->isAvailable())
IsAvailable = false;
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index f9866957a14..d8e1d581150 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -2796,7 +2796,7 @@ llvm::GlobalValue::LinkageTypes CodeGenModule::getLLVMLinkageForDeclarator(
// We are guaranteed to have a strong definition somewhere else,
// so we can use available_externally linkage.
if (Linkage == GVA_AvailableExternally)
- return llvm::Function::AvailableExternallyLinkage;
+ return llvm::GlobalValue::AvailableExternallyLinkage;
// Note that Apple's kernel linker doesn't support symbol
// coalescing, so we need to avoid linkonce and weak linkages there.
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index ee46f921ccb..a8c1e616577 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -1955,6 +1955,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Args.hasArg(OPT_fmodules_decluse) || Opts.ModulesStrictDeclUse;
Opts.ModulesLocalVisibility =
Args.hasArg(OPT_fmodules_local_submodule_visibility) || Opts.ModulesTS;
+ Opts.ModularCodegen = Args.hasArg(OPT_fmodule_codegen);
Opts.ModulesSearchAll = Opts.Modules &&
!Args.hasArg(OPT_fno_modules_search_all) &&
Args.hasArg(OPT_fmodules_search_all);
diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp
index 1488f624da6..1db5becac4b 100644
--- a/clang/lib/Lex/ModuleMap.cpp
+++ b/clang/lib/Lex/ModuleMap.cpp
@@ -91,6 +91,7 @@ ModuleMap::ModuleMap(SourceManager &SourceMgr, DiagnosticsEngine &Diags,
HeaderInfo(HeaderInfo), BuiltinIncludeDir(nullptr),
SourceModule(nullptr), NumCreatedModules(0) {
MMapLangOpts.LineComment = true;
+ MMapLangOpts.ModularCodegen = LangOpts.ModularCodegen;
}
ModuleMap::~ModuleMap() {
@@ -554,16 +555,17 @@ Module *ModuleMap::lookupModuleQualified(StringRef Name, Module *Context) const{
return Context->findSubmodule(Name);
}
-std::pair<Module *, bool>
-ModuleMap::findOrCreateModule(StringRef Name, Module *Parent, bool IsFramework,
- bool IsExplicit) {
+std::pair<Module *, bool> ModuleMap::findOrCreateModule(StringRef Name,
+ Module *Parent,
+ bool IsFramework,
+ bool IsExplicit) {
// Try to find an existing module with this name.
if (Module *Sub = lookupModuleQualified(Name, Parent))
return std::make_pair(Sub, false);
// Create a new module with this name.
- Module *Result = new Module(Name, SourceLocation(), Parent,
- IsFramework, IsExplicit, NumCreatedModules++);
+ Module *Result = new Module(Name, SourceLocation(), Parent, IsFramework,
+ IsExplicit, NumCreatedModules++);
if (!Parent) {
if (LangOpts.CurrentModule == Name)
SourceModule = Result;
@@ -1499,6 +1501,7 @@ void ModuleMapParser::parseModuleDecl() {
(!ActiveModule->Parent && ModuleName == "Darwin"))
ActiveModule->NoUndeclaredIncludes = true;
ActiveModule->Directory = Directory;
+ ActiveModule->WithCodegen = L.getLangOpts().ModularCodegen;
if (!ActiveModule->Parent) {
StringRef MapFileName(ModuleMapFile->getName());
diff --git a/clang/lib/Sema/MultiplexExternalSemaSource.cpp b/clang/lib/Sema/MultiplexExternalSemaSource.cpp
index 077a56ff8e7..c97e4dfdd6d 100644
--- a/clang/lib/Sema/MultiplexExternalSemaSource.cpp
+++ b/clang/lib/Sema/MultiplexExternalSemaSource.cpp
@@ -94,6 +94,15 @@ MultiplexExternalSemaSource::GetExternalCXXCtorInitializers(uint64_t Offset) {
return nullptr;
}
+ExternalASTSource::ExtKind
+MultiplexExternalSemaSource::hasExternalDefinitions(unsigned int ID) {
+ for (const auto &S : Sources)
+ if (auto EK = S->hasExternalDefinitions(ID))
+ if (EK != EK_ReplyHazy)
+ return EK;
+ return EK_ReplyHazy;
+}
+
bool MultiplexExternalSemaSource::
FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) {
bool AnyDeclsFound = false;
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 44cef7de312..e3122039c7d 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -2607,7 +2607,8 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
break;
case SUBMODULE_BLOCK_ID:
- if (ASTReadResult Result = ReadSubmoduleBlock(F, ClientLoadCapabilities))
+ if (ASTReadResult Result =
+ ReadSubmoduleBlock(F, ClientLoadCapabilities))
return Result;
break;
@@ -2772,6 +2773,14 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
EagerlyDeserializedDecls.push_back(getGlobalDeclID(F, Record[I]));
break;
+ case MODULAR_CODEGEN_DECLS:
+ // FIXME: Skip reading this record if our ASTConsumer doesn't care about
+ // them (ie: if we're not codegenerating this module).
+ if (F.Kind == MK_MainFile)
+ for (unsigned I = 0, N = Record.size(); I != N; ++I)
+ EagerlyDeserializedDecls.push_back(getGlobalDeclID(F, Record[I]));
+ break;
+
case SPECIAL_TYPES:
if (SpecialTypes.empty()) {
for (unsigned I = 0, N = Record.size(); I != N; ++I)
@@ -4628,6 +4637,7 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
bool InferExplicitSubmodules = Record[Idx++];
bool InferExportWildcard = Record[Idx++];
bool ConfigMacrosExhaustive = Record[Idx++];
+ bool WithCodegen = Record[Idx++];
Module *ParentModule = nullptr;
if (Parent)
@@ -4635,8 +4645,9 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
// Retrieve this (sub)module from the module map, creating it if
// necessary.
- CurrentModule = ModMap.findOrCreateModule(Name, ParentModule, IsFramework,
- IsExplicit).first;
+ CurrentModule =
+ ModMap.findOrCreateModule(Name, ParentModule, IsFramework, IsExplicit)
+ .first;
// FIXME: set the definition loc for CurrentModule, or call
// ModMap.setInferredModuleAllowedBy()
@@ -4672,6 +4683,7 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
CurrentModule->InferExplicitSubmodules = InferExplicitSubmodules;
CurrentModule->InferExportWildcard = InferExportWildcard;
CurrentModule->ConfigMacrosExhaustive = ConfigMacrosExhaustive;
+ CurrentModule->WithCodegen = WithCodegen;
if (DeserializationListener)
DeserializationListener->ModuleRead(GlobalID, CurrentModule);
@@ -7895,6 +7907,18 @@ ASTReader::getSourceDescriptor(unsigned ID) {
return None;
}
+ExternalASTSource::ExtKind ASTReader::hasExternalDefinitions(unsigned ID) {
+ const Module *M = getSubmodule(ID);
+ if (!M || !M->WithCodegen)
+ return EK_ReplyHazy;
+
+ ModuleFile *MF = ModuleMgr.lookup(M->getASTFile());
+ assert(MF); // ?
+ if (MF->Kind == ModuleKind::MK_MainFile)
+ return EK_Never;
+ return EK_Always;
+}
+
Selector ASTReader::getLocalSelector(ModuleFile &M, unsigned LocalID) {
return DecodeSelector(getGlobalSelectorID(M, LocalID));
}
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index a0caca9b26c..cfd4c38888d 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -1044,6 +1044,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(IDENTIFIER_OFFSET);
RECORD(IDENTIFIER_TABLE);
RECORD(EAGERLY_DESERIALIZED_DECLS);
+ RECORD(MODULAR_CODEGEN_DECLS);
RECORD(SPECIAL_TYPES);
RECORD(STATISTICS);
RECORD(TENTATIVE_DEFINITIONS);
@@ -2589,6 +2590,7 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferExplicit...
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferExportWild...
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ConfigMacrosExh...
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // WithCodegen
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
unsigned DefinitionAbbrev = Stream.EmitAbbrev(std::move(Abbrev));
@@ -2677,11 +2679,18 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
// Emit the definition of the block.
{
- RecordData::value_type Record[] = {
- SUBMODULE_DEFINITION, ID, ParentID, Mod->IsFramework, Mod->IsExplicit,
- Mod->IsSystem, Mod->IsExternC, Mod->InferSubmodules,
- Mod->InferExplicitSubmodules, Mod->InferExportWildcard,
- Mod->ConfigMacrosExhaustive};
+ RecordData::value_type Record[] = {SUBMODULE_DEFINITION,
+ ID,
+ ParentID,
+ Mod->IsFramework,
+ Mod->IsExplicit,
+ Mod->IsSystem,
+ Mod->IsExternC,
+ Mod->InferSubmodules,
+ Mod->InferExplicitSubmodules,
+ Mod->InferExportWildcard,
+ Mod->ConfigMacrosExhaustive,
+ Mod->WithCodegen};
Stream.EmitRecordWithBlob(DefinitionAbbrev, Record, Mod->Name);
}
@@ -4694,6 +4703,9 @@ uint64_t ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
if (!EagerlyDeserializedDecls.empty())
Stream.EmitRecord(EAGERLY_DESERIALIZED_DECLS, EagerlyDeserializedDecls);
+ if (Context.getLangOpts().ModularCodegen)
+ Stream.EmitRecord(MODULAR_CODEGEN_DECLS, ModularCodegenDecls);
+
// Write the record containing tentative definitions.
if (!TentativeDefinitions.empty())
Stream.EmitRecord(TENTATIVE_DEFINITIONS, TentativeDefinitions);
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index 292861755ba..6629036809f 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -2153,7 +2153,7 @@ void ASTWriter::WriteDeclAbbrevs() {
/// relatively painless since they would presumably only do it for top-level
/// decls.
static bool isRequiredDecl(const Decl *D, ASTContext &Context,
- bool WritingModule) {
+ bool WritingModule, bool ModularCode) {
// An ObjCMethodDecl is never considered as "required" because its
// implementation container always is.
@@ -2169,7 +2169,7 @@ static bool isRequiredDecl(const Decl *D, ASTContext &Context,
return false;
}
- return Context.DeclMustBeEmitted(D);
+ return Context.DeclMustBeEmitted(D, ModularCode);
}
void ASTWriter::WriteDecl(ASTContext &Context, Decl *D) {
@@ -2213,8 +2213,11 @@ void ASTWriter::WriteDecl(ASTContext &Context, Decl *D) {
// Note declarations that should be deserialized eagerly so that we can add
// them to a record in the AST file later.
- if (isRequiredDecl(D, Context, WritingModule))
+ if (isRequiredDecl(D, Context, WritingModule, false))
EagerlyDeserializedDecls.push_back(ID);
+ else if (Context.getLangOpts().ModularCodegen && WritingModule &&
+ isRequiredDecl(D, Context, true, true))
+ ModularCodegenDecls.push_back(ID);
}
void ASTRecordWriter::AddFunctionDefinition(const FunctionDecl *FD) {
diff --git a/clang/test/Modules/Inputs/codegen/bar.h b/clang/test/Modules/Inputs/codegen/bar.h
new file mode 100644
index 00000000000..a00e8f70e08
--- /dev/null
+++ b/clang/test/Modules/Inputs/codegen/bar.h
@@ -0,0 +1,2 @@
+#include "foo.h"
+inline void bar() { foo(); }
diff --git a/clang/test/Modules/Inputs/codegen/bar.modulemap b/clang/test/Modules/Inputs/codegen/bar.modulemap
new file mode 100644
index 00000000000..f1dc625857e
--- /dev/null
+++ b/clang/test/Modules/Inputs/codegen/bar.modulemap
@@ -0,0 +1 @@
+module bar { header "bar.h" }
diff --git a/clang/test/Modules/Inputs/codegen/foo.h b/clang/test/Modules/Inputs/codegen/foo.h
new file mode 100644
index 00000000000..b3a7af7c9d9
--- /dev/null
+++ b/clang/test/Modules/Inputs/codegen/foo.h
@@ -0,0 +1,10 @@
+void f1(int &);
+static void f2() {}
+inline void foo() {
+ static int i;
+ f1(i);
+ f2();
+}
+inline void foo2() {
+}
+void foo_ext() {}
diff --git a/clang/test/Modules/Inputs/codegen/foo.modulemap b/clang/test/Modules/Inputs/codegen/foo.modulemap
new file mode 100644
index 00000000000..2e095d2794c
--- /dev/null
+++ b/clang/test/Modules/Inputs/codegen/foo.modulemap
@@ -0,0 +1 @@
+module foo { header "foo.h" }
diff --git a/clang/test/Modules/Inputs/codegen/use.cpp b/clang/test/Modules/Inputs/codegen/use.cpp
new file mode 100644
index 00000000000..b55a31fe158
--- /dev/null
+++ b/clang/test/Modules/Inputs/codegen/use.cpp
@@ -0,0 +1,2 @@
+#include "bar.h"
+int main() { bar(); }
diff --git a/clang/test/Modules/codegen.test b/clang/test/Modules/codegen.test
new file mode 100644
index 00000000000..538dfd87aea
--- /dev/null
+++ b/clang/test/Modules/codegen.test
@@ -0,0 +1,64 @@
+RUN: rm -rf %t
+
+RUN: %clang_cc1 -fmodules-codegen -x c++ -fmodules -emit-module -fmodule-name=foo %S/Inputs/codegen/foo.modulemap -o %t/foo.pcm
+RUN: %clang_cc1 -fmodules-codegen -x c++ -fmodules -emit-module -fmodule-name=bar %S/Inputs/codegen/bar.modulemap -o %t/bar.pcm -fmodule-file=%t/foo.pcm
+
+RUN: %clang_cc1 -emit-llvm %t/foo.pcm -o - | FileCheck --check-prefix=FOO %s
+RUN: %clang_cc1 -emit-llvm %t/bar.pcm -o - -fmodule-file=%t/foo.pcm | FileCheck --check-prefix=BAR-CMN --check-prefix=BAR %s
+RUN: %clang_cc1 -fmodules -fmodule-file=%t/foo.pcm -fmodule-file=%t/bar.pcm %S/Inputs/codegen/use.cpp -emit-llvm -o - | FileCheck --check-prefix=USE-CMN --check-prefix=USE %s
+
+RUN: %clang_cc1 -O2 -disable-llvm-passes -emit-llvm %t/foo.pcm -o - | FileCheck --check-prefix=FOO %s
+RUN: %clang_cc1 -O2 -disable-llvm-passes -emit-llvm %t/bar.pcm -o - -fmodule-file=%t/foo.pcm | FileCheck --check-prefix=BAR-CMN --check-prefix=BAR-OPT %s
+RUN: %clang_cc1 -O2 -disable-llvm-passes -fmodules -fmodule-file=%t/foo.pcm -fmodule-file=%t/bar.pcm %S/Inputs/codegen/use.cpp -emit-llvm -o - | FileCheck --check-prefix=USE-CMN --check-prefix=USE-OPT %s
+
+FOO-NOT: comdat
+FOO: $_Z3foov = comdat any
+FOO: $_Z4foo2v = comdat any
+FOO: $_ZZ3foovE1i = comdat any
+FOO: @_ZZ3foovE1i = linkonce_odr global i32 0, comdat
+FOO-NOT: {{comdat|define|declare}}
+FOO: define void @_Z7foo_extv()
+FOO-NOT: {{define|declare}}
+FOO: define weak_odr void @_Z3foov() #{{[0-9]+}} comdat
+FOO-NOT: {{define|declare}}
+FOO: declare void @_Z2f1Ri(i32*
+FOO-NOT: {{define|declare}}
+
+FIXME: this internal function should be weak_odr, comdat, and with a new mangling
+FOO: define internal void @_ZL2f2v() #{{[0-9]+}}
+FOO-NOT: {{define|declare}}
+
+FOO: define weak_odr void @_Z4foo2v() #{{[0-9]+}} comdat
+FOO-NOT: {{define|declare}}
+
+
+BAR-CMN-NOT: comdat
+BAR-CMN: $_Z3barv = comdat any
+BAR-OPT: @_ZZ3foovE1i = linkonce_odr global i32 0, comdat
+BAR-CMN-NOT: {{comdat|define|declare}}
+BAR-CMN: define weak_odr void @_Z3barv() #{{[0-9]+}} comdat
+BAR-CMN-NOT: {{define|declare}}
+BAR: declare void @_Z3foov()
+Include all the available_externally definitions required for bar (foo -> f2)
+BAR-OPT: define available_externally void @_Z3foov()
+BAR-CMN-NOT: {{define|declare}}
+BAR-OPT: declare void @_Z2f1Ri(i32*
+BAR-OPT-NOT: {{define|declare}}
+BAR-OPT: define available_externally void @_ZL2f2v()
+BAR-OPT-NOT: {{define|declare}}
+
+
+USE-OPT: @_ZZ3foovE1i = linkonce_odr global i32 0, comdat
+USE-CMN-NOT: {{comdat|define|declare}}
+USE-CMN: define i32 @main()
+USE-CMN-NOT: {{define|declare}}
+USE: declare void @_Z3barv()
+Include all the available_externally definitions required for main (bar -> foo -> f2)
+USE-OPT: define available_externally void @_Z3barv()
+USE-CMN-NOT: {{define|declare}}
+USE-OPT: define available_externally void @_Z3foov()
+USE-OPT-NOT: {{define|declare}}
+USE-OPT: declare void @_Z2f1Ri(i32*
+USE-OPT-NOT: {{define|declare}}
+USE-OPT: define available_externally void @_ZL2f2v()
+USE-OPT-NOT: {{define|declare}}
OpenPOWER on IntegriCloud