diff options
author | Marek Polacek <polacek@redhat.com> | 2021-11-03 11:04:22 -0400 |
---|---|---|
committer | Marek Polacek <polacek@redhat.com> | 2021-11-18 18:00:08 -0500 |
commit | 93810fd673654db9ff16170624a6d36449eab241 (patch) | |
tree | f31a7d9ee315aff919b2dd0a393c981dae0e4b54 /gcc | |
parent | 6f4ac4f81f89caac7e74127ed2e6db6bbb3d7426 (diff) | |
download | gcc-93810fd673654db9ff16170624a6d36449eab241.zip gcc-93810fd673654db9ff16170624a6d36449eab241.tar.gz gcc-93810fd673654db9ff16170624a6d36449eab241.tar.bz2 |
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.
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/semantics.c | 14 | ||||
-rw-r--r-- | gcc/cp/typeck2.c | 26 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/auto25.C | 4 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/auto9.C | 2 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp23/auto-fncast1.C | 14 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp23/auto-fncast2.C | 62 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp23/auto-fncast3.C | 21 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp23/auto-fncast4.C | 26 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp23/auto-fncast5.C | 39 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp23/auto-fncast6.C | 14 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-2.C | 3 | ||||
-rw-r--r-- | 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 8f79f04..d962b29 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, + "%<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 e98fbf7..3fb651a 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, + "%<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 19d51bc..3af0899 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/cpp0x/auto9.C b/gcc/testsuite/g++.dg/cpp0x/auto9.C index 0e80c30..a3a6caf 100644 --- a/gcc/testsuite/g++.dg/cpp0x/auto9.C +++ b/gcc/testsuite/g++.dg/cpp0x/auto9.C @@ -45,7 +45,7 @@ foo () C<int> c; dynamic_cast<auto> (c); // { dg-error "auto" } reinterpret_cast<auto> (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 0000000..25e53c4 --- /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 0000000..327a448 --- /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 0000000..1204458 --- /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 0000000..0e26bf2 --- /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 0000000..b29901f --- /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 0000000..6b7858d --- /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 290aaf8..025bbf3 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 d612327..80a3884 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 { |