PR c/86125 - missing -Wbuiltin-declaration-mismatch on a mismatched return type
authorMartin Sebor <msebor@redhat.com>
Thu, 24 Jan 2019 21:06:01 +0000 (21:06 +0000)
committerMartin Sebor <msebor@gcc.gnu.org>
Thu, 24 Jan 2019 21:06:01 +0000 (14:06 -0700)
PR c/86125 - missing -Wbuiltin-declaration-mismatch on a mismatched return type
PR middle-end/86308 - ICE in verify_gimple calling index() with an invalid declaration
PR c/86125 - missing -Wbuiltin-declaration-mismatch on a mismatched return type
PR c/88886 - [9 Regression] ice in get_constant, at c-family/c-format.c:292

gcc/c/ChangeLog:

PR c/86125
PR c/88886
PR middle-end/86308
* c-decl.c (match_builtin_function_types): Add arguments.
(diagnose_mismatched_decls): Diagnose mismatched declarations
of built-ins more strictly.

gcc/testsuite/ChangeLog:

PR c/86125
PR c/88886
PR middle-end/86308
* gcc.dg/Wbuiltin-declaration-mismatch-6.c: New test.
* gcc.dg/Wbuiltin-declaration-mismatch-7.c: New test.
* gcc.dg/Wbuiltin-declaration-mismatch-8.c: New test.
* gcc.dg/Wbuiltin-declaration-mismatch-9.c: New test.
* gcc.dg/Wbuiltin-declaration-mismatch-10.c: New test.
* gcc.dg/builtins-69.c: New test.
* gcc.dg/Wint-conversion-2.c: Add expected warning.
* gcc.c-torture/execute/eeprof-1.c: Adjust function signatures.

From-SVN: r268251

gcc/c/ChangeLog
gcc/c/c-decl.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/execute/eeprof-1.c
gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-10.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-6.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-7.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-8.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-9.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/Wint-conversion-2.c
gcc/testsuite/gcc.dg/builtins-69.c [new file with mode: 0644]

index 32c77f9360b1c5e19ca9d88b8803541974a49c14..cb89cd881e50639b92a4a8f11c1967195be0bd7d 100644 (file)
@@ -1,3 +1,12 @@
+2019-01-24  Martin Sebor  <msebor@redhat.com>
+
+       PR c/86125
+       PR c/88886
+       PR middle-end/86308
+       * c-decl.c (match_builtin_function_types): Add arguments.
+       (diagnose_mismatched_decls): Diagnose mismatched declarations
+       of built-ins more strictly.
+
 2019-01-24  Jakub Jelinek  <jakub@redhat.com>
 
        PR c++/88976
index 57049f8007322b6ca32e5ad4feb202c77160ffaf..b60f1557e9e0e3449b679ad62932fb86720372b9 100644 (file)
@@ -1631,43 +1631,91 @@ c_bind (location_t loc, tree decl, bool is_global)
   bind (DECL_NAME (decl), decl, scope, false, nested, loc);
 }
 \f
+
+/* 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).
+   Used only by match_builtin_function_types.  */
+
+static GTY(()) tree last_fileptr_type;
+
 /* Subroutine of compare_decls.  Allow harmless mismatches in return
-   and argument types provided that the type modes match.  This function
-   return a unified type given a suitable match, and 0 otherwise.  */
+   and argument types provided that the type modes match.  Set *STRICT
+   and *ARGNO to the expected argument type and number in case of
+   an argument type mismatch or null and zero otherwise.  Return
+   a unified type given a suitable match, and 0 otherwise.  */
 
 static tree
