diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Basic/Module.cpp | 14 | ||||
-rw-r--r-- | clang/lib/Driver/Tools.cpp | 7 | ||||
-rw-r--r-- | clang/lib/Frontend/CompilerInvocation.cpp | 1 | ||||
-rw-r--r-- | clang/lib/Lex/HeaderSearch.cpp | 1 | ||||
-rw-r--r-- | clang/lib/Lex/ModuleMap.cpp | 64 | ||||
-rw-r--r-- | clang/lib/Lex/PPDirectives.cpp | 107 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.cpp | 1 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTReader.cpp | 4 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTWriter.cpp | 4 |
9 files changed, 179 insertions, 24 deletions
diff --git a/clang/lib/Basic/Module.cpp b/clang/lib/Basic/Module.cpp index 7ec5e68fc45..8c35b342ecb 100644 --- a/clang/lib/Basic/Module.cpp +++ b/clang/lib/Basic/Module.cpp @@ -362,6 +362,20 @@ void Module::print(raw_ostream &OS, unsigned Indent) const { OS << "\n"; } + for (unsigned I = 0, N = DirectUses.size(); I != N; ++I) { + OS.indent(Indent + 2); + OS << "use "; + OS << DirectUses[I]->getFullModuleName(); + OS << "\n"; + } + + for (unsigned I = 0, N = UnresolvedDirectUses.size(); I != N; ++I) { + OS.indent(Indent + 2); + OS << "use "; + printModuleId(OS, UnresolvedDirectUses[I]); + OS << "\n"; + } + for (unsigned I = 0, N = LinkLibraries.size(); I != N; ++I) { OS.indent(Indent + 2); OS << "link "; diff --git a/clang/lib/Driver/Tools.cpp b/clang/lib/Driver/Tools.cpp index 23f3648ddba..6a803cc17d1 100644 --- a/clang/lib/Driver/Tools.cpp +++ b/clang/lib/Driver/Tools.cpp @@ -3034,6 +3034,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fmodule-maps"); } + // -fmodule-decluse checks that modules used are declared so (off by default). + if (Args.hasFlag(options::OPT_fmodules_decluse, + options::OPT_fno_modules_decluse, + false)) { + CmdArgs.push_back("-fmodule-decluse"); + } + // If a module path was provided, pass it along. Otherwise, use a temporary // directory. if (Arg *A = Args.getLastArg(options::OPT_fmodules_cache_path)) { diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index b13507a5ef1..c8c676899c5 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1280,6 +1280,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.Blocks = Args.hasArg(OPT_fblocks); Opts.BlocksRuntimeOptional = Args.hasArg(OPT_fblocks_runtime_optional); Opts.Modules = Args.hasArg(OPT_fmodules); + Opts.ModulesDeclUse = Args.hasArg(OPT_fmodules_decluse); Opts.CharIsSigned = Opts.OpenCL || !Args.hasArg(OPT_fno_signed_char); Opts.WChar = Opts.CPlusPlus && !Args.hasArg(OPT_fno_wchar); Opts.ShortWChar = Args.hasArg(OPT_fshort_wchar); diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp index 631a7fd1dab..ec84bb16d60 100644 --- a/clang/lib/Lex/HeaderSearch.cpp +++ b/clang/lib/Lex/HeaderSearch.cpp @@ -22,6 +22,7 @@ #include "llvm/Support/Capacity.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" #include <cstdio> #if defined(LLVM_ON_UNIX) #include <limits.h> diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp index df80a93e4db..0f12af361a4 100644 --- a/clang/lib/Lex/ModuleMap.cpp +++ b/clang/lib/Lex/ModuleMap.cpp @@ -387,6 +387,10 @@ ModuleMap::findOrCreateModule(StringRef Name, Module *Parent, bool IsFramework, // Create a new module with this name. Module *Result = new Module(Name, SourceLocation(), Parent, IsFramework, IsExplicit); + if (LangOpts.CurrentModule == Name) { + SourceModule = Result; + SourceModuleName = Name; + } if (!Parent) { Modules[Name] = Result; if (!LangOpts.CurrentModule.empty() && !CompilingModule && @@ -518,6 +522,10 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName, Module *Result = new Module(ModuleName, SourceLocation(), Parent, /*IsFramework=*/true, /*IsExplicit=*/false); + if (LangOpts.CurrentModule == ModuleName) { + SourceModule = Result; + SourceModuleName = ModuleName; + } if (IsSystem) Result->IsSystem = IsSystem; @@ -653,6 +661,20 @@ bool ModuleMap::resolveExports(Module *Mod, bool Complain) { return HadError; } +bool ModuleMap::resolveUses(Module *Mod, bool Complain) { + bool HadError = false; + for (unsigned I = 0, N = Mod->UnresolvedDirectUses.size(); I != N; ++I) { + Module *DirectUse = + resolveModuleId(Mod->UnresolvedDirectUses[I], Mod, Complain); + if (DirectUse) + Mod->DirectUses.push_back(DirectUse); + else + HadError = true; + } + Mod->UnresolvedDirectUses.clear(); + return HadError; +} + bool ModuleMap::resolveConflicts(Module *Mod, bool Complain) { bool HadError = false; for (unsigned I = 0, N = Mod->UnresolvedConflicts.size(); I != N; ++I) { @@ -727,6 +749,7 @@ namespace clang { Period, PrivateKeyword, UmbrellaKeyword, + UseKeyword, RequiresKeyword, Star, StringLiteral, @@ -819,6 +842,7 @@ namespace clang { SourceLocation LeadingLoc); void parseUmbrellaDirDecl(SourceLocation UmbrellaLoc); void parseExportDecl(); + void parseUseDecl(); void parseLinkDecl(); void parseConfigMacros(); void parseConflict(); @@ -873,6 +897,7 @@ retry: .Case("private", MMToken::PrivateKeyword) .Case("requires", MMToken::RequiresKeyword) .Case("umbrella", MMToken::UmbrellaKeyword) + .Case("use", MMToken::UseKeyword) .Default(MMToken::Identifier); break; @@ -1209,6 +1234,10 @@ void ModuleMapParser::parseModuleDecl() { case MMToken::ExportKeyword: parseExportDecl(); break; + + case MMToken::UseKeyword: + parseUseDecl(); + break; case MMToken::RequiresKeyword: parseRequiresDecl(); @@ -1593,7 +1622,7 @@ void ModuleMapParser::parseExportDecl() { break; } - Diags.Report(Tok.getLocation(), diag::err_mmap_export_module_id); + Diags.Report(Tok.getLocation(), diag::err_mmap_module_id); HadError = true; return; } while (true); @@ -1604,6 +1633,38 @@ void ModuleMapParser::parseExportDecl() { ActiveModule->UnresolvedExports.push_back(Unresolved); } +/// \brief Parse a module uses declaration. +/// +/// uses-declaration: +/// 'uses' wildcard-module-id +void ModuleMapParser::parseUseDecl() { + assert(Tok.is(MMToken::UseKeyword)); + consumeToken(); + // Parse the module-id. + ModuleId ParsedModuleId; + + do { + if (Tok.is(MMToken::Identifier)) { + ParsedModuleId.push_back( + std::make_pair(Tok.getString(), Tok.getLocation())); + consumeToken(); + + if (Tok.is(MMToken::Period)) { + consumeToken(); + continue; + } + + break; + } + + Diags.Report(Tok.getLocation(), diag::err_mmap_module_id); + HadError = true; + return; + } while (true); + + ActiveModule->UnresolvedDirectUses.push_back(ParsedModuleId); +} + /// \brief Parse a link declaration. /// /// module-declaration: @@ -2001,6 +2062,7 @@ bool ModuleMapParser::parseModuleMapFile() { case MMToken::Star: case MMToken::StringLiteral: case MMToken::UmbrellaKeyword: + case MMToken::UseKeyword: Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module); HadError = true; consumeToken(); diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp index 86d6ad9eb86..75919925961 100644 --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/lib/Lex/PPDirectives.cpp @@ -532,6 +532,88 @@ void Preprocessor::PTHSkipExcludedConditionalBlock() { } } +Module *Preprocessor::getModuleForLocation(SourceLocation FilenameLoc) { + ModuleMap &ModMap = HeaderInfo.getModuleMap(); + if (SourceMgr.isInMainFile(FilenameLoc)) { + if (Module *CurMod = getCurrentModule()) + return CurMod; // Compiling a module. + return HeaderInfo.getModuleMap().SourceModule; // Compiling a source. + } + // Try to determine the module of the include directive. + FileID IDOfIncl = SourceMgr.getFileID(FilenameLoc); + if (const FileEntry *EntryOfIncl = SourceMgr.getFileEntryForID(IDOfIncl)) { + // The include comes from a file. + return ModMap.findModuleForHeader(EntryOfIncl).getModule(); + } else { + // The include does not come from a file, + // so it is probably a module compilation. + return getCurrentModule(); + } +} + +bool Preprocessor::violatesPrivateInclude( + Module *RequestingModule, + const FileEntry *IncFileEnt, + ModuleMap::ModuleHeaderRole Role, + Module *RequestedModule) { + #ifndef NDEBUG + // Check for consistency between the module header role + // as obtained from the lookup and as obtained from the module. + // This check is not cheap, so enable it only for debugging. + SmallVectorImpl<const FileEntry *> &PvtHdrs + = RequestedModule->PrivateHeaders; + SmallVectorImpl<const FileEntry *>::iterator Look + = std::find(PvtHdrs.begin(), PvtHdrs.end(), IncFileEnt); + bool IsPrivate = Look != PvtHdrs.end(); + assert((IsPrivate && Role == ModuleMap::PrivateHeader) + || (!IsPrivate && Role != ModuleMap::PrivateHeader)); + #endif + return Role == ModuleMap::PrivateHeader && + RequestedModule->getTopLevelModule() != RequestingModule; +} + +bool Preprocessor::violatesUseDeclarations( + Module *RequestingModule, + Module *RequestedModule) { + ModuleMap &ModMap = HeaderInfo.getModuleMap(); + ModMap.resolveUses(RequestingModule, /*Complain=*/false); + const SmallVectorImpl<Module *> &AllowedUses = RequestingModule->DirectUses; + SmallVectorImpl<Module *>::const_iterator Declared = + std::find(AllowedUses.begin(), AllowedUses.end(), RequestedModule); + return Declared == AllowedUses.end(); +} + +void Preprocessor::verifyModuleInclude( + SourceLocation FilenameLoc, + StringRef Filename, + const FileEntry *IncFileEnt, + ModuleMap::KnownHeader *SuggestedModule) { + Module *RequestingModule = getModuleForLocation(FilenameLoc); + Module *RequestedModule = SuggestedModule->getModule(); + if (!RequestedModule) + RequestedModule = HeaderInfo.findModuleForHeader(IncFileEnt).getModule(); + + if (RequestingModule == RequestedModule) + return; // No faults wihin a module, or between files both not in modules. + + if (RequestingModule != HeaderInfo.getModuleMap().SourceModule) + return; // No errors for indirect modules. + // This may be a bit of a problem for modules with no source files. + + if (RequestedModule && + violatesPrivateInclude(RequestingModule, IncFileEnt, + SuggestedModule->getRole(), RequestedModule)) + Diag(FilenameLoc, diag::error_use_of_private_header_outside_module) + << Filename; + + // FIXME: Add support for FixIts in module map files and offer adding the + // required use declaration. + if (RequestingModule && getLangOpts().ModulesDeclUse && + violatesUseDeclarations(RequestingModule, RequestedModule)) + Diag(FilenameLoc, diag::error_undeclared_use_of_module) + << Filename; +} + const FileEntry *Preprocessor::LookupFile( SourceLocation FilenameLoc, StringRef Filename, @@ -567,29 +649,8 @@ const FileEntry *Preprocessor::LookupFile( Filename, isAngled, FromDir, CurDir, CurFileEnt, SearchPath, RelativePath, SuggestedModule, SkipCache); if (FE) { - if (SuggestedModule) { - Module *RequestedModule = SuggestedModule->getModule(); - if (RequestedModule) { - ModuleMap::ModuleHeaderRole Role = SuggestedModule->getRole(); - #ifndef NDEBUG - // Check for consistency between the module header role - // as obtained from the lookup and as obtained from the module. - // This check is not cheap, so enable it only for debugging. - SmallVectorImpl<const FileEntry *> &PvtHdrs - = RequestedModule->PrivateHeaders; - SmallVectorImpl<const FileEntry *>::iterator Look - = std::find(PvtHdrs.begin(), PvtHdrs.end(), FE); - bool IsPrivate = Look != PvtHdrs.end(); - assert((IsPrivate && Role == ModuleMap::PrivateHeader) - || (!IsPrivate && Role != ModuleMap::PrivateHeader)); - #endif - if (Role == ModuleMap::PrivateHeader) { - if (RequestedModule->getTopLevelModule() != getCurrentModule()) - Diag(FilenameLoc, diag::error_use_of_private_header_outside_module) - << Filename; - } - } - } + if (SuggestedModule) + verifyModuleInclude(FilenameLoc, Filename, FE, SuggestedModule); return FE; } diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 72fdc528fd4..00f38bfa8c6 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -654,6 +654,7 @@ void Sema::ActOnEndOfTranslationUnit() { // diagnostic client to deal with complaints in the module map at this // point. ModMap.resolveExports(Mod, /*Complain=*/false); + ModMap.resolveUses(Mod, /*Complain=*/false); ModMap.resolveConflicts(Mod, /*Complain=*/false); // Queue the submodules, so their exports will also be resolved. diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 5b55390730d..9bb9a7a8632 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -3028,6 +3028,10 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName, } } UnresolvedModuleRefs.clear(); + + // FIXME: How do we load the 'use'd modules? They may not be submodules. + // Might be unnecessary as use declarations are only used to build the + // module itself. InitializeContext(); diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index a4879226f97..409c9a18a50 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -2421,6 +2421,10 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { Stream.EmitRecord(SUBMODULE_EXPORTS, Record); } + //FIXME: How do we emit the 'use'd modules? They may not be submodules. + // Might be unnecessary as use declarations are only used to build the + // module itself. + // Emit the link libraries. for (unsigned I = 0, N = Mod->LinkLibraries.size(); I != N; ++I) { Record.clear(); |