Started implementing variable templates. Top level declarations should be fully supported, up to some limitations documented as FIXMEs or TODO. Static data member templates work very partially. Static data member templates of class templates need particular attention...
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@187762 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp b/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp
index 2eae112..8a3168e 100644
--- a/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp
+++ b/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp
@@ -23,4 +23,4 @@
return X0<X2>::value; // expected-note{{instantiation}}
}
-template<typename T> T x; // expected-error{{variable 'x' declared as a template}}
+template<typename T> T x; // expected-warning{{variable templates are a C++1y extension}}
diff --git a/test/CXX/temp/temp.spec/cxx1y-variable-template-no-body.cpp b/test/CXX/temp/temp.spec/cxx1y-variable-template-no-body.cpp
new file mode 100644
index 0000000..4cff1e2
--- /dev/null
+++ b/test/CXX/temp/temp.spec/cxx1y-variable-template-no-body.cpp
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 --std=c++1y -fsyntax-only -verify %s
+// RUN: cp %s %t
+// RUN: not %clang_cc1 --std=c++1y -x c++ -fixit %t -DFIXING
+// RUN: %clang_cc1 --std=c++1y -x c++ %t -DFIXING
+
+template<typename T>
+T pi = T(3.1415926535897932385); // expected-note {{template is declared here}}
+
+template int pi<int>;
+
+#ifndef FIXING
+template float pi; // expected-error {{too few template arguments for template 'pi'}}
+template double pi_var0; // expected-error {{explicit instantiation of 'pi_var0' does not refer to a function template, variable template, member function, member class, or static data member}}
+#endif
+
+// Should recover as if definition
+template double pi_var = 5; // expected-error {{variable cannot be defined in an explicit instantiation; if this declaration is meant to be a variable definition, remove the 'template' keyword}}
+#ifndef FIXING
+template<typename T>
+T pi0 = T(3.1415926535897932385); // expected-note {{previous definition is here}}
+
+template int pi0 = 10; // expected-error {{variable cannot be defined in an explicit instantiation; if this declaration is meant to be a variable definition, remove the 'template' keyword}} \
+ expected-error{{redefinition of 'pi0' with a different type: 'int' vs 'T'}}
+#endif
+
+template<typename T>
+T pi1 = T(3.1415926535897932385);
+
+// Should recover as if specialization
+template float pi1<float> = 1.0; // expected-error {{explicit template instantiation cannot have a definition; if this definition is meant to be an explicit specialization, add '<>' after the 'template' keyword}}
+#ifndef FIXING
+namespace expected_global {
+ template<> double pi1<double> = 1.5; // expected-error {{no variable template matches specialization}}
+ template int pi1<int> = 10; // expected-error {{explicit template instantiation cannot have a definition; if this definition is meant to be an explicit specialization, add '<>' after the 'template' keyword}} \
+ expected-error {{no variable template matches specialization}}
+}
+#endif
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp
index aecbfb5..3844ec9 100644
--- a/test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp
@@ -163,7 +163,8 @@
template<> struct X<1>::Y { static const int Z = 1; };
const int X<0>::Y::Z;
- template<> const int X<1>::Y::Z; // expected-error{{extraneous 'template<>' in declaration of variable 'Z'}}
+ template<> const int X<1>::Y::Z; // expected-error{{extraneous 'template<>' in declaration of variable 'Z'}} \
+ // expected-error{{forward declaration of variable template cannot have a nested name specifier}}
}
namespace PR9913 {
diff --git a/test/SemaCXX/conversion-function.cpp b/test/SemaCXX/conversion-function.cpp
index 0e7c391..7eaed54 100644
--- a/test/SemaCXX/conversion-function.cpp
+++ b/test/SemaCXX/conversion-function.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
class X {
public:
operator bool();
diff --git a/test/SemaCXX/cxx1y-variable-templates_in_class.cpp b/test/SemaCXX/cxx1y-variable-templates_in_class.cpp
new file mode 100644
index 0000000..7f2823c
--- /dev/null
+++ b/test/SemaCXX/cxx1y-variable-templates_in_class.cpp
@@ -0,0 +1,159 @@
+// RUN: %clang_cc1 -verify -fsyntax-only %s -Wno-c++11-extensions -Wno-c++1y-extensions -DPRECXX11
+// RUN: %clang_cc1 -std=c++11 -verify -fsyntax-only -Wno-c++1y-extensions %s
+// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only %s
+
+class A {
+ template<typename T> const T wrong; // expected-error {{member 'wrong' declared as a template}}
+ template<typename T> const T wrong_init = 5; // expected-error {{member 'wrong_init' declared as a template}}
+ template<typename T, typename T0> static const T right = T(100);
+ template<typename T> static const T right<T,int> = 5;
+ template<typename T> const int right<int,T>; // expected-error {{member 'right' declared as a template}}
+ template<typename T> const float right<float,T> = 5; // expected-error {{member 'right' declared as a template}}
+ template<> static const int right<int,int> = 7; // expected-error {{explicit specialization of 'right' in class scope}}
+ template<> static const float right<float,int>; // expected-error {{explicit specialization of 'right' in class scope}}
+ template static const int right<int,int>; // expected-error {{template specialization requires 'template<>'}} \
+ // expected-error {{explicit specialization of 'right' in class scope}}
+};
+
+namespace out_of_line {
+ class B0 {
+ template<typename T, typename T0> static const T right = T(100);
+ template<typename T> static const T right<T,int> = T(5);
+ };
+ template<> const int B0::right<int,int> = 7;
+ template const int B0::right<int,int>;
+ template<> const int B0::right<int,float>;
+ template const int B0::right<int,float>;
+
+ class B1 {
+ template<typename T, typename T0> static const T right;
+ template<typename T> static const T right<T,int>;
+ };
+ template<typename T, typename T0> const T B1::right = T(100);
+ template<typename T> const T B1::right<T,int> = T(5);
+
+ class B2 {
+ template<typename T, typename T0> static const T right = T(100); // expected-note {{previous definition is here}}
+ template<typename T> static const T right<T,int> = T(5); // expected-note {{previous definition is here}}
+ };
+ template<typename T, typename T0> const T B2::right = T(100); // expected-error {{redefinition of 'right'}}
+ template<typename T> const T B2::right<T,int> = T(5); // expected-error {{redefinition of 'right'}}
+
+ class B3 {
+ template<typename T, typename T0> static const T right = T(100);
+ template<typename T> static const T right<T,int> = T(5);
+ };
+ template<typename T, typename T0> const T B3::right; // expected-error {{forward declaration of variable template cannot have a nested name specifier}}
+ template<typename T> const T B3::right<T,int>; // expected-error {{forward declaration of variable template partial specialization cannot have a nested name specifier}}
+
+ class B4 {
+ template<typename T, typename T0> static const T right;
+ template<typename T> static const T right<T,int>;
+ template<typename T, typename T0> static const T right_def = T(100);
+ template<typename T> static const T right_def<T,int>; // expected-note {{explicit instantiation refers here}}
+ };
+ template<typename T, typename T0> const T B4::right; // expected-error {{forward declaration of variable template cannot have a nested name specifier}}
+ template<typename T> const T B4::right<T,int>; // expected-error {{forward declaration of variable template partial specialization cannot have a nested name specifier}} \
+ // expected-note {{explicit instantiation refers here}}
+ template const int B4::right<int,int>; // expected-error {{explicit instantiation of undefined static data member template 'right' of class}}
+ template const int B4::right_def<int,int>; // expected-error {{explicit instantiation of undefined static data member template 'right_def' of class}}
+}
+
+namespace non_const_init {
+ class A {
+ template<typename T> static T wrong_inst = T(10); // expected-error {{non-const static data member must be initialized out of line}}
+ template<typename T> static T wrong_inst_fixed;
+ };
+ template int A::wrong_inst<int>; // expected-note {{in instantiation of static data member 'non_const_init::A::wrong_inst<int>' requested here}}
+ template<typename T> T A::wrong_inst_fixed = T(10);
+ template int A::wrong_inst_fixed<int>;
+
+ class B {
+ template<typename T> static T wrong_inst;
+ template<typename T> static T wrong_inst<T*> = T(100); // expected-error {{non-const static data member must be initialized out of line}}
+
+ template<typename T> static T wrong_inst_fixed;
+ template<typename T> static T wrong_inst_fixed<T*>;
+ };
+ template int B::wrong_inst<int*>; // expected-note {{in instantiation of static data member 'non_const_init::B::wrong_inst<int *>' requested here}}
+ template<typename T> T B::wrong_inst_fixed = T(100);
+ template int B::wrong_inst_fixed<int>;
+
+ class C {
+ template<typename T> static const T right_inst = T(10);
+ template<typename T> static const T right_inst<T*> = T(100);
+ };
+ template const int C::right_inst<int>;
+ template const int C::right_inst<int*>;
+
+ namespace pointers {
+
+ struct C0 {
+ template<typename U> static U Data;
+ template<typename U> static const U Data<U*> = U(); // Okay
+ };
+ template const int C0::Data<int*>;
+
+ struct C1a {
+ template<typename U> static U Data;
+ template<typename U> static U* Data<U>; // Okay, with out-of-line definition
+ };
+ template<typename T> T* C1a::Data<T> = new T();
+ template int* C1a::Data<int>;
+
+ struct C1b {
+ template<typename U> static U Data;
+ template<typename U> static const U* Data<U>; // Okay, with out-of-line definition
+ };
+ template<typename T> const T* C1b::Data<T> = (T*)(0);
+ template const int* C1b::Data<int>;
+
+ struct C2a {
+ template<typename U> static U Data;
+ template<typename U> static U* Data<U> = new U(); // expected-error {{non-const static data member must be initialized out of line}}
+ };
+ template int* C2a::Data<int>; // expected-note {{in instantiation of static data member 'non_const_init::pointers::C2a::Data<int>' requested here}}
+
+ struct C2b { // FIXME: ?!? Should this be an error? pointer-types are automatically non-const?
+ template<typename U> static U Data;
+ template<typename U> static const U* Data<U> = (U*)(0); // expected-error {{non-const static data member must be initialized out of line}}
+ };
+ template const int* C2b::Data<int>; // expected-note {{in instantiation of static data member 'non_const_init::pointers::C2b::Data<int>' requested here}}
+ }
+}
+
+struct matrix_constants {
+ // TODO: (?)
+};
+
+namespace in_class_template {
+ // FIXME: member data templates of class templates are not well supported yet.
+
+ template<typename T>
+ class D0 {
+ template<typename U> static U Data;
+ template<typename U> static const U Data<U*> = U();
+ };
+
+ template<typename T>
+ class D1 {
+ template<typename U> static U Data;
+ template<typename U> static U* Data<U*>;
+ };
+ template<typename T>
+ template<typename U> U* D1<T>::Data<U*> = (U*)(0);
+
+ namespace to_be_fixed {
+ // FIXME: The following generate runtime exceptions!
+
+ //template<>
+ //template<typename U> U* D1<float>::Data<U*> = (U*)(0) + 1;
+ //template const int D0<float>::Data<int*>;
+ //template int* D1<float>::Data<int*>;
+ }
+}
+
+namespace in_nested_classes {
+ // TODO:
+}
+
diff --git a/test/SemaCXX/cxx1y-variable-templates_top_level.cpp b/test/SemaCXX/cxx1y-variable-templates_top_level.cpp
new file mode 100644
index 0000000..66ee4e1
--- /dev/null
+++ b/test/SemaCXX/cxx1y-variable-templates_top_level.cpp
@@ -0,0 +1,415 @@
+// RUN: %clang_cc1 -verify -fsyntax-only -Wno-c++11-extensions -Wno-c++1y-extensions %s
+// RUN: %clang_cc1 -std=c++11 -verify -fsyntax-only -Wno-c++1y-extensions %s -DCXX11
+// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only %s -DCXX11
+
+#ifdef CXX11
+ #define CONST constexpr
+#else
+ #define CONST const
+#endif
+
+template<typename T>
+T pi = T(3.1415926535897932385); // expected-note {{template is declared here}}
+
+template<typename T>
+CONST T cpi = T(3.1415926535897932385); // expected-note {{template is declared here}}
+
+namespace use_in_top_level_funcs {
+
+ void good() {
+ int ipi = pi<int>;
+ int icpi = cpi<int>;
+ double dpi = pi<double>;
+ double dcpi = cpi<double>;
+ }
+
+ void no_deduce() {
+ // template arguments are not deduced for uses of variable templates.
+ int ipi = pi; // expected-error {{cannot refer to variable template 'pi' without a template argument list}}
+ int icpi = cpi; // expected-error {{cannot refer to variable template 'cpi' without a template argument list}}
+ }
+
+ template<typename T>
+ T circular_area(T r) {
+ return pi<T> * r * r;
+ }
+
+ template<typename T>
+ CONST T const_circular_area(T r) {
+ return cpi<T> * r * r;
+ }
+
+ double use_circular_area(double r) {
+ CONST float t = const_circular_area(2.0) - 12;
+#ifdef CXX11
+ static_assert(const_circular_area(2) == 12, "");
+ CONST int test = (t > 0) && (t < 1);
+ static_assert(test, "");
+#endif
+ return circular_area(r);
+ }
+}
+
+namespace shadow {
+ void foo() {
+ int ipi0 = pi<int>;
+ int pi;
+ int a = pi;
+ int ipi = pi<int>; // expected-error {{expected '(' for function-style cast or type construction}} \
+ // expected-error {{expected expression}}
+ }
+}
+
+namespace odr_tmpl {
+ namespace pv_cvt {
+ int v; // expected-note {{previous definition is here}}
+ template<typename T> T v; // expected-error {{redefinition of 'v' as different kind of symbol}}
+ }
+ namespace pvt_cv {
+ template<typename T> T v; // expected-note {{previous definition is here}}
+ int v; // expected-error {{redefinition of 'v' with a different type: 'int' vs 'T'}}
+ }
+ namespace pvt_cvt {
+ template<typename T> T v0; // expected-note {{previous definition is here}}
+ template<typename T> T v0; // expected-error {{redefinition of 'v0'}}
+
+ template<typename T> T v; // expected-note {{previous definition is here}}
+ template<typename T> int v; // expected-error {{redefinition of 'v'}}
+
+ template<typename T> int v1; // expected-note {{previous template declaration is here}}
+ template<int I> int v1; // expected-error {{template parameter has a different kind in template redeclaration}}
+ }
+ namespace pvt_use {
+ template<typename T> T v;
+ v = 10; // expected-error {{C++ requires a type specifier for all declarations}}
+ }
+
+ namespace pvt_diff_params {
+ // FIXME: (?) Redefinitions should simply be not allowed, whether the
+ // template parameters match or not. However, this current behaviour also
+ // matches that of class templates...
+ template<typename T, typename> T v; // expected-note 2{{previous template declaration is here}}
+ template<typename T> T v; // expected-error {{too few template parameters in template redeclaration}}
+ template<typename T, typename, typename> T v; // expected-error {{too many template parameters in template redeclaration}}
+ }
+
+ namespace pvt_extern {
+ template<typename T> T v = T();
+ template<typename T> extern T v; // redeclaration is allowed \
+ // expected-note {{previous definition is here}}
+ template<typename T> extern int v; // expected-error {{redefinition of 'v' with a different type: 'int' vs 'T'}}
+
+#ifdef CXX11
+ template<typename T> extern auto v; // expected-error {{declaration of variable 'v' with type 'auto' requires an initializer}}
+#endif
+ }
+
+#ifdef CXX11
+ namespace pvt_auto {
+ template<typename T> auto v0; // expected-error {{declaration of variable 'v0' with type 'auto' requires an initializer}}
+ template<typename T> auto v1 = T(); // expected-note {{previous definition is here}}
+ template<typename T> int v1; // expected-error {{redefinition of 'v1' with a different type: 'int' vs 'auto'}}
+ template<typename T> auto v2 = T(); // expected-note {{previous definition is here}}
+ template<typename T> T v2; // expected-error {{redefinition of 'v2'}}
+ template<typename T> auto v3 = T(); // expected-note {{previous definition is here}}
+ template<typename T> extern T v3; // expected-error {{redefinition of 'v3' with a different type: 'T' vs 'auto'}}
+ template<typename T> auto v4 = T();
+ template<typename T> extern auto v4; // expected-error {{declaration of variable 'v4' with type 'auto' requires an initializer}}
+ }
+#endif
+
+}
+
+namespace explicit_instantiation {
+ template<typename T>
+ T pi0a = T(3.1415926535897932385); // expected-note {{variable template 'pi0a' declared here}}
+ template float pi0a<int>; // expected-error {{type 'float' of explicit instantiation of 'pi0a' does not match expected type 'int'}}
+
+ template<typename T>
+ T pi0b = T(3.1415926535897932385); // expected-note {{variable template 'pi0b' declared here}}
+ template CONST int pi0b<int>; // expected-error {{type 'const int' of explicit instantiation of 'pi0b' does not match expected type 'int'}}
+
+ template<typename T>
+ T pi0c = T(3.1415926535897932385); // expected-note {{variable template 'pi0c' declared here}}
+ template int pi0c<const int>; // expected-error {{type 'int' of explicit instantiation of 'pi0c' does not match expected type 'const int'}}
+
+ template<typename T>
+ T pi0 = T(3.1415926535897932385);
+ template int pi0<int>; // expected-note {{previous explicit instantiation is here}}
+ template int pi0<int>; // expected-error {{duplicate explicit instantiation of 'pi0<int>'}}
+
+ template<typename T>
+ CONST T pi1a = T(3.1415926535897932385); // expected-note {{variable template 'pi1a' declared here}}
+ template int pi1a<int>; // expected-error {{type 'int' of explicit instantiation of 'pi1a' does not match expected type 'const int'}}
+
+ template<typename T>
+ CONST T pi1b = T(3.1415926535897932385); // expected-note {{variable template 'pi1b' declared here}}
+ template int pi1b<const int>; // expected-error {{type 'int' of explicit instantiation of 'pi1b' does not match expected type 'const const int'}}
+
+ template<typename T>
+ CONST T pi1 = T(3.1415926535897932385);
+ template CONST int pi1<int>; // expected-note {{previous explicit instantiation is here}}
+ template CONST int pi1<int>; // expected-error {{duplicate explicit instantiation of 'pi1<int>'}}
+
+#ifdef CXX11
+ namespace auto_var {
+ template<typename T> auto var0 = T();
+ template auto var0<int>; // expected-error {{'auto' variable template instantiation is not allowed}}
+
+ template<typename T> auto var = T();
+ template int var<int>;
+ }
+#endif
+
+ namespace extern_var {
+ // TODO:
+ }
+}
+
+namespace explicit_specialization {
+
+ namespace good {
+ template<typename T1, typename T2>
+ CONST int pi2 = 1;
+
+ template<typename T>
+ CONST int pi2<T,int> = 2;
+
+ template<typename T>
+ CONST int pi2<int,T> = 3;
+
+ template<> CONST int pi2<int,int> = 4;
+
+#ifdef CXX11
+ void foo() {
+ static_assert(pi2<int,int> == 4, "");
+ static_assert(pi2<float,int> == 2, "");
+ static_assert(pi2<int,float> == 3, "");
+ static_assert(pi2<int,float> == pi2<int,double>, "");
+ static_assert(pi2<float,float> == 1, "");
+ static_assert(pi2<float,float> == pi2<float,double>, "");
+ }
+#endif
+ }
+
+ namespace ambiguous {
+
+ template<typename T1, typename T2>
+ CONST int pi2 = 1;
+
+ template<typename T>
+ CONST int pi2<T,int> = 2; // expected-note {{partial specialization matches [with T = int]}}
+
+ template<typename T>
+ CONST int pi2<int,T> = 3; // expected-note {{partial specialization matches [with T = int]}}
+
+ void foo() {
+ int a = pi2<int,int>; // expected-error {{ambiguous partial specializations of 'pi2<int, int>'}}
+ }
+ }
+
+ namespace type_changes {
+
+ template<typename T>
+ T pi0 = T(3.1415926535897932385);
+
+ template<> float pi0<int> = 10;
+ template<> int pi0<const int> = 10;
+
+ template<typename T>
+ T pi1 = T(3.1415926535897932385);
+ template<> CONST int pi1<int> = 10;
+
+ template<typename T>
+ T pi2 = T(3.1415926535897932385);
+ template<> int pi2<const int> = 10;
+
+ template<typename T>
+ CONST T pi4 = T(3.1415926535897932385);
+ template<> int pi4<int> = 10;
+ }
+
+ namespace redefinition {
+ template<typename T>
+ T pi0 = T(3.1415926535897932385);
+
+ template<> int pi0<int> = 10; // expected-note 3{{previous definition is here}}
+#ifdef CXX11
+// expected-note@-2 {{previous definition is here}}
+#endif
+ template<> int pi0<int> = 10; // expected-error {{redefinition of 'pi0<int>'}}
+ template<> CONST int pi0<int> = 10; // expected-error {{redefinition of 'pi0' with a different type: 'const int' vs 'int'}}
+ template<> float pi0<int> = 10; // expected-error {{redefinition of 'pi0' with a different type: 'float' vs 'int'}}
+#ifdef CXX11
+ template<> auto pi0<int> = 10; // expected-error {{redefinition of 'pi0<int>'}}
+#endif
+
+
+ template<typename T>
+ CONST T pi1 = T(3.1415926535897932385);
+
+ template<> CONST int pi1<int> = 10; // expected-note {{previous definition is here}}
+ template<> CONST int pi1<int> = 10; // expected-error {{redefinition of 'pi1<int>'}}
+ }
+
+ namespace before_instantiation {
+ template<typename T>
+ T pi0 = T(3.1415926535897932385); // expected-note {{variable template 'pi0' declared here}}
+
+ template<> int pi0<int> = 10;
+ template int pi0<int>;
+ template float pi0<int>; // expected-error {{type 'float' of explicit instantiation of 'pi0' does not match expected type}}
+
+ template<typename T1, typename T2>
+ CONST int pi2 = 1;
+
+ template<typename T> CONST int pi2<T,int> = 2;
+ template CONST int pi2<int,int>;
+ }
+ namespace after_instantiation {
+ template<typename T>
+ T pi0 = T(3.1415926535897932385);
+
+ template int pi0<int>; // expected-note 2{{explicit instantiation first required here}}
+ template<> int pi0<int> = 10; // expected-error {{explicit specialization of 'pi0' after instantiation}}
+ template<> float pi0<int>; // expected-error {{explicit specialization of 'pi0' after instantiation}}
+
+ template<typename T1, typename T2>
+ CONST int pi2 = 1;
+
+ template CONST int pi2<int,int>;
+ template<typename T> CONST int pi2<T,int> = 2;
+ }
+
+#ifdef CXX11
+ namespace auto_var {
+ template<typename T, typename> auto var0 = T();
+ template<typename T> auto var0<T,int> = T();
+ template<> auto var0<int,int> = 7;
+
+ template<typename T, typename> auto var = T();
+ template<typename T> T var<T,int> = T(5);
+ template<> int var<int,int> = 7;
+
+ void foo() {
+ int i0 = var0<int,int>;
+ int b = var<int,int>;
+ }
+ }
+#endif
+
+ namespace extern_var {
+ // TODO:
+ }
+
+ namespace diff_type {
+ // TODO:
+ template<typename T> T var = T();
+ template<typename T> T* var<T> = new T();
+#ifdef CXX11
+ template<typename T> auto var<T*> = T(); // expected-note {{previous definition is here}}
+ template<typename T> T var<T*> = T(); // expected-error {{redefinition of 'var' with a different type: 'T' vs 'auto'}}
+#endif
+ }
+}
+
+namespace use_in_structs {
+ // TODO:
+}
+
+namespace attributes {
+ // TODO:
+}
+
+#ifdef CXX11
+namespace arrays {
+ template<typename T>
+ T* arr = new T[10]{T(10), T(23)};
+
+ float f = 10.5;
+ template<> float* arr<float> = &f;
+
+ void bar() {
+ int *iarr = arr<int>;
+ iarr[0] = 1;
+ iarr[2] = 3;
+ iarr[6] = -2;
+
+ float ff = *arr<float>;
+ float nof = arr<float>[3]; // No bounds-check in C++
+ }
+}
+#endif
+
+namespace nested {
+
+ namespace n0a {
+ template<typename T>
+ T pi0a = T(3.1415926535897932385);
+ }
+
+ using namespace n0a;
+ int i0a = pi0a<int>;
+
+ template float pi0a<float>;
+ float f0a = pi0a<float>;
+
+ template<> double pi0a<double> = 5.2;
+ double d0a = pi0a<double>;
+
+ namespace n0b {
+ template<typename T>
+ T pi0b = T(3.1415926535897932385);
+ }
+
+ int i0b = n0b::pi0b<int>;
+
+ template float n0b::pi0b<float>;
+ float f0b = n0b::pi0b<float>;
+
+ template<> double n0b::pi0b<double> = 5.2;
+ double d0b = n0b::pi0b<double>;
+
+ namespace n1 {
+ template<typename T>
+ T pi1a = T(3.1415926535897932385);
+#ifdef CXX11
+// expected-note@-2 {{explicit instantiation refers here}}
+#endif
+
+ template<typename T>
+ T pi1b = T(3.1415926535897932385); // expected-note {{explicitly specialized declaration is here}}
+#ifdef CXX11
+// expected-note@-2 {{explicit instantiation refers here}}
+#endif
+ }
+
+ namespace use_n1a {
+ using namespace n1;
+ int i1 = pi1a<int>;
+
+ template float pi1a<float>;
+#ifdef CXX11
+// expected-error@-2 {{explicit instantiation of 'pi1a<float>' not in a namespace enclosing 'n1'}}
+#endif
+ float f1 = pi1a<float>;
+
+ template<> double pi1a<double> = 5.2; // expected-error {{no variable template matches specialization}}
+ double d1 = pi1a<double>;
+ }
+
+ namespace use_n1b {
+ int i1 = n1::pi1b<int>;
+
+ template float n1::pi1b<float>;
+#ifdef CXX11
+// expected-error@-2 {{explicit instantiation of 'pi1b<float>' not in a namespace enclosing 'n1'}}
+#endif
+ float f1 = n1::pi1b<float>;
+
+ template<> double n1::pi1b<double> = 5.2; // expected-error {{cannot define or redeclare 'pi1b' here because namespace 'use_n1b' does not enclose namespace 'n1'}} \
+ // expected-error {{variable template specialization of 'pi1b' must originally be declared in namespace 'n1'}}
+ double d1 = n1::pi1b<double>;
+ }
+}
+
diff --git a/test/SemaCXX/cxx98-compat.cpp b/test/SemaCXX/cxx98-compat.cpp
index 7ab92f0..eeef136 100644
--- a/test/SemaCXX/cxx98-compat.cpp
+++ b/test/SemaCXX/cxx98-compat.cpp
@@ -1,5 +1,8 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat -verify %s
// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++1y -Wc++98-c++11-compat -verify %s -DCXX1YCOMPAT
+
+#ifndef CXX1YCOMPAT
namespace std {
struct type_info;
@@ -378,3 +381,77 @@
X x; // expected-warning{{union member 'x' with a non-trivial constructor is incompatible with C++98}}
};
}
+#endif
+
+template<typename T> T var = T(10);
+#ifdef CXX1YCOMPAT
+// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++1y}}
+#else
+// expected-warning@-4 {{variable templates are a C++1y extension}}
+#endif
+
+template<typename T> T* var<T*> = new T();
+#ifdef CXX1YCOMPAT
+// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++1y}}
+#else
+// expected-warning@-4 {{variable templates are a C++1y extension}}
+#endif
+
+template<> int var<int> = 10;
+#ifdef CXX1YCOMPAT
+// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++1y}}
+#else
+// expected-warning@-4 {{variable templates are a C++1y extension}}
+#endif
+
+template int var<int>;
+float fvar = var<float>;
+
+class A {
+ template<typename T> static T var = T(10);
+#ifdef CXX1YCOMPAT
+// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++1y}}
+#else
+// expected-warning@-4 {{variable templates are a C++1y extension}}
+#endif
+
+ template<typename T> static T* var<T*> = new T();
+#ifdef CXX1YCOMPAT
+// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++1y}}
+#else
+// expected-warning@-4 {{variable templates are a C++1y extension}}
+#endif
+
+};
+
+struct B { template<typename T> static T v; };
+#ifdef CXX1YCOMPAT
+// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++1y}}
+#else
+// expected-warning@-4 {{variable templates are a C++1y extension}}
+#endif
+
+template<typename T> T B::v = T();
+#ifdef CXX1YCOMPAT
+// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++1y}}
+#else
+// expected-warning@-4 {{variable templates are a C++1y extension}}
+#endif
+
+template<typename T> T* B::v<T*> = new T();
+#ifdef CXX1YCOMPAT
+// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++1y}}
+#else
+// expected-warning@-4 {{variable templates are a C++1y extension}}
+#endif
+
+template<> int B::v<int> = 10;
+#ifdef CXX1YCOMPAT
+// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++1y}}
+#else
+// expected-warning@-4 {{variable templates are a C++1y extension}}
+#endif
+
+template int B::v<int>;
+float fsvar = B::v<float>;
+
diff --git a/test/SemaCXX/for-range-examples.cpp b/test/SemaCXX/for-range-examples.cpp
index 953c98b..ca505e0 100644
--- a/test/SemaCXX/for-range-examples.cpp
+++ b/test/SemaCXX/for-range-examples.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
namespace value_range_detail {
template<typename T>
diff --git a/test/SemaCXX/unknown-type-name.cpp b/test/SemaCXX/unknown-type-name.cpp
index ce5972b..f2c84df 100644
--- a/test/SemaCXX/unknown-type-name.cpp
+++ b/test/SemaCXX/unknown-type-name.cpp
@@ -93,14 +93,14 @@
template<typename T> int h(T::type, int); // expected-error{{missing 'typename'}}
template<typename T> int h(T::type x, char); // expected-error{{missing 'typename'}}
-template<typename T> int junk1(T::junk); // expected-error{{declared as a template}}
+template<typename T> int junk1(T::junk); // expected-warning{{variable templates are a C++1y extension}}
template<typename T> int junk2(T::junk) throw(); // expected-error{{missing 'typename'}}
template<typename T> int junk3(T::junk) = delete; // expected-error{{missing 'typename'}} expected-warning{{C++11}}
template<typename T> int junk4(T::junk j); // expected-error{{missing 'typename'}}
// FIXME: We can tell this was intended to be a function because it does not
// have a dependent nested name specifier.
-template<typename T> int i(T::type, int()); // expected-error{{variable 'i' declared as a template}}
+template<typename T> int i(T::type, int()); // expected-warning{{variable templates are a C++1y extension}}
// FIXME: We know which type specifier should have been specified here. Provide
// a fix-it to add 'typename A<T>::type'
diff --git a/test/SemaTemplate/class-template-decl.cpp b/test/SemaTemplate/class-template-decl.cpp
index fe23d92..e65da2b 100644
--- a/test/SemaTemplate/class-template-decl.cpp
+++ b/test/SemaTemplate/class-template-decl.cpp
@@ -50,7 +50,9 @@
template<typename T> class X; // expected-error{{expression}}
}
-template<typename T> class X1 var; // expected-error{{declared as a template}}
+template<typename T> class X1 var; // expected-warning{{variable templates are a C++1y extension}} \
+ // expected-error {{variable has incomplete type 'class X1'}} \
+ // expected-note {{forward declaration of 'X1'}}
namespace M {
}