-match_builtin_function_types (tree newtype, tree oldtype)
+match_builtin_function_types (tree newtype, tree oldtype,
+                             tree *strict, unsigned *argno)
 {
-  tree newrettype, oldrettype;
-  tree newargs, oldargs;
-  tree trytype, tryargs;
-
   /* Accept the return type of the new declaration if same modes.  */
-  oldrettype = TREE_TYPE (oldtype);
-  newrettype = TREE_TYPE (newtype);
+  tree oldrettype = TREE_TYPE (oldtype);
+  tree newrettype = TREE_TYPE (newtype);
+
+  *argno = 0;
+  *strict = NULL_TREE;
 
   if (TYPE_MODE (oldrettype) != TYPE_MODE (newrettype))
     return NULL_TREE;
 
-  oldargs = TYPE_ARG_TYPES (oldtype);
-  newargs = TYPE_ARG_TYPES (newtype);
-  tryargs = newargs;
+  if (!comptypes (oldrettype, newrettype))
+    *strict = oldrettype;
 
-  while (oldargs || newargs)
+  tree oldargs = TYPE_ARG_TYPES (oldtype);
+  tree newargs = TYPE_ARG_TYPES (newtype);
+  tree tryargs = newargs;
+
+  for (unsigned i = 1; oldargs || newargs; ++i)
     {
       if (!oldargs
          || !newargs
          || !TREE_VALUE (oldargs)
-         || !TREE_VALUE (newargs)
-         || TYPE_MODE (TREE_VALUE (oldargs))
-            != TYPE_MODE (TREE_VALUE (newargs)))
+         || !TREE_VALUE (newargs))
        return NULL_TREE;
 
+      tree oldtype = TREE_VALUE (oldargs);
+      tree newtype = TREE_VALUE (newargs);
+
+      /* Fail for types with incompatible modes/sizes.  */
+      if (TYPE_MODE (TREE_VALUE (oldargs))
+         != TYPE_MODE (TREE_VALUE (newargs)))
+       return NULL_TREE;
+
+      /* Fail for function and object pointer mismatches.  */
+      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))
+       {
+         *argno = i;
+         *strict = oldtype;
+       }
+
       oldargs = TREE_CHAIN (oldargs);
       newargs = TREE_CHAIN (newargs);
     }
 
-  trytype = build_function_type (newrettype, tryargs);
+  tree trytype = build_function_type (newrettype, tryargs);
 
   /* Allow declaration to change transaction_safe attribute.  */
   tree oldattrs = TYPE_ATTRIBUTES (oldtype);
@@ -1881,14 +1929,26 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
       if (TREE_CODE (olddecl) == FUNCTION_DECL
          && fndecl_built_in_p (olddecl) && !C_DECL_DECLARED_BUILTIN (olddecl))
        {
-         /* Accept harmless mismatch in function types.
-            This is for the ffs and fprintf builtins.  */
-         tree trytype = match_builtin_function_types (newtype, oldtype);
+         /* Accept "harmless" mismatches in function types such
+            as missing qualifiers or pointer vs same size integer
+            mismatches.  This is for the ffs and fprintf builtins.
+            However, with -Wextra in effect, diagnose return and
+            argument types that are incompatible according to
+            language rules.  */
+         tree mismatch_expect;
+         unsigned mismatch_argno;
+
+         tree trytype = match_builtin_function_types (newtype, oldtype,
+                                                      &mismatch_expect,
+                                                      &mismatch_argno);
 
          if (trytype && comptypes (newtype, trytype))
            *oldtypep = oldtype = trytype;
          else
            {
+             /* If types don't match for a built-in, throw away the
+                built-in.  No point in calling locate_old_decl here, it
+                won't print anything.  */
              const char *header
                = header_for_builtin_fn (DECL_FUNCTION_CODE (olddecl));
              location_t loc = DECL_SOURCE_LOCATION (newdecl);
@@ -1905,11 +1965,25 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
                  inform (&richloc,
                          "%qD is declared in header %qs", olddecl, header);
                }
-             /* If types don't match for a built-in, throw away the
-                built-in.  No point in calling locate_old_decl here, it
-                won't print anything.  */
              return false;
            }
+
+         if (mismatch_expect && extra_warnings)
+           {
+             /* If types match only loosely, print a warning but accept
+                the redeclaration.  */
+             location_t newloc = DECL_SOURCE_LOCATION (newdecl);
+             if (mismatch_argno)
+               warning_at (newloc, OPT_Wbuiltin_declaration_mismatch,
+                           "mismatch in argument %u type of built-in "
+                           "function %qD; expected %qT",
+                           mismatch_argno, newdecl, mismatch_expect);
+             else
+               warning_at (newloc, OPT_Wbuiltin_declaration_mismatch,
+                           "mismatch in return type of built-in "
+                           "function %qD; expected %qT",
+                           newdecl, mismatch_expect);
+           }
        }
       else if (TREE_CODE (olddecl) == FUNCTION_DECL
               && DECL_IS_BUILTIN (olddecl))
