summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2013-03-20 00:22:05 +0000
committerDouglas Gregor <dgregor@apple.com>2013-03-20 00:22:05 +0000
commit35b13ece231bbd70cd5cfe7a3a1b931d74cef797 (patch)
tree93c842d670d3af218e85017d2b707a0aa2e39b04 /clang/lib
parentd068943809f09a96e6bb2885e40c5651c8b3447c (diff)
downloadbcm5719-llvm-35b13ece231bbd70cd5cfe7a3a1b931d74cef797.tar.gz
bcm5719-llvm-35b13ece231bbd70cd5cfe7a3a1b931d74cef797.zip
<rdar://problem/10796651> Introduce configuration macros into module maps.
Configuration macros are macros that are intended to alter how a module works, such that we need to build different module variants for different values of these macros. A module can declare its configuration macros, in which case we will complain if the definition of a configation macro on the command line (or lack thereof) differs from the current preprocessor state at the point where the module is imported. This should eliminate some surprises when enabling modules, because "#define CONFIG_MACRO ..." followed by "#include <module/header.h>" would silently ignore the CONFIG_MACRO setting. At least it will no longer be silent about it. Configuration macros are eventually intended to help reduce the number of module variants that need to be built. When the list of configuration macros for a module is exhaustive, we only need to consider the settings for those macros when building/finding the module, which can help isolate modules for various project-specific -D flags that should never affect how modules are build (but currently do). llvm-svn: 177466
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