| // RUN: %clang_cc1 -std=c++1z -verify %s -DERRORS -Wundefined-func-template |
| // RUN: %clang_cc1 -std=c++1z -verify %s -UERRORS -Wundefined-func-template |
| |
| // This test is split into two because we only produce "undefined internal" |
| // warnings if we didn't produce any errors. |
| #if ERRORS |
| |
| namespace std { |
| using size_t = decltype(sizeof(0)); |
| template<typename T> struct initializer_list { |
| const T *p; |
| size_t n; |
| initializer_list(); |
| }; |
| // FIXME: This should probably not be necessary. |
| template<typename T> initializer_list(initializer_list<T>) -> initializer_list<T>; |
| } |
| |
| template<typename T> constexpr bool has_type(...) { return false; } |
| template<typename T> constexpr bool has_type(T) { return true; } |
| |
| std::initializer_list il = {1, 2, 3, 4, 5}; |
| |
| template<typename T> struct vector { |
| template<typename Iter> vector(Iter, Iter); |
| vector(std::initializer_list<T>); |
| }; |
| |
| template<typename T> vector(std::initializer_list<T>) -> vector<T>; |
| template<typename Iter> explicit vector(Iter, Iter) -> vector<typename Iter::value_type>; |
| template<typename T> explicit vector(std::size_t, T) -> vector<T>; |
| |
| vector v1 = {1, 2, 3, 4}; |
| static_assert(has_type<vector<int>>(v1)); |
| |
| struct iter { typedef char value_type; } it, end; |
| vector v2(it, end); |
| static_assert(has_type<vector<char>>(v2)); |
| |
| vector v3(5, 5); |
| static_assert(has_type<vector<int>>(v3)); |
| |
| vector v4 = {it, end}; |
| static_assert(has_type<vector<iter>>(v4)); |
| |
| vector v5{it, end}; |
| static_assert(has_type<vector<iter>>(v5)); |
| |
| template<typename ...T> struct tuple { tuple(T...); }; |
| template<typename ...T> explicit tuple(T ...t) -> tuple<T...>; // expected-note {{declared}} |
| // FIXME: Remove |
| template<typename ...T> tuple(tuple<T...>) -> tuple<T...>; |
| |
| const int n = 4; |
| tuple ta = tuple{1, 'a', "foo", n}; |
| static_assert(has_type<tuple<int, char, const char*, int>>(ta)); |
| |
| tuple tb{ta}; |
| static_assert(has_type<tuple<int, char, const char*, int>>(tb)); |
| |
| // FIXME: This should be tuple<tuple<...>>; when the above guide is removed. |
| tuple tc = {ta}; |
| static_assert(has_type<tuple<int, char, const char*, int>>(tc)); |
| |
| tuple td = {1, 2, 3}; // expected-error {{selected an explicit deduction guide}} |
| static_assert(has_type<tuple<int, char, const char*, int>>(td)); |
| |
| // FIXME: This is a GCC extension for now; if CWG don't allow this, at least |
| // add a warning for it. |
| namespace new_expr { |
| tuple<int> *p = new tuple{0}; |
| tuple<float, float> *q = new tuple(1.0f, 2.0f); |
| } |
| |
| namespace ambiguity { |
| template<typename T> struct A {}; |
| A(unsigned short) -> A<int>; // expected-note {{candidate}} |
| A(short) -> A<int>; // expected-note {{candidate}} |
| A a = 0; // expected-error {{ambiguous deduction for template arguments of 'A'}} |
| |
| template<typename T> struct B {}; |
| template<typename T> B(T(&)(int)) -> B<int>; // expected-note {{candidate function [with T = int]}} |
| template<typename T> B(int(&)(T)) -> B<int>; // expected-note {{candidate function [with T = int]}} |
| int f(int); |
| B b = f; // expected-error {{ambiguous deduction for template arguments of 'B'}} |
| } |
| |
| // FIXME: Revisit this once CWG decides if attributes, and [[deprecated]] in |
| // particular, should be permitted here. |
| namespace deprecated { |
| template<typename T> struct A { A(int); }; |
| [[deprecated]] A(int) -> A<void>; // expected-note {{marked deprecated here}} |
| A a = 0; // expected-warning {{'<deduction guide for A>' is deprecated}} |
| } |
| |
| namespace dependent { |
| template<template<typename...> typename A> decltype(auto) a = A{1, 2, 3}; |
| static_assert(has_type<vector<int>>(a<vector>)); |
| static_assert(has_type<tuple<int, int, int>>(a<tuple>)); |
| |
| struct B { |
| template<typename T> struct X { X(T); }; |
| X(int) -> X<int>; |
| template<typename T> using Y = X<T>; // expected-note {{template}} |
| }; |
| template<typename T> void f() { |
| typename T::X tx = 0; |
| typename T::Y ty = 0; // expected-error {{alias template 'Y' requires template arguments; argument deduction only allowed for class templates}} |
| } |
| template void f<B>(); // expected-note {{in instantiation of}} |
| |
| template<typename T> struct C { C(T); }; |
| template<typename T> C(T) -> C<T>; |
| template<typename T> void g(T a) { |
| C b = 0; |
| C c = a; |
| using U = decltype(b); // expected-note {{previous}} |
| using U = decltype(c); // expected-error {{different types ('C<const char *>' vs 'C<int>')}} |
| } |
| void h() { |
| g(0); |
| g("foo"); // expected-note {{instantiation of}} |
| } |
| } |
| |
| namespace look_into_current_instantiation { |
| template<typename U> struct Q {}; |
| template<typename T> struct A { |
| using U = T; |
| template<typename> using V = Q<A<T>::U>; |
| template<typename W = int> A(V<W>); |
| }; |
| A a = Q<float>(); // ok, can look through class-scope typedefs and alias |
| // templates, and members of the current instantiation |
| A<float> &r = a; |
| |
| template<typename T> struct B { // expected-note {{could not match 'B<T>' against 'int'}} |
| struct X { |
| typedef T type; |
| }; |
| B(typename X::type); // expected-note {{couldn't infer template argument 'T'}} |
| }; |
| B b = 0; // expected-error {{no viable}} |
| |
| // We should have a substitution failure in the immediate context of |
| // deduction when using the C(T, U) constructor (probably; core wording |
| // unclear). |
| template<typename T> struct C { |
| using U = typename T::type; |
| C(T, U); |
| }; |
| |
| struct R { R(int); typedef R type; }; |
| C(...) -> C<R>; |
| |
| C c = {1, 2}; |
| } |
| |
| namespace nondeducible { |
| template<typename A, typename B> struct X {}; |
| |
| template<typename A> // expected-note {{non-deducible template parameter 'A'}} |
| X() -> X<A, int>; // expected-error {{deduction guide template contains a template parameter that cannot be deduced}} |
| |
| template<typename A> // expected-note {{non-deducible template parameter 'A'}} |
| X(typename X<A, int>::type) -> X<A, int>; // expected-error {{deduction guide template contains a template parameter that cannot be deduced}} |
| |
| template<typename A = int, |
| typename B> // expected-note {{non-deducible template parameter 'B'}} |
| X(int) -> X<A, B>; // expected-error {{deduction guide template contains a template parameter that cannot be deduced}} |
| |
| template<typename A = int, |
| typename ...B> |
| X(float) -> X<A, B...>; // ok |
| } |
| |
| namespace default_args_from_ctor { |
| template <class A> struct S { S(A = 0) {} }; |
| S s(0); |
| |
| template <class A> struct T { template<typename B> T(A = 0, B = 0) {} }; |
| T t(0, 0); |
| } |
| |
| namespace transform_params { |
| template<typename T, T N, template<T (*v)[N]> typename U, T (*X)[N]> |
| struct A { |
| template<typename V, V M, V (*Y)[M], template<V (*v)[M]> typename W> |
| A(U<X>, W<Y>); |
| |
| static constexpr T v = N; |
| }; |
| |
| int n[12]; |
| template<int (*)[12]> struct Q {}; |
| Q<&n> qn; |
| A a(qn, qn); |
| static_assert(a.v == 12); |
| |
| template<typename ...T> struct B { |
| template<T ...V> B(const T (&...p)[V]) { |
| constexpr int Vs[] = {V...}; |
| static_assert(Vs[0] == 3 && Vs[1] == 4 && Vs[2] == 4); |
| } |
| static constexpr int (*p)(T...) = (int(*)(int, char, char))nullptr; |
| }; |
| B b({1, 2, 3}, "foo", {'x', 'y', 'z', 'w'}); // ok |
| |
| template<typename ...T> struct C { |
| template<T ...V, template<T...> typename X> |
| C(X<V...>); |
| }; |
| template<int...> struct Y {}; |
| C c(Y<0, 1, 2>{}); |
| |
| template<typename ...T> struct D { |
| template<T ...V> D(Y<V...>); |
| }; |
| D d(Y<0, 1, 2>{}); |
| } |
| |
| namespace variadic { |
| int arr3[3], arr4[4]; |
| |
| // PR32673 |
| template<typename T> struct A { |
| template<typename ...U> A(T, U...); |
| }; |
| A a(1, 2, 3); |
| |
| template<typename T> struct B { |
| template<int ...N> B(T, int (&...r)[N]); |
| }; |
| B b(1, arr3, arr4); |
| |
| template<typename T> struct C { |
| template<template<typename> typename ...U> C(T, U<int>...); |
| }; |
| C c(1, a, b); |
| |
| template<typename ...U> struct X { |
| template<typename T> X(T, U...); |
| }; |
| X x(1, 2, 3); |
| |
| template<int ...N> struct Y { |
| template<typename T> Y(T, int (&...r)[N]); |
| }; |
| Y y(1, arr3, arr4); |
| |
| template<template<typename> typename ...U> struct Z { |
| template<typename T> Z(T, U<int>...); |
| }; |
| Z z(1, a, b); |
| } |
| |
| namespace tuple_tests { |
| // The converting n-ary constructor appears viable, deducing T as an empty |
| // pack (until we check its SFINAE constraints). |
| namespace libcxx_1 { |
| template<class ...T> struct tuple { |
| template<class ...Args> struct X { static const bool value = false; }; |
| template<class ...U, bool Y = X<U...>::value> tuple(U &&...u); |
| }; |
| tuple a = {1, 2, 3}; |
| } |
| |
| // Don't get caught by surprise when X<...> doesn't even exist in the |
| // selected specialization! |
| namespace libcxx_2 { |
| template<class ...T> struct tuple { |
| template<class ...Args> struct X { static const bool value = false; }; |
| // Substitution into X<U...>::value succeeds but produces the |
| // value-dependent expression |
| // tuple<T...>::X<>::value |
| // FIXME: Is that the right behavior? |
| template<class ...U, bool Y = X<U...>::value> tuple(U &&...u); |
| }; |
| template <> class tuple<> {}; |
| tuple a = {1, 2, 3}; // expected-error {{excess elements in struct initializer}} |
| } |
| |
| namespace libcxx_3 { |
| template<typename ...T> struct scoped_lock { |
| scoped_lock(T...); |
| }; |
| template<> struct scoped_lock<> {}; |
| scoped_lock l = {}; |
| } |
| } |
| |
| namespace dependent { |
| template<typename T> struct X { |
| X(T); |
| }; |
| template<typename T> int Var(T t) { |
| X x(t); |
| return X(x) + 1; // expected-error {{invalid operands}} |
| } |
| template<typename T> int Cast(T t) { |
| return X(X(t)) + 1; // expected-error {{invalid operands}} |
| } |
| template<typename T> int New(T t) { |
| return X(new X(t)) + 1; // expected-error {{invalid operands}} |
| }; |
| template int Var(float); // expected-note {{instantiation of}} |
| template int Cast(float); // expected-note {{instantiation of}} |
| template int New(float); // expected-note {{instantiation of}} |
| template<typename T> int operator+(X<T>, int); |
| template int Var(int); |
| template int Cast(int); |
| template int New(int); |
| |
| template<template<typename> typename Y> void test() { |
| Y(0); |
| new Y(0); |
| Y y(0); |
| } |
| template void test<X>(); |
| } |
| |
| namespace injected_class_name { |
| template<typename T = void> struct A { |
| A(); |
| template<typename U> A(A<U>); |
| }; |
| A<int> a; |
| A b = a; |
| using T = decltype(a); |
| using T = decltype(b); |
| } |
| |
| namespace member_guides { |
| // PR34520 |
| template<class> |
| struct Foo { |
| template <class T> struct Bar { |
| Bar(...) {} |
| }; |
| Bar(int) -> Bar<int>; |
| }; |
| Foo<int>::Bar b = 0; |
| |
| struct A { |
| template<typename T> struct Public; // expected-note {{declared public}} |
| Public(float) -> Public<float>; |
| protected: // expected-note {{declared protected by intervening access specifier}} |
| template<typename T> struct Protected; // expected-note 2{{declared protected}} |
| Protected(float) -> Protected<float>; |
| Public(int) -> Public<int>; // expected-error {{different access}} |
| private: // expected-note {{declared private by intervening access specifier}} |
| template<typename T> struct Private; // expected-note {{declared private}} |
| Protected(int) -> Protected<int>; // expected-error {{different access}} |
| public: // expected-note 2{{declared public by intervening access specifier}} |
| template<typename T> Public(T) -> Public<T>; |
| template<typename T> Protected(T) -> Protected<T>; // expected-error {{different access}} |
| template<typename T> Private(T) -> Private<T>; // expected-error {{different access}} |
| }; |
| } |
| |
| namespace rdar41903969 { |
| template <class T> struct A {}; |
| template <class T> struct B; |
| template <class T> struct C { |
| C(A<T>&); |
| C(B<T>&); |
| }; |
| |
| void foo(A<int> &a, B<int> &b) { |
| (void)C{b}; |
| (void)C{a}; |
| } |
| |
| template<typename T> struct X { |
| X(std::initializer_list<T>) = delete; |
| X(const X&); |
| }; |
| |
| template <class T> struct D : X<T> {}; |
| |
| void bar(D<int>& d) { |
| (void)X{d}; |
| } |
| } |
| |
| namespace rdar41330135 { |
| template <int> struct A {}; |
| template <class T> |
| struct S { |
| template <class U> |
| S(T a, U t, A<sizeof(t)>); |
| }; |
| template <class T> struct D { |
| D(T t, A<sizeof(t)>); |
| }; |
| int f() { |
| S s(0, 0, A<sizeof(int)>()); |
| D d(0, A<sizeof(int)>()); |
| } |
| |
| namespace test_dupls { |
| template<unsigned long> struct X {}; |
| template<typename T> struct A { |
| A(T t, X<sizeof(t)>); |
| }; |
| A a(0, {}); |
| template<typename U> struct B { |
| B(U u, X<sizeof(u)>); |
| }; |
| B b(0, {}); |
| } |
| |
| } |
| |
| #pragma clang diagnostic push |
| #pragma clang diagnostic warning "-Wctad-maybe-unsupported" |
| namespace test_implicit_ctad_warning { |
| |
| template <class T> |
| struct Tag {}; |
| |
| template <class T> |
| struct NoExplicit { // expected-note {{add a deduction guide to suppress this warning}} |
| NoExplicit(T) {} |
| NoExplicit(T, int) {} |
| }; |
| |
| // expected-warning@+1 {{'NoExplicit' may not intend to support class template argument deduction}} |
| NoExplicit ne(42); |
| |
| template <class U> |
| struct HasExplicit { |
| HasExplicit(U) {} |
| HasExplicit(U, int) {} |
| }; |
| template <class U> HasExplicit(U, int) -> HasExplicit<Tag<U>>; |
| |
| HasExplicit he(42); |
| |
| // Motivating examples from (taken from Stephan Lavavej's 2018 Cppcon talk) |
| template <class T, class U> |
| struct AmateurPair { // expected-note {{add a deduction guide to suppress this warning}} |
| T first; |
| U second; |
| explicit AmateurPair(const T &t, const U &u) {} |
| }; |
| // expected-warning@+1 {{'AmateurPair' may not intend to support class template argument deduction}} |
| AmateurPair p1(42, "hello world"); // deduces to Pair<int, char[12]> |
| |
| template <class T, class U> |
| struct AmateurPair2 { // expected-note {{add a deduction guide to suppress this warning}} |
| T first; |
| U second; |
| explicit AmateurPair2(T t, U u) {} |
| }; |
| // expected-warning@+1 {{'AmateurPair2' may not intend to support class template argument deduction}} |
| AmateurPair2 p2(42, "hello world"); // deduces to Pair2<int, const char*> |
| |
| template <class T, class U> |
| struct ProPair { |
| T first; U second; |
| explicit ProPair(T const& t, U const& u) {} |
| }; |
| template<class T1, class T2> |
| ProPair(T1, T2) -> ProPair<T1, T2>; |
| ProPair p3(42, "hello world"); // deduces to ProPair<int, const char*> |
| static_assert(__is_same(decltype(p3), ProPair<int, const char*>)); |
| |
| // Test that user-defined explicit guides suppress the warning even if they |
| // aren't used as candidates. |
| template <class T> |
| struct TestExplicitCtor { |
| TestExplicitCtor(T) {} |
| }; |
| template <class T> |
| explicit TestExplicitCtor(TestExplicitCtor<T> const&) -> TestExplicitCtor<void>; |
| TestExplicitCtor<int> ce1{42}; |
| TestExplicitCtor ce2 = ce1; |
| static_assert(__is_same(decltype(ce2), TestExplicitCtor<int>), ""); |
| |
| struct allow_ctad_t { |
| allow_ctad_t() = delete; |
| }; |
| |
| template <class T> |
| struct TestSuppression { |
| TestSuppression(T) {} |
| }; |
| TestSuppression(allow_ctad_t)->TestSuppression<void>; |
| TestSuppression ta("abc"); |
| static_assert(__is_same(decltype(ta), TestSuppression<const char *>), ""); |
| } |
| #pragma clang diagnostic pop |
| |
| namespace PR41549 { |
| |
| template <class H, class P> struct umm; |
| |
| template <class H = int, class P = int> |
| struct umm { |
| umm(H h = 0, P p = 0); |
| }; |
| |
| template <class H, class P> struct umm; |
| |
| umm m(1); |
| |
| } |
| |
| #else |
| |
| // expected-no-diagnostics |
| namespace undefined_warnings { |
| // Make sure we don't get an "undefined but used internal symbol" warning for the deduction guide here. |
| namespace { |
| template <typename T> |
| struct TemplDObj { |
| explicit TemplDObj(T func) noexcept {} |
| }; |
| auto test1 = TemplDObj(0); |
| |
| TemplDObj(float) -> TemplDObj<double>; |
| auto test2 = TemplDObj(.0f); |
| } |
| } |
| #endif |