[clang] 6114491 - [C++20][Modules][4/8] Handle generation of partition implementation CMIs.

Iain Sandoe via cfe-commits cfe-commits at lists.llvm.org
Fri Feb 25 01:33:40 PST 2022


Author: Iain Sandoe
Date: 2022-02-25T09:33:14Z
New Revision: 6114491441700cc8a614d284407e9a6e9bf74751

URL: https://github.com/llvm/llvm-project/commit/6114491441700cc8a614d284407e9a6e9bf74751
DIFF: https://github.com/llvm/llvm-project/commit/6114491441700cc8a614d284407e9a6e9bf74751.diff

LOG: [C++20][Modules][4/8] Handle generation of partition implementation CMIs.

Partition implementations are special, they generate a CMI, but it
does not have an 'export' line, and we cannot export anything from the
it [that is it can only make decls available to other members of the
owning module, not to importers of that].

Add initial testcases for partition handling, derived from the examples in
Section 10 of the C++20 standard, which identifies what should be accepted
and/or rejected.

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

Added: 
    clang/test/Modules/cxx20-10-1-ex1.cpp
    clang/test/Modules/cxx20-10-1-ex2.cpp

Modified: 
    clang/include/clang/Sema/Sema.h
    clang/lib/Sema/SemaModule.cpp
    clang/test/Modules/cxx20-import-diagnostics-a.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 436718a54640e..0b872c48482db 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -2943,8 +2943,10 @@ class Sema final {
                               SourceLocation SemiLoc);
 
   enum class ModuleDeclKind {
-    Interface,      ///< 'export module X;'
-    Implementation, ///< 'module X;'
+    Interface,               ///< 'export module X;'
+    Implementation,          ///< 'module X;'
+    PartitionInterface,      ///< 'export module X:Y;'
+    PartitionImplementation, ///< 'module X:Y;'
   };
 
   /// An enumeration to represent the transition of states in parsing module

diff  --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp
index a797644754b59..b2515075a7f23 100644
--- a/clang/lib/Sema/SemaModule.cpp
+++ b/clang/lib/Sema/SemaModule.cpp
@@ -110,9 +110,24 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
   // module state;
   ImportState = ModuleImportState::NotACXX20Module;
 
