diff options
author | Eli Bendersky <eliben@chromium.org> | 2013-07-15 16:08:08 -0700 |
---|---|---|
committer | Eli Bendersky <eliben@chromium.org> | 2013-07-15 16:08:08 -0700 |
commit | e789858899a7b36caf11b371a97411a1582a482b (patch) | |
tree | e8c28b178b32010f73b477b3c65b5ff74437530c /lib/Lex/ModuleMap.cpp | |
parent | 99a5501f5ae5b75017dfc386d4abf648234e85df (diff) | |
parent | 20c7d45a4da9f58ad805ad1d37f92fe7dc232ec8 (diff) |
Merge commit '20c7d45a4da9f58ad805ad1d37f92fe7dc232ec8'
Conflicts:
lib/CodeGen/ItaniumCXXABI.cpp
Diffstat (limited to 'lib/Lex/ModuleMap.cpp')
-rw-r--r-- | lib/Lex/ModuleMap.cpp | 274 |
1 files changed, 227 insertions, 47 deletions
diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp index 81cb94de51..3e7a44c0e3 100644 --- a/lib/Lex/ModuleMap.cpp +++ b/lib/Lex/ModuleMap.cpp @@ -18,6 +18,7 @@ #include "clang/Basic/FileManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/TargetOptions.h" +#include "clang/Lex/HeaderSearch.h" #include "clang/Lex/LexDiagnostic.h" #include "clang/Lex/Lexer.h" #include "clang/Lex/LiteralSupport.h" @@ -44,45 +45,55 @@ ModuleMap::resolveExport(Module *Mod, return Module::ExportDecl(0, true); } + // Resolve the module-id. + Module *Context = resolveModuleId(Unresolved.Id, Mod, Complain); + if (!Context) + return Module::ExportDecl(); + + return Module::ExportDecl(Context, Unresolved.Wildcard); +} + +Module *ModuleMap::resolveModuleId(const ModuleId &Id, Module *Mod, + bool Complain) const { // Find the starting module. - Module *Context = lookupModuleUnqualified(Unresolved.Id[0].first, Mod); + Module *Context = lookupModuleUnqualified(Id[0].first, Mod); if (!Context) { if (Complain) - Diags->Report(Unresolved.Id[0].second, - diag::err_mmap_missing_module_unqualified) - << Unresolved.Id[0].first << Mod->getFullModuleName(); - - return Module::ExportDecl(); + Diags->Report(Id[0].second, diag::err_mmap_missing_module_unqualified) + << Id[0].first << Mod->getFullModuleName(); + + return 0; } // Dig into the module path. - for (unsigned I = 1, N = Unresolved.Id.size(); I != N; ++I) { - Module *Sub = lookupModuleQualified(Unresolved.Id[I].first, - Context); + for (unsigned I = 1, N = Id.size(); I != N; ++I) { + Module *Sub = lookupModuleQualified(Id[I].first, Context); if (!Sub) { if (Complain) - Diags->Report(Unresolved.Id[I].second, - diag::err_mmap_missing_module_qualified) - << Unresolved.Id[I].first << Context->getFullModuleName() - << SourceRange(Unresolved.Id[0].second, Unresolved.Id[I-1].second); - - return Module::ExportDecl(); + Diags->Report(Id[I].second, diag::err_mmap_missing_module_qualified) + << Id[I].first << Context->getFullModuleName() + << SourceRange(Id[0].second, Id[I-1].second); + + return 0; } - + Context = Sub; } - - return Module::ExportDecl(Context, Unresolved.Wildcard); + + return Context; } -ModuleMap::ModuleMap(FileManager &FileMgr, const DiagnosticConsumer &DC, - const LangOptions &LangOpts, const TargetInfo *Target) - : LangOpts(LangOpts), Target(Target), BuiltinIncludeDir(0) +ModuleMap::ModuleMap(FileManager &FileMgr, DiagnosticConsumer &DC, + const LangOptions &LangOpts, const TargetInfo *Target, + HeaderSearch &HeaderInfo) + : LangOpts(LangOpts), Target(Target), HeaderInfo(HeaderInfo), + BuiltinIncludeDir(0) { IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(new DiagnosticIDs); Diags = IntrusiveRefCntPtr<DiagnosticsEngine>( new DiagnosticsEngine(DiagIDs, new DiagnosticOptions)); - Diags->setClient(DC.clone(*Diags), /*ShouldOwnClient=*/true); + Diags->setClient(new ForwardingDiagnosticConsumer(DC), + /*ShouldOwnClient=*/true); SourceMgr = new SourceManager(*Diags, FileMgr); } @@ -139,6 +150,24 @@ static StringRef sanitizeFilenameAsIdentifier(StringRef Name, return Name; } +/// \brief Determine whether the given file name is the name of a builtin +/// header, supplied by Clang to replace, override, or augment existing system +/// headers. +static bool isBuiltinHeader(StringRef FileName) { + return llvm::StringSwitch<bool>(FileName) + .Case("float.h", true) + .Case("iso646.h", true) + .Case("limits.h", true) + .Case("stdalign.h", true) + .Case("stdarg.h", true) + .Case("stdbool.h", true) + .Case("stddef.h", true) + .Case("stdint.h", true) + .Case("tgmath.h", true) + .Case("unwind.h", true) + .Default(false); +} + Module *ModuleMap::findModuleForHeader(const FileEntry *File) { HeadersMap::iterator Known = Headers.find(File); if (Known != Headers.end()) { @@ -148,6 +177,25 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) { return Known->second.getModule(); } + + // If we've found a builtin header within Clang's builtin include directory, + // load all of the module maps to see if it will get associated with a + // specific module (e.g., in /usr/include). + if (File->getDir() == BuiltinIncludeDir && + isBuiltinHeader(llvm::sys::path::filename(File->getName()))) { + SmallVector<Module *, 4> AllModules; + HeaderInfo.collectAllModules(AllModules); + + // Check again. + Known = Headers.find(File); + if (Known != Headers.end()) { + // If a header is not available, don't report that it maps to anything. + if (!Known->second.isAvailable()) + return 0; + + return Known->second.getModule(); + } + } const DirectoryEntry *Dir = File->getDir(); SmallVector<const DirectoryEntry *, 2> SkippedDirs; @@ -202,7 +250,7 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) { llvm::sys::path::stem(File->getName()), NameBuf); Result = findOrCreateModule(Name, Result, /*IsFramework=*/false, Explicit).first; - Result->TopHeaders.insert(File); + Result->addTopHeader(File); // If inferred submodules export everything they import, add a // wildcard to the set of exports. @@ -553,10 +601,12 @@ void ModuleMap::setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir) { void ModuleMap::addHeader(Module *Mod, const FileEntry *Header, bool Excluded) { - if (Excluded) + if (Excluded) { Mod->ExcludedHeaders.push_back(Header); - else + } else { Mod->Headers.push_back(Header); + HeaderInfo.MarkFileModuleHeader(Header); + } Headers[Header] = KnownHeader(Mod, Excluded); } @@ -598,6 +648,25 @@ bool ModuleMap::resolveExports(Module *Mod, bool Complain) { return HadError; } +bool ModuleMap::resolveConflicts(Module *Mod, bool Complain) { + bool HadError = false; + for (unsigned I = 0, N = Mod->UnresolvedConflicts.size(); I != N; ++I) { + Module *OtherMod = resolveModuleId(Mod->UnresolvedConflicts[I].Id, + Mod, Complain); + if (!OtherMod) { + HadError = true; + continue; + } + + Module::Conflict Conflict; + Conflict.Other = OtherMod; + Conflict.Message = Mod->UnresolvedConflicts[I].Message; + Mod->Conflicts.push_back(Conflict); + } + Mod->UnresolvedConflicts.clear(); + return HadError; +} + Module *ModuleMap::inferModuleFromLocation(FullSourceLoc Loc) { if (Loc.isInvalid()) return 0; @@ -638,6 +707,8 @@ namespace clang { struct MMToken { enum TokenKind { Comma, + ConfigMacros, + Conflict, EndOfFile, HeaderKeyword, Identifier, @@ -682,10 +753,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; }; @@ -734,6 +808,8 @@ namespace clang { void parseUmbrellaDirDecl(SourceLocation UmbrellaLoc); void parseExportDecl(); void parseLinkDecl(); + void parseConfigMacros(); + void parseConflict(); void parseInferredModuleDecl(bool Framework, bool Explicit); bool parseOptionalAttributes(Attributes &Attrs); @@ -771,11 +847,13 @@ 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("conflict", MMToken::Conflict) .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) @@ -932,7 +1010,9 @@ namespace { /// \brief An unknown attribute. AT_unknown, /// \brief The 'system' attribute. - AT_system + AT_system, + /// \brief The 'exhaustive' attribute. + AT_exhaustive }; } @@ -1089,7 +1169,15 @@ void ModuleMapParser::parseModuleDecl() { case MMToken::RBrace: Done = true; break; - + + case MMToken::ConfigMacros: + parseConfigMacros(); + break; + + case MMToken::Conflict: + parseConflict(); + break; + case MMToken::ExplicitKeyword: case MMToken::FrameworkKeyword: case MMToken::ModuleKeyword: @@ -1216,24 +1304,6 @@ static void appendSubframeworkPaths(Module *Mod, } } -/// \brief Determine whether the given file name is the name of a builtin -/// header, supplied by Clang to replace, override, or augment existing system -/// headers. -static bool isBuiltinHeader(StringRef FileName) { - return llvm::StringSwitch<bool>(FileName) - .Case("float.h", true) - .Case("iso646.h", true) - .Case("limits.h", true) - .Case("stdalign.h", true) - .Case("stdarg.h", true) - .Case("stdbool.h", true) - .Case("stddef.h", true) - .Case("stdint.h", true) - .Case("tgmath.h", true) - .Case("unwind.h", true) - .Default(false); -} - /// \brief Parse a header declaration. /// /// header-declaration: @@ -1484,6 +1554,109 @@ 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 Format a module-id into a string. +static std::string formatModuleId(const ModuleId &Id) { + std::string result; + { + llvm::raw_string_ostream OS(result); + + for (unsigned I = 0, N = Id.size(); I != N; ++I) { + if (I) + OS << "."; + OS << Id[I].first; + } + } + + return result; +} + +/// \brief Parse a conflict declaration. +/// +/// module-declaration: +/// 'conflict' module-id ',' string-literal +void ModuleMapParser::parseConflict() { + assert(Tok.is(MMToken::Conflict)); + SourceLocation ConflictLoc = consumeToken(); + Module::UnresolvedConflict Conflict; + + // Parse the module-id. + if (parseModuleId(Conflict.Id)) + return; + + // Parse the ','. + if (!Tok.is(MMToken::Comma)) { + Diags.Report(Tok.getLocation(), diag::err_mmap_expected_conflicts_comma) + << SourceRange(ConflictLoc); + return; + } + consumeToken(); + + // Parse the message. + if (!Tok.is(MMToken::StringLiteral)) { + Diags.Report(Tok.getLocation(), diag::err_mmap_expected_conflicts_message) + << formatModuleId(Conflict.Id); + return; + } + Conflict.Message = Tok.getString().str(); + consumeToken(); + + // Add this unresolved conflict. + ActiveModule->UnresolvedConflicts.push_back(Conflict); +} + /// \brief Parse an inferred module declaration (wildcard modules). /// /// module-declaration: @@ -1663,6 +1836,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) { @@ -1674,6 +1848,10 @@ bool ModuleMapParser::parseOptionalAttributes(Attributes &Attrs) { case AT_system: Attrs.IsSystem = true; break; + + case AT_exhaustive: + Attrs.IsExhaustive = true; + break; } consumeToken(); @@ -1725,6 +1903,8 @@ bool ModuleMapParser::parseModuleMapFile() { break; case MMToken::Comma: + case MMToken::ConfigMacros: + case MMToken::Conflict: case MMToken::ExcludeKeyword: case MMToken::ExportKeyword: case MMToken::HeaderKeyword: |