// RUN: %clang_cc1 -std=c++20 -verify %s // RUN: %clang_cc1 -std=c++17 -verify %s // p0388 conversions to unbounded array // dcl.init.list/3 namespace One { int ga[1]; auto &frob1() { int(&r1)[] = ga; #if __cplusplus < 202002 // expected-error@-2{{cannot bind to a value of unrelated type}} #endif return r1; } auto &frob2(int (&arp)[1]) { int(&r2)[] = arp; #if __cplusplus < 202002 // expected-error@-2{{cannot bind to a value of unrelated type}} #endif return r2; } } // namespace One namespace Two { int ga[1]; auto *frob1() { int(*r1)[] = &ga; #if __cplusplus < 202002 // expected-error@-2{{with an rvalue of type}} #endif return r1; } auto *frob2(int (*arp)[1]) { int(*r2)[] = arp; #if __cplusplus < 202002 // expected-error@-2{{with an lvalue of type}} #endif return r2; } } // namespace Two namespace Four { using Inc = int[2]; using Mat = Inc[1]; Mat *ga[2]; auto *frob1() { Inc(*const(*r1)[])[] = &ga; #if __cplusplus < 202002 // expected-error@-2{{with an rvalue of type}} #else // missing a required 'const' Inc(*(*r2)[])[] = &ga; // expected-error{{cannot initialize}} #endif return r1; } auto *frob2(Mat *(*arp)[1]) { Inc(*const(*r2)[])[] = arp; #if __cplusplus < 202002 // expected-error@-2{{with an lvalue of type}} #else Inc(*(*r3)[])[] = arp; // expected-error{{cannot initialize}} #endif return r2; } } // namespace Four namespace Five { // from the paper char (&b(int(&&)[]))[1]; // #1 char (&b(long(&&)[]))[2]; // #2 char (&b(int(&&)[1]))[3]; // #3 char (&b(long(&&)[1]))[4]; // #4 char (&b(int(&&)[2]))[5]; // #5 #if __cplusplus < 202002 // expected-note@-6{{cannot convert initializer}} // expected-note@-6{{cannot convert initializer}} // expected-note@-6{{too many initializers}} // expected-note@-6{{too many initializers}} // expected-note@-6{{too many initializers}} #endif void f() { static_assert(sizeof(b({1})) == 3); static_assert(sizeof(b({1, 2})) == 5); static_assert(sizeof(b({1, 2, 3})) == 1); #if __cplusplus < 202002 // expected-error@-2{{no matching function}} #endif } } // namespace Five #if __cplusplus >= 202002 namespace Six { // from over.ics.rank 3.1 char (&f(int(&&)[]))[1]; // #1 char (&f(double(&&)[]))[2]; // #2 char (&f(int(&&)[2]))[3]; // #3 void toto() { // Calls #1: Better than #2 due to conversion, better than #3 due to bounds static_assert(sizeof(f({1})) == 1); // Calls #2: Identity conversion is better than floating-integral conversion static_assert(sizeof(f({1.0})) == 2); // Calls #2: Identity conversion is better than floating-integral conversion static_assert(sizeof(f({1.0, 2.0})) == 2); // Calls #3: Converting to array of known bound is better than to unknown // bound, and an identity conversion is better than // floating-integral conversion static_assert(sizeof(f({1, 2})) == 3); } } // namespace Six namespace Seven { char (&f(int(&&)[]))[1]; // #1 char (&f(double(&&)[1]))[2]; // #2 void quux() { // Calls #2, float-integral conversion rather than create zero-sized array static_assert(sizeof(f({})) == 2); } } // namespace Seven namespace Eight { // brace-elision is not a thing here: struct A { int x, y; }; char (&f1(int(&&)[]))[1]; // #1 char (&f1(A(&&)[]))[2]; // #2 void g1() { // pick #1, even though that is more elements than #2 // 6 ints, as opposed to 3 As static_assert(sizeof(f1({1, 2, 3, 4, 5, 6})) == 1); } void f2(A(&&)[]); // expected-note{{candidate function not viable}} void g2() { f2({1, 2, 3, 4, 5, 6}); // expected-error{{no matching function}} } void f3(A(&&)[]); void g3() { auto &f = f3; f({1, 2, 3, 4, 5, 6}); // OK! We're coercing to an already-selected function } } // namespace Eight #endif