diff options
| author | Richard Smith <richard-llvm@metafoo.co.uk> | 2016-05-05 00:56:12 +0000 |
|---|---|---|
| committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2016-05-05 00:56:12 +0000 |
| commit | 6739a10cec3d5681cc1c0f793be58756dfe0537a (patch) | |
| tree | e2742beb3f5a7c2dd218150a1deeaebee1005f18 /clang/test/Modules | |
| parent | d55bc4c7abeff02a8641918dfa65cac16d9c8818 (diff) | |
| download | bcm5719-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.h | 17 | ||||
| -rw-r--r-- | clang/test/Modules/Inputs/cxx-templates-unimported.h | 43 | ||||
| -rw-r--r-- | clang/test/Modules/Inputs/module.map | 2 | ||||
| -rw-r--r-- | clang/test/Modules/cxx-templates.cpp | 70 |
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}} |

