<div dir="ltr">Thank you!</div><div class="gmail_extra"><br><div class="gmail_quote">On 2 June 2017 at 10:31, Benjamin Kramer <span dir="ltr"><<a href="mailto:benny.kra@gmail.com" target="_blank">benny.kra@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">I committed a workaround in r304568.<br>
<div class="HOEnZb"><div class="h5"><br>
On Fri, Jun 2, 2017 at 6:59 PM, Alexander Kornienko via cfe-commits<br>
<<a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a>> wrote:<br>
> I've not yet figured out exactly, but I have a suspicion that this commit<br>
> causes crashes when run under asan. Specifically, when running<br>
> test/Modules/preprocess-<wbr>module.cpp<br>
><br>
> The stack trace is:<br>
>     #0 0x1d644c6 in (anonymous<br>
> namespace)::<wbr>HeaderFileInfoTrait::EmitData(<wbr>llvm::raw_ostream&, (anonymous<br>
> namespace)::<wbr>HeaderFileInfoTrait::key_type const&, (anonymous<br>
> namespace)::<wbr>HeaderFileInfoTrait::data_type const&, unsigned int)<br>
> llvm/tools/clang/lib/<wbr>Serialization/ASTWriter.cpp:<wbr>1926:39<br>
>     #1 0x1d322f3 in llvm::<wbr>OnDiskChainedHashTableGenerato<wbr>r<(anonymous<br>
> namespace)::<wbr>HeaderFileInfoTrait>::Emit(<wbr>llvm::raw_ostream&, (anonymous<br>
> namespace)::<wbr>HeaderFileInfoTrait&)<br>
> llvm/include/llvm/Support/<wbr>OnDiskHashTable.h:198:17<br>
>     #2 0x1d3168d in clang::ASTWriter::<wbr>WriteHeaderSearch(clang::<wbr>HeaderSearch<br>
> const&) llvm/tools/clang/lib/<wbr>Serialization/ASTWriter.cpp:<wbr>2092:30<br>
>     #3 0x1d52f4c in clang::ASTWriter::<wbr>WriteASTCore(clang::Sema&,<br>
> llvm::StringRef, std::string const&, clang::Module*)<br>
> llvm/tools/clang/lib/<wbr>Serialization/ASTWriter.cpp:<wbr>4857:3<br>
>     #4 0x1d4f7db in clang::ASTWriter::WriteAST(<wbr>clang::Sema&, std::string<br>
> const&, clang::Module*, llvm::StringRef, bool)<br>
> llvm/tools/clang/lib/<wbr>Serialization/ASTWriter.cpp:<wbr>4475:7<br>
>     #5 0x1cd0333 in<br>
> clang::PCHGenerator::<wbr>HandleTranslationUnit(clang::<wbr>ASTContext&)<br>
> llvm/tools/clang/lib/<wbr>Serialization/GeneratePCH.cpp:<wbr>62:14<br>
>     #6 0x1f56cc7 in<br>
> clang::MultiplexConsumer::<wbr>HandleTranslationUnit(clang::<wbr>ASTContext&)<br>
> llvm/tools/clang/lib/Frontend/<wbr>MultiplexConsumer.cpp:305:15<br>
>     #7 0x24ebc9c in clang::ParseAST(clang::Sema&, bool, bool)<br>
> llvm/tools/clang/lib/Parse/<wbr>ParseAST.cpp:159:13<br>
>     #8 0x1f4b283 in clang::FrontendAction::<wbr>Execute()<br>
> llvm/tools/clang/lib/Frontend/<wbr>FrontendAction.cpp:856:8<br>
>     #9 0x1caf916 in<br>
> clang::CompilerInstance::<wbr>ExecuteAction(clang::<wbr>FrontendAction&)<br>
> llvm/tools/clang/lib/Frontend/<wbr>CompilerInstance.cpp:970:11<br>
>     #10 0x5ed12c in<br>
> clang::<wbr>ExecuteCompilerInvocation(<wbr>clang::CompilerInstance*)<br>
> llvm/tools/clang/lib/<wbr>FrontendTool/<wbr>ExecuteCompilerInvocation.cpp:<wbr>249:25<br>
><br>
> Could you take a look?<br>
><br>
><br>
> On Fri, Jun 2, 2017 at 3:55 AM, Richard Smith via cfe-commits<br>
> <<a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a>> wrote:<br>
>><br>
>> Author: rsmith<br>
>> Date: Thu Jun  1 20:55:39 2017<br>
>> New Revision: 304515<br>
>><br>
>> URL: <a href="http://llvm.org/viewvc/llvm-project?rev=304515&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project?rev=304515&view=rev</a><br>
>> Log:<br>
>> Support lazy stat'ing of files referenced by module maps.<br>
>><br>
>> This patch adds support for a `header` declaration in a module map to<br>
>> specify<br>
>> certain `stat` information (currently, size and mtime) about that header<br>
>> file.<br>
>> This has two purposes:<br>
>><br>
>> - It removes the need to eagerly `stat` every file referenced by a module<br>
>> map.<br>
>>   Instead, we track a list of unresolved header files with each size /<br>
>> mtime<br>
>>   (actually, for simplicity, we track submodules with such headers), and<br>
>> when<br>
>>   attempting to look up a header file based on a `FileEntry`, we check if<br>
>> there<br>
>>   are any unresolved header directives with that `FileEntry`'s size /<br>
>> mtime and<br>
>>   perform deferred `stat`s if so.<br>
>><br>
>> - It permits a preprocessed module to be compiled without the original<br>
>> files<br>
>>   being present on disk. The only reason we used to need those files was<br>
>> to get<br>
>>   the `stat` information in order to do header -> module lookups when<br>
>> using the<br>
>>   module. If we're provided with the `stat` information in the<br>
>> preprocessed<br>
>>   module, we can avoid requiring the files to exist.<br>
>><br>
>> Unlike most `header` directives, if a `header` directive with `stat`<br>
>> information has no corresponding on-disk file the enclosing module is<br>
>> *not*<br>
>> marked unavailable (so that behavior is consistent regardless of whether<br>
>> we've<br>
>> resolved a header directive, and so that preprocessed modules don't get<br>
>> marked<br>
>> unavailable). We could actually do this for all `header` directives: the<br>
>> only<br>
>> reason we mark the module unavailable if headers are missing is to give a<br>
>> diagnostic slightly earlier (rather than waiting until we actually try to<br>
>> build<br>
>> the module / load and validate its .pcm file).<br>
>><br>
>> Differential Revision: <a href="https://reviews.llvm.org/D33703" rel="noreferrer" target="_blank">https://reviews.llvm.org/<wbr>D33703</a><br>
>><br>
>> Added:<br>
>>     cfe/trunk/test/Modules/Inputs/<wbr>header-attribs/<br>
>>     cfe/trunk/test/Modules/Inputs/<wbr>header-attribs/bar.h<br>
>>     cfe/trunk/test/Modules/Inputs/<wbr>header-attribs/baz.h<br>
>>     cfe/trunk/test/Modules/Inputs/<wbr>header-attribs/foo.h<br>
>>     cfe/trunk/test/Modules/Inputs/<wbr>header-attribs/modular.<wbr>modulemap<br>
>>     cfe/trunk/test/Modules/Inputs/<wbr>header-attribs/textual.<wbr>modulemap<br>
>>     cfe/trunk/test/Modules/header-<wbr>attribs.cpp<br>
>>     cfe/trunk/test/Modules/<wbr>preprocess-missing.modulemap<br>
>> Modified:<br>
>>     cfe/trunk/docs/Modules.rst<br>
>>     cfe/trunk/include/clang/Basic/<wbr>DiagnosticLexKinds.td<br>
>>     cfe/trunk/include/clang/Basic/<wbr>DiagnosticSerializationKinds.<wbr>td<br>
>>     cfe/trunk/include/clang/Basic/<wbr>Module.h<br>
>>     cfe/trunk/include/clang/Lex/<wbr>ModuleMap.h<br>
>>     cfe/trunk/lib/Basic/Module.cpp<br>
>>     cfe/trunk/lib/Frontend/<wbr>FrontendAction.cpp<br>
>>     cfe/trunk/lib/Lex/<wbr>HeaderSearch.cpp<br>
>>     cfe/trunk/lib/Lex/ModuleMap.<wbr>cpp<br>
>>     cfe/trunk/lib/Lex/<wbr>PPDirectives.cpp<br>
>>     cfe/trunk/lib/Serialization/<wbr>ASTWriter.cpp<br>
>>     cfe/trunk/test/Modules/<wbr>diagnostics.modulemap<br>
>>     cfe/trunk/test/Modules/<wbr>preprocess-module.cpp<br>
>><br>
>> Modified: cfe/trunk/docs/Modules.rst<br>
>> URL:<br>
>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/Modules.rst?rev=304515&r1=304514&r2=304515&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/docs/<wbr>Modules.rst?rev=304515&r1=<wbr>304514&r2=304515&view=diff</a><br>
>><br>
>> ==============================<wbr>==============================<wbr>==================<br>
>> --- cfe/trunk/docs/Modules.rst (original)<br>
>> +++ cfe/trunk/docs/Modules.rst Thu Jun  1 20:55:39 2017<br>
>> @@ -469,9 +469,16 @@ A header declaration specifies that a pa<br>
>>  .. parsed-literal::<br>
>><br>
>>    *header-declaration*:<br>
>> -    ``private``:sub:`opt` ``textual``:sub:`opt` ``header``<br>
>> *string-literal*<br>
>> -    ``umbrella`` ``header`` *string-literal*<br>
>> -    ``exclude`` ``header`` *string-literal*<br>
>> +    ``private``:sub:`opt` ``textual``:sub:`opt` ``header``<br>
>> *string-literal* *header-attrs*:sub:`opt`<br>
>> +    ``umbrella`` ``header`` *string-literal* *header-attrs*:sub:`opt`<br>
>> +    ``exclude`` ``header`` *string-literal* *header-attrs*:sub:`opt`<br>
>> +<br>
>> +  *header-attrs*:<br>
>> +    '{' *header-attr** '}'<br>
>> +<br>
>> +  *header-attr*:<br>
>> +    ``size`` *integer-literal*<br>
>> +    ``mtime`` *integer-literal*<br>
>><br>
>>  A header declaration that does not contain ``exclude`` nor ``textual``<br>
>> specifies a header that contributes to the enclosing module. Specifically,<br>
>> when the module is built, the named header will be parsed and its<br>
>> declarations will be (logically) placed into the enclosing submodule.<br>
>><br>
>> @@ -504,6 +511,18 @@ A header with the ``exclude`` specifier<br>
>><br>
>>  A given header shall not be referenced by more than one<br>
>> *header-declaration*.<br>
>><br>
>> +Two *header-declaration*\s, or a *header-declaration* and a ``#include``,<br>
>> are<br>
>> +considered to refer to the same file if the paths resolve to the same<br>
>> file<br>
>> +and the specified *header-attr*\s (if any) match the attributes of that<br>
>> file,<br>
>> +even if the file is named differently (for instance, by a relative path<br>
>> or<br>
>> +via symlinks).<br>
>> +<br>
>> +.. note::<br>
>> +    The use of *header-attr*\s avoids the need for Clang to speculatively<br>
>> +    ``stat`` every header referenced by a module map. It is recommended<br>
>> that<br>
>> +    *header-attr*\s only be used in machine-generated module maps, to<br>
>> avoid<br>
>> +    mismatches between attribute values and the corresponding files.<br>
>> +<br>
>>  Umbrella directory declaration<br>
>>  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~<br>
>>  An umbrella directory declaration specifies that all of the headers in<br>
>> the specified directory should be included within the module.<br>
>><br>
>> Modified: cfe/trunk/include/clang/Basic/<wbr>DiagnosticLexKinds.td<br>
>> URL:<br>
>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td?rev=304515&r1=304514&r2=304515&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/include/<wbr>clang/Basic/<wbr>DiagnosticLexKinds.td?rev=<wbr>304515&r1=304514&r2=304515&<wbr>view=diff</a><br>
>><br>
>> ==============================<wbr>==============================<wbr>==================<br>
>> --- cfe/trunk/include/clang/Basic/<wbr>DiagnosticLexKinds.td (original)<br>
>> +++ cfe/trunk/include/clang/Basic/<wbr>DiagnosticLexKinds.td Thu Jun  1<br>
>> 20:55:39 2017<br>
>> @@ -664,6 +664,12 @@ def warn_mmap_mismatched_top_<wbr>level_priva<br>
>>    InGroup<PrivateModule>;<br>
>>  def note_mmap_rename_top_level_<wbr>private_as_submodule : Note<<br>
>>    "make '%0' a submodule of '%1' to ensure it can be found by name">;<br>
>> +def err_mmap_duplicate_header_<wbr>attribute : Error<<br>
>> +  "header attribute '%0' specified multiple times">;<br>
>> +def err_mmap_invalid_header_<wbr>attribute_value : Error<<br>
>> +  "expected integer literal as value for header attribute '%0'">;<br>
>> +def err_mmap_expected_header_<wbr>attribute : Error<<br>
>> +  "expected a header attribute name ('size' or 'mtime')">;<br>
>><br>
>>  def warn_auto_module_import : Warning<<br>
>>    "treating #%select{include|import|<wbr>include_next|__include_macros}<wbr>0 as an<br>
>> "<br>
>><br>
>> Modified: cfe/trunk/include/clang/Basic/<wbr>DiagnosticSerializationKinds.<wbr>td<br>
>> URL:<br>
>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSerializationKinds.td?rev=304515&r1=304514&r2=304515&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/include/<wbr>clang/Basic/<wbr>DiagnosticSerializationKinds.<wbr>td?rev=304515&r1=304514&r2=<wbr>304515&view=diff</a><br>
>><br>
>> ==============================<wbr>==============================<wbr>==================<br>
>> --- cfe/trunk/include/clang/Basic/<wbr>DiagnosticSerializationKinds.<wbr>td<br>
>> (original)<br>
>> +++ cfe/trunk/include/clang/Basic/<wbr>DiagnosticSerializationKinds.<wbr>td Thu Jun<br>
>> 1 20:55:39 2017<br>
>> @@ -174,10 +174,6 @@ def note_module_odr_violation_<wbr>mismatch_d<br>
>>    "method %2 with %ordinal3 parameter of type %4%select{| decayed from<br>
>> %6}5|"<br>
>>    "method %2 with %ordinal3 parameter named %4}1">;<br>
>><br>
>> -def warn_module_uses_date_time : Warning<<br>
>> -  "%select{precompiled header|module}0 uses __DATE__ or __TIME__">,<br>
>> -  InGroup<DiagGroup<"pch-date-<wbr>time">>;<br>
>> -<br>
>>  def warn_duplicate_module_file_<wbr>extension : Warning<<br>
>>    "duplicate module file extension block name '%0'">,<br>
>>    InGroup<ModuleFileExtension>;<br>
>> @@ -186,7 +182,15 @@ def warn_module_system_bit_<wbr>conflict : Wa<br>
>>    "module file '%0' was validated as a system module and is now being<br>
>> imported "<br>
>>    "as a non-system module; any difference in diagnostic options will be<br>
>> ignored">,<br>
>>    InGroup<ModuleConflict>;<br>
>> +} // let CategoryName<br>
>><br>
>> +let CategoryName = "AST Serialization Issue" in {<br>
>> +def warn_module_uses_date_time : Warning<<br>
>> +  "%select{precompiled header|module}0 uses __DATE__ or __TIME__">,<br>
>> +  InGroup<DiagGroup<"pch-date-<wbr>time">>;<br>
>> +def err_module_no_size_mtime_for_<wbr>header : Error<<br>
>> +  "cannot emit module %0: %select{size|mtime}1 must be explicitly<br>
>> specified "<br>
>> +  "for missing header file \"%2\"">;<br>
>>  } // let CategoryName<br>
>>  } // let Component<br>
>><br>
>><br>
>> Modified: cfe/trunk/include/clang/Basic/<wbr>Module.h<br>
>> URL:<br>
>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Module.h?rev=304515&r1=304514&r2=304515&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/include/<wbr>clang/Basic/Module.h?rev=<wbr>304515&r1=304514&r2=304515&<wbr>view=diff</a><br>
>><br>
>> ==============================<wbr>==============================<wbr>==================<br>
>> --- cfe/trunk/include/clang/Basic/<wbr>Module.h (original)<br>
>> +++ cfe/trunk/include/clang/Basic/<wbr>Module.h Thu Jun  1 20:55:39 2017<br>
>> @@ -154,11 +154,19 @@ public:<br>
>>    /// \brief Stored information about a header directive that was found<br>
>> in the<br>
>>    /// module map file but has not been resolved to a file.<br>
>>    struct UnresolvedHeaderDirective {<br>
>> +    HeaderKind Kind = HK_Normal;<br>
>>      SourceLocation FileNameLoc;<br>
>>      std::string FileName;<br>
>> -    bool IsUmbrella;<br>
>> +    bool IsUmbrella = false;<br>
>> +    bool HasBuiltinHeader = false;<br>
>> +    Optional<off_t> Size;<br>
>> +    Optional<time_t> ModTime;<br>
>>    };<br>
>><br>
>> +  /// Headers that are mentioned in the module map file but that we have<br>
>> not<br>
>> +  /// yet attempted to resolve to a file on the file system.<br>
>> +  SmallVector<<wbr>UnresolvedHeaderDirective, 1> UnresolvedHeaders;<br>
>> +<br>
>>    /// \brief Headers that are mentioned in the module map file but could<br>
>> not be<br>
>>    /// found on the file system.<br>
>>    SmallVector<<wbr>UnresolvedHeaderDirective, 1> MissingHeaders;<br>
>><br>
>> Modified: cfe/trunk/include/clang/Lex/<wbr>ModuleMap.h<br>
>> URL:<br>
>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/ModuleMap.h?rev=304515&r1=304514&r2=304515&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/include/<wbr>clang/Lex/ModuleMap.h?rev=<wbr>304515&r1=304514&r2=304515&<wbr>view=diff</a><br>
>><br>
>> ==============================<wbr>==============================<wbr>==================<br>
>> --- cfe/trunk/include/clang/Lex/<wbr>ModuleMap.h (original)<br>
>> +++ cfe/trunk/include/clang/Lex/<wbr>ModuleMap.h Thu Jun  1 20:55:39 2017<br>
>> @@ -26,6 +26,7 @@<br>
>>  #include "llvm/ADT/SmallVector.h"<br>
>>  #include "llvm/ADT/StringMap.h"<br>
>>  #include "llvm/ADT/StringRef.h"<br>
>> +#include "llvm/ADT/TinyPtrVector.h"<br>
>>  #include "llvm/ADT/Twine.h"<br>
>>  #include <algorithm><br>
>>  #include <memory><br>
>> @@ -116,6 +117,11 @@ public:<br>
>>      // Adjust ModuleMap::addHeader.<br>
>>    };<br>
>><br>
>> +  /// Convert a header kind to a role. Requires Kind to not be<br>
>> HK_Excluded.<br>
>> +  static ModuleHeaderRole headerKindToRole(Module::<wbr>HeaderKind Kind);<br>
>> +  /// Convert a header role to a kind.<br>
>> +  static Module::HeaderKind headerRoleToKind(<wbr>ModuleHeaderRole Role);<br>
>> +<br>
>>    /// \brief A header that is known to reside within a given module,<br>
>>    /// whether it was included or excluded.<br>
>>    class KnownHeader {<br>
>> @@ -165,7 +171,13 @@ private:<br>
>>    /// \brief Mapping from each header to the module that owns the<br>
>> contents of<br>
>>    /// that header.<br>
>>    HeadersMap Headers;<br>
>> -<br>
>> +<br>
>> +  /// Map from file sizes to modules with lazy header directives of that<br>
>> size.<br>
>> +  mutable llvm::DenseMap<off_t, llvm::TinyPtrVector<Module*>><br>
>> LazyHeadersBySize;<br>
>> +  /// Map from mtimes to modules with lazy header directives with those<br>
>> mtimes.<br>
>> +  mutable llvm::DenseMap<time_t, llvm::TinyPtrVector<Module*>><br>
>> +              LazyHeadersByModTime;<br>
>> +<br>
>>    /// \brief Mapping from directories with umbrella headers to the module<br>
>>    /// that is generated from the umbrella header.<br>
>>    ///<br>
>> @@ -257,22 +269,30 @@ private:<br>
>>    /// resolved.<br>
>>    Module *resolveModuleId(const ModuleId &Id, Module *Mod, bool Complain)<br>
>> const;<br>
>><br>
>> -  /// Resolve the given header directive to an actual header file.<br>
>> +  /// Add an unresolved header to a module.<br>
>> +  void addUnresolvedHeader(Module *Mod,<br>
>> +                           Module::<wbr>UnresolvedHeaderDirective Header);<br>
>> +<br>
>> +  /// Look up the given header directive to find an actual header file.<br>
>>    ///<br>
>>    /// \param M The module in which we're resolving the header directive.<br>
>>    /// \param Header The header directive to resolve.<br>
>>    /// \param RelativePathName Filled in with the relative path name from<br>
>> the<br>
>>    ///        module to the resolved header.<br>
>>    /// \return The resolved file, if any.<br>
>> -  const FileEntry *resolveHeader(Module *M,<br>
>> -                                 Module::<wbr>UnresolvedHeaderDirective<br>
>> Header,<br>
>> -                                 SmallVectorImpl<char><br>
>> &RelativePathName);<br>
>> +  const FileEntry *findHeader(Module *M,<br>
>> +                              const Module::<wbr>UnresolvedHeaderDirective<br>
>> &Header,<br>
>> +                              SmallVectorImpl<char> &RelativePathName);<br>
>> +<br>
>> +  /// Resolve the given header directive.<br>
>> +  void resolveHeader(Module *M,<br>
>> +                     const Module::<wbr>UnresolvedHeaderDirective &Header);<br>
>><br>
>>    /// Attempt to resolve the specified header directive as naming a<br>
>> builtin<br>
>>    /// header.<br>
>> -  const FileEntry *<br>
>> -  resolveAsBuiltinHeader(Module *M, Module::<wbr>UnresolvedHeaderDirective<br>
>> Header,<br>
>> -                         SmallVectorImpl<char> &BuiltinPathName);<br>
>> +  /// \return \c true if a corresponding builtin header was found.<br>
>> +  bool resolveAsBuiltinHeader(Module *M,<br>
>> +                              const Module::<wbr>UnresolvedHeaderDirective<br>
>> &Header);<br>
>><br>
>>    /// \brief Looks up the modules that \p File corresponds to.<br>
>>    ///<br>
>> @@ -368,6 +388,15 @@ public:<br>
>>    /// the preferred module for the header.<br>
>>    ArrayRef<KnownHeader> findAllModulesForHeader(const FileEntry *File)<br>
>> const;<br>
>><br>
>> +  /// Resolve all lazy header directives for the specified file.<br>
>> +  ///<br>
>> +  /// This ensures that the HeaderFileInfo on HeaderSearch is up to date.<br>
>> This<br>
>> +  /// is effectively internal, but is exposed so HeaderSearch can call<br>
>> it.<br>
>> +  void resolveHeaderDirectives(const FileEntry *File) const;<br>
>> +<br>
>> +  /// Resolve all lazy header directives for the specified module.<br>
>> +  void resolveHeaderDirectives(Module *Mod) const;<br>
>> +<br>
>>    /// \brief Reports errors if a module must not include a specific file.<br>
>>    ///<br>
>>    /// \param RequestingModule The module including a file.<br>
>><br>
>> Modified: cfe/trunk/lib/Basic/Module.cpp<br>
>> URL:<br>
>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Module.cpp?rev=304515&r1=304514&r2=304515&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/Basic/<wbr>Module.cpp?rev=304515&r1=<wbr>304514&r2=304515&view=diff</a><br>
>><br>
>> ==============================<wbr>==============================<wbr>==================<br>
>> --- cfe/trunk/lib/Basic/Module.cpp (original)<br>
>> +++ cfe/trunk/lib/Basic/Module.cpp Thu Jun  1 20:55:39 2017<br>
>> @@ -394,11 +394,30 @@ void Module::print(raw_ostream &OS, unsi<br>
>>                 {"exclude ", HK_Excluded}};<br>
>><br>
>>    for (auto &K : Kinds) {<br>
>> +    assert(&K == &Kinds[K.Kind] && "kinds in wrong order");<br>
>>      for (auto &H : Headers[K.Kind]) {<br>
>>        OS.indent(Indent + 2);<br>
>>        OS << K.Prefix << "header \"";<br>
>>        OS.write_escaped(H.<wbr>NameAsWritten);<br>
>> -      OS << "\"\n";<br>
>> +      OS << "\" { size " << H.Entry->getSize()<br>
>> +         << " mtime " << H.Entry->getModificationTime() << " }\n";<br>
>> +    }<br>
>> +  }<br>
>> +  for (auto *Unresolved : {&UnresolvedHeaders, &MissingHeaders}) {<br>
>> +    for (auto &U : *Unresolved) {<br>
>> +      OS.indent(Indent + 2);<br>
>> +      OS << Kinds[U.Kind].Prefix << "header \"";<br>
>> +      OS.write_escaped(U.FileName);<br>
>> +      OS << "\"";<br>
>> +      if (U.Size || U.ModTime) {<br>
>> +        OS << " {";<br>
>> +        if (U.Size)<br>
>> +          OS << " size " << *U.Size;<br>
>> +        if (U.ModTime)<br>
>> +          OS << " mtime " << *U.ModTime;<br>
>> +        OS << " }";<br>
>> +      }<br>
>> +      OS << "\n";<br>
>>      }<br>
>>    }<br>
>><br>
>><br>
>> Modified: cfe/trunk/lib/Frontend/<wbr>FrontendAction.cpp<br>
>> URL:<br>
>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/FrontendAction.cpp?rev=304515&r1=304514&r2=304515&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/<wbr>Frontend/FrontendAction.cpp?<wbr>rev=304515&r1=304514&r2=<wbr>304515&view=diff</a><br>
>><br>
>> ==============================<wbr>==============================<wbr>==================<br>
>> --- cfe/trunk/lib/Frontend/<wbr>FrontendAction.cpp (original)<br>
>> +++ cfe/trunk/lib/Frontend/<wbr>FrontendAction.cpp Thu Jun  1 20:55:39 2017<br>
>> @@ -289,14 +289,28 @@ static void addHeaderInclude(StringRef H<br>
>>  ///<br>
>>  /// \param Includes Will be augmented with the set of \#includes or<br>
>> \#imports<br>
>>  /// needed to load all of the named headers.<br>
>> -static std::error_code<br>
>> -collectModuleHeaderIncludes(<wbr>const LangOptions &LangOpts, FileManager<br>
>> &FileMgr,<br>
>> -                            ModuleMap &ModMap, clang::Module *Module,<br>
>> -                            SmallVectorImpl<char> &Includes) {<br>
>> +static std::error_code collectModuleHeaderIncludes(<br>
>> +    const LangOptions &LangOpts, FileManager &FileMgr, DiagnosticsEngine<br>
>> &Diag,<br>
>> +    ModuleMap &ModMap, clang::Module *Module, SmallVectorImpl<char><br>
>> &Includes) {<br>
>>    // Don't collect any headers for unavailable modules.<br>
>>    if (!Module->isAvailable())<br>
>>      return std::error_code();<br>
>><br>
>> +  // Resolve all lazy header directives to header files.<br>
>> +  ModMap.<wbr>resolveHeaderDirectives(<wbr>Module);<br>
>> +<br>
>> +  // If any headers are missing, we can't build this module. In most<br>
>> cases,<br>
>> +  // diagnostics for this should have already been produced; we only get<br>
>> here<br>
>> +  // if explicit stat information was provided.<br>
>> +  // FIXME: If the name resolves to a file with different stat<br>
>> information,<br>
>> +  // produce a better diagnostic.<br>
>> +  if (!Module->MissingHeaders.<wbr>empty()) {<br>
>> +    auto &MissingHeader = Module->MissingHeaders.front()<wbr>;<br>
>> +    Diag.Report(MissingHeader.<wbr>FileNameLoc,<br>
>> diag::err_module_header_<wbr>missing)<br>
>> +      << MissingHeader.IsUmbrella << MissingHeader.FileName;<br>
>> +    return std::error_code();<br>
>> +  }<br>
>> +<br>
>>    // Add includes for each of these headers.<br>
>>    for (auto HK : {Module::HK_Normal, Module::HK_Private}) {<br>
>>      for (Module::Header &H : Module->Headers[HK]) {<br>
>> @@ -367,7 +381,7 @@ collectModuleHeaderIncludes(<wbr>const LangOp<br>
>>                                        SubEnd = Module->submodule_end();<br>
>>         Sub != SubEnd; ++Sub)<br>
>>      if (std::error_code Err = collectModuleHeaderIncludes(<br>
>> -            LangOpts, FileMgr, ModMap, *Sub, Includes))<br>
>> +            LangOpts, FileMgr, Diag, ModMap, *Sub, Includes))<br>
>>        return Err;<br>
>><br>
>>    return std::error_code();<br>
>> @@ -494,7 +508,7 @@ getInputBufferForModule(<wbr>CompilerInstance<br>
>>      addHeaderInclude(<wbr>UmbrellaHeader.NameAsWritten, HeaderContents,<br>
>>                       CI.getLangOpts(), M->IsExternC);<br>
>>    Err = collectModuleHeaderIncludes(<br>
>> -      CI.getLangOpts(), FileMgr,<br>
>> +      CI.getLangOpts(), FileMgr, CI.getDiagnostics(),<br>
>>        CI.getPreprocessor().<wbr>getHeaderSearchInfo().<wbr>getModuleMap(), M,<br>
>>        HeaderContents);<br>
>><br>
>><br>
>> Modified: cfe/trunk/lib/Lex/<wbr>HeaderSearch.cpp<br>
>> URL:<br>
>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/HeaderSearch.cpp?rev=304515&r1=304514&r2=304515&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/Lex/<wbr>HeaderSearch.cpp?rev=304515&<wbr>r1=304514&r2=304515&view=diff</a><br>
>><br>
>> ==============================<wbr>==============================<wbr>==================<br>
>> --- cfe/trunk/lib/Lex/<wbr>HeaderSearch.cpp (original)<br>
>> +++ cfe/trunk/lib/Lex/<wbr>HeaderSearch.cpp Thu Jun  1 20:55:39 2017<br>
>> @@ -1114,6 +1114,8 @@ bool HeaderSearch::<wbr>ShouldEnterIncludeFil<br>
>>    auto TryEnterImported = [&](void) -> bool {<br>
>>      if (!ModulesEnabled)<br>
>>        return false;<br>
>> +    // Ensure FileInfo bits are up to date.<br>
>> +    ModMap.<wbr>resolveHeaderDirectives(File);<br>
>>      // Modules with builtins are special; multiple modules use builtins<br>
>> as<br>
>>      // modular headers, example:<br>
>>      //<br>
>><br>
>> Modified: cfe/trunk/lib/Lex/ModuleMap.<wbr>cpp<br>
>> URL:<br>
>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/ModuleMap.cpp?rev=304515&r1=304514&r2=304515&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/Lex/<wbr>ModuleMap.cpp?rev=304515&r1=<wbr>304514&r2=304515&view=diff</a><br>
>><br>
>> ==============================<wbr>==============================<wbr>==================<br>
>> --- cfe/trunk/lib/Lex/ModuleMap.<wbr>cpp (original)<br>
>> +++ cfe/trunk/lib/Lex/ModuleMap.<wbr>cpp Thu Jun  1 20:55:39 2017<br>
>> @@ -36,6 +36,37 @@<br>
>>  #endif<br>
>>  using namespace clang;<br>
>><br>
>> +Module::HeaderKind ModuleMap::headerRoleToKind(<wbr>ModuleHeaderRole Role) {<br>
>> +  switch ((int)Role) {<br>
>> +  default: llvm_unreachable("unknown header role");<br>
>> +  case NormalHeader:<br>
>> +    return Module::HK_Normal;<br>
>> +  case PrivateHeader:<br>
>> +    return Module::HK_Private;<br>
>> +  case TextualHeader:<br>
>> +    return Module::HK_Textual;<br>
>> +  case PrivateHeader | TextualHeader:<br>
>> +    return Module::HK_PrivateTextual;<br>
>> +  }<br>
>> +}<br>
>> +<br>
>> +ModuleMap::ModuleHeaderRole<br>
>> +ModuleMap::headerKindToRole(<wbr>Module::HeaderKind Kind) {<br>
>> +  switch ((int)Kind) {<br>
>> +  case Module::HK_Normal:<br>
>> +    return NormalHeader;<br>
>> +  case Module::HK_Private:<br>
>> +    return PrivateHeader;<br>
>> +  case Module::HK_Textual:<br>
>> +    return TextualHeader;<br>
>> +  case Module::HK_PrivateTextual:<br>
>> +    return ModuleHeaderRole(PrivateHeader | TextualHeader);<br>
>> +  case Module::HK_Excluded:<br>
>> +    llvm_unreachable("unexpected header kind");<br>
>> +  }<br>
>> +  llvm_unreachable("unknown header kind");<br>
>> +}<br>
>> +<br>
>>  Module::ExportDecl<br>
>>  ModuleMap::resolveExport(<wbr>Module *Mod,<br>
>>                           const Module::UnresolvedExportDecl &Unresolved,<br>
>> @@ -104,12 +135,22 @@ static void appendSubframeworkPaths(Modu<br>
>>  }<br>
>><br>
>>  const FileEntry *<br>
>> -ModuleMap::resolveHeader(<wbr>Module *M, Module::<wbr>UnresolvedHeaderDirective<br>
>> Header,<br>
>> -                         SmallVectorImpl<char> &RelativePathName) {<br>
>> +ModuleMap::findHeader(Module *M,<br>
>> +                      const Module::<wbr>UnresolvedHeaderDirective &Header,<br>
>> +                      SmallVectorImpl<char> &RelativePathName) {<br>
>> +  auto GetFile = [&](StringRef Filename) -> const FileEntry * {<br>
>> +    auto *File = SourceMgr.getFileManager().<wbr>getFile(Filename);<br>
>> +    if (!File ||<br>
>> +        (Header.Size && File->getSize() != *Header.Size) ||<br>
>> +        (Header.ModTime && File->getModificationTime() !=<br>
>> *Header.ModTime))<br>
>> +      return nullptr;<br>
>> +    return File;<br>
>> +  };<br>
>> +<br>
>>    if (llvm::sys::path::is_absolute(<wbr>Header.FileName)) {<br>
>>      RelativePathName.clear();<br>
>>      RelativePathName.append(<wbr>Header.FileName.begin(),<br>
>> Header.FileName.end());<br>
>> -    return SourceMgr.getFileManager().<wbr>getFile(Header.FileName);<br>
>> +    return GetFile(Header.FileName);<br>
>>    }<br>
>><br>
>>    // Search for the header file within the module's home directory.<br>
>> @@ -124,7 +165,7 @@ ModuleMap::resolveHeader(<wbr>Module *M, Modu<br>
>>      // Check whether this file is in the public headers.<br>
>>      llvm::sys::path::append(<wbr>RelativePathName, "Headers",<br>
>> Header.FileName);<br>
>>      llvm::sys::path::append(<wbr>FullPathName, RelativePathName);<br>
>> -    if (auto *File = SourceMgr.getFileManager().<wbr>getFile(FullPathName))<br>
>> +    if (auto *File = GetFile(FullPathName))<br>
>>        return File;<br>
>><br>
>>      // Check whether this file is in the private headers.<br>
>> @@ -141,31 +182,74 @@ ModuleMap::resolveHeader(<wbr>Module *M, Modu<br>
>>      llvm::sys::path::append(<wbr>RelativePathName, "PrivateHeaders",<br>
>>                              Header.FileName);<br>
>>      llvm::sys::path::append(<wbr>FullPathName, RelativePathName);<br>
>> -    return SourceMgr.getFileManager().<wbr>getFile(FullPathName);<br>
>> +    return GetFile(FullPathName);<br>
>>    }<br>
>><br>
>>    // Lookup for normal headers.<br>
>>    llvm::sys::path::append(<wbr>RelativePathName, Header.FileName);<br>
>>    llvm::sys::path::append(<wbr>FullPathName, RelativePathName);<br>
>> -  return SourceMgr.getFileManager().<wbr>getFile(FullPathName);<br>
>> +  return GetFile(FullPathName);<br>
>>  }<br>
>><br>
>> -const FileEntry *<br>
>> -ModuleMap::<wbr>resolveAsBuiltinHeader(Module *M,<br>
>> -                                  Module::<wbr>UnresolvedHeaderDirective<br>
>> Header,<br>
>> -                                  SmallVectorImpl<char> &BuiltinPathName)<br>
>> {<br>
>> -  if (llvm::sys::path::is_absolute(<wbr>Header.FileName) ||<br>
>> M->isPartOfFramework() ||<br>
>> -      !M->IsSystem || Header.IsUmbrella || !BuiltinIncludeDir ||<br>
>> -      BuiltinIncludeDir == M->Directory ||<br>
>> !isBuiltinHeader(Header.<wbr>FileName))<br>
>> -    return nullptr;<br>
>> +void ModuleMap::resolveHeader(<wbr>Module *Mod,<br>
>> +                              const Module::<wbr>UnresolvedHeaderDirective<br>
>> &Header) {<br>
>> +  SmallString<128> RelativePathName;<br>
>> +  if (const FileEntry *File = findHeader(Mod, Header, RelativePathName))<br>
>> {<br>
>> +    if (Header.IsUmbrella) {<br>
>> +      const DirectoryEntry *UmbrellaDir = File->getDir();<br>
>> +      if (Module *UmbrellaMod = UmbrellaDirs[UmbrellaDir])<br>
>> +        Diags.Report(Header.<wbr>FileNameLoc, diag::err_mmap_umbrella_clash)<br>
>> +          << UmbrellaMod-><wbr>getFullModuleName();<br>
>> +      else<br>
>> +        // Record this umbrella header.<br>
>> +        setUmbrellaHeader(Mod, File, RelativePathName.str());<br>
>> +    } else {<br>
>> +      Module::Header H = {RelativePathName.str(), File};<br>
>> +      if (Header.Kind == Module::HK_Excluded)<br>
>> +        excludeHeader(Mod, H);<br>
>> +      else<br>
>> +        addHeader(Mod, H, headerKindToRole(Header.Kind))<wbr>;<br>
>> +    }<br>
>> +  } else if (Header.HasBuiltinHeader && !Header.Size && !Header.ModTime)<br>
>> {<br>
>> +    // There's a builtin header but no corresponding on-disk header.<br>
>> Assume<br>
>> +    // this was supposed to modularize the builtin header alone.<br>
>> +  } else if (Header.Kind == Module::HK_Excluded) {<br>
>> +    // Ignore missing excluded header files. They're optional anyway.<br>
>> +  } else {<br>
>> +    // If we find a module that has a missing header, we mark this module<br>
>> as<br>
>> +    // unavailable and store the header directive for displaying<br>
>> diagnostics.<br>
>> +    Mod->MissingHeaders.push_back(<wbr>Header);<br>
>> +    // A missing header with stat information doesn't make the module<br>
>> +    // unavailable; this keeps our behavior consistent as headers are<br>
>> lazily<br>
>> +    // resolved. (Such a module still can't be built though, except from<br>
>> +    // preprocessed source.)<br>
>> +    if (!Header.Size && !Header.ModTime)<br>
>> +      Mod->markUnavailable();<br>
>> +  }<br>
>> +}<br>
>> +<br>
>> +bool ModuleMap::<wbr>resolveAsBuiltinHeader(<br>
>> +    Module *Mod, const Module::<wbr>UnresolvedHeaderDirective &Header) {<br>
>> +  if (Header.Kind == Module::HK_Excluded ||<br>
>> +      llvm::sys::path::is_absolute(<wbr>Header.FileName) ||<br>
>> +      Mod->isPartOfFramework() || !Mod->IsSystem || Header.IsUmbrella ||<br>
>> +      !BuiltinIncludeDir || BuiltinIncludeDir == Mod->Directory ||<br>
>> +      !isBuiltinHeader(Header.<wbr>FileName))<br>
>> +    return false;<br>
>><br>
>>    // This is a system module with a top-level header. This header<br>
>>    // may have a counterpart (or replacement) in the set of headers<br>
>>    // supplied by Clang. Find that builtin header.<br>
>> -  llvm::sys::path::append(<wbr>BuiltinPathName, BuiltinIncludeDir->getName(),<br>
>> -                          Header.FileName);<br>
>> -  return SourceMgr.getFileManager().<wbr>getFile(<br>
>> -      StringRef(BuiltinPathName.<wbr>data(), BuiltinPathName.size()));<br>
>> +  SmallString<128> Path;<br>
>> +  llvm::sys::path::append(Path, BuiltinIncludeDir->getName(),<br>
>> Header.FileName);<br>
>> +  auto *File = SourceMgr.getFileManager().<wbr>getFile(Path);<br>
>> +  if (!File)<br>
>> +    return false;<br>
>> +<br>
>> +  auto Role = headerKindToRole(Header.Kind);<br>
>> +  Module::Header H = {Path.str(), File};<br>
>> +  addHeader(Mod, H, Role);<br>
>> +  return true;<br>
>>  }<br>
>><br>
>>  ModuleMap::ModuleMap(<wbr>SourceManager &SourceMgr, DiagnosticsEngine &Diags,<br>
>> @@ -246,6 +330,7 @@ bool ModuleMap::isBuiltinHeader(<wbr>StringRe<br>
>><br>
>>  ModuleMap::HeadersMap::<wbr>iterator<br>
>>  ModuleMap::findKnownHeader(<wbr>const FileEntry *File) {<br>
>> +  resolveHeaderDirectives(File);<br>
>>    HeadersMap::iterator Known = Headers.find(File);<br>
>>    if (HeaderInfo.<wbr>getHeaderSearchOpts().<wbr>ImplicitModuleMaps &&<br>
>>        Known == Headers.end() && File->getDir() == BuiltinIncludeDir &&<br>
>> @@ -328,8 +413,10 @@ void ModuleMap::<wbr>diagnoseHeaderInclusion(<br>
>>    if (getTopLevelOrNull(<wbr>RequestingModule) !=<br>
>> getTopLevelOrNull(<wbr>SourceModule))<br>
>>      return;<br>
>><br>
>> -  if (RequestingModule)<br>
>> +  if (RequestingModule) {<br>
>>      resolveUses(RequestingModule, /*Complain=*/false);<br>
>> +    resolveHeaderDirectives(<wbr>RequestingModule);<br>
>> +  }<br>
>><br>
>>    bool Excluded = false;<br>
>>    Module *Private = nullptr;<br>
>> @@ -511,6 +598,7 @@ ModuleMap::<wbr>findOrCreateModuleForHeaderIn<br>
>><br>
>>  ArrayRef<ModuleMap::<wbr>KnownHeader><br>
>>  ModuleMap::<wbr>findAllModulesForHeader(const FileEntry *File) const {<br>
>> +  resolveHeaderDirectives(File);<br>
>>    auto It = Headers.find(File);<br>
>>    if (It == Headers.end())<br>
>>      return None;<br>
>> @@ -524,6 +612,7 @@ bool ModuleMap::<wbr>isHeaderInUnavailableMod<br>
>>  bool<br>
>>  ModuleMap::<wbr>isHeaderUnavailableInModule(<wbr>const FileEntry *Header,<br>
>>                                         const Module *RequestingModule)<br>
>> const {<br>
>> +  resolveHeaderDirectives(<wbr>Header);<br>
>>    HeadersMap::const_iterator Known = Headers.find(Header);<br>
>>    if (Known != Headers.end()) {<br>
>>      for (SmallVectorImpl<KnownHeader>:<wbr>:const_iterator<br>
>> @@ -896,20 +985,65 @@ void ModuleMap::setUmbrellaDir(<wbr>Module *M<br>
>>    UmbrellaDirs[UmbrellaDir] = Mod;<br>
>>  }<br>
>><br>
>> -static Module::HeaderKind headerRoleToKind(ModuleMap::<wbr>ModuleHeaderRole<br>
>> Role) {<br>
>> -  switch ((int)Role) {<br>
>> -  default: llvm_unreachable("unknown header role");<br>
>> -  case ModuleMap::NormalHeader:<br>
>> -    return Module::HK_Normal;<br>
>> -  case ModuleMap::PrivateHeader:<br>
>> -    return Module::HK_Private;<br>
>> -  case ModuleMap::TextualHeader:<br>
>> -    return Module::HK_Textual;<br>
>> -  case ModuleMap::PrivateHeader | ModuleMap::TextualHeader:<br>
>> -    return Module::HK_PrivateTextual;<br>
>> +void ModuleMap::<wbr>addUnresolvedHeader(Module *Mod,<br>
>> +                                    Module::<wbr>UnresolvedHeaderDirective<br>
>> Header) {<br>
>> +  // If there is a builtin counterpart to this file, add it now so it can<br>
>> +  // wrap the system header.<br>
>> +  if (resolveAsBuiltinHeader(Mod, Header)) {<br>
>> +    // If we have both a builtin and system version of the file, the<br>
>> +    // builtin version may want to inject macros into the system header,<br>
>> so<br>
>> +    // force the system header to be treated as a textual header in this<br>
>> +    // case.<br>
>> +    Header.Kind = headerRoleToKind(ModuleMap::<wbr>ModuleHeaderRole(<br>
>> +        headerKindToRole(Header.Kind) | ModuleMap::TextualHeader));<br>
>> +    Header.HasBuiltinHeader = true;<br>
>> +  }<br>
>> +<br>
>> +  // If possible, don't stat the header until we need to. This requires<br>
>> the<br>
>> +  // user to have provided us with some stat information about the file.<br>
>> +  // FIXME: Add support for lazily stat'ing umbrella headers and excluded<br>
>> +  // headers.<br>
>> +  if ((Header.Size || Header.ModTime) && !Header.IsUmbrella &&<br>
>> +      Header.Kind != Module::HK_Excluded) {<br>
>> +    // We expect more variation in mtime than size, so if we're given<br>
>> both,<br>
>> +    // use the mtime as the key.<br>
>> +    if (Header.ModTime)<br>
>> +      LazyHeadersByModTime[*Header.<wbr>ModTime].push_back(Mod);<br>
>> +    else<br>
>> +      LazyHeadersBySize[*Header.<wbr>Size].push_back(Mod);<br>
>> +    Mod->UnresolvedHeaders.push_<wbr>back(Header);<br>
>> +    return;<br>
>> +  }<br>
>> +<br>
>> +  // We don't have stat information or can't defer looking this file up.<br>
>> +  // Perform the lookup now.<br>
>> +  resolveHeader(Mod, Header);<br>
>> +}<br>
>> +<br>
>> +void ModuleMap::<wbr>resolveHeaderDirectives(const FileEntry *File) const {<br>
>> +  auto BySize = LazyHeadersBySize.find(File-><wbr>getSize());<br>
>> +  if (BySize != LazyHeadersBySize.end()) {<br>
>> +    for (auto *M : BySize->second)<br>
>> +      resolveHeaderDirectives(M);<br>
>> +    LazyHeadersBySize.erase(<wbr>BySize);<br>
>> +  }<br>
>> +<br>
>> +  auto ByModTime =<br>
>> LazyHeadersByModTime.find(<wbr>File->getModificationTime());<br>
>> +  if (ByModTime != LazyHeadersByModTime.end()) {<br>
>> +    for (auto *M : ByModTime->second)<br>
>> +      resolveHeaderDirectives(M);<br>
>> +    LazyHeadersByModTime.erase(<wbr>ByModTime);<br>
>>    }<br>
>>  }<br>
>><br>
>> +void ModuleMap::<wbr>resolveHeaderDirectives(Module *Mod) const {<br>
>> +  for (auto &Header : Mod->UnresolvedHeaders)<br>
>> +    // This operation is logically const; we're just changing how we<br>
>> represent<br>
>> +    // the header information for this file.<br>
>> +    const_cast<ModuleMap*>(this)-><wbr>resolveHeader(Mod, Header);<br>
>> +  Mod->UnresolvedHeaders.clear()<wbr>;<br>
>> +}<br>
>> +<br>
>>  void ModuleMap::addHeader(Module *Mod, Module::Header Header,<br>
>>                            ModuleHeaderRole Role, bool Imported) {<br>
>>    KnownHeader KH(Mod, Role);<br>
>> @@ -1063,6 +1197,7 @@ namespace clang {<br>
>>        RequiresKeyword,<br>
>>        Star,<br>
>>        StringLiteral,<br>
>> +      IntegerLiteral,<br>
>>        TextualKeyword,<br>
>>        LBrace,<br>
>>        RBrace,<br>
>> @@ -1072,7 +1207,12 @@ namespace clang {<br>
>><br>
>>      unsigned Location;<br>
>>      unsigned StringLength;<br>
>> -    const char *StringData;<br>
>> +    union {<br>
>> +      // If Kind != IntegerLiteral.<br>
>> +      const char *StringData;<br>
>> +      // If Kind == IntegerLiteral.<br>
>> +      uint64_t IntegerValue;<br>
>> +    };<br>
>><br>
>>      void clear() {<br>
>>        Kind = EndOfFile;<br>
>> @@ -1086,9 +1226,14 @@ namespace clang {<br>
>>      SourceLocation getLocation() const {<br>
>>        return SourceLocation::<wbr>getFromRawEncoding(Location);<br>
>>      }<br>
>> +<br>
>> +    uint64_t getInteger() const {<br>
>> +      return Kind == IntegerLiteral ? IntegerValue : 0;<br>
>> +    }<br>
>><br>
>>      StringRef getString() const {<br>
>> -      return StringRef(StringData, StringLength);<br>
>> +      return Kind == IntegerLiteral ? StringRef()<br>
>> +                                    : StringRef(StringData,<br>
>> StringLength);<br>
>>      }<br>
>>    };<br>
>><br>
>> @@ -1278,6 +1423,25 @@ retry:<br>
>>      Tok.StringLength = Length;<br>
>>      break;<br>
>>    }<br>
>> +<br>
>> +  case tok::numeric_constant: {<br>
>> +    // We don't support any suffixes or other complications.<br>
>> +    SmallString<32> SpellingBuffer;<br>
>> +    SpellingBuffer.resize(LToken.<wbr>getLength() + 1);<br>
>> +    const char *Start = SpellingBuffer.data();<br>
>> +    unsigned Length =<br>
>> +        Lexer::getSpelling(LToken, Start, SourceMgr, L.getLangOpts());<br>
>> +    uint64_t Value;<br>
>> +    if (StringRef(Start, Length).getAsInteger(0, Value)) {<br>
>> +      Diags.Report(Tok.getLocation()<wbr>, diag::err_mmap_unknown_token);<br>
>> +      HadError = true;<br>
>> +      goto retry;<br>
>> +    }<br>
>> +<br>
>> +    Tok.Kind = MMToken::IntegerLiteral;<br>
>> +    Tok.IntegerValue = Value;<br>
>> +    break;<br>
>> +  }<br>
>><br>
>>    case tok::comment:<br>
>>      goto retry;<br>
>> @@ -1904,6 +2068,9 @@ void ModuleMapParser::<wbr>parseHeaderDecl(MM<br>
>>    Header.FileName = Tok.getString();<br>
>>    Header.FileNameLoc = consumeToken();<br>
>>    Header.IsUmbrella = LeadingToken == MMToken::UmbrellaKeyword;<br>
>> +  Header.Kind =<br>
>> +      (LeadingToken == MMToken::ExcludeKeyword ? Module::HK_Excluded<br>
>> +                                               :<br>
>> Map.headerRoleToKind(Role));<br>
>><br>
>>    // Check whether we already have an umbrella.<br>
>>    if (Header.IsUmbrella && ActiveModule->Umbrella) {<br>
>> @@ -1913,64 +2080,62 @@ void ModuleMapParser::<wbr>parseHeaderDecl(MM<br>
>>      return;<br>
>>    }<br>
>><br>
>> -  // Look for this file by name if we don't have any stat information.<br>
>> -  SmallString<128> RelativePathName, BuiltinPathName;<br>
>> -  const FileEntry *File =<br>
>> -      Map.resolveHeader(<wbr>ActiveModule, Header, RelativePathName);<br>
>> -  const FileEntry *BuiltinFile =<br>
>> -      Map.resolveAsBuiltinHeader(<wbr>ActiveModule, Header, BuiltinPathName);<br>
>> -<br>
>> -  // If Clang supplies this header but the underlying system does not,<br>
>> -  // just silently swap in our builtin version. Otherwise, we'll end<br>
>> -  // up adding both (later).<br>
>> -  if (BuiltinFile && !File) {<br>
>> -    RelativePathName = BuiltinPathName;<br>
>> -    File = BuiltinFile;<br>
>> -    BuiltinFile = nullptr;<br>
>> -  }<br>
>> -<br>
>> -  // FIXME: We shouldn't be eagerly stat'ing every file named in a module<br>
>> map.<br>
>> -  // Come up with a lazy way to do this.<br>
>> -  if (File) {<br>
>> -    if (Header.IsUmbrella) {<br>
>> -      const DirectoryEntry *UmbrellaDir = File->getDir();<br>
>> -      if (Module *UmbrellaModule = Map.UmbrellaDirs[UmbrellaDir]) {<br>
>> -        Diags.Report(LeadingLoc, diag::err_mmap_umbrella_clash)<br>
>> -          << UmbrellaModule-><wbr>getFullModuleName();<br>
>> -        HadError = true;<br>
>> -      } else {<br>
>> -        // Record this umbrella header.<br>
>> -        Map.setUmbrellaHeader(<wbr>ActiveModule, File,<br>
>> RelativePathName.str());<br>
>> -      }<br>
>> -    } else if (LeadingToken == MMToken::ExcludeKeyword) {<br>
>> -      Module::Header H = {RelativePathName.str(), File};<br>
>> -      Map.excludeHeader(<wbr>ActiveModule, H);<br>
>> -    } else {<br>
>> -      // If there is a builtin counterpart to this file, add it now so it<br>
>> can<br>
>> -      // wrap the system header.<br>
>> -      if (BuiltinFile) {<br>
>> -        Module::Header H = { BuiltinPathName.str(), BuiltinFile };<br>
>> -        Map.addHeader(ActiveModule, H, Role);<br>
>> -<br>
>> -        // If we have both a builtin and system version of the file, the<br>
>> -        // builtin version may want to inject macros into the system<br>
>> header, so<br>
>> -        // force the system header to be treated as a textual header in<br>
>> this<br>
>> -        // case.<br>
>> -        Role = ModuleMap::ModuleHeaderRole(<wbr>Role |<br>
>> ModuleMap::TextualHeader);<br>
>> -      }<br>
>> +  // If we were given stat information, parse it so we can skip looking<br>
>> for<br>
>> +  // the file.<br>
>> +  if (Tok.is(MMToken::LBrace)) {<br>
>> +    SourceLocation LBraceLoc = consumeToken();<br>
>> +<br>
>> +    while (!Tok.is(MMToken::RBrace) && !Tok.is(MMToken::EndOfFile)) {<br>
>> +      enum Attribute { Size, ModTime, Unknown };<br>
>> +      StringRef Str = Tok.getString();<br>
>> +      SourceLocation Loc = consumeToken();<br>
>> +      switch (llvm::StringSwitch<Attribute><wbr>(Str)<br>
>> +                  .Case("size", Size)<br>
>> +                  .Case("mtime", ModTime)<br>
>> +                  .Default(Unknown)) {<br>
>> +      case Size:<br>
>> +        if (Header.Size)<br>
>> +          Diags.Report(Loc, diag::err_mmap_duplicate_<wbr>header_attribute) <<<br>
>> Str;<br>
>> +        if (!Tok.is(MMToken::<wbr>IntegerLiteral)) {<br>
>> +          Diags.Report(Tok.getLocation()<wbr>,<br>
>> +                       diag::err_mmap_invalid_header_<wbr>attribute_value) <<<br>
>> Str;<br>
>> +          skipUntil(MMToken::RBrace);<br>
>> +          break;<br>
>> +        }<br>
>> +        Header.Size = Tok.getInteger();<br>
>> +        consumeToken();<br>
>> +        break;<br>
>><br>
>> -      // Record this header.<br>
>> -      Module::Header H = { RelativePathName.str(), File };<br>
>> -      Map.addHeader(ActiveModule, H, Role);<br>
>> +      case ModTime:<br>
>> +        if (Header.ModTime)<br>
>> +          Diags.Report(Loc, diag::err_mmap_duplicate_<wbr>header_attribute) <<<br>
>> Str;<br>
>> +        if (!Tok.is(MMToken::<wbr>IntegerLiteral)) {<br>
>> +          Diags.Report(Tok.getLocation()<wbr>,<br>
>> +                       diag::err_mmap_invalid_header_<wbr>attribute_value) <<<br>
>> Str;<br>
>> +          skipUntil(MMToken::RBrace);<br>
>> +          break;<br>
>> +        }<br>
>> +        Header.ModTime = Tok.getInteger();<br>
>> +        consumeToken();<br>
>> +        break;<br>
>> +<br>
>> +      case Unknown:<br>
>> +        Diags.Report(Loc, diag::err_mmap_expected_<wbr>header_attribute);<br>
>> +        skipUntil(MMToken::RBrace);<br>
>> +        break;<br>
>> +      }<br>
>>      }<br>
>> -  } else if (LeadingToken != MMToken::ExcludeKeyword) {<br>
>> -    // Ignore excluded header files. They're optional anyway.<br>
>><br>
>> -    // If we find a module that has a missing header, we mark this module<br>
>> as<br>
>> -    // unavailable and store the header directive for displaying<br>
>> diagnostics.<br>
>> -    ActiveModule->markUnavailable(<wbr>);<br>
>> -    ActiveModule->MissingHeaders.<wbr>push_back(Header);<br>
>> +    if (Tok.is(MMToken::RBrace))<br>
>> +      consumeToken();<br>
>> +    else {<br>
>> +      Diags.Report(Tok.getLocation()<wbr>, diag::err_mmap_expected_<wbr>rbrace);<br>
>> +      Diags.Report(LBraceLoc, diag::note_mmap_lbrace_match);<br>
>> +      HadError = true;<br>
>> +    }<br>
>>    }<br>
>> +<br>
>> +  Map.addUnresolvedHeader(<wbr>ActiveModule, std::move(Header));<br>
>>  }<br>
>><br>
>>  static int compareModuleHeaders(const Module::Header *A,<br>
>> @@ -2521,6 +2686,7 @@ bool ModuleMapParser::<wbr>parseModuleMapFile<br>
>>      case MMToken::RequiresKeyword:<br>
>>      case MMToken::Star:<br>
>>      case MMToken::StringLiteral:<br>
>> +    case MMToken::IntegerLiteral:<br>
>>      case MMToken::TextualKeyword:<br>
>>      case MMToken::UmbrellaKeyword:<br>
>>      case MMToken::UseKeyword:<br>
>><br>
>> Modified: cfe/trunk/lib/Lex/<wbr>PPDirectives.cpp<br>
>> URL:<br>
>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPDirectives.cpp?rev=304515&r1=304514&r2=304515&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/Lex/<wbr>PPDirectives.cpp?rev=304515&<wbr>r1=304514&r2=304515&view=diff</a><br>
>><br>
>> ==============================<wbr>==============================<wbr>==================<br>
>> --- cfe/trunk/lib/Lex/<wbr>PPDirectives.cpp (original)<br>
>> +++ cfe/trunk/lib/Lex/<wbr>PPDirectives.cpp Thu Jun  1 20:55:39 2017<br>
>> @@ -689,6 +689,8 @@ Preprocessor::<wbr>getModuleHeaderToIncludeFo<br>
>>    while (!Loc.isInvalid() && !SM.isInMainFile(Loc)) {<br>
>>      auto ID = SM.getFileID(SM.<wbr>getExpansionLoc(Loc));<br>
>>      auto *FE = SM.getFileEntryForID(ID);<br>
>> +    if (!FE)<br>
>> +      break;<br>
>><br>
>>      bool InTextualHeader = false;<br>
>>      for (auto Header :<br>
>> HeaderInfo.getModuleMap().<wbr>findAllModulesForHeader(FE)) {<br>
>><br>
>> Modified: cfe/trunk/lib/Serialization/<wbr>ASTWriter.cpp<br>
>> URL:<br>
>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=304515&r1=304514&r2=304515&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/<wbr>Serialization/ASTWriter.cpp?<wbr>rev=304515&r1=304514&r2=<wbr>304515&view=diff</a><br>
>><br>
>> ==============================<wbr>==============================<wbr>==================<br>
>> --- cfe/trunk/lib/Serialization/<wbr>ASTWriter.cpp (original)<br>
>> +++ cfe/trunk/lib/Serialization/<wbr>ASTWriter.cpp Thu Jun  1 20:55:39 2017<br>
>> @@ -1856,24 +1856,31 @@ namespace {<br>
>>    // Trait used for the on-disk hash table of header search information.<br>
>>    class HeaderFileInfoTrait {<br>
>>      ASTWriter &Writer;<br>
>> -    const HeaderSearch &HS;<br>
>><br>
>>      // Keep track of the framework names we've used during serialization.<br>
>>      SmallVector<char, 128> FrameworkStringData;<br>
>>      llvm::StringMap<unsigned> FrameworkNameOffset;<br>
>><br>
>>    public:<br>
>> -    HeaderFileInfoTrait(ASTWriter &Writer, const HeaderSearch &HS)<br>
>> -      : Writer(Writer), HS(HS) { }<br>
>> -<br>
>> +    HeaderFileInfoTrait(ASTWriter &Writer) : Writer(Writer) {}<br>
>> +<br>
>>      struct key_type {<br>
>> -      const FileEntry *FE;<br>
>>        StringRef Filename;<br>
>> +      off_t Size;<br>
>> +      time_t ModTime;<br>
>>      };<br>
>>      typedef const key_type &key_type_ref;<br>
>> +<br>
>> +    using UnresolvedModule =<br>
>> +        llvm::PointerIntPair<Module *, 2, ModuleMap::ModuleHeaderRole>;<br>
>><br>
>> -    typedef HeaderFileInfo data_type;<br>
>> +    struct data_type {<br>
>> +      const HeaderFileInfo &HFI;<br>
>> +      ArrayRef<ModuleMap::<wbr>KnownHeader> KnownHeaders;<br>
>> +      UnresolvedModule Unresolved;<br>
>> +    };<br>
>>      typedef const data_type &data_type_ref;<br>
>> +<br>
>>      typedef unsigned hash_value_type;<br>
>>      typedef unsigned offset_type;<br>
>><br>
>> @@ -1881,8 +1888,7 @@ namespace {<br>
>>        // The hash is based only on size/time of the file, so that the<br>
>> reader can<br>
>>        // match even when symlinking or excess path elements ("foo/../",<br>
>> "../")<br>
>>        // change the form of the name. However, complete path is still the<br>
>> key.<br>
>> -      return llvm::hash_combine(key.FE-><wbr>getSize(),<br>
>> -                                Writer.getTimestampForOutput(<wbr>key.FE));<br>
>> +      return llvm::hash_combine(key.Size, key.ModTime);<br>
>>      }<br>
>><br>
>>      std::pair<unsigned,unsigned><br>
>> @@ -1892,68 +1898,74 @@ namespace {<br>
>>        unsigned KeyLen = key.Filename.size() + 1 + 8 + 8;<br>
>>        LE.write<uint16_t>(KeyLen);<br>
>>        unsigned DataLen = 1 + 2 + 4 + 4;<br>
>> -      for (auto ModInfo :<br>
>> HS.getModuleMap().<wbr>findAllModulesForHeader(key.<wbr>FE))<br>
>> +      for (auto ModInfo : Data.KnownHeaders)<br>
>>          if (Writer.<wbr>getLocalOrImportedSubmoduleID(<wbr>ModInfo.getModule()))<br>
>>            DataLen += 4;<br>
>> +      if (Data.Unresolved.getPointer())<br>
>> +        DataLen += 4;<br>
>>        LE.write<uint8_t>(DataLen);<br>
>>        return std::make_pair(KeyLen, DataLen);<br>
>>      }<br>
>> -<br>
>> +<br>
>>      void EmitKey(raw_ostream& Out, key_type_ref key, unsigned KeyLen) {<br>
>>        using namespace llvm::support;<br>
>>        endian::Writer<little> LE(Out);<br>
>> -      LE.write<uint64_t>(key.FE-><wbr>getSize());<br>
>> +      LE.write<uint64_t>(key.Size);<br>
>>        KeyLen -= 8;<br>
>> -      LE.write<uint64_t>(Writer.<wbr>getTimestampForOutput(key.FE))<wbr>;<br>
>> +      LE.write<uint64_t>(key.<wbr>ModTime);<br>
>>        KeyLen -= 8;<br>
>>        Out.write(key.Filename.data(), KeyLen);<br>
>>      }<br>
>> -<br>
>> +<br>
>>      void EmitData(raw_ostream &Out, key_type_ref key,<br>
>>                    data_type_ref Data, unsigned DataLen) {<br>
>>        using namespace llvm::support;<br>
>>        endian::Writer<little> LE(Out);<br>
>>        uint64_t Start = Out.tell(); (void)Start;<br>
>><br>
>> -      unsigned char Flags = (Data.isImport << 4)<br>
>> -                          | (Data.isPragmaOnce << 3)<br>
>> -                          | (Data.DirInfo << 1)<br>
>> -                          | Data.IndexHeaderMapHeader;<br>
>> +      unsigned char Flags = (Data.HFI.isImport << 4)<br>
>> +                          | (Data.HFI.isPragmaOnce << 3)<br>
>> +                          | (Data.HFI.DirInfo << 1)<br>
>> +                          | Data.HFI.IndexHeaderMapHeader;<br>
>>        LE.write<uint8_t>(Flags);<br>
>> -      LE.write<uint16_t>(Data.<wbr>NumIncludes);<br>
>> +      LE.write<uint16_t>(Data.HFI.<wbr>NumIncludes);<br>
>><br>
>> -      if (!Data.ControllingMacro)<br>
>> -        LE.write<uint32_t>(Data.<wbr>ControllingMacroID);<br>
>> +      if (!Data.HFI.ControllingMacro)<br>
>> +        LE.write<uint32_t>(Data.HFI.<wbr>ControllingMacroID);<br>
>>        else<br>
>> -<br>
>> LE.write<uint32_t>(Writer.<wbr>getIdentifierRef(Data.<wbr>ControllingMacro));<br>
>> -<br>
>> +<br>
>> LE.write<uint32_t>(Writer.<wbr>getIdentifierRef(Data.HFI.<wbr>ControllingMacro));<br>
>> +<br>
>>        unsigned Offset = 0;<br>
>> -      if (!Data.Framework.empty()) {<br>
>> +      if (!Data.HFI.Framework.empty()) {<br>
>>          // If this header refers into a framework, save the framework<br>
>> name.<br>
>>          llvm::StringMap<unsigned>::<wbr>iterator Pos<br>
>> -          = FrameworkNameOffset.find(Data.<wbr>Framework);<br>
>> +          = FrameworkNameOffset.find(Data.<wbr>HFI.Framework);<br>
>>          if (Pos == FrameworkNameOffset.end()) {<br>
>>            Offset = FrameworkStringData.size() + 1;<br>
>> -          FrameworkStringData.append(<wbr>Data.Framework.begin(),<br>
>> -                                     Data.Framework.end());<br>
>> +          FrameworkStringData.append(<wbr>Data.HFI.Framework.begin(),<br>
>> +                                     Data.HFI.Framework.end());<br>
>>            FrameworkStringData.push_back(<wbr>0);<br>
>><br>
>> -          FrameworkNameOffset[Data.<wbr>Framework] = Offset;<br>
>> +          FrameworkNameOffset[Data.HFI.<wbr>Framework] = Offset;<br>
>>          } else<br>
>>            Offset = Pos->second;<br>
>>        }<br>
>>        LE.write<uint32_t>(Offset);<br>
>><br>
>> -      // FIXME: If the header is excluded, we should write out some<br>
>> -      // record of that fact.<br>
>> -      for (auto ModInfo :<br>
>> HS.getModuleMap().<wbr>findAllModulesForHeader(key.<wbr>FE)) {<br>
>> -        if (uint32_t ModID =<br>
>> -<br>
>> Writer.<wbr>getLocalOrImportedSubmoduleID(<wbr>ModInfo.getModule())) {<br>
>> -          uint32_t Value = (ModID << 2) | (unsigned)ModInfo.getRole();<br>
>> +      auto EmitModule = [&](Module *M, ModuleMap::ModuleHeaderRole Role)<br>
>> {<br>
>> +        if (uint32_t ModID = Writer.<wbr>getLocalOrImportedSubmoduleID(<wbr>M)) {<br>
>> +          uint32_t Value = (ModID << 2) | (unsigned)Role;<br>
>>            assert((Value >> 2) == ModID && "overflow in header module<br>
>> info");<br>
>>            LE.write<uint32_t>(Value);<br>
>>          }<br>
>> -      }<br>
>> +      };<br>
>> +<br>
>> +      // FIXME: If the header is excluded, we should write out some<br>
>> +      // record of that fact.<br>
>> +      for (auto ModInfo : Data.KnownHeaders)<br>
>> +        EmitModule(ModInfo.getModule()<wbr>, ModInfo.getRole());<br>
>> +      if (Data.Unresolved.getPointer())<br>
>> +        EmitModule(Data.Unresolved.<wbr>getPointer(),<br>
>> Data.Unresolved.getInt());<br>
>><br>
>>        assert(Out.tell() - Start == DataLen && "Wrong data length");<br>
>>      }<br>
>> @@ -1968,16 +1980,71 @@ namespace {<br>
>>  ///<br>
>>  /// \param HS The header search structure to save.<br>
>>  void ASTWriter::WriteHeaderSearch(<wbr>const HeaderSearch &HS) {<br>
>> +  HeaderFileInfoTrait GeneratorTrait(*this);<br>
>> +  llvm::<wbr>OnDiskChainedHashTableGenerato<wbr>r<HeaderFileInfoTrait> Generator;<br>
>> +  SmallVector<const char *, 4> SavedStrings;<br>
>> +  unsigned NumHeaderSearchEntries = 0;<br>
>> +<br>
>> +  // Find all unresolved headers for the current module. We generally<br>
>> will<br>
>> +  // have resolved them before we get here, but not necessarily: we might<br>
>> be<br>
>> +  // compiling a preprocessed module, where there is no requirement for<br>
>> the<br>
>> +  // original files to exist any more.<br>
>> +  if (WritingModule) {<br>
>> +    llvm::SmallVector<Module *, 16> Worklist(1, WritingModule);<br>
>> +    while (!Worklist.empty()) {<br>
>> +      Module *M = Worklist.pop_back_val();<br>
>> +      if (!M->isAvailable())<br>
>> +        continue;<br>
>> +<br>
>> +      // Map to disk files where possible, to pick up any missing stat<br>
>> +      // information. This also means we don't need to check the<br>
>> unresolved<br>
>> +      // headers list when emitting resolved headers in the first loop<br>
>> below.<br>
>> +      // FIXME: It'd be preferable to avoid doing this if we were given<br>
>> +      // sufficient stat information in the module map.<br>
>> +      HS.getModuleMap().<wbr>resolveHeaderDirectives(M);<br>
>> +<br>
>> +      // If the file didn't exist, we can still create a module if we<br>
>> were given<br>
>> +      // enough information in the module map.<br>
>> +      for (auto U : M->MissingHeaders) {<br>
>> +        // Check that we were given enough information to build a module<br>
>> +        // without this file existing on disk.<br>
>> +        if (!U.Size || (!U.ModTime && IncludeTimestamps)) {<br>
>> +          PP->Diag(U.FileNameLoc,<br>
>> diag::err_module_no_size_<wbr>mtime_for_header)<br>
>> +            << WritingModule-><wbr>getFullModuleName() << U.Size.hasValue()<br>
>> +            << U.FileName;<br>
>> +          continue;<br>
>> +        }<br>
>> +<br>
>> +        // Form the effective relative pathname for the file.<br>
>> +        SmallString<128> Filename(M->Directory-><wbr>getName());<br>
>> +        llvm::sys::path::append(<wbr>Filename, U.FileName);<br>
>> +        PreparePathForOutput(Filename)<wbr>;<br>
>> +<br>
>> +        StringRef FilenameDup = strdup(Filename.c_str());<br>
>> +        SavedStrings.push_back(<wbr>FilenameDup.data());<br>
>> +<br>
>> +        HeaderFileInfoTrait::key_type Key = {<br>
>> +          FilenameDup, *U.Size, IncludeTimestamps ? *U.ModTime : 0<br>
>> +        };<br>
>> +        HeaderFileInfoTrait::data_type Data = {<br>
>> +          {}, {}, {M, ModuleMap::headerKindToRole(U.<wbr>Kind)}<br>
>> +        };<br>
>> +        // FIXME: Deal with cases where there are multiple unresolved<br>
>> header<br>
>> +        // directives in different submodules for the same header.<br>
>> +        Generator.insert(Key, Data, GeneratorTrait);<br>
>> +        ++NumHeaderSearchEntries;<br>
>> +      }<br>
>> +<br>
>> +      Worklist.append(M->submodule_<wbr>begin(), M->submodule_end());<br>
>> +    }<br>
>> +  }<br>
>> +<br>
>>    SmallVector<const FileEntry *, 16> FilesByUID;<br>
>>    HS.getFileMgr().<wbr>GetUniqueIDMapping(FilesByUID)<wbr>;<br>
>><br>
>>    if (FilesByUID.size() > HS.header_file_size())<br>
>>      FilesByUID.resize(HS.header_<wbr>file_size());<br>
>> -<br>
>> -  HeaderFileInfoTrait GeneratorTrait(*this, HS);<br>
>> -  llvm::<wbr>OnDiskChainedHashTableGenerato<wbr>r<HeaderFileInfoTrait> Generator;<br>
>> -  SmallVector<const char *, 4> SavedStrings;<br>
>> -  unsigned NumHeaderSearchEntries = 0;<br>
>> +<br>
>>    for (unsigned UID = 0, LastUID = FilesByUID.size(); UID != LastUID;<br>
>> ++UID) {<br>
>>      const FileEntry *File = FilesByUID[UID];<br>
>>      if (!File)<br>
>> @@ -2004,11 +2071,16 @@ void ASTWriter::WriteHeaderSearch(<wbr>const<br>
>>        SavedStrings.push_back(<wbr>Filename.data());<br>
>>      }<br>
>><br>
>> -    HeaderFileInfoTrait::key_type key = { File, Filename };<br>
>> -    Generator.insert(key, *HFI, GeneratorTrait);<br>
>> +    HeaderFileInfoTrait::key_type Key = {<br>
>> +      Filename, File->getSize(), getTimestampForOutput(File)<br>
>> +    };<br>
>> +    HeaderFileInfoTrait::data_type Data = {<br>
>> +      *HFI, HS.getModuleMap().<wbr>findAllModulesForHeader(File), {}<br>
>> +    };<br>
>> +    Generator.insert(Key, Data, GeneratorTrait);<br>
>>      ++NumHeaderSearchEntries;<br>
>>    }<br>
>> -<br>
>> +<br>
>>    // Create the on-disk hash table in a buffer.<br>
>>    SmallString<4096> TableData;<br>
>>    uint32_t BucketOffset;<br>
>><br>
>> Added: cfe/trunk/test/Modules/Inputs/<wbr>header-attribs/bar.h<br>
>> URL:<br>
>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/header-attribs/bar.h?rev=304515&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/test/<wbr>Modules/Inputs/header-attribs/<wbr>bar.h?rev=304515&view=auto</a><br>
>><br>
>> ==============================<wbr>==============================<wbr>==================<br>
>> --- cfe/trunk/test/Modules/Inputs/<wbr>header-attribs/bar.h (added)<br>
>> +++ cfe/trunk/test/Modules/Inputs/<wbr>header-attribs/bar.h Thu Jun  1 20:55:39<br>
>> 2017<br>
>> @@ -0,0 +1 @@<br>
>> +extern int b;<br>
>><br>
>> Added: cfe/trunk/test/Modules/Inputs/<wbr>header-attribs/baz.h<br>
>> URL:<br>
>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/header-attribs/baz.h?rev=304515&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/test/<wbr>Modules/Inputs/header-attribs/<wbr>baz.h?rev=304515&view=auto</a><br>
>><br>
>> ==============================<wbr>==============================<wbr>==================<br>
>> --- cfe/trunk/test/Modules/Inputs/<wbr>header-attribs/baz.h (added)<br>
>> +++ cfe/trunk/test/Modules/Inputs/<wbr>header-attribs/baz.h Thu Jun  1 20:55:39<br>
>> 2017<br>
>> @@ -0,0 +1 @@<br>
>> +extern int c;<br>
>><br>
>> Added: cfe/trunk/test/Modules/Inputs/<wbr>header-attribs/foo.h<br>
>> URL:<br>
>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/header-attribs/foo.h?rev=304515&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/test/<wbr>Modules/Inputs/header-attribs/<wbr>foo.h?rev=304515&view=auto</a><br>
>><br>
>> ==============================<wbr>==============================<wbr>==================<br>
>> --- cfe/trunk/test/Modules/Inputs/<wbr>header-attribs/foo.h (added)<br>
>> +++ cfe/trunk/test/Modules/Inputs/<wbr>header-attribs/foo.h Thu Jun  1 20:55:39<br>
>> 2017<br>
>> @@ -0,0 +1 @@<br>
>> +extern int a;<br>
>> \ No newline at end of file<br>
>><br>
>> Added: cfe/trunk/test/Modules/Inputs/<wbr>header-attribs/modular.<wbr>modulemap<br>
>> URL:<br>
>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/header-attribs/modular.modulemap?rev=304515&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/test/<wbr>Modules/Inputs/header-attribs/<wbr>modular.modulemap?rev=304515&<wbr>view=auto</a><br>
>><br>
>> ==============================<wbr>==============================<wbr>==================<br>
>> --- cfe/trunk/test/Modules/Inputs/<wbr>header-attribs/modular.<wbr>modulemap (added)<br>
>> +++ cfe/trunk/test/Modules/Inputs/<wbr>header-attribs/modular.<wbr>modulemap Thu Jun<br>
>> 1 20:55:39 2017<br>
>> @@ -0,0 +1,5 @@<br>
>> +module A {<br>
>> +  header "foo.h" { size 13 }<br>
>> +  header "bar.h" { size 1000 }<br>
>> +  header "baz.h" { mtime 1 }<br>
>> +}<br>
>><br>
>> Added: cfe/trunk/test/Modules/Inputs/<wbr>header-attribs/textual.<wbr>modulemap<br>
>> URL:<br>
>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/header-attribs/textual.modulemap?rev=304515&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/test/<wbr>Modules/Inputs/header-attribs/<wbr>textual.modulemap?rev=304515&<wbr>view=auto</a><br>
>><br>
>> ==============================<wbr>==============================<wbr>==================<br>
>> --- cfe/trunk/test/Modules/Inputs/<wbr>header-attribs/textual.<wbr>modulemap (added)<br>
>> +++ cfe/trunk/test/Modules/Inputs/<wbr>header-attribs/textual.<wbr>modulemap Thu Jun<br>
>> 1 20:55:39 2017<br>
>> @@ -0,0 +1,5 @@<br>
>> +module A {<br>
>> +  textual header "foo.h" { size 13 }<br>
>> +  textual header "bar.h" { size 1000 }<br>
>> +  textual header "baz.h" { mtime 1 }<br>
>> +}<br>
>><br>
>> Modified: cfe/trunk/test/Modules/<wbr>diagnostics.modulemap<br>
>> URL:<br>
>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/diagnostics.modulemap?rev=304515&r1=304514&r2=304515&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/test/<wbr>Modules/diagnostics.modulemap?<wbr>rev=304515&r1=304514&r2=<wbr>304515&view=diff</a><br>
>><br>
>> ==============================<wbr>==============================<wbr>==================<br>
>> --- cfe/trunk/test/Modules/<wbr>diagnostics.modulemap (original)<br>
>> +++ cfe/trunk/test/Modules/<wbr>diagnostics.modulemap Thu Jun  1 20:55:39 2017<br>
>> @@ -1,4 +1,4 @@<br>
>> -// RUN: not %clang_cc1 -fmodules -fmodules-cache-path=%t<br>
>> -fmodule-map-file=%S/Inputs/<wbr>diagnostics-aux.modulemap -fmodule-map-file=%s<br>
>> -fsyntax-only -x c++ /dev/null 2>&1 | FileCheck %s<br>
>> +// RUN: not %clang_cc1 -fmodules -fmodules-cache-path=%t<br>
>> -fmodule-map-file=%S/Inputs/<wbr>diagnostics-aux.modulemap -fmodule-map-file=%s<br>
>> -fsyntax-only -x c++ /dev/null 2>&1 | FileCheck %s --implicit-check-not<br>
>> error:<br>
>><br>
>>  // CHECK: In file included from {{.*}}diagnostics-aux.<wbr>modulemap:3:<br>
>>  // CHECK: diagnostics-aux-2.modulemap:2:<wbr>3: error: expected<br>
>> @@ -15,3 +15,15 @@ module bad_use {<br>
>>    // CHECK: diagnostics.modulemap:[[@LINE+<wbr>1]]:22: error: use declarations<br>
>> are only allowed in top-level modules<br>
>>    module submodule { use foo }<br>
>>  }<br>
>> +<br>
>> +module header_attr {<br>
>> +  // CHECK: diagnostics.modulemap:[[@LINE+<wbr>1]]:20: error: expected a<br>
>> header attribute name<br>
>> +  header "foo.h" { x }<br>
>> +  // CHECK: diagnostics.modulemap:[[@LINE+<wbr>1]]:27: error: header attribute<br>
>> 'size' specified multiple times<br>
>> +  header "bar.h" { size 1 size 2 }<br>
>> +  // CHECK: diagnostics.modulemap:[[@LINE+<wbr>1]]:25: error: expected integer<br>
>> literal as value for header attribute 'size'<br>
>> +  header "baz.h" { size "30 kilobytes" }<br>
>> +<br>
>> +  header "quux.h" { size 1 mtime 2 }<br>
>> +  header "no_attrs.h" {}<br>
>> +}<br>
>><br>
>> Added: cfe/trunk/test/Modules/header-<wbr>attribs.cpp<br>
>> URL:<br>
>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/header-attribs.cpp?rev=304515&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/test/<wbr>Modules/header-attribs.cpp?<wbr>rev=304515&view=auto</a><br>
>><br>
>> ==============================<wbr>==============================<wbr>==================<br>
>> --- cfe/trunk/test/Modules/header-<wbr>attribs.cpp (added)<br>
>> +++ cfe/trunk/test/Modules/header-<wbr>attribs.cpp Thu Jun  1 20:55:39 2017<br>
>> @@ -0,0 +1,10 @@<br>
>> +// RUN: rm -rf %t<br>
>> +// RUN: %clang_cc1 -fmodules -I%S/Inputs/header-attribs<br>
>> -fmodule-map-file=%S/Inputs/<wbr>header-attribs/textual.<wbr>modulemap<br>
>> -fmodules-cache-path=%t -verify %s -fmodule-name=A -fmodules-strict-decluse<br>
>> +// RUN: not %clang_cc1 -fmodules -I%S/Inputs/header-attribs -emit-module<br>
>> -x c++-module-map %S/Inputs/header-attribs/<wbr>modular.modulemap<br>
>> -fmodules-cache-path=%t -fmodule-name=A 2>&1 | FileCheck %s --check-prefix<br>
>> BUILD-MODULAR<br>
>> +<br>
>> +#include "foo.h" // ok, stats match<br>
>> +#include "bar.h" // expected-error {{does not depend on a module<br>
>> exporting 'bar.h'}}<br>
>> +#include "baz.h" // expected-error {{does not depend on a module<br>
>> exporting 'baz.h'}}<br>
>> +<br>
>> +// FIXME: Explain why the 'bar.h' found on disk doesn't match the module<br>
>> map.<br>
>> +// BUILD-MODULAR: error: header 'bar.h' not found<br>
>><br>
>> Added: cfe/trunk/test/Modules/<wbr>preprocess-missing.modulemap<br>
>> URL:<br>
>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/preprocess-missing.modulemap?rev=304515&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/test/<wbr>Modules/preprocess-missing.<wbr>modulemap?rev=304515&view=auto</a><br>
>><br>
>> ==============================<wbr>==============================<wbr>==================<br>
>> --- cfe/trunk/test/Modules/<wbr>preprocess-missing.modulemap (added)<br>
>> +++ cfe/trunk/test/Modules/<wbr>preprocess-missing.modulemap Thu Jun  1<br>
>> 20:55:39 2017<br>
>> @@ -0,0 +1,7 @@<br>
>> +// RUN: %clang_cc1 -fmodules -fmodule-name=A -x c++-module-map %s<br>
>> -emit-module -o /dev/null -verify<br>
>> +module A {<br>
>> +  header "does not exist" { size 12345 } // ok, do not need mtime for<br>
>> explicit module build<br>
>> +  header "also does not exist" { mtime 12345 }<br>
>> +}<br>
>> +#pragma clang module contents<br>
>> +// expected-error@4 {{cannot emit module A: size must be explicitly<br>
>> specified for missing header file "also does not exist"}}<br>
>><br>
>> Modified: cfe/trunk/test/Modules/<wbr>preprocess-module.cpp<br>
>> URL:<br>
>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/preprocess-module.cpp?rev=304515&r1=304514&r2=304515&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/test/<wbr>Modules/preprocess-module.cpp?<wbr>rev=304515&r1=304514&r2=<wbr>304515&view=diff</a><br>
>><br>
>> ==============================<wbr>==============================<wbr>==================<br>
>> --- cfe/trunk/test/Modules/<wbr>preprocess-module.cpp (original)<br>
>> +++ cfe/trunk/test/Modules/<wbr>preprocess-module.cpp Thu Jun  1 20:55:39 2017<br>
>> @@ -28,12 +28,21 @@<br>
>>  // RUN: %clang_cc1 -fmodules -fmodule-file=%t/no-rewrite.<wbr>pcm %s -I%t<br>
>> -verify -fno-modules-error-recovery -DINCLUDE -I%S/Inputs/preprocess<br>
>>  // RUN: %clang_cc1 -fmodules -fmodule-file=%t/rewrite.pcm %s -I%t -verify<br>
>> -fno-modules-error-recovery -DREWRITE -DINCLUDE -I%S/Inputs/preprocess<br>
>><br>
>> +// Now try building the module when the header files are missing.<br>
>> +// RUN: cp %S/Inputs/preprocess/fwd.h %S/Inputs/preprocess/file.h<br>
>> %S/Inputs/preprocess/file2.h %S/Inputs/preprocess/module.<wbr>modulemap %t<br>
>> +// RUN: %clang_cc1 -fmodules -fmodule-name=file -fmodule-file=%t/fwd.pcm<br>
>> -I%t -x c++-module-map %t/module.modulemap -E -frewrite-includes -o<br>
>> %t/copy.ii<br>
>> +// RUN: rm %t/fwd.h %t/file.h %t/file2.h %t/module.modulemap<br>
>> +// RUN: %clang_cc1 -fmodules -fmodule-name=file -fmodule-file=%t/fwd.pcm<br>
>> -x c++-module-map-cpp-output %t/copy.ii -emit-module -o %t/copy.pcm<br>
>> +<br>
>> +// Finally, check that our module contains correct mapping information<br>
>> for the headers.<br>
>> +// RUN: cp %S/Inputs/preprocess/fwd.h %S/Inputs/preprocess/file.h<br>
>> %S/Inputs/preprocess/file2.h %S/Inputs/preprocess/module.<wbr>modulemap %t<br>
>> +// RUN: %clang_cc1 -fmodules -fmodule-file=%t/copy.pcm %s -I%t -verify<br>
>> -fno-modules-error-recovery -DCOPY -DINCLUDE<br>
>><br>
>>  // == module map<br>
>>  // CHECK: # 1 "{{.*}}module.modulemap"<br>
>>  // CHECK: module file {<br>
>> -// CHECK:   header "file.h"<br>
>> -// CHECK:   header "file2.h"<br>
>> +// CHECK:   header "file.h" { size<br>
>> +// CHECK:   header "file2.h" { size<br>
>>  // CHECK: }<br>
>><br>
>>  // == file.h<br>
>> @@ -98,6 +107,8 @@<br>
>>  __FILE *a; // expected-error {{declaration of '__FILE' must be imported}}<br>
>>  #ifdef REWRITE<br>
>>  // expected-note@rewrite.ii:1 {{here}}<br>
>> +#elif COPY<br>
>> +// expected-note@copy.ii:1 {{here}}<br>
>>  #else<br>
>>  // expected-note@no-rewrite.ii:1 {{here}}<br>
>>  #endif<br>
>><br>
>><br>
>> ______________________________<wbr>_________________<br>
>> cfe-commits mailing list<br>
>> <a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a><br>
>> <a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/cfe-commits</a><br>
><br>
><br>
><br>
> ______________________________<wbr>_________________<br>
> cfe-commits mailing list<br>
> <a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a><br>
> <a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/cfe-commits</a><br>
><br>
</div></div></blockquote></div><br></div>