iains updated this revision to Diff 418038.
iains marked 3 inline comments as done.
iains added a comment.

rebased, addressed review comments.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D122119/new/

https://reviews.llvm.org/D122119

Files:
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaModule.cpp
  clang/test/CXX/module/module.interface/p3.cpp
  clang/test/CXX/module/module.interface/p5.cpp
  clang/test/CXX/module/module.interface/p6.cpp
  clang/test/Modules/cxx20-10-2-ex1.cpp
  clang/test/Modules/cxx20-10-2-ex3.cpp
  clang/test/Modules/cxx20-10-2-ex4.cpp
  clang/test/Modules/cxx20-10-2-ex5.cpp
  clang/test/Modules/cxx20-10-2-ex6.cpp
  clang/test/Modules/cxx20-10-2-ex7.cpp

Index: clang/test/Modules/cxx20-10-2-ex7.cpp
===================================================================
--- /dev/null
+++ clang/test/Modules/cxx20-10-2-ex7.cpp
@@ -0,0 +1,9 @@
+// Based on C++20 10.2 example 6.
+
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface %s -verify -o M.pcm
+
+export module M;
+export namespace N {
+int x;                 // OK
+static_assert(1 == 1); // expected-error {{static_assert declaration cannot be exported}}
+} // namespace N
Index: clang/test/Modules/cxx20-10-2-ex6.cpp
===================================================================
--- /dev/null
+++ clang/test/Modules/cxx20-10-2-ex6.cpp
@@ -0,0 +1,21 @@
+// Based on C++20 10.2 example 6.
+
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface %s -verify -o M.pcm
+
+export module M;
+
+static int f();  // expected-note {{previous declaration is here}} #1
+                 // error: #1 gives internal linkage
+export int f();  // expected-error {{cannot export redeclaration 'f' here since the previous declaration has internal linkage}}
+struct S;        // expected-note {{previous declaration is here}} #2
+                 // error: #2 gives module linkage
+export struct S; // expected-error {{cannot export redeclaration 'S' here since the previous declaration has module linkage}}
+
+namespace {
+namespace N {
+extern int x; // expected-note {{previous declaration is here}} #3
+}
+} // namespace
+  // error: #3 gives internal linkage
+export int N::x; // expected-error {{cannot export redeclaration 'x' here since the previous declaration has internal linkage}}
+                 // expected-error@-1 {{declaration of 'x' with internal linkage cannot be exported}}
Index: clang/test/Modules/cxx20-10-2-ex5.cpp
===================================================================
--- /dev/null
+++ clang/test/Modules/cxx20-10-2-ex5.cpp
@@ -0,0 +1,54 @@
+// Based on C++20 10.2 example 5.
+
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: split-file %s %t
+
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/std-10-2-ex5-tu1.cpp \
+// RUN:  -o  %t/M.pcm
+
+// RUN: %clang_cc1 -std=c++20 -emit-obj %t/std-10-2-ex5-tu2.cpp \
+// RUN:  -fmodule-file=%t/M.pcm -o  %t/tu-2.o
+
+// RUN: %clang_cc1 -std=c++20 -emit-obj %t/std-10-2-ex5-tu3.cpp \
+// RUN:  -fmodule-file=%t/M.pcm -verify -o %t/main.o
+
+//--- std-10-2-ex5-tu1.cpp
+export module M;
+export struct X {
+  static void f();
+  struct Y {};
+};
+namespace {
+struct S {};
+} // namespace
+export void f(S); // OK
+struct T {};
+export T id(T);  // OK
+export struct A; // A exported as incomplete
+
+export auto rootFinder(double a) {
+  return [=](double x) { return (x + a / x) / 2; };
+}
+export const int n = 5; // OK, n has external linkage
+
+//--- std-10-2-ex5-tu2.cpp
+
+module M;
+struct A {
+  int value;
+};
+
+//--- std-10-2-ex5-tu3.cpp
+
+import M;
+
+int main() {
+  X::f();                 // OK, X is exported and definition of X is reachable
+  X::Y y;                 // OK, X::Y is exported as a complete type
+  auto f = rootFinder(2); // OK
+                          // error: A is incomplete
+  return A{45}.value;     // expected-error {{invalid use of incomplete type 'A'}}
+                          // expected-error@-1 {{member access into incomplete type 'A'}}
+                          // expected-n...@std-10-2-ex5-tu1.cpp:12 2{{forward declaration of 'A'}}
+}
Index: clang/test/Modules/cxx20-10-2-ex4.cpp
===================================================================
--- /dev/null
+++ clang/test/Modules/cxx20-10-2-ex4.cpp
@@ -0,0 +1,12 @@
+// Based on C++20 10.2 example 4.
+
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface %s -verify -o M.pcm
+
+export module M;
+
+struct S { // expected-note {{previous declaration is here}}
+  int n;
+};
+typedef S S;
+export typedef S S; // OK, does not redeclare an entity
+export struct S;    // expected-error {{cannot export redeclaration 'S' here since the previous declaration has module linkage}}
Index: clang/test/Modules/cxx20-10-2-ex3.cpp
===================================================================
--- /dev/null
+++ clang/test/Modules/cxx20-10-2-ex3.cpp
@@ -0,0 +1,9 @@
+// Based on C++20 10.2 example 3.
+
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface %s -o M.pcm
+
+export module M;
+struct S;
+export using T = S; // OK, exports name T denoting type S
+
+// expected-no-diagnostics
Index: clang/test/Modules/cxx20-10-2-ex1.cpp
===================================================================
--- /dev/null
+++ clang/test/Modules/cxx20-10-2-ex1.cpp
@@ -0,0 +1,31 @@
+// Based on C++20 10.2 example 1.
+
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: split-file %s %t
+
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/std-10-2-ex1-tu1.cpp \
+// RUN: -pedantic-errors -verify -o %t/m1.pcm
+
+//--- std-10-2-ex1.h
+export int x;
+
+//--- std-10-2-ex1-tu1.cpp
+module;
+
+#include "std-10-2-ex1.h"
+// expected-error@std-10-2-ex1.h:* {{export declaration can only be used within a module interface unit after the module declaration}}
+
+export module M1;
+export namespace {} // expected-error {{declaration does not introduce any names to be exported}}
+export namespace {
+int a1; // expected-error {{declaration of 'a1' with internal linkage cannot be exported}}
+}
+namespace {    // expected-note {{anonymous namespace begins here}}
+export int a2; // expected-error {{export declaration appears within anonymous namespace}}
+}
+export static int b; // expected-error {{declaration of 'b' with internal linkage cannot be exported}}
+export int f();      // OK
+
+export namespace N {}     // namespace N
+export using namespace N; // expected-error {{ISO C++20 does not permit using directive to be exported}}
Index: clang/test/CXX/module/module.interface/p6.cpp
===================================================================
--- clang/test/CXX/module/module.interface/p6.cpp
+++ clang/test/CXX/module/module.interface/p6.cpp
@@ -9,7 +9,7 @@
 };
 typedef S S;
 export typedef S S; // OK, does not redeclare an entity
