From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1734) id CF6CA385800F; Thu, 18 Nov 2021 23:01:29 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org CF6CA385800F MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Marek Polacek To: gcc-cvs@gcc.gnu.org Subject: [gcc r12-5386] c++: Implement C++23 P0849R8 - auto(x) [PR103049] X-Act-Checkin: gcc X-Git-Author: Marek Polacek X-Git-Refname: refs/heads/trunk X-Git-Oldrev: 6f4ac4f81f89caac7e74127ed2e6db6bbb3d7426 X-Git-Newrev: 93810fd673654db9ff16170624a6d36449eab241 Message-Id: <20211118230129.CF6CA385800F@sourceware.org> Date: Thu, 18 Nov 2021 23:01:29 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 18 Nov 2021 23:01:29 -0000 https://gcc.gnu.org/g:93810fd673654db9ff16170624a6d36449eab241 commit r12-5386-g93810fd673654db9ff16170624a6d36449eab241 Author: Marek Polacek Date: Wed Nov 3 11:04:22 2021 -0400 c++: Implement C++23 P0849R8 - auto(x) [PR103049] This patch implements P0849R8 which allows auto in a functional cast, the result of which is a prvalue. [expr.type.conv]/1 says that the type is determined by placeholder type deduction. We only accept 'auto', not 'decltype(auto)' -- that the type shall be auto comes from [dcl.type.auto.deduct]. Therefore the rules are like for [temp.deduct.call], deducing template arguments from a function call, so the result type will never be a reference, and we decay arrays/functions. PR c++/103049 gcc/cp/ChangeLog: * semantics.c (finish_compound_literal): Accept C++23 auto{x}. * typeck2.c (build_functional_cast_1): Accept C++23 auto(x). gcc/testsuite/ChangeLog: * g++.dg/cpp0x/auto25.C: Adjust dg-error. * g++.dg/cpp0x/auto9.C: Likewise. * g++.dg/cpp2a/concepts-pr84979-2.C: Likewise. * g++.dg/cpp2a/concepts-pr84979-3.C: Likewise. * g++.dg/cpp23/auto-fncast1.C: New test. * g++.dg/cpp23/auto-fncast2.C: New test. * g++.dg/cpp23/auto-fncast3.C: New test. * g++.dg/cpp23/auto-fncast4.C: New test. * g++.dg/cpp23/auto-fncast5.C: New test. * g++.dg/cpp23/auto-fncast6.C: New test. Diff: --- gcc/cp/semantics.c | 14 ++++++ gcc/cp/typeck2.c | 26 +++++++---- gcc/testsuite/g++.dg/cpp0x/auto25.C | 4 +- gcc/testsuite/g++.dg/cpp0x/auto9.C | 2 +- gcc/testsuite/g++.dg/cpp23/auto-fncast1.C | 14 ++++++ gcc/testsuite/g++.dg/cpp23/auto-fncast2.C | 62 +++++++++++++++++++++++++ gcc/testsuite/g++.dg/cpp23/auto-fncast3.C | 21 +++++++++ gcc/testsuite/g++.dg/cpp23/auto-fncast4.C | 26 +++++++++++ gcc/testsuite/g++.dg/cpp23/auto-fncast5.C | 39 ++++++++++++++++ gcc/testsuite/g++.dg/cpp23/auto-fncast6.C | 14 ++++++ gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-2.C | 3 +- gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-3.C | 3 +- 12 files changed, 215 insertions(+), 13 deletions(-) diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 8f79f047c01..d962b290211 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -3134,6 +3134,20 @@ finish_compound_literal (tree type, tree compound_literal, if (type == error_mark_node) return error_mark_node; } + /* C++23 auto{x}. */ + else if (is_auto (type) + && !AUTO_IS_DECLTYPE (type) + && CONSTRUCTOR_NELTS (compound_literal) == 1) + { + if (cxx_dialect < cxx23) + pedwarn (input_location, OPT_Wc__23_extensions, + "% only available with " + "%<-std=c++2b%> or %<-std=gnu++2b%>"); + type = do_auto_deduction (type, compound_literal, type, complain, + adc_variable_type); + if (type == error_mark_node) + return error_mark_node; + } /* Used to hold a copy of the compound literal in a template. */ tree orig_cl = NULL_TREE; diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index e98fbf7f5fa..3fb651a02ba 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -2201,19 +2201,29 @@ build_functional_cast_1 (location_t loc, tree exp, tree parms, if (tree anode = type_uses_auto (type)) { - if (!CLASS_PLACEHOLDER_TEMPLATE (anode)) + tree init; + if (CLASS_PLACEHOLDER_TEMPLATE (anode)) + init = parms; + /* C++23 auto(x). */ + else if (!AUTO_IS_DECLTYPE (anode) + && list_length (parms) == 1) { - if (complain & tf_error) - error_at (loc, "invalid use of %qT", anode); - return error_mark_node; + init = TREE_VALUE (parms); + if (cxx_dialect < cxx23) + pedwarn (loc, OPT_Wc__23_extensions, + "% only available with " + "%<-std=c++2b%> or %<-std=gnu++2b%>"); } else { - type = do_auto_deduction (type, parms, anode, complain, - adc_variable_type); - if (type == error_mark_node) - return error_mark_node; + if (complain & tf_error) + error_at (loc, "invalid use of %qT", anode); + return error_mark_node; } + type = do_auto_deduction (type, init, anode, complain, + adc_variable_type); + if (type == error_mark_node) + return error_mark_node; } if (processing_template_decl) diff --git a/gcc/testsuite/g++.dg/cpp0x/auto25.C b/gcc/testsuite/g++.dg/cpp0x/auto25.C index 19d51bc8590..3af089958fb 100644 --- a/gcc/testsuite/g++.dg/cpp0x/auto25.C +++ b/gcc/testsuite/g++.dg/cpp0x/auto25.C @@ -3,10 +3,10 @@ template struct A { - int a[auto(1)]; // { dg-error "9:invalid use of" } + int a[auto(1)]; // { dg-error "9:only available" "" { target c++20_down } } }; template void foo() { - int a[auto(1)]; // { dg-error "9:invalid use of" } + int a[auto(1)]; // { dg-error "9:only available" "" { target c++20_down } } } diff --git a/gcc/testsuite/g++.dg/cpp0x/auto9.C b/gcc/testsuite/g++.dg/cpp0x/auto9.C index 0e80c30ef74..a3a6caf0a66 100644 --- a/gcc/testsuite/g++.dg/cpp0x/auto9.C +++ b/gcc/testsuite/g++.dg/cpp0x/auto9.C @@ -45,7 +45,7 @@ foo () C c; dynamic_cast (c); // { dg-error "auto" } reinterpret_cast (c); // { dg-error "auto" } - int i = auto (0); // { dg-error "auto" } + int i = auto (0); // { dg-error "auto" "" { target c++20_down } } auto p1 = new (auto); // { dg-error "auto" } auto p2 = new (auto) (42); // { dg-error "invalid use of|deduce" } offsetof (auto, fld); // { dg-error "auto" } diff --git a/gcc/testsuite/g++.dg/cpp23/auto-fncast1.C b/gcc/testsuite/g++.dg/cpp23/auto-fncast1.C new file mode 100644 index 00000000000..25e53c4d61e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/auto-fncast1.C @@ -0,0 +1,14 @@ +// PR c++/103049 +// P0849R8 - auto(x) +// { dg-do compile { target c++23 } } +// Testcase from P0849R8. + +struct A {}; +void f(A&) = delete; // #1 +void f(A&&); // #2 +A& g(); +void h() { +// f(g()); // calls #1 + f(A(g())); // calls #2 with a temporary object + f(auto(g())); // calls #2 with a temporary object +} diff --git a/gcc/testsuite/g++.dg/cpp23/auto-fncast2.C b/gcc/testsuite/g++.dg/cpp23/auto-fncast2.C new file mode 100644 index 00000000000..327a4480030 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/auto-fncast2.C @@ -0,0 +1,62 @@ +// PR c++/103049 +// P0849R8 - auto(x) +// { dg-do compile { target c++23 } } + +struct X { }; +X& fn (); +X&& fnr (); + +void h() +{ + double v[] = { 1.2, 3.4 }; + +auto(v); + +auto{v}; + static_assert (__is_same_as (decltype (auto(v)), double *)); + static_assert (__is_same_as (decltype (auto{v}), double *)); + auto a1 = fn (); + static_assert (__is_same_as (decltype (auto(fn())), decltype (a1))); + static_assert (__is_same_as (decltype (auto{fn()}), decltype (a1))); + auto a2 = fnr (); + static_assert (__is_same_as (decltype (auto(fnr())), decltype (a2))); + static_assert (__is_same_as (decltype (auto{fnr()}), decltype (a2))); + +auto(1); + new auto(1); + +auto{1}; + new auto{1}; +} + +template +void baz (T t, const T &tr, T &&trr) +{ + +auto(t); + +auto{t}; + +auto(tr); + +auto{tr}; + +auto(trr); + +auto{trr}; + static_assert (__is_same_as (decltype (auto(t)), T)); + static_assert (__is_same_as (decltype (auto{t}), T)); + static_assert (__is_same_as (decltype (auto(tr)), T)); + static_assert (__is_same_as (decltype (auto{tr}), T)); + static_assert (__is_same_as (decltype (auto(trr)), T)); + static_assert (__is_same_as (decltype (auto{trr}), T)); +} + +template +void foo () +{ +} + +template +void bar () +{ +} + +void +g() +{ + foo<>(); + bar<>(); + int i = 42; + baz (1, i, 42); +} diff --git a/gcc/testsuite/g++.dg/cpp23/auto-fncast3.C b/gcc/testsuite/g++.dg/cpp23/auto-fncast3.C new file mode 100644 index 00000000000..1204458c931 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/auto-fncast3.C @@ -0,0 +1,21 @@ +// PR c++/103049 +// P0849R8 - auto(x) +// { dg-do compile { target c++23 } } +// Test invalid use. + +void +f () +{ + char x[] = "foo"; + +decltype(auto){x}; // { dg-error "invalid use of .decltype\\(auto\\)." } + +decltype(auto)(x); // { dg-error "invalid use of .decltype\\(auto\\)." } + + +auto(); // { dg-error "invalid use of .auto." } + new auto(); // { dg-error "requires exactly one element" } + +auto{}; // { dg-error "invalid use of .auto." } + new auto{}; // { dg-error "requires exactly one element" } + +auto(1, 2); // { dg-error "invalid use of .auto." } + new auto(1, 2); // { dg-error "requires exactly one element" } + +auto{1, 2}; // { dg-error "too many initializers" } + new auto{1, 2}; // { dg-error "requires exactly one element" } +} diff --git a/gcc/testsuite/g++.dg/cpp23/auto-fncast4.C b/gcc/testsuite/g++.dg/cpp23/auto-fncast4.C new file mode 100644 index 00000000000..0e26bf2bc66 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/auto-fncast4.C @@ -0,0 +1,26 @@ +// PR c++/103049 +// P0849R8 - auto(x) +// { dg-do compile { target c++23 } } + +class cmdline_parser +{ + public: + cmdline_parser(char const*); + + auto add_option(char const*, char const*) & -> cmdline_parser &; + auto add_option(char const*, char const*) && -> cmdline_parser &&; + + void parse(int, char**); +}; + +int main(int argc, char *argv[]) +{ + auto cmdline = cmdline_parser("driver"); + + cmdline.add_option("-h", "show help messages") + .add_option("-v", "show version"); + + auto internal = auto(cmdline).add_option("--logging-level", "set logging level to 1-3") + .add_option("--dump-full", "do not minimize dump"); + internal.parse(argc, argv); +} diff --git a/gcc/testsuite/g++.dg/cpp23/auto-fncast5.C b/gcc/testsuite/g++.dg/cpp23/auto-fncast5.C new file mode 100644 index 00000000000..b29901ffea4 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/auto-fncast5.C @@ -0,0 +1,39 @@ +// PR c++/103049 +// P0849R8 - auto(x) +// { dg-do compile { target c++23 } } + +struct X { + X() = default; + X(const X&) = delete; +}; + +void +g () +{ + X x; + +X(x); // { dg-error "use of deleted function" } + +auto(x); // { dg-error "use of deleted function" } +} + +class A; +void f(A); + +class A { + int x; + +public: + A(); + + auto run() { + f(A(*this)); + f(auto(*this)); + } + +protected: + A(const A&); +}; + +void z () { + A a; + a.run (); +} diff --git a/gcc/testsuite/g++.dg/cpp23/auto-fncast6.C b/gcc/testsuite/g++.dg/cpp23/auto-fncast6.C new file mode 100644 index 00000000000..6b7858d9de5 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/auto-fncast6.C @@ -0,0 +1,14 @@ +// PR c++/103049 +// P0849R8 - auto(x) +// { dg-do compile { target c++20 } } + +void f (int); + +void +g () +{ + auto a1 = auto(f); // { dg-error "only available with" "" { target c++20_only } } + auto a2 = auto{f}; // { dg-error "only available with" "" { target c++20_only } } + static_assert (__is_same_as (decltype (a1), void(*)(int))); + static_assert (__is_same_as (decltype (a2), void(*)(int))); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-2.C index 290aaf83819..025bbf3bb93 100644 --- a/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-2.C +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-2.C @@ -6,7 +6,8 @@ void foo1(T& t) { typename T::template C tcv = t; typename T::template C u = tcv; // { dg-error "not permitted" "" { target c++20 } } T::template C::f (tcv, u); // { dg-error "incomplete|not permitted" } - (typename T::template D (t)); // { dg-error "invalid|not permitted" } + (typename T::template D (t)); // { dg-error "invalid|not permitted|unable" } +// { dg-warning "only available" "" { target c++17_down } .-1 } } struct T1 { diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-3.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-3.C index d612327b9ae..80a388462eb 100644 --- a/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-3.C +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-3.C @@ -10,7 +10,8 @@ void foo1(T& t) { typename T::template C tcv = t; typename T::template C u = tcv; // { dg-error "not permitted" "" { target c++20 } } T::template C::f (tcv, u); // { dg-error "incomplete|not permitted" } - (typename T::template D (t)); // { dg-error "invalid|not permitted" } + (typename T::template D (t)); // { dg-error "invalid|not permitted|no class" } +// { dg-warning "only available" "" { target c++17_down } .-1 } } struct T1 {