c++: Improve checking of decls with trailing return type [PR95820]
authorMarek Polacek <polacek@redhat.com>
Wed, 24 Jun 2020 21:39:21 +0000 (17:39 -0400)
committerMarek Polacek <polacek@redhat.com>
Tue, 14 Jul 2020 13:35:53 +0000 (09:35 -0400)
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;

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
gcc/testsuite/g++.dg/cpp1y/auto-fn58.C [new file with mode: 0644]

index 5a262436cd39a96ce625b2d2c0aba0eb74358bc7..6e4d546d55e7b0ce5e56e138a66361a7c8342a11 100644 (file)
@@ -12105,106 +12105,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 (file)
index 0000000..8c4f24c
--- /dev/null
@@ -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" }