-export struct S;    // expected-error {{cannot export redeclaration 'S' here since the previous declaration is not exported}}
+export struct S;    // expected-error {{cannot export redeclaration 'S' here since the previous declaration has module linkage}}
 
 namespace A {
 struct X; // expected-note {{previous declaration is here}}
@@ -17,10 +17,10 @@
 } // namespace A
 
 namespace A {
-export struct X; // expected-error {{cannot export redeclaration 'X' here since the previous declaration is not exported}}
+export struct X; // expected-error {{cannot export redeclaration 'X' here since the previous declaration has module linkage}}
 export struct Y; // OK
 struct Z;        // expected-note {{previous declaration is here}}
-export struct Z; // expected-error {{cannot export redeclaration 'Z' here since the previous declaration is not exported}}
+export struct Z; // expected-error {{cannot export redeclaration 'Z' here since the previous declaration has module linkage}}
 } // namespace A
 
 namespace A {
@@ -29,29 +29,29 @@
 } // namespace A
 
 namespace A {
-export struct B {}; // expected-error {{cannot export redeclaration 'B' here since the previous declaration is not exported}}
-export struct C;    // expected-error {{cannot export redeclaration 'C' here since the previous declaration is not exported}}
+export struct B {}; // expected-error {{cannot export redeclaration 'B' here since the previous declaration has module linkage}}
+export struct C;    // expected-error {{cannot export redeclaration 'C' here since the previous declaration has module linkage}}
 } // namespace A
 
 template <typename T>
 struct TemplS; // expected-note {{previous declaration is here}}
 
 export template <typename T>
-struct TemplS {}; // expected-error {{cannot export redeclaration 'TemplS' here since the previous declaration is not exported}}
+struct TemplS {}; // expected-error {{cannot export redeclaration 'TemplS' here since the previous declaration has module linkage}}
 
 template <typename T>
 struct TemplS2; // expected-note {{previous declaration is here}}
 
 export template <typename U>
