Hi!

The following patch fixes build of older GCC releases with newer ones.
In GCC 4.6 and earlier, we had:
struct cgraph_node;
struct cgraph_node *cgraph_node (tree);
and that is something on which GCC 9+ code errors on if it sees any
__gcc_diag__ and similar attributes, because cgraph_node it wants to find is
not a type.

As older GCC releases don't have the __gcc_diag__ etc. attributes guarded on
no newer GCC releases, only on minimum GCC version that does support it,
I think we need to make sure we don't reject what older GCCs used to have.

The following patch does that.  In addition, get_pointer_to_named_type
looked misnamed, because we actually aren't interested in getting gimple *
etc. type, but gimple.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk
and eventually 9 too?

2019-11-19  Jakub Jelinek  <ja...@redhat.com>

        PR c/90677
        * c-format.c (get_pointer_to_named_type): Renamed to ...
        (get_named_type): ... this.  If result is FUNCTION_DECL for
        cgraph_node, return cgraph_node from pointee of return type if
        possible instead of emitting an error.
        (init_dynamic_diag_info): Adjust get_pointer_to_named_type callers
        to call get_named_type instead.  Formatting fixes.

        * c-c++-common/pr90677.c: New test.

--- gcc/c-family/c-format.c.jj  2019-10-05 09:35:12.917997709 +0200
+++ gcc/c-family/c-format.c     2019-11-19 13:05:10.113308578 +0100
@@ -4899,21 +4899,39 @@ init_dynamic_gfc_info (void)
     }
 }
 
-/* Lookup the type named NAME and return a pointer-to-NAME type if found.
-   Otherwise, return void_type_node if NAME has not been used yet, or 
NULL_TREE if
-   NAME is not a type (issuing an error).  */
+/* Lookup the type named NAME and return a NAME type if found.
+   Otherwise, return void_type_node if NAME has not been used yet,
+   or NULL_TREE if NAME is not a type (issuing an error).  */
 
 static tree
-get_pointer_to_named_type (const char *name)
+get_named_type (const char *name)
 {
   tree result;
-  if ((result = maybe_get_identifier (name)))
+  if (tree id = maybe_get_identifier (name))
     {
-      result = identifier_global_value (result);
+      result = identifier_global_value (id);
       if (result)
        {
          if (TREE_CODE (result) != TYPE_DECL)
            {
+             if (TREE_CODE (result) == FUNCTION_DECL
+                 && !strcmp (name, "cgraph_node")
+                 && TREE_CODE (TREE_TYPE (result)) == FUNCTION_TYPE)
+               {
+                 /* Before GCC 4.7, there used to be
+                    struct cgraph_node;
+                    struct cgraph_node *cgraph_node (tree);
+                    Don't error in this case, so that GCC 9+ can still
+                    compile GCC 4.6 and earlier.  */
+                 tree res = TREE_TYPE (TREE_TYPE (result));
+                 if (TREE_CODE (res) == POINTER_TYPE
+                     && (TYPE_NAME (TREE_TYPE (res)) == id
+                         || (TREE_CODE (TYPE_NAME (TREE_TYPE (res)))
+                             == TYPE_DECL
+                             && (DECL_NAME (TYPE_NAME (TREE_TYPE (res)))
+                                 == id))))
+                   return TREE_TYPE (res);
+               }
              error ("%qs is not defined as a type", name);
              result = NULL_TREE;
            }
@@ -4953,23 +4971,24 @@ init_dynamic_diag_info (void)
         an extra type level.  */
       if ((local_tree_type_node = maybe_get_identifier ("tree")))
        {
-         local_tree_type_node = identifier_global_value (local_tree_type_node);
+         local_tree_type_node
+           = identifier_global_value (local_tree_type_node);
          if (local_tree_type_node)
            {
              if (TREE_CODE (local_tree_type_node) != TYPE_DECL)
                {
                  error ("%<tree%> is not defined as a type");
-                 local_tree_type_node = 0;
+                 local_tree_type_node = NULL_TREE;
                }
              else if (TREE_CODE (TREE_TYPE (local_tree_type_node))
                       != POINTER_TYPE)
                {
                  error ("%<tree%> is not defined as a pointer type");
-                 local_tree_type_node = 0;
+                 local_tree_type_node = NULL_TREE;
                }
              else
-               local_tree_type_node =
-                 TREE_TYPE (TREE_TYPE (local_tree_type_node));
+               local_tree_type_node
+                 = TREE_TYPE (TREE_TYPE (local_tree_type_node));
            }
        }
       else
@@ -4979,12 +4998,12 @@ init_dynamic_diag_info (void)
   /* Similar to the above but for gimple*.  */
   if (!local_gimple_ptr_node
       || local_gimple_ptr_node == void_type_node)
-    local_gimple_ptr_node = get_pointer_to_named_type ("gimple");
+    local_gimple_ptr_node = get_named_type ("gimple");
 
   /* Similar to the above but for cgraph_node*.  */
   if (!local_cgraph_node_ptr_node
       || local_cgraph_node_ptr_node == void_type_node)
-    local_cgraph_node_ptr_node = get_pointer_to_named_type ("cgraph_node");
+    local_cgraph_node_ptr_node = get_named_type ("cgraph_node");
 
   static tree hwi;
 
--- gcc/testsuite/c-c++-common/pr90677.c.jj     2019-11-19 13:02:45.709465310 
+0100
+++ gcc/testsuite/c-c++-common/pr90677.c        2019-11-19 13:03:58.925371802 
+0100
@@ -0,0 +1,11 @@
+/* PR c/90677 */
+/* { dg-do compile } */
+/* { dg-options "-W -Wall" } */
+
+struct cgraph_node;
+union tree_node;
+typedef union tree_node *tree;
+union gimple_statement_d;
+typedef union gimple_statement_d *gimple;
+struct cgraph_node *cgraph_node (tree);
+void foo (int, const char *, ...) __attribute__((__format__(__gcc_diag__, 2, 
3)));

        Jakub

Reply via email to