summaryrefslogtreecommitdiffstats
path: root/clang/test/Modules
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2016-05-05 00:56:12 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2016-05-05 00:56:12 +0000
commit6739a10cec3d5681cc1c0f793be58756dfe0537a (patch)
treee2742beb3f5a7c2dd218150a1deeaebee1005f18 /clang/test/Modules
parentd55bc4c7abeff02a8641918dfa65cac16d9c8818 (diff)
downloadbcm5719-llvm-6739a10cec3d5681cc1c0f793be58756dfe0537a.tar.gz
bcm5719-llvm-6739a10cec3d5681cc1c0f793be58756dfe0537a.zip
[modules] Enforce the rules that an explicit or partial specialization must be
declared before it is used. Because we don't use normal name lookup to find these, the normal code to filter out non-visible names from name lookup results does not apply. llvm-svn: 268585
Diffstat (limited to 'clang/test/Modules')
-rw-r--r--clang/test/Modules/Inputs/cxx-templates-common.h17
-rw-r--r--clang/test/Modules/Inputs/cxx-templates-unimported.h43
-rw-r--r--clang/test/Modules/Inputs/module.map2
-rw-r--r--clang/test/Modules/cxx-templates.cpp70
4 files changed, 126 insertions, 6 deletions
diff --git a/clang/test/Modules/Inputs/cxx-templates-common.h b/clang/test/Modules/Inputs/cxx-templates-common.h
index a9ca6244867..8e730c8a852 100644
--- a/clang/test/Modules/Inputs/cxx-templates-common.h
+++ b/clang/test/Modules/Inputs/cxx-templates-common.h
@@ -53,4 +53,21 @@ template<typename T> struct WithAnonymousDecls {
typedef int X;
};
+namespace hidden_specializations {
+ template<typename T> void fn() {}
+
+ template<typename T> struct cls {
+ static void nested_fn() {}
+ struct nested_cls {};
+ static int nested_var;
+ enum class nested_enum {};
+
+ template<typename U> static void nested_fn_t() {}
+ template<typename U> struct nested_cls_t {};
+ template<typename U> static int nested_var_t;
+ };
+
+ template<typename T> int var;
+}
+
#include "cxx-templates-textual.h"
diff --git a/clang/test/Modules/Inputs/cxx-templates-unimported.h b/clang/test/Modules/Inputs/cxx-templates-unimported.h
new file mode 100644
index 00000000000..c2b6b915924
--- /dev/null
+++ b/clang/test/Modules/Inputs/cxx-templates-unimported.h
@@ -0,0 +1,43 @@
+#include "cxx-templates-common.h"
+
+namespace hidden_specializations {
+ // explicit specializations
+ template<> void fn<int>() {}
+ template<> struct cls<int> {
+ void nested_fn();
+ struct nested_cls;
+ static int nested_var;
+ enum nested_enum : int;
+ };
+ template<> int var<int>;
+
+ // partial specializations
+ template<typename T> struct cls<T*> {
+ void nested_fn();
+ struct nested_cls;
+ static int nested_var;
+ enum nested_enum : int;
+ };
+ template<typename T> int var<T*>;
+
+ // member specializations
+ template<> void cls<void>::nested_fn() {}
+ template<> struct cls<void>::nested_cls {};
+ template<> int cls<void>::nested_var;
+ template<> enum class cls<void>::nested_enum { e };
+ template<> template<typename U> void cls<void>::nested_fn_t() {}
+ template<> template<typename U> struct cls<void>::nested_cls_t {};
+ template<> template<typename U> int cls<void>::nested_var_t;
+
+ // specializations instantiated here are ok if their pattern is
+ inline void use_stuff() {
+ fn<char>();
+ cls<char>();
+ (void)var<char>;
+ cls<char*>();
+ (void)var<char*>;
+ cls<void>::nested_fn_t<char>();
+ cls<void>::nested_cls_t<char>();
+ (void)cls<void>::nested_var_t<char>;
+ }
+}
diff --git a/clang/test/Modules/Inputs/module.map b/clang/test/Modules/Inputs/module.map
index 66b52e9105e..4db1cca925c 100644
--- a/clang/test/Modules/Inputs/module.map
+++ b/clang/test/Modules/Inputs/module.map
@@ -215,6 +215,8 @@ module cxx_linkage_cache {
module cxx_templates_common {
header "cxx-templates-common.h"
+
+ explicit module unimported { header "cxx-templates-unimported.h" }
}
module cxx_templates_a {
diff --git a/clang/test/Modules/cxx-templates.cpp b/clang/test/Modules/cxx-templates.cpp
index ef4e4e420d0..eea90774aa8 100644
--- a/clang/test/Modules/cxx-templates.cpp
+++ b/clang/test/Modules/cxx-templates.cpp
@@ -1,9 +1,9 @@
// RUN: rm -rf %t
-// RUN: not %clang_cc1 -x objective-c++ -fmodules -fimplicit-module-maps -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -std=c++11 -ast-dump-lookups | FileCheck %s --check-prefix=CHECK-GLOBAL
-// RUN: not %clang_cc1 -x objective-c++ -fmodules -fimplicit-module-maps -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -std=c++11 -ast-dump-lookups -ast-dump-filter N | FileCheck %s --check-prefix=CHECK-NAMESPACE-N
-// RUN: not %clang_cc1 -x objective-c++ -fmodules -fimplicit-module-maps -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -std=c++11 -ast-dump -ast-dump-filter SomeTemplate | FileCheck %s --check-prefix=CHECK-DUMP
-// RUN: %clang_cc1 -x objective-c++ -fmodules -fimplicit-module-maps -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -verify -std=c++11
-// RUN: %clang_cc1 -x objective-c++ -fmodules -fimplicit-module-maps -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -verify -std=c++11 -DEARLY_IMPORT
+// RUN: not %clang_cc1 -x objective-c++ -fmodules -fimplicit-module-maps -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -std=c++14 -ast-dump-lookups | FileCheck %s --check-prefix=CHECK-GLOBAL
+// RUN: not %clang_cc1 -x objective-c++ -fmodules -fimplicit-module-maps -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -std=c++14 -ast-dump-lookups -ast-dump-filter N | FileCheck %s --check-prefix=CHECK-NAMESPACE-N
+// RUN: not %clang_cc1 -x objective-c++ -fmodules -fimplicit-module-maps -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -std=c++14 -ast-dump -ast-dump-filter SomeTemplate | FileCheck %s --check-prefix=CHECK-DUMP
+// RUN: %clang_cc1 -x objective-c++ -fmodules -fimplicit-module-maps -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -verify -std=c++14
+// RUN: %clang_cc1 -x objective-c++ -fmodules -fimplicit-module-maps -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -verify -std=c++14 -DEARLY_IMPORT
#ifdef EARLY_IMPORT
#include "cxx-templates-textual.h"
@@ -105,7 +105,8 @@ void g() {
TemplateInstantiationVisibility<char[1]> tiv1;
TemplateInstantiationVisibility<char[2]> tiv2;
- TemplateInstantiationVisibility<char[3]> tiv3; // expected-error 2{{must be imported from module 'cxx_templates_b_impl'}}
+ TemplateInstantiationVisibility<char[3]> tiv3; // expected-error 5{{must be imported from module 'cxx_templates_b_impl'}}
+ // expected-note@cxx-templates-b-impl.h:10 3{{explicit specialization declared here}}
// expected-note@cxx-templates-b-impl.h:10 2{{previous definition is here}}
TemplateInstantiationVisibility<char[4]> tiv4;
@@ -172,6 +173,63 @@ bool testFriendInClassTemplate(Std::WithFriend<int> wfi) {
return wfi != wfi;
}
+namespace hidden_specializations {
+ // expected-note@cxx-templates-unimported.h:* 1+{{here}}
+ void test() {
+ // For functions, uses that would trigger instantiations of definitions are
+ // not allowed.
+ fn<void>(); // ok
+ fn<char>(); // ok
+ fn<int>(); // expected-error 1+{{explicit specialization of 'fn<int>' must be imported}}
+ cls<void>::nested_fn(); // expected-error 1+{{explicit specialization of 'nested_fn' must be imported}}
+ cls<void>::nested_fn_t<int>(); // expected-error 1+{{explicit specialization of 'nested_fn_t' must be imported}}
+ cls<void>::nested_fn_t<char>(); // expected-error 1+{{explicit specialization of 'nested_fn_t' must be imported}}
+
+ // For classes, uses that would trigger instantiations of definitions are
+ // not allowed.
+ cls<void> *k0; // ok
+ cls<char> *k1; // ok
+ cls<int> *k2; // ok
+ cls<int*> *k3; // ok
+ cls<void>::nested_cls *nk1; // ok
+ cls<void>::nested_cls_t<int> *nk2; // ok
+ cls<void>::nested_cls_t<char> *nk3; // ok
+ cls<int> uk1; // expected-error 1+{{explicit specialization of 'cls<int>' must be imported}} expected-error 1+{{definition of}}
+ cls<int*> uk3; // expected-error 1+{{partial specialization of 'cls<type-parameter-0-0 *>' must be imported}} expected-error 1+{{definition of}}
+ cls<char*> uk4; // expected-error 1+{{partial specialization of 'cls<type-parameter-0-0 *>' must be imported}} expected-error 1+{{definition of}}
+ cls<void>::nested_cls unk1; // expected-error 1+{{explicit specialization of 'nested_cls' must be imported}} expected-error 1+{{definition of}}
+ cls<void>::nested_cls_t<int> unk2; // expected-error 1+{{explicit specialization of 'nested_cls_t' must be imported}} expected-error 1+{{definition of}}
+ cls<void>::nested_cls_t<char> unk3; // expected-error 1+{{explicit specialization of 'nested_cls_t' must be imported}}
+
+ // For enums, uses that would trigger instantiations of definitions are not
+ // allowed.
+ cls<void>::nested_enum e; // ok
+ (void)cls<void>::nested_enum::e; // expected-error 1+{{definition of 'nested_enum' must be imported}} expected-error 1+{{declaration of 'e'}}
+
+ // For variable template specializations, no uses are allowed because
+ // specializations can change the type.
+ (void)sizeof(var<void>); // ok
+ (void)sizeof(var<char>); // ok
+ (void)sizeof(var<int>); // expected-error 1+{{explicit specialization of 'var<int>' must be imported}}
+ (void)sizeof(var<int*>); // expected-error 1+{{partial specialization of 'var<type-parameter-0-0 *>' must be imported}}
+ (void)sizeof(var<char*>); // expected-error 1+{{partial specialization of 'var<type-parameter-0-0 *>' must be imported}}
+ (void)sizeof(cls<void>::nested_var); // ok
+ (void)cls<void>::nested_var; // expected-error 1+{{explicit specialization of 'nested_var' must be imported}}
+ (void)sizeof(cls<void>::nested_var_t<int>); // expected-error 1+{{explicit specialization of 'nested_var_t' must be imported}}
+ (void)sizeof(cls<void>::nested_var_t<char>); // expected-error 1+{{explicit specialization of 'nested_var_t' must be imported}}
+ }
+
+ void cls<int>::nested_fn() {} // expected-error 1+{{explicit specialization of 'cls<int>' must be imported}} expected-error 1+{{definition of}}
+ struct cls<int>::nested_cls {}; // expected-error 1+{{explicit specialization of 'cls<int>' must be imported}} expected-error 1+{{definition of}}
+ int cls<int>::nested_var; // expected-error 1+{{explicit specialization of 'cls<int>' must be imported}} expected-error 1+{{definition of}}
+ enum cls<int>::nested_enum : int {}; // expected-error 1+{{explicit specialization of 'cls<int>' must be imported}} expected-error 1+{{definition of}}
+
+ template<typename T> void cls<T*>::nested_fn() {} // expected-error 1+{{partial specialization of 'cls<type-parameter-0-0 *>' must be imported}}
+ template<typename T> struct cls<T*>::nested_cls {}; // expected-error 1+{{partial specialization of 'cls<type-parameter-0-0 *>' must be imported}}
+ template<typename T> int cls<T*>::nested_var; // expected-error 1+{{partial specialization of 'cls<type-parameter-0-0 *>' must be imported}}
+ template<typename T> enum cls<T*>::nested_enum : int {}; // expected-error 1+{{partial specialization of 'cls<type-parameter-0-0 *>' must be imported}}
+}
+
namespace Std {
void g(); // expected-error {{functions that differ only in their return type cannot be overloaded}}
// expected-note@cxx-templates-common.h:21 {{previous}}
OpenPOWER on IntegriCloud