Compiler projects using llvm
// 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