diff options
Diffstat (limited to 'test/Modules')
27 files changed, 1389 insertions, 135 deletions
diff --git a/test/Modules/ExtDebugInfo.cpp b/test/Modules/ExtDebugInfo.cpp index ed9d1e859d83..97386bc4d007 100644 --- a/test/Modules/ExtDebugInfo.cpp +++ b/test/Modules/ExtDebugInfo.cpp @@ -69,6 +69,8 @@ WithSpecializedBase<int> definedLocally4; void foo() { anon.i = GlobalStruct.i = GlobalUnion.i = GlobalEnum; + A a; + Virtual virt; } // CHECK: ![[CPP:.*]] = !DIFile(filename: {{.*}}ExtDebugInfo.cpp" @@ -210,3 +212,10 @@ void foo() { // CHECK-SAME: dwoId: // CHECK-PCH: !DICompileUnit({{.*}}splitDebugFilename: // CHECK-PCH: dwoId: 18446744073709551614 + +// CHECK: !DICompositeType(tag: DW_TAG_class_type, name: "A", +// CHECK-SAME: DIFlagFwdDecl, identifier: "_ZTS1A") + +// There is a full definition of the type available in the module. +// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "Virtual", +// CHECK-SAME: DIFlagFwdDecl, identifier: "_ZTS7Virtual") diff --git a/test/Modules/Inputs/DebugCXX.h b/test/Modules/Inputs/DebugCXX.h index c9cd68f30c46..1ccf8d302f13 100644 --- a/test/Modules/Inputs/DebugCXX.h +++ b/test/Modules/Inputs/DebugCXX.h @@ -54,9 +54,9 @@ namespace DebugCXX { } // Virtual class with a forward declaration. -class FwdVirtual; -class FwdVirtual { - virtual ~FwdVirtual() {} +struct Virtual; +struct Virtual { + virtual ~Virtual() {} }; struct PureForwardDecl; diff --git a/test/Modules/Inputs/codegen/foo.h b/test/Modules/Inputs/codegen/foo.h index bd3b6489e710..76ad6559cca0 100644 --- a/test/Modules/Inputs/codegen/foo.h +++ b/test/Modules/Inputs/codegen/foo.h @@ -29,4 +29,7 @@ inline void inst_decl() { inst<float>(); } +__attribute__((always_inline)) inline void always_inl() { +} + asm("narf"); diff --git a/test/Modules/Inputs/codegen/use.cpp b/test/Modules/Inputs/codegen/use.cpp index cd1a4a642d09..3e551881f636 100644 --- a/test/Modules/Inputs/codegen/use.cpp +++ b/test/Modules/Inputs/codegen/use.cpp @@ -6,3 +6,6 @@ void non_modular_use_of_implicit_dtor() { void use_of_instantiated_declaration_without_definition() { inst<int>(); } +void call_always_inline() { + always_inl(); +} diff --git a/test/Modules/Inputs/export_as_test.modulemap b/test/Modules/Inputs/export_as_test.modulemap new file mode 100644 index 000000000000..4aaec4194ef5 --- /dev/null +++ b/test/Modules/Inputs/export_as_test.modulemap @@ -0,0 +1,9 @@ +module PrivateFoo { + export_as Foo + export_as Bar + export_as Bar + + module Sub { + export_as Wibble + } +} diff --git a/test/Modules/ModuleDebugInfo.cpp b/test/Modules/ModuleDebugInfo.cpp index 71b05e5aeb8b..008b3e4f2bab 100644 --- a/test/Modules/ModuleDebugInfo.cpp +++ b/test/Modules/ModuleDebugInfo.cpp @@ -86,10 +86,10 @@ // CHECK-SAME: flags: DIFlagFwdDecl // CHECK-SAME: identifier: "_ZTSN8DebugCXX8TemplateIfNS_6traitsIfEEEE") -// CHECK: !DICompositeType(tag: DW_TAG_class_type, name: "FwdVirtual" +// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "Virtual" // CHECK-SAME: elements: -// CHECK-SAME: identifier: "_ZTS10FwdVirtual") -// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "_vptr$FwdVirtual" +// CHECK-SAME: identifier: "_ZTS7Virtual") +// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "_vptr$Virtual" // CHECK: !DICompositeType(tag: DW_TAG_union_type, // CHECK-NOT: name: @@ -111,6 +111,11 @@ // CHECK-SAME: name: "InAnonymousNamespace", // CHECK-SAME: elements: !{{[0-9]+}}) +// CHECK: ![[A:.*]] = {{.*}}!DICompositeType(tag: DW_TAG_class_type, name: "A", +// CHECK-SAME: elements: +// CHECK-SAME: vtableHolder: ![[A]], +// CHECK-SAME: identifier: "_ZTS1A") + // CHECK: ![[DERIVED:.*]] = {{.*}}!DICompositeType(tag: DW_TAG_class_type, name: "Derived", // CHECK-SAME: identifier: "_ZTS7Derived") // CHECK: !DICompositeType(tag: DW_TAG_class_type, name: "B", scope: ![[DERIVED]], diff --git a/test/Modules/adl.cpp b/test/Modules/adl.cpp new file mode 100644 index 000000000000..a1055a889d00 --- /dev/null +++ b/test/Modules/adl.cpp @@ -0,0 +1,40 @@ +// RUN: %clang_cc1 -fmodules -verify -fno-modules-error-recovery -fno-spell-checking %s +// RUN: %clang_cc1 -fmodules -verify -fno-modules-error-recovery -DONLY_Y %s + +#pragma clang module build a +module a { + explicit module x {} + explicit module y {} +} +#pragma clang module contents +#pragma clang module begin a.x +namespace N { + template<typename T> extern int f(T) { return 0; } +} +#pragma clang module end + +#pragma clang module begin a.y +#pragma clang module import a.x +using N::f; +#pragma clang module end +#pragma clang module endbuild + +namespace N { struct A {}; } +struct B {}; + +#ifndef ONLY_Y +#pragma clang module import a.x +void test1() { + f(N::A()); + f(B()); // expected-error {{use of undeclared identifier 'f'}} +} +#else +// expected-no-diagnostics +#endif + +#pragma clang module import a.y +void test2() { + // These are OK even if a.x is not imported. + f(N::A()); + f(B()); +} diff --git a/test/Modules/anon-linkage.cpp b/test/Modules/anon-linkage.cpp new file mode 100644 index 000000000000..590638292b5e --- /dev/null +++ b/test/Modules/anon-linkage.cpp @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -std=c++17 -fmodules-ts %s + +typedef struct { + int c; + union { + int n; + char c[4]; + } v; +} mbstate; + +export module M; +export using ::mbstate; diff --git a/test/Modules/builtin-import.mm b/test/Modules/builtin-import.mm index 2536ac51c42f..cbc312b05904 100644 --- a/test/Modules/builtin-import.mm +++ b/test/Modules/builtin-import.mm @@ -1,7 +1,5 @@ -// REQUIRES: system-darwin - // RUN: rm -rf %t -// RUN: %clang -cc1 -fsyntax-only -nostdinc++ -isysroot %S/Inputs/libc-libcxx/sysroot -isystem %S/Inputs/libc-libcxx/sysroot/usr/include/c++/v1 -std=c++11 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x objective-c++ -fmodules-local-submodule-visibility %s +// RUN: %clang -cc1 -fsyntax-only -nobuiltininc -nostdinc++ -isysroot %S/Inputs/libc-libcxx/sysroot -isystem %S/Inputs/libc-libcxx/sysroot/usr/include/c++/v1 -isystem %S/Inputs/libc-libcxx/sysroot/usr/include -std=c++11 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x objective-c++ -fmodules-local-submodule-visibility %s #include <stdio.h> #include <stddef.h> diff --git a/test/Modules/codegen-opt.test b/test/Modules/codegen-opt.test index 2f4997a7c73f..f62cf38a5356 100644 --- a/test/Modules/codegen-opt.test +++ b/test/Modules/codegen-opt.test @@ -25,7 +25,13 @@ FOO-NOT: {{define|declare}} FOO: declare void @_Z2f1Ri(i32* FOO-NOT: {{define|declare}} -FIXME: this internal function should be weak_odr, comdat, and with a new mangling +Internal functions are not modularly code generated - they are +internal wherever they're used. This might not be ideal, but +continues to workaround/support some oddities that backwards +compatible modules have seen and supported in the wild. To remove +the duplication here, the internal functions would need to be +promoted to weak_odr, placed in comdat and given a new mangling - +this would be needed for the C++ Modules TS anyway. FOO: define internal void @_ZL2f2v() #{{[0-9]+}} FOO-NOT: {{define|declare}} @@ -45,7 +51,7 @@ BAR-OPT: define available_externally void @_Z3foov() BAR-CMN-NOT: {{define|declare}} BAR-OPT: declare void @_Z2f1Ri(i32* BAR-OPT-NOT: {{define|declare}} -BAR-OPT: define available_externally void @_ZL2f2v() +BAR-OPT: define internal void @_ZL2f2v() BAR-OPT-NOT: {{define|declare}} @@ -61,5 +67,5 @@ USE-OPT: define available_externally void @_Z3foov() USE-OPT-NOT: {{define|declare}} USE-OPT: declare void @_Z2f1Ri(i32* USE-OPT-NOT: {{define|declare}} -USE-OPT: define available_externally void @_ZL2f2v() +USE-OPT: define internal void @_ZL2f2v() USE-OPT-NOT: {{define|declare}} diff --git a/test/Modules/codegen.test b/test/Modules/codegen.test index 1bdea5df4317..a919933da2d2 100644 --- a/test/Modules/codegen.test +++ b/test/Modules/codegen.test @@ -4,7 +4,7 @@ REQUIRES: x86-registered-target RUN: %clang_cc1 -triple=x86_64-linux-gnu -fmodules-codegen -fmodules-debuginfo -x c++ -fmodules -emit-module -fmodule-name=foo %S/Inputs/codegen/foo.modulemap -o %t/foo.pcm RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -debug-info-kind=limited -o - %t/foo.pcm | FileCheck --check-prefix=FOO --check-prefix=BOTH %s -RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -debug-info-kind=limited -o - -fmodules -fmodule-file=%t/foo.pcm %S/Inputs/codegen/use.cpp | FileCheck --check-prefix=BOTH --check-prefix=USE %s +RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -debug-info-kind=limited -o - -fmodules -disable-llvm-passes -fmodule-file=%t/foo.pcm %S/Inputs/codegen/use.cpp | FileCheck --check-prefix=BOTH --check-prefix=USE %s For want of any better definition, inline asm goes "everywhere" the same as it if it were in a header (with the disadvantage that the inline asm will be @@ -23,6 +23,7 @@ USE: module asm "narf" FOO: $_Z2f1PKcz = comdat any FOO: $_ZN13implicit_dtorD1Ev = comdat any USE: $_Z4instIiEvv = comdat any +USE: $_Z10always_inlv = comdat any FOO: $_ZN13implicit_dtorD2Ev = comdat any FOO: define weak_odr void @_Z2f1PKcz(i8* %fmt, ...) #{{[0-9]+}} comdat FOO: call void @llvm.va_start(i8* %{{[a-zA-Z0-9]*}}) @@ -38,6 +39,7 @@ FOO: define weak_odr void @_ZN13implicit_dtorD2Ev USE: define linkonce_odr void @_ZN20uninst_implicit_dtorD1Ev USE: define linkonce_odr void @_Z4instIiEvv +USE: define linkonce_odr void @_Z10always_inlv USE: define linkonce_odr void @_ZN20uninst_implicit_dtorD2Ev Modular debug info puts the definition of a class defined in a module in that diff --git a/test/Modules/crash-typo-correction-visibility.cpp b/test/Modules/crash-typo-correction-visibility.cpp index 518293026a63..9f0ed3b7b132 100644 --- a/test/Modules/crash-typo-correction-visibility.cpp +++ b/test/Modules/crash-typo-correction-visibility.cpp @@ -1,5 +1,6 @@ -// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodule-name=module -o %T/module.pcm -emit-module %S/Inputs/crash-typo-correction-visibility/module.modulemap -// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodule-file=%T/module.pcm %s -verify +// RUN: mkdir -p %t +// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodule-name=module -o %t/module.pcm -emit-module %S/Inputs/crash-typo-correction-visibility/module.modulemap +// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodule-file=%t/module.pcm %s -verify struct S { int member; // expected-note {{declared here}} diff --git a/test/Modules/crash-vfs-ivfsoverlay.m b/test/Modules/crash-vfs-ivfsoverlay.m index abbc0151a8cf..85aaeaef67a5 100644 --- a/test/Modules/crash-vfs-ivfsoverlay.m +++ b/test/Modules/crash-vfs-ivfsoverlay.m @@ -7,6 +7,7 @@ // RUN: %S/../VFS/Inputs/vfsoverlay2.yaml > %t/srcvfs.yaml // RUN: not env FORCE_CLANG_DIAGNOSTICS_CRASH= TMPDIR=%t TEMP=%t TMP=%t \ +// RUN: ASAN_OPTIONS=detect_leaks=0 \ // RUN: %clang -fsyntax-only -nostdinc %s \ // RUN: -I %S/Inputs/crash-recovery/usr/include \ // RUN: -ivfsoverlay %t/srcvfs.yaml \ diff --git a/test/Modules/cxx-templates.cpp b/test/Modules/cxx-templates.cpp index 401b7704900b..25f8a9992585 100644 --- a/test/Modules/cxx-templates.cpp +++ b/test/Modules/cxx-templates.cpp @@ -251,8 +251,22 @@ namespace Std { // CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} prev {{.*}} SomeTemplate // CHECK-DUMP-NEXT: TemplateArgument type 'char [2]' // CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} SomeTemplate definition +// CHECK-DUMP-NEXT: DefinitionData +// CHECK-DUMP-NEXT: DefaultConstructor +// CHECK-DUMP-NEXT: CopyConstructor +// CHECK-DUMP-NEXT: MoveConstructor +// CHECK-DUMP-NEXT: CopyAssignment +// CHECK-DUMP-NEXT: MoveAssignment +// CHECK-DUMP-NEXT: Destructor // CHECK-DUMP-NEXT: TemplateArgument type 'char [2]' // CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} prev {{.*}} SomeTemplate // CHECK-DUMP-NEXT: TemplateArgument type 'char [1]' // CHECK-DUMP: ClassTemplateSpecializationDecl {{.*}} SomeTemplate definition +// CHECK-DUMP-NEXT: DefinitionData +// CHECK-DUMP-NEXT: DefaultConstructor +// CHECK-DUMP-NEXT: CopyConstructor +// CHECK-DUMP-NEXT: MoveConstructor +// CHECK-DUMP-NEXT: CopyAssignment +// CHECK-DUMP-NEXT: MoveAssignment +// CHECK-DUMP-NEXT: Destructor // CHECK-DUMP-NEXT: TemplateArgument type 'char [1]' diff --git a/test/Modules/cxx17-inline-variables.cpp b/test/Modules/cxx17-inline-variables.cpp new file mode 100644 index 000000000000..be6a190a256b --- /dev/null +++ b/test/Modules/cxx17-inline-variables.cpp @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -std=c++17 -fsyntax-only -fmodules %s + +#pragma clang module build a +module a {} +#pragma clang module contents +#pragma clang module begin a + +template <class c, c e> struct ak { static constexpr c value = e; }; +ak<bool, true> instantiate_class_definition; + +#pragma clang module end /* a */ +#pragma clang module endbuild + + +#pragma clang module build o +module o {} +#pragma clang module contents +#pragma clang module begin o +#pragma clang module import a + +inline int instantiate_var_definition() { return ak<bool, true>::value; } + +#pragma clang module end +#pragma clang module endbuild + + +#pragma clang module import o +#pragma clang module import a + +int main() { return ak<bool, true>::value; } diff --git a/test/Modules/export_as_test.c b/test/Modules/export_as_test.c new file mode 100644 index 000000000000..a73d6bfc460d --- /dev/null +++ b/test/Modules/export_as_test.c @@ -0,0 +1,9 @@ +// RUN: rm -rf %t +// RUN: not %clang_cc1 -fmodules -fmodules-cache-path=%t -fmodule-map-file=%S/Inputs/export_as_test.modulemap %s 2> %t.err +// RUN: FileCheck %s < %t.err + +// CHECK: export_as_test.modulemap:3:13: error: conflicting re-export of module 'PrivateFoo' as 'Foo' or 'Bar' +// CHECK: export_as_test.modulemap:4:13: warning: module 'PrivateFoo' already re-exported as 'Bar' +// CHECK: export_as_test.modulemap:7:15: error: only top-level modules can be re-exported as public + + diff --git a/test/Modules/merge-anon-in-extern_c.cpp b/test/Modules/merge-anon-in-extern_c.cpp new file mode 100644 index 000000000000..1443251f7e61 --- /dev/null +++ b/test/Modules/merge-anon-in-extern_c.cpp @@ -0,0 +1,19 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -verify %s +// expected-no-diagnostics + +#pragma clang module build sys_types +module sys_types {} +#pragma clang module contents +#pragma clang module begin sys_types +extern "C" { + typedef union { bool b; } pthread_mutex_t; +} +#pragma clang module end +#pragma clang module endbuild + +typedef union { bool b; } pthread_mutex_t; +#pragma clang module import sys_types + +const pthread_mutex_t *m; + diff --git a/test/Modules/module-imported-by-pch-path.m b/test/Modules/module-imported-by-pch-path.m new file mode 100644 index 000000000000..04c6caf24dec --- /dev/null +++ b/test/Modules/module-imported-by-pch-path.m @@ -0,0 +1,17 @@ +// RUN: rm -rf %t.dst %t.cache +// RUN: mkdir -p %t.dst/folder-with-modulemap %t.dst/pch-folder +// RUN: echo '#import "folder-with-modulemap/included.h"' > %t.dst/header.h +// RUN: echo 'extern int MyModuleVersion;' > %t.dst/folder-with-modulemap/MyModule.h +// RUN: echo '@import MyModule;' > %t.dst/folder-with-modulemap/included.h +// RUN: echo 'module MyModule { header "MyModule.h" }' > %t.dst/folder-with-modulemap/module.modulemap + +// RUN: %clang -o %t.dst/pch-folder/header.pch -x objective-c-header -fmodules-cache-path=%t.cache -fmodules %t.dst/header.h +// RUN: not %clang -fsyntax-only -fmodules-cache-path=%t.cache -fmodules %s -include-pch %t.dst/pch-folder/header.pch 2>&1 | FileCheck %s + +void test() { + (void)MyModuleVersion; // should be found by implicit import +} + +// CHECK: module 'MyModule' in AST file '{{.*MyModule.*pcm}}' (imported by AST file '[[PCH:.*header.pch]]') is not defined in any loaded module map file; maybe you need to load '[[PATH:.*folder-with-modulemap]] +// CHECK: consider adding '[[PATH]]' to the header search path +// CHECK: imported by '[[PCH]]' diff --git a/test/Modules/modules-cache-path-canonicalization.m b/test/Modules/modules-cache-path-canonicalization.m index 9d68cb06faf8..a9d3e3478604 100644 --- a/test/Modules/modules-cache-path-canonicalization.m +++ b/test/Modules/modules-cache-path-canonicalization.m @@ -1,4 +1,4 @@ -// RUN: rm -rf %t/cache %T/rel +// RUN: rm -rf %t/cache %t/rel // This testcase reproduces a use-after-free after looking up a PCM in // a non-canonical modules-cache-path. @@ -22,7 +22,7 @@ // Unrelated to the above: Check that a relative path is resolved correctly. // -// RUN: %clang_cc1 -working-directory %T/rel -fmodules-cache-path=./cache \ +// RUN: %clang_cc1 -working-directory %t/rel -fmodules-cache-path=./cache \ // RUN: -fmodules -fimplicit-module-maps -I %S/Inputs/outofdate-rebuild \ // RUN: -fdisable-module-hash %t.m -fsyntax-only -Rmodule-build 2>&1 \ // RUN: | FileCheck %s diff --git a/test/Modules/odr_hash.cpp b/test/Modules/odr_hash.cpp index 68a988dc8e78..b672695dce15 100644 --- a/test/Modules/odr_hash.cpp +++ b/test/Modules/odr_hash.cpp @@ -12,6 +12,10 @@ // RUN: echo "#define SECOND" >> %t/Inputs/second.h // RUN: cat %s >> %t/Inputs/second.h +// Test that each header can compile +// RUN: %clang_cc1 -fsyntax-only -x c++ -std=c++1z %t/Inputs/first.h +// RUN: %clang_cc1 -fsyntax-only -x c++ -std=c++1z %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 @@ -28,6 +32,13 @@ #include "second.h" #endif +// Used for testing +#if defined(FIRST) +#define ACCESS public: +#elif defined(SECOND) +#define ACCESS private: +#endif + namespace AccessSpecifiers { #if defined(FIRST) struct S1 { @@ -55,6 +66,32 @@ 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 + +#define DECLS \ +public: \ +private: \ +protected: + +#if defined(FIRST) || defined(SECOND) +struct Valid1 { + DECLS +}; +#else +Valid1 v1; +#endif + +#if defined(FIRST) || defined(SECOND) +struct Invalid1 { + DECLS + ACCESS +}; +#else +Invalid1 i1; +// expected-error@second.h:* {{'AccessSpecifiers::Invalid1' 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 + +#undef DECLS } // namespace AccessSpecifiers namespace StaticAssert { @@ -113,7 +150,31 @@ 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 -} + +#define DECLS \ + static_assert(4 == 4, "Message"); \ + static_assert(5 == 5); + +#if defined(FIRST) || defined(SECOND) +struct Valid1 { + DECLS +}; +#else +Valid1 v1; +#endif + +#if defined(FIRST) || defined(SECOND) +struct Invalid1 { + DECLS + ACCESS +}; +#else +Invalid1 i1; +// expected-error@second.h:* {{'StaticAssert::Invalid1' 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 +#undef DECLS +} // namespace StaticAssert namespace Field { #if defined(FIRST) @@ -302,6 +363,38 @@ S13 s13; // expected-error@first.h:* {{'Field::S13::x' from module 'FirstModule' is not present in definition of 'Field::S13' in module 'SecondModule'}} // expected-note@second.h:* {{declaration of 'x' does not match}} #endif + +#define DECLS \ + int a; \ + int b : 3; \ + unsigned c : 1 + 2; \ + s d; \ + double e = 1.0; \ + long f[5]; + +#if defined(FIRST) || defined(SECOND) +typedef short s; +#endif + +#if defined(FIRST) || defined(SECOND) +struct Valid1 { + DECLS +}; +#else +Valid1 v1; +#endif + +#if defined(FIRST) || defined(SECOND) +struct Invalid1 { + DECLS + ACCESS +}; +#else +Invalid1 i1; +// expected-error@second.h:* {{'Field::Invalid1' 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 +#undef DECLS } // namespace Field namespace Method { @@ -531,6 +624,40 @@ S15 s15; // expected-error@first.h:* {{'Method::S15::A' from module 'FirstModule' is not present in definition of 'Method::S15' in module 'SecondModule'}} // expected-note@second.h:* {{declaration of 'A' does not match}} #endif + +#define DECLS \ + void A(); \ + static void B(); \ + virtual void C(); \ + virtual void D() = 0; \ + inline void E(); \ + void F() const; \ + void G() volatile; \ + void H(int x); \ + void I(int x = 5 + 5); \ + void J(int); \ + void K(int x[2]); \ + int L(); + +#if defined(FIRST) || defined(SECOND) +struct Valid1 { + DECLS +}; +#else +Valid1* v1; +#endif + +#if defined(FIRST) || defined(SECOND) +struct Invalid1 { + DECLS + ACCESS +}; +#else +Invalid1* i1; +// expected-error@second.h:* {{'Method::Invalid1' 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 +#undef DECLS } // namespace Method namespace Constructor { @@ -565,6 +692,31 @@ S2* s2; // expected-error@second.h:* {{'Constructor::S2' has different definitions in different modules; first difference is definition in module 'SecondModule' found constructor that has 2 parameters}} // expected-note@first.h:* {{but in 'FirstModule' found constructor that has 1 parameter}} #endif + +#define DECLS(CLASS) \ + CLASS(int); \ + CLASS(double); \ + CLASS(int, int); + +#if defined(FIRST) || defined(SECOND) +struct Valid1 { + DECLS(Valid1) +}; +#else +Valid1* v1; +#endif + +#if defined(FIRST) || defined(SECOND) +struct Invalid1 { + DECLS(Invalid1) + ACCESS +}; +#else +Invalid1* i1; +// expected-error@second.h:* {{'Constructor::Invalid1' 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 +#undef DECLS } // namespace Constructor namespace Destructor { @@ -600,32 +752,44 @@ S2 s2; // expected-note@first.h:* {{but in 'FirstModule' found destructor is virtual}} #endif -} // namespace Destructor - -// 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) {} +#if defined(FIRST) || defined(SECOND) +struct Valid1 { + ~Valid1(); }; +#else +Valid1 v1; +#endif -struct Xx { - struct Yy { - }; +#if defined(FIRST) || defined(SECOND) +struct Invalid1 { + ~Invalid1(); + ACCESS }; +#else +Invalid1 i1; +// expected-error@second.h:* {{'Destructor::Invalid1' 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 -Xx::Xx::Xx::Yy yy; +#if defined(FIRST) || defined(SECOND) +struct Valid2 { + virtual ~Valid2(); +}; +#else +Valid2 v2; +#endif -namespace NNS { -template <typename> struct Foo; -template <template <class> class T = NNS::Foo> -struct NestedNamespaceSpecifier {}; -} +#if defined(FIRST) || defined(SECOND) +struct Invalid2 { + virtual ~Invalid2(); + ACCESS +}; +#else +Invalid2 i2; +// expected-error@second.h:* {{'Destructor::Invalid2' 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 SelfReference +} // namespace Destructor namespace TypeDef { #if defined(FIRST) @@ -722,6 +886,35 @@ S6 s6; // expected-error@second.h:* {{'TypeDef::S6' has different definitions in different modules; first difference is definition in module 'SecondModule' found typedef 'b' with underlying type 'float'}} // expected-note@first.h:* {{but in 'FirstModule' found typedef 'b' with different underlying type 'TypeDef::F' (aka 'float')}} #endif + +#define DECLS \ + typedef int A; \ + typedef double B; \ + typedef I C; + +#if defined(FIRST) || defined(SECOND) +typedef int I; +#endif + +#if defined(FIRST) || defined(SECOND) +struct Valid1 { + DECLS +}; +#else +Valid1 v1; +#endif + +#if defined(FIRST) || defined(SECOND) +struct Invalid1 { + DECLS + ACCESS +}; +#else +Invalid1 i1; +// expected-error@second.h:* {{'TypeDef::Invalid1' 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 +#undef DECLS } // namespace TypeDef namespace Using { @@ -819,6 +1012,35 @@ S6 s6; // expected-error@second.h:* {{'Using::S6' has different definitions in different modules; first difference is definition in module 'SecondModule' found type alias 'b' with underlying type 'float'}} // expected-note@first.h:* {{but in 'FirstModule' found type alias 'b' with different underlying type 'Using::F' (aka 'float')}} #endif + +#if defined(FIRST) || defined(SECOND) +using I = int; +#endif + +#define DECLS \ + using A = int; \ + using B = double; \ + using C = I; + +#if defined(FIRST) || defined(SECOND) +struct Valid1 { + DECLS +}; +#else +Valid1 v1; +#endif + +#if defined(FIRST) || defined(SECOND) +struct Invalid1 { + DECLS + ACCESS +}; +#else +Invalid1 i1; +// expected-error@second.h:* {{'Using::Invalid1' 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 +#undef DECLS } // namespace Using namespace RecordType { @@ -837,7 +1059,34 @@ S1 s1; // expected-error@first.h:* {{'RecordType::S1::x' from module 'FirstModule' is not present in definition of 'RecordType::S1' in module 'SecondModule'}} // expected-note@second.h:* {{declaration of 'x' does not match}} #endif -} + +#define DECLS \ + Foo F; + +#if defined(FIRST) || defined(SECOND) +struct Foo {}; +#endif + +#if defined(FIRST) || defined(SECOND) +struct Valid1 { + DECLS +}; +#else +Valid1 v1; +#endif + +#if defined(FIRST) || defined(SECOND) +struct Invalid1 { + DECLS + ACCESS +}; +#else +Invalid1 i1; +// expected-error@second.h:* {{'RecordType::Invalid1' 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 +#undef DECLS +} // namespace RecordType namespace DependentType { #if defined(FIRST) @@ -856,7 +1105,34 @@ using U1 = S1<T>; // expected-error@first.h:* {{'DependentType::S1::x' from module 'FirstModule' is not present in definition of 'S1<T>' in module 'SecondModule'}} // expected-note@second.h:* {{declaration of 'x' does not match}} #endif -} + +#define DECLS \ + typename T::typeA x; + +#if defined(FIRST) || defined(SECOND) +template <class T> +struct Valid1 { + DECLS +}; +#else +template <class T> +using V1 = Valid1<T>; +#endif + +#if defined(FIRST) || defined(SECOND) +template <class T> +struct Invalid1 { + DECLS + ACCESS +}; +#else +template <class T> +using I1 = Invalid1<T>; +// expected-error@second.h:* {{'DependentType::Invalid1' 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 +#undef DECLS +} // namespace DependentType namespace ElaboratedType { #if defined(FIRST) @@ -874,7 +1150,34 @@ S1 s1; // expected-error@first.h:* {{'ElaboratedType::S1::x' from module 'FirstModule' is not present in definition of 'ElaboratedType::S1' in module 'SecondModule'}} // expected-note@second.h:* {{declaration of 'x' does not match}} #endif -} + +#define DECLS \ + NS::type x; + +#if defined(FIRST) || defined(SECOND) +namespace NS { using type = float; } +#endif + +#if defined(FIRST) || defined(SECOND) +struct Valid1 { + DECLS +}; +#else +Valid1 v1; +#endif + +#if defined(FIRST) || defined(SECOND) +struct Invalid1 { + DECLS + ACCESS +}; +#else +Invalid1 i1; +// expected-error@second.h:* {{'ElaboratedType::Invalid1' 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 +#undef DECLS +} // namespace ElaboratedType namespace Enum { #if defined(FIRST) @@ -892,6 +1195,33 @@ S1 s1; // expected-error@first.h:* {{'Enum::S1::x' from module 'FirstModule' is not present in definition of 'Enum::S1' in module 'SecondModule'}} // expected-note@second.h:* {{declaration of 'x' does not match}} #endif + +#define DECLS \ + E e = E1; + +#if defined(FIRST) || defined(SECOND) +enum E { E1, E2 }; +#endif + +#if defined(FIRST) || defined(SECOND) +struct Valid1 { + DECLS +}; +#else +Valid1 v1; +#endif + +#if defined(FIRST) || defined(SECOND) +struct Invalid1 { + DECLS + ACCESS +}; +#else +Invalid1 i1; +// expected-error@second.h:* {{'Enum::Invalid1' 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 +#undef DECLS } namespace NestedNamespaceSpecifier { @@ -1069,7 +1399,73 @@ S10 s10; // expected-note@first.h:* {{declaration of 'x' does not match}} #endif } + +#define DECLS \ + NS1::Type a; \ + NS1::NS2::Type b; \ + NS1::S c; \ + NS3::Type d; + +#if defined(FIRST) || defined(SECOND) +namespace NS1 { + using Type = int; + namespace NS2 { + using Type = double; + } + struct S {}; } +namespace NS3 = NS1; +#endif + +#if defined(FIRST) || defined(SECOND) +struct Valid1 { + DECLS +}; +#else +Valid1 v1; +#endif + +#if defined(FIRST) || defined(SECOND) +struct Invalid1 { + DECLS + ACCESS +}; +#else +Invalid1 i1; +// expected-error@second.h:* {{'NestedNamespaceSpecifier::Invalid1' 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 +#undef DECLS + +#define DECLS \ + typename T::type *x = {}; \ + int y = x->T::foo(); \ + int z = U::template X<int>::value; + +#if defined(FIRST) || defined(SECOND) +template <class T, class U> +struct Valid2 { + DECLS +}; +#else +template <class T, class U> +using V2 = Valid2<T, U>; +#endif + +#if defined(FIRST) || defined(SECOND) +template <class T, class U> +struct Invalid2 { + DECLS + ACCESS +}; +#else +template <class T, class U> +using I2 = Invalid2<T, U>; +// expected-error@second.h:* {{'NestedNamespaceSpecifier::Invalid2' 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 +#undef DECLS +} // namespace NestedNamespaceSpecifier namespace TemplateSpecializationType { #if defined(FIRST) @@ -1103,7 +1499,40 @@ S2 s2; // expected-error@first.h:* {{'TemplateSpecializationType::S2::u' from module 'FirstModule' is not present in definition of 'TemplateSpecializationType::S2' in module 'SecondModule'}} // expected-note@second.h:* {{declaration of 'u' does not match}} #endif -} + +#define DECLS \ + OneTemplateArg<int> x; \ + OneTemplateArg<double> y; \ + OneTemplateArg<char *> z; \ + TwoTemplateArgs<int, int> a; \ + TwoTemplateArgs<double, float> b; \ + TwoTemplateArgs<short *, char> c; + +#if defined(FIRST) || defined(SECOND) +template <class T> struct OneTemplateArg {}; +template <class T, class U> struct TwoTemplateArgs {}; +#endif + +#if defined(FIRST) || defined(SECOND) +struct Valid1 { +DECLS +}; +#else +Valid1 v1; +#endif + +#if defined(FIRST) || defined(SECOND) +struct Invalid1 { +DECLS +ACCESS +}; +#else +Invalid1 i1; +// expected-error@second.h:* {{'TemplateSpecializationType::Invalid1' 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 +#undef DECLS +} // namespace TemplateSpecializationType namespace TemplateArgument { #if defined(FIRST) @@ -1205,7 +1634,43 @@ S6 s6; // expected-error@second.h:* {{'TemplateArgument::S6' 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 -} + +#define DECLS \ + OneClass<int> a; \ + OneInt<1> b; \ + using c = OneClass<float>; \ + using d = OneInt<2>; \ + using e = OneInt<2 + 2>; \ + OneTemplateClass<OneClass> f; \ + OneTemplateInt<OneInt> g; + +#if defined(FIRST) || defined(SECOND) +template <class> struct OneClass{}; +template <int> struct OneInt{}; +template <template <class> class> struct OneTemplateClass{}; +template <template <int> class> struct OneTemplateInt{}; +#endif + +#if defined(FIRST) || defined(SECOND) +struct Valid1 { +DECLS +}; +#else +Valid1 v1; +#endif + +#if defined(FIRST) || defined(SECOND) +struct Invalid1 { +DECLS +ACCESS +}; +#else +Invalid1 i1; +// expected-error@second.h:* {{'TemplateArgument::Invalid1' 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 +#undef DECLS +} // namespace TemplateArgument namespace TemplateTypeParmType { #if defined(FIRST) @@ -1247,7 +1712,41 @@ using TemplateTypeParmType::S2; // expected-error@first.h:* {{'TemplateTypeParmType::S2::type' from module 'FirstModule' is not present in definition of 'S2<T, U>' in module 'SecondModule'}} // expected-note@second.h:* {{declaration of 'type' does not match}} #endif -} + +#define DECLS \ + T t; \ + U u; \ + ParameterPack<T> a; \ + ParameterPack<T, U> b; \ + ParameterPack<U> c; \ + ParameterPack<U, T> d; + +#if defined(FIRST) || defined(SECOND) +template <class ...Ts> struct ParameterPack {}; +#endif + +#if defined(FIRST) || defined(SECOND) +template <class T, class U> +struct Valid1 { + DECLS +}; +#else +using TemplateTypeParmType::Valid1; +#endif + +#if defined(FIRST) || defined(SECOND) +template <class T, class U> +struct Invalid1 { + DECLS + ACCESS +}; +#else +using TemplateTypeParmType::Invalid1; +// expected-error@second.h:* {{'TemplateTypeParmType::Invalid1' 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 +#undef DECLS +} // namespace TemplateTypeParmType namespace VarDecl { #if defined(FIRST) @@ -1381,46 +1880,36 @@ S9 s9; // expected-note@second.h:* {{declaration of 'x' does not match}} #endif -#if defined(FIRST) -template <typename T> -struct S { - struct R { - void foo(T x = 0) {} - }; -}; -#elif defined(SECOND) -template <typename T> -struct S { - struct R { - void foo(T x = 1) {} - }; +#define DECLS \ + static int a; \ + static I b; \ + static const int c = 1; \ + static constexpr int d = 5; + +#if defined(FIRST) || defined(SECOND) +using I = int; +#endif + +#if defined(FIRST) || defined(SECOND) +struct Valid1 { + DECLS }; #else -void run() { - S<int>::R().foo(); -} -// expected-error@second.h:* {{'VarDecl::S::R' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'foo' with 1st parameter with a default argument}} -// expected-note@first.h:* {{but in 'FirstModule' found method 'foo' with 1st parameter with a different default argument}} +Valid1 v1; #endif -#if defined(FIRST) -template <typename alpha> struct Bravo { - void charlie(bool delta = false) {} -}; -typedef Bravo<char> echo; -echo foxtrot; -#elif defined(SECOND) -template <typename alpha> struct Bravo { - void charlie(bool delta = (false)) {} +#if defined(FIRST) || defined(SECOND) +struct Invalid1 { + DECLS + ACCESS }; -typedef Bravo<char> echo; -echo foxtrot; #else -Bravo<char> golf; -// expected-error@second.h:* {{'VarDecl::Bravo' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'charlie' with 1st parameter with a default argument}} -// expected-note@first.h:* {{but in 'FirstModule' found method 'charlie' with 1st parameter with a different default argument}} +Invalid1 i1; +// expected-error@second.h:* {{'VarDecl::Invalid1' 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 -} +#undef DECLS +} // namespace VarDecl namespace Friend { #if defined(FIRST) @@ -1499,67 +1988,331 @@ S5 s5; // expected-error@second.h:* {{'Friend::S5' has different definitions in different modules; first difference is definition in module 'SecondModule' found friend function 'T5b'}} // expected-note@first.h:* {{but in 'FirstModule' found friend function 'T5a'}} #endif -} -// 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 { -#define CREATE_ALL_DECL_STRUCT(NAME, ACCESS) \ - typedef int INT; \ - struct NAME { \ - 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; \ - \ - void method_one_arg(int x) {} \ - void method_one_arg_default_argument(int x = 5 + 5) {} \ - void method_decayed_type(int x[5]) {} \ - \ - int constant_arr[5]; \ - \ - ACCESS: \ - }; +#define DECLS \ + friend class FriendA; \ + friend struct FriendB; \ + friend FriendC; \ + friend const FriendD; \ + friend void Function(); + +#if defined(FIRST) || defined(SECOND) +class FriendA {}; +class FriendB {}; +class FriendC {}; +class FriendD {}; +#endif + +#if defined(FIRST) || defined(SECOND) +struct Valid1 { + DECLS +}; +#else +Valid1 v1; +#endif + +#if defined(FIRST) || defined(SECOND) +struct Invalid1 { + DECLS + ACCESS +}; +#else +Invalid1 i1; +// expected-error@second.h:* {{'Friend::Invalid1' 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 +#undef DECLS +} // namespace Friend + +namespace TemplateParameters { #if defined(FIRST) -CREATE_ALL_DECL_STRUCT(S, public) +template <class A> +struct S1 {}; #elif defined(SECOND) -CREATE_ALL_DECL_STRUCT(S, public) +template <class B> +struct S1 {}; #else -S *s; +using TemplateParameters::S1; +// expected-error@second.h:* {{'TemplateParameters::S1' has different definitions in different modules; first difference is definition in module 'SecondModule' found template parameter 'B'}} +// expected-note@first.h:* {{but in 'FirstModule' found template parameter 'A'}} #endif #if defined(FIRST) -CREATE_ALL_DECL_STRUCT(T, private) +template <class A = double> +struct S2 {}; #elif defined(SECOND) -CREATE_ALL_DECL_STRUCT(T, public) +template <class A = int> +struct S2 {}; #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}} +using TemplateParameters::S2; +// expected-error@second.h:* {{'TemplateParameters::S2' has different definitions in different modules; first difference is definition in module 'SecondModule' found template parameter with default argument}} +// expected-note@first.h:* {{but in 'FirstModule' found template parameter with different default argument}} +#endif + +#if defined(FIRST) +template <class A = int> +struct S3 {}; +#elif defined(SECOND) +template <class A> +struct S3 {}; +#else +using TemplateParameters::S3; +// expected-error@second.h:* {{'TemplateParameters::S3' has different definitions in different modules; first difference is definition in module 'SecondModule' found template parameter with no default argument}} +// expected-note@first.h:* {{but in 'FirstModule' found template parameter with default argument}} +#endif + +#if defined(FIRST) +template <int A> +struct S4 {}; +#elif defined(SECOND) +template <int A = 2> +struct S4 {}; +#else +using TemplateParameters::S4; +// expected-error@second.h:* {{'TemplateParameters::S4' has different definitions in different modules; first difference is definition in module 'SecondModule' found template parameter with default argument}} +// expected-note@first.h:* {{but in 'FirstModule' found template parameter with no default argument}} +#endif + +#if defined(FIRST) +template <int> class S5_first {}; +template <template<int> class A = S5_first> +struct S5 {}; +#elif defined(SECOND) +template <int> class S5_second {}; +template <template<int> class A = S5_second> +struct S5 {}; +#else +using TemplateParameters::S5; +// expected-error@second.h:* {{'TemplateParameters::S5' has different definitions in different modules; first difference is definition in module 'SecondModule' found template parameter with default argument}} +// expected-note@first.h:* {{but in 'FirstModule' found template parameter with different default argument}} +#endif + +#if defined(FIRST) +template <class A> +struct S6 {}; +#elif defined(SECOND) +template <class> +struct S6 {}; +#else +using TemplateParameters::S6; +// expected-error@second.h:* {{'TemplateParameters::S6' has different definitions in different modules; first difference is definition in module 'SecondModule' found unnamed template parameter}} +// expected-note@first.h:* {{but in 'FirstModule' found template parameter 'A'}} +#endif + +#define DECLS + +#if defined(FIRST) || defined(SECOND) +template <class> class DefaultArg; #endif + +#if defined(FIRST) || defined(SECOND) +template <int, class, template <class> class, + int A, class B, template <int> class C, + int D = 1, class E = int, template <class F> class = DefaultArg> +struct Valid1 { + DECLS +}; +#else +using TemplateParameters::Valid1; +#endif + +#if defined(FIRST) || defined(SECOND) +template <int, class, template <class> class, + int A, class B, template <int> class C, + int D = 1, class E = int, template <class F> class = DefaultArg> +struct Invalid1 { + DECLS + ACCESS +}; +#else +using TemplateParameters::Invalid1; +// expected-error@second.h:* {{'TemplateParameters::Invalid1' 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 +#undef DECLS +} // namespace TemplateParameters + +namespace BaseClass { +#if defined(FIRST) +struct B1 {}; +struct S1 : B1 {}; +#elif defined(SECOND) +struct S1 {}; +#else +S1 s1; +// expected-error@second.h:* {{'BaseClass::S1' has different definitions in different modules; first difference is definition in module 'SecondModule' found 0 base classes}} +// expected-note@first.h:* {{but in 'FirstModule' found 1 base class}} +#endif + +#if defined(FIRST) +struct S2 {}; +#elif defined(SECOND) +struct B2 {}; +struct S2 : virtual B2 {}; +#else +S2 s2; +// expected-error@second.h:* {{'BaseClass::S2' has different definitions in different modules; first difference is definition in module 'SecondModule' found 1 base class}} +// expected-note@first.h:* {{but in 'FirstModule' found 0 base classes}} +#endif + +#if defined(FIRST) +struct B3a {}; +struct S3 : B3a {}; +#elif defined(SECOND) +struct B3b {}; +struct S3 : virtual B3b {}; +#else +S3 s3; +// expected-error@second.h:* {{'BaseClass::S3' has different definitions in different modules; first difference is definition in module 'SecondModule' found 1 virtual base class}} +// expected-note@first.h:* {{but in 'FirstModule' found 0 virtual base classes}} +#endif + +#if defined(FIRST) +struct B4a {}; +struct S4 : B4a {}; +#elif defined(SECOND) +struct B4b {}; +struct S4 : B4b {}; +#else +S4 s4; +// expected-error@second.h:* {{'BaseClass::S4' has different definitions in different modules; first difference is definition in module 'SecondModule' found 1st base class with type 'BaseClass::B4b'}} +// expected-note@first.h:* {{but in 'FirstModule' found 1st base class with different type 'BaseClass::B4a'}} +#endif + +#if defined(FIRST) +struct B5a {}; +struct S5 : virtual B5a {}; +#elif defined(SECOND) +struct B5a {}; +struct S5 : B5a {}; +#else +S5 s5; +// expected-error@second.h:* {{'BaseClass::S5' has different definitions in different modules; first difference is definition in module 'SecondModule' found 0 virtual base classes}} +// expected-note@first.h:* {{but in 'FirstModule' found 1 virtual base class}} +#endif + +#if defined(FIRST) +struct B6a {}; +struct S6 : B6a {}; +#elif defined(SECOND) +struct B6a {}; +struct S6 : virtual B6a {}; +#else +S6 s6; +// expected-error@second.h:* {{'BaseClass::S6' has different definitions in different modules; first difference is definition in module 'SecondModule' found 1 virtual base class}} +// expected-note@first.h:* {{but in 'FirstModule' found 0 virtual base classes}} +#endif + +#if defined(FIRST) +struct B7a {}; +struct S7 : protected B7a {}; +#elif defined(SECOND) +struct B7a {}; +struct S7 : B7a {}; +#else +S7 s7; +// expected-error@second.h:* {{'BaseClass::S7' has different definitions in different modules; first difference is definition in module 'SecondModule' found 1st base class 'BaseClass::B7a' with no access specifier}} +// expected-note@first.h:* {{but in 'FirstModule' found 1st base class 'BaseClass::B7a' with protected access specifier}} +#endif + +#if defined(FIRST) +struct B8a {}; +struct S8 : public B8a {}; +#elif defined(SECOND) +struct B8a {}; +struct S8 : private B8a {}; +#else +S8 s8; +// expected-error@second.h:* {{'BaseClass::S8' has different definitions in different modules; first difference is definition in module 'SecondModule' found 1st base class 'BaseClass::B8a' with private access specifier}} +// expected-note@first.h:* {{but in 'FirstModule' found 1st base class 'BaseClass::B8a' with public access specifier}} +#endif + +#if defined(FIRST) +struct B9a {}; +struct S9 : private B9a {}; +#elif defined(SECOND) +struct B9a {}; +struct S9 : public B9a {}; +#else +S9 s9; +// expected-error@second.h:* {{'BaseClass::S9' has different definitions in different modules; first difference is definition in module 'SecondModule' found 1st base class 'BaseClass::B9a' with public access specifier}} +// expected-note@first.h:* {{but in 'FirstModule' found 1st base class 'BaseClass::B9a' with private access specifier}} +#endif + +#if defined(FIRST) +struct B10a {}; +struct S10 : B10a {}; +#elif defined(SECOND) +struct B10a {}; +struct S10 : protected B10a {}; +#else +S10 s10; +// expected-error@second.h:* {{'BaseClass::S10' has different definitions in different modules; first difference is definition in module 'SecondModule' found 1st base class 'BaseClass::B10a' with protected access specifier}} +// expected-note@first.h:* {{but in 'FirstModule' found 1st base class 'BaseClass::B10a' with no access specifier}} +#endif + +#define DECLS + +#if defined(FIRST) || defined(SECOND) +struct Base1 {}; +struct Base2 {}; +struct Base3 {}; +struct Base4 {}; +struct Base5 {}; +#endif + +#if defined(FIRST) || defined(SECOND) +struct Valid1 : + Base1, virtual Base2, protected Base3, public Base4, private Base5 { + + DECLS +}; +#else +Valid1 v1; +#endif + +#if defined(FIRST) || defined(SECOND) +struct Invalid1 : + Base1, virtual Base2, protected Base3, public Base4, private Base5 { + + DECLS + ACCESS +}; +#else +Invalid1 i1; +// expected-error@second.h:* {{'BaseClass::Invalid1' 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 +#undef DECLS +} // namespace BaseClass + + +// Collection of interesting cases below. + +// 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 FriendFunction { #if defined(FIRST) @@ -1628,7 +2381,7 @@ T t; // expected-note@second.h:* {{but in 'SecondModule' found public access specifier}} #endif -} // namespace ImplicitDelc +} // namespace ImplicitDecl namespace TemplatedClass { #if defined(FIRST) @@ -1854,7 +2607,7 @@ void run() { S<int>::R().foo(); } #endif -} +} // namespace LateParsedDefaultArgument namespace LateParsedDefaultArgument { #if defined(FIRST) @@ -1868,7 +2621,7 @@ Bravo<char> golf; #elif defined(SECOND) #else #endif -} +} // LateParsedDefaultArgument namespace DifferentParameterNameInTemplate { #if defined(FIRST) || defined(SECOND) @@ -1914,7 +2667,7 @@ struct BetaHelper { #else Alpha::Alpha() {} #endif -} +} // DifferentParameterNameInTemplate namespace ParameterTest { #if defined(FIRST) @@ -1941,7 +2694,7 @@ G* S<G>::Foo(const G* asdf, int*) {} #else S<X> s; #endif -} +} // ParameterTest namespace MultipleTypedefs { #if defined(FIRST) @@ -1991,12 +2744,59 @@ struct S3 { #else S3 s3; #endif +} // MultipleTypedefs + +namespace DefaultArguments { +#if defined(FIRST) +template <typename T> +struct S { + struct R { + void foo(T x = 0) {} + }; +}; +#elif defined(SECOND) +template <typename T> +struct S { + struct R { + void foo(T x = 1) {} + }; +}; +#else +void run() { + S<int>::R().foo(); } +// expected-error@second.h:* {{'DefaultArguments::S::R' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'foo' with 1st parameter with a default argument}} +// expected-note@first.h:* {{but in 'FirstModule' found method 'foo' with 1st parameter with a different default argument}} +#endif + +#if defined(FIRST) +template <typename alpha> struct Bravo { + void charlie(bool delta = false) {} +}; +typedef Bravo<char> echo; +echo foxtrot; +#elif defined(SECOND) +template <typename alpha> struct Bravo { + void charlie(bool delta = (false)) {} +}; +typedef Bravo<char> echo; +echo foxtrot; +#else +Bravo<char> golf; +// expected-error@second.h:* {{'DefaultArguments::Bravo' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'charlie' with 1st parameter with a default argument}} +// expected-note@first.h:* {{but in 'FirstModule' found method 'charlie' with 1st parameter with a different default argument}} +#endif +} // namespace DefaultArguments // Keep macros contained to one file. #ifdef FIRST #undef FIRST #endif + #ifdef SECOND #undef SECOND #endif + +#ifdef ACCESS +#undef ACCESS +#endif diff --git a/test/Modules/path-resolution.modulemap b/test/Modules/path-resolution.modulemap new file mode 100644 index 000000000000..72f5f142c326 --- /dev/null +++ b/test/Modules/path-resolution.modulemap @@ -0,0 +1,70 @@ +// RUN: rm -rf %t +// +// First, create two modules a and b, with a dependency b -> a, both within +// the same directory p1. +// +// RUN: mkdir -p %t/p1 +// RUN: cd %t/p1 +// +// RUN: grep "<AM>" %s > %t/p1/a.modulemap +// RUN: %clang_cc1 -x c++ -fmodules -emit-module -fmodule-map-file-home-is-cwd \ +// RUN: -fmodules-embed-all-files -fmodules-local-submodule-visibility \ +// RUN: -fmodule-name="a" -o a.pcm a.modulemap +// +// RUN: grep "<BM>" %s > %t/p1/b.modulemap +// RUN: %clang_cc1 -x c++ -fmodules -emit-module -fmodule-map-file-home-is-cwd \ +// RUN: -fmodules-embed-all-files -fmodules-local-submodule-visibility \ +// RUN: -fmodule-name="b" -o b.pcm b.modulemap +// +// Next, move the whole tree p1 -> p2. +// +// RUN: cd %t +// RUN: mv %t/p1 %t/p2 +// RUN: cd %t/p2 +// +// Compile a new module c in the newly generated tree that depends on b; c.pcm +// has to be within a subdirectory so a.modulemap will be one step up (../) from +// c.pcm. +// +// RUN: mkdir %t/p2/c +// RUN: grep "<CM>" %s > %t/p2/c/c.modulemap +// RUN: grep "<CH>" %s > %t/p2/c/c.h +// RUN: %clang_cc1 -x c++ -fmodules -emit-module -fmodule-map-file-home-is-cwd \ +// RUN: -fmodules-embed-all-files -fmodules-local-submodule-visibility \ +// RUN: -fmodule-name="c" -fmodule-file=b.pcm -o c/c.pcm c/c.modulemap +// +// Delete a.modulemap from its original location, and instead inject a different +// (unrelated) a.modulemap in the path p2/p2. +// +// RUN: rm %t/p2/a.modulemap +// RUN: mkdir -p %t/p2/p2 +// RUN: touch %t/p2/p2/a.modulemap +// +// Now compile a file c.cpp that uses c.h and the module c; it is important +// to first load b.pcm and a.pcm before c.pcm on the command line to trigger +// the right order of module loading. This used to trigger clang to find the +// p2/p2/a.modulemap via the path c/../p2/a.modulemap, which is not the correct +// relative path from c. +// +// RUN: grep "<CC>" %s > %t/p2/c/c.cpp +// RUN: %clang_cc1 -I. -x c++ -fmodules \ +// RUN: -fmodule-file=b.pcm -fmodule-file=a.pcm -fmodule-file=c/c.pcm \ +// RUN: -o c/c.o -emit-obj c/c.cpp + +module "a" { // <AM> +} // <AM> + +module "b" { // <BM> + use "a" // <BM> +} // <BM> + +module "c" { // <CM> + header "c/c.h" // <CM> + use "a" // <CM> + use "b" // <CM> +} // <CM> + +inline void c() {} // <CH> + +#include "c/c.h" // <CC> +void foo() { c(); } // <CC> diff --git a/test/Modules/umbrella-header-include-builtin.mm b/test/Modules/umbrella-header-include-builtin.mm index da21779683cf..b14c73705ca8 100644 --- a/test/Modules/umbrella-header-include-builtin.mm +++ b/test/Modules/umbrella-header-include-builtin.mm @@ -1,7 +1,5 @@ -// REQUIRES: system-darwin - // RUN: rm -rf %t -// RUN: %clang -cc1 -fsyntax-only -nostdinc++ -isysroot %S/Inputs/libc-libcxx/sysroot -isystem %S/Inputs/libc-libcxx/sysroot/usr/include/c++/v1 -F%S/Inputs/libc-libcxx/sysroot/Frameworks -std=c++11 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x objective-c++ %s +// RUN: %clang -cc1 -fsyntax-only -nobuiltininc -nostdinc++ -isysroot %S/Inputs/libc-libcxx/sysroot -isystem %S/Inputs/libc-libcxx/sysroot/usr/include/c++/v1 -isystem %S/Inputs/libc-libcxx/sysroot/usr/include -F%S/Inputs/libc-libcxx/sysroot/Frameworks -std=c++11 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x objective-c++ %s #include <A/A.h> diff --git a/test/Modules/using-decl-inheritance.cpp b/test/Modules/using-decl-inheritance.cpp new file mode 100644 index 000000000000..eba9636b75ef --- /dev/null +++ b/test/Modules/using-decl-inheritance.cpp @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -x c++ -fmodules -fmodules-local-submodule-visibility -fmodules-cache-path=%t %s -verify +// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t %s -verify + +// expected-no-diagnostics + +#pragma clang module build A + module A { } +#pragma clang module contents +#pragma clang module begin A +struct A { + virtual void Foo(double x) const; +}; +#pragma clang module end +#pragma clang module endbuild + +#pragma clang module build B + module B { } +#pragma clang module contents +#pragma clang module begin B +#pragma clang module import A +struct B : A { + using A::Foo; + virtual void Foo(double x) const; +}; +#pragma clang module end +#pragma clang module endbuild + +#pragma clang module import B + +int main() { + B b; + b.Foo(1.0); +} + diff --git a/test/Modules/using-directive-redecl.cpp b/test/Modules/using-directive-redecl.cpp new file mode 100644 index 000000000000..94772f30a3d4 --- /dev/null +++ b/test/Modules/using-directive-redecl.cpp @@ -0,0 +1,37 @@ +// RUN: %clang_cc1 -fmodules -fmodules-local-submodule-visibility -verify %s +// expected-no-diagnostics +#pragma clang module build M +module M { module TDFNodes {} module TDFInterface {} } +#pragma clang module contents + // TDFNodes + #pragma clang module begin M.TDFNodes + namespace Detail { + namespace TDF { + class TLoopManager {}; + } + } + namespace Internal { + namespace TDF { + using namespace Detail::TDF; + } + } + #pragma clang module end + + // TDFInterface + #pragma clang module begin M.TDFInterface + #pragma clang module import M.TDFNodes + namespace Internal { + namespace TDF { + using namespace Detail::TDF; + } + } + #pragma clang module end + +#pragma clang module endbuild + +#pragma clang module import M.TDFNodes +namespace Internal { + namespace TDF { + TLoopManager * use; + } +} diff --git a/test/Modules/using-directive.cpp b/test/Modules/using-directive.cpp new file mode 100644 index 000000000000..6ca5c6eab4f9 --- /dev/null +++ b/test/Modules/using-directive.cpp @@ -0,0 +1,62 @@ +// RUN: %clang_cc1 -fmodules -fmodules-local-submodule-visibility -fno-modules-error-recovery -fno-spell-checking -verify %s + +#pragma clang module build a +module a { explicit module b {} explicit module c {} } +#pragma clang module contents + +#pragma clang module begin a.b +namespace b { int n; } +#pragma clang module end + +#pragma clang module begin a.c +#pragma clang module import a.b +namespace c { using namespace b; } +#pragma clang module end + +#pragma clang module begin a +#pragma clang module import a.c +using namespace c; +#pragma clang module end + +#pragma clang module endbuild + +#pragma clang module import a.b +void use1() { + (void)n; // expected-error {{use of undeclared identifier}} + (void)::n; // expected-error {{no member named 'n' in the global namespace}} + (void)b::n; +} +namespace b { + void use1_in_b() { (void)n; } +} +namespace c { + void use1_in_c() { (void)n; } // expected-error {{use of undeclared identifier}} +} + +#pragma clang module import a.c +void use2() { + (void)n; // expected-error {{use of undeclared identifier}} + (void)::n; // expected-error {{no member named 'n' in the global namespace}} + (void)b::n; + (void)c::n; +} +namespace b { + void use2_in_b() { (void)n; } +} +namespace c { + void use2_in_c() { (void)n; } +} + +#pragma clang module import a +void use3() { + (void)n; + (void)::n; + (void)b::n; + (void)c::n; +} +namespace b { + void use3_in_b() { (void)n; } +} +namespace c { + void use3_in_c() { (void)n; } +} diff --git a/test/Modules/var-templates.cpp b/test/Modules/var-templates.cpp new file mode 100644 index 000000000000..eca242873969 --- /dev/null +++ b/test/Modules/var-templates.cpp @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -fmodules -std=c++14 -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s + +#pragma clang module build A +module A {} +#pragma clang module contents +#pragma clang module begin A +template<int> int n = 42; +decltype(n<0>) f(); +#pragma clang module end +#pragma clang module endbuild + +#pragma clang module build B +module B {} +#pragma clang module contents +#pragma clang module begin B +#pragma clang module import A +inline int f() { return n<0>; } +#pragma clang module end +#pragma clang module endbuild + +#pragma clang module import B + +// CHECK: @_Z1nILi0EE = linkonce_odr global i32 42, comdat +int g() { return f(); } diff --git a/test/Modules/visibility-in-instantiation.cpp b/test/Modules/visibility-in-instantiation.cpp new file mode 100644 index 000000000000..8689758a42ba --- /dev/null +++ b/test/Modules/visibility-in-instantiation.cpp @@ -0,0 +1,51 @@ +// RUN: %clang_cc1 -std=c++11 -fmodules %s -verify + +#pragma clang module build M + module M { module A {} module B {} module C {} } +#pragma clang module contents + + #pragma clang module begin M.A + template<typename U> struct X { + template<typename T> void f(); + }; + #pragma clang module end + + #pragma clang module begin M.B + template<typename T, typename U = void> struct ST { static void f(); }; + #pragma clang module end + + #pragma clang module begin M.C + template<typename U> struct X; + void foo(X<int>); + #pragma clang module end +#pragma clang module endbuild + +#pragma clang module build N + module N {} +#pragma clang module contents + #pragma clang module begin N + #pragma clang module import M.B // not re-exported + + template<typename U> struct X { + template<typename T> void f(); + template<typename T> void g(); + }; + + template<typename U> template<typename T> + void X<U>::f() { + ST<T>::f(); // definition and default argument found in M.B + foo(*this); // found by ADL in M.C + }; + + #pragma clang module import M.C // not re-exported + #pragma clang module end +#pragma clang module endbuild + +#pragma clang module import N +void g() { + X<int>().f<int>(); + + ST<int>::f(); // expected-error {{must be imported from module 'M.B'}} + foo(X<int>()); // expected-error {{must be imported from module 'M.C'}} + // expected-note@* 2{{previous declaration is here}} +} |