aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIain Sandoe <iain@sandoe.co.uk>2023-06-12 20:38:02 +0100
committerIain Sandoe <iain@sandoe.co.uk>2023-06-25 08:33:39 +0100
commitb37233a253f30e4bd5f040d598826df443293bee (patch)
tree82d6ff3f6f8eacb0b770e8cc337decb8f3155227
parent2a61ceddb30aaed291317795e3183371e8cf3d7a (diff)
downloadllvm-b37233a253f30e4bd5f040d598826df443293bee.zip
llvm-b37233a253f30e4bd5f040d598826df443293bee.tar.gz
llvm-b37233a253f30e4bd5f040d598826df443293bee.tar.bz2
[C++20][Modules] Complete implementation of module.import p7.
The following test fails to compile TU b.cpp because we are not making the transitively imported modules visible (per [module.import]/p7) ``` a.cppm: export module a; export int foo() { return 42; } b.cppm: export module b; import a; export int bar(); b.cpp: module b; int bar() { return foo(); } clang++ -c -std=c++2b -fmodule-output a.cppm clang++ -c -std=c++2b -fmodule-output -fprebuilt-module-path=. b.cppm clang++ -c -std=c++2b -fprebuilt-module-path=. b.cpp b.cpp:4:12: error: declaration of 'foo' must be imported from module 'a' before it is required return foo(); ``` This is fixed by the following patch (which also addresses a FIXME in basic.def.odr/p6.cppm). Differential Revision: https://reviews.llvm.org/D152746
-rw-r--r--clang/include/clang/Basic/Module.h5
-rw-r--r--clang/lib/Basic/Module.cpp8
-rw-r--r--clang/lib/Sema/SemaModule.cpp1
-rw-r--r--clang/test/CXX/module/basic/basic.def.odr/p6.cppm5
-rw-r--r--clang/test/CXX/module/module.import/p7.cpp49
5 files changed, 65 insertions, 3 deletions
diff --git a/clang/include/clang/Basic/Module.h b/clang/include/clang/Basic/Module.h
index 399ed92..b3b5376 100644
--- a/clang/include/clang/Basic/Module.h
+++ b/clang/include/clang/Basic/Module.h
@@ -822,6 +822,11 @@ public:
ConflictCallback Cb = [](ArrayRef<Module *>, Module *,
StringRef) {});
+ /// Make transitive imports visible for [module.import]/7.
+ void makeTransitiveImportsVisible(
+ Module *M, SourceLocation Loc, VisibleCallback Vis = [](Module *) {},
+ ConflictCallback Cb = [](ArrayRef<Module *>, Module *, StringRef) {});
+
private:
/// Import locations for each visible module. Indexed by the module's
/// VisibilityID.
diff --git a/clang/lib/Basic/Module.cpp b/clang/lib/Basic/Module.cpp
index 3f9b8d0..2bdbe8d2 100644
--- a/clang/lib/Basic/Module.cpp
+++ b/clang/lib/Basic/Module.cpp
@@ -695,6 +695,14 @@ void VisibleModuleSet::setVisible(Module *M, SourceLocation Loc,
VisitModule({M, nullptr});
}
+void VisibleModuleSet::makeTransitiveImportsVisible(Module *M,
+ SourceLocation Loc,
+ VisibleCallback Vis,
+ ConflictCallback Cb) {
+ for (auto *I : M->Imports)
+ setVisible(I, Loc, Vis, Cb);
+}
+
ASTSourceDescriptor::ASTSourceDescriptor(Module &M)
: Signature(M.Signature), ClangModule(&M) {
if (M.Directory)
diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp
index 9b2982e..2ffb0db 100644
--- a/clang/lib/Sema/SemaModule.cpp
+++ b/clang/lib/Sema/SemaModule.cpp
@@ -397,6 +397,7 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
if (Interface) {
VisibleModules.setVisible(Interface, ModuleLoc);
+ VisibleModules.makeTransitiveImportsVisible(Interface, ModuleLoc);
// Make the import decl for the interface in the impl module.
ImportDecl *Import = ImportDecl::Create(Context, CurContext, ModuleLoc,
diff --git a/clang/test/CXX/module/basic/basic.def.odr/p6.cppm b/clang/test/CXX/module/basic/basic.def.odr/p6.cppm
index d84c05c..8e7917d 100644
--- a/clang/test/CXX/module/basic/basic.def.odr/p6.cppm
+++ b/clang/test/CXX/module/basic/basic.def.odr/p6.cppm
@@ -17,9 +17,8 @@
//
// RUN: %clang_cc1 -std=c++20 %t/module-vs-module.cpp -fmodule-file=M=%t/M.pcm -emit-module-interface -o %t/N.pcm -DMODULE_INTERFACE -DNO_ERRORS
// RUN: %clang_cc1 -std=c++20 %t/module-vs-module.cpp -fmodule-file=M=%t/M.pcm -fmodule-file=N=%t/N.pcm -verify
-// FIXME: Once we start importing "import" declarations properly, this should
-// be rejected (-verify should be added to the following line).
-// RUN: %clang_cc1 -std=c++20 %t/module-vs-module.cpp -fmodule-file=M=%t/M.pcm -fmodule-file=N=%t/N.pcm -DNO_IMPORT
+//
+// RUN: %clang_cc1 -std=c++20 %t/module-vs-module.cpp -fmodule-file=M=%t/M.pcm -fmodule-file=N=%t/N.pcm -DNO_IMPORT -verify
//
// RUN: %clang_cc1 -std=c++20 %t/module-vs-module.cpp -fmodule-file=M=%t/M.pcm -emit-module-interface -o %t/N-no-M.pcm -DMODULE_INTERFACE -DNO_ERRORS -DNO_IMPORT
// RUN: %clang_cc1 -std=c++20 %t/module-vs-module.cpp -fmodule-file=M=%t/M.pcm -fmodule-file=N=%t/N-no-M.pcm -verify
diff --git a/clang/test/CXX/module/module.import/p7.cpp b/clang/test/CXX/module/module.import/p7.cpp
new file mode 100644
index 0000000..2de6f0b
--- /dev/null
+++ b/clang/test/CXX/module/module.import/p7.cpp
@@ -0,0 +1,49 @@
+// RUN: mkdir -p %t
+// RUN: split-file %s %t
+
+// All of the following should build without diagnostics.
+//
+// RUN: %clang_cc1 -std=c++20 %t/a.cpp -emit-module-interface -o %t/a.pcm
+// R U N: %clang_cc1 -std=c++20 %t/a.pcm -emit-obj -o %t/a.o
+//
+// RUN: %clang_cc1 -std=c++20 %t/b.cpp -emit-module-interface -o %t/b.pcm \
+// RUN: -fprebuilt-module-path=%t
+// R U N: %clang_cc1 -std=c++20 %t/b.pcm -emit-obj -o %t/b.o
+//
+// RUN: %clang_cc1 -std=c++20 %t/b-impl.cpp -emit-obj -o %t/b-impl.o \
+// RUN: -fprebuilt-module-path=%t
+//
+// RUN: %clang_cc1 -std=c++20 %t/ab-main.cpp -fsyntax-only \
+// RUN: -fprebuilt-module-path=%t
+
+//--- a.cpp
+
+export module a;
+
+export int foo() {
+ return 42;
+}
+
+//--- b.cpp
+
+export module b;
+import a;
+
+export int bar();
+
+//--- b-impl.cpp
+
+module b;
+
+int bar() {
+ return foo();
+}
+
+//--- ab-main.cpp
+
+import b;
+
+int main() {
+ return bar();
+}
+