Hi!

Here is an untested patch that should fix all of that, ok for trunk
if it passes bootstrap/regtest on {x86_64,i686}-linux?

Notes:
1) seems the C++ FE is even stricter and uses the
   builtin_structptr_types[x].str string to verify the pointed type
   has the right TYPE_NAME; is that something we want to require
   for C also?  That would mean we'd warn about
   Wbuiltin-declaration-mismatch-6.c etc. too, because it uses:
   struct StdioFile;
   int fprintf (struct StdioFile*, const char*, ...);
   If it was
   typedef struct StdioFile FILE;
   int fprintf (FILE*, const char*, ...);
   that would be accepted then.  Also, unlike C++, C has struct tags vs.
   typedef tags as separate namespaces, so we'd need to either handle
   it specially for struct tm (where the standard prototype is
   const struct tm *, not const tm *) vs. the rest, or accept struct
   as well as typedef names equal to builtin_structptr_types[x].str,
   or don't do anything here (I didn't want to be even stricter than
   Martin's patch)
2) it accepts any kind of pointed type and just requires it is the same
   later on, so it accepts e.g.
   struct StdioFile;
   typedef struct StdioFile FILE;
   int fprintf (const FILE *, const char *, ...);
   and then requires those pointers to be the same in all cases.
   Shall we verify the qualifiers on the pointed type before we accept
   it into last_structptr_types?  If yes, right now it would emit
   weird diagnostics (request that the type would be say const void *
   instead of struct tm *)
3) for fexcept_t and fenv_t, there are actually 2 types for each,
   const {fexcept,fenv}_t * vs. {fexcept,fenv}_t *.  No verification
   is done that the TYPE_MAIN_VARIANT is the same between both if both
   are seen.  This only makes sense if 2) is implemented, and would
   probably work if both 1) and 2) are implemented without anything
   further.

Not planning to work on these myself, all I want to fix is the breakage.

2019-01-26  Jakub Jelinek  <ja...@redhat.com>

        PR c/86125
        * c-decl.c (last_fileptr_type): Remove.
        (last_structptr_types): New variable.
        (match_builtin_function_types): Compare TYPE_MAIN_VARIANT of
        {old,new}rettype instead of the types themselves.  Assert
        last_structptr_types array has the same number of elements
        as builtin_structptr_types array.  Use TYPE_MAIN_VARIANT for
        argument oldtype and newtype.  Instead of handling
        just fileptr_type_node specially, handle all builtin_structptr_types
        pointer nodes.  Formatting fix.

        * c-common.c (c_common_nodes_and_builtins): Build type variants for
        builtin_structptr_types types even for C.

        * gcc.dg/Wbuiltin-declaration-mismatch-7.c: Guard testcase for
        lp64, ilp32 and llp64 only.
        (fputs): Use unsigned long long instead of size_t for return type.
        (vfprintf, vfscanf): Accept arbitrary target specific type for
        va_list.

--- gcc/c/c-decl.c.jj   2019-01-25 23:46:06.121198286 +0100
+++ gcc/c/c-decl.c      2019-01-26 15:34:02.749450800 +0100
@@ -1632,13 +1632,13 @@ c_bind (location_t loc, tree decl, bool
 }
 
 
-/* Stores the first FILE* argument type (whatever it is) seen in
-   a declaration of a file I/O built-in.  Subsequent declarations
-   of such built-ins are expected to refer to it rather than to
-   fileptr_type_node which is just void* (or to any other type).
+/* Stores the first FILE*, const struct tm* etc. argument type (whatever it
+   is) seen in a declaration of a file I/O etc. built-in.  Subsequent
+   declarations of such built-ins are expected to refer to it rather than to
+   fileptr_type_node etc. which is just void* (or to any other type).
    Used only by match_builtin_function_types.  */
 
