231 lines
6.7 KiB
C++
231 lines
6.7 KiB
C++
|
// 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 {{explicit qualification required to use member 'f' from dependent base class}}
|
||
|
void h() {
|
||
|
Unexpanded<type...> *p; // expected-error {{undeclared identifier 'type'}}
|
||
|
}
|
||
|
};
|
||
|
void test_Unexpanded() {
|
||
|
struct A { void f(); };
|
||
|
struct B { void f(int); }; // expected-note {{here}}
|
||
|
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... {
|
||
|
using T::T ...; // expected-note 2{{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 {
|
||
|
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);
|
||
|
};
|
||
|
struct Z {
|
||
|
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}}
|
||
|
using type = int;
|
||
|
};
|
||
|
};
|
||
|
struct C {
|
||
|
template<typename> struct X {
|
||
|
void f(int); // expected-note {{candidate}}
|
||
|
void f(int, int);
|
||
|
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}}
|
||
|
}
|
||
|
}
|