aboutsummaryrefslogtreecommitdiff
path: root/test/CXX/temp/temp.spec/temp.expl.spec
diff options
context:
space:
mode:
Diffstat (limited to 'test/CXX/temp/temp.spec/temp.expl.spec')
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p1.cpp99
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p10.cpp7
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p11.cpp8
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p13.cpp6
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p14.cpp42
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p15.cpp22
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p16.cpp26
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp12
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p18.cpp20
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p19.cpp30
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp239
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p20.cpp14
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p21.cpp30
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p3.cpp14
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p4.cpp59
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p5.cpp61
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p6.cpp56
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p9.cpp14
18 files changed, 759 insertions, 0 deletions
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p1.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p1.cpp
new file mode 100644
index 000000000000..239b8aeb04e4
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p1.cpp
@@ -0,0 +1,99 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// This test creates cases where implicit instantiations of various entities
+// would cause a diagnostic, but provides expliict specializations for those
+// entities that avoid the diagnostic. The intent is to verify that
+// implicit instantiations do not occur (because the explicit specialization
+// is used instead).
+struct NonDefaultConstructible {
+ NonDefaultConstructible(int);
+};
+
+
+// C++ [temp.expl.spec]p1:
+// An explicit specialization of any of the following:
+
+// -- function template
+template<typename T> void f0(T) {
+ T t;
+}
+
+template<> void f0(NonDefaultConstructible) { }
+
+void test_f0(NonDefaultConstructible NDC) {
+ f0(NDC);
+}
+
+// -- class template
+template<typename T>
+struct X0 {
+ static T member;
+
+ void f1(T t) {
+ t = 17;
+ }
+
+ struct Inner : public T { };
+
+ template<typename U>
+ struct InnerTemplate : public T { };
+
+ template<typename U>
+ void ft1(T t, U u);
+};
+
+template<typename T>
+template<typename U>
+void X0<T>::ft1(T t, U u) {
+ t = u;
+}
+
+template<typename T> T X0<T>::member;
+
+template<> struct X0<void> { };
+X0<void> test_X0;
+
+
+// -- member function of a class template
+template<> void X0<void*>::f1(void *) { }
+
+void test_spec(X0<void*> xvp, void *vp) {
+ xvp.f1(vp);
+}
+
+// -- static data member of a class template
+template<>
+NonDefaultConstructible X0<NonDefaultConstructible>::member = 17;
+
+NonDefaultConstructible &get_static_member() {
+ return X0<NonDefaultConstructible>::member;
+}
+
+// -- member class of a class template
+template<>
+struct X0<void*>::Inner { };
+
+X0<void*>::Inner inner0;
+
+// -- member class template of a class template
+template<>
+template<>
+struct X0<void*>::InnerTemplate<int> { };
+
+X0<void*>::InnerTemplate<int> inner_template0;
+
+// -- member function template of a class template
+template<>
+template<>
+void X0<void*>::ft1(void*, const void*) { }
+
+void test_func_template(X0<void *> xvp, void *vp, const void *cvp) {
+ xvp.ft1(vp, cvp);
+}
+
+// example from the standard:
+template<class T> class stream;
+template<> class stream<char> { /* ... */ };
+template<class T> class Array { /* ... */ };
+template<class T> void sort(Array<T>& v) { /* ... */ }
+template<> void sort<char*>(Array<char*>&) ;
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p10.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p10.cpp
new file mode 100644
index 000000000000..61f1710a6b9e
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p10.cpp
@@ -0,0 +1,7 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<class T> class X;
+template<> class X<int>; // expected-note{{forward}}
+X<int>* p;
+
+X<int> x; // expected-error{{incomplete type}}
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p11.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p11.cpp
new file mode 100644
index 000000000000..e794e67a5ef3
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p11.cpp
@@ -0,0 +1,8 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<class T> class Array { /* ... */ };
+template<class T> void sort(Array<T>& v);
+
+// explicit specialization for sort(Array<int>&)
+// with deduced template-argument of type int
+template<> void sort(Array<int>&);
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p13.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p13.cpp
new file mode 100644
index 000000000000..63cf9f5e50d1
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p13.cpp
@@ -0,0 +1,6 @@
+// RUN: clang-cc -fsyntax-only %s
+
+template<typename T> void f(T);
+
+template<> void f(int) { }
+void f(int) { }
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p14.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p14.cpp
new file mode 100644
index 000000000000..a5d5b9e3c41e
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p14.cpp
@@ -0,0 +1,42 @@
+// RUN: clang-cc -emit-llvm -o - %s | FileCheck %s
+
+template<class T> void f(T) { /* ... */ }
+template<class T> inline void g(T) { /* ... */ }
+
+// CHECK: define void @_Z1gIiEvT_
+template<> void g<>(int) { /* ... */ }
+
+template<class T>
+struct X {
+ void f() { }
+ void g();
+ void h();
+};
+
+template<class T>
+void X<T>::g() {
+}
+
+template<class T>
+inline void X<T>::h() {
+}
+
+// CHECK: define void @_ZN1XIiE1fEv
+template<> void X<int>::f() { }
+
+// CHECK: define void @_ZN1XIiE1hEv
+template<> void X<int>::h() { }
+
+// CHECK: define linkonce_odr void @_Z1fIiEvT_
+template<> inline void f<>(int) { /* ... */ }
+
+// CHECK: define linkonce_odr void @_ZN1XIiE1gEv
+template<> inline void X<int>::g() { }
+
+void test(X<int> xi) {
+ f(17);
+ g(17);
+ xi.f();
+ xi.g();
+ xi.h();
+}
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p15.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p15.cpp
new file mode 100644
index 000000000000..840f566362ed
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p15.cpp
@@ -0,0 +1,22 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+struct NonDefaultConstructible {
+ NonDefaultConstructible(const NonDefaultConstructible&);
+};
+
+template<typename T, typename U>
+struct X {
+ static T member;
+};
+
+template<typename T, typename U>
+T X<T, U>::member; // expected-error{{no matching constructor}}
+
+// Okay; this is a declaration, not a definition.
+template<>
+NonDefaultConstructible X<NonDefaultConstructible, long>::member;
+
+NonDefaultConstructible &test(bool b) {
+ return b? X<NonDefaultConstructible, int>::member // expected-note{{instantiation}}
+ : X<NonDefaultConstructible, long>::member;
+}
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p16.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p16.cpp
new file mode 100644
index 000000000000..ce40afd40225
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p16.cpp
@@ -0,0 +1,26 @@
+// RUN: clang-cc -fsyntax-only %s
+template<class T> struct A {
+ void f(T);
+ template<class X1> void g1(T, X1);
+ template<class X2> void g2(T, X2);
+ void h(T) { }
+};
+
+// specialization
+template<> void A<int>::f(int);
+
+// out of class member template definition
+template<class T> template<class X1> void A<T>::g1(T, X1) { }
+
+// member template specialization
+template<> template<class X1> void A<int>::g1(int, X1);
+
+// member template specialization
+template<> template<>
+ void A<int>::g1(int, char); // X1 deduced as char
+
+template<> template<>
+ void A<int>::g2<char>(int, char); // X2 specified as char
+ // member specialization even if defined in class definition
+
+template<> void A<int>::h(int) { }
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp
new file mode 100644
index 000000000000..883cb71d5686
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp
@@ -0,0 +1,12 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+template<class T1>
+class A {
+ template<class T2> class B {
+ void mf();
+ };
+};
+
+template<> template<> class A<int>::B<double>;
+template<> template<> void A<char>::B<char>::mf();
+
+template<> void A<char>::B<int>::mf(); // expected-error{{requires 'template<>'}}
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p18.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p18.cpp
new file mode 100644
index 000000000000..a5877d281d74
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p18.cpp
@@ -0,0 +1,20 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+template<class T1> class A {
+ template<class T2> class B {
+ template<class T3> void mf1(T3);
+ void mf2();
+ };
+};
+
+template<> template<class X>
+class A<long>::B { };
+
+template<> template<> template<class T>
+ void A<int>::B<double>::mf1(T t) { }
+
+template<> template<> template<class T>
+void A<long>::B<double>::mf1(T t) { } // expected-error{{does not match}}
+
+// FIXME: This diagnostic could probably be better.
+template<class Y> template<>
+ void A<Y>::B<double>::mf2() { } // expected-error{{does not refer}}
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p19.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p19.cpp
new file mode 100644
index 000000000000..1f38e5a2c17d
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p19.cpp
@@ -0,0 +1,30 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T>
+struct X {
+ template<typename U> struct Inner { };
+
+ template<typename U> void f(T, U) { }
+};
+
+template<> template<typename U>
+struct X<int>::Inner {
+ U member;
+};
+
+template<> template<typename U>
+void X<int>::f(int x, U y) {
+ x = y; // expected-error{{incompatible type}}
+}
+
+void test(X<int> xi, X<long> xl, float *fp) {
+ X<int>::Inner<float*> xii;
+ xii.member = fp;
+ xi.f(17, 25);
+ xi.f(17, 3.14159);
+ xi.f(17, fp); // expected-note{{instantiation}}
+ X<long>::Inner<float*> xli;
+
+ xli.member = fp; // expected-error{{no member}}
+ xl.f(17, fp); // okay
+}
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp
new file mode 100644
index 000000000000..64856605a0a7
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp
@@ -0,0 +1,239 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// This test creates cases where implicit instantiations of various entities
+// would cause a diagnostic, but provides expliict specializations for those
+// entities that avoid the diagnostic. The specializations are alternately
+// declarations and definitions, and the intent of this test is to verify
+// that we allow specializations only in the appropriate namespaces (and
+// nowhere else).
+struct NonDefaultConstructible {
+ NonDefaultConstructible(int);
+};
+
+
+// C++ [temp.expl.spec]p1:
+// An explicit specialization of any of the following:
+
+// -- function template
+namespace N0 {
+ template<typename T> void f0(T) { // expected-note{{here}}
+ T t;
+ }
+
+ template<> void f0(NonDefaultConstructible) { }
+
+ void test_f0(NonDefaultConstructible NDC) {
+ f0(NDC);
+ }
+
+ template<> void f0(int);
+ template<> void f0(long);
+}
+
+template<> void N0::f0(int) { } // okay
+
+namespace N1 {
+ template<> void N0::f0(long) { } // expected-error{{not in a namespace enclosing}}
+}
+
+template<> void N0::f0(double) { } // expected-error{{originally be declared}}
+
+struct X1 {
+ template<typename T> void f(T);
+
+ template<> void f(int); // expected-error{{in class scope}}
+};
+
+// -- class template
+namespace N0 {
+
+template<typename T>
+struct X0 { // expected-note 2{{here}}
+ static T member; // expected-note{{here}}
+
+ void f1(T t) { // expected-note{{explicitly specialized declaration is here}}
+ t = 17;
+ }
+
+ struct Inner : public T { }; // expected-note 3{{here}}
+
+ template<typename U>
+ struct InnerTemplate : public T { }; // expected-note 2{{explicitly specialized}} \
+ // expected-error{{base specifier}}
+
+ template<typename U>
+ void ft1(T t, U u); // expected-note{{explicitly specialized}}
+};
+
+}
+
+template<typename T>
+template<typename U>
+void N0::X0<T>::ft1(T t, U u) {
+ t = u;
+}
+
+template<typename T> T N0::X0<T>::member;
+
+template<> struct N0::X0<void> { }; // expected-error{{originally}}
+N0::X0<void> test_X0;
+
+namespace N1 {
+ template<> struct N0::X0<const void> { }; // expected-error{{originally}}
+}
+
+namespace N0 {
+ template<> struct X0<volatile void>;
+}
+
+template<> struct N0::X0<volatile void> {
+ void f1(void *);
+};
+
+// -- member function of a class template
+template<> void N0::X0<void*>::f1(void *) { } // expected-error{{member function specialization}}
+
+void test_spec(N0::X0<void*> xvp, void *vp) {
+ xvp.f1(vp);
+}
+
+namespace N0 {
+ template<> void X0<volatile void>::f1(void *) { } // expected-error{{no function template matches}}
+
+ template<> void X0<const volatile void*>::f1(const volatile void*);
+}
+
+void test_x0_cvvoid(N0::X0<const volatile void*> x0, const volatile void *cvp) {
+ x0.f1(cvp); // okay: we've explicitly specialized
+}
+
+// -- static data member of a class template
+namespace N0 {
+ // This actually tests p15; the following is a declaration, not a definition.
+ template<>
+ NonDefaultConstructible X0<NonDefaultConstructible>::member;
+
+ template<> long X0<long>::member = 17;
+
+ template<> float X0<float>::member;
+
+ template<> double X0<double>::member;
+}
+
+NonDefaultConstructible &get_static_member() {
+ return N0::X0<NonDefaultConstructible>::member;
+}
+
+template<> int N0::X0<int>::member; // expected-error{{originally}}
+
+template<> float N0::X0<float>::member = 3.14f;
+
+namespace N1 {
+ template<> double N0::X0<double>::member = 3.14; // expected-error{{not in a namespace enclosing}}
+}
+
+// -- member class of a class template
+namespace N0 {
+
+ template<>
+ struct X0<void*>::Inner { };
+
+ template<>
+ struct X0<int>::Inner { };
+
+ template<>
+ struct X0<unsigned>::Inner;
+
+ template<>
+ struct X0<float>::Inner;
+
+ template<>
+ struct X0<double>::Inner; // expected-note{{forward declaration}}
+}
+
+template<>
+struct N0::X0<long>::Inner { }; // expected-error{{originally}}
+
+template<>
+struct N0::X0<float>::Inner { };
+
+namespace N1 {
+ template<>
+ struct N0::X0<unsigned>::Inner { }; // expected-error{{member class specialization}}
+
+ template<>
+ struct N0::X0<unsigned long>::Inner { }; // expected-error{{member class specialization}}
+};
+
+N0::X0<void*>::Inner inner0;
+N0::X0<int>::Inner inner1;
+N0::X0<long>::Inner inner2;
+N0::X0<float>::Inner inner3;
+N0::X0<double>::Inner inner4; // expected-error{{incomplete}}
+
+// -- member class template of a class template
+namespace N0 {
+ template<>
+ template<>
+ struct X0<void*>::InnerTemplate<int> { };
+
+ template<> template<>
+ struct X0<int>::InnerTemplate<int>; // expected-note{{forward declaration}}
+
+ template<> template<>
+ struct X0<int>::InnerTemplate<long>;
+
+ template<> template<>
+ struct X0<int>::InnerTemplate<double>;
+}
+
+template<> template<>
+struct N0::X0<int>::InnerTemplate<long> { }; // okay
+
+template<> template<>
+struct N0::X0<int>::InnerTemplate<float> { }; // expected-error{{class template specialization}}
+
+namespace N1 {
+ template<> template<>
+ struct N0::X0<int>::InnerTemplate<double> { }; // expected-error{{enclosing}}
+}
+
+N0::X0<void*>::InnerTemplate<int> inner_template0;
+N0::X0<int>::InnerTemplate<int> inner_template1; // expected-error{{incomplete}}
+N0::X0<int>::InnerTemplate<long> inner_template2;
+N0::X0<int>::InnerTemplate<unsigned long> inner_template3; // expected-note{{instantiation}}
+
+// -- member function template of a class template
+namespace N0 {
+ template<>
+ template<>
+ void X0<void*>::ft1(void*, const void*) { }
+
+ template<> template<>
+ void X0<void*>::ft1(void *, int);
+
+ template<> template<>
+ void X0<void*>::ft1(void *, unsigned);
+
+ template<> template<>
+ void X0<void*>::ft1(void *, long);
+}
+
+template<> template<>
+void N0::X0<void*>::ft1(void *, unsigned) { } // okay
+
+template<> template<>
+void N0::X0<void*>::ft1(void *, float) { } // expected-error{{function template specialization}}
+
+namespace N1 {
+ template<> template<>
+ void N0::X0<void*>::ft1(void *, long) { } // expected-error{{enclosing}}
+}
+
+
+void test_func_template(N0::X0<void *> xvp, void *vp, const void *cvp,
+ int i, unsigned u) {
+ xvp.ft1(vp, cvp);
+ xvp.ft1(vp, i);
+ xvp.ft1(vp, u);
+}
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p20.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p20.cpp
new file mode 100644
index 000000000000..d270b8167a16
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p20.cpp
@@ -0,0 +1,14 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+template<typename T>
+void f(T);
+
+template<typename T>
+struct A { };
+
+struct X {
+ template<> friend void f<int>(int); // expected-error{{in class scope}}
+ template<> friend class A<int>; // expected-error{{cannot be a friend}}
+
+ friend void f<float>(float); // okay
+ friend class A<float>; // okay
+};
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p21.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p21.cpp
new file mode 100644
index 000000000000..9dae3eb5190b
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p21.cpp
@@ -0,0 +1,30 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T>
+struct X {
+ void mf1(T);
+ template<typename U> void mf2(T, U); // expected-note{{previous}}
+};
+
+template<>
+void X<int>::mf1(int i = 17) // expected-error{{default}}
+{
+}
+
+template<> template<>
+void X<int>::mf2(int, int = 17) // expected-error{{default}}
+{ }
+
+template<> template<typename U>
+void X<int>::mf2(int, U = U()) // expected-error{{default}}
+{
+}
+
+template<>
+struct X<float> {
+ void mf1(float);
+};
+
+void X<float>::mf1(float = 3.14f) // okay
+{
+}
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p3.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p3.cpp
new file mode 100644
index 000000000000..2bd1400faefb
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p3.cpp
@@ -0,0 +1,14 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+namespace N {
+ template<class T> class X;
+}
+
+// FIXME: this diagnostic is terrible (PR3844).
+template<> class X<int> { /* ... */ }; // expected-error {{unqualified-id}}
+
+namespace N {
+
+template<> class X<char*> { /* ... */ }; // OK: X is a template
+
+} \ No newline at end of file
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p4.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p4.cpp
new file mode 100644
index 000000000000..8d91068f9b99
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p4.cpp
@@ -0,0 +1,59 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+struct IntHolder { // expected-note{{here}}
+ IntHolder(int);
+};
+
+template<typename T, typename U>
+struct X { // expected-note{{here}}
+ void f() {
+ T t; // expected-error{{no matching}}
+ }
+
+ void g() { }
+
+ struct Inner {
+ T value; // expected-note {{member is declared here}}
+ };
+
+ static T value;
+};
+
+template<typename T, typename U>
+T X<T, U>::value; // expected-error{{no matching constructor}}
+
+IntHolder &test_X_IntHolderInt(X<IntHolder, int> xih) {
+ xih.g(); // okay
+ xih.f(); // expected-note{{instantiation}}
+
+ // FIXME: diagnostic here has incorrect reason (PR5154)
+ X<IntHolder, int>::Inner inner; // expected-error{{implicit default}}
+
+ return X<IntHolder, int>::value; // expected-note{{instantiation}}
+}
+
+// Explicitly specialize the members of X<IntHolder, long> to not cause
+// problems with instantiation.
+template<>
+void X<IntHolder, long>::f() { }
+
+template<>
+struct X<IntHolder, long>::Inner {
+ Inner() : value(17) { }
+ IntHolder value;
+};
+
+template<>
+IntHolder X<IntHolder, long>::value = 17;
+
+IntHolder &test_X_IntHolderInt(X<IntHolder, long> xih) {
+ xih.g(); // okay
+ xih.f(); // okay, uses specialization
+
+ X<IntHolder, long>::Inner inner; // okay, uses specialization
+
+ return X<IntHolder, long>::value; // okay, uses specialization
+}
+
+template<>
+X<IntHolder, long>::X() { } // expected-error{{instantiated member}}
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p5.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p5.cpp
new file mode 100644
index 000000000000..58682c786f95
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p5.cpp
@@ -0,0 +1,61 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+struct IntHolder {
+ IntHolder(int);
+};
+
+template<typename T, typename U>
+struct X {
+ void f() {
+ T t;
+ }
+
+ void g() { }
+
+ struct Inner {
+ T value;
+ };
+
+ static T value;
+};
+
+template<typename T, typename U>
+T X<T, U>::value;
+
+// Explicitly specialize the members of X<IntHolder, long> to not cause
+// problems with instantiation, but only provide declarations (not definitions).
+template<>
+void X<IntHolder, long>::f();
+
+template<>
+struct X<IntHolder, long>::Inner; // expected-note{{forward declaration}}
+
+template<>
+IntHolder X<IntHolder, long>::value;
+
+IntHolder &test_X_IntHolderInt(X<IntHolder, long> xih) {
+ xih.g(); // okay
+ xih.f(); // okay, uses specialization
+
+ X<IntHolder, long>::Inner inner; // expected-error {{incomplete}}
+
+ return X<IntHolder, long>::value; // okay, uses specialization
+}
+
+
+template<class T> struct A {
+ void f(T) { /* ... */ }
+};
+
+template<> struct A<int> {
+ void f(int);
+};
+
+void h() {
+ A<int> a;
+ a.f(16); // A<int>::f must be defined somewhere
+}
+
+// explicit specialization syntax not used for a member of
+// explicitly specialized class template specialization
+void A<int>::f(int) { /* ... */ }
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p6.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p6.cpp
new file mode 100644
index 000000000000..e92d3f0a8883
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p6.cpp
@@ -0,0 +1,56 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T>
+struct X0 {
+ void f();
+
+ template<typename U>
+ void g(U);
+
+ struct Nested {
+ };
+
+ static T member;
+};
+
+int &use_X0_int(X0<int> x0i, // expected-note{{implicit instantiation first required here}}
+ int i) {
+ x0i.f(); // expected-note{{implicit instantiation first required here}}
+ x0i.g(i); // expected-note{{implicit instantiation first required here}}
+ X0<int>::Nested nested; // expected-note{{implicit instantiation first required here}}
+ return X0<int>::member; // expected-note{{implicit instantiation first required here}}
+}
+
+template<>
+void X0<int>::f() { // expected-error{{after instantiation}}
+}
+
+template<> template<>
+void X0<int>::g(int) { // expected-error{{after instantiation}}
+}
+
+template<>
+struct X0<int>::Nested { }; // expected-error{{after instantiation}}
+
+template<>
+int X0<int>::member = 17; // expected-error{{after instantiation}}
+
+template<>
+struct X0<int> { }; // expected-error{{after instantiation}}
+
+// Example from the standard
+template<class T> class Array { /* ... */ };
+
+template<class T> void sort(Array<T>& v) { /* ... */ }
+
+struct String {};
+
+void f(Array<String>& v) {
+
+ sort(v); // expected-note{{required}}
+ // use primary template
+ // sort(Array<T>&), T is String
+}
+
+template<> void sort<String>(Array<String>& v); // // expected-error{{after instantiation}}
+template<> void sort<>(Array<char*>& v); // OK: sort<char*> not yet used
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p9.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p9.cpp
new file mode 100644
index 000000000000..49481d2e6d7a
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p9.cpp
@@ -0,0 +1,14 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+namespace N {
+ template<class T> class X { /* ... */ };
+ template<class T> class Y { /* ... */ };
+ template<> class X<int> { /* ... */ };
+ template<> class Y<double>;
+
+ const unsigned NumElements = 17;
+}
+
+template<> class N::Y<double> {
+ int array[NumElements];
+};