[C++20] [Modules] Don't create multiple global module fragment
authorChuanqi Xu <yedeng.yd@linux.alibaba.com>
Tue, 8 Feb 2022 03:50:57 +0000 (11:50 +0800)
committerChuanqi Xu <yedeng.yd@linux.alibaba.com>
Tue, 8 Feb 2022 03:52:09 +0000 (11:52 +0800)
Since the serialization code would recognize modules by names and the
name of all global module fragment is <global>, so that the
serialization code would complain for the same module.

This patch fixes this by using a unique global module fragment in Sema.
Before this patch, the compiler would fail on an assertion complaining
the duplicated modules.

Reviewed By: urnathan, rsmith

Differential Revision: https://reviews.llvm.org/D115610

clang/include/clang/Sema/Sema.h
clang/lib/Sema/SemaModule.cpp
clang/test/CXX/module/module.unit/p7/Inputs/h8.h [new file with mode: 0644]
clang/test/CXX/module/module.unit/p7/Inputs/m8.cppm [new file with mode: 0644]
clang/test/CXX/module/module.unit/p7/t8.cpp [new file with mode: 0644]

index 4b609f4..3014865 100644 (file)
@@ -2218,6 +2218,8 @@ private:
   };
   /// The modules we're currently parsing.
   llvm::SmallVector<ModuleScope, 16> ModuleScopes;
+  /// The global module fragment of the current translation unit.
+  clang::Module *GlobalModuleFragment = nullptr;
 
   /// Namespace definitions that we will export when they finish.
   llvm::SmallPtrSet<const NamespaceDecl*, 8> DeferredExportedNamespaces;
index 747734f..85e5864 100644 (file)
@@ -720,19 +720,24 @@ Decl *Sema::ActOnFinishExportDecl(Scope *S, Decl *D, SourceLocation RBraceLoc) {
 
 Module *Sema::PushGlobalModuleFragment(SourceLocation BeginLoc,
                                        bool IsImplicit) {
-  ModuleMap &Map = PP.getHeaderSearchInfo().getModuleMap();
-  Module *GlobalModule =
-      Map.createGlobalModuleFragmentForModuleUnit(BeginLoc, getCurrentModule());
-  assert(GlobalModule && "module creation should not fail");
+  // We shouldn't create new global module fragment if there is already
+  // one.
+  if (!GlobalModuleFragment) {
+    ModuleMap &Map = PP.getHeaderSearchInfo().getModuleMap();
+    GlobalModuleFragment = Map.createGlobalModuleFragmentForModuleUnit(
+        BeginLoc, getCurrentModule());
+  }
+
+  assert(GlobalModuleFragment && "module creation should not fail");
 
   // Enter the scope of the global module.
-  ModuleScopes.push_back({BeginLoc, GlobalModule,
+  ModuleScopes.push_back({BeginLoc, GlobalModuleFragment,
                           /*ModuleInterface=*/false,
                           /*ImplicitGlobalModuleFragment=*/IsImplicit,
-                          /*VisibleModuleSet*/{}});
-  VisibleModules.setVisible(GlobalModule, BeginLoc);
+                          /*VisibleModuleSet*/ {}});
+  VisibleModules.setVisible(GlobalModuleFragment, BeginLoc);
 
-  return GlobalModule;
+  return GlobalModuleFragment;
 }
 
 void Sema::PopGlobalModuleFragment() {
diff --git a/clang/test/CXX/module/module.unit/p7/Inputs/h8.h b/clang/test/CXX/module/module.unit/p7/Inputs/h8.h
new file mode 100644 (file)
index 0000000..2ef06cd
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef H8
+#define H8
+void foo();
+#endif
diff --git a/clang/test/CXX/module/module.unit/p7/Inputs/m8.cppm b/clang/test/CXX/module/module.unit/p7/Inputs/m8.cppm
new file mode 100644 (file)
index 0000000..ef0c6c6
--- /dev/null
@@ -0,0 +1,7 @@
+module;
+#include "h8.h"
+export module m8;
+
+extern "C++" {
+void bar();
+}
diff --git a/clang/test/CXX/module/module.unit/p7/t8.cpp b/clang/test/CXX/module/module.unit/p7/t8.cpp
new file mode 100644 (file)
index 0000000..8310fc7
--- /dev/null
@@ -0,0 +1,7 @@
+// RUN: rm -fr %t
+// RUN: mkdir %t
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface %S/Inputs/m8.cppm -I%S/Inputs -o %t/m8.pcm
+// RUN: %clang_cc1 -std=c++20 -I%S/Inputs/ -fprebuilt-module-path=%t %s -verify -fsyntax-only
+// expected-no-diagnostics
+export module t8;
+import m8;