summaryrefslogtreecommitdiffstats
path: root/clang/test/SemaTemplate/cxx1z-using-declaration.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/test/SemaTemplate/cxx1z-using-declaration.cpp')
-rw-r--r--clang/test/SemaTemplate/cxx1z-using-declaration.cpp230
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}}
+ }
+}
OpenPOWER on IntegriCloud