-  // A module implementation unit requires that we are not compiling a module
-  // of any kind. A module interface unit requires that we are not compiling a
-  // module map.
+  bool IsPartition = !Partition.empty();
+  if (IsPartition)
+    switch (MDK) {
+    case ModuleDeclKind::Implementation:
+      MDK = ModuleDeclKind::PartitionImplementation;
+      break;
+    case ModuleDeclKind::Interface:
+      MDK = ModuleDeclKind::PartitionInterface;
+      break;
+    default:
+      llvm_unreachable("how did we get a partition type set?");
+    }
+
+  // A (non-partition) module implementation unit requires that we are not
+  // compiling a module of any kind.  A partition implementation emits an
+  // interface (and the AST for the implementation), which will subsequently
+  // be consumed to emit a binary.
+  // A module interface unit requires that we are not compiling a module map.
   switch (getLangOpts().getCompilingModule()) {
   case LangOptions::CMK_None:
     // It's OK to compile a module interface as a normal translation unit.
@@ -123,7 +138,7 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
       break;
 
     // We were asked to compile a module interface unit but this is a module
-    // implementation unit. That indicates the 'export' is missing.
+    // implementation unit.
     Diag(ModuleLoc, diag::err_module_interface_implementation_mismatch)
       << FixItHint::CreateInsertion(ModuleLoc, "export ");
     MDK = ModuleDeclKind::Interface;
@@ -180,7 +195,6 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
   // modules, the dots here are just another character that can appear in a
   // module name.
   std::string ModuleName = stringFromPath(Path);
-  bool IsPartition = !Partition.empty();
   if (IsPartition) {
     ModuleName += ":";
     ModuleName += stringFromPath(Partition);
@@ -202,7 +216,8 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
   Module *Mod;
 
   switch (MDK) {
-  case ModuleDeclKind::Interface: {
+  case ModuleDeclKind::Interface:
+  case ModuleDeclKind::PartitionInterface: {
     // We can't have parsed or imported a definition of this module or parsed a
     // module map defining it already.
     if (auto *M = Map.findModule(ModuleName)) {
@@ -219,36 +234,36 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
     // Create a Module for the module that we're defining.
     Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName,
                                            GlobalModuleFragment);
-    if (IsPartition)
+    if (MDK == ModuleDeclKind::PartitionInterface)
       Mod->Kind = Module::ModulePartitionInterface;
     assert(Mod && "module creation should not fail");
     break;
   }
 
-  case ModuleDeclKind::Implementation:
+  case ModuleDeclKind::Implementation: {
     std::pair<IdentifierInfo *, SourceLocation> ModuleNameLoc(
         PP.getIdentifierInfo(ModuleName), Path[0].second);
-    if (IsPartition) {
-      // Create an interface, but note that it is an implementation
-      // unit.
+    // C++20 A module-declaration that contains neither an export-
+    // keyword nor a module-partition implicitly imports the primary
+    // module interface unit of the module as if by a module-import-
+    // declaration.
+    Mod = getModuleLoader().loadModule(ModuleLoc, {ModuleNameLoc},
+                                       Module::AllVisible,
+                                       /*IsInclusionDirective=*/false);
+    if (!Mod) {
+      Diag(ModuleLoc, diag::err_module_not_defined) << ModuleName;
+      // Create an empty module interface unit for error recovery.
       Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName,
                                              GlobalModuleFragment);
-      Mod->Kind = Module::ModulePartitionImplementation;
-    } else {
-      // C++20 A module-declaration that contains neither an export-
-      // keyword nor a module-partition implicitly imports the primary
-      // module interface unit of the module as if by a module-import-
-      // declaration.
-      Mod = getModuleLoader().loadModule(ModuleLoc, {ModuleNameLoc},
-                                         Module::AllVisible,
-                                         /*IsInclusionDirective=*/false);
-      if (!Mod) {
-        Diag(ModuleLoc, diag::err_module_not_defined) << ModuleName;
-        // Create an empty module interface unit for error recovery.
-        Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName,
-                                               GlobalModuleFragment);
-      }
     }
+  } break;
+
+  case ModuleDeclKind::PartitionImplementation:
+    // Create an interface, but note that it is an implementation
+    // unit.
+    Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName,
+                                           GlobalModuleFragment);
+    Mod->Kind = Module::ModulePartitionImplementation;
     break;
   }
 
@@ -264,8 +279,7 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
   // Switch from the global module fragment (if any) to the named module.
   ModuleScopes.back().BeginLoc = StartLoc;
   ModuleScopes.back().Module = Mod;
-  ModuleScopes.back().ModuleInterface =
-      (MDK != ModuleDeclKind::Implementation || IsPartition);
+  ModuleScopes.back().ModuleInterface = MDK != ModuleDeclKind::Implementation;
   ModuleScopes.back().IsPartition = IsPartition;
   VisibleModules.setVisible(Mod, ModuleLoc);
 

diff  --git a/clang/test/Modules/cxx20-10-1-ex1.cpp b/clang/test/Modules/cxx20-10-1-ex1.cpp
new file mode 100644
index 0000000000000..b9a5e8023d035
--- /dev/null
+++ b/clang/test/Modules/cxx20-10-1-ex1.cpp
@@ -0,0 +1,48 @@
+// The example in the standard is not in required build order.
+// revised here
+
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: split-file %s %t
+
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/std10-1-ex1-tu1.cpp \
+// RUN:  -o %t/A_Internals.pcm
+
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/std10-1-ex1-tu2.cpp \
+// RUN:  -fmodule-file=%t/A_Internals.pcm -o %t/A_Foo.pcm
+
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/std10-1-ex1-tu3.cpp \
+// RUN:  -fmodule-file=%t/A_Foo.pcm -o %t/A.pcm
+
+// RUN: %clang_cc1 -std=c++20 -emit-obj %t/std10-1-ex1-tu4.cpp \
+// RUN:  -fmodule-file=%t/A.pcm -o %t/ex1.o
+
+// expected-no-diagnostics
+
+//--- std10-1-ex1-tu1.cpp
+
+module A:Internals;
+int bar();
+
+//--- std10-1-ex1-tu2.cpp
+
+export module A:Foo;
+
+import :Internals;
+
+export int foo() { return 2 * (bar() + 1); }
+
+//--- std10-1-ex1-tu3.cpp
+
+export module A;
+export import :Foo;
+export int baz();
+
+//--- std10-1-ex1-tu4.cpp
+
+module A;
+
+import :Internals;
+
+int bar() { return baz() - 10; }
+int baz() { return 30; }

diff  --git a/clang/test/Modules/cxx20-10-1-ex2.cpp b/clang/test/Modules/cxx20-10-1-ex2.cpp
new file mode 100644
index 0000000000000..66323fc9d6460
--- /dev/null
+++ b/clang/test/Modules/cxx20-10-1-ex2.cpp
@@ -0,0 +1,64 @@
+
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: split-file %s %t
+
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/std10-1-ex2-tu1.cpp \
+// RUN:  -o %t/B_Y.pcm
+
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/std10-1-ex2-tu2.cpp \
+// RUN:  -fmodule-file=%t/B_Y.pcm -o %t/B.pcm
+
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/std10-1-ex2-tu3.cpp \
+// RUN:   -o %t/B_X1.pcm -verify
+
+// Not expected to work yet.
+//  %clang_cc1 -std=c++20 -emit-module-interface %t/std10-1-ex2-tu4.cpp \
+//   -fmodule-file=%t/B.pcm  -o %t/B_X2.pcm
+
+// RUN: %clang_cc1 -std=c++20 -emit-obj %t/std10-1-ex2-tu5.cpp \
+// RUN:  -fmodule-file=%t/B.pcm  -o %t/b_tu5.o
+
+// RUN: %clang_cc1 -std=c++20 -S %t/std10-1-ex2-tu6.cpp \
+// RUN:  -fmodule-file=%t/B.pcm  -o %t/b_tu6.s -verify
+
+// Not expected to work yet.
+//  %clang_cc1 -std=c++20 -emit-module-interface %t/std10-1-ex2-tu7.cpp \
+//   -fmodule-file=%t/B_X2.pcm  -o %t/B_X3.pcm -verify
+
+//--- std10-1-ex2-tu1.cpp
+module B:Y;
+int y();
+// expected-no-diagnostics
+
+//--- std10-1-ex2-tu2.cpp
+export module B;
+import :Y;
+int n = y();
+// expected-no-diagnostics
+
+//--- std10-1-ex2-tu3.cpp
+module B:X1; // does not implicitly import B
+int &a = n;  // expected-error {{use of undeclared identifier }}
+
+//--- std10-1-ex2-tu4.cpp
+module B:X2; // does not implicitly import B
+import B;
+int &b = n; // OK
+// expected-no-diagnostics
+
+//--- std10-1-ex2-tu5.cpp
+module B;   // implicitly imports B
+int &c = n; // OK
+// expected-no-diagnostics
+
+//--- std10-1-ex2-tu6.cpp
+import B;
+// error, n is module-local and this is not a module.
+int &c = n; // expected-error {{use of undeclared identifier}}
+
+//--- std10-1-ex2-tu7.cpp
+module B:X3; // does not implicitly import B
+import :X2;  // X2 is an implementation so exports nothing.
+             // error: n not visible here.
+int &c = n;  // expected-error {{use of undeclared identifier }}

diff  --git a/clang/test/Modules/cxx20-import-diagnostics-a.cpp b/clang/test/Modules/cxx20-import-diagnostics-a.cpp
index 8e2940a432e6d..8017e19e957d6 100644
--- a/clang/test/Modules/cxx20-import-diagnostics-a.cpp
+++ b/clang/test/Modules/cxx20-import-diagnostics-a.cpp
@@ -95,9 +95,9 @@ import C; // expected-error {{imports must immediately follow the module declara
 //--- import-diags-tu7.cpp
 
 module;
-// We can only have preprocessor commands here, which could include an include
+// We can only have preprocessor directives here, which permits an include-
 // translated header unit.  However those are identified specifically by the
-// preprocessor; non-preprocessed user code should not contain an import here.
+// preprocessor; non-preprocessed user code should not contain an 'import' here.
 import B; // expected-error {{module imports cannot be in the global module fragment}}
 
 export module D;


        


More information about the cfe-commits mailing list