-static GTY(()) tree last_fileptr_type;
+static GTY(()) tree last_structptr_types[6];
 
 /* Subroutine of compare_decls.  Allow harmless mismatches in return
    and argument types provided that the type modes match.  Set *STRICT
@@ -1660,13 +1660,18 @@ match_builtin_function_types (tree newty
   if (TYPE_MODE (oldrettype) != TYPE_MODE (newrettype))
     return NULL_TREE;
 
-  if (!comptypes (oldrettype, newrettype))
+  if (!comptypes (TYPE_MAIN_VARIANT (oldrettype),
+                 TYPE_MAIN_VARIANT (newrettype)))
     *strict = oldrettype;
 
   tree oldargs = TYPE_ARG_TYPES (oldtype);
   tree newargs = TYPE_ARG_TYPES (newtype);
   tree tryargs = newargs;
 
+  gcc_checking_assert ((sizeof (last_structptr_types)
+                       / sizeof (last_structptr_types[0]))
+                      == (sizeof (builtin_structptr_types)
+                          / sizeof (builtin_structptr_types[0])));
   for (unsigned i = 1; oldargs || newargs; ++i)
     {
       if (!oldargs
@@ -1675,8 +1680,8 @@ match_builtin_function_types (tree newty
          || !TREE_VALUE (newargs))
        return NULL_TREE;
 
-      tree oldtype = TREE_VALUE (oldargs);
-      tree newtype = TREE_VALUE (newargs);
+      tree oldtype = TYPE_MAIN_VARIANT (TREE_VALUE (oldargs));
+      tree newtype = TYPE_MAIN_VARIANT (TREE_VALUE (newargs));
 
       /* Fail for types with incompatible modes/sizes.  */
       if (TYPE_MODE (TREE_VALUE (oldargs))
@@ -1684,28 +1689,39 @@ match_builtin_function_types (tree newty
        return NULL_TREE;
 
       /* Fail for function and object pointer mismatches.  */
-      if (FUNCTION_POINTER_TYPE_P (oldtype) != FUNCTION_POINTER_TYPE_P 
(newtype)
+      if ((FUNCTION_POINTER_TYPE_P (oldtype)
+          != FUNCTION_POINTER_TYPE_P (newtype))
          || POINTER_TYPE_P (oldtype) != POINTER_TYPE_P (newtype))
        return NULL_TREE;
 
-      if (oldtype == fileptr_type_node)
-       {
-         /* Store the first FILE* argument type (whatever it is), and
-            expect any subsequent declarations of file I/O built-ins
-            to refer to it rather than to fileptr_type_node which is
-            just void*.  */
-         if (last_fileptr_type)
-           {
-             if (!comptypes (last_fileptr_type, newtype))
-               {
-                 *argno = i;
-                 *strict = last_fileptr_type;
-               }
-           }
-         else
-           last_fileptr_type = newtype;
-       }
-      else if (!*strict && !comptypes (oldtype, newtype))
+      unsigned j = (sizeof (builtin_structptr_types)
+                   / sizeof (builtin_structptr_types[0]));
+      if (POINTER_TYPE_P (oldtype))
+       for (j = 0; j < (sizeof (builtin_structptr_types)
+                        / sizeof (builtin_structptr_types[0])); ++j)
+         {
+           if (TREE_VALUE (oldargs) != builtin_structptr_types[j].node)
+             continue;
+           /* Store the first FILE* etc. argument type (whatever it is), and
+              expect any subsequent declarations of file I/O etc. built-ins
+              to refer to it rather than to fileptr_type_node etc. which is
+              just void* (or const void*).  */
+           if (last_structptr_types[j])
+             {
+               if (!comptypes (last_structptr_types[j], newtype))
+                 {
+                   *argno = i;
+                   *strict = last_structptr_types[j];
+                 }
+             }
+           else
+             last_structptr_types[j] = newtype;
+           break;
+         }
+      if (j == (sizeof (builtin_structptr_types)
+               / sizeof (builtin_structptr_types[0]))
+         && !*strict
+         && !comptypes (oldtype, newtype))
        {
          *argno = i;
          *strict = oldtype;
--- gcc/c-family/c-common.c.jj  2019-01-16 09:35:04.566323056 +0100
+++ gcc/c-family/c-common.c     2019-01-26 14:39:04.909695084 +0100
@@ -4296,18 +4296,13 @@ c_common_nodes_and_builtins (void)
                         COMPLEX_FLOATN_NX_TYPE_NODE (i)));
        }
 
-  if (c_dialect_cxx ())
-    {
-      /* For C++, make fileptr_type_node a distinct void * type until
-        FILE type is defined.  Likewise for const struct tm*.  */
-      for (unsigned i = 0;
-          i < sizeof (builtin_structptr_types)
-              / sizeof (builtin_structptr_type);
-          ++i)
-       builtin_structptr_types[i].node =
-         build_variant_type_copy (builtin_structptr_types[i].base);
-
-    }
+  /* Make fileptr_type_node a distinct void * type until
+     FILE type is defined.  Likewise for const struct tm*.  */
+  for (unsigned i = 0;
+       i < sizeof (builtin_structptr_types) / sizeof (builtin_structptr_type);
+       ++i)
+    builtin_structptr_types[i].node
+      = build_variant_type_copy (builtin_structptr_types[i].base);
 
   record_builtin_type (RID_VOID, NULL, void_type_node);
 
--- gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-7.c.jj   2019-01-25 
06:08:50.629941283 +0100
+++ gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-7.c      2019-01-26 
13:23:18.126323403 +0100
@@ -2,7 +2,7 @@
    return type
    Verify that a declaration of vfprintf() with withe the wrong last
    argument triggers -Wbuiltin-declaration-mismatch even without -Wextra.
-   { dg-do compile }
+   { dg-do compile { target { lp64 || ilp32 || llp64 } } }
    { dg-options "-Wbuiltin-declaration-mismatch" } */
 
 struct StdioFile;
@@ -13,14 +13,14 @@ struct StdioFile;
 
 int fprintf (struct StdioFile*, const char*);   /* { dg-warning "conflicting 
types for built-in function .fprintf.; expected .int\\\(\[a-z_\]+ \\\*, const 
char \\\*, \.\.\.\\\)." } */
 
-int vfprintf (struct StdioFile*, const char*, ...);   /* { dg-warning 
"conflicting types for built-in function .vfprintf.; expected .int\\\(\[a-z_\]+ 
\\\*, const char \\\*, \[a-z_\]+ \\\*\\\)." } */
+int vfprintf (struct StdioFile*, const char*, ...);   /* { dg-warning 
"conflicting types for built-in function .vfprintf.; expected .int\\\(\[a-z_\]+ 
\\\*, const char \\\*, \[^\n\r,\\\)\]+\\\)." } */
 
 int fputc (char, struct StdioFile*);   /* { dg-warning "conflicting types for 
built-in function .fputc.; expected .int\\\(int,  void \\\*\\\)." } */
 
-size_t fputs (const char*, struct StdioFile*);   /* { dg-warning "conflicting 
types for built-in function .fputs.; expected .int\\\(const char \\\*, 
\[a-z_\]+ \\\*\\\)." } */
+unsigned long long fputs (const char*, struct StdioFile*);   /* { dg-warning 
"conflicting types for built-in function .fputs.; expected .int\\\(const char 
\\\*, \[a-z_\]+ \\\*\\\)." } */
 
 int fscanf (struct StdioFile*, const char*, size_t, ...);   /* { dg-warning 
"conflicting types for built-in function .fscanf.; expected .int\\\(\[a-z_\]+ 
\\\*, const char \\\*, \.\.\.\\\)." } */
 
-int vfscanf (struct StdioFile*, const char*, ...);   /* { dg-warning 
"conflicting types for built-in function .vfscanf.; expected .int\\\(\[a-z_\]+ 
\\\*, const char \\\*, \[a-z_\]+ \\\*\\\)." } */
+int vfscanf (struct StdioFile*, const char*, ...);   /* { dg-warning 
"conflicting types for built-in function .vfscanf.; expected .int\\\(\[a-z_\]+ 
\\\*, const char \\\*, \[^\n\r,\\\)\]+\\\)." } */
 
 size_t fwrite (const void*, size_t, size_t, struct StdioFile);    /* { 
dg-warning "conflicting types for built-in function .fwrite.; expected .\(long 
\)?unsigned int\\\(const void \\\*, \(long \)?unsigned int, *\(long \)?unsigned 
int, *\[a-z_\]+ \\\*\\\)." } */
--- gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-11.c.jj  2019-01-26 
12:31:26.035636194 +0100
+++ gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-11.c     2019-01-26 
14:16:38.869483474 +0100
@@ -0,0 +1,21 @@
+/* PR c/86125 */
+/* { dg-do compile } */
+/* { dg-options "-Wbuiltin-declaration-mismatch -Wextra 
-Wno-ignored-qualifiers" } */
+
+typedef __SIZE_TYPE__ size_t;
+struct FILE;
+struct tm;
+struct fenv_t;
+struct fexcept_t;
+typedef struct FILE FILE;
+typedef struct fenv_t fenv_t;
+typedef struct fexcept_t fexcept_t;
+typedef const int cint;
+size_t strftime (char *__restrict, const size_t, const char *__restrict,       
/* { dg-bogus "mismatch in argument 1 type of built-in function" } */
+                 const struct tm *__restrict) __attribute__((nothrow));
+int fprintf (struct FILE *, const char *const, ...);                           
/* { dg-bogus "mismatch in argument 2 type of built-in function" } */
+cint putc (int, struct FILE *);                                                
        /* { dg-bogus "mismatch in return type of built-in function" } */
+cint fegetenv (fenv_t *);                                                      
/* { dg-bogus "mismatch in argument 1 type of built-in function" } */
+cint fesetenv (const fenv_t *);                                                
        /* { dg-bogus "mismatch in return type of built-in function" } */
+int fegetexceptflag (fexcept_t *, const int);                                  
/* { dg-bogus "mismatch in argument 1 type of built-in function" } */
+int fesetexceptflag (const fexcept_t *, const int);                            
/* { dg-bogus "mismatch in argument 1 type of built-in function" } */


        Jakub

Reply via email to