[PATCH] c++: Implement C++23 P0849R8 - auto(x) [PR103049]
Jason Merrill
jason@redhat.com
Thu Nov 18 22:36:45 GMT 2021
On 11/4/21 16:26, Marek Polacek wrote:
> 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.
>
> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
OK.
> 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/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.
> ---
> gcc/cp/semantics.c | 14 +++++
> gcc/cp/typeck2.c | 26 +++++---
> gcc/testsuite/g++.dg/cpp0x/auto25.C | 4 +-
> 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 +++++
> .../g++.dg/cpp2a/concepts-pr84979-2.C | 3 +-
> .../g++.dg/cpp2a/concepts-pr84979-3.C | 3 +-
> 11 files changed, 214 insertions(+), 12 deletions(-)
> create mode 100644 gcc/testsuite/g++.dg/cpp23/auto-fncast1.C
> create mode 100644 gcc/testsuite/g++.dg/cpp23/auto-fncast2.C
> create mode 100644 gcc/testsuite/g++.dg/cpp23/auto-fncast3.C
> create mode 100644 gcc/testsuite/g++.dg/cpp23/auto-fncast4.C
> create mode 100644 gcc/testsuite/g++.dg/cpp23/auto-fncast5.C
> create mode 100644 gcc/testsuite/g++.dg/cpp23/auto-fncast6.C
>
> diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
> index 2443d032749..21b48d6abad 100644
> --- a/gcc/cp/semantics.c
> +++ b/gcc/cp/semantics.c
> @@ -3143,6 +3143,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,
> + "%<auto{x}%> 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 c01f2f8ced4..f2c980ad7a9 100644
> --- a/gcc/cp/typeck2.c
> +++ b/gcc/cp/typeck2.c
> @@ -2192,19 +2192,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,
> + "%<auto(x)%> 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<int> 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<int> 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/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<typename T>
> +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<typename = decltype(auto(1))>
> +void foo ()
> +{
> +}
> +
> +template<int = auto(1)>
> +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<void> tcv = t;
> typename T::template C<auto> u = tcv; // { dg-error "not permitted" "" { target c++20 } }
> T::template C<auto>::f (tcv, u); // { dg-error "incomplete|not permitted" }
> - (typename T::template D<auto> (t)); // { dg-error "invalid|not permitted" }
> + (typename T::template D<auto> (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<void> tcv = t;
> typename T::template C<auto> u = tcv; // { dg-error "not permitted" "" { target c++20 } }
> T::template C<auto>::f (tcv, u); // { dg-error "incomplete|not permitted" }
> - (typename T::template D<auto> (t)); // { dg-error "invalid|not permitted" }
> + (typename T::template D<auto> (t)); // { dg-error "invalid|not permitted|no class" }
> +// { dg-warning "only available" "" { target c++17_down } .-1 }
> }
>
> struct T1 {
>
> base-commit: 1b4a63593bc6b9770789816b205039fdf3cfd3fc
>
More information about the Gcc-patches
mailing list