diff options
Diffstat (limited to 'test/SemaTemplate')
32 files changed, 724 insertions, 55 deletions
diff --git a/test/SemaTemplate/alias-templates.cpp b/test/SemaTemplate/alias-templates.cpp index 3b7548d169b0..240a6eeff2e7 100644 --- a/test/SemaTemplate/alias-templates.cpp +++ b/test/SemaTemplate/alias-templates.cpp @@ -256,12 +256,14 @@ namespace PR31514 { } namespace an_alias_template_is_not_a_class_template { - template<typename T> using Foo = int; // expected-note 2{{here}} + template<typename T> using Foo = int; // expected-note 3{{here}} Foo x; // expected-error {{use of alias template 'Foo' requires template arguments}} Foo<> y; // expected-error {{too few template arguments for alias template 'Foo'}} + int z = Foo(); // expected-error {{use of alias template 'Foo' requires template arguments}} - template<template<typename> class Bar> void f() { // expected-note 2{{here}} + template<template<typename> class Bar> void f() { // expected-note 3{{here}} Bar x; // expected-error {{use of template template parameter 'Bar' requires template arguments}} Bar<> y; // expected-error {{too few template arguments for template template parameter 'Bar'}} + int z = Bar(); // expected-error {{use of template template parameter 'Bar' requires template arguments}} } } diff --git a/test/SemaTemplate/alignas.cpp b/test/SemaTemplate/alignas.cpp index 8a1f96e5bdec..680f07b32998 100644 --- a/test/SemaTemplate/alignas.cpp +++ b/test/SemaTemplate/alignas.cpp @@ -21,3 +21,14 @@ struct C { char a[16]; }; static_assert(sizeof(my_union<A, B, C>) == 16, ""); static_assert(alignof(my_union<A, B, C>) == 8, ""); + +namespace PR35028 { + template<class X, int Alignment> struct alignas(X) alignas(long long) alignas(long double) alignas(Alignment) Aligned { + union { + long long align1; + long double align2; + char data[sizeof(X)]; + }; + }; + Aligned<int, 1> a; +} diff --git a/test/SemaTemplate/argument-dependent-lookup.cpp b/test/SemaTemplate/argument-dependent-lookup.cpp new file mode 100644 index 000000000000..d1603d56b960 --- /dev/null +++ b/test/SemaTemplate/argument-dependent-lookup.cpp @@ -0,0 +1,45 @@ +// RUN: %clang_cc1 -verify %s +// RUN: %clang_cc1 -verify %s -DHAVE_UNQUALIFIED_LOOKUP_RESULTS +// expected-no-diagnostics + +namespace address_of { +#ifdef HAVE_UNQUALIFIED_LOOKUP_RESULTS + struct Q {}; + void operator&(Q); +#endif + + template<typename T> struct A { + static constexpr auto x = &T::value; + }; + + template<typename T> struct B { + constexpr int operator&() { return 123; } + }; + + template<typename T> struct C { + static_assert(sizeof(T) == 123, ""); + }; + + struct X1 { + static B<X1> value; + }; + struct X2 : B<X2> { + enum E { value }; + friend constexpr int operator&(E) { return 123; } + }; + + struct Y1 { + C<int> *value; + }; + struct Y2 { + C<int> value(); + }; + + // ok, uses ADL to find operator&: + static_assert(A<X1>::x == 123, ""); + static_assert(A<X2>::x == 123, ""); + + // ok, does not use ADL so does not instantiate C<T>: + static_assert(A<Y1>::x == &Y1::value, ""); + static_assert(A<Y2>::x == &Y2::value, ""); +} diff --git a/test/SemaTemplate/attributes.cpp b/test/SemaTemplate/attributes.cpp index 1d46058b0191..7634b937c906 100644 --- a/test/SemaTemplate/attributes.cpp +++ b/test/SemaTemplate/attributes.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -std=gnu++11 -fsyntax-only -verify %s +// RUN: not %clang_cc1 -std=gnu++11 -ast-dump %s | FileCheck %s namespace attribute_aligned { template<int N> @@ -52,3 +53,13 @@ namespace PR9049 { template<typename T> inline void WBCFRelease(__attribute__((cf_consumed)) T aValue) { if(aValue) CFRelease(aValue); } } + +// CHECK: FunctionTemplateDecl {{.*}} HasAnnotations +// CHECK: AnnotateAttr {{.*}} "ANNOTATE_BAR" +// CHECK: AnnotateAttr {{.*}} "ANNOTATE_FOO" +// CHECK: FunctionDecl {{.*}} HasAnnotations +// CHECK: TemplateArgument type 'int' +// CHECK: AnnotateAttr {{.*}} "ANNOTATE_BAR" +// CHECK: AnnotateAttr {{.*}} "ANNOTATE_FOO" +template<typename T> [[clang::annotate("ANNOTATE_FOO"), clang::annotate("ANNOTATE_BAR")]] void HasAnnotations(); +void UseAnnotations() { HasAnnotations<int>(); } diff --git a/test/SemaTemplate/class-template-spec.cpp b/test/SemaTemplate/class-template-spec.cpp index 00e03ef61eb0..d763944371cc 100644 --- a/test/SemaTemplate/class-template-spec.cpp +++ b/test/SemaTemplate/class-template-spec.cpp @@ -78,9 +78,6 @@ template<> struct ::A<double>; namespace N { template<typename T> struct B; // expected-note {{explicitly specialized}} -#if __cplusplus <= 199711L - // expected-note@-2 {{explicitly specialized}} -#endif template<> struct ::N::B<char>; // okay template<> struct ::N::B<short>; // okay @@ -92,9 +89,6 @@ namespace N { template<> struct N::B<int> { }; // okay template<> struct N::B<float> { }; -#if __cplusplus <= 199711L -// expected-warning@-2 {{first declaration of class template specialization of 'B' outside namespace 'N' is a C++11 extension}} -#endif namespace M { @@ -121,9 +115,9 @@ class Wibble<int> { }; // expected-error{{cannot specialize a template template namespace rdar9676205 { template<typename T> - struct X { + struct X { // expected-note {{here}} template<typename U> - struct X<U*> { // expected-error{{explicit specialization of 'X' in class scope}} + struct X<U*> { // expected-error{{partial specialization of 'X' not in a namespace enclosing}} }; }; diff --git a/test/SemaTemplate/cxx17-inline-variables.cpp b/test/SemaTemplate/cxx17-inline-variables.cpp index 9e6761ee57aa..7fc0aa8eeeb0 100644 --- a/test/SemaTemplate/cxx17-inline-variables.cpp +++ b/test/SemaTemplate/cxx17-inline-variables.cpp @@ -16,3 +16,14 @@ namespace CompleteType { constexpr int n = X<true>::value; } + +template <typename T> struct A { + static const int n; + static const int m; + constexpr int f() { return n; } + constexpr int g() { return n; } +}; +template <typename T> constexpr int A<T>::n = sizeof(A) + sizeof(T); +template <typename T> inline constexpr int A<T>::m = sizeof(A) + sizeof(T); +static_assert(A<int>().f() == 5); +static_assert(A<int>().g() == 5); diff --git a/test/SemaTemplate/dependent-base-classes.cpp b/test/SemaTemplate/dependent-base-classes.cpp index 1853511bfc8f..6d342f984d53 100644 --- a/test/SemaTemplate/dependent-base-classes.cpp +++ b/test/SemaTemplate/dependent-base-classes.cpp @@ -55,7 +55,7 @@ namespace PR6031 { struct NoDepBase { int foo() { class NoDepBase::Nested nested; // expected-error{{no class named 'Nested' in 'NoDepBase<T>'}} - typedef typename NoDepBase::template MemberTemplate<T>::type type; // expected-error{{'MemberTemplate' following the 'template' keyword does not refer to a template}} \ + typedef typename NoDepBase::template MemberTemplate<T>::type type; // expected-error{{no member named 'MemberTemplate' in 'NoDepBase<T>'}} \ // FIXME: expected-error{{unqualified-id}} return NoDepBase::a; // expected-error{{no member named 'a' in 'NoDepBase<T>'}} } @@ -103,7 +103,7 @@ namespace PR6081 { template< class X > void f0(const X & k) { - this->template f1<int>()(k); // expected-error{{'f1' following the 'template' keyword does not refer to a template}} \ + this->template f1<int>()(k); // expected-error{{no member named 'f1' in 'C<T>'}} \ // FIXME: expected-error{{unqualified-id}} \ // expected-error{{function-style cast or type construction}} \ // expected-error{{expected expression}} diff --git a/test/SemaTemplate/dependent-names.cpp b/test/SemaTemplate/dependent-names.cpp index d5c9d66c4526..67ef238083f0 100644 --- a/test/SemaTemplate/dependent-names.cpp +++ b/test/SemaTemplate/dependent-names.cpp @@ -419,3 +419,43 @@ template <typename> struct CT2 { template <class U> struct X; }; template <typename T> int CT2<int>::X<>; // expected-error {{template parameter list matching the non-templated nested type 'CT2<int>' should be empty}} + +namespace DependentTemplateIdWithNoArgs { + template<typename T> void f() { T::template f(); } + struct X { + template<int = 0> static void f(); + }; + void g() { f<X>(); } +} + +namespace DependentUnresolvedUsingTemplate { + template<typename T> + struct X : T { + using T::foo; + void f() { this->template foo(); } // expected-error {{does not refer to a template}} + void g() { this->template foo<>(); } // expected-error {{does not refer to a template}} + void h() { this->template foo<int>(); } // expected-error {{does not refer to a template}} + }; + struct A { template<typename = int> int foo(); }; + struct B { int foo(); }; // expected-note 3{{non-template here}} + void test(X<A> xa, X<B> xb) { + xa.f(); + xa.g(); + xa.h(); + xb.f(); // expected-note {{instantiation of}} + xb.g(); // expected-note {{instantiation of}} + xb.h(); // expected-note {{instantiation of}} + } +} + +namespace PR37680 { + template <class a> struct b : a { + using a::add; + template<int> int add() { return this->template add(0); } + }; + struct a { + template<typename T = void> int add(...); + void add(int); + }; + int f(b<a> ba) { return ba.add<0>(); } +} diff --git a/test/SemaTemplate/dependent-template-recover.cpp b/test/SemaTemplate/dependent-template-recover.cpp index ac1623041719..37a8faa705f7 100644 --- a/test/SemaTemplate/dependent-template-recover.cpp +++ b/test/SemaTemplate/dependent-template-recover.cpp @@ -5,18 +5,69 @@ struct X { t->f0<U>(); // expected-error{{use 'template' keyword to treat 'f0' as a dependent template name}} t->f0<int>(); // expected-error{{use 'template' keyword to treat 'f0' as a dependent template name}} - t->operator+<U const, 1>(); // expected-error{{use 'template' keyword to treat 'operator +' as a dependent template name}} - t->f1<int const, 2>(); // expected-error{{use 'template' keyword to treat 'f1' as a dependent template name}} + t->operator+<U const, 1>(1); // expected-error{{use 'template' keyword to treat 'operator +' as a dependent template name}} + t->f1<int const, 2>(1); // expected-error{{use 'template' keyword to treat 'f1' as a dependent template name}} + t->f1<3, int const>(1); // expected-error{{missing 'template' keyword prior to dependent template name 'f1'}} T::getAs<U>(); // expected-error{{use 'template' keyword to treat 'getAs' as a dependent template name}} t->T::getAs<U>(); // expected-error{{use 'template' keyword to treat 'getAs' as a dependent template name}} - // FIXME: We can't recover from these yet - (*t).f2<N>(); // expected-error{{expected expression}} - (*t).f2<0>(); // expected-error{{expected expression}} + (*t).f2<N>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f2'}} + (*t).f2<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f2'}} + T::f2<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f2'}} + T::f2<0, int>(0); // expected-error{{missing 'template' keyword prior to dependent template name 'f2'}} + + T::foo<N < 2 || N >= 4>(); // expected-error{{missing 'template' keyword prior to dependent template name 'foo'}} + + // If there are multiple potential template names, pick the one where there + // is no whitespace between the name and the '<'. + T::foo<T::bar < 1>(); // expected-error{{missing 'template' keyword prior to dependent template name 'foo'}} + T::foo < T::bar<1>(); // expected-error{{missing 'template' keyword prior to dependent template name 'bar'}} + + // Prefer to diagonse a missing 'template' keyword rather than finding a non-template name. + xyz < T::foo < 1 > (); // expected-error{{missing 'template' keyword prior to dependent template name 'foo'}} + T::foo < xyz < 1 > (); // expected-error{{missing 'template' keyword prior to dependent template name 'foo'}} + + // ... even if the whitespace suggests the other name is the template name. + // FIXME: Is this the right heuristic? + xyz<T::foo < 1>(); // expected-error{{missing 'template' keyword prior to dependent template name 'foo'}} + T::foo < xyz<1>(); // expected-error{{missing 'template' keyword prior to dependent template name 'foo'}} + + sizeof T::foo < 123 > (); // expected-error{{missing 'template' keyword prior to dependent template name 'foo'}} + f(t->foo<1, 2>(), // expected-error{{missing 'template' keyword prior to dependent template name 'foo'}} + t->bar<3, 4>()); // expected-error{{missing 'template' keyword prior to dependent template name 'bar'}} + + int arr[] = { + t->baz<1, 2>(1 + 1), // ok, two comparisons + t->foo<1, 2>(), // expected-error{{missing 'template' keyword prior to dependent template name 'foo'}} + t->bar<3, 4>() // FIXME: we don't recover from the previous error so don't diagnose this + }; } + + int xyz; }; +template <typename T> void not_missing_template(T t) { + (T::n < 0) > ( + ) // expected-error {{expected expression}} + ; + + int a = T::x < 3; + int b = T::y > (); // expected-error {{expected expression}} + + void c(int = T::x < 3); + void d(int = T::y > ()); // expected-error {{expected expression}} + + for (int x = t < 3 ? 1 : 2; t > (); ++t) { // expected-error {{expected expression}} + } + + // FIXME: We shouldn't treat 'T::t' as a potential template-name here, + // because that would leave a '?' with no matching ':'. + // We should probably generally treat '?' ... ':' as a bracket-like + // construct. + bool k = T::t < 3 ? 1 > () : false; // expected-error {{missing 'template' keyword}} expected-error +{{}} expected-note +{{}} +} + struct MrsBadcrumble { friend MrsBadcrumble operator<(void (*)(int), MrsBadcrumble); friend void operator>(MrsBadcrumble, int); @@ -30,6 +81,9 @@ template<int N, typename T> void f(T t) { // Note: no diagnostic here, this is actually valid as a comparison between // the decayed pointer to Y::g<> and mb! T::g<mb>(0); + + // ... but this one must be a template-id. + T::g<mb, int>(0); // expected-error {{missing 'template' keyword prior to dependent template name 'g'}} } struct Y { diff --git a/test/SemaTemplate/ext_ms_template_spec.cpp b/test/SemaTemplate/ext_ms_template_spec.cpp index fc2ed16f9f8a..cb303217ea90 100644 --- a/test/SemaTemplate/ext_ms_template_spec.cpp +++ b/test/SemaTemplate/ext_ms_template_spec.cpp @@ -18,16 +18,16 @@ template <typename T> struct X { namespace B { template <> -class A::ClassTemplate<int>; // expected-warning {{class template specialization of 'ClassTemplate' outside namespace enclosing 'A' is a Microsoft extension}} +class A::ClassTemplate<int>; // expected-warning {{class template specialization of 'ClassTemplate' not in a namespace enclosing 'A' is a Microsoft extension}} template <class T1> -class A::ClassTemplatePartial<T1, T1 *> {}; // expected-warning {{class template partial specialization of 'ClassTemplatePartial' outside namespace enclosing 'A' is a Microsoft extension}} +class A::ClassTemplatePartial<T1, T1 *> {}; // expected-warning {{class template partial specialization of 'ClassTemplatePartial' not in a namespace enclosing 'A' is a Microsoft extension}} template <> -struct A::X<int>::MemberClass; // expected-warning {{member class specialization of 'MemberClass' outside namespace enclosing 'A' is a Microsoft extension}} +struct A::X<int>::MemberClass; // expected-warning {{member class specialization of 'MemberClass' not in class 'X' or an enclosing namespace is a Microsoft extension}} template <> -enum A::X<int>::MemberEnumeration; // expected-warning {{member enumeration specialization of 'MemberEnumeration' outside namespace enclosing 'A' is a Microsoft extension}} // expected-error {{ISO C++ forbids forward references to 'enum' types}} +enum A::X<int>::MemberEnumeration; // expected-warning {{member enumeration specialization of 'MemberEnumeration' not in class 'X' or an enclosing namespace is a Microsoft extension}} // expected-error {{ISO C++ forbids forward references to 'enum' types}} } diff --git a/test/SemaTemplate/function-pointer-qualifier.cpp b/test/SemaTemplate/function-pointer-qualifier.cpp new file mode 100644 index 000000000000..97d160738a28 --- /dev/null +++ b/test/SemaTemplate/function-pointer-qualifier.cpp @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// expected-no-diagnostics + +template<class _Ty> inline + void testparam(_Ty **, _Ty **) + { + } + +template<class _Ty> inline + void testparam(_Ty *const *, _Ty **) + { + } + +template<class _Ty> inline + void testparam(_Ty **, const _Ty **) + { + } + +template<class _Ty> inline + void testparam(_Ty *const *, const _Ty **) + { + } + +void case0() +{ + void (**p1)(); + void (**p2)(); + testparam(p1, p2); +} diff --git a/test/SemaTemplate/function-template-specialization.cpp b/test/SemaTemplate/function-template-specialization.cpp index 6327ff64c336..a3669fd7fdda 100644 --- a/test/SemaTemplate/function-template-specialization.cpp +++ b/test/SemaTemplate/function-template-specialization.cpp @@ -54,5 +54,5 @@ class Foo { // Don't crash here. template<> - static void Bar(const long& input) {} // expected-error{{explicit specialization of 'Bar' in class scope}} + static void Bar(const long& input) {} // expected-warning{{explicit specialization cannot have a storage class}} }; diff --git a/test/SemaTemplate/instantiate-after-fatal-cxx17.cpp b/test/SemaTemplate/instantiate-after-fatal-cxx17.cpp new file mode 100644 index 000000000000..3e0ddf1ae60f --- /dev/null +++ b/test/SemaTemplate/instantiate-after-fatal-cxx17.cpp @@ -0,0 +1,16 @@ +// RUN: not %clang_cc1 -std=c++17 -fsyntax-only -ferror-limit 1 %s 2>&1 | FileCheck %s + +#error Error 1 +#error Error 2 +// CHECK: fatal error: too many errors emitted, stopping now + +namespace rdar39051732 { + + template<class T> struct A { + template <class U> A(T&, ...); + }; + // Deduction guide triggers constructor instantiation. + template<class T> A(const T&, const T&) -> A<T&>; + +} + diff --git a/test/SemaTemplate/instantiate-init.cpp b/test/SemaTemplate/instantiate-init.cpp index 244e94f6d605..51fa6955d0c0 100644 --- a/test/SemaTemplate/instantiate-init.cpp +++ b/test/SemaTemplate/instantiate-init.cpp @@ -142,3 +142,17 @@ namespace ReturnStmtIsInitialization { template<typename T> X f() { return {}; } auto &&x = f<void>(); } + +namespace InitListUpdate { + struct A { int n; }; + using AA = A[1]; + + // Check that an init list update doesn't "lose" the pack-ness of an expression. + template <int... N> void f() { + g(AA{0, [0].n = N} ...); // expected-warning 3{{overrides prior init}} expected-note 3{{previous init}} + g(AA{N, [0].n = 0} ...); // expected-warning 3{{overrides prior init}} expected-note 3{{previous init}} + }; + + void g(AA, AA); + void h() { f<1, 2>(); } // expected-note {{instantiation of}} +} diff --git a/test/SemaTemplate/instantiate-method.cpp b/test/SemaTemplate/instantiate-method.cpp index 961884417b54..9cd668dacf5c 100644 --- a/test/SemaTemplate/instantiate-method.cpp +++ b/test/SemaTemplate/instantiate-method.cpp @@ -185,7 +185,7 @@ namespace SameSignatureAfterInstantiation { namespace PR22040 { template <typename T> struct Foobar { - template <> void bazqux(typename T::type) {} // expected-error {{cannot specialize a function 'bazqux' within class scope}} expected-error 2{{cannot be used prior to '::' because it has no members}} + template <> void bazqux(typename T::type) {} // expected-error 2{{cannot be used prior to '::' because it has no members}} }; void test() { diff --git a/test/SemaTemplate/late-parsing-eager-instantiation.cpp b/test/SemaTemplate/late-parsing-eager-instantiation.cpp new file mode 100644 index 000000000000..412f0265a46a --- /dev/null +++ b/test/SemaTemplate/late-parsing-eager-instantiation.cpp @@ -0,0 +1,40 @@ +// RUN: %clang_cc1 -std=c++14 -verify %s + +// pr33561 +class ArrayBuffer; +template <typename T> class Trans_NS_WTF_RefPtr { +public: + ArrayBuffer *operator->() { return nullptr; } +}; +Trans_NS_WTF_RefPtr<ArrayBuffer> get(); +template <typename _Visitor> +constexpr void visit(_Visitor __visitor) { + __visitor(get()); // expected-note {{in instantiation}} +} +class ArrayBuffer { + char data() { + visit([](auto buffer) -> char { // expected-note {{in instantiation}} + buffer->data(); + }); // expected-warning {{control reaches end of non-void lambda}} + } // expected-warning {{control reaches end of non-void function}} +}; + +// pr34185 +template <typename Promise> struct coroutine_handle { + Promise &promise() const { return + *static_cast<Promise *>(nullptr); // expected-warning {{binding dereferenced null}} + } +}; + +template <typename Promise> auto GetCurrenPromise() { + struct Awaiter { // expected-note {{in instantiation}} + void await_suspend(coroutine_handle<Promise> h) { + h.promise(); // expected-note {{in instantiation}} + } + }; + return Awaiter{}; +} + +void foo() { + auto &&p = GetCurrenPromise<int>(); // expected-note {{in instantiation}} +} diff --git a/test/SemaTemplate/metafun-apply.cpp b/test/SemaTemplate/metafun-apply.cpp index 3a7408e28025..55f6194a5103 100644 --- a/test/SemaTemplate/metafun-apply.cpp +++ b/test/SemaTemplate/metafun-apply.cpp @@ -15,7 +15,7 @@ struct add_reference { }; struct bogus { - struct apply { + struct apply { // expected-note{{declared as a non-template here}} typedef int type; }; }; diff --git a/test/SemaTemplate/ms-function-specialization-class-scope.cpp b/test/SemaTemplate/ms-function-specialization-class-scope.cpp index 3c7111d05838..dcab9bfaeabc 100644 --- a/test/SemaTemplate/ms-function-specialization-class-scope.cpp +++ b/test/SemaTemplate/ms-function-specialization-class-scope.cpp @@ -1,18 +1,15 @@ // RUN: %clang_cc1 -fms-extensions -fsyntax-only -verify %s // RUN: %clang_cc1 -fms-extensions -fdelayed-template-parsing -fsyntax-only -verify %s +// expected-no-diagnostics class A { public: template<class U> A(U p) {} - template<> A(int p) { - // expected-warning@-1 {{explicit specialization of 'A' within class scope is a Microsoft extension}} - } + template<> A(int p) {} template<class U> void f(U p) {} - template<> void f(int p) { - // expected-warning@-1 {{explicit specialization of 'f' within class scope is a Microsoft extension}} - } + template<> void f(int p) {} void f(int p) {} }; @@ -28,14 +25,11 @@ void test1() { template<class T> class B { public: template<class U> B(U p) {} - template<> B(int p) { - // expected-warning@-1 {{explicit specialization of 'B<T>' within class scope is a Microsoft extension}} - } + template<> B(int p) {} template<class U> void f(U p) { T y = 9; } template<> void f(int p) { - // expected-warning@-1 {{explicit specialization of 'f' within class scope is a Microsoft extension}} T a = 3; } @@ -56,9 +50,7 @@ namespace PR12709 { template<bool b> void specialized_member_template() {} - template<> void specialized_member_template<false>() { - // expected-warning@-1 {{explicit specialization of 'specialized_member_template' within class scope is a Microsoft extension}} - } + template<> void specialized_member_template<false>() {} }; void f() { TemplateClass<int> t; } @@ -67,8 +59,8 @@ namespace PR12709 { namespace Duplicates { template<typename T> struct A { template<typename U> void f(); - template<> void f<int>() {} // expected-warning {{Microsoft extension}} - template<> void f<T>() {} // expected-warning {{Microsoft extension}} + template<> void f<int>() {} + template<> void f<T>() {} }; // FIXME: We should diagnose the duplicate explicit specialization definitions @@ -81,6 +73,6 @@ struct S { template <int> int f(int = 0); template <> - int f<0>(int); // expected-warning {{Microsoft extension}} + int f<0>(int); }; } diff --git a/test/SemaTemplate/nested-name-spec-template.cpp b/test/SemaTemplate/nested-name-spec-template.cpp index 78d09d13deea..e9d0eb202033 100644 --- a/test/SemaTemplate/nested-name-spec-template.cpp +++ b/test/SemaTemplate/nested-name-spec-template.cpp @@ -49,7 +49,7 @@ namespace N { struct X; }; - struct B; + struct B; // expected-note{{declared as a non-template here}} } struct ::N::A<int>::X { @@ -131,7 +131,7 @@ namespace PR9226 { template<typename T, typename U> struct Y { - typedef typename T::template f<U> type; // expected-error{{template name refers to non-type template 'X::f'}} + typedef typename T::template f<U> type; // expected-error{{template name refers to non-type template 'X::template f'}} }; Y<X, int> yxi; // expected-note{{in instantiation of template class 'PR9226::Y<PR9226::X, int>' requested here}} @@ -144,7 +144,7 @@ namespace PR9449 { template <typename T> void f() { int s<T>::template n<T>::* f; // expected-error{{implicit instantiation of undefined template 'PR9449::s<int>'}} \ - // expected-error{{following the 'template' keyword}} + // expected-error{{no member named 'n'}} } template void f<int>(); // expected-note{{in instantiation of}} diff --git a/test/SemaTemplate/nested-template.cpp b/test/SemaTemplate/nested-template.cpp index 44cb82e95bbf..efbde2076b9f 100644 --- a/test/SemaTemplate/nested-template.cpp +++ b/test/SemaTemplate/nested-template.cpp @@ -161,3 +161,10 @@ class Outer1 { template <typename T> struct X; template <typename T> int X<T>::func() {} // expected-error{{out-of-line definition of 'func' from class 'X<T>' without definition}} }; + +namespace RefPack { + template<const int &...N> struct A { template<typename ...T> void f(T (&...t)[N]); }; + constexpr int k = 10; + int arr[10]; + void g() { A<k>().f(arr); } +} diff --git a/test/SemaTemplate/pack-deduction.cpp b/test/SemaTemplate/pack-deduction.cpp index 84eefa63d215..f9309d52111e 100644 --- a/test/SemaTemplate/pack-deduction.cpp +++ b/test/SemaTemplate/pack-deduction.cpp @@ -65,3 +65,104 @@ namespace PR14615 { void f() { check<char>(1, 2); } // expected-error {{no matching function}} } } + +namespace fully_expanded_packs { + template<typename ...T> struct A { + template<T ...X> static constexpr int f() { + // expected-note@-1 1+{{deduced too few arguments for expanded pack 'X'}} + // expected-note@-2 1+{{too many template arguments}} + return (X + ... + 0); // expected-warning {{extension}} + } + + template<T ...X, int Y> static constexpr int g() { + // expected-note@-1 1+{{deduced too few arguments for expanded pack 'X'}} + // expected-note@-2 1+{{couldn't infer template argument 'Y'}} + // expected-note@-3 1+{{too many template arguments}} + return (X + ... + (1000 * Y)); // expected-warning {{extension}} + } + + template<T ...X, int Y, T ...Z> static constexpr int h() { + // expected-note@-1 1+{{deduced too few arguments for expanded pack 'X'}} + // expected-note@-2 1+{{couldn't infer template argument 'Y'}} + // expected-note@-3 1+{{deduced too few arguments for expanded pack 'Z'}} + // expected-note@-4 1+{{too many template arguments}} + return (X + ... + (1000 * Y)) + 1000000 * (Z + ... + 0); // expected-warning 2{{extension}} + } + + template<T ...X, int ...Z> static constexpr int i() { + return (X + ... + 0) + 1000 * (Z + ... + 0); // expected-warning 2{{extension}} + } + + template<T ...X, int Y, int ...Z> static constexpr int j() { + return (X + ... + (1000 * Y)) + 1000000 * (Z + ... + 0); // expected-warning 2{{extension}} + } + }; + + void check_invalid_calls() { + A<int, int>::f(); // expected-error {{no matching function}} + A<int, int>::f<>(); // expected-error {{no matching function}} + A<int, int>::f<0>(); // expected-error {{no matching function}} + A<int, int>::g(); // expected-error {{no matching function}} + A<int, int>::g<>(); // expected-error {{no matching function}} + A<int, int>::g<0>(); // expected-error {{no matching function}} + A<int, int>::g<0, 0>(); // expected-error {{no matching function}} + A<>::f<0>(); // expected-error {{no matching function}} + A<>::g(); // expected-error {{no matching function}} + A<>::g<>(); // expected-error {{no matching function}} + A<>::g<0, 0>(); // expected-error {{no matching function}} + A<>::h<>(); // expected-error {{no matching function}} + A<int>::h<>(); // expected-error {{no matching function}} + A<int>::h<0, 0>(); // expected-error {{no matching function}} + A<>::h<0, 0>(); // expected-error {{no matching function}} + } + + static_assert(A<>::f() == 0, ""); + static_assert(A<int>::f<1>() == 1, ""); + static_assert(A<>::g<1>() == 1000, ""); + static_assert(A<int>::g<1, 2>() == 2001, ""); + static_assert(A<>::h<1>() == 1000, ""); + static_assert(A<int>::h<1, 2, 3>() == 3002001, ""); + static_assert(A<int, int>::h<1, 20, 3, 4, 50>() == 54003021, ""); + static_assert(A<>::i<1>() == 1000, ""); + static_assert(A<int>::i<1>() == 1, ""); + static_assert(A<>::j<1, 2, 30>() == 32001000, ""); + static_assert(A<int>::j<1, 2, 3, 40>() == 43002001, ""); +} + +namespace partial_full_mix { + template<typename T, typename U> struct pair {}; + template<typename ...T> struct tuple {}; + template<typename ...T> struct A { + template<typename ...U> static pair<tuple<T...>, tuple<U...>> f(pair<T, U> ...p); + // expected-note@-1 {{[with U = <char, double, long>]: pack expansion contains parameter pack 'U' that has a different length (2 vs. 3) from outer parameter packs}} + // expected-note@-2 {{[with U = <char, double, void>]: pack expansion contains parameter pack 'U' that has a different length (at least 3 vs. 2) from outer parameter packs}} + + template<typename ...U> static pair<tuple<T...>, tuple<U...>> g(pair<T, U> ...p, ...); + // expected-note@-1 {{[with U = <char, double, long>]: pack expansion contains parameter pack 'U' that has a different length (2 vs. 3) from outer parameter packs}} + + template<typename ...U> static tuple<U...> h(tuple<pair<T, U>..., pair<int, int>>); + // expected-note@-1 {{[with U = <int [2]>]: pack expansion contains parameter pack 'U' that has a different length (2 vs. 1) from outer parameter packs}} + }; + + pair<tuple<int, float>, tuple<char, double>> k1 = A<int, float>().f<char>(pair<int, char>(), pair<float, double>()); + pair<tuple<int, float>, tuple<char, double>> k2 = A<int, float>().f<char>(pair<int, char>(), pair<float, double>(), pair<void, long>()); // expected-error {{no match}} + pair<tuple<int, float>, tuple<char, double>> k3 = A<int, float>().f<char, double, void>(pair<int, char>(), pair<float, double>()); // expected-error {{no match}} + + // FIXME: We should accept this by treating the pack 'p' as having a fixed length of 2 here. + pair<tuple<int, float>, tuple<char, double>> k4 = A<int, float>().g<char>(pair<int, char>(), pair<float, double>(), pair<void, long>()); // expected-error {{no match}} + + // FIXME: We should accept this by treating the pack of pairs as having a fixed length of 2 here. + tuple<int[2], int[4]> k5 = A<int[1], int[3]>::h<int[2]>(tuple<pair<int[1], int[2]>, pair<int[3], int[4]>, pair<int, int>>()); // expected-error {{no match}} +} + +namespace substitution_vs_function_deduction { + template <typename... T> struct A { + template <typename... U> void f(void(*...)(T, U)); // expected-warning {{ISO C++11 requires a parenthesized pack declaration to have a name}} + template <typename... U> void g(void...(T, U)); // expected-note {{could not match 'void (T, U)' against 'void (*)(int, int)'}} + }; + void f(int, int) { + A<int>().f(f); + // FIXME: We fail to decay the parameter to a pointer type. + A<int>().g(f); // expected-error {{no match}} + } +} diff --git a/test/SemaTemplate/partial-spec-instantiate.cpp b/test/SemaTemplate/partial-spec-instantiate.cpp index d5ecd8c1e3bf..2fc0517ae3d3 100644 --- a/test/SemaTemplate/partial-spec-instantiate.cpp +++ b/test/SemaTemplate/partial-spec-instantiate.cpp @@ -55,3 +55,46 @@ namespace rdar9169404 { // expected-no-diagnostics #endif } + +// rdar://problem/39524996 +namespace rdar39524996 { + template <typename T, typename U> + struct enable_if_not_same + { + typedef void type; + }; + template <typename T> + struct enable_if_not_same<T, T>; + + template <typename T> + struct Wrapper { + // Assertion triggered on trying to set twice the same partial specialization + // enable_if_not_same<int, int> + template <class U> + Wrapper(const Wrapper<U>& other, + typename enable_if_not_same<U, T>::type* = 0) {} + + explicit Wrapper(int i) {} + }; + + template <class T> + struct Container { + // It is important that the struct has implicit copy and move constructors. + Container() : x() {} + + template <class U> + Container(const Container<U>& other) : x(static_cast<T>(other.x)) {} + + // Implicit constructors are member-wise, so the field triggers instantiation + // of T constructors and we instantiate all of them for overloading purposes. + T x; + }; + + void takesWrapperInContainer(const Container< Wrapper<int> >& c); + void test() { + // Type mismatch triggers initialization with conversion which requires + // implicit constructors to be instantiated. + Container<int> c; + takesWrapperInContainer(c); + } +} diff --git a/test/SemaTemplate/sizeof-pack.cpp b/test/SemaTemplate/sizeof-pack.cpp new file mode 100644 index 000000000000..4b0c883a24ac --- /dev/null +++ b/test/SemaTemplate/sizeof-pack.cpp @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -std=c++11 -verify %s +// expected-no-diagnostics + +template<int &...Ns> int f() { + return sizeof...(Ns); +} +template int f<>(); diff --git a/test/SemaTemplate/stmt-expr.cpp b/test/SemaTemplate/stmt-expr.cpp new file mode 100644 index 000000000000..2516a5220c1a --- /dev/null +++ b/test/SemaTemplate/stmt-expr.cpp @@ -0,0 +1,39 @@ +// RUN: %clang_cc1 -verify %s + +// FIXME: We could in principle support cases like this (particularly, cases +// where the statement-expression contains no labels). +template <typename... T> void f1() { + int arr[] = { + ({ + T(); // expected-error {{unexpanded parameter pack}} + }) ... // expected-error {{does not contain any unexpanded parameter packs}} + }; +} + +// FIXME: The error for this isn't ideal; it'd be preferable to say that pack +// expansion of a statement expression is not permitted. +template <typename... T> void f2() { + [] { + int arr[] = { + T() + ({ + foo: + T t; // expected-error {{unexpanded parameter pack}} + goto foo; + 0; + }) ... + }; + }; +} + +template <typename... T> void f3() { + ({ + int arr[] = { + [] { + foo: + T t; // OK, expanded within compound statement + goto foo; + return 0; + } ... + }; + }); +} diff --git a/test/SemaTemplate/temp-param-subst-linear.cpp b/test/SemaTemplate/temp-param-subst-linear.cpp new file mode 100644 index 000000000000..fd93aa568553 --- /dev/null +++ b/test/SemaTemplate/temp-param-subst-linear.cpp @@ -0,0 +1,56 @@ +// RUN: %clang_cc1 -std=c++17 %s -verify +// expected-no-diagnostics + +// This test attempts to ensure that the below template parameter pack +// splitting technique executes in linear time in the number of template +// parameters. The size of the list below is selected so as to execute +// relatively quickly on a "good" compiler and to time out otherwise. + +template<typename...> struct TypeList; + +namespace detail { +template<unsigned> using Unsigned = unsigned; +template<typename T, T ...N> using ListOfNUnsignedsImpl = TypeList<Unsigned<N>...>; +template<unsigned N> using ListOfNUnsigneds = + __make_integer_seq<ListOfNUnsignedsImpl, unsigned, N>; + +template<typename T> struct TypeWrapper { + template<unsigned> using AsTemplate = T; +}; + +template<typename ...N> struct Splitter { + template<template<N> class ...L, + template<unsigned> class ...R> struct Split { + using Left = TypeList<L<0>...>; + using Right = TypeList<R<0>...>; + }; +}; +} + +template<typename TypeList, unsigned N, typename = detail::ListOfNUnsigneds<N>> +struct SplitAtIndex; + +template<typename ...T, unsigned N, typename ...NUnsigneds> +struct SplitAtIndex<TypeList<T...>, N, TypeList<NUnsigneds...>> : + detail::Splitter<NUnsigneds...>:: + template Split<detail::TypeWrapper<T>::template AsTemplate...> {}; + +template<typename T, int N> struct Rep : Rep<typename Rep<T, N-1>::type, 1> {}; +template<typename ...T> struct Rep<TypeList<T...>, 1> { typedef TypeList<T..., T...> type; }; + +using Ints = Rep<TypeList<int>, 14>::type; + +template<typename T> extern int Size; +template<typename ...T> constexpr int Size<TypeList<T...>> = sizeof...(T); + +using Left = SplitAtIndex<Ints, Size<Ints> / 2>::Left; +using Right = SplitAtIndex<Ints, Size<Ints> / 2>::Right; +static_assert(Size<Left> == 8192); +static_assert(Size<Right> == 8192); + +template<typename L, typename R> struct Concat; +template<typename ...L, typename ...R> struct Concat<TypeList<L...>, TypeList<R...>> { + using type = TypeList<L..., R...>; +}; + +using Ints = Concat<Left, Right>::type; diff --git a/test/SemaTemplate/temp_arg_nontype_cxx11.cpp b/test/SemaTemplate/temp_arg_nontype_cxx11.cpp index 0b8f0eed1601..313114e2cb8e 100644 --- a/test/SemaTemplate/temp_arg_nontype_cxx11.cpp +++ b/test/SemaTemplate/temp_arg_nontype_cxx11.cpp @@ -36,3 +36,15 @@ namespace check_conversion_early { struct Y { constexpr operator int() const { return 0; } }; template<Y &y> struct A<y> {}; // expected-error {{cannot be deduced}} expected-note {{'y'}} } + +namespace ReportCorrectParam { +template <int a, unsigned b, int c> +void TempFunc() {} + +void Useage() { + //expected-error@+2 {{no matching function}} + //expected-note@-4 {{candidate template ignored: invalid explicitly-specified argument for template parameter 'b'}} + TempFunc<1, -1, 1>(); +} +} + diff --git a/test/SemaTemplate/temp_arg_pack.cpp b/test/SemaTemplate/temp_arg_pack.cpp new file mode 100644 index 000000000000..b79dca78bced --- /dev/null +++ b/test/SemaTemplate/temp_arg_pack.cpp @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -verify %s + +namespace deduce_pack_non_pack { + template <typename...> class A; + template <typename> struct C {}; + template <typename T> void g(C<A<T>>); // expected-note {{candidate template ignored: deduced type 'C<A<[...], (no argument)>>' of 1st parameter does not match adjusted type 'C<A<[...], int>>' of argument [with T = bool]}} + void h(C<A<bool, int>> &x) { g(x); } // expected-error {{no matching function}} +} diff --git a/test/SemaTemplate/temp_class_spec_neg.cpp b/test/SemaTemplate/temp_class_spec_neg.cpp index 6366a528ff53..7465e5e8caaa 100644 --- a/test/SemaTemplate/temp_class_spec_neg.cpp +++ b/test/SemaTemplate/temp_class_spec_neg.cpp @@ -7,17 +7,11 @@ template<typename T> struct vector; namespace N { namespace M { template<typename T> struct A; -#if __cplusplus <= 199711L // C++03 or earlier modes - // expected-note@-2{{explicitly specialized declaration is here}} -#endif } } template<typename T> struct N::M::A<T*> { }; -#if __cplusplus <= 199711L -// expected-warning@-2{{first declaration of class template partial specialization of 'A' outside namespace 'M' is a C++11 extension}} -#endif // C++ [temp.class.spec]p9 // bullet 1, as amended by DR1315 diff --git a/test/SemaTemplate/template-id-expr.cpp b/test/SemaTemplate/template-id-expr.cpp index 4e6e22479b3f..0555d8b94504 100644 --- a/test/SemaTemplate/template-id-expr.cpp +++ b/test/SemaTemplate/template-id-expr.cpp @@ -56,7 +56,7 @@ struct Y0 { template<typename U> static void f2(U); - void f3(int); + void f3(int); // expected-note 2{{declared as a non-template here}} static int f4(int); template<typename U> @@ -85,10 +85,85 @@ struct Y0 { } }; +template<typename U> void Y0 + ::template // expected-error {{expected unqualified-id}} + f1(U) {} + +// FIXME: error recovery is awful without this. + ; + +template<typename T> +struct Y1 { + template<typename U> + void f1(U); + + template<typename U> + static void f2(U); + + void f3(int); // expected-note 4{{declared as a non-template here}} + + static int f4(int); + template<typename U> + static void f4(U); + + template<typename U> + void f() { + Y1::template f1<U>(0); + Y1::template f1(0); + this->template f1(0); + + Y1::template f2<U>(0); + Y1::template f2(0); + + Y1::template f3(0); // expected-error {{'f3' following the 'template' keyword does not refer to a template}} + Y1::template f3(); // expected-error {{'f3' following the 'template' keyword does not refer to a template}} + + int x; + x = Y1::f4(0); + x = Y1::f4<int>(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} + x = Y1::template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} + + x = this->f4(0); + x = this->f4<int>(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} + x = this->template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} + } +}; + +void use_Y1(Y1<int> y1) { y1.f<int>(); } // expected-note {{in instantiation of}} + +template<typename T> +struct Y2 : Y1<T> { + typedef ::Y1<T> Y1; + + template<typename U> + void f(Y1 *p) { + Y1::template f1<U>(0); + Y1::template f1(0); + p->template f1(0); + + Y1::template f2<U>(0); + Y1::template f2(0); + + Y1::template f3(0); // expected-error {{'f3' following the 'template' keyword does not refer to a template}} + Y1::template f3(); // expected-error {{'f3' following the 'template' keyword does not refer to a template}} + + int x; + x = Y1::f4(0); + x = Y1::f4<int>(0); // expected-error {{use 'template'}} expected-error {{assigning to 'int' from incompatible type 'void'}} + x = Y1::template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} + + x = p->f4(0); + x = p->f4<int>(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} expected-error {{use 'template'}} + x = p->template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} + } +}; + +void use_Y2(Y2<int> y2) { y2.f<int>(0); } // expected-note {{in instantiation of}} + struct A { template<int I> struct B { - static void b1(); + static void b1(); // expected-note {{declared as a non-template here}} }; }; diff --git a/test/SemaTemplate/typo-dependent-name.cpp b/test/SemaTemplate/typo-dependent-name.cpp index 78cedd0c98ca..0231740f6c2e 100644 --- a/test/SemaTemplate/typo-dependent-name.cpp +++ b/test/SemaTemplate/typo-dependent-name.cpp @@ -1,18 +1,45 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -// expected-no-diagnostics + +using nullptr_t = decltype(nullptr); template<typename T> struct Base { T inner; }; +int z; + template<typename T> -struct X { - template<typename U> +struct X : Base<T> { + static int z; + + template<int U> struct Inner { }; bool f(T other) { - return this->inner < other; + // A pair of comparisons; 'inner' is a dependent name so can't be assumed + // to be a template. + return this->inner < other > ::z; } }; + +void use_x(X<int> x) { x.f(0); } + +template<typename T> +struct Y { + static int z; + + template<int U> + struct Inner : Y { // expected-note {{declared here}} + }; + + bool f(T other) { + // We can determine that 'inner' does not exist at parse time, so can + // perform typo correction in this case. + return this->inner<other>::z; // expected-error {{no template named 'inner' in 'Y<T>'; did you mean 'Inner'?}} + } +}; + +struct Q { constexpr operator int() { return 0; } }; +void use_y(Y<Q> x) { x.f(Q()); } diff --git a/test/SemaTemplate/undefined-template.cpp b/test/SemaTemplate/undefined-template.cpp index 7dfe2fde94b0..52530e2e3909 100644 --- a/test/SemaTemplate/undefined-template.cpp +++ b/test/SemaTemplate/undefined-template.cpp @@ -1,5 +1,6 @@ // RUN: %clang_cc1 -fsyntax-only -verify -std=c++14 -Wundefined-func-template %s +#if !defined(INCLUDE) template <class T> struct C1 { static char s_var_1; // expected-note{{forward declaration of template entity is here}} static char s_var_2; // expected-note{{forward declaration of template entity is here}} @@ -142,6 +143,16 @@ namespace test_24 { void h(X<int> x) { g(x); } // no warning for use of 'g' despite the declaration having been instantiated from a template } +#define INCLUDE +#include "undefined-template.cpp" +void func_25(SystemHeader<char> *x) { + x->meth(); +} + int main() { return 0; } +#else +#pragma clang system_header +template <typename T> struct SystemHeader { T meth(); }; +#endif diff --git a/test/SemaTemplate/warn-thread-safety-analysis.cpp b/test/SemaTemplate/warn-thread-safety-analysis.cpp new file mode 100644 index 000000000000..710f424c17dc --- /dev/null +++ b/test/SemaTemplate/warn-thread-safety-analysis.cpp @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -std=c++11 %s -verify -Wthread-safety-analysis + +class Mutex { +public: + void Lock() __attribute__((exclusive_lock_function())); + void Unlock() __attribute__((unlock_function())); +}; + +class A { +public: + Mutex mu1, mu2; + + void foo() __attribute__((exclusive_locks_required(mu1))) __attribute__((exclusive_locks_required(mu2))) {} + + template <class T> void bar() __attribute__((exclusive_locks_required(mu1))) __attribute__((exclusive_locks_required(mu2))) { + foo(); + } +}; + +void f() { + A a; + a.mu1.Lock(); + a.mu2.Lock(); + a.bar<int>(); + a.mu2.Unlock(); + a.bar<int>(); // expected-warning {{calling function 'bar<int>' requires holding mutex 'a.mu2' exclusively}} + a.mu1.Unlock(); + a.bar<int>(); // expected-warning {{calling function 'bar<int>' requires holding mutex 'a.mu1' exclusively}} \ + expected-warning {{calling function 'bar<int>' requires holding mutex 'a.mu2' exclusively}} +} |
