c++: Implement C++23 P0849R8 - auto(x) [PR103049]
Commit Message
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?
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
base-commit: 1b4a63593bc6b9770789816b205039fdf3cfd3fc
Comments
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
>
On Thu, Nov 18, 2021 at 05:36:45PM -0500, Jason Merrill wrote:
> 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.
Running dg.exp again, I noticed
FAIL: g++.dg/cpp0x/auto9.C -std=c++23 (test for errors, line 48)
which I'd missed before, but that was an obvious fix, so I fixed it
and pushed the patch, thanks!
Marek
@@ -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;
@@ -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)
@@ -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 } }
}
new file mode 100644
@@ -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
+}
new file mode 100644
@@ -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);
+}
new file mode 100644
@@ -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" }
+}
new file mode 100644
@@ -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);
+}
new file mode 100644
@@ -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 ();
+}
new file mode 100644
@@ -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)));
+}
@@ -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 {
@@ -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 {