When making modules transitively visible, don't take into account
authorRichard Smith <richard@metafoo.co.uk>
Sat, 18 Apr 2020 03:25:15 +0000 (20:25 -0700)
committerRichard Smith <richard@metafoo.co.uk>
Sat, 18 Apr 2020 05:49:58 +0000 (22:49 -0700)
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).

clang/lib/Basic/Module.cpp
clang/lib/Lex/ModuleMap.cpp
clang/lib/Serialization/ASTReader.cpp
clang/lib/Serialization/ASTWriter.cpp
clang/test/Modules/Inputs/missing-header-local-visibility/a.h [new file with mode: 0644]
clang/test/Modules/Inputs/missing-header-local-visibility/all.h [new file with mode: 0644]
clang/test/Modules/Inputs/missing-header-local-visibility/b.h [new file with mode: 0644]
clang/test/Modules/Inputs/missing-header-local-visibility/module.modulemap [new file with mode: 0644]
clang/test/Modules/Inputs/missing-header-local-visibility/x.h [new file with mode: 0644]
clang/test/Modules/missing-header-local-visibility.cpp [new file with mode: 0644]

index 22e1da4..b3daaa3 100644 (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});
     }
 
index 2c79bb2..4f7d5ab 100644 (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;
 
index e2f89f5..8731158 100644 (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;
     }
 
index 18a92aa..31d004f 100644 (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
diff --git a/clang/test/Modules/Inputs/missing-header-local-visibility/a.h b/clang/test/Modules/Inputs/missing-header-local-visibility/a.h
new file mode 100644 (file)
index 0000000..3ff0ea8
--- /dev/null
@@ -0,0 +1,2 @@
+#include "x.h"
+X a();
diff --git a/clang/test/Modules/Inputs/missing-header-local-visibility/all.h b/clang/test/Modules/Inputs/missing-header-local-visibility/all.h
new file mode 100644 (file)
index 0000000..600af31
--- /dev/null
@@ -0,0 +1,2 @@
+#include "a.h"
+#include "b.h"
diff --git a/clang/test/Modules/Inputs/missing-header-local-visibility/b.h b/clang/test/Modules/Inputs/missing-header-local-visibility/b.h
new file mode 100644 (file)
index 0000000..0fdb115
--- /dev/null
@@ -0,0 +1,2 @@
+#include "a.h"
+X b();
diff --git a/clang/test/Modules/Inputs/missing-header-local-visibility/module.modulemap b/clang/test/Modules/Inputs/missing-header-local-visibility/module.modulemap
new file mode 100644 (file)
index 0000000..0f21cee
--- /dev/null
@@ -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 * }
+}
diff --git a/clang/test/Modules/Inputs/missing-header-local-visibility/x.h b/clang/test/Modules/Inputs/missing-header-local-visibility/x.h
new file mode 100644 (file)
index 0000000..0498c5d
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef X_H
+#define X_H
+struct X {};
+#endif
diff --git a/clang/test/Modules/missing-header-local-visibility.cpp b/clang/test/Modules/missing-header-local-visibility.cpp
new file mode 100644 (file)
index 0000000..e282a1b
--- /dev/null
@@ -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"