public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* Re: Ping - old patch from April - mingw support for I32/I64 MS printf formatters to c-format.c
@ 2008-03-13 22:38 FX Coudert
  2008-03-14  1:33 ` Joseph S. Myers
  2008-03-16  7:58 ` Danny Smith
  0 siblings, 2 replies; 61+ messages in thread
From: FX Coudert @ 2008-03-13 22:38 UTC (permalink / raw)
  To: gcc patches, Danny Smith, Kai Tietz

Hi Danny,

I see you're running the testsuite on mingw. How are you doing it?  
I've tried quite a few things, but none of them worked. I've asked on  
various lists (including here and on the mingw list some time ago),  
but have never found somone to explain or give a link to  
documentation explaining how to do it.

Also, could you post the results to gcc-testresults?

Thanks,
FX

-- 
François-Xavier Coudert
http://www.homepages.ucl.ac.uk/~uccafco/

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf  formatters to c-format.c
  2008-03-13 22:38 Ping - old patch from April - mingw support for I32/I64 MS printf formatters to c-format.c FX Coudert
@ 2008-03-14  1:33 ` Joseph S. Myers
  2008-03-16  7:58 ` Danny Smith
  1 sibling, 0 replies; 61+ messages in thread
From: Joseph S. Myers @ 2008-03-14  1:33 UTC (permalink / raw)
  To: FX Coudert; +Cc: gcc patches, Danny Smith, Kai Tietz

On Thu, 13 Mar 2008, FX Coudert wrote:

> Hi Danny,
> 
> I see you're running the testsuite on mingw. How are you doing it? I've tried
> quite a few things, but none of them worked. I've asked on various lists
> (including here and on the mingw list some time ago), but have never found
> somone to explain or give a link to documentation explaining how to do it.

I can't speak for how Danny runs the tests, but I test cross compilers 
from GNU/Linux to MinGW (using Cygwin sshd for remote login to the Windows 
system).  I have posted results: 
<http://gcc.gnu.org/ml/gcc-testresults/2008-02/msg01726.html>.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf formatters to c-format.c
  2008-03-13 22:38 Ping - old patch from April - mingw support for I32/I64 MS printf formatters to c-format.c FX Coudert
  2008-03-14  1:33 ` Joseph S. Myers
@ 2008-03-16  7:58 ` Danny Smith
  1 sibling, 0 replies; 61+ messages in thread
From: Danny Smith @ 2008-03-16  7:58 UTC (permalink / raw)
  To: FX Coudert; +Cc: gcc patches, Danny Smith, Kai Tietz

On Fri, Mar 14, 2008 at 11:21 AM, FX Coudert <fxcoudert@gmail.com> wrote:
> Hi Danny,
>
>  I see you're running the testsuite on mingw. How are you doing it?

I use cygwin bash, make, autotools,etc with my mingw gcc toolchain.
To make it easier I create mounts that translate identically with
cygwin tools and native exes.

C:\cygwin\lib on /usr/lib type system (binmode)
C:\cygwin\usr on /usr type system (binmode)
c:\cygwin\bin on /bin type system (binmode)
c:\cygwin\bin on /usr/bin type system (binmode)
c:\develop on /develop type system (binmode)  <<< "identity" mount
C:\cygwin on / type system (binmode)
c:\Users on /home type system (binmode)
c:\mingw on /mingw type system (binmode)  <<< "identity" mount
c: on /cygdrive/c type system (binmode,noumount)
e: on /cygdrive/e type system (binmode,noumount)
f: on /cygdrive/f type system (binmode,noumount)
g: on /cygdrive/g type system (binmode,noumount)
z: on /cygdrive/z type system (binmode,noumount)

All development sources and builds live in the /develop mount

I also set

DEJAGNULIBS=/usr/share/dejagnu
TCL_LIBRARY=/usr/share/tcl8.4
 as envirnonmental variables

Then the the dejagnu installed  by cygwin's setup just works.


>  I've tried quite a few things, but none of them worked. I've asked on
>  various lists (including here and on the mingw list some time ago),
>  but have never found somone to explain or give a link to
>  documentation explaining how to do it.

I don't know how to make dejagnu work with MSYS. The cygwin-based
environment that I use appears to be more stable (it has worked for my
builds gcc since 2001).

Danny

>
>  Also, could you post the results to gcc-testresults?
>

Yes I will.
Danny

>  Thanks,
>  FX
>
>  --
>  François-Xavier Coudert
>  http://www.homepages.ucl.ac.uk/~uccafco/
>
>

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf  formatters to c-format.c
  2008-03-20  1:18                                             ` Danny Smith
  2008-03-20  1:18                                               ` NightStrike
@ 2008-03-20  9:54                                               ` Kai Tietz
  1 sibling, 0 replies; 61+ messages in thread
From: Kai Tietz @ 2008-03-20  9:54 UTC (permalink / raw)
  To: Danny Smith; +Cc: GCC Patches, ktietz70, NightStrike

"Danny Smith" <dansmister@gmail.com> wrote on 20.03.2008 00:43:03:

> Hello Kai
> Thank you for your perseverence, Kai.  The mingw32-specific changes in
> the latest patchset are  OK for trunk
> Danny

Committed :)

Cheers
  Kai

|  (\_/)  This is Bunny. Copy and paste Bunny
| (='.'=) into your signature to help him gain
| (")_(") world domination.

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf formatters to c-format.c
  2008-03-20  1:18                                             ` Danny Smith
@ 2008-03-20  1:18                                               ` NightStrike
  2008-03-20  9:54                                               ` Kai Tietz
  1 sibling, 0 replies; 61+ messages in thread
From: NightStrike @ 2008-03-20  1:18 UTC (permalink / raw)
  To: Danny Smith; +Cc: Kai Tietz, GCC Patches, ktietz70

On 3/19/08, Danny Smith <dansmister@gmail.com> wrote:
> Hello Kai
> Thank you for your perseverence, Kai.  The mingw32-specific changes in
> the latest patchset are  OK for trunk
> Danny

Does this mean the patch can be applied?  It's certainly been a long
time coming :)

It's good, though, that you guys are so thorough.

Now we just need to work on why g++/gfortran don't work at all when
run natively :)

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf formatters to c-format.c
  2008-03-19  9:42                                           ` Kai Tietz
  2008-03-19 13:43                                             ` NightStrike
  2008-03-19 13:51                                             ` NightStrike
@ 2008-03-20  1:18                                             ` Danny Smith
  2008-03-20  1:18                                               ` NightStrike
  2008-03-20  9:54                                               ` Kai Tietz
  2 siblings, 2 replies; 61+ messages in thread
From: Danny Smith @ 2008-03-20  1:18 UTC (permalink / raw)
  To: Kai Tietz; +Cc: GCC Patches, ktietz70, NightStrike

On Wed, Mar 19, 2008 at 9:43 PM, Kai Tietz <Kai.Tietz@onevision.com> wrote:
> "Danny Smith" <dansmister@gmail.com> wrote on 19.03.2008 07:01:25:
>

>  > Actually., I think it makes a lot of sense to test whether the
>  > appropriate warning is reported.
>  I agree, that some testcases have to be added to test all ms versus gnu
>  feature set. When the initial patch is applied, we can add the additional
>  necessary testcases. Eg. the test for 'll', additional tests for 'I64',
>  'I32', and 'I' in failure cases (ISO C, wrong type specifiers, etc). For
>  this patch I wanted just to have an initial set of major tests, where
>  others can continue on.
>
>
>  > Also, if you look again at the msdn page you will note that the field
>  > width flag (a glibc extensuion) is not documented.
>  > Indeed if you test a format like "%5m", you will see that it  produces
>  > this as output:  "m"   The use of  this flag should produce a warning.
>  You are right, I removed the 'w' flag for ms_strftime.
>

Hello Kai
Thank you for your perseverence, Kai.  The mingw32-specific changes in
the latest patchset are  OK for trunk
Danny



>  Cheers,
>   Kai
>
>
>
>  PS:  NightStrike could you rerun the testsuite? Thanks in advance.
>
>
>
>  |  (\_/)  This is Bunny. Copy and paste Bunny
>  | (='.'=) into your signature to help him gain
>  | (")_(") world domination.
>

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf formatters to c-format.c
  2008-03-19  9:42                                           ` Kai Tietz
  2008-03-19 13:43                                             ` NightStrike
@ 2008-03-19 13:51                                             ` NightStrike
  2008-03-20  1:18                                             ` Danny Smith
  2 siblings, 0 replies; 61+ messages in thread
From: NightStrike @ 2008-03-19 13:51 UTC (permalink / raw)
  To: Kai Tietz; +Cc: Danny Smith, GCC Patches, ktietz70

[-- Attachment #1: Type: text/plain, Size: 345 bytes --]

On 3/19/08, Kai Tietz <Kai.Tietz@onevision.com> wrote:
> PS:  NightStrike could you rerun the testsuite? Thanks in advance.

                === gcc Summary ===

# of expected passes            3946
# of unsupported tests          12
/tmp/build/gcc-svn/build-x86_64-pc-linux/gcc/xgcc  version 4.4.0
20080319 (experimental) (GCC)


Log attached.

[-- Attachment #2: gcc.log.bz2 --]
[-- Type: application/x-bzip2, Size: 31254 bytes --]

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf formatters to c-format.c
  2008-03-19  9:42                                           ` Kai Tietz
@ 2008-03-19 13:43                                             ` NightStrike
  2008-03-19 13:51                                             ` NightStrike
  2008-03-20  1:18                                             ` Danny Smith
  2 siblings, 0 replies; 61+ messages in thread
From: NightStrike @ 2008-03-19 13:43 UTC (permalink / raw)
  To: Kai Tietz; +Cc: Danny Smith, GCC Patches, ktietz70

On 3/19/08, Kai Tietz <Kai.Tietz@onevision.com> wrote:
> PS:  NightStrike could you rerun the testsuite? Thanks in advance.

Ah, you're killin' me, man :) :) :)

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf  formatters to c-format.c
  2008-03-19  6:22                                         ` Danny Smith
@ 2008-03-19  9:42                                           ` Kai Tietz
  2008-03-19 13:43                                             ` NightStrike
                                                               ` (2 more replies)
  0 siblings, 3 replies; 61+ messages in thread
From: Kai Tietz @ 2008-03-19  9:42 UTC (permalink / raw)
  To: Danny Smith; +Cc: GCC Patches, ktietz70, NightStrike

[-- Attachment #1: Type: text/plain, Size: 1568 bytes --]

"Danny Smith" <dansmister@gmail.com> wrote on 19.03.2008 07:01:25:

> On Wed, Mar 19, 2008 at 3:34 AM, Kai Tietz <Kai.Tietz@onevision.com> 
wrote:
> > NightStrike <nightstrike@gmail.com> wrote on 18.03.2008 14:34:11:
> >
> >
> > > Attached is the gcc test log for formatters for this latest patch
> >  > (recompiled and retested in like 10 minutes :)
> >
> >  Sorry, this was a typo of mine. I removed the testcase ms_warnll-1.c
> >  completly. It makes not so much sense to check ISO C90 ll for mingw 
:)
> >  I attached the updated patch.
> 
> Actually., I think it makes a lot of sense to test whether the
> appropriate warning is reported.
I agree, that some testcases have to be added to test all ms versus gnu 
feature set. When the initial patch is applied, we can add the additional 
necessary testcases. Eg. the test for 'll', additional tests for 'I64', 
'I32', and 'I' in failure cases (ISO C, wrong type specifiers, etc). For 
this patch I wanted just to have an initial set of major tests, where 
others can continue on.

> Also, if you look again at the msdn page you will note that the field
> width flag (a glibc extensuion) is not documented.
> Indeed if you test a format like "%5m", you will see that it  produces
> this as output:  "m"   The use of  this flag should produce a warning.
You are right, I removed the 'w' flag for ms_strftime.

Cheers,
  Kai



PS:  NightStrike could you rerun the testsuite? Thanks in advance.

|  (\_/)  This is Bunny. Copy and paste Bunny
| (='.'=) into your signature to help him gain
| (")_(") world domination.

[-- Attachment #2: mingw-msformat.txt --]
[-- Type: text/plain, Size: 150416 bytes --]

Index: gcc/gcc/c-format.c
===================================================================
--- gcc.orig/gcc/c-format.c
+++ gcc/gcc/c-format.c
@@ -62,8 +62,7 @@ enum format_type { printf_format_type, a
 		   gcc_diag_format_type, gcc_tdiag_format_type,
 		   gcc_cdiag_format_type,
 		   gcc_cxxdiag_format_type, gcc_gfc_format_type,
-		   scanf_format_type, strftime_format_type,
-		   strfmon_format_type, format_type_error = -1};
+		   format_type_error = -1};
 
 typedef struct function_format_info
 {
@@ -80,7 +79,8 @@ static bool check_format_string (tree ar
 				 int flags, bool *no_add_attrs);
 static bool get_constant (tree expr, unsigned HOST_WIDE_INT *value,
 			  int validated_p);
-
+static const char *convert_format_name_to_system_name (const char *attr_name);
+static bool cmp_attribs (const char *tattr_name, const char *attr_name);
 
 /* Handle a "format_arg" attribute; arguments as in
    struct attribute_spec.handler.  */
@@ -191,6 +191,8 @@ decode_format_attr (tree args, function_
     {
       const char *p = IDENTIFIER_POINTER (format_type_id);
 
+      p = convert_format_name_to_system_name (p);
+
       info->format_type = decode_format_type (p);
 
       if (info->format_type == format_type_error)
@@ -715,7 +717,7 @@ static const format_char_info monetary_c
 /* This must be in the same order as enum format_type.  */
 static const format_kind_info format_types_orig[] =
 {
-  { "printf",   printf_length_specs,  print_char_table, " +#0-'I", NULL,
+  { "gnu_printf",   printf_length_specs,  print_char_table, " +#0-'I", NULL,
     printf_flag_specs, printf_flag_pairs,
     FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
     'w', 0, 'p', 0, 'L', 0,
@@ -757,18 +759,18 @@ static const format_kind_info format_typ
     0, 0, 0, 0, 0, 0,
     NULL, NULL
   },
-  { "scanf",    scanf_length_specs,   scan_char_table,  "*'I", NULL,
+  { "gnu_scanf",    scanf_length_specs,   scan_char_table,  "*'I", NULL,
     scanf_flag_specs, scanf_flag_pairs,
     FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
     'w', 0, 0, '*', 'L', 'm',
     NULL, NULL
   },
-  { "strftime", NULL,                 time_char_table,  "_-0^#", "EO",
+  { "gnu_strftime", NULL,                 time_char_table,  "_-0^#", "EO",
     strftime_flag_specs, strftime_flag_pairs,
     FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0, 0,
     NULL, NULL
   },
-  { "strfmon",  strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
+  { "gnu_strfmon",  strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
     strfmon_flag_specs, strfmon_flag_pairs,
     FMT_FLAG_ARG_CONVERT, 'w', '#', 'p', 0, 'L', 0,
     NULL, NULL
@@ -847,6 +849,8 @@ decode_format_type (const char *s)
 {
   int i;
   int slen;
+
+  s = convert_format_name_to_system_name (s);
   slen = strlen (s);
   for (i = 0; i < n_format_types; i++)
     {
@@ -1776,7 +1780,22 @@ check_format_info_main (format_check_res
       if (fli)
 	{
 	  while (fli->name != 0 && fli->name[0] != *format_chars)
-	    fli++;
+	    {
+	      if (fli->name[0] == '\0')
+		{
+		  int si  = strlen (fli->name + 1) + 1;
+		  int i = 1;
+		  while (fli->name[i] != 0 && fli->name[i] == format_chars [i - 1])
+		    ++i;
+		 if (si == i)
+		   {
+		     if (si > 2)
+		       format_chars += si - 2;
+		     break;
+		   }
+	       }
+	      fli++;
+	    }
 	  if (fli->name != 0)
 	    {
 	      format_chars++;
@@ -2703,6 +2722,84 @@ init_dynamic_diag_info (void)
 extern const format_kind_info TARGET_FORMAT_TYPES[];
 #endif
 
+#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+extern const target_ovr_attr TARGET_OVERRIDES_FORMAT_ATTRIBUTES[];
+#endif
+
+/* Attributes such as "printf" are equivalent to those such as
+   "gnu_printf" unless this is overridden by a target.  */
+static const target_ovr_attr gnu_target_overrides_format_attributes[] =
+{
+  { "gnu_printf",   "printf" },
+  { "gnu_scanf",    "scanf" },
+  { "gnu_strftime", "strftime" },
+  { "gnu_strfmon",  "strfmon" },
+  { NULL,           NULL }
+};
+
+/* Translate to unified attribute name. This is used in decode_format_type and
+   decode_format_attr. In attr_name the user specified argument is passed. It
+   returns the unified format name from TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+   or the attr_name passed to this function, if there is no matching entry.  */
+static const char *
+convert_format_name_to_system_name (const char *attr_name)
+{
+  int i;
+
+  if (attr_name == NULL || *attr_name == 0
+      || strncmp (attr_name, "gcc_", 4) == 0)
+    return attr_name;
+
+#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+  /* Check if format attribute is overridden by target.  */
+  if (TARGET_OVERRIDES_FORMAT_ATTRIBUTES != NULL
+      && TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT > 0)
+    {
+      for (i = 0; i < TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT; ++i)
+        {
+          if (cmp_attribs (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src,
+			   attr_name))
+            return attr_name;
+          if (cmp_attribs (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_dst,
+			   attr_name))
+            return TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src;
+        }
+    }
+#endif
+  /* Otherwise default to gnu format.  */
+  for (i = 0;
+       gnu_target_overrides_format_attributes[i].named_attr_src != NULL;
+       ++i)
+    {
+      if (cmp_attribs (gnu_target_overrides_format_attributes[i].named_attr_src,
+		       attr_name))
+        return attr_name;
+      if (cmp_attribs (gnu_target_overrides_format_attributes[i].named_attr_dst,
+		       attr_name))
+        return gnu_target_overrides_format_attributes[i].named_attr_src;
+    }
+
+  return attr_name;
+}
+
+/* Return true if TATTR_NAME and ATTR_NAME are the same format attribute,
+   counting "name" and "__name__" as the same, false otherwise.  */
+static bool
+cmp_attribs (const char *tattr_name, const char *attr_name)
+{
+  int alen = strlen (attr_name);
+  int slen = (tattr_name ? strlen (tattr_name) : 0);
+  if (alen > 4 && attr_name[0] == '_' && attr_name[1] == '_'
+      && attr_name[alen - 1] == '_' && attr_name[alen - 2] == '_')
+    {
+      attr_name += 2;
+      alen -= 4;
+    }
+  if (alen != slen || strncmp (tattr_name, attr_name, alen) != 0)
+    return false;
+  return true;
+}
+
 /* Handle a "format" attribute; arguments as in
    struct attribute_spec.handler.  */
 tree
@@ -2762,7 +2859,10 @@ handle_format_attribute (tree *node, tre
 	}
     }
 
-  if (info.format_type == strftime_format_type && info.first_arg_num != 0)
+  /* Check if this is a strftime variant. Just for this variant
+     FMT_FLAG_ARG_CONVERT is not set.  */
+  if ((format_types[info.format_type].flags & (int) FMT_FLAG_ARG_CONVERT) == 0
+      && info.first_arg_num != 0)
     {
       error ("strftime formats cannot format arguments");
       *no_add_attrs = true;
Index: gcc/gcc/c-format.h
===================================================================
--- gcc.orig/gcc/c-format.h
+++ gcc/gcc/c-format.h
@@ -80,12 +80,13 @@ enum
      of whether length modifiers can occur (length_char_specs).  */
 };
 
-
 /* Structure describing a length modifier supported in format checking, and
    possibly a doubled version such as "hh".  */
 typedef struct
 {
-  /* Name of the single-character length modifier.  */
+  /* Name of the single-character length modifier. If prefixed by
+     a zero character, it describes a multi character length
+     modifier, like I64, I32, etc.  */
   const char *name;
   /* Index into a format_char_info.types array.  */
   enum format_lengths index;
@@ -306,4 +307,16 @@ typedef struct
 #define T_D128  &dfloat128_type_node
 #define TEX_D128 { STD_EXT, "_Decimal128", T_D128 }
 
+/* Structure describing how format attributes such as "printf" are
+   interpreted as "gnu_printf" or "ms_printf" on a particular system.
+   TARGET_OVERRIDES_FORMAT_ATTRIBUTES is used to specify target-specific
+   defaults.  */
+typedef struct
+{
+  /* The name of the to be copied format attribute. */
+  const char *named_attr_src;
+  /* The name of the to be overridden format attribute. */
+  const char *named_attr_dst;
+} target_ovr_attr;
+
 #endif /* GCC_C_FORMAT_H */
Index: gcc/gcc/config.gcc
===================================================================
--- gcc.orig/gcc/config.gcc
+++ gcc/gcc/config.gcc
@@ -1372,8 +1372,8 @@ i[34567]86-*-pe | i[34567]86-*-cygwin*)
 	target_gtfiles="\$(srcdir)/config/i386/winnt.c"
 	extra_options="${extra_options} i386/cygming.opt"
 	extra_objs="winnt.o winnt-stubs.o"
-	c_target_objs=cygwin2.o
-	cxx_target_objs="cygwin2.o winnt-cxx.o"
+	c_target_objs="cygwin2.o msformat-c.o"
+	cxx_target_objs="cygwin2.o winnt-cxx.o msformat-c.o"
 	extra_gcc_objs=cygwin1.o
 	if test x$enable_threads = xyes; then
 		thread_file='posix'
@@ -1386,7 +1386,8 @@ i[34567]86-*-mingw32* | x86_64-*-mingw32
 	target_gtfiles="\$(srcdir)/config/i386/winnt.c"
 	extra_options="${extra_options} i386/cygming.opt"
 	extra_objs="winnt.o winnt-stubs.o"
-	cxx_target_objs=winnt-cxx.o
+	c_target_objs="msformat-c.o"
+	cxx_target_objs="winnt-cxx.o msformat-c.o"
 	default_use_cxa_atexit=yes
 	case ${enable_threads} in
 	  "" | yes | win32)
Index: gcc/gcc/config/i386/mingw32.h
===================================================================
--- gcc.orig/gcc/config/i386/mingw32.h
+++ gcc/gcc/config/i386/mingw32.h
@@ -143,6 +143,23 @@ do {						         \
    to register C++ static destructors.  */
 #define TARGET_CXX_USE_ATEXIT_FOR_CXA_ATEXIT hook_bool_void_true
 
+/* Contains a pointer to type target_ovr_attr defining the target specific
+   overrides of format attributes.  See c-format.h for structure
+   definition.  */
+#undef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+#define TARGET_OVERRIDES_FORMAT_ATTRIBUTES mingw_format_attribute_overrides
+
+/* Specify the count of elements in TARGET_OVERRIDES_ATTRIBUTE.  */
+#undef TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT
+#define TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT 3
+
+/* MS specific format attributes for ms_printf, ms_scanf, ms_strftime.  */
+#undef TARGET_FORMAT_TYPES
+#define TARGET_FORMAT_TYPES mingw_format_attributes
+
+#undef TARGET_N_FORMAT_TYPES
+#define TARGET_N_FORMAT_TYPES 3
+
 /* JCR_SECTION works on mingw32.  */
 #undef TARGET_USE_JCR_SECTION
 #define TARGET_USE_JCR_SECTION 1
Index: gcc/gcc/config/i386/msformat-c.c
===================================================================
--- /dev/null
+++ gcc/gcc/config/i386/msformat-c.c
@@ -0,0 +1,175 @@
+/* Check calls to formatted I/O functions (-Wformat).
+   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+   2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "flags.h"
+#include "c-common.h"
+#include "toplev.h"
+#include "intl.h"
+#include "diagnostic.h"
+#include "langhooks.h"
+#include "c-format.h"
+#include "alloc-pool.h"
+
+/* Mingw specific format attributes ms_printf, ms_scanf, and ms_strftime.  */
+
+static const format_length_info ms_printf_length_specs[] =
+{
+  { "h", FMT_LEN_h, STD_C89, NULL, 0, 0 },
+  { "l", FMT_LEN_l, STD_C89, NULL, 0, 0 },
+  { "\0I32", FMT_LEN_l, STD_EXT, NULL, 0, 0 },
+  { "\0I64", FMT_LEN_ll, STD_EXT, NULL, 0, 0 },
+  { "I", FMT_LEN_L, STD_EXT, NULL, 0, 0 },
+  { NULL, 0, 0, NULL, 0, 0 }
+};
+
+static const format_flag_spec ms_printf_flag_specs[] =
+{
+  { ' ',  0, 0, N_("' ' flag"),        N_("the ' ' printf flag"),              STD_C89 },
+  { '+',  0, 0, N_("'+' flag"),        N_("the '+' printf flag"),              STD_C89 },
+  { '#',  0, 0, N_("'#' flag"),        N_("the '#' printf flag"),              STD_C89 },
+  { '0',  0, 0, N_("'0' flag"),        N_("the '0' printf flag"),              STD_C89 },
+  { '-',  0, 0, N_("'-' flag"),        N_("the '-' printf flag"),              STD_C89 },
+  { '\'', 0, 0, N_("''' flag"),        N_("the ''' printf flag"),              STD_EXT },
+  { 'w',  0, 0, N_("field width"),     N_("field width in printf format"),     STD_C89 },
+  { 'p',  0, 0, N_("precision"),       N_("precision in printf format"),       STD_C89 },
+  { 'L',  0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_printf_flag_pairs[] =
+{
+  { ' ', '+', 1, 0   },
+  { '0', '-', 1, 0   }, { '0', 'p', 1, 'i' },
+  { 0, 0, 0, 0 }
+};
+
+static const format_flag_spec ms_scanf_flag_specs[] =
+{
+  { '*',  0, 0, N_("assignment suppression"), N_("the assignment suppression scanf feature"), STD_C89 },
+  { 'a',  0, 0, N_("'a' flag"),               N_("the 'a' scanf flag"),                       STD_EXT },
+  { 'w',  0, 0, N_("field width"),            N_("field width in scanf format"),              STD_C89 },
+  { 'L',  0, 0, N_("length modifier"),        N_("length modifier in scanf format"),          STD_C89 },
+  { '\'', 0, 0, N_("''' flag"),               N_("the ''' scanf flag"),                       STD_EXT },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_scanf_flag_pairs[] =
+{
+  { '*', 'L', 0, 0 },
+  { 0, 0, 0, 0 }
+};
+
+static const format_flag_spec ms_strftime_flag_specs[] =
+{
+  { '#', 0,   0, N_("'#' flag"),     N_("the '#' strftime flag"),          STD_EXT },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_strftime_flag_pairs[] =
+{
+  { 0, 0, 0, 0 }
+};
+
+static const format_char_info ms_print_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "di",  0, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  T99_SST,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-wp0 +'",  "i",  NULL },
+  { "oxX", 0, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN, BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "-wp0#",     "i",  NULL },
+  { "u",   0, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN, BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "-wp0'",    "i",  NULL },
+  { "fgG", 0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "-wp0 +#'", "",   NULL },
+  { "eE",  0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "-wp0 +#",  "",   NULL },
+  { "c",   0, STD_C89, { T89_I,   BADLEN,  T89_S,  T94_WI,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "",   NULL },
+  { "s",   1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-wp",       "cR", NULL },
+  { "p",   1, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "c",  NULL },
+  { "n",   1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  BADLEN,  BADLEN, BADLEN,  T99_IM,  BADLEN,  BADLEN,  BADLEN }, "",          "W",  NULL },
+  /* X/Open conversion specifiers.  */
+  { "C",   0, STD_EXT, { TEX_WI,  BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "",   NULL },
+  { "S",   1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-wp",       "R",  NULL },
+  { NULL,  0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+static const format_char_info ms_scan_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "di",    1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  T99_SST,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w'", "W",   NULL },
+  { "u",     1, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN,  BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "*w'", "W",   NULL },
+  { "oxX",   1, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN,  BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "efgEG", 1, STD_C89, { T89_F,   BADLEN,  BADLEN,  T89_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "*w'",  "W",   NULL },
+  { "c",     1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "cW",  NULL },
+  { "s",     1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "cW",  NULL },
+  { "[",     1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "cW[", NULL },
+  { "p",     2, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "n",     1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  BADLEN,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "",     "W",   NULL },
+  /* X/Open conversion specifiers.  */
+  { "C",     1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "S",     1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "W",   NULL },
+  { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+static const format_char_info ms_time_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "ABZab",		0, STD_C89, NOLENGTHS, "#",     "",   NULL },
+  { "cx",		0, STD_C89, NOLENGTHS, "#",      "3",  NULL },
+  { "HIMSUWdmw",	0, STD_C89, NOLENGTHS, "#",  "",   NULL },
+  { "j",		0, STD_C89, NOLENGTHS, "#",  "",  NULL },
+  { "p",		0, STD_C89, NOLENGTHS, "#",      "",   NULL },
+  { "X",		0, STD_C89, NOLENGTHS, "#",      "",   NULL },
+  { "y",		0, STD_C89, NOLENGTHS, "#", "4",  NULL },
+  { "Y",		0, STD_C89, NOLENGTHS, "#", "",  NULL },
+  { "%",		0, STD_C89, NOLENGTHS, "",       "",   NULL },
+  /* C99 conversion specifiers.  */
+  { "z",		0, STD_C99, NOLENGTHS, "#",      "",  NULL },
+  { NULL,		0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+const format_kind_info mingw_format_attributes[3] =
+{
+  { "ms_printf",   ms_printf_length_specs,  ms_print_char_table, " +#0-'", NULL,
+    ms_printf_flag_specs, ms_printf_flag_pairs,
+    FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
+    'w', 0, 'p', 0, 'L', 0,
+    &integer_type_node, &integer_type_node
+  },
+  { "ms_scanf",    ms_printf_length_specs,   ms_scan_char_table,  "*'", NULL,
+    ms_scanf_flag_specs, ms_scanf_flag_pairs,
+    FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
+    'w', 0, 0, '*', 'L', 0,
+    NULL, NULL
+  },
+  { "ms_strftime", NULL,                 ms_time_char_table,  "", "#",
+    ms_strftime_flag_specs, ms_strftime_flag_pairs,
+    FMT_FLAG_FANCY_PERCENT_OK, 0, 0, 0, 0, 0, 0,
+    NULL, NULL
+  }
+};
+
+/* Default overrides for printf, scanf and strftime.  */
+const target_ovr_attr mingw_format_attribute_overrides[4] =
+{
+  { "ms_printf", "printf" },
+  { "ms_scanf", "scanf" },
+  { "ms_strftime", "strftime" }
+};
Index: gcc/gcc/config/i386/t-cygming
===================================================================
--- gcc.orig/gcc/config/i386/t-cygming
+++ gcc/gcc/config/i386/t-cygming
@@ -29,4 +29,10 @@ winnt-stubs.o: $(srcdir)/config/i386/win
 	$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
 	$(srcdir)/config/i386/winnt-stubs.c
 
+msformat-c.o: $(srcdir)/config/i386/msformat-c.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
+  $(TM_H) $(RTL_H) $(REGS_H) hard-reg-set.h output.h $(TREE_H) flags.h \
+  $(TM_P_H) toplev.h $(HASHTAB_H) $(GGC_H)
+	$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
+	$(srcdir)/config/i386/msformat-c.c
+
 STMP_FIXINC=stmp-fixinc
Index: gcc/gcc/doc/extend.texi
===================================================================
--- gcc.orig/gcc/doc/extend.texi
+++ gcc/gcc/doc/extend.texi
@@ -2204,13 +2204,22 @@ for consistency with the @code{printf} s
 @code{my_format}.
 
 The parameter @var{archetype} determines how the format string is
-interpreted, and should be @code{printf}, @code{scanf}, @code{strftime}
-or @code{strfmon}.  (You can also use @code{__printf__},
-@code{__scanf__}, @code{__strftime__} or @code{__strfmon__}.)  The
-parameter @var{string-index} specifies which argument is the format
-string argument (starting from 1), while @var{first-to-check} is the
-number of the first argument to check against the format string.  For
-functions where the arguments are not available to be checked (such as
+interpreted, and should be @code{printf}, @code{scanf}, @code{strftime},
+@code{gnu_printf}, @code{gnu_scanf}, @code{gnu_strftime} or
+@code{strfmon}.  (You can also use @code{__printf__},
+@code{__scanf__}, @code{__strftime__} or @code{__strfmon__}.)  On
+MinGW targets, @code{ms_printf}, @code{ms_scanf}, and
+@code{ms_strftime} are also present.
+@var{archtype} values such as @code{printf} refer to the formats accepted
+by the system's C run-time library, while @code{gnu_} values always refer
+to the formats accepted by the GNU C Library.  On Microsoft Windows
+targets, @code{ms_} values refer to the formats accepted by the
+@file{msvcrt.dll} library.
+The parameter @var{string-index}
+specifies which argument is the format string argument (starting
+from 1), while @var{first-to-check} is the number of the first
+argument to check against the format string.  For functions
+where the arguments are not available to be checked (such as
 @code{vprintf}), specify the third parameter as zero.  In this case the
 compiler only checks the format string for consistency.  For
 @code{strftime} formats, the third parameter is required to be zero.
Index: gcc/gcc/doc/tm.texi
===================================================================
--- gcc.orig/gcc/doc/tm.texi
+++ gcc/gcc/doc/tm.texi
@@ -10319,6 +10319,18 @@ If defined, this macro is the number of 
 @code{TARGET_FORMAT_TYPES}.
 @end defmac
 
+@defmac TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+If defined, this macro is the name of a global variable containing
+target-specific format overrides for the @option{-Wformat} option. The
+default is to have no target-specific format overrides. If defined,
+@code{TARGET_FORMAT_TYPES} must be defined, too.
+@end defmac
+
+@defmac TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT
+If defined, this macro specifies the number of entries in
+@code{TARGET_OVERRIDES_FORMAT_ATTRIBUTES}.
+@end defmac
+
 @deftypefn {Target Hook} bool TARGET_RELAXED_ORDERING
 If set to @code{true}, means that the target's memory model does not
 guarantee that loads which do not depend on one another will access
Index: gcc/gcc/testsuite/gcc.dg/format/format.h
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/format.h
+++ gcc/gcc/testsuite/gcc.dg/format/format.h
@@ -1,6 +1,37 @@
 /* Format checking tests: common header.  */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
 
+/* DONT_GNU_PROTOTYPE */
+#if defined (_WIN32) && !defined (__CYGWIN__)
+#if !defined (USE_SYSTEM_FORMATS)
+#define gnu_attr_printf	gnu_printf
+#define gnu_attr___printf__ __gnu_printf__
+#define gnu_attr_scanf	gnu_scanf
+#define gnu_attr___scanf__ __gnu_scanf__
+#define gnu_attr_strftime gnu_strftime
+#define gnu_attr___strftime__ __gnu_strftime__
+#endif
+#endif
+
+#ifndef gnu_attr_printf
+#define gnu_attr_printf	printf
+#define gnu_attr___printf__ __printf__
+#define gnu_attr_scanf	scanf
+#define gnu_attr___scanf__ __scanf__
+#define gnu_attr_strftime strftime
+#define gnu_attr___strftime__ __strftime__
+#endif
+
+#if !defined (USE_SYSTEM_FORMATS)
+#define USE_PRINTF(FMTPOS, WILDARG) __attribute__((format(gnu_printf, FMTPOS, WILDARG))) __attribute__((nonnull (FMTPOS)))
+#define USE_SCANF(FMTPOS, WILDARG) __attribute__((format(gnu_scanf, FMTPOS, WILDARG))) __attribute__((nonnull (FMTPOS)))
+#define USE_STRFTIME(FMTPOS) __attribute__((__format__(gnu_strftime, FMTPOS, 0))) __attribute__((nonnull (FMTPOS)))
+#else
+#define USE_PRINTF(FMTPOS, WILDARG)
+#define USE_SCANF(FMTPOS, WILDARG)
+#define USE_STRFTIME(FMTPOS)
+#endif
+
 #include <stdarg.h>
 #include <stddef.h>
 
@@ -11,6 +42,20 @@
 typedef __WINT_TYPE__ wint_t;
 #endif
 
+#ifdef _WIN64
+/* Kludges to get types corresponding to size_t and ptrdiff_t.  */
+#define unsigned signed
+typedef signed int signed_size_t __attribute__ ((mode (DI)));
+/* We also use this type to approximate ssize_t.  */
+typedef signed int ssize_t __attribute__ ((mode (DI)));
+#undef unsigned
+#define signed /* Type might or might not have explicit 'signed'.  */
+typedef unsigned int unsigned_ptrdiff_t __attribute__ ((mode (DI)));
+#undef signed
+
+__extension__ typedef int llong  __attribute__ ((mode (DI)));
+__extension__ typedef unsigned int ullong  __attribute__ ((mode (DI)));
+#else
 /* Kludges to get types corresponding to size_t and ptrdiff_t.  */
 #define unsigned signed
 typedef __SIZE_TYPE__ signed_size_t;
@@ -23,6 +68,7 @@ typedef unsigned __PTRDIFF_TYPE__ unsign
 
 __extension__ typedef long long int llong;
 __extension__ typedef unsigned long long int ullong;
+#endif
 
 /* %q formats want a "quad"; GCC considers this to be a long long.  */
 typedef llong quad_t;
@@ -70,3 +116,77 @@ extern size_t strftime (char *restrict, 
 			const struct tm *restrict);
 
 extern ssize_t strfmon (char *restrict, size_t, const char *restrict, ...);
+
+/* Mingw specific part.  */
+#if !defined (USE_SYSTEM_FORMATS) && defined(_WIN32) && !defined(DONT_GNU_PROTOTYPE)
+
+extern USE_PRINTF(2,3) int fprintf_gnu (FILE *restrict, const char *restrict, ...);
+#undef fprintf
+#define fprintf fprintf_gnu
+
+extern USE_PRINTF(1,2) int printf_gnu (const char *restrict, ...);
+#undef printf
+#define printf printf_gnu
+
+extern USE_PRINTF(2,3) int fprintf_unlocked_gnu (FILE *restrict, const char *restrict, ...);
+#undef fprintf_unlocked
+#define fprintf_unlocked fprintf_unlocked_gnu
+
+extern USE_PRINTF(1,2)int printf_unlocked_gnu (const char *restrict, ...);
+#undef printf_unlocked
+#define printf_unlocked printf_unlocked_gnu
+
+extern USE_PRINTF(2,3) int sprintf_gnu (char *restrict, const char *restrict, ...);
+#undef sprintf
+#define sprintf sprintf_gnu
+
+extern USE_PRINTF(2,0) int vfprintf_gnu (FILE *restrict, const char *restrict, va_list);
+#undef vsprintf
+#define vsprintf vsprintf_gnu
+
+extern USE_PRINTF(1,0) int vprintf_gnu (const char *restrict, va_list);
+#undef vprintf
+#define vprintf vprintf_gnu
+
+extern USE_PRINTF(2,0) int vsprintf_gnu (char *restrict, const char *restrict, va_list);
+#undef vsprintf
+#define vsprintf vsprintf_gnu
+
+extern USE_PRINTF(3,4) int snprintf_gnu (char *restrict, size_t, const char *restrict, ...);
+#undef snprintf
+#define snprintf snprintf_gnu
+
+extern USE_PRINTF(3,0) int vsnprintf_gnu (char *restrict, size_t, const char *restrict, va_list);
+#undef vsnprintf
+#define vsnprintf vsnprintf_gnu
+
+extern USE_SCANF(2,3) int fscanf_gnu (FILE *restrict, const char *restrict, ...);
+#undef fscanf
+#define fscanf fscanf_gnu
+
+extern USE_SCANF(1,2) int scanf_gnu (const char *restrict, ...);
+#undef scanf
+#define scanf scanf_gnu
+
+extern USE_SCANF(2,3) int sscanf_gnu (const char *restrict, const char *restrict, ...);
+#undef sscanf
+#define sscanf sscanf_gnu
+
+extern USE_SCANF(2,0) int vfscanf_gnu (FILE *restrict, const char *restrict, va_list);
+#undef vfscanf
+#define vfscanf vfscanf_gnu
+
+extern USE_SCANF(1,0) int vscanf_gnu (const char *restrict, va_list);
+#undef vscanf
+#define vscanf vscanf_gnu
+
+extern USE_SCANF(2,0) int vsscanf_gnu (const char *restrict, const char *restrict, va_list);
+#undef vsscanf
+#define vsscanf vsscanf_gnu
+
+extern USE_STRFTIME(3) size_t strftime_gnu (char *restrict, size_t, const char *restrict,
+			const struct tm *restrict);
+#undef strftime
+#define strftime strftime_gnu
+
+#endif
Index: gcc/gcc/testsuite/gcc.dg/format/attr-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-1.c
@@ -3,7 +3,8 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern void foo0 (const char *) __attribute__((__format__(__strftime__, 1, 0)));
-extern void foo1 (const char *, ...) __attribute__((__format__(__strftime__, 1, 2))); /* { dg-error "cannot format" "strftime first_arg_num != 0" } */
+extern void foo0 (const char *) __attribute__((__format__(gnu_attr___strftime__, 1, 0)));
+extern void foo1 (const char *, ...) __attribute__((__format__(gnu_attr___strftime__, 1, 2))); /* { dg-error "cannot format" "strftime first_arg_num != 0" } */
Index: gcc/gcc/testsuite/gcc.dg/format/attr-2.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-2.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-2.c
@@ -3,22 +3,23 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern void tformatprintf (const char *, ...) __attribute__((format(printf, 1, 2)));
-extern void tformat__printf__ (const char *, ...) __attribute__((format(__printf__, 1, 2)));
-extern void tformatscanf (const char *, ...) __attribute__((format(scanf, 1, 2)));
-extern void tformat__scanf__ (const char *, ...) __attribute__((format(__scanf__, 1, 2)));
-extern void tformatstrftime (const char *) __attribute__((format(strftime, 1, 0)));
-extern void tformat__strftime__ (const char *) __attribute__((format(__strftime__, 1, 0)));
+extern void tformatprintf (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
+extern void tformat__printf__ (const char *, ...) __attribute__((format(gnu_attr___printf__, 1, 2)));
+extern void tformatscanf (const char *, ...) __attribute__((format(gnu_attr_scanf, 1, 2)));
+extern void tformat__scanf__ (const char *, ...) __attribute__((format(gnu_attr___scanf__, 1, 2)));
+extern void tformatstrftime (const char *) __attribute__((format(gnu_attr_strftime, 1, 0)));
+extern void tformat__strftime__ (const char *) __attribute__((format(gnu_attr___strftime__, 1, 0)));
 extern void tformatstrfmon (const char *, ...) __attribute__((format(strfmon, 1, 2)));
 extern void tformat__strfmon__ (const char *, ...) __attribute__((format(__strfmon__, 1, 2)));
-extern void t__format__printf (const char *, ...) __attribute__((__format__(printf, 1, 2)));
-extern void t__format____printf__ (const char *, ...) __attribute__((__format__(__printf__, 1, 2)));
-extern void t__format__scanf (const char *, ...) __attribute__((__format__(scanf, 1, 2)));
-extern void t__format____scanf__ (const char *, ...) __attribute__((__format__(__scanf__, 1, 2)));
-extern void t__format__strftime (const char *) __attribute__((__format__(strftime, 1, 0)));
-extern void t__format____strftime__ (const char *) __attribute__((__format__(__strftime__, 1, 0)));
+extern void t__format__printf (const char *, ...) __attribute__((__format__(gnu_attr_printf, 1, 2)));
+extern void t__format____printf__ (const char *, ...) __attribute__((__format__(gnu_attr___printf__, 1, 2)));
+extern void t__format__scanf (const char *, ...) __attribute__((__format__(gnu_attr_scanf, 1, 2)));
+extern void t__format____scanf__ (const char *, ...) __attribute__((__format__(gnu_attr___scanf__, 1, 2)));
+extern void t__format__strftime (const char *) __attribute__((__format__(gnu_attr_strftime, 1, 0)));
+extern void t__format____strftime__ (const char *) __attribute__((__format__(gnu_attr___strftime__, 1, 0)));
 extern void t__format__strfmon (const char *, ...) __attribute__((__format__(strfmon, 1, 2)));
 extern void t__format____strfmon__ (const char *, ...) __attribute__((__format__(__strfmon__, 1, 2)));
 
Index: gcc/gcc/testsuite/gcc.dg/format/attr-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-3.c
@@ -3,20 +3,21 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 /* Proper uses of the attributes.  */
-extern void fa0 (const char *, ...) __attribute__((format(printf, 1, 2)));
-extern void fa1 (char *, ...) __attribute__((format(printf, 1, 2)));
+extern void fa0 (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
+extern void fa1 (char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
 extern char *fa2 (const char *) __attribute__((format_arg(1)));
 extern char *fa3 (char *) __attribute__((format_arg(1)));
 
 /* Uses with too few or too many arguments.  */
 extern void fb0 (const char *, ...) __attribute__((format)); /* { dg-error "wrong number of arguments" "bad format" } */
 extern void fb1 (const char *, ...) __attribute__((format())); /* { dg-error "wrong number of arguments" "bad format" } */
-extern void fb2 (const char *, ...) __attribute__((format(printf))); /* { dg-error "wrong number of arguments" "bad format" } */
-extern void fb3 (const char *, ...) __attribute__((format(printf, 1))); /* { dg-error "wrong number of arguments" "bad format" } */
-extern void fb4 (const char *, ...) __attribute__((format(printf, 1, 2, 3))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb2 (const char *, ...) __attribute__((format(gnu_attr_printf))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb3 (const char *, ...) __attribute__((format(gnu_attr_printf, 1))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb4 (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2, 3))); /* { dg-error "wrong number of arguments" "bad format" } */
 
 extern void fc1 (const char *) __attribute__((format_arg)); /* { dg-error "wrong number of arguments" "bad format_arg" } */
 extern void fc2 (const char *) __attribute__((format_arg())); /* { dg-error "wrong number of arguments" "bad format_arg" } */
@@ -25,9 +26,9 @@ extern void fc3 (const char *) __attribu
 /* These attributes presently only apply to declarations, not to types.
    Eventually, they should be usable with declarators for function types
    anywhere, but still not with structure/union/enum types.  */
-struct s0 { int i; } __attribute__((format(printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on struct" } */
-union u0 { int i; } __attribute__((format(printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on union" } */
-enum e0 { E0V0 } __attribute__((format(printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on enum" } */
+struct s0 { int i; } __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on struct" } */
+union u0 { int i; } __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on union" } */
+enum e0 { E0V0 } __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on enum" } */
 
 struct s1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on struct" } */
 union u1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on union" } */
@@ -38,28 +39,28 @@ extern void fe0 (const char *, ...) __at
 extern void fe1 (const char *, ...) __attribute__((format(nosuch, 1, 2))); /* { dg-warning "format function type" "unknown format" } */
 
 /* Both the numbers must be integer constant expressions.  */
-extern void ff0 (const char *, ...) __attribute__((format(printf, 3-2, (long long)(10/5))));
+extern void ff0 (const char *, ...) __attribute__((format(gnu_attr_printf, 3-2, (long long)(10/5))));
 int foo;
-extern void ff1 (const char *, ...) __attribute__((format(printf, foo, 10/5))); /* { dg-error "invalid operand" "bad number" } */
-extern void ff2 (const char *, ...) __attribute__((format(printf, 3-2, foo))); /* { dg-error "invalid operand" "bad number" } */
+extern void ff1 (const char *, ...) __attribute__((format(gnu_attr_printf, foo, 10/5))); /* { dg-error "invalid operand" "bad number" } */
+extern void ff2 (const char *, ...) __attribute__((format(gnu_attr_printf, 3-2, foo))); /* { dg-error "invalid operand" "bad number" } */
 extern char *ff3 (const char *) __attribute__((format_arg(3-2)));
 extern char *ff4 (const char *) __attribute__((format_arg(foo))); /* { dg-error "invalid operand" "bad format_arg number" } */
 
 /* The format string argument must precede the arguments to be formatted.
    This includes if no parameter types are specified (which is not valid ISO
    C for variadic functions).  */
-extern void fg0 () __attribute__((format(printf, 1, 2)));
-extern void fg1 () __attribute__((format(printf, 1, 0)));
-extern void fg2 () __attribute__((format(printf, 1, 1))); /* { dg-error "follows" "bad number order" } */
-extern void fg3 () __attribute__((format(printf, 2, 1))); /* { dg-error "follows" "bad number order" } */
+extern void fg0 () __attribute__((format(gnu_attr_printf, 1, 2)));
+extern void fg1 () __attribute__((format(gnu_attr_printf, 1, 0)));
+extern void fg2 () __attribute__((format(gnu_attr_printf, 1, 1))); /* { dg-error "follows" "bad number order" } */
+extern void fg3 () __attribute__((format(gnu_attr_printf, 2, 1))); /* { dg-error "follows" "bad number order" } */
 
 /* The format string argument must be a string type, and the arguments to
    be formatted must be the "...".  */
-extern void fh0 (int, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "not a string" "format int string" } */
-extern void fh1 (signed char *, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "not a string" "signed char string" } */
-extern void fh2 (unsigned char *, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "not a string" "unsigned char string" } */
-extern void fh3 (const char *, ...) __attribute__((format(printf, 1, 3))); /* { dg-error "is not" "not ..." } */
-extern void fh4 (const char *, int, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "is not" "not ..." } */
+extern void fh0 (int, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "format int string" } */
+extern void fh1 (signed char *, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "signed char string" } */
+extern void fh2 (unsigned char *, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "unsigned char string" } */
+extern void fh3 (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 3))); /* { dg-error "is not" "not ..." } */
+extern void fh4 (const char *, int, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "is not" "not ..." } */
 
 /* format_arg formats must take and return a string.  */
 extern char *fi0 (int) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg int string" } */
Index: gcc/gcc/testsuite/gcc.dg/format/attr-4.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-4.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-4.c
@@ -4,12 +4,13 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern __attribute__((format(printf, 1, 2))) void tformatprintf0 (const char *, ...);
-extern void __attribute__((format(printf, 1, 2))) tformatprintf1 (const char *, ...);
-extern void foo (void), __attribute__((format(printf, 1, 2))) tformatprintf2 (const char *, ...);
-extern __attribute__((noreturn)) void bar (void), __attribute__((format(printf, 1, 2))) tformatprintf3 (const char *, ...);
+extern __attribute__((format(gnu_attr_printf, 1, 2))) void tformatprintf0 (const char *, ...);
+extern void __attribute__((format(gnu_attr_printf, 1, 2))) tformatprintf1 (const char *, ...);
+extern void foo (void), __attribute__((format(gnu_attr_printf, 1, 2))) tformatprintf2 (const char *, ...);
+extern __attribute__((noreturn)) void bar (void), __attribute__((format(gnu_attr_printf, 1, 2))) tformatprintf3 (const char *, ...);
 
 void
 baz (int i, int *ip, double d)
Index: gcc/gcc/testsuite/gcc.dg/format/attr-7.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-7.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-7.c
@@ -3,12 +3,13 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-__attribute__((format(printf, 1, 2))) void (*tformatprintf0) (const char *, ...);
-void (*tformatprintf1) (const char *, ...) __attribute__((format(printf, 1, 2)));
-void (__attribute__((format(printf, 1, 2))) *tformatprintf2) (const char *, ...);
-void (__attribute__((format(printf, 1, 2))) ****tformatprintf3) (const char *, ...);
+__attribute__((format(gnu_attr_printf, 1, 2))) void (*tformatprintf0) (const char *, ...);
+void (*tformatprintf1) (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
+void (__attribute__((format(gnu_attr_printf, 1, 2))) *tformatprintf2) (const char *, ...);
+void (__attribute__((format(gnu_attr_printf, 1, 2))) ****tformatprintf3) (const char *, ...);
 
 char * (__attribute__((format_arg(1))) *tformat_arg) (const char *);
 
Index: gcc/gcc/testsuite/gcc.dg/format/c90-printf-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/c90-printf-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/c90-printf-3.c
@@ -3,7 +3,7 @@
    do not.
 */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
-/* { dg-do compile } */
+/* { dg-do compile { target { ! *-*-mingw* } } } */
 /* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
 
 #include "format.h"
Index: gcc/gcc/testsuite/gcc.dg/format/c90-scanf-4.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/c90-scanf-4.c
+++ gcc/gcc/testsuite/gcc.dg/format/c90-scanf-4.c
@@ -3,7 +3,7 @@
    do not.
 */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
-/* { dg-do compile } */
+/* { dg-do compile { target { ! *-*-mingw* } } } */
 /* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
 
 #include "format.h"
Index: gcc/gcc/testsuite/gcc.dg/format/c99-printf-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/c99-printf-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/c99-printf-3.c
@@ -2,7 +2,7 @@
    attributes in strict C99 mode, but the gettext functions do not.
 */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
-/* { dg-do compile } */
+/* { dg-do compile { target { ! *-*-mingw* } } } */
 /* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
 
 #include "format.h"
Index: gcc/gcc/testsuite/gcc.dg/format/miss-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-1.c
@@ -23,7 +23,7 @@ bar (const char *fmt, ...)
   va_end (ap);
 }
 
-__attribute__((__format__(__printf__, 1, 2))) void
+__attribute__((__format__(gnu_attr___printf__, 1, 2))) void
 foo2 (const char *fmt, ...)
 {
   va_list ap;
Index: gcc/gcc/testsuite/gcc.dg/format/miss-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-3.c
@@ -3,13 +3,14 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 void
 foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
@@ -18,7 +19,7 @@ foo1 (noattr_t na, attr_t a, vnoattr_t v
   noattr_t na2 = a; /* { dg-warning "candidate" "initialization warning" } */
   attr_t a1 = na;
   attr_t a2 = a;
-  
+
   vnoattr_t vna1 = vna;
   vnoattr_t vna2 = va; /* { dg-warning "candidate" "initialization warning" } */
   vattr_t va1 = vna;
Index: gcc/gcc/testsuite/gcc.dg/format/miss-4.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-4.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-4.c
@@ -3,20 +3,21 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 void
 foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
 {
   noattr_t na1, na2;
   attr_t a1, a2;
-  
+
   vnoattr_t vna1, vna2;
   vattr_t va1, va2;
 
@@ -24,7 +25,7 @@ foo1 (noattr_t na, attr_t a, vnoattr_t v
   na2 = a; /* { dg-warning "candidate" "assignment warning" } */
   a1 = na;
   a2 = a;
-  
+
   vna1 = vna;
   vna2 = va; /* { dg-warning "candidate" "assignment warning" } */
   va1 = vna;
Index: gcc/gcc/testsuite/gcc.dg/format/miss-5.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-5.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-5.c
@@ -3,13 +3,14 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 noattr_t
 foo1 (noattr_t na, attr_t a, int i)
Index: gcc/gcc/testsuite/gcc.dg/format/miss-6.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-6.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-6.c
@@ -3,13 +3,14 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 extern void foo1 (noattr_t);
 extern void foo2 (attr_t);
@@ -23,7 +24,7 @@ foo (noattr_t na, attr_t a, vnoattr_t vn
   foo1 (a); /* { dg-warning "candidate" "parameter passing warning" } */
   foo2 (na);
   foo2 (a);
-  
+
   foo3 (vna);
   foo3 (va); /* { dg-warning "candidate" "parameter passing warning" } */
   foo4 (vna);
Index: gcc/gcc/testsuite/gcc.dg/format/ms_array-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_array-1.c
@@ -0,0 +1,42 @@
+/* Test for format checking of constant arrays.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat=2" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+const char a1[] = "foo";
+const char a2[] = "foo%d";
+const char b1[3] = "foo";
+const char b2[1] = "1";
+static const char c1[] = "foo";
+static const char c2[] = "foo%d";
+char d[] = "foo";
+volatile const char e[] = "foo";
+
+void
+foo (int i, long l)
+{
+  const char p1[] = "bar";
+  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 (c1);
+  printf (c2, i);
+  printf (c2, l); /* { dg-warning "format" "wrong type with array" } */
+  printf (p1);
+  printf (p2, i);
+  printf (p2, l); /* { dg-warning "format" "wrong type with array" } */
+  printf (q1);
+  printf (q2, i);
+  printf (q2, l); /* { dg-warning "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" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-1.c
@@ -0,0 +1,10 @@
+/* Test for strftime format attributes: can't have first_arg_num != 0.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define DONT_GNU_PROTOTYPE
+#include "format.h"
+
+extern void foo0 (const char *) __attribute__((__format__(__ms_strftime__, 1, 0)));
+extern void foo1 (const char *, ...) __attribute__((__format__(__ms_strftime__, 1, 2))); /* { dg-error "cannot format" "strftime first_arg_num != 0" } */
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-2.c
@@ -0,0 +1,68 @@
+/* Test for format attributes: test use of __attribute__.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define DONT_GNU_PROTOTYPE
+#include "format.h"
+
+extern void tformatprintf (const char *, ...) __attribute__((format(ms_printf, 1, 2)));
+extern void tformat__printf__ (const char *, ...) __attribute__((format(__ms_printf__, 1, 2)));
+extern void tformatscanf (const char *, ...) __attribute__((format(ms_scanf, 1, 2)));
+extern void tformat__scanf__ (const char *, ...) __attribute__((format(__ms_scanf__, 1, 2)));
+extern void tformatstrftime (const char *) __attribute__((format(ms_strftime, 1, 0)));
+extern void tformat__strftime__ (const char *) __attribute__((format(__ms_strftime__, 1, 0)));
+extern void tformatstrfmon (const char *, ...) __attribute__((format(strfmon, 1, 2)));
+extern void tformat__strfmon__ (const char *, ...) __attribute__((format(__strfmon__, 1, 2)));
+extern void t__format__printf (const char *, ...) __attribute__((__format__(ms_printf, 1, 2)));
+extern void t__format____printf__ (const char *, ...) __attribute__((__format__(__ms_printf__, 1, 2)));
+extern void t__format__scanf (const char *, ...) __attribute__((__format__(ms_scanf, 1, 2)));
+extern void t__format____scanf__ (const char *, ...) __attribute__((__format__(__ms_scanf__, 1, 2)));
+extern void t__format__strftime (const char *) __attribute__((__format__(ms_strftime, 1, 0)));
+extern void t__format____strftime__ (const char *) __attribute__((__format__(__ms_strftime__, 1, 0)));
+extern void t__format__strfmon (const char *, ...) __attribute__((__format__(strfmon, 1, 2)));
+extern void t__format____strfmon__ (const char *, ...) __attribute__((__format__(__strfmon__, 1, 2)));
+
+extern char *tformat_arg (const char *) __attribute__((format_arg(1)));
+extern char *t__format_arg__ (const char *) __attribute__((__format_arg__(1)));
+
+void
+foo (int i, int *ip, double d)
+{
+  tformatprintf ("%d", i);
+  tformatprintf ("%"); /* { dg-warning "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);
+  tformat__scanf__ ("%"); /* { dg-warning "format" "attribute format __scanf__" } */
+  tformatstrftime ("%a");
+  tformatstrftime ("%"); /* { dg-warning "format" "attribute format strftime" } */
+  tformat__strftime__ ("%a");
+  tformat__strftime__ ("%"); /* { dg-warning "format" "attribute format __strftime__" } */
+  tformatstrfmon ("%n", d);
+  tformatstrfmon ("%"); /* { dg-warning "format" "attribute format strfmon" } */
+  tformat__strfmon__ ("%n", d);
+  tformat__strfmon__ ("%"); /* { dg-warning "format" "attribute format __strfmon__" } */
+  t__format__printf ("%d", i);
+  t__format__printf ("%"); /* { dg-warning "format" "attribute __format__ printf" } */
+  t__format____printf__ ("%d", i);
+  t__format____printf__ ("%"); /* { dg-warning "format" "attribute __format__ __printf__" } */
+  t__format__scanf ("%d", ip);
+  t__format__scanf ("%"); /* { dg-warning "format" "attribute __format__ scanf" } */
+  t__format____scanf__ ("%d", ip);
+  t__format____scanf__ ("%"); /* { dg-warning "format" "attribute __format__ __scanf__" } */
+  t__format__strftime ("%a");
+  t__format__strftime ("%"); /* { dg-warning "format" "attribute __format__ strftime" } */
+  t__format____strftime__ ("%a");
+  t__format____strftime__ ("%"); /* { dg-warning "format" "attribute __format__ __strftime__" } */
+  t__format__strfmon ("%n", d);
+  t__format__strfmon ("%"); /* { dg-warning "format" "attribute __format__ strfmon" } */
+  t__format____strfmon__ ("%n", d);
+  t__format____strfmon__ ("%"); /* { dg-warning "format" "attribute __format__ __strfmon__" } */
+  tformatprintf (tformat_arg ("%d"), i);
+  tformatprintf (tformat_arg ("%")); /* { dg-warning "format" "attribute format_arg" } */
+  tformatprintf (t__format_arg__ ("%d"), i);
+  tformatprintf (t__format_arg__ ("%")); /* { dg-warning "format" "attribute __format_arg__" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-3.c
@@ -0,0 +1,71 @@
+/* Test for format attributes: test bad uses of __attribute__.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* Proper uses of the attributes.  */
+extern void fa0 (const char *, ...) __attribute__((format(ms_printf, 1, 2)));
+extern void fa1 (char *, ...) __attribute__((format(ms_printf, 1, 2)));
+extern char *fa2 (const char *) __attribute__((format_arg(1)));
+extern char *fa3 (char *) __attribute__((format_arg(1)));
+
+/* Uses with too few or too many arguments.  */
+extern void fb0 (const char *, ...) __attribute__((format)); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb1 (const char *, ...) __attribute__((format())); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb2 (const char *, ...) __attribute__((format(ms_printf))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb3 (const char *, ...) __attribute__((format(ms_printf, 1))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb4 (const char *, ...) __attribute__((format(ms_printf, 1, 2, 3))); /* { dg-error "wrong number of arguments" "bad format" } */
+
+extern void fc1 (const char *) __attribute__((format_arg)); /* { dg-error "wrong number of arguments" "bad format_arg" } */
+extern void fc2 (const char *) __attribute__((format_arg())); /* { dg-error "wrong number of arguments" "bad format_arg" } */
+extern void fc3 (const char *) __attribute__((format_arg(1, 2))); /* { dg-error "wrong number of arguments" "bad format_arg" } */
+
+/* These attributes presently only apply to declarations, not to types.
+   Eventually, they should be usable with declarators for function types
+   anywhere, but still not with structure/union/enum types.  */
+struct s0 { int i; } __attribute__((format(ms_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on struct" } */
+union u0 { int i; } __attribute__((format(ms_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on union" } */
+enum e0 { E0V0 } __attribute__((format(ms_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on enum" } */
+
+struct s1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on struct" } */
+union u1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on union" } */
+enum e1 { E1V0 } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on enum" } */
+
+/* The format type must be an identifier, one of those recognized.  */
+extern void fe0 (const char *, ...) __attribute__((format(12345, 1, 2))); /* { dg-error "format specifier" "non-id format" } */
+extern void fe1 (const char *, ...) __attribute__((format(nosuch, 1, 2))); /* { dg-warning "format function type" "unknown format" } */
+
+/* Both the numbers must be integer constant expressions.  */
+extern void ff0 (const char *, ...) __attribute__((format(ms_printf, 3-2, (long long)(10/5))));
+int foo;
+extern void ff1 (const char *, ...) __attribute__((format(ms_printf, foo, 10/5))); /* { dg-error "invalid operand" "bad number" } */
+extern void ff2 (const char *, ...) __attribute__((format(ms_printf, 3-2, foo))); /* { dg-error "invalid operand" "bad number" } */
+extern char *ff3 (const char *) __attribute__((format_arg(3-2)));
+extern char *ff4 (const char *) __attribute__((format_arg(foo))); /* { dg-error "invalid operand" "bad format_arg number" } */
+
+/* The format string argument must precede the arguments to be formatted.
+   This includes if no parameter types are specified (which is not valid ISO
+   C for variadic functions).  */
+extern void fg0 () __attribute__((format(ms_printf, 1, 2)));
+extern void fg1 () __attribute__((format(ms_printf, 1, 0)));
+extern void fg2 () __attribute__((format(ms_printf, 1, 1))); /* { dg-error "follows" "bad number order" } */
+extern void fg3 () __attribute__((format(ms_printf, 2, 1))); /* { dg-error "follows" "bad number order" } */
+
+/* The format string argument must be a string type, and the arguments to
+   be formatted must be the "...".  */
+extern void fh0 (int, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "not a string" "format int string" } */
+extern void fh1 (signed char *, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "not a string" "signed char string" } */
+extern void fh2 (unsigned char *, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "not a string" "unsigned char string" } */
+extern void fh3 (const char *, ...) __attribute__((format(ms_printf, 1, 3))); /* { dg-error "is not" "not ..." } */
+extern void fh4 (const char *, int, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "is not" "not ..." } */
+
+/* format_arg formats must take and return a string.  */
+extern char *fi0 (int) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg int string" } */
+extern char *fi1 (signed char *) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg signed char string" } */
+extern char *fi2 (unsigned char *) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg unsigned char string" } */
+extern int fi3 (const char *) __attribute__((format_arg(1))); /* { dg-error "not return string" "format_arg ret int string" } */
+extern signed char *fi4 (const char *) __attribute__((format_arg(1))); /* { dg-error "not return string" "format_arg ret signed char string" } */
+extern unsigned char *fi5 (const char *) __attribute__((format_arg(1))); /* { dg-error "not return string" "format_arg ret unsigned char string" } */
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-4.c
@@ -0,0 +1,26 @@
+/* Test for format attributes: test use of __attribute__
+   in prefix attributes.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+extern __attribute__((format(ms_printf, 1, 2))) void tformatprintf0 (const char *, ...);
+extern void __attribute__((format(ms_printf, 1, 2))) tformatprintf1 (const char *, ...);
+extern void foo (void), __attribute__((format(ms_printf, 1, 2))) tformatprintf2 (const char *, ...);
+extern __attribute__((noreturn)) void bar (void), __attribute__((format(ms_printf, 1, 2))) tformatprintf3 (const char *, ...);
+
+void
+baz (int i, int *ip, double d)
+{
+  tformatprintf0 ("%d", i);
+  tformatprintf0 ("%"); /* { dg-warning "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);
+  tformatprintf3 ("%"); /* { dg-warning "format" "attribute format printf case 3" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-7.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-7.c
@@ -0,0 +1,35 @@
+/* Test for format attributes: test applying them to types.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define DONT_GNU_PROTOTYPE
+#include "format.h"
+
+__attribute__((format(ms_printf, 1, 2))) void (*tformatprintf0) (const char *, ...);
+void (*tformatprintf1) (const char *, ...) __attribute__((format(ms_printf, 1, 2)));
+void (__attribute__((format(ms_printf, 1, 2))) *tformatprintf2) (const char *, ...);
+void (__attribute__((format(ms_printf, 1, 2))) ****tformatprintf3) (const char *, ...);
+
+char * (__attribute__((format_arg(1))) *tformat_arg) (const char *);
+
+void
+baz (int i)
+{
+  (*tformatprintf0) ("%d", i);
+  (*tformatprintf0) ((*tformat_arg) ("%d"), i);
+  (*tformatprintf0) ("%"); /* { dg-warning "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" } */
+  (*tformatprintf2) ("%d", i);
+  (*tformatprintf2) ((*tformat_arg) ("%d"), i);
+  (*tformatprintf2) ("%"); /* { dg-warning "format" "nested" } */
+  (*tformatprintf2) ((*tformat_arg) ("%")); /* { dg-warning "format" "nested" } */
+  (****tformatprintf3) ("%d", i);
+  (****tformatprintf3) ((*tformat_arg) ("%d"), i);
+  (****tformatprintf3) ("%"); /* { dg-warning "format" "nested 2" } */
+  (****tformatprintf3) ((*tformat_arg) ("%")); /* { dg-warning "format" "nested 2" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_bitfld-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_bitfld-1.c
@@ -0,0 +1,52 @@
+/* Test for printf formats and bit-fields: bug 22421.  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+/* { dg-require-effective-target int32plus } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+struct s {
+  unsigned int u1 : 1;
+  signed int s1 : 1;
+  unsigned int u15 : 15;
+  signed int s15 : 15;
+  unsigned int u16 : 16;
+  signed int s16 : 16;
+  unsigned long u31 : 31;
+  signed long s31 : 31;
+  unsigned long u32 : 32;
+  signed long s32 : 32;
+  unsigned long long u48 : 48;
+} x;
+
+void
+foo (void)
+{
+  printf ("%d%u", x.u1, x.u1);
+  printf ("%d%u", x.s1, x.s1);
+  printf ("%d%u", x.u15, x.u15);
+  printf ("%d%u", x.s15, x.s15);
+  printf ("%d%u", x.u16, x.u16);
+  printf ("%d%u", x.s16, x.s16);
+#if __INT_MAX__ > 32767
+  /* If integers are 16 bits, there doesn't seem to be a way of
+     printing these without getting an error.  */
+  printf ("%d%u", x.u31, x.u31);
+  printf ("%d%u", x.s31, x.s31);
+#endif
+#if __LONG_MAX__ > 2147483647 && __INT_MAX__ >= 2147483647
+  /* If long is wider than 32 bits, the 32-bit bit-fields are int or
+     unsigned int or promote to those types.  Otherwise, long is 32
+     bits and the bit-fields are of type plain long or unsigned
+     long.  */
+  printf ("%d%u", x.u32, x.u32);
+  printf ("%d%u", x.s32, x.s32);
+#else
+  printf ("%ld%lu", x.u32, x.u32);
+  printf ("%ld%lu", x.s32, x.s32);
+#endif
+  printf ("%I64u", x.u48); /* { dg-warning "has type '.*unsigned int:48'" } */
+  printf ("%I64u", (unsigned long long)x.u48);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_branch-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_branch-1.c
@@ -0,0 +1,28 @@
+/* Test for format checking of conditional expressions.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+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" } */
+  /* 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) ? "%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" } */
+  /* 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 *-*-* } 26 } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-1.c
@@ -0,0 +1,184 @@
+/* Test for printf formats.  Formats using C90 features, including cases
+   where C90 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, int i1, int i2, unsigned int u, double d, char *s, void *p,
+     int *n, short int *hn, long int l, unsigned long int ul,
+     long int *ln, long double ld, wint_t lc, wchar_t *ls, llong ll,
+     ullong ull, unsigned int *un, const int *cn, signed char *ss,
+     unsigned char *us, const signed char *css, unsigned int u1,
+     unsigned int u2)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.1 (pages 131-134).  */
+  /* Basic sanity checks for the different components of a format.  */
+  printf ("%d\n", i);
+  printf ("%+d\n", i);
+  printf ("%3d\n", i);
+  printf ("%-3d\n", i);
+  printf ("%*d\n", i1, i);
+  printf ("%d %lu\n", i, ul);
+  /* Bogus use of width.  */
+  printf ("%5n\n", n); /* { dg-warning "width" "width 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 ("%-%"); /* { dg-warning "format" "bogus %%" } */
+  printf ("%-%\n"); /* { dg-warning "format" "bogus %%" } */
+  printf ("%5%\n"); /* { dg-warning "format" "bogus %%" } */
+  printf ("%h%\n"); /* { dg-warning "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
+     differences in format checking here, and this is relied on to get the
+     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);
+  printf ("%hs", hn);
+  printf ("%hp", p); /* { dg-warning "length" "bad use of %h" } */
+  printf ("%h"); /* { dg-warning "conversion lacks type" "bare %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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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% 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* Various tests of bad argument types.  */
+  printf ("%d", l); /* { dg-warning "format" "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" } */
+  /* 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
+     discussion of the requirements of rules on identical representation,
+     and of the application of the as if rule with the new va_arg
+     allowances in C99 to printf.)  Likewise, we should warn if
+     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" } */
+  /* 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" } */
+  /* The historical behavior is to allow signed / unsigned types
+     interchangably as arguments.  For values representable in both types,
+     such usage may be correct.  For now preserve the behavior of GCC
+     in such cases.
+  */
+  printf ("%d", u);
+  /* Wrong number of arguments.  */
+  printf ("%d%d", i); /* { dg-warning "arguments" "wrong number of args" } */
+  printf ("%d", i, i); /* { dg-warning "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" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-2.c
@@ -0,0 +1,25 @@
+/* Test for printf formats.  Formats using C99 features should be rejected
+   outside of C99 mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, double d, llong ll, intmax_t j, size_t z, ptrdiff_t t)
+{
+  /* Some tests already in c90-printf-1.c, e.g. %lf.  */
+  /* The widths hh, ll, j, z, t are new.  */
+  printf ("%hhd", i); /* { dg-warning "unknown|format" "%hh is unsupported" } */
+  printf ("%I64d", ll); /* { dg-warning "length|C" "%I64 in C90" } */
+  printf ("%jd", j); /* { dg-warning "unknown|format" "%j is unsupported" } */
+  printf ("%zu", z); /* { dg-warning "unknown|format" "%z is unsupported" } */
+  printf ("%td", t); /* { dg-warning "unknown|format" "%t is unsupported" } */
+  /* The formats F, a, A are new.  */
+  printf ("%F", d); /* { dg-warning "unknown|format" "%F is unsupported" } */
+  printf ("%a", d); /* { dg-warning "unknown|format" "%a is unsupported" } */
+  printf ("%A", d); /* { dg-warning "unknown|format" "%A is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-3.c
@@ -0,0 +1,43 @@
+/* Test for printf formats.  Test that the C90 functions get their default
+   attributes in strict C90 mode, but the C99 and gettext functions
+   do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, char *s, size_t n, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5, va_list v6, va_list v7, va_list v8)
+{
+  fprintf (stdout, "%d", i);
+  fprintf (stdout, "%ld", i); /* { dg-warning "format" "fprintf" } */
+  printf ("%d", i);
+  printf ("%ld", i); /* { dg-warning "format" "printf" } */
+  /* The "unlocked" functions shouldn't warn in c90 mode.  */
+  fprintf_unlocked (stdout, "%ld", i);
+  printf_unlocked ("%ld", i);
+  sprintf (s, "%d", i);
+  sprintf (s, "%ld", i); /* { dg-warning "format" "sprintf" } */
+  vfprintf (stdout, "%d", v0);
+  vfprintf (stdout, "%Y", v1); /* { dg-warning "format" "vfprintf" } */
+  vprintf ("%d", v2);
+  vprintf ("%Y", v3); /* { dg-warning "format" "vprintf" } */
+  /* The following used to give a bogus warning.  */
+  vprintf ("%*.*d", v8);   /* { dg-bogus "format" "vprintf" } */
+  vsprintf (s, "%d", v4);
+  vsprintf (s, "%Y", v5); /* { dg-warning "format" "Y is invalid" } */
+  snprintf (s, n, "%d", i);
+  snprintf (s, n, "%ld", i);
+  vsnprintf (s, n, "%d", v6);
+  vsnprintf (s, n, "%Y", v7);
+  printf (gettext ("%d"), i);
+  printf (gettext ("%ld"), i);
+  printf (dgettext ("", "%d"), i);
+  printf (dgettext ("", "%ld"), i);
+  printf (dcgettext ("", "%d", 0), i);
+  printf (dcgettext ("", "%ld", 0), i);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-1.c
@@ -0,0 +1,119 @@
+/* Test for scanf formats.  Formats using C90 features, including cases
+   where C90 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, unsigned int *uip, short int *hp, unsigned short int *uhp,
+     long int *lp, unsigned long int *ulp, float *fp, double *dp,
+     long double *ldp, char *s, signed char *ss, unsigned char *us,
+     void **pp, int *n, llong *llp, ullong *ullp, wchar_t *ls,
+     const int *cip, const int *cn, const char *cs, const void **ppc,
+     void *const *pcp, short int *hn, long int *ln, void *p, char **sp,
+     volatile void *ppv)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.2 (pages 134-138).  */
+  /* Basic sanity checks for the different components of a format.  */
+  scanf ("%d", ip);
+  scanf ("%*d");
+  scanf ("%3d", ip);
+  scanf ("%hd", hp);
+  scanf ("%3ld", lp);
+  scanf ("%*3d");
+  scanf ("%d %ld", ip, lp);
+  /* Valid and invalid %% constructions.  */
+  scanf ("%%");
+  scanf ("%*%"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%*%\n"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%4%"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%4%\n"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%h%"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%h%\n"); /* { dg-warning "format" "bogus %%" } */
+  /* Valid, invalid and silly assignment-suppression constructions.  */
+  scanf ("%*d%*i%*o%*u%*x%*X%*e%*E%*f%*g%*G%*s%*[abc]%*c%*p");
+  scanf ("%*2d%*8s%*3c");
+  scanf ("%*n", n); /* { dg-warning "suppress" "suppression of %n" } */
+  scanf ("%*hd"); /* { dg-warning "together" "suppression with length" } */
+  /* Valid, invalid and silly width constructions.  */
+  scanf ("%2d%3i%4o%5u%6x%7X%8e%9E%10f%11g%12G%13s%14[abc]%15c%16p",
+	 ip, ip, uip, uip, uip, uip, fp, fp, fp, fp, fp, s, s, s, pp);
+  scanf ("%0d", ip); /* { dg-warning "width" "warning for zero width" } */
+  scanf ("%3n", n); /* { dg-warning "width" "width with %n" } */
+  /* Valid and invalid %h, %l, %L constructions.  */
+  scanf ("%hd%hi%ho%hu%hx%hX%hn", hp, hp, uhp, uhp, uhp, uhp, hn);
+  scanf ("%he", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hE", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hf", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hg", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hG", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hs", hp);
+  scanf ("%h[ac]", s); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hc", hp);
+  scanf ("%hp", pp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%h"); /* { dg-warning "conversion lacks type" "bare %h" } */
+  scanf ("%h."); /* { dg-warning "conversion" "bogus %h" } */
+  scanf ("%ld%li%lo%lu%lx%lX%ln", lp, lp, ulp, ulp, ulp, ulp, ln);
+  scanf ("%le%lE%lf%lg%lG", dp, dp, dp, dp, dp);
+  scanf ("%lp", pp); /* { dg-warning "length" "bad use of %l" } */
+  /* These next three formats were added in C94.  */
+  scanf ("%ls", ls); /* { dg-warning "length|C" "bad use of %l" } */
+  scanf ("%l[ac]", ls); /* { dg-warning "length|C" "bad use of %l" } */
+  scanf ("%lc", ls); /* { dg-warning "length|C" "bad use of %l" } */
+  scanf ("%Ld", llp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Li", llp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lo", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lu", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lx", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%LX", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Ls", s); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%L[ac]", s); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lc", s); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lp", pp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Ln", n); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  /* Valid uses of each bare conversion.  */
+  scanf ("%d%i%o%u%x%X%e%E%f%g%G%s%[abc]%c%p%n%%", ip, ip, uip, uip, uip,
+	 uip, fp, fp, fp, fp, fp, s, s, s, pp, n);
+  /* Allow other character pointers with %s, %c, %[].  */
+  scanf ("%2s%3s%4c%5c%6[abc]%7[abc]", ss, us, ss, us, ss, us);
+  /* Further tests for %[].  */
+  scanf ("%[%d]%d", s, ip);
+  scanf ("%[^%d]%d", s, ip);
+  scanf ("%[]%d]%d", s, ip);
+  scanf ("%[^]%d]%d", s, ip);
+  scanf ("%[%d]%d", s, ip);
+  scanf ("%[]abcd", s); /* { dg-warning "no closing" "incomplete scanset" } */
+  /* Various tests of bad argument types.  Some of these are only pedantic
+     warnings.
+  */
+  scanf ("%d", lp); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%d", uip); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%d", pp); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", ppc); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", ppv); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%s", n); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%s", p); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", p); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", sp); /* { dg-warning "format" "bad argument types" } */
+  /* Tests for writing into constant values.  */
+  scanf ("%d", cip); /* { dg-warning "constant" "%d writing into const" } */
+  scanf ("%n", cn); /* { dg-warning "constant" "%n writing into const" } */
+  scanf ("%s", cs); /* { dg-warning "constant" "%s writing into const" } */
+  scanf ("%p", pcp); /* { dg-warning "constant" "%p writing into const" } */
+  /* Wrong number of arguments.  */
+  scanf ("%d%d", ip); /* { dg-warning "arguments" "wrong number of args" } */
+  scanf ("%d", ip, ip); /* { dg-warning "arguments" "wrong number of args" } */
+  /* Miscellaneous bogus constructions.  */
+  scanf (""); /* { dg-warning "zero-length" "warning for empty format" } */
+  scanf ("\0"); /* { dg-warning "embedded" "warning for embedded NUL" } */
+  scanf ("%d\0", ip); /* { dg-warning "embedded" "warning for embedded NUL" } */
+  scanf ("%d\0%d", ip, ip); /* { dg-warning "embedded|too many" "warning for embedded NUL" } */
+  scanf (NULL); /* { dg-warning "null" "null format string warning" } */
+  scanf ("%"); /* { dg-warning "trailing" "trailing % warning" } */
+  scanf ("%d", (int *)0); /* { dg-warning "null" "writing into NULL" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-2.c
@@ -0,0 +1,26 @@
+/* Test for scanf formats.  Formats using C99 features should be rejected
+   outside of C99 mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (signed char *hhp, float *fp, llong *llp, intmax_t *jp,
+     size_t *zp, ptrdiff_t *tp)
+{
+  /* Some tests already in c90-scanf-1.c.  */
+  /* The widths hh, ll, j, z, t are new.  */
+  scanf ("%hhd", hhp); /* { dg-warning "unknown|format" "%hh is unsupported" } */
+  scanf ("%I64d", llp); /* { dg-warning "length|C" "%I64 in C90" } */
+  scanf ("%jd", jp); /* { dg-warning "unknown|format" "%j is unsupported" } */
+  scanf ("%zu", zp); /* { dg-warning "unknown|format" "%z is unsupported" } */
+  scanf ("%td", tp); /* { dg-warning "unknown|format" "%t is unsupported" } */
+  /* The formats F, a, A are new.  */
+  scanf ("%F", fp); /* { dg-warning "unknown|format" "%F is unsupported" } */
+  scanf ("%a", fp); /* { dg-warning "unknown|format" "%a is unsupported" } */
+  scanf ("%A", fp); /* { dg-warning "unknown|format" "%A is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-3.c
@@ -0,0 +1,20 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char **sp, wchar_t **lsp)
+{
+  /* %a formats for allocation, only recognized in C90 mode, are a
+     GNU extension.
+  */
+  scanf ("%as", sp); /* { dg-warning "flag" "%as is unsupported" } */
+  scanf ("%aS", lsp); /* { dg-warning "format|flag" "%aS is unsupported" } */
+  scanf ("%a[bcd]", sp); /* { dg-warning "flag" "%a[] is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-4.c
@@ -0,0 +1,31 @@
+/* Test for scanf formats.  Test that the C90 functions get their default
+   attributes in strict C90 mode, but the C99 and gettext functions
+   do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, char *s, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5)
+{
+  fscanf (stdin, "%d", ip);
+  fscanf (stdin, "%ld", ip); /* { dg-warning "format" "fscanf" } */
+  scanf ("%d", ip);
+  scanf ("%ld", ip); /* { dg-warning "format" "scanf" } */
+  sscanf (s, "%d", ip);
+  sscanf (s, "%ld", ip); /* { dg-warning "format" "sscanf" } */
+  vfscanf (stdin, "%d", v0);
+  vscanf ("%d", v2);
+  vsscanf (s, "%d", v4);
+  scanf (gettext ("%d"), ip);
+  scanf (gettext ("%ld"), ip);
+  scanf (dgettext ("", "%d"), ip);
+  scanf (dgettext ("", "%ld"), ip);
+  scanf (dcgettext ("", "%d", 0), ip);
+  scanf (dcgettext ("", "%ld", 0), ip);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-5.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-5.c
@@ -0,0 +1,20 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char **sp, wchar_t **lsp)
+{
+  /* m assignment-allocation modifier, recognized in both C90
+     and C99 modes, is a POSIX and ISO/IEC WDTR 24731-2 extension.  */
+  scanf ("%ms", sp); /* { dg-warning "unknown|format" "%ms is unsupported" } */
+  scanf ("%mS", lsp); /* { dg-warning "unknown|format" "%mS is unsupported" } */
+  scanf ("%mls", lsp); /* { dg-warning "unknown|format" "%mls is unsupported" } */
+  scanf ("%m[bcd]", sp); /* { dg-warning "unknown|format" "%m[] is unsupported" } */
+  scanf ("%ml[bcd]", lsp); /* { dg-warning "unknown|format" "%ml[] is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-1.c
@@ -0,0 +1,20 @@
+/* Test for strftime formats.  Formats using C90 features.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wformat-y2k" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.12.3.5 (pages 174-175).  */
+  /* Formats which are Y2K-compliant (no 2-digit years).  */
+  strftime (s, m, "%a%A%b%B%d%H%I%j%m%M%p%S%U%w%W%X%Y%Z%%", tp);
+  /* Formats with 2-digit years.  */
+  strftime (s, m, "%y", tp); /* { dg-warning "only last 2" "2-digit year" } */
+  /* Formats with 2-digit years in some locales.  */
+  strftime (s, m, "%c", tp); /* { dg-warning "some locales" "2-digit year" } */
+  strftime (s, m, "%x", tp); /* { dg-warning "some locales" "2-digit year" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-2.c
@@ -0,0 +1,28 @@
+/* Test for strftime formats.  Rejection of formats using C99 features in
+   pedantic C90 mode.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wformat-y2k" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  strftime (s, m, "%C", tp); /* { dg-warning "format" "%C is unsupported" } */
+  strftime (s, m, "%D", tp); /* { dg-warning "format" "%D is unsupported" } */
+  strftime (s, m, "%e", tp); /* { dg-warning "format" "%e is unsupported" } */
+  strftime (s, m, "%F", tp); /* { dg-warning "format" "%F is unsupported" } */
+  strftime (s, m, "%g", tp); /* { dg-warning "format" "%g is unsupported" } */
+  strftime (s, m, "%G", tp); /* { dg-warning "format" "%G is unsupported" } */
+  strftime (s, m, "%h", tp); /* { dg-warning "format" "%h is unsupported" } */
+  strftime (s, m, "%n", tp); /* { dg-warning "format" "%n is unsupported" } */
+  strftime (s, m, "%r", tp); /* { dg-warning "format" "%r is unsupported" } */
+  strftime (s, m, "%R", tp); /* { dg-warning "format" "%R is unsupported" } */
+  strftime (s, m, "%t", tp); /* { dg-warning "format" "%t is unsupported" } */
+  strftime (s, m, "%T", tp); /* { dg-warning "format" "%T is unsupported" } */
+  strftime (s, m, "%u", tp); /* { dg-warning "format" "%u is unsupported" } */
+  strftime (s, m, "%V", tp); /* { dg-warning "format" "%V is unsupported" } */
+  strftime (s, m, "%z", tp); /* { dg-warning "C" "%z not in C90" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c94-printf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c94-printf-1.c
@@ -0,0 +1,19 @@
+/* Test for printf formats.  Changes in C94 to C90.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:199409 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (wint_t lc, wchar_t *ls)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.1 (pages 131-134),
+     as amended by ISO/IEC 9899:1990/Amd.1:1995 (E) (pages 4-5).
+     We do not repeat here all the C90 format checks, but just verify
+     that %ls and %lc are accepted without warning.
+  */
+  printf ("%lc", lc);
+  printf ("%ls", ls);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c94-scanf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c94-scanf-1.c
@@ -0,0 +1,18 @@
+/* Test for scanf formats.  Changes in C94 to C90.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:199409 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (wchar_t *ls)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.2 (pages 134-138),
+     as amended by ISO/IEC 9899:1990/Amd.1:1995 (E) (pages 5-6).
+     We do not repeat here all the C90 format checks, but just verify
+     that %ls, %lc, %l[] are accepted without warning.
+  */
+  scanf ("%lc%ls%l[abc]", ls, ls, ls);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-1.c
@@ -0,0 +1,109 @@
+/* Test for printf formats.  Formats using C99 features, including cases
+   where C99 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, unsigned int u, double d, char *s, void *p, int *n,
+     long double ld, wint_t lc, wchar_t *ls, long long int ll,
+     unsigned long long int ull, signed char *ss, unsigned char *us,
+     long long int *lln, intmax_t j, uintmax_t uj, intmax_t *jn,
+     size_t z, signed_size_t sz, signed_size_t *zn,
+     ptrdiff_t t, ptrdiff_t *tn)
+{
+  /* See ISO/IEC 9899:1999 (E) subclause 7.19.6.1 (pages 273-281).
+     We do not repeat here most of the checks for correct C90 formats
+     or completely broken formats.
+  */
+  /* Valid and invalid %h, %hh, %l, %j, %z, %t, %L constructions.  */
+  printf ("%hf", d); /* { dg-warning "length" "bad use of %h" } */
+  printf ("%hF", d); /* { dg-warning "unknown|format" "bad use of %hF" } */
+  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 ("%ha", d); /* { dg-warning "unknown|format" "bad use of %ha" } */
+  printf ("%hA", d); /* { dg-warning "unknown|format" "bad use of %hA" } */
+  printf ("%hc", i);
+  printf ("%hs", (short *)s);
+  printf ("%hp", p); /* { dg-warning "length" "bad use of %h" } */
+  printf ("%lc", lc);
+  printf ("%ls", ls);
+  printf ("%lp", p); /* { dg-warning "length|C" "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" } */
+  /* 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" } */
+  /* 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% 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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 ("%-08F", d); /* { dg-warning "unknown|format" "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 ("%-08a", d); /* { dg-warning "unknown|format" "0 flag ignored with - flag" } */
+  printf ("%-08A", d); /* { dg-warning "unknown|format" "0 flag ignored with - flag" } */
+  /* Various tests of bad argument types.  Mostly covered in c90-printf-1.c;
+     here just test for pointer target sign with %hhn.  (Probably allowed
+     by the standard, but a bad idea, so GCC should diagnose if what
+     is used is not signed char *.)
+  */
+  printf ("%hhn", s); /* { dg-warning "unknown|format" "%hhn is unsupported" } */
+  printf ("%hhn", us); /* { dg-warning "unknown|format" "%hhn is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-2.c
@@ -0,0 +1,32 @@
+/* Test for printf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, long long ll, size_t z, wint_t lc, wchar_t *ls)
+{
+  /* The length modifiers q, Z and L as applied to integer formats are
+     extensions.
+  */
+  printf ("%qd", ll); /* { dg-warning "unknown|format" "%q length is unsupported" } */
+  printf ("%Ld", ll); /* { dg-warning "unknown|format" "%L length is unsupported" } */
+  printf ("%Zd", z); /* { dg-warning "unknown|format" "%Z length is unsupported" } */
+  /* The conversion specifiers C and S are X/Open extensions; the
+     conversion specifier m is a GNU extension.
+  */
+  printf ("%m"); /* { dg-warning "unknown" "printf %m is unsupported" } */
+  printf ("%C", lc); /* { dg-warning "C" "printf %C" } */
+  printf ("%S", ls); /* { dg-warning "C" "printf %S" } */
+  /* The flag character ', and the use of operand number $ formats, are
+     X/Open extensions.
+  */
+  printf ("%'d", i); /* { dg-warning "C" "printf ' flag" } */
+  printf ("%1$d", i); /* { dg-warning "C" "printf $ format" } */
+  printf ("%Ix", z); /* { dg-warning "C" "printf I format" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-3.c
@@ -0,0 +1,40 @@
+/* Test for printf formats.  Test that the C99 functions get their default
+   attributes in strict C99 mode, but the gettext functions do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, char *s, size_t n, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5, va_list v6, va_list v7)
+{
+  fprintf (stdout, "%d", i);
+  fprintf (stdout, "%ld", i); /* { dg-warning "format" "fprintf" } */
+  printf ("%d", i);
+  printf ("%ld", i); /* { dg-warning "format" "printf" } */
+  /* The "unlocked" functions shouldn't warn in c99 mode.  */
+  fprintf_unlocked (stdout, "%ld", i);
+  printf_unlocked ("%ld", i);
+  sprintf (s, "%d", i);
+  sprintf (s, "%ld", i); /* { dg-warning "format" "sprintf" } */
+  snprintf (s, n, "%d", i);
+  snprintf (s, n, "%ld", i); /* { dg-warning "format" "snprintf" } */
+  vfprintf (stdout, "%d", v0);
+  vfprintf (stdout, "%Y", v1); /* { dg-warning "format" "vfprintf" } */
+  vprintf ("%d", v0);
+  vprintf ("%Y", v1); /* { dg-warning "format" "vprintf" } */
+  vsprintf (s, "%d", v0);
+  vsprintf (s, "%Y", v1); /* { dg-warning "format" "vsprintf" } */
+  vsnprintf (s, n, "%d", v0);
+  vsnprintf (s, n, "%Y", v1); /* { dg-warning "format" "vsnprintf" } */
+  printf (gettext ("%d"), i);
+  printf (gettext ("%ld"), (long) i);
+  printf (dgettext ("", "%d"), i);
+  printf (dgettext ("", "%ld"), (long) i);
+  printf (dcgettext ("", "%d", 0), i);
+  printf (dcgettext ("", "%ld", 0), (long) i);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-1.c
@@ -0,0 +1,63 @@
+/* Test for scanf formats.  Formats using C99 features, including cases
+   where C99 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, unsigned int *uip, short int *hp, unsigned short int *uhp,
+     signed char *hhp, unsigned char *uhhp, long int *lp,
+     unsigned long int *ulp, float *fp, double *dp, long double *ldp, char *s,
+     void **pp, int *n, long long *llp, unsigned long long *ullp, wchar_t *ls,
+     short int *hn, signed char *hhn, long int *ln, long long int *lln,
+     intmax_t *jp, uintmax_t *ujp, intmax_t *jn, size_t *zp,
+     signed_size_t *szp, signed_size_t *zn, ptrdiff_t *tp,
+     unsigned_ptrdiff_t *utp, ptrdiff_t *tn)
+{
+  /* See ISO/IEC 9899:1999 (E) subclause 7.19.6.2 (pages 281-288).
+     We do not repeat here most of the checks for correct C90 formats
+     or completely broken formats.
+  */
+  /* Valid, invalid and silly assignment-suppression
+     and width constructions.
+  */
+  scanf ("%*d%*i%*o%*u%*x%*X%*e%*E%*f%*g%*G%*s%*[abc]%*c%*p");
+  scanf ("%*2d%*8s%*3c");
+  scanf ("%*n", n); /* { dg-warning "suppress" "suppression of %n" } */
+  scanf ("%*hd"); /* { dg-warning "together" "suppression with length" } */
+  scanf ("%2d%3i%4o%5u%6x%7X%10e%11E%12f%14g%15G%16s%3[abc]%4c%5p",
+	 ip, ip, uip, uip, uip, uip, fp, fp, fp, fp, fp,
+	 s, s, s, pp);
+  scanf ("%0d", ip); /* { dg-warning "width" "warning for zero width" } */
+  scanf ("%3n", n); /* { dg-warning "width" "width with %n" } */
+  /* Valid and invalid %h, %hh, %l, %j, %z, %t, %L constructions.  */
+  scanf ("%hd%hi%ho%hu%hx%hX%hn", hp, hp, uhp, uhp, uhp, uhp, hn);
+  scanf ("%he", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hE", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hf", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hg", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hG", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hs", hp);
+  scanf ("%h[ac]", s); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hc", (short *)s);
+  scanf ("%hp", pp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hhd", hhp); /* { dg-warning "unknown|format" "%hh is unsupported" } */
+  scanf ("%ld%li%lo%lu%lx%lX%ln", lp, lp, ulp, ulp, ulp, ulp, ln);
+  scanf ("%le%lE%lf%lg%lG", dp, dp, dp, dp, dp);
+  scanf ("%lp", pp); /* { dg-warning "length" "bad use of %l" } */
+  scanf ("%ls", ls);
+  scanf ("%l[ac]", ls);
+  scanf ("%lc", ls);
+  scanf ("%jd", jp); /* { dg-warning "unknown|format" "%j not supported" } */
+  scanf ("%zd", zp); /* { dg-warning "unknown|format" "%z not supported" } */
+  scanf ("%td", tp); /* { dg-warning "unknown|format" "%t not supported" } */
+  scanf ("%Lf", llp); /* { dg-warning "unknown|format" "bad use of %L is not supported" } */
+  /* Valid uses of each bare conversion.  */
+  scanf ("%d%i%o%u%x%X%e%E%f%g%G%s%[abc]%c%p%n%%", ip, ip, uip, uip, uip,
+         uip, fp, fp, fp, fp, fp, s, s, s, pp, n);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-2.c
@@ -0,0 +1,27 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, long long int *llp, wchar_t *ls)
+{
+  /* The length modifiers q and L as applied to integer formats are
+     extensions.
+  */
+  scanf ("%qd", llp); /* { dg-warning "unknown|format" "%q is unsupported" } */
+  scanf ("%Ld", llp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  /* The conversion specifiers C and S are X/Open extensions.  */
+  scanf ("%C", ls); /* { dg-warning "C" "scanf %C" } */
+  scanf ("%S", ls); /* { dg-warning "C" "scanf %S" } */
+  /* The use of operand number $ formats is an X/Open extension.  */
+  scanf ("%1$d", ip); /* { dg-warning "C" "scanf $ format" } */
+  /* glibc also supports flags ' and I on scanf formats as an extension.  */
+  scanf ("%'d", ip); /* { dg-warning "C" "scanf ' flag" } */
+  scanf ("%Id", (ssize_t *)ip); /* { dg-warning "C" "scanf I flag" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-3.c
@@ -0,0 +1,33 @@
+/* Test for scanf formats.  Test that the C99 functions get their default
+   attributes in strict C99 mode, but the gettext functions do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, char *s, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5)
+{
+  fscanf (stdin, "%d", ip);
+  fscanf (stdin, "%ld", ip); /* { dg-warning "format" "fscanf" } */
+  scanf ("%d", ip);
+  scanf ("%ld", ip); /* { dg-warning "format" "scanf" } */
+  sscanf (s, "%d", ip);
+  sscanf (s, "%ld", ip); /* { dg-warning "format" "sscanf" } */
+  vfscanf (stdin, "%d", v0);
+  vfscanf (stdin, "%Y", v1); /* { dg-warning "format" "vfscanf" } */
+  vscanf ("%d", v2);
+  vscanf ("%Y", v3); /* { dg-warning "format" "vscanf" } */
+  vsscanf (s, "%d", v4);
+  vsscanf (s, "%Y", v5); /* { dg-warning "format" "vsscanf" } */
+  scanf (gettext ("%d"), ip);
+  scanf (gettext ("%ld"), ip);
+  scanf (dgettext ("", "%d"), ip);
+  scanf (dgettext ("", "%ld"), ip);
+  scanf (dcgettext ("", "%d", 0), ip);
+  scanf (dcgettext ("", "%ld", 0), ip);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-4.c
@@ -0,0 +1,20 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char **sp, wchar_t **lsp)
+{
+  /* m assignment-allocation modifier, recognized in both C90
+     and C99 modes, is a POSIX and ISO/IEC WDTR 24731-2 extension.  */
+  scanf ("%ms", sp); /* { dg-warning "unknown|format" "%ms is unsupported" } */
+  scanf ("%mS", lsp); /* { dg-warning "unknown|format" "%mS is unsupported" } */
+  scanf ("%mls", lsp); /* { dg-warning "unknown|format" "%mls is unsupported" } */
+  scanf ("%m[bcd]", sp); /* { dg-warning "unknown|format" "%m[] is unsupported" } */
+  scanf ("%ml[bcd]", lsp); /* { dg-warning "unknown|format" "%ml[] is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-1.c
@@ -0,0 +1,20 @@
+/* Test for strftime formats.  Formats using C99 features.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat -Wformat-y2k" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.12.3.5 (pages 174-175).  */
+  /* Formats which are Y2K-compliant (no 2-digit years).  */
+  strftime (s, m, "%a%A%b%B%d%H%I%j%m%M%p%S%U%w%W%X%Y%z%Z%%", tp);
+  /* Formats with 2-digit years.  */
+  strftime (s, m, "%y", tp); /* { dg-warning "only last 2" "2-digit year" } */
+  /* Formats with 2-digit years in some locales.  */
+  strftime (s, m, "%c", tp); /* { dg-warning "some locales" "2-digit year" } */
+  strftime (s, m, "%x", tp); /* { dg-warning "some locales" "2-digit year" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-2.c
@@ -0,0 +1,20 @@
+/* Test for strftime formats.  Rejection of extensions in pedantic mode.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  /* %P is a lowercase version of %p.  */
+  strftime (s, m, "%P", tp); /* { dg-warning "unknown" "strftime %P" } */
+  /* %k is %H but padded with a space rather than 0 if necessary.  */
+  strftime (s, m, "%k", tp); /* { dg-warning "unknown" "strftime %k" } */
+  /* %l is %I but padded with a space rather than 0 if necessary.  */
+  strftime (s, m, "%l", tp); /* { dg-warning "unknown" "strftime %l" } */
+  /* %s is the number of seconds since the Epoch.  */
+  strftime (s, m, "%s", tp); /* { dg-warning "unknown" "strftime %s" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_cast-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_cast-1.c
@@ -0,0 +1,17 @@
+/* Test for strings cast through integer types: should not be treated
+   as format strings unless the types are of the same width as
+   pointers (intptr_t or similar).  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+f (int x)
+{
+  printf("%s", x); /* { dg-warning "format" } */
+  printf((char *)(size_t)"%s", x); /* { dg-warning "format" } */
+  printf((char *)(char)"%s", x); /* { dg-warning "cast from pointer to integer of different size" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-1.c
@@ -0,0 +1,40 @@
+/* Test for warnings for missing format attributes.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  vprintf (fmt, ap); /* { dg-warning "candidate" "printf attribute warning" } */
+  va_end (ap);
+}
+
+void
+bar (const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  vscanf (fmt, ap); /* { dg-warning "candidate" "scanf attribute warning" } */
+  va_end (ap);
+}
+
+__attribute__((__format__(__ms_printf__, 1, 2))) void
+foo2 (const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  vprintf (fmt, ap);
+  va_end (ap);
+}
+
+void
+vfoo (const char *fmt, va_list arg)
+{
+  vprintf (fmt, arg); /* { dg-warning "candidate" "printf attribute warning 2" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-2.c
@@ -0,0 +1,17 @@
+/* Test for warnings for missing format attributes.  Don't warn if no
+   relevant parameters for a format attribute; see c/1017.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, ...)
+{
+  va_list ap;
+  va_start (ap, i);
+  vprintf ("Foo %s bar %s", ap); /* { dg-bogus "candidate" "bogus printf attribute warning" } */
+  va_end (ap);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-3.c
@@ -0,0 +1,27 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+void
+foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
+{
+  noattr_t na1 = na;
+  noattr_t na2 = a; /* { dg-warning "candidate" "initialization warning" } */
+  attr_t a1 = na;
+  attr_t a2 = a;
+
+  vnoattr_t vna1 = vna;
+  vnoattr_t vna2 = va; /* { dg-warning "candidate" "initialization warning" } */
+  vattr_t va1 = vna;
+  vattr_t va2 = va;
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-4.c
@@ -0,0 +1,33 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+void
+foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
+{
+  noattr_t na1, na2;
+  attr_t a1, a2;
+
+  vnoattr_t vna1, vna2;
+  vattr_t va1, va2;
+
+  na1 = na;
+  na2 = a; /* { dg-warning "candidate" "assignment warning" } */
+  a1 = na;
+  a2 = a;
+
+  vna1 = vna;
+  vna2 = va; /* { dg-warning "candidate" "assignment warning" } */
+  va1 = vna;
+  va1 = va;
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-5.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-5.c
@@ -0,0 +1,49 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+noattr_t
+foo1 (noattr_t na, attr_t a, int i)
+{
+  if (i)
+    return na;
+  else
+    return a; /* { dg-warning "candidate" "return type warning" } */
+}
+
+attr_t
+foo2 (noattr_t na, attr_t a, int i)
+{
+  if (i)
+    return na;
+  else
+    return a;
+}
+
+vnoattr_t
+foo3 (vnoattr_t vna, vattr_t va, int i)
+{
+  if (i)
+    return vna;
+  else
+    return va; /* { dg-warning "candidate" "return type warning" } */
+}
+
+vattr_t
+foo4 (vnoattr_t vna, vattr_t va, int i)
+{
+  if (i)
+    return vna;
+  else
+    return va;
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-6.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-6.c
@@ -0,0 +1,32 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+extern void foo1 (noattr_t);
+extern void foo2 (attr_t);
+extern void foo3 (vnoattr_t);
+extern void foo4 (vattr_t);
+
+void
+foo (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
+{
+  foo1 (na);
+  foo1 (a); /* { dg-warning "candidate" "parameter passing warning" } */
+  foo2 (na);
+  foo2 (a);
+
+  foo3 (vna);
+  foo3 (va); /* { dg-warning "candidate" "parameter passing warning" } */
+  foo4 (vna);
+  foo4 (va);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_multattr-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_multattr-1.c
@@ -0,0 +1,51 @@
+/* Test for multiple format attributes.  Test for printf and scanf attributes
+   together.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* If we specify multiple attributes for a single function, they should
+   all apply.  This should apply whether they are on the same declaration
+   or on different declarations.  */
+
+extern void my_vprintf_scanf (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_printf__, 1, 0)))
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern void my_vprintf_scanf2 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)))
+     __attribute__((__format__(__ms_printf__, 1, 0)));
+
+extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_printf__, 1, 0)));
+extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_printf__, 1, 0)));
+
+void
+foo (va_list ap, int *ip, long *lp)
+{
+  my_vprintf_scanf ("%d", ap, "%d", ip);
+  my_vprintf_scanf ("%d", ap, "%ld", lp);
+  my_vprintf_scanf ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf2 ("%d", ap, "%d", ip);
+  my_vprintf_scanf2 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf2 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf2 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf3 ("%d", ap, "%d", ip);
+  my_vprintf_scanf3 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf3 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf3 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf4 ("%d", ap, "%d", ip);
+  my_vprintf_scanf4 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf4 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf4 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_multattr-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_multattr-2.c
@@ -0,0 +1,40 @@
+/* Test for multiple format attributes.  Test for printf and scanf attributes
+   together, in different places on the declarations.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* If we specify multiple attributes for a single function, they should
+   all apply, wherever they are placed on the declarations.  */
+
+extern __attribute__((__format__(__ms_printf__, 1, 0))) void
+     my_vprintf_scanf (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern void (__attribute__((__format__(__ms_printf__, 1, 0))) my_vprintf_scanf2)
+     (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern __attribute__((__format__(__ms_scanf__, 3, 4))) void
+     (__attribute__((__format__(__ms_printf__, 1, 0))) my_vprintf_scanf3)
+     (const char *, va_list, const char *, ...);
+
+void
+foo (va_list ap, int *ip, long *lp)
+{
+  my_vprintf_scanf ("%d", ap, "%d", ip);
+  my_vprintf_scanf ("%d", ap, "%ld", lp);
+  my_vprintf_scanf ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf2 ("%d", ap, "%d", ip);
+  my_vprintf_scanf2 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf2 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf2 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf3 ("%d", ap, "%d", ip);
+  my_vprintf_scanf3 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf3 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf3 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_multattr-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_multattr-3.c
@@ -0,0 +1,29 @@
+/* Test for multiple format_arg attributes.  Test for both branches
+   getting checked.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+extern char *ngettext (const char *, const char *, unsigned long int)
+     __attribute__((__format_arg__(1))) __attribute__((__format_arg__(2)));
+
+void
+foo (long l, int nfoo)
+{
+  printf (ngettext ("%d foo", "%d foos", nfoo), nfoo);
+  printf (ngettext ("%d foo", "%d foos", l), l); /* { dg-warning "int" "wrong type in conditional expr" } */
+  printf (ngettext ("%d foo", "%ld foos", l), l); /* { dg-warning "int" "wrong type in conditional expr" } */
+  printf (ngettext ("%ld foo", "%d foos", l), l); /* { dg-warning "int" "wrong type in conditional expr" } */
+  /* Should allow one case to have extra arguments.  */
+  printf (ngettext ("1 foo", "%d foos", nfoo), nfoo);
+  printf (ngettext ("1 foo", "many foos", nfoo), nfoo); /* { dg-warning "too many" "too many args in all branches" } */
+  printf (ngettext ("", "%d foos", nfoo), nfoo);
+  printf (ngettext ("1 foo", (nfoo > 0) ? "%d foos" : "no foos", nfoo), nfoo);
+  printf (ngettext ("%d foo", (nfoo > 0) ? "%d foos" : "no foos", nfoo), nfoo);
+  printf (ngettext ("%ld foo", (nfoo > 0) ? "%d foos" : "no foos", nfoo), nfoo); /* { dg-warning "long int" "wrong type" } */
+  printf (ngettext ("%d foo", (nfoo > 0) ? "%ld foos" : "no foos", nfoo), nfoo); /* { dg-warning "long int" "wrong type" } */
+  printf (ngettext ("%d foo", (nfoo > 0) ? "%d foos" : "%ld foos", nfoo), nfoo); /* { dg-warning "long int" "wrong type" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-1.c
@@ -0,0 +1,15 @@
+/* Test for warnings for extra format arguments being disabled by
+   -Wno-format-extra-args.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wno-format-extra-args" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i)
+{
+  printf ("foo", i);
+  printf ("%1$d", i, i);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-2.c
@@ -0,0 +1,28 @@
+/* Test for warnings for extra format arguments being disabled by
+   -Wno-format-extra-args.  Test which warnings still apply with $
+   operand numbers.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wno-format-extra-args" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, int *ip, va_list va)
+{
+  printf ("%3$d%1$d", i, i, i); /* { dg-warning "before used" "unused $ operand" } */
+  printf ("%2$d%1$d", i, i, i);
+  vprintf ("%3$d%1$d", va); /* { dg-warning "before used" "unused $ operand" } */
+  /* With scanf formats, gaps in the used arguments are allowed only if the
+     arguments are all pointers.  In such a case, should only give the lesser
+     warning about unused arguments rather than the more serious one about
+     argument gaps.  */
+  scanf ("%3$d%1$d", ip, ip, ip);
+  /* If there are non-pointer arguments unused at the end, this is also OK.  */
+  scanf ("%3$d%1$d", ip, ip, ip, i);
+  scanf ("%3$d%1$d", ip, i, ip); /* { dg-warning "before used" "unused $ scanf non-pointer operand" } */
+  /* Can't check the arguments in the vscanf case, so should suppose the
+     lesser problem.  */
+  vscanf ("%3$d%1$d", va);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_no-y2k-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_no-y2k-1.c
@@ -0,0 +1,13 @@
+/* Test for warnings for Y2K problems not being on by default.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  strftime (s, m, "%y%c%x", tp);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-1.c
@@ -0,0 +1,14 @@
+/* Test for warnings for non-string-literal formats.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wformat-nonliteral" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t i)
+{
+  printf ((const char *)i, i); /* { dg-warning "argument types" "non-literal" } */
+  printf (s, i); /* { dg-warning "argument types" "non-literal" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-2.c
@@ -0,0 +1,14 @@
+/* Test for warnings for non-string-literal formats.  Test with -Wformat=2.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat=2" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t i)
+{
+  printf ((const char *)i, i); /* { dg-warning "argument types" "non-literal" } */
+  printf (s, i); /* { dg-warning "argument types" "non-literal" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-3.c
@@ -0,0 +1,13 @@
+/* Test for warnings for non-string-literal formats.  Test for strftime formats.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wformat-nonliteral" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp, char *fmt)
+{
+  strftime (s, m, fmt, tp); /* { dg-warning "format string" "non-literal" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nul-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nul-1.c
@@ -0,0 +1,15 @@
+/* Test diagnostics for suppressing contains nul
+   -Wformat.  -Wformat.  */
+/* Origin: Bruce Korb <bkorb@gnu.org> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat -Wno-format-contains-nul" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (void)
+{
+  static char const fmt[] = "x%s\0%s\n\0abc";
+  printf (fmt+4, fmt+8); /* { dg-bogus "embedded.*in format" "bogus embed warning" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nul-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nul-2.c
@@ -0,0 +1,17 @@
+/* Test diagnostics for options used on their own without
+   -Wformat.  -Wformat-.  */
+/* Origin: Bruce Korb <bkorb@gnu.org> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+
+/* { dg-warning "embedded .* in format" "ignored" { target *-*-* } 0 } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+fumble (void)
+{
+  static char const fmt[] = "x%s\0%s\n\0abc";
+  printf (fmt+4, fmt+8);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_null-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_null-1.c
@@ -0,0 +1,28 @@
+/* Test for some aspects of null format string handling.  */
+/* Origin: Jason Thorpe <thorpej@wasabisystems.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+extern void my_printf (const char *, ...) __attribute__((format(ms_printf,1,2)));
+extern const char *my_format (const char *, const char *)
+  __attribute__((format_arg(2)));
+
+void
+foo (int i1)
+{
+  /* Warning about a null format string has been decoupled from the actual
+     format check.  However, we still expect to be warned about any excess
+     arguments after a null format string.  */
+  my_printf (NULL);
+  my_printf (NULL, i1); /* { dg-warning "too many" "null format with arguments" } */
+
+  my_printf (my_format ("", NULL));
+  my_printf (my_format ("", NULL), i1); /* { dg-warning "too many" "null format_arg with arguments" } */
+
+  /* While my_printf allows a null argument, dgettext does not, so we expect
+     a null argument warning here.  */
+  my_printf (dgettext ("", NULL)); /* { dg-warning "null" "null format with dgettext" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_plus-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_plus-1.c
@@ -0,0 +1,21 @@
+/* Test for printf formats using string literal plus constant.
+ */
+/* Origin: Jakub Jelinek <jakub@redhat.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat=2" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i)
+{
+  printf ("%%d\n" + 1, i);
+  printf (5 + "%.-*d%3d\n", i);
+  printf ("%d%d" + 2, i, i);	/* { dg-warning "arguments" "wrong number of args" } */
+  printf (3 + "%d\n");		/* { dg-warning "zero-length" "zero-length string" } */
+  printf ("%d\n" + i, i);	/* { dg-warning "not a string" "non-constant addend" } */
+  printf ("%d\n" + 10);		/* { dg-warning "not a string" "too large addend" } */
+  printf ("%d\n" - 1, i);	/* { dg-warning "not a string" "minus constant" } */
+  printf ("%d\n" + -1, i);	/* { dg-warning "not a string" "negative addend" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_sec-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_sec-1.c
@@ -0,0 +1,13 @@
+/* Test for security warning when non-literal format has no arguments.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wformat-security" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s)
+{
+  printf (s); /* { dg-warning "no format arguments" "security warning" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_unnamed-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_unnamed-1.c
@@ -0,0 +1,24 @@
+/* Test for warnings with possibly unnamed integer types.  Bug 24329.  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+/* { dg-options "-Wformat -msse" { target { { i?86-*-* x86_64-*-* } && ilp32 } } } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* Definition of TItype follows same logic as in gcc.dg/titype-1.c,
+   but must be a #define to avoid giving the type a name.  */
+#if defined(__LP64__) && !defined(__hppa__)
+#define TItype int __attribute__ ((mode (TI)))
+#else
+#define TItype long
+#endif
+
+void
+f (TItype x)
+{
+  printf("%d", x); /* { dg-warning "expects type" } */
+  printf("%d", 141592653589793238462643383279502884197169399375105820974944); /* { dg-warning "expects type" } */
+  /* { dg-warning "unsigned only|too large" "constant" { target *-*-* } 22 } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_va-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_va-1.c
@@ -0,0 +1,14 @@
+/* Test for strange warning in format checking.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (void *p)
+{
+  printf ("%d", p); /* { dg-bogus "va_list" "wrong type in format warning" } */
+  /* { dg-warning "format" "format error" { target *-*-* } 12 } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_zero-length-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_zero-length-1.c
@@ -0,0 +1,16 @@
+/* Test the -Wno-format-zero-length option, which suppresses warnings
+   about zero-length formats.  */
+/* Origin: Jason Thorpe <thorpej@wasabisystems.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wno-format-zero-length" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (void)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.1 (pages 131-134).  */
+  /* Zero-length format strings are allowed.  */
+  printf ("");
+}
Index: gcc/gcc/testsuite/gcc.dg/format/multattr-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/multattr-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/multattr-1.c
@@ -4,6 +4,7 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 /* If we specify multiple attributes for a single function, they should
@@ -11,22 +12,22 @@
    or on different declarations.  */
 
 extern void my_vprintf_scanf (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__printf__, 1, 0)))
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)))
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
 extern void my_vprintf_scanf2 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)))
-     __attribute__((__format__(__printf__, 1, 0)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)))
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)));
 
 extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__printf__, 1, 0)));
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)));
 extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
 extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__printf__, 1, 0)));
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)));
 
 void
 foo (va_list ap, int *ip, long *lp)
Index: gcc/gcc/testsuite/gcc.dg/format/multattr-2.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/multattr-2.c
+++ gcc/gcc/testsuite/gcc.dg/format/multattr-2.c
@@ -4,21 +4,22 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 /* If we specify multiple attributes for a single function, they should
    all apply, wherever they are placed on the declarations.  */
 
-extern __attribute__((__format__(__printf__, 1, 0))) void
+extern __attribute__((__format__(gnu_attr___printf__, 1, 0))) void
      my_vprintf_scanf (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
-extern void (__attribute__((__format__(__printf__, 1, 0))) my_vprintf_scanf2)
+extern void (__attribute__((__format__(gnu_attr___printf__, 1, 0))) my_vprintf_scanf2)
      (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
-extern __attribute__((__format__(__scanf__, 3, 4))) void
-     (__attribute__((__format__(__printf__, 1, 0))) my_vprintf_scanf3)
+extern __attribute__((__format__(gnu_attr___scanf__, 3, 4))) void
+     (__attribute__((__format__(gnu_attr___printf__, 1, 0))) my_vprintf_scanf3)
      (const char *, va_list, const char *, ...);
 
 void
Index: gcc/gcc/testsuite/gcc.dg/format/null-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/null-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/null-1.c
@@ -3,9 +3,10 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern void my_printf (const char *, ...) __attribute__((format(printf,1,2)));
+extern void my_printf (const char *, ...) __attribute__((format(gnu_attr_printf,1,2)));
 extern const char *my_format (const char *, const char *)
   __attribute__((format_arg(2)));
 
=

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf formatters to c-format.c
  2008-03-18 15:07                                       ` Kai Tietz
  2008-03-19  5:01                                         ` NightStrike
@ 2008-03-19  6:22                                         ` Danny Smith
  2008-03-19  9:42                                           ` Kai Tietz
  1 sibling, 1 reply; 61+ messages in thread
From: Danny Smith @ 2008-03-19  6:22 UTC (permalink / raw)
  To: Kai Tietz; +Cc: NightStrike, GCC Patches, ktietz70

On Wed, Mar 19, 2008 at 3:34 AM, Kai Tietz <Kai.Tietz@onevision.com> wrote:
> NightStrike <nightstrike@gmail.com> wrote on 18.03.2008 14:34:11:
>
>
> > Attached is the gcc test log for formatters for this latest patch
>  > (recompiled and retested in like 10 minutes :)
>
>  Sorry, this was a typo of mine. I removed the testcase ms_warnll-1.c
>  completly. It makes not so much sense to check ISO C90 ll for mingw :)
>  I attached the updated patch.

Actually., I think it makes a lot of sense to test whether the
appropriate warning is reported.
Also, if you look again at the msdn page you will note that the field
width flag (a glibc extensuion) is not documented.
Indeed if you test a format like "%5m", you will see that it  produces
this as output:  "m"   The use of  this flag should produce a warning.

Danny
>
>  Cheers,
>   Kai
>
>
>
>  |  (\_/)  This is Bunny. Copy and paste Bunny
>  | (='.'=) into your signature to help him gain
>  | (")_(") world domination.
>
>
>
> ------------------------------------------------------------------------------------------
>   OneVision Software Entwicklungs GmbH & Co. KG
>   Dr.-Leo-Ritter-Straße 9 - 93049 Regensburg
>   Tel: +49.(0)941.78004.0 - Fax: +49.(0)941.78004.489 - www.OneVision.com
>   Commerzbank Regensburg - BLZ 750 400 62 - Konto 6011050
>   Handelsregister: HRA 6744, Amtsgericht Regensburg
>   Komplementärin: OneVision Software Entwicklungs Verwaltungs GmbH
>   Dr.-Leo-Ritter-Straße 9 – 93049 Regensburg
>   Handelsregister: HRB 8932, Amtsgericht Regensburg - Geschäftsführer:
>  Ulrike Döhler, Manuela Kluger
>
>

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf formatters to c-format.c
  2008-03-18 15:07                                       ` Kai Tietz
@ 2008-03-19  5:01                                         ` NightStrike
  2008-03-19  6:22                                         ` Danny Smith
  1 sibling, 0 replies; 61+ messages in thread
From: NightStrike @ 2008-03-19  5:01 UTC (permalink / raw)
  To: Kai Tietz; +Cc: Danny Smith, GCC Patches, ktietz70

[-- Attachment #1: Type: text/plain, Size: 683 bytes --]

On 3/18/08, Kai Tietz <Kai.Tietz@onevision.com> wrote:
> NightStrike <nightstrike@gmail.com> wrote on 18.03.2008 14:34:11:
>
> > Attached is the gcc test log for formatters for this latest patch
> > (recompiled and retested in like 10 minutes :)
>
> Sorry, this was a typo of mine. I removed the testcase ms_warnll-1.c
> completly. It makes not so much sense to check ISO C90 ll for mingw :)
> I attached the updated patch.

Results attached:

testcase /tmp/build/gcc-svn/gcc/gcc/testsuite/gcc.dg/format/format.exp
completed in 16 seconds

                === gcc Summary ===

# of expected passes            3938
# of unexpected failures        2
# of unsupported tests          12

[-- Attachment #2: gcc.log.bz2 --]
[-- Type: application/x-bzip2, Size: 31417 bytes --]

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf  formatters to c-format.c
  2008-03-18 13:44                                     ` NightStrike
  2008-03-18 13:51                                       ` Kai Tietz
@ 2008-03-18 15:07                                       ` Kai Tietz
  2008-03-19  5:01                                         ` NightStrike
  2008-03-19  6:22                                         ` Danny Smith
  1 sibling, 2 replies; 61+ messages in thread
From: Kai Tietz @ 2008-03-18 15:07 UTC (permalink / raw)
  To: NightStrike; +Cc: Danny Smith, GCC Patches, ktietz70

[-- Attachment #1: Type: text/plain, Size: 1116 bytes --]

NightStrike <nightstrike@gmail.com> wrote on 18.03.2008 14:34:11:

> Attached is the gcc test log for formatters for this latest patch
> (recompiled and retested in like 10 minutes :)

Sorry, this was a typo of mine. I removed the testcase ms_warnll-1.c 
completly. It makes not so much sense to check ISO C90 ll for mingw :)
I attached the updated patch.

Cheers,
  Kai



|  (\_/)  This is Bunny. Copy and paste Bunny
| (='.'=) into your signature to help him gain
| (")_(") world domination.

------------------------------------------------------------------------------------------
  OneVision Software Entwicklungs GmbH & Co. KG
  Dr.-Leo-Ritter-Straße 9 - 93049 Regensburg
  Tel: +49.(0)941.78004.0 - Fax: +49.(0)941.78004.489 - www.OneVision.com
  Commerzbank Regensburg - BLZ 750 400 62 - Konto 6011050
  Handelsregister: HRA 6744, Amtsgericht Regensburg
  Komplementärin: OneVision Software Entwicklungs Verwaltungs GmbH
  Dr.-Leo-Ritter-Straße 9 – 93049 Regensburg
  Handelsregister: HRB 8932, Amtsgericht Regensburg - Geschäftsführer: 
Ulrike Döhler, Manuela Kluger


[-- Attachment #2: mingw-msformat.txt --]
[-- Type: text/plain, Size: 150420 bytes --]

Index: gcc/gcc/c-format.c
===================================================================
--- gcc.orig/gcc/c-format.c
+++ gcc/gcc/c-format.c
@@ -62,8 +62,7 @@ enum format_type { printf_format_type, a
 		   gcc_diag_format_type, gcc_tdiag_format_type,
 		   gcc_cdiag_format_type,
 		   gcc_cxxdiag_format_type, gcc_gfc_format_type,
-		   scanf_format_type, strftime_format_type,
-		   strfmon_format_type, format_type_error = -1};
+		   format_type_error = -1};
 
 typedef struct function_format_info
 {
@@ -80,7 +79,8 @@ static bool check_format_string (tree ar
 				 int flags, bool *no_add_attrs);
 static bool get_constant (tree expr, unsigned HOST_WIDE_INT *value,
 			  int validated_p);
-
+static const char *convert_format_name_to_system_name (const char *attr_name);
+static bool cmp_attribs (const char *tattr_name, const char *attr_name);
 
 /* Handle a "format_arg" attribute; arguments as in
    struct attribute_spec.handler.  */
@@ -191,6 +191,8 @@ decode_format_attr (tree args, function_
     {
       const char *p = IDENTIFIER_POINTER (format_type_id);
 
+      p = convert_format_name_to_system_name (p);
+
       info->format_type = decode_format_type (p);
 
       if (info->format_type == format_type_error)
@@ -715,7 +717,7 @@ static const format_char_info monetary_c
 /* This must be in the same order as enum format_type.  */
 static const format_kind_info format_types_orig[] =
 {
-  { "printf",   printf_length_specs,  print_char_table, " +#0-'I", NULL,
+  { "gnu_printf",   printf_length_specs,  print_char_table, " +#0-'I", NULL,
     printf_flag_specs, printf_flag_pairs,
     FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
     'w', 0, 'p', 0, 'L', 0,
@@ -757,18 +759,18 @@ static const format_kind_info format_typ
     0, 0, 0, 0, 0, 0,
     NULL, NULL
   },
-  { "scanf",    scanf_length_specs,   scan_char_table,  "*'I", NULL,
+  { "gnu_scanf",    scanf_length_specs,   scan_char_table,  "*'I", NULL,
     scanf_flag_specs, scanf_flag_pairs,
     FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
     'w', 0, 0, '*', 'L', 'm',
     NULL, NULL
   },
-  { "strftime", NULL,                 time_char_table,  "_-0^#", "EO",
+  { "gnu_strftime", NULL,                 time_char_table,  "_-0^#", "EO",
     strftime_flag_specs, strftime_flag_pairs,
     FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0, 0,
     NULL, NULL
   },
-  { "strfmon",  strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
+  { "gnu_strfmon",  strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
     strfmon_flag_specs, strfmon_flag_pairs,
     FMT_FLAG_ARG_CONVERT, 'w', '#', 'p', 0, 'L', 0,
     NULL, NULL
@@ -847,6 +849,8 @@ decode_format_type (const char *s)
 {
   int i;
   int slen;
+
+  s = convert_format_name_to_system_name (s);
   slen = strlen (s);
   for (i = 0; i < n_format_types; i++)
     {
@@ -1776,7 +1780,22 @@ check_format_info_main (format_check_res
       if (fli)
 	{
 	  while (fli->name != 0 && fli->name[0] != *format_chars)
-	    fli++;
+	    {
+	      if (fli->name[0] == '\0')
+		{
+		  int si  = strlen (fli->name + 1) + 1;
+		  int i = 1;
+		  while (fli->name[i] != 0 && fli->name[i] == format_chars [i - 1])
+		    ++i;
+		 if (si == i)
+		   {
+		     if (si > 2)
+		       format_chars += si - 2;
+		     break;
+		   }
+	       }
+	      fli++;
+	    }
 	  if (fli->name != 0)
 	    {
 	      format_chars++;
@@ -2703,6 +2722,84 @@ init_dynamic_diag_info (void)
 extern const format_kind_info TARGET_FORMAT_TYPES[];
 #endif
 
+#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+extern const target_ovr_attr TARGET_OVERRIDES_FORMAT_ATTRIBUTES[];
+#endif
+
+/* Attributes such as "printf" are equivalent to those such as
+   "gnu_printf" unless this is overridden by a target.  */
+static const target_ovr_attr gnu_target_overrides_format_attributes[] =
+{
+  { "gnu_printf",   "printf" },
+  { "gnu_scanf",    "scanf" },
+  { "gnu_strftime", "strftime" },
+  { "gnu_strfmon",  "strfmon" },
+  { NULL,           NULL }
+};
+
+/* Translate to unified attribute name. This is used in decode_format_type and
+   decode_format_attr. In attr_name the user specified argument is passed. It
+   returns the unified format name from TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+   or the attr_name passed to this function, if there is no matching entry.  */
+static const char *
+convert_format_name_to_system_name (const char *attr_name)
+{
+  int i;
+
+  if (attr_name == NULL || *attr_name == 0
+      || strncmp (attr_name, "gcc_", 4) == 0)
+    return attr_name;
+
+#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+  /* Check if format attribute is overridden by target.  */
+  if (TARGET_OVERRIDES_FORMAT_ATTRIBUTES != NULL
+      && TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT > 0)
+    {
+      for (i = 0; i < TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT; ++i)
+        {
+          if (cmp_attribs (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src,
+			   attr_name))
+            return attr_name;
+          if (cmp_attribs (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_dst,
+			   attr_name))
+            return TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src;
+        }
+    }
+#endif
+  /* Otherwise default to gnu format.  */
+  for (i = 0;
+       gnu_target_overrides_format_attributes[i].named_attr_src != NULL;
+       ++i)
+    {
+      if (cmp_attribs (gnu_target_overrides_format_attributes[i].named_attr_src,
+		       attr_name))
+        return attr_name;
+      if (cmp_attribs (gnu_target_overrides_format_attributes[i].named_attr_dst,
+		       attr_name))
+        return gnu_target_overrides_format_attributes[i].named_attr_src;
+    }
+
+  return attr_name;
+}
+
+/* Return true if TATTR_NAME and ATTR_NAME are the same format attribute,
+   counting "name" and "__name__" as the same, false otherwise.  */
+static bool
+cmp_attribs (const char *tattr_name, const char *attr_name)
+{
+  int alen = strlen (attr_name);
+  int slen = (tattr_name ? strlen (tattr_name) : 0);
+  if (alen > 4 && attr_name[0] == '_' && attr_name[1] == '_'
+      && attr_name[alen - 1] == '_' && attr_name[alen - 2] == '_')
+    {
+      attr_name += 2;
+      alen -= 4;
+    }
+  if (alen != slen || strncmp (tattr_name, attr_name, alen) != 0)
+    return false;
+  return true;
+}
+
 /* Handle a "format" attribute; arguments as in
    struct attribute_spec.handler.  */
 tree
@@ -2762,7 +2859,10 @@ handle_format_attribute (tree *node, tre
 	}
     }
 
-  if (info.format_type == strftime_format_type && info.first_arg_num != 0)
+  /* Check if this is a strftime variant. Just for this variant
+     FMT_FLAG_ARG_CONVERT is not set.  */
+  if ((format_types[info.format_type].flags & (int) FMT_FLAG_ARG_CONVERT) == 0
+      && info.first_arg_num != 0)
     {
       error ("strftime formats cannot format arguments");
       *no_add_attrs = true;
Index: gcc/gcc/c-format.h
===================================================================
--- gcc.orig/gcc/c-format.h
+++ gcc/gcc/c-format.h
@@ -80,12 +80,13 @@ enum
      of whether length modifiers can occur (length_char_specs).  */
 };
 
-
 /* Structure describing a length modifier supported in format checking, and
    possibly a doubled version such as "hh".  */
 typedef struct
 {
-  /* Name of the single-character length modifier.  */
+  /* Name of the single-character length modifier. If prefixed by
+     a zero character, it describes a multi character length
+     modifier, like I64, I32, etc.  */
   const char *name;
   /* Index into a format_char_info.types array.  */
   enum format_lengths index;
@@ -306,4 +307,16 @@ typedef struct
 #define T_D128  &dfloat128_type_node
 #define TEX_D128 { STD_EXT, "_Decimal128", T_D128 }
 
+/* Structure describing how format attributes such as "printf" are
+   interpreted as "gnu_printf" or "ms_printf" on a particular system.
+   TARGET_OVERRIDES_FORMAT_ATTRIBUTES is used to specify target-specific
+   defaults.  */
+typedef struct
+{
+  /* The name of the to be copied format attribute. */
+  const char *named_attr_src;
+  /* The name of the to be overridden format attribute. */
+  const char *named_attr_dst;
+} target_ovr_attr;
+
 #endif /* GCC_C_FORMAT_H */
Index: gcc/gcc/config.gcc
===================================================================
--- gcc.orig/gcc/config.gcc
+++ gcc/gcc/config.gcc
@@ -1372,8 +1372,8 @@ i[34567]86-*-pe | i[34567]86-*-cygwin*)
 	target_gtfiles="\$(srcdir)/config/i386/winnt.c"
 	extra_options="${extra_options} i386/cygming.opt"
 	extra_objs="winnt.o winnt-stubs.o"
-	c_target_objs=cygwin2.o
-	cxx_target_objs="cygwin2.o winnt-cxx.o"
+	c_target_objs="cygwin2.o msformat-c.o"
+	cxx_target_objs="cygwin2.o winnt-cxx.o msformat-c.o"
 	extra_gcc_objs=cygwin1.o
 	if test x$enable_threads = xyes; then
 		thread_file='posix'
@@ -1386,7 +1386,8 @@ i[34567]86-*-mingw32* | x86_64-*-mingw32
 	target_gtfiles="\$(srcdir)/config/i386/winnt.c"
 	extra_options="${extra_options} i386/cygming.opt"
 	extra_objs="winnt.o winnt-stubs.o"
-	cxx_target_objs=winnt-cxx.o
+	c_target_objs="msformat-c.o"
+	cxx_target_objs="winnt-cxx.o msformat-c.o"
 	default_use_cxa_atexit=yes
 	case ${enable_threads} in
 	  "" | yes | win32)
Index: gcc/gcc/config/i386/mingw32.h
===================================================================
--- gcc.orig/gcc/config/i386/mingw32.h
+++ gcc/gcc/config/i386/mingw32.h
@@ -143,6 +143,23 @@ do {						         \
    to register C++ static destructors.  */
 #define TARGET_CXX_USE_ATEXIT_FOR_CXA_ATEXIT hook_bool_void_true
 
+/* Contains a pointer to type target_ovr_attr defining the target specific
+   overrides of format attributes.  See c-format.h for structure
+   definition.  */
+#undef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+#define TARGET_OVERRIDES_FORMAT_ATTRIBUTES mingw_format_attribute_overrides
+
+/* Specify the count of elements in TARGET_OVERRIDES_ATTRIBUTE.  */
+#undef TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT
+#define TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT 3
+
+/* MS specific format attributes for ms_printf, ms_scanf, ms_strftime.  */
+#undef TARGET_FORMAT_TYPES
+#define TARGET_FORMAT_TYPES mingw_format_attributes
+
+#undef TARGET_N_FORMAT_TYPES
+#define TARGET_N_FORMAT_TYPES 3
+
 /* JCR_SECTION works on mingw32.  */
 #undef TARGET_USE_JCR_SECTION
 #define TARGET_USE_JCR_SECTION 1
Index: gcc/gcc/config/i386/msformat-c.c
===================================================================
--- /dev/null
+++ gcc/gcc/config/i386/msformat-c.c
@@ -0,0 +1,176 @@
+/* Check calls to formatted I/O functions (-Wformat).
+   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+   2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "flags.h"
+#include "c-common.h"
+#include "toplev.h"
+#include "intl.h"
+#include "diagnostic.h"
+#include "langhooks.h"
+#include "c-format.h"
+#include "alloc-pool.h"
+
+/* Mingw specific format attributes ms_printf, ms_scanf, and ms_strftime.  */
+
+static const format_length_info ms_printf_length_specs[] =
+{
+  { "h", FMT_LEN_h, STD_C89, NULL, 0, 0 },
+  { "l", FMT_LEN_l, STD_C89, NULL, 0, 0 },
+  { "\0I32", FMT_LEN_l, STD_EXT, NULL, 0, 0 },
+  { "\0I64", FMT_LEN_ll, STD_EXT, NULL, 0, 0 },
+  { "I", FMT_LEN_L, STD_EXT, NULL, 0, 0 },
+  { NULL, 0, 0, NULL, 0, 0 }
+};
+
+static const format_flag_spec ms_printf_flag_specs[] =
+{
+  { ' ',  0, 0, N_("' ' flag"),        N_("the ' ' printf flag"),              STD_C89 },
+  { '+',  0, 0, N_("'+' flag"),        N_("the '+' printf flag"),              STD_C89 },
+  { '#',  0, 0, N_("'#' flag"),        N_("the '#' printf flag"),              STD_C89 },
+  { '0',  0, 0, N_("'0' flag"),        N_("the '0' printf flag"),              STD_C89 },
+  { '-',  0, 0, N_("'-' flag"),        N_("the '-' printf flag"),              STD_C89 },
+  { '\'', 0, 0, N_("''' flag"),        N_("the ''' printf flag"),              STD_EXT },
+  { 'w',  0, 0, N_("field width"),     N_("field width in printf format"),     STD_C89 },
+  { 'p',  0, 0, N_("precision"),       N_("precision in printf format"),       STD_C89 },
+  { 'L',  0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_printf_flag_pairs[] =
+{
+  { ' ', '+', 1, 0   },
+  { '0', '-', 1, 0   }, { '0', 'p', 1, 'i' },
+  { 0, 0, 0, 0 }
+};
+
+static const format_flag_spec ms_scanf_flag_specs[] =
+{
+  { '*',  0, 0, N_("assignment suppression"), N_("the assignment suppression scanf feature"), STD_C89 },
+  { 'a',  0, 0, N_("'a' flag"),               N_("the 'a' scanf flag"),                       STD_EXT },
+  { 'w',  0, 0, N_("field width"),            N_("field width in scanf format"),              STD_C89 },
+  { 'L',  0, 0, N_("length modifier"),        N_("length modifier in scanf format"),          STD_C89 },
+  { '\'', 0, 0, N_("''' flag"),               N_("the ''' scanf flag"),                       STD_EXT },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_scanf_flag_pairs[] =
+{
+  { '*', 'L', 0, 0 },
+  { 0, 0, 0, 0 }
+};
+
+static const format_flag_spec ms_strftime_flag_specs[] =
+{
+  { '#', 0,   0, N_("'#' flag"),     N_("the '#' strftime flag"),          STD_EXT },
+  { 'w', 0,   0, N_("field width"),  N_("field width in strftime format"), STD_EXT },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_strftime_flag_pairs[] =
+{
+  { 0, 0, 0, 0 }
+};
+
+static const format_char_info ms_print_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "di",  0, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  T99_SST,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-wp0 +'",  "i",  NULL },
+  { "oxX", 0, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN, BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "-wp0#",     "i",  NULL },
+  { "u",   0, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN, BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "-wp0'",    "i",  NULL },
+  { "fgG", 0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "-wp0 +#'", "",   NULL },
+  { "eE",  0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "-wp0 +#",  "",   NULL },
+  { "c",   0, STD_C89, { T89_I,   BADLEN,  T89_S,  T94_WI,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "",   NULL },
+  { "s",   1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-wp",       "cR", NULL },
+  { "p",   1, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "c",  NULL },
+  { "n",   1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  BADLEN,  BADLEN, BADLEN,  T99_IM,  BADLEN,  BADLEN,  BADLEN }, "",          "W",  NULL },
+  /* X/Open conversion specifiers.  */
+  { "C",   0, STD_EXT, { TEX_WI,  BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "",   NULL },
+  { "S",   1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-wp",       "R",  NULL },
+  { NULL,  0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+static const format_char_info ms_scan_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "di",    1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  T99_SST,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w'", "W",   NULL },
+  { "u",     1, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN,  BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "*w'", "W",   NULL },
+  { "oxX",   1, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN,  BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "efgEG", 1, STD_C89, { T89_F,   BADLEN,  BADLEN,  T89_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "*w'",  "W",   NULL },
+  { "c",     1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "cW",  NULL },
+  { "s",     1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "cW",  NULL },
+  { "[",     1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "cW[", NULL },
+  { "p",     2, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "n",     1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  BADLEN,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "",     "W",   NULL },
+  /* X/Open conversion specifiers.  */
+  { "C",     1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "S",     1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "W",   NULL },
+  { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+static const format_char_info ms_time_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "ABZab",		0, STD_C89, NOLENGTHS, "#",     "",   NULL },
+  { "cx",		0, STD_C89, NOLENGTHS, "#",      "3",  NULL },
+  { "HIMSUWdmw",	0, STD_C89, NOLENGTHS, "#w",  "",   NULL },
+  { "j",		0, STD_C89, NOLENGTHS, "#w",  "",  NULL },
+  { "p",		0, STD_C89, NOLENGTHS, "#",      "",   NULL },
+  { "X",		0, STD_C89, NOLENGTHS, "#",      "",   NULL },
+  { "y",		0, STD_C89, NOLENGTHS, "#w", "4",  NULL },
+  { "Y",		0, STD_C89, NOLENGTHS, "#w", "",  NULL },
+  { "%",		0, STD_C89, NOLENGTHS, "",       "",   NULL },
+  /* C99 conversion specifiers.  */
+  { "z",		0, STD_C99, NOLENGTHS, "#",      "",  NULL },
+  { NULL,		0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+const format_kind_info mingw_format_attributes[3] =
+{
+  { "ms_printf",   ms_printf_length_specs,  ms_print_char_table, " +#0-'", NULL,
+    ms_printf_flag_specs, ms_printf_flag_pairs,
+    FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
+    'w', 0, 'p', 0, 'L', 0,
+    &integer_type_node, &integer_type_node
+  },
+  { "ms_scanf",    ms_printf_length_specs,   ms_scan_char_table,  "*'", NULL,
+    ms_scanf_flag_specs, ms_scanf_flag_pairs,
+    FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
+    'w', 0, 0, '*', 'L', 0,
+    NULL, NULL
+  },
+  { "ms_strftime", NULL,                 ms_time_char_table,  "", "#",
+    ms_strftime_flag_specs, ms_strftime_flag_pairs,
+    FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0, 0,
+    NULL, NULL
+  }
+};
+
+/* Default overrides for printf, scanf and strftime.  */
+const target_ovr_attr mingw_format_attribute_overrides[4] =
+{
+  { "ms_printf", "printf" },
+  { "ms_scanf", "scanf" },
+  { "ms_strftime", "strftime" }
+};
Index: gcc/gcc/config/i386/t-cygming
===================================================================
--- gcc.orig/gcc/config/i386/t-cygming
+++ gcc/gcc/config/i386/t-cygming
@@ -29,4 +29,10 @@ winnt-stubs.o: $(srcdir)/config/i386/win
 	$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
 	$(srcdir)/config/i386/winnt-stubs.c
 
+msformat-c.o: $(srcdir)/config/i386/msformat-c.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
+  $(TM_H) $(RTL_H) $(REGS_H) hard-reg-set.h output.h $(TREE_H) flags.h \
+  $(TM_P_H) toplev.h $(HASHTAB_H) $(GGC_H)
+	$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
+	$(srcdir)/config/i386/msformat-c.c
+
 STMP_FIXINC=stmp-fixinc
Index: gcc/gcc/doc/extend.texi
===================================================================
--- gcc.orig/gcc/doc/extend.texi
+++ gcc/gcc/doc/extend.texi
@@ -2204,13 +2204,22 @@ for consistency with the @code{printf} s
 @code{my_format}.
 
 The parameter @var{archetype} determines how the format string is
-interpreted, and should be @code{printf}, @code{scanf}, @code{strftime}
-or @code{strfmon}.  (You can also use @code{__printf__},
-@code{__scanf__}, @code{__strftime__} or @code{__strfmon__}.)  The
-parameter @var{string-index} specifies which argument is the format
-string argument (starting from 1), while @var{first-to-check} is the
-number of the first argument to check against the format string.  For
-functions where the arguments are not available to be checked (such as
+interpreted, and should be @code{printf}, @code{scanf}, @code{strftime},
+@code{gnu_printf}, @code{gnu_scanf}, @code{gnu_strftime} or
+@code{strfmon}.  (You can also use @code{__printf__},
+@code{__scanf__}, @code{__strftime__} or @code{__strfmon__}.)  On
+MinGW targets, @code{ms_printf}, @code{ms_scanf}, and
+@code{ms_strftime} are also present.
+@var{archtype} values such as @code{printf} refer to the formats accepted
+by the system's C run-time library, while @code{gnu_} values always refer
+to the formats accepted by the GNU C Library.  On Microsoft Windows
+targets, @code{ms_} values refer to the formats accepted by the
+@file{msvcrt.dll} library.
+The parameter @var{string-index}
+specifies which argument is the format string argument (starting
+from 1), while @var{first-to-check} is the number of the first
+argument to check against the format string.  For functions
+where the arguments are not available to be checked (such as
 @code{vprintf}), specify the third parameter as zero.  In this case the
 compiler only checks the format string for consistency.  For
 @code{strftime} formats, the third parameter is required to be zero.
Index: gcc/gcc/doc/tm.texi
===================================================================
--- gcc.orig/gcc/doc/tm.texi
+++ gcc/gcc/doc/tm.texi
@@ -10319,6 +10319,18 @@ If defined, this macro is the number of 
 @code{TARGET_FORMAT_TYPES}.
 @end defmac
 
+@defmac TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+If defined, this macro is the name of a global variable containing
+target-specific format overrides for the @option{-Wformat} option. The
+default is to have no target-specific format overrides. If defined,
+@code{TARGET_FORMAT_TYPES} must be defined, too.
+@end defmac
+
+@defmac TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT
+If defined, this macro specifies the number of entries in
+@code{TARGET_OVERRIDES_FORMAT_ATTRIBUTES}.
+@end defmac
+
 @deftypefn {Target Hook} bool TARGET_RELAXED_ORDERING
 If set to @code{true}, means that the target's memory model does not
 guarantee that loads which do not depend on one another will access
Index: gcc/gcc/testsuite/gcc.dg/format/format.h
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/format.h
+++ gcc/gcc/testsuite/gcc.dg/format/format.h
@@ -1,6 +1,37 @@
 /* Format checking tests: common header.  */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
 
+/* DONT_GNU_PROTOTYPE */
+#if defined (_WIN32) && !defined (__CYGWIN__)
+#if !defined (USE_SYSTEM_FORMATS)
+#define gnu_attr_printf	gnu_printf
+#define gnu_attr___printf__ __gnu_printf__
+#define gnu_attr_scanf	gnu_scanf
+#define gnu_attr___scanf__ __gnu_scanf__
+#define gnu_attr_strftime gnu_strftime
+#define gnu_attr___strftime__ __gnu_strftime__
+#endif
+#endif
+
+#ifndef gnu_attr_printf
+#define gnu_attr_printf	printf
+#define gnu_attr___printf__ __printf__
+#define gnu_attr_scanf	scanf
+#define gnu_attr___scanf__ __scanf__
+#define gnu_attr_strftime strftime
+#define gnu_attr___strftime__ __strftime__
+#endif
+
+#if !defined (USE_SYSTEM_FORMATS)
+#define USE_PRINTF(FMTPOS, WILDARG) __attribute__((format(gnu_printf, FMTPOS, WILDARG))) __attribute__((nonnull (FMTPOS)))
+#define USE_SCANF(FMTPOS, WILDARG) __attribute__((format(gnu_scanf, FMTPOS, WILDARG))) __attribute__((nonnull (FMTPOS)))
+#define USE_STRFTIME(FMTPOS) __attribute__((__format__(gnu_strftime, FMTPOS, 0))) __attribute__((nonnull (FMTPOS)))
+#else
+#define USE_PRINTF(FMTPOS, WILDARG)
+#define USE_SCANF(FMTPOS, WILDARG)
+#define USE_STRFTIME(FMTPOS)
+#endif
+
 #include <stdarg.h>
 #include <stddef.h>
 
@@ -11,6 +42,20 @@
 typedef __WINT_TYPE__ wint_t;
 #endif
 
+#ifdef _WIN64
+/* Kludges to get types corresponding to size_t and ptrdiff_t.  */
+#define unsigned signed
+typedef signed int signed_size_t __attribute__ ((mode (DI)));
+/* We also use this type to approximate ssize_t.  */
+typedef signed int ssize_t __attribute__ ((mode (DI)));
+#undef unsigned
+#define signed /* Type might or might not have explicit 'signed'.  */
+typedef unsigned int unsigned_ptrdiff_t __attribute__ ((mode (DI)));
+#undef signed
+
+__extension__ typedef int llong  __attribute__ ((mode (DI)));
+__extension__ typedef unsigned int ullong  __attribute__ ((mode (DI)));
+#else
 /* Kludges to get types corresponding to size_t and ptrdiff_t.  */
 #define unsigned signed
 typedef __SIZE_TYPE__ signed_size_t;
@@ -23,6 +68,7 @@ typedef unsigned __PTRDIFF_TYPE__ unsign
 
 __extension__ typedef long long int llong;
 __extension__ typedef unsigned long long int ullong;
+#endif
 
 /* %q formats want a "quad"; GCC considers this to be a long long.  */
 typedef llong quad_t;
@@ -70,3 +116,77 @@ extern size_t strftime (char *restrict, 
 			const struct tm *restrict);
 
 extern ssize_t strfmon (char *restrict, size_t, const char *restrict, ...);
+
+/* Mingw specific part.  */
+#if !defined (USE_SYSTEM_FORMATS) && defined(_WIN32) && !defined(DONT_GNU_PROTOTYPE)
+
+extern USE_PRINTF(2,3) int fprintf_gnu (FILE *restrict, const char *restrict, ...);
+#undef fprintf
+#define fprintf fprintf_gnu
+
+extern USE_PRINTF(1,2) int printf_gnu (const char *restrict, ...);
+#undef printf
+#define printf printf_gnu
+
+extern USE_PRINTF(2,3) int fprintf_unlocked_gnu (FILE *restrict, const char *restrict, ...);
+#undef fprintf_unlocked
+#define fprintf_unlocked fprintf_unlocked_gnu
+
+extern USE_PRINTF(1,2)int printf_unlocked_gnu (const char *restrict, ...);
+#undef printf_unlocked
+#define printf_unlocked printf_unlocked_gnu
+
+extern USE_PRINTF(2,3) int sprintf_gnu (char *restrict, const char *restrict, ...);
+#undef sprintf
+#define sprintf sprintf_gnu
+
+extern USE_PRINTF(2,0) int vfprintf_gnu (FILE *restrict, const char *restrict, va_list);
+#undef vsprintf
+#define vsprintf vsprintf_gnu
+
+extern USE_PRINTF(1,0) int vprintf_gnu (const char *restrict, va_list);
+#undef vprintf
+#define vprintf vprintf_gnu
+
+extern USE_PRINTF(2,0) int vsprintf_gnu (char *restrict, const char *restrict, va_list);
+#undef vsprintf
+#define vsprintf vsprintf_gnu
+
+extern USE_PRINTF(3,4) int snprintf_gnu (char *restrict, size_t, const char *restrict, ...);
+#undef snprintf
+#define snprintf snprintf_gnu
+
+extern USE_PRINTF(3,0) int vsnprintf_gnu (char *restrict, size_t, const char *restrict, va_list);
+#undef vsnprintf
+#define vsnprintf vsnprintf_gnu
+
+extern USE_SCANF(2,3) int fscanf_gnu (FILE *restrict, const char *restrict, ...);
+#undef fscanf
+#define fscanf fscanf_gnu
+
+extern USE_SCANF(1,2) int scanf_gnu (const char *restrict, ...);
+#undef scanf
+#define scanf scanf_gnu
+
+extern USE_SCANF(2,3) int sscanf_gnu (const char *restrict, const char *restrict, ...);
+#undef sscanf
+#define sscanf sscanf_gnu
+
+extern USE_SCANF(2,0) int vfscanf_gnu (FILE *restrict, const char *restrict, va_list);
+#undef vfscanf
+#define vfscanf vfscanf_gnu
+
+extern USE_SCANF(1,0) int vscanf_gnu (const char *restrict, va_list);
+#undef vscanf
+#define vscanf vscanf_gnu
+
+extern USE_SCANF(2,0) int vsscanf_gnu (const char *restrict, const char *restrict, va_list);
+#undef vsscanf
+#define vsscanf vsscanf_gnu
+
+extern USE_STRFTIME(3) size_t strftime_gnu (char *restrict, size_t, const char *restrict,
+			const struct tm *restrict);
+#undef strftime
+#define strftime strftime_gnu
+
+#endif
Index: gcc/gcc/testsuite/gcc.dg/format/attr-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-1.c
@@ -3,7 +3,8 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern void foo0 (const char *) __attribute__((__format__(__strftime__, 1, 0)));
-extern void foo1 (const char *, ...) __attribute__((__format__(__strftime__, 1, 2))); /* { dg-error "cannot format" "strftime first_arg_num != 0" } */
+extern void foo0 (const char *) __attribute__((__format__(gnu_attr___strftime__, 1, 0)));
+extern void foo1 (const char *, ...) __attribute__((__format__(gnu_attr___strftime__, 1, 2))); /* { dg-error "cannot format" "strftime first_arg_num != 0" } */
Index: gcc/gcc/testsuite/gcc.dg/format/attr-2.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-2.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-2.c
@@ -3,22 +3,23 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern void tformatprintf (const char *, ...) __attribute__((format(printf, 1, 2)));
-extern void tformat__printf__ (const char *, ...) __attribute__((format(__printf__, 1, 2)));
-extern void tformatscanf (const char *, ...) __attribute__((format(scanf, 1, 2)));
-extern void tformat__scanf__ (const char *, ...) __attribute__((format(__scanf__, 1, 2)));
-extern void tformatstrftime (const char *) __attribute__((format(strftime, 1, 0)));
-extern void tformat__strftime__ (const char *) __attribute__((format(__strftime__, 1, 0)));
+extern void tformatprintf (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
+extern void tformat__printf__ (const char *, ...) __attribute__((format(gnu_attr___printf__, 1, 2)));
+extern void tformatscanf (const char *, ...) __attribute__((format(gnu_attr_scanf, 1, 2)));
+extern void tformat__scanf__ (const char *, ...) __attribute__((format(gnu_attr___scanf__, 1, 2)));
+extern void tformatstrftime (const char *) __attribute__((format(gnu_attr_strftime, 1, 0)));
+extern void tformat__strftime__ (const char *) __attribute__((format(gnu_attr___strftime__, 1, 0)));
 extern void tformatstrfmon (const char *, ...) __attribute__((format(strfmon, 1, 2)));
 extern void tformat__strfmon__ (const char *, ...) __attribute__((format(__strfmon__, 1, 2)));
-extern void t__format__printf (const char *, ...) __attribute__((__format__(printf, 1, 2)));
-extern void t__format____printf__ (const char *, ...) __attribute__((__format__(__printf__, 1, 2)));
-extern void t__format__scanf (const char *, ...) __attribute__((__format__(scanf, 1, 2)));
-extern void t__format____scanf__ (const char *, ...) __attribute__((__format__(__scanf__, 1, 2)));
-extern void t__format__strftime (const char *) __attribute__((__format__(strftime, 1, 0)));
-extern void t__format____strftime__ (const char *) __attribute__((__format__(__strftime__, 1, 0)));
+extern void t__format__printf (const char *, ...) __attribute__((__format__(gnu_attr_printf, 1, 2)));
+extern void t__format____printf__ (const char *, ...) __attribute__((__format__(gnu_attr___printf__, 1, 2)));
+extern void t__format__scanf (const char *, ...) __attribute__((__format__(gnu_attr_scanf, 1, 2)));
+extern void t__format____scanf__ (const char *, ...) __attribute__((__format__(gnu_attr___scanf__, 1, 2)));
+extern void t__format__strftime (const char *) __attribute__((__format__(gnu_attr_strftime, 1, 0)));
+extern void t__format____strftime__ (const char *) __attribute__((__format__(gnu_attr___strftime__, 1, 0)));
 extern void t__format__strfmon (const char *, ...) __attribute__((__format__(strfmon, 1, 2)));
 extern void t__format____strfmon__ (const char *, ...) __attribute__((__format__(__strfmon__, 1, 2)));
 
Index: gcc/gcc/testsuite/gcc.dg/format/attr-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-3.c
@@ -3,20 +3,21 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 /* Proper uses of the attributes.  */
-extern void fa0 (const char *, ...) __attribute__((format(printf, 1, 2)));
-extern void fa1 (char *, ...) __attribute__((format(printf, 1, 2)));
+extern void fa0 (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
+extern void fa1 (char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
 extern char *fa2 (const char *) __attribute__((format_arg(1)));
 extern char *fa3 (char *) __attribute__((format_arg(1)));
 
 /* Uses with too few or too many arguments.  */
 extern void fb0 (const char *, ...) __attribute__((format)); /* { dg-error "wrong number of arguments" "bad format" } */
 extern void fb1 (const char *, ...) __attribute__((format())); /* { dg-error "wrong number of arguments" "bad format" } */
-extern void fb2 (const char *, ...) __attribute__((format(printf))); /* { dg-error "wrong number of arguments" "bad format" } */
-extern void fb3 (const char *, ...) __attribute__((format(printf, 1))); /* { dg-error "wrong number of arguments" "bad format" } */
-extern void fb4 (const char *, ...) __attribute__((format(printf, 1, 2, 3))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb2 (const char *, ...) __attribute__((format(gnu_attr_printf))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb3 (const char *, ...) __attribute__((format(gnu_attr_printf, 1))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb4 (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2, 3))); /* { dg-error "wrong number of arguments" "bad format" } */
 
 extern void fc1 (const char *) __attribute__((format_arg)); /* { dg-error "wrong number of arguments" "bad format_arg" } */
 extern void fc2 (const char *) __attribute__((format_arg())); /* { dg-error "wrong number of arguments" "bad format_arg" } */
@@ -25,9 +26,9 @@ extern void fc3 (const char *) __attribu
 /* These attributes presently only apply to declarations, not to types.
    Eventually, they should be usable with declarators for function types
    anywhere, but still not with structure/union/enum types.  */
-struct s0 { int i; } __attribute__((format(printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on struct" } */
-union u0 { int i; } __attribute__((format(printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on union" } */
-enum e0 { E0V0 } __attribute__((format(printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on enum" } */
+struct s0 { int i; } __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on struct" } */
+union u0 { int i; } __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on union" } */
+enum e0 { E0V0 } __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on enum" } */
 
 struct s1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on struct" } */
 union u1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on union" } */
@@ -38,28 +39,28 @@ extern void fe0 (const char *, ...) __at
 extern void fe1 (const char *, ...) __attribute__((format(nosuch, 1, 2))); /* { dg-warning "format function type" "unknown format" } */
 
 /* Both the numbers must be integer constant expressions.  */
-extern void ff0 (const char *, ...) __attribute__((format(printf, 3-2, (long long)(10/5))));
+extern void ff0 (const char *, ...) __attribute__((format(gnu_attr_printf, 3-2, (long long)(10/5))));
 int foo;
-extern void ff1 (const char *, ...) __attribute__((format(printf, foo, 10/5))); /* { dg-error "invalid operand" "bad number" } */
-extern void ff2 (const char *, ...) __attribute__((format(printf, 3-2, foo))); /* { dg-error "invalid operand" "bad number" } */
+extern void ff1 (const char *, ...) __attribute__((format(gnu_attr_printf, foo, 10/5))); /* { dg-error "invalid operand" "bad number" } */
+extern void ff2 (const char *, ...) __attribute__((format(gnu_attr_printf, 3-2, foo))); /* { dg-error "invalid operand" "bad number" } */
 extern char *ff3 (const char *) __attribute__((format_arg(3-2)));
 extern char *ff4 (const char *) __attribute__((format_arg(foo))); /* { dg-error "invalid operand" "bad format_arg number" } */
 
 /* The format string argument must precede the arguments to be formatted.
    This includes if no parameter types are specified (which is not valid ISO
    C for variadic functions).  */
-extern void fg0 () __attribute__((format(printf, 1, 2)));
-extern void fg1 () __attribute__((format(printf, 1, 0)));
-extern void fg2 () __attribute__((format(printf, 1, 1))); /* { dg-error "follows" "bad number order" } */
-extern void fg3 () __attribute__((format(printf, 2, 1))); /* { dg-error "follows" "bad number order" } */
+extern void fg0 () __attribute__((format(gnu_attr_printf, 1, 2)));
+extern void fg1 () __attribute__((format(gnu_attr_printf, 1, 0)));
+extern void fg2 () __attribute__((format(gnu_attr_printf, 1, 1))); /* { dg-error "follows" "bad number order" } */
+extern void fg3 () __attribute__((format(gnu_attr_printf, 2, 1))); /* { dg-error "follows" "bad number order" } */
 
 /* The format string argument must be a string type, and the arguments to
    be formatted must be the "...".  */
-extern void fh0 (int, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "not a string" "format int string" } */
-extern void fh1 (signed char *, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "not a string" "signed char string" } */
-extern void fh2 (unsigned char *, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "not a string" "unsigned char string" } */
-extern void fh3 (const char *, ...) __attribute__((format(printf, 1, 3))); /* { dg-error "is not" "not ..." } */
-extern void fh4 (const char *, int, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "is not" "not ..." } */
+extern void fh0 (int, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "format int string" } */
+extern void fh1 (signed char *, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "signed char string" } */
+extern void fh2 (unsigned char *, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "unsigned char string" } */
+extern void fh3 (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 3))); /* { dg-error "is not" "not ..." } */
+extern void fh4 (const char *, int, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "is not" "not ..." } */
 
 /* format_arg formats must take and return a string.  */
 extern char *fi0 (int) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg int string" } */
Index: gcc/gcc/testsuite/gcc.dg/format/attr-4.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-4.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-4.c
@@ -4,12 +4,13 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern __attribute__((format(printf, 1, 2))) void tformatprintf0 (const char *, ...);
-extern void __attribute__((format(printf, 1, 2))) tformatprintf1 (const char *, ...);
-extern void foo (void), __attribute__((format(printf, 1, 2))) tformatprintf2 (const char *, ...);
-extern __attribute__((noreturn)) void bar (void), __attribute__((format(printf, 1, 2))) tformatprintf3 (const char *, ...);
+extern __attribute__((format(gnu_attr_printf, 1, 2))) void tformatprintf0 (const char *, ...);
+extern void __attribute__((format(gnu_attr_printf, 1, 2))) tformatprintf1 (const char *, ...);
+extern void foo (void), __attribute__((format(gnu_attr_printf, 1, 2))) tformatprintf2 (const char *, ...);
+extern __attribute__((noreturn)) void bar (void), __attribute__((format(gnu_attr_printf, 1, 2))) tformatprintf3 (const char *, ...);
 
 void
 baz (int i, int *ip, double d)
Index: gcc/gcc/testsuite/gcc.dg/format/attr-7.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-7.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-7.c
@@ -3,12 +3,13 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-__attribute__((format(printf, 1, 2))) void (*tformatprintf0) (const char *, ...);
-void (*tformatprintf1) (const char *, ...) __attribute__((format(printf, 1, 2)));
-void (__attribute__((format(printf, 1, 2))) *tformatprintf2) (const char *, ...);
-void (__attribute__((format(printf, 1, 2))) ****tformatprintf3) (const char *, ...);
+__attribute__((format(gnu_attr_printf, 1, 2))) void (*tformatprintf0) (const char *, ...);
+void (*tformatprintf1) (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
+void (__attribute__((format(gnu_attr_printf, 1, 2))) *tformatprintf2) (const char *, ...);
+void (__attribute__((format(gnu_attr_printf, 1, 2))) ****tformatprintf3) (const char *, ...);
 
 char * (__attribute__((format_arg(1))) *tformat_arg) (const char *);
 
Index: gcc/gcc/testsuite/gcc.dg/format/c90-printf-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/c90-printf-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/c90-printf-3.c
@@ -3,7 +3,7 @@
    do not.
 */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
-/* { dg-do compile } */
+/* { dg-do compile { target { ! *-*-mingw* } } } */
 /* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
 
 #include "format.h"
Index: gcc/gcc/testsuite/gcc.dg/format/c90-scanf-4.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/c90-scanf-4.c
+++ gcc/gcc/testsuite/gcc.dg/format/c90-scanf-4.c
@@ -3,7 +3,7 @@
    do not.
 */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
-/* { dg-do compile } */
+/* { dg-do compile { target { ! *-*-mingw* } } } */
 /* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
 
 #include "format.h"
Index: gcc/gcc/testsuite/gcc.dg/format/c99-printf-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/c99-printf-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/c99-printf-3.c
@@ -2,7 +2,7 @@
    attributes in strict C99 mode, but the gettext functions do not.
 */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
-/* { dg-do compile } */
+/* { dg-do compile { target { ! *-*-mingw* } } } */
 /* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
 
 #include "format.h"
Index: gcc/gcc/testsuite/gcc.dg/format/miss-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-1.c
@@ -23,7 +23,7 @@ bar (const char *fmt, ...)
   va_end (ap);
 }
 
-__attribute__((__format__(__printf__, 1, 2))) void
+__attribute__((__format__(gnu_attr___printf__, 1, 2))) void
 foo2 (const char *fmt, ...)
 {
   va_list ap;
Index: gcc/gcc/testsuite/gcc.dg/format/miss-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-3.c
@@ -3,13 +3,14 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 void
 foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
@@ -18,7 +19,7 @@ foo1 (noattr_t na, attr_t a, vnoattr_t v
   noattr_t na2 = a; /* { dg-warning "candidate" "initialization warning" } */
   attr_t a1 = na;
   attr_t a2 = a;
-  
+
   vnoattr_t vna1 = vna;
   vnoattr_t vna2 = va; /* { dg-warning "candidate" "initialization warning" } */
   vattr_t va1 = vna;
Index: gcc/gcc/testsuite/gcc.dg/format/miss-4.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-4.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-4.c
@@ -3,20 +3,21 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 void
 foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
 {
   noattr_t na1, na2;
   attr_t a1, a2;
-  
+
   vnoattr_t vna1, vna2;
   vattr_t va1, va2;
 
@@ -24,7 +25,7 @@ foo1 (noattr_t na, attr_t a, vnoattr_t v
   na2 = a; /* { dg-warning "candidate" "assignment warning" } */
   a1 = na;
   a2 = a;
-  
+
   vna1 = vna;
   vna2 = va; /* { dg-warning "candidate" "assignment warning" } */
   va1 = vna;
Index: gcc/gcc/testsuite/gcc.dg/format/miss-5.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-5.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-5.c
@@ -3,13 +3,14 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 noattr_t
 foo1 (noattr_t na, attr_t a, int i)
Index: gcc/gcc/testsuite/gcc.dg/format/miss-6.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-6.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-6.c
@@ -3,13 +3,14 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 extern void foo1 (noattr_t);
 extern void foo2 (attr_t);
@@ -23,7 +24,7 @@ foo (noattr_t na, attr_t a, vnoattr_t vn
   foo1 (a); /* { dg-warning "candidate" "parameter passing warning" } */
   foo2 (na);
   foo2 (a);
-  
+
   foo3 (vna);
   foo3 (va); /* { dg-warning "candidate" "parameter passing warning" } */
   foo4 (vna);
Index: gcc/gcc/testsuite/gcc.dg/format/ms_array-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_array-1.c
@@ -0,0 +1,42 @@
+/* Test for format checking of constant arrays.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat=2" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+const char a1[] = "foo";
+const char a2[] = "foo%d";
+const char b1[3] = "foo";
+const char b2[1] = "1";
+static const char c1[] = "foo";
+static const char c2[] = "foo%d";
+char d[] = "foo";
+volatile const char e[] = "foo";
+
+void
+foo (int i, long l)
+{
+  const char p1[] = "bar";
+  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 (c1);
+  printf (c2, i);
+  printf (c2, l); /* { dg-warning "format" "wrong type with array" } */
+  printf (p1);
+  printf (p2, i);
+  printf (p2, l); /* { dg-warning "format" "wrong type with array" } */
+  printf (q1);
+  printf (q2, i);
+  printf (q2, l); /* { dg-warning "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" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-1.c
@@ -0,0 +1,10 @@
+/* Test for strftime format attributes: can't have first_arg_num != 0.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define DONT_GNU_PROTOTYPE
+#include "format.h"
+
+extern void foo0 (const char *) __attribute__((__format__(__ms_strftime__, 1, 0)));
+extern void foo1 (const char *, ...) __attribute__((__format__(__ms_strftime__, 1, 2))); /* { dg-error "cannot format" "strftime first_arg_num != 0" } */
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-2.c
@@ -0,0 +1,68 @@
+/* Test for format attributes: test use of __attribute__.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define DONT_GNU_PROTOTYPE
+#include "format.h"
+
+extern void tformatprintf (const char *, ...) __attribute__((format(ms_printf, 1, 2)));
+extern void tformat__printf__ (const char *, ...) __attribute__((format(__ms_printf__, 1, 2)));
+extern void tformatscanf (const char *, ...) __attribute__((format(ms_scanf, 1, 2)));
+extern void tformat__scanf__ (const char *, ...) __attribute__((format(__ms_scanf__, 1, 2)));
+extern void tformatstrftime (const char *) __attribute__((format(ms_strftime, 1, 0)));
+extern void tformat__strftime__ (const char *) __attribute__((format(__ms_strftime__, 1, 0)));
+extern void tformatstrfmon (const char *, ...) __attribute__((format(strfmon, 1, 2)));
+extern void tformat__strfmon__ (const char *, ...) __attribute__((format(__strfmon__, 1, 2)));
+extern void t__format__printf (const char *, ...) __attribute__((__format__(ms_printf, 1, 2)));
+extern void t__format____printf__ (const char *, ...) __attribute__((__format__(__ms_printf__, 1, 2)));
+extern void t__format__scanf (const char *, ...) __attribute__((__format__(ms_scanf, 1, 2)));
+extern void t__format____scanf__ (const char *, ...) __attribute__((__format__(__ms_scanf__, 1, 2)));
+extern void t__format__strftime (const char *) __attribute__((__format__(ms_strftime, 1, 0)));
+extern void t__format____strftime__ (const char *) __attribute__((__format__(__ms_strftime__, 1, 0)));
+extern void t__format__strfmon (const char *, ...) __attribute__((__format__(strfmon, 1, 2)));
+extern void t__format____strfmon__ (const char *, ...) __attribute__((__format__(__strfmon__, 1, 2)));
+
+extern char *tformat_arg (const char *) __attribute__((format_arg(1)));
+extern char *t__format_arg__ (const char *) __attribute__((__format_arg__(1)));
+
+void
+foo (int i, int *ip, double d)
+{
+  tformatprintf ("%d", i);
+  tformatprintf ("%"); /* { dg-warning "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);
+  tformat__scanf__ ("%"); /* { dg-warning "format" "attribute format __scanf__" } */
+  tformatstrftime ("%a");
+  tformatstrftime ("%"); /* { dg-warning "format" "attribute format strftime" } */
+  tformat__strftime__ ("%a");
+  tformat__strftime__ ("%"); /* { dg-warning "format" "attribute format __strftime__" } */
+  tformatstrfmon ("%n", d);
+  tformatstrfmon ("%"); /* { dg-warning "format" "attribute format strfmon" } */
+  tformat__strfmon__ ("%n", d);
+  tformat__strfmon__ ("%"); /* { dg-warning "format" "attribute format __strfmon__" } */
+  t__format__printf ("%d", i);
+  t__format__printf ("%"); /* { dg-warning "format" "attribute __format__ printf" } */
+  t__format____printf__ ("%d", i);
+  t__format____printf__ ("%"); /* { dg-warning "format" "attribute __format__ __printf__" } */
+  t__format__scanf ("%d", ip);
+  t__format__scanf ("%"); /* { dg-warning "format" "attribute __format__ scanf" } */
+  t__format____scanf__ ("%d", ip);
+  t__format____scanf__ ("%"); /* { dg-warning "format" "attribute __format__ __scanf__" } */
+  t__format__strftime ("%a");
+  t__format__strftime ("%"); /* { dg-warning "format" "attribute __format__ strftime" } */
+  t__format____strftime__ ("%a");
+  t__format____strftime__ ("%"); /* { dg-warning "format" "attribute __format__ __strftime__" } */
+  t__format__strfmon ("%n", d);
+  t__format__strfmon ("%"); /* { dg-warning "format" "attribute __format__ strfmon" } */
+  t__format____strfmon__ ("%n", d);
+  t__format____strfmon__ ("%"); /* { dg-warning "format" "attribute __format__ __strfmon__" } */
+  tformatprintf (tformat_arg ("%d"), i);
+  tformatprintf (tformat_arg ("%")); /* { dg-warning "format" "attribute format_arg" } */
+  tformatprintf (t__format_arg__ ("%d"), i);
+  tformatprintf (t__format_arg__ ("%")); /* { dg-warning "format" "attribute __format_arg__" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-3.c
@@ -0,0 +1,71 @@
+/* Test for format attributes: test bad uses of __attribute__.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* Proper uses of the attributes.  */
+extern void fa0 (const char *, ...) __attribute__((format(ms_printf, 1, 2)));
+extern void fa1 (char *, ...) __attribute__((format(ms_printf, 1, 2)));
+extern char *fa2 (const char *) __attribute__((format_arg(1)));
+extern char *fa3 (char *) __attribute__((format_arg(1)));
+
+/* Uses with too few or too many arguments.  */
+extern void fb0 (const char *, ...) __attribute__((format)); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb1 (const char *, ...) __attribute__((format())); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb2 (const char *, ...) __attribute__((format(ms_printf))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb3 (const char *, ...) __attribute__((format(ms_printf, 1))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb4 (const char *, ...) __attribute__((format(ms_printf, 1, 2, 3))); /* { dg-error "wrong number of arguments" "bad format" } */
+
+extern void fc1 (const char *) __attribute__((format_arg)); /* { dg-error "wrong number of arguments" "bad format_arg" } */
+extern void fc2 (const char *) __attribute__((format_arg())); /* { dg-error "wrong number of arguments" "bad format_arg" } */
+extern void fc3 (const char *) __attribute__((format_arg(1, 2))); /* { dg-error "wrong number of arguments" "bad format_arg" } */
+
+/* These attributes presently only apply to declarations, not to types.
+   Eventually, they should be usable with declarators for function types
+   anywhere, but still not with structure/union/enum types.  */
+struct s0 { int i; } __attribute__((format(ms_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on struct" } */
+union u0 { int i; } __attribute__((format(ms_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on union" } */
+enum e0 { E0V0 } __attribute__((format(ms_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on enum" } */
+
+struct s1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on struct" } */
+union u1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on union" } */
+enum e1 { E1V0 } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on enum" } */
+
+/* The format type must be an identifier, one of those recognized.  */
+extern void fe0 (const char *, ...) __attribute__((format(12345, 1, 2))); /* { dg-error "format specifier" "non-id format" } */
+extern void fe1 (const char *, ...) __attribute__((format(nosuch, 1, 2))); /* { dg-warning "format function type" "unknown format" } */
+
+/* Both the numbers must be integer constant expressions.  */
+extern void ff0 (const char *, ...) __attribute__((format(ms_printf, 3-2, (long long)(10/5))));
+int foo;
+extern void ff1 (const char *, ...) __attribute__((format(ms_printf, foo, 10/5))); /* { dg-error "invalid operand" "bad number" } */
+extern void ff2 (const char *, ...) __attribute__((format(ms_printf, 3-2, foo))); /* { dg-error "invalid operand" "bad number" } */
+extern char *ff3 (const char *) __attribute__((format_arg(3-2)));
+extern char *ff4 (const char *) __attribute__((format_arg(foo))); /* { dg-error "invalid operand" "bad format_arg number" } */
+
+/* The format string argument must precede the arguments to be formatted.
+   This includes if no parameter types are specified (which is not valid ISO
+   C for variadic functions).  */
+extern void fg0 () __attribute__((format(ms_printf, 1, 2)));
+extern void fg1 () __attribute__((format(ms_printf, 1, 0)));
+extern void fg2 () __attribute__((format(ms_printf, 1, 1))); /* { dg-error "follows" "bad number order" } */
+extern void fg3 () __attribute__((format(ms_printf, 2, 1))); /* { dg-error "follows" "bad number order" } */
+
+/* The format string argument must be a string type, and the arguments to
+   be formatted must be the "...".  */
+extern void fh0 (int, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "not a string" "format int string" } */
+extern void fh1 (signed char *, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "not a string" "signed char string" } */
+extern void fh2 (unsigned char *, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "not a string" "unsigned char string" } */
+extern void fh3 (const char *, ...) __attribute__((format(ms_printf, 1, 3))); /* { dg-error "is not" "not ..." } */
+extern void fh4 (const char *, int, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "is not" "not ..." } */
+
+/* format_arg formats must take and return a string.  */
+extern char *fi0 (int) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg int string" } */
+extern char *fi1 (signed char *) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg signed char string" } */
+extern char *fi2 (unsigned char *) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg unsigned char string" } */
+extern int fi3 (const char *) __attribute__((format_arg(1))); /* { dg-error "not return string" "format_arg ret int string" } */
+extern signed char *fi4 (const char *) __attribute__((format_arg(1))); /* { dg-error "not return string" "format_arg ret signed char string" } */
+extern unsigned char *fi5 (const char *) __attribute__((format_arg(1))); /* { dg-error "not return string" "format_arg ret unsigned char string" } */
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-4.c
@@ -0,0 +1,26 @@
+/* Test for format attributes: test use of __attribute__
+   in prefix attributes.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+extern __attribute__((format(ms_printf, 1, 2))) void tformatprintf0 (const char *, ...);
+extern void __attribute__((format(ms_printf, 1, 2))) tformatprintf1 (const char *, ...);
+extern void foo (void), __attribute__((format(ms_printf, 1, 2))) tformatprintf2 (const char *, ...);
+extern __attribute__((noreturn)) void bar (void), __attribute__((format(ms_printf, 1, 2))) tformatprintf3 (const char *, ...);
+
+void
+baz (int i, int *ip, double d)
+{
+  tformatprintf0 ("%d", i);
+  tformatprintf0 ("%"); /* { dg-warning "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);
+  tformatprintf3 ("%"); /* { dg-warning "format" "attribute format printf case 3" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-7.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-7.c
@@ -0,0 +1,35 @@
+/* Test for format attributes: test applying them to types.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define DONT_GNU_PROTOTYPE
+#include "format.h"
+
+__attribute__((format(ms_printf, 1, 2))) void (*tformatprintf0) (const char *, ...);
+void (*tformatprintf1) (const char *, ...) __attribute__((format(ms_printf, 1, 2)));
+void (__attribute__((format(ms_printf, 1, 2))) *tformatprintf2) (const char *, ...);
+void (__attribute__((format(ms_printf, 1, 2))) ****tformatprintf3) (const char *, ...);
+
+char * (__attribute__((format_arg(1))) *tformat_arg) (const char *);
+
+void
+baz (int i)
+{
+  (*tformatprintf0) ("%d", i);
+  (*tformatprintf0) ((*tformat_arg) ("%d"), i);
+  (*tformatprintf0) ("%"); /* { dg-warning "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" } */
+  (*tformatprintf2) ("%d", i);
+  (*tformatprintf2) ((*tformat_arg) ("%d"), i);
+  (*tformatprintf2) ("%"); /* { dg-warning "format" "nested" } */
+  (*tformatprintf2) ((*tformat_arg) ("%")); /* { dg-warning "format" "nested" } */
+  (****tformatprintf3) ("%d", i);
+  (****tformatprintf3) ((*tformat_arg) ("%d"), i);
+  (****tformatprintf3) ("%"); /* { dg-warning "format" "nested 2" } */
+  (****tformatprintf3) ((*tformat_arg) ("%")); /* { dg-warning "format" "nested 2" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_bitfld-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_bitfld-1.c
@@ -0,0 +1,52 @@
+/* Test for printf formats and bit-fields: bug 22421.  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+/* { dg-require-effective-target int32plus } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+struct s {
+  unsigned int u1 : 1;
+  signed int s1 : 1;
+  unsigned int u15 : 15;
+  signed int s15 : 15;
+  unsigned int u16 : 16;
+  signed int s16 : 16;
+  unsigned long u31 : 31;
+  signed long s31 : 31;
+  unsigned long u32 : 32;
+  signed long s32 : 32;
+  unsigned long long u48 : 48;
+} x;
+
+void
+foo (void)
+{
+  printf ("%d%u", x.u1, x.u1);
+  printf ("%d%u", x.s1, x.s1);
+  printf ("%d%u", x.u15, x.u15);
+  printf ("%d%u", x.s15, x.s15);
+  printf ("%d%u", x.u16, x.u16);
+  printf ("%d%u", x.s16, x.s16);
+#if __INT_MAX__ > 32767
+  /* If integers are 16 bits, there doesn't seem to be a way of
+     printing these without getting an error.  */
+  printf ("%d%u", x.u31, x.u31);
+  printf ("%d%u", x.s31, x.s31);
+#endif
+#if __LONG_MAX__ > 2147483647 && __INT_MAX__ >= 2147483647
+  /* If long is wider than 32 bits, the 32-bit bit-fields are int or
+     unsigned int or promote to those types.  Otherwise, long is 32
+     bits and the bit-fields are of type plain long or unsigned
+     long.  */
+  printf ("%d%u", x.u32, x.u32);
+  printf ("%d%u", x.s32, x.s32);
+#else
+  printf ("%ld%lu", x.u32, x.u32);
+  printf ("%ld%lu", x.s32, x.s32);
+#endif
+  printf ("%I64u", x.u48); /* { dg-warning "has type '.*unsigned int:48'" } */
+  printf ("%I64u", (unsigned long long)x.u48);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_branch-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_branch-1.c
@@ -0,0 +1,28 @@
+/* Test for format checking of conditional expressions.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+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" } */
+  /* 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) ? "%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" } */
+  /* 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 *-*-* } 26 } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-1.c
@@ -0,0 +1,184 @@
+/* Test for printf formats.  Formats using C90 features, including cases
+   where C90 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, int i1, int i2, unsigned int u, double d, char *s, void *p,
+     int *n, short int *hn, long int l, unsigned long int ul,
+     long int *ln, long double ld, wint_t lc, wchar_t *ls, llong ll,
+     ullong ull, unsigned int *un, const int *cn, signed char *ss,
+     unsigned char *us, const signed char *css, unsigned int u1,
+     unsigned int u2)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.1 (pages 131-134).  */
+  /* Basic sanity checks for the different components of a format.  */
+  printf ("%d\n", i);
+  printf ("%+d\n", i);
+  printf ("%3d\n", i);
+  printf ("%-3d\n", i);
+  printf ("%*d\n", i1, i);
+  printf ("%d %lu\n", i, ul);
+  /* Bogus use of width.  */
+  printf ("%5n\n", n); /* { dg-warning "width" "width 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 ("%-%"); /* { dg-warning "format" "bogus %%" } */
+  printf ("%-%\n"); /* { dg-warning "format" "bogus %%" } */
+  printf ("%5%\n"); /* { dg-warning "format" "bogus %%" } */
+  printf ("%h%\n"); /* { dg-warning "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
+     differences in format checking here, and this is relied on to get the
+     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);
+  printf ("%hs", hn);
+  printf ("%hp", p); /* { dg-warning "length" "bad use of %h" } */
+  printf ("%h"); /* { dg-warning "conversion lacks type" "bare %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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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% 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* Various tests of bad argument types.  */
+  printf ("%d", l); /* { dg-warning "format" "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" } */
+  /* 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
+     discussion of the requirements of rules on identical representation,
+     and of the application of the as if rule with the new va_arg
+     allowances in C99 to printf.)  Likewise, we should warn if
+     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" } */
+  /* 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" } */
+  /* The historical behavior is to allow signed / unsigned types
+     interchangably as arguments.  For values representable in both types,
+     such usage may be correct.  For now preserve the behavior of GCC
+     in such cases.
+  */
+  printf ("%d", u);
+  /* Wrong number of arguments.  */
+  printf ("%d%d", i); /* { dg-warning "arguments" "wrong number of args" } */
+  printf ("%d", i, i); /* { dg-warning "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" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-2.c
@@ -0,0 +1,25 @@
+/* Test for printf formats.  Formats using C99 features should be rejected
+   outside of C99 mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, double d, llong ll, intmax_t j, size_t z, ptrdiff_t t)
+{
+  /* Some tests already in c90-printf-1.c, e.g. %lf.  */
+  /* The widths hh, ll, j, z, t are new.  */
+  printf ("%hhd", i); /* { dg-warning "unknown|format" "%hh is unsupported" } */
+  printf ("%I64d", ll); /* { dg-warning "length|C" "%I64 in C90" } */
+  printf ("%jd", j); /* { dg-warning "unknown|format" "%j is unsupported" } */
+  printf ("%zu", z); /* { dg-warning "unknown|format" "%z is unsupported" } */
+  printf ("%td", t); /* { dg-warning "unknown|format" "%t is unsupported" } */
+  /* The formats F, a, A are new.  */
+  printf ("%F", d); /* { dg-warning "unknown|format" "%F is unsupported" } */
+  printf ("%a", d); /* { dg-warning "unknown|format" "%a is unsupported" } */
+  printf ("%A", d); /* { dg-warning "unknown|format" "%A is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-3.c
@@ -0,0 +1,43 @@
+/* Test for printf formats.  Test that the C90 functions get their default
+   attributes in strict C90 mode, but the C99 and gettext functions
+   do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, char *s, size_t n, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5, va_list v6, va_list v7, va_list v8)
+{
+  fprintf (stdout, "%d", i);
+  fprintf (stdout, "%ld", i); /* { dg-warning "format" "fprintf" } */
+  printf ("%d", i);
+  printf ("%ld", i); /* { dg-warning "format" "printf" } */
+  /* The "unlocked" functions shouldn't warn in c90 mode.  */
+  fprintf_unlocked (stdout, "%ld", i);
+  printf_unlocked ("%ld", i);
+  sprintf (s, "%d", i);
+  sprintf (s, "%ld", i); /* { dg-warning "format" "sprintf" } */
+  vfprintf (stdout, "%d", v0);
+  vfprintf (stdout, "%Y", v1); /* { dg-warning "format" "vfprintf" } */
+  vprintf ("%d", v2);
+  vprintf ("%Y", v3); /* { dg-warning "format" "vprintf" } */
+  /* The following used to give a bogus warning.  */
+  vprintf ("%*.*d", v8);   /* { dg-bogus "format" "vprintf" } */
+  vsprintf (s, "%d", v4);
+  vsprintf (s, "%Y", v5); /* { dg-warning "format" "Y is invalid" } */
+  snprintf (s, n, "%d", i);
+  snprintf (s, n, "%ld", i);
+  vsnprintf (s, n, "%d", v6);
+  vsnprintf (s, n, "%Y", v7);
+  printf (gettext ("%d"), i);
+  printf (gettext ("%ld"), i);
+  printf (dgettext ("", "%d"), i);
+  printf (dgettext ("", "%ld"), i);
+  printf (dcgettext ("", "%d", 0), i);
+  printf (dcgettext ("", "%ld", 0), i);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-1.c
@@ -0,0 +1,119 @@
+/* Test for scanf formats.  Formats using C90 features, including cases
+   where C90 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, unsigned int *uip, short int *hp, unsigned short int *uhp,
+     long int *lp, unsigned long int *ulp, float *fp, double *dp,
+     long double *ldp, char *s, signed char *ss, unsigned char *us,
+     void **pp, int *n, llong *llp, ullong *ullp, wchar_t *ls,
+     const int *cip, const int *cn, const char *cs, const void **ppc,
+     void *const *pcp, short int *hn, long int *ln, void *p, char **sp,
+     volatile void *ppv)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.2 (pages 134-138).  */
+  /* Basic sanity checks for the different components of a format.  */
+  scanf ("%d", ip);
+  scanf ("%*d");
+  scanf ("%3d", ip);
+  scanf ("%hd", hp);
+  scanf ("%3ld", lp);
+  scanf ("%*3d");
+  scanf ("%d %ld", ip, lp);
+  /* Valid and invalid %% constructions.  */
+  scanf ("%%");
+  scanf ("%*%"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%*%\n"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%4%"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%4%\n"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%h%"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%h%\n"); /* { dg-warning "format" "bogus %%" } */
+  /* Valid, invalid and silly assignment-suppression constructions.  */
+  scanf ("%*d%*i%*o%*u%*x%*X%*e%*E%*f%*g%*G%*s%*[abc]%*c%*p");
+  scanf ("%*2d%*8s%*3c");
+  scanf ("%*n", n); /* { dg-warning "suppress" "suppression of %n" } */
+  scanf ("%*hd"); /* { dg-warning "together" "suppression with length" } */
+  /* Valid, invalid and silly width constructions.  */
+  scanf ("%2d%3i%4o%5u%6x%7X%8e%9E%10f%11g%12G%13s%14[abc]%15c%16p",
+	 ip, ip, uip, uip, uip, uip, fp, fp, fp, fp, fp, s, s, s, pp);
+  scanf ("%0d", ip); /* { dg-warning "width" "warning for zero width" } */
+  scanf ("%3n", n); /* { dg-warning "width" "width with %n" } */
+  /* Valid and invalid %h, %l, %L constructions.  */
+  scanf ("%hd%hi%ho%hu%hx%hX%hn", hp, hp, uhp, uhp, uhp, uhp, hn);
+  scanf ("%he", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hE", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hf", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hg", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hG", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hs", hp);
+  scanf ("%h[ac]", s); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hc", hp);
+  scanf ("%hp", pp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%h"); /* { dg-warning "conversion lacks type" "bare %h" } */
+  scanf ("%h."); /* { dg-warning "conversion" "bogus %h" } */
+  scanf ("%ld%li%lo%lu%lx%lX%ln", lp, lp, ulp, ulp, ulp, ulp, ln);
+  scanf ("%le%lE%lf%lg%lG", dp, dp, dp, dp, dp);
+  scanf ("%lp", pp); /* { dg-warning "length" "bad use of %l" } */
+  /* These next three formats were added in C94.  */
+  scanf ("%ls", ls); /* { dg-warning "length|C" "bad use of %l" } */
+  scanf ("%l[ac]", ls); /* { dg-warning "length|C" "bad use of %l" } */
+  scanf ("%lc", ls); /* { dg-warning "length|C" "bad use of %l" } */
+  scanf ("%Ld", llp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Li", llp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lo", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lu", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lx", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%LX", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Ls", s); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%L[ac]", s); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lc", s); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lp", pp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Ln", n); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  /* Valid uses of each bare conversion.  */
+  scanf ("%d%i%o%u%x%X%e%E%f%g%G%s%[abc]%c%p%n%%", ip, ip, uip, uip, uip,
+	 uip, fp, fp, fp, fp, fp, s, s, s, pp, n);
+  /* Allow other character pointers with %s, %c, %[].  */
+  scanf ("%2s%3s%4c%5c%6[abc]%7[abc]", ss, us, ss, us, ss, us);
+  /* Further tests for %[].  */
+  scanf ("%[%d]%d", s, ip);
+  scanf ("%[^%d]%d", s, ip);
+  scanf ("%[]%d]%d", s, ip);
+  scanf ("%[^]%d]%d", s, ip);
+  scanf ("%[%d]%d", s, ip);
+  scanf ("%[]abcd", s); /* { dg-warning "no closing" "incomplete scanset" } */
+  /* Various tests of bad argument types.  Some of these are only pedantic
+     warnings.
+  */
+  scanf ("%d", lp); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%d", uip); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%d", pp); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", ppc); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", ppv); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%s", n); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%s", p); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", p); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", sp); /* { dg-warning "format" "bad argument types" } */
+  /* Tests for writing into constant values.  */
+  scanf ("%d", cip); /* { dg-warning "constant" "%d writing into const" } */
+  scanf ("%n", cn); /* { dg-warning "constant" "%n writing into const" } */
+  scanf ("%s", cs); /* { dg-warning "constant" "%s writing into const" } */
+  scanf ("%p", pcp); /* { dg-warning "constant" "%p writing into const" } */
+  /* Wrong number of arguments.  */
+  scanf ("%d%d", ip); /* { dg-warning "arguments" "wrong number of args" } */
+  scanf ("%d", ip, ip); /* { dg-warning "arguments" "wrong number of args" } */
+  /* Miscellaneous bogus constructions.  */
+  scanf (""); /* { dg-warning "zero-length" "warning for empty format" } */
+  scanf ("\0"); /* { dg-warning "embedded" "warning for embedded NUL" } */
+  scanf ("%d\0", ip); /* { dg-warning "embedded" "warning for embedded NUL" } */
+  scanf ("%d\0%d", ip, ip); /* { dg-warning "embedded|too many" "warning for embedded NUL" } */
+  scanf (NULL); /* { dg-warning "null" "null format string warning" } */
+  scanf ("%"); /* { dg-warning "trailing" "trailing % warning" } */
+  scanf ("%d", (int *)0); /* { dg-warning "null" "writing into NULL" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-2.c
@@ -0,0 +1,26 @@
+/* Test for scanf formats.  Formats using C99 features should be rejected
+   outside of C99 mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (signed char *hhp, float *fp, llong *llp, intmax_t *jp,
+     size_t *zp, ptrdiff_t *tp)
+{
+  /* Some tests already in c90-scanf-1.c.  */
+  /* The widths hh, ll, j, z, t are new.  */
+  scanf ("%hhd", hhp); /* { dg-warning "unknown|format" "%hh is unsupported" } */
+  scanf ("%I64d", llp); /* { dg-warning "length|C" "%I64 in C90" } */
+  scanf ("%jd", jp); /* { dg-warning "unknown|format" "%j is unsupported" } */
+  scanf ("%zu", zp); /* { dg-warning "unknown|format" "%z is unsupported" } */
+  scanf ("%td", tp); /* { dg-warning "unknown|format" "%t is unsupported" } */
+  /* The formats F, a, A are new.  */
+  scanf ("%F", fp); /* { dg-warning "unknown|format" "%F is unsupported" } */
+  scanf ("%a", fp); /* { dg-warning "unknown|format" "%a is unsupported" } */
+  scanf ("%A", fp); /* { dg-warning "unknown|format" "%A is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-3.c
@@ -0,0 +1,20 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char **sp, wchar_t **lsp)
+{
+  /* %a formats for allocation, only recognized in C90 mode, are a
+     GNU extension.
+  */
+  scanf ("%as", sp); /* { dg-warning "flag" "%as is unsupported" } */
+  scanf ("%aS", lsp); /* { dg-warning "format|flag" "%aS is unsupported" } */
+  scanf ("%a[bcd]", sp); /* { dg-warning "flag" "%a[] is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-4.c
@@ -0,0 +1,31 @@
+/* Test for scanf formats.  Test that the C90 functions get their default
+   attributes in strict C90 mode, but the C99 and gettext functions
+   do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, char *s, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5)
+{
+  fscanf (stdin, "%d", ip);
+  fscanf (stdin, "%ld", ip); /* { dg-warning "format" "fscanf" } */
+  scanf ("%d", ip);
+  scanf ("%ld", ip); /* { dg-warning "format" "scanf" } */
+  sscanf (s, "%d", ip);
+  sscanf (s, "%ld", ip); /* { dg-warning "format" "sscanf" } */
+  vfscanf (stdin, "%d", v0);
+  vscanf ("%d", v2);
+  vsscanf (s, "%d", v4);
+  scanf (gettext ("%d"), ip);
+  scanf (gettext ("%ld"), ip);
+  scanf (dgettext ("", "%d"), ip);
+  scanf (dgettext ("", "%ld"), ip);
+  scanf (dcgettext ("", "%d", 0), ip);
+  scanf (dcgettext ("", "%ld", 0), ip);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-5.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-5.c
@@ -0,0 +1,20 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char **sp, wchar_t **lsp)
+{
+  /* m assignment-allocation modifier, recognized in both C90
+     and C99 modes, is a POSIX and ISO/IEC WDTR 24731-2 extension.  */
+  scanf ("%ms", sp); /* { dg-warning "unknown|format" "%ms is unsupported" } */
+  scanf ("%mS", lsp); /* { dg-warning "unknown|format" "%mS is unsupported" } */
+  scanf ("%mls", lsp); /* { dg-warning "unknown|format" "%mls is unsupported" } */
+  scanf ("%m[bcd]", sp); /* { dg-warning "unknown|format" "%m[] is unsupported" } */
+  scanf ("%ml[bcd]", lsp); /* { dg-warning "unknown|format" "%ml[] is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-1.c
@@ -0,0 +1,20 @@
+/* Test for strftime formats.  Formats using C90 features.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wformat-y2k" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.12.3.5 (pages 174-175).  */
+  /* Formats which are Y2K-compliant (no 2-digit years).  */
+  strftime (s, m, "%a%A%b%B%d%H%I%j%m%M%p%S%U%w%W%X%Y%Z%%", tp);
+  /* Formats with 2-digit years.  */
+  strftime (s, m, "%y", tp); /* { dg-warning "only last 2" "2-digit year" } */
+  /* Formats with 2-digit years in some locales.  */
+  strftime (s, m, "%c", tp); /* { dg-warning "some locales" "2-digit year" } */
+  strftime (s, m, "%x", tp); /* { dg-warning "some locales" "2-digit year" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-2.c
@@ -0,0 +1,28 @@
+/* Test for strftime formats.  Rejection of formats using C99 features in
+   pedantic C90 mode.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wformat-y2k" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  strftime (s, m, "%C", tp); /* { dg-warning "format" "%C is unsupported" } */
+  strftime (s, m, "%D", tp); /* { dg-warning "format" "%D is unsupported" } */
+  strftime (s, m, "%e", tp); /* { dg-warning "format" "%e is unsupported" } */
+  strftime (s, m, "%F", tp); /* { dg-warning "format" "%F is unsupported" } */
+  strftime (s, m, "%g", tp); /* { dg-warning "format" "%g is unsupported" } */
+  strftime (s, m, "%G", tp); /* { dg-warning "format" "%G is unsupported" } */
+  strftime (s, m, "%h", tp); /* { dg-warning "format" "%h is unsupported" } */
+  strftime (s, m, "%n", tp); /* { dg-warning "format" "%n is unsupported" } */
+  strftime (s, m, "%r", tp); /* { dg-warning "format" "%r is unsupported" } */
+  strftime (s, m, "%R", tp); /* { dg-warning "format" "%R is unsupported" } */
+  strftime (s, m, "%t", tp); /* { dg-warning "format" "%t is unsupported" } */
+  strftime (s, m, "%T", tp); /* { dg-warning "format" "%T is unsupported" } */
+  strftime (s, m, "%u", tp); /* { dg-warning "format" "%u is unsupported" } */
+  strftime (s, m, "%V", tp); /* { dg-warning "format" "%V is unsupported" } */
+  strftime (s, m, "%z", tp); /* { dg-warning "C" "%z not in C90" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c94-printf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c94-printf-1.c
@@ -0,0 +1,19 @@
+/* Test for printf formats.  Changes in C94 to C90.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:199409 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (wint_t lc, wchar_t *ls)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.1 (pages 131-134),
+     as amended by ISO/IEC 9899:1990/Amd.1:1995 (E) (pages 4-5).
+     We do not repeat here all the C90 format checks, but just verify
+     that %ls and %lc are accepted without warning.
+  */
+  printf ("%lc", lc);
+  printf ("%ls", ls);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c94-scanf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c94-scanf-1.c
@@ -0,0 +1,18 @@
+/* Test for scanf formats.  Changes in C94 to C90.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:199409 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (wchar_t *ls)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.2 (pages 134-138),
+     as amended by ISO/IEC 9899:1990/Amd.1:1995 (E) (pages 5-6).
+     We do not repeat here all the C90 format checks, but just verify
+     that %ls, %lc, %l[] are accepted without warning.
+  */
+  scanf ("%lc%ls%l[abc]", ls, ls, ls);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-1.c
@@ -0,0 +1,109 @@
+/* Test for printf formats.  Formats using C99 features, including cases
+   where C99 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, unsigned int u, double d, char *s, void *p, int *n,
+     long double ld, wint_t lc, wchar_t *ls, long long int ll,
+     unsigned long long int ull, signed char *ss, unsigned char *us,
+     long long int *lln, intmax_t j, uintmax_t uj, intmax_t *jn,
+     size_t z, signed_size_t sz, signed_size_t *zn,
+     ptrdiff_t t, ptrdiff_t *tn)
+{
+  /* See ISO/IEC 9899:1999 (E) subclause 7.19.6.1 (pages 273-281).
+     We do not repeat here most of the checks for correct C90 formats
+     or completely broken formats.
+  */
+  /* Valid and invalid %h, %hh, %l, %j, %z, %t, %L constructions.  */
+  printf ("%hf", d); /* { dg-warning "length" "bad use of %h" } */
+  printf ("%hF", d); /* { dg-warning "unknown|format" "bad use of %hF" } */
+  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 ("%ha", d); /* { dg-warning "unknown|format" "bad use of %ha" } */
+  printf ("%hA", d); /* { dg-warning "unknown|format" "bad use of %hA" } */
+  printf ("%hc", i);
+  printf ("%hs", (short *)s);
+  printf ("%hp", p); /* { dg-warning "length" "bad use of %h" } */
+  printf ("%lc", lc);
+  printf ("%ls", ls);
+  printf ("%lp", p); /* { dg-warning "length|C" "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" } */
+  /* 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" } */
+  /* 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% 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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 ("%-08F", d); /* { dg-warning "unknown|format" "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 ("%-08a", d); /* { dg-warning "unknown|format" "0 flag ignored with - flag" } */
+  printf ("%-08A", d); /* { dg-warning "unknown|format" "0 flag ignored with - flag" } */
+  /* Various tests of bad argument types.  Mostly covered in c90-printf-1.c;
+     here just test for pointer target sign with %hhn.  (Probably allowed
+     by the standard, but a bad idea, so GCC should diagnose if what
+     is used is not signed char *.)
+  */
+  printf ("%hhn", s); /* { dg-warning "unknown|format" "%hhn is unsupported" } */
+  printf ("%hhn", us); /* { dg-warning "unknown|format" "%hhn is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-2.c
@@ -0,0 +1,32 @@
+/* Test for printf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, long long ll, size_t z, wint_t lc, wchar_t *ls)
+{
+  /* The length modifiers q, Z and L as applied to integer formats are
+     extensions.
+  */
+  printf ("%qd", ll); /* { dg-warning "unknown|format" "%q length is unsupported" } */
+  printf ("%Ld", ll); /* { dg-warning "unknown|format" "%L length is unsupported" } */
+  printf ("%Zd", z); /* { dg-warning "unknown|format" "%Z length is unsupported" } */
+  /* The conversion specifiers C and S are X/Open extensions; the
+     conversion specifier m is a GNU extension.
+  */
+  printf ("%m"); /* { dg-warning "unknown" "printf %m is unsupported" } */
+  printf ("%C", lc); /* { dg-warning "C" "printf %C" } */
+  printf ("%S", ls); /* { dg-warning "C" "printf %S" } */
+  /* The flag character ', and the use of operand number $ formats, are
+     X/Open extensions.
+  */
+  printf ("%'d", i); /* { dg-warning "C" "printf ' flag" } */
+  printf ("%1$d", i); /* { dg-warning "C" "printf $ format" } */
+  printf ("%Ix", z); /* { dg-warning "C" "printf I format" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-3.c
@@ -0,0 +1,40 @@
+/* Test for printf formats.  Test that the C99 functions get their default
+   attributes in strict C99 mode, but the gettext functions do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, char *s, size_t n, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5, va_list v6, va_list v7)
+{
+  fprintf (stdout, "%d", i);
+  fprintf (stdout, "%ld", i); /* { dg-warning "format" "fprintf" } */
+  printf ("%d", i);
+  printf ("%ld", i); /* { dg-warning "format" "printf" } */
+  /* The "unlocked" functions shouldn't warn in c99 mode.  */
+  fprintf_unlocked (stdout, "%ld", i);
+  printf_unlocked ("%ld", i);
+  sprintf (s, "%d", i);
+  sprintf (s, "%ld", i); /* { dg-warning "format" "sprintf" } */
+  snprintf (s, n, "%d", i);
+  snprintf (s, n, "%ld", i); /* { dg-warning "format" "snprintf" } */
+  vfprintf (stdout, "%d", v0);
+  vfprintf (stdout, "%Y", v1); /* { dg-warning "format" "vfprintf" } */
+  vprintf ("%d", v0);
+  vprintf ("%Y", v1); /* { dg-warning "format" "vprintf" } */
+  vsprintf (s, "%d", v0);
+  vsprintf (s, "%Y", v1); /* { dg-warning "format" "vsprintf" } */
+  vsnprintf (s, n, "%d", v0);
+  vsnprintf (s, n, "%Y", v1); /* { dg-warning "format" "vsnprintf" } */
+  printf (gettext ("%d"), i);
+  printf (gettext ("%ld"), (long) i);
+  printf (dgettext ("", "%d"), i);
+  printf (dgettext ("", "%ld"), (long) i);
+  printf (dcgettext ("", "%d", 0), i);
+  printf (dcgettext ("", "%ld", 0), (long) i);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-1.c
@@ -0,0 +1,63 @@
+/* Test for scanf formats.  Formats using C99 features, including cases
+   where C99 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, unsigned int *uip, short int *hp, unsigned short int *uhp,
+     signed char *hhp, unsigned char *uhhp, long int *lp,
+     unsigned long int *ulp, float *fp, double *dp, long double *ldp, char *s,
+     void **pp, int *n, long long *llp, unsigned long long *ullp, wchar_t *ls,
+     short int *hn, signed char *hhn, long int *ln, long long int *lln,
+     intmax_t *jp, uintmax_t *ujp, intmax_t *jn, size_t *zp,
+     signed_size_t *szp, signed_size_t *zn, ptrdiff_t *tp,
+     unsigned_ptrdiff_t *utp, ptrdiff_t *tn)
+{
+  /* See ISO/IEC 9899:1999 (E) subclause 7.19.6.2 (pages 281-288).
+     We do not repeat here most of the checks for correct C90 formats
+     or completely broken formats.
+  */
+  /* Valid, invalid and silly assignment-suppression
+     and width constructions.
+  */
+  scanf ("%*d%*i%*o%*u%*x%*X%*e%*E%*f%*g%*G%*s%*[abc]%*c%*p");
+  scanf ("%*2d%*8s%*3c");
+  scanf ("%*n", n); /* { dg-warning "suppress" "suppression of %n" } */
+  scanf ("%*hd"); /* { dg-warning "together" "suppression with length" } */
+  scanf ("%2d%3i%4o%5u%6x%7X%10e%11E%12f%14g%15G%16s%3[abc]%4c%5p",
+	 ip, ip, uip, uip, uip, uip, fp, fp, fp, fp, fp,
+	 s, s, s, pp);
+  scanf ("%0d", ip); /* { dg-warning "width" "warning for zero width" } */
+  scanf ("%3n", n); /* { dg-warning "width" "width with %n" } */
+  /* Valid and invalid %h, %hh, %l, %j, %z, %t, %L constructions.  */
+  scanf ("%hd%hi%ho%hu%hx%hX%hn", hp, hp, uhp, uhp, uhp, uhp, hn);
+  scanf ("%he", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hE", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hf", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hg", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hG", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hs", hp);
+  scanf ("%h[ac]", s); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hc", (short *)s);
+  scanf ("%hp", pp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hhd", hhp); /* { dg-warning "unknown|format" "%hh is unsupported" } */
+  scanf ("%ld%li%lo%lu%lx%lX%ln", lp, lp, ulp, ulp, ulp, ulp, ln);
+  scanf ("%le%lE%lf%lg%lG", dp, dp, dp, dp, dp);
+  scanf ("%lp", pp); /* { dg-warning "length" "bad use of %l" } */
+  scanf ("%ls", ls);
+  scanf ("%l[ac]", ls);
+  scanf ("%lc", ls);
+  scanf ("%jd", jp); /* { dg-warning "unknown|format" "%j not supported" } */
+  scanf ("%zd", zp); /* { dg-warning "unknown|format" "%z not supported" } */
+  scanf ("%td", tp); /* { dg-warning "unknown|format" "%t not supported" } */
+  scanf ("%Lf", llp); /* { dg-warning "unknown|format" "bad use of %L is not supported" } */
+  /* Valid uses of each bare conversion.  */
+  scanf ("%d%i%o%u%x%X%e%E%f%g%G%s%[abc]%c%p%n%%", ip, ip, uip, uip, uip,
+         uip, fp, fp, fp, fp, fp, s, s, s, pp, n);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-2.c
@@ -0,0 +1,27 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, long long int *llp, wchar_t *ls)
+{
+  /* The length modifiers q and L as applied to integer formats are
+     extensions.
+  */
+  scanf ("%qd", llp); /* { dg-warning "unknown|format" "%q is unsupported" } */
+  scanf ("%Ld", llp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  /* The conversion specifiers C and S are X/Open extensions.  */
+  scanf ("%C", ls); /* { dg-warning "C" "scanf %C" } */
+  scanf ("%S", ls); /* { dg-warning "C" "scanf %S" } */
+  /* The use of operand number $ formats is an X/Open extension.  */
+  scanf ("%1$d", ip); /* { dg-warning "C" "scanf $ format" } */
+  /* glibc also supports flags ' and I on scanf formats as an extension.  */
+  scanf ("%'d", ip); /* { dg-warning "C" "scanf ' flag" } */
+  scanf ("%Id", (ssize_t *)ip); /* { dg-warning "C" "scanf I flag" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-3.c
@@ -0,0 +1,33 @@
+/* Test for scanf formats.  Test that the C99 functions get their default
+   attributes in strict C99 mode, but the gettext functions do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, char *s, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5)
+{
+  fscanf (stdin, "%d", ip);
+  fscanf (stdin, "%ld", ip); /* { dg-warning "format" "fscanf" } */
+  scanf ("%d", ip);
+  scanf ("%ld", ip); /* { dg-warning "format" "scanf" } */
+  sscanf (s, "%d", ip);
+  sscanf (s, "%ld", ip); /* { dg-warning "format" "sscanf" } */
+  vfscanf (stdin, "%d", v0);
+  vfscanf (stdin, "%Y", v1); /* { dg-warning "format" "vfscanf" } */
+  vscanf ("%d", v2);
+  vscanf ("%Y", v3); /* { dg-warning "format" "vscanf" } */
+  vsscanf (s, "%d", v4);
+  vsscanf (s, "%Y", v5); /* { dg-warning "format" "vsscanf" } */
+  scanf (gettext ("%d"), ip);
+  scanf (gettext ("%ld"), ip);
+  scanf (dgettext ("", "%d"), ip);
+  scanf (dgettext ("", "%ld"), ip);
+  scanf (dcgettext ("", "%d", 0), ip);
+  scanf (dcgettext ("", "%ld", 0), ip);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-4.c
@@ -0,0 +1,20 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char **sp, wchar_t **lsp)
+{
+  /* m assignment-allocation modifier, recognized in both C90
+     and C99 modes, is a POSIX and ISO/IEC WDTR 24731-2 extension.  */
+  scanf ("%ms", sp); /* { dg-warning "unknown|format" "%ms is unsupported" } */
+  scanf ("%mS", lsp); /* { dg-warning "unknown|format" "%mS is unsupported" } */
+  scanf ("%mls", lsp); /* { dg-warning "unknown|format" "%mls is unsupported" } */
+  scanf ("%m[bcd]", sp); /* { dg-warning "unknown|format" "%m[] is unsupported" } */
+  scanf ("%ml[bcd]", lsp); /* { dg-warning "unknown|format" "%ml[] is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-1.c
@@ -0,0 +1,22 @@
+/* Test for strftime formats.  Formats using C99 features.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat -Wformat-y2k" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.12.3.5 (pages 174-175).  */
+  /* Formats which are Y2K-compliant (no 2-digit years).  */
+  strftime (s, m, "%a%A%b%B%d%H%I%j%m%M%p%S%U%w%W%X%Y%z%Z%%", tp);
+  /* Formats with 2-digit years.  */
+  strftime (s, m, "%D", tp);
+  strftime (s, m, "%g", tp);
+  strftime (s, m, "%y", tp);
+  /* Formats with 2-digit years in some locales.  */
+  strftime (s, m, "%c", tp);
+  strftime (s, m, "%x", tp);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-2.c
@@ -0,0 +1,20 @@
+/* Test for strftime formats.  Rejection of extensions in pedantic mode.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  /* %P is a lowercase version of %p.  */
+  strftime (s, m, "%P", tp); /* { dg-warning "unknown" "strftime %P" } */
+  /* %k is %H but padded with a space rather than 0 if necessary.  */
+  strftime (s, m, "%k", tp); /* { dg-warning "unknown" "strftime %k" } */
+  /* %l is %I but padded with a space rather than 0 if necessary.  */
+  strftime (s, m, "%l", tp); /* { dg-warning "unknown" "strftime %l" } */
+  /* %s is the number of seconds since the Epoch.  */
+  strftime (s, m, "%s", tp); /* { dg-warning "unknown" "strftime %s" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_cast-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_cast-1.c
@@ -0,0 +1,17 @@
+/* Test for strings cast through integer types: should not be treated
+   as format strings unless the types are of the same width as
+   pointers (intptr_t or similar).  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+f (int x)
+{
+  printf("%s", x); /* { dg-warning "format" } */
+  printf((char *)(size_t)"%s", x); /* { dg-warning "format" } */
+  printf((char *)(char)"%s", x); /* { dg-warning "cast from pointer to integer of different size" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-1.c
@@ -0,0 +1,40 @@
+/* Test for warnings for missing format attributes.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  vprintf (fmt, ap); /* { dg-warning "candidate" "printf attribute warning" } */
+  va_end (ap);
+}
+
+void
+bar (const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  vscanf (fmt, ap); /* { dg-warning "candidate" "scanf attribute warning" } */
+  va_end (ap);
+}
+
+__attribute__((__format__(__ms_printf__, 1, 2))) void
+foo2 (const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  vprintf (fmt, ap);
+  va_end (ap);
+}
+
+void
+vfoo (const char *fmt, va_list arg)
+{
+  vprintf (fmt, arg); /* { dg-warning "candidate" "printf attribute warning 2" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-2.c
@@ -0,0 +1,17 @@
+/* Test for warnings for missing format attributes.  Don't warn if no
+   relevant parameters for a format attribute; see c/1017.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, ...)
+{
+  va_list ap;
+  va_start (ap, i);
+  vprintf ("Foo %s bar %s", ap); /* { dg-bogus "candidate" "bogus printf attribute warning" } */
+  va_end (ap);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-3.c
@@ -0,0 +1,27 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+void
+foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
+{
+  noattr_t na1 = na;
+  noattr_t na2 = a; /* { dg-warning "candidate" "initialization warning" } */
+  attr_t a1 = na;
+  attr_t a2 = a;
+
+  vnoattr_t vna1 = vna;
+  vnoattr_t vna2 = va; /* { dg-warning "candidate" "initialization warning" } */
+  vattr_t va1 = vna;
+  vattr_t va2 = va;
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-4.c
@@ -0,0 +1,33 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+void
+foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
+{
+  noattr_t na1, na2;
+  attr_t a1, a2;
+
+  vnoattr_t vna1, vna2;
+  vattr_t va1, va2;
+
+  na1 = na;
+  na2 = a; /* { dg-warning "candidate" "assignment warning" } */
+  a1 = na;
+  a2 = a;
+
+  vna1 = vna;
+  vna2 = va; /* { dg-warning "candidate" "assignment warning" } */
+  va1 = vna;
+  va1 = va;
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-5.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-5.c
@@ -0,0 +1,49 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+noattr_t
+foo1 (noattr_t na, attr_t a, int i)
+{
+  if (i)
+    return na;
+  else
+    return a; /* { dg-warning "candidate" "return type warning" } */
+}
+
+attr_t
+foo2 (noattr_t na, attr_t a, int i)
+{
+  if (i)
+    return na;
+  else
+    return a;
+}
+
+vnoattr_t
+foo3 (vnoattr_t vna, vattr_t va, int i)
+{
+  if (i)
+    return vna;
+  else
+    return va; /* { dg-warning "candidate" "return type warning" } */
+}
+
+vattr_t
+foo4 (vnoattr_t vna, vattr_t va, int i)
+{
+  if (i)
+    return vna;
+  else
+    return va;
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-6.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-6.c
@@ -0,0 +1,32 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+extern void foo1 (noattr_t);
+extern void foo2 (attr_t);
+extern void foo3 (vnoattr_t);
+extern void foo4 (vattr_t);
+
+void
+foo (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
+{
+  foo1 (na);
+  foo1 (a); /* { dg-warning "candidate" "parameter passing warning" } */
+  foo2 (na);
+  foo2 (a);
+
+  foo3 (vna);
+  foo3 (va); /* { dg-warning "candidate" "parameter passing warning" } */
+  foo4 (vna);
+  foo4 (va);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_multattr-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_multattr-1.c
@@ -0,0 +1,51 @@
+/* Test for multiple format attributes.  Test for printf and scanf attributes
+   together.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* If we specify multiple attributes for a single function, they should
+   all apply.  This should apply whether they are on the same declaration
+   or on different declarations.  */
+
+extern void my_vprintf_scanf (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_printf__, 1, 0)))
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern void my_vprintf_scanf2 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)))
+     __attribute__((__format__(__ms_printf__, 1, 0)));
+
+extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_printf__, 1, 0)));
+extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_printf__, 1, 0)));
+
+void
+foo (va_list ap, int *ip, long *lp)
+{
+  my_vprintf_scanf ("%d", ap, "%d", ip);
+  my_vprintf_scanf ("%d", ap, "%ld", lp);
+  my_vprintf_scanf ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf2 ("%d", ap, "%d", ip);
+  my_vprintf_scanf2 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf2 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf2 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf3 ("%d", ap, "%d", ip);
+  my_vprintf_scanf3 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf3 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf3 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf4 ("%d", ap, "%d", ip);
+  my_vprintf_scanf4 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf4 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf4 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_multattr-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_multattr-2.c
@@ -0,0 +1,40 @@
+/* Test for multiple format attributes.  Test for printf and scanf attributes
+   together, in different places on the declarations.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* If we specify multiple attributes for a single function, they should
+   all apply, wherever they are placed on the declarations.  */
+
+extern __attribute__((__format__(__ms_printf__, 1, 0))) void
+     my_vprintf_scanf (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern void (__attribute__((__format__(__ms_printf__, 1, 0))) my_vprintf_scanf2)
+     (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern __attribute__((__format__(__ms_scanf__, 3, 4))) void
+     (__attribute__((__format__(__ms_printf__, 1, 0))) my_vprintf_scanf3)
+     (const char *, va_list, const char *, ...);
+
+void
+foo (va_list ap, int *ip, long *lp)
+{
+  my_vprintf_scanf ("%d", ap, "%d", ip);
+  my_vprintf_scanf ("%d", ap, "%ld", lp);
+  my_vprintf_scanf ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf2 ("%d", ap, "%d", ip);
+  my_vprintf_scanf2 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf2 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf2 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf3 ("%d", ap, "%d", ip);
+  my_vprintf_scanf3 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf3 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf3 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_multattr-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_multattr-3.c
@@ -0,0 +1,29 @@
+/* Test for multiple format_arg attributes.  Test for both branches
+   getting checked.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+extern char *ngettext (const char *, const char *, unsigned long int)
+     __attribute__((__format_arg__(1))) __attribute__((__format_arg__(2)));
+
+void
+foo (long l, int nfoo)
+{
+  printf (ngettext ("%d foo", "%d foos", nfoo), nfoo);
+  printf (ngettext ("%d foo", "%d foos", l), l); /* { dg-warning "int" "wrong type in conditional expr" } */
+  printf (ngettext ("%d foo", "%ld foos", l), l); /* { dg-warning "int" "wrong type in conditional expr" } */
+  printf (ngettext ("%ld foo", "%d foos", l), l); /* { dg-warning "int" "wrong type in conditional expr" } */
+  /* Should allow one case to have extra arguments.  */
+  printf (ngettext ("1 foo", "%d foos", nfoo), nfoo);
+  printf (ngettext ("1 foo", "many foos", nfoo), nfoo); /* { dg-warning "too many" "too many args in all branches" } */
+  printf (ngettext ("", "%d foos", nfoo), nfoo);
+  printf (ngettext ("1 foo", (nfoo > 0) ? "%d foos" : "no foos", nfoo), nfoo);
+  printf (ngettext ("%d foo", (nfoo > 0) ? "%d foos" : "no foos", nfoo), nfoo);
+  printf (ngettext ("%ld foo", (nfoo > 0) ? "%d foos" : "no foos", nfoo), nfoo); /* { dg-warning "long int" "wrong type" } */
+  printf (ngettext ("%d foo", (nfoo > 0) ? "%ld foos" : "no foos", nfoo), nfoo); /* { dg-warning "long int" "wrong type" } */
+  printf (ngettext ("%d foo", (nfoo > 0) ? "%d foos" : "%ld foos", nfoo), nfoo); /* { dg-warning "long int" "wrong type" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-1.c
@@ -0,0 +1,15 @@
+/* Test for warnings for extra format arguments being disabled by
+   -Wno-format-extra-args.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wno-format-extra-args" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i)
+{
+  printf ("foo", i);
+  printf ("%1$d", i, i);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-2.c
@@ -0,0 +1,28 @@
+/* Test for warnings for extra format arguments being disabled by
+   -Wno-format-extra-args.  Test which warnings still apply with $
+   operand numbers.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wno-format-extra-args" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, int *ip, va_list va)
+{
+  printf ("%3$d%1$d", i, i, i); /* { dg-warning "before used" "unused $ operand" } */
+  printf ("%2$d%1$d", i, i, i);
+  vprintf ("%3$d%1$d", va); /* { dg-warning "before used" "unused $ operand" } */
+  /* With scanf formats, gaps in the used arguments are allowed only if the
+     arguments are all pointers.  In such a case, should only give the lesser
+     warning about unused arguments rather than the more serious one about
+     argument gaps.  */
+  scanf ("%3$d%1$d", ip, ip, ip);
+  /* If there are non-pointer arguments unused at the end, this is also OK.  */
+  scanf ("%3$d%1$d", ip, ip, ip, i);
+  scanf ("%3$d%1$d", ip, i, ip); /* { dg-warning "before used" "unused $ scanf non-pointer operand" } */
+  /* Can't check the arguments in the vscanf case, so should suppose the
+     lesser problem.  */
+  vscanf ("%3$d%1$d", va);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_no-y2k-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_no-y2k-1.c
@@ -0,0 +1,13 @@
+/* Test for warnings for Y2K problems not being on by default.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  strftime (s, m, "%y%c%x", tp);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-1.c
@@ -0,0 +1,14 @@
+/* Test for warnings for non-string-literal formats.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wformat-nonliteral" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t i)
+{
+  printf ((const char *)i, i); /* { dg-warning "argument types" "non-literal" } */
+  printf (s, i); /* { dg-warning "argument types" "non-literal" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-2.c
@@ -0,0 +1,14 @@
+/* Test for warnings for non-string-literal formats.  Test with -Wformat=2.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat=2" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t i)
+{
+  printf ((const char *)i, i); /* { dg-warning "argument types" "non-literal" } */
+  printf (s, i); /* { dg-warning "argument types" "non-literal" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-3.c
@@ -0,0 +1,13 @@
+/* Test for warnings for non-string-literal formats.  Test for strftime formats.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wformat-nonliteral" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp, char *fmt)
+{
+  strftime (s, m, fmt, tp); /* { dg-warning "format string" "non-literal" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nul-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nul-1.c
@@ -0,0 +1,15 @@
+/* Test diagnostics for suppressing contains nul
+   -Wformat.  -Wformat.  */
+/* Origin: Bruce Korb <bkorb@gnu.org> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat -Wno-format-contains-nul" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (void)
+{
+  static char const fmt[] = "x%s\0%s\n\0abc";
+  printf (fmt+4, fmt+8); /* { dg-bogus "embedded.*in format" "bogus embed warning" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nul-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nul-2.c
@@ -0,0 +1,17 @@
+/* Test diagnostics for options used on their own without
+   -Wformat.  -Wformat-.  */
+/* Origin: Bruce Korb <bkorb@gnu.org> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+
+/* { dg-warning "embedded .* in format" "ignored" { target *-*-* } 0 } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+fumble (void)
+{
+  static char const fmt[] = "x%s\0%s\n\0abc";
+  printf (fmt+4, fmt+8);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_null-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_null-1.c
@@ -0,0 +1,28 @@
+/* Test for some aspects of null format string handling.  */
+/* Origin: Jason Thorpe <thorpej@wasabisystems.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+extern void my_printf (const char *, ...) __attribute__((format(ms_printf,1,2)));
+extern const char *my_format (const char *, const char *)
+  __attribute__((format_arg(2)));
+
+void
+foo (int i1)
+{
+  /* Warning about a null format string has been decoupled from the actual
+     format check.  However, we still expect to be warned about any excess
+     arguments after a null format string.  */
+  my_printf (NULL);
+  my_printf (NULL, i1); /* { dg-warning "too many" "null format with arguments" } */
+
+  my_printf (my_format ("", NULL));
+  my_printf (my_format ("", NULL), i1); /* { dg-warning "too many" "null format_arg with arguments" } */
+
+  /* While my_printf allows a null argument, dgettext does not, so we expect
+     a null argument warning here.  */
+  my_printf (dgettext ("", NULL)); /* { dg-warning "null" "null format with dgettext" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_plus-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_plus-1.c
@@ -0,0 +1,21 @@
+/* Test for printf formats using string literal plus constant.
+ */
+/* Origin: Jakub Jelinek <jakub@redhat.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat=2" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i)
+{
+  printf ("%%d\n" + 1, i);
+  printf (5 + "%.-*d%3d\n", i);
+  printf ("%d%d" + 2, i, i);	/* { dg-warning "arguments" "wrong number of args" } */
+  printf (3 + "%d\n");		/* { dg-warning "zero-length" "zero-length string" } */
+  printf ("%d\n" + i, i);	/* { dg-warning "not a string" "non-constant addend" } */
+  printf ("%d\n" + 10);		/* { dg-warning "not a string" "too large addend" } */
+  printf ("%d\n" - 1, i);	/* { dg-warning "not a string" "minus constant" } */
+  printf ("%d\n" + -1, i);	/* { dg-warning "not a string" "negative addend" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_sec-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_sec-1.c
@@ -0,0 +1,13 @@
+/* Test for security warning when non-literal format has no arguments.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wformat-security" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s)
+{
+  printf (s); /* { dg-warning "no format arguments" "security warning" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_unnamed-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_unnamed-1.c
@@ -0,0 +1,24 @@
+/* Test for warnings with possibly unnamed integer types.  Bug 24329.  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+/* { dg-options "-Wformat -msse" { target { { i?86-*-* x86_64-*-* } && ilp32 } } } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* Definition of TItype follows same logic as in gcc.dg/titype-1.c,
+   but must be a #define to avoid giving the type a name.  */
+#if defined(__LP64__) && !defined(__hppa__)
+#define TItype int __attribute__ ((mode (TI)))
+#else
+#define TItype long
+#endif
+
+void
+f (TItype x)
+{
+  printf("%d", x); /* { dg-warning "expects type" } */
+  printf("%d", 141592653589793238462643383279502884197169399375105820974944); /* { dg-warning "expects type" } */
+  /* { dg-warning "unsigned only|too large" "constant" { target *-*-* } 22 } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_va-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_va-1.c
@@ -0,0 +1,14 @@
+/* Test for strange warning in format checking.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (void *p)
+{
+  printf ("%d", p); /* { dg-bogus "va_list" "wrong type in format warning" } */
+  /* { dg-warning "format" "format error" { target *-*-* } 12 } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_zero-length-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_zero-length-1.c
@@ -0,0 +1,16 @@
+/* Test the -Wno-format-zero-length option, which suppresses warnings
+   about zero-length formats.  */
+/* Origin: Jason Thorpe <thorpej@wasabisystems.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wno-format-zero-length" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (void)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.1 (pages 131-134).  */
+  /* Zero-length format strings are allowed.  */
+  printf ("");
+}
Index: gcc/gcc/testsuite/gcc.dg/format/multattr-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/multattr-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/multattr-1.c
@@ -4,6 +4,7 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 /* If we specify multiple attributes for a single function, they should
@@ -11,22 +12,22 @@
    or on different declarations.  */
 
 extern void my_vprintf_scanf (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__printf__, 1, 0)))
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)))
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
 extern void my_vprintf_scanf2 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)))
-     __attribute__((__format__(__printf__, 1, 0)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)))
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)));
 
 extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__printf__, 1, 0)));
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)));
 extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
 extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__printf__, 1, 0)));
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)));
 
 void
 foo (va_list ap, int *ip, long *lp)
Index: gcc/gcc/testsuite/gcc.dg/format/multattr-2.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/multattr-2.c
+++ gcc/gcc/testsuite/gcc.dg/format/multattr-2.c
@@ -4,21 +4,22 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 /* If we specify multiple attributes for a single function, they should
    all apply, wherever they are placed on the declarations.  */
 
-extern __attribute__((__format__(__printf__, 1, 0))) void
+extern __attribute__((__format__(gnu_attr___printf__, 1, 0))) void
      my_vprintf_scanf (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
-extern void (__attribute__((__format__(__printf__, 1, 0))) my_vprintf_scanf2)
+extern void (__attribute__((__format__(gnu_attr___printf__, 1, 0))) my_vprintf_scanf2)
      (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
-extern __attribute__((__format__(__scanf__, 3, 4))) void
-     (__attribute__((__format__(__printf__, 1, 0))) my_vprintf_scanf3)
+extern __attribute__((__format__(gnu_attr___scanf__, 3, 4))) void
+     (__attribute__((__format__(gnu_attr___printf__, 1, 0))) my_vprintf_scanf3)
      (const char *, va_list, const char *, ...);
 
 void
Index: gcc/gcc/testsuite/gcc.dg/format/null-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/null-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/null-1.c
@@ -3,9 +3,10 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern void my_printf (const char *, ...) __attribute__((format(printf,1,2)));
+extern void my_printf (const char *, ...) __attribute__((format(gnu_attr_printf,1,2)));
 extern const char *my_format (const char *, const char *)
   __attribute__((format_arg(2)));
 
=

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf  formatters to c-format.c
  2008-03-18 13:44                                     ` NightStrike
@ 2008-03-18 13:51                                       ` Kai Tietz
  2008-03-18 15:07                                       ` Kai Tietz
  1 sibling, 0 replies; 61+ messages in thread
From: Kai Tietz @ 2008-03-18 13:51 UTC (permalink / raw)
  To: NightStrike; +Cc: Danny Smith, GCC Patches, ktietz70

NightStrike <nightstrike@gmail.com> wrote on 18.03.2008 14:34:11:

> On 3/18/08, Kai Tietz <Kai.Tietz@onevision.com> wrote:
> > Hi Danny,
> >
> > "Danny Smith" <dansmister@gmail.com> wrote on 16.03.2008 06:32:03:
> >
> > > On Fri, Mar 14, 2008 at 11:55 PM, Kai Tietz 
<Kai.Tietz@onevision.com> w
> > > >  Thank you for the log file. I correct the tested cases so far. 
The
> > major
> > > >  problem is that by your suggestion 'I64' length specifier isn't
> > treated as
> > > >  equivalent to the gnu 'll' length sepecifier. This is the reason 
for
> > the
> > > >  failure of a lot of warnings. I let the test-case ms_warnll-1.c 
as it
> > is
> > > >  for showing the issue. I64 and co are declared as STD_EXT, which 
is
> > in my
> > > >  opinion not correct. They should be set as STD_C890 IMHO.
> > I mean STD_C890 is STD_C89. I removed from the testcase ms_warnll-1.c 
the
> > -std settings to let the test pass. We should test I64.
> >
> > I attached the revised patch.
> >
> > > As I indicated earlier, handling of ms_strftime was  and still is
> > incorrect.
> > >
> > > With your patch and this snippet:
> > >
> > > #include <time.h>
> > > #include <stdio.h>
> > > #include <sys/types.h>
> > >
> > > int main()
> > > {
> > >     char buf[128];
> > >     time_t ltime;
> > >     struct tm* today;
> > >
> > >     time (&ltime);
> > >     today =  localtime(&ltime);
> > >
> > >     printf ("c, x, y, formats\n");
> > >     strftime (buf, 128, "c: %c\n", today);
> > >     printf (buf);
> > >     strftime (buf, 128, "x: %x\n", today);
> > >     printf (buf);
> > >     strftime (buf, 128, "y: %y\n", today);
> > >     printf (buf);
> > >
> > >
> > >     printf ("Alternative #c, #x, #y, formats\n");
> > >     strftime (buf, 128, "#c %#c\n", today);
> > >     printf (buf);
> > >     strftime (buf, 128, "#x %#x\n", today);
> > >     printf (buf);
> > >     strftime (buf, 128, "#y %#y\n", today);
> > >     printf (buf);
> > >
> > >     return 0;
> > > }
> > >
> > > compiled as
> > >
> > > gcc -Wall  -Wformat-y2k ms_stftrime_y2k.c
> > >
> > > I get:
> > >
> > > ms_stftrime_y2k.c: In function 'main':
> > > ms_stftrime_y2k.c:24: warning: '#' flag used with '%c' ms_strftime
> > format
> > > ms_stftrime_y2k.c: warning: '#' flag used with '%x' ms_strftime 
format
> > > ms_stftrime_y2k.c:28: warning: '#' flag used with '%y' ms_strftime
> > format
> > >
> > > 1) The warnings are bogus.
> > > 2) There are no  y2k warnings, but there should be, because this is
> > > the output:
> > >
> > > c, x, y, formats
> > > c: 03/16/08 16:05:38
> > > x: 03/16/08
> > > y: 08
> > > Alternative #c, #x, #y, formats
> > > #c Sunday, March 16, 2008 16:05:38
> > > #x Sunday, March 16, 2008
> > > #y 8
> > >
> > >
> > > Note that '#' does not have glibc meaning.  Instead,  when prefixing 
c
> > > and x flags, is like 'E'.
> > I corrected this as general option with type of STD_EXT and add the 
y2k
> > check to cxy format specifiers.
> 
> Attached is the gcc test log for formatters for this latest patch
> (recompiled and retested in like 10 minutes :)

The file ms_c90-strftime-1.c was not taken out from the new patch. I 
assume ms_warnll_1, too. Please verify and rerun test. 

Thanks and cheers,
  Kai

|  (\_/)  This is Bunny. Copy and paste Bunny
| (='.'=) into your signature to help him gain
| (")_(") world domination.

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf formatters to c-format.c
  2008-03-18 13:20                                   ` Kai Tietz
@ 2008-03-18 13:44                                     ` NightStrike
  2008-03-18 13:51                                       ` Kai Tietz
  2008-03-18 15:07                                       ` Kai Tietz
  0 siblings, 2 replies; 61+ messages in thread
From: NightStrike @ 2008-03-18 13:44 UTC (permalink / raw)
  To: Kai Tietz; +Cc: Danny Smith, GCC Patches, ktietz70

[-- Attachment #1: Type: text/plain, Size: 2789 bytes --]

On 3/18/08, Kai Tietz <Kai.Tietz@onevision.com> wrote:
> Hi Danny,
>
> "Danny Smith" <dansmister@gmail.com> wrote on 16.03.2008 06:32:03:
>
> > On Fri, Mar 14, 2008 at 11:55 PM, Kai Tietz <Kai.Tietz@onevision.com> w
> > >  Thank you for the log file. I correct the tested cases so far. The
> major
> > >  problem is that by your suggestion 'I64' length specifier isn't
> treated as
> > >  equivalent to the gnu 'll' length sepecifier. This is the reason for
> the
> > >  failure of a lot of warnings. I let the test-case ms_warnll-1.c as it
> is
> > >  for showing the issue. I64 and co are declared as STD_EXT, which is
> in my
> > >  opinion not correct. They should be set as STD_C890 IMHO.
> I mean STD_C890 is STD_C89. I removed from the testcase ms_warnll-1.c the
> -std settings to let the test pass. We should test I64.
>
> I attached the revised patch.
>
> > As I indicated earlier, handling of ms_strftime was  and still is
> incorrect.
> >
> > With your patch and this snippet:
> >
> > #include <time.h>
> > #include <stdio.h>
> > #include <sys/types.h>
> >
> > int main()
> > {
> >     char buf[128];
> >     time_t ltime;
> >     struct tm* today;
> >
> >     time (&ltime);
> >     today =  localtime(&ltime);
> >
> >     printf ("c, x, y, formats\n");
> >     strftime (buf, 128, "c: %c\n", today);
> >     printf (buf);
> >     strftime (buf, 128, "x: %x\n", today);
> >     printf (buf);
> >     strftime (buf, 128, "y: %y\n", today);
> >     printf (buf);
> >
> >
> >     printf ("Alternative #c, #x, #y, formats\n");
> >     strftime (buf, 128, "#c %#c\n", today);
> >     printf (buf);
> >     strftime (buf, 128, "#x %#x\n", today);
> >     printf (buf);
> >     strftime (buf, 128, "#y %#y\n", today);
> >     printf (buf);
> >
> >     return 0;
> > }
> >
> > compiled as
> >
> > gcc -Wall  -Wformat-y2k ms_stftrime_y2k.c
> >
> > I get:
> >
> > ms_stftrime_y2k.c: In function 'main':
> > ms_stftrime_y2k.c:24: warning: '#' flag used with '%c' ms_strftime
> format
> > ms_stftrime_y2k.c: warning: '#' flag used with '%x' ms_strftime format
> > ms_stftrime_y2k.c:28: warning: '#' flag used with '%y' ms_strftime
> format
> >
> > 1) The warnings are bogus.
> > 2) There are no  y2k warnings, but there should be, because this is
> > the output:
> >
> > c, x, y, formats
> > c: 03/16/08 16:05:38
> > x: 03/16/08
> > y: 08
> > Alternative #c, #x, #y, formats
> > #c Sunday, March 16, 2008 16:05:38
> > #x Sunday, March 16, 2008
> > #y 8
> >
> >
> > Note that '#' does not have glibc meaning.  Instead,  when prefixing c
> > and x flags, is like 'E'.
> I corrected this as general option with type of STD_EXT and add the y2k
> check to cxy format specifiers.

Attached is the gcc test log for formatters for this latest patch
(recompiled and retested in like 10 minutes :)

[-- Attachment #2: gcc.log.bz2 --]
[-- Type: application/x-bzip2, Size: 31379 bytes --]

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf  formatters to c-format.c
  2008-03-16  5:54                                 ` Danny Smith
  2008-03-16 12:16                                   ` Kai Tietz
@ 2008-03-18 13:20                                   ` Kai Tietz
  2008-03-18 13:44                                     ` NightStrike
  1 sibling, 1 reply; 61+ messages in thread
From: Kai Tietz @ 2008-03-18 13:20 UTC (permalink / raw)
  To: Danny Smith; +Cc: GCC Patches, ktietz70, NightStrike

[-- Attachment #1: Type: text/plain, Size: 2610 bytes --]

Hi Danny,

"Danny Smith" <dansmister@gmail.com> wrote on 16.03.2008 06:32:03:

> On Fri, Mar 14, 2008 at 11:55 PM, Kai Tietz <Kai.Tietz@onevision.com> w
> >  Thank you for the log file. I correct the tested cases so far. The 
major
> >  problem is that by your suggestion 'I64' length specifier isn't 
treated as
> >  equivalent to the gnu 'll' length sepecifier. This is the reason for 
the
> >  failure of a lot of warnings. I let the test-case ms_warnll-1.c as it 
is
> >  for showing the issue. I64 and co are declared as STD_EXT, which is 
in my
> >  opinion not correct. They should be set as STD_C890 IMHO.
I mean STD_C890 is STD_C89. I removed from the testcase ms_warnll-1.c the 
-std settings to let the test pass. We should test I64.

I attached the revised patch.

> As I indicated earlier, handling of ms_strftime was  and still is 
incorrect.
> 
> With your patch and this snippet:
> 
> #include <time.h>
> #include <stdio.h>
> #include <sys/types.h>
> 
> int main()
> {
>     char buf[128];
>     time_t ltime;
>     struct tm* today;
> 
>     time (&ltime);
>     today =  localtime(&ltime);
> 
>     printf ("c, x, y, formats\n");
>     strftime (buf, 128, "c: %c\n", today);
>     printf (buf);
>     strftime (buf, 128, "x: %x\n", today);
>     printf (buf);
>     strftime (buf, 128, "y: %y\n", today);
>     printf (buf);
> 
> 
>     printf ("Alternative #c, #x, #y, formats\n");
>     strftime (buf, 128, "#c %#c\n", today);
>     printf (buf);
>     strftime (buf, 128, "#x %#x\n", today);
>     printf (buf);
>     strftime (buf, 128, "#y %#y\n", today);
>     printf (buf);
> 
>     return 0;
> }
> 
> compiled as
> 
> gcc -Wall  -Wformat-y2k ms_stftrime_y2k.c
> 
> I get:
> 
> ms_stftrime_y2k.c: In function 'main':
> ms_stftrime_y2k.c:24: warning: '#' flag used with '%c' ms_strftime 
format
> ms_stftrime_y2k.c: warning: '#' flag used with '%x' ms_strftime format
> ms_stftrime_y2k.c:28: warning: '#' flag used with '%y' ms_strftime 
format
> 
> 1) The warnings are bogus.
> 2) There are no  y2k warnings, but there should be, because this is 
> the output:
> 
> c, x, y, formats
> c: 03/16/08 16:05:38
> x: 03/16/08
> y: 08
> Alternative #c, #x, #y, formats
> #c Sunday, March 16, 2008 16:05:38
> #x Sunday, March 16, 2008
> #y 8
> 
> 
> Note that '#' does not have glibc meaning.  Instead,  when prefixing c
> and x flags, is like 'E'.
I corrected this as general option with type of STD_EXT and add the y2k 
check to cxy format specifiers.

Cheers,
  Kai



|  (\_/)  This is Bunny. Copy and paste Bunny
| (='.'=) into your signature to help him gain
| (")_(") world domination.

[-- Attachment #2: mingw-msformat.txt --]
[-- Type: text/plain, Size: 151347 bytes --]

Index: gcc/gcc/c-format.c
===================================================================
--- gcc.orig/gcc/c-format.c
+++ gcc/gcc/c-format.c
@@ -62,8 +62,7 @@ enum format_type { printf_format_type, a
 		   gcc_diag_format_type, gcc_tdiag_format_type,
 		   gcc_cdiag_format_type,
 		   gcc_cxxdiag_format_type, gcc_gfc_format_type,
-		   scanf_format_type, strftime_format_type,
-		   strfmon_format_type, format_type_error = -1};
+		   format_type_error = -1};
 
 typedef struct function_format_info
 {
@@ -80,7 +79,8 @@ static bool check_format_string (tree ar
 				 int flags, bool *no_add_attrs);
 static bool get_constant (tree expr, unsigned HOST_WIDE_INT *value,
 			  int validated_p);
-
+static const char *convert_format_name_to_system_name (const char *attr_name);
+static bool cmp_attribs (const char *tattr_name, const char *attr_name);
 
 /* Handle a "format_arg" attribute; arguments as in
    struct attribute_spec.handler.  */
@@ -191,6 +191,8 @@ decode_format_attr (tree args, function_
     {
       const char *p = IDENTIFIER_POINTER (format_type_id);
 
+      p = convert_format_name_to_system_name (p);
+
       info->format_type = decode_format_type (p);
 
       if (info->format_type == format_type_error)
@@ -715,7 +717,7 @@ static const format_char_info monetary_c
 /* This must be in the same order as enum format_type.  */
 static const format_kind_info format_types_orig[] =
 {
-  { "printf",   printf_length_specs,  print_char_table, " +#0-'I", NULL,
+  { "gnu_printf",   printf_length_specs,  print_char_table, " +#0-'I", NULL,
     printf_flag_specs, printf_flag_pairs,
     FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
     'w', 0, 'p', 0, 'L', 0,
@@ -757,18 +759,18 @@ static const format_kind_info format_typ
     0, 0, 0, 0, 0, 0,
     NULL, NULL
   },
-  { "scanf",    scanf_length_specs,   scan_char_table,  "*'I", NULL,
+  { "gnu_scanf",    scanf_length_specs,   scan_char_table,  "*'I", NULL,
     scanf_flag_specs, scanf_flag_pairs,
     FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
     'w', 0, 0, '*', 'L', 'm',
     NULL, NULL
   },
-  { "strftime", NULL,                 time_char_table,  "_-0^#", "EO",
+  { "gnu_strftime", NULL,                 time_char_table,  "_-0^#", "EO",
     strftime_flag_specs, strftime_flag_pairs,
     FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0, 0,
     NULL, NULL
   },
-  { "strfmon",  strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
+  { "gnu_strfmon",  strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
     strfmon_flag_specs, strfmon_flag_pairs,
     FMT_FLAG_ARG_CONVERT, 'w', '#', 'p', 0, 'L', 0,
     NULL, NULL
@@ -847,6 +849,8 @@ decode_format_type (const char *s)
 {
   int i;
   int slen;
+
+  s = convert_format_name_to_system_name (s);
   slen = strlen (s);
   for (i = 0; i < n_format_types; i++)
     {
@@ -1776,7 +1780,22 @@ check_format_info_main (format_check_res
       if (fli)
 	{
 	  while (fli->name != 0 && fli->name[0] != *format_chars)
-	    fli++;
+	    {
+	      if (fli->name[0] == '\0')
+		{
+		  int si  = strlen (fli->name + 1) + 1;
+		  int i = 1;
+		  while (fli->name[i] != 0 && fli->name[i] == format_chars [i - 1])
+		    ++i;
+		 if (si == i)
+		   {
+		     if (si > 2)
+		       format_chars += si - 2;
+		     break;
+		   }
+	       }
+	      fli++;
+	    }
 	  if (fli->name != 0)
 	    {
 	      format_chars++;
@@ -2703,6 +2722,84 @@ init_dynamic_diag_info (void)
 extern const format_kind_info TARGET_FORMAT_TYPES[];
 #endif
 
+#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+extern const target_ovr_attr TARGET_OVERRIDES_FORMAT_ATTRIBUTES[];
+#endif
+
+/* Attributes such as "printf" are equivalent to those such as
+   "gnu_printf" unless this is overridden by a target.  */
+static const target_ovr_attr gnu_target_overrides_format_attributes[] =
+{
+  { "gnu_printf",   "printf" },
+  { "gnu_scanf",    "scanf" },
+  { "gnu_strftime", "strftime" },
+  { "gnu_strfmon",  "strfmon" },
+  { NULL,           NULL }
+};
+
+/* Translate to unified attribute name. This is used in decode_format_type and
+   decode_format_attr. In attr_name the user specified argument is passed. It
+   returns the unified format name from TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+   or the attr_name passed to this function, if there is no matching entry.  */
+static const char *
+convert_format_name_to_system_name (const char *attr_name)
+{
+  int i;
+
+  if (attr_name == NULL || *attr_name == 0
+      || strncmp (attr_name, "gcc_", 4) == 0)
+    return attr_name;
+
+#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+  /* Check if format attribute is overridden by target.  */
+  if (TARGET_OVERRIDES_FORMAT_ATTRIBUTES != NULL
+      && TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT > 0)
+    {
+      for (i = 0; i < TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT; ++i)
+        {
+          if (cmp_attribs (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src,
+			   attr_name))
+            return attr_name;
+          if (cmp_attribs (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_dst,
+			   attr_name))
+            return TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src;
+        }
+    }
+#endif
+  /* Otherwise default to gnu format.  */
+  for (i = 0;
+       gnu_target_overrides_format_attributes[i].named_attr_src != NULL;
+       ++i)
+    {
+      if (cmp_attribs (gnu_target_overrides_format_attributes[i].named_attr_src,
+		       attr_name))
+        return attr_name;
+      if (cmp_attribs (gnu_target_overrides_format_attributes[i].named_attr_dst,
+		       attr_name))
+        return gnu_target_overrides_format_attributes[i].named_attr_src;
+    }
+
+  return attr_name;
+}
+
+/* Return true if TATTR_NAME and ATTR_NAME are the same format attribute,
+   counting "name" and "__name__" as the same, false otherwise.  */
+static bool
+cmp_attribs (const char *tattr_name, const char *attr_name)
+{
+  int alen = strlen (attr_name);
+  int slen = (tattr_name ? strlen (tattr_name) : 0);
+  if (alen > 4 && attr_name[0] == '_' && attr_name[1] == '_'
+      && attr_name[alen - 1] == '_' && attr_name[alen - 2] == '_')
+    {
+      attr_name += 2;
+      alen -= 4;
+    }
+  if (alen != slen || strncmp (tattr_name, attr_name, alen) != 0)
+    return false;
+  return true;
+}
+
 /* Handle a "format" attribute; arguments as in
    struct attribute_spec.handler.  */
 tree
@@ -2762,7 +2859,10 @@ handle_format_attribute (tree *node, tre
 	}
     }
 
-  if (info.format_type == strftime_format_type && info.first_arg_num != 0)
+  /* Check if this is a strftime variant. Just for this variant
+     FMT_FLAG_ARG_CONVERT is not set.  */
+  if ((format_types[info.format_type].flags & (int) FMT_FLAG_ARG_CONVERT) == 0
+      && info.first_arg_num != 0)
     {
       error ("strftime formats cannot format arguments");
       *no_add_attrs = true;
Index: gcc/gcc/c-format.h
===================================================================
--- gcc.orig/gcc/c-format.h
+++ gcc/gcc/c-format.h
@@ -80,12 +80,13 @@ enum
      of whether length modifiers can occur (length_char_specs).  */
 };
 
-
 /* Structure describing a length modifier supported in format checking, and
    possibly a doubled version such as "hh".  */
 typedef struct
 {
-  /* Name of the single-character length modifier.  */
+  /* Name of the single-character length modifier. If prefixed by
+     a zero character, it describes a multi character length
+     modifier, like I64, I32, etc.  */
   const char *name;
   /* Index into a format_char_info.types array.  */
   enum format_lengths index;
@@ -306,4 +307,16 @@ typedef struct
 #define T_D128  &dfloat128_type_node
 #define TEX_D128 { STD_EXT, "_Decimal128", T_D128 }
 
+/* Structure describing how format attributes such as "printf" are
+   interpreted as "gnu_printf" or "ms_printf" on a particular system.
+   TARGET_OVERRIDES_FORMAT_ATTRIBUTES is used to specify target-specific
+   defaults.  */
+typedef struct
+{
+  /* The name of the to be copied format attribute. */
+  const char *named_attr_src;
+  /* The name of the to be overridden format attribute. */
+  const char *named_attr_dst;
+} target_ovr_attr;
+
 #endif /* GCC_C_FORMAT_H */
Index: gcc/gcc/config.gcc
===================================================================
--- gcc.orig/gcc/config.gcc
+++ gcc/gcc/config.gcc
@@ -1372,8 +1372,8 @@ i[34567]86-*-pe | i[34567]86-*-cygwin*)
 	target_gtfiles="\$(srcdir)/config/i386/winnt.c"
 	extra_options="${extra_options} i386/cygming.opt"
 	extra_objs="winnt.o winnt-stubs.o"
-	c_target_objs=cygwin2.o
-	cxx_target_objs="cygwin2.o winnt-cxx.o"
+	c_target_objs="cygwin2.o msformat-c.o"
+	cxx_target_objs="cygwin2.o winnt-cxx.o msformat-c.o"
 	extra_gcc_objs=cygwin1.o
 	if test x$enable_threads = xyes; then
 		thread_file='posix'
@@ -1386,7 +1386,8 @@ i[34567]86-*-mingw32* | x86_64-*-mingw32
 	target_gtfiles="\$(srcdir)/config/i386/winnt.c"
 	extra_options="${extra_options} i386/cygming.opt"
 	extra_objs="winnt.o winnt-stubs.o"
-	cxx_target_objs=winnt-cxx.o
+	c_target_objs="msformat-c.o"
+	cxx_target_objs="winnt-cxx.o msformat-c.o"
 	default_use_cxa_atexit=yes
 	case ${enable_threads} in
 	  "" | yes | win32)
Index: gcc/gcc/config/i386/mingw32.h
===================================================================
--- gcc.orig/gcc/config/i386/mingw32.h
+++ gcc/gcc/config/i386/mingw32.h
@@ -143,6 +143,23 @@ do {						         \
    to register C++ static destructors.  */
 #define TARGET_CXX_USE_ATEXIT_FOR_CXA_ATEXIT hook_bool_void_true
 
+/* Contains a pointer to type target_ovr_attr defining the target specific
+   overrides of format attributes.  See c-format.h for structure
+   definition.  */
+#undef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+#define TARGET_OVERRIDES_FORMAT_ATTRIBUTES mingw_format_attribute_overrides
+
+/* Specify the count of elements in TARGET_OVERRIDES_ATTRIBUTE.  */
+#undef TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT
+#define TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT 3
+
+/* MS specific format attributes for ms_printf, ms_scanf, ms_strftime.  */
+#undef TARGET_FORMAT_TYPES
+#define TARGET_FORMAT_TYPES mingw_format_attributes
+
+#undef TARGET_N_FORMAT_TYPES
+#define TARGET_N_FORMAT_TYPES 3
+
 /* JCR_SECTION works on mingw32.  */
 #undef TARGET_USE_JCR_SECTION
 #define TARGET_USE_JCR_SECTION 1
Index: gcc/gcc/config/i386/msformat-c.c
===================================================================
--- /dev/null
+++ gcc/gcc/config/i386/msformat-c.c
@@ -0,0 +1,176 @@
+/* Check calls to formatted I/O functions (-Wformat).
+   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+   2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "flags.h"
+#include "c-common.h"
+#include "toplev.h"
+#include "intl.h"
+#include "diagnostic.h"
+#include "langhooks.h"
+#include "c-format.h"
+#include "alloc-pool.h"
+
+/* Mingw specific format attributes ms_printf, ms_scanf, and ms_strftime.  */
+
+static const format_length_info ms_printf_length_specs[] =
+{
+  { "h", FMT_LEN_h, STD_C89, NULL, 0, 0 },
+  { "l", FMT_LEN_l, STD_C89, NULL, 0, 0 },
+  { "\0I32", FMT_LEN_l, STD_EXT, NULL, 0, 0 },
+  { "\0I64", FMT_LEN_ll, STD_EXT, NULL, 0, 0 },
+  { "I", FMT_LEN_L, STD_EXT, NULL, 0, 0 },
+  { NULL, 0, 0, NULL, 0, 0 }
+};
+
+static const format_flag_spec ms_printf_flag_specs[] =
+{
+  { ' ',  0, 0, N_("' ' flag"),        N_("the ' ' printf flag"),              STD_C89 },
+  { '+',  0, 0, N_("'+' flag"),        N_("the '+' printf flag"),              STD_C89 },
+  { '#',  0, 0, N_("'#' flag"),        N_("the '#' printf flag"),              STD_C89 },
+  { '0',  0, 0, N_("'0' flag"),        N_("the '0' printf flag"),              STD_C89 },
+  { '-',  0, 0, N_("'-' flag"),        N_("the '-' printf flag"),              STD_C89 },
+  { '\'', 0, 0, N_("''' flag"),        N_("the ''' printf flag"),              STD_EXT },
+  { 'w',  0, 0, N_("field width"),     N_("field width in printf format"),     STD_C89 },
+  { 'p',  0, 0, N_("precision"),       N_("precision in printf format"),       STD_C89 },
+  { 'L',  0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_printf_flag_pairs[] =
+{
+  { ' ', '+', 1, 0   },
+  { '0', '-', 1, 0   }, { '0', 'p', 1, 'i' },
+  { 0, 0, 0, 0 }
+};
+
+static const format_flag_spec ms_scanf_flag_specs[] =
+{
+  { '*',  0, 0, N_("assignment suppression"), N_("the assignment suppression scanf feature"), STD_C89 },
+  { 'a',  0, 0, N_("'a' flag"),               N_("the 'a' scanf flag"),                       STD_EXT },
+  { 'w',  0, 0, N_("field width"),            N_("field width in scanf format"),              STD_C89 },
+  { 'L',  0, 0, N_("length modifier"),        N_("length modifier in scanf format"),          STD_C89 },
+  { '\'', 0, 0, N_("''' flag"),               N_("the ''' scanf flag"),                       STD_EXT },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_scanf_flag_pairs[] =
+{
+  { '*', 'L', 0, 0 },
+  { 0, 0, 0, 0 }
+};
+
+static const format_flag_spec ms_strftime_flag_specs[] =
+{
+  { '#', 0,   0, N_("'#' flag"),     N_("the '#' strftime flag"),          STD_EXT },
+  { 'w', 0,   0, N_("field width"),  N_("field width in strftime format"), STD_EXT },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_strftime_flag_pairs[] =
+{
+  { 0, 0, 0, 0 }
+};
+
+static const format_char_info ms_print_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "di",  0, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  T99_SST,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-wp0 +'",  "i",  NULL },
+  { "oxX", 0, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN, BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "-wp0#",     "i",  NULL },
+  { "u",   0, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN, BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "-wp0'",    "i",  NULL },
+  { "fgG", 0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "-wp0 +#'", "",   NULL },
+  { "eE",  0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "-wp0 +#",  "",   NULL },
+  { "c",   0, STD_C89, { T89_I,   BADLEN,  T89_S,  T94_WI,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "",   NULL },
+  { "s",   1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-wp",       "cR", NULL },
+  { "p",   1, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "c",  NULL },
+  { "n",   1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  BADLEN,  BADLEN, BADLEN,  T99_IM,  BADLEN,  BADLEN,  BADLEN }, "",          "W",  NULL },
+  /* X/Open conversion specifiers.  */
+  { "C",   0, STD_EXT, { TEX_WI,  BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "",   NULL },
+  { "S",   1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-wp",       "R",  NULL },
+  { NULL,  0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+static const format_char_info ms_scan_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "di",    1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  T99_SST,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w'", "W",   NULL },
+  { "u",     1, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN,  BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "*w'", "W",   NULL },
+  { "oxX",   1, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN,  BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "efgEG", 1, STD_C89, { T89_F,   BADLEN,  BADLEN,  T89_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "*w'",  "W",   NULL },
+  { "c",     1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "cW",  NULL },
+  { "s",     1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "cW",  NULL },
+  { "[",     1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "cW[", NULL },
+  { "p",     2, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "n",     1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  BADLEN,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "",     "W",   NULL },
+  /* X/Open conversion specifiers.  */
+  { "C",     1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "S",     1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "W",   NULL },
+  { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+static const format_char_info ms_time_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "ABZab",		0, STD_C89, NOLENGTHS, "#",     "",   NULL },
+  { "cx",		0, STD_C89, NOLENGTHS, "#",      "3",  NULL },
+  { "HIMSUWdmw",	0, STD_C89, NOLENGTHS, "#w",  "",   NULL },
+  { "j",		0, STD_C89, NOLENGTHS, "#w",  "",  NULL },
+  { "p",		0, STD_C89, NOLENGTHS, "#",      "",   NULL },
+  { "X",		0, STD_C89, NOLENGTHS, "#",      "",   NULL },
+  { "y",		0, STD_C89, NOLENGTHS, "#w", "4",  NULL },
+  { "Y",		0, STD_C89, NOLENGTHS, "#w", "",  NULL },
+  { "%",		0, STD_C89, NOLENGTHS, "",       "",   NULL },
+  /* C99 conversion specifiers.  */
+  { "z",		0, STD_C99, NOLENGTHS, "#",      "",  NULL },
+  { NULL,		0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+const format_kind_info mingw_format_attributes[3] =
+{
+  { "ms_printf",   ms_printf_length_specs,  ms_print_char_table, " +#0-'", NULL,
+    ms_printf_flag_specs, ms_printf_flag_pairs,
+    FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
+    'w', 0, 'p', 0, 'L', 0,
+    &integer_type_node, &integer_type_node
+  },
+  { "ms_scanf",    ms_printf_length_specs,   ms_scan_char_table,  "*'", NULL,
+    ms_scanf_flag_specs, ms_scanf_flag_pairs,
+    FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
+    'w', 0, 0, '*', 'L', 0,
+    NULL, NULL
+  },
+  { "ms_strftime", NULL,                 ms_time_char_table,  "", "#",
+    ms_strftime_flag_specs, ms_strftime_flag_pairs,
+    FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0, 0,
+    NULL, NULL
+  }
+};
+
+/* Default overrides for printf, scanf and strftime.  */
+const target_ovr_attr mingw_format_attribute_overrides[4] =
+{
+  { "ms_printf", "printf" },
+  { "ms_scanf", "scanf" },
+  { "ms_strftime", "strftime" }
+};
Index: gcc/gcc/config/i386/t-cygming
===================================================================
--- gcc.orig/gcc/config/i386/t-cygming
+++ gcc/gcc/config/i386/t-cygming
@@ -29,4 +29,10 @@ winnt-stubs.o: $(srcdir)/config/i386/win
 	$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
 	$(srcdir)/config/i386/winnt-stubs.c
 
+msformat-c.o: $(srcdir)/config/i386/msformat-c.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
+  $(TM_H) $(RTL_H) $(REGS_H) hard-reg-set.h output.h $(TREE_H) flags.h \
+  $(TM_P_H) toplev.h $(HASHTAB_H) $(GGC_H)
+	$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
+	$(srcdir)/config/i386/msformat-c.c
+
 STMP_FIXINC=stmp-fixinc
Index: gcc/gcc/doc/extend.texi
===================================================================
--- gcc.orig/gcc/doc/extend.texi
+++ gcc/gcc/doc/extend.texi
@@ -2204,13 +2204,22 @@ for consistency with the @code{printf} s
 @code{my_format}.
 
 The parameter @var{archetype} determines how the format string is
-interpreted, and should be @code{printf}, @code{scanf}, @code{strftime}
-or @code{strfmon}.  (You can also use @code{__printf__},
-@code{__scanf__}, @code{__strftime__} or @code{__strfmon__}.)  The
-parameter @var{string-index} specifies which argument is the format
-string argument (starting from 1), while @var{first-to-check} is the
-number of the first argument to check against the format string.  For
-functions where the arguments are not available to be checked (such as
+interpreted, and should be @code{printf}, @code{scanf}, @code{strftime},
+@code{gnu_printf}, @code{gnu_scanf}, @code{gnu_strftime} or
+@code{strfmon}.  (You can also use @code{__printf__},
+@code{__scanf__}, @code{__strftime__} or @code{__strfmon__}.)  On
+MinGW targets, @code{ms_printf}, @code{ms_scanf}, and
+@code{ms_strftime} are also present.
+@var{archtype} values such as @code{printf} refer to the formats accepted
+by the system's C run-time library, while @code{gnu_} values always refer
+to the formats accepted by the GNU C Library.  On Microsoft Windows
+targets, @code{ms_} values refer to the formats accepted by the
+@file{msvcrt.dll} library.
+The parameter @var{string-index}
+specifies which argument is the format string argument (starting
+from 1), while @var{first-to-check} is the number of the first
+argument to check against the format string.  For functions
+where the arguments are not available to be checked (such as
 @code{vprintf}), specify the third parameter as zero.  In this case the
 compiler only checks the format string for consistency.  For
 @code{strftime} formats, the third parameter is required to be zero.
Index: gcc/gcc/doc/tm.texi
===================================================================
--- gcc.orig/gcc/doc/tm.texi
+++ gcc/gcc/doc/tm.texi
@@ -10319,6 +10319,18 @@ If defined, this macro is the number of 
 @code{TARGET_FORMAT_TYPES}.
 @end defmac
 
+@defmac TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+If defined, this macro is the name of a global variable containing
+target-specific format overrides for the @option{-Wformat} option. The
+default is to have no target-specific format overrides. If defined,
+@code{TARGET_FORMAT_TYPES} must be defined, too.
+@end defmac
+
+@defmac TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT
+If defined, this macro specifies the number of entries in
+@code{TARGET_OVERRIDES_FORMAT_ATTRIBUTES}.
+@end defmac
+
 @deftypefn {Target Hook} bool TARGET_RELAXED_ORDERING
 If set to @code{true}, means that the target's memory model does not
 guarantee that loads which do not depend on one another will access
Index: gcc/gcc/testsuite/gcc.dg/format/format.h
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/format.h
+++ gcc/gcc/testsuite/gcc.dg/format/format.h
@@ -1,6 +1,37 @@
 /* Format checking tests: common header.  */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
 
+/* DONT_GNU_PROTOTYPE */
+#if defined (_WIN32) && !defined (__CYGWIN__)
+#if !defined (USE_SYSTEM_FORMATS)
+#define gnu_attr_printf	gnu_printf
+#define gnu_attr___printf__ __gnu_printf__
+#define gnu_attr_scanf	gnu_scanf
+#define gnu_attr___scanf__ __gnu_scanf__
+#define gnu_attr_strftime gnu_strftime
+#define gnu_attr___strftime__ __gnu_strftime__
+#endif
+#endif
+
+#ifndef gnu_attr_printf
+#define gnu_attr_printf	printf
+#define gnu_attr___printf__ __printf__
+#define gnu_attr_scanf	scanf
+#define gnu_attr___scanf__ __scanf__
+#define gnu_attr_strftime strftime
+#define gnu_attr___strftime__ __strftime__
+#endif
+
+#if !defined (USE_SYSTEM_FORMATS)
+#define USE_PRINTF(FMTPOS, WILDARG) __attribute__((format(gnu_printf, FMTPOS, WILDARG))) __attribute__((nonnull (FMTPOS)))
+#define USE_SCANF(FMTPOS, WILDARG) __attribute__((format(gnu_scanf, FMTPOS, WILDARG))) __attribute__((nonnull (FMTPOS)))
+#define USE_STRFTIME(FMTPOS) __attribute__((__format__(gnu_strftime, FMTPOS, 0))) __attribute__((nonnull (FMTPOS)))
+#else
+#define USE_PRINTF(FMTPOS, WILDARG)
+#define USE_SCANF(FMTPOS, WILDARG)
+#define USE_STRFTIME(FMTPOS)
+#endif
+
 #include <stdarg.h>
 #include <stddef.h>
 
@@ -11,6 +42,20 @@
 typedef __WINT_TYPE__ wint_t;
 #endif
 
+#ifdef _WIN64
+/* Kludges to get types corresponding to size_t and ptrdiff_t.  */
+#define unsigned signed
+typedef signed int signed_size_t __attribute__ ((mode (DI)));
+/* We also use this type to approximate ssize_t.  */
+typedef signed int ssize_t __attribute__ ((mode (DI)));
+#undef unsigned
+#define signed /* Type might or might not have explicit 'signed'.  */
+typedef unsigned int unsigned_ptrdiff_t __attribute__ ((mode (DI)));
+#undef signed
+
+__extension__ typedef int llong  __attribute__ ((mode (DI)));
+__extension__ typedef unsigned int ullong  __attribute__ ((mode (DI)));
+#else
 /* Kludges to get types corresponding to size_t and ptrdiff_t.  */
 #define unsigned signed
 typedef __SIZE_TYPE__ signed_size_t;
@@ -23,6 +68,7 @@ typedef unsigned __PTRDIFF_TYPE__ unsign
 
 __extension__ typedef long long int llong;
 __extension__ typedef unsigned long long int ullong;
+#endif
 
 /* %q formats want a "quad"; GCC considers this to be a long long.  */
 typedef llong quad_t;
@@ -70,3 +116,77 @@ extern size_t strftime (char *restrict, 
 			const struct tm *restrict);
 
 extern ssize_t strfmon (char *restrict, size_t, const char *restrict, ...);
+
+/* Mingw specific part.  */
+#if !defined (USE_SYSTEM_FORMATS) && defined(_WIN32) && !defined(DONT_GNU_PROTOTYPE)
+
+extern USE_PRINTF(2,3) int fprintf_gnu (FILE *restrict, const char *restrict, ...);
+#undef fprintf
+#define fprintf fprintf_gnu
+
+extern USE_PRINTF(1,2) int printf_gnu (const char *restrict, ...);
+#undef printf
+#define printf printf_gnu
+
+extern USE_PRINTF(2,3) int fprintf_unlocked_gnu (FILE *restrict, const char *restrict, ...);
+#undef fprintf_unlocked
+#define fprintf_unlocked fprintf_unlocked_gnu
+
+extern USE_PRINTF(1,2)int printf_unlocked_gnu (const char *restrict, ...);
+#undef printf_unlocked
+#define printf_unlocked printf_unlocked_gnu
+
+extern USE_PRINTF(2,3) int sprintf_gnu (char *restrict, const char *restrict, ...);
+#undef sprintf
+#define sprintf sprintf_gnu
+
+extern USE_PRINTF(2,0) int vfprintf_gnu (FILE *restrict, const char *restrict, va_list);
+#undef vsprintf
+#define vsprintf vsprintf_gnu
+
+extern USE_PRINTF(1,0) int vprintf_gnu (const char *restrict, va_list);
+#undef vprintf
+#define vprintf vprintf_gnu
+
+extern USE_PRINTF(2,0) int vsprintf_gnu (char *restrict, const char *restrict, va_list);
+#undef vsprintf
+#define vsprintf vsprintf_gnu
+
+extern USE_PRINTF(3,4) int snprintf_gnu (char *restrict, size_t, const char *restrict, ...);
+#undef snprintf
+#define snprintf snprintf_gnu
+
+extern USE_PRINTF(3,0) int vsnprintf_gnu (char *restrict, size_t, const char *restrict, va_list);
+#undef vsnprintf
+#define vsnprintf vsnprintf_gnu
+
+extern USE_SCANF(2,3) int fscanf_gnu (FILE *restrict, const char *restrict, ...);
+#undef fscanf
+#define fscanf fscanf_gnu
+
+extern USE_SCANF(1,2) int scanf_gnu (const char *restrict, ...);
+#undef scanf
+#define scanf scanf_gnu
+
+extern USE_SCANF(2,3) int sscanf_gnu (const char *restrict, const char *restrict, ...);
+#undef sscanf
+#define sscanf sscanf_gnu
+
+extern USE_SCANF(2,0) int vfscanf_gnu (FILE *restrict, const char *restrict, va_list);
+#undef vfscanf
+#define vfscanf vfscanf_gnu
+
+extern USE_SCANF(1,0) int vscanf_gnu (const char *restrict, va_list);
+#undef vscanf
+#define vscanf vscanf_gnu
+
+extern USE_SCANF(2,0) int vsscanf_gnu (const char *restrict, const char *restrict, va_list);
+#undef vsscanf
+#define vsscanf vsscanf_gnu
+
+extern USE_STRFTIME(3) size_t strftime_gnu (char *restrict, size_t, const char *restrict,
+			const struct tm *restrict);
+#undef strftime
+#define strftime strftime_gnu
+
+#endif
Index: gcc/gcc/testsuite/gcc.dg/format/attr-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-1.c
@@ -3,7 +3,8 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern void foo0 (const char *) __attribute__((__format__(__strftime__, 1, 0)));
-extern void foo1 (const char *, ...) __attribute__((__format__(__strftime__, 1, 2))); /* { dg-error "cannot format" "strftime first_arg_num != 0" } */
+extern void foo0 (const char *) __attribute__((__format__(gnu_attr___strftime__, 1, 0)));
+extern void foo1 (const char *, ...) __attribute__((__format__(gnu_attr___strftime__, 1, 2))); /* { dg-error "cannot format" "strftime first_arg_num != 0" } */
Index: gcc/gcc/testsuite/gcc.dg/format/attr-2.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-2.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-2.c
@@ -3,22 +3,23 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern void tformatprintf (const char *, ...) __attribute__((format(printf, 1, 2)));
-extern void tformat__printf__ (const char *, ...) __attribute__((format(__printf__, 1, 2)));
-extern void tformatscanf (const char *, ...) __attribute__((format(scanf, 1, 2)));
-extern void tformat__scanf__ (const char *, ...) __attribute__((format(__scanf__, 1, 2)));
-extern void tformatstrftime (const char *) __attribute__((format(strftime, 1, 0)));
-extern void tformat__strftime__ (const char *) __attribute__((format(__strftime__, 1, 0)));
+extern void tformatprintf (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
+extern void tformat__printf__ (const char *, ...) __attribute__((format(gnu_attr___printf__, 1, 2)));
+extern void tformatscanf (const char *, ...) __attribute__((format(gnu_attr_scanf, 1, 2)));
+extern void tformat__scanf__ (const char *, ...) __attribute__((format(gnu_attr___scanf__, 1, 2)));
+extern void tformatstrftime (const char *) __attribute__((format(gnu_attr_strftime, 1, 0)));
+extern void tformat__strftime__ (const char *) __attribute__((format(gnu_attr___strftime__, 1, 0)));
 extern void tformatstrfmon (const char *, ...) __attribute__((format(strfmon, 1, 2)));
 extern void tformat__strfmon__ (const char *, ...) __attribute__((format(__strfmon__, 1, 2)));
-extern void t__format__printf (const char *, ...) __attribute__((__format__(printf, 1, 2)));
-extern void t__format____printf__ (const char *, ...) __attribute__((__format__(__printf__, 1, 2)));
-extern void t__format__scanf (const char *, ...) __attribute__((__format__(scanf, 1, 2)));
-extern void t__format____scanf__ (const char *, ...) __attribute__((__format__(__scanf__, 1, 2)));
-extern void t__format__strftime (const char *) __attribute__((__format__(strftime, 1, 0)));
-extern void t__format____strftime__ (const char *) __attribute__((__format__(__strftime__, 1, 0)));
+extern void t__format__printf (const char *, ...) __attribute__((__format__(gnu_attr_printf, 1, 2)));
+extern void t__format____printf__ (const char *, ...) __attribute__((__format__(gnu_attr___printf__, 1, 2)));
+extern void t__format__scanf (const char *, ...) __attribute__((__format__(gnu_attr_scanf, 1, 2)));
+extern void t__format____scanf__ (const char *, ...) __attribute__((__format__(gnu_attr___scanf__, 1, 2)));
+extern void t__format__strftime (const char *) __attribute__((__format__(gnu_attr_strftime, 1, 0)));
+extern void t__format____strftime__ (const char *) __attribute__((__format__(gnu_attr___strftime__, 1, 0)));
 extern void t__format__strfmon (const char *, ...) __attribute__((__format__(strfmon, 1, 2)));
 extern void t__format____strfmon__ (const char *, ...) __attribute__((__format__(__strfmon__, 1, 2)));
 
Index: gcc/gcc/testsuite/gcc.dg/format/attr-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-3.c
@@ -3,20 +3,21 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 /* Proper uses of the attributes.  */
-extern void fa0 (const char *, ...) __attribute__((format(printf, 1, 2)));
-extern void fa1 (char *, ...) __attribute__((format(printf, 1, 2)));
+extern void fa0 (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
+extern void fa1 (char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
 extern char *fa2 (const char *) __attribute__((format_arg(1)));
 extern char *fa3 (char *) __attribute__((format_arg(1)));
 
 /* Uses with too few or too many arguments.  */
 extern void fb0 (const char *, ...) __attribute__((format)); /* { dg-error "wrong number of arguments" "bad format" } */
 extern void fb1 (const char *, ...) __attribute__((format())); /* { dg-error "wrong number of arguments" "bad format" } */
-extern void fb2 (const char *, ...) __attribute__((format(printf))); /* { dg-error "wrong number of arguments" "bad format" } */
-extern void fb3 (const char *, ...) __attribute__((format(printf, 1))); /* { dg-error "wrong number of arguments" "bad format" } */
-extern void fb4 (const char *, ...) __attribute__((format(printf, 1, 2, 3))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb2 (const char *, ...) __attribute__((format(gnu_attr_printf))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb3 (const char *, ...) __attribute__((format(gnu_attr_printf, 1))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb4 (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2, 3))); /* { dg-error "wrong number of arguments" "bad format" } */
 
 extern void fc1 (const char *) __attribute__((format_arg)); /* { dg-error "wrong number of arguments" "bad format_arg" } */
 extern void fc2 (const char *) __attribute__((format_arg())); /* { dg-error "wrong number of arguments" "bad format_arg" } */
@@ -25,9 +26,9 @@ extern void fc3 (const char *) __attribu
 /* These attributes presently only apply to declarations, not to types.
    Eventually, they should be usable with declarators for function types
    anywhere, but still not with structure/union/enum types.  */
-struct s0 { int i; } __attribute__((format(printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on struct" } */
-union u0 { int i; } __attribute__((format(printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on union" } */
-enum e0 { E0V0 } __attribute__((format(printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on enum" } */
+struct s0 { int i; } __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on struct" } */
+union u0 { int i; } __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on union" } */
+enum e0 { E0V0 } __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on enum" } */
 
 struct s1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on struct" } */
 union u1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on union" } */
@@ -38,28 +39,28 @@ extern void fe0 (const char *, ...) __at
 extern void fe1 (const char *, ...) __attribute__((format(nosuch, 1, 2))); /* { dg-warning "format function type" "unknown format" } */
 
 /* Both the numbers must be integer constant expressions.  */
-extern void ff0 (const char *, ...) __attribute__((format(printf, 3-2, (long long)(10/5))));
+extern void ff0 (const char *, ...) __attribute__((format(gnu_attr_printf, 3-2, (long long)(10/5))));
 int foo;
-extern void ff1 (const char *, ...) __attribute__((format(printf, foo, 10/5))); /* { dg-error "invalid operand" "bad number" } */
-extern void ff2 (const char *, ...) __attribute__((format(printf, 3-2, foo))); /* { dg-error "invalid operand" "bad number" } */
+extern void ff1 (const char *, ...) __attribute__((format(gnu_attr_printf, foo, 10/5))); /* { dg-error "invalid operand" "bad number" } */
+extern void ff2 (const char *, ...) __attribute__((format(gnu_attr_printf, 3-2, foo))); /* { dg-error "invalid operand" "bad number" } */
 extern char *ff3 (const char *) __attribute__((format_arg(3-2)));
 extern char *ff4 (const char *) __attribute__((format_arg(foo))); /* { dg-error "invalid operand" "bad format_arg number" } */
 
 /* The format string argument must precede the arguments to be formatted.
    This includes if no parameter types are specified (which is not valid ISO
    C for variadic functions).  */
-extern void fg0 () __attribute__((format(printf, 1, 2)));
-extern void fg1 () __attribute__((format(printf, 1, 0)));
-extern void fg2 () __attribute__((format(printf, 1, 1))); /* { dg-error "follows" "bad number order" } */
-extern void fg3 () __attribute__((format(printf, 2, 1))); /* { dg-error "follows" "bad number order" } */
+extern void fg0 () __attribute__((format(gnu_attr_printf, 1, 2)));
+extern void fg1 () __attribute__((format(gnu_attr_printf, 1, 0)));
+extern void fg2 () __attribute__((format(gnu_attr_printf, 1, 1))); /* { dg-error "follows" "bad number order" } */
+extern void fg3 () __attribute__((format(gnu_attr_printf, 2, 1))); /* { dg-error "follows" "bad number order" } */
 
 /* The format string argument must be a string type, and the arguments to
    be formatted must be the "...".  */
-extern void fh0 (int, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "not a string" "format int string" } */
-extern void fh1 (signed char *, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "not a string" "signed char string" } */
-extern void fh2 (unsigned char *, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "not a string" "unsigned char string" } */
-extern void fh3 (const char *, ...) __attribute__((format(printf, 1, 3))); /* { dg-error "is not" "not ..." } */
-extern void fh4 (const char *, int, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "is not" "not ..." } */
+extern void fh0 (int, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "format int string" } */
+extern void fh1 (signed char *, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "signed char string" } */
+extern void fh2 (unsigned char *, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "unsigned char string" } */
+extern void fh3 (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 3))); /* { dg-error "is not" "not ..." } */
+extern void fh4 (const char *, int, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "is not" "not ..." } */
 
 /* format_arg formats must take and return a string.  */
 extern char *fi0 (int) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg int string" } */
Index: gcc/gcc/testsuite/gcc.dg/format/attr-4.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-4.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-4.c
@@ -4,12 +4,13 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern __attribute__((format(printf, 1, 2))) void tformatprintf0 (const char *, ...);
-extern void __attribute__((format(printf, 1, 2))) tformatprintf1 (const char *, ...);
-extern void foo (void), __attribute__((format(printf, 1, 2))) tformatprintf2 (const char *, ...);
-extern __attribute__((noreturn)) void bar (void), __attribute__((format(printf, 1, 2))) tformatprintf3 (const char *, ...);
+extern __attribute__((format(gnu_attr_printf, 1, 2))) void tformatprintf0 (const char *, ...);
+extern void __attribute__((format(gnu_attr_printf, 1, 2))) tformatprintf1 (const char *, ...);
+extern void foo (void), __attribute__((format(gnu_attr_printf, 1, 2))) tformatprintf2 (const char *, ...);
+extern __attribute__((noreturn)) void bar (void), __attribute__((format(gnu_attr_printf, 1, 2))) tformatprintf3 (const char *, ...);
 
 void
 baz (int i, int *ip, double d)
Index: gcc/gcc/testsuite/gcc.dg/format/attr-7.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-7.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-7.c
@@ -3,12 +3,13 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-__attribute__((format(printf, 1, 2))) void (*tformatprintf0) (const char *, ...);
-void (*tformatprintf1) (const char *, ...) __attribute__((format(printf, 1, 2)));
-void (__attribute__((format(printf, 1, 2))) *tformatprintf2) (const char *, ...);
-void (__attribute__((format(printf, 1, 2))) ****tformatprintf3) (const char *, ...);
+__attribute__((format(gnu_attr_printf, 1, 2))) void (*tformatprintf0) (const char *, ...);
+void (*tformatprintf1) (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
+void (__attribute__((format(gnu_attr_printf, 1, 2))) *tformatprintf2) (const char *, ...);
+void (__attribute__((format(gnu_attr_printf, 1, 2))) ****tformatprintf3) (const char *, ...);
 
 char * (__attribute__((format_arg(1))) *tformat_arg) (const char *);
 
Index: gcc/gcc/testsuite/gcc.dg/format/c90-printf-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/c90-printf-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/c90-printf-3.c
@@ -3,7 +3,7 @@
    do not.
 */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
-/* { dg-do compile } */
+/* { dg-do compile { target { ! *-*-mingw* } } } */
 /* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
 
 #include "format.h"
Index: gcc/gcc/testsuite/gcc.dg/format/c90-scanf-4.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/c90-scanf-4.c
+++ gcc/gcc/testsuite/gcc.dg/format/c90-scanf-4.c
@@ -3,7 +3,7 @@
    do not.
 */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
-/* { dg-do compile } */
+/* { dg-do compile { target { ! *-*-mingw* } } } */
 /* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
 
 #include "format.h"
Index: gcc/gcc/testsuite/gcc.dg/format/c99-printf-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/c99-printf-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/c99-printf-3.c
@@ -2,7 +2,7 @@
    attributes in strict C99 mode, but the gettext functions do not.
 */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
-/* { dg-do compile } */
+/* { dg-do compile { target { ! *-*-mingw* } } } */
 /* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
 
 #include "format.h"
Index: gcc/gcc/testsuite/gcc.dg/format/miss-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-1.c
@@ -23,7 +23,7 @@ bar (const char *fmt, ...)
   va_end (ap);
 }
 
-__attribute__((__format__(__printf__, 1, 2))) void
+__attribute__((__format__(gnu_attr___printf__, 1, 2))) void
 foo2 (const char *fmt, ...)
 {
   va_list ap;
Index: gcc/gcc/testsuite/gcc.dg/format/miss-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-3.c
@@ -3,13 +3,14 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 void
 foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
@@ -18,7 +19,7 @@ foo1 (noattr_t na, attr_t a, vnoattr_t v
   noattr_t na2 = a; /* { dg-warning "candidate" "initialization warning" } */
   attr_t a1 = na;
   attr_t a2 = a;
-  
+
   vnoattr_t vna1 = vna;
   vnoattr_t vna2 = va; /* { dg-warning "candidate" "initialization warning" } */
   vattr_t va1 = vna;
Index: gcc/gcc/testsuite/gcc.dg/format/miss-4.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-4.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-4.c
@@ -3,20 +3,21 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 void
 foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
 {
   noattr_t na1, na2;
   attr_t a1, a2;
-  
+
   vnoattr_t vna1, vna2;
   vattr_t va1, va2;
 
@@ -24,7 +25,7 @@ foo1 (noattr_t na, attr_t a, vnoattr_t v
   na2 = a; /* { dg-warning "candidate" "assignment warning" } */
   a1 = na;
   a2 = a;
-  
+
   vna1 = vna;
   vna2 = va; /* { dg-warning "candidate" "assignment warning" } */
   va1 = vna;
Index: gcc/gcc/testsuite/gcc.dg/format/miss-5.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-5.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-5.c
@@ -3,13 +3,14 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 noattr_t
 foo1 (noattr_t na, attr_t a, int i)
Index: gcc/gcc/testsuite/gcc.dg/format/miss-6.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-6.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-6.c
@@ -3,13 +3,14 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 extern void foo1 (noattr_t);
 extern void foo2 (attr_t);
@@ -23,7 +24,7 @@ foo (noattr_t na, attr_t a, vnoattr_t vn
   foo1 (a); /* { dg-warning "candidate" "parameter passing warning" } */
   foo2 (na);
   foo2 (a);
-  
+
   foo3 (vna);
   foo3 (va); /* { dg-warning "candidate" "parameter passing warning" } */
   foo4 (vna);
Index: gcc/gcc/testsuite/gcc.dg/format/ms_array-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_array-1.c
@@ -0,0 +1,42 @@
+/* Test for format checking of constant arrays.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat=2" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+const char a1[] = "foo";
+const char a2[] = "foo%d";
+const char b1[3] = "foo";
+const char b2[1] = "1";
+static const char c1[] = "foo";
+static const char c2[] = "foo%d";
+char d[] = "foo";
+volatile const char e[] = "foo";
+
+void
+foo (int i, long l)
+{
+  const char p1[] = "bar";
+  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 (c1);
+  printf (c2, i);
+  printf (c2, l); /* { dg-warning "format" "wrong type with array" } */
+  printf (p1);
+  printf (p2, i);
+  printf (p2, l); /* { dg-warning "format" "wrong type with array" } */
+  printf (q1);
+  printf (q2, i);
+  printf (q2, l); /* { dg-warning "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" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-1.c
@@ -0,0 +1,10 @@
+/* Test for strftime format attributes: can't have first_arg_num != 0.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define DONT_GNU_PROTOTYPE
+#include "format.h"
+
+extern void foo0 (const char *) __attribute__((__format__(__ms_strftime__, 1, 0)));
+extern void foo1 (const char *, ...) __attribute__((__format__(__ms_strftime__, 1, 2))); /* { dg-error "cannot format" "strftime first_arg_num != 0" } */
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-2.c
@@ -0,0 +1,68 @@
+/* Test for format attributes: test use of __attribute__.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define DONT_GNU_PROTOTYPE
+#include "format.h"
+
+extern void tformatprintf (const char *, ...) __attribute__((format(ms_printf, 1, 2)));
+extern void tformat__printf__ (const char *, ...) __attribute__((format(__ms_printf__, 1, 2)));
+extern void tformatscanf (const char *, ...) __attribute__((format(ms_scanf, 1, 2)));
+extern void tformat__scanf__ (const char *, ...) __attribute__((format(__ms_scanf__, 1, 2)));
+extern void tformatstrftime (const char *) __attribute__((format(ms_strftime, 1, 0)));
+extern void tformat__strftime__ (const char *) __attribute__((format(__ms_strftime__, 1, 0)));
+extern void tformatstrfmon (const char *, ...) __attribute__((format(strfmon, 1, 2)));
+extern void tformat__strfmon__ (const char *, ...) __attribute__((format(__strfmon__, 1, 2)));
+extern void t__format__printf (const char *, ...) __attribute__((__format__(ms_printf, 1, 2)));
+extern void t__format____printf__ (const char *, ...) __attribute__((__format__(__ms_printf__, 1, 2)));
+extern void t__format__scanf (const char *, ...) __attribute__((__format__(ms_scanf, 1, 2)));
+extern void t__format____scanf__ (const char *, ...) __attribute__((__format__(__ms_scanf__, 1, 2)));
+extern void t__format__strftime (const char *) __attribute__((__format__(ms_strftime, 1, 0)));
+extern void t__format____strftime__ (const char *) __attribute__((__format__(__ms_strftime__, 1, 0)));
+extern void t__format__strfmon (const char *, ...) __attribute__((__format__(strfmon, 1, 2)));
+extern void t__format____strfmon__ (const char *, ...) __attribute__((__format__(__strfmon__, 1, 2)));
+
+extern char *tformat_arg (const char *) __attribute__((format_arg(1)));
+extern char *t__format_arg__ (const char *) __attribute__((__format_arg__(1)));
+
+void
+foo (int i, int *ip, double d)
+{
+  tformatprintf ("%d", i);
+  tformatprintf ("%"); /* { dg-warning "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);
+  tformat__scanf__ ("%"); /* { dg-warning "format" "attribute format __scanf__" } */
+  tformatstrftime ("%a");
+  tformatstrftime ("%"); /* { dg-warning "format" "attribute format strftime" } */
+  tformat__strftime__ ("%a");
+  tformat__strftime__ ("%"); /* { dg-warning "format" "attribute format __strftime__" } */
+  tformatstrfmon ("%n", d);
+  tformatstrfmon ("%"); /* { dg-warning "format" "attribute format strfmon" } */
+  tformat__strfmon__ ("%n", d);
+  tformat__strfmon__ ("%"); /* { dg-warning "format" "attribute format __strfmon__" } */
+  t__format__printf ("%d", i);
+  t__format__printf ("%"); /* { dg-warning "format" "attribute __format__ printf" } */
+  t__format____printf__ ("%d", i);
+  t__format____printf__ ("%"); /* { dg-warning "format" "attribute __format__ __printf__" } */
+  t__format__scanf ("%d", ip);
+  t__format__scanf ("%"); /* { dg-warning "format" "attribute __format__ scanf" } */
+  t__format____scanf__ ("%d", ip);
+  t__format____scanf__ ("%"); /* { dg-warning "format" "attribute __format__ __scanf__" } */
+  t__format__strftime ("%a");
+  t__format__strftime ("%"); /* { dg-warning "format" "attribute __format__ strftime" } */
+  t__format____strftime__ ("%a");
+  t__format____strftime__ ("%"); /* { dg-warning "format" "attribute __format__ __strftime__" } */
+  t__format__strfmon ("%n", d);
+  t__format__strfmon ("%"); /* { dg-warning "format" "attribute __format__ strfmon" } */
+  t__format____strfmon__ ("%n", d);
+  t__format____strfmon__ ("%"); /* { dg-warning "format" "attribute __format__ __strfmon__" } */
+  tformatprintf (tformat_arg ("%d"), i);
+  tformatprintf (tformat_arg ("%")); /* { dg-warning "format" "attribute format_arg" } */
+  tformatprintf (t__format_arg__ ("%d"), i);
+  tformatprintf (t__format_arg__ ("%")); /* { dg-warning "format" "attribute __format_arg__" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-3.c
@@ -0,0 +1,71 @@
+/* Test for format attributes: test bad uses of __attribute__.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* Proper uses of the attributes.  */
+extern void fa0 (const char *, ...) __attribute__((format(ms_printf, 1, 2)));
+extern void fa1 (char *, ...) __attribute__((format(ms_printf, 1, 2)));
+extern char *fa2 (const char *) __attribute__((format_arg(1)));
+extern char *fa3 (char *) __attribute__((format_arg(1)));
+
+/* Uses with too few or too many arguments.  */
+extern void fb0 (const char *, ...) __attribute__((format)); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb1 (const char *, ...) __attribute__((format())); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb2 (const char *, ...) __attribute__((format(ms_printf))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb3 (const char *, ...) __attribute__((format(ms_printf, 1))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb4 (const char *, ...) __attribute__((format(ms_printf, 1, 2, 3))); /* { dg-error "wrong number of arguments" "bad format" } */
+
+extern void fc1 (const char *) __attribute__((format_arg)); /* { dg-error "wrong number of arguments" "bad format_arg" } */
+extern void fc2 (const char *) __attribute__((format_arg())); /* { dg-error "wrong number of arguments" "bad format_arg" } */
+extern void fc3 (const char *) __attribute__((format_arg(1, 2))); /* { dg-error "wrong number of arguments" "bad format_arg" } */
+
+/* These attributes presently only apply to declarations, not to types.
+   Eventually, they should be usable with declarators for function types
+   anywhere, but still not with structure/union/enum types.  */
+struct s0 { int i; } __attribute__((format(ms_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on struct" } */
+union u0 { int i; } __attribute__((format(ms_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on union" } */
+enum e0 { E0V0 } __attribute__((format(ms_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on enum" } */
+
+struct s1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on struct" } */
+union u1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on union" } */
+enum e1 { E1V0 } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on enum" } */
+
+/* The format type must be an identifier, one of those recognized.  */
+extern void fe0 (const char *, ...) __attribute__((format(12345, 1, 2))); /* { dg-error "format specifier" "non-id format" } */
+extern void fe1 (const char *, ...) __attribute__((format(nosuch, 1, 2))); /* { dg-warning "format function type" "unknown format" } */
+
+/* Both the numbers must be integer constant expressions.  */
+extern void ff0 (const char *, ...) __attribute__((format(ms_printf, 3-2, (long long)(10/5))));
+int foo;
+extern void ff1 (const char *, ...) __attribute__((format(ms_printf, foo, 10/5))); /* { dg-error "invalid operand" "bad number" } */
+extern void ff2 (const char *, ...) __attribute__((format(ms_printf, 3-2, foo))); /* { dg-error "invalid operand" "bad number" } */
+extern char *ff3 (const char *) __attribute__((format_arg(3-2)));
+extern char *ff4 (const char *) __attribute__((format_arg(foo))); /* { dg-error "invalid operand" "bad format_arg number" } */
+
+/* The format string argument must precede the arguments to be formatted.
+   This includes if no parameter types are specified (which is not valid ISO
+   C for variadic functions).  */
+extern void fg0 () __attribute__((format(ms_printf, 1, 2)));
+extern void fg1 () __attribute__((format(ms_printf, 1, 0)));
+extern void fg2 () __attribute__((format(ms_printf, 1, 1))); /* { dg-error "follows" "bad number order" } */
+extern void fg3 () __attribute__((format(ms_printf, 2, 1))); /* { dg-error "follows" "bad number order" } */
+
+/* The format string argument must be a string type, and the arguments to
+   be formatted must be the "...".  */
+extern void fh0 (int, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "not a string" "format int string" } */
+extern void fh1 (signed char *, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "not a string" "signed char string" } */
+extern void fh2 (unsigned char *, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "not a string" "unsigned char string" } */
+extern void fh3 (const char *, ...) __attribute__((format(ms_printf, 1, 3))); /* { dg-error "is not" "not ..." } */
+extern void fh4 (const char *, int, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "is not" "not ..." } */
+
+/* format_arg formats must take and return a string.  */
+extern char *fi0 (int) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg int string" } */
+extern char *fi1 (signed char *) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg signed char string" } */
+extern char *fi2 (unsigned char *) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg unsigned char string" } */
+extern int fi3 (const char *) __attribute__((format_arg(1))); /* { dg-error "not return string" "format_arg ret int string" } */
+extern signed char *fi4 (const char *) __attribute__((format_arg(1))); /* { dg-error "not return string" "format_arg ret signed char string" } */
+extern unsigned char *fi5 (const char *) __attribute__((format_arg(1))); /* { dg-error "not return string" "format_arg ret unsigned char string" } */
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-4.c
@@ -0,0 +1,26 @@
+/* Test for format attributes: test use of __attribute__
+   in prefix attributes.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+extern __attribute__((format(ms_printf, 1, 2))) void tformatprintf0 (const char *, ...);
+extern void __attribute__((format(ms_printf, 1, 2))) tformatprintf1 (const char *, ...);
+extern void foo (void), __attribute__((format(ms_printf, 1, 2))) tformatprintf2 (const char *, ...);
+extern __attribute__((noreturn)) void bar (void), __attribute__((format(ms_printf, 1, 2))) tformatprintf3 (const char *, ...);
+
+void
+baz (int i, int *ip, double d)
+{
+  tformatprintf0 ("%d", i);
+  tformatprintf0 ("%"); /* { dg-warning "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);
+  tformatprintf3 ("%"); /* { dg-warning "format" "attribute format printf case 3" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-7.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-7.c
@@ -0,0 +1,35 @@
+/* Test for format attributes: test applying them to types.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define DONT_GNU_PROTOTYPE
+#include "format.h"
+
+__attribute__((format(ms_printf, 1, 2))) void (*tformatprintf0) (const char *, ...);
+void (*tformatprintf1) (const char *, ...) __attribute__((format(ms_printf, 1, 2)));
+void (__attribute__((format(ms_printf, 1, 2))) *tformatprintf2) (const char *, ...);
+void (__attribute__((format(ms_printf, 1, 2))) ****tformatprintf3) (const char *, ...);
+
+char * (__attribute__((format_arg(1))) *tformat_arg) (const char *);
+
+void
+baz (int i)
+{
+  (*tformatprintf0) ("%d", i);
+  (*tformatprintf0) ((*tformat_arg) ("%d"), i);
+  (*tformatprintf0) ("%"); /* { dg-warning "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" } */
+  (*tformatprintf2) ("%d", i);
+  (*tformatprintf2) ((*tformat_arg) ("%d"), i);
+  (*tformatprintf2) ("%"); /* { dg-warning "format" "nested" } */
+  (*tformatprintf2) ((*tformat_arg) ("%")); /* { dg-warning "format" "nested" } */
+  (****tformatprintf3) ("%d", i);
+  (****tformatprintf3) ((*tformat_arg) ("%d"), i);
+  (****tformatprintf3) ("%"); /* { dg-warning "format" "nested 2" } */
+  (****tformatprintf3) ((*tformat_arg) ("%")); /* { dg-warning "format" "nested 2" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_bitfld-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_bitfld-1.c
@@ -0,0 +1,52 @@
+/* Test for printf formats and bit-fields: bug 22421.  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+/* { dg-require-effective-target int32plus } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+struct s {
+  unsigned int u1 : 1;
+  signed int s1 : 1;
+  unsigned int u15 : 15;
+  signed int s15 : 15;
+  unsigned int u16 : 16;
+  signed int s16 : 16;
+  unsigned long u31 : 31;
+  signed long s31 : 31;
+  unsigned long u32 : 32;
+  signed long s32 : 32;
+  unsigned long long u48 : 48;
+} x;
+
+void
+foo (void)
+{
+  printf ("%d%u", x.u1, x.u1);
+  printf ("%d%u", x.s1, x.s1);
+  printf ("%d%u", x.u15, x.u15);
+  printf ("%d%u", x.s15, x.s15);
+  printf ("%d%u", x.u16, x.u16);
+  printf ("%d%u", x.s16, x.s16);
+#if __INT_MAX__ > 32767
+  /* If integers are 16 bits, there doesn't seem to be a way of
+     printing these without getting an error.  */
+  printf ("%d%u", x.u31, x.u31);
+  printf ("%d%u", x.s31, x.s31);
+#endif
+#if __LONG_MAX__ > 2147483647 && __INT_MAX__ >= 2147483647
+  /* If long is wider than 32 bits, the 32-bit bit-fields are int or
+     unsigned int or promote to those types.  Otherwise, long is 32
+     bits and the bit-fields are of type plain long or unsigned
+     long.  */
+  printf ("%d%u", x.u32, x.u32);
+  printf ("%d%u", x.s32, x.s32);
+#else
+  printf ("%ld%lu", x.u32, x.u32);
+  printf ("%ld%lu", x.s32, x.s32);
+#endif
+  printf ("%I64u", x.u48); /* { dg-warning "has type '.*unsigned int:48'" } */
+  printf ("%I64u", (unsigned long long)x.u48);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_branch-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_branch-1.c
@@ -0,0 +1,28 @@
+/* Test for format checking of conditional expressions.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+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" } */
+  /* 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) ? "%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" } */
+  /* 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 *-*-* } 26 } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-1.c
@@ -0,0 +1,184 @@
+/* Test for printf formats.  Formats using C90 features, including cases
+   where C90 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, int i1, int i2, unsigned int u, double d, char *s, void *p,
+     int *n, short int *hn, long int l, unsigned long int ul,
+     long int *ln, long double ld, wint_t lc, wchar_t *ls, llong ll,
+     ullong ull, unsigned int *un, const int *cn, signed char *ss,
+     unsigned char *us, const signed char *css, unsigned int u1,
+     unsigned int u2)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.1 (pages 131-134).  */
+  /* Basic sanity checks for the different components of a format.  */
+  printf ("%d\n", i);
+  printf ("%+d\n", i);
+  printf ("%3d\n", i);
+  printf ("%-3d\n", i);
+  printf ("%*d\n", i1, i);
+  printf ("%d %lu\n", i, ul);
+  /* Bogus use of width.  */
+  printf ("%5n\n", n); /* { dg-warning "width" "width 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 ("%-%"); /* { dg-warning "format" "bogus %%" } */
+  printf ("%-%\n"); /* { dg-warning "format" "bogus %%" } */
+  printf ("%5%\n"); /* { dg-warning "format" "bogus %%" } */
+  printf ("%h%\n"); /* { dg-warning "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
+     differences in format checking here, and this is relied on to get the
+     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);
+  printf ("%hs", hn);
+  printf ("%hp", p); /* { dg-warning "length" "bad use of %h" } */
+  printf ("%h"); /* { dg-warning "conversion lacks type" "bare %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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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% 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* Various tests of bad argument types.  */
+  printf ("%d", l); /* { dg-warning "format" "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" } */
+  /* 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
+     discussion of the requirements of rules on identical representation,
+     and of the application of the as if rule with the new va_arg
+     allowances in C99 to printf.)  Likewise, we should warn if
+     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" } */
+  /* 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" } */
+  /* The historical behavior is to allow signed / unsigned types
+     interchangably as arguments.  For values representable in both types,
+     such usage may be correct.  For now preserve the behavior of GCC
+     in such cases.
+  */
+  printf ("%d", u);
+  /* Wrong number of arguments.  */
+  printf ("%d%d", i); /* { dg-warning "arguments" "wrong number of args" } */
+  printf ("%d", i, i); /* { dg-warning "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" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-2.c
@@ -0,0 +1,25 @@
+/* Test for printf formats.  Formats using C99 features should be rejected
+   outside of C99 mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, double d, llong ll, intmax_t j, size_t z, ptrdiff_t t)
+{
+  /* Some tests already in c90-printf-1.c, e.g. %lf.  */
+  /* The widths hh, ll, j, z, t are new.  */
+  printf ("%hhd", i); /* { dg-warning "unknown|format" "%hh is unsupported" } */
+  printf ("%I64d", ll); /* { dg-warning "length|C" "%I64 in C90" } */
+  printf ("%jd", j); /* { dg-warning "unknown|format" "%j is unsupported" } */
+  printf ("%zu", z); /* { dg-warning "unknown|format" "%z is unsupported" } */
+  printf ("%td", t); /* { dg-warning "unknown|format" "%t is unsupported" } */
+  /* The formats F, a, A are new.  */
+  printf ("%F", d); /* { dg-warning "unknown|format" "%F is unsupported" } */
+  printf ("%a", d); /* { dg-warning "unknown|format" "%a is unsupported" } */
+  printf ("%A", d); /* { dg-warning "unknown|format" "%A is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-3.c
@@ -0,0 +1,43 @@
+/* Test for printf formats.  Test that the C90 functions get their default
+   attributes in strict C90 mode, but the C99 and gettext functions
+   do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, char *s, size_t n, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5, va_list v6, va_list v7, va_list v8)
+{
+  fprintf (stdout, "%d", i);
+  fprintf (stdout, "%ld", i); /* { dg-warning "format" "fprintf" } */
+  printf ("%d", i);
+  printf ("%ld", i); /* { dg-warning "format" "printf" } */
+  /* The "unlocked" functions shouldn't warn in c90 mode.  */
+  fprintf_unlocked (stdout, "%ld", i);
+  printf_unlocked ("%ld", i);
+  sprintf (s, "%d", i);
+  sprintf (s, "%ld", i); /* { dg-warning "format" "sprintf" } */
+  vfprintf (stdout, "%d", v0);
+  vfprintf (stdout, "%Y", v1); /* { dg-warning "format" "vfprintf" } */
+  vprintf ("%d", v2);
+  vprintf ("%Y", v3); /* { dg-warning "format" "vprintf" } */
+  /* The following used to give a bogus warning.  */
+  vprintf ("%*.*d", v8);   /* { dg-bogus "format" "vprintf" } */
+  vsprintf (s, "%d", v4);
+  vsprintf (s, "%Y", v5); /* { dg-warning "format" "Y is invalid" } */
+  snprintf (s, n, "%d", i);
+  snprintf (s, n, "%ld", i);
+  vsnprintf (s, n, "%d", v6);
+  vsnprintf (s, n, "%Y", v7);
+  printf (gettext ("%d"), i);
+  printf (gettext ("%ld"), i);
+  printf (dgettext ("", "%d"), i);
+  printf (dgettext ("", "%ld"), i);
+  printf (dcgettext ("", "%d", 0), i);
+  printf (dcgettext ("", "%ld", 0), i);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-1.c
@@ -0,0 +1,119 @@
+/* Test for scanf formats.  Formats using C90 features, including cases
+   where C90 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, unsigned int *uip, short int *hp, unsigned short int *uhp,
+     long int *lp, unsigned long int *ulp, float *fp, double *dp,
+     long double *ldp, char *s, signed char *ss, unsigned char *us,
+     void **pp, int *n, llong *llp, ullong *ullp, wchar_t *ls,
+     const int *cip, const int *cn, const char *cs, const void **ppc,
+     void *const *pcp, short int *hn, long int *ln, void *p, char **sp,
+     volatile void *ppv)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.2 (pages 134-138).  */
+  /* Basic sanity checks for the different components of a format.  */
+  scanf ("%d", ip);
+  scanf ("%*d");
+  scanf ("%3d", ip);
+  scanf ("%hd", hp);
+  scanf ("%3ld", lp);
+  scanf ("%*3d");
+  scanf ("%d %ld", ip, lp);
+  /* Valid and invalid %% constructions.  */
+  scanf ("%%");
+  scanf ("%*%"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%*%\n"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%4%"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%4%\n"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%h%"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%h%\n"); /* { dg-warning "format" "bogus %%" } */
+  /* Valid, invalid and silly assignment-suppression constructions.  */
+  scanf ("%*d%*i%*o%*u%*x%*X%*e%*E%*f%*g%*G%*s%*[abc]%*c%*p");
+  scanf ("%*2d%*8s%*3c");
+  scanf ("%*n", n); /* { dg-warning "suppress" "suppression of %n" } */
+  scanf ("%*hd"); /* { dg-warning "together" "suppression with length" } */
+  /* Valid, invalid and silly width constructions.  */
+  scanf ("%2d%3i%4o%5u%6x%7X%8e%9E%10f%11g%12G%13s%14[abc]%15c%16p",
+	 ip, ip, uip, uip, uip, uip, fp, fp, fp, fp, fp, s, s, s, pp);
+  scanf ("%0d", ip); /* { dg-warning "width" "warning for zero width" } */
+  scanf ("%3n", n); /* { dg-warning "width" "width with %n" } */
+  /* Valid and invalid %h, %l, %L constructions.  */
+  scanf ("%hd%hi%ho%hu%hx%hX%hn", hp, hp, uhp, uhp, uhp, uhp, hn);
+  scanf ("%he", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hE", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hf", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hg", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hG", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hs", hp);
+  scanf ("%h[ac]", s); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hc", hp);
+  scanf ("%hp", pp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%h"); /* { dg-warning "conversion lacks type" "bare %h" } */
+  scanf ("%h."); /* { dg-warning "conversion" "bogus %h" } */
+  scanf ("%ld%li%lo%lu%lx%lX%ln", lp, lp, ulp, ulp, ulp, ulp, ln);
+  scanf ("%le%lE%lf%lg%lG", dp, dp, dp, dp, dp);
+  scanf ("%lp", pp); /* { dg-warning "length" "bad use of %l" } */
+  /* These next three formats were added in C94.  */
+  scanf ("%ls", ls); /* { dg-warning "length|C" "bad use of %l" } */
+  scanf ("%l[ac]", ls); /* { dg-warning "length|C" "bad use of %l" } */
+  scanf ("%lc", ls); /* { dg-warning "length|C" "bad use of %l" } */
+  scanf ("%Ld", llp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Li", llp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lo", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lu", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lx", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%LX", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Ls", s); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%L[ac]", s); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lc", s); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lp", pp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Ln", n); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  /* Valid uses of each bare conversion.  */
+  scanf ("%d%i%o%u%x%X%e%E%f%g%G%s%[abc]%c%p%n%%", ip, ip, uip, uip, uip,
+	 uip, fp, fp, fp, fp, fp, s, s, s, pp, n);
+  /* Allow other character pointers with %s, %c, %[].  */
+  scanf ("%2s%3s%4c%5c%6[abc]%7[abc]", ss, us, ss, us, ss, us);
+  /* Further tests for %[].  */
+  scanf ("%[%d]%d", s, ip);
+  scanf ("%[^%d]%d", s, ip);
+  scanf ("%[]%d]%d", s, ip);
+  scanf ("%[^]%d]%d", s, ip);
+  scanf ("%[%d]%d", s, ip);
+  scanf ("%[]abcd", s); /* { dg-warning "no closing" "incomplete scanset" } */
+  /* Various tests of bad argument types.  Some of these are only pedantic
+     warnings.
+  */
+  scanf ("%d", lp); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%d", uip); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%d", pp); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", ppc); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", ppv); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%s", n); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%s", p); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", p); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", sp); /* { dg-warning "format" "bad argument types" } */
+  /* Tests for writing into constant values.  */
+  scanf ("%d", cip); /* { dg-warning "constant" "%d writing into const" } */
+  scanf ("%n", cn); /* { dg-warning "constant" "%n writing into const" } */
+  scanf ("%s", cs); /* { dg-warning "constant" "%s writing into const" } */
+  scanf ("%p", pcp); /* { dg-warning "constant" "%p writing into const" } */
+  /* Wrong number of arguments.  */
+  scanf ("%d%d", ip); /* { dg-warning "arguments" "wrong number of args" } */
+  scanf ("%d", ip, ip); /* { dg-warning "arguments" "wrong number of args" } */
+  /* Miscellaneous bogus constructions.  */
+  scanf (""); /* { dg-warning "zero-length" "warning for empty format" } */
+  scanf ("\0"); /* { dg-warning "embedded" "warning for embedded NUL" } */
+  scanf ("%d\0", ip); /* { dg-warning "embedded" "warning for embedded NUL" } */
+  scanf ("%d\0%d", ip, ip); /* { dg-warning "embedded|too many" "warning for embedded NUL" } */
+  scanf (NULL); /* { dg-warning "null" "null format string warning" } */
+  scanf ("%"); /* { dg-warning "trailing" "trailing % warning" } */
+  scanf ("%d", (int *)0); /* { dg-warning "null" "writing into NULL" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-2.c
@@ -0,0 +1,26 @@
+/* Test for scanf formats.  Formats using C99 features should be rejected
+   outside of C99 mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (signed char *hhp, float *fp, llong *llp, intmax_t *jp,
+     size_t *zp, ptrdiff_t *tp)
+{
+  /* Some tests already in c90-scanf-1.c.  */
+  /* The widths hh, ll, j, z, t are new.  */
+  scanf ("%hhd", hhp); /* { dg-warning "unknown|format" "%hh is unsupported" } */
+  scanf ("%I64d", llp); /* { dg-warning "length|C" "%I64 in C90" } */
+  scanf ("%jd", jp); /* { dg-warning "unknown|format" "%j is unsupported" } */
+  scanf ("%zu", zp); /* { dg-warning "unknown|format" "%z is unsupported" } */
+  scanf ("%td", tp); /* { dg-warning "unknown|format" "%t is unsupported" } */
+  /* The formats F, a, A are new.  */
+  scanf ("%F", fp); /* { dg-warning "unknown|format" "%F is unsupported" } */
+  scanf ("%a", fp); /* { dg-warning "unknown|format" "%a is unsupported" } */
+  scanf ("%A", fp); /* { dg-warning "unknown|format" "%A is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-3.c
@@ -0,0 +1,20 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char **sp, wchar_t **lsp)
+{
+  /* %a formats for allocation, only recognized in C90 mode, are a
+     GNU extension.
+  */
+  scanf ("%as", sp); /* { dg-warning "flag" "%as is unsupported" } */
+  scanf ("%aS", lsp); /* { dg-warning "format|flag" "%aS is unsupported" } */
+  scanf ("%a[bcd]", sp); /* { dg-warning "flag" "%a[] is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-4.c
@@ -0,0 +1,31 @@
+/* Test for scanf formats.  Test that the C90 functions get their default
+   attributes in strict C90 mode, but the C99 and gettext functions
+   do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, char *s, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5)
+{
+  fscanf (stdin, "%d", ip);
+  fscanf (stdin, "%ld", ip); /* { dg-warning "format" "fscanf" } */
+  scanf ("%d", ip);
+  scanf ("%ld", ip); /* { dg-warning "format" "scanf" } */
+  sscanf (s, "%d", ip);
+  sscanf (s, "%ld", ip); /* { dg-warning "format" "sscanf" } */
+  vfscanf (stdin, "%d", v0);
+  vscanf ("%d", v2);
+  vsscanf (s, "%d", v4);
+  scanf (gettext ("%d"), ip);
+  scanf (gettext ("%ld"), ip);
+  scanf (dgettext ("", "%d"), ip);
+  scanf (dgettext ("", "%ld"), ip);
+  scanf (dcgettext ("", "%d", 0), ip);
+  scanf (dcgettext ("", "%ld", 0), ip);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-5.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-5.c
@@ -0,0 +1,20 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char **sp, wchar_t **lsp)
+{
+  /* m assignment-allocation modifier, recognized in both C90
+     and C99 modes, is a POSIX and ISO/IEC WDTR 24731-2 extension.  */
+  scanf ("%ms", sp); /* { dg-warning "unknown|format" "%ms is unsupported" } */
+  scanf ("%mS", lsp); /* { dg-warning "unknown|format" "%mS is unsupported" } */
+  scanf ("%mls", lsp); /* { dg-warning "unknown|format" "%mls is unsupported" } */
+  scanf ("%m[bcd]", sp); /* { dg-warning "unknown|format" "%m[] is unsupported" } */
+  scanf ("%ml[bcd]", lsp); /* { dg-warning "unknown|format" "%ml[] is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-1.c
@@ -0,0 +1,20 @@
+/* Test for strftime formats.  Formats using C90 features.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wformat-y2k" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.12.3.5 (pages 174-175).  */
+  /* Formats which are Y2K-compliant (no 2-digit years).  */
+  strftime (s, m, "%a%A%b%B%d%H%I%j%m%M%p%S%U%w%W%X%Y%Z%%", tp);
+  /* Formats with 2-digit years.  */
+  strftime (s, m, "%y", tp); /* { dg-warning "some locales" "2-digit year" } */
+  /* Formats with 2-digit years in some locales.  */
+  strftime (s, m, "%c", tp); /* { dg-warning "some locales" "2-digit year" } */
+  strftime (s, m, "%x", tp); /* { dg-warning "some locales" "2-digit year" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-2.c
@@ -0,0 +1,28 @@
+/* Test for strftime formats.  Rejection of formats using C99 features in
+   pedantic C90 mode.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wformat-y2k" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  strftime (s, m, "%C", tp); /* { dg-warning "format" "%C is unsupported" } */
+  strftime (s, m, "%D", tp); /* { dg-warning "format" "%D is unsupported" } */
+  strftime (s, m, "%e", tp); /* { dg-warning "format" "%e is unsupported" } */
+  strftime (s, m, "%F", tp); /* { dg-warning "format" "%F is unsupported" } */
+  strftime (s, m, "%g", tp); /* { dg-warning "format" "%g is unsupported" } */
+  strftime (s, m, "%G", tp); /* { dg-warning "format" "%G is unsupported" } */
+  strftime (s, m, "%h", tp); /* { dg-warning "format" "%h is unsupported" } */
+  strftime (s, m, "%n", tp); /* { dg-warning "format" "%n is unsupported" } */
+  strftime (s, m, "%r", tp); /* { dg-warning "format" "%r is unsupported" } */
+  strftime (s, m, "%R", tp); /* { dg-warning "format" "%R is unsupported" } */
+  strftime (s, m, "%t", tp); /* { dg-warning "format" "%t is unsupported" } */
+  strftime (s, m, "%T", tp); /* { dg-warning "format" "%T is unsupported" } */
+  strftime (s, m, "%u", tp); /* { dg-warning "format" "%u is unsupported" } */
+  strftime (s, m, "%V", tp); /* { dg-warning "format" "%V is unsupported" } */
+  strftime (s, m, "%z", tp); /* { dg-warning "C" "%z not in C90" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c94-printf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c94-printf-1.c
@@ -0,0 +1,19 @@
+/* Test for printf formats.  Changes in C94 to C90.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:199409 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (wint_t lc, wchar_t *ls)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.1 (pages 131-134),
+     as amended by ISO/IEC 9899:1990/Amd.1:1995 (E) (pages 4-5).
+     We do not repeat here all the C90 format checks, but just verify
+     that %ls and %lc are accepted without warning.
+  */
+  printf ("%lc", lc);
+  printf ("%ls", ls);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c94-scanf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c94-scanf-1.c
@@ -0,0 +1,18 @@
+/* Test for scanf formats.  Changes in C94 to C90.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:199409 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (wchar_t *ls)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.2 (pages 134-138),
+     as amended by ISO/IEC 9899:1990/Amd.1:1995 (E) (pages 5-6).
+     We do not repeat here all the C90 format checks, but just verify
+     that %ls, %lc, %l[] are accepted without warning.
+  */
+  scanf ("%lc%ls%l[abc]", ls, ls, ls);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-1.c
@@ -0,0 +1,109 @@
+/* Test for printf formats.  Formats using C99 features, including cases
+   where C99 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, unsigned int u, double d, char *s, void *p, int *n,
+     long double ld, wint_t lc, wchar_t *ls, long long int ll,
+     unsigned long long int ull, signed char *ss, unsigned char *us,
+     long long int *lln, intmax_t j, uintmax_t uj, intmax_t *jn,
+     size_t z, signed_size_t sz, signed_size_t *zn,
+     ptrdiff_t t, ptrdiff_t *tn)
+{
+  /* See ISO/IEC 9899:1999 (E) subclause 7.19.6.1 (pages 273-281).
+     We do not repeat here most of the checks for correct C90 formats
+     or completely broken formats.
+  */
+  /* Valid and invalid %h, %hh, %l, %j, %z, %t, %L constructions.  */
+  printf ("%hf", d); /* { dg-warning "length" "bad use of %h" } */
+  printf ("%hF", d); /* { dg-warning "unknown|format" "bad use of %hF" } */
+  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 ("%ha", d); /* { dg-warning "unknown|format" "bad use of %ha" } */
+  printf ("%hA", d); /* { dg-warning "unknown|format" "bad use of %hA" } */
+  printf ("%hc", i);
+  printf ("%hs", (short *)s);
+  printf ("%hp", p); /* { dg-warning "length" "bad use of %h" } */
+  printf ("%lc", lc);
+  printf ("%ls", ls);
+  printf ("%lp", p); /* { dg-warning "length|C" "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" } */
+  /* 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" } */
+  /* 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% 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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 ("%-08F", d); /* { dg-warning "unknown|format" "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 ("%-08a", d); /* { dg-warning "unknown|format" "0 flag ignored with - flag" } */
+  printf ("%-08A", d); /* { dg-warning "unknown|format" "0 flag ignored with - flag" } */
+  /* Various tests of bad argument types.  Mostly covered in c90-printf-1.c;
+     here just test for pointer target sign with %hhn.  (Probably allowed
+     by the standard, but a bad idea, so GCC should diagnose if what
+     is used is not signed char *.)
+  */
+  printf ("%hhn", s); /* { dg-warning "unknown|format" "%hhn is unsupported" } */
+  printf ("%hhn", us); /* { dg-warning "unknown|format" "%hhn is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-2.c
@@ -0,0 +1,32 @@
+/* Test for printf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, long long ll, size_t z, wint_t lc, wchar_t *ls)
+{
+  /* The length modifiers q, Z and L as applied to integer formats are
+     extensions.
+  */
+  printf ("%qd", ll); /* { dg-warning "unknown|format" "%q length is unsupported" } */
+  printf ("%Ld", ll); /* { dg-warning "unknown|format" "%L length is unsupported" } */
+  printf ("%Zd", z); /* { dg-warning "unknown|format" "%Z length is unsupported" } */
+  /* The conversion specifiers C and S are X/Open extensions; the
+     conversion specifier m is a GNU extension.
+  */
+  printf ("%m"); /* { dg-warning "unknown" "printf %m is unsupported" } */
+  printf ("%C", lc); /* { dg-warning "C" "printf %C" } */
+  printf ("%S", ls); /* { dg-warning "C" "printf %S" } */
+  /* The flag character ', and the use of operand number $ formats, are
+     X/Open extensions.
+  */
+  printf ("%'d", i); /* { dg-warning "C" "printf ' flag" } */
+  printf ("%1$d", i); /* { dg-warning "C" "printf $ format" } */
+  printf ("%Ix", z); /* { dg-warning "C" "printf I format" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-3.c
@@ -0,0 +1,40 @@
+/* Test for printf formats.  Test that the C99 functions get their default
+   attributes in strict C99 mode, but the gettext functions do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, char *s, size_t n, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5, va_list v6, va_list v7)
+{
+  fprintf (stdout, "%d", i);
+  fprintf (stdout, "%ld", i); /* { dg-warning "format" "fprintf" } */
+  printf ("%d", i);
+  printf ("%ld", i); /* { dg-warning "format" "printf" } */
+  /* The "unlocked" functions shouldn't warn in c99 mode.  */
+  fprintf_unlocked (stdout, "%ld", i);
+  printf_unlocked ("%ld", i);
+  sprintf (s, "%d", i);
+  sprintf (s, "%ld", i); /* { dg-warning "format" "sprintf" } */
+  snprintf (s, n, "%d", i);
+  snprintf (s, n, "%ld", i); /* { dg-warning "format" "snprintf" } */
+  vfprintf (stdout, "%d", v0);
+  vfprintf (stdout, "%Y", v1); /* { dg-warning "format" "vfprintf" } */
+  vprintf ("%d", v0);
+  vprintf ("%Y", v1); /* { dg-warning "format" "vprintf" } */
+  vsprintf (s, "%d", v0);
+  vsprintf (s, "%Y", v1); /* { dg-warning "format" "vsprintf" } */
+  vsnprintf (s, n, "%d", v0);
+  vsnprintf (s, n, "%Y", v1); /* { dg-warning "format" "vsnprintf" } */
+  printf (gettext ("%d"), i);
+  printf (gettext ("%ld"), (long) i);
+  printf (dgettext ("", "%d"), i);
+  printf (dgettext ("", "%ld"), (long) i);
+  printf (dcgettext ("", "%d", 0), i);
+  printf (dcgettext ("", "%ld", 0), (long) i);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-1.c
@@ -0,0 +1,63 @@
+/* Test for scanf formats.  Formats using C99 features, including cases
+   where C99 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, unsigned int *uip, short int *hp, unsigned short int *uhp,
+     signed char *hhp, unsigned char *uhhp, long int *lp,
+     unsigned long int *ulp, float *fp, double *dp, long double *ldp, char *s,
+     void **pp, int *n, long long *llp, unsigned long long *ullp, wchar_t *ls,
+     short int *hn, signed char *hhn, long int *ln, long long int *lln,
+     intmax_t *jp, uintmax_t *ujp, intmax_t *jn, size_t *zp,
+     signed_size_t *szp, signed_size_t *zn, ptrdiff_t *tp,
+     unsigned_ptrdiff_t *utp, ptrdiff_t *tn)
+{
+  /* See ISO/IEC 9899:1999 (E) subclause 7.19.6.2 (pages 281-288).
+     We do not repeat here most of the checks for correct C90 formats
+     or completely broken formats.
+  */
+  /* Valid, invalid and silly assignment-suppression
+     and width constructions.
+  */
+  scanf ("%*d%*i%*o%*u%*x%*X%*e%*E%*f%*g%*G%*s%*[abc]%*c%*p");
+  scanf ("%*2d%*8s%*3c");
+  scanf ("%*n", n); /* { dg-warning "suppress" "suppression of %n" } */
+  scanf ("%*hd"); /* { dg-warning "together" "suppression with length" } */
+  scanf ("%2d%3i%4o%5u%6x%7X%10e%11E%12f%14g%15G%16s%3[abc]%4c%5p",
+	 ip, ip, uip, uip, uip, uip, fp, fp, fp, fp, fp,
+	 s, s, s, pp);
+  scanf ("%0d", ip); /* { dg-warning "width" "warning for zero width" } */
+  scanf ("%3n", n); /* { dg-warning "width" "width with %n" } */
+  /* Valid and invalid %h, %hh, %l, %j, %z, %t, %L constructions.  */
+  scanf ("%hd%hi%ho%hu%hx%hX%hn", hp, hp, uhp, uhp, uhp, uhp, hn);
+  scanf ("%he", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hE", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hf", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hg", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hG", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hs", hp);
+  scanf ("%h[ac]", s); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hc", (short *)s);
+  scanf ("%hp", pp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hhd", hhp); /* { dg-warning "unknown|format" "%hh is unsupported" } */
+  scanf ("%ld%li%lo%lu%lx%lX%ln", lp, lp, ulp, ulp, ulp, ulp, ln);
+  scanf ("%le%lE%lf%lg%lG", dp, dp, dp, dp, dp);
+  scanf ("%lp", pp); /* { dg-warning "length" "bad use of %l" } */
+  scanf ("%ls", ls);
+  scanf ("%l[ac]", ls);
+  scanf ("%lc", ls);
+  scanf ("%jd", jp); /* { dg-warning "unknown|format" "%j not supported" } */
+  scanf ("%zd", zp); /* { dg-warning "unknown|format" "%z not supported" } */
+  scanf ("%td", tp); /* { dg-warning "unknown|format" "%t not supported" } */
+  scanf ("%Lf", llp); /* { dg-warning "unknown|format" "bad use of %L is not supported" } */
+  /* Valid uses of each bare conversion.  */
+  scanf ("%d%i%o%u%x%X%e%E%f%g%G%s%[abc]%c%p%n%%", ip, ip, uip, uip, uip,
+         uip, fp, fp, fp, fp, fp, s, s, s, pp, n);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-2.c
@@ -0,0 +1,27 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, long long int *llp, wchar_t *ls)
+{
+  /* The length modifiers q and L as applied to integer formats are
+     extensions.
+  */
+  scanf ("%qd", llp); /* { dg-warning "unknown|format" "%q is unsupported" } */
+  scanf ("%Ld", llp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  /* The conversion specifiers C and S are X/Open extensions.  */
+  scanf ("%C", ls); /* { dg-warning "C" "scanf %C" } */
+  scanf ("%S", ls); /* { dg-warning "C" "scanf %S" } */
+  /* The use of operand number $ formats is an X/Open extension.  */
+  scanf ("%1$d", ip); /* { dg-warning "C" "scanf $ format" } */
+  /* glibc also supports flags ' and I on scanf formats as an extension.  */
+  scanf ("%'d", ip); /* { dg-warning "C" "scanf ' flag" } */
+  scanf ("%Id", (ssize_t *)ip); /* { dg-warning "C" "scanf I flag" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-3.c
@@ -0,0 +1,33 @@
+/* Test for scanf formats.  Test that the C99 functions get their default
+   attributes in strict C99 mode, but the gettext functions do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, char *s, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5)
+{
+  fscanf (stdin, "%d", ip);
+  fscanf (stdin, "%ld", ip); /* { dg-warning "format" "fscanf" } */
+  scanf ("%d", ip);
+  scanf ("%ld", ip); /* { dg-warning "format" "scanf" } */
+  sscanf (s, "%d", ip);
+  sscanf (s, "%ld", ip); /* { dg-warning "format" "sscanf" } */
+  vfscanf (stdin, "%d", v0);
+  vfscanf (stdin, "%Y", v1); /* { dg-warning "format" "vfscanf" } */
+  vscanf ("%d", v2);
+  vscanf ("%Y", v3); /* { dg-warning "format" "vscanf" } */
+  vsscanf (s, "%d", v4);
+  vsscanf (s, "%Y", v5); /* { dg-warning "format" "vsscanf" } */
+  scanf (gettext ("%d"), ip);
+  scanf (gettext ("%ld"), ip);
+  scanf (dgettext ("", "%d"), ip);
+  scanf (dgettext ("", "%ld"), ip);
+  scanf (dcgettext ("", "%d", 0), ip);
+  scanf (dcgettext ("", "%ld", 0), ip);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-4.c
@@ -0,0 +1,20 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char **sp, wchar_t **lsp)
+{
+  /* m assignment-allocation modifier, recognized in both C90
+     and C99 modes, is a POSIX and ISO/IEC WDTR 24731-2 extension.  */
+  scanf ("%ms", sp); /* { dg-warning "unknown|format" "%ms is unsupported" } */
+  scanf ("%mS", lsp); /* { dg-warning "unknown|format" "%mS is unsupported" } */
+  scanf ("%mls", lsp); /* { dg-warning "unknown|format" "%mls is unsupported" } */
+  scanf ("%m[bcd]", sp); /* { dg-warning "unknown|format" "%m[] is unsupported" } */
+  scanf ("%ml[bcd]", lsp); /* { dg-warning "unknown|format" "%ml[] is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-1.c
@@ -0,0 +1,22 @@
+/* Test for strftime formats.  Formats using C99 features.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat -Wformat-y2k" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.12.3.5 (pages 174-175).  */
+  /* Formats which are Y2K-compliant (no 2-digit years).  */
+  strftime (s, m, "%a%A%b%B%d%H%I%j%m%M%p%S%U%w%W%X%Y%z%Z%%", tp);
+  /* Formats with 2-digit years.  */
+  strftime (s, m, "%D", tp);
+  strftime (s, m, "%g", tp);
+  strftime (s, m, "%y", tp);
+  /* Formats with 2-digit years in some locales.  */
+  strftime (s, m, "%c", tp);
+  strftime (s, m, "%x", tp);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-2.c
@@ -0,0 +1,20 @@
+/* Test for strftime formats.  Rejection of extensions in pedantic mode.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  /* %P is a lowercase version of %p.  */
+  strftime (s, m, "%P", tp); /* { dg-warning "unknown" "strftime %P" } */
+  /* %k is %H but padded with a space rather than 0 if necessary.  */
+  strftime (s, m, "%k", tp); /* { dg-warning "unknown" "strftime %k" } */
+  /* %l is %I but padded with a space rather than 0 if necessary.  */
+  strftime (s, m, "%l", tp); /* { dg-warning "unknown" "strftime %l" } */
+  /* %s is the number of seconds since the Epoch.  */
+  strftime (s, m, "%s", tp); /* { dg-warning "unknown" "strftime %s" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_cast-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_cast-1.c
@@ -0,0 +1,17 @@
+/* Test for strings cast through integer types: should not be treated
+   as format strings unless the types are of the same width as
+   pointers (intptr_t or similar).  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+f (int x)
+{
+  printf("%s", x); /* { dg-warning "format" } */
+  printf((char *)(size_t)"%s", x); /* { dg-warning "format" } */
+  printf((char *)(char)"%s", x); /* { dg-warning "cast from pointer to integer of different size" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-1.c
@@ -0,0 +1,40 @@
+/* Test for warnings for missing format attributes.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  vprintf (fmt, ap); /* { dg-warning "candidate" "printf attribute warning" } */
+  va_end (ap);
+}
+
+void
+bar (const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  vscanf (fmt, ap); /* { dg-warning "candidate" "scanf attribute warning" } */
+  va_end (ap);
+}
+
+__attribute__((__format__(__ms_printf__, 1, 2))) void
+foo2 (const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  vprintf (fmt, ap);
+  va_end (ap);
+}
+
+void
+vfoo (const char *fmt, va_list arg)
+{
+  vprintf (fmt, arg); /* { dg-warning "candidate" "printf attribute warning 2" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-2.c
@@ -0,0 +1,17 @@
+/* Test for warnings for missing format attributes.  Don't warn if no
+   relevant parameters for a format attribute; see c/1017.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, ...)
+{
+  va_list ap;
+  va_start (ap, i);
+  vprintf ("Foo %s bar %s", ap); /* { dg-bogus "candidate" "bogus printf attribute warning" } */
+  va_end (ap);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-3.c
@@ -0,0 +1,27 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+void
+foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
+{
+  noattr_t na1 = na;
+  noattr_t na2 = a; /* { dg-warning "candidate" "initialization warning" } */
+  attr_t a1 = na;
+  attr_t a2 = a;
+
+  vnoattr_t vna1 = vna;
+  vnoattr_t vna2 = va; /* { dg-warning "candidate" "initialization warning" } */
+  vattr_t va1 = vna;
+  vattr_t va2 = va;
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-4.c
@@ -0,0 +1,33 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+void
+foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
+{
+  noattr_t na1, na2;
+  attr_t a1, a2;
+
+  vnoattr_t vna1, vna2;
+  vattr_t va1, va2;
+
+  na1 = na;
+  na2 = a; /* { dg-warning "candidate" "assignment warning" } */
+  a1 = na;
+  a2 = a;
+
+  vna1 = vna;
+  vna2 = va; /* { dg-warning "candidate" "assignment warning" } */
+  va1 = vna;
+  va1 = va;
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-5.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-5.c
@@ -0,0 +1,49 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+noattr_t
+foo1 (noattr_t na, attr_t a, int i)
+{
+  if (i)
+    return na;
+  else
+    return a; /* { dg-warning "candidate" "return type warning" } */
+}
+
+attr_t
+foo2 (noattr_t na, attr_t a, int i)
+{
+  if (i)
+    return na;
+  else
+    return a;
+}
+
+vnoattr_t
+foo3 (vnoattr_t vna, vattr_t va, int i)
+{
+  if (i)
+    return vna;
+  else
+    return va; /* { dg-warning "candidate" "return type warning" } */
+}
+
+vattr_t
+foo4 (vnoattr_t vna, vattr_t va, int i)
+{
+  if (i)
+    return vna;
+  else
+    return va;
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-6.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-6.c
@@ -0,0 +1,32 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+extern void foo1 (noattr_t);
+extern void foo2 (attr_t);
+extern void foo3 (vnoattr_t);
+extern void foo4 (vattr_t);
+
+void
+foo (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
+{
+  foo1 (na);
+  foo1 (a); /* { dg-warning "candidate" "parameter passing warning" } */
+  foo2 (na);
+  foo2 (a);
+
+  foo3 (vna);
+  foo3 (va); /* { dg-warning "candidate" "parameter passing warning" } */
+  foo4 (vna);
+  foo4 (va);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_multattr-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_multattr-1.c
@@ -0,0 +1,51 @@
+/* Test for multiple format attributes.  Test for printf and scanf attributes
+   together.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* If we specify multiple attributes for a single function, they should
+   all apply.  This should apply whether they are on the same declaration
+   or on different declarations.  */
+
+extern void my_vprintf_scanf (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_printf__, 1, 0)))
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern void my_vprintf_scanf2 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)))
+     __attribute__((__format__(__ms_printf__, 1, 0)));
+
+extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_printf__, 1, 0)));
+extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_printf__, 1, 0)));
+
+void
+foo (va_list ap, int *ip, long *lp)
+{
+  my_vprintf_scanf ("%d", ap, "%d", ip);
+  my_vprintf_scanf ("%d", ap, "%ld", lp);
+  my_vprintf_scanf ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf2 ("%d", ap, "%d", ip);
+  my_vprintf_scanf2 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf2 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf2 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf3 ("%d", ap, "%d", ip);
+  my_vprintf_scanf3 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf3 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf3 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf4 ("%d", ap, "%d", ip);
+  my_vprintf_scanf4 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf4 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf4 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_multattr-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_multattr-2.c
@@ -0,0 +1,40 @@
+/* Test for multiple format attributes.  Test for printf and scanf attributes
+   together, in different places on the declarations.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* If we specify multiple attributes for a single function, they should
+   all apply, wherever they are placed on the declarations.  */
+
+extern __attribute__((__format__(__ms_printf__, 1, 0))) void
+     my_vprintf_scanf (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern void (__attribute__((__format__(__ms_printf__, 1, 0))) my_vprintf_scanf2)
+     (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern __attribute__((__format__(__ms_scanf__, 3, 4))) void
+     (__attribute__((__format__(__ms_printf__, 1, 0))) my_vprintf_scanf3)
+     (const char *, va_list, const char *, ...);
+
+void
+foo (va_list ap, int *ip, long *lp)
+{
+  my_vprintf_scanf ("%d", ap, "%d", ip);
+  my_vprintf_scanf ("%d", ap, "%ld", lp);
+  my_vprintf_scanf ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf2 ("%d", ap, "%d", ip);
+  my_vprintf_scanf2 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf2 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf2 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf3 ("%d", ap, "%d", ip);
+  my_vprintf_scanf3 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf3 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf3 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_multattr-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_multattr-3.c
@@ -0,0 +1,29 @@
+/* Test for multiple format_arg attributes.  Test for both branches
+   getting checked.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+extern char *ngettext (const char *, const char *, unsigned long int)
+     __attribute__((__format_arg__(1))) __attribute__((__format_arg__(2)));
+
+void
+foo (long l, int nfoo)
+{
+  printf (ngettext ("%d foo", "%d foos", nfoo), nfoo);
+  printf (ngettext ("%d foo", "%d foos", l), l); /* { dg-warning "int" "wrong type in conditional expr" } */
+  printf (ngettext ("%d foo", "%ld foos", l), l); /* { dg-warning "int" "wrong type in conditional expr" } */
+  printf (ngettext ("%ld foo", "%d foos", l), l); /* { dg-warning "int" "wrong type in conditional expr" } */
+  /* Should allow one case to have extra arguments.  */
+  printf (ngettext ("1 foo", "%d foos", nfoo), nfoo);
+  printf (ngettext ("1 foo", "many foos", nfoo), nfoo); /* { dg-warning "too many" "too many args in all branches" } */
+  printf (ngettext ("", "%d foos", nfoo), nfoo);
+  printf (ngettext ("1 foo", (nfoo > 0) ? "%d foos" : "no foos", nfoo), nfoo);
+  printf (ngettext ("%d foo", (nfoo > 0) ? "%d foos" : "no foos", nfoo), nfoo);
+  printf (ngettext ("%ld foo", (nfoo > 0) ? "%d foos" : "no foos", nfoo), nfoo); /* { dg-warning "long int" "wrong type" } */
+  printf (ngettext ("%d foo", (nfoo > 0) ? "%ld foos" : "no foos", nfoo), nfoo); /* { dg-warning "long int" "wrong type" } */
+  printf (ngettext ("%d foo", (nfoo > 0) ? "%d foos" : "%ld foos", nfoo), nfoo); /* { dg-warning "long int" "wrong type" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-1.c
@@ -0,0 +1,15 @@
+/* Test for warnings for extra format arguments being disabled by
+   -Wno-format-extra-args.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wno-format-extra-args" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i)
+{
+  printf ("foo", i);
+  printf ("%1$d", i, i);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-2.c
@@ -0,0 +1,28 @@
+/* Test for warnings for extra format arguments being disabled by
+   -Wno-format-extra-args.  Test which warnings still apply with $
+   operand numbers.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wno-format-extra-args" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, int *ip, va_list va)
+{
+  printf ("%3$d%1$d", i, i, i); /* { dg-warning "before used" "unused $ operand" } */
+  printf ("%2$d%1$d", i, i, i);
+  vprintf ("%3$d%1$d", va); /* { dg-warning "before used" "unused $ operand" } */
+  /* With scanf formats, gaps in the used arguments are allowed only if the
+     arguments are all pointers.  In such a case, should only give the lesser
+     warning about unused arguments rather than the more serious one about
+     argument gaps.  */
+  scanf ("%3$d%1$d", ip, ip, ip);
+  /* If there are non-pointer arguments unused at the end, this is also OK.  */
+  scanf ("%3$d%1$d", ip, ip, ip, i);
+  scanf ("%3$d%1$d", ip, i, ip); /* { dg-warning "before used" "unused $ scanf non-pointer operand" } */
+  /* Can't check the arguments in the vscanf case, so should suppose the
+     lesser problem.  */
+  vscanf ("%3$d%1$d", va);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_no-y2k-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_no-y2k-1.c
@@ -0,0 +1,13 @@
+/* Test for warnings for Y2K problems not being on by default.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  strftime (s, m, "%y%c%x", tp);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-1.c
@@ -0,0 +1,14 @@
+/* Test for warnings for non-string-literal formats.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wformat-nonliteral" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t i)
+{
+  printf ((const char *)i, i); /* { dg-warning "argument types" "non-literal" } */
+  printf (s, i); /* { dg-warning "argument types" "non-literal" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-2.c
@@ -0,0 +1,14 @@
+/* Test for warnings for non-string-literal formats.  Test with -Wformat=2.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat=2" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t i)
+{
+  printf ((const char *)i, i); /* { dg-warning "argument types" "non-literal" } */
+  printf (s, i); /* { dg-warning "argument types" "non-literal" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-3.c
@@ -0,0 +1,13 @@
+/* Test for warnings for non-string-literal formats.  Test for strftime formats.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wformat-nonliteral" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp, char *fmt)
+{
+  strftime (s, m, fmt, tp); /* { dg-warning "format string" "non-literal" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nul-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nul-1.c
@@ -0,0 +1,15 @@
+/* Test diagnostics for suppressing contains nul
+   -Wformat.  -Wformat.  */
+/* Origin: Bruce Korb <bkorb@gnu.org> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat -Wno-format-contains-nul" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (void)
+{
+  static char const fmt[] = "x%s\0%s\n\0abc";
+  printf (fmt+4, fmt+8); /* { dg-bogus "embedded.*in format" "bogus embed warning" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nul-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nul-2.c
@@ -0,0 +1,17 @@
+/* Test diagnostics for options used on their own without
+   -Wformat.  -Wformat-.  */
+/* Origin: Bruce Korb <bkorb@gnu.org> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+
+/* { dg-warning "embedded .* in format" "ignored" { target *-*-* } 0 } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+fumble (void)
+{
+  static char const fmt[] = "x%s\0%s\n\0abc";
+  printf (fmt+4, fmt+8);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_null-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_null-1.c
@@ -0,0 +1,28 @@
+/* Test for some aspects of null format string handling.  */
+/* Origin: Jason Thorpe <thorpej@wasabisystems.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+extern void my_printf (const char *, ...) __attribute__((format(ms_printf,1,2)));
+extern const char *my_format (const char *, const char *)
+  __attribute__((format_arg(2)));
+
+void
+foo (int i1)
+{
+  /* Warning about a null format string has been decoupled from the actual
+     format check.  However, we still expect to be warned about any excess
+     arguments after a null format string.  */
+  my_printf (NULL);
+  my_printf (NULL, i1); /* { dg-warning "too many" "null format with arguments" } */
+
+  my_printf (my_format ("", NULL));
+  my_printf (my_format ("", NULL), i1); /* { dg-warning "too many" "null format_arg with arguments" } */
+
+  /* While my_printf allows a null argument, dgettext does not, so we expect
+     a null argument warning here.  */
+  my_printf (dgettext ("", NULL)); /* { dg-warning "null" "null format with dgettext" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_plus-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_plus-1.c
@@ -0,0 +1,21 @@
+/* Test for printf formats using string literal plus constant.
+ */
+/* Origin: Jakub Jelinek <jakub@redhat.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat=2" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i)
+{
+  printf ("%%d\n" + 1, i);
+  printf (5 + "%.-*d%3d\n", i);
+  printf ("%d%d" + 2, i, i);	/* { dg-warning "arguments" "wrong number of args" } */
+  printf (3 + "%d\n");		/* { dg-warning "zero-length" "zero-length string" } */
+  printf ("%d\n" + i, i);	/* { dg-warning "not a string" "non-constant addend" } */
+  printf ("%d\n" + 10);		/* { dg-warning "not a string" "too large addend" } */
+  printf ("%d\n" - 1, i);	/* { dg-warning "not a string" "minus constant" } */
+  printf ("%d\n" + -1, i);	/* { dg-warning "not a string" "negative addend" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_sec-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_sec-1.c
@@ -0,0 +1,13 @@
+/* Test for security warning when non-literal format has no arguments.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wformat-security" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s)
+{
+  printf (s); /* { dg-warning "no format arguments" "security warning" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_unnamed-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_unnamed-1.c
@@ -0,0 +1,24 @@
+/* Test for warnings with possibly unnamed integer types.  Bug 24329.  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+/* { dg-options "-Wformat -msse" { target { { i?86-*-* x86_64-*-* } && ilp32 } } } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* Definition of TItype follows same logic as in gcc.dg/titype-1.c,
+   but must be a #define to avoid giving the type a name.  */
+#if defined(__LP64__) && !defined(__hppa__)
+#define TItype int __attribute__ ((mode (TI)))
+#else
+#define TItype long
+#endif
+
+void
+f (TItype x)
+{
+  printf("%d", x); /* { dg-warning "expects type" } */
+  printf("%d", 141592653589793238462643383279502884197169399375105820974944); /* { dg-warning "expects type" } */
+  /* { dg-warning "unsigned only|too large" "constant" { target *-*-* } 22 } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_va-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_va-1.c
@@ -0,0 +1,14 @@
+/* Test for strange warning in format checking.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (void *p)
+{
+  printf ("%d", p); /* { dg-bogus "va_list" "wrong type in format warning" } */
+  /* { dg-warning "format" "format error" { target *-*-* } 12 } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_warnll-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_warnll-1.c
@@ -0,0 +1,20 @@
+/* Test for printf formats.  C99 "long long" formats should be accepted with
+   -Wno-long-long.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-pedantic -Wformat -Wno-long-long" } */
+
+/* Disabled -std=iso9899:1990 */
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (long long ll, unsigned long long ull, long long *lln,
+     long long *llp, unsigned long long *ullp)
+{
+  /* Test for accepting standard "long long" formats.  */
+  printf ("%I64d%I64i%I64o%I64u%I64x%I64X%I64n", ll, ll, ull, ull, ull, ull, lln);
+  scanf ("%I64d%I64i%I64o%I64u%I64x%I64X%I64n", llp, llp,
+	 ullp, ullp, ullp, ullp, lln);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_zero-length-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_zero-length-1.c
@@ -0,0 +1,16 @@
+/* Test the -Wno-format-zero-length option, which suppresses warnings
+   about zero-length formats.  */
+/* Origin: Jason Thorpe <thorpej@wasabisystems.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wno-format-zero-length" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (void)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.1 (pages 131-134).  */
+  /* Zero-length format strings are allowed.  */
+  printf ("");
+}
Index: gcc/gcc/testsuite/gcc.dg/format/multattr-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/multattr-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/multattr-1.c
@@ -4,6 +4,7 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 /* If we specify multiple attributes for a single function, they should
@@ -11,22 +12,22 @@
    or on different declarations.  */
 
 extern void my_vprintf_scanf (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__printf__, 1, 0)))
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)))
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
 extern void my_vprintf_scanf2 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)))
-     __attribute__((__format__(__printf__, 1, 0)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)))
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)));
 
 extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__printf__, 1, 0)));
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)));
 extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
 extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__printf__, 1, 0)));
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)));
 
 void
 foo (va_list ap, int *ip, long *lp)
Index: gcc/gcc/testsuite/gcc.dg/format/multattr-2.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/multattr-2.c
+++ gcc/gcc/testsuite/gcc.dg/format/multattr-2.c
@@ -4,21 +4,22 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 /* If we specify multiple attributes for a single function, they should
    all apply, wherever they are placed on the declarations.  */
 
-extern __attribute__((__format__(__printf__, 1, 0))) void
+extern __attribute__((__format__(gnu_attr___printf__, 1, 0))) void
      my_vprintf_scanf (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
-extern void (__attribute__((__format__(__printf__, 1, 0))) my_vprintf_scanf2)
+extern void (__attribute__((__format__(gnu_attr___printf__, 1, 0))) my_vprintf_scanf2)
      (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
-extern __attribute__((__format__(__scanf__, 3, 4))) void
-     (__attribute__((__format__(__printf__, 1, 0))) my_vprintf_scanf3)
+extern __attribute__((__format__(gnu_attr___scanf__, 3, 4))) void
+     (__attribute__((__format__(gnu_attr___printf__, 1, 0))) my_vprintf_scanf3)
      (const char *, va_list, const char *, ...);
 
 void
Index: gcc/gcc/testsuite/gcc.dg/format/null-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/null-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/null-1.c
@@ -3,9 +3,10 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern void my_printf (const char *, ...) __attribute__((format(printf,1,2)));
+extern void my_printf (const char *, ...) __attribute__((format(gnu_attr_printf,1,2)));
 extern const char *my_format (const char *, const char *)
   __attribute__((format_arg(2)));
 
=

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf formatters to c-format.c
  2008-03-16  5:54                                 ` Danny Smith
@ 2008-03-16 12:16                                   ` Kai Tietz
  2008-03-18 13:20                                   ` Kai Tietz
  1 sibling, 0 replies; 61+ messages in thread
From: Kai Tietz @ 2008-03-16 12:16 UTC (permalink / raw)
  To: Danny Smith; +Cc: Kai Tietz, GCC Patches, NightStrike

2008/3/16, Danny Smith <dansmister@gmail.com>:
> On Fri, Mar 14, 2008 at 11:55 PM, Kai Tietz <Kai.Tietz@onevision.com> w
> >  Thank you for the log file. I correct the tested cases so far. The major
> >  problem is that by your suggestion 'I64' length specifier isn't treated as
> >  equivalent to the gnu 'll' length sepecifier. This is the reason for the
> >  failure of a lot of warnings. I let the test-case ms_warnll-1.c as it is
> >  for showing the issue. I64 and co are declared as STD_EXT, which is in my
> >  opinion not correct. They should be set as STD_C890 IMHO.
> >
> >  I attached the revised patch.
>
> As I indicated earlier, handling of ms_strftime was  and still is incorrect.
>
> With your patch and this snippet:
>
> #include <time.h>
> #include <stdio.h>
> #include <sys/types.h>
>
> int main()
> {
>    char buf[128];
>    time_t ltime;
>    struct tm* today;
>
>    time (&ltime);
>    today =  localtime(&ltime);
>
>    printf ("c, x, y, formats\n");
>    strftime (buf, 128, "c: %c\n", today);
>    printf (buf);
>    strftime (buf, 128, "x: %x\n", today);
>    printf (buf);
>    strftime (buf, 128, "y: %y\n", today);
>    printf (buf);
>
>
>    printf ("Alternative #c, #x, #y, formats\n");
>    strftime (buf, 128, "#c %#c\n", today);
>    printf (buf);
>    strftime (buf, 128, "#x %#x\n", today);
>    printf (buf);
>    strftime (buf, 128, "#y %#y\n", today);
>    printf (buf);
>
>    return 0;
> }
>
> compiled as
>
> gcc -Wall  -Wformat-y2k ms_stftrime_y2k.c
>
> I get:
>
> ms_stftrime_y2k.c: In function 'main':
> ms_stftrime_y2k.c:24: warning: '#' flag used with '%c' ms_strftime format
> ms_stftrime_y2k.c: warning: '#' flag used with '%x' ms_strftime format
> ms_stftrime_y2k.c:28: warning: '#' flag used with '%y' ms_strftime format
>
> 1) The warnings are bogus.
> 2) There are no  y2k warnings, but there should be, because this is the output:
>
> c, x, y, formats
> c: 03/16/08 16:05:38
> x: 03/16/08
> y: 08
> Alternative #c, #x, #y, formats
> #c Sunday, March 16, 2008 16:05:38
> #x Sunday, March 16, 2008
> #y 8

I will take a look, why the y2k warning is not emitted. I think this
has something to do with the c part, where indexes are used to
identify the kind.

> Note that '#' does not have glibc meaning.  Instead,  when prefixing c
> and x flags, is like 'E'.
>
> http://msdn2.microsoft.com/en-us/library/fe06s4ak(vs.71).aspx
Ok, I see. The '#' is valid for all format flags of strftime and just
indicates, that leading zeros should be suppressed, isn't it?
I sent tomorrow an update for this.

Cheers,
  Kai
-- 
|  (\_/) This is Bunny. Copy and paste
| (='.'=) Bunny into your signature to help
| (")_(") him gain world domination

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf formatters to c-format.c
  2008-03-14 11:00                               ` Kai Tietz
@ 2008-03-16  5:54                                 ` Danny Smith
  2008-03-16 12:16                                   ` Kai Tietz
  2008-03-18 13:20                                   ` Kai Tietz
  0 siblings, 2 replies; 61+ messages in thread
From: Danny Smith @ 2008-03-16  5:54 UTC (permalink / raw)
  To: Kai Tietz; +Cc: GCC Patches, ktietz70, NightStrike

On Fri, Mar 14, 2008 at 11:55 PM, Kai Tietz <Kai.Tietz@onevision.com> w
>  Thank you for the log file. I correct the tested cases so far. The major
>  problem is that by your suggestion 'I64' length specifier isn't treated as
>  equivalent to the gnu 'll' length sepecifier. This is the reason for the
>  failure of a lot of warnings. I let the test-case ms_warnll-1.c as it is
>  for showing the issue. I64 and co are declared as STD_EXT, which is in my
>  opinion not correct. They should be set as STD_C890 IMHO.
>
>  I attached the revised patch.

As I indicated earlier, handling of ms_strftime was  and still is incorrect.

With your patch and this snippet:

#include <time.h>
#include <stdio.h>
#include <sys/types.h>

int main()
{
    char buf[128];
    time_t ltime;
    struct tm* today;

    time (&ltime);
    today =  localtime(&ltime);

    printf ("c, x, y, formats\n");
    strftime (buf, 128, "c: %c\n", today);
    printf (buf);
    strftime (buf, 128, "x: %x\n", today);
    printf (buf);
    strftime (buf, 128, "y: %y\n", today);
    printf (buf);


    printf ("Alternative #c, #x, #y, formats\n");
    strftime (buf, 128, "#c %#c\n", today);
    printf (buf);
    strftime (buf, 128, "#x %#x\n", today);
    printf (buf);
    strftime (buf, 128, "#y %#y\n", today);
    printf (buf);

    return 0;
}

compiled as

gcc -Wall  -Wformat-y2k ms_stftrime_y2k.c

I get:

ms_stftrime_y2k.c: In function 'main':
ms_stftrime_y2k.c:24: warning: '#' flag used with '%c' ms_strftime format
ms_stftrime_y2k.c: warning: '#' flag used with '%x' ms_strftime format
ms_stftrime_y2k.c:28: warning: '#' flag used with '%y' ms_strftime format

1) The warnings are bogus.
2) There are no  y2k warnings, but there should be, because this is the output:

c, x, y, formats
c: 03/16/08 16:05:38
x: 03/16/08
y: 08
Alternative #c, #x, #y, formats
#c Sunday, March 16, 2008 16:05:38
#x Sunday, March 16, 2008
#y 8


Note that '#' does not have glibc meaning.  Instead,  when prefixing c
and x flags, is like 'E'.

http://msdn2.microsoft.com/en-us/library/fe06s4ak(vs.71).aspx

Danny

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf  formatters to c-format.c
  2008-03-13 20:52                             ` Danny Smith
@ 2008-03-14 11:00                               ` Kai Tietz
  2008-03-16  5:54                                 ` Danny Smith
  0 siblings, 1 reply; 61+ messages in thread
From: Kai Tietz @ 2008-03-14 11:00 UTC (permalink / raw)
  To: Danny Smith; +Cc: GCC Patches, ktietz70, NightStrike

[-- Attachment #1: Type: text/plain, Size: 1070 bytes --]

"Danny Smith" <dansmister@gmail.com> wrote on 13.03.2008 21:40:40:

> >  >
> >  > I see 44 format.exp failures in testsuite  with your patch
> >  I corrected the test-cases so far.
> 
> Well I suppose one way to correct the test case is just to remove some
> tests, but your revised patch doesn't really address the problems with
> strftime.
> Attached is log of "make -k check-gcc RUNTESTFLAGS=format.exp" using
> prior patch.  Do you not see these errors?

Thank you for the log file. I correct the tested cases so far. The major 
problem is that by your suggestion 'I64' length specifier isn't treated as 
equivalent to the gnu 'll' length sepecifier. This is the reason for the 
failure of a lot of warnings. I let the test-case ms_warnll-1.c as it is 
for showing the issue. I64 and co are declared as STD_EXT, which is in my 
opinion not correct. They should be set as STD_C890 IMHO.

I attached the revised patch.

Cheers,
 i.A. Kai Tietz



|  (\_/)  This is Bunny. Copy and paste Bunny
| (='.'=) into your signature to help him gain
| (")_(") world domination.

[-- Attachment #2: mingw-msformat.txt --]
[-- Type: text/plain, Size: 151168 bytes --]

Index: gcc/gcc/c-format.c
===================================================================
--- gcc.orig/gcc/c-format.c
+++ gcc/gcc/c-format.c
@@ -62,8 +62,7 @@ enum format_type { printf_format_type, a
 		   gcc_diag_format_type, gcc_tdiag_format_type,
 		   gcc_cdiag_format_type,
 		   gcc_cxxdiag_format_type, gcc_gfc_format_type,
-		   scanf_format_type, strftime_format_type,
-		   strfmon_format_type, format_type_error = -1};
+		   format_type_error = -1};
 
 typedef struct function_format_info
 {
@@ -80,7 +79,8 @@ static bool check_format_string (tree ar
 				 int flags, bool *no_add_attrs);
 static bool get_constant (tree expr, unsigned HOST_WIDE_INT *value,
 			  int validated_p);
-
+static const char *convert_format_name_to_system_name (const char *attr_name);
+static bool cmp_attribs (const char *tattr_name, const char *attr_name);
 
 /* Handle a "format_arg" attribute; arguments as in
    struct attribute_spec.handler.  */
@@ -191,6 +191,8 @@ decode_format_attr (tree args, function_
     {
       const char *p = IDENTIFIER_POINTER (format_type_id);
 
+      p = convert_format_name_to_system_name (p);
+
       info->format_type = decode_format_type (p);
 
       if (info->format_type == format_type_error)
@@ -715,7 +717,7 @@ static const format_char_info monetary_c
 /* This must be in the same order as enum format_type.  */
 static const format_kind_info format_types_orig[] =
 {
-  { "printf",   printf_length_specs,  print_char_table, " +#0-'I", NULL,
+  { "gnu_printf",   printf_length_specs,  print_char_table, " +#0-'I", NULL,
     printf_flag_specs, printf_flag_pairs,
     FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
     'w', 0, 'p', 0, 'L', 0,
@@ -757,18 +759,18 @@ static const format_kind_info format_typ
     0, 0, 0, 0, 0, 0,
     NULL, NULL
   },
-  { "scanf",    scanf_length_specs,   scan_char_table,  "*'I", NULL,
+  { "gnu_scanf",    scanf_length_specs,   scan_char_table,  "*'I", NULL,
     scanf_flag_specs, scanf_flag_pairs,
     FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
     'w', 0, 0, '*', 'L', 'm',
     NULL, NULL
   },
-  { "strftime", NULL,                 time_char_table,  "_-0^#", "EO",
+  { "gnu_strftime", NULL,                 time_char_table,  "_-0^#", "EO",
     strftime_flag_specs, strftime_flag_pairs,
     FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0, 0,
     NULL, NULL
   },
-  { "strfmon",  strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
+  { "gnu_strfmon",  strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
     strfmon_flag_specs, strfmon_flag_pairs,
     FMT_FLAG_ARG_CONVERT, 'w', '#', 'p', 0, 'L', 0,
     NULL, NULL
@@ -847,6 +849,8 @@ decode_format_type (const char *s)
 {
   int i;
   int slen;
+
+  s = convert_format_name_to_system_name (s);
   slen = strlen (s);
   for (i = 0; i < n_format_types; i++)
     {
@@ -1776,7 +1780,22 @@ check_format_info_main (format_check_res
       if (fli)
 	{
 	  while (fli->name != 0 && fli->name[0] != *format_chars)
-	    fli++;
+	    {
+	      if (fli->name[0] == '\0')
+		{
+		  int si  = strlen (fli->name + 1) + 1;
+		  int i = 1;
+		  while (fli->name[i] != 0 && fli->name[i] == format_chars [i - 1])
+		    ++i;
+		 if (si == i)
+		   {
+		     if (si > 2)
+		       format_chars += si - 2;
+		     break;
+		   }
+	       }
+	      fli++;
+	    }
 	  if (fli->name != 0)
 	    {
 	      format_chars++;
@@ -2703,6 +2722,84 @@ init_dynamic_diag_info (void)
 extern const format_kind_info TARGET_FORMAT_TYPES[];
 #endif
 
+#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+extern const target_ovr_attr TARGET_OVERRIDES_FORMAT_ATTRIBUTES[];
+#endif
+
+/* Attributes such as "printf" are equivalent to those such as
+   "gnu_printf" unless this is overridden by a target.  */
+static const target_ovr_attr gnu_target_overrides_format_attributes[] =
+{
+  { "gnu_printf",   "printf" },
+  { "gnu_scanf",    "scanf" },
+  { "gnu_strftime", "strftime" },
+  { "gnu_strfmon",  "strfmon" },
+  { NULL,           NULL }
+};
+
+/* Translate to unified attribute name. This is used in decode_format_type and
+   decode_format_attr. In attr_name the user specified argument is passed. It
+   returns the unified format name from TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+   or the attr_name passed to this function, if there is no matching entry.  */
+static const char *
+convert_format_name_to_system_name (const char *attr_name)
+{
+  int i;
+
+  if (attr_name == NULL || *attr_name == 0
+      || strncmp (attr_name, "gcc_", 4) == 0)
+    return attr_name;
+
+#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+  /* Check if format attribute is overridden by target.  */
+  if (TARGET_OVERRIDES_FORMAT_ATTRIBUTES != NULL
+      && TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT > 0)
+    {
+      for (i = 0; i < TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT; ++i)
+        {
+          if (cmp_attribs (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src,
+			   attr_name))
+            return attr_name;
+          if (cmp_attribs (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_dst,
+			   attr_name))
+            return TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src;
+        }
+    }
+#endif
+  /* Otherwise default to gnu format.  */
+  for (i = 0;
+       gnu_target_overrides_format_attributes[i].named_attr_src != NULL;
+       ++i)
+    {
+      if (cmp_attribs (gnu_target_overrides_format_attributes[i].named_attr_src,
+		       attr_name))
+        return attr_name;
+      if (cmp_attribs (gnu_target_overrides_format_attributes[i].named_attr_dst,
+		       attr_name))
+        return gnu_target_overrides_format_attributes[i].named_attr_src;
+    }
+
+  return attr_name;
+}
+
+/* Return true if TATTR_NAME and ATTR_NAME are the same format attribute,
+   counting "name" and "__name__" as the same, false otherwise.  */
+static bool
+cmp_attribs (const char *tattr_name, const char *attr_name)
+{
+  int alen = strlen (attr_name);
+  int slen = (tattr_name ? strlen (tattr_name) : 0);
+  if (alen > 4 && attr_name[0] == '_' && attr_name[1] == '_'
+      && attr_name[alen - 1] == '_' && attr_name[alen - 2] == '_')
+    {
+      attr_name += 2;
+      alen -= 4;
+    }
+  if (alen != slen || strncmp (tattr_name, attr_name, alen) != 0)
+    return false;
+  return true;
+}
+
 /* Handle a "format" attribute; arguments as in
    struct attribute_spec.handler.  */
 tree
@@ -2762,7 +2859,10 @@ handle_format_attribute (tree *node, tre
 	}
     }
 
-  if (info.format_type == strftime_format_type && info.first_arg_num != 0)
+  /* Check if this is a strftime variant. Just for this variant
+     FMT_FLAG_ARG_CONVERT is not set.  */
+  if ((format_types[info.format_type].flags & (int) FMT_FLAG_ARG_CONVERT) == 0
+      && info.first_arg_num != 0)
     {
       error ("strftime formats cannot format arguments");
       *no_add_attrs = true;
Index: gcc/gcc/c-format.h
===================================================================
--- gcc.orig/gcc/c-format.h
+++ gcc/gcc/c-format.h
@@ -80,12 +80,13 @@ enum
      of whether length modifiers can occur (length_char_specs).  */
 };
 
-
 /* Structure describing a length modifier supported in format checking, and
    possibly a doubled version such as "hh".  */
 typedef struct
 {
-  /* Name of the single-character length modifier.  */
+  /* Name of the single-character length modifier. If prefixed by
+     a zero character, it describes a multi character length
+     modifier, like I64, I32, etc.  */
   const char *name;
   /* Index into a format_char_info.types array.  */
   enum format_lengths index;
@@ -306,4 +307,16 @@ typedef struct
 #define T_D128  &dfloat128_type_node
 #define TEX_D128 { STD_EXT, "_Decimal128", T_D128 }
 
+/* Structure describing how format attributes such as "printf" are
+   interpreted as "gnu_printf" or "ms_printf" on a particular system.
+   TARGET_OVERRIDES_FORMAT_ATTRIBUTES is used to specify target-specific
+   defaults.  */
+typedef struct
+{
+  /* The name of the to be copied format attribute. */
+  const char *named_attr_src;
+  /* The name of the to be overridden format attribute. */
+  const char *named_attr_dst;
+} target_ovr_attr;
+
 #endif /* GCC_C_FORMAT_H */
Index: gcc/gcc/config.gcc
===================================================================
--- gcc.orig/gcc/config.gcc
+++ gcc/gcc/config.gcc
@@ -1372,8 +1372,8 @@ i[34567]86-*-pe | i[34567]86-*-cygwin*)
 	target_gtfiles="\$(srcdir)/config/i386/winnt.c"
 	extra_options="${extra_options} i386/cygming.opt"
 	extra_objs="winnt.o winnt-stubs.o"
-	c_target_objs=cygwin2.o
-	cxx_target_objs="cygwin2.o winnt-cxx.o"
+	c_target_objs="cygwin2.o msformat-c.o"
+	cxx_target_objs="cygwin2.o winnt-cxx.o msformat-c.o"
 	extra_gcc_objs=cygwin1.o
 	if test x$enable_threads = xyes; then
 		thread_file='posix'
@@ -1386,7 +1386,8 @@ i[34567]86-*-mingw32* | x86_64-*-mingw32
 	target_gtfiles="\$(srcdir)/config/i386/winnt.c"
 	extra_options="${extra_options} i386/cygming.opt"
 	extra_objs="winnt.o winnt-stubs.o"
-	cxx_target_objs=winnt-cxx.o
+	c_target_objs="msformat-c.o"
+	cxx_target_objs="winnt-cxx.o msformat-c.o"
 	default_use_cxa_atexit=yes
 	case ${enable_threads} in
 	  "" | yes | win32)
Index: gcc/gcc/config/i386/mingw32.h
===================================================================
--- gcc.orig/gcc/config/i386/mingw32.h
+++ gcc/gcc/config/i386/mingw32.h
@@ -143,6 +143,23 @@ do {						         \
    to register C++ static destructors.  */
 #define TARGET_CXX_USE_ATEXIT_FOR_CXA_ATEXIT hook_bool_void_true
 
+/* Contains a pointer to type target_ovr_attr defining the target specific
+   overrides of format attributes.  See c-format.h for structure
+   definition.  */
+#undef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+#define TARGET_OVERRIDES_FORMAT_ATTRIBUTES mingw_format_attribute_overrides
+
+/* Specify the count of elements in TARGET_OVERRIDES_ATTRIBUTE.  */
+#undef TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT
+#define TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT 3
+
+/* MS specific format attributes for ms_printf, ms_scanf, ms_strftime.  */
+#undef TARGET_FORMAT_TYPES
+#define TARGET_FORMAT_TYPES mingw_format_attributes
+
+#undef TARGET_N_FORMAT_TYPES
+#define TARGET_N_FORMAT_TYPES 3
+
 /* JCR_SECTION works on mingw32.  */
 #undef TARGET_USE_JCR_SECTION
 #define TARGET_USE_JCR_SECTION 1
Index: gcc/gcc/config/i386/msformat-c.c
===================================================================
--- /dev/null
+++ gcc/gcc/config/i386/msformat-c.c
@@ -0,0 +1,176 @@
+/* Check calls to formatted I/O functions (-Wformat).
+   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+   2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "flags.h"
+#include "c-common.h"
+#include "toplev.h"
+#include "intl.h"
+#include "diagnostic.h"
+#include "langhooks.h"
+#include "c-format.h"
+#include "alloc-pool.h"
+
+/* Mingw specific format attributes ms_printf, ms_scanf, and ms_strftime.  */
+
+static const format_length_info ms_printf_length_specs[] =
+{
+  { "h", FMT_LEN_h, STD_C89, NULL, 0, 0 },
+  { "l", FMT_LEN_l, STD_C89, NULL, 0, 0 },
+  { "\0I32", FMT_LEN_l, STD_EXT, NULL, 0, 0 },
+  { "\0I64", FMT_LEN_ll, STD_EXT, NULL, 0, 0 },
+  { "I", FMT_LEN_L, STD_EXT, NULL, 0, 0 },
+  { NULL, 0, 0, NULL, 0, 0 }
+};
+
+static const format_flag_spec ms_printf_flag_specs[] =
+{
+  { ' ',  0, 0, N_("' ' flag"),        N_("the ' ' printf flag"),              STD_C89 },
+  { '+',  0, 0, N_("'+' flag"),        N_("the '+' printf flag"),              STD_C89 },
+  { '#',  0, 0, N_("'#' flag"),        N_("the '#' printf flag"),              STD_C89 },
+  { '0',  0, 0, N_("'0' flag"),        N_("the '0' printf flag"),              STD_C89 },
+  { '-',  0, 0, N_("'-' flag"),        N_("the '-' printf flag"),              STD_C89 },
+  { '\'', 0, 0, N_("''' flag"),        N_("the ''' printf flag"),              STD_EXT },
+  { 'w',  0, 0, N_("field width"),     N_("field width in printf format"),     STD_C89 },
+  { 'p',  0, 0, N_("precision"),       N_("precision in printf format"),       STD_C89 },
+  { 'L',  0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_printf_flag_pairs[] =
+{
+  { ' ', '+', 1, 0   },
+  { '0', '-', 1, 0   }, { '0', 'p', 1, 'i' },
+  { 0, 0, 0, 0 }
+};
+
+static const format_flag_spec ms_scanf_flag_specs[] =
+{
+  { '*',  0, 0, N_("assignment suppression"), N_("the assignment suppression scanf feature"), STD_C89 },
+  { 'a',  0, 0, N_("'a' flag"),               N_("the 'a' scanf flag"),                       STD_EXT },
+  { 'w',  0, 0, N_("field width"),            N_("field width in scanf format"),              STD_C89 },
+  { 'L',  0, 0, N_("length modifier"),        N_("length modifier in scanf format"),          STD_C89 },
+  { '\'', 0, 0, N_("''' flag"),               N_("the ''' scanf flag"),                       STD_EXT },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_scanf_flag_pairs[] =
+{
+  { '*', 'L', 0, 0 },
+  { 0, 0, 0, 0 }
+};
+
+static const format_flag_spec ms_strftime_flag_specs[] =
+{
+  { '#', 0,   0, N_("'#' flag"),     N_("the '#' strftime flag"),          STD_EXT },
+  { 'w', 0,   0, N_("field width"),  N_("field width in strftime format"), STD_EXT },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_strftime_flag_pairs[] =
+{
+  { 0, 0, 0, 0 }
+};
+
+static const format_char_info ms_print_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "di",  0, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  T99_SST,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-wp0 +'",  "i",  NULL },
+  { "oxX", 0, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN, BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "-wp0#",     "i",  NULL },
+  { "u",   0, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN, BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "-wp0'",    "i",  NULL },
+  { "fgG", 0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "-wp0 +#'", "",   NULL },
+  { "eE",  0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "-wp0 +#",  "",   NULL },
+  { "c",   0, STD_C89, { T89_I,   BADLEN,  T89_S,  T94_WI,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "",   NULL },
+  { "s",   1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-wp",       "cR", NULL },
+  { "p",   1, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "c",  NULL },
+  { "n",   1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  BADLEN,  BADLEN, BADLEN,  T99_IM,  BADLEN,  BADLEN,  BADLEN }, "",          "W",  NULL },
+  /* X/Open conversion specifiers.  */
+  { "C",   0, STD_EXT, { TEX_WI,  BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "",   NULL },
+  { "S",   1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-wp",       "R",  NULL },
+  { NULL,  0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+static const format_char_info ms_scan_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "di",    1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  T99_SST,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w'", "W",   NULL },
+  { "u",     1, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN,  BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "*w'", "W",   NULL },
+  { "oxX",   1, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN,  BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "efgEG", 1, STD_C89, { T89_F,   BADLEN,  BADLEN,  T89_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "*w'",  "W",   NULL },
+  { "c",     1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "cW",  NULL },
+  { "s",     1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "cW",  NULL },
+  { "[",     1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "cW[", NULL },
+  { "p",     2, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "n",     1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  BADLEN,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "",     "W",   NULL },
+  /* X/Open conversion specifiers.  */
+  { "C",     1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "S",     1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "W",   NULL },
+  { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+static const format_char_info ms_time_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "ABZab",		0, STD_C89, NOLENGTHS, "#",     "",   NULL },
+  { "cx",		0, STD_C89, NOLENGTHS, "",      "",  NULL },
+  { "HIMSUWdmw",	0, STD_C89, NOLENGTHS, "w",  "",   NULL },
+  { "j",		0, STD_C89, NOLENGTHS, "w",  "",  NULL },
+  { "p",		0, STD_C89, NOLENGTHS, "#",      "",   NULL },
+  { "X",		0, STD_C89, NOLENGTHS, "",      "",   NULL },
+  { "y",		0, STD_C89, NOLENGTHS, "w", "",  NULL },
+  { "Y",		0, STD_C89, NOLENGTHS, "w", "",  NULL },
+  { "%",		0, STD_C89, NOLENGTHS, "",       "",   NULL },
+  /* C99 conversion specifiers.  */
+  { "z",		0, STD_C99, NOLENGTHS, "",      "",  NULL },
+  { NULL,		0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+const format_kind_info mingw_format_attributes[3] =
+{
+  { "ms_printf",   ms_printf_length_specs,  ms_print_char_table, " +#0-'", NULL,
+    ms_printf_flag_specs, ms_printf_flag_pairs,
+    FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
+    'w', 0, 'p', 0, 'L', 0,
+    &integer_type_node, &integer_type_node
+  },
+  { "ms_scanf",    ms_printf_length_specs,   ms_scan_char_table,  "*'", NULL,
+    ms_scanf_flag_specs, ms_scanf_flag_pairs,
+    FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
+    'w', 0, 0, '*', 'L', 0,
+    NULL, NULL
+  },
+  { "ms_strftime", NULL,                 ms_time_char_table,  "#", "",
+    ms_strftime_flag_specs, ms_strftime_flag_pairs,
+    FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0, 0,
+    NULL, NULL
+  }
+};
+
+/* Default overrides for printf, scanf and strftime.  */
+const target_ovr_attr mingw_format_attribute_overrides[4] =
+{
+  { "ms_printf", "printf" },
+  { "ms_scanf", "scanf" },
+  { "ms_strftime", "strftime" }
+};
Index: gcc/gcc/config/i386/t-cygming
===================================================================
--- gcc.orig/gcc/config/i386/t-cygming
+++ gcc/gcc/config/i386/t-cygming
@@ -29,4 +29,10 @@ winnt-stubs.o: $(srcdir)/config/i386/win
 	$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
 	$(srcdir)/config/i386/winnt-stubs.c
 
+msformat-c.o: $(srcdir)/config/i386/msformat-c.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
+  $(TM_H) $(RTL_H) $(REGS_H) hard-reg-set.h output.h $(TREE_H) flags.h \
+  $(TM_P_H) toplev.h $(HASHTAB_H) $(GGC_H)
+	$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
+	$(srcdir)/config/i386/msformat-c.c
+
 STMP_FIXINC=stmp-fixinc
Index: gcc/gcc/doc/extend.texi
===================================================================
--- gcc.orig/gcc/doc/extend.texi
+++ gcc/gcc/doc/extend.texi
@@ -2204,13 +2204,22 @@ for consistency with the @code{printf} s
 @code{my_format}.
 
 The parameter @var{archetype} determines how the format string is
-interpreted, and should be @code{printf}, @code{scanf}, @code{strftime}
-or @code{strfmon}.  (You can also use @code{__printf__},
-@code{__scanf__}, @code{__strftime__} or @code{__strfmon__}.)  The
-parameter @var{string-index} specifies which argument is the format
-string argument (starting from 1), while @var{first-to-check} is the
-number of the first argument to check against the format string.  For
-functions where the arguments are not available to be checked (such as
+interpreted, and should be @code{printf}, @code{scanf}, @code{strftime},
+@code{gnu_printf}, @code{gnu_scanf}, @code{gnu_strftime} or
+@code{strfmon}.  (You can also use @code{__printf__},
+@code{__scanf__}, @code{__strftime__} or @code{__strfmon__}.)  On
+MinGW targets, @code{ms_printf}, @code{ms_scanf}, and
+@code{ms_strftime} are also present.
+@var{archtype} values such as @code{printf} refer to the formats accepted
+by the system's C run-time library, while @code{gnu_} values always refer
+to the formats accepted by the GNU C Library.  On Microsoft Windows
+targets, @code{ms_} values refer to the formats accepted by the
+@file{msvcrt.dll} library.
+The parameter @var{string-index}
+specifies which argument is the format string argument (starting
+from 1), while @var{first-to-check} is the number of the first
+argument to check against the format string.  For functions
+where the arguments are not available to be checked (such as
 @code{vprintf}), specify the third parameter as zero.  In this case the
 compiler only checks the format string for consistency.  For
 @code{strftime} formats, the third parameter is required to be zero.
Index: gcc/gcc/doc/tm.texi
===================================================================
--- gcc.orig/gcc/doc/tm.texi
+++ gcc/gcc/doc/tm.texi
@@ -10319,6 +10319,18 @@ If defined, this macro is the number of 
 @code{TARGET_FORMAT_TYPES}.
 @end defmac
 
+@defmac TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+If defined, this macro is the name of a global variable containing
+target-specific format overrides for the @option{-Wformat} option. The
+default is to have no target-specific format overrides. If defined,
+@code{TARGET_FORMAT_TYPES} must be defined, too.
+@end defmac
+
+@defmac TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT
+If defined, this macro specifies the number of entries in
+@code{TARGET_OVERRIDES_FORMAT_ATTRIBUTES}.
+@end defmac
+
 @deftypefn {Target Hook} bool TARGET_RELAXED_ORDERING
 If set to @code{true}, means that the target's memory model does not
 guarantee that loads which do not depend on one another will access
Index: gcc/gcc/testsuite/gcc.dg/format/format.h
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/format.h
+++ gcc/gcc/testsuite/gcc.dg/format/format.h
@@ -1,6 +1,37 @@
 /* Format checking tests: common header.  */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
 
+/* DONT_GNU_PROTOTYPE */
+#if defined (_WIN32) && !defined (__CYGWIN__)
+#if !defined (USE_SYSTEM_FORMATS)
+#define gnu_attr_printf	gnu_printf
+#define gnu_attr___printf__ __gnu_printf__
+#define gnu_attr_scanf	gnu_scanf
+#define gnu_attr___scanf__ __gnu_scanf__
+#define gnu_attr_strftime gnu_strftime
+#define gnu_attr___strftime__ __gnu_strftime__
+#endif
+#endif
+
+#ifndef gnu_attr_printf
+#define gnu_attr_printf	printf
+#define gnu_attr___printf__ __printf__
+#define gnu_attr_scanf	scanf
+#define gnu_attr___scanf__ __scanf__
+#define gnu_attr_strftime strftime
+#define gnu_attr___strftime__ __strftime__
+#endif
+
+#if !defined (USE_SYSTEM_FORMATS)
+#define USE_PRINTF(FMTPOS, WILDARG) __attribute__((format(gnu_printf, FMTPOS, WILDARG))) __attribute__((nonnull (FMTPOS)))
+#define USE_SCANF(FMTPOS, WILDARG) __attribute__((format(gnu_scanf, FMTPOS, WILDARG))) __attribute__((nonnull (FMTPOS)))
+#define USE_STRFTIME(FMTPOS) __attribute__((__format__(gnu_strftime, FMTPOS, 0))) __attribute__((nonnull (FMTPOS)))
+#else
+#define USE_PRINTF(FMTPOS, WILDARG)
+#define USE_SCANF(FMTPOS, WILDARG)
+#define USE_STRFTIME(FMTPOS)
+#endif
+
 #include <stdarg.h>
 #include <stddef.h>
 
@@ -11,6 +42,20 @@
 typedef __WINT_TYPE__ wint_t;
 #endif
 
+#ifdef _WIN64
+/* Kludges to get types corresponding to size_t and ptrdiff_t.  */
+#define unsigned signed
+typedef signed int signed_size_t __attribute__ ((mode (DI)));
+/* We also use this type to approximate ssize_t.  */
+typedef signed int ssize_t __attribute__ ((mode (DI)));
+#undef unsigned
+#define signed /* Type might or might not have explicit 'signed'.  */
+typedef unsigned int unsigned_ptrdiff_t __attribute__ ((mode (DI)));
+#undef signed
+
+__extension__ typedef int llong  __attribute__ ((mode (DI)));
+__extension__ typedef unsigned int ullong  __attribute__ ((mode (DI)));
+#else
 /* Kludges to get types corresponding to size_t and ptrdiff_t.  */
 #define unsigned signed
 typedef __SIZE_TYPE__ signed_size_t;
@@ -23,6 +68,7 @@ typedef unsigned __PTRDIFF_TYPE__ unsign
 
 __extension__ typedef long long int llong;
 __extension__ typedef unsigned long long int ullong;
+#endif
 
 /* %q formats want a "quad"; GCC considers this to be a long long.  */
 typedef llong quad_t;
@@ -70,3 +116,77 @@ extern size_t strftime (char *restrict, 
 			const struct tm *restrict);
 
 extern ssize_t strfmon (char *restrict, size_t, const char *restrict, ...);
+
+/* Mingw specific part.  */
+#if !defined (USE_SYSTEM_FORMATS) && defined(_WIN32) && !defined(DONT_GNU_PROTOTYPE)
+
+extern USE_PRINTF(2,3) int fprintf_gnu (FILE *restrict, const char *restrict, ...);
+#undef fprintf
+#define fprintf fprintf_gnu
+
+extern USE_PRINTF(1,2) int printf_gnu (const char *restrict, ...);
+#undef printf
+#define printf printf_gnu
+
+extern USE_PRINTF(2,3) int fprintf_unlocked_gnu (FILE *restrict, const char *restrict, ...);
+#undef fprintf_unlocked
+#define fprintf_unlocked fprintf_unlocked_gnu
+
+extern USE_PRINTF(1,2)int printf_unlocked_gnu (const char *restrict, ...);
+#undef printf_unlocked
+#define printf_unlocked printf_unlocked_gnu
+
+extern USE_PRINTF(2,3) int sprintf_gnu (char *restrict, const char *restrict, ...);
+#undef sprintf
+#define sprintf sprintf_gnu
+
+extern USE_PRINTF(2,0) int vfprintf_gnu (FILE *restrict, const char *restrict, va_list);
+#undef vsprintf
+#define vsprintf vsprintf_gnu
+
+extern USE_PRINTF(1,0) int vprintf_gnu (const char *restrict, va_list);
+#undef vprintf
+#define vprintf vprintf_gnu
+
+extern USE_PRINTF(2,0) int vsprintf_gnu (char *restrict, const char *restrict, va_list);
+#undef vsprintf
+#define vsprintf vsprintf_gnu
+
+extern USE_PRINTF(3,4) int snprintf_gnu (char *restrict, size_t, const char *restrict, ...);
+#undef snprintf
+#define snprintf snprintf_gnu
+
+extern USE_PRINTF(3,0) int vsnprintf_gnu (char *restrict, size_t, const char *restrict, va_list);
+#undef vsnprintf
+#define vsnprintf vsnprintf_gnu
+
+extern USE_SCANF(2,3) int fscanf_gnu (FILE *restrict, const char *restrict, ...);
+#undef fscanf
+#define fscanf fscanf_gnu
+
+extern USE_SCANF(1,2) int scanf_gnu (const char *restrict, ...);
+#undef scanf
+#define scanf scanf_gnu
+
+extern USE_SCANF(2,3) int sscanf_gnu (const char *restrict, const char *restrict, ...);
+#undef sscanf
+#define sscanf sscanf_gnu
+
+extern USE_SCANF(2,0) int vfscanf_gnu (FILE *restrict, const char *restrict, va_list);
+#undef vfscanf
+#define vfscanf vfscanf_gnu
+
+extern USE_SCANF(1,0) int vscanf_gnu (const char *restrict, va_list);
+#undef vscanf
+#define vscanf vscanf_gnu
+
+extern USE_SCANF(2,0) int vsscanf_gnu (const char *restrict, const char *restrict, va_list);
+#undef vsscanf
+#define vsscanf vsscanf_gnu
+
+extern USE_STRFTIME(3) size_t strftime_gnu (char *restrict, size_t, const char *restrict,
+			const struct tm *restrict);
+#undef strftime
+#define strftime strftime_gnu
+
+#endif
Index: gcc/gcc/testsuite/gcc.dg/format/attr-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-1.c
@@ -3,7 +3,8 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern void foo0 (const char *) __attribute__((__format__(__strftime__, 1, 0)));
-extern void foo1 (const char *, ...) __attribute__((__format__(__strftime__, 1, 2))); /* { dg-error "cannot format" "strftime first_arg_num != 0" } */
+extern void foo0 (const char *) __attribute__((__format__(gnu_attr___strftime__, 1, 0)));
+extern void foo1 (const char *, ...) __attribute__((__format__(gnu_attr___strftime__, 1, 2))); /* { dg-error "cannot format" "strftime first_arg_num != 0" } */
Index: gcc/gcc/testsuite/gcc.dg/format/attr-2.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-2.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-2.c
@@ -3,22 +3,23 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern void tformatprintf (const char *, ...) __attribute__((format(printf, 1, 2)));
-extern void tformat__printf__ (const char *, ...) __attribute__((format(__printf__, 1, 2)));
-extern void tformatscanf (const char *, ...) __attribute__((format(scanf, 1, 2)));
-extern void tformat__scanf__ (const char *, ...) __attribute__((format(__scanf__, 1, 2)));
-extern void tformatstrftime (const char *) __attribute__((format(strftime, 1, 0)));
-extern void tformat__strftime__ (const char *) __attribute__((format(__strftime__, 1, 0)));
+extern void tformatprintf (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
+extern void tformat__printf__ (const char *, ...) __attribute__((format(gnu_attr___printf__, 1, 2)));
+extern void tformatscanf (const char *, ...) __attribute__((format(gnu_attr_scanf, 1, 2)));
+extern void tformat__scanf__ (const char *, ...) __attribute__((format(gnu_attr___scanf__, 1, 2)));
+extern void tformatstrftime (const char *) __attribute__((format(gnu_attr_strftime, 1, 0)));
+extern void tformat__strftime__ (const char *) __attribute__((format(gnu_attr___strftime__, 1, 0)));
 extern void tformatstrfmon (const char *, ...) __attribute__((format(strfmon, 1, 2)));
 extern void tformat__strfmon__ (const char *, ...) __attribute__((format(__strfmon__, 1, 2)));
-extern void t__format__printf (const char *, ...) __attribute__((__format__(printf, 1, 2)));
-extern void t__format____printf__ (const char *, ...) __attribute__((__format__(__printf__, 1, 2)));
-extern void t__format__scanf (const char *, ...) __attribute__((__format__(scanf, 1, 2)));
-extern void t__format____scanf__ (const char *, ...) __attribute__((__format__(__scanf__, 1, 2)));
-extern void t__format__strftime (const char *) __attribute__((__format__(strftime, 1, 0)));
-extern void t__format____strftime__ (const char *) __attribute__((__format__(__strftime__, 1, 0)));
+extern void t__format__printf (const char *, ...) __attribute__((__format__(gnu_attr_printf, 1, 2)));
+extern void t__format____printf__ (const char *, ...) __attribute__((__format__(gnu_attr___printf__, 1, 2)));
+extern void t__format__scanf (const char *, ...) __attribute__((__format__(gnu_attr_scanf, 1, 2)));
+extern void t__format____scanf__ (const char *, ...) __attribute__((__format__(gnu_attr___scanf__, 1, 2)));
+extern void t__format__strftime (const char *) __attribute__((__format__(gnu_attr_strftime, 1, 0)));
+extern void t__format____strftime__ (const char *) __attribute__((__format__(gnu_attr___strftime__, 1, 0)));
 extern void t__format__strfmon (const char *, ...) __attribute__((__format__(strfmon, 1, 2)));
 extern void t__format____strfmon__ (const char *, ...) __attribute__((__format__(__strfmon__, 1, 2)));
 
Index: gcc/gcc/testsuite/gcc.dg/format/attr-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-3.c
@@ -3,20 +3,21 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 /* Proper uses of the attributes.  */
-extern void fa0 (const char *, ...) __attribute__((format(printf, 1, 2)));
-extern void fa1 (char *, ...) __attribute__((format(printf, 1, 2)));
+extern void fa0 (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
+extern void fa1 (char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
 extern char *fa2 (const char *) __attribute__((format_arg(1)));
 extern char *fa3 (char *) __attribute__((format_arg(1)));
 
 /* Uses with too few or too many arguments.  */
 extern void fb0 (const char *, ...) __attribute__((format)); /* { dg-error "wrong number of arguments" "bad format" } */
 extern void fb1 (const char *, ...) __attribute__((format())); /* { dg-error "wrong number of arguments" "bad format" } */
-extern void fb2 (const char *, ...) __attribute__((format(printf))); /* { dg-error "wrong number of arguments" "bad format" } */
-extern void fb3 (const char *, ...) __attribute__((format(printf, 1))); /* { dg-error "wrong number of arguments" "bad format" } */
-extern void fb4 (const char *, ...) __attribute__((format(printf, 1, 2, 3))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb2 (const char *, ...) __attribute__((format(gnu_attr_printf))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb3 (const char *, ...) __attribute__((format(gnu_attr_printf, 1))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb4 (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2, 3))); /* { dg-error "wrong number of arguments" "bad format" } */
 
 extern void fc1 (const char *) __attribute__((format_arg)); /* { dg-error "wrong number of arguments" "bad format_arg" } */
 extern void fc2 (const char *) __attribute__((format_arg())); /* { dg-error "wrong number of arguments" "bad format_arg" } */
@@ -25,9 +26,9 @@ extern void fc3 (const char *) __attribu
 /* These attributes presently only apply to declarations, not to types.
    Eventually, they should be usable with declarators for function types
    anywhere, but still not with structure/union/enum types.  */
-struct s0 { int i; } __attribute__((format(printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on struct" } */
-union u0 { int i; } __attribute__((format(printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on union" } */
-enum e0 { E0V0 } __attribute__((format(printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on enum" } */
+struct s0 { int i; } __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on struct" } */
+union u0 { int i; } __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on union" } */
+enum e0 { E0V0 } __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on enum" } */
 
 struct s1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on struct" } */
 union u1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on union" } */
@@ -38,28 +39,28 @@ extern void fe0 (const char *, ...) __at
 extern void fe1 (const char *, ...) __attribute__((format(nosuch, 1, 2))); /* { dg-warning "format function type" "unknown format" } */
 
 /* Both the numbers must be integer constant expressions.  */
-extern void ff0 (const char *, ...) __attribute__((format(printf, 3-2, (long long)(10/5))));
+extern void ff0 (const char *, ...) __attribute__((format(gnu_attr_printf, 3-2, (long long)(10/5))));
 int foo;
-extern void ff1 (const char *, ...) __attribute__((format(printf, foo, 10/5))); /* { dg-error "invalid operand" "bad number" } */
-extern void ff2 (const char *, ...) __attribute__((format(printf, 3-2, foo))); /* { dg-error "invalid operand" "bad number" } */
+extern void ff1 (const char *, ...) __attribute__((format(gnu_attr_printf, foo, 10/5))); /* { dg-error "invalid operand" "bad number" } */
+extern void ff2 (const char *, ...) __attribute__((format(gnu_attr_printf, 3-2, foo))); /* { dg-error "invalid operand" "bad number" } */
 extern char *ff3 (const char *) __attribute__((format_arg(3-2)));
 extern char *ff4 (const char *) __attribute__((format_arg(foo))); /* { dg-error "invalid operand" "bad format_arg number" } */
 
 /* The format string argument must precede the arguments to be formatted.
    This includes if no parameter types are specified (which is not valid ISO
    C for variadic functions).  */
-extern void fg0 () __attribute__((format(printf, 1, 2)));
-extern void fg1 () __attribute__((format(printf, 1, 0)));
-extern void fg2 () __attribute__((format(printf, 1, 1))); /* { dg-error "follows" "bad number order" } */
-extern void fg3 () __attribute__((format(printf, 2, 1))); /* { dg-error "follows" "bad number order" } */
+extern void fg0 () __attribute__((format(gnu_attr_printf, 1, 2)));
+extern void fg1 () __attribute__((format(gnu_attr_printf, 1, 0)));
+extern void fg2 () __attribute__((format(gnu_attr_printf, 1, 1))); /* { dg-error "follows" "bad number order" } */
+extern void fg3 () __attribute__((format(gnu_attr_printf, 2, 1))); /* { dg-error "follows" "bad number order" } */
 
 /* The format string argument must be a string type, and the arguments to
    be formatted must be the "...".  */
-extern void fh0 (int, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "not a string" "format int string" } */
-extern void fh1 (signed char *, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "not a string" "signed char string" } */
-extern void fh2 (unsigned char *, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "not a string" "unsigned char string" } */
-extern void fh3 (const char *, ...) __attribute__((format(printf, 1, 3))); /* { dg-error "is not" "not ..." } */
-extern void fh4 (const char *, int, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "is not" "not ..." } */
+extern void fh0 (int, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "format int string" } */
+extern void fh1 (signed char *, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "signed char string" } */
+extern void fh2 (unsigned char *, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "unsigned char string" } */
+extern void fh3 (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 3))); /* { dg-error "is not" "not ..." } */
+extern void fh4 (const char *, int, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "is not" "not ..." } */
 
 /* format_arg formats must take and return a string.  */
 extern char *fi0 (int) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg int string" } */
Index: gcc/gcc/testsuite/gcc.dg/format/attr-4.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-4.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-4.c
@@ -4,12 +4,13 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern __attribute__((format(printf, 1, 2))) void tformatprintf0 (const char *, ...);
-extern void __attribute__((format(printf, 1, 2))) tformatprintf1 (const char *, ...);
-extern void foo (void), __attribute__((format(printf, 1, 2))) tformatprintf2 (const char *, ...);
-extern __attribute__((noreturn)) void bar (void), __attribute__((format(printf, 1, 2))) tformatprintf3 (const char *, ...);
+extern __attribute__((format(gnu_attr_printf, 1, 2))) void tformatprintf0 (const char *, ...);
+extern void __attribute__((format(gnu_attr_printf, 1, 2))) tformatprintf1 (const char *, ...);
+extern void foo (void), __attribute__((format(gnu_attr_printf, 1, 2))) tformatprintf2 (const char *, ...);
+extern __attribute__((noreturn)) void bar (void), __attribute__((format(gnu_attr_printf, 1, 2))) tformatprintf3 (const char *, ...);
 
 void
 baz (int i, int *ip, double d)
Index: gcc/gcc/testsuite/gcc.dg/format/attr-7.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-7.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-7.c
@@ -3,12 +3,13 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-__attribute__((format(printf, 1, 2))) void (*tformatprintf0) (const char *, ...);
-void (*tformatprintf1) (const char *, ...) __attribute__((format(printf, 1, 2)));
-void (__attribute__((format(printf, 1, 2))) *tformatprintf2) (const char *, ...);
-void (__attribute__((format(printf, 1, 2))) ****tformatprintf3) (const char *, ...);
+__attribute__((format(gnu_attr_printf, 1, 2))) void (*tformatprintf0) (const char *, ...);
+void (*tformatprintf1) (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
+void (__attribute__((format(gnu_attr_printf, 1, 2))) *tformatprintf2) (const char *, ...);
+void (__attribute__((format(gnu_attr_printf, 1, 2))) ****tformatprintf3) (const char *, ...);
 
 char * (__attribute__((format_arg(1))) *tformat_arg) (const char *);
 
Index: gcc/gcc/testsuite/gcc.dg/format/c90-printf-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/c90-printf-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/c90-printf-3.c
@@ -3,7 +3,7 @@
    do not.
 */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
-/* { dg-do compile } */
+/* { dg-do compile { target { ! *-*-mingw* } } } */
 /* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
 
 #include "format.h"
Index: gcc/gcc/testsuite/gcc.dg/format/c90-scanf-4.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/c90-scanf-4.c
+++ gcc/gcc/testsuite/gcc.dg/format/c90-scanf-4.c
@@ -3,7 +3,7 @@
    do not.
 */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
-/* { dg-do compile } */
+/* { dg-do compile { target { ! *-*-mingw* } } } */
 /* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
 
 #include "format.h"
Index: gcc/gcc/testsuite/gcc.dg/format/c99-printf-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/c99-printf-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/c99-printf-3.c
@@ -2,7 +2,7 @@
    attributes in strict C99 mode, but the gettext functions do not.
 */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
-/* { dg-do compile } */
+/* { dg-do compile { target { ! *-*-mingw* } } } */
 /* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
 
 #include "format.h"
Index: gcc/gcc/testsuite/gcc.dg/format/miss-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-1.c
@@ -23,7 +23,7 @@ bar (const char *fmt, ...)
   va_end (ap);
 }
 
-__attribute__((__format__(__printf__, 1, 2))) void
+__attribute__((__format__(gnu_attr___printf__, 1, 2))) void
 foo2 (const char *fmt, ...)
 {
   va_list ap;
Index: gcc/gcc/testsuite/gcc.dg/format/miss-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-3.c
@@ -3,13 +3,14 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 void
 foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
@@ -18,7 +19,7 @@ foo1 (noattr_t na, attr_t a, vnoattr_t v
   noattr_t na2 = a; /* { dg-warning "candidate" "initialization warning" } */
   attr_t a1 = na;
   attr_t a2 = a;
-  
+
   vnoattr_t vna1 = vna;
   vnoattr_t vna2 = va; /* { dg-warning "candidate" "initialization warning" } */
   vattr_t va1 = vna;
Index: gcc/gcc/testsuite/gcc.dg/format/miss-4.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-4.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-4.c
@@ -3,20 +3,21 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 void
 foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
 {
   noattr_t na1, na2;
   attr_t a1, a2;
-  
+
   vnoattr_t vna1, vna2;
   vattr_t va1, va2;
 
@@ -24,7 +25,7 @@ foo1 (noattr_t na, attr_t a, vnoattr_t v
   na2 = a; /* { dg-warning "candidate" "assignment warning" } */
   a1 = na;
   a2 = a;
-  
+
   vna1 = vna;
   vna2 = va; /* { dg-warning "candidate" "assignment warning" } */
   va1 = vna;
Index: gcc/gcc/testsuite/gcc.dg/format/miss-5.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-5.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-5.c
@@ -3,13 +3,14 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 noattr_t
 foo1 (noattr_t na, attr_t a, int i)
Index: gcc/gcc/testsuite/gcc.dg/format/miss-6.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-6.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-6.c
@@ -3,13 +3,14 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 extern void foo1 (noattr_t);
 extern void foo2 (attr_t);
@@ -23,7 +24,7 @@ foo (noattr_t na, attr_t a, vnoattr_t vn
   foo1 (a); /* { dg-warning "candidate" "parameter passing warning" } */
   foo2 (na);
   foo2 (a);
-  
+
   foo3 (vna);
   foo3 (va); /* { dg-warning "candidate" "parameter passing warning" } */
   foo4 (vna);
Index: gcc/gcc/testsuite/gcc.dg/format/ms_array-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_array-1.c
@@ -0,0 +1,42 @@
+/* Test for format checking of constant arrays.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat=2" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+const char a1[] = "foo";
+const char a2[] = "foo%d";
+const char b1[3] = "foo";
+const char b2[1] = "1";
+static const char c1[] = "foo";
+static const char c2[] = "foo%d";
+char d[] = "foo";
+volatile const char e[] = "foo";
+
+void
+foo (int i, long l)
+{
+  const char p1[] = "bar";
+  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 (c1);
+  printf (c2, i);
+  printf (c2, l); /* { dg-warning "format" "wrong type with array" } */
+  printf (p1);
+  printf (p2, i);
+  printf (p2, l); /* { dg-warning "format" "wrong type with array" } */
+  printf (q1);
+  printf (q2, i);
+  printf (q2, l); /* { dg-warning "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" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-1.c
@@ -0,0 +1,10 @@
+/* Test for strftime format attributes: can't have first_arg_num != 0.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define DONT_GNU_PROTOTYPE
+#include "format.h"
+
+extern void foo0 (const char *) __attribute__((__format__(__ms_strftime__, 1, 0)));
+extern void foo1 (const char *, ...) __attribute__((__format__(__ms_strftime__, 1, 2))); /* { dg-error "cannot format" "strftime first_arg_num != 0" } */
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-2.c
@@ -0,0 +1,68 @@
+/* Test for format attributes: test use of __attribute__.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define DONT_GNU_PROTOTYPE
+#include "format.h"
+
+extern void tformatprintf (const char *, ...) __attribute__((format(ms_printf, 1, 2)));
+extern void tformat__printf__ (const char *, ...) __attribute__((format(__ms_printf__, 1, 2)));
+extern void tformatscanf (const char *, ...) __attribute__((format(ms_scanf, 1, 2)));
+extern void tformat__scanf__ (const char *, ...) __attribute__((format(__ms_scanf__, 1, 2)));
+extern void tformatstrftime (const char *) __attribute__((format(ms_strftime, 1, 0)));
+extern void tformat__strftime__ (const char *) __attribute__((format(__ms_strftime__, 1, 0)));
+extern void tformatstrfmon (const char *, ...) __attribute__((format(strfmon, 1, 2)));
+extern void tformat__strfmon__ (const char *, ...) __attribute__((format(__strfmon__, 1, 2)));
+extern void t__format__printf (const char *, ...) __attribute__((__format__(ms_printf, 1, 2)));
+extern void t__format____printf__ (const char *, ...) __attribute__((__format__(__ms_printf__, 1, 2)));
+extern void t__format__scanf (const char *, ...) __attribute__((__format__(ms_scanf, 1, 2)));
+extern void t__format____scanf__ (const char *, ...) __attribute__((__format__(__ms_scanf__, 1, 2)));
+extern void t__format__strftime (const char *) __attribute__((__format__(ms_strftime, 1, 0)));
+extern void t__format____strftime__ (const char *) __attribute__((__format__(__ms_strftime__, 1, 0)));
+extern void t__format__strfmon (const char *, ...) __attribute__((__format__(strfmon, 1, 2)));
+extern void t__format____strfmon__ (const char *, ...) __attribute__((__format__(__strfmon__, 1, 2)));
+
+extern char *tformat_arg (const char *) __attribute__((format_arg(1)));
+extern char *t__format_arg__ (const char *) __attribute__((__format_arg__(1)));
+
+void
+foo (int i, int *ip, double d)
+{
+  tformatprintf ("%d", i);
+  tformatprintf ("%"); /* { dg-warning "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);
+  tformat__scanf__ ("%"); /* { dg-warning "format" "attribute format __scanf__" } */
+  tformatstrftime ("%a");
+  tformatstrftime ("%"); /* { dg-warning "format" "attribute format strftime" } */
+  tformat__strftime__ ("%a");
+  tformat__strftime__ ("%"); /* { dg-warning "format" "attribute format __strftime__" } */
+  tformatstrfmon ("%n", d);
+  tformatstrfmon ("%"); /* { dg-warning "format" "attribute format strfmon" } */
+  tformat__strfmon__ ("%n", d);
+  tformat__strfmon__ ("%"); /* { dg-warning "format" "attribute format __strfmon__" } */
+  t__format__printf ("%d", i);
+  t__format__printf ("%"); /* { dg-warning "format" "attribute __format__ printf" } */
+  t__format____printf__ ("%d", i);
+  t__format____printf__ ("%"); /* { dg-warning "format" "attribute __format__ __printf__" } */
+  t__format__scanf ("%d", ip);
+  t__format__scanf ("%"); /* { dg-warning "format" "attribute __format__ scanf" } */
+  t__format____scanf__ ("%d", ip);
+  t__format____scanf__ ("%"); /* { dg-warning "format" "attribute __format__ __scanf__" } */
+  t__format__strftime ("%a");
+  t__format__strftime ("%"); /* { dg-warning "format" "attribute __format__ strftime" } */
+  t__format____strftime__ ("%a");
+  t__format____strftime__ ("%"); /* { dg-warning "format" "attribute __format__ __strftime__" } */
+  t__format__strfmon ("%n", d);
+  t__format__strfmon ("%"); /* { dg-warning "format" "attribute __format__ strfmon" } */
+  t__format____strfmon__ ("%n", d);
+  t__format____strfmon__ ("%"); /* { dg-warning "format" "attribute __format__ __strfmon__" } */
+  tformatprintf (tformat_arg ("%d"), i);
+  tformatprintf (tformat_arg ("%")); /* { dg-warning "format" "attribute format_arg" } */
+  tformatprintf (t__format_arg__ ("%d"), i);
+  tformatprintf (t__format_arg__ ("%")); /* { dg-warning "format" "attribute __format_arg__" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-3.c
@@ -0,0 +1,71 @@
+/* Test for format attributes: test bad uses of __attribute__.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* Proper uses of the attributes.  */
+extern void fa0 (const char *, ...) __attribute__((format(ms_printf, 1, 2)));
+extern void fa1 (char *, ...) __attribute__((format(ms_printf, 1, 2)));
+extern char *fa2 (const char *) __attribute__((format_arg(1)));
+extern char *fa3 (char *) __attribute__((format_arg(1)));
+
+/* Uses with too few or too many arguments.  */
+extern void fb0 (const char *, ...) __attribute__((format)); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb1 (const char *, ...) __attribute__((format())); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb2 (const char *, ...) __attribute__((format(ms_printf))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb3 (const char *, ...) __attribute__((format(ms_printf, 1))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb4 (const char *, ...) __attribute__((format(ms_printf, 1, 2, 3))); /* { dg-error "wrong number of arguments" "bad format" } */
+
+extern void fc1 (const char *) __attribute__((format_arg)); /* { dg-error "wrong number of arguments" "bad format_arg" } */
+extern void fc2 (const char *) __attribute__((format_arg())); /* { dg-error "wrong number of arguments" "bad format_arg" } */
+extern void fc3 (const char *) __attribute__((format_arg(1, 2))); /* { dg-error "wrong number of arguments" "bad format_arg" } */
+
+/* These attributes presently only apply to declarations, not to types.
+   Eventually, they should be usable with declarators for function types
+   anywhere, but still not with structure/union/enum types.  */
+struct s0 { int i; } __attribute__((format(ms_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on struct" } */
+union u0 { int i; } __attribute__((format(ms_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on union" } */
+enum e0 { E0V0 } __attribute__((format(ms_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on enum" } */
+
+struct s1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on struct" } */
+union u1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on union" } */
+enum e1 { E1V0 } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on enum" } */
+
+/* The format type must be an identifier, one of those recognized.  */
+extern void fe0 (const char *, ...) __attribute__((format(12345, 1, 2))); /* { dg-error "format specifier" "non-id format" } */
+extern void fe1 (const char *, ...) __attribute__((format(nosuch, 1, 2))); /* { dg-warning "format function type" "unknown format" } */
+
+/* Both the numbers must be integer constant expressions.  */
+extern void ff0 (const char *, ...) __attribute__((format(ms_printf, 3-2, (long long)(10/5))));
+int foo;
+extern void ff1 (const char *, ...) __attribute__((format(ms_printf, foo, 10/5))); /* { dg-error "invalid operand" "bad number" } */
+extern void ff2 (const char *, ...) __attribute__((format(ms_printf, 3-2, foo))); /* { dg-error "invalid operand" "bad number" } */
+extern char *ff3 (const char *) __attribute__((format_arg(3-2)));
+extern char *ff4 (const char *) __attribute__((format_arg(foo))); /* { dg-error "invalid operand" "bad format_arg number" } */
+
+/* The format string argument must precede the arguments to be formatted.
+   This includes if no parameter types are specified (which is not valid ISO
+   C for variadic functions).  */
+extern void fg0 () __attribute__((format(ms_printf, 1, 2)));
+extern void fg1 () __attribute__((format(ms_printf, 1, 0)));
+extern void fg2 () __attribute__((format(ms_printf, 1, 1))); /* { dg-error "follows" "bad number order" } */
+extern void fg3 () __attribute__((format(ms_printf, 2, 1))); /* { dg-error "follows" "bad number order" } */
+
+/* The format string argument must be a string type, and the arguments to
+   be formatted must be the "...".  */
+extern void fh0 (int, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "not a string" "format int string" } */
+extern void fh1 (signed char *, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "not a string" "signed char string" } */
+extern void fh2 (unsigned char *, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "not a string" "unsigned char string" } */
+extern void fh3 (const char *, ...) __attribute__((format(ms_printf, 1, 3))); /* { dg-error "is not" "not ..." } */
+extern void fh4 (const char *, int, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "is not" "not ..." } */
+
+/* format_arg formats must take and return a string.  */
+extern char *fi0 (int) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg int string" } */
+extern char *fi1 (signed char *) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg signed char string" } */
+extern char *fi2 (unsigned char *) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg unsigned char string" } */
+extern int fi3 (const char *) __attribute__((format_arg(1))); /* { dg-error "not return string" "format_arg ret int string" } */
+extern signed char *fi4 (const char *) __attribute__((format_arg(1))); /* { dg-error "not return string" "format_arg ret signed char string" } */
+extern unsigned char *fi5 (const char *) __attribute__((format_arg(1))); /* { dg-error "not return string" "format_arg ret unsigned char string" } */
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-4.c
@@ -0,0 +1,26 @@
+/* Test for format attributes: test use of __attribute__
+   in prefix attributes.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+extern __attribute__((format(ms_printf, 1, 2))) void tformatprintf0 (const char *, ...);
+extern void __attribute__((format(ms_printf, 1, 2))) tformatprintf1 (const char *, ...);
+extern void foo (void), __attribute__((format(ms_printf, 1, 2))) tformatprintf2 (const char *, ...);
+extern __attribute__((noreturn)) void bar (void), __attribute__((format(ms_printf, 1, 2))) tformatprintf3 (const char *, ...);
+
+void
+baz (int i, int *ip, double d)
+{
+  tformatprintf0 ("%d", i);
+  tformatprintf0 ("%"); /* { dg-warning "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);
+  tformatprintf3 ("%"); /* { dg-warning "format" "attribute format printf case 3" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-7.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-7.c
@@ -0,0 +1,35 @@
+/* Test for format attributes: test applying them to types.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define DONT_GNU_PROTOTYPE
+#include "format.h"
+
+__attribute__((format(ms_printf, 1, 2))) void (*tformatprintf0) (const char *, ...);
+void (*tformatprintf1) (const char *, ...) __attribute__((format(ms_printf, 1, 2)));
+void (__attribute__((format(ms_printf, 1, 2))) *tformatprintf2) (const char *, ...);
+void (__attribute__((format(ms_printf, 1, 2))) ****tformatprintf3) (const char *, ...);
+
+char * (__attribute__((format_arg(1))) *tformat_arg) (const char *);
+
+void
+baz (int i)
+{
+  (*tformatprintf0) ("%d", i);
+  (*tformatprintf0) ((*tformat_arg) ("%d"), i);
+  (*tformatprintf0) ("%"); /* { dg-warning "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" } */
+  (*tformatprintf2) ("%d", i);
+  (*tformatprintf2) ((*tformat_arg) ("%d"), i);
+  (*tformatprintf2) ("%"); /* { dg-warning "format" "nested" } */
+  (*tformatprintf2) ((*tformat_arg) ("%")); /* { dg-warning "format" "nested" } */
+  (****tformatprintf3) ("%d", i);
+  (****tformatprintf3) ((*tformat_arg) ("%d"), i);
+  (****tformatprintf3) ("%"); /* { dg-warning "format" "nested 2" } */
+  (****tformatprintf3) ((*tformat_arg) ("%")); /* { dg-warning "format" "nested 2" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_bitfld-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_bitfld-1.c
@@ -0,0 +1,52 @@
+/* Test for printf formats and bit-fields: bug 22421.  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+/* { dg-require-effective-target int32plus } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+struct s {
+  unsigned int u1 : 1;
+  signed int s1 : 1;
+  unsigned int u15 : 15;
+  signed int s15 : 15;
+  unsigned int u16 : 16;
+  signed int s16 : 16;
+  unsigned long u31 : 31;
+  signed long s31 : 31;
+  unsigned long u32 : 32;
+  signed long s32 : 32;
+  unsigned long long u48 : 48;
+} x;
+
+void
+foo (void)
+{
+  printf ("%d%u", x.u1, x.u1);
+  printf ("%d%u", x.s1, x.s1);
+  printf ("%d%u", x.u15, x.u15);
+  printf ("%d%u", x.s15, x.s15);
+  printf ("%d%u", x.u16, x.u16);
+  printf ("%d%u", x.s16, x.s16);
+#if __INT_MAX__ > 32767
+  /* If integers are 16 bits, there doesn't seem to be a way of
+     printing these without getting an error.  */
+  printf ("%d%u", x.u31, x.u31);
+  printf ("%d%u", x.s31, x.s31);
+#endif
+#if __LONG_MAX__ > 2147483647 && __INT_MAX__ >= 2147483647
+  /* If long is wider than 32 bits, the 32-bit bit-fields are int or
+     unsigned int or promote to those types.  Otherwise, long is 32
+     bits and the bit-fields are of type plain long or unsigned
+     long.  */
+  printf ("%d%u", x.u32, x.u32);
+  printf ("%d%u", x.s32, x.s32);
+#else
+  printf ("%ld%lu", x.u32, x.u32);
+  printf ("%ld%lu", x.s32, x.s32);
+#endif
+  printf ("%I64u", x.u48); /* { dg-warning "has type '.*unsigned int:48'" } */
+  printf ("%I64u", (unsigned long long)x.u48);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_branch-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_branch-1.c
@@ -0,0 +1,28 @@
+/* Test for format checking of conditional expressions.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+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" } */
+  /* 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) ? "%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" } */
+  /* 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 *-*-* } 26 } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-1.c
@@ -0,0 +1,184 @@
+/* Test for printf formats.  Formats using C90 features, including cases
+   where C90 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, int i1, int i2, unsigned int u, double d, char *s, void *p,
+     int *n, short int *hn, long int l, unsigned long int ul,
+     long int *ln, long double ld, wint_t lc, wchar_t *ls, llong ll,
+     ullong ull, unsigned int *un, const int *cn, signed char *ss,
+     unsigned char *us, const signed char *css, unsigned int u1,
+     unsigned int u2)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.1 (pages 131-134).  */
+  /* Basic sanity checks for the different components of a format.  */
+  printf ("%d\n", i);
+  printf ("%+d\n", i);
+  printf ("%3d\n", i);
+  printf ("%-3d\n", i);
+  printf ("%*d\n", i1, i);
+  printf ("%d %lu\n", i, ul);
+  /* Bogus use of width.  */
+  printf ("%5n\n", n); /* { dg-warning "width" "width 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 ("%-%"); /* { dg-warning "format" "bogus %%" } */
+  printf ("%-%\n"); /* { dg-warning "format" "bogus %%" } */
+  printf ("%5%\n"); /* { dg-warning "format" "bogus %%" } */
+  printf ("%h%\n"); /* { dg-warning "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
+     differences in format checking here, and this is relied on to get the
+     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);
+  printf ("%hs", hn);
+  printf ("%hp", p); /* { dg-warning "length" "bad use of %h" } */
+  printf ("%h"); /* { dg-warning "conversion lacks type" "bare %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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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% 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* Various tests of bad argument types.  */
+  printf ("%d", l); /* { dg-warning "format" "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" } */
+  /* 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
+     discussion of the requirements of rules on identical representation,
+     and of the application of the as if rule with the new va_arg
+     allowances in C99 to printf.)  Likewise, we should warn if
+     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" } */
+  /* 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" } */
+  /* The historical behavior is to allow signed / unsigned types
+     interchangably as arguments.  For values representable in both types,
+     such usage may be correct.  For now preserve the behavior of GCC
+     in such cases.
+  */
+  printf ("%d", u);
+  /* Wrong number of arguments.  */
+  printf ("%d%d", i); /* { dg-warning "arguments" "wrong number of args" } */
+  printf ("%d", i, i); /* { dg-warning "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" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-2.c
@@ -0,0 +1,25 @@
+/* Test for printf formats.  Formats using C99 features should be rejected
+   outside of C99 mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, double d, llong ll, intmax_t j, size_t z, ptrdiff_t t)
+{
+  /* Some tests already in c90-printf-1.c, e.g. %lf.  */
+  /* The widths hh, ll, j, z, t are new.  */
+  printf ("%hhd", i); /* { dg-warning "unknown|format" "%hh is unsupported" } */
+  printf ("%I64d", ll); /* { dg-warning "length|C" "%I64 in C90" } */
+  printf ("%jd", j); /* { dg-warning "unknown|format" "%j is unsupported" } */
+  printf ("%zu", z); /* { dg-warning "unknown|format" "%z is unsupported" } */
+  printf ("%td", t); /* { dg-warning "unknown|format" "%t is unsupported" } */
+  /* The formats F, a, A are new.  */
+  printf ("%F", d); /* { dg-warning "unknown|format" "%F is unsupported" } */
+  printf ("%a", d); /* { dg-warning "unknown|format" "%a is unsupported" } */
+  printf ("%A", d); /* { dg-warning "unknown|format" "%A is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-3.c
@@ -0,0 +1,43 @@
+/* Test for printf formats.  Test that the C90 functions get their default
+   attributes in strict C90 mode, but the C99 and gettext functions
+   do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, char *s, size_t n, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5, va_list v6, va_list v7, va_list v8)
+{
+  fprintf (stdout, "%d", i);
+  fprintf (stdout, "%ld", i); /* { dg-warning "format" "fprintf" } */
+  printf ("%d", i);
+  printf ("%ld", i); /* { dg-warning "format" "printf" } */
+  /* The "unlocked" functions shouldn't warn in c90 mode.  */
+  fprintf_unlocked (stdout, "%ld", i);
+  printf_unlocked ("%ld", i);
+  sprintf (s, "%d", i);
+  sprintf (s, "%ld", i); /* { dg-warning "format" "sprintf" } */
+  vfprintf (stdout, "%d", v0);
+  vfprintf (stdout, "%Y", v1); /* { dg-warning "format" "vfprintf" } */
+  vprintf ("%d", v2);
+  vprintf ("%Y", v3); /* { dg-warning "format" "vprintf" } */
+  /* The following used to give a bogus warning.  */
+  vprintf ("%*.*d", v8);   /* { dg-bogus "format" "vprintf" } */
+  vsprintf (s, "%d", v4);
+  vsprintf (s, "%Y", v5); /* { dg-warning "format" "Y is invalid" } */
+  snprintf (s, n, "%d", i);
+  snprintf (s, n, "%ld", i);
+  vsnprintf (s, n, "%d", v6);
+  vsnprintf (s, n, "%Y", v7);
+  printf (gettext ("%d"), i);
+  printf (gettext ("%ld"), i);
+  printf (dgettext ("", "%d"), i);
+  printf (dgettext ("", "%ld"), i);
+  printf (dcgettext ("", "%d", 0), i);
+  printf (dcgettext ("", "%ld", 0), i);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-1.c
@@ -0,0 +1,119 @@
+/* Test for scanf formats.  Formats using C90 features, including cases
+   where C90 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, unsigned int *uip, short int *hp, unsigned short int *uhp,
+     long int *lp, unsigned long int *ulp, float *fp, double *dp,
+     long double *ldp, char *s, signed char *ss, unsigned char *us,
+     void **pp, int *n, llong *llp, ullong *ullp, wchar_t *ls,
+     const int *cip, const int *cn, const char *cs, const void **ppc,
+     void *const *pcp, short int *hn, long int *ln, void *p, char **sp,
+     volatile void *ppv)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.2 (pages 134-138).  */
+  /* Basic sanity checks for the different components of a format.  */
+  scanf ("%d", ip);
+  scanf ("%*d");
+  scanf ("%3d", ip);
+  scanf ("%hd", hp);
+  scanf ("%3ld", lp);
+  scanf ("%*3d");
+  scanf ("%d %ld", ip, lp);
+  /* Valid and invalid %% constructions.  */
+  scanf ("%%");
+  scanf ("%*%"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%*%\n"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%4%"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%4%\n"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%h%"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%h%\n"); /* { dg-warning "format" "bogus %%" } */
+  /* Valid, invalid and silly assignment-suppression constructions.  */
+  scanf ("%*d%*i%*o%*u%*x%*X%*e%*E%*f%*g%*G%*s%*[abc]%*c%*p");
+  scanf ("%*2d%*8s%*3c");
+  scanf ("%*n", n); /* { dg-warning "suppress" "suppression of %n" } */
+  scanf ("%*hd"); /* { dg-warning "together" "suppression with length" } */
+  /* Valid, invalid and silly width constructions.  */
+  scanf ("%2d%3i%4o%5u%6x%7X%8e%9E%10f%11g%12G%13s%14[abc]%15c%16p",
+	 ip, ip, uip, uip, uip, uip, fp, fp, fp, fp, fp, s, s, s, pp);
+  scanf ("%0d", ip); /* { dg-warning "width" "warning for zero width" } */
+  scanf ("%3n", n); /* { dg-warning "width" "width with %n" } */
+  /* Valid and invalid %h, %l, %L constructions.  */
+  scanf ("%hd%hi%ho%hu%hx%hX%hn", hp, hp, uhp, uhp, uhp, uhp, hn);
+  scanf ("%he", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hE", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hf", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hg", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hG", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hs", hp);
+  scanf ("%h[ac]", s); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hc", hp);
+  scanf ("%hp", pp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%h"); /* { dg-warning "conversion lacks type" "bare %h" } */
+  scanf ("%h."); /* { dg-warning "conversion" "bogus %h" } */
+  scanf ("%ld%li%lo%lu%lx%lX%ln", lp, lp, ulp, ulp, ulp, ulp, ln);
+  scanf ("%le%lE%lf%lg%lG", dp, dp, dp, dp, dp);
+  scanf ("%lp", pp); /* { dg-warning "length" "bad use of %l" } */
+  /* These next three formats were added in C94.  */
+  scanf ("%ls", ls); /* { dg-warning "length|C" "bad use of %l" } */
+  scanf ("%l[ac]", ls); /* { dg-warning "length|C" "bad use of %l" } */
+  scanf ("%lc", ls); /* { dg-warning "length|C" "bad use of %l" } */
+  scanf ("%Ld", llp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Li", llp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lo", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lu", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lx", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%LX", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Ls", s); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%L[ac]", s); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lc", s); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lp", pp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Ln", n); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  /* Valid uses of each bare conversion.  */
+  scanf ("%d%i%o%u%x%X%e%E%f%g%G%s%[abc]%c%p%n%%", ip, ip, uip, uip, uip,
+	 uip, fp, fp, fp, fp, fp, s, s, s, pp, n);
+  /* Allow other character pointers with %s, %c, %[].  */
+  scanf ("%2s%3s%4c%5c%6[abc]%7[abc]", ss, us, ss, us, ss, us);
+  /* Further tests for %[].  */
+  scanf ("%[%d]%d", s, ip);
+  scanf ("%[^%d]%d", s, ip);
+  scanf ("%[]%d]%d", s, ip);
+  scanf ("%[^]%d]%d", s, ip);
+  scanf ("%[%d]%d", s, ip);
+  scanf ("%[]abcd", s); /* { dg-warning "no closing" "incomplete scanset" } */
+  /* Various tests of bad argument types.  Some of these are only pedantic
+     warnings.
+  */
+  scanf ("%d", lp); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%d", uip); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%d", pp); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", ppc); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", ppv); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%s", n); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%s", p); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", p); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", sp); /* { dg-warning "format" "bad argument types" } */
+  /* Tests for writing into constant values.  */
+  scanf ("%d", cip); /* { dg-warning "constant" "%d writing into const" } */
+  scanf ("%n", cn); /* { dg-warning "constant" "%n writing into const" } */
+  scanf ("%s", cs); /* { dg-warning "constant" "%s writing into const" } */
+  scanf ("%p", pcp); /* { dg-warning "constant" "%p writing into const" } */
+  /* Wrong number of arguments.  */
+  scanf ("%d%d", ip); /* { dg-warning "arguments" "wrong number of args" } */
+  scanf ("%d", ip, ip); /* { dg-warning "arguments" "wrong number of args" } */
+  /* Miscellaneous bogus constructions.  */
+  scanf (""); /* { dg-warning "zero-length" "warning for empty format" } */
+  scanf ("\0"); /* { dg-warning "embedded" "warning for embedded NUL" } */
+  scanf ("%d\0", ip); /* { dg-warning "embedded" "warning for embedded NUL" } */
+  scanf ("%d\0%d", ip, ip); /* { dg-warning "embedded|too many" "warning for embedded NUL" } */
+  scanf (NULL); /* { dg-warning "null" "null format string warning" } */
+  scanf ("%"); /* { dg-warning "trailing" "trailing % warning" } */
+  scanf ("%d", (int *)0); /* { dg-warning "null" "writing into NULL" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-2.c
@@ -0,0 +1,26 @@
+/* Test for scanf formats.  Formats using C99 features should be rejected
+   outside of C99 mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (signed char *hhp, float *fp, llong *llp, intmax_t *jp,
+     size_t *zp, ptrdiff_t *tp)
+{
+  /* Some tests already in c90-scanf-1.c.  */
+  /* The widths hh, ll, j, z, t are new.  */
+  scanf ("%hhd", hhp); /* { dg-warning "unknown|format" "%hh is unsupported" } */
+  scanf ("%I64d", llp); /* { dg-warning "length|C" "%I64 in C90" } */
+  scanf ("%jd", jp); /* { dg-warning "unknown|format" "%j is unsupported" } */
+  scanf ("%zu", zp); /* { dg-warning "unknown|format" "%z is unsupported" } */
+  scanf ("%td", tp); /* { dg-warning "unknown|format" "%t is unsupported" } */
+  /* The formats F, a, A are new.  */
+  scanf ("%F", fp); /* { dg-warning "unknown|format" "%F is unsupported" } */
+  scanf ("%a", fp); /* { dg-warning "unknown|format" "%a is unsupported" } */
+  scanf ("%A", fp); /* { dg-warning "unknown|format" "%A is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-3.c
@@ -0,0 +1,20 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char **sp, wchar_t **lsp)
+{
+  /* %a formats for allocation, only recognized in C90 mode, are a
+     GNU extension.
+  */
+  scanf ("%as", sp); /* { dg-warning "flag" "%as is unsupported" } */
+  scanf ("%aS", lsp); /* { dg-warning "format|flag" "%aS is unsupported" } */
+  scanf ("%a[bcd]", sp); /* { dg-warning "flag" "%a[] is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-4.c
@@ -0,0 +1,31 @@
+/* Test for scanf formats.  Test that the C90 functions get their default
+   attributes in strict C90 mode, but the C99 and gettext functions
+   do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, char *s, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5)
+{
+  fscanf (stdin, "%d", ip);
+  fscanf (stdin, "%ld", ip); /* { dg-warning "format" "fscanf" } */
+  scanf ("%d", ip);
+  scanf ("%ld", ip); /* { dg-warning "format" "scanf" } */
+  sscanf (s, "%d", ip);
+  sscanf (s, "%ld", ip); /* { dg-warning "format" "sscanf" } */
+  vfscanf (stdin, "%d", v0);
+  vscanf ("%d", v2);
+  vsscanf (s, "%d", v4);
+  scanf (gettext ("%d"), ip);
+  scanf (gettext ("%ld"), ip);
+  scanf (dgettext ("", "%d"), ip);
+  scanf (dgettext ("", "%ld"), ip);
+  scanf (dcgettext ("", "%d", 0), ip);
+  scanf (dcgettext ("", "%ld", 0), ip);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-5.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-5.c
@@ -0,0 +1,20 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char **sp, wchar_t **lsp)
+{
+  /* m assignment-allocation modifier, recognized in both C90
+     and C99 modes, is a POSIX and ISO/IEC WDTR 24731-2 extension.  */
+  scanf ("%ms", sp); /* { dg-warning "unknown|format" "%ms is unsupported" } */
+  scanf ("%mS", lsp); /* { dg-warning "unknown|format" "%mS is unsupported" } */
+  scanf ("%mls", lsp); /* { dg-warning "unknown|format" "%mls is unsupported" } */
+  scanf ("%m[bcd]", sp); /* { dg-warning "unknown|format" "%m[] is unsupported" } */
+  scanf ("%ml[bcd]", lsp); /* { dg-warning "unknown|format" "%ml[] is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-1.c
@@ -0,0 +1,20 @@
+/* Test for strftime formats.  Formats using C90 features.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wformat-y2k" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.12.3.5 (pages 174-175).  */
+  /* Formats which are Y2K-compliant (no 2-digit years).  */
+  strftime (s, m, "%a%A%b%B%d%H%I%j%m%M%p%S%U%w%W%X%Y%Z%%", tp);
+  /* Formats with 2-digit years.  */
+  strftime (s, m, "%y", tp);
+  /* Formats with 2-digit years in some locales.  */
+  strftime (s, m, "%c", tp);
+  strftime (s, m, "%x", tp);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-2.c
@@ -0,0 +1,28 @@
+/* Test for strftime formats.  Rejection of formats using C99 features in
+   pedantic C90 mode.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wformat-y2k" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  strftime (s, m, "%C", tp); /* { dg-warning "format" "%C is unsupported" } */
+  strftime (s, m, "%D", tp); /* { dg-warning "format" "%D is unsupported" } */
+  strftime (s, m, "%e", tp); /* { dg-warning "format" "%e is unsupported" } */
+  strftime (s, m, "%F", tp); /* { dg-warning "format" "%F is unsupported" } */
+  strftime (s, m, "%g", tp); /* { dg-warning "format" "%g is unsupported" } */
+  strftime (s, m, "%G", tp); /* { dg-warning "format" "%G is unsupported" } */
+  strftime (s, m, "%h", tp); /* { dg-warning "format" "%h is unsupported" } */
+  strftime (s, m, "%n", tp); /* { dg-warning "format" "%n is unsupported" } */
+  strftime (s, m, "%r", tp); /* { dg-warning "format" "%r is unsupported" } */
+  strftime (s, m, "%R", tp); /* { dg-warning "format" "%R is unsupported" } */
+  strftime (s, m, "%t", tp); /* { dg-warning "format" "%t is unsupported" } */
+  strftime (s, m, "%T", tp); /* { dg-warning "format" "%T is unsupported" } */
+  strftime (s, m, "%u", tp); /* { dg-warning "format" "%u is unsupported" } */
+  strftime (s, m, "%V", tp); /* { dg-warning "format" "%V is unsupported" } */
+  strftime (s, m, "%z", tp); /* { dg-warning "C" "%z not in C90" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c94-printf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c94-printf-1.c
@@ -0,0 +1,19 @@
+/* Test for printf formats.  Changes in C94 to C90.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:199409 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (wint_t lc, wchar_t *ls)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.1 (pages 131-134),
+     as amended by ISO/IEC 9899:1990/Amd.1:1995 (E) (pages 4-5).
+     We do not repeat here all the C90 format checks, but just verify
+     that %ls and %lc are accepted without warning.
+  */
+  printf ("%lc", lc);
+  printf ("%ls", ls);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c94-scanf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c94-scanf-1.c
@@ -0,0 +1,18 @@
+/* Test for scanf formats.  Changes in C94 to C90.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:199409 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (wchar_t *ls)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.2 (pages 134-138),
+     as amended by ISO/IEC 9899:1990/Amd.1:1995 (E) (pages 5-6).
+     We do not repeat here all the C90 format checks, but just verify
+     that %ls, %lc, %l[] are accepted without warning.
+  */
+  scanf ("%lc%ls%l[abc]", ls, ls, ls);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-1.c
@@ -0,0 +1,109 @@
+/* Test for printf formats.  Formats using C99 features, including cases
+   where C99 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, unsigned int u, double d, char *s, void *p, int *n,
+     long double ld, wint_t lc, wchar_t *ls, long long int ll,
+     unsigned long long int ull, signed char *ss, unsigned char *us,
+     long long int *lln, intmax_t j, uintmax_t uj, intmax_t *jn,
+     size_t z, signed_size_t sz, signed_size_t *zn,
+     ptrdiff_t t, ptrdiff_t *tn)
+{
+  /* See ISO/IEC 9899:1999 (E) subclause 7.19.6.1 (pages 273-281).
+     We do not repeat here most of the checks for correct C90 formats
+     or completely broken formats.
+  */
+  /* Valid and invalid %h, %hh, %l, %j, %z, %t, %L constructions.  */
+  printf ("%hf", d); /* { dg-warning "length" "bad use of %h" } */
+  printf ("%hF", d); /* { dg-warning "unknown|format" "bad use of %hF" } */
+  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 ("%ha", d); /* { dg-warning "unknown|format" "bad use of %ha" } */
+  printf ("%hA", d); /* { dg-warning "unknown|format" "bad use of %hA" } */
+  printf ("%hc", i);
+  printf ("%hs", (short *)s);
+  printf ("%hp", p); /* { dg-warning "length" "bad use of %h" } */
+  printf ("%lc", lc);
+  printf ("%ls", ls);
+  printf ("%lp", p); /* { dg-warning "length|C" "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" } */
+  /* 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" } */
+  /* 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% 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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 ("%-08F", d); /* { dg-warning "unknown|format" "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 ("%-08a", d); /* { dg-warning "unknown|format" "0 flag ignored with - flag" } */
+  printf ("%-08A", d); /* { dg-warning "unknown|format" "0 flag ignored with - flag" } */
+  /* Various tests of bad argument types.  Mostly covered in c90-printf-1.c;
+     here just test for pointer target sign with %hhn.  (Probably allowed
+     by the standard, but a bad idea, so GCC should diagnose if what
+     is used is not signed char *.)
+  */
+  printf ("%hhn", s); /* { dg-warning "unknown|format" "%hhn is unsupported" } */
+  printf ("%hhn", us); /* { dg-warning "unknown|format" "%hhn is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-2.c
@@ -0,0 +1,32 @@
+/* Test for printf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, long long ll, size_t z, wint_t lc, wchar_t *ls)
+{
+  /* The length modifiers q, Z and L as applied to integer formats are
+     extensions.
+  */
+  printf ("%qd", ll); /* { dg-warning "unknown|format" "%q length is unsupported" } */
+  printf ("%Ld", ll); /* { dg-warning "unknown|format" "%L length is unsupported" } */
+  printf ("%Zd", z); /* { dg-warning "unknown|format" "%Z length is unsupported" } */
+  /* The conversion specifiers C and S are X/Open extensions; the
+     conversion specifier m is a GNU extension.
+  */
+  printf ("%m"); /* { dg-warning "unknown" "printf %m is unsupported" } */
+  printf ("%C", lc); /* { dg-warning "C" "printf %C" } */
+  printf ("%S", ls); /* { dg-warning "C" "printf %S" } */
+  /* The flag character ', and the use of operand number $ formats, are
+     X/Open extensions.
+  */
+  printf ("%'d", i); /* { dg-warning "C" "printf ' flag" } */
+  printf ("%1$d", i); /* { dg-warning "C" "printf $ format" } */
+  printf ("%Ix", z); /* { dg-warning "C" "printf I format" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-3.c
@@ -0,0 +1,40 @@
+/* Test for printf formats.  Test that the C99 functions get their default
+   attributes in strict C99 mode, but the gettext functions do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, char *s, size_t n, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5, va_list v6, va_list v7)
+{
+  fprintf (stdout, "%d", i);
+  fprintf (stdout, "%ld", i); /* { dg-warning "format" "fprintf" } */
+  printf ("%d", i);
+  printf ("%ld", i); /* { dg-warning "format" "printf" } */
+  /* The "unlocked" functions shouldn't warn in c99 mode.  */
+  fprintf_unlocked (stdout, "%ld", i);
+  printf_unlocked ("%ld", i);
+  sprintf (s, "%d", i);
+  sprintf (s, "%ld", i); /* { dg-warning "format" "sprintf" } */
+  snprintf (s, n, "%d", i);
+  snprintf (s, n, "%ld", i); /* { dg-warning "format" "snprintf" } */
+  vfprintf (stdout, "%d", v0);
+  vfprintf (stdout, "%Y", v1); /* { dg-warning "format" "vfprintf" } */
+  vprintf ("%d", v0);
+  vprintf ("%Y", v1); /* { dg-warning "format" "vprintf" } */
+  vsprintf (s, "%d", v0);
+  vsprintf (s, "%Y", v1); /* { dg-warning "format" "vsprintf" } */
+  vsnprintf (s, n, "%d", v0);
+  vsnprintf (s, n, "%Y", v1); /* { dg-warning "format" "vsnprintf" } */
+  printf (gettext ("%d"), i);
+  printf (gettext ("%ld"), (long) i);
+  printf (dgettext ("", "%d"), i);
+  printf (dgettext ("", "%ld"), (long) i);
+  printf (dcgettext ("", "%d", 0), i);
+  printf (dcgettext ("", "%ld", 0), (long) i);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-1.c
@@ -0,0 +1,63 @@
+/* Test for scanf formats.  Formats using C99 features, including cases
+   where C99 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, unsigned int *uip, short int *hp, unsigned short int *uhp,
+     signed char *hhp, unsigned char *uhhp, long int *lp,
+     unsigned long int *ulp, float *fp, double *dp, long double *ldp, char *s,
+     void **pp, int *n, long long *llp, unsigned long long *ullp, wchar_t *ls,
+     short int *hn, signed char *hhn, long int *ln, long long int *lln,
+     intmax_t *jp, uintmax_t *ujp, intmax_t *jn, size_t *zp,
+     signed_size_t *szp, signed_size_t *zn, ptrdiff_t *tp,
+     unsigned_ptrdiff_t *utp, ptrdiff_t *tn)
+{
+  /* See ISO/IEC 9899:1999 (E) subclause 7.19.6.2 (pages 281-288).
+     We do not repeat here most of the checks for correct C90 formats
+     or completely broken formats.
+  */
+  /* Valid, invalid and silly assignment-suppression
+     and width constructions.
+  */
+  scanf ("%*d%*i%*o%*u%*x%*X%*e%*E%*f%*g%*G%*s%*[abc]%*c%*p");
+  scanf ("%*2d%*8s%*3c");
+  scanf ("%*n", n); /* { dg-warning "suppress" "suppression of %n" } */
+  scanf ("%*hd"); /* { dg-warning "together" "suppression with length" } */
+  scanf ("%2d%3i%4o%5u%6x%7X%10e%11E%12f%14g%15G%16s%3[abc]%4c%5p",
+	 ip, ip, uip, uip, uip, uip, fp, fp, fp, fp, fp,
+	 s, s, s, pp);
+  scanf ("%0d", ip); /* { dg-warning "width" "warning for zero width" } */
+  scanf ("%3n", n); /* { dg-warning "width" "width with %n" } */
+  /* Valid and invalid %h, %hh, %l, %j, %z, %t, %L constructions.  */
+  scanf ("%hd%hi%ho%hu%hx%hX%hn", hp, hp, uhp, uhp, uhp, uhp, hn);
+  scanf ("%he", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hE", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hf", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hg", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hG", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hs", hp);
+  scanf ("%h[ac]", s); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hc", (short *)s);
+  scanf ("%hp", pp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hhd", hhp); /* { dg-warning "unknown|format" "%hh is unsupported" } */
+  scanf ("%ld%li%lo%lu%lx%lX%ln", lp, lp, ulp, ulp, ulp, ulp, ln);
+  scanf ("%le%lE%lf%lg%lG", dp, dp, dp, dp, dp);
+  scanf ("%lp", pp); /* { dg-warning "length" "bad use of %l" } */
+  scanf ("%ls", ls);
+  scanf ("%l[ac]", ls);
+  scanf ("%lc", ls);
+  scanf ("%jd", jp); /* { dg-warning "unknown|format" "%j not supported" } */
+  scanf ("%zd", zp); /* { dg-warning "unknown|format" "%z not supported" } */
+  scanf ("%td", tp); /* { dg-warning "unknown|format" "%t not supported" } */
+  scanf ("%Lf", llp); /* { dg-warning "unknown|format" "bad use of %L is not supported" } */
+  /* Valid uses of each bare conversion.  */
+  scanf ("%d%i%o%u%x%X%e%E%f%g%G%s%[abc]%c%p%n%%", ip, ip, uip, uip, uip,
+         uip, fp, fp, fp, fp, fp, s, s, s, pp, n);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-2.c
@@ -0,0 +1,27 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, long long int *llp, wchar_t *ls)
+{
+  /* The length modifiers q and L as applied to integer formats are
+     extensions.
+  */
+  scanf ("%qd", llp); /* { dg-warning "unknown|format" "%q is unsupported" } */
+  scanf ("%Ld", llp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  /* The conversion specifiers C and S are X/Open extensions.  */
+  scanf ("%C", ls); /* { dg-warning "C" "scanf %C" } */
+  scanf ("%S", ls); /* { dg-warning "C" "scanf %S" } */
+  /* The use of operand number $ formats is an X/Open extension.  */
+  scanf ("%1$d", ip); /* { dg-warning "C" "scanf $ format" } */
+  /* glibc also supports flags ' and I on scanf formats as an extension.  */
+  scanf ("%'d", ip); /* { dg-warning "C" "scanf ' flag" } */
+  scanf ("%Id", (ssize_t *)ip); /* { dg-warning "C" "scanf I flag" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-3.c
@@ -0,0 +1,33 @@
+/* Test for scanf formats.  Test that the C99 functions get their default
+   attributes in strict C99 mode, but the gettext functions do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, char *s, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5)
+{
+  fscanf (stdin, "%d", ip);
+  fscanf (stdin, "%ld", ip); /* { dg-warning "format" "fscanf" } */
+  scanf ("%d", ip);
+  scanf ("%ld", ip); /* { dg-warning "format" "scanf" } */
+  sscanf (s, "%d", ip);
+  sscanf (s, "%ld", ip); /* { dg-warning "format" "sscanf" } */
+  vfscanf (stdin, "%d", v0);
+  vfscanf (stdin, "%Y", v1); /* { dg-warning "format" "vfscanf" } */
+  vscanf ("%d", v2);
+  vscanf ("%Y", v3); /* { dg-warning "format" "vscanf" } */
+  vsscanf (s, "%d", v4);
+  vsscanf (s, "%Y", v5); /* { dg-warning "format" "vsscanf" } */
+  scanf (gettext ("%d"), ip);
+  scanf (gettext ("%ld"), ip);
+  scanf (dgettext ("", "%d"), ip);
+  scanf (dgettext ("", "%ld"), ip);
+  scanf (dcgettext ("", "%d", 0), ip);
+  scanf (dcgettext ("", "%ld", 0), ip);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-4.c
@@ -0,0 +1,20 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char **sp, wchar_t **lsp)
+{
+  /* m assignment-allocation modifier, recognized in both C90
+     and C99 modes, is a POSIX and ISO/IEC WDTR 24731-2 extension.  */
+  scanf ("%ms", sp); /* { dg-warning "unknown|format" "%ms is unsupported" } */
+  scanf ("%mS", lsp); /* { dg-warning "unknown|format" "%mS is unsupported" } */
+  scanf ("%mls", lsp); /* { dg-warning "unknown|format" "%mls is unsupported" } */
+  scanf ("%m[bcd]", sp); /* { dg-warning "unknown|format" "%m[] is unsupported" } */
+  scanf ("%ml[bcd]", lsp); /* { dg-warning "unknown|format" "%ml[] is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-1.c
@@ -0,0 +1,22 @@
+/* Test for strftime formats.  Formats using C99 features.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat -Wformat-y2k" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.12.3.5 (pages 174-175).  */
+  /* Formats which are Y2K-compliant (no 2-digit years).  */
+  strftime (s, m, "%a%A%b%B%d%H%I%j%m%M%p%S%U%w%W%X%Y%z%Z%%", tp);
+  /* Formats with 2-digit years.  */
+  strftime (s, m, "%D", tp);
+  strftime (s, m, "%g", tp);
+  strftime (s, m, "%y", tp);
+  /* Formats with 2-digit years in some locales.  */
+  strftime (s, m, "%c", tp);
+  strftime (s, m, "%x", tp);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-2.c
@@ -0,0 +1,20 @@
+/* Test for strftime formats.  Rejection of extensions in pedantic mode.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  /* %P is a lowercase version of %p.  */
+  strftime (s, m, "%P", tp); /* { dg-warning "unknown" "strftime %P" } */
+  /* %k is %H but padded with a space rather than 0 if necessary.  */
+  strftime (s, m, "%k", tp); /* { dg-warning "unknown" "strftime %k" } */
+  /* %l is %I but padded with a space rather than 0 if necessary.  */
+  strftime (s, m, "%l", tp); /* { dg-warning "unknown" "strftime %l" } */
+  /* %s is the number of seconds since the Epoch.  */
+  strftime (s, m, "%s", tp); /* { dg-warning "unknown" "strftime %s" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_cast-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_cast-1.c
@@ -0,0 +1,17 @@
+/* Test for strings cast through integer types: should not be treated
+   as format strings unless the types are of the same width as
+   pointers (intptr_t or similar).  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+f (int x)
+{
+  printf("%s", x); /* { dg-warning "format" } */
+  printf((char *)(size_t)"%s", x); /* { dg-warning "format" } */
+  printf((char *)(char)"%s", x); /* { dg-warning "cast from pointer to integer of different size" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-1.c
@@ -0,0 +1,40 @@
+/* Test for warnings for missing format attributes.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  vprintf (fmt, ap); /* { dg-warning "candidate" "printf attribute warning" } */
+  va_end (ap);
+}
+
+void
+bar (const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  vscanf (fmt, ap); /* { dg-warning "candidate" "scanf attribute warning" } */
+  va_end (ap);
+}
+
+__attribute__((__format__(__ms_printf__, 1, 2))) void
+foo2 (const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  vprintf (fmt, ap);
+  va_end (ap);
+}
+
+void
+vfoo (const char *fmt, va_list arg)
+{
+  vprintf (fmt, arg); /* { dg-warning "candidate" "printf attribute warning 2" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-2.c
@@ -0,0 +1,17 @@
+/* Test for warnings for missing format attributes.  Don't warn if no
+   relevant parameters for a format attribute; see c/1017.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, ...)
+{
+  va_list ap;
+  va_start (ap, i);
+  vprintf ("Foo %s bar %s", ap); /* { dg-bogus "candidate" "bogus printf attribute warning" } */
+  va_end (ap);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-3.c
@@ -0,0 +1,27 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+void
+foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
+{
+  noattr_t na1 = na;
+  noattr_t na2 = a; /* { dg-warning "candidate" "initialization warning" } */
+  attr_t a1 = na;
+  attr_t a2 = a;
+
+  vnoattr_t vna1 = vna;
+  vnoattr_t vna2 = va; /* { dg-warning "candidate" "initialization warning" } */
+  vattr_t va1 = vna;
+  vattr_t va2 = va;
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-4.c
@@ -0,0 +1,33 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+void
+foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
+{
+  noattr_t na1, na2;
+  attr_t a1, a2;
+
+  vnoattr_t vna1, vna2;
+  vattr_t va1, va2;
+
+  na1 = na;
+  na2 = a; /* { dg-warning "candidate" "assignment warning" } */
+  a1 = na;
+  a2 = a;
+
+  vna1 = vna;
+  vna2 = va; /* { dg-warning "candidate" "assignment warning" } */
+  va1 = vna;
+  va1 = va;
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-5.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-5.c
@@ -0,0 +1,49 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+noattr_t
+foo1 (noattr_t na, attr_t a, int i)
+{
+  if (i)
+    return na;
+  else
+    return a; /* { dg-warning "candidate" "return type warning" } */
+}
+
+attr_t
+foo2 (noattr_t na, attr_t a, int i)
+{
+  if (i)
+    return na;
+  else
+    return a;
+}
+
+vnoattr_t
+foo3 (vnoattr_t vna, vattr_t va, int i)
+{
+  if (i)
+    return vna;
+  else
+    return va; /* { dg-warning "candidate" "return type warning" } */
+}
+
+vattr_t
+foo4 (vnoattr_t vna, vattr_t va, int i)
+{
+  if (i)
+    return vna;
+  else
+    return va;
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-6.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-6.c
@@ -0,0 +1,32 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+extern void foo1 (noattr_t);
+extern void foo2 (attr_t);
+extern void foo3 (vnoattr_t);
+extern void foo4 (vattr_t);
+
+void
+foo (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
+{
+  foo1 (na);
+  foo1 (a); /* { dg-warning "candidate" "parameter passing warning" } */
+  foo2 (na);
+  foo2 (a);
+
+  foo3 (vna);
+  foo3 (va); /* { dg-warning "candidate" "parameter passing warning" } */
+  foo4 (vna);
+  foo4 (va);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_multattr-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_multattr-1.c
@@ -0,0 +1,51 @@
+/* Test for multiple format attributes.  Test for printf and scanf attributes
+   together.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* If we specify multiple attributes for a single function, they should
+   all apply.  This should apply whether they are on the same declaration
+   or on different declarations.  */
+
+extern void my_vprintf_scanf (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_printf__, 1, 0)))
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern void my_vprintf_scanf2 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)))
+     __attribute__((__format__(__ms_printf__, 1, 0)));
+
+extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_printf__, 1, 0)));
+extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_printf__, 1, 0)));
+
+void
+foo (va_list ap, int *ip, long *lp)
+{
+  my_vprintf_scanf ("%d", ap, "%d", ip);
+  my_vprintf_scanf ("%d", ap, "%ld", lp);
+  my_vprintf_scanf ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf2 ("%d", ap, "%d", ip);
+  my_vprintf_scanf2 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf2 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf2 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf3 ("%d", ap, "%d", ip);
+  my_vprintf_scanf3 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf3 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf3 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf4 ("%d", ap, "%d", ip);
+  my_vprintf_scanf4 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf4 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf4 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_multattr-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_multattr-2.c
@@ -0,0 +1,40 @@
+/* Test for multiple format attributes.  Test for printf and scanf attributes
+   together, in different places on the declarations.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* If we specify multiple attributes for a single function, they should
+   all apply, wherever they are placed on the declarations.  */
+
+extern __attribute__((__format__(__ms_printf__, 1, 0))) void
+     my_vprintf_scanf (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern void (__attribute__((__format__(__ms_printf__, 1, 0))) my_vprintf_scanf2)
+     (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern __attribute__((__format__(__ms_scanf__, 3, 4))) void
+     (__attribute__((__format__(__ms_printf__, 1, 0))) my_vprintf_scanf3)
+     (const char *, va_list, const char *, ...);
+
+void
+foo (va_list ap, int *ip, long *lp)
+{
+  my_vprintf_scanf ("%d", ap, "%d", ip);
+  my_vprintf_scanf ("%d", ap, "%ld", lp);
+  my_vprintf_scanf ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf2 ("%d", ap, "%d", ip);
+  my_vprintf_scanf2 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf2 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf2 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf3 ("%d", ap, "%d", ip);
+  my_vprintf_scanf3 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf3 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf3 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_multattr-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_multattr-3.c
@@ -0,0 +1,29 @@
+/* Test for multiple format_arg attributes.  Test for both branches
+   getting checked.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+extern char *ngettext (const char *, const char *, unsigned long int)
+     __attribute__((__format_arg__(1))) __attribute__((__format_arg__(2)));
+
+void
+foo (long l, int nfoo)
+{
+  printf (ngettext ("%d foo", "%d foos", nfoo), nfoo);
+  printf (ngettext ("%d foo", "%d foos", l), l); /* { dg-warning "int" "wrong type in conditional expr" } */
+  printf (ngettext ("%d foo", "%ld foos", l), l); /* { dg-warning "int" "wrong type in conditional expr" } */
+  printf (ngettext ("%ld foo", "%d foos", l), l); /* { dg-warning "int" "wrong type in conditional expr" } */
+  /* Should allow one case to have extra arguments.  */
+  printf (ngettext ("1 foo", "%d foos", nfoo), nfoo);
+  printf (ngettext ("1 foo", "many foos", nfoo), nfoo); /* { dg-warning "too many" "too many args in all branches" } */
+  printf (ngettext ("", "%d foos", nfoo), nfoo);
+  printf (ngettext ("1 foo", (nfoo > 0) ? "%d foos" : "no foos", nfoo), nfoo);
+  printf (ngettext ("%d foo", (nfoo > 0) ? "%d foos" : "no foos", nfoo), nfoo);
+  printf (ngettext ("%ld foo", (nfoo > 0) ? "%d foos" : "no foos", nfoo), nfoo); /* { dg-warning "long int" "wrong type" } */
+  printf (ngettext ("%d foo", (nfoo > 0) ? "%ld foos" : "no foos", nfoo), nfoo); /* { dg-warning "long int" "wrong type" } */
+  printf (ngettext ("%d foo", (nfoo > 0) ? "%d foos" : "%ld foos", nfoo), nfoo); /* { dg-warning "long int" "wrong type" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-1.c
@@ -0,0 +1,15 @@
+/* Test for warnings for extra format arguments being disabled by
+   -Wno-format-extra-args.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wno-format-extra-args" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i)
+{
+  printf ("foo", i);
+  printf ("%1$d", i, i);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-2.c
@@ -0,0 +1,28 @@
+/* Test for warnings for extra format arguments being disabled by
+   -Wno-format-extra-args.  Test which warnings still apply with $
+   operand numbers.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wno-format-extra-args" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, int *ip, va_list va)
+{
+  printf ("%3$d%1$d", i, i, i); /* { dg-warning "before used" "unused $ operand" } */
+  printf ("%2$d%1$d", i, i, i);
+  vprintf ("%3$d%1$d", va); /* { dg-warning "before used" "unused $ operand" } */
+  /* With scanf formats, gaps in the used arguments are allowed only if the
+     arguments are all pointers.  In such a case, should only give the lesser
+     warning about unused arguments rather than the more serious one about
+     argument gaps.  */
+  scanf ("%3$d%1$d", ip, ip, ip);
+  /* If there are non-pointer arguments unused at the end, this is also OK.  */
+  scanf ("%3$d%1$d", ip, ip, ip, i);
+  scanf ("%3$d%1$d", ip, i, ip); /* { dg-warning "before used" "unused $ scanf non-pointer operand" } */
+  /* Can't check the arguments in the vscanf case, so should suppose the
+     lesser problem.  */
+  vscanf ("%3$d%1$d", va);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_no-y2k-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_no-y2k-1.c
@@ -0,0 +1,13 @@
+/* Test for warnings for Y2K problems not being on by default.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  strftime (s, m, "%y%c%x", tp);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-1.c
@@ -0,0 +1,14 @@
+/* Test for warnings for non-string-literal formats.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wformat-nonliteral" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t i)
+{
+  printf ((const char *)i, i); /* { dg-warning "argument types" "non-literal" } */
+  printf (s, i); /* { dg-warning "argument types" "non-literal" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-2.c
@@ -0,0 +1,14 @@
+/* Test for warnings for non-string-literal formats.  Test with -Wformat=2.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat=2" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t i)
+{
+  printf ((const char *)i, i); /* { dg-warning "argument types" "non-literal" } */
+  printf (s, i); /* { dg-warning "argument types" "non-literal" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-3.c
@@ -0,0 +1,13 @@
+/* Test for warnings for non-string-literal formats.  Test for strftime formats.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wformat-nonliteral" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp, char *fmt)
+{
+  strftime (s, m, fmt, tp); /* { dg-warning "format string" "non-literal" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nul-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nul-1.c
@@ -0,0 +1,15 @@
+/* Test diagnostics for suppressing contains nul
+   -Wformat.  -Wformat.  */
+/* Origin: Bruce Korb <bkorb@gnu.org> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat -Wno-format-contains-nul" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (void)
+{
+  static char const fmt[] = "x%s\0%s\n\0abc";
+  printf (fmt+4, fmt+8); /* { dg-bogus "embedded.*in format" "bogus embed warning" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nul-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nul-2.c
@@ -0,0 +1,17 @@
+/* Test diagnostics for options used on their own without
+   -Wformat.  -Wformat-.  */
+/* Origin: Bruce Korb <bkorb@gnu.org> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+
+/* { dg-warning "embedded .* in format" "ignored" { target *-*-* } 0 } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+fumble (void)
+{
+  static char const fmt[] = "x%s\0%s\n\0abc";
+  printf (fmt+4, fmt+8);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_null-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_null-1.c
@@ -0,0 +1,28 @@
+/* Test for some aspects of null format string handling.  */
+/* Origin: Jason Thorpe <thorpej@wasabisystems.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+extern void my_printf (const char *, ...) __attribute__((format(ms_printf,1,2)));
+extern const char *my_format (const char *, const char *)
+  __attribute__((format_arg(2)));
+
+void
+foo (int i1)
+{
+  /* Warning about a null format string has been decoupled from the actual
+     format check.  However, we still expect to be warned about any excess
+     arguments after a null format string.  */
+  my_printf (NULL);
+  my_printf (NULL, i1); /* { dg-warning "too many" "null format with arguments" } */
+
+  my_printf (my_format ("", NULL));
+  my_printf (my_format ("", NULL), i1); /* { dg-warning "too many" "null format_arg with arguments" } */
+
+  /* While my_printf allows a null argument, dgettext does not, so we expect
+     a null argument warning here.  */
+  my_printf (dgettext ("", NULL)); /* { dg-warning "null" "null format with dgettext" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_plus-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_plus-1.c
@@ -0,0 +1,21 @@
+/* Test for printf formats using string literal plus constant.
+ */
+/* Origin: Jakub Jelinek <jakub@redhat.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat=2" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i)
+{
+  printf ("%%d\n" + 1, i);
+  printf (5 + "%.-*d%3d\n", i);
+  printf ("%d%d" + 2, i, i);	/* { dg-warning "arguments" "wrong number of args" } */
+  printf (3 + "%d\n");		/* { dg-warning "zero-length" "zero-length string" } */
+  printf ("%d\n" + i, i);	/* { dg-warning "not a string" "non-constant addend" } */
+  printf ("%d\n" + 10);		/* { dg-warning "not a string" "too large addend" } */
+  printf ("%d\n" - 1, i);	/* { dg-warning "not a string" "minus constant" } */
+  printf ("%d\n" + -1, i);	/* { dg-warning "not a string" "negative addend" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_sec-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_sec-1.c
@@ -0,0 +1,13 @@
+/* Test for security warning when non-literal format has no arguments.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wformat-security" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s)
+{
+  printf (s); /* { dg-warning "no format arguments" "security warning" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_unnamed-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_unnamed-1.c
@@ -0,0 +1,24 @@
+/* Test for warnings with possibly unnamed integer types.  Bug 24329.  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+/* { dg-options "-Wformat -msse" { target { { i?86-*-* x86_64-*-* } && ilp32 } } } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* Definition of TItype follows same logic as in gcc.dg/titype-1.c,
+   but must be a #define to avoid giving the type a name.  */
+#if defined(__LP64__) && !defined(__hppa__)
+#define TItype int __attribute__ ((mode (TI)))
+#else
+#define TItype long
+#endif
+
+void
+f (TItype x)
+{
+  printf("%d", x); /* { dg-warning "expects type" } */
+  printf("%d", 141592653589793238462643383279502884197169399375105820974944); /* { dg-warning "expects type" } */
+  /* { dg-warning "unsigned only|too large" "constant" { target *-*-* } 22 } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_va-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_va-1.c
@@ -0,0 +1,14 @@
+/* Test for strange warning in format checking.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (void *p)
+{
+  printf ("%d", p); /* { dg-bogus "va_list" "wrong type in format warning" } */
+  /* { dg-warning "format" "format error" { target *-*-* } 12 } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_warnll-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_warnll-1.c
@@ -0,0 +1,19 @@
+/* Test for printf formats.  C99 "long long" formats should be accepted with
+   -Wno-long-long.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wno-long-long" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (long long ll, unsigned long long ull, long long *lln,
+     long long *llp, unsigned long long *ullp)
+{
+  /* Test for accepting standard "long long" formats.  */
+  printf ("%I64d%I64i%I64o%I64u%I64x%I64X%I64n", ll, ll, ull, ull, ull, ull, lln);
+  scanf ("%I64d%I64i%I64o%I64u%I64x%I64X%I64n", llp, llp,
+	 ullp, ullp, ullp, ullp, lln);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_zero-length-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_zero-length-1.c
@@ -0,0 +1,16 @@
+/* Test the -Wno-format-zero-length option, which suppresses warnings
+   about zero-length formats.  */
+/* Origin: Jason Thorpe <thorpej@wasabisystems.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wno-format-zero-length" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (void)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.1 (pages 131-134).  */
+  /* Zero-length format strings are allowed.  */
+  printf ("");
+}
Index: gcc/gcc/testsuite/gcc.dg/format/multattr-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/multattr-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/multattr-1.c
@@ -4,6 +4,7 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 /* If we specify multiple attributes for a single function, they should
@@ -11,22 +12,22 @@
    or on different declarations.  */
 
 extern void my_vprintf_scanf (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__printf__, 1, 0)))
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)))
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
 extern void my_vprintf_scanf2 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)))
-     __attribute__((__format__(__printf__, 1, 0)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)))
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)));
 
 extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__printf__, 1, 0)));
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)));
 extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
 extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__printf__, 1, 0)));
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)));
 
 void
 foo (va_list ap, int *ip, long *lp)
Index: gcc/gcc/testsuite/gcc.dg/format/multattr-2.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/multattr-2.c
+++ gcc/gcc/testsuite/gcc.dg/format/multattr-2.c
@@ -4,21 +4,22 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 /* If we specify multiple attributes for a single function, they should
    all apply, wherever they are placed on the declarations.  */
 
-extern __attribute__((__format__(__printf__, 1, 0))) void
+extern __attribute__((__format__(gnu_attr___printf__, 1, 0))) void
      my_vprintf_scanf (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
-extern void (__attribute__((__format__(__printf__, 1, 0))) my_vprintf_scanf2)
+extern void (__attribute__((__format__(gnu_attr___printf__, 1, 0))) my_vprintf_scanf2)
      (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
-extern __attribute__((__format__(__scanf__, 3, 4))) void
-     (__attribute__((__format__(__printf__, 1, 0))) my_vprintf_scanf3)
+extern __attribute__((__format__(gnu_attr___scanf__, 3, 4))) void
+     (__attribute__((__format__(gnu_attr___printf__, 1, 0))) my_vprintf_scanf3)
      (const char *, va_list, const char *, ...);
 
 void
Index: gcc/gcc/testsuite/gcc.dg/format/null-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/null-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/null-1.c
@@ -3,9 +3,10 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern void my_printf (const char *, ...) __attribute__((format(printf,1,2)));
+extern void my_printf (const char *, ...) __attribute__((format(gnu_attr_printf,1,2)));
 extern const char *my_format (const char *, const char *)
   __attribute__((format_arg(2)));
 
=

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf   formatters to c-format.c
  2008-03-13 19:24                             ` Ralf Wildenhues
@ 2008-03-14  9:32                               ` Kai Tietz
  0 siblings, 0 replies; 61+ messages in thread
From: Kai Tietz @ 2008-03-14  9:32 UTC (permalink / raw)
  To: Ralf Wildenhues; +Cc: Danny Smith, GCC Patches, ktietz70, NightStrike

Hello Ralf,
 
Ralf Wildenhues <Ralf.Wildenhues@gmx.de> wrote on 13.03.2008 20:23:54:

> a couple of typo nits:

Thanks. I correct them so far.

Cheers,
  Kai

|  (\_/)  This is Bunny. Copy and paste Bunny
| (='.'=) into your signature to help him gain
| (")_(") world domination.

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf formatters to c-format.c
  2008-03-13  9:29                           ` Kai Tietz
  2008-03-13 19:24                             ` Ralf Wildenhues
@ 2008-03-13 20:52                             ` Danny Smith
  2008-03-14 11:00                               ` Kai Tietz
  1 sibling, 1 reply; 61+ messages in thread
From: Danny Smith @ 2008-03-13 20:52 UTC (permalink / raw)
  To: Kai Tietz; +Cc: GCC Patches, ktietz70, NightStrike

[-- Attachment #1: Type: text/plain, Size: 379 bytes --]

>  >
>  > I see 44 format.exp failures in testsuite  with your patch
>  I corrected the test-cases so far.

Well I suppose one way to correct the test case is just to remove some
tests, but your revised patch doesn't really address the problems with
strftime.
Attached is log of "make -k check-gcc RUNTESTFLAGS=format.exp" using
prior patch.  Do you not see these errors?

Danny

[-- Attachment #2: gcc.log.gz --]
[-- Type: application/x-gzip, Size: 54414 bytes --]

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS  printf  formatters to c-format.c
  2008-03-13  9:29                           ` Kai Tietz
@ 2008-03-13 19:24                             ` Ralf Wildenhues
  2008-03-14  9:32                               ` Kai Tietz
  2008-03-13 20:52                             ` Danny Smith
  1 sibling, 1 reply; 61+ messages in thread
From: Ralf Wildenhues @ 2008-03-13 19:24 UTC (permalink / raw)
  To: Kai Tietz; +Cc: Danny Smith, GCC Patches, ktietz70, NightStrike

Hello Kai,

a couple of typo nits:

* Kai Tietz wrote on Thu, Mar 13, 2008 at 10:28:16AM CET:
> --- gcc.orig/gcc/doc/extend.texi
> +++ gcc/gcc/doc/extend.texi
> @@ -2204,13 +2204,22 @@ for consistency with the @code{printf} s
[...]
> +@code{__scanf__}, @code{__strftime__} or @code{__strfmon__}.)  On
> +MinGW targets there is also @code{ms_printf}, @code{ms_scanf}, and
> +@code{ms_strftime} present.

On MinGW targets, @code{...}..., and @code{...} are also present.

> --- gcc.orig/gcc/doc/tm.texi
> +++ gcc/gcc/doc/tm.texi
> @@ -10319,6 +10319,18 @@ If defined, this macro is the number of 
>  @code{TARGET_FORMAT_TYPES}.
>  @end defmac
>  
> +@defmac TARGET_OVERRIDES_FORMAT_ATTRIBUTES
> +If defined, this macro is the name of a global variable containg

s/containg/containing/

> +target-specific format overrides for the @option{-Wformat} option. The
> +default is to have no target-specific format overrides. If defined,
> +@code{TARGET_FORMAT_TYPES} must be defined too.
> +@end defmac

> --- /dev/null
> +++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-2.c
> @@ -0,0 +1,33 @@
[...]
> +  printf ("%qd", ll); /* { dg-warning "unknown|format" "%q length is unsupported" } */
> +  printf ("%Ld", ll); /* { dg-warning "unknown|format" "%L length is unsupported" } */
> +  printf ("%Zd", z); /* { dg-warning "unknown|format" "%Z lengthis unsupported" } */

s/lengthis/ length is/

Cheers,
Ralf

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf  formatters to c-format.c
  2008-03-13  0:03                         ` Danny Smith
  2008-03-13  8:43                           ` Kai Tietz
@ 2008-03-13  9:29                           ` Kai Tietz
  2008-03-13 19:24                             ` Ralf Wildenhues
  2008-03-13 20:52                             ` Danny Smith
  1 sibling, 2 replies; 61+ messages in thread
From: Kai Tietz @ 2008-03-13  9:29 UTC (permalink / raw)
  To: Danny Smith; +Cc: GCC Patches, ktietz70, NightStrike

[-- Attachment #1: Type: text/plain, Size: 872 bytes --]

"Danny Smith" <dansmister@gmail.com> wrote on 13.03.2008 01:02:48:

> On Tue, Mar 11, 2008 at 11:29 AM, Joseph S. Myers
> <joseph@codesourcery.com> wrote:
> > On Mon, 10 Mar 2008, Kai Tietz wrote:
> >
> >  > > Note that this part of the patch will need reviewing by a MinGW
> >  > > maintainer.
> >  >
> >  > Danny, could you do that?
> >  >
> >  > Is this ok for apply to trunk?
> >
> >  The C front end parts of the patch are OK.  As noted before, the 
MinGW
> >  parts (in particular the tables and the new testcases) will need 
reviewing
> >  by a MinGW maintainer.
> >
> >
> Kai.
> 
> I see 44 format.exp failures in testsuite  with your patch
I corrected the test-cases so far.

> The summary is attached.
Thank you very much.

Cheers,
  Kai



|  (\_/)  This is Bunny. Copy and paste Bunny
| (='.'=) into your signature to help him gain
| (")_(") world domination.

[-- Attachment #2: mingw-msformat.txt --]
[-- Type: text/plain, Size: 153082 bytes --]

Index: gcc/gcc/c-format.c
===================================================================
--- gcc.orig/gcc/c-format.c
+++ gcc/gcc/c-format.c
@@ -62,8 +62,7 @@ enum format_type { printf_format_type, a
 		   gcc_diag_format_type, gcc_tdiag_format_type,
 		   gcc_cdiag_format_type,
 		   gcc_cxxdiag_format_type, gcc_gfc_format_type,
-		   scanf_format_type, strftime_format_type,
-		   strfmon_format_type, format_type_error = -1};
+		   format_type_error = -1};
 
 typedef struct function_format_info
 {
@@ -80,7 +79,8 @@ static bool check_format_string (tree ar
 				 int flags, bool *no_add_attrs);
 static bool get_constant (tree expr, unsigned HOST_WIDE_INT *value,
 			  int validated_p);
-
+static const char *convert_format_name_to_system_name (const char *attr_name);
+static bool cmp_attribs (const char *tattr_name, const char *attr_name);
 
 /* Handle a "format_arg" attribute; arguments as in
    struct attribute_spec.handler.  */
@@ -191,6 +191,8 @@ decode_format_attr (tree args, function_
     {
       const char *p = IDENTIFIER_POINTER (format_type_id);
 
+      p = convert_format_name_to_system_name (p);
+
       info->format_type = decode_format_type (p);
 
       if (info->format_type == format_type_error)
@@ -715,7 +717,7 @@ static const format_char_info monetary_c
 /* This must be in the same order as enum format_type.  */
 static const format_kind_info format_types_orig[] =
 {
-  { "printf",   printf_length_specs,  print_char_table, " +#0-'I", NULL,
+  { "gnu_printf",   printf_length_specs,  print_char_table, " +#0-'I", NULL,
     printf_flag_specs, printf_flag_pairs,
     FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
     'w', 0, 'p', 0, 'L', 0,
@@ -757,18 +759,18 @@ static const format_kind_info format_typ
     0, 0, 0, 0, 0, 0,
     NULL, NULL
   },
-  { "scanf",    scanf_length_specs,   scan_char_table,  "*'I", NULL,
+  { "gnu_scanf",    scanf_length_specs,   scan_char_table,  "*'I", NULL,
     scanf_flag_specs, scanf_flag_pairs,
     FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
     'w', 0, 0, '*', 'L', 'm',
     NULL, NULL
   },
-  { "strftime", NULL,                 time_char_table,  "_-0^#", "EO",
+  { "gnu_strftime", NULL,                 time_char_table,  "_-0^#", "EO",
     strftime_flag_specs, strftime_flag_pairs,
     FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0, 0,
     NULL, NULL
   },
-  { "strfmon",  strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
+  { "gnu_strfmon",  strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
     strfmon_flag_specs, strfmon_flag_pairs,
     FMT_FLAG_ARG_CONVERT, 'w', '#', 'p', 0, 'L', 0,
     NULL, NULL
@@ -847,6 +849,8 @@ decode_format_type (const char *s)
 {
   int i;
   int slen;
+
+  s = convert_format_name_to_system_name (s);
   slen = strlen (s);
   for (i = 0; i < n_format_types; i++)
     {
@@ -1776,7 +1780,22 @@ check_format_info_main (format_check_res
       if (fli)
 	{
 	  while (fli->name != 0 && fli->name[0] != *format_chars)
-	    fli++;
+	    {
+	      if (fli->name[0] == '\0')
+		{
+		  int si  = strlen (fli->name + 1) + 1;
+		  int i = 1;
+		  while (fli->name[i] != 0 && fli->name[i] == format_chars [i - 1])
+		    ++i;
+		 if (si == i)
+		   {
+		     if (si > 2)
+		       format_chars += si - 2;
+		     break;
+		   }
+	       }
+	      fli++;
+	    }
 	  if (fli->name != 0)
 	    {
 	      format_chars++;
@@ -2703,6 +2722,84 @@ init_dynamic_diag_info (void)
 extern const format_kind_info TARGET_FORMAT_TYPES[];
 #endif
 
+#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+extern const target_ovr_attr TARGET_OVERRIDES_FORMAT_ATTRIBUTES[];
+#endif
+
+/* Attributes such as "printf" are equivalent to those such as
+   "gnu_printf" unless this is overridden by a target.  */
+static const target_ovr_attr gnu_target_overrides_format_attributes[] =
+{
+  { "gnu_printf",   "printf" },
+  { "gnu_scanf",    "scanf" },
+  { "gnu_strftime", "strftime" },
+  { "gnu_strfmon",  "strfmon" },
+  { NULL,           NULL }
+};
+
+/* Translate to unified attribute name. This is used in decode_format_type and
+   decode_format_attr. In attr_name the user specified argument is passed. It
+   returns the unified format name from TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+   or the attr_name passed to this function, if there is no matching entry.  */
+static const char *
+convert_format_name_to_system_name (const char *attr_name)
+{
+  int i;
+
+  if (attr_name == NULL || *attr_name == 0
+      || strncmp (attr_name, "gcc_", 4) == 0)
+    return attr_name;
+
+#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+  /* Check if format attribute is overridden by target.  */
+  if (TARGET_OVERRIDES_FORMAT_ATTRIBUTES != NULL
+      && TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT > 0)
+    {
+      for (i = 0; i < TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT; ++i)
+        {
+          if (cmp_attribs (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src,
+			   attr_name))
+            return attr_name;
+          if (cmp_attribs (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_dst,
+			   attr_name))
+            return TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src;
+        }
+    }
+#endif
+  /* Otherwise default to gnu format.  */
+  for (i = 0;
+       gnu_target_overrides_format_attributes[i].named_attr_src != NULL;
+       ++i)
+    {
+      if (cmp_attribs (gnu_target_overrides_format_attributes[i].named_attr_src,
+		       attr_name))
+        return attr_name;
+      if (cmp_attribs (gnu_target_overrides_format_attributes[i].named_attr_dst,
+		       attr_name))
+        return gnu_target_overrides_format_attributes[i].named_attr_src;
+    }
+
+  return attr_name;
+}
+
+/* Return true if TATTR_NAME and ATTR_NAME are the same format attribute,
+   counting "name" and "__name__" as the same, false otherwise.  */
+static bool
+cmp_attribs (const char *tattr_name, const char *attr_name)
+{
+  int alen = strlen (attr_name);
+  int slen = (tattr_name ? strlen (tattr_name) : 0);
+  if (alen > 4 && attr_name[0] == '_' && attr_name[1] == '_'
+      && attr_name[alen - 1] == '_' && attr_name[alen - 2] == '_')
+    {
+      attr_name += 2;
+      alen -= 4;
+    }
+  if (alen != slen || strncmp (tattr_name, attr_name, alen) != 0)
+    return false;
+  return true;
+}
+
 /* Handle a "format" attribute; arguments as in
    struct attribute_spec.handler.  */
 tree
@@ -2762,7 +2859,10 @@ handle_format_attribute (tree *node, tre
 	}
     }
 
-  if (info.format_type == strftime_format_type && info.first_arg_num != 0)
+  /* Check if this is a strftime variant. Just for this variant
+     FMT_FLAG_ARG_CONVERT is not set.  */
+  if ((format_types[info.format_type].flags & (int) FMT_FLAG_ARG_CONVERT) == 0
+      && info.first_arg_num != 0)
     {
       error ("strftime formats cannot format arguments");
       *no_add_attrs = true;
Index: gcc/gcc/c-format.h
===================================================================
--- gcc.orig/gcc/c-format.h
+++ gcc/gcc/c-format.h
@@ -80,12 +80,13 @@ enum
      of whether length modifiers can occur (length_char_specs).  */
 };
 
-
 /* Structure describing a length modifier supported in format checking, and
    possibly a doubled version such as "hh".  */
 typedef struct
 {
-  /* Name of the single-character length modifier.  */
+  /* Name of the single-character length modifier. If prefixed by
+     a zero character, it describes a multi character length
+     modifier, like I64, I32, etc.  */
   const char *name;
   /* Index into a format_char_info.types array.  */
   enum format_lengths index;
@@ -306,4 +307,16 @@ typedef struct
 #define T_D128  &dfloat128_type_node
 #define TEX_D128 { STD_EXT, "_Decimal128", T_D128 }
 
+/* Structure describing how format attributes such as "printf" are
+   interpreted as "gnu_printf" or "ms_printf" on a particular system.
+   TARGET_OVERRIDES_FORMAT_ATTRIBUTES is used to specify target-specific
+   defaults.  */
+typedef struct
+{
+  /* The name of the to be copied format attribute. */
+  const char *named_attr_src;
+  /* The name of the to be overridden format attribute. */
+  const char *named_attr_dst;
+} target_ovr_attr;
+
 #endif /* GCC_C_FORMAT_H */
Index: gcc/gcc/config.gcc
===================================================================
--- gcc.orig/gcc/config.gcc
+++ gcc/gcc/config.gcc
@@ -1372,8 +1372,8 @@ i[34567]86-*-pe | i[34567]86-*-cygwin*)
 	target_gtfiles="\$(srcdir)/config/i386/winnt.c"
 	extra_options="${extra_options} i386/cygming.opt"
 	extra_objs="winnt.o winnt-stubs.o"
-	c_target_objs=cygwin2.o
-	cxx_target_objs="cygwin2.o winnt-cxx.o"
+	c_target_objs="cygwin2.o msformat-c.o"
+	cxx_target_objs="cygwin2.o winnt-cxx.o msformat-c.o"
 	extra_gcc_objs=cygwin1.o
 	if test x$enable_threads = xyes; then
 		thread_file='posix'
@@ -1386,7 +1386,8 @@ i[34567]86-*-mingw32* | x86_64-*-mingw32
 	target_gtfiles="\$(srcdir)/config/i386/winnt.c"
 	extra_options="${extra_options} i386/cygming.opt"
 	extra_objs="winnt.o winnt-stubs.o"
-	cxx_target_objs=winnt-cxx.o
+	c_target_objs="msformat-c.o"
+	cxx_target_objs="winnt-cxx.o msformat-c.o"
 	default_use_cxa_atexit=yes
 	case ${enable_threads} in
 	  "" | yes | win32)
Index: gcc/gcc/config/i386/mingw32.h
===================================================================
--- gcc.orig/gcc/config/i386/mingw32.h
+++ gcc/gcc/config/i386/mingw32.h
@@ -143,6 +143,23 @@ do {						         \
    to register C++ static destructors.  */
 #define TARGET_CXX_USE_ATEXIT_FOR_CXA_ATEXIT hook_bool_void_true
 
+/* Contains a pointer to type target_ovr_attr defining the target specific
+   overrides of format attributes.  See c-format.h for structure
+   definition.  */
+#undef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+#define TARGET_OVERRIDES_FORMAT_ATTRIBUTES mingw_format_attribute_overrides
+
+/* Specify the count of elements in TARGET_OVERRIDES_ATTRIBUTE.  */
+#undef TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT
+#define TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT 3
+
+/* MS specific format attributes for ms_printf, ms_scanf, ms_strftime.  */
+#undef TARGET_FORMAT_TYPES
+#define TARGET_FORMAT_TYPES mingw_format_attributes
+
+#undef TARGET_N_FORMAT_TYPES
+#define TARGET_N_FORMAT_TYPES 3
+
 /* JCR_SECTION works on mingw32.  */
 #undef TARGET_USE_JCR_SECTION
 #define TARGET_USE_JCR_SECTION 1
Index: gcc/gcc/config/i386/msformat-c.c
===================================================================
--- /dev/null
+++ gcc/gcc/config/i386/msformat-c.c
@@ -0,0 +1,176 @@
+/* Check calls to formatted I/O functions (-Wformat).
+   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+   2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "flags.h"
+#include "c-common.h"
+#include "toplev.h"
+#include "intl.h"
+#include "diagnostic.h"
+#include "langhooks.h"
+#include "c-format.h"
+#include "alloc-pool.h"
+
+/* Mingw specific format attributes ms_printf, ms_scanf, and ms_strftime.  */
+
+static const format_length_info ms_printf_length_specs[] =
+{
+  { "h", FMT_LEN_h, STD_C89, NULL, 0, 0 },
+  { "l", FMT_LEN_l, STD_C89, NULL, 0, 0 },
+  { "\0I32", FMT_LEN_l, STD_EXT, NULL, 0, 0 },
+  { "\0I64", FMT_LEN_ll, STD_EXT, NULL, 0, 0 },
+  { "I", FMT_LEN_L, STD_EXT, NULL, 0, 0 },
+  { NULL, 0, 0, NULL, 0, 0 }
+};
+
+static const format_flag_spec ms_printf_flag_specs[] =
+{
+  { ' ',  0, 0, N_("' ' flag"),        N_("the ' ' printf flag"),              STD_C89 },
+  { '+',  0, 0, N_("'+' flag"),        N_("the '+' printf flag"),              STD_C89 },
+  { '#',  0, 0, N_("'#' flag"),        N_("the '#' printf flag"),              STD_C89 },
+  { '0',  0, 0, N_("'0' flag"),        N_("the '0' printf flag"),              STD_C89 },
+  { '-',  0, 0, N_("'-' flag"),        N_("the '-' printf flag"),              STD_C89 },
+  { '\'', 0, 0, N_("''' flag"),        N_("the ''' printf flag"),              STD_EXT },
+  { 'w',  0, 0, N_("field width"),     N_("field width in printf format"),     STD_C89 },
+  { 'p',  0, 0, N_("precision"),       N_("precision in printf format"),       STD_C89 },
+  { 'L',  0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_printf_flag_pairs[] =
+{
+  { ' ', '+', 1, 0   },
+  { '0', '-', 1, 0   }, { '0', 'p', 1, 'i' },
+  { 0, 0, 0, 0 }
+};
+
+static const format_flag_spec ms_scanf_flag_specs[] =
+{
+  { '*',  0, 0, N_("assignment suppression"), N_("the assignment suppression scanf feature"), STD_C89 },
+  { 'a',  0, 0, N_("'a' flag"),               N_("the 'a' scanf flag"),                       STD_EXT },
+  { 'w',  0, 0, N_("field width"),            N_("field width in scanf format"),              STD_C89 },
+  { 'L',  0, 0, N_("length modifier"),        N_("length modifier in scanf format"),          STD_C89 },
+  { '\'', 0, 0, N_("''' flag"),               N_("the ''' scanf flag"),                       STD_EXT },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_scanf_flag_pairs[] =
+{
+  { '*', 'L', 0, 0 },
+  { 0, 0, 0, 0 }
+};
+
+static const format_flag_spec ms_strftime_flag_specs[] =
+{
+  { '#', 0,   0, N_("'#' flag"),     N_("the '#' strftime flag"),          STD_EXT },
+  { 'w', 0,   0, N_("field width"),  N_("field width in strftime format"), STD_EXT },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_strftime_flag_pairs[] =
+{
+  { 0, 0, 0, 0 }
+};
+
+static const format_char_info ms_print_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "di",  0, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  T99_SST,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-wp0 +'",  "i",  NULL },
+  { "oxX", 0, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN, BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "-wp0#",     "i",  NULL },
+  { "u",   0, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN, BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "-wp0'",    "i",  NULL },
+  { "fgG", 0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "-wp0 +#'", "",   NULL },
+  { "eE",  0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "-wp0 +#",  "",   NULL },
+  { "c",   0, STD_C89, { T89_I,   BADLEN,  T89_S,  T94_WI,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "",   NULL },
+  { "s",   1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-wp",       "cR", NULL },
+  { "p",   1, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "c",  NULL },
+  { "n",   1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  BADLEN,  BADLEN, BADLEN,  T99_IM,  BADLEN,  BADLEN,  BADLEN }, "",          "W",  NULL },
+  /* X/Open conversion specifiers.  */
+  { "C",   0, STD_EXT, { TEX_WI,  BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "",   NULL },
+  { "S",   1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-wp",       "R",  NULL },
+  { NULL,  0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+static const format_char_info ms_scan_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "di",    1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  T99_SST,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w'", "W",   NULL },
+  { "u",     1, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN,  BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "*w'", "W",   NULL },
+  { "oxX",   1, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN,  BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "efgEG", 1, STD_C89, { T89_F,   BADLEN,  BADLEN,  T89_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "*w'",  "W",   NULL },
+  { "c",     1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "cW",  NULL },
+  { "s",     1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "cW",  NULL },
+  { "[",     1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "cW[", NULL },
+  { "p",     2, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "n",     1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  BADLEN,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "",     "W",   NULL },
+  /* X/Open conversion specifiers.  */
+  { "C",     1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "S",     1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "W",   NULL },
+  { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+static const format_char_info ms_time_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "ABZab",		0, STD_C89, NOLENGTHS, "#",     "",   NULL },
+  { "cx",		0, STD_C89, NOLENGTHS, "",      "",  NULL },
+  { "HIMSUWdmw",	0, STD_C89, NOLENGTHS, "w",  "",   NULL },
+  { "j",		0, STD_C89, NOLENGTHS, "w",  "",  NULL },
+  { "p",		0, STD_C89, NOLENGTHS, "#",      "",   NULL },
+  { "X",		0, STD_C89, NOLENGTHS, "",      "",   NULL },
+  { "y",		0, STD_C89, NOLENGTHS, "w", "",  NULL },
+  { "Y",		0, STD_C89, NOLENGTHS, "w", "",  NULL },
+  { "%",		0, STD_C89, NOLENGTHS, "",       "",   NULL },
+  /* C99 conversion specifiers.  */
+  { "z",		0, STD_C99, NOLENGTHS, "",      "",  NULL },
+  { NULL,		0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+const format_kind_info mingw_format_attributes[3] =
+{
+  { "ms_printf",   ms_printf_length_specs,  ms_print_char_table, " +#0-'", NULL,
+    ms_printf_flag_specs, ms_printf_flag_pairs,
+    FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
+    'w', 0, 'p', 0, 'L', 0,
+    &integer_type_node, &integer_type_node
+  },
+  { "ms_scanf",    ms_printf_length_specs,   ms_scan_char_table,  "*'", NULL,
+    ms_scanf_flag_specs, ms_scanf_flag_pairs,
+    FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
+    'w', 0, 0, '*', 'L', 0,
+    NULL, NULL
+  },
+  { "ms_strftime", NULL,                 ms_time_char_table,  "#", "",
+    ms_strftime_flag_specs, ms_strftime_flag_pairs,
+    FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0, 0,
+    NULL, NULL
+  }
+};
+
+/* Default overrides for printf, scanf and strftime.  */
+const target_ovr_attr mingw_format_attribute_overrides[4] =
+{
+  { "ms_printf", "printf" },
+  { "ms_scanf", "scanf" },
+  { "ms_strftime", "strftime" }
+};
Index: gcc/gcc/config/i386/t-cygming
===================================================================
--- gcc.orig/gcc/config/i386/t-cygming
+++ gcc/gcc/config/i386/t-cygming
@@ -29,4 +29,10 @@ winnt-stubs.o: $(srcdir)/config/i386/win
 	$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
 	$(srcdir)/config/i386/winnt-stubs.c
 
+msformat-c.o: $(srcdir)/config/i386/msformat-c.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
+  $(TM_H) $(RTL_H) $(REGS_H) hard-reg-set.h output.h $(TREE_H) flags.h \
+  $(TM_P_H) toplev.h $(HASHTAB_H) $(GGC_H)
+	$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
+	$(srcdir)/config/i386/msformat-c.c
+
 STMP_FIXINC=stmp-fixinc
Index: gcc/gcc/doc/extend.texi
===================================================================
--- gcc.orig/gcc/doc/extend.texi
+++ gcc/gcc/doc/extend.texi
@@ -2204,13 +2204,22 @@ for consistency with the @code{printf} s
 @code{my_format}.
 
 The parameter @var{archetype} determines how the format string is
-interpreted, and should be @code{printf}, @code{scanf}, @code{strftime}
-or @code{strfmon}.  (You can also use @code{__printf__},
-@code{__scanf__}, @code{__strftime__} or @code{__strfmon__}.)  The
-parameter @var{string-index} specifies which argument is the format
-string argument (starting from 1), while @var{first-to-check} is the
-number of the first argument to check against the format string.  For
-functions where the arguments are not available to be checked (such as
+interpreted, and should be @code{printf}, @code{scanf}, @code{strftime},
+@code{gnu_printf}, @code{gnu_scanf}, @code{gnu_strftime} or
+@code{strfmon}.  (You can also use @code{__printf__},
+@code{__scanf__}, @code{__strftime__} or @code{__strfmon__}.)  On
+MinGW targets there is also @code{ms_printf}, @code{ms_scanf}, and
+@code{ms_strftime} present.
+@var{archtype} values such as @code{printf} refer to the formats accepted
+by the system's C run-time library, while @code{gnu_} values always refer
+to the formats accepted by the GNU C Library.  On Microsoft Windows
+targets, @code{ms_} values refer to the formats accepted by the
+@file{msvcrt.dll} library.
+The parameter @var{string-index}
+specifies which argument is the format string argument (starting
+from 1), while @var{first-to-check} is the number of the first
+argument to check against the format string.  For functions
+where the arguments are not available to be checked (such as
 @code{vprintf}), specify the third parameter as zero.  In this case the
 compiler only checks the format string for consistency.  For
 @code{strftime} formats, the third parameter is required to be zero.
Index: gcc/gcc/doc/tm.texi
===================================================================
--- gcc.orig/gcc/doc/tm.texi
+++ gcc/gcc/doc/tm.texi
@@ -10319,6 +10319,18 @@ If defined, this macro is the number of 
 @code{TARGET_FORMAT_TYPES}.
 @end defmac
 
+@defmac TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+If defined, this macro is the name of a global variable containg
+target-specific format overrides for the @option{-Wformat} option. The
+default is to have no target-specific format overrides. If defined,
+@code{TARGET_FORMAT_TYPES} must be defined too.
+@end defmac
+
+@defmac TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT
+If defined, this macro specifies the number of entries in
+@code{TARGET_OVERRIDES_FORMAT_ATTRIBUTES}.
+@end defmac
+
 @deftypefn {Target Hook} bool TARGET_RELAXED_ORDERING
 If set to @code{true}, means that the target's memory model does not
 guarantee that loads which do not depend on one another will access
Index: gcc/gcc/testsuite/gcc.dg/format/format.h
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/format.h
+++ gcc/gcc/testsuite/gcc.dg/format/format.h
@@ -1,6 +1,37 @@
 /* Format checking tests: common header.  */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
 
+/* DONT_GNU_PROTOTYPE */
+#if defined (_WIN32) && !defined (__CYGWIN__)
+#if !defined (USE_SYSTEM_FORMATS)
+#define gnu_attr_printf	gnu_printf
+#define gnu_attr___printf__ __gnu_printf__
+#define gnu_attr_scanf	gnu_scanf
+#define gnu_attr___scanf__ __gnu_scanf__
+#define gnu_attr_strftime gnu_strftime
+#define gnu_attr___strftime__ __gnu_strftime__
+#endif
+#endif
+
+#ifndef gnu_attr_printf
+#define gnu_attr_printf	printf
+#define gnu_attr___printf__ __printf__
+#define gnu_attr_scanf	scanf
+#define gnu_attr___scanf__ __scanf__
+#define gnu_attr_strftime strftime
+#define gnu_attr___strftime__ __strftime__
+#endif
+
+#if !defined (USE_SYSTEM_FORMATS)
+#define USE_PRINTF(FMTPOS, WILDARG) __attribute__((format(gnu_printf, FMTPOS, WILDARG))) __attribute__((nonnull (FMTPOS)))
+#define USE_SCANF(FMTPOS, WILDARG) __attribute__((format(gnu_scanf, FMTPOS, WILDARG))) __attribute__((nonnull (FMTPOS)))
+#define USE_STRFTIME(FMTPOS) __attribute__((__format__(gnu_strftime, FMTPOS, 0))) __attribute__((nonnull (FMTPOS)))
+#else
+#define USE_PRINTF(FMTPOS, WILDARG)
+#define USE_SCANF(FMTPOS, WILDARG)
+#define USE_STRFTIME(FMTPOS)
+#endif
+
 #include <stdarg.h>
 #include <stddef.h>
 
@@ -11,6 +42,20 @@
 typedef __WINT_TYPE__ wint_t;
 #endif
 
+#ifdef _WIN64
+/* Kludges to get types corresponding to size_t and ptrdiff_t.  */
+#define unsigned signed
+typedef signed int signed_size_t __attribute__ ((mode (DI)));
+/* We also use this type to approximate ssize_t.  */
+typedef signed int ssize_t __attribute__ ((mode (DI)));
+#undef unsigned
+#define signed /* Type might or might not have explicit 'signed'.  */
+typedef unsigned int unsigned_ptrdiff_t __attribute__ ((mode (DI)));
+#undef signed
+
+__extension__ typedef int llong  __attribute__ ((mode (DI)));
+__extension__ typedef unsigned int ullong  __attribute__ ((mode (DI)));
+#else
 /* Kludges to get types corresponding to size_t and ptrdiff_t.  */
 #define unsigned signed
 typedef __SIZE_TYPE__ signed_size_t;
@@ -23,6 +68,7 @@ typedef unsigned __PTRDIFF_TYPE__ unsign
 
 __extension__ typedef long long int llong;
 __extension__ typedef unsigned long long int ullong;
+#endif
 
 /* %q formats want a "quad"; GCC considers this to be a long long.  */
 typedef llong quad_t;
@@ -70,3 +116,77 @@ extern size_t strftime (char *restrict, 
 			const struct tm *restrict);
 
 extern ssize_t strfmon (char *restrict, size_t, const char *restrict, ...);
+
+/* Mingw specific part.  */
+#if !defined (USE_SYSTEM_FORMATS) && defined(_WIN32) && !defined(DONT_GNU_PROTOTYPE)
+
+extern USE_PRINTF(2,3) int fprintf_gnu (FILE *restrict, const char *restrict, ...);
+#undef fprintf
+#define fprintf fprintf_gnu
+
+extern USE_PRINTF(1,2) int printf_gnu (const char *restrict, ...);
+#undef printf
+#define printf printf_gnu
+
+extern USE_PRINTF(2,3) int fprintf_unlocked_gnu (FILE *restrict, const char *restrict, ...);
+#undef fprintf_unlocked
+#define fprintf_unlocked fprintf_unlocked_gnu
+
+extern USE_PRINTF(1,2)int printf_unlocked_gnu (const char *restrict, ...);
+#undef printf_unlocked
+#define printf_unlocked printf_unlocked_gnu
+
+extern USE_PRINTF(2,3) int sprintf_gnu (char *restrict, const char *restrict, ...);
+#undef sprintf
+#define sprintf sprintf_gnu
+
+extern USE_PRINTF(2,0) int vfprintf_gnu (FILE *restrict, const char *restrict, va_list);
+#undef vsprintf
+#define vsprintf vsprintf_gnu
+
+extern USE_PRINTF(1,0) int vprintf_gnu (const char *restrict, va_list);
+#undef vprintf
+#define vprintf vprintf_gnu
+
+extern USE_PRINTF(2,0) int vsprintf_gnu (char *restrict, const char *restrict, va_list);
+#undef vsprintf
+#define vsprintf vsprintf_gnu
+
+extern USE_PRINTF(3,4) int snprintf_gnu (char *restrict, size_t, const char *restrict, ...);
+#undef snprintf
+#define snprintf snprintf_gnu
+
+extern USE_PRINTF(3,0) int vsnprintf_gnu (char *restrict, size_t, const char *restrict, va_list);
+#undef vsnprintf
+#define vsnprintf vsnprintf_gnu
+
+extern USE_SCANF(2,3) int fscanf_gnu (FILE *restrict, const char *restrict, ...);
+#undef fscanf
+#define fscanf fscanf_gnu
+
+extern USE_SCANF(1,2) int scanf_gnu (const char *restrict, ...);
+#undef scanf
+#define scanf scanf_gnu
+
+extern USE_SCANF(2,3) int sscanf_gnu (const char *restrict, const char *restrict, ...);
+#undef sscanf
+#define sscanf sscanf_gnu
+
+extern USE_SCANF(2,0) int vfscanf_gnu (FILE *restrict, const char *restrict, va_list);
+#undef vfscanf
+#define vfscanf vfscanf_gnu
+
+extern USE_SCANF(1,0) int vscanf_gnu (const char *restrict, va_list);
+#undef vscanf
+#define vscanf vscanf_gnu
+
+extern USE_SCANF(2,0) int vsscanf_gnu (const char *restrict, const char *restrict, va_list);
+#undef vsscanf
+#define vsscanf vsscanf_gnu
+
+extern USE_STRFTIME(3) size_t strftime_gnu (char *restrict, size_t, const char *restrict,
+			const struct tm *restrict);
+#undef strftime
+#define strftime strftime_gnu
+
+#endif
Index: gcc/gcc/testsuite/gcc.dg/format/attr-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-1.c
@@ -3,7 +3,8 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern void foo0 (const char *) __attribute__((__format__(__strftime__, 1, 0)));
-extern void foo1 (const char *, ...) __attribute__((__format__(__strftime__, 1, 2))); /* { dg-error "cannot format" "strftime first_arg_num != 0" } */
+extern void foo0 (const char *) __attribute__((__format__(gnu_attr___strftime__, 1, 0)));
+extern void foo1 (const char *, ...) __attribute__((__format__(gnu_attr___strftime__, 1, 2))); /* { dg-error "cannot format" "strftime first_arg_num != 0" } */
Index: gcc/gcc/testsuite/gcc.dg/format/attr-2.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-2.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-2.c
@@ -3,22 +3,23 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern void tformatprintf (const char *, ...) __attribute__((format(printf, 1, 2)));
-extern void tformat__printf__ (const char *, ...) __attribute__((format(__printf__, 1, 2)));
-extern void tformatscanf (const char *, ...) __attribute__((format(scanf, 1, 2)));
-extern void tformat__scanf__ (const char *, ...) __attribute__((format(__scanf__, 1, 2)));
-extern void tformatstrftime (const char *) __attribute__((format(strftime, 1, 0)));
-extern void tformat__strftime__ (const char *) __attribute__((format(__strftime__, 1, 0)));
+extern void tformatprintf (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
+extern void tformat__printf__ (const char *, ...) __attribute__((format(gnu_attr___printf__, 1, 2)));
+extern void tformatscanf (const char *, ...) __attribute__((format(gnu_attr_scanf, 1, 2)));
+extern void tformat__scanf__ (const char *, ...) __attribute__((format(gnu_attr___scanf__, 1, 2)));
+extern void tformatstrftime (const char *) __attribute__((format(gnu_attr_strftime, 1, 0)));
+extern void tformat__strftime__ (const char *) __attribute__((format(gnu_attr___strftime__, 1, 0)));
 extern void tformatstrfmon (const char *, ...) __attribute__((format(strfmon, 1, 2)));
 extern void tformat__strfmon__ (const char *, ...) __attribute__((format(__strfmon__, 1, 2)));
-extern void t__format__printf (const char *, ...) __attribute__((__format__(printf, 1, 2)));
-extern void t__format____printf__ (const char *, ...) __attribute__((__format__(__printf__, 1, 2)));
-extern void t__format__scanf (const char *, ...) __attribute__((__format__(scanf, 1, 2)));
-extern void t__format____scanf__ (const char *, ...) __attribute__((__format__(__scanf__, 1, 2)));
-extern void t__format__strftime (const char *) __attribute__((__format__(strftime, 1, 0)));
-extern void t__format____strftime__ (const char *) __attribute__((__format__(__strftime__, 1, 0)));
+extern void t__format__printf (const char *, ...) __attribute__((__format__(gnu_attr_printf, 1, 2)));
+extern void t__format____printf__ (const char *, ...) __attribute__((__format__(gnu_attr___printf__, 1, 2)));
+extern void t__format__scanf (const char *, ...) __attribute__((__format__(gnu_attr_scanf, 1, 2)));
+extern void t__format____scanf__ (const char *, ...) __attribute__((__format__(gnu_attr___scanf__, 1, 2)));
+extern void t__format__strftime (const char *) __attribute__((__format__(gnu_attr_strftime, 1, 0)));
+extern void t__format____strftime__ (const char *) __attribute__((__format__(gnu_attr___strftime__, 1, 0)));
 extern void t__format__strfmon (const char *, ...) __attribute__((__format__(strfmon, 1, 2)));
 extern void t__format____strfmon__ (const char *, ...) __attribute__((__format__(__strfmon__, 1, 2)));
 
Index: gcc/gcc/testsuite/gcc.dg/format/attr-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-3.c
@@ -3,20 +3,21 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 /* Proper uses of the attributes.  */
-extern void fa0 (const char *, ...) __attribute__((format(printf, 1, 2)));
-extern void fa1 (char *, ...) __attribute__((format(printf, 1, 2)));
+extern void fa0 (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
+extern void fa1 (char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
 extern char *fa2 (const char *) __attribute__((format_arg(1)));
 extern char *fa3 (char *) __attribute__((format_arg(1)));
 
 /* Uses with too few or too many arguments.  */
 extern void fb0 (const char *, ...) __attribute__((format)); /* { dg-error "wrong number of arguments" "bad format" } */
 extern void fb1 (const char *, ...) __attribute__((format())); /* { dg-error "wrong number of arguments" "bad format" } */
-extern void fb2 (const char *, ...) __attribute__((format(printf))); /* { dg-error "wrong number of arguments" "bad format" } */
-extern void fb3 (const char *, ...) __attribute__((format(printf, 1))); /* { dg-error "wrong number of arguments" "bad format" } */
-extern void fb4 (const char *, ...) __attribute__((format(printf, 1, 2, 3))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb2 (const char *, ...) __attribute__((format(gnu_attr_printf))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb3 (const char *, ...) __attribute__((format(gnu_attr_printf, 1))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb4 (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2, 3))); /* { dg-error "wrong number of arguments" "bad format" } */
 
 extern void fc1 (const char *) __attribute__((format_arg)); /* { dg-error "wrong number of arguments" "bad format_arg" } */
 extern void fc2 (const char *) __attribute__((format_arg())); /* { dg-error "wrong number of arguments" "bad format_arg" } */
@@ -25,9 +26,9 @@ extern void fc3 (const char *) __attribu
 /* These attributes presently only apply to declarations, not to types.
    Eventually, they should be usable with declarators for function types
    anywhere, but still not with structure/union/enum types.  */
-struct s0 { int i; } __attribute__((format(printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on struct" } */
-union u0 { int i; } __attribute__((format(printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on union" } */
-enum e0 { E0V0 } __attribute__((format(printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on enum" } */
+struct s0 { int i; } __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on struct" } */
+union u0 { int i; } __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on union" } */
+enum e0 { E0V0 } __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on enum" } */
 
 struct s1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on struct" } */
 union u1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on union" } */
@@ -38,28 +39,28 @@ extern void fe0 (const char *, ...) __at
 extern void fe1 (const char *, ...) __attribute__((format(nosuch, 1, 2))); /* { dg-warning "format function type" "unknown format" } */
 
 /* Both the numbers must be integer constant expressions.  */
-extern void ff0 (const char *, ...) __attribute__((format(printf, 3-2, (long long)(10/5))));
+extern void ff0 (const char *, ...) __attribute__((format(gnu_attr_printf, 3-2, (long long)(10/5))));
 int foo;
-extern void ff1 (const char *, ...) __attribute__((format(printf, foo, 10/5))); /* { dg-error "invalid operand" "bad number" } */
-extern void ff2 (const char *, ...) __attribute__((format(printf, 3-2, foo))); /* { dg-error "invalid operand" "bad number" } */
+extern void ff1 (const char *, ...) __attribute__((format(gnu_attr_printf, foo, 10/5))); /* { dg-error "invalid operand" "bad number" } */
+extern void ff2 (const char *, ...) __attribute__((format(gnu_attr_printf, 3-2, foo))); /* { dg-error "invalid operand" "bad number" } */
 extern char *ff3 (const char *) __attribute__((format_arg(3-2)));
 extern char *ff4 (const char *) __attribute__((format_arg(foo))); /* { dg-error "invalid operand" "bad format_arg number" } */
 
 /* The format string argument must precede the arguments to be formatted.
    This includes if no parameter types are specified (which is not valid ISO
    C for variadic functions).  */
-extern void fg0 () __attribute__((format(printf, 1, 2)));
-extern void fg1 () __attribute__((format(printf, 1, 0)));
-extern void fg2 () __attribute__((format(printf, 1, 1))); /* { dg-error "follows" "bad number order" } */
-extern void fg3 () __attribute__((format(printf, 2, 1))); /* { dg-error "follows" "bad number order" } */
+extern void fg0 () __attribute__((format(gnu_attr_printf, 1, 2)));
+extern void fg1 () __attribute__((format(gnu_attr_printf, 1, 0)));
+extern void fg2 () __attribute__((format(gnu_attr_printf, 1, 1))); /* { dg-error "follows" "bad number order" } */
+extern void fg3 () __attribute__((format(gnu_attr_printf, 2, 1))); /* { dg-error "follows" "bad number order" } */
 
 /* The format string argument must be a string type, and the arguments to
    be formatted must be the "...".  */
-extern void fh0 (int, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "not a string" "format int string" } */
-extern void fh1 (signed char *, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "not a string" "signed char string" } */
-extern void fh2 (unsigned char *, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "not a string" "unsigned char string" } */
-extern void fh3 (const char *, ...) __attribute__((format(printf, 1, 3))); /* { dg-error "is not" "not ..." } */
-extern void fh4 (const char *, int, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "is not" "not ..." } */
+extern void fh0 (int, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "format int string" } */
+extern void fh1 (signed char *, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "signed char string" } */
+extern void fh2 (unsigned char *, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "unsigned char string" } */
+extern void fh3 (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 3))); /* { dg-error "is not" "not ..." } */
+extern void fh4 (const char *, int, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "is not" "not ..." } */
 
 /* format_arg formats must take and return a string.  */
 extern char *fi0 (int) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg int string" } */
Index: gcc/gcc/testsuite/gcc.dg/format/attr-4.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-4.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-4.c
@@ -4,12 +4,13 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern __attribute__((format(printf, 1, 2))) void tformatprintf0 (const char *, ...);
-extern void __attribute__((format(printf, 1, 2))) tformatprintf1 (const char *, ...);
-extern void foo (void), __attribute__((format(printf, 1, 2))) tformatprintf2 (const char *, ...);
-extern __attribute__((noreturn)) void bar (void), __attribute__((format(printf, 1, 2))) tformatprintf3 (const char *, ...);
+extern __attribute__((format(gnu_attr_printf, 1, 2))) void tformatprintf0 (const char *, ...);
+extern void __attribute__((format(gnu_attr_printf, 1, 2))) tformatprintf1 (const char *, ...);
+extern void foo (void), __attribute__((format(gnu_attr_printf, 1, 2))) tformatprintf2 (const char *, ...);
+extern __attribute__((noreturn)) void bar (void), __attribute__((format(gnu_attr_printf, 1, 2))) tformatprintf3 (const char *, ...);
 
 void
 baz (int i, int *ip, double d)
Index: gcc/gcc/testsuite/gcc.dg/format/attr-7.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-7.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-7.c
@@ -3,12 +3,13 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-__attribute__((format(printf, 1, 2))) void (*tformatprintf0) (const char *, ...);
-void (*tformatprintf1) (const char *, ...) __attribute__((format(printf, 1, 2)));
-void (__attribute__((format(printf, 1, 2))) *tformatprintf2) (const char *, ...);
-void (__attribute__((format(printf, 1, 2))) ****tformatprintf3) (const char *, ...);
+__attribute__((format(gnu_attr_printf, 1, 2))) void (*tformatprintf0) (const char *, ...);
+void (*tformatprintf1) (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
+void (__attribute__((format(gnu_attr_printf, 1, 2))) *tformatprintf2) (const char *, ...);
+void (__attribute__((format(gnu_attr_printf, 1, 2))) ****tformatprintf3) (const char *, ...);
 
 char * (__attribute__((format_arg(1))) *tformat_arg) (const char *);
 
Index: gcc/gcc/testsuite/gcc.dg/format/c90-printf-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/c90-printf-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/c90-printf-3.c
@@ -3,7 +3,7 @@
    do not.
 */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
-/* { dg-do compile } */
+/* { dg-do compile { target { ! *-*-mingw* } } } */
 /* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
 
 #include "format.h"
Index: gcc/gcc/testsuite/gcc.dg/format/c90-scanf-4.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/c90-scanf-4.c
+++ gcc/gcc/testsuite/gcc.dg/format/c90-scanf-4.c
@@ -3,7 +3,7 @@
    do not.
 */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
-/* { dg-do compile } */
+/* { dg-do compile { target { ! *-*-mingw* } } } */
 /* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
 
 #include "format.h"
Index: gcc/gcc/testsuite/gcc.dg/format/c99-printf-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/c99-printf-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/c99-printf-3.c
@@ -2,7 +2,7 @@
    attributes in strict C99 mode, but the gettext functions do not.
 */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
-/* { dg-do compile } */
+/* { dg-do compile { target { ! *-*-mingw* } } } */
 /* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
 
 #include "format.h"
Index: gcc/gcc/testsuite/gcc.dg/format/miss-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-1.c
@@ -23,7 +23,7 @@ bar (const char *fmt, ...)
   va_end (ap);
 }
 
-__attribute__((__format__(__printf__, 1, 2))) void
+__attribute__((__format__(gnu_attr___printf__, 1, 2))) void
 foo2 (const char *fmt, ...)
 {
   va_list ap;
Index: gcc/gcc/testsuite/gcc.dg/format/miss-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-3.c
@@ -3,13 +3,14 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 void
 foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
@@ -18,7 +19,7 @@ foo1 (noattr_t na, attr_t a, vnoattr_t v
   noattr_t na2 = a; /* { dg-warning "candidate" "initialization warning" } */
   attr_t a1 = na;
   attr_t a2 = a;
-  
+
   vnoattr_t vna1 = vna;
   vnoattr_t vna2 = va; /* { dg-warning "candidate" "initialization warning" } */
   vattr_t va1 = vna;
Index: gcc/gcc/testsuite/gcc.dg/format/miss-4.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-4.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-4.c
@@ -3,20 +3,21 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 void
 foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
 {
   noattr_t na1, na2;
   attr_t a1, a2;
-  
+
   vnoattr_t vna1, vna2;
   vattr_t va1, va2;
 
@@ -24,7 +25,7 @@ foo1 (noattr_t na, attr_t a, vnoattr_t v
   na2 = a; /* { dg-warning "candidate" "assignment warning" } */
   a1 = na;
   a2 = a;
-  
+
   vna1 = vna;
   vna2 = va; /* { dg-warning "candidate" "assignment warning" } */
   va1 = vna;
Index: gcc/gcc/testsuite/gcc.dg/format/miss-5.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-5.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-5.c
@@ -3,13 +3,14 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 noattr_t
 foo1 (noattr_t na, attr_t a, int i)
Index: gcc/gcc/testsuite/gcc.dg/format/miss-6.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-6.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-6.c
@@ -3,13 +3,14 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 extern void foo1 (noattr_t);
 extern void foo2 (attr_t);
@@ -23,7 +24,7 @@ foo (noattr_t na, attr_t a, vnoattr_t vn
   foo1 (a); /* { dg-warning "candidate" "parameter passing warning" } */
   foo2 (na);
   foo2 (a);
-  
+
   foo3 (vna);
   foo3 (va); /* { dg-warning "candidate" "parameter passing warning" } */
   foo4 (vna);
Index: gcc/gcc/testsuite/gcc.dg/format/ms_array-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_array-1.c
@@ -0,0 +1,42 @@
+/* Test for format checking of constant arrays.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat=2" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+const char a1[] = "foo";
+const char a2[] = "foo%d";
+const char b1[3] = "foo";
+const char b2[1] = "1";
+static const char c1[] = "foo";
+static const char c2[] = "foo%d";
+char d[] = "foo";
+volatile const char e[] = "foo";
+
+void
+foo (int i, long l)
+{
+  const char p1[] = "bar";
+  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 (c1);
+  printf (c2, i);
+  printf (c2, l); /* { dg-warning "format" "wrong type with array" } */
+  printf (p1);
+  printf (p2, i);
+  printf (p2, l); /* { dg-warning "format" "wrong type with array" } */
+  printf (q1);
+  printf (q2, i);
+  printf (q2, l); /* { dg-warning "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" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-1.c
@@ -0,0 +1,10 @@
+/* Test for strftime format attributes: can't have first_arg_num != 0.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define DONT_GNU_PROTOTYPE
+#include "format.h"
+
+extern void foo0 (const char *) __attribute__((__format__(__ms_strftime__, 1, 0)));
+extern void foo1 (const char *, ...) __attribute__((__format__(__ms_strftime__, 1, 2))); /* { dg-error "cannot format" "strftime first_arg_num != 0" } */
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-2.c
@@ -0,0 +1,68 @@
+/* Test for format attributes: test use of __attribute__.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define DONT_GNU_PROTOTYPE
+#include "format.h"
+
+extern void tformatprintf (const char *, ...) __attribute__((format(ms_printf, 1, 2)));
+extern void tformat__printf__ (const char *, ...) __attribute__((format(__ms_printf__, 1, 2)));
+extern void tformatscanf (const char *, ...) __attribute__((format(ms_scanf, 1, 2)));
+extern void tformat__scanf__ (const char *, ...) __attribute__((format(__ms_scanf__, 1, 2)));
+extern void tformatstrftime (const char *) __attribute__((format(ms_strftime, 1, 0)));
+extern void tformat__strftime__ (const char *) __attribute__((format(__ms_strftime__, 1, 0)));
+extern void tformatstrfmon (const char *, ...) __attribute__((format(strfmon, 1, 2)));
+extern void tformat__strfmon__ (const char *, ...) __attribute__((format(__strfmon__, 1, 2)));
+extern void t__format__printf (const char *, ...) __attribute__((__format__(ms_printf, 1, 2)));
+extern void t__format____printf__ (const char *, ...) __attribute__((__format__(__ms_printf__, 1, 2)));
+extern void t__format__scanf (const char *, ...) __attribute__((__format__(ms_scanf, 1, 2)));
+extern void t__format____scanf__ (const char *, ...) __attribute__((__format__(__ms_scanf__, 1, 2)));
+extern void t__format__strftime (const char *) __attribute__((__format__(ms_strftime, 1, 0)));
+extern void t__format____strftime__ (const char *) __attribute__((__format__(__ms_strftime__, 1, 0)));
+extern void t__format__strfmon (const char *, ...) __attribute__((__format__(strfmon, 1, 2)));
+extern void t__format____strfmon__ (const char *, ...) __attribute__((__format__(__strfmon__, 1, 2)));
+
+extern char *tformat_arg (const char *) __attribute__((format_arg(1)));
+extern char *t__format_arg__ (const char *) __attribute__((__format_arg__(1)));
+
+void
+foo (int i, int *ip, double d)
+{
+  tformatprintf ("%d", i);
+  tformatprintf ("%"); /* { dg-warning "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);
+  tformat__scanf__ ("%"); /* { dg-warning "format" "attribute format __scanf__" } */
+  tformatstrftime ("%a");
+  tformatstrftime ("%"); /* { dg-warning "format" "attribute format strftime" } */
+  tformat__strftime__ ("%a");
+  tformat__strftime__ ("%"); /* { dg-warning "format" "attribute format __strftime__" } */
+  tformatstrfmon ("%n", d);
+  tformatstrfmon ("%"); /* { dg-warning "format" "attribute format strfmon" } */
+  tformat__strfmon__ ("%n", d);
+  tformat__strfmon__ ("%"); /* { dg-warning "format" "attribute format __strfmon__" } */
+  t__format__printf ("%d", i);
+  t__format__printf ("%"); /* { dg-warning "format" "attribute __format__ printf" } */
+  t__format____printf__ ("%d", i);
+  t__format____printf__ ("%"); /* { dg-warning "format" "attribute __format__ __printf__" } */
+  t__format__scanf ("%d", ip);
+  t__format__scanf ("%"); /* { dg-warning "format" "attribute __format__ scanf" } */
+  t__format____scanf__ ("%d", ip);
+  t__format____scanf__ ("%"); /* { dg-warning "format" "attribute __format__ __scanf__" } */
+  t__format__strftime ("%a");
+  t__format__strftime ("%"); /* { dg-warning "format" "attribute __format__ strftime" } */
+  t__format____strftime__ ("%a");
+  t__format____strftime__ ("%"); /* { dg-warning "format" "attribute __format__ __strftime__" } */
+  t__format__strfmon ("%n", d);
+  t__format__strfmon ("%"); /* { dg-warning "format" "attribute __format__ strfmon" } */
+  t__format____strfmon__ ("%n", d);
+  t__format____strfmon__ ("%"); /* { dg-warning "format" "attribute __format__ __strfmon__" } */
+  tformatprintf (tformat_arg ("%d"), i);
+  tformatprintf (tformat_arg ("%")); /* { dg-warning "format" "attribute format_arg" } */
+  tformatprintf (t__format_arg__ ("%d"), i);
+  tformatprintf (t__format_arg__ ("%")); /* { dg-warning "format" "attribute __format_arg__" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-3.c
@@ -0,0 +1,71 @@
+/* Test for format attributes: test bad uses of __attribute__.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* Proper uses of the attributes.  */
+extern void fa0 (const char *, ...) __attribute__((format(ms_printf, 1, 2)));
+extern void fa1 (char *, ...) __attribute__((format(ms_printf, 1, 2)));
+extern char *fa2 (const char *) __attribute__((format_arg(1)));
+extern char *fa3 (char *) __attribute__((format_arg(1)));
+
+/* Uses with too few or too many arguments.  */
+extern void fb0 (const char *, ...) __attribute__((format)); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb1 (const char *, ...) __attribute__((format())); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb2 (const char *, ...) __attribute__((format(ms_printf))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb3 (const char *, ...) __attribute__((format(ms_printf, 1))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb4 (const char *, ...) __attribute__((format(ms_printf, 1, 2, 3))); /* { dg-error "wrong number of arguments" "bad format" } */
+
+extern void fc1 (const char *) __attribute__((format_arg)); /* { dg-error "wrong number of arguments" "bad format_arg" } */
+extern void fc2 (const char *) __attribute__((format_arg())); /* { dg-error "wrong number of arguments" "bad format_arg" } */
+extern void fc3 (const char *) __attribute__((format_arg(1, 2))); /* { dg-error "wrong number of arguments" "bad format_arg" } */
+
+/* These attributes presently only apply to declarations, not to types.
+   Eventually, they should be usable with declarators for function types
+   anywhere, but still not with structure/union/enum types.  */
+struct s0 { int i; } __attribute__((format(ms_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on struct" } */
+union u0 { int i; } __attribute__((format(ms_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on union" } */
+enum e0 { E0V0 } __attribute__((format(ms_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on enum" } */
+
+struct s1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on struct" } */
+union u1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on union" } */
+enum e1 { E1V0 } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on enum" } */
+
+/* The format type must be an identifier, one of those recognized.  */
+extern void fe0 (const char *, ...) __attribute__((format(12345, 1, 2))); /* { dg-error "format specifier" "non-id format" } */
+extern void fe1 (const char *, ...) __attribute__((format(nosuch, 1, 2))); /* { dg-warning "format function type" "unknown format" } */
+
+/* Both the numbers must be integer constant expressions.  */
+extern void ff0 (const char *, ...) __attribute__((format(ms_printf, 3-2, (long long)(10/5))));
+int foo;
+extern void ff1 (const char *, ...) __attribute__((format(ms_printf, foo, 10/5))); /* { dg-error "invalid operand" "bad number" } */
+extern void ff2 (const char *, ...) __attribute__((format(ms_printf, 3-2, foo))); /* { dg-error "invalid operand" "bad number" } */
+extern char *ff3 (const char *) __attribute__((format_arg(3-2)));
+extern char *ff4 (const char *) __attribute__((format_arg(foo))); /* { dg-error "invalid operand" "bad format_arg number" } */
+
+/* The format string argument must precede the arguments to be formatted.
+   This includes if no parameter types are specified (which is not valid ISO
+   C for variadic functions).  */
+extern void fg0 () __attribute__((format(ms_printf, 1, 2)));
+extern void fg1 () __attribute__((format(ms_printf, 1, 0)));
+extern void fg2 () __attribute__((format(ms_printf, 1, 1))); /* { dg-error "follows" "bad number order" } */
+extern void fg3 () __attribute__((format(ms_printf, 2, 1))); /* { dg-error "follows" "bad number order" } */
+
+/* The format string argument must be a string type, and the arguments to
+   be formatted must be the "...".  */
+extern void fh0 (int, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "not a string" "format int string" } */
+extern void fh1 (signed char *, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "not a string" "signed char string" } */
+extern void fh2 (unsigned char *, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "not a string" "unsigned char string" } */
+extern void fh3 (const char *, ...) __attribute__((format(ms_printf, 1, 3))); /* { dg-error "is not" "not ..." } */
+extern void fh4 (const char *, int, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "is not" "not ..." } */
+
+/* format_arg formats must take and return a string.  */
+extern char *fi0 (int) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg int string" } */
+extern char *fi1 (signed char *) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg signed char string" } */
+extern char *fi2 (unsigned char *) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg unsigned char string" } */
+extern int fi3 (const char *) __attribute__((format_arg(1))); /* { dg-error "not return string" "format_arg ret int string" } */
+extern signed char *fi4 (const char *) __attribute__((format_arg(1))); /* { dg-error "not return string" "format_arg ret signed char string" } */
+extern unsigned char *fi5 (const char *) __attribute__((format_arg(1))); /* { dg-error "not return string" "format_arg ret unsigned char string" } */
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-4.c
@@ -0,0 +1,26 @@
+/* Test for format attributes: test use of __attribute__
+   in prefix attributes.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+extern __attribute__((format(ms_printf, 1, 2))) void tformatprintf0 (const char *, ...);
+extern void __attribute__((format(ms_printf, 1, 2))) tformatprintf1 (const char *, ...);
+extern void foo (void), __attribute__((format(ms_printf, 1, 2))) tformatprintf2 (const char *, ...);
+extern __attribute__((noreturn)) void bar (void), __attribute__((format(ms_printf, 1, 2))) tformatprintf3 (const char *, ...);
+
+void
+baz (int i, int *ip, double d)
+{
+  tformatprintf0 ("%d", i);
+  tformatprintf0 ("%"); /* { dg-warning "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);
+  tformatprintf3 ("%"); /* { dg-warning "format" "attribute format printf case 3" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-7.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-7.c
@@ -0,0 +1,35 @@
+/* Test for format attributes: test applying them to types.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define DONT_GNU_PROTOTYPE
+#include "format.h"
+
+__attribute__((format(ms_printf, 1, 2))) void (*tformatprintf0) (const char *, ...);
+void (*tformatprintf1) (const char *, ...) __attribute__((format(ms_printf, 1, 2)));
+void (__attribute__((format(ms_printf, 1, 2))) *tformatprintf2) (const char *, ...);
+void (__attribute__((format(ms_printf, 1, 2))) ****tformatprintf3) (const char *, ...);
+
+char * (__attribute__((format_arg(1))) *tformat_arg) (const char *);
+
+void
+baz (int i)
+{
+  (*tformatprintf0) ("%d", i);
+  (*tformatprintf0) ((*tformat_arg) ("%d"), i);
+  (*tformatprintf0) ("%"); /* { dg-warning "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" } */
+  (*tformatprintf2) ("%d", i);
+  (*tformatprintf2) ((*tformat_arg) ("%d"), i);
+  (*tformatprintf2) ("%"); /* { dg-warning "format" "nested" } */
+  (*tformatprintf2) ((*tformat_arg) ("%")); /* { dg-warning "format" "nested" } */
+  (****tformatprintf3) ("%d", i);
+  (****tformatprintf3) ((*tformat_arg) ("%d"), i);
+  (****tformatprintf3) ("%"); /* { dg-warning "format" "nested 2" } */
+  (****tformatprintf3) ((*tformat_arg) ("%")); /* { dg-warning "format" "nested 2" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_bitfld-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_bitfld-1.c
@@ -0,0 +1,52 @@
+/* Test for printf formats and bit-fields: bug 22421.  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+/* { dg-require-effective-target int32plus } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+struct s {
+  unsigned int u1 : 1;
+  signed int s1 : 1;
+  unsigned int u15 : 15;
+  signed int s15 : 15;
+  unsigned int u16 : 16;
+  signed int s16 : 16;
+  unsigned long u31 : 31;
+  signed long s31 : 31;
+  unsigned long u32 : 32;
+  signed long s32 : 32;
+  unsigned long long u48 : 48;
+} x;
+
+void
+foo (void)
+{
+  printf ("%d%u", x.u1, x.u1);
+  printf ("%d%u", x.s1, x.s1);
+  printf ("%d%u", x.u15, x.u15);
+  printf ("%d%u", x.s15, x.s15);
+  printf ("%d%u", x.u16, x.u16);
+  printf ("%d%u", x.s16, x.s16);
+#if __INT_MAX__ > 32767
+  /* If integers are 16 bits, there doesn't seem to be a way of
+     printing these without getting an error.  */
+  printf ("%d%u", x.u31, x.u31);
+  printf ("%d%u", x.s31, x.s31);
+#endif
+#if __LONG_MAX__ > 2147483647 && __INT_MAX__ >= 2147483647
+  /* If long is wider than 32 bits, the 32-bit bit-fields are int or
+     unsigned int or promote to those types.  Otherwise, long is 32
+     bits and the bit-fields are of type plain long or unsigned
+     long.  */
+  printf ("%d%u", x.u32, x.u32);
+  printf ("%d%u", x.s32, x.s32);
+#else
+  printf ("%ld%lu", x.u32, x.u32);
+  printf ("%ld%lu", x.s32, x.s32);
+#endif
+  printf ("%I64u", x.u48); /* { dg-warning "has type '.*unsigned int:48'" } */
+  printf ("%I64u", (unsigned long long)x.u48);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_branch-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_branch-1.c
@@ -0,0 +1,28 @@
+/* Test for format checking of conditional expressions.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+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" } */
+  /* 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) ? "%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" } */
+  /* 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 *-*-* } 26 } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-1.c
@@ -0,0 +1,184 @@
+/* Test for printf formats.  Formats using C90 features, including cases
+   where C90 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, int i1, int i2, unsigned int u, double d, char *s, void *p,
+     int *n, short int *hn, long int l, unsigned long int ul,
+     long int *ln, long double ld, wint_t lc, wchar_t *ls, llong ll,
+     ullong ull, unsigned int *un, const int *cn, signed char *ss,
+     unsigned char *us, const signed char *css, unsigned int u1,
+     unsigned int u2)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.1 (pages 131-134).  */
+  /* Basic sanity checks for the different components of a format.  */
+  printf ("%d\n", i);
+  printf ("%+d\n", i);
+  printf ("%3d\n", i);
+  printf ("%-3d\n", i);
+  printf ("%*d\n", i1, i);
+  printf ("%d %lu\n", i, ul);
+  /* Bogus use of width.  */
+  printf ("%5n\n", n); /* { dg-warning "width" "width 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 ("%-%"); /* { dg-warning "format" "bogus %%" } */
+  printf ("%-%\n"); /* { dg-warning "format" "bogus %%" } */
+  printf ("%5%\n"); /* { dg-warning "format" "bogus %%" } */
+  printf ("%h%\n"); /* { dg-warning "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
+     differences in format checking here, and this is relied on to get the
+     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);
+  printf ("%hs", hn);
+  printf ("%hp", p); /* { dg-warning "length" "bad use of %h" } */
+  printf ("%h"); /* { dg-warning "conversion lacks type" "bare %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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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% 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* Various tests of bad argument types.  */
+  printf ("%d", l); /* { dg-warning "format" "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" } */
+  /* 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
+     discussion of the requirements of rules on identical representation,
+     and of the application of the as if rule with the new va_arg
+     allowances in C99 to printf.)  Likewise, we should warn if
+     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" } */
+  /* 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" } */
+  /* The historical behavior is to allow signed / unsigned types
+     interchangably as arguments.  For values representable in both types,
+     such usage may be correct.  For now preserve the behavior of GCC
+     in such cases.
+  */
+  printf ("%d", u);
+  /* Wrong number of arguments.  */
+  printf ("%d%d", i); /* { dg-warning "arguments" "wrong number of args" } */
+  printf ("%d", i, i); /* { dg-warning "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" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-2.c
@@ -0,0 +1,25 @@
+/* Test for printf formats.  Formats using C99 features should be rejected
+   outside of C99 mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, double d, llong ll, intmax_t j, size_t z, ptrdiff_t t)
+{
+  /* Some tests already in c90-printf-1.c, e.g. %lf.  */
+  /* The widths hh, ll, j, z, t are new.  */
+  printf ("%hhd", i); /* { dg-warning "unknown|format" "%hh is unsupported" } */
+  printf ("%I64d", ll); /* { dg-warning "length|C" "%I64 in C90" } */
+  printf ("%jd", j); /* { dg-warning "unknown|format" "%j is unsupported" } */
+  printf ("%zu", z); /* { dg-warning "unknown|format" "%z is unsupported" } */
+  printf ("%td", t); /* { dg-warning "unknown|format" "%t is unsupported" } */
+  /* The formats F, a, A are new.  */
+  printf ("%F", d); /* { dg-warning "unknown|format" "%F is unsupported" } */
+  printf ("%a", d); /* { dg-warning "unknown|format" "%a is unsupported" } */
+  printf ("%A", d); /* { dg-warning "unknown|format" "%A is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-3.c
@@ -0,0 +1,43 @@
+/* Test for printf formats.  Test that the C90 functions get their default
+   attributes in strict C90 mode, but the C99 and gettext functions
+   do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, char *s, size_t n, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5, va_list v6, va_list v7, va_list v8)
+{
+  fprintf (stdout, "%d", i);
+  fprintf (stdout, "%ld", i); /* { dg-warning "format" "fprintf" } */
+  printf ("%d", i);
+  printf ("%ld", i); /* { dg-warning "format" "printf" } */
+  /* The "unlocked" functions shouldn't warn in c90 mode.  */
+  fprintf_unlocked (stdout, "%ld", i);
+  printf_unlocked ("%ld", i);
+  sprintf (s, "%d", i);
+  sprintf (s, "%ld", i); /* { dg-warning "format" "sprintf" } */
+  vfprintf (stdout, "%d", v0);
+  vfprintf (stdout, "%Y", v1); /* { dg-warning "format" "vfprintf" } */
+  vprintf ("%d", v2);
+  vprintf ("%Y", v3); /* { dg-warning "format" "vprintf" } */
+  /* The following used to give a bogus warning.  */
+  vprintf ("%*.*d", v8);
+  vsprintf (s, "%d", v4);
+  vsprintf (s, "%Y", v5); /* { dg-warning "format" "Y is invalid" } */
+  snprintf (s, n, "%d", i);
+  snprintf (s, n, "%ld", (long) i);
+  vsnprintf (s, n, "%d", v6);
+  vsnprintf (s, n, "%Y", v7);
+  printf (gettext ("%d"), i);
+  printf (gettext ("%ld"), i);
+  printf (dgettext ("", "%d"), i);
+  printf (dgettext ("", "%ld"), (long) i);
+  printf (dcgettext ("", "%d", 0), i);
+  printf (dcgettext ("", "%ld", 0), (long) i);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-1.c
@@ -0,0 +1,119 @@
+/* Test for scanf formats.  Formats using C90 features, including cases
+   where C90 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, unsigned int *uip, short int *hp, unsigned short int *uhp,
+     long int *lp, unsigned long int *ulp, float *fp, double *dp,
+     long double *ldp, char *s, signed char *ss, unsigned char *us,
+     void **pp, int *n, llong *llp, ullong *ullp, wchar_t *ls,
+     const int *cip, const int *cn, const char *cs, const void **ppc,
+     void *const *pcp, short int *hn, long int *ln, void *p, char **sp,
+     volatile void *ppv)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.2 (pages 134-138).  */
+  /* Basic sanity checks for the different components of a format.  */
+  scanf ("%d", ip);
+  scanf ("%*d");
+  scanf ("%3d", ip);
+  scanf ("%hd", hp);
+  scanf ("%3ld", lp);
+  scanf ("%*3d");
+  scanf ("%d %ld", ip, lp);
+  /* Valid and invalid %% constructions.  */
+  scanf ("%%");
+  scanf ("%*%"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%*%\n"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%4%"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%4%\n"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%h%"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%h%\n"); /* { dg-warning "format" "bogus %%" } */
+  /* Valid, invalid and silly assignment-suppression constructions.  */
+  scanf ("%*d%*i%*o%*u%*x%*X%*e%*E%*f%*g%*G%*s%*[abc]%*c%*p");
+  scanf ("%*2d%*8s%*3c");
+  scanf ("%*n", n); /* { dg-warning "suppress" "suppression of %n" } */
+  scanf ("%*hd"); /* { dg-warning "together" "suppression with length" } */
+  /* Valid, invalid and silly width constructions.  */
+  scanf ("%2d%3i%4o%5u%6x%7X%8e%9E%10f%11g%12G%13s%14[abc]%15c%16p",
+	 ip, ip, uip, uip, uip, uip, fp, fp, fp, fp, fp, s, s, s, pp);
+  scanf ("%0d", ip); /* { dg-warning "width" "warning for zero width" } */
+  scanf ("%3n", n); /* { dg-warning "width" "width with %n" } */
+  /* Valid and invalid %h, %l, %L constructions.  */
+  scanf ("%hd%hi%ho%hu%hx%hX%hn", hp, hp, uhp, uhp, uhp, uhp, hn);
+  scanf ("%he", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hE", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hf", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hg", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hG", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hs", hp);
+  scanf ("%h[ac]", s); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hc", hp);
+  scanf ("%hp", pp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%h"); /* { dg-warning "conversion lacks type" "bare %h" } */
+  scanf ("%h."); /* { dg-warning "conversion" "bogus %h" } */
+  scanf ("%ld%li%lo%lu%lx%lX%ln", lp, lp, ulp, ulp, ulp, ulp, ln);
+  scanf ("%le%lE%lf%lg%lG", dp, dp, dp, dp, dp);
+  scanf ("%lp", pp); /* { dg-warning "length" "bad use of %l" } */
+  /* These next three formats were added in C94.  */
+  scanf ("%ls", ls); /* { dg-warning "length|C" "bad use of %l" } */
+  scanf ("%l[ac]", ls); /* { dg-warning "length|C" "bad use of %l" } */
+  scanf ("%lc", ls); /* { dg-warning "length|C" "bad use of %l" } */
+  scanf ("%Ld", llp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Li", llp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lo", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lu", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lx", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%LX", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Ls", s); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%L[ac]", s); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lc", s); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lp", pp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Ln", n); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  /* Valid uses of each bare conversion.  */
+  scanf ("%d%i%o%u%x%X%e%E%f%g%G%s%[abc]%c%p%n%%", ip, ip, uip, uip, uip,
+	 uip, fp, fp, fp, fp, fp, s, s, s, pp, n);
+  /* Allow other character pointers with %s, %c, %[].  */
+  scanf ("%2s%3s%4c%5c%6[abc]%7[abc]", ss, us, ss, us, ss, us);
+  /* Further tests for %[].  */
+  scanf ("%[%d]%d", s, ip);
+  scanf ("%[^%d]%d", s, ip);
+  scanf ("%[]%d]%d", s, ip);
+  scanf ("%[^]%d]%d", s, ip);
+  scanf ("%[%d]%d", s, ip);
+  scanf ("%[]abcd", s); /* { dg-warning "no closing" "incomplete scanset" } */
+  /* Various tests of bad argument types.  Some of these are only pedantic
+     warnings.
+  */
+  scanf ("%d", lp); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%d", uip); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%d", pp); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", ppc); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", ppv); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%s", n); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%s", p); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", p); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", sp); /* { dg-warning "format" "bad argument types" } */
+  /* Tests for writing into constant values.  */
+  scanf ("%d", cip); /* { dg-warning "constant" "%d writing into const" } */
+  scanf ("%n", cn); /* { dg-warning "constant" "%n writing into const" } */
+  scanf ("%s", cs); /* { dg-warning "constant" "%s writing into const" } */
+  scanf ("%p", pcp); /* { dg-warning "constant" "%p writing into const" } */
+  /* Wrong number of arguments.  */
+  scanf ("%d%d", ip); /* { dg-warning "arguments" "wrong number of args" } */
+  scanf ("%d", ip, ip); /* { dg-warning "arguments" "wrong number of args" } */
+  /* Miscellaneous bogus constructions.  */
+  scanf (""); /* { dg-warning "zero-length" "warning for empty format" } */
+  scanf ("\0"); /* { dg-warning "embedded" "warning for embedded NUL" } */
+  scanf ("%d\0", ip); /* { dg-warning "embedded" "warning for embedded NUL" } */
+  scanf ("%d\0%d", ip, ip); /* { dg-warning "embedded|too many" "warning for embedded NUL" } */
+  scanf (NULL); /* { dg-warning "null" "null format string warning" } */
+  scanf ("%"); /* { dg-warning "trailing" "trailing % warning" } */
+  scanf ("%d", (int *)0); /* { dg-warning "null" "writing into NULL" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-2.c
@@ -0,0 +1,26 @@
+/* Test for scanf formats.  Formats using C99 features should be rejected
+   outside of C99 mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (signed char *hhp, float *fp, llong *llp, intmax_t *jp,
+     size_t *zp, ptrdiff_t *tp)
+{
+  /* Some tests already in c90-scanf-1.c.  */
+  /* The widths hh, ll, j, z, t are new.  */
+  scanf ("%hhd", hhp); /* { dg-warning "unknown|format" "%hh is unsupported" } */
+  scanf ("%I64d", llp); /* { dg-warning "length|C" "%I64 in C90" } */
+  scanf ("%jd", jp); /* { dg-warning "unknown|format" "%j is unsupported" } */
+  scanf ("%zu", zp); /* { dg-warning "unknown|format" "%z is unsupported" } */
+  scanf ("%td", tp); /* { dg-warning "unknown|format" "%t is unsupported" } */
+  /* The formats F, a, A are new.  */
+  scanf ("%F", fp); /* { dg-warning "unknown|format" "%F is unsupported" } */
+  scanf ("%a", fp); /* { dg-warning "unknown|format" "%a is unsupported" } */
+  scanf ("%A", fp); /* { dg-warning "unknown|format" "%A is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-3.c
@@ -0,0 +1,20 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char **sp, wchar_t **lsp)
+{
+  /* %a formats for allocation, only recognized in C90 mode, are a
+     GNU extension.
+  */
+  scanf ("%as", sp); /* { dg-warning "flag" "%as is unsupported" } */
+  scanf ("%aS", lsp); /* { dg-warning "format|flag" "%aS is unsupported" } */
+  scanf ("%a[bcd]", sp); /* { dg-warning "flag" "%a[] is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-4.c
@@ -0,0 +1,31 @@
+/* Test for scanf formats.  Test that the C90 functions get their default
+   attributes in strict C90 mode, but the C99 and gettext functions
+   do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, char *s, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5)
+{
+  fscanf (stdin, "%d", ip);
+  fscanf (stdin, "%ld", ip); /* { dg-warning "format" "fscanf" } */
+  scanf ("%d", ip);
+  scanf ("%ld", ip); /* { dg-warning "format" "scanf" } */
+  sscanf (s, "%d", ip);
+  sscanf (s, "%ld", ip); /* { dg-warning "format" "sscanf" } */
+  vfscanf (stdin, "%d", v0);
+  vscanf ("%d", v2);
+  vsscanf (s, "%d", v4);
+  scanf (gettext ("%d"), ip);
+  scanf (gettext ("%ld"), ip);
+  scanf (dgettext ("", "%d"), ip);
+  scanf (dgettext ("", "%ld"), ip);
+  scanf (dcgettext ("", "%d", 0), ip);
+  scanf (dcgettext ("", "%ld", 0), ip);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-5.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-5.c
@@ -0,0 +1,20 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char **sp, wchar_t **lsp)
+{
+  /* m assignment-allocation modifier, recognized in both C90
+     and C99 modes, is a POSIX and ISO/IEC WDTR 24731-2 extension.  */
+  scanf ("%ms", sp); /* { dg-warning "unknown|format" "%ms is unsupported" } */
+  scanf ("%mS", lsp); /* { dg-warning "unknown|format" "%mS is unsupported" } */
+  scanf ("%mls", lsp); /* { dg-warning "unknown|format" "%mls is unsupported" } */
+  scanf ("%m[bcd]", sp); /* { dg-warning "unknown|format" "%m[] is unsupported" } */
+  scanf ("%ml[bcd]", lsp); /* { dg-warning "unknown|format" "%ml[] is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-1.c
@@ -0,0 +1,20 @@
+/* Test for strftime formats.  Formats using C90 features.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wformat-y2k" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.12.3.5 (pages 174-175).  */
+  /* Formats which are Y2K-compliant (no 2-digit years).  */
+  strftime (s, m, "%a%A%b%B%d%H%I%j%m%M%p%S%U%w%W%X%Y%Z%%", tp);
+  /* Formats with 2-digit years.  */
+  strftime (s, m, "%y", tp);
+  /* Formats with 2-digit years in some locales.  */
+  strftime (s, m, "%c", tp);
+  strftime (s, m, "%x", tp);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-2.c
@@ -0,0 +1,28 @@
+/* Test for strftime formats.  Rejection of formats using C99 features in
+   pedantic C90 mode.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wformat-y2k" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  strftime (s, m, "%C", tp); /* { dg-warning "format" "%C is unsupported" } */
+  strftime (s, m, "%D", tp); /* { dg-warning "format" "%D is unsupported" } */
+  strftime (s, m, "%e", tp); /* { dg-warning "format" "%e is unsupported" } */
+  strftime (s, m, "%F", tp); /* { dg-warning "format" "%F is unsupported" } */
+  strftime (s, m, "%g", tp); /* { dg-warning "format" "%g is unsupported" } */
+  strftime (s, m, "%G", tp); /* { dg-warning "format" "%G is unsupported" } */
+  strftime (s, m, "%h", tp); /* { dg-warning "format" "%h is unsupported" } */
+  strftime (s, m, "%n", tp); /* { dg-warning "format" "%n is unsupported" } */
+  strftime (s, m, "%r", tp); /* { dg-warning "format" "%r is unsupported" } */
+  strftime (s, m, "%R", tp); /* { dg-warning "format" "%R is unsupported" } */
+  strftime (s, m, "%t", tp); /* { dg-warning "format" "%t is unsupported" } */
+  strftime (s, m, "%T", tp); /* { dg-warning "format" "%T is unsupported" } */
+  strftime (s, m, "%u", tp); /* { dg-warning "format" "%u is unsupported" } */
+  strftime (s, m, "%V", tp); /* { dg-warning "format" "%V is unsupported" } */
+  strftime (s, m, "%z", tp); /* { dg-warning "C" "%z not in C90" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c94-printf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c94-printf-1.c
@@ -0,0 +1,19 @@
+/* Test for printf formats.  Changes in C94 to C90.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:199409 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (wint_t lc, wchar_t *ls)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.1 (pages 131-134),
+     as amended by ISO/IEC 9899:1990/Amd.1:1995 (E) (pages 4-5).
+     We do not repeat here all the C90 format checks, but just verify
+     that %ls and %lc are accepted without warning.
+  */
+  printf ("%lc", lc);
+  printf ("%ls", ls);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c94-scanf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c94-scanf-1.c
@@ -0,0 +1,18 @@
+/* Test for scanf formats.  Changes in C94 to C90.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:199409 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (wchar_t *ls)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.2 (pages 134-138),
+     as amended by ISO/IEC 9899:1990/Amd.1:1995 (E) (pages 5-6).
+     We do not repeat here all the C90 format checks, but just verify
+     that %ls, %lc, %l[] are accepted without warning.
+  */
+  scanf ("%lc%ls%l[abc]", ls, ls, ls);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-1.c
@@ -0,0 +1,122 @@
+/* Test for printf formats.  Formats using C99 features, including cases
+   where C99 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, unsigned int u, double d, char *s, void *p, int *n,
+     long double ld, wint_t lc, wchar_t *ls, long long int ll,
+     unsigned long long int ull, signed char *ss, unsigned char *us,
+     long long int *lln, intmax_t j, uintmax_t uj, intmax_t *jn,
+     size_t z, signed_size_t sz, signed_size_t *zn,
+     ptrdiff_t t, ptrdiff_t *tn)
+{
+  /* See ISO/IEC 9899:1999 (E) subclause 7.19.6.1 (pages 273-281).
+     We do not repeat here most of the checks for correct C90 formats
+     or completely broken formats.
+  */
+  /* Valid and invalid %h, %hh, %l, %I64, %j, %z, %t, %L constructions.  */
+  printf ("%hf", d); /* { dg-warning "length" "bad use of %h" } */
+  printf ("%hF", d); /* { dg-warning "unknown|format" "bad use of %hF" } */
+  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 ("%ha", d); /* { dg-warning "unknown|format" "bad use of %ha" } */
+  printf ("%hA", d); /* { dg-warning "unknown|format" "bad use of %hA" } */
+  printf ("%hc", i);
+  printf ("%hs", (short *)s);
+  printf ("%hp", p); /* { dg-warning "length" "bad use of %h" } */
+  printf ("%lc", lc);
+  printf ("%ls", ls);
+  printf ("%lp", p); /* { dg-warning "length|C" "bad use of %l" } */
+  printf ("%I64d%I64i%I64o%I64u%I64x%I64X", ll, ll, ull, ull, ull, ull);
+  printf ("%I64n", lln);
+  printf ("%I64f", d); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64F", d); /* { dg-warning "unknown|format" "bad use of %I64F" } */
+  printf ("%I64e", d); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64E", d); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64g", d); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64G", d); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64a", d); /* { dg-warning "unknown|format" "bad use of %I64a" } */
+  printf ("%I64A", d); /* { dg-warning "unknown|format" "bad use of %I64A" } */
+  printf ("%I64c", i); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64s", s); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64p", p); /* { dg-warning "length" "bad use of %I64" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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% 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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 ("%-08F", d); /* { dg-warning "unknown|format" "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 ("%-08a", d); /* { dg-warning "unknown|format" "0 flag ignored with - flag" } */
+  printf ("%-08A", d); /* { dg-warning "unknown|format" "0 flag ignored with - flag" } */
+  /* Various tests of bad argument types.  Mostly covered in c90-printf-1.c;
+     here just test for pointer target sign with %hhn.  (Probably allowed
+     by the standard, but a bad idea, so GCC should diagnose if what
+     is used is not signed char *.)
+  */
+  printf ("%hhn", s); /* { dg-warning "unknown|format" "%hhn is unsupported" } */
+  printf ("%hhn", us); /* { dg-warning "unknown|format" "%hhn is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-2.c
@@ -0,0 +1,33 @@
+/* Test for printf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, long long ll, size_t z, wint_t lc, wchar_t *ls)
+{
+  /* The length modifiers q, Z and L as applied to integer formats are
+     extensions.
+  */
+  printf ("%qd", ll); /* { dg-warning "unknown|format" "%q length is unsupported" } */
+  printf ("%Ld", ll); /* { dg-warning "unknown|format" "%L length is unsupported" } */
+  printf ("%Zd", z); /* { dg-warning "unknown|format" "%Z lengthis unsupported" } */
+  /* The conversion specifiers C and S are X/Open extensions; the
+     conversion specifier m is a GNU extension.
+  */
+  printf ("%m"); /* { dg-warning "unknown|format" "printf %m is unsupported" } */
+  printf ("%C", lc); /* { dg-warning "C" "printf %C" } */
+  printf ("%S", ls); /* { dg-warning "C" "printf %S" } */
+  /* The flag character ', and the use of operand number $ formats, are
+     X/Open extensions.
+  */
+  printf ("%'d", i); /* { dg-warning "C" "printf ' flag" } */
+  printf ("%1$d", i); /* { dg-warning "C" "printf $ format" } */
+  /* The flag character I is a GNU extension.  */
+  printf ("%Ix", z);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-3.c
@@ -0,0 +1,40 @@
+/* Test for printf formats.  Test that the C99 functions get their default
+   attributes in strict C99 mode, but the gettext functions do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, char *s, size_t n, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5, va_list v6, va_list v7)
+{
+  fprintf (stdout, "%d", i);
+  fprintf (stdout, "%ld", i); /* { dg-warning "format" "fprintf" } */
+  printf ("%d", i);
+  printf ("%ld", i); /* { dg-warning "format" "printf" } */
+  /* The "unlocked" functions shouldn't warn in c99 mode.  */
+  fprintf_unlocked (stdout, "%ld", i);
+  printf_unlocked ("%ld", i);
+  sprintf (s, "%d", i);
+  sprintf (s, "%ld", i); /* { dg-warning "format" "sprintf" } */
+  snprintf (s, n, "%d", i);
+  snprintf (s, n, "%ld", i); /* { dg-warning "format" "snprintf" } */
+  vfprintf (stdout, "%d", v0);
+  vfprintf (stdout, "%Y", v1); /* { dg-warning "format" "vfprintf" } */
+  vprintf ("%d", v0);
+  vprintf ("%Y", v1); /* { dg-warning "format" "vprintf" } */
+  vsprintf (s, "%d", v0);
+  vsprintf (s, "%Y", v1); /* { dg-warning "format" "vsprintf" } */
+  vsnprintf (s, n, "%d", v0);
+  vsnprintf (s, n, "%Y", v1); /* { dg-warning "format" "vsnprintf" } */
+  printf (gettext ("%d"), i);
+  printf (gettext ("%ld"), (long) i);
+  printf (dgettext ("", "%d"), i);
+  printf (dgettext ("", "%ld"), (long) i);
+  printf (dcgettext ("", "%d", 0), i);
+  printf (dcgettext ("", "%ld", 0), (long) i);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-1.c
@@ -0,0 +1,75 @@
+/* Test for scanf formats.  Formats using C99 features, including cases
+   where C99 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, unsigned int *uip, short int *hp, unsigned short int *uhp,
+     signed char *hhp, unsigned char *uhhp, long int *lp,
+     unsigned long int *ulp, float *fp, double *dp, long double *ldp, char *s,
+     void **pp, int *n, long long *llp, unsigned long long *ullp, wchar_t *ls,
+     short int *hn, signed char *hhn, long int *ln, long long int *lln,
+     intmax_t *jp, uintmax_t *ujp, intmax_t *jn, size_t *zp,
+     signed_size_t *szp, signed_size_t *zn, ptrdiff_t *tp,
+     unsigned_ptrdiff_t *utp, ptrdiff_t *tn)
+{
+  /* See ISO/IEC 9899:1999 (E) subclause 7.19.6.2 (pages 281-288).
+     We do not repeat here most of the checks for correct C90 formats
+     or completely broken formats.
+  */
+  /* Valid, invalid and silly assignment-suppression
+     and width constructions.
+  */
+  scanf ("%*d%*i%*o%*u%*x%*X%*e%*E%*f%*g%*G%*s%*[abc]%*c%*p");
+  scanf ("%*2d%*8s%*3c");
+  scanf ("%*n", n); /* { dg-warning "suppress" "suppression of %n" } */
+  scanf ("%*hd"); /* { dg-warning "together" "suppression with length" } */
+  scanf ("%2d%3i%4o%5u%6x%7X%10e%11E%12f%14g%15G%16s%3[abc]%4c%5p",
+	 ip, ip, uip, uip, uip, uip, fp, fp, fp, fp, fp,
+	 s, s, s, pp);
+  scanf ("%0d", ip); /* { dg-warning "width" "warning for zero width" } */
+  scanf ("%3n", n); /* { dg-warning "width" "width with %n" } */
+  /* Valid and invalid %h, %hh, %l, %I64, %j, %z, %t, %L constructions.  */
+  scanf ("%hd%hi%ho%hu%hx%hX%hn", hp, hp, uhp, uhp, uhp, uhp, hn);
+  scanf ("%he", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hE", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hf", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hg", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hG", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hs", hp);
+  scanf ("%h[ac]", s); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hc", (short *)s);
+  scanf ("%hp", pp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hhd", hhp); /* { dg-warning "unknown|format" "%hh is unsupported" } */
+  scanf ("%ld%li%lo%lu%lx%lX%ln", lp, lp, ulp, ulp, ulp, ulp, ln);
+  scanf ("%le%lE%lf%lg%lG", dp, dp, dp, dp, dp);
+  scanf ("%lp", pp); /* { dg-warning "length" "bad use of %l" } */
+  scanf ("%ls", ls);
+  scanf ("%l[ac]", ls);
+  scanf ("%lc", ls);
+  scanf ("%I64d%I64i%I64o%I64u%I64x%I64X%I64n", llp, llp, ullp, ullp, ullp, ullp,
+	 lln);
+  scanf ("%I64e", fp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64E", fp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64f", fp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64F", fp); /* { dg-warning "unknown|format" "'F' is unsupported" } */
+  scanf ("%I64g", fp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64G", fp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64s", s); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64[ac]", s); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64c", s); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64p", pp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%jd", jp); /* { dg-warning "unknown|format" "%j not supported" } */
+  scanf ("%zd", zp); /* { dg-warning "unknown|format" "%z not supported" } */
+  scanf ("%td", tp); /* { dg-warning "unknown|format" "%t not supported" } */
+  scanf ("%Lf", llp); /* { dg-warning "unknown|format" "bad use of %L is not supported" } */
+  /* Valid uses of each bare conversion.  */
+  scanf ("%d%i%o%u%x%X%e%E%f%g%G%s%[abc]%c%p%n%%", ip, ip, uip, uip, uip,
+         uip, fp, fp, fp, fp, fp, s, s, s, pp, n);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-2.c
@@ -0,0 +1,27 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, long long int *llp, wchar_t *ls)
+{
+  /* The length modifiers q and L as applied to integer formats are
+     extensions.
+  */
+  scanf ("%qd", llp); /* { dg-warning "unknown|format" "%q is unsupported" } */
+  scanf ("%Ld", llp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  /* The conversion specifiers C and S are X/Open extensions.  */
+  scanf ("%C", ls); /* { dg-warning "C" "scanf %C" } */
+  scanf ("%S", ls); /* { dg-warning "C" "scanf %S" } */
+  /* The use of operand number $ formats is an X/Open extension.  */
+  scanf ("%1$d", ip); /* { dg-warning "C" "scanf $ format" } */
+  /* glibc also supports flags ' and I on scanf formats as an extension.  */
+  scanf ("%'d", ip); /* { dg-warning "C" "scanf ' flag" } */
+  scanf ("%Id", (ssize_t *)ip);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-3.c
@@ -0,0 +1,33 @@
+/* Test for scanf formats.  Test that the C99 functions get their default
+   attributes in strict C99 mode, but the gettext functions do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, char *s, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5)
+{
+  fscanf (stdin, "%d", ip);
+  fscanf (stdin, "%ld", ip); /* { dg-warning "format" "fscanf" } */
+  scanf ("%d", ip);
+  scanf ("%ld", ip); /* { dg-warning "format" "scanf" } */
+  sscanf (s, "%d", ip);
+  sscanf (s, "%ld", ip); /* { dg-warning "format" "sscanf" } */
+  vfscanf (stdin, "%d", v0);
+  vfscanf (stdin, "%Y", v1); /* { dg-warning "format" "vfscanf" } */
+  vscanf ("%d", v2);
+  vscanf ("%Y", v3); /* { dg-warning "format" "vscanf" } */
+  vsscanf (s, "%d", v4);
+  vsscanf (s, "%Y", v5); /* { dg-warning "format" "vsscanf" } */
+  scanf (gettext ("%d"), ip);
+  scanf (gettext ("%ld"), ip);
+  scanf (dgettext ("", "%d"), ip);
+  scanf (dgettext ("", "%ld"), ip);
+  scanf (dcgettext ("", "%d", 0), ip);
+  scanf (dcgettext ("", "%ld", 0), ip);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-4.c
@@ -0,0 +1,20 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char **sp, wchar_t **lsp)
+{
+  /* m assignment-allocation modifier, recognized in both C90
+     and C99 modes, is a POSIX and ISO/IEC WDTR 24731-2 extension.  */
+  scanf ("%ms", sp); /* { dg-warning "unknown|format" "%ms is unsupported" } */
+  scanf ("%mS", lsp); /* { dg-warning "unknown|format" "%mS is unsupported" } */
+  scanf ("%mls", lsp); /* { dg-warning "unknown|format" "%mls is unsupported" } */
+  scanf ("%m[bcd]", sp); /* { dg-warning "unknown|format" "%m[] is unsupported" } */
+  scanf ("%ml[bcd]", lsp); /* { dg-warning "unknown|format" "%ml[] is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-1.c
@@ -0,0 +1,23 @@
+/* Test for strftime formats.  Formats using C99 features.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat -Wformat-y2k" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.12.3.5 (pages 174-175).  */
+  /* Formats which are Y2K-compliant (no 2-digit years).  */
+  strftime (s, m, "%a%A%b%B%d%H%I%j%m%M%p%S%U%w%W%X%Y%z%Z%%", tp);
+  strftime (s, m, "%EX%EY%Od%OH%OI%Om%OM%OS%OU%Ow%OW", tp);
+  /* Formats with 2-digit years.  */
+  strftime (s, m, "%D", tp); /* { dg-warning "unknown" "2-digit year unsupported" } */
+  strftime (s, m, "%g", tp); /* { dg-warning "unknown" "2-digit year unsupported" } */
+  strftime (s, m, "%y", tp);
+  /* Formats with 2-digit years in some locales.  */
+  strftime (s, m, "%c", tp);
+  strftime (s, m, "%x", tp);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-2.c
@@ -0,0 +1,20 @@
+/* Test for strftime formats.  Rejection of extensions in pedantic mode.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  /* %P is a lowercase version of %p.  */
+  strftime (s, m, "%P", tp); /* { dg-warning "unknown" "strftime %P" } */
+  /* %k is %H but padded with a space rather than 0 if necessary.  */
+  strftime (s, m, "%k", tp); /* { dg-warning "unknown" "strftime %k" } */
+  /* %l is %I but padded with a space rather than 0 if necessary.  */
+  strftime (s, m, "%l", tp); /* { dg-warning "unknown" "strftime %l" } */
+  /* %s is the number of seconds since the Epoch.  */
+  strftime (s, m, "%s", tp); /* { dg-warning "unknown" "strftime %s" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_cast-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_cast-1.c
@@ -0,0 +1,17 @@
+/* Test for strings cast through integer types: should not be treated
+   as format strings unless the types are of the same width as
+   pointers (intptr_t or similar).  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+f (int x)
+{
+  printf("%s", x); /* { dg-warning "format" } */
+  printf((char *)(size_t)"%s", x); /* { dg-warning "format" } */
+  printf((char *)(char)"%s", x); /* { dg-warning "cast from pointer to integer of different size" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-1.c
@@ -0,0 +1,40 @@
+/* Test for warnings for missing format attributes.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  vprintf (fmt, ap); /* { dg-warning "candidate" "printf attribute warning" } */
+  va_end (ap);
+}
+
+void
+bar (const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  vscanf (fmt, ap); /* { dg-warning "candidate" "scanf attribute warning" } */
+  va_end (ap);
+}
+
+__attribute__((__format__(__ms_printf__, 1, 2))) void
+foo2 (const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  vprintf (fmt, ap);
+  va_end (ap);
+}
+
+void
+vfoo (const char *fmt, va_list arg)
+{
+  vprintf (fmt, arg); /* { dg-warning "candidate" "printf attribute warning 2" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-2.c
@@ -0,0 +1,17 @@
+/* Test for warnings for missing format attributes.  Don't warn if no
+   relevant parameters for a format attribute; see c/1017.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, ...)
+{
+  va_list ap;
+  va_start (ap, i);
+  vprintf ("Foo %s bar %s", ap); /* { dg-bogus "candidate" "bogus printf attribute warning" } */
+  va_end (ap);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-3.c
@@ -0,0 +1,27 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+void
+foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
+{
+  noattr_t na1 = na;
+  noattr_t na2 = a; /* { dg-warning "candidate" "initialization warning" } */
+  attr_t a1 = na;
+  attr_t a2 = a;
+
+  vnoattr_t vna1 = vna;
+  vnoattr_t vna2 = va; /* { dg-warning "candidate" "initialization warning" } */
+  vattr_t va1 = vna;
+  vattr_t va2 = va;
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-4.c
@@ -0,0 +1,33 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+void
+foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
+{
+  noattr_t na1, na2;
+  attr_t a1, a2;
+
+  vnoattr_t vna1, vna2;
+  vattr_t va1, va2;
+
+  na1 = na;
+  na2 = a; /* { dg-warning "candidate" "assignment warning" } */
+  a1 = na;
+  a2 = a;
+
+  vna1 = vna;
+  vna2 = va; /* { dg-warning "candidate" "assignment warning" } */
+  va1 = vna;
+  va1 = va;
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-5.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-5.c
@@ -0,0 +1,49 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+noattr_t
+foo1 (noattr_t na, attr_t a, int i)
+{
+  if (i)
+    return na;
+  else
+    return a; /* { dg-warning "candidate" "return type warning" } */
+}
+
+attr_t
+foo2 (noattr_t na, attr_t a, int i)
+{
+  if (i)
+    return na;
+  else
+    return a;
+}
+
+vnoattr_t
+foo3 (vnoattr_t vna, vattr_t va, int i)
+{
+  if (i)
+    return vna;
+  else
+    return va; /* { dg-warning "candidate" "return type warning" } */
+}
+
+vattr_t
+foo4 (vnoattr_t vna, vattr_t va, int i)
+{
+  if (i)
+    return vna;
+  else
+    return va;
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-6.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-6.c
@@ -0,0 +1,32 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+extern void foo1 (noattr_t);
+extern void foo2 (attr_t);
+extern void foo3 (vnoattr_t);
+extern void foo4 (vattr_t);
+
+void
+foo (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
+{
+  foo1 (na);
+  foo1 (a); /* { dg-warning "candidate" "parameter passing warning" } */
+  foo2 (na);
+  foo2 (a);
+
+  foo3 (vna);
+  foo3 (va); /* { dg-warning "candidate" "parameter passing warning" } */
+  foo4 (vna);
+  foo4 (va);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_multattr-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_multattr-1.c
@@ -0,0 +1,51 @@
+/* Test for multiple format attributes.  Test for printf and scanf attributes
+   together.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* If we specify multiple attributes for a single function, they should
+   all apply.  This should apply whether they are on the same declaration
+   or on different declarations.  */
+
+extern void my_vprintf_scanf (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_printf__, 1, 0)))
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern void my_vprintf_scanf2 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)))
+     __attribute__((__format__(__ms_printf__, 1, 0)));
+
+extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_printf__, 1, 0)));
+extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_printf__, 1, 0)));
+
+void
+foo (va_list ap, int *ip, long *lp)
+{
+  my_vprintf_scanf ("%d", ap, "%d", ip);
+  my_vprintf_scanf ("%d", ap, "%ld", lp);
+  my_vprintf_scanf ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf2 ("%d", ap, "%d", ip);
+  my_vprintf_scanf2 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf2 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf2 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf3 ("%d", ap, "%d", ip);
+  my_vprintf_scanf3 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf3 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf3 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf4 ("%d", ap, "%d", ip);
+  my_vprintf_scanf4 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf4 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf4 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_multattr-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_multattr-2.c
@@ -0,0 +1,40 @@
+/* Test for multiple format attributes.  Test for printf and scanf attributes
+   together, in different places on the declarations.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* If we specify multiple attributes for a single function, they should
+   all apply, wherever they are placed on the declarations.  */
+
+extern __attribute__((__format__(__ms_printf__, 1, 0))) void
+     my_vprintf_scanf (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern void (__attribute__((__format__(__ms_printf__, 1, 0))) my_vprintf_scanf2)
+     (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern __attribute__((__format__(__ms_scanf__, 3, 4))) void
+     (__attribute__((__format__(__ms_printf__, 1, 0))) my_vprintf_scanf3)
+     (const char *, va_list, const char *, ...);
+
+void
+foo (va_list ap, int *ip, long *lp)
+{
+  my_vprintf_scanf ("%d", ap, "%d", ip);
+  my_vprintf_scanf ("%d", ap, "%ld", lp);
+  my_vprintf_scanf ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf2 ("%d", ap, "%d", ip);
+  my_vprintf_scanf2 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf2 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf2 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf3 ("%d", ap, "%d", ip);
+  my_vprintf_scanf3 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf3 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf3 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_multattr-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_multattr-3.c
@@ -0,0 +1,29 @@
+/* Test for multiple format_arg attributes.  Test for both branches
+   getting checked.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+extern char *ngettext (const char *, const char *, unsigned long int)
+     __attribute__((__format_arg__(1))) __attribute__((__format_arg__(2)));
+
+void
+foo (long l, int nfoo)
+{
+  printf (ngettext ("%d foo", "%d foos", nfoo), nfoo);
+  printf (ngettext ("%d foo", "%d foos", l), l); /* { dg-warning "int" "wrong type in conditional expr" } */
+  printf (ngettext ("%d foo", "%ld foos", l), l); /* { dg-warning "int" "wrong type in conditional expr" } */
+  printf (ngettext ("%ld foo", "%d foos", l), l); /* { dg-warning "int" "wrong type in conditional expr" } */
+  /* Should allow one case to have extra arguments.  */
+  printf (ngettext ("1 foo", "%d foos", nfoo), nfoo);
+  printf (ngettext ("1 foo", "many foos", nfoo), nfoo); /* { dg-warning "too many" "too many args in all branches" } */
+  printf (ngettext ("", "%d foos", nfoo), nfoo);
+  printf (ngettext ("1 foo", (nfoo > 0) ? "%d foos" : "no foos", nfoo), nfoo);
+  printf (ngettext ("%d foo", (nfoo > 0) ? "%d foos" : "no foos", nfoo), nfoo);
+  printf (ngettext ("%ld foo", (nfoo > 0) ? "%d foos" : "no foos", nfoo), nfoo); /* { dg-warning "long int" "wrong type" } */
+  printf (ngettext ("%d foo", (nfoo > 0) ? "%ld foos" : "no foos", nfoo), nfoo); /* { dg-warning "long int" "wrong type" } */
+  printf (ngettext ("%d foo", (nfoo > 0) ? "%d foos" : "%ld foos", nfoo), nfoo); /* { dg-warning "long int" "wrong type" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-1.c
@@ -0,0 +1,15 @@
+/* Test for warnings for extra format arguments being disabled by
+   -Wno-format-extra-args.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wno-format-extra-args" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i)
+{
+  printf ("foo", i);
+  printf ("%1$d", i, i);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-2.c
@@ -0,0 +1,28 @@
+/* Test for warnings for extra format arguments being disabled by
+   -Wno-format-extra-args.  Test which warnings still apply with $
+   operand numbers.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wno-format-extra-args" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, int *ip, va_list va)
+{
+  printf ("%3$d%1$d", i, i, i); /* { dg-warning "before used" "unused $ operand" } */
+  printf ("%2$d%1$d", i, i, i);
+  vprintf ("%3$d%1$d", va); /* { dg-warning "before used" "unused $ operand" } */
+  /* With scanf formats, gaps in the used arguments are allowed only if the
+     arguments are all pointers.  In such a case, should only give the lesser
+     warning about unused arguments rather than the more serious one about
+     argument gaps.  */
+  scanf ("%3$d%1$d", ip, ip, ip);
+  /* If there are non-pointer arguments unused at the end, this is also OK.  */
+  scanf ("%3$d%1$d", ip, ip, ip, i);
+  scanf ("%3$d%1$d", ip, i, ip); /* { dg-warning "before used" "unused $ scanf non-pointer operand" } */
+  /* Can't check the arguments in the vscanf case, so should suppose the
+     lesser problem.  */
+  vscanf ("%3$d%1$d", va);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_no-y2k-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_no-y2k-1.c
@@ -0,0 +1,13 @@
+/* Test for warnings for Y2K problems not being on by default.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  strftime (s, m, "%y%c%x", tp);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-1.c
@@ -0,0 +1,14 @@
+/* Test for warnings for non-string-literal formats.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wformat-nonliteral" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t i)
+{
+  printf ((const char *)i, i); /* { dg-warning "argument types" "non-literal" } */
+  printf (s, i); /* { dg-warning "argument types" "non-literal" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-2.c
@@ -0,0 +1,14 @@
+/* Test for warnings for non-string-literal formats.  Test with -Wformat=2.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat=2" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t i)
+{
+  printf ((const char *)i, i); /* { dg-warning "argument types" "non-literal" } */
+  printf (s, i); /* { dg-warning "argument types" "non-literal" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-3.c
@@ -0,0 +1,13 @@
+/* Test for warnings for non-string-literal formats.  Test for strftime formats.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wformat-nonliteral" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp, char *fmt)
+{
+  strftime (s, m, fmt, tp); /* { dg-warning "format string" "non-literal" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nul-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nul-1.c
@@ -0,0 +1,15 @@
+/* Test diagnostics for suppressing contains nul
+   -Wformat.  -Wformat.  */
+/* Origin: Bruce Korb <bkorb@gnu.org> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat -Wno-format-contains-nul" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (void)
+{
+  static char const fmt[] = "x%s\0%s\n\0abc";
+  printf (fmt+4, fmt+8); /* { dg-bogus "embedded.*in format" "bogus embed warning" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nul-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nul-2.c
@@ -0,0 +1,17 @@
+/* Test diagnostics for options used on their own without
+   -Wformat.  -Wformat-.  */
+/* Origin: Bruce Korb <bkorb@gnu.org> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+
+/* { dg-warning "embedded .* in format" "ignored" { target *-*-* } 0 } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+fumble (void)
+{
+  static char const fmt[] = "x%s\0%s\n\0abc";
+  printf (fmt+4, fmt+8);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_null-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_null-1.c
@@ -0,0 +1,28 @@
+/* Test for some aspects of null format string handling.  */
+/* Origin: Jason Thorpe <thorpej@wasabisystems.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+extern void my_printf (const char *, ...) __attribute__((format(ms_printf,1,2)));
+extern const char *my_format (const char *, const char *)
+  __attribute__((format_arg(2)));
+
+void
+foo (int i1)
+{
+  /* Warning about a null format string has been decoupled from the actual
+     format check.  However, we still expect to be warned about any excess
+     arguments after a null format string.  */
+  my_printf (NULL);
+  my_printf (NULL, i1); /* { dg-warning "too many" "null format with arguments" } */
+
+  my_printf (my_format ("", NULL));
+  my_printf (my_format ("", NULL), i1); /* { dg-warning "too many" "null format_arg with arguments" } */
+
+  /* While my_printf allows a null argument, dgettext does not, so we expect
+     a null argument warning here.  */
+  my_printf (dgettext ("", NULL)); /* { dg-warning "null" "null format with dgettext" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_plus-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_plus-1.c
@@ -0,0 +1,21 @@
+/* Test for printf formats using string literal plus constant.
+ */
+/* Origin: Jakub Jelinek <jakub@redhat.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat=2" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i)
+{
+  printf ("%%d\n" + 1, i);
+  printf (5 + "%.-*d%3d\n", i);
+  printf ("%d%d" + 2, i, i);	/* { dg-warning "arguments" "wrong number of args" } */
+  printf (3 + "%d\n");		/* { dg-warning "zero-length" "zero-length string" } */
+  printf ("%d\n" + i, i);	/* { dg-warning "not a string" "non-constant addend" } */
+  printf ("%d\n" + 10);		/* { dg-warning "not a string" "too large addend" } */
+  printf ("%d\n" - 1, i);	/* { dg-warning "not a string" "minus constant" } */
+  printf ("%d\n" + -1, i);	/* { dg-warning "not a string" "negative addend" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_sec-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_sec-1.c
@@ -0,0 +1,13 @@
+/* Test for security warning when non-literal format has no arguments.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wformat-security" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s)
+{
+  printf (s); /* { dg-warning "no format arguments" "security warning" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_unnamed-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_unnamed-1.c
@@ -0,0 +1,24 @@
+/* Test for warnings with possibly unnamed integer types.  Bug 24329.  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+/* { dg-options "-Wformat -msse" { target { { i?86-*-* x86_64-*-* } && ilp32 } } } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* Definition of TItype follows same logic as in gcc.dg/titype-1.c,
+   but must be a #define to avoid giving the type a name.  */
+#if defined(__LP64__) && !defined(__hppa__)
+#define TItype int __attribute__ ((mode (TI)))
+#else
+#define TItype long
+#endif
+
+void
+f (TItype x)
+{
+  printf("%d", x); /* { dg-warning "expects type" } */
+  printf("%d", 141592653589793238462643383279502884197169399375105820974944); /* { dg-warning "expects type" } */
+  /* { dg-warning "unsigned only|too large" "constant" { target *-*-* } 22 } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_va-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_va-1.c
@@ -0,0 +1,14 @@
+/* Test for strange warning in format checking.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (void *p)
+{
+  printf ("%d", p); /* { dg-bogus "va_list" "wrong type in format warning" } */
+  /* { dg-warning "format" "format error" { target *-*-* } 12 } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_warnll-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_warnll-1.c
@@ -0,0 +1,19 @@
+/* Test for printf formats.  C99 "long long" formats should be accepted with
+   -Wno-long-long.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wno-long-long" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (long long ll, unsigned long long ull, long long *lln,
+     long long *llp, unsigned long long *ullp)
+{
+  /* Test for accepting standard "long long" formats.  */
+  printf ("%I64d%I64i%I64o%I64u%I64x%I64X%I64n", ll, ll, ull, ull, ull, ull, lln);
+  scanf ("%I64d%I64i%I64o%I64u%I64x%I64X%I64n", llp, llp,
+	 ullp, ullp, ullp, ullp, lln);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_zero-length-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_zero-length-1.c
@@ -0,0 +1,16 @@
+/* Test the -Wno-format-zero-length option, which suppresses warnings
+   about zero-length formats.  */
+/* Origin: Jason Thorpe <thorpej@wasabisystems.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wno-format-zero-length" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (void)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.1 (pages 131-134).  */
+  /* Zero-length format strings are allowed.  */
+  printf ("");
+}
Index: gcc/gcc/testsuite/gcc.dg/format/multattr-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/multattr-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/multattr-1.c
@@ -4,6 +4,7 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 /* If we specify multiple attributes for a single function, they should
@@ -11,22 +12,22 @@
    or on different declarations.  */
 
 extern void my_vprintf_scanf (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__printf__, 1, 0)))
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)))
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
 extern void my_vprintf_scanf2 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)))
-     __attribute__((__format__(__printf__, 1, 0)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)))
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)));
 
 extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__printf__, 1, 0)));
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)));
 extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
 extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__printf__, 1, 0)));
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)));
 
 void
 foo (va_list ap, int *ip, long *lp)
Index: gcc/gcc/testsuite/gcc.dg/format/multattr-2.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/multattr-2.c
+++ gcc/gcc/testsuite/gcc.dg/format/multattr-2.c
@@ -4,21 +4,22 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 /* If we specify multiple attributes for a single function, they should
    all apply, wherever they are placed on the declarations.  */
 
-extern __attribute__((__format__(__printf__, 1, 0))) void
+extern __attribute__((__format__(gnu_attr___printf__, 1, 0))) void
      my_vprintf_scanf (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
-extern void (__attribute__((__format__(__printf__, 1, 0))) my_vprintf_scanf2)
+extern void (__attribute__((__format__(gnu_attr___printf__, 1, 0))) my_vprintf_scanf2)
      (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
-extern __attribute__((__format__(__scanf__, 3, 4))) void
-     (__attribute__((__format__(__printf__, 1, 0))) my_vprintf_scanf3)
+extern __attribute__((__format__(gnu_attr___scanf__, 3, 4))) void
+     (__attribute__((__format__(gnu_attr___printf__, 1, 0))) my_vprintf_scanf3)
      (const char *, va_list, const char *, ...);
 
 void
Index: gcc/gcc/testsuite/gcc.dg/format/null-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/null-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/null-1.c
@@ -3,9 +3,10 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern void my_printf (const char *, ...) __attribute__((format(printf,1,2)));
+extern void my_printf (const char *, ...) __attribute__((format(gnu_attr_printf,1,2)));
 extern const char *my_format (const char *, const char *)
   __attribute__((format_arg(2)));
 
=

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf  formatters to c-format.c
  2008-03-13  0:03                         ` Danny Smith
@ 2008-03-13  8:43                           ` Kai Tietz
  2008-03-13  9:29                           ` Kai Tietz
  1 sibling, 0 replies; 61+ messages in thread
From: Kai Tietz @ 2008-03-13  8:43 UTC (permalink / raw)
  To: Danny Smith; +Cc: GCC Patches, ktietz70, NightStrike

"Danny Smith" <dansmister@gmail.com> wrote on 13.03.2008 01:02:48:

> On Tue, Mar 11, 2008 at 11:29 AM, Joseph S. Myers
> <joseph@codesourcery.com> wrote:
> > On Mon, 10 Mar 2008, Kai Tietz wrote:
> >
> >  > > Note that this part of the patch will need reviewing by a MinGW
> >  > > maintainer.
> >  >
> >  > Danny, could you do that?
> >  >
> >  > Is this ok for apply to trunk?
> >
> >  The C front end parts of the patch are OK.  As noted before, the 
MinGW
> >  parts (in particular the tables and the new testcases) will need 
reviewing
> >  by a MinGW maintainer.
> >
> >
> Kai.
> 
> I see 44 format.exp failures in testsuite  with your patch
> 
> The summary is attached.
> Danny
> [attachment "Failures.txt" deleted by Kai Tietz/Onevision] 

Could you sent me the log file, too?
The for strftime test, it seems that I accidentily typed the double year 
format, which isn't support by ms variant. I will fix this soon.

Is is ok for apply?

Kai

|  (\_/)  This is Bunny. Copy and paste Bunny
| (='.'=) into your signature to help him gain
| (")_(") world domination.

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf formatters to c-format.c
  2008-03-10 22:29                       ` Joseph S. Myers
@ 2008-03-13  0:03                         ` Danny Smith
  2008-03-13  8:43                           ` Kai Tietz
  2008-03-13  9:29                           ` Kai Tietz
  0 siblings, 2 replies; 61+ messages in thread
From: Danny Smith @ 2008-03-13  0:03 UTC (permalink / raw)
  To: Kai Tietz; +Cc: GCC Patches, ktietz70, NightStrike

[-- Attachment #1: Type: text/plain, Size: 573 bytes --]

On Tue, Mar 11, 2008 at 11:29 AM, Joseph S. Myers
<joseph@codesourcery.com> wrote:
> On Mon, 10 Mar 2008, Kai Tietz wrote:
>
>  > > Note that this part of the patch will need reviewing by a MinGW
>  > > maintainer.
>  >
>  > Danny, could you do that?
>  >
>  > Is this ok for apply to trunk?
>
>  The C front end parts of the patch are OK.  As noted before, the MinGW
>  parts (in particular the tables and the new testcases) will need reviewing
>  by a MinGW maintainer.
>
>
Kai.

I see 44 format.exp failures in testsuite  with your patch

The summary is attached.
Danny

[-- Attachment #2: Failures.txt --]
[-- Type: text/plain, Size: 3739 bytes --]

Test Run By Danny on Thu Mar 13 12:40:49 2008
Native configuration is i386-pc-mingw32

		=== gcc tests ===

Schedule of variations:
    unix

Running target unix
Running /develop/svn/trunk/src/gcc/testsuite/gcc.dg/format/format.exp ...
FAIL: gcc.dg/format/ms_c90-printf-3.c dot is invalid (test for warnings, line 30)
FAIL: gcc.dg/format/ms_c90-printf-3.c dot is invalid (test for warnings, line 30)
FAIL: gcc.dg/format/ms_c90-strftime-1.c 2-digit year (test for warnings, line 16)
FAIL: gcc.dg/format/ms_c90-strftime-1.c 2-digit year (test for warnings, line 18)
FAIL: gcc.dg/format/ms_c90-strftime-1.c 2-digit year (test for warnings, line 19)
FAIL: gcc.dg/format/ms_c90-strftime-1.c 2-digit year (test for warnings, line 16)
FAIL: gcc.dg/format/ms_c90-strftime-1.c 2-digit year (test for warnings, line 18)
FAIL: gcc.dg/format/ms_c90-strftime-1.c 2-digit year (test for warnings, line 19)
FAIL: gcc.dg/format/ms_c90-strftime-2.c %E not in C90 (test for warnings, line 28)
FAIL: gcc.dg/format/ms_c90-strftime-2.c %O not in C90 (test for warnings, line 29)
FAIL: gcc.dg/format/ms_c90-strftime-2.c (test for excess errors)
FAIL: gcc.dg/format/ms_c90-strftime-2.c %E not in C90 (test for warnings, line 28)
FAIL: gcc.dg/format/ms_c90-strftime-2.c %O not in C90 (test for warnings, line 29)
FAIL: gcc.dg/format/ms_c90-strftime-2.c (test for excess errors)
FAIL: gcc.dg/format/ms_c99-printf-1.c (test for excess errors)
FAIL: gcc.dg/format/ms_c99-printf-1.c (test for excess errors)
FAIL: gcc.dg/format/ms_c99-printf-2.c (test for excess errors)
FAIL: gcc.dg/format/ms_c99-printf-2.c (test for excess errors)
FAIL: gcc.dg/format/ms_c99-scanf-1.c (test for excess errors)
FAIL: gcc.dg/format/ms_c99-scanf-1.c (test for excess errors)
FAIL: gcc.dg/format/ms_c99-scanf-2.c (test for excess errors)
FAIL: gcc.dg/format/ms_c99-scanf-2.c (test for excess errors)
FAIL: gcc.dg/format/ms_c99-strftime-1.c 2-digit year (test for warnings, line 19)
FAIL: gcc.dg/format/ms_c99-strftime-1.c 2-digit year (test for warnings, line 20)
FAIL: gcc.dg/format/ms_c99-strftime-1.c 2-digit year (test for warnings, line 22)
FAIL: gcc.dg/format/ms_c99-strftime-1.c 2-digit year (test for warnings, line 23)
FAIL: gcc.dg/format/ms_c99-strftime-1.c 2-digit year (test for warnings, line 24)
FAIL: gcc.dg/format/ms_c99-strftime-1.c 2-digit year (test for warnings, line 25)
FAIL: gcc.dg/format/ms_c99-strftime-1.c 2-digit year (test for warnings, line 29)
FAIL: gcc.dg/format/ms_c99-strftime-1.c (test for excess errors)
FAIL: gcc.dg/format/ms_c99-strftime-1.c 2-digit year (test for warnings, line 19)
FAIL: gcc.dg/format/ms_c99-strftime-1.c 2-digit year (test for warnings, line 20)
FAIL: gcc.dg/format/ms_c99-strftime-1.c 2-digit year (test for warnings, line 22)
FAIL: gcc.dg/format/ms_c99-strftime-1.c 2-digit year (test for warnings, line 23)
FAIL: gcc.dg/format/ms_c99-strftime-1.c 2-digit year (test for warnings, line 24)
FAIL: gcc.dg/format/ms_c99-strftime-1.c 2-digit year (test for warnings, line 25)
FAIL: gcc.dg/format/ms_c99-strftime-1.c 2-digit year (test for warnings, line 29)
FAIL: gcc.dg/format/ms_c99-strftime-1.c (test for excess errors)
FAIL: gcc.dg/format/ms_c99-strftime-2.c strftime flags (test for warnings, line 23)
FAIL: gcc.dg/format/ms_c99-strftime-2.c (test for excess errors)
FAIL: gcc.dg/format/ms_c99-strftime-2.c strftime flags (test for warnings, line 23)
FAIL: gcc.dg/format/ms_c99-strftime-2.c (test for excess errors)
FAIL: gcc.dg/format/ms_warnll-1.c (test for excess errors)
FAIL: gcc.dg/format/ms_warnll-1.c (test for excess errors)

		=== gcc Summary ===

# of expected passes		3962
# of unexpected failures	44
# of unsupported tests		12
/develop/svn/trunk/build/gcc/xgcc  version 4.4.0-dw2 20080312 (experimental) (GCC) 


^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf             formatters to c-format.c
  2008-03-10 11:06                     ` Kai Tietz
@ 2008-03-10 22:29                       ` Joseph S. Myers
  2008-03-13  0:03                         ` Danny Smith
  0 siblings, 1 reply; 61+ messages in thread
From: Joseph S. Myers @ 2008-03-10 22:29 UTC (permalink / raw)
  To: Kai Tietz; +Cc: Danny Smith, GCC Patches, ktietz70, NightStrike

On Mon, 10 Mar 2008, Kai Tietz wrote:

> > Note that this part of the patch will need reviewing by a MinGW 
> > maintainer.
> 
> Danny, could you do that?
> 
> Is this ok for apply to trunk?

The C front end parts of the patch are OK.  As noted before, the MinGW 
parts (in particular the tables and the new testcases) will need reviewing 
by a MinGW maintainer.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf            formatters to c-format.c
  2008-02-25 18:53                   ` Joseph S. Myers
  2008-03-04 19:25                     ` Joseph S. Myers
@ 2008-03-10 11:06                     ` Kai Tietz
  2008-03-10 22:29                       ` Joseph S. Myers
  1 sibling, 1 reply; 61+ messages in thread
From: Kai Tietz @ 2008-03-10 11:06 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: Danny Smith, GCC Patches, ktietz70, NightStrike

[-- Attachment #1: Type: text/plain, Size: 5297 bytes --]

"Joseph S. Myers" <joseph@codesourcery.com> wrote on 25.02.2008 19:48:56:

Ok, I am back at work again. AFAIK does cygwin needs this just for the 
case somebody uses cygwin gcc as mingw compiler. Otherwise they need just 
the variable to be able link. Cygwin uses gnu format attributes by 
default, isn't it?
I changed your suggestions and patched the flags of strftime for ms 
format.

> Note that this part of the patch will need reviewing by a MinGW 
> maintainer.

Danny, could you do that?

Is this ok for apply to trunk?

2008-03-10      Kai Tietz  <kai.tietz@onevision.com>

        * c-format.c (replace_format_name_to_system_name): New.
        (cmp_attribs): New.
        (convert_format_name_to_system_name): New.
        (decode_format_attr): Add use of 
convert_format_name_to_system_name.
        (format_types_orig): Add gnu_ prefix to names.
        (check_format_info_main): Special treating of \0 escaped names for
        supporting multi-character format specifiers as I32, I64.
        (TARGET_OVERRIDES_FORMAT_ATTRIBUTES): Use of user defined 
attributes.
        (gnu_target_overrides_format_attributes): New.
        * c-format.h: Add structure target_ovr_attr to hold
        system specific formatter names.
        * config.gcc: Add for x86&x86_64 cygwin and mingw32 targets the
        msformat-c.o file to c_target_objs and cxx_target_objs.
        * config/i386/mingw32.h (TARGET_OVERRIDES_FORMAT_ATTRIBUTES): New.
        (TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT): New.
        (TARGET_N_FORMAT_TYPES): New.
        * config/i386/msformat-c.c: New.
        * config/i386/t-cygming: Add build rule for msformat-c.o.
        * doc/extend.texi: Add new format names gnu_* and ms_* and
        further details.
        * doc/tm.texi: (TARGET_OVERRIDES_FORMAT_ATTRIBUTES): New.

ChangeLog for testcase

2008-03-10  Kai Tietz  <kai.tietz@onevision.com>

        * gcc.dg/format/ms_array-1.c: New.
        * gcc.dg/format/ms_c90-scanf-3.c: New.
        * gcc.dg/format/ms_c99-strftime-1.c: New.
        * gcc.dg/format/ms_no-y2k-1.c: New.
        * gcc.dg/format/ms_attr-1.c: New.
        * gcc.dg/format/ms_c90-scanf-4.c: New.
        * gcc.dg/format/ms_c99-strftime-2.c: New.
        * gcc.dg/format/ms_nonlit-1.c: New.
        * gcc.dg/format/ms_c90-scanf-5.c: New.
        * gcc.dg/format/ms_cast-1.c: New.
        * gcc.dg/format/ms_nonlit-2.c: New.
        * gcc.dg/format/ms_attr-2.c: New.
        * gcc.dg/format/ms_c90-strftime-1.c: New.
        * gcc.dg/format/ms_miss-1.c: New.
        * gcc.dg/format/ms_nonlit-3.c: New.
        * gcc.dg/format/ms_attr-3.c: New.
        * gcc.dg/format/ms_c90-strftime-2.c: New.
        * gcc.dg/format/ms_miss-2.c: New.
        * gcc.dg/format/ms_nul-1.c: New.
        * gcc.dg/format/ms_attr-4.c: New.
        * gcc.dg/format/ms_c94-printf-1.c: New.
        * gcc.dg/format/ms_miss-3.c: New.
        * gcc.dg/format/ms_nul-2.c: New.
        * gcc.dg/format/ms_attr-7.c: New.
        * gcc.dg/format/ms_c94-scanf-1.c: New.
        * gcc.dg/format/ms_miss-4.c: New.
        * gcc.dg/format/ms_null-1.c: New.
        * gcc.dg/format/ms_bitfld-1.c: New.
        * gcc.dg/format/ms_c99-printf-1.c: New.
        * gcc.dg/format/ms_miss-5.c: New.
        * gcc.dg/format/ms_plus-1.c: New.
        * gcc.dg/format/ms_branch-1.c: New.
        * gcc.dg/format/ms_c99-printf-2.c: New.
        * gcc.dg/format/ms_miss-6.c: New.
        * gcc.dg/format/ms_sec-1.c: New.
        * gcc.dg/format/ms_c90-printf-1.c: New.
        * gcc.dg/format/ms_c99-printf-3.c: New.
        * gcc.dg/format/ms_multattr-1.c: New.
        * gcc.dg/format/ms_unnamed-1.c: New.
        * gcc.dg/format/ms_c90-printf-2.c: New.
        * gcc.dg/format/ms_c99-scanf-1.c: New.
        * gcc.dg/format/ms_multattr-2.c: New.
        * gcc.dg/format/ms_va-1.c: New.
        * gcc.dg/format/ms_c90-printf-3.c: New.
        * gcc.dg/format/ms_c99-scanf-2.c: New.
        * gcc.dg/format/ms_multattr-3.c: New.
        * gcc.dg/format/ms_warnll-1.c: New.
        * gcc.dg/format/ms_c90-scanf-1.c: New.
        * gcc.dg/format/ms_c99-scanf-3.c: New.
        * gcc.dg/format/ms_no-exargs-1.c: New.
        * gcc.dg/format/ms_zero-length-1.c: New.
        * gcc.dg/format/ms_c90-scanf-2.c: New.
        * gcc.dg/format/ms_c99-scanf-4.c: New.
        * gcc.dg/format/ms_no-exargs-2.c: New.
        * gcc.dg/format/null-1.c: Add gnu style usage for mingw.
        * gcc.dg/format/miss-1.c: Likewise.
        * gcc.dg/format/miss-3.c: Likewise.
        * gcc.dg/format/multattr-2.c: Likewise.
        * gcc.dg/format/miss-5.c: Likewise.
        * gcc.dg/format/attr-2.c: Likewise.
        * gcc.dg/format/attr-4.c: Likewise.
        * gcc.dg/format/c90-scanf-4.c: Likewise.
        * gcc.dg/format/c99-printf-3.c: Likewise.
        * gcc.dg/format/multattr-1.c: Likewise.
        * gcc.dg/format/miss-4.c: Likewise.
        * gcc.dg/format/miss-6.c: Likewise.
        * gcc.dg/format/c90-printf-3.c: Likewise.
        * gcc.dg/format/attr-1.c: Likewise.
        * gcc.dg/format/attr-3.c: Likewise.
        * gcc.dg/format/attr-7.c: Likewise.
        * gcc.dg/format/format.h: Treat mingw and gnu style.
        * gcc.dg/format/sys_format.c: New.

Kai



|  (\_/)  This is Bunny. Copy and paste Bunny
| (='.'=) into your signature to help him gain
| (")_(") world domination.

[-- Attachment #2: mingw-msformat.txt --]
[-- Type: text/plain, Size: 154305 bytes --]

Index: gcc/gcc/c-format.c
===================================================================
--- gcc.orig/gcc/c-format.c
+++ gcc/gcc/c-format.c
@@ -62,8 +62,7 @@ enum format_type { printf_format_type, a
 		   gcc_diag_format_type, gcc_tdiag_format_type,
 		   gcc_cdiag_format_type,
 		   gcc_cxxdiag_format_type, gcc_gfc_format_type,
-		   scanf_format_type, strftime_format_type,
-		   strfmon_format_type, format_type_error = -1};
+		   format_type_error = -1};
 
 typedef struct function_format_info
 {
@@ -80,7 +79,8 @@ static bool check_format_string (tree ar
 				 int flags, bool *no_add_attrs);
 static bool get_constant (tree expr, unsigned HOST_WIDE_INT *value,
 			  int validated_p);
-
+static const char *convert_format_name_to_system_name (const char *attr_name);
+static bool cmp_attribs (const char *tattr_name, const char *attr_name);
 
 /* Handle a "format_arg" attribute; arguments as in
    struct attribute_spec.handler.  */
@@ -191,6 +191,8 @@ decode_format_attr (tree args, function_
     {
       const char *p = IDENTIFIER_POINTER (format_type_id);
 
+      p = convert_format_name_to_system_name (p);
+
       info->format_type = decode_format_type (p);
 
       if (info->format_type == format_type_error)
@@ -715,7 +717,7 @@ static const format_char_info monetary_c
 /* This must be in the same order as enum format_type.  */
 static const format_kind_info format_types_orig[] =
 {
-  { "printf",   printf_length_specs,  print_char_table, " +#0-'I", NULL,
+  { "gnu_printf",   printf_length_specs,  print_char_table, " +#0-'I", NULL,
     printf_flag_specs, printf_flag_pairs,
     FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
     'w', 0, 'p', 0, 'L', 0,
@@ -757,18 +759,18 @@ static const format_kind_info format_typ
     0, 0, 0, 0, 0, 0,
     NULL, NULL
   },
-  { "scanf",    scanf_length_specs,   scan_char_table,  "*'I", NULL,
+  { "gnu_scanf",    scanf_length_specs,   scan_char_table,  "*'I", NULL,
     scanf_flag_specs, scanf_flag_pairs,
     FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
     'w', 0, 0, '*', 'L', 'm',
     NULL, NULL
   },
-  { "strftime", NULL,                 time_char_table,  "_-0^#", "EO",
+  { "gnu_strftime", NULL,                 time_char_table,  "_-0^#", "EO",
     strftime_flag_specs, strftime_flag_pairs,
     FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0, 0,
     NULL, NULL
   },
-  { "strfmon",  strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
+  { "gnu_strfmon",  strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
     strfmon_flag_specs, strfmon_flag_pairs,
     FMT_FLAG_ARG_CONVERT, 'w', '#', 'p', 0, 'L', 0,
     NULL, NULL
@@ -847,6 +849,8 @@ decode_format_type (const char *s)
 {
   int i;
   int slen;
+
+  s = convert_format_name_to_system_name (s);
   slen = strlen (s);
   for (i = 0; i < n_format_types; i++)
     {
@@ -1776,7 +1780,22 @@ check_format_info_main (format_check_res
       if (fli)
 	{
 	  while (fli->name != 0 && fli->name[0] != *format_chars)
-	    fli++;
+	    {
+	      if (fli->name[0] == '\0')
+		{
+		  int si  = strlen (fli->name + 1) + 1;
+		  int i = 1;
+		  while (fli->name[i] != 0 && fli->name[i] == format_chars [i - 1])
+		    ++i;
+		 if (si == i)
+		   {
+		     if (si > 2)
+		       format_chars += si - 2;
+		     break;
+		   }
+	       }
+	      fli++;
+	    }
 	  if (fli->name != 0)
 	    {
 	      format_chars++;
@@ -2703,6 +2722,84 @@ init_dynamic_diag_info (void)
 extern const format_kind_info TARGET_FORMAT_TYPES[];
 #endif
 
+#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+extern const target_ovr_attr TARGET_OVERRIDES_FORMAT_ATTRIBUTES[];
+#endif
+
+/* Attributes such as "printf" are equivalent to those such as
+   "gnu_printf" unless this is overridden by a target.  */
+static const target_ovr_attr gnu_target_overrides_format_attributes[] =
+{
+  { "gnu_printf",   "printf" },
+  { "gnu_scanf",    "scanf" },
+  { "gnu_strftime", "strftime" },
+  { "gnu_strfmon",  "strfmon" },
+  { NULL,           NULL }
+};
+
+/* Translate to unified attribute name. This is used in decode_format_type and
+   decode_format_attr. In attr_name the user specified argument is passed. It
+   returns the unified format name from TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+   or the attr_name passed to this function, if there is no matching entry.  */
+static const char *
+convert_format_name_to_system_name (const char *attr_name)
+{
+  int i;
+
+  if (attr_name == NULL || *attr_name == 0
+      || strncmp (attr_name, "gcc_", 4) == 0)
+    return attr_name;
+
+#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+  /* Check if format attribute is overridden by target.  */
+  if (TARGET_OVERRIDES_FORMAT_ATTRIBUTES != NULL
+      && TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT > 0)
+    {
+      for (i = 0; i < TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT; ++i)
+        {
+          if (cmp_attribs (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src,
+			   attr_name))
+            return attr_name;
+          if (cmp_attribs (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_dst,
+			   attr_name))
+            return TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src;
+        }
+    }
+#endif
+  /* Otherwise default to gnu format.  */
+  for (i = 0;
+       gnu_target_overrides_format_attributes[i].named_attr_src != NULL;
+       ++i)
+    {
+      if (cmp_attribs (gnu_target_overrides_format_attributes[i].named_attr_src,
+		       attr_name))
+        return attr_name;
+      if (cmp_attribs (gnu_target_overrides_format_attributes[i].named_attr_dst,
+		       attr_name))
+        return gnu_target_overrides_format_attributes[i].named_attr_src;
+    }
+
+  return attr_name;
+}
+
+/* Return true if TATTR_NAME and ATTR_NAME are the same format attribute,
+   counting "name" and "__name__" as the same, false otherwise.  */
+static bool
+cmp_attribs (const char *tattr_name, const char *attr_name)
+{
+  int alen = strlen (attr_name);
+  int slen = (tattr_name ? strlen (tattr_name) : 0);
+  if (alen > 4 && attr_name[0] == '_' && attr_name[1] == '_'
+      && attr_name[alen - 1] == '_' && attr_name[alen - 2] == '_')
+    {
+      attr_name += 2;
+      alen -= 4;
+    }
+  if (alen != slen || strncmp (tattr_name, attr_name, alen) != 0)
+    return false;
+  return true;
+}
+
 /* Handle a "format" attribute; arguments as in
    struct attribute_spec.handler.  */
 tree
@@ -2762,7 +2859,10 @@ handle_format_attribute (tree *node, tre
 	}
     }
 
-  if (info.format_type == strftime_format_type && info.first_arg_num != 0)
+  /* Check if this is a strftime variant. Just for this variant
+     FMT_FLAG_ARG_CONVERT is not set.  */
+  if ((format_types[info.format_type].flags & (int) FMT_FLAG_ARG_CONVERT) == 0
+      && info.first_arg_num != 0)
     {
       error ("strftime formats cannot format arguments");
       *no_add_attrs = true;
Index: gcc/gcc/c-format.h
===================================================================
--- gcc.orig/gcc/c-format.h
+++ gcc/gcc/c-format.h
@@ -80,12 +80,13 @@ enum
      of whether length modifiers can occur (length_char_specs).  */
 };
 
-
 /* Structure describing a length modifier supported in format checking, and
    possibly a doubled version such as "hh".  */
 typedef struct
 {
-  /* Name of the single-character length modifier.  */
+  /* Name of the single-character length modifier. If prefixed by
+     a zero character, it describes a multi character length
+     modifier, like I64, I32, etc.  */
   const char *name;
   /* Index into a format_char_info.types array.  */
   enum format_lengths index;
@@ -306,4 +307,16 @@ typedef struct
 #define T_D128  &dfloat128_type_node
 #define TEX_D128 { STD_EXT, "_Decimal128", T_D128 }
 
+/* Structure describing how format attributes such as "printf" are
+   interpreted as "gnu_printf" or "ms_printf" on a particular system.
+   TARGET_OVERRIDES_FORMAT_ATTRIBUTES is used to specify target-specific
+   defaults.  */
+typedef struct
+{
+  /* The name of the to be copied format attribute. */
+  const char *named_attr_src;
+  /* The name of the to be overridden format attribute. */
+  const char *named_attr_dst;
+} target_ovr_attr;
+
 #endif /* GCC_C_FORMAT_H */
Index: gcc/gcc/config.gcc
===================================================================
--- gcc.orig/gcc/config.gcc
+++ gcc/gcc/config.gcc
@@ -1372,8 +1372,8 @@ i[34567]86-*-pe | i[34567]86-*-cygwin*)
 	target_gtfiles="\$(srcdir)/config/i386/winnt.c"
 	extra_options="${extra_options} i386/cygming.opt"
 	extra_objs="winnt.o winnt-stubs.o"
-	c_target_objs=cygwin2.o
-	cxx_target_objs="cygwin2.o winnt-cxx.o"
+	c_target_objs="cygwin2.o msformat-c.o"
+	cxx_target_objs="cygwin2.o winnt-cxx.o msformat-c.o"
 	extra_gcc_objs=cygwin1.o
 	if test x$enable_threads = xyes; then
 		thread_file='posix'
@@ -1386,7 +1386,8 @@ i[34567]86-*-mingw32* | x86_64-*-mingw32
 	target_gtfiles="\$(srcdir)/config/i386/winnt.c"
 	extra_options="${extra_options} i386/cygming.opt"
 	extra_objs="winnt.o winnt-stubs.o"
-	cxx_target_objs=winnt-cxx.o
+	c_target_objs="msformat-c.o"
+	cxx_target_objs="winnt-cxx.o msformat-c.o"
 	default_use_cxa_atexit=yes
 	case ${enable_threads} in
 	  "" | yes | win32)
Index: gcc/gcc/config/i386/mingw32.h
===================================================================
--- gcc.orig/gcc/config/i386/mingw32.h
+++ gcc/gcc/config/i386/mingw32.h
@@ -143,6 +143,23 @@ do {						         \
    to register C++ static destructors.  */
 #define TARGET_CXX_USE_ATEXIT_FOR_CXA_ATEXIT hook_bool_void_true
 
+/* Contains a pointer to type target_ovr_attr defining the target specific
+   overrides of format attributes.  See c-format.h for structure
+   definition.  */
+#undef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+#define TARGET_OVERRIDES_FORMAT_ATTRIBUTES mingw_format_attribute_overrides
+
+/* Specify the count of elements in TARGET_OVERRIDES_ATTRIBUTE.  */
+#undef TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT
+#define TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT 3
+
+/* MS specific format attributes for ms_printf, ms_scanf, ms_strftime.  */
+#undef TARGET_FORMAT_TYPES
+#define TARGET_FORMAT_TYPES mingw_format_attributes
+
+#undef TARGET_N_FORMAT_TYPES
+#define TARGET_N_FORMAT_TYPES 3
+
 /* JCR_SECTION works on mingw32.  */
 #undef TARGET_USE_JCR_SECTION
 #define TARGET_USE_JCR_SECTION 1
Index: gcc/gcc/config/i386/msformat-c.c
===================================================================
--- /dev/null
+++ gcc/gcc/config/i386/msformat-c.c
@@ -0,0 +1,176 @@
+/* Check calls to formatted I/O functions (-Wformat).
+   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+   2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "flags.h"
+#include "c-common.h"
+#include "toplev.h"
+#include "intl.h"
+#include "diagnostic.h"
+#include "langhooks.h"
+#include "c-format.h"
+#include "alloc-pool.h"
+
+/* Mingw specific format attributes ms_printf, ms_scanf, and ms_strftime.  */
+
+static const format_length_info ms_printf_length_specs[] =
+{
+  { "h", FMT_LEN_h, STD_C89, NULL, 0, 0 },
+  { "l", FMT_LEN_l, STD_C89, NULL, 0, 0 },
+  { "\0I32", FMT_LEN_l, STD_EXT, NULL, 0, 0 },
+  { "\0I64", FMT_LEN_ll, STD_EXT, NULL, 0, 0 },
+  { "I", FMT_LEN_L, STD_EXT, NULL, 0, 0 },
+  { NULL, 0, 0, NULL, 0, 0 }
+};
+
+static const format_flag_spec ms_printf_flag_specs[] =
+{
+  { ' ',  0, 0, N_("' ' flag"),        N_("the ' ' printf flag"),              STD_C89 },
+  { '+',  0, 0, N_("'+' flag"),        N_("the '+' printf flag"),              STD_C89 },
+  { '#',  0, 0, N_("'#' flag"),        N_("the '#' printf flag"),              STD_C89 },
+  { '0',  0, 0, N_("'0' flag"),        N_("the '0' printf flag"),              STD_C89 },
+  { '-',  0, 0, N_("'-' flag"),        N_("the '-' printf flag"),              STD_C89 },
+  { '\'', 0, 0, N_("''' flag"),        N_("the ''' printf flag"),              STD_EXT },
+  { 'w',  0, 0, N_("field width"),     N_("field width in printf format"),     STD_C89 },
+  { 'p',  0, 0, N_("precision"),       N_("precision in printf format"),       STD_C89 },
+  { 'L',  0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_printf_flag_pairs[] =
+{
+  { ' ', '+', 1, 0   },
+  { '0', '-', 1, 0   }, { '0', 'p', 1, 'i' },
+  { 0, 0, 0, 0 }
+};
+
+static const format_flag_spec ms_scanf_flag_specs[] =
+{
+  { '*',  0, 0, N_("assignment suppression"), N_("the assignment suppression scanf feature"), STD_C89 },
+  { 'a',  0, 0, N_("'a' flag"),               N_("the 'a' scanf flag"),                       STD_EXT },
+  { 'w',  0, 0, N_("field width"),            N_("field width in scanf format"),              STD_C89 },
+  { 'L',  0, 0, N_("length modifier"),        N_("length modifier in scanf format"),          STD_C89 },
+  { '\'', 0, 0, N_("''' flag"),               N_("the ''' scanf flag"),                       STD_EXT },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_scanf_flag_pairs[] =
+{
+  { '*', 'L', 0, 0 },
+  { 0, 0, 0, 0 }
+};
+
+static const format_flag_spec ms_strftime_flag_specs[] =
+{
+  { '#', 0,   0, N_("'#' flag"),     N_("the '#' strftime flag"),          STD_EXT },
+  { 'w', 0,   0, N_("field width"),  N_("field width in strftime format"), STD_EXT },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_strftime_flag_pairs[] =
+{
+  { 0, 0, 0, 0 }
+};
+
+static const format_char_info ms_print_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "di",  0, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  T99_SST,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-wp0 +'",  "i",  NULL },
+  { "oxX", 0, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN, BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "-wp0#",     "i",  NULL },
+  { "u",   0, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN, BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "-wp0'",    "i",  NULL },
+  { "fgG", 0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "-wp0 +#'", "",   NULL },
+  { "eE",  0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "-wp0 +#",  "",   NULL },
+  { "c",   0, STD_C89, { T89_I,   BADLEN,  T89_S,  T94_WI,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "",   NULL },
+  { "s",   1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-wp",       "cR", NULL },
+  { "p",   1, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "c",  NULL },
+  { "n",   1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  BADLEN,  BADLEN, BADLEN,  T99_IM,  BADLEN,  BADLEN,  BADLEN }, "",          "W",  NULL },
+  /* X/Open conversion specifiers.  */
+  { "C",   0, STD_EXT, { TEX_WI,  BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "",   NULL },
+  { "S",   1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-wp",       "R",  NULL },
+  { NULL,  0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+static const format_char_info ms_scan_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "di",    1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  T99_SST,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w'", "W",   NULL },
+  { "u",     1, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN,  BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "*w'", "W",   NULL },
+  { "oxX",   1, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN,  BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "efgEG", 1, STD_C89, { T89_F,   BADLEN,  BADLEN,  T89_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "*w'",  "W",   NULL },
+  { "c",     1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "cW",  NULL },
+  { "s",     1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "cW",  NULL },
+  { "[",     1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "cW[", NULL },
+  { "p",     2, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "n",     1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  BADLEN,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "",     "W",   NULL },
+  /* X/Open conversion specifiers.  */
+  { "C",     1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "S",     1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "W",   NULL },
+  { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+static const format_char_info ms_time_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "ABZab",		0, STD_C89, NOLENGTHS, "#",     "",   NULL },
+  { "cx",		0, STD_C89, NOLENGTHS, "",      "",  NULL },
+  { "HIMSUWdmw",	0, STD_C89, NOLENGTHS, "w",  "",   NULL },
+  { "j",		0, STD_C89, NOLENGTHS, "w",  "",  NULL },
+  { "p",		0, STD_C89, NOLENGTHS, "#",      "",   NULL },
+  { "X",		0, STD_C89, NOLENGTHS, "",      "",   NULL },
+  { "y",		0, STD_C89, NOLENGTHS, "w", "",  NULL },
+  { "Y",		0, STD_C89, NOLENGTHS, "w", "",  NULL },
+  { "%",		0, STD_C89, NOLENGTHS, "",       "",   NULL },
+  /* C99 conversion specifiers.  */
+  { "z",		0, STD_C99, NOLENGTHS, "",      "",  NULL },
+  { NULL,		0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+const format_kind_info mingw_format_attributes[3] =
+{
+  { "ms_printf",   ms_printf_length_specs,  ms_print_char_table, " +#0-'", NULL,
+    ms_printf_flag_specs, ms_printf_flag_pairs,
+    FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
+    'w', 0, 'p', 0, 'L', 0,
+    &integer_type_node, &integer_type_node
+  },
+  { "ms_scanf",    ms_printf_length_specs,   ms_scan_char_table,  "*'", NULL,
+    ms_scanf_flag_specs, ms_scanf_flag_pairs,
+    FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
+    'w', 0, 0, '*', 'L', 0,
+    NULL, NULL
+  },
+  { "ms_strftime", NULL,                 ms_time_char_table,  "#", "",
+    ms_strftime_flag_specs, ms_strftime_flag_pairs,
+    FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0, 0,
+    NULL, NULL
+  }
+};
+
+/* Default overrides for printf, scanf and strftime.  */
+const target_ovr_attr mingw_format_attribute_overrides[4] =
+{
+  { "ms_printf", "printf" },
+  { "ms_scanf", "scanf" },
+  { "ms_strftime", "strftime" }
+};
Index: gcc/gcc/config/i386/t-cygming
===================================================================
--- gcc.orig/gcc/config/i386/t-cygming
+++ gcc/gcc/config/i386/t-cygming
@@ -29,4 +29,10 @@ winnt-stubs.o: $(srcdir)/config/i386/win
 	$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
 	$(srcdir)/config/i386/winnt-stubs.c
 
+msformat-c.o: $(srcdir)/config/i386/msformat-c.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
+  $(TM_H) $(RTL_H) $(REGS_H) hard-reg-set.h output.h $(TREE_H) flags.h \
+  $(TM_P_H) toplev.h $(HASHTAB_H) $(GGC_H)
+	$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
+	$(srcdir)/config/i386/msformat-c.c
+
 STMP_FIXINC=stmp-fixinc
Index: gcc/gcc/doc/extend.texi
===================================================================
--- gcc.orig/gcc/doc/extend.texi
+++ gcc/gcc/doc/extend.texi
@@ -2204,13 +2204,22 @@ for consistency with the @code{printf} s
 @code{my_format}.
 
 The parameter @var{archetype} determines how the format string is
-interpreted, and should be @code{printf}, @code{scanf}, @code{strftime}
-or @code{strfmon}.  (You can also use @code{__printf__},
-@code{__scanf__}, @code{__strftime__} or @code{__strfmon__}.)  The
-parameter @var{string-index} specifies which argument is the format
-string argument (starting from 1), while @var{first-to-check} is the
-number of the first argument to check against the format string.  For
-functions where the arguments are not available to be checked (such as
+interpreted, and should be @code{printf}, @code{scanf}, @code{strftime},
+@code{gnu_printf}, @code{gnu_scanf}, @code{gnu_strftime} or
+@code{strfmon}.  (You can also use @code{__printf__},
+@code{__scanf__}, @code{__strftime__} or @code{__strfmon__}.)  On
+MinGW targets there is also @code{ms_printf}, @code{ms_scanf}, and
+@code{ms_strftime} present.
+@var{archtype} values such as @code{printf} refer to the formats accepted
+by the system's C run-time library, while @code{gnu_} values always refer
+to the formats accepted by the GNU C Library.  On Microsoft Windows
+targets, @code{ms_} values refer to the formats accepted by the
+@file{msvcrt.dll} library.
+The parameter @var{string-index}
+specifies which argument is the format string argument (starting
+from 1), while @var{first-to-check} is the number of the first
+argument to check against the format string.  For functions
+where the arguments are not available to be checked (such as
 @code{vprintf}), specify the third parameter as zero.  In this case the
 compiler only checks the format string for consistency.  For
 @code{strftime} formats, the third parameter is required to be zero.
Index: gcc/gcc/doc/tm.texi
===================================================================
--- gcc.orig/gcc/doc/tm.texi
+++ gcc/gcc/doc/tm.texi
@@ -10319,6 +10319,18 @@ If defined, this macro is the number of 
 @code{TARGET_FORMAT_TYPES}.
 @end defmac
 
+@defmac TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+If defined, this macro is the name of a global variable containg
+target-specific format overrides for the @option{-Wformat} option. The
+default is to have no target-specific format overrides. If defined,
+@code{TARGET_FORMAT_TYPES} must be defined too.
+@end defmac
+
+@defmac TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT
+If defined, this macro specifies the number of entries in
+@code{TARGET_OVERRIDES_FORMAT_ATTRIBUTES}.
+@end defmac
+
 @deftypefn {Target Hook} bool TARGET_RELAXED_ORDERING
 If set to @code{true}, means that the target's memory model does not
 guarantee that loads which do not depend on one another will access
Index: gcc/gcc/testsuite/gcc.dg/format/format.h
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/format.h
+++ gcc/gcc/testsuite/gcc.dg/format/format.h
@@ -1,6 +1,37 @@
 /* Format checking tests: common header.  */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
 
+/* DONT_GNU_PROTOTYPE */
+#if defined (_WIN32) && !defined (__CYGWIN__)
+#if !defined (USE_SYSTEM_FORMATS)
+#define gnu_attr_printf	gnu_printf
+#define gnu_attr___printf__ __gnu_printf__
+#define gnu_attr_scanf	gnu_scanf
+#define gnu_attr___scanf__ __gnu_scanf__
+#define gnu_attr_strftime gnu_strftime
+#define gnu_attr___strftime__ __gnu_strftime__
+#endif
+#endif
+
+#ifndef gnu_attr_printf
+#define gnu_attr_printf	printf
+#define gnu_attr___printf__ __printf__
+#define gnu_attr_scanf	scanf
+#define gnu_attr___scanf__ __scanf__
+#define gnu_attr_strftime strftime
+#define gnu_attr___strftime__ __strftime__
+#endif
+
+#if !defined (USE_SYSTEM_FORMATS)
+#define USE_PRINTF(FMTPOS, WILDARG) __attribute__((format(gnu_printf, FMTPOS, WILDARG))) __attribute__((nonnull (FMTPOS)))
+#define USE_SCANF(FMTPOS, WILDARG) __attribute__((format(gnu_scanf, FMTPOS, WILDARG))) __attribute__((nonnull (FMTPOS)))
+#define USE_STRFTIME(FMTPOS) __attribute__((__format__(gnu_strftime, FMTPOS, 0))) __attribute__((nonnull (FMTPOS)))
+#else
+#define USE_PRINTF(FMTPOS, WILDARG)
+#define USE_SCANF(FMTPOS, WILDARG)
+#define USE_STRFTIME(FMTPOS)
+#endif
+
 #include <stdarg.h>
 #include <stddef.h>
 
@@ -11,6 +42,20 @@
 typedef __WINT_TYPE__ wint_t;
 #endif
 
+#ifdef _WIN64
+/* Kludges to get types corresponding to size_t and ptrdiff_t.  */
+#define unsigned signed
+typedef signed int signed_size_t __attribute__ ((mode (DI)));
+/* We also use this type to approximate ssize_t.  */
+typedef signed int ssize_t __attribute__ ((mode (DI)));
+#undef unsigned
+#define signed /* Type might or might not have explicit 'signed'.  */
+typedef unsigned int unsigned_ptrdiff_t __attribute__ ((mode (DI)));
+#undef signed
+
+__extension__ typedef int llong  __attribute__ ((mode (DI)));
+__extension__ typedef unsigned int ullong  __attribute__ ((mode (DI)));
+#else
 /* Kludges to get types corresponding to size_t and ptrdiff_t.  */
 #define unsigned signed
 typedef __SIZE_TYPE__ signed_size_t;
@@ -23,6 +68,7 @@ typedef unsigned __PTRDIFF_TYPE__ unsign
 
 __extension__ typedef long long int llong;
 __extension__ typedef unsigned long long int ullong;
+#endif
 
 /* %q formats want a "quad"; GCC considers this to be a long long.  */
 typedef llong quad_t;
@@ -70,3 +116,77 @@ extern size_t strftime (char *restrict, 
 			const struct tm *restrict);
 
 extern ssize_t strfmon (char *restrict, size_t, const char *restrict, ...);
+
+/* Mingw specific part.  */
+#if !defined (USE_SYSTEM_FORMATS) && defined(_WIN32) && !defined(DONT_GNU_PROTOTYPE)
+
+extern USE_PRINTF(2,3) int fprintf_gnu (FILE *restrict, const char *restrict, ...);
+#undef fprintf
+#define fprintf fprintf_gnu
+
+extern USE_PRINTF(1,2) int printf_gnu (const char *restrict, ...);
+#undef printf
+#define printf printf_gnu
+
+extern USE_PRINTF(2,3) int fprintf_unlocked_gnu (FILE *restrict, const char *restrict, ...);
+#undef fprintf_unlocked
+#define fprintf_unlocked fprintf_unlocked_gnu
+
+extern USE_PRINTF(1,2)int printf_unlocked_gnu (const char *restrict, ...);
+#undef printf_unlocked
+#define printf_unlocked printf_unlocked_gnu
+
+extern USE_PRINTF(2,3) int sprintf_gnu (char *restrict, const char *restrict, ...);
+#undef sprintf
+#define sprintf sprintf_gnu
+
+extern USE_PRINTF(2,0) int vfprintf_gnu (FILE *restrict, const char *restrict, va_list);
+#undef vsprintf
+#define vsprintf vsprintf_gnu
+
+extern USE_PRINTF(1,0) int vprintf_gnu (const char *restrict, va_list);
+#undef vprintf
+#define vprintf vprintf_gnu
+
+extern USE_PRINTF(2,0) int vsprintf_gnu (char *restrict, const char *restrict, va_list);
+#undef vsprintf
+#define vsprintf vsprintf_gnu
+
+extern USE_PRINTF(3,4) int snprintf_gnu (char *restrict, size_t, const char *restrict, ...);
+#undef snprintf
+#define snprintf snprintf_gnu
+
+extern USE_PRINTF(3,0) int vsnprintf_gnu (char *restrict, size_t, const char *restrict, va_list);
+#undef vsnprintf
+#define vsnprintf vsnprintf_gnu
+
+extern USE_SCANF(2,3) int fscanf_gnu (FILE *restrict, const char *restrict, ...);
+#undef fscanf
+#define fscanf fscanf_gnu
+
+extern USE_SCANF(1,2) int scanf_gnu (const char *restrict, ...);
+#undef scanf
+#define scanf scanf_gnu
+
+extern USE_SCANF(2,3) int sscanf_gnu (const char *restrict, const char *restrict, ...);
+#undef sscanf
+#define sscanf sscanf_gnu
+
+extern USE_SCANF(2,0) int vfscanf_gnu (FILE *restrict, const char *restrict, va_list);
+#undef vfscanf
+#define vfscanf vfscanf_gnu
+
+extern USE_SCANF(1,0) int vscanf_gnu (const char *restrict, va_list);
+#undef vscanf
+#define vscanf vscanf_gnu
+
+extern USE_SCANF(2,0) int vsscanf_gnu (const char *restrict, const char *restrict, va_list);
+#undef vsscanf
+#define vsscanf vsscanf_gnu
+
+extern USE_STRFTIME(3) size_t strftime_gnu (char *restrict, size_t, const char *restrict,
+			const struct tm *restrict);
+#undef strftime
+#define strftime strftime_gnu
+
+#endif
Index: gcc/gcc/testsuite/gcc.dg/format/attr-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-1.c
@@ -3,7 +3,8 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern void foo0 (const char *) __attribute__((__format__(__strftime__, 1, 0)));
-extern void foo1 (const char *, ...) __attribute__((__format__(__strftime__, 1, 2))); /* { dg-error "cannot format" "strftime first_arg_num != 0" } */
+extern void foo0 (const char *) __attribute__((__format__(gnu_attr___strftime__, 1, 0)));
+extern void foo1 (const char *, ...) __attribute__((__format__(gnu_attr___strftime__, 1, 2))); /* { dg-error "cannot format" "strftime first_arg_num != 0" } */
Index: gcc/gcc/testsuite/gcc.dg/format/attr-2.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-2.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-2.c
@@ -3,22 +3,23 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern void tformatprintf (const char *, ...) __attribute__((format(printf, 1, 2)));
-extern void tformat__printf__ (const char *, ...) __attribute__((format(__printf__, 1, 2)));
-extern void tformatscanf (const char *, ...) __attribute__((format(scanf, 1, 2)));
-extern void tformat__scanf__ (const char *, ...) __attribute__((format(__scanf__, 1, 2)));
-extern void tformatstrftime (const char *) __attribute__((format(strftime, 1, 0)));
-extern void tformat__strftime__ (const char *) __attribute__((format(__strftime__, 1, 0)));
+extern void tformatprintf (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
+extern void tformat__printf__ (const char *, ...) __attribute__((format(gnu_attr___printf__, 1, 2)));
+extern void tformatscanf (const char *, ...) __attribute__((format(gnu_attr_scanf, 1, 2)));
+extern void tformat__scanf__ (const char *, ...) __attribute__((format(gnu_attr___scanf__, 1, 2)));
+extern void tformatstrftime (const char *) __attribute__((format(gnu_attr_strftime, 1, 0)));
+extern void tformat__strftime__ (const char *) __attribute__((format(gnu_attr___strftime__, 1, 0)));
 extern void tformatstrfmon (const char *, ...) __attribute__((format(strfmon, 1, 2)));
 extern void tformat__strfmon__ (const char *, ...) __attribute__((format(__strfmon__, 1, 2)));
-extern void t__format__printf (const char *, ...) __attribute__((__format__(printf, 1, 2)));
-extern void t__format____printf__ (const char *, ...) __attribute__((__format__(__printf__, 1, 2)));
-extern void t__format__scanf (const char *, ...) __attribute__((__format__(scanf, 1, 2)));
-extern void t__format____scanf__ (const char *, ...) __attribute__((__format__(__scanf__, 1, 2)));
-extern void t__format__strftime (const char *) __attribute__((__format__(strftime, 1, 0)));
-extern void t__format____strftime__ (const char *) __attribute__((__format__(__strftime__, 1, 0)));
+extern void t__format__printf (const char *, ...) __attribute__((__format__(gnu_attr_printf, 1, 2)));
+extern void t__format____printf__ (const char *, ...) __attribute__((__format__(gnu_attr___printf__, 1, 2)));
+extern void t__format__scanf (const char *, ...) __attribute__((__format__(gnu_attr_scanf, 1, 2)));
+extern void t__format____scanf__ (const char *, ...) __attribute__((__format__(gnu_attr___scanf__, 1, 2)));
+extern void t__format__strftime (const char *) __attribute__((__format__(gnu_attr_strftime, 1, 0)));
+extern void t__format____strftime__ (const char *) __attribute__((__format__(gnu_attr___strftime__, 1, 0)));
 extern void t__format__strfmon (const char *, ...) __attribute__((__format__(strfmon, 1, 2)));
 extern void t__format____strfmon__ (const char *, ...) __attribute__((__format__(__strfmon__, 1, 2)));
 
Index: gcc/gcc/testsuite/gcc.dg/format/attr-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-3.c
@@ -3,20 +3,21 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 /* Proper uses of the attributes.  */
-extern void fa0 (const char *, ...) __attribute__((format(printf, 1, 2)));
-extern void fa1 (char *, ...) __attribute__((format(printf, 1, 2)));
+extern void fa0 (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
+extern void fa1 (char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
 extern char *fa2 (const char *) __attribute__((format_arg(1)));
 extern char *fa3 (char *) __attribute__((format_arg(1)));
 
 /* Uses with too few or too many arguments.  */
 extern void fb0 (const char *, ...) __attribute__((format)); /* { dg-error "wrong number of arguments" "bad format" } */
 extern void fb1 (const char *, ...) __attribute__((format())); /* { dg-error "wrong number of arguments" "bad format" } */
-extern void fb2 (const char *, ...) __attribute__((format(printf))); /* { dg-error "wrong number of arguments" "bad format" } */
-extern void fb3 (const char *, ...) __attribute__((format(printf, 1))); /* { dg-error "wrong number of arguments" "bad format" } */
-extern void fb4 (const char *, ...) __attribute__((format(printf, 1, 2, 3))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb2 (const char *, ...) __attribute__((format(gnu_attr_printf))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb3 (const char *, ...) __attribute__((format(gnu_attr_printf, 1))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb4 (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2, 3))); /* { dg-error "wrong number of arguments" "bad format" } */
 
 extern void fc1 (const char *) __attribute__((format_arg)); /* { dg-error "wrong number of arguments" "bad format_arg" } */
 extern void fc2 (const char *) __attribute__((format_arg())); /* { dg-error "wrong number of arguments" "bad format_arg" } */
@@ -25,9 +26,9 @@ extern void fc3 (const char *) __attribu
 /* These attributes presently only apply to declarations, not to types.
    Eventually, they should be usable with declarators for function types
    anywhere, but still not with structure/union/enum types.  */
-struct s0 { int i; } __attribute__((format(printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on struct" } */
-union u0 { int i; } __attribute__((format(printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on union" } */
-enum e0 { E0V0 } __attribute__((format(printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on enum" } */
+struct s0 { int i; } __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on struct" } */
+union u0 { int i; } __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on union" } */
+enum e0 { E0V0 } __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on enum" } */
 
 struct s1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on struct" } */
 union u1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on union" } */
@@ -38,28 +39,28 @@ extern void fe0 (const char *, ...) __at
 extern void fe1 (const char *, ...) __attribute__((format(nosuch, 1, 2))); /* { dg-warning "format function type" "unknown format" } */
 
 /* Both the numbers must be integer constant expressions.  */
-extern void ff0 (const char *, ...) __attribute__((format(printf, 3-2, (long long)(10/5))));
+extern void ff0 (const char *, ...) __attribute__((format(gnu_attr_printf, 3-2, (long long)(10/5))));
 int foo;
-extern void ff1 (const char *, ...) __attribute__((format(printf, foo, 10/5))); /* { dg-error "invalid operand" "bad number" } */
-extern void ff2 (const char *, ...) __attribute__((format(printf, 3-2, foo))); /* { dg-error "invalid operand" "bad number" } */
+extern void ff1 (const char *, ...) __attribute__((format(gnu_attr_printf, foo, 10/5))); /* { dg-error "invalid operand" "bad number" } */
+extern void ff2 (const char *, ...) __attribute__((format(gnu_attr_printf, 3-2, foo))); /* { dg-error "invalid operand" "bad number" } */
 extern char *ff3 (const char *) __attribute__((format_arg(3-2)));
 extern char *ff4 (const char *) __attribute__((format_arg(foo))); /* { dg-error "invalid operand" "bad format_arg number" } */
 
 /* The format string argument must precede the arguments to be formatted.
    This includes if no parameter types are specified (which is not valid ISO
    C for variadic functions).  */
-extern void fg0 () __attribute__((format(printf, 1, 2)));
-extern void fg1 () __attribute__((format(printf, 1, 0)));
-extern void fg2 () __attribute__((format(printf, 1, 1))); /* { dg-error "follows" "bad number order" } */
-extern void fg3 () __attribute__((format(printf, 2, 1))); /* { dg-error "follows" "bad number order" } */
+extern void fg0 () __attribute__((format(gnu_attr_printf, 1, 2)));
+extern void fg1 () __attribute__((format(gnu_attr_printf, 1, 0)));
+extern void fg2 () __attribute__((format(gnu_attr_printf, 1, 1))); /* { dg-error "follows" "bad number order" } */
+extern void fg3 () __attribute__((format(gnu_attr_printf, 2, 1))); /* { dg-error "follows" "bad number order" } */
 
 /* The format string argument must be a string type, and the arguments to
    be formatted must be the "...".  */
-extern void fh0 (int, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "not a string" "format int string" } */
-extern void fh1 (signed char *, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "not a string" "signed char string" } */
-extern void fh2 (unsigned char *, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "not a string" "unsigned char string" } */
-extern void fh3 (const char *, ...) __attribute__((format(printf, 1, 3))); /* { dg-error "is not" "not ..." } */
-extern void fh4 (const char *, int, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "is not" "not ..." } */
+extern void fh0 (int, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "format int string" } */
+extern void fh1 (signed char *, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "signed char string" } */
+extern void fh2 (unsigned char *, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "unsigned char string" } */
+extern void fh3 (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 3))); /* { dg-error "is not" "not ..." } */
+extern void fh4 (const char *, int, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "is not" "not ..." } */
 
 /* format_arg formats must take and return a string.  */
 extern char *fi0 (int) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg int string" } */
Index: gcc/gcc/testsuite/gcc.dg/format/attr-4.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-4.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-4.c
@@ -4,12 +4,13 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern __attribute__((format(printf, 1, 2))) void tformatprintf0 (const char *, ...);
-extern void __attribute__((format(printf, 1, 2))) tformatprintf1 (const char *, ...);
-extern void foo (void), __attribute__((format(printf, 1, 2))) tformatprintf2 (const char *, ...);
-extern __attribute__((noreturn)) void bar (void), __attribute__((format(printf, 1, 2))) tformatprintf3 (const char *, ...);
+extern __attribute__((format(gnu_attr_printf, 1, 2))) void tformatprintf0 (const char *, ...);
+extern void __attribute__((format(gnu_attr_printf, 1, 2))) tformatprintf1 (const char *, ...);
+extern void foo (void), __attribute__((format(gnu_attr_printf, 1, 2))) tformatprintf2 (const char *, ...);
+extern __attribute__((noreturn)) void bar (void), __attribute__((format(gnu_attr_printf, 1, 2))) tformatprintf3 (const char *, ...);
 
 void
 baz (int i, int *ip, double d)
Index: gcc/gcc/testsuite/gcc.dg/format/attr-7.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-7.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-7.c
@@ -3,12 +3,13 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-__attribute__((format(printf, 1, 2))) void (*tformatprintf0) (const char *, ...);
-void (*tformatprintf1) (const char *, ...) __attribute__((format(printf, 1, 2)));
-void (__attribute__((format(printf, 1, 2))) *tformatprintf2) (const char *, ...);
-void (__attribute__((format(printf, 1, 2))) ****tformatprintf3) (const char *, ...);
+__attribute__((format(gnu_attr_printf, 1, 2))) void (*tformatprintf0) (const char *, ...);
+void (*tformatprintf1) (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
+void (__attribute__((format(gnu_attr_printf, 1, 2))) *tformatprintf2) (const char *, ...);
+void (__attribute__((format(gnu_attr_printf, 1, 2))) ****tformatprintf3) (const char *, ...);
 
 char * (__attribute__((format_arg(1))) *tformat_arg) (const char *);
 
Index: gcc/gcc/testsuite/gcc.dg/format/c90-printf-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/c90-printf-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/c90-printf-3.c
@@ -3,7 +3,7 @@
    do not.
 */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
-/* { dg-do compile } */
+/* { dg-do compile { target { ! *-*-mingw* } } } */
 /* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
 
 #include "format.h"
Index: gcc/gcc/testsuite/gcc.dg/format/c90-scanf-4.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/c90-scanf-4.c
+++ gcc/gcc/testsuite/gcc.dg/format/c90-scanf-4.c
@@ -3,7 +3,7 @@
    do not.
 */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
-/* { dg-do compile } */
+/* { dg-do compile { target { ! *-*-mingw* } } } */
 /* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
 
 #include "format.h"
Index: gcc/gcc/testsuite/gcc.dg/format/c99-printf-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/c99-printf-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/c99-printf-3.c
@@ -2,7 +2,7 @@
    attributes in strict C99 mode, but the gettext functions do not.
 */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
-/* { dg-do compile } */
+/* { dg-do compile { target { ! *-*-mingw* } } } */
 /* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
 
 #include "format.h"
Index: gcc/gcc/testsuite/gcc.dg/format/miss-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-1.c
@@ -23,7 +23,7 @@ bar (const char *fmt, ...)
   va_end (ap);
 }
 
-__attribute__((__format__(__printf__, 1, 2))) void
+__attribute__((__format__(gnu_attr___printf__, 1, 2))) void
 foo2 (const char *fmt, ...)
 {
   va_list ap;
Index: gcc/gcc/testsuite/gcc.dg/format/miss-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-3.c
@@ -3,13 +3,14 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 void
 foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
@@ -18,7 +19,7 @@ foo1 (noattr_t na, attr_t a, vnoattr_t v
   noattr_t na2 = a; /* { dg-warning "candidate" "initialization warning" } */
   attr_t a1 = na;
   attr_t a2 = a;
-  
+
   vnoattr_t vna1 = vna;
   vnoattr_t vna2 = va; /* { dg-warning "candidate" "initialization warning" } */
   vattr_t va1 = vna;
Index: gcc/gcc/testsuite/gcc.dg/format/miss-4.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-4.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-4.c
@@ -3,20 +3,21 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 void
 foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
 {
   noattr_t na1, na2;
   attr_t a1, a2;
-  
+
   vnoattr_t vna1, vna2;
   vattr_t va1, va2;
 
@@ -24,7 +25,7 @@ foo1 (noattr_t na, attr_t a, vnoattr_t v
   na2 = a; /* { dg-warning "candidate" "assignment warning" } */
   a1 = na;
   a2 = a;
-  
+
   vna1 = vna;
   vna2 = va; /* { dg-warning "candidate" "assignment warning" } */
   va1 = vna;
Index: gcc/gcc/testsuite/gcc.dg/format/miss-5.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-5.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-5.c
@@ -3,13 +3,14 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 noattr_t
 foo1 (noattr_t na, attr_t a, int i)
Index: gcc/gcc/testsuite/gcc.dg/format/miss-6.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-6.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-6.c
@@ -3,13 +3,14 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 extern void foo1 (noattr_t);
 extern void foo2 (attr_t);
@@ -23,7 +24,7 @@ foo (noattr_t na, attr_t a, vnoattr_t vn
   foo1 (a); /* { dg-warning "candidate" "parameter passing warning" } */
   foo2 (na);
   foo2 (a);
-  
+
   foo3 (vna);
   foo3 (va); /* { dg-warning "candidate" "parameter passing warning" } */
   foo4 (vna);
Index: gcc/gcc/testsuite/gcc.dg/format/ms_array-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_array-1.c
@@ -0,0 +1,42 @@
+/* Test for format checking of constant arrays.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat=2" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+const char a1[] = "foo";
+const char a2[] = "foo%d";
+const char b1[3] = "foo";
+const char b2[1] = "1";
+static const char c1[] = "foo";
+static const char c2[] = "foo%d";
+char d[] = "foo";
+volatile const char e[] = "foo";
+
+void
+foo (int i, long l)
+{
+  const char p1[] = "bar";
+  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 (c1);
+  printf (c2, i);
+  printf (c2, l); /* { dg-warning "format" "wrong type with array" } */
+  printf (p1);
+  printf (p2, i);
+  printf (p2, l); /* { dg-warning "format" "wrong type with array" } */
+  printf (q1);
+  printf (q2, i);
+  printf (q2, l); /* { dg-warning "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" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-1.c
@@ -0,0 +1,10 @@
+/* Test for strftime format attributes: can't have first_arg_num != 0.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define DONT_GNU_PROTOTYPE
+#include "format.h"
+
+extern void foo0 (const char *) __attribute__((__format__(__ms_strftime__, 1, 0)));
+extern void foo1 (const char *, ...) __attribute__((__format__(__ms_strftime__, 1, 2))); /* { dg-error "cannot format" "strftime first_arg_num != 0" } */
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-2.c
@@ -0,0 +1,68 @@
+/* Test for format attributes: test use of __attribute__.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define DONT_GNU_PROTOTYPE
+#include "format.h"
+
+extern void tformatprintf (const char *, ...) __attribute__((format(ms_printf, 1, 2)));
+extern void tformat__printf__ (const char *, ...) __attribute__((format(__ms_printf__, 1, 2)));
+extern void tformatscanf (const char *, ...) __attribute__((format(ms_scanf, 1, 2)));
+extern void tformat__scanf__ (const char *, ...) __attribute__((format(__ms_scanf__, 1, 2)));
+extern void tformatstrftime (const char *) __attribute__((format(ms_strftime, 1, 0)));
+extern void tformat__strftime__ (const char *) __attribute__((format(__ms_strftime__, 1, 0)));
+extern void tformatstrfmon (const char *, ...) __attribute__((format(strfmon, 1, 2)));
+extern void tformat__strfmon__ (const char *, ...) __attribute__((format(__strfmon__, 1, 2)));
+extern void t__format__printf (const char *, ...) __attribute__((__format__(ms_printf, 1, 2)));
+extern void t__format____printf__ (const char *, ...) __attribute__((__format__(__ms_printf__, 1, 2)));
+extern void t__format__scanf (const char *, ...) __attribute__((__format__(ms_scanf, 1, 2)));
+extern void t__format____scanf__ (const char *, ...) __attribute__((__format__(__ms_scanf__, 1, 2)));
+extern void t__format__strftime (const char *) __attribute__((__format__(ms_strftime, 1, 0)));
+extern void t__format____strftime__ (const char *) __attribute__((__format__(__ms_strftime__, 1, 0)));
+extern void t__format__strfmon (const char *, ...) __attribute__((__format__(strfmon, 1, 2)));
+extern void t__format____strfmon__ (const char *, ...) __attribute__((__format__(__strfmon__, 1, 2)));
+
+extern char *tformat_arg (const char *) __attribute__((format_arg(1)));
+extern char *t__format_arg__ (const char *) __attribute__((__format_arg__(1)));
+
+void
+foo (int i, int *ip, double d)
+{
+  tformatprintf ("%d", i);
+  tformatprintf ("%"); /* { dg-warning "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);
+  tformat__scanf__ ("%"); /* { dg-warning "format" "attribute format __scanf__" } */
+  tformatstrftime ("%a");
+  tformatstrftime ("%"); /* { dg-warning "format" "attribute format strftime" } */
+  tformat__strftime__ ("%a");
+  tformat__strftime__ ("%"); /* { dg-warning "format" "attribute format __strftime__" } */
+  tformatstrfmon ("%n", d);
+  tformatstrfmon ("%"); /* { dg-warning "format" "attribute format strfmon" } */
+  tformat__strfmon__ ("%n", d);
+  tformat__strfmon__ ("%"); /* { dg-warning "format" "attribute format __strfmon__" } */
+  t__format__printf ("%d", i);
+  t__format__printf ("%"); /* { dg-warning "format" "attribute __format__ printf" } */
+  t__format____printf__ ("%d", i);
+  t__format____printf__ ("%"); /* { dg-warning "format" "attribute __format__ __printf__" } */
+  t__format__scanf ("%d", ip);
+  t__format__scanf ("%"); /* { dg-warning "format" "attribute __format__ scanf" } */
+  t__format____scanf__ ("%d", ip);
+  t__format____scanf__ ("%"); /* { dg-warning "format" "attribute __format__ __scanf__" } */
+  t__format__strftime ("%a");
+  t__format__strftime ("%"); /* { dg-warning "format" "attribute __format__ strftime" } */
+  t__format____strftime__ ("%a");
+  t__format____strftime__ ("%"); /* { dg-warning "format" "attribute __format__ __strftime__" } */
+  t__format__strfmon ("%n", d);
+  t__format__strfmon ("%"); /* { dg-warning "format" "attribute __format__ strfmon" } */
+  t__format____strfmon__ ("%n", d);
+  t__format____strfmon__ ("%"); /* { dg-warning "format" "attribute __format__ __strfmon__" } */
+  tformatprintf (tformat_arg ("%d"), i);
+  tformatprintf (tformat_arg ("%")); /* { dg-warning "format" "attribute format_arg" } */
+  tformatprintf (t__format_arg__ ("%d"), i);
+  tformatprintf (t__format_arg__ ("%")); /* { dg-warning "format" "attribute __format_arg__" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-3.c
@@ -0,0 +1,71 @@
+/* Test for format attributes: test bad uses of __attribute__.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* Proper uses of the attributes.  */
+extern void fa0 (const char *, ...) __attribute__((format(ms_printf, 1, 2)));
+extern void fa1 (char *, ...) __attribute__((format(ms_printf, 1, 2)));
+extern char *fa2 (const char *) __attribute__((format_arg(1)));
+extern char *fa3 (char *) __attribute__((format_arg(1)));
+
+/* Uses with too few or too many arguments.  */
+extern void fb0 (const char *, ...) __attribute__((format)); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb1 (const char *, ...) __attribute__((format())); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb2 (const char *, ...) __attribute__((format(ms_printf))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb3 (const char *, ...) __attribute__((format(ms_printf, 1))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb4 (const char *, ...) __attribute__((format(ms_printf, 1, 2, 3))); /* { dg-error "wrong number of arguments" "bad format" } */
+
+extern void fc1 (const char *) __attribute__((format_arg)); /* { dg-error "wrong number of arguments" "bad format_arg" } */
+extern void fc2 (const char *) __attribute__((format_arg())); /* { dg-error "wrong number of arguments" "bad format_arg" } */
+extern void fc3 (const char *) __attribute__((format_arg(1, 2))); /* { dg-error "wrong number of arguments" "bad format_arg" } */
+
+/* These attributes presently only apply to declarations, not to types.
+   Eventually, they should be usable with declarators for function types
+   anywhere, but still not with structure/union/enum types.  */
+struct s0 { int i; } __attribute__((format(ms_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on struct" } */
+union u0 { int i; } __attribute__((format(ms_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on union" } */
+enum e0 { E0V0 } __attribute__((format(ms_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on enum" } */
+
+struct s1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on struct" } */
+union u1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on union" } */
+enum e1 { E1V0 } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on enum" } */
+
+/* The format type must be an identifier, one of those recognized.  */
+extern void fe0 (const char *, ...) __attribute__((format(12345, 1, 2))); /* { dg-error "format specifier" "non-id format" } */
+extern void fe1 (const char *, ...) __attribute__((format(nosuch, 1, 2))); /* { dg-warning "format function type" "unknown format" } */
+
+/* Both the numbers must be integer constant expressions.  */
+extern void ff0 (const char *, ...) __attribute__((format(ms_printf, 3-2, (long long)(10/5))));
+int foo;
+extern void ff1 (const char *, ...) __attribute__((format(ms_printf, foo, 10/5))); /* { dg-error "invalid operand" "bad number" } */
+extern void ff2 (const char *, ...) __attribute__((format(ms_printf, 3-2, foo))); /* { dg-error "invalid operand" "bad number" } */
+extern char *ff3 (const char *) __attribute__((format_arg(3-2)));
+extern char *ff4 (const char *) __attribute__((format_arg(foo))); /* { dg-error "invalid operand" "bad format_arg number" } */
+
+/* The format string argument must precede the arguments to be formatted.
+   This includes if no parameter types are specified (which is not valid ISO
+   C for variadic functions).  */
+extern void fg0 () __attribute__((format(ms_printf, 1, 2)));
+extern void fg1 () __attribute__((format(ms_printf, 1, 0)));
+extern void fg2 () __attribute__((format(ms_printf, 1, 1))); /* { dg-error "follows" "bad number order" } */
+extern void fg3 () __attribute__((format(ms_printf, 2, 1))); /* { dg-error "follows" "bad number order" } */
+
+/* The format string argument must be a string type, and the arguments to
+   be formatted must be the "...".  */
+extern void fh0 (int, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "not a string" "format int string" } */
+extern void fh1 (signed char *, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "not a string" "signed char string" } */
+extern void fh2 (unsigned char *, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "not a string" "unsigned char string" } */
+extern void fh3 (const char *, ...) __attribute__((format(ms_printf, 1, 3))); /* { dg-error "is not" "not ..." } */
+extern void fh4 (const char *, int, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "is not" "not ..." } */
+
+/* format_arg formats must take and return a string.  */
+extern char *fi0 (int) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg int string" } */
+extern char *fi1 (signed char *) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg signed char string" } */
+extern char *fi2 (unsigned char *) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg unsigned char string" } */
+extern int fi3 (const char *) __attribute__((format_arg(1))); /* { dg-error "not return string" "format_arg ret int string" } */
+extern signed char *fi4 (const char *) __attribute__((format_arg(1))); /* { dg-error "not return string" "format_arg ret signed char string" } */
+extern unsigned char *fi5 (const char *) __attribute__((format_arg(1))); /* { dg-error "not return string" "format_arg ret unsigned char string" } */
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-4.c
@@ -0,0 +1,26 @@
+/* Test for format attributes: test use of __attribute__
+   in prefix attributes.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+extern __attribute__((format(ms_printf, 1, 2))) void tformatprintf0 (const char *, ...);
+extern void __attribute__((format(ms_printf, 1, 2))) tformatprintf1 (const char *, ...);
+extern void foo (void), __attribute__((format(ms_printf, 1, 2))) tformatprintf2 (const char *, ...);
+extern __attribute__((noreturn)) void bar (void), __attribute__((format(ms_printf, 1, 2))) tformatprintf3 (const char *, ...);
+
+void
+baz (int i, int *ip, double d)
+{
+  tformatprintf0 ("%d", i);
+  tformatprintf0 ("%"); /* { dg-warning "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);
+  tformatprintf3 ("%"); /* { dg-warning "format" "attribute format printf case 3" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-7.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-7.c
@@ -0,0 +1,35 @@
+/* Test for format attributes: test applying them to types.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define DONT_GNU_PROTOTYPE
+#include "format.h"
+
+__attribute__((format(ms_printf, 1, 2))) void (*tformatprintf0) (const char *, ...);
+void (*tformatprintf1) (const char *, ...) __attribute__((format(ms_printf, 1, 2)));
+void (__attribute__((format(ms_printf, 1, 2))) *tformatprintf2) (const char *, ...);
+void (__attribute__((format(ms_printf, 1, 2))) ****tformatprintf3) (const char *, ...);
+
+char * (__attribute__((format_arg(1))) *tformat_arg) (const char *);
+
+void
+baz (int i)
+{
+  (*tformatprintf0) ("%d", i);
+  (*tformatprintf0) ((*tformat_arg) ("%d"), i);
+  (*tformatprintf0) ("%"); /* { dg-warning "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" } */
+  (*tformatprintf2) ("%d", i);
+  (*tformatprintf2) ((*tformat_arg) ("%d"), i);
+  (*tformatprintf2) ("%"); /* { dg-warning "format" "nested" } */
+  (*tformatprintf2) ((*tformat_arg) ("%")); /* { dg-warning "format" "nested" } */
+  (****tformatprintf3) ("%d", i);
+  (****tformatprintf3) ((*tformat_arg) ("%d"), i);
+  (****tformatprintf3) ("%"); /* { dg-warning "format" "nested 2" } */
+  (****tformatprintf3) ((*tformat_arg) ("%")); /* { dg-warning "format" "nested 2" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_bitfld-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_bitfld-1.c
@@ -0,0 +1,52 @@
+/* Test for printf formats and bit-fields: bug 22421.  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+/* { dg-require-effective-target int32plus } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+struct s {
+  unsigned int u1 : 1;
+  signed int s1 : 1;
+  unsigned int u15 : 15;
+  signed int s15 : 15;
+  unsigned int u16 : 16;
+  signed int s16 : 16;
+  unsigned long u31 : 31;
+  signed long s31 : 31;
+  unsigned long u32 : 32;
+  signed long s32 : 32;
+  unsigned long long u48 : 48;
+} x;
+
+void
+foo (void)
+{
+  printf ("%d%u", x.u1, x.u1);
+  printf ("%d%u", x.s1, x.s1);
+  printf ("%d%u", x.u15, x.u15);
+  printf ("%d%u", x.s15, x.s15);
+  printf ("%d%u", x.u16, x.u16);
+  printf ("%d%u", x.s16, x.s16);
+#if __INT_MAX__ > 32767
+  /* If integers are 16 bits, there doesn't seem to be a way of
+     printing these without getting an error.  */
+  printf ("%d%u", x.u31, x.u31);
+  printf ("%d%u", x.s31, x.s31);
+#endif
+#if __LONG_MAX__ > 2147483647 && __INT_MAX__ >= 2147483647
+  /* If long is wider than 32 bits, the 32-bit bit-fields are int or
+     unsigned int or promote to those types.  Otherwise, long is 32
+     bits and the bit-fields are of type plain long or unsigned
+     long.  */
+  printf ("%d%u", x.u32, x.u32);
+  printf ("%d%u", x.s32, x.s32);
+#else
+  printf ("%ld%lu", x.u32, x.u32);
+  printf ("%ld%lu", x.s32, x.s32);
+#endif
+  printf ("%I64u", x.u48); /* { dg-warning "has type '.*unsigned int:48'" } */
+  printf ("%I64u", (unsigned long long)x.u48);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_branch-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_branch-1.c
@@ -0,0 +1,28 @@
+/* Test for format checking of conditional expressions.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+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" } */
+  /* 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) ? "%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" } */
+  /* 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 *-*-* } 26 } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-1.c
@@ -0,0 +1,184 @@
+/* Test for printf formats.  Formats using C90 features, including cases
+   where C90 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, int i1, int i2, unsigned int u, double d, char *s, void *p,
+     int *n, short int *hn, long int l, unsigned long int ul,
+     long int *ln, long double ld, wint_t lc, wchar_t *ls, llong ll,
+     ullong ull, unsigned int *un, const int *cn, signed char *ss,
+     unsigned char *us, const signed char *css, unsigned int u1,
+     unsigned int u2)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.1 (pages 131-134).  */
+  /* Basic sanity checks for the different components of a format.  */
+  printf ("%d\n", i);
+  printf ("%+d\n", i);
+  printf ("%3d\n", i);
+  printf ("%-3d\n", i);
+  printf ("%*d\n", i1, i);
+  printf ("%d %lu\n", i, ul);
+  /* Bogus use of width.  */
+  printf ("%5n\n", n); /* { dg-warning "width" "width 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 ("%-%"); /* { dg-warning "format" "bogus %%" } */
+  printf ("%-%\n"); /* { dg-warning "format" "bogus %%" } */
+  printf ("%5%\n"); /* { dg-warning "format" "bogus %%" } */
+  printf ("%h%\n"); /* { dg-warning "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
+     differences in format checking here, and this is relied on to get the
+     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);
+  printf ("%hs", hn);
+  printf ("%hp", p); /* { dg-warning "length" "bad use of %h" } */
+  printf ("%h"); /* { dg-warning "conversion lacks type" "bare %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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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% 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* Various tests of bad argument types.  */
+  printf ("%d", l); /* { dg-warning "format" "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" } */
+  /* 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
+     discussion of the requirements of rules on identical representation,
+     and of the application of the as if rule with the new va_arg
+     allowances in C99 to printf.)  Likewise, we should warn if
+     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" } */
+  /* 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" } */
+  /* The historical behavior is to allow signed / unsigned types
+     interchangably as arguments.  For values representable in both types,
+     such usage may be correct.  For now preserve the behavior of GCC
+     in such cases.
+  */
+  printf ("%d", u);
+  /* Wrong number of arguments.  */
+  printf ("%d%d", i); /* { dg-warning "arguments" "wrong number of args" } */
+  printf ("%d", i, i); /* { dg-warning "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" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-2.c
@@ -0,0 +1,25 @@
+/* Test for printf formats.  Formats using C99 features should be rejected
+   outside of C99 mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, double d, llong ll, intmax_t j, size_t z, ptrdiff_t t)
+{
+  /* Some tests already in c90-printf-1.c, e.g. %lf.  */
+  /* The widths hh, ll, j, z, t are new.  */
+  printf ("%hhd", i); /* { dg-warning "unknown|format" "%hh is unsupported" } */
+  printf ("%I64d", ll); /* { dg-warning "length|C" "%I64 in C90" } */
+  printf ("%jd", j); /* { dg-warning "unknown|format" "%j is unsupported" } */
+  printf ("%zu", z); /* { dg-warning "unknown|format" "%z is unsupported" } */
+  printf ("%td", t); /* { dg-warning "unknown|format" "%t is unsupported" } */
+  /* The formats F, a, A are new.  */
+  printf ("%F", d); /* { dg-warning "unknown|format" "%F is unsupported" } */
+  printf ("%a", d); /* { dg-warning "unknown|format" "%a is unsupported" } */
+  printf ("%A", d); /* { dg-warning "unknown|format" "%A is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-3.c
@@ -0,0 +1,43 @@
+/* Test for printf formats.  Test that the C90 functions get their default
+   attributes in strict C90 mode, but the C99 and gettext functions
+   do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, char *s, size_t n, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5, va_list v6, va_list v7, va_list v8)
+{
+  fprintf (stdout, "%d", i);
+  fprintf (stdout, "%ld", i); /* { dg-warning "format" "fprintf" } */
+  printf ("%d", i);
+  printf ("%ld", i); /* { dg-warning "format" "printf" } */
+  /* The "unlocked" functions shouldn't warn in c90 mode.  */
+  fprintf_unlocked (stdout, "%ld", i);
+  printf_unlocked ("%ld", i);
+  sprintf (s, "%d", i);
+  sprintf (s, "%ld", i); /* { dg-warning "format" "sprintf" } */
+  vfprintf (stdout, "%d", v0);
+  vfprintf (stdout, "%Y", v1); /* { dg-warning "format" "vfprintf" } */
+  vprintf ("%d", v2);
+  vprintf ("%Y", v3); /* { dg-warning "format" "vprintf" } */
+  /* The following used to give a bogus warning.  */
+  vprintf ("%*.*d", v8); /* { dg-warning "format" "dot is invalid" } */
+  vsprintf (s, "%d", v4);
+  vsprintf (s, "%Y", v5); /* { dg-warning "format" "Y is invalid" } */
+  snprintf (s, n, "%d", i);
+  snprintf (s, n, "%ld", i);
+  vsnprintf (s, n, "%d", v6);
+  vsnprintf (s, n, "%Y", v7);
+  printf (gettext ("%d"), i);
+  printf (gettext ("%ld"), i);
+  printf (dgettext ("", "%d"), i);
+  printf (dgettext ("", "%ld"), (long) i);
+  printf (dcgettext ("", "%d", 0), i);
+  printf (dcgettext ("", "%ld", 0), (long) i);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-1.c
@@ -0,0 +1,119 @@
+/* Test for scanf formats.  Formats using C90 features, including cases
+   where C90 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, unsigned int *uip, short int *hp, unsigned short int *uhp,
+     long int *lp, unsigned long int *ulp, float *fp, double *dp,
+     long double *ldp, char *s, signed char *ss, unsigned char *us,
+     void **pp, int *n, llong *llp, ullong *ullp, wchar_t *ls,
+     const int *cip, const int *cn, const char *cs, const void **ppc,
+     void *const *pcp, short int *hn, long int *ln, void *p, char **sp,
+     volatile void *ppv)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.2 (pages 134-138).  */
+  /* Basic sanity checks for the different components of a format.  */
+  scanf ("%d", ip);
+  scanf ("%*d");
+  scanf ("%3d", ip);
+  scanf ("%hd", hp);
+  scanf ("%3ld", lp);
+  scanf ("%*3d");
+  scanf ("%d %ld", ip, lp);
+  /* Valid and invalid %% constructions.  */
+  scanf ("%%");
+  scanf ("%*%"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%*%\n"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%4%"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%4%\n"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%h%"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%h%\n"); /* { dg-warning "format" "bogus %%" } */
+  /* Valid, invalid and silly assignment-suppression constructions.  */
+  scanf ("%*d%*i%*o%*u%*x%*X%*e%*E%*f%*g%*G%*s%*[abc]%*c%*p");
+  scanf ("%*2d%*8s%*3c");
+  scanf ("%*n", n); /* { dg-warning "suppress" "suppression of %n" } */
+  scanf ("%*hd"); /* { dg-warning "together" "suppression with length" } */
+  /* Valid, invalid and silly width constructions.  */
+  scanf ("%2d%3i%4o%5u%6x%7X%8e%9E%10f%11g%12G%13s%14[abc]%15c%16p",
+	 ip, ip, uip, uip, uip, uip, fp, fp, fp, fp, fp, s, s, s, pp);
+  scanf ("%0d", ip); /* { dg-warning "width" "warning for zero width" } */
+  scanf ("%3n", n); /* { dg-warning "width" "width with %n" } */
+  /* Valid and invalid %h, %l, %L constructions.  */
+  scanf ("%hd%hi%ho%hu%hx%hX%hn", hp, hp, uhp, uhp, uhp, uhp, hn);
+  scanf ("%he", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hE", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hf", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hg", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hG", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hs", hp);
+  scanf ("%h[ac]", s); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hc", hp);
+  scanf ("%hp", pp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%h"); /* { dg-warning "conversion lacks type" "bare %h" } */
+  scanf ("%h."); /* { dg-warning "conversion" "bogus %h" } */
+  scanf ("%ld%li%lo%lu%lx%lX%ln", lp, lp, ulp, ulp, ulp, ulp, ln);
+  scanf ("%le%lE%lf%lg%lG", dp, dp, dp, dp, dp);
+  scanf ("%lp", pp); /* { dg-warning "length" "bad use of %l" } */
+  /* These next three formats were added in C94.  */
+  scanf ("%ls", ls); /* { dg-warning "length|C" "bad use of %l" } */
+  scanf ("%l[ac]", ls); /* { dg-warning "length|C" "bad use of %l" } */
+  scanf ("%lc", ls); /* { dg-warning "length|C" "bad use of %l" } */
+  scanf ("%Ld", llp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Li", llp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lo", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lu", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lx", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%LX", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Ls", s); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%L[ac]", s); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lc", s); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lp", pp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Ln", n); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  /* Valid uses of each bare conversion.  */
+  scanf ("%d%i%o%u%x%X%e%E%f%g%G%s%[abc]%c%p%n%%", ip, ip, uip, uip, uip,
+	 uip, fp, fp, fp, fp, fp, s, s, s, pp, n);
+  /* Allow other character pointers with %s, %c, %[].  */
+  scanf ("%2s%3s%4c%5c%6[abc]%7[abc]", ss, us, ss, us, ss, us);
+  /* Further tests for %[].  */
+  scanf ("%[%d]%d", s, ip);
+  scanf ("%[^%d]%d", s, ip);
+  scanf ("%[]%d]%d", s, ip);
+  scanf ("%[^]%d]%d", s, ip);
+  scanf ("%[%d]%d", s, ip);
+  scanf ("%[]abcd", s); /* { dg-warning "no closing" "incomplete scanset" } */
+  /* Various tests of bad argument types.  Some of these are only pedantic
+     warnings.
+  */
+  scanf ("%d", lp); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%d", uip); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%d", pp); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", ppc); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", ppv); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%s", n); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%s", p); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", p); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", sp); /* { dg-warning "format" "bad argument types" } */
+  /* Tests for writing into constant values.  */
+  scanf ("%d", cip); /* { dg-warning "constant" "%d writing into const" } */
+  scanf ("%n", cn); /* { dg-warning "constant" "%n writing into const" } */
+  scanf ("%s", cs); /* { dg-warning "constant" "%s writing into const" } */
+  scanf ("%p", pcp); /* { dg-warning "constant" "%p writing into const" } */
+  /* Wrong number of arguments.  */
+  scanf ("%d%d", ip); /* { dg-warning "arguments" "wrong number of args" } */
+  scanf ("%d", ip, ip); /* { dg-warning "arguments" "wrong number of args" } */
+  /* Miscellaneous bogus constructions.  */
+  scanf (""); /* { dg-warning "zero-length" "warning for empty format" } */
+  scanf ("\0"); /* { dg-warning "embedded" "warning for embedded NUL" } */
+  scanf ("%d\0", ip); /* { dg-warning "embedded" "warning for embedded NUL" } */
+  scanf ("%d\0%d", ip, ip); /* { dg-warning "embedded|too many" "warning for embedded NUL" } */
+  scanf (NULL); /* { dg-warning "null" "null format string warning" } */
+  scanf ("%"); /* { dg-warning "trailing" "trailing % warning" } */
+  scanf ("%d", (int *)0); /* { dg-warning "null" "writing into NULL" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-2.c
@@ -0,0 +1,26 @@
+/* Test for scanf formats.  Formats using C99 features should be rejected
+   outside of C99 mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (signed char *hhp, float *fp, llong *llp, intmax_t *jp,
+     size_t *zp, ptrdiff_t *tp)
+{
+  /* Some tests already in c90-scanf-1.c.  */
+  /* The widths hh, ll, j, z, t are new.  */
+  scanf ("%hhd", hhp); /* { dg-warning "unknown|format" "%hh is unsupported" } */
+  scanf ("%I64d", llp); /* { dg-warning "length|C" "%I64 in C90" } */
+  scanf ("%jd", jp); /* { dg-warning "unknown|format" "%j is unsupported" } */
+  scanf ("%zu", zp); /* { dg-warning "unknown|format" "%z is unsupported" } */
+  scanf ("%td", tp); /* { dg-warning "unknown|format" "%t is unsupported" } */
+  /* The formats F, a, A are new.  */
+  scanf ("%F", fp); /* { dg-warning "unknown|format" "%F is unsupported" } */
+  scanf ("%a", fp); /* { dg-warning "unknown|format" "%a is unsupported" } */
+  scanf ("%A", fp); /* { dg-warning "unknown|format" "%A is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-3.c
@@ -0,0 +1,20 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char **sp, wchar_t **lsp)
+{
+  /* %a formats for allocation, only recognized in C90 mode, are a
+     GNU extension.
+  */
+  scanf ("%as", sp); /* { dg-warning "flag" "%as is unsupported" } */
+  scanf ("%aS", lsp); /* { dg-warning "format|flag" "%aS is unsupported" } */
+  scanf ("%a[bcd]", sp); /* { dg-warning "flag" "%a[] is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-4.c
@@ -0,0 +1,31 @@
+/* Test for scanf formats.  Test that the C90 functions get their default
+   attributes in strict C90 mode, but the C99 and gettext functions
+   do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, char *s, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5)
+{
+  fscanf (stdin, "%d", ip);
+  fscanf (stdin, "%ld", ip); /* { dg-warning "format" "fscanf" } */
+  scanf ("%d", ip);
+  scanf ("%ld", ip); /* { dg-warning "format" "scanf" } */
+  sscanf (s, "%d", ip);
+  sscanf (s, "%ld", ip); /* { dg-warning "format" "sscanf" } */
+  vfscanf (stdin, "%d", v0);
+  vscanf ("%d", v2);
+  vsscanf (s, "%d", v4);
+  scanf (gettext ("%d"), ip);
+  scanf (gettext ("%ld"), ip);
+  scanf (dgettext ("", "%d"), ip);
+  scanf (dgettext ("", "%ld"), ip);
+  scanf (dcgettext ("", "%d", 0), ip);
+  scanf (dcgettext ("", "%ld", 0), ip);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-5.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-5.c
@@ -0,0 +1,20 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char **sp, wchar_t **lsp)
+{
+  /* m assignment-allocation modifier, recognized in both C90
+     and C99 modes, is a POSIX and ISO/IEC WDTR 24731-2 extension.  */
+  scanf ("%ms", sp); /* { dg-warning "unknown|format" "%ms is unsupported" } */
+  scanf ("%mS", lsp); /* { dg-warning "unknown|format" "%mS is unsupported" } */
+  scanf ("%mls", lsp); /* { dg-warning "unknown|format" "%mls is unsupported" } */
+  scanf ("%m[bcd]", sp); /* { dg-warning "unknown|format" "%m[] is unsupported" } */
+  scanf ("%ml[bcd]", lsp); /* { dg-warning "unknown|format" "%ml[] is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-1.c
@@ -0,0 +1,20 @@
+/* Test for strftime formats.  Formats using C90 features.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wformat-y2k" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.12.3.5 (pages 174-175).  */
+  /* Formats which are Y2K-compliant (no 2-digit years).  */
+  strftime (s, m, "%a%A%b%B%d%H%I%j%m%M%p%S%U%w%W%X%Y%Z%%", tp);
+  /* Formats with 2-digit years.  */
+  strftime (s, m, "%y", tp); /* { dg-warning "only last 2" "2-digit year" } */
+  /* Formats with 2-digit years in some locales.  */
+  strftime (s, m, "%c", tp); /* { dg-warning "some locales" "2-digit year" } */
+  strftime (s, m, "%x", tp); /* { dg-warning "some locales" "2-digit year" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-2.c
@@ -0,0 +1,30 @@
+/* Test for strftime formats.  Rejection of formats using C99 features in
+   pedantic C90 mode.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wformat-y2k" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  strftime (s, m, "%C", tp); /* { dg-warning "format" "%C is unsupported" } */
+  strftime (s, m, "%D", tp); /* { dg-warning "format" "%D is unsupported" } */
+  strftime (s, m, "%e", tp); /* { dg-warning "format" "%e is unsupported" } */
+  strftime (s, m, "%F", tp); /* { dg-warning "format" "%F is unsupported" } */
+  strftime (s, m, "%g", tp); /* { dg-warning "format" "%g is unsupported" } */
+  strftime (s, m, "%G", tp); /* { dg-warning "format" "%G is unsupported" } */
+  strftime (s, m, "%h", tp); /* { dg-warning "format" "%h is unsupported" } */
+  strftime (s, m, "%n", tp); /* { dg-warning "format" "%n is unsupported" } */
+  strftime (s, m, "%r", tp); /* { dg-warning "format" "%r is unsupported" } */
+  strftime (s, m, "%R", tp); /* { dg-warning "format" "%R is unsupported" } */
+  strftime (s, m, "%t", tp); /* { dg-warning "format" "%t is unsupported" } */
+  strftime (s, m, "%T", tp); /* { dg-warning "format" "%T is unsupported" } */
+  strftime (s, m, "%u", tp); /* { dg-warning "format" "%u is unsupported" } */
+  strftime (s, m, "%V", tp); /* { dg-warning "format" "%V is unsupported" } */
+  strftime (s, m, "%z", tp); /* { dg-warning "C" "%z not in C90" } */
+  strftime (s, m, "%EX", tp); /* { dg-warning "C" "%E not in C90" } */
+  strftime (s, m, "%OW", tp); /* { dg-warning "C" "%O not in C90" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c94-printf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c94-printf-1.c
@@ -0,0 +1,19 @@
+/* Test for printf formats.  Changes in C94 to C90.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:199409 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (wint_t lc, wchar_t *ls)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.1 (pages 131-134),
+     as amended by ISO/IEC 9899:1990/Amd.1:1995 (E) (pages 4-5).
+     We do not repeat here all the C90 format checks, but just verify
+     that %ls and %lc are accepted without warning.
+  */
+  printf ("%lc", lc);
+  printf ("%ls", ls);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c94-scanf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c94-scanf-1.c
@@ -0,0 +1,18 @@
+/* Test for scanf formats.  Changes in C94 to C90.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:199409 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (wchar_t *ls)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.2 (pages 134-138),
+     as amended by ISO/IEC 9899:1990/Amd.1:1995 (E) (pages 5-6).
+     We do not repeat here all the C90 format checks, but just verify
+     that %ls, %lc, %l[] are accepted without warning.
+  */
+  scanf ("%lc%ls%l[abc]", ls, ls, ls);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-1.c
@@ -0,0 +1,122 @@
+/* Test for printf formats.  Formats using C99 features, including cases
+   where C99 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, unsigned int u, double d, char *s, void *p, int *n,
+     long double ld, wint_t lc, wchar_t *ls, long long int ll,
+     unsigned long long int ull, signed char *ss, unsigned char *us,
+     long long int *lln, intmax_t j, uintmax_t uj, intmax_t *jn,
+     size_t z, signed_size_t sz, signed_size_t *zn,
+     ptrdiff_t t, ptrdiff_t *tn)
+{
+  /* See ISO/IEC 9899:1999 (E) subclause 7.19.6.1 (pages 273-281).
+     We do not repeat here most of the checks for correct C90 formats
+     or completely broken formats.
+  */
+  /* Valid and invalid %h, %hh, %l, %I64, %j, %z, %t, %L constructions.  */
+  printf ("%hf", d); /* { dg-warning "length" "bad use of %h" } */
+  printf ("%hF", d); /* { dg-warning "unknown|format" "bad use of %hF" } */
+  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 ("%ha", d); /* { dg-warning "unknown|format" "bad use of %ha" } */
+  printf ("%hA", d); /* { dg-warning "unknown|format" "bad use of %hA" } */
+  printf ("%hc", i);
+  printf ("%hs", (short *)s);
+  printf ("%hp", p); /* { dg-warning "length" "bad use of %h" } */
+  printf ("%lc", lc);
+  printf ("%ls", ls);
+  printf ("%lp", p); /* { dg-warning "length|C" "bad use of %l" } */
+  printf ("%I64d%I64i%I64o%I64u%I64x%I64X", ll, ll, ull, ull, ull, ull);
+  printf ("%I64n", lln);
+  printf ("%I64f", d); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64F", d); /* { dg-warning "unknown|format" "bad use of %I64F" } */
+  printf ("%I64e", d); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64E", d); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64g", d); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64G", d); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64a", d); /* { dg-warning "unknown|format" "bad use of %I64a" } */
+  printf ("%I64A", d); /* { dg-warning "unknown|format" "bad use of %I64A" } */
+  printf ("%I64c", i); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64s", s); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64p", p); /* { dg-warning "length" "bad use of %I64" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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% 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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 ("%-08F", d); /* { dg-warning "unknown|format" "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 ("%-08a", d); /* { dg-warning "unknown|format" "0 flag ignored with - flag" } */
+  printf ("%-08A", d); /* { dg-warning "unknown|format" "0 flag ignored with - flag" } */
+  /* Various tests of bad argument types.  Mostly covered in c90-printf-1.c;
+     here just test for pointer target sign with %hhn.  (Probably allowed
+     by the standard, but a bad idea, so GCC should diagnose if what
+     is used is not signed char *.)
+  */
+  printf ("%hhn", s); /* { dg-warning "unknown|format" "%hhn is unsupported" } */
+  printf ("%hhn", us); /* { dg-warning "unknown|format" "%hhn is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-2.c
@@ -0,0 +1,33 @@
+/* Test for printf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, long long ll, size_t z, wint_t lc, wchar_t *ls)
+{
+  /* The length modifiers q, Z and L as applied to integer formats are
+     extensions.
+  */
+  printf ("%qd", ll); /* { dg-warning "unknown|format" "%q length is unsupported" } */
+  printf ("%Ld", ll); /* { dg-warning "unknown|format" "%L length is unsupported" } */
+  printf ("%Zd", z); /* { dg-warning "unknown|format" "%Z lengthis unsupported" } */
+  /* The conversion specifiers C and S are X/Open extensions; the
+     conversion specifier m is a GNU extension.
+  */
+  printf ("%m"); /* { dg-warning "unknown|format" "printf %m is unsupported" } */
+  printf ("%C", lc); /* { dg-warning "C" "printf %C" } */
+  printf ("%S", ls); /* { dg-warning "C" "printf %S" } */
+  /* The flag character ', and the use of operand number $ formats, are
+     X/Open extensions.
+  */
+  printf ("%'d", i); /* { dg-warning "C" "printf ' flag" } */
+  printf ("%1$d", i); /* { dg-warning "C" "printf $ format" } */
+  /* The flag character I is a GNU extension.  */
+  printf ("%Ix", z);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-3.c
@@ -0,0 +1,40 @@
+/* Test for printf formats.  Test that the C99 functions get their default
+   attributes in strict C99 mode, but the gettext functions do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, char *s, size_t n, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5, va_list v6, va_list v7)
+{
+  fprintf (stdout, "%d", i);
+  fprintf (stdout, "%ld", i); /* { dg-warning "format" "fprintf" } */
+  printf ("%d", i);
+  printf ("%ld", i); /* { dg-warning "format" "printf" } */
+  /* The "unlocked" functions shouldn't warn in c99 mode.  */
+  fprintf_unlocked (stdout, "%ld", i);
+  printf_unlocked ("%ld", i);
+  sprintf (s, "%d", i);
+  sprintf (s, "%ld", i); /* { dg-warning "format" "sprintf" } */
+  snprintf (s, n, "%d", i);
+  snprintf (s, n, "%ld", i); /* { dg-warning "format" "snprintf" } */
+  vfprintf (stdout, "%d", v0);
+  vfprintf (stdout, "%Y", v1); /* { dg-warning "format" "vfprintf" } */
+  vprintf ("%d", v0);
+  vprintf ("%Y", v1); /* { dg-warning "format" "vprintf" } */
+  vsprintf (s, "%d", v0);
+  vsprintf (s, "%Y", v1); /* { dg-warning "format" "vsprintf" } */
+  vsnprintf (s, n, "%d", v0);
+  vsnprintf (s, n, "%Y", v1); /* { dg-warning "format" "vsnprintf" } */
+  printf (gettext ("%d"), i);
+  printf (gettext ("%ld"), (long) i);
+  printf (dgettext ("", "%d"), i);
+  printf (dgettext ("", "%ld"), (long) i);
+  printf (dcgettext ("", "%d", 0), i);
+  printf (dcgettext ("", "%ld", 0), (long) i);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-1.c
@@ -0,0 +1,75 @@
+/* Test for scanf formats.  Formats using C99 features, including cases
+   where C99 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, unsigned int *uip, short int *hp, unsigned short int *uhp,
+     signed char *hhp, unsigned char *uhhp, long int *lp,
+     unsigned long int *ulp, float *fp, double *dp, long double *ldp, char *s,
+     void **pp, int *n, long long *llp, unsigned long long *ullp, wchar_t *ls,
+     short int *hn, signed char *hhn, long int *ln, long long int *lln,
+     intmax_t *jp, uintmax_t *ujp, intmax_t *jn, size_t *zp,
+     signed_size_t *szp, signed_size_t *zn, ptrdiff_t *tp,
+     unsigned_ptrdiff_t *utp, ptrdiff_t *tn)
+{
+  /* See ISO/IEC 9899:1999 (E) subclause 7.19.6.2 (pages 281-288).
+     We do not repeat here most of the checks for correct C90 formats
+     or completely broken formats.
+  */
+  /* Valid, invalid and silly assignment-suppression
+     and width constructions.
+  */
+  scanf ("%*d%*i%*o%*u%*x%*X%*e%*E%*f%*g%*G%*s%*[abc]%*c%*p");
+  scanf ("%*2d%*8s%*3c");
+  scanf ("%*n", n); /* { dg-warning "suppress" "suppression of %n" } */
+  scanf ("%*hd"); /* { dg-warning "together" "suppression with length" } */
+  scanf ("%2d%3i%4o%5u%6x%7X%10e%11E%12f%14g%15G%16s%3[abc]%4c%5p",
+	 ip, ip, uip, uip, uip, uip, fp, fp, fp, fp, fp,
+	 s, s, s, pp);
+  scanf ("%0d", ip); /* { dg-warning "width" "warning for zero width" } */
+  scanf ("%3n", n); /* { dg-warning "width" "width with %n" } */
+  /* Valid and invalid %h, %hh, %l, %I64, %j, %z, %t, %L constructions.  */
+  scanf ("%hd%hi%ho%hu%hx%hX%hn", hp, hp, uhp, uhp, uhp, uhp, hn);
+  scanf ("%he", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hE", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hf", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hg", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hG", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hs", hp);
+  scanf ("%h[ac]", s); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hc", (short *)s);
+  scanf ("%hp", pp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hhd", hhp); /* { dg-warning "unknown|format" "%hh is unsupported" } */
+  scanf ("%ld%li%lo%lu%lx%lX%ln", lp, lp, ulp, ulp, ulp, ulp, ln);
+  scanf ("%le%lE%lf%lg%lG", dp, dp, dp, dp, dp);
+  scanf ("%lp", pp); /* { dg-warning "length" "bad use of %l" } */
+  scanf ("%ls", ls);
+  scanf ("%l[ac]", ls);
+  scanf ("%lc", ls);
+  scanf ("%I64d%I64i%I64o%I64u%I64x%I64X%I64n", llp, llp, ullp, ullp, ullp, ullp,
+	 lln);
+  scanf ("%I64e", fp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64E", fp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64f", fp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64F", fp); /* { dg-warning "unknown|format" "'F' is unsupported" } */
+  scanf ("%I64g", fp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64G", fp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64s", s); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64[ac]", s); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64c", s); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64p", pp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%jd", jp); /* { dg-warning "unknown|format" "%j not supported" } */
+  scanf ("%zd", zp); /* { dg-warning "unknown|format" "%z not supported" } */
+  scanf ("%td", tp); /* { dg-warning "unknown|format" "%t not supported" } */
+  scanf ("%Lf", llp); /* { dg-warning "unknown|format" "bad use of %L is not supported" } */
+  /* Valid uses of each bare conversion.  */
+  scanf ("%d%i%o%u%x%X%e%E%f%g%G%s%[abc]%c%p%n%%", ip, ip, uip, uip, uip,
+         uip, fp, fp, fp, fp, fp, s, s, s, pp, n);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-2.c
@@ -0,0 +1,27 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, long long int *llp, wchar_t *ls)
+{
+  /* The length modifiers q and L as applied to integer formats are
+     extensions.
+  */
+  scanf ("%qd", llp); /* { dg-warning "unknown|format" "%q is unsupported" } */
+  scanf ("%Ld", llp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  /* The conversion specifiers C and S are X/Open extensions.  */
+  scanf ("%C", ls); /* { dg-warning "C" "scanf %C" } */
+  scanf ("%S", ls); /* { dg-warning "C" "scanf %S" } */
+  /* The use of operand number $ formats is an X/Open extension.  */
+  scanf ("%1$d", ip); /* { dg-warning "C" "scanf $ format" } */
+  /* glibc also supports flags ' and I on scanf formats as an extension.  */
+  scanf ("%'d", ip); /* { dg-warning "C" "scanf ' flag" } */
+  scanf ("%Id", (ssize_t *)ip);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-3.c
@@ -0,0 +1,33 @@
+/* Test for scanf formats.  Test that the C99 functions get their default
+   attributes in strict C99 mode, but the gettext functions do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, char *s, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5)
+{
+  fscanf (stdin, "%d", ip);
+  fscanf (stdin, "%ld", ip); /* { dg-warning "format" "fscanf" } */
+  scanf ("%d", ip);
+  scanf ("%ld", ip); /* { dg-warning "format" "scanf" } */
+  sscanf (s, "%d", ip);
+  sscanf (s, "%ld", ip); /* { dg-warning "format" "sscanf" } */
+  vfscanf (stdin, "%d", v0);
+  vfscanf (stdin, "%Y", v1); /* { dg-warning "format" "vfscanf" } */
+  vscanf ("%d", v2);
+  vscanf ("%Y", v3); /* { dg-warning "format" "vscanf" } */
+  vsscanf (s, "%d", v4);
+  vsscanf (s, "%Y", v5); /* { dg-warning "format" "vsscanf" } */
+  scanf (gettext ("%d"), ip);
+  scanf (gettext ("%ld"), ip);
+  scanf (dgettext ("", "%d"), ip);
+  scanf (dgettext ("", "%ld"), ip);
+  scanf (dcgettext ("", "%d", 0), ip);
+  scanf (dcgettext ("", "%ld", 0), ip);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-4.c
@@ -0,0 +1,20 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char **sp, wchar_t **lsp)
+{
+  /* m assignment-allocation modifier, recognized in both C90
+     and C99 modes, is a POSIX and ISO/IEC WDTR 24731-2 extension.  */
+  scanf ("%ms", sp); /* { dg-warning "unknown|format" "%ms is unsupported" } */
+  scanf ("%mS", lsp); /* { dg-warning "unknown|format" "%mS is unsupported" } */
+  scanf ("%mls", lsp); /* { dg-warning "unknown|format" "%mls is unsupported" } */
+  scanf ("%m[bcd]", sp); /* { dg-warning "unknown|format" "%m[] is unsupported" } */
+  scanf ("%ml[bcd]", lsp); /* { dg-warning "unknown|format" "%ml[] is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-1.c
@@ -0,0 +1,30 @@
+/* Test for strftime formats.  Formats using C99 features.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat -Wformat-y2k" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.12.3.5 (pages 174-175).  */
+  /* Formats which are Y2K-compliant (no 2-digit years).  */
+  strftime (s, m, "%a%A%b%B%d%H%I%j%m%M%p%S%U%w%W%X%Y%z%Z%%", tp);
+  strftime (s, m, "%EX%EY%Od%OH%OI%Om%OM%OS%OU%Ow%OW", tp);
+  /* Formats with 2-digit years.  */
+  strftime (s, m, "%D", tp); /* { dg-warning "unknown" "2-digit year unsupported" } */
+  strftime (s, m, "%g", tp); /* { dg-warning "unknown" "2-digit year unsupported" } */
+  strftime (s, m, "%y", tp); /* { dg-warning "only last 2" "2-digit year" } */
+  strftime (s, m, "%Oy", tp); /* { dg-warning "only last 2" "2-digit year" } */
+  /* Formats with 2-digit years in some locales.  */
+  strftime (s, m, "%c", tp); /* { dg-warning "some locales" "2-digit year" } */
+  strftime (s, m, "%Ec", tp); /* { dg-warning "some locales" "2-digit year" } */
+  strftime (s, m, "%x", tp); /* { dg-warning "some locales" "2-digit year" } */
+  strftime (s, m, "%Ex", tp); /* { dg-warning "some locales" "2-digit year" } */
+  /* %Ey is explicitly an era offset not a 2-digit year; but in some
+     locales the E modifier may be ignored.
+  */
+  strftime (s, m, "%Ey", tp); /* { dg-warning "some locales" "2-digit year" } */
+  }
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-2.c
@@ -0,0 +1,24 @@
+/* Test for strftime formats.  Rejection of extensions in pedantic mode.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  /* %P is a lowercase version of %p.  */
+  strftime (s, m, "%P", tp); /* { dg-warning "unknown" "strftime %P" } */
+  /* %k is %H but padded with a space rather than 0 if necessary.  */
+  strftime (s, m, "%k", tp); /* { dg-warning "unknown" "strftime %k" } */
+  /* %l is %I but padded with a space rather than 0 if necessary.  */
+  strftime (s, m, "%l", tp); /* { dg-warning "unknown" "strftime %l" } */
+  /* %s is the number of seconds since the Epoch.  */
+  strftime (s, m, "%s", tp); /* { dg-warning "unknown" "strftime %s" } */
+  /* Extensions using %O already tested in c99-strftime-1.c.  */
+  /* Width and flags are GNU extensions for strftime.  */
+  strftime (s, m, "%20Y", tp); /* { dg-warning "C" "strftime width" } */
+  strftime (s, m, "%^A", tp); /* { dg-warning "C" "strftime flags" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_cast-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_cast-1.c
@@ -0,0 +1,17 @@
+/* Test for strings cast through integer types: should not be treated
+   as format strings unless the types are of the same width as
+   pointers (intptr_t or similar).  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+f (int x)
+{
+  printf("%s", x); /* { dg-warning "format" } */
+  printf((char *)(size_t)"%s", x); /* { dg-warning "format" } */
+  printf((char *)(char)"%s", x); /* { dg-warning "cast from pointer to integer of different size" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-1.c
@@ -0,0 +1,40 @@
+/* Test for warnings for missing format attributes.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  vprintf (fmt, ap); /* { dg-warning "candidate" "printf attribute warning" } */
+  va_end (ap);
+}
+
+void
+bar (const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  vscanf (fmt, ap); /* { dg-warning "candidate" "scanf attribute warning" } */
+  va_end (ap);
+}
+
+__attribute__((__format__(__ms_printf__, 1, 2))) void
+foo2 (const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  vprintf (fmt, ap);
+  va_end (ap);
+}
+
+void
+vfoo (const char *fmt, va_list arg)
+{
+  vprintf (fmt, arg); /* { dg-warning "candidate" "printf attribute warning 2" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-2.c
@@ -0,0 +1,17 @@
+/* Test for warnings for missing format attributes.  Don't warn if no
+   relevant parameters for a format attribute; see c/1017.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, ...)
+{
+  va_list ap;
+  va_start (ap, i);
+  vprintf ("Foo %s bar %s", ap); /* { dg-bogus "candidate" "bogus printf attribute warning" } */
+  va_end (ap);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-3.c
@@ -0,0 +1,27 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+void
+foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
+{
+  noattr_t na1 = na;
+  noattr_t na2 = a; /* { dg-warning "candidate" "initialization warning" } */
+  attr_t a1 = na;
+  attr_t a2 = a;
+
+  vnoattr_t vna1 = vna;
+  vnoattr_t vna2 = va; /* { dg-warning "candidate" "initialization warning" } */
+  vattr_t va1 = vna;
+  vattr_t va2 = va;
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-4.c
@@ -0,0 +1,33 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+void
+foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
+{
+  noattr_t na1, na2;
+  attr_t a1, a2;
+
+  vnoattr_t vna1, vna2;
+  vattr_t va1, va2;
+
+  na1 = na;
+  na2 = a; /* { dg-warning "candidate" "assignment warning" } */
+  a1 = na;
+  a2 = a;
+
+  vna1 = vna;
+  vna2 = va; /* { dg-warning "candidate" "assignment warning" } */
+  va1 = vna;
+  va1 = va;
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-5.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-5.c
@@ -0,0 +1,49 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+noattr_t
+foo1 (noattr_t na, attr_t a, int i)
+{
+  if (i)
+    return na;
+  else
+    return a; /* { dg-warning "candidate" "return type warning" } */
+}
+
+attr_t
+foo2 (noattr_t na, attr_t a, int i)
+{
+  if (i)
+    return na;
+  else
+    return a;
+}
+
+vnoattr_t
+foo3 (vnoattr_t vna, vattr_t va, int i)
+{
+  if (i)
+    return vna;
+  else
+    return va; /* { dg-warning "candidate" "return type warning" } */
+}
+
+vattr_t
+foo4 (vnoattr_t vna, vattr_t va, int i)
+{
+  if (i)
+    return vna;
+  else
+    return va;
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-6.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-6.c
@@ -0,0 +1,32 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+extern void foo1 (noattr_t);
+extern void foo2 (attr_t);
+extern void foo3 (vnoattr_t);
+extern void foo4 (vattr_t);
+
+void
+foo (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
+{
+  foo1 (na);
+  foo1 (a); /* { dg-warning "candidate" "parameter passing warning" } */
+  foo2 (na);
+  foo2 (a);
+
+  foo3 (vna);
+  foo3 (va); /* { dg-warning "candidate" "parameter passing warning" } */
+  foo4 (vna);
+  foo4 (va);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_multattr-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_multattr-1.c
@@ -0,0 +1,51 @@
+/* Test for multiple format attributes.  Test for printf and scanf attributes
+   together.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* If we specify multiple attributes for a single function, they should
+   all apply.  This should apply whether they are on the same declaration
+   or on different declarations.  */
+
+extern void my_vprintf_scanf (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_printf__, 1, 0)))
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern void my_vprintf_scanf2 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)))
+     __attribute__((__format__(__ms_printf__, 1, 0)));
+
+extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_printf__, 1, 0)));
+extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_printf__, 1, 0)));
+
+void
+foo (va_list ap, int *ip, long *lp)
+{
+  my_vprintf_scanf ("%d", ap, "%d", ip);
+  my_vprintf_scanf ("%d", ap, "%ld", lp);
+  my_vprintf_scanf ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf2 ("%d", ap, "%d", ip);
+  my_vprintf_scanf2 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf2 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf2 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf3 ("%d", ap, "%d", ip);
+  my_vprintf_scanf3 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf3 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf3 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf4 ("%d", ap, "%d", ip);
+  my_vprintf_scanf4 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf4 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf4 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_multattr-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_multattr-2.c
@@ -0,0 +1,40 @@
+/* Test for multiple format attributes.  Test for printf and scanf attributes
+   together, in different places on the declarations.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* If we specify multiple attributes for a single function, they should
+   all apply, wherever they are placed on the declarations.  */
+
+extern __attribute__((__format__(__ms_printf__, 1, 0))) void
+     my_vprintf_scanf (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern void (__attribute__((__format__(__ms_printf__, 1, 0))) my_vprintf_scanf2)
+     (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern __attribute__((__format__(__ms_scanf__, 3, 4))) void
+     (__attribute__((__format__(__ms_printf__, 1, 0))) my_vprintf_scanf3)
+     (const char *, va_list, const char *, ...);
+
+void
+foo (va_list ap, int *ip, long *lp)
+{
+  my_vprintf_scanf ("%d", ap, "%d", ip);
+  my_vprintf_scanf ("%d", ap, "%ld", lp);
+  my_vprintf_scanf ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf2 ("%d", ap, "%d", ip);
+  my_vprintf_scanf2 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf2 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf2 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf3 ("%d", ap, "%d", ip);
+  my_vprintf_scanf3 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf3 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf3 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_multattr-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_multattr-3.c
@@ -0,0 +1,29 @@
+/* Test for multiple format_arg attributes.  Test for both branches
+   getting checked.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+extern char *ngettext (const char *, const char *, unsigned long int)
+     __attribute__((__format_arg__(1))) __attribute__((__format_arg__(2)));
+
+void
+foo (long l, int nfoo)
+{
+  printf (ngettext ("%d foo", "%d foos", nfoo), nfoo);
+  printf (ngettext ("%d foo", "%d foos", l), l); /* { dg-warning "int" "wrong type in conditional expr" } */
+  printf (ngettext ("%d foo", "%ld foos", l), l); /* { dg-warning "int" "wrong type in conditional expr" } */
+  printf (ngettext ("%ld foo", "%d foos", l), l); /* { dg-warning "int" "wrong type in conditional expr" } */
+  /* Should allow one case to have extra arguments.  */
+  printf (ngettext ("1 foo", "%d foos", nfoo), nfoo);
+  printf (ngettext ("1 foo", "many foos", nfoo), nfoo); /* { dg-warning "too many" "too many args in all branches" } */
+  printf (ngettext ("", "%d foos", nfoo), nfoo);
+  printf (ngettext ("1 foo", (nfoo > 0) ? "%d foos" : "no foos", nfoo), nfoo);
+  printf (ngettext ("%d foo", (nfoo > 0) ? "%d foos" : "no foos", nfoo), nfoo);
+  printf (ngettext ("%ld foo", (nfoo > 0) ? "%d foos" : "no foos", nfoo), nfoo); /* { dg-warning "long int" "wrong type" } */
+  printf (ngettext ("%d foo", (nfoo > 0) ? "%ld foos" : "no foos", nfoo), nfoo); /* { dg-warning "long int" "wrong type" } */
+  printf (ngettext ("%d foo", (nfoo > 0) ? "%d foos" : "%ld foos", nfoo), nfoo); /* { dg-warning "long int" "wrong type" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-1.c
@@ -0,0 +1,15 @@
+/* Test for warnings for extra format arguments being disabled by
+   -Wno-format-extra-args.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wno-format-extra-args" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i)
+{
+  printf ("foo", i);
+  printf ("%1$d", i, i);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-2.c
@@ -0,0 +1,28 @@
+/* Test for warnings for extra format arguments being disabled by
+   -Wno-format-extra-args.  Test which warnings still apply with $
+   operand numbers.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wno-format-extra-args" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, int *ip, va_list va)
+{
+  printf ("%3$d%1$d", i, i, i); /* { dg-warning "before used" "unused $ operand" } */
+  printf ("%2$d%1$d", i, i, i);
+  vprintf ("%3$d%1$d", va); /* { dg-warning "before used" "unused $ operand" } */
+  /* With scanf formats, gaps in the used arguments are allowed only if the
+     arguments are all pointers.  In such a case, should only give the lesser
+     warning about unused arguments rather than the more serious one about
+     argument gaps.  */
+  scanf ("%3$d%1$d", ip, ip, ip);
+  /* If there are non-pointer arguments unused at the end, this is also OK.  */
+  scanf ("%3$d%1$d", ip, ip, ip, i);
+  scanf ("%3$d%1$d", ip, i, ip); /* { dg-warning "before used" "unused $ scanf non-pointer operand" } */
+  /* Can't check the arguments in the vscanf case, so should suppose the
+     lesser problem.  */
+  vscanf ("%3$d%1$d", va);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_no-y2k-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_no-y2k-1.c
@@ -0,0 +1,13 @@
+/* Test for warnings for Y2K problems not being on by default.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  strftime (s, m, "%y%c%x", tp);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-1.c
@@ -0,0 +1,14 @@
+/* Test for warnings for non-string-literal formats.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wformat-nonliteral" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t i)
+{
+  printf ((const char *)i, i); /* { dg-warning "argument types" "non-literal" } */
+  printf (s, i); /* { dg-warning "argument types" "non-literal" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-2.c
@@ -0,0 +1,14 @@
+/* Test for warnings for non-string-literal formats.  Test with -Wformat=2.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat=2" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t i)
+{
+  printf ((const char *)i, i); /* { dg-warning "argument types" "non-literal" } */
+  printf (s, i); /* { dg-warning "argument types" "non-literal" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-3.c
@@ -0,0 +1,13 @@
+/* Test for warnings for non-string-literal formats.  Test for strftime formats.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wformat-nonliteral" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp, char *fmt)
+{
+  strftime (s, m, fmt, tp); /* { dg-warning "format string" "non-literal" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nul-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nul-1.c
@@ -0,0 +1,15 @@
+/* Test diagnostics for suppressing contains nul
+   -Wformat.  -Wformat.  */
+/* Origin: Bruce Korb <bkorb@gnu.org> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat -Wno-format-contains-nul" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (void)
+{
+  static char const fmt[] = "x%s\0%s\n\0abc";
+  printf (fmt+4, fmt+8); /* { dg-bogus "embedded.*in format" "bogus embed warning" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nul-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nul-2.c
@@ -0,0 +1,17 @@
+/* Test diagnostics for options used on their own without
+   -Wformat.  -Wformat-.  */
+/* Origin: Bruce Korb <bkorb@gnu.org> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+
+/* { dg-warning "embedded .* in format" "ignored" { target *-*-* } 0 } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+fumble (void)
+{
+  static char const fmt[] = "x%s\0%s\n\0abc";
+  printf (fmt+4, fmt+8);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_null-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_null-1.c
@@ -0,0 +1,28 @@
+/* Test for some aspects of null format string handling.  */
+/* Origin: Jason Thorpe <thorpej@wasabisystems.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+extern void my_printf (const char *, ...) __attribute__((format(ms_printf,1,2)));
+extern const char *my_format (const char *, const char *)
+  __attribute__((format_arg(2)));
+
+void
+foo (int i1)
+{
+  /* Warning about a null format string has been decoupled from the actual
+     format check.  However, we still expect to be warned about any excess
+     arguments after a null format string.  */
+  my_printf (NULL);
+  my_printf (NULL, i1); /* { dg-warning "too many" "null format with arguments" } */
+
+  my_printf (my_format ("", NULL));
+  my_printf (my_format ("", NULL), i1); /* { dg-warning "too many" "null format_arg with arguments" } */
+
+  /* While my_printf allows a null argument, dgettext does not, so we expect
+     a null argument warning here.  */
+  my_printf (dgettext ("", NULL)); /* { dg-warning "null" "null format with dgettext" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_plus-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_plus-1.c
@@ -0,0 +1,21 @@
+/* Test for printf formats using string literal plus constant.
+ */
+/* Origin: Jakub Jelinek <jakub@redhat.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat=2" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i)
+{
+  printf ("%%d\n" + 1, i);
+  printf (5 + "%.-*d%3d\n", i);
+  printf ("%d%d" + 2, i, i);	/* { dg-warning "arguments" "wrong number of args" } */
+  printf (3 + "%d\n");		/* { dg-warning "zero-length" "zero-length string" } */
+  printf ("%d\n" + i, i);	/* { dg-warning "not a string" "non-constant addend" } */
+  printf ("%d\n" + 10);		/* { dg-warning "not a string" "too large addend" } */
+  printf ("%d\n" - 1, i);	/* { dg-warning "not a string" "minus constant" } */
+  printf ("%d\n" + -1, i);	/* { dg-warning "not a string" "negative addend" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_sec-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_sec-1.c
@@ -0,0 +1,13 @@
+/* Test for security warning when non-literal format has no arguments.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wformat-security" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s)
+{
+  printf (s); /* { dg-warning "no format arguments" "security warning" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_unnamed-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_unnamed-1.c
@@ -0,0 +1,24 @@
+/* Test for warnings with possibly unnamed integer types.  Bug 24329.  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+/* { dg-options "-Wformat -msse" { target { { i?86-*-* x86_64-*-* } && ilp32 } } } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* Definition of TItype follows same logic as in gcc.dg/titype-1.c,
+   but must be a #define to avoid giving the type a name.  */
+#if defined(__LP64__) && !defined(__hppa__)
+#define TItype int __attribute__ ((mode (TI)))
+#else
+#define TItype long
+#endif
+
+void
+f (TItype x)
+{
+  printf("%d", x); /* { dg-warning "expects type" } */
+  printf("%d", 141592653589793238462643383279502884197169399375105820974944); /* { dg-warning "expects type" } */
+  /* { dg-warning "unsigned only|too large" "constant" { target *-*-* } 22 } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_va-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_va-1.c
@@ -0,0 +1,14 @@
+/* Test for strange warning in format checking.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (void *p)
+{
+  printf ("%d", p); /* { dg-bogus "va_list" "wrong type in format warning" } */
+  /* { dg-warning "format" "format error" { target *-*-* } 12 } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_warnll-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_warnll-1.c
@@ -0,0 +1,19 @@
+/* Test for printf formats.  C99 "long long" formats should be accepted with
+   -Wno-long-long.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wno-long-long" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (long long ll, unsigned long long ull, long long *lln,
+     long long *llp, unsigned long long *ullp)
+{
+  /* Test for accepting standard "long long" formats.  */
+  printf ("%I64d%I64i%I64o%I64u%I64x%I64X%I64n", ll, ll, ull, ull, ull, ull, lln);
+  scanf ("%I64d%I64i%I64o%I64u%I64x%I64X%I64n", llp, llp,
+	 ullp, ullp, ullp, ullp, lln);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_zero-length-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_zero-length-1.c
@@ -0,0 +1,16 @@
+/* Test the -Wno-format-zero-length option, which suppresses warnings
+   about zero-length formats.  */
+/* Origin: Jason Thorpe <thorpej@wasabisystems.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wno-format-zero-length" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (void)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.1 (pages 131-134).  */
+  /* Zero-length format strings are allowed.  */
+  printf ("");
+}
Index: gcc/gcc/testsuite/gcc.dg/format/multattr-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/multattr-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/multattr-1.c
@@ -4,6 +4,7 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 /* If we specify multiple attributes for a single function, they should
@@ -11,22 +12,22 @@
    or on different declarations.  */
 
 extern void my_vprintf_scanf (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__printf__, 1, 0)))
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)))
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
 extern void my_vprintf_scanf2 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)))
-     __attribute__((__format__(__printf__, 1, 0)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)))
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)));
 
 extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__printf__, 1, 0)));
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)));
 extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
 extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__printf__, 1, 0)));
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)));
 
 void
 foo (va_list ap, int *ip, long *lp)
Index: gcc/gcc/testsuite/gcc.dg/format/multattr-2.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/multattr-2.c
+++ gcc/gcc/testsuite/gcc.dg/format/multattr-2.c
@@ -4,21 +4,22 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 /* If we specify multiple attributes for a single function, they should
    all apply, wherever they are placed on the declarations.  */
 
-extern __attribute__((__format__(__printf__, 1, 0))) void
+extern __attribute__((__format__(gnu_attr___printf__, 1, 0))) void
      my_vprintf_scanf (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
-extern void (__attribute__((__format__(__printf__, 1, 0))) my_vprintf_scanf2)
+extern void (__attribute__((__format__(gnu_attr___printf__, 1, 0))) my_vprintf_scanf2)
      (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
-extern __attribute__((__format__(__scanf__, 3, 4))) void
-     (__attribute__((__format__(__printf__, 1, 0))) my_vprintf_scanf3)
+extern __attribute__((__format__(gnu_attr___scanf__, 3, 4))) void
+     (__attribute__((__format__(gnu_attr___printf__, 1, 0))) my_vprintf_scanf3)
      (const char *, va_list, const char *, ...);
 
 void
Index: gcc/gcc/testsuite/gcc.dg/format/null-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/null-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/null-1.c
@@ -3,9 +3,10 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern void my_printf (const char *, ...) __attribute__((format(printf,1,2)));
+extern void my_printf (const char *, ...) __attribute__((format(gnu_attr_printf,1,2)));
 extern const char *my_format (const char *, const char *)
   __attribute__((format_arg(2)));
 
=

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf             formatters to c-format.c
  2008-02-25 18:53                   ` Joseph S. Myers
@ 2008-03-04 19:25                     ` Joseph S. Myers
  2008-03-10 11:06                     ` Kai Tietz
  1 sibling, 0 replies; 61+ messages in thread
From: Joseph S. Myers @ 2008-03-04 19:25 UTC (permalink / raw)
  To: Kai Tietz, ktietz70; +Cc: Danny Smith, GCC Patches, NightStrike

A further issue regarding this patch:

ms_time_char_table appears to indicate strftime as supporting many 
different format flags and modifiers.  For example, it indicates %Ex as 
supported.  However, my testing suggests that %Ex is not supported by 
Windows strftime, and that this is the cause of

FAIL: 22_locale/time_put/put/char/1.cc execution test
FAIL: 22_locale/time_put/put/wchar_t/1.cc execution test

in libstdc++ testing on MinGW.

(MSDN lists '#' as supported with strftime formats, but nothing else.)

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf            formatters to c-format.c
  2008-02-19 15:16                 ` Kai Tietz
  2008-02-25 16:46                   ` NightStrike
@ 2008-02-25 18:53                   ` Joseph S. Myers
  2008-03-04 19:25                     ` Joseph S. Myers
  2008-03-10 11:06                     ` Kai Tietz
  1 sibling, 2 replies; 61+ messages in thread
From: Joseph S. Myers @ 2008-02-25 18:53 UTC (permalink / raw)
  To: Kai Tietz, ktietz70; +Cc: Danny Smith, GCC Patches, NightStrike

On Tue, 19 Feb 2008, Kai Tietz wrote:

>         * gcc/c-format.h: Add structure target_ovr_attr to hold
>         system specific formatter names.

No "gcc/" in ChangeLog entries.  Also note the proper style

	* file (part of file): Message.

so "c-format.h (target_ovr_attr): New structure." (for example).

The use of "formatter" still needs changing to "format" throughout the 
patch.

> +  if (attr_name == NULL || *attr_name == 0 || strncmp (attr_name, "gcc_", 4) == 0)

Please ensure source lines are under 80 columns wide.

> +  for (i = 0; gnu_target_overrides_format_attributes[i].named_attr_src != NULL; ++i)

Likewise.


> +  /* Name of the single-character length modifier. If prefixed by
> +     a zero character, it discribes a multi character length

"describes".

> +     modifier, lile I64, I32, etc.  */

"like".

> +/* Contains a pointer to type target_ovr_attr defining the target specific
> +   overrides of formatter attributs.  See format.h for structure definition.  */

"attributes", and I think you mean c-format.h.

> Index: gcc/gcc/config/i386/msformat-c.c

Note that this part of the patch will need reviewing by a MinGW 
maintainer.

>  The parameter @var{archetype} determines how the format string is
> -interpreted, and should be @code{printf}, @code{scanf}, @code{strftime}
> -or @code{strfmon}.  (You can also use @code{__printf__},
> -@code{__scanf__}, @code{__strftime__} or @code{__strfmon__}.)  The
> -parameter @var{string-index} specifies which argument is the format
> -string argument (starting from 1), while @var{first-to-check} is the
> -number of the first argument to check against the format string.  For
> -functions where the arguments are not available to be checked (such as
> +interpreted, and should be @code{printf}, @code{scanf}, @code{strftime},
> +@code{gnu_printf}, @code{gnu_scanf}, @code{gnu_strftime} or
> +@code{strfmon}.  (You can also use @code{__printf__},
> +@code{__scanf__}, @code{__strftime__} or @code{__strfmon__}.)  On
> +mingw targets there is also @code{ms_printf}, @code{ms_scanf}, and

"MinGW".  And I think it's actually "Microsoft Windows targets", since 
these appear to be available on Cygwin as well, judging by the config.gcc 
patch.

> +@code{ms_strftime} present. The none target specific formatters are
> +always the variant of the system.  The parameter @var{string-index}

"@var{archtype} values such as @code{printf} refer to the formats accepted 
by the system's C run-time library, while @code{gnu_} values always refer 
to the formats accepted by the GNU C Library.  On Microsoft Windows 
targets, @code{ms_} values refer to the formats accepted by the 
@file{msvcrt.dll} library."

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf formatters to c-format.c
  2008-02-25 16:58                     ` Joseph S. Myers
@ 2008-02-25 17:42                       ` NightStrike
  0 siblings, 0 replies; 61+ messages in thread
From: NightStrike @ 2008-02-25 17:42 UTC (permalink / raw)
  To: Joseph S. Myers, Kai Tietz; +Cc: Kai Tietz, Danny Smith, GCC Patches

On 2/25/08, Joseph S. Myers <joseph@codesourcery.com> wrote:
> On Mon, 25 Feb 2008, NightStrike wrote:
>
> > On 2/19/08, Kai Tietz <Kai.Tietz@onevision.com> wrote:
> > > Is this ok for apply to trunk?
> >
> > Kai informed me that he will be unavailable for a week or so, and will
> > be unable to apply this patch (latest one from 6 days ago, the 19th of
> > February).  Can someone else?
>
> It may need more iterations of revising the patch further anyway, but
> we've got four months (until the end of Stage 2).

What else needs revising?

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf  formatters to c-format.c
  2008-02-25 16:46                   ` NightStrike
@ 2008-02-25 16:58                     ` Joseph S. Myers
  2008-02-25 17:42                       ` NightStrike
  0 siblings, 1 reply; 61+ messages in thread
From: Joseph S. Myers @ 2008-02-25 16:58 UTC (permalink / raw)
  To: NightStrike; +Cc: Kai Tietz, Danny Smith, GCC Patches

On Mon, 25 Feb 2008, NightStrike wrote:

> On 2/19/08, Kai Tietz <Kai.Tietz@onevision.com> wrote:
> > Is this ok for apply to trunk?
> 
> Kai informed me that he will be unavailable for a week or so, and will
> be unable to apply this patch (latest one from 6 days ago, the 19th of
> February).  Can someone else?

It may need more iterations of revising the patch further anyway, but 
we've got four months (until the end of Stage 2).

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf formatters to c-format.c
  2008-02-19 15:16                 ` Kai Tietz
@ 2008-02-25 16:46                   ` NightStrike
  2008-02-25 16:58                     ` Joseph S. Myers
  2008-02-25 18:53                   ` Joseph S. Myers
  1 sibling, 1 reply; 61+ messages in thread
From: NightStrike @ 2008-02-25 16:46 UTC (permalink / raw)
  To: Kai Tietz; +Cc: Joseph S. Myers, Danny Smith, GCC Patches

On 2/19/08, Kai Tietz <Kai.Tietz@onevision.com> wrote:
> Is this ok for apply to trunk?

Kai informed me that he will be unavailable for a week or so, and will
be unable to apply this patch (latest one from 6 days ago, the 19th of
February).  Can someone else?

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf           formatters to c-format.c
  2008-02-19 14:10               ` Joseph S. Myers
@ 2008-02-19 15:16                 ` Kai Tietz
  2008-02-25 16:46                   ` NightStrike
  2008-02-25 18:53                   ` Joseph S. Myers
  0 siblings, 2 replies; 61+ messages in thread
From: Kai Tietz @ 2008-02-19 15:16 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: Danny Smith, GCC Patches, NightStrike

[-- Attachment #1: Type: text/plain, Size: 6870 bytes --]

"Joseph S. Myers" <joseph@codesourcery.com> wrote on 19.02.2008 15:01:10:

> On Tue, 19 Feb 2008, Kai Tietz wrote:
> 
> > What's about extending the attribute definition structure by a kind 
member 
> > and compare instead of index position, there kind? So this function is 
no 
> > longer necessary and we need just in the c-format.h enum values 
defining 
> > kinds.
> > 
> > typedef enum {
> >  attr_kind_printf=0,
> >  attr_kind_scanf,
> >  ...
> > } attr_kind;
> 
> That would be better, but it's still the wrong abstraction level.  We 
> should never be asking the question "is this a printf format?". Instead, 

> we should ask "does this have property X that is relevant for this piece 

> of code?".  Property X would then have its own flag set in the structure 

> for printf.
> 
> There's a check against strftime_format_type; we already have the right 
> flag for that, FMT_FLAG_ARG_CONVERT.  There are also checks against 
> GCC-internal types; those could stay, since they won't get 
system-specific 
> variants, or they could get a few more flags (for the three essentially 
> different styles of internal format that get handled differently in 
> handle_format_attribute where these checks appear).

Ok, I removed the cmp_formatter_kind method. Additionally I removed the 
copy of the enum from format.h.

Is this ok for apply to trunk?

2008-02-19      Kai Tietz  <kai.tietz@onevision.com>

        * c-format.c: (replace_formatter_name_to_system_name): New.
        (cmp_attribs): New.
        (convert_formatter_name_to_system_name): New.
        (decode_format_attr): Use of 
replace_formatter_name_to_system_name.
        (format_types_orig): Add gnu_ prefix to names.
        (check_format_info_main): Special treating of \0 escaped names for
        supporting multi-character formatters as I32, I64.
        (TARGET_OVERRIDES_FORMAT_ATTRIBUTES): Use of user defined 
attributes.
        (gnu_target_overrides_format_attributes): New.
        * gcc/c-format.h: Add structure target_ovr_attr to hold
        system specific formatter names.
        * config.gcc: Add for x86&x86_64 cygwin and mingw32 targets the
        msformat-c.o file to c_target_objs and cxx_target_objs.
        * config/i386/mingw32.h: (TARGET_OVERRIDES_FORMAT_ATTRIBUTES): 
New.
        (TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT): New.
        (TARGET_N_FORMAT_TYPES): New.
        * config/i386/msformat-c.c: New.
        * config/i386/t-cygming: Add build rule for msformat-c.o.
        * doc/extend.texi: Add new format names gnu_* and ms_*.
        * doc/tm.texi: (TARGET_OVERRIDES_FORMAT_ATTRIBUTES): New.

ChangeLog for gcc/testcase

2008-02-19  Kai Tietz  <kai.tietz@onevision.com>

        * gcc.dg/format/ms_array-1.c: New.
        * gcc.dg/format/ms_c90-scanf-3.c: New.
        * gcc.dg/format/ms_c99-strftime-1.c: New.
        * gcc.dg/format/ms_no-y2k-1.c: New.
        * gcc.dg/format/ms_attr-1.c: New.
        * gcc.dg/format/ms_c90-scanf-4.c: New.
        * gcc.dg/format/ms_c99-strftime-2.c: New.
        * gcc.dg/format/ms_nonlit-1.c: New.
        * gcc.dg/format/ms_c90-scanf-5.c: New.
        * gcc.dg/format/ms_cast-1.c: New.
        * gcc.dg/format/ms_nonlit-2.c: New.
        * gcc.dg/format/ms_attr-2.c: New.
        * gcc.dg/format/ms_c90-strftime-1.c: New.
        * gcc.dg/format/ms_miss-1.c: New.
        * gcc.dg/format/ms_nonlit-3.c: New.
        * gcc.dg/format/ms_attr-3.c: New.
        * gcc.dg/format/ms_c90-strftime-2.c: New.
        * gcc.dg/format/ms_miss-2.c: New.
        * gcc.dg/format/ms_nul-1.c: New.
        * gcc.dg/format/ms_attr-4.c: New.
        * gcc.dg/format/ms_c94-printf-1.c: New.
        * gcc.dg/format/ms_miss-3.c: New.
        * gcc.dg/format/ms_nul-2.c: New.
        * gcc.dg/format/ms_attr-7.c: New.
        * gcc.dg/format/ms_c94-scanf-1.c: New.
        * gcc.dg/format/ms_miss-4.c: New.
        * gcc.dg/format/ms_null-1.c: New.
        * gcc.dg/format/ms_bitfld-1.c: New.
        * gcc.dg/format/ms_c99-printf-1.c: New.
        * gcc.dg/format/ms_miss-5.c: New.
        * gcc.dg/format/ms_plus-1.c: New.
        * gcc.dg/format/ms_branch-1.c: New.
        * gcc.dg/format/ms_c99-printf-2.c: New.
        * gcc.dg/format/ms_miss-6.c: New.
        * gcc.dg/format/ms_sec-1.c: New.
        * gcc.dg/format/ms_c90-printf-1.c: New.
        * gcc.dg/format/ms_c99-printf-3.c: New.
        * gcc.dg/format/ms_multattr-1.c: New.
        * gcc.dg/format/ms_unnamed-1.c: New.
        * gcc.dg/format/ms_c90-printf-2.c: New.
        * gcc.dg/format/ms_c99-scanf-1.c: New.
        * gcc.dg/format/ms_multattr-2.c: New.
        * gcc.dg/format/ms_va-1.c: New.
        * gcc.dg/format/ms_c90-printf-3.c: New.
        * gcc.dg/format/ms_c99-scanf-2.c: New.
        * gcc.dg/format/ms_multattr-3.c: New.
        * gcc.dg/format/ms_warnll-1.c: New.
        * gcc.dg/format/ms_c90-scanf-1.c: New.
        * gcc.dg/format/ms_c99-scanf-3.c: New.
        * gcc.dg/format/ms_no-exargs-1.c: New.
        * gcc.dg/format/ms_zero-length-1.c: New.
        * gcc.dg/format/ms_c90-scanf-2.c: New.
        * gcc.dg/format/ms_c99-scanf-4.c: New.
        * gcc.dg/format/ms_no-exargs-2.c: New.
        * gcc.dg/format/null-1.c: Add gnu style usage for mingw.
        * gcc.dg/format/miss-1.c: Likewise.
        * gcc.dg/format/miss-3.c: Likewise.
        * gcc.dg/format/multattr-2.c: Likewise.
        * gcc.dg/format/miss-5.c: Likewise.
        * gcc.dg/format/attr-2.c: Likewise.
        * gcc.dg/format/attr-4.c: Likewise.
        * gcc.dg/format/c90-scanf-4.c: Likewise.
        * gcc.dg/format/c99-printf-3.c: Likewise.
        * gcc.dg/format/multattr-1.c: Likewise.
        * gcc.dg/format/miss-4.c: Likewise.
        * gcc.dg/format/miss-6.c: Likewise.
        * gcc.dg/format/c90-printf-3.c: Likewise.
        * gcc.dg/format/attr-1.c: Likewise.
        * gcc.dg/format/attr-3.c: Likewise.
        * gcc.dg/format/attr-7.c: Likewise.
        * gcc.dg/format/format.h: Treat mingw and gnu style.
        * gcc.dg/format/sys_format.c: New.



  Kai Tietz



|  (\_/)  This is Bunny. Copy and paste Bunny
| (='.'=) into your signature to help him gain
| (")_(") world domination.

------------------------------------------------------------------------------------------
  OneVision Software Entwicklungs GmbH & Co. KG
  Dr.-Leo-Ritter-Straße 9 - 93049 Regensburg
  Tel: +49.(0)941.78004.0 - Fax: +49.(0)941.78004.489 - www.OneVision.com
  Commerzbank Regensburg - BLZ 750 400 62 - Konto 6011050
  Handelsregister: HRA 6744, Amtsgericht Regensburg
  Komplementärin: OneVision Software Entwicklungs Verwaltungs GmbH
  Dr.-Leo-Ritter-Straße 9 – 93049 Regensburg
  Handelsregister: HRB 8932, Amtsgericht Regensburg - Geschäftsführer: 
Ulrike Döhler, Manuela Kluger


[-- Attachment #2: mingw-msformat.txt --]
[-- Type: text/plain, Size: 154797 bytes --]

Index: gcc/gcc/c-format.c
===================================================================
--- gcc.orig/gcc/c-format.c
+++ gcc/gcc/c-format.c
@@ -62,8 +62,7 @@ enum format_type { printf_format_type, a
 		   gcc_diag_format_type, gcc_tdiag_format_type,
 		   gcc_cdiag_format_type,
 		   gcc_cxxdiag_format_type, gcc_gfc_format_type,
-		   scanf_format_type, strftime_format_type,
-		   strfmon_format_type, format_type_error = -1};
+		   format_type_error = -1};
 
 typedef struct function_format_info
 {
@@ -80,7 +79,8 @@ static bool check_format_string (tree ar
 				 int flags, bool *no_add_attrs);
 static bool get_constant (tree expr, unsigned HOST_WIDE_INT *value,
 			  int validated_p);
-
+static const char *convert_formatter_name_to_system_name (const char *attr_name);
+static bool cmp_attribs (const char *tattr_name, const char *attr_name);
 
 /* Handle a "format_arg" attribute; arguments as in
    struct attribute_spec.handler.  */
@@ -191,6 +191,8 @@ decode_format_attr (tree args, function_
     {
       const char *p = IDENTIFIER_POINTER (format_type_id);
 
+      p = convert_formatter_name_to_system_name (p);
+
       info->format_type = decode_format_type (p);
 
       if (info->format_type == format_type_error)
@@ -715,7 +717,7 @@ static const format_char_info monetary_c
 /* This must be in the same order as enum format_type.  */
 static const format_kind_info format_types_orig[] =
 {
-  { "printf",   printf_length_specs,  print_char_table, " +#0-'I", NULL,
+  { "gnu_printf",   printf_length_specs,  print_char_table, " +#0-'I", NULL,
     printf_flag_specs, printf_flag_pairs,
     FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
     'w', 0, 'p', 0, 'L', 0,
@@ -757,18 +759,18 @@ static const format_kind_info format_typ
     0, 0, 0, 0, 0, 0,
     NULL, NULL
   },
-  { "scanf",    scanf_length_specs,   scan_char_table,  "*'I", NULL,
+  { "gnu_scanf",    scanf_length_specs,   scan_char_table,  "*'I", NULL,
     scanf_flag_specs, scanf_flag_pairs,
     FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
     'w', 0, 0, '*', 'L', 'm',
     NULL, NULL
   },
-  { "strftime", NULL,                 time_char_table,  "_-0^#", "EO",
+  { "gnu_strftime", NULL,                 time_char_table,  "_-0^#", "EO",
     strftime_flag_specs, strftime_flag_pairs,
     FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0, 0,
     NULL, NULL
   },
-  { "strfmon",  strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
+  { "gnu_strfmon",  strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
     strfmon_flag_specs, strfmon_flag_pairs,
     FMT_FLAG_ARG_CONVERT, 'w', '#', 'p', 0, 'L', 0,
     NULL, NULL
@@ -847,6 +849,8 @@ decode_format_type (const char *s)
 {
   int i;
   int slen;
+
+  s = convert_formatter_name_to_system_name (s);
   slen = strlen (s);
   for (i = 0; i < n_format_types; i++)
     {
@@ -1776,7 +1780,22 @@ check_format_info_main (format_check_res
       if (fli)
 	{
 	  while (fli->name != 0 && fli->name[0] != *format_chars)
-	    fli++;
+	    {
+	      if (fli->name[0] == '\0')
+		{
+		  int si  = strlen (fli->name + 1) + 1;
+		  int i = 1;
+		  while (fli->name[i] != 0 && fli->name[i] == format_chars [i - 1])
+		    ++i;
+		 if (si == i)
+		   {
+		     if (si > 2)
+		       format_chars += si - 2;
+		     break;
+		   }
+	       }
+	      fli++;
+	    }
 	  if (fli->name != 0)
 	    {
 	      format_chars++;
@@ -2703,6 +2722,81 @@ init_dynamic_diag_info (void)
 extern const format_kind_info TARGET_FORMAT_TYPES[];
 #endif
 
+#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+extern const target_ovr_attr TARGET_OVERRIDES_FORMAT_ATTRIBUTES[];
+#endif
+
+/* Attributes such as "printf" are equivalent to those such as
+   "gnu_printf" unless this is overridden by a target.  */
+static const target_ovr_attr gnu_target_overrides_format_attributes[] =
+{
+  { "gnu_printf",   "printf" },
+  { "gnu_scanf",    "scanf" },
+  { "gnu_strftime", "strftime" },
+  { "gnu_strfmon",  "strfmon" },
+  { NULL,           NULL }
+};
+
+/* Translate to unified attribute name. This is used in decode_format_type and
+   decode_format_attr. In attr_name the user specified argument is passed. It
+   returns the unified formatter name from TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+   or the attr_name passed to this function, if there is no matching entry.  */
+static const char *
+convert_formatter_name_to_system_name (const char *attr_name)
+{
+  int i;
+
+  if (attr_name == NULL || *attr_name == 0 || strncmp (attr_name, "gcc_", 4) == 0)
+    return attr_name;
+
+#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+  /* Check if format attribute is overridden by target.  */
+  if (TARGET_OVERRIDES_FORMAT_ATTRIBUTES != NULL
+      && TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT > 0)
+    {
+      for (i = 0; i < TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT; ++i)
+        {
+          if (cmp_attribs (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src,
+			   attr_name))
+            return attr_name;
+          if (cmp_attribs (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_dst,
+			   attr_name))
+            return TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src;
+        }
+    }
+#endif
+  /* Otherwise default to gnu formatter.  */
+  for (i = 0; gnu_target_overrides_format_attributes[i].named_attr_src != NULL; ++i)
+    {
+      if (cmp_attribs (gnu_target_overrides_format_attributes[i].named_attr_src,
+		       attr_name))
+        return attr_name;
+      if (cmp_attribs (gnu_target_overrides_format_attributes[i].named_attr_dst,
+		       attr_name))
+        return gnu_target_overrides_format_attributes[i].named_attr_src;
+    }
+
+  return attr_name;
+}
+
+/* Return true if TATTR_NAME and ATTR_NAME are the same format attribute,
+   counting "name" and "__name__" as the same, false otherwise.  */
+static bool
+cmp_attribs (const char *tattr_name, const char *attr_name)
+{
+  int alen = strlen (attr_name);
+  int slen = (tattr_name ? strlen (tattr_name) : 0);
+  if (alen > 4 && attr_name[0] == '_' && attr_name[1] == '_'
+      && attr_name[alen - 1] == '_' && attr_name[alen - 2] == '_')
+    {
+      attr_name += 2;
+      alen -= 4;
+    }
+  if (alen != slen || strncmp (tattr_name, attr_name, alen) != 0)
+    return false;
+  return true;
+}
+
 /* Handle a "format" attribute; arguments as in
    struct attribute_spec.handler.  */
 tree
@@ -2762,7 +2856,9 @@ handle_format_attribute (tree *node, tre
 	}
     }
 
-  if (info.format_type == strftime_format_type && info.first_arg_num != 0)
+  /* Check if this is a strftime variant. Just for this variant
+     FMT_FLAG_ARG_CONVERT is not set.  */
+  if ((info.flags & FMT_FLAG_ARG_CONVERT) == 0) && info.first_arg_num != 0)
     {
       error ("strftime formats cannot format arguments");
       *no_add_attrs = true;
Index: gcc/gcc/c-format.h
===================================================================
--- gcc.orig/gcc/c-format.h
+++ gcc/gcc/c-format.h
@@ -80,12 +80,13 @@ enum
      of whether length modifiers can occur (length_char_specs).  */
 };
 
-
 /* Structure describing a length modifier supported in format checking, and
    possibly a doubled version such as "hh".  */
 typedef struct
 {
-  /* Name of the single-character length modifier.  */
+  /* Name of the single-character length modifier. If prefixed by
+     a zero character, it discribes a multi character length
+     modifier, lile I64, I32, etc.  */
   const char *name;
   /* Index into a format_char_info.types array.  */
   enum format_lengths index;
@@ -306,4 +307,16 @@ typedef struct
 #define T_D128  &dfloat128_type_node
 #define TEX_D128 { STD_EXT, "_Decimal128", T_D128 }
 
+/* Structure describing how format attributes such as "printf" are
+   interpreted as "gnu_printf" or "ms_printf" on a particular system.
+   TARGET_OVERRIDES_FORMAT_ATTRIBUTES is used to specify target-specific
+   defaults.  */
+typedef struct
+{
+  /* The name of the to be copied formatter attribute. */
+  const char *named_attr_src;
+  /* The name of the to be overridden formatter attribute. */
+  const char *named_attr_dst;
+} target_ovr_attr;
+
 #endif /* GCC_C_FORMAT_H */
Index: gcc/gcc/config.gcc
===================================================================
--- gcc.orig/gcc/config.gcc
+++ gcc/gcc/config.gcc
@@ -1365,8 +1365,8 @@ i[34567]86-*-pe | i[34567]86-*-cygwin*)
 	target_gtfiles="\$(srcdir)/config/i386/winnt.c"
 	extra_options="${extra_options} i386/cygming.opt"
 	extra_objs="winnt.o winnt-stubs.o"
-	c_target_objs=cygwin2.o
-	cxx_target_objs="cygwin2.o winnt-cxx.o"
+	c_target_objs="cygwin2.o msformat-c.o"
+	cxx_target_objs="cygwin2.o winnt-cxx.o msformat-c.o"
 	extra_gcc_objs=cygwin1.o
 	if test x$enable_threads = xyes; then
 		thread_file='posix'
@@ -1379,7 +1379,8 @@ i[34567]86-*-mingw32* | x86_64-*-mingw32
 	target_gtfiles="\$(srcdir)/config/i386/winnt.c"
 	extra_options="${extra_options} i386/cygming.opt"
 	extra_objs="winnt.o winnt-stubs.o"
-	cxx_target_objs=winnt-cxx.o
+	c_target_objs="msformat-c.o"
+	cxx_target_objs="winnt-cxx.o msformat-c.o"
 	default_use_cxa_atexit=yes
 	case ${enable_threads} in
 	  "" | yes | win32)
Index: gcc/gcc/config/i386/mingw32.h
===================================================================
--- gcc.orig/gcc/config/i386/mingw32.h
+++ gcc/gcc/config/i386/mingw32.h
@@ -143,6 +143,22 @@ do {						         \
    to register C++ static destructors.  */
 #define TARGET_CXX_USE_ATEXIT_FOR_CXA_ATEXIT hook_bool_void_true
 
+/* Contains a pointer to type target_ovr_attr defining the target specific
+   overrides of formatter attributs.  See format.h for structure definition.  */
+#undef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+#define TARGET_OVERRIDES_FORMAT_ATTRIBUTES mingw_formatter_attribute_overrides
+
+/* Specify the count of elements in TARGET_OVERRIDES_ATTRIBUTE.  */
+#undef TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT
+#define TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT 3
+
+/* MS specific format attributes for ms_printf, ms_scanf, ms_strftime.  */
+#undef TARGET_FORMAT_TYPES
+#define TARGET_FORMAT_TYPES mingw_formatter_attributes
+
+#undef TARGET_N_FORMAT_TYPES
+#define TARGET_N_FORMAT_TYPES 3
+
 /* JCR_SECTION works on mingw32.  */
 #undef TARGET_USE_JCR_SECTION
 #define TARGET_USE_JCR_SECTION 1
Index: gcc/gcc/config/i386/msformat-c.c
===================================================================
--- /dev/null
+++ gcc/gcc/config/i386/msformat-c.c
@@ -0,0 +1,188 @@
+/* Check calls to formatted I/O functions (-Wformat).
+   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+   2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "flags.h"
+#include "c-common.h"
+#include "toplev.h"
+#include "intl.h"
+#include "diagnostic.h"
+#include "langhooks.h"
+#include "c-format.h"
+#include "alloc-pool.h"
+
+/* Mingw specific format attributes ms_printf, ms_scanf, and ms_strftime.  */
+
+static const format_length_info ms_printf_length_specs[] =
+{
+  { "h", FMT_LEN_h, STD_C89, NULL, 0, 0 },
+  { "l", FMT_LEN_l, STD_C89, NULL, 0, 0 },
+  { "\0I32", FMT_LEN_l, STD_EXT, NULL, 0, 0 },
+  { "\0I64", FMT_LEN_ll, STD_EXT, NULL, 0, 0 },
+  { "I", FMT_LEN_L, STD_EXT, NULL, 0, 0 },
+  { NULL, 0, 0, NULL, 0, 0 }
+};
+
+static const format_flag_spec ms_printf_flag_specs[] =
+{
+  { ' ',  0, 0, N_("' ' flag"),        N_("the ' ' printf flag"),              STD_C89 },
+  { '+',  0, 0, N_("'+' flag"),        N_("the '+' printf flag"),              STD_C89 },
+  { '#',  0, 0, N_("'#' flag"),        N_("the '#' printf flag"),              STD_C89 },
+  { '0',  0, 0, N_("'0' flag"),        N_("the '0' printf flag"),              STD_C89 },
+  { '-',  0, 0, N_("'-' flag"),        N_("the '-' printf flag"),              STD_C89 },
+  { '\'', 0, 0, N_("''' flag"),        N_("the ''' printf flag"),              STD_EXT },
+  { 'w',  0, 0, N_("field width"),     N_("field width in printf format"),     STD_C89 },
+  { 'p',  0, 0, N_("precision"),       N_("precision in printf format"),       STD_C89 },
+  { 'L',  0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_printf_flag_pairs[] =
+{
+  { ' ', '+', 1, 0   },
+  { '0', '-', 1, 0   }, { '0', 'p', 1, 'i' },
+  { 0, 0, 0, 0 }
+};
+
+static const format_flag_spec ms_scanf_flag_specs[] =
+{
+  { '*',  0, 0, N_("assignment suppression"), N_("the assignment suppression scanf feature"), STD_C89 },
+  { 'a',  0, 0, N_("'a' flag"),               N_("the 'a' scanf flag"),                       STD_EXT },
+  { 'w',  0, 0, N_("field width"),            N_("field width in scanf format"),              STD_C89 },
+  { 'L',  0, 0, N_("length modifier"),        N_("length modifier in scanf format"),          STD_C89 },
+  { '\'', 0, 0, N_("''' flag"),               N_("the ''' scanf flag"),                       STD_EXT },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_scanf_flag_pairs[] =
+{
+  { '*', 'L', 0, 0 },
+  { 0, 0, 0, 0 }
+};
+
+static const format_flag_spec ms_strftime_flag_specs[] =
+{
+  { '_', 0,   0, N_("'_' flag"),     N_("the '_' strftime flag"),          STD_EXT },
+  { '-', 0,   0, N_("'-' flag"),     N_("the '-' strftime flag"),          STD_EXT },
+  { '0', 0,   0, N_("'0' flag"),     N_("the '0' strftime flag"),          STD_EXT },
+  { '^', 0,   0, N_("'^' flag"),     N_("the '^' strftime flag"),          STD_EXT },
+  { '#', 0,   0, N_("'#' flag"),     N_("the '#' strftime flag"),          STD_EXT },
+  { 'w', 0,   0, N_("field width"),  N_("field width in strftime format"), STD_EXT },
+  { 'E', 0,   0, N_("'E' modifier"), N_("the 'E' strftime modifier"),      STD_C99 },
+  { 'O', 0,   0, N_("'O' modifier"), N_("the 'O' strftime modifier"),      STD_C99 },
+  { 'O', 'o', 0, NULL,               N_("the 'O' modifier"),               STD_EXT },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_strftime_flag_pairs[] =
+{
+  { 'E', 'O', 0, 0 },
+  { '_', '-', 0, 0 },
+  { '_', '0', 0, 0 },
+  { '-', '0', 0, 0 },
+  { '^', '#', 0, 0 },
+  { 0, 0, 0, 0 }
+};
+
+static const format_char_info ms_print_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "di",  0, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  T99_SST,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-wp0 +'",  "i",  NULL },
+  { "oxX", 0, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN, BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "-wp0#",     "i",  NULL },
+  { "u",   0, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN, BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "-wp0'",    "i",  NULL },
+  { "fgG", 0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "-wp0 +#'", "",   NULL },
+  { "eE",  0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "-wp0 +#",  "",   NULL },
+  { "c",   0, STD_C89, { T89_I,   BADLEN,  T89_S,  T94_WI,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "",   NULL },
+  { "s",   1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-wp",       "cR", NULL },
+  { "p",   1, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "c",  NULL },
+  { "n",   1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  BADLEN,  BADLEN, BADLEN,  T99_IM,  BADLEN,  BADLEN,  BADLEN }, "",          "W",  NULL },
+  /* X/Open conversion specifiers.  */
+  { "C",   0, STD_EXT, { TEX_WI,  BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "",   NULL },
+  { "S",   1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-wp",       "R",  NULL },
+  { NULL,  0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+static const format_char_info ms_scan_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "di",    1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  T99_SST,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w'", "W",   NULL },
+  { "u",     1, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN,  BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "*w'", "W",   NULL },
+  { "oxX",   1, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN,  BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "efgEG", 1, STD_C89, { T89_F,   BADLEN,  BADLEN,  T89_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "*w'",  "W",   NULL },
+  { "c",     1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "cW",  NULL },
+  { "s",     1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "cW",  NULL },
+  { "[",     1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "cW[", NULL },
+  { "p",     2, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "n",     1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  BADLEN,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "",     "W",   NULL },
+  /* X/Open conversion specifiers.  */
+  { "C",     1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "S",     1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "W",   NULL },
+  { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+static const format_char_info ms_time_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "ABZab",		0, STD_C89, NOLENGTHS, "^#",     "",   NULL },
+  { "cx",		0, STD_C89, NOLENGTHS, "E",      "3",  NULL },
+  { "HIMSUWdmw",	0, STD_C89, NOLENGTHS, "-_0Ow",  "",   NULL },
+  { "j",		0, STD_C89, NOLENGTHS, "-_0Ow",  "o",  NULL },
+  { "p",		0, STD_C89, NOLENGTHS, "#",      "",   NULL },
+  { "X",		0, STD_C89, NOLENGTHS, "E",      "",   NULL },
+  { "y",		0, STD_C89, NOLENGTHS, "EO-_0w", "4",  NULL },
+  { "Y",		0, STD_C89, NOLENGTHS, "-_0EOw", "o",  NULL },
+  { "%",		0, STD_C89, NOLENGTHS, "",       "",   NULL },
+  /* C99 conversion specifiers.  */
+  { "z",		0, STD_C99, NOLENGTHS, "O",      "o",  NULL },
+  { NULL,		0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+const format_kind_info mingw_formatter_attributes[3] =
+{
+  { "ms_printf",   ms_printf_length_specs,  ms_print_char_table, " +#0-'", NULL,
+    ms_printf_flag_specs, ms_printf_flag_pairs,
+    FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
+    'w', 0, 'p', 0, 'L', 0,
+    &integer_type_node, &integer_type_node
+  },
+  { "ms_scanf",    ms_printf_length_specs,   ms_scan_char_table,  "*'", NULL,
+    ms_scanf_flag_specs, ms_scanf_flag_pairs,
+    FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
+    'w', 0, 0, '*', 'L', 0,
+    NULL, NULL
+  },
+  { "ms_strftime", NULL,                 ms_time_char_table,  "_-0^#", "EO",
+    ms_strftime_flag_specs, ms_strftime_flag_pairs,
+    FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0, 0,
+    NULL, NULL
+  }
+};
+
+/* Default overrides for printf, scanf and strftime.  */
+const target_ovr_attr mingw_formatter_attribute_overrides[4] =
+{
+  { "ms_printf", "printf" },
+  { "ms_scanf", "scanf" },
+  { "ms_strftime", "strftime" }
+};
Index: gcc/gcc/config/i386/t-cygming
===================================================================
--- gcc.orig/gcc/config/i386/t-cygming
+++ gcc/gcc/config/i386/t-cygming
@@ -29,4 +29,10 @@ winnt-stubs.o: $(srcdir)/config/i386/win
 	$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
 	$(srcdir)/config/i386/winnt-stubs.c
 
+msformat-c.o: $(srcdir)/config/i386/msformat-c.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
+  $(TM_H) $(RTL_H) $(REGS_H) hard-reg-set.h output.h $(TREE_H) flags.h \
+  $(TM_P_H) toplev.h $(HASHTAB_H) $(GGC_H)
+	$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
+	$(srcdir)/config/i386/msformat-c.c
+
 STMP_FIXINC=stmp-fixinc
Index: gcc/gcc/doc/extend.texi
===================================================================
--- gcc.orig/gcc/doc/extend.texi
+++ gcc/gcc/doc/extend.texi
@@ -2204,13 +2204,17 @@ for consistency with the @code{printf} s
 @code{my_format}.
 
 The parameter @var{archetype} determines how the format string is
-interpreted, and should be @code{printf}, @code{scanf}, @code{strftime}
-or @code{strfmon}.  (You can also use @code{__printf__},
-@code{__scanf__}, @code{__strftime__} or @code{__strfmon__}.)  The
-parameter @var{string-index} specifies which argument is the format
-string argument (starting from 1), while @var{first-to-check} is the
-number of the first argument to check against the format string.  For
-functions where the arguments are not available to be checked (such as
+interpreted, and should be @code{printf}, @code{scanf}, @code{strftime},
+@code{gnu_printf}, @code{gnu_scanf}, @code{gnu_strftime} or
+@code{strfmon}.  (You can also use @code{__printf__},
+@code{__scanf__}, @code{__strftime__} or @code{__strfmon__}.)  On
+mingw targets there is also @code{ms_printf}, @code{ms_scanf}, and
+@code{ms_strftime} present. The none target specific formatters are
+always the variant of the system.  The parameter @var{string-index}
+specifies which argument is the format string argument (starting
+from 1), while @var{first-to-check} is the number of the first
+argument to check against the format string.  For functions
+where the arguments are not available to be checked (such as
 @code{vprintf}), specify the third parameter as zero.  In this case the
 compiler only checks the format string for consistency.  For
 @code{strftime} formats, the third parameter is required to be zero.
Index: gcc/gcc/doc/tm.texi
===================================================================
--- gcc.orig/gcc/doc/tm.texi
+++ gcc/gcc/doc/tm.texi
@@ -10319,6 +10319,18 @@ If defined, this macro is the number of 
 @code{TARGET_FORMAT_TYPES}.
 @end defmac
 
+@defmac TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+If defined, this macro is the name of a global variable containg
+target-specific format overrides for the @option{-Wformat} option. The
+default is to have no target-specific format overrides. If defined,
+@code{TARGET_FORMAT_TYPES} must be defined too.
+@end defmac
+
+@defmac TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT
+If defined, this macro specifies the number of entries in
+@code{TARGET_OVERRIDES_FORMAT_ATTRIBUTES}.
+@end defmac
+
 @deftypefn {Target Hook} bool TARGET_RELAXED_ORDERING
 If set to @code{true}, means that the target's memory model does not
 guarantee that loads which do not depend on one another will access
Index: gcc/gcc/testsuite/gcc.dg/format/format.h
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/format.h
+++ gcc/gcc/testsuite/gcc.dg/format/format.h
@@ -1,6 +1,37 @@
 /* Format checking tests: common header.  */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
 
+/* DONT_GNU_PROTOTYPE */
+#if defined (_WIN32) && !defined (__CYGWIN__)
+#if !defined (USE_SYSTEM_FORMATS)
+#define gnu_attr_printf	gnu_printf
+#define gnu_attr___printf__ __gnu_printf__
+#define gnu_attr_scanf	gnu_scanf
+#define gnu_attr___scanf__ __gnu_scanf__
+#define gnu_attr_strftime gnu_strftime
+#define gnu_attr___strftime__ __gnu_strftime__
+#endif
+#endif
+
+#ifndef gnu_attr_printf
+#define gnu_attr_printf	printf
+#define gnu_attr___printf__ __printf__
+#define gnu_attr_scanf	scanf
+#define gnu_attr___scanf__ __scanf__
+#define gnu_attr_strftime strftime
+#define gnu_attr___strftime__ __strftime__
+#endif
+
+#if !defined (USE_SYSTEM_FORMATS)
+#define USE_PRINTF(FMTPOS, WILDARG) __attribute__((format(gnu_printf, FMTPOS, WILDARG))) __attribute__((nonnull (FMTPOS)))
+#define USE_SCANF(FMTPOS, WILDARG) __attribute__((format(gnu_scanf, FMTPOS, WILDARG))) __attribute__((nonnull (FMTPOS)))
+#define USE_STRFTIME(FMTPOS) __attribute__((__format__(gnu_strftime, FMTPOS, 0))) __attribute__((nonnull (FMTPOS)))
+#else
+#define USE_PRINTF(FMTPOS, WILDARG)
+#define USE_SCANF(FMTPOS, WILDARG)
+#define USE_STRFTIME(FMTPOS)
+#endif
+
 #include <stdarg.h>
 #include <stddef.h>
 
@@ -11,6 +42,20 @@
 typedef __WINT_TYPE__ wint_t;
 #endif
 
+#ifdef _WIN64
+/* Kludges to get types corresponding to size_t and ptrdiff_t.  */
+#define unsigned signed
+typedef signed int signed_size_t __attribute__ ((mode (DI)));
+/* We also use this type to approximate ssize_t.  */
+typedef signed int ssize_t __attribute__ ((mode (DI)));
+#undef unsigned
+#define signed /* Type might or might not have explicit 'signed'.  */
+typedef unsigned int unsigned_ptrdiff_t __attribute__ ((mode (DI)));
+#undef signed
+
+__extension__ typedef int llong  __attribute__ ((mode (DI)));
+__extension__ typedef unsigned int ullong  __attribute__ ((mode (DI)));
+#else
 /* Kludges to get types corresponding to size_t and ptrdiff_t.  */
 #define unsigned signed
 typedef __SIZE_TYPE__ signed_size_t;
@@ -23,6 +68,7 @@ typedef unsigned __PTRDIFF_TYPE__ unsign
 
 __extension__ typedef long long int llong;
 __extension__ typedef unsigned long long int ullong;
+#endif
 
 /* %q formats want a "quad"; GCC considers this to be a long long.  */
 typedef llong quad_t;
@@ -70,3 +116,77 @@ extern size_t strftime (char *restrict, 
 			const struct tm *restrict);
 
 extern ssize_t strfmon (char *restrict, size_t, const char *restrict, ...);
+
+/* Mingw specific part.  */
+#if !defined (USE_SYSTEM_FORMATS) && defined(_WIN32) && !defined(DONT_GNU_PROTOTYPE)
+
+extern USE_PRINTF(2,3) int fprintf_gnu (FILE *restrict, const char *restrict, ...);
+#undef fprintf
+#define fprintf fprintf_gnu
+
+extern USE_PRINTF(1,2) int printf_gnu (const char *restrict, ...);
+#undef printf
+#define printf printf_gnu
+
+extern USE_PRINTF(2,3) int fprintf_unlocked_gnu (FILE *restrict, const char *restrict, ...);
+#undef fprintf_unlocked
+#define fprintf_unlocked fprintf_unlocked_gnu
+
+extern USE_PRINTF(1,2)int printf_unlocked_gnu (const char *restrict, ...);
+#undef printf_unlocked
+#define printf_unlocked printf_unlocked_gnu
+
+extern USE_PRINTF(2,3) int sprintf_gnu (char *restrict, const char *restrict, ...);
+#undef sprintf
+#define sprintf sprintf_gnu
+
+extern USE_PRINTF(2,0) int vfprintf_gnu (FILE *restrict, const char *restrict, va_list);
+#undef vsprintf
+#define vsprintf vsprintf_gnu
+
+extern USE_PRINTF(1,0) int vprintf_gnu (const char *restrict, va_list);
+#undef vprintf
+#define vprintf vprintf_gnu
+
+extern USE_PRINTF(2,0) int vsprintf_gnu (char *restrict, const char *restrict, va_list);
+#undef vsprintf
+#define vsprintf vsprintf_gnu
+
+extern USE_PRINTF(3,4) int snprintf_gnu (char *restrict, size_t, const char *restrict, ...);
+#undef snprintf
+#define snprintf snprintf_gnu
+
+extern USE_PRINTF(3,0) int vsnprintf_gnu (char *restrict, size_t, const char *restrict, va_list);
+#undef vsnprintf
+#define vsnprintf vsnprintf_gnu
+
+extern USE_SCANF(2,3) int fscanf_gnu (FILE *restrict, const char *restrict, ...);
+#undef fscanf
+#define fscanf fscanf_gnu
+
+extern USE_SCANF(1,2) int scanf_gnu (const char *restrict, ...);
+#undef scanf
+#define scanf scanf_gnu
+
+extern USE_SCANF(2,3) int sscanf_gnu (const char *restrict, const char *restrict, ...);
+#undef sscanf
+#define sscanf sscanf_gnu
+
+extern USE_SCANF(2,0) int vfscanf_gnu (FILE *restrict, const char *restrict, va_list);
+#undef vfscanf
+#define vfscanf vfscanf_gnu
+
+extern USE_SCANF(1,0) int vscanf_gnu (const char *restrict, va_list);
+#undef vscanf
+#define vscanf vscanf_gnu
+
+extern USE_SCANF(2,0) int vsscanf_gnu (const char *restrict, const char *restrict, va_list);
+#undef vsscanf
+#define vsscanf vsscanf_gnu
+
+extern USE_STRFTIME(3) size_t strftime_gnu (char *restrict, size_t, const char *restrict,
+			const struct tm *restrict);
+#undef strftime
+#define strftime strftime_gnu
+
+#endif
Index: gcc/gcc/testsuite/gcc.dg/format/attr-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-1.c
@@ -3,7 +3,8 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern void foo0 (const char *) __attribute__((__format__(__strftime__, 1, 0)));
-extern void foo1 (const char *, ...) __attribute__((__format__(__strftime__, 1, 2))); /* { dg-error "cannot format" "strftime first_arg_num != 0" } */
+extern void foo0 (const char *) __attribute__((__format__(gnu_attr___strftime__, 1, 0)));
+extern void foo1 (const char *, ...) __attribute__((__format__(gnu_attr___strftime__, 1, 2))); /* { dg-error "cannot format" "strftime first_arg_num != 0" } */
Index: gcc/gcc/testsuite/gcc.dg/format/attr-2.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-2.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-2.c
@@ -3,22 +3,23 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern void tformatprintf (const char *, ...) __attribute__((format(printf, 1, 2)));
-extern void tformat__printf__ (const char *, ...) __attribute__((format(__printf__, 1, 2)));
-extern void tformatscanf (const char *, ...) __attribute__((format(scanf, 1, 2)));
-extern void tformat__scanf__ (const char *, ...) __attribute__((format(__scanf__, 1, 2)));
-extern void tformatstrftime (const char *) __attribute__((format(strftime, 1, 0)));
-extern void tformat__strftime__ (const char *) __attribute__((format(__strftime__, 1, 0)));
+extern void tformatprintf (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
+extern void tformat__printf__ (const char *, ...) __attribute__((format(gnu_attr___printf__, 1, 2)));
+extern void tformatscanf (const char *, ...) __attribute__((format(gnu_attr_scanf, 1, 2)));
+extern void tformat__scanf__ (const char *, ...) __attribute__((format(gnu_attr___scanf__, 1, 2)));
+extern void tformatstrftime (const char *) __attribute__((format(gnu_attr_strftime, 1, 0)));
+extern void tformat__strftime__ (const char *) __attribute__((format(gnu_attr___strftime__, 1, 0)));
 extern void tformatstrfmon (const char *, ...) __attribute__((format(strfmon, 1, 2)));
 extern void tformat__strfmon__ (const char *, ...) __attribute__((format(__strfmon__, 1, 2)));
-extern void t__format__printf (const char *, ...) __attribute__((__format__(printf, 1, 2)));
-extern void t__format____printf__ (const char *, ...) __attribute__((__format__(__printf__, 1, 2)));
-extern void t__format__scanf (const char *, ...) __attribute__((__format__(scanf, 1, 2)));
-extern void t__format____scanf__ (const char *, ...) __attribute__((__format__(__scanf__, 1, 2)));
-extern void t__format__strftime (const char *) __attribute__((__format__(strftime, 1, 0)));
-extern void t__format____strftime__ (const char *) __attribute__((__format__(__strftime__, 1, 0)));
+extern void t__format__printf (const char *, ...) __attribute__((__format__(gnu_attr_printf, 1, 2)));
+extern void t__format____printf__ (const char *, ...) __attribute__((__format__(gnu_attr___printf__, 1, 2)));
+extern void t__format__scanf (const char *, ...) __attribute__((__format__(gnu_attr_scanf, 1, 2)));
+extern void t__format____scanf__ (const char *, ...) __attribute__((__format__(gnu_attr___scanf__, 1, 2)));
+extern void t__format__strftime (const char *) __attribute__((__format__(gnu_attr_strftime, 1, 0)));
+extern void t__format____strftime__ (const char *) __attribute__((__format__(gnu_attr___strftime__, 1, 0)));
 extern void t__format__strfmon (const char *, ...) __attribute__((__format__(strfmon, 1, 2)));
 extern void t__format____strfmon__ (const char *, ...) __attribute__((__format__(__strfmon__, 1, 2)));
 
Index: gcc/gcc/testsuite/gcc.dg/format/attr-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-3.c
@@ -3,20 +3,21 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 /* Proper uses of the attributes.  */
-extern void fa0 (const char *, ...) __attribute__((format(printf, 1, 2)));
-extern void fa1 (char *, ...) __attribute__((format(printf, 1, 2)));
+extern void fa0 (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
+extern void fa1 (char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
 extern char *fa2 (const char *) __attribute__((format_arg(1)));
 extern char *fa3 (char *) __attribute__((format_arg(1)));
 
 /* Uses with too few or too many arguments.  */
 extern void fb0 (const char *, ...) __attribute__((format)); /* { dg-error "wrong number of arguments" "bad format" } */
 extern void fb1 (const char *, ...) __attribute__((format())); /* { dg-error "wrong number of arguments" "bad format" } */
-extern void fb2 (const char *, ...) __attribute__((format(printf))); /* { dg-error "wrong number of arguments" "bad format" } */
-extern void fb3 (const char *, ...) __attribute__((format(printf, 1))); /* { dg-error "wrong number of arguments" "bad format" } */
-extern void fb4 (const char *, ...) __attribute__((format(printf, 1, 2, 3))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb2 (const char *, ...) __attribute__((format(gnu_attr_printf))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb3 (const char *, ...) __attribute__((format(gnu_attr_printf, 1))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb4 (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2, 3))); /* { dg-error "wrong number of arguments" "bad format" } */
 
 extern void fc1 (const char *) __attribute__((format_arg)); /* { dg-error "wrong number of arguments" "bad format_arg" } */
 extern void fc2 (const char *) __attribute__((format_arg())); /* { dg-error "wrong number of arguments" "bad format_arg" } */
@@ -25,9 +26,9 @@ extern void fc3 (const char *) __attribu
 /* These attributes presently only apply to declarations, not to types.
    Eventually, they should be usable with declarators for function types
    anywhere, but still not with structure/union/enum types.  */
-struct s0 { int i; } __attribute__((format(printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on struct" } */
-union u0 { int i; } __attribute__((format(printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on union" } */
-enum e0 { E0V0 } __attribute__((format(printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on enum" } */
+struct s0 { int i; } __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on struct" } */
+union u0 { int i; } __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on union" } */
+enum e0 { E0V0 } __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on enum" } */
 
 struct s1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on struct" } */
 union u1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on union" } */
@@ -38,28 +39,28 @@ extern void fe0 (const char *, ...) __at
 extern void fe1 (const char *, ...) __attribute__((format(nosuch, 1, 2))); /* { dg-warning "format function type" "unknown format" } */
 
 /* Both the numbers must be integer constant expressions.  */
-extern void ff0 (const char *, ...) __attribute__((format(printf, 3-2, (long long)(10/5))));
+extern void ff0 (const char *, ...) __attribute__((format(gnu_attr_printf, 3-2, (long long)(10/5))));
 int foo;
-extern void ff1 (const char *, ...) __attribute__((format(printf, foo, 10/5))); /* { dg-error "invalid operand" "bad number" } */
-extern void ff2 (const char *, ...) __attribute__((format(printf, 3-2, foo))); /* { dg-error "invalid operand" "bad number" } */
+extern void ff1 (const char *, ...) __attribute__((format(gnu_attr_printf, foo, 10/5))); /* { dg-error "invalid operand" "bad number" } */
+extern void ff2 (const char *, ...) __attribute__((format(gnu_attr_printf, 3-2, foo))); /* { dg-error "invalid operand" "bad number" } */
 extern char *ff3 (const char *) __attribute__((format_arg(3-2)));
 extern char *ff4 (const char *) __attribute__((format_arg(foo))); /* { dg-error "invalid operand" "bad format_arg number" } */
 
 /* The format string argument must precede the arguments to be formatted.
    This includes if no parameter types are specified (which is not valid ISO
    C for variadic functions).  */
-extern void fg0 () __attribute__((format(printf, 1, 2)));
-extern void fg1 () __attribute__((format(printf, 1, 0)));
-extern void fg2 () __attribute__((format(printf, 1, 1))); /* { dg-error "follows" "bad number order" } */
-extern void fg3 () __attribute__((format(printf, 2, 1))); /* { dg-error "follows" "bad number order" } */
+extern void fg0 () __attribute__((format(gnu_attr_printf, 1, 2)));
+extern void fg1 () __attribute__((format(gnu_attr_printf, 1, 0)));
+extern void fg2 () __attribute__((format(gnu_attr_printf, 1, 1))); /* { dg-error "follows" "bad number order" } */
+extern void fg3 () __attribute__((format(gnu_attr_printf, 2, 1))); /* { dg-error "follows" "bad number order" } */
 
 /* The format string argument must be a string type, and the arguments to
    be formatted must be the "...".  */
-extern void fh0 (int, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "not a string" "format int string" } */
-extern void fh1 (signed char *, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "not a string" "signed char string" } */
-extern void fh2 (unsigned char *, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "not a string" "unsigned char string" } */
-extern void fh3 (const char *, ...) __attribute__((format(printf, 1, 3))); /* { dg-error "is not" "not ..." } */
-extern void fh4 (const char *, int, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "is not" "not ..." } */
+extern void fh0 (int, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "format int string" } */
+extern void fh1 (signed char *, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "signed char string" } */
+extern void fh2 (unsigned char *, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "unsigned char string" } */
+extern void fh3 (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 3))); /* { dg-error "is not" "not ..." } */
+extern void fh4 (const char *, int, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "is not" "not ..." } */
 
 /* format_arg formats must take and return a string.  */
 extern char *fi0 (int) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg int string" } */
Index: gcc/gcc/testsuite/gcc.dg/format/attr-4.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-4.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-4.c
@@ -4,12 +4,13 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern __attribute__((format(printf, 1, 2))) void tformatprintf0 (const char *, ...);
-extern void __attribute__((format(printf, 1, 2))) tformatprintf1 (const char *, ...);
-extern void foo (void), __attribute__((format(printf, 1, 2))) tformatprintf2 (const char *, ...);
-extern __attribute__((noreturn)) void bar (void), __attribute__((format(printf, 1, 2))) tformatprintf3 (const char *, ...);
+extern __attribute__((format(gnu_attr_printf, 1, 2))) void tformatprintf0 (const char *, ...);
+extern void __attribute__((format(gnu_attr_printf, 1, 2))) tformatprintf1 (const char *, ...);
+extern void foo (void), __attribute__((format(gnu_attr_printf, 1, 2))) tformatprintf2 (const char *, ...);
+extern __attribute__((noreturn)) void bar (void), __attribute__((format(gnu_attr_printf, 1, 2))) tformatprintf3 (const char *, ...);
 
 void
 baz (int i, int *ip, double d)
Index: gcc/gcc/testsuite/gcc.dg/format/attr-7.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-7.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-7.c
@@ -3,12 +3,13 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-__attribute__((format(printf, 1, 2))) void (*tformatprintf0) (const char *, ...);
-void (*tformatprintf1) (const char *, ...) __attribute__((format(printf, 1, 2)));
-void (__attribute__((format(printf, 1, 2))) *tformatprintf2) (const char *, ...);
-void (__attribute__((format(printf, 1, 2))) ****tformatprintf3) (const char *, ...);
+__attribute__((format(gnu_attr_printf, 1, 2))) void (*tformatprintf0) (const char *, ...);
+void (*tformatprintf1) (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
+void (__attribute__((format(gnu_attr_printf, 1, 2))) *tformatprintf2) (const char *, ...);
+void (__attribute__((format(gnu_attr_printf, 1, 2))) ****tformatprintf3) (const char *, ...);
 
 char * (__attribute__((format_arg(1))) *tformat_arg) (const char *);
 
Index: gcc/gcc/testsuite/gcc.dg/format/c90-printf-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/c90-printf-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/c90-printf-3.c
@@ -3,7 +3,7 @@
    do not.
 */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
-/* { dg-do compile } */
+/* { dg-do compile { target { ! *-*-mingw* } } } */
 /* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
 
 #include "format.h"
Index: gcc/gcc/testsuite/gcc.dg/format/c90-scanf-4.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/c90-scanf-4.c
+++ gcc/gcc/testsuite/gcc.dg/format/c90-scanf-4.c
@@ -3,7 +3,7 @@
    do not.
 */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
-/* { dg-do compile } */
+/* { dg-do compile { target { ! *-*-mingw* } } } */
 /* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
 
 #include "format.h"
Index: gcc/gcc/testsuite/gcc.dg/format/c99-printf-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/c99-printf-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/c99-printf-3.c
@@ -2,7 +2,7 @@
    attributes in strict C99 mode, but the gettext functions do not.
 */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
-/* { dg-do compile } */
+/* { dg-do compile { target { ! *-*-mingw* } } } */
 /* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
 
 #include "format.h"
Index: gcc/gcc/testsuite/gcc.dg/format/miss-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-1.c
@@ -23,7 +23,7 @@ bar (const char *fmt, ...)
   va_end (ap);
 }
 
-__attribute__((__format__(__printf__, 1, 2))) void
+__attribute__((__format__(gnu_attr___printf__, 1, 2))) void
 foo2 (const char *fmt, ...)
 {
   va_list ap;
Index: gcc/gcc/testsuite/gcc.dg/format/miss-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-3.c
@@ -3,13 +3,14 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 void
 foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
@@ -18,7 +19,7 @@ foo1 (noattr_t na, attr_t a, vnoattr_t v
   noattr_t na2 = a; /* { dg-warning "candidate" "initialization warning" } */
   attr_t a1 = na;
   attr_t a2 = a;
-  
+
   vnoattr_t vna1 = vna;
   vnoattr_t vna2 = va; /* { dg-warning "candidate" "initialization warning" } */
   vattr_t va1 = vna;
Index: gcc/gcc/testsuite/gcc.dg/format/miss-4.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-4.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-4.c
@@ -3,20 +3,21 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 void
 foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
 {
   noattr_t na1, na2;
   attr_t a1, a2;
-  
+
   vnoattr_t vna1, vna2;
   vattr_t va1, va2;
 
@@ -24,7 +25,7 @@ foo1 (noattr_t na, attr_t a, vnoattr_t v
   na2 = a; /* { dg-warning "candidate" "assignment warning" } */
   a1 = na;
   a2 = a;
-  
+
   vna1 = vna;
   vna2 = va; /* { dg-warning "candidate" "assignment warning" } */
   va1 = vna;
Index: gcc/gcc/testsuite/gcc.dg/format/miss-5.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-5.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-5.c
@@ -3,13 +3,14 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 noattr_t
 foo1 (noattr_t na, attr_t a, int i)
Index: gcc/gcc/testsuite/gcc.dg/format/miss-6.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-6.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-6.c
@@ -3,13 +3,14 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 extern void foo1 (noattr_t);
 extern void foo2 (attr_t);
@@ -23,7 +24,7 @@ foo (noattr_t na, attr_t a, vnoattr_t vn
   foo1 (a); /* { dg-warning "candidate" "parameter passing warning" } */
   foo2 (na);
   foo2 (a);
-  
+
   foo3 (vna);
   foo3 (va); /* { dg-warning "candidate" "parameter passing warning" } */
   foo4 (vna);
Index: gcc/gcc/testsuite/gcc.dg/format/ms_array-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_array-1.c
@@ -0,0 +1,42 @@
+/* Test for format checking of constant arrays.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat=2" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+const char a1[] = "foo";
+const char a2[] = "foo%d";
+const char b1[3] = "foo";
+const char b2[1] = "1";
+static const char c1[] = "foo";
+static const char c2[] = "foo%d";
+char d[] = "foo";
+volatile const char e[] = "foo";
+
+void
+foo (int i, long l)
+{
+  const char p1[] = "bar";
+  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 (c1);
+  printf (c2, i);
+  printf (c2, l); /* { dg-warning "format" "wrong type with array" } */
+  printf (p1);
+  printf (p2, i);
+  printf (p2, l); /* { dg-warning "format" "wrong type with array" } */
+  printf (q1);
+  printf (q2, i);
+  printf (q2, l); /* { dg-warning "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" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-1.c
@@ -0,0 +1,10 @@
+/* Test for strftime format attributes: can't have first_arg_num != 0.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define DONT_GNU_PROTOTYPE
+#include "format.h"
+
+extern void foo0 (const char *) __attribute__((__format__(__ms_strftime__, 1, 0)));
+extern void foo1 (const char *, ...) __attribute__((__format__(__ms_strftime__, 1, 2))); /* { dg-error "cannot format" "strftime first_arg_num != 0" } */
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-2.c
@@ -0,0 +1,68 @@
+/* Test for format attributes: test use of __attribute__.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define DONT_GNU_PROTOTYPE
+#include "format.h"
+
+extern void tformatprintf (const char *, ...) __attribute__((format(ms_printf, 1, 2)));
+extern void tformat__printf__ (const char *, ...) __attribute__((format(__ms_printf__, 1, 2)));
+extern void tformatscanf (const char *, ...) __attribute__((format(ms_scanf, 1, 2)));
+extern void tformat__scanf__ (const char *, ...) __attribute__((format(__ms_scanf__, 1, 2)));
+extern void tformatstrftime (const char *) __attribute__((format(ms_strftime, 1, 0)));
+extern void tformat__strftime__ (const char *) __attribute__((format(__ms_strftime__, 1, 0)));
+extern void tformatstrfmon (const char *, ...) __attribute__((format(strfmon, 1, 2)));
+extern void tformat__strfmon__ (const char *, ...) __attribute__((format(__strfmon__, 1, 2)));
+extern void t__format__printf (const char *, ...) __attribute__((__format__(ms_printf, 1, 2)));
+extern void t__format____printf__ (const char *, ...) __attribute__((__format__(__ms_printf__, 1, 2)));
+extern void t__format__scanf (const char *, ...) __attribute__((__format__(ms_scanf, 1, 2)));
+extern void t__format____scanf__ (const char *, ...) __attribute__((__format__(__ms_scanf__, 1, 2)));
+extern void t__format__strftime (const char *) __attribute__((__format__(ms_strftime, 1, 0)));
+extern void t__format____strftime__ (const char *) __attribute__((__format__(__ms_strftime__, 1, 0)));
+extern void t__format__strfmon (const char *, ...) __attribute__((__format__(strfmon, 1, 2)));
+extern void t__format____strfmon__ (const char *, ...) __attribute__((__format__(__strfmon__, 1, 2)));
+
+extern char *tformat_arg (const char *) __attribute__((format_arg(1)));
+extern char *t__format_arg__ (const char *) __attribute__((__format_arg__(1)));
+
+void
+foo (int i, int *ip, double d)
+{
+  tformatprintf ("%d", i);
+  tformatprintf ("%"); /* { dg-warning "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);
+  tformat__scanf__ ("%"); /* { dg-warning "format" "attribute format __scanf__" } */
+  tformatstrftime ("%a");
+  tformatstrftime ("%"); /* { dg-warning "format" "attribute format strftime" } */
+  tformat__strftime__ ("%a");
+  tformat__strftime__ ("%"); /* { dg-warning "format" "attribute format __strftime__" } */
+  tformatstrfmon ("%n", d);
+  tformatstrfmon ("%"); /* { dg-warning "format" "attribute format strfmon" } */
+  tformat__strfmon__ ("%n", d);
+  tformat__strfmon__ ("%"); /* { dg-warning "format" "attribute format __strfmon__" } */
+  t__format__printf ("%d", i);
+  t__format__printf ("%"); /* { dg-warning "format" "attribute __format__ printf" } */
+  t__format____printf__ ("%d", i);
+  t__format____printf__ ("%"); /* { dg-warning "format" "attribute __format__ __printf__" } */
+  t__format__scanf ("%d", ip);
+  t__format__scanf ("%"); /* { dg-warning "format" "attribute __format__ scanf" } */
+  t__format____scanf__ ("%d", ip);
+  t__format____scanf__ ("%"); /* { dg-warning "format" "attribute __format__ __scanf__" } */
+  t__format__strftime ("%a");
+  t__format__strftime ("%"); /* { dg-warning "format" "attribute __format__ strftime" } */
+  t__format____strftime__ ("%a");
+  t__format____strftime__ ("%"); /* { dg-warning "format" "attribute __format__ __strftime__" } */
+  t__format__strfmon ("%n", d);
+  t__format__strfmon ("%"); /* { dg-warning "format" "attribute __format__ strfmon" } */
+  t__format____strfmon__ ("%n", d);
+  t__format____strfmon__ ("%"); /* { dg-warning "format" "attribute __format__ __strfmon__" } */
+  tformatprintf (tformat_arg ("%d"), i);
+  tformatprintf (tformat_arg ("%")); /* { dg-warning "format" "attribute format_arg" } */
+  tformatprintf (t__format_arg__ ("%d"), i);
+  tformatprintf (t__format_arg__ ("%")); /* { dg-warning "format" "attribute __format_arg__" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-3.c
@@ -0,0 +1,71 @@
+/* Test for format attributes: test bad uses of __attribute__.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* Proper uses of the attributes.  */
+extern void fa0 (const char *, ...) __attribute__((format(ms_printf, 1, 2)));
+extern void fa1 (char *, ...) __attribute__((format(ms_printf, 1, 2)));
+extern char *fa2 (const char *) __attribute__((format_arg(1)));
+extern char *fa3 (char *) __attribute__((format_arg(1)));
+
+/* Uses with too few or too many arguments.  */
+extern void fb0 (const char *, ...) __attribute__((format)); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb1 (const char *, ...) __attribute__((format())); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb2 (const char *, ...) __attribute__((format(ms_printf))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb3 (const char *, ...) __attribute__((format(ms_printf, 1))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb4 (const char *, ...) __attribute__((format(ms_printf, 1, 2, 3))); /* { dg-error "wrong number of arguments" "bad format" } */
+
+extern void fc1 (const char *) __attribute__((format_arg)); /* { dg-error "wrong number of arguments" "bad format_arg" } */
+extern void fc2 (const char *) __attribute__((format_arg())); /* { dg-error "wrong number of arguments" "bad format_arg" } */
+extern void fc3 (const char *) __attribute__((format_arg(1, 2))); /* { dg-error "wrong number of arguments" "bad format_arg" } */
+
+/* These attributes presently only apply to declarations, not to types.
+   Eventually, they should be usable with declarators for function types
+   anywhere, but still not with structure/union/enum types.  */
+struct s0 { int i; } __attribute__((format(ms_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on struct" } */
+union u0 { int i; } __attribute__((format(ms_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on union" } */
+enum e0 { E0V0 } __attribute__((format(ms_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on enum" } */
+
+struct s1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on struct" } */
+union u1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on union" } */
+enum e1 { E1V0 } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on enum" } */
+
+/* The format type must be an identifier, one of those recognized.  */
+extern void fe0 (const char *, ...) __attribute__((format(12345, 1, 2))); /* { dg-error "format specifier" "non-id format" } */
+extern void fe1 (const char *, ...) __attribute__((format(nosuch, 1, 2))); /* { dg-warning "format function type" "unknown format" } */
+
+/* Both the numbers must be integer constant expressions.  */
+extern void ff0 (const char *, ...) __attribute__((format(ms_printf, 3-2, (long long)(10/5))));
+int foo;
+extern void ff1 (const char *, ...) __attribute__((format(ms_printf, foo, 10/5))); /* { dg-error "invalid operand" "bad number" } */
+extern void ff2 (const char *, ...) __attribute__((format(ms_printf, 3-2, foo))); /* { dg-error "invalid operand" "bad number" } */
+extern char *ff3 (const char *) __attribute__((format_arg(3-2)));
+extern char *ff4 (const char *) __attribute__((format_arg(foo))); /* { dg-error "invalid operand" "bad format_arg number" } */
+
+/* The format string argument must precede the arguments to be formatted.
+   This includes if no parameter types are specified (which is not valid ISO
+   C for variadic functions).  */
+extern void fg0 () __attribute__((format(ms_printf, 1, 2)));
+extern void fg1 () __attribute__((format(ms_printf, 1, 0)));
+extern void fg2 () __attribute__((format(ms_printf, 1, 1))); /* { dg-error "follows" "bad number order" } */
+extern void fg3 () __attribute__((format(ms_printf, 2, 1))); /* { dg-error "follows" "bad number order" } */
+
+/* The format string argument must be a string type, and the arguments to
+   be formatted must be the "...".  */
+extern void fh0 (int, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "not a string" "format int string" } */
+extern void fh1 (signed char *, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "not a string" "signed char string" } */
+extern void fh2 (unsigned char *, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "not a string" "unsigned char string" } */
+extern void fh3 (const char *, ...) __attribute__((format(ms_printf, 1, 3))); /* { dg-error "is not" "not ..." } */
+extern void fh4 (const char *, int, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "is not" "not ..." } */
+
+/* format_arg formats must take and return a string.  */
+extern char *fi0 (int) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg int string" } */
+extern char *fi1 (signed char *) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg signed char string" } */
+extern char *fi2 (unsigned char *) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg unsigned char string" } */
+extern int fi3 (const char *) __attribute__((format_arg(1))); /* { dg-error "not return string" "format_arg ret int string" } */
+extern signed char *fi4 (const char *) __attribute__((format_arg(1))); /* { dg-error "not return string" "format_arg ret signed char string" } */
+extern unsigned char *fi5 (const char *) __attribute__((format_arg(1))); /* { dg-error "not return string" "format_arg ret unsigned char string" } */
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-4.c
@@ -0,0 +1,26 @@
+/* Test for format attributes: test use of __attribute__
+   in prefix attributes.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+extern __attribute__((format(ms_printf, 1, 2))) void tformatprintf0 (const char *, ...);
+extern void __attribute__((format(ms_printf, 1, 2))) tformatprintf1 (const char *, ...);
+extern void foo (void), __attribute__((format(ms_printf, 1, 2))) tformatprintf2 (const char *, ...);
+extern __attribute__((noreturn)) void bar (void), __attribute__((format(ms_printf, 1, 2))) tformatprintf3 (const char *, ...);
+
+void
+baz (int i, int *ip, double d)
+{
+  tformatprintf0 ("%d", i);
+  tformatprintf0 ("%"); /* { dg-warning "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);
+  tformatprintf3 ("%"); /* { dg-warning "format" "attribute format printf case 3" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-7.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-7.c
@@ -0,0 +1,35 @@
+/* Test for format attributes: test applying them to types.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define DONT_GNU_PROTOTYPE
+#include "format.h"
+
+__attribute__((format(ms_printf, 1, 2))) void (*tformatprintf0) (const char *, ...);
+void (*tformatprintf1) (const char *, ...) __attribute__((format(ms_printf, 1, 2)));
+void (__attribute__((format(ms_printf, 1, 2))) *tformatprintf2) (const char *, ...);
+void (__attribute__((format(ms_printf, 1, 2))) ****tformatprintf3) (const char *, ...);
+
+char * (__attribute__((format_arg(1))) *tformat_arg) (const char *);
+
+void
+baz (int i)
+{
+  (*tformatprintf0) ("%d", i);
+  (*tformatprintf0) ((*tformat_arg) ("%d"), i);
+  (*tformatprintf0) ("%"); /* { dg-warning "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" } */
+  (*tformatprintf2) ("%d", i);
+  (*tformatprintf2) ((*tformat_arg) ("%d"), i);
+  (*tformatprintf2) ("%"); /* { dg-warning "format" "nested" } */
+  (*tformatprintf2) ((*tformat_arg) ("%")); /* { dg-warning "format" "nested" } */
+  (****tformatprintf3) ("%d", i);
+  (****tformatprintf3) ((*tformat_arg) ("%d"), i);
+  (****tformatprintf3) ("%"); /* { dg-warning "format" "nested 2" } */
+  (****tformatprintf3) ((*tformat_arg) ("%")); /* { dg-warning "format" "nested 2" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_bitfld-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_bitfld-1.c
@@ -0,0 +1,52 @@
+/* Test for printf formats and bit-fields: bug 22421.  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+/* { dg-require-effective-target int32plus } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+struct s {
+  unsigned int u1 : 1;
+  signed int s1 : 1;
+  unsigned int u15 : 15;
+  signed int s15 : 15;
+  unsigned int u16 : 16;
+  signed int s16 : 16;
+  unsigned long u31 : 31;
+  signed long s31 : 31;
+  unsigned long u32 : 32;
+  signed long s32 : 32;
+  unsigned long long u48 : 48;
+} x;
+
+void
+foo (void)
+{
+  printf ("%d%u", x.u1, x.u1);
+  printf ("%d%u", x.s1, x.s1);
+  printf ("%d%u", x.u15, x.u15);
+  printf ("%d%u", x.s15, x.s15);
+  printf ("%d%u", x.u16, x.u16);
+  printf ("%d%u", x.s16, x.s16);
+#if __INT_MAX__ > 32767
+  /* If integers are 16 bits, there doesn't seem to be a way of
+     printing these without getting an error.  */
+  printf ("%d%u", x.u31, x.u31);
+  printf ("%d%u", x.s31, x.s31);
+#endif
+#if __LONG_MAX__ > 2147483647 && __INT_MAX__ >= 2147483647
+  /* If long is wider than 32 bits, the 32-bit bit-fields are int or
+     unsigned int or promote to those types.  Otherwise, long is 32
+     bits and the bit-fields are of type plain long or unsigned
+     long.  */
+  printf ("%d%u", x.u32, x.u32);
+  printf ("%d%u", x.s32, x.s32);
+#else
+  printf ("%ld%lu", x.u32, x.u32);
+  printf ("%ld%lu", x.s32, x.s32);
+#endif
+  printf ("%I64u", x.u48); /* { dg-warning "has type '.*unsigned int:48'" } */
+  printf ("%I64u", (unsigned long long)x.u48);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_branch-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_branch-1.c
@@ -0,0 +1,28 @@
+/* Test for format checking of conditional expressions.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+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" } */
+  /* 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) ? "%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" } */
+  /* 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 *-*-* } 26 } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-1.c
@@ -0,0 +1,184 @@
+/* Test for printf formats.  Formats using C90 features, including cases
+   where C90 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, int i1, int i2, unsigned int u, double d, char *s, void *p,
+     int *n, short int *hn, long int l, unsigned long int ul,
+     long int *ln, long double ld, wint_t lc, wchar_t *ls, llong ll,
+     ullong ull, unsigned int *un, const int *cn, signed char *ss,
+     unsigned char *us, const signed char *css, unsigned int u1,
+     unsigned int u2)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.1 (pages 131-134).  */
+  /* Basic sanity checks for the different components of a format.  */
+  printf ("%d\n", i);
+  printf ("%+d\n", i);
+  printf ("%3d\n", i);
+  printf ("%-3d\n", i);
+  printf ("%*d\n", i1, i);
+  printf ("%d %lu\n", i, ul);
+  /* Bogus use of width.  */
+  printf ("%5n\n", n); /* { dg-warning "width" "width 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 ("%-%"); /* { dg-warning "format" "bogus %%" } */
+  printf ("%-%\n"); /* { dg-warning "format" "bogus %%" } */
+  printf ("%5%\n"); /* { dg-warning "format" "bogus %%" } */
+  printf ("%h%\n"); /* { dg-warning "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
+     differences in format checking here, and this is relied on to get the
+     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);
+  printf ("%hs", hn);
+  printf ("%hp", p); /* { dg-warning "length" "bad use of %h" } */
+  printf ("%h"); /* { dg-warning "conversion lacks type" "bare %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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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% 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* Various tests of bad argument types.  */
+  printf ("%d", l); /* { dg-warning "format" "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" } */
+  /* 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
+     discussion of the requirements of rules on identical representation,
+     and of the application of the as if rule with the new va_arg
+     allowances in C99 to printf.)  Likewise, we should warn if
+     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" } */
+  /* 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" } */
+  /* The historical behavior is to allow signed / unsigned types
+     interchangably as arguments.  For values representable in both types,
+     such usage may be correct.  For now preserve the behavior of GCC
+     in such cases.
+  */
+  printf ("%d", u);
+  /* Wrong number of arguments.  */
+  printf ("%d%d", i); /* { dg-warning "arguments" "wrong number of args" } */
+  printf ("%d", i, i); /* { dg-warning "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" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-2.c
@@ -0,0 +1,25 @@
+/* Test for printf formats.  Formats using C99 features should be rejected
+   outside of C99 mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, double d, llong ll, intmax_t j, size_t z, ptrdiff_t t)
+{
+  /* Some tests already in c90-printf-1.c, e.g. %lf.  */
+  /* The widths hh, ll, j, z, t are new.  */
+  printf ("%hhd", i); /* { dg-warning "unknown|format" "%hh is unsupported" } */
+  printf ("%I64d", ll); /* { dg-warning "length|C" "%I64 in C90" } */
+  printf ("%jd", j); /* { dg-warning "unknown|format" "%j is unsupported" } */
+  printf ("%zu", z); /* { dg-warning "unknown|format" "%z is unsupported" } */
+  printf ("%td", t); /* { dg-warning "unknown|format" "%t is unsupported" } */
+  /* The formats F, a, A are new.  */
+  printf ("%F", d); /* { dg-warning "unknown|format" "%F is unsupported" } */
+  printf ("%a", d); /* { dg-warning "unknown|format" "%a is unsupported" } */
+  printf ("%A", d); /* { dg-warning "unknown|format" "%A is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-3.c
@@ -0,0 +1,43 @@
+/* Test for printf formats.  Test that the C90 functions get their default
+   attributes in strict C90 mode, but the C99 and gettext functions
+   do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, char *s, size_t n, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5, va_list v6, va_list v7, va_list v8)
+{
+  fprintf (stdout, "%d", i);
+  fprintf (stdout, "%ld", i); /* { dg-warning "format" "fprintf" } */
+  printf ("%d", i);
+  printf ("%ld", i); /* { dg-warning "format" "printf" } */
+  /* The "unlocked" functions shouldn't warn in c90 mode.  */
+  fprintf_unlocked (stdout, "%ld", i);
+  printf_unlocked ("%ld", i);
+  sprintf (s, "%d", i);
+  sprintf (s, "%ld", i); /* { dg-warning "format" "sprintf" } */
+  vfprintf (stdout, "%d", v0);
+  vfprintf (stdout, "%Y", v1); /* { dg-warning "format" "vfprintf" } */
+  vprintf ("%d", v2);
+  vprintf ("%Y", v3); /* { dg-warning "format" "vprintf" } */
+  /* The following used to give a bogus warning.  */
+  vprintf ("%*.*d", v8); /* { dg-warning "format" "dot is invalid" } */
+  vsprintf (s, "%d", v4);
+  vsprintf (s, "%Y", v5); /* { dg-warning "format" "Y is invalid" } */
+  snprintf (s, n, "%d", i);
+  snprintf (s, n, "%ld", i);
+  vsnprintf (s, n, "%d", v6);
+  vsnprintf (s, n, "%Y", v7);
+  printf (gettext ("%d"), i);
+  printf (gettext ("%ld"), i);
+  printf (dgettext ("", "%d"), i);
+  printf (dgettext ("", "%ld"), (long) i);
+  printf (dcgettext ("", "%d", 0), i);
+  printf (dcgettext ("", "%ld", 0), (long) i);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-1.c
@@ -0,0 +1,119 @@
+/* Test for scanf formats.  Formats using C90 features, including cases
+   where C90 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, unsigned int *uip, short int *hp, unsigned short int *uhp,
+     long int *lp, unsigned long int *ulp, float *fp, double *dp,
+     long double *ldp, char *s, signed char *ss, unsigned char *us,
+     void **pp, int *n, llong *llp, ullong *ullp, wchar_t *ls,
+     const int *cip, const int *cn, const char *cs, const void **ppc,
+     void *const *pcp, short int *hn, long int *ln, void *p, char **sp,
+     volatile void *ppv)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.2 (pages 134-138).  */
+  /* Basic sanity checks for the different components of a format.  */
+  scanf ("%d", ip);
+  scanf ("%*d");
+  scanf ("%3d", ip);
+  scanf ("%hd", hp);
+  scanf ("%3ld", lp);
+  scanf ("%*3d");
+  scanf ("%d %ld", ip, lp);
+  /* Valid and invalid %% constructions.  */
+  scanf ("%%");
+  scanf ("%*%"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%*%\n"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%4%"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%4%\n"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%h%"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%h%\n"); /* { dg-warning "format" "bogus %%" } */
+  /* Valid, invalid and silly assignment-suppression constructions.  */
+  scanf ("%*d%*i%*o%*u%*x%*X%*e%*E%*f%*g%*G%*s%*[abc]%*c%*p");
+  scanf ("%*2d%*8s%*3c");
+  scanf ("%*n", n); /* { dg-warning "suppress" "suppression of %n" } */
+  scanf ("%*hd"); /* { dg-warning "together" "suppression with length" } */
+  /* Valid, invalid and silly width constructions.  */
+  scanf ("%2d%3i%4o%5u%6x%7X%8e%9E%10f%11g%12G%13s%14[abc]%15c%16p",
+	 ip, ip, uip, uip, uip, uip, fp, fp, fp, fp, fp, s, s, s, pp);
+  scanf ("%0d", ip); /* { dg-warning "width" "warning for zero width" } */
+  scanf ("%3n", n); /* { dg-warning "width" "width with %n" } */
+  /* Valid and invalid %h, %l, %L constructions.  */
+  scanf ("%hd%hi%ho%hu%hx%hX%hn", hp, hp, uhp, uhp, uhp, uhp, hn);
+  scanf ("%he", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hE", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hf", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hg", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hG", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hs", hp);
+  scanf ("%h[ac]", s); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hc", hp);
+  scanf ("%hp", pp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%h"); /* { dg-warning "conversion lacks type" "bare %h" } */
+  scanf ("%h."); /* { dg-warning "conversion" "bogus %h" } */
+  scanf ("%ld%li%lo%lu%lx%lX%ln", lp, lp, ulp, ulp, ulp, ulp, ln);
+  scanf ("%le%lE%lf%lg%lG", dp, dp, dp, dp, dp);
+  scanf ("%lp", pp); /* { dg-warning "length" "bad use of %l" } */
+  /* These next three formats were added in C94.  */
+  scanf ("%ls", ls); /* { dg-warning "length|C" "bad use of %l" } */
+  scanf ("%l[ac]", ls); /* { dg-warning "length|C" "bad use of %l" } */
+  scanf ("%lc", ls); /* { dg-warning "length|C" "bad use of %l" } */
+  scanf ("%Ld", llp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Li", llp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lo", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lu", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lx", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%LX", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Ls", s); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%L[ac]", s); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lc", s); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lp", pp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Ln", n); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  /* Valid uses of each bare conversion.  */
+  scanf ("%d%i%o%u%x%X%e%E%f%g%G%s%[abc]%c%p%n%%", ip, ip, uip, uip, uip,
+	 uip, fp, fp, fp, fp, fp, s, s, s, pp, n);
+  /* Allow other character pointers with %s, %c, %[].  */
+  scanf ("%2s%3s%4c%5c%6[abc]%7[abc]", ss, us, ss, us, ss, us);
+  /* Further tests for %[].  */
+  scanf ("%[%d]%d", s, ip);
+  scanf ("%[^%d]%d", s, ip);
+  scanf ("%[]%d]%d", s, ip);
+  scanf ("%[^]%d]%d", s, ip);
+  scanf ("%[%d]%d", s, ip);
+  scanf ("%[]abcd", s); /* { dg-warning "no closing" "incomplete scanset" } */
+  /* Various tests of bad argument types.  Some of these are only pedantic
+     warnings.
+  */
+  scanf ("%d", lp); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%d", uip); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%d", pp); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", ppc); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", ppv); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%s", n); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%s", p); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", p); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", sp); /* { dg-warning "format" "bad argument types" } */
+  /* Tests for writing into constant values.  */
+  scanf ("%d", cip); /* { dg-warning "constant" "%d writing into const" } */
+  scanf ("%n", cn); /* { dg-warning "constant" "%n writing into const" } */
+  scanf ("%s", cs); /* { dg-warning "constant" "%s writing into const" } */
+  scanf ("%p", pcp); /* { dg-warning "constant" "%p writing into const" } */
+  /* Wrong number of arguments.  */
+  scanf ("%d%d", ip); /* { dg-warning "arguments" "wrong number of args" } */
+  scanf ("%d", ip, ip); /* { dg-warning "arguments" "wrong number of args" } */
+  /* Miscellaneous bogus constructions.  */
+  scanf (""); /* { dg-warning "zero-length" "warning for empty format" } */
+  scanf ("\0"); /* { dg-warning "embedded" "warning for embedded NUL" } */
+  scanf ("%d\0", ip); /* { dg-warning "embedded" "warning for embedded NUL" } */
+  scanf ("%d\0%d", ip, ip); /* { dg-warning "embedded|too many" "warning for embedded NUL" } */
+  scanf (NULL); /* { dg-warning "null" "null format string warning" } */
+  scanf ("%"); /* { dg-warning "trailing" "trailing % warning" } */
+  scanf ("%d", (int *)0); /* { dg-warning "null" "writing into NULL" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-2.c
@@ -0,0 +1,26 @@
+/* Test for scanf formats.  Formats using C99 features should be rejected
+   outside of C99 mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (signed char *hhp, float *fp, llong *llp, intmax_t *jp,
+     size_t *zp, ptrdiff_t *tp)
+{
+  /* Some tests already in c90-scanf-1.c.  */
+  /* The widths hh, ll, j, z, t are new.  */
+  scanf ("%hhd", hhp); /* { dg-warning "unknown|format" "%hh is unsupported" } */
+  scanf ("%I64d", llp); /* { dg-warning "length|C" "%I64 in C90" } */
+  scanf ("%jd", jp); /* { dg-warning "unknown|format" "%j is unsupported" } */
+  scanf ("%zu", zp); /* { dg-warning "unknown|format" "%z is unsupported" } */
+  scanf ("%td", tp); /* { dg-warning "unknown|format" "%t is unsupported" } */
+  /* The formats F, a, A are new.  */
+  scanf ("%F", fp); /* { dg-warning "unknown|format" "%F is unsupported" } */
+  scanf ("%a", fp); /* { dg-warning "unknown|format" "%a is unsupported" } */
+  scanf ("%A", fp); /* { dg-warning "unknown|format" "%A is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-3.c
@@ -0,0 +1,20 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char **sp, wchar_t **lsp)
+{
+  /* %a formats for allocation, only recognized in C90 mode, are a
+     GNU extension.
+  */
+  scanf ("%as", sp); /* { dg-warning "flag" "%as is unsupported" } */
+  scanf ("%aS", lsp); /* { dg-warning "format|flag" "%aS is unsupported" } */
+  scanf ("%a[bcd]", sp); /* { dg-warning "flag" "%a[] is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-4.c
@@ -0,0 +1,31 @@
+/* Test for scanf formats.  Test that the C90 functions get their default
+   attributes in strict C90 mode, but the C99 and gettext functions
+   do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, char *s, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5)
+{
+  fscanf (stdin, "%d", ip);
+  fscanf (stdin, "%ld", ip); /* { dg-warning "format" "fscanf" } */
+  scanf ("%d", ip);
+  scanf ("%ld", ip); /* { dg-warning "format" "scanf" } */
+  sscanf (s, "%d", ip);
+  sscanf (s, "%ld", ip); /* { dg-warning "format" "sscanf" } */
+  vfscanf (stdin, "%d", v0);
+  vscanf ("%d", v2);
+  vsscanf (s, "%d", v4);
+  scanf (gettext ("%d"), ip);
+  scanf (gettext ("%ld"), ip);
+  scanf (dgettext ("", "%d"), ip);
+  scanf (dgettext ("", "%ld"), ip);
+  scanf (dcgettext ("", "%d", 0), ip);
+  scanf (dcgettext ("", "%ld", 0), ip);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-5.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-5.c
@@ -0,0 +1,20 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char **sp, wchar_t **lsp)
+{
+  /* m assignment-allocation modifier, recognized in both C90
+     and C99 modes, is a POSIX and ISO/IEC WDTR 24731-2 extension.  */
+  scanf ("%ms", sp); /* { dg-warning "unknown|format" "%ms is unsupported" } */
+  scanf ("%mS", lsp); /* { dg-warning "unknown|format" "%mS is unsupported" } */
+  scanf ("%mls", lsp); /* { dg-warning "unknown|format" "%mls is unsupported" } */
+  scanf ("%m[bcd]", sp); /* { dg-warning "unknown|format" "%m[] is unsupported" } */
+  scanf ("%ml[bcd]", lsp); /* { dg-warning "unknown|format" "%ml[] is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-1.c
@@ -0,0 +1,20 @@
+/* Test for strftime formats.  Formats using C90 features.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wformat-y2k" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.12.3.5 (pages 174-175).  */
+  /* Formats which are Y2K-compliant (no 2-digit years).  */
+  strftime (s, m, "%a%A%b%B%d%H%I%j%m%M%p%S%U%w%W%X%Y%Z%%", tp);
+  /* Formats with 2-digit years.  */
+  strftime (s, m, "%y", tp); /* { dg-warning "only last 2" "2-digit year" } */
+  /* Formats with 2-digit years in some locales.  */
+  strftime (s, m, "%c", tp); /* { dg-warning "some locales" "2-digit year" } */
+  strftime (s, m, "%x", tp); /* { dg-warning "some locales" "2-digit year" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-2.c
@@ -0,0 +1,30 @@
+/* Test for strftime formats.  Rejection of formats using C99 features in
+   pedantic C90 mode.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wformat-y2k" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  strftime (s, m, "%C", tp); /* { dg-warning "format" "%C is unsupported" } */
+  strftime (s, m, "%D", tp); /* { dg-warning "format" "%D is unsupported" } */
+  strftime (s, m, "%e", tp); /* { dg-warning "format" "%e is unsupported" } */
+  strftime (s, m, "%F", tp); /* { dg-warning "format" "%F is unsupported" } */
+  strftime (s, m, "%g", tp); /* { dg-warning "format" "%g is unsupported" } */
+  strftime (s, m, "%G", tp); /* { dg-warning "format" "%G is unsupported" } */
+  strftime (s, m, "%h", tp); /* { dg-warning "format" "%h is unsupported" } */
+  strftime (s, m, "%n", tp); /* { dg-warning "format" "%n is unsupported" } */
+  strftime (s, m, "%r", tp); /* { dg-warning "format" "%r is unsupported" } */
+  strftime (s, m, "%R", tp); /* { dg-warning "format" "%R is unsupported" } */
+  strftime (s, m, "%t", tp); /* { dg-warning "format" "%t is unsupported" } */
+  strftime (s, m, "%T", tp); /* { dg-warning "format" "%T is unsupported" } */
+  strftime (s, m, "%u", tp); /* { dg-warning "format" "%u is unsupported" } */
+  strftime (s, m, "%V", tp); /* { dg-warning "format" "%V is unsupported" } */
+  strftime (s, m, "%z", tp); /* { dg-warning "C" "%z not in C90" } */
+  strftime (s, m, "%EX", tp); /* { dg-warning "C" "%E not in C90" } */
+  strftime (s, m, "%OW", tp); /* { dg-warning "C" "%O not in C90" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c94-printf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c94-printf-1.c
@@ -0,0 +1,19 @@
+/* Test for printf formats.  Changes in C94 to C90.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:199409 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (wint_t lc, wchar_t *ls)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.1 (pages 131-134),
+     as amended by ISO/IEC 9899:1990/Amd.1:1995 (E) (pages 4-5).
+     We do not repeat here all the C90 format checks, but just verify
+     that %ls and %lc are accepted without warning.
+  */
+  printf ("%lc", lc);
+  printf ("%ls", ls);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c94-scanf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c94-scanf-1.c
@@ -0,0 +1,18 @@
+/* Test for scanf formats.  Changes in C94 to C90.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:199409 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (wchar_t *ls)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.2 (pages 134-138),
+     as amended by ISO/IEC 9899:1990/Amd.1:1995 (E) (pages 5-6).
+     We do not repeat here all the C90 format checks, but just verify
+     that %ls, %lc, %l[] are accepted without warning.
+  */
+  scanf ("%lc%ls%l[abc]", ls, ls, ls);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-1.c
@@ -0,0 +1,122 @@
+/* Test for printf formats.  Formats using C99 features, including cases
+   where C99 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, unsigned int u, double d, char *s, void *p, int *n,
+     long double ld, wint_t lc, wchar_t *ls, long long int ll,
+     unsigned long long int ull, signed char *ss, unsigned char *us,
+     long long int *lln, intmax_t j, uintmax_t uj, intmax_t *jn,
+     size_t z, signed_size_t sz, signed_size_t *zn,
+     ptrdiff_t t, ptrdiff_t *tn)
+{
+  /* See ISO/IEC 9899:1999 (E) subclause 7.19.6.1 (pages 273-281).
+     We do not repeat here most of the checks for correct C90 formats
+     or completely broken formats.
+  */
+  /* Valid and invalid %h, %hh, %l, %I64, %j, %z, %t, %L constructions.  */
+  printf ("%hf", d); /* { dg-warning "length" "bad use of %h" } */
+  printf ("%hF", d); /* { dg-warning "unknown|format" "bad use of %hF" } */
+  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 ("%ha", d); /* { dg-warning "unknown|format" "bad use of %ha" } */
+  printf ("%hA", d); /* { dg-warning "unknown|format" "bad use of %hA" } */
+  printf ("%hc", i);
+  printf ("%hs", (short *)s);
+  printf ("%hp", p); /* { dg-warning "length" "bad use of %h" } */
+  printf ("%lc", lc);
+  printf ("%ls", ls);
+  printf ("%lp", p); /* { dg-warning "length|C" "bad use of %l" } */
+  printf ("%I64d%I64i%I64o%I64u%I64x%I64X", ll, ll, ull, ull, ull, ull);
+  printf ("%I64n", lln);
+  printf ("%I64f", d); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64F", d); /* { dg-warning "unknown|format" "bad use of %I64F" } */
+  printf ("%I64e", d); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64E", d); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64g", d); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64G", d); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64a", d); /* { dg-warning "unknown|format" "bad use of %I64a" } */
+  printf ("%I64A", d); /* { dg-warning "unknown|format" "bad use of %I64A" } */
+  printf ("%I64c", i); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64s", s); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64p", p); /* { dg-warning "length" "bad use of %I64" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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% 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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 ("%-08F", d); /* { dg-warning "unknown|format" "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 ("%-08a", d); /* { dg-warning "unknown|format" "0 flag ignored with - flag" } */
+  printf ("%-08A", d); /* { dg-warning "unknown|format" "0 flag ignored with - flag" } */
+  /* Various tests of bad argument types.  Mostly covered in c90-printf-1.c;
+     here just test for pointer target sign with %hhn.  (Probably allowed
+     by the standard, but a bad idea, so GCC should diagnose if what
+     is used is not signed char *.)
+  */
+  printf ("%hhn", s); /* { dg-warning "unknown|format" "%hhn is unsupported" } */
+  printf ("%hhn", us); /* { dg-warning "unknown|format" "%hhn is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-2.c
@@ -0,0 +1,33 @@
+/* Test for printf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, long long ll, size_t z, wint_t lc, wchar_t *ls)
+{
+  /* The length modifiers q, Z and L as applied to integer formats are
+     extensions.
+  */
+  printf ("%qd", ll); /* { dg-warning "unknown|format" "%q length is unsupported" } */
+  printf ("%Ld", ll); /* { dg-warning "unknown|format" "%L length is unsupported" } */
+  printf ("%Zd", z); /* { dg-warning "unknown|format" "%Z lengthis unsupported" } */
+  /* The conversion specifiers C and S are X/Open extensions; the
+     conversion specifier m is a GNU extension.
+  */
+  printf ("%m"); /* { dg-warning "unknown|format" "printf %m is unsupported" } */
+  printf ("%C", lc); /* { dg-warning "C" "printf %C" } */
+  printf ("%S", ls); /* { dg-warning "C" "printf %S" } */
+  /* The flag character ', and the use of operand number $ formats, are
+     X/Open extensions.
+  */
+  printf ("%'d", i); /* { dg-warning "C" "printf ' flag" } */
+  printf ("%1$d", i); /* { dg-warning "C" "printf $ format" } */
+  /* The flag character I is a GNU extension.  */
+  printf ("%Ix", z);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-3.c
@@ -0,0 +1,40 @@
+/* Test for printf formats.  Test that the C99 functions get their default
+   attributes in strict C99 mode, but the gettext functions do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, char *s, size_t n, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5, va_list v6, va_list v7)
+{
+  fprintf (stdout, "%d", i);
+  fprintf (stdout, "%ld", i); /* { dg-warning "format" "fprintf" } */
+  printf ("%d", i);
+  printf ("%ld", i); /* { dg-warning "format" "printf" } */
+  /* The "unlocked" functions shouldn't warn in c99 mode.  */
+  fprintf_unlocked (stdout, "%ld", i);
+  printf_unlocked ("%ld", i);
+  sprintf (s, "%d", i);
+  sprintf (s, "%ld", i); /* { dg-warning "format" "sprintf" } */
+  snprintf (s, n, "%d", i);
+  snprintf (s, n, "%ld", i); /* { dg-warning "format" "snprintf" } */
+  vfprintf (stdout, "%d", v0);
+  vfprintf (stdout, "%Y", v1); /* { dg-warning "format" "vfprintf" } */
+  vprintf ("%d", v0);
+  vprintf ("%Y", v1); /* { dg-warning "format" "vprintf" } */
+  vsprintf (s, "%d", v0);
+  vsprintf (s, "%Y", v1); /* { dg-warning "format" "vsprintf" } */
+  vsnprintf (s, n, "%d", v0);
+  vsnprintf (s, n, "%Y", v1); /* { dg-warning "format" "vsnprintf" } */
+  printf (gettext ("%d"), i);
+  printf (gettext ("%ld"), (long) i);
+  printf (dgettext ("", "%d"), i);
+  printf (dgettext ("", "%ld"), (long) i);
+  printf (dcgettext ("", "%d", 0), i);
+  printf (dcgettext ("", "%ld", 0), (long) i);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-1.c
@@ -0,0 +1,75 @@
+/* Test for scanf formats.  Formats using C99 features, including cases
+   where C99 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, unsigned int *uip, short int *hp, unsigned short int *uhp,
+     signed char *hhp, unsigned char *uhhp, long int *lp,
+     unsigned long int *ulp, float *fp, double *dp, long double *ldp, char *s,
+     void **pp, int *n, long long *llp, unsigned long long *ullp, wchar_t *ls,
+     short int *hn, signed char *hhn, long int *ln, long long int *lln,
+     intmax_t *jp, uintmax_t *ujp, intmax_t *jn, size_t *zp,
+     signed_size_t *szp, signed_size_t *zn, ptrdiff_t *tp,
+     unsigned_ptrdiff_t *utp, ptrdiff_t *tn)
+{
+  /* See ISO/IEC 9899:1999 (E) subclause 7.19.6.2 (pages 281-288).
+     We do not repeat here most of the checks for correct C90 formats
+     or completely broken formats.
+  */
+  /* Valid, invalid and silly assignment-suppression
+     and width constructions.
+  */
+  scanf ("%*d%*i%*o%*u%*x%*X%*e%*E%*f%*g%*G%*s%*[abc]%*c%*p");
+  scanf ("%*2d%*8s%*3c");
+  scanf ("%*n", n); /* { dg-warning "suppress" "suppression of %n" } */
+  scanf ("%*hd"); /* { dg-warning "together" "suppression with length" } */
+  scanf ("%2d%3i%4o%5u%6x%7X%10e%11E%12f%14g%15G%16s%3[abc]%4c%5p",
+	 ip, ip, uip, uip, uip, uip, fp, fp, fp, fp, fp,
+	 s, s, s, pp);
+  scanf ("%0d", ip); /* { dg-warning "width" "warning for zero width" } */
+  scanf ("%3n", n); /* { dg-warning "width" "width with %n" } */
+  /* Valid and invalid %h, %hh, %l, %I64, %j, %z, %t, %L constructions.  */
+  scanf ("%hd%hi%ho%hu%hx%hX%hn", hp, hp, uhp, uhp, uhp, uhp, hn);
+  scanf ("%he", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hE", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hf", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hg", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hG", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hs", hp);
+  scanf ("%h[ac]", s); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hc", (short *)s);
+  scanf ("%hp", pp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hhd", hhp); /* { dg-warning "unknown|format" "%hh is unsupported" } */
+  scanf ("%ld%li%lo%lu%lx%lX%ln", lp, lp, ulp, ulp, ulp, ulp, ln);
+  scanf ("%le%lE%lf%lg%lG", dp, dp, dp, dp, dp);
+  scanf ("%lp", pp); /* { dg-warning "length" "bad use of %l" } */
+  scanf ("%ls", ls);
+  scanf ("%l[ac]", ls);
+  scanf ("%lc", ls);
+  scanf ("%I64d%I64i%I64o%I64u%I64x%I64X%I64n", llp, llp, ullp, ullp, ullp, ullp,
+	 lln);
+  scanf ("%I64e", fp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64E", fp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64f", fp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64F", fp); /* { dg-warning "unknown|format" "'F' is unsupported" } */
+  scanf ("%I64g", fp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64G", fp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64s", s); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64[ac]", s); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64c", s); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64p", pp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%jd", jp); /* { dg-warning "unknown|format" "%j not supported" } */
+  scanf ("%zd", zp); /* { dg-warning "unknown|format" "%z not supported" } */
+  scanf ("%td", tp); /* { dg-warning "unknown|format" "%t not supported" } */
+  scanf ("%Lf", llp); /* { dg-warning "unknown|format" "bad use of %L is not supported" } */
+  /* Valid uses of each bare conversion.  */
+  scanf ("%d%i%o%u%x%X%e%E%f%g%G%s%[abc]%c%p%n%%", ip, ip, uip, uip, uip,
+         uip, fp, fp, fp, fp, fp, s, s, s, pp, n);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-2.c
@@ -0,0 +1,27 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, long long int *llp, wchar_t *ls)
+{
+  /* The length modifiers q and L as applied to integer formats are
+     extensions.
+  */
+  scanf ("%qd", llp); /* { dg-warning "unknown|format" "%q is unsupported" } */
+  scanf ("%Ld", llp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  /* The conversion specifiers C and S are X/Open extensions.  */
+  scanf ("%C", ls); /* { dg-warning "C" "scanf %C" } */
+  scanf ("%S", ls); /* { dg-warning "C" "scanf %S" } */
+  /* The use of operand number $ formats is an X/Open extension.  */
+  scanf ("%1$d", ip); /* { dg-warning "C" "scanf $ format" } */
+  /* glibc also supports flags ' and I on scanf formats as an extension.  */
+  scanf ("%'d", ip); /* { dg-warning "C" "scanf ' flag" } */
+  scanf ("%Id", (ssize_t *)ip);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-3.c
@@ -0,0 +1,33 @@
+/* Test for scanf formats.  Test that the C99 functions get their default
+   attributes in strict C99 mode, but the gettext functions do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, char *s, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5)
+{
+  fscanf (stdin, "%d", ip);
+  fscanf (stdin, "%ld", ip); /* { dg-warning "format" "fscanf" } */
+  scanf ("%d", ip);
+  scanf ("%ld", ip); /* { dg-warning "format" "scanf" } */
+  sscanf (s, "%d", ip);
+  sscanf (s, "%ld", ip); /* { dg-warning "format" "sscanf" } */
+  vfscanf (stdin, "%d", v0);
+  vfscanf (stdin, "%Y", v1); /* { dg-warning "format" "vfscanf" } */
+  vscanf ("%d", v2);
+  vscanf ("%Y", v3); /* { dg-warning "format" "vscanf" } */
+  vsscanf (s, "%d", v4);
+  vsscanf (s, "%Y", v5); /* { dg-warning "format" "vsscanf" } */
+  scanf (gettext ("%d"), ip);
+  scanf (gettext ("%ld"), ip);
+  scanf (dgettext ("", "%d"), ip);
+  scanf (dgettext ("", "%ld"), ip);
+  scanf (dcgettext ("", "%d", 0), ip);
+  scanf (dcgettext ("", "%ld", 0), ip);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-4.c
@@ -0,0 +1,20 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char **sp, wchar_t **lsp)
+{
+  /* m assignment-allocation modifier, recognized in both C90
+     and C99 modes, is a POSIX and ISO/IEC WDTR 24731-2 extension.  */
+  scanf ("%ms", sp); /* { dg-warning "unknown|format" "%ms is unsupported" } */
+  scanf ("%mS", lsp); /* { dg-warning "unknown|format" "%mS is unsupported" } */
+  scanf ("%mls", lsp); /* { dg-warning "unknown|format" "%mls is unsupported" } */
+  scanf ("%m[bcd]", sp); /* { dg-warning "unknown|format" "%m[] is unsupported" } */
+  scanf ("%ml[bcd]", lsp); /* { dg-warning "unknown|format" "%ml[] is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-1.c
@@ -0,0 +1,30 @@
+/* Test for strftime formats.  Formats using C99 features.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat -Wformat-y2k" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.12.3.5 (pages 174-175).  */
+  /* Formats which are Y2K-compliant (no 2-digit years).  */
+  strftime (s, m, "%a%A%b%B%d%H%I%j%m%M%p%S%U%w%W%X%Y%z%Z%%", tp);
+  strftime (s, m, "%EX%EY%Od%OH%OI%Om%OM%OS%OU%Ow%OW", tp);
+  /* Formats with 2-digit years.  */
+  strftime (s, m, "%D", tp); /* { dg-warning "unknown" "2-digit year unsupported" } */
+  strftime (s, m, "%g", tp); /* { dg-warning "unknown" "2-digit year unsupported" } */
+  strftime (s, m, "%y", tp); /* { dg-warning "only last 2" "2-digit year" } */
+  strftime (s, m, "%Oy", tp); /* { dg-warning "only last 2" "2-digit year" } */
+  /* Formats with 2-digit years in some locales.  */
+  strftime (s, m, "%c", tp); /* { dg-warning "some locales" "2-digit year" } */
+  strftime (s, m, "%Ec", tp); /* { dg-warning "some locales" "2-digit year" } */
+  strftime (s, m, "%x", tp); /* { dg-warning "some locales" "2-digit year" } */
+  strftime (s, m, "%Ex", tp); /* { dg-warning "some locales" "2-digit year" } */
+  /* %Ey is explicitly an era offset not a 2-digit year; but in some
+     locales the E modifier may be ignored.
+  */
+  strftime (s, m, "%Ey", tp); /* { dg-warning "some locales" "2-digit year" } */
+  }
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-2.c
@@ -0,0 +1,24 @@
+/* Test for strftime formats.  Rejection of extensions in pedantic mode.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  /* %P is a lowercase version of %p.  */
+  strftime (s, m, "%P", tp); /* { dg-warning "unknown" "strftime %P" } */
+  /* %k is %H but padded with a space rather than 0 if necessary.  */
+  strftime (s, m, "%k", tp); /* { dg-warning "unknown" "strftime %k" } */
+  /* %l is %I but padded with a space rather than 0 if necessary.  */
+  strftime (s, m, "%l", tp); /* { dg-warning "unknown" "strftime %l" } */
+  /* %s is the number of seconds since the Epoch.  */
+  strftime (s, m, "%s", tp); /* { dg-warning "unknown" "strftime %s" } */
+  /* Extensions using %O already tested in c99-strftime-1.c.  */
+  /* Width and flags are GNU extensions for strftime.  */
+  strftime (s, m, "%20Y", tp); /* { dg-warning "C" "strftime width" } */
+  strftime (s, m, "%^A", tp); /* { dg-warning "C" "strftime flags" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_cast-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_cast-1.c
@@ -0,0 +1,17 @@
+/* Test for strings cast through integer types: should not be treated
+   as format strings unless the types are of the same width as
+   pointers (intptr_t or similar).  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+f (int x)
+{
+  printf("%s", x); /* { dg-warning "format" } */
+  printf((char *)(size_t)"%s", x); /* { dg-warning "format" } */
+  printf((char *)(char)"%s", x); /* { dg-warning "cast from pointer to integer of different size" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-1.c
@@ -0,0 +1,40 @@
+/* Test for warnings for missing format attributes.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  vprintf (fmt, ap); /* { dg-warning "candidate" "printf attribute warning" } */
+  va_end (ap);
+}
+
+void
+bar (const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  vscanf (fmt, ap); /* { dg-warning "candidate" "scanf attribute warning" } */
+  va_end (ap);
+}
+
+__attribute__((__format__(__ms_printf__, 1, 2))) void
+foo2 (const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  vprintf (fmt, ap);
+  va_end (ap);
+}
+
+void
+vfoo (const char *fmt, va_list arg)
+{
+  vprintf (fmt, arg); /* { dg-warning "candidate" "printf attribute warning 2" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-2.c
@@ -0,0 +1,17 @@
+/* Test for warnings for missing format attributes.  Don't warn if no
+   relevant parameters for a format attribute; see c/1017.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, ...)
+{
+  va_list ap;
+  va_start (ap, i);
+  vprintf ("Foo %s bar %s", ap); /* { dg-bogus "candidate" "bogus printf attribute warning" } */
+  va_end (ap);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-3.c
@@ -0,0 +1,27 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+void
+foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
+{
+  noattr_t na1 = na;
+  noattr_t na2 = a; /* { dg-warning "candidate" "initialization warning" } */
+  attr_t a1 = na;
+  attr_t a2 = a;
+
+  vnoattr_t vna1 = vna;
+  vnoattr_t vna2 = va; /* { dg-warning "candidate" "initialization warning" } */
+  vattr_t va1 = vna;
+  vattr_t va2 = va;
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-4.c
@@ -0,0 +1,33 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+void
+foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
+{
+  noattr_t na1, na2;
+  attr_t a1, a2;
+
+  vnoattr_t vna1, vna2;
+  vattr_t va1, va2;
+
+  na1 = na;
+  na2 = a; /* { dg-warning "candidate" "assignment warning" } */
+  a1 = na;
+  a2 = a;
+
+  vna1 = vna;
+  vna2 = va; /* { dg-warning "candidate" "assignment warning" } */
+  va1 = vna;
+  va1 = va;
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-5.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-5.c
@@ -0,0 +1,49 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+noattr_t
+foo1 (noattr_t na, attr_t a, int i)
+{
+  if (i)
+    return na;
+  else
+    return a; /* { dg-warning "candidate" "return type warning" } */
+}
+
+attr_t
+foo2 (noattr_t na, attr_t a, int i)
+{
+  if (i)
+    return na;
+  else
+    return a;
+}
+
+vnoattr_t
+foo3 (vnoattr_t vna, vattr_t va, int i)
+{
+  if (i)
+    return vna;
+  else
+    return va; /* { dg-warning "candidate" "return type warning" } */
+}
+
+vattr_t
+foo4 (vnoattr_t vna, vattr_t va, int i)
+{
+  if (i)
+    return vna;
+  else
+    return va;
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-6.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-6.c
@@ -0,0 +1,32 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+extern void foo1 (noattr_t);
+extern void foo2 (attr_t);
+extern void foo3 (vnoattr_t);
+extern void foo4 (vattr_t);
+
+void
+foo (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
+{
+  foo1 (na);
+  foo1 (a); /* { dg-warning "candidate" "parameter passing warning" } */
+  foo2 (na);
+  foo2 (a);
+
+  foo3 (vna);
+  foo3 (va); /* { dg-warning "candidate" "parameter passing warning" } */
+  foo4 (vna);
+  foo4 (va);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_multattr-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_multattr-1.c
@@ -0,0 +1,51 @@
+/* Test for multiple format attributes.  Test for printf and scanf attributes
+   together.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* If we specify multiple attributes for a single function, they should
+   all apply.  This should apply whether they are on the same declaration
+   or on different declarations.  */
+
+extern void my_vprintf_scanf (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_printf__, 1, 0)))
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern void my_vprintf_scanf2 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)))
+     __attribute__((__format__(__ms_printf__, 1, 0)));
+
+extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_printf__, 1, 0)));
+extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_printf__, 1, 0)));
+
+void
+foo (va_list ap, int *ip, long *lp)
+{
+  my_vprintf_scanf ("%d", ap, "%d", ip);
+  my_vprintf_scanf ("%d", ap, "%ld", lp);
+  my_vprintf_scanf ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf2 ("%d", ap, "%d", ip);
+  my_vprintf_scanf2 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf2 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf2 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf3 ("%d", ap, "%d", ip);
+  my_vprintf_scanf3 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf3 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf3 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf4 ("%d", ap, "%d", ip);
+  my_vprintf_scanf4 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf4 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf4 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_multattr-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_multattr-2.c
@@ -0,0 +1,40 @@
+/* Test for multiple format attributes.  Test for printf and scanf attributes
+   together, in different places on the declarations.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* If we specify multiple attributes for a single function, they should
+   all apply, wherever they are placed on the declarations.  */
+
+extern __attribute__((__format__(__ms_printf__, 1, 0))) void
+     my_vprintf_scanf (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern void (__attribute__((__format__(__ms_printf__, 1, 0))) my_vprintf_scanf2)
+     (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern __attribute__((__format__(__ms_scanf__, 3, 4))) void
+     (__attribute__((__format__(__ms_printf__, 1, 0))) my_vprintf_scanf3)
+     (const char *, va_list, const char *, ...);
+
+void
+foo (va_list ap, int *ip, long *lp)
+{
+  my_vprintf_scanf ("%d", ap, "%d", ip);
+  my_vprintf_scanf ("%d", ap, "%ld", lp);
+  my_vprintf_scanf ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf2 ("%d", ap, "%d", ip);
+  my_vprintf_scanf2 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf2 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf2 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf3 ("%d", ap, "%d", ip);
+  my_vprintf_scanf3 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf3 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf3 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_multattr-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_multattr-3.c
@@ -0,0 +1,29 @@
+/* Test for multiple format_arg attributes.  Test for both branches
+   getting checked.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+extern char *ngettext (const char *, const char *, unsigned long int)
+     __attribute__((__format_arg__(1))) __attribute__((__format_arg__(2)));
+
+void
+foo (long l, int nfoo)
+{
+  printf (ngettext ("%d foo", "%d foos", nfoo), nfoo);
+  printf (ngettext ("%d foo", "%d foos", l), l); /* { dg-warning "int" "wrong type in conditional expr" } */
+  printf (ngettext ("%d foo", "%ld foos", l), l); /* { dg-warning "int" "wrong type in conditional expr" } */
+  printf (ngettext ("%ld foo", "%d foos", l), l); /* { dg-warning "int" "wrong type in conditional expr" } */
+  /* Should allow one case to have extra arguments.  */
+  printf (ngettext ("1 foo", "%d foos", nfoo), nfoo);
+  printf (ngettext ("1 foo", "many foos", nfoo), nfoo); /* { dg-warning "too many" "too many args in all branches" } */
+  printf (ngettext ("", "%d foos", nfoo), nfoo);
+  printf (ngettext ("1 foo", (nfoo > 0) ? "%d foos" : "no foos", nfoo), nfoo);
+  printf (ngettext ("%d foo", (nfoo > 0) ? "%d foos" : "no foos", nfoo), nfoo);
+  printf (ngettext ("%ld foo", (nfoo > 0) ? "%d foos" : "no foos", nfoo), nfoo); /* { dg-warning "long int" "wrong type" } */
+  printf (ngettext ("%d foo", (nfoo > 0) ? "%ld foos" : "no foos", nfoo), nfoo); /* { dg-warning "long int" "wrong type" } */
+  printf (ngettext ("%d foo", (nfoo > 0) ? "%d foos" : "%ld foos", nfoo), nfoo); /* { dg-warning "long int" "wrong type" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-1.c
@@ -0,0 +1,15 @@
+/* Test for warnings for extra format arguments being disabled by
+   -Wno-format-extra-args.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wno-format-extra-args" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i)
+{
+  printf ("foo", i);
+  printf ("%1$d", i, i);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-2.c
@@ -0,0 +1,28 @@
+/* Test for warnings for extra format arguments being disabled by
+   -Wno-format-extra-args.  Test which warnings still apply with $
+   operand numbers.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wno-format-extra-args" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, int *ip, va_list va)
+{
+  printf ("%3$d%1$d", i, i, i); /* { dg-warning "before used" "unused $ operand" } */
+  printf ("%2$d%1$d", i, i, i);
+  vprintf ("%3$d%1$d", va); /* { dg-warning "before used" "unused $ operand" } */
+  /* With scanf formats, gaps in the used arguments are allowed only if the
+     arguments are all pointers.  In such a case, should only give the lesser
+     warning about unused arguments rather than the more serious one about
+     argument gaps.  */
+  scanf ("%3$d%1$d", ip, ip, ip);
+  /* If there are non-pointer arguments unused at the end, this is also OK.  */
+  scanf ("%3$d%1$d", ip, ip, ip, i);
+  scanf ("%3$d%1$d", ip, i, ip); /* { dg-warning "before used" "unused $ scanf non-pointer operand" } */
+  /* Can't check the arguments in the vscanf case, so should suppose the
+     lesser problem.  */
+  vscanf ("%3$d%1$d", va);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_no-y2k-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_no-y2k-1.c
@@ -0,0 +1,13 @@
+/* Test for warnings for Y2K problems not being on by default.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  strftime (s, m, "%y%c%x", tp);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-1.c
@@ -0,0 +1,14 @@
+/* Test for warnings for non-string-literal formats.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wformat-nonliteral" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t i)
+{
+  printf ((const char *)i, i); /* { dg-warning "argument types" "non-literal" } */
+  printf (s, i); /* { dg-warning "argument types" "non-literal" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-2.c
@@ -0,0 +1,14 @@
+/* Test for warnings for non-string-literal formats.  Test with -Wformat=2.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat=2" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t i)
+{
+  printf ((const char *)i, i); /* { dg-warning "argument types" "non-literal" } */
+  printf (s, i); /* { dg-warning "argument types" "non-literal" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-3.c
@@ -0,0 +1,13 @@
+/* Test for warnings for non-string-literal formats.  Test for strftime formats.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wformat-nonliteral" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp, char *fmt)
+{
+  strftime (s, m, fmt, tp); /* { dg-warning "format string" "non-literal" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nul-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nul-1.c
@@ -0,0 +1,15 @@
+/* Test diagnostics for suppressing contains nul
+   -Wformat.  -Wformat.  */
+/* Origin: Bruce Korb <bkorb@gnu.org> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat -Wno-format-contains-nul" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (void)
+{
+  static char const fmt[] = "x%s\0%s\n\0abc";
+  printf (fmt+4, fmt+8); /* { dg-bogus "embedded.*in format" "bogus embed warning" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nul-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nul-2.c
@@ -0,0 +1,17 @@
+/* Test diagnostics for options used on their own without
+   -Wformat.  -Wformat-.  */
+/* Origin: Bruce Korb <bkorb@gnu.org> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+
+/* { dg-warning "embedded .* in format" "ignored" { target *-*-* } 0 } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+fumble (void)
+{
+  static char const fmt[] = "x%s\0%s\n\0abc";
+  printf (fmt+4, fmt+8);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_null-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_null-1.c
@@ -0,0 +1,28 @@
+/* Test for some aspects of null format string handling.  */
+/* Origin: Jason Thorpe <thorpej@wasabisystems.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+extern void my_printf (const char *, ...) __attribute__((format(ms_printf,1,2)));
+extern const char *my_format (const char *, const char *)
+  __attribute__((format_arg(2)));
+
+void
+foo (int i1)
+{
+  /* Warning about a null format string has been decoupled from the actual
+     format check.  However, we still expect to be warned about any excess
+     arguments after a null format string.  */
+  my_printf (NULL);
+  my_printf (NULL, i1); /* { dg-warning "too many" "null format with arguments" } */
+
+  my_printf (my_format ("", NULL));
+  my_printf (my_format ("", NULL), i1); /* { dg-warning "too many" "null format_arg with arguments" } */
+
+  /* While my_printf allows a null argument, dgettext does not, so we expect
+     a null argument warning here.  */
+  my_printf (dgettext ("", NULL)); /* { dg-warning "null" "null format with dgettext" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_plus-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_plus-1.c
@@ -0,0 +1,21 @@
+/* Test for printf formats using string literal plus constant.
+ */
+/* Origin: Jakub Jelinek <jakub@redhat.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat=2" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i)
+{
+  printf ("%%d\n" + 1, i);
+  printf (5 + "%.-*d%3d\n", i);
+  printf ("%d%d" + 2, i, i);	/* { dg-warning "arguments" "wrong number of args" } */
+  printf (3 + "%d\n");		/* { dg-warning "zero-length" "zero-length string" } */
+  printf ("%d\n" + i, i);	/* { dg-warning "not a string" "non-constant addend" } */
+  printf ("%d\n" + 10);		/* { dg-warning "not a string" "too large addend" } */
+  printf ("%d\n" - 1, i);	/* { dg-warning "not a string" "minus constant" } */
+  printf ("%d\n" + -1, i);	/* { dg-warning "not a string" "negative addend" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_sec-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_sec-1.c
@@ -0,0 +1,13 @@
+/* Test for security warning when non-literal format has no arguments.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wformat-security" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s)
+{
+  printf (s); /* { dg-warning "no format arguments" "security warning" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_unnamed-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_unnamed-1.c
@@ -0,0 +1,24 @@
+/* Test for warnings with possibly unnamed integer types.  Bug 24329.  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+/* { dg-options "-Wformat -msse" { target { { i?86-*-* x86_64-*-* } && ilp32 } } } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* Definition of TItype follows same logic as in gcc.dg/titype-1.c,
+   but must be a #define to avoid giving the type a name.  */
+#if defined(__LP64__) && !defined(__hppa__)
+#define TItype int __attribute__ ((mode (TI)))
+#else
+#define TItype long
+#endif
+
+void
+f (TItype x)
+{
+  printf("%d", x); /* { dg-warning "expects type" } */
+  printf("%d", 141592653589793238462643383279502884197169399375105820974944); /* { dg-warning "expects type" } */
+  /* { dg-warning "unsigned only|too large" "constant" { target *-*-* } 22 } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_va-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_va-1.c
@@ -0,0 +1,14 @@
+/* Test for strange warning in format checking.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (void *p)
+{
+  printf ("%d", p); /* { dg-bogus "va_list" "wrong type in format warning" } */
+  /* { dg-warning "format" "format error" { target *-*-* } 12 } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_warnll-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_warnll-1.c
@@ -0,0 +1,19 @@
+/* Test for printf formats.  C99 "long long" formats should be accepted with
+   -Wno-long-long.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wno-long-long" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (long long ll, unsigned long long ull, long long *lln,
+     long long *llp, unsigned long long *ullp)
+{
+  /* Test for accepting standard "long long" formats.  */
+  printf ("%I64d%I64i%I64o%I64u%I64x%I64X%I64n", ll, ll, ull, ull, ull, ull, lln);
+  scanf ("%I64d%I64i%I64o%I64u%I64x%I64X%I64n", llp, llp,
+	 ullp, ullp, ullp, ullp, lln);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_zero-length-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_zero-length-1.c
@@ -0,0 +1,16 @@
+/* Test the -Wno-format-zero-length option, which suppresses warnings
+   about zero-length formats.  */
+/* Origin: Jason Thorpe <thorpej@wasabisystems.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wno-format-zero-length" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (void)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.1 (pages 131-134).  */
+  /* Zero-length format strings are allowed.  */
+  printf ("");
+}
Index: gcc/gcc/testsuite/gcc.dg/format/multattr-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/multattr-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/multattr-1.c
@@ -4,6 +4,7 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 /* If we specify multiple attributes for a single function, they should
@@ -11,22 +12,22 @@
    or on different declarations.  */
 
 extern void my_vprintf_scanf (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__printf__, 1, 0)))
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)))
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
 extern void my_vprintf_scanf2 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)))
-     __attribute__((__format__(__printf__, 1, 0)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)))
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)));
 
 extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__printf__, 1, 0)));
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)));
 extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
 extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__printf__, 1, 0)));
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)));
 
 void
 foo (va_list ap, int *ip, long *lp)
Index: gcc/gcc/testsuite/gcc.dg/format/multattr-2.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/multattr-2.c
+++ gcc/gcc/testsuite/gcc.dg/format/multattr-2.c
@@ -4,21 +4,22 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 /* If we specify multiple attributes for a single function, they should
    all apply, wherever they are placed on the declarations.  */
 
-extern __attribute__((__format__(__printf__, 1, 0))) void
+extern __attribute__((__format__(gnu_attr___printf__, 1, 0))) void
      my_vprintf_scanf (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
-extern void (__attribute__((__format__(__printf__, 1, 0))) my_vprintf_scanf2)
+extern void (__attribute__((__format__(gnu_attr___printf__, 1, 0))) my_vprintf_scanf2)
      (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
-extern __attribute__((__format__(__scanf__, 3, 4))) void
-     (__attribute__((__format__(__printf__, 1, 0))) my_vprintf_scanf3)
+extern __attribute__((__format__(gnu_attr___scanf__, 3, 4))) void
+     (__attribute__((__format__(gnu_attr___printf__, 1, 0))) my_vprintf_scanf3)
      (const char *, va_list, const char *, ...);
 
 void
Index: gcc/gcc/testsuite/gcc.dg/format/null-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/null-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/null-1.c
@@ -3,9 +3,10 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern void my_printf (const char *, ...) __attribute__((format(printf,1,2)));
+extern void my_printf (const char *, ...) __attribute__((format(gnu_attr_printf,1,2)));
 extern const char *my_format (const char *, const char *)
   __attribute__((format_arg(2)));
 
=

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf           formatters to c-format.c
  2008-02-19 13:30             ` Kai Tietz
@ 2008-02-19 14:10               ` Joseph S. Myers
  2008-02-19 15:16                 ` Kai Tietz
  0 siblings, 1 reply; 61+ messages in thread
From: Joseph S. Myers @ 2008-02-19 14:10 UTC (permalink / raw)
  To: Kai Tietz; +Cc: Danny Smith, GCC Patches, NightStrike

On Tue, 19 Feb 2008, Kai Tietz wrote:

> What's about extending the attribute definition structure by a kind member 
> and compare instead of index position, there kind? So this function is no 
> longer necessary and we need just in the c-format.h enum values defining 
> kinds.
> 
> typedef enum {
>  attr_kind_printf=0,
>  attr_kind_scanf,
>  ...
> } attr_kind;

That would be better, but it's still the wrong abstraction level.  We 
should never be asking the question "is this a printf format?".  Instead, 
we should ask "does this have property X that is relevant for this piece 
of code?".  Property X would then have its own flag set in the structure 
for printf.

There's a check against strftime_format_type; we already have the right 
flag for that, FMT_FLAG_ARG_CONVERT.  There are also checks against 
GCC-internal types; those could stay, since they won't get system-specific 
variants, or they could get a few more flags (for the three essentially 
different styles of internal format that get handled differently in 
handle_format_attribute where these checks appear).

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf          formatters to c-format.c
  2008-02-19 12:38           ` Joseph S. Myers
@ 2008-02-19 13:30             ` Kai Tietz
  2008-02-19 14:10               ` Joseph S. Myers
  0 siblings, 1 reply; 61+ messages in thread
From: Kai Tietz @ 2008-02-19 13:30 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: Danny Smith, GCC Patches, NightStrike

"Joseph S. Myers" <joseph@codesourcery.com> wrote on 19.02.2008 13:28:31:

> On Tue, 19 Feb 2008, Kai Tietz wrote:
> 
> > > "formatter" is nowhere used in the existing code to refer to kinds 
of 
> > > formats; I suggest just using "format" throughout the patch.
> > 
> > 
> > It is renamed to sys_format.c, fine?
> 
> I mean everywhere: in all the function names, not just in one file name.
> 
> > > > +/* For none gnu style formatter types we need to compare the none
> > > gnu formatter
> > > > +   and a gnu style formatter style to compare in kind.   This is 
> > > done via the
> > > > +   array TARGET_OVERRIDES_FORMAT_ATTRIBUTES.  The argument 
> > > custom_type specifiers
> > > > +   the index of the formatter. The argument def_type specifies 
> > > the gnu style
> > > > +   formatter index to be compare with. If the kind is equal it 
> > > returns true,
> > > > +   otherwise false.  */
> > > > +static int
> > > 
> > > What should this return for comparing each pair of strftime, 
> > gnu_strftime, 
> > > ms_strftime?  I can't tell from the comment.
> > > 
> > > Actually, I don't think we need this function.  The comparisons 
against 
> > > specific types that you change to call this function are used for 
two 
> > > things: processing GCC-internal formats, and giving the error 
"strftime 
> > > formats cannot format arguments".  For the former, there will be no 
> > > target-specific variants; these formats are the same everywhere. For 

> > the 
> > > latter, it would be better to replace the hardcoded check for 
> > > strftime_format_type with a check for the format not setting 
> > > FMT_FLAG_ARG_CONVERT in its flags; that's the right condition to 
check. 
> > > The diagnostic should name the particular attribute in use, whether 
> > > "strftime", "gnu_strftime" or "ms_strftime" (that is, the attribute 
in 
> > the 
> > > user's source code, not any translated version of it).
> > 
> > IMHO, this method is necessary to be able to use the existing argument 

> > checking routines and generalize the existing code.
> > If we have user defined formatters extensions, we need to get their 
gnu 
> > style variant. So we can check, if the attribute has a formatter, 
needs 
> > additional arguments, and if the formatter can be NULL, and so on.
> 
> I still can't tell what the definition is for what is considered "equal" 

> or not, and in particular what the answers should be for each pair of 
the 
> three attributes I listed above.
I treated the enums simply as kinds, not as index positions. What is a bit 
wired here in fact. I agree, that this is no fast and good solution as it 
is.

> The code should not be comparing against particular enum values.  It 
> should:
> 
> * Get a structure with information about the format (possibly converting 

> "strftime" to "gnu_strftime" or "ms_strftime" in the process, for 
> example).
> 
> * Look up information in that structure.  This information will tell 
> everything about format strings, additional arguments etc..
> 
> The only exception might be for the GCC-internal types, where you know 
> there will never be system-specific variants.

What's about extending the attribute definition structure by a kind member 
and compare instead of index position, there kind? So this function is no 
longer necessary and we need just in the c-format.h enum values defining 
kinds.

typedef enum {
 attr_kind_printf=0,
 attr_kind_scanf,
 ...
} attr_kind;

And we can remove the doubled enum list.

 Kai Tietz

|  (\_/)  This is Bunny. Copy and paste Bunny
| (='.'=) into your signature to help him gain
| (")_(") world domination.

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf          formatters to c-format.c
  2008-02-19  9:22         ` Kai Tietz
@ 2008-02-19 12:38           ` Joseph S. Myers
  2008-02-19 13:30             ` Kai Tietz
  0 siblings, 1 reply; 61+ messages in thread
From: Joseph S. Myers @ 2008-02-19 12:38 UTC (permalink / raw)
  To: Kai Tietz; +Cc: Danny Smith, GCC Patches, NightStrike

On Tue, 19 Feb 2008, Kai Tietz wrote:

> > "formatter" is nowhere used in the existing code to refer to kinds of 
> > formats; I suggest just using "format" throughout the patch.
> 
> 
> It is renamed to sys_format.c, fine?

I mean everywhere: in all the function names, not just in one file name.

> > > +/* For none gnu style formatter types we need to compare the none
> > gnu formatter
> > > +   and a gnu style formatter style to compare in kind.   This is 
> > done via the
> > > +   array TARGET_OVERRIDES_FORMAT_ATTRIBUTES.  The argument 
> > custom_type specifiers
> > > +   the index of the formatter. The argument def_type specifies 
> > the gnu style
> > > +   formatter index to be compare with. If the kind is equal it 
> > returns true,
> > > +   otherwise false.  */
> > > +static int
> > 
> > What should this return for comparing each pair of strftime, 
> gnu_strftime, 
> > ms_strftime?  I can't tell from the comment.
> > 
> > Actually, I don't think we need this function.  The comparisons against 
> > specific types that you change to call this function are used for two 
> > things: processing GCC-internal formats, and giving the error "strftime 
> > formats cannot format arguments".  For the former, there will be no 
> > target-specific variants; these formats are the same everywhere.  For 
> the 
> > latter, it would be better to replace the hardcoded check for 
> > strftime_format_type with a check for the format not setting 
> > FMT_FLAG_ARG_CONVERT in its flags; that's the right condition to check. 
> > The diagnostic should name the particular attribute in use, whether 
> > "strftime", "gnu_strftime" or "ms_strftime" (that is, the attribute in 
> the 
> > user's source code, not any translated version of it).
> 
> IMHO, this method is necessary to be able to use the existing argument 
> checking routines and generalize the existing code.
> If we have user defined formatters extensions, we need to get their gnu 
> style variant. So we can check, if the attribute has a formatter, needs 
> additional arguments, and if the formatter can be NULL, and so on.

I still can't tell what the definition is for what is considered "equal" 
or not, and in particular what the answers should be for each pair of the 
three attributes I listed above.

The code should not be comparing against particular enum values.  It 
should:

* Get a structure with information about the format (possibly converting 
"strftime" to "gnu_strftime" or "ms_strftime" in the process, for 
example).

* Look up information in that structure.  This information will tell 
everything about format strings, additional arguments etc..

The only exception might be for the GCC-internal types, where you know 
there will never be system-specific variants.

> > Perhaps that enum should simply move to this header and avoid the 
> separate 
> > list?
> 
> Fine, but this can be a follow up patch. We have to give for these enums 
> more unique names, to prevent clashs. Do you agree?

There should not be any intermediate committed stage with duplicate enums.  
Moving things as a *preliminary* patch (not a followup patch) that can be 
considered on its own before the main patch would however make sense.

Much the same applies to eliminating comparisons with particular enum 
values: that could be done as a preliminary patch.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf         formatters to c-format.c
  2008-02-13 18:32       ` Joseph S. Myers
@ 2008-02-19  9:22         ` Kai Tietz
  2008-02-19 12:38           ` Joseph S. Myers
  0 siblings, 1 reply; 61+ messages in thread
From: Kai Tietz @ 2008-02-19  9:22 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: Danny Smith, GCC Patches, NightStrike

[-- Attachment #1: Type: text/plain, Size: 10526 bytes --]

Hi,

"Joseph S. Myers" <joseph@codesourcery.com> wrote on 13.02.2008 19:17:01:

> On Mon, 4 Feb 2008, Kai Tietz wrote:
> 
> > Thank you for your advice. May just by consistancy we should'nt 
declare 
> > C99 functions for c90 in format.h. But the %Y is not present for mingw 
at 
> > all. Therefore I prefer to disable them for these targets completely.
> 
> In that case you'll need to disable c99-printf-3.c for those targets as 
> well; this patch version still has the bogus changes there.
I revert c99-printf-3.c and disable it for mingw.

> "formatter" is nowhere used in the existing code to refer to kinds of 
> formats; I suggest just using "format" throughout the patch.


It is renamed to sys_format.c, fine?

> >         * testsuite/gcc.dg/format/sys_formatter.c: New.
> 
> Does not belong in gcc/; you appear to have a properly located ChangeLog 

> entry for this file below.
> 
> > @@ -1776,7 +1782,22 @@ check_format_info_main (format_check_res
> >        if (fli)
> >     {
> >       while (fli->name != 0 && fli->name[0] != *format_chars)
> > -       fli++;
> > +       {
> > +         if (fli->name[0] == '\0')
> [...]
> 
> If this patch chunk is changing the meaning of some structure in 
> c-format.h, the comments on that structure need updating to describe the 

> new semantics implemented by this new code.
> 
> > +/* Description of gnu specific format attributes reflected to
> > +   system format attribute types, as printf, scanf, strftime, and
> > +   strfmon.  */
> 
> Not clear English, especially "reflected".  I think something like
> 
> /* Attributes such as "printf" are equivalent to those such as
>    "gnu_printf" unless this is overridden by a target.  */
> 
> would be a clearer description of the purpose of this array.
> 
> > +const target_ovr_attr gnu_target_overrides_format_attributes[] =
> 
> I think this can be static.
> 
> > +/* Translate to unified attribute name. This is used in 
> decode_format_type and
> > +   decode_format_attr. In attr_name the user specified argument 
> is passed. It
> > +   returns the unified formatter name from 
> TARGET_OVERRIDES_FORMAT_ATTRIBUTES
> > +   or the attr_name passed to this function, if there is no 
> matching entry.  */
> > +static const char *
> > +replace_formatter_name_to_system_name (const char *attr_name)
> 
> "replace ... to" isn't idiomatic English; "convert" might be better than 

> "replace" here.
> 
> > +/* A helper function to compare the target override format 
> attribute tattr_name
> > +   and the user format attribute attr_name. The underscore 
> variant of attr_name
> > +   is ignore for compare. I returns for equal attribute the value
> one, otherwise
> > +   zero.  */
> 
> /* Return true if TATTR_NAME and ATTR_NAME are the same format 
attribute,
>    counting "name" and "__name__" as the same, false otherwise.  */
> 
> > +static int
> 
> Should return bool rather than int.
> 

I changed all you suggest above.

> > +/* For none gnu style formatter types we need to compare the none
> gnu formatter
> > +   and a gnu style formatter style to compare in kind.   This is 
> done via the
> > +   array TARGET_OVERRIDES_FORMAT_ATTRIBUTES.  The argument 
> custom_type specifiers
> > +   the index of the formatter. The argument def_type specifies 
> the gnu style
> > +   formatter index to be compare with. If the kind is equal it 
> returns true,
> > +   otherwise false.  */
> > +static int
> 
> What should this return for comparing each pair of strftime, 
gnu_strftime, 
> ms_strftime?  I can't tell from the comment.
> 
> Actually, I don't think we need this function.  The comparisons against 
> specific types that you change to call this function are used for two 
> things: processing GCC-internal formats, and giving the error "strftime 
> formats cannot format arguments".  For the former, there will be no 
> target-specific variants; these formats are the same everywhere.  For 
the 
> latter, it would be better to replace the hardcoded check for 
> strftime_format_type with a check for the format not setting 
> FMT_FLAG_ARG_CONVERT in its flags; that's the right condition to check. 
> The diagnostic should name the particular attribute in use, whether 
> "strftime", "gnu_strftime" or "ms_strftime" (that is, the attribute in 
the 
> user's source code, not any translated version of it).

IMHO, this method is necessary to be able to use the existing argument 
checking routines and generalize the existing code.
If we have user defined formatters extensions, we need to get their gnu 
style variant. So we can check, if the attribute has a formatter, needs 
additional arguments, and if the formatter can be NULL, and so on.

> Perhaps that enum should simply move to this header and avoid the 
separate 
> list?

Fine, but this can be a follow up patch. We have to give for these enums 
more unique names, to prevent clashs. Do you agree?

2008-02-04      Kai Tietz  <kai.tietz@onevision.com>

        * c-format.c: (replace_formatter_name_to_system_name): New.
        (cmp_formatter_kind): New.
        (cmp_attribs): New.
        (compare_formatter_name_to_system_name): New.
        (decode_format_attr): Use of 
replace_formatter_name_to_system_name.
        (format_types_orig): Add gnu_ prefix to names.
        (check_format_info_main): Special treating of \0 escaped names for
        supporting multi-character formatters as I32, I64.
        (TARGET_OVERRIDES_FORMAT_ATTRIBUTES): Use of user defined 
attributes.
        (gnu_target_overrides_format_attributes): New.
        * gcc/c-format.h: Add structure target_ovr_attr to hold
        system specific formatter names.
        * config.gcc: Add for x86&x86_64 cygwin and mingw32 targets the
        msformat-c.o file to c_target_objs and cxx_target_objs.
        * config/i386/mingw32.h: (TARGET_OVERRIDES_FORMAT_ATTRIBUTES): 
New.
        (TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT): New.
        (TARGET_N_FORMAT_TYPES): New.
        * config/i386/msformat-c.c: New.
        * config/i386/t-cygming: Add build rule for msformat-c.o.
        * doc/extend.texi: Add new format names gnu_* and ms_*.
        * doc/tm.texi: (TARGET_OVERRIDES_FORMAT_ATTRIBUTES): New.

ChangeLog for gcc/testcase

2008-02-04  Kai Tietz  <kai.tietz@onevision.com>

        * gcc.dg/format/ms_array-1.c: New.
        * gcc.dg/format/ms_c90-scanf-3.c: New.
        * gcc.dg/format/ms_c99-strftime-1.c: New.
        * gcc.dg/format/ms_no-y2k-1.c: New.
        * gcc.dg/format/ms_attr-1.c: New.
        * gcc.dg/format/ms_c90-scanf-4.c: New.
        * gcc.dg/format/ms_c99-strftime-2.c: New.
        * gcc.dg/format/ms_nonlit-1.c: New.
        * gcc.dg/format/ms_c90-scanf-5.c: New.
        * gcc.dg/format/ms_cast-1.c: New.
        * gcc.dg/format/ms_nonlit-2.c: New.
        * gcc.dg/format/ms_attr-2.c: New.
        * gcc.dg/format/ms_c90-strftime-1.c: New.
        * gcc.dg/format/ms_miss-1.c: New.
        * gcc.dg/format/ms_nonlit-3.c: New.
        * gcc.dg/format/ms_attr-3.c: New.
        * gcc.dg/format/ms_c90-strftime-2.c: New.
        * gcc.dg/format/ms_miss-2.c: New.
        * gcc.dg/format/ms_nul-1.c: New.
        * gcc.dg/format/ms_attr-4.c: New.
        * gcc.dg/format/ms_c94-printf-1.c: New.
        * gcc.dg/format/ms_miss-3.c: New.
        * gcc.dg/format/ms_nul-2.c: New.
        * gcc.dg/format/ms_attr-7.c: New.
        * gcc.dg/format/ms_c94-scanf-1.c: New.
        * gcc.dg/format/ms_miss-4.c: New.
        * gcc.dg/format/ms_null-1.c: New.
        * gcc.dg/format/ms_bitfld-1.c: New.
        * gcc.dg/format/ms_c99-printf-1.c: New.
        * gcc.dg/format/ms_miss-5.c: New.
        * gcc.dg/format/ms_plus-1.c: New.
        * gcc.dg/format/ms_branch-1.c: New.
        * gcc.dg/format/ms_c99-printf-2.c: New.
        * gcc.dg/format/ms_miss-6.c: New.
        * gcc.dg/format/ms_sec-1.c: New.
        * gcc.dg/format/ms_c90-printf-1.c: New.
        * gcc.dg/format/ms_c99-printf-3.c: New.
        * gcc.dg/format/ms_multattr-1.c: New.
        * gcc.dg/format/ms_unnamed-1.c: New.
        * gcc.dg/format/ms_c90-printf-2.c: New.
        * gcc.dg/format/ms_c99-scanf-1.c: New.
        * gcc.dg/format/ms_multattr-2.c: New.
        * gcc.dg/format/ms_va-1.c: New.
        * gcc.dg/format/ms_c90-printf-3.c: New.
        * gcc.dg/format/ms_c99-scanf-2.c: New.
        * gcc.dg/format/ms_multattr-3.c: New.
        * gcc.dg/format/ms_warnll-1.c: New.
        * gcc.dg/format/ms_c90-scanf-1.c: New.
        * gcc.dg/format/ms_c99-scanf-3.c: New.
        * gcc.dg/format/ms_no-exargs-1.c: New.
        * gcc.dg/format/ms_zero-length-1.c: New.
        * gcc.dg/format/ms_c90-scanf-2.c: New.
        * gcc.dg/format/ms_c99-scanf-4.c: New.
        * gcc.dg/format/ms_no-exargs-2.c: New.
        * gcc.dg/format/null-1.c: Add gnu style usage for mingw.
        * gcc.dg/format/miss-1.c: Likewise.
        * gcc.dg/format/miss-3.c: Likewise.
        * gcc.dg/format/multattr-2.c: Likewise.
        * gcc.dg/format/miss-5.c: Likewise.
        * gcc.dg/format/attr-2.c: Likewise.
        * gcc.dg/format/attr-4.c: Likewise.
        * gcc.dg/format/c90-scanf-4.c: Likewise.
        * gcc.dg/format/c99-printf-3.c: Likewise.
        * gcc.dg/format/multattr-1.c: Likewise.
        * gcc.dg/format/miss-4.c: Likewise.
        * gcc.dg/format/miss-6.c: Likewise.
        * gcc.dg/format/c90-printf-3.c: Likewise.
        * gcc.dg/format/attr-1.c: Likewise.
        * gcc.dg/format/attr-3.c: Likewise.
        * gcc.dg/format/attr-7.c: Likewise.
        * gcc.dg/format/format.h: Treat mingw and gnu style.
        * gcc.dg/format/sys_format.c: New.


  Kai



|  (\_/)  This is Bunny. Copy and paste Bunny
| (='.'=) into your signature to help him gain
| (")_(") world domination.

------------------------------------------------------------------------------------------
  OneVision Software Entwicklungs GmbH & Co. KG
  Dr.-Leo-Ritter-Straße 9 - 93049 Regensburg
  Tel: +49.(0)941.78004.0 - Fax: +49.(0)941.78004.489 - www.OneVision.com
  Commerzbank Regensburg - BLZ 750 400 62 - Konto 6011050
  Handelsregister: HRA 6744, Amtsgericht Regensburg
  Komplementärin: OneVision Software Entwicklungs Verwaltungs GmbH
  Dr.-Leo-Ritter-Straße 9 – 93049 Regensburg
  Handelsregister: HRB 8932, Amtsgericht Regensburg - Geschäftsführer: 
Ulrike Döhler, Manuela Kluger


[-- Attachment #2: mingw-msformat.txt --]
[-- Type: text/plain, Size: 159096 bytes --]

Index: gcc/gcc/c-format.c
===================================================================
--- gcc.orig/gcc/c-format.c
+++ gcc/gcc/c-format.c
@@ -74,13 +74,15 @@ typedef struct function_format_info
 
 static bool decode_format_attr (tree, function_format_info *, int);
 static int decode_format_type (const char *);
+static bool cmp_formatter_kind (int ctype, int def_type);
 
 static bool check_format_string (tree argument,
 				 unsigned HOST_WIDE_INT format_num,
 				 int flags, bool *no_add_attrs);
 static bool get_constant (tree expr, unsigned HOST_WIDE_INT *value,
 			  int validated_p);
-
+static const char *convert_formatter_name_to_system_name (const char *attr_name);
+static bool cmp_attribs (const char *tattr_name, const char *attr_name);
 
 /* Handle a "format_arg" attribute; arguments as in
    struct attribute_spec.handler.  */
@@ -191,6 +193,8 @@ decode_format_attr (tree args, function_
     {
       const char *p = IDENTIFIER_POINTER (format_type_id);
 
+      p = convert_formatter_name_to_system_name (p);
+
       info->format_type = decode_format_type (p);
 
       if (info->format_type == format_type_error)
@@ -715,7 +719,7 @@ static const format_char_info monetary_c
 /* This must be in the same order as enum format_type.  */
 static const format_kind_info format_types_orig[] =
 {
-  { "printf",   printf_length_specs,  print_char_table, " +#0-'I", NULL,
+  { "gnu_printf",   printf_length_specs,  print_char_table, " +#0-'I", NULL,
     printf_flag_specs, printf_flag_pairs,
     FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
     'w', 0, 'p', 0, 'L', 0,
@@ -757,18 +761,18 @@ static const format_kind_info format_typ
     0, 0, 0, 0, 0, 0,
     NULL, NULL
   },
-  { "scanf",    scanf_length_specs,   scan_char_table,  "*'I", NULL,
+  { "gnu_scanf",    scanf_length_specs,   scan_char_table,  "*'I", NULL,
     scanf_flag_specs, scanf_flag_pairs,
     FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
     'w', 0, 0, '*', 'L', 'm',
     NULL, NULL
   },
-  { "strftime", NULL,                 time_char_table,  "_-0^#", "EO",
+  { "gnu_strftime", NULL,                 time_char_table,  "_-0^#", "EO",
     strftime_flag_specs, strftime_flag_pairs,
     FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0, 0,
     NULL, NULL
   },
-  { "strfmon",  strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
+  { "gnu_strfmon",  strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
     strfmon_flag_specs, strfmon_flag_pairs,
     FMT_FLAG_ARG_CONVERT, 'w', '#', 'p', 0, 'L', 0,
     NULL, NULL
@@ -847,6 +851,8 @@ decode_format_type (const char *s)
 {
   int i;
   int slen;
+
+  s = convert_formatter_name_to_system_name (s);
   slen = strlen (s);
   for (i = 0; i < n_format_types; i++)
     {
@@ -1776,7 +1782,22 @@ check_format_info_main (format_check_res
       if (fli)
 	{
 	  while (fli->name != 0 && fli->name[0] != *format_chars)
-	    fli++;
+	    {
+	      if (fli->name[0] == '\0')
+		{
+		  int si  = strlen (fli->name + 1) + 1;
+		  int i = 1;
+		  while (fli->name[i] != 0 && fli->name[i] == format_chars [i - 1])
+		    ++i;
+		 if (si == i)
+		   {
+		     if (si > 2)
+		       format_chars += si - 2;
+		     break;
+		   }
+	       }
+	      fli++;
+	    }
 	  if (fli->name != 0)
 	    {
 	      format_chars++;
@@ -2703,6 +2724,81 @@ init_dynamic_diag_info (void)
 extern const format_kind_info TARGET_FORMAT_TYPES[];
 #endif
 
+#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+extern const target_ovr_attr TARGET_OVERRIDES_FORMAT_ATTRIBUTES[];
+#endif
+
+/* Attributes such as "printf" are equivalent to those such as
+   "gnu_printf" unless this is overridden by a target.  */
+static const target_ovr_attr gnu_target_overrides_format_attributes[] =
+{
+  { "gnu_printf",   "printf", ovr_printf_format_type },
+  { "gnu_scanf",    "scanf", ovr_scanf_format_type },
+  { "gnu_strftime", "strftime", ovr_strftime_format_type },
+  { "gnu_strfmon",  "strfmon", ovr_strfmon_format_type },
+  { NULL,           NULL, -1 }
+};
+
+/* Translate to unified attribute name. This is used in decode_format_type and
+   decode_format_attr. In attr_name the user specified argument is passed. It
+   returns the unified formatter name from TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+   or the attr_name passed to this function, if there is no matching entry.  */
+static const char *
+convert_formatter_name_to_system_name (const char *attr_name)
+{
+  int i;
+
+  if (attr_name == NULL || *attr_name == 0 || strncmp (attr_name, "gcc_", 4) == 0)
+    return attr_name;
+
+#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+  /* Check if format attribute is overridden by target.  */
+  if (TARGET_OVERRIDES_FORMAT_ATTRIBUTES != NULL
+      && TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT > 0)
+    {
+      for (i = 0; i < TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT; ++i)
+        {
+          if (cmp_attribs (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src,
+			   attr_name))
+            return attr_name;
+          if (cmp_attribs (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_dst,
+			   attr_name))
+            return TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src;
+        }
+    }
+#endif
+  /* Otherwise default to gnu formatter.  */
+  for (i = 0; gnu_target_overrides_format_attributes[i].named_attr_src != NULL; ++i)
+    {
+      if (cmp_attribs (gnu_target_overrides_format_attributes[i].named_attr_src,
+		       attr_name))
+        return attr_name;
+      if (cmp_attribs (gnu_target_overrides_format_attributes[i].named_attr_dst,
+		       attr_name))
+        return gnu_target_overrides_format_attributes[i].named_attr_src;
+    }
+
+  return attr_name;
+}
+
+/* Return true if TATTR_NAME and ATTR_NAME are the same format attribute,
+   counting "name" and "__name__" as the same, false otherwise.  */
+static bool
+cmp_attribs (const char *tattr_name, const char *attr_name)
+{
+  int alen = strlen (attr_name);
+  int slen = (tattr_name ? strlen (tattr_name) : 0);
+  if (alen > 4 && attr_name[0] == '_' && attr_name[1] == '_'
+      && attr_name[alen - 1] == '_' && attr_name[alen - 2] == '_')
+    {
+      attr_name += 2;
+      alen -= 4;
+    }
+  if (alen != slen || strncmp (tattr_name, attr_name, alen) != 0)
+    return false;
+  return true;
+}
+
 /* Handle a "format" attribute; arguments as in
    struct attribute_spec.handler.  */
 tree
@@ -2762,7 +2858,7 @@ handle_format_attribute (tree *node, tre
 	}
     }
 
-  if (info.format_type == strftime_format_type && info.first_arg_num != 0)
+  if (cmp_formatter_kind (info.format_type, strftime_format_type) && info.first_arg_num != 0)
     {
       error ("strftime formats cannot format arguments");
       *no_add_attrs = true;
@@ -2771,12 +2867,12 @@ handle_format_attribute (tree *node, tre
 
   /* If this is a custom GCC-internal format type, we have to
      initialize certain bits a runtime.  */
-  if (info.format_type == asm_fprintf_format_type
-      || info.format_type == gcc_gfc_format_type
-      || info.format_type == gcc_diag_format_type
-      || info.format_type == gcc_tdiag_format_type
-      || info.format_type == gcc_cdiag_format_type
-      || info.format_type == gcc_cxxdiag_format_type)
+  if (cmp_formatter_kind (info.format_type, asm_fprintf_format_type)
+      || cmp_formatter_kind (info.format_type, gcc_gfc_format_type)
+      || cmp_formatter_kind (info.format_type, gcc_diag_format_type)
+      || cmp_formatter_kind (info.format_type, gcc_tdiag_format_type)
+      || cmp_formatter_kind (info.format_type, gcc_cdiag_format_type)
+      || cmp_formatter_kind (info.format_type, gcc_cxxdiag_format_type))
     {
       /* Our first time through, we have to make sure that our
 	 format_type data is allocated dynamically and is modifiable.  */
@@ -2787,18 +2883,18 @@ handle_format_attribute (tree *node, tre
 
       /* If this is format __asm_fprintf__, we have to initialize
 	 GCC's notion of HOST_WIDE_INT for checking %wd.  */
-      if (info.format_type == asm_fprintf_format_type)
+      if (cmp_formatter_kind (info.format_type, asm_fprintf_format_type))
 	init_dynamic_asm_fprintf_info ();
       /* If this is format __gcc_gfc__, we have to initialize GCC's
 	 notion of 'locus' at runtime for %L.  */
-      else if (info.format_type == gcc_gfc_format_type)
+      else if (cmp_formatter_kind (info.format_type, gcc_gfc_format_type))
 	init_dynamic_gfc_info ();
       /* If this is one of the diagnostic attributes, then we have to
 	 initialize 'location_t' and 'tree' at runtime.  */
-      else if (info.format_type == gcc_diag_format_type
-	       || info.format_type == gcc_tdiag_format_type
-	       || info.format_type == gcc_cdiag_format_type
-	       || info.format_type == gcc_cxxdiag_format_type)
+      else if (cmp_formatter_kind (info.format_type, gcc_diag_format_type)
+	       || cmp_formatter_kind (info.format_type, gcc_tdiag_format_type)
+	       || cmp_formatter_kind (info.format_type, gcc_cdiag_format_type)
+	       || cmp_formatter_kind (info.format_type, gcc_cxxdiag_format_type))
 	init_dynamic_diag_info ();
       else
 	gcc_unreachable ();
@@ -2806,3 +2902,43 @@ handle_format_attribute (tree *node, tre
 
   return NULL_TREE;
 }
+
+/* If we have user defined formatters extensions, we need to get their gnu style
+   variant. So we can check, if the attribute has a formatter, needs additional
+   arguments, and if the formatter can be NULL, and so on.
+   If the kind is equal it returns true, otherwise false.  */
+static bool
+cmp_formatter_kind (int custom_type, int def_type)
+{
+  int i;
+  int n_format_types_org = ARRAY_SIZE (format_types_orig);
+  const char *name_custom = NULL;
+  if (custom_type < n_format_types_org)
+    return custom_type == def_type;
+#ifdef TARGET_FORMAT_TYPES
+  if (TARGET_N_FORMAT_TYPES <= 0
+      || ((custom_type - n_format_types_org) >= TARGET_N_FORMAT_TYPES))
+    return custom_type == def_type;
+
+  name_custom = TARGET_FORMAT_TYPES[custom_type - n_format_types_org].name;
+
+#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+  /* Check if format attribute is overridden by target.  */
+  if (TARGET_OVERRIDES_FORMAT_ATTRIBUTES != NULL
+      && TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT > 0)
+    {
+      for (i = 0; i < TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT; ++i)
+        {
+          if (cmp_attribs (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src,
+                           name_custom))
+            {
+	      custom_type = TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_type;
+	      break;
+	    }
+        }
+    }
+#endif
+
+#endif
+  return custom_type == def_type;
+}
Index: gcc/gcc/c-format.h
===================================================================
--- gcc.orig/gcc/c-format.h
+++ gcc/gcc/c-format.h
@@ -85,7 +85,9 @@ enum
    possibly a doubled version such as "hh".  */
 typedef struct
 {
-  /* Name of the single-character length modifier.  */
+  /* Name of the single-character length modifier. If prefixed by
+     a zero character, it discribes a multi character length
+     modifier, lile I64, I32, etc.  */
   const char *name;
   /* Index into a format_char_info.types array.  */
   enum format_lengths index;
@@ -306,4 +308,26 @@ typedef struct
 #define T_D128  &dfloat128_type_node
 #define TEX_D128 { STD_EXT, "_Decimal128", T_D128 }
 
+/* Structure describing how format attributes such as "printf" are
+   interpreted as "gnu_printf" or "ms_printf" on a particular system.
+   TARGET_OVERRIDES_FORMAT_ATTRIBUTES is used to specify target-specific
+   defaults.  */
+typedef struct
+{
+  /* The name of the to be copied formatter attribute. */
+  const char *named_attr_src;
+  /* The name of the to be overridden formatter attribute. */
+  const char *named_attr_dst;
+  /* Values of enum ovr_format_type.  */
+  int named_attr_type;
+} target_ovr_attr;
+
+/* Be aware to keep these values in synch with enum format_type from c-format.c.  */
+enum ovr_format_type { ovr_printf_format_type, ovr_asm_fprintf_format_type,
+		   ovr_gcc_diag_format_type, ovr_gcc_tdiag_format_type,
+		   ovr_gcc_cdiag_format_type,
+		   ovr_gcc_cxxdiag_format_type, ovr_gcc_gfc_format_type,
+		   ovr_scanf_format_type, ovr_strftime_format_type,
+		   ovr_strfmon_format_type, ovr_format_type_error = -1};
+
 #endif /* GCC_C_FORMAT_H */
Index: gcc/gcc/config.gcc
===================================================================
--- gcc.orig/gcc/config.gcc
+++ gcc/gcc/config.gcc
@@ -1365,8 +1365,8 @@ i[34567]86-*-pe | i[34567]86-*-cygwin*)
 	target_gtfiles="\$(srcdir)/config/i386/winnt.c"
 	extra_options="${extra_options} i386/cygming.opt"
 	extra_objs="winnt.o winnt-stubs.o"
-	c_target_objs=cygwin2.o
-	cxx_target_objs="cygwin2.o winnt-cxx.o"
+	c_target_objs="cygwin2.o msformat-c.o"
+	cxx_target_objs="cygwin2.o winnt-cxx.o msformat-c.o"
 	extra_gcc_objs=cygwin1.o
 	if test x$enable_threads = xyes; then
 		thread_file='posix'
@@ -1379,7 +1379,8 @@ i[34567]86-*-mingw32* | x86_64-*-mingw32
 	target_gtfiles="\$(srcdir)/config/i386/winnt.c"
 	extra_options="${extra_options} i386/cygming.opt"
 	extra_objs="winnt.o winnt-stubs.o"
-	cxx_target_objs=winnt-cxx.o
+	c_target_objs="msformat-c.o"
+	cxx_target_objs="winnt-cxx.o msformat-c.o"
 	default_use_cxa_atexit=yes
 	case ${enable_threads} in
 	  "" | yes | win32)
Index: gcc/gcc/config/i386/mingw32.h
===================================================================
--- gcc.orig/gcc/config/i386/mingw32.h
+++ gcc/gcc/config/i386/mingw32.h
@@ -143,6 +143,22 @@ do {						         \
    to register C++ static destructors.  */
 #define TARGET_CXX_USE_ATEXIT_FOR_CXA_ATEXIT hook_bool_void_true
 
+/* Contains a pointer to type target_ovr_attr defining the target specific
+   overrides of formatter attributs.  See format.h for structure definition.  */
+#undef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+#define TARGET_OVERRIDES_FORMAT_ATTRIBUTES mingw_formatter_attribute_overrides
+
+/* Specify the count of elements in TARGET_OVERRIDES_ATTRIBUTE.  */
+#undef TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT
+#define TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT 3
+
+/* MS specific format attributes for ms_printf, ms_scanf, ms_strftime.  */
+#undef TARGET_FORMAT_TYPES
+#define TARGET_FORMAT_TYPES mingw_formatter_attributes
+
+#undef TARGET_N_FORMAT_TYPES
+#define TARGET_N_FORMAT_TYPES 3
+
 /* JCR_SECTION works on mingw32.  */
 #undef TARGET_USE_JCR_SECTION
 #define TARGET_USE_JCR_SECTION 1
Index: gcc/gcc/config/i386/msformat-c.c
===================================================================
--- /dev/null
+++ gcc/gcc/config/i386/msformat-c.c
@@ -0,0 +1,188 @@
+/* Check calls to formatted I/O functions (-Wformat).
+   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+   2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "flags.h"
+#include "c-common.h"
+#include "toplev.h"
+#include "intl.h"
+#include "diagnostic.h"
+#include "langhooks.h"
+#include "c-format.h"
+#include "alloc-pool.h"
+
+/* Mingw specific format attributes ms_printf, ms_scanf, and ms_strftime.  */
+
+static const format_length_info ms_printf_length_specs[] =
+{
+  { "h", FMT_LEN_h, STD_C89, NULL, 0, 0 },
+  { "l", FMT_LEN_l, STD_C89, NULL, 0, 0 },
+  { "\0I32", FMT_LEN_l, STD_EXT, NULL, 0, 0 },
+  { "\0I64", FMT_LEN_ll, STD_EXT, NULL, 0, 0 },
+  { "I", FMT_LEN_L, STD_EXT, NULL, 0, 0 },
+  { NULL, 0, 0, NULL, 0, 0 }
+};
+
+static const format_flag_spec ms_printf_flag_specs[] =
+{
+  { ' ',  0, 0, N_("' ' flag"),        N_("the ' ' printf flag"),              STD_C89 },
+  { '+',  0, 0, N_("'+' flag"),        N_("the '+' printf flag"),              STD_C89 },
+  { '#',  0, 0, N_("'#' flag"),        N_("the '#' printf flag"),              STD_C89 },
+  { '0',  0, 0, N_("'0' flag"),        N_("the '0' printf flag"),              STD_C89 },
+  { '-',  0, 0, N_("'-' flag"),        N_("the '-' printf flag"),              STD_C89 },
+  { '\'', 0, 0, N_("''' flag"),        N_("the ''' printf flag"),              STD_EXT },
+  { 'w',  0, 0, N_("field width"),     N_("field width in printf format"),     STD_C89 },
+  { 'p',  0, 0, N_("precision"),       N_("precision in printf format"),       STD_C89 },
+  { 'L',  0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_printf_flag_pairs[] =
+{
+  { ' ', '+', 1, 0   },
+  { '0', '-', 1, 0   }, { '0', 'p', 1, 'i' },
+  { 0, 0, 0, 0 }
+};
+
+static const format_flag_spec ms_scanf_flag_specs[] =
+{
+  { '*',  0, 0, N_("assignment suppression"), N_("the assignment suppression scanf feature"), STD_C89 },
+  { 'a',  0, 0, N_("'a' flag"),               N_("the 'a' scanf flag"),                       STD_EXT },
+  { 'w',  0, 0, N_("field width"),            N_("field width in scanf format"),              STD_C89 },
+  { 'L',  0, 0, N_("length modifier"),        N_("length modifier in scanf format"),          STD_C89 },
+  { '\'', 0, 0, N_("''' flag"),               N_("the ''' scanf flag"),                       STD_EXT },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_scanf_flag_pairs[] =
+{
+  { '*', 'L', 0, 0 },
+  { 0, 0, 0, 0 }
+};
+
+static const format_flag_spec ms_strftime_flag_specs[] =
+{
+  { '_', 0,   0, N_("'_' flag"),     N_("the '_' strftime flag"),          STD_EXT },
+  { '-', 0,   0, N_("'-' flag"),     N_("the '-' strftime flag"),          STD_EXT },
+  { '0', 0,   0, N_("'0' flag"),     N_("the '0' strftime flag"),          STD_EXT },
+  { '^', 0,   0, N_("'^' flag"),     N_("the '^' strftime flag"),          STD_EXT },
+  { '#', 0,   0, N_("'#' flag"),     N_("the '#' strftime flag"),          STD_EXT },
+  { 'w', 0,   0, N_("field width"),  N_("field width in strftime format"), STD_EXT },
+  { 'E', 0,   0, N_("'E' modifier"), N_("the 'E' strftime modifier"),      STD_C99 },
+  { 'O', 0,   0, N_("'O' modifier"), N_("the 'O' strftime modifier"),      STD_C99 },
+  { 'O', 'o', 0, NULL,               N_("the 'O' modifier"),               STD_EXT },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_strftime_flag_pairs[] =
+{
+  { 'E', 'O', 0, 0 },
+  { '_', '-', 0, 0 },
+  { '_', '0', 0, 0 },
+  { '-', '0', 0, 0 },
+  { '^', '#', 0, 0 },
+  { 0, 0, 0, 0 }
+};
+
+static const format_char_info ms_print_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "di",  0, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  T99_SST,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-wp0 +'",  "i",  NULL },
+  { "oxX", 0, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN, BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "-wp0#",     "i",  NULL },
+  { "u",   0, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN, BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "-wp0'",    "i",  NULL },
+  { "fgG", 0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "-wp0 +#'", "",   NULL },
+  { "eE",  0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "-wp0 +#",  "",   NULL },
+  { "c",   0, STD_C89, { T89_I,   BADLEN,  T89_S,  T94_WI,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "",   NULL },
+  { "s",   1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-wp",       "cR", NULL },
+  { "p",   1, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "c",  NULL },
+  { "n",   1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  BADLEN,  BADLEN, BADLEN,  T99_IM,  BADLEN,  BADLEN,  BADLEN }, "",          "W",  NULL },
+  /* X/Open conversion specifiers.  */
+  { "C",   0, STD_EXT, { TEX_WI,  BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "",   NULL },
+  { "S",   1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-wp",       "R",  NULL },
+  { NULL,  0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+static const format_char_info ms_scan_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "di",    1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  T99_SST,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w'", "W",   NULL },
+  { "u",     1, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN,  BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "*w'", "W",   NULL },
+  { "oxX",   1, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN,  BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "efgEG", 1, STD_C89, { T89_F,   BADLEN,  BADLEN,  T89_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "*w'",  "W",   NULL },
+  { "c",     1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "cW",  NULL },
+  { "s",     1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "cW",  NULL },
+  { "[",     1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "cW[", NULL },
+  { "p",     2, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "n",     1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  BADLEN,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "",     "W",   NULL },
+  /* X/Open conversion specifiers.  */
+  { "C",     1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "S",     1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "W",   NULL },
+  { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+static const format_char_info ms_time_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "ABZab",		0, STD_C89, NOLENGTHS, "^#",     "",   NULL },
+  { "cx",		0, STD_C89, NOLENGTHS, "E",      "3",  NULL },
+  { "HIMSUWdmw",	0, STD_C89, NOLENGTHS, "-_0Ow",  "",   NULL },
+  { "j",		0, STD_C89, NOLENGTHS, "-_0Ow",  "o",  NULL },
+  { "p",		0, STD_C89, NOLENGTHS, "#",      "",   NULL },
+  { "X",		0, STD_C89, NOLENGTHS, "E",      "",   NULL },
+  { "y",		0, STD_C89, NOLENGTHS, "EO-_0w", "4",  NULL },
+  { "Y",		0, STD_C89, NOLENGTHS, "-_0EOw", "o",  NULL },
+  { "%",		0, STD_C89, NOLENGTHS, "",       "",   NULL },
+  /* C99 conversion specifiers.  */
+  { "z",		0, STD_C99, NOLENGTHS, "O",      "o",  NULL },
+  { NULL,		0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+const format_kind_info mingw_formatter_attributes[3] =
+{
+  { "ms_printf",   ms_printf_length_specs,  ms_print_char_table, " +#0-'", NULL,
+    ms_printf_flag_specs, ms_printf_flag_pairs,
+    FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
+    'w', 0, 'p', 0, 'L', 0,
+    &integer_type_node, &integer_type_node
+  },
+  { "ms_scanf",    ms_printf_length_specs,   ms_scan_char_table,  "*'", NULL,
+    ms_scanf_flag_specs, ms_scanf_flag_pairs,
+    FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
+    'w', 0, 0, '*', 'L', 0,
+    NULL, NULL
+  },
+  { "ms_strftime", NULL,                 ms_time_char_table,  "_-0^#", "EO",
+    ms_strftime_flag_specs, ms_strftime_flag_pairs,
+    FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0, 0,
+    NULL, NULL
+  }
+};
+
+/* Default overrides for printf, scanf and strftime.  */
+const target_ovr_attr mingw_formatter_attribute_overrides[4] =
+{
+  { "ms_printf", "printf", ovr_printf_format_type },
+  { "ms_scanf", "scanf", ovr_scanf_format_type },
+  { "ms_strftime", "strftime", ovr_strftime_format_type }
+};
Index: gcc/gcc/config/i386/t-cygming
===================================================================
--- gcc.orig/gcc/config/i386/t-cygming
+++ gcc/gcc/config/i386/t-cygming
@@ -29,4 +29,10 @@ winnt-stubs.o: $(srcdir)/config/i386/win
 	$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
 	$(srcdir)/config/i386/winnt-stubs.c
 
+msformat-c.o: $(srcdir)/config/i386/msformat-c.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
+  $(TM_H) $(RTL_H) $(REGS_H) hard-reg-set.h output.h $(TREE_H) flags.h \
+  $(TM_P_H) toplev.h $(HASHTAB_H) $(GGC_H)
+	$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
+	$(srcdir)/config/i386/msformat-c.c
+
 STMP_FIXINC=stmp-fixinc
Index: gcc/gcc/doc/extend.texi
===================================================================
--- gcc.orig/gcc/doc/extend.texi
+++ gcc/gcc/doc/extend.texi
@@ -2204,13 +2204,17 @@ for consistency with the @code{printf} s
 @code{my_format}.
 
 The parameter @var{archetype} determines how the format string is
-interpreted, and should be @code{printf}, @code{scanf}, @code{strftime}
-or @code{strfmon}.  (You can also use @code{__printf__},
-@code{__scanf__}, @code{__strftime__} or @code{__strfmon__}.)  The
-parameter @var{string-index} specifies which argument is the format
-string argument (starting from 1), while @var{first-to-check} is the
-number of the first argument to check against the format string.  For
-functions where the arguments are not available to be checked (such as
+interpreted, and should be @code{printf}, @code{scanf}, @code{strftime},
+@code{gnu_printf}, @code{gnu_scanf}, @code{gnu_strftime} or
+@code{strfmon}.  (You can also use @code{__printf__},
+@code{__scanf__}, @code{__strftime__} or @code{__strfmon__}.)  On
+mingw targets there is also @code{ms_printf}, @code{ms_scanf}, and
+@code{ms_strftime} present. The none target specific formatters are
+always the variant of the system.  The parameter @var{string-index}
+specifies which argument is the format string argument (starting
+from 1), while @var{first-to-check} is the number of the first
+argument to check against the format string.  For functions
+where the arguments are not available to be checked (such as
 @code{vprintf}), specify the third parameter as zero.  In this case the
 compiler only checks the format string for consistency.  For
 @code{strftime} formats, the third parameter is required to be zero.
Index: gcc/gcc/doc/tm.texi
===================================================================
--- gcc.orig/gcc/doc/tm.texi
+++ gcc/gcc/doc/tm.texi
@@ -10319,6 +10319,18 @@ If defined, this macro is the number of 
 @code{TARGET_FORMAT_TYPES}.
 @end defmac
 
+@defmac TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+If defined, this macro is the name of a global variable containg
+target-specific format overrides for the @option{-Wformat} option. The
+default is to have no target-specific format overrides. If defined,
+@code{TARGET_FORMAT_TYPES} must be defined too.
+@end defmac
+
+@defmac TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT
+If defined, this macro specifies the number of entries in
+@code{TARGET_OVERRIDES_FORMAT_ATTRIBUTES}.
+@end defmac
+
 @deftypefn {Target Hook} bool TARGET_RELAXED_ORDERING
 If set to @code{true}, means that the target's memory model does not
 guarantee that loads which do not depend on one another will access
Index: gcc/gcc/testsuite/gcc.dg/format/format.h
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/format.h
+++ gcc/gcc/testsuite/gcc.dg/format/format.h
@@ -1,6 +1,37 @@
 /* Format checking tests: common header.  */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
 
+/* DONT_GNU_PROTOTYPE */
+#if defined (_WIN32) && !defined (__CYGWIN__)
+#if !defined (USE_SYSTEM_FORMATS)
+#define gnu_attr_printf	gnu_printf
+#define gnu_attr___printf__ __gnu_printf__
+#define gnu_attr_scanf	gnu_scanf
+#define gnu_attr___scanf__ __gnu_scanf__
+#define gnu_attr_strftime gnu_strftime
+#define gnu_attr___strftime__ __gnu_strftime__
+#endif
+#endif
+
+#ifndef gnu_attr_printf
+#define gnu_attr_printf	printf
+#define gnu_attr___printf__ __printf__
+#define gnu_attr_scanf	scanf
+#define gnu_attr___scanf__ __scanf__
+#define gnu_attr_strftime strftime
+#define gnu_attr___strftime__ __strftime__
+#endif
+
+#if !defined (USE_SYSTEM_FORMATS)
+#define USE_PRINTF(FMTPOS, WILDARG) __attribute__((format(gnu_printf, FMTPOS, WILDARG))) __attribute__((nonnull (FMTPOS)))
+#define USE_SCANF(FMTPOS, WILDARG) __attribute__((format(gnu_scanf, FMTPOS, WILDARG))) __attribute__((nonnull (FMTPOS)))
+#define USE_STRFTIME(FMTPOS) __attribute__((__format__(gnu_strftime, FMTPOS, 0))) __attribute__((nonnull (FMTPOS)))
+#else
+#define USE_PRINTF(FMTPOS, WILDARG)
+#define USE_SCANF(FMTPOS, WILDARG)
+#define USE_STRFTIME(FMTPOS)
+#endif
+
 #include <stdarg.h>
 #include <stddef.h>
 
@@ -11,6 +42,20 @@
 typedef __WINT_TYPE__ wint_t;
 #endif
 
+#ifdef _WIN64
+/* Kludges to get types corresponding to size_t and ptrdiff_t.  */
+#define unsigned signed
+typedef signed int signed_size_t __attribute__ ((mode (DI)));
+/* We also use this type to approximate ssize_t.  */
+typedef signed int ssize_t __attribute__ ((mode (DI)));
+#undef unsigned
+#define signed /* Type might or might not have explicit 'signed'.  */
+typedef unsigned int unsigned_ptrdiff_t __attribute__ ((mode (DI)));
+#undef signed
+
+__extension__ typedef int llong  __attribute__ ((mode (DI)));
+__extension__ typedef unsigned int ullong  __attribute__ ((mode (DI)));
+#else
 /* Kludges to get types corresponding to size_t and ptrdiff_t.  */
 #define unsigned signed
 typedef __SIZE_TYPE__ signed_size_t;
@@ -23,6 +68,7 @@ typedef unsigned __PTRDIFF_TYPE__ unsign
 
 __extension__ typedef long long int llong;
 __extension__ typedef unsigned long long int ullong;
+#endif
 
 /* %q formats want a "quad"; GCC considers this to be a long long.  */
 typedef llong quad_t;
@@ -70,3 +116,77 @@ extern size_t strftime (char *restrict, 
 			const struct tm *restrict);
 
 extern ssize_t strfmon (char *restrict, size_t, const char *restrict, ...);
+
+/* Mingw specific part.  */
+#if !defined (USE_SYSTEM_FORMATS) && defined(_WIN32) && !defined(DONT_GNU_PROTOTYPE)
+
+extern USE_PRINTF(2,3) int fprintf_gnu (FILE *restrict, const char *restrict, ...);
+#undef fprintf
+#define fprintf fprintf_gnu
+
+extern USE_PRINTF(1,2) int printf_gnu (const char *restrict, ...);
+#undef printf
+#define printf printf_gnu
+
+extern USE_PRINTF(2,3) int fprintf_unlocked_gnu (FILE *restrict, const char *restrict, ...);
+#undef fprintf_unlocked
+#define fprintf_unlocked fprintf_unlocked_gnu
+
+extern USE_PRINTF(1,2)int printf_unlocked_gnu (const char *restrict, ...);
+#undef printf_unlocked
+#define printf_unlocked printf_unlocked_gnu
+
+extern USE_PRINTF(2,3) int sprintf_gnu (char *restrict, const char *restrict, ...);
+#undef sprintf
+#define sprintf sprintf_gnu
+
+extern USE_PRINTF(2,0) int vfprintf_gnu (FILE *restrict, const char *restrict, va_list);
+#undef vsprintf
+#define vsprintf vsprintf_gnu
+
+extern USE_PRINTF(1,0) int vprintf_gnu (const char *restrict, va_list);
+#undef vprintf
+#define vprintf vprintf_gnu
+
+extern USE_PRINTF(2,0) int vsprintf_gnu (char *restrict, const char *restrict, va_list);
+#undef vsprintf
+#define vsprintf vsprintf_gnu
+
+extern USE_PRINTF(3,4) int snprintf_gnu (char *restrict, size_t, const char *restrict, ...);
+#undef snprintf
+#define snprintf snprintf_gnu
+
+extern USE_PRINTF(3,0) int vsnprintf_gnu (char *restrict, size_t, const char *restrict, va_list);
+#undef vsnprintf
+#define vsnprintf vsnprintf_gnu
+
+extern USE_SCANF(2,3) int fscanf_gnu (FILE *restrict, const char *restrict, ...);
+#undef fscanf
+#define fscanf fscanf_gnu
+
+extern USE_SCANF(1,2) int scanf_gnu (const char *restrict, ...);
+#undef scanf
+#define scanf scanf_gnu
+
+extern USE_SCANF(2,3) int sscanf_gnu (const char *restrict, const char *restrict, ...);
+#undef sscanf
+#define sscanf sscanf_gnu
+
+extern USE_SCANF(2,0) int vfscanf_gnu (FILE *restrict, const char *restrict, va_list);
+#undef vfscanf
+#define vfscanf vfscanf_gnu
+
+extern USE_SCANF(1,0) int vscanf_gnu (const char *restrict, va_list);
+#undef vscanf
+#define vscanf vscanf_gnu
+
+extern USE_SCANF(2,0) int vsscanf_gnu (const char *restrict, const char *restrict, va_list);
+#undef vsscanf
+#define vsscanf vsscanf_gnu
+
+extern USE_STRFTIME(3) size_t strftime_gnu (char *restrict, size_t, const char *restrict,
+			const struct tm *restrict);
+#undef strftime
+#define strftime strftime_gnu
+
+#endif
Index: gcc/gcc/testsuite/gcc.dg/format/attr-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-1.c
@@ -3,7 +3,8 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern void foo0 (const char *) __attribute__((__format__(__strftime__, 1, 0)));
-extern void foo1 (const char *, ...) __attribute__((__format__(__strftime__, 1, 2))); /* { dg-error "cannot format" "strftime first_arg_num != 0" } */
+extern void foo0 (const char *) __attribute__((__format__(gnu_attr___strftime__, 1, 0)));
+extern void foo1 (const char *, ...) __attribute__((__format__(gnu_attr___strftime__, 1, 2))); /* { dg-error "cannot format" "strftime first_arg_num != 0" } */
Index: gcc/gcc/testsuite/gcc.dg/format/attr-2.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-2.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-2.c
@@ -3,22 +3,23 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern void tformatprintf (const char *, ...) __attribute__((format(printf, 1, 2)));
-extern void tformat__printf__ (const char *, ...) __attribute__((format(__printf__, 1, 2)));
-extern void tformatscanf (const char *, ...) __attribute__((format(scanf, 1, 2)));
-extern void tformat__scanf__ (const char *, ...) __attribute__((format(__scanf__, 1, 2)));
-extern void tformatstrftime (const char *) __attribute__((format(strftime, 1, 0)));
-extern void tformat__strftime__ (const char *) __attribute__((format(__strftime__, 1, 0)));
+extern void tformatprintf (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
+extern void tformat__printf__ (const char *, ...) __attribute__((format(gnu_attr___printf__, 1, 2)));
+extern void tformatscanf (const char *, ...) __attribute__((format(gnu_attr_scanf, 1, 2)));
+extern void tformat__scanf__ (const char *, ...) __attribute__((format(gnu_attr___scanf__, 1, 2)));
+extern void tformatstrftime (const char *) __attribute__((format(gnu_attr_strftime, 1, 0)));
+extern void tformat__strftime__ (const char *) __attribute__((format(gnu_attr___strftime__, 1, 0)));
 extern void tformatstrfmon (const char *, ...) __attribute__((format(strfmon, 1, 2)));
 extern void tformat__strfmon__ (const char *, ...) __attribute__((format(__strfmon__, 1, 2)));
-extern void t__format__printf (const char *, ...) __attribute__((__format__(printf, 1, 2)));
-extern void t__format____printf__ (const char *, ...) __attribute__((__format__(__printf__, 1, 2)));
-extern void t__format__scanf (const char *, ...) __attribute__((__format__(scanf, 1, 2)));
-extern void t__format____scanf__ (const char *, ...) __attribute__((__format__(__scanf__, 1, 2)));
-extern void t__format__strftime (const char *) __attribute__((__format__(strftime, 1, 0)));
-extern void t__format____strftime__ (const char *) __attribute__((__format__(__strftime__, 1, 0)));
+extern void t__format__printf (const char *, ...) __attribute__((__format__(gnu_attr_printf, 1, 2)));
+extern void t__format____printf__ (const char *, ...) __attribute__((__format__(gnu_attr___printf__, 1, 2)));
+extern void t__format__scanf (const char *, ...) __attribute__((__format__(gnu_attr_scanf, 1, 2)));
+extern void t__format____scanf__ (const char *, ...) __attribute__((__format__(gnu_attr___scanf__, 1, 2)));
+extern void t__format__strftime (const char *) __attribute__((__format__(gnu_attr_strftime, 1, 0)));
+extern void t__format____strftime__ (const char *) __attribute__((__format__(gnu_attr___strftime__, 1, 0)));
 extern void t__format__strfmon (const char *, ...) __attribute__((__format__(strfmon, 1, 2)));
 extern void t__format____strfmon__ (const char *, ...) __attribute__((__format__(__strfmon__, 1, 2)));
 
Index: gcc/gcc/testsuite/gcc.dg/format/attr-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-3.c
@@ -3,20 +3,21 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 /* Proper uses of the attributes.  */
-extern void fa0 (const char *, ...) __attribute__((format(printf, 1, 2)));
-extern void fa1 (char *, ...) __attribute__((format(printf, 1, 2)));
+extern void fa0 (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
+extern void fa1 (char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
 extern char *fa2 (const char *) __attribute__((format_arg(1)));
 extern char *fa3 (char *) __attribute__((format_arg(1)));
 
 /* Uses with too few or too many arguments.  */
 extern void fb0 (const char *, ...) __attribute__((format)); /* { dg-error "wrong number of arguments" "bad format" } */
 extern void fb1 (const char *, ...) __attribute__((format())); /* { dg-error "wrong number of arguments" "bad format" } */
-extern void fb2 (const char *, ...) __attribute__((format(printf))); /* { dg-error "wrong number of arguments" "bad format" } */
-extern void fb3 (const char *, ...) __attribute__((format(printf, 1))); /* { dg-error "wrong number of arguments" "bad format" } */
-extern void fb4 (const char *, ...) __attribute__((format(printf, 1, 2, 3))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb2 (const char *, ...) __attribute__((format(gnu_attr_printf))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb3 (const char *, ...) __attribute__((format(gnu_attr_printf, 1))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb4 (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2, 3))); /* { dg-error "wrong number of arguments" "bad format" } */
 
 extern void fc1 (const char *) __attribute__((format_arg)); /* { dg-error "wrong number of arguments" "bad format_arg" } */
 extern void fc2 (const char *) __attribute__((format_arg())); /* { dg-error "wrong number of arguments" "bad format_arg" } */
@@ -25,9 +26,9 @@ extern void fc3 (const char *) __attribu
 /* These attributes presently only apply to declarations, not to types.
    Eventually, they should be usable with declarators for function types
    anywhere, but still not with structure/union/enum types.  */
-struct s0 { int i; } __attribute__((format(printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on struct" } */
-union u0 { int i; } __attribute__((format(printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on union" } */
-enum e0 { E0V0 } __attribute__((format(printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on enum" } */
+struct s0 { int i; } __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on struct" } */
+union u0 { int i; } __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on union" } */
+enum e0 { E0V0 } __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on enum" } */
 
 struct s1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on struct" } */
 union u1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on union" } */
@@ -38,28 +39,28 @@ extern void fe0 (const char *, ...) __at
 extern void fe1 (const char *, ...) __attribute__((format(nosuch, 1, 2))); /* { dg-warning "format function type" "unknown format" } */
 
 /* Both the numbers must be integer constant expressions.  */
-extern void ff0 (const char *, ...) __attribute__((format(printf, 3-2, (long long)(10/5))));
+extern void ff0 (const char *, ...) __attribute__((format(gnu_attr_printf, 3-2, (long long)(10/5))));
 int foo;
-extern void ff1 (const char *, ...) __attribute__((format(printf, foo, 10/5))); /* { dg-error "invalid operand" "bad number" } */
-extern void ff2 (const char *, ...) __attribute__((format(printf, 3-2, foo))); /* { dg-error "invalid operand" "bad number" } */
+extern void ff1 (const char *, ...) __attribute__((format(gnu_attr_printf, foo, 10/5))); /* { dg-error "invalid operand" "bad number" } */
+extern void ff2 (const char *, ...) __attribute__((format(gnu_attr_printf, 3-2, foo))); /* { dg-error "invalid operand" "bad number" } */
 extern char *ff3 (const char *) __attribute__((format_arg(3-2)));
 extern char *ff4 (const char *) __attribute__((format_arg(foo))); /* { dg-error "invalid operand" "bad format_arg number" } */
 
 /* The format string argument must precede the arguments to be formatted.
    This includes if no parameter types are specified (which is not valid ISO
    C for variadic functions).  */
-extern void fg0 () __attribute__((format(printf, 1, 2)));
-extern void fg1 () __attribute__((format(printf, 1, 0)));
-extern void fg2 () __attribute__((format(printf, 1, 1))); /* { dg-error "follows" "bad number order" } */
-extern void fg3 () __attribute__((format(printf, 2, 1))); /* { dg-error "follows" "bad number order" } */
+extern void fg0 () __attribute__((format(gnu_attr_printf, 1, 2)));
+extern void fg1 () __attribute__((format(gnu_attr_printf, 1, 0)));
+extern void fg2 () __attribute__((format(gnu_attr_printf, 1, 1))); /* { dg-error "follows" "bad number order" } */
+extern void fg3 () __attribute__((format(gnu_attr_printf, 2, 1))); /* { dg-error "follows" "bad number order" } */
 
 /* The format string argument must be a string type, and the arguments to
    be formatted must be the "...".  */
-extern void fh0 (int, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "not a string" "format int string" } */
-extern void fh1 (signed char *, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "not a string" "signed char string" } */
-extern void fh2 (unsigned char *, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "not a string" "unsigned char string" } */
-extern void fh3 (const char *, ...) __attribute__((format(printf, 1, 3))); /* { dg-error "is not" "not ..." } */
-extern void fh4 (const char *, int, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "is not" "not ..." } */
+extern void fh0 (int, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "format int string" } */
+extern void fh1 (signed char *, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "signed char string" } */
+extern void fh2 (unsigned char *, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "unsigned char string" } */
+extern void fh3 (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 3))); /* { dg-error "is not" "not ..." } */
+extern void fh4 (const char *, int, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "is not" "not ..." } */
 
 /* format_arg formats must take and return a string.  */
 extern char *fi0 (int) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg int string" } */
Index: gcc/gcc/testsuite/gcc.dg/format/attr-4.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-4.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-4.c
@@ -4,12 +4,13 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern __attribute__((format(printf, 1, 2))) void tformatprintf0 (const char *, ...);
-extern void __attribute__((format(printf, 1, 2))) tformatprintf1 (const char *, ...);
-extern void foo (void), __attribute__((format(printf, 1, 2))) tformatprintf2 (const char *, ...);
-extern __attribute__((noreturn)) void bar (void), __attribute__((format(printf, 1, 2))) tformatprintf3 (const char *, ...);
+extern __attribute__((format(gnu_attr_printf, 1, 2))) void tformatprintf0 (const char *, ...);
+extern void __attribute__((format(gnu_attr_printf, 1, 2))) tformatprintf1 (const char *, ...);
+extern void foo (void), __attribute__((format(gnu_attr_printf, 1, 2))) tformatprintf2 (const char *, ...);
+extern __attribute__((noreturn)) void bar (void), __attribute__((format(gnu_attr_printf, 1, 2))) tformatprintf3 (const char *, ...);
 
 void
 baz (int i, int *ip, double d)
Index: gcc/gcc/testsuite/gcc.dg/format/attr-7.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-7.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-7.c
@@ -3,12 +3,13 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-__attribute__((format(printf, 1, 2))) void (*tformatprintf0) (const char *, ...);
-void (*tformatprintf1) (const char *, ...) __attribute__((format(printf, 1, 2)));
-void (__attribute__((format(printf, 1, 2))) *tformatprintf2) (const char *, ...);
-void (__attribute__((format(printf, 1, 2))) ****tformatprintf3) (const char *, ...);
+__attribute__((format(gnu_attr_printf, 1, 2))) void (*tformatprintf0) (const char *, ...);
+void (*tformatprintf1) (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
+void (__attribute__((format(gnu_attr_printf, 1, 2))) *tformatprintf2) (const char *, ...);
+void (__attribute__((format(gnu_attr_printf, 1, 2))) ****tformatprintf3) (const char *, ...);
 
 char * (__attribute__((format_arg(1))) *tformat_arg) (const char *);
 
Index: gcc/gcc/testsuite/gcc.dg/format/c90-printf-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/c90-printf-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/c90-printf-3.c
@@ -3,7 +3,7 @@
    do not.
 */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
-/* { dg-do compile } */
+/* { dg-do compile { target { ! *-*-mingw* } } } */
 /* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
 
 #include "format.h"
Index: gcc/gcc/testsuite/gcc.dg/format/c90-scanf-4.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/c90-scanf-4.c
+++ gcc/gcc/testsuite/gcc.dg/format/c90-scanf-4.c
@@ -3,7 +3,7 @@
    do not.
 */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
-/* { dg-do compile } */
+/* { dg-do compile { target { ! *-*-mingw* } } } */
 /* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
 
 #include "format.h"
Index: gcc/gcc/testsuite/gcc.dg/format/c99-printf-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/c99-printf-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/c99-printf-3.c
@@ -2,7 +2,7 @@
    attributes in strict C99 mode, but the gettext functions do not.
 */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
-/* { dg-do compile } */
+/* { dg-do compile { target { ! *-*-mingw* } } } */
 /* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
 
 #include "format.h"
Index: gcc/gcc/testsuite/gcc.dg/format/miss-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-1.c
@@ -23,7 +23,7 @@ bar (const char *fmt, ...)
   va_end (ap);
 }
 
-__attribute__((__format__(__printf__, 1, 2))) void
+__attribute__((__format__(gnu_attr___printf__, 1, 2))) void
 foo2 (const char *fmt, ...)
 {
   va_list ap;
Index: gcc/gcc/testsuite/gcc.dg/format/miss-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-3.c
@@ -3,13 +3,14 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 void
 foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
@@ -18,7 +19,7 @@ foo1 (noattr_t na, attr_t a, vnoattr_t v
   noattr_t na2 = a; /* { dg-warning "candidate" "initialization warning" } */
   attr_t a1 = na;
   attr_t a2 = a;
-  
+
   vnoattr_t vna1 = vna;
   vnoattr_t vna2 = va; /* { dg-warning "candidate" "initialization warning" } */
   vattr_t va1 = vna;
Index: gcc/gcc/testsuite/gcc.dg/format/miss-4.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-4.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-4.c
@@ -3,20 +3,21 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 void
 foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
 {
   noattr_t na1, na2;
   attr_t a1, a2;
-  
+
   vnoattr_t vna1, vna2;
   vattr_t va1, va2;
 
@@ -24,7 +25,7 @@ foo1 (noattr_t na, attr_t a, vnoattr_t v
   na2 = a; /* { dg-warning "candidate" "assignment warning" } */
   a1 = na;
   a2 = a;
-  
+
   vna1 = vna;
   vna2 = va; /* { dg-warning "candidate" "assignment warning" } */
   va1 = vna;
Index: gcc/gcc/testsuite/gcc.dg/format/miss-5.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-5.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-5.c
@@ -3,13 +3,14 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 noattr_t
 foo1 (noattr_t na, attr_t a, int i)
Index: gcc/gcc/testsuite/gcc.dg/format/miss-6.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-6.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-6.c
@@ -3,13 +3,14 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 extern void foo1 (noattr_t);
 extern void foo2 (attr_t);
@@ -23,7 +24,7 @@ foo (noattr_t na, attr_t a, vnoattr_t vn
   foo1 (a); /* { dg-warning "candidate" "parameter passing warning" } */
   foo2 (na);
   foo2 (a);
-  
+
   foo3 (vna);
   foo3 (va); /* { dg-warning "candidate" "parameter passing warning" } */
   foo4 (vna);
Index: gcc/gcc/testsuite/gcc.dg/format/ms_array-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_array-1.c
@@ -0,0 +1,42 @@
+/* Test for format checking of constant arrays.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat=2" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+const char a1[] = "foo";
+const char a2[] = "foo%d";
+const char b1[3] = "foo";
+const char b2[1] = "1";
+static const char c1[] = "foo";
+static const char c2[] = "foo%d";
+char d[] = "foo";
+volatile const char e[] = "foo";
+
+void
+foo (int i, long l)
+{
+  const char p1[] = "bar";
+  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 (c1);
+  printf (c2, i);
+  printf (c2, l); /* { dg-warning "format" "wrong type with array" } */
+  printf (p1);
+  printf (p2, i);
+  printf (p2, l); /* { dg-warning "format" "wrong type with array" } */
+  printf (q1);
+  printf (q2, i);
+  printf (q2, l); /* { dg-warning "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" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-1.c
@@ -0,0 +1,10 @@
+/* Test for strftime format attributes: can't have first_arg_num != 0.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define DONT_GNU_PROTOTYPE
+#include "format.h"
+
+extern void foo0 (const char *) __attribute__((__format__(__ms_strftime__, 1, 0)));
+extern void foo1 (const char *, ...) __attribute__((__format__(__ms_strftime__, 1, 2))); /* { dg-error "cannot format" "strftime first_arg_num != 0" } */
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-2.c
@@ -0,0 +1,68 @@
+/* Test for format attributes: test use of __attribute__.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define DONT_GNU_PROTOTYPE
+#include "format.h"
+
+extern void tformatprintf (const char *, ...) __attribute__((format(ms_printf, 1, 2)));
+extern void tformat__printf__ (const char *, ...) __attribute__((format(__ms_printf__, 1, 2)));
+extern void tformatscanf (const char *, ...) __attribute__((format(ms_scanf, 1, 2)));
+extern void tformat__scanf__ (const char *, ...) __attribute__((format(__ms_scanf__, 1, 2)));
+extern void tformatstrftime (const char *) __attribute__((format(ms_strftime, 1, 0)));
+extern void tformat__strftime__ (const char *) __attribute__((format(__ms_strftime__, 1, 0)));
+extern void tformatstrfmon (const char *, ...) __attribute__((format(strfmon, 1, 2)));
+extern void tformat__strfmon__ (const char *, ...) __attribute__((format(__strfmon__, 1, 2)));
+extern void t__format__printf (const char *, ...) __attribute__((__format__(ms_printf, 1, 2)));
+extern void t__format____printf__ (const char *, ...) __attribute__((__format__(__ms_printf__, 1, 2)));
+extern void t__format__scanf (const char *, ...) __attribute__((__format__(ms_scanf, 1, 2)));
+extern void t__format____scanf__ (const char *, ...) __attribute__((__format__(__ms_scanf__, 1, 2)));
+extern void t__format__strftime (const char *) __attribute__((__format__(ms_strftime, 1, 0)));
+extern void t__format____strftime__ (const char *) __attribute__((__format__(__ms_strftime__, 1, 0)));
+extern void t__format__strfmon (const char *, ...) __attribute__((__format__(strfmon, 1, 2)));
+extern void t__format____strfmon__ (const char *, ...) __attribute__((__format__(__strfmon__, 1, 2)));
+
+extern char *tformat_arg (const char *) __attribute__((format_arg(1)));
+extern char *t__format_arg__ (const char *) __attribute__((__format_arg__(1)));
+
+void
+foo (int i, int *ip, double d)
+{
+  tformatprintf ("%d", i);
+  tformatprintf ("%"); /* { dg-warning "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);
+  tformat__scanf__ ("%"); /* { dg-warning "format" "attribute format __scanf__" } */
+  tformatstrftime ("%a");
+  tformatstrftime ("%"); /* { dg-warning "format" "attribute format strftime" } */
+  tformat__strftime__ ("%a");
+  tformat__strftime__ ("%"); /* { dg-warning "format" "attribute format __strftime__" } */
+  tformatstrfmon ("%n", d);
+  tformatstrfmon ("%"); /* { dg-warning "format" "attribute format strfmon" } */
+  tformat__strfmon__ ("%n", d);
+  tformat__strfmon__ ("%"); /* { dg-warning "format" "attribute format __strfmon__" } */
+  t__format__printf ("%d", i);
+  t__format__printf ("%"); /* { dg-warning "format" "attribute __format__ printf" } */
+  t__format____printf__ ("%d", i);
+  t__format____printf__ ("%"); /* { dg-warning "format" "attribute __format__ __printf__" } */
+  t__format__scanf ("%d", ip);
+  t__format__scanf ("%"); /* { dg-warning "format" "attribute __format__ scanf" } */
+  t__format____scanf__ ("%d", ip);
+  t__format____scanf__ ("%"); /* { dg-warning "format" "attribute __format__ __scanf__" } */
+  t__format__strftime ("%a");
+  t__format__strftime ("%"); /* { dg-warning "format" "attribute __format__ strftime" } */
+  t__format____strftime__ ("%a");
+  t__format____strftime__ ("%"); /* { dg-warning "format" "attribute __format__ __strftime__" } */
+  t__format__strfmon ("%n", d);
+  t__format__strfmon ("%"); /* { dg-warning "format" "attribute __format__ strfmon" } */
+  t__format____strfmon__ ("%n", d);
+  t__format____strfmon__ ("%"); /* { dg-warning "format" "attribute __format__ __strfmon__" } */
+  tformatprintf (tformat_arg ("%d"), i);
+  tformatprintf (tformat_arg ("%")); /* { dg-warning "format" "attribute format_arg" } */
+  tformatprintf (t__format_arg__ ("%d"), i);
+  tformatprintf (t__format_arg__ ("%")); /* { dg-warning "format" "attribute __format_arg__" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-3.c
@@ -0,0 +1,71 @@
+/* Test for format attributes: test bad uses of __attribute__.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* Proper uses of the attributes.  */
+extern void fa0 (const char *, ...) __attribute__((format(ms_printf, 1, 2)));
+extern void fa1 (char *, ...) __attribute__((format(ms_printf, 1, 2)));
+extern char *fa2 (const char *) __attribute__((format_arg(1)));
+extern char *fa3 (char *) __attribute__((format_arg(1)));
+
+/* Uses with too few or too many arguments.  */
+extern void fb0 (const char *, ...) __attribute__((format)); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb1 (const char *, ...) __attribute__((format())); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb2 (const char *, ...) __attribute__((format(ms_printf))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb3 (const char *, ...) __attribute__((format(ms_printf, 1))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb4 (const char *, ...) __attribute__((format(ms_printf, 1, 2, 3))); /* { dg-error "wrong number of arguments" "bad format" } */
+
+extern void fc1 (const char *) __attribute__((format_arg)); /* { dg-error "wrong number of arguments" "bad format_arg" } */
+extern void fc2 (const char *) __attribute__((format_arg())); /* { dg-error "wrong number of arguments" "bad format_arg" } */
+extern void fc3 (const char *) __attribute__((format_arg(1, 2))); /* { dg-error "wrong number of arguments" "bad format_arg" } */
+
+/* These attributes presently only apply to declarations, not to types.
+   Eventually, they should be usable with declarators for function types
+   anywhere, but still not with structure/union/enum types.  */
+struct s0 { int i; } __attribute__((format(ms_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on struct" } */
+union u0 { int i; } __attribute__((format(ms_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on union" } */
+enum e0 { E0V0 } __attribute__((format(ms_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on enum" } */
+
+struct s1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on struct" } */
+union u1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on union" } */
+enum e1 { E1V0 } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on enum" } */
+
+/* The format type must be an identifier, one of those recognized.  */
+extern void fe0 (const char *, ...) __attribute__((format(12345, 1, 2))); /* { dg-error "format specifier" "non-id format" } */
+extern void fe1 (const char *, ...) __attribute__((format(nosuch, 1, 2))); /* { dg-warning "format function type" "unknown format" } */
+
+/* Both the numbers must be integer constant expressions.  */
+extern void ff0 (const char *, ...) __attribute__((format(ms_printf, 3-2, (long long)(10/5))));
+int foo;
+extern void ff1 (const char *, ...) __attribute__((format(ms_printf, foo, 10/5))); /* { dg-error "invalid operand" "bad number" } */
+extern void ff2 (const char *, ...) __attribute__((format(ms_printf, 3-2, foo))); /* { dg-error "invalid operand" "bad number" } */
+extern char *ff3 (const char *) __attribute__((format_arg(3-2)));
+extern char *ff4 (const char *) __attribute__((format_arg(foo))); /* { dg-error "invalid operand" "bad format_arg number" } */
+
+/* The format string argument must precede the arguments to be formatted.
+   This includes if no parameter types are specified (which is not valid ISO
+   C for variadic functions).  */
+extern void fg0 () __attribute__((format(ms_printf, 1, 2)));
+extern void fg1 () __attribute__((format(ms_printf, 1, 0)));
+extern void fg2 () __attribute__((format(ms_printf, 1, 1))); /* { dg-error "follows" "bad number order" } */
+extern void fg3 () __attribute__((format(ms_printf, 2, 1))); /* { dg-error "follows" "bad number order" } */
+
+/* The format string argument must be a string type, and the arguments to
+   be formatted must be the "...".  */
+extern void fh0 (int, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "not a string" "format int string" } */
+extern void fh1 (signed char *, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "not a string" "signed char string" } */
+extern void fh2 (unsigned char *, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "not a string" "unsigned char string" } */
+extern void fh3 (const char *, ...) __attribute__((format(ms_printf, 1, 3))); /* { dg-error "is not" "not ..." } */
+extern void fh4 (const char *, int, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "is not" "not ..." } */
+
+/* format_arg formats must take and return a string.  */
+extern char *fi0 (int) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg int string" } */
+extern char *fi1 (signed char *) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg signed char string" } */
+extern char *fi2 (unsigned char *) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg unsigned char string" } */
+extern int fi3 (const char *) __attribute__((format_arg(1))); /* { dg-error "not return string" "format_arg ret int string" } */
+extern signed char *fi4 (const char *) __attribute__((format_arg(1))); /* { dg-error "not return string" "format_arg ret signed char string" } */
+extern unsigned char *fi5 (const char *) __attribute__((format_arg(1))); /* { dg-error "not return string" "format_arg ret unsigned char string" } */
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-4.c
@@ -0,0 +1,26 @@
+/* Test for format attributes: test use of __attribute__
+   in prefix attributes.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+extern __attribute__((format(ms_printf, 1, 2))) void tformatprintf0 (const char *, ...);
+extern void __attribute__((format(ms_printf, 1, 2))) tformatprintf1 (const char *, ...);
+extern void foo (void), __attribute__((format(ms_printf, 1, 2))) tformatprintf2 (const char *, ...);
+extern __attribute__((noreturn)) void bar (void), __attribute__((format(ms_printf, 1, 2))) tformatprintf3 (const char *, ...);
+
+void
+baz (int i, int *ip, double d)
+{
+  tformatprintf0 ("%d", i);
+  tformatprintf0 ("%"); /* { dg-warning "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);
+  tformatprintf3 ("%"); /* { dg-warning "format" "attribute format printf case 3" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-7.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-7.c
@@ -0,0 +1,35 @@
+/* Test for format attributes: test applying them to types.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define DONT_GNU_PROTOTYPE
+#include "format.h"
+
+__attribute__((format(ms_printf, 1, 2))) void (*tformatprintf0) (const char *, ...);
+void (*tformatprintf1) (const char *, ...) __attribute__((format(ms_printf, 1, 2)));
+void (__attribute__((format(ms_printf, 1, 2))) *tformatprintf2) (const char *, ...);
+void (__attribute__((format(ms_printf, 1, 2))) ****tformatprintf3) (const char *, ...);
+
+char * (__attribute__((format_arg(1))) *tformat_arg) (const char *);
+
+void
+baz (int i)
+{
+  (*tformatprintf0) ("%d", i);
+  (*tformatprintf0) ((*tformat_arg) ("%d"), i);
+  (*tformatprintf0) ("%"); /* { dg-warning "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" } */
+  (*tformatprintf2) ("%d", i);
+  (*tformatprintf2) ((*tformat_arg) ("%d"), i);
+  (*tformatprintf2) ("%"); /* { dg-warning "format" "nested" } */
+  (*tformatprintf2) ((*tformat_arg) ("%")); /* { dg-warning "format" "nested" } */
+  (****tformatprintf3) ("%d", i);
+  (****tformatprintf3) ((*tformat_arg) ("%d"), i);
+  (****tformatprintf3) ("%"); /* { dg-warning "format" "nested 2" } */
+  (****tformatprintf3) ((*tformat_arg) ("%")); /* { dg-warning "format" "nested 2" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_bitfld-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_bitfld-1.c
@@ -0,0 +1,52 @@
+/* Test for printf formats and bit-fields: bug 22421.  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+/* { dg-require-effective-target int32plus } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+struct s {
+  unsigned int u1 : 1;
+  signed int s1 : 1;
+  unsigned int u15 : 15;
+  signed int s15 : 15;
+  unsigned int u16 : 16;
+  signed int s16 : 16;
+  unsigned long u31 : 31;
+  signed long s31 : 31;
+  unsigned long u32 : 32;
+  signed long s32 : 32;
+  unsigned long long u48 : 48;
+} x;
+
+void
+foo (void)
+{
+  printf ("%d%u", x.u1, x.u1);
+  printf ("%d%u", x.s1, x.s1);
+  printf ("%d%u", x.u15, x.u15);
+  printf ("%d%u", x.s15, x.s15);
+  printf ("%d%u", x.u16, x.u16);
+  printf ("%d%u", x.s16, x.s16);
+#if __INT_MAX__ > 32767
+  /* If integers are 16 bits, there doesn't seem to be a way of
+     printing these without getting an error.  */
+  printf ("%d%u", x.u31, x.u31);
+  printf ("%d%u", x.s31, x.s31);
+#endif
+#if __LONG_MAX__ > 2147483647 && __INT_MAX__ >= 2147483647
+  /* If long is wider than 32 bits, the 32-bit bit-fields are int or
+     unsigned int or promote to those types.  Otherwise, long is 32
+     bits and the bit-fields are of type plain long or unsigned
+     long.  */
+  printf ("%d%u", x.u32, x.u32);
+  printf ("%d%u", x.s32, x.s32);
+#else
+  printf ("%ld%lu", x.u32, x.u32);
+  printf ("%ld%lu", x.s32, x.s32);
+#endif
+  printf ("%I64u", x.u48); /* { dg-warning "has type '.*unsigned int:48'" } */
+  printf ("%I64u", (unsigned long long)x.u48);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_branch-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_branch-1.c
@@ -0,0 +1,28 @@
+/* Test for format checking of conditional expressions.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+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" } */
+  /* 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) ? "%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" } */
+  /* 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 *-*-* } 26 } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-1.c
@@ -0,0 +1,184 @@
+/* Test for printf formats.  Formats using C90 features, including cases
+   where C90 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, int i1, int i2, unsigned int u, double d, char *s, void *p,
+     int *n, short int *hn, long int l, unsigned long int ul,
+     long int *ln, long double ld, wint_t lc, wchar_t *ls, llong ll,
+     ullong ull, unsigned int *un, const int *cn, signed char *ss,
+     unsigned char *us, const signed char *css, unsigned int u1,
+     unsigned int u2)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.1 (pages 131-134).  */
+  /* Basic sanity checks for the different components of a format.  */
+  printf ("%d\n", i);
+  printf ("%+d\n", i);
+  printf ("%3d\n", i);
+  printf ("%-3d\n", i);
+  printf ("%*d\n", i1, i);
+  printf ("%d %lu\n", i, ul);
+  /* Bogus use of width.  */
+  printf ("%5n\n", n); /* { dg-warning "width" "width 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 ("%-%"); /* { dg-warning "format" "bogus %%" } */
+  printf ("%-%\n"); /* { dg-warning "format" "bogus %%" } */
+  printf ("%5%\n"); /* { dg-warning "format" "bogus %%" } */
+  printf ("%h%\n"); /* { dg-warning "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
+     differences in format checking here, and this is relied on to get the
+     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);
+  printf ("%hs", hn);
+  printf ("%hp", p); /* { dg-warning "length" "bad use of %h" } */
+  printf ("%h"); /* { dg-warning "conversion lacks type" "bare %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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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% 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* Various tests of bad argument types.  */
+  printf ("%d", l); /* { dg-warning "format" "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" } */
+  /* 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
+     discussion of the requirements of rules on identical representation,
+     and of the application of the as if rule with the new va_arg
+     allowances in C99 to printf.)  Likewise, we should warn if
+     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" } */
+  /* 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" } */
+  /* The historical behavior is to allow signed / unsigned types
+     interchangably as arguments.  For values representable in both types,
+     such usage may be correct.  For now preserve the behavior of GCC
+     in such cases.
+  */
+  printf ("%d", u);
+  /* Wrong number of arguments.  */
+  printf ("%d%d", i); /* { dg-warning "arguments" "wrong number of args" } */
+  printf ("%d", i, i); /* { dg-warning "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" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-2.c
@@ -0,0 +1,25 @@
+/* Test for printf formats.  Formats using C99 features should be rejected
+   outside of C99 mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, double d, llong ll, intmax_t j, size_t z, ptrdiff_t t)
+{
+  /* Some tests already in c90-printf-1.c, e.g. %lf.  */
+  /* The widths hh, ll, j, z, t are new.  */
+  printf ("%hhd", i); /* { dg-warning "unknown|format" "%hh is unsupported" } */
+  printf ("%I64d", ll); /* { dg-warning "length|C" "%I64 in C90" } */
+  printf ("%jd", j); /* { dg-warning "unknown|format" "%j is unsupported" } */
+  printf ("%zu", z); /* { dg-warning "unknown|format" "%z is unsupported" } */
+  printf ("%td", t); /* { dg-warning "unknown|format" "%t is unsupported" } */
+  /* The formats F, a, A are new.  */
+  printf ("%F", d); /* { dg-warning "unknown|format" "%F is unsupported" } */
+  printf ("%a", d); /* { dg-warning "unknown|format" "%a is unsupported" } */
+  printf ("%A", d); /* { dg-warning "unknown|format" "%A is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-3.c
@@ -0,0 +1,43 @@
+/* Test for printf formats.  Test that the C90 functions get their default
+   attributes in strict C90 mode, but the C99 and gettext functions
+   do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, char *s, size_t n, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5, va_list v6, va_list v7, va_list v8)
+{
+  fprintf (stdout, "%d", i);
+  fprintf (stdout, "%ld", i); /* { dg-warning "format" "fprintf" } */
+  printf ("%d", i);
+  printf ("%ld", i); /* { dg-warning "format" "printf" } */
+  /* The "unlocked" functions shouldn't warn in c90 mode.  */
+  fprintf_unlocked (stdout, "%ld", i);
+  printf_unlocked ("%ld", i);
+  sprintf (s, "%d", i);
+  sprintf (s, "%ld", i); /* { dg-warning "format" "sprintf" } */
+  vfprintf (stdout, "%d", v0);
+  vfprintf (stdout, "%Y", v1); /* { dg-warning "format" "vfprintf" } */
+  vprintf ("%d", v2);
+  vprintf ("%Y", v3); /* { dg-warning "format" "vprintf" } */
+  /* The following used to give a bogus warning.  */
+  vprintf ("%*.*d", v8); /* { dg-warning "format" "dot is invalid" } */
+  vsprintf (s, "%d", v4);
+  vsprintf (s, "%Y", v5); /* { dg-warning "format" "Y is invalid" } */
+  snprintf (s, n, "%d", i);
+  snprintf (s, n, "%ld", i);
+  vsnprintf (s, n, "%d", v6);
+  vsnprintf (s, n, "%Y", v7);
+  printf (gettext ("%d"), i);
+  printf (gettext ("%ld"), i);
+  printf (dgettext ("", "%d"), i);
+  printf (dgettext ("", "%ld"), (long) i);
+  printf (dcgettext ("", "%d", 0), i);
+  printf (dcgettext ("", "%ld", 0), (long) i);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-1.c
@@ -0,0 +1,119 @@
+/* Test for scanf formats.  Formats using C90 features, including cases
+   where C90 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, unsigned int *uip, short int *hp, unsigned short int *uhp,
+     long int *lp, unsigned long int *ulp, float *fp, double *dp,
+     long double *ldp, char *s, signed char *ss, unsigned char *us,
+     void **pp, int *n, llong *llp, ullong *ullp, wchar_t *ls,
+     const int *cip, const int *cn, const char *cs, const void **ppc,
+     void *const *pcp, short int *hn, long int *ln, void *p, char **sp,
+     volatile void *ppv)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.2 (pages 134-138).  */
+  /* Basic sanity checks for the different components of a format.  */
+  scanf ("%d", ip);
+  scanf ("%*d");
+  scanf ("%3d", ip);
+  scanf ("%hd", hp);
+  scanf ("%3ld", lp);
+  scanf ("%*3d");
+  scanf ("%d %ld", ip, lp);
+  /* Valid and invalid %% constructions.  */
+  scanf ("%%");
+  scanf ("%*%"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%*%\n"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%4%"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%4%\n"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%h%"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%h%\n"); /* { dg-warning "format" "bogus %%" } */
+  /* Valid, invalid and silly assignment-suppression constructions.  */
+  scanf ("%*d%*i%*o%*u%*x%*X%*e%*E%*f%*g%*G%*s%*[abc]%*c%*p");
+  scanf ("%*2d%*8s%*3c");
+  scanf ("%*n", n); /* { dg-warning "suppress" "suppression of %n" } */
+  scanf ("%*hd"); /* { dg-warning "together" "suppression with length" } */
+  /* Valid, invalid and silly width constructions.  */
+  scanf ("%2d%3i%4o%5u%6x%7X%8e%9E%10f%11g%12G%13s%14[abc]%15c%16p",
+	 ip, ip, uip, uip, uip, uip, fp, fp, fp, fp, fp, s, s, s, pp);
+  scanf ("%0d", ip); /* { dg-warning "width" "warning for zero width" } */
+  scanf ("%3n", n); /* { dg-warning "width" "width with %n" } */
+  /* Valid and invalid %h, %l, %L constructions.  */
+  scanf ("%hd%hi%ho%hu%hx%hX%hn", hp, hp, uhp, uhp, uhp, uhp, hn);
+  scanf ("%he", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hE", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hf", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hg", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hG", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hs", hp);
+  scanf ("%h[ac]", s); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hc", hp);
+  scanf ("%hp", pp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%h"); /* { dg-warning "conversion lacks type" "bare %h" } */
+  scanf ("%h."); /* { dg-warning "conversion" "bogus %h" } */
+  scanf ("%ld%li%lo%lu%lx%lX%ln", lp, lp, ulp, ulp, ulp, ulp, ln);
+  scanf ("%le%lE%lf%lg%lG", dp, dp, dp, dp, dp);
+  scanf ("%lp", pp); /* { dg-warning "length" "bad use of %l" } */
+  /* These next three formats were added in C94.  */
+  scanf ("%ls", ls); /* { dg-warning "length|C" "bad use of %l" } */
+  scanf ("%l[ac]", ls); /* { dg-warning "length|C" "bad use of %l" } */
+  scanf ("%lc", ls); /* { dg-warning "length|C" "bad use of %l" } */
+  scanf ("%Ld", llp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Li", llp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lo", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lu", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lx", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%LX", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Ls", s); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%L[ac]", s); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lc", s); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lp", pp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Ln", n); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  /* Valid uses of each bare conversion.  */
+  scanf ("%d%i%o%u%x%X%e%E%f%g%G%s%[abc]%c%p%n%%", ip, ip, uip, uip, uip,
+	 uip, fp, fp, fp, fp, fp, s, s, s, pp, n);
+  /* Allow other character pointers with %s, %c, %[].  */
+  scanf ("%2s%3s%4c%5c%6[abc]%7[abc]", ss, us, ss, us, ss, us);
+  /* Further tests for %[].  */
+  scanf ("%[%d]%d", s, ip);
+  scanf ("%[^%d]%d", s, ip);
+  scanf ("%[]%d]%d", s, ip);
+  scanf ("%[^]%d]%d", s, ip);
+  scanf ("%[%d]%d", s, ip);
+  scanf ("%[]abcd", s); /* { dg-warning "no closing" "incomplete scanset" } */
+  /* Various tests of bad argument types.  Some of these are only pedantic
+     warnings.
+  */
+  scanf ("%d", lp); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%d", uip); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%d", pp); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", ppc); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", ppv); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%s", n); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%s", p); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", p); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", sp); /* { dg-warning "format" "bad argument types" } */
+  /* Tests for writing into constant values.  */
+  scanf ("%d", cip); /* { dg-warning "constant" "%d writing into const" } */
+  scanf ("%n", cn); /* { dg-warning "constant" "%n writing into const" } */
+  scanf ("%s", cs); /* { dg-warning "constant" "%s writing into const" } */
+  scanf ("%p", pcp); /* { dg-warning "constant" "%p writing into const" } */
+  /* Wrong number of arguments.  */
+  scanf ("%d%d", ip); /* { dg-warning "arguments" "wrong number of args" } */
+  scanf ("%d", ip, ip); /* { dg-warning "arguments" "wrong number of args" } */
+  /* Miscellaneous bogus constructions.  */
+  scanf (""); /* { dg-warning "zero-length" "warning for empty format" } */
+  scanf ("\0"); /* { dg-warning "embedded" "warning for embedded NUL" } */
+  scanf ("%d\0", ip); /* { dg-warning "embedded" "warning for embedded NUL" } */
+  scanf ("%d\0%d", ip, ip); /* { dg-warning "embedded|too many" "warning for embedded NUL" } */
+  scanf (NULL); /* { dg-warning "null" "null format string warning" } */
+  scanf ("%"); /* { dg-warning "trailing" "trailing % warning" } */
+  scanf ("%d", (int *)0); /* { dg-warning "null" "writing into NULL" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-2.c
@@ -0,0 +1,26 @@
+/* Test for scanf formats.  Formats using C99 features should be rejected
+   outside of C99 mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (signed char *hhp, float *fp, llong *llp, intmax_t *jp,
+     size_t *zp, ptrdiff_t *tp)
+{
+  /* Some tests already in c90-scanf-1.c.  */
+  /* The widths hh, ll, j, z, t are new.  */
+  scanf ("%hhd", hhp); /* { dg-warning "unknown|format" "%hh is unsupported" } */
+  scanf ("%I64d", llp); /* { dg-warning "length|C" "%I64 in C90" } */
+  scanf ("%jd", jp); /* { dg-warning "unknown|format" "%j is unsupported" } */
+  scanf ("%zu", zp); /* { dg-warning "unknown|format" "%z is unsupported" } */
+  scanf ("%td", tp); /* { dg-warning "unknown|format" "%t is unsupported" } */
+  /* The formats F, a, A are new.  */
+  scanf ("%F", fp); /* { dg-warning "unknown|format" "%F is unsupported" } */
+  scanf ("%a", fp); /* { dg-warning "unknown|format" "%a is unsupported" } */
+  scanf ("%A", fp); /* { dg-warning "unknown|format" "%A is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-3.c
@@ -0,0 +1,20 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char **sp, wchar_t **lsp)
+{
+  /* %a formats for allocation, only recognized in C90 mode, are a
+     GNU extension.
+  */
+  scanf ("%as", sp); /* { dg-warning "flag" "%as is unsupported" } */
+  scanf ("%aS", lsp); /* { dg-warning "format|flag" "%aS is unsupported" } */
+  scanf ("%a[bcd]", sp); /* { dg-warning "flag" "%a[] is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-4.c
@@ -0,0 +1,31 @@
+/* Test for scanf formats.  Test that the C90 functions get their default
+   attributes in strict C90 mode, but the C99 and gettext functions
+   do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, char *s, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5)
+{
+  fscanf (stdin, "%d", ip);
+  fscanf (stdin, "%ld", ip); /* { dg-warning "format" "fscanf" } */
+  scanf ("%d", ip);
+  scanf ("%ld", ip); /* { dg-warning "format" "scanf" } */
+  sscanf (s, "%d", ip);
+  sscanf (s, "%ld", ip); /* { dg-warning "format" "sscanf" } */
+  vfscanf (stdin, "%d", v0);
+  vscanf ("%d", v2);
+  vsscanf (s, "%d", v4);
+  scanf (gettext ("%d"), ip);
+  scanf (gettext ("%ld"), ip);
+  scanf (dgettext ("", "%d"), ip);
+  scanf (dgettext ("", "%ld"), ip);
+  scanf (dcgettext ("", "%d", 0), ip);
+  scanf (dcgettext ("", "%ld", 0), ip);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-5.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-5.c
@@ -0,0 +1,20 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char **sp, wchar_t **lsp)
+{
+  /* m assignment-allocation modifier, recognized in both C90
+     and C99 modes, is a POSIX and ISO/IEC WDTR 24731-2 extension.  */
+  scanf ("%ms", sp); /* { dg-warning "unknown|format" "%ms is unsupported" } */
+  scanf ("%mS", lsp); /* { dg-warning "unknown|format" "%mS is unsupported" } */
+  scanf ("%mls", lsp); /* { dg-warning "unknown|format" "%mls is unsupported" } */
+  scanf ("%m[bcd]", sp); /* { dg-warning "unknown|format" "%m[] is unsupported" } */
+  scanf ("%ml[bcd]", lsp); /* { dg-warning "unknown|format" "%ml[] is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-1.c
@@ -0,0 +1,20 @@
+/* Test for strftime formats.  Formats using C90 features.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wformat-y2k" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.12.3.5 (pages 174-175).  */
+  /* Formats which are Y2K-compliant (no 2-digit years).  */
+  strftime (s, m, "%a%A%b%B%d%H%I%j%m%M%p%S%U%w%W%X%Y%Z%%", tp);
+  /* Formats with 2-digit years.  */
+  strftime (s, m, "%y", tp); /* { dg-warning "only last 2" "2-digit year" } */
+  /* Formats with 2-digit years in some locales.  */
+  strftime (s, m, "%c", tp); /* { dg-warning "some locales" "2-digit year" } */
+  strftime (s, m, "%x", tp); /* { dg-warning "some locales" "2-digit year" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-2.c
@@ -0,0 +1,30 @@
+/* Test for strftime formats.  Rejection of formats using C99 features in
+   pedantic C90 mode.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wformat-y2k" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  strftime (s, m, "%C", tp); /* { dg-warning "format" "%C is unsupported" } */
+  strftime (s, m, "%D", tp); /* { dg-warning "format" "%D is unsupported" } */
+  strftime (s, m, "%e", tp); /* { dg-warning "format" "%e is unsupported" } */
+  strftime (s, m, "%F", tp); /* { dg-warning "format" "%F is unsupported" } */
+  strftime (s, m, "%g", tp); /* { dg-warning "format" "%g is unsupported" } */
+  strftime (s, m, "%G", tp); /* { dg-warning "format" "%G is unsupported" } */
+  strftime (s, m, "%h", tp); /* { dg-warning "format" "%h is unsupported" } */
+  strftime (s, m, "%n", tp); /* { dg-warning "format" "%n is unsupported" } */
+  strftime (s, m, "%r", tp); /* { dg-warning "format" "%r is unsupported" } */
+  strftime (s, m, "%R", tp); /* { dg-warning "format" "%R is unsupported" } */
+  strftime (s, m, "%t", tp); /* { dg-warning "format" "%t is unsupported" } */
+  strftime (s, m, "%T", tp); /* { dg-warning "format" "%T is unsupported" } */
+  strftime (s, m, "%u", tp); /* { dg-warning "format" "%u is unsupported" } */
+  strftime (s, m, "%V", tp); /* { dg-warning "format" "%V is unsupported" } */
+  strftime (s, m, "%z", tp); /* { dg-warning "C" "%z not in C90" } */
+  strftime (s, m, "%EX", tp); /* { dg-warning "C" "%E not in C90" } */
+  strftime (s, m, "%OW", tp); /* { dg-warning "C" "%O not in C90" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c94-printf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c94-printf-1.c
@@ -0,0 +1,19 @@
+/* Test for printf formats.  Changes in C94 to C90.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:199409 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (wint_t lc, wchar_t *ls)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.1 (pages 131-134),
+     as amended by ISO/IEC 9899:1990/Amd.1:1995 (E) (pages 4-5).
+     We do not repeat here all the C90 format checks, but just verify
+     that %ls and %lc are accepted without warning.
+  */
+  printf ("%lc", lc);
+  printf ("%ls", ls);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c94-scanf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c94-scanf-1.c
@@ -0,0 +1,18 @@
+/* Test for scanf formats.  Changes in C94 to C90.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:199409 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (wchar_t *ls)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.2 (pages 134-138),
+     as amended by ISO/IEC 9899:1990/Amd.1:1995 (E) (pages 5-6).
+     We do not repeat here all the C90 format checks, but just verify
+     that %ls, %lc, %l[] are accepted without warning.
+  */
+  scanf ("%lc%ls%l[abc]", ls, ls, ls);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-1.c
@@ -0,0 +1,122 @@
+/* Test for printf formats.  Formats using C99 features, including cases
+   where C99 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, unsigned int u, double d, char *s, void *p, int *n,
+     long double ld, wint_t lc, wchar_t *ls, long long int ll,
+     unsigned long long int ull, signed char *ss, unsigned char *us,
+     long long int *lln, intmax_t j, uintmax_t uj, intmax_t *jn,
+     size_t z, signed_size_t sz, signed_size_t *zn,
+     ptrdiff_t t, ptrdiff_t *tn)
+{
+  /* See ISO/IEC 9899:1999 (E) subclause 7.19.6.1 (pages 273-281).
+     We do not repeat here most of the checks for correct C90 formats
+     or completely broken formats.
+  */
+  /* Valid and invalid %h, %hh, %l, %I64, %j, %z, %t, %L constructions.  */
+  printf ("%hf", d); /* { dg-warning "length" "bad use of %h" } */
+  printf ("%hF", d); /* { dg-warning "unknown|format" "bad use of %hF" } */
+  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 ("%ha", d); /* { dg-warning "unknown|format" "bad use of %ha" } */
+  printf ("%hA", d); /* { dg-warning "unknown|format" "bad use of %hA" } */
+  printf ("%hc", i);
+  printf ("%hs", (short *)s);
+  printf ("%hp", p); /* { dg-warning "length" "bad use of %h" } */
+  printf ("%lc", lc);
+  printf ("%ls", ls);
+  printf ("%lp", p); /* { dg-warning "length|C" "bad use of %l" } */
+  printf ("%I64d%I64i%I64o%I64u%I64x%I64X", ll, ll, ull, ull, ull, ull);
+  printf ("%I64n", lln);
+  printf ("%I64f", d); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64F", d); /* { dg-warning "unknown|format" "bad use of %I64F" } */
+  printf ("%I64e", d); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64E", d); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64g", d); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64G", d); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64a", d); /* { dg-warning "unknown|format" "bad use of %I64a" } */
+  printf ("%I64A", d); /* { dg-warning "unknown|format" "bad use of %I64A" } */
+  printf ("%I64c", i); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64s", s); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64p", p); /* { dg-warning "length" "bad use of %I64" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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% 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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 ("%-08F", d); /* { dg-warning "unknown|format" "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 ("%-08a", d); /* { dg-warning "unknown|format" "0 flag ignored with - flag" } */
+  printf ("%-08A", d); /* { dg-warning "unknown|format" "0 flag ignored with - flag" } */
+  /* Various tests of bad argument types.  Mostly covered in c90-printf-1.c;
+     here just test for pointer target sign with %hhn.  (Probably allowed
+     by the standard, but a bad idea, so GCC should diagnose if what
+     is used is not signed char *.)
+  */
+  printf ("%hhn", s); /* { dg-warning "unknown|format" "%hhn is unsupported" } */
+  printf ("%hhn", us); /* { dg-warning "unknown|format" "%hhn is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-2.c
@@ -0,0 +1,33 @@
+/* Test for printf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, long long ll, size_t z, wint_t lc, wchar_t *ls)
+{
+  /* The length modifiers q, Z and L as applied to integer formats are
+     extensions.
+  */
+  printf ("%qd", ll); /* { dg-warning "unknown|format" "%q length is unsupported" } */
+  printf ("%Ld", ll); /* { dg-warning "unknown|format" "%L length is unsupported" } */
+  printf ("%Zd", z); /* { dg-warning "unknown|format" "%Z lengthis unsupported" } */
+  /* The conversion specifiers C and S are X/Open extensions; the
+     conversion specifier m is a GNU extension.
+  */
+  printf ("%m"); /* { dg-warning "unknown|format" "printf %m is unsupported" } */
+  printf ("%C", lc); /* { dg-warning "C" "printf %C" } */
+  printf ("%S", ls); /* { dg-warning "C" "printf %S" } */
+  /* The flag character ', and the use of operand number $ formats, are
+     X/Open extensions.
+  */
+  printf ("%'d", i); /* { dg-warning "C" "printf ' flag" } */
+  printf ("%1$d", i); /* { dg-warning "C" "printf $ format" } */
+  /* The flag character I is a GNU extension.  */
+  printf ("%Ix", z);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-3.c
@@ -0,0 +1,40 @@
+/* Test for printf formats.  Test that the C99 functions get their default
+   attributes in strict C99 mode, but the gettext functions do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, char *s, size_t n, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5, va_list v6, va_list v7)
+{
+  fprintf (stdout, "%d", i);
+  fprintf (stdout, "%ld", i); /* { dg-warning "format" "fprintf" } */
+  printf ("%d", i);
+  printf ("%ld", i); /* { dg-warning "format" "printf" } */
+  /* The "unlocked" functions shouldn't warn in c99 mode.  */
+  fprintf_unlocked (stdout, "%ld", i);
+  printf_unlocked ("%ld", i);
+  sprintf (s, "%d", i);
+  sprintf (s, "%ld", i); /* { dg-warning "format" "sprintf" } */
+  snprintf (s, n, "%d", i);
+  snprintf (s, n, "%ld", i); /* { dg-warning "format" "snprintf" } */
+  vfprintf (stdout, "%d", v0);
+  vfprintf (stdout, "%Y", v1); /* { dg-warning "format" "vfprintf" } */
+  vprintf ("%d", v0);
+  vprintf ("%Y", v1); /* { dg-warning "format" "vprintf" } */
+  vsprintf (s, "%d", v0);
+  vsprintf (s, "%Y", v1); /* { dg-warning "format" "vsprintf" } */
+  vsnprintf (s, n, "%d", v0);
+  vsnprintf (s, n, "%Y", v1); /* { dg-warning "format" "vsnprintf" } */
+  printf (gettext ("%d"), i);
+  printf (gettext ("%ld"), (long) i);
+  printf (dgettext ("", "%d"), i);
+  printf (dgettext ("", "%ld"), (long) i);
+  printf (dcgettext ("", "%d", 0), i);
+  printf (dcgettext ("", "%ld", 0), (long) i);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-1.c
@@ -0,0 +1,75 @@
+/* Test for scanf formats.  Formats using C99 features, including cases
+   where C99 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, unsigned int *uip, short int *hp, unsigned short int *uhp,
+     signed char *hhp, unsigned char *uhhp, long int *lp,
+     unsigned long int *ulp, float *fp, double *dp, long double *ldp, char *s,
+     void **pp, int *n, long long *llp, unsigned long long *ullp, wchar_t *ls,
+     short int *hn, signed char *hhn, long int *ln, long long int *lln,
+     intmax_t *jp, uintmax_t *ujp, intmax_t *jn, size_t *zp,
+     signed_size_t *szp, signed_size_t *zn, ptrdiff_t *tp,
+     unsigned_ptrdiff_t *utp, ptrdiff_t *tn)
+{
+  /* See ISO/IEC 9899:1999 (E) subclause 7.19.6.2 (pages 281-288).
+     We do not repeat here most of the checks for correct C90 formats
+     or completely broken formats.
+  */
+  /* Valid, invalid and silly assignment-suppression
+     and width constructions.
+  */
+  scanf ("%*d%*i%*o%*u%*x%*X%*e%*E%*f%*g%*G%*s%*[abc]%*c%*p");
+  scanf ("%*2d%*8s%*3c");
+  scanf ("%*n", n); /* { dg-warning "suppress" "suppression of %n" } */
+  scanf ("%*hd"); /* { dg-warning "together" "suppression with length" } */
+  scanf ("%2d%3i%4o%5u%6x%7X%10e%11E%12f%14g%15G%16s%3[abc]%4c%5p",
+	 ip, ip, uip, uip, uip, uip, fp, fp, fp, fp, fp,
+	 s, s, s, pp);
+  scanf ("%0d", ip); /* { dg-warning "width" "warning for zero width" } */
+  scanf ("%3n", n); /* { dg-warning "width" "width with %n" } */
+  /* Valid and invalid %h, %hh, %l, %I64, %j, %z, %t, %L constructions.  */
+  scanf ("%hd%hi%ho%hu%hx%hX%hn", hp, hp, uhp, uhp, uhp, uhp, hn);
+  scanf ("%he", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hE", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hf", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hg", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hG", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hs", hp);
+  scanf ("%h[ac]", s); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hc", (short *)s);
+  scanf ("%hp", pp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hhd", hhp); /* { dg-warning "unknown|format" "%hh is unsupported" } */
+  scanf ("%ld%li%lo%lu%lx%lX%ln", lp, lp, ulp, ulp, ulp, ulp, ln);
+  scanf ("%le%lE%lf%lg%lG", dp, dp, dp, dp, dp);
+  scanf ("%lp", pp); /* { dg-warning "length" "bad use of %l" } */
+  scanf ("%ls", ls);
+  scanf ("%l[ac]", ls);
+  scanf ("%lc", ls);
+  scanf ("%I64d%I64i%I64o%I64u%I64x%I64X%I64n", llp, llp, ullp, ullp, ullp, ullp,
+	 lln);
+  scanf ("%I64e", fp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64E", fp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64f", fp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64F", fp); /* { dg-warning "unknown|format" "'F' is unsupported" } */
+  scanf ("%I64g", fp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64G", fp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64s", s); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64[ac]", s); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64c", s); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64p", pp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%jd", jp); /* { dg-warning "unknown|format" "%j not supported" } */
+  scanf ("%zd", zp); /* { dg-warning "unknown|format" "%z not supported" } */
+  scanf ("%td", tp); /* { dg-warning "unknown|format" "%t not supported" } */
+  scanf ("%Lf", llp); /* { dg-warning "unknown|format" "bad use of %L is not supported" } */
+  /* Valid uses of each bare conversion.  */
+  scanf ("%d%i%o%u%x%X%e%E%f%g%G%s%[abc]%c%p%n%%", ip, ip, uip, uip, uip,
+         uip, fp, fp, fp, fp, fp, s, s, s, pp, n);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-2.c
@@ -0,0 +1,27 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, long long int *llp, wchar_t *ls)
+{
+  /* The length modifiers q and L as applied to integer formats are
+     extensions.
+  */
+  scanf ("%qd", llp); /* { dg-warning "unknown|format" "%q is unsupported" } */
+  scanf ("%Ld", llp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  /* The conversion specifiers C and S are X/Open extensions.  */
+  scanf ("%C", ls); /* { dg-warning "C" "scanf %C" } */
+  scanf ("%S", ls); /* { dg-warning "C" "scanf %S" } */
+  /* The use of operand number $ formats is an X/Open extension.  */
+  scanf ("%1$d", ip); /* { dg-warning "C" "scanf $ format" } */
+  /* glibc also supports flags ' and I on scanf formats as an extension.  */
+  scanf ("%'d", ip); /* { dg-warning "C" "scanf ' flag" } */
+  scanf ("%Id", (ssize_t *)ip);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-3.c
@@ -0,0 +1,33 @@
+/* Test for scanf formats.  Test that the C99 functions get their default
+   attributes in strict C99 mode, but the gettext functions do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, char *s, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5)
+{
+  fscanf (stdin, "%d", ip);
+  fscanf (stdin, "%ld", ip); /* { dg-warning "format" "fscanf" } */
+  scanf ("%d", ip);
+  scanf ("%ld", ip); /* { dg-warning "format" "scanf" } */
+  sscanf (s, "%d", ip);
+  sscanf (s, "%ld", ip); /* { dg-warning "format" "sscanf" } */
+  vfscanf (stdin, "%d", v0);
+  vfscanf (stdin, "%Y", v1); /* { dg-warning "format" "vfscanf" } */
+  vscanf ("%d", v2);
+  vscanf ("%Y", v3); /* { dg-warning "format" "vscanf" } */
+  vsscanf (s, "%d", v4);
+  vsscanf (s, "%Y", v5); /* { dg-warning "format" "vsscanf" } */
+  scanf (gettext ("%d"), ip);
+  scanf (gettext ("%ld"), ip);
+  scanf (dgettext ("", "%d"), ip);
+  scanf (dgettext ("", "%ld"), ip);
+  scanf (dcgettext ("", "%d", 0), ip);
+  scanf (dcgettext ("", "%ld", 0), ip);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-4.c
@@ -0,0 +1,20 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char **sp, wchar_t **lsp)
+{
+  /* m assignment-allocation modifier, recognized in both C90
+     and C99 modes, is a POSIX and ISO/IEC WDTR 24731-2 extension.  */
+  scanf ("%ms", sp); /* { dg-warning "unknown|format" "%ms is unsupported" } */
+  scanf ("%mS", lsp); /* { dg-warning "unknown|format" "%mS is unsupported" } */
+  scanf ("%mls", lsp); /* { dg-warning "unknown|format" "%mls is unsupported" } */
+  scanf ("%m[bcd]", sp); /* { dg-warning "unknown|format" "%m[] is unsupported" } */
+  scanf ("%ml[bcd]", lsp); /* { dg-warning "unknown|format" "%ml[] is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-1.c
@@ -0,0 +1,30 @@
+/* Test for strftime formats.  Formats using C99 features.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat -Wformat-y2k" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.12.3.5 (pages 174-175).  */
+  /* Formats which are Y2K-compliant (no 2-digit years).  */
+  strftime (s, m, "%a%A%b%B%d%H%I%j%m%M%p%S%U%w%W%X%Y%z%Z%%", tp);
+  strftime (s, m, "%EX%EY%Od%OH%OI%Om%OM%OS%OU%Ow%OW", tp);
+  /* Formats with 2-digit years.  */
+  strftime (s, m, "%D", tp); /* { dg-warning "unknown" "2-digit year unsupported" } */
+  strftime (s, m, "%g", tp); /* { dg-warning "unknown" "2-digit year unsupported" } */
+  strftime (s, m, "%y", tp); /* { dg-warning "only last 2" "2-digit year" } */
+  strftime (s, m, "%Oy", tp); /* { dg-warning "only last 2" "2-digit year" } */
+  /* Formats with 2-digit years in some locales.  */
+  strftime (s, m, "%c", tp); /* { dg-warning "some locales" "2-digit year" } */
+  strftime (s, m, "%Ec", tp); /* { dg-warning "some locales" "2-digit year" } */
+  strftime (s, m, "%x", tp); /* { dg-warning "some locales" "2-digit year" } */
+  strftime (s, m, "%Ex", tp); /* { dg-warning "some locales" "2-digit year" } */
+  /* %Ey is explicitly an era offset not a 2-digit year; but in some
+     locales the E modifier may be ignored.
+  */
+  strftime (s, m, "%Ey", tp); /* { dg-warning "some locales" "2-digit year" } */
+  }
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-2.c
@@ -0,0 +1,24 @@
+/* Test for strftime formats.  Rejection of extensions in pedantic mode.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  /* %P is a lowercase version of %p.  */
+  strftime (s, m, "%P", tp); /* { dg-warning "unknown" "strftime %P" } */
+  /* %k is %H but padded with a space rather than 0 if necessary.  */
+  strftime (s, m, "%k", tp); /* { dg-warning "unknown" "strftime %k" } */
+  /* %l is %I but padded with a space rather than 0 if necessary.  */
+  strftime (s, m, "%l", tp); /* { dg-warning "unknown" "strftime %l" } */
+  /* %s is the number of seconds since the Epoch.  */
+  strftime (s, m, "%s", tp); /* { dg-warning "unknown" "strftime %s" } */
+  /* Extensions using %O already tested in c99-strftime-1.c.  */
+  /* Width and flags are GNU extensions for strftime.  */
+  strftime (s, m, "%20Y", tp); /* { dg-warning "C" "strftime width" } */
+  strftime (s, m, "%^A", tp); /* { dg-warning "C" "strftime flags" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_cast-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_cast-1.c
@@ -0,0 +1,17 @@
+/* Test for strings cast through integer types: should not be treated
+   as format strings unless the types are of the same width as
+   pointers (intptr_t or similar).  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+f (int x)
+{
+  printf("%s", x); /* { dg-warning "format" } */
+  printf((char *)(size_t)"%s", x); /* { dg-warning "format" } */
+  printf((char *)(char)"%s", x); /* { dg-warning "cast from pointer to integer of different size" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-1.c
@@ -0,0 +1,40 @@
+/* Test for warnings for missing format attributes.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  vprintf (fmt, ap); /* { dg-warning "candidate" "printf attribute warning" } */
+  va_end (ap);
+}
+
+void
+bar (const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  vscanf (fmt, ap); /* { dg-warning "candidate" "scanf attribute warning" } */
+  va_end (ap);
+}
+
+__attribute__((__format__(__ms_printf__, 1, 2))) void
+foo2 (const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  vprintf (fmt, ap);
+  va_end (ap);
+}
+
+void
+vfoo (const char *fmt, va_list arg)
+{
+  vprintf (fmt, arg); /* { dg-warning "candidate" "printf attribute warning 2" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-2.c
@@ -0,0 +1,17 @@
+/* Test for warnings for missing format attributes.  Don't warn if no
+   relevant parameters for a format attribute; see c/1017.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, ...)
+{
+  va_list ap;
+  va_start (ap, i);
+  vprintf ("Foo %s bar %s", ap); /* { dg-bogus "candidate" "bogus printf attribute warning" } */
+  va_end (ap);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-3.c
@@ -0,0 +1,27 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+void
+foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
+{
+  noattr_t na1 = na;
+  noattr_t na2 = a; /* { dg-warning "candidate" "initialization warning" } */
+  attr_t a1 = na;
+  attr_t a2 = a;
+
+  vnoattr_t vna1 = vna;
+  vnoattr_t vna2 = va; /* { dg-warning "candidate" "initialization warning" } */
+  vattr_t va1 = vna;
+  vattr_t va2 = va;
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-4.c
@@ -0,0 +1,33 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+void
+foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
+{
+  noattr_t na1, na2;
+  attr_t a1, a2;
+
+  vnoattr_t vna1, vna2;
+  vattr_t va1, va2;
+
+  na1 = na;
+  na2 = a; /* { dg-warning "candidate" "assignment warning" } */
+  a1 = na;
+  a2 = a;
+
+  vna1 = vna;
+  vna2 = va; /* { dg-warning "candidate" "assignment warning" } */
+  va1 = vna;
+  va1 = va;
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-5.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-5.c
@@ -0,0 +1,49 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+noattr_t
+foo1 (noattr_t na, attr_t a, int i)
+{
+  if (i)
+    return na;
+  else
+    return a; /* { dg-warning "candidate" "return type warning" } */
+}
+
+attr_t
+foo2 (noattr_t na, attr_t a, int i)
+{
+  if (i)
+    return na;
+  else
+    return a;
+}
+
+vnoattr_t
+foo3 (vnoattr_t vna, vattr_t va, int i)
+{
+  if (i)
+    return vna;
+  else
+    return va; /* { dg-warning "candidate" "return type warning" } */
+}
+
+vattr_t
+foo4 (vnoattr_t vna, vattr_t va, int i)
+{
+  if (i)
+    return vna;
+  else
+    return va;
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-6.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-6.c
@@ -0,0 +1,32 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+extern void foo1 (noattr_t);
+extern void foo2 (attr_t);
+extern void foo3 (vnoattr_t);
+extern void foo4 (vattr_t);
+
+void
+foo (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
+{
+  foo1 (na);
+  foo1 (a); /* { dg-warning "candidate" "parameter passing warning" } */
+  foo2 (na);
+  foo2 (a);
+
+  foo3 (vna);
+  foo3 (va); /* { dg-warning "candidate" "parameter passing warning" } */
+  foo4 (vna);
+  foo4 (va);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_multattr-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_multattr-1.c
@@ -0,0 +1,51 @@
+/* Test for multiple format attributes.  Test for printf and scanf attributes
+   together.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* If we specify multiple attributes for a single function, they should
+   all apply.  This should apply whether they are on the same declaration
+   or on different declarations.  */
+
+extern void my_vprintf_scanf (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_printf__, 1, 0)))
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern void my_vprintf_scanf2 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)))
+     __attribute__((__format__(__ms_printf__, 1, 0)));
+
+extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_printf__, 1, 0)));
+extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_printf__, 1, 0)));
+
+void
+foo (va_list ap, int *ip, long *lp)
+{
+  my_vprintf_scanf ("%d", ap, "%d", ip);
+  my_vprintf_scanf ("%d", ap, "%ld", lp);
+  my_vprintf_scanf ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf2 ("%d", ap, "%d", ip);
+  my_vprintf_scanf2 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf2 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf2 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf3 ("%d", ap, "%d", ip);
+  my_vprintf_scanf3 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf3 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf3 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf4 ("%d", ap, "%d", ip);
+  my_vprintf_scanf4 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf4 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf4 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_multattr-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_multattr-2.c
@@ -0,0 +1,40 @@
+/* Test for multiple format attributes.  Test for printf and scanf attributes
+   together, in different places on the declarations.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* If we specify multiple attributes for a single function, they should
+   all apply, wherever they are placed on the declarations.  */
+
+extern __attribute__((__format__(__ms_printf__, 1, 0))) void
+     my_vprintf_scanf (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern void (__attribute__((__format__(__ms_printf__, 1, 0))) my_vprintf_scanf2)
+     (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern __attribute__((__format__(__ms_scanf__, 3, 4))) void
+     (__attribute__((__format__(__ms_printf__, 1, 0))) my_vprintf_scanf3)
+     (const char *, va_list, const char *, ...);
+
+void
+foo (va_list ap, int *ip, long *lp)
+{
+  my_vprintf_scanf ("%d", ap, "%d", ip);
+  my_vprintf_scanf ("%d", ap, "%ld", lp);
+  my_vprintf_scanf ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf2 ("%d", ap, "%d", ip);
+  my_vprintf_scanf2 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf2 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf2 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf3 ("%d", ap, "%d", ip);
+  my_vprintf_scanf3 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf3 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf3 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_multattr-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_multattr-3.c
@@ -0,0 +1,29 @@
+/* Test for multiple format_arg attributes.  Test for both branches
+   getting checked.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+extern char *ngettext (const char *, const char *, unsigned long int)
+     __attribute__((__format_arg__(1))) __attribute__((__format_arg__(2)));
+
+void
+foo (long l, int nfoo)
+{
+  printf (ngettext ("%d foo", "%d foos", nfoo), nfoo);
+  printf (ngettext ("%d foo", "%d foos", l), l); /* { dg-warning "int" "wrong type in conditional expr" } */
+  printf (ngettext ("%d foo", "%ld foos", l), l); /* { dg-warning "int" "wrong type in conditional expr" } */
+  printf (ngettext ("%ld foo", "%d foos", l), l); /* { dg-warning "int" "wrong type in conditional expr" } */
+  /* Should allow one case to have extra arguments.  */
+  printf (ngettext ("1 foo", "%d foos", nfoo), nfoo);
+  printf (ngettext ("1 foo", "many foos", nfoo), nfoo); /* { dg-warning "too many" "too many args in all branches" } */
+  printf (ngettext ("", "%d foos", nfoo), nfoo);
+  printf (ngettext ("1 foo", (nfoo > 0) ? "%d foos" : "no foos", nfoo), nfoo);
+  printf (ngettext ("%d foo", (nfoo > 0) ? "%d foos" : "no foos", nfoo), nfoo);
+  printf (ngettext ("%ld foo", (nfoo > 0) ? "%d foos" : "no foos", nfoo), nfoo); /* { dg-warning "long int" "wrong type" } */
+  printf (ngettext ("%d foo", (nfoo > 0) ? "%ld foos" : "no foos", nfoo), nfoo); /* { dg-warning "long int" "wrong type" } */
+  printf (ngettext ("%d foo", (nfoo > 0) ? "%d foos" : "%ld foos", nfoo), nfoo); /* { dg-warning "long int" "wrong type" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-1.c
@@ -0,0 +1,15 @@
+/* Test for warnings for extra format arguments being disabled by
+   -Wno-format-extra-args.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wno-format-extra-args" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i)
+{
+  printf ("foo", i);
+  printf ("%1$d", i, i);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-2.c
@@ -0,0 +1,28 @@
+/* Test for warnings for extra format arguments being disabled by
+   -Wno-format-extra-args.  Test which warnings still apply with $
+   operand numbers.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wno-format-extra-args" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, int *ip, va_list va)
+{
+  printf ("%3$d%1$d", i, i, i); /* { dg-warning "before used" "unused $ operand" } */
+  printf ("%2$d%1$d", i, i, i);
+  vprintf ("%3$d%1$d", va); /* { dg-warning "before used" "unused $ operand" } */
+  /* With scanf formats, gaps in the used arguments are allowed only if the
+     arguments are all pointers.  In such a case, should only give the lesser
+     warning about unused arguments rather than the more serious one about
+     argument gaps.  */
+  scanf ("%3$d%1$d", ip, ip, ip);
+  /* If there are non-pointer arguments unused at the end, this is also OK.  */
+  scanf ("%3$d%1$d", ip, ip, ip, i);
+  scanf ("%3$d%1$d", ip, i, ip); /* { dg-warning "before used" "unused $ scanf non-pointer operand" } */
+  /* Can't check the arguments in the vscanf case, so should suppose the
+     lesser problem.  */
+  vscanf ("%3$d%1$d", va);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_no-y2k-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_no-y2k-1.c
@@ -0,0 +1,13 @@
+/* Test for warnings for Y2K problems not being on by default.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  strftime (s, m, "%y%c%x", tp);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-1.c
@@ -0,0 +1,14 @@
+/* Test for warnings for non-string-literal formats.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wformat-nonliteral" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t i)
+{
+  printf ((const char *)i, i); /* { dg-warning "argument types" "non-literal" } */
+  printf (s, i); /* { dg-warning "argument types" "non-literal" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-2.c
@@ -0,0 +1,14 @@
+/* Test for warnings for non-string-literal formats.  Test with -Wformat=2.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat=2" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t i)
+{
+  printf ((const char *)i, i); /* { dg-warning "argument types" "non-literal" } */
+  printf (s, i); /* { dg-warning "argument types" "non-literal" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-3.c
@@ -0,0 +1,13 @@
+/* Test for warnings for non-string-literal formats.  Test for strftime formats.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wformat-nonliteral" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp, char *fmt)
+{
+  strftime (s, m, fmt, tp); /* { dg-warning "format string" "non-literal" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nul-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nul-1.c
@@ -0,0 +1,15 @@
+/* Test diagnostics for suppressing contains nul
+   -Wformat.  -Wformat.  */
+/* Origin: Bruce Korb <bkorb@gnu.org> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat -Wno-format-contains-nul" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (void)
+{
+  static char const fmt[] = "x%s\0%s\n\0abc";
+  printf (fmt+4, fmt+8); /* { dg-bogus "embedded.*in format" "bogus embed warning" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nul-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nul-2.c
@@ -0,0 +1,17 @@
+/* Test diagnostics for options used on their own without
+   -Wformat.  -Wformat-.  */
+/* Origin: Bruce Korb <bkorb@gnu.org> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+
+/* { dg-warning "embedded .* in format" "ignored" { target *-*-* } 0 } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+fumble (void)
+{
+  static char const fmt[] = "x%s\0%s\n\0abc";
+  printf (fmt+4, fmt+8);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_null-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_null-1.c
@@ -0,0 +1,28 @@
+/* Test for some aspects of null format string handling.  */
+/* Origin: Jason Thorpe <thorpej@wasabisystems.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+extern void my_printf (const char *, ...) __attribute__((format(ms_printf,1,2)));
+extern const char *my_format (const char *, const char *)
+  __attribute__((format_arg(2)));
+
+void
+foo (int i1)
+{
+  /* Warning about a null format string has been decoupled from the actual
+     format check.  However, we still expect to be warned about any excess
+     arguments after a null format string.  */
+  my_printf (NULL);
+  my_printf (NULL, i1); /* { dg-warning "too many" "null format with arguments" } */
+
+  my_printf (my_format ("", NULL));
+  my_printf (my_format ("", NULL), i1); /* { dg-warning "too many" "null format_arg with arguments" } */
+
+  /* While my_printf allows a null argument, dgettext does not, so we expect
+     a null argument warning here.  */
+  my_printf (dgettext ("", NULL)); /* { dg-warning "null" "null format with dgettext" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_plus-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_plus-1.c
@@ -0,0 +1,21 @@
+/* Test for printf formats using string literal plus constant.
+ */
+/* Origin: Jakub Jelinek <jakub@redhat.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat=2" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i)
+{
+  printf ("%%d\n" + 1, i);
+  printf (5 + "%.-*d%3d\n", i);
+  printf ("%d%d" + 2, i, i);	/* { dg-warning "arguments" "wrong number of args" } */
+  printf (3 + "%d\n");		/* { dg-warning "zero-length" "zero-length string" } */
+  printf ("%d\n" + i, i);	/* { dg-warning "not a string" "non-constant addend" } */
+  printf ("%d\n" + 10);		/* { dg-warning "not a string" "too large addend" } */
+  printf ("%d\n" - 1, i);	/* { dg-warning "not a string" "minus constant" } */
+  printf ("%d\n" + -1, i);	/* { dg-warning "not a string" "negative addend" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_sec-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_sec-1.c
@@ -0,0 +1,13 @@
+/* Test for security warning when non-literal format has no arguments.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wformat-security" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s)
+{
+  printf (s); /* { dg-warning "no format arguments" "security warning" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_unnamed-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_unnamed-1.c
@@ -0,0 +1,24 @@
+/* Test for warnings with possibly unnamed integer types.  Bug 24329.  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+/* { dg-options "-Wformat -msse" { target { { i?86-*-* x86_64-*-* } && ilp32 } } } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* Definition of TItype follows same logic as in gcc.dg/titype-1.c,
+   but must be a #define to avoid giving the type a name.  */
+#if defined(__LP64__) && !defined(__hppa__)
+#define TItype int __attribute__ ((mode (TI)))
+#else
+#define TItype long
+#endif
+
+void
+f (TItype x)
+{
+  printf("%d", x); /* { dg-warning "expects type" } */
+  printf("%d", 141592653589793238462643383279502884197169399375105820974944); /* { dg-warning "expects type" } */
+  /* { dg-warning "unsigned only|too large" "constant" { target *-*-* } 22 } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_va-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_va-1.c
@@ -0,0 +1,14 @@
+/* Test for strange warning in format checking.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (void *p)
+{
+  printf ("%d", p); /* { dg-bogus "va_list" "wrong type in format warning" } */
+  /* { dg-warning "format" "format error" { target *-*-* } 12 } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_warnll-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_warnll-1.c
@@ -0,0 +1,19 @@
+/* Test for printf formats.  C99 "long long" formats should be accepted with
+   -Wno-long-long.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wno-long-long" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (long long ll, unsigned long long ull, long long *lln,
+     long long *llp, unsigned long long *ullp)
+{
+  /* Test for accepting standard "long long" formats.  */
+  printf ("%I64d%I64i%I64o%I64u%I64x%I64X%I64n", ll, ll, ull, ull, ull, ull, lln);
+  scanf ("%I64d%I64i%I64o%I64u%I64x%I64X%I64n", llp, llp,
+	 ullp, ullp, ullp, ullp, lln);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_zero-length-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_zero-length-1.c
@@ -0,0 +1,16 @@
+/* Test the -Wno-format-zero-length option, which suppresses warnings
+   about zero-length formats.  */
+/* Origin: Jason Thorpe <thorpej@wasabisystems.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wno-format-zero-length" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (void)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.1 (pages 131-134).  */
+  /* Zero-length format strings are allowed.  */
+  printf ("");
+}
Index: gcc/gcc/testsuite/gcc.dg/format/multattr-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/multattr-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/multattr-1.c
@@ -4,6 +4,7 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 /* If we specify multiple attributes for a single function, they should
@@ -11,22 +12,22 @@
    or on different declarations.  */
 
 extern void my_vprintf_scanf (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__printf__, 1, 0)))
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)))
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
 extern void my_vprintf_scanf2 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)))
-     __attribute__((__format__(__printf__, 1, 0)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)))
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)));
 
 extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__printf__, 1, 0)));
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)));
 extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
 extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__printf__, 1, 0)));
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)));
 
 void
 foo (va_list ap, int *ip, long *lp)
Index: gcc/gcc/testsuite/gcc.dg/format/multattr-2.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/multattr-2.c
+++ gcc/gcc/testsuite/gcc.dg/format/multattr-2.c
@@ -4,21 +4,22 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 /* If we specify multiple attributes for a single function, they should
    all apply, wherever they are placed on the declarations.  */
 
-extern __attribute__((__format__(__printf__, 1, 0))) void
+extern __attribute__((__format__(gnu_attr___printf__, 1, 0))) void
      my_vprintf_scanf (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
-extern void (__attribute__((__format__(__printf__, 1, 0))) my_vprintf_scanf2)
+extern void (__attribute__((__format__(gnu_attr___printf__, 1, 0))) my_vprintf_scanf2)
      (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
-extern __attribute__((__format__(__scanf__, 3, 4))) void
-     (__attribute__((__format__(__printf__, 1, 0))) my_vprintf_scanf3)
+extern __attribute__((__format__(gnu_attr___scanf__, 3, 4))) void
+     (__attribute__((__format__(gnu_attr___printf__, 1, 0))) my_vprintf_scanf3)
      (const char *, va_list, const char *, ...);
 
 void
Index: gcc/gcc/testsuite/gcc.dg/format/null-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/null-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/null-1.c
@@ -3,9 +3,10 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern void my_printf (const char *, ...) __attribute__((format(printf,1,2)));
+extern void my_printf (const char *, ...) __attribute__((format(gnu_attr_printf,1,2)));
 extern const char *my_format (const char *, const char *)
   __attribute__((format_arg(2)));
 
=

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf  formatters to c-format.c
  2008-02-13 21:27       ` Danny Smith
@ 2008-02-19  9:17         ` Kai Tietz
  0 siblings, 0 replies; 61+ messages in thread
From: Kai Tietz @ 2008-02-19  9:17 UTC (permalink / raw)
  To: Danny Smith; +Cc: GCC Patches, Joseph S. Myers, NightStrike

"Danny Smith" <dansmister@gmail.com> wrote on 13.02.2008 22:06:47:

> >
> > 2008-02-04      Kai Tietz  <kai.tietz@onevision.com>
> >
> >         * c-format.c: (replace_formatter_name_to_system_name): New.
> >         (cmp_formatter_kind): New.
> >         (cmp_attribs): New.
> >         (replace_formatter_name_to_system_name): New.
> >         (decode_format_attr): Use of
> > replace_formatter_name_to_system_name.
> >         (format_types_orig): Add gnu_ prefix to names.
> >         (check_format_info_main): Special treating of \0 escaped names 
for
> >         supporting multi-character formatters as I32, I64.
> >         (TARGET_OVERRIDES_FORMAT_ATTRIBUTES): Use of user defined
> > attributes.
> >         (gnu_target_overrides_format_attributes): New.
> >         * gcc/c-format.h: Add structure target_ovr_attr to hold
> >         system specific formatter names.
> >         * config.gcc: Add for x86&x86_64 cygwin and mingw32 targets 
the
> >         msformat-c.o file to c_target_objs and cxx_target_objs.
> >         * config/i386/mingw32.h: (TARGET_OVERRIDES_FORMAT_ATTRIBUTES):
> > New.
> >         (TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT): New.
> >         (TARGET_N_FORMAT_TYPES): New.
> >         * config/i386/msformat-c.c: New.
> >         * config/i386/t-cygming: Add build rule for msformat-c.o.
> >         * doc/extend.texi: Add new format names gnu_* and ms_*.
> >         * doc/tm.texi: (TARGET_OVERRIDES_FORMAT_ATTRIBUTES): New.
> >         * testsuite/gcc.dg/format/sys_formatter.c: New.
> >
> 
> 
> This does not look right.
> 
> +/* Mingw specific format attributes ms_printf, ms_scanf, and 
ms_strftime.  */
> +
> +static const format_length_info ms_printf_length_specs[] =
> +{
> +  { "h", FMT_LEN_h, STD_C89, NULL, 0, 0 },
> +  { "l", FMT_LEN_l, STD_C89, NULL, 0, 0 },
> +  { "\0I32", FMT_LEN_l, STD_C89, NULL, 0, 0 },
> +  { "\0I64", FMT_LEN_ll, STD_C9L, NULL, 0, 0 },
> +  { "I", FMT_LEN_L, STD_C89, NULL, 0, 0 },
> +  { NULL, 0, 0, NULL, 0, 0 }
> +};
> +
> The  MS specs  I32, i64, and I specs are STD_EXT  and should cause a 
pedwarn

Thank you for the remark. I correct them. While implementation I thought, 
that it would be best to have a C89 declaration to avoid these warnings, 
which are not really preventable.
By the way, why should we insist for this target on a pedwarn? Is there a 
chance for this target to avoid this?

Cheers,
   Kai

|  (\_/)  This is Bunny. Copy and paste Bunny
| (='.'=) into your signature to help him gain
| (")_(") world domination.

------------------------------------------------------------------------------------------
  OneVision Software Entwicklungs GmbH & Co. KG
  Dr.-Leo-Ritter-Straße 9 - 93049 Regensburg
  Tel: +49.(0)941.78004.0 - Fax: +49.(0)941.78004.489 - www.OneVision.com
  Commerzbank Regensburg - BLZ 750 400 62 - Konto 6011050
  Handelsregister: HRA 6744, Amtsgericht Regensburg
  Komplementärin: OneVision Software Entwicklungs Verwaltungs GmbH
  Dr.-Leo-Ritter-Straße 9 – 93049 Regensburg
  Handelsregister: HRB 8932, Amtsgericht Regensburg - Geschäftsführer: 
Ulrike Döhler, Manuela Kluger



^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf formatters to c-format.c
  2008-02-04 14:23     ` Kai Tietz
  2008-02-13 18:32       ` Joseph S. Myers
@ 2008-02-13 21:27       ` Danny Smith
  2008-02-19  9:17         ` Kai Tietz
  1 sibling, 1 reply; 61+ messages in thread
From: Danny Smith @ 2008-02-13 21:27 UTC (permalink / raw)
  To: Kai Tietz; +Cc: Joseph S. Myers, GCC Patches, NightStrike

>
> 2008-02-04      Kai Tietz  <kai.tietz@onevision.com>
>
>         * c-format.c: (replace_formatter_name_to_system_name): New.
>         (cmp_formatter_kind): New.
>         (cmp_attribs): New.
>         (replace_formatter_name_to_system_name): New.
>         (decode_format_attr): Use of
> replace_formatter_name_to_system_name.
>         (format_types_orig): Add gnu_ prefix to names.
>         (check_format_info_main): Special treating of \0 escaped names for
>         supporting multi-character formatters as I32, I64.
>         (TARGET_OVERRIDES_FORMAT_ATTRIBUTES): Use of user defined
> attributes.
>         (gnu_target_overrides_format_attributes): New.
>         * gcc/c-format.h: Add structure target_ovr_attr to hold
>         system specific formatter names.
>         * config.gcc: Add for x86&x86_64 cygwin and mingw32 targets the
>         msformat-c.o file to c_target_objs and cxx_target_objs.
>         * config/i386/mingw32.h: (TARGET_OVERRIDES_FORMAT_ATTRIBUTES):
> New.
>         (TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT): New.
>         (TARGET_N_FORMAT_TYPES): New.
>         * config/i386/msformat-c.c: New.
>         * config/i386/t-cygming: Add build rule for msformat-c.o.
>         * doc/extend.texi: Add new format names gnu_* and ms_*.
>         * doc/tm.texi: (TARGET_OVERRIDES_FORMAT_ATTRIBUTES): New.
>         * testsuite/gcc.dg/format/sys_formatter.c: New.
>


This does not look right.

+/* Mingw specific format attributes ms_printf, ms_scanf, and ms_strftime.  */
+
+static const format_length_info ms_printf_length_specs[] =
+{
+  { "h", FMT_LEN_h, STD_C89, NULL, 0, 0 },
+  { "l", FMT_LEN_l, STD_C89, NULL, 0, 0 },
+  { "\0I32", FMT_LEN_l, STD_C89, NULL, 0, 0 },
+  { "\0I64", FMT_LEN_ll, STD_C9L, NULL, 0, 0 },
+  { "I", FMT_LEN_L, STD_C89, NULL, 0, 0 },
+  { NULL, 0, 0, NULL, 0, 0 }
+};
+
The  MS specs  I32, i64, and I specs are STD_EXT  and should cause a pedwarn
Danny

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf         formatters to c-format.c
  2008-02-04 14:23     ` Kai Tietz
@ 2008-02-13 18:32       ` Joseph S. Myers
  2008-02-19  9:22         ` Kai Tietz
  2008-02-13 21:27       ` Danny Smith
  1 sibling, 1 reply; 61+ messages in thread
From: Joseph S. Myers @ 2008-02-13 18:32 UTC (permalink / raw)
  To: Kai Tietz; +Cc: Danny Smith, GCC Patches, NightStrike

On Mon, 4 Feb 2008, Kai Tietz wrote:

> Thank you for your advice. May just by consistancy we should'nt declare 
> C99 functions for c90 in format.h. But the %Y is not present for mingw at 
> all. Therefore I prefer to disable them for these targets completely.

In that case you'll need to disable c99-printf-3.c for those targets as 
well; this patch version still has the bogus changes there.

"formatter" is nowhere used in the existing code to refer to kinds of 
formats; I suggest just using "format" throughout the patch.

>         * testsuite/gcc.dg/format/sys_formatter.c: New.

Does not belong in gcc/; you appear to have a properly located ChangeLog 
entry for this file below.

> @@ -1776,7 +1782,22 @@ check_format_info_main (format_check_res
>        if (fli)
>  	{
>  	  while (fli->name != 0 && fli->name[0] != *format_chars)
> -	    fli++;
> +	    {
> +	      if (fli->name[0] == '\0')
[...]

If this patch chunk is changing the meaning of some structure in 
c-format.h, the comments on that structure need updating to describe the 
new semantics implemented by this new code.

> +/* Description of gnu specific format attributes reflected to
> +   system format attribute types, as printf, scanf, strftime, and
> +   strfmon.  */

Not clear English, especially "reflected".  I think something like

/* Attributes such as "printf" are equivalent to those such as
   "gnu_printf" unless this is overridden by a target.  */

would be a clearer description of the purpose of this array.

> +const target_ovr_attr gnu_target_overrides_format_attributes[] =

I think this can be static.

> +/* Translate to unified attribute name. This is used in decode_format_type and
> +   decode_format_attr. In attr_name the user specified argument is passed. It
> +   returns the unified formatter name from TARGET_OVERRIDES_FORMAT_ATTRIBUTES
> +   or the attr_name passed to this function, if there is no matching entry.  */
> +static const char *
> +replace_formatter_name_to_system_name (const char *attr_name)

"replace ... to" isn't idiomatic English; "convert" might be better than 
"replace" here.

> +/* A helper function to compare the target override format attribute tattr_name
> +   and the user format attribute attr_name. The underscore variant of attr_name
> +   is ignore for compare. I returns for equal attribute the value one, otherwise
> +   zero.  */

/* Return true if TATTR_NAME and ATTR_NAME are the same format attribute,
   counting "name" and "__name__" as the same, false otherwise.  */

> +static int

Should return bool rather than int.

> +/* For none gnu style formatter types we need to compare the none gnu formatter
> +   and a gnu style formatter style to compare in kind.   This is done via the
> +   array TARGET_OVERRIDES_FORMAT_ATTRIBUTES.  The argument custom_type specifiers
> +   the index of the formatter. The argument def_type specifies the gnu style
> +   formatter index to be compare with. If the kind is equal it returns true,
> +   otherwise false.  */
> +static int

What should this return for comparing each pair of strftime, gnu_strftime, 
ms_strftime?  I can't tell from the comment.

Actually, I don't think we need this function.  The comparisons against 
specific types that you change to call this function are used for two 
things: processing GCC-internal formats, and giving the error "strftime 
formats cannot format arguments".  For the former, there will be no 
target-specific variants; these formats are the same everywhere.  For the 
latter, it would be better to replace the hardcoded check for 
strftime_format_type with a check for the format not setting 
FMT_FLAG_ARG_CONVERT in its flags; that's the right condition to check.  
The diagnostic should name the particular attribute in use, whether 
"strftime", "gnu_strftime" or "ms_strftime" (that is, the attribute in the 
user's source code, not any translated version of it).

> +/* Structure describing the target specific to be override formatter
> +   attributes, e.g. printf, scanf, etc.  This allows to support different
> +   runtime-library specific formatter attributes to co-exist and defining
> +   a default system version.
> +   This type is used for the pointer variable TARGET_OVERRIDES_FORMAT_ATTRIBUTES
> +   refers to.  */

/* Structure describing how format attributes such as "printf" are
   interpreted as "gnu_printf" or "ms_printf" on a particular system.
   TARGET_OVERRIDES_FORMAT_ATTRIBUTES is used to specify target-specific
   defaults.  */

> +/* Be aware to keep these values in synch with enum format_type from c-format.c.  */

Perhaps that enum should simply move to this header and avoid the separate 
list?

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf        formatters to c-format.c
  2008-02-01 15:52   ` Joseph S. Myers
@ 2008-02-04 14:23     ` Kai Tietz
  2008-02-13 18:32       ` Joseph S. Myers
  2008-02-13 21:27       ` Danny Smith
  0 siblings, 2 replies; 61+ messages in thread
From: Kai Tietz @ 2008-02-04 14:23 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: Danny Smith, GCC Patches, NightStrike

[-- Attachment #1: Type: text/plain, Size: 6510 bytes --]

"Joseph S. Myers" <joseph@codesourcery.com> wrote on 01.02.2008 16:52:27:

> On Fri, 1 Feb 2008, Kai Tietz wrote:
> 
> > For the testcases c90-scanf-4.c and c90-printf-3.c may it would be 
better 
> > to avoid their build for mingw targets at all. So how can I specify 
not to 
> > run a test far a specific target?
> 
> See the documentation of selector expressions in doc/sourcebuild.texi. 
> But you could also only add the attributes conditionally:
> 
> #if (existing condition for only adding attributes in tests on Windows)
> #if !defined __STRICT_ANSI__ || __STDC_VERSION__ >= 199901L
> /* Can add attributes to C99 functions.  */
> #endif
> #endif

Thank you for your advice. May just by consistancy we should'nt declare 
C99 functions for c90 in format.h. But the %Y is not present for mingw at 
all. Therefore I prefer to disable them for these targets completely.

The ChangeLog so far:

2008-02-04      Kai Tietz  <kai.tietz@onevision.com>

        * c-format.c: (replace_formatter_name_to_system_name): New.
        (cmp_formatter_kind): New.
        (cmp_attribs): New.
        (replace_formatter_name_to_system_name): New.
        (decode_format_attr): Use of 
replace_formatter_name_to_system_name.
        (format_types_orig): Add gnu_ prefix to names.
        (check_format_info_main): Special treating of \0 escaped names for
        supporting multi-character formatters as I32, I64.
        (TARGET_OVERRIDES_FORMAT_ATTRIBUTES): Use of user defined 
attributes.
        (gnu_target_overrides_format_attributes): New.
        * gcc/c-format.h: Add structure target_ovr_attr to hold
        system specific formatter names.
        * config.gcc: Add for x86&x86_64 cygwin and mingw32 targets the
        msformat-c.o file to c_target_objs and cxx_target_objs.
        * config/i386/mingw32.h: (TARGET_OVERRIDES_FORMAT_ATTRIBUTES): 
New.
        (TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT): New.
        (TARGET_N_FORMAT_TYPES): New.
        * config/i386/msformat-c.c: New.
        * config/i386/t-cygming: Add build rule for msformat-c.o.
        * doc/extend.texi: Add new format names gnu_* and ms_*.
        * doc/tm.texi: (TARGET_OVERRIDES_FORMAT_ATTRIBUTES): New.
        * testsuite/gcc.dg/format/sys_formatter.c: New.

ChangeLog for gcc/testcase

2008-02-04  Kai Tietz  <kai.tietz@onevision.com>

        * gcc.dg/format/ms_array-1.c: New.
        * gcc.dg/format/ms_c90-scanf-3.c: New.
        * gcc.dg/format/ms_c99-strftime-1.c: New.
        * gcc.dg/format/ms_no-y2k-1.c: New.
        * gcc.dg/format/ms_attr-1.c: New.
        * gcc.dg/format/ms_c90-scanf-4.c: New.
        * gcc.dg/format/ms_c99-strftime-2.c: New.
        * gcc.dg/format/ms_nonlit-1.c: New.
        * gcc.dg/format/ms_c90-scanf-5.c: New.
        * gcc.dg/format/ms_cast-1.c: New.
        * gcc.dg/format/ms_nonlit-2.c: New.
        * gcc.dg/format/ms_attr-2.c: New.
        * gcc.dg/format/ms_c90-strftime-1.c: New.
        * gcc.dg/format/ms_miss-1.c: New.
        * gcc.dg/format/ms_nonlit-3.c: New.
        * gcc.dg/format/ms_attr-3.c: New.
        * gcc.dg/format/ms_c90-strftime-2.c: New.
        * gcc.dg/format/ms_miss-2.c: New.
        * gcc.dg/format/ms_nul-1.c: New.
        * gcc.dg/format/ms_attr-4.c: New.
        * gcc.dg/format/ms_c94-printf-1.c: New.
        * gcc.dg/format/ms_miss-3.c: New.
        * gcc.dg/format/ms_nul-2.c: New.
        * gcc.dg/format/ms_attr-7.c: New.
        * gcc.dg/format/ms_c94-scanf-1.c: New.
        * gcc.dg/format/ms_miss-4.c: New.
        * gcc.dg/format/ms_null-1.c: New.
        * gcc.dg/format/ms_bitfld-1.c: New.
        * gcc.dg/format/ms_c99-printf-1.c: New.
        * gcc.dg/format/ms_miss-5.c: New.
        * gcc.dg/format/ms_plus-1.c: New.
        * gcc.dg/format/ms_branch-1.c: New.
        * gcc.dg/format/ms_c99-printf-2.c: New.
        * gcc.dg/format/ms_miss-6.c: New.
        * gcc.dg/format/ms_sec-1.c: New.
        * gcc.dg/format/ms_c90-printf-1.c: New.
        * gcc.dg/format/ms_c99-printf-3.c: New.
        * gcc.dg/format/ms_multattr-1.c: New.
        * gcc.dg/format/ms_unnamed-1.c: New.
        * gcc.dg/format/ms_c90-printf-2.c: New.
        * gcc.dg/format/ms_c99-scanf-1.c: New.
        * gcc.dg/format/ms_multattr-2.c: New.
        * gcc.dg/format/ms_va-1.c: New.
        * gcc.dg/format/ms_c90-printf-3.c: New.
        * gcc.dg/format/ms_c99-scanf-2.c: New.
        * gcc.dg/format/ms_multattr-3.c: New.
        * gcc.dg/format/ms_warnll-1.c: New.
        * gcc.dg/format/ms_c90-scanf-1.c: New.
        * gcc.dg/format/ms_c99-scanf-3.c: New.
        * gcc.dg/format/ms_no-exargs-1.c: New.
        * gcc.dg/format/ms_zero-length-1.c: New.
        * gcc.dg/format/ms_c90-scanf-2.c: New.
        * gcc.dg/format/ms_c99-scanf-4.c: New.
        * gcc.dg/format/ms_no-exargs-2.c: New.
        * gcc.dg/format/sys_formatter.c: New.
        * gcc.dg/format/null-1.c: Add gnu style usage for mingw.
        * gcc.dg/format/miss-1.c: Likewise.
        * gcc.dg/format/miss-3.c: Likewise.
        * gcc.dg/format/multattr-2.c: Likewise.
        * gcc.dg/format/miss-5.c: Likewise.
        * gcc.dg/format/attr-2.c: Likewise.
        * gcc.dg/format/attr-4.c: Likewise.
        * gcc.dg/format/c90-scanf-4.c: Likewise.
        * gcc.dg/format/c99-printf-3.c: Likewise.
        * gcc.dg/format/multattr-1.c: Likewise.
        * gcc.dg/format/miss-4.c: Likewise.
        * gcc.dg/format/miss-6.c: Likewise.
        * gcc.dg/format/c90-printf-3.c: Likewise.
        * gcc.dg/format/attr-1.c: Likewise.
        * gcc.dg/format/attr-3.c: Likewise.
        * gcc.dg/format/attr-7.c: Likewise.
        * gcc.dg/format/format.h: Treat mingw and gnu style.





Regards,
 i.A. Kai Tietz

|  (\_/)  This is Bunny. Copy and paste Bunny
| (='.'=) into your signature to help him gain
| (")_(") world domination.

------------------------------------------------------------------------------------------
  OneVision Software Entwicklungs GmbH & Co. KG
  Dr.-Leo-Ritter-Straße 9 - 93049 Regensburg
  Tel: +49.(0)941.78004.0 - Fax: +49.(0)941.78004.489 - www.OneVision.com
  Commerzbank Regensburg - BLZ 750 400 62 - Konto 6011050
  Handelsregister: HRA 6744, Amtsgericht Regensburg
  Komplementärin: OneVision Software Entwicklungs Verwaltungs GmbH
  Dr.-Leo-Ritter-Straße 9 – 93049 Regensburg
  Handelsregister: HRB 8932, Amtsgericht Regensburg - Geschäftsführer: 
Ulrike Döhler, Manuela Kluger


[-- Attachment #2: mingw-msformat.txt --]
[-- Type: text/plain, Size: 160577 bytes --]

Index: gcc/gcc/c-format.c
===================================================================
--- gcc.orig/gcc/c-format.c
+++ gcc/gcc/c-format.c
@@ -74,13 +74,15 @@ typedef struct function_format_info
 
 static bool decode_format_attr (tree, function_format_info *, int);
 static int decode_format_type (const char *);
+static int cmp_formatter_kind (int ctype, int def_type);
 
 static bool check_format_string (tree argument,
 				 unsigned HOST_WIDE_INT format_num,
 				 int flags, bool *no_add_attrs);
 static bool get_constant (tree expr, unsigned HOST_WIDE_INT *value,
 			  int validated_p);
-
+static const char *replace_formatter_name_to_system_name (const char *attr_name);
+static int cmp_attribs (const char *tattr_name, const char *attr_name);
 
 /* Handle a "format_arg" attribute; arguments as in
    struct attribute_spec.handler.  */
@@ -191,6 +193,8 @@ decode_format_attr (tree args, function_
     {
       const char *p = IDENTIFIER_POINTER (format_type_id);
 
+      p = replace_formatter_name_to_system_name (p);
+
       info->format_type = decode_format_type (p);
 
       if (info->format_type == format_type_error)
@@ -715,7 +719,7 @@ static const format_char_info monetary_c
 /* This must be in the same order as enum format_type.  */
 static const format_kind_info format_types_orig[] =
 {
-  { "printf",   printf_length_specs,  print_char_table, " +#0-'I", NULL,
+  { "gnu_printf",   printf_length_specs,  print_char_table, " +#0-'I", NULL,
     printf_flag_specs, printf_flag_pairs,
     FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
     'w', 0, 'p', 0, 'L', 0,
@@ -757,18 +761,18 @@ static const format_kind_info format_typ
     0, 0, 0, 0, 0, 0,
     NULL, NULL
   },
-  { "scanf",    scanf_length_specs,   scan_char_table,  "*'I", NULL,
+  { "gnu_scanf",    scanf_length_specs,   scan_char_table,  "*'I", NULL,
     scanf_flag_specs, scanf_flag_pairs,
     FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
     'w', 0, 0, '*', 'L', 'm',
     NULL, NULL
   },
-  { "strftime", NULL,                 time_char_table,  "_-0^#", "EO",
+  { "gnu_strftime", NULL,                 time_char_table,  "_-0^#", "EO",
     strftime_flag_specs, strftime_flag_pairs,
     FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0, 0,
     NULL, NULL
   },
-  { "strfmon",  strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
+  { "gnu_strfmon",  strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
     strfmon_flag_specs, strfmon_flag_pairs,
     FMT_FLAG_ARG_CONVERT, 'w', '#', 'p', 0, 'L', 0,
     NULL, NULL
@@ -847,6 +851,8 @@ decode_format_type (const char *s)
 {
   int i;
   int slen;
+
+  s = replace_formatter_name_to_system_name (s);
   slen = strlen (s);
   for (i = 0; i < n_format_types; i++)
     {
@@ -1776,7 +1782,22 @@ check_format_info_main (format_check_res
       if (fli)
 	{
 	  while (fli->name != 0 && fli->name[0] != *format_chars)
-	    fli++;
+	    {
+	      if (fli->name[0] == '\0')
+		{
+		  int si  = strlen (fli->name + 1) + 1;
+		  int i = 1;
+		  while (fli->name[i] != 0 && fli->name[i] == format_chars [i - 1])
+		    ++i;
+		 if (si == i)
+		   {
+		     if (si > 2)
+		       format_chars += si - 2;
+		     break;
+		   }
+	       }
+	      fli++;
+	    }
 	  if (fli->name != 0)
 	    {
 	      format_chars++;
@@ -2703,6 +2724,84 @@ init_dynamic_diag_info (void)
 extern const format_kind_info TARGET_FORMAT_TYPES[];
 #endif
 
+#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+extern const target_ovr_attr TARGET_OVERRIDES_FORMAT_ATTRIBUTES[];
+#endif
+
+/* Description of gnu specific format attributes reflected to
+   system format attribute types, as printf, scanf, strftime, and
+   strfmon.  */
+const target_ovr_attr gnu_target_overrides_format_attributes[] =
+{
+  { "gnu_printf",   "printf", ovr_printf_format_type },
+  { "gnu_scanf",    "scanf", ovr_scanf_format_type },
+  { "gnu_strftime", "strftime", ovr_strftime_format_type },
+  { "gnu_strfmon",  "strfmon", ovr_strfmon_format_type },
+  { NULL,           NULL, -1 }
+};
+
+/* Translate to unified attribute name. This is used in decode_format_type and
+   decode_format_attr. In attr_name the user specified argument is passed. It
+   returns the unified formatter name from TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+   or the attr_name passed to this function, if there is no matching entry.  */
+static const char *
+replace_formatter_name_to_system_name (const char *attr_name)
+{
+  int i;
+
+  if (attr_name == NULL || *attr_name == 0 || strncmp (attr_name, "gcc_", 4) == 0)
+    return attr_name;
+
+#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+  /* Check if format attribute is overridden by target.  */
+  if (TARGET_OVERRIDES_FORMAT_ATTRIBUTES != NULL
+      && TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT > 0)
+    {
+      for (i = 0; i < TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT; ++i)
+        {
+          if (cmp_attribs (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src,
+			   attr_name))
+            return attr_name;
+          if (cmp_attribs (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_dst,
+			   attr_name))
+            return TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src;
+        }
+    }
+#endif
+  /* Otherwise default to gnu formatter.  */
+  for (i = 0; gnu_target_overrides_format_attributes[i].named_attr_src != NULL; ++i)
+    {
+      if (cmp_attribs (gnu_target_overrides_format_attributes[i].named_attr_src,
+		       attr_name))
+        return attr_name;
+      if (cmp_attribs (gnu_target_overrides_format_attributes[i].named_attr_dst,
+		       attr_name))
+        return gnu_target_overrides_format_attributes[i].named_attr_src;
+    }
+
+  return attr_name;
+}
+
+/* A helper function to compare the target override format attribute tattr_name
+   and the user format attribute attr_name. The underscore variant of attr_name
+   is ignore for compare. I returns for equal attribute the value one, otherwise
+   zero.  */
+static int
+cmp_attribs (const char *tattr_name, const char *attr_name)
+{
+  int alen = strlen (attr_name);
+  int slen = (tattr_name ? strlen (tattr_name) : 0);
+  if (alen > 4 && attr_name[0] == '_' && attr_name[1] == '_'
+      && attr_name[alen - 1] == '_' && attr_name[alen - 2] == '_')
+    {
+      attr_name += 2;
+      alen -= 4;
+    }
+  if (alen != slen || strncmp (tattr_name, attr_name, alen) != 0)
+    return 0;
+  return 1;
+}
+
 /* Handle a "format" attribute; arguments as in
    struct attribute_spec.handler.  */
 tree
@@ -2762,7 +2861,7 @@ handle_format_attribute (tree *node, tre
 	}
     }
 
-  if (info.format_type == strftime_format_type && info.first_arg_num != 0)
+  if (cmp_formatter_kind (info.format_type, strftime_format_type) && info.first_arg_num != 0)
     {
       error ("strftime formats cannot format arguments");
       *no_add_attrs = true;
@@ -2771,12 +2870,12 @@ handle_format_attribute (tree *node, tre
 
   /* If this is a custom GCC-internal format type, we have to
      initialize certain bits a runtime.  */
-  if (info.format_type == asm_fprintf_format_type
-      || info.format_type == gcc_gfc_format_type
-      || info.format_type == gcc_diag_format_type
-      || info.format_type == gcc_tdiag_format_type
-      || info.format_type == gcc_cdiag_format_type
-      || info.format_type == gcc_cxxdiag_format_type)
+  if (cmp_formatter_kind (info.format_type, asm_fprintf_format_type)
+      || cmp_formatter_kind (info.format_type, gcc_gfc_format_type)
+      || cmp_formatter_kind (info.format_type, gcc_diag_format_type)
+      || cmp_formatter_kind (info.format_type, gcc_tdiag_format_type)
+      || cmp_formatter_kind (info.format_type, gcc_cdiag_format_type)
+      || cmp_formatter_kind (info.format_type, gcc_cxxdiag_format_type))
     {
       /* Our first time through, we have to make sure that our
 	 format_type data is allocated dynamically and is modifiable.  */
@@ -2787,18 +2886,18 @@ handle_format_attribute (tree *node, tre
 
       /* If this is format __asm_fprintf__, we have to initialize
 	 GCC's notion of HOST_WIDE_INT for checking %wd.  */
-      if (info.format_type == asm_fprintf_format_type)
+      if (cmp_formatter_kind (info.format_type, asm_fprintf_format_type))
 	init_dynamic_asm_fprintf_info ();
       /* If this is format __gcc_gfc__, we have to initialize GCC's
 	 notion of 'locus' at runtime for %L.  */
-      else if (info.format_type == gcc_gfc_format_type)
+      else if (cmp_formatter_kind (info.format_type, gcc_gfc_format_type))
 	init_dynamic_gfc_info ();
       /* If this is one of the diagnostic attributes, then we have to
 	 initialize 'location_t' and 'tree' at runtime.  */
-      else if (info.format_type == gcc_diag_format_type
-	       || info.format_type == gcc_tdiag_format_type
-	       || info.format_type == gcc_cdiag_format_type
-	       || info.format_type == gcc_cxxdiag_format_type)
+      else if (cmp_formatter_kind (info.format_type, gcc_diag_format_type)
+	       || cmp_formatter_kind (info.format_type, gcc_tdiag_format_type)
+	       || cmp_formatter_kind (info.format_type, gcc_cdiag_format_type)
+	       || cmp_formatter_kind (info.format_type, gcc_cxxdiag_format_type))
 	init_dynamic_diag_info ();
       else
 	gcc_unreachable ();
@@ -2806,3 +2905,45 @@ handle_format_attribute (tree *node, tre
 
   return NULL_TREE;
 }
+
+/* For none gnu style formatter types we need to compare the none gnu formatter
+   and a gnu style formatter style to compare in kind.   This is done via the
+   array TARGET_OVERRIDES_FORMAT_ATTRIBUTES.  The argument custom_type specifiers
+   the index of the formatter. The argument def_type specifies the gnu style
+   formatter index to be compare with. If the kind is equal it returns true,
+   otherwise false.  */
+static int
+cmp_formatter_kind (int custom_type, int def_type)
+{
+  int i;
+  int n_format_types_org = ARRAY_SIZE (format_types_orig);
+  const char *name_custom = NULL;
+  if (custom_type < n_format_types_org)
+    return custom_type == def_type;
+#ifdef TARGET_FORMAT_TYPES
+  if (TARGET_N_FORMAT_TYPES <= 0
+      || ((custom_type - n_format_types_org) >= TARGET_N_FORMAT_TYPES))
+    return custom_type == def_type;
+
+  name_custom = TARGET_FORMAT_TYPES[custom_type - n_format_types_org].name;
+
+#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+  /* Check if format attribute is overridden by target.  */
+  if (TARGET_OVERRIDES_FORMAT_ATTRIBUTES != NULL
+      && TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT > 0)
+    {
+      for (i = 0; i < TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT; ++i)
+        {
+          if (cmp_attribs (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src,
+                           name_custom))
+            {
+	      custom_type = TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_type;
+	      break;
+	    }
+        }
+    }
+#endif
+
+#endif
+  return custom_type == def_type;
+}
Index: gcc/gcc/c-format.h
===================================================================
--- gcc.orig/gcc/c-format.h
+++ gcc/gcc/c-format.h
@@ -306,4 +306,28 @@ typedef struct
 #define T_D128  &dfloat128_type_node
 #define TEX_D128 { STD_EXT, "_Decimal128", T_D128 }
 
+/* Structure describing the target specific to be override formatter
+   attributes, e.g. printf, scanf, etc.  This allows to support different
+   runtime-library specific formatter attributes to co-exist and defining
+   a default system version.
+   This type is used for the pointer variable TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+   refers to.  */
+typedef struct
+{
+  /* The name of the to be copied formatter attribute. */
+  const char *named_attr_src;
+  /* The name of the to be overridden formatter attribute. */
+  const char *named_attr_dst;
+  /* Values of enum ovr_format_type.  */
+  int named_attr_type;
+} target_ovr_attr;
+
+/* Be aware to keep these values in synch with enum format_type from c-format.c.  */
+enum ovr_format_type { ovr_printf_format_type, ovr_asm_fprintf_format_type,
+		   ovr_gcc_diag_format_type, ovr_gcc_tdiag_format_type,
+		   ovr_gcc_cdiag_format_type,
+		   ovr_gcc_cxxdiag_format_type, ovr_gcc_gfc_format_type,
+		   ovr_scanf_format_type, ovr_strftime_format_type,
+		   ovr_strfmon_format_type, ovr_format_type_error = -1};
+
 #endif /* GCC_C_FORMAT_H */
Index: gcc/gcc/config.gcc
===================================================================
--- gcc.orig/gcc/config.gcc
+++ gcc/gcc/config.gcc
@@ -1365,8 +1365,8 @@ i[34567]86-*-pe | i[34567]86-*-cygwin*)
 	target_gtfiles="\$(srcdir)/config/i386/winnt.c"
 	extra_options="${extra_options} i386/cygming.opt"
 	extra_objs="winnt.o winnt-stubs.o"
-	c_target_objs=cygwin2.o
-	cxx_target_objs="cygwin2.o winnt-cxx.o"
+	c_target_objs="cygwin2.o msformat-c.o"
+	cxx_target_objs="cygwin2.o winnt-cxx.o msformat-c.o"
 	extra_gcc_objs=cygwin1.o
 	if test x$enable_threads = xyes; then
 		thread_file='posix'
@@ -1379,7 +1379,8 @@ i[34567]86-*-mingw32* | x86_64-*-mingw32
 	target_gtfiles="\$(srcdir)/config/i386/winnt.c"
 	extra_options="${extra_options} i386/cygming.opt"
 	extra_objs="winnt.o winnt-stubs.o"
-	cxx_target_objs=winnt-cxx.o
+	c_target_objs="msformat-c.o"
+	cxx_target_objs="winnt-cxx.o msformat-c.o"
 	default_use_cxa_atexit=yes
 	case ${enable_threads} in
 	  "" | yes | win32)
Index: gcc/gcc/config/i386/mingw32.h
===================================================================
--- gcc.orig/gcc/config/i386/mingw32.h
+++ gcc/gcc/config/i386/mingw32.h
@@ -143,6 +143,22 @@ do {						         \
    to register C++ static destructors.  */
 #define TARGET_CXX_USE_ATEXIT_FOR_CXA_ATEXIT hook_bool_void_true
 
+/* Contains a pointer to type target_ovr_attr defining the target specific
+   overrides of formatter attributs.  See format.h for structure definition.  */
+#undef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+#define TARGET_OVERRIDES_FORMAT_ATTRIBUTES mingw_formatter_attribute_overrides
+
+/* Specify the count of elements in TARGET_OVERRIDES_ATTRIBUTE.  */
+#undef TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT
+#define TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT 3
+
+/* MS specific format attributes for ms_printf, ms_scanf, ms_strftime.  */
+#undef TARGET_FORMAT_TYPES
+#define TARGET_FORMAT_TYPES mingw_formatter_attributes
+
+#undef TARGET_N_FORMAT_TYPES
+#define TARGET_N_FORMAT_TYPES 3
+
 /* JCR_SECTION works on mingw32.  */
 #undef TARGET_USE_JCR_SECTION
 #define TARGET_USE_JCR_SECTION 1
Index: gcc/gcc/config/i386/msformat-c.c
===================================================================
--- /dev/null
+++ gcc/gcc/config/i386/msformat-c.c
@@ -0,0 +1,188 @@
+/* Check calls to formatted I/O functions (-Wformat).
+   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+   2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "flags.h"
+#include "c-common.h"
+#include "toplev.h"
+#include "intl.h"
+#include "diagnostic.h"
+#include "langhooks.h"
+#include "c-format.h"
+#include "alloc-pool.h"
+
+/* Mingw specific format attributes ms_printf, ms_scanf, and ms_strftime.  */
+
+static const format_length_info ms_printf_length_specs[] =
+{
+  { "h", FMT_LEN_h, STD_C89, NULL, 0, 0 },
+  { "l", FMT_LEN_l, STD_C89, NULL, 0, 0 },
+  { "\0I32", FMT_LEN_l, STD_C89, NULL, 0, 0 },
+  { "\0I64", FMT_LEN_ll, STD_C9L, NULL, 0, 0 },
+  { "I", FMT_LEN_L, STD_C89, NULL, 0, 0 },
+  { NULL, 0, 0, NULL, 0, 0 }
+};
+
+static const format_flag_spec ms_printf_flag_specs[] =
+{
+  { ' ',  0, 0, N_("' ' flag"),        N_("the ' ' printf flag"),              STD_C89 },
+  { '+',  0, 0, N_("'+' flag"),        N_("the '+' printf flag"),              STD_C89 },
+  { '#',  0, 0, N_("'#' flag"),        N_("the '#' printf flag"),              STD_C89 },
+  { '0',  0, 0, N_("'0' flag"),        N_("the '0' printf flag"),              STD_C89 },
+  { '-',  0, 0, N_("'-' flag"),        N_("the '-' printf flag"),              STD_C89 },
+  { '\'', 0, 0, N_("''' flag"),        N_("the ''' printf flag"),              STD_EXT },
+  { 'w',  0, 0, N_("field width"),     N_("field width in printf format"),     STD_C89 },
+  { 'p',  0, 0, N_("precision"),       N_("precision in printf format"),       STD_C89 },
+  { 'L',  0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_printf_flag_pairs[] =
+{
+  { ' ', '+', 1, 0   },
+  { '0', '-', 1, 0   }, { '0', 'p', 1, 'i' },
+  { 0, 0, 0, 0 }
+};
+
+static const format_flag_spec ms_scanf_flag_specs[] =
+{
+  { '*',  0, 0, N_("assignment suppression"), N_("the assignment suppression scanf feature"), STD_C89 },
+  { 'a',  0, 0, N_("'a' flag"),               N_("the 'a' scanf flag"),                       STD_EXT },
+  { 'w',  0, 0, N_("field width"),            N_("field width in scanf format"),              STD_C89 },
+  { 'L',  0, 0, N_("length modifier"),        N_("length modifier in scanf format"),          STD_C89 },
+  { '\'', 0, 0, N_("''' flag"),               N_("the ''' scanf flag"),                       STD_EXT },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_scanf_flag_pairs[] =
+{
+  { '*', 'L', 0, 0 },
+  { 0, 0, 0, 0 }
+};
+
+static const format_flag_spec ms_strftime_flag_specs[] =
+{
+  { '_', 0,   0, N_("'_' flag"),     N_("the '_' strftime flag"),          STD_EXT },
+  { '-', 0,   0, N_("'-' flag"),     N_("the '-' strftime flag"),          STD_EXT },
+  { '0', 0,   0, N_("'0' flag"),     N_("the '0' strftime flag"),          STD_EXT },
+  { '^', 0,   0, N_("'^' flag"),     N_("the '^' strftime flag"),          STD_EXT },
+  { '#', 0,   0, N_("'#' flag"),     N_("the '#' strftime flag"),          STD_EXT },
+  { 'w', 0,   0, N_("field width"),  N_("field width in strftime format"), STD_EXT },
+  { 'E', 0,   0, N_("'E' modifier"), N_("the 'E' strftime modifier"),      STD_C99 },
+  { 'O', 0,   0, N_("'O' modifier"), N_("the 'O' strftime modifier"),      STD_C99 },
+  { 'O', 'o', 0, NULL,               N_("the 'O' modifier"),               STD_EXT },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_strftime_flag_pairs[] =
+{
+  { 'E', 'O', 0, 0 },
+  { '_', '-', 0, 0 },
+  { '_', '0', 0, 0 },
+  { '-', '0', 0, 0 },
+  { '^', '#', 0, 0 },
+  { 0, 0, 0, 0 }
+};
+
+static const format_char_info ms_print_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "di",  0, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  T99_SST,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-wp0 +'",  "i",  NULL },
+  { "oxX", 0, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN, BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "-wp0#",     "i",  NULL },
+  { "u",   0, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN, BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "-wp0'",    "i",  NULL },
+  { "fgG", 0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "-wp0 +#'", "",   NULL },
+  { "eE",  0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "-wp0 +#",  "",   NULL },
+  { "c",   0, STD_C89, { T89_I,   BADLEN,  T89_S,  T94_WI,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "",   NULL },
+  { "s",   1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-wp",       "cR", NULL },
+  { "p",   1, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "c",  NULL },
+  { "n",   1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  BADLEN,  BADLEN, BADLEN,  T99_IM,  BADLEN,  BADLEN,  BADLEN }, "",          "W",  NULL },
+  /* X/Open conversion specifiers.  */
+  { "C",   0, STD_EXT, { TEX_WI,  BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "",   NULL },
+  { "S",   1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-wp",       "R",  NULL },
+  { NULL,  0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+static const format_char_info ms_scan_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "di",    1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  T99_SST,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w'", "W",   NULL },
+  { "u",     1, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN,  BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "*w'", "W",   NULL },
+  { "oxX",   1, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN,  BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "efgEG", 1, STD_C89, { T89_F,   BADLEN,  BADLEN,  T89_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "*w'",  "W",   NULL },
+  { "c",     1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "cW",  NULL },
+  { "s",     1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "cW",  NULL },
+  { "[",     1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "cW[", NULL },
+  { "p",     2, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "n",     1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  BADLEN,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "",     "W",   NULL },
+  /* X/Open conversion specifiers.  */
+  { "C",     1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "S",     1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "W",   NULL },
+  { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+static const format_char_info ms_time_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "ABZab",		0, STD_C89, NOLENGTHS, "^#",     "",   NULL },
+  { "cx",		0, STD_C89, NOLENGTHS, "E",      "3",  NULL },
+  { "HIMSUWdmw",	0, STD_C89, NOLENGTHS, "-_0Ow",  "",   NULL },
+  { "j",		0, STD_C89, NOLENGTHS, "-_0Ow",  "o",  NULL },
+  { "p",		0, STD_C89, NOLENGTHS, "#",      "",   NULL },
+  { "X",		0, STD_C89, NOLENGTHS, "E",      "",   NULL },
+  { "y",		0, STD_C89, NOLENGTHS, "EO-_0w", "4",  NULL },
+  { "Y",		0, STD_C89, NOLENGTHS, "-_0EOw", "o",  NULL },
+  { "%",		0, STD_C89, NOLENGTHS, "",       "",   NULL },
+  /* C99 conversion specifiers.  */
+  { "z",		0, STD_C99, NOLENGTHS, "O",      "o",  NULL },
+  { NULL,		0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+const format_kind_info mingw_formatter_attributes[3] =
+{
+  { "ms_printf",   ms_printf_length_specs,  ms_print_char_table, " +#0-'", NULL,
+    ms_printf_flag_specs, ms_printf_flag_pairs,
+    FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
+    'w', 0, 'p', 0, 'L', 0,
+    &integer_type_node, &integer_type_node
+  },
+  { "ms_scanf",    ms_printf_length_specs,   ms_scan_char_table,  "*'", NULL,
+    ms_scanf_flag_specs, ms_scanf_flag_pairs,
+    FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
+    'w', 0, 0, '*', 'L', 0,
+    NULL, NULL
+  },
+  { "ms_strftime", NULL,                 ms_time_char_table,  "_-0^#", "EO",
+    ms_strftime_flag_specs, ms_strftime_flag_pairs,
+    FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0, 0,
+    NULL, NULL
+  }
+};
+
+/* Default overrides for printf, scanf and strftime.  */
+const target_ovr_attr mingw_formatter_attribute_overrides[4] =
+{
+  { "ms_printf", "printf", ovr_printf_format_type },
+  { "ms_scanf", "scanf", ovr_scanf_format_type },
+  { "ms_strftime", "strftime", ovr_strftime_format_type }
+};
Index: gcc/gcc/config/i386/t-cygming
===================================================================
--- gcc.orig/gcc/config/i386/t-cygming
+++ gcc/gcc/config/i386/t-cygming
@@ -29,4 +29,10 @@ winnt-stubs.o: $(srcdir)/config/i386/win
 	$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
 	$(srcdir)/config/i386/winnt-stubs.c
 
+msformat-c.o: $(srcdir)/config/i386/msformat-c.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
+  $(TM_H) $(RTL_H) $(REGS_H) hard-reg-set.h output.h $(TREE_H) flags.h \
+  $(TM_P_H) toplev.h $(HASHTAB_H) $(GGC_H)
+	$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
+	$(srcdir)/config/i386/msformat-c.c
+
 STMP_FIXINC=stmp-fixinc
Index: gcc/gcc/doc/extend.texi
===================================================================
--- gcc.orig/gcc/doc/extend.texi
+++ gcc/gcc/doc/extend.texi
@@ -2204,13 +2204,17 @@ for consistency with the @code{printf} s
 @code{my_format}.
 
 The parameter @var{archetype} determines how the format string is
-interpreted, and should be @code{printf}, @code{scanf}, @code{strftime}
-or @code{strfmon}.  (You can also use @code{__printf__},
-@code{__scanf__}, @code{__strftime__} or @code{__strfmon__}.)  The
-parameter @var{string-index} specifies which argument is the format
-string argument (starting from 1), while @var{first-to-check} is the
-number of the first argument to check against the format string.  For
-functions where the arguments are not available to be checked (such as
+interpreted, and should be @code{printf}, @code{scanf}, @code{strftime},
+@code{gnu_printf}, @code{gnu_scanf}, @code{gnu_strftime} or
+@code{strfmon}.  (You can also use @code{__printf__},
+@code{__scanf__}, @code{__strftime__} or @code{__strfmon__}.)  On
+mingw targets there is also @code{ms_printf}, @code{ms_scanf}, and
+@code{ms_strftime} present. The none target specific formatters are
+always the variant of the system.  The parameter @var{string-index}
+specifies which argument is the format string argument (starting
+from 1), while @var{first-to-check} is the number of the first
+argument to check against the format string.  For functions
+where the arguments are not available to be checked (such as
 @code{vprintf}), specify the third parameter as zero.  In this case the
 compiler only checks the format string for consistency.  For
 @code{strftime} formats, the third parameter is required to be zero.
Index: gcc/gcc/doc/tm.texi
===================================================================
--- gcc.orig/gcc/doc/tm.texi
+++ gcc/gcc/doc/tm.texi
@@ -10319,6 +10319,18 @@ If defined, this macro is the number of 
 @code{TARGET_FORMAT_TYPES}.
 @end defmac
 
+@defmac TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+If defined, this macro is the name of a global variable containg
+target-specific format overrides for the @option{-Wformat} option. The
+default is to have no target-specific format overrides. If defined,
+@code{TARGET_FORMAT_TYPES} must be defined too.
+@end defmac
+
+@defmac TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT
+If defined, this macro specifies the number of entries in
+@code{TARGET_OVERRIDES_FORMAT_ATTRIBUTES}.
+@end defmac
+
 @deftypefn {Target Hook} bool TARGET_RELAXED_ORDERING
 If set to @code{true}, means that the target's memory model does not
 guarantee that loads which do not depend on one another will access
Index: gcc/gcc/testsuite/gcc.dg/format/sys_formatter.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/sys_formatter.c
@@ -0,0 +1,14 @@
+/* Test system default printf formatter specifiers.  */
+/* Origin: Kai Tietz <KaiTietz.@onevision.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu89" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+__attribute__((format(printf, 1, 2))) void foo (const char *, ...);
+
+void bar (long long v1, long v2, int v3)
+{
+  foo ("%I64d %I32d %ld %d\n", v1, v2, v2, v3);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/format.h
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/format.h
+++ gcc/gcc/testsuite/gcc.dg/format/format.h
@@ -1,6 +1,37 @@
 /* Format checking tests: common header.  */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
 
+/* DONT_GNU_PROTOTYPE */
+#if defined (_WIN32) && !defined (__CYGWIN__)
+#if !defined (USE_SYSTEM_FORMATS)
+#define gnu_attr_printf	gnu_printf
+#define gnu_attr___printf__ __gnu_printf__
+#define gnu_attr_scanf	gnu_scanf
+#define gnu_attr___scanf__ __gnu_scanf__
+#define gnu_attr_strftime gnu_strftime
+#define gnu_attr___strftime__ __gnu_strftime__
+#endif
+#endif
+
+#ifndef gnu_attr_printf
+#define gnu_attr_printf	printf
+#define gnu_attr___printf__ __printf__
+#define gnu_attr_scanf	scanf
+#define gnu_attr___scanf__ __scanf__
+#define gnu_attr_strftime strftime
+#define gnu_attr___strftime__ __strftime__
+#endif
+
+#if !defined (USE_SYSTEM_FORMATS)
+#define USE_PRINTF(FMTPOS, WILDARG) __attribute__((format(gnu_printf, FMTPOS, WILDARG))) __attribute__((nonnull (FMTPOS)))
+#define USE_SCANF(FMTPOS, WILDARG) __attribute__((format(gnu_scanf, FMTPOS, WILDARG))) __attribute__((nonnull (FMTPOS)))
+#define USE_STRFTIME(FMTPOS) __attribute__((__format__(gnu_strftime, FMTPOS, 0))) __attribute__((nonnull (FMTPOS)))
+#else
+#define USE_PRINTF(FMTPOS, WILDARG)
+#define USE_SCANF(FMTPOS, WILDARG)
+#define USE_STRFTIME(FMTPOS)
+#endif
+
 #include <stdarg.h>
 #include <stddef.h>
 
@@ -11,6 +42,20 @@
 typedef __WINT_TYPE__ wint_t;
 #endif
 
+#ifdef _WIN64
+/* Kludges to get types corresponding to size_t and ptrdiff_t.  */
+#define unsigned signed
+typedef signed int signed_size_t __attribute__ ((mode (DI)));
+/* We also use this type to approximate ssize_t.  */
+typedef signed int ssize_t __attribute__ ((mode (DI)));
+#undef unsigned
+#define signed /* Type might or might not have explicit 'signed'.  */
+typedef unsigned int unsigned_ptrdiff_t __attribute__ ((mode (DI)));
+#undef signed
+
+__extension__ typedef int llong  __attribute__ ((mode (DI)));
+__extension__ typedef unsigned int ullong  __attribute__ ((mode (DI)));
+#else
 /* Kludges to get types corresponding to size_t and ptrdiff_t.  */
 #define unsigned signed
 typedef __SIZE_TYPE__ signed_size_t;
@@ -23,6 +68,7 @@ typedef unsigned __PTRDIFF_TYPE__ unsign
 
 __extension__ typedef long long int llong;
 __extension__ typedef unsigned long long int ullong;
+#endif
 
 /* %q formats want a "quad"; GCC considers this to be a long long.  */
 typedef llong quad_t;
@@ -70,3 +116,77 @@ extern size_t strftime (char *restrict, 
 			const struct tm *restrict);
 
 extern ssize_t strfmon (char *restrict, size_t, const char *restrict, ...);
+
+/* Mingw specific part.  */
+#if !defined (USE_SYSTEM_FORMATS) && defined(_WIN32) && !defined(DONT_GNU_PROTOTYPE)
+
+extern USE_PRINTF(2,3) int fprintf_gnu (FILE *restrict, const char *restrict, ...);
+#undef fprintf
+#define fprintf fprintf_gnu
+
+extern USE_PRINTF(1,2) int printf_gnu (const char *restrict, ...);
+#undef printf
+#define printf printf_gnu
+
+extern USE_PRINTF(2,3) int fprintf_unlocked_gnu (FILE *restrict, const char *restrict, ...);
+#undef fprintf_unlocked
+#define fprintf_unlocked fprintf_unlocked_gnu
+
+extern USE_PRINTF(1,2)int printf_unlocked_gnu (const char *restrict, ...);
+#undef printf_unlocked
+#define printf_unlocked printf_unlocked_gnu
+
+extern USE_PRINTF(2,3) int sprintf_gnu (char *restrict, const char *restrict, ...);
+#undef sprintf
+#define sprintf sprintf_gnu
+
+extern USE_PRINTF(2,0) int vfprintf_gnu (FILE *restrict, const char *restrict, va_list);
+#undef vsprintf
+#define vsprintf vsprintf_gnu
+
+extern USE_PRINTF(1,0) int vprintf_gnu (const char *restrict, va_list);
+#undef vprintf
+#define vprintf vprintf_gnu
+
+extern USE_PRINTF(2,0) int vsprintf_gnu (char *restrict, const char *restrict, va_list);
+#undef vsprintf
+#define vsprintf vsprintf_gnu
+
+extern USE_PRINTF(3,4) int snprintf_gnu (char *restrict, size_t, const char *restrict, ...);
+#undef snprintf
+#define snprintf snprintf_gnu
+
+extern USE_PRINTF(3,0) int vsnprintf_gnu (char *restrict, size_t, const char *restrict, va_list);
+#undef vsnprintf
+#define vsnprintf vsnprintf_gnu
+
+extern USE_SCANF(2,3) int fscanf_gnu (FILE *restrict, const char *restrict, ...);
+#undef fscanf
+#define fscanf fscanf_gnu
+
+extern USE_SCANF(1,2) int scanf_gnu (const char *restrict, ...);
+#undef scanf
+#define scanf scanf_gnu
+
+extern USE_SCANF(2,3) int sscanf_gnu (const char *restrict, const char *restrict, ...);
+#undef sscanf
+#define sscanf sscanf_gnu
+
+extern USE_SCANF(2,0) int vfscanf_gnu (FILE *restrict, const char *restrict, va_list);
+#undef vfscanf
+#define vfscanf vfscanf_gnu
+
+extern USE_SCANF(1,0) int vscanf_gnu (const char *restrict, va_list);
+#undef vscanf
+#define vscanf vscanf_gnu
+
+extern USE_SCANF(2,0) int vsscanf_gnu (const char *restrict, const char *restrict, va_list);
+#undef vsscanf
+#define vsscanf vsscanf_gnu
+
+extern USE_STRFTIME(3) size_t strftime_gnu (char *restrict, size_t, const char *restrict,
+			const struct tm *restrict);
+#undef strftime
+#define strftime strftime_gnu
+
+#endif
Index: gcc/gcc/testsuite/gcc.dg/format/attr-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-1.c
@@ -3,7 +3,8 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern void foo0 (const char *) __attribute__((__format__(__strftime__, 1, 0)));
-extern void foo1 (const char *, ...) __attribute__((__format__(__strftime__, 1, 2))); /* { dg-error "cannot format" "strftime first_arg_num != 0" } */
+extern void foo0 (const char *) __attribute__((__format__(gnu_attr___strftime__, 1, 0)));
+extern void foo1 (const char *, ...) __attribute__((__format__(gnu_attr___strftime__, 1, 2))); /* { dg-error "cannot format" "strftime first_arg_num != 0" } */
Index: gcc/gcc/testsuite/gcc.dg/format/attr-2.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-2.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-2.c
@@ -3,22 +3,23 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern void tformatprintf (const char *, ...) __attribute__((format(printf, 1, 2)));
-extern void tformat__printf__ (const char *, ...) __attribute__((format(__printf__, 1, 2)));
-extern void tformatscanf (const char *, ...) __attribute__((format(scanf, 1, 2)));
-extern void tformat__scanf__ (const char *, ...) __attribute__((format(__scanf__, 1, 2)));
-extern void tformatstrftime (const char *) __attribute__((format(strftime, 1, 0)));
-extern void tformat__strftime__ (const char *) __attribute__((format(__strftime__, 1, 0)));
+extern void tformatprintf (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
+extern void tformat__printf__ (const char *, ...) __attribute__((format(gnu_attr___printf__, 1, 2)));
+extern void tformatscanf (const char *, ...) __attribute__((format(gnu_attr_scanf, 1, 2)));
+extern void tformat__scanf__ (const char *, ...) __attribute__((format(gnu_attr___scanf__, 1, 2)));
+extern void tformatstrftime (const char *) __attribute__((format(gnu_attr_strftime, 1, 0)));
+extern void tformat__strftime__ (const char *) __attribute__((format(gnu_attr___strftime__, 1, 0)));
 extern void tformatstrfmon (const char *, ...) __attribute__((format(strfmon, 1, 2)));
 extern void tformat__strfmon__ (const char *, ...) __attribute__((format(__strfmon__, 1, 2)));
-extern void t__format__printf (const char *, ...) __attribute__((__format__(printf, 1, 2)));
-extern void t__format____printf__ (const char *, ...) __attribute__((__format__(__printf__, 1, 2)));
-extern void t__format__scanf (const char *, ...) __attribute__((__format__(scanf, 1, 2)));
-extern void t__format____scanf__ (const char *, ...) __attribute__((__format__(__scanf__, 1, 2)));
-extern void t__format__strftime (const char *) __attribute__((__format__(strftime, 1, 0)));
-extern void t__format____strftime__ (const char *) __attribute__((__format__(__strftime__, 1, 0)));
+extern void t__format__printf (const char *, ...) __attribute__((__format__(gnu_attr_printf, 1, 2)));
+extern void t__format____printf__ (const char *, ...) __attribute__((__format__(gnu_attr___printf__, 1, 2)));
+extern void t__format__scanf (const char *, ...) __attribute__((__format__(gnu_attr_scanf, 1, 2)));
+extern void t__format____scanf__ (const char *, ...) __attribute__((__format__(gnu_attr___scanf__, 1, 2)));
+extern void t__format__strftime (const char *) __attribute__((__format__(gnu_attr_strftime, 1, 0)));
+extern void t__format____strftime__ (const char *) __attribute__((__format__(gnu_attr___strftime__, 1, 0)));
 extern void t__format__strfmon (const char *, ...) __attribute__((__format__(strfmon, 1, 2)));
 extern void t__format____strfmon__ (const char *, ...) __attribute__((__format__(__strfmon__, 1, 2)));
 
Index: gcc/gcc/testsuite/gcc.dg/format/attr-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-3.c
@@ -3,20 +3,21 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 /* Proper uses of the attributes.  */
-extern void fa0 (const char *, ...) __attribute__((format(printf, 1, 2)));
-extern void fa1 (char *, ...) __attribute__((format(printf, 1, 2)));
+extern void fa0 (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
+extern void fa1 (char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
 extern char *fa2 (const char *) __attribute__((format_arg(1)));
 extern char *fa3 (char *) __attribute__((format_arg(1)));
 
 /* Uses with too few or too many arguments.  */
 extern void fb0 (const char *, ...) __attribute__((format)); /* { dg-error "wrong number of arguments" "bad format" } */
 extern void fb1 (const char *, ...) __attribute__((format())); /* { dg-error "wrong number of arguments" "bad format" } */
-extern void fb2 (const char *, ...) __attribute__((format(printf))); /* { dg-error "wrong number of arguments" "bad format" } */
-extern void fb3 (const char *, ...) __attribute__((format(printf, 1))); /* { dg-error "wrong number of arguments" "bad format" } */
-extern void fb4 (const char *, ...) __attribute__((format(printf, 1, 2, 3))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb2 (const char *, ...) __attribute__((format(gnu_attr_printf))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb3 (const char *, ...) __attribute__((format(gnu_attr_printf, 1))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb4 (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2, 3))); /* { dg-error "wrong number of arguments" "bad format" } */
 
 extern void fc1 (const char *) __attribute__((format_arg)); /* { dg-error "wrong number of arguments" "bad format_arg" } */
 extern void fc2 (const char *) __attribute__((format_arg())); /* { dg-error "wrong number of arguments" "bad format_arg" } */
@@ -25,9 +26,9 @@ extern void fc3 (const char *) __attribu
 /* These attributes presently only apply to declarations, not to types.
    Eventually, they should be usable with declarators for function types
    anywhere, but still not with structure/union/enum types.  */
-struct s0 { int i; } __attribute__((format(printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on struct" } */
-union u0 { int i; } __attribute__((format(printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on union" } */
-enum e0 { E0V0 } __attribute__((format(printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on enum" } */
+struct s0 { int i; } __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on struct" } */
+union u0 { int i; } __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on union" } */
+enum e0 { E0V0 } __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on enum" } */
 
 struct s1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on struct" } */
 union u1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on union" } */
@@ -38,28 +39,28 @@ extern void fe0 (const char *, ...) __at
 extern void fe1 (const char *, ...) __attribute__((format(nosuch, 1, 2))); /* { dg-warning "format function type" "unknown format" } */
 
 /* Both the numbers must be integer constant expressions.  */
-extern void ff0 (const char *, ...) __attribute__((format(printf, 3-2, (long long)(10/5))));
+extern void ff0 (const char *, ...) __attribute__((format(gnu_attr_printf, 3-2, (long long)(10/5))));
 int foo;
-extern void ff1 (const char *, ...) __attribute__((format(printf, foo, 10/5))); /* { dg-error "invalid operand" "bad number" } */
-extern void ff2 (const char *, ...) __attribute__((format(printf, 3-2, foo))); /* { dg-error "invalid operand" "bad number" } */
+extern void ff1 (const char *, ...) __attribute__((format(gnu_attr_printf, foo, 10/5))); /* { dg-error "invalid operand" "bad number" } */
+extern void ff2 (const char *, ...) __attribute__((format(gnu_attr_printf, 3-2, foo))); /* { dg-error "invalid operand" "bad number" } */
 extern char *ff3 (const char *) __attribute__((format_arg(3-2)));
 extern char *ff4 (const char *) __attribute__((format_arg(foo))); /* { dg-error "invalid operand" "bad format_arg number" } */
 
 /* The format string argument must precede the arguments to be formatted.
    This includes if no parameter types are specified (which is not valid ISO
    C for variadic functions).  */
-extern void fg0 () __attribute__((format(printf, 1, 2)));
-extern void fg1 () __attribute__((format(printf, 1, 0)));
-extern void fg2 () __attribute__((format(printf, 1, 1))); /* { dg-error "follows" "bad number order" } */
-extern void fg3 () __attribute__((format(printf, 2, 1))); /* { dg-error "follows" "bad number order" } */
+extern void fg0 () __attribute__((format(gnu_attr_printf, 1, 2)));
+extern void fg1 () __attribute__((format(gnu_attr_printf, 1, 0)));
+extern void fg2 () __attribute__((format(gnu_attr_printf, 1, 1))); /* { dg-error "follows" "bad number order" } */
+extern void fg3 () __attribute__((format(gnu_attr_printf, 2, 1))); /* { dg-error "follows" "bad number order" } */
 
 /* The format string argument must be a string type, and the arguments to
    be formatted must be the "...".  */
-extern void fh0 (int, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "not a string" "format int string" } */
-extern void fh1 (signed char *, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "not a string" "signed char string" } */
-extern void fh2 (unsigned char *, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "not a string" "unsigned char string" } */
-extern void fh3 (const char *, ...) __attribute__((format(printf, 1, 3))); /* { dg-error "is not" "not ..." } */
-extern void fh4 (const char *, int, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "is not" "not ..." } */
+extern void fh0 (int, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "format int string" } */
+extern void fh1 (signed char *, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "signed char string" } */
+extern void fh2 (unsigned char *, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "unsigned char string" } */
+extern void fh3 (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 3))); /* { dg-error "is not" "not ..." } */
+extern void fh4 (const char *, int, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "is not" "not ..." } */
 
 /* format_arg formats must take and return a string.  */
 extern char *fi0 (int) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg int string" } */
Index: gcc/gcc/testsuite/gcc.dg/format/attr-4.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-4.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-4.c
@@ -4,12 +4,13 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern __attribute__((format(printf, 1, 2))) void tformatprintf0 (const char *, ...);
-extern void __attribute__((format(printf, 1, 2))) tformatprintf1 (const char *, ...);
-extern void foo (void), __attribute__((format(printf, 1, 2))) tformatprintf2 (const char *, ...);
-extern __attribute__((noreturn)) void bar (void), __attribute__((format(printf, 1, 2))) tformatprintf3 (const char *, ...);
+extern __attribute__((format(gnu_attr_printf, 1, 2))) void tformatprintf0 (const char *, ...);
+extern void __attribute__((format(gnu_attr_printf, 1, 2))) tformatprintf1 (const char *, ...);
+extern void foo (void), __attribute__((format(gnu_attr_printf, 1, 2))) tformatprintf2 (const char *, ...);
+extern __attribute__((noreturn)) void bar (void), __attribute__((format(gnu_attr_printf, 1, 2))) tformatprintf3 (const char *, ...);
 
 void
 baz (int i, int *ip, double d)
Index: gcc/gcc/testsuite/gcc.dg/format/attr-7.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-7.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-7.c
@@ -3,12 +3,13 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-__attribute__((format(printf, 1, 2))) void (*tformatprintf0) (const char *, ...);
-void (*tformatprintf1) (const char *, ...) __attribute__((format(printf, 1, 2)));
-void (__attribute__((format(printf, 1, 2))) *tformatprintf2) (const char *, ...);
-void (__attribute__((format(printf, 1, 2))) ****tformatprintf3) (const char *, ...);
+__attribute__((format(gnu_attr_printf, 1, 2))) void (*tformatprintf0) (const char *, ...);
+void (*tformatprintf1) (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
+void (__attribute__((format(gnu_attr_printf, 1, 2))) *tformatprintf2) (const char *, ...);
+void (__attribute__((format(gnu_attr_printf, 1, 2))) ****tformatprintf3) (const char *, ...);
 
 char * (__attribute__((format_arg(1))) *tformat_arg) (const char *);
 
Index: gcc/gcc/testsuite/gcc.dg/format/c90-printf-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/c90-printf-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/c90-printf-3.c
@@ -3,7 +3,7 @@
    do not.
 */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
-/* { dg-do compile } */
+/* { dg-do compile { target { ! *-*-mingw* } } } */
 /* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
 
 #include "format.h"
Index: gcc/gcc/testsuite/gcc.dg/format/c90-scanf-4.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/c90-scanf-4.c
+++ gcc/gcc/testsuite/gcc.dg/format/c90-scanf-4.c
@@ -3,7 +3,7 @@
    do not.
 */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
-/* { dg-do compile } */
+/* { dg-do compile { target { ! *-*-mingw* } } } */
 /* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
 
 #include "format.h"
Index: gcc/gcc/testsuite/gcc.dg/format/c99-printf-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/c99-printf-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/c99-printf-3.c
@@ -16,8 +16,8 @@ foo (int i, char *s, size_t n, va_list v
   printf ("%d", i);
   printf ("%ld", i); /* { dg-warning "format" "printf" } */
   /* The "unlocked" functions shouldn't warn in c99 mode.  */
-  fprintf_unlocked (stdout, "%ld", i); /* { dg-bogus "format" "fprintf_unlocked" } */
-  printf_unlocked ("%ld", i); /* { dg-bogus "format" "printf_unlocked" } */
+  fprintf_unlocked (stdout, "%ld", i); /* { dg-warning "format" "fprintf_unlocked" } */
+  printf_unlocked ("%ld", i); /* { dg-warning "format" "printf_unlocked" } */
   sprintf (s, "%d", i);
   sprintf (s, "%ld", i); /* { dg-warning "format" "sprintf" } */
   snprintf (s, n, "%d", i);
@@ -31,9 +31,9 @@ foo (int i, char *s, size_t n, va_list v
   vsnprintf (s, n, "%d", v0);
   vsnprintf (s, n, "%Y", v1); /* { dg-warning "format" "vsnprintf" } */
   printf (gettext ("%d"), i);
-  printf (gettext ("%ld"), i);
+  printf (gettext ("%ld"), (long) i);
   printf (dgettext ("", "%d"), i);
-  printf (dgettext ("", "%ld"), i);
+  printf (dgettext ("", "%ld"), (long) i);
   printf (dcgettext ("", "%d", 0), i);
-  printf (dcgettext ("", "%ld", 0), i);
+  printf (dcgettext ("", "%ld", 0), (long) i);
 }
Index: gcc/gcc/testsuite/gcc.dg/format/miss-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-1.c
@@ -23,7 +23,7 @@ bar (const char *fmt, ...)
   va_end (ap);
 }
 
-__attribute__((__format__(__printf__, 1, 2))) void
+__attribute__((__format__(gnu_attr___printf__, 1, 2))) void
 foo2 (const char *fmt, ...)
 {
   va_list ap;
Index: gcc/gcc/testsuite/gcc.dg/format/miss-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-3.c
@@ -3,13 +3,14 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 void
 foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
@@ -18,7 +19,7 @@ foo1 (noattr_t na, attr_t a, vnoattr_t v
   noattr_t na2 = a; /* { dg-warning "candidate" "initialization warning" } */
   attr_t a1 = na;
   attr_t a2 = a;
-  
+
   vnoattr_t vna1 = vna;
   vnoattr_t vna2 = va; /* { dg-warning "candidate" "initialization warning" } */
   vattr_t va1 = vna;
Index: gcc/gcc/testsuite/gcc.dg/format/miss-4.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-4.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-4.c
@@ -3,20 +3,21 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 void
 foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
 {
   noattr_t na1, na2;
   attr_t a1, a2;
-  
+
   vnoattr_t vna1, vna2;
   vattr_t va1, va2;
 
@@ -24,7 +25,7 @@ foo1 (noattr_t na, attr_t a, vnoattr_t v
   na2 = a; /* { dg-warning "candidate" "assignment warning" } */
   a1 = na;
   a2 = a;
-  
+
   vna1 = vna;
   vna2 = va; /* { dg-warning "candidate" "assignment warning" } */
   va1 = vna;
Index: gcc/gcc/testsuite/gcc.dg/format/miss-5.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-5.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-5.c
@@ -3,13 +3,14 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 noattr_t
 foo1 (noattr_t na, attr_t a, int i)
Index: gcc/gcc/testsuite/gcc.dg/format/miss-6.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-6.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-6.c
@@ -3,13 +3,14 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 extern void foo1 (noattr_t);
 extern void foo2 (attr_t);
@@ -23,7 +24,7 @@ foo (noattr_t na, attr_t a, vnoattr_t vn
   foo1 (a); /* { dg-warning "candidate" "parameter passing warning" } */
   foo2 (na);
   foo2 (a);
-  
+
   foo3 (vna);
   foo3 (va); /* { dg-warning "candidate" "parameter passing warning" } */
   foo4 (vna);
Index: gcc/gcc/testsuite/gcc.dg/format/ms_array-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_array-1.c
@@ -0,0 +1,42 @@
+/* Test for format checking of constant arrays.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat=2" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+const char a1[] = "foo";
+const char a2[] = "foo%d";
+const char b1[3] = "foo";
+const char b2[1] = "1";
+static const char c1[] = "foo";
+static const char c2[] = "foo%d";
+char d[] = "foo";
+volatile const char e[] = "foo";
+
+void
+foo (int i, long l)
+{
+  const char p1[] = "bar";
+  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 (c1);
+  printf (c2, i);
+  printf (c2, l); /* { dg-warning "format" "wrong type with array" } */
+  printf (p1);
+  printf (p2, i);
+  printf (p2, l); /* { dg-warning "format" "wrong type with array" } */
+  printf (q1);
+  printf (q2, i);
+  printf (q2, l); /* { dg-warning "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" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-1.c
@@ -0,0 +1,10 @@
+/* Test for strftime format attributes: can't have first_arg_num != 0.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define DONT_GNU_PROTOTYPE
+#include "format.h"
+
+extern void foo0 (const char *) __attribute__((__format__(__ms_strftime__, 1, 0)));
+extern void foo1 (const char *, ...) __attribute__((__format__(__ms_strftime__, 1, 2))); /* { dg-error "cannot format" "strftime first_arg_num != 0" } */
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-2.c
@@ -0,0 +1,68 @@
+/* Test for format attributes: test use of __attribute__.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define DONT_GNU_PROTOTYPE
+#include "format.h"
+
+extern void tformatprintf (const char *, ...) __attribute__((format(ms_printf, 1, 2)));
+extern void tformat__printf__ (const char *, ...) __attribute__((format(__ms_printf__, 1, 2)));
+extern void tformatscanf (const char *, ...) __attribute__((format(ms_scanf, 1, 2)));
+extern void tformat__scanf__ (const char *, ...) __attribute__((format(__ms_scanf__, 1, 2)));
+extern void tformatstrftime (const char *) __attribute__((format(ms_strftime, 1, 0)));
+extern void tformat__strftime__ (const char *) __attribute__((format(__ms_strftime__, 1, 0)));
+extern void tformatstrfmon (const char *, ...) __attribute__((format(strfmon, 1, 2)));
+extern void tformat__strfmon__ (const char *, ...) __attribute__((format(__strfmon__, 1, 2)));
+extern void t__format__printf (const char *, ...) __attribute__((__format__(ms_printf, 1, 2)));
+extern void t__format____printf__ (const char *, ...) __attribute__((__format__(__ms_printf__, 1, 2)));
+extern void t__format__scanf (const char *, ...) __attribute__((__format__(ms_scanf, 1, 2)));
+extern void t__format____scanf__ (const char *, ...) __attribute__((__format__(__ms_scanf__, 1, 2)));
+extern void t__format__strftime (const char *) __attribute__((__format__(ms_strftime, 1, 0)));
+extern void t__format____strftime__ (const char *) __attribute__((__format__(__ms_strftime__, 1, 0)));
+extern void t__format__strfmon (const char *, ...) __attribute__((__format__(strfmon, 1, 2)));
+extern void t__format____strfmon__ (const char *, ...) __attribute__((__format__(__strfmon__, 1, 2)));
+
+extern char *tformat_arg (const char *) __attribute__((format_arg(1)));
+extern char *t__format_arg__ (const char *) __attribute__((__format_arg__(1)));
+
+void
+foo (int i, int *ip, double d)
+{
+  tformatprintf ("%d", i);
+  tformatprintf ("%"); /* { dg-warning "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);
+  tformat__scanf__ ("%"); /* { dg-warning "format" "attribute format __scanf__" } */
+  tformatstrftime ("%a");
+  tformatstrftime ("%"); /* { dg-warning "format" "attribute format strftime" } */
+  tformat__strftime__ ("%a");
+  tformat__strftime__ ("%"); /* { dg-warning "format" "attribute format __strftime__" } */
+  tformatstrfmon ("%n", d);
+  tformatstrfmon ("%"); /* { dg-warning "format" "attribute format strfmon" } */
+  tformat__strfmon__ ("%n", d);
+  tformat__strfmon__ ("%"); /* { dg-warning "format" "attribute format __strfmon__" } */
+  t__format__printf ("%d", i);
+  t__format__printf ("%"); /* { dg-warning "format" "attribute __format__ printf" } */
+  t__format____printf__ ("%d", i);
+  t__format____printf__ ("%"); /* { dg-warning "format" "attribute __format__ __printf__" } */
+  t__format__scanf ("%d", ip);
+  t__format__scanf ("%"); /* { dg-warning "format" "attribute __format__ scanf" } */
+  t__format____scanf__ ("%d", ip);
+  t__format____scanf__ ("%"); /* { dg-warning "format" "attribute __format__ __scanf__" } */
+  t__format__strftime ("%a");
+  t__format__strftime ("%"); /* { dg-warning "format" "attribute __format__ strftime" } */
+  t__format____strftime__ ("%a");
+  t__format____strftime__ ("%"); /* { dg-warning "format" "attribute __format__ __strftime__" } */
+  t__format__strfmon ("%n", d);
+  t__format__strfmon ("%"); /* { dg-warning "format" "attribute __format__ strfmon" } */
+  t__format____strfmon__ ("%n", d);
+  t__format____strfmon__ ("%"); /* { dg-warning "format" "attribute __format__ __strfmon__" } */
+  tformatprintf (tformat_arg ("%d"), i);
+  tformatprintf (tformat_arg ("%")); /* { dg-warning "format" "attribute format_arg" } */
+  tformatprintf (t__format_arg__ ("%d"), i);
+  tformatprintf (t__format_arg__ ("%")); /* { dg-warning "format" "attribute __format_arg__" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-3.c
@@ -0,0 +1,71 @@
+/* Test for format attributes: test bad uses of __attribute__.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* Proper uses of the attributes.  */
+extern void fa0 (const char *, ...) __attribute__((format(ms_printf, 1, 2)));
+extern void fa1 (char *, ...) __attribute__((format(ms_printf, 1, 2)));
+extern char *fa2 (const char *) __attribute__((format_arg(1)));
+extern char *fa3 (char *) __attribute__((format_arg(1)));
+
+/* Uses with too few or too many arguments.  */
+extern void fb0 (const char *, ...) __attribute__((format)); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb1 (const char *, ...) __attribute__((format())); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb2 (const char *, ...) __attribute__((format(ms_printf))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb3 (const char *, ...) __attribute__((format(ms_printf, 1))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb4 (const char *, ...) __attribute__((format(ms_printf, 1, 2, 3))); /* { dg-error "wrong number of arguments" "bad format" } */
+
+extern void fc1 (const char *) __attribute__((format_arg)); /* { dg-error "wrong number of arguments" "bad format_arg" } */
+extern void fc2 (const char *) __attribute__((format_arg())); /* { dg-error "wrong number of arguments" "bad format_arg" } */
+extern void fc3 (const char *) __attribute__((format_arg(1, 2))); /* { dg-error "wrong number of arguments" "bad format_arg" } */
+
+/* These attributes presently only apply to declarations, not to types.
+   Eventually, they should be usable with declarators for function types
+   anywhere, but still not with structure/union/enum types.  */
+struct s0 { int i; } __attribute__((format(ms_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on struct" } */
+union u0 { int i; } __attribute__((format(ms_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on union" } */
+enum e0 { E0V0 } __attribute__((format(ms_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on enum" } */
+
+struct s1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on struct" } */
+union u1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on union" } */
+enum e1 { E1V0 } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on enum" } */
+
+/* The format type must be an identifier, one of those recognized.  */
+extern void fe0 (const char *, ...) __attribute__((format(12345, 1, 2))); /* { dg-error "format specifier" "non-id format" } */
+extern void fe1 (const char *, ...) __attribute__((format(nosuch, 1, 2))); /* { dg-warning "format function type" "unknown format" } */
+
+/* Both the numbers must be integer constant expressions.  */
+extern void ff0 (const char *, ...) __attribute__((format(ms_printf, 3-2, (long long)(10/5))));
+int foo;
+extern void ff1 (const char *, ...) __attribute__((format(ms_printf, foo, 10/5))); /* { dg-error "invalid operand" "bad number" } */
+extern void ff2 (const char *, ...) __attribute__((format(ms_printf, 3-2, foo))); /* { dg-error "invalid operand" "bad number" } */
+extern char *ff3 (const char *) __attribute__((format_arg(3-2)));
+extern char *ff4 (const char *) __attribute__((format_arg(foo))); /* { dg-error "invalid operand" "bad format_arg number" } */
+
+/* The format string argument must precede the arguments to be formatted.
+   This includes if no parameter types are specified (which is not valid ISO
+   C for variadic functions).  */
+extern void fg0 () __attribute__((format(ms_printf, 1, 2)));
+extern void fg1 () __attribute__((format(ms_printf, 1, 0)));
+extern void fg2 () __attribute__((format(ms_printf, 1, 1))); /* { dg-error "follows" "bad number order" } */
+extern void fg3 () __attribute__((format(ms_printf, 2, 1))); /* { dg-error "follows" "bad number order" } */
+
+/* The format string argument must be a string type, and the arguments to
+   be formatted must be the "...".  */
+extern void fh0 (int, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "not a string" "format int string" } */
+extern void fh1 (signed char *, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "not a string" "signed char string" } */
+extern void fh2 (unsigned char *, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "not a string" "unsigned char string" } */
+extern void fh3 (const char *, ...) __attribute__((format(ms_printf, 1, 3))); /* { dg-error "is not" "not ..." } */
+extern void fh4 (const char *, int, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "is not" "not ..." } */
+
+/* format_arg formats must take and return a string.  */
+extern char *fi0 (int) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg int string" } */
+extern char *fi1 (signed char *) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg signed char string" } */
+extern char *fi2 (unsigned char *) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg unsigned char string" } */
+extern int fi3 (const char *) __attribute__((format_arg(1))); /* { dg-error "not return string" "format_arg ret int string" } */
+extern signed char *fi4 (const char *) __attribute__((format_arg(1))); /* { dg-error "not return string" "format_arg ret signed char string" } */
+extern unsigned char *fi5 (const char *) __attribute__((format_arg(1))); /* { dg-error "not return string" "format_arg ret unsigned char string" } */
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-4.c
@@ -0,0 +1,26 @@
+/* Test for format attributes: test use of __attribute__
+   in prefix attributes.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+extern __attribute__((format(ms_printf, 1, 2))) void tformatprintf0 (const char *, ...);
+extern void __attribute__((format(ms_printf, 1, 2))) tformatprintf1 (const char *, ...);
+extern void foo (void), __attribute__((format(ms_printf, 1, 2))) tformatprintf2 (const char *, ...);
+extern __attribute__((noreturn)) void bar (void), __attribute__((format(ms_printf, 1, 2))) tformatprintf3 (const char *, ...);
+
+void
+baz (int i, int *ip, double d)
+{
+  tformatprintf0 ("%d", i);
+  tformatprintf0 ("%"); /* { dg-warning "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);
+  tformatprintf3 ("%"); /* { dg-warning "format" "attribute format printf case 3" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-7.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-7.c
@@ -0,0 +1,35 @@
+/* Test for format attributes: test applying them to types.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define DONT_GNU_PROTOTYPE
+#include "format.h"
+
+__attribute__((format(ms_printf, 1, 2))) void (*tformatprintf0) (const char *, ...);
+void (*tformatprintf1) (const char *, ...) __attribute__((format(ms_printf, 1, 2)));
+void (__attribute__((format(ms_printf, 1, 2))) *tformatprintf2) (const char *, ...);
+void (__attribute__((format(ms_printf, 1, 2))) ****tformatprintf3) (const char *, ...);
+
+char * (__attribute__((format_arg(1))) *tformat_arg) (const char *);
+
+void
+baz (int i)
+{
+  (*tformatprintf0) ("%d", i);
+  (*tformatprintf0) ((*tformat_arg) ("%d"), i);
+  (*tformatprintf0) ("%"); /* { dg-warning "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" } */
+  (*tformatprintf2) ("%d", i);
+  (*tformatprintf2) ((*tformat_arg) ("%d"), i);
+  (*tformatprintf2) ("%"); /* { dg-warning "format" "nested" } */
+  (*tformatprintf2) ((*tformat_arg) ("%")); /* { dg-warning "format" "nested" } */
+  (****tformatprintf3) ("%d", i);
+  (****tformatprintf3) ((*tformat_arg) ("%d"), i);
+  (****tformatprintf3) ("%"); /* { dg-warning "format" "nested 2" } */
+  (****tformatprintf3) ((*tformat_arg) ("%")); /* { dg-warning "format" "nested 2" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_bitfld-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_bitfld-1.c
@@ -0,0 +1,52 @@
+/* Test for printf formats and bit-fields: bug 22421.  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+/* { dg-require-effective-target int32plus } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+struct s {
+  unsigned int u1 : 1;
+  signed int s1 : 1;
+  unsigned int u15 : 15;
+  signed int s15 : 15;
+  unsigned int u16 : 16;
+  signed int s16 : 16;
+  unsigned long u31 : 31;
+  signed long s31 : 31;
+  unsigned long u32 : 32;
+  signed long s32 : 32;
+  unsigned long long u48 : 48;
+} x;
+
+void
+foo (void)
+{
+  printf ("%d%u", x.u1, x.u1);
+  printf ("%d%u", x.s1, x.s1);
+  printf ("%d%u", x.u15, x.u15);
+  printf ("%d%u", x.s15, x.s15);
+  printf ("%d%u", x.u16, x.u16);
+  printf ("%d%u", x.s16, x.s16);
+#if __INT_MAX__ > 32767
+  /* If integers are 16 bits, there doesn't seem to be a way of
+     printing these without getting an error.  */
+  printf ("%d%u", x.u31, x.u31);
+  printf ("%d%u", x.s31, x.s31);
+#endif
+#if __LONG_MAX__ > 2147483647 && __INT_MAX__ >= 2147483647
+  /* If long is wider than 32 bits, the 32-bit bit-fields are int or
+     unsigned int or promote to those types.  Otherwise, long is 32
+     bits and the bit-fields are of type plain long or unsigned
+     long.  */
+  printf ("%d%u", x.u32, x.u32);
+  printf ("%d%u", x.s32, x.s32);
+#else
+  printf ("%ld%lu", x.u32, x.u32);
+  printf ("%ld%lu", x.s32, x.s32);
+#endif
+  printf ("%I64u", x.u48); /* { dg-warning "has type '.*unsigned int:48'" } */
+  printf ("%I64u", (unsigned long long)x.u48);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_branch-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_branch-1.c
@@ -0,0 +1,28 @@
+/* Test for format checking of conditional expressions.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+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" } */
+  /* 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) ? "%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" } */
+  /* 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 *-*-* } 26 } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-1.c
@@ -0,0 +1,184 @@
+/* Test for printf formats.  Formats using C90 features, including cases
+   where C90 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, int i1, int i2, unsigned int u, double d, char *s, void *p,
+     int *n, short int *hn, long int l, unsigned long int ul,
+     long int *ln, long double ld, wint_t lc, wchar_t *ls, llong ll,
+     ullong ull, unsigned int *un, const int *cn, signed char *ss,
+     unsigned char *us, const signed char *css, unsigned int u1,
+     unsigned int u2)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.1 (pages 131-134).  */
+  /* Basic sanity checks for the different components of a format.  */
+  printf ("%d\n", i);
+  printf ("%+d\n", i);
+  printf ("%3d\n", i);
+  printf ("%-3d\n", i);
+  printf ("%*d\n", i1, i);
+  printf ("%d %lu\n", i, ul);
+  /* Bogus use of width.  */
+  printf ("%5n\n", n); /* { dg-warning "width" "width 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 ("%-%"); /* { dg-warning "format" "bogus %%" } */
+  printf ("%-%\n"); /* { dg-warning "format" "bogus %%" } */
+  printf ("%5%\n"); /* { dg-warning "format" "bogus %%" } */
+  printf ("%h%\n"); /* { dg-warning "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
+     differences in format checking here, and this is relied on to get the
+     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);
+  printf ("%hs", hn);
+  printf ("%hp", p); /* { dg-warning "length" "bad use of %h" } */
+  printf ("%h"); /* { dg-warning "conversion lacks type" "bare %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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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% 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* Various tests of bad argument types.  */
+  printf ("%d", l); /* { dg-warning "format" "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" } */
+  /* 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
+     discussion of the requirements of rules on identical representation,
+     and of the application of the as if rule with the new va_arg
+     allowances in C99 to printf.)  Likewise, we should warn if
+     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" } */
+  /* 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" } */
+  /* The historical behavior is to allow signed / unsigned types
+     interchangably as arguments.  For values representable in both types,
+     such usage may be correct.  For now preserve the behavior of GCC
+     in such cases.
+  */
+  printf ("%d", u);
+  /* Wrong number of arguments.  */
+  printf ("%d%d", i); /* { dg-warning "arguments" "wrong number of args" } */
+  printf ("%d", i, i); /* { dg-warning "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" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-2.c
@@ -0,0 +1,25 @@
+/* Test for printf formats.  Formats using C99 features should be rejected
+   outside of C99 mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, double d, llong ll, intmax_t j, size_t z, ptrdiff_t t)
+{
+  /* Some tests already in c90-printf-1.c, e.g. %lf.  */
+  /* The widths hh, ll, j, z, t are new.  */
+  printf ("%hhd", i); /* { dg-warning "unknown|format" "%hh is unsupported" } */
+  printf ("%I64d", ll); /* { dg-warning "length|C" "%I64 in C90" } */
+  printf ("%jd", j); /* { dg-warning "unknown|format" "%j is unsupported" } */
+  printf ("%zu", z); /* { dg-warning "unknown|format" "%z is unsupported" } */
+  printf ("%td", t); /* { dg-warning "unknown|format" "%t is unsupported" } */
+  /* The formats F, a, A are new.  */
+  printf ("%F", d); /* { dg-warning "unknown|format" "%F is unsupported" } */
+  printf ("%a", d); /* { dg-warning "unknown|format" "%a is unsupported" } */
+  printf ("%A", d); /* { dg-warning "unknown|format" "%A is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-3.c
@@ -0,0 +1,43 @@
+/* Test for printf formats.  Test that the C90 functions get their default
+   attributes in strict C90 mode, but the C99 and gettext functions
+   do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, char *s, size_t n, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5, va_list v6, va_list v7, va_list v8)
+{
+  fprintf (stdout, "%d", i);
+  fprintf (stdout, "%ld", i); /* { dg-warning "format" "fprintf" } */
+  printf ("%d", i);
+  printf ("%ld", i); /* { dg-warning "format" "printf" } */
+  /* The "unlocked" functions shouldn't warn in c90 mode.  */
+  fprintf_unlocked (stdout, "%ld", i);
+  printf_unlocked ("%ld", i);
+  sprintf (s, "%d", i);
+  sprintf (s, "%ld", i); /* { dg-warning "format" "sprintf" } */
+  vfprintf (stdout, "%d", v0);
+  vfprintf (stdout, "%Y", v1); /* { dg-warning "format" "vfprintf" } */
+  vprintf ("%d", v2);
+  vprintf ("%Y", v3); /* { dg-warning "format" "vprintf" } */
+  /* The following used to give a bogus warning.  */
+  vprintf ("%*.*d", v8); /* { dg-warning "format" "dot is invalid" } */
+  vsprintf (s, "%d", v4);
+  vsprintf (s, "%Y", v5); /* { dg-warning "format" "Y is invalid" } */
+  snprintf (s, n, "%d", i);
+  snprintf (s, n, "%ld", i);
+  vsnprintf (s, n, "%d", v6);
+  vsnprintf (s, n, "%Y", v7);
+  printf (gettext ("%d"), i);
+  printf (gettext ("%ld"), i);
+  printf (dgettext ("", "%d"), i);
+  printf (dgettext ("", "%ld"), (long) i);
+  printf (dcgettext ("", "%d", 0), i);
+  printf (dcgettext ("", "%ld", 0), (long) i);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-1.c
@@ -0,0 +1,119 @@
+/* Test for scanf formats.  Formats using C90 features, including cases
+   where C90 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, unsigned int *uip, short int *hp, unsigned short int *uhp,
+     long int *lp, unsigned long int *ulp, float *fp, double *dp,
+     long double *ldp, char *s, signed char *ss, unsigned char *us,
+     void **pp, int *n, llong *llp, ullong *ullp, wchar_t *ls,
+     const int *cip, const int *cn, const char *cs, const void **ppc,
+     void *const *pcp, short int *hn, long int *ln, void *p, char **sp,
+     volatile void *ppv)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.2 (pages 134-138).  */
+  /* Basic sanity checks for the different components of a format.  */
+  scanf ("%d", ip);
+  scanf ("%*d");
+  scanf ("%3d", ip);
+  scanf ("%hd", hp);
+  scanf ("%3ld", lp);
+  scanf ("%*3d");
+  scanf ("%d %ld", ip, lp);
+  /* Valid and invalid %% constructions.  */
+  scanf ("%%");
+  scanf ("%*%"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%*%\n"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%4%"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%4%\n"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%h%"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%h%\n"); /* { dg-warning "format" "bogus %%" } */
+  /* Valid, invalid and silly assignment-suppression constructions.  */
+  scanf ("%*d%*i%*o%*u%*x%*X%*e%*E%*f%*g%*G%*s%*[abc]%*c%*p");
+  scanf ("%*2d%*8s%*3c");
+  scanf ("%*n", n); /* { dg-warning "suppress" "suppression of %n" } */
+  scanf ("%*hd"); /* { dg-warning "together" "suppression with length" } */
+  /* Valid, invalid and silly width constructions.  */
+  scanf ("%2d%3i%4o%5u%6x%7X%8e%9E%10f%11g%12G%13s%14[abc]%15c%16p",
+	 ip, ip, uip, uip, uip, uip, fp, fp, fp, fp, fp, s, s, s, pp);
+  scanf ("%0d", ip); /* { dg-warning "width" "warning for zero width" } */
+  scanf ("%3n", n); /* { dg-warning "width" "width with %n" } */
+  /* Valid and invalid %h, %l, %L constructions.  */
+  scanf ("%hd%hi%ho%hu%hx%hX%hn", hp, hp, uhp, uhp, uhp, uhp, hn);
+  scanf ("%he", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hE", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hf", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hg", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hG", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hs", hp);
+  scanf ("%h[ac]", s); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hc", hp);
+  scanf ("%hp", pp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%h"); /* { dg-warning "conversion lacks type" "bare %h" } */
+  scanf ("%h."); /* { dg-warning "conversion" "bogus %h" } */
+  scanf ("%ld%li%lo%lu%lx%lX%ln", lp, lp, ulp, ulp, ulp, ulp, ln);
+  scanf ("%le%lE%lf%lg%lG", dp, dp, dp, dp, dp);
+  scanf ("%lp", pp); /* { dg-warning "length" "bad use of %l" } */
+  /* These next three formats were added in C94.  */
+  scanf ("%ls", ls); /* { dg-warning "length|C" "bad use of %l" } */
+  scanf ("%l[ac]", ls); /* { dg-warning "length|C" "bad use of %l" } */
+  scanf ("%lc", ls); /* { dg-warning "length|C" "bad use of %l" } */
+  scanf ("%Ld", llp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Li", llp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lo", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lu", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lx", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%LX", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Ls", s); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%L[ac]", s); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lc", s); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lp", pp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Ln", n); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  /* Valid uses of each bare conversion.  */
+  scanf ("%d%i%o%u%x%X%e%E%f%g%G%s%[abc]%c%p%n%%", ip, ip, uip, uip, uip,
+	 uip, fp, fp, fp, fp, fp, s, s, s, pp, n);
+  /* Allow other character pointers with %s, %c, %[].  */
+  scanf ("%2s%3s%4c%5c%6[abc]%7[abc]", ss, us, ss, us, ss, us);
+  /* Further tests for %[].  */
+  scanf ("%[%d]%d", s, ip);
+  scanf ("%[^%d]%d", s, ip);
+  scanf ("%[]%d]%d", s, ip);
+  scanf ("%[^]%d]%d", s, ip);
+  scanf ("%[%d]%d", s, ip);
+  scanf ("%[]abcd", s); /* { dg-warning "no closing" "incomplete scanset" } */
+  /* Various tests of bad argument types.  Some of these are only pedantic
+     warnings.
+  */
+  scanf ("%d", lp); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%d", uip); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%d", pp); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", ppc); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", ppv); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%s", n); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%s", p); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", p); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", sp); /* { dg-warning "format" "bad argument types" } */
+  /* Tests for writing into constant values.  */
+  scanf ("%d", cip); /* { dg-warning "constant" "%d writing into const" } */
+  scanf ("%n", cn); /* { dg-warning "constant" "%n writing into const" } */
+  scanf ("%s", cs); /* { dg-warning "constant" "%s writing into const" } */
+  scanf ("%p", pcp); /* { dg-warning "constant" "%p writing into const" } */
+  /* Wrong number of arguments.  */
+  scanf ("%d%d", ip); /* { dg-warning "arguments" "wrong number of args" } */
+  scanf ("%d", ip, ip); /* { dg-warning "arguments" "wrong number of args" } */
+  /* Miscellaneous bogus constructions.  */
+  scanf (""); /* { dg-warning "zero-length" "warning for empty format" } */
+  scanf ("\0"); /* { dg-warning "embedded" "warning for embedded NUL" } */
+  scanf ("%d\0", ip); /* { dg-warning "embedded" "warning for embedded NUL" } */
+  scanf ("%d\0%d", ip, ip); /* { dg-warning "embedded|too many" "warning for embedded NUL" } */
+  scanf (NULL); /* { dg-warning "null" "null format string warning" } */
+  scanf ("%"); /* { dg-warning "trailing" "trailing % warning" } */
+  scanf ("%d", (int *)0); /* { dg-warning "null" "writing into NULL" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-2.c
@@ -0,0 +1,26 @@
+/* Test for scanf formats.  Formats using C99 features should be rejected
+   outside of C99 mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (signed char *hhp, float *fp, llong *llp, intmax_t *jp,
+     size_t *zp, ptrdiff_t *tp)
+{
+  /* Some tests already in c90-scanf-1.c.  */
+  /* The widths hh, ll, j, z, t are new.  */
+  scanf ("%hhd", hhp); /* { dg-warning "unknown|format" "%hh is unsupported" } */
+  scanf ("%I64d", llp); /* { dg-warning "length|C" "%I64 in C90" } */
+  scanf ("%jd", jp); /* { dg-warning "unknown|format" "%j is unsupported" } */
+  scanf ("%zu", zp); /* { dg-warning "unknown|format" "%z is unsupported" } */
+  scanf ("%td", tp); /* { dg-warning "unknown|format" "%t is unsupported" } */
+  /* The formats F, a, A are new.  */
+  scanf ("%F", fp); /* { dg-warning "unknown|format" "%F is unsupported" } */
+  scanf ("%a", fp); /* { dg-warning "unknown|format" "%a is unsupported" } */
+  scanf ("%A", fp); /* { dg-warning "unknown|format" "%A is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-3.c
@@ -0,0 +1,20 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char **sp, wchar_t **lsp)
+{
+  /* %a formats for allocation, only recognized in C90 mode, are a
+     GNU extension.
+  */
+  scanf ("%as", sp); /* { dg-warning "flag" "%as is unsupported" } */
+  scanf ("%aS", lsp); /* { dg-warning "format|flag" "%aS is unsupported" } */
+  scanf ("%a[bcd]", sp); /* { dg-warning "flag" "%a[] is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-4.c
@@ -0,0 +1,31 @@
+/* Test for scanf formats.  Test that the C90 functions get their default
+   attributes in strict C90 mode, but the C99 and gettext functions
+   do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, char *s, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5)
+{
+  fscanf (stdin, "%d", ip);
+  fscanf (stdin, "%ld", ip); /* { dg-warning "format" "fscanf" } */
+  scanf ("%d", ip);
+  scanf ("%ld", ip); /* { dg-warning "format" "scanf" } */
+  sscanf (s, "%d", ip);
+  sscanf (s, "%ld", ip); /* { dg-warning "format" "sscanf" } */
+  vfscanf (stdin, "%d", v0);
+  vscanf ("%d", v2);
+  vsscanf (s, "%d", v4);
+  scanf (gettext ("%d"), ip);
+  scanf (gettext ("%ld"), ip);
+  scanf (dgettext ("", "%d"), ip);
+  scanf (dgettext ("", "%ld"), ip);
+  scanf (dcgettext ("", "%d", 0), ip);
+  scanf (dcgettext ("", "%ld", 0), ip);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-5.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-5.c
@@ -0,0 +1,20 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char **sp, wchar_t **lsp)
+{
+  /* m assignment-allocation modifier, recognized in both C90
+     and C99 modes, is a POSIX and ISO/IEC WDTR 24731-2 extension.  */
+  scanf ("%ms", sp); /* { dg-warning "unknown|format" "%ms is unsupported" } */
+  scanf ("%mS", lsp); /* { dg-warning "unknown|format" "%mS is unsupported" } */
+  scanf ("%mls", lsp); /* { dg-warning "unknown|format" "%mls is unsupported" } */
+  scanf ("%m[bcd]", sp); /* { dg-warning "unknown|format" "%m[] is unsupported" } */
+  scanf ("%ml[bcd]", lsp); /* { dg-warning "unknown|format" "%ml[] is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-1.c
@@ -0,0 +1,20 @@
+/* Test for strftime formats.  Formats using C90 features.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wformat-y2k" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.12.3.5 (pages 174-175).  */
+  /* Formats which are Y2K-compliant (no 2-digit years).  */
+  strftime (s, m, "%a%A%b%B%d%H%I%j%m%M%p%S%U%w%W%X%Y%Z%%", tp);
+  /* Formats with 2-digit years.  */
+  strftime (s, m, "%y", tp); /* { dg-warning "only last 2" "2-digit year" } */
+  /* Formats with 2-digit years in some locales.  */
+  strftime (s, m, "%c", tp); /* { dg-warning "some locales" "2-digit year" } */
+  strftime (s, m, "%x", tp); /* { dg-warning "some locales" "2-digit year" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-2.c
@@ -0,0 +1,30 @@
+/* Test for strftime formats.  Rejection of formats using C99 features in
+   pedantic C90 mode.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wformat-y2k" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  strftime (s, m, "%C", tp); /* { dg-warning "format" "%C is unsupported" } */
+  strftime (s, m, "%D", tp); /* { dg-warning "format" "%D is unsupported" } */
+  strftime (s, m, "%e", tp); /* { dg-warning "format" "%e is unsupported" } */
+  strftime (s, m, "%F", tp); /* { dg-warning "format" "%F is unsupported" } */
+  strftime (s, m, "%g", tp); /* { dg-warning "format" "%g is unsupported" } */
+  strftime (s, m, "%G", tp); /* { dg-warning "format" "%G is unsupported" } */
+  strftime (s, m, "%h", tp); /* { dg-warning "format" "%h is unsupported" } */
+  strftime (s, m, "%n", tp); /* { dg-warning "format" "%n is unsupported" } */
+  strftime (s, m, "%r", tp); /* { dg-warning "format" "%r is unsupported" } */
+  strftime (s, m, "%R", tp); /* { dg-warning "format" "%R is unsupported" } */
+  strftime (s, m, "%t", tp); /* { dg-warning "format" "%t is unsupported" } */
+  strftime (s, m, "%T", tp); /* { dg-warning "format" "%T is unsupported" } */
+  strftime (s, m, "%u", tp); /* { dg-warning "format" "%u is unsupported" } */
+  strftime (s, m, "%V", tp); /* { dg-warning "format" "%V is unsupported" } */
+  strftime (s, m, "%z", tp); /* { dg-warning "C" "%z not in C90" } */
+  strftime (s, m, "%EX", tp); /* { dg-warning "C" "%E not in C90" } */
+  strftime (s, m, "%OW", tp); /* { dg-warning "C" "%O not in C90" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c94-printf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c94-printf-1.c
@@ -0,0 +1,19 @@
+/* Test for printf formats.  Changes in C94 to C90.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:199409 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (wint_t lc, wchar_t *ls)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.1 (pages 131-134),
+     as amended by ISO/IEC 9899:1990/Amd.1:1995 (E) (pages 4-5).
+     We do not repeat here all the C90 format checks, but just verify
+     that %ls and %lc are accepted without warning.
+  */
+  printf ("%lc", lc);
+  printf ("%ls", ls);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c94-scanf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c94-scanf-1.c
@@ -0,0 +1,18 @@
+/* Test for scanf formats.  Changes in C94 to C90.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:199409 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (wchar_t *ls)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.2 (pages 134-138),
+     as amended by ISO/IEC 9899:1990/Amd.1:1995 (E) (pages 5-6).
+     We do not repeat here all the C90 format checks, but just verify
+     that %ls, %lc, %l[] are accepted without warning.
+  */
+  scanf ("%lc%ls%l[abc]", ls, ls, ls);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-1.c
@@ -0,0 +1,122 @@
+/* Test for printf formats.  Formats using C99 features, including cases
+   where C99 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, unsigned int u, double d, char *s, void *p, int *n,
+     long double ld, wint_t lc, wchar_t *ls, long long int ll,
+     unsigned long long int ull, signed char *ss, unsigned char *us,
+     long long int *lln, intmax_t j, uintmax_t uj, intmax_t *jn,
+     size_t z, signed_size_t sz, signed_size_t *zn,
+     ptrdiff_t t, ptrdiff_t *tn)
+{
+  /* See ISO/IEC 9899:1999 (E) subclause 7.19.6.1 (pages 273-281).
+     We do not repeat here most of the checks for correct C90 formats
+     or completely broken formats.
+  */
+  /* Valid and invalid %h, %hh, %l, %I64, %j, %z, %t, %L constructions.  */
+  printf ("%hf", d); /* { dg-warning "length" "bad use of %h" } */
+  printf ("%hF", d); /* { dg-warning "unknown|format" "bad use of %hF" } */
+  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 ("%ha", d); /* { dg-warning "unknown|format" "bad use of %ha" } */
+  printf ("%hA", d); /* { dg-warning "unknown|format" "bad use of %hA" } */
+  printf ("%hc", i);
+  printf ("%hs", (short *)s);
+  printf ("%hp", p); /* { dg-warning "length" "bad use of %h" } */
+  printf ("%lc", lc);
+  printf ("%ls", ls);
+  printf ("%lp", p); /* { dg-warning "length|C" "bad use of %l" } */
+  printf ("%I64d%I64i%I64o%I64u%I64x%I64X", ll, ll, ull, ull, ull, ull);
+  printf ("%I64n", lln);
+  printf ("%I64f", d); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64F", d); /* { dg-warning "unknown|format" "bad use of %I64F" } */
+  printf ("%I64e", d); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64E", d); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64g", d); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64G", d); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64a", d); /* { dg-warning "unknown|format" "bad use of %I64a" } */
+  printf ("%I64A", d); /* { dg-warning "unknown|format" "bad use of %I64A" } */
+  printf ("%I64c", i); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64s", s); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64p", p); /* { dg-warning "length" "bad use of %I64" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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% 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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 ("%-08F", d); /* { dg-warning "unknown|format" "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 ("%-08a", d); /* { dg-warning "unknown|format" "0 flag ignored with - flag" } */
+  printf ("%-08A", d); /* { dg-warning "unknown|format" "0 flag ignored with - flag" } */
+  /* Various tests of bad argument types.  Mostly covered in c90-printf-1.c;
+     here just test for pointer target sign with %hhn.  (Probably allowed
+     by the standard, but a bad idea, so GCC should diagnose if what
+     is used is not signed char *.)
+  */
+  printf ("%hhn", s); /* { dg-warning "unknown|format" "%hhn is unsupported" } */
+  printf ("%hhn", us); /* { dg-warning "unknown|format" "%hhn is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-2.c
@@ -0,0 +1,33 @@
+/* Test for printf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, long long ll, size_t z, wint_t lc, wchar_t *ls)
+{
+  /* The length modifiers q, Z and L as applied to integer formats are
+     extensions.
+  */
+  printf ("%qd", ll); /* { dg-warning "unknown|format" "%q length is unsupported" } */
+  printf ("%Ld", ll); /* { dg-warning "unknown|format" "%L length is unsupported" } */
+  printf ("%Zd", z); /* { dg-warning "unknown|format" "%Z lengthis unsupported" } */
+  /* The conversion specifiers C and S are X/Open extensions; the
+     conversion specifier m is a GNU extension.
+  */
+  printf ("%m"); /* { dg-warning "unknown|format" "printf %m is unsupported" } */
+  printf ("%C", lc); /* { dg-warning "C" "printf %C" } */
+  printf ("%S", ls); /* { dg-warning "C" "printf %S" } */
+  /* The flag character ', and the use of operand number $ formats, are
+     X/Open extensions.
+  */
+  printf ("%'d", i); /* { dg-warning "C" "printf ' flag" } */
+  printf ("%1$d", i); /* { dg-warning "C" "printf $ format" } */
+  /* The flag character I is a GNU extension.  */
+  printf ("%Ix", z);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-3.c
@@ -0,0 +1,40 @@
+/* Test for printf formats.  Test that the C99 functions get their default
+   attributes in strict C99 mode, but the gettext functions do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, char *s, size_t n, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5, va_list v6, va_list v7)
+{
+  fprintf (stdout, "%d", i);
+  fprintf (stdout, "%ld", i); /* { dg-warning "format" "fprintf" } */
+  printf ("%d", i);
+  printf ("%ld", i); /* { dg-warning "format" "printf" } */
+  /* The "unlocked" functions shouldn't warn in c99 mode.  */
+  fprintf_unlocked (stdout, "%ld", i);
+  printf_unlocked ("%ld", i);
+  sprintf (s, "%d", i);
+  sprintf (s, "%ld", i); /* { dg-warning "format" "sprintf" } */
+  snprintf (s, n, "%d", i);
+  snprintf (s, n, "%ld", i); /* { dg-warning "format" "snprintf" } */
+  vfprintf (stdout, "%d", v0);
+  vfprintf (stdout, "%Y", v1); /* { dg-warning "format" "vfprintf" } */
+  vprintf ("%d", v0);
+  vprintf ("%Y", v1); /* { dg-warning "format" "vprintf" } */
+  vsprintf (s, "%d", v0);
+  vsprintf (s, "%Y", v1); /* { dg-warning "format" "vsprintf" } */
+  vsnprintf (s, n, "%d", v0);
+  vsnprintf (s, n, "%Y", v1); /* { dg-warning "format" "vsnprintf" } */
+  printf (gettext ("%d"), i);
+  printf (gettext ("%ld"), (long) i);
+  printf (dgettext ("", "%d"), i);
+  printf (dgettext ("", "%ld"), (long) i);
+  printf (dcgettext ("", "%d", 0), i);
+  printf (dcgettext ("", "%ld", 0), (long) i);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-1.c
@@ -0,0 +1,75 @@
+/* Test for scanf formats.  Formats using C99 features, including cases
+   where C99 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, unsigned int *uip, short int *hp, unsigned short int *uhp,
+     signed char *hhp, unsigned char *uhhp, long int *lp,
+     unsigned long int *ulp, float *fp, double *dp, long double *ldp, char *s,
+     void **pp, int *n, long long *llp, unsigned long long *ullp, wchar_t *ls,
+     short int *hn, signed char *hhn, long int *ln, long long int *lln,
+     intmax_t *jp, uintmax_t *ujp, intmax_t *jn, size_t *zp,
+     signed_size_t *szp, signed_size_t *zn, ptrdiff_t *tp,
+     unsigned_ptrdiff_t *utp, ptrdiff_t *tn)
+{
+  /* See ISO/IEC 9899:1999 (E) subclause 7.19.6.2 (pages 281-288).
+     We do not repeat here most of the checks for correct C90 formats
+     or completely broken formats.
+  */
+  /* Valid, invalid and silly assignment-suppression
+     and width constructions.
+  */
+  scanf ("%*d%*i%*o%*u%*x%*X%*e%*E%*f%*g%*G%*s%*[abc]%*c%*p");
+  scanf ("%*2d%*8s%*3c");
+  scanf ("%*n", n); /* { dg-warning "suppress" "suppression of %n" } */
+  scanf ("%*hd"); /* { dg-warning "together" "suppression with length" } */
+  scanf ("%2d%3i%4o%5u%6x%7X%10e%11E%12f%14g%15G%16s%3[abc]%4c%5p",
+	 ip, ip, uip, uip, uip, uip, fp, fp, fp, fp, fp,
+	 s, s, s, pp);
+  scanf ("%0d", ip); /* { dg-warning "width" "warning for zero width" } */
+  scanf ("%3n", n); /* { dg-warning "width" "width with %n" } */
+  /* Valid and invalid %h, %hh, %l, %I64, %j, %z, %t, %L constructions.  */
+  scanf ("%hd%hi%ho%hu%hx%hX%hn", hp, hp, uhp, uhp, uhp, uhp, hn);
+  scanf ("%he", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hE", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hf", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hg", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hG", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hs", hp);
+  scanf ("%h[ac]", s); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hc", (short *)s);
+  scanf ("%hp", pp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hhd", hhp); /* { dg-warning "unknown|format" "%hh is unsupported" } */
+  scanf ("%ld%li%lo%lu%lx%lX%ln", lp, lp, ulp, ulp, ulp, ulp, ln);
+  scanf ("%le%lE%lf%lg%lG", dp, dp, dp, dp, dp);
+  scanf ("%lp", pp); /* { dg-warning "length" "bad use of %l" } */
+  scanf ("%ls", ls);
+  scanf ("%l[ac]", ls);
+  scanf ("%lc", ls);
+  scanf ("%I64d%I64i%I64o%I64u%I64x%I64X%I64n", llp, llp, ullp, ullp, ullp, ullp,
+	 lln);
+  scanf ("%I64e", fp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64E", fp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64f", fp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64F", fp); /* { dg-warning "unknown|format" "'F' is unsupported" } */
+  scanf ("%I64g", fp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64G", fp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64s", s); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64[ac]", s); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64c", s); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64p", pp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%jd", jp); /* { dg-warning "unknown|format" "%j not supported" } */
+  scanf ("%zd", zp); /* { dg-warning "unknown|format" "%z not supported" } */
+  scanf ("%td", tp); /* { dg-warning "unknown|format" "%t not supported" } */
+  scanf ("%Lf", llp); /* { dg-warning "unknown|format" "bad use of %L is not supported" } */
+  /* Valid uses of each bare conversion.  */
+  scanf ("%d%i%o%u%x%X%e%E%f%g%G%s%[abc]%c%p%n%%", ip, ip, uip, uip, uip,
+         uip, fp, fp, fp, fp, fp, s, s, s, pp, n);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-2.c
@@ -0,0 +1,27 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, long long int *llp, wchar_t *ls)
+{
+  /* The length modifiers q and L as applied to integer formats are
+     extensions.
+  */
+  scanf ("%qd", llp); /* { dg-warning "unknown|format" "%q is unsupported" } */
+  scanf ("%Ld", llp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  /* The conversion specifiers C and S are X/Open extensions.  */
+  scanf ("%C", ls); /* { dg-warning "C" "scanf %C" } */
+  scanf ("%S", ls); /* { dg-warning "C" "scanf %S" } */
+  /* The use of operand number $ formats is an X/Open extension.  */
+  scanf ("%1$d", ip); /* { dg-warning "C" "scanf $ format" } */
+  /* glibc also supports flags ' and I on scanf formats as an extension.  */
+  scanf ("%'d", ip); /* { dg-warning "C" "scanf ' flag" } */
+  scanf ("%Id", (ssize_t *)ip);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-3.c
@@ -0,0 +1,33 @@
+/* Test for scanf formats.  Test that the C99 functions get their default
+   attributes in strict C99 mode, but the gettext functions do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, char *s, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5)
+{
+  fscanf (stdin, "%d", ip);
+  fscanf (stdin, "%ld", ip); /* { dg-warning "format" "fscanf" } */
+  scanf ("%d", ip);
+  scanf ("%ld", ip); /* { dg-warning "format" "scanf" } */
+  sscanf (s, "%d", ip);
+  sscanf (s, "%ld", ip); /* { dg-warning "format" "sscanf" } */
+  vfscanf (stdin, "%d", v0);
+  vfscanf (stdin, "%Y", v1); /* { dg-warning "format" "vfscanf" } */
+  vscanf ("%d", v2);
+  vscanf ("%Y", v3); /* { dg-warning "format" "vscanf" } */
+  vsscanf (s, "%d", v4);
+  vsscanf (s, "%Y", v5); /* { dg-warning "format" "vsscanf" } */
+  scanf (gettext ("%d"), ip);
+  scanf (gettext ("%ld"), ip);
+  scanf (dgettext ("", "%d"), ip);
+  scanf (dgettext ("", "%ld"), ip);
+  scanf (dcgettext ("", "%d", 0), ip);
+  scanf (dcgettext ("", "%ld", 0), ip);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-4.c
@@ -0,0 +1,20 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char **sp, wchar_t **lsp)
+{
+  /* m assignment-allocation modifier, recognized in both C90
+     and C99 modes, is a POSIX and ISO/IEC WDTR 24731-2 extension.  */
+  scanf ("%ms", sp); /* { dg-warning "unknown|format" "%ms is unsupported" } */
+  scanf ("%mS", lsp); /* { dg-warning "unknown|format" "%mS is unsupported" } */
+  scanf ("%mls", lsp); /* { dg-warning "unknown|format" "%mls is unsupported" } */
+  scanf ("%m[bcd]", sp); /* { dg-warning "unknown|format" "%m[] is unsupported" } */
+  scanf ("%ml[bcd]", lsp); /* { dg-warning "unknown|format" "%ml[] is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-1.c
@@ -0,0 +1,30 @@
+/* Test for strftime formats.  Formats using C99 features.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat -Wformat-y2k" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.12.3.5 (pages 174-175).  */
+  /* Formats which are Y2K-compliant (no 2-digit years).  */
+  strftime (s, m, "%a%A%b%B%d%H%I%j%m%M%p%S%U%w%W%X%Y%z%Z%%", tp);
+  strftime (s, m, "%EX%EY%Od%OH%OI%Om%OM%OS%OU%Ow%OW", tp);
+  /* Formats with 2-digit years.  */
+  strftime (s, m, "%D", tp); /* { dg-warning "unknown" "2-digit year unsupported" } */
+  strftime (s, m, "%g", tp); /* { dg-warning "unknown" "2-digit year unsupported" } */
+  strftime (s, m, "%y", tp); /* { dg-warning "only last 2" "2-digit year" } */
+  strftime (s, m, "%Oy", tp); /* { dg-warning "only last 2" "2-digit year" } */
+  /* Formats with 2-digit years in some locales.  */
+  strftime (s, m, "%c", tp); /* { dg-warning "some locales" "2-digit year" } */
+  strftime (s, m, "%Ec", tp); /* { dg-warning "some locales" "2-digit year" } */
+  strftime (s, m, "%x", tp); /* { dg-warning "some locales" "2-digit year" } */
+  strftime (s, m, "%Ex", tp); /* { dg-warning "some locales" "2-digit year" } */
+  /* %Ey is explicitly an era offset not a 2-digit year; but in some
+     locales the E modifier may be ignored.
+  */
+  strftime (s, m, "%Ey", tp); /* { dg-warning "some locales" "2-digit year" } */
+  }
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-2.c
@@ -0,0 +1,24 @@
+/* Test for strftime formats.  Rejection of extensions in pedantic mode.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  /* %P is a lowercase version of %p.  */
+  strftime (s, m, "%P", tp); /* { dg-warning "unknown" "strftime %P" } */
+  /* %k is %H but padded with a space rather than 0 if necessary.  */
+  strftime (s, m, "%k", tp); /* { dg-warning "unknown" "strftime %k" } */
+  /* %l is %I but padded with a space rather than 0 if necessary.  */
+  strftime (s, m, "%l", tp); /* { dg-warning "unknown" "strftime %l" } */
+  /* %s is the number of seconds since the Epoch.  */
+  strftime (s, m, "%s", tp); /* { dg-warning "unknown" "strftime %s" } */
+  /* Extensions using %O already tested in c99-strftime-1.c.  */
+  /* Width and flags are GNU extensions for strftime.  */
+  strftime (s, m, "%20Y", tp); /* { dg-warning "C" "strftime width" } */
+  strftime (s, m, "%^A", tp); /* { dg-warning "C" "strftime flags" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_cast-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_cast-1.c
@@ -0,0 +1,17 @@
+/* Test for strings cast through integer types: should not be treated
+   as format strings unless the types are of the same width as
+   pointers (intptr_t or similar).  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+f (int x)
+{
+  printf("%s", x); /* { dg-warning "format" } */
+  printf((char *)(size_t)"%s", x); /* { dg-warning "format" } */
+  printf((char *)(char)"%s", x); /* { dg-warning "cast from pointer to integer of different size" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-1.c
@@ -0,0 +1,40 @@
+/* Test for warnings for missing format attributes.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  vprintf (fmt, ap); /* { dg-warning "candidate" "printf attribute warning" } */
+  va_end (ap);
+}
+
+void
+bar (const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  vscanf (fmt, ap); /* { dg-warning "candidate" "scanf attribute warning" } */
+  va_end (ap);
+}
+
+__attribute__((__format__(__ms_printf__, 1, 2))) void
+foo2 (const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  vprintf (fmt, ap);
+  va_end (ap);
+}
+
+void
+vfoo (const char *fmt, va_list arg)
+{
+  vprintf (fmt, arg); /* { dg-warning "candidate" "printf attribute warning 2" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-2.c
@@ -0,0 +1,17 @@
+/* Test for warnings for missing format attributes.  Don't warn if no
+   relevant parameters for a format attribute; see c/1017.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, ...)
+{
+  va_list ap;
+  va_start (ap, i);
+  vprintf ("Foo %s bar %s", ap); /* { dg-bogus "candidate" "bogus printf attribute warning" } */
+  va_end (ap);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-3.c
@@ -0,0 +1,27 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+void
+foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
+{
+  noattr_t na1 = na;
+  noattr_t na2 = a; /* { dg-warning "candidate" "initialization warning" } */
+  attr_t a1 = na;
+  attr_t a2 = a;
+
+  vnoattr_t vna1 = vna;
+  vnoattr_t vna2 = va; /* { dg-warning "candidate" "initialization warning" } */
+  vattr_t va1 = vna;
+  vattr_t va2 = va;
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-4.c
@@ -0,0 +1,33 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+void
+foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
+{
+  noattr_t na1, na2;
+  attr_t a1, a2;
+
+  vnoattr_t vna1, vna2;
+  vattr_t va1, va2;
+
+  na1 = na;
+  na2 = a; /* { dg-warning "candidate" "assignment warning" } */
+  a1 = na;
+  a2 = a;
+
+  vna1 = vna;
+  vna2 = va; /* { dg-warning "candidate" "assignment warning" } */
+  va1 = vna;
+  va1 = va;
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-5.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-5.c
@@ -0,0 +1,49 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+noattr_t
+foo1 (noattr_t na, attr_t a, int i)
+{
+  if (i)
+    return na;
+  else
+    return a; /* { dg-warning "candidate" "return type warning" } */
+}
+
+attr_t
+foo2 (noattr_t na, attr_t a, int i)
+{
+  if (i)
+    return na;
+  else
+    return a;
+}
+
+vnoattr_t
+foo3 (vnoattr_t vna, vattr_t va, int i)
+{
+  if (i)
+    return vna;
+  else
+    return va; /* { dg-warning "candidate" "return type warning" } */
+}
+
+vattr_t
+foo4 (vnoattr_t vna, vattr_t va, int i)
+{
+  if (i)
+    return vna;
+  else
+    return va;
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-6.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-6.c
@@ -0,0 +1,32 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+extern void foo1 (noattr_t);
+extern void foo2 (attr_t);
+extern void foo3 (vnoattr_t);
+extern void foo4 (vattr_t);
+
+void
+foo (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
+{
+  foo1 (na);
+  foo1 (a); /* { dg-warning "candidate" "parameter passing warning" } */
+  foo2 (na);
+  foo2 (a);
+
+  foo3 (vna);
+  foo3 (va); /* { dg-warning "candidate" "parameter passing warning" } */
+  foo4 (vna);
+  foo4 (va);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_multattr-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_multattr-1.c
@@ -0,0 +1,51 @@
+/* Test for multiple format attributes.  Test for printf and scanf attributes
+   together.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* If we specify multiple attributes for a single function, they should
+   all apply.  This should apply whether they are on the same declaration
+   or on different declarations.  */
+
+extern void my_vprintf_scanf (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_printf__, 1, 0)))
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern void my_vprintf_scanf2 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)))
+     __attribute__((__format__(__ms_printf__, 1, 0)));
+
+extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_printf__, 1, 0)));
+extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_printf__, 1, 0)));
+
+void
+foo (va_list ap, int *ip, long *lp)
+{
+  my_vprintf_scanf ("%d", ap, "%d", ip);
+  my_vprintf_scanf ("%d", ap, "%ld", lp);
+  my_vprintf_scanf ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf2 ("%d", ap, "%d", ip);
+  my_vprintf_scanf2 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf2 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf2 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf3 ("%d", ap, "%d", ip);
+  my_vprintf_scanf3 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf3 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf3 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf4 ("%d", ap, "%d", ip);
+  my_vprintf_scanf4 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf4 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf4 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_multattr-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_multattr-2.c
@@ -0,0 +1,40 @@
+/* Test for multiple format attributes.  Test for printf and scanf attributes
+   together, in different places on the declarations.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* If we specify multiple attributes for a single function, they should
+   all apply, wherever they are placed on the declarations.  */
+
+extern __attribute__((__format__(__ms_printf__, 1, 0))) void
+     my_vprintf_scanf (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern void (__attribute__((__format__(__ms_printf__, 1, 0))) my_vprintf_scanf2)
+     (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern __attribute__((__format__(__ms_scanf__, 3, 4))) void
+     (__attribute__((__format__(__ms_printf__, 1, 0))) my_vprintf_scanf3)
+     (const char *, va_list, const char *, ...);
+
+void
+foo (va_list ap, int *ip, long *lp)
+{
+  my_vprintf_scanf ("%d", ap, "%d", ip);
+  my_vprintf_scanf ("%d", ap, "%ld", lp);
+  my_vprintf_scanf ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf2 ("%d", ap, "%d", ip);
+  my_vprintf_scanf2 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf2 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf2 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf3 ("%d", ap, "%d", ip);
+  my_vprintf_scanf3 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf3 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf3 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_multattr-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_multattr-3.c
@@ -0,0 +1,29 @@
+/* Test for multiple format_arg attributes.  Test for both branches
+   getting checked.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+extern char *ngettext (const char *, const char *, unsigned long int)
+     __attribute__((__format_arg__(1))) __attribute__((__format_arg__(2)));
+
+void
+foo (long l, int nfoo)
+{
+  printf (ngettext ("%d foo", "%d foos", nfoo), nfoo);
+  printf (ngettext ("%d foo", "%d foos", l), l); /* { dg-warning "int" "wrong type in conditional expr" } */
+  printf (ngettext ("%d foo", "%ld foos", l), l); /* { dg-warning "int" "wrong type in conditional expr" } */
+  printf (ngettext ("%ld foo", "%d foos", l), l); /* { dg-warning "int" "wrong type in conditional expr" } */
+  /* Should allow one case to have extra arguments.  */
+  printf (ngettext ("1 foo", "%d foos", nfoo), nfoo);
+  printf (ngettext ("1 foo", "many foos", nfoo), nfoo); /* { dg-warning "too many" "too many args in all branches" } */
+  printf (ngettext ("", "%d foos", nfoo), nfoo);
+  printf (ngettext ("1 foo", (nfoo > 0) ? "%d foos" : "no foos", nfoo), nfoo);
+  printf (ngettext ("%d foo", (nfoo > 0) ? "%d foos" : "no foos", nfoo), nfoo);
+  printf (ngettext ("%ld foo", (nfoo > 0) ? "%d foos" : "no foos", nfoo), nfoo); /* { dg-warning "long int" "wrong type" } */
+  printf (ngettext ("%d foo", (nfoo > 0) ? "%ld foos" : "no foos", nfoo), nfoo); /* { dg-warning "long int" "wrong type" } */
+  printf (ngettext ("%d foo", (nfoo > 0) ? "%d foos" : "%ld foos", nfoo), nfoo); /* { dg-warning "long int" "wrong type" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-1.c
@@ -0,0 +1,15 @@
+/* Test for warnings for extra format arguments being disabled by
+   -Wno-format-extra-args.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wno-format-extra-args" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i)
+{
+  printf ("foo", i);
+  printf ("%1$d", i, i);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-2.c
@@ -0,0 +1,28 @@
+/* Test for warnings for extra format arguments being disabled by
+   -Wno-format-extra-args.  Test which warnings still apply with $
+   operand numbers.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wno-format-extra-args" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, int *ip, va_list va)
+{
+  printf ("%3$d%1$d", i, i, i); /* { dg-warning "before used" "unused $ operand" } */
+  printf ("%2$d%1$d", i, i, i);
+  vprintf ("%3$d%1$d", va); /* { dg-warning "before used" "unused $ operand" } */
+  /* With scanf formats, gaps in the used arguments are allowed only if the
+     arguments are all pointers.  In such a case, should only give the lesser
+     warning about unused arguments rather than the more serious one about
+     argument gaps.  */
+  scanf ("%3$d%1$d", ip, ip, ip);
+  /* If there are non-pointer arguments unused at the end, this is also OK.  */
+  scanf ("%3$d%1$d", ip, ip, ip, i);
+  scanf ("%3$d%1$d", ip, i, ip); /* { dg-warning "before used" "unused $ scanf non-pointer operand" } */
+  /* Can't check the arguments in the vscanf case, so should suppose the
+     lesser problem.  */
+  vscanf ("%3$d%1$d", va);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_no-y2k-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_no-y2k-1.c
@@ -0,0 +1,13 @@
+/* Test for warnings for Y2K problems not being on by default.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  strftime (s, m, "%y%c%x", tp);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-1.c
@@ -0,0 +1,14 @@
+/* Test for warnings for non-string-literal formats.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wformat-nonliteral" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t i)
+{
+  printf ((const char *)i, i); /* { dg-warning "argument types" "non-literal" } */
+  printf (s, i); /* { dg-warning "argument types" "non-literal" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-2.c
@@ -0,0 +1,14 @@
+/* Test for warnings for non-string-literal formats.  Test with -Wformat=2.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat=2" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t i)
+{
+  printf ((const char *)i, i); /* { dg-warning "argument types" "non-literal" } */
+  printf (s, i); /* { dg-warning "argument types" "non-literal" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-3.c
@@ -0,0 +1,13 @@
+/* Test for warnings for non-string-literal formats.  Test for strftime formats.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wformat-nonliteral" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp, char *fmt)
+{
+  strftime (s, m, fmt, tp); /* { dg-warning "format string" "non-literal" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nul-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nul-1.c
@@ -0,0 +1,15 @@
+/* Test diagnostics for suppressing contains nul
+   -Wformat.  -Wformat.  */
+/* Origin: Bruce Korb <bkorb@gnu.org> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat -Wno-format-contains-nul" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (void)
+{
+  static char const fmt[] = "x%s\0%s\n\0abc";
+  printf (fmt+4, fmt+8); /* { dg-bogus "embedded.*in format" "bogus embed warning" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nul-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nul-2.c
@@ -0,0 +1,17 @@
+/* Test diagnostics for options used on their own without
+   -Wformat.  -Wformat-.  */
+/* Origin: Bruce Korb <bkorb@gnu.org> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+
+/* { dg-warning "embedded .* in format" "ignored" { target *-*-* } 0 } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+fumble (void)
+{
+  static char const fmt[] = "x%s\0%s\n\0abc";
+  printf (fmt+4, fmt+8);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_null-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_null-1.c
@@ -0,0 +1,28 @@
+/* Test for some aspects of null format string handling.  */
+/* Origin: Jason Thorpe <thorpej@wasabisystems.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+extern void my_printf (const char *, ...) __attribute__((format(ms_printf,1,2)));
+extern const char *my_format (const char *, const char *)
+  __attribute__((format_arg(2)));
+
+void
+foo (int i1)
+{
+  /* Warning about a null format string has been decoupled from the actual
+     format check.  However, we still expect to be warned about any excess
+     arguments after a null format string.  */
+  my_printf (NULL);
+  my_printf (NULL, i1); /* { dg-warning "too many" "null format with arguments" } */
+
+  my_printf (my_format ("", NULL));
+  my_printf (my_format ("", NULL), i1); /* { dg-warning "too many" "null format_arg with arguments" } */
+
+  /* While my_printf allows a null argument, dgettext does not, so we expect
+     a null argument warning here.  */
+  my_printf (dgettext ("", NULL)); /* { dg-warning "null" "null format with dgettext" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_plus-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_plus-1.c
@@ -0,0 +1,21 @@
+/* Test for printf formats using string literal plus constant.
+ */
+/* Origin: Jakub Jelinek <jakub@redhat.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat=2" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i)
+{
+  printf ("%%d\n" + 1, i);
+  printf (5 + "%.-*d%3d\n", i);
+  printf ("%d%d" + 2, i, i);	/* { dg-warning "arguments" "wrong number of args" } */
+  printf (3 + "%d\n");		/* { dg-warning "zero-length" "zero-length string" } */
+  printf ("%d\n" + i, i);	/* { dg-warning "not a string" "non-constant addend" } */
+  printf ("%d\n" + 10);		/* { dg-warning "not a string" "too large addend" } */
+  printf ("%d\n" - 1, i);	/* { dg-warning "not a string" "minus constant" } */
+  printf ("%d\n" + -1, i);	/* { dg-warning "not a string" "negative addend" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_sec-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_sec-1.c
@@ -0,0 +1,13 @@
+/* Test for security warning when non-literal format has no arguments.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wformat-security" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s)
+{
+  printf (s); /* { dg-warning "no format arguments" "security warning" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_unnamed-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_unnamed-1.c
@@ -0,0 +1,24 @@
+/* Test for warnings with possibly unnamed integer types.  Bug 24329.  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+/* { dg-options "-Wformat -msse" { target { { i?86-*-* x86_64-*-* } && ilp32 } } } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* Definition of TItype follows same logic as in gcc.dg/titype-1.c,
+   but must be a #define to avoid giving the type a name.  */
+#if defined(__LP64__) && !defined(__hppa__)
+#define TItype int __attribute__ ((mode (TI)))
+#else
+#define TItype long
+#endif
+
+void
+f (TItype x)
+{
+  printf("%d", x); /* { dg-warning "expects type" } */
+  printf("%d", 141592653589793238462643383279502884197169399375105820974944); /* { dg-warning "expects type" } */
+  /* { dg-warning "unsigned only|too large" "constant" { target *-*-* } 22 } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_va-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_va-1.c
@@ -0,0 +1,14 @@
+/* Test for strange warning in format checking.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (void *p)
+{
+  printf ("%d", p); /* { dg-bogus "va_list" "wrong type in format warning" } */
+  /* { dg-warning "format" "format error" { target *-*-* } 12 } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_warnll-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_warnll-1.c
@@ -0,0 +1,19 @@
+/* Test for printf formats.  C99 "long long" formats should be accepted with
+   -Wno-long-long.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wno-long-long" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (long long ll, unsigned long long ull, long long *lln,
+     long long *llp, unsigned long long *ullp)
+{
+  /* Test for accepting standard "long long" formats.  */
+  printf ("%I64d%I64i%I64o%I64u%I64x%I64X%I64n", ll, ll, ull, ull, ull, ull, lln);
+  scanf ("%I64d%I64i%I64o%I64u%I64x%I64X%I64n", llp, llp,
+	 ullp, ullp, ullp, ullp, lln);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_zero-length-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_zero-length-1.c
@@ -0,0 +1,16 @@
+/* Test the -Wno-format-zero-length option, which suppresses warnings
+   about zero-length formats.  */
+/* Origin: Jason Thorpe <thorpej@wasabisystems.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wno-format-zero-length" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (void)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.1 (pages 131-134).  */
+  /* Zero-length format strings are allowed.  */
+  printf ("");
+}
Index: gcc/gcc/testsuite/gcc.dg/format/multattr-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/multattr-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/multattr-1.c
@@ -4,6 +4,7 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 /* If we specify multiple attributes for a single function, they should
@@ -11,22 +12,22 @@
    or on different declarations.  */
 
 extern void my_vprintf_scanf (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__printf__, 1, 0)))
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)))
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
 extern void my_vprintf_scanf2 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)))
-     __attribute__((__format__(__printf__, 1, 0)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)))
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)));
 
 extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__printf__, 1, 0)));
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)));
 extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
 extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__printf__, 1, 0)));
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)));
 
 void
 foo (va_list ap, int *ip, long *lp)
Index: gcc/gcc/testsuite/gcc.dg/format/multattr-2.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/multattr-2.c
+++ gcc/gcc/testsuite/gcc.dg/format/multattr-2.c
@@ -4,21 +4,22 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 /* If we specify multiple attributes for a single function, they should
    all apply, wherever they are placed on the declarations.  */
 
-extern __attribute__((__format__(__printf__, 1, 0))) void
+extern __attribute__((__format__(gnu_attr___printf__, 1, 0))) void
      my_vprintf_scanf (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
-extern void (__attribute__((__format__(__printf__, 1, 0))) my_vprintf_scanf2)
+extern void (__attribute__((__format__(gnu_attr___printf__, 1, 0))) my_vprintf_scanf2)
      (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
-extern __attribute__((__format__(__scanf__, 3, 4))) void
-     (__attribute__((__format__(__printf__, 1, 0))) my_vprintf_scanf3)
+extern __attribute__((__format__(gnu_attr___scanf__, 3, 4))) void
+     (__attribute__((__format__(gnu_attr___printf__, 1, 0))) my_vprintf_scanf3)
      (const char *, va_list, const char *, ...);
 
 void
Index: gcc/gcc/testsuite/gcc.dg/format/null-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/null-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/null-1.c
@@ -3,9 +3,10 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern void my_printf (const char *, ...) __attribute__((format(printf,1,2)));
+extern void my_printf (const char *, ...) __attribute__((format(gnu_attr_printf,1,2)));
 extern const char *my_format (const char *, const char *)
   __attribute__((format_arg(2)));
 
=

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf        formatters to c-format.c
  2008-02-01 11:04 ` Kai Tietz
@ 2008-02-01 15:52   ` Joseph S. Myers
  2008-02-04 14:23     ` Kai Tietz
  0 siblings, 1 reply; 61+ messages in thread
From: Joseph S. Myers @ 2008-02-01 15:52 UTC (permalink / raw)
  To: Kai Tietz; +Cc: Danny Smith, GCC Patches, NightStrike

On Fri, 1 Feb 2008, Kai Tietz wrote:

> For the testcases c90-scanf-4.c and c90-printf-3.c may it would be better 
> to avoid their build for mingw targets at all. So how can I specify not to 
> run a test far a specific target?

See the documentation of selector expressions in doc/sourcebuild.texi.  
But you could also only add the attributes conditionally:

#if (existing condition for only adding attributes in tests on Windows)
#if !defined __STRICT_ANSI__ || __STDC_VERSION__ >= 199901L
/* Can add attributes to C99 functions.  */
#endif
#endif

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf       formatters to c-format.c
       [not found] <Pine.LNX.4.64.0801312346090.5937@digraph.polyomino.org.uk>
@ 2008-02-01 11:04 ` Kai Tietz
  2008-02-01 15:52   ` Joseph S. Myers
  0 siblings, 1 reply; 61+ messages in thread
From: Kai Tietz @ 2008-02-01 11:04 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: Danny Smith, GCC Patches, NightStrike

"Joseph S. Myers" wrote on 01.02.2008 00:56:40:

> On Wed, 16 Jan 2008, Kai Tietz wrote:
> 
> > ChangeLog of gcc/:
> > 2008-01-15      Kai Tietz  <kai.tietz@onevision.com>
> > 
> >         * gcc/c-format.h: Add structure target_ovr_attr to hold
> 
> You need to remove the gcc/ from this and subsequent names in this 
> ChangeLog.
> 
> > +static const char *
> > +replace_formatter_name_to_system_name (const char *attr_name)
> 
> You need a comment above this function explaining what it does 
(including 
> the significance of the parameter and the return value.
> 
> > +  if (attr_name == NULL || *attr_name == 0 || strncmp (attr_name,
> "gcc_", 4) == 0)
> 
> Please try to keep source lines under 80 characters wide, here and 
> elsewhere.
> 
> > +/* Compare the target override format attribute by treating 
> double underscore syntax.  */
> > +static int
> > +compare_tofa (const char *tattr_name, const char *attr_name)
> 
> The comment needs to explain the parameters and the return value. "tofa" 

> is also cryptic; a longer, more descriptive, function name might be 
> better.
> 
> > +/* For custom types we need to compare in a special way.  */
> > +static int compare_format_types (int custom_type, int def_type)
> 
> Again, explain the parameters and return types; this comment isn't 
> explaining the function interface at all.  The formatting should be:
> 
> static int
> compare_format_types (int custom_type, int def_type)
> 
> > +@defmac TARGET_OVERRIDES_FORMAT_ATTRIBUTES
> > +If defined, this macro is the name of a global variable containg
> > +target-specific format overrides for the @option{-Wformat} option. 
The
> > +default is to have no target-specific format overrides. This depends, 
that
> > +@code{TARGET_FORMAT_TYPES} is defined too.
> > +@end defmac
> 
> The last sentence "This depends, that code{TARGET_FORMAT_TYPES} is 
defined 
> too." doesn't make sense to me.
> 
> > +@defmac TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT
> > +If defined, this macro is the number of entries in
> > +@code{}.
> > +@end defmac
> 
> This (in particular the empty @code{}) is clearly incomplete.
> 
> > Index: gcc/gcc/testsuite/gcc.dg/format/c90-printf-3.c
> > ===================================================================
> > --- gcc.orig/gcc/testsuite/gcc.dg/format/c90-printf-3.c
> > +++ gcc/gcc/testsuite/gcc.dg/format/c90-printf-3.c
> > @@ -17,8 +17,8 @@ foo (int i, char *s, size_t n, va_list v
> >    printf ("%d", i);
> >    printf ("%ld", i); /* { dg-warning "format" "printf" } */
> >    /* The "unlocked" functions shouldn't warn in c90 mode.  */
> > -  fprintf_unlocked (stdout, "%ld", i); /* { dg-bogus "format" 
> "fprintf_unlocked" } */
> > -  printf_unlocked ("%ld", i); /* { dg-bogus "format" 
"printf_unlocked" } */
> > +  fprintf_unlocked (stdout, "%ld", i); /* { dg-warning "format" 
> "fprintf_unlocked" } */
> > +  printf_unlocked ("%ld", i); /* { dg-warning "format" 
> "printf_unlocked" } */
> 
> You are changing the test in a way that contradicts its purpose.  The 
> whole point of the tests of non-C90 functions in this file is to assert 
> that those functions do not receive default attributes in strict C90 
mode; 
> you'll need to find some way to avoid giving them explicit attributes 
for 
> this file.
> 
> > Index: gcc/gcc/testsuite/gcc.dg/format/c90-scanf-4.c
> 
> Likewise here.
> 
> > Index: gcc/gcc/testsuite/gcc.dg/format/c99-printf-3.c
> 
> Likewise here.

Ok, corrected the documentation so far and renamed the tofa function to a 
more suitable name and tried to avoid lines of 80 characters.

For the testcases c90-scanf-4.c and c90-printf-3.c may it would be better 
to avoid their build for mingw targets at all. So how can I specify not to 
run a test far a specific target?

Regards,
 i.A. Kai Tietz

|  (\_/)  This is Bunny. Copy and paste Bunny
| (='.'=) into your signature to help him gain
| (")_(") world domination.

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf      formatters to c-format.c
@ 2008-01-16 16:14 Kai Tietz
  0 siblings, 0 replies; 61+ messages in thread
From: Kai Tietz @ 2008-01-16 16:14 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: Danny Smith, GCC Patches, NightStrike

[-- Attachment #1: Type: text/plain, Size: 7066 bytes --]

Hi all,

Sorry, I missed the precision definition for printf (e.g. something like 
%2.2x). So I corrected it in msformat-c.c file.
BTW: I found by this already an issue in binutils for mingw. The binutils 
assumes that 'll' length specifier is valid for mingw, which isn't true. 
So I think, this patch seems to be very useful.

"Joseph S. Myers" wrote on 08.01.2008 17:51:58:

> On Tue, 8 Jan 2008, Kai Tietz wrote:
> 
> >         * gcc/testsuite/gcc.dg/format/format.h: Add for mingw the gnu 
> > style printf prototypes.
> > 
> > Do you think it is ok for apply ?
> 
> The general approach is plausible, but the patch still needs full test 
> coverage for the MinGW formats before it's ready for review.  Every C90, 

> C99, X/Open or GNU format feature not present on Windows should have a 
> MinGW-specific test assertion added to the testsuite that the use of 
that 
> feature is diagnosed, which every such feature present on Windows should 

> have a MinGW-specific test assertion added that the feature is not 
> diagnosed.  (The effect should be that every entry in the MinGW format 
> datastructures is tested, and every difference from the GNU format 
> datastructures.)  When you have a patch ready with such tests, please 
> confirm that all the format tests pass cleanly with it applied for both 
> MinGW and non-MinGW targets; then it will be ready for review.

This patch includes the testcases for format for gnu and mingw style.

ChangeLog for gcc/testcase

2008-01-15  Kai Tietz  <kai.tietz@onevision.com>

        * gcc.dg/format/ms_array-1.c: New.
        * gcc.dg/format/ms_c90-scanf-3.c: New.
        * gcc.dg/format/ms_c99-strftime-1.c: New.
        * gcc.dg/format/ms_no-y2k-1.c: New.
        * gcc.dg/format/ms_attr-1.c: New.
        * gcc.dg/format/ms_c90-scanf-4.c: New.
        * gcc.dg/format/ms_c99-strftime-2.c: New.
        * gcc.dg/format/ms_nonlit-1.c: New.
        * gcc.dg/format/ms_c90-scanf-5.c: New.
        * gcc.dg/format/ms_cast-1.c: New.
        * gcc.dg/format/ms_nonlit-2.c: New.
        * gcc.dg/format/ms_attr-2.c: New.
        * gcc.dg/format/ms_c90-strftime-1.c: New.
        * gcc.dg/format/ms_miss-1.c: New.
        * gcc.dg/format/ms_nonlit-3.c: New.
        * gcc.dg/format/ms_attr-3.c: New.
        * gcc.dg/format/ms_c90-strftime-2.c: New.
        * gcc.dg/format/ms_miss-2.c: New.
        * gcc.dg/format/ms_nul-1.c: New.
        * gcc.dg/format/ms_attr-4.c: New.
        * gcc.dg/format/ms_c94-printf-1.c: New.
        * gcc.dg/format/ms_miss-3.c: New.
        * gcc.dg/format/ms_nul-2.c: New.
        * gcc.dg/format/ms_attr-7.c: New.
        * gcc.dg/format/ms_c94-scanf-1.c: New.
        * gcc.dg/format/ms_miss-4.c: New.
        * gcc.dg/format/ms_null-1.c: New.
        * gcc.dg/format/ms_bitfld-1.c: New.
        * gcc.dg/format/ms_c99-printf-1.c: New.
        * gcc.dg/format/ms_miss-5.c: New.
        * gcc.dg/format/ms_plus-1.c: New.
        * gcc.dg/format/ms_branch-1.c: New.
        * gcc.dg/format/ms_c99-printf-2.c: New.
        * gcc.dg/format/ms_miss-6.c: New.
        * gcc.dg/format/ms_sec-1.c: New.
        * gcc.dg/format/ms_c90-printf-1.c: New.
        * gcc.dg/format/ms_c99-printf-3.c: New.
        * gcc.dg/format/ms_multattr-1.c: New.
        * gcc.dg/format/ms_unnamed-1.c: New.
        * gcc.dg/format/ms_c90-printf-2.c: New.
        * gcc.dg/format/ms_c99-scanf-1.c: New.
        * gcc.dg/format/ms_multattr-2.c: New.
        * gcc.dg/format/ms_va-1.c: New.
        * gcc.dg/format/ms_c90-printf-3.c: New.
        * gcc.dg/format/ms_c99-scanf-2.c: New.
        * gcc.dg/format/ms_multattr-3.c: New.
        * gcc.dg/format/ms_warnll-1.c: New.
        * gcc.dg/format/ms_c90-scanf-1.c: New.
        * gcc.dg/format/ms_c99-scanf-3.c: New.
        * gcc.dg/format/ms_no-exargs-1.c: New.
        * gcc.dg/format/ms_zero-length-1.c: New.
        * gcc.dg/format/ms_c90-scanf-2.c: New.
        * gcc.dg/format/ms_c99-scanf-4.c: New.
        * gcc.dg/format/ms_no-exargs-2.c: New.
        * gcc.dg/format/sys_formatter.c: New.
        * gcc.dg/format/null-1.c: Add gnu style usage for mingw.
        * gcc.dg/format/miss-1.c: Likewise.
        * gcc.dg/format/miss-3.c: Likewise.
        * gcc.dg/format/multattr-2.c: Likewise.
        * gcc.dg/format/miss-5.c: Likewise.
        * gcc.dg/format/attr-2.c: Likewise.
        * gcc.dg/format/attr-4.c: Likewise.
        * gcc.dg/format/c90-scanf-4.c: Likewise.
        * gcc.dg/format/c99-printf-3.c: Likewise.
        * gcc.dg/format/multattr-1.c: Likewise.
        * gcc.dg/format/miss-4.c: Likewise.
        * gcc.dg/format/miss-6.c: Likewise.
        * gcc.dg/format/c90-printf-3.c: Likewise.
        * gcc.dg/format/attr-1.c: Likewise.
        * gcc.dg/format/attr-3.c: Likewise.
        * gcc.dg/format/attr-7.c: Likewise.
        * gcc.dg/format/format.h: Treat mingw and gnu style.

ChangeLog of gcc/:
2008-01-15      Kai Tietz  <kai.tietz@onevision.com>

        * c-format.c: (replace_formatter_name_to_system_name): New.
        (compare_tofa): New.
        (compare_format_types): New.
        (decode_format_attr): Use of 
replace_formatter_name_to_system_name.
        (format_types_orig): Add gnu_ prefix to names.
        (check_format_info_main): Special treating of \0 escaped names for
        supporting multi-character formatters as I32, I64.
        (TARGET_OVERRIDES_FORMAT_ATTRIBUTES): Use of user defined 
attributes.
        (gnu_target_overrides_format_attributes): New.
        * gcc/c-format.h: Add structure target_ovr_attr to hold
        system specific formatter names.
        (ovr_format_type): New enum.
        * gcc/config.gcc: Add for x86&x86_64 cygwin and mingw32 targets 
the
        msformat-c.o file to c_target_objs and cxx_target_objs.
        * gcc/config/i386/mingw32.h: (TARGET_OVERRIDES_FORMAT_ATTRIBUTES): 
New.
        (TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT): New.
        (TARGET_N_FORMAT_TYPES): New.
        * gcc/config/i386/msformat-c.c: New.
        * gcc/config/i386/t-cygming: Add build rule for msformat-c.o.
        * gcc/doc/extend.texi: Add new format names gnu_* and ms_*.
        * gcc/doc/tm.texi: (TARGET_OVERRIDES_FORMAT_ATTRIBUTES): New.

Is this ok for review ?

Cheers,
 i.A. Kai Tietz



|  (\_/)  This is Bunny. Copy and paste Bunny
| (='.'=) into your signature to help him gain
| (")_(") world domination.

------------------------------------------------------------------------------------------
  OneVision Software Entwicklungs GmbH & Co. KG
  Dr.-Leo-Ritter-Straße 9 - 93049 Regensburg
  Tel: +49.(0)941.78004.0 - Fax: +49.(0)941.78004.489 - www.OneVision.com
  Commerzbank Regensburg - BLZ 750 400 62 - Konto 6011050
  Handelsregister: HRA 6744, Amtsgericht Regensburg
  Komplementärin: OneVision Software Entwicklungs Verwaltungs GmbH
  Dr.-Leo-Ritter-Straße 9 – 93049 Regensburg
  Handelsregister: HRB 8932, Amtsgericht Regensburg - Geschäftsführer: 
Ulrike Döhler, Manuela Kluger


[-- Attachment #2: mingw-msformat.txt --]
[-- Type: text/plain, Size: 161164 bytes --]

Index: gcc/gcc/c-format.c
===================================================================
--- gcc.orig/gcc/c-format.c
+++ gcc/gcc/c-format.c
@@ -74,13 +74,15 @@ typedef struct function_format_info
 
 static bool decode_format_attr (tree, function_format_info *, int);
 static int decode_format_type (const char *);
+static int compare_format_types (int ctype, int def_type);
 
 static bool check_format_string (tree argument,
 				 unsigned HOST_WIDE_INT format_num,
 				 int flags, bool *no_add_attrs);
 static bool get_constant (tree expr, unsigned HOST_WIDE_INT *value,
 			  int validated_p);
-
+static const char *replace_formatter_name_to_system_name (const char *attr_name);
+static int compare_tofa (const char *tattr_name, const char *attr_name);
 
 /* Handle a "format_arg" attribute; arguments as in
    struct attribute_spec.handler.  */
@@ -191,6 +193,8 @@ decode_format_attr (tree args, function_
     {
       const char *p = IDENTIFIER_POINTER (format_type_id);
 
+      p = replace_formatter_name_to_system_name (p);
+
       info->format_type = decode_format_type (p);
 
       if (info->format_type == format_type_error)
@@ -715,7 +719,7 @@ static const format_char_info monetary_c
 /* This must be in the same order as enum format_type.  */
 static const format_kind_info format_types_orig[] =
 {
-  { "printf",   printf_length_specs,  print_char_table, " +#0-'I", NULL,
+  { "gnu_printf",   printf_length_specs,  print_char_table, " +#0-'I", NULL,
     printf_flag_specs, printf_flag_pairs,
     FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
     'w', 0, 'p', 0, 'L', 0,
@@ -757,18 +761,18 @@ static const format_kind_info format_typ
     0, 0, 0, 0, 0, 0,
     NULL, NULL
   },
-  { "scanf",    scanf_length_specs,   scan_char_table,  "*'I", NULL,
+  { "gnu_scanf",    scanf_length_specs,   scan_char_table,  "*'I", NULL,
     scanf_flag_specs, scanf_flag_pairs,
     FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
     'w', 0, 0, '*', 'L', 'm',
     NULL, NULL
   },
-  { "strftime", NULL,                 time_char_table,  "_-0^#", "EO",
+  { "gnu_strftime", NULL,                 time_char_table,  "_-0^#", "EO",
     strftime_flag_specs, strftime_flag_pairs,
     FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0, 0,
     NULL, NULL
   },
-  { "strfmon",  strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
+  { "gnu_strfmon",  strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
     strfmon_flag_specs, strfmon_flag_pairs,
     FMT_FLAG_ARG_CONVERT, 'w', '#', 'p', 0, 'L', 0,
     NULL, NULL
@@ -847,6 +851,8 @@ decode_format_type (const char *s)
 {
   int i;
   int slen;
+
+  s = replace_formatter_name_to_system_name (s);
   slen = strlen (s);
   for (i = 0; i < n_format_types; i++)
     {
@@ -1776,7 +1782,22 @@ check_format_info_main (format_check_res
       if (fli)
 	{
 	  while (fli->name != 0 && fli->name[0] != *format_chars)
-	    fli++;
+	    {
+	      if (fli->name[0] == '\0')
+		{
+		  int si  = strlen (fli->name + 1) + 1;
+		  int i = 1;
+		  while (fli->name[i] != 0 && fli->name[i] == format_chars [i - 1])
+		    ++i;
+		 if (si == i)
+		   {
+		     if (si > 2)
+		       format_chars += si - 2;
+		     break;
+		   }
+	       }
+	      fli++;
+	    }
 	  if (fli->name != 0)
 	    {
 	      format_chars++;
@@ -2703,6 +2724,72 @@ init_dynamic_diag_info (void)
 extern const format_kind_info TARGET_FORMAT_TYPES[];
 #endif
 
+#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+extern const target_ovr_attr TARGET_OVERRIDES_FORMAT_ATTRIBUTES[];
+#endif
+
+/* Description of gnu specific format attributes reflected to
+   system format attribute types, as printf, scanf, strftime, and
+   strfmon.  */
+const target_ovr_attr gnu_target_overrides_format_attributes[] =
+{
+  { "gnu_printf",   "printf", ovr_printf_format_type },
+  { "gnu_scanf",    "scanf", ovr_scanf_format_type },
+  { "gnu_strftime", "strftime", ovr_strftime_format_type },
+  { "gnu_strfmon",  "strfmon", ovr_strfmon_format_type },
+  { NULL,           NULL, -1 }
+};
+
+static const char *
+replace_formatter_name_to_system_name (const char *attr_name)
+{
+  int i;
+
+  if (attr_name == NULL || *attr_name == 0 || strncmp (attr_name, "gcc_", 4) == 0)
+    return attr_name;
+
+#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+  /* Check if format attribute is overridden by target.  */
+  if (TARGET_OVERRIDES_FORMAT_ATTRIBUTES != NULL && TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT > 0)
+    {
+      for (i = 0; i < TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT; ++i)
+        {
+          if (compare_tofa (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src, attr_name))
+            return attr_name;
+          if (compare_tofa (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_dst, attr_name))
+            return TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src;
+        }
+    }
+#endif
+  /* Otherwise default to gnu formatter.  */
+  for (i = 0; gnu_target_overrides_format_attributes[i].named_attr_src != NULL; ++i)
+    {
+      if (compare_tofa (gnu_target_overrides_format_attributes[i].named_attr_src, attr_name))
+        return attr_name;
+      if (compare_tofa (gnu_target_overrides_format_attributes[i].named_attr_dst, attr_name))
+        return gnu_target_overrides_format_attributes[i].named_attr_src;
+    }
+
+  return attr_name;
+}
+
+/* Compare the target override format attribute by treating double underscore syntax.  */
+static int
+compare_tofa (const char *tattr_name, const char *attr_name)
+{
+  int alen = strlen (attr_name);
+  int slen = (tattr_name ? strlen (tattr_name) : 0);
+  if (alen > 4 && attr_name[0] == '_' && attr_name[1] == '_'
+      && attr_name[alen - 1] == '_' && attr_name[alen - 2] == '_')
+    {
+      attr_name += 2;
+      alen -= 4;
+    }
+  if (alen != slen || strncmp (tattr_name, attr_name, alen) != 0)
+    return 0;
+  return 1;
+}
+
 /* Handle a "format" attribute; arguments as in
    struct attribute_spec.handler.  */
 tree
@@ -2762,7 +2849,7 @@ handle_format_attribute (tree *node, tre
 	}
     }
 
-  if (info.format_type == strftime_format_type && info.first_arg_num != 0)
+  if (compare_format_types (info.format_type, strftime_format_type) && info.first_arg_num != 0)
     {
       error ("strftime formats cannot format arguments");
       *no_add_attrs = true;
@@ -2771,12 +2858,12 @@ handle_format_attribute (tree *node, tre
 
   /* If this is a custom GCC-internal format type, we have to
      initialize certain bits a runtime.  */
-  if (info.format_type == asm_fprintf_format_type
-      || info.format_type == gcc_gfc_format_type
-      || info.format_type == gcc_diag_format_type
-      || info.format_type == gcc_tdiag_format_type
-      || info.format_type == gcc_cdiag_format_type
-      || info.format_type == gcc_cxxdiag_format_type)
+  if (compare_format_types (info.format_type, asm_fprintf_format_type)
+      || compare_format_types (info.format_type, gcc_gfc_format_type)
+      || compare_format_types (info.format_type, gcc_diag_format_type)
+      || compare_format_types (info.format_type, gcc_tdiag_format_type)
+      || compare_format_types (info.format_type, gcc_cdiag_format_type)
+      || compare_format_types (info.format_type, gcc_cxxdiag_format_type))
     {
       /* Our first time through, we have to make sure that our
 	 format_type data is allocated dynamically and is modifiable.  */
@@ -2787,18 +2874,18 @@ handle_format_attribute (tree *node, tre
 
       /* If this is format __asm_fprintf__, we have to initialize
 	 GCC's notion of HOST_WIDE_INT for checking %wd.  */
-      if (info.format_type == asm_fprintf_format_type)
+      if (compare_format_types (info.format_type, asm_fprintf_format_type))
 	init_dynamic_asm_fprintf_info ();
       /* If this is format __gcc_gfc__, we have to initialize GCC's
 	 notion of 'locus' at runtime for %L.  */
-      else if (info.format_type == gcc_gfc_format_type)
+      else if (compare_format_types (info.format_type, gcc_gfc_format_type))
 	init_dynamic_gfc_info ();
       /* If this is one of the diagnostic attributes, then we have to
 	 initialize 'location_t' and 'tree' at runtime.  */
-      else if (info.format_type == gcc_diag_format_type
-	       || info.format_type == gcc_tdiag_format_type
-	       || info.format_type == gcc_cdiag_format_type
-	       || info.format_type == gcc_cxxdiag_format_type)
+      else if (compare_format_types (info.format_type, gcc_diag_format_type)
+	       || compare_format_types (info.format_type, gcc_tdiag_format_type)
+	       || compare_format_types (info.format_type, gcc_cdiag_format_type)
+	       || compare_format_types (info.format_type, gcc_cxxdiag_format_type))
 	init_dynamic_diag_info ();
       else
 	gcc_unreachable ();
@@ -2806,3 +2893,36 @@ handle_format_attribute (tree *node, tre
 
   return NULL_TREE;
 }
+
+/* For custom types we need to compare in a special way.  */
+static int compare_format_types (int custom_type, int def_type)
+{
+  int i;
+  int n_format_types_org = ARRAY_SIZE (format_types_orig);
+  const char *name_custom = NULL;
+  if (custom_type < n_format_types_org)
+    return custom_type == def_type;
+#ifdef TARGET_FORMAT_TYPES
+  if (TARGET_N_FORMAT_TYPES <= 0
+      || ((custom_type - n_format_types_org) >= TARGET_N_FORMAT_TYPES))
+    return custom_type == def_type;
+
+  name_custom = TARGET_FORMAT_TYPES[custom_type - n_format_types_org].name;
+
+#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+  /* Check if format attribute is overridden by target.  */
+  if (TARGET_OVERRIDES_FORMAT_ATTRIBUTES != NULL && TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT > 0)
+    {
+      for (i = 0; i < TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT; ++i)
+        {
+          if (compare_tofa (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src, name_custom))
+            {
+	      custom_type = TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_type; break;
+	    }
+        }
+    }
+#endif
+
+#endif
+  return custom_type == def_type;
+}
Index: gcc/gcc/c-format.h
===================================================================
--- gcc.orig/gcc/c-format.h
+++ gcc/gcc/c-format.h
@@ -306,4 +306,28 @@ typedef struct
 #define T_D128  &dfloat128_type_node
 #define TEX_D128 { STD_EXT, "_Decimal128", T_D128 }
 
+/* Structure describing the target specific to be override formatter
+   attributes, e.g. printf, scanf, etc.  This allows to support different
+   runtime-library specific formatter attributes to co-exist and defining
+   a default system version.
+   This type is used for the pointer variable TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+   refers to.  */
+typedef struct
+{
+  /* The name of the to be copied formatter attribute. */
+  const char *named_attr_src;
+  /* The name of the to be overridden formatter attribute. */
+  const char *named_attr_dst;
+  /* Values of enum ovr_format_type.  */
+  int named_attr_type;
+} target_ovr_attr;
+
+/* Be aware to keep these values in synch with enum format_type from c-format.c.  */
+enum ovr_format_type { ovr_printf_format_type, ovr_asm_fprintf_format_type,
+		   ovr_gcc_diag_format_type, ovr_gcc_tdiag_format_type,
+		   ovr_gcc_cdiag_format_type,
+		   ovr_gcc_cxxdiag_format_type, ovr_gcc_gfc_format_type,
+		   ovr_scanf_format_type, ovr_strftime_format_type,
+		   ovr_strfmon_format_type, ovr_format_type_error = -1};
+
 #endif /* GCC_C_FORMAT_H */
Index: gcc/gcc/config.gcc
===================================================================
--- gcc.orig/gcc/config.gcc
+++ gcc/gcc/config.gcc
@@ -1359,8 +1359,8 @@ i[34567]86-*-pe | i[34567]86-*-cygwin*)
 	target_gtfiles="\$(srcdir)/config/i386/winnt.c"
 	extra_options="${extra_options} i386/cygming.opt"
 	extra_objs="winnt.o winnt-stubs.o"
-	c_target_objs=cygwin2.o
-	cxx_target_objs="cygwin2.o winnt-cxx.o"
+	c_target_objs="cygwin2.o msformat-c.o"
+	cxx_target_objs="cygwin2.o winnt-cxx.o msformat-c.o"
 	extra_gcc_objs=cygwin1.o
 	if test x$enable_threads = xyes; then
 		thread_file='posix'
@@ -1373,7 +1373,8 @@ i[34567]86-*-mingw32* | x86_64-*-mingw32
 	target_gtfiles="\$(srcdir)/config/i386/winnt.c"
 	extra_options="${extra_options} i386/cygming.opt"
 	extra_objs="winnt.o winnt-stubs.o"
-	cxx_target_objs=winnt-cxx.o
+	c_target_objs="msformat-c.o"
+	cxx_target_objs="winnt-cxx.o msformat-c.o"
 	default_use_cxa_atexit=yes
 	case ${enable_threads} in
 	  "" | yes | win32)
Index: gcc/gcc/config/i386/mingw32.h
===================================================================
--- gcc.orig/gcc/config/i386/mingw32.h
+++ gcc/gcc/config/i386/mingw32.h
@@ -143,6 +143,22 @@ do {						         \
    to register C++ static destructors.  */
 #define TARGET_CXX_USE_ATEXIT_FOR_CXA_ATEXIT hook_bool_void_true
 
+/* Contains a pointer to type target_ovr_attr defining the target specific
+   overrides of formatter attributs.  See format.h for structure definition.  */
+#undef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+#define TARGET_OVERRIDES_FORMAT_ATTRIBUTES mingw_formatter_attribute_overrides
+
+/* Specify the count of elements in TARGET_OVERRIDES_ATTRIBUTE.  */
+#undef TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT
+#define TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT 3
+
+/* MS specific format attributes for ms_printf, ms_scanf, ms_strftime.  */
+#undef TARGET_FORMAT_TYPES
+#define TARGET_FORMAT_TYPES mingw_formatter_attributes
+
+#undef TARGET_N_FORMAT_TYPES
+#define TARGET_N_FORMAT_TYPES 3
+
 /* JCR_SECTION works on mingw32.  */
 #undef TARGET_USE_JCR_SECTION
 #define TARGET_USE_JCR_SECTION 1
Index: gcc/gcc/config/i386/msformat-c.c
===================================================================
--- /dev/null
+++ gcc/gcc/config/i386/msformat-c.c
@@ -0,0 +1,188 @@
+/* Check calls to formatted I/O functions (-Wformat).
+   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+   2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "flags.h"
+#include "c-common.h"
+#include "toplev.h"
+#include "intl.h"
+#include "diagnostic.h"
+#include "langhooks.h"
+#include "c-format.h"
+#include "alloc-pool.h"
+
+/* Mingw specific format attributes ms_printf, ms_scanf, and ms_strftime.  */
+
+static const format_length_info ms_printf_length_specs[] =
+{
+  { "h", FMT_LEN_h, STD_C89, NULL, 0, 0 },
+  { "l", FMT_LEN_l, STD_C89, NULL, 0, 0 },
+  { "\0I32", FMT_LEN_l, STD_C89, NULL, 0, 0 },
+  { "\0I64", FMT_LEN_ll, STD_C9L, NULL, 0, 0 },
+  { "I", FMT_LEN_L, STD_C89, NULL, 0, 0 },
+  { NULL, 0, 0, NULL, 0, 0 }
+};
+
+static const format_flag_spec ms_printf_flag_specs[] =
+{
+  { ' ',  0, 0, N_("' ' flag"),        N_("the ' ' printf flag"),              STD_C89 },
+  { '+',  0, 0, N_("'+' flag"),        N_("the '+' printf flag"),              STD_C89 },
+  { '#',  0, 0, N_("'#' flag"),        N_("the '#' printf flag"),              STD_C89 },
+  { '0',  0, 0, N_("'0' flag"),        N_("the '0' printf flag"),              STD_C89 },
+  { '-',  0, 0, N_("'-' flag"),        N_("the '-' printf flag"),              STD_C89 },
+  { '\'', 0, 0, N_("''' flag"),        N_("the ''' printf flag"),              STD_EXT },
+  { 'w',  0, 0, N_("field width"),     N_("field width in printf format"),     STD_C89 },
+  { 'p',  0, 0, N_("precision"),       N_("precision in printf format"),       STD_C89 },
+  { 'L',  0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_printf_flag_pairs[] =
+{
+  { ' ', '+', 1, 0   },
+  { '0', '-', 1, 0   }, { '0', 'p', 1, 'i' },
+  { 0, 0, 0, 0 }
+};
+
+static const format_flag_spec ms_scanf_flag_specs[] =
+{
+  { '*',  0, 0, N_("assignment suppression"), N_("the assignment suppression scanf feature"), STD_C89 },
+  { 'a',  0, 0, N_("'a' flag"),               N_("the 'a' scanf flag"),                       STD_EXT },
+  { 'w',  0, 0, N_("field width"),            N_("field width in scanf format"),              STD_C89 },
+  { 'L',  0, 0, N_("length modifier"),        N_("length modifier in scanf format"),          STD_C89 },
+  { '\'', 0, 0, N_("''' flag"),               N_("the ''' scanf flag"),                       STD_EXT },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_scanf_flag_pairs[] =
+{
+  { '*', 'L', 0, 0 },
+  { 0, 0, 0, 0 }
+};
+
+static const format_flag_spec ms_strftime_flag_specs[] =
+{
+  { '_', 0,   0, N_("'_' flag"),     N_("the '_' strftime flag"),          STD_EXT },
+  { '-', 0,   0, N_("'-' flag"),     N_("the '-' strftime flag"),          STD_EXT },
+  { '0', 0,   0, N_("'0' flag"),     N_("the '0' strftime flag"),          STD_EXT },
+  { '^', 0,   0, N_("'^' flag"),     N_("the '^' strftime flag"),          STD_EXT },
+  { '#', 0,   0, N_("'#' flag"),     N_("the '#' strftime flag"),          STD_EXT },
+  { 'w', 0,   0, N_("field width"),  N_("field width in strftime format"), STD_EXT },
+  { 'E', 0,   0, N_("'E' modifier"), N_("the 'E' strftime modifier"),      STD_C99 },
+  { 'O', 0,   0, N_("'O' modifier"), N_("the 'O' strftime modifier"),      STD_C99 },
+  { 'O', 'o', 0, NULL,               N_("the 'O' modifier"),               STD_EXT },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_strftime_flag_pairs[] =
+{
+  { 'E', 'O', 0, 0 },
+  { '_', '-', 0, 0 },
+  { '_', '0', 0, 0 },
+  { '-', '0', 0, 0 },
+  { '^', '#', 0, 0 },
+  { 0, 0, 0, 0 }
+};
+
+static const format_char_info ms_print_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "di",  0, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  T99_SST,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-wp0 +'",  "i",  NULL },
+  { "oxX", 0, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN, BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "-wp0#",     "i",  NULL },
+  { "u",   0, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN, BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "-wp0'",    "i",  NULL },
+  { "fgG", 0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "-wp0 +#'", "",   NULL },
+  { "eE",  0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "-wp0 +#",  "",   NULL },
+  { "c",   0, STD_C89, { T89_I,   BADLEN,  T89_S,  T94_WI,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "",   NULL },
+  { "s",   1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-wp",       "cR", NULL },
+  { "p",   1, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "c",  NULL },
+  { "n",   1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  BADLEN,  BADLEN, BADLEN,  T99_IM,  BADLEN,  BADLEN,  BADLEN }, "",          "W",  NULL },
+  /* X/Open conversion specifiers.  */
+  { "C",   0, STD_EXT, { TEX_WI,  BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "",   NULL },
+  { "S",   1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-wp",       "R",  NULL },
+  { NULL,  0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+static const format_char_info ms_scan_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "di",    1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  T99_SST,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w'", "W",   NULL },
+  { "u",     1, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN,  BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "*w'", "W",   NULL },
+  { "oxX",   1, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN,  BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "efgEG", 1, STD_C89, { T89_F,   BADLEN,  BADLEN,  T89_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "*w'",  "W",   NULL },
+  { "c",     1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "cW",  NULL },
+  { "s",     1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "cW",  NULL },
+  { "[",     1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "cW[", NULL },
+  { "p",     2, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "n",     1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  BADLEN,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "",     "W",   NULL },
+  /* X/Open conversion specifiers.  */
+  { "C",     1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "S",     1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "W",   NULL },
+  { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+static const format_char_info ms_time_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "ABZab",		0, STD_C89, NOLENGTHS, "^#",     "",   NULL },
+  { "cx",		0, STD_C89, NOLENGTHS, "E",      "3",  NULL },
+  { "HIMSUWdmw",	0, STD_C89, NOLENGTHS, "-_0Ow",  "",   NULL },
+  { "j",		0, STD_C89, NOLENGTHS, "-_0Ow",  "o",  NULL },
+  { "p",		0, STD_C89, NOLENGTHS, "#",      "",   NULL },
+  { "X",		0, STD_C89, NOLENGTHS, "E",      "",   NULL },
+  { "y",		0, STD_C89, NOLENGTHS, "EO-_0w", "4",  NULL },
+  { "Y",		0, STD_C89, NOLENGTHS, "-_0EOw", "o",  NULL },
+  { "%",		0, STD_C89, NOLENGTHS, "",       "",   NULL },
+  /* C99 conversion specifiers.  */
+  { "z",		0, STD_C99, NOLENGTHS, "O",      "o",  NULL },
+  { NULL,		0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+const format_kind_info mingw_formatter_attributes[3] =
+{
+  { "ms_printf",   ms_printf_length_specs,  ms_print_char_table, " +#0-'", NULL,
+    ms_printf_flag_specs, ms_printf_flag_pairs,
+    FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
+    'w', 0, 'p', 0, 'L', 0,
+    &integer_type_node, &integer_type_node
+  },
+  { "ms_scanf",    ms_printf_length_specs,   ms_scan_char_table,  "*'", NULL,
+    ms_scanf_flag_specs, ms_scanf_flag_pairs,
+    FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
+    'w', 0, 0, '*', 'L', 0,
+    NULL, NULL
+  },
+  { "ms_strftime", NULL,                 ms_time_char_table,  "_-0^#", "EO",
+    ms_strftime_flag_specs, ms_strftime_flag_pairs,
+    FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0, 0,
+    NULL, NULL
+  }
+};
+
+/* Default overrides for printf, scanf and strftime.  */
+const target_ovr_attr mingw_formatter_attribute_overrides[4] =
+{
+  { "ms_printf", "printf", ovr_printf_format_type },
+  { "ms_scanf", "scanf", ovr_scanf_format_type },
+  { "ms_strftime", "strftime", ovr_strftime_format_type }
+};
Index: gcc/gcc/config/i386/t-cygming
===================================================================
--- gcc.orig/gcc/config/i386/t-cygming
+++ gcc/gcc/config/i386/t-cygming
@@ -29,4 +29,10 @@ winnt-stubs.o: $(srcdir)/config/i386/win
 	$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
 	$(srcdir)/config/i386/winnt-stubs.c
 
+msformat-c.o: $(srcdir)/config/i386/msformat-c.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
+  $(TM_H) $(RTL_H) $(REGS_H) hard-reg-set.h output.h $(TREE_H) flags.h \
+  $(TM_P_H) toplev.h $(HASHTAB_H) $(GGC_H)
+	$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
+	$(srcdir)/config/i386/msformat-c.c
+
 STMP_FIXINC=stmp-fixinc
Index: gcc/gcc/doc/extend.texi
===================================================================
--- gcc.orig/gcc/doc/extend.texi
+++ gcc/gcc/doc/extend.texi
@@ -2204,13 +2204,17 @@ for consistency with the @code{printf} s
 @code{my_format}.
 
 The parameter @var{archetype} determines how the format string is
-interpreted, and should be @code{printf}, @code{scanf}, @code{strftime}
-or @code{strfmon}.  (You can also use @code{__printf__},
-@code{__scanf__}, @code{__strftime__} or @code{__strfmon__}.)  The
-parameter @var{string-index} specifies which argument is the format
-string argument (starting from 1), while @var{first-to-check} is the
-number of the first argument to check against the format string.  For
-functions where the arguments are not available to be checked (such as
+interpreted, and should be @code{printf}, @code{scanf}, @code{strftime},
+@code{gnu_printf}, @code{gnu_scanf}, @code{gnu_strftime} or
+@code{strfmon}.  (You can also use @code{__printf__},
+@code{__scanf__}, @code{__strftime__} or @code{__strfmon__}.)  On
+mingw targets there is also @code{ms_printf}, @code{ms_scanf}, and
+@code{ms_strftime} present. The none target specific formatters are
+always the variant of the system.  The parameter @var{string-index}
+specifies which argument is the format string argument (starting
+from 1), while @var{first-to-check} is the number of the first
+argument to check against the format string.  For functions
+where the arguments are not available to be checked (such as
 @code{vprintf}), specify the third parameter as zero.  In this case the
 compiler only checks the format string for consistency.  For
 @code{strftime} formats, the third parameter is required to be zero.
Index: gcc/gcc/doc/tm.texi
===================================================================
--- gcc.orig/gcc/doc/tm.texi
+++ gcc/gcc/doc/tm.texi
@@ -10311,6 +10311,18 @@ If defined, this macro is the number of 
 @code{TARGET_FORMAT_TYPES}.
 @end defmac
 
+@defmac TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+If defined, this macro is the name of a global variable containg
+target-specific format overrides for the @option{-Wformat} option. The
+default is to have no target-specific format overrides. This depends, that
+@code{TARGET_FORMAT_TYPES} is defined too.
+@end defmac
+
+@defmac TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT
+If defined, this macro is the number of entries in
+@code{}.
+@end defmac
+
 @deftypefn {Target Hook} bool TARGET_RELAXED_ORDERING
 If set to @code{true}, means that the target's memory model does not
 guarantee that loads which do not depend on one another will access
Index: gcc/gcc/testsuite/gcc.dg/format/sys_formatter.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/sys_formatter.c
@@ -0,0 +1,14 @@
+/* Test system default printf formatter specifiers.  */
+/* Origin: Kai Tietz <KaiTietz.@onevision.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu89" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+__attribute__((format(printf, 1, 2))) void foo (const char *, ...);
+
+void bar (long long v1, long v2, int v3)
+{
+  foo ("%I64d %I32d %ld %d\n", v1, v2, v2, v3);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/format.h
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/format.h
+++ gcc/gcc/testsuite/gcc.dg/format/format.h
@@ -1,6 +1,37 @@
 /* Format checking tests: common header.  */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
 
+/* DONT_GNU_PROTOTYPE */
+#if defined (_WIN32) && !defined (__CYGWIN__)
+#if !defined (USE_SYSTEM_FORMATS)
+#define gnu_attr_printf	gnu_printf
+#define gnu_attr___printf__ __gnu_printf__
+#define gnu_attr_scanf	gnu_scanf
+#define gnu_attr___scanf__ __gnu_scanf__
+#define gnu_attr_strftime gnu_strftime
+#define gnu_attr___strftime__ __gnu_strftime__
+#endif
+#endif
+
+#ifndef gnu_attr_printf
+#define gnu_attr_printf	printf
+#define gnu_attr___printf__ __printf__
+#define gnu_attr_scanf	scanf
+#define gnu_attr___scanf__ __scanf__
+#define gnu_attr_strftime strftime
+#define gnu_attr___strftime__ __strftime__
+#endif
+
+#if !defined (USE_SYSTEM_FORMATS)
+#define USE_PRINTF(FMTPOS, WILDARG) __attribute__((format(gnu_printf, FMTPOS, WILDARG))) __attribute__((nonnull (FMTPOS)))
+#define USE_SCANF(FMTPOS, WILDARG) __attribute__((format(gnu_scanf, FMTPOS, WILDARG))) __attribute__((nonnull (FMTPOS)))
+#define USE_STRFTIME(FMTPOS) __attribute__((__format__(gnu_strftime, FMTPOS, 0))) __attribute__((nonnull (FMTPOS)))
+#else
+#define USE_PRINTF(FMTPOS, WILDARG)
+#define USE_SCANF(FMTPOS, WILDARG)
+#define USE_STRFTIME(FMTPOS)
+#endif
+
 #include <stdarg.h>
 #include <stddef.h>
 
@@ -11,6 +42,20 @@
 typedef __WINT_TYPE__ wint_t;
 #endif
 
+#ifdef _WIN64
+/* Kludges to get types corresponding to size_t and ptrdiff_t.  */
+#define unsigned signed
+typedef signed int signed_size_t __attribute__ ((mode (DI)));
+/* We also use this type to approximate ssize_t.  */
+typedef signed int ssize_t __attribute__ ((mode (DI)));
+#undef unsigned
+#define signed /* Type might or might not have explicit 'signed'.  */
+typedef unsigned int unsigned_ptrdiff_t __attribute__ ((mode (DI)));
+#undef signed
+
+__extension__ typedef int llong  __attribute__ ((mode (DI)));
+__extension__ typedef unsigned int ullong  __attribute__ ((mode (DI)));
+#else
 /* Kludges to get types corresponding to size_t and ptrdiff_t.  */
 #define unsigned signed
 typedef __SIZE_TYPE__ signed_size_t;
@@ -23,6 +68,7 @@ typedef unsigned __PTRDIFF_TYPE__ unsign
 
 __extension__ typedef long long int llong;
 __extension__ typedef unsigned long long int ullong;
+#endif
 
 /* %q formats want a "quad"; GCC considers this to be a long long.  */
 typedef llong quad_t;
@@ -70,3 +116,77 @@ extern size_t strftime (char *restrict, 
 			const struct tm *restrict);
 
 extern ssize_t strfmon (char *restrict, size_t, const char *restrict, ...);
+
+/* Mingw specific part.  */
+#if !defined (USE_SYSTEM_FORMATS) && defined(_WIN32) && !defined(DONT_GNU_PROTOTYPE)
+
+extern USE_PRINTF(2,3) int fprintf_gnu (FILE *restrict, const char *restrict, ...);
+#undef fprintf
+#define fprintf fprintf_gnu
+
+extern USE_PRINTF(1,2) int printf_gnu (const char *restrict, ...);
+#undef printf
+#define printf printf_gnu
+
+extern USE_PRINTF(2,3) int fprintf_unlocked_gnu (FILE *restrict, const char *restrict, ...);
+#undef fprintf_unlocked
+#define fprintf_unlocked fprintf_unlocked_gnu
+
+extern USE_PRINTF(1,2)int printf_unlocked_gnu (const char *restrict, ...);
+#undef printf_unlocked
+#define printf_unlocked printf_unlocked_gnu
+
+extern USE_PRINTF(2,3) int sprintf_gnu (char *restrict, const char *restrict, ...);
+#undef sprintf
+#define sprintf sprintf_gnu
+
+extern USE_PRINTF(2,0) int vfprintf_gnu (FILE *restrict, const char *restrict, va_list);
+#undef vsprintf
+#define vsprintf vsprintf_gnu
+
+extern USE_PRINTF(1,0) int vprintf_gnu (const char *restrict, va_list);
+#undef vprintf
+#define vprintf vprintf_gnu
+
+extern USE_PRINTF(2,0) int vsprintf_gnu (char *restrict, const char *restrict, va_list);
+#undef vsprintf
+#define vsprintf vsprintf_gnu
+
+extern USE_PRINTF(3,4) int snprintf_gnu (char *restrict, size_t, const char *restrict, ...);
+#undef snprintf
+#define snprintf snprintf_gnu
+
+extern USE_PRINTF(3,0) int vsnprintf_gnu (char *restrict, size_t, const char *restrict, va_list);
+#undef vsnprintf
+#define vsnprintf vsnprintf_gnu
+
+extern USE_SCANF(2,3) int fscanf_gnu (FILE *restrict, const char *restrict, ...);
+#undef fscanf
+#define fscanf fscanf_gnu
+
+extern USE_SCANF(1,2) int scanf_gnu (const char *restrict, ...);
+#undef scanf
+#define scanf scanf_gnu
+
+extern USE_SCANF(2,3) int sscanf_gnu (const char *restrict, const char *restrict, ...);
+#undef sscanf
+#define sscanf sscanf_gnu
+
+extern USE_SCANF(2,0) int vfscanf_gnu (FILE *restrict, const char *restrict, va_list);
+#undef vfscanf
+#define vfscanf vfscanf_gnu
+
+extern USE_SCANF(1,0) int vscanf_gnu (const char *restrict, va_list);
+#undef vscanf
+#define vscanf vscanf_gnu
+
+extern USE_SCANF(2,0) int vsscanf_gnu (const char *restrict, const char *restrict, va_list);
+#undef vsscanf
+#define vsscanf vsscanf_gnu
+
+extern USE_STRFTIME(3) size_t strftime_gnu (char *restrict, size_t, const char *restrict,
+			const struct tm *restrict);
+#undef strftime
+#define strftime strftime_gnu
+
+#endif
Index: gcc/gcc/testsuite/gcc.dg/format/attr-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-1.c
@@ -3,7 +3,8 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern void foo0 (const char *) __attribute__((__format__(__strftime__, 1, 0)));
-extern void foo1 (const char *, ...) __attribute__((__format__(__strftime__, 1, 2))); /* { dg-error "cannot format" "strftime first_arg_num != 0" } */
+extern void foo0 (const char *) __attribute__((__format__(gnu_attr___strftime__, 1, 0)));
+extern void foo1 (const char *, ...) __attribute__((__format__(gnu_attr___strftime__, 1, 2))); /* { dg-error "cannot format" "strftime first_arg_num != 0" } */
Index: gcc/gcc/testsuite/gcc.dg/format/attr-2.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-2.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-2.c
@@ -3,22 +3,23 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern void tformatprintf (const char *, ...) __attribute__((format(printf, 1, 2)));
-extern void tformat__printf__ (const char *, ...) __attribute__((format(__printf__, 1, 2)));
-extern void tformatscanf (const char *, ...) __attribute__((format(scanf, 1, 2)));
-extern void tformat__scanf__ (const char *, ...) __attribute__((format(__scanf__, 1, 2)));
-extern void tformatstrftime (const char *) __attribute__((format(strftime, 1, 0)));
-extern void tformat__strftime__ (const char *) __attribute__((format(__strftime__, 1, 0)));
+extern void tformatprintf (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
+extern void tformat__printf__ (const char *, ...) __attribute__((format(gnu_attr___printf__, 1, 2)));
+extern void tformatscanf (const char *, ...) __attribute__((format(gnu_attr_scanf, 1, 2)));
+extern void tformat__scanf__ (const char *, ...) __attribute__((format(gnu_attr___scanf__, 1, 2)));
+extern void tformatstrftime (const char *) __attribute__((format(gnu_attr_strftime, 1, 0)));
+extern void tformat__strftime__ (const char *) __attribute__((format(gnu_attr___strftime__, 1, 0)));
 extern void tformatstrfmon (const char *, ...) __attribute__((format(strfmon, 1, 2)));
 extern void tformat__strfmon__ (const char *, ...) __attribute__((format(__strfmon__, 1, 2)));
-extern void t__format__printf (const char *, ...) __attribute__((__format__(printf, 1, 2)));
-extern void t__format____printf__ (const char *, ...) __attribute__((__format__(__printf__, 1, 2)));
-extern void t__format__scanf (const char *, ...) __attribute__((__format__(scanf, 1, 2)));
-extern void t__format____scanf__ (const char *, ...) __attribute__((__format__(__scanf__, 1, 2)));
-extern void t__format__strftime (const char *) __attribute__((__format__(strftime, 1, 0)));
-extern void t__format____strftime__ (const char *) __attribute__((__format__(__strftime__, 1, 0)));
+extern void t__format__printf (const char *, ...) __attribute__((__format__(gnu_attr_printf, 1, 2)));
+extern void t__format____printf__ (const char *, ...) __attribute__((__format__(gnu_attr___printf__, 1, 2)));
+extern void t__format__scanf (const char *, ...) __attribute__((__format__(gnu_attr_scanf, 1, 2)));
+extern void t__format____scanf__ (const char *, ...) __attribute__((__format__(gnu_attr___scanf__, 1, 2)));
+extern void t__format__strftime (const char *) __attribute__((__format__(gnu_attr_strftime, 1, 0)));
+extern void t__format____strftime__ (const char *) __attribute__((__format__(gnu_attr___strftime__, 1, 0)));
 extern void t__format__strfmon (const char *, ...) __attribute__((__format__(strfmon, 1, 2)));
 extern void t__format____strfmon__ (const char *, ...) __attribute__((__format__(__strfmon__, 1, 2)));
 
Index: gcc/gcc/testsuite/gcc.dg/format/attr-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-3.c
@@ -3,20 +3,21 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 /* Proper uses of the attributes.  */
-extern void fa0 (const char *, ...) __attribute__((format(printf, 1, 2)));
-extern void fa1 (char *, ...) __attribute__((format(printf, 1, 2)));
+extern void fa0 (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
+extern void fa1 (char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
 extern char *fa2 (const char *) __attribute__((format_arg(1)));
 extern char *fa3 (char *) __attribute__((format_arg(1)));
 
 /* Uses with too few or too many arguments.  */
 extern void fb0 (const char *, ...) __attribute__((format)); /* { dg-error "wrong number of arguments" "bad format" } */
 extern void fb1 (const char *, ...) __attribute__((format())); /* { dg-error "wrong number of arguments" "bad format" } */
-extern void fb2 (const char *, ...) __attribute__((format(printf))); /* { dg-error "wrong number of arguments" "bad format" } */
-extern void fb3 (const char *, ...) __attribute__((format(printf, 1))); /* { dg-error "wrong number of arguments" "bad format" } */
-extern void fb4 (const char *, ...) __attribute__((format(printf, 1, 2, 3))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb2 (const char *, ...) __attribute__((format(gnu_attr_printf))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb3 (const char *, ...) __attribute__((format(gnu_attr_printf, 1))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb4 (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2, 3))); /* { dg-error "wrong number of arguments" "bad format" } */
 
 extern void fc1 (const char *) __attribute__((format_arg)); /* { dg-error "wrong number of arguments" "bad format_arg" } */
 extern void fc2 (const char *) __attribute__((format_arg())); /* { dg-error "wrong number of arguments" "bad format_arg" } */
@@ -25,9 +26,9 @@ extern void fc3 (const char *) __attribu
 /* These attributes presently only apply to declarations, not to types.
    Eventually, they should be usable with declarators for function types
    anywhere, but still not with structure/union/enum types.  */
-struct s0 { int i; } __attribute__((format(printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on struct" } */
-union u0 { int i; } __attribute__((format(printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on union" } */
-enum e0 { E0V0 } __attribute__((format(printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on enum" } */
+struct s0 { int i; } __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on struct" } */
+union u0 { int i; } __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on union" } */
+enum e0 { E0V0 } __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on enum" } */
 
 struct s1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on struct" } */
 union u1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on union" } */
@@ -38,28 +39,28 @@ extern void fe0 (const char *, ...) __at
 extern void fe1 (const char *, ...) __attribute__((format(nosuch, 1, 2))); /* { dg-warning "format function type" "unknown format" } */
 
 /* Both the numbers must be integer constant expressions.  */
-extern void ff0 (const char *, ...) __attribute__((format(printf, 3-2, (long long)(10/5))));
+extern void ff0 (const char *, ...) __attribute__((format(gnu_attr_printf, 3-2, (long long)(10/5))));
 int foo;
-extern void ff1 (const char *, ...) __attribute__((format(printf, foo, 10/5))); /* { dg-error "invalid operand" "bad number" } */
-extern void ff2 (const char *, ...) __attribute__((format(printf, 3-2, foo))); /* { dg-error "invalid operand" "bad number" } */
+extern void ff1 (const char *, ...) __attribute__((format(gnu_attr_printf, foo, 10/5))); /* { dg-error "invalid operand" "bad number" } */
+extern void ff2 (const char *, ...) __attribute__((format(gnu_attr_printf, 3-2, foo))); /* { dg-error "invalid operand" "bad number" } */
 extern char *ff3 (const char *) __attribute__((format_arg(3-2)));
 extern char *ff4 (const char *) __attribute__((format_arg(foo))); /* { dg-error "invalid operand" "bad format_arg number" } */
 
 /* The format string argument must precede the arguments to be formatted.
    This includes if no parameter types are specified (which is not valid ISO
    C for variadic functions).  */
-extern void fg0 () __attribute__((format(printf, 1, 2)));
-extern void fg1 () __attribute__((format(printf, 1, 0)));
-extern void fg2 () __attribute__((format(printf, 1, 1))); /* { dg-error "follows" "bad number order" } */
-extern void fg3 () __attribute__((format(printf, 2, 1))); /* { dg-error "follows" "bad number order" } */
+extern void fg0 () __attribute__((format(gnu_attr_printf, 1, 2)));
+extern void fg1 () __attribute__((format(gnu_attr_printf, 1, 0)));
+extern void fg2 () __attribute__((format(gnu_attr_printf, 1, 1))); /* { dg-error "follows" "bad number order" } */
+extern void fg3 () __attribute__((format(gnu_attr_printf, 2, 1))); /* { dg-error "follows" "bad number order" } */
 
 /* The format string argument must be a string type, and the arguments to
    be formatted must be the "...".  */
-extern void fh0 (int, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "not a string" "format int string" } */
-extern void fh1 (signed char *, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "not a string" "signed char string" } */
-extern void fh2 (unsigned char *, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "not a string" "unsigned char string" } */
-extern void fh3 (const char *, ...) __attribute__((format(printf, 1, 3))); /* { dg-error "is not" "not ..." } */
-extern void fh4 (const char *, int, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "is not" "not ..." } */
+extern void fh0 (int, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "format int string" } */
+extern void fh1 (signed char *, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "signed char string" } */
+extern void fh2 (unsigned char *, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "unsigned char string" } */
+extern void fh3 (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 3))); /* { dg-error "is not" "not ..." } */
+extern void fh4 (const char *, int, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "is not" "not ..." } */
 
 /* format_arg formats must take and return a string.  */
 extern char *fi0 (int) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg int string" } */
Index: gcc/gcc/testsuite/gcc.dg/format/attr-4.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-4.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-4.c
@@ -4,12 +4,13 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern __attribute__((format(printf, 1, 2))) void tformatprintf0 (const char *, ...);
-extern void __attribute__((format(printf, 1, 2))) tformatprintf1 (const char *, ...);
-extern void foo (void), __attribute__((format(printf, 1, 2))) tformatprintf2 (const char *, ...);
-extern __attribute__((noreturn)) void bar (void), __attribute__((format(printf, 1, 2))) tformatprintf3 (const char *, ...);
+extern __attribute__((format(gnu_attr_printf, 1, 2))) void tformatprintf0 (const char *, ...);
+extern void __attribute__((format(gnu_attr_printf, 1, 2))) tformatprintf1 (const char *, ...);
+extern void foo (void), __attribute__((format(gnu_attr_printf, 1, 2))) tformatprintf2 (const char *, ...);
+extern __attribute__((noreturn)) void bar (void), __attribute__((format(gnu_attr_printf, 1, 2))) tformatprintf3 (const char *, ...);
 
 void
 baz (int i, int *ip, double d)
Index: gcc/gcc/testsuite/gcc.dg/format/attr-7.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-7.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-7.c
@@ -3,12 +3,13 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-__attribute__((format(printf, 1, 2))) void (*tformatprintf0) (const char *, ...);
-void (*tformatprintf1) (const char *, ...) __attribute__((format(printf, 1, 2)));
-void (__attribute__((format(printf, 1, 2))) *tformatprintf2) (const char *, ...);
-void (__attribute__((format(printf, 1, 2))) ****tformatprintf3) (const char *, ...);
+__attribute__((format(gnu_attr_printf, 1, 2))) void (*tformatprintf0) (const char *, ...);
+void (*tformatprintf1) (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
+void (__attribute__((format(gnu_attr_printf, 1, 2))) *tformatprintf2) (const char *, ...);
+void (__attribute__((format(gnu_attr_printf, 1, 2))) ****tformatprintf3) (const char *, ...);
 
 char * (__attribute__((format_arg(1))) *tformat_arg) (const char *);
 
Index: gcc/gcc/testsuite/gcc.dg/format/c90-printf-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/c90-printf-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/c90-printf-3.c
@@ -17,8 +17,8 @@ foo (int i, char *s, size_t n, va_list v
   printf ("%d", i);
   printf ("%ld", i); /* { dg-warning "format" "printf" } */
   /* The "unlocked" functions shouldn't warn in c90 mode.  */
-  fprintf_unlocked (stdout, "%ld", i); /* { dg-bogus "format" "fprintf_unlocked" } */
-  printf_unlocked ("%ld", i); /* { dg-bogus "format" "printf_unlocked" } */
+  fprintf_unlocked (stdout, "%ld", i); /* { dg-warning "format" "fprintf_unlocked" } */
+  printf_unlocked ("%ld", i); /* { dg-warning "format" "printf_unlocked" } */
   sprintf (s, "%d", i);
   sprintf (s, "%ld", i); /* { dg-warning "format" "sprintf" } */
   vfprintf (stdout, "%d", v0);
@@ -30,13 +30,13 @@ foo (int i, char *s, size_t n, va_list v
   vsprintf (s, "%d", v4);
   vsprintf (s, "%Y", v5); /* { dg-warning "format" "vsprintf" } */
   snprintf (s, n, "%d", i);
-  snprintf (s, n, "%ld", i);
+  snprintf (s, n, "%ld", i); /* { dg-warning "format" "snprintf" } */
   vsnprintf (s, n, "%d", v6);
-  vsnprintf (s, n, "%Y", v7);
+  vsnprintf (s, n, "%Y", v7); /* { dg-warning "format" "vsprintf" } */
   printf (gettext ("%d"), i);
   printf (gettext ("%ld"), i);
   printf (dgettext ("", "%d"), i);
-  printf (dgettext ("", "%ld"), i);
+  printf (dgettext ("", "%ld"), (long) i);
   printf (dcgettext ("", "%d", 0), i);
-  printf (dcgettext ("", "%ld", 0), i);
+  printf (dcgettext ("", "%ld", 0), (long) i);
 }
Index: gcc/gcc/testsuite/gcc.dg/format/c90-scanf-4.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/c90-scanf-4.c
+++ gcc/gcc/testsuite/gcc.dg/format/c90-scanf-4.c
@@ -19,11 +19,11 @@ foo (int *ip, char *s, va_list v0, va_li
   sscanf (s, "%d", ip);
   sscanf (s, "%ld", ip); /* { dg-warning "format" "sscanf" } */
   vfscanf (stdin, "%d", v0);
-  vfscanf (stdin, "%Y", v1);
+  vfscanf (stdin, "%Y", v1);  /* { dg-warning "format" "vfscanf" } */
   vscanf ("%d", v2);
-  vscanf ("%Y", v3);
+  vscanf ("%Y", v3);  /* { dg-warning "format" "vscanf" } */
   vsscanf (s, "%d", v4);
-  vsscanf (s, "%Y", v5);
+  vsscanf (s, "%Y", v5);  /* { dg-warning "format" "vsscanf" } */
   scanf (gettext ("%d"), ip);
   scanf (gettext ("%ld"), ip);
   scanf (dgettext ("", "%d"), ip);
Index: gcc/gcc/testsuite/gcc.dg/format/c99-printf-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/c99-printf-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/c99-printf-3.c
@@ -16,8 +16,8 @@ foo (int i, char *s, size_t n, va_list v
   printf ("%d", i);
   printf ("%ld", i); /* { dg-warning "format" "printf" } */
   /* The "unlocked" functions shouldn't warn in c99 mode.  */
-  fprintf_unlocked (stdout, "%ld", i); /* { dg-bogus "format" "fprintf_unlocked" } */
-  printf_unlocked ("%ld", i); /* { dg-bogus "format" "printf_unlocked" } */
+  fprintf_unlocked (stdout, "%ld", i); /* { dg-warning "format" "fprintf_unlocked" } */
+  printf_unlocked ("%ld", i); /* { dg-warning "format" "printf_unlocked" } */
   sprintf (s, "%d", i);
   sprintf (s, "%ld", i); /* { dg-warning "format" "sprintf" } */
   snprintf (s, n, "%d", i);
@@ -31,9 +31,9 @@ foo (int i, char *s, size_t n, va_list v
   vsnprintf (s, n, "%d", v0);
   vsnprintf (s, n, "%Y", v1); /* { dg-warning "format" "vsnprintf" } */
   printf (gettext ("%d"), i);
-  printf (gettext ("%ld"), i);
+  printf (gettext ("%ld"), (long) i);
   printf (dgettext ("", "%d"), i);
-  printf (dgettext ("", "%ld"), i);
+  printf (dgettext ("", "%ld"), (long) i);
   printf (dcgettext ("", "%d", 0), i);
-  printf (dcgettext ("", "%ld", 0), i);
+  printf (dcgettext ("", "%ld", 0), (long) i);
 }
Index: gcc/gcc/testsuite/gcc.dg/format/miss-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-1.c
@@ -23,7 +23,7 @@ bar (const char *fmt, ...)
   va_end (ap);
 }
 
-__attribute__((__format__(__printf__, 1, 2))) void
+__attribute__((__format__(gnu_attr___printf__, 1, 2))) void
 foo2 (const char *fmt, ...)
 {
   va_list ap;
Index: gcc/gcc/testsuite/gcc.dg/format/miss-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-3.c
@@ -3,13 +3,14 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 void
 foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
@@ -18,7 +19,7 @@ foo1 (noattr_t na, attr_t a, vnoattr_t v
   noattr_t na2 = a; /* { dg-warning "candidate" "initialization warning" } */
   attr_t a1 = na;
   attr_t a2 = a;
-  
+
   vnoattr_t vna1 = vna;
   vnoattr_t vna2 = va; /* { dg-warning "candidate" "initialization warning" } */
   vattr_t va1 = vna;
Index: gcc/gcc/testsuite/gcc.dg/format/miss-4.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-4.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-4.c
@@ -3,20 +3,21 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 void
 foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
 {
   noattr_t na1, na2;
   attr_t a1, a2;
-  
+
   vnoattr_t vna1, vna2;
   vattr_t va1, va2;
 
@@ -24,7 +25,7 @@ foo1 (noattr_t na, attr_t a, vnoattr_t v
   na2 = a; /* { dg-warning "candidate" "assignment warning" } */
   a1 = na;
   a2 = a;
-  
+
   vna1 = vna;
   vna2 = va; /* { dg-warning "candidate" "assignment warning" } */
   va1 = vna;
Index: gcc/gcc/testsuite/gcc.dg/format/miss-5.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-5.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-5.c
@@ -3,13 +3,14 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 noattr_t
 foo1 (noattr_t na, attr_t a, int i)
Index: gcc/gcc/testsuite/gcc.dg/format/miss-6.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-6.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-6.c
@@ -3,13 +3,14 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 extern void foo1 (noattr_t);
 extern void foo2 (attr_t);
@@ -23,7 +24,7 @@ foo (noattr_t na, attr_t a, vnoattr_t vn
   foo1 (a); /* { dg-warning "candidate" "parameter passing warning" } */
   foo2 (na);
   foo2 (a);
-  
+
   foo3 (vna);
   foo3 (va); /* { dg-warning "candidate" "parameter passing warning" } */
   foo4 (vna);
Index: gcc/gcc/testsuite/gcc.dg/format/ms_array-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_array-1.c
@@ -0,0 +1,42 @@
+/* Test for format checking of constant arrays.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat=2" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+const char a1[] = "foo";
+const char a2[] = "foo%d";
+const char b1[3] = "foo";
+const char b2[1] = "1";
+static const char c1[] = "foo";
+static const char c2[] = "foo%d";
+char d[] = "foo";
+volatile const char e[] = "foo";
+
+void
+foo (int i, long l)
+{
+  const char p1[] = "bar";
+  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 (c1);
+  printf (c2, i);
+  printf (c2, l); /* { dg-warning "format" "wrong type with array" } */
+  printf (p1);
+  printf (p2, i);
+  printf (p2, l); /* { dg-warning "format" "wrong type with array" } */
+  printf (q1);
+  printf (q2, i);
+  printf (q2, l); /* { dg-warning "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" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-1.c
@@ -0,0 +1,10 @@
+/* Test for strftime format attributes: can't have first_arg_num != 0.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define DONT_GNU_PROTOTYPE
+#include "format.h"
+
+extern void foo0 (const char *) __attribute__((__format__(__ms_strftime__, 1, 0)));
+extern void foo1 (const char *, ...) __attribute__((__format__(__ms_strftime__, 1, 2))); /* { dg-error "cannot format" "strftime first_arg_num != 0" } */
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-2.c
@@ -0,0 +1,68 @@
+/* Test for format attributes: test use of __attribute__.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define DONT_GNU_PROTOTYPE
+#include "format.h"
+
+extern void tformatprintf (const char *, ...) __attribute__((format(ms_printf, 1, 2)));
+extern void tformat__printf__ (const char *, ...) __attribute__((format(__ms_printf__, 1, 2)));
+extern void tformatscanf (const char *, ...) __attribute__((format(ms_scanf, 1, 2)));
+extern void tformat__scanf__ (const char *, ...) __attribute__((format(__ms_scanf__, 1, 2)));
+extern void tformatstrftime (const char *) __attribute__((format(ms_strftime, 1, 0)));
+extern void tformat__strftime__ (const char *) __attribute__((format(__ms_strftime__, 1, 0)));
+extern void tformatstrfmon (const char *, ...) __attribute__((format(strfmon, 1, 2)));
+extern void tformat__strfmon__ (const char *, ...) __attribute__((format(__strfmon__, 1, 2)));
+extern void t__format__printf (const char *, ...) __attribute__((__format__(ms_printf, 1, 2)));
+extern void t__format____printf__ (const char *, ...) __attribute__((__format__(__ms_printf__, 1, 2)));
+extern void t__format__scanf (const char *, ...) __attribute__((__format__(ms_scanf, 1, 2)));
+extern void t__format____scanf__ (const char *, ...) __attribute__((__format__(__ms_scanf__, 1, 2)));
+extern void t__format__strftime (const char *) __attribute__((__format__(ms_strftime, 1, 0)));
+extern void t__format____strftime__ (const char *) __attribute__((__format__(__ms_strftime__, 1, 0)));
+extern void t__format__strfmon (const char *, ...) __attribute__((__format__(strfmon, 1, 2)));
+extern void t__format____strfmon__ (const char *, ...) __attribute__((__format__(__strfmon__, 1, 2)));
+
+extern char *tformat_arg (const char *) __attribute__((format_arg(1)));
+extern char *t__format_arg__ (const char *) __attribute__((__format_arg__(1)));
+
+void
+foo (int i, int *ip, double d)
+{
+  tformatprintf ("%d", i);
+  tformatprintf ("%"); /* { dg-warning "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);
+  tformat__scanf__ ("%"); /* { dg-warning "format" "attribute format __scanf__" } */
+  tformatstrftime ("%a");
+  tformatstrftime ("%"); /* { dg-warning "format" "attribute format strftime" } */
+  tformat__strftime__ ("%a");
+  tformat__strftime__ ("%"); /* { dg-warning "format" "attribute format __strftime__" } */
+  tformatstrfmon ("%n", d);
+  tformatstrfmon ("%"); /* { dg-warning "format" "attribute format strfmon" } */
+  tformat__strfmon__ ("%n", d);
+  tformat__strfmon__ ("%"); /* { dg-warning "format" "attribute format __strfmon__" } */
+  t__format__printf ("%d", i);
+  t__format__printf ("%"); /* { dg-warning "format" "attribute __format__ printf" } */
+  t__format____printf__ ("%d", i);
+  t__format____printf__ ("%"); /* { dg-warning "format" "attribute __format__ __printf__" } */
+  t__format__scanf ("%d", ip);
+  t__format__scanf ("%"); /* { dg-warning "format" "attribute __format__ scanf" } */
+  t__format____scanf__ ("%d", ip);
+  t__format____scanf__ ("%"); /* { dg-warning "format" "attribute __format__ __scanf__" } */
+  t__format__strftime ("%a");
+  t__format__strftime ("%"); /* { dg-warning "format" "attribute __format__ strftime" } */
+  t__format____strftime__ ("%a");
+  t__format____strftime__ ("%"); /* { dg-warning "format" "attribute __format__ __strftime__" } */
+  t__format__strfmon ("%n", d);
+  t__format__strfmon ("%"); /* { dg-warning "format" "attribute __format__ strfmon" } */
+  t__format____strfmon__ ("%n", d);
+  t__format____strfmon__ ("%"); /* { dg-warning "format" "attribute __format__ __strfmon__" } */
+  tformatprintf (tformat_arg ("%d"), i);
+  tformatprintf (tformat_arg ("%")); /* { dg-warning "format" "attribute format_arg" } */
+  tformatprintf (t__format_arg__ ("%d"), i);
+  tformatprintf (t__format_arg__ ("%")); /* { dg-warning "format" "attribute __format_arg__" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-3.c
@@ -0,0 +1,71 @@
+/* Test for format attributes: test bad uses of __attribute__.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* Proper uses of the attributes.  */
+extern void fa0 (const char *, ...) __attribute__((format(ms_printf, 1, 2)));
+extern void fa1 (char *, ...) __attribute__((format(ms_printf, 1, 2)));
+extern char *fa2 (const char *) __attribute__((format_arg(1)));
+extern char *fa3 (char *) __attribute__((format_arg(1)));
+
+/* Uses with too few or too many arguments.  */
+extern void fb0 (const char *, ...) __attribute__((format)); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb1 (const char *, ...) __attribute__((format())); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb2 (const char *, ...) __attribute__((format(ms_printf))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb3 (const char *, ...) __attribute__((format(ms_printf, 1))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb4 (const char *, ...) __attribute__((format(ms_printf, 1, 2, 3))); /* { dg-error "wrong number of arguments" "bad format" } */
+
+extern void fc1 (const char *) __attribute__((format_arg)); /* { dg-error "wrong number of arguments" "bad format_arg" } */
+extern void fc2 (const char *) __attribute__((format_arg())); /* { dg-error "wrong number of arguments" "bad format_arg" } */
+extern void fc3 (const char *) __attribute__((format_arg(1, 2))); /* { dg-error "wrong number of arguments" "bad format_arg" } */
+
+/* These attributes presently only apply to declarations, not to types.
+   Eventually, they should be usable with declarators for function types
+   anywhere, but still not with structure/union/enum types.  */
+struct s0 { int i; } __attribute__((format(ms_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on struct" } */
+union u0 { int i; } __attribute__((format(ms_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on union" } */
+enum e0 { E0V0 } __attribute__((format(ms_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on enum" } */
+
+struct s1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on struct" } */
+union u1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on union" } */
+enum e1 { E1V0 } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on enum" } */
+
+/* The format type must be an identifier, one of those recognized.  */
+extern void fe0 (const char *, ...) __attribute__((format(12345, 1, 2))); /* { dg-error "format specifier" "non-id format" } */
+extern void fe1 (const char *, ...) __attribute__((format(nosuch, 1, 2))); /* { dg-warning "format function type" "unknown format" } */
+
+/* Both the numbers must be integer constant expressions.  */
+extern void ff0 (const char *, ...) __attribute__((format(ms_printf, 3-2, (long long)(10/5))));
+int foo;
+extern void ff1 (const char *, ...) __attribute__((format(ms_printf, foo, 10/5))); /* { dg-error "invalid operand" "bad number" } */
+extern void ff2 (const char *, ...) __attribute__((format(ms_printf, 3-2, foo))); /* { dg-error "invalid operand" "bad number" } */
+extern char *ff3 (const char *) __attribute__((format_arg(3-2)));
+extern char *ff4 (const char *) __attribute__((format_arg(foo))); /* { dg-error "invalid operand" "bad format_arg number" } */
+
+/* The format string argument must precede the arguments to be formatted.
+   This includes if no parameter types are specified (which is not valid ISO
+   C for variadic functions).  */
+extern void fg0 () __attribute__((format(ms_printf, 1, 2)));
+extern void fg1 () __attribute__((format(ms_printf, 1, 0)));
+extern void fg2 () __attribute__((format(ms_printf, 1, 1))); /* { dg-error "follows" "bad number order" } */
+extern void fg3 () __attribute__((format(ms_printf, 2, 1))); /* { dg-error "follows" "bad number order" } */
+
+/* The format string argument must be a string type, and the arguments to
+   be formatted must be the "...".  */
+extern void fh0 (int, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "not a string" "format int string" } */
+extern void fh1 (signed char *, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "not a string" "signed char string" } */
+extern void fh2 (unsigned char *, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "not a string" "unsigned char string" } */
+extern void fh3 (const char *, ...) __attribute__((format(ms_printf, 1, 3))); /* { dg-error "is not" "not ..." } */
+extern void fh4 (const char *, int, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "is not" "not ..." } */
+
+/* format_arg formats must take and return a string.  */
+extern char *fi0 (int) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg int string" } */
+extern char *fi1 (signed char *) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg signed char string" } */
+extern char *fi2 (unsigned char *) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg unsigned char string" } */
+extern int fi3 (const char *) __attribute__((format_arg(1))); /* { dg-error "not return string" "format_arg ret int string" } */
+extern signed char *fi4 (const char *) __attribute__((format_arg(1))); /* { dg-error "not return string" "format_arg ret signed char string" } */
+extern unsigned char *fi5 (const char *) __attribute__((format_arg(1))); /* { dg-error "not return string" "format_arg ret unsigned char string" } */
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-4.c
@@ -0,0 +1,26 @@
+/* Test for format attributes: test use of __attribute__
+   in prefix attributes.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+extern __attribute__((format(ms_printf, 1, 2))) void tformatprintf0 (const char *, ...);
+extern void __attribute__((format(ms_printf, 1, 2))) tformatprintf1 (const char *, ...);
+extern void foo (void), __attribute__((format(ms_printf, 1, 2))) tformatprintf2 (const char *, ...);
+extern __attribute__((noreturn)) void bar (void), __attribute__((format(ms_printf, 1, 2))) tformatprintf3 (const char *, ...);
+
+void
+baz (int i, int *ip, double d)
+{
+  tformatprintf0 ("%d", i);
+  tformatprintf0 ("%"); /* { dg-warning "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);
+  tformatprintf3 ("%"); /* { dg-warning "format" "attribute format printf case 3" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-7.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-7.c
@@ -0,0 +1,35 @@
+/* Test for format attributes: test applying them to types.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define DONT_GNU_PROTOTYPE
+#include "format.h"
+
+__attribute__((format(ms_printf, 1, 2))) void (*tformatprintf0) (const char *, ...);
+void (*tformatprintf1) (const char *, ...) __attribute__((format(ms_printf, 1, 2)));
+void (__attribute__((format(ms_printf, 1, 2))) *tformatprintf2) (const char *, ...);
+void (__attribute__((format(ms_printf, 1, 2))) ****tformatprintf3) (const char *, ...);
+
+char * (__attribute__((format_arg(1))) *tformat_arg) (const char *);
+
+void
+baz (int i)
+{
+  (*tformatprintf0) ("%d", i);
+  (*tformatprintf0) ((*tformat_arg) ("%d"), i);
+  (*tformatprintf0) ("%"); /* { dg-warning "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" } */
+  (*tformatprintf2) ("%d", i);
+  (*tformatprintf2) ((*tformat_arg) ("%d"), i);
+  (*tformatprintf2) ("%"); /* { dg-warning "format" "nested" } */
+  (*tformatprintf2) ((*tformat_arg) ("%")); /* { dg-warning "format" "nested" } */
+  (****tformatprintf3) ("%d", i);
+  (****tformatprintf3) ((*tformat_arg) ("%d"), i);
+  (****tformatprintf3) ("%"); /* { dg-warning "format" "nested 2" } */
+  (****tformatprintf3) ((*tformat_arg) ("%")); /* { dg-warning "format" "nested 2" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_bitfld-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_bitfld-1.c
@@ -0,0 +1,52 @@
+/* Test for printf formats and bit-fields: bug 22421.  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+/* { dg-require-effective-target int32plus } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+struct s {
+  unsigned int u1 : 1;
+  signed int s1 : 1;
+  unsigned int u15 : 15;
+  signed int s15 : 15;
+  unsigned int u16 : 16;
+  signed int s16 : 16;
+  unsigned long u31 : 31;
+  signed long s31 : 31;
+  unsigned long u32 : 32;
+  signed long s32 : 32;
+  unsigned long long u48 : 48;
+} x;
+
+void
+foo (void)
+{
+  printf ("%d%u", x.u1, x.u1);
+  printf ("%d%u", x.s1, x.s1);
+  printf ("%d%u", x.u15, x.u15);
+  printf ("%d%u", x.s15, x.s15);
+  printf ("%d%u", x.u16, x.u16);
+  printf ("%d%u", x.s16, x.s16);
+#if __INT_MAX__ > 32767
+  /* If integers are 16 bits, there doesn't seem to be a way of
+     printing these without getting an error.  */
+  printf ("%d%u", x.u31, x.u31);
+  printf ("%d%u", x.s31, x.s31);
+#endif
+#if __LONG_MAX__ > 2147483647 && __INT_MAX__ >= 2147483647
+  /* If long is wider than 32 bits, the 32-bit bit-fields are int or
+     unsigned int or promote to those types.  Otherwise, long is 32
+     bits and the bit-fields are of type plain long or unsigned
+     long.  */
+  printf ("%d%u", x.u32, x.u32);
+  printf ("%d%u", x.s32, x.s32);
+#else
+  printf ("%ld%lu", x.u32, x.u32);
+  printf ("%ld%lu", x.s32, x.s32);
+#endif
+  printf ("%I64u", x.u48); /* { dg-warning "has type '.*unsigned int:48'" } */
+  printf ("%I64u", (unsigned long long)x.u48);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_branch-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_branch-1.c
@@ -0,0 +1,28 @@
+/* Test for format checking of conditional expressions.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+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" } */
+  /* 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) ? "%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" } */
+  /* 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 *-*-* } 26 } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-1.c
@@ -0,0 +1,184 @@
+/* Test for printf formats.  Formats using C90 features, including cases
+   where C90 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, int i1, int i2, unsigned int u, double d, char *s, void *p,
+     int *n, short int *hn, long int l, unsigned long int ul,
+     long int *ln, long double ld, wint_t lc, wchar_t *ls, llong ll,
+     ullong ull, unsigned int *un, const int *cn, signed char *ss,
+     unsigned char *us, const signed char *css, unsigned int u1,
+     unsigned int u2)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.1 (pages 131-134).  */
+  /* Basic sanity checks for the different components of a format.  */
+  printf ("%d\n", i);
+  printf ("%+d\n", i);
+  printf ("%3d\n", i);
+  printf ("%-3d\n", i);
+  printf ("%*d\n", i1, i);
+  printf ("%d %lu\n", i, ul);
+  /* Bogus use of width.  */
+  printf ("%5n\n", n); /* { dg-warning "width" "width 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 ("%-%"); /* { dg-warning "format" "bogus %%" } */
+  printf ("%-%\n"); /* { dg-warning "format" "bogus %%" } */
+  printf ("%5%\n"); /* { dg-warning "format" "bogus %%" } */
+  printf ("%h%\n"); /* { dg-warning "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
+     differences in format checking here, and this is relied on to get the
+     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);
+  printf ("%hs", hn);
+  printf ("%hp", p); /* { dg-warning "length" "bad use of %h" } */
+  printf ("%h"); /* { dg-warning "conversion lacks type" "bare %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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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% 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* Various tests of bad argument types.  */
+  printf ("%d", l); /* { dg-warning "format" "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" } */
+  /* 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
+     discussion of the requirements of rules on identical representation,
+     and of the application of the as if rule with the new va_arg
+     allowances in C99 to printf.)  Likewise, we should warn if
+     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" } */
+  /* 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" } */
+  /* The historical behavior is to allow signed / unsigned types
+     interchangably as arguments.  For values representable in both types,
+     such usage may be correct.  For now preserve the behavior of GCC
+     in such cases.
+  */
+  printf ("%d", u);
+  /* Wrong number of arguments.  */
+  printf ("%d%d", i); /* { dg-warning "arguments" "wrong number of args" } */
+  printf ("%d", i, i); /* { dg-warning "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" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-2.c
@@ -0,0 +1,25 @@
+/* Test for printf formats.  Formats using C99 features should be rejected
+   outside of C99 mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, double d, llong ll, intmax_t j, size_t z, ptrdiff_t t)
+{
+  /* Some tests already in c90-printf-1.c, e.g. %lf.  */
+  /* The widths hh, ll, j, z, t are new.  */
+  printf ("%hhd", i); /* { dg-warning "unknown|format" "%hh is unsupported" } */
+  printf ("%I64d", ll); /* { dg-warning "length|C" "%I64 in C90" } */
+  printf ("%jd", j); /* { dg-warning "unknown|format" "%j is unsupported" } */
+  printf ("%zu", z); /* { dg-warning "unknown|format" "%z is unsupported" } */
+  printf ("%td", t); /* { dg-warning "unknown|format" "%t is unsupported" } */
+  /* The formats F, a, A are new.  */
+  printf ("%F", d); /* { dg-warning "unknown|format" "%F is unsupported" } */
+  printf ("%a", d); /* { dg-warning "unknown|format" "%a is unsupported" } */
+  printf ("%A", d); /* { dg-warning "unknown|format" "%A is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-3.c
@@ -0,0 +1,43 @@
+/* Test for printf formats.  Test that the C90 functions get their default
+   attributes in strict C90 mode, but the C99 and gettext functions
+   do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, char *s, size_t n, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5, va_list v6, va_list v7, va_list v8)
+{
+  fprintf (stdout, "%d", i);
+  fprintf (stdout, "%ld", i); /* { dg-warning "format" "fprintf" } */
+  printf ("%d", i);
+  printf ("%ld", i); /* { dg-warning "format" "printf" } */
+  /* The "unlocked" functions shouldn't warn in c90 mode.  */
+  fprintf_unlocked (stdout, "%ld", i);
+  printf_unlocked ("%ld", i);
+  sprintf (s, "%d", i);
+  sprintf (s, "%ld", i); /* { dg-warning "format" "sprintf" } */
+  vfprintf (stdout, "%d", v0);
+  vfprintf (stdout, "%Y", v1); /* { dg-warning "format" "vfprintf" } */
+  vprintf ("%d", v2);
+  vprintf ("%Y", v3); /* { dg-warning "format" "vprintf" } */
+  /* The following used to give a bogus warning.  */
+  vprintf ("%*.*d", v8); /* { dg-warning "format" "dot is invalid" } */
+  vsprintf (s, "%d", v4);
+  vsprintf (s, "%Y", v5); /* { dg-warning "format" "Y is invalid" } */
+  snprintf (s, n, "%d", i);
+  snprintf (s, n, "%ld", i);
+  vsnprintf (s, n, "%d", v6);
+  vsnprintf (s, n, "%Y", v7);
+  printf (gettext ("%d"), i);
+  printf (gettext ("%ld"), i);
+  printf (dgettext ("", "%d"), i);
+  printf (dgettext ("", "%ld"), (long) i);
+  printf (dcgettext ("", "%d", 0), i);
+  printf (dcgettext ("", "%ld", 0), (long) i);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-1.c
@@ -0,0 +1,119 @@
+/* Test for scanf formats.  Formats using C90 features, including cases
+   where C90 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, unsigned int *uip, short int *hp, unsigned short int *uhp,
+     long int *lp, unsigned long int *ulp, float *fp, double *dp,
+     long double *ldp, char *s, signed char *ss, unsigned char *us,
+     void **pp, int *n, llong *llp, ullong *ullp, wchar_t *ls,
+     const int *cip, const int *cn, const char *cs, const void **ppc,
+     void *const *pcp, short int *hn, long int *ln, void *p, char **sp,
+     volatile void *ppv)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.2 (pages 134-138).  */
+  /* Basic sanity checks for the different components of a format.  */
+  scanf ("%d", ip);
+  scanf ("%*d");
+  scanf ("%3d", ip);
+  scanf ("%hd", hp);
+  scanf ("%3ld", lp);
+  scanf ("%*3d");
+  scanf ("%d %ld", ip, lp);
+  /* Valid and invalid %% constructions.  */
+  scanf ("%%");
+  scanf ("%*%"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%*%\n"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%4%"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%4%\n"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%h%"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%h%\n"); /* { dg-warning "format" "bogus %%" } */
+  /* Valid, invalid and silly assignment-suppression constructions.  */
+  scanf ("%*d%*i%*o%*u%*x%*X%*e%*E%*f%*g%*G%*s%*[abc]%*c%*p");
+  scanf ("%*2d%*8s%*3c");
+  scanf ("%*n", n); /* { dg-warning "suppress" "suppression of %n" } */
+  scanf ("%*hd"); /* { dg-warning "together" "suppression with length" } */
+  /* Valid, invalid and silly width constructions.  */
+  scanf ("%2d%3i%4o%5u%6x%7X%8e%9E%10f%11g%12G%13s%14[abc]%15c%16p",
+	 ip, ip, uip, uip, uip, uip, fp, fp, fp, fp, fp, s, s, s, pp);
+  scanf ("%0d", ip); /* { dg-warning "width" "warning for zero width" } */
+  scanf ("%3n", n); /* { dg-warning "width" "width with %n" } */
+  /* Valid and invalid %h, %l, %L constructions.  */
+  scanf ("%hd%hi%ho%hu%hx%hX%hn", hp, hp, uhp, uhp, uhp, uhp, hn);
+  scanf ("%he", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hE", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hf", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hg", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hG", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hs", hp);
+  scanf ("%h[ac]", s); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hc", hp);
+  scanf ("%hp", pp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%h"); /* { dg-warning "conversion lacks type" "bare %h" } */
+  scanf ("%h."); /* { dg-warning "conversion" "bogus %h" } */
+  scanf ("%ld%li%lo%lu%lx%lX%ln", lp, lp, ulp, ulp, ulp, ulp, ln);
+  scanf ("%le%lE%lf%lg%lG", dp, dp, dp, dp, dp);
+  scanf ("%lp", pp); /* { dg-warning "length" "bad use of %l" } */
+  /* These next three formats were added in C94.  */
+  scanf ("%ls", ls); /* { dg-warning "length|C" "bad use of %l" } */
+  scanf ("%l[ac]", ls); /* { dg-warning "length|C" "bad use of %l" } */
+  scanf ("%lc", ls); /* { dg-warning "length|C" "bad use of %l" } */
+  scanf ("%Ld", llp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Li", llp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lo", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lu", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lx", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%LX", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Ls", s); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%L[ac]", s); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lc", s); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lp", pp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Ln", n); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  /* Valid uses of each bare conversion.  */
+  scanf ("%d%i%o%u%x%X%e%E%f%g%G%s%[abc]%c%p%n%%", ip, ip, uip, uip, uip,
+	 uip, fp, fp, fp, fp, fp, s, s, s, pp, n);
+  /* Allow other character pointers with %s, %c, %[].  */
+  scanf ("%2s%3s%4c%5c%6[abc]%7[abc]", ss, us, ss, us, ss, us);
+  /* Further tests for %[].  */
+  scanf ("%[%d]%d", s, ip);
+  scanf ("%[^%d]%d", s, ip);
+  scanf ("%[]%d]%d", s, ip);
+  scanf ("%[^]%d]%d", s, ip);
+  scanf ("%[%d]%d", s, ip);
+  scanf ("%[]abcd", s); /* { dg-warning "no closing" "incomplete scanset" } */
+  /* Various tests of bad argument types.  Some of these are only pedantic
+     warnings.
+  */
+  scanf ("%d", lp); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%d", uip); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%d", pp); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", ppc); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", ppv); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%s", n); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%s", p); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", p); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", sp); /* { dg-warning "format" "bad argument types" } */
+  /* Tests for writing into constant values.  */
+  scanf ("%d", cip); /* { dg-warning "constant" "%d writing into const" } */
+  scanf ("%n", cn); /* { dg-warning "constant" "%n writing into const" } */
+  scanf ("%s", cs); /* { dg-warning "constant" "%s writing into const" } */
+  scanf ("%p", pcp); /* { dg-warning "constant" "%p writing into const" } */
+  /* Wrong number of arguments.  */
+  scanf ("%d%d", ip); /* { dg-warning "arguments" "wrong number of args" } */
+  scanf ("%d", ip, ip); /* { dg-warning "arguments" "wrong number of args" } */
+  /* Miscellaneous bogus constructions.  */
+  scanf (""); /* { dg-warning "zero-length" "warning for empty format" } */
+  scanf ("\0"); /* { dg-warning "embedded" "warning for embedded NUL" } */
+  scanf ("%d\0", ip); /* { dg-warning "embedded" "warning for embedded NUL" } */
+  scanf ("%d\0%d", ip, ip); /* { dg-warning "embedded|too many" "warning for embedded NUL" } */
+  scanf (NULL); /* { dg-warning "null" "null format string warning" } */
+  scanf ("%"); /* { dg-warning "trailing" "trailing % warning" } */
+  scanf ("%d", (int *)0); /* { dg-warning "null" "writing into NULL" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-2.c
@@ -0,0 +1,26 @@
+/* Test for scanf formats.  Formats using C99 features should be rejected
+   outside of C99 mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (signed char *hhp, float *fp, llong *llp, intmax_t *jp,
+     size_t *zp, ptrdiff_t *tp)
+{
+  /* Some tests already in c90-scanf-1.c.  */
+  /* The widths hh, ll, j, z, t are new.  */
+  scanf ("%hhd", hhp); /* { dg-warning "unknown|format" "%hh is unsupported" } */
+  scanf ("%I64d", llp); /* { dg-warning "length|C" "%I64 in C90" } */
+  scanf ("%jd", jp); /* { dg-warning "unknown|format" "%j is unsupported" } */
+  scanf ("%zu", zp); /* { dg-warning "unknown|format" "%z is unsupported" } */
+  scanf ("%td", tp); /* { dg-warning "unknown|format" "%t is unsupported" } */
+  /* The formats F, a, A are new.  */
+  scanf ("%F", fp); /* { dg-warning "unknown|format" "%F is unsupported" } */
+  scanf ("%a", fp); /* { dg-warning "unknown|format" "%a is unsupported" } */
+  scanf ("%A", fp); /* { dg-warning "unknown|format" "%A is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-3.c
@@ -0,0 +1,20 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char **sp, wchar_t **lsp)
+{
+  /* %a formats for allocation, only recognized in C90 mode, are a
+     GNU extension.
+  */
+  scanf ("%as", sp); /* { dg-warning "flag" "%as is unsupported" } */
+  scanf ("%aS", lsp); /* { dg-warning "format|flag" "%aS is unsupported" } */
+  scanf ("%a[bcd]", sp); /* { dg-warning "flag" "%a[] is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-4.c
@@ -0,0 +1,31 @@
+/* Test for scanf formats.  Test that the C90 functions get their default
+   attributes in strict C90 mode, but the C99 and gettext functions
+   do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, char *s, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5)
+{
+  fscanf (stdin, "%d", ip);
+  fscanf (stdin, "%ld", ip); /* { dg-warning "format" "fscanf" } */
+  scanf ("%d", ip);
+  scanf ("%ld", ip); /* { dg-warning "format" "scanf" } */
+  sscanf (s, "%d", ip);
+  sscanf (s, "%ld", ip); /* { dg-warning "format" "sscanf" } */
+  vfscanf (stdin, "%d", v0);
+  vscanf ("%d", v2);
+  vsscanf (s, "%d", v4);
+  scanf (gettext ("%d"), ip);
+  scanf (gettext ("%ld"), ip);
+  scanf (dgettext ("", "%d"), ip);
+  scanf (dgettext ("", "%ld"), ip);
+  scanf (dcgettext ("", "%d", 0), ip);
+  scanf (dcgettext ("", "%ld", 0), ip);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-5.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-5.c
@@ -0,0 +1,20 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char **sp, wchar_t **lsp)
+{
+  /* m assignment-allocation modifier, recognized in both C90
+     and C99 modes, is a POSIX and ISO/IEC WDTR 24731-2 extension.  */
+  scanf ("%ms", sp); /* { dg-warning "unknown|format" "%ms is unsupported" } */
+  scanf ("%mS", lsp); /* { dg-warning "unknown|format" "%mS is unsupported" } */
+  scanf ("%mls", lsp); /* { dg-warning "unknown|format" "%mls is unsupported" } */
+  scanf ("%m[bcd]", sp); /* { dg-warning "unknown|format" "%m[] is unsupported" } */
+  scanf ("%ml[bcd]", lsp); /* { dg-warning "unknown|format" "%ml[] is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-1.c
@@ -0,0 +1,20 @@
+/* Test for strftime formats.  Formats using C90 features.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wformat-y2k" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.12.3.5 (pages 174-175).  */
+  /* Formats which are Y2K-compliant (no 2-digit years).  */
+  strftime (s, m, "%a%A%b%B%d%H%I%j%m%M%p%S%U%w%W%X%Y%Z%%", tp);
+  /* Formats with 2-digit years.  */
+  strftime (s, m, "%y", tp); /* { dg-warning "only last 2" "2-digit year" } */
+  /* Formats with 2-digit years in some locales.  */
+  strftime (s, m, "%c", tp); /* { dg-warning "some locales" "2-digit year" } */
+  strftime (s, m, "%x", tp); /* { dg-warning "some locales" "2-digit year" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-2.c
@@ -0,0 +1,30 @@
+/* Test for strftime formats.  Rejection of formats using C99 features in
+   pedantic C90 mode.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wformat-y2k" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  strftime (s, m, "%C", tp); /* { dg-warning "format" "%C is unsupported" } */
+  strftime (s, m, "%D", tp); /* { dg-warning "format" "%D is unsupported" } */
+  strftime (s, m, "%e", tp); /* { dg-warning "format" "%e is unsupported" } */
+  strftime (s, m, "%F", tp); /* { dg-warning "format" "%F is unsupported" } */
+  strftime (s, m, "%g", tp); /* { dg-warning "format" "%g is unsupported" } */
+  strftime (s, m, "%G", tp); /* { dg-warning "format" "%G is unsupported" } */
+  strftime (s, m, "%h", tp); /* { dg-warning "format" "%h is unsupported" } */
+  strftime (s, m, "%n", tp); /* { dg-warning "format" "%n is unsupported" } */
+  strftime (s, m, "%r", tp); /* { dg-warning "format" "%r is unsupported" } */
+  strftime (s, m, "%R", tp); /* { dg-warning "format" "%R is unsupported" } */
+  strftime (s, m, "%t", tp); /* { dg-warning "format" "%t is unsupported" } */
+  strftime (s, m, "%T", tp); /* { dg-warning "format" "%T is unsupported" } */
+  strftime (s, m, "%u", tp); /* { dg-warning "format" "%u is unsupported" } */
+  strftime (s, m, "%V", tp); /* { dg-warning "format" "%V is unsupported" } */
+  strftime (s, m, "%z", tp); /* { dg-warning "C" "%z not in C90" } */
+  strftime (s, m, "%EX", tp); /* { dg-warning "C" "%E not in C90" } */
+  strftime (s, m, "%OW", tp); /* { dg-warning "C" "%O not in C90" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c94-printf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c94-printf-1.c
@@ -0,0 +1,19 @@
+/* Test for printf formats.  Changes in C94 to C90.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:199409 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (wint_t lc, wchar_t *ls)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.1 (pages 131-134),
+     as amended by ISO/IEC 9899:1990/Amd.1:1995 (E) (pages 4-5).
+     We do not repeat here all the C90 format checks, but just verify
+     that %ls and %lc are accepted without warning.
+  */
+  printf ("%lc", lc);
+  printf ("%ls", ls);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c94-scanf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c94-scanf-1.c
@@ -0,0 +1,18 @@
+/* Test for scanf formats.  Changes in C94 to C90.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:199409 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (wchar_t *ls)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.2 (pages 134-138),
+     as amended by ISO/IEC 9899:1990/Amd.1:1995 (E) (pages 5-6).
+     We do not repeat here all the C90 format checks, but just verify
+     that %ls, %lc, %l[] are accepted without warning.
+  */
+  scanf ("%lc%ls%l[abc]", ls, ls, ls);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-1.c
@@ -0,0 +1,122 @@
+/* Test for printf formats.  Formats using C99 features, including cases
+   where C99 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, unsigned int u, double d, char *s, void *p, int *n,
+     long double ld, wint_t lc, wchar_t *ls, long long int ll,
+     unsigned long long int ull, signed char *ss, unsigned char *us,
+     long long int *lln, intmax_t j, uintmax_t uj, intmax_t *jn,
+     size_t z, signed_size_t sz, signed_size_t *zn,
+     ptrdiff_t t, ptrdiff_t *tn)
+{
+  /* See ISO/IEC 9899:1999 (E) subclause 7.19.6.1 (pages 273-281).
+     We do not repeat here most of the checks for correct C90 formats
+     or completely broken formats.
+  */
+  /* Valid and invalid %h, %hh, %l, %I64, %j, %z, %t, %L constructions.  */
+  printf ("%hf", d); /* { dg-warning "length" "bad use of %h" } */
+  printf ("%hF", d); /* { dg-warning "unknown|format" "bad use of %hF" } */
+  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 ("%ha", d); /* { dg-warning "unknown|format" "bad use of %ha" } */
+  printf ("%hA", d); /* { dg-warning "unknown|format" "bad use of %hA" } */
+  printf ("%hc", i);
+  printf ("%hs", (short *)s);
+  printf ("%hp", p); /* { dg-warning "length" "bad use of %h" } */
+  printf ("%lc", lc);
+  printf ("%ls", ls);
+  printf ("%lp", p); /* { dg-warning "length|C" "bad use of %l" } */
+  printf ("%I64d%I64i%I64o%I64u%I64x%I64X", ll, ll, ull, ull, ull, ull);
+  printf ("%I64n", lln);
+  printf ("%I64f", d); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64F", d); /* { dg-warning "unknown|format" "bad use of %I64F" } */
+  printf ("%I64e", d); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64E", d); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64g", d); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64G", d); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64a", d); /* { dg-warning "unknown|format" "bad use of %I64a" } */
+  printf ("%I64A", d); /* { dg-warning "unknown|format" "bad use of %I64A" } */
+  printf ("%I64c", i); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64s", s); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64p", p); /* { dg-warning "length" "bad use of %I64" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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% 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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 ("%-08F", d); /* { dg-warning "unknown|format" "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 ("%-08a", d); /* { dg-warning "unknown|format" "0 flag ignored with - flag" } */
+  printf ("%-08A", d); /* { dg-warning "unknown|format" "0 flag ignored with - flag" } */
+  /* Various tests of bad argument types.  Mostly covered in c90-printf-1.c;
+     here just test for pointer target sign with %hhn.  (Probably allowed
+     by the standard, but a bad idea, so GCC should diagnose if what
+     is used is not signed char *.)
+  */
+  printf ("%hhn", s); /* { dg-warning "unknown|format" "%hhn is unsupported" } */
+  printf ("%hhn", us); /* { dg-warning "unknown|format" "%hhn is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-2.c
@@ -0,0 +1,33 @@
+/* Test for printf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, long long ll, size_t z, wint_t lc, wchar_t *ls)
+{
+  /* The length modifiers q, Z and L as applied to integer formats are
+     extensions.
+  */
+  printf ("%qd", ll); /* { dg-warning "unknown|format" "%q length is unsupported" } */
+  printf ("%Ld", ll); /* { dg-warning "unknown|format" "%L length is unsupported" } */
+  printf ("%Zd", z); /* { dg-warning "unknown|format" "%Z lengthis unsupported" } */
+  /* The conversion specifiers C and S are X/Open extensions; the
+     conversion specifier m is a GNU extension.
+  */
+  printf ("%m"); /* { dg-warning "unknown|format" "printf %m is unsupported" } */
+  printf ("%C", lc); /* { dg-warning "C" "printf %C" } */
+  printf ("%S", ls); /* { dg-warning "C" "printf %S" } */
+  /* The flag character ', and the use of operand number $ formats, are
+     X/Open extensions.
+  */
+  printf ("%'d", i); /* { dg-warning "C" "printf ' flag" } */
+  printf ("%1$d", i); /* { dg-warning "C" "printf $ format" } */
+  /* The flag character I is a GNU extension.  */
+  printf ("%Ix", z);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-3.c
@@ -0,0 +1,40 @@
+/* Test for printf formats.  Test that the C99 functions get their default
+   attributes in strict C99 mode, but the gettext functions do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, char *s, size_t n, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5, va_list v6, va_list v7)
+{
+  fprintf (stdout, "%d", i);
+  fprintf (stdout, "%ld", i); /* { dg-warning "format" "fprintf" } */
+  printf ("%d", i);
+  printf ("%ld", i); /* { dg-warning "format" "printf" } */
+  /* The "unlocked" functions shouldn't warn in c99 mode.  */
+  fprintf_unlocked (stdout, "%ld", i);
+  printf_unlocked ("%ld", i);
+  sprintf (s, "%d", i);
+  sprintf (s, "%ld", i); /* { dg-warning "format" "sprintf" } */
+  snprintf (s, n, "%d", i);
+  snprintf (s, n, "%ld", i); /* { dg-warning "format" "snprintf" } */
+  vfprintf (stdout, "%d", v0);
+  vfprintf (stdout, "%Y", v1); /* { dg-warning "format" "vfprintf" } */
+  vprintf ("%d", v0);
+  vprintf ("%Y", v1); /* { dg-warning "format" "vprintf" } */
+  vsprintf (s, "%d", v0);
+  vsprintf (s, "%Y", v1); /* { dg-warning "format" "vsprintf" } */
+  vsnprintf (s, n, "%d", v0);
+  vsnprintf (s, n, "%Y", v1); /* { dg-warning "format" "vsnprintf" } */
+  printf (gettext ("%d"), i);
+  printf (gettext ("%ld"), (long) i);
+  printf (dgettext ("", "%d"), i);
+  printf (dgettext ("", "%ld"), (long) i);
+  printf (dcgettext ("", "%d", 0), i);
+  printf (dcgettext ("", "%ld", 0), (long) i);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-1.c
@@ -0,0 +1,75 @@
+/* Test for scanf formats.  Formats using C99 features, including cases
+   where C99 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, unsigned int *uip, short int *hp, unsigned short int *uhp,
+     signed char *hhp, unsigned char *uhhp, long int *lp,
+     unsigned long int *ulp, float *fp, double *dp, long double *ldp, char *s,
+     void **pp, int *n, long long *llp, unsigned long long *ullp, wchar_t *ls,
+     short int *hn, signed char *hhn, long int *ln, long long int *lln,
+     intmax_t *jp, uintmax_t *ujp, intmax_t *jn, size_t *zp,
+     signed_size_t *szp, signed_size_t *zn, ptrdiff_t *tp,
+     unsigned_ptrdiff_t *utp, ptrdiff_t *tn)
+{
+  /* See ISO/IEC 9899:1999 (E) subclause 7.19.6.2 (pages 281-288).
+     We do not repeat here most of the checks for correct C90 formats
+     or completely broken formats.
+  */
+  /* Valid, invalid and silly assignment-suppression
+     and width constructions.
+  */
+  scanf ("%*d%*i%*o%*u%*x%*X%*e%*E%*f%*g%*G%*s%*[abc]%*c%*p");
+  scanf ("%*2d%*8s%*3c");
+  scanf ("%*n", n); /* { dg-warning "suppress" "suppression of %n" } */
+  scanf ("%*hd"); /* { dg-warning "together" "suppression with length" } */
+  scanf ("%2d%3i%4o%5u%6x%7X%10e%11E%12f%14g%15G%16s%3[abc]%4c%5p",
+	 ip, ip, uip, uip, uip, uip, fp, fp, fp, fp, fp,
+	 s, s, s, pp);
+  scanf ("%0d", ip); /* { dg-warning "width" "warning for zero width" } */
+  scanf ("%3n", n); /* { dg-warning "width" "width with %n" } */
+  /* Valid and invalid %h, %hh, %l, %I64, %j, %z, %t, %L constructions.  */
+  scanf ("%hd%hi%ho%hu%hx%hX%hn", hp, hp, uhp, uhp, uhp, uhp, hn);
+  scanf ("%he", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hE", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hf", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hg", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hG", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hs", hp);
+  scanf ("%h[ac]", s); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hc", (short *)s);
+  scanf ("%hp", pp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hhd", hhp); /* { dg-warning "unknown|format" "%hh is unsupported" } */
+  scanf ("%ld%li%lo%lu%lx%lX%ln", lp, lp, ulp, ulp, ulp, ulp, ln);
+  scanf ("%le%lE%lf%lg%lG", dp, dp, dp, dp, dp);
+  scanf ("%lp", pp); /* { dg-warning "length" "bad use of %l" } */
+  scanf ("%ls", ls);
+  scanf ("%l[ac]", ls);
+  scanf ("%lc", ls);
+  scanf ("%I64d%I64i%I64o%I64u%I64x%I64X%I64n", llp, llp, ullp, ullp, ullp, ullp,
+	 lln);
+  scanf ("%I64e", fp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64E", fp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64f", fp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64F", fp); /* { dg-warning "unknown|format" "'F' is unsupported" } */
+  scanf ("%I64g", fp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64G", fp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64s", s); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64[ac]", s); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64c", s); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64p", pp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%jd", jp); /* { dg-warning "unknown|format" "%j not supported" } */
+  scanf ("%zd", zp); /* { dg-warning "unknown|format" "%z not supported" } */
+  scanf ("%td", tp); /* { dg-warning "unknown|format" "%t not supported" } */
+  scanf ("%Lf", llp); /* { dg-warning "unknown|format" "bad use of %L is not supported" } */
+  /* Valid uses of each bare conversion.  */
+  scanf ("%d%i%o%u%x%X%e%E%f%g%G%s%[abc]%c%p%n%%", ip, ip, uip, uip, uip,
+         uip, fp, fp, fp, fp, fp, s, s, s, pp, n);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-2.c
@@ -0,0 +1,27 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, long long int *llp, wchar_t *ls)
+{
+  /* The length modifiers q and L as applied to integer formats are
+     extensions.
+  */
+  scanf ("%qd", llp); /* { dg-warning "unknown|format" "%q is unsupported" } */
+  scanf ("%Ld", llp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  /* The conversion specifiers C and S are X/Open extensions.  */
+  scanf ("%C", ls); /* { dg-warning "C" "scanf %C" } */
+  scanf ("%S", ls); /* { dg-warning "C" "scanf %S" } */
+  /* The use of operand number $ formats is an X/Open extension.  */
+  scanf ("%1$d", ip); /* { dg-warning "C" "scanf $ format" } */
+  /* glibc also supports flags ' and I on scanf formats as an extension.  */
+  scanf ("%'d", ip); /* { dg-warning "C" "scanf ' flag" } */
+  scanf ("%Id", (ssize_t *)ip);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-3.c
@@ -0,0 +1,33 @@
+/* Test for scanf formats.  Test that the C99 functions get their default
+   attributes in strict C99 mode, but the gettext functions do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, char *s, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5)
+{
+  fscanf (stdin, "%d", ip);
+  fscanf (stdin, "%ld", ip); /* { dg-warning "format" "fscanf" } */
+  scanf ("%d", ip);
+  scanf ("%ld", ip); /* { dg-warning "format" "scanf" } */
+  sscanf (s, "%d", ip);
+  sscanf (s, "%ld", ip); /* { dg-warning "format" "sscanf" } */
+  vfscanf (stdin, "%d", v0);
+  vfscanf (stdin, "%Y", v1); /* { dg-warning "format" "vfscanf" } */
+  vscanf ("%d", v2);
+  vscanf ("%Y", v3); /* { dg-warning "format" "vscanf" } */
+  vsscanf (s, "%d", v4);
+  vsscanf (s, "%Y", v5); /* { dg-warning "format" "vsscanf" } */
+  scanf (gettext ("%d"), ip);
+  scanf (gettext ("%ld"), ip);
+  scanf (dgettext ("", "%d"), ip);
+  scanf (dgettext ("", "%ld"), ip);
+  scanf (dcgettext ("", "%d", 0), ip);
+  scanf (dcgettext ("", "%ld", 0), ip);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-4.c
@@ -0,0 +1,20 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char **sp, wchar_t **lsp)
+{
+  /* m assignment-allocation modifier, recognized in both C90
+     and C99 modes, is a POSIX and ISO/IEC WDTR 24731-2 extension.  */
+  scanf ("%ms", sp); /* { dg-warning "unknown|format" "%ms is unsupported" } */
+  scanf ("%mS", lsp); /* { dg-warning "unknown|format" "%mS is unsupported" } */
+  scanf ("%mls", lsp); /* { dg-warning "unknown|format" "%mls is unsupported" } */
+  scanf ("%m[bcd]", sp); /* { dg-warning "unknown|format" "%m[] is unsupported" } */
+  scanf ("%ml[bcd]", lsp); /* { dg-warning "unknown|format" "%ml[] is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-1.c
@@ -0,0 +1,30 @@
+/* Test for strftime formats.  Formats using C99 features.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat -Wformat-y2k" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.12.3.5 (pages 174-175).  */
+  /* Formats which are Y2K-compliant (no 2-digit years).  */
+  strftime (s, m, "%a%A%b%B%d%H%I%j%m%M%p%S%U%w%W%X%Y%z%Z%%", tp);
+  strftime (s, m, "%EX%EY%Od%OH%OI%Om%OM%OS%OU%Ow%OW", tp);
+  /* Formats with 2-digit years.  */
+  strftime (s, m, "%D", tp); /* { dg-warning "unknown" "2-digit year unsupported" } */
+  strftime (s, m, "%g", tp); /* { dg-warning "unknown" "2-digit year unsupported" } */
+  strftime (s, m, "%y", tp); /* { dg-warning "only last 2" "2-digit year" } */
+  strftime (s, m, "%Oy", tp); /* { dg-warning "only last 2" "2-digit year" } */
+  /* Formats with 2-digit years in some locales.  */
+  strftime (s, m, "%c", tp); /* { dg-warning "some locales" "2-digit year" } */
+  strftime (s, m, "%Ec", tp); /* { dg-warning "some locales" "2-digit year" } */
+  strftime (s, m, "%x", tp); /* { dg-warning "some locales" "2-digit year" } */
+  strftime (s, m, "%Ex", tp); /* { dg-warning "some locales" "2-digit year" } */
+  /* %Ey is explicitly an era offset not a 2-digit year; but in some
+     locales the E modifier may be ignored.
+  */
+  strftime (s, m, "%Ey", tp); /* { dg-warning "some locales" "2-digit year" } */
+  }
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-2.c
@@ -0,0 +1,24 @@
+/* Test for strftime formats.  Rejection of extensions in pedantic mode.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  /* %P is a lowercase version of %p.  */
+  strftime (s, m, "%P", tp); /* { dg-warning "unknown" "strftime %P" } */
+  /* %k is %H but padded with a space rather than 0 if necessary.  */
+  strftime (s, m, "%k", tp); /* { dg-warning "unknown" "strftime %k" } */
+  /* %l is %I but padded with a space rather than 0 if necessary.  */
+  strftime (s, m, "%l", tp); /* { dg-warning "unknown" "strftime %l" } */
+  /* %s is the number of seconds since the Epoch.  */
+  strftime (s, m, "%s", tp); /* { dg-warning "unknown" "strftime %s" } */
+  /* Extensions using %O already tested in c99-strftime-1.c.  */
+  /* Width and flags are GNU extensions for strftime.  */
+  strftime (s, m, "%20Y", tp); /* { dg-warning "C" "strftime width" } */
+  strftime (s, m, "%^A", tp); /* { dg-warning "C" "strftime flags" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_cast-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_cast-1.c
@@ -0,0 +1,17 @@
+/* Test for strings cast through integer types: should not be treated
+   as format strings unless the types are of the same width as
+   pointers (intptr_t or similar).  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+f (int x)
+{
+  printf("%s", x); /* { dg-warning "format" } */
+  printf((char *)(size_t)"%s", x); /* { dg-warning "format" } */
+  printf((char *)(char)"%s", x); /* { dg-warning "cast from pointer to integer of different size" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-1.c
@@ -0,0 +1,40 @@
+/* Test for warnings for missing format attributes.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  vprintf (fmt, ap); /* { dg-warning "candidate" "printf attribute warning" } */
+  va_end (ap);
+}
+
+void
+bar (const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  vscanf (fmt, ap); /* { dg-warning "candidate" "scanf attribute warning" } */
+  va_end (ap);
+}
+
+__attribute__((__format__(__ms_printf__, 1, 2))) void
+foo2 (const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  vprintf (fmt, ap);
+  va_end (ap);
+}
+
+void
+vfoo (const char *fmt, va_list arg)
+{
+  vprintf (fmt, arg); /* { dg-warning "candidate" "printf attribute warning 2" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-2.c
@@ -0,0 +1,17 @@
+/* Test for warnings for missing format attributes.  Don't warn if no
+   relevant parameters for a format attribute; see c/1017.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, ...)
+{
+  va_list ap;
+  va_start (ap, i);
+  vprintf ("Foo %s bar %s", ap); /* { dg-bogus "candidate" "bogus printf attribute warning" } */
+  va_end (ap);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-3.c
@@ -0,0 +1,27 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+void
+foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
+{
+  noattr_t na1 = na;
+  noattr_t na2 = a; /* { dg-warning "candidate" "initialization warning" } */
+  attr_t a1 = na;
+  attr_t a2 = a;
+
+  vnoattr_t vna1 = vna;
+  vnoattr_t vna2 = va; /* { dg-warning "candidate" "initialization warning" } */
+  vattr_t va1 = vna;
+  vattr_t va2 = va;
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-4.c
@@ -0,0 +1,33 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+void
+foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
+{
+  noattr_t na1, na2;
+  attr_t a1, a2;
+
+  vnoattr_t vna1, vna2;
+  vattr_t va1, va2;
+
+  na1 = na;
+  na2 = a; /* { dg-warning "candidate" "assignment warning" } */
+  a1 = na;
+  a2 = a;
+
+  vna1 = vna;
+  vna2 = va; /* { dg-warning "candidate" "assignment warning" } */
+  va1 = vna;
+  va1 = va;
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-5.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-5.c
@@ -0,0 +1,49 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+noattr_t
+foo1 (noattr_t na, attr_t a, int i)
+{
+  if (i)
+    return na;
+  else
+    return a; /* { dg-warning "candidate" "return type warning" } */
+}
+
+attr_t
+foo2 (noattr_t na, attr_t a, int i)
+{
+  if (i)
+    return na;
+  else
+    return a;
+}
+
+vnoattr_t
+foo3 (vnoattr_t vna, vattr_t va, int i)
+{
+  if (i)
+    return vna;
+  else
+    return va; /* { dg-warning "candidate" "return type warning" } */
+}
+
+vattr_t
+foo4 (vnoattr_t vna, vattr_t va, int i)
+{
+  if (i)
+    return vna;
+  else
+    return va;
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-6.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-6.c
@@ -0,0 +1,32 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+extern void foo1 (noattr_t);
+extern void foo2 (attr_t);
+extern void foo3 (vnoattr_t);
+extern void foo4 (vattr_t);
+
+void
+foo (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
+{
+  foo1 (na);
+  foo1 (a); /* { dg-warning "candidate" "parameter passing warning" } */
+  foo2 (na);
+  foo2 (a);
+
+  foo3 (vna);
+  foo3 (va); /* { dg-warning "candidate" "parameter passing warning" } */
+  foo4 (vna);
+  foo4 (va);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_multattr-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_multattr-1.c
@@ -0,0 +1,51 @@
+/* Test for multiple format attributes.  Test for printf and scanf attributes
+   together.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* If we specify multiple attributes for a single function, they should
+   all apply.  This should apply whether they are on the same declaration
+   or on different declarations.  */
+
+extern void my_vprintf_scanf (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_printf__, 1, 0)))
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern void my_vprintf_scanf2 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)))
+     __attribute__((__format__(__ms_printf__, 1, 0)));
+
+extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_printf__, 1, 0)));
+extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_printf__, 1, 0)));
+
+void
+foo (va_list ap, int *ip, long *lp)
+{
+  my_vprintf_scanf ("%d", ap, "%d", ip);
+  my_vprintf_scanf ("%d", ap, "%ld", lp);
+  my_vprintf_scanf ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf2 ("%d", ap, "%d", ip);
+  my_vprintf_scanf2 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf2 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf2 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf3 ("%d", ap, "%d", ip);
+  my_vprintf_scanf3 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf3 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf3 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf4 ("%d", ap, "%d", ip);
+  my_vprintf_scanf4 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf4 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf4 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_multattr-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_multattr-2.c
@@ -0,0 +1,40 @@
+/* Test for multiple format attributes.  Test for printf and scanf attributes
+   together, in different places on the declarations.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* If we specify multiple attributes for a single function, they should
+   all apply, wherever they are placed on the declarations.  */
+
+extern __attribute__((__format__(__ms_printf__, 1, 0))) void
+     my_vprintf_scanf (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern void (__attribute__((__format__(__ms_printf__, 1, 0))) my_vprintf_scanf2)
+     (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern __attribute__((__format__(__ms_scanf__, 3, 4))) void
+     (__attribute__((__format__(__ms_printf__, 1, 0))) my_vprintf_scanf3)
+     (const char *, va_list, const char *, ...);
+
+void
+foo (va_list ap, int *ip, long *lp)
+{
+  my_vprintf_scanf ("%d", ap, "%d", ip);
+  my_vprintf_scanf ("%d", ap, "%ld", lp);
+  my_vprintf_scanf ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf2 ("%d", ap, "%d", ip);
+  my_vprintf_scanf2 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf2 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf2 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf3 ("%d", ap, "%d", ip);
+  my_vprintf_scanf3 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf3 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf3 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_multattr-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_multattr-3.c
@@ -0,0 +1,29 @@
+/* Test for multiple format_arg attributes.  Test for both branches
+   getting checked.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+extern char *ngettext (const char *, const char *, unsigned long int)
+     __attribute__((__format_arg__(1))) __attribute__((__format_arg__(2)));
+
+void
+foo (long l, int nfoo)
+{
+  printf (ngettext ("%d foo", "%d foos", nfoo), nfoo);
+  printf (ngettext ("%d foo", "%d foos", l), l); /* { dg-warning "int" "wrong type in conditional expr" } */
+  printf (ngettext ("%d foo", "%ld foos", l), l); /* { dg-warning "int" "wrong type in conditional expr" } */
+  printf (ngettext ("%ld foo", "%d foos", l), l); /* { dg-warning "int" "wrong type in conditional expr" } */
+  /* Should allow one case to have extra arguments.  */
+  printf (ngettext ("1 foo", "%d foos", nfoo), nfoo);
+  printf (ngettext ("1 foo", "many foos", nfoo), nfoo); /* { dg-warning "too many" "too many args in all branches" } */
+  printf (ngettext ("", "%d foos", nfoo), nfoo);
+  printf (ngettext ("1 foo", (nfoo > 0) ? "%d foos" : "no foos", nfoo), nfoo);
+  printf (ngettext ("%d foo", (nfoo > 0) ? "%d foos" : "no foos", nfoo), nfoo);
+  printf (ngettext ("%ld foo", (nfoo > 0) ? "%d foos" : "no foos", nfoo), nfoo); /* { dg-warning "long int" "wrong type" } */
+  printf (ngettext ("%d foo", (nfoo > 0) ? "%ld foos" : "no foos", nfoo), nfoo); /* { dg-warning "long int" "wrong type" } */
+  printf (ngettext ("%d foo", (nfoo > 0) ? "%d foos" : "%ld foos", nfoo), nfoo); /* { dg-warning "long int" "wrong type" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-1.c
@@ -0,0 +1,15 @@
+/* Test for warnings for extra format arguments being disabled by
+   -Wno-format-extra-args.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wno-format-extra-args" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i)
+{
+  printf ("foo", i);
+  printf ("%1$d", i, i);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-2.c
@@ -0,0 +1,28 @@
+/* Test for warnings for extra format arguments being disabled by
+   -Wno-format-extra-args.  Test which warnings still apply with $
+   operand numbers.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wno-format-extra-args" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, int *ip, va_list va)
+{
+  printf ("%3$d%1$d", i, i, i); /* { dg-warning "before used" "unused $ operand" } */
+  printf ("%2$d%1$d", i, i, i);
+  vprintf ("%3$d%1$d", va); /* { dg-warning "before used" "unused $ operand" } */
+  /* With scanf formats, gaps in the used arguments are allowed only if the
+     arguments are all pointers.  In such a case, should only give the lesser
+     warning about unused arguments rather than the more serious one about
+     argument gaps.  */
+  scanf ("%3$d%1$d", ip, ip, ip);
+  /* If there are non-pointer arguments unused at the end, this is also OK.  */
+  scanf ("%3$d%1$d", ip, ip, ip, i);
+  scanf ("%3$d%1$d", ip, i, ip); /* { dg-warning "before used" "unused $ scanf non-pointer operand" } */
+  /* Can't check the arguments in the vscanf case, so should suppose the
+     lesser problem.  */
+  vscanf ("%3$d%1$d", va);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_no-y2k-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_no-y2k-1.c
@@ -0,0 +1,13 @@
+/* Test for warnings for Y2K problems not being on by default.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  strftime (s, m, "%y%c%x", tp);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-1.c
@@ -0,0 +1,14 @@
+/* Test for warnings for non-string-literal formats.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wformat-nonliteral" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t i)
+{
+  printf ((const char *)i, i); /* { dg-warning "argument types" "non-literal" } */
+  printf (s, i); /* { dg-warning "argument types" "non-literal" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-2.c
@@ -0,0 +1,14 @@
+/* Test for warnings for non-string-literal formats.  Test with -Wformat=2.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat=2" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t i)
+{
+  printf ((const char *)i, i); /* { dg-warning "argument types" "non-literal" } */
+  printf (s, i); /* { dg-warning "argument types" "non-literal" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-3.c
@@ -0,0 +1,13 @@
+/* Test for warnings for non-string-literal formats.  Test for strftime formats.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wformat-nonliteral" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp, char *fmt)
+{
+  strftime (s, m, fmt, tp); /* { dg-warning "format string" "non-literal" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nul-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nul-1.c
@@ -0,0 +1,15 @@
+/* Test diagnostics for suppressing contains nul
+   -Wformat.  -Wformat.  */
+/* Origin: Bruce Korb <bkorb@gnu.org> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat -Wno-format-contains-nul" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (void)
+{
+  static char const fmt[] = "x%s\0%s\n\0abc";
+  printf (fmt+4, fmt+8); /* { dg-bogus "embedded.*in format" "bogus embed warning" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nul-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nul-2.c
@@ -0,0 +1,17 @@
+/* Test diagnostics for options used on their own without
+   -Wformat.  -Wformat-.  */
+/* Origin: Bruce Korb <bkorb@gnu.org> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+
+/* { dg-warning "embedded .* in format" "ignored" { target *-*-* } 0 } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+fumble (void)
+{
+  static char const fmt[] = "x%s\0%s\n\0abc";
+  printf (fmt+4, fmt+8);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_null-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_null-1.c
@@ -0,0 +1,28 @@
+/* Test for some aspects of null format string handling.  */
+/* Origin: Jason Thorpe <thorpej@wasabisystems.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+extern void my_printf (const char *, ...) __attribute__((format(ms_printf,1,2)));
+extern const char *my_format (const char *, const char *)
+  __attribute__((format_arg(2)));
+
+void
+foo (int i1)
+{
+  /* Warning about a null format string has been decoupled from the actual
+     format check.  However, we still expect to be warned about any excess
+     arguments after a null format string.  */
+  my_printf (NULL);
+  my_printf (NULL, i1); /* { dg-warning "too many" "null format with arguments" } */
+
+  my_printf (my_format ("", NULL));
+  my_printf (my_format ("", NULL), i1); /* { dg-warning "too many" "null format_arg with arguments" } */
+
+  /* While my_printf allows a null argument, dgettext does not, so we expect
+     a null argument warning here.  */
+  my_printf (dgettext ("", NULL)); /* { dg-warning "null" "null format with dgettext" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_plus-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_plus-1.c
@@ -0,0 +1,21 @@
+/* Test for printf formats using string literal plus constant.
+ */
+/* Origin: Jakub Jelinek <jakub@redhat.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat=2" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i)
+{
+  printf ("%%d\n" + 1, i);
+  printf (5 + "%.-*d%3d\n", i);
+  printf ("%d%d" + 2, i, i);	/* { dg-warning "arguments" "wrong number of args" } */
+  printf (3 + "%d\n");		/* { dg-warning "zero-length" "zero-length string" } */
+  printf ("%d\n" + i, i);	/* { dg-warning "not a string" "non-constant addend" } */
+  printf ("%d\n" + 10);		/* { dg-warning "not a string" "too large addend" } */
+  printf ("%d\n" - 1, i);	/* { dg-warning "not a string" "minus constant" } */
+  printf ("%d\n" + -1, i);	/* { dg-warning "not a string" "negative addend" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_sec-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_sec-1.c
@@ -0,0 +1,13 @@
+/* Test for security warning when non-literal format has no arguments.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wformat-security" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s)
+{
+  printf (s); /* { dg-warning "no format arguments" "security warning" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_unnamed-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_unnamed-1.c
@@ -0,0 +1,24 @@
+/* Test for warnings with possibly unnamed integer types.  Bug 24329.  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+/* { dg-options "-Wformat -msse" { target { { i?86-*-* x86_64-*-* } && ilp32 } } } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* Definition of TItype follows same logic as in gcc.dg/titype-1.c,
+   but must be a #define to avoid giving the type a name.  */
+#if defined(__LP64__) && !defined(__hppa__)
+#define TItype int __attribute__ ((mode (TI)))
+#else
+#define TItype long
+#endif
+
+void
+f (TItype x)
+{
+  printf("%d", x); /* { dg-warning "expects type" } */
+  printf("%d", 141592653589793238462643383279502884197169399375105820974944); /* { dg-warning "expects type" } */
+  /* { dg-warning "unsigned only|too large" "constant" { target *-*-* } 22 } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_va-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_va-1.c
@@ -0,0 +1,14 @@
+/* Test for strange warning in format checking.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (void *p)
+{
+  printf ("%d", p); /* { dg-bogus "va_list" "wrong type in format warning" } */
+  /* { dg-warning "format" "format error" { target *-*-* } 12 } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_warnll-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_warnll-1.c
@@ -0,0 +1,19 @@
+/* Test for printf formats.  C99 "long long" formats should be accepted with
+   -Wno-long-long.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wno-long-long" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (long long ll, unsigned long long ull, long long *lln,
+     long long *llp, unsigned long long *ullp)
+{
+  /* Test for accepting standard "long long" formats.  */
+  printf ("%I64d%I64i%I64o%I64u%I64x%I64X%I64n", ll, ll, ull, ull, ull, ull, lln);
+  scanf ("%I64d%I64i%I64o%I64u%I64x%I64X%I64n", llp, llp,
+	 ullp, ullp, ullp, ullp, lln);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_zero-length-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_zero-length-1.c
@@ -0,0 +1,16 @@
+/* Test the -Wno-format-zero-length option, which suppresses warnings
+   about zero-length formats.  */
+/* Origin: Jason Thorpe <thorpej@wasabisystems.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wno-format-zero-length" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (void)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.1 (pages 131-134).  */
+  /* Zero-length format strings are allowed.  */
+  printf ("");
+}
Index: gcc/gcc/testsuite/gcc.dg/format/multattr-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/multattr-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/multattr-1.c
@@ -4,6 +4,7 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 /* If we specify multiple attributes for a single function, they should
@@ -11,22 +12,22 @@
    or on different declarations.  */
 
 extern void my_vprintf_scanf (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__printf__, 1, 0)))
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)))
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
 extern void my_vprintf_scanf2 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)))
-     __attribute__((__format__(__printf__, 1, 0)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)))
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)));
 
 extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__printf__, 1, 0)));
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)));
 extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
 extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__printf__, 1, 0)));
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)));
 
 void
 foo (va_list ap, int *ip, long *lp)
Index: gcc/gcc/testsuite/gcc.dg/format/multattr-2.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/multattr-2.c
+++ gcc/gcc/testsuite/gcc.dg/format/multattr-2.c
@@ -4,21 +4,22 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 /* If we specify multiple attributes for a single function, they should
    all apply, wherever they are placed on the declarations.  */
 
-extern __attribute__((__format__(__printf__, 1, 0))) void
+extern __attribute__((__format__(gnu_attr___printf__, 1, 0))) void
      my_vprintf_scanf (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
-extern void (__attribute__((__format__(__printf__, 1, 0))) my_vprintf_scanf2)
+extern void (__attribute__((__format__(gnu_attr___printf__, 1, 0))) my_vprintf_scanf2)
      (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
-extern __attribute__((__format__(__scanf__, 3, 4))) void
-     (__attribute__((__format__(__printf__, 1, 0))) my_vprintf_scanf3)
+extern __attribute__((__format__(gnu_attr___scanf__, 3, 4))) void
+     (__attribute__((__format__(gnu_attr___printf__, 1, 0))) my_vprintf_scanf3)
      (const char *, va_list, const char *, ...);
 
 void
Index: gcc/gcc/testsuite/gcc.dg/format/null-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/null-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/null-1.c
@@ -3,9 +3,10 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern void my_printf (const char *, ...) __attribute__((format(printf,1,2)));
+extern void my_printf (const char *, ...) __attribute__((format(gnu_attr_printf,1,2)));
 extern const char *my_format (const char *, const char *)
   __attribute__((format_arg(2)));
 
=

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf      formatters to c-format.c
  2008-01-08 18:18                         ` Joseph S. Myers
@ 2008-01-15 16:45                           ` Kai Tietz
  0 siblings, 0 replies; 61+ messages in thread
From: Kai Tietz @ 2008-01-15 16:45 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: Danny Smith, GCC Patches, NightStrike

[-- Attachment #1: Type: text/plain, Size: 6743 bytes --]

Hi Joseph,

"Joseph S. Myers" wrote on 08.01.2008 17:51:58:

> On Tue, 8 Jan 2008, Kai Tietz wrote:
> 
> >         * gcc/testsuite/gcc.dg/format/format.h: Add for mingw the gnu 
> > style printf prototypes.
> > 
> > Do you think it is ok for apply ?
> 
> The general approach is plausible, but the patch still needs full test 
> coverage for the MinGW formats before it's ready for review.  Every C90, 

> C99, X/Open or GNU format feature not present on Windows should have a 
> MinGW-specific test assertion added to the testsuite that the use of 
that 
> feature is diagnosed, which every such feature present on Windows should 

> have a MinGW-specific test assertion added that the feature is not 
> diagnosed.  (The effect should be that every entry in the MinGW format 
> datastructures is tested, and every difference from the GNU format 
> datastructures.)  When you have a patch ready with such tests, please 
> confirm that all the format tests pass cleanly with it applied for both 
> MinGW and non-MinGW targets; then it will be ready for review.

This patch includes the testcases for format for gnu and mingw style.

ChangeLog for gcc/testcase

2008-01-15  Kai Tietz  <kai.tietz@onevision.com>

        * gcc.dg/format/ms_array-1.c: New.
        * gcc.dg/format/ms_c90-scanf-3.c: New.
        * gcc.dg/format/ms_c99-strftime-1.c: New.
        * gcc.dg/format/ms_no-y2k-1.c: New.
        * gcc.dg/format/ms_attr-1.c: New.
        * gcc.dg/format/ms_c90-scanf-4.c: New.
        * gcc.dg/format/ms_c99-strftime-2.c: New.
        * gcc.dg/format/ms_nonlit-1.c: New.
        * gcc.dg/format/ms_c90-scanf-5.c: New.
        * gcc.dg/format/ms_cast-1.c: New.
        * gcc.dg/format/ms_nonlit-2.c: New.
        * gcc.dg/format/ms_attr-2.c: New.
        * gcc.dg/format/ms_c90-strftime-1.c: New.
        * gcc.dg/format/ms_miss-1.c: New.
        * gcc.dg/format/ms_nonlit-3.c: New.
        * gcc.dg/format/ms_attr-3.c: New.
        * gcc.dg/format/ms_c90-strftime-2.c: New.
        * gcc.dg/format/ms_miss-2.c: New.
        * gcc.dg/format/ms_nul-1.c: New.
        * gcc.dg/format/ms_attr-4.c: New.
        * gcc.dg/format/ms_c94-printf-1.c: New.
        * gcc.dg/format/ms_miss-3.c: New.
        * gcc.dg/format/ms_nul-2.c: New.
        * gcc.dg/format/ms_attr-7.c: New.
        * gcc.dg/format/ms_c94-scanf-1.c: New.
        * gcc.dg/format/ms_miss-4.c: New.
        * gcc.dg/format/ms_null-1.c: New.
        * gcc.dg/format/ms_bitfld-1.c: New.
        * gcc.dg/format/ms_c99-printf-1.c: New.
        * gcc.dg/format/ms_miss-5.c: New.
        * gcc.dg/format/ms_plus-1.c: New.
        * gcc.dg/format/ms_branch-1.c: New.
        * gcc.dg/format/ms_c99-printf-2.c: New.
        * gcc.dg/format/ms_miss-6.c: New.
        * gcc.dg/format/ms_sec-1.c: New.
        * gcc.dg/format/ms_c90-printf-1.c: New.
        * gcc.dg/format/ms_c99-printf-3.c: New.
        * gcc.dg/format/ms_multattr-1.c: New.
        * gcc.dg/format/ms_unnamed-1.c: New.
        * gcc.dg/format/ms_c90-printf-2.c: New.
        * gcc.dg/format/ms_c99-scanf-1.c: New.
        * gcc.dg/format/ms_multattr-2.c: New.
        * gcc.dg/format/ms_va-1.c: New.
        * gcc.dg/format/ms_c90-printf-3.c: New.
        * gcc.dg/format/ms_c99-scanf-2.c: New.
        * gcc.dg/format/ms_multattr-3.c: New.
        * gcc.dg/format/ms_warnll-1.c: New.
        * gcc.dg/format/ms_c90-scanf-1.c: New.
        * gcc.dg/format/ms_c99-scanf-3.c: New.
        * gcc.dg/format/ms_no-exargs-1.c: New.
        * gcc.dg/format/ms_zero-length-1.c: New.
        * gcc.dg/format/ms_c90-scanf-2.c: New.
        * gcc.dg/format/ms_c99-scanf-4.c: New.
        * gcc.dg/format/ms_no-exargs-2.c: New.
        * gcc.dg/format/sys_formatter.c: New.
        * gcc.dg/format/null-1.c: Add gnu style usage for mingw.
        * gcc.dg/format/miss-1.c: Likewise.
        * gcc.dg/format/miss-3.c: Likewise.
        * gcc.dg/format/multattr-2.c: Likewise.
        * gcc.dg/format/miss-5.c: Likewise.
        * gcc.dg/format/attr-2.c: Likewise.
        * gcc.dg/format/attr-4.c: Likewise.
        * gcc.dg/format/c90-scanf-4.c: Likewise.
        * gcc.dg/format/c99-printf-3.c: Likewise.
        * gcc.dg/format/multattr-1.c: Likewise.
        * gcc.dg/format/miss-4.c: Likewise.
        * gcc.dg/format/miss-6.c: Likewise.
        * gcc.dg/format/c90-printf-3.c: Likewise.
        * gcc.dg/format/attr-1.c: Likewise.
        * gcc.dg/format/attr-3.c: Likewise.
        * gcc.dg/format/attr-7.c: Likewise.
        * gcc.dg/format/format.h: Treat mingw and gnu style.

ChangeLog of gcc/:
2008-01-15      Kai Tietz  <kai.tietz@onevision.com>

        * c-format.c: (replace_formatter_name_to_system_name): New.
        (compare_tofa): New.
        (compare_format_types): New.
        (decode_format_attr): Use of 
replace_formatter_name_to_system_name.
        (format_types_orig): Add gnu_ prefix to names.
        (check_format_info_main): Special treating of \0 escaped names for
        supporting multi-character formatters as I32, I64.
        (TARGET_OVERRIDES_FORMAT_ATTRIBUTES): Use of user defined 
attributes.
        (gnu_target_overrides_format_attributes): New.
        * gcc/c-format.h: Add structure target_ovr_attr to hold
        system specific formatter names.
        (ovr_format_type): New enum.
        * gcc/config.gcc: Add for x86&x86_64 cygwin and mingw32 targets 
the
        msformat-c.o file to c_target_objs and cxx_target_objs.
        * gcc/config/i386/mingw32.h: (TARGET_OVERRIDES_FORMAT_ATTRIBUTES): 
New.
        (TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT): New.
        (TARGET_N_FORMAT_TYPES): New.
        * gcc/config/i386/msformat-c.c: New.
        * gcc/config/i386/t-cygming: Add build rule for msformat-c.o.
        * gcc/doc/extend.texi: Add new format names gnu_* and ms_*.
        * gcc/doc/tm.texi: (TARGET_OVERRIDES_FORMAT_ATTRIBUTES): New.

Is this ok for review ?

Cheers,
 i.A. Kai Tietz



|  (\_/)  This is Bunny. Copy and paste Bunny
| (='.'=) into your signature to help him gain
| (")_(") world domination.

------------------------------------------------------------------------------------------
  OneVision Software Entwicklungs GmbH & Co. KG
  Dr.-Leo-Ritter-Straße 9 - 93049 Regensburg
  Tel: +49.(0)941.78004.0 - Fax: +49.(0)941.78004.489 - www.OneVision.com
  Commerzbank Regensburg - BLZ 750 400 62 - Konto 6011050
  Handelsregister: HRA 6744, Amtsgericht Regensburg
  Komplementärin: OneVision Software Entwicklungs Verwaltungs GmbH
  Dr.-Leo-Ritter-Straße 9 – 93049 Regensburg
  Handelsregister: HRB 8932, Amtsgericht Regensburg - Geschäftsführer: 
Ulrike Döhler, Manuela Kluger


[-- Attachment #2: mingw-msformat.txt --]
[-- Type: text/plain, Size: 161140 bytes --]

Index: gcc/gcc/c-format.c
===================================================================
--- gcc.orig/gcc/c-format.c
+++ gcc/gcc/c-format.c
@@ -74,13 +74,15 @@ typedef struct function_format_info
 
 static bool decode_format_attr (tree, function_format_info *, int);
 static int decode_format_type (const char *);
+static int compare_format_types (int ctype, int def_type);
 
 static bool check_format_string (tree argument,
 				 unsigned HOST_WIDE_INT format_num,
 				 int flags, bool *no_add_attrs);
 static bool get_constant (tree expr, unsigned HOST_WIDE_INT *value,
 			  int validated_p);
-
+static const char *replace_formatter_name_to_system_name (const char *attr_name);
+static int compare_tofa (const char *tattr_name, const char *attr_name);
 
 /* Handle a "format_arg" attribute; arguments as in
    struct attribute_spec.handler.  */
@@ -191,6 +193,8 @@ decode_format_attr (tree args, function_
     {
       const char *p = IDENTIFIER_POINTER (format_type_id);
 
+      p = replace_formatter_name_to_system_name (p);
+
       info->format_type = decode_format_type (p);
 
       if (info->format_type == format_type_error)
@@ -715,7 +719,7 @@ static const format_char_info monetary_c
 /* This must be in the same order as enum format_type.  */
 static const format_kind_info format_types_orig[] =
 {
-  { "printf",   printf_length_specs,  print_char_table, " +#0-'I", NULL,
+  { "gnu_printf",   printf_length_specs,  print_char_table, " +#0-'I", NULL,
     printf_flag_specs, printf_flag_pairs,
     FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
     'w', 0, 'p', 0, 'L', 0,
@@ -757,18 +761,18 @@ static const format_kind_info format_typ
     0, 0, 0, 0, 0, 0,
     NULL, NULL
   },
-  { "scanf",    scanf_length_specs,   scan_char_table,  "*'I", NULL,
+  { "gnu_scanf",    scanf_length_specs,   scan_char_table,  "*'I", NULL,
     scanf_flag_specs, scanf_flag_pairs,
     FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
     'w', 0, 0, '*', 'L', 'm',
     NULL, NULL
   },
-  { "strftime", NULL,                 time_char_table,  "_-0^#", "EO",
+  { "gnu_strftime", NULL,                 time_char_table,  "_-0^#", "EO",
     strftime_flag_specs, strftime_flag_pairs,
     FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0, 0,
     NULL, NULL
   },
-  { "strfmon",  strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
+  { "gnu_strfmon",  strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
     strfmon_flag_specs, strfmon_flag_pairs,
     FMT_FLAG_ARG_CONVERT, 'w', '#', 'p', 0, 'L', 0,
     NULL, NULL
@@ -847,6 +851,8 @@ decode_format_type (const char *s)
 {
   int i;
   int slen;
+
+  s = replace_formatter_name_to_system_name (s);
   slen = strlen (s);
   for (i = 0; i < n_format_types; i++)
     {
@@ -1776,7 +1782,22 @@ check_format_info_main (format_check_res
       if (fli)
 	{
 	  while (fli->name != 0 && fli->name[0] != *format_chars)
-	    fli++;
+	    {
+	      if (fli->name[0] == '\0')
+		{
+		  int si  = strlen (fli->name + 1) + 1;
+		  int i = 1;
+		  while (fli->name[i] != 0 && fli->name[i] == format_chars [i - 1])
+		    ++i;
+		 if (si == i)
+		   {
+		     if (si > 2)
+		       format_chars += si - 2;
+		     break;
+		   }
+	       }
+	      fli++;
+	    }
 	  if (fli->name != 0)
 	    {
 	      format_chars++;
@@ -2703,6 +2724,72 @@ init_dynamic_diag_info (void)
 extern const format_kind_info TARGET_FORMAT_TYPES[];
 #endif
 
+#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+extern const target_ovr_attr TARGET_OVERRIDES_FORMAT_ATTRIBUTES[];
+#endif
+
+/* Description of gnu specific format attributes reflected to
+   system format attribute types, as printf, scanf, strftime, and
+   strfmon.  */
+const target_ovr_attr gnu_target_overrides_format_attributes[] =
+{
+  { "gnu_printf",   "printf", ovr_printf_format_type },
+  { "gnu_scanf",    "scanf", ovr_scanf_format_type },
+  { "gnu_strftime", "strftime", ovr_strftime_format_type },
+  { "gnu_strfmon",  "strfmon", ovr_strfmon_format_type },
+  { NULL,           NULL, -1 }
+};
+
+static const char *
+replace_formatter_name_to_system_name (const char *attr_name)
+{
+  int i;
+
+  if (attr_name == NULL || *attr_name == 0 || strncmp (attr_name, "gcc_", 4) == 0)
+    return attr_name;
+
+#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+  /* Check if format attribute is overridden by target.  */
+  if (TARGET_OVERRIDES_FORMAT_ATTRIBUTES != NULL && TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT > 0)
+    {
+      for (i = 0; i < TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT; ++i)
+        {
+          if (compare_tofa (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src, attr_name))
+            return attr_name;
+          if (compare_tofa (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_dst, attr_name))
+            return TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src;
+        }
+    }
+#endif
+  /* Otherwise default to gnu formatter.  */
+  for (i = 0; gnu_target_overrides_format_attributes[i].named_attr_src != NULL; ++i)
+    {
+      if (compare_tofa (gnu_target_overrides_format_attributes[i].named_attr_src, attr_name))
+        return attr_name;
+      if (compare_tofa (gnu_target_overrides_format_attributes[i].named_attr_dst, attr_name))
+        return gnu_target_overrides_format_attributes[i].named_attr_src;
+    }
+
+  return attr_name;
+}
+
+/* Compare the target override format attribute by treating double underscore syntax.  */
+static int
+compare_tofa (const char *tattr_name, const char *attr_name)
+{
+  int alen = strlen (attr_name);
+  int slen = (tattr_name ? strlen (tattr_name) : 0);
+  if (alen > 4 && attr_name[0] == '_' && attr_name[1] == '_'
+      && attr_name[alen - 1] == '_' && attr_name[alen - 2] == '_')
+    {
+      attr_name += 2;
+      alen -= 4;
+    }
+  if (alen != slen || strncmp (tattr_name, attr_name, alen) != 0)
+    return 0;
+  return 1;
+}
+
 /* Handle a "format" attribute; arguments as in
    struct attribute_spec.handler.  */
 tree
@@ -2762,7 +2849,7 @@ handle_format_attribute (tree *node, tre
 	}
     }
 
-  if (info.format_type == strftime_format_type && info.first_arg_num != 0)
+  if (compare_format_types (info.format_type, strftime_format_type) && info.first_arg_num != 0)
     {
       error ("strftime formats cannot format arguments");
       *no_add_attrs = true;
@@ -2771,12 +2858,12 @@ handle_format_attribute (tree *node, tre
 
   /* If this is a custom GCC-internal format type, we have to
      initialize certain bits a runtime.  */
-  if (info.format_type == asm_fprintf_format_type
-      || info.format_type == gcc_gfc_format_type
-      || info.format_type == gcc_diag_format_type
-      || info.format_type == gcc_tdiag_format_type
-      || info.format_type == gcc_cdiag_format_type
-      || info.format_type == gcc_cxxdiag_format_type)
+  if (compare_format_types (info.format_type, asm_fprintf_format_type)
+      || compare_format_types (info.format_type, gcc_gfc_format_type)
+      || compare_format_types (info.format_type, gcc_diag_format_type)
+      || compare_format_types (info.format_type, gcc_tdiag_format_type)
+      || compare_format_types (info.format_type, gcc_cdiag_format_type)
+      || compare_format_types (info.format_type, gcc_cxxdiag_format_type))
     {
       /* Our first time through, we have to make sure that our
 	 format_type data is allocated dynamically and is modifiable.  */
@@ -2787,18 +2874,18 @@ handle_format_attribute (tree *node, tre
 
       /* If this is format __asm_fprintf__, we have to initialize
 	 GCC's notion of HOST_WIDE_INT for checking %wd.  */
-      if (info.format_type == asm_fprintf_format_type)
+      if (compare_format_types (info.format_type, asm_fprintf_format_type))
 	init_dynamic_asm_fprintf_info ();
       /* If this is format __gcc_gfc__, we have to initialize GCC's
 	 notion of 'locus' at runtime for %L.  */
-      else if (info.format_type == gcc_gfc_format_type)
+      else if (compare_format_types (info.format_type, gcc_gfc_format_type))
 	init_dynamic_gfc_info ();
       /* If this is one of the diagnostic attributes, then we have to
 	 initialize 'location_t' and 'tree' at runtime.  */
-      else if (info.format_type == gcc_diag_format_type
-	       || info.format_type == gcc_tdiag_format_type
-	       || info.format_type == gcc_cdiag_format_type
-	       || info.format_type == gcc_cxxdiag_format_type)
+      else if (compare_format_types (info.format_type, gcc_diag_format_type)
+	       || compare_format_types (info.format_type, gcc_tdiag_format_type)
+	       || compare_format_types (info.format_type, gcc_cdiag_format_type)
+	       || compare_format_types (info.format_type, gcc_cxxdiag_format_type))
 	init_dynamic_diag_info ();
       else
 	gcc_unreachable ();
@@ -2806,3 +2893,36 @@ handle_format_attribute (tree *node, tre
 
   return NULL_TREE;
 }
+
+/* For custom types we need to compare in a special way.  */
+static int compare_format_types (int custom_type, int def_type)
+{
+  int i;
+  int n_format_types_org = ARRAY_SIZE (format_types_orig);
+  const char *name_custom = NULL;
+  if (custom_type < n_format_types_org)
+    return custom_type == def_type;
+#ifdef TARGET_FORMAT_TYPES
+  if (TARGET_N_FORMAT_TYPES <= 0
+      || ((custom_type - n_format_types_org) >= TARGET_N_FORMAT_TYPES))
+    return custom_type == def_type;
+
+  name_custom = TARGET_FORMAT_TYPES[custom_type - n_format_types_org].name;
+
+#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+  /* Check if format attribute is overridden by target.  */
+  if (TARGET_OVERRIDES_FORMAT_ATTRIBUTES != NULL && TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT > 0)
+    {
+      for (i = 0; i < TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT; ++i)
+        {
+          if (compare_tofa (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src, name_custom))
+            {
+	      custom_type = TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_type; break;
+	    }
+        }
+    }
+#endif
+
+#endif
+  return custom_type == def_type;
+}
Index: gcc/gcc/c-format.h
===================================================================
--- gcc.orig/gcc/c-format.h
+++ gcc/gcc/c-format.h
@@ -306,4 +306,28 @@ typedef struct
 #define T_D128  &dfloat128_type_node
 #define TEX_D128 { STD_EXT, "_Decimal128", T_D128 }
 
+/* Structure describing the target specific to be override formatter
+   attributes, e.g. printf, scanf, etc.  This allows to support different
+   runtime-library specific formatter attributes to co-exist and defining
+   a default system version.
+   This type is used for the pointer variable TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+   refers to.  */
+typedef struct
+{
+  /* The name of the to be copied formatter attribute. */
+  const char *named_attr_src;
+  /* The name of the to be overridden formatter attribute. */
+  const char *named_attr_dst;
+  /* Values of enum ovr_format_type.  */
+  int named_attr_type;
+} target_ovr_attr;
+
+/* Be aware to keep these values in synch with enum format_type from c-format.c.  */
+enum ovr_format_type { ovr_printf_format_type, ovr_asm_fprintf_format_type,
+		   ovr_gcc_diag_format_type, ovr_gcc_tdiag_format_type,
+		   ovr_gcc_cdiag_format_type,
+		   ovr_gcc_cxxdiag_format_type, ovr_gcc_gfc_format_type,
+		   ovr_scanf_format_type, ovr_strftime_format_type,
+		   ovr_strfmon_format_type, ovr_format_type_error = -1};
+
 #endif /* GCC_C_FORMAT_H */
Index: gcc/gcc/config.gcc
===================================================================
--- gcc.orig/gcc/config.gcc
+++ gcc/gcc/config.gcc
@@ -1359,8 +1359,8 @@ i[34567]86-*-pe | i[34567]86-*-cygwin*)
 	target_gtfiles="\$(srcdir)/config/i386/winnt.c"
 	extra_options="${extra_options} i386/cygming.opt"
 	extra_objs="winnt.o winnt-stubs.o"
-	c_target_objs=cygwin2.o
-	cxx_target_objs="cygwin2.o winnt-cxx.o"
+	c_target_objs="cygwin2.o msformat-c.o"
+	cxx_target_objs="cygwin2.o winnt-cxx.o msformat-c.o"
 	extra_gcc_objs=cygwin1.o
 	if test x$enable_threads = xyes; then
 		thread_file='posix'
@@ -1373,7 +1373,8 @@ i[34567]86-*-mingw32* | x86_64-*-mingw32
 	target_gtfiles="\$(srcdir)/config/i386/winnt.c"
 	extra_options="${extra_options} i386/cygming.opt"
 	extra_objs="winnt.o winnt-stubs.o"
-	cxx_target_objs=winnt-cxx.o
+	c_target_objs="msformat-c.o"
+	cxx_target_objs="winnt-cxx.o msformat-c.o"
 	default_use_cxa_atexit=yes
 	case ${enable_threads} in
 	  "" | yes | win32)
Index: gcc/gcc/config/i386/mingw32.h
===================================================================
--- gcc.orig/gcc/config/i386/mingw32.h
+++ gcc/gcc/config/i386/mingw32.h
@@ -143,6 +143,22 @@ do {						         \
    to register C++ static destructors.  */
 #define TARGET_CXX_USE_ATEXIT_FOR_CXA_ATEXIT hook_bool_void_true
 
+/* Contains a pointer to type target_ovr_attr defining the target specific
+   overrides of formatter attributs.  See format.h for structure definition.  */
+#undef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+#define TARGET_OVERRIDES_FORMAT_ATTRIBUTES mingw_formatter_attribute_overrides
+
+/* Specify the count of elements in TARGET_OVERRIDES_ATTRIBUTE.  */
+#undef TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT
+#define TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT 3
+
+/* MS specific format attributes for ms_printf, ms_scanf, ms_strftime.  */
+#undef TARGET_FORMAT_TYPES
+#define TARGET_FORMAT_TYPES mingw_formatter_attributes
+
+#undef TARGET_N_FORMAT_TYPES
+#define TARGET_N_FORMAT_TYPES 3
+
 /* JCR_SECTION works on mingw32.  */
 #undef TARGET_USE_JCR_SECTION
 #define TARGET_USE_JCR_SECTION 1
Index: gcc/gcc/config/i386/msformat-c.c
===================================================================
--- /dev/null
+++ gcc/gcc/config/i386/msformat-c.c
@@ -0,0 +1,188 @@
+/* Check calls to formatted I/O functions (-Wformat).
+   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+   2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "flags.h"
+#include "c-common.h"
+#include "toplev.h"
+#include "intl.h"
+#include "diagnostic.h"
+#include "langhooks.h"
+#include "c-format.h"
+#include "alloc-pool.h"
+
+/* Mingw specific format attributes ms_printf, ms_scanf, and ms_strftime.  */
+
+static const format_length_info ms_printf_length_specs[] =
+{
+  { "h", FMT_LEN_h, STD_C89, NULL, 0, 0 },
+  { "l", FMT_LEN_l, STD_C89, NULL, 0, 0 },
+  { "\0I32", FMT_LEN_l, STD_C89, NULL, 0, 0 },
+  { "\0I64", FMT_LEN_ll, STD_C9L, NULL, 0, 0 },
+  { "I", FMT_LEN_L, STD_C89, NULL, 0, 0 },
+  { NULL, 0, 0, NULL, 0, 0 }
+};
+
+static const format_flag_spec ms_printf_flag_specs[] =
+{
+  { ' ',  0, 0, N_("' ' flag"),        N_("the ' ' printf flag"),              STD_C89 },
+  { '+',  0, 0, N_("'+' flag"),        N_("the '+' printf flag"),              STD_C89 },
+  { '#',  0, 0, N_("'#' flag"),        N_("the '#' printf flag"),              STD_C89 },
+  { '0',  0, 0, N_("'0' flag"),        N_("the '0' printf flag"),              STD_C89 },
+  { '-',  0, 0, N_("'-' flag"),        N_("the '-' printf flag"),              STD_C89 },
+  { '\'', 0, 0, N_("''' flag"),        N_("the ''' printf flag"),              STD_EXT },
+  { 'w',  0, 0, N_("field width"),     N_("field width in printf format"),     STD_C89 },
+  { '.',  0, 0, N_("precision"),       N_("precision in printf format"),       STD_C89 },
+  { 'L',  0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_printf_flag_pairs[] =
+{
+  { ' ', '+', 1, 0   },
+  { '0', '-', 1, 0   },
+  { 0, 0, 0, 0 }
+};
+
+static const format_flag_spec ms_scanf_flag_specs[] =
+{
+  { '*',  0, 0, N_("assignment suppression"), N_("the assignment suppression scanf feature"), STD_C89 },
+  { 'a',  0, 0, N_("'a' flag"),               N_("the 'a' scanf flag"),                       STD_EXT },
+  { 'w',  0, 0, N_("field width"),            N_("field width in scanf format"),              STD_C89 },
+  { 'L',  0, 0, N_("length modifier"),        N_("length modifier in scanf format"),          STD_C89 },
+  { '\'', 0, 0, N_("''' flag"),               N_("the ''' scanf flag"),                       STD_EXT },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_scanf_flag_pairs[] =
+{
+  { '*', 'L', 0, 0 },
+  { 0, 0, 0, 0 }
+};
+
+static const format_flag_spec ms_strftime_flag_specs[] =
+{
+  { '_', 0,   0, N_("'_' flag"),     N_("the '_' strftime flag"),          STD_EXT },
+  { '-', 0,   0, N_("'-' flag"),     N_("the '-' strftime flag"),          STD_EXT },
+  { '0', 0,   0, N_("'0' flag"),     N_("the '0' strftime flag"),          STD_EXT },
+  { '^', 0,   0, N_("'^' flag"),     N_("the '^' strftime flag"),          STD_EXT },
+  { '#', 0,   0, N_("'#' flag"),     N_("the '#' strftime flag"),          STD_EXT },
+  { 'w', 0,   0, N_("field width"),  N_("field width in strftime format"), STD_EXT },
+  { 'E', 0,   0, N_("'E' modifier"), N_("the 'E' strftime modifier"),      STD_C99 },
+  { 'O', 0,   0, N_("'O' modifier"), N_("the 'O' strftime modifier"),      STD_C99 },
+  { 'O', 'o', 0, NULL,               N_("the 'O' modifier"),               STD_EXT },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_strftime_flag_pairs[] =
+{
+  { 'E', 'O', 0, 0 },
+  { '_', '-', 0, 0 },
+  { '_', '0', 0, 0 },
+  { '-', '0', 0, 0 },
+  { '^', '#', 0, 0 },
+  { 0, 0, 0, 0 }
+};
+
+static const format_char_info ms_print_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "di",  0, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  T99_SST,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-wp0 +'",  "i",  NULL },
+  { "oxX", 0, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN, BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "-wp0#",     "i",  NULL },
+  { "u",   0, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN, BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "-wp0'",    "i",  NULL },
+  { "fgG", 0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "-wp0 +#'", "",   NULL },
+  { "eE",  0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "-wp0 +#",  "",   NULL },
+  { "c",   0, STD_C89, { T89_I,   BADLEN,  T89_S,  T94_WI,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "",   NULL },
+  { "s",   1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-wp",       "cR", NULL },
+  { "p",   1, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "c",  NULL },
+  { "n",   1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  BADLEN,  BADLEN, BADLEN,  T99_IM,  BADLEN,  BADLEN,  BADLEN }, "",          "W",  NULL },
+  /* X/Open conversion specifiers.  */
+  { "C",   0, STD_EXT, { TEX_WI,  BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "",   NULL },
+  { "S",   1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-wp",       "R",  NULL },
+  { NULL,  0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+static const format_char_info ms_scan_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "di",    1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  T99_SST,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w'", "W",   NULL },
+  { "u",     1, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN,  BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "*w'", "W",   NULL },
+  { "oxX",   1, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T99_ST, BADLEN,  BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "efgEG", 1, STD_C89, { T89_F,   BADLEN,  BADLEN,  T89_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "*w'",  "W",   NULL },
+  { "c",     1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "cW",  NULL },
+  { "s",     1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "cW",  NULL },
+  { "[",     1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "cW[", NULL },
+  { "p",     2, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "n",     1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  BADLEN,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "",     "W",   NULL },
+  /* X/Open conversion specifiers.  */
+  { "C",     1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "S",     1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "W",   NULL },
+  { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+static const format_char_info ms_time_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "ABZab",		0, STD_C89, NOLENGTHS, "^#",     "",   NULL },
+  { "cx",		0, STD_C89, NOLENGTHS, "E",      "3",  NULL },
+  { "HIMSUWdmw",	0, STD_C89, NOLENGTHS, "-_0Ow",  "",   NULL },
+  { "j",		0, STD_C89, NOLENGTHS, "-_0Ow",  "o",  NULL },
+  { "p",		0, STD_C89, NOLENGTHS, "#",      "",   NULL },
+  { "X",		0, STD_C89, NOLENGTHS, "E",      "",   NULL },
+  { "y",		0, STD_C89, NOLENGTHS, "EO-_0w", "4",  NULL },
+  { "Y",		0, STD_C89, NOLENGTHS, "-_0EOw", "o",  NULL },
+  { "%",		0, STD_C89, NOLENGTHS, "",       "",   NULL },
+  /* C99 conversion specifiers.  */
+  { "z",		0, STD_C99, NOLENGTHS, "O",      "o",  NULL },
+  { NULL,		0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+const format_kind_info mingw_formatter_attributes[3] =
+{
+  { "ms_printf",   ms_printf_length_specs,  ms_print_char_table, " +#0-'", NULL,
+    ms_printf_flag_specs, ms_printf_flag_pairs,
+    FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
+    'w', 0, 0, 0, 'L', 0,
+    &integer_type_node, &integer_type_node
+  },
+  { "ms_scanf",    ms_printf_length_specs,   ms_scan_char_table,  "*'", NULL,
+    ms_scanf_flag_specs, ms_scanf_flag_pairs,
+    FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
+    'w', 0, 0, '*', 'L', 0,
+    NULL, NULL
+  },
+  { "ms_strftime", NULL,                 ms_time_char_table,  "_-0^#", "EO",
+    ms_strftime_flag_specs, ms_strftime_flag_pairs,
+    FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0, 0,
+    NULL, NULL
+  }
+};
+
+/* Default overrides for printf, scanf and strftime.  */
+const target_ovr_attr mingw_formatter_attribute_overrides[4] =
+{
+  { "ms_printf", "printf", ovr_printf_format_type },
+  { "ms_scanf", "scanf", ovr_scanf_format_type },
+  { "ms_strftime", "strftime", ovr_strftime_format_type }
+};
Index: gcc/gcc/config/i386/t-cygming
===================================================================
--- gcc.orig/gcc/config/i386/t-cygming
+++ gcc/gcc/config/i386/t-cygming
@@ -29,4 +29,10 @@ winnt-stubs.o: $(srcdir)/config/i386/win
 	$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
 	$(srcdir)/config/i386/winnt-stubs.c
 
+msformat-c.o: $(srcdir)/config/i386/msformat-c.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
+  $(TM_H) $(RTL_H) $(REGS_H) hard-reg-set.h output.h $(TREE_H) flags.h \
+  $(TM_P_H) toplev.h $(HASHTAB_H) $(GGC_H)
+	$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
+	$(srcdir)/config/i386/msformat-c.c
+
 STMP_FIXINC=stmp-fixinc
Index: gcc/gcc/doc/extend.texi
===================================================================
--- gcc.orig/gcc/doc/extend.texi
+++ gcc/gcc/doc/extend.texi
@@ -2204,13 +2204,17 @@ for consistency with the @code{printf} s
 @code{my_format}.
 
 The parameter @var{archetype} determines how the format string is
-interpreted, and should be @code{printf}, @code{scanf}, @code{strftime}
-or @code{strfmon}.  (You can also use @code{__printf__},
-@code{__scanf__}, @code{__strftime__} or @code{__strfmon__}.)  The
-parameter @var{string-index} specifies which argument is the format
-string argument (starting from 1), while @var{first-to-check} is the
-number of the first argument to check against the format string.  For
-functions where the arguments are not available to be checked (such as
+interpreted, and should be @code{printf}, @code{scanf}, @code{strftime},
+@code{gnu_printf}, @code{gnu_scanf}, @code{gnu_strftime} or
+@code{strfmon}.  (You can also use @code{__printf__},
+@code{__scanf__}, @code{__strftime__} or @code{__strfmon__}.)  On
+mingw targets there is also @code{ms_printf}, @code{ms_scanf}, and
+@code{ms_strftime} present. The none target specific formatters are
+always the variant of the system.  The parameter @var{string-index}
+specifies which argument is the format string argument (starting
+from 1), while @var{first-to-check} is the number of the first
+argument to check against the format string.  For functions
+where the arguments are not available to be checked (such as
 @code{vprintf}), specify the third parameter as zero.  In this case the
 compiler only checks the format string for consistency.  For
 @code{strftime} formats, the third parameter is required to be zero.
Index: gcc/gcc/doc/tm.texi
===================================================================
--- gcc.orig/gcc/doc/tm.texi
+++ gcc/gcc/doc/tm.texi
@@ -10311,6 +10311,18 @@ If defined, this macro is the number of 
 @code{TARGET_FORMAT_TYPES}.
 @end defmac
 
+@defmac TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+If defined, this macro is the name of a global variable containg
+target-specific format overrides for the @option{-Wformat} option. The
+default is to have no target-specific format overrides. This depends, that
+@code{TARGET_FORMAT_TYPES} is defined too.
+@end defmac
+
+@defmac TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT
+If defined, this macro is the number of entries in
+@code{}.
+@end defmac
+
 @deftypefn {Target Hook} bool TARGET_RELAXED_ORDERING
 If set to @code{true}, means that the target's memory model does not
 guarantee that loads which do not depend on one another will access
Index: gcc/gcc/testsuite/gcc.dg/format/sys_formatter.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/sys_formatter.c
@@ -0,0 +1,14 @@
+/* Test system default printf formatter specifiers.  */
+/* Origin: Kai Tietz <KaiTietz.@onevision.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu89" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+__attribute__((format(printf, 1, 2))) void foo (const char *, ...);
+
+void bar (long long v1, long v2, int v3)
+{
+  foo ("%I64d %I32d %ld %d\n", v1, v2, v2, v3);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/format.h
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/format.h
+++ gcc/gcc/testsuite/gcc.dg/format/format.h
@@ -1,6 +1,37 @@
 /* Format checking tests: common header.  */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
 
+/* DONT_GNU_PROTOTYPE */
+#if defined (_WIN32) && !defined (__CYGWIN__)
+#if !defined (USE_SYSTEM_FORMATS)
+#define gnu_attr_printf	gnu_printf
+#define gnu_attr___printf__ __gnu_printf__
+#define gnu_attr_scanf	gnu_scanf
+#define gnu_attr___scanf__ __gnu_scanf__
+#define gnu_attr_strftime gnu_strftime
+#define gnu_attr___strftime__ __gnu_strftime__
+#endif
+#endif
+
+#ifndef gnu_attr_printf
+#define gnu_attr_printf	printf
+#define gnu_attr___printf__ __printf__
+#define gnu_attr_scanf	scanf
+#define gnu_attr___scanf__ __scanf__
+#define gnu_attr_strftime strftime
+#define gnu_attr___strftime__ __strftime__
+#endif
+
+#if !defined (USE_SYSTEM_FORMATS)
+#define USE_PRINTF(FMTPOS, WILDARG) __attribute__((format(gnu_printf, FMTPOS, WILDARG))) __attribute__((nonnull (FMTPOS)))
+#define USE_SCANF(FMTPOS, WILDARG) __attribute__((format(gnu_scanf, FMTPOS, WILDARG))) __attribute__((nonnull (FMTPOS)))
+#define USE_STRFTIME(FMTPOS) __attribute__((__format__(gnu_strftime, FMTPOS, 0))) __attribute__((nonnull (FMTPOS)))
+#else
+#define USE_PRINTF(FMTPOS, WILDARG)
+#define USE_SCANF(FMTPOS, WILDARG)
+#define USE_STRFTIME(FMTPOS)
+#endif
+
 #include <stdarg.h>
 #include <stddef.h>
 
@@ -11,6 +42,20 @@
 typedef __WINT_TYPE__ wint_t;
 #endif
 
+#ifdef _WIN64
+/* Kludges to get types corresponding to size_t and ptrdiff_t.  */
+#define unsigned signed
+typedef signed int signed_size_t __attribute__ ((mode (DI)));
+/* We also use this type to approximate ssize_t.  */
+typedef signed int ssize_t __attribute__ ((mode (DI)));
+#undef unsigned
+#define signed /* Type might or might not have explicit 'signed'.  */
+typedef unsigned int unsigned_ptrdiff_t __attribute__ ((mode (DI)));
+#undef signed
+
+__extension__ typedef int llong  __attribute__ ((mode (DI)));
+__extension__ typedef unsigned int ullong  __attribute__ ((mode (DI)));
+#else
 /* Kludges to get types corresponding to size_t and ptrdiff_t.  */
 #define unsigned signed
 typedef __SIZE_TYPE__ signed_size_t;
@@ -23,6 +68,7 @@ typedef unsigned __PTRDIFF_TYPE__ unsign
 
 __extension__ typedef long long int llong;
 __extension__ typedef unsigned long long int ullong;
+#endif
 
 /* %q formats want a "quad"; GCC considers this to be a long long.  */
 typedef llong quad_t;
@@ -70,3 +116,77 @@ extern size_t strftime (char *restrict, 
 			const struct tm *restrict);
 
 extern ssize_t strfmon (char *restrict, size_t, const char *restrict, ...);
+
+/* Mingw specific part.  */
+#if !defined (USE_SYSTEM_FORMATS) && defined(_WIN32) && !defined(DONT_GNU_PROTOTYPE)
+
+extern USE_PRINTF(2,3) int fprintf_gnu (FILE *restrict, const char *restrict, ...);
+#undef fprintf
+#define fprintf fprintf_gnu
+
+extern USE_PRINTF(1,2) int printf_gnu (const char *restrict, ...);
+#undef printf
+#define printf printf_gnu
+
+extern USE_PRINTF(2,3) int fprintf_unlocked_gnu (FILE *restrict, const char *restrict, ...);
+#undef fprintf_unlocked
+#define fprintf_unlocked fprintf_unlocked_gnu
+
+extern USE_PRINTF(1,2)int printf_unlocked_gnu (const char *restrict, ...);
+#undef printf_unlocked
+#define printf_unlocked printf_unlocked_gnu
+
+extern USE_PRINTF(2,3) int sprintf_gnu (char *restrict, const char *restrict, ...);
+#undef sprintf
+#define sprintf sprintf_gnu
+
+extern USE_PRINTF(2,0) int vfprintf_gnu (FILE *restrict, const char *restrict, va_list);
+#undef vsprintf
+#define vsprintf vsprintf_gnu
+
+extern USE_PRINTF(1,0) int vprintf_gnu (const char *restrict, va_list);
+#undef vprintf
+#define vprintf vprintf_gnu
+
+extern USE_PRINTF(2,0) int vsprintf_gnu (char *restrict, const char *restrict, va_list);
+#undef vsprintf
+#define vsprintf vsprintf_gnu
+
+extern USE_PRINTF(3,4) int snprintf_gnu (char *restrict, size_t, const char *restrict, ...);
+#undef snprintf
+#define snprintf snprintf_gnu
+
+extern USE_PRINTF(3,0) int vsnprintf_gnu (char *restrict, size_t, const char *restrict, va_list);
+#undef vsnprintf
+#define vsnprintf vsnprintf_gnu
+
+extern USE_SCANF(2,3) int fscanf_gnu (FILE *restrict, const char *restrict, ...);
+#undef fscanf
+#define fscanf fscanf_gnu
+
+extern USE_SCANF(1,2) int scanf_gnu (const char *restrict, ...);
+#undef scanf
+#define scanf scanf_gnu
+
+extern USE_SCANF(2,3) int sscanf_gnu (const char *restrict, const char *restrict, ...);
+#undef sscanf
+#define sscanf sscanf_gnu
+
+extern USE_SCANF(2,0) int vfscanf_gnu (FILE *restrict, const char *restrict, va_list);
+#undef vfscanf
+#define vfscanf vfscanf_gnu
+
+extern USE_SCANF(1,0) int vscanf_gnu (const char *restrict, va_list);
+#undef vscanf
+#define vscanf vscanf_gnu
+
+extern USE_SCANF(2,0) int vsscanf_gnu (const char *restrict, const char *restrict, va_list);
+#undef vsscanf
+#define vsscanf vsscanf_gnu
+
+extern USE_STRFTIME(3) size_t strftime_gnu (char *restrict, size_t, const char *restrict,
+			const struct tm *restrict);
+#undef strftime
+#define strftime strftime_gnu
+
+#endif
Index: gcc/gcc/testsuite/gcc.dg/format/attr-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-1.c
@@ -3,7 +3,8 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern void foo0 (const char *) __attribute__((__format__(__strftime__, 1, 0)));
-extern void foo1 (const char *, ...) __attribute__((__format__(__strftime__, 1, 2))); /* { dg-error "cannot format" "strftime first_arg_num != 0" } */
+extern void foo0 (const char *) __attribute__((__format__(gnu_attr___strftime__, 1, 0)));
+extern void foo1 (const char *, ...) __attribute__((__format__(gnu_attr___strftime__, 1, 2))); /* { dg-error "cannot format" "strftime first_arg_num != 0" } */
Index: gcc/gcc/testsuite/gcc.dg/format/attr-2.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-2.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-2.c
@@ -3,22 +3,23 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern void tformatprintf (const char *, ...) __attribute__((format(printf, 1, 2)));
-extern void tformat__printf__ (const char *, ...) __attribute__((format(__printf__, 1, 2)));
-extern void tformatscanf (const char *, ...) __attribute__((format(scanf, 1, 2)));
-extern void tformat__scanf__ (const char *, ...) __attribute__((format(__scanf__, 1, 2)));
-extern void tformatstrftime (const char *) __attribute__((format(strftime, 1, 0)));
-extern void tformat__strftime__ (const char *) __attribute__((format(__strftime__, 1, 0)));
+extern void tformatprintf (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
+extern void tformat__printf__ (const char *, ...) __attribute__((format(gnu_attr___printf__, 1, 2)));
+extern void tformatscanf (const char *, ...) __attribute__((format(gnu_attr_scanf, 1, 2)));
+extern void tformat__scanf__ (const char *, ...) __attribute__((format(gnu_attr___scanf__, 1, 2)));
+extern void tformatstrftime (const char *) __attribute__((format(gnu_attr_strftime, 1, 0)));
+extern void tformat__strftime__ (const char *) __attribute__((format(gnu_attr___strftime__, 1, 0)));
 extern void tformatstrfmon (const char *, ...) __attribute__((format(strfmon, 1, 2)));
 extern void tformat__strfmon__ (const char *, ...) __attribute__((format(__strfmon__, 1, 2)));
-extern void t__format__printf (const char *, ...) __attribute__((__format__(printf, 1, 2)));
-extern void t__format____printf__ (const char *, ...) __attribute__((__format__(__printf__, 1, 2)));
-extern void t__format__scanf (const char *, ...) __attribute__((__format__(scanf, 1, 2)));
-extern void t__format____scanf__ (const char *, ...) __attribute__((__format__(__scanf__, 1, 2)));
-extern void t__format__strftime (const char *) __attribute__((__format__(strftime, 1, 0)));
-extern void t__format____strftime__ (const char *) __attribute__((__format__(__strftime__, 1, 0)));
+extern void t__format__printf (const char *, ...) __attribute__((__format__(gnu_attr_printf, 1, 2)));
+extern void t__format____printf__ (const char *, ...) __attribute__((__format__(gnu_attr___printf__, 1, 2)));
+extern void t__format__scanf (const char *, ...) __attribute__((__format__(gnu_attr_scanf, 1, 2)));
+extern void t__format____scanf__ (const char *, ...) __attribute__((__format__(gnu_attr___scanf__, 1, 2)));
+extern void t__format__strftime (const char *) __attribute__((__format__(gnu_attr_strftime, 1, 0)));
+extern void t__format____strftime__ (const char *) __attribute__((__format__(gnu_attr___strftime__, 1, 0)));
 extern void t__format__strfmon (const char *, ...) __attribute__((__format__(strfmon, 1, 2)));
 extern void t__format____strfmon__ (const char *, ...) __attribute__((__format__(__strfmon__, 1, 2)));
 
Index: gcc/gcc/testsuite/gcc.dg/format/attr-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-3.c
@@ -3,20 +3,21 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 /* Proper uses of the attributes.  */
-extern void fa0 (const char *, ...) __attribute__((format(printf, 1, 2)));
-extern void fa1 (char *, ...) __attribute__((format(printf, 1, 2)));
+extern void fa0 (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
+extern void fa1 (char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
 extern char *fa2 (const char *) __attribute__((format_arg(1)));
 extern char *fa3 (char *) __attribute__((format_arg(1)));
 
 /* Uses with too few or too many arguments.  */
 extern void fb0 (const char *, ...) __attribute__((format)); /* { dg-error "wrong number of arguments" "bad format" } */
 extern void fb1 (const char *, ...) __attribute__((format())); /* { dg-error "wrong number of arguments" "bad format" } */
-extern void fb2 (const char *, ...) __attribute__((format(printf))); /* { dg-error "wrong number of arguments" "bad format" } */
-extern void fb3 (const char *, ...) __attribute__((format(printf, 1))); /* { dg-error "wrong number of arguments" "bad format" } */
-extern void fb4 (const char *, ...) __attribute__((format(printf, 1, 2, 3))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb2 (const char *, ...) __attribute__((format(gnu_attr_printf))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb3 (const char *, ...) __attribute__((format(gnu_attr_printf, 1))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb4 (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2, 3))); /* { dg-error "wrong number of arguments" "bad format" } */
 
 extern void fc1 (const char *) __attribute__((format_arg)); /* { dg-error "wrong number of arguments" "bad format_arg" } */
 extern void fc2 (const char *) __attribute__((format_arg())); /* { dg-error "wrong number of arguments" "bad format_arg" } */
@@ -25,9 +26,9 @@ extern void fc3 (const char *) __attribu
 /* These attributes presently only apply to declarations, not to types.
    Eventually, they should be usable with declarators for function types
    anywhere, but still not with structure/union/enum types.  */
-struct s0 { int i; } __attribute__((format(printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on struct" } */
-union u0 { int i; } __attribute__((format(printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on union" } */
-enum e0 { E0V0 } __attribute__((format(printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on enum" } */
+struct s0 { int i; } __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on struct" } */
+union u0 { int i; } __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on union" } */
+enum e0 { E0V0 } __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on enum" } */
 
 struct s1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on struct" } */
 union u1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on union" } */
@@ -38,28 +39,28 @@ extern void fe0 (const char *, ...) __at
 extern void fe1 (const char *, ...) __attribute__((format(nosuch, 1, 2))); /* { dg-warning "format function type" "unknown format" } */
 
 /* Both the numbers must be integer constant expressions.  */
-extern void ff0 (const char *, ...) __attribute__((format(printf, 3-2, (long long)(10/5))));
+extern void ff0 (const char *, ...) __attribute__((format(gnu_attr_printf, 3-2, (long long)(10/5))));
 int foo;
-extern void ff1 (const char *, ...) __attribute__((format(printf, foo, 10/5))); /* { dg-error "invalid operand" "bad number" } */
-extern void ff2 (const char *, ...) __attribute__((format(printf, 3-2, foo))); /* { dg-error "invalid operand" "bad number" } */
+extern void ff1 (const char *, ...) __attribute__((format(gnu_attr_printf, foo, 10/5))); /* { dg-error "invalid operand" "bad number" } */
+extern void ff2 (const char *, ...) __attribute__((format(gnu_attr_printf, 3-2, foo))); /* { dg-error "invalid operand" "bad number" } */
 extern char *ff3 (const char *) __attribute__((format_arg(3-2)));
 extern char *ff4 (const char *) __attribute__((format_arg(foo))); /* { dg-error "invalid operand" "bad format_arg number" } */
 
 /* The format string argument must precede the arguments to be formatted.
    This includes if no parameter types are specified (which is not valid ISO
    C for variadic functions).  */
-extern void fg0 () __attribute__((format(printf, 1, 2)));
-extern void fg1 () __attribute__((format(printf, 1, 0)));
-extern void fg2 () __attribute__((format(printf, 1, 1))); /* { dg-error "follows" "bad number order" } */
-extern void fg3 () __attribute__((format(printf, 2, 1))); /* { dg-error "follows" "bad number order" } */
+extern void fg0 () __attribute__((format(gnu_attr_printf, 1, 2)));
+extern void fg1 () __attribute__((format(gnu_attr_printf, 1, 0)));
+extern void fg2 () __attribute__((format(gnu_attr_printf, 1, 1))); /* { dg-error "follows" "bad number order" } */
+extern void fg3 () __attribute__((format(gnu_attr_printf, 2, 1))); /* { dg-error "follows" "bad number order" } */
 
 /* The format string argument must be a string type, and the arguments to
    be formatted must be the "...".  */
-extern void fh0 (int, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "not a string" "format int string" } */
-extern void fh1 (signed char *, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "not a string" "signed char string" } */
-extern void fh2 (unsigned char *, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "not a string" "unsigned char string" } */
-extern void fh3 (const char *, ...) __attribute__((format(printf, 1, 3))); /* { dg-error "is not" "not ..." } */
-extern void fh4 (const char *, int, ...) __attribute__((format(printf, 1, 2))); /* { dg-error "is not" "not ..." } */
+extern void fh0 (int, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "format int string" } */
+extern void fh1 (signed char *, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "signed char string" } */
+extern void fh2 (unsigned char *, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "not a string" "unsigned char string" } */
+extern void fh3 (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 3))); /* { dg-error "is not" "not ..." } */
+extern void fh4 (const char *, int, ...) __attribute__((format(gnu_attr_printf, 1, 2))); /* { dg-error "is not" "not ..." } */
 
 /* format_arg formats must take and return a string.  */
 extern char *fi0 (int) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg int string" } */
Index: gcc/gcc/testsuite/gcc.dg/format/attr-4.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-4.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-4.c
@@ -4,12 +4,13 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern __attribute__((format(printf, 1, 2))) void tformatprintf0 (const char *, ...);
-extern void __attribute__((format(printf, 1, 2))) tformatprintf1 (const char *, ...);
-extern void foo (void), __attribute__((format(printf, 1, 2))) tformatprintf2 (const char *, ...);
-extern __attribute__((noreturn)) void bar (void), __attribute__((format(printf, 1, 2))) tformatprintf3 (const char *, ...);
+extern __attribute__((format(gnu_attr_printf, 1, 2))) void tformatprintf0 (const char *, ...);
+extern void __attribute__((format(gnu_attr_printf, 1, 2))) tformatprintf1 (const char *, ...);
+extern void foo (void), __attribute__((format(gnu_attr_printf, 1, 2))) tformatprintf2 (const char *, ...);
+extern __attribute__((noreturn)) void bar (void), __attribute__((format(gnu_attr_printf, 1, 2))) tformatprintf3 (const char *, ...);
 
 void
 baz (int i, int *ip, double d)
Index: gcc/gcc/testsuite/gcc.dg/format/attr-7.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/attr-7.c
+++ gcc/gcc/testsuite/gcc.dg/format/attr-7.c
@@ -3,12 +3,13 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-__attribute__((format(printf, 1, 2))) void (*tformatprintf0) (const char *, ...);
-void (*tformatprintf1) (const char *, ...) __attribute__((format(printf, 1, 2)));
-void (__attribute__((format(printf, 1, 2))) *tformatprintf2) (const char *, ...);
-void (__attribute__((format(printf, 1, 2))) ****tformatprintf3) (const char *, ...);
+__attribute__((format(gnu_attr_printf, 1, 2))) void (*tformatprintf0) (const char *, ...);
+void (*tformatprintf1) (const char *, ...) __attribute__((format(gnu_attr_printf, 1, 2)));
+void (__attribute__((format(gnu_attr_printf, 1, 2))) *tformatprintf2) (const char *, ...);
+void (__attribute__((format(gnu_attr_printf, 1, 2))) ****tformatprintf3) (const char *, ...);
 
 char * (__attribute__((format_arg(1))) *tformat_arg) (const char *);
 
Index: gcc/gcc/testsuite/gcc.dg/format/c90-printf-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/c90-printf-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/c90-printf-3.c
@@ -17,8 +17,8 @@ foo (int i, char *s, size_t n, va_list v
   printf ("%d", i);
   printf ("%ld", i); /* { dg-warning "format" "printf" } */
   /* The "unlocked" functions shouldn't warn in c90 mode.  */
-  fprintf_unlocked (stdout, "%ld", i); /* { dg-bogus "format" "fprintf_unlocked" } */
-  printf_unlocked ("%ld", i); /* { dg-bogus "format" "printf_unlocked" } */
+  fprintf_unlocked (stdout, "%ld", i); /* { dg-warning "format" "fprintf_unlocked" } */
+  printf_unlocked ("%ld", i); /* { dg-warning "format" "printf_unlocked" } */
   sprintf (s, "%d", i);
   sprintf (s, "%ld", i); /* { dg-warning "format" "sprintf" } */
   vfprintf (stdout, "%d", v0);
@@ -30,13 +30,13 @@ foo (int i, char *s, size_t n, va_list v
   vsprintf (s, "%d", v4);
   vsprintf (s, "%Y", v5); /* { dg-warning "format" "vsprintf" } */
   snprintf (s, n, "%d", i);
-  snprintf (s, n, "%ld", i);
+  snprintf (s, n, "%ld", i); /* { dg-warning "format" "snprintf" } */
   vsnprintf (s, n, "%d", v6);
-  vsnprintf (s, n, "%Y", v7);
+  vsnprintf (s, n, "%Y", v7); /* { dg-warning "format" "vsprintf" } */
   printf (gettext ("%d"), i);
   printf (gettext ("%ld"), i);
   printf (dgettext ("", "%d"), i);
-  printf (dgettext ("", "%ld"), i);
+  printf (dgettext ("", "%ld"), (long) i);
   printf (dcgettext ("", "%d", 0), i);
-  printf (dcgettext ("", "%ld", 0), i);
+  printf (dcgettext ("", "%ld", 0), (long) i);
 }
Index: gcc/gcc/testsuite/gcc.dg/format/c90-scanf-4.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/c90-scanf-4.c
+++ gcc/gcc/testsuite/gcc.dg/format/c90-scanf-4.c
@@ -19,11 +19,11 @@ foo (int *ip, char *s, va_list v0, va_li
   sscanf (s, "%d", ip);
   sscanf (s, "%ld", ip); /* { dg-warning "format" "sscanf" } */
   vfscanf (stdin, "%d", v0);
-  vfscanf (stdin, "%Y", v1);
+  vfscanf (stdin, "%Y", v1);  /* { dg-warning "format" "vfscanf" } */
   vscanf ("%d", v2);
-  vscanf ("%Y", v3);
+  vscanf ("%Y", v3);  /* { dg-warning "format" "vscanf" } */
   vsscanf (s, "%d", v4);
-  vsscanf (s, "%Y", v5);
+  vsscanf (s, "%Y", v5);  /* { dg-warning "format" "vsscanf" } */
   scanf (gettext ("%d"), ip);
   scanf (gettext ("%ld"), ip);
   scanf (dgettext ("", "%d"), ip);
Index: gcc/gcc/testsuite/gcc.dg/format/c99-printf-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/c99-printf-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/c99-printf-3.c
@@ -16,8 +16,8 @@ foo (int i, char *s, size_t n, va_list v
   printf ("%d", i);
   printf ("%ld", i); /* { dg-warning "format" "printf" } */
   /* The "unlocked" functions shouldn't warn in c99 mode.  */
-  fprintf_unlocked (stdout, "%ld", i); /* { dg-bogus "format" "fprintf_unlocked" } */
-  printf_unlocked ("%ld", i); /* { dg-bogus "format" "printf_unlocked" } */
+  fprintf_unlocked (stdout, "%ld", i); /* { dg-warning "format" "fprintf_unlocked" } */
+  printf_unlocked ("%ld", i); /* { dg-warning "format" "printf_unlocked" } */
   sprintf (s, "%d", i);
   sprintf (s, "%ld", i); /* { dg-warning "format" "sprintf" } */
   snprintf (s, n, "%d", i);
@@ -31,9 +31,9 @@ foo (int i, char *s, size_t n, va_list v
   vsnprintf (s, n, "%d", v0);
   vsnprintf (s, n, "%Y", v1); /* { dg-warning "format" "vsnprintf" } */
   printf (gettext ("%d"), i);
-  printf (gettext ("%ld"), i);
+  printf (gettext ("%ld"), (long) i);
   printf (dgettext ("", "%d"), i);
-  printf (dgettext ("", "%ld"), i);
+  printf (dgettext ("", "%ld"), (long) i);
   printf (dcgettext ("", "%d", 0), i);
-  printf (dcgettext ("", "%ld", 0), i);
+  printf (dcgettext ("", "%ld", 0), (long) i);
 }
Index: gcc/gcc/testsuite/gcc.dg/format/miss-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-1.c
@@ -23,7 +23,7 @@ bar (const char *fmt, ...)
   va_end (ap);
 }
 
-__attribute__((__format__(__printf__, 1, 2))) void
+__attribute__((__format__(gnu_attr___printf__, 1, 2))) void
 foo2 (const char *fmt, ...)
 {
   va_list ap;
Index: gcc/gcc/testsuite/gcc.dg/format/miss-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-3.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-3.c
@@ -3,13 +3,14 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 void
 foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
@@ -18,7 +19,7 @@ foo1 (noattr_t na, attr_t a, vnoattr_t v
   noattr_t na2 = a; /* { dg-warning "candidate" "initialization warning" } */
   attr_t a1 = na;
   attr_t a2 = a;
-  
+
   vnoattr_t vna1 = vna;
   vnoattr_t vna2 = va; /* { dg-warning "candidate" "initialization warning" } */
   vattr_t va1 = vna;
Index: gcc/gcc/testsuite/gcc.dg/format/miss-4.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-4.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-4.c
@@ -3,20 +3,21 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 void
 foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
 {
   noattr_t na1, na2;
   attr_t a1, a2;
-  
+
   vnoattr_t vna1, vna2;
   vattr_t va1, va2;
 
@@ -24,7 +25,7 @@ foo1 (noattr_t na, attr_t a, vnoattr_t v
   na2 = a; /* { dg-warning "candidate" "assignment warning" } */
   a1 = na;
   a2 = a;
-  
+
   vna1 = vna;
   vna2 = va; /* { dg-warning "candidate" "assignment warning" } */
   va1 = vna;
Index: gcc/gcc/testsuite/gcc.dg/format/miss-5.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-5.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-5.c
@@ -3,13 +3,14 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 noattr_t
 foo1 (noattr_t na, attr_t a, int i)
Index: gcc/gcc/testsuite/gcc.dg/format/miss-6.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/miss-6.c
+++ gcc/gcc/testsuite/gcc.dg/format/miss-6.c
@@ -3,13 +3,14 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 typedef void (*noattr_t) (const char *, ...);
-typedef noattr_t __attribute__ ((__format__(__printf__, 1, 2))) attr_t;
+typedef noattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 2))) attr_t;
 
 typedef void (*vnoattr_t) (const char *, va_list);
-typedef vnoattr_t __attribute__ ((__format__(__printf__, 1, 0))) vattr_t;
+typedef vnoattr_t __attribute__ ((__format__(gnu_attr___printf__, 1, 0))) vattr_t;
 
 extern void foo1 (noattr_t);
 extern void foo2 (attr_t);
@@ -23,7 +24,7 @@ foo (noattr_t na, attr_t a, vnoattr_t vn
   foo1 (a); /* { dg-warning "candidate" "parameter passing warning" } */
   foo2 (na);
   foo2 (a);
-  
+
   foo3 (vna);
   foo3 (va); /* { dg-warning "candidate" "parameter passing warning" } */
   foo4 (vna);
Index: gcc/gcc/testsuite/gcc.dg/format/ms_array-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_array-1.c
@@ -0,0 +1,42 @@
+/* Test for format checking of constant arrays.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat=2" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+const char a1[] = "foo";
+const char a2[] = "foo%d";
+const char b1[3] = "foo";
+const char b2[1] = "1";
+static const char c1[] = "foo";
+static const char c2[] = "foo%d";
+char d[] = "foo";
+volatile const char e[] = "foo";
+
+void
+foo (int i, long l)
+{
+  const char p1[] = "bar";
+  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 (c1);
+  printf (c2, i);
+  printf (c2, l); /* { dg-warning "format" "wrong type with array" } */
+  printf (p1);
+  printf (p2, i);
+  printf (p2, l); /* { dg-warning "format" "wrong type with array" } */
+  printf (q1);
+  printf (q2, i);
+  printf (q2, l); /* { dg-warning "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" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-1.c
@@ -0,0 +1,10 @@
+/* Test for strftime format attributes: can't have first_arg_num != 0.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define DONT_GNU_PROTOTYPE
+#include "format.h"
+
+extern void foo0 (const char *) __attribute__((__format__(__ms_strftime__, 1, 0)));
+extern void foo1 (const char *, ...) __attribute__((__format__(__ms_strftime__, 1, 2))); /* { dg-error "cannot format" "strftime first_arg_num != 0" } */
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-2.c
@@ -0,0 +1,68 @@
+/* Test for format attributes: test use of __attribute__.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define DONT_GNU_PROTOTYPE
+#include "format.h"
+
+extern void tformatprintf (const char *, ...) __attribute__((format(ms_printf, 1, 2)));
+extern void tformat__printf__ (const char *, ...) __attribute__((format(__ms_printf__, 1, 2)));
+extern void tformatscanf (const char *, ...) __attribute__((format(ms_scanf, 1, 2)));
+extern void tformat__scanf__ (const char *, ...) __attribute__((format(__ms_scanf__, 1, 2)));
+extern void tformatstrftime (const char *) __attribute__((format(ms_strftime, 1, 0)));
+extern void tformat__strftime__ (const char *) __attribute__((format(__ms_strftime__, 1, 0)));
+extern void tformatstrfmon (const char *, ...) __attribute__((format(strfmon, 1, 2)));
+extern void tformat__strfmon__ (const char *, ...) __attribute__((format(__strfmon__, 1, 2)));
+extern void t__format__printf (const char *, ...) __attribute__((__format__(ms_printf, 1, 2)));
+extern void t__format____printf__ (const char *, ...) __attribute__((__format__(__ms_printf__, 1, 2)));
+extern void t__format__scanf (const char *, ...) __attribute__((__format__(ms_scanf, 1, 2)));
+extern void t__format____scanf__ (const char *, ...) __attribute__((__format__(__ms_scanf__, 1, 2)));
+extern void t__format__strftime (const char *) __attribute__((__format__(ms_strftime, 1, 0)));
+extern void t__format____strftime__ (const char *) __attribute__((__format__(__ms_strftime__, 1, 0)));
+extern void t__format__strfmon (const char *, ...) __attribute__((__format__(strfmon, 1, 2)));
+extern void t__format____strfmon__ (const char *, ...) __attribute__((__format__(__strfmon__, 1, 2)));
+
+extern char *tformat_arg (const char *) __attribute__((format_arg(1)));
+extern char *t__format_arg__ (const char *) __attribute__((__format_arg__(1)));
+
+void
+foo (int i, int *ip, double d)
+{
+  tformatprintf ("%d", i);
+  tformatprintf ("%"); /* { dg-warning "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);
+  tformat__scanf__ ("%"); /* { dg-warning "format" "attribute format __scanf__" } */
+  tformatstrftime ("%a");
+  tformatstrftime ("%"); /* { dg-warning "format" "attribute format strftime" } */
+  tformat__strftime__ ("%a");
+  tformat__strftime__ ("%"); /* { dg-warning "format" "attribute format __strftime__" } */
+  tformatstrfmon ("%n", d);
+  tformatstrfmon ("%"); /* { dg-warning "format" "attribute format strfmon" } */
+  tformat__strfmon__ ("%n", d);
+  tformat__strfmon__ ("%"); /* { dg-warning "format" "attribute format __strfmon__" } */
+  t__format__printf ("%d", i);
+  t__format__printf ("%"); /* { dg-warning "format" "attribute __format__ printf" } */
+  t__format____printf__ ("%d", i);
+  t__format____printf__ ("%"); /* { dg-warning "format" "attribute __format__ __printf__" } */
+  t__format__scanf ("%d", ip);
+  t__format__scanf ("%"); /* { dg-warning "format" "attribute __format__ scanf" } */
+  t__format____scanf__ ("%d", ip);
+  t__format____scanf__ ("%"); /* { dg-warning "format" "attribute __format__ __scanf__" } */
+  t__format__strftime ("%a");
+  t__format__strftime ("%"); /* { dg-warning "format" "attribute __format__ strftime" } */
+  t__format____strftime__ ("%a");
+  t__format____strftime__ ("%"); /* { dg-warning "format" "attribute __format__ __strftime__" } */
+  t__format__strfmon ("%n", d);
+  t__format__strfmon ("%"); /* { dg-warning "format" "attribute __format__ strfmon" } */
+  t__format____strfmon__ ("%n", d);
+  t__format____strfmon__ ("%"); /* { dg-warning "format" "attribute __format__ __strfmon__" } */
+  tformatprintf (tformat_arg ("%d"), i);
+  tformatprintf (tformat_arg ("%")); /* { dg-warning "format" "attribute format_arg" } */
+  tformatprintf (t__format_arg__ ("%d"), i);
+  tformatprintf (t__format_arg__ ("%")); /* { dg-warning "format" "attribute __format_arg__" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-3.c
@@ -0,0 +1,71 @@
+/* Test for format attributes: test bad uses of __attribute__.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* Proper uses of the attributes.  */
+extern void fa0 (const char *, ...) __attribute__((format(ms_printf, 1, 2)));
+extern void fa1 (char *, ...) __attribute__((format(ms_printf, 1, 2)));
+extern char *fa2 (const char *) __attribute__((format_arg(1)));
+extern char *fa3 (char *) __attribute__((format_arg(1)));
+
+/* Uses with too few or too many arguments.  */
+extern void fb0 (const char *, ...) __attribute__((format)); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb1 (const char *, ...) __attribute__((format())); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb2 (const char *, ...) __attribute__((format(ms_printf))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb3 (const char *, ...) __attribute__((format(ms_printf, 1))); /* { dg-error "wrong number of arguments" "bad format" } */
+extern void fb4 (const char *, ...) __attribute__((format(ms_printf, 1, 2, 3))); /* { dg-error "wrong number of arguments" "bad format" } */
+
+extern void fc1 (const char *) __attribute__((format_arg)); /* { dg-error "wrong number of arguments" "bad format_arg" } */
+extern void fc2 (const char *) __attribute__((format_arg())); /* { dg-error "wrong number of arguments" "bad format_arg" } */
+extern void fc3 (const char *) __attribute__((format_arg(1, 2))); /* { dg-error "wrong number of arguments" "bad format_arg" } */
+
+/* These attributes presently only apply to declarations, not to types.
+   Eventually, they should be usable with declarators for function types
+   anywhere, but still not with structure/union/enum types.  */
+struct s0 { int i; } __attribute__((format(ms_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on struct" } */
+union u0 { int i; } __attribute__((format(ms_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on union" } */
+enum e0 { E0V0 } __attribute__((format(ms_printf, 1, 2))); /* { dg-error "does not apply|only applies" "format on enum" } */
+
+struct s1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on struct" } */
+union u1 { int i; } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on union" } */
+enum e1 { E1V0 } __attribute__((format_arg(1))); /* { dg-error "does not apply|only applies" "format_arg on enum" } */
+
+/* The format type must be an identifier, one of those recognized.  */
+extern void fe0 (const char *, ...) __attribute__((format(12345, 1, 2))); /* { dg-error "format specifier" "non-id format" } */
+extern void fe1 (const char *, ...) __attribute__((format(nosuch, 1, 2))); /* { dg-warning "format function type" "unknown format" } */
+
+/* Both the numbers must be integer constant expressions.  */
+extern void ff0 (const char *, ...) __attribute__((format(ms_printf, 3-2, (long long)(10/5))));
+int foo;
+extern void ff1 (const char *, ...) __attribute__((format(ms_printf, foo, 10/5))); /* { dg-error "invalid operand" "bad number" } */
+extern void ff2 (const char *, ...) __attribute__((format(ms_printf, 3-2, foo))); /* { dg-error "invalid operand" "bad number" } */
+extern char *ff3 (const char *) __attribute__((format_arg(3-2)));
+extern char *ff4 (const char *) __attribute__((format_arg(foo))); /* { dg-error "invalid operand" "bad format_arg number" } */
+
+/* The format string argument must precede the arguments to be formatted.
+   This includes if no parameter types are specified (which is not valid ISO
+   C for variadic functions).  */
+extern void fg0 () __attribute__((format(ms_printf, 1, 2)));
+extern void fg1 () __attribute__((format(ms_printf, 1, 0)));
+extern void fg2 () __attribute__((format(ms_printf, 1, 1))); /* { dg-error "follows" "bad number order" } */
+extern void fg3 () __attribute__((format(ms_printf, 2, 1))); /* { dg-error "follows" "bad number order" } */
+
+/* The format string argument must be a string type, and the arguments to
+   be formatted must be the "...".  */
+extern void fh0 (int, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "not a string" "format int string" } */
+extern void fh1 (signed char *, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "not a string" "signed char string" } */
+extern void fh2 (unsigned char *, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "not a string" "unsigned char string" } */
+extern void fh3 (const char *, ...) __attribute__((format(ms_printf, 1, 3))); /* { dg-error "is not" "not ..." } */
+extern void fh4 (const char *, int, ...) __attribute__((format(ms_printf, 1, 2))); /* { dg-error "is not" "not ..." } */
+
+/* format_arg formats must take and return a string.  */
+extern char *fi0 (int) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg int string" } */
+extern char *fi1 (signed char *) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg signed char string" } */
+extern char *fi2 (unsigned char *) __attribute__((format_arg(1))); /* { dg-error "not a string" "format_arg unsigned char string" } */
+extern int fi3 (const char *) __attribute__((format_arg(1))); /* { dg-error "not return string" "format_arg ret int string" } */
+extern signed char *fi4 (const char *) __attribute__((format_arg(1))); /* { dg-error "not return string" "format_arg ret signed char string" } */
+extern unsigned char *fi5 (const char *) __attribute__((format_arg(1))); /* { dg-error "not return string" "format_arg ret unsigned char string" } */
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-4.c
@@ -0,0 +1,26 @@
+/* Test for format attributes: test use of __attribute__
+   in prefix attributes.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+extern __attribute__((format(ms_printf, 1, 2))) void tformatprintf0 (const char *, ...);
+extern void __attribute__((format(ms_printf, 1, 2))) tformatprintf1 (const char *, ...);
+extern void foo (void), __attribute__((format(ms_printf, 1, 2))) tformatprintf2 (const char *, ...);
+extern __attribute__((noreturn)) void bar (void), __attribute__((format(ms_printf, 1, 2))) tformatprintf3 (const char *, ...);
+
+void
+baz (int i, int *ip, double d)
+{
+  tformatprintf0 ("%d", i);
+  tformatprintf0 ("%"); /* { dg-warning "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);
+  tformatprintf3 ("%"); /* { dg-warning "format" "attribute format printf case 3" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_attr-7.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_attr-7.c
@@ -0,0 +1,35 @@
+/* Test for format attributes: test applying them to types.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define DONT_GNU_PROTOTYPE
+#include "format.h"
+
+__attribute__((format(ms_printf, 1, 2))) void (*tformatprintf0) (const char *, ...);
+void (*tformatprintf1) (const char *, ...) __attribute__((format(ms_printf, 1, 2)));
+void (__attribute__((format(ms_printf, 1, 2))) *tformatprintf2) (const char *, ...);
+void (__attribute__((format(ms_printf, 1, 2))) ****tformatprintf3) (const char *, ...);
+
+char * (__attribute__((format_arg(1))) *tformat_arg) (const char *);
+
+void
+baz (int i)
+{
+  (*tformatprintf0) ("%d", i);
+  (*tformatprintf0) ((*tformat_arg) ("%d"), i);
+  (*tformatprintf0) ("%"); /* { dg-warning "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" } */
+  (*tformatprintf2) ("%d", i);
+  (*tformatprintf2) ((*tformat_arg) ("%d"), i);
+  (*tformatprintf2) ("%"); /* { dg-warning "format" "nested" } */
+  (*tformatprintf2) ((*tformat_arg) ("%")); /* { dg-warning "format" "nested" } */
+  (****tformatprintf3) ("%d", i);
+  (****tformatprintf3) ((*tformat_arg) ("%d"), i);
+  (****tformatprintf3) ("%"); /* { dg-warning "format" "nested 2" } */
+  (****tformatprintf3) ((*tformat_arg) ("%")); /* { dg-warning "format" "nested 2" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_bitfld-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_bitfld-1.c
@@ -0,0 +1,52 @@
+/* Test for printf formats and bit-fields: bug 22421.  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+/* { dg-require-effective-target int32plus } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+struct s {
+  unsigned int u1 : 1;
+  signed int s1 : 1;
+  unsigned int u15 : 15;
+  signed int s15 : 15;
+  unsigned int u16 : 16;
+  signed int s16 : 16;
+  unsigned long u31 : 31;
+  signed long s31 : 31;
+  unsigned long u32 : 32;
+  signed long s32 : 32;
+  unsigned long long u48 : 48;
+} x;
+
+void
+foo (void)
+{
+  printf ("%d%u", x.u1, x.u1);
+  printf ("%d%u", x.s1, x.s1);
+  printf ("%d%u", x.u15, x.u15);
+  printf ("%d%u", x.s15, x.s15);
+  printf ("%d%u", x.u16, x.u16);
+  printf ("%d%u", x.s16, x.s16);
+#if __INT_MAX__ > 32767
+  /* If integers are 16 bits, there doesn't seem to be a way of
+     printing these without getting an error.  */
+  printf ("%d%u", x.u31, x.u31);
+  printf ("%d%u", x.s31, x.s31);
+#endif
+#if __LONG_MAX__ > 2147483647 && __INT_MAX__ >= 2147483647
+  /* If long is wider than 32 bits, the 32-bit bit-fields are int or
+     unsigned int or promote to those types.  Otherwise, long is 32
+     bits and the bit-fields are of type plain long or unsigned
+     long.  */
+  printf ("%d%u", x.u32, x.u32);
+  printf ("%d%u", x.s32, x.s32);
+#else
+  printf ("%ld%lu", x.u32, x.u32);
+  printf ("%ld%lu", x.s32, x.s32);
+#endif
+  printf ("%I64u", x.u48); /* { dg-warning "has type '.*unsigned int:48'" } */
+  printf ("%I64u", (unsigned long long)x.u48);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_branch-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_branch-1.c
@@ -0,0 +1,28 @@
+/* Test for format checking of conditional expressions.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+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" } */
+  /* 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) ? "%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" } */
+  /* 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 *-*-* } 26 } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-1.c
@@ -0,0 +1,184 @@
+/* Test for printf formats.  Formats using C90 features, including cases
+   where C90 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, int i1, int i2, unsigned int u, double d, char *s, void *p,
+     int *n, short int *hn, long int l, unsigned long int ul,
+     long int *ln, long double ld, wint_t lc, wchar_t *ls, llong ll,
+     ullong ull, unsigned int *un, const int *cn, signed char *ss,
+     unsigned char *us, const signed char *css, unsigned int u1,
+     unsigned int u2)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.1 (pages 131-134).  */
+  /* Basic sanity checks for the different components of a format.  */
+  printf ("%d\n", i);
+  printf ("%+d\n", i);
+  printf ("%3d\n", i);
+  printf ("%-3d\n", i);
+  printf ("%*d\n", i1, i);
+  printf ("%d %lu\n", i, ul);
+  /* Bogus use of width.  */
+  printf ("%5n\n", n); /* { dg-warning "width" "width 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 ("%-%"); /* { dg-warning "format" "bogus %%" } */
+  printf ("%-%\n"); /* { dg-warning "format" "bogus %%" } */
+  printf ("%5%\n"); /* { dg-warning "format" "bogus %%" } */
+  printf ("%h%\n"); /* { dg-warning "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
+     differences in format checking here, and this is relied on to get the
+     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);
+  printf ("%hs", hn);
+  printf ("%hp", p); /* { dg-warning "length" "bad use of %h" } */
+  printf ("%h"); /* { dg-warning "conversion lacks type" "bare %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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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% 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* Various tests of bad argument types.  */
+  printf ("%d", l); /* { dg-warning "format" "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" } */
+  /* 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
+     discussion of the requirements of rules on identical representation,
+     and of the application of the as if rule with the new va_arg
+     allowances in C99 to printf.)  Likewise, we should warn if
+     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" } */
+  /* 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" } */
+  /* The historical behavior is to allow signed / unsigned types
+     interchangably as arguments.  For values representable in both types,
+     such usage may be correct.  For now preserve the behavior of GCC
+     in such cases.
+  */
+  printf ("%d", u);
+  /* Wrong number of arguments.  */
+  printf ("%d%d", i); /* { dg-warning "arguments" "wrong number of args" } */
+  printf ("%d", i, i); /* { dg-warning "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" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-2.c
@@ -0,0 +1,25 @@
+/* Test for printf formats.  Formats using C99 features should be rejected
+   outside of C99 mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, double d, llong ll, intmax_t j, size_t z, ptrdiff_t t)
+{
+  /* Some tests already in c90-printf-1.c, e.g. %lf.  */
+  /* The widths hh, ll, j, z, t are new.  */
+  printf ("%hhd", i); /* { dg-warning "unknown|format" "%hh is unsupported" } */
+  printf ("%I64d", ll); /* { dg-warning "length|C" "%I64 in C90" } */
+  printf ("%jd", j); /* { dg-warning "unknown|format" "%j is unsupported" } */
+  printf ("%zu", z); /* { dg-warning "unknown|format" "%z is unsupported" } */
+  printf ("%td", t); /* { dg-warning "unknown|format" "%t is unsupported" } */
+  /* The formats F, a, A are new.  */
+  printf ("%F", d); /* { dg-warning "unknown|format" "%F is unsupported" } */
+  printf ("%a", d); /* { dg-warning "unknown|format" "%a is unsupported" } */
+  printf ("%A", d); /* { dg-warning "unknown|format" "%A is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-printf-3.c
@@ -0,0 +1,43 @@
+/* Test for printf formats.  Test that the C90 functions get their default
+   attributes in strict C90 mode, but the C99 and gettext functions
+   do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, char *s, size_t n, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5, va_list v6, va_list v7, va_list v8)
+{
+  fprintf (stdout, "%d", i);
+  fprintf (stdout, "%ld", i); /* { dg-warning "format" "fprintf" } */
+  printf ("%d", i);
+  printf ("%ld", i); /* { dg-warning "format" "printf" } */
+  /* The "unlocked" functions shouldn't warn in c90 mode.  */
+  fprintf_unlocked (stdout, "%ld", i);
+  printf_unlocked ("%ld", i);
+  sprintf (s, "%d", i);
+  sprintf (s, "%ld", i); /* { dg-warning "format" "sprintf" } */
+  vfprintf (stdout, "%d", v0);
+  vfprintf (stdout, "%Y", v1); /* { dg-warning "format" "vfprintf" } */
+  vprintf ("%d", v2);
+  vprintf ("%Y", v3); /* { dg-warning "format" "vprintf" } */
+  /* The following used to give a bogus warning.  */
+  vprintf ("%*.*d", v8); /* { dg-warning "format" "dot is invalid" } */
+  vsprintf (s, "%d", v4);
+  vsprintf (s, "%Y", v5); /* { dg-warning "format" "Y is invalid" } */
+  snprintf (s, n, "%d", i);
+  snprintf (s, n, "%ld", i);
+  vsnprintf (s, n, "%d", v6);
+  vsnprintf (s, n, "%Y", v7);
+  printf (gettext ("%d"), i);
+  printf (gettext ("%ld"), i);
+  printf (dgettext ("", "%d"), i);
+  printf (dgettext ("", "%ld"), (long) i);
+  printf (dcgettext ("", "%d", 0), i);
+  printf (dcgettext ("", "%ld", 0), (long) i);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-1.c
@@ -0,0 +1,119 @@
+/* Test for scanf formats.  Formats using C90 features, including cases
+   where C90 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, unsigned int *uip, short int *hp, unsigned short int *uhp,
+     long int *lp, unsigned long int *ulp, float *fp, double *dp,
+     long double *ldp, char *s, signed char *ss, unsigned char *us,
+     void **pp, int *n, llong *llp, ullong *ullp, wchar_t *ls,
+     const int *cip, const int *cn, const char *cs, const void **ppc,
+     void *const *pcp, short int *hn, long int *ln, void *p, char **sp,
+     volatile void *ppv)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.2 (pages 134-138).  */
+  /* Basic sanity checks for the different components of a format.  */
+  scanf ("%d", ip);
+  scanf ("%*d");
+  scanf ("%3d", ip);
+  scanf ("%hd", hp);
+  scanf ("%3ld", lp);
+  scanf ("%*3d");
+  scanf ("%d %ld", ip, lp);
+  /* Valid and invalid %% constructions.  */
+  scanf ("%%");
+  scanf ("%*%"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%*%\n"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%4%"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%4%\n"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%h%"); /* { dg-warning "format" "bogus %%" } */
+  scanf ("%h%\n"); /* { dg-warning "format" "bogus %%" } */
+  /* Valid, invalid and silly assignment-suppression constructions.  */
+  scanf ("%*d%*i%*o%*u%*x%*X%*e%*E%*f%*g%*G%*s%*[abc]%*c%*p");
+  scanf ("%*2d%*8s%*3c");
+  scanf ("%*n", n); /* { dg-warning "suppress" "suppression of %n" } */
+  scanf ("%*hd"); /* { dg-warning "together" "suppression with length" } */
+  /* Valid, invalid and silly width constructions.  */
+  scanf ("%2d%3i%4o%5u%6x%7X%8e%9E%10f%11g%12G%13s%14[abc]%15c%16p",
+	 ip, ip, uip, uip, uip, uip, fp, fp, fp, fp, fp, s, s, s, pp);
+  scanf ("%0d", ip); /* { dg-warning "width" "warning for zero width" } */
+  scanf ("%3n", n); /* { dg-warning "width" "width with %n" } */
+  /* Valid and invalid %h, %l, %L constructions.  */
+  scanf ("%hd%hi%ho%hu%hx%hX%hn", hp, hp, uhp, uhp, uhp, uhp, hn);
+  scanf ("%he", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hE", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hf", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hg", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hG", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hs", hp);
+  scanf ("%h[ac]", s); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hc", hp);
+  scanf ("%hp", pp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%h"); /* { dg-warning "conversion lacks type" "bare %h" } */
+  scanf ("%h."); /* { dg-warning "conversion" "bogus %h" } */
+  scanf ("%ld%li%lo%lu%lx%lX%ln", lp, lp, ulp, ulp, ulp, ulp, ln);
+  scanf ("%le%lE%lf%lg%lG", dp, dp, dp, dp, dp);
+  scanf ("%lp", pp); /* { dg-warning "length" "bad use of %l" } */
+  /* These next three formats were added in C94.  */
+  scanf ("%ls", ls); /* { dg-warning "length|C" "bad use of %l" } */
+  scanf ("%l[ac]", ls); /* { dg-warning "length|C" "bad use of %l" } */
+  scanf ("%lc", ls); /* { dg-warning "length|C" "bad use of %l" } */
+  scanf ("%Ld", llp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Li", llp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lo", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lu", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lx", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%LX", ullp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Ls", s); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%L[ac]", s); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lc", s); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Lp", pp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  scanf ("%Ln", n); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  /* Valid uses of each bare conversion.  */
+  scanf ("%d%i%o%u%x%X%e%E%f%g%G%s%[abc]%c%p%n%%", ip, ip, uip, uip, uip,
+	 uip, fp, fp, fp, fp, fp, s, s, s, pp, n);
+  /* Allow other character pointers with %s, %c, %[].  */
+  scanf ("%2s%3s%4c%5c%6[abc]%7[abc]", ss, us, ss, us, ss, us);
+  /* Further tests for %[].  */
+  scanf ("%[%d]%d", s, ip);
+  scanf ("%[^%d]%d", s, ip);
+  scanf ("%[]%d]%d", s, ip);
+  scanf ("%[^]%d]%d", s, ip);
+  scanf ("%[%d]%d", s, ip);
+  scanf ("%[]abcd", s); /* { dg-warning "no closing" "incomplete scanset" } */
+  /* Various tests of bad argument types.  Some of these are only pedantic
+     warnings.
+  */
+  scanf ("%d", lp); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%d", uip); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%d", pp); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", ppc); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", ppv); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%s", n); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%s", p); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", p); /* { dg-warning "format" "bad argument types" } */
+  scanf ("%p", sp); /* { dg-warning "format" "bad argument types" } */
+  /* Tests for writing into constant values.  */
+  scanf ("%d", cip); /* { dg-warning "constant" "%d writing into const" } */
+  scanf ("%n", cn); /* { dg-warning "constant" "%n writing into const" } */
+  scanf ("%s", cs); /* { dg-warning "constant" "%s writing into const" } */
+  scanf ("%p", pcp); /* { dg-warning "constant" "%p writing into const" } */
+  /* Wrong number of arguments.  */
+  scanf ("%d%d", ip); /* { dg-warning "arguments" "wrong number of args" } */
+  scanf ("%d", ip, ip); /* { dg-warning "arguments" "wrong number of args" } */
+  /* Miscellaneous bogus constructions.  */
+  scanf (""); /* { dg-warning "zero-length" "warning for empty format" } */
+  scanf ("\0"); /* { dg-warning "embedded" "warning for embedded NUL" } */
+  scanf ("%d\0", ip); /* { dg-warning "embedded" "warning for embedded NUL" } */
+  scanf ("%d\0%d", ip, ip); /* { dg-warning "embedded|too many" "warning for embedded NUL" } */
+  scanf (NULL); /* { dg-warning "null" "null format string warning" } */
+  scanf ("%"); /* { dg-warning "trailing" "trailing % warning" } */
+  scanf ("%d", (int *)0); /* { dg-warning "null" "writing into NULL" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-2.c
@@ -0,0 +1,26 @@
+/* Test for scanf formats.  Formats using C99 features should be rejected
+   outside of C99 mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (signed char *hhp, float *fp, llong *llp, intmax_t *jp,
+     size_t *zp, ptrdiff_t *tp)
+{
+  /* Some tests already in c90-scanf-1.c.  */
+  /* The widths hh, ll, j, z, t are new.  */
+  scanf ("%hhd", hhp); /* { dg-warning "unknown|format" "%hh is unsupported" } */
+  scanf ("%I64d", llp); /* { dg-warning "length|C" "%I64 in C90" } */
+  scanf ("%jd", jp); /* { dg-warning "unknown|format" "%j is unsupported" } */
+  scanf ("%zu", zp); /* { dg-warning "unknown|format" "%z is unsupported" } */
+  scanf ("%td", tp); /* { dg-warning "unknown|format" "%t is unsupported" } */
+  /* The formats F, a, A are new.  */
+  scanf ("%F", fp); /* { dg-warning "unknown|format" "%F is unsupported" } */
+  scanf ("%a", fp); /* { dg-warning "unknown|format" "%a is unsupported" } */
+  scanf ("%A", fp); /* { dg-warning "unknown|format" "%A is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-3.c
@@ -0,0 +1,20 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char **sp, wchar_t **lsp)
+{
+  /* %a formats for allocation, only recognized in C90 mode, are a
+     GNU extension.
+  */
+  scanf ("%as", sp); /* { dg-warning "flag" "%as is unsupported" } */
+  scanf ("%aS", lsp); /* { dg-warning "format|flag" "%aS is unsupported" } */
+  scanf ("%a[bcd]", sp); /* { dg-warning "flag" "%a[] is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-4.c
@@ -0,0 +1,31 @@
+/* Test for scanf formats.  Test that the C90 functions get their default
+   attributes in strict C90 mode, but the C99 and gettext functions
+   do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, char *s, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5)
+{
+  fscanf (stdin, "%d", ip);
+  fscanf (stdin, "%ld", ip); /* { dg-warning "format" "fscanf" } */
+  scanf ("%d", ip);
+  scanf ("%ld", ip); /* { dg-warning "format" "scanf" } */
+  sscanf (s, "%d", ip);
+  sscanf (s, "%ld", ip); /* { dg-warning "format" "sscanf" } */
+  vfscanf (stdin, "%d", v0);
+  vscanf ("%d", v2);
+  vsscanf (s, "%d", v4);
+  scanf (gettext ("%d"), ip);
+  scanf (gettext ("%ld"), ip);
+  scanf (dgettext ("", "%d"), ip);
+  scanf (dgettext ("", "%ld"), ip);
+  scanf (dcgettext ("", "%d", 0), ip);
+  scanf (dcgettext ("", "%ld", 0), ip);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-5.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-scanf-5.c
@@ -0,0 +1,20 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char **sp, wchar_t **lsp)
+{
+  /* m assignment-allocation modifier, recognized in both C90
+     and C99 modes, is a POSIX and ISO/IEC WDTR 24731-2 extension.  */
+  scanf ("%ms", sp); /* { dg-warning "unknown|format" "%ms is unsupported" } */
+  scanf ("%mS", lsp); /* { dg-warning "unknown|format" "%mS is unsupported" } */
+  scanf ("%mls", lsp); /* { dg-warning "unknown|format" "%mls is unsupported" } */
+  scanf ("%m[bcd]", sp); /* { dg-warning "unknown|format" "%m[] is unsupported" } */
+  scanf ("%ml[bcd]", lsp); /* { dg-warning "unknown|format" "%ml[] is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-1.c
@@ -0,0 +1,20 @@
+/* Test for strftime formats.  Formats using C90 features.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wformat-y2k" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.12.3.5 (pages 174-175).  */
+  /* Formats which are Y2K-compliant (no 2-digit years).  */
+  strftime (s, m, "%a%A%b%B%d%H%I%j%m%M%p%S%U%w%W%X%Y%Z%%", tp);
+  /* Formats with 2-digit years.  */
+  strftime (s, m, "%y", tp); /* { dg-warning "only last 2" "2-digit year" } */
+  /* Formats with 2-digit years in some locales.  */
+  strftime (s, m, "%c", tp); /* { dg-warning "some locales" "2-digit year" } */
+  strftime (s, m, "%x", tp); /* { dg-warning "some locales" "2-digit year" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c90-strftime-2.c
@@ -0,0 +1,30 @@
+/* Test for strftime formats.  Rejection of formats using C99 features in
+   pedantic C90 mode.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wformat-y2k" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  strftime (s, m, "%C", tp); /* { dg-warning "format" "%C is unsupported" } */
+  strftime (s, m, "%D", tp); /* { dg-warning "format" "%D is unsupported" } */
+  strftime (s, m, "%e", tp); /* { dg-warning "format" "%e is unsupported" } */
+  strftime (s, m, "%F", tp); /* { dg-warning "format" "%F is unsupported" } */
+  strftime (s, m, "%g", tp); /* { dg-warning "format" "%g is unsupported" } */
+  strftime (s, m, "%G", tp); /* { dg-warning "format" "%G is unsupported" } */
+  strftime (s, m, "%h", tp); /* { dg-warning "format" "%h is unsupported" } */
+  strftime (s, m, "%n", tp); /* { dg-warning "format" "%n is unsupported" } */
+  strftime (s, m, "%r", tp); /* { dg-warning "format" "%r is unsupported" } */
+  strftime (s, m, "%R", tp); /* { dg-warning "format" "%R is unsupported" } */
+  strftime (s, m, "%t", tp); /* { dg-warning "format" "%t is unsupported" } */
+  strftime (s, m, "%T", tp); /* { dg-warning "format" "%T is unsupported" } */
+  strftime (s, m, "%u", tp); /* { dg-warning "format" "%u is unsupported" } */
+  strftime (s, m, "%V", tp); /* { dg-warning "format" "%V is unsupported" } */
+  strftime (s, m, "%z", tp); /* { dg-warning "C" "%z not in C90" } */
+  strftime (s, m, "%EX", tp); /* { dg-warning "C" "%E not in C90" } */
+  strftime (s, m, "%OW", tp); /* { dg-warning "C" "%O not in C90" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c94-printf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c94-printf-1.c
@@ -0,0 +1,19 @@
+/* Test for printf formats.  Changes in C94 to C90.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:199409 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (wint_t lc, wchar_t *ls)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.1 (pages 131-134),
+     as amended by ISO/IEC 9899:1990/Amd.1:1995 (E) (pages 4-5).
+     We do not repeat here all the C90 format checks, but just verify
+     that %ls and %lc are accepted without warning.
+  */
+  printf ("%lc", lc);
+  printf ("%ls", ls);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c94-scanf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c94-scanf-1.c
@@ -0,0 +1,18 @@
+/* Test for scanf formats.  Changes in C94 to C90.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:199409 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (wchar_t *ls)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.2 (pages 134-138),
+     as amended by ISO/IEC 9899:1990/Amd.1:1995 (E) (pages 5-6).
+     We do not repeat here all the C90 format checks, but just verify
+     that %ls, %lc, %l[] are accepted without warning.
+  */
+  scanf ("%lc%ls%l[abc]", ls, ls, ls);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-1.c
@@ -0,0 +1,122 @@
+/* Test for printf formats.  Formats using C99 features, including cases
+   where C99 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, unsigned int u, double d, char *s, void *p, int *n,
+     long double ld, wint_t lc, wchar_t *ls, long long int ll,
+     unsigned long long int ull, signed char *ss, unsigned char *us,
+     long long int *lln, intmax_t j, uintmax_t uj, intmax_t *jn,
+     size_t z, signed_size_t sz, signed_size_t *zn,
+     ptrdiff_t t, ptrdiff_t *tn)
+{
+  /* See ISO/IEC 9899:1999 (E) subclause 7.19.6.1 (pages 273-281).
+     We do not repeat here most of the checks for correct C90 formats
+     or completely broken formats.
+  */
+  /* Valid and invalid %h, %hh, %l, %I64, %j, %z, %t, %L constructions.  */
+  printf ("%hf", d); /* { dg-warning "length" "bad use of %h" } */
+  printf ("%hF", d); /* { dg-warning "unknown|format" "bad use of %hF" } */
+  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 ("%ha", d); /* { dg-warning "unknown|format" "bad use of %ha" } */
+  printf ("%hA", d); /* { dg-warning "unknown|format" "bad use of %hA" } */
+  printf ("%hc", i);
+  printf ("%hs", (short *)s);
+  printf ("%hp", p); /* { dg-warning "length" "bad use of %h" } */
+  printf ("%lc", lc);
+  printf ("%ls", ls);
+  printf ("%lp", p); /* { dg-warning "length|C" "bad use of %l" } */
+  printf ("%I64d%I64i%I64o%I64u%I64x%I64X", ll, ll, ull, ull, ull, ull);
+  printf ("%I64n", lln);
+  printf ("%I64f", d); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64F", d); /* { dg-warning "unknown|format" "bad use of %I64F" } */
+  printf ("%I64e", d); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64E", d); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64g", d); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64G", d); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64a", d); /* { dg-warning "unknown|format" "bad use of %I64a" } */
+  printf ("%I64A", d); /* { dg-warning "unknown|format" "bad use of %I64A" } */
+  printf ("%I64c", i); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64s", s); /* { dg-warning "length" "bad use of %I64" } */
+  printf ("%I64p", p); /* { dg-warning "length" "bad use of %I64" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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% 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" } */
+  /* 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" } */
+  /* 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" } */
+  /* 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 ("%-08F", d); /* { dg-warning "unknown|format" "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 ("%-08a", d); /* { dg-warning "unknown|format" "0 flag ignored with - flag" } */
+  printf ("%-08A", d); /* { dg-warning "unknown|format" "0 flag ignored with - flag" } */
+  /* Various tests of bad argument types.  Mostly covered in c90-printf-1.c;
+     here just test for pointer target sign with %hhn.  (Probably allowed
+     by the standard, but a bad idea, so GCC should diagnose if what
+     is used is not signed char *.)
+  */
+  printf ("%hhn", s); /* { dg-warning "unknown|format" "%hhn is unsupported" } */
+  printf ("%hhn", us); /* { dg-warning "unknown|format" "%hhn is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-2.c
@@ -0,0 +1,33 @@
+/* Test for printf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, long long ll, size_t z, wint_t lc, wchar_t *ls)
+{
+  /* The length modifiers q, Z and L as applied to integer formats are
+     extensions.
+  */
+  printf ("%qd", ll); /* { dg-warning "unknown|format" "%q length is unsupported" } */
+  printf ("%Ld", ll); /* { dg-warning "unknown|format" "%L length is unsupported" } */
+  printf ("%Zd", z); /* { dg-warning "unknown|format" "%Z lengthis unsupported" } */
+  /* The conversion specifiers C and S are X/Open extensions; the
+     conversion specifier m is a GNU extension.
+  */
+  printf ("%m"); /* { dg-warning "unknown|format" "printf %m is unsupported" } */
+  printf ("%C", lc); /* { dg-warning "C" "printf %C" } */
+  printf ("%S", ls); /* { dg-warning "C" "printf %S" } */
+  /* The flag character ', and the use of operand number $ formats, are
+     X/Open extensions.
+  */
+  printf ("%'d", i); /* { dg-warning "C" "printf ' flag" } */
+  printf ("%1$d", i); /* { dg-warning "C" "printf $ format" } */
+  /* The flag character I is a GNU extension.  */
+  printf ("%Ix", z);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-printf-3.c
@@ -0,0 +1,40 @@
+/* Test for printf formats.  Test that the C99 functions get their default
+   attributes in strict C99 mode, but the gettext functions do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, char *s, size_t n, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5, va_list v6, va_list v7)
+{
+  fprintf (stdout, "%d", i);
+  fprintf (stdout, "%ld", i); /* { dg-warning "format" "fprintf" } */
+  printf ("%d", i);
+  printf ("%ld", i); /* { dg-warning "format" "printf" } */
+  /* The "unlocked" functions shouldn't warn in c99 mode.  */
+  fprintf_unlocked (stdout, "%ld", i);
+  printf_unlocked ("%ld", i);
+  sprintf (s, "%d", i);
+  sprintf (s, "%ld", i); /* { dg-warning "format" "sprintf" } */
+  snprintf (s, n, "%d", i);
+  snprintf (s, n, "%ld", i); /* { dg-warning "format" "snprintf" } */
+  vfprintf (stdout, "%d", v0);
+  vfprintf (stdout, "%Y", v1); /* { dg-warning "format" "vfprintf" } */
+  vprintf ("%d", v0);
+  vprintf ("%Y", v1); /* { dg-warning "format" "vprintf" } */
+  vsprintf (s, "%d", v0);
+  vsprintf (s, "%Y", v1); /* { dg-warning "format" "vsprintf" } */
+  vsnprintf (s, n, "%d", v0);
+  vsnprintf (s, n, "%Y", v1); /* { dg-warning "format" "vsnprintf" } */
+  printf (gettext ("%d"), i);
+  printf (gettext ("%ld"), (long) i);
+  printf (dgettext ("", "%d"), i);
+  printf (dgettext ("", "%ld"), (long) i);
+  printf (dcgettext ("", "%d", 0), i);
+  printf (dcgettext ("", "%ld", 0), (long) i);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-1.c
@@ -0,0 +1,75 @@
+/* Test for scanf formats.  Formats using C99 features, including cases
+   where C99 specifies some aspect of the format to be ignored or where
+   the behavior is undefined.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, unsigned int *uip, short int *hp, unsigned short int *uhp,
+     signed char *hhp, unsigned char *uhhp, long int *lp,
+     unsigned long int *ulp, float *fp, double *dp, long double *ldp, char *s,
+     void **pp, int *n, long long *llp, unsigned long long *ullp, wchar_t *ls,
+     short int *hn, signed char *hhn, long int *ln, long long int *lln,
+     intmax_t *jp, uintmax_t *ujp, intmax_t *jn, size_t *zp,
+     signed_size_t *szp, signed_size_t *zn, ptrdiff_t *tp,
+     unsigned_ptrdiff_t *utp, ptrdiff_t *tn)
+{
+  /* See ISO/IEC 9899:1999 (E) subclause 7.19.6.2 (pages 281-288).
+     We do not repeat here most of the checks for correct C90 formats
+     or completely broken formats.
+  */
+  /* Valid, invalid and silly assignment-suppression
+     and width constructions.
+  */
+  scanf ("%*d%*i%*o%*u%*x%*X%*e%*E%*f%*g%*G%*s%*[abc]%*c%*p");
+  scanf ("%*2d%*8s%*3c");
+  scanf ("%*n", n); /* { dg-warning "suppress" "suppression of %n" } */
+  scanf ("%*hd"); /* { dg-warning "together" "suppression with length" } */
+  scanf ("%2d%3i%4o%5u%6x%7X%10e%11E%12f%14g%15G%16s%3[abc]%4c%5p",
+	 ip, ip, uip, uip, uip, uip, fp, fp, fp, fp, fp,
+	 s, s, s, pp);
+  scanf ("%0d", ip); /* { dg-warning "width" "warning for zero width" } */
+  scanf ("%3n", n); /* { dg-warning "width" "width with %n" } */
+  /* Valid and invalid %h, %hh, %l, %I64, %j, %z, %t, %L constructions.  */
+  scanf ("%hd%hi%ho%hu%hx%hX%hn", hp, hp, uhp, uhp, uhp, uhp, hn);
+  scanf ("%he", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hE", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hf", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hg", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hG", fp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hs", hp);
+  scanf ("%h[ac]", s); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hc", (short *)s);
+  scanf ("%hp", pp); /* { dg-warning "length" "bad use of %h" } */
+  scanf ("%hhd", hhp); /* { dg-warning "unknown|format" "%hh is unsupported" } */
+  scanf ("%ld%li%lo%lu%lx%lX%ln", lp, lp, ulp, ulp, ulp, ulp, ln);
+  scanf ("%le%lE%lf%lg%lG", dp, dp, dp, dp, dp);
+  scanf ("%lp", pp); /* { dg-warning "length" "bad use of %l" } */
+  scanf ("%ls", ls);
+  scanf ("%l[ac]", ls);
+  scanf ("%lc", ls);
+  scanf ("%I64d%I64i%I64o%I64u%I64x%I64X%I64n", llp, llp, ullp, ullp, ullp, ullp,
+	 lln);
+  scanf ("%I64e", fp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64E", fp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64f", fp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64F", fp); /* { dg-warning "unknown|format" "'F' is unsupported" } */
+  scanf ("%I64g", fp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64G", fp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64s", s); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64[ac]", s); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64c", s); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%I64p", pp); /* { dg-warning "length" "bad use of %I64" } */
+  scanf ("%jd", jp); /* { dg-warning "unknown|format" "%j not supported" } */
+  scanf ("%zd", zp); /* { dg-warning "unknown|format" "%z not supported" } */
+  scanf ("%td", tp); /* { dg-warning "unknown|format" "%t not supported" } */
+  scanf ("%Lf", llp); /* { dg-warning "unknown|format" "bad use of %L is not supported" } */
+  /* Valid uses of each bare conversion.  */
+  scanf ("%d%i%o%u%x%X%e%E%f%g%G%s%[abc]%c%p%n%%", ip, ip, uip, uip, uip,
+         uip, fp, fp, fp, fp, fp, s, s, s, pp, n);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-2.c
@@ -0,0 +1,27 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, long long int *llp, wchar_t *ls)
+{
+  /* The length modifiers q and L as applied to integer formats are
+     extensions.
+  */
+  scanf ("%qd", llp); /* { dg-warning "unknown|format" "%q is unsupported" } */
+  scanf ("%Ld", llp); /* { dg-warning "unknown|format" "%L is unsupported" } */
+  /* The conversion specifiers C and S are X/Open extensions.  */
+  scanf ("%C", ls); /* { dg-warning "C" "scanf %C" } */
+  scanf ("%S", ls); /* { dg-warning "C" "scanf %S" } */
+  /* The use of operand number $ formats is an X/Open extension.  */
+  scanf ("%1$d", ip); /* { dg-warning "C" "scanf $ format" } */
+  /* glibc also supports flags ' and I on scanf formats as an extension.  */
+  scanf ("%'d", ip); /* { dg-warning "C" "scanf ' flag" } */
+  scanf ("%Id", (ssize_t *)ip);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-3.c
@@ -0,0 +1,33 @@
+/* Test for scanf formats.  Test that the C99 functions get their default
+   attributes in strict C99 mode, but the gettext functions do not.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int *ip, char *s, va_list v0, va_list v1, va_list v2, va_list v3,
+     va_list v4, va_list v5)
+{
+  fscanf (stdin, "%d", ip);
+  fscanf (stdin, "%ld", ip); /* { dg-warning "format" "fscanf" } */
+  scanf ("%d", ip);
+  scanf ("%ld", ip); /* { dg-warning "format" "scanf" } */
+  sscanf (s, "%d", ip);
+  sscanf (s, "%ld", ip); /* { dg-warning "format" "sscanf" } */
+  vfscanf (stdin, "%d", v0);
+  vfscanf (stdin, "%Y", v1); /* { dg-warning "format" "vfscanf" } */
+  vscanf ("%d", v2);
+  vscanf ("%Y", v3); /* { dg-warning "format" "vscanf" } */
+  vsscanf (s, "%d", v4);
+  vsscanf (s, "%Y", v5); /* { dg-warning "format" "vsscanf" } */
+  scanf (gettext ("%d"), ip);
+  scanf (gettext ("%ld"), ip);
+  scanf (dgettext ("", "%d"), ip);
+  scanf (dgettext ("", "%ld"), ip);
+  scanf (dcgettext ("", "%d", 0), ip);
+  scanf (dcgettext ("", "%ld", 0), ip);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-scanf-4.c
@@ -0,0 +1,20 @@
+/* Test for scanf formats.  Formats using extensions to the standard
+   should be rejected in strict pedantic mode.
+*/
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char **sp, wchar_t **lsp)
+{
+  /* m assignment-allocation modifier, recognized in both C90
+     and C99 modes, is a POSIX and ISO/IEC WDTR 24731-2 extension.  */
+  scanf ("%ms", sp); /* { dg-warning "unknown|format" "%ms is unsupported" } */
+  scanf ("%mS", lsp); /* { dg-warning "unknown|format" "%mS is unsupported" } */
+  scanf ("%mls", lsp); /* { dg-warning "unknown|format" "%mls is unsupported" } */
+  scanf ("%m[bcd]", sp); /* { dg-warning "unknown|format" "%m[] is unsupported" } */
+  scanf ("%ml[bcd]", lsp); /* { dg-warning "unknown|format" "%ml[] is unsupported" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-1.c
@@ -0,0 +1,30 @@
+/* Test for strftime formats.  Formats using C99 features.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat -Wformat-y2k" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.12.3.5 (pages 174-175).  */
+  /* Formats which are Y2K-compliant (no 2-digit years).  */
+  strftime (s, m, "%a%A%b%B%d%H%I%j%m%M%p%S%U%w%W%X%Y%z%Z%%", tp);
+  strftime (s, m, "%EX%EY%Od%OH%OI%Om%OM%OS%OU%Ow%OW", tp);
+  /* Formats with 2-digit years.  */
+  strftime (s, m, "%D", tp); /* { dg-warning "unknown" "2-digit year unsupported" } */
+  strftime (s, m, "%g", tp); /* { dg-warning "unknown" "2-digit year unsupported" } */
+  strftime (s, m, "%y", tp); /* { dg-warning "only last 2" "2-digit year" } */
+  strftime (s, m, "%Oy", tp); /* { dg-warning "only last 2" "2-digit year" } */
+  /* Formats with 2-digit years in some locales.  */
+  strftime (s, m, "%c", tp); /* { dg-warning "some locales" "2-digit year" } */
+  strftime (s, m, "%Ec", tp); /* { dg-warning "some locales" "2-digit year" } */
+  strftime (s, m, "%x", tp); /* { dg-warning "some locales" "2-digit year" } */
+  strftime (s, m, "%Ex", tp); /* { dg-warning "some locales" "2-digit year" } */
+  /* %Ey is explicitly an era offset not a 2-digit year; but in some
+     locales the E modifier may be ignored.
+  */
+  strftime (s, m, "%Ey", tp); /* { dg-warning "some locales" "2-digit year" } */
+  }
Index: gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_c99-strftime-2.c
@@ -0,0 +1,24 @@
+/* Test for strftime formats.  Rejection of extensions in pedantic mode.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1999 -pedantic -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  /* %P is a lowercase version of %p.  */
+  strftime (s, m, "%P", tp); /* { dg-warning "unknown" "strftime %P" } */
+  /* %k is %H but padded with a space rather than 0 if necessary.  */
+  strftime (s, m, "%k", tp); /* { dg-warning "unknown" "strftime %k" } */
+  /* %l is %I but padded with a space rather than 0 if necessary.  */
+  strftime (s, m, "%l", tp); /* { dg-warning "unknown" "strftime %l" } */
+  /* %s is the number of seconds since the Epoch.  */
+  strftime (s, m, "%s", tp); /* { dg-warning "unknown" "strftime %s" } */
+  /* Extensions using %O already tested in c99-strftime-1.c.  */
+  /* Width and flags are GNU extensions for strftime.  */
+  strftime (s, m, "%20Y", tp); /* { dg-warning "C" "strftime width" } */
+  strftime (s, m, "%^A", tp); /* { dg-warning "C" "strftime flags" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_cast-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_cast-1.c
@@ -0,0 +1,17 @@
+/* Test for strings cast through integer types: should not be treated
+   as format strings unless the types are of the same width as
+   pointers (intptr_t or similar).  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+f (int x)
+{
+  printf("%s", x); /* { dg-warning "format" } */
+  printf((char *)(size_t)"%s", x); /* { dg-warning "format" } */
+  printf((char *)(char)"%s", x); /* { dg-warning "cast from pointer to integer of different size" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-1.c
@@ -0,0 +1,40 @@
+/* Test for warnings for missing format attributes.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  vprintf (fmt, ap); /* { dg-warning "candidate" "printf attribute warning" } */
+  va_end (ap);
+}
+
+void
+bar (const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  vscanf (fmt, ap); /* { dg-warning "candidate" "scanf attribute warning" } */
+  va_end (ap);
+}
+
+__attribute__((__format__(__ms_printf__, 1, 2))) void
+foo2 (const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  vprintf (fmt, ap);
+  va_end (ap);
+}
+
+void
+vfoo (const char *fmt, va_list arg)
+{
+  vprintf (fmt, arg); /* { dg-warning "candidate" "printf attribute warning 2" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-2.c
@@ -0,0 +1,17 @@
+/* Test for warnings for missing format attributes.  Don't warn if no
+   relevant parameters for a format attribute; see c/1017.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, ...)
+{
+  va_list ap;
+  va_start (ap, i);
+  vprintf ("Foo %s bar %s", ap); /* { dg-bogus "candidate" "bogus printf attribute warning" } */
+  va_end (ap);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-3.c
@@ -0,0 +1,27 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+void
+foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
+{
+  noattr_t na1 = na;
+  noattr_t na2 = a; /* { dg-warning "candidate" "initialization warning" } */
+  attr_t a1 = na;
+  attr_t a2 = a;
+
+  vnoattr_t vna1 = vna;
+  vnoattr_t vna2 = va; /* { dg-warning "candidate" "initialization warning" } */
+  vattr_t va1 = vna;
+  vattr_t va2 = va;
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-4.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-4.c
@@ -0,0 +1,33 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+void
+foo1 (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
+{
+  noattr_t na1, na2;
+  attr_t a1, a2;
+
+  vnoattr_t vna1, vna2;
+  vattr_t va1, va2;
+
+  na1 = na;
+  na2 = a; /* { dg-warning "candidate" "assignment warning" } */
+  a1 = na;
+  a2 = a;
+
+  vna1 = vna;
+  vna2 = va; /* { dg-warning "candidate" "assignment warning" } */
+  va1 = vna;
+  va1 = va;
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-5.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-5.c
@@ -0,0 +1,49 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+noattr_t
+foo1 (noattr_t na, attr_t a, int i)
+{
+  if (i)
+    return na;
+  else
+    return a; /* { dg-warning "candidate" "return type warning" } */
+}
+
+attr_t
+foo2 (noattr_t na, attr_t a, int i)
+{
+  if (i)
+    return na;
+  else
+    return a;
+}
+
+vnoattr_t
+foo3 (vnoattr_t vna, vattr_t va, int i)
+{
+  if (i)
+    return vna;
+  else
+    return va; /* { dg-warning "candidate" "return type warning" } */
+}
+
+vattr_t
+foo4 (vnoattr_t vna, vattr_t va, int i)
+{
+  if (i)
+    return vna;
+  else
+    return va;
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_miss-6.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_miss-6.c
@@ -0,0 +1,32 @@
+/* Test warnings for missing format attributes on function pointers.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wmissing-format-attribute" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+typedef void (*noattr_t) (const char *, ...);
+typedef noattr_t __attribute__ ((__format__(__ms_printf__, 1, 2))) attr_t;
+
+typedef void (*vnoattr_t) (const char *, va_list);
+typedef vnoattr_t __attribute__ ((__format__(__ms_printf__, 1, 0))) vattr_t;
+
+extern void foo1 (noattr_t);
+extern void foo2 (attr_t);
+extern void foo3 (vnoattr_t);
+extern void foo4 (vattr_t);
+
+void
+foo (noattr_t na, attr_t a, vnoattr_t vna, vattr_t va)
+{
+  foo1 (na);
+  foo1 (a); /* { dg-warning "candidate" "parameter passing warning" } */
+  foo2 (na);
+  foo2 (a);
+
+  foo3 (vna);
+  foo3 (va); /* { dg-warning "candidate" "parameter passing warning" } */
+  foo4 (vna);
+  foo4 (va);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_multattr-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_multattr-1.c
@@ -0,0 +1,51 @@
+/* Test for multiple format attributes.  Test for printf and scanf attributes
+   together.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* If we specify multiple attributes for a single function, they should
+   all apply.  This should apply whether they are on the same declaration
+   or on different declarations.  */
+
+extern void my_vprintf_scanf (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_printf__, 1, 0)))
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern void my_vprintf_scanf2 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)))
+     __attribute__((__format__(__ms_printf__, 1, 0)));
+
+extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_printf__, 1, 0)));
+extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_printf__, 1, 0)));
+
+void
+foo (va_list ap, int *ip, long *lp)
+{
+  my_vprintf_scanf ("%d", ap, "%d", ip);
+  my_vprintf_scanf ("%d", ap, "%ld", lp);
+  my_vprintf_scanf ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf2 ("%d", ap, "%d", ip);
+  my_vprintf_scanf2 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf2 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf2 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf3 ("%d", ap, "%d", ip);
+  my_vprintf_scanf3 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf3 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf3 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf4 ("%d", ap, "%d", ip);
+  my_vprintf_scanf4 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf4 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf4 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_multattr-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_multattr-2.c
@@ -0,0 +1,40 @@
+/* Test for multiple format attributes.  Test for printf and scanf attributes
+   together, in different places on the declarations.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* If we specify multiple attributes for a single function, they should
+   all apply, wherever they are placed on the declarations.  */
+
+extern __attribute__((__format__(__ms_printf__, 1, 0))) void
+     my_vprintf_scanf (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern void (__attribute__((__format__(__ms_printf__, 1, 0))) my_vprintf_scanf2)
+     (const char *, va_list, const char *, ...)
+     __attribute__((__format__(__ms_scanf__, 3, 4)));
+
+extern __attribute__((__format__(__ms_scanf__, 3, 4))) void
+     (__attribute__((__format__(__ms_printf__, 1, 0))) my_vprintf_scanf3)
+     (const char *, va_list, const char *, ...);
+
+void
+foo (va_list ap, int *ip, long *lp)
+{
+  my_vprintf_scanf ("%d", ap, "%d", ip);
+  my_vprintf_scanf ("%d", ap, "%ld", lp);
+  my_vprintf_scanf ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf2 ("%d", ap, "%d", ip);
+  my_vprintf_scanf2 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf2 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf2 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+  my_vprintf_scanf3 ("%d", ap, "%d", ip);
+  my_vprintf_scanf3 ("%d", ap, "%ld", lp);
+  my_vprintf_scanf3 ("%", ap, "%d", ip); /* { dg-warning "format" "printf" } */
+  my_vprintf_scanf3 ("%d", ap, "%ld", ip); /* { dg-warning "format" "scanf" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_multattr-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_multattr-3.c
@@ -0,0 +1,29 @@
+/* Test for multiple format_arg attributes.  Test for both branches
+   getting checked.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+extern char *ngettext (const char *, const char *, unsigned long int)
+     __attribute__((__format_arg__(1))) __attribute__((__format_arg__(2)));
+
+void
+foo (long l, int nfoo)
+{
+  printf (ngettext ("%d foo", "%d foos", nfoo), nfoo);
+  printf (ngettext ("%d foo", "%d foos", l), l); /* { dg-warning "int" "wrong type in conditional expr" } */
+  printf (ngettext ("%d foo", "%ld foos", l), l); /* { dg-warning "int" "wrong type in conditional expr" } */
+  printf (ngettext ("%ld foo", "%d foos", l), l); /* { dg-warning "int" "wrong type in conditional expr" } */
+  /* Should allow one case to have extra arguments.  */
+  printf (ngettext ("1 foo", "%d foos", nfoo), nfoo);
+  printf (ngettext ("1 foo", "many foos", nfoo), nfoo); /* { dg-warning "too many" "too many args in all branches" } */
+  printf (ngettext ("", "%d foos", nfoo), nfoo);
+  printf (ngettext ("1 foo", (nfoo > 0) ? "%d foos" : "no foos", nfoo), nfoo);
+  printf (ngettext ("%d foo", (nfoo > 0) ? "%d foos" : "no foos", nfoo), nfoo);
+  printf (ngettext ("%ld foo", (nfoo > 0) ? "%d foos" : "no foos", nfoo), nfoo); /* { dg-warning "long int" "wrong type" } */
+  printf (ngettext ("%d foo", (nfoo > 0) ? "%ld foos" : "no foos", nfoo), nfoo); /* { dg-warning "long int" "wrong type" } */
+  printf (ngettext ("%d foo", (nfoo > 0) ? "%d foos" : "%ld foos", nfoo), nfoo); /* { dg-warning "long int" "wrong type" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-1.c
@@ -0,0 +1,15 @@
+/* Test for warnings for extra format arguments being disabled by
+   -Wno-format-extra-args.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wno-format-extra-args" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i)
+{
+  printf ("foo", i);
+  printf ("%1$d", i, i);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_no-exargs-2.c
@@ -0,0 +1,28 @@
+/* Test for warnings for extra format arguments being disabled by
+   -Wno-format-extra-args.  Test which warnings still apply with $
+   operand numbers.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wno-format-extra-args" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i, int *ip, va_list va)
+{
+  printf ("%3$d%1$d", i, i, i); /* { dg-warning "before used" "unused $ operand" } */
+  printf ("%2$d%1$d", i, i, i);
+  vprintf ("%3$d%1$d", va); /* { dg-warning "before used" "unused $ operand" } */
+  /* With scanf formats, gaps in the used arguments are allowed only if the
+     arguments are all pointers.  In such a case, should only give the lesser
+     warning about unused arguments rather than the more serious one about
+     argument gaps.  */
+  scanf ("%3$d%1$d", ip, ip, ip);
+  /* If there are non-pointer arguments unused at the end, this is also OK.  */
+  scanf ("%3$d%1$d", ip, ip, ip, i);
+  scanf ("%3$d%1$d", ip, i, ip); /* { dg-warning "before used" "unused $ scanf non-pointer operand" } */
+  /* Can't check the arguments in the vscanf case, so should suppose the
+     lesser problem.  */
+  vscanf ("%3$d%1$d", va);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_no-y2k-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_no-y2k-1.c
@@ -0,0 +1,13 @@
+/* Test for warnings for Y2K problems not being on by default.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp)
+{
+  strftime (s, m, "%y%c%x", tp);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-1.c
@@ -0,0 +1,14 @@
+/* Test for warnings for non-string-literal formats.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wformat-nonliteral" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t i)
+{
+  printf ((const char *)i, i); /* { dg-warning "argument types" "non-literal" } */
+  printf (s, i); /* { dg-warning "argument types" "non-literal" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-2.c
@@ -0,0 +1,14 @@
+/* Test for warnings for non-string-literal formats.  Test with -Wformat=2.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat=2" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t i)
+{
+  printf ((const char *)i, i); /* { dg-warning "argument types" "non-literal" } */
+  printf (s, i); /* { dg-warning "argument types" "non-literal" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-3.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nonlit-3.c
@@ -0,0 +1,13 @@
+/* Test for warnings for non-string-literal formats.  Test for strftime formats.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wformat-nonliteral" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s, size_t m, const struct tm *tp, char *fmt)
+{
+  strftime (s, m, fmt, tp); /* { dg-warning "format string" "non-literal" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nul-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nul-1.c
@@ -0,0 +1,15 @@
+/* Test diagnostics for suppressing contains nul
+   -Wformat.  -Wformat.  */
+/* Origin: Bruce Korb <bkorb@gnu.org> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat -Wno-format-contains-nul" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (void)
+{
+  static char const fmt[] = "x%s\0%s\n\0abc";
+  printf (fmt+4, fmt+8); /* { dg-bogus "embedded.*in format" "bogus embed warning" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_nul-2.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_nul-2.c
@@ -0,0 +1,17 @@
+/* Test diagnostics for options used on their own without
+   -Wformat.  -Wformat-.  */
+/* Origin: Bruce Korb <bkorb@gnu.org> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+
+/* { dg-warning "embedded .* in format" "ignored" { target *-*-* } 0 } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+fumble (void)
+{
+  static char const fmt[] = "x%s\0%s\n\0abc";
+  printf (fmt+4, fmt+8);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_null-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_null-1.c
@@ -0,0 +1,28 @@
+/* Test for some aspects of null format string handling.  */
+/* Origin: Jason Thorpe <thorpej@wasabisystems.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+extern void my_printf (const char *, ...) __attribute__((format(ms_printf,1,2)));
+extern const char *my_format (const char *, const char *)
+  __attribute__((format_arg(2)));
+
+void
+foo (int i1)
+{
+  /* Warning about a null format string has been decoupled from the actual
+     format check.  However, we still expect to be warned about any excess
+     arguments after a null format string.  */
+  my_printf (NULL);
+  my_printf (NULL, i1); /* { dg-warning "too many" "null format with arguments" } */
+
+  my_printf (my_format ("", NULL));
+  my_printf (my_format ("", NULL), i1); /* { dg-warning "too many" "null format_arg with arguments" } */
+
+  /* While my_printf allows a null argument, dgettext does not, so we expect
+     a null argument warning here.  */
+  my_printf (dgettext ("", NULL)); /* { dg-warning "null" "null format with dgettext" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_plus-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_plus-1.c
@@ -0,0 +1,21 @@
+/* Test for printf formats using string literal plus constant.
+ */
+/* Origin: Jakub Jelinek <jakub@redhat.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat=2" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (int i)
+{
+  printf ("%%d\n" + 1, i);
+  printf (5 + "%.-*d%3d\n", i);
+  printf ("%d%d" + 2, i, i);	/* { dg-warning "arguments" "wrong number of args" } */
+  printf (3 + "%d\n");		/* { dg-warning "zero-length" "zero-length string" } */
+  printf ("%d\n" + i, i);	/* { dg-warning "not a string" "non-constant addend" } */
+  printf ("%d\n" + 10);		/* { dg-warning "not a string" "too large addend" } */
+  printf ("%d\n" - 1, i);	/* { dg-warning "not a string" "minus constant" } */
+  printf ("%d\n" + -1, i);	/* { dg-warning "not a string" "negative addend" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_sec-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_sec-1.c
@@ -0,0 +1,13 @@
+/* Test for security warning when non-literal format has no arguments.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=gnu99 -Wformat -Wformat-security" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (char *s)
+{
+  printf (s); /* { dg-warning "no format arguments" "security warning" } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_unnamed-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_unnamed-1.c
@@ -0,0 +1,24 @@
+/* Test for warnings with possibly unnamed integer types.  Bug 24329.  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+/* { dg-options "-Wformat -msse" { target { { i?86-*-* x86_64-*-* } && ilp32 } } } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+/* Definition of TItype follows same logic as in gcc.dg/titype-1.c,
+   but must be a #define to avoid giving the type a name.  */
+#if defined(__LP64__) && !defined(__hppa__)
+#define TItype int __attribute__ ((mode (TI)))
+#else
+#define TItype long
+#endif
+
+void
+f (TItype x)
+{
+  printf("%d", x); /* { dg-warning "expects type" } */
+  printf("%d", 141592653589793238462643383279502884197169399375105820974944); /* { dg-warning "expects type" } */
+  /* { dg-warning "unsigned only|too large" "constant" { target *-*-* } 22 } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_va-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_va-1.c
@@ -0,0 +1,14 @@
+/* Test for strange warning in format checking.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-Wformat" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (void *p)
+{
+  printf ("%d", p); /* { dg-bogus "va_list" "wrong type in format warning" } */
+  /* { dg-warning "format" "format error" { target *-*-* } 12 } */
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_warnll-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_warnll-1.c
@@ -0,0 +1,19 @@
+/* Test for printf formats.  C99 "long long" formats should be accepted with
+   -Wno-long-long.
+*/
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wno-long-long" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (long long ll, unsigned long long ull, long long *lln,
+     long long *llp, unsigned long long *ullp)
+{
+  /* Test for accepting standard "long long" formats.  */
+  printf ("%I64d%I64i%I64o%I64u%I64x%I64X%I64n", ll, ll, ull, ull, ull, ull, lln);
+  scanf ("%I64d%I64i%I64o%I64u%I64x%I64X%I64n", llp, llp,
+	 ullp, ullp, ullp, ullp, lln);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/ms_zero-length-1.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/ms_zero-length-1.c
@@ -0,0 +1,16 @@
+/* Test the -Wno-format-zero-length option, which suppresses warnings
+   about zero-length formats.  */
+/* Origin: Jason Thorpe <thorpej@wasabisystems.com> */
+/* { dg-do compile { target { *-*-mingw* } } } */
+/* { dg-options "-std=iso9899:1990 -pedantic -Wformat -Wno-format-zero-length" } */
+
+#define USE_SYSTEM_FORMATS
+#include "format.h"
+
+void
+foo (void)
+{
+  /* See ISO/IEC 9899:1990 (E) subclause 7.9.6.1 (pages 131-134).  */
+  /* Zero-length format strings are allowed.  */
+  printf ("");
+}
Index: gcc/gcc/testsuite/gcc.dg/format/multattr-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/multattr-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/multattr-1.c
@@ -4,6 +4,7 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 /* If we specify multiple attributes for a single function, they should
@@ -11,22 +12,22 @@
    or on different declarations.  */
 
 extern void my_vprintf_scanf (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__printf__, 1, 0)))
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)))
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
 extern void my_vprintf_scanf2 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)))
-     __attribute__((__format__(__printf__, 1, 0)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)))
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)));
 
 extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__printf__, 1, 0)));
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)));
 extern void my_vprintf_scanf3 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
 extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 extern void my_vprintf_scanf4 (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__printf__, 1, 0)));
+     __attribute__((__format__(gnu_attr___printf__, 1, 0)));
 
 void
 foo (va_list ap, int *ip, long *lp)
Index: gcc/gcc/testsuite/gcc.dg/format/multattr-2.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/multattr-2.c
+++ gcc/gcc/testsuite/gcc.dg/format/multattr-2.c
@@ -4,21 +4,22 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
 /* If we specify multiple attributes for a single function, they should
    all apply, wherever they are placed on the declarations.  */
 
-extern __attribute__((__format__(__printf__, 1, 0))) void
+extern __attribute__((__format__(gnu_attr___printf__, 1, 0))) void
      my_vprintf_scanf (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
-extern void (__attribute__((__format__(__printf__, 1, 0))) my_vprintf_scanf2)
+extern void (__attribute__((__format__(gnu_attr___printf__, 1, 0))) my_vprintf_scanf2)
      (const char *, va_list, const char *, ...)
-     __attribute__((__format__(__scanf__, 3, 4)));
+     __attribute__((__format__(gnu_attr___scanf__, 3, 4)));
 
-extern __attribute__((__format__(__scanf__, 3, 4))) void
-     (__attribute__((__format__(__printf__, 1, 0))) my_vprintf_scanf3)
+extern __attribute__((__format__(gnu_attr___scanf__, 3, 4))) void
+     (__attribute__((__format__(gnu_attr___printf__, 1, 0))) my_vprintf_scanf3)
      (const char *, va_list, const char *, ...);
 
 void
Index: gcc/gcc/testsuite/gcc.dg/format/null-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/null-1.c
+++ gcc/gcc/testsuite/gcc.dg/format/null-1.c
@@ -3,9 +3,10 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu99 -Wformat" } */
 
+#define DONT_GNU_PROTOTYPE
 #include "format.h"
 
-extern void my_printf (const char *, ...) __attribute__((format(printf,1,2)));
+extern void my_printf (const char *, ...) __attribute__((format(gnu_attr_printf,1,2)));
 extern const char *my_format (const char *, const char *)
   __attribute__((format_arg(2)));
 
=

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf      formatters to c-format.c
  2008-01-08 14:37                       ` Kai Tietz
@ 2008-01-08 18:18                         ` Joseph S. Myers
  2008-01-15 16:45                           ` Kai Tietz
  0 siblings, 1 reply; 61+ messages in thread
From: Joseph S. Myers @ 2008-01-08 18:18 UTC (permalink / raw)
  To: Kai Tietz; +Cc: Danny Smith, GCC Patches, NightStrike

On Tue, 8 Jan 2008, Kai Tietz wrote:

>         * gcc/testsuite/gcc.dg/format/format.h: Add for mingw the gnu 
> style printf prototypes.
> 
> Do you think it is ok for apply ?

The general approach is plausible, but the patch still needs full test 
coverage for the MinGW formats before it's ready for review.  Every C90, 
C99, X/Open or GNU format feature not present on Windows should have a 
MinGW-specific test assertion added to the testsuite that the use of that 
feature is diagnosed, which every such feature present on Windows should 
have a MinGW-specific test assertion added that the feature is not 
diagnosed.  (The effect should be that every entry in the MinGW format 
datastructures is tested, and every difference from the GNU format 
datastructures.)  When you have a patch ready with such tests, please 
confirm that all the format tests pass cleanly with it applied for both 
MinGW and non-MinGW targets; then it will be ready for review.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf     formatters to c-format.c
  2008-01-07 14:44                     ` Joseph S. Myers
  2008-01-07 16:26                       ` Kai Tietz
@ 2008-01-08 14:37                       ` Kai Tietz
  2008-01-08 18:18                         ` Joseph S. Myers
  1 sibling, 1 reply; 61+ messages in thread
From: Kai Tietz @ 2008-01-08 14:37 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: Danny Smith, GCC Patches, NightStrike

[-- Attachment #1: Type: text/plain, Size: 1044 bytes --]

Hi Joseph,

I modified - as we spoke about - the format.h defaulting for mingw to use 
the ..._gnu function prototypes.

Changed to prior:

        * gcc/testsuite/gcc.dg/format/format.h: Add for mingw the gnu 
style printf prototypes.

Do you think it is ok for apply ?

Cheers,
 i.A. Kai Tietz



|  (\_/)  This is Bunny. Copy and paste Bunny
| (='.'=) into your signature to help him gain
| (")_(") world domination.

------------------------------------------------------------------------------------------
  OneVision Software Entwicklungs GmbH & Co. KG
  Dr.-Leo-Ritter-Straße 9 - 93049 Regensburg
  Tel: +49.(0)941.78004.0 - Fax: +49.(0)941.78004.489 - www.OneVision.com
  Commerzbank Regensburg - BLZ 750 400 62 - Konto 6011050
  Handelsregister: HRA 6744, Amtsgericht Regensburg
  Komplementärin: OneVision Software Entwicklungs Verwaltungs GmbH
  Dr.-Leo-Ritter-Straße 9 – 93049 Regensburg
  Handelsregister: HRB 8932, Amtsgericht Regensburg - Geschäftsführer: 
Ulrike Döhler, Manuela Kluger


[-- Attachment #2: mingw-msformat.txt --]
[-- Type: text/plain, Size: 27642 bytes --]

Index: gcc/gcc/c-format.c
===================================================================
--- gcc.orig/gcc/c-format.c
+++ gcc/gcc/c-format.c
@@ -80,7 +80,8 @@ static bool check_format_string (tree ar
 				 int flags, bool *no_add_attrs);
 static bool get_constant (tree expr, unsigned HOST_WIDE_INT *value,
 			  int validated_p);
-
+static const char *replace_formatter_name_to_system_name (const char *attr_name);
+static int compare_tofa (const char *tattr_name, const char *attr_name);
 
 /* Handle a "format_arg" attribute; arguments as in
    struct attribute_spec.handler.  */
@@ -191,6 +192,8 @@ decode_format_attr (tree args, function_
     {
       const char *p = IDENTIFIER_POINTER (format_type_id);
 
+      p = replace_formatter_name_to_system_name (p);
+
       info->format_type = decode_format_type (p);
 
       if (info->format_type == format_type_error)
@@ -715,7 +718,7 @@ static const format_char_info monetary_c
 /* This must be in the same order as enum format_type.  */
 static const format_kind_info format_types_orig[] =
 {
-  { "printf",   printf_length_specs,  print_char_table, " +#0-'I", NULL,
+  { "gnu_printf",   printf_length_specs,  print_char_table, " +#0-'I", NULL,
     printf_flag_specs, printf_flag_pairs,
     FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
     'w', 0, 'p', 0, 'L', 0,
@@ -757,18 +760,18 @@ static const format_kind_info format_typ
     0, 0, 0, 0, 0, 0,
     NULL, NULL
   },
-  { "scanf",    scanf_length_specs,   scan_char_table,  "*'I", NULL,
+  { "gnu_scanf",    scanf_length_specs,   scan_char_table,  "*'I", NULL,
     scanf_flag_specs, scanf_flag_pairs,
     FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
     'w', 0, 0, '*', 'L', 'm',
     NULL, NULL
   },
-  { "strftime", NULL,                 time_char_table,  "_-0^#", "EO",
+  { "gnu_strftime", NULL,                 time_char_table,  "_-0^#", "EO",
     strftime_flag_specs, strftime_flag_pairs,
     FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0, 0,
     NULL, NULL
   },
-  { "strfmon",  strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
+  { "gnu_strfmon",  strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
     strfmon_flag_specs, strfmon_flag_pairs,
     FMT_FLAG_ARG_CONVERT, 'w', '#', 'p', 0, 'L', 0,
     NULL, NULL
@@ -847,6 +850,7 @@ decode_format_type (const char *s)
 {
   int i;
   int slen;
+  s = replace_formatter_name_to_system_name (s);
   slen = strlen (s);
   for (i = 0; i < n_format_types; i++)
     {
@@ -1776,7 +1780,22 @@ check_format_info_main (format_check_res
       if (fli)
 	{
 	  while (fli->name != 0 && fli->name[0] != *format_chars)
-	    fli++;
+	    {
+	      if (fli->name[0] == '\0')
+		{
+		  int si  = strlen (fli->name + 1) + 1;
+		  int i = 1;
+		  while (fli->name[i] != 0 && fli->name[i] == format_chars [i - 1])
+		    ++i;
+		 if (si == i)
+		   {
+		     if (si > 2)
+		       format_chars += si - 2;
+		     break;
+		   }
+	       }
+	      fli++;
+	    }
 	  if (fli->name != 0)
 	    {
 	      format_chars++;
@@ -2703,6 +2722,72 @@ init_dynamic_diag_info (void)
 extern const format_kind_info TARGET_FORMAT_TYPES[];
 #endif
 
+#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+extern const target_ovr_attr TARGET_OVERRIDES_FORMAT_ATTRIBUTES[];
+#endif
+
+/* Description of gnu specific format attributes reflected to
+   system format attribute types, as printf, scanf, strftime, and
+   strfmon.  */
+const target_ovr_attr gnu_target_overrides_format_attributes[] =
+{
+  { "gnu_printf",   "printf" },
+  { "gnu_scanf",    "scanf" },
+  { "gnu_strftime", "strftime" },
+  { "gnu_strfmon",  "strfmon" },
+  { NULL,           NULL }
+};
+
+static const char *
+replace_formatter_name_to_system_name (const char *attr_name)
+{
+  int i;
+
+  if (attr_name == NULL || *attr_name == 0 || strncmp (attr_name, "gcc_", 4) == 0)
+    return attr_name;
+
+#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+  /* Check if format attribute is overridden by target.  */
+  if (TARGET_OVERRIDES_FORMAT_ATTRIBUTES != NULL && TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT > 0)
+    {
+      for (i = 0; i < TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT; ++i)
+        {
+          if (compare_tofa (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src, attr_name))
+            return attr_name;
+          if (compare_tofa (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_dst, attr_name))
+            return TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src;
+        }
+    }
+#endif
+  /* Otherwise default to gnu formatter.  */
+  for (i = 0; gnu_target_overrides_format_attributes[i].named_attr_src != NULL; ++i)
+    {
+      if (compare_tofa (gnu_target_overrides_format_attributes[i].named_attr_src, attr_name))
+        return attr_name;
+      if (compare_tofa (gnu_target_overrides_format_attributes[i].named_attr_dst, attr_name))
+        return gnu_target_overrides_format_attributes[i].named_attr_src;
+    }
+
+  return attr_name;
+}
+
+/* Compare the target override format attribute by treating double underscore syntax.  */
+static int
+compare_tofa (const char *tattr_name, const char *attr_name)
+{
+  int alen = strlen (attr_name);
+  int slen = (tattr_name ? strlen (tattr_name) : 0);
+  if (alen > 4 && attr_name[0] == '_' && attr_name[1] == '_'
+      && attr_name[alen - 1] == '_' && attr_name[alen - 2] == '_')
+    {
+      attr_name += 2;
+      alen -= 4;
+    }
+  if (alen != slen || strncmp (tattr_name, attr_name, alen) != 0)
+    return 0;
+  return 1;
+}
+
 /* Handle a "format" attribute; arguments as in
    struct attribute_spec.handler.  */
 tree
Index: gcc/gcc/c-format.h
===================================================================
--- gcc.orig/gcc/c-format.h
+++ gcc/gcc/c-format.h
@@ -306,4 +306,18 @@ typedef struct
 #define T_D128  &dfloat128_type_node
 #define TEX_D128 { STD_EXT, "_Decimal128", T_D128 }
 
+/* Structure describing the target specific to be override formatter
+   attributes, e.g. printf, scanf, etc.  This allows to support different
+   runtime-library specific formatter attributes to co-exist and defining
+   a default system version.
+   This type is used for the pointer variable TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+   refers to.  */
+typedef struct
+{
+  /* The name of the to be copied formatter attribute. */
+  const char *named_attr_src;
+  /* The name of the to be overridden formatter attribute. */
+  const char *named_attr_dst;
+} target_ovr_attr;
+
 #endif /* GCC_C_FORMAT_H */
Index: gcc/gcc/config.gcc
===================================================================
--- gcc.orig/gcc/config.gcc
+++ gcc/gcc/config.gcc
@@ -1359,8 +1359,8 @@ i[34567]86-*-pe | i[34567]86-*-cygwin*)
 	target_gtfiles="\$(srcdir)/config/i386/winnt.c"
 	extra_options="${extra_options} i386/cygming.opt"
 	extra_objs="winnt.o winnt-stubs.o"
-	c_target_objs=cygwin2.o
-	cxx_target_objs="cygwin2.o winnt-cxx.o"
+	c_target_objs="cygwin2.o msformat-c.o"
+	cxx_target_objs="cygwin2.o winnt-cxx.o msformat-c.o"
 	extra_gcc_objs=cygwin1.o
 	if test x$enable_threads = xyes; then
 		thread_file='posix'
@@ -1373,7 +1373,8 @@ i[34567]86-*-mingw32* | x86_64-*-mingw32
 	target_gtfiles="\$(srcdir)/config/i386/winnt.c"
 	extra_options="${extra_options} i386/cygming.opt"
 	extra_objs="winnt.o winnt-stubs.o"
-	cxx_target_objs=winnt-cxx.o
+	c_target_objs="msformat-c.o"
+	cxx_target_objs="winnt-cxx.o msformat-c.o"
 	default_use_cxa_atexit=yes
 	case ${enable_threads} in
 	  "" | yes | win32)
Index: gcc/gcc/config/i386/mingw32.h
===================================================================
--- gcc.orig/gcc/config/i386/mingw32.h
+++ gcc/gcc/config/i386/mingw32.h
@@ -143,6 +143,22 @@ do {						         \
    to register C++ static destructors.  */
 #define TARGET_CXX_USE_ATEXIT_FOR_CXA_ATEXIT hook_bool_void_true
 
+/* Contains a pointer to type target_ovr_attr defining the target specific
+   overrides of formatter attributs.  See format.h for structure definition.  */
+#undef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+#define TARGET_OVERRIDES_FORMAT_ATTRIBUTES mingw_formatter_attribute_overrides
+
+/* Specify the count of elements in TARGET_OVERRIDES_ATTRIBUTE.  */
+#undef TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT
+#define TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT 3
+
+/* MS specific format attributes for ms_printf, ms_scanf, ms_strftime.  */
+#undef TARGET_FORMAT_TYPES
+#define TARGET_FORMAT_TYPES mingw_formatter_attributes
+
+#undef TARGET_N_FORMAT_TYPES
+#define TARGET_N_FORMAT_TYPES 3
+
 /* JCR_SECTION works on mingw32.  */
 #undef TARGET_USE_JCR_SECTION
 #define TARGET_USE_JCR_SECTION 1
Index: gcc/gcc/config/i386/msformat-c.c
===================================================================
--- /dev/null
+++ gcc/gcc/config/i386/msformat-c.c
@@ -0,0 +1,189 @@
+/* Check calls to formatted I/O functions (-Wformat).
+   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+   2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "flags.h"
+#include "c-common.h"
+#include "toplev.h"
+#include "intl.h"
+#include "diagnostic.h"
+#include "langhooks.h"
+#include "c-format.h"
+#include "alloc-pool.h"
+
+/* Mingw specific format attributes ms_printf, ms_scanf, and ms_strftime.  */
+
+static const format_length_info ms_printf_length_specs[] =
+{
+  { "h", FMT_LEN_h, STD_C89, NULL, 0, 0 },
+  { "l", FMT_LEN_l, STD_C89, NULL, 0, 0 },
+  { "\0I32", FMT_LEN_l, STD_C89, NULL, 0, 0 },
+  { "\0I64", FMT_LEN_ll, STD_C9L, NULL, 0, 0 },
+  { "I", FMT_LEN_L, STD_C89, NULL, 0, 0 },
+  { NULL, 0, 0, NULL, 0, 0 }
+};
+
+static const format_flag_spec ms_printf_flag_specs[] =
+{
+  { ' ',  0, 0, N_("' ' flag"),        N_("the ' ' printf flag"),              STD_C89 },
+  { '+',  0, 0, N_("'+' flag"),        N_("the '+' printf flag"),              STD_C89 },
+  { '#',  0, 0, N_("'#' flag"),        N_("the '#' printf flag"),              STD_C89 },
+  { '0',  0, 0, N_("'0' flag"),        N_("the '0' printf flag"),              STD_C89 },
+  { '-',  0, 0, N_("'-' flag"),        N_("the '-' printf flag"),              STD_C89 },
+  { '\'', 0, 0, N_("''' flag"),        N_("the ''' printf flag"),              STD_EXT },
+  { 'w',  0, 0, N_("field width"),     N_("field width in printf format"),     STD_C89 },
+  { '.',  0, 0, N_("precision"),       N_("precision in printf format"),       STD_C89 },
+  { 'L',  0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_printf_flag_pairs[] =
+{
+  { ' ', '+', 1, 0   },
+  { '0', '-', 1, 0   },
+  { 0, 0, 0, 0 }
+};
+
+static const format_flag_spec ms_scanf_flag_specs[] =
+{
+  { '*',  0, 0, N_("assignment suppression"), N_("the assignment suppression scanf feature"), STD_C89 },
+  { 'a',  0, 0, N_("'a' flag"),               N_("the 'a' scanf flag"),                       STD_EXT },
+  { 'w',  0, 0, N_("field width"),            N_("field width in scanf format"),              STD_C89 },
+  { 'L',  0, 0, N_("length modifier"),        N_("length modifier in scanf format"),          STD_C89 },
+  { '\'', 0, 0, N_("''' flag"),               N_("the ''' scanf flag"),                       STD_EXT },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_scanf_flag_pairs[] =
+{
+  { '*', 'L', 0, 0 },
+  { 0, 0, 0, 0 }
+};
+
+static const format_flag_spec ms_strftime_flag_specs[] =
+{
+  { '_', 0,   0, N_("'_' flag"),     N_("the '_' strftime flag"),          STD_EXT },
+  { '-', 0,   0, N_("'-' flag"),     N_("the '-' strftime flag"),          STD_EXT },
+  { '0', 0,   0, N_("'0' flag"),     N_("the '0' strftime flag"),          STD_EXT },
+  { '^', 0,   0, N_("'^' flag"),     N_("the '^' strftime flag"),          STD_EXT },
+  { '#', 0,   0, N_("'#' flag"),     N_("the '#' strftime flag"),          STD_EXT },
+  { 'w', 0,   0, N_("field width"),  N_("field width in strftime format"), STD_EXT },
+  { 'E', 0,   0, N_("'E' modifier"), N_("the 'E' strftime modifier"),      STD_C99 },
+  { 'O', 0,   0, N_("'O' modifier"), N_("the 'O' strftime modifier"),      STD_C99 },
+  { 'O', 'o', 0, NULL,               N_("the 'O' modifier"),               STD_EXT },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+
+static const format_flag_pair ms_strftime_flag_pairs[] =
+{
+  { 'E', 'O', 0, 0 },
+  { '_', '-', 0, 0 },
+  { '_', '0', 0, 0 },
+  { '-', '0', 0, 0 },
+  { '^', '#', 0, 0 },
+  { 0, 0, 0, 0 }
+};
+
+static const format_char_info ms_print_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "di",  0, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  T89_V,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-wp0 +'",  "i",  NULL },
+  { "oxX", 0, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T89_V, BADLEN, BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "-wp0#",     "i",  NULL },
+  { "u",   0, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T89_V, BADLEN, BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "-wp0'",    "i",  NULL },
+  { "fgG", 0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "-wp0 +#'", "",   NULL },
+  { "eE",  0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "-wp0 +#",  "",   NULL },
+  { "c",   0, STD_C89, { T89_I,   BADLEN,  T89_S,  T94_WI,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "",   NULL },
+  { "s",   1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-wp",       "cR", NULL },
+  { "p",   1, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "c",  NULL },
+  { "n",   1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  BADLEN,  BADLEN, BADLEN,  T99_IM,  BADLEN,  BADLEN,  BADLEN }, "",          "W",  NULL },
+  /* X/Open conversion specifiers.  */
+  { "C",   0, STD_EXT, { TEX_WI,  BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "",   NULL },
+  { "S",   1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-wp",       "R",  NULL },
+  { NULL,  0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+static const format_char_info ms_scan_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "di",    1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  T89_V,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w'", "W",   NULL },
+  { "u",     1, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T89_V, BADLEN,  BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "*w'", "W",   NULL },
+  { "oxX",   1, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T89_V, BADLEN,  BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "efgEG", 1, STD_C89, { T89_F,   BADLEN,  BADLEN,  T89_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "*w'",  "W",   NULL },
+  { "c",     1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "cW",  NULL },
+  { "s",     1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "cW",  NULL },
+  { "[",     1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "cW[", NULL },
+  { "p",     2, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "n",     1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  BADLEN,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "",     "W",   NULL },
+  /* X/Open conversion specifiers.  */
+  { "C",     1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "S",     1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "W",   NULL },
+  { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+static const format_char_info ms_time_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "ABZab",		0, STD_C89, NOLENGTHS, "^#",     "",   NULL },
+  { "cx",		0, STD_C89, NOLENGTHS, "E",      "3",  NULL },
+  { "HIMSUWdmw",	0, STD_C89, NOLENGTHS, "-_0Ow",  "",   NULL },
+  { "j",		0, STD_C89, NOLENGTHS, "-_0Ow",  "o",  NULL },
+  { "p",		0, STD_C89, NOLENGTHS, "#",      "",   NULL },
+  { "X",		0, STD_C89, NOLENGTHS, "E",      "",   NULL },
+  { "y",		0, STD_C89, NOLENGTHS, "EO-_0w", "4",  NULL },
+  { "Y",		0, STD_C89, NOLENGTHS, "-_0EOw", "o",  NULL },
+  { "%",		0, STD_C89, NOLENGTHS, "",       "",   NULL },
+  /* C99 conversion specifiers.  */
+  { "z",		0, STD_C99, NOLENGTHS, "O",      "o",  NULL },
+  { NULL,		0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+const format_kind_info mingw_formatter_attributes[3] =
+{
+  { "ms_printf",   ms_printf_length_specs,  ms_print_char_table, " +#0-'", NULL,
+    ms_printf_flag_specs, ms_printf_flag_pairs,
+    FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
+    'w', 0, 0, 0, 'L', 0,
+    &integer_type_node, &integer_type_node
+  },
+  { "ms_scanf",    ms_printf_length_specs,   ms_scan_char_table,  "*'", NULL,
+    ms_scanf_flag_specs, ms_scanf_flag_pairs,
+    FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
+    'w', 0, 0, '*', 'L', 'm',
+    NULL, NULL
+  },
+  { "ms_strftime", NULL,                 ms_time_char_table,  "_-0^#", "EO",
+    ms_strftime_flag_specs, ms_strftime_flag_pairs,
+    FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0, 0,
+    NULL, NULL
+  }
+};
+
+/* Default overrides for printf, scanf and strftime.  */
+const target_ovr_attr mingw_formatter_attribute_overrides[4] =
+{
+  { "ms_printf", "printf" },
+  { "ms_scanf", "scanf" },
+  { "ms_strftime", "strftime" }
+};
Index: gcc/gcc/config/i386/t-cygming
===================================================================
--- gcc.orig/gcc/config/i386/t-cygming
+++ gcc/gcc/config/i386/t-cygming
@@ -29,4 +29,10 @@ winnt-stubs.o: $(srcdir)/config/i386/win
 	$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
 	$(srcdir)/config/i386/winnt-stubs.c
 
+msformat-c.o: $(srcdir)/config/i386/msformat-c.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
+  $(TM_H) $(RTL_H) $(REGS_H) hard-reg-set.h output.h $(TREE_H) flags.h \
+  $(TM_P_H) toplev.h $(HASHTAB_H) $(GGC_H)
+	$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
+	$(srcdir)/config/i386/msformat-c.c
+
 STMP_FIXINC=stmp-fixinc
Index: gcc/gcc/doc/extend.texi
===================================================================
--- gcc.orig/gcc/doc/extend.texi
+++ gcc/gcc/doc/extend.texi
@@ -2204,13 +2204,17 @@ for consistency with the @code{printf} s
 @code{my_format}.
 
 The parameter @var{archetype} determines how the format string is
-interpreted, and should be @code{printf}, @code{scanf}, @code{strftime}
-or @code{strfmon}.  (You can also use @code{__printf__},
-@code{__scanf__}, @code{__strftime__} or @code{__strfmon__}.)  The
-parameter @var{string-index} specifies which argument is the format
-string argument (starting from 1), while @var{first-to-check} is the
-number of the first argument to check against the format string.  For
-functions where the arguments are not available to be checked (such as
+interpreted, and should be @code{printf}, @code{scanf}, @code{strftime},
+@code{gnu_printf}, @code{gnu_scanf}, @code{gnu_strftime} or
+@code{strfmon}.  (You can also use @code{__printf__},
+@code{__scanf__}, @code{__strftime__} or @code{__strfmon__}.)  On
+mingw targets there is also @code{ms_printf}, @code{ms_scanf}, and
+@code{ms_strftime} present. The none target specific formatters are
+always the variant of the system.  The parameter @var{string-index}
+specifies which argument is the format string argument (starting
+from 1), while @var{first-to-check} is the number of the first
+argument to check against the format string.  For functions
+where the arguments are not available to be checked (such as
 @code{vprintf}), specify the third parameter as zero.  In this case the
 compiler only checks the format string for consistency.  For
 @code{strftime} formats, the third parameter is required to be zero.
Index: gcc/gcc/doc/tm.texi
===================================================================
--- gcc.orig/gcc/doc/tm.texi
+++ gcc/gcc/doc/tm.texi
@@ -10311,6 +10311,18 @@ If defined, this macro is the number of 
 @code{TARGET_FORMAT_TYPES}.
 @end defmac
 
+@defmac TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+If defined, this macro is the name of a global variable containg
+target-specific format overrides for the @option{-Wformat} option. The
+default is to have no target-specific format overrides. This depends, that
+@code{TARGET_FORMAT_TYPES} is defined too.
+@end defmac
+
+@defmac TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT
+If defined, this macro is the number of entries in
+@code{}.
+@end defmac
+
 @deftypefn {Target Hook} bool TARGET_RELAXED_ORDERING
 If set to @code{true}, means that the target's memory model does not
 guarantee that loads which do not depend on one another will access
Index: gcc/gcc/testsuite/gcc.dg/format/sys_formatter.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/sys_formatter.c
@@ -0,0 +1,20 @@
+/* Test system default printf formatter specifiers.  */
+/* Origin: Kai Tietz <KaiTietz.@onevision.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu89" } */
+
+#define USE_SYSTEM_FORMATS
+#include <format.h>
+
+__attribute__((format(printf, 1, 2))) void foo (const char *, ...);
+
+#ifdef _WIN32
+#define FORMATTER_TEXT	"%I64d %I32d %ld %d\n"
+#else
+#define FORMATTER_TEXT	"%lld %ld %ld %d"
+#endif
+
+void bar (long long v1, long v2, int v3)
+{
+  foo (FORMATTER_TEXT, v1, v2, v2, v3);
+}
Index: gcc/gcc/testsuite/gcc.dg/format/format.h
===================================================================
--- gcc.orig/gcc/testsuite/gcc.dg/format/format.h
+++ gcc/gcc/testsuite/gcc.dg/format/format.h
@@ -1,6 +1,29 @@
 /* Format checking tests: common header.  */
 /* Origin: Joseph Myers <jsm28@cam.ac.uk> */
 
+#if defined (_WIN32) && !defined (__CYGWIN__)
+#define SYSTEM_PRINTF(FMTPOS, WILDARG) __attribute__((format(ms_printf, FMTPOS, WILDARG)))
+#define SYSTEM_SCANF(FMTPOS, WILDARG) __attribute__((format(ms_scanf, FMTPOS, WILDARG)))
+#define SYSTEM_STRFTIME(FMTPOS) __attribute__((__format__(ms_strftime, FMTPOS, 0)))
+#else
+#define SYSTEM_PRINTF(FMTPOS, WILDARG) __attribute__((format(gnu_printf, FMTPOS, WILDARG)))
+#define SYSTEM_SCANF(FMTPOS, WILDARG) __attribute__((format(gnu_scanf, FMTPOS, WILDARG)))
+#define SYSTEM_STRFTIME(FMTPOS) __attribute__((__format__(gnu_strftime, FMTPOS, 0)))
+#endif
+
+#if !defined (USE_SYSTEM_FORMATS)
+#define __printf__	__gnu_printf__
+#define __scanf__	__gnu_scanf__
+#define __strftime__	__gnu_strftime__
+#define USE_PRINTF(FMTPOS, WILDARG) __attribute__((format(gnu_printf, FMTPOS, WILDARG)))
+#define USE_SCANF(FMTPOS, WILDARG) __attribute__((format(gnu_scanf, FMTPOS, WILDARG)))
+#define USE_STRFTIME(FMTPOS) __attribute__((__format__(gnu_strftime, FMTPOS, 0)))
+#else
+#define USE_PRINTF(FMTPOS, WILDARG)
+#define USE_SCANF(FMTPOS, WILDARG)
+#define USE_STRFTIME(FMTPOS)
+#endif
+
 #include <stdarg.h>
 #include <stddef.h>
 
@@ -70,3 +93,75 @@ extern size_t strftime (char *restrict, 
 			const struct tm *restrict);
 
 extern ssize_t strfmon (char *restrict, size_t, const char *restrict, ...);
+
+/* Mingw specific part.  */
+#if !defined (USE_SYSTEM_FORMATS) && defined(_WIN32)
+extern USE_PRINTF(2,3) int fprintf_gnu (FILE *restrict, const char *restrict, ...);
+#undef fprintf
+#define fprintf fprintf_gnu
+
+extern USE_PRINTF(1,2) int printf_gnu (const char *restrict, ...);
+#undef printf
+#define printf printf_gnu
+
+extern USE_PRINTF(2,3) int fprintf_unlocked_gnu (FILE *restrict, const char *restrict, ...);
+#undef fprintf_unlocked
+#define fprintf_unlocked fprintf_unlocked_gnu
+
+extern USE_PRINTF(1,2)int printf_unlocked_gnu (const char *restrict, ...);
+#undef printf_unlocked
+#define printf_unlocked printf_unlocked_gnu
+
+extern USE_PRINTF(2,3) int sprintf_gnu (char *restrict, const char *restrict, ...);
+#undef sprintf
+#define sprintf sprintf_gnu
+
+extern USE_PRINTF(2,0) int vfprintf_gnu (FILE *restrict, const char *restrict, va_list);
+#undef vsprintf
+#define vsprintf vsprintf_gnu
+
+extern USE_PRINTF(1,0) int vprintf_gnu (const char *restrict, va_list);
+#undef vprintf
+#define vprintf vprintf_gnu
+
+extern USE_PRINTF(2,0) int vsprintf_gnu (char *restrict, const char *restrict, va_list);
+#undef vsprintf
+#define vsprintf vsprintf_gnu
+
+extern USE_PRINTF(3,4) int snprintf_gnu (char *restrict, size_t, const char *restrict, ...);
+#undef snprintf
+#define snprintf snprintf_gnu
+
+extern USE_PRINTF(3,0) int vsnprintf_gnu (char *restrict, size_t, const char *restrict, va_list);
+#undef vsnprintf
+#define vsnprintf vsnprintf_gnu
+
+extern USE_SCANF(2,3) int fscanf_gnu (FILE *restrict, const char *restrict, ...);
+#undef fscanf
+#define fscanf fscanf_gnu
+
+extern USE_SCANF(1,2) int scanf_gnu (const char *restrict, ...);
+#undef scanf
+#define scanf scanf_gnu
+
+extern USE_SCANF(2,3) int sscanf_gnu (const char *restrict, const char *restrict, ...);
+#undef sscanf
+#define sscanf sscanf_gnu
+
+extern USE_SCANF(2,0) int vfscanf_gnu (FILE *restrict, const char *restrict, va_list);
+#undef vfscanf
+#define vfscanf vfscanf_gnu
+
+extern USE_SCANF(1,0) int vscanf_gnu (const char *restrict, va_list);
+#undef vscanf
+#define vscanf vscanf_gnu
+
+extern USE_SCANF(2,0) int vsscanf_gnu (const char *restrict, const char *restrict, va_list);
+#undef vsscanf
+#define vsscanf vsscanf_gnu
+
+extern USE_STRFTIME(3) size_t strftime_gnu (char *restrict, size_t, const char *restrict,
+			const struct tm *restrict);
+#undef strftime
+#define strftime strftime_gnu
+#endif
=

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf     formatters to c-format.c
  2008-01-07 14:44                     ` Joseph S. Myers
@ 2008-01-07 16:26                       ` Kai Tietz
  2008-01-08 14:37                       ` Kai Tietz
  1 sibling, 0 replies; 61+ messages in thread
From: Kai Tietz @ 2008-01-07 16:26 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: Danny Smith, GCC Patches, NightStrike

Hi,

"Joseph S. Myers" wrote on 07.01.2008 13:32:37:

> On Mon, 7 Jan 2008, Kai Tietz wrote:
> 
> If you are referring to the tests asserting that C99 functions do not 
have 
> default attributes in -std=c89 mode, then indeed those will need 
> separating from some of the other tests when you make most of the tests 
be 
> of functions using gnu_printf etc. attributes when run got MinGW 
targets. 
> If you are referring to something else, you need to cite specific lines 
of 
> specific files and specific diagnostics or lack thereof to explain what 
> you are referring to.

Yes, I am referring to the tests asserting that C99 functions and the C90 
functions.
The C90 tests are a bit special, because mingw-64 needs a 64-bit type for 
size_t (as long long), which is not in the C90 standard. So there are 
additional warnings about this. But may this is a different point.

If I change the existing test-cases for printf/scanf/strftime using gnu_ 
variant, is this OK for you ?

Cheers,
 i.A. Kai Tietz

|  (\_/)  This is Bunny. Copy and paste Bunny
| (='.'=) into your signature to help him gain
| (")_(") world domination.

------------------------------------------------------------------------------------------
  OneVision Software Entwicklungs GmbH & Co. KG
  Dr.-Leo-Ritter-Straße 9 - 93049 Regensburg
  Tel: +49.(0)941.78004.0 - Fax: +49.(0)941.78004.489 - www.OneVision.com
  Commerzbank Regensburg - BLZ 750 400 62 - Konto 6011050
  Handelsregister: HRA 6744, Amtsgericht Regensburg
  Komplementärin: OneVision Software Entwicklungs Verwaltungs GmbH
  Dr.-Leo-Ritter-Straße 9 – 93049 Regensburg
  Handelsregister: HRB 8932, Amtsgericht Regensburg - Geschäftsführer: 
Ulrike Döhler, Manuela Kluger


^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf     formatters to c-format.c
  2008-01-07 13:56                   ` Kai Tietz
@ 2008-01-07 14:44                     ` Joseph S. Myers
  2008-01-07 16:26                       ` Kai Tietz
  2008-01-08 14:37                       ` Kai Tietz
  0 siblings, 2 replies; 61+ messages in thread
From: Joseph S. Myers @ 2008-01-07 14:44 UTC (permalink / raw)
  To: Kai Tietz; +Cc: Danny Smith, GCC Patches, NightStrike

On Mon, 7 Jan 2008, Kai Tietz wrote:

> Ok, while running the testsuite I noticed, that at some places the 
> formatter "%ld" is used together with an "int" type, which isn't marked to 
> produce a warning. Which is at least for x86_64 linux targets a problem. I 
> see on my tests that it got warned correctly as it should be a long.
> Just for "printf/scanf/strftime" formatters, there are some problems, the 
> other formatters seems to work as before.

If you are referring to the tests asserting that C99 functions do not have 
default attributes in -std=c89 mode, then indeed those will need 
separating from some of the other tests when you make most of the tests be 
of functions using gnu_printf etc. attributes when run got MinGW targets.  
If you are referring to something else, you need to cite specific lines of 
specific files and specific diagnostics or lack thereof to explain what 
you are referring to.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf    formatters to c-format.c
  2007-12-21 14:38                 ` Joseph S. Myers
@ 2008-01-07 13:56                   ` Kai Tietz
  2008-01-07 14:44                     ` Joseph S. Myers
  0 siblings, 1 reply; 61+ messages in thread
From: Kai Tietz @ 2008-01-07 13:56 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: Danny Smith, GCC Patches, NightStrike

[-- Attachment #1: Type: text/plain, Size: 3559 bytes --]

Hi Joseph,

"Joseph S. Myers" wrote on 21.12.2007 14:19:57:

> On Fri, 21 Dec 2007, Kai Tietz wrote:
> 
> > There is a problem with the fortran compiler and this patch. The 
fortran 
> > compiler inherits i386.c as target, but does not have the 
c_global_trees 
> > symbol, which is referenced by the formatter tables. So this patch 
will 
> > fail for it. To solve this, I suggest, that the tables should be 
placed 
> > within c-format.c. Is this ok for you ?
> 
> No, you should put it in a new *-c.c file listed in c_target_objs and 
> cxx_target_objs in config.gcc and add the necessary rule to the 
associated 
> t-* file to build this object.  sol2-c.c has an existing example of 
> target-specific formats.

Thanks for you hint. I moved the formatter rules for the ms style in 
/config/i386/msformat-c.c and added the rules in config.gcc for it.

Ok, while running the testsuite I noticed, that at some places the 
formatter "%ld" is used together with an "int" type, which isn't marked to 
produce a warning. Which is at least for x86_64 linux targets a problem. I 
see on my tests that it got warned correctly as it should be a long.
Just for "printf/scanf/strftime" formatters, there are some problems, the 
other formatters seems to work as before.

I needed to add a special prefix to the format char definition to allow 
multi-charaters here. I choose the \0, but may you have an better idea for 
that?

The ChangeLog so far:

2008-01-07      Kai Tietz  <kai.tietz@onevision.com>

        * gcc/c-format.c: (replace_formatter_name_to_system_name): New.
        (compare_tofa): New.
        (decode_format_attr): Use of 
replace_formatter_name_to_system_name.
        (format_types_orig): Add gnu_ prefix to names.
        (check_format_info_main): Special treating of \0 escaped names for
        supporting multi-character formatters as I32, I64.
        (TARGET_OVERRIDES_FORMAT_ATTRIBUTES): Use of user defined 
attributes.
        (gnu_target_overrides_format_attributes): New.
        * gcc/c-format.h: Add structure target_ovr_attr to hold
        system specific formatter names.
        * gcc/config.gcc: Add for x86&x86_64 cygwin and mingw32 targets 
the
        msformat-c.o file to c_target_objs and cxx_target_objs.
        * gcc/config/i386/mingw32.h: (TARGET_OVERRIDES_FORMAT_ATTRIBUTES): 
New.
        (TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT): New.
        (TARGET_N_FORMAT_TYPES): New.
        * gcc/config/i386/msformat-c.c: New.
        * gcc/config/i386/t-cygming: Add build rule for msformat-c.o.
        * gcc/doc/extend.texi: Add new format names gnu_* and ms_*.
        * gcc/doc/tm.texi: (TARGET_OVERRIDES_FORMAT_ATTRIBUTES): New.
        * gcc/testsuite/gcc.dg/format/sys_formatter.c: New.

Cheers,
 i.A. Kai Tietz



|  (\_/)  This is Bunny. Copy and paste Bunny
| (='.'=) into your signature to help him gain
| (")_(") world domination.

------------------------------------------------------------------------------------------
  OneVision Software Entwicklungs GmbH & Co. KG
  Dr.-Leo-Ritter-Straße 9 - 93049 Regensburg
  Tel: +49.(0)941.78004.0 - Fax: +49.(0)941.78004.489 - www.OneVision.com
  Commerzbank Regensburg - BLZ 750 400 62 - Konto 6011050
  Handelsregister: HRA 6744, Amtsgericht Regensburg
  Komplementärin: OneVision Software Entwicklungs Verwaltungs GmbH
  Dr.-Leo-Ritter-Straße 9 – 93049 Regensburg
  Handelsregister: HRB 8932, Amtsgericht Regensburg - Geschäftsführer: 
Ulrike Döhler, Manuela Kluger



[-- Attachment #2: mingw-msformat.txt --]
[-- Type: text/plain, Size: 23433 bytes --]

Index: gcc/gcc/c-format.c
===================================================================
--- gcc.orig/gcc/c-format.c
+++ gcc/gcc/c-format.c
@@ -80,7 +80,8 @@ static bool check_format_string (tree ar
 				 int flags, bool *no_add_attrs);
 static bool get_constant (tree expr, unsigned HOST_WIDE_INT *value,
 			  int validated_p);
-
+static const char *replace_formatter_name_to_system_name (const char *attr_name);
+static int compare_tofa (const char *tattr_name, const char *attr_name);
 
 /* Handle a "format_arg" attribute; arguments as in
    struct attribute_spec.handler.  */
@@ -191,6 +192,8 @@ decode_format_attr (tree args, function_
     {
       const char *p = IDENTIFIER_POINTER (format_type_id);
 
+      p = replace_formatter_name_to_system_name (p);
+
       info->format_type = decode_format_type (p);
 
       if (info->format_type == format_type_error)
@@ -715,7 +718,7 @@ static const format_char_info monetary_c
 /* This must be in the same order as enum format_type.  */
 static const format_kind_info format_types_orig[] =
 {
-  { "printf",   printf_length_specs,  print_char_table, " +#0-'I", NULL,
+  { "gnu_printf",   printf_length_specs,  print_char_table, " +#0-'I", NULL,
     printf_flag_specs, printf_flag_pairs,
     FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
     'w', 0, 'p', 0, 'L', 0,
@@ -757,18 +760,18 @@ static const format_kind_info format_typ
     0, 0, 0, 0, 0, 0,
     NULL, NULL
   },
-  { "scanf",    scanf_length_specs,   scan_char_table,  "*'I", NULL,
+  { "gnu_scanf",    scanf_length_specs,   scan_char_table,  "*'I", NULL,
     scanf_flag_specs, scanf_flag_pairs,
     FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
     'w', 0, 0, '*', 'L', 'm',
     NULL, NULL
   },
-  { "strftime", NULL,                 time_char_table,  "_-0^#", "EO",
+  { "gnu_strftime", NULL,                 time_char_table,  "_-0^#", "EO",
     strftime_flag_specs, strftime_flag_pairs,
     FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0, 0,
     NULL, NULL
   },
-  { "strfmon",  strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
+  { "gnu_strfmon",  strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
     strfmon_flag_specs, strfmon_flag_pairs,
     FMT_FLAG_ARG_CONVERT, 'w', '#', 'p', 0, 'L', 0,
     NULL, NULL
@@ -847,6 +850,7 @@ decode_format_type (const char *s)
 {
   int i;
   int slen;
+  s = replace_formatter_name_to_system_name (s);
   slen = strlen (s);
   for (i = 0; i < n_format_types; i++)
     {
@@ -1776,7 +1780,22 @@ check_format_info_main (format_check_res
       if (fli)
 	{
 	  while (fli->name != 0 && fli->name[0] != *format_chars)
-	    fli++;
+	    {
+	      if (fli->name[0] == '\0')
+		{
+		  int si  = strlen (fli->name + 1) + 1;
+		  int i = 1;
+		  while (fli->name[i] != 0 && fli->name[i] == format_chars [i - 1])
+		    ++i;
+		 if (si == i)
+		   {
+		     if (si > 2)
+		       format_chars += si - 2;
+		     break;
+		   }
+	       }
+	      fli++;
+	    }
 	  if (fli->name != 0)
 	    {
 	      format_chars++;
@@ -2703,6 +2722,72 @@ init_dynamic_diag_info (void)
 extern const format_kind_info TARGET_FORMAT_TYPES[];
 #endif
 
+#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+extern const target_ovr_attr TARGET_OVERRIDES_FORMAT_ATTRIBUTES[];
+#endif
+
+/* Description of gnu specific format attributes reflected to
+   system format attribute types, as printf, scanf, strftime, and
+   strfmon.  */
+const target_ovr_attr gnu_target_overrides_format_attributes[] =
+{
+  { "gnu_printf",   "printf" },
+  { "gnu_scanf",    "scanf" },
+  { "gnu_strftime", "strftime" },
+  { "gnu_strfmon",  "strfmon" },
+  { NULL,           NULL }
+};
+
+static const char *
+replace_formatter_name_to_system_name (const char *attr_name)
+{
+  int i;
+
+  if (attr_name == NULL || *attr_name == 0 || strncmp (attr_name, "gcc_", 4) == 0)
+    return attr_name;
+
+#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+  /* Check if format attribute is overridden by target.  */
+  if (TARGET_OVERRIDES_FORMAT_ATTRIBUTES != NULL && TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT > 0)
+    {
+      for (i = 0; i < TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT; ++i)
+        {
+          if (compare_tofa (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src, attr_name))
+            return attr_name;
+          if (compare_tofa (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_dst, attr_name))
+            return TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src;
+        }
+    }
+#endif
+  /* Otherwise default to gnu formatter.  */
+  for (i = 0; gnu_target_overrides_format_attributes[i].named_attr_src != NULL; ++i)
+    {
+      if (compare_tofa (gnu_target_overrides_format_attributes[i].named_attr_src, attr_name))
+        return attr_name;
+      if (compare_tofa (gnu_target_overrides_format_attributes[i].named_attr_dst, attr_name))
+        return gnu_target_overrides_format_attributes[i].named_attr_src;
+    }
+
+  return attr_name;
+}
+
+/* Compare the target override format attribute by treating double underscore syntax.  */
+static int
+compare_tofa (const char *tattr_name, const char *attr_name)
+{
+  int alen = strlen (attr_name);
+  int slen = (tattr_name ? strlen (tattr_name) : 0);
+  if (alen > 4 && attr_name[0] == '_' && attr_name[1] == '_'
+      && attr_name[alen - 1] == '_' && attr_name[alen - 2] == '_')
+    {
+      attr_name += 2;
+      alen -= 4;
+    }
+  if (alen != slen || strncmp (tattr_name, attr_name, alen) != 0)
+    return 0;
+  return 1;
+}
+
 /* Handle a "format" attribute; arguments as in
    struct attribute_spec.handler.  */
 tree
Index: gcc/gcc/c-format.h
===================================================================
--- gcc.orig/gcc/c-format.h
+++ gcc/gcc/c-format.h
@@ -306,4 +306,18 @@ typedef struct
 #define T_D128  &dfloat128_type_node
 #define TEX_D128 { STD_EXT, "_Decimal128", T_D128 }
 
+/* Structure describing the target specific to be override formatter
+   attributes, e.g. printf, scanf, etc.  This allows to support different
+   runtime-library specific formatter attributes to co-exist and defining
+   a default system version.
+   This type is used for the pointer variable TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+   refers to.  */
+typedef struct
+{
+  /* The name of the to be copied formatter attribute. */
+  const char *named_attr_src;
+  /* The name of the to be overridden formatter attribute. */
+  const char *named_attr_dst;
+} target_ovr_attr;
+
 #endif /* GCC_C_FORMAT_H */
Index: gcc/gcc/config.gcc
===================================================================
--- gcc.orig/gcc/config.gcc
+++ gcc/gcc/config.gcc
@@ -1359,8 +1359,8 @@ i[34567]86-*-pe | i[34567]86-*-cygwin*)
 	target_gtfiles="\$(srcdir)/config/i386/winnt.c"
 	extra_options="${extra_options} i386/cygming.opt"
 	extra_objs="winnt.o winnt-stubs.o"
-	c_target_objs=cygwin2.o
-	cxx_target_objs="cygwin2.o winnt-cxx.o"
+	c_target_objs="cygwin2.o msformat-c.o"
+	cxx_target_objs="cygwin2.o winnt-cxx.o msformat-c.o"
 	extra_gcc_objs=cygwin1.o
 	if test x$enable_threads = xyes; then
 		thread_file='posix'
@@ -1373,7 +1373,8 @@ i[34567]86-*-mingw32* | x86_64-*-mingw32
 	target_gtfiles="\$(srcdir)/config/i386/winnt.c"
 	extra_options="${extra_options} i386/cygming.opt"
 	extra_objs="winnt.o winnt-stubs.o"
-	cxx_target_objs=winnt-cxx.o
+	c_target_objs="msformat-c.o"
+	cxx_target_objs="winnt-cxx.o msformat-c.o"
 	default_use_cxa_atexit=yes
 	case ${enable_threads} in
 	  "" | yes | win32)
Index: gcc/gcc/config/i386/mingw32.h
===================================================================
--- gcc.orig/gcc/config/i386/mingw32.h
+++ gcc/gcc/config/i386/mingw32.h
@@ -143,6 +143,22 @@ do {						         \
    to register C++ static destructors.  */
 #define TARGET_CXX_USE_ATEXIT_FOR_CXA_ATEXIT hook_bool_void_true
 
+/* Contains a pointer to type target_ovr_attr defining the target specific
+   overrides of formatter attributs.  See format.h for structure definition.  */
+#undef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+#define TARGET_OVERRIDES_FORMAT_ATTRIBUTES mingw_formatter_attribute_overrides
+
+/* Specify the count of elements in TARGET_OVERRIDES_ATTRIBUTE.  */
+#undef TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT
+#define TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT 3
+
+/* MS specific format attributes for ms_printf, ms_scanf, ms_strftime.  */
+#undef TARGET_FORMAT_TYPES
+#define TARGET_FORMAT_TYPES mingw_formatter_attributes
+
+#undef TARGET_N_FORMAT_TYPES
+#define TARGET_N_FORMAT_TYPES 3
+
 /* JCR_SECTION works on mingw32.  */
 #undef TARGET_USE_JCR_SECTION
 #define TARGET_USE_JCR_SECTION 1
Index: gcc/gcc/config/i386/msformat-c.c
===================================================================
--- /dev/null
+++ gcc/gcc/config/i386/msformat-c.c
@@ -0,0 +1,189 @@
+/* Check calls to formatted I/O functions (-Wformat).
+   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+   2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "flags.h"
+#include "c-common.h"
+#include "toplev.h"
+#include "intl.h"
+#include "diagnostic.h"
+#include "langhooks.h"
+#include "c-format.h"
+#include "alloc-pool.h"
+
+/* Mingw specific format attributes ms_printf, ms_scanf, and ms_strftime.  */
+
+static const format_length_info ms_printf_length_specs[] =
+{
+  { "h", FMT_LEN_h, STD_C89, NULL, 0, 0 },
+  { "l", FMT_LEN_l, STD_C89, NULL, 0, 0 },
+  { "\0I32", FMT_LEN_l, STD_C89, NULL, 0, 0 },
+  { "\0I64", FMT_LEN_ll, STD_C9L, NULL, 0, 0 },
+  { "I", FMT_LEN_L, STD_C89, NULL, 0, 0 },
+  { NULL, 0, 0, NULL, 0, 0 }
+};
+
+static const format_flag_spec ms_printf_flag_specs[] =
+{
+  { ' ',  0, 0, N_("' ' flag"),        N_("the ' ' printf flag"),              STD_C89 },
+  { '+',  0, 0, N_("'+' flag"),        N_("the '+' printf flag"),              STD_C89 },
+  { '#',  0, 0, N_("'#' flag"),        N_("the '#' printf flag"),              STD_C89 },
+  { '0',  0, 0, N_("'0' flag"),        N_("the '0' printf flag"),              STD_C89 },
+  { '-',  0, 0, N_("'-' flag"),        N_("the '-' printf flag"),              STD_C89 },
+  { '\'', 0, 0, N_("''' flag"),        N_("the ''' printf flag"),              STD_EXT },
+  { 'w',  0, 0, N_("field width"),     N_("field width in printf format"),     STD_C89 },
+  { '.',  0, 0, N_("precision"),       N_("precision in printf format"),       STD_C89 },
+  { 'L',  0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_printf_flag_pairs[] =
+{
+  { ' ', '+', 1, 0   },
+  { '0', '-', 1, 0   },
+  { 0, 0, 0, 0 }
+};
+
+static const format_flag_spec ms_scanf_flag_specs[] =
+{
+  { '*',  0, 0, N_("assignment suppression"), N_("the assignment suppression scanf feature"), STD_C89 },
+  { 'a',  0, 0, N_("'a' flag"),               N_("the 'a' scanf flag"),                       STD_EXT },
+  { 'w',  0, 0, N_("field width"),            N_("field width in scanf format"),              STD_C89 },
+  { 'L',  0, 0, N_("length modifier"),        N_("length modifier in scanf format"),          STD_C89 },
+  { '\'', 0, 0, N_("''' flag"),               N_("the ''' scanf flag"),                       STD_EXT },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_scanf_flag_pairs[] =
+{
+  { '*', 'L', 0, 0 },
+  { 0, 0, 0, 0 }
+};
+
+static const format_flag_spec ms_strftime_flag_specs[] =
+{
+  { '_', 0,   0, N_("'_' flag"),     N_("the '_' strftime flag"),          STD_EXT },
+  { '-', 0,   0, N_("'-' flag"),     N_("the '-' strftime flag"),          STD_EXT },
+  { '0', 0,   0, N_("'0' flag"),     N_("the '0' strftime flag"),          STD_EXT },
+  { '^', 0,   0, N_("'^' flag"),     N_("the '^' strftime flag"),          STD_EXT },
+  { '#', 0,   0, N_("'#' flag"),     N_("the '#' strftime flag"),          STD_EXT },
+  { 'w', 0,   0, N_("field width"),  N_("field width in strftime format"), STD_EXT },
+  { 'E', 0,   0, N_("'E' modifier"), N_("the 'E' strftime modifier"),      STD_C99 },
+  { 'O', 0,   0, N_("'O' modifier"), N_("the 'O' strftime modifier"),      STD_C99 },
+  { 'O', 'o', 0, NULL,               N_("the 'O' modifier"),               STD_EXT },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+
+static const format_flag_pair ms_strftime_flag_pairs[] =
+{
+  { 'E', 'O', 0, 0 },
+  { '_', '-', 0, 0 },
+  { '_', '0', 0, 0 },
+  { '-', '0', 0, 0 },
+  { '^', '#', 0, 0 },
+  { 0, 0, 0, 0 }
+};
+
+static const format_char_info ms_print_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "di",  0, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  T89_V,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-wp0 +'",  "i",  NULL },
+  { "oxX", 0, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T89_V, BADLEN, BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "-wp0#",     "i",  NULL },
+  { "u",   0, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T89_V, BADLEN, BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "-wp0'",    "i",  NULL },
+  { "fgG", 0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "-wp0 +#'", "",   NULL },
+  { "eE",  0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "-wp0 +#",  "",   NULL },
+  { "c",   0, STD_C89, { T89_I,   BADLEN,  T89_S,  T94_WI,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "",   NULL },
+  { "s",   1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-wp",       "cR", NULL },
+  { "p",   1, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "c",  NULL },
+  { "n",   1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  BADLEN,  BADLEN, BADLEN,  T99_IM,  BADLEN,  BADLEN,  BADLEN }, "",          "W",  NULL },
+  /* X/Open conversion specifiers.  */
+  { "C",   0, STD_EXT, { TEX_WI,  BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "",   NULL },
+  { "S",   1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-wp",       "R",  NULL },
+  { NULL,  0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+static const format_char_info ms_scan_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "di",    1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  T89_V,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w'", "W",   NULL },
+  { "u",     1, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T89_V, BADLEN,  BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "*w'", "W",   NULL },
+  { "oxX",   1, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T89_V, BADLEN,  BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "efgEG", 1, STD_C89, { T89_F,   BADLEN,  BADLEN,  T89_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "*w'",  "W",   NULL },
+  { "c",     1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "cW",  NULL },
+  { "s",     1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "cW",  NULL },
+  { "[",     1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "cW[", NULL },
+  { "p",     2, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "n",     1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  BADLEN,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "",     "W",   NULL },
+  /* X/Open conversion specifiers.  */
+  { "C",     1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "S",     1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "W",   NULL },
+  { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+static const format_char_info ms_time_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "ABZab",		0, STD_C89, NOLENGTHS, "^#",     "",   NULL },
+  { "cx",		0, STD_C89, NOLENGTHS, "E",      "3",  NULL },
+  { "HIMSUWdmw",	0, STD_C89, NOLENGTHS, "-_0Ow",  "",   NULL },
+  { "j",		0, STD_C89, NOLENGTHS, "-_0Ow",  "o",  NULL },
+  { "p",		0, STD_C89, NOLENGTHS, "#",      "",   NULL },
+  { "X",		0, STD_C89, NOLENGTHS, "E",      "",   NULL },
+  { "y",		0, STD_C89, NOLENGTHS, "EO-_0w", "4",  NULL },
+  { "Y",		0, STD_C89, NOLENGTHS, "-_0EOw", "o",  NULL },
+  { "%",		0, STD_C89, NOLENGTHS, "",       "",   NULL },
+  /* C99 conversion specifiers.  */
+  { "z",		0, STD_C99, NOLENGTHS, "O",      "o",  NULL },
+  { NULL,		0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+const format_kind_info mingw_formatter_attributes[3] =
+{
+  { "ms_printf",   ms_printf_length_specs,  ms_print_char_table, " +#0-'", NULL,
+    ms_printf_flag_specs, ms_printf_flag_pairs,
+    FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
+    'w', 0, 0, 0, 'L', 0,
+    &integer_type_node, &integer_type_node
+  },
+  { "ms_scanf",    ms_printf_length_specs,   ms_scan_char_table,  "*'", NULL,
+    ms_scanf_flag_specs, ms_scanf_flag_pairs,
+    FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
+    'w', 0, 0, '*', 'L', 'm',
+    NULL, NULL
+  },
+  { "ms_strftime", NULL,                 ms_time_char_table,  "_-0^#", "EO",
+    ms_strftime_flag_specs, ms_strftime_flag_pairs,
+    FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0, 0,
+    NULL, NULL
+  }
+};
+
+/* Default overrides for printf, scanf and strftime.  */
+const target_ovr_attr mingw_formatter_attribute_overrides[4] =
+{
+  { "ms_printf", "printf" },
+  { "ms_scanf", "scanf" },
+  { "ms_strftime", "strftime" }
+};
Index: gcc/gcc/config/i386/t-cygming
===================================================================
--- gcc.orig/gcc/config/i386/t-cygming
+++ gcc/gcc/config/i386/t-cygming
@@ -29,4 +29,10 @@ winnt-stubs.o: $(srcdir)/config/i386/win
 	$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
 	$(srcdir)/config/i386/winnt-stubs.c
 
+msformat-c.o: $(srcdir)/config/i386/msformat-c.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
+  $(TM_H) $(RTL_H) $(REGS_H) hard-reg-set.h output.h $(TREE_H) flags.h \
+  $(TM_P_H) toplev.h $(HASHTAB_H) $(GGC_H)
+	$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
+	$(srcdir)/config/i386/msformat-c.c
+
 STMP_FIXINC=stmp-fixinc
Index: gcc/gcc/doc/extend.texi
===================================================================
--- gcc.orig/gcc/doc/extend.texi
+++ gcc/gcc/doc/extend.texi
@@ -2204,13 +2204,17 @@ for consistency with the @code{printf} s
 @code{my_format}.
 
 The parameter @var{archetype} determines how the format string is
-interpreted, and should be @code{printf}, @code{scanf}, @code{strftime}
-or @code{strfmon}.  (You can also use @code{__printf__},
-@code{__scanf__}, @code{__strftime__} or @code{__strfmon__}.)  The
-parameter @var{string-index} specifies which argument is the format
-string argument (starting from 1), while @var{first-to-check} is the
-number of the first argument to check against the format string.  For
-functions where the arguments are not available to be checked (such as
+interpreted, and should be @code{printf}, @code{scanf}, @code{strftime},
+@code{gnu_printf}, @code{gnu_scanf}, @code{gnu_strftime} or
+@code{strfmon}.  (You can also use @code{__printf__},
+@code{__scanf__}, @code{__strftime__} or @code{__strfmon__}.)  On
+mingw targets there is also @code{ms_printf}, @code{ms_scanf}, and
+@code{ms_strftime} present. The none target specific formatters are
+always the variant of the system.  The parameter @var{string-index}
+specifies which argument is the format string argument (starting
+from 1), while @var{first-to-check} is the number of the first
+argument to check against the format string.  For functions
+where the arguments are not available to be checked (such as
 @code{vprintf}), specify the third parameter as zero.  In this case the
 compiler only checks the format string for consistency.  For
 @code{strftime} formats, the third parameter is required to be zero.
Index: gcc/gcc/doc/tm.texi
===================================================================
--- gcc.orig/gcc/doc/tm.texi
+++ gcc/gcc/doc/tm.texi
@@ -10311,6 +10311,18 @@ If defined, this macro is the number of 
 @code{TARGET_FORMAT_TYPES}.
 @end defmac
 
+@defmac TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+If defined, this macro is the name of a global variable containg
+target-specific format overrides for the @option{-Wformat} option. The
+default is to have no target-specific format overrides. This depends, that
+@code{TARGET_FORMAT_TYPES} is defined too.
+@end defmac
+
+@defmac TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT
+If defined, this macro is the number of entries in
+@code{}.
+@end defmac
+
 @deftypefn {Target Hook} bool TARGET_RELAXED_ORDERING
 If set to @code{true}, means that the target's memory model does not
 guarantee that loads which do not depend on one another will access
Index: gcc/gcc/testsuite/gcc.dg/format/sys_formatter.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/sys_formatter.c
@@ -0,0 +1,19 @@
+/* Test system default printf formatter specifiers.  */
+/* Origin: Kai Tietz <KaiTietz.@onevision.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu89" } */
+
+#include <format.h>
+
+__attribute__((format(printf, 1, 2))) void foo (const char *, ...);
+
+#ifdef _WIN32
+#define FORMATTER_TEXT	"%I64d %I32d %ld %d\n"
+#else
+#define FORMATTER_TEXT	"%lld %ld %ld %d"
+#endif
+
+void bar (long long v1, long v2, int v3)
+{
+  foo (FORMATTER_TEXT, v1, v2, v2, v3);
+}
=

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf    formatters to c-format.c
  2007-12-21 14:03               ` Kai Tietz
@ 2007-12-21 14:38                 ` Joseph S. Myers
  2008-01-07 13:56                   ` Kai Tietz
  0 siblings, 1 reply; 61+ messages in thread
From: Joseph S. Myers @ 2007-12-21 14:38 UTC (permalink / raw)
  To: Kai Tietz; +Cc: Danny Smith, GCC Patches, NightStrike

On Fri, 21 Dec 2007, Kai Tietz wrote:

> There is a problem with the fortran compiler and this patch. The fortran 
> compiler inherits i386.c as target, but does not have the c_global_trees 
> symbol, which is referenced by the formatter tables. So this patch will 
> fail for it. To solve this, I suggest, that the tables should be placed 
> within c-format.c. Is this ok for you ?

No, you should put it in a new *-c.c file listed in c_target_objs and 
cxx_target_objs in config.gcc and add the necessary rule to the associated 
t-* file to build this object.  sol2-c.c has an existing example of 
target-specific formats.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf   formatters to c-format.c
  2007-12-20 14:16             ` Joseph S. Myers
  2007-12-20 14:30               ` Kai Tietz
@ 2007-12-21 14:03               ` Kai Tietz
  2007-12-21 14:38                 ` Joseph S. Myers
  1 sibling, 1 reply; 61+ messages in thread
From: Kai Tietz @ 2007-12-21 14:03 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: Danny Smith, GCC Patches, NightStrike

[-- Attachment #1: Type: text/plain, Size: 1200 bytes --]

Hi Joseph,

There is a problem with the fortran compiler and this patch. The fortran 
compiler inherits i386.c as target, but does not have the c_global_trees 
symbol, which is referenced by the formatter tables. So this patch will 
fail for it. To solve this, I suggest, that the tables should be placed 
within c-format.c. Is this ok for you ?

I did a bootstap test for this on x86_64-pc-mingw32 and for 
i686-pc-cygwin.





Cheers,
 i.A. Kai Tietz

|  (\_/)  This is Bunny. Copy and paste Bunny
| (='.'=) into your signature to help him gain
| (")_(") world domination.

------------------------------------------------------------------------------------------
  OneVision Software Entwicklungs GmbH & Co. KG
  Dr.-Leo-Ritter-Straße 9 - 93049 Regensburg
  Tel: +49.(0)941.78004.0 - Fax: +49.(0)941.78004.489 - www.OneVision.com
  Commerzbank Regensburg - BLZ 750 400 62 - Konto 6011050
  Handelsregister: HRA 6744, Amtsgericht Regensburg
  Komplementärin: OneVision Software Entwicklungs Verwaltungs GmbH
  Dr.-Leo-Ritter-Straße 9 – 93049 Regensburg
  Handelsregister: HRB 8932, Amtsgericht Regensburg - Geschäftsführer: 
Ulrike Döhler, Manuela Kluger


[-- Attachment #2: ext_formatter.txt --]
[-- Type: text/plain, Size: 19517 bytes --]

Index: gcc/gcc/c-format.c
===================================================================
--- gcc.orig/gcc/c-format.c
+++ gcc/gcc/c-format.c
@@ -80,7 +80,7 @@ static bool check_format_string (tree ar
 				 int flags, bool *no_add_attrs);
 static bool get_constant (tree expr, unsigned HOST_WIDE_INT *value,
 			  int validated_p);
-
+static const char *replace_formatter_name_to_system_name (const char *attr_name);
 
 /* Handle a "format_arg" attribute; arguments as in
    struct attribute_spec.handler.  */
@@ -191,6 +191,8 @@ decode_format_attr (tree args, function_
     {
       const char *p = IDENTIFIER_POINTER (format_type_id);
 
+      p = replace_formatter_name_to_system_name (p);
+
       info->format_type = decode_format_type (p);
 
       if (info->format_type == format_type_error)
@@ -715,7 +717,7 @@ static const format_char_info monetary_c
 /* This must be in the same order as enum format_type.  */
 static const format_kind_info format_types_orig[] =
 {
-  { "printf",   printf_length_specs,  print_char_table, " +#0-'I", NULL,
+  { "gnu_printf",   printf_length_specs,  print_char_table, " +#0-'I", NULL,
     printf_flag_specs, printf_flag_pairs,
     FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
     'w', 0, 'p', 0, 'L', 0,
@@ -757,24 +759,179 @@ static const format_kind_info format_typ
     0, 0, 0, 0, 0, 0,
     NULL, NULL
   },
-  { "scanf",    scanf_length_specs,   scan_char_table,  "*'I", NULL,
+  { "gnu_scanf",    scanf_length_specs,   scan_char_table,  "*'I", NULL,
     scanf_flag_specs, scanf_flag_pairs,
     FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
     'w', 0, 0, '*', 'L', 'm',
     NULL, NULL
   },
-  { "strftime", NULL,                 time_char_table,  "_-0^#", "EO",
+  { "gnu_strftime", NULL,                 time_char_table,  "_-0^#", "EO",
     strftime_flag_specs, strftime_flag_pairs,
     FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0, 0,
     NULL, NULL
   },
-  { "strfmon",  strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
+  { "gnu_strfmon",  strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
     strfmon_flag_specs, strfmon_flag_pairs,
     FMT_FLAG_ARG_CONVERT, 'w', '#', 'p', 0, 'L', 0,
     NULL, NULL
   }
 };
 
+/* Mingw specific format attributes ms_printf, ms_scanf, and ms_strftime.  */
+
+static const format_length_info ms_printf_length_specs[] =
+{
+  { "h", FMT_LEN_h, STD_C89, NULL, 0, 0 },
+  { "l", FMT_LEN_l, STD_C89, NULL, 0, 0 },
+  { "I32", FMT_LEN_l, STD_C89, "I64", FMT_LEN_ll, STD_C9L },
+  { "I", FMT_LEN_L, STD_C89, NULL, 0, 0 },
+  { NULL, 0, 0, NULL, 0, 0 }
+};
+
+static const format_flag_spec ms_printf_flag_specs[] =
+{
+  { ' ',  0, 0, N_("' ' flag"),        N_("the ' ' printf flag"),              STD_C89 },
+  { '+',  0, 0, N_("'+' flag"),        N_("the '+' printf flag"),              STD_C89 },
+  { '#',  0, 0, N_("'#' flag"),        N_("the '#' printf flag"),              STD_C89 },
+  { '0',  0, 0, N_("'0' flag"),        N_("the '0' printf flag"),              STD_C89 },
+  { '-',  0, 0, N_("'-' flag"),        N_("the '-' printf flag"),              STD_C89 },
+  { '\'', 0, 0, N_("''' flag"),        N_("the ''' printf flag"),              STD_EXT },
+  { 'w',  0, 0, N_("field width"),     N_("field width in printf format"),     STD_C89 },
+  { '.',  0, 0, N_("precision"),       N_("precision in printf format"),       STD_C89 },
+  { 'L',  0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_printf_flag_pairs[] =
+{
+  { ' ', '+', 1, 0   },
+  { '0', '-', 1, 0   },
+  { 0, 0, 0, 0 }
+};
+
+static const format_flag_spec ms_scanf_flag_specs[] =
+{
+  { '*',  0, 0, N_("assignment suppression"), N_("the assignment suppression scanf feature"), STD_C89 },
+  { 'a',  0, 0, N_("'a' flag"),               N_("the 'a' scanf flag"),                       STD_EXT },
+  { 'w',  0, 0, N_("field width"),            N_("field width in scanf format"),              STD_C89 },
+  { 'L',  0, 0, N_("length modifier"),        N_("length modifier in scanf format"),          STD_C89 },
+  { '\'', 0, 0, N_("''' flag"),               N_("the ''' scanf flag"),                       STD_EXT },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_scanf_flag_pairs[] =
+{
+  { '*', 'L', 0, 0 },
+  { 0, 0, 0, 0 }
+};
+
+static const format_flag_spec ms_strftime_flag_specs[] =
+{
+  { '_', 0,   0, N_("'_' flag"),     N_("the '_' strftime flag"),          STD_EXT },
+  { '-', 0,   0, N_("'-' flag"),     N_("the '-' strftime flag"),          STD_EXT },
+  { '0', 0,   0, N_("'0' flag"),     N_("the '0' strftime flag"),          STD_EXT },
+  { '^', 0,   0, N_("'^' flag"),     N_("the '^' strftime flag"),          STD_EXT },
+  { '#', 0,   0, N_("'#' flag"),     N_("the '#' strftime flag"),          STD_EXT },
+  { 'w', 0,   0, N_("field width"),  N_("field width in strftime format"), STD_EXT },
+  { 'E', 0,   0, N_("'E' modifier"), N_("the 'E' strftime modifier"),      STD_C99 },
+  { 'O', 0,   0, N_("'O' modifier"), N_("the 'O' strftime modifier"),      STD_C99 },
+  { 'O', 'o', 0, NULL,               N_("the 'O' modifier"),               STD_EXT },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+
+static const format_flag_pair ms_strftime_flag_pairs[] =
+{
+  { 'E', 'O', 0, 0 },
+  { '_', '-', 0, 0 },
+  { '_', '0', 0, 0 },
+  { '-', '0', 0, 0 },
+  { '^', '#', 0, 0 },
+  { 0, 0, 0, 0 }
+};
+
+static const format_char_info ms_print_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "di",  0, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  T89_V,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-wp0 +'",  "i",  NULL },
+  { "oxX", 0, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T89_V, BADLEN, BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "-wp0#",     "i",  NULL },
+  { "u",   0, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T89_V, BADLEN, BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "-wp0'",    "i",  NULL },
+  { "fgG", 0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "-wp0 +#'", "",   NULL },
+  { "eE",  0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "-wp0 +#",  "",   NULL },
+  { "c",   0, STD_C89, { T89_I,   BADLEN,  T89_S,  T94_WI,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "",   NULL },
+  { "s",   1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-wp",       "cR", NULL },
+  { "p",   1, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "c",  NULL },
+  { "n",   1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  BADLEN,  BADLEN, BADLEN,  T99_IM,  BADLEN,  BADLEN,  BADLEN }, "",          "W",  NULL },
+  /* X/Open conversion specifiers.  */
+  { "C",   0, STD_EXT, { TEX_WI,  BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "",   NULL },
+  { "S",   1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-wp",       "R",  NULL },
+  { NULL,  0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+static const format_char_info ms_scan_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "di",    1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  T89_V,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w'", "W",   NULL },
+  { "u",     1, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T89_V, BADLEN,  BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "*w'", "W",   NULL },
+  { "oxX",   1, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T89_V, BADLEN,  BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "efgEG", 1, STD_C89, { T89_F,   BADLEN,  BADLEN,  T89_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "*w'",  "W",   NULL },
+  { "c",     1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "cW",  NULL },
+  { "s",     1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "cW",  NULL },
+  { "[",     1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "cW[", NULL },
+  { "p",     2, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "n",     1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  BADLEN,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "",     "W",   NULL },
+  /* X/Open conversion specifiers.  */
+  { "C",     1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "S",     1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "W",   NULL },
+  { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+static const format_char_info ms_time_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "ABZab",		0, STD_C89, NOLENGTHS, "^#",     "",   NULL },
+  { "cx",		0, STD_C89, NOLENGTHS, "E",      "3",  NULL },
+  { "HIMSUWdmw",	0, STD_C89, NOLENGTHS, "-_0Ow",  "",   NULL },
+  { "j",		0, STD_C89, NOLENGTHS, "-_0Ow",  "o",  NULL },
+  { "p",		0, STD_C89, NOLENGTHS, "#",      "",   NULL },
+  { "X",		0, STD_C89, NOLENGTHS, "E",      "",   NULL },
+  { "y",		0, STD_C89, NOLENGTHS, "EO-_0w", "4",  NULL },
+  { "Y",		0, STD_C89, NOLENGTHS, "-_0EOw", "o",  NULL },
+  { "%",		0, STD_C89, NOLENGTHS, "",       "",   NULL },
+  /* C99 conversion specifiers.  */
+  { "z",		0, STD_C99, NOLENGTHS, "O",      "o",  NULL },
+  { NULL,		0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+const format_kind_info mingw_formatter_attributes[3] =
+{
+  { "ms_printf",   ms_printf_length_specs,  ms_print_char_table, " +#0-'I", NULL,
+    ms_printf_flag_specs, ms_printf_flag_pairs,
+    FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
+    'w', 0, 'p', 0, 'L', 0,
+    &integer_type_node, &integer_type_node
+  },
+  { "ms_scanf",    ms_printf_length_specs,   ms_scan_char_table,  "*'I", NULL,
+    ms_scanf_flag_specs, ms_scanf_flag_pairs,
+    FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
+    'w', 0, 0, '*', 'L', 'm',
+    NULL, NULL
+  },
+  { "ms_strftime", NULL,                 ms_time_char_table,  "_-0^#", "EO",
+    ms_strftime_flag_specs, ms_strftime_flag_pairs,
+    FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0, 0,
+    NULL, NULL
+  }
+};
+
+/* Default overrides for printf, scanf and strftime.  */
+const target_ovr_attr mingw_formatter_attribute_overrides[3] =
+{
+  { "ms_printf", "printf" },
+  { "ms_scanf", "scanf" },
+  { "ms_strftime", "strftime" }
+};
+
 /* This layer of indirection allows GCC to reassign format_types with
    new data if necessary, while still allowing the original data to be
    const.  */
@@ -2703,6 +2860,55 @@ init_dynamic_diag_info (void)
 extern const format_kind_info TARGET_FORMAT_TYPES[];
 #endif
 
+#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+extern const target_ovr_attr TARGET_OVERRIDES_FORMAT_ATTRIBUTES[];
+#endif
+
+/* Description of gnu specific format attributes reflected to
+   system format attribute types, as printf, scanf, strftime, and
+   strfmon.  */
+const target_ovr_attr gnu_target_overrides_format_attributes[] =
+{
+  { "gnu_printf",   "printf" },
+  { "gnu_scanf",    "scanf" },
+  { "gnu_strftime", "strftime" },
+  { "gnu_strfmon",  "strfmon" },
+  { NULL,           NULL }
+};
+
+static const char *
+replace_formatter_name_to_system_name (const char *attr_name)
+{
+  int i;
+
+  if (attr_name == NULL || *attr_name == 0 || strncmp (attr_name, "gcc_", 4) == 0)
+    return attr_name;
+
+#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+  /* Check if format attribute is overridden by target.  */
+  if (TARGET_OVERRIDES_FORMAT_ATTRIBUTES != NULL && TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT > 0)
+    {
+      for (i = 0; i < TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT; ++i)
+        {
+          if (strcmp (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src, attr_name) == 0)
+            return attr_name;
+          if (strcmp (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_dst, attr_name) == 0)
+            return TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src;
+        }
+    }
+#endif
+  /* Otherwise default to gnu formatter.  */
+  for (i = 0; gnu_target_overrides_format_attributes[i].named_attr_src != NULL; ++i)
+    {
+      if (strcmp (gnu_target_overrides_format_attributes[i].named_attr_src, attr_name) == 0)
+        return attr_name;
+      if (strcmp (gnu_target_overrides_format_attributes[i].named_attr_dst, attr_name) == 0)
+        return gnu_target_overrides_format_attributes[i].named_attr_src;
+    }
+
+  return attr_name;
+}
+
 /* Handle a "format" attribute; arguments as in
    struct attribute_spec.handler.  */
 tree
Index: gcc/gcc/c-format.h
===================================================================
--- gcc.orig/gcc/c-format.h
+++ gcc/gcc/c-format.h
@@ -306,4 +306,18 @@ typedef struct
 #define T_D128  &dfloat128_type_node
 #define TEX_D128 { STD_EXT, "_Decimal128", T_D128 }
 
+/* Structure describing the target specific to be override formatter
+   attributes, e.g. printf, scanf, etc.  This allows to support different
+   runtime-library specific formatter attributes to co-exist and defining
+   a default system version.
+   This type is used for the pointer variable TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+   refers to.  */
+typedef struct
+{
+  /* The name of the to be copied formatter attribute. */
+  const char *named_attr_src;
+  /* The name of the to be overridden formatter attribute. */
+  const char *named_attr_dst;
+} target_ovr_attr;
+
 #endif /* GCC_C_FORMAT_H */
Index: gcc/gcc/config/i386/i386.c
===================================================================
--- gcc.orig/gcc/config/i386/i386.c
+++ gcc/gcc/config/i386/i386.c
@@ -51,6 +51,7 @@ along with GCC; see the file COPYING3.  
 #include "df.h"
 #include "tm-constrs.h"
 #include "params.h"
+#include "c-format.h"
 
 static int x86_builtin_vectorization_cost (bool);
 
Index: gcc/gcc/config/i386/mingw32.h
===================================================================
--- gcc.orig/gcc/config/i386/mingw32.h
+++ gcc/gcc/config/i386/mingw32.h
@@ -143,6 +143,22 @@ do {						         \
    to register C++ static destructors.  */
 #define TARGET_CXX_USE_ATEXIT_FOR_CXA_ATEXIT hook_bool_void_true
 
+/* Contains a pointer to type target_ovr_attr defining the target specific
+   overrides of formatter attributs.  See format.h for structure definition.  */
+#undef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+#define TARGET_OVERRIDES_FORMAT_ATTRIBUTES mingw_formatter_attribute_overrides
+
+/* Specify the count of elements in TARGET_OVERRIDES_ATTRIBUTE.  */
+#undef TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT
+#define TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT 3
+
+/* MS specific format attributes for ms_printf, ms_scanf, ms_strftime.  */
+#undef TARGET_FORMAT_TYPES
+#define TARGET_FORMAT_TYPES mingw_formatter_attributes
+
+#undef TARGET_N_FORMAT_TYPES
+#define TARGET_N_FORMAT_TYPES 3
+
 /* JCR_SECTION works on mingw32.  */
 #undef TARGET_USE_JCR_SECTION
 #define TARGET_USE_JCR_SECTION 1
Index: gcc/gcc/doc/extend.texi
===================================================================
--- gcc.orig/gcc/doc/extend.texi
+++ gcc/gcc/doc/extend.texi
@@ -2198,13 +2198,17 @@ for consistency with the @code{printf} s
 @code{my_format}.
 
 The parameter @var{archetype} determines how the format string is
-interpreted, and should be @code{printf}, @code{scanf}, @code{strftime}
-or @code{strfmon}.  (You can also use @code{__printf__},
-@code{__scanf__}, @code{__strftime__} or @code{__strfmon__}.)  The
-parameter @var{string-index} specifies which argument is the format
-string argument (starting from 1), while @var{first-to-check} is the
-number of the first argument to check against the format string.  For
-functions where the arguments are not available to be checked (such as
+interpreted, and should be @code{printf}, @code{scanf}, @code{strftime},
+@code{gnu_printf}, @code{gnu_scanf}, @code{gnu_strftime} or
+@code{strfmon}.  (You can also use @code{__printf__},
+@code{__scanf__}, @code{__strftime__} or @code{__strfmon__}.)  On
+mingw targets there is also @code{ms_printf}, @code{ms_scanf}, and
+@code{ms_strftime} present. The none target specific formatters are
+always the variant of the system.  The parameter @var{string-index}
+specifies which argument is the format string argument (starting
+from 1), while @var{first-to-check} is the number of the first
+argument to check against the format string.  For functions
+where the arguments are not available to be checked (such as
 @code{vprintf}), specify the third parameter as zero.  In this case the
 compiler only checks the format string for consistency.  For
 @code{strftime} formats, the third parameter is required to be zero.
Index: gcc/gcc/doc/tm.texi
===================================================================
--- gcc.orig/gcc/doc/tm.texi
+++ gcc/gcc/doc/tm.texi
@@ -10303,6 +10303,18 @@ If defined, this macro is the number of 
 @code{TARGET_FORMAT_TYPES}.
 @end defmac
 
+@defmac TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+If defined, this macro is the name of a global variable containg
+target-specific format overrides for the @option{-Wformat} option. The
+default is to have no target-specific format overrides. This depends, that
+@code{TARGET_FORMAT_TYPES} is defined too.
+@end defmac
+
+@defmac TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT
+If defined, this macro is the number of entries in
+@code{}.
+@end defmac
+
 @deftypefn {Target Hook} bool TARGET_RELAXED_ORDERING
 If set to @code{true}, means that the target's memory model does not
 guarantee that loads which do not depend on one another will access
Index: gcc/gcc/testsuite/gcc.dg/format/sys_formatter.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/sys_formatter.c
@@ -0,0 +1,20 @@
+/* Test system default printf formatter specifiers.  */
+/* Origin: Kai Tietz <KaiTietz.@onevision.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu89" } */
+
+#include <format.h>
+
+__attribute__((format(printf, 1, 2))) void foo (const char *, ...);
+
+#ifdef _WIN32
+FORMATTER_TEXT	"%I64d %I32d %ld %d\n"
+#else
+FORMATTER_TEXT	"%lld %ld %ld %d"
+
+#endif
+
+void bar (long long v1, long v2, int v3)
+{
+  foo (FORMATTER_TEXT, v1, v2, v2, v3);
+}
=

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf   formatters to c-format.c
  2007-12-20 14:16             ` Joseph S. Myers
@ 2007-12-20 14:30               ` Kai Tietz
  2007-12-21 14:03               ` Kai Tietz
  1 sibling, 0 replies; 61+ messages in thread
From: Kai Tietz @ 2007-12-20 14:30 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: Danny Smith, GCC Patches, NightStrike

"Joseph S. Myers" wrote on 20.12.2007 14:56:42:

> On Thu, 20 Dec 2007, Kai Tietz wrote:
> 
> > I moved the test case to gcc.dg/format as mentioned. No until now I 
didn't 
> > ran all test-case for this. But I am certain, we need to re-arrange 
things 
> > here.
> 
> I will await a patch with such rearrangements, confirmed to pass all 
tests 
> on both MinGW and non-MinGW, and with new tests added to test that all 
the 
> standard and GNU features not supported by Windows receive proper 
> diagnostics (for example, a test that %ll gets a diagnostic on Windows), 

> before attempting any detailed review.

Fine. I am working on that, but may it will take till January (reasoned by 
vacation).

> I also await the answer to my question:
> 
> Does the set of format features supported on Windows depend at all on 
the 
> version of Windows?  If so, for what version of Windows did you prepare 
> the tables of supported features?

It does not depend on the version of Windows, but on the version of the MS 
runtime. E.g. the standard runtime 'msvcrt.dll' does not support the 'll' 
proper, but the the 'msvcr80.dll' (the new runtime of MS which is not part 
of the OS itself) supports it. Reasoned by the fact, that mingw just 
supports the 'msvcrt.dll' variant (it is part of the OS), I think gcc 
should just support this one.

> Were the tables prepared by examining Windows documentation, or by 
running 
> tests on Windows?  Either would be OK, but one or the other must have 
been 
> done for every feature and combination in the tables you have of Windows 

> formats, and for verifying that the C99 features removed as not 
supported 
> on Windows are indeed not supported.

I took the information about the tables out of the msdn library 
documentation and tested it by doing a canadian cross on gcc for the 
64-bit mingw. I agree, that there should be a test case probing the 
supported and non-supported formatting rules (as e.g. C99).

Cheers,
 i.A. Kai Tietz

|  (\_/)  This is Bunny. Copy and paste Bunny
| (='.'=) into your signature to help him gain
| (")_(") world domination.

------------------------------------------------------------------------------------------
  OneVision Software Entwicklungs GmbH & Co. KG
  Dr.-Leo-Ritter-Straße 9 - 93049 Regensburg
  Tel: +49.(0)941.78004.0 - Fax: +49.(0)941.78004.489 - www.OneVision.com
  Commerzbank Regensburg - BLZ 750 400 62 - Konto 6011050
  Handelsregister: HRA 6744, Amtsgericht Regensburg
  Komplementärin: OneVision Software Entwicklungs Verwaltungs GmbH
  Dr.-Leo-Ritter-Straße 9 – 93049 Regensburg
  Handelsregister: HRB 8932, Amtsgericht Regensburg - Geschäftsführer: 
Ulrike Döhler, Manuela Kluger



^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf   formatters to c-format.c
  2007-12-20 13:00           ` Kai Tietz
@ 2007-12-20 14:16             ` Joseph S. Myers
  2007-12-20 14:30               ` Kai Tietz
  2007-12-21 14:03               ` Kai Tietz
  0 siblings, 2 replies; 61+ messages in thread
From: Joseph S. Myers @ 2007-12-20 14:16 UTC (permalink / raw)
  To: Kai Tietz; +Cc: Danny Smith, GCC Patches, NightStrike

On Thu, 20 Dec 2007, Kai Tietz wrote:

> I moved the test case to gcc.dg/format as mentioned. No until now I didn't 
> ran all test-case for this. But I am certain, we need to re-arrange things 
> here.

I will await a patch with such rearrangements, confirmed to pass all tests 
on both MinGW and non-MinGW, and with new tests added to test that all the 
standard and GNU features not supported by Windows receive proper 
diagnostics (for example, a test that %ll gets a diagnostic on Windows), 
before attempting any detailed review.

I also await the answer to my question:

Does the set of format features supported on Windows depend at all on the 
version of Windows?  If so, for what version of Windows did you prepare 
the tables of supported features?

Were the tables prepared by examining Windows documentation, or by running 
tests on Windows?  Either would be OK, but one or the other must have been 
done for every feature and combination in the tables you have of Windows 
formats, and for verifying that the C99 features removed as not supported 
on Windows are indeed not supported.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf  formatters to c-format.c
  2007-12-18 21:14         ` Danny Smith
@ 2007-12-20 13:00           ` Kai Tietz
  2007-12-20 14:16             ` Joseph S. Myers
  0 siblings, 1 reply; 61+ messages in thread
From: Kai Tietz @ 2007-12-20 13:00 UTC (permalink / raw)
  To: Danny Smith; +Cc: GCC Patches, Joseph S. Myers, NightStrike

[-- Attachment #1: Type: text/plain, Size: 1791 bytes --]

Hello Danny and Joseph,

Thank you for your comments.
I moved the test case to gcc.dg/format as mentioned. No until now I didn't 
ran all test-case for this. But I am certain, we need to re-arrange things 
here.

> Some quibles:
> 
> MS uses the "%I" flag as a length specifier for size_t/ptrdiff_t
> http://msdn2.microsoft.com/en-us/library/tcxf1dw6(VS.80).aspx

Ok, I changed the formatter defines for this. I reused the .._L flag for 
the 'I' type, because 'L' is no valid length specifier for MS at all. I am 
not quite sure if this ok, but it seems to work.

> Your patch still retains "I" in its gnu  extension sense.
> MS printf will get confused by it.
I removed the I flag definition now AFAIS.
> TODO:
>  MS printf does not handle "%hh" or "%ll" correctly and does not even
> recognize long double.

I disabled the hh and removed the floating point use of 'll'. The .._ll 
flag remains for the I64 specifier.

> Also what about  MS extension %hc' and '%lc'.
This I added to formatter rules.

Cheers,
 i.A. Kai Tietz



|  (\_/)  This is Bunny. Copy and paste Bunny
| (='.'=) into your signature to help him gain
| (")_(") world domination.

------------------------------------------------------------------------------------------
  OneVision Software Entwicklungs GmbH & Co. KG
  Dr.-Leo-Ritter-Straße 9 - 93049 Regensburg
  Tel: +49.(0)941.78004.0 - Fax: +49.(0)941.78004.489 - www.OneVision.com
  Commerzbank Regensburg - BLZ 750 400 62 - Konto 6011050
  Handelsregister: HRA 6744, Amtsgericht Regensburg
  Komplementärin: OneVision Software Entwicklungs Verwaltungs GmbH
  Dr.-Leo-Ritter-Straße 9 – 93049 Regensburg
  Handelsregister: HRB 8932, Amtsgericht Regensburg - Geschäftsführer: 
Ulrike Döhler, Manuela Kluger


[-- Attachment #2: ext_formatter.txt --]
[-- Type: text/plain, Size: 19661 bytes --]

Index: gcc/gcc/c-format.c
===================================================================
--- gcc.orig/gcc/c-format.c
+++ gcc/gcc/c-format.c
@@ -80,7 +80,7 @@ static bool check_format_string (tree ar
 				 int flags, bool *no_add_attrs);
 static bool get_constant (tree expr, unsigned HOST_WIDE_INT *value,
 			  int validated_p);
-
+static const char *replace_formatter_name_to_system_name (const char *attr_name);
 
 /* Handle a "format_arg" attribute; arguments as in
    struct attribute_spec.handler.  */
@@ -191,6 +191,8 @@ decode_format_attr (tree args, function_
     {
       const char *p = IDENTIFIER_POINTER (format_type_id);
 
+      p = replace_formatter_name_to_system_name (p);
+
       info->format_type = decode_format_type (p);
 
       if (info->format_type == format_type_error)
@@ -715,7 +717,7 @@ static const format_char_info monetary_c
 /* This must be in the same order as enum format_type.  */
 static const format_kind_info format_types_orig[] =
 {
-  { "printf",   printf_length_specs,  print_char_table, " +#0-'I", NULL,
+  { "gnu_printf",   printf_length_specs,  print_char_table, " +#0-'I", NULL,
     printf_flag_specs, printf_flag_pairs,
     FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
     'w', 0, 'p', 0, 'L', 0,
@@ -757,18 +759,18 @@ static const format_kind_info format_typ
     0, 0, 0, 0, 0, 0,
     NULL, NULL
   },
-  { "scanf",    scanf_length_specs,   scan_char_table,  "*'I", NULL,
+  { "gnu_scanf",    scanf_length_specs,   scan_char_table,  "*'I", NULL,
     scanf_flag_specs, scanf_flag_pairs,
     FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
     'w', 0, 0, '*', 'L', 'm',
     NULL, NULL
   },
-  { "strftime", NULL,                 time_char_table,  "_-0^#", "EO",
+  { "gnu_strftime", NULL,                 time_char_table,  "_-0^#", "EO",
     strftime_flag_specs, strftime_flag_pairs,
     FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0, 0,
     NULL, NULL
   },
-  { "strfmon",  strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
+  { "gnu_strfmon",  strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
     strfmon_flag_specs, strfmon_flag_pairs,
     FMT_FLAG_ARG_CONVERT, 'w', '#', 'p', 0, 'L', 0,
     NULL, NULL
@@ -2703,6 +2705,55 @@ init_dynamic_diag_info (void)
 extern const format_kind_info TARGET_FORMAT_TYPES[];
 #endif
 
+#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+extern const target_ovr_attr TARGET_OVERRIDES_FORMAT_ATTRIBUTES[];
+#endif
+
+/* Description of gnu specific format attributes reflected to
+   system format attribute types, as printf, scanf, strftime, and
+   strfmon.  */
+const target_ovr_attr gnu_target_overrides_format_attributes[] =
+{
+  { "gnu_printf",   "printf" },
+  { "gnu_scanf",    "scanf" },
+  { "gnu_strftime", "strftime" },
+  { "gnu_strfmon",  "strfmon" }
+  { NULL,           NULL }
+};
+
+static const char *
+replace_formatter_name_to_system_name (const char *attr_name)
+{
+  int i;
+
+  if (attr_name == NULL || *attr_name == 0 || strncmp (attr_name, "gcc_", 4) == 0)
+    return attr_name;
+
+#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+  /* Check if format attribute is overridden by target.  */
+  if (TARGET_OVERRIDES_FORMAT_ATTRIBUTES != NULL && TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT > 0)
+    {
+      for (i = 0; i < TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT; ++i)
+        {
+          if (strcmp (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src, attr_name) == 0)
+            return attr_name;
+          if (strcmp (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_dst, attr_name) == 0)
+            return TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src;
+        }
+    }
+#endif
+  /* Otherwise default to gnu formatter.  */
+  for (i = 0; gnu_target_overrides_format_attributes[i].named_attr_src != NULL; ++i)
+    {
+      if (strcmp (gnu_target_overrides_format_attributes[i].named_attr_src, attr_name) == 0)
+        return attr_name;
+      if (strcmp (gnu_target_overrides_format_attributes[i].named_attr_dst, attr_name) == 0)
+        return gnu_target_overrides_format_attributes[i].named_attr_src;
+    }
+
+  return attr_name;
+}
+
 /* Handle a "format" attribute; arguments as in
    struct attribute_spec.handler.  */
 tree
Index: gcc/gcc/c-format.h
===================================================================
--- gcc.orig/gcc/c-format.h
+++ gcc/gcc/c-format.h
@@ -306,4 +306,18 @@ typedef struct
 #define T_D128  &dfloat128_type_node
 #define TEX_D128 { STD_EXT, "_Decimal128", T_D128 }
 
+/* Structure describing the target specific to be override formatter
+   attributes, e.g. printf, scanf, etc.  This allows to support different
+   runtime-library specific formatter attributes to co-exist and defining
+   a default system version.
+   This type is used for the pointer variable TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+   refers to.  */
+typedef struct
+{
+  /* The name of the to be copied formatter attribute. */
+  const char *named_attr_src;
+  /* The name of the to be overridden formatter attribute. */
+  const char *named_attr_dst;
+} target_ovr_attr;
+
 #endif /* GCC_C_FORMAT_H */
Index: gcc/gcc/config/i386/i386.c
===================================================================
--- gcc.orig/gcc/config/i386/i386.c
+++ gcc/gcc/config/i386/i386.c
@@ -51,6 +51,7 @@ along with GCC; see the file COPYING3.  
 #include "df.h"
 #include "tm-constrs.h"
 #include "params.h"
+#include "c-format.h"
 
 static int x86_builtin_vectorization_cost (bool);
 
@@ -1745,6 +1746,162 @@ static const char * const x86_64_reg_cla
 static REAL_VALUE_TYPE ext_80387_constants_table [5];
 static bool ext_80387_constants_init = 0;
 
+/* Mingw specific format attributes ms_printf, ms_scanf, and ms_strftime.  */
+
+static const format_length_info ms_printf_length_specs[] =
+{
+  { "h", FMT_LEN_h, STD_C89, NULL, 0, 0 },
+  { "l", FMT_LEN_l, STD_C89, NULL, 0, 0 },
+  { "I32", FMT_LEN_l, STD_C89, "I64", FMT_LEN_ll, STD_C9L },
+  { "I", FMT_LEN_L, STD_C89, NULL, 0, 0 },
+  { NULL, 0, 0, NULL, 0, 0 }
+};
+
+static const format_flag_spec ms_printf_flag_specs[] =
+{
+  { ' ',  0, 0, N_("' ' flag"),        N_("the ' ' printf flag"),              STD_C89 },
+  { '+',  0, 0, N_("'+' flag"),        N_("the '+' printf flag"),              STD_C89 },
+  { '#',  0, 0, N_("'#' flag"),        N_("the '#' printf flag"),              STD_C89 },
+  { '0',  0, 0, N_("'0' flag"),        N_("the '0' printf flag"),              STD_C89 },
+  { '-',  0, 0, N_("'-' flag"),        N_("the '-' printf flag"),              STD_C89 },
+  { '\'', 0, 0, N_("''' flag"),        N_("the ''' printf flag"),              STD_EXT },
+  { 'w',  0, 0, N_("field width"),     N_("field width in printf format"),     STD_C89 },
+  { '.',  0, 0, N_("precision"),       N_("precision in printf format"),       STD_C89 },
+  { 'L',  0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_printf_flag_pairs[] =
+{
+  { ' ', '+', 1, 0   },
+  { '0', '-', 1, 0   },
+  { '0', 'p', 1, 'i' },
+  { 0, 0, 0, 0 }
+};
+
+static const format_flag_spec ms_scanf_flag_specs[] =
+{
+  { '*',  0, 0, N_("assignment suppression"), N_("the assignment suppression scanf feature"), STD_C89 },
+  { 'a',  0, 0, N_("'a' flag"),               N_("the 'a' scanf flag"),                       STD_EXT },
+  { 'w',  0, 0, N_("field width"),            N_("field width in scanf format"),              STD_C89 },
+  { 'L',  0, 0, N_("length modifier"),        N_("length modifier in scanf format"),          STD_C89 },
+  { '\'', 0, 0, N_("''' flag"),               N_("the ''' scanf flag"),                       STD_EXT },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_scanf_flag_pairs[] =
+{
+  { '*', 'L', 0, 0 },
+  { 0, 0, 0, 0 }
+};
+
+static const format_flag_spec ms_strftime_flag_specs[] =
+{
+  { '_', 0,   0, N_("'_' flag"),     N_("the '_' strftime flag"),          STD_EXT },
+  { '-', 0,   0, N_("'-' flag"),     N_("the '-' strftime flag"),          STD_EXT },
+  { '0', 0,   0, N_("'0' flag"),     N_("the '0' strftime flag"),          STD_EXT },
+  { '^', 0,   0, N_("'^' flag"),     N_("the '^' strftime flag"),          STD_EXT },
+  { '#', 0,   0, N_("'#' flag"),     N_("the '#' strftime flag"),          STD_EXT },
+  { 'w', 0,   0, N_("field width"),  N_("field width in strftime format"), STD_EXT },
+  { 'E', 0,   0, N_("'E' modifier"), N_("the 'E' strftime modifier"),      STD_C99 },
+  { 'O', 0,   0, N_("'O' modifier"), N_("the 'O' strftime modifier"),      STD_C99 },
+  { 'O', 'o', 0, NULL,               N_("the 'O' modifier"),               STD_EXT },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+
+static const format_flag_pair ms_strftime_flag_pairs[] =
+{
+  { 'E', 'O', 0, 0 },
+  { '_', '-', 0, 0 },
+  { '_', '0', 0, 0 },
+  { '-', '0', 0, 0 },
+  { '^', '#', 0, 0 },
+  { 0, 0, 0, 0 }
+};
+
+static const format_char_info ms_print_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "di",  0, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  T89_V,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-wp0 +'",  "i",  NULL },
+  { "oxX", 0, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T89_V, BADLEN, BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "-wp0#",     "i",  NULL },
+  { "u",   0, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T89_V, BADLEN, BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "-wp0'",    "i",  NULL },
+  { "fgG", 0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "-wp0 +#'", "",   NULL },
+  { "eE",  0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "-wp0 +#",  "",   NULL },
+  { "c",   0, STD_C89, { T89_I,   BADLEN,  T89_S,  T94_WI,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "",   NULL },
+  { "s",   1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-wp",       "cR", NULL },
+  { "p",   1, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "c",  NULL },
+  { "n",   1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  BADLEN,  BADLEN, BADLEN,  T99_IM,  BADLEN,  BADLEN,  BADLEN }, "",          "W",  NULL },
+  /* X/Open conversion specifiers.  */
+  { "C",   0, STD_EXT, { TEX_WI,  BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "",   NULL },
+  { "S",   1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-wp",       "R",  NULL },
+  { NULL,  0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+static const format_char_info ms_scan_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "di",    1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  T89_V,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w'", "W",   NULL },
+  { "u",     1, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T89_V, BADLEN,  BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "*w'", "W",   NULL },
+  { "oxX",   1, STD_C89, { T89_UI,  BADLEN,  T89_US,  T89_UL,  T9L_ULL, T89_V, BADLEN,  BADLEN, BADLEN, BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "efgEG", 1, STD_C89, { T89_F,   BADLEN,  BADLEN,  T89_D,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN, BADLEN, BADLEN }, "*w'",  "W",   NULL },
+  { "c",     1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "cW",  NULL },
+  { "s",     1, STD_C89, { T89_C,   BADLEN,  T89_S,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "cW",  NULL },
+  { "[",     1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "cW[", NULL },
+  { "p",     2, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "n",     1, STD_C89, { T89_I,   BADLEN,  T89_S,   T89_L,   T9L_LL,  BADLEN,  BADLEN, BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "",     "W",   NULL },
+  /* X/Open conversion specifiers.  */
+  { "C",     1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "S",     1, STD_EXT, { TEX_W,   BADLEN,  T89_S,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "W",   NULL },
+  { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+static const format_char_info ms_time_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "ABZab",		0, STD_C89, NOLENGTHS, "^#",     "",   NULL },
+  { "cx",		0, STD_C89, NOLENGTHS, "E",      "3",  NULL },
+  { "HIMSUWdmw",	0, STD_C89, NOLENGTHS, "-_0Ow",  "",   NULL },
+  { "j",		0, STD_C89, NOLENGTHS, "-_0Ow",  "o",  NULL },
+  { "p",		0, STD_C89, NOLENGTHS, "#",      "",   NULL },
+  { "X",		0, STD_C89, NOLENGTHS, "E",      "",   NULL },
+  { "y",		0, STD_C89, NOLENGTHS, "EO-_0w", "4",  NULL },
+  { "Y",		0, STD_C89, NOLENGTHS, "-_0EOw", "o",  NULL },
+  { "%",		0, STD_C89, NOLENGTHS, "",       "",   NULL },
+  /* C99 conversion specifiers.  */
+  { "z",		0, STD_C99, NOLENGTHS, "O",      "o",  NULL },
+  { NULL,		0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+const format_kind_info mingw_formatter_attributes[3] =
+{
+  { "ms_printf",   ms_printf_length_specs,  ms_print_char_table, " +#0-'I", NULL,
+    ms_printf_flag_specs, ms_printf_flag_pairs,
+    FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
+    'w', 0, 'p', 0, 'L',
+    &integer_type_node, &integer_type_node
+  },
+  { "ms_scanf",    ms_printf_length_specs,   ms_scan_char_table,  "*'I", NULL,
+    ms_scanf_flag_specs, ms_scanf_flag_pairs,
+    FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
+    'w', 0, 0, '*', 'L',
+    NULL, NULL
+  },
+  { "ms_strftime", NULL,                 ms_time_char_table,  "_-0^#", "EO",
+    ms_strftime_flag_specs, ms_strftime_flag_pairs,
+    FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0,
+    NULL, NULL
+  }
+};
+
+/* Default overrides for printf, scanf and strftime.  */
+const target_ovr_attr mingw_formatter_attribute_overrides[3] =
+{
+  { "ms_printf", "printf" },
+  { "ms_scanf", "scanf" },
+  { "ms_strftime", "strftime" }
+};
+
 \f
 static struct machine_function * ix86_init_machine_status (void);
 static rtx ix86_function_value (const_tree, const_tree, bool);
Index: gcc/gcc/config/i386/mingw32.h
===================================================================
--- gcc.orig/gcc/config/i386/mingw32.h
+++ gcc/gcc/config/i386/mingw32.h
@@ -143,6 +143,22 @@ do {						         \
    to register C++ static destructors.  */
 #define TARGET_CXX_USE_ATEXIT_FOR_CXA_ATEXIT hook_bool_void_true
 
+/* Contains a pointer to type target_ovr_attr defining the target specific
+   overrides of formatter attributs.  See format.h for structure definition.  */
+#undef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+#define TARGET_OVERRIDES_FORMAT_ATTRIBUTES mingw_formatter_attribute_overrides
+
+/* Specify the count of elements in TARGET_OVERRIDES_ATTRIBUTE.  */
+#undef TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT
+#define TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT 3
+
+/* MS specific format attributes for ms_printf, ms_scanf, ms_strftime.  */
+#undef TARGET_FORMAT_TYPES
+#define TARGET_FORMAT_TYPES mingw_formatter_attributes
+
+#undef TARGET_N_FORMAT_TYPES
+#define TARGET_N_FORMAT_TYPES 3
+
 /* JCR_SECTION works on mingw32.  */
 #undef TARGET_USE_JCR_SECTION
 #define TARGET_USE_JCR_SECTION 1
Index: gcc/gcc/doc/extend.texi
===================================================================
--- gcc.orig/gcc/doc/extend.texi
+++ gcc/gcc/doc/extend.texi
@@ -2198,13 +2198,17 @@ for consistency with the @code{printf} s
 @code{my_format}.
 
 The parameter @var{archetype} determines how the format string is
-interpreted, and should be @code{printf}, @code{scanf}, @code{strftime}
-or @code{strfmon}.  (You can also use @code{__printf__},
-@code{__scanf__}, @code{__strftime__} or @code{__strfmon__}.)  The
-parameter @var{string-index} specifies which argument is the format
-string argument (starting from 1), while @var{first-to-check} is the
-number of the first argument to check against the format string.  For
-functions where the arguments are not available to be checked (such as
+interpreted, and should be @code{printf}, @code{scanf}, @code{strftime},
+@code{gnu_printf}, @code{gnu_scanf}, @code{gnu_strftime} or
+@code{strfmon}.  (You can also use @code{__printf__},
+@code{__scanf__}, @code{__strftime__} or @code{__strfmon__}.)  On
+mingw targets there is also @code{ms_printf}, @code{ms_scanf}, and
+@code{ms_strftime} present. The none target specific formatters are
+always the variant of the system.  The parameter @var{string-index}
+specifies which argument is the format string argument (starting
+from 1), while @var{first-to-check} is the number of the first
+argument to check against the format string.  For functions
+where the arguments are not available to be checked (such as
 @code{vprintf}), specify the third parameter as zero.  In this case the
 compiler only checks the format string for consistency.  For
 @code{strftime} formats, the third parameter is required to be zero.
Index: gcc/gcc/doc/tm.texi
===================================================================
--- gcc.orig/gcc/doc/tm.texi
+++ gcc/gcc/doc/tm.texi
@@ -10303,6 +10303,18 @@ If defined, this macro is the number of 
 @code{TARGET_FORMAT_TYPES}.
 @end defmac
 
+@defmac TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+If defined, this macro is the name of a global variable containg
+target-specific format overrides for the @option{-Wformat} option. The
+default is to have no target-specific format overrides. This depends, that
+@code{TARGET_FORMAT_TYPES} is defined too.
+@end defmac
+
+@define TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT
+If defined, this macro is the number of entries in
+@code{}.
+@end defmac
+
 @deftypefn {Target Hook} bool TARGET_RELAXED_ORDERING
 If set to @code{true}, means that the target's memory model does not
 guarantee that loads which do not depend on one another will access
Index: gcc/gcc/testsuite/gcc.dg/format/sys_formatter.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/format/sys_formatter.c
@@ -0,0 +1,20 @@
+/* Test system default printf formatter specifiers.  */
+/* Origin: Kai Tietz <KaiTietz.@onevision.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu89" } */
+
+#include <format.h>
+
+__attribute__((format(printf, 1, 2))) void foo (const char *, ...);
+
+#ifdef _WIN32
+FORMATTER_TEXT	"%I64d %I32d %ld %d\n"
+#else
+FORMATTER_TEXT	"%lld %ld %ld %d"
+
+#endif
+
+void bar (long long v1, long v2, int v3)
+{
+  foo (FORMATTER_TEXT, v1, v2, v2, v3);
+}
=

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf formatters to c-format.c
  2007-12-18 14:06       ` Kai Tietz
  2007-12-18 16:30         ` Joseph S. Myers
@ 2007-12-18 21:14         ` Danny Smith
  2007-12-20 13:00           ` Kai Tietz
  1 sibling, 1 reply; 61+ messages in thread
From: Danny Smith @ 2007-12-18 21:14 UTC (permalink / raw)
  To: Kai Tietz; +Cc: Joseph S. Myers, GCC Patches, NightStrike

Hello Kai

> This patch is tested for *-pc-mingw32 (using MS %I32 and %I64) and for
> i686-pc-cygwin (for the gnu variant).
>
> ChangeLog:
>
> 2007-12-18  Kai Tietz   <kai.tietz@onevision.com>
>
>         * gcc/doc/extend.texi: Extent user description.
>         * gcc/doc/tm.texi: (TARGET_OVERRIDES_FORMAT_ATTRIBUTES,
>         TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT): New.
>         * gcc/c-format.c: (replace_formatter_name_to_system_name): New
>         method to map target format attributes as system.
>         (decode_format_attr): Translate system format attribute names.
>         (format_types_orig): Prefix gnu attributes by "gnu_".
>         (ARGET_OVERRIDES_FORMAT_ATTRIBUTES): New extern for
>         target specific system format attribute override.
>         (gnu_target_overrides_format_attributes): Default overrides for
> gnu.
>         * gcc/c-format.h: (target_ovr_attr): New type for system attribute
>         mapping.
>         * gcc/config/i386/mingw32.h: (TARGET_OVERRIDES_FORMAT_ATTRIBUTES,
>         TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT,
>         TARGET_FORMAT_TYPES, TARGET_N_FORMAT_TYPES): New.
>         * gcc/config/i386/i386.c: Add ms-formatter definitions.
>         * gcc/testsuite/gcc.dg/sys_formatter.c: New test case.
>

Some quibles:

MS uses the "%I" flag as a length specifier for size_t/ptrdiff_t
http://msdn2.microsoft.com/en-us/library/tcxf1dw6(VS.80).aspx

Your patch still retains "I" in its gnu  extension sense.
MS printf will get confused by it.

TODO:
 MS printf does not handle "%hh" or "%ll" correctly and does not even
recognize long double.

Also what about  MS extension %hc' and '%lc'.

Danny

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf   formatters to c-format.c
  2007-12-18 14:06       ` Kai Tietz
@ 2007-12-18 16:30         ` Joseph S. Myers
  2007-12-18 21:14         ` Danny Smith
  1 sibling, 0 replies; 61+ messages in thread
From: Joseph S. Myers @ 2007-12-18 16:30 UTC (permalink / raw)
  To: Kai Tietz; +Cc: GCC Patches, NightStrike

On Tue, 18 Dec 2007, Kai Tietz wrote:

> I added updated the patch against current head version of gcc and add a 
> test-case for the common case that the system (crt) version of formatter 
> is used. For mingw targets there is no %lld formatter existing. Instead MS 
> functions are using %I64d and %I64d. This patch additionally allows the 
> user to define a alternative formatter beside the system one for i386 
> targets. The default formatters are named "gnu_*" and the MS specific 
> "ms_*".
> 
> This patch is tested for *-pc-mingw32 (using MS %I32 and %I64) and for 
> i686-pc-cygwin (for the gnu variant).

The new test needs to go in gcc.dg/format, and where possible tests should 
use format.h.  In addition to testing the new Windows format, you need to 
test that all the standard and GNU features not supported by Windows 
receive proper diagnostics.

Did you really get clean test results for all the existing testcases in 
gcc.dg/format on MinGW?  Since they use system functions such as printf, 
I'd have expected many failures as they test features not supported by 
Windows.  This would require appropriate arrangements for the functions to 
be declared with the gnu_* attributes on Windows, or to be mapped with 
#define to functions so declared (as the minimal change to keep the tests 
working) for most tests, with separate Windows-only tests that appropriate 
features are accepted and rejected for the system and ms_ formats.

Does the set of format features supported on Windows depend at all on the 
version of Windows?  If so, for what version of Windows did you prepare 
the tables of supported features?

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf  formatters to c-format.c
  2007-12-05 22:53     ` Joseph S. Myers
@ 2007-12-18 14:06       ` Kai Tietz
  2007-12-18 16:30         ` Joseph S. Myers
  2007-12-18 21:14         ` Danny Smith
  0 siblings, 2 replies; 61+ messages in thread
From: Kai Tietz @ 2007-12-18 14:06 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: GCC Patches, NightStrike

[-- Attachment #1: Type: text/plain, Size: 4759 bytes --]

Hi Joseph,

> On Wed, 5 Dec 2007, NightStrike wrote:
> 
> > On 12/4/07, Joseph S. Myers <joseph@codesourcery.com> wrote:
> > > On Tue, 4 Dec 2007, NightStrike wrote:
> > >
> > > > http://gcc.gnu.org/ml/gcc-patches/2007-04/msg00767.html
> > > >
> > > > This old thread is in need of review to help the x86_64-pc-mingw32
> > > > port of gcc.  It's been about 8 months so far.  Any takers to 
review
> > > > the patch?
> > >
> > > If there is a patch with full testcases, please point to it - that 
patch
> > > appears to be one without testcases, and so not ready for review.
> > 
> > I think Kai was waiting until your review before making the testcases.
> >  Can you at least evaluate what's there already?
> 
> No, in the original discussions leading to that patch we already 
discussed 
> the general nature of what the feature should look like at the language 
> level, and assessing whether the patch meets that requires testcases 
(and 
> changes to existing testcases) that provide proper coverage of the new 
and 
> existing features and leave all the format checking tests passing on 
both 
> MinGW and non-MinGW targets.
> 
> If after reviewing testcases and code I suspect problems in areas not 
> covered by the tests I build the compiler with a patch when reviewing it 

> and try my own tests, but the basic tests to provide thorough coverage 
of 
> the patch are the responsibility of the patch submitter.  This (and 
> diagnostic-related patches in general) is the sort of patch I review 
> primarily by examining the testcases to see if I agree with the 
> diagnostics asserted to be present or absent and that the testcases 
appear 
> to cover the feature as described, and only secondarily if the testcases 

> appear correct and adequate by examining the implementation.
> 
> I made clear on 25 April 
> <http://gcc.gnu.org/ml/gcc-patches/2007-04/msg01734.html> that I was 
> awaiting testsuite changes.  I do not think there is any open question 
> regarding the principle of the feature (where partial patches might be 
of 
> value in assessing how worthwhile a feature is bearing in mind the cost 
of 
> the implementation); what needs review is the quality of an 
> implementation, and that needs a complete patch submission.

I added updated the patch against current head version of gcc and add a 
test-case for the common case that the system (crt) version of formatter 
is used. For mingw targets there is no %lld formatter existing. Instead MS 
functions are using %I64d and %I64d. This patch additionally allows the 
user to define a alternative formatter beside the system one for i386 
targets. The default formatters are named "gnu_*" and the MS specific 
"ms_*".

This patch is tested for *-pc-mingw32 (using MS %I32 and %I64) and for 
i686-pc-cygwin (for the gnu variant).

ChangeLog:

2007-12-18  Kai Tietz   <kai.tietz@onevision.com>

        * gcc/doc/extend.texi: Extent user description.
        * gcc/doc/tm.texi: (TARGET_OVERRIDES_FORMAT_ATTRIBUTES,
        TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT): New.
        * gcc/c-format.c: (replace_formatter_name_to_system_name): New
        method to map target format attributes as system.
        (decode_format_attr): Translate system format attribute names.
        (format_types_orig): Prefix gnu attributes by "gnu_".
        (ARGET_OVERRIDES_FORMAT_ATTRIBUTES): New extern for
        target specific system format attribute override.
        (gnu_target_overrides_format_attributes): Default overrides for 
gnu.
        * gcc/c-format.h: (target_ovr_attr): New type for system attribute
        mapping.
        * gcc/config/i386/mingw32.h: (TARGET_OVERRIDES_FORMAT_ATTRIBUTES,
        TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT,
        TARGET_FORMAT_TYPES, TARGET_N_FORMAT_TYPES): New.
        * gcc/config/i386/i386.c: Add ms-formatter definitions.
        * gcc/testsuite/gcc.dg/sys_formatter.c: New test case.


Cheers,
 i.A. Kai Tietz



|  (\_/)  This is Bunny. Copy and paste Bunny
| (='.'=) into your signature to help him gain
| (")_(") world domination.

------------------------------------------------------------------------------------------
  OneVision Software Entwicklungs GmbH & Co. KG
  Dr.-Leo-Ritter-Straße 9 - 93049 Regensburg
  Tel: +49.(0)941.78004.0 - Fax: +49.(0)941.78004.489 - www.OneVision.com
  Commerzbank Regensburg - BLZ 750 400 62 - Konto 6011050
  Handelsregister: HRA 6744, Amtsgericht Regensburg
  Komplementärin: OneVision Software Entwicklungs Verwaltungs GmbH
  Dr.-Leo-Ritter-Straße 9 – 93049 Regensburg
  Handelsregister: HRB 8932, Amtsgericht Regensburg - Geschäftsführer: 
Ulrike Döhler, Manuela Kluger


[-- Attachment #2: ext_formatter.txt --]
[-- Type: text/plain, Size: 20596 bytes --]

Index: gcc/gcc/c-format.c
===================================================================
--- gcc.orig/gcc/c-format.c
+++ gcc/gcc/c-format.c
@@ -80,7 +80,7 @@ static bool check_format_string (tree ar
 				 int flags, bool *no_add_attrs);
 static bool get_constant (tree expr, unsigned HOST_WIDE_INT *value,
 			  int validated_p);
-
+static const char *replace_formatter_name_to_system_name (const char *attr_name);
 
 /* Handle a "format_arg" attribute; arguments as in
    struct attribute_spec.handler.  */
@@ -191,6 +191,8 @@ decode_format_attr (tree args, function_
     {
       const char *p = IDENTIFIER_POINTER (format_type_id);
 
+      p = replace_formatter_name_to_system_name (p);
+
       info->format_type = decode_format_type (p);
 
       if (info->format_type == format_type_error)
@@ -715,7 +717,7 @@ static const format_char_info monetary_c
 /* This must be in the same order as enum format_type.  */
 static const format_kind_info format_types_orig[] =
 {
-  { "printf",   printf_length_specs,  print_char_table, " +#0-'I", NULL,
+  { "gnu_printf",   printf_length_specs,  print_char_table, " +#0-'I", NULL,
     printf_flag_specs, printf_flag_pairs,
     FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
     'w', 0, 'p', 0, 'L', 0,
@@ -757,18 +759,18 @@ static const format_kind_info format_typ
     0, 0, 0, 0, 0, 0,
     NULL, NULL
   },
-  { "scanf",    scanf_length_specs,   scan_char_table,  "*'I", NULL,
+  { "gnu_scanf",    scanf_length_specs,   scan_char_table,  "*'I", NULL,
     scanf_flag_specs, scanf_flag_pairs,
     FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
     'w', 0, 0, '*', 'L', 'm',
     NULL, NULL
   },
-  { "strftime", NULL,                 time_char_table,  "_-0^#", "EO",
+  { "gnu_strftime", NULL,                 time_char_table,  "_-0^#", "EO",
     strftime_flag_specs, strftime_flag_pairs,
     FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0, 0,
     NULL, NULL
   },
-  { "strfmon",  strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
+  { "gnu_strfmon",  strfmon_length_specs, monetary_char_table, "=^+(!-", NULL,
     strfmon_flag_specs, strfmon_flag_pairs,
     FMT_FLAG_ARG_CONVERT, 'w', '#', 'p', 0, 'L', 0,
     NULL, NULL
@@ -2703,6 +2705,55 @@ init_dynamic_diag_info (void)
 extern const format_kind_info TARGET_FORMAT_TYPES[];
 #endif
 
+#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+extern const target_ovr_attr TARGET_OVERRIDES_FORMAT_ATTRIBUTES[];
+#endif
+
+/* Description of gnu specific format attributes reflected to
+   system format attribute types, as printf, scanf, strftime, and
+   strfmon.  */
+const target_ovr_attr gnu_target_overrides_format_attributes[] =
+{
+  { "gnu_printf",   "printf" },
+  { "gnu_scanf",    "scanf" },
+  { "gnu_strftime", "strftime" },
+  { "gnu_strfmon",  "strfmon" }
+  { NULL,           NULL }
+};
+
+static const char *
+replace_formatter_name_to_system_name (const char *attr_name)
+{
+  int i;
+
+  if (attr_name == NULL || *attr_name == 0 || strncmp (attr_name, "gcc_", 4) == 0)
+    return attr_name;
+
+#ifdef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+  /* Check if format attribute is overridden by target.  */
+  if (TARGET_OVERRIDES_FORMAT_ATTRIBUTES != NULL && TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT > 0)
+    {
+      for (i = 0; i < TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT; ++i)
+        {
+          if (strcmp (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src, attr_name) == 0)
+            return attr_name;
+          if (strcmp (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_dst, attr_name) == 0)
+            return TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src;
+        }
+    }
+#endif
+  /* Otherwise default to gnu formatter.  */
+  for (i = 0; gnu_target_overrides_format_attributes[i].named_attr_src != NULL; ++i)
+    {
+      if (strcmp (gnu_target_overrides_format_attributes[i].named_attr_src, attr_name) == 0)
+        return attr_name;
+      if (strcmp (gnu_target_overrides_format_attributes[i].named_attr_dst, attr_name) == 0)
+        return gnu_target_overrides_format_attributes[i].named_attr_src;
+    }
+
+  return attr_name;
+}
+
 /* Handle a "format" attribute; arguments as in
    struct attribute_spec.handler.  */
 tree
Index: gcc/gcc/c-format.h
===================================================================
--- gcc.orig/gcc/c-format.h
+++ gcc/gcc/c-format.h
@@ -306,4 +306,18 @@ typedef struct
 #define T_D128  &dfloat128_type_node
 #define TEX_D128 { STD_EXT, "_Decimal128", T_D128 }
 
+/* Structure describing the target specific to be override formatter
+   attributes, e.g. printf, scanf, etc.  This allows to support different
+   runtime-library specific formatter attributes to co-exist and defining
+   a default system version.
+   This type is used for the pointer variable TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+   refers to.  */
+typedef struct
+{
+  /* The name of the to be copied formatter attribute. */
+  const char *named_attr_src;
+  /* The name of the to be overridden formatter attribute. */
+  const char *named_attr_dst;
+} target_ovr_attr;
+
 #endif /* GCC_C_FORMAT_H */
Index: gcc/gcc/config/i386/i386.c
===================================================================
--- gcc.orig/gcc/config/i386/i386.c
+++ gcc/gcc/config/i386/i386.c
@@ -51,6 +51,7 @@ along with GCC; see the file COPYING3.  
 #include "df.h"
 #include "tm-constrs.h"
 #include "params.h"
+#include "c-format.h"
 
 static int x86_builtin_vectorization_cost (bool);
 
@@ -1745,6 +1746,170 @@ static const char * const x86_64_reg_cla
 static REAL_VALUE_TYPE ext_80387_constants_table [5];
 static bool ext_80387_constants_init = 0;
 
+/* Mingw specific format attributes ms_printf, ms_scanf, and ms_strftime.  */
+
+static const format_length_info ms_printf_length_specs[] =
+{
+  { "h", FMT_LEN_h, STD_C89, NULL, 0, 0 },
+  { "l", FMT_LEN_l, STD_C89, NULL, 0, 0 },
+  { "I32", FMT_LEN_l, STD_C89, "I64", FMT_LEN_ll, STD_C9L },
+  { "L", FMT_LEN_L, STD_C89, NULL, 0, 0 },
+  { NULL, 0, 0, NULL, 0, 0 }
+};
+
+static const format_flag_spec ms_printf_flag_specs[] =
+{
+  { ' ',  0, 0, N_("' ' flag"),        N_("the ' ' printf flag"),              STD_C89 },
+  { '+',  0, 0, N_("'+' flag"),        N_("the '+' printf flag"),              STD_C89 },
+  { '#',  0, 0, N_("'#' flag"),        N_("the '#' printf flag"),              STD_C89 },
+  { '0',  0, 0, N_("'0' flag"),        N_("the '0' printf flag"),              STD_C89 },
+  { '-',  0, 0, N_("'-' flag"),        N_("the '-' printf flag"),              STD_C89 },
+  { '\'', 0, 0, N_("''' flag"),        N_("the ''' printf flag"),              STD_EXT },
+  { 'I',  0, 0, N_("'I' flag"),        N_("the 'I' printf flag"),              STD_EXT },
+  { 'w',  0, 0, N_("field width"),     N_("field width in printf format"),     STD_C89 },
+  { '.',  0, 0, N_("precision"),       N_("precision in printf format"),       STD_C89 },
+  { 'L',  0, 0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_printf_flag_pairs[] =
+{
+  { ' ', '+', 1, 0   },
+  { '0', '-', 1, 0   },
+  { '0', 'p', 1, 'i' },
+  { 0, 0, 0, 0 }
+};
+
+static const format_flag_spec ms_scanf_flag_specs[] =
+{
+  { '*',  0, 0, N_("assignment suppression"), N_("the assignment suppression scanf feature"), STD_C89 },
+  { 'a',  0, 0, N_("'a' flag"),               N_("the 'a' scanf flag"),                       STD_EXT },
+  { 'w',  0, 0, N_("field width"),            N_("field width in scanf format"),              STD_C89 },
+  { 'L',  0, 0, N_("length modifier"),        N_("length modifier in scanf format"),          STD_C89 },
+  { '\'', 0, 0, N_("''' flag"),               N_("the ''' scanf flag"),                       STD_EXT },
+  { 'I',  0, 0, N_("'I' flag"),               N_("the 'I' scanf flag"),                       STD_EXT },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+static const format_flag_pair ms_scanf_flag_pairs[] =
+{
+  { '*', 'L', 0, 0 },
+  { 0, 0, 0, 0 }
+};
+
+static const format_flag_spec ms_strftime_flag_specs[] =
+{
+  { '_', 0,   0, N_("'_' flag"),     N_("the '_' strftime flag"),          STD_EXT },
+  { '-', 0,   0, N_("'-' flag"),     N_("the '-' strftime flag"),          STD_EXT },
+  { '0', 0,   0, N_("'0' flag"),     N_("the '0' strftime flag"),          STD_EXT },
+  { '^', 0,   0, N_("'^' flag"),     N_("the '^' strftime flag"),          STD_EXT },
+  { '#', 0,   0, N_("'#' flag"),     N_("the '#' strftime flag"),          STD_EXT },
+  { 'w', 0,   0, N_("field width"),  N_("field width in strftime format"), STD_EXT },
+  { 'E', 0,   0, N_("'E' modifier"), N_("the 'E' strftime modifier"),      STD_C99 },
+  { 'O', 0,   0, N_("'O' modifier"), N_("the 'O' strftime modifier"),      STD_C99 },
+  { 'O', 'o', 0, NULL,               N_("the 'O' modifier"),               STD_EXT },
+  { 0, 0, 0, NULL, NULL, 0 }
+};
+
+
+static const format_flag_pair ms_strftime_flag_pairs[] =
+{
+  { 'E', 'O', 0, 0 },
+  { '_', '-', 0, 0 },
+  { '_', '0', 0, 0 },
+  { '-', '0', 0, 0 },
+  { '^', '#', 0, 0 },
+  { 0, 0, 0, 0 }
+};
+
+static const format_char_info ms_print_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "di",  0, STD_C89, { T89_I,   T99_SC,  T89_S,   T89_L,   T9L_LL,  TEX_LL,  T99_SST, T99_PD,  T99_IM,  BADLEN,  BADLEN,  BADLEN  }, "-wp0 +'I",  "i",  NULL },
+  { "oxX", 0, STD_C89, { T89_UI,  T99_UC,  T89_US,  T89_UL,  T9L_ULL, TEX_ULL, T99_ST,  T99_UPD, T99_UIM, BADLEN,  BADLEN,  BADLEN }, "-wp0#",     "i",  NULL },
+  { "u",   0, STD_C89, { T89_UI,  T99_UC,  T89_US,  T89_UL,  T9L_ULL, TEX_ULL, T99_ST,  T99_UPD, T99_UIM, BADLEN,  BADLEN,  BADLEN }, "-wp0'I",    "i",  NULL },
+  { "fgG", 0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  T89_LD,  BADLEN,  BADLEN,  BADLEN,  TEX_D32, TEX_D64, TEX_D128 }, "-wp0 +#'I", "",   NULL },
+  { "eE",  0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  T89_LD,  BADLEN,  BADLEN,  BADLEN,  TEX_D32, TEX_D64, TEX_D128 }, "-wp0 +#I",  "",   NULL },
+  { "c",   0, STD_C89, { T89_I,   BADLEN,  BADLEN,  T94_WI,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "",   NULL },
+  { "s",   1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-wp",       "cR", NULL },
+  { "p",   1, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "c",  NULL },
+  { "n",   1, STD_C89, { T89_I,   T99_SC,  T89_S,   T89_L,   T9L_LL,  BADLEN,  T99_SST, T99_PD,  T99_IM,  BADLEN,  BADLEN,  BADLEN }, "",          "W",  NULL },
+  /* C99 conversion specifiers.  */
+  { "F",   0, STD_C99, { T99_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  T99_LD,  BADLEN,  BADLEN,  BADLEN,  TEX_D32, TEX_D64, TEX_D128 }, "-wp0 +#'I", "",   NULL },
+  { "aA",  0, STD_C99, { T99_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  T99_LD,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-wp0 +#",   "",   NULL },
+  /* X/Open conversion specifiers.  */
+  { "C",   0, STD_EXT, { TEX_WI,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-w",        "",   NULL },
+  { "S",   1, STD_EXT, { TEX_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "-wp",       "R",  NULL },
+  { NULL,  0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+static const format_char_info ms_scan_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "di",    1, STD_C89, { T89_I,   T99_SC,  T89_S,   T89_L,   T9L_LL,  TEX_LL,  T99_SST, T99_PD,  T99_IM,  BADLEN,  BADLEN,  BADLEN }, "*w'I", "W",   NULL },
+  { "u",     1, STD_C89, { T89_UI,  T99_UC,  T89_US,  T89_UL,  T9L_ULL, TEX_ULL, T99_ST,  T99_UPD, T99_UIM, BADLEN,  BADLEN,  BADLEN }, "*w'I", "W",   NULL },
+  { "oxX",   1, STD_C89, { T89_UI,  T99_UC,  T89_US,  T89_UL,  T9L_ULL, TEX_ULL, T99_ST,  T99_UPD, T99_UIM, BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "efgEG", 1, STD_C89, { T89_F,   BADLEN,  BADLEN,  T89_D,   BADLEN,  T89_LD,  BADLEN,  BADLEN,  BADLEN,  TEX_D32, TEX_D64, TEX_D128 }, "*w'",  "W",   NULL },
+  { "c",     1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "cW",  NULL },
+  { "s",     1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "cW",  NULL },
+  { "[",     1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "cW[", NULL },
+  { "p",     2, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "n",     1, STD_C89, { T89_I,   T99_SC,  T89_S,   T89_L,   T9L_LL,  BADLEN,  T99_SST, T99_PD,  T99_IM,  BADLEN,  BADLEN,  BADLEN }, "",     "W",   NULL },
+  /* C99 conversion specifiers.  */
+  { "F",   1, STD_C99, { T99_F,   BADLEN,  BADLEN,  T99_D,   BADLEN,  T99_LD,  BADLEN,  BADLEN,  BADLEN,  TEX_D32, TEX_D64, TEX_D128 }, "*w'",  "W",   NULL },
+  { "aA",   1, STD_C99, { T99_F,   BADLEN,  BADLEN,  T99_D,   BADLEN,  T99_LD,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w'",  "W",   NULL },
+  /* X/Open conversion specifiers.  */
+  { "C",     1, STD_EXT, { TEX_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*w",   "W",   NULL },
+  { "S",     1, STD_EXT, { TEX_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN }, "*aw",  "W",   NULL },
+  { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+static const format_char_info ms_time_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "ABZab",		0, STD_C89, NOLENGTHS, "^#",     "",   NULL },
+  { "cx",		0, STD_C89, NOLENGTHS, "E",      "3",  NULL },
+  { "HIMSUWdmw",	0, STD_C89, NOLENGTHS, "-_0Ow",  "",   NULL },
+  { "j",		0, STD_C89, NOLENGTHS, "-_0Ow",  "o",  NULL },
+  { "p",		0, STD_C89, NOLENGTHS, "#",      "",   NULL },
+  { "X",		0, STD_C89, NOLENGTHS, "E",      "",   NULL },
+  { "y",		0, STD_C89, NOLENGTHS, "EO-_0w", "4",  NULL },
+  { "Y",		0, STD_C89, NOLENGTHS, "-_0EOw", "o",  NULL },
+  { "%",		0, STD_C89, NOLENGTHS, "",       "",   NULL },
+  /* C99 conversion specifiers.  */
+  { "z",		0, STD_C99, NOLENGTHS, "O",      "o",  NULL },
+  { NULL,		0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
+const format_kind_info mingw_formatter_attributes[3] =
+{
+  { "ms_printf",   ms_printf_length_specs,  ms_print_char_table, " +#0-'I", NULL,
+    ms_printf_flag_specs, ms_printf_flag_pairs,
+    FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_EMPTY_PREC_OK,
+    'w', 0, 'p', 0, 'L',
+    &integer_type_node, &integer_type_node
+  },
+  { "ms_scanf",    ms_printf_length_specs,   ms_scan_char_table,  "*'I", NULL,
+    ms_scanf_flag_specs, ms_scanf_flag_pairs,
+    FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE|FMT_FLAG_USE_DOLLAR|FMT_FLAG_ZERO_WIDTH_BAD|FMT_FLAG_DOLLAR_GAP_POINTER_OK,
+    'w', 0, 0, '*', 'L',
+    NULL, NULL
+  },
+  { "ms_strftime", NULL,                 ms_time_char_table,  "_-0^#", "EO",
+    ms_strftime_flag_specs, ms_strftime_flag_pairs,
+    FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0, 0,
+    NULL, NULL
+  }
+};
+
+/* Default overrides for printf, scanf and strftime.  */
+const target_ovr_attr mingw_formatter_attribute_overrides[3] =
+{
+  { "ms_printf", "printf" },
+  { "ms_scanf", "scanf" },
+  { "ms_strftime", "strftime" }
+};
+
 \f
 static struct machine_function * ix86_init_machine_status (void);
 static rtx ix86_function_value (const_tree, const_tree, bool);
Index: gcc/gcc/config/i386/mingw32.h
===================================================================
--- gcc.orig/gcc/config/i386/mingw32.h
+++ gcc/gcc/config/i386/mingw32.h
@@ -143,6 +143,22 @@ do {						         \
    to register C++ static destructors.  */
 #define TARGET_CXX_USE_ATEXIT_FOR_CXA_ATEXIT hook_bool_void_true
 
+/* Contains a pointer to type target_ovr_attr defining the target specific
+   overrides of formatter attributs.  See format.h for structure definition.  */
+#undef TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+#define TARGET_OVERRIDES_FORMAT_ATTRIBUTES mingw_formatter_attribute_overrides
+
+/* Specify the count of elements in TARGET_OVERRIDES_ATTRIBUTE.  */
+#undef TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT
+#define TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT 3
+
+/* MS specific format attributes for ms_printf, ms_scanf, ms_strftime.  */
+#undef TARGET_FORMAT_TYPES
+#define TARGET_FORMAT_TYPES mingw_formatter_attributes
+
+#undef TARGET_N_FORMAT_TYPES
+#define TARGET_N_FORMAT_TYPES 3
+
 /* JCR_SECTION works on mingw32.  */
 #undef TARGET_USE_JCR_SECTION
 #define TARGET_USE_JCR_SECTION 1
Index: gcc/gcc/doc/extend.texi
===================================================================
--- gcc.orig/gcc/doc/extend.texi
+++ gcc/gcc/doc/extend.texi
@@ -2198,13 +2198,17 @@ for consistency with the @code{printf} s
 @code{my_format}.
 
 The parameter @var{archetype} determines how the format string is
-interpreted, and should be @code{printf}, @code{scanf}, @code{strftime}
-or @code{strfmon}.  (You can also use @code{__printf__},
-@code{__scanf__}, @code{__strftime__} or @code{__strfmon__}.)  The
-parameter @var{string-index} specifies which argument is the format
-string argument (starting from 1), while @var{first-to-check} is the
-number of the first argument to check against the format string.  For
-functions where the arguments are not available to be checked (such as
+interpreted, and should be @code{printf}, @code{scanf}, @code{strftime},
+@code{gnu_printf}, @code{gnu_scanf}, @code{gnu_strftime} or
+@code{strfmon}.  (You can also use @code{__printf__},
+@code{__scanf__}, @code{__strftime__} or @code{__strfmon__}.)  On
+mingw targets there is also @code{ms_printf}, @code{ms_scanf}, and
+@code{ms_strftime} present. The none target specific formatters are
+always the variant of the system.  The parameter @var{string-index}
+specifies which argument is the format string argument (starting
+from 1), while @var{first-to-check} is the number of the first
+argument to check against the format string.  For functions
+where the arguments are not available to be checked (such as
 @code{vprintf}), specify the third parameter as zero.  In this case the
 compiler only checks the format string for consistency.  For
 @code{strftime} formats, the third parameter is required to be zero.
Index: gcc/gcc/doc/tm.texi
===================================================================
--- gcc.orig/gcc/doc/tm.texi
+++ gcc/gcc/doc/tm.texi
@@ -10303,6 +10303,18 @@ If defined, this macro is the number of 
 @code{TARGET_FORMAT_TYPES}.
 @end defmac
 
+@defmac TARGET_OVERRIDES_FORMAT_ATTRIBUTES
+If defined, this macro is the name of a global variable containg
+target-specific format overrides for the @option{-Wformat} option. The
+default is to have no target-specific format overrides. This depends, that
+@code{TARGET_FORMAT_TYPES} is defined too.
+@end defmac
+
+@define TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT
+If defined, this macro is the number of entries in
+@code{}.
+@end defmac
+
 @deftypefn {Target Hook} bool TARGET_RELAXED_ORDERING
 If set to @code{true}, means that the target's memory model does not
 guarantee that loads which do not depend on one another will access
Index: gcc/gcc/testsuite/gcc.dg/sys_formatter.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.dg/sys_formatter.c
@@ -0,0 +1,18 @@
+/* Test system default printf formatter specifiers.  */
+/* Origin: Kai Tietz <KaiTietz.@onevision.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu89" } */
+
+__attribute__((format(printf, 1, 2))) void foo (const char *, ...);
+
+#ifdef _WIN32
+FORMATTER_TEXT	"%I64d %I32d %ld %d\n"
+#else
+FORMATTER_TEXT	"%lld %ld %ld %d"
+
+#endif
+
+void bar (long long v1, long v2, int v3)
+{
+  foo (FORMATTER_TEXT, v1, v2, v2, v3);
+}
=

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf  formatters to c-format.c
  2007-12-05 21:35   ` NightStrike
@ 2007-12-05 22:53     ` Joseph S. Myers
  2007-12-18 14:06       ` Kai Tietz
  0 siblings, 1 reply; 61+ messages in thread
From: Joseph S. Myers @ 2007-12-05 22:53 UTC (permalink / raw)
  To: NightStrike; +Cc: GCC Patches, Kai Tietz

On Wed, 5 Dec 2007, NightStrike wrote:

> On 12/4/07, Joseph S. Myers <joseph@codesourcery.com> wrote:
> > On Tue, 4 Dec 2007, NightStrike wrote:
> >
> > > http://gcc.gnu.org/ml/gcc-patches/2007-04/msg00767.html
> > >
> > > This old thread is in need of review to help the x86_64-pc-mingw32
> > > port of gcc.  It's been about 8 months so far.  Any takers to review
> > > the patch?
> >
> > If there is a patch with full testcases, please point to it - that patch
> > appears to be one without testcases, and so not ready for review.
> 
> I think Kai was waiting until your review before making the testcases.
>  Can you at least evaluate what's there already?

No, in the original discussions leading to that patch we already discussed 
the general nature of what the feature should look like at the language 
level, and assessing whether the patch meets that requires testcases (and 
changes to existing testcases) that provide proper coverage of the new and 
existing features and leave all the format checking tests passing on both 
MinGW and non-MinGW targets.

If after reviewing testcases and code I suspect problems in areas not 
covered by the tests I build the compiler with a patch when reviewing it 
and try my own tests, but the basic tests to provide thorough coverage of 
the patch are the responsibility of the patch submitter.  This (and 
diagnostic-related patches in general) is the sort of patch I review 
primarily by examining the testcases to see if I agree with the 
diagnostics asserted to be present or absent and that the testcases appear 
to cover the feature as described, and only secondarily if the testcases 
appear correct and adequate by examining the implementation.

I made clear on 25 April 
<http://gcc.gnu.org/ml/gcc-patches/2007-04/msg01734.html> that I was 
awaiting testsuite changes.  I do not think there is any open question 
regarding the principle of the feature (where partial patches might be of 
value in assessing how worthwhile a feature is bearing in mind the cost of 
the implementation); what needs review is the quality of an 
implementation, and that needs a complete patch submission.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf formatters to c-format.c
  2007-12-04 18:32 ` Joseph S. Myers
@ 2007-12-05 21:35   ` NightStrike
  2007-12-05 22:53     ` Joseph S. Myers
  0 siblings, 1 reply; 61+ messages in thread
From: NightStrike @ 2007-12-05 21:35 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: GCC Patches, Kai Tietz

On 12/4/07, Joseph S. Myers <joseph@codesourcery.com> wrote:
> On Tue, 4 Dec 2007, NightStrike wrote:
>
> > http://gcc.gnu.org/ml/gcc-patches/2007-04/msg00767.html
> >
> > This old thread is in need of review to help the x86_64-pc-mingw32
> > port of gcc.  It's been about 8 months so far.  Any takers to review
> > the patch?
>
> If there is a patch with full testcases, please point to it - that patch
> appears to be one without testcases, and so not ready for review.

I think Kai was waiting until your review before making the testcases.
 Can you at least evaluate what's there already?

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: Ping - old patch from April - mingw support for I32/I64 MS printf  formatters to c-format.c
  2007-12-04 17:55 NightStrike
@ 2007-12-04 18:32 ` Joseph S. Myers
  2007-12-05 21:35   ` NightStrike
  0 siblings, 1 reply; 61+ messages in thread
From: Joseph S. Myers @ 2007-12-04 18:32 UTC (permalink / raw)
  To: NightStrike; +Cc: GCC Patches, Kai Tietz

On Tue, 4 Dec 2007, NightStrike wrote:

> http://gcc.gnu.org/ml/gcc-patches/2007-04/msg00767.html
> 
> This old thread is in need of review to help the x86_64-pc-mingw32
> port of gcc.  It's been about 8 months so far.  Any takers to review
> the patch?

If there is a patch with full testcases, please point to it - that patch 
appears to be one without testcases, and so not ready for review.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Ping - old patch from April - mingw support for I32/I64 MS printf formatters to c-format.c
@ 2007-12-04 17:55 NightStrike
  2007-12-04 18:32 ` Joseph S. Myers
  0 siblings, 1 reply; 61+ messages in thread
From: NightStrike @ 2007-12-04 17:55 UTC (permalink / raw)
  To: GCC Patches; +Cc: Kai Tietz

http://gcc.gnu.org/ml/gcc-patches/2007-04/msg00767.html

This old thread is in need of review to help the x86_64-pc-mingw32
port of gcc.  It's been about 8 months so far.  Any takers to review
the patch?

^ permalink raw reply	[flat|nested] 61+ messages in thread

end of thread, other threads:[~2008-03-20  8:43 UTC | newest]

Thread overview: 61+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-03-13 22:38 Ping - old patch from April - mingw support for I32/I64 MS printf formatters to c-format.c FX Coudert
2008-03-14  1:33 ` Joseph S. Myers
2008-03-16  7:58 ` Danny Smith
     [not found] <Pine.LNX.4.64.0801312346090.5937@digraph.polyomino.org.uk>
2008-02-01 11:04 ` Kai Tietz
2008-02-01 15:52   ` Joseph S. Myers
2008-02-04 14:23     ` Kai Tietz
2008-02-13 18:32       ` Joseph S. Myers
2008-02-19  9:22         ` Kai Tietz
2008-02-19 12:38           ` Joseph S. Myers
2008-02-19 13:30             ` Kai Tietz
2008-02-19 14:10               ` Joseph S. Myers
2008-02-19 15:16                 ` Kai Tietz
2008-02-25 16:46                   ` NightStrike
2008-02-25 16:58                     ` Joseph S. Myers
2008-02-25 17:42                       ` NightStrike
2008-02-25 18:53                   ` Joseph S. Myers
2008-03-04 19:25                     ` Joseph S. Myers
2008-03-10 11:06                     ` Kai Tietz
2008-03-10 22:29                       ` Joseph S. Myers
2008-03-13  0:03                         ` Danny Smith
2008-03-13  8:43                           ` Kai Tietz
2008-03-13  9:29                           ` Kai Tietz
2008-03-13 19:24                             ` Ralf Wildenhues
2008-03-14  9:32                               ` Kai Tietz
2008-03-13 20:52                             ` Danny Smith
2008-03-14 11:00                               ` Kai Tietz
2008-03-16  5:54                                 ` Danny Smith
2008-03-16 12:16                                   ` Kai Tietz
2008-03-18 13:20                                   ` Kai Tietz
2008-03-18 13:44                                     ` NightStrike
2008-03-18 13:51                                       ` Kai Tietz
2008-03-18 15:07                                       ` Kai Tietz
2008-03-19  5:01                                         ` NightStrike
2008-03-19  6:22                                         ` Danny Smith
2008-03-19  9:42                                           ` Kai Tietz
2008-03-19 13:43                                             ` NightStrike
2008-03-19 13:51                                             ` NightStrike
2008-03-20  1:18                                             ` Danny Smith
2008-03-20  1:18                                               ` NightStrike
2008-03-20  9:54                                               ` Kai Tietz
2008-02-13 21:27       ` Danny Smith
2008-02-19  9:17         ` Kai Tietz
  -- strict thread matches above, loose matches on Subject: below --
2008-01-16 16:14 Kai Tietz
2007-12-04 17:55 NightStrike
2007-12-04 18:32 ` Joseph S. Myers
2007-12-05 21:35   ` NightStrike
2007-12-05 22:53     ` Joseph S. Myers
2007-12-18 14:06       ` Kai Tietz
2007-12-18 16:30         ` Joseph S. Myers
2007-12-18 21:14         ` Danny Smith
2007-12-20 13:00           ` Kai Tietz
2007-12-20 14:16             ` Joseph S. Myers
2007-12-20 14:30               ` Kai Tietz
2007-12-21 14:03               ` Kai Tietz
2007-12-21 14:38                 ` Joseph S. Myers
2008-01-07 13:56                   ` Kai Tietz
2008-01-07 14:44                     ` Joseph S. Myers
2008-01-07 16:26                       ` Kai Tietz
2008-01-08 14:37                       ` Kai Tietz
2008-01-08 18:18                         ` Joseph S. Myers
2008-01-15 16:45                           ` Kai Tietz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).