aboutsummaryrefslogtreecommitdiff
path: root/test/CXX/temp
diff options
context:
space:
mode:
Diffstat (limited to 'test/CXX/temp')
-rw-r--r--test/CXX/temp/temp.decls/temp.class.spec/p6.cpp20
-rw-r--r--test/CXX/temp/temp.decls/temp.class.spec/temp.class.order/p2.cpp16
-rw-r--r--test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1-neg.cpp25
-rw-r--r--test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1.cpp26
-rw-r--r--test/CXX/temp/temp.decls/temp.class/temp.mem.class/p1.cpp27
-rw-r--r--test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1-retmem.cpp28
-rw-r--r--test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1.cpp68
-rw-r--r--test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1inst.cpp17
-rw-r--r--test/CXX/temp/temp.decls/temp.class/temp.mem.func/pr5056.cpp17
-rw-r--r--test/CXX/temp/temp.decls/temp.class/temp.static/p1-inst.cpp28
-rw-r--r--test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp26
-rw-r--r--test/CXX/temp/temp.decls/temp.fct/temp.func.order/p4.cpp23
-rw-r--r--test/CXX/temp/temp.decls/temp.fct/temp.func.order/p5.cpp12
-rw-r--r--test/CXX/temp/temp.decls/temp.fct/temp.over.link/p4-neg.cpp6
-rw-r--r--test/CXX/temp/temp.decls/temp.fct/temp.over.link/p6.cpp16
-rw-r--r--test/CXX/temp/temp.decls/temp.friend/p1.cpp56
-rw-r--r--test/CXX/temp/temp.decls/temp.friend/p3.cpp13
-rw-r--r--test/CXX/temp/temp.decls/temp.friend/p5.cpp11
-rw-r--r--test/CXX/temp/temp.decls/temp.mem/p1.cpp16
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3.cpp2
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp32
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p2.cpp36
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p3.cpp30
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p4.cpp44
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.funcaddr/p1.cpp22
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.partial/p11.cpp22
-rw-r--r--test/CXX/temp/temp.param/p1.cpp3
-rw-r--r--test/CXX/temp/temp.res/temp.dep/p3.cpp43
-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
46 files changed, 1438 insertions, 6 deletions
diff --git a/test/CXX/temp/temp.decls/temp.class.spec/p6.cpp b/test/CXX/temp/temp.decls/temp.class.spec/p6.cpp
new file mode 100644
index 000000000000..afe6ab2b968e
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.class.spec/p6.cpp
@@ -0,0 +1,20 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T>
+struct X0 {
+ template<typename U> struct Inner0 {
+ static const unsigned value = 0;
+ };
+
+ template<typename U> struct Inner0<U*> {
+ static const unsigned value = 1;
+ };
+};
+
+template<typename T> template<typename U>
+struct X0<T>::Inner0<const U*> {
+ static const unsigned value = 2;
+};
+
+// FIXME: Test instantiation of these partial specializations (once they are
+// implemented).
diff --git a/test/CXX/temp/temp.decls/temp.class.spec/temp.class.order/p2.cpp b/test/CXX/temp/temp.decls/temp.class.spec/temp.class.order/p2.cpp
new file mode 100644
index 000000000000..b3b7635106c5
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.class.spec/temp.class.order/p2.cpp
@@ -0,0 +1,16 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+template<int I, int J, class T> class X {
+ static const int value = 0;
+};
+
+template<int I, int J> class X<I, J, int> {
+ static const int value = 1;
+};
+
+template<int I> class X<I, I, int> {
+ static const int value = 2;
+};
+
+int array0[X<0, 0, float>::value == 0? 1 : -1];
+int array1[X<0, 1, int>::value == 1? 1 : -1];
+int array2[X<0, 0, int>::value == 2? 1 : -1];
diff --git a/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1-neg.cpp b/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1-neg.cpp
new file mode 100644
index 000000000000..47cf8379c319
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1-neg.cpp
@@ -0,0 +1,25 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T, int N>
+struct A;
+
+template<typename T> // expected-note{{previous template declaration}}
+struct A<T*, 2> {
+ void f0();
+ void f1();
+ void f2();
+};
+
+template<>
+struct A<int, 1> {
+ void g0();
+};
+
+// FIXME: We should probably give more precise diagnostics here, but the
+// diagnostics we give aren't terrible.
+// FIXME: why not point to the first parameter that's "too many"?
+template<typename T, int N> // expected-error{{too many template parameters}}
+void A<T*, 2>::f0() { }
+
+template<typename T, int N>
+void A<T, N>::f1() { } // expected-error{{out-of-line definition}}
diff --git a/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1.cpp b/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1.cpp
new file mode 100644
index 000000000000..b63c56c40fe8
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1.cpp
@@ -0,0 +1,26 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T, int N>
+struct A;
+
+template<typename T>
+struct A<T*, 2> {
+ A(T);
+ ~A();
+
+ void f(T*);
+
+ operator T*();
+
+ static T value;
+};
+
+template<class X> void A<X*, 2>::f(X*) { }
+
+template<class X> X A<X*, 2>::value;
+
+template<class X> A<X*, 2>::A(X) { value = 0; }
+
+template<class X> A<X*, 2>::~A() { }
+
+template<class X> A<X*, 2>::operator X*() { return 0; }
diff --git a/test/CXX/temp/temp.decls/temp.class/temp.mem.class/p1.cpp b/test/CXX/temp/temp.decls/temp.class/temp.mem.class/p1.cpp
new file mode 100644
index 000000000000..bc4bb5da4011
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.class/temp.mem.class/p1.cpp
@@ -0,0 +1,27 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T, typename U>
+struct X0 {
+ struct Inner;
+};
+
+template<typename T, typename U>
+struct X0<T, U>::Inner {
+ T x;
+ U y;
+
+ void f() { x = y; } // expected-error{{incompatible}}
+};
+
+
+void test(int i, float f) {
+ X0<int, float>::Inner inner;
+ inner.x = 5;
+ inner.y = 3.4;
+ inner.f();
+
+ X0<int*, float *>::Inner inner2;
+ inner2.x = &i;
+ inner2.y = &f;
+ inner2.f(); // expected-note{{instantiation}}
+}
diff --git a/test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1-retmem.cpp b/test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1-retmem.cpp
new file mode 100644
index 000000000000..fd3fb0bc7a7d
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1-retmem.cpp
@@ -0,0 +1,28 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T> struct X1 { };
+
+template<typename T>
+struct X0 {
+ typedef int size_type;
+ typedef T value_type;
+
+ size_type f0() const;
+ value_type *f1();
+ X1<value_type*> f2();
+};
+
+template<typename T>
+typename X0<T>::size_type X0<T>::f0() const {
+ return 0;
+}
+
+template<typename U>
+typename X0<U>::value_type *X0<U>::f1() {
+ return 0;
+};
+
+template<typename U>
+X1<typename X0<U>::value_type*> X0<U>::f2() {
+ return 0;
+};
diff --git a/test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1.cpp b/test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1.cpp
new file mode 100644
index 000000000000..725b61c27162
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1.cpp
@@ -0,0 +1,68 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T, typename U> // expected-note{{previous template}}
+class X0 {
+public:
+ typedef int size_type;
+
+ X0(int);
+ ~X0();
+
+ void f0(const T&, const U&);
+
+ T& operator[](int i) const;
+
+ void f1(size_type) const;
+ void f2(size_type) const;
+ void f3(size_type) const;
+ void f4() ;
+
+ operator T*() const;
+
+ T value;
+};
+
+template<typename T, typename U>
+void X0<T, U>::f0(const T&, const U&) { // expected-note{{previous definition}}
+}
+
+template<class X, class Y>
+X& X0<X, Y>::operator[](int i) const {
+ (void)i;
+ return value;
+}
+
+template<class X, class Y>
+void X0<X, Y>::f1(int) const { }
+
+template<class X, class Y>
+void X0<X, Y>::f2(size_type) const { }
+
+template<class X, class Y, class Z> // expected-error{{too many template parameters}}
+void X0<X, Y>::f3(size_type) const {
+}
+
+template<class X, class Y>
+void X0<Y, X>::f4() { } // expected-error{{does not refer}}
+
+// FIXME: error message should probably say, "redefinition of 'X0<T, U>::f0'"
+// rather than just "redefinition of 'f0'"
+template<typename T, typename U>
+void X0<T, U>::f0(const T&, const U&) { // expected-error{{redefinition}}
+}
+
+// Test out-of-line constructors, destructors
+template<typename T, typename U>
+X0<T, U>::X0(int x) : value(x) { }
+
+template<typename T, typename U>
+X0<T, U>::~X0() { }
+
+// Test out-of-line conversion functions.
+template<typename T, typename U>
+X0<T, U>::operator T*() const {
+ return &value;
+}
+
+namespace N { template <class X> class A {void a();}; }
+namespace N { template <class X> void A<X>::a() {} }
diff --git a/test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1inst.cpp b/test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1inst.cpp
new file mode 100644
index 000000000000..a09d0efa297f
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.class/temp.mem.func/p1inst.cpp
@@ -0,0 +1,17 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+// Test instantiation of member functions of class templates defined out-of-line
+template<typename T, typename U>
+struct X0 {
+ void f(T *t, const U &u);
+ void f(T *);
+};
+
+template<typename T, typename U>
+void X0<T, U>::f(T *t, const U &u) {
+ *t = u; // expected-error{{not assignable}}
+}
+
+void test_f(X0<float, int> xfi, X0<void, int> xvi, float *fp, void *vp, int i) {
+ xfi.f(fp, i);
+ xvi.f(vp, i); // expected-note{{instantiation}}
+}
diff --git a/test/CXX/temp/temp.decls/temp.class/temp.mem.func/pr5056.cpp b/test/CXX/temp/temp.decls/temp.class/temp.mem.func/pr5056.cpp
new file mode 100644
index 000000000000..602fd374c2ab
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.class/temp.mem.func/pr5056.cpp
@@ -0,0 +1,17 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+extern "C" void * malloc(int);
+
+template <typename T> struct A {
+ void *malloc(int);
+};
+
+template <typename T>
+inline void *A<T>::malloc(int)
+{
+ return 0;
+}
+
+void f() {
+ malloc(10);
+}
diff --git a/test/CXX/temp/temp.decls/temp.class/temp.static/p1-inst.cpp b/test/CXX/temp/temp.decls/temp.class/temp.static/p1-inst.cpp
new file mode 100644
index 000000000000..2ddb8eac6c0a
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.class/temp.static/p1-inst.cpp
@@ -0,0 +1,28 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// Test instantiation of static data members declared out-of-line.
+
+template<typename T>
+struct X {
+ static T value;
+};
+
+template<typename T>
+ T X<T>::value = 17; // expected-error{{initialize}}
+
+struct InitOkay {
+ InitOkay(int) { }
+};
+
+struct CannotInit { };
+
+int &returnInt() { return X<int>::value; }
+float &returnFloat() { return X<float>::value; }
+
+InitOkay &returnInitOkay() { return X<InitOkay>::value; }
+
+unsigned long sizeOkay() { return sizeof(X<CannotInit>::value); }
+
+CannotInit &returnError() {
+ return X<CannotInit>::value; // expected-note{{instantiation}}
+}
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
new file mode 100644
index 000000000000..949a8b0a72c7
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp
@@ -0,0 +1,26 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T>
+struct X0 {
+ static T value;
+};
+
+template<typename T>
+T X0<T>::value = 0; // expected-error{{initialize}}
+
+struct X1 {
+ X1(int);
+};
+
+struct X2 { };
+
+int& get_int() { return X0<int>::value; }
+X1& get_X1() { return X0<X1>::value; }
+
+double*& get_double_ptr() { return X0<int*>::value; } // expected-error{{initialized}}
+
+X2& get_X2() {
+ return X0<X2>::value; // expected-note{{instantiation}}
+}
+
+template<typename T> T x; // expected-error{{variable 'x' declared as a template}}
diff --git a/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p4.cpp b/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p4.cpp
new file mode 100644
index 000000000000..fe42ba41d81e
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p4.cpp
@@ -0,0 +1,23 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<class T> struct A { A(); };
+template<class T> int &f(T);
+template<class T> float &f(T*);
+template<class T> double &f(const T*);
+
+template<class T> void g(T); // expected-note{{candidate}}
+template<class T> void g(T&); // expected-note{{candidate}}
+
+template<class T> int &h(const T&);
+template<class T> float &h(A<T>&);
+
+void m() {
+ const int *p;
+ double &dr1 = f(p);
+ float x;
+ g(x); // expected-error{{ambiguous}}
+ A<int> z;
+ float &fr1 = h(z);
+ const A<int> z2;
+ int &ir1 = h(z2);
+}
diff --git a/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p5.cpp b/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p5.cpp
new file mode 100644
index 000000000000..27e4426b9082
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p5.cpp
@@ -0,0 +1,12 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+template<class T> int &f(T);
+template<class T> float &f(T*, int=1);
+
+template<class T> int &g(T);
+template<class T> float &g(T*, ...);
+
+int main() {
+ int* ip;
+ float &fr1 = f(ip);
+ float &fr2 = g(ip);
+}
diff --git a/test/CXX/temp/temp.decls/temp.fct/temp.over.link/p4-neg.cpp b/test/CXX/temp/temp.decls/temp.fct/temp.over.link/p4-neg.cpp
index b482955818cb..399dcc4bed76 100644
--- a/test/CXX/temp/temp.decls/temp.fct/temp.over.link/p4-neg.cpp
+++ b/test/CXX/temp/temp.decls/temp.fct/temp.over.link/p4-neg.cpp
@@ -17,11 +17,11 @@ template<typename T>
struct MetaFun;
template<typename T>
- typename MetaFun<T*>::type f0(const T&) { } // expected-note{{previous}}
+ typename MetaFun<T*>::type f0(const T&) { while (1) {} } // expected-note{{previous}}
template<class U>
- typename MetaFun<U*>::type f0(const U&) { } // expected-error{{redefinition}}
+ typename MetaFun<U*>::type f0(const U&) { while (1) {} } // expected-error{{redefinition}}
// FIXME: We need canonicalization of expressions for this to work
// template<int> struct A { };
// template<int I> void f0(A<I>) { } // Xpected-note{{previous}}
-// template<int J> void f0(A<J>) { } // Xpected-error{{redefinition}} \ No newline at end of file
+// template<int J> void f0(A<J>) { } // Xpected-error{{redefinition}}
diff --git a/test/CXX/temp/temp.decls/temp.fct/temp.over.link/p6.cpp b/test/CXX/temp/temp.decls/temp.fct/temp.over.link/p6.cpp
new file mode 100644
index 000000000000..2571e45c5cde
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.fct/temp.over.link/p6.cpp
@@ -0,0 +1,16 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<int N, int M>
+struct A0 {
+ void g0();
+};
+
+template<int X, int Y> void f0(A0<X, Y>) { } // expected-note{{previous}}
+template<int N, int M> void f0(A0<M, N>) { }
+template<int V1, int V2> void f0(A0<V1, V2>) { } // expected-error{{redefinition}}
+
+template<int X, int Y> void f1(A0<0, (X + Y)>) { } // expected-note{{previous}}
+template<int X, int Y> void f1(A0<0, (X - Y)>) { }
+template<int A, int B> void f1(A0<0, (A + B)>) { } // expected-error{{redefinition}}
+
+template<int X, int Y> void A0<X, Y>::g0() { }
diff --git a/test/CXX/temp/temp.decls/temp.friend/p1.cpp b/test/CXX/temp/temp.decls/temp.friend/p1.cpp
new file mode 100644
index 000000000000..fc392da00acf
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.friend/p1.cpp
@@ -0,0 +1,56 @@
+// RUN: clang-cc -emit-llvm-only %s
+
+template <typename T> struct Num {
+ T value_;
+
+public:
+ Num(T value) : value_(value) {}
+ T get() const { return value_; }
+
+ template <typename U> struct Rep {
+ U count_;
+ Rep(U count) : count_(count) {}
+
+ friend Num operator*(const Num &a, const Rep &n) {
+ Num x = 0;
+ for (U count = n.count_; count; --count)
+ x += a;
+ return x;
+ }
+ };
+
+ friend Num operator+(const Num &a, const Num &b) {
+ return a.value_ + b.value_;
+ }
+
+ Num& operator+=(const Num& b) {
+ value_ += b.value_;
+ return *this;
+ }
+
+ class Representation {};
+ friend class Representation;
+};
+
+class A {
+ template <typename T> friend bool iszero(const A &a) throw();
+};
+
+template <class T> class B_iterator;
+template <class T> class B {
+ friend class B_iterator<T>;
+};
+
+int calc1() {
+ Num<int> left = -1;
+ Num<int> right = 1;
+ Num<int> result = left + right;
+ return result.get();
+}
+
+int calc2() {
+ Num<int> x = 3;
+ Num<int>::Rep<char> n = (char) 10;
+ Num<int> result = x * n;
+ return result.get();
+}
diff --git a/test/CXX/temp/temp.decls/temp.friend/p3.cpp b/test/CXX/temp/temp.decls/temp.friend/p3.cpp
new file mode 100644
index 000000000000..4615bebe711f
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.friend/p3.cpp
@@ -0,0 +1,13 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template <class T> class A {
+ typedef int Member;
+};
+
+class B {
+ template <class T> friend class A;
+ template <class T> friend class Undeclared;
+
+ // FIXME: Diagnostic below could be (and was) better.
+ template <class T> friend typename A<T>::Member; // expected-error {{classes or functions}}
+};
diff --git a/test/CXX/temp/temp.decls/temp.friend/p5.cpp b/test/CXX/temp/temp.decls/temp.friend/p5.cpp
new file mode 100644
index 000000000000..f1142a4129b2
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.friend/p5.cpp
@@ -0,0 +1,11 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template <class T> class A {
+ class Member {
+ };
+};
+
+class B {
+ template <class T> friend class A<T>::Member;
+};
+
diff --git a/test/CXX/temp/temp.decls/temp.mem/p1.cpp b/test/CXX/temp/temp.decls/temp.mem/p1.cpp
new file mode 100644
index 000000000000..80b18467a364
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.mem/p1.cpp
@@ -0,0 +1,16 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template <class T> struct A {
+ static T cond;
+
+ template <class U> struct B {
+ static T twice(U value) {
+ return (cond ? value + value : value);
+ }
+ };
+};
+
+int foo() {
+ A<bool>::cond = true;
+ return A<bool>::B<int>::twice(4);
+}
diff --git a/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3.cpp b/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3.cpp
index f4970b89f693..01030b2a8a20 100644
--- a/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3.cpp
@@ -8,4 +8,4 @@ void g() {
f<int>("aa",3.0); // Y is deduced to be char*, and
// Z is deduced to be double
f("aa",3.0); // expected-error{{no matching}}
-} \ No newline at end of file
+}
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp
index c014c663598c..dbe2ff3e18fb 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp
@@ -1,4 +1,4 @@
-// RUN: clang-cc -fsyntax-only %s
+// RUN: clang-cc -fsyntax-only -verify %s
template<typename T> struct A { };
@@ -57,4 +57,32 @@ void test_f3(int ***ip, volatile int ***vip) {
A<volatile int> a1 = f3(vip);
}
-// FIXME: the next bullet requires a lot of effort.
+// - If P is a class, and P has the form template-id, then A can be a
+// derived class of the deduced A. Likewise, if P is a pointer to a class
+// of the form template-id, A can be a pointer to a derived class pointed
+// to by the deduced A.
+template<typename T, int I> struct C { };
+
+struct D : public C<int, 1> { };
+struct E : public D { };
+struct F : A<float> { };
+struct G : A<float>, C<int, 1> { };
+
+template<typename T, int I>
+ C<T, I> *f4a(const C<T, I>&);
+template<typename T, int I>
+ C<T, I> *f4b(C<T, I>);
+template<typename T, int I>
+ C<T, I> *f4c(C<T, I>*);
+int *f4c(...);
+
+void test_f4(D d, E e, F f, G g) {
+ C<int, 1> *ci1a = f4a(d);
+ C<int, 1> *ci2a = f4a(e);
+ C<int, 1> *ci1b = f4b(d);
+ C<int, 1> *ci2b = f4b(e);
+ C<int, 1> *ci1c = f4c(&d);
+ C<int, 1> *ci2c = f4c(&e);
+ C<int, 1> *ci3c = f4c(&g);
+ int *ip1 = f4c(&f);
+}
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p2.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p2.cpp
new file mode 100644
index 000000000000..7d175781c2d9
--- /dev/null
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p2.cpp
@@ -0,0 +1,36 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// FIXME: [temp.deduct.conv]p2 bullets 1 and 2 can't actually happen without
+// references?
+// struct ConvertibleToArray {
+// // template<typename T, unsigned N>
+// // operator T(()[]) const;
+
+// private:
+// typedef int array[17];
+
+// operator array() const;
+// };
+
+// void test_array(ConvertibleToArray cta) {
+// int *ip = cta;
+// ip = cta;
+// const float *cfp = cta;
+// }
+
+// bullet 2
+// struct ConvertibleToFunction {
+// template<typename T, typename A1, typename A2>
+// operator T(A1, A2) const () { };
+// };
+
+// bullet 3
+struct ConvertibleToCVQuals {
+ template<typename T>
+ operator T* const() const;
+};
+
+void test_cvqual_conv(ConvertibleToCVQuals ctcv) {
+ int *ip = ctcv;
+ const int *icp = ctcv;
+}
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p3.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p3.cpp
new file mode 100644
index 000000000000..95bd7fe12159
--- /dev/null
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p3.cpp
@@ -0,0 +1,30 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+struct AnyPtr {
+ template<typename T>
+ operator T*() const;
+};
+
+// If A is a cv-qualified type, the top level cv-qualifiers of A's type
+// are ignored for type deduction.
+void test_cvquals(AnyPtr ap) {
+ int* const ip = ap;
+ const float * const volatile fp = ap;
+}
+
+// If A is a reference type, the type referred to by A is used for
+// type deduction.
+void test_ref_arg(AnyPtr ap) {
+ const int* const &ip = ap;
+ double * const &dp = ap;
+}
+
+struct AnyRef {
+ template<typename T>
+ operator T&() const;
+};
+
+void test_ref_param(AnyRef ar) {
+ int &ir = ar;
+ const float &fr = ar;
+ int i = ar;
+}
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p4.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p4.cpp
new file mode 100644
index 000000000000..50d31fb2f851
--- /dev/null
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p4.cpp
@@ -0,0 +1,44 @@
+// RUN: clang-cc -fsyntax-only %s
+
+struct AnyT {
+ template<typename T>
+ operator T();
+};
+
+void test_cvqual_ref(AnyT any) {
+ const int &cir = any;
+}
+
+struct AnyThreeLevelPtr {
+ template<typename T>
+ operator T***() const
+ {
+ T x = 0;
+ // FIXME: looks like we get this wrong, too!
+ // x = 0; // will fail if T is deduced to a const type
+ // (EDG and GCC get this wrong)
+ return 0;
+ }
+};
+
+struct X { };
+
+void test_deduce_with_qual(AnyThreeLevelPtr a3) {
+ int * const * const * const ip = a3;
+}
+
+struct AnyPtrMem {
+ template<typename Class, typename T>
+ operator T Class::*() const
+ {
+ T x = 0;
+ // FIXME: looks like we get this wrong, too!
+ // x = 0; // will fail if T is deduced to a const type.
+ // (EDG and GCC get this wrong)
+ return 0;
+ }
+};
+
+void test_deduce_ptrmem_with_qual(AnyPtrMem apm) {
+ const float X::* pm = apm;
+}
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.funcaddr/p1.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.funcaddr/p1.cpp
new file mode 100644
index 000000000000..86a34500ad41
--- /dev/null
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.funcaddr/p1.cpp
@@ -0,0 +1,22 @@
+// RUN: clang-cc -fsyntax-only %s
+
+template<typename T>
+ T f0(T, int);
+
+void test_f0() {
+ int (*f0a)(int, int) = f0;
+ int (*f0b)(int, int) = &f0;
+ float (*f0c)(float, int) = &f0;
+}
+
+template<typename T> T f1(T, int);
+template<typename T> T f1(T);
+
+void test_f1() {
+ float (*f1a)(float, int) = f1;
+ float (*f1b)(float, int) = &f1;
+ float (*f1c)(float) = f1;
+ float (*f1d)(float) = (f1);
+ float (*f1e)(float) = &f1;
+ float (*f1f)(float) = (&f1);
+}
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.partial/p11.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.partial/p11.cpp
new file mode 100644
index 000000000000..072789c7d579
--- /dev/null
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.partial/p11.cpp
@@ -0,0 +1,22 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template <class T> T* f(int); // #1
+template <class T, class U> T& f(U); // #2
+
+void g() {
+ int *ip = f<int>(1); // calls #1
+}
+
+template<typename T>
+struct identity {
+ typedef T type;
+};
+
+template <class T>
+ T* f2(int, typename identity<T>::type = 0); // expected-note{{candidate}}
+template <class T, class U>
+ T& f2(U, typename identity<T>::type = 0); // expected-note{{candidate}}
+
+void g2() {
+ f2<int>(1); // expected-error{{ambiguous}}
+}
diff --git a/test/CXX/temp/temp.param/p1.cpp b/test/CXX/temp/temp.param/p1.cpp
index 488c3a07429a..a6638b4f60f2 100644
--- a/test/CXX/temp/temp.param/p1.cpp
+++ b/test/CXX/temp/temp.param/p1.cpp
@@ -1 +1,4 @@
+// Suppress 'no run line' failure.
+// RUN: true
+
// Paragraph 1 is descriptive, and therefore requires no tests.
diff --git a/test/CXX/temp/temp.res/temp.dep/p3.cpp b/test/CXX/temp/temp.res/temp.dep/p3.cpp
new file mode 100644
index 000000000000..d47f0d683514
--- /dev/null
+++ b/test/CXX/temp/temp.res/temp.dep/p3.cpp
@@ -0,0 +1,43 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+struct A0 {
+ struct K { };
+};
+
+template <typename T> struct B0: A0 {
+ static void f() {
+ K k;
+ }
+};
+
+namespace E1 {
+ typedef double A;
+
+ template<class T> class B {
+ typedef int A;
+ };
+
+ template<class T>
+ struct X : B<T> {
+ A* blarg(double *dp) {
+ return dp;
+ }
+ };
+}
+
+namespace E2 {
+ struct A {
+ struct B;
+ int *a;
+ int Y;
+ };
+
+ int a;
+ template<class T> struct Y : T {
+ struct B { /* ... */ };
+ B b;
+ void f(int i) { a = i; }
+ Y* p;
+ };
+
+ Y<A> ya;
+}
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];
+};