From 35b13ece231bbd70cd5cfe7a3a1b931d74cef797 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Wed, 20 Mar 2013 00:22:05 +0000 Subject: 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 " 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 --- clang/lib/Lex/ModuleMap.cpp | 79 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 75 insertions(+), 4 deletions(-) (limited to 'clang/lib/Lex/ModuleMap.cpp') diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp index 71a98e2..9cea5aa 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(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(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: -- cgit v1.1