I was hoping to avoid the complexity but I appreciate
the desire for a more permissive solution, at least for
some transitional period.

I've reworked the patch to avoid diagnosing 'void abort();'
(the only library built-in that takes no arguments).
Instead, calls that pass arguments to it are diagnosed.

While at it, I generalized the convert_arguments() function
to diagnose argument mismatches in calls to any built-in
declared without a prototype.  I think this is a useful
feature regardless because many such calls are not considered
for optimization even when they are safe.  But with it in
place, declarations of built-ins without a prototype could
continue to be silently accepted by default for a period and
only diagnosed with -Wextra until we are ready to turn on
the warnings by default.  (If that's thought necessary --
the patch as is doesn't do that.)

Since these changes involve factoring quite a bit of code into
a new function (with only very minor tweaks), to make review
easier, I attach two diffs: one with -w, and another full one.
The full diff also contains the cleanup of the failing tests.

Martin

On 06/27/2018 09:27 AM, Jakub Jelinek wrote:
On Wed, Jun 27, 2018 at 09:17:07AM -0600, Jeff Law wrote:
About 115 tests fail due to incompatible declarations of
the built-in functions below (the number shows the number
of warnings for each functions):

428   abort
 58   exit
 36   memcpy
 17   memmove
 15   realloc
 14   cabs
  5   strncpy
  4   strcmp
  3   alloca
  2   rindex
  1   aligned_alloc
I'm supportive of this change.  Though I'm more worried about the
affects on the distros than I am on the testsuite (which I expected to
be in worse shape WRT this issue than your analysis indicates).

I'm mainly worried about configure tests, those will be hit hardest by
this and might result in silently turning off many features of the compiled
programs.

I think
void abort ();
is very common and if people actually don't pass any arguments to abort, I
think warning by default about this is too much.

        Jakub


PR c/83656 - missing -Wbuiltin-declaration-mismatch on declaration without 
prototype

gcc/c/ChangeLog:

        PR c/83656
        * c-decl.c (diagnose_mismatched_decls): Diagnose declarations of
        built-in functions without a prototype.
        * c-typeck.c (convert_argument): New function.
        (convert_arguments): Factor code out into convert_argument.
        Detect mismatches between built-in formal arguments in calls
        to built-in without prototype.
        (convert_for_assignment): Add argument.  Conditionally issue
        warnings instead of errors for mismatches.

diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index af16cfd..07beaa1 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -1886,8 +1886,9 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
                 built-in.  No point in calling locate_old_decl here, it
                 won't print anything.  */
              warning (OPT_Wbuiltin_declaration_mismatch,
-                      "conflicting types for built-in function %q+D",
-                      newdecl);
+                      "conflicting types for built-in function %q+D; "
+                      "expected %qT",
+                      newdecl, oldtype);
              return false;
            }
        }
@@ -2021,17 +2022,35 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
         can't validate the argument list) the built-in definition is
         overridden, but optionally warn this was a bad choice of name.  */
       if (DECL_BUILT_IN (olddecl)
-         && !C_DECL_DECLARED_BUILTIN (olddecl)
-         && (!TREE_PUBLIC (newdecl)
+         && !C_DECL_DECLARED_BUILTIN (olddecl))
+       {
+         if (!TREE_PUBLIC (newdecl)
              || (DECL_INITIAL (newdecl)
-                 && !prototype_p (TREE_TYPE (newdecl)))))
+                 && !prototype_p (TREE_TYPE (newdecl))))
            {
-         warning (OPT_Wshadow, "declaration of %q+D shadows "
+             warning_at (DECL_SOURCE_LOCATION (newdecl),
+                         OPT_Wshadow, "declaration of %qD shadows "
                          "a built-in function", newdecl);
              /* Discard the old built-in function.  */
              return false;
            }
 
+         if (!prototype_p (TREE_TYPE (newdecl)))
+           {
+             /* Set for built-ins that take no arguments.  */
+             bool func_void_args = false;
+             if (tree at = TYPE_ARG_TYPES (oldtype))
+               func_void_args = VOID_TYPE_P (TREE_VALUE (at));
+
+             if (extra_warnings || !func_void_args)
+               warning_at (DECL_SOURCE_LOCATION (newdecl),
+                           OPT_Wbuiltin_declaration_mismatch,
+                           "declaration of built-in function %qD without "
+                           "a prototype; expected %qT",
+                           newdecl, TREE_TYPE (olddecl));
+           }
+       }
+
       if (DECL_INITIAL (newdecl))
        {
          if (DECL_INITIAL (olddecl))
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 90ae306..e0584b9 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -97,7 +97,8 @@ static int convert_arguments (location_t, vec<location_t>, 
tree,
                              tree);
 static tree pointer_diff (location_t, tree, tree, tree *);
 static tree convert_for_assignment (location_t, location_t, tree, tree, tree,
-                                   enum impl_conv, bool, tree, tree, int);
+                                   enum impl_conv, bool, tree, tree, int,
+                                   int = 0);
 static tree valid_compound_expr_initializer (tree, tree);
 static void push_string (const char *);
 static void push_member_name (tree);
@@ -3179,164 +3180,20 @@ c_build_function_call_vec (location_t loc, 
vec<location_t> arg_loc,
   return build_function_call_vec (loc, arg_loc, function, params, origtypes);
 }
 
