Ping.
On Wed, Jun 24, 2020 at 07:27:14PM -0400, Marek Polacek via Gcc-patches wrote:
> This is an ICE-on-invalid but I've been seeing it when reducing
> various testcases, so it's more important for me than usually.
>
> splice_late_return_type now checks that if we've seen a late return
> type, the function return type was auto. That's a fair assumption
> but grokdeclarator/cdk_function wasn't giving errors for function
> pointers and similar. So we want to perform various checks not only
> when funcdecl_p || inner_declarator == NULL. But only give the
> !late_return_type errors when funcdecl_p, to accept e.g.
>
> auto (*fp)() = f;
>
> in C++11. Here's a diff -w to ease the review:
>
> --- a/gcc/cp/decl.c
> +++ b/gcc/cp/decl.c
> @@ -12102,14 +12102,9 @@ grokdeclarator (const cp_declarator *declarator,
>
> /* Handle a late-specified return type. */
> tree late_return_type = declarator->u.function.late_return_type;
> - if (funcdecl_p
> - /* This is the case e.g. for
> - using T = auto () -> int. */
> - || inner_declarator == NULL)
> - {
> if (tree auto_node = type_uses_auto (type))
> {
> - if (!late_return_type)
> + if (!late_return_type && funcdecl_p)
> {
> if (current_class_type
> && LAMBDA_TYPE_P (current_class_type))
> @@ -12201,7 +12196,6 @@ grokdeclarator (const cp_declarator *declarator,
> "type specifier", name);
> return error_mark_node;
> }
> - }
> type = splice_late_return_type (type, late_return_type);
> if (type == error_mark_node)
> return error_mark_node;
>
> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
>
> gcc/cp/ChangeLog:
>
> PR c++/95820
> * decl.c (grokdeclarator) <case cdk_function>: Check also
> pointers/references/... to functions.
>
> gcc/testsuite/ChangeLog:
>
> PR c++/95820
> * g++.dg/cpp1y/auto-fn58.C: New test.
> ---
> gcc/cp/decl.c | 166 ++++++++++++-------------
> gcc/testsuite/g++.dg/cpp1y/auto-fn58.C | 13 ++
> 2 files changed, 93 insertions(+), 86 deletions(-)
> create mode 100644 gcc/testsuite/g++.dg/cpp1y/auto-fn58.C
>
> diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
> index 3afad5ca805..a9ec328c498 100644
> --- a/gcc/cp/decl.c
> +++ b/gcc/cp/decl.c
> @@ -12102,106 +12102,100 @@ grokdeclarator (const cp_declarator *declarator,
>
> /* Handle a late-specified return type. */
> tree late_return_type = declarator->u.function.late_return_type;
> - if (funcdecl_p
> - /* This is the case e.g. for
> - using T = auto () -> int. */
> - || inner_declarator == NULL)
> + if (tree auto_node = type_uses_auto (type))
> {
> - if (tree auto_node = type_uses_auto (type))
> + if (!late_return_type && funcdecl_p)
> {
> - if (!late_return_type)
> + if (current_class_type
> + && LAMBDA_TYPE_P (current_class_type))
> + /* OK for C++11 lambdas. */;
> + else if (cxx_dialect < cxx14)
> {
> - if (current_class_type
> - && LAMBDA_TYPE_P (current_class_type))
> - /* OK for C++11 lambdas. */;
> - else if (cxx_dialect < cxx14)
> - {
> - error_at (typespec_loc, "%qs function uses "
> - "%<auto%> type specifier without "
> - "trailing return type", name);
> - inform (typespec_loc,
> - "deduced return type only available "
> - "with %<-std=c++14%> or %<-std=gnu++14%>");
> - }
> - else if (virtualp)
> - {
> - error_at (typespec_loc, "virtual function "
> - "cannot have deduced return type");
> - virtualp = false;
> - }
> + error_at (typespec_loc, "%qs function uses "
> + "%<auto%> type specifier without "
> + "trailing return type", name);
> + inform (typespec_loc,
> + "deduced return type only available "
> + "with %<-std=c++14%> or %<-std=gnu++14%>");
> }
> - else if (!is_auto (type) && sfk != sfk_conversion)
> + else if (virtualp)
> {
> - error_at (typespec_loc, "%qs function with trailing "
> - "return type has %qT as its type rather "
> - "than plain %<auto%>", name, type);
> - return error_mark_node;
> + error_at (typespec_loc, "virtual function "
> + "cannot have deduced return type");
> + virtualp = false;
> }
> - else if (is_auto (type) && AUTO_IS_DECLTYPE (type))
> + }
> + else if (!is_auto (type) && sfk != sfk_conversion)
> + {
> + error_at (typespec_loc, "%qs function with trailing "
> + "return type has %qT as its type rather "
> + "than plain %<auto%>", name, type);
> + return error_mark_node;
> + }
> + else if (is_auto (type) && AUTO_IS_DECLTYPE (type))
> + {
> + if (funcdecl_p)
> + error_at (typespec_loc,
> + "%qs function with trailing return type "
> + "has %<decltype(auto)%> as its type "
> + "rather than plain %<auto%>", name);
> + else
> + error_at (typespec_loc,
> + "invalid use of %<decltype(auto)%>");
> + return error_mark_node;
> + }
> + tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node);
> + if (!tmpl)
> + if (tree late_auto = type_uses_auto (late_return_type))
> + tmpl = CLASS_PLACEHOLDER_TEMPLATE (late_auto);
> + if (tmpl && funcdecl_p)
> + {
> + if (!dguide_name_p (unqualified_id))
> {
> - if (funcdecl_p)
> - error_at (typespec_loc,
> - "%qs function with trailing return type "
> - "has %<decltype(auto)%> as its type "
> - "rather than plain %<auto%>", name);
> - else
> - error_at (typespec_loc,
> - "invalid use of %<decltype(auto)%>");
> + error_at (declarator->id_loc, "deduced class "
> + "type %qD in function return type",
> + DECL_NAME (tmpl));
> + inform (DECL_SOURCE_LOCATION (tmpl),
> + "%qD declared here", tmpl);
> return error_mark_node;
> }
> - tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node);
> - if (!tmpl)
> - if (tree late_auto = type_uses_auto (late_return_type))
> - tmpl = CLASS_PLACEHOLDER_TEMPLATE (late_auto);
> - if (tmpl && funcdecl_p)
> + else if (!late_return_type)
> {
> - if (!dguide_name_p (unqualified_id))
> - {
> - error_at (declarator->id_loc, "deduced class "
> - "type %qD in function return type",
> - DECL_NAME (tmpl));
> - inform (DECL_SOURCE_LOCATION (tmpl),
> - "%qD declared here", tmpl);
> - return error_mark_node;
> - }
> - else if (!late_return_type)
> - {
> - error_at (declarator->id_loc, "deduction guide "
> - "for %qT must have trailing return "
> - "type", TREE_TYPE (tmpl));
> - inform (DECL_SOURCE_LOCATION (tmpl),
> - "%qD declared here", tmpl);
> - return error_mark_node;
> - }
> - else if (CLASS_TYPE_P (late_return_type)
> - && CLASSTYPE_TEMPLATE_INFO (late_return_type)
> - && (CLASSTYPE_TI_TEMPLATE (late_return_type)
> - == tmpl))
> - /* OK */;
> - else
> - error ("trailing return type %qT of deduction guide "
> - "is not a specialization of %qT",
> - late_return_type, TREE_TYPE (tmpl));
> + error_at (declarator->id_loc, "deduction guide "
> + "for %qT must have trailing return "
> + "type", TREE_TYPE (tmpl));
> + inform (DECL_SOURCE_LOCATION (tmpl),
> + "%qD declared here", tmpl);
> + return error_mark_node;
> }
> - }
> - else if (late_return_type
> - && sfk != sfk_conversion)
> - {
> - if (late_return_type == error_mark_node)
> - return error_mark_node;
> - if (cxx_dialect < cxx11)
> - /* Not using maybe_warn_cpp0x because this should
> - always be an error. */
> - error_at (typespec_loc,
> - "trailing return type only available "
> - "with %<-std=c++11%> or %<-std=gnu++11%>");
> + else if (CLASS_TYPE_P (late_return_type)
> + && CLASSTYPE_TEMPLATE_INFO (late_return_type)
> + && (CLASSTYPE_TI_TEMPLATE (late_return_type)
> + == tmpl))
> + /* OK */;
> else
> - error_at (typespec_loc, "%qs function with trailing "
> - "return type not declared with %<auto%> "
> - "type specifier", name);
> - return error_mark_node;
> + error ("trailing return type %qT of deduction guide "
> + "is not a specialization of %qT",
> + late_return_type, TREE_TYPE (tmpl));
> }
> }
> + else if (late_return_type
> + && sfk != sfk_conversion)
> + {
> + if (late_return_type == error_mark_node)
> + return error_mark_node;
> + if (cxx_dialect < cxx11)
> + /* Not using maybe_warn_cpp0x because this should
> + always be an error. */
> + error_at (typespec_loc,
> + "trailing return type only available "
> + "with %<-std=c++11%> or %<-std=gnu++11%>");
> + else
> + error_at (typespec_loc, "%qs function with trailing "
> + "return type not declared with %<auto%> "
> + "type specifier", name);
> + return error_mark_node;
> + }
> type = splice_late_return_type (type, late_return_type);
> if (type == error_mark_node)
> return error_mark_node;
> diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn58.C
> b/gcc/testsuite/g++.dg/cpp1y/auto-fn58.C
> new file mode 100644
> index 00000000000..8c4f24ccc74
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn58.C
> @@ -0,0 +1,13 @@
> +// PR c++/95820
> +// { dg-do compile { target c++14 } }
> +
> +auto (*a)() -> bool = nullptr;
> +int (*b)() -> bool = nullptr; // { dg-error "function with trailing return
> type" }
> +int (**c)() -> bool = nullptr; // { dg-error "function with trailing return
> type" }
> +int (&d)() -> bool = nullptr; // { dg-error "function with trailing return
> type" }
> +int (*&e)() -> bool = nullptr; // { dg-error "function with trailing return
> type" }
> +int (f[])() -> bool = nullptr; // { dg-error "function with trailing return
> type" }
> +auto* (*g)() -> bool = nullptr; // { dg-error "function with trailing return
> type" }
> +decltype(auto) (*h)() -> bool = nullptr; // { dg-error "invalid use" }
> +decltype(auto)* (*i)() -> bool = nullptr; // { dg-error "function with
> trailing return type" }
> +decltype(auto)& (*j)() -> bool = nullptr; // { dg-error "function with
> trailing return type" }
>
> base-commit: ef6506e23691a72e1e724977e8ee8b9f3db74015
> --
> Marek Polacek • Red Hat, Inc. • 300 A St, Boston, MA
>
Marek