diff --git a/clang/include/clang/Lex/HeaderSearch.h b/clang/include/clang/Lex/HeaderSearch.h --- a/clang/include/clang/Lex/HeaderSearch.h +++ b/clang/include/clang/Lex/HeaderSearch.h @@ -277,6 +277,9 @@ /// Keeps track of each lookup performed by LookupFile. struct LookupFileCacheInfo { + // The requesting module for the lookup we cached. + const Module *RequestingModule = nullptr; + /// Starting search directory iterator that the cached search was performed /// from. If there is a hit and this value doesn't match the current query, /// the cache has to be ignored. @@ -292,7 +295,9 @@ /// Default constructor -- Initialize all members with zero. LookupFileCacheInfo() = default; - void reset(ConstSearchDirIterator NewStartIt) { + void reset(const Module *NewRequestingModule, + ConstSearchDirIterator NewStartIt) { + RequestingModule = NewRequestingModule; StartIt = NewStartIt; MappedName = nullptr; } diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp --- a/clang/lib/Lex/HeaderSearch.cpp +++ b/clang/lib/Lex/HeaderSearch.cpp @@ -1008,7 +1008,8 @@ ConstSearchDirIterator NextIt = std::next(It); if (!SkipCache) { - if (CacheLookup.StartIt == NextIt) { + if (CacheLookup.StartIt == NextIt && + CacheLookup.RequestingModule == RequestingModule) { // HIT: Skip querying potentially lots of directories for this lookup. if (CacheLookup.HitIt) It = CacheLookup.HitIt; @@ -1021,7 +1022,7 @@ // MISS: This is the first query, or the previous query didn't match // our search start. We will fill in our found location below, so prime // the start point value. - CacheLookup.reset(/*NewStartIt=*/NextIt); + CacheLookup.reset(RequestingModule, /*NewStartIt=*/NextIt); if (It == search_dir_begin() && FirstNonHeaderMapSearchDirIdx > 0) { // Handle cold misses of user includes in the presence of many header @@ -1036,8 +1037,9 @@ It = search_dir_nth(Iter->second); } } - } else - CacheLookup.reset(/*NewStartIt=*/NextIt); + } else { + CacheLookup.reset(RequestingModule, /*NewStartIt=*/NextIt); + } SmallString<64> MappedName; diff --git a/clang/test/Modules/lookup-file-cache.cpp b/clang/test/Modules/lookup-file-cache.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Modules/lookup-file-cache.cpp @@ -0,0 +1,27 @@ +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: %clang_cc1 -I %t/include -fmodules -fimplicit-module-maps \ +// RUN: -fmodules-cache-path=%t/cache -fsyntax-only %t/tu.c + +//--- include/module.modulemap +module A [no_undeclared_includes] { textual header "A.h" } +module B { header "B.h" } + +//--- include/A.h +#if __has_include() +#error B.h should not be available from A.h. +#endif + +//--- include/B.h +// This file intentionally left blank. + +//--- tu.c +#if !__has_include() +#error B.h should be available from tu.c. +#endif + +#include "A.h" + +#if !__has_include() +#error B.h should still be available from tu.c. +#endif