]> granicus.if.org Git - clang/commitdiff
[modules] Track how 'header' directives were written in module map files,
authorRichard Smith <richard-llvm@metafoo.co.uk>
Tue, 2 Dec 2014 00:08:08 +0000 (00:08 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Tue, 2 Dec 2014 00:08:08 +0000 (00:08 +0000)
rather than trying to extract this information from the FileEntry after the
fact.

This has a number of beneficial effects. For instance, diagnostic messages for
failed module builds give a path relative to the "module root" rather than an
absolute file path, and the contents of the module includes file is no longer
dependent on what files the including TU happened to inspect prior to
triggering the module build.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@223095 91177308-0d34-0410-b5e6-96231b3b80d8

13 files changed:
include/clang/Basic/Module.h
include/clang/Lex/ModuleMap.h
include/clang/Lex/Preprocessor.h
lib/Basic/Module.cpp
lib/Frontend/CompilerInstance.cpp
lib/Frontend/FrontendActions.cpp
lib/Lex/HeaderSearch.cpp
lib/Lex/ModuleMap.cpp
lib/Lex/PPDirectives.cpp
lib/Lex/Preprocessor.cpp
lib/Serialization/ASTReader.cpp
lib/Serialization/ASTWriter.cpp
test/Modules/malformed.cpp

index e46be9edca5e55846e3a8980bb0f3cea486357f7..e3953a4571fad44cf15c3a892708c2b1a7fbca54 100644 (file)
@@ -55,7 +55,12 @@ public:
   /// \brief The parent of this module. This will be NULL for the top-level
   /// module.
   Module *Parent;
-  
+
+  /// \brief The build directory of this module. This is the directory in
+  /// which the module is notionally built, and relative to which its headers
+  /// are found.
+  const DirectoryEntry *Directory;
+
   /// \brief The umbrella header or directory.
   llvm::PointerUnion<const DirectoryEntry *, const FileEntry *> Umbrella;
   
@@ -81,26 +86,28 @@ private:
   mutable llvm::DenseSet<const Module*> VisibleModulesCache;
 
 public:
-  /// \brief The headers that are part of this module.
-  SmallVector<const FileEntry *, 2> NormalHeaders;
-
-  /// \brief The headers that are logically part of this module but
-  /// must be textually included.
-  SmallVector<const FileEntry *, 2> TextualHeaders;
-
-  /// \brief The headers that are private to this module.
-  SmallVector<const FileEntry *, 2> PrivateHeaders;
-
-  /// \brief The headers that are private to this module and are to be
-  /// included textually.
-  SmallVector<const FileEntry *, 2> PrivateTextualHeaders;
-
-  /// \brief The headers that are explicitly excluded from this module.
-  SmallVector<const FileEntry *, 2> ExcludedHeaders;
+  enum HeaderKind {
+    HK_Normal,
+    HK_Textual,
+    HK_Private,
+    HK_PrivateTextual,
+    HK_Excluded
+  };
+  static const int NumHeaderKinds = HK_Excluded + 1;
 
   /// \brief Information about a header directive as found in the module map
   /// file.
-  struct HeaderDirective {
+  struct Header {
+    std::string NameAsWritten;
+    const FileEntry *Entry;
+  };
+
+  /// \brief The headers that are part of this module.
+  SmallVector<Header, 2> Headers[5];
+
+  /// \brief Stored information about a header directive that was found in the
+  /// module map file but has not been resolved to a file.
+  struct UnresolvedHeaderDirective {
     SourceLocation FileNameLoc;
     std::string FileName;
     bool IsUmbrella;
@@ -108,7 +115,7 @@ public:
 
   /// \brief Headers that are mentioned in the module map file but could not be
   /// found on the file system.
-  SmallVector<HeaderDirective, 1> MissingHeaders;
+  SmallVector<UnresolvedHeaderDirective, 1> MissingHeaders;
 
   /// \brief An individual requirement: a feature name and a flag indicating
   /// the required state of that feature.
@@ -303,7 +310,7 @@ public:
   bool isAvailable(const LangOptions &LangOpts, 
                    const TargetInfo &Target,
                    Requirement &Req,
-                   HeaderDirective &MissingHeader) const;
+                   UnresolvedHeaderDirective &MissingHeader) const;
 
   /// \brief Determine whether this module is a submodule.
   bool isSubModule() const { return Parent != nullptr; }
index 553716b8f65a44bb22ab8f4e896879c0277f0421..aad83c1fce28b53da713ae9d8041b4364e305a4e 100644 (file)
@@ -440,11 +440,11 @@ public:
 
   /// \brief Adds this header to the given module.
   /// \param Role The role of the header wrt the module.
-  void addHeader(Module *Mod, const FileEntry *Header,
+  void addHeader(Module *Mod, Module::Header Header,
                  ModuleHeaderRole Role);
 
   /// \brief Marks this header as being excluded from the given module.
-  void excludeHeader(Module *Mod, const FileEntry *Header);
+  void excludeHeader(Module *Mod, Module::Header Header);
 
   /// \brief Parse the given module map file, and record any modules we 
   /// encounter.
index d16f2128164c67af3a78c254fdf9749db3dd57b3..cfbc2c8091a244f8b4de0fab559e1c5b4e99b972 100644 (file)
@@ -257,6 +257,11 @@ class Preprocessor : public RefCountedBase<Preprocessor> {
   /// \brief True if we hit the code-completion point.
   bool CodeCompletionReached;
 
+  /// \brief The directory that the main file should be considered to occupy,
+  /// if it does not correspond to a real file (as happens when building a
+  /// module).
+  const DirectoryEntry *MainFileDir;
+
   /// \brief The number of bytes that we will initially skip when entering the
   /// main file, along with a flag that indicates whether skipping this number
   /// of bytes will place the lexer at the start of a line.
@@ -1014,6 +1019,12 @@ public:
     PragmaARCCFCodeAuditedLoc = Loc;
   }
 
+  /// \brief Set the directory in which the main file should be considered
+  /// to have been found, if it is not a real file.
+  void setMainFileDir(const DirectoryEntry *Dir) {
+    MainFileDir = Dir;
+  }
+
   /// \brief Instruct the preprocessor to skip part of the main source file.
   ///
   /// \param Bytes The number of bytes in the preamble to skip.
index c0f5a6afa1060fa675e5fc6bb3558d45ad274cad..ba3526c334f18e9ab7820c1dcceac666b3b9412d 100644 (file)
@@ -26,7 +26,7 @@ using namespace clang;
 
 Module::Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent,
                bool IsFramework, bool IsExplicit)
-    : Name(Name), DefinitionLoc(DefinitionLoc), Parent(Parent),
+    : Name(Name), DefinitionLoc(DefinitionLoc), Parent(Parent), Directory(),
       Umbrella(), ASTFile(nullptr), IsMissingRequirement(false),
       IsAvailable(true), IsFromModuleFile(false), IsFramework(IsFramework),
       IsExplicit(IsExplicit), IsSystem(false), IsExternC(false),
@@ -70,9 +70,9 @@ static bool hasFeature(StringRef Feature, const LangOptions &LangOpts,
            .Default(Target.hasFeature(Feature));
 }
 
-bool
-Module::isAvailable(const LangOptions &LangOpts, const TargetInfo &Target,
-                    Requirement &Req, HeaderDirective &MissingHeader) const {
+bool Module::isAvailable(const LangOptions &LangOpts, const TargetInfo &Target,
+                         Requirement &Req,
+                         UnresolvedHeaderDirective &MissingHeader) const {
   if (IsAvailable)
     return true;
 
@@ -338,19 +338,20 @@ void Module::print(raw_ostream &OS, unsigned Indent) const {
     OS << "\n";
   }
 
-  struct HeaderKind {
+  struct {
     StringRef Prefix;
-    const SmallVectorImpl<const FileEntry *> &Headers;
-  } Kinds[] = {{"", NormalHeaders},
-               {"exclude ", ExcludedHeaders},
-               {"textual ", TextualHeaders},
-               {"private ", PrivateHeaders}};
+    HeaderKind Kind;
+  } Kinds[] = {{"", HK_Normal},
+               {"textual ", HK_Textual},
+               {"private ", HK_Private},
+               {"private textual ", HK_PrivateTextual},
+               {"exclude ", HK_Excluded}};
 
   for (auto &K : Kinds) {
-    for (auto *H : K.Headers) {
+    for (auto &H : Headers[K.Kind]) {
       OS.indent(Indent + 2);
       OS << K.Prefix << "header \"";
-      OS.write_escaped(H->getName());
+      OS.write_escaped(H.NameAsWritten);
       OS << "\"\n";
     }
   }
index b059965f2f0d7ca4e0fafcc38a3bc194a4b603b4..dcc824723aa0ebcfbc76a4a425c487e17b1591bf 100644 (file)
@@ -1552,7 +1552,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
 
     // Check whether this module is available.
     clang::Module::Requirement Requirement;
-    clang::Module::HeaderDirective MissingHeader;
+    clang::Module::UnresolvedHeaderDirective MissingHeader;
     if (!Module->isAvailable(getLangOpts(), getTarget(), Requirement,
                              MissingHeader)) {
       if (MissingHeader.FileNameLoc.isValid()) {
@@ -1581,9 +1581,16 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
                      Module, ImportLoc);
   }
 
+  // Determine whether we're in the #include buffer for a module. The #includes
+  // in that buffer do not qualify as module imports; they're just an
+  // implementation detail of us building the module.
+  bool IsInModuleIncludes = !getLangOpts().CurrentModule.empty() &&
+                            getSourceManager().getFileID(ImportLoc) ==
+                                getSourceManager().getMainFileID();
+
   // If this module import was due to an inclusion directive, create an 
   // implicit import declaration to capture it in the AST.
-  if (IsInclusionDirective && hasASTContext()) {
+  if (IsInclusionDirective && hasASTContext() && !IsInModuleIncludes) {
     TranslationUnitDecl *TU = getASTContext().getTranslationUnitDecl();
     ImportDecl *ImportD = ImportDecl::CreateImplicit(getASTContext(), TU,
                                                      ImportLoc, Module,
index 6a2ac60570d3d48ae192b56c02ddf493f1c53aa4..701ef026d49c0928eabba27c13931a7e9bba37cf 100644 (file)
@@ -142,17 +142,9 @@ static std::error_code addHeaderInclude(StringRef HeaderName,
     Includes += "#import \"";
   else
     Includes += "#include \"";
-  // Use an absolute path for the include; there's no reason to think that
-  // a relative path will work (. might not be on our include path) or that
-  // it will find the same file.
-  if (llvm::sys::path::is_absolute(HeaderName)) {
-    Includes += HeaderName;
-  } else {
-    SmallString<256> Header = HeaderName;
-    if (std::error_code Err = llvm::sys::fs::make_absolute(Header))
-      return Err;
-    Includes += Header;
-  }
+
+  Includes += HeaderName;
+
   Includes += "\"\n";
   if (IsExternC && LangOpts.CPlusPlus)
     Includes += "}\n";
@@ -163,7 +155,16 @@ static std::error_code addHeaderInclude(const FileEntry *Header,
                                         SmallVectorImpl<char> &Includes,
                                         const LangOptions &LangOpts,
                                         bool IsExternC) {
-  return addHeaderInclude(Header->getName(), Includes, LangOpts, IsExternC);
+  // Use an absolute path if we don't have a filename as written in the module
+  // map file; this ensures that we will identify the right file independent of
+  // header search paths.
+  if (llvm::sys::path::is_absolute(Header->getName()))
+    return addHeaderInclude(Header->getName(), Includes, LangOpts, IsExternC);
+
+  SmallString<256> AbsName(Header->getName());
+  if (std::error_code Err = llvm::sys::fs::make_absolute(AbsName))
+    return Err;
+  return addHeaderInclude(AbsName, Includes, LangOpts, IsExternC);
 }
 
 /// \brief Collect the set of header includes needed to construct the given 
@@ -182,16 +183,20 @@ collectModuleHeaderIncludes(const LangOptions &LangOpts, FileManager &FileMgr,
     return std::error_code();
 
   // Add includes for each of these headers.
-  for (unsigned I = 0, N = Module->NormalHeaders.size(); I != N; ++I) {
-    const FileEntry *Header = Module->NormalHeaders[I];
-    Module->addTopHeader(Header);
-    if (std::error_code Err =
-            addHeaderInclude(Header, Includes, LangOpts, Module->IsExternC))
+  for (Module::Header &H : Module->Headers[Module::HK_Normal]) {
+    Module->addTopHeader(H.Entry);
+    // Use the path as specified in the module map file. We'll look for this
+    // file relative to the module build directory (the directory containing
+    // the module map file) so this will find the same file that we found
+    // while parsing the module map.
+    if (std::error_code Err = addHeaderInclude(H.NameAsWritten, Includes,
+                                               LangOpts, Module->IsExternC))
       return Err;
   }
   // Note that Module->PrivateHeaders will not be a TopHeader.
 
   if (const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader()) {
+    // FIXME: Track the name as written here.
     Module->addTopHeader(UmbrellaHeader);
     if (Module->Parent) {
       // Include the umbrella header for submodules.
@@ -213,25 +218,30 @@ collectModuleHeaderIncludes(const LangOptions &LangOpts, FileManager &FileMgr,
           .Cases(".h", ".H", ".hh", ".hpp", true)
           .Default(false))
         continue;
-      
+
+      const FileEntry *Header = FileMgr.getFile(Dir->path());
+      // FIXME: This shouldn't happen unless there is a file system race. Is
+      // that worth diagnosing?
+      if (!Header)
+        continue;
+
       // If this header is marked 'unavailable' in this module, don't include 
       // it.
-      if (const FileEntry *Header = FileMgr.getFile(Dir->path())) {
-        if (ModMap.isHeaderUnavailableInModule(Header, Module))
-          continue;
-        Module->addTopHeader(Header);
-      }
-      
+      if (ModMap.isHeaderUnavailableInModule(Header, Module))
+        continue;
+
       // Include this header as part of the umbrella directory.
-      if (std::error_code Err = addHeaderInclude(Dir->path(), Includes,
-                                                 LangOpts, Module->IsExternC))
+      // FIXME: Track the name as written through to here.
+      Module->addTopHeader(Header);
+      if (std::error_code Err =
+              addHeaderInclude(Header, Includes, LangOpts, Module->IsExternC))
         return Err;
     }
 
     if (EC)
       return EC;
   }
-  
+
   // Recurse into submodules.
   for (clang::Module::submodule_iterator Sub = Module->submodule_begin(),
                                       SubEnd = Module->submodule_end();
@@ -288,7 +298,7 @@ bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI,
 
   // Check whether we can build this module at all.
   clang::Module::Requirement Requirement;
-  clang::Module::HeaderDirective MissingHeader;
+  clang::Module::UnresolvedHeaderDirective MissingHeader;
   if (!Module->isAvailable(CI.getLangOpts(), CI.getTarget(), Requirement,
                            MissingHeader)) {
     if (MissingHeader.FileNameLoc.isValid()) {
@@ -317,6 +327,7 @@ bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI,
   SmallString<256> HeaderContents;
   std::error_code Err = std::error_code();
   if (const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader())
+    // FIXME: Track the file name as written.
     Err = addHeaderInclude(UmbrellaHeader, HeaderContents, CI.getLangOpts(),
                            Module->IsExternC);
   if (!Err)
@@ -331,6 +342,10 @@ bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI,
     return false;
   }
 
+  // Inform the preprocessor that includes from within the input buffer should
+  // be resolved relative to the build directory of the module map file.
+  CI.getPreprocessor().setMainFileDir(Module->Directory);
+
   std::unique_ptr<llvm::MemoryBuffer> InputBuffer =
       llvm::MemoryBuffer::getMemBufferCopy(HeaderContents,
                                            Module::getModuleInputBufferName());
index 125fe260e133f1d11341b7200c543edf1fc48f7d..131f6aa09cf824f747c927d0d76645bfec782dcc 100644 (file)
@@ -624,11 +624,20 @@ const FileEntry *HeaderSearch::LookupFile(
       // FIXME: We don't cache the result of getFileInfo across the call to
       // getFileAndSuggestModule, because it's a reference to an element of
       // a container that could be reallocated across this call.
+      //
+      // FIXME: If we have no includer, that means we're processing a #include
+      // from a module build. We should treat this as a system header if we're
+      // building a [system] module.
       bool IncluderIsSystemHeader =
-          getFileInfo(Includer).DirInfo != SrcMgr::C_User;
+          Includer && getFileInfo(Includer).DirInfo != SrcMgr::C_User;
       if (const FileEntry *FE = getFileAndSuggestModule(
               *this, TmpDir.str(), IncluderAndDir.second,
               IncluderIsSystemHeader, SuggestedModule)) {
+        if (!Includer) {
+          assert(First && "only first includer can have no file");
+          return FE;
+        }
+
         // Leave CurDir unset.
         // This file is a system header or C++ unfriendly if the old file is.
         //
@@ -770,7 +779,7 @@ const FileEntry *HeaderSearch::LookupFile(
   // a header in a framework that is currently being built, and we couldn't
   // resolve "foo.h" any other way, change the include to <Foo/foo.h>, where
   // "Foo" is the name of the framework in which the including header was found.
-  if (!Includers.empty() && !isAngled &&
+  if (!Includers.empty() && Includers.front().first && !isAngled &&
       Filename.find('/') == StringRef::npos) {
     HeaderFileInfo &IncludingHFI = getFileInfo(Includers.front().first);
     if (IncludingHFI.IndexHeaderMapHeader) {
@@ -1079,7 +1088,9 @@ bool HeaderSearch::hasModuleMap(StringRef FileName,
       return false;
 
     // Try to load the module map file in this directory.
-    switch (loadModuleMapFile(Dir, IsSystem, /*IsFramework*/false)) {
+    switch (loadModuleMapFile(Dir, IsSystem,
+                              llvm::sys::path::extension(Dir->getName()) ==
+                                  ".framework")) {
     case LMM_NewlyLoaded:
     case LMM_AlreadyLoaded:
       // Success. All of the directories we stepped through inherit this module
index 6a470ef886c526a2b608cea54032c4b663b306d0..a270b56e6af35b5fd9ed68aa975790a29eabdc84 100644 (file)
@@ -220,12 +220,14 @@ static bool violatesPrivateInclude(Module *RequestingModule,
   // as obtained from the lookup and as obtained from the module.
   // This check is not cheap, so enable it only for debugging.
   bool IsPrivate = false;
-  SmallVectorImpl<const FileEntry *> *HeaderList[] =
-      {&RequestedModule->PrivateHeaders,
-       &RequestedModule->PrivateTextualHeaders};
+  SmallVectorImpl<Module::Header> *HeaderList[] =
+      {&RequestedModule->Headers[Module::HK_Private],
+       &RequestedModule->Headers[Module::HK_PrivateTextual]};
   for (auto *Hdrs : HeaderList)
     IsPrivate |=
-        std::find(Hdrs->begin(), Hdrs->end(), IncFileEnt) != Hdrs->end();
+        std::find_if(Hdrs->begin(), Hdrs->end(), [&](const Module::Header &H) {
+          return H.Entry == IncFileEnt;
+        }) != Hdrs->end();
   assert(IsPrivate == IsPrivateRole && "inconsistent headers and roles");
 #endif
   return IsPrivateRole &&
@@ -778,40 +780,40 @@ void ModuleMap::setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir) {
   UmbrellaDirs[UmbrellaDir] = Mod;
 }
 
-void ModuleMap::addHeader(Module *Mod, const FileEntry *Header,
-                          ModuleHeaderRole Role) {
+static Module::HeaderKind headerRoleToKind(ModuleMap::ModuleHeaderRole Role) {
   switch ((int)Role) {
-  default:
-    llvm_unreachable("unknown header role");
-  case NormalHeader:
-    Mod->NormalHeaders.push_back(Header);
-    break;
-  case PrivateHeader:
-    Mod->PrivateHeaders.push_back(Header);
-    break;
-  case TextualHeader:
-    Mod->TextualHeaders.push_back(Header);
-    break;
-  case PrivateHeader | TextualHeader:
-    Mod->PrivateTextualHeaders.push_back(Header);
-    break;
+  default: llvm_unreachable("unknown header role");
+  case ModuleMap::NormalHeader:
+    return Module::HK_Normal;
+  case ModuleMap::PrivateHeader:
+    return Module::HK_Private;
+  case ModuleMap::TextualHeader:
+    return Module::HK_Textual;
+  case ModuleMap::PrivateHeader | ModuleMap::TextualHeader:
+    return Module::HK_PrivateTextual;
   }
+}
 
+void ModuleMap::addHeader(Module *Mod, Module::Header Header,
+                          ModuleHeaderRole Role) {
   if (!(Role & TextualHeader)) {
     bool isCompilingModuleHeader = Mod->getTopLevelModule() == CompilingModule;
-    HeaderInfo.MarkFileModuleHeader(Header, Role, isCompilingModuleHeader);
+    HeaderInfo.MarkFileModuleHeader(Header.Entry, Role,
+                                    isCompilingModuleHeader);
   }
-  Headers[Header].push_back(KnownHeader(Mod, Role));
-}
+  Headers[Header.Entry].push_back(KnownHeader(Mod, Role));
 
-void ModuleMap::excludeHeader(Module *Mod, const FileEntry *Header) {
-  Mod->ExcludedHeaders.push_back(Header);
+  Mod->Headers[headerRoleToKind(Role)].push_back(std::move(Header));
+}
 
+void ModuleMap::excludeHeader(Module *Mod, Module::Header Header) {
   // Add this as a known header so we won't implicitly add it to any
   // umbrella directory module.
   // FIXME: Should we only exclude it from umbrella modules within the
   // specified module?
-  (void) Headers[Header];
+  (void) Headers[Header.Entry];
+
+  Mod->Headers[Module::HK_Excluded].push_back(std::move(Header));
 }
 
 const FileEntry *
@@ -1447,6 +1449,7 @@ void ModuleMapParser::parseModuleDecl() {
     ActiveModule->IsSystem = true;
   if (Attrs.IsExternC)
     ActiveModule->IsExternC = true;
+  ActiveModule->Directory = Directory;
 
   bool Done = false;
   do {
@@ -1699,7 +1702,7 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
     HadError = true;
     return;
   }
-  Module::HeaderDirective Header;
+  Module::UnresolvedHeaderDirective Header;
   Header.FileName = Tok.getString();
   Header.FileNameLoc = consumeToken();
   
@@ -1714,33 +1717,39 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
   // Look for this file.
   const FileEntry *File = nullptr;
   const FileEntry *BuiltinFile = nullptr;
-  SmallString<128> PathName;
+  SmallString<128> RelativePathName;
   if (llvm::sys::path::is_absolute(Header.FileName)) {
-    PathName = Header.FileName;
-    File = SourceMgr.getFileManager().getFile(PathName);
+    RelativePathName = Header.FileName;
+    File = SourceMgr.getFileManager().getFile(RelativePathName);
   } else {
     // Search for the header file within the search directory.
-    PathName = Directory->getName();
-    unsigned PathLength = PathName.size();
+    SmallString<128> FullPathName(Directory->getName());
+    unsigned FullPathLength = FullPathName.size();
     
     if (ActiveModule->isPartOfFramework()) {
-      appendSubframeworkPaths(ActiveModule, PathName);
+      appendSubframeworkPaths(ActiveModule, RelativePathName);
       
       // Check whether this file is in the public headers.
-      llvm::sys::path::append(PathName, "Headers", Header.FileName);
-      File = SourceMgr.getFileManager().getFile(PathName);
+      llvm::sys::path::append(RelativePathName, "Headers", Header.FileName);
+      llvm::sys::path::append(FullPathName, RelativePathName.str());
+      File = SourceMgr.getFileManager().getFile(FullPathName);
       
       if (!File) {
         // Check whether this file is in the private headers.
-        PathName.resize(PathLength);
-        llvm::sys::path::append(PathName, "PrivateHeaders", Header.FileName);
-        File = SourceMgr.getFileManager().getFile(PathName);
+        // FIXME: Should we retain the subframework paths here?
+        RelativePathName.clear();
+        FullPathName.resize(FullPathLength);
+        llvm::sys::path::append(RelativePathName, "PrivateHeaders",
+                                Header.FileName);
+        llvm::sys::path::append(FullPathName, RelativePathName.str());
+        File = SourceMgr.getFileManager().getFile(FullPathName);
       }
     } else {
       // Lookup for normal headers.
-      llvm::sys::path::append(PathName, Header.FileName);
-      File = SourceMgr.getFileManager().getFile(PathName);
-      
+      llvm::sys::path::append(RelativePathName, Header.FileName);
+      llvm::sys::path::append(FullPathName, RelativePathName.str());
+      File = SourceMgr.getFileManager().getFile(FullPathName);
+
       // If this is a system module with a top-level header, this header
       // may have a counterpart (or replacement) in the set of headers
       // supplied by Clang. Find that builtin header.
@@ -1750,18 +1759,19 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
         SmallString<128> BuiltinPathName(BuiltinIncludeDir->getName());
         llvm::sys::path::append(BuiltinPathName, Header.FileName);
         BuiltinFile = SourceMgr.getFileManager().getFile(BuiltinPathName);
-        
+
         // If Clang supplies this header but the underlying system does not,
         // just silently swap in our builtin version. Otherwise, we'll end
         // up adding both (later).
         if (!File && BuiltinFile) {
           File = BuiltinFile;
+          RelativePathName = BuiltinPathName;
           BuiltinFile = nullptr;
         }
       }
     }
   }
-  
+
   // FIXME: We shouldn't be eagerly stat'ing every file named in a module map.
   // Come up with a lazy way to do this.
   if (File) {
@@ -1776,16 +1786,23 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
         Map.setUmbrellaHeader(ActiveModule, File);
       }
     } else if (LeadingToken == MMToken::ExcludeKeyword) {
-      Map.excludeHeader(ActiveModule, File);
+      Map.excludeHeader(ActiveModule,
+                        Module::Header{RelativePathName.str(), File});
     } else {
       // If there is a builtin counterpart to this file, add it now, before
       // the "real" header, so we build the built-in one first when building
       // the module.
       if (BuiltinFile)
-        Map.addHeader(ActiveModule, BuiltinFile, Role);
+        // FIXME: Taking the name from the FileEntry is unstable and can give
+        // different results depending on how we've previously named that file
+        // in this build.
+        Map.addHeader(ActiveModule,
+                      Module::Header{BuiltinFile->getName(), BuiltinFile},
+                      Role);
 
       // Record this header.
-      Map.addHeader(ActiveModule, File, Role);
+      Map.addHeader(ActiveModule, Module::Header{RelativePathName.str(), File},
+                    Role);
     }
   } else if (LeadingToken != MMToken::ExcludeKeyword) {
     // Ignore excluded header files. They're optional anyway.
index 04f3b29bd5b7c1db7c987ecad0135fe907ede5c4..0a46663d85de2573958cd293a40bd48d8824514b 100644 (file)
@@ -550,14 +550,22 @@ const FileEntry *Preprocessor::LookupFile(
     const FileEntry *FileEnt = SourceMgr.getFileEntryForID(FID);
 
     // If there is no file entry associated with this file, it must be the
-    // predefines buffer.  Any other file is not lexed with a normal lexer, so
-    // it won't be scanned for preprocessor directives.   If we have the
-    // predefines buffer, resolve #include references (which come from the
-    // -include command line argument) from the current working directory
-    // instead of relative to the main file.
+    // predefines buffer or the module includes buffer. Any other file is not
+    // lexed with a normal lexer, so it won't be scanned for preprocessor
+    // directives.
+    //
+    // If we have the predefines buffer, resolve #include references (which come
+    // from the -include command line argument) from the current working
+    // directory instead of relative to the main file.
+    //
+    // If we have the module includes buffer, resolve #include references (which
+    // come from header declarations in the module map) relative to the module
+    // map file.
     if (!FileEnt) {
-      FileEnt = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID());
-      if (FileEnt)
+      if (FID == SourceMgr.getMainFileID() && MainFileDir)
+        Includers.push_back(std::make_pair(nullptr, MainFileDir));
+      else if ((FileEnt =
+                    SourceMgr.getFileEntryForID(SourceMgr.getMainFileID())))
         Includers.push_back(std::make_pair(FileEnt, FileMgr.getDirectory(".")));
     } else {
       Includers.push_back(std::make_pair(FileEnt, FileEnt->getDir()));
index 5da54aea30f730063e83aaf1d0f1ab2b99b4a3d7..63c9aec8554f17ef78dd1bdfb25bd966e0070f00 100644 (file)
@@ -71,7 +71,7 @@ Preprocessor::Preprocessor(IntrusiveRefCntPtr<PreprocessorOptions> PPOpts,
       CodeComplete(nullptr), CodeCompletionFile(nullptr),
       CodeCompletionOffset(0), LastTokenWasAt(false),
       ModuleImportExpectsIdentifier(false), CodeCompletionReached(0),
-      SkipMainFilePreamble(0, true), CurPPLexer(nullptr),
+      MainFileDir(nullptr), SkipMainFilePreamble(0, true), CurPPLexer(nullptr),
       CurDirLookup(nullptr), CurLexerKind(CLK_Lexer), CurSubmodule(nullptr),
       Callbacks(nullptr), MacroArgCache(nullptr), Record(nullptr),
       MIChainHead(nullptr), DeserialMIChainHead(nullptr) {
index c0f22846787420acfc60cb1c649428b43603e391..e1daa04647f63b8d9efd149109175b83561f0106 100644 (file)
@@ -1559,7 +1559,13 @@ HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d,
       FileManager &FileMgr = Reader.getFileManager();
       ModuleMap &ModMap =
           Reader.getPreprocessor().getHeaderSearchInfo().getModuleMap();
-      ModMap.addHeader(Mod, FileMgr.getFile(key.Filename), HFI.getHeaderRole());
+      // FIXME: This is wrong. We should track the filename as written; this
+      // information should be propagated through the SUBMODULE_HEADER etc
+      // records rather than from here.
+      // FIXME: We don't ever mark excluded headers.
+      ModMap.addHeader(
+          Mod, Module::Header{key.Filename, FileMgr.getFile(key.Filename)},
+          HFI.getHeaderRole());
     }
   }
 
index b9be775408b2dac812efc150f114beb6c72c6dbc..5ffb259b0a184ee37efb6605edfc1c37e09381b7 100644 (file)
@@ -2511,24 +2511,31 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
 
     // Emit the headers.
     struct {
-      unsigned Kind;
+      unsigned RecordKind;
       unsigned Abbrev;
-      ArrayRef<const FileEntry*> Headers;
+      Module::HeaderKind HeaderKind;
     } HeaderLists[] = {
-      {SUBMODULE_HEADER, HeaderAbbrev, Mod->NormalHeaders},
-      {SUBMODULE_TEXTUAL_HEADER, TextualHeaderAbbrev, Mod->TextualHeaders},
-      {SUBMODULE_PRIVATE_HEADER, PrivateHeaderAbbrev, Mod->PrivateHeaders},
+      {SUBMODULE_HEADER, HeaderAbbrev, Module::HK_Normal},
+      {SUBMODULE_TEXTUAL_HEADER, TextualHeaderAbbrev, Module::HK_Textual},
+      {SUBMODULE_PRIVATE_HEADER, PrivateHeaderAbbrev, Module::HK_Private},
       {SUBMODULE_PRIVATE_TEXTUAL_HEADER, PrivateTextualHeaderAbbrev,
-       Mod->PrivateTextualHeaders},
-      {SUBMODULE_EXCLUDED_HEADER, ExcludedHeaderAbbrev, Mod->ExcludedHeaders},
-      {SUBMODULE_TOPHEADER, TopHeaderAbbrev,
-       Mod->getTopHeaders(PP->getFileManager())}
+        Module::HK_PrivateTextual},
+      {SUBMODULE_EXCLUDED_HEADER, ExcludedHeaderAbbrev, Module::HK_Excluded}
     };
     for (auto &HL : HeaderLists) {
       Record.clear();
-      Record.push_back(HL.Kind);
-      for (auto *H : HL.Headers)
-        Stream.EmitRecordWithBlob(HL.Abbrev, Record, H->getName());
+      Record.push_back(HL.RecordKind);
+      for (auto &H : Mod->Headers[HL.HeaderKind])
+        Stream.EmitRecordWithBlob(HL.Abbrev, Record, H.NameAsWritten);
+    }
+
+    // Emit the top headers.
+    {
+      auto TopHeaders = Mod->getTopHeaders(PP->getFileManager());
+      Record.clear();
+      Record.push_back(SUBMODULE_TOPHEADER);
+      for (auto *H : TopHeaders)
+        Stream.EmitRecordWithBlob(TopHeaderAbbrev, Record, H->getName());
     }
 
     // Emit the imports. 
index cd7b33493998bd3b28ca40cbfec2b8039d9c57ef..e107680fdf9c4ee7b4bf59107e7139689a559fe0 100644 (file)
@@ -1,23 +1,27 @@
+// This test explicitly cd's to the test/Modules directory so that we can test
+// that filenames found via relative -I paths are printed correctly.
+//
 // RUN: rm -rf %t
-// RUN: not %clang_cc1 -fmodules -fmodules-cache-path=%t -I %S/Inputs/malformed -DHEADER="a1.h" %s 2>&1 | FileCheck %s --check-prefix=CHECK-A
-// RUN: not %clang_cc1 -fmodules -fmodules-cache-path=%t -I %S/Inputs/malformed -DHEADER="b1.h" %s 2>&1 | FileCheck %s --check-prefix=CHECK-B
+// RUN: cd %S
+// RUN: not %clang_cc1 -fmodules -fmodules-cache-path=%t -I Inputs/malformed -DHEADER="a1.h" %s 2>&1 | FileCheck %s --check-prefix=CHECK-A
+// RUN: not %clang_cc1 -fmodules -fmodules-cache-path=%t -I Inputs/malformed -DHEADER="b1.h" %s 2>&1 | FileCheck %s --check-prefix=CHECK-B
 
 #define STR2(x) #x
 #define STR(x) STR2(x)
 #include STR(HEADER)
 
 // CHECK-A: While building module 'malformed_a'
-// CHECK-A: a1.h:1:{{.*}} error: expected '}'
-// CHECK-A: a1.h:1:{{.*}} note: to match this '{'
+// CHECK-A: {{^}}Inputs/malformed/a1.h:1:{{.*}} error: expected '}'
+// CHECK-A: {{^}}Inputs/malformed/a1.h:1:{{.*}} note: to match this '{'
 //
 // CHECK-A: While building module 'malformed_a'
-// CHECK-A: a2.h:1:{{.*}} error: extraneous closing brace
+// CHECK-A: {{^}}Inputs/malformed/a2.h:1:{{.*}} error: extraneous closing brace
 
 // CHECK-B: While building module 'malformed_b'
-// CHECK-B: b1.h:2:{{.*}} error: expected '}'
-// CHECK-B: b1.h:1:{{.*}} note: to match this '{'
-// CHECK-B: b1.h:3:{{.*}} error: extraneous closing brace ('}')
+// CHECK-B: {{^}}Inputs/malformed/b1.h:2:{{.*}} error: expected '}'
+// CHECK-B: {{^}}Inputs/malformed/b1.h:1:{{.*}} note: to match this '{'
+// CHECK-B: {{^}}Inputs/malformed/b1.h:3:{{.*}} error: extraneous closing brace ('}')
 //
 // CHECK-B: While building module 'malformed_b'
-// CHECK-B: b2.h:1:{{.*}} error: redefinition of 'g'
-// CHECK-B: b2.h:1:{{.*}} note: previous definition is here
+// CHECK-B: {{^}}Inputs/malformed/b2.h:1:{{.*}} error: redefinition of 'g'
+// CHECK-B: {{^}}Inputs/malformed/b2.h:1:{{.*}} note: previous definition is here