Iain Sandoe f60dc3caa6 [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
2022-04-08 08:57:37 +01:00

115 lines
4.5 KiB
C++

// The test is check we couldn't export a redeclaration which isn't exported previously and
// check it is OK to redeclare no matter exported nor not if is the previous declaration is exported.
// RUN: %clang_cc1 -std=c++20 %s -verify
export module X;
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}}
namespace A {
struct X; // expected-note {{previous declaration is here}}
export struct Y;
} // namespace A
namespace A {
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 has module linkage}}
} // namespace A
namespace A {
struct B; // expected-note {{previous declaration is here}}
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 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 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 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 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 has module linkage}}
void f1(); // expected-note {{previous declaration is here}}
} // namespace A
// OK
//
// [module.interface]/p6
// A redeclaration of an entity X is implicitly exported if X was introduced by an exported declaration
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 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 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 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 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 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 has module linkage}}
// Test the compiler wouldn't complain about the redeclaration of friend in exported class.
namespace Friend {
template <typename T>
class bar;
class gua;
template <typename T>
void hello();
void hi();
export class foo;
bool operator<(const foo &a, const foo &b);
export class foo {
template <typename T>
friend class bar;
friend class gua;
template <typename T>
friend void hello();
friend void hi();
friend bool operator<(const foo &a, const foo &b);
};
} // namespace Friend