diff options
Diffstat (limited to 'test/SemaTemplate')
22 files changed, 917 insertions, 38 deletions
diff --git a/test/SemaTemplate/alias-templates.cpp b/test/SemaTemplate/alias-templates.cpp index b7078353ff1b3..bcdc84e19f7e7 100644 --- a/test/SemaTemplate/alias-templates.cpp +++ b/test/SemaTemplate/alias-templates.cpp @@ -220,6 +220,23 @@ namespace PR14858 { template<typename ...T, typename ...U> void h(X<T...> &) {} template<typename ...T, typename ...U> void h(X<U...> &) {} // ok, different + + template<typename ...T> void i(auto (T ...t) -> int(&)[sizeof...(t)]); + auto mk_arr(int, int) -> int(&)[2]; + void test_i() { i<int, int>(mk_arr); } + +#if 0 // FIXME: This causes clang to assert. + template<typename ...T> using Z = auto (T ...p) -> int (&)[sizeof...(p)]; + template<typename ...T, typename ...U> void j(Z<T..., U...> &) {} + void test_j() { j<int, int>(mk_arr); } +#endif + + template<typename ...T> struct Q { + template<typename ...U> using V = int[sizeof...(U)]; + template<typename ...U> void f(V<typename U::type..., typename T::type...> *); + }; + struct B { typedef int type; }; + void test_q(int (&a)[5]) { Q<B, B, B>().f<B, B>(&a); } } namespace redecl { diff --git a/test/SemaTemplate/array-redeclaration.cpp b/test/SemaTemplate/array-redeclaration.cpp new file mode 100644 index 0000000000000..4edee701cfc46 --- /dev/null +++ b/test/SemaTemplate/array-redeclaration.cpp @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// expected-no-diagnostics + +extern int array[1]; + +template <typename> +class C { + enum { D }; +public: + template <typename A> void foo1() { + extern int array[((int)C<A>::k > (int)D) ? 1 : -1]; + } +}; + +template<> +class C<int> { +public: + const static int k = 2; +}; + +void foo2() { + C<char> c; + c.foo1<int>(); +} + +template<int n> +void foo3() { + extern int array[n ? 1 : -1]; +} + +void foo4() { + foo3<5>(); +} diff --git a/test/SemaTemplate/class-template-decl.cpp b/test/SemaTemplate/class-template-decl.cpp index 63482d84df0c9..2e36cae14f600 100644 --- a/test/SemaTemplate/class-template-decl.cpp +++ b/test/SemaTemplate/class-template-decl.cpp @@ -10,11 +10,11 @@ namespace N { template<typename T> class C; } -extern "C" { +extern "C" { // expected-note {{extern "C" language linkage specification begins here}} template<typename T> class D; // expected-error{{templates must have C++ linkage}} } -extern "C" { +extern "C" { // expected-note 2 {{extern "C" language linkage specification begins here}} class PR17968 { template<typename T> class D; // expected-error{{templates must have C++ linkage}} template<typename T> void f(); // expected-error{{templates must have C++ linkage}} @@ -148,7 +148,7 @@ namespace redecl { } extern "C" template <typename T> // expected-error{{templates must have C++ linkage}} -void DontCrashOnThis() { +void DontCrashOnThis() { // expected-note@-1 {{extern "C" language linkage specification begins here}} T &pT = T(); pT; } diff --git a/test/SemaTemplate/class-template-spec.cpp b/test/SemaTemplate/class-template-spec.cpp index 86cace19dbfbc..518ec78e6f7d0 100644 --- a/test/SemaTemplate/class-template-spec.cpp +++ b/test/SemaTemplate/class-template-spec.cpp @@ -137,12 +137,16 @@ namespace PR18009 { A<int>::S<8, sizeof(int)> a; // ok template <typename T> struct B { - template <int N, int M> struct S; // expected-note {{declared here}} - template <int N> struct S<N, sizeof(T) + - N // expected-error {{non-type template argument depends on a template parameter of the partial specialization}} - > {}; + template <int N, int M> struct S; + template <int N> struct S<N, sizeof(T) + N> {}; // ok (dr1315) }; - B<int>::S<8, sizeof(int) + 8> s; // expected-error {{undefined}} + B<int>::S<8, sizeof(int) + 8> b; + + template <typename T> struct C { + template <int N, int M> struct S; + template <int N> struct S<N, N ? **(T(*)[N])0 : 0> {}; // expected-error {{depends on a template parameter of the partial specialization}} + }; + C<int> c; // expected-note {{in instantiation of}} template<int A> struct outer { template<int B, int C> struct inner {}; @@ -167,10 +171,16 @@ namespace PR16519 { // expected-warning@-2 {{variadic templates are a C++11 extension}} #endif - template<typename T, T ...N, T ...Extra> struct __make_integer_sequence_impl<integer_sequence<T, N...>, Extra...> { + // Note that the following seemingly-equivalent template parameter list is + // not OK; it would result in a partial specialization that is not more + // specialized than the primary template. (See NTTPTypeVsPartialOrder below.) + // + // template<typename T, T ...N, T ...Extra> + template<typename T, T ...N, typename integer_sequence<T, N...>::value_type ...Extra> #if __cplusplus <= 199711L - // expected-warning@-2 2 {{variadic templates are a C++11 extension}} + // expected-warning@-2 2{{variadic templates are a C++11 extension}} #endif + struct __make_integer_sequence_impl<integer_sequence<T, N...>, Extra...> { typedef integer_sequence<T, N..., sizeof...(N) + N..., Extra...> type; }; @@ -193,13 +203,32 @@ namespace PR16519 { #endif } +namespace NTTPTypeVsPartialOrder { + struct X { typedef int value_type; }; + template<typename T> struct Y { typedef T value_type; }; + + template<typename T, typename T::value_type N> struct A; // expected-note {{template}} + template<int N> struct A<X, N> {}; + template<typename T, T N> struct A<Y<T>, N> {}; // expected-error {{not more specialized}} expected-note {{'T' vs 'typename Y<type-parameter-0-0>::value_type'}} + A<X, 0> ax; + A<Y<int>, 0> ay; + + + template<int, typename T, typename T::value_type> struct B; // expected-note {{template}} + template<typename T, typename T::value_type N> struct B<0, T, N>; // expected-note {{matches}} + template<int N> struct B<0, X, N> {}; + template<typename T, T N> struct B<0, Y<T>, N> {}; // expected-error {{not more specialized}} expected-note {{'T' vs 'typename Y<type-parameter-0-0>::value_type'}} expected-note {{matches}} + B<0, X, 0> bx; + B<0, Y<int>, 0> by; // expected-error {{ambiguous}} +} + namespace DefaultArgVsPartialSpec { // Check that the diagnostic points at the partial specialization, not just at // the default argument. template<typename T, int N = - sizeof(T) // expected-note {{template parameter is used in default argument declared here}} + sizeof(T) // ok (dr1315) > struct X {}; - template<typename T> struct X<T> {}; // expected-error {{non-type template argument depends on a template parameter of the partial specialization}} + template<typename T> struct X<T> {}; template<typename T, T N = 0 // expected-note {{template parameter is declared here}} diff --git a/test/SemaTemplate/cxx1z-decomposition.cpp b/test/SemaTemplate/cxx1z-decomposition.cpp new file mode 100644 index 0000000000000..779c4cf75e9db --- /dev/null +++ b/test/SemaTemplate/cxx1z-decomposition.cpp @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -std=c++1z -verify %s + +struct A { int x, y; }; +typedef int B[2]; +struct C { template<int> int get(); }; +struct D { int x, y, z; }; +struct E { int *p, n; }; + +namespace std { + using size_t = decltype(sizeof(0)); + template<typename> struct tuple_size; + template<size_t, typename> struct tuple_element { using type = int; }; +} + +template<> struct std::tuple_size<C> { enum { value = 2 }; }; + +template<typename T> int decomp(T &t) { + auto &[a, b] = t; // expected-error {{type 'D' decomposes into 3 elements, but only 2 names were provided}} + return a + b; // expected-error {{cannot initialize return object of type 'int' with an rvalue of type 'int *'}} +} + +void test() { + A a; + B b; + C c; + D d; + E e; + decomp(a); + decomp(b); + decomp(c); + decomp(d); // expected-note {{in instantiation of}} + decomp(e); // expected-note {{in instantiation of}} +} diff --git a/test/SemaTemplate/cxx1z-using-declaration.cpp b/test/SemaTemplate/cxx1z-using-declaration.cpp new file mode 100644 index 0000000000000..7bef36db1f47a --- /dev/null +++ b/test/SemaTemplate/cxx1z-using-declaration.cpp @@ -0,0 +1,230 @@ +// RUN: %clang_cc1 -std=c++1z -verify %s + +// Test that we cope with failure to expand a pack. +template<typename ...T> struct Unexpanded : T... { + using T::f; // expected-error {{unexpanded}} + using typename T::type; // expected-error {{unexpanded}} + template<typename ...U> void g(U ...u) { f(u...); } // expected-error {{undeclared identifier 'f'}} + void h() { + Unexpanded<type...> *p; // expected-error {{undeclared identifier 'type'}} + } +}; +void test_Unexpanded() { + struct A { void f(); }; // expected-note {{must qualify}} + struct B { void f(int); }; // expected-note {{must qualify}} + Unexpanded<A, B>().g(0); // expected-note {{instantiation of}} +} + +// Test using non-type members from pack of base classes. +template<typename ...T> struct A : T... { // expected-note 2{{candidate}} + using T::T ...; // expected-note 6{{inherited here}} + using T::operator() ...; + using T::operator T* ...; + using T::h ...; + + void f(int n) { h(n); } // expected-error {{ambiguous}} + void f(int n, int m) { h(n, m); } // expected-error {{member using declaration 'h' instantiates to an empty pack}} + void g(int n) { (*this)(n); } // expected-error {{ambiguous}} + void g(int n, int m) { (*this)(n, m); } // expected-error {{does not provide a call operator}} +}; + +namespace test_A { + struct X { // expected-note 2{{candidate}} + X(); + X(int); // expected-note {{candidate}} + void operator()(int); // expected-note 2{{candidate}} + operator X *(); + void h(int); // expected-note {{candidate}} + }; + struct Y { + Y(); + Y(int, int); + void operator()(int, int); + operator Y *(); + void h(int, int); // expected-note {{not viable}} + }; + struct Z { // expected-note 2{{candidate}} + Z(); + Z(int); // expected-note {{candidate}} + void operator()(int); // expected-note 2{{candidate}} + operator Z *(); + void h(int); // expected-note {{candidate}} + }; + + void f() { + A<> a; + a.f(0, 0); // expected-note {{instantiation of}} + a.g(0, 0); // expected-note {{instantiation of}} + + A<X, Y> axy(0); + A<X, Y>(0, 0); + axy.f(0); + axy.f(0, 0); + axy.g(0); + axy.g(0, 0); + axy(0); + axy(0, 0); + + A<X, Y, Z>(0); // expected-error {{ambiguous}} + A<X, Y, Z> axyz(0, 0); + axyz.f(0); // expected-note {{instantiation of}} + axyz.f(0, 0); + axyz.g(0); // expected-note {{instantiation of}} + axyz.g(0, 0); + axyz(0); // expected-error {{ambiguous}} + axyz(0, 0); + + X *x; + x = a; // expected-error {{incompatible}} + x = axy; + x = axyz; + x = a.operator X*(); // expected-error {{no member}} + x = axy.operator X*(); + x = axyz.operator X*(); + + Z *z; + z = axyz; + z = axyz.operator Z*(); + } +} + +// Test using pack of non-type members from single base class. +template<typename X, typename Y, typename ...T> struct B : X, Y { + using X::operator T* ...; +}; + +namespace test_B { + struct X { operator int*(); operator float*(); operator char*(); }; // expected-note {{candidate}} + struct Y { operator int*(); operator float*(); operator char*(); }; // expected-note {{candidate}} + B<X, Y, int, float> bif; + int *pi = bif; + float *pf = bif; + char *pc = bif; // expected-error {{ambiguous}} +} + +// Test using type member from pack of base classes. +template<typename ...T> struct C : T... { + using typename T::type ...; // expected-error {{target of using declaration conflicts}} + void f() { type value; } // expected-error {{member using declaration 'type' instantiates to an empty pack}} +}; + +namespace test_C { + struct X { typedef int type; }; + struct Y { typedef int type; }; // expected-note {{conflicting}} + struct Z { typedef float type; }; // expected-note {{target}} + + void f() { + C<> c; + c.f(); // expected-note {{instantiation of}} + + C<X, Y> cxy; + cxy.f(); + + C<X, Y, Z> cxyz; // expected-note {{instantiation of}} + cxyz.f(); + } +} + +// Test using pack of non-types at block scope. +template<typename ...T> int fn1() { + using T::e ...; // expected-error 2{{class member}} expected-note 2{{instead}} + // expected-error@-1 2{{produces multiple values}} + return e; // expected-error {{using declaration 'e' instantiates to an empty pack}} +} + +namespace test_fn1 { + struct X { static int e; }; + struct Y { typedef int e; }; + inline namespace P { enum E { e }; } + inline namespace Q { enum F { e }; } + void f() { + fn1<>(); // expected-note {{instantiation of}} + fn1<X>(); // expected-note {{instantiation of}} + fn1<Y>(); // expected-note {{instantiation of}} + fn1<E>(); + fn1<E, F>(); // expected-note {{instantiation of}} + fn1<E, X>(); // expected-note {{instantiation of}} + } +} + +// Test using pack of types at block scope. +template<typename ...T> void fn2() { + // This cannot ever be valid: in order for T::type to be a type, T must be a + // class, and a class member cannot be named by a block-scope using declaration. + using typename T::type ...; // expected-error {{class member}} + type x; // expected-error {{unknown type name 'type'}} +} + +// Test partial substitution into class-scope pack. +template<typename ...T> auto lambda1() { + return [](auto x) { + struct A : T::template X<decltype(x)>... { // expected-note 1+{{instantiation of}} + using T::template X<decltype(x)>::f ...; + using typename T::template X<decltype(x)>::type ...; + void g(int n) { f(n); } // expected-error {{empty pack}} expected-error {{expected 2, have 1}} expected-error {{ambiguous}} + void h() { type value; } // expected-error {{empty pack}} + }; + return A(); + }; +} + +namespace test_lambda1 { + struct A { + template<typename> struct X { + void f(int); // expected-note {{candidate}} + using type = int; + }; + }; + struct B { + template<typename> struct X { + void f(int, int); // expected-note {{declared here}} expected-note {{not viable}} + using type = int; + }; + }; + struct C { + template<typename> struct X { + void f(int); // expected-note {{candidate}} + void f(int, int); // expected-note {{not viable}} + using type = int; + }; + }; + + void f() { + lambda1<>() // expected-note 2{{instantiation of}} + (0) + // FIXME: This is poor error recovery + .g(0); // expected-error {{no member named 'g'}} + lambda1<A>() + (0) + .g(0); + lambda1<B>() + (0) // expected-note {{instantiation of}} + .g(0); + lambda1<A, B, C>() + (0) // expected-note {{instantiation of}} + .g(0); + } +} + +namespace p0195r2_example { + template<typename ...Ts> + struct Overloader : Ts... { + using Ts::operator() ...; + }; + + template<typename ...Ts> + constexpr auto make_overloader(Ts &&...ts) { + return Overloader<Ts...>{static_cast<Ts&&>(ts)...}; + } + + void test() { + auto o = make_overloader( + [&](int &r) -> int & { return r; }, // expected-note {{candidate function}} + [&](float &r) -> float & { return r; } // expected-note {{candidate function}} + ); + int a; float f; double d; + int &ra = o(a); + float &rf = o(f); + double &rd = o(d); // expected-error {{no matching function}} + } +} diff --git a/test/SemaTemplate/deduction.cpp b/test/SemaTemplate/deduction.cpp index d024c3147735a..9471bac91c308 100644 --- a/test/SemaTemplate/deduction.cpp +++ b/test/SemaTemplate/deduction.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11 +// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++1z // Template argument deduction with template template parameters. template<typename T, template<T> class A> @@ -264,4 +265,86 @@ int main() { return 0; } } // end ns2 -}
\ No newline at end of file +} + +namespace multiple_deduction_different_type { + template<typename T, T v> struct X {}; + template<template<typename T, T> class X, typename T, typename U, int N> + void f(X<T, N>, X<U, N>) {} // expected-note 2{{values of conflicting types}} + template<template<typename T, T> class X, typename T, typename U, const int *N> + void g(X<T, N>, X<U, N>) {} // expected-note 0-2{{values of conflicting types}} + int n; + void h() { + f(X<int, 1+1>(), X<unsigned int, 3-1>()); // expected-error {{no matching function}} + f(X<unsigned int, 1+1>(), X<int, 3-1>()); // expected-error {{no matching function}} +#if __cplusplus > 201402L + g(X<const int*, &n>(), X<int*, &n + 1 - 1>()); // expected-error {{no matching function}} + g(X<int*, &n>(), X<const int*, &n + 1 - 1>()); // expected-error {{no matching function}} +#endif + } + + template<template<typename T, T> class X, typename T, typename U, T N> + void x(X<T, N>, int(*)[N], X<U, N>) {} // expected-note 1+{{candidate}} + template<template<typename T, T> class X, typename T, typename U, T N> + void x(int(*)[N], X<T, N>, X<U, N>) {} // expected-note 1+{{candidate}} + int arr[3]; + void y() { + x(X<int, 3>(), &arr, X<int, 3>()); + x(&arr, X<int, 3>(), X<int, 3>()); + + x(X<int, 3>(), &arr, X<char, 3>()); // expected-error {{no matching function}} + x(&arr, X<int, 3>(), X<char, 3>()); // expected-error {{no matching function}} + + x(X<char, 3>(), &arr, X<char, 3>()); + x(&arr, X<char, 3>(), X<char, 3>()); + } +} + +namespace nullptr_deduction { + using nullptr_t = decltype(nullptr); + + template<typename T, T v> struct X {}; + template<typename T, T v> void f(X<T, v>) { + static_assert(!v, ""); + } + void g() { + f(X<int*, nullptr>()); + f(X<nullptr_t, nullptr>()); + } + + template<template<typename T, T> class X, typename T, typename U, int *P> + void f1(X<T, P>, X<U, P>) {} // expected-note 2{{values of conflicting types}} + void h() { + f1(X<int*, nullptr>(), X<nullptr_t, nullptr>()); // expected-error {{no matching function}} + f1(X<nullptr_t, nullptr>(), X<int*, nullptr>()); // expected-error {{no matching function}} + } + + template<template<typename T, T> class X, typename T, typename U, nullptr_t P> + void f2(X<T, P>, X<U, P>) {} // expected-note 2{{values of conflicting types}} + void i() { + f2(X<int*, nullptr>(), X<nullptr_t, nullptr>()); // expected-error {{no matching function}} + f2(X<nullptr_t, nullptr>(), X<int*, nullptr>()); // expected-error {{no matching function}} + } +} + +namespace member_pointer { + struct A { void f(int); }; + template<typename T, void (A::*F)(T)> struct B; + template<typename T> struct C; + template<typename T, void (A::*F)(T)> struct C<B<T, F>> { + C() { A a; T t; (a.*F)(t); } + }; + C<B<int, &A::f>> c; +} + +namespace deduction_substitution_failure { + template<typename T> struct Fail { typedef typename T::error error; }; // expected-error 2{{prior to '::'}} + + template<typename T, typename U> struct A {}; + template<typename T> struct A<T, typename Fail<T>::error> {}; // expected-note {{instantiation of}} + A<int, int> ai; // expected-note {{during template argument deduction for class template partial specialization 'A<T, typename Fail<T>::error>' [with T = int]}} + + template<typename T, typename U> int B; // expected-warning 0-1 {{extension}} + template<typename T> int B<T, typename Fail<T>::error> {}; // expected-note {{instantiation of}} + int bi = B<char, char>; // expected-note {{during template argument deduction for variable template partial specialization 'B<T, typename Fail<T>::error>' [with T = char]}} +} diff --git a/test/SemaTemplate/default-expr-arguments-3.cpp b/test/SemaTemplate/default-expr-arguments-3.cpp new file mode 100644 index 0000000000000..9dc3b134300ac --- /dev/null +++ b/test/SemaTemplate/default-expr-arguments-3.cpp @@ -0,0 +1,55 @@ +// RUN: %clang_cc1 -std=c++14 -verify -ast-dump %s | FileCheck %s +// expected-no-diagnostics + +// CHECK: FunctionDecl {{.*}} used func 'void (void)' +// CHECK-NEXT: TemplateArgument type 'int' +// CHECK: LambdaExpr {{.*}} 'class (lambda at +// CHECK: ParmVarDecl {{.*}} used f 'enum foo' cinit +// CHECK-NEXT: DeclRefExpr {{.*}} 'enum foo' EnumConstant {{.*}} 'a' 'enum foo' + +namespace PR28795 { + template<typename T> + void func() { + enum class foo { a, b }; + auto bar = [](foo f = foo::a) { return f; }; + bar(); + } + + void foo() { + func<int>(); + } +} + +// CHECK: ClassTemplateSpecializationDecl {{.*}} struct class2 definition +// CHECK-NEXT: TemplateArgument type 'int' +// CHECK: LambdaExpr {{.*}} 'class (lambda at +// CHECK: ParmVarDecl {{.*}} used f 'enum foo' cinit +// CHECK-NEXT: DeclRefExpr {{.*}} 'enum foo' EnumConstant {{.*}} 'a' 'enum foo' + +// Template struct case: +template <class T> struct class2 { + void bar() { + enum class foo { a, b }; + [](foo f = foo::a) { return f; }(); + } +}; + +template struct class2<int>; + +// CHECK: FunctionTemplateDecl {{.*}} f1 +// CHECK-NEXT: TemplateTypeParmDecl {{.*}} typename T +// CHECK-NEXT: FunctionDecl {{.*}} f1 'void (void)' +// CHECK: FunctionDecl {{.*}} f1 'void (void)' +// CHECK-NEXT: TemplateArgument type 'int' +// CHECK: ParmVarDecl {{.*}} n 'enum foo' cinit +// CHECK-NEXT: DeclRefExpr {{.*}} 'enum foo' EnumConstant {{.*}} 'a' 'enum foo' + +template<typename T> +void f1() { + enum class foo { a, b }; + struct S { + int g1(foo n = foo::a); + }; +} + +template void f1<int>(); diff --git a/test/SemaTemplate/dependent-type-identity.cpp b/test/SemaTemplate/dependent-type-identity.cpp index 6b23a38f84863..c826268c864c4 100644 --- a/test/SemaTemplate/dependent-type-identity.cpp +++ b/test/SemaTemplate/dependent-type-identity.cpp @@ -80,11 +80,20 @@ namespace PR6851 { S< S<w>::cond && 1 > foo(); }; + struct Arrow { Arrow *operator->(); int n; }; + template<typename T> struct M { + Arrow a; + auto f() -> M<decltype(a->n)>; + }; + struct Alien; bool operator&&(const Alien&, const Alien&); template <bool w> S< S<w>::cond && 1 > N::foo() { } + + template<typename T> + auto M<T>::f() -> M<decltype(a->n)> {} } namespace PR7460 { diff --git a/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp b/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp index 6e8323d1ee2ca..c5290efafc1ab 100644 --- a/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp +++ b/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp @@ -30,8 +30,6 @@ template<unsigned N> struct S { // expected-error {{no member named 'recurse'}} \ // expected-note 9{{instantiation of exception spec}} }; -decltype(S<0>::recurse()) *pVoid1 = 0; // ok, exception spec not needed -decltype(&S<0>::recurse) pFn = 0; // ok, exception spec not needed template<> struct S<10> {}; void (*pFn2)() noexcept = &S<0>::recurse; // expected-note {{instantiation of exception spec}} expected-error {{not superset}} @@ -39,7 +37,7 @@ void (*pFn2)() noexcept = &S<0>::recurse; // expected-note {{instantiation of ex namespace dr1330_example { template <class T> struct A { - void f(...) throw (typename T::X); // expected-error {{'int'}} + void f(...) throw (typename T::X); void f(int); }; @@ -48,16 +46,14 @@ namespace dr1330_example { } struct S { - template<typename T> - static int f() noexcept(noexcept(A<T>().f("boo!"))) { return 0; } // \ - // expected-note {{instantiation of exception spec}} - typedef decltype(f<S>()) X; + template<typename T> static void f() throw(typename T::X); + typedef decltype(f<S>()) X; // expected-error {{exception specification is not available}} }; - int test2() { - S().f<S>(); // ok - S().f<int>(); // expected-note {{instantiation of exception spec}} - } + struct T { + template<typename T> static void f() throw(T**); + typedef decltype(f<S>()) X; // expected-error {{exception specification is not available}} + }; template<typename T> struct U { diff --git a/test/SemaTemplate/instantiation-default-1.cpp b/test/SemaTemplate/instantiation-default-1.cpp index 99154a5cc4606..ab9eca75e239b 100644 --- a/test/SemaTemplate/instantiation-default-1.cpp +++ b/test/SemaTemplate/instantiation-default-1.cpp @@ -36,7 +36,7 @@ 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<const int>'}} +template<> struct Def1<const int> { }; // expected-error{{redefinition of 'Def1<const int, const int>'}} template<typename T, typename T2 = T&> struct Def3; diff --git a/test/SemaTemplate/instantiation-depth-default.cpp b/test/SemaTemplate/instantiation-depth-default.cpp new file mode 100644 index 0000000000000..3d89aa18ca438 --- /dev/null +++ b/test/SemaTemplate/instantiation-depth-default.cpp @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -ftemplate-backtrace-limit 2 %s +// +// FIXME: Disable this test when Clang was built with ASan, because ASan +// increases our per-frame stack usage enough that this test no longer fits +// within our normal stack space allocation. +// REQUIRES: not_asan + +template<int N, typename T> struct X : X<N+1, T*> {}; +// expected-error-re@8 {{recursive template instantiation exceeded maximum depth of 1024{{$}}}} +// expected-note@8 {{instantiation of template class}} +// expected-note@8 {{skipping 1023 contexts in backtrace}} +// expected-note@8 {{use -ftemplate-depth=N to increase recursive template instantiation depth}} + +X<0, int> x; // expected-note {{in instantiation of}} + +// FIXME: It crashes. Investigating. +// UNSUPPORTED: mingw32 diff --git a/test/SemaTemplate/ms-class-specialization-class-scope.cpp b/test/SemaTemplate/ms-class-specialization-class-scope.cpp index 3ebb1c9c555ea..fc51c23a34e91 100644 --- a/test/SemaTemplate/ms-class-specialization-class-scope.cpp +++ b/test/SemaTemplate/ms-class-specialization-class-scope.cpp @@ -19,7 +19,7 @@ public: X<double>::y c; template<> struct X<float> {}; // expected-note {{previous definition is here}} - template<> struct X<float> {}; // expected-error {{redefinition of 'A::X<float>'}} + template<> struct X<float> {}; // expected-error {{redefinition of 'X<float>'}} }; A::X<void>::x axv; diff --git a/test/SemaTemplate/temp_arg_enum_printing.cpp b/test/SemaTemplate/temp_arg_enum_printing.cpp index a788975b20dd9..bdf277d308c3d 100644 --- a/test/SemaTemplate/temp_arg_enum_printing.cpp +++ b/test/SemaTemplate/temp_arg_enum_printing.cpp @@ -13,11 +13,11 @@ template <NamedEnum E> void foo(); void test() { - // CHECK: template <NamedEnumNS::NamedEnum E = NamedEnumNS::NamedEnum::Val0> + // CHECK: template<> void foo<NamedEnumNS::NamedEnum::Val0>() NamedEnumNS::foo<Val0>(); - // CHECK: template <NamedEnumNS::NamedEnum E = NamedEnumNS::NamedEnum::Val1> + // CHECK: template<> void foo<NamedEnumNS::NamedEnum::Val1>() NamedEnumNS::foo<(NamedEnum)1>(); - // CHECK: template <NamedEnumNS::NamedEnum E = 2> + // CHECK: template<> void foo<2>() NamedEnumNS::foo<(NamedEnum)2>(); } diff --git a/test/SemaTemplate/temp_arg_nontype.cpp b/test/SemaTemplate/temp_arg_nontype.cpp index 91b0c6e765088..93f11b5657d03 100644 --- a/test/SemaTemplate/temp_arg_nontype.cpp +++ b/test/SemaTemplate/temp_arg_nontype.cpp @@ -364,3 +364,90 @@ namespace PR17696 { b<&a::i> c; // okay } + +namespace partial_order_different_types { + // These are unordered because the type of the final argument doesn't match. + template<int, int, typename T, typename, T> struct A; // expected-note {{here}} + template<int N, typename T, typename U, T V> struct A<0, N, T, U, V> {}; // expected-note {{matches}} + template<typename T, typename U, U V> struct A<0, 0, T, U, V> {}; // expected-note {{matches}} + // expected-error@-1 {{not more specialized than the primary}} + // expected-note@-2 {{deduced non-type template argument does not have the same type as the corresponding template parameter ('U' vs 'type-parameter-0-0')}} + A<0, 0, int, int, 0> a; // expected-error {{ambiguous partial specializations}} +} + +namespace partial_order_references { + // FIXME: The standard does not appear to consider the second specialization + // to be more more specialized than the first! The problem is that deducing + // an 'int&' parameter from an argument 'R' results in a type mismatch, + // because the parameter has a reference type and the argument is an + // expression and thus does not have reference type. We resolve this by + // matching the type of an expression corresponding to the parameter rather + // than matching the parameter itself. + template <int, int, int &> struct A {}; + template <int N, int &R> struct A<N, 0, R> {}; + template <int &R> struct A<0, 0, R> {}; + int N; + A<0, 0, N> a; + + template<int, int &R> struct B; // expected-note 2{{template}} + template<const int &R> struct B<0, R> {}; + // expected-error@-1 {{not more specialized than the primary}} + // expected-note@-2 {{'const int' vs 'int &'}} + B<0, N> b; // expected-error {{undefined}} + + template<int, const int &R> struct C; // expected-note 2{{template}} + template<int &R> struct C<0, R> {}; + // expected-error@-1 {{not more specialized than the primary}} + // expected-note@-2 {{'int' vs 'const int &'}} + C<0, N> c; // expected-error {{undefined}} + + template<int, const int &R> struct D; // expected-note 2{{template}} + template<int N> struct D<0, N> {}; + // expected-error@-1 {{not more specialized than the primary}} + // expected-note@-2 {{'int' vs 'const int &'}} + extern const int K = 5; + D<0, K> d; // expected-error {{undefined}} +} + +namespace dependent_nested_partial_specialization { + template<typename> using X = int; // expected-warning {{C++11}} + template<typename T> using Y = T*; // expected-warning {{C++11}} + int n; + + template<template<typename> class X> struct A { + template<typename T, X<T> N> struct B; // expected-note 2{{here}} + template<typename T> struct B<T, 0> {}; // expected-error {{specializes a template parameter with dependent type 'Y<T>'}} + }; + A<X>::B<int, 0> ax; + A<Y>::B<int, &n> ay; // expected-error {{undefined}} expected-note {{instantiation of}} + + template<template<typename> class X> struct C { + template<typename T, int N, int M> struct D; // expected-note {{here}} + template<typename T, X<T> N> struct D<T*, N, N + 1> {}; // expected-error {{type of specialized non-type template argument depends on}} + }; + C<X>::D<int*, 0, 1> cx; + C<Y>::D<int*, 0, 1> cy; // expected-error {{undefined}} expected-note {{instantiation of}} + + template<typename T> struct E { + template<typename U, U V> struct F; // expected-note {{template}} + template<typename W, T V> struct F<W, V> {}; // expected-error {{not more specialized than the primary}} expected-note {{does not have the same type}} + }; + E<int>::F<int, 0> e1; // expected-note {{instantiation of}} +} + +namespace nondependent_default_arg_ordering { + int n, m; + template<typename A, A B = &n> struct X {}; + template<typename A> void f(X<A>); // expected-note {{candidate}} + template<typename A> void f(X<A, &m>); // expected-note {{candidate}} + template<typename A, A B> void f(X<A, B>); // expected-note 2{{candidate}} + template<template<typename U, U> class T, typename A, int *B> void f(T<A, B>); // expected-note 2{{candidate}} + void g() { + // FIXME: The first and second function templates above should be + // considered more specialized than the last two, but during partial + // ordering we fail to check that we actually deduced template arguments + // that make the deduced A identical to A. + X<int *, &n> x; f(x); // expected-error {{ambiguous}} + X<int *, &m> y; f(y); // expected-error {{ambiguous}} + } +} diff --git a/test/SemaTemplate/temp_arg_nontype_cxx11.cpp b/test/SemaTemplate/temp_arg_nontype_cxx11.cpp index 15c9c2560a964..cfaad0cd0c96f 100644 --- a/test/SemaTemplate/temp_arg_nontype_cxx11.cpp +++ b/test/SemaTemplate/temp_arg_nontype_cxx11.cpp @@ -23,3 +23,16 @@ namespace CanonicalNullptr { B<int> b = MakeB<int>(); C<int> c = MakeC<int>(); } + +namespace Auto { + template<auto> struct A { }; // expected-error {{until C++1z}} +} + +namespace check_conversion_early { + struct X {}; + template<int> struct A {}; + template<X &x> struct A<x> {}; // expected-error {{not implicitly convertible}} + + struct Y { constexpr operator int() const { return 0; } }; + template<Y &y> struct A<y> {}; // expected-error {{cannot be deduced}} expected-note {{'y'}} +} diff --git a/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp b/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp index 548f7f8f34fbe..c1fcedd58d134 100644 --- a/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp +++ b/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp @@ -122,13 +122,13 @@ namespace DeduceDifferentType { int a_exp = a<3>(A<3>()); template<decltype(nullptr)> struct B {}; - template<int *P> int b(B<P>); // expected-note {{could not match}} expected-note {{not implicitly convertible}} + template<int *P> int b(B<P>); // expected-error {{value of type 'int *' is not implicitly convertible to 'decltype(nullptr)'}} int b_imp = b(B<nullptr>()); // expected-error {{no matching function}} int b_exp = b<nullptr>(B<nullptr>()); // expected-error {{no matching function}} struct X { constexpr operator int() { return 0; } } x; template<X &> struct C {}; - template<int N> int c(C<N>); // expected-note {{does not have the same type}} expected-note {{not implicitly convertible}} + template<int N> int c(C<N>); // expected-error {{value of type 'int' is not implicitly convertible to 'DeduceDifferentType::X &'}} int c_imp = c(C<x>()); // expected-error {{no matching function}} int c_exp = c<x>(C<x>()); // expected-error {{no matching function}} @@ -137,7 +137,7 @@ namespace DeduceDifferentType { struct Z { constexpr operator Y&() { return y; } } z; constexpr Y::operator Z&() { return z; } template<Y &> struct D {}; - template<Z &z> int d(D<z>); // expected-note {{does not have the same type}} + template<Z &z> int d(D<z>); // expected-note {{couldn't infer template argument 'z'}} int d_imp = d(D<y>()); // expected-error {{no matching function}} int d_exp = d<y>(D<y>()); } @@ -155,3 +155,176 @@ namespace PR24921 { template<int> void f(int); template<> void f<e>() {} } + +namespace Auto { + namespace Basic { + // simple auto + template<auto x> constexpr auto constant = x; // expected-note {{declared here}} + + auto v1 = constant<5>; + auto v2 = constant<true>; + auto v3 = constant<'a'>; + auto v4 = constant<2.5>; // expected-error {{cannot have type 'double'}} + + using T1 = decltype(v1); + using T1 = int; + using T2 = decltype(v2); + using T2 = bool; + using T3 = decltype(v3); + using T3 = char; + + // pointers + template<auto v> class B { }; + template<auto* p> class B<p> { }; // expected-note {{matches}} + template<auto** pp> class B<pp> { }; + template<auto* p0> int &f(B<p0> b); // expected-note {{candidate}} + template<auto** pp0> float &f(B<pp0> b); // expected-note {{candidate}} + + int a, *b = &a; + int &r = f(B<&a>()); + float &s = f(B<&b>()); + + // pointers to members + template<typename T, auto *T::*p> struct B<p> {}; + template<typename T, auto **T::*p> struct B<p> {}; + template<typename T, auto *T::*p0> char &f(B<p0> b); // expected-note {{candidate}} + template<typename T, auto **T::*pp0> short &f(B<pp0> b); // expected-note {{candidate}} + + struct X { int n; int *p; int **pp; typedef int a, b; }; + auto t = f(B<&X::n>()); // expected-error {{no match}} + char &u = f(B<&X::p>()); + short &v = f(B<&X::pp>()); + + // A case where we need to do auto-deduction, and check whether the + // resulting dependent types match during partial ordering. These + // templates are not ordered due to the mismatching function parameter. + template<typename T, auto *(*f)(T, typename T::a)> struct B<f> {}; // expected-note {{matches}} + template<typename T, auto **(*f)(T, typename T::b)> struct B<f> {}; // expected-note {{matches}} + int **g(X, int); + B<&g> bg; // expected-error {{ambiguous}} + } + + namespace Chained { + // chained template argument deduction + template<long n> struct C { }; + template<class T> struct D; + template<class T, T n> struct D<C<n>> + { + using Q = T; + }; + using DQ = long; + using DQ = D<C<short(2)>>::Q; + + // chained template argument deduction from an array bound + template<typename T> struct E; + template<typename T, T n> struct E<int[n]> { + using Q = T; + }; + using EQ = E<int[short(42)]>::Q; + using EQ = decltype(sizeof 0); + + template<int N> struct F; + template<typename T, T N> int foo(F<N> *) = delete; // expected-note {{explicitly deleted}} + void foo(void *); // expected-note {{candidate function}} + void bar(F<0> *p) { + foo(p); // expected-error {{deleted function}} + } + } + + namespace ArrayToPointer { + constexpr char s[] = "test"; + template<const auto* p> struct S { }; + S<s> p; + } + + namespace DecltypeAuto { + template<auto v> struct A { }; + template<decltype(auto) v> struct DA { }; + template<auto&> struct R { }; + + auto n = 0; // expected-note + {{declared here}} + A<n> a; // expected-error {{not a constant}} expected-note {{non-const variable 'n'}} + DA<n> da1; // expected-error {{not a constant}} expected-note {{non-const variable 'n'}} + DA<(n)> da2; + R<n> r; + } + + namespace Decomposition { + // Types of deduced non-type template arguments must match exactly, so + // partial ordering fails in both directions here. + template<auto> struct Any; + template<int N> struct Any<N> { typedef int Int; }; // expected-note 3{{match}} + template<short N> struct Any<N> { typedef int Short; }; // expected-note 3{{match}} + Any<0>::Int is_int; // expected-error {{ambiguous}} + Any<(short)0>::Short is_short; // expected-error {{ambiguous}} + Any<(char)0>::Short is_char; // expected-error {{ambiguous}} + + template<int, auto> struct NestedAny; + template<auto N> struct NestedAny<0, N>; // expected-note 3{{match}} + template<int N> struct NestedAny<0, N> { typedef int Int; }; // expected-note 3{{match}} + template<short N> struct NestedAny<0, N> { typedef int Short; }; // expected-note 3{{match}} + NestedAny<0, 0>::Int nested_int; // expected-error {{ambiguous}} + NestedAny<0, (short)0>::Short nested_short; // expected-error {{ambiguous}} + NestedAny<0, (char)0>::Short nested_char; // expected-error {{ambiguous}} + + double foo(int, bool); + template<auto& f> struct fn_result_type; + + template<class R, class... Args, R (& f)(Args...)> + struct fn_result_type<f> + { + using type = R; + }; + + using R1 = fn_result_type<foo>::type; + using R1 = double; + + template<int, auto &f> struct fn_result_type_partial_order; + template<auto &f> struct fn_result_type_partial_order<0, f>; + template<class R, class... Args, R (& f)(Args...)> + struct fn_result_type_partial_order<0, f> {}; + fn_result_type_partial_order<0, foo> frtpo; + } + + namespace Variadic { + template<auto... vs> struct value_list { }; + + using size_t = decltype(sizeof 0); + template<size_t n, class List> struct nth_element; + template<size_t n, class List> constexpr auto nth_element_v = nth_element<n, List>::value; + + template<size_t n, auto v0, auto... vs> + struct nth_element<n, value_list<v0, vs...>> + { + static constexpr auto value = nth_element<n - 1, value_list<vs...>>::value; + }; + template<auto v0, auto... vs> + struct nth_element<0, value_list<v0, vs...>> + { + static constexpr auto value = v0; + }; + + static_assert(nth_element_v<2, value_list<'a', 27U, false>> == false, "value mismatch"); + } +} + +namespace Nested { + template<typename T> struct A { + template<auto X> struct B; + template<auto *P> struct B<P>; + template<auto **P> struct B<P> { using pointee = decltype(+**P); }; + template<auto (*P)(T)> struct B<P> { using param = T; }; + template<typename U, auto (*P)(T, U)> struct B<P> { using param2 = U; }; + }; + + using Int = int; + + int *n; + using Int = A<int>::B<&n>::pointee; + + void f(int); + using Int = A<int>::B<&f>::param; + + void g(int, int); + using Int = A<int>::B<&g>::param2; +} diff --git a/test/SemaTemplate/temp_arg_template.cpp b/test/SemaTemplate/temp_arg_template.cpp index 6d93f1504a469..67cde53c928b3 100644 --- a/test/SemaTemplate/temp_arg_template.cpp +++ b/test/SemaTemplate/temp_arg_template.cpp @@ -6,11 +6,12 @@ template<template<typename T> class X> struct A; // expected-note 2{{previous te 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<template<int I> class X> struct C; // expected-note 2{{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}} +template<const int &N> struct Yref; // expected-note{{template non-type parameter has a different type 'const int &' in template argument}} namespace N { template<class> struct Z; @@ -27,6 +28,7 @@ A<TooMany> *a5; // expected-error{{template template argument has different temp 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}} +C<Yref> *a9; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}} template<typename T> void f(int); diff --git a/test/SemaTemplate/temp_arg_template_cxx1z.cpp b/test/SemaTemplate/temp_arg_template_cxx1z.cpp new file mode 100644 index 0000000000000..b6b283b53c6be --- /dev/null +++ b/test/SemaTemplate/temp_arg_template_cxx1z.cpp @@ -0,0 +1,102 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1z -frelaxed-template-template-args %s + +// expected-note@temp_arg_template_cxx1z.cpp:* 1+{{}} + +template<template<int> typename> struct Ti; +template<template<int...> typename> struct TPi; +template<template<int, int...> typename> struct TiPi; +template<template<int..., int...> typename> struct TPiPi; // FIXME: Why is this not ill-formed? + +template<typename T, template<T> typename> struct tT0; +template<template<typename T, T> typename> struct Tt0; + +template<template<typename> typename> struct Tt; +template<template<typename, typename...> typename> struct TtPt; + +template<int> struct i; +template<int, int = 0> struct iDi; +template<int, int> struct ii; +template<int...> struct Pi; +template<int, int, int...> struct iiPi; + +template<int, typename = int> struct iDt; +template<int, typename> struct it; + +template<typename T, T v> struct t0; + +template<typename...> struct Pt; + +namespace IntParam { + using ok = Pt<Ti<i>, + Ti<iDi>, + Ti<Pi>, + Ti<iDt>>; + using err1 = Ti<ii>; // expected-error {{different template parameters}} + using err2 = Ti<iiPi>; // expected-error {{different template parameters}} + using err3 = Ti<t0>; // expected-error {{different template parameters}} + using err4 = Ti<it>; // expected-error {{different template parameters}} +} + +// These are accepted by the backwards-compatibility "parameter pack in +// parameter matches any number of parameters in arguments" rule. +namespace IntPackParam { + using ok = TPi<Pi>; + using ok_compat = Pt<TPi<i>, TPi<iDi>, TPi<ii>, TPi<iiPi>>; + using err1 = TPi<t0>; // expected-error {{different template parameters}} + using err2 = TPi<iDt>; // expected-error {{different template parameters}} + using err3 = TPi<it>; // expected-error {{different template parameters}} +} + +namespace IntAndPackParam { + using ok = TiPi<Pi>; + using ok_compat = Pt<TiPi<ii>, TiPi<iDi>, TiPi<iiPi>>; + using err = TiPi<iDi>; +} + +namespace DependentType { + using ok = Pt<tT0<int, i>, tT0<int, iDi>>; + using err1 = tT0<int, ii>; // expected-error {{different template parameters}} + using err2 = tT0<short, i>; // FIXME: should this be OK? + using err2a = tT0<long long, i>; // FIXME: should this be OK (if long long is larger than int)? + using err2b = tT0<void*, i>; // expected-error {{different template parameters}} + using err3 = tT0<short, t0>; // expected-error {{different template parameters}} + + using ok2 = Tt0<t0>; + using err4 = Tt0<it>; // expected-error {{different template parameters}} +} + +namespace Auto { + template<template<int> typename T> struct TInt {}; + template<template<int*> typename T> struct TIntPtr {}; + template<template<auto> typename T> struct TAuto {}; + template<template<auto*> typename T> struct TAutoPtr {}; + template<auto> struct Auto; + template<auto*> struct AutoPtr; + template<int> struct Int; + template<int*> struct IntPtr; + + TInt<Auto> ia; + TInt<AutoPtr> iap; // FIXME: ill-formed + TInt<Int> ii; + TInt<IntPtr> iip; // expected-error {{different template parameters}} + + TIntPtr<Auto> ipa; + TIntPtr<AutoPtr> ipap; + TIntPtr<Int> ipi; // expected-error {{different template parameters}} + TIntPtr<IntPtr> ipip; + + TAuto<Auto> aa; + TAuto<AutoPtr> aap; // FIXME: ill-formed + TAuto<Int> ai; // FIXME: ill-formed + TAuto<IntPtr> aip; // FIXME: ill-formed + + TAutoPtr<Auto> apa; + TAutoPtr<AutoPtr> apap; + TAutoPtr<Int> api; // FIXME: ill-formed + TAutoPtr<IntPtr> apip; // FIXME: ill-formed + + int n; + template<auto A, decltype(A) B = &n> struct SubstFailure; + TInt<SubstFailure> isf; // expected-error {{different template parameters}} + TIntPtr<SubstFailure> ipsf; // expected-error {{different template parameters}} +} diff --git a/test/SemaTemplate/temp_class_spec_neg.cpp b/test/SemaTemplate/temp_class_spec_neg.cpp index 1c77038ab8a9a..6366a528ff530 100644 --- a/test/SemaTemplate/temp_class_spec_neg.cpp +++ b/test/SemaTemplate/temp_class_spec_neg.cpp @@ -20,9 +20,9 @@ struct N::M::A<T*> { }; #endif // C++ [temp.class.spec]p9 -// bullet 1 +// bullet 1, as amended by DR1315 template <int I, int J> struct A {}; -template <int I> struct A<I+5, I*2> {}; // expected-error{{depends on}} +template <int I> struct A<I+5, I*2> {}; // expected-error{{cannot be deduced}} expected-note {{'I'}} template <int I, int J> struct B {}; template <int I> struct B<I, I> {}; //OK @@ -50,4 +50,4 @@ template<typename T = int, // expected-error{{default template argument}} template<typename T> struct Test1; template<typename T, typename U> // expected-note{{non-deducible}} - struct Test1<T*> { }; // expected-warning{{never be used}} + struct Test1<T*> { }; // expected-error{{never be used}} diff --git a/test/SemaTemplate/temp_explicit.cpp b/test/SemaTemplate/temp_explicit.cpp index 80c90d0cfcd20..e8c9dfb5f5d2c 100644 --- a/test/SemaTemplate/temp_explicit.cpp +++ b/test/SemaTemplate/temp_explicit.cpp @@ -26,7 +26,7 @@ template class X0<double> { }; // expected-error{{explicit specialization}} template class X0<int, int>; // expected-error{{duplicate}} template<> class X0<char> { }; // expected-note{{previous}} -template class X0<char>; // expected-warning{{ignored}} +template class X0<char>; // expected-warning{{has no effect}} void foo(X0<short>) { } template class X0<short>; diff --git a/test/SemaTemplate/template-id-expr.cpp b/test/SemaTemplate/template-id-expr.cpp index 499d289ee6754..e311b5832d0d2 100644 --- a/test/SemaTemplate/template-id-expr.cpp +++ b/test/SemaTemplate/template-id-expr.cpp @@ -100,5 +100,5 @@ template void f5<0>(); // expected-note {{in instantiation of function template class C {}; template <template <typename> class D> // expected-note{{previous use is here}} class E { - template class D<C>; // expected-error {{elaborated type refers to a template template argument}} + template class D<C>; // expected-error {{template template argument 'D' cannot be referenced with a class specifier}} }; |
