This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH]: Add fortran dir specific format attribute "gcc_gfc"
- From: "Kaveh R. Ghazi" <ghazi at caipclassic dot rutgers dot edu>
- To: joseph at codesourcery dot com
- Cc: fortran at gcc dot gnu dot org, gcc-patches at gcc dot gnu dot org
- Date: Sun, 3 Jul 2005 09:02:14 -0400 (EDT)
- Subject: Re: [PATCH]: Add fortran dir specific format attribute "gcc_gfc"
- References: <200506291136.j5TBaFUj001165@caipclassic.rutgers.edu> <Pine.LNX.4.61.0507030043380.1625@digraph.polyomino.org.uk>
> > As we have done with asm_fprintf and the gcc diagnostic routines, we
> > can have a custom format attribute to check for errors. Is this
> > something the fortran maintainers want?
> >
> > If so, I've written a patch for mainline to do this. I need a
> > fortran maintainer and a C front-end maintainer to review the
> > separate bits.
>
> If the Fortran maintainers want this, then the C parts are OK (though
> they'll need updating to apply after my recent changes to the same
> code).
Thanks, I've reapplied the patch and fixed one minor conflict.
So fortran maintainers, okay to apply the fortran bits?
Thanks,
--Kaveh
2005-06-29 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".
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.
diff -rup orig/egcc-CVS20050702/gcc/c-format.c egcc-CVS20050702/gcc/c-format.c
--- orig/egcc-CVS20050702/gcc/c-format.c 2005-07-02 21:13:15.000000000 -0400
+++ egcc-CVS20050702/gcc/c-format.c 2005-07-03 08:47:19.000000000 -0400
@@ -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_f
#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_cxxdia
{ 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_typ
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, 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
@@ -2676,6 +2754,10 @@ handle_format_attribute (tree *node, tre
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
diff -rup orig/egcc-CVS20050702/gcc/fortran/error.c egcc-CVS20050702/gcc/fortran/error.c
--- orig/egcc-CVS20050702/gcc/fortran/error.c 2005-06-25 22:38:09.000000000 -0400
+++ egcc-CVS20050702/gcc/fortran/error.c 2005-07-03 08:46:18.000000000 -0400
@@ -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];
diff -rup orig/egcc-CVS20050702/gcc/fortran/gfortran.h egcc-CVS20050702/gcc/fortran/gfortran.h
--- orig/egcc-CVS20050702/gcc/fortran/gfortran.h 2005-06-25 22:38:09.000000000 -0400
+++ egcc-CVS20050702/gcc/fortran/gfortran.h 2005-07-03 08:46:18.000000000 -0400
@@ -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) \
diff -rup orig/egcc-CVS20050702/gcc/testsuite/gcc.dg/format/gcc_gfc-1.c egcc-CVS20050702/gcc/testsuite/gcc.dg/format/gcc_gfc-1.c
--- orig/egcc-CVS20050702/gcc/testsuite/gcc.dg/format/gcc_gfc-1.c 2005-07-03 08:48:26.000000000 -0400
+++ egcc-CVS20050702/gcc/testsuite/gcc.dg/format/gcc_gfc-1.c 2005-07-03 08:46:18.000000000 -0400
@@ -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" } */
+}