[PR,c/52952] More precise locations for Wformat
diff mbox

Message ID CAESRpQBTHobockE18An_GMDBan6tKBEJ_GJ5zTvb3pzg1HzpWA@mail.gmail.com
State New
Headers show

Commit Message

Manuel López-Ibáñez Aug. 15, 2014, 1:51 p.m. UTC
Hi,

This patch moves the location of various Wformat warnings from
pointing to the first character of the function name (such as printf)
to the actual format string. This is specially useful when you have
something like

printf (cond ? "format 1" : "format 2");

It also moves (some) of the warnings about too many arguments to the
first argument that is unused. Since the format string and/or the
arguments might not be expressions or strings, this doesn't always
work and then we are back to the status-quo.

This is anyway a first step. I have some patches to point within the
format string for some cases. This is why I added column markers to
testcases even if we don't actually improve the location: it  will
help us to identify testcases that need updating as the location info
improves.

Unfortunately, reaching the level of Clang seems well beyond the time
I can dedicate to this, so any help would be appreciated.

OK for trunk?


gcc/c-family/ChangeLog:

2014-08-15  Manuel López-Ibáñez  <manu.gnu.org>

    PR c/52952
    * c-format.c: Add extra_arg_loc and format_string_loc to struct
    format_check_results.
    (check_function_format): Use true and add comment for boolean
    argument.
    (finish_dollar_format_checking): Use explicit location when warning.
    (check_format_info): Likewise.
    (check_format_arg): Set extra_arg_loc and format_string_loc.
    (check_format_info_main): Use explicit location when warning.
    (check_format_types): Pass explicit location.
    (format_type_warning): Likewise.

gcc/testsuite/ChangeLog:

2014-08-15  Manuel López-Ibáñez  <manu.gnu.org>

    PR c/52952
    * gcc.dg/redecl-4.c: Add column markers.
    * gcc.dg/format/bitfld-1.c: Likewise.
    * gcc.dg/format/attr-2.c: Likewise.
    * gcc.dg/format/attr-6.c: Likewise.
    * gcc.dg/format/array-1.c: Likewise.
    * gcc.dg/format/attr-7.c: Likewise.
    * gcc.dg/format/asm_fprintf-1.c: Likewise.
    * gcc.dg/format/attr-4.c: Likewise.
    * gcc.dg/format/branch-1.c: Likewise.
    * gcc.dg/format/c90-printf-1.c: Likewise.

Comments

Manuel López-Ibáñez Aug. 15, 2014, 3:06 p.m. UTC | #1
I should have pointed out that this is based on a preliminary patch by
Steven attached to PR 52952. I will update the Changelog to reflect
this when committing.

Cheers,

Manuel.


On 15 August 2014 15:51, Manuel López-Ibáñez <lopezibanez@gmail.com> wrote:
> Hi,
>
> This patch moves the location of various Wformat warnings from
> pointing to the first character of the function name (such as printf)
> to the actual format string. This is specially useful when you have
> something like
>
> printf (cond ? "format 1" : "format 2");
>
> It also moves (some) of the warnings about too many arguments to the
> first argument that is unused. Since the format string and/or the
> arguments might not be expressions or strings, this doesn't always
> work and then we are back to the status-quo.
>
> This is anyway a first step. I have some patches to point within the
> format string for some cases. This is why I added column markers to
> testcases even if we don't actually improve the location: it  will
> help us to identify testcases that need updating as the location info
> improves.
>
> Unfortunately, reaching the level of Clang seems well beyond the time
> I can dedicate to this, so any help would be appreciated.
>
> OK for trunk?
>
>
> gcc/c-family/ChangeLog:
>
> 2014-08-15  Manuel López-Ibáñez  <manu.gnu.org>
>
>     PR c/52952
>     * c-format.c: Add extra_arg_loc and format_string_loc to struct
>     format_check_results.
>     (check_function_format): Use true and add comment for boolean
>     argument.
>     (finish_dollar_format_checking): Use explicit location when warning.
>     (check_format_info): Likewise.
>     (check_format_arg): Set extra_arg_loc and format_string_loc.
>     (check_format_info_main): Use explicit location when warning.
>     (check_format_types): Pass explicit location.
>     (format_type_warning): Likewise.
>
> gcc/testsuite/ChangeLog:
>
> 2014-08-15  Manuel López-Ibáñez  <manu.gnu.org>
>
>     PR c/52952
>     * gcc.dg/redecl-4.c: Add column markers.
>     * gcc.dg/format/bitfld-1.c: Likewise.
>     * gcc.dg/format/attr-2.c: Likewise.
>     * gcc.dg/format/attr-6.c: Likewise.
>     * gcc.dg/format/array-1.c: Likewise.
>     * gcc.dg/format/attr-7.c: Likewise.
>     * gcc.dg/format/asm_fprintf-1.c: Likewise.
>     * gcc.dg/format/attr-4.c: Likewise.
>     * gcc.dg/format/branch-1.c: Likewise.
>     * gcc.dg/format/c90-printf-1.c: Likewise.
Joseph Myers Aug. 18, 2014, 10:15 p.m. UTC | #2
On Fri, 15 Aug 2014, Manuel López-Ibáñez wrote:

> Hi,
> 
> This patch moves the location of various Wformat warnings from
> pointing to the first character of the function name (such as printf)
> to the actual format string. This is specially useful when you have
> something like
> 
> printf (cond ? "format 1" : "format 2");
> 
> It also moves (some) of the warnings about too many arguments to the
> first argument that is unused. Since the format string and/or the
> arguments might not be expressions or strings, this doesn't always
> work and then we are back to the status-quo.
> 
> This is anyway a first step. I have some patches to point within the
> format string for some cases. This is why I added column markers to
> testcases even if we don't actually improve the location: it  will
> help us to identify testcases that need updating as the location info
> improves.
> 
> Unfortunately, reaching the level of Clang seems well beyond the time
> I can dedicate to this, so any help would be appreciated.
> 
> OK for trunk?

OK.

Patch
diff mbox

Index: gcc/c-family/c-format.c
===================================================================
--- gcc/c-family/c-format.c	(revision 213927)
+++ gcc/c-family/c-format.c	(working copy)
@@ -894,10 +894,11 @@  typedef struct
      as they were not string literals.  */
   int number_non_literal;
   /* Number of leaves of the format argument that were null pointers or
      string literals, but had extra format arguments.  */
   int number_extra_args;
+  location_t extra_arg_loc;
   /* Number of leaves of the format argument that were null pointers or
      string literals, but had extra format arguments and used $ operand
      numbers.  */
   int number_dollar_extra_args;
   /* Number of leaves of the format argument that were wide string
@@ -908,10 +909,12 @@  typedef struct
   /* Number of leaves of the format argument that were unterminated
      strings.  */
   int number_unterminated;
   /* Number of leaves of the format argument that were not counted above.  */
   int number_other;
