From ef1b5dcd49061f669fd4565fa48a3e8d85fd7c73 Mon Sep 17 00:00:00 2001 From: Ben Langmuir Date: Mon, 14 Apr 2014 18:00:01 +0000 Subject: [PATCH] Allow multiple modules with the same name to coexist in the module cache MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit To differentiate between two modules with the same name, we will consider the path the module map file that they are defined by* part of the ‘key’ for looking up the precompiled module (pcm file). Specifically, this patch renames the precompiled module (pcm) files from cache-path//Foo.pcm to cache-path//Foo-.pcm In addition, I’ve taught the ASTReader to re-resolve the names of imported modules during module loading so that if the header search context changes between when a module was originally built and when it is loaded we can rebuild it if necessary. For example, if module A imports module B first time: clang -I /path/to/A -I /path/to/B ... second time: clang -I /path/to/A -I /different/path/to/B ... will now rebuild A as expected. * in the case of inferred modules, we use the module map file that allowed the inference, not the __inferred_module.map file, since the inferred file path is the same for every inferred module. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@206201 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../Basic/DiagnosticSerializationKinds.td | 7 +- include/clang/Basic/Module.h | 19 ++++- include/clang/Frontend/FrontendActions.h | 20 +++--- include/clang/Lex/HeaderSearch.h | 5 +- include/clang/Lex/ModuleMap.h | 10 ++- include/clang/Serialization/ASTBitCodes.h | 9 ++- include/clang/Serialization/ASTReader.h | 1 + include/clang/Serialization/Module.h | 5 ++ lib/Basic/Module.cpp | 4 +- lib/Frontend/CompilerInstance.cpp | 5 +- lib/Frontend/FrontendAction.cpp | 16 +++-- lib/Frontend/FrontendActions.cpp | 12 ++-- lib/Lex/HeaderSearch.cpp | 35 +++++---- lib/Lex/ModuleMap.cpp | 45 ++++++++---- lib/Serialization/ASTReader.cpp | 71 +++++++++++++++---- lib/Serialization/ASTWriter.cpp | 29 +++++++- lib/Serialization/GlobalModuleIndex.cpp | 10 ++- lib/Serialization/ModuleManager.cpp | 5 +- test/Index/annotate-module.m | 2 +- test/Index/pch-depending-on-deleted-module.c | 6 +- .../DependsOnA/DependsOnA.h | 1 + .../DependsOnA/module.modulemap | 4 ++ .../Inputs/modules-with-same-name/path1/A/a.h | 1 + .../path1/A/module.modulemap | 3 + .../Inputs/modules-with-same-name/path2/A/a.h | 1 + .../path2/A/module.modulemap | 3 + test/Modules/dependency-gen-pch.m | 2 +- test/Modules/diamond-pch.c | 2 +- test/Modules/macro-undef-through-pch.m | 4 +- test/Modules/modules-with-same-name.m | 35 +++++++++ test/Modules/prune.m | 20 +++--- test/Modules/redecls/main.m | 2 +- test/Modules/resolution-change.m | 24 +++++++ test/Modules/system_version.m | 6 +- test/PCH/modified-module-dependency.m | 4 +- 35 files changed, 328 insertions(+), 100 deletions(-) create mode 100644 test/Modules/Inputs/modules-with-same-name/DependsOnA/DependsOnA.h create mode 100644 test/Modules/Inputs/modules-with-same-name/DependsOnA/module.modulemap create mode 100644 test/Modules/Inputs/modules-with-same-name/path1/A/a.h create mode 100644 test/Modules/Inputs/modules-with-same-name/path1/A/module.modulemap create mode 100644 test/Modules/Inputs/modules-with-same-name/path2/A/a.h create mode 100644 test/Modules/Inputs/modules-with-same-name/path2/A/module.modulemap create mode 100644 test/Modules/modules-with-same-name.m create mode 100644 test/Modules/resolution-change.m diff --git a/include/clang/Basic/DiagnosticSerializationKinds.td b/include/clang/Basic/DiagnosticSerializationKinds.td index 57ba0a4bcb..956c27d93d 100644 --- a/include/clang/Basic/DiagnosticSerializationKinds.td +++ b/include/clang/Basic/DiagnosticSerializationKinds.td @@ -48,7 +48,12 @@ def err_pch_different_branch : Error< "PCH file built from a different branch (%0) than the compiler (%1)">; def err_pch_with_compiler_errors : Error< "PCH file contains compiler errors">; - + +def err_imported_module_not_found : Error< + "module '%0' imported by AST file '%1' not found">, DefaultFatal; +def err_imported_module_modmap_changed : Error< + "module '%0' imported by AST file '%1' found in a different module map file" + " (%2) than when the importing AST file was built (%3)">, DefaultFatal; def warn_module_conflict : Warning< "module '%0' conflicts with already-imported module '%1': %2">, InGroup; diff --git a/include/clang/Basic/Module.h b/include/clang/Basic/Module.h index 1f7f71d54b..ab58131f5c 100644 --- a/include/clang/Basic/Module.h +++ b/include/clang/Basic/Module.h @@ -51,10 +51,21 @@ public: /// \brief The location of the module definition. SourceLocation DefinitionLoc; - + /// \brief The parent of this module. This will be NULL for the top-level /// module. Module *Parent; + + /// \brief The module map file that (along with the module name) uniquely + /// identifies this module. + /// + /// The particular module that \c Name refers to may depend on how the module + /// was found in header search. However, the combination of \c Name and + /// \c ModuleMap will be globally unique for top-level modules. In the case of + /// inferred modules, \c ModuleMap will contain the module map that allowed + /// the inference (e.g. contained 'Module *') rather than the virtual + /// inferred module map file. + const FileEntry *ModuleMap; /// \brief The umbrella header or directory. llvm::PointerUnion Umbrella; @@ -264,8 +275,10 @@ public: std::vector Conflicts; /// \brief Construct a new module or submodule. - Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent, - bool IsFramework, bool IsExplicit); + /// + /// For an explanation of \p ModuleMap, see Module::ModuleMap. + Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent, + const FileEntry *ModuleMap, bool IsFramework, bool IsExplicit); ~Module(); diff --git a/include/clang/Frontend/FrontendActions.h b/include/clang/Frontend/FrontendActions.h index a5db2523d2..a3cf5cb2cd 100644 --- a/include/clang/Frontend/FrontendActions.h +++ b/include/clang/Frontend/FrontendActions.h @@ -17,6 +17,7 @@ namespace clang { class Module; +class FileEntry; //===----------------------------------------------------------------------===// // Custom Consumer Actions @@ -92,7 +93,8 @@ public: }; class GenerateModuleAction : public ASTFrontendAction { - clang::Module *Module; + Module *Module; + const FileEntry *ModuleMapForUniquing; bool IsSystem; protected: @@ -106,8 +108,10 @@ protected: bool hasASTFileSupport() const override { return false; } public: - explicit GenerateModuleAction(bool IsSystem = false) - : ASTFrontendAction(), IsSystem(IsSystem) { } + GenerateModuleAction(const FileEntry *ModuleMap = nullptr, + bool IsSystem = false) + : ASTFrontendAction(), ModuleMapForUniquing(ModuleMap), IsSystem(IsSystem) + { } bool BeginSourceFileAction(CompilerInstance &CI, StringRef Filename) override; @@ -115,11 +119,11 @@ public: /// create the PCHGenerator instance returned by CreateASTConsumer. /// /// \returns true if an error occurred, false otherwise. - static bool ComputeASTConsumerArguments(CompilerInstance &CI, - StringRef InFile, - std::string &Sysroot, - std::string &OutputFile, - raw_ostream *&OS); + bool ComputeASTConsumerArguments(CompilerInstance &CI, + StringRef InFile, + std::string &Sysroot, + std::string &OutputFile, + raw_ostream *&OS); }; class SyntaxOnlyAction : public ASTFrontendAction { diff --git a/include/clang/Lex/HeaderSearch.h b/include/clang/Lex/HeaderSearch.h index c3af6335a0..507ede583f 100644 --- a/include/clang/Lex/HeaderSearch.h +++ b/include/clang/Lex/HeaderSearch.h @@ -493,9 +493,12 @@ public: /// /// \param ModuleName The module whose module file name will be returned. /// + /// \param ModuleMapPath A path that when combined with \c ModuleName + /// uniquely identifies this module. See Module::ModuleMap. + /// /// \returns The name of the module file that corresponds to this module, /// or an empty string if this module does not correspond to any module file. - std::string getModuleFileName(StringRef ModuleName); + std::string getModuleFileName(StringRef ModuleName, StringRef ModuleMapPath); /// \brief Lookup a module Search for a module with the given name. /// diff --git a/include/clang/Lex/ModuleMap.h b/include/clang/Lex/ModuleMap.h index db7568387e..fde33ecadb 100644 --- a/include/clang/Lex/ModuleMap.h +++ b/include/clang/Lex/ModuleMap.h @@ -131,6 +131,10 @@ private: /// \brief Whether the modules we infer are [system] modules. unsigned InferSystemModules : 1; + /// \brief If \c InferModules is non-zero, the module map file that allowed + /// inferred modules. Otherwise, nullptr. + const FileEntry *ModuleMapFile; + /// \brief The names of modules that cannot be inferred within this /// directory. SmallVector ExcludedModules; @@ -293,13 +297,17 @@ public: /// \param Parent The module that will act as the parent of this submodule, /// or NULL to indicate that this is a top-level module. /// + /// \param ModuleMap The module map that defines or allows the inference of + /// this module. + /// /// \param IsFramework Whether this is a framework module. /// /// \param IsExplicit Whether this is an explicit submodule. /// /// \returns The found or newly-created module, along with a boolean value /// that will be true if the module is newly-created. - std::pair findOrCreateModule(StringRef Name, Module *Parent, + std::pair findOrCreateModule(StringRef Name, Module *Parent, + const FileEntry *ModuleMap, bool IsFramework, bool IsExplicit); diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index 35765b67f0..89435f3afe 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -281,7 +281,14 @@ namespace clang { HEADER_SEARCH_OPTIONS = 11, /// \brief Record code for the preprocessor options table. - PREPROCESSOR_OPTIONS = 12 + PREPROCESSOR_OPTIONS = 12, + + /// \brief Record code for the module name. + MODULE_NAME = 13, + + /// \brief Record code for the module map file that was used to build this + /// AST file. + MODULE_MAP_FILE = 14 }; /// \brief Record types that occur within the input-files block diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index 54002aa52a..1f27e384ae 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -1079,6 +1079,7 @@ private: unsigned ClientLoadCapabilities); ASTReadResult ReadControlBlock(ModuleFile &F, SmallVectorImpl &Loaded, + const ModuleFile *ImportedBy, unsigned ClientLoadCapabilities); ASTReadResult ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities); bool ParseLineTable(ModuleFile &F, SmallVectorImpl &Record); diff --git a/include/clang/Serialization/Module.h b/include/clang/Serialization/Module.h index 626901ed79..0c551b7f4b 100644 --- a/include/clang/Serialization/Module.h +++ b/include/clang/Serialization/Module.h @@ -116,6 +116,9 @@ public: /// \brief The file name of the module file. std::string FileName; + /// \brief The name of the module. + std::string ModuleName; + std::string getTimestampFilename() const { return FileName + ".timestamp"; } @@ -137,6 +140,8 @@ public: /// allow resolving headers even after headers+PCH was moved to a new path. std::string OriginalDir; + std::string ModuleMapPath; + /// \brief Whether this precompiled header is a relocatable PCH file. bool RelocatablePCH; diff --git a/lib/Basic/Module.cpp b/lib/Basic/Module.cpp index 237c78981f..2612ee0dde 100644 --- a/lib/Basic/Module.cpp +++ b/lib/Basic/Module.cpp @@ -25,8 +25,8 @@ using namespace clang; Module::Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent, - bool IsFramework, bool IsExplicit) - : Name(Name), DefinitionLoc(DefinitionLoc), Parent(Parent), + const FileEntry *File, bool IsFramework, bool IsExplicit) + : Name(Name), DefinitionLoc(DefinitionLoc), Parent(Parent), ModuleMap(File), Umbrella(), ASTFile(0), IsAvailable(true), IsFromModuleFile(false), IsFramework(IsFramework), IsExplicit(IsExplicit), IsSystem(false), IsExternC(false), InferSubmodules(false), InferExplicitSubmodules(false), diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index f12f6303f0..267d318fa9 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -870,8 +870,9 @@ static void compileModuleImpl(CompilerInstance &ImportingInstance, SourceMgr.overrideFileContents(ModuleMapFile, ModuleMapBuffer); } - // Construct a module-generating action. - GenerateModuleAction CreateModuleAction(Module->IsSystem); + // Construct a module-generating action. Passing through Module->ModuleMap is + // safe because the FileManager is shared between the compiler instances. + GenerateModuleAction CreateModuleAction(Module->ModuleMap, Module->IsSystem); // Execute the action to actually build the module in-place. Use a separate // thread so that we get a stack large enough. diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp index d2ece7e732..dc4dd89371 100644 --- a/lib/Frontend/FrontendAction.cpp +++ b/lib/Frontend/FrontendAction.cpp @@ -256,6 +256,10 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, if (!BeginSourceFileAction(CI, InputFile)) goto failure; + // Initialize the main file entry. + if (!CI.InitializeSourceManager(CurrentInput)) + goto failure; + return true; } @@ -302,6 +306,11 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, if (!BeginSourceFileAction(CI, InputFile)) goto failure; + // Initialize the main file entry. It is important that this occurs after + // BeginSourceFileAction, which may change CurrentInput during module builds. + if (!CI.InitializeSourceManager(CurrentInput)) + goto failure; + // Create the AST context and consumer unless this is a preprocessor only // action. if (!usesPreprocessorOnly()) { @@ -389,13 +398,6 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, bool FrontendAction::Execute() { CompilerInstance &CI = getCompilerInstance(); - // Initialize the main file entry. This needs to be delayed until after PCH - // has loaded. - if (!isCurrentFileAST()) { - if (!CI.InitializeSourceManager(getCurrentInput())) - return false; - } - if (CI.hasFrontendTimer()) { llvm::TimeRegion Timer(CI.getFrontendTimer()); ExecuteAction(); diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp index 3f1d2c6106..bbd2dff46c 100644 --- a/lib/Frontend/FrontendActions.cpp +++ b/lib/Frontend/FrontendActions.cpp @@ -299,6 +299,11 @@ bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI, return false; } + if (!ModuleMapForUniquing) + ModuleMapForUniquing = ModuleMap; + Module->ModuleMap = ModuleMapForUniquing; + assert(Module->ModuleMap && "missing module map file"); + FileManager &FileMgr = CI.getFileManager(); // Collect the set of #includes we need to build the module. @@ -337,10 +342,9 @@ bool GenerateModuleAction::ComputeASTConsumerArguments(CompilerInstance &CI, // in the module cache. if (CI.getFrontendOpts().OutputFile.empty()) { HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo(); - SmallString<256> ModuleFileName(HS.getModuleCachePath()); - llvm::sys::path::append(ModuleFileName, - CI.getLangOpts().CurrentModule + ".pcm"); - CI.getFrontendOpts().OutputFile = ModuleFileName.str(); + CI.getFrontendOpts().OutputFile = + HS.getModuleFileName(CI.getLangOpts().CurrentModule, + ModuleMapForUniquing->getName()); } // We use createOutputFile here because this is exposed via libclang, and we diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp index f081024706..87a5053628 100644 --- a/lib/Lex/HeaderSearch.cpp +++ b/lib/Lex/HeaderSearch.cpp @@ -18,6 +18,8 @@ #include "clang/Lex/HeaderSearchOptions.h" #include "clang/Lex/LexDiagnostic.h" #include "clang/Lex/Lexer.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/Hashing.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/Capacity.h" #include "llvm/Support/FileSystem.h" @@ -112,24 +114,33 @@ const HeaderMap *HeaderSearch::CreateHeaderMap(const FileEntry *FE) { } std::string HeaderSearch::getModuleFileName(Module *Module) { - // If we don't have a module cache path, we can't do anything. - if (ModuleCachePath.empty()) - return std::string(); - - - SmallString<256> Result(ModuleCachePath); - llvm::sys::path::append(Result, Module->getTopLevelModule()->Name + ".pcm"); - return Result.str().str(); + return getModuleFileName(Module->Name, Module->ModuleMap->getName()); } -std::string HeaderSearch::getModuleFileName(StringRef ModuleName) { +std::string HeaderSearch::getModuleFileName(StringRef ModuleName, + StringRef ModuleMapPath) { // If we don't have a module cache path, we can't do anything. if (ModuleCachePath.empty()) return std::string(); - - + SmallString<256> Result(ModuleCachePath); - llvm::sys::path::append(Result, ModuleName + ".pcm"); + llvm::sys::fs::make_absolute(Result); + + if (HSOpts->DisableModuleHash) { + llvm::sys::path::append(Result, ModuleName + ".pcm"); + } else { + // Construct the name -.pcm which should + // be globally unique to this particular module. To avoid false-negatives + // on case-insensitive filesystems, we use lower-case, which is safe because + // to cause a collision the modules must have the same name, which is an + // error if they are imported in the same translation. + SmallString<256> AbsModuleMapPath(ModuleMapPath); + llvm::sys::fs::make_absolute(AbsModuleMapPath); + llvm::APInt Code(64, llvm::hash_value(AbsModuleMapPath.str().lower())); + SmallString<128> HashStr; + Code.toStringUnsigned(HashStr, /*Radix*/36); + llvm::sys::path::append(Result, ModuleName + "-" + HashStr.str() + ".pcm"); + } return Result.str().str(); } diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp index 689ef73b46..810fcf0547 100644 --- a/lib/Lex/ModuleMap.cpp +++ b/lib/Lex/ModuleMap.cpp @@ -363,8 +363,8 @@ ModuleMap::findModuleForHeader(const FileEntry *File, SmallString<32> NameBuf; StringRef Name = sanitizeFilenameAsIdentifier( llvm::sys::path::stem(SkippedDirs[I-1]->getName()), NameBuf); - Result = findOrCreateModule(Name, Result, /*IsFramework=*/false, - Explicit).first; + Result = findOrCreateModule(Name, Result, UmbrellaModule->ModuleMap, + /*IsFramework=*/false, Explicit).first; // Associate the module and the directory. UmbrellaDirs[SkippedDirs[I-1]] = Result; @@ -378,9 +378,9 @@ ModuleMap::findModuleForHeader(const FileEntry *File, // Infer a submodule with the same name as this header file. SmallString<32> NameBuf; StringRef Name = sanitizeFilenameAsIdentifier( - llvm::sys::path::stem(File->getName()), NameBuf); - Result = findOrCreateModule(Name, Result, /*IsFramework=*/false, - Explicit).first; + llvm::sys::path::stem(File->getName()), NameBuf); + Result = findOrCreateModule(Name, Result, UmbrellaModule->ModuleMap, + /*IsFramework=*/false, Explicit).first; Result->addTopHeader(File); // If inferred submodules export everything they import, add a @@ -518,15 +518,16 @@ Module *ModuleMap::lookupModuleQualified(StringRef Name, Module *Context) const{ } std::pair -ModuleMap::findOrCreateModule(StringRef Name, Module *Parent, bool IsFramework, +ModuleMap::findOrCreateModule(StringRef Name, Module *Parent, + const FileEntry *ModuleMap, bool IsFramework, bool IsExplicit) { // Try to find an existing module with this name. if (Module *Sub = lookupModuleQualified(Name, Parent)) return std::make_pair(Sub, false); // Create a new module with this name. - Module *Result = new Module(Name, SourceLocation(), Parent, IsFramework, - IsExplicit); + Module *Result = new Module(Name, SourceLocation(), Parent, ModuleMap, + IsFramework, IsExplicit); if (LangOpts.CurrentModule == Name) { SourceModule = Result; SourceModuleName = Name; @@ -595,6 +596,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName, // If the framework has a parent path from which we're allowed to infer // a framework module, do so. + const FileEntry *ModuleMapFile = nullptr; if (!Parent) { // Determine whether we're allowed to infer a module map. @@ -639,6 +641,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName, if (inferred->second.InferSystemModules) IsSystem = true; + ModuleMapFile = inferred->second.ModuleMapFile; } } } @@ -646,7 +649,8 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName, // If we're not allowed to infer a framework module, don't. if (!canInfer) return 0; - } + } else + ModuleMapFile = Parent->ModuleMap; // Look for an umbrella header. @@ -660,7 +664,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName, if (!UmbrellaHeader) return 0; - Module *Result = new Module(ModuleName, SourceLocation(), Parent, + Module *Result = new Module(ModuleName, SourceLocation(), Parent, ModuleMapFile, /*IsFramework=*/true, /*IsExplicit=*/false); if (LangOpts.CurrentModule == ModuleName) { SourceModule = Result; @@ -954,6 +958,9 @@ namespace clang { DiagnosticsEngine &Diags; ModuleMap ⤅ + + /// \brief The current module map file. + const FileEntry *ModuleMapFile; /// \brief The directory that this module map resides in. const DirectoryEntry *Directory; @@ -1007,12 +1014,14 @@ namespace clang { const TargetInfo *Target, DiagnosticsEngine &Diags, ModuleMap &Map, + const FileEntry *ModuleMapFile, const DirectoryEntry *Directory, const DirectoryEntry *BuiltinIncludeDir, bool IsSystem) : L(L), SourceMgr(SourceMgr), Target(Target), Diags(Diags), Map(Map), - Directory(Directory), BuiltinIncludeDir(BuiltinIncludeDir), - IsSystem(IsSystem), HadError(false), ActiveModule(0) + ModuleMapFile(ModuleMapFile), Directory(Directory), + BuiltinIncludeDir(BuiltinIncludeDir), IsSystem(IsSystem), + HadError(false), ActiveModule(0) { Tok.clear(); consumeToken(); @@ -1359,9 +1368,14 @@ void ModuleMapParser::parseModuleDecl() { return; } + // If this is a submodule, use the parent's module map, since we don't want + // the private module map file. + const FileEntry *ModuleMap = ActiveModule ? ActiveModule->ModuleMap + : ModuleMapFile; + // Start defining this module. - ActiveModule = Map.findOrCreateModule(ModuleName, ActiveModule, Framework, - Explicit).first; + ActiveModule = Map.findOrCreateModule(ModuleName, ActiveModule, ModuleMap, + Framework, Explicit).first; ActiveModule->DefinitionLoc = ModuleNameLoc; if (Attrs.IsSystem || IsSystem) ActiveModule->IsSystem = true; @@ -2020,6 +2034,7 @@ void ModuleMapParser::parseInferredModuleDecl(bool Framework, bool Explicit) { // We'll be inferring framework modules for this directory. Map.InferredDirectories[Directory].InferModules = true; Map.InferredDirectories[Directory].InferSystemModules = Attrs.IsSystem; + Map.InferredDirectories[Directory].ModuleMapFile = ModuleMapFile; // FIXME: Handle the 'framework' keyword. } @@ -2256,7 +2271,7 @@ bool ModuleMap::parseModuleMapFile(const FileEntry *File, bool IsSystem) { // Parse this module map file. Lexer L(ID, SourceMgr.getBuffer(ID), SourceMgr, MMapLangOpts); - ModuleMapParser Parser(L, SourceMgr, Target, Diags, *this, Dir, + ModuleMapParser Parser(L, SourceMgr, Target, Diags, *this, File, Dir, BuiltinIncludeDir, IsSystem); bool Result = Parser.parseModuleMapFile(); ParsedModuleMap[File] = Result; diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 1d1957d6bf..ea3b8b6cd1 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -1161,7 +1161,7 @@ std::pair ASTReader::getModuleImportLoc(int ID) { // FIXME: Can we map this down to a particular submodule? That would be // ideal. - return std::make_pair(M->ImportLoc, llvm::sys::path::stem(M->FileName)); + return std::make_pair(M->ImportLoc, StringRef(M->ModuleName)); } /// \brief Find the location where the module F is imported. @@ -1172,14 +1172,10 @@ SourceLocation ASTReader::getImportLocation(ModuleFile *F) { // Otherwise we have a PCH. It's considered to be "imported" at the first // location of its includer. if (F->ImportedBy.empty() || !F->ImportedBy[0]) { - // Main file is the importer. We assume that it is the first entry in the - // entry table. We can't ask the manager, because at the time of PCH loading - // the main file entry doesn't exist yet. - // The very first entry is the invalid instantiation loc, which takes up - // offsets 0 and 1. - return SourceLocation::getFromRawEncoding(2U); - } - //return F->Loaders[0]->FirstLoc; + // Main file is the importer. + assert(!SourceMgr.getMainFileID().isInvalid() && "missing main file"); + return SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID()); + } return F->ImportedBy[0]->FirstLoc; } @@ -2089,6 +2085,7 @@ void ASTReader::MaybeAddSystemRootToFilename(ModuleFile &M, ASTReader::ASTReadResult ASTReader::ReadControlBlock(ModuleFile &F, SmallVectorImpl &Loaded, + const ModuleFile *ImportedBy, unsigned ClientLoadCapabilities) { BitstreamCursor &Stream = F.Stream; @@ -2314,6 +2311,44 @@ ASTReader::ReadControlBlock(ModuleFile &F, F.OriginalDir = Blob; break; + case MODULE_NAME: + F.ModuleName = Blob; + break; + + case MODULE_MAP_FILE: + F.ModuleMapPath = Blob; + + // Try to resolve ModuleName in the current header search context and + // verify that it is found in the same module map file as we saved. If the + // top-level AST file is a main file, skip this check because there is no + // usable header search context. + assert(!F.ModuleName.empty() && + "MODULE_NAME should come before MOUDLE_MAP_FILE"); + if (F.Kind == MK_Module && + (*ModuleMgr.begin())->Kind != MK_MainFile) { + Module *M = PP.getHeaderSearchInfo().lookupModule(F.ModuleName); + if (!M) { + assert(ImportedBy && "top-level import should be verified"); + if ((ClientLoadCapabilities & ARR_Missing) == 0) + Diag(diag::err_imported_module_not_found) + << F.ModuleName << ImportedBy->FileName; + return Missing; + } + + const FileEntry *StoredModMap = FileMgr.getFile(F.ModuleMapPath); + if (StoredModMap == nullptr || StoredModMap != M->ModuleMap) { + assert(M->ModuleMap && "found module is missing module map file"); + assert(M->Name == F.ModuleName && "found module with different name"); + assert(ImportedBy && "top-level import should be verified"); + if ((ClientLoadCapabilities & ARR_OutOfDate) == 0) + Diag(diag::err_imported_module_modmap_changed) + << F.ModuleName << ImportedBy->FileName + << M->ModuleMap->getName() << F.ModuleMapPath; + return OutOfDate; + } + } + break; + case INPUT_FILE_OFFSETS: F.InputFileOffsets = (const uint32_t *)Blob.data(); F.InputFilesLoaded.resize(Record[0]); @@ -3537,7 +3572,7 @@ ASTReader::ReadASTCore(StringRef FileName, break; case CONTROL_BLOCK_ID: HaveReadControlBlock = true; - switch (ReadControlBlock(F, Loaded, ClientLoadCapabilities)) { + switch (ReadControlBlock(F, Loaded, ImportedBy, ClientLoadCapabilities)) { case Success: break; @@ -4059,13 +4094,19 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { bool InferExportWildcard = Record[Idx++]; bool ConfigMacrosExhaustive = Record[Idx++]; - Module *ParentModule = 0; - if (Parent) + Module *ParentModule = nullptr; + const FileEntry *ModuleMap = nullptr; + if (Parent) { ParentModule = getSubmodule(Parent); - + ModuleMap = ParentModule->ModuleMap; + } + + if (!F.ModuleMapPath.empty()) + ModuleMap = FileMgr.getFile(F.ModuleMapPath); + // Retrieve this (sub)module from the module map, creating it if // necessary. - CurrentModule = ModMap.findOrCreateModule(Name, ParentModule, + CurrentModule = ModMap.findOrCreateModule(Name, ParentModule, ModuleMap, IsFramework, IsExplicit).first; SubmoduleID GlobalIndex = GlobalID - NUM_PREDEF_SUBMODULE_IDS; @@ -4090,7 +4131,7 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { CurrentModule->setASTFile(F.File); } - + CurrentModule->IsFromModuleFile = true; CurrentModule->IsSystem = IsSystem || CurrentModule->IsSystem; CurrentModule->IsExternC = IsExternC; diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 99f0b5c566..96a254ae9a 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -798,6 +798,8 @@ void ASTWriter::WriteBlockInfoBlock() { // Control Block. BLOCK(CONTROL_BLOCK); RECORD(METADATA); + RECORD(MODULE_NAME); + RECORD(MODULE_MAP_FILE); RECORD(IMPORTS); RECORD(LANGUAGE_OPTIONS); RECORD(TARGET_OPTIONS); @@ -1050,6 +1052,32 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, Stream.EmitRecordWithBlob(MetadataAbbrevCode, Record, getClangFullRepositoryVersion()); + // Module name + if (WritingModule) { + BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(MODULE_NAME)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name + unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev); + RecordData Record; + Record.push_back(MODULE_NAME); + Stream.EmitRecordWithBlob(AbbrevCode, Record, WritingModule->Name); + } + + // Module map file + if (WritingModule) { + BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(MODULE_MAP_FILE)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Filename + unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev); + + assert(WritingModule->ModuleMap && "missing module map"); + SmallString<128> ModuleMap(WritingModule->ModuleMap->getName()); + llvm::sys::fs::make_absolute(ModuleMap); + RecordData Record; + Record.push_back(MODULE_MAP_FILE); + Stream.EmitRecordWithBlob(AbbrevCode, Record, ModuleMap.str()); + } + // Imports if (Chain) { serialization::ModuleManager &Mgr = Chain->getModuleManager(); @@ -1065,7 +1093,6 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, AddSourceLocation((*M)->ImportLoc, Record); Record.push_back((*M)->File->getSize()); Record.push_back((*M)->File->getModificationTime()); - // FIXME: This writes the absolute path for AST files we depend on. const std::string &FileName = (*M)->FileName; Record.push_back(FileName.size()); Record.append(FileName.begin(), FileName.end()); diff --git a/lib/Serialization/GlobalModuleIndex.cpp b/lib/Serialization/GlobalModuleIndex.cpp index 804a14363a..9ebb0ad5e5 100644 --- a/lib/Serialization/GlobalModuleIndex.cpp +++ b/lib/Serialization/GlobalModuleIndex.cpp @@ -14,6 +14,7 @@ #include "ASTReaderInternals.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/OnDiskHashTable.h" +#include "clang/Lex/HeaderSearch.h" #include "clang/Serialization/ASTBitCodes.h" #include "clang/Serialization/GlobalModuleIndex.h" #include "clang/Serialization/Module.h" @@ -203,7 +204,12 @@ GlobalModuleIndex::GlobalModuleIndex(llvm::MemoryBuffer *Buffer, assert(Idx == Record.size() && "More module info?"); // Record this module as an unresolved module. - UnresolvedModules[llvm::sys::path::stem(Modules[ID].FileName)] = ID; + // FIXME: this doesn't work correctly for module names containing path + // separators. + StringRef ModuleName = llvm::sys::path::stem(Modules[ID].FileName); + // Remove the - + ModuleName = ModuleName.rsplit('-').first; + UnresolvedModules[ModuleName] = ID; break; } @@ -308,7 +314,7 @@ bool GlobalModuleIndex::lookupIdentifier(StringRef Name, HitSet &Hits) { bool GlobalModuleIndex::loadedModuleFile(ModuleFile *File) { // Look for the module in the global module index based on the module name. - StringRef Name = llvm::sys::path::stem(File->FileName); + StringRef Name = File->ModuleName; llvm::StringMap::iterator Known = UnresolvedModules.find(Name); if (Known == UnresolvedModules.end()) { return true; diff --git a/lib/Serialization/ModuleManager.cpp b/lib/Serialization/ModuleManager.cpp index 3513eba860..c36d902deb 100644 --- a/lib/Serialization/ModuleManager.cpp +++ b/lib/Serialization/ModuleManager.cpp @@ -11,6 +11,7 @@ // modules for the ASTReader. // //===----------------------------------------------------------------------===// +#include "clang/Lex/HeaderSearch.h" #include "clang/Lex/ModuleMap.h" #include "clang/Serialization/GlobalModuleIndex.h" #include "clang/Serialization/ModuleManager.h" @@ -155,7 +156,7 @@ void ModuleManager::removeModules(ModuleIterator first, ModuleIterator last, FileMgr.invalidateCache((*victim)->File); if (modMap) { - StringRef ModuleName = llvm::sys::path::stem((*victim)->FileName); + StringRef ModuleName = (*victim)->ModuleName; if (Module *mod = modMap->findModule(ModuleName)) { mod->setASTFile(0); } @@ -429,7 +430,7 @@ namespace llvm { } std::string getNodeLabel(ModuleFile *M, const ModuleManager&) { - return llvm::sys::path::stem(M->FileName); + return M->ModuleName; } }; } diff --git a/test/Index/annotate-module.m b/test/Index/annotate-module.m index 55e21d235e..3082e21086 100644 --- a/test/Index/annotate-module.m +++ b/test/Index/annotate-module.m @@ -44,6 +44,6 @@ int glob; // RUN: c-index-test -cursor-at=%s:3:11 %s -fmodules-cache-path=%t.cache -fmodules -F %S/../Modules/Inputs \ // RUN: | FileCheck %s -check-prefix=CHECK-CURSOR -// CHECK-CURSOR: 3:1 ModuleImport=DependsOnModule:3:1 (Definition) Extent=[3:1 - 3:24] Spelling=DependsOnModule ([3:9 - 3:24]) ModuleName=DependsOnModule ({{.*}}DependsOnModule.pcm) Headers(2): +// CHECK-CURSOR: 3:1 ModuleImport=DependsOnModule:3:1 (Definition) Extent=[3:1 - 3:24] Spelling=DependsOnModule ([3:9 - 3:24]) ModuleName=DependsOnModule ({{.*}}DependsOnModule-{{[^.]*}}.pcm) Headers(2): // CHECK-CURSOR-NEXT: {{.*}}other.h // CHECK-CURSOR-NEXT: {{.*}}DependsOnModule.h diff --git a/test/Index/pch-depending-on-deleted-module.c b/test/Index/pch-depending-on-deleted-module.c index 223b6361a8..4e85ff0f96 100644 --- a/test/Index/pch-depending-on-deleted-module.c +++ b/test/Index/pch-depending-on-deleted-module.c @@ -4,10 +4,10 @@ // RUN: mkdir %t // RUN: %clang_cc1 -x c-header -fmodules -fdisable-module-hash -fmodules-cache-path=%t/modules-cache -emit-pch -I %S/Inputs/Headers -o %t/use_LibA.pch %s -// RUN: %clang_cc1 -fmodules -fdisable-module-hash -fmodules-cache-path=%t/modules-cache -verify-pch %t/use_LibA.pch +// RUN: %clang_cc1 -fmodules -fdisable-module-hash -fmodules-cache-path=%t/modules-cache -I %S/Inputs/Headers -verify-pch %t/use_LibA.pch // RUN: rm -f %t/modules-cache/LibA.pcm -// RUN: not %clang_cc1 -fmodules -fdisable-module-hash -fmodules-cache-path=modules-cache -verify-pch %t/use_LibA.pch 2>&1 | FileCheck -check-prefix=VERIFY %s -// RUN: not c-index-test -test-load-source all -x c -fmodules -fdisable-module-hash -fmodules-cache-path=modules-cache -include-pch %t/use_LibA.pch %s 2>&1 | FileCheck -check-prefix=INDEX %s +// RUN: not %clang_cc1 -fmodules -fdisable-module-hash -fmodules-cache-path=%t/modules-cache -I %S/Inputs/Headers -verify-pch %t/use_LibA.pch 2>&1 | FileCheck -check-prefix=VERIFY %s +// RUN: not c-index-test -test-load-source all -x c -fmodules -Xclang -fdisable-module-hash -fmodules-cache-path=%t/modules-cache -I %S/Inputs/Headers -include-pch %t/use_LibA.pch %s 2>&1 | FileCheck -check-prefix=INDEX %s // VERIFY: fatal error: malformed or corrupted AST file: 'Unable to load module // INDEX: {{^}}Failure: AST deserialization error occurred{{$}} diff --git a/test/Modules/Inputs/modules-with-same-name/DependsOnA/DependsOnA.h b/test/Modules/Inputs/modules-with-same-name/DependsOnA/DependsOnA.h new file mode 100644 index 0000000000..9d0256bdff --- /dev/null +++ b/test/Modules/Inputs/modules-with-same-name/DependsOnA/DependsOnA.h @@ -0,0 +1 @@ +@import A; diff --git a/test/Modules/Inputs/modules-with-same-name/DependsOnA/module.modulemap b/test/Modules/Inputs/modules-with-same-name/DependsOnA/module.modulemap new file mode 100644 index 0000000000..b2a027b55d --- /dev/null +++ b/test/Modules/Inputs/modules-with-same-name/DependsOnA/module.modulemap @@ -0,0 +1,4 @@ +module DependsOnA { + header "DependsOnA.h" + export * +} diff --git a/test/Modules/Inputs/modules-with-same-name/path1/A/a.h b/test/Modules/Inputs/modules-with-same-name/path1/A/a.h new file mode 100644 index 0000000000..0086e2a250 --- /dev/null +++ b/test/Modules/Inputs/modules-with-same-name/path1/A/a.h @@ -0,0 +1 @@ +#define FROM_PATH 1 diff --git a/test/Modules/Inputs/modules-with-same-name/path1/A/module.modulemap b/test/Modules/Inputs/modules-with-same-name/path1/A/module.modulemap new file mode 100644 index 0000000000..bbd9d674c9 --- /dev/null +++ b/test/Modules/Inputs/modules-with-same-name/path1/A/module.modulemap @@ -0,0 +1,3 @@ +module A { + header "a.h" +} diff --git a/test/Modules/Inputs/modules-with-same-name/path2/A/a.h b/test/Modules/Inputs/modules-with-same-name/path2/A/a.h new file mode 100644 index 0000000000..184c190bcb --- /dev/null +++ b/test/Modules/Inputs/modules-with-same-name/path2/A/a.h @@ -0,0 +1 @@ +#define FROM_PATH 2 diff --git a/test/Modules/Inputs/modules-with-same-name/path2/A/module.modulemap b/test/Modules/Inputs/modules-with-same-name/path2/A/module.modulemap new file mode 100644 index 0000000000..bbd9d674c9 --- /dev/null +++ b/test/Modules/Inputs/modules-with-same-name/path2/A/module.modulemap @@ -0,0 +1,3 @@ +module A { + header "a.h" +} diff --git a/test/Modules/dependency-gen-pch.m b/test/Modules/dependency-gen-pch.m index b0c75513d9..65e22d485d 100644 --- a/test/Modules/dependency-gen-pch.m +++ b/test/Modules/dependency-gen-pch.m @@ -1,7 +1,7 @@ // RUN: rm -rf %t-mcp // RUN: mkdir -p %t-mcp -// RUN: %clang_cc1 -isysroot %S/Inputs/System -triple x86_64-apple-darwin10 -module-file-deps -dependency-file %t.d -MT %s.o -I %S/Inputs -fmodules -fmodules-cache-path=%t-mcp -emit-pch -o %t.pch %s +// RUN: %clang_cc1 -isysroot %S/Inputs/System -triple x86_64-apple-darwin10 -module-file-deps -dependency-file %t.d -MT %s.o -I %S/Inputs -fmodules -fdisable-module-hash -fmodules-cache-path=%t-mcp -emit-pch -o %t.pch %s // RUN: FileCheck %s < %t.d // CHECK: dependency-gen-pch.m.o // CHECK-NEXT: dependency-gen-pch.m diff --git a/test/Modules/diamond-pch.c b/test/Modules/diamond-pch.c index 37a8cbe25d..f66ad877de 100644 --- a/test/Modules/diamond-pch.c +++ b/test/Modules/diamond-pch.c @@ -4,7 +4,7 @@ // RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodules-cache-path=%t -fmodule-name=diamond_right %S/Inputs/module.map // RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodules-cache-path=%t -fmodule-name=diamond_bottom %S/Inputs/module.map // RUN: %clang_cc1 -fmodules -x objective-c -emit-pch -fmodules-cache-path=%t -I %S/Inputs -o %t.pch %S/Inputs/diamond.h -// RUN: %clang_cc1 -fmodules -x objective-c -fmodules-cache-path=%t -include-pch %t.pch %s -verify +// RUN: %clang_cc1 -fmodules -x objective-c -fmodules-cache-path=%t -include-pch %t.pch %s -I %S/Inputs -verify // FIXME: When we have a syntax for modules in C, use that. void test_diamond(int i, float f, double d, char c) { diff --git a/test/Modules/macro-undef-through-pch.m b/test/Modules/macro-undef-through-pch.m index ff0736ca99..0e5e99fb8b 100644 --- a/test/Modules/macro-undef-through-pch.m +++ b/test/Modules/macro-undef-through-pch.m @@ -2,7 +2,9 @@ // RUN: %clang_cc1 -x objective-c-header -fmodules -fmodules-cache-path=%t \ // RUN: -I%S/Inputs/macro-undef-through-pch -emit-pch \ // RUN: %S/Inputs/macro-undef-through-pch/foo.h -o %t.pch -// RUN: %clang_cc1 -x objective-c -fmodules -fmodules-cache-path=%t -include-pch %t.pch %s +// RUN: %clang_cc1 -x objective-c -fmodules -fmodules-cache-path=%t \ +// RUN: -I%S/Inputs/macro-undef-through-pch -emit-pch \ +// RUN: -include-pch %t.pch %s // PR19215 #undef AB diff --git a/test/Modules/modules-with-same-name.m b/test/Modules/modules-with-same-name.m new file mode 100644 index 0000000000..c90aa5d7d8 --- /dev/null +++ b/test/Modules/modules-with-same-name.m @@ -0,0 +1,35 @@ +// REQUIRES: shell +// RUN: rm -rf %t + +// A from path 1 +// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fmodules-ignore-macro=EXPECTED_PATH -fmodules-ignore-macro=DIRECT -fsyntax-only %s -verify -I %S/Inputs/modules-with-same-name/path1/A -DDIRECT -DEXPECTED_PATH=1 + +// A from path 2 +// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fmodules-ignore-macro=EXPECTED_PATH -fmodules-ignore-macro=DIRECT -fsyntax-only %s -verify -I %S/Inputs/modules-with-same-name/path2/A -DDIRECT -DEXPECTED_PATH=2 + +// Confirm that we have two pcm files (one for each 'A'). +// RUN: find %t -name "A-*.pcm" | count 2 + +// DependsOnA, using A from path 1 +// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fmodules-ignore-macro=EXPECTED_PATH -fmodules-ignore-macro=DIRECT -fsyntax-only %s -verify -I %S/Inputs/modules-with-same-name/DependsOnA -I %S/Inputs/modules-with-same-name/path1/A -DEXPECTED_PATH=1 + +// Confirm that we have three pcm files (one for each 'A', and one for 'DependsOnA') +// RUN: find %t -name "*.pcm" | count 3 + +// DependsOnA, using A from path 2 +// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fmodules-ignore-macro=EXPECTED_PATH -fmodules-ignore-macro=DIRECT -fsyntax-only %s -verify -I %S/Inputs/modules-with-same-name/DependsOnA -I %S/Inputs/modules-with-same-name/path2/A -DEXPECTED_PATH=2 + +// Confirm that we still have three pcm files, since DependsOnA will be rebuilt +// RUN: find %t -name "*.pcm" | count 3 + +#ifdef DIRECT +@import A; +#else +@import DependsOnA; +#endif + +#if FROM_PATH != EXPECTED_PATH +#error "Got the wrong module!" +#endif + +// expected-no-diagnostics diff --git a/test/Modules/prune.m b/test/Modules/prune.m index 8af7e6c395..4901792589 100644 --- a/test/Modules/prune.m +++ b/test/Modules/prune.m @@ -14,33 +14,33 @@ // RUN: %clang_cc1 -DIMPORT_DEPENDS_ON_MODULE -fmodules-ignore-macro=DIMPORT_DEPENDS_ON_MODULE -fmodules -F %S/Inputs -fmodules-cache-path=%t %s -verify // RUN: %clang_cc1 -DIMPORT_DEPENDS_ON_MODULE -fmodules-ignore-macro=DIMPORT_DEPENDS_ON_MODULE -fmodules -F %S/Inputs -fmodules-cache-path=%t %s -verify // RUN: ls %t | grep modules.timestamp -// RUN: ls -R %t | grep ^Module.pcm -// RUN: ls -R %t | grep DependsOnModule.pcm +// RUN: ls -R %t | grep ^Module.*pcm +// RUN: ls -R %t | grep DependsOnModule.*pcm // Set the timestamp back more than two days. We should try to prune, // but nothing gets pruned because the module files are new enough. // RUN: touch -m -a -t 201101010000 %t/modules.timestamp // RUN: %clang_cc1 -fmodules -F %S/Inputs -fmodules-cache-path=%t -fmodules -fmodules-prune-interval=172800 -fmodules-prune-after=345600 %s -verify // RUN: ls %t | grep modules.timestamp -// RUN: ls -R %t | grep ^Module.pcm -// RUN: ls -R %t | grep DependsOnModule.pcm +// RUN: ls -R %t | grep ^Module.*pcm +// RUN: ls -R %t | grep DependsOnModule.*pcm // Set the DependsOnModule access time back more than four days. // This shouldn't prune anything, because the timestamp has been updated, so // the pruning mechanism won't fire. -// RUN: find %t -name DependsOnModule.pcm | xargs touch -a -t 201101010000 +// RUN: find %t -name DependsOnModule*.pcm | xargs touch -a -t 201101010000 // RUN: %clang_cc1 -fmodules -F %S/Inputs -fmodules-cache-path=%t -fmodules -fmodules-prune-interval=172800 -fmodules-prune-after=345600 %s -verify // RUN: ls %t | grep modules.timestamp -// RUN: ls -R %t | grep ^Module.pcm -// RUN: ls -R %t | grep DependsOnModule.pcm +// RUN: ls -R %t | grep ^Module.*pcm +// RUN: ls -R %t | grep DependsOnModule.*pcm // Set both timestamp and DependsOnModule.pcm back beyond the cutoff. // This should trigger pruning, which will remove DependsOnModule but not Module. // RUN: touch -m -a -t 201101010000 %t/modules.timestamp -// RUN: find %t -name DependsOnModule.pcm | xargs touch -a -t 201101010000 +// RUN: find %t -name DependsOnModule..pcm | xargs touch -a -t 201101010000 // RUN: %clang_cc1 -fmodules -F %S/Inputs -fmodules-cache-path=%t -fmodules -fmodules-prune-interval=172800 -fmodules-prune-after=345600 %s -verify // RUN: ls %t | grep modules.timestamp -// RUN: ls -R %t | grep ^Module.pcm -// RUN: ls -R %t | not grep DependsOnModule.pcm +// RUN: ls -R %t | grep ^Module.*pcm +// RUN: ls -R %t | not grep DependsOnModule.*pcm // expected-no-diagnostics diff --git a/test/Modules/redecls/main.m b/test/Modules/redecls/main.m index 8236092956..bf3788a96d 100644 --- a/test/Modules/redecls/main.m +++ b/test/Modules/redecls/main.m @@ -3,7 +3,7 @@ // RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodule-name=b %S/module.map -fmodules-cache-path=%t.mcp // RUN: %clang_cc1 -fmodules %s -emit-pch -o %t1.pch -fmodules-cache-path=%t.mcp -I %S // RUN: %clang_cc1 -fmodules %s -emit-pch -o %t2.pch -include-pch %t1.pch -fmodules-cache-path=%t.mcp -I %S -// RUN: %clang_cc1 -fmodules %s -fsyntax-only -include-pch %t2.pch -fmodules-cache-path=%t.mcp -verify +// RUN: %clang_cc1 -fmodules %s -fsyntax-only -include-pch %t2.pch -I %S -fmodules-cache-path=%t.mcp -verify #ifndef HEADER1 #define HEADER1 diff --git a/test/Modules/resolution-change.m b/test/Modules/resolution-change.m new file mode 100644 index 0000000000..a69014c6ae --- /dev/null +++ b/test/Modules/resolution-change.m @@ -0,0 +1,24 @@ +// RUN: rm -rf %t + +// Build PCH using A from path 1 +// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -I %S/Inputs/modules-with-same-name/DependsOnA -I %S/Inputs/modules-with-same-name/path1/A -emit-pch -o %t-A.pch %s + +// Use the PCH with the same header search options; should be fine +// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -I %S/Inputs/modules-with-same-name/DependsOnA -I %S/Inputs/modules-with-same-name/path1/A -include-pch %t-A.pch %s -fsyntax-only -Werror + +// Use the PCH with no way to resolve DependsOnA +// RUN: not %clang_cc1 -fmodules -fmodules-cache-path=%t -include-pch %t-A.pch %s -fsyntax-only 2>&1 | FileCheck -check-prefix=CHECK-NODOA %s +// CHECK-NODOA: module 'DependsOnA' imported by AST file '{{.*A.pch}}' not found + +// Use the PCH with no way to resolve A +// RUN: not %clang_cc1 -fmodules -fmodules-cache-path=%t -I %S/Inputs/modules-with-same-name/DependsOnA -include-pch %t-A.pch %s -fsyntax-only 2>&1 | FileCheck -check-prefix=CHECK-NOA %s +// CHECK-NOA: module 'A' imported by AST file '{{.*DependsOnA.*pcm}}' not found + +// Use the PCH and have it resolve the the other A +// RUN: not %clang_cc1 -fmodules -fmodules-cache-path=%t -I %S/Inputs/modules-with-same-name/DependsOnA -I %S/Inputs/modules-with-same-name/path2/A -include-pch %t-A.pch %s -fsyntax-only 2>&1 | FileCheck -check-prefix=CHECK-WRONGA %s +// CHECK-WRONGA: module 'A' imported by AST file '{{.*DependsOnA.*pcm}}' found in a different module map file ({{.*path2.*}}) than when the importing AST file was built ({{.*path1.*}}) + +#ifndef HEADER +#define HEADER +@import DependsOnA; +#endif diff --git a/test/Modules/system_version.m b/test/Modules/system_version.m index 85b3263f72..bc82bf8bc1 100644 --- a/test/Modules/system_version.m +++ b/test/Modules/system_version.m @@ -11,21 +11,21 @@ // Run once with no system version file. We should end up with one module. // RUN: %clang_cc1 -fmodules-cache-path=%t/cache -fmodules -isysroot %t -I %t/usr/include %s -verify -// RUN: ls -R %t | grep -c ModA.pcm| grep 1 +// RUN: ls -R %t | grep -c "ModA.*pcm" | grep 1 // Add a system version file and run again. We should now have two // module variants. // RUN: mkdir -p %t/System/Library/CoreServices // RUN: echo "hello" > %t/System/Library/CoreServices/SystemVersion.plist // RUN: %clang_cc1 -fmodules-cache-path=%t/cache -fmodules -isysroot %t -I %t/usr/include %s -verify -// RUN: ls -R %t | grep -c ModA.pcm| grep 2 +// RUN: ls -R %t | grep -c "ModA.*pcm" | grep 2 // Change the system version file and run again. We should now have three // module variants. // RUN: mkdir -p %t/System/Library/CoreServices // RUN: echo "modules" > %t/System/Library/CoreServices/SystemVersion.plist // RUN: %clang_cc1 -fmodules-cache-path=%t/cache -fmodules -isysroot %t -I %t/usr/include %s -verify -// RUN: ls -R %t | grep -c ModA.pcm| grep 3 +// RUN: ls -R %t | grep -c "ModA.*pcm" | grep 3 // expected-no-diagnostics @import ModA; diff --git a/test/PCH/modified-module-dependency.m b/test/PCH/modified-module-dependency.m index 650eaddacd..3db8f3d9c7 100644 --- a/test/PCH/modified-module-dependency.m +++ b/test/PCH/modified-module-dependency.m @@ -5,13 +5,13 @@ // RUN: cp %S/modified-module-dependency.module.map %t-dir/module.map // Precompile prefix.pch. -// RUN: %clang_cc1 -x objective-c -I %t-dir -fmodules -fmodules-cache-path=%t-dir/cache -emit-pch %t-dir/prefix.h -o %t-dir/prefix.pch +// RUN: %clang_cc1 -x objective-c -I %t-dir -fmodules -fmodules-cache-path=%t-dir/cache -fdisable-module-hash -emit-pch %t-dir/prefix.h -o %t-dir/prefix.pch // Modify the dependency. // RUN: echo ' ' >> %t-dir/test.h // Run and check the diagnostics. -// RUN: not %clang_cc1 -x objective-c -include-pch %t-dir/prefix.pch -fmodules -fmodules-cache-path=%t-dir/cache -fsyntax-only %s 2> %t-dir/log +// RUN: not %clang_cc1 -x objective-c -I %t-dir -include-pch %t-dir/prefix.pch -fmodules -fmodules-cache-path=%t-dir/cache -fdisable-module-hash -fsyntax-only %s 2> %t-dir/log // RUN: FileCheck %s < %t-dir/log // CHECK: file '[[TEST_H:.*[/\\]test\.h]]' has been modified since the precompiled header '[[PREFIX_PCH:.*/prefix\.pch]]' was built -- 2.50.1