OSDN Git Service

* c-format.c (gcc_gfc_format_type, gcc_gfc_flag_pairs,
authorghazi <ghazi@138bc75d-0d04-0410-961f-82ee72b054a4>
Sun, 3 Jul 2005 14:28:03 +0000 (14:28 +0000)
committerghazi <ghazi@138bc75d-0d04-0410-961f-82ee72b054a4>
Sun, 3 Jul 2005 14:28:03 +0000 (14:28 +0000)
gcc_gfc_char_table, init_dynamic_gfc_info): New.
(format_types_orig, handle_format_attribute): Add support for
format "gcc_gfc".

fortran:
* error.c (error_printf, error_print): Use ATTRIBUTE_GCC_GFC.
* gfortran.h (ATTRIBUTE_GCC_GFC): New.
(gfc_warning, gfc_warning_now, gfc_error, gfc_error_now,
gfc_fatal_error, gfc_internal_error, gfc_notify_std): Use
ATTRIBUTE_GCC_GFC.

testsuite:
* gcc.dg/format/gcc_gfc-1.c: New.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@101552 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/c-format.c
gcc/fortran/ChangeLog
gcc/fortran/error.c
gcc/fortran/gfortran.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/format/gcc_gfc-1.c [new file with mode: 0644]

index fe12be0..fccafdd 100644 (file)
@@ -1,3 +1,10 @@
+2005-07-03  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
+
+       * c-format.c (gcc_gfc_format_type, gcc_gfc_flag_pairs,
+       gcc_gfc_char_table, init_dynamic_gfc_info): New.
+       (format_types_orig, handle_format_attribute): Add support for
+       format "gcc_gfc".
+
 2005-07-03  Gabriel Dos Reis  <gdr@integrable-solutions.net>
 
        * varasm.c (assemble_variable): Fix format specifier thinko.
index 49af576..10a5f21 100644 (file)
@@ -60,7 +60,7 @@ set_Wformat (int setting)
 enum format_type { printf_format_type, asm_fprintf_format_type,
                   gcc_diag_format_type, gcc_tdiag_format_type,
                   gcc_cdiag_format_type,
-                  gcc_cxxdiag_format_type,
+                  gcc_cxxdiag_format_type, gcc_gfc_format_type,
                   scanf_format_type, strftime_format_type,
                   strfmon_format_type, format_type_error = -1};
 
@@ -392,6 +392,11 @@ static const format_flag_pair gcc_diag_flag_pairs[] =
 #define gcc_cdiag_flag_pairs gcc_diag_flag_pairs
 #define gcc_cxxdiag_flag_pairs gcc_diag_flag_pairs
 
+static const format_flag_pair gcc_gfc_flag_pairs[] =
+{
+  { 0, 0, 0, 0 }
+};
+
 static const format_flag_spec gcc_diag_flag_specs[] =
 {
   { '+',  0, 0, N_("'+' flag"),        N_("the '+' printf flag"),              STD_C89 },
@@ -619,6 +624,23 @@ static const format_char_info gcc_cxxdiag_char_table[] =
   { NULL,  0, 0, NOLENGTHS, NULL, NULL, NULL }
 };
 
