[clang] f60dc3c - [C++20][Modules] Adjust handling of exports of namespaces and using-decls.
Iain Sandoe via cfe-commits
cfe-commits at lists.llvm.org
Fri Apr 8 00:57:50 PDT 2022
Author: Iain Sandoe
Date: 2022-04-08T08:57:37+01:00
New Revision: f60dc3caa67374c0e2941ee3866b5eaef0c6ffe6
URL: https://github.com/llvm/llvm-project/commit/f60dc3caa67374c0e2941ee3866b5eaef0c6ffe6
DIFF: https://github.com/llvm/llvm-project/commit/f60dc3caa67374c0e2941ee3866b5eaef0c6ffe6.diff
LOG: [C++20][Modules] Adjust handling of exports of namespaces and using-decls.
This adjusts the handling for:
export module M;
export namespace {};
export namespace N {};
export using namespace N;
In the first case, we were allowing empty anonymous namespaces
as part of an extension allowing empty top-level entities, but that seems
inappropriate in this case, since the linkage would be internal for the
anonymous namespace. We now report an error for this.
The second case was producing a warning diagnostic that this was
accepted as an extension - however the C++20 standard does allow this
as well-formed.
In the third case we keep the current practice that this is accepted with a
warning (as an extension). The C++20 standard says it's an error.
We also ensure that using decls are only applied to items with external linkage.
This adjusts error messages for exports involving redeclarations in modules to
be more specific about the reason that the decl has been rejected.
Differential Revision: https://reviews.llvm.org/D122119
Added:
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
Modified:
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
Removed:
################################################################################
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 96cd00c8bb2a1..20b5f1e972471 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -7853,8 +7853,8 @@ def err_invalid_declarator_scope : Error<"cannot define or redeclare %0 here "
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<
@@ -11071,6 +11071,8 @@ def ext_export_no_name_block : ExtWarn<
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">;
@@ -11082,7 +11084,8 @@ def err_export_within_export : Error<
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">;
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index a2d3722f2efb8..427b25766bc73 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -1679,7 +1679,13 @@ bool Sema::CheckRedeclarationExported(NamedDecl *New, NamedDecl *Old) {
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;
}
diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp
index 893b913194aae..a9d3540e2ef6e 100644
--- a/clang/lib/Sema/SemaModule.cpp
+++ b/clang/lib/Sema/SemaModule.cpp
@@ -762,6 +762,7 @@ enum class UnnamedDeclKind {
StaticAssert,
Asm,
UsingDirective,
+ Namespace,
Context
};
}
@@ -791,6 +792,10 @@ unsigned getUnnamedDeclDiag(UnnamedDeclKind UDK, bool InBlock) {
// 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.
@@ -818,10 +823,12 @@ static bool checkExportedDecl(Sema &S, Decl *D, SourceLocation BlockStart) {
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);
@@ -833,8 +840,10 @@ static bool checkExportedDecl(Sema &S, Decl *D, SourceLocation BlockStart) {
// 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);
@@ -842,10 +851,18 @@ static bool checkExportedDecl(Sema &S, Decl *D, SourceLocation BlockStart) {
}
// 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;
}
diff --git a/clang/test/CXX/module/module.interface/p3.cpp b/clang/test/CXX/module/module.interface/p3.cpp
index 29d2cb43b4d23..2d888d2018e87 100644
--- a/clang/test/CXX/module/module.interface/p3.cpp
+++ b/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 typedef int; // expected-error {{typedef requires a name}}
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}}
diff --git a/clang/test/CXX/module/module.interface/p5.cpp b/clang/test/CXX/module/module.interface/p5.cpp
index 17c4105baa0e8..a76be594e19d2 100644
--- a/clang/test/CXX/module/module.interface/p5.cpp
+++ b/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 @@ namespace UnnamedNS {
}
}
-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 {
diff --git a/clang/test/CXX/module/module.interface/p6.cpp b/clang/test/CXX/module/module.interface/p6.cpp
index 070aa62f5800a..2b7fa78cdbbe6 100644
--- a/clang/test/CXX/module/module.interface/p6.cpp
+++ b/clang/test/CXX/module/module.interface/p6.cpp
@@ -9,7 +9,7 @@ struct S { // expected-note {{previous declaration is here}}
};
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 @@ export struct Y;
} // 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 @@ struct C {}; // expected-note {{previous declaration is here}}
} // 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 @@ void A::foo();
// 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 {
diff --git a/clang/test/Modules/cxx20-10-2-ex1.cpp b/clang/test/Modules/cxx20-10-2-ex1.cpp
new file mode 100644
index 0000000000000..e91997afe898a
--- /dev/null
+++ b/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 at 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}}
diff --git a/clang/test/Modules/cxx20-10-2-ex3.cpp b/clang/test/Modules/cxx20-10-2-ex3.cpp
new file mode 100644
index 0000000000000..b41269f06fb3c
--- /dev/null
+++ b/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
diff --git a/clang/test/Modules/cxx20-10-2-ex4.cpp b/clang/test/Modules/cxx20-10-2-ex4.cpp
new file mode 100644
index 0000000000000..48d351f472307
--- /dev/null
+++ b/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}}
diff --git a/clang/test/Modules/cxx20-10-2-ex5.cpp b/clang/test/Modules/cxx20-10-2-ex5.cpp
new file mode 100644
index 0000000000000..32a9350d2b6bb
--- /dev/null
+++ b/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 at -1 {{member access into incomplete type 'A'}}
+ // expected-note at std-10-2-ex5-tu1.cpp:12 2{{forward declaration of 'A'}}
+}
diff --git a/clang/test/Modules/cxx20-10-2-ex6.cpp b/clang/test/Modules/cxx20-10-2-ex6.cpp
new file mode 100644
index 0000000000000..7f66e90b178ea
--- /dev/null
+++ b/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 at -1 {{declaration of 'x' with internal linkage cannot be exported}}
diff --git a/clang/test/Modules/cxx20-10-2-ex7.cpp b/clang/test/Modules/cxx20-10-2-ex7.cpp
new file mode 100644
index 0000000000000..86d139ff5b556
--- /dev/null
+++ b/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
More information about the cfe-commits
mailing list