From: Ben Langmuir Date: Mon, 14 Apr 2014 18:00:01 +0000 (+0000) Subject: Allow multiple modules with the same name to coexist in the module cache X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ef1b5dcd49061f669fd4565fa48a3e8d85fd7c73;p=clang Allow multiple modules with the same name to coexist in the module cache 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 --- 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