index 55dcd7469a64b648e5aeefbb64a0f21c33da3654..fa88d9d35cba0d0f2d2f92bf6983e684108ed605 100644 (file)
@@ -1,3 +1,17 @@
+2019-01-24  Martin Sebor  <msebor@redhat.com>
+
+       PR c/86125
+       PR c/88886
+       PR middle-end/86308
+       * gcc.dg/Wbuiltin-declaration-mismatch-6.c: New test.
+       * gcc.dg/Wbuiltin-declaration-mismatch-7.c: New test.
+       * gcc.dg/Wbuiltin-declaration-mismatch-8.c: New test.
+       * gcc.dg/Wbuiltin-declaration-mismatch-9.c: New test.
+       * gcc.dg/Wbuiltin-declaration-mismatch-10.c: New test.
+       * gcc.dg/builtins-69.c: New test.
+       * gcc.dg/Wint-conversion-2.c: Add expected warning.
+       * gcc.c-torture/execute/eeprof-1.c: Adjust function signatures.
+
 2019-01-24  Uroš Bizjak  <ubizjak@gmail.com>
 
        PR rtl-optimization/88948
index 81dcefbab1200f427dc277dcff42efe7302d334e..c10f4cf83c358a3fdf7c52a5b2ad1ec0857a859e 100644 (file)
@@ -62,18 +62,18 @@ int main ()
   return 0;
 }
 
-void __cyg_profile_func_enter (void (*fn)(), void (*parent)()) NOCHK;
-void __cyg_profile_func_exit (void (*fn)(), void (*parent)()) NOCHK;
+void __cyg_profile_func_enter (void*, void*) NOCHK;
+void __cyg_profile_func_exit (void*, void*) NOCHK;
 
 __attribute__ ((noinline))
-void __cyg_profile_func_enter (void (*fn)(), void (*parent)())
+void __cyg_profile_func_enter (void *fn, void *parent)
 {
   entry_calls++;
-  last_fn_entered = fn;
+  last_fn_entered = (void (*)())fn;
 }
 __attribute__ ((noinline))
-void __cyg_profile_func_exit (void (*fn)(), void (*parent)())
+void __cyg_profile_func_exit (void *fn, void *parent)
 {
   exit_calls++;
-  last_fn_exited = fn;
+  last_fn_exited = (void (*)())fn;
 }
