diff options
Diffstat (limited to 'test/CXX/temp')
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]; +}; |