-/* Convert the argument expressions in the vector VALUES
-   to the types in the list TYPELIST.
-
-   If TYPELIST is exhausted, or when an element has NULL as its type,
-   perform the default conversions.
-
-   ORIGTYPES is the original types of the expressions in VALUES.  This
-   holds the type of enum values which have been converted to integral
-   types.  It may be NULL.
-
-   FUNCTION is a tree for the called function.  It is used only for
-   error messages, where it is formatted with %qE.
-
-   This is also where warnings about wrong number of args are generated.
-
-   ARG_LOC are locations of function arguments (if any).
-
-   Returns the actual number of arguments processed (which may be less
-   than the length of VALUES in some error situations), or -1 on
-   failure.  */
-
-static int
-convert_arguments (location_t loc, vec<location_t> arg_loc, tree typelist,
-                  vec<tree, va_gc> *values, vec<tree, va_gc> *origtypes,
-                  tree function, tree fundecl)
-{
-  tree typetail, val;
-  unsigned int parmnum;
-  bool error_args = false;
-  const bool type_generic = fundecl
-    && lookup_attribute ("type generic", TYPE_ATTRIBUTES (TREE_TYPE 
(fundecl)));
-  bool type_generic_remove_excess_precision = false;
-  bool type_generic_overflow_p = false;
-  tree selector;
-
-  /* Change pointer to function to the function itself for
-     diagnostics.  */
-  if (TREE_CODE (function) == ADDR_EXPR
-      && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL)
-    function = TREE_OPERAND (function, 0);
-
-  /* Handle an ObjC selector specially for diagnostics.  */
-  selector = objc_message_selector ();
-
-  /* For type-generic built-in functions, determine whether excess
-     precision should be removed (classification) or not
-     (comparison).  */
-  if (type_generic
-      && DECL_BUILT_IN (fundecl)
-      && DECL_BUILT_IN_CLASS (fundecl) == BUILT_IN_NORMAL)
-    {
-      switch (DECL_FUNCTION_CODE (fundecl))
-       {
-       case BUILT_IN_ISFINITE:
-       case BUILT_IN_ISINF:
-       case BUILT_IN_ISINF_SIGN:
-       case BUILT_IN_ISNAN:
-       case BUILT_IN_ISNORMAL:
-       case BUILT_IN_FPCLASSIFY:
-         type_generic_remove_excess_precision = true;
-         break;
+/* Helper for convert_arguments called to convert the VALue of argument
+   number ARGNUM from ORIGTYPE to the corresponding parameter number
+   PARMNUL and TYPE.  */
 
-       case BUILT_IN_ADD_OVERFLOW_P:
-       case BUILT_IN_SUB_OVERFLOW_P:
-       case BUILT_IN_MUL_OVERFLOW_P:
-         /* The last argument of these type-generic builtins
-            should not be promoted.  */
-         type_generic_overflow_p = true;
-         break;
-
-       default:
-         break;
-       }
-    }
-
-  /* Scan the given expressions and types, producing individual
-     converted arguments.  */
-
-  for (typetail = typelist, parmnum = 0;
-       values && values->iterate (parmnum, &val);
-       ++parmnum)
+static tree
+convert_argument (location_t ploc, tree function, tree fundecl,
+                 tree type, tree origtype, tree val,
+                 tree rname, int parmnum, int argnum,
+                 bool excess_precision, int warnopt)
 {
-      tree type = typetail ? TREE_VALUE (typetail) : 0;
   tree valtype = TREE_TYPE (val);
-      tree rname = function;
-      int argnum = parmnum + 1;
-      const char *invalid_func_diag;
-      bool excess_precision = false;
-      bool npc;
-      tree parmval;
-      /* Some __atomic_* builtins have additional hidden argument at
-        position 0.  */
-      location_t ploc
-       = !arg_loc.is_empty () && values->length () == arg_loc.length ()
-         ? expansion_point_location_if_in_system_header (arg_loc[parmnum])
-         : input_location;
-
-      if (type == void_type_node)
-       {
-         if (selector)
-           error_at (loc, "too many arguments to method %qE", selector);
-         else
-           error_at (loc, "too many arguments to function %qE", function);
-         inform_declaration (fundecl);
-         return error_args ? -1 : (int) parmnum;
-       }
 
-      if (selector && argnum > 2)
-       {
-         rname = selector;
-         argnum -= 2;
-       }
-
-      npc = null_pointer_constant_p (val);
-
-      /* If there is excess precision and a prototype, convert once to
-        the required type rather than converting via the semantic
-        type.  Likewise without a prototype a float value represented
-        as long double should be converted once to double.  But for
-        type-generic classification functions excess precision must
-        be removed here.  */
-      if (TREE_CODE (val) == EXCESS_PRECISION_EXPR
-         && (type || !type_generic || !type_generic_remove_excess_precision))
-       {
-         val = TREE_OPERAND (val, 0);
-         excess_precision = true;
-       }
-      val = c_fully_fold (val, false, NULL);
-      STRIP_TYPE_NOPS (val);
-
-      val = require_complete_type (ploc, val);
-
-      /* Some floating-point arguments must be promoted to double when
-        no type is specified by a prototype.  This applies to
-        arguments of type float, and to architecture-specific types
-        (ARM __fp16), but not to _FloatN or _FloatNx types.  */
-      bool promote_float_arg = false;
-      if (type == NULL_TREE
-         && TREE_CODE (valtype) == REAL_TYPE
-         && (TYPE_PRECISION (valtype)
-             <= TYPE_PRECISION (double_type_node))
-         && TYPE_MAIN_VARIANT (valtype) != double_type_node
-         && TYPE_MAIN_VARIANT (valtype) != long_double_type_node
-         && !DECIMAL_FLOAT_MODE_P (TYPE_MODE (valtype)))
-       {
-         /* Promote this argument, unless it has a _FloatN or
-            _FloatNx type.  */
-         promote_float_arg = true;
-         for (int i = 0; i < NUM_FLOATN_NX_TYPES; i++)
-           if (TYPE_MAIN_VARIANT (valtype) == FLOATN_NX_TYPE_NODE (i))
-             {
-               promote_float_arg = false;
-               break;
-             }
-       }
+  tree parmval;
 
-      if (type != NULL_TREE)
-       {
   /* Formal parm type is specified by a function prototype.  */
 
   if (type == error_mark_node || !COMPLETE_TYPE_P (type))
@@ -3347,10 +3204,8 @@ convert_arguments (location_t loc, vec<location_t> 
arg_loc, tree typelist,
     }
   else
     {
-             tree origtype;
-
-             /* Optionally warn about conversions that
-                differ from the default conversions.  */
+      /* Optionally warn about conversions that differ from the default
+        conversions.  */
       if (warn_traditional_conversion || warn_traditional)
        {
          unsigned int formal_prec = TYPE_PRECISION (type);
@@ -3492,17 +3347,208 @@ convert_arguments (location_t loc, vec<location_t> 
arg_loc, tree typelist,
         sake of better warnings from convert_and_check.  */
       if (excess_precision)
        val = build1 (EXCESS_PRECISION_EXPR, valtype, val);
-             origtype = (!origtypes) ? NULL_TREE : (*origtypes)[parmnum];
-             parmval = convert_for_assignment (loc, ploc, type,
+
+      parmval = convert_for_assignment (ploc, ploc, type,
                                        val, origtype, ic_argpass,
-                                               npc, fundecl, function,
-                                               parmnum + 1);
+                                       null_pointer_constant_p (val),
+                                       fundecl, function,
+                                       parmnum + 1, warnopt);
 
       if (targetm.calls.promote_prototypes (fundecl ? TREE_TYPE (fundecl) : 0)
          && INTEGRAL_TYPE_P (type)
          && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
        parmval = default_conversion (parmval);
     }
+
+  return parmval;
+}
+
+/* Convert the argument expressions in the vector VALUES
+   to the types in the list TYPELIST.
+
+   If TYPELIST is exhausted, or when an element has NULL as its type,
+   perform the default conversions.
+
+   ORIGTYPES is the original types of the expressions in VALUES.  This
+   holds the type of enum values which have been converted to integral
+   types.  It may be NULL.
+
+   FUNCTION is a tree for the called function.  It is used only for
+   error messages, where it is formatted with %qE.
+
+   This is also where warnings about wrong number of args are generated.
+
+   ARG_LOC are locations of function arguments (if any).
+
+   Returns the actual number of arguments processed (which may be less
+   than the length of VALUES in some error situations), or -1 on
+   failure.  */
+
+static int
+convert_arguments (location_t loc, vec<location_t> arg_loc, tree typelist,
+                  vec<tree, va_gc> *values, vec<tree, va_gc> *origtypes,
+                  tree function, tree fundecl)
+{
+  unsigned int parmnum;
+  bool error_args = false;
+  const bool type_generic = fundecl
+    && lookup_attribute ("type generic", TYPE_ATTRIBUTES (TREE_TYPE 
(fundecl)));
+  bool type_generic_remove_excess_precision = false;
+  bool type_generic_overflow_p = false;
+  tree selector;
+
+  /* Change pointer to function to the function itself for
+     diagnostics.  */
+  if (TREE_CODE (function) == ADDR_EXPR
+      && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL)
+    function = TREE_OPERAND (function, 0);
+
+  /* Handle an ObjC selector specially for diagnostics.  */
+  selector = objc_message_selector ();
+
+  /* For a call to a built-in function declared without a prototype,
+     set to the built-in function's argument list.  */
+  tree builtin_typelist = NULL_TREE;
+
+  if (fundecl
+      && DECL_BUILT_IN (fundecl)
+      && DECL_BUILT_IN_CLASS (fundecl) == BUILT_IN_NORMAL)
+    {
+      built_in_function code = DECL_FUNCTION_CODE (fundecl);
+      if (C_DECL_BUILTIN_PROTOTYPE (fundecl))
+       {
+         if (tree bdecl = builtin_decl_implicit (code))
+           builtin_typelist = TYPE_ARG_TYPES (TREE_TYPE (bdecl));
+       }
+
+      /* For type-generic built-in functions, determine whether excess
+        precision should be removed (classification) or not
+        (comparison).  */
+      if (type_generic)
+       switch (code)
+         {
+         case BUILT_IN_ISFINITE:
+         case BUILT_IN_ISINF:
+         case BUILT_IN_ISINF_SIGN:
+         case BUILT_IN_ISNAN:
+         case BUILT_IN_ISNORMAL:
+         case BUILT_IN_FPCLASSIFY:
+           type_generic_remove_excess_precision = true;
+           break;
+
+         case BUILT_IN_ADD_OVERFLOW_P:
+         case BUILT_IN_SUB_OVERFLOW_P:
+         case BUILT_IN_MUL_OVERFLOW_P:
+           /* The last argument of these type-generic builtins
+              should not be promoted.  */
+           type_generic_overflow_p = true;
+           break;
+
+         default:
+           break;
+         }
+    }
+
+  /* Scan the given expressions and types, producing individual
+     converted arguments.  */
+
+  tree typetail, builtin_typetail, val;
+  for (typetail = typelist,
+        builtin_typetail = builtin_typelist,
+        parmnum = 0;
+       values && values->iterate (parmnum, &val);
+       ++parmnum)
+    {
+      tree type = typetail ? TREE_VALUE (typetail) : NULL_TREE;
+      tree builtin_type = (builtin_typetail
+                          ? TREE_VALUE (builtin_typetail) : NULL_TREE);
+      tree valtype = TREE_TYPE (val);
+      tree rname = function;
+      int argnum = parmnum + 1;
+      const char *invalid_func_diag;
+      bool excess_precision = false;
+      tree parmval;
+      /* Some __atomic_* builtins have additional hidden argument at
+        position 0.  */
+      location_t ploc
+       = !arg_loc.is_empty () && values->length () == arg_loc.length ()
+         ? expansion_point_location_if_in_system_header (arg_loc[parmnum])
+         : input_location;
+
+      if (type == void_type_node)
+       {
+         if (selector)
+           error_at (loc, "too many arguments to method %qE", selector);
+         else
+           error_at (loc, "too many arguments to function %qE", function);
+         inform_declaration (fundecl);
+         return error_args ? -1 : (int) parmnum;
+       }
+
+      if (builtin_type == void_type_node)
+       {
+         warning_at (loc, OPT_Wbuiltin_declaration_mismatch,
+                     "too many arguments to built-in function %qE "
+                     "expecting %d",
+                     function, parmnum);
+
+         inform_declaration (fundecl);
+         builtin_typetail = NULL_TREE;
+       }
+
+      if (selector && argnum > 2)
+       {
+         rname = selector;
+         argnum -= 2;
+       }
+
+      /* If there is excess precision and a prototype, convert once to
+        the required type rather than converting via the semantic
+        type.  Likewise without a prototype a float value represented
+        as long double should be converted once to double.  But for
+        type-generic classification functions excess precision must
+        be removed here.  */
+      if (TREE_CODE (val) == EXCESS_PRECISION_EXPR
+         && (type || !type_generic || !type_generic_remove_excess_precision))
+       {
+         val = TREE_OPERAND (val, 0);
+         excess_precision = true;
+       }
+      val = c_fully_fold (val, false, NULL);
+      STRIP_TYPE_NOPS (val);
+
+      val = require_complete_type (ploc, val);
+
+      /* Some floating-point arguments must be promoted to double when
+        no type is specified by a prototype.  This applies to
+        arguments of type float, and to architecture-specific types
+        (ARM __fp16), but not to _FloatN or _FloatNx types.  */
+      bool promote_float_arg = false;
+      if (type == NULL_TREE
+         && TREE_CODE (valtype) == REAL_TYPE
+         && (TYPE_PRECISION (valtype)
+             <= TYPE_PRECISION (double_type_node))
+         && TYPE_MAIN_VARIANT (valtype) != double_type_node
+         && TYPE_MAIN_VARIANT (valtype) != long_double_type_node
+         && !DECIMAL_FLOAT_MODE_P (TYPE_MODE (valtype)))
+       {
+         /* Promote this argument, unless it has a _FloatN or
+            _FloatNx type.  */
+         promote_float_arg = true;
+         for (int i = 0; i < NUM_FLOATN_NX_TYPES; i++)
+           if (TYPE_MAIN_VARIANT (valtype) == FLOATN_NX_TYPE_NODE (i))
+             {
+               promote_float_arg = false;
+               break;
+             }
+       }
+
+      if (type != NULL_TREE)
+       {
+         tree origtype = (!origtypes) ? NULL_TREE : (*origtypes)[parmnum];
+         parmval = convert_argument (ploc, function, fundecl, type, origtype,
+                                     val, rname, parmnum, argnum,
+                                     excess_precision, 0);
        }
       else if (promote_float_arg)
         {
@@ -3544,8 +3590,24 @@ convert_arguments (location_t loc, vec<location_t> 
arg_loc, tree typelist,
       if (parmval == error_mark_node)
        error_args = true;
 
+      if (!type && builtin_type && TREE_CODE (builtin_type) != VOID_TYPE)
+       {
+         /* For a call to a built-in function declared without a prototype,
+            perform the coversions from the argument to the expected type
+            but issue warnings rather than errors for any mismatches.
+            Ignore the converted argument and use the PARMVAL obtained
+            above by applying default coversions instead.  */
+         tree origtype = (!origtypes) ? NULL_TREE : (*origtypes)[parmnum];
+         convert_argument (ploc, function, fundecl, builtin_type, origtype,
+                           val, rname, parmnum, argnum, excess_precision,
+                           OPT_Wbuiltin_declaration_mismatch);
+       }
+
       if (typetail)
        typetail = TREE_CHAIN (typetail);
+
+      if (builtin_typetail)
+       builtin_typetail = TREE_CHAIN (builtin_typetail);
     }
 
   gcc_assert (parmnum == vec_safe_length (values));
@@ -3557,6 +3619,18 @@ convert_arguments (location_t loc, vec<location_t> 
arg_loc, tree typelist,
       return -1;
     }
 
+  if (builtin_typetail && TREE_VALUE (builtin_typetail) != void_type_node)
+    {
+      unsigned nargs = parmnum;
+      for (tree t = builtin_typetail; t; t = TREE_CHAIN (t))
+       ++nargs;
+
+      warning_at (loc, OPT_Wbuiltin_declaration_mismatch,
+                 "too few arguments to built-in function %qE expecting %u",
+                 function, nargs - 1);
+      inform_declaration (fundecl);
+    }
+
   return error_args ? -1 : (int) parmnum;
 }
 
@@ -6328,13 +6402,16 @@ inform_for_arg (tree fundecl, location_t ploc, int 
parmnum,
            ^
 
    FUNCTION is a tree for the function being called.
-   PARMNUM is the number of the argument, for printing in error messages.  */
+   PARMNUM is the number of the argument, for printing in error messages.
+   WARNOPT may be set to a warning option to issue the corresponding warning
+   rather than an error for invalid conversions.  Used for calls to built-in
+   functions declared without a prototype.  */
 
 static tree
 convert_for_assignment (location_t location, location_t expr_loc, tree type,
                        tree rhs, tree origtype, enum impl_conv errtype,
                        bool null_pointer_constant, tree fundecl,
-                       tree function, int parmnum)
+                       tree function, int parmnum, int warnopt /* = 0 */)
 {
   enum tree_code codel = TREE_CODE (type);
   tree orig_rhs = rhs;
@@ -6523,7 +6600,11 @@ convert_for_assignment (location_t location, location_t 
expr_loc, tree type,
         an unprototyped function, it is compile-time undefined;
         making it a constraint in that case was rejected in
         DR#252.  */
-      error_at (location, "void value not ignored as it ought to be");
+      const char msg[] = "void value not ignored as it ought to be";
+      if (warnopt)
+       warning_at (location, warnopt, msg);
+      else
+       error_at (location, msg);
       return error_mark_node;
     }
   rhs = require_complete_type (location, rhs);
@@ -6539,7 +6620,11 @@ convert_for_assignment (location_t location, location_t 
expr_loc, tree type,
     {
       if (!lvalue_p (rhs))
        {
-         error_at (location, "cannot pass rvalue to reference parameter");
+         const char msg[] = "cannot pass rvalue to reference parameter";
+         if (warnopt)
+           warning_at (location, warnopt, msg);
+         else
+           error_at (location, msg);
          return error_mark_node;
        }
       if (!c_mark_addressable (rhs))
@@ -6551,7 +6636,7 @@ convert_for_assignment (location_t location, location_t 
expr_loc, tree type,
                                    build_pointer_type (TREE_TYPE (type)),
                                    rhs, origtype, errtype,
                                    null_pointer_constant, fundecl, function,
-                                   parmnum);
+                                   parmnum, warnopt);
       if (rhs == error_mark_node)
        return error_mark_node;
 
@@ -6778,21 +6863,45 @@ convert_for_assignment (location_t location, location_t 
expr_loc, tree type,
          switch (errtype)
            {
            case ic_argpass:
-             error_at (expr_loc, "passing argument %d of %qE from pointer to "
-                       "non-enclosed address space", parmnum, rname);
+             {
+               const char msg[] = G_("passing argument %d of %qE from "
+                                     "pointer to non-enclosed address space");
+               if (warnopt)
+                 warning_at (expr_loc, warnopt, msg, parmnum, rname);
+               else
+                 error_at (expr_loc, msg, parmnum, rname);
              break;
+             }
            case ic_assign:
-             error_at (location, "assignment from pointer to "
+             {
+               const char msg[] = G_("assignment from pointer to "
                                      "non-enclosed address space");
+               if (warnopt)
+                 warning_at (location, warnopt, msg);
+               else
+                 error_at (location, msg);
                break;
+             }
            case ic_init:
-             error_at (location, "initialization from pointer to "
+             {
+               const char msg[] = G_("initialization from pointer to "
                                      "non-enclosed address space");
+               if (warnopt)
+                 warning_at (location, warnopt, msg);
+               else
+                 error_at (location, msg);
                break;
+             }
            case ic_return:
-             error_at (location, "return from pointer to "
+             {
+               const char msg[] = G_("return from pointer to "
                                      "non-enclosed address space");
+               if (warnopt)
+                 warning_at (location, warnopt, msg);
+               else
+                 error_at (location, msg);
                break;
+             }
            default:
              gcc_unreachable ();
            }
@@ -7007,7 +7116,11 @@ convert_for_assignment (location_t location, location_t 
expr_loc, tree type,
     {
       /* ??? This should not be an error when inlining calls to
         unprototyped functions.  */
-      error_at (location, "invalid use of non-lvalue array");
+      const char msg[] = "invalid use of non-lvalue array";
+      if (warnopt)
+       warning_at (location, warnopt, msg);
+      else
+       error_at (location, msg);
       return error_mark_node;
     }
   else if (codel == POINTER_TYPE && coder == INTEGER_TYPE)
@@ -7089,24 +7202,45 @@ convert_for_assignment (location_t location, location_t 
expr_loc, tree type,
   switch (errtype)
     {
     case ic_argpass:
-      error_at (expr_loc, "incompatible type for argument %d of %qE", parmnum,
-               rname);
+      {
+       const char msg[] = G_("incompatible type for argument %d of %qE");
+       if (warnopt)
+         warning_at (expr_loc, 0, msg, parmnum, rname);
+       else
+         error_at (expr_loc, msg, parmnum, rname);
        inform_for_arg (fundecl, expr_loc, parmnum, type, rhstype);
        break;
+      }
     case ic_assign:
-      error_at (location, "incompatible types when assigning to type %qT from "
-               "type %qT", type, rhstype);
+      {
+       const char msg[]
+         = G_("incompatible types when assigning to type %qT from type %qT");
+       if (warnopt)
+         warning_at (expr_loc, 0, msg, type, rhstype);
+       else
+         error_at (expr_loc, msg, type, rhstype);
        break;
+      }
     case ic_init:
-      error_at (location,
-               "incompatible types when initializing type %qT using type %qT",
-               type, rhstype);
+      {
+       const char msg[]
+         = G_("incompatible types when initializing type %qT using type %qT");
+       if (warnopt)
+         warning_at (location, 0, msg, type, rhstype);
+       else
+         error_at (location, msg, type, rhstype);
        break;
+      }
     case ic_return:
-      error_at (location,
-               "incompatible types when returning type %qT but %qT was "
-               "expected", rhstype, type);
+      {
+       const char msg[]
+         = G_("incompatible types when returning type %qT but %qT was 
expected");
+       if (warnopt)
+         warning_at (location, 0, msg, rhstype, type);
+       else
+         error_at (location, msg, rhstype, type);
        break;
+      }
     default:
       gcc_unreachable ();
     }
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index df4c55f..ad7c067 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -6569,7 +6569,12 @@ attributes.
 @opindex Wno-builtin-declaration-mismatch
 @opindex Wbuiltin-declaration-mismatch
 Warn if a built-in function is declared with the wrong signature or
-as non-function.
+as non-function.  Also warn when a built-in function that takes arguments
+is declared without a prototype, and for calls to built-in functions
+declared ithout a prototype made with the wrong number of arguments or
+with arguments with incompatible types.  When @option{-Wextra} is used
+declarations without a prototype of built-in functions that take no
+arguments are diagnosed as well.
 This warning is enabled by default.
 
 @item -Wno-builtin-macro-redefined
PR c/83656 - missing -Wbuiltin-declaration-mismatch on declaration without prototype

gcc/c/ChangeLog:

	PR c/83656
	* c-decl.c (diagnose_mismatched_decls): Diagnose declarations of
	built-in functions without a prototype.
	* c-typeck.c (convert_argument): New function.
	(convert_arguments): Factor code out into convert_argument.
	Detect mismatches between built-in formal arguments in calls
	to built-in without prototype.
	(convert_for_assignment): Add argument.  Conditionally issue
	warnings instead of errors for mismatches.

gcc/testsuite/ChangeLog:

	PR c/83656
	* gcc.dg/Wbuiltin-declaration-mismatch-5.c: New test.
	* gcc.dg/Wbuiltin-declaration-mismatch-6.c: New test.
	* gcc.dg/Walloca-16.c: Adjust.
	* gcc.dg/Wrestrict-4.c: Adjust.
	* gcc.dg/Wrestrict-5.c: Adjust.
	* gcc.dg/pr15698-1.c: Adjust.
	* gcc.dg/pr83463.c: Adjust.
	* gcc.dg/redecl-4.c: Adjust.
	* gcc.dg/torture/pr55890-2.c: Adjust.
	* gcc.dg/torture/pr55890-3.c: Adjust.
	* gcc.dg/torture/pr67741.c: Adjust.
	* gcc.dg/torture/stackalign/sibcall-1.c: Adjust.

diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index af16cfd..07beaa1 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -1886,8 +1886,9 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
 		 built-in.  No point in calling locate_old_decl here, it
 		 won't print anything.  */
 	      warning (OPT_Wbuiltin_declaration_mismatch,
-		       "conflicting types for built-in function %q+D",
-		       newdecl);
+		       "conflicting types for built-in function %q+D; "
+		       "expected %qT",
+		       newdecl, oldtype);
 	      return false;
 	    }
 	}
@@ -2021,15 +2022,33 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
 	 can't validate the argument list) the built-in definition is
 	 overridden, but optionally warn this was a bad choice of name.  */
       if (DECL_BUILT_IN (olddecl)
-	  && !C_DECL_DECLARED_BUILTIN (olddecl)
-	  && (!TREE_PUBLIC (newdecl)
-	      || (DECL_INITIAL (newdecl)
-		  && !prototype_p (TREE_TYPE (newdecl)))))
+	  && !C_DECL_DECLARED_BUILTIN (olddecl))
 	{
-	  warning (OPT_Wshadow, "declaration of %q+D shadows "
-		   "a built-in function", newdecl);
-	  /* Discard the old built-in function.  */
-	  return false;
+	  if (!TREE_PUBLIC (newdecl)
+	      || (DECL_INITIAL (newdecl)
+		  && !prototype_p (TREE_TYPE (newdecl))))
+	    {
+	      warning_at (DECL_SOURCE_LOCATION (newdecl),
+			  OPT_Wshadow, "declaration of %qD shadows "
+			  "a built-in function", newdecl);
+	      /* Discard the old built-in function.  */
+	      return false;
+	    }
+
+	  if (!prototype_p (TREE_TYPE (newdecl)))
+	    {
+	      /* Set for built-ins that take no arguments.  */
+	      bool func_void_args = false;
+	      if (tree at = TYPE_ARG_TYPES (oldtype))
+		func_void_args = VOID_TYPE_P (TREE_VALUE (at));
+
+	      if (extra_warnings || !func_void_args)
+		warning_at (DECL_SOURCE_LOCATION (newdecl),
+			    OPT_Wbuiltin_declaration_mismatch,
+			    "declaration of built-in function %qD without "
+			    "a prototype; expected %qT",
+			    newdecl, TREE_TYPE (olddecl));
+	    }
 	}
 
       if (DECL_INITIAL (newdecl))
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 90ae306..e0584b9 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -97,7 +97,8 @@ static int convert_arguments (location_t, vec<location_t>, tree,
 			      tree);
 static tree pointer_diff (location_t, tree, tree, tree *);
 static tree convert_for_assignment (location_t, location_t, tree, tree, tree,
-				    enum impl_conv, bool, tree, tree, int);
+				    enum impl_conv, bool, tree, tree, int,
+				    int = 0);
 static tree valid_compound_expr_initializer (tree, tree);
 static void push_string (const char *);
 static void push_member_name (tree);
@@ -3179,6 +3180,189 @@ c_build_function_call_vec (location_t loc, vec<location_t> arg_loc,
   return build_function_call_vec (loc, arg_loc, function, params, origtypes);
 }
 
+/* Helper for convert_arguments called to convert the VALue of argument
+   number ARGNUM from ORIGTYPE to the corresponding parameter number
+   PARMNUL and TYPE.  */
+
+static tree
+convert_argument (location_t ploc, tree function, tree fundecl,
+		  tree type, tree origtype, tree val,
+		  tree rname, int parmnum, int argnum,
+		  bool excess_precision, int warnopt)
+{
+  tree valtype = TREE_TYPE (val);
+
+  tree parmval;
+
+  /* Formal parm type is specified by a function prototype.  */
+
+  if (type == error_mark_node || !COMPLETE_TYPE_P (type))
+    {
+      error_at (ploc, "type of formal parameter %d is incomplete",
+		parmnum + 1);
+      parmval = val;
+    }
+  else
+    {
+      /* Optionally warn about conversions that differ from the default
+	 conversions.  */
+      if (warn_traditional_conversion || warn_traditional)
+	{
+	  unsigned int formal_prec = TYPE_PRECISION (type);
+
+	  if (INTEGRAL_TYPE_P (type)
+	      && TREE_CODE (valtype) == REAL_TYPE)
+	    warning_at (ploc, OPT_Wtraditional_conversion,
+			"passing argument %d of %qE as integer rather "
+			"than floating due to prototype",
+			argnum, rname);
+	  if (INTEGRAL_TYPE_P (type)
+	      && TREE_CODE (valtype) == COMPLEX_TYPE)
+	    warning_at (ploc, OPT_Wtraditional_conversion,
+			"passing argument %d of %qE as integer rather "
+			"than complex due to prototype",
+			argnum, rname);
+	  else if (TREE_CODE (type) == COMPLEX_TYPE
+		   && TREE_CODE (valtype) == REAL_TYPE)
+	    warning_at (ploc, OPT_Wtraditional_conversion,
+			"passing argument %d of %qE as complex rather "
+			"than floating due to prototype",
+			argnum, rname);
+	  else if (TREE_CODE (type) == REAL_TYPE
+		   && INTEGRAL_TYPE_P (valtype))
+	    warning_at (ploc, OPT_Wtraditional_conversion,
+			"passing argument %d of %qE as floating rather "
+			"than integer due to prototype",
+			argnum, rname);
+	  else if (TREE_CODE (type) == COMPLEX_TYPE
+		   && INTEGRAL_TYPE_P (valtype))
+	    warning_at (ploc, OPT_Wtraditional_conversion,
+			"passing argument %d of %qE as complex rather "
+			"than integer due to prototype",
+			argnum, rname);
+	  else if (TREE_CODE (type) == REAL_TYPE
+		   && TREE_CODE (valtype) == COMPLEX_TYPE)
+	    warning_at (ploc, OPT_Wtraditional_conversion,
+			"passing argument %d of %qE as floating rather "
+			"than complex due to prototype",
+			argnum, rname);
+	  /* ??? At some point, messages should be written about
+	     conversions between complex types, but that's too messy
+	     to do now.  */
+	  else if (TREE_CODE (type) == REAL_TYPE
+		   && TREE_CODE (valtype) == REAL_TYPE)
+	    {
+	      /* Warn if any argument is passed as `float',
+		 since without a prototype it would be `double'.  */
+	      if (formal_prec == TYPE_PRECISION (float_type_node)
+		  && type != dfloat32_type_node)
+		warning_at (ploc, 0,
+			    "passing argument %d of %qE as %<float%> "
+			    "rather than %<double%> due to prototype",
+			    argnum, rname);
+
+	      /* Warn if mismatch between argument and prototype
+		 for decimal float types.  Warn of conversions with
+		 binary float types and of precision narrowing due to
+		 prototype. */
+	      else if (type != valtype
+		       && (type == dfloat32_type_node
+			   || type == dfloat64_type_node
+			   || type == dfloat128_type_node
+			   || valtype == dfloat32_type_node
+			   || valtype == dfloat64_type_node
+			   || valtype == dfloat128_type_node)
+		       && (formal_prec
+			   <= TYPE_PRECISION (valtype)
+			   || (type == dfloat128_type_node
+			       && (valtype
+				   != dfloat64_type_node
+				   && (valtype
+				       != dfloat32_type_node)))
+			   || (type == dfloat64_type_node
+			       && (valtype
+				   != dfloat32_type_node))))
+		warning_at (ploc, 0,
+			    "passing argument %d of %qE as %qT "
+			    "rather than %qT due to prototype",
+			    argnum, rname, type, valtype);
+
+	    }
+	  /* Detect integer changing in width or signedness.
+	     These warnings are only activated with
+	     -Wtraditional-conversion, not with -Wtraditional.  */
+	  else if (warn_traditional_conversion
+		   && INTEGRAL_TYPE_P (type)
+		   && INTEGRAL_TYPE_P (valtype))
+	    {
+	      tree would_have_been = default_conversion (val);
+	      tree type1 = TREE_TYPE (would_have_been);
+
+	      if (val == error_mark_node)
+		/* VAL could have been of incomplete type.  */;
+	      else if (TREE_CODE (type) == ENUMERAL_TYPE
+		       && (TYPE_MAIN_VARIANT (type)
+			   == TYPE_MAIN_VARIANT (valtype)))
+		/* No warning if function asks for enum
+		   and the actual arg is that enum type.  */
+		;
+	      else if (formal_prec != TYPE_PRECISION (type1))
+		warning_at (ploc, OPT_Wtraditional_conversion,
+			    "passing argument %d of %qE "
+			    "with different width due to prototype",
+			    argnum, rname);
+	      else if (TYPE_UNSIGNED (type) == TYPE_UNSIGNED (type1))
+		;
+	      /* Don't complain if the formal parameter type
+		 is an enum, because we can't tell now whether
+		 the value was an enum--even the same enum.  */
+	      else if (TREE_CODE (type) == ENUMERAL_TYPE)
+		;
+	      else if (TREE_CODE (val) == INTEGER_CST
+		       && int_fits_type_p (val, type))
+		/* Change in signedness doesn't matter
+		   if a constant value is unaffected.  */
+		;
+	      /* If the value is extended from a narrower
+		 unsigned type, it doesn't matter whether we
+		 pass it as signed or unsigned; the value
+		 certainly is the same either way.  */
+	      else if (TYPE_PRECISION (valtype) < TYPE_PRECISION (type)
+		       && TYPE_UNSIGNED (valtype))
+		;
+	      else if (TYPE_UNSIGNED (type))
+		warning_at (ploc, OPT_Wtraditional_conversion,
+			    "passing argument %d of %qE "
+			    "as unsigned due to prototype",
+			    argnum, rname);
+	      else
+		warning_at (ploc, OPT_Wtraditional_conversion,
+			    "passing argument %d of %qE "
+			    "as signed due to prototype",
+			    argnum, rname);
+	    }
+	}
+
+      /* Possibly restore an EXCESS_PRECISION_EXPR for the
+	 sake of better warnings from convert_and_check.  */
+      if (excess_precision)
+	val = build1 (EXCESS_PRECISION_EXPR, valtype, val);
+
+      parmval = convert_for_assignment (ploc, ploc, type,
+					val, origtype, ic_argpass,
+					null_pointer_constant_p (val),
+					fundecl, function,
+					parmnum + 1, warnopt);
+
+      if (targetm.calls.promote_prototypes (fundecl ? TREE_TYPE (fundecl) : 0)
+	  && INTEGRAL_TYPE_P (type)
+	  && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
+	parmval = default_conversion (parmval);
+    }
+
+  return parmval;
+}
+
 /* Convert the argument expressions in the vector VALUES
    to the types in the list TYPELIST.
 
@@ -3205,7 +3389,6 @@ convert_arguments (location_t loc, vec<location_t> arg_loc, tree typelist,
 		   vec<tree, va_gc> *values, vec<tree, va_gc> *origtypes,
 		   tree function, tree fundecl)
 {
-  tree typetail, val;
   unsigned int parmnum;
   bool error_args = false;
   const bool type_generic = fundecl
@@ -3223,51 +3406,67 @@ convert_arguments (location_t loc, vec<location_t> arg_loc, tree typelist,
   /* Handle an ObjC selector specially for diagnostics.  */
   selector = objc_message_selector ();
 
-  /* For type-generic built-in functions, determine whether excess
-     precision should be removed (classification) or not
-     (comparison).  */
-  if (type_generic
+  /* For a call to a built-in function declared without a prototype,
+     set to the built-in function's argument list.  */
+  tree builtin_typelist = NULL_TREE;
+
+  if (fundecl
       && DECL_BUILT_IN (fundecl)
       && DECL_BUILT_IN_CLASS (fundecl) == BUILT_IN_NORMAL)
     {
-      switch (DECL_FUNCTION_CODE (fundecl))
+      built_in_function code = DECL_FUNCTION_CODE (fundecl);
+      if (C_DECL_BUILTIN_PROTOTYPE (fundecl))
 	{
-	case BUILT_IN_ISFINITE:
-	case BUILT_IN_ISINF:
-	case BUILT_IN_ISINF_SIGN:
-	case BUILT_IN_ISNAN:
-	case BUILT_IN_ISNORMAL:
-	case BUILT_IN_FPCLASSIFY:
-	  type_generic_remove_excess_precision = true;
-	  break;
+	  if (tree bdecl = builtin_decl_implicit (code))
+	    builtin_typelist = TYPE_ARG_TYPES (TREE_TYPE (bdecl));
+	}
 
-	case BUILT_IN_ADD_OVERFLOW_P:
-	case BUILT_IN_SUB_OVERFLOW_P:
-	case BUILT_IN_MUL_OVERFLOW_P:
-	  /* The last argument of these type-generic builtins
-	     should not be promoted.  */
-	  type_generic_overflow_p = true;
-	  break;
+      /* For type-generic built-in functions, determine whether excess
+	 precision should be removed (classification) or not
+	 (comparison).  */
+      if (type_generic)
+	switch (code)
+	  {
+	  case BUILT_IN_ISFINITE:
+	  case BUILT_IN_ISINF:
+	  case BUILT_IN_ISINF_SIGN:
+	  case BUILT_IN_ISNAN:
+	  case BUILT_IN_ISNORMAL:
+	  case BUILT_IN_FPCLASSIFY:
+	    type_generic_remove_excess_precision = true;
+	    break;
 
-	default:
-	  break;
-	}
+	  case BUILT_IN_ADD_OVERFLOW_P:
+	  case BUILT_IN_SUB_OVERFLOW_P:
+	  case BUILT_IN_MUL_OVERFLOW_P:
+	    /* The last argument of these type-generic builtins
+	       should not be promoted.  */
+	    type_generic_overflow_p = true;
+	    break;
+
+	  default:
+	    break;
+	  }
     }
 
   /* Scan the given expressions and types, producing individual
      converted arguments.  */
 
-  for (typetail = typelist, parmnum = 0;
+  tree typetail, builtin_typetail, val;
+  for (typetail = typelist,
+	 builtin_typetail = builtin_typelist,
+	 parmnum = 0;
        values && values->iterate (parmnum, &val);
        ++parmnum)
     {
-      tree type = typetail ? TREE_VALUE (typetail) : 0;
+      tree type = typetail ? TREE_VALUE (typetail) : NULL_TREE;
+      tree builtin_type = (builtin_typetail
+			   ? TREE_VALUE (builtin_typetail) : NULL_TREE);
       tree valtype = TREE_TYPE (val);
       tree rname = function;
       int argnum = parmnum + 1;
       const char *invalid_func_diag;
       bool excess_precision = false;
-      bool npc;
       tree parmval;
       /* Some __atomic_* builtins have additional hidden argument at
 	 position 0.  */
@@ -3286,14 +3485,23 @@ convert_arguments (location_t loc, vec<location_t> arg_loc, tree typelist,
 	  return error_args ? -1 : (int) parmnum;
 	}
 
+      if (builtin_type == void_type_node)
+	{
+	  warning_at (loc, OPT_Wbuiltin_declaration_mismatch,
+		      "too many arguments to built-in function %qE "
+		      "expecting %d",
+		      function, parmnum);
+
+	  inform_declaration (fundecl);
+	  builtin_typetail = NULL_TREE;
+	}
+
       if (selector && argnum > 2)
 	{
 	  rname = selector;
 	  argnum -= 2;
 	}
 
-      npc = null_pointer_constant_p (val);
-
       /* If there is excess precision and a prototype, convert once to
 	 the required type rather than converting via the semantic
 	 type.  Likewise without a prototype a float value represented
@@ -3337,172 +3545,10 @@ convert_arguments (location_t loc, vec<location_t> arg_loc, tree typelist,
 
       if (type != NULL_TREE)
 	{
-	  /* Formal parm type is specified by a function prototype.  */
-
-	  if (type == error_mark_node || !COMPLETE_TYPE_P (type))
-	    {
-	      error_at (ploc, "type of formal parameter %d is incomplete",
-			parmnum + 1);
-	      parmval = val;
-	    }
-	  else
-	    {
-	      tree origtype;
-
-	      /* Optionally warn about conversions that
-		 differ from the default conversions.  */
-	      if (warn_traditional_conversion || warn_traditional)
-		{
-		  unsigned int formal_prec = TYPE_PRECISION (type);
-
-		  if (INTEGRAL_TYPE_P (type)
-		      && TREE_CODE (valtype) == REAL_TYPE)
-		    warning_at (ploc, OPT_Wtraditional_conversion,
-				"passing argument %d of %qE as integer rather "
-				"than floating due to prototype",
-				argnum, rname);
-		  if (INTEGRAL_TYPE_P (type)
-		      && TREE_CODE (valtype) == COMPLEX_TYPE)
-		    warning_at (ploc, OPT_Wtraditional_conversion,
-				"passing argument %d of %qE as integer rather "
-				"than complex due to prototype",
-				argnum, rname);
-		  else if (TREE_CODE (type) == COMPLEX_TYPE
-			   && TREE_CODE (valtype) == REAL_TYPE)
-		    warning_at (ploc, OPT_Wtraditional_conversion,
-				"passing argument %d of %qE as complex rather "
-				"than floating due to prototype",
-				argnum, rname);
-		  else if (TREE_CODE (type) == REAL_TYPE
-			   && INTEGRAL_TYPE_P (valtype))
-		    warning_at (ploc, OPT_Wtraditional_conversion,
-				"passing argument %d of %qE as floating rather "
-				"than integer due to prototype",
-				argnum, rname);
-		  else if (TREE_CODE (type) == COMPLEX_TYPE
-			   && INTEGRAL_TYPE_P (valtype))
-		    warning_at (ploc, OPT_Wtraditional_conversion,
-				"passing argument %d of %qE as complex rather "
-				"than integer due to prototype",
-				argnum, rname);
-		  else if (TREE_CODE (type) == REAL_TYPE
-			   && TREE_CODE (valtype) == COMPLEX_TYPE)
-		    warning_at (ploc, OPT_Wtraditional_conversion,
-				"passing argument %d of %qE as floating rather "
-				"than complex due to prototype",
-				argnum, rname);
-		  /* ??? At some point, messages should be written about
-		     conversions between complex types, but that's too messy
-		     to do now.  */
-		  else if (TREE_CODE (type) == REAL_TYPE
-			   && TREE_CODE (valtype) == REAL_TYPE)
-		    {
-		      /* Warn if any argument is passed as `float',
-			 since without a prototype it would be `double'.  */
-		      if (formal_prec == TYPE_PRECISION (float_type_node)
-			  && type != dfloat32_type_node)
-			warning_at (ploc, 0,
-				    "passing argument %d of %qE as %<float%> "
-				    "rather than %<double%> due to prototype",
-				    argnum, rname);
-
-		      /* Warn if mismatch between argument and prototype
-			 for decimal float types.  Warn of conversions with
-			 binary float types and of precision narrowing due to
-			 prototype. */
- 		      else if (type != valtype
-			       && (type == dfloat32_type_node
-				   || type == dfloat64_type_node
-				   || type == dfloat128_type_node
-				   || valtype == dfloat32_type_node
-				   || valtype == dfloat64_type_node
-				   || valtype == dfloat128_type_node)
-			       && (formal_prec
-				   <= TYPE_PRECISION (valtype)
-				   || (type == dfloat128_type_node
-				       && (valtype
-					   != dfloat64_type_node
-					   && (valtype
-					       != dfloat32_type_node)))
-				   || (type == dfloat64_type_node
-				       && (valtype
-					   != dfloat32_type_node))))
-			warning_at (ploc, 0,
-				    "passing argument %d of %qE as %qT "
-				    "rather than %qT due to prototype",
-				    argnum, rname, type, valtype);
-
-		    }
-		  /* Detect integer changing in width or signedness.
-		     These warnings are only activated with
-		     -Wtraditional-conversion, not with -Wtraditional.  */
-		  else if (warn_traditional_conversion
-			   && INTEGRAL_TYPE_P (type)
-			   && INTEGRAL_TYPE_P (valtype))
-		    {
-		      tree would_have_been = default_conversion (val);
-		      tree type1 = TREE_TYPE (would_have_been);
-
-		      if (val == error_mark_node)
-			/* VAL could have been of incomplete type.  */;
-		      else if (TREE_CODE (type) == ENUMERAL_TYPE
-			       && (TYPE_MAIN_VARIANT (type)
-				   == TYPE_MAIN_VARIANT (valtype)))
-			/* No warning if function asks for enum
-			   and the actual arg is that enum type.  */
-			;
-		      else if (formal_prec != TYPE_PRECISION (type1))
-			warning_at (ploc, OPT_Wtraditional_conversion,
-				    "passing argument %d of %qE "
-				    "with different width due to prototype",
-				    argnum, rname);
-		      else if (TYPE_UNSIGNED (type) == TYPE_UNSIGNED (type1))
-			;
-		      /* Don't complain if the formal parameter type
-			 is an enum, because we can't tell now whether
-			 the value was an enum--even the same enum.  */
-		      else if (TREE_CODE (type) == ENUMERAL_TYPE)
-			;
-		      else if (TREE_CODE (val) == INTEGER_CST
-			       && int_fits_type_p (val, type))
-			/* Change in signedness doesn't matter
-			   if a constant value is unaffected.  */
-			;
-		      /* If the value is extended from a narrower
-			 unsigned type, it doesn't matter whether we
-			 pass it as signed or unsigned; the value
-			 certainly is the same either way.  */
-		      else if (TYPE_PRECISION (valtype) < TYPE_PRECISION (type)
-			       && TYPE_UNSIGNED (valtype))
-			;
-		      else if (TYPE_UNSIGNED (type))
-			warning_at (ploc, OPT_Wtraditional_conversion,
-				    "passing argument %d of %qE "
-				    "as unsigned due to prototype",
-				    argnum, rname);
-		      else
-			warning_at (ploc, OPT_Wtraditional_conversion,
-				    "passing argument %d of %qE "
-				    "as signed due to prototype",
-				    argnum, rname);
-		    }
-		}
-
-	      /* Possibly restore an EXCESS_PRECISION_EXPR for the
-		 sake of better warnings from convert_and_check.  */
-	      if (excess_precision)
-		val = build1 (EXCESS_PRECISION_EXPR, valtype, val);
-	      origtype = (!origtypes) ? NULL_TREE : (*origtypes)[parmnum];
-	      parmval = convert_for_assignment (loc, ploc, type,
-						val, origtype, ic_argpass,
-						npc, fundecl, function,
-						parmnum + 1);
-
-	      if (targetm.calls.promote_prototypes (fundecl ? TREE_TYPE (fundecl) : 0)
-		  && INTEGRAL_TYPE_P (type)
-		  && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
-		parmval = default_conversion (parmval);
-	    }
+	  tree origtype = (!origtypes) ? NULL_TREE : (*origtypes)[parmnum];
+	  parmval = convert_argument (ploc, function, fundecl, type, origtype,
+				      val, rname, parmnum, argnum,
+				      excess_precision, 0);
 	}
       else if (promote_float_arg)
         {
@@ -3544,8 +3590,24 @@ convert_arguments (location_t loc, vec<location_t> arg_loc, tree typelist,
       if (parmval == error_mark_node)
 	error_args = true;
 
+      if (!type && builtin_type && TREE_CODE (builtin_type) != VOID_TYPE)
+	{
+	  /* For a call to a built-in function declared without a prototype,
+	     perform the coversions from the argument to the expected type
+	     but issue warnings rather than errors for any mismatches.
+	     Ignore the converted argument and use the PARMVAL obtained
+	     above by applying default coversions instead.  */
+	  tree origtype = (!origtypes) ? NULL_TREE : (*origtypes)[parmnum];
+	  convert_argument (ploc, function, fundecl, builtin_type, origtype,
+			    val, rname, parmnum, argnum, excess_precision,
+			    OPT_Wbuiltin_declaration_mismatch);
+	}
+
       if (typetail)
 	typetail = TREE_CHAIN (typetail);
+
+      if (builtin_typetail)
+	builtin_typetail = TREE_CHAIN (builtin_typetail);
     }
 
   gcc_assert (parmnum == vec_safe_length (values));
@@ -3557,6 +3619,18 @@ convert_arguments (location_t loc, vec<location_t> arg_loc, tree typelist,
       return -1;
     }
 
+  if (builtin_typetail && TREE_VALUE (builtin_typetail) != void_type_node)
+    {
+      unsigned nargs = parmnum;
+      for (tree t = builtin_typetail; t; t = TREE_CHAIN (t))
+	++nargs;
+
+      warning_at (loc, OPT_Wbuiltin_declaration_mismatch,
+		  "too few arguments to built-in function %qE expecting %u",
+		  function, nargs - 1);
+      inform_declaration (fundecl);
+    }
+
   return error_args ? -1 : (int) parmnum;
 }
 
@@ -6328,13 +6402,16 @@ inform_for_arg (tree fundecl, location_t ploc, int parmnum,
 	    ^
 
    FUNCTION is a tree for the function being called.
-   PARMNUM is the number of the argument, for printing in error messages.  */
+   PARMNUM is the number of the argument, for printing in error messages.
+   WARNOPT may be set to a warning option to issue the corresponding warning
+   rather than an error for invalid conversions.  Used for calls to built-in
+   functions declared without a prototype.  */
 
 static tree
 convert_for_assignment (location_t location, location_t expr_loc, tree type,
 			tree rhs, tree origtype, enum impl_conv errtype,
 			bool null_pointer_constant, tree fundecl,
-			tree function, int parmnum)
+			tree function, int parmnum, int warnopt /* = 0 */)
 {
   enum tree_code codel = TREE_CODE (type);
   tree orig_rhs = rhs;
@@ -6523,7 +6600,11 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
 	 an unprototyped function, it is compile-time undefined;
 	 making it a constraint in that case was rejected in
 	 DR#252.  */
-      error_at (location, "void value not ignored as it ought to be");
+      const char msg[] = "void value not ignored as it ought to be";
+      if (warnopt)
+	warning_at (location, warnopt, msg);
+      else
+	error_at (location, msg);
       return error_mark_node;
     }
   rhs = require_complete_type (location, rhs);
@@ -6539,7 +6620,11 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
     {
       if (!lvalue_p (rhs))
 	{
-	  error_at (location, "cannot pass rvalue to reference parameter");
+	  const char msg[] = "cannot pass rvalue to reference parameter";
+	  if (warnopt)
+	    warning_at (location, warnopt, msg);
+	  else
+	    error_at (location, msg);
 	  return error_mark_node;
 	}
       if (!c_mark_addressable (rhs))
@@ -6551,7 +6636,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
 				    build_pointer_type (TREE_TYPE (type)),
 				    rhs, origtype, errtype,
 				    null_pointer_constant, fundecl, function,
-				    parmnum);
+				    parmnum, warnopt);
       if (rhs == error_mark_node)
 	return error_mark_node;
 
@@ -6778,21 +6863,45 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
 	  switch (errtype)
 	    {
 	    case ic_argpass:
-	      error_at (expr_loc, "passing argument %d of %qE from pointer to "
-			"non-enclosed address space", parmnum, rname);
+	      {
+		const char msg[] = G_("passing argument %d of %qE from "
+				      "pointer to non-enclosed address space");
+		if (warnopt)
+		  warning_at (expr_loc, warnopt, msg, parmnum, rname);
+		else
+		  error_at (expr_loc, msg, parmnum, rname);
 	      break;
+	      }
 	    case ic_assign:
-	      error_at (location, "assignment from pointer to "
-			"non-enclosed address space");
-	      break;
+	      {
+		const char msg[] = G_("assignment from pointer to "
+				      "non-enclosed address space");
+		if (warnopt)
+		  warning_at (location, warnopt, msg);
+		else
+		  error_at (location, msg);
+		break;
+	      }
 	    case ic_init:
-	      error_at (location, "initialization from pointer to "
-			"non-enclosed address space");
-	      break;
+	      {
+		const char msg[] = G_("initialization from pointer to "
+				      "non-enclosed address space");
+		if (warnopt)
+		  warning_at (location, warnopt, msg);
+		else
+		  error_at (location, msg);
+		break;
+	      }
 	    case ic_return:
-	      error_at (location, "return from pointer to "
-			"non-enclosed address space");
-	      break;
+	      {
+		const char msg[] = G_("return from pointer to "
+				      "non-enclosed address space");
+		if (warnopt)
+		  warning_at (location, warnopt, msg);
+		else
+		  error_at (location, msg);
+		break;
+	      }
 	    default:
 	      gcc_unreachable ();
 	    }
@@ -7007,7 +7116,11 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
     {
       /* ??? This should not be an error when inlining calls to
 	 unprototyped functions.  */
-      error_at (location, "invalid use of non-lvalue array");
+      const char msg[] = "invalid use of non-lvalue array";
+      if (warnopt)
+	warning_at (location, warnopt, msg);
+      else
+	error_at (location, msg);
       return error_mark_node;
     }
   else if (codel == POINTER_TYPE && coder == INTEGER_TYPE)
@@ -7089,24 +7202,45 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
   switch (errtype)
     {
     case ic_argpass:
-      error_at (expr_loc, "incompatible type for argument %d of %qE", parmnum,
-		rname);
-      inform_for_arg (fundecl, expr_loc, parmnum, type, rhstype);
-      break;
+      {
+	const char msg[] = G_("incompatible type for argument %d of %qE");
+	if (warnopt)
+	  warning_at (expr_loc, 0, msg, parmnum, rname);
+	else
+	  error_at (expr_loc, msg, parmnum, rname);
+	inform_for_arg (fundecl, expr_loc, parmnum, type, rhstype);
+	break;
+      }
     case ic_assign:
-      error_at (location, "incompatible types when assigning to type %qT from "
-		"type %qT", type, rhstype);
-      break;
+      {
+	const char msg[]
+	  = G_("incompatible types when assigning to type %qT from type %qT");
+	if (warnopt)
+	  warning_at (expr_loc, 0, msg, type, rhstype);
+	else
+	  error_at (expr_loc, msg, type, rhstype);
+	break;
+      }
     case ic_init:
-      error_at (location,
-		"incompatible types when initializing type %qT using type %qT",
-		type, rhstype);
-      break;
+      {
+	const char msg[]
+	  = G_("incompatible types when initializing type %qT using type %qT");
+	if (warnopt)
+	  warning_at (location, 0, msg, type, rhstype);
+	else
+	  error_at (location, msg, type, rhstype);
+	break;
+      }
     case ic_return:
-      error_at (location,
-		"incompatible types when returning type %qT but %qT was "
-		"expected", rhstype, type);
-      break;
+      {
+	const char msg[]
+	  = G_("incompatible types when returning type %qT but %qT was expected");
+	if (warnopt)
+	  warning_at (location, 0, msg, rhstype, type);
+	else
+	  error_at (location, msg, rhstype, type);
+	break;
+      }
     default:
       gcc_unreachable ();
     }
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index df4c55f..ad7c067 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -6568,8 +6568,13 @@ attributes.
 @item -Wno-builtin-declaration-mismatch
 @opindex Wno-builtin-declaration-mismatch
 @opindex Wbuiltin-declaration-mismatch
-Warn if a built-in function is declared with the wrong signature or 
-as non-function.
+Warn if a built-in function is declared with the wrong signature or
+as non-function.  Also warn when a built-in function that takes arguments
+is declared without a prototype, and for calls to built-in functions
+declared ithout a prototype made with the wrong number of arguments or
+with arguments with incompatible types.  When @option{-Wextra} is used
+declarations without a prototype of built-in functions that take no
+arguments are diagnosed as well.
 This warning is enabled by default.
 
 @item -Wno-builtin-macro-redefined
diff --git a/gcc/testsuite/gcc.dg/Walloca-16.c b/gcc/testsuite/gcc.dg/Walloca-16.c
index 3ee96a9..866594c 100644
--- a/gcc/testsuite/gcc.dg/Walloca-16.c
+++ b/gcc/testsuite/gcc.dg/Walloca-16.c
@@ -4,3 +4,5 @@
 
 void *alloca ();
 __typeof__(alloca ()) a () { return alloca (); }
+
+/* { dg-prune-output "\\\[-Wbuiltin-declaration-mismatch]" } */
diff --git a/gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-5.c b/gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-5.c
new file mode 100644
index 0000000..d268215
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-5.c
@@ -0,0 +1,63 @@
+/* PR c/83656 - missing -Wbuiltin-declaration-mismatch on declaration
+   without prototype
+   { dg-do compile }
+   { dg-options "-Wbuiltin-declaration-mismatch" } */
+
+/* Verify that built-ins that take no arguments (i.e., abort) are
+   not diagnosed by default.  */
+void abort ();
+
+void exit ();       /* { dg-warning "declaration of built-in function .exit. without a prototype; expected .void\\\(int\\\)." } */
+
+void* memcpy ();    /* { dg-warning "declaration of built-in function .memcpy. without a prototype; expected .void \\\*\\\(void \\\*, const void \\\*, \(long \)?unsigned int\\\)." } */
+
+int strcmp ();      /* { dg-warning "declaration of built-in function .strcmp. without a prototype; expected .int\\\(const char* \\\*, const char \\\*\\\)." } */
+
+int strcpy ();      /* { dg-warning "conflicting types for built-in function .strcpy.; expected .char \\\*\\\(char \\\*, const char \\\*\\\)." } */
+
+
+void test_call_abort (void)
+{
+  /* Verify that a valid call to abort() is not diagnosed.  */
+  abort ();
+
+  abort (1);        /* { dg-warning "too many arguments to built-in function 'abort' expecting 0" } */
+
+  abort (1, 2);     /* { dg-warning "too many arguments" } */
+}
+
+
+void test_call_exit (void)
+{
+  /* Verify that a valid call to exit is not diagnosed.  */
+  exit (0);
+
+  exit ();          /* { dg-warning "too few arguments to built-in function 'exit' expecting 1" } */
+
+  exit (1, 2);      /* { dg-warning "too many arguments" } */
+
+  /* Verify that passing incompatible arguments is diagnosed by
+     a warning.  */
+  exit ("");        /* { dg-warning "\\\[-Wint-conversion]" } */
+
+  struct S { int i; } s = { 0 };
+  exit (s);         /* { dg-warning "incompatible type for argument 1" } */
+}
+
+
+void test_call_memcpy (void *p, const void *q, unsigned n)
+{
+  memcpy (p, q, n);
+
+  memcpy ();        /* { dg-warning "too few arguments to built-in function 'memcpy' expecting 3" } */
+
+  memcpy (p);       /* { dg-warning "too few arguments to built-in function 'memcpy' expecting 3" } */
+
+  memcpy (p, q);     /* { dg-warning "too few arguments to built-in function 'memcpy' expecting 3" } */
+
+  memcpy (q, p, n); /* { dg-warning "\\\[-Wdiscarded-qualifiers]" } */
+
+  memcpy (p, n, q); /* { dg-warning "\\\[-Wint-conversion]" } */
+
+  memcpy (p, q, n, 0); /* { dg-warning "too many arguments to built-in function 'memcpy' expecting 3" } */
+}
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
index 0000000..b66d6f4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wbuiltin-declaration-mismatch-6.c
@@ -0,0 +1,8 @@
+/* PR c/83656 - missing -Wbuiltin-declaration-mismatch on declaration
+   without prototype
+   { dg-do compile }
+   { dg-options "-Wbuiltin-declaration-mismatch -Wextra" } */
+
+/* Verify that with -Wextra, even declarations of built-ins that take
+   no arguments (i.e., abort) are diagnosed.  */
+void abort ();      /* { dg-warning "declaration of built-in function .abort. without a prototype; expected .void\\\(void\\\)." } */
diff --git a/gcc/testsuite/gcc.dg/Wrestrict-4.c b/gcc/testsuite/gcc.dg/Wrestrict-4.c
index f2398ef..55ea6c0 100644
--- a/gcc/testsuite/gcc.dg/Wrestrict-4.c
+++ b/gcc/testsuite/gcc.dg/Wrestrict-4.c
@@ -108,3 +108,5 @@ void* test_strncpy_2 (char *d, const char *s)
 {
   return strncpy (d, s);
 }
+
+/* { dg-prune-output "\\\[-Wbuiltin-declaration-mismatch]" } */
diff --git a/gcc/testsuite/gcc.dg/Wrestrict-5.c b/gcc/testsuite/gcc.dg/Wrestrict-5.c
index 4912ee5..7064e1e 100644
--- a/gcc/testsuite/gcc.dg/Wrestrict-5.c
+++ b/gcc/testsuite/gcc.dg/Wrestrict-5.c
@@ -41,3 +41,6 @@ void test_strncpy_nowarn (char *d)
 {
   strncpy (d + 1, d + 3, "");
 }
+
+/* { dg-prune-output "\\\[-Wbuiltin-declaration-mismatch]" }
+   { dg-prune-output "\\\[-Wint-conversion]" } */
diff --git a/gcc/testsuite/gcc.dg/pr15698-1.c b/gcc/testsuite/gcc.dg/pr15698-1.c
index 5a75a10..cbe613c 100644
--- a/gcc/testsuite/gcc.dg/pr15698-1.c
+++ b/gcc/testsuite/gcc.dg/pr15698-1.c
@@ -21,3 +21,5 @@ char *rindex(a, b)
 {
   return 0;
 }
+
+/* { dg-prune-output "\\\[-Wbuiltin-declaration-mismatch]" } */
diff --git a/gcc/testsuite/gcc.dg/pr83463.c b/gcc/testsuite/gcc.dg/pr83463.c
index ddf662f..cd11f64 100644
--- a/gcc/testsuite/gcc.dg/pr83463.c
+++ b/gcc/testsuite/gcc.dg/pr83463.c
@@ -15,3 +15,5 @@ p ()
 {
   m (p + (long) a);
 }
+
+/* { dg-prune-output "\\\[-Wbuiltin-declaration-mismatch]" } */
diff --git a/gcc/testsuite/gcc.dg/redecl-4.c b/gcc/testsuite/gcc.dg/redecl-4.c
index 2ba74a3..8f12488 100644
--- a/gcc/testsuite/gcc.dg/redecl-4.c
+++ b/gcc/testsuite/gcc.dg/redecl-4.c
@@ -27,3 +27,6 @@ f (void)
 
 /* Should still diagnose incompatible prototype for strcmp.  */
 int strcmp (void); /* { dg-error "conflict" } */
+
+/* { dg-prune-output "\\\[-Wbuiltin-declaration-mismatch]" }
+   { dg-prune-output "\\\[-Wint-conversion]" } */
diff --git a/gcc/testsuite/gcc.dg/torture/pr55890-2.c b/gcc/testsuite/gcc.dg/torture/pr55890-2.c
index 1cf71d7..31779e0 100644
--- a/gcc/testsuite/gcc.dg/torture/pr55890-2.c
+++ b/gcc/testsuite/gcc.dg/torture/pr55890-2.c
@@ -2,3 +2,5 @@
 
 extern void *memcpy();
 int main() { memcpy(); }
+
+/* { dg-prune-output "\\\[-Wbuiltin-declaration-mismatch]" } */
diff --git a/gcc/testsuite/gcc.dg/torture/pr55890-3.c b/gcc/testsuite/gcc.dg/torture/pr55890-3.c
index c7f77be..21a3d98 100644
--- a/gcc/testsuite/gcc.dg/torture/pr55890-3.c
+++ b/gcc/testsuite/gcc.dg/torture/pr55890-3.c
@@ -7,3 +7,5 @@ bar ()
 {
   return memmove ();
 }
+
+/* { dg-prune-output "\\\[-Wbuiltin-declaration-mismatch]" } */
diff --git a/gcc/testsuite/gcc.dg/torture/pr67741.c b/gcc/testsuite/gcc.dg/torture/pr67741.c
index 1ffc707..833e53e 100644
--- a/gcc/testsuite/gcc.dg/torture/pr67741.c
+++ b/gcc/testsuite/gcc.dg/torture/pr67741.c
@@ -3,11 +3,12 @@
 struct singlecomplex { float real, imag ; } ;
 struct doublecomplex { double real, imag ; } ;
 struct extendedcomplex { long double real, imag ; } ;
-extern double cabs();
+extern double cabs(); /* { dg-warning "\\\[-Wbuiltin-declaration-mismatch]" } */
 float cabsf(fc)
      struct singlecomplex fc;  /* { dg-warning "doesn't match" } */
 {
   struct doublecomplex dc ;
   dc.real=fc.real; dc.imag=fc.imag;
-  return (float) cabs(dc);
+  return (float) cabs(dc);   /* { dg-warning "incompatible type for argument 1 of .cabs." } */
 }
+
diff --git a/gcc/testsuite/gcc.dg/torture/stackalign/sibcall-1.c b/gcc/testsuite/gcc.dg/torture/stackalign/sibcall-1.c
index 8c17475..c4992df 100644
--- a/gcc/testsuite/gcc.dg/torture/stackalign/sibcall-1.c
+++ b/gcc/testsuite/gcc.dg/torture/stackalign/sibcall-1.c
@@ -1,7 +1,7 @@
 /* { dg-do run } */
 
 extern int ok (int);
-extern void exit ();
+extern void exit (int);
 static int gen_x86_64_shrd (int);
 static int
 gen_x86_64_shrd(int a __attribute__ ((__unused__)))

Reply via email to