From ddd2dfc1d3f4a36cbe8cd775c588623a17049f9f Mon Sep 17 00:00:00 2001 From: Daniel Jasper Date: Tue, 24 Sep 2013 09:14:14 +0000 Subject: [PATCH] Module use declarations (II) Review: http://llvm-reviews.chandlerc.com/D1546. I have picked up this patch form Lawrence (http://llvm-reviews.chandlerc.com/D1063) and did a few changes. From the original change description (updated as appropriate): This patch adds a check that ensures that modules only use modules they have so declared. To this end, it adds a statement on intended module use to the module.map grammar: use module-id A module can then only use headers from other modules if it 'uses' them. This enforcement is off by default, but may be turned on with the new option -fmodules-decluse. When enforcing the module semantics, we also need to consider a source file part of a module. This is achieved with a compiler option -fmodule-name=. The compiler at present only applies restrictions to the module directly being built. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@191283 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/Modules.rst | 39 +++++++- include/clang/Basic/DiagnosticLexKinds.td | 8 +- include/clang/Basic/LangOptions.def | 1 + include/clang/Basic/Module.h | 6 ++ include/clang/Driver/Options.td | 5 + include/clang/Lex/ModuleMap.h | 16 +++ include/clang/Lex/Preprocessor.h | 25 +++++ lib/Basic/Module.cpp | 14 +++ lib/Driver/Tools.cpp | 7 ++ lib/Frontend/CompilerInvocation.cpp | 1 + lib/Lex/HeaderSearch.cpp | 1 + lib/Lex/ModuleMap.cpp | 64 +++++++++++- lib/Lex/PPDirectives.cpp | 107 ++++++++++++++++----- lib/Sema/Sema.cpp | 1 + lib/Serialization/ASTReader.cpp | 4 + lib/Serialization/ASTWriter.cpp | 4 + test/Modules/Inputs/declare-use/a.h | 4 + test/Modules/Inputs/declare-use/b.h | 4 + test/Modules/Inputs/declare-use/c.h | 6 ++ test/Modules/Inputs/declare-use/d.h | 6 ++ test/Modules/Inputs/declare-use/e.h | 6 ++ test/Modules/Inputs/declare-use/f.h | 6 ++ test/Modules/Inputs/declare-use/g.h | 6 ++ test/Modules/Inputs/declare-use/g1.h | 1 + test/Modules/Inputs/declare-use/h.h | 7 ++ test/Modules/Inputs/declare-use/h1.h | 1 + test/Modules/Inputs/declare-use/module.map | 43 +++++++++ test/Modules/declare-use1.cpp | 7 ++ test/Modules/declare-use2.cpp | 7 ++ 29 files changed, 379 insertions(+), 28 deletions(-) create mode 100644 test/Modules/Inputs/declare-use/a.h create mode 100644 test/Modules/Inputs/declare-use/b.h create mode 100644 test/Modules/Inputs/declare-use/c.h create mode 100644 test/Modules/Inputs/declare-use/d.h create mode 100644 test/Modules/Inputs/declare-use/e.h create mode 100644 test/Modules/Inputs/declare-use/f.h create mode 100644 test/Modules/Inputs/declare-use/g.h create mode 100644 test/Modules/Inputs/declare-use/g1.h create mode 100644 test/Modules/Inputs/declare-use/h.h create mode 100644 test/Modules/Inputs/declare-use/h1.h create mode 100644 test/Modules/Inputs/declare-use/module.map create mode 100644 test/Modules/declare-use1.cpp create mode 100644 test/Modules/declare-use2.cpp diff --git a/docs/Modules.rst b/docs/Modules.rst index 8c20301315..02393d7ba9 100644 --- a/docs/Modules.rst +++ b/docs/Modules.rst @@ -188,6 +188,12 @@ Command-line parameters ``-module-file-info `` Debugging aid that prints information about a given module file (with a ``.pcm`` extension), including the language and preprocessor options that particular module variant was built with. +``-fmodules-decluse`` + Enable checking of module ``use`` declarations. + +``-fmodule-name=module-id`` + Consider a source file as a part of the given module. + Module Map Language =================== @@ -238,7 +244,7 @@ Module map files use a simplified form of the C99 lexer, with the same rules for ``conflict`` ``framework`` ``requires`` ``exclude`` ``header`` ``private`` ``explicit`` ``link`` ``umbrella`` - ``extern`` + ``extern`` ``use`` Module map file --------------- @@ -293,6 +299,7 @@ Modules can have a number of different kinds of members, each of which is descri *umbrella-dir-declaration* *submodule-declaration* *export-declaration* + *use-declaration* *link-declaration* *config-macros-declaration* *conflict-declaration* @@ -533,6 +540,36 @@ Note that, if ``Derived.h`` includes ``Base.h``, one can simply use a wildcard e compatibility for programs that rely on transitive inclusion (i.e., all of them). +Use declaration +~~~~~~~~~~~~~~~ +A *use-declaration* specifies one of the other modules that the module is allowed to use. An import or include not matching one of these is rejected when the option *-fmodules-decluse*. + +.. parsed-literal:: + + *use-declaration*: + ``use`` *module-id* + +**Example**:: In the following example, use of A from C is not declared, so will trigger a warning. + +.. parsed-literal:: + + module A { + header "a.h" + } + + module B { + header "b.h" + } + + module C { + header "c.h" + use B + } + +When compiling a source file that implements a module, use the option ``-fmodule-name=``module-id to indicate that the source file is logically part of that module. + +The compiler at present only applies restrictions to the module directly being built. + Link declaration ~~~~~~~~~~~~~~~~ A *link-declaration* specifies a library or framework against which a program should be linked if the enclosing module is imported in any translation unit in that program. diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td index 3abbb8574f..9a40fe75a5 100644 --- a/include/clang/Basic/DiagnosticLexKinds.td +++ b/include/clang/Basic/DiagnosticLexKinds.td @@ -554,8 +554,8 @@ def err_mmap_umbrella_dir_not_found : Error< "umbrella directory '%0' not found">; def err_mmap_umbrella_clash : Error< "umbrella for module '%0' already covers this directory">; -def err_mmap_export_module_id : Error< - "expected an exported module name or '*'">; +def err_mmap_module_id : Error< + "expected a module name or '*'">; def err_mmap_expected_library_name : Error< "expected %select{library|framework}0 name as a string">; def err_mmap_config_macro_submodule : Error< @@ -610,7 +610,9 @@ def err_expected_id_building_module : Error< "expected a module name in '__building_module' expression">; def error_use_of_private_header_outside_module : Error< "use of private header from outside its module: '%0'">; - +def error_undeclared_use_of_module : Error< + "use of a module not declared used: '%0'">; + def warn_header_guard : Warning< "%0 is used as a header guard here, followed by #define of a different macro">, InGroup>; diff --git a/include/clang/Basic/LangOptions.def b/include/clang/Basic/LangOptions.def index 55db34ce30..f992a3e178 100644 --- a/include/clang/Basic/LangOptions.def +++ b/include/clang/Basic/LangOptions.def @@ -94,6 +94,7 @@ BENIGN_LANGOPT(EmitAllDecls , 1, 0, "support for emitting all declarations" LANGOPT(MathErrno , 1, 1, "errno support for math functions") BENIGN_LANGOPT(HeinousExtensions , 1, 0, "Extensions that we really don't like and may be ripped out at any time") LANGOPT(Modules , 1, 0, "modules extension to C") +LANGOPT(ModulesDeclUse , 1, 0, "require declaration of module uses") LANGOPT(Optimize , 1, 0, "__OPTIMIZE__ predefined macro") LANGOPT(OptimizeSize , 1, 0, "__OPTIMIZE_SIZE__ predefined macro") LANGOPT(Static , 1, 0, "__STATIC__ predefined macro (as opposed to __DYNAMIC__)") diff --git a/include/clang/Basic/Module.h b/include/clang/Basic/Module.h index 26466be7e4..e6913d8470 100644 --- a/include/clang/Basic/Module.h +++ b/include/clang/Basic/Module.h @@ -183,6 +183,12 @@ public: /// \brief The set of export declarations that have yet to be resolved. SmallVector UnresolvedExports; + /// \brief The directly used modules. + SmallVector DirectUses; + + /// \brief The set of use declarations that have yet to be resolved. + SmallVector UnresolvedDirectUses; + /// \brief A library or framework to link against when an entity from this /// module is used. struct LinkLibrary { diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index 81221f87db..529d03c422 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -561,6 +561,9 @@ def fmodule_maps : Flag <["-"], "fmodule-maps">, Group, HelpText<"Read module maps to understand the structure of library headers">; def fmodules_ignore_macro : Joined<["-"], "fmodules-ignore-macro=">, Group, Flags<[CC1Option]>, HelpText<"Ignore the definition of the given macro when building and loading modules">; +def fmodules_decluse : Flag <["-"], "fmodules-decluse">, Group, + Flags<[DriverOption,CC1Option]>, + HelpText<"Require declaration of modules used within a module">; def fretain_comments_from_system_headers : Flag<["-"], "fretain-comments-from-system-headers">, Group, Flags<[CC1Option]>; def fmudflapth : Flag<["-"], "fmudflapth">, Group; @@ -621,6 +624,8 @@ def fno_modules : Flag <["-"], "fno-modules">, Group, Flags<[DriverOption]>; def fno_module_maps : Flag <["-"], "fno-module-maps">, Group, Flags<[DriverOption]>; +def fno_modules_decluse : Flag <["-"], "fno-modules-decluse">, Group, + Flags<[DriverOption]>; def fno_ms_extensions : Flag<["-"], "fno-ms-extensions">, Group; def fno_ms_compatibility : Flag<["-"], "fno-ms-compatibility">, Group; def fno_delayed_template_parsing : Flag<["-"], "fno-delayed-template-parsing">, Group; diff --git a/include/clang/Lex/ModuleMap.h b/include/clang/Lex/ModuleMap.h index 8e588bfdc1..90cfc6c7e1 100644 --- a/include/clang/Lex/ModuleMap.h +++ b/include/clang/Lex/ModuleMap.h @@ -55,6 +55,12 @@ class ModuleMap { // The module that we are building; related to \c LangOptions::CurrentModule. Module *CompilingModule; +public: + // The module that the .cc source file is associated with. + Module *SourceModule; + std::string SourceModuleName; + +private: /// \brief The top-level modules that are known. llvm::StringMap Modules; @@ -299,6 +305,16 @@ public: /// false otherwise. bool resolveExports(Module *Mod, bool Complain); + /// \brief Resolve all of the unresolved uses in the given module. + /// + /// \param Mod The module whose uses should be resolved. + /// + /// \param Complain Whether to emit diagnostics for failures. + /// + /// \returns true if any errors were encountered while resolving uses, + /// false otherwise. + bool resolveUses(Module *Mod, bool Complain); + /// \brief Resolve all of the unresolved conflicts in the given module. /// /// \param Mod The module whose conflicts should be resolved. diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h index d1e16f152f..f9eae97634 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -1441,6 +1441,31 @@ private: void HandleImportDirective(SourceLocation HashLoc, Token &Tok); void HandleMicrosoftImportDirective(Token &Tok); + // Module inclusion testing. + /// \brief Find the module for the source or header file that \p FilenameLoc + /// points to. + Module *getModuleForLocation(SourceLocation FilenameLoc); + + /// \brief Verify that a private header is included only from within its + /// module. + bool violatesPrivateInclude(Module *RequestingModule, + const FileEntry *IncFileEnt, + ModuleMap::ModuleHeaderRole Role, + Module *RequestedModule); + + /// \brief Verify that a module includes headers only from modules that it + /// has declared that it uses. + bool violatesUseDeclarations(Module *RequestingModule, + Module *RequestedModule); + + /// \brief Verify that it is legal for the source file that \p FilenameLoc + /// points to to include the file \p Filename. + /// + /// Tries to reuse \p IncFileEnt and \p SuggestedModule. + void verifyModuleInclude(SourceLocation FilenameLoc, StringRef Filename, + const FileEntry *IncFileEnt, + ModuleMap::KnownHeader *SuggestedModule); + // Macro handling. void HandleDefineDirective(Token &Tok, bool ImmediatelyAfterTopLevelIfndef); void HandleUndefDirective(Token &Tok); diff --git a/lib/Basic/Module.cpp b/lib/Basic/Module.cpp index 7ec5e68fc4..8c35b342ec 100644 --- a/lib/Basic/Module.cpp +++ b/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/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index 23f3648ddb..6a803cc17d 100644 --- a/lib/Driver/Tools.cpp +++ b/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/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index b13507a5ef..c8c676899c 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/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/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp index 631a7fd1da..ec84bb16d6 100644 --- a/lib/Lex/HeaderSearch.cpp +++ b/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 #if defined(LLVM_ON_UNIX) #include diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp index df80a93e4d..0f12af361a 100644 --- a/lib/Lex/ModuleMap.cpp +++ b/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/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp index 86d6ad9eb8..7591992596 100644 --- a/lib/Lex/PPDirectives.cpp +++ b/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 &PvtHdrs + = RequestedModule->PrivateHeaders; + SmallVectorImpl::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 &AllowedUses = RequestingModule->DirectUses; + SmallVectorImpl::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 &PvtHdrs - = RequestedModule->PrivateHeaders; - SmallVectorImpl::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/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 72fdc528fd..00f38bfa8c 100644 --- a/lib/Sema/Sema.cpp +++ b/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/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 5b55390730..9bb9a7a863 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/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/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index a4879226f9..409c9a18a5 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/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(); diff --git a/test/Modules/Inputs/declare-use/a.h b/test/Modules/Inputs/declare-use/a.h new file mode 100644 index 0000000000..a36dc1b59d --- /dev/null +++ b/test/Modules/Inputs/declare-use/a.h @@ -0,0 +1,4 @@ +#ifndef A_H +#define A_H +const int a = 2; +#endif diff --git a/test/Modules/Inputs/declare-use/b.h b/test/Modules/Inputs/declare-use/b.h new file mode 100644 index 0000000000..55daf72868 --- /dev/null +++ b/test/Modules/Inputs/declare-use/b.h @@ -0,0 +1,4 @@ +#ifndef B_H +#define B_H +const int b = 3; +#endif diff --git a/test/Modules/Inputs/declare-use/c.h b/test/Modules/Inputs/declare-use/c.h new file mode 100644 index 0000000000..a24cd5ae44 --- /dev/null +++ b/test/Modules/Inputs/declare-use/c.h @@ -0,0 +1,6 @@ +#ifndef C_H +#define C_H +#include "a.h" +#include "b.h" +const int c = a+b; +#endif diff --git a/test/Modules/Inputs/declare-use/d.h b/test/Modules/Inputs/declare-use/d.h new file mode 100644 index 0000000000..a597b01c5d --- /dev/null +++ b/test/Modules/Inputs/declare-use/d.h @@ -0,0 +1,6 @@ +#ifndef D_H +#define D_H +#include "a.h" +#include "b.h" +const int d = a+b; +#endif diff --git a/test/Modules/Inputs/declare-use/e.h b/test/Modules/Inputs/declare-use/e.h new file mode 100644 index 0000000000..ed8d843f9a --- /dev/null +++ b/test/Modules/Inputs/declare-use/e.h @@ -0,0 +1,6 @@ +#ifndef E_H +#define E_H +#include "a.h" +#include "b.h" +const int e = a*b; +#endif diff --git a/test/Modules/Inputs/declare-use/f.h b/test/Modules/Inputs/declare-use/f.h new file mode 100644 index 0000000000..1d8e2fd288 --- /dev/null +++ b/test/Modules/Inputs/declare-use/f.h @@ -0,0 +1,6 @@ +#ifndef F_H +#define F_H +#include "a.h" +#include "b.h" +const int f = a+b; +#endif diff --git a/test/Modules/Inputs/declare-use/g.h b/test/Modules/Inputs/declare-use/g.h new file mode 100644 index 0000000000..2a590177f8 --- /dev/null +++ b/test/Modules/Inputs/declare-use/g.h @@ -0,0 +1,6 @@ +#ifndef G_H +#define G_H +#include "c.h" +#include "g1.h" +const int g1 = aux_g*c*7; +#endif diff --git a/test/Modules/Inputs/declare-use/g1.h b/test/Modules/Inputs/declare-use/g1.h new file mode 100644 index 0000000000..78a072451f --- /dev/null +++ b/test/Modules/Inputs/declare-use/g1.h @@ -0,0 +1 @@ +int aux_g = 11; diff --git a/test/Modules/Inputs/declare-use/h.h b/test/Modules/Inputs/declare-use/h.h new file mode 100644 index 0000000000..df99a6dd10 --- /dev/null +++ b/test/Modules/Inputs/declare-use/h.h @@ -0,0 +1,7 @@ +#ifndef H_H +#define H_H +#include "c.h" +#include "d.h" // expected-error {{use of a module not declared used}} +#include "h1.h" +const int h1 = aux_h*c*7*d; +#endif diff --git a/test/Modules/Inputs/declare-use/h1.h b/test/Modules/Inputs/declare-use/h1.h new file mode 100644 index 0000000000..a9275d555c --- /dev/null +++ b/test/Modules/Inputs/declare-use/h1.h @@ -0,0 +1 @@ +int aux_h = 13; diff --git a/test/Modules/Inputs/declare-use/module.map b/test/Modules/Inputs/declare-use/module.map new file mode 100644 index 0000000000..ae3e90801e --- /dev/null +++ b/test/Modules/Inputs/declare-use/module.map @@ -0,0 +1,43 @@ +module A { + header "a.h" +} + +module B { + header "b.h" +} + +module C { + header "c.h" + use A +} + +module D { + header "d.h" + use A +} + +module E { + header "e.h" + use A + use B +} + +module F { + header "f.h" + use A + use B +} + +module G { + header "g.h" + header "g1.h" + use C + use E +} + +module H { + header "h.h" + header "h1.h" + use C + use E +} diff --git a/test/Modules/declare-use1.cpp b/test/Modules/declare-use1.cpp new file mode 100644 index 0000000000..5bb7e2a47a --- /dev/null +++ b/test/Modules/declare-use1.cpp @@ -0,0 +1,7 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -x objective-c++ -fmodules-cache-path=%t -fmodules -fmodules-decluse -fmodule-name=G -I %S/Inputs/declare-use %s -verify + +#include "g.h" +#include "e.h" +#include "f.h" // expected-error {{use of a module not declared used}} +const int g2 = g1+e+f; diff --git a/test/Modules/declare-use2.cpp b/test/Modules/declare-use2.cpp new file mode 100644 index 0000000000..807962cbdb --- /dev/null +++ b/test/Modules/declare-use2.cpp @@ -0,0 +1,7 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -x objective-c++ -fmodules-cache-path=%t -fmodules -fmodules-decluse -fmodule-name=H -I %S/Inputs/declare-use %s -verify + +#include "h.h" +#include "e.h" +#include "f.h" // expected-error {{use of a module not declared used}} +const int h2 = h1+e+f; -- 2.40.0