When making modules transitively visible, don't take into account

whether they have missing header files.

Whether a module's headers happen to be present on the local file system
should make no difference to whether we make its contents visible when
importing another module that re-exports it. If we have an up-to-date
AST file that we can load, that's all that matters.

This fixes the ability to header syntax checking for modular headers in
C++20 mode (or in prior modes where -fmodules-local-submodule-visibility
is enabled but -fmodules is not).
This commit is contained in:
Richard Smith 2020-04-17 20:25:15 -07:00
parent fc76b4ad3d
commit 6bc7502385
10 changed files with 32 additions and 5 deletions

View File

@ -654,8 +654,8 @@ void VisibleModuleSet::setVisible(Module *M, SourceLocation Loc,
SmallVector<Module *, 16> Exports;
V.M->getExportedModules(Exports);
for (Module *E : Exports) {
// Don't recurse to unavailable submodules.
if (E->isAvailable())
// Don't import non-importable modules.
if (!E->isUnimportable())
VisitModule({E, &V});
}

View File

@ -544,6 +544,9 @@ void ModuleMap::diagnoseHeaderInclusion(Module *RequestingModule,
static bool isBetterKnownHeader(const ModuleMap::KnownHeader &New,
const ModuleMap::KnownHeader &Old) {
// Prefer available modules.
// FIXME: Considering whether the module is available rather than merely
// importable is non-hermetic and can result in surprising behavior for
// prebuilt modules. Consider only checking for importability here.
if (New.getModule()->isAvailable() && !Old.getModule()->isAvailable())
return true;

View File

@ -4033,8 +4033,8 @@ void ASTReader::makeModuleVisible(Module *Mod,
continue;
}
if (!Mod->isAvailable()) {
// Modules that aren't available cannot be made visible.
if (Mod->isUnimportable()) {
// Modules that aren't importable cannot be made visible.
continue;
}

View File

@ -1729,7 +1729,8 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS) {
llvm::SmallVector<Module *, 16> Worklist(1, WritingModule);
while (!Worklist.empty()) {
Module *M = Worklist.pop_back_val();
if (!M->isAvailable())
// We don't care about headers in unimportable submodules.
if (M->isUnimportable())
continue;
// Map to disk files where possible, to pick up any missing stat

View File

@ -0,0 +1,2 @@
#include "x.h"
X a();

View File

@ -0,0 +1,2 @@
#include "a.h"
#include "b.h"

View File

@ -0,0 +1,2 @@
#include "a.h"
X b();

View File

@ -0,0 +1,6 @@
module M {
module A { header "a.h" export * }
module B { header "b.h" export * }
module X { header "x.h" header "missing.h" export * }
module All { header "all.h" export * }
}

View File

@ -0,0 +1,4 @@
#ifndef X_H
#define X_H
struct X {};
#endif

View File

@ -0,0 +1,7 @@
// RUN: %clang_cc1 -fmodules-local-submodule-visibility -fimplicit-module-maps -I%S/Inputs/missing-header-local-visibility %s
// RUN: %clang_cc1 -fmodules-local-submodule-visibility -fimplicit-module-maps -I%S/Inputs/missing-header-local-visibility -x c++-header %S/Inputs/missing-header-local-visibility/all.h
// RUN: %clang_cc1 -fmodule-name=M -std=c++2a -fimplicit-module-maps -I%S/Inputs/missing-header-local-visibility -x c++-header %s
// RUN: %clang_cc1 -fmodule-name=M -std=c++2a -fimplicit-module-maps -I%S/Inputs/missing-header-local-visibility -x c++-header %S/Inputs/missing-header-local-visibility/all.h
#include "a.h"
#include "b.h"