summaryrefslogtreecommitdiff
path: root/test/Modules/odr_hash.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'test/Modules/odr_hash.cpp')
-rw-r--r--test/Modules/odr_hash.cpp953
1 files changed, 953 insertions, 0 deletions
diff --git a/test/Modules/odr_hash.cpp b/test/Modules/odr_hash.cpp
new file mode 100644
index 0000000000000..75436706200c5
--- /dev/null
+++ b/test/Modules/odr_hash.cpp
@@ -0,0 +1,953 @@
+// Clear and create directories
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: mkdir %t/cache
+// RUN: mkdir %t/Inputs
+
+// Build first header file
+// RUN: echo "#define FIRST" >> %t/Inputs/first.h
+// RUN: cat %s >> %t/Inputs/first.h
+
+// Build second header file
+// RUN: echo "#define SECOND" >> %t/Inputs/second.h
+// RUN: cat %s >> %t/Inputs/second.h
+
+// Build module map file
+// RUN: echo "module FirstModule {" >> %t/Inputs/module.map
+// RUN: echo " header \"first.h\"" >> %t/Inputs/module.map
+// RUN: echo "}" >> %t/Inputs/module.map
+// RUN: echo "module SecondModule {" >> %t/Inputs/module.map
+// RUN: echo " header \"second.h\"" >> %t/Inputs/module.map
+// RUN: echo "}" >> %t/Inputs/module.map
+
+// Run test
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/cache -x c++ -I%t/Inputs -verify %s -std=c++1z
+
+#if !defined(FIRST) && !defined(SECOND)
+#include "first.h"
+#include "second.h"
+#endif
+
+namespace AccessSpecifiers {
+#if defined(FIRST)
+struct S1 {
+};
+#elif defined(SECOND)
+struct S1 {
+ private:
+};
+#else
+S1 s1;
+// expected-error@second.h:* {{'AccessSpecifiers::S1' has different definitions in different modules; first difference is definition in module 'SecondModule' found private access specifier}}
+// expected-note@first.h:* {{but in 'FirstModule' found end of class}}
+#endif
+
+#if defined(FIRST)
+struct S2 {
+ public:
+};
+#elif defined(SECOND)
+struct S2 {
+ protected:
+};
+#else
+S2 s2;
+// expected-error@second.h:* {{'AccessSpecifiers::S2' has different definitions in different modules; first difference is definition in module 'SecondModule' found protected access specifier}}
+// expected-note@first.h:* {{but in 'FirstModule' found public access specifier}}
+#endif
+} // namespace AccessSpecifiers
+
+namespace StaticAssert {
+#if defined(FIRST)
+struct S1 {
+ static_assert(1 == 1, "First");
+};
+#elif defined(SECOND)
+struct S1 {
+ static_assert(1 == 1, "Second");
+};
+#else
+S1 s1;
+// expected-error@second.h:* {{'StaticAssert::S1' has different definitions in different modules; first difference is definition in module 'SecondModule' found static assert with message}}
+// expected-note@first.h:* {{but in 'FirstModule' found static assert with different message}}
+#endif
+
+#if defined(FIRST)
+struct S2 {
+ static_assert(2 == 2, "Message");
+};
+#elif defined(SECOND)
+struct S2 {
+ static_assert(2 == 2);
+};
+#else
+S2 s2;
+// expected-error@second.h:* {{'StaticAssert::S2' has different definitions in different modules; first difference is definition in module 'SecondModule' found static assert with no message}}
+// expected-note@first.h:* {{but in 'FirstModule' found static assert with message}}
+#endif
+
+#if defined(FIRST)
+struct S3 {
+ static_assert(3 == 3, "Message");
+};
+#elif defined(SECOND)
+struct S3 {
+ static_assert(3 != 4, "Message");
+};
+#else
+S3 s3;
+// expected-error@second.h:* {{'StaticAssert::S3' has different definitions in different modules; first difference is definition in module 'SecondModule' found static assert with condition}}
+// expected-note@first.h:* {{but in 'FirstModule' found static assert with different condition}}
+#endif
+
+#if defined(FIRST)
+struct S4 {
+ static_assert(4 == 4, "Message");
+};
+#elif defined(SECOND)
+struct S4 {
+ public:
+};
+#else
+S4 s4;
+// expected-error@second.h:* {{'StaticAssert::S4' has different definitions in different modules; first difference is definition in module 'SecondModule' found public access specifier}}
+// expected-note@first.h:* {{but in 'FirstModule' found static assert}}
+#endif
+}
+
+namespace Field {
+#if defined(FIRST)
+struct S1 {
+ int x;
+ private:
+ int y;
+};
+#elif defined(SECOND)
+struct S1 {
+ int x;
+ int y;
+};
+#else
+S1 s1;
+// expected-error@second.h:* {{'Field::S1' has different definitions in different modules; first difference is definition in module 'SecondModule' found field}}
+// expected-note@first.h:* {{but in 'FirstModule' found private access specifier}}
+#endif
+
+#if defined(FIRST)
+struct S2 {
+ int x;
+ int y;
+};
+#elif defined(SECOND)
+struct S2 {
+ int y;
+ int x;
+};
+#else
+S2 s2;
+// expected-error@second.h:* {{'Field::S2' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'y'}}
+// expected-note@first.h:* {{but in 'FirstModule' found field 'x'}}
+#endif
+
+#if defined(FIRST)
+struct S3 {
+ double x;
+};
+#elif defined(SECOND)
+struct S3 {
+ int x;
+};
+#else
+S3 s3;
+// expected-error@first.h:* {{'Field::S3::x' from module 'FirstModule' is not present in definition of 'Field::S3' in module 'SecondModule'}}
+// expected-note@second.h:* {{declaration of 'x' does not match}}
+#endif
+
+#if defined(FIRST)
+typedef int A;
+struct S4 {
+ A x;
+};
+
+struct S5 {
+ A x;
+};
+#elif defined(SECOND)
+typedef int B;
+struct S4 {
+ B x;
+};
+
+struct S5 {
+ int x;
+};
+#else
+S4 s4;
+// expected-error@second.h:* {{'Field::S4' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with type 'Field::B' (aka 'int')}}
+// expected-note@first.h:* {{but in 'FirstModule' found field 'x' with type 'Field::A' (aka 'int')}}
+
+S5 s5;
+// expected-error@second.h:* {{'Field::S5' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with type 'int'}}
+// expected-note@first.h:* {{but in 'FirstModule' found field 'x' with type 'Field::A' (aka 'int')}}
+#endif
+
+#if defined(FIRST)
+struct S6 {
+ unsigned x;
+};
+#elif defined(SECOND)
+struct S6 {
+ unsigned x : 1;
+};
+#else
+S6 s6;
+// expected-error@second.h:* {{'Field::S6' has different definitions in different modules; first difference is definition in module 'SecondModule' found bitfield 'x'}}
+// expected-note@first.h:* {{but in 'FirstModule' found non-bitfield 'x'}}
+#endif
+
+#if defined(FIRST)
+struct S7 {
+ unsigned x : 2;
+};
+#elif defined(SECOND)
+struct S7 {
+ unsigned x : 1;
+};
+#else
+S7 s7;
+// expected-error@second.h:* {{'Field::S7' has different definitions in different modules; first difference is definition in module 'SecondModule' found bitfield 'x' with one width expression}}
+// expected-note@first.h:* {{but in 'FirstModule' found bitfield 'x' with different width expression}}
+#endif
+
+#if defined(FIRST)
+struct S8 {
+ unsigned x : 2;
+};
+#elif defined(SECOND)
+struct S8 {
+ unsigned x : 1 + 1;
+};
+#else
+S8 s8;
+// expected-error@second.h:* {{'Field::S8' has different definitions in different modules; first difference is definition in module 'SecondModule' found bitfield 'x' with one width expression}}
+// expected-note@first.h:* {{but in 'FirstModule' found bitfield 'x' with different width expression}}
+#endif
+
+#if defined(FIRST)
+struct S9 {
+ mutable int x;
+};
+#elif defined(SECOND)
+struct S9 {
+ int x;
+};
+#else
+S9 s9;
+// expected-error@second.h:* {{'Field::S9' has different definitions in different modules; first difference is definition in module 'SecondModule' found non-mutable field 'x'}}
+// expected-note@first.h:* {{but in 'FirstModule' found mutable field 'x'}}
+#endif
+
+#if defined(FIRST)
+struct S10 {
+ unsigned x = 5;
+};
+#elif defined(SECOND)
+struct S10 {
+ unsigned x;
+};
+#else
+S10 s10;
+// expected-error@second.h:* {{'Field::S10' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with no initalizer}}
+// expected-note@first.h:* {{but in 'FirstModule' found field 'x' with an initializer}}
+#endif
+
+#if defined(FIRST)
+struct S11 {
+ unsigned x = 5;
+};
+#elif defined(SECOND)
+struct S11 {
+ unsigned x = 7;
+};
+#else
+S11 s11;
+// expected-error@second.h:* {{'Field::S11' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with an initializer}}
+// expected-note@first.h:* {{but in 'FirstModule' found field 'x' with a different initializer}}
+#endif
+
+} // namespace Field
+
+namespace Method {
+#if defined(FIRST)
+struct S1 {
+ void A() {}
+};
+#elif defined(SECOND)
+struct S1 {
+ private:
+ void A() {}
+};
+#else
+S1 s1;
+// expected-error@second.h:* {{'Method::S1' has different definitions in different modules; first difference is definition in module 'SecondModule' found private access specifier}}
+// expected-note@first.h:* {{but in 'FirstModule' found method}}
+#endif
+
+#if defined(FIRST)
+struct S2 {
+ void A() {}
+ void B() {}
+};
+#elif defined(SECOND)
+struct S2 {
+ void B() {}
+ void A() {}
+};
+#else
+S2 s2;
+// expected-error@second.h:* {{'Method::S2' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'B'}}
+// expected-note@first.h:* {{but in 'FirstModule' found method 'A'}}
+#endif
+
+#if defined(FIRST)
+struct S3 {
+ static void A() {}
+ void A(int) {}
+};
+#elif defined(SECOND)
+struct S3 {
+ void A(int) {}
+ static void A() {}
+};
+#else
+S3 s3;
+// expected-error@second.h:* {{'Method::S3' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' is not static}}
+// expected-note@first.h:* {{but in 'FirstModule' found method 'A' is static}}
+#endif
+
+#if defined(FIRST)
+struct S4 {
+ virtual void A() {}
+ void B() {}
+};
+#elif defined(SECOND)
+struct S4 {
+ void A() {}
+ virtual void B() {}
+};
+#else
+S4 s4;
+// expected-error@second.h:* {{'Method::S4' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' is not virtual}}
+// expected-note@first.h:* {{but in 'FirstModule' found method 'A' is virtual}}
+#endif
+
+#if defined(FIRST)
+struct S5 {
+ virtual void A() = 0;
+ virtual void B() {};
+};
+#elif defined(SECOND)
+struct S5 {
+ virtual void A() {}
+ virtual void B() = 0;
+};
+#else
+S5 *s5;
+// expected-error@second.h:* {{'Method::S5' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' is virtual}}
+// expected-note@first.h:* {{but in 'FirstModule' found method 'A' is pure virtual}}
+#endif
+
+#if defined(FIRST)
+struct S6 {
+ inline void A() {}
+};
+#elif defined(SECOND)
+struct S6 {
+ void A() {}
+};
+#else
+S6 s6;
+// expected-error@second.h:* {{'Method::S6' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' is not inline}}
+// expected-note@first.h:* {{but in 'FirstModule' found method 'A' is inline}}
+#endif
+
+#if defined(FIRST)
+struct S7 {
+ void A() volatile {}
+ void A() {}
+};
+#elif defined(SECOND)
+struct S7 {
+ void A() {}
+ void A() volatile {}
+};
+#else
+S7 s7;
+// expected-error@second.h:* {{'Method::S7' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' is not volatile}}
+// expected-note@first.h:* {{but in 'FirstModule' found method 'A' is volatile}}
+#endif
+
+#if defined(FIRST)
+struct S8 {
+ void A() const {}
+ void A() {}
+};
+#elif defined(SECOND)
+struct S8 {
+ void A() {}
+ void A() const {}
+};
+#else
+S8 s8;
+// expected-error@second.h:* {{'Method::S8' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'A' is not const}}
+// expected-note@first.h:* {{but in 'FirstModule' found method 'A' is const}}
+#endif
+
+} // namespace Method
+
+// Naive parsing of AST can lead to cycles in processing. Ensure
+// self-references don't trigger an endless cycles of AST node processing.
+namespace SelfReference {
+#if defined(FIRST)
+template <template <int> class T> class Wrapper {};
+
+template <int N> class S {
+ S(Wrapper<::SelfReference::S> &Ref) {}
+};
+
+struct Xx {
+ struct Yy {
+ };
+};
+
+Xx::Xx::Xx::Yy yy;
+
+namespace NNS {
+template <typename> struct Foo;
+template <template <class> class T = NNS::Foo>
+struct NestedNamespaceSpecifier {};
+}
+#endif
+} // namespace SelfReference
+
+namespace TypeDef {
+#if defined(FIRST)
+struct S1 {
+ typedef int a;
+};
+#elif defined(SECOND)
+struct S1 {
+ typedef double a;
+};
+#else
+S1 s1;
+// expected-error@first.h:* {{'TypeDef::S1::a' from module 'FirstModule' is not present in definition of 'TypeDef::S1' in module 'SecondModule'}}
+// expected-note@second.h:* {{declaration of 'a' does not match}}
+#endif
+
+#if defined(FIRST)
+struct S2 {
+ typedef int a;
+};
+#elif defined(SECOND)
+struct S2 {
+ typedef int b;
+};
+#else
+S2 s2;
+// expected-error@first.h:* {{'TypeDef::S2::a' from module 'FirstModule' is not present in definition of 'TypeDef::S2' in module 'SecondModule'}}
+// expected-note@second.h:* {{definition has no member 'a'}}
+#endif
+
+#if defined(FIRST)
+typedef int T;
+struct S3 {
+ typedef T a;
+};
+#elif defined(SECOND)
+typedef double T;
+struct S3 {
+ typedef T a;
+};
+#else
+S3 s3;
+// expected-error@first.h:* {{'TypeDef::S3::a' from module 'FirstModule' is not present in definition of 'TypeDef::S3' in module 'SecondModule'}}
+// expected-note@second.h:* {{declaration of 'a' does not match}}
+#endif
+} // namespace TypeDef
+
+namespace Using {
+#if defined(FIRST)
+struct S1 {
+ using a = int;
+};
+#elif defined(SECOND)
+struct S1 {
+ using a = double;
+};
+#else
+S1 s1;
+// expected-error@first.h:* {{'Using::S1::a' from module 'FirstModule' is not present in definition of 'Using::S1' in module 'SecondModule'}}
+// expected-note@second.h:* {{declaration of 'a' does not match}}
+#endif
+
+#if defined(FIRST)
+struct S2 {
+ using a = int;
+};
+#elif defined(SECOND)
+struct S2 {
+ using b = int;
+};
+#else
+S2 s2;
+// expected-error@first.h:* {{'Using::S2::a' from module 'FirstModule' is not present in definition of 'Using::S2' in module 'SecondModule'}}
+// expected-note@second.h:* {{definition has no member 'a'}}
+#endif
+
+#if defined(FIRST)
+typedef int T;
+struct S3 {
+ using a = T;
+};
+#elif defined(SECOND)
+typedef double T;
+struct S3 {
+ using a = T;
+};
+#else
+S3 s3;
+// expected-error@first.h:* {{'Using::S3::a' from module 'FirstModule' is not present in definition of 'Using::S3' in module 'SecondModule'}}
+// expected-note@second.h:* {{declaration of 'a' does not match}}
+#endif
+} // namespace Using
+
+
+// Interesting cases that should not cause errors. struct S should not error
+// while struct T should error at the access specifier mismatch at the end.
+namespace AllDecls {
+#if defined(FIRST)
+typedef int INT;
+struct S {
+ public:
+ private:
+ protected:
+
+ static_assert(1 == 1, "Message");
+ static_assert(2 == 2);
+
+ int x;
+ double y;
+
+ INT z;
+
+ unsigned a : 1;
+ unsigned b : 2*2 + 5/2;
+
+ mutable int c = sizeof(x + y);
+
+ void method() {}
+ static void static_method() {}
+ virtual void virtual_method() {}
+ virtual void pure_virtual_method() = 0;
+ inline void inline_method() {}
+ void volatile_method() volatile {}
+ void const_method() const {}
+
+ typedef int typedef_int;
+ using using_int = int;
+};
+#elif defined(SECOND)
+typedef int INT;
+struct S {
+ public:
+ private:
+ protected:
+
+ static_assert(1 == 1, "Message");
+ static_assert(2 == 2);
+
+ int x;
+ double y;
+
+ INT z;
+
+ unsigned a : 1;
+ unsigned b : 2 * 2 + 5 / 2;
+
+ mutable int c = sizeof(x + y);
+
+ void method() {}
+ static void static_method() {}
+ virtual void virtual_method() {}
+ virtual void pure_virtual_method() = 0;
+ inline void inline_method() {}
+ void volatile_method() volatile {}
+ void const_method() const {}
+
+ typedef int typedef_int;
+ using using_int = int;
+};
+#else
+S *s;
+#endif
+
+#if defined(FIRST)
+typedef int INT;
+struct T {
+ public:
+ private:
+ protected:
+
+ static_assert(1 == 1, "Message");
+ static_assert(2 == 2);
+
+ int x;
+ double y;
+
+ INT z;
+
+ unsigned a : 1;
+ unsigned b : 2 * 2 + 5 / 2;
+
+ mutable int c = sizeof(x + y);
+
+ void method() {}
+ static void static_method() {}
+ virtual void virtual_method() {}
+ virtual void pure_virtual_method() = 0;
+ inline void inline_method() {}
+ void volatile_method() volatile {}
+ void const_method() const {}
+
+ typedef int typedef_int;
+ using using_int = int;
+
+ private:
+};
+#elif defined(SECOND)
+typedef int INT;
+struct T {
+ public:
+ private:
+ protected:
+
+ static_assert(1 == 1, "Message");
+ static_assert(2 == 2);
+
+ int x;
+ double y;
+
+ INT z;
+
+ unsigned a : 1;
+ unsigned b : 2 * 2 + 5 / 2;
+
+ mutable int c = sizeof(x + y);
+
+ void method() {}
+ static void static_method() {}
+ virtual void virtual_method() {}
+ virtual void pure_virtual_method() = 0;
+ inline void inline_method() {}
+ void volatile_method() volatile {}
+ void const_method() const {}
+
+ typedef int typedef_int;
+ using using_int = int;
+
+ public:
+};
+#else
+T *t;
+// expected-error@second.h:* {{'AllDecls::T' has different definitions in different modules; first difference is definition in module 'SecondModule' found public access specifier}}
+// expected-note@first.h:* {{but in 'FirstModule' found private access specifier}}
+#endif
+}
+
+namespace FriendFunction {
+#if defined(FIRST)
+void F(int = 0);
+struct S { friend void F(int); };
+#elif defined(SECOND)
+void F(int);
+struct S { friend void F(int); };
+#else
+S s;
+#endif
+
+#if defined(FIRST)
+void G(int = 0);
+struct T {
+ friend void G(int);
+
+ private:
+};
+#elif defined(SECOND)
+void G(int);
+struct T {
+ friend void G(int);
+
+ public:
+};
+#else
+T t;
+// expected-error@second.h:* {{'FriendFunction::T' has different definitions in different modules; first difference is definition in module 'SecondModule' found public access specifier}}
+// expected-note@first.h:* {{but in 'FirstModule' found private access specifier}}
+#endif
+} // namespace FriendFunction
+
+namespace ImplicitDecl {
+#if defined(FIRST)
+struct S { };
+void S_Constructors() {
+ // Trigger creation of implicit contructors
+ S foo;
+ S bar = foo;
+ S baz(bar);
+}
+#elif defined(SECOND)
+struct S { };
+#else
+S s;
+#endif
+
+#if defined(FIRST)
+struct T {
+ private:
+};
+void T_Constructors() {
+ // Trigger creation of implicit contructors
+ T foo;
+ T bar = foo;
+ T baz(bar);
+}
+#elif defined(SECOND)
+struct T {
+ public:
+};
+#else
+T t;
+// expected-error@first.h:* {{'ImplicitDecl::T' has different definitions in different modules; first difference is definition in module 'FirstModule' found private access specifier}}
+// expected-note@second.h:* {{but in 'SecondModule' found public access specifier}}
+#endif
+
+} // namespace ImplicitDelc
+
+namespace TemplatedClass {
+#if defined(FIRST)
+template <class>
+struct S {};
+#elif defined(SECOND)
+template <class>
+struct S {};
+#else
+S<int> s;
+#endif
+
+#if defined(FIRST)
+template <class>
+struct T {
+ private:
+};
+#elif defined(SECOND)
+template <class>
+struct T {
+ public:
+};
+#else
+T<int> t;
+// expected-error@second.h:* {{'TemplatedClass::T' has different definitions in different modules; first difference is definition in module 'SecondModule' found public access specifier}}
+// expected-note@first.h:* {{but in 'FirstModule' found private access specifier}}
+#endif
+} // namespace TemplatedClass
+
+namespace TemplateClassWithField {
+#if defined(FIRST)
+template <class A>
+struct S {
+ A a;
+};
+#elif defined(SECOND)
+template <class A>
+struct S {
+ A a;
+};
+#else
+S<int> s;
+#endif
+
+#if defined(FIRST)
+template <class A>
+struct T {
+ A a;
+
+ private:
+};
+#elif defined(SECOND)
+template <class A>
+struct T {
+ A a;
+
+ public:
+};
+#else
+T<int> t;
+// expected-error@second.h:* {{'TemplateClassWithField::T' has different definitions in different modules; first difference is definition in module 'SecondModule' found public access specifier}}
+// expected-note@first.h:* {{but in 'FirstModule' found private access specifier}}
+#endif
+} // namespace TemplateClassWithField
+
+namespace TemplateClassWithTemplateField {
+#if defined(FIRST)
+template <class A>
+class WrapperS;
+template <class A>
+struct S {
+ WrapperS<A> a;
+};
+#elif defined(SECOND)
+template <class A>
+class WrapperS;
+template <class A>
+struct S {
+ WrapperS<A> a;
+};
+#else
+template <class A>
+class WrapperS{};
+S<int> s;
+#endif
+
+#if defined(FIRST)
+template <class A>
+class WrapperT;
+template <class A>
+struct T {
+ WrapperT<A> a;
+
+ public:
+};
+#elif defined(SECOND)
+template <class A>
+class WrapperT;
+template <class A>
+struct T {
+ WrapperT<A> a;
+
+ private:
+};
+#else
+template <class A>
+class WrapperT{};
+T<int> t;
+// expected-error@second.h:* {{'TemplateClassWithTemplateField::T' has different definitions in different modules; first difference is definition in module 'SecondModule' found private access specifier}}
+// expected-note@first.h:* {{but in 'FirstModule' found public access specifier}}
+#endif
+} // namespace TemplateClassWithTemplateField
+
+namespace EnumWithForwardDeclaration {
+#if defined(FIRST)
+enum E : int;
+struct S {
+ void get(E) {}
+};
+#elif defined(SECOND)
+enum E : int { A, B };
+struct S {
+ void get(E) {}
+};
+#else
+S s;
+#endif
+
+#if defined(FIRST)
+struct T {
+ void get(E) {}
+ public:
+};
+#elif defined(SECOND)
+struct T {
+ void get(E) {}
+ private:
+};
+#else
+T t;
+// expected-error@second.h:* {{'EnumWithForwardDeclaration::T' has different definitions in different modules; first difference is definition in module 'SecondModule' found private access specifier}}
+// expected-note@first.h:* {{but in 'FirstModule' found public access specifier}}
+#endif
+} // namespace EnumWithForwardDeclaration
+
+namespace StructWithForwardDeclaration {
+#if defined(FIRST)
+struct P {};
+struct S {
+ struct P *ptr;
+};
+#elif defined(SECOND)
+struct S {
+ struct P *ptr;
+};
+#else
+S s;
+#endif
+
+#if defined(FIRST)
+struct Q {};
+struct T {
+ struct Q *ptr;
+ public:
+};
+#elif defined(SECOND)
+struct T {
+ struct Q *ptr;
+ private:
+};
+#else
+T t;
+// expected-error@second.h:* {{'StructWithForwardDeclaration::T' has different definitions in different modules; first difference is definition in module 'SecondModule' found private access specifier}}
+// expected-note@first.h:* {{but in 'FirstModule' found public access specifier}}
+#endif
+} // namespace StructWithForwardDeclaration
+
+namespace StructWithForwardDeclarationNoDefinition {
+#if defined(FIRST)
+struct P;
+struct S {
+ struct P *ptr;
+};
+#elif defined(SECOND)
+struct S {
+ struct P *ptr;
+};
+#else
+S s;
+#endif
+
+#if defined(FIRST)
+struct Q;
+struct T {
+ struct Q *ptr;
+
+ public:
+};
+#elif defined(SECOND)
+struct T {
+ struct Q *ptr;
+
+ private:
+};
+#else
+T t;
+// expected-error@second.h:* {{'StructWithForwardDeclarationNoDefinition::T' has different definitions in different modules; first difference is definition in module 'SecondModule' found private access specifier}}
+// expected-note@first.h:* {{but in 'FirstModule' found public access specifier}}
+#endif
+} // namespace StructWithForwardDeclarationNoDefinition
+
+// Keep macros contained to one file.
+#ifdef FIRST
+#undef FIRST
+#endif
+#ifdef SECOND
+#undef SECOND
+#endif