summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Basic/Module.cpp14
-rw-r--r--clang/lib/Frontend/CompilerInstance.cpp99
-rw-r--r--clang/lib/Lex/ModuleMap.cpp79
-rw-r--r--clang/lib/Serialization/ASTReader.cpp12
-rw-r--r--clang/lib/Serialization/ASTWriter.cpp15
5 files changed, 213 insertions, 6 deletions
diff --git a/clang/lib/Basic/Module.cpp b/clang/lib/Basic/Module.cpp
index f074391098b..019d04732b1 100644
--- a/clang/lib/Basic/Module.cpp
+++ b/clang/lib/Basic/Module.cpp
@@ -279,7 +279,19 @@ void Module::print(raw_ostream &OS, unsigned Indent) const {
OS.write_escaped(UmbrellaDir->getName());
OS << "\"\n";
}
-
+
+ if (!ConfigMacros.empty() || ConfigMacrosExhaustive) {
+ OS.indent(Indent + 2);
+ OS << "config_macros ";
+ if (ConfigMacrosExhaustive)
+ OS << "[exhausive]";
+ for (unsigned I = 0, N = ConfigMacros.size(); I != N; ++I) {
+ if (I)
+ OS << ", ";
+ OS << ConfigMacros[I];
+ }
+ }
+
for (unsigned I = 0, N = Headers.size(); I != N; ++I) {
OS.indent(Indent + 2);
OS << "header \"";
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index d5c1a27ec82..a20e7d7ed08 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -905,6 +905,96 @@ static void compileModule(CompilerInstance &ImportingInstance,
}
}
+/// \brief Diagnose differences between the current definition of the given
+/// configuration macro and the definition provided on the command line.
+static void checkConfigMacro(Preprocessor &PP, StringRef ConfigMacro,
+ Module *Mod, SourceLocation ImportLoc) {
+ IdentifierInfo *Id = PP.getIdentifierInfo(ConfigMacro);
+ SourceManager &SourceMgr = PP.getSourceManager();
+
+ // If this identifier has never had a macro definition, then it could
+ // not have changed.
+ if (!Id->hadMacroDefinition())
+ return;
+
+ // If this identifier does not currently have a macro definition,
+ // check whether it had one on the command line.
+ if (!Id->hasMacroDefinition()) {
+ MacroDirective *UndefMD = PP.getMacroDirectiveHistory(Id);
+ for (MacroDirective *MD = UndefMD; MD; MD = MD->getPrevious()) {
+
+ FileID FID = SourceMgr.getFileID(MD->getLocation());
+ if (FID.isInvalid())
+ continue;
+
+ const llvm::MemoryBuffer *Buffer = SourceMgr.getBuffer(FID);
+ if (!Buffer)
+ continue;
+
+ // We only care about the predefines buffer.
+ if (!StringRef(Buffer->getBufferIdentifier()).equals("<built-in>"))
+ continue;
+
+ // This macro was defined on the command line, then #undef'd later.
+ // Complain.
+ PP.Diag(ImportLoc, diag::warn_module_config_macro_undef)
+ << true << ConfigMacro << Mod->getFullModuleName();
+ if (UndefMD->getUndefLoc().isValid())
+ PP.Diag(UndefMD->getUndefLoc(), diag::note_module_def_undef_here)
+ << true;
+ return;
+ }
+
+ // Okay: no definition in the predefines buffer.
+ return;
+ }
+
+ // This identifier has a macro definition. Check whether we had a definition
+ // on the command line.
+ MacroDirective *DefMD = PP.getMacroDirective(Id);
+ MacroDirective *PredefinedMD = 0;
+ for (MacroDirective *MD = DefMD; MD; MD = MD->getPrevious()) {
+ FileID FID = SourceMgr.getFileID(MD->getLocation());
+ if (FID.isInvalid())
+ continue;
+
+ const llvm::MemoryBuffer *Buffer = SourceMgr.getBuffer(FID);
+ if (!Buffer)
+ continue;
+
+ // We only care about the predefines buffer.
+ if (!StringRef(Buffer->getBufferIdentifier()).equals("<built-in>"))
+ continue;
+
+ PredefinedMD = MD;
+ break;
+ }
+
+ // If there was no definition for this macro in the predefines buffer,
+ // complain.
+ if (!PredefinedMD ||
+ (!PredefinedMD->getLocation().isValid() &&
+ PredefinedMD->getUndefLoc().isValid())) {
+ PP.Diag(ImportLoc, diag::warn_module_config_macro_undef)
+ << false << ConfigMacro << Mod->getFullModuleName();
+ PP.Diag(DefMD->getLocation(), diag::note_module_def_undef_here)
+ << false;
+ return;
+ }
+
+ // If the current macro definition is the same as the predefined macro
+ // definition, it's okay.
+ if (DefMD == PredefinedMD ||
+ DefMD->getInfo()->isIdenticalTo(*PredefinedMD->getInfo(), PP))
+ return;
+
+ // The macro definitions differ.
+ PP.Diag(ImportLoc, diag::warn_module_config_macro_undef)
+ << false << ConfigMacro << Mod->getFullModuleName();
+ PP.Diag(DefMD->getLocation(), diag::note_module_def_undef_here)
+ << false;
+}
+
ModuleLoadResult
CompilerInstance::loadModule(SourceLocation ImportLoc,
ModuleIdPath Path,
@@ -1177,7 +1267,14 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
ModuleManager->makeModuleVisible(Module, Visibility, ImportLoc);
}
-
+
+ // Check for any configuration macros that have changed.
+ clang::Module *TopModule = Module->getTopLevelModule();
+ for (unsigned I = 0, N = TopModule->ConfigMacros.size(); I != N; ++I) {
+ checkConfigMacro(getPreprocessor(), TopModule->ConfigMacros[I],
+ Module, ImportLoc);
+ }
+
// If this module import was due to an inclusion directive, create an
// implicit import declaration to capture it in the AST.
if (IsInclusionDirective && hasASTContext()) {
diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp
index 71a98e2152a..9cea5aace72 100644
--- a/clang/lib/Lex/ModuleMap.cpp
+++ b/clang/lib/Lex/ModuleMap.cpp
@@ -643,6 +643,7 @@ namespace clang {
struct MMToken {
enum TokenKind {
Comma,
+ ConfigMacros,
EndOfFile,
HeaderKeyword,
Identifier,
@@ -687,10 +688,13 @@ namespace clang {
/// \brief The set of attributes that can be attached to a module.
struct Attributes {
- Attributes() : IsSystem() { }
+ Attributes() : IsSystem(), IsExhaustive() { }
/// \brief Whether this is a system module.
unsigned IsSystem : 1;
+
+ /// \brief Whether this is an exhaustive set of configuration macros.
+ unsigned IsExhaustive : 1;
};
@@ -739,6 +743,7 @@ namespace clang {
void parseUmbrellaDirDecl(SourceLocation UmbrellaLoc);
void parseExportDecl();
void parseLinkDecl();
+ void parseConfigMacros();
void parseInferredModuleDecl(bool Framework, bool Explicit);
bool parseOptionalAttributes(Attributes &Attrs);
@@ -776,11 +781,12 @@ retry:
Tok.StringData = LToken.getRawIdentifierData();
Tok.StringLength = LToken.getLength();
Tok.Kind = llvm::StringSwitch<MMToken::TokenKind>(Tok.getString())
- .Case("header", MMToken::HeaderKeyword)
+ .Case("config_macros", MMToken::ConfigMacros)
.Case("exclude", MMToken::ExcludeKeyword)
.Case("explicit", MMToken::ExplicitKeyword)
.Case("export", MMToken::ExportKeyword)
.Case("framework", MMToken::FrameworkKeyword)
+ .Case("header", MMToken::HeaderKeyword)
.Case("link", MMToken::LinkKeyword)
.Case("module", MMToken::ModuleKeyword)
.Case("requires", MMToken::RequiresKeyword)
@@ -937,7 +943,9 @@ namespace {
/// \brief An unknown attribute.
AT_unknown,
/// \brief The 'system' attribute.
- AT_system
+ AT_system,
+ /// \brief The 'exhaustive' attribute.
+ AT_exhaustive
};
}
@@ -1094,7 +1102,11 @@ void ModuleMapParser::parseModuleDecl() {
case MMToken::RBrace:
Done = true;
break;
-
+
+ case MMToken::ConfigMacros:
+ parseConfigMacros();
+ break;
+
case MMToken::ExplicitKeyword:
case MMToken::FrameworkKeyword:
case MMToken::ModuleKeyword:
@@ -1489,6 +1501,59 @@ void ModuleMapParser::parseLinkDecl() {
IsFramework));
}
+/// \brief Parse a configuration macro declaration.
+///
+/// module-declaration:
+/// 'config_macros' attributes[opt] config-macro-list?
+///
+/// config-macro-list:
+/// identifier (',' identifier)?
+void ModuleMapParser::parseConfigMacros() {
+ assert(Tok.is(MMToken::ConfigMacros));
+ SourceLocation ConfigMacrosLoc = consumeToken();
+
+ // Only top-level modules can have configuration macros.
+ if (ActiveModule->Parent) {
+ Diags.Report(ConfigMacrosLoc, diag::err_mmap_config_macro_submodule);
+ }
+
+ // Parse the optional attributes.
+ Attributes Attrs;
+ parseOptionalAttributes(Attrs);
+ if (Attrs.IsExhaustive && !ActiveModule->Parent) {
+ ActiveModule->ConfigMacrosExhaustive = true;
+ }
+
+ // If we don't have an identifier, we're done.
+ if (!Tok.is(MMToken::Identifier))
+ return;
+
+ // Consume the first identifier.
+ if (!ActiveModule->Parent) {
+ ActiveModule->ConfigMacros.push_back(Tok.getString().str());
+ }
+ consumeToken();
+
+ do {
+ // If there's a comma, consume it.
+ if (!Tok.is(MMToken::Comma))
+ break;
+ consumeToken();
+
+ // We expect to see a macro name here.
+ if (!Tok.is(MMToken::Identifier)) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_config_macro);
+ break;
+ }
+
+ // Consume the macro name.
+ if (!ActiveModule->Parent) {
+ ActiveModule->ConfigMacros.push_back(Tok.getString().str());
+ }
+ consumeToken();
+ } while (true);
+}
+
/// \brief Parse an inferred module declaration (wildcard modules).
///
/// module-declaration:
@@ -1668,6 +1733,7 @@ bool ModuleMapParser::parseOptionalAttributes(Attributes &Attrs) {
// Decode the attribute name.
AttributeKind Attribute
= llvm::StringSwitch<AttributeKind>(Tok.getString())
+ .Case("exhaustive", AT_exhaustive)
.Case("system", AT_system)
.Default(AT_unknown);
switch (Attribute) {
@@ -1679,6 +1745,10 @@ bool ModuleMapParser::parseOptionalAttributes(Attributes &Attrs) {
case AT_system:
Attrs.IsSystem = true;
break;
+
+ case AT_exhaustive:
+ Attrs.IsExhaustive = true;
+ break;
}
consumeToken();
@@ -1730,6 +1800,7 @@ bool ModuleMapParser::parseModuleMapFile() {
break;
case MMToken::Comma:
+ case MMToken::ConfigMacros:
case MMToken::ExcludeKeyword:
case MMToken::ExportKeyword:
case MMToken::HeaderKeyword:
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 42b5038ae94..00e5ce910b9 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -3718,6 +3718,18 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
CurrentModule->LinkLibraries.push_back(
Module::LinkLibrary(Blob, Record[0]));
break;
+
+ case SUBMODULE_CONFIG_MACRO:
+ if (First) {
+ Error("missing submodule metadata record at beginning of block");
+ return true;
+ }
+
+ if (!CurrentModule)
+ break;
+
+ CurrentModule->ConfigMacros.push_back(Blob.str());
+ break;
}
}
}
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index 724c8cf8254..08e8afdd0ab 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -2135,6 +2135,7 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferSubmodules...
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::Blob)); // Name
unsigned DefinitionAbbrev = Stream.EmitAbbrev(Abbrev);
@@ -2174,6 +2175,11 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
unsigned LinkLibraryAbbrev = Stream.EmitAbbrev(Abbrev);
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_CONFIG_MACRO));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Macro name
+ unsigned ConfigMacroAbbrev = Stream.EmitAbbrev(Abbrev);
+
// Write the submodule metadata block.
RecordData Record;
Record.push_back(getNumberOfModules(WritingModule));
@@ -2204,6 +2210,7 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Record.push_back(Mod->InferSubmodules);
Record.push_back(Mod->InferExplicitSubmodules);
Record.push_back(Mod->InferExportWildcard);
+ Record.push_back(Mod->ConfigMacrosExhaustive);
Stream.EmitRecordWithBlob(DefinitionAbbrev, Record, Mod->Name);
// Emit the requirements.
@@ -2288,6 +2295,14 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Mod->LinkLibraries[I].Library);
}
+ // Emit the configuration macros.
+ for (unsigned I = 0, N = Mod->ConfigMacros.size(); I != N; ++I) {
+ Record.clear();
+ Record.push_back(SUBMODULE_CONFIG_MACRO);
+ Stream.EmitRecordWithBlob(ConfigMacroAbbrev, Record,
+ Mod->ConfigMacros[I]);
+ }
+
// Queue up the submodules of this module.
for (Module::submodule_iterator Sub = Mod->submodule_begin(),
SubEnd = Mod->submodule_end();
OpenPOWER on IntegriCloud