-struct TemplS2 {}; // expected-error {{cannot export redeclaration 'TemplS2' here since the previous declaration is not exported}}
+struct TemplS2 {}; // expected-error {{cannot export redeclaration 'TemplS2' here since the previous declaration has module linkage}}
 
 void baz();        // expected-note {{previous declaration is here}}
-export void baz(); // expected-error {{cannot export redeclaration 'baz' here since the previous declaration is not exported}}
+export void baz(); // expected-error {{cannot export redeclaration 'baz' here since the previous declaration has module linkage}}
 
 namespace A {
 export void foo();
 void bar();        // expected-note {{previous declaration is here}}
-export void bar(); // expected-error {{cannot export redeclaration 'bar' here since the previous declaration is not exported}}
+export void bar(); // expected-error {{cannot export redeclaration 'bar' here since the previous declaration has module linkage}}
 void f1();         // expected-note {{previous declaration is here}}
 } // namespace A
 
@@ -63,34 +63,34 @@
 
 // The compiler couldn't export A::f1() here since A::f1() is declared above without exported.
 // See [module.interface]/p6 for details.
-export void A::f1(); // expected-error {{cannot export redeclaration 'f1' here since the previous declaration is not exported}}
+export void A::f1(); // expected-error {{cannot export redeclaration 'f1' here since the previous declaration has module linkage}}
 
 template <typename T>
 void TemplFunc(); // expected-note {{previous declaration is here}}
 
 export template <typename T>
