The recent -Wbuiltin-declaration-mismatch enhancement to detect
calls with incompatible arguments to built-ins declared without
a prototype introduced a subtle bug in the detection of floating
conversion errors when passing EXCESS_PRECISION_EXPR arguments
to floating function parameters with different precision.
The bug was caught by tests on a handful of targets, but
unfortunately not on x86_64-linux.

The attached patch corrects this bug.  Because it also changes
the indentation of the affected function to make the control flow
easier to follow I include two diffs: one that can be applied as
is and another with whitespace changes ignored.

Tested on x86_64-linux with -m32/-m64 and with an i386-solaris2.11
cross-compiler.

Martin
PR c/88091 - c-c++-common/Wconversion-real.c etc. FAIL

gcc/c/ChangeLog:

	PR c/88091
	* c-typeck.c (convert_argument): Add a parameter.  Adjust indentation.
	(convert_arguments): Add comments.  Pass additional argument to
	the function above.

Index: gcc/c/c-typeck.c
===================================================================
--- gcc/c/c-typeck.c	(revision 266284)
+++ gcc/c/c-typeck.c	(working copy)
@@ -3190,14 +3190,10 @@ c_build_function_call_vec (location_t loc, vec<loc
 
 static tree
 convert_argument (location_t ploc, tree function, tree fundecl,
-		  tree type, tree origtype, tree val, bool npc,
-		  tree rname, int parmnum, int argnum,
+		  tree type, tree origtype, tree val, tree valtype,
+		  bool npc, 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))
@@ -3204,164 +3200,162 @@ convert_argument (location_t ploc, tree function,
     {
       error_at (ploc, "type of formal parameter %d is incomplete",
 		parmnum + 1);
-      parmval = val;
+      return val;
     }
-  else
+
+  /* Optionally warn about conversions that differ from the default
+     conversions.  */
+  if (warn_traditional_conversion || warn_traditional)
     {
-      /* 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)
 	{
-	  unsigned int formal_prec = TYPE_PRECISION (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);
 
-	  if (INTEGRAL_TYPE_P (type)
-	      && TREE_CODE (valtype) == REAL_TYPE)
+	  /* 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 as integer rather "
-			"than floating due to prototype",
+			"passing argument %d of %qE "
+			"with different width due to prototype",
 			argnum, rname);
-	  if (INTEGRAL_TYPE_P (type)
-	      && TREE_CODE (valtype) == COMPLEX_TYPE)
+	  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 integer rather "
-			"than complex due to prototype",
+			"passing argument %d of %qE "
+			"as unsigned due to prototype",
 			argnum, rname);
-	  else if (TREE_CODE (type) == COMPLEX_TYPE
-		   && TREE_CODE (valtype) == REAL_TYPE)
+	  else
 	    warning_at (ploc, OPT_Wtraditional_conversion,
-			"passing argument %d of %qE as complex rather "
-			"than floating due to prototype",
+			"passing argument %d of %qE "
+			"as signed 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);
+  /* 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,
-					npc, fundecl, function,
-					parmnum + 1, warnopt);
+  tree parmval = convert_for_assignment (ploc, ploc, type,
+					 val, origtype, ic_argpass,
+					 npc, 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);
-    }
+  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;
 }
@@ -3454,8 +3448,8 @@ convert_arguments (location_t loc, vec<location_t>
 	  }
     }
 
-  /* Scan the given expressions and types, producing individual
-     converted arguments.  */
+  /* Scan the given expressions (VALUES) and types (TYPELIST), producing
+     individual converted arguments.  */
 
   tree typetail, builtin_typetail, val;
   for (typetail = typelist,
@@ -3464,14 +3458,23 @@ convert_arguments (location_t loc, vec<location_t>
        values && values->iterate (parmnum, &val);
        ++parmnum)
     {
+      /* The type of the function parameter (if it was declared with one).  */
       tree type = typetail ? TREE_VALUE (typetail) : NULL_TREE;
+      /* The type of the built-in function parameter (if the function
+	 is a built-in).  Used to detect type incompatibilities in
+	 calls to built-ins declared without a prototype.  */
       tree builtin_type = (builtin_typetail
 			   ? TREE_VALUE (builtin_typetail) : NULL_TREE);
+      /* The original type of the argument being passed to the function.  */
       tree valtype = TREE_TYPE (val);
+      /* The called function (or function selector in Objective C).  */
       tree rname = function;
       int argnum = parmnum + 1;
       const char *invalid_func_diag;
+      /* Set for EXCESS_PRECISION_EXPR arguments.  */
       bool excess_precision = false;
+      /* The value of the argument after conversion to the type
+	 of the function parameter it is passed to.  */
       tree parmval;
       /* Some __atomic_* builtins have additional hidden argument at
 	 position 0.  */
@@ -3555,7 +3558,7 @@ convert_arguments (location_t loc, vec<location_t>
 	{
 	  tree origtype = (!origtypes) ? NULL_TREE : (*origtypes)[parmnum];
 	  parmval = convert_argument (ploc, function, fundecl, type, origtype,
-				      val, npc, rname, parmnum, argnum,
+				      val, valtype, npc, rname, parmnum, argnum,
 				      excess_precision, 0);
 	}
       else if (promote_float_arg)
@@ -3607,7 +3610,8 @@ convert_arguments (location_t loc, vec<location_t>
 	     above by applying default conversions instead.  */
 	  tree origtype = (!origtypes) ? NULL_TREE : (*origtypes)[parmnum];
 	  convert_argument (ploc, function, fundecl, builtin_type, origtype,
-			    val, npc, rname, parmnum, argnum, excess_precision,
+			    val, valtype, npc, rname, parmnum, argnum,
+			    excess_precision,
 			    OPT_Wbuiltin_declaration_mismatch);
 	}
 
Index: gcc/c/c-typeck.c
===================================================================
--- gcc/c/c-typeck.c    (revision 266284)
+++ gcc/c/c-typeck.c    (working copy)
@@ -3190,14 +3190,10 @@
 
 static tree
 convert_argument (location_t ploc, tree function, tree fundecl,
-                 tree type, tree origtype, tree val, bool npc,
-                 tree rname, int parmnum, int argnum,
+                 tree type, tree origtype, tree val, tree valtype,
+                 bool npc, 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))
@@ -3204,10 +3200,9 @@
     {
       error_at (ploc, "type of formal parameter %d is incomplete",
                parmnum + 1);
-      parmval = val;
+      return val;
     }
-  else
-    {
+
       /* Optionally warn about conversions that differ from the default
         conversions.  */
       if (warn_traditional_conversion || warn_traditional)
@@ -3352,7 +3347,7 @@
       if (excess_precision)
        val = build1 (EXCESS_PRECISION_EXPR, valtype, val);
 
-      parmval = convert_for_assignment (ploc, ploc, type,
+  tree parmval = convert_for_assignment (ploc, ploc, type,
                                        val, origtype, ic_argpass,
                                        npc, fundecl, function,
                                        parmnum + 1, warnopt);
@@ -3361,7 +3356,6 @@
          && INTEGRAL_TYPE_P (type)
          && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
        parmval = default_conversion (parmval);
-    }
 
   return parmval;
 }
@@ -3454,8 +3448,8 @@
          }
     }
 
-  /* Scan the given expressions and types, producing individual
-     converted arguments.  */
+  /* Scan the given expressions (VALUES) and types (TYPELIST), producing
+     individual converted arguments.  */
 
   tree typetail, builtin_typetail, val;
   for (typetail = typelist,
@@ -3464,14 +3458,23 @@
        values && values->iterate (parmnum, &val);
        ++parmnum)
     {
+      /* The type of the function parameter (if it was declared with one).  */
       tree type = typetail ? TREE_VALUE (typetail) : NULL_TREE;
+      /* The type of the built-in function parameter (if the function
+        is a built-in).  Used to detect type incompatibilities in
+        calls to built-ins declared without a prototype.  */
       tree builtin_type = (builtin_typetail
                           ? TREE_VALUE (builtin_typetail) : NULL_TREE);
+      /* The original type of the argument being passed to the function.  */
       tree valtype = TREE_TYPE (val);
+      /* The called function (or function selector in Objective C).  */
       tree rname = function;
       int argnum = parmnum + 1;
       const char *invalid_func_diag;
+      /* Set for EXCESS_PRECISION_EXPR arguments.  */
       bool excess_precision = false;
+      /* The value of the argument after conversion to the type
+        of the function parameter it is passed to.  */
       tree parmval;
       /* Some __atomic_* builtins have additional hidden argument at
         position 0.  */
@@ -3555,7 +3558,7 @@
        {
          tree origtype = (!origtypes) ? NULL_TREE : (*origtypes)[parmnum];
          parmval = convert_argument (ploc, function, fundecl, type, origtype,
-                                     val, npc, rname, parmnum, argnum,
+                                     val, valtype, npc, rname, parmnum, argnum,
                                      excess_precision, 0);
        }
       else if (promote_float_arg)
@@ -3607,7 +3610,8 @@
             above by applying default conversions instead.  */
          tree origtype = (!origtypes) ? NULL_TREE : (*origtypes)[parmnum];
          convert_argument (ploc, function, fundecl, builtin_type, origtype,
-                           val, npc, rname, parmnum, argnum, excess_precision,
+                           val, valtype, npc, rname, parmnum, argnum,
+                           excess_precision,
                            OPT_Wbuiltin_declaration_mismatch);
        }
 

Reply via email to