diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 6f273bfe21f..de464afdb54 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -16432,6 +16432,16 @@ cp_parser_decltype (cp_parser *parser) = parser->greater_than_is_operator_p; parser->greater_than_is_operator_p = true; + /* Don't synthesize an implicit template type parameter here. This + could happen with C++23 code like + + void f(decltype(new auto{0})); + + where we want to deduce the auto right away so that the parameter + is of type 'int *'. */ + auto cleanup = make_temp_override + (parser->auto_is_implicit_function_template_parm_p, false); + /* Do not actually evaluate the expression. */ ++cp_unevaluated_operand; @@ -24144,22 +24154,22 @@ cp_parser_type_id_1 (cp_parser *parser, cp_parser_flags flags, /* OK */; else { - location_t loc = type_specifier_seq.locations[ds_type_spec]; - if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node)) + if (!cp_parser_simulate_error (parser)) { - if (!cp_parser_simulate_error (parser)) + location_t loc = type_specifier_seq.locations[ds_type_spec]; + if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node)) { error_at (loc, "missing template arguments after %qT", auto_node); inform (DECL_SOURCE_LOCATION (tmpl), "%qD declared here", tmpl); } + else if (parser->in_template_argument_list_p) + error_at (loc, "%qT not permitted in template argument", + auto_node); + else + error_at (loc, "invalid use of %qT", auto_node); } - else if (parser->in_template_argument_list_p) - error_at (loc, "%qT not permitted in template argument", - auto_node); - else - error_at (loc, "invalid use of %qT", auto_node); return error_mark_node; } } @@ -24668,6 +24678,15 @@ cp_parser_parameter_declaration (cp_parser *parser, &decl_specifiers, &declares_class_or_enum); + /* [dcl.spec.auto.general]: "A placeholder-type-specifier of the form + type-constraint opt auto can be used as a decl-specifier of the + decl-specifier-seq of a parameter-declaration of a function declaration + or lambda-expression..." but we must not synthesize an implicit template + type parameter in its declarator. That is, in "void f(auto[auto{10}]);" + we want to synthesize only the first auto. */ + auto cleanup = make_temp_override + (parser->auto_is_implicit_function_template_parm_p, false); + /* Complain about missing 'typename' or other invalid type names. */ if (!decl_specifiers.any_type_specifiers_p && cp_parser_parse_and_diagnose_invalid_type_name (parser)) @@ -32369,6 +32388,9 @@ cp_parser_sizeof_operand (cp_parser* parser, enum rid keyword) = parser->non_integral_constant_expression_p; parser->integral_constant_expression_p = false; + auto cleanup = make_temp_override + (parser->auto_is_implicit_function_template_parm_p, false); + /* Do not actually evaluate the expression. */ ++cp_unevaluated_operand; ++c_inhibit_evaluation_warnings; diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-85713-2.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-85713-2.C index 8fb8dfdeaf0..dbc9e8c732c 100644 --- a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-85713-2.C +++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-85713-2.C @@ -2,6 +2,6 @@ // { dg-do compile { target c++14 } } auto l4 = [](auto v, auto (&array (int)) [5]) -> int { return v + array[0]; }; -auto l5 = [](auto v, auto (&array (auto)) [5]) -> int { return v + array[0]; }; +auto l5 = [](auto v, auto (&array (auto)) [5]) -> int { return v + array[0]; }; // { dg-error ".auto. parameter not permitted in this context" } auto l6 = [](auto v, auto (&array (int int)) [5]) -> int { return v + array[0]; }; // { dg-error "two or more data types" } auto l7 = [](auto v, auto (&array (int auto)) [5]) -> int { return v + array[0]; }; // { dg-error "two or more data types" } diff --git a/gcc/testsuite/g++.dg/cpp1y/pr60054.C b/gcc/testsuite/g++.dg/cpp1y/pr60054.C index f51120f6425..0d4925afbf2 100644 --- a/gcc/testsuite/g++.dg/cpp1y/pr60054.C +++ b/gcc/testsuite/g++.dg/cpp1y/pr60054.C @@ -6,6 +6,6 @@ template decltype(T{}) fooB(T); void bar() { - fooA((auto*)0); // { dg-error "invalid use" } - fooB((auto*)0); // { dg-error "invalid use" } + fooA((auto*)0); // { dg-error "expected" } + fooB((auto*)0); // { dg-error "expected" } } diff --git a/gcc/testsuite/g++.dg/cpp1y/pr60332.C b/gcc/testsuite/g++.dg/cpp1y/pr60332.C index e75ab8584e3..f3a7980b380 100644 --- a/gcc/testsuite/g++.dg/cpp1y/pr60332.C +++ b/gcc/testsuite/g++.dg/cpp1y/pr60332.C @@ -3,4 +3,5 @@ void foo(); -auto f = (auto(*)())(&foo); // { dg-error "invalid" } +auto f = (auto(*)())(&foo); // { dg-error "expected" } +// { dg-error "only available" "" { target c++20_down } .-1 } diff --git a/gcc/testsuite/g++.dg/cpp23/auto-fncast7.C b/gcc/testsuite/g++.dg/cpp23/auto-fncast7.C new file mode 100644 index 00000000000..763164f3e5b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/auto-fncast7.C @@ -0,0 +1,9 @@ +// PR c++/103401 +// { dg-do compile { target c++23 } } + +void f(decltype(auto(0))) { } + +int main() +{ + f(0); // { dg-error "no matching function" } +} diff --git a/gcc/testsuite/g++.dg/cpp23/auto-fncast8.C b/gcc/testsuite/g++.dg/cpp23/auto-fncast8.C new file mode 100644 index 00000000000..9fb7b9c2516 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/auto-fncast8.C @@ -0,0 +1,42 @@ +// PR c++/103401 +// { dg-do compile { target c++23 } } + +void f1 (decltype(auto(0))); +void f2 (decltype(auto{0})); +void f3 (int = auto(42)); +void f4 (int = auto{42}); +void f5 (decltype(auto(0)) = auto(42)); +void f6 (auto (x)); +void f7 (int[auto(10)]); +void f8 (int[auto{10}]); +void f9 (auto[auto{10}]); +void f10 (auto); +void f11 (int x, decltype(x) y); +void f12 (int[sizeof(auto{10})]); +void f13 (int[sizeof(auto(10))]); +void f14 (int[__extension__ alignof(auto{10})]); +void f15 (int[__extension__ alignof(auto(10))]); + +void +g () +{ + int a[2]; + f1 (1); + f2 (1); + f3 (); + f3 (1); + f4 (); + f4 (1); + f5 (); + f5 (1); + f6 ('a'); + f7 (&a[0]); + f8 (&a[0]); + f9 (&a[0]); + f10 (1); + f11 (1, 2); + f12 (&a[0]); + f13 (&a[0]); + f14 (&a[0]); + f15 (&a[0]); +} diff --git a/gcc/testsuite/g++.dg/cpp23/auto-fncast9.C b/gcc/testsuite/g++.dg/cpp23/auto-fncast9.C new file mode 100644 index 00000000000..12a0dcece75 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/auto-fncast9.C @@ -0,0 +1,17 @@ +// PR c++/103401 +// { dg-do compile { target c++23 } } + +void f1(decltype(new auto{0})); +void f2(decltype(new int{0})); + +void +g () +{ + int i; + void f3(decltype(new auto{0})); + void f4(decltype(new int{0})); + f1 (&i); + f2 (&i); + f3 (&i); + f4 (&i); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-2.C index 025bbf3bb93..75f8e40ca58 100644 --- a/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-2.C +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-2.C @@ -4,9 +4,9 @@ template 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|unable" } + typename T::template C u = tcv; // { dg-error "" "" { target c++20 } } + T::template C::f (tcv, u); // { dg-error "" } + (typename T::template D (t)); // { dg-error "" } // { dg-warning "only available" "" { target c++17_down } .-1 } } @@ -23,9 +23,9 @@ struct T1 { template void foo2(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" } - T::template D (t); // { dg-error "invalid|not permitted" } + typename T::template C u = tcv; // { dg-error "" "" { target c++20 } } + T::template C::f (tcv, u); // { dg-error "" } + T::template D (t); // { dg-error "" } } struct T2 { diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-3.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-3.C index 80a388462eb..1c1a41c0fa2 100644 --- a/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-3.C +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-3.C @@ -8,9 +8,9 @@ template 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|no class" } + typename T::template C u = tcv; // { dg-error "" "" { target c++20 } } + T::template C::f (tcv, u); // { dg-error "" } + (typename T::template D (t)); // { dg-error "" } // { dg-warning "only available" "" { target c++17_down } .-1 } } @@ -27,9 +27,9 @@ struct T1 { template void foo2(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" } - T::template D (t); // { dg-error "yields a type|not permitted" } + typename T::template C u = tcv; // { dg-error "" "" { target c++20 } } + T::template C::f (tcv, u); // { dg-error "" } + T::template D (t); // { dg-error "" } } struct T2 { diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979.C index 81555eb4554..a83601527bb 100644 --- a/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979.C +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979.C @@ -5,5 +5,5 @@ template void foo() {} void bar() { - foo(); // { dg-error "not permitted|invalid|no matching function" } + foo(); // { dg-error "" } }