diff options
-rw-r--r-- | gcc/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/c-format.c | 84 | ||||
-rw-r--r-- | gcc/fortran/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/fortran/error.c | 4 | ||||
-rw-r--r-- | gcc/fortran/gfortran.h | 22 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/format/gcc_gfc-1.c | 30 |
7 files changed, 149 insertions, 10 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index fe12be0e7f2..fccafdd3cfa 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -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. diff --git a/gcc/c-format.c b/gcc/c-format.c index 49af5762298..10a5f21db59 100644 --- a/gcc/c-format.c +++ b/gcc/c-format.c @@ -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 diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 6750a13189e..b589f66711e 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -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 diff --git a/gcc/fortran/error.c b/gcc/fortran/error.c index d30153c6226..fe7decc5dfb 100644 --- a/gcc/fortran/error.c +++ b/gcc/fortran/error.c @@ -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 --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index 8de2c424c0e..07a3f2c2bba 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -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 --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ce967281595..2cc6f5c63c2 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -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 index 00000000000..d23701d8d17 --- /dev/null +++ b/gcc/testsuite/gcc.dg/format/gcc_gfc-1.c @@ -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" } */ +} |