diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h index bba0c38cec777420ca21f31f00d96c0bc12ef30b..b2f58ead0e7560d785e6236667a024f33730045d 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -786,6 +786,22 @@ public: (!getLangOpts().Modules || (bool)getMacroDefinition(II)); } + /// \brief Determine whether II is defined as a macro within the module M, + /// if that is a module that we've already preprocessed. Does not check for + /// macros imported into M. + bool isMacroDefinedInLocalModule(const IdentifierInfo *II, Module *M) { + if (!II->hasMacroDefinition()) + return false; + auto I = Submodules.find(M); + if (I == Submodules.end()) + return false; + auto J = I->second.Macros.find(II); + if (J == I->second.Macros.end()) + return false; + auto *MD = J->second.getLatest(); + return MD && MD->isDefined(); + } + MacroDefinition getMacroDefinition(const IdentifierInfo *II) { if (!II->hasMacroDefinition()) return MacroDefinition(); diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp index 6c5c64bd266b0a5865bd91bcc00d6aced91fbaed..b805990eecbf2c4703d52f5241376c7656c09fbe 100644 --- a/lib/Lex/HeaderSearch.cpp +++ b/lib/Lex/HeaderSearch.cpp @@ -995,7 +995,8 @@ HeaderFileInfo &HeaderSearch::getFileInfo(const FileEntry *FE) { return HFI; } -bool HeaderSearch::tryGetFileInfo(const FileEntry *FE, HeaderFileInfo &Result) const { +bool HeaderSearch::tryGetFileInfo(const FileEntry *FE, + HeaderFileInfo &Result) const { if (FE->getUID() >= FileInfo.size()) return false; const HeaderFileInfo &HFI = FileInfo[FE->getUID()]; @@ -1028,7 +1029,7 @@ void HeaderSearch::MarkFileModuleHeader(const FileEntry *FE, HeaderFileInfo &HFI = FileInfo[FE->getUID()]; HFI.isModuleHeader = true; - HFI.isCompilingModuleHeader = isCompilingModuleHeader; + HFI.isCompilingModuleHeader |= isCompilingModuleHeader; HFI.setHeaderRole(Role); } @@ -1058,15 +1059,16 @@ bool HeaderSearch::ShouldEnterIncludeFile(Preprocessor &PP, // Next, check to see if the file is wrapped with #ifndef guards. If so, and // if the macro that guards it is defined, we know the #include has no effect. if (const IdentifierInfo *ControllingMacro - = FileInfo.getControllingMacro(ExternalLookup)) - // If the include file is part of a module, and we already know what its - // controlling macro is, then we've already parsed it and can safely just - // make it visible. This saves us needing to switch into the visibility - // state of the module just to check whether the macro is defined within it. - if (M || PP.isMacroDefined(ControllingMacro)) { + = FileInfo.getControllingMacro(ExternalLookup)) { + // If the header corresponds to a module, check whether the macro is already + // defined in that module rather than checking in the current set of visible + // modules. + if (M ? PP.isMacroDefinedInLocalModule(ControllingMacro, M) + : PP.isMacroDefined(ControllingMacro)) { ++NumMultiIncludeFileOptzn; return false; } + } // Increment the number of times this file has been included. ++FileInfo.NumIncludes; diff --git a/test/Modules/Inputs/multiple-include/a.h b/test/Modules/Inputs/multiple-include/a.h new file mode 100644 index 0000000000000000000000000000000000000000..8266190858888adfe621c73a9f7722dab8737ece --- /dev/null +++ b/test/Modules/Inputs/multiple-include/a.h @@ -0,0 +1 @@ +#include "x.h" diff --git a/test/Modules/Inputs/multiple-include/b.h b/test/Modules/Inputs/multiple-include/b.h new file mode 100644 index 0000000000000000000000000000000000000000..f56ab64da6b1c0883345bd52f8fbd8899f35f3c9 --- /dev/null +++ b/test/Modules/Inputs/multiple-include/b.h @@ -0,0 +1,3 @@ +#pragma clang __debug macro C_H +#include "c.h" +inline int get() { return c; } diff --git a/test/Modules/Inputs/multiple-include/c.h b/test/Modules/Inputs/multiple-include/c.h new file mode 100644 index 0000000000000000000000000000000000000000..4e7d4b742dc3ab667eb06d23fc519d5b744ead4a --- /dev/null +++ b/test/Modules/Inputs/multiple-include/c.h @@ -0,0 +1,4 @@ +#ifndef C_H +#define C_H +extern int c; +#endif diff --git a/test/Modules/Inputs/multiple-include/module.modulemap b/test/Modules/Inputs/multiple-include/module.modulemap new file mode 100644 index 0000000000000000000000000000000000000000..1228ae6cbb732119318c8843e474f7dc0cf50063 --- /dev/null +++ b/test/Modules/Inputs/multiple-include/module.modulemap @@ -0,0 +1,2 @@ +module A { module a { header "a.h" } module b { header "b.h" } module c { header "c.h" } } +module X { module x { header "x.h" } module c { header "c.h" } } diff --git a/test/Modules/Inputs/multiple-include/x.h b/test/Modules/Inputs/multiple-include/x.h new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/test/Modules/multiple-include.cpp b/test/Modules/multiple-include.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7cbeefc81782efa1493984294fd9651426144f61 --- /dev/null +++ b/test/Modules/multiple-include.cpp @@ -0,0 +1,5 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -fmodules -I%S/Inputs/multiple-include -fmodules-cache-path=%t -fimplicit-module-maps -verify %s -fmodules-local-submodule-visibility +// expected-no-diagnostics +#include "b.h" +int c = get();