aboutsummaryrefslogtreecommitdiff
path: root/test/Modules
diff options
context:
space:
mode:
Diffstat (limited to 'test/Modules')
-rw-r--r--test/Modules/ExtDebugInfo.cpp9
-rw-r--r--test/Modules/Inputs/DebugCXX.h6
-rw-r--r--test/Modules/Inputs/codegen/foo.h3
-rw-r--r--test/Modules/Inputs/codegen/use.cpp3
-rw-r--r--test/Modules/Inputs/export_as_test.modulemap9
-rw-r--r--test/Modules/ModuleDebugInfo.cpp11
-rw-r--r--test/Modules/adl.cpp40
-rw-r--r--test/Modules/anon-linkage.cpp12
-rw-r--r--test/Modules/builtin-import.mm4
-rw-r--r--test/Modules/codegen-opt.test12
-rw-r--r--test/Modules/codegen.test4
-rw-r--r--test/Modules/crash-typo-correction-visibility.cpp5
-rw-r--r--test/Modules/crash-vfs-ivfsoverlay.m1
-rw-r--r--test/Modules/cxx-templates.cpp14
-rw-r--r--test/Modules/cxx17-inline-variables.cpp30
-rw-r--r--test/Modules/export_as_test.c9
-rw-r--r--test/Modules/merge-anon-in-extern_c.cpp19
-rw-r--r--test/Modules/module-imported-by-pch-path.m17
-rw-r--r--test/Modules/modules-cache-path-canonicalization.m4
-rw-r--r--test/Modules/odr_hash.cpp1030
-rw-r--r--test/Modules/path-resolution.modulemap70
-rw-r--r--test/Modules/umbrella-header-include-builtin.mm4
-rw-r--r--test/Modules/using-decl-inheritance.cpp34
-rw-r--r--test/Modules/using-directive-redecl.cpp37
-rw-r--r--test/Modules/using-directive.cpp62
-rw-r--r--test/Modules/var-templates.cpp24
-rw-r--r--test/Modules/visibility-in-instantiation.cpp51
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}}
+}