c++: P0847R7 (deducing this) - xobj lambdas. [PR102609]
[official-gcc.git] / gcc / testsuite / g++.dg / cpp23 / explicit-obj-lambda13.C
blobc48de47e1f97bef21c72a8497f8f7049298017e8
1 // P0847R7
2 // { dg-do compile { target c++23 } }
4 // SFINAE when the call operator for a lambda with captures is instantiated
5 // with an unrelated type.
6 // diagnose ambiguous overloads when the call operator for a captureless lambda is instantiated
7 // with an unrelated type.
9 // overload resolution from call expression
11 /* [expr.prim.lambda.general-5]
13    Given a lambda with a lambda-capture, the type of the explicit object
14    parameter, if any, of the lambda's function call operator (possibly
15    instantiated from a function call operator template) shall be either:
17    --(5.1) the closure type,
18    --(5.2) a class type derived from the closure type, or
19    --(5.3) a reference to a possibly cv-qualified such type.  */
21 // The above wording is similar to [dcl.fct-15] which is handled by SFINAE,
22 // thus we also handle the following cases the same way.
24 // We need the 2 overloads to be ambiguous to observe substitution failure
25 // for the lambda's call operator when instantiated with an unrelated type.
26 // We accomplish this by introducing both overloads through using declarations.
28 struct B0 {
29   void operator()(this auto) {}
32 template<typename T>
33 struct S0 : T, B0 {
34   using T::operator();
35   using B0::operator();
36   operator int() const {return {};}
39 void test0()
41   auto s0 = S0{[](this auto){}};
42   s0.operator()<int>(); // { dg-error {call of overloaded 'operator\(\)\(\)' is ambiguous} }
44   auto s1 = S0{[x = 42](this auto){}};
45   s1.operator()<int>(); // { dg-bogus {call of overloaded 'operator\(\)\(\)' is ambiguous} }
49 struct B1 {
50   void operator()(this auto&&) {}
52 template<typename T>
53 struct S1 : T, B1 {
54   using T::operator();
55   using B1::operator();
56   operator int() const {return {};}
59 void test1()
61   auto s0 = S1{[](this auto&&){}};
62   s0.operator()<int>(); // { dg-error {call of overloaded 'operator\(\)\(\)' is ambiguous} }
64   auto s1 = S1{[x = 42](this auto&&){}};
65   s1.operator()<int>(); // { dg-bogus {call of overloaded 'operator\(\)\(\)' is ambiguous} }
69 struct B2 {
70   // needs to be a template, we are explicitly passing a template argument,
71   // without the parameter here this would not be a candidate
72   template<typename U = void>
73   void operator()(this int) {}
76 template<typename T>
77 struct S2 : T, B2 {
78   using T::operator();
79   using B2::operator();
80   operator int() const {return {};}
83 // I don't know why the calls to s0::operator() are not ambiguous, it might have to do with one taking less conversions, I'm not sure.
84 // Someone who knows better should remove those cases if they are sure they are actually correct.
86 void test2()
88   auto s0 = S2{[](this auto){}};
89   s0.operator()<int>(); // { dg-error {call of overloaded 'operator\(\)\(\)' is ambiguous} {Not sure if this is a bug, one might be a better conversion} { xfail *-*-* } }
91   auto s1 = S2{[x = 42](this auto){}};
92   s1.operator()<int>(); // { dg-bogus {call of overloaded 'operator\(\)\(\)' is ambiguous} }
95 void test3()
97   auto s0 = S2{[](this auto&&){}};
98   s0.operator()<int>(); // { dg-error {call of overloaded 'operator\(\)\(\)' is ambiguous} {Not sure if this is a bug, one might be a better conversion} { xfail *-*-* } }
100   auto s1 = S2{[x = 42](this auto&&){}};
101   s1.operator()<int>(); // { dg-bogus {call of overloaded 'operator\(\)\(\)' is ambiguous} }