diff options
Diffstat (limited to 'clang/test/SemaTemplate/cxx1z-using-declaration.cpp')
-rw-r--r-- | clang/test/SemaTemplate/cxx1z-using-declaration.cpp | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/clang/test/SemaTemplate/cxx1z-using-declaration.cpp b/clang/test/SemaTemplate/cxx1z-using-declaration.cpp new file mode 100644 index 00000000000..7bef36db1f4 --- /dev/null +++ b/clang/test/SemaTemplate/cxx1z-using-declaration.cpp @@ -0,0 +1,230 @@ +// RUN: %clang_cc1 -std=c++1z -verify %s + +// Test that we cope with failure to expand a pack. +template<typename ...T> struct Unexpanded : T... { + using T::f; // expected-error {{unexpanded}} + using typename T::type; // expected-error {{unexpanded}} + template<typename ...U> void g(U ...u) { f(u...); } // expected-error {{undeclared identifier 'f'}} + void h() { + Unexpanded<type...> *p; // expected-error {{undeclared identifier 'type'}} + } +}; +void test_Unexpanded() { + struct A { void f(); }; // expected-note {{must qualify}} + struct B { void f(int); }; // expected-note {{must qualify}} + Unexpanded<A, B>().g(0); // expected-note {{instantiation of}} +} + +// Test using non-type members from pack of base classes. +template<typename ...T> struct A : T... { // expected-note 2{{candidate}} + using T::T ...; // expected-note 6{{inherited here}} + using T::operator() ...; + using T::operator T* ...; + using T::h ...; + + void f(int n) { h(n); } // expected-error {{ambiguous}} + void f(int n, int m) { h(n, m); } // expected-error {{member using declaration 'h' instantiates to an empty pack}} + void g(int n) { (*this)(n); } // expected-error {{ambiguous}} + void g(int n, int m) { (*this)(n, m); } // expected-error {{does not provide a call operator}} +}; + +namespace test_A { + struct X { // expected-note 2{{candidate}} + X(); + X(int); // expected-note {{candidate}} + void operator()(int); // expected-note 2{{candidate}} + operator X *(); + void h(int); // expected-note {{candidate}} + }; + struct Y { + Y(); + Y(int, int); + void operator()(int, int); + operator Y *(); + void h(int, int); // expected-note {{not viable}} + }; + struct Z { // expected-note 2{{candidate}} + Z(); + Z(int); // expected-note {{candidate}} + void operator()(int); // expected-note 2{{candidate}} + operator Z *(); + void h(int); // expected-note {{candidate}} + }; + + void f() { + A<> a; + a.f(0, 0); // expected-note {{instantiation of}} + a.g(0, 0); // expected-note {{instantiation of}} + + A<X, Y> axy(0); + A<X, Y>(0, 0); + axy.f(0); + axy.f(0, 0); + axy.g(0); + axy.g(0, 0); + axy(0); + axy(0, 0); + + A<X, Y, Z>(0); // expected-error {{ambiguous}} + A<X, Y, Z> axyz(0, 0); + axyz.f(0); // expected-note {{instantiation of}} + axyz.f(0, 0); + axyz.g(0); // expected-note {{instantiation of}} + axyz.g(0, 0); + axyz(0); // expected-error {{ambiguous}} + axyz(0, 0); + + X *x; + x = a; // expected-error {{incompatible}} + x = axy; + x = axyz; + x = a.operator X*(); // expected-error {{no member}} + x = axy.operator X*(); + x = axyz.operator X*(); + + Z *z; + z = axyz; + z = axyz.operator Z*(); + } +} + +// Test using pack of non-type members from single base class. +template<typename X, typename Y, typename ...T> struct B : X, Y { + using X::operator T* ...; +}; + +namespace test_B { + struct X { operator int*(); operator float*(); operator char*(); }; // expected-note {{candidate}} + struct Y { operator int*(); operator float*(); operator char*(); }; // expected-note {{candidate}} + B<X, Y, int, float> bif; + int *pi = bif; + float *pf = bif; + char *pc = bif; // expected-error {{ambiguous}} +} + +// Test using type member from pack of base classes. +template<typename ...T> struct C : T... { + using typename T::type ...; // expected-error {{target of using declaration conflicts}} + void f() { type value; } // expected-error {{member using declaration 'type' instantiates to an empty pack}} +}; + +namespace test_C { + struct X { typedef int type; }; + struct Y { typedef int type; }; // expected-note {{conflicting}} + struct Z { typedef float type; }; // expected-note {{target}} + + void f() { + C<> c; + c.f(); // expected-note {{instantiation of}} + + C<X, Y> cxy; + cxy.f(); + + C<X, Y, Z> cxyz; // expected-note {{instantiation of}} + cxyz.f(); + } +} + +// Test using pack of non-types at block scope. +template<typename ...T> int fn1() { + using T::e ...; // expected-error 2{{class member}} expected-note 2{{instead}} + // expected-error@-1 2{{produces multiple values}} + return e; // expected-error {{using declaration 'e' instantiates to an empty pack}} +} + +namespace test_fn1 { + struct X { static int e; }; + struct Y { typedef int e; }; + inline namespace P { enum E { e }; } + inline namespace Q { enum F { e }; } + void f() { + fn1<>(); // expected-note {{instantiation of}} + fn1<X>(); // expected-note {{instantiation of}} + fn1<Y>(); // expected-note {{instantiation of}} + fn1<E>(); + fn1<E, F>(); // expected-note {{instantiation of}} + fn1<E, X>(); // expected-note {{instantiation of}} + } +} + +// Test using pack of types at block scope. +template<typename ...T> void fn2() { + // This cannot ever be valid: in order for T::type to be a type, T must be a + // class, and a class member cannot be named by a block-scope using declaration. + using typename T::type ...; // expected-error {{class member}} + type x; // expected-error {{unknown type name 'type'}} +} + +// Test partial substitution into class-scope pack. +template<typename ...T> auto lambda1() { + return [](auto x) { + struct A : T::template X<decltype(x)>... { // expected-note 1+{{instantiation of}} + using T::template X<decltype(x)>::f ...; + using typename T::template X<decltype(x)>::type ...; + void g(int n) { f(n); } // expected-error {{empty pack}} expected-error {{expected 2, have 1}} expected-error {{ambiguous}} + void h() { type value; } // expected-error {{empty pack}} + }; + return A(); + }; +} + +namespace test_lambda1 { + struct A { + template<typename> struct X { + void f(int); // expected-note {{candidate}} + using type = int; + }; + }; + struct B { + template<typename> struct X { + void f(int, int); // expected-note {{declared here}} expected-note {{not viable}} + using type = int; + }; + }; + struct C { + template<typename> struct X { + void f(int); // expected-note {{candidate}} + void f(int, int); // expected-note {{not viable}} + using type = int; + }; + }; + + void f() { + lambda1<>() // expected-note 2{{instantiation of}} + (0) + // FIXME: This is poor error recovery + .g(0); // expected-error {{no member named 'g'}} + lambda1<A>() + (0) + .g(0); + lambda1<B>() + (0) // expected-note {{instantiation of}} + .g(0); + lambda1<A, B, C>() + (0) // expected-note {{instantiation of}} + .g(0); + } +} + +namespace p0195r2_example { + template<typename ...Ts> + struct Overloader : Ts... { + using Ts::operator() ...; + }; + + template<typename ...Ts> + constexpr auto make_overloader(Ts &&...ts) { + return Overloader<Ts...>{static_cast<Ts&&>(ts)...}; + } + + void test() { + auto o = make_overloader( + [&](int &r) -> int & { return r; }, // expected-note {{candidate function}} + [&](float &r) -> float & { return r; } // expected-note {{candidate function}} + ); + int a; float f; double d; + int &ra = o(a); + float &rf = o(f); + double &rd = o(d); // expected-error {{no matching function}} + } +} |