-void TemplFunc() { // expected-error {{cannot export redeclaration 'TemplFunc' here since the previous declaration is not exported}}
+void TemplFunc() { // expected-error {{cannot export redeclaration 'TemplFunc' here since the previous declaration has module linkage}}
 }
 
 namespace A {
 template <typename T>
 void TemplFunc2(); // expected-note {{previous declaration is here}}
 export template <typename T>
-void TemplFunc2() {} // expected-error {{cannot export redeclaration 'TemplFunc2' here since the previous declaration is not exported}}
+void TemplFunc2() {} // expected-error {{cannot export redeclaration 'TemplFunc2' here since the previous declaration has module linkage}}
 template <typename T>
 void TemplFunc3(); // expected-note {{previous declaration is here}}
 } // namespace A
 
 export template <typename T>
-void A::TemplFunc3() {} // expected-error {{cannot export redeclaration 'TemplFunc3' here since the previous declaration is not exported}}
+void A::TemplFunc3() {} // expected-error {{cannot export redeclaration 'TemplFunc3' here since the previous declaration has module linkage}}
 
 int var;        // expected-note {{previous declaration is here}}
-export int var; // expected-error {{cannot export redeclaration 'var' here since the previous declaration is not exported}}
+export int var; // expected-error {{cannot export redeclaration 'var' here since the previous declaration has module linkage}}
 
 template <typename T>
 T TemplVar; // expected-note {{previous declaration is here}}
 export template <typename T>
-T TemplVar; // expected-error {{cannot export redeclaration 'TemplVar' here since the previous declaration is not exported}}
+T TemplVar; // expected-error {{cannot export redeclaration 'TemplVar' here since the previous declaration has module linkage}}
 
 // Test the compiler wouldn't complain about the redeclaration of friend in exported class.
 namespace Friend {
Index: clang/test/CXX/module/module.interface/p5.cpp
===================================================================
--- clang/test/CXX/module/module.interface/p5.cpp
+++ clang/test/CXX/module/module.interface/p5.cpp
@@ -2,24 +2,24 @@
 
 export module p5;
 
-int a;
+int a; // expected-note {{target}}
 static int sa; // expected-note {{target}}
-void b();
+void b(); // expected-note {{target}}
 static void sb(); // expected-note {{target}}
-struct c {};
-enum d {};
+struct c {}; // expected-note {{target}}
+enum d {}; // expected-note {{target}}
 using e = int;
 using f = c;
 static union { int sg1, sg2; }; // expected-note {{target}}
 namespace NS {}
 
-template<typename> int ta;
+template<typename> int ta; // expected-note {{target}}
 template<typename> static int sta; // expected-note {{target}}
-template<typename> void tb();
+template<typename> void tb(); // expected-note {{target}}
 template<typename> static void stb(); // expected-note {{target}}
-template<typename> struct tc {};
-template<typename> using te = int;
-template<typename> using tf = c;
+template<typename> struct tc {}; // expected-note {{target}}
+template<typename> using te = int; // expected-note {{target}}
+template<typename> using tf = c; // expected-note {{target}}
 
 namespace UnnamedNS {
   namespace {
@@ -44,24 +44,24 @@
   }
 }
 
-export { // expected-note 19{{here}}
-  using ::a;
+export { // expected-note 28{{here}}
+  using ::a; // expected-error {{using declaration referring to 'a' with module linkage cannot be exported}}
   using ::sa; // expected-error {{using declaration referring to 'sa' with internal linkage}}
-  using ::b;
+  using ::b; // expected-error {{using declaration referring to 'b' with module linkage cannot be exported}}
   using ::sb; // expected-error {{using declaration referring to 'sb' with internal linkage}}
-  using ::c;
-  using ::d;
+  using ::c; // expected-error {{using declaration referring to 'c' with module linkage cannot be exported}}
+  using ::d; // expected-error {{using declaration referring to 'd' with module linkage cannot be exported}}
   using ::e;
   using ::f;
   using ::sg1; // expected-error {{using declaration referring to 'sg1' with internal linkage}}
 
-  using ::ta;
+  using ::ta; // expected-error {{using declaration referring to 'ta' with module linkage cannot be exported}}
   using ::sta; // expected-error {{using declaration referring to 'sta' with internal linkage}}
-  using ::tb;
+  using ::tb; // expected-error {{using declaration referring to 'tb' with module linkage cannot be exported}}
   using ::stb; // expected-error {{using declaration referring to 'stb' with internal linkage}}
-  using ::tc;
-  using ::te;
-  using ::tf;
+  using ::tc; // expected-error {{using declaration referring to 'tc' with module linkage cannot be exported}}
+  using ::te; // expected-error {{using declaration referring to 'te' with module linkage cannot be exported}}
+  using ::tf; // expected-error {{using declaration referring to 'tf' with module linkage cannot be exported}}
   namespace NS2 = ::NS;
 
   namespace UnnamedNS {
Index: clang/test/CXX/module/module.interface/p3.cpp
===================================================================
--- clang/test/CXX/module/module.interface/p3.cpp
+++ clang/test/CXX/module/module.interface/p3.cpp
@@ -2,17 +2,17 @@
 
 export module p3;
 
-namespace A { int ns_mem; }
+namespace A { int ns_mem; } // expected-note 2{{target}}
 
 // An exported declaration shall declare at least one name.
 export; // expected-error {{empty declaration cannot be exported}}
 export static_assert(true); // expected-error {{static_assert declaration cannot be exported}}
-export using namespace A; // expected-error {{ISO C++20 does not permit using directive to be exported}}
+export using namespace A;   // expected-error {{ISO C++20 does not permit using directive to be exported}}
 
 export { // expected-note 3{{export block begins here}}
   ; // expected-error {{ISO C++20 does not permit an empty declaration to appear in an export block}}
   static_assert(true); // expected-error {{ISO C++20 does not permit a static_assert declaration to appear in an export block}}
-  using namespace A; // expected-error {{ISO C++20 does not permit using directive to be exported}}
+  using namespace A;   // expected-error {{ISO C++20 does not permit using directive to be exported}}
 }
 
 export struct {}; // expected-error {{must be class member}} expected-error {{GNU extension}} expected-error {{does not declare anything}}
@@ -26,9 +26,9 @@
 export static union {}; // expected-error {{does not declare anything}}
 export asm(""); // expected-error {{asm declaration cannot be exported}}
 export namespace B = A;
-export using A::ns_mem;
+export using A::ns_mem; // expected-error {{using declaration referring to 'ns_mem' with module linkage cannot be exported}}
 namespace A {
-  export using A::ns_mem;
+  export using A::ns_mem; // expected-error {{using declaration referring to 'ns_mem' with module linkage cannot be exported}}
 }
 export using Int = int;
 export extern "C++" {} // expected-error {{ISO C++20 does not permit a declaration that does not introduce any names to be exported}}
Index: clang/lib/Sema/SemaModule.cpp
===================================================================
--- clang/lib/Sema/SemaModule.cpp
+++ clang/lib/Sema/SemaModule.cpp
@@ -714,6 +714,7 @@
   StaticAssert,
   Asm,
   UsingDirective,
+  Namespace,
   Context
 };
 }
@@ -743,6 +744,10 @@
     // Allow exporting using-directives as an extension.
     return diag::ext_export_using_directive;
 
+  case UnnamedDeclKind::Namespace:
+    // Anonymous namespace with no content.
+    return diag::introduces_no_names;
+
   case UnnamedDeclKind::Context:
     // Allow exporting DeclContexts that transitively contain no declarations
     // as an extension.
@@ -770,10 +775,12 @@
     diagExportedUnnamedDecl(S, *UDK, D, BlockStart);
 
   //   [...] shall not declare a name with internal linkage.
+  bool HasName = false;
   if (auto *ND = dyn_cast<NamedDecl>(D)) {
     // Don't diagnose anonymous union objects; we'll diagnose their members
     // instead.
-    if (ND->getDeclName() && ND->getFormalLinkage() == InternalLinkage) {
+    HasName = (bool)ND->getDeclName();
+    if (HasName && ND->getFormalLinkage() == InternalLinkage) {
       S.Diag(ND->getLocation(), diag::err_export_internal) << ND;
       if (BlockStart.isValid())
         S.Diag(BlockStart, diag::note_export);
@@ -785,8 +792,10 @@
   //   shall have been introduced with a name having external linkage
   if (auto *USD = dyn_cast<UsingShadowDecl>(D)) {
     NamedDecl *Target = USD->getUnderlyingDecl();
-    if (Target->getFormalLinkage() == InternalLinkage) {
-      S.Diag(USD->getLocation(), diag::err_export_using_internal) << Target;
+    Linkage Lk = Target->getFormalLinkage();
+    if (Lk == InternalLinkage || Lk == ModuleLinkage) {
+      S.Diag(USD->getLocation(), diag::err_export_using_internal)
+          << (Lk == InternalLinkage ? 0 : 1) << Target;
       S.Diag(Target->getLocation(), diag::note_using_decl_target);
       if (BlockStart.isValid())
         S.Diag(BlockStart, diag::note_export);
@@ -794,10 +803,18 @@
   }
 
   // Recurse into namespace-scope DeclContexts. (Only namespace-scope
-  // declarations are exported.)
-  if (auto *DC = dyn_cast<DeclContext>(D))
-    if (DC->getRedeclContext()->isFileContext() && !isa<EnumDecl>(D))
+  // declarations are exported.).
+  if (auto *DC = dyn_cast<DeclContext>(D)) {
+    if (isa<NamespaceDecl>(D) && DC->decls().empty()) {
+      if (!HasName)
+        // We don't allow an empty anonymous namespace (we don't allow decls
+        // in them either, but that's handled in the recursion).
+        diagExportedUnnamedDecl(S, UnnamedDeclKind::Namespace, D, BlockStart);
+      else
+        ; // We allow an empty named namespace decl.
+    } else if (DC->getRedeclContext()->isFileContext() && !isa<EnumDecl>(D))
       return checkExportedDeclContext(S, DC, BlockStart);
+  }
   return false;
 }
 
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -1679,7 +1679,13 @@
 
   assert(IsNewExported);
 
-  Diag(New->getLocation(), diag::err_redeclaration_non_exported) << New;
+  auto Lk = Old->getFormalLinkage();
+  int S = 0;
+  if (Lk == Linkage::InternalLinkage)
+    S = 1;
+  else if (Lk == Linkage::ModuleLinkage)
+    S = 2;
+  Diag(New->getLocation(), diag::err_redeclaration_non_exported) << New << S;
   Diag(Old->getLocation(), diag::note_previous_declaration);
   return true;
 }
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -7843,8 +7843,8 @@
 def err_export_non_namespace_scope_name : Error<
   "cannot export %0 as it is not at namespace scope">;
 def err_redeclaration_non_exported : Error <
-  "cannot export redeclaration %0 here since the previous declaration is not "
-  "exported">;
+  "cannot export redeclaration %0 here since the previous declaration "
+  "%select{is not exported|has internal linkage|has module linkage}1">;
 def err_invalid_declarator_global_scope : Error<
   "definition or redeclaration of %0 cannot name the global scope">;
 def err_invalid_declarator_in_function : Error<
@@ -11059,6 +11059,8 @@
 def ext_export_no_names : ExtWarn<
   "ISO C++20 does not permit a declaration that does not introduce any names "
   "to be exported">, InGroup<ExportUnnamed>;
+def introduces_no_names : Error<
+  "declaration does not introduce any names to be exported">;
 def note_export : Note<"export block begins here">;
 def err_export_no_name : Error<
   "%select{empty|static_assert|asm}0 declaration cannot be exported">;
@@ -11070,7 +11072,8 @@
 def err_export_internal : Error<
   "declaration of %0 with internal linkage cannot be exported">;
 def err_export_using_internal : Error<
-  "using declaration referring to %0 with internal linkage cannot be exported">;
+  "using declaration referring to %1 with %select{internal|module|unknown}0 "
+  "linkage cannot be exported">;
 def err_export_not_in_module_interface : Error<
   "export declaration can only be used within a module interface unit"
   "%select{ after the module declaration|}0">;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to