diff --git a/gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-10.c b/gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-10.c
new file mode 100644 (file)
index 0000000..58de1d4
--- /dev/null
@@ -0,0 +1,10 @@
+/* PR c/86308 - ICE in verify_gimple calling an invalid index() declaration
+   { dg-do compile }
+   { dg-options "-Wall" } */
+
+int index (int, int);         /* { dg-warning "conflicting types for built-in function .index.; expected .char \\\*\\\(const char \\\*, int\\\)." } */
+
+int foo (const short *a)
+{
+  return a[index (0, 0)];
+}
diff --git a/gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-6.c b/gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-6.c
new file mode 100644 (file)
index 0000000..32af9fe
--- /dev/null
@@ -0,0 +1,18 @@
+/* PR c/86125 - missing -Wbuiltin-declaration-mismatch on a mismatched
+   return type
+   Verify that declarations of file I/O built-ins with an arbitrary
+   object pointer do not trigger -Wbuiltin-declaration-mismatch.
+   { dg-do compile }
+   { dg-options "-Wbuiltin-declaration-mismatch -Wextra" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+struct StdioFile;
+
+int fprintf (struct StdioFile*, const char*, ...);
+int vfprintf (struct StdioFile*, const char*, __builtin_va_list);
+int fputc (int, struct StdioFile*);
+int fputs (const char*, struct StdioFile*);
+int fscanf (struct StdioFile*, const char*, ...);
+int vfscanf (struct StdioFile*, const char*, __builtin_va_list);
+size_t fwrite (const void*, size_t, size_t, struct StdioFile*);
diff --git a/gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-7.c b/gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-7.c
new file mode 100644 (file)
index 0000000..77a4bff
--- /dev/null
@@ -0,0 +1,26 @@
+/* PR c/86125 - missing -Wbuiltin-declaration-mismatch on a mismatched
+   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-options "-Wbuiltin-declaration-mismatch" } */
+
+struct StdioFile;
+
+typedef __SIZE_TYPE__ size_t;
+
+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 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_\]+ \\\*\\\)." } */
+
+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_\]+ \\\*\\\)." } */
+
+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_\]+ \\\*\\\)." } */
diff --git a/gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-8.c b/gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-8.c
new file mode 100644 (file)
index 0000000..d06af65
--- /dev/null
@@ -0,0 +1,26 @@
+/* PR c/86125 - missing -Wbuiltin-declaration-mismatch on a mismatched
+   return type
+   Verify that declarations of file I/O built-ins with different
+   definitions of struct FILE triggers -Wbuiltin-declaration-mismatch
+   when -Wextra is specified.
+   { dg-do compile }
+   { dg-options "-Wall -Wbuiltin-declaration-mismatch" } */
+
+struct FooFile;
+int fputc (int, struct FooFile*);
+
+typedef struct FooFile AlsoFooFile;
+int fprintf (AlsoFooFile*, const char*, ...);
+
+typedef AlsoFooFile* FooFilePtr;
+int fscanf (FooFilePtr, const char*, ...);
+
+/* No warning here (-Wextra not specified).  */
+struct BarFile;
+int vfprintf (struct BarFile*, const char*, __builtin_va_list);
+
+
+/* Set -Wextra and verify -Wbuiltin-declaration-mismatch is issued.  */
+#pragma GCC diagnostic warning "-Wextra"
+
+int fputs (const char*, struct BarFile*);   /* { dg-warning "mismatch in argument 2 type of built-in function .fputs.; expected .struct FooFile \\\*." } */
diff --git a/gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-9.c b/gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-9.c
new file mode 100644 (file)
index 0000000..f0c1ce3
--- /dev/null
@@ -0,0 +1,12 @@
+/* PR c/88886 - ice in get_constant, at c-family/c-format.c:292
+   { dg-do compile }
+   { dg-options "-Wall" } */
+
+int sscanf (long, unsigned[], ...);   /* { dg-warning "conflicting types for built-in function .sscanf.; expected .int\\\(const char \\\*, const char \\\*, ...\\\)." } */
+
+void a (void)
+{
+  sscanf (0,
+         ""        /* { dg-warning "passing argument 2 of .sscanf. from incompatible pointer type" } */
+         );
+}
index 0c9dac44c41650c265a4371511c5348354d2e384..bf590a7bcd7d0c963bd78558666c19d22ddcb57f 100644 (file)
@@ -1,8 +1,9 @@
-/* PR middle-end/86202 */
+/* PR middle-end/86202 - ICE in get_range_info calling an invalid memcpy()
+   declaration */
 /* { dg-do compile } */
 /* { dg-options "-Wint-conversion" } */
 
-void *memcpy (void *, void *, __SIZE_TYPE__ *);
+void *memcpy (void *, void *, __SIZE_TYPE__ *);   /* { dg-warning "conflicting types for built-in function .memcpy." } */
 void *a, *b;
 void f (void)
 {
diff --git a/gcc/testsuite/gcc.dg/builtins-69.c b/gcc/testsuite/gcc.dg/builtins-69.c
new file mode 100644 (file)
index 0000000..26dfb3b
--- /dev/null
@@ -0,0 +1,22 @@
+/* PR middle-end/86308 - ICE in verify_gimple calling index() with
+   an invalid declaration
+   { dg-do compile }
+   { dg-options "-O2 -Wall" }  */
+
+int index (int, int);   /* { dg-warning "conflicting types for built-in function .index.; expected .char \\\*\\\(const char \\\*, int\\\)." } */
+
+int test_index (void)
+{
+  return index (0, 0);
+}
+
+
+/* PR middle-end/86202 - ICE in get_range_info calling an invalid memcpy()
+   declaration */
+
+void *memcpy (void *, void *, __SIZE_TYPE__ *);   /* { dg-warning "conflicting types for built-in function .memcpy.; expected .void \\\*\\\(void \\\*, const void \\\*, \(long \)?unsigned int\\\)." } */
+
+void test_memcpy (void *p, void *q, __SIZE_TYPE__ *r)
+{
+  memcpy (p, q, r);
+}