+static const format_char_info gcc_gfc_char_table[] =
+{
+  /* C89 conversion specifiers.  */
+  { "di",  0, STD_C89, { T89_I,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "", "", NULL },
+  { "c",   0, STD_C89, { T89_I,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "", "", NULL },
+  { "s",   1, STD_C89, { T89_C,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "", "cR", NULL },
+
+  /* gfc conversion specifiers.  */
+
+  { "C",   0, STD_C89, NOARGUMENTS, "",      "",   NULL },
+
+  /* This will require a "locus" at runtime.  */
+  { "L",   0, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "", "R", NULL },
+
+  { NULL,  0, 0, NOLENGTHS, NULL, NULL, NULL }
+};
+
 static const format_char_info scan_char_table[] =
 {
   /* C89 conversion specifiers.  */
@@ -711,6 +733,12 @@ static const format_kind_info format_types_orig[] =
     0, 0, 'p', 0, 'L',
     NULL, &integer_type_node
   },
+  { "gcc_gfc", NULL, gcc_gfc_char_table, "", NULL, 
+    NULL, gcc_gfc_flag_pairs,
+    FMT_FLAG_ARG_CONVERT,
+    0, 0, 0, 0, 0,
+    NULL, NULL
+  },
   { "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,
@@ -2383,6 +2411,55 @@ init_dynamic_asm_fprintf_info (void)
     }
 }
 
+/* Determine the type of a "locus" in the code being compiled for use
+   in GCC's __gcc_gfc__ custom format attribute.  You must have set
+   dynamic_format_types before calling this function.  */
+static void
+init_dynamic_gfc_info (void)
+{
+  static tree locus;
+  
+  if (!locus)
+    {
+      static format_char_info *gfc_fci;
+
+      /* For the GCC __gcc_gfc__ custom format specifier to work, one
+        must have declared 'locus' prior to using this attribute.  If
+        we haven't seen this declarations then you shouldn't use the
+        specifier requiring that type.  */
+      if ((locus = maybe_get_identifier ("locus")))
+       {
+         locus = identifier_global_value (locus);
+         if (locus)
+           {
+             if (TREE_CODE (locus) != TYPE_DECL)
+               {
+                 error ("%<locus%> is not defined as a type");
+                 locus = 0;
+               }
+             else
+               locus = TREE_TYPE (locus);
+           }
+       }
+
+      /* Assign the new data for use.  */
+
+      /* Handle the __gcc_gfc__ format specifics.  */
+      if (!gfc_fci)
+       dynamic_format_types[gcc_gfc_format_type].conversion_specs =
+         gfc_fci = (format_char_info *)
+                    xmemdup (gcc_gfc_char_table,
+                             sizeof (gcc_gfc_char_table),
+                             sizeof (gcc_gfc_char_table));
+      if (locus)
+        {
+         const unsigned i = find_char_info_specifier_index (gfc_fci, 'L');
+         gfc_fci[i].types[0].type = &locus;
+         gfc_fci[i].pointer_count = 1;
+       }
+    }
+}
+
 /* Determine the types of "tree" and "location_t" in the code being
    compiled for use in GCC's diagnostic custom format attributes.  You
    must have set dynamic_format_types before calling this function.  */
@@ -2660,6 +2737,7 @@ handle_format_attribute (tree *node, tree ARG_UNUSED (name), tree args,
   /* 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
@@ -2676,6 +2754,10 @@ handle_format_attribute (tree *node, tree ARG_UNUSED (name), tree args,
          GCC's notion of HOST_WIDE_INT for checking %wd.  */
       if (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)
+       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
index 6750a13..b589f66 100644 (file)
@@ -1,3 +1,11 @@
+2005-07-03  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
+
+       * error.c (error_printf, error_print): Use ATTRIBUTE_GCC_GFC.
+       * gfortran.h (ATTRIBUTE_GCC_GFC): New.
+       (gfc_warning, gfc_warning_now, gfc_error, gfc_error_now,
+       gfc_fatal_error, gfc_internal_error, gfc_notify_std): Use
+       ATTRIBUTE_GCC_GFC.
+
 2005-07-03  Francois-Xavier Coudert  <coudert@clipper.ens.fr>
 
        PR fortran/20842
index d30153c..fe7decc 100644 (file)
@@ -118,7 +118,7 @@ error_string (const char *p)
    locus.  Calls error_printf() recursively, but the recursion is at
    most one level deep.  */
 
-static void error_printf (const char *, ...) ATTRIBUTE_PRINTF_1;
+static void error_printf (const char *, ...) ATTRIBUTE_GCC_GFC(1,2);
 
 static void
 show_locus (int offset, locus * loc)
@@ -314,7 +314,7 @@ separate:
 #define IBUF_LEN 30
 #define MAX_ARGS 10
 
-static void
+static void ATTRIBUTE_GCC_GFC(2,0)
 error_print (const char *type, const char *format0, va_list argp)
 {
   char c, *p, int_buf[IBUF_LEN], c_arg[MAX_ARGS], *cp_arg[MAX_ARGS];
index 8de2c42..07a3f2c 100644 (file)
@@ -501,6 +501,14 @@ typedef struct
   gfc_linebuf *lb;
 } locus;
 
+/* In order for the "gfc" format checking to work correctly, you must
+   have declared a typedef locus first.  */
+#if GCC_VERSION >= 4001
+#define ATTRIBUTE_GCC_GFC(m, n) __attribute__ ((__format__ (__gcc_gfc__, m, n))) ATTRIBUTE_NONNULL(m)
+#else
+#define ATTRIBUTE_GCC_GFC(m, n) ATTRIBUTE_NONNULL(m)
+#endif
+
 
 #include <limits.h>
 #ifndef PATH_MAX
@@ -1543,19 +1551,19 @@ typedef struct gfc_error_buf
 void gfc_error_init_1 (void);
 void gfc_buffer_error (int);
 
-void gfc_warning (const char *, ...);
-void gfc_warning_now (const char *, ...);
+void gfc_warning (const char *, ...) ATTRIBUTE_GCC_GFC(1,2);
+void gfc_warning_now (const char *, ...) ATTRIBUTE_GCC_GFC(1,2);
 void gfc_clear_warning (void);
 void gfc_warning_check (void);
 
-void gfc_error (const char *, ...);
-void gfc_error_now (const char *, ...);
-void gfc_fatal_error (const char *, ...) ATTRIBUTE_NORETURN;
-void gfc_internal_error (const char *, ...) ATTRIBUTE_NORETURN;
+void gfc_error (const char *, ...) ATTRIBUTE_GCC_GFC(1,2);
+void gfc_error_now (const char *, ...) ATTRIBUTE_GCC_GFC(1,2);
+void gfc_fatal_error (const char *, ...) ATTRIBUTE_NORETURN ATTRIBUTE_GCC_GFC(1,2);
+void gfc_internal_error (const char *, ...) ATTRIBUTE_NORETURN ATTRIBUTE_GCC_GFC(1,2);
 void gfc_clear_error (void);
 int gfc_error_check (void);
 
-try gfc_notify_std (int, const char *, ...);
+try gfc_notify_std (int, const char *, ...) ATTRIBUTE_GCC_GFC(2,3);
 
 /* A general purpose syntax error.  */
 #define gfc_syntax_error(ST)   \
index ce96728..2cc6f5c 100644 (file)
@@ -1,3 +1,7 @@
+2005-07-03  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
+
+       * gcc.dg/format/gcc_gfc-1.c: New.
+
 2005-07-03  Andrew Pinski  <pinskia@physics.uc.edu>
 
        * pr14490-[1-4].c: Fix typos scan-tree-dump-times so they now pass.
diff --git a/gcc/testsuite/gcc.dg/format/gcc_gfc-1.c b/gcc/testsuite/gcc.dg/format/gcc_gfc-1.c
new file mode 100644 (file)
index 0000000..d23701d
--- /dev/null
@@ -0,0 +1,30 @@
+/* Test for gcc_gfc formats.  */
+/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
+/* { dg-do compile } */
+/* { dg-options "-Wformat" } */
+
+#include "format.h"
+
+/* Magic identifier must be set before the attribute is used.  */
+typedef struct locus locus;
+
+extern int gfc_warn (const char *, ...) __attribute__ ((__format__ (__gcc_gfc__, 1, 2))) __attribute__ ((__nonnull__));
+
+void
+foo (int i, char *s, long int l, llong ll, locus *loc)
+{
+  /* Acceptable C90 specifiers, flags and modifiers.  */
+  gfc_warn ("%%");
+  gfc_warn ("%d%i%c%s%%", i, i, i, s);
+
+  /* Extensions provided in gfc_warn.  */
+  gfc_warn ("%C");
+  gfc_warn ("%L", loc);
+
+  /* Various tests of bad argument types.  */
+  gfc_warn ("%d", l); /* { dg-warning "format" "bad argument types" } */
+  gfc_warn ("%d", ll); /* { dg-warning "format" "bad argument types" } */
+  gfc_warn ("%s", &i); /* { dg-warning "format" "bad argument types" } */
+  gfc_warn ("%L", &i); /* { dg-warning "format" "bad argument types" } */
+  gfc_warn ("%C", i); /* { dg-warning "format" "too many arguments" } */
+}