diff options
Diffstat (limited to 'test/SemaTemplate')
59 files changed, 3101 insertions, 0 deletions
diff --git a/test/SemaTemplate/class-template-decl.cpp b/test/SemaTemplate/class-template-decl.cpp new file mode 100644 index 000000000000..c81267771297 --- /dev/null +++ b/test/SemaTemplate/class-template-decl.cpp @@ -0,0 +1,49 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +template<typename T> class A; + +extern "C++" { + template<typename T> class B; +} + +namespace N { + template<typename T> class C; +} + +extern "C" { + template<typename T> class D; // expected-error{{templates must have C++ linkage}} +} + +template<class U> class A; // expected-note{{previous template declaration is here}} + +template<int N> class A; // expected-error{{template parameter has a different kind in template redeclaration}} + +template<int N> class NonTypeTemplateParm; + +typedef int INT; + +template<INT M> class NonTypeTemplateParm; // expected-note{{previous non-type template parameter with type 'INT' (aka 'int') is here}} + +template<long> class NonTypeTemplateParm; // expected-error{{template non-type parameter has a different type 'long' in template redeclaration}} + +template<template<typename T> class X> class TemplateTemplateParm; + +template<template<class> class Y> class TemplateTemplateParm; // expected-note{{previous template declaration is here}} \ + // expected-note{{previous template template parameter is here}} + +template<typename> class TemplateTemplateParm; // expected-error{{template parameter has a different kind in template redeclaration}} + +template<template<typename T, int> class X> class TemplateTemplateParm; // expected-error{{too many template parameters in template template parameter redeclaration}} + +#if 0 +// FIXME: parse template declarations in these scopes, so that we can +// complain about the one at function scope. +class X { +public: + template<typename T> class C; +}; + +void f() { + template<typename T> class X; +} +#endif diff --git a/test/SemaTemplate/class-template-id-2.cpp b/test/SemaTemplate/class-template-id-2.cpp new file mode 100644 index 000000000000..c4388a7c1556 --- /dev/null +++ b/test/SemaTemplate/class-template-id-2.cpp @@ -0,0 +1,24 @@ +// RUN: clang-cc -fsyntax-only -verify %s +namespace N { + template<typename T> class A { }; + + template<> class A<int> { }; + + template<> class A<float>; // expected-note{{forward declaration of 'class N::A<float>'}} + + class B : public A<int> { }; +} + +class C1 : public N::A<int> { }; + +class C2 : public N::A<float> { }; // expected-error{{base class has incomplete type}} + +struct D1 { + operator N::A<int>(); +}; + +namespace N { + struct D2 { + operator A<int>(); + }; +} diff --git a/test/SemaTemplate/class-template-id.cpp b/test/SemaTemplate/class-template-id.cpp new file mode 100644 index 000000000000..e74a6f8dcca9 --- /dev/null +++ b/test/SemaTemplate/class-template-id.cpp @@ -0,0 +1,38 @@ +// RUN: clang-cc -fsyntax-only -verify %s +template<typename T, typename U = float> struct A { }; + +typedef A<int> A_int; + +typedef float FLOAT; + +A<int, FLOAT> *foo(A<int> *ptr, A<int> const *ptr2, A<int, double> *ptr3) { + if (ptr) + return ptr; // okay + else if (ptr2) + return ptr2; // expected-error{{incompatible type returning 'A<int> const *', expected 'A<int, FLOAT> *'}} + else { + return ptr3; // expected-error{{incompatible type returning 'A<int, double> *', expected 'A<int, FLOAT> *'}} + } +} + +template<int I> struct B; + +const int value = 12; +B<17 + 2> *bar(B<(19)> *ptr1, B< (::value + 7) > *ptr2, B<19 - 3> *ptr3) { + if (ptr1) + return ptr1; + else if (ptr2) + return ptr2; + else + return ptr3; // expected-error{{incompatible type returning 'B<19 - 3> *', expected 'B<17 + 2> *'}} +} + +typedef B<5> B5; + + +namespace N { + template<typename T> struct C {}; +} + +N::C<int> c1; +typedef N::C<float> c2; diff --git a/test/SemaTemplate/class-template-spec.cpp b/test/SemaTemplate/class-template-spec.cpp new file mode 100644 index 000000000000..71d8ea14be6b --- /dev/null +++ b/test/SemaTemplate/class-template-spec.cpp @@ -0,0 +1,80 @@ +// RUN: clang-cc -fsyntax-only -verify %s +template<typename T, typename U = int> struct A; // expected-note 2{{template is declared here}} + +template<> struct A<double, double>; // expected-note{{forward declaration}} + +template<> struct A<float, float> { // expected-note{{previous definition}} + int x; +}; + +template<> struct A<float> { // expected-note{{previous definition}} + int y; +}; + +int test_specs(A<float, float> *a1, A<float, int> *a2) { + return a1->x + a2->y; +} + +int test_incomplete_specs(A<double, double> *a1, + A<double> *a2) +{ + (void)a1->x; // expected-error{{incomplete definition of type 'A<double, double>'}} + (void)a2->x; // expected-error{{implicit instantiation of undefined template 'struct A<double, int>'}} +} + +typedef float FLOAT; + +template<> struct A<float, FLOAT>; + +template<> struct A<FLOAT, float> { }; // expected-error{{redefinition}} + +template<> struct A<float, int> { }; // expected-error{{redefinition}} + +template<typename T, typename U = int> struct X; + +template <> struct X<int, int> { int foo(); }; // #1 +template <> struct X<float> { int bar(); }; // #2 + +typedef int int_type; +void testme(X<int_type> *x1, X<float, int> *x2) { + (void)x1->foo(); // okay: refers to #1 + (void)x2->bar(); // okay: refers to #2 +} + +// Make sure specializations are proper classes. +template<> +struct A<char> { + A(); +}; + +A<char>::A() { } + +// Diagnose specialization errors +struct A<double> { }; // expected-error{{template specialization requires 'template<>'}} + +template<> struct ::A<double>; + +namespace N { + template<typename T> struct B; // expected-note 2{{template is declared here}} + + template<> struct ::N::B<char>; // okay + template<> struct ::N::B<short>; // okay + template<> struct ::N::B<int>; // okay + + int f(int); +} + +template<> struct N::B<int> { }; // okay + +template<> struct N::B<float> { }; // expected-error{{class template specialization of 'B' not in namespace 'N'}} + +namespace M { + template<> struct ::N::B<short> { }; // expected-error{{class template specialization of 'B' not in a namespace enclosing 'N'}} + + template<> struct ::A<long double>; // expected-error{{class template specialization of 'A' must occur in the global scope}} +} + +template<> struct N::B<char> { + int testf(int x) { return f(x); } +}; + diff --git a/test/SemaTemplate/current-instantiation.cpp b/test/SemaTemplate/current-instantiation.cpp new file mode 100644 index 000000000000..603c14016fbc --- /dev/null +++ b/test/SemaTemplate/current-instantiation.cpp @@ -0,0 +1,71 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +// This test concerns the identity of dependent types within the +// canonical type system, specifically focusing on the difference +// between members of the current instantiation and membmers of an +// unknown specialization. This considers C++ [temp.type], which +// specifies type equivalence within a template, and C++0x +// [temp.dep.type], which defines what it means to be a member of the +// current instantiation. + +template<typename T, typename U> +struct X0 { + typedef T T_type; + typedef U U_type; + + void f0(T&); // expected-note{{previous}} + void f0(typename X0::U_type&); + void f0(typename X0::T_type&); // expected-error{{redecl}} + + void f1(T&); // expected-note{{previous}} + void f1(typename X0::U_type&); + void f1(typename X0<T, U>::T_type&); // expected-error{{redecl}} + + void f2(T&); // expected-note{{previous}} + void f2(typename X0::U_type&); + void f2(typename X0<T_type, U_type>::T_type&); // expected-error{{redecl}} + + void f3(T&); // expected-note{{previous}} + void f3(typename X0::U_type&); + void f3(typename ::X0<T_type, U_type>::T_type&); // expected-error{{redecl}} + + struct X1 { + typedef T my_T_type; + + void g0(T&); // expected-note{{previous}} + void g0(typename X0::U_type&); + void g0(typename X0::T_type&); // expected-error{{redecl}} + + void g1(T&); // expected-note{{previous}} + void g1(typename X0::U_type&); + void g1(typename X0<T, U>::T_type&); // expected-error{{redecl}} + + void g2(T&); // expected-note{{previous}} + void g2(typename X0::U_type&); + void g2(typename X0<T_type, U_type>::T_type&); // expected-error{{redecl}} + + void g3(T&); // expected-note{{previous}} + void g3(typename X0::U_type&); + void g3(typename ::X0<T_type, U_type>::T_type&); // expected-error{{redecl}} + + void g4(T&); // expected-note{{previous}} + void g4(typename X0::U_type&); + void g4(typename X1::my_T_type&); // expected-error{{redecl}} + + void g5(T&); // expected-note{{previous}} + void g5(typename X0::U_type&); + void g5(typename X0::X1::my_T_type&); // expected-error{{redecl}} + + void g6(T&); // expected-note{{previous}} + void g6(typename X0::U_type&); + void g6(typename X0<T, U>::X1::my_T_type&); // expected-error{{redecl}} + + void g7(T&); // expected-note{{previous}} + void g7(typename X0::U_type&); + void g7(typename ::X0<typename X1::my_T_type, U_type>::X1::my_T_type&); // expected-error{{redecl}} + + void g8(T&); // expected-note{{previous}} + void g8(typename X0<U, T_type>::T_type&); + void g8(typename ::X0<typename X0<T_type, U>::X1::my_T_type, U_type>::X1::my_T_type&); // expected-error{{redecl}} + }; +}; diff --git a/test/SemaTemplate/default-arguments.cpp b/test/SemaTemplate/default-arguments.cpp new file mode 100644 index 000000000000..572227cb61de --- /dev/null +++ b/test/SemaTemplate/default-arguments.cpp @@ -0,0 +1,12 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +template<typename T, int N = 2> struct X; // expected-note{{template is declared here}} + +X<int, 1> *x1; +X<int> *x2; + +X<> *x3; // expected-error{{too few template arguments for class template 'X'}} + +template<typename U = float, int M> struct X; + +X<> *x4; diff --git a/test/SemaTemplate/dependent-type-identity.cpp b/test/SemaTemplate/dependent-type-identity.cpp new file mode 100644 index 000000000000..739cb7f39fa3 --- /dev/null +++ b/test/SemaTemplate/dependent-type-identity.cpp @@ -0,0 +1,72 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +// This test concerns the identity of dependent types within the +// canonical type system. This corresponds to C++ [temp.type], which +// specifies type equivalence within a template. +// +// FIXME: template template parameters + +namespace N { + template<typename T> + struct X2 { + template<typename U> + struct apply { + typedef U* type; + }; + }; +} + +namespace Nalias = N; + +template<typename T> +struct X0 { }; + +using namespace N; + +template<typename T, typename U> +struct X1 { + typedef T type; + typedef U U_type; + + void f0(T); // expected-note{{previous}} + void f0(U); + void f0(type); // expected-error{{redeclar}} + + void f1(T*); // expected-note{{previous}} + void f1(U*); + void f1(type*); // expected-error{{redeclar}} + + void f2(X0<T>*); // expected-note{{previous}} + void f2(X0<U>*); + void f2(X0<type>*); // expected-error{{redeclar}} + + void f3(X0<T>*); // expected-note{{previous}} + void f3(X0<U>*); + void f3(::X0<type>*); // expected-error{{redeclar}} + + void f4(typename T::template apply<U>*); // expected-note{{previous}} + void f4(typename U::template apply<U>*); + void f4(typename type::template apply<T>*); + void f4(typename type::template apply<U_type>*); // expected-error{{redeclar}} + + void f5(typename T::template apply<U>::type*); // expected-note{{previous}} + void f5(typename U::template apply<U>::type*); + void f5(typename U::template apply<T>::type*); + void f5(typename type::template apply<T>::type*); + void f5(typename type::template apply<U_type>::type*); // expected-error{{redeclar}} + + void f6(typename N::X2<T>::template apply<U> *); // expected-note{{previous}} + void f6(typename N::X2<U>::template apply<U> *); + void f6(typename N::X2<U>::template apply<T> *); + void f6(typename ::N::X2<type>::template apply<U_type> *); // expected-error{{redeclar}} + + void f7(typename N::X2<T>::template apply<U> *); // expected-note{{previous}} + void f7(typename N::X2<U>::template apply<U> *); + void f7(typename N::X2<U>::template apply<T> *); + void f7(typename X2<type>::template apply<U_type> *); // expected-error{{redeclar}} + + void f8(typename N::X2<T>::template apply<U> *); // expected-note{{previous}} + void f8(typename N::X2<U>::template apply<U> *); + void f8(typename N::X2<U>::template apply<T> *); + void f8(typename ::Nalias::X2<type>::template apply<U_type> *); // expected-error{{redeclar}} +}; diff --git a/test/SemaTemplate/enum-argument.cpp b/test/SemaTemplate/enum-argument.cpp new file mode 100644 index 000000000000..101a1d0cd9da --- /dev/null +++ b/test/SemaTemplate/enum-argument.cpp @@ -0,0 +1,7 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +enum Enum { val = 1 }; +template <Enum v> struct C { + typedef C<v> Self; +}; +template struct C<val>; diff --git a/test/SemaTemplate/example-dynarray.cpp b/test/SemaTemplate/example-dynarray.cpp new file mode 100644 index 000000000000..cca3709bebbf --- /dev/null +++ b/test/SemaTemplate/example-dynarray.cpp @@ -0,0 +1,150 @@ +// RUN: clang-cc -fsyntax-only -verify %s +#include <stddef.h> +#include <stdlib.h> +#include <assert.h> + +// Placement new requires <new> to be included, but we don't support that yet. +void* operator new(size_t, void* ptr) throw() { + return ptr; +} +void operator delete(void*, void*) throw() { +} + +template<typename T> +class dynarray { +public: + dynarray() { Start = Last = End = 0; } + + dynarray(const dynarray &other) { + Start = (T*)malloc(sizeof(T) * other.size()); + Last = End = Start + other.size(); + + for (unsigned I = 0, N = other.size(); I != N; ++I) + new (Start + I) T(other[I]); + } + + ~dynarray() { + free(Start); + } + + dynarray &operator=(const dynarray &other) { + T* NewStart = (T*)malloc(sizeof(T) * other.size()); + + for (unsigned I = 0, N = other.size(); I != N; ++I) + new (NewStart + I) T(other[I]); + + // FIXME: destroy everything in Start + free(Start); + Start = NewStart; + Last = End = NewStart + other.size(); + return *this; + } + + unsigned size() const { return Last - Start; } + unsigned capacity() const { return End - Start; } + + void push_back(const T& value) { + if (Last == End) { + unsigned NewCapacity = capacity() * 2; + if (NewCapacity == 0) + NewCapacity = 4; + + T* NewStart = (T*)malloc(sizeof(T) * NewCapacity); + + unsigned Size = size(); + for (unsigned I = 0; I != Size; ++I) + new (NewStart + I) T(Start[I]); + + // FIXME: destruct old values + free(Start); + + Start = NewStart; + Last = Start + Size; + End = Start + NewCapacity; + } + + new (Last) T(value); + ++Last; + } + + void pop_back() { + // FIXME: destruct old value + --Last; + } + + T& operator[](unsigned Idx) { + return Start[Idx]; + } + + const T& operator[](unsigned Idx) const { + return Start[Idx]; + } + + typedef T* iterator; + typedef const T* const_iterator; + + iterator begin() { return Start; } + const_iterator begin() const { return Start; } + + iterator end() { return Last; } + const_iterator end() const { return Last; } + +public: + T* Start, *Last, *End; +}; + +struct Point { + Point() { x = y = z = 0.0; } + Point(const Point& other) : x(other.x), y(other.y), z(other.z) { } + + float x, y, z; +}; + +// FIXME: remove these when we have implicit instantiation for member +// functions of class templates. +template class dynarray<int>; +template class dynarray<Point>; + +int main() { + dynarray<int> di; + di.push_back(0); + di.push_back(1); + di.push_back(2); + di.push_back(3); + di.push_back(4); + assert(di.size() == 5); + for (dynarray<int>::iterator I = di.begin(), IEnd = di.end(); I != IEnd; ++I) + assert(*I == I - di.begin()); + + for (int I = 0, N = di.size(); I != N; ++I) + assert(di[I] == I); + + di.pop_back(); + assert(di.size() == 4); + di.push_back(4); + + dynarray<int> di2 = di; + assert(di2.size() == 5); + assert(di.begin() != di2.begin()); + for (dynarray<int>::iterator I = di2.begin(), IEnd = di2.end(); + I != IEnd; ++I) + assert(*I == I - di2.begin()); + + dynarray<int> di3(di); + assert(di3.size() == 5); + assert(di.begin() != di3.begin()); + for (dynarray<int>::iterator I = di3.begin(), IEnd = di3.end(); + I != IEnd; ++I) + assert(*I == I - di3.begin()); + + dynarray<int> di4; + assert(di4.size() == 0); + di4 = di; + assert(di4.size() == 5); + assert(di.begin() != di4.begin()); + for (dynarray<int>::iterator I = di4.begin(), IEnd = di4.end(); + I != IEnd; ++I) + assert(*I == I - di4.begin()); + + return 0; +} diff --git a/test/SemaTemplate/fibonacci.cpp b/test/SemaTemplate/fibonacci.cpp new file mode 100644 index 000000000000..6cd50157e2bd --- /dev/null +++ b/test/SemaTemplate/fibonacci.cpp @@ -0,0 +1,66 @@ +// RUN: clang-cc -fsyntax-only %s + +template<unsigned I> +struct FibonacciEval; + +template<unsigned I> +struct Fibonacci { + enum { value = FibonacciEval<I-1>::value + FibonacciEval<I-2>::value }; +}; + +template<unsigned I> +struct FibonacciEval { + enum { value = Fibonacci<I>::value }; +}; + +template<> struct Fibonacci<0> { + enum { value = 0 }; +}; + +template<> struct Fibonacci<1> { + enum { value = 1 }; +}; + +int array5[Fibonacci<5>::value == 5? 1 : -1]; +int array10[Fibonacci<10>::value == 55? 1 : -1]; + +template<unsigned I> +struct FibonacciEval2; + +template<unsigned I> +struct Fibonacci2 { + static const unsigned value + = FibonacciEval2<I-1>::value + FibonacciEval2<I-2>::value; +}; + +template<unsigned I> +struct FibonacciEval2 { + static const unsigned value = Fibonacci2<I>::value; +}; + +template<> struct Fibonacci2<0> { + static const unsigned value = 0; +}; + +template<> struct Fibonacci2<1> { + static const unsigned value = 1; +}; + +int array5_2[Fibonacci2<5>::value == 5? 1 : -1]; +int array10_2[Fibonacci2<10>::value == 55? 1 : -1]; + +template<unsigned I> +struct Fibonacci3 { + static const unsigned value = Fibonacci3<I-1>::value + Fibonacci3<I-2>::value; +}; + +template<> struct Fibonacci3<0> { + static const unsigned value = 0; +}; + +template<> struct Fibonacci3<1> { + static const unsigned value = 1; +}; + +int array5_3[Fibonacci3<5>::value == 5? 1 : -1]; +int array10_3[Fibonacci3<10>::value == 55? 1 : -1]; diff --git a/test/SemaTemplate/fun-template-def.cpp b/test/SemaTemplate/fun-template-def.cpp new file mode 100644 index 000000000000..8833ef4ddc1d --- /dev/null +++ b/test/SemaTemplate/fun-template-def.cpp @@ -0,0 +1,43 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +// Tests that dependent expressions are always allowed, whereas non-dependent +// are checked as usual. + +#include <stddef.h> + +// Fake typeid, lacking a typeinfo header. +namespace std { class type_info {}; } + +struct dummy {}; + +template <typename T, typename U> +T f(T t1, U u1, int i1) +{ + T t2 = i1; + t2 = i1 + u1; + ++u1; + u1++; + int i2 = u1; + + i1 = t1[u1]; + i1 *= t1; + + i1(u1, t1); // error + u1(i1, t1); + + U u2 = (T)i1; + static_cast<void>(static_cast<U>(reinterpret_cast<T>( + dynamic_cast<U>(const_cast<T>(i1))))); + + new U(i1, t1); + new int(t1, u1); // expected-error {{initializer of a builtin type can only take one argument}} + new (t1, u1) int; + delete t1; + + dummy d1 = sizeof(t1); // FIXME: delayed checking okay? + dummy d2 = offsetof(T, foo); // expected-error {{cannot initialize 'd2'}} + dummy d3 = __alignof(u1); // FIXME: delayed checking okay? + i1 = typeid(t1); // expected-error {{incompatible type assigning}} + + return u1; +} diff --git a/test/SemaTemplate/injected-class-name.cpp b/test/SemaTemplate/injected-class-name.cpp new file mode 100644 index 000000000000..c5f826d849ca --- /dev/null +++ b/test/SemaTemplate/injected-class-name.cpp @@ -0,0 +1,40 @@ +// RUN: clang-cc -fsyntax-only -verify %s +template<typename T> +struct X { + X<T*> *ptr; +}; + +X<int> x; + +template<> +struct X<int***> { + typedef X<int***> *ptr; +}; + +// FIXME: EDG rejects this in their strict-conformance mode, but I +// don't see any wording making this ill-formed. Actually, +// [temp.local]p2 might make it ill-formed. Are we "in the scope of +// the class template specialization?" +X<float>::X<int> xi = x; + +// [temp.local]p1: + +// FIXME: test non-type and template template parameters +template<typename T, typename U> +struct X0 { + typedef T type; + typedef U U_type; + typedef U_type U_type2; + + void f0(const X0&); // expected-note{{here}} + void f0(X0&); + void f0(const X0<T, U>&); // expected-error{{redecl}} + + void f1(const X0&); // expected-note{{here}} + void f1(X0&); + void f1(const X0<type, U_type2>&); // expected-error{{redecl}} + + void f2(const X0&); // expected-note{{here}} + void f2(X0&); + void f2(const ::X0<type, U_type2>&); // expected-error{{redecl}} +}; diff --git a/test/SemaTemplate/instantiate-array.cpp b/test/SemaTemplate/instantiate-array.cpp new file mode 100644 index 000000000000..29279b436899 --- /dev/null +++ b/test/SemaTemplate/instantiate-array.cpp @@ -0,0 +1,28 @@ +// RUN: clang-cc -fsyntax-only -verify %s -std=c++0x + +#ifndef __GXX_EXPERIMENTAL_CXX0X__ +#define __CONCAT(__X, __Y) __CONCAT1(__X, __Y) +#define __CONCAT1(__X, __Y) __X ## __Y + +#define static_assert(__b, __m) \ + typedef int __CONCAT(__sa, __LINE__)[__b ? 1 : -1] +#endif + +template <int N> class IntArray { + int elems[N]; +}; + +static_assert(sizeof(IntArray<10>) == sizeof(int) * 10, "Array size mismatch"); +static_assert(sizeof(IntArray<1>) == sizeof(int) * 1, "Array size mismatch"); + +template <typename T> class TenElementArray { + int elems[10]; +}; + +static_assert(sizeof(TenElementArray<int>) == sizeof(int) * 10, "Array size mismatch"); + +template<typename T, int N> class Array { + T elems[N]; +}; + +static_assert(sizeof(Array<int, 10>) == sizeof(int) * 10, "Array size mismatch"); diff --git a/test/SemaTemplate/instantiate-c99.cpp b/test/SemaTemplate/instantiate-c99.cpp new file mode 100644 index 000000000000..cf691cffad36 --- /dev/null +++ b/test/SemaTemplate/instantiate-c99.cpp @@ -0,0 +1,81 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +// Test template instantiation for C99-specific features. + +// --------------------------------------------------------------------- +// Designated initializers +// --------------------------------------------------------------------- +template<typename T, typename XType, typename YType> +struct DesigInit0 { + void f(XType x, YType y) { + T agg = { + .y = y, // expected-error{{does not refer}} + .x = x // expected-error{{does not refer}} + }; + } +}; + +struct Point2D { + float x, y; +}; + +template struct DesigInit0<Point2D, int, double>; + +struct Point3D { + float x, y, z; +}; + +template struct DesigInit0<Point3D, int, double>; + +struct Color { + unsigned char red, green, blue; +}; + +struct ColorPoint3D { + Color color; + float x, y, z; +}; + +template struct DesigInit0<ColorPoint3D, int, double>; +template struct DesigInit0<Color, int, double>; // expected-note{{instantiation}} + +template<typename T, int Subscript1, int Subscript2, + typename Val1, typename Val2> +struct DesigArrayInit0 { + void f(Val1 val1, Val2 val2) { + T array = { + [Subscript1] = val1, + [Subscript2] = val2 // expected-error{{exceeds array bounds}} + }; + + int array2[10] = { [5] = 3 }; + } +}; + +template struct DesigArrayInit0<int[8], 5, 3, float, int>; +template struct DesigArrayInit0<int[8], 5, 13, float, int>; // expected-note{{instantiation}} + +template<typename T, int Subscript1, int Subscript2, + typename Val1> +struct DesigArrayRangeInit0 { + void f(Val1 val1) { + T array = { + [Subscript1...Subscript2] = val1 // expected-error{{exceeds}} + }; + } +}; + +template struct DesigArrayRangeInit0<int[8], 3, 5, float>; +template struct DesigArrayRangeInit0<int[8], 5, 13, float>; // expected-note{{instantiation}} + +// --------------------------------------------------------------------- +// Compound literals +// --------------------------------------------------------------------- +template<typename T, typename Arg1, typename Arg2> +struct CompoundLiteral0 { + T f(Arg1 a1, Arg2 a2) { + return (T){a1, a2}; + } +}; + +template struct CompoundLiteral0<Point2D, int, float>; diff --git a/test/SemaTemplate/instantiate-call.cpp b/test/SemaTemplate/instantiate-call.cpp new file mode 100644 index 000000000000..a9c4bf481ded --- /dev/null +++ b/test/SemaTemplate/instantiate-call.cpp @@ -0,0 +1,50 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +namespace N1 { + struct X0 { }; + + int& f0(X0); +} + +namespace N2 { + char& f0(char); + + template<typename T, typename Result> + struct call_f0 { + void test_f0(T t) { + Result result = f0(t); + } + }; +} + +template struct N2::call_f0<int, char&>; +template struct N2::call_f0<N1::X0, int&>; + +namespace N3 { + template<typename T, typename Result> + struct call_f0 { + void test_f0(T t) { + Result &result = f0(t); // expected-error 2{{no matching}} + } + }; +} + +template struct N3::call_f0<int, char&>; // expected-note{{instantiation}} +template struct N3::call_f0<N1::X0, int&>; + +short& f0(char); +namespace N4 { + template<typename T, typename Result> + struct call_f0 { + void test_f0(T t) { + Result &result = f0(t); + } + }; +} + +template struct N4::call_f0<int, short&>; +template struct N4::call_f0<N1::X0, int&>; +template struct N3::call_f0<int, short&>; // expected-note{{instantiation}} + +// FIXME: test overloaded function call operators, calls to member +// functions, etc. diff --git a/test/SemaTemplate/instantiate-cast.cpp b/test/SemaTemplate/instantiate-cast.cpp new file mode 100644 index 000000000000..d99f3e556602 --- /dev/null +++ b/test/SemaTemplate/instantiate-cast.cpp @@ -0,0 +1,109 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +struct A { int x; }; + +class Base { +public: + virtual void f(); +}; + +class Derived : public Base { }; + +struct ConvertibleToInt { + operator int() const; +}; + +struct Constructible { + Constructible(int, float); +}; + +// --------------------------------------------------------------------- +// C-style casts +// --------------------------------------------------------------------- +template<typename T, typename U> +struct CStyleCast0 { + void f(T t) { + (void)((U)t); // FIXME:ugly expected-error{{operand}} + } +}; + +template struct CStyleCast0<int, float>; +template struct CStyleCast0<A, int>; // expected-note{{instantiation}} + +// --------------------------------------------------------------------- +// static_cast +// --------------------------------------------------------------------- +template<typename T, typename U> +struct StaticCast0 { + void f(T t) { + (void)static_cast<U>(t); // expected-error{{static_cast}} + } +}; + +template struct StaticCast0<ConvertibleToInt, bool>; +template struct StaticCast0<int, float>; +template struct StaticCast0<int, A>; // expected-note{{instantiation}} + +// --------------------------------------------------------------------- +// dynamic_cast +// --------------------------------------------------------------------- +template<typename T, typename U> +struct DynamicCast0 { + void f(T t) { + (void)dynamic_cast<U>(t); // expected-error{{not a reference or pointer}} + } +}; + +template struct DynamicCast0<Base*, Derived*>; +template struct DynamicCast0<Base*, A>; // expected-note{{instantiation}} + +// --------------------------------------------------------------------- +// reinterpret_cast +// --------------------------------------------------------------------- +template<typename T, typename U> +struct ReinterpretCast0 { + void f(T t) { + (void)reinterpret_cast<U>(t); // expected-error{{constness}} + } +}; + +template struct ReinterpretCast0<void (*)(int), void (*)(float)>; +template struct ReinterpretCast0<int const *, float *>; // expected-note{{instantiation}} + +// --------------------------------------------------------------------- +// const_cast +// --------------------------------------------------------------------- +template<typename T, typename U> +struct ConstCast0 { + void f(T t) { + (void)const_cast<U>(t); // expected-error{{not allowed}} + } +}; + +template struct ConstCast0<int const * *, int * *>; +template struct ConstCast0<int const *, float *>; // expected-note{{instantiation}} + +// --------------------------------------------------------------------- +// C++ functional cast +// --------------------------------------------------------------------- +template<typename T, typename U> +struct FunctionalCast1 { + void f(T t) { + (void)U(t); // FIXME:ugly expected-error{{operand}} + } +}; + +template struct FunctionalCast1<int, float>; +template struct FunctionalCast1<A, int>; // expected-note{{instantiation}} + +#if 0 +// Generates temporaries, which we cannot handle yet. +template<int N, long M> +struct FunctionalCast2 { + void f() { + (void)Constructible(N, M); + } +}; + +template struct FunctionalCast2<1, 3>; +#endif diff --git a/test/SemaTemplate/instantiate-clang.cpp b/test/SemaTemplate/instantiate-clang.cpp new file mode 100644 index 000000000000..a6c28d9e19db --- /dev/null +++ b/test/SemaTemplate/instantiate-clang.cpp @@ -0,0 +1,35 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +// Test template instantiation for Clang-specific features. + +// --------------------------------------------------------------------- +// Vector types +// --------------------------------------------------------------------- +typedef __attribute__(( ext_vector_type(2) )) double double2; +typedef __attribute__(( ext_vector_type(4) )) double double4; + +template<typename T> +struct ExtVectorAccess0 { + void f(T v1, double4 v2) { + v1.xy = v2.yx; + } +}; + +template struct ExtVectorAccess0<double2>; +template struct ExtVectorAccess0<double4>; + +typedef __attribute__(( ext_vector_type(2) )) double double2; + +template<typename T, typename U, int N, int M> +struct ShuffleVector0 { + void f(T t, U u, double2 a, double2 b) { + (void)__builtin_shufflevector(t, u, N, M); // expected-error{{index}} + (void)__builtin_shufflevector(a, b, N, M); + (void)__builtin_shufflevector(a, b, 2, 1); + } +}; + +template struct ShuffleVector0<double2, double2, 2, 1>; +template struct ShuffleVector0<double2, double2, 4, 3>; // expected-note{{instantiation}} + + diff --git a/test/SemaTemplate/instantiate-complete.cpp b/test/SemaTemplate/instantiate-complete.cpp new file mode 100644 index 000000000000..babc55217a95 --- /dev/null +++ b/test/SemaTemplate/instantiate-complete.cpp @@ -0,0 +1,47 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +// Tests various places where requiring a complete type involves +// instantiation of that type. + +template<typename T> +struct X { + X(T); + + T f; // expected-error{{data member instantiated with function type 'float (int)'}} \ + // expected-error{{data member instantiated with function type 'int (int)'}} \ + // expected-error{{data member instantiated with function type 'char (char)'}} \ + // expected-error{{data member instantiated with function type 'short (short)'}} \ + // expected-error{{data member instantiated with function type 'float (float)'}} +}; + +X<int> f() { return 0; } + +struct XField { + X<float(int)> xf; // expected-note{{in instantiation of template class 'struct X<float (int)>' requested here}} +}; + +void test_subscript(X<double> *ptr1, X<int(int)> *ptr2, int i) { + (void)ptr1[i]; + (void)ptr2[i]; // expected-note{{in instantiation of template class 'struct X<int (int)>' requested here}} +} + +void test_arith(X<signed char> *ptr1, X<unsigned char> *ptr2, + X<char(char)> *ptr3, X<short(short)> *ptr4) { + (void)(ptr1 + 5); + // FIXME: if I drop the ')' after void, below, it still parses (!) + (void)(5 + ptr2); + (void)(ptr3 + 5); // expected-note{{in instantiation of template class 'struct X<char (char)>' requested here}} + (void)(5 + ptr4); // expected-note{{in instantiation of template class 'struct X<short (short)>' requested here}} +} + +void test_new() { + (void)new X<float>(0); + (void)new X<float(float)>; // expected-note{{in instantiation of template class 'struct X<float (float)>' requested here}} +} + +void test_memptr(X<long> *p1, long X<long>::*pm1, + X<long(long)> *p2, + long (X<long(long)>::*pm2)(long)) { + (void)(p1->*pm1); + (void)((p2->*pm2)(0)); +} diff --git a/test/SemaTemplate/instantiate-declref.cpp b/test/SemaTemplate/instantiate-declref.cpp new file mode 100644 index 000000000000..051c6050abea --- /dev/null +++ b/test/SemaTemplate/instantiate-declref.cpp @@ -0,0 +1,71 @@ +// RUN: clang-cc -fsyntax-only -verify %s +namespace N { + struct Outer { + struct Inner { + template<typename T> + struct InnerTemplate { + struct VeryInner { + typedef T type; + + static enum K1 { K1Val = sizeof(T) } Kind1; + static enum { K2Val = sizeof(T)*2 } Kind2; + enum { K3Val = sizeof(T)*2 } Kind3; + + void foo() { + K1 k1 = K1Val; + Kind1 = K1Val; + Outer::Inner::InnerTemplate<type>::VeryInner::Kind2 = K2Val; + Kind3 = K3Val; + } + + struct UeberInner { + void bar() { + K1 k1 = K1Val; + Kind1 = K1Val; + Outer::Inner::InnerTemplate<type>::VeryInner::Kind2 = K2Val; + + InnerTemplate t; + InnerTemplate<type> t2; + } + }; + }; + }; + }; + }; +} + +typedef int INT; +template struct N::Outer::Inner::InnerTemplate<INT>::VeryInner; +template struct N::Outer::Inner::InnerTemplate<INT>::UeberInner; // expected-error{{'UeberInner' does not name a tag member}} + +namespace N2 { + struct Outer2 { + template<typename T, typename U = T> + struct Inner { + void foo() { + enum { K1Val = sizeof(T) } k1; + enum K2 { K2Val = sizeof(T)*2 } k2a; + + K2 k2b = K2Val; + + struct S { T x, y; } s1; + struct { U x, y; } s2; + s1.x = s2.x; // expected-error{{incompatible}} + + typedef T type; + type t2 = s1.x; + + typedef struct { T z; } type2; + type2 t3 = { s1.x }; + + Inner i1; + i1.foo(); + Inner<T> i2; + i2.foo(); + } + }; + }; +} + +template struct N2::Outer2::Inner<float>; +template struct N2::Outer2::Inner<int*, float*>; // expected-note{{instantiation}} diff --git a/test/SemaTemplate/instantiate-enum.cpp b/test/SemaTemplate/instantiate-enum.cpp new file mode 100644 index 000000000000..a7acf22a45a1 --- /dev/null +++ b/test/SemaTemplate/instantiate-enum.cpp @@ -0,0 +1,11 @@ +// RUN: clang-cc -fsyntax-only %s + +template<typename T, T I, int J> +struct adder { + enum { + value = I + J, + value2 + }; +}; + +int array1[adder<long, 3, 4>::value == 7? 1 : -1]; diff --git a/test/SemaTemplate/instantiate-expr-1.cpp b/test/SemaTemplate/instantiate-expr-1.cpp new file mode 100644 index 000000000000..13ee3ab525ba --- /dev/null +++ b/test/SemaTemplate/instantiate-expr-1.cpp @@ -0,0 +1,71 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +template<int I, int J> +struct Bitfields { + int simple : I; // expected-error{{bit-field 'simple' has zero width}} + int parens : (J); +}; + +void test_Bitfields(Bitfields<0, 5> *b) { + (void)sizeof(Bitfields<10, 5>); + (void)sizeof(Bitfields<0, 1>); // expected-note{{in instantiation of template class 'struct Bitfields<0, 1>' requested here}} +} + +template<int I, int J> +struct BitfieldPlus { + int bitfield : I + J; // expected-error{{bit-field 'bitfield' has zero width}} +}; + +void test_BitfieldPlus() { + (void)sizeof(BitfieldPlus<0, 1>); + (void)sizeof(BitfieldPlus<-5, 5>); // expected-note{{in instantiation of template class 'struct BitfieldPlus<-5, 5>' requested here}} +} + +template<int I, int J> +struct BitfieldMinus { + int bitfield : I - J; // expected-error{{bit-field 'bitfield' has negative width (-1)}} \ + // expected-error{{bit-field 'bitfield' has zero width}} +}; + +void test_BitfieldMinus() { + (void)sizeof(BitfieldMinus<5, 1>); + (void)sizeof(BitfieldMinus<0, 1>); // expected-note{{in instantiation of template class 'struct BitfieldMinus<0, 1>' requested here}} + (void)sizeof(BitfieldMinus<5, 5>); // expected-note{{in instantiation of template class 'struct BitfieldMinus<5, 5>' requested here}} +} + +template<int I, int J> +struct BitfieldDivide { + int bitfield : I / J; // expected-error{{expression is not an integer constant expression}} \ + // expected-note{{division by zero}} +}; + +void test_BitfieldDivide() { + (void)sizeof(BitfieldDivide<5, 1>); + (void)sizeof(BitfieldDivide<5, 0>); // expected-note{{in instantiation of template class 'struct BitfieldDivide<5, 0>' requested here}} +} + +template<typename T, T I, int J> +struct BitfieldDep { + int bitfield : I + J; +}; + +void test_BitfieldDep() { + (void)sizeof(BitfieldDep<int, 1, 5>); +} + +template<int I> +struct BitfieldNeg { + int bitfield : (-I); // expected-error{{bit-field 'bitfield' has negative width (-5)}} +}; + +template<typename T, T I> +struct BitfieldNeg2 { + int bitfield : (-I); // expected-error{{bit-field 'bitfield' has negative width (-5)}} +}; + +void test_BitfieldNeg() { + (void)sizeof(BitfieldNeg<-5>); // okay + (void)sizeof(BitfieldNeg<5>); // expected-note{{in instantiation of template class 'struct BitfieldNeg<5>' requested here}} + (void)sizeof(BitfieldNeg2<int, -5>); // okay + (void)sizeof(BitfieldNeg2<int, 5>); // expected-note{{in instantiation of template class 'struct BitfieldNeg2<int, 5>' requested here}} +} diff --git a/test/SemaTemplate/instantiate-expr-2.cpp b/test/SemaTemplate/instantiate-expr-2.cpp new file mode 100644 index 000000000000..80f403ed56fe --- /dev/null +++ b/test/SemaTemplate/instantiate-expr-2.cpp @@ -0,0 +1,132 @@ +// RUN: clang-cc -fsyntax-only %s +typedef char one_byte; +typedef char (&two_bytes)[2]; +typedef char (&four_bytes)[4]; +typedef char (&eight_bytes)[8]; + +template<int N> struct A { }; + +namespace N1 { + struct X { }; +} + +namespace N2 { + struct Y { }; + + two_bytes operator+(Y, Y); +} + +namespace N3 { + struct Z { }; + + eight_bytes operator+(Z, Z); +} + +namespace N4 { + one_byte operator+(N1::X, N2::Y); + + template<typename T, typename U> + struct BinOpOverload { + typedef A<sizeof(T() + U())> type; + }; +} + +namespace N1 { + four_bytes operator+(X, X); +} + +namespace N3 { + eight_bytes operator+(Z, Z); // redeclaration +} + +void test_bin_op_overload(A<1> *a1, A<2> *a2, A<4> *a4, A<8> *a8) { + typedef N4::BinOpOverload<N1::X, N2::Y>::type XY; + XY *xy = a1; + typedef N4::BinOpOverload<N1::X, N1::X>::type XX; + XX *xx = a4; + typedef N4::BinOpOverload<N2::Y, N2::Y>::type YY; + YY *yy = a2; + typedef N4::BinOpOverload<N3::Z, N3::Z>::type ZZ; + ZZ *zz = a8; +} + +namespace N3 { + eight_bytes operator-(::N3::Z); +} + +namespace N4 { + template<typename T> + struct UnaryOpOverload { + typedef A<sizeof(-T())> type; + }; +} + +void test_unary_op_overload(A<8> *a8) { + typedef N4::UnaryOpOverload<N3::Z>::type UZ; + UZ *uz = a8; +} + +/* +namespace N5 { + template<int I> + struct Lookup { + enum { val = I, more = val + 1 }; + }; + + template<bool B> + struct Cond { + enum Junk { is = B ? Lookup<B>::more : Lookup<Lookup<B+1>::more>::val }; + }; + + enum { resultT = Cond<true>::is, + resultF = Cond<false>::is }; +} +*/ + +namespace N6 { + // non-typedependent + template<int I> + struct Lookup {}; + + template<bool B, typename T, typename E> + struct Cond { + typedef Lookup<B ? sizeof(T) : sizeof(E)> True; + typedef Lookup<!B ? sizeof(T) : sizeof(E)> False; + }; + + typedef Cond<true, int, char>::True True; + typedef Cond<true, int, char>::False False; + + // check that we have the right types + Lookup<1> const &L1(False()); + Lookup<sizeof(int)> const &L2(True()); +} + + +namespace N7 { + // type dependent + template<int I> + struct Lookup {}; + + template<bool B, typename T, typename E> + struct Cond { + T foo() { return B ? T() : E(); } + typedef Lookup<sizeof(B ? T() : E())> Type; + }; + + //Cond<true, int*, double> C; // Errors + //int V(C.foo()); // Errors + //typedef Cond<true, int*, double>::Type Type; // Errors + typedef Cond<true, int, double>::Type Type; +} + +template<typename T, unsigned long N> struct IntegralConstant { }; + +template<typename T> +struct X0 { + void f(T x, IntegralConstant<T, sizeof(x)>); +}; + +void test_X0(X0<int> x, IntegralConstant<int, sizeof(int)> ic) { + x.f(5,ic); +} diff --git a/test/SemaTemplate/instantiate-expr-3.cpp b/test/SemaTemplate/instantiate-expr-3.cpp new file mode 100644 index 000000000000..696b58325cd7 --- /dev/null +++ b/test/SemaTemplate/instantiate-expr-3.cpp @@ -0,0 +1,115 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +// --------------------------------------------------------------------- +// Imaginary literals +// --------------------------------------------------------------------- +template<typename T> +struct ImaginaryLiteral0 { + void f(T &x) { + x = 3.0I; // expected-error{{incompatible type}} + } +}; + +template struct ImaginaryLiteral0<_Complex float>; +template struct ImaginaryLiteral0<int*>; // expected-note{{instantiation}} + +// --------------------------------------------------------------------- +// Compound assignment operator +// --------------------------------------------------------------------- +namespace N1 { + struct X { }; + + int& operator+=(X&, int); // expected-note{{candidate}} +} + +namespace N2 { + long& operator+=(N1::X&, long); // expected-note{{candidate}} + + template<typename T, typename U, typename Result> + struct PlusEquals0 { + void f(T t, U u) { + Result r = t += u; // expected-error{{ambiguous}} + } + }; +} + +namespace N3 { + struct Y : public N1::X { + short& operator+=(long); // expected-note{{candidate}} + }; +} + +template struct N2::PlusEquals0<N1::X, int, int&>; +template struct N2::PlusEquals0<N1::X, long, long&>; +template struct N2::PlusEquals0<N3::Y, long, short&>; +template struct N2::PlusEquals0<int, int, int&>; +template struct N2::PlusEquals0<N3::Y, int, short&>; // expected-note{{instantiation}} + +// --------------------------------------------------------------------- +// Conditional operator +// --------------------------------------------------------------------- +template<typename T, typename U, typename Result> +struct Conditional0 { + void f(T t, U u) { + Result result = t? : u; + } +}; + +template struct Conditional0<int, int, int>; + +// --------------------------------------------------------------------- +// Statement expressions +// --------------------------------------------------------------------- +template<typename T> +struct StatementExpr0 { + void f(T t) { + (void)({ if (t) t = t + 17; t + 12;}); // expected-error{{invalid}} + } +}; + +template struct StatementExpr0<int>; +template struct StatementExpr0<N1::X>; // expected-note{{instantiation}} + +// --------------------------------------------------------------------- +// __builtin_choose_expr +// --------------------------------------------------------------------- +template<bool Cond, typename T, typename U, typename Result> +struct Choose0 { + void f(T t, U u) { + Result r = __builtin_choose_expr(Cond, t, u); // expected-error{{lvalue}} + } +}; + +template struct Choose0<true, int, float, int&>; +template struct Choose0<false, int, float, float&>; +template struct Choose0<true, int, float, float&>; // expected-note{{instantiation}} + +// --------------------------------------------------------------------- +// __builtin_va_arg +// --------------------------------------------------------------------- +template<typename ArgType> +struct VaArg0 { + void f(int n, ...) { + __builtin_va_list va; + __builtin_va_start(va, n); + for (int i = 0; i != n; ++i) + (void)__builtin_va_arg(va, ArgType); + __builtin_va_end(va); + } +}; + +template struct VaArg0<int>; + +template<typename VaList, typename ArgType> +struct VaArg1 { + void f(int n, ...) { + VaList va; + __builtin_va_start(va, n); // expected-error{{int}} + for (int i = 0; i != n; ++i) + (void)__builtin_va_arg(va, ArgType); + __builtin_va_end(va); + } +}; + +template struct VaArg1<__builtin_va_list, int>; +template struct VaArg1<int, int>; // expected-note{{instantiation}} diff --git a/test/SemaTemplate/instantiate-expr-4.cpp b/test/SemaTemplate/instantiate-expr-4.cpp new file mode 100644 index 000000000000..cd74a21d6dbc --- /dev/null +++ b/test/SemaTemplate/instantiate-expr-4.cpp @@ -0,0 +1,289 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +// --------------------------------------------------------------------- +// C++ Functional Casts +// --------------------------------------------------------------------- +template<int N> +struct ValueInit0 { + int f() { + return int(); + } +}; + +template struct ValueInit0<5>; + +template<int N> +struct FunctionalCast0 { + int f() { + return int(N); + } +}; + +template struct FunctionalCast0<5>; + +struct X { // expected-note 2 {{candidate function}} + X(int, int); // expected-note 2 {{candidate function}} +}; + +template<int N, int M> +struct BuildTemporary0 { + X f() { + return X(N, M); + } +}; + +template struct BuildTemporary0<5, 7>; + +template<int N, int M> +struct Temporaries0 { + void f() { + (void)X(N, M); + } +}; + +template struct Temporaries0<5, 7>; + +// --------------------------------------------------------------------- +// new/delete expressions +// --------------------------------------------------------------------- +struct Y { }; + +template<typename T> +struct New0 { + T* f(bool x) { + if (x) + return new T; // expected-error{{no matching}} + else + return new T(); + } +}; + +template struct New0<int>; +template struct New0<Y>; +template struct New0<X>; // expected-note{{instantiation}} + +template<typename T, typename Arg1> +struct New1 { + T* f(bool x, Arg1 a1) { + return new T(a1); // expected-error{{no matching}} + } +}; + +template struct New1<int, float>; +template struct New1<Y, Y>; +template struct New1<X, Y>; // expected-note{{instantiation}} + +template<typename T, typename Arg1, typename Arg2> +struct New2 { + T* f(bool x, Arg1 a1, Arg2 a2) { + return new T(a1, a2); // expected-error{{no matching}} + } +}; + +template struct New2<X, int, float>; +template struct New2<X, int, int*>; // expected-note{{instantiation}} +// FIXME: template struct New2<int, int, float>; + +template<typename T> +struct Delete0 { + void f(T t) { + delete t; // expected-error{{cannot delete}} + ::delete [] t; + } +}; + +template struct Delete0<int*>; +template struct Delete0<X*>; +template struct Delete0<int>; // expected-note{{instantiation}} + +// --------------------------------------------------------------------- +// throw expressions +// --------------------------------------------------------------------- +template<typename T> +struct Throw1 { + void f(T t) { + throw; + throw t; // expected-error{{incomplete type}} + } +}; + +struct Incomplete; // expected-note{{forward}} + +template struct Throw1<int>; +template struct Throw1<int*>; +template struct Throw1<Incomplete*>; // expected-note{{instantiation}} + +// --------------------------------------------------------------------- +// typeid expressions +// --------------------------------------------------------------------- + +// FIXME: This should really include <typeinfo>, but we don't have that yet. +namespace std { + class type_info; +} + +template<typename T> +struct TypeId0 { + const std::type_info &f(T* ptr) { + if (ptr) + return typeid(ptr); + else + return typeid(T); + } +}; + +struct Abstract { + virtual void f() = 0; +}; + +template struct TypeId0<int>; +template struct TypeId0<Incomplete>; +template struct TypeId0<Abstract>; + +// --------------------------------------------------------------------- +// type traits +// --------------------------------------------------------------------- +template<typename T> +struct is_pod { + static const bool value = __is_pod(T); +}; + +static const int is_pod0[is_pod<X>::value? -1 : 1]; +static const int is_pod1[is_pod<Y>::value? 1 : -1]; + +// --------------------------------------------------------------------- +// initializer lists +// --------------------------------------------------------------------- +template<typename T, typename Val1> +struct InitList1 { + void f(Val1 val1) { + T x = { val1 }; + } +}; + +struct APair { + int *x; + const float *y; +}; + +template struct InitList1<int[1], float>; +template struct InitList1<APair, int*>; + +template<typename T, typename Val1, typename Val2> +struct InitList2 { + void f(Val1 val1, Val2 val2) { + T x = { val1, val2 }; // expected-error{{incompatible}} + } +}; + +template struct InitList2<APair, int*, float*>; +template struct InitList2<APair, int*, double*>; // expected-note{{instantiation}} + +// --------------------------------------------------------------------- +// member references +// --------------------------------------------------------------------- +template<typename T, typename Result> +struct DotMemRef0 { + void f(T t) { + Result result = t.m; // expected-error{{cannot be initialized}} + } +}; + +struct MemInt { + int m; +}; + +struct InheritsMemInt : MemInt { }; + +struct MemIntFunc { + static int m(int); +}; + +template struct DotMemRef0<MemInt, int&>; +template struct DotMemRef0<InheritsMemInt, int&>; +template struct DotMemRef0<MemIntFunc, int (*)(int)>; +template struct DotMemRef0<MemInt, float&>; // expected-note{{instantiation}} + +template<typename T, typename Result> +struct ArrowMemRef0 { + void f(T t) { + Result result = t->m; // expected-error 2{{cannot be initialized}} + } +}; + +template<typename T> +struct ArrowWrapper { + T operator->(); +}; + +template struct ArrowMemRef0<MemInt*, int&>; +template struct ArrowMemRef0<InheritsMemInt*, int&>; +template struct ArrowMemRef0<MemIntFunc*, int (*)(int)>; +template struct ArrowMemRef0<MemInt*, float&>; // expected-note{{instantiation}} + +template struct ArrowMemRef0<ArrowWrapper<MemInt*>, int&>; +template struct ArrowMemRef0<ArrowWrapper<InheritsMemInt*>, int&>; +template struct ArrowMemRef0<ArrowWrapper<MemIntFunc*>, int (*)(int)>; +template struct ArrowMemRef0<ArrowWrapper<MemInt*>, float&>; // expected-note{{instantiation}} +template struct ArrowMemRef0<ArrowWrapper<ArrowWrapper<MemInt*> >, int&>; + +// FIXME: we should be able to return a MemInt without the reference! +MemInt &createMemInt(int); + +template<int N> +struct NonDepMemberExpr0 { + void f() { + createMemInt(N).m = N; + } +}; + +template struct NonDepMemberExpr0<0>; + +template<typename T, typename Result> +struct MemberFuncCall0 { + void f(T t) { + Result result = t.f(); + } +}; + +template<typename T> +struct HasMemFunc0 { + T f(); +}; + + +template struct MemberFuncCall0<HasMemFunc0<int&>, const int&>; + +template<typename Result> +struct ThisMemberFuncCall0 { + Result g(); + + void f() { + Result r1 = g(); + Result r2 = this->g(); + } +}; + +template struct ThisMemberFuncCall0<int&>; + +template<typename T> +struct NonDepMemberCall0 { + void foo(HasMemFunc0<int&> x) { + T result = x.f(); // expected-error{{initialized}} + } +}; + +template struct NonDepMemberCall0<int&>; +template struct NonDepMemberCall0<const int&>; +template struct NonDepMemberCall0<float&>; // expected-note{{instantiation}} + + +template<typename T> +struct QualifiedDeclRef0 { + T f() { + return is_pod<X>::value; // expected-error{{initialized}} + } +}; + +template struct QualifiedDeclRef0<bool>; +template struct QualifiedDeclRef0<int&>; // expected-note{{instantiation}} diff --git a/test/SemaTemplate/instantiate-expr-basic.cpp b/test/SemaTemplate/instantiate-expr-basic.cpp new file mode 100644 index 000000000000..2b5fcaeb0454 --- /dev/null +++ b/test/SemaTemplate/instantiate-expr-basic.cpp @@ -0,0 +1,17 @@ +// RUN: clang-cc -fsyntax-only -Wno-unused-value -std=c++0x %s + +template <typename T> +struct S { + void f() { + __func__; // PredefinedExpr + 10; // IntegerLiteral + 10.5; // FloatingLiteral + 'c'; // CharacterLiteral + "hello"; // StringLiteral + true; // CXXBooleanLiteralExpr + nullptr; // CXXNullPtrLiteralExpr + __null; // GNUNullExpr + } +}; + +template struct S<int>; diff --git a/test/SemaTemplate/instantiate-field.cpp b/test/SemaTemplate/instantiate-field.cpp new file mode 100644 index 000000000000..8e2a3758b0d7 --- /dev/null +++ b/test/SemaTemplate/instantiate-field.cpp @@ -0,0 +1,28 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +template<typename T> +struct X { + int x; + T y; // expected-error{{data member instantiated with function type}} + T* z; + T bitfield : 12; // expected-error{{bit-field 'bitfield' has non-integral type 'float'}} \ + // expected-error{{data member instantiated with function type}} + + mutable T x2; // expected-error{{data member instantiated with function type}} +}; + +void test1(const X<int> *xi) { + int i1 = xi->x; + const int &i2 = xi->y; + int* ip1 = xi->z; + int i3 = xi->bitfield; + xi->x2 = 17; +} + +void test2(const X<float> *xf) { + (void)xf->x; // expected-note{{in instantiation of template class 'struct X<float>' requested here}} +} + +void test3(const X<int(int)> *xf) { + (void)xf->x; // expected-note{{in instantiation of template class 'struct X<int (int)>' requested here}} +} diff --git a/test/SemaTemplate/instantiate-function-1.cpp b/test/SemaTemplate/instantiate-function-1.cpp new file mode 100644 index 000000000000..5b3a6d998404 --- /dev/null +++ b/test/SemaTemplate/instantiate-function-1.cpp @@ -0,0 +1,211 @@ +// RUN: clang-cc -fsyntax-only -verify %s +template<typename T, typename U> +struct X0 { + void f(T x, U y) { + (void)(x + y); // expected-error{{invalid operands}} + } +}; + +struct X1 { }; + +template struct X0<int, float>; +template struct X0<int*, int>; +template struct X0<int X1::*, int>; // expected-note{{instantiation of}} + +template<typename T> +struct X2 { + void f(T); + + T g(T x, T y) { + /* DeclStmt */; + T *xp = &x, &yr = y; // expected-error{{pointer to a reference}} + /* NullStmt */; + } +}; + +template struct X2<int>; +template struct X2<int&>; // expected-note{{instantiation of}} + +template<typename T> +struct X3 { + void f(T) { + Label: + T x; + goto Label; + } +}; + +template struct X3<int>; + +template <typename T> struct X4 { + T f() const { + return; // expected-warning{{non-void function 'f' should return a value}} + } + + T g() const { + return 1; // expected-warning{{void function 'g' should not return a value}} + } +}; + +template struct X4<void>; // expected-note{{in instantiation of}} +template struct X4<int>; // expected-note{{in instantiation of}} + +struct Incomplete; // expected-note 2{{forward declaration}} + +template<typename T> struct X5 { + T f() { } // expected-error{{incomplete result type}} +}; +void test_X5(X5<Incomplete> x5); // okay! + +template struct X5<Incomplete>; // expected-note{{instantiation}} + +template<typename T, typename U, typename V> struct X6 { + U f(T t, U u, V v) { + // IfStmt + if (t > 0) + return u; + else { + if (t < 0) + return v; // expected-error{{incompatible type}} + } + + if (T x = t) { + t = x; + } + return v; + } +}; + +struct ConvertibleToInt { + operator int() const; +}; + +template struct X6<ConvertibleToInt, float, char>; +template struct X6<bool, int, int*>; // expected-note{{instantiation}} + +template <typename T> struct X7 { + void f() { + void *v = this; + } +}; + +template struct X7<int>; + +template<typename T> struct While0 { + void f(T t) { + while (t) { + } + + while (T t2 = T()) ; + } +}; + +template struct While0<float>; + +template<typename T> struct Do0 { + void f(T t) { + do { + } while (t); // expected-error{{not contextually}} + + do { + } while (T t2 = T()); + } +}; + +struct NotConvertibleToBool { }; +template struct Do0<ConvertibleToInt>; +template struct Do0<NotConvertibleToBool>; // expected-note{{instantiation}} + +template<typename T> struct For0 { + void f(T f, T l) { + for (; f != l; ++f) { + if (*f) + continue; + else if (*f == 17) + break; + } + } +}; + +template struct For0<int*>; + +template<typename T> struct Member0 { + void f(T t) { + t; + t.f; + t->f; + + T* tp; + tp.f; // expected-error{{member reference base type 'T *' is not a structure or union}} + tp->f; + + this->f; + this.f; // expected-error{{member reference base type 'struct Member0 *const' is not a structure or union}} + } +}; + +template<typename T, typename U> struct Switch0 { + U f(T value, U v0, U v1, U v2) { + switch (value) { + case 0: return v0; + + case 1: return v1; + + case 2: // fall through + + default: + return v2; + } + } +}; + +template struct Switch0<int, float>; + +template<typename T, int I1, int I2> struct Switch1 { + T f(T x, T y, T z) { + switch (x) { + case I1: return y; // expected-note{{previous}} + case I2: return z; // expected-error{{duplicate}} + default: return x; + } + } +}; + +template struct Switch1<int, 1, 2>; +template struct Switch1<int, 2, 2>; // expected-note{{instantiation}} + +template<typename T> struct IndirectGoto0 { + void f(T x) { + // FIXME: crummy error message below + goto *x; // expected-error{{incompatible}} + + prior: + T prior_label = &&prior; + + T later_label = &&later; + + later: + (void)(1+1); + } +}; + +template struct IndirectGoto0<void*>; +template struct IndirectGoto0<int>; // expected-note{{instantiation}} + +template<typename T> struct TryCatch0 { + void f() { + try { + } catch (T t) { // expected-error{{incomplete type}} \ + // expected-error{{abstract class}} + } catch (...) { + } + } +}; + +struct Abstract { + virtual void foo() = 0; // expected-note{{pure virtual}} +}; + +template struct TryCatch0<int>; // okay +template struct TryCatch0<Incomplete*>; // expected-note{{instantiation}} +template struct TryCatch0<Abstract>; // expected-note{{instantiation}} diff --git a/test/SemaTemplate/instantiate-function-1.mm b/test/SemaTemplate/instantiate-function-1.mm new file mode 100644 index 000000000000..aef2d9dbb7eb --- /dev/null +++ b/test/SemaTemplate/instantiate-function-1.mm @@ -0,0 +1,14 @@ +template<typename T> struct Member0 { + void f(T t) { + t; + t.f; + t->f; + + T* tp; + tp.f; + tp->f; + + this->f; + this.f; // expected-error{{member reference base type 'struct Member0 *const' is not a structure or union}} + } +}; diff --git a/test/SemaTemplate/instantiate-function-2.cpp b/test/SemaTemplate/instantiate-function-2.cpp new file mode 100644 index 000000000000..51a60146d46a --- /dev/null +++ b/test/SemaTemplate/instantiate-function-2.cpp @@ -0,0 +1,12 @@ +// RUN: clang-cc -fsyntax-only -verify %s +template <typename T> struct S { + S() { } + S(T t); +}; + +template struct S<int>; + +void f() { + S<int> s1; + S<int> s2(10); +} diff --git a/test/SemaTemplate/instantiate-member-class.cpp b/test/SemaTemplate/instantiate-member-class.cpp new file mode 100644 index 000000000000..fab65cef2e45 --- /dev/null +++ b/test/SemaTemplate/instantiate-member-class.cpp @@ -0,0 +1,38 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +template<typename T> +class X { +public: + struct C { T &foo(); }; + + struct D { + struct E { T &bar(); }; // expected-error{{cannot form a reference to 'void'}} + struct F; // expected-note{{member is declared here}} + }; +}; + +X<int>::C *c1; +X<float>::C *c2; + +X<int>::X *xi; +X<float>::X *xf; + +void test_naming() { + c1 = c2; // expected-error{{incompatible type assigning 'X<float>::C *', expected 'X<int>::C *'}} + xi = xf; // expected-error{{incompatible type assigning}} + // FIXME: error above doesn't print the type X<int>::X cleanly! +} + +void test_instantiation(X<double>::C *x, + X<float>::D::E *e, + X<float>::D::F *f) { + double &dr = x->foo(); + float &fr = e->bar(); + f->foo(); // expected-error{{implicit instantiation of undefined member 'struct X<float>::D::F'}} + +} + + +X<void>::C *c3; // okay +X<void>::D::E *e1; // okay +X<void>::D::E e2; // expected-note{{in instantiation of member class 'struct X<void>::D::E' requested here}} diff --git a/test/SemaTemplate/instantiate-method.cpp b/test/SemaTemplate/instantiate-method.cpp new file mode 100644 index 000000000000..daea7465dc12 --- /dev/null +++ b/test/SemaTemplate/instantiate-method.cpp @@ -0,0 +1,74 @@ +// RUN: clang-cc -fsyntax-only -verify %s +template<typename T> +class X { +public: + void f(T x); // expected-error{{argument may not have 'void' type}} + void g(T*); + + static int h(T, T); // expected-error 2{{argument may not have 'void' type}} +}; + +int identity(int x) { return x; } + +void test(X<int> *xi, int *ip, X<int(int)> *xf) { + xi->f(17); + xi->g(ip); + xf->f(&identity); + xf->g(identity); + X<int>::h(17, 25); + X<int(int)>::h(identity, &identity); +} + +void test_bad() { + X<void> xv; // expected-note{{in instantiation of template class 'class X<void>' requested here}} +} + +template<typename T, typename U> +class Overloading { +public: + int& f(T, T); // expected-note{{previous declaration is here}} + float& f(T, U); // expected-error{{functions that differ only in their return type cannot be overloaded}} +}; + +void test_ovl(Overloading<int, long> *oil, int i, long l) { + int &ir = oil->f(i, i); + float &fr = oil->f(i, l); +} + +void test_ovl_bad() { + Overloading<float, float> off; // expected-note{{in instantiation of template class 'class Overloading<float, float>' requested here}} +} + +template<typename T> +class HasDestructor { +public: + virtual ~HasDestructor() = 0; +}; + +int i = sizeof(HasDestructor<int>); // FIXME: forces instantiation, but + // the code below should probably instantiate by itself. +int abstract_destructor[__is_abstract(HasDestructor<int>)? 1 : -1]; + + +template<typename T> +class Constructors { +public: + Constructors(const T&); + Constructors(const Constructors &other); +}; + +void test_constructors() { + Constructors<int> ci1(17); + Constructors<int> ci2 = ci1; +} + + +template<typename T> +struct ConvertsTo { + operator T(); +}; + +void test_converts_to(ConvertsTo<int> ci, ConvertsTo<int *> cip) { + int i = ci; + int *ip = cip; +} diff --git a/test/SemaTemplate/instantiate-static-var.cpp b/test/SemaTemplate/instantiate-static-var.cpp new file mode 100644 index 000000000000..99e6b9cc06c3 --- /dev/null +++ b/test/SemaTemplate/instantiate-static-var.cpp @@ -0,0 +1,18 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +template<typename T, T Divisor> +class X { +public: + static const T value = 10 / Divisor; // expected-error{{in-class initializer is not an integral constant expression}} +}; + +int array1[X<int, 2>::value == 5? 1 : -1]; +X<int, 0> xi0; // expected-note{{in instantiation of template class 'class X<int, 0>' requested here}} + + +template<typename T> +class Y { + static const T value = 0; // expected-error{{'value' can only be initialized if it is a static const integral data member}} +}; + +Y<float> fy; // expected-note{{in instantiation of template class 'class Y<float>' requested here}} diff --git a/test/SemaTemplate/instantiate-subscript.cpp b/test/SemaTemplate/instantiate-subscript.cpp new file mode 100644 index 000000000000..434d84e2b893 --- /dev/null +++ b/test/SemaTemplate/instantiate-subscript.cpp @@ -0,0 +1,26 @@ +// RUN: clang-cc -fsyntax-only -verify %s + + +struct Sub0 { + int &operator[](int); +}; + +struct Sub1 { + long &operator[](long); +}; + +struct ConvertibleToInt { + operator int(); +}; + +template<typename T, typename U, typename Result> +struct Subscript0 { + void test(T t, U u) { + Result &result = t[u]; // expected-error{{subscripted value is not}} + } +}; + +template struct Subscript0<int*, int, int&>; +template struct Subscript0<Sub0, int, int&>; +template struct Subscript0<Sub1, ConvertibleToInt, long&>; +template struct Subscript0<Sub1, Sub0, long&>; // expected-note{{instantiation}} diff --git a/test/SemaTemplate/instantiate-template-template-parm.cpp b/test/SemaTemplate/instantiate-template-template-parm.cpp new file mode 100644 index 000000000000..b158251915a0 --- /dev/null +++ b/test/SemaTemplate/instantiate-template-template-parm.cpp @@ -0,0 +1,21 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +template<template<typename T> class MetaFun, typename Value> +struct apply { + typedef typename MetaFun<Value>::type type; +}; + +template<class T> +struct add_pointer { + typedef T* type; +}; + +template<class T> +struct add_reference { + typedef T& type; +}; + +int i; +apply<add_pointer, int>::type ip = &i; +apply<add_reference, int>::type ir = i; +apply<add_reference, float>::type fr = i; // expected-error{{non-const lvalue reference to type 'float' cannot be initialized with a value of type 'int'}} diff --git a/test/SemaTemplate/instantiate-try-catch.cpp b/test/SemaTemplate/instantiate-try-catch.cpp new file mode 100644 index 000000000000..074afa9d173d --- /dev/null +++ b/test/SemaTemplate/instantiate-try-catch.cpp @@ -0,0 +1,14 @@ +// RUN: clang-cc -fsyntax-only -std=c++0x -verify %s + +template<typename T> struct TryCatch0 { + void f() { + try { + } catch (T&&) { // expected-error 2{{cannot catch exceptions by rvalue reference}} + } + } +}; + +template struct TryCatch0<int&>; // okay +template struct TryCatch0<int&&>; // expected-note{{instantiation}} +template struct TryCatch0<int>; // expected-note{{instantiation}} + diff --git a/test/SemaTemplate/instantiate-type.cpp b/test/SemaTemplate/instantiate-type.cpp new file mode 100644 index 000000000000..48060c4e384e --- /dev/null +++ b/test/SemaTemplate/instantiate-type.cpp @@ -0,0 +1,17 @@ +// RUN: clang-cc -fsyntax-only %s + +int* f(int); +float *f(...); + +template<typename T> +struct X { + typedef typeof(T*) typeof_type; + typedef typeof(f(T())) typeof_expr; +}; + +int *iptr0; +float *fptr0; +X<int>::typeof_type &iptr1 = iptr0; + +X<int>::typeof_expr &iptr2 = iptr0; +X<float*>::typeof_expr &fptr1 = fptr0; diff --git a/test/SemaTemplate/instantiate-typedef.cpp b/test/SemaTemplate/instantiate-typedef.cpp new file mode 100644 index 000000000000..d30309cc86ca --- /dev/null +++ b/test/SemaTemplate/instantiate-typedef.cpp @@ -0,0 +1,16 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +template<typename T> +struct add_pointer { + typedef T* type; // expected-error{{'type' declared as a pointer to a reference}} +}; + +add_pointer<int>::type test1(int * ptr) { return ptr; } + +add_pointer<float>::type test2(int * ptr) { + return ptr; // expected-error{{incompatible type returning 'int *', expected 'add_pointer<float>::type' (aka 'float *')}} +} + +add_pointer<int&>::type // expected-note{{in instantiation of template class 'struct add_pointer<int &>' requested here}} \ +// expected-error {{unknown type name 'type'}} +test3(); diff --git a/test/SemaTemplate/instantiation-backtrace.cpp b/test/SemaTemplate/instantiation-backtrace.cpp new file mode 100644 index 000000000000..869662268dd2 --- /dev/null +++ b/test/SemaTemplate/instantiation-backtrace.cpp @@ -0,0 +1,32 @@ +// RUN: clang-cc -fsyntax-only -verify %s +template<typename T> struct A; // expected-note 4{{template is declared here}} + +template<typename T> struct B : A<T*> { }; // expected-error{{implicit instantiation of undefined template}} \ +// expected-error{{implicit instantiation of undefined template 'struct A<X *>'}} + +template<typename T> struct C : B<T> { } ; // expected-note{{instantiation of template class}} + +template<typename T> struct D : C<T> { }; // expected-note{{instantiation of template class}} + +template<typename T> struct E : D<T> { }; // expected-note{{instantiation of template class}} + +template<typename T> struct F : E<T(T)> { }; // expected-note{{instantiation of template class}} + +void f() { + (void)sizeof(F<int>); // expected-note{{instantiation of template class}} +} + +typedef struct { } X; + +void g() { + (void)sizeof(B<X>); // expected-note{{in instantiation of template class 'struct B<X>' requested here}} +} + +template<typename T> +struct G : A<T>, // expected-error{{implicit instantiation of undefined template 'struct A<int>'}} + A<T*> // expected-error{{implicit instantiation of undefined template 'struct A<int *>'}} + { }; + +void h() { + (void)sizeof(G<int>); // expected-note{{in instantiation of template class 'struct G<int>' requested here}} +} diff --git a/test/SemaTemplate/instantiation-default-1.cpp b/test/SemaTemplate/instantiation-default-1.cpp new file mode 100644 index 000000000000..f0ce0d3cc669 --- /dev/null +++ b/test/SemaTemplate/instantiation-default-1.cpp @@ -0,0 +1,102 @@ +// RUN: clang-cc -fsyntax-only -verify %s +template<typename T, typename U = const T> struct Def1; + +template<> struct Def1<int> { + void foo(); +}; + +template<> struct Def1<const int> { // expected-note{{previous definition is here}} + void bar(); +}; + +template<> struct Def1<int&> { + void wibble(); +}; + +void test_Def1(Def1<int, const int> *d1, Def1<const int, const int> *d2, + Def1<int&, int&> *d3) { + d1->foo(); + d2->bar(); + d3->wibble(); +} + +template<typename T, // FIXME: bad error message below, needs better location info + typename T2 = const T*> // expected-error{{'T2' declared as a pointer to a reference}} + struct Def2; + +template<> struct Def2<int> { + void foo(); +}; + +void test_Def2(Def2<int, int const*> *d2) { + d2->foo(); +} + +typedef int& int_ref_t; +Def2<int_ref_t> *d2; // expected-note{{in instantiation of default argument for 'Def2<int &>' required here}} + + +template<> struct Def1<const int, const int> { }; // expected-error{{redefinition of 'Def1<int const>'}} + +template<typename T, typename T2 = T&> struct Def3; + +template<> struct Def3<int> { + void foo(); +}; + +template<> struct Def3<int&> { + void bar(); +}; + +void test_Def3(Def3<int, int&> *d3a, Def3<int&, int&> *d3b) { + d3a->foo(); + d3b->bar(); +} + + +template<typename T, typename T2 = T[]> struct Def4; + +template<> struct Def4<int> { + void foo(); +}; + +void test_Def4(Def4<int, int[]> *d4a) { + d4a->foo(); +} + +template<typename T, typename T2 = T const[12]> struct Def5; + +template<> struct Def5<int> { + void foo(); +}; + +template<> struct Def5<int, int const[13]> { + void bar(); +}; + +void test_Def5(Def5<int, const int[12]> *d5a, Def5<int, const int[13]> *d5b) { + d5a->foo(); + d5b->bar(); +} + +template<typename R, typename Arg1, typename Arg2 = Arg1, + typename FuncType = R (*)(Arg1, Arg2)> + struct Def6; + +template<> struct Def6<int, float> { + void foo(); +}; + +template<> struct Def6<bool, int[5], float(double, double)> { + void bar(); +}; + +bool test_Def6(Def6<int, float, float> *d6a, + Def6<int, float, float, int (*)(float, float)> *d6b, + Def6<bool, int[5], float(double, double), + bool(*)(int*, float(*)(double, double))> *d6c) { + d6a->foo(); + d6b->foo(); + d6c->bar(); + return d6a == d6b; +} diff --git a/test/SemaTemplate/instantiation-default-2.cpp b/test/SemaTemplate/instantiation-default-2.cpp new file mode 100644 index 000000000000..740832c5ba39 --- /dev/null +++ b/test/SemaTemplate/instantiation-default-2.cpp @@ -0,0 +1,18 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +template<typename T, T Value> struct Constant; // expected-note{{template parameter is declared here}} \ +// FIXME: bad location expected-error{{a non-type template parameter cannot have type 'float'}} + +Constant<int, 5> *c1; + +int x; +float f(int, double); + +Constant<int&, x> *c2; +Constant<int*, &x> *c3; +Constant<float (*)(int, double), f> *c4; +Constant<float (*)(int, double), &f> *c5; + +Constant<float (*)(int, int), f> *c6; // expected-error{{non-type template argument of type 'float (*)(int, double)' cannot be converted to a value of type 'float (*)(int, int)'}} + +Constant<float, 0> *c7; // expected-note{{in instantiation of default argument for 'Constant<float>' required here}} diff --git a/test/SemaTemplate/instantiation-default-3.cpp b/test/SemaTemplate/instantiation-default-3.cpp new file mode 100644 index 000000000000..521edf66f24c --- /dev/null +++ b/test/SemaTemplate/instantiation-default-3.cpp @@ -0,0 +1,21 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +template<typename T> struct A { }; + +template<typename T, typename U = A<T*> > + struct B : U { }; + +template<> +struct A<int*> { + void foo(); +}; + +template<> +struct A<float*> { + void bar(); +}; + +void test(B<int> *b1, B<float> *b2) { + b1->foo(); + b2->bar(); +} diff --git a/test/SemaTemplate/instantiation-depth.cpp b/test/SemaTemplate/instantiation-depth.cpp new file mode 100644 index 000000000000..522c4e1cbb5c --- /dev/null +++ b/test/SemaTemplate/instantiation-depth.cpp @@ -0,0 +1,9 @@ +// RUN: clang-cc -fsyntax-only -ftemplate-depth=5 -verify %s + +template<typename T> struct X : X<T*> { }; // expected-error{{recursive template instantiation exceeded maximum depth of 5}} \ +// expected-note{{use -ftemplate-depth-N to increase recursive template instantiation depth}} \ +// expected-note 5 {{instantiation of template class}} + +void test() { + (void)sizeof(X<int>); // expected-note {{instantiation of template class}} +} diff --git a/test/SemaTemplate/metafun-apply.cpp b/test/SemaTemplate/metafun-apply.cpp new file mode 100644 index 000000000000..7bc971f24b59 --- /dev/null +++ b/test/SemaTemplate/metafun-apply.cpp @@ -0,0 +1,43 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +struct add_pointer { + template<typename T> + struct apply { + typedef T* type; + }; +}; + +struct add_reference { + template<typename T> + struct apply { + typedef T& type; // expected-error{{cannot form a reference to 'void'}} + }; +}; + +struct bogus { + struct apply { + typedef int type; + }; +}; + +template<typename MetaFun, typename T> +struct apply1 { + typedef typename MetaFun::template apply<T>::type type; // expected-note{{in instantiation of template class 'struct add_reference::apply<void>' requested here}} \ + // expected-error{{'apply' following the 'template' keyword does not refer to a template}} \ + // FIXME: expected-error{{type 'MetaFun::template apply<int>' cannot be used prior to '::' because it has no members}} +}; + +int i; +apply1<add_pointer, int>::type ip = &i; +apply1<add_reference, int>::type ir = i; +apply1<add_reference, float>::type fr = i; // expected-error{{non-const lvalue reference to type 'float' cannot be initialized with a value of type 'int'}} + +void test() { + apply1<add_reference, void>::type t; // expected-note{{in instantiation of template class 'struct apply1<struct add_reference, void>' requested here}} \ + // FIXME: expected-error{{unexpected type name 'type': expected expression}} + + apply1<bogus, int>::type t2; // expected-note{{in instantiation of template class 'struct apply1<struct bogus, int>' requested here}} \ + // FIXME: expected-error{{unexpected type name 'type': expected expression}} +} + + diff --git a/test/SemaTemplate/nested-name-spec-template.cpp b/test/SemaTemplate/nested-name-spec-template.cpp new file mode 100644 index 000000000000..a5aa2dcb527a --- /dev/null +++ b/test/SemaTemplate/nested-name-spec-template.cpp @@ -0,0 +1,61 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +namespace N { + namespace M { + template<typename T> struct Promote; + + template<> struct Promote<short> { + typedef int type; + }; + + template<> struct Promote<int> { + typedef int type; + }; + + template<> struct Promote<float> { + typedef double type; + }; + + Promote<short>::type *ret_intptr(int* ip) { return ip; } + Promote<int>::type *ret_intptr2(int* ip) { return ip; } + } + + M::Promote<int>::type *ret_intptr3(int* ip) { return ip; } + M::template Promote<int>::type *ret_intptr4(int* ip) { return ip; } +} + +N::M::Promote<int>::type *ret_intptr5(int* ip) { return ip; } +::N::M::Promote<int>::type *ret_intptr6(int* ip) { return ip; } + + +N::M::template; // expected-error{{expected template name after 'template' keyword in nested name specifier}} \ + // expected-error{{expected unqualified-id}} + +N::M::template Promote; // expected-error{{expected '<' after 'template Promote' in nested name specifier}} \ +// expected-error{{C++ requires a type specifier for all declarations}} + +namespace N { + template<typename T> struct A; + + template<> + struct A<int> { + struct X; + }; + + struct B; +} + +struct ::N::A<int>::X { + int foo; +}; + +#if 0 +// FIXME: the following crashes the parser, because Sema has no way to +// communicate that the "dependent" template-name N::template B doesn't +// actually refer to a template. +template<typename T> +struct TestA { + typedef typename N::template B<T>::type type; // xpected-error{{'B' following the 'template' keyword does not refer to a template}} + // FIXME: should show what B *does* refer to. +}; +#endif diff --git a/test/SemaTemplate/nested-template.cpp b/test/SemaTemplate/nested-template.cpp new file mode 100644 index 000000000000..bd9e89f76a0a --- /dev/null +++ b/test/SemaTemplate/nested-template.cpp @@ -0,0 +1,16 @@ +// RUN: clang-cc -fsyntax-only %s + +class A; + +class S { +public: + template<typename T> struct A { + struct Nested { + typedef T type; + }; + }; +}; + +int i; +S::A<int>::Nested::type *ip = &i; + diff --git a/test/SemaTemplate/qualified-names-diag.cpp b/test/SemaTemplate/qualified-names-diag.cpp new file mode 100644 index 000000000000..c875332905fb --- /dev/null +++ b/test/SemaTemplate/qualified-names-diag.cpp @@ -0,0 +1,16 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +namespace std { + template<typename T> class vector { }; +} + +typedef int INT; +typedef float Real; + +void test() { + using namespace std; + + std::vector<INT> v1; + vector<Real> v2; + v1 = v2; // expected-error{{no viable overloaded '='}} +} diff --git a/test/SemaTemplate/right-angle-brackets-0x.cpp b/test/SemaTemplate/right-angle-brackets-0x.cpp new file mode 100644 index 000000000000..57b6ee22410c --- /dev/null +++ b/test/SemaTemplate/right-angle-brackets-0x.cpp @@ -0,0 +1,22 @@ +// RUN: clang-cc -fsyntax-only -std=c++0x -verify %s +template<typename T> struct X; +template<int I> struct Y; + +X<X<int>> *x1; + +Y<(1 >> 2)> *y1; +Y<1 >> 2> *y2; // FIXME: expected-error{{expected unqualified-id}} + +X<X<X<X<X<int>>>>> *x2; + +template<> struct X<int> { }; +typedef X<int> X_int; +struct Z : X_int { }; + +void f(const X<int> x) { + (void)reinterpret_cast<X<int>>(x); // expected-error{{reinterpret_cast from}} + (void)reinterpret_cast<X<X<X<int>>>>(x); // expected-error{{reinterpret_cast from}} + + X<X<int>> *x1; +} + diff --git a/test/SemaTemplate/right-angle-brackets-98.cpp b/test/SemaTemplate/right-angle-brackets-98.cpp new file mode 100644 index 000000000000..764bb7bae073 --- /dev/null +++ b/test/SemaTemplate/right-angle-brackets-98.cpp @@ -0,0 +1,12 @@ +// RUN: clang-cc -fsyntax-only -std=c++98 -verify %s +template<typename T> struct X; +template<int I> struct Y; + +X<X<int> > *x1; +X<X<int>> *x2; // expected-error{{a space is required between consecutive right angle brackets (use '> >')}} + +X<X<X<X<int>> // expected-error{{a space is required between consecutive right angle brackets (use '> >')}} + >> *x3; // expected-error{{a space is required between consecutive right angle brackets (use '> >')}} + +Y<(1 >> 2)> *y1; +Y<1 >> 2> *y2; // expected-warning{{use of right-shift operator ('>>') in template argument will require parentheses in C++0x}} diff --git a/test/SemaTemplate/temp.cpp b/test/SemaTemplate/temp.cpp new file mode 100644 index 000000000000..8be4739a741b --- /dev/null +++ b/test/SemaTemplate/temp.cpp @@ -0,0 +1,5 @@ +// RUN: clang-cc -fsyntax-only -verify %s + + +// p3 +template<typename T> int foo(T), bar(T, T); // expected-error{{single entity}} diff --git a/test/SemaTemplate/temp_arg.cpp b/test/SemaTemplate/temp_arg.cpp new file mode 100644 index 000000000000..e873b8e2a61d --- /dev/null +++ b/test/SemaTemplate/temp_arg.cpp @@ -0,0 +1,12 @@ +// RUN: clang-cc -fsyntax-only -verify %s +template<typename T, + int I, + template<typename> class TT> + class A; // expected-note 2 {{template is declared here}} + +template<typename> class X; + +A<int, 0, X> * a1; + +A<float, 1, X, double> *a2; // expected-error{{too many template arguments for class template 'A'}} +A<float, 1> *a3; // expected-error{{too few template arguments for class template 'A'}} diff --git a/test/SemaTemplate/temp_arg_nontype.cpp b/test/SemaTemplate/temp_arg_nontype.cpp new file mode 100644 index 000000000000..fe18fe657c16 --- /dev/null +++ b/test/SemaTemplate/temp_arg_nontype.cpp @@ -0,0 +1,124 @@ +// RUN: clang-cc -fsyntax-only -std=c++98 -verify %s +template<int N> struct A; // expected-note 5{{template parameter is declared here}} + +A<0> *a0; + +A<int()> *a1; // expected-error{{template argument for non-type template parameter is treated as type 'int (void)'}} + +A<int> *a2; // expected-error{{template argument for non-type template parameter must be an expression}} + +A<1 >> 2> *a3; // expected-warning{{use of right-shift operator ('>>') in template argument will require parentheses in C++0x}} + +// C++ [temp.arg.nontype]p5: +A<A> *a4; // expected-error{{must have an integral or enumeration type}} \ + // FIXME: the error message above is a bit lame + +enum E { Enumerator = 17 }; +A<E> *a5; // expected-error{{template argument for non-type template parameter must be an expression}} +template<E Value> struct A1; // expected-note{{template parameter is declared here}} +A1<Enumerator> *a6; // okay +A1<17> *a7; // expected-error{{non-type template argument of type 'int' cannot be converted to a value of type 'enum E'}} + +const long LongValue = 12345678; +A<LongValue> *a8; +const short ShortValue = 17; +A<ShortValue> *a9; + +int f(int); +A<f(17)> *a10; // expected-error{{non-type template argument of type 'int' is not an integral constant expression}} + +class X { +public: + X(); + X(int, int); + operator int() const; +}; +A<X(17, 42)> *a11; // expected-error{{non-type template argument of type 'class X' must have an integral or enumeration type}} + +template<X const *Ptr> struct A2; + +X *X_ptr; +X an_X; +X array_of_Xs[10]; +A2<X_ptr> *a12; +A2<array_of_Xs> *a13; +A2<&an_X> *a13_2; +A2<(&an_X)> *a13_3; // expected-error{{non-type template argument cannot be surrounded by parentheses}} + +float f(float); + +float g(float); +double g(double); + +int h(int); +float h2(float); + +template<int fp(int)> struct A3; // expected-note 2{{template parameter is declared here}} +A3<h> *a14_1; +A3<&h> *a14_2; +A3<f> *a14_3; +A3<&f> *a14_4; +A3<h2> *a14_6; // expected-error{{non-type template argument of type 'float (*)(float)' cannot be converted to a value of type 'int (*)(int)'}} +A3<g> *a14_7; // expected-error{{non-type template argument of type '<overloaded function type>' cannot be converted to a value of type 'int (*)(int)'}} +// FIXME: the first error includes the string <overloaded function +// type>, which makes Doug slightly unhappy. + + +struct Y { } y; + +volatile X * X_volatile_ptr; +template<X const &AnX> struct A4; // expected-note 2{{template parameter is declared here}} +A4<an_X> *a15_1; // okay +A4<*X_volatile_ptr> *a15_2; // expected-error{{reference binding of non-type template parameter of type 'class X const &' to template argument of type 'class X volatile' ignores qualifiers}} +A4<y> *15_3; // expected-error{{non-type template parameter of reference type 'class X const &' cannot bind to template argument of type 'struct Y'}} \ + // FIXME: expected-error{{expected unqualified-id}} + +template<int (&fr)(int)> struct A5; // expected-note 2{{template parameter is declared here}} +A5<h> *a16_1; +A5<f> *a16_3; +A5<h2> *a16_6; // expected-error{{non-type template argument of type 'float (float)' cannot be converted to a value of type 'int (&)(int)'}} +A5<g> *a14_7; // expected-error{{non-type template argument of type '<overloaded function type>' cannot be converted to a value of type 'int (&)(int)'}} +// FIXME: the first error includes the string <overloaded function +// type>, which makes Doug slightly unhappy. + +struct Z { + int foo(int); + float bar(float); + int bar(int); + double baz(double); + + int int_member; + float float_member; +}; +template<int (Z::*pmf)(int)> struct A6; // expected-note{{template parameter is declared here}} +A6<&Z::foo> *a17_1; +A6<&Z::bar> *a17_2; +A6<&Z::baz> *a17_3; // expected-error{{non-type template argument of type 'double (struct Z::*)(double)' cannot be converted to a value of type 'int (struct Z::*)(int)'}} + + +template<int Z::*pm> struct A7; // expected-note{{template parameter is declared here}} +template<int Z::*pm> struct A7c; +A7<&Z::int_member> *a18_1; +A7c<&Z::int_member> *a18_2; +A7<&Z::float_member> *a18_3; // expected-error{{non-type template argument of type 'float struct Z::*' cannot be converted to a value of type 'int struct Z::*'}} +A7c<(&Z::int_member)> *a18_3; // expected-error{{non-type template argument cannot be surrounded by parentheses}} + +template<unsigned char C> struct Overflow; // expected-note{{template parameter is declared here}} + +Overflow<5> *overflow1; // okay +Overflow<256> *overflow2; // expected-error{{non-type template argument value '256' is too large for template parameter of type 'unsigned char'}} + + +template<unsigned> struct Signedness; // expected-note{{template parameter is declared here}} +Signedness<10> *signedness1; // okay +Signedness<-10> *signedness2; // expected-error{{non-type template argument provides negative value '-10' for unsigned template parameter of type 'unsigned int'}} + +// Check canonicalization of template arguments. +template<int (*)(int, int)> struct FuncPtr0; +int func0(int, int); +extern FuncPtr0<&func0> *fp0; +template<int (*)(int, int)> struct FuncPtr0; +extern FuncPtr0<&func0> *fp0; +int func0(int, int); +extern FuncPtr0<&func0> *fp0; + diff --git a/test/SemaTemplate/temp_arg_template.cpp b/test/SemaTemplate/temp_arg_template.cpp new file mode 100644 index 000000000000..a5e9f75fa77a --- /dev/null +++ b/test/SemaTemplate/temp_arg_template.cpp @@ -0,0 +1,38 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +template<template<typename T> class X> struct A; // expected-note 2{{previous template template parameter is here}} + +template<template<typename T, int I> class X> struct B; // expected-note{{previous template template parameter is here}} + +template<template<int I> class X> struct C; // expected-note{{previous non-type template parameter with type 'int' is here}} + +template<class> struct X; // expected-note{{too few template parameters in template template argument}} +template<int N> struct Y; // expected-note{{template parameter has a different kind in template argument}} +template<long N> struct Ylong; // expected-note{{template non-type parameter has a different type 'long' in template argument}} + +namespace N { + template<class> struct Z; +} +template<class, class> struct TooMany; // expected-note{{too many template parameters in template template argument}} + + +A<X> *a1; +A<N::Z> *a2; +A< ::N::Z> *a3; + +A<Y> *a4; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}} +A<TooMany> *a5; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}} +B<X> *a6; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}} +C<Y> *a7; +C<Ylong> *a8; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}} + +template<typename T> void f(int); + +// FIXME: we're right to provide an error message, but it should say +// that we need a class template. We won't get this right until name +// lookup of 'f' returns a TemplateDecl. +A<f> *a9; // expected-error{{template argument for template template parameter must be a template}} + +// FIXME: The code below is ill-formed, because of the evil digraph '<:'. +// We should provide a much better error message than we currently do. +// A<::N::Z> *a10; diff --git a/test/SemaTemplate/temp_arg_type.cpp b/test/SemaTemplate/temp_arg_type.cpp new file mode 100644 index 000000000000..b322dae98b90 --- /dev/null +++ b/test/SemaTemplate/temp_arg_type.cpp @@ -0,0 +1,24 @@ +// RUN: clang-cc -fsyntax-only -verify %s +template<typename T> class A; // expected-note 2 {{template parameter is declared here}} + +// [temp.arg.type]p1 +A<0> *a1; // expected-error{{template argument for template type parameter must be a type}} + +A<A> *a2; // expected-error{{template argument for template type parameter must be a type}} + +A<int> *a3; +A<int()> *a4; +A<int(float)> *a5; +A<A<int> > *a6; + +// [temp.arg.type]p2 +void f() { + class X { }; + A<X> * a = 0; // expected-error{{template argument uses local type 'class X'}} +} + +struct { int x; } Unnamed; // expected-note{{unnamed type used in template argument was declared here}} +A<__typeof__(Unnamed)> *a7; // expected-error{{template argument uses unnamed type}} + +// FIXME: [temp.arg.type]p3. The check doesn't really belong here (it +// belongs somewhere in the template instantiation section). diff --git a/test/SemaTemplate/temp_class_spec.cpp b/test/SemaTemplate/temp_class_spec.cpp new file mode 100644 index 000000000000..df652b5ba38d --- /dev/null +++ b/test/SemaTemplate/temp_class_spec.cpp @@ -0,0 +1,20 @@ +// RUN: clang-cc -fsyntax-only -verify %s +template<typename T> +struct is_pointer { + static const bool value = false; +}; + +template<typename T> +struct is_pointer<T*> { + static const bool value = true; +}; + +template<typename T> +struct is_pointer<const T*> { + static const bool value = true; +}; + +int array0[is_pointer<int>::value? -1 : 1]; +int array1[is_pointer<int*>::value? 1 : -1]; +int array2[is_pointer<const int*>::value? 1 : -1]; // expected-error{{partial ordering}} \ +// expected-error{{negative}} diff --git a/test/SemaTemplate/temp_explicit.cpp b/test/SemaTemplate/temp_explicit.cpp new file mode 100644 index 000000000000..0292964a1a76 --- /dev/null +++ b/test/SemaTemplate/temp_explicit.cpp @@ -0,0 +1,111 @@ +// RUN: clang-cc -fsyntax-only -pedantic -verify %s +// +// Tests explicit instantiation of templates. +template<typename T, typename U = T> class X0 { }; + +namespace N { + template<typename T, typename U = T> class X1 { }; +} + +// Check the syntax of explicit instantiations. +template class X0<int, float>; +template class X0<int>; // expected-note{{previous}} + +template class N::X1<int>; +template class ::N::X1<int, float>; + +using namespace N; +template class X1<float>; + +// Check for some bogus syntax that probably means that the user +// wanted to write an explicit specialization, but forgot the '<>' +// after 'template'. +template class X0<double> { }; // expected-error{{explicit specialization}} + +// Check for explicit instantiations that come after other kinds of +// instantiations or declarations. +template class X0<int, int>; // expected-error{{duplicate}} + +template<> class X0<char> { }; // expected-note{{previous}} +template class X0<char>; // expected-warning{{ignored}} + +void foo(X0<short>) { } +template class X0<short>; + +// Check that explicit instantiations actually produce definitions. We +// determine whether this happens by placing semantic errors in the +// definition of the template we're instantiating. +template<typename T> struct X2; // expected-note{{declared here}} + +template struct X2<float>; // expected-error{{undefined template}} + +template<typename T> +struct X2 { + void f0(T*); // expected-error{{pointer to a reference}} +}; + +template struct X2<int>; // okay +template struct X2<int&>; // expected-note{{in instantiation of}} + +// Check that explicit instantiations instantiate member classes. +template<typename T> struct X3 { + struct Inner { + void f(T*); // expected-error{{pointer to a reference}} + }; +}; + +void f1(X3<int&>); // okay, Inner, not instantiated + +template struct X3<int&>; // expected-note{{instantiation}} + +template<typename T> struct X4 { + struct Inner { + struct VeryInner { + void f(T*); // expected-error 2{{pointer to a reference}} + }; + }; +}; + +void f2(X4<int&>); // okay, Inner, not instantiated +void f3(X4<int&>::Inner); // okay, Inner::VeryInner, not instantiated + +template struct X4<int&>; // expected-note{{instantiation}} +template struct X4<float&>; // expected-note{{instantiation}} + +// Check explicit instantiation of member classes +namespace N2 { + +template<typename T> +struct X5 { + struct Inner1 { + void f(T&); + }; + + struct Inner2 { + struct VeryInner { + void g(T*); // expected-error 2{{pointer to a reference}} + }; + }; +}; + +} + +template struct N2::X5<void>::Inner2; + +using namespace N2; +template struct X5<int&>::Inner2; // expected-note{{instantiation}} + +void f4(X5<float&>::Inner2); +template struct X5<float&>::Inner2; // expected-note{{instantiation}} + +namespace N3 { + template struct N2::X5<int>::Inner2; +} + +struct X6 { + struct Inner { // expected-note{{here}} + void f(); + }; +}; + +template struct X6::Inner; // expected-error{{non-templated}} diff --git a/test/SemaTemplate/temp_explicit_cxx0x.cpp b/test/SemaTemplate/temp_explicit_cxx0x.cpp new file mode 100644 index 000000000000..7045afc3032f --- /dev/null +++ b/test/SemaTemplate/temp_explicit_cxx0x.cpp @@ -0,0 +1,24 @@ +// RUN: clang-cc -fsyntax-only -std=c++0x -verify %s +namespace N1 { + + template<typename T> struct X0 { }; // expected-note{{here}} + + namespace Inner { + template<typename T> struct X1 { }; + } + + template struct X0<int>; + template struct Inner::X1<int>; +} + +template<typename T> struct X2 { }; // expected-note{{here}} + +template struct ::N1::Inner::X1<float>; + +namespace N2 { + using namespace N1; + + template struct X0<double>; // expected-error{{not in a namespace enclosing}} + + template struct X2<float>; // expected-error{{at global scope}} +} diff --git a/test/SemaTemplate/temp_param.cpp b/test/SemaTemplate/temp_param.cpp new file mode 100644 index 000000000000..c042f0849a04 --- /dev/null +++ b/test/SemaTemplate/temp_param.cpp @@ -0,0 +1,90 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +class X; + +// C++ [temp.param]p4 +typedef int INT; +enum E { enum1, enum2 }; +template<int N> struct A1; +template<INT N, INT M> struct A2; +template<enum E x, E y> struct A3; +template<int &X> struct A4; +template<int *Ptr> struct A5; +template<int (&f)(int, int)> struct A6; +template<int (*fp)(float, double)> struct A7; +template<int X::*pm> struct A8; +template<float (X::*pmf)(float, int)> struct A9; +template<typename T, T x> struct A10; + +template<float f> struct A11; // expected-error{{a non-type template parameter cannot have type 'float'}} + +template<void *Ptr> struct A12; // expected-error{{a non-type template parameter cannot have type 'void *'}} + +// C++ [temp.param]p8 +template<int X[10]> struct A5; +template<int f(float, double)> struct A7; + +// C++ [temp.param]p11: +template<typename> struct Y1; // expected-note{{too few template parameters in template template argument}} +template<typename, int> struct Y2; + +template<class T1 = int, // expected-note{{previous default template argument defined here}} + class T2> // expected-error{{template parameter missing a default argument}} + class B1; + +template<template<class> class = Y1, // expected-note{{previous default template argument defined here}} + template<class> class> // expected-error{{template parameter missing a default argument}} + class B1t; + +template<int N = 5, // expected-note{{previous default template argument defined here}} + int M> // expected-error{{template parameter missing a default argument}} + class B1n; + +// Check for bogus template parameter shadow warning. +template<template<class T> class, + template<class T> class> + class B1noshadow; + +// C++ [temp.param]p10: +template<class T1, class T2 = int> class B2; +template<class T1 = int, class T2> class B2; + +template<template<class, int> class, template<class> class = Y1> class B2t; +template<template<class, int> class = Y2, template<class> class> class B2t; + +template<int N, int M = 5> class B2n; +template<int N = 5, int M> class B2n; + +// C++ [temp.param]p12: +template<class T1, + class T2 = int> // expected-note{{previous default template argument defined here}} + class B3; +template<class T1, typename T2> class B3; +template<class T1, + typename T2 = float> // expected-error{{template parameter redefines default argument}} + class B3; + +template<template<class, int> class, + template<class> class = Y1> // expected-note{{previous default template argument defined here}} + class B3t; + +template<template<class, int> class, template<class> class> class B3t; + +template<template<class, int> class, + template<class> class = Y1> // expected-error{{template parameter redefines default argument}} + class B3t; + +template<int N, + int M = 5> // expected-note{{previous default template argument defined here}} + class B3n; + +template<int N, int M> class B3n; + +template<int N, + int M = 7> // expected-error{{template parameter redefines default argument}} + class B3n; + +// Check validity of default arguments +template<template<class, int> class // expected-note{{previous template template parameter is here}} + = Y1> // expected-error{{template template argument has different template parameters than its corresponding template template parameter}} + class C1; diff --git a/test/SemaTemplate/typename-specifier-2.cpp b/test/SemaTemplate/typename-specifier-2.cpp new file mode 100644 index 000000000000..99e628523158 --- /dev/null +++ b/test/SemaTemplate/typename-specifier-2.cpp @@ -0,0 +1,30 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +template<typename MetaFun, typename T> +struct bind_metafun { + typedef typename MetaFun::template apply<T> type; +}; + +struct add_pointer { + template<typename T> + struct apply { + typedef T* type; + }; +}; + +int i; +// FIXME: if we make the declarator below a pointer (e.g., with *ip), +// the error message isn't so good because we don't get the handy +// 'aka' telling us that we're dealing with an int**. Should we fix +// getDesugaredType to dig through pointers and such? +bind_metafun<add_pointer, int>::type::type ip = &i; +bind_metafun<add_pointer, float>::type::type fp = &i; // expected-error{{incompatible type initializing 'int *', expected 'bind_metafun<add_pointer, float>::type::type' (aka 'float *')}} + + +template<typename T> +struct extract_type_type { + typedef typename T::type::type t; +}; + +double d; +extract_type_type<bind_metafun<add_pointer, double> >::t dp = &d; diff --git a/test/SemaTemplate/typename-specifier.cpp b/test/SemaTemplate/typename-specifier.cpp new file mode 100644 index 000000000000..d3fca3eacad5 --- /dev/null +++ b/test/SemaTemplate/typename-specifier.cpp @@ -0,0 +1,74 @@ +// RUN: clang-cc -fsyntax-only -verify %s +namespace N { + struct A { + typedef int type; + }; + + struct B { + }; + + struct C { + struct type { }; + int type; // expected-note 2{{referenced member 'type' is declared here}} + }; +} + +int i; + +typename N::A::type *ip1 = &i; +typename N::B::type *ip2 = &i; // expected-error{{ no type named 'type' in 'B'}} +typename N::C::type *ip3 = &i; // expected-error{{typename specifier refers to non-type member 'type'}} + +void test(double d) { + typename N::A::type f(typename N::A::type(a)); // expected-warning{{parentheses were disambiguated as a function declarator}} + int five = f(5); + + using namespace N; + for (typename A::type i = 0; i < 10; ++i) + five += 1; + + const typename N::A::type f2(d); +} + +namespace N { + template<typename T> + struct X { + typedef typename T::type type; // expected-error 2{{no type named 'type' in 'B'}} \ + // FIXME: location info for error above isn't very good \ + // expected-error 2{{typename specifier refers to non-type member 'type'}} \ + // expected-error{{type 'int' cannot be used prior to '::' because it has no members}} + }; +} + +N::X<N::A>::type *ip4 = &i; +N::X<N::B>::type *ip5 = &i; // expected-note{{in instantiation of template class 'struct N::X<struct N::B>' requested here}} \ +// expected-error{{unknown type name 'type'}} +N::X<N::C>::type *ip6 = &i; // expected-note{{in instantiation of template class 'struct N::X<struct N::C>' requested here}} \ +// expected-error{{unknown type name 'type'}} + +N::X<int>::type fail1; // expected-note{{in instantiation of template class 'struct N::X<int>' requested here}} \ +// expected-error{{unknown type name 'type'}} + +template<typename T> +struct Y { + typedef typename N::X<T>::type *type; // expected-note{{in instantiation of template class 'struct N::X<struct B>' requested here}} \ + // expected-note{{in instantiation of template class 'struct N::X<struct C>' requested here}} +}; + +struct A { + typedef int type; +}; + +struct B { +}; + +struct C { + struct type { }; + int type; // expected-note{{referenced member 'type' is declared here}} +}; + +::Y<A>::type ip7 = &i; +::Y<B>::type ip8 = &i; // expected-note{{in instantiation of template class 'struct Y<struct B>' requested here}} \ +// expected-error{{unknown type name 'type'}} +::Y<C>::type ip9 = &i; // expected-note{{in instantiation of template class 'struct Y<struct C>' requested here}} \ +// expected-error{{unknown type name 'type'}} |