+  /* Location of the format string.  */
+  location_t format_string_loc;
 } format_check_results;
 
 typedef struct
 {
   format_check_results *res;
@@ -953,12 +956,12 @@  static bool avoid_dollar_number (const c
 static void finish_dollar_format_checking (format_check_results *, int);
 
 static const format_flag_spec *get_flag_spec (const format_flag_spec *,
 					      int, const char *);
 
-static void check_format_types (format_wanted_type *);
-static void format_type_warning (format_wanted_type *, tree, tree);
+static void check_format_types (location_t, format_wanted_type *);
+static void format_type_warning (location_t, format_wanted_type *, tree, tree);
 
 /* Decode a format type from a string, returning the type, or
    format_type_error if not valid, in which case the caller should print an
    error message.  */
 static int
@@ -1001,11 +1004,11 @@  check_function_format (tree attrs, int n
     {
       if (is_attribute_p ("format", TREE_PURPOSE (a)))
 	{
 	  /* Yup; check it.  */
 	  function_format_info info;
-	  decode_format_attr (TREE_VALUE (a), &info, 1);
+	  decode_format_attr (TREE_VALUE (a), &info, /*validated=*/true);
 	  if (warn_format)
 	    {
 	      /* FIXME: Rewrite all the internal functions in this file
 		 to use the ARGARRAY directly instead of constructing this
 		 temporary list.  */
@@ -1255,13 +1258,13 @@  finish_dollar_format_checking (format_ch
 	{
 	  if (pointer_gap_ok && (dollar_first_arg_num == 0
 				 || dollar_arguments_pointer_p[i]))
 	    found_pointer_gap = true;
 	  else
-	    warning (OPT_Wformat_,
-		     "format argument %d unused before used argument %d in $-style format",
-		     i + 1, dollar_max_arg_used);
+	    warning_at (res->format_string_loc, OPT_Wformat_,
+			"format argument %d unused before used argument %d in $-style format",
+			i + 1, dollar_max_arg_used);
 	}
     }
   if (found_pointer_gap
       || (dollar_first_arg_num
 	  && dollar_max_arg_used < dollar_arguments_count))
@@ -1328,34 +1331,40 @@  check_format_info (function_format_info
   if (format_tree == 0)
     return;
 
   res.number_non_literal = 0;
   res.number_extra_args = 0;
+  res.extra_arg_loc = UNKNOWN_LOCATION;
   res.number_dollar_extra_args = 0;
   res.number_wide = 0;
   res.number_empty = 0;
   res.number_unterminated = 0;
   res.number_other = 0;
+  res.format_string_loc = input_location;
 
   format_ctx.res = &res;
   format_ctx.info = info;
   format_ctx.params = params;
 
   check_function_arguments_recurse (check_format_arg, &format_ctx,
 				    format_tree, arg_num);
 
+  location_t loc = format_ctx.res->format_string_loc;
+  if (res.extra_arg_loc == UNKNOWN_LOCATION)
+    res.extra_arg_loc = loc;
+
   if (res.number_non_literal > 0)
     {
       /* Functions taking a va_list normally pass a non-literal format
 	 string.  These functions typically are declared with
 	 first_arg_num == 0, so avoid warning in those cases.  */
       if (!(format_types[info->format_type].flags & (int) FMT_FLAG_ARG_CONVERT))
 	{
 	  /* For strftime-like formats, warn for not checking the format
 	     string; but there are no arguments to check.  */
-	  warning (OPT_Wformat_nonliteral,
-		   "format not a string literal, format string not checked");
+	  warning_at (loc, OPT_Wformat_nonliteral,
+		      "format not a string literal, format string not checked");
 	}
       else if (info->first_arg_num != 0)
 	{
 	  /* If there are no arguments for the format at all, we may have
 	     printf (foo) which is likely to be a security hole.  */
@@ -1365,18 +1374,18 @@  check_format_info (function_format_info
 		break;
 	      params = TREE_CHAIN (params);
 	      ++arg_num;
 	    }
 	  if (params == 0 && warn_format_security)
-	    warning (OPT_Wformat_security,
-		     "format not a string literal and no format arguments");
+	    warning_at (loc, OPT_Wformat_security,
+			"format not a string literal and no format arguments");
 	  else if (params == 0 && warn_format_nonliteral)
-	    warning (OPT_Wformat_nonliteral,
-		     "format not a string literal and no format arguments");
+	    warning_at (loc, OPT_Wformat_nonliteral,
+			"format not a string literal and no format arguments");
 	  else
-	    warning (OPT_Wformat_nonliteral,
-		     "format not a string literal, argument types not checked");
+	    warning_at (loc, OPT_Wformat_nonliteral,
+			"format not a string literal, argument types not checked");
 	}
     }
 
   /* If there were extra arguments to the format, normally warn.  However,
      the standard does say extra arguments are ignored, so in the specific
@@ -1385,24 +1394,25 @@  check_format_info (function_format_info
      arguments, but was otherwise OK (either non-literal or checked OK).
      If the format is an empty string, this should be counted similarly to the
      case of extra format arguments.  */
   if (res.number_extra_args > 0 && res.number_non_literal == 0
       && res.number_other == 0)
-    warning (OPT_Wformat_extra_args, "too many arguments for format");
+    warning_at (res.extra_arg_loc, OPT_Wformat_extra_args,
+		"too many arguments for format");
   if (res.number_dollar_extra_args > 0 && res.number_non_literal == 0
       && res.number_other == 0)
-    warning (OPT_Wformat_extra_args, "unused arguments in $-style format");
+    warning_at (loc, OPT_Wformat_extra_args, "unused arguments in $-style format");
   if (res.number_empty > 0 && res.number_non_literal == 0
       && res.number_other == 0)
-    warning (OPT_Wformat_zero_length, "zero-length %s format string",
+    warning_at (loc, OPT_Wformat_zero_length, "zero-length %s format string",
 	     format_types[info->format_type].name);
 
   if (res.number_wide > 0)
-    warning (OPT_Wformat_, "format is a wide character string");
+    warning_at (loc, OPT_Wformat_, "format is a wide character string");
 
   if (res.number_unterminated > 0)
-    warning (OPT_Wformat_, "unterminated format string");
+    warning_at (loc, OPT_Wformat_, "unterminated format string");
 }
 
 /* Callback from check_function_arguments_recurse to check a
    format string.  FORMAT_TREE is the format parameter.  ARG_NUM
    is the number of the format argument.  CTX points to a
@@ -1436,13 +1446,17 @@  check_format_arg (void *ctx, tree format
 	  ++arg_num;
 	}
 
       if (params == 0)
 	res->number_other++;
-      else
-	res->number_extra_args++;
-
+      else 
+	{
+	  if (res->number_extra_args == 0)
+	    res->extra_arg_loc = EXPR_LOC_OR_LOC (TREE_VALUE (params),
+						  input_location);
+	  res->number_extra_args++;
+	}
       return;
     }
 
   offset = 0;
   if (TREE_CODE (format_tree) == POINTER_PLUS_EXPR)
@@ -1470,10 +1484,11 @@  check_format_arg (void *ctx, tree format
   if (TREE_CODE (format_tree) != ADDR_EXPR)
     {
       res->number_non_literal++;
       return;
     }
+  res->format_string_loc = EXPR_LOC_OR_LOC (format_tree, input_location);
   format_tree = TREE_OPERAND (format_tree, 0);
   if (format_types[info->format_type].flags 
       & (int) FMT_FLAG_PARSE_ARG_CONVERT_EXTERNAL)
     {
       bool objc_str = (info->format_type == gcc_objc_string_format_type);
@@ -1605,10 +1620,11 @@  check_format_info_main (format_check_res
   tree first_fillin_param = params;
 
   const format_kind_info *fki = &format_types[info->format_type];
   const format_flag_spec *flag_specs = fki->flag_specs;
   const format_flag_pair *bad_flag_pairs = fki->bad_flag_pairs;
+  location_t format_string_loc = res->format_string_loc;
 
   /* -1 if no conversions taking an operand have been found; 0 if one has
      and it didn't use $; 1 if $ formats are in use.  */
   int has_operand_number = -1;
 
@@ -1642,11 +1658,12 @@  check_format_info_main (format_check_res
 
       if (*format_chars++ != '%')
 	continue;
       if (*format_chars == 0)
 	{
-	  warning (OPT_Wformat_, "spurious trailing %<%%%> in format");
+          warning_at (format_string_loc, OPT_Wformat_,
+		      "spurious trailing %<%%%> in format");
 	  continue;
 	}
       if (*format_chars == '%')
 	{
 	  ++format_chars;
@@ -1686,11 +1703,12 @@  check_format_info_main (format_check_res
 	{
 	  const format_flag_spec *s = get_flag_spec (flag_specs,
 						     *format_chars, NULL);
 	  if (strchr (flag_chars, *format_chars) != 0)
 	    {
-	      warning (OPT_Wformat_, "repeated %s in format", _(s->name));
+	      warning_at (format_string_loc, OPT_Wformat_,
+			  "repeated %s in format", _(s->name));
 	    }
 	  else
 	    {
 	      i = strlen (flag_chars);
 	      flag_chars[i++] = *format_chars;
@@ -1699,11 +1717,12 @@  check_format_info_main (format_check_res
 	  if (s->skip_next_char)
 	    {
 	      ++format_chars;
 	      if (*format_chars == 0)
 		{
-		  warning (OPT_Wformat_, "missing fill character at end of strfmon format");
+		  warning_at (format_string_loc, OPT_Wformat_,
+			      "missing fill character at end of strfmon format");
 		  return;
 		}
 	    }
 	  ++format_chars;
 	}
@@ -1787,11 +1806,12 @@  check_format_info_main (format_check_res
 		    non_zero_width_char = TRUE;
 		  ++format_chars;
 		}
 	      if (found_width && !non_zero_width_char &&
 		  (fki->flags & (int) FMT_FLAG_ZERO_WIDTH_BAD))
-		warning (OPT_Wformat_, "zero width in %s format", fki->name);
+		warning_at (format_string_loc, OPT_Wformat_,
+			    "zero width in %s format", fki->name);
 	      if (found_width)
 		{
 		  i = strlen (flag_chars);
 		  flag_chars[i++] = fki->width_char;
 		  flag_chars[i] = 0;
@@ -1805,11 +1825,12 @@  check_format_info_main (format_check_res
 	  ++format_chars;
 	  i = strlen (flag_chars);
 	  flag_chars[i++] = fki->left_precision_char;
 	  flag_chars[i] = 0;
 	  if (!ISDIGIT (*format_chars))
-	    warning (OPT_Wformat_, "empty left precision in %s format", fki->name);
+	    warning_at (format_string_loc, OPT_Wformat_,
+			"empty left precision in %s format", fki->name);
 	  while (ISDIGIT (*format_chars))
 	    ++format_chars;
 	}
 
       /* Read any format precision, possibly * or *m$.  */
@@ -1881,11 +1902,12 @@  check_format_info_main (format_check_res
 	    }
 	  else
 	    {
 	      if (!(fki->flags & (int) FMT_FLAG_EMPTY_PREC_OK)
 		  && !ISDIGIT (*format_chars))
-		warning (OPT_Wformat_, "empty precision in %s format", fki->name);
+		warning_at (format_string_loc, OPT_Wformat_,
+			    "empty precision in %s format", fki->name);
 	      while (ISDIGIT (*format_chars))
 		++format_chars;
 	    }
 	}
 
@@ -1949,14 +1971,14 @@  check_format_info_main (format_check_res
 	    }
 	  if (pedantic)
 	    {
 	      /* Warn if the length modifier is non-standard.  */
 	      if (ADJ_STD (length_chars_std) > C_STD_VER)
-		warning (OPT_Wformat_,
-			 "%s does not support the %qs %s length modifier",
-			 C_STD_NAME (length_chars_std), length_chars,
-			 fki->name);
+		warning_at (format_string_loc, OPT_Wformat_,
+			    "%s does not support the %qs %s length modifier",
+			    C_STD_NAME (length_chars_std), length_chars,
+			    fki->name);
 	    }
 	}
 
       /* Read any modifier (strftime E/O).  */
       if (fki->modifier_chars != NULL)
@@ -1966,11 +1988,12 @@  check_format_info_main (format_check_res
 	    {
 	      if (strchr (flag_chars, *format_chars) != 0)
 		{
 		  const format_flag_spec *s = get_flag_spec (flag_specs,
 							     *format_chars, NULL);
-		  warning (OPT_Wformat_, "repeated %s in format", _(s->name));
+		  warning_at (format_string_loc, OPT_Wformat_,
+			      "repeated %s in format", _(s->name));
 		}
 	      else
 		{
 		  i = strlen (flag_chars);
 		  flag_chars[i++] = *format_chars;
@@ -1983,33 +2006,37 @@  check_format_info_main (format_check_res
       format_char = *format_chars;
       if (format_char == 0
 	  || (!(fki->flags & (int) FMT_FLAG_FANCY_PERCENT_OK)
 	      && format_char == '%'))
 	{
-	  warning (OPT_Wformat_, "conversion lacks type at end of format");
+	  warning_at (format_string_loc, OPT_Wformat_,
+		      "conversion lacks type at end of format");
 	  continue;
 	}
       format_chars++;
       fci = fki->conversion_specs;
       while (fci->format_chars != 0
 	     && strchr (fci->format_chars, format_char) == 0)
 	  ++fci;
       if (fci->format_chars == 0)
 	{
 	  if (ISGRAPH (format_char))
-	    warning (OPT_Wformat_, "unknown conversion type character %qc in format",
-		     format_char);
+	    warning_at (format_string_loc, OPT_Wformat_,
+			"unknown conversion type character %qc in format",
+			format_char);
 	  else
-	    warning (OPT_Wformat_, "unknown conversion type character 0x%x in format",
-		     format_char);
+	    warning_at (format_string_loc, OPT_Wformat_,
+			"unknown conversion type character 0x%x in format",
+			format_char);
 	  continue;
 	}
       if (pedantic)
 	{
 	  if (ADJ_STD (fci->std) > C_STD_VER)
-	    warning (OPT_Wformat_, "%s does not support the %<%%%c%> %s format",
-		     C_STD_NAME (fci->std), format_char, fki->name);
+	    warning_at (format_string_loc, OPT_Wformat_,
+			"%s does not support the %<%%%c%> %s format",
+			C_STD_NAME (fci->std), format_char, fki->name);
 	}
 
       /* Validate the individual flags used, removing any that are invalid.  */
       {
 	int d = 0;
@@ -2020,32 +2047,34 @@  check_format_info_main (format_check_res
 	    flag_chars[i - d] = flag_chars[i];
 	    if (flag_chars[i] == fki->length_code_char)
 	      continue;
 	    if (strchr (fci->flag_chars, flag_chars[i]) == 0)
 	      {
-		warning (OPT_Wformat_, "%s used with %<%%%c%> %s format",
-			 _(s->name), format_char, fki->name);
+		warning_at (format_string_loc, 
+                            OPT_Wformat_, "%s used with %<%%%c%> %s format",
+			    _(s->name), format_char, fki->name);
 		d++;
 		continue;
 	      }
 	    if (pedantic)
 	      {
 		const format_flag_spec *t;
 		if (ADJ_STD (s->std) > C_STD_VER)
-		  warning (OPT_Wformat_, "%s does not support %s",
-			   C_STD_NAME (s->std), _(s->long_name));
+		  warning_at (format_string_loc, OPT_Wformat_,
+			      "%s does not support %s",
+                              C_STD_NAME (s->std), _(s->long_name));
 		t = get_flag_spec (flag_specs, flag_chars[i], fci->flags2);
 		if (t != NULL && ADJ_STD (t->std) > ADJ_STD (s->std))
 		  {
 		    const char *long_name = (t->long_name != NULL
 					     ? t->long_name
 					     : s->long_name);
 		    if (ADJ_STD (t->std) > C_STD_VER)
-		      warning (OPT_Wformat_,
-			       "%s does not support %s with the %<%%%c%> %s format",
-			       C_STD_NAME (t->std), _(long_name),
-			       format_char, fki->name);
+		      warning_at (format_string_loc, OPT_Wformat_,
+				  "%s does not support %s with the %<%%%c%> %s format",
+				  C_STD_NAME (t->std), _(long_name),
+				  format_char, fki->name);
 		  }
 	      }
 	  }
 	flag_chars[i - d] = 0;
       }
@@ -2074,28 +2103,30 @@  check_format_info_main (format_check_res
 	  s = get_flag_spec (flag_specs, bad_flag_pairs[i].flag_char1, NULL);
 	  t = get_flag_spec (flag_specs, bad_flag_pairs[i].flag_char2, NULL);
 	  if (bad_flag_pairs[i].ignored)
 	    {
 	      if (bad_flag_pairs[i].predicate != 0)
-		warning (OPT_Wformat_,
-			 "%s ignored with %s and %<%%%c%> %s format",
-			 _(s->name), _(t->name), format_char,
-			 fki->name);
+		warning_at (format_string_loc, OPT_Wformat_,
+			    "%s ignored with %s and %<%%%c%> %s format",
+			    _(s->name), _(t->name), format_char,
+			    fki->name);
 	      else
-		warning (OPT_Wformat_, "%s ignored with %s in %s format",
-			 _(s->name), _(t->name), fki->name);
+		warning_at (format_string_loc, OPT_Wformat_,
+			    "%s ignored with %s in %s format",
+			    _(s->name), _(t->name), fki->name);
 	    }
 	  else
 	    {
 	      if (bad_flag_pairs[i].predicate != 0)
-		warning (OPT_Wformat_,
-			 "use of %s and %s together with %<%%%c%> %s format",
-			 _(s->name), _(t->name), format_char,
-			 fki->name);
+		warning_at (format_string_loc, OPT_Wformat_,
+			    "use of %s and %s together with %<%%%c%> %s format",
+			    _(s->name), _(t->name), format_char,
+			    fki->name);
 	      else
-		warning (OPT_Wformat_, "use of %s and %s together in %s format",
-			 _(s->name), _(t->name), fki->name);
+		warning_at (format_string_loc, OPT_Wformat_,
+			    "use of %s and %s together in %s format",
+			    _(s->name), _(t->name), fki->name);
 	    }
 	}
 
       /* Give Y2K warnings.  */
       if (warn_format_y2k)
@@ -2109,15 +2140,17 @@  check_format_info_main (format_check_res
 	  else if (strchr (fci->flags2, '3') != 0)
 	    y2k_level = 3;
 	  else if (strchr (fci->flags2, '2') != 0)
 	    y2k_level = 2;
 	  if (y2k_level == 3)
-	    warning (OPT_Wformat_y2k, "%<%%%c%> yields only last 2 digits of "
-		     "year in some locales", format_char);
+	    warning_at (format_string_loc, OPT_Wformat_y2k,
+			"%<%%%c%> yields only last 2 digits of "
+			"year in some locales", format_char);
 	  else if (y2k_level == 2)
-	    warning (OPT_Wformat_y2k, "%<%%%c%> yields only last 2 digits of "
-		     "year", format_char);
+	    warning_at (format_string_loc, OPT_Wformat_y2k,
+			"%<%%%c%> yields only last 2 digits of year",
+			format_char);
 	}
 
       if (strchr (fci->flags2, '[') != 0)
 	{
 	  /* Skip over scan set, in case it happens to have '%' in it.  */
@@ -2129,11 +2162,12 @@  check_format_info_main (format_check_res
 	    ++format_chars;
 	  while (*format_chars && *format_chars != ']')
 	    ++format_chars;
 	  if (*format_chars != ']')
 	    /* The end of the format string was reached.  */
-	    warning (OPT_Wformat_, "no closing %<]%> for %<%%[%> format");
+	    warning_at (format_string_loc, OPT_Wformat_,
+			"no closing %<]%> for %<%%[%> format");
 	}
 
       wanted_type = 0;
       wanted_type_name = 0;
       if (fki->flags & (int) FMT_FLAG_ARG_CONVERT)
@@ -2142,13 +2176,13 @@  check_format_info_main (format_check_res
 			 ? *fci->types[length_chars_val].type : 0);
 	  wanted_type_name = fci->types[length_chars_val].name;
 	  wanted_type_std = fci->types[length_chars_val].std;
 	  if (wanted_type == 0)
 	    {
-	      warning (OPT_Wformat_,
-		       "use of %qs length modifier with %qc type character",
-		       length_chars, format_char);
+	      warning_at (format_string_loc, OPT_Wformat_,
+			  "use of %qs length modifier with %qc type character",
+			  length_chars, format_char);
 	      /* Heuristic: skip one argument when an invalid length/type
 		 combination is encountered.  */
 	      arg_num++;
 	      if (params != 0)
                 params = TREE_CHAIN (params);
@@ -2160,14 +2194,14 @@  check_format_info_main (format_check_res
 		      have been warned for.  */
 		   && ADJ_STD (wanted_type_std) > ADJ_STD (length_chars_std)
 		   && ADJ_STD (wanted_type_std) > ADJ_STD (fci->std))
 	    {
 	      if (ADJ_STD (wanted_type_std) > C_STD_VER)
-		warning (OPT_Wformat_,
-			 "%s does not support the %<%%%s%c%> %s format",
-			 C_STD_NAME (wanted_type_std), length_chars,
-			 format_char, fki->name);
+		warning_at (format_string_loc, OPT_Wformat_,
+			    "%s does not support the %<%%%s%c%> %s format",
+			    C_STD_NAME (wanted_type_std), length_chars,
+			    format_char, fki->name);
 	    }
 	}
 
       main_wanted_type.next = NULL;
 
@@ -2178,15 +2212,17 @@  check_format_info_main (format_check_res
 	  || suppressed)
 	{
 	  if (main_arg_num != 0)
 	    {
 	      if (suppressed)
-		warning (OPT_Wformat_, "operand number specified with "
-			 "suppressed assignment");
+		warning_at (format_string_loc, OPT_Wformat_,
+			    "operand number specified with "
+			    "suppressed assignment");
 	      else
-		warning (OPT_Wformat_, "operand number specified for format "
-			 "taking no argument");
+		warning_at (format_string_loc, OPT_Wformat_,
+			    "operand number specified for format "
+			    "taking no argument");
 	    }
 	}
       else
 	{
 	  format_wanted_type *wanted_type_ptr;
@@ -2199,11 +2235,12 @@  check_format_info_main (format_check_res
 	  else
 	    {
 	      ++arg_num;
 	      if (has_operand_number > 0)
 		{
-		  warning (OPT_Wformat_, "missing $ operand number in format");
+		  warning_at (format_string_loc, OPT_Wformat_,
+			      "missing $ operand number in format");
 		  return;
 		}
 	      else
 		has_operand_number = 0;
 	    }
@@ -2262,15 +2299,16 @@  check_format_info_main (format_check_res
 		}
 	    }
 	}
 
       if (first_wanted_type != 0)
-        check_format_types (first_wanted_type);
+        check_format_types (format_string_loc, first_wanted_type);
     }
 
   if (format_chars - orig_format_chars != format_length)
-    warning (OPT_Wformat_contains_nul, "embedded %<\\0%> in format");
+    warning_at (format_string_loc, OPT_Wformat_contains_nul,
+		"embedded %<\\0%> in format");
   if (info->first_arg_num != 0 && params != 0
       && has_operand_number <= 0)
     {
       res->number_other--;
       res->number_extra_args++;
@@ -2279,13 +2317,14 @@  check_format_info_main (format_check_res
     finish_dollar_format_checking (res, fki->flags & (int) FMT_FLAG_DOLLAR_GAP_POINTER_OK);
 }
 
 
 /* Check the argument types from a single format conversion (possibly
-   including width and precision arguments).  */
+   including width and precision arguments).  LOC is the location of
+   the format string.  */
 static void
-check_format_types (format_wanted_type *types)
+check_format_types (location_t loc, format_wanted_type *types)
 {
   for (; types != 0; types = types->next)
     {
       tree cur_param;
       tree cur_type;
@@ -2308,11 +2347,11 @@  check_format_types (format_wanted_type *
       wanted_type = TYPE_MAIN_VARIANT (wanted_type);
 
       cur_param = types->param;
       if (!cur_param)
         {
-          format_type_warning (types, wanted_type, NULL);
+          format_type_warning (loc, types, wanted_type, NULL);
           continue;
         }
 
       cur_type = TREE_TYPE (cur_param);
       if (cur_type == error_mark_node)
@@ -2382,11 +2421,11 @@  check_format_types (format_wanted_type *
 			 arg_num);
 
 	    }
 	  else
 	    {
-              format_type_warning (types, wanted_type, orig_cur_type);
+              format_type_warning (loc, types, wanted_type, orig_cur_type);
 	      break;
 	    }
 	}
 
       if (i < types->pointer_count)
@@ -2436,24 +2475,25 @@  check_format_types (format_wanted_type *
 	      || (INTEGRAL_TYPE_P (cur_type)
 		  && INTEGRAL_TYPE_P (wanted_type)))
 	  && TYPE_PRECISION (cur_type) == TYPE_PRECISION (wanted_type))
 	continue;
       /* Now we have a type mismatch.  */
-      format_type_warning (types, wanted_type, orig_cur_type);
+      format_type_warning (loc, types, wanted_type, orig_cur_type);
     }
 }
 
 
-/* Give a warning about a format argument of different type from that
+/* Give a warning at LOC about a format argument of different type from that
    expected.  WANTED_TYPE is the type the argument should have, possibly
    stripped of pointer dereferences.  The description (such as "field
    precision"), the placement in the format string, a possibly more
    friendly name of WANTED_TYPE, and the number of pointer dereferences
    are taken from TYPE.  ARG_TYPE is the type of the actual argument,
    or NULL if it is missing.  */
 static void
-format_type_warning (format_wanted_type *type, tree wanted_type, tree arg_type)
+format_type_warning (location_t loc, format_wanted_type *type,
+		     tree wanted_type, tree arg_type)
 {
   int kind = type->kind;
   const char *wanted_type_name = type->wanted_type_name;
   const char *format_start = type->format_start;
   int format_length = type->format_length;
@@ -2493,36 +2533,40 @@  format_type_warning (format_wanted_type
     }
 
   if (wanted_type_name)
     {
       if (arg_type)
-        warning (OPT_Wformat_, "%s %<%s%.*s%> expects argument of type %<%s%s%>, "
-                 "but argument %d has type %qT",
-                 gettext (kind_descriptions[kind]),
-                 (kind == CF_KIND_FORMAT ? "%" : ""),
-                 format_length, format_start, 
-                 wanted_type_name, p, arg_num, arg_type);
+        warning_at (loc, OPT_Wformat_,
+		    "%s %<%s%.*s%> expects argument of type %<%s%s%>, "
+		    "but argument %d has type %qT",
+		    gettext (kind_descriptions[kind]),
+		    (kind == CF_KIND_FORMAT ? "%" : ""),
+		    format_length, format_start, 
+		    wanted_type_name, p, arg_num, arg_type);
       else
-        warning (OPT_Wformat_, "%s %<%s%.*s%> expects a matching %<%s%s%> argument",
-                 gettext (kind_descriptions[kind]),
-                 (kind == CF_KIND_FORMAT ? "%" : ""),
-                 format_length, format_start, wanted_type_name, p);
+        warning_at (loc, OPT_Wformat_,
+		    "%s %<%s%.*s%> expects a matching %<%s%s%> argument",
+		    gettext (kind_descriptions[kind]),
+		    (kind == CF_KIND_FORMAT ? "%" : ""),
+		    format_length, format_start, wanted_type_name, p);
     }
   else
     {
       if (arg_type)
-        warning (OPT_Wformat_, "%s %<%s%.*s%> expects argument of type %<%T%s%>, "
-                 "but argument %d has type %qT",
-                 gettext (kind_descriptions[kind]),
-                 (kind == CF_KIND_FORMAT ? "%" : ""),
-                 format_length, format_start, 
-                 wanted_type, p, arg_num, arg_type);
+        warning_at (loc, OPT_Wformat_,
+		    "%s %<%s%.*s%> expects argument of type %<%T%s%>, "
+		    "but argument %d has type %qT",
+		    gettext (kind_descriptions[kind]),
+		    (kind == CF_KIND_FORMAT ? "%" : ""),
+		    format_length, format_start, 
+		    wanted_type, p, arg_num, arg_type);
       else
-        warning (OPT_Wformat_, "%s %<%s%.*s%> expects a matching %<%T%s%> argument",
-                 gettext (kind_descriptions[kind]),
-                 (kind == CF_KIND_FORMAT ? "%" : ""),
-                 format_length, format_start, wanted_type, p);
+        warning_at (loc, OPT_Wformat_,
+		    "%s %<%s%.*s%> expects a matching %<%T%s%> argument",
+		    gettext (kind_descriptions[kind]),
+		    (kind == CF_KIND_FORMAT ? "%" : ""),
+		    format_length, format_start, wanted_type, p);
     }
 }
 
 
 /* Given a format_char_info array FCI, and a character C, this function
Index: gcc/testsuite/gcc.dg/redecl-4.c
===================================================================
--- gcc/testsuite/gcc.dg/redecl-4.c	(revision 213927)
+++ gcc/testsuite/gcc.dg/redecl-4.c	(working copy)
@@ -12,11 +12,12 @@  f (void)
   {
     int printf (const char *, ...);
     int strcmp ();
     /* Should get format warnings even though the built-in declaration
        isn't "visible".  */
-    printf ("%s", 1); /* { dg-warning "format" } */
+    printf (
+	    "%s", 1); /* { dg-warning "6:format" } */
     /* The type of strcmp here should have no prototype.  */
     if (0)
       strcmp (1);
     /* Likewise, implicitly declared memcmp.  */
     if (0)
Index: gcc/testsuite/gcc.dg/format/bitfld-1.c
===================================================================
--- gcc/testsuite/gcc.dg/format/bitfld-1.c	(revision 213927)
+++ gcc/testsuite/gcc.dg/format/bitfld-1.c	(working copy)
@@ -44,8 +44,8 @@  foo (void)
   printf ("%d%u", x.s32, x.s32);
 #else
   printf ("%ld%lu", x.u32, x.u32);
   printf ("%ld%lu", x.s32, x.s32);
 #endif
-  printf ("%llu", x.u48); /* { dg-warning "has type '.*unsigned int:48'" } */
+  printf ("%llu", x.u48); /* { dg-warning "11:has type '.*unsigned int:48'" } */
   printf ("%llu", (unsigned long long)x.u48);
 }
Index: gcc/testsuite/gcc.dg/format/attr-2.c
===================================================================
--- gcc/testsuite/gcc.dg/format/attr-2.c	(revision 213927)
+++ gcc/testsuite/gcc.dg/format/attr-2.c	(working copy)
@@ -28,11 +28,11 @@  extern char *t__format_arg__ (const char
 
 void
 foo (int i, int *ip, double d)
 {
   tformatprintf ("%d", i);
-  tformatprintf ("%"); /* { dg-warning "format" "attribute format printf" } */
+  tformatprintf ("%"); /* { dg-warning "18:format" "attribute format printf" } */
   tformat__printf__ ("%d", i);
   tformat__printf__ ("%"); /* { dg-warning "format" "attribute format __printf__" } */
   tformatscanf ("%d", ip);
   tformatscanf ("%"); /* { dg-warning "format" "attribute format scanf" } */
   tformat__scanf__ ("%d", ip);
Index: gcc/testsuite/gcc.dg/format/attr-6.c
===================================================================
--- gcc/testsuite/gcc.dg/format/attr-6.c	(revision 213927)
+++ gcc/testsuite/gcc.dg/format/attr-6.c	(working copy)
@@ -15,8 +15,8 @@ 
    of it as a built-in function.  */
 
 void
 foo (const char *s, int *p)
 {
-  scanf("%ld", p); /* { dg-warning "format" "implicit scanf" } */
+  scanf("%ld", p); /* { dg-warning "9:format" "implicit scanf" } */
   /* { dg-warning "implicit" "implicit decl warning" { target *-*-* } 20 } */
 }
Index: gcc/testsuite/gcc.dg/format/array-1.c
===================================================================
--- gcc/testsuite/gcc.dg/format/array-1.c	(revision 213927)
+++ gcc/testsuite/gcc.dg/format/array-1.c	(working copy)
@@ -21,21 +21,21 @@  foo (int i, long l)
   const char p2[] = "bar%d";
   static const char q1[] = "bar";
   static const char q2[] = "bar%d";
   printf (a1);
   printf (a2, i);
-  printf (a2, l); /* { dg-warning "format" "wrong type with array" } */
-  printf (b1); /* { dg-warning "unterminated" "unterminated array" } */
-  printf (b2); /* { dg-warning "unterminated" "unterminated array" } */
+  printf (a2, l); /* { dg-warning "11:format" "wrong type with array" } */
+  printf (b1); /* { dg-warning "11:unterminated" "unterminated array" } */
+  printf (b2); /* { dg-warning "11:unterminated" "unterminated array" } */
   printf (c1);
   printf (c2, i);
-  printf (c2, l); /* { dg-warning "format" "wrong type with array" } */
+  printf (c2, l); /* { dg-warning "11:format" "wrong type with array" } */
   printf (p1);
   printf (p2, i);
-  printf (p2, l); /* { dg-warning "format" "wrong type with array" } */
+  printf (p2, l); /* { dg-warning "11:format" "wrong type with array" } */
   printf (q1);
   printf (q2, i);
-  printf (q2, l); /* { dg-warning "format" "wrong type with array" } */
+  printf (q2, l); /* { dg-warning "11:format" "wrong type with array" } */
   /* Volatile or non-constant arrays must not be checked.  */
-  printf (d); /* { dg-warning "not a string literal" "non-const" } */
-  printf ((const char *)e); /* { dg-warning "not a string literal" "volatile" } */
+  printf (d); /* { dg-warning "11:not a string literal" "non-const" } */
+  printf ((const char *)e); /* { dg-warning "25:not a string literal" "volatile" } */
 }
Index: gcc/testsuite/gcc.dg/format/attr-7.c
===================================================================
--- gcc/testsuite/gcc.dg/format/attr-7.c	(revision 213927)
+++ gcc/testsuite/gcc.dg/format/attr-7.c	(working copy)
@@ -16,11 +16,11 @@  char * (__attribute__((format_arg(1))) *
 void
 baz (int i)
 {
   (*tformatprintf0) ("%d", i);
   (*tformatprintf0) ((*tformat_arg) ("%d"), i);
-  (*tformatprintf0) ("%"); /* { dg-warning "format" "prefix" } */
+  (*tformatprintf0) ("%"); /* { dg-warning "22:format" "prefix" } */
   (*tformatprintf0) ((*tformat_arg) ("%")); /* { dg-warning "format" "prefix" } */
   (*tformatprintf1) ("%d", i);
   (*tformatprintf1) ((*tformat_arg) ("%d"), i);
   (*tformatprintf1) ("%"); /* { dg-warning "format" "postfix" } */
   (*tformatprintf1) ((*tformat_arg) ("%")); /* { dg-warning "format" "postfix" } */
Index: gcc/testsuite/gcc.dg/format/asm_fprintf-1.c
===================================================================
--- gcc/testsuite/gcc.dg/format/asm_fprintf-1.c	(revision 213927)
+++ gcc/testsuite/gcc.dg/format/asm_fprintf-1.c	(working copy)
@@ -40,41 +40,41 @@  foo (int i, int i1, int i2, unsigned int
   asm_fprintf ("%O%R%I%L%U%@");
   asm_fprintf ("%r", i);
   asm_fprintf ("%wd%wi%wo%wu%wx%wX", ll, ll, ull, ull, ull, ull);
 
   /* Standard specifiers not accepted in asm_fprintf.  */
-  asm_fprintf ("%f\n", d); /* { dg-warning "format" "float" } */
-  asm_fprintf ("%e\n", d); /* { dg-warning "format" "float" } */
-  asm_fprintf ("%E\n", d); /* { dg-warning "format" "float" } */
-  asm_fprintf ("%g\n", d); /* { dg-warning "format" "float" } */
-  asm_fprintf ("%G\n", d); /* { dg-warning "format" "float" } */
-  asm_fprintf ("%p\n", p); /* { dg-warning "format" "pointer" } */
-  asm_fprintf ("%n\n", n); /* { dg-warning "format" "counter" } */
-  asm_fprintf ("%hd\n", i); /* { dg-warning "format" "conversion" } */
+  asm_fprintf ("%f\n", d); /* { dg-warning "16:format" "float" } */
+  asm_fprintf ("%e\n", d); /* { dg-warning "16:format" "float" } */
+  asm_fprintf ("%E\n", d); /* { dg-warning "16:format" "float" } */
+  asm_fprintf ("%g\n", d); /* { dg-warning "16:format" "float" } */
+  asm_fprintf ("%G\n", d); /* { dg-warning "16:format" "float" } */
+  asm_fprintf ("%p\n", p); /* { dg-warning "16:format" "pointer" } */
+  asm_fprintf ("%n\n", n); /* { dg-warning "16:format" "counter" } */
+  asm_fprintf ("%hd\n", i); /* { dg-warning "16:format" "conversion" } */
 
   /* Various tests of bad argument types.  */
-  asm_fprintf ("%d", l); /* { dg-warning "format" "bad argument types" } */
-  asm_fprintf ("%wd", l); /* { dg-warning "format" "bad argument types" } */
-  asm_fprintf ("%d", ll); /* { dg-warning "format" "bad argument types" } */
-  asm_fprintf ("%*d\n", i1, i); /* { dg-warning "format" "bad * argument types" } */
-  asm_fprintf ("%.*d\n", i2, i); /* { dg-warning "format" "bad * argument types" } */
-  asm_fprintf ("%*.*ld\n", i1, i2, l); /* { dg-warning "format" "bad * argument types" } */
-  asm_fprintf ("%ld", i); /* { dg-warning "format" "bad argument types" } */
-  asm_fprintf ("%s", n); /* { dg-warning "format" "bad argument types" } */
+  asm_fprintf ("%d", l); /* { dg-warning "16:format" "bad argument types" } */
+  asm_fprintf ("%wd", l); /* { dg-warning "16:format" "bad argument types" } */
+  asm_fprintf ("%d", ll); /* { dg-warning "16:format" "bad argument types" } */
+  asm_fprintf ("%*d\n", i1, i); /* { dg-warning "16:format" "bad * argument types" } */
+  asm_fprintf ("%.*d\n", i2, i); /* { dg-warning "16:format" "bad * argument types" } */
+  asm_fprintf ("%*.*ld\n", i1, i2, l); /* { dg-warning "16:format" "bad * argument types" } */
+  asm_fprintf ("%ld", i); /* { dg-warning "16:format" "bad argument types" } */
+  asm_fprintf ("%s", n); /* { dg-warning "16:format" "bad argument types" } */
 
   /* Wrong number of arguments.  */
-  asm_fprintf ("%d%d", i); /* { dg-warning "matching" "wrong number of args" } */
-  asm_fprintf ("%d", i, i); /* { dg-warning "arguments" "wrong number of args" } */
+  asm_fprintf ("%d%d", i); /* { dg-warning "16:matching" "wrong number of args" } */
+  asm_fprintf ("%d", i, i); /* { dg-warning "16:arguments" "wrong number of args" } */
   /* Miscellaneous bogus constructions.  */
-  asm_fprintf (""); /* { dg-warning "zero-length" "warning for empty format" } */
-  asm_fprintf ("\0"); /* { dg-warning "embedded" "warning for embedded NUL" } */
-  asm_fprintf ("%d\0", i); /* { dg-warning "embedded" "warning for embedded NUL" } */
-  asm_fprintf ("%d\0%d", i, i); /* { dg-warning "embedded|too many" "warning for embedded NUL" } */
+  asm_fprintf (""); /* { dg-warning "16:zero-length" "warning for empty format" } */
+  asm_fprintf ("\0"); /* { dg-warning "16:embedded" "warning for embedded NUL" } */
+  asm_fprintf ("%d\0", i); /* { dg-warning "16:embedded" "warning for embedded NUL" } */
+  asm_fprintf ("%d\0%d", i, i); /* { dg-warning "16:embedded|too many" "warning for embedded NUL" } */
   asm_fprintf (NULL); /* { dg-warning "null" "null format string warning" } */
-  asm_fprintf ("%"); /* { dg-warning "trailing" "trailing % warning" } */
-  asm_fprintf ("%++d", i); /* { dg-warning "repeated" "repeated flag warning" } */
-  asm_fprintf ((const char *)L"foo"); /* { dg-warning "wide" "wide string" } */
+  asm_fprintf ("%"); /* { dg-warning "16:trailing" "trailing % warning" } */
+  asm_fprintf ("%++d", i); /* { dg-warning "16:repeated" "repeated flag warning" } */
+  asm_fprintf ((const char *)L"foo"); /* { dg-warning "30:wide" "wide string" } */
   asm_fprintf ("%s", (char *)0); /* { dg-warning "null" "%s with NULL" } */
 
   /* Make sure we still get warnings for regular printf.  */
-  printf ("%d\n", ll); /* { dg-warning "format" "bad argument types" } */
+  printf ("%d\n", ll); /* { dg-warning "11:format" "bad argument types" } */
 }
Index: gcc/testsuite/gcc.dg/format/attr-4.c
===================================================================
--- gcc/testsuite/gcc.dg/format/attr-4.c	(revision 213927)
+++ gcc/testsuite/gcc.dg/format/attr-4.c	(working copy)
@@ -14,11 +14,11 @@  extern __attribute__((noreturn)) void ba
 
 void
 baz (int i, int *ip, double d)
 {
   tformatprintf0 ("%d", i);
-  tformatprintf0 ("%"); /* { dg-warning "format" "attribute format printf case 0" } */
+  tformatprintf0 ("%"); /* { dg-warning "19:format" "attribute format printf case 0" } */
   tformatprintf1 ("%d", i);
   tformatprintf1 ("%"); /* { dg-warning "format" "attribute format printf case 1" } */
   tformatprintf2 ("%d", i);
   tformatprintf2 ("%"); /* { dg-warning "format" "attribute format printf case 2" } */
   tformatprintf3 ("%d", i);
Index: gcc/testsuite/gcc.dg/format/branch-1.c
===================================================================
--- gcc/testsuite/gcc.dg/format/branch-1.c	(revision 213927)
+++ gcc/testsuite/gcc.dg/format/branch-1.c	(working copy)
@@ -7,21 +7,22 @@ 
 
 void
 foo (long l, int nfoo)
 {
   printf ((nfoo > 1) ? "%d foos" : "%d foo", nfoo);
-  printf ((l > 1) ? "%d foos" : "%d foo", l); /* { dg-warning "int" "wrong type in conditional expr" } */
-  printf ((l > 1) ? "%ld foos" : "%d foo", l); /* { dg-warning "int" "wrong type in conditional expr" } */
-  printf ((l > 1) ? "%d foos" : "%ld foo", l); /* { dg-warning "int" "wrong type in conditional expr" } */
+  printf ((l > 1) ? "%d foos" /* { dg-warning "21:int" "wrong type in conditional expr" } */
+	          : "%d foo", l); /* { dg-warning "14:int" "wrong type in conditional expr" } */
+  printf ((l > 1) ? "%ld foos" : "%d foo", l); /* { dg-warning "34:int" "wrong type in conditional expr" } */
+  printf ((l > 1) ? "%d foos" : "%ld foo", l); /* { dg-warning "21:int" "wrong type in conditional expr" } */
   /* Should allow one case to have extra arguments.  */
   printf ((nfoo > 1) ? "%d foos" : "1 foo", nfoo);
-  printf ((nfoo > 1) ? "many foos" : "1 foo", nfoo); /* { dg-warning "too many" "too many args in all branches" } */
+  printf ((nfoo > 1) ? "many foos" : "1 foo", nfoo); /* { dg-warning "38:too many" "too many args in all branches" } */
   printf ((nfoo > 1) ? "%d foos" : "", nfoo);
   printf ((nfoo > 1) ? "%d foos" : ((nfoo > 0) ? "1 foo" : "no foos"), nfoo);
   printf ((nfoo > 1) ? "%d foos" : ((nfoo > 0) ? "%d foo" : "%d foos"), nfoo);
-  printf ((nfoo > 1) ? "%d foos" : ((nfoo > 0) ? "%d foo" : "%ld foos"), nfoo); /* { dg-warning "long int" "wrong type" } */
-  printf ((nfoo > 1) ? "%ld foos" : ((nfoo > 0) ? "%d foo" : "%d foos"), nfoo); /* { dg-warning "long int" "wrong type" } */
-  printf ((nfoo > 1) ? "%d foos" : ((nfoo > 0) ? "%ld foo" : "%d foos"), nfoo); /* { dg-warning "long int" "wrong type" } */
+  printf ((nfoo > 1) ? "%d foos" : ((nfoo > 0) ? "%d foo" : "%ld foos"), nfoo); /* { dg-warning "61:long int" "wrong type" } */
+  printf ((nfoo > 1) ? "%ld foos" : ((nfoo > 0) ? "%d foo" : "%d foos"), nfoo); /* { dg-warning "24:long int" "wrong type" } */
+  printf ((nfoo > 1) ? "%d foos" : ((nfoo > 0) ? "%ld foo" : "%d foos"), nfoo); /* { dg-warning "50:long int" "wrong type" } */
   /* Extra arguments to NULL should be complained about.  */
-  printf (NULL, "foo"); /* { dg-warning "too many" "NULL extra args" } */
-  /* { dg-warning "null" "null format arg" { target *-*-* } 25 } */
+  printf (0, "foo"); /* { dg-warning "14:too many" "NULL extra args" } */
+  /* { dg-warning "null" "null format arg" { target *-*-* } 26 } */
 }
Index: gcc/testsuite/gcc.dg/format/c90-printf-1.c
===================================================================
--- gcc/testsuite/gcc.dg/format/c90-printf-1.c	(revision 213927)
+++ gcc/testsuite/gcc.dg/format/c90-printf-1.c	(working copy)
@@ -32,32 +32,32 @@  foo (int i, int i1, int i2, unsigned int
   /* GCC has objected to the next one in the past, but it is a valid way
      of specifying zero precision.
   */
   printf ("%.e\n", d); /* { dg-bogus "precision" "bogus precision warning" } */
   /* Bogus use of width.  */
-  printf ("%5n\n", n); /* { dg-warning "width" "width with %n" } */
+  printf ("%5n\n", n); /* { dg-warning "11:width" "width with %n" } */
   /* Erroneous, ignored or pointless constructs with precision.  */
   /* Whether negative values for precision may be included in the format
      string is not entirely clear; presume not, following Clive Feather's
      proposed resolution to DR#220 against C99.  In any case, such a
      construct should be warned about.
   */
-  printf ("%.-5d\n", i); /* { dg-warning "format|precision" "negative precision warning" } */
-  printf ("%.-*d\n", i); /* { dg-warning "format" "broken %.-*d format" } */
-  printf ("%.3c\n", i); /* { dg-warning "precision" "precision with %c" } */
-  printf ("%.3p\n", p); /* { dg-warning "precision" "precision with %p" } */
-  printf ("%.3n\n", n); /* { dg-warning "precision" "precision with %n" } */
+  printf ("%.-5d\n", i); /* { dg-warning "11:format|precision" "negative precision warning" } */
+  printf ("%.-*d\n", i); /* { dg-warning "11:format" "broken %.-*d format" } */
+  printf ("%.3c\n", i); /* { dg-warning "11:precision" "precision with %c" } */
+  printf ("%.3p\n", p); /* { dg-warning "11:precision" "precision with %p" } */
+  printf ("%.3n\n", n); /* { dg-warning "11:precision" "precision with %n" } */
   /* Valid and invalid %% constructions.  Some of the warning messages
      are non-optimal, but they do detect the errorneous nature of the
      format string.
   */
   printf ("%%");
-  printf ("%.3%"); /* { dg-warning "format" "bogus %%" } */
-  printf ("%-%"); /* { dg-warning "format" "bogus %%" } */
-  printf ("%-%\n"); /* { dg-warning "format" "bogus %%" } */
-  printf ("%5%\n"); /* { dg-warning "format" "bogus %%" } */
-  printf ("%h%\n"); /* { dg-warning "format" "bogus %%" } */
+  printf ("%.3%"); /* { dg-warning "11:format" "bogus %%" } */
+  printf ("%-%"); /* { dg-warning "11:format" "bogus %%" } */
+  printf ("%-%\n"); /* { dg-warning "11:format" "bogus %%" } */
+  printf ("%5%\n"); /* { dg-warning "11:format" "bogus %%" } */
+  printf ("%h%\n"); /* { dg-warning "11:format" "bogus %%" } */
   /* Valid and invalid %h, %l, %L constructions.  */
   printf ("%hd", i);
   printf ("%hi", i);
   /* Strictly, these parameters should be int or unsigned int according to
      what unsigned short promotes to.  However, GCC ignores sign
@@ -65,126 +65,126 @@  foo (int i, int i1, int i2, unsigned int
      correct checking without print_char_table needing to know whether
      int and short are the same size.
   */
   printf ("%ho%hu%hx%hX", u, u, u, u);
   printf ("%hn", hn);
-  printf ("%hf", d); /* { dg-warning "length" "bad use of %h" } */
-  printf ("%he", d); /* { dg-warning "length" "bad use of %h" } */
-  printf ("%hE", d); /* { dg-warning "length" "bad use of %h" } */
-  printf ("%hg", d); /* { dg-warning "length" "bad use of %h" } */
-  printf ("%hG", d); /* { dg-warning "length" "bad use of %h" } */
-  printf ("%hc", i); /* { dg-warning "length" "bad use of %h" } */
-  printf ("%hs", s); /* { dg-warning "length" "bad use of %h" } */
-  printf ("%hp", p); /* { dg-warning "length" "bad use of %h" } */
-  printf ("%h"); /* { dg-warning "conversion lacks type" "bare %h" } */
-  printf ("%h."); /* { dg-warning "conversion" "bogus %h." } */
+  printf ("%hf", d); /* { dg-warning "11:length" "bad use of %h" } */
+  printf ("%he", d); /* { dg-warning "11:length" "bad use of %h" } */
+  printf ("%hE", d); /* { dg-warning "11:length" "bad use of %h" } */
+  printf ("%hg", d); /* { dg-warning "11:length" "bad use of %h" } */
+  printf ("%hG", d); /* { dg-warning "11:length" "bad use of %h" } */
+  printf ("%hc", i); /* { dg-warning "11:length" "bad use of %h" } */
+  printf ("%hs", s); /* { dg-warning "11:length" "bad use of %h" } */
+  printf ("%hp", p); /* { dg-warning "11:length" "bad use of %h" } */
+  printf ("%h"); /* { dg-warning "11:conversion lacks type" "bare %h" } */
+  printf ("%h."); /* { dg-warning "11:conversion" "bogus %h." } */
   printf ("%ld%li%lo%lu%lx%lX", l, l, ul, ul, ul, ul);
   printf ("%ln", ln);
-  printf ("%lf", d); /* { dg-warning "length|C" "bad use of %l" } */
-  printf ("%le", d); /* { dg-warning "length|C" "bad use of %l" } */
-  printf ("%lE", d); /* { dg-warning "length|C" "bad use of %l" } */
-  printf ("%lg", d); /* { dg-warning "length|C" "bad use of %l" } */
-  printf ("%lG", d); /* { dg-warning "length|C" "bad use of %l" } */
-  printf ("%lp", p); /* { dg-warning "length|C" "bad use of %l" } */
+  printf ("%lf", d); /* { dg-warning "11:length|C" "bad use of %l" } */
+  printf ("%le", d); /* { dg-warning "11:length|C" "bad use of %l" } */
+  printf ("%lE", d); /* { dg-warning "11:length|C" "bad use of %l" } */
+  printf ("%lg", d); /* { dg-warning "11:length|C" "bad use of %l" } */
+  printf ("%lG", d); /* { dg-warning "11:length|C" "bad use of %l" } */
+  printf ("%lp", p); /* { dg-warning "11:length|C" "bad use of %l" } */
   /* These next two were added in C94, but should be objected to in C90.
      For the first one, GCC has wanted wchar_t instead of the correct C94
      and C99 wint_t.
   */
-  printf ("%lc", lc); /* { dg-warning "length|C" "C90 bad use of %l" } */
-  printf ("%ls", ls); /* { dg-warning "length|C" "C90 bad use of %l" } */
+  printf ("%lc", lc); /* { dg-warning "11:length|C" "C90 bad use of %l" } */
+  printf ("%ls", ls); /* { dg-warning "11:length|C" "C90 bad use of %l" } */
   /* These uses of %L are legitimate, though GCC has wrongly warned for
      them in the past.
   */
   printf ("%Le%LE%Lf%Lg%LG", ld, ld, ld, ld, ld);
   /* These next six are accepted by GCC as referring to long long,
      but -pedantic correctly warns.
   */
-  printf ("%Ld", ll); /* { dg-warning "does not support" "bad use of %L" } */
-  printf ("%Li", ll); /* { dg-warning "does not support" "bad use of %L" } */
-  printf ("%Lo", ull); /* { dg-warning "does not support" "bad use of %L" } */
-  printf ("%Lu", ull); /* { dg-warning "does not support" "bad use of %L" } */
-  printf ("%Lx", ull); /* { dg-warning "does not support" "bad use of %L" } */
-  printf ("%LX", ull); /* { dg-warning "does not support" "bad use of %L" } */
-  printf ("%Lc", i); /* { dg-warning "length" "bad use of %L" } */
-  printf ("%Ls", s); /* { dg-warning "length" "bad use of %L" } */
-  printf ("%Lp", p); /* { dg-warning "length" "bad use of %L" } */
-  printf ("%Ln", n); /* { dg-warning "length" "bad use of %L" } */
+  printf ("%Ld", ll); /* { dg-warning "11:does not support" "bad use of %L" } */
+  printf ("%Li", ll); /* { dg-warning "11:does not support" "bad use of %L" } */
+  printf ("%Lo", ull); /* { dg-warning "11:does not support" "bad use of %L" } */
+  printf ("%Lu", ull); /* { dg-warning "11:does not support" "bad use of %L" } */
+  printf ("%Lx", ull); /* { dg-warning "11:does not support" "bad use of %L" } */
+  printf ("%LX", ull); /* { dg-warning "11:does not support" "bad use of %L" } */
+  printf ("%Lc", i); /* { dg-warning "11:length" "bad use of %L" } */
+  printf ("%Ls", s); /* { dg-warning "11:length" "bad use of %L" } */
+  printf ("%Lp", p); /* { dg-warning "11:length" "bad use of %L" } */
+  printf ("%Ln", n); /* { dg-warning "11:length" "bad use of %L" } */
   /* Valid uses of each bare conversion.  */
   printf ("%d%i%o%u%x%X%f%e%E%g%G%c%s%p%n%%", i, i, u, u, u, u, d, d, d, d, d,
 	  i, s, p, n);
   /* Uses of the - flag (valid on all non-%, non-n conversions).  */
   printf ("%-d%-i%-o%-u%-x%-X%-f%-e%-E%-g%-G%-c%-s%-p", i, i, u, u, u, u,
 	  d, d, d, d, d, i, s, p);
-  printf ("%-n", n); /* { dg-warning "flag" "bad use of %-n" } */
+  printf ("%-n", n); /* { dg-warning "11:flag" "bad use of %-n" } */
   /* Uses of the + flag (valid on signed conversions only).  */
   printf ("%+d%+i%+f%+e%+E%+g%+G\n", i, i, d, d, d, d, d);
-  printf ("%+o", u); /* { dg-warning "flag" "bad use of + flag" } */
-  printf ("%+u", u); /* { dg-warning "flag" "bad use of + flag" } */
-  printf ("%+x", u); /* { dg-warning "flag" "bad use of + flag" } */
-  printf ("%+X", u); /* { dg-warning "flag" "bad use of + flag" } */
-  printf ("%+c", i); /* { dg-warning "flag" "bad use of + flag" } */
-  printf ("%+s", s); /* { dg-warning "flag" "bad use of + flag" } */
-  printf ("%+p", p); /* { dg-warning "flag" "bad use of + flag" } */
-  printf ("%+n", n); /* { dg-warning "flag" "bad use of + flag" } */
+  printf ("%+o", u); /* { dg-warning "11:flag" "bad use of + flag" } */
+  printf ("%+u", u); /* { dg-warning "11:flag" "bad use of + flag" } */
+  printf ("%+x", u); /* { dg-warning "11:flag" "bad use of + flag" } */
+  printf ("%+X", u); /* { dg-warning "11:flag" "bad use of + flag" } */
+  printf ("%+c", i); /* { dg-warning "11:flag" "bad use of + flag" } */
+  printf ("%+s", s); /* { dg-warning "11:flag" "bad use of + flag" } */
+  printf ("%+p", p); /* { dg-warning "11:flag" "bad use of + flag" } */
+  printf ("%+n", n); /* { dg-warning "11:flag" "bad use of + flag" } */
   /* Uses of the space flag (valid on signed conversions only, and ignored
      with +).
   */
-  printf ("% +d", i); /* { dg-warning "use of both|ignored" "use of space and + flags" } */
-  printf ("%+ d", i); /* { dg-warning "use of both|ignored" "use of space and + flags" } */
+  printf ("% +d", i); /* { dg-warning "11:use of both|ignored" "use of space and + flags" } */
+  printf ("%+ d", i); /* { dg-warning "11:use of both|ignored" "use of space and + flags" } */
   printf ("% d% i% f% e% E% g% G\n", i, i, d, d, d, d, d);
-  printf ("% o", u); /* { dg-warning "flag" "bad use of space flag" } */
-  printf ("% u", u); /* { dg-warning "flag" "bad use of space flag" } */
-  printf ("% x", u); /* { dg-warning "flag" "bad use of space flag" } */
-  printf ("% X", u); /* { dg-warning "flag" "bad use of space flag" } */
-  printf ("% c", i); /* { dg-warning "flag" "bad use of space flag" } */
-  printf ("% s", s); /* { dg-warning "flag" "bad use of space flag" } */
-  printf ("% p", p); /* { dg-warning "flag" "bad use of space flag" } */
-  printf ("% n", n); /* { dg-warning "flag" "bad use of space flag" } */
+  printf ("% o", u); /* { dg-warning "11:flag" "bad use of space flag" } */
+  printf ("% u", u); /* { dg-warning "11:flag" "bad use of space flag" } */
+  printf ("% x", u); /* { dg-warning "11:flag" "bad use of space flag" } */
+  printf ("% X", u); /* { dg-warning "11:flag" "bad use of space flag" } */
+  printf ("% c", i); /* { dg-warning "11:flag" "bad use of space flag" } */
+  printf ("% s", s); /* { dg-warning "11:flag" "bad use of space flag" } */
+  printf ("% p", p); /* { dg-warning "11:flag" "bad use of space flag" } */
+  printf ("% n", n); /* { dg-warning "11:flag" "bad use of space flag" } */
   /* Uses of the # flag.  */
   printf ("%#o%#x%#X%#e%#E%#f%#g%#G", u, u, u, d, d, d, d, d);
-  printf ("%#d", i); /* { dg-warning "flag" "bad use of # flag" } */
-  printf ("%#i", i); /* { dg-warning "flag" "bad use of # flag" } */
-  printf ("%#u", u); /* { dg-warning "flag" "bad use of # flag" } */
-  printf ("%#c", i); /* { dg-warning "flag" "bad use of # flag" } */
-  printf ("%#s", s); /* { dg-warning "flag" "bad use of # flag" } */
-  printf ("%#p", p); /* { dg-warning "flag" "bad use of # flag" } */
-  printf ("%#n", n); /* { dg-warning "flag" "bad use of # flag" } */
+  printf ("%#d", i); /* { dg-warning "11:flag" "bad use of # flag" } */
+  printf ("%#i", i); /* { dg-warning "11:flag" "bad use of # flag" } */
+  printf ("%#u", u); /* { dg-warning "11:flag" "bad use of # flag" } */
+  printf ("%#c", i); /* { dg-warning "11:flag" "bad use of # flag" } */
+  printf ("%#s", s); /* { dg-warning "11:flag" "bad use of # flag" } */
+  printf ("%#p", p); /* { dg-warning "11:flag" "bad use of # flag" } */
+  printf ("%#n", n); /* { dg-warning "11:flag" "bad use of # flag" } */
   /* Uses of the 0 flag.  */
   printf ("%08d%08i%08o%08u%08x%08X%08e%08E%08f%08g%08G", i, i, u, u, u, u,
 	  d, d, d, d, d);
-  printf ("%0c", i); /* { dg-warning "flag" "bad use of 0 flag" } */
-  printf ("%0s", s); /* { dg-warning "flag" "bad use of 0 flag" } */
-  printf ("%0p", p); /* { dg-warning "flag" "bad use of 0 flag" } */
-  printf ("%0n", n); /* { dg-warning "flag" "bad use of 0 flag" } */
+  printf ("%0c", i); /* { dg-warning "11:flag" "bad use of 0 flag" } */
+  printf ("%0s", s); /* { dg-warning "11:flag" "bad use of 0 flag" } */
+  printf ("%0p", p); /* { dg-warning "11:flag" "bad use of 0 flag" } */
+  printf ("%0n", n); /* { dg-warning "11:flag" "bad use of 0 flag" } */
   /* 0 flag ignored with precision for certain types, not others.  */
-  printf ("%08.5d", i); /* { dg-warning "ignored" "0 flag ignored with precision" } */
-  printf ("%08.5i", i); /* { dg-warning "ignored" "0 flag ignored with precision" } */
-  printf ("%08.5o", u); /* { dg-warning "ignored" "0 flag ignored with precision" } */
-  printf ("%08.5u", u); /* { dg-warning "ignored" "0 flag ignored with precision" } */
-  printf ("%08.5x", u); /* { dg-warning "ignored" "0 flag ignored with precision" } */
-  printf ("%08.5X", u); /* { dg-warning "ignored" "0 flag ignored with precision" } */
+  printf ("%08.5d", i); /* { dg-warning "11:ignored" "0 flag ignored with precision" } */
+  printf ("%08.5i", i); /* { dg-warning "11:ignored" "0 flag ignored with precision" } */
+  printf ("%08.5o", u); /* { dg-warning "11:ignored" "0 flag ignored with precision" } */
+  printf ("%08.5u", u); /* { dg-warning "11:ignored" "0 flag ignored with precision" } */
+  printf ("%08.5x", u); /* { dg-warning "11:ignored" "0 flag ignored with precision" } */
+  printf ("%08.5X", u); /* { dg-warning "11:ignored" "0 flag ignored with precision" } */
   printf ("%08.5f%08.5e%08.5E%08.5g%08.5G", d, d, d, d, d);
   /* 0 flag ignored with - flag.  */
-  printf ("%-08d", i); /* { dg-warning "flags|ignored" "0 flag ignored with - flag" } */
-  printf ("%-08i", i); /* { dg-warning "flags|ignored" "0 flag ignored with - flag" } */
-  printf ("%-08o", u); /* { dg-warning "flags|ignored" "0 flag ignored with - flag" } */
-  printf ("%-08u", u); /* { dg-warning "flags|ignored" "0 flag ignored with - flag" } */
-  printf ("%-08x", u); /* { dg-warning "flags|ignored" "0 flag ignored with - flag" } */
-  printf ("%-08X", u); /* { dg-warning "flags|ignored" "0 flag ignored with - flag" } */
-  printf ("%-08e", d); /* { dg-warning "flags|ignored" "0 flag ignored with - flag" } */
-  printf ("%-08E", d); /* { dg-warning "flags|ignored" "0 flag ignored with - flag" } */
-  printf ("%-08f", d); /* { dg-warning "flags|ignored" "0 flag ignored with - flag" } */
-  printf ("%-08g", d); /* { dg-warning "flags|ignored" "0 flag ignored with - flag" } */
-  printf ("%-08G", d); /* { dg-warning "flags|ignored" "0 flag ignored with - flag" } */
+  printf ("%-08d", i); /* { dg-warning "11:flags|ignored" "0 flag ignored with - flag" } */
+  printf ("%-08i", i); /* { dg-warning "11:flags|ignored" "0 flag ignored with - flag" } */
+  printf ("%-08o", u); /* { dg-warning "11:flags|ignored" "0 flag ignored with - flag" } */
+  printf ("%-08u", u); /* { dg-warning "11:flags|ignored" "0 flag ignored with - flag" } */
+  printf ("%-08x", u); /* { dg-warning "11:flags|ignored" "0 flag ignored with - flag" } */
+  printf ("%-08X", u); /* { dg-warning "11:flags|ignored" "0 flag ignored with - flag" } */
+  printf ("%-08e", d); /* { dg-warning "11:flags|ignored" "0 flag ignored with - flag" } */
+  printf ("%-08E", d); /* { dg-warning "11:flags|ignored" "0 flag ignored with - flag" } */
+  printf ("%-08f", d); /* { dg-warning "11:flags|ignored" "0 flag ignored with - flag" } */
+  printf ("%-08g", d); /* { dg-warning "11:flags|ignored" "0 flag ignored with - flag" } */
+  printf ("%-08G", d); /* { dg-warning "11:flags|ignored" "0 flag ignored with - flag" } */
   /* Various tests of bad argument types.  */
-  printf ("%d", l); /* { dg-warning "format" "bad argument types" } */
-  printf ("%*.*d", l, i2, i); /* { dg-warning "field" "bad * argument types" } */
-  printf ("%*.*d", i1, l, i); /* { dg-warning "field" "bad * argument types" } */
-  printf ("%ld", i); /* { dg-warning "format" "bad argument types" } */
-  printf ("%s", n); /* { dg-warning "format" "bad argument types" } */
-  printf ("%p", i); /* { dg-warning "format" "bad argument types" } */
-  printf ("%n", p); /* { dg-warning "format" "bad argument types" } */
+  printf ("%d", l); /* { dg-warning "11:format" "bad argument types" } */
+  printf ("%*.*d", l, i2, i); /* { dg-warning "11:field" "bad * argument types" } */
+  printf ("%*.*d", i1, l, i); /* { dg-warning "11:field" "bad * argument types" } */
+  printf ("%ld", i); /* { dg-warning "11:format" "bad argument types" } */
+  printf ("%s", n); /* { dg-warning "11:format" "bad argument types" } */
+  printf ("%p", i); /* { dg-warning "11:format" "bad argument types" } */
+  printf ("%n", p); /* { dg-warning "11:format" "bad argument types" } */
   /* With -pedantic, we want some further checks for pointer targets:
      %p should allow only pointers to void (possibly qualified) and
      to character types (possibly qualified), but not function pointers
      or pointers to other types.  (Whether, in fact, character types are
      allowed here is unclear; see thread on comp.std.c, July 2000 for
@@ -194,22 +194,22 @@  foo (int i, int i1, int i2, unsigned int
      pointer targets differ in signedness, except in some circumstances
      for character pointers.  (In C99 we should consider warning for
      char * or unsigned char * being passed to %hhn, even if strictly
      legitimate by the standard.)
   */
-  printf ("%p", foo); /* { dg-warning "format" "bad argument types" } */
-  printf ("%n", un); /* { dg-warning "format" "bad argument types" } */
-  printf ("%p", n); /* { dg-warning "format" "bad argument types" } */
+  printf ("%p", foo); /* { dg-warning "11:format" "bad argument types" } */
+  printf ("%n", un); /* { dg-warning "11:format" "bad argument types" } */
+  printf ("%p", n); /* { dg-warning "11:format" "bad argument types" } */
   /* Allow character pointers with %p.  */
   printf ("%p%p%p%p", s, ss, us, css);
   /* %s allows any character type.  */
   printf ("%s%s%s%s", s, ss, us, css);
   /* Warning for void * arguments for %s is GCC's historical behavior,
      and seems useful to keep, even if some standard versions might be
      read to permit it.
   */
-  printf ("%s", p); /* { dg-warning "format" "bad argument types" } */
+  printf ("%s", p); /* { dg-warning "11:format" "bad argument types" } */
   /* The historical behavior is to allow signed / unsigned types
      interchangeably as arguments.  For values representable in both types,
      such usage may be correct.  For now preserve the behavior of GCC
      in such cases.
   */
@@ -218,20 +218,20 @@  foo (int i, int i1, int i2, unsigned int
      GCC has been inconsistent and allowed unsigned for width but not
      precision.
   */
   printf ("%*.*d", u1, u2, i);
   /* Wrong number of arguments.  */
-  printf ("%d%d", i); /* { dg-warning "matching" "wrong number of args" } */
-  printf ("%d", i, i); /* { dg-warning "arguments" "wrong number of args" } */
+  printf ("%d%d", i); /* { dg-warning "11:matching" "wrong number of args" } */
+  printf ("%d", i, i); /* { dg-warning "11:arguments" "wrong number of args" } */
   /* Miscellaneous bogus constructions.  */
-  printf (""); /* { dg-warning "zero-length" "warning for empty format" } */
-  printf ("\0"); /* { dg-warning "embedded" "warning for embedded NUL" } */
-  printf ("%d\0", i); /* { dg-warning "embedded" "warning for embedded NUL" } */
-  printf ("%d\0%d", i, i); /* { dg-warning "embedded|too many" "warning for embedded NUL" } */
-  printf (NULL); /* { dg-warning "null" "null format string warning" } */
-  printf ("%"); /* { dg-warning "trailing" "trailing % warning" } */
-  printf ("%++d", i); /* { dg-warning "repeated" "repeated flag warning" } */
-  printf ("%n", cn); /* { dg-warning "constant" "%n with const" } */
-  printf ((const char *)L"foo"); /* { dg-warning "wide" "wide string" } */
-  printf ("%n", (int *)0); /* { dg-warning "null" "%n with NULL" } */
-  printf ("%s", (char *)0); /* { dg-warning "null" "%s with NULL" } */
+  printf (""); /* { dg-warning "11:zero-length" "warning for empty format" } */
+  printf ("\0"); /* { dg-warning "11:embedded" "warning for embedded NUL" } */
+  printf ("%d\0", i); /* { dg-warning "11:embedded" "warning for embedded NUL" } */
+  printf ("%d\0%d", i, i); /* { dg-warning "11:embedded|too many" "warning for embedded NUL" } */
+  printf (NULL); /* { dg-warning "3:null" "null format string warning" } */
+  printf ("%"); /* { dg-warning "11:trailing" "trailing % warning" } */
+  printf ("%++d", i); /* { dg-warning "11:repeated" "repeated flag warning" } */
+  printf ("%n", cn); /* { dg-warning "3:constant" "%n with const" } */
+  printf ((const char *)L"foo"); /* { dg-warning "25:wide" "wide string" } */
+  printf ("%n", (int *)0); /* { dg-warning "3:null" "%n with NULL" } */
+  printf ("%s", (char *)0); /* { dg-warning "3:null" "%s with NULL" } */
 }