X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fc-format.c;h=6b14f4026c73a1c837b12e7f904475bb6b2d0e14;hb=d0aaf3990d011abe5d7c65905f240a60d2fdccb6;hp=9994cf4cc2d9d808b449ee94db225ac91621b442;hpb=8c4c00c181e6df4f0a9afc76e4c9edbbc1c2fd41;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/c-format.c b/gcc/c-format.c index 9994cf4cc2d..6b14f4026c7 100644 --- a/gcc/c-format.c +++ b/gcc/c-format.c @@ -1,6 +1,6 @@ /* 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. + 2001, 2002, 2003, 2004, 2005, 2007, 2008 Free Software Foundation, Inc. This file is part of GCC. @@ -30,6 +30,7 @@ along with GCC; see the file COPYING3. If not see #include "diagnostic.h" #include "langhooks.h" #include "c-format.h" +#include "alloc-pool.h" /* Set format warning options according to a -Wformat=n option. */ @@ -61,8 +62,7 @@ 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_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 { @@ -79,7 +79,8 @@ static bool check_format_string (tree argument, 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. */ @@ -190,6 +191,8 @@ decode_format_attr (tree args, function_format_info *info, int validated_p) { 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) @@ -256,6 +259,8 @@ typedef struct format_wanted_type tree wanted_type; /* The name of this type to use in diagnostics. */ const char *wanted_type_name; + /* Should be type checked just for scalar width identity. */ + int scalar_identity_flag; /* The level of indirection through pointers at which this type occurs. */ int pointer_count; /* Whether, when pointer_count is 1, to allow any character type when @@ -280,36 +285,38 @@ typedef struct format_wanted_type struct format_wanted_type *next; } format_wanted_type; +/* Convenience macro for format_length_info meaning unused. */ +#define NO_FMT NULL, FMT_LEN_none, STD_C89 static const format_length_info printf_length_specs[] = { - { "h", FMT_LEN_h, STD_C89, "hh", FMT_LEN_hh, STD_C99 }, - { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C9L }, - { "q", FMT_LEN_ll, STD_EXT, NULL, 0, 0 }, - { "L", FMT_LEN_L, STD_C89, NULL, 0, 0 }, - { "z", FMT_LEN_z, STD_C99, NULL, 0, 0 }, - { "Z", FMT_LEN_z, STD_EXT, NULL, 0, 0 }, - { "t", FMT_LEN_t, STD_C99, NULL, 0, 0 }, - { "j", FMT_LEN_j, STD_C99, NULL, 0, 0 }, - { "H", FMT_LEN_H, STD_EXT, NULL, 0, 0 }, - { "D", FMT_LEN_D, STD_EXT, "DD", FMT_LEN_DD, STD_EXT }, - { NULL, 0, 0, NULL, 0, 0 } + { "h", FMT_LEN_h, STD_C89, "hh", FMT_LEN_hh, STD_C99, 0 }, + { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C9L, 0 }, + { "q", FMT_LEN_ll, STD_EXT, NO_FMT, 0 }, + { "L", FMT_LEN_L, STD_C89, NO_FMT, 0 }, + { "z", FMT_LEN_z, STD_C99, NO_FMT, 0 }, + { "Z", FMT_LEN_z, STD_EXT, NO_FMT, 0 }, + { "t", FMT_LEN_t, STD_C99, NO_FMT, 0 }, + { "j", FMT_LEN_j, STD_C99, NO_FMT, 0 }, + { "H", FMT_LEN_H, STD_EXT, NO_FMT, 0 }, + { "D", FMT_LEN_D, STD_EXT, "DD", FMT_LEN_DD, STD_EXT, 0 }, + { NO_FMT, NO_FMT, 0 } }; /* Length specifiers valid for asm_fprintf. */ static const format_length_info asm_fprintf_length_specs[] = { - { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C89 }, - { "w", FMT_LEN_none, STD_C89, NULL, 0, 0 }, - { NULL, 0, 0, NULL, 0, 0 } + { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C89, 0 }, + { "w", FMT_LEN_none, STD_C89, NO_FMT, 0 }, + { NO_FMT, NO_FMT, 0 } }; /* Length specifiers valid for GCC diagnostics. */ static const format_length_info gcc_diag_length_specs[] = { - { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C89 }, - { "w", FMT_LEN_none, STD_C89, NULL, 0, 0 }, - { NULL, 0, 0, NULL, 0, 0 } + { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C89, 0 }, + { "w", FMT_LEN_none, STD_C89, NO_FMT, 0 }, + { NO_FMT, NO_FMT, 0 } }; /* The custom diagnostics all accept the same length specifiers. */ @@ -320,16 +327,16 @@ static const format_length_info gcc_diag_length_specs[] = /* This differs from printf_length_specs only in that "Z" is not accepted. */ static const format_length_info scanf_length_specs[] = { - { "h", FMT_LEN_h, STD_C89, "hh", FMT_LEN_hh, STD_C99 }, - { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C9L }, - { "q", FMT_LEN_ll, STD_EXT, NULL, 0, 0 }, - { "L", FMT_LEN_L, STD_C89, NULL, 0, 0 }, - { "z", FMT_LEN_z, STD_C99, NULL, 0, 0 }, - { "t", FMT_LEN_t, STD_C99, NULL, 0, 0 }, - { "j", FMT_LEN_j, STD_C99, NULL, 0, 0 }, - { "H", FMT_LEN_H, STD_EXT, NULL, 0, 0 }, - { "D", FMT_LEN_D, STD_EXT, "DD", FMT_LEN_DD, STD_EXT }, - { NULL, 0, 0, NULL, 0, 0 } + { "h", FMT_LEN_h, STD_C89, "hh", FMT_LEN_hh, STD_C99, 0 }, + { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C9L, 0 }, + { "q", FMT_LEN_ll, STD_EXT, NO_FMT, 0 }, + { "L", FMT_LEN_L, STD_C89, NO_FMT, 0 }, + { "z", FMT_LEN_z, STD_C99, NO_FMT, 0 }, + { "t", FMT_LEN_t, STD_C99, NO_FMT, 0 }, + { "j", FMT_LEN_j, STD_C99, NO_FMT, 0 }, + { "H", FMT_LEN_H, STD_EXT, NO_FMT, 0 }, + { "D", FMT_LEN_D, STD_EXT, "DD", FMT_LEN_DD, STD_EXT, 0 }, + { NO_FMT, NO_FMT, 0 } }; @@ -338,10 +345,19 @@ static const format_length_info scanf_length_specs[] = static const format_length_info strfmon_length_specs[] = { /* A GNU extension. */ - { "L", FMT_LEN_L, STD_C89, NULL, 0, 0 }, - { NULL, 0, 0, NULL, 0, 0 } + { "L", FMT_LEN_L, STD_C89, NO_FMT, 0 }, + { NO_FMT, NO_FMT, 0 } }; + +/* For now, the Fortran front-end routines only use l as length modifier. */ +static const format_length_info gcc_gfc_length_specs[] = +{ + { "l", FMT_LEN_l, STD_C89, NO_FMT, 0 }, + { NO_FMT, NO_FMT, 0 } +}; + + static const format_flag_spec printf_flag_specs[] = { { ' ', 0, 0, N_("' ' flag"), N_("the ' ' printf flag"), STD_C89 }, @@ -354,7 +370,7 @@ static const format_flag_spec printf_flag_specs[] = { '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 } + { 0, 0, 0, NULL, NULL, STD_C89 } }; @@ -376,7 +392,7 @@ static const format_flag_spec asm_fprintf_flag_specs[] = { '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 } + { 0, 0, 0, NULL, NULL, STD_C89 } }; static const format_flag_pair asm_fprintf_flag_pairs[] = @@ -407,7 +423,7 @@ static const format_flag_spec gcc_diag_flag_specs[] = { 'q', 0, 0, N_("'q' flag"), N_("the 'q' diagnostic flag"), 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 } + { 0, 0, 0, NULL, NULL, STD_C89 } }; #define gcc_tdiag_flag_specs gcc_diag_flag_specs @@ -420,24 +436,26 @@ static const format_flag_spec gcc_cxxdiag_flag_specs[] = { 'q', 0, 0, N_("'q' flag"), N_("the 'q' diagnostic flag"), 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 } + { 0, 0, 0, NULL, NULL, STD_C89 } }; static const format_flag_spec 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 }, + { 'm', 0, 0, N_("'m' flag"), N_("the 'm' 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 } + { 0, 0, 0, NULL, NULL, STD_C89 } }; static const format_flag_pair scanf_flag_pairs[] = { { '*', 'L', 0, 0 }, + { 'a', 'm', 0, 0 }, { 0, 0, 0, 0 } }; @@ -453,7 +471,7 @@ static const format_flag_spec strftime_flag_specs[] = { '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 } + { 0, 0, 0, NULL, NULL, STD_C89 } }; @@ -480,7 +498,7 @@ static const format_flag_spec strfmon_flag_specs[] = { '#', 0, 0, N_("left precision"), N_("left precision in strfmon format"), STD_C89 }, { 'p', 0, 0, N_("right precision"), N_("right precision in strfmon format"), STD_C89 }, { 'L', 0, 0, N_("length modifier"), N_("length modifier in strfmon format"), STD_C89 }, - { 0, 0, 0, NULL, NULL, 0 } + { 0, 0, 0, NULL, NULL, STD_C89 } }; static const format_flag_pair strfmon_flag_pairs[] = @@ -510,7 +528,7 @@ static const format_char_info print_char_table[] = { "S", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "R", NULL }, /* GNU conversion specifiers. */ { "m", 0, STD_EXT, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "", NULL }, - { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL } + { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL } }; static const format_char_info asm_fprintf_char_table[] = @@ -530,7 +548,7 @@ static const format_char_info asm_fprintf_char_table[] = { "U", 0, STD_C89, NOARGUMENTS, "", "", NULL }, { "r", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "", NULL }, { "@", 0, STD_C89, NOARGUMENTS, "", "", NULL }, - { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL } + { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL } }; static const format_char_info gcc_diag_char_table[] = @@ -545,15 +563,12 @@ static const format_char_info gcc_diag_char_table[] = /* Custom conversion specifiers. */ - /* %H will require "location_t" at runtime. */ - { "H", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - /* These will require a "tree" at runtime. */ - { "J", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, + { "K", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, { "<>'", 0, STD_C89, NOARGUMENTS, "", "", NULL }, { "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL }, - { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL } + { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL } }; static const format_char_info gcc_tdiag_char_table[] = @@ -568,15 +583,12 @@ static const format_char_info gcc_tdiag_char_table[] = /* Custom conversion specifiers. */ - /* %H will require "location_t" at runtime. */ - { "H", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - /* These will require a "tree" at runtime. */ - { "DFJT", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q+", "", NULL }, + { "DFKTE", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q+", "", NULL }, { "<>'", 0, STD_C89, NOARGUMENTS, "", "", NULL }, { "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL }, - { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL } + { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL } }; static const format_char_info gcc_cdiag_char_table[] = @@ -591,15 +603,12 @@ static const format_char_info gcc_cdiag_char_table[] = /* Custom conversion specifiers. */ - /* %H will require "location_t" at runtime. */ - { "H", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - /* These will require a "tree" at runtime. */ - { "DEFJT", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q+", "", NULL }, + { "DEFKT", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q+", "", NULL }, { "<>'", 0, STD_C89, NOARGUMENTS, "", "", NULL }, { "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL }, - { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL } + { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL } }; static const format_char_info gcc_cxxdiag_char_table[] = @@ -614,24 +623,22 @@ static const format_char_info gcc_cxxdiag_char_table[] = /* Custom conversion specifiers. */ - /* %H will require "location_t" at runtime. */ - { "H", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - /* These will require a "tree" at runtime. */ - { "ADEFJTV",0,STD_C89,{ T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q+#", "", NULL }, + { "ADEFKTV",0,STD_C89,{ T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q+#", "", NULL }, /* These accept either an 'int' or an 'enum tree_code' (which is handled as an 'int'.) */ { "CLOPQ",0,STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, { "<>'", 0, STD_C89, NOARGUMENTS, "", "", NULL }, { "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL }, - { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL } + { NULL, 0, STD_C89, 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 }, + { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "", NULL }, + { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, 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 }, @@ -642,7 +649,7 @@ static const format_char_info gcc_gfc_char_table[] = /* 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 } + { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL } }; static const format_char_info scan_char_table[] = @@ -652,18 +659,18 @@ static const format_char_info scan_char_table[] = { "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 }, + { "c", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*mw", "cW", NULL }, + { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*amw", "cW", NULL }, + { "[", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*amw", "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 } + { "C", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*mw", "W", NULL }, + { "S", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*amw", "W", NULL }, + { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL } }; static const format_char_info time_char_table[] = @@ -690,74 +697,74 @@ static const format_char_info time_char_table[] = /* GNU conversion specifiers. */ { "kls", 0, STD_EXT, NOLENGTHS, "-_0Ow", "", NULL }, { "P", 0, STD_EXT, NOLENGTHS, "", "", NULL }, - { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL } + { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL } }; static const format_char_info monetary_char_table[] = { { "in", 0, STD_C89, { T89_D, BADLEN, BADLEN, BADLEN, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "=^+(!-w#p", "", NULL }, - { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL } + { NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL } }; /* 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', + 'w', 0, 'p', 0, 'L', 0, &integer_type_node, &integer_type_node }, { "asm_fprintf", asm_fprintf_length_specs, asm_fprintf_char_table, " +#0-", NULL, asm_fprintf_flag_specs, asm_fprintf_flag_pairs, FMT_FLAG_ARG_CONVERT|FMT_FLAG_EMPTY_PREC_OK, - 'w', 0, 'p', 0, 'L', + 'w', 0, 'p', 0, 'L', 0, NULL, NULL }, { "gcc_diag", gcc_diag_length_specs, gcc_diag_char_table, "q+", NULL, gcc_diag_flag_specs, gcc_diag_flag_pairs, FMT_FLAG_ARG_CONVERT, - 0, 0, 'p', 0, 'L', + 0, 0, 'p', 0, 'L', 0, NULL, &integer_type_node }, { "gcc_tdiag", gcc_tdiag_length_specs, gcc_tdiag_char_table, "q+", NULL, gcc_tdiag_flag_specs, gcc_tdiag_flag_pairs, FMT_FLAG_ARG_CONVERT, - 0, 0, 'p', 0, 'L', + 0, 0, 'p', 0, 'L', 0, NULL, &integer_type_node }, { "gcc_cdiag", gcc_cdiag_length_specs, gcc_cdiag_char_table, "q+", NULL, gcc_cdiag_flag_specs, gcc_cdiag_flag_pairs, FMT_FLAG_ARG_CONVERT, - 0, 0, 'p', 0, 'L', + 0, 0, 'p', 0, 'L', 0, NULL, &integer_type_node }, { "gcc_cxxdiag", gcc_cxxdiag_length_specs, gcc_cxxdiag_char_table, "q+#", NULL, gcc_cxxdiag_flag_specs, gcc_cxxdiag_flag_pairs, FMT_FLAG_ARG_CONVERT, - 0, 0, 'p', 0, 'L', + 0, 0, 'p', 0, 'L', 0, NULL, &integer_type_node }, - { "gcc_gfc", NULL, gcc_gfc_char_table, "", NULL, + { "gcc_gfc", gcc_gfc_length_specs, gcc_gfc_char_table, "", NULL, NULL, gcc_gfc_flag_pairs, FMT_FLAG_ARG_CONVERT, - 0, 0, 0, 0, 0, + 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', + '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, + 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', + FMT_FLAG_ARG_CONVERT, 'w', '#', 'p', 0, 'L', 0, NULL, NULL } }; @@ -811,7 +818,7 @@ static void check_format_arg (void *, tree, unsigned HOST_WIDE_INT); static void check_format_info_main (format_check_results *, function_format_info *, const char *, int, tree, - unsigned HOST_WIDE_INT); + unsigned HOST_WIDE_INT, alloc_pool); static void init_dollar_format_checking (int, tree); static int maybe_read_dollar_number (const char **, int, @@ -834,6 +841,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++) { @@ -1290,6 +1299,7 @@ check_format_arg (void *ctx, tree format_tree, const char *format_chars; tree array_size = 0; tree array_init; + alloc_pool fwt_pool; if (integer_zerop (format_tree)) { @@ -1391,21 +1401,16 @@ check_format_arg (void *ctx, tree format_tree, format_chars += offset; format_length -= offset; } - if (format_length < 1) + if (format_length < 1 || format_chars[--format_length] != 0) { res->number_unterminated++; return; } - if (format_length == 1) + if (format_length == 0) { res->number_empty++; return; } - if (format_chars[--format_length] != 0) - { - res->number_unterminated++; - return; - } /* Skip to first argument to check. */ while (arg_num + 1 < info->first_arg_num) @@ -1419,8 +1424,11 @@ check_format_arg (void *ctx, tree format_tree, will decrement it if it finds there are extra arguments, but this way need not adjust it for every return. */ res->number_other++; + fwt_pool = create_alloc_pool ("format_wanted_type pool", + sizeof (format_wanted_type), 10); check_format_info_main (res, info, format_chars, format_length, - params, arg_num); + params, arg_num, fwt_pool); + free_alloc_pool (fwt_pool); } @@ -1435,7 +1443,7 @@ static void check_format_info_main (format_check_results *res, function_format_info *info, const char *format_chars, int format_length, tree params, - unsigned HOST_WIDE_INT arg_num) + unsigned HOST_WIDE_INT arg_num, alloc_pool fwt_pool) { const char *orig_format_chars = format_chars; tree first_fillin_param = params; @@ -1472,7 +1480,8 @@ check_format_info_main (format_check_results *res, const format_length_info *fli = NULL; const format_char_info *fci = NULL; char flag_chars[256]; - int aflag = 0; + int alloc_flag = 0; + int scalar_identity_flag = 0; const char *format_start = format_chars; if (*format_chars == 0) { @@ -1606,6 +1615,7 @@ check_format_info_main (format_check_results *res, width_wanted_type.wanted_type_name = NULL; width_wanted_type.pointer_count = 0; width_wanted_type.char_lenient_flag = 0; + width_wanted_type.scalar_identity_flag = 0; width_wanted_type.writing_in_flag = 0; width_wanted_type.reading_from_flag = 0; width_wanted_type.name = _("field width"); @@ -1708,6 +1718,7 @@ check_format_info_main (format_check_results *res, precision_wanted_type.wanted_type_name = NULL; precision_wanted_type.pointer_count = 0; precision_wanted_type.char_lenient_flag = 0; + precision_wanted_type.scalar_identity_flag = 0; precision_wanted_type.writing_in_flag = 0; precision_wanted_type.reading_from_flag = 0; precision_wanted_type.name = _("field precision"); @@ -1731,18 +1742,45 @@ check_format_info_main (format_check_results *res, } } + if (fki->alloc_char && fki->alloc_char == *format_chars) + { + i = strlen (flag_chars); + flag_chars[i++] = fki->alloc_char; + flag_chars[i] = 0; + format_chars++; + } + + /* Handle the scanf allocation kludge. */ + if (fki->flags & (int) FMT_FLAG_SCANF_A_KLUDGE) + { + if (*format_chars == 'a' && !flag_isoc99) + { + if (format_chars[1] == 's' || format_chars[1] == 'S' + || format_chars[1] == '[') + { + /* 'a' is used as a flag. */ + i = strlen (flag_chars); + flag_chars[i++] = 'a'; + flag_chars[i] = 0; + format_chars++; + } + } + } + /* Read any length modifier, if this kind of format has them. */ fli = fki->length_char_specs; length_chars = NULL; length_chars_val = FMT_LEN_none; length_chars_std = STD_C89; + scalar_identity_flag = 0; if (fli) { - while (fli->name != 0 && fli->name[0] != *format_chars) - fli++; + while (fli->name != 0 + && strncmp (fli->name, format_chars, strlen (fli->name))) + fli++; if (fli->name != 0) { - format_chars++; + format_chars += strlen (fli->name); if (fli->double_name != 0 && fli->name[0] == *format_chars) { format_chars++; @@ -1755,6 +1793,7 @@ check_format_info_main (format_check_results *res, length_chars = fli->name; length_chars_val = fli->index; length_chars_std = fli->std; + scalar_identity_flag = fli->scalar_identity_flag; } i = strlen (flag_chars); flag_chars[i++] = fki->length_code_char; @@ -1793,23 +1832,6 @@ check_format_info_main (format_check_results *res, } } - /* Handle the scanf allocation kludge. */ - if (fki->flags & (int) FMT_FLAG_SCANF_A_KLUDGE) - { - if (*format_chars == 'a' && !flag_isoc99) - { - if (format_chars[1] == 's' || format_chars[1] == 'S' - || format_chars[1] == '[') - { - /* 'a' is used as a flag. */ - i = strlen (flag_chars); - flag_chars[i++] = 'a'; - flag_chars[i] = 0; - format_chars++; - } - } - } - format_char = *format_chars; if (format_char == 0 || (!(fki->flags & (int) FMT_FLAG_FANCY_PERCENT_OK) @@ -1882,7 +1904,9 @@ check_format_info_main (format_check_results *res, if ((fki->flags & (int) FMT_FLAG_SCANF_A_KLUDGE) && strchr (flag_chars, 'a') != 0) - aflag = 1; + alloc_flag = 1; + if (fki->alloc_char && strchr (flag_chars, fki->alloc_char) != 0) + alloc_flag = 1; if (fki->suppression_char && strchr (flag_chars, fki->suppression_char) != 0) @@ -2054,13 +2078,16 @@ check_format_info_main (format_check_results *res, wanted_type_ptr->wanted_type = wanted_type; wanted_type_ptr->wanted_type_name = wanted_type_name; - wanted_type_ptr->pointer_count = fci->pointer_count + aflag; + wanted_type_ptr->pointer_count = fci->pointer_count + alloc_flag; wanted_type_ptr->char_lenient_flag = 0; if (strchr (fci->flags2, 'c') != 0) wanted_type_ptr->char_lenient_flag = 1; + wanted_type_ptr->scalar_identity_flag = 0; + if (scalar_identity_flag) + wanted_type_ptr->scalar_identity_flag = 1; wanted_type_ptr->writing_in_flag = 0; wanted_type_ptr->reading_from_flag = 0; - if (aflag) + if (alloc_flag) wanted_type_ptr->writing_in_flag = 1; else { @@ -2082,7 +2109,8 @@ check_format_info_main (format_check_results *res, fci = fci->chain; if (fci) { - wanted_type_ptr = GGC_NEW (format_wanted_type); + wanted_type_ptr = (format_wanted_type *) + pool_alloc (fwt_pool); arg_num++; wanted_type = *fci->types[length_chars_val].type; wanted_type_name = fci->types[length_chars_val].name; @@ -2093,17 +2121,6 @@ check_format_info_main (format_check_results *res, if (first_wanted_type != 0) check_format_types (first_wanted_type, format_start, format_chars - format_start); - - if (main_wanted_type.next != NULL) - { - format_wanted_type *wanted_type_ptr = main_wanted_type.next; - while (wanted_type_ptr) - { - format_wanted_type *next = wanted_type_ptr->next; - ggc_free (wanted_type_ptr); - wanted_type_ptr = next; - } - } } } @@ -2252,6 +2269,12 @@ check_format_types (format_wanted_type *types, const char *format_start, && (!pedantic || i < 2) && char_type_flag) continue; + if (types->scalar_identity_flag + && (TREE_CODE (cur_type) == TREE_CODE (wanted_type) + || (INTEGRAL_TYPE_P (cur_type) + && INTEGRAL_TYPE_P (wanted_type))) + && TYPE_PRECISION (cur_type) == TYPE_PRECISION (wanted_type)) + continue; /* Now we have a type mismatch. */ format_type_warning (types->name, format_start, format_length, wanted_type, types->pointer_count, @@ -2443,7 +2466,8 @@ init_dynamic_gfc_info (void) locus = identifier_global_value (locus); if (locus) { - if (TREE_CODE (locus) != TYPE_DECL) + if (TREE_CODE (locus) != TYPE_DECL + || TREE_TYPE (locus) == error_mark_node) { error ("% is not defined as a type"); locus = 0; @@ -2588,15 +2612,9 @@ init_dynamic_diag_info (void) xmemdup (gcc_diag_char_table, sizeof (gcc_diag_char_table), sizeof (gcc_diag_char_table)); - if (loc) - { - i = find_char_info_specifier_index (diag_fci, 'H'); - diag_fci[i].types[0].type = &loc; - diag_fci[i].pointer_count = 1; - } if (t) { - i = find_char_info_specifier_index (diag_fci, 'J'); + i = find_char_info_specifier_index (diag_fci, 'K'); diag_fci[i].types[0].type = &t; diag_fci[i].pointer_count = 1; } @@ -2608,19 +2626,13 @@ init_dynamic_diag_info (void) xmemdup (gcc_tdiag_char_table, sizeof (gcc_tdiag_char_table), sizeof (gcc_tdiag_char_table)); - if (loc) - { - i = find_char_info_specifier_index (tdiag_fci, 'H'); - tdiag_fci[i].types[0].type = &loc; - tdiag_fci[i].pointer_count = 1; - } if (t) { /* All specifiers taking a tree share the same struct. */ i = find_char_info_specifier_index (tdiag_fci, 'D'); tdiag_fci[i].types[0].type = &t; tdiag_fci[i].pointer_count = 1; - i = find_char_info_specifier_index (tdiag_fci, 'J'); + i = find_char_info_specifier_index (tdiag_fci, 'K'); tdiag_fci[i].types[0].type = &t; tdiag_fci[i].pointer_count = 1; } @@ -2632,19 +2644,13 @@ init_dynamic_diag_info (void) xmemdup (gcc_cdiag_char_table, sizeof (gcc_cdiag_char_table), sizeof (gcc_cdiag_char_table)); - if (loc) - { - i = find_char_info_specifier_index (cdiag_fci, 'H'); - cdiag_fci[i].types[0].type = &loc; - cdiag_fci[i].pointer_count = 1; - } if (t) { /* All specifiers taking a tree share the same struct. */ i = find_char_info_specifier_index (cdiag_fci, 'D'); cdiag_fci[i].types[0].type = &t; cdiag_fci[i].pointer_count = 1; - i = find_char_info_specifier_index (cdiag_fci, 'J'); + i = find_char_info_specifier_index (cdiag_fci, 'K'); cdiag_fci[i].types[0].type = &t; cdiag_fci[i].pointer_count = 1; } @@ -2656,19 +2662,13 @@ init_dynamic_diag_info (void) xmemdup (gcc_cxxdiag_char_table, sizeof (gcc_cxxdiag_char_table), sizeof (gcc_cxxdiag_char_table)); - if (loc) - { - i = find_char_info_specifier_index (cxxdiag_fci, 'H'); - cxxdiag_fci[i].types[0].type = &loc; - cxxdiag_fci[i].pointer_count = 1; - } if (t) { /* All specifiers taking a tree share the same struct. */ i = find_char_info_specifier_index (cxxdiag_fci, 'D'); cxxdiag_fci[i].types[0].type = &t; cxxdiag_fci[i].pointer_count = 1; - i = find_char_info_specifier_index (cxxdiag_fci, 'J'); + i = find_char_info_specifier_index (cxxdiag_fci, 'K'); cxxdiag_fci[i].types[0].type = &t; cxxdiag_fci[i].pointer_count = 1; } @@ -2679,6 +2679,90 @@ 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 +#ifdef TARGET_OVERRIDES_FORMAT_INIT + extern void TARGET_OVERRIDES_FORMAT_INIT (void); +#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_INIT + TARGET_OVERRIDES_FORMAT_INIT (); +#endif + +#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 @@ -2694,8 +2778,8 @@ handle_format_attribute (tree *node, tree ARG_UNUSED (name), tree args, add them to FORMAT_TYPES at first use. */ if (TARGET_FORMAT_TYPES != NULL && !dynamic_format_types) { - dynamic_format_types = xmalloc ((n_format_types + TARGET_N_FORMAT_TYPES) - * sizeof (dynamic_format_types[0])); + dynamic_format_types = XNEWVEC (format_kind_info, + n_format_types + TARGET_N_FORMAT_TYPES); memcpy (dynamic_format_types, format_types_orig, sizeof (format_types_orig)); memcpy (&dynamic_format_types[n_format_types], TARGET_FORMAT_TYPES, @@ -2738,7 +2822,10 @@ handle_format_attribute (tree *node, tree ARG_UNUSED (name), tree args, } } - 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; @@ -2746,7 +2833,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. */ + initialize certain bits at runtime. */ if (info.format_type == asm_fprintf_format_type || info.format_type == gcc_gfc_format_type || info.format_type == gcc_diag_format_type