aboutsummaryrefslogtreecommitdiff
path: root/test/SemaTemplate
diff options
context:
space:
mode:
Diffstat (limited to 'test/SemaTemplate')
-rw-r--r--test/SemaTemplate/alias-templates.cpp6
-rw-r--r--test/SemaTemplate/alignas.cpp11
-rw-r--r--test/SemaTemplate/argument-dependent-lookup.cpp45
-rw-r--r--test/SemaTemplate/attributes.cpp11
-rw-r--r--test/SemaTemplate/class-template-spec.cpp10
-rw-r--r--test/SemaTemplate/cxx17-inline-variables.cpp11
-rw-r--r--test/SemaTemplate/dependent-base-classes.cpp4
-rw-r--r--test/SemaTemplate/dependent-names.cpp40
-rw-r--r--test/SemaTemplate/dependent-template-recover.cpp64
-rw-r--r--test/SemaTemplate/ext_ms_template_spec.cpp8
-rw-r--r--test/SemaTemplate/function-pointer-qualifier.cpp29
-rw-r--r--test/SemaTemplate/function-template-specialization.cpp2
-rw-r--r--test/SemaTemplate/instantiate-after-fatal-cxx17.cpp16
-rw-r--r--test/SemaTemplate/instantiate-init.cpp14
-rw-r--r--test/SemaTemplate/instantiate-method.cpp2
-rw-r--r--test/SemaTemplate/late-parsing-eager-instantiation.cpp40
-rw-r--r--test/SemaTemplate/metafun-apply.cpp2
-rw-r--r--test/SemaTemplate/ms-function-specialization-class-scope.cpp24
-rw-r--r--test/SemaTemplate/nested-name-spec-template.cpp6
-rw-r--r--test/SemaTemplate/nested-template.cpp7
-rw-r--r--test/SemaTemplate/pack-deduction.cpp101
-rw-r--r--test/SemaTemplate/partial-spec-instantiate.cpp43
-rw-r--r--test/SemaTemplate/sizeof-pack.cpp7
-rw-r--r--test/SemaTemplate/stmt-expr.cpp39
-rw-r--r--test/SemaTemplate/temp-param-subst-linear.cpp56
-rw-r--r--test/SemaTemplate/temp_arg_nontype_cxx11.cpp12
-rw-r--r--test/SemaTemplate/temp_arg_pack.cpp8
-rw-r--r--test/SemaTemplate/temp_class_spec_neg.cpp6
-rw-r--r--test/SemaTemplate/template-id-expr.cpp79
-rw-r--r--test/SemaTemplate/typo-dependent-name.cpp35
-rw-r--r--test/SemaTemplate/undefined-template.cpp11
-rw-r--r--test/SemaTemplate/warn-thread-safety-analysis.cpp30
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}}
+}