From: Daniel Jacobowitz Date: Mon, 19 Jul 2004 14:48:09 +0000 (+0000) Subject: Makefile.in (c-format.o): Depend on c-format.h. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=a2bec818635587d03fa02bd57c2bf0985510de56;p=gcc.git Makefile.in (c-format.o): Depend on c-format.h. gcc/ * Makefile.in (c-format.o): Depend on c-format.h. * c-format.h: New file. (struct format_char_info): Add CHAIN member. * c-format.c: Move some types and constants to c-format.h. (format_type_error): Set to -1. (struct function_format_info): Use an int for format_type. (decode_format_type): Return an int. Return format_type_error on error. (print_char_table, asm_fprintf_char_table, gcc_diag_char_table) (gcc_diag_char_table, gcc_cdiag_char_table, gcc_cxxdiag_char_table) (scan_char_table, time_char_table, monetary_char_table): Initialize CHAIN to NULL. (n_format_types): New variable. (check_format_info_main): Handle CHAIN in format_char_info. (handle_format_attribute): Handle TARGET_FORMAT_TYPES and TARGET_N_FORMAT_TYPES. * config.gcc (i[34567]86-*-solaris2*, sparc64-*-solaris2*) (sparc-*-solaris2*): Include config/t-sol2 and config/sol2-c.c. * config/sol2-c.c: New file. * config/t-sol2: New file. * config/sol2.h (TARGET_N_FORMAT_TYPES, TARGET_FORMAT_TYPES): Define. * config/sparc/elf.h, config/sparc/sp64-elf.h: Undefine TARGET_N_FORMAT_TYPES and TARGET_FORMAT_TYPES. * doc/extend.texi (Target Format Checks): New section. (Function Attributes): Mention it. * doc/invoke.texi: Mention target format checks. * doc/sourcebuild.texi: Mention target format checks. * dc/tm.texi (Misc): Document TARGET_N_FORMAT_TYPES and TARGET_FORMAT_TYPES. testsuite/ * gcc.dg/format/cmn-err-1.c: New test. From-SVN: r84920 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b70d6d2cb61..ad0b3b7b525 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,36 @@ +2004-07-19 Daniel Jacobowitz + + * Makefile.in (c-format.o): Depend on c-format.h. + * c-format.h: New file. + (struct format_char_info): Add CHAIN member. + * c-format.c: Move some types and constants to c-format.h. + (format_type_error): Set to -1. + (struct function_format_info): Use an int for format_type. + (decode_format_type): Return an int. Return format_type_error + on error. + (print_char_table, asm_fprintf_char_table, gcc_diag_char_table) + (gcc_diag_char_table, gcc_cdiag_char_table, gcc_cxxdiag_char_table) + (scan_char_table, time_char_table, monetary_char_table): Initialize + CHAIN to NULL. + (n_format_types): New variable. + (check_format_info_main): Handle CHAIN in format_char_info. + (handle_format_attribute): Handle TARGET_FORMAT_TYPES and + TARGET_N_FORMAT_TYPES. + * config.gcc (i[34567]86-*-solaris2*, sparc64-*-solaris2*) + (sparc-*-solaris2*): Include config/t-sol2 and config/sol2-c.c. + * config/sol2-c.c: New file. + * config/t-sol2: New file. + * config/sol2.h (TARGET_N_FORMAT_TYPES, TARGET_FORMAT_TYPES): Define. + * config/sparc/elf.h, config/sparc/sp64-elf.h: Undefine + TARGET_N_FORMAT_TYPES and TARGET_FORMAT_TYPES. + + * doc/extend.texi (Target Format Checks): New section. + (Function Attributes): Mention it. + * doc/invoke.texi: Mention target format checks. + * doc/sourcebuild.texi: Mention target format checks. + * dc/tm.texi (Misc): Document TARGET_N_FORMAT_TYPES and + TARGET_FORMAT_TYPES. + 2004-07-19 Andreas Krebbel * config/s390/s390-protos.h (s390_return_address_offset): Prototype diff --git a/gcc/Makefile.in b/gcc/Makefile.in index c9793fc4b62..f8acb48f5b2 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1440,7 +1440,7 @@ attribs.o : attribs.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(FL builtin-types.def $(TARGET_H) langhooks.h c-format.o : c-format.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) langhooks.h \ - $(C_COMMON_H) $(FLAGS_H) toplev.h intl.h $(DIAGNOSTIC_H) + $(C_COMMON_H) $(FLAGS_H) toplev.h intl.h $(DIAGNOSTIC_H) c-format.h c-semantics.o : c-semantics.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ $(C_TREE_H) $(FLAGS_H) toplev.h output.h c-pragma.h $(RTL_H) $(GGC_H) \ diff --git a/gcc/c-format.c b/gcc/c-format.c index 98274ee649d..4aff5f2660b 100644 --- a/gcc/c-format.c +++ b/gcc/c-format.c @@ -30,6 +30,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "intl.h" #include "diagnostic.h" #include "langhooks.h" +#include "c-format.h" /* Set format warning options according to a -Wformat=n option. */ @@ -53,23 +54,24 @@ set_Wformat (int setting) /* Handle attributes associated with format checking. */ -/* This must be in the same order as format_types, with format_type_error - last. */ +/* This must be in the same order as format_types, except for + format_type_error. Target-specific format types do not have + matching enum values. */ enum format_type { printf_format_type, asm_fprintf_format_type, gcc_diag_format_type, gcc_cdiag_format_type, gcc_cxxdiag_format_type, scanf_format_type, strftime_format_type, - strfmon_format_type, format_type_error }; + strfmon_format_type, format_type_error = -1}; typedef struct function_format_info { - enum format_type format_type; /* type of format (printf, scanf, etc.) */ + int format_type; /* type of format (printf, scanf, etc.) */ unsigned HOST_WIDE_INT format_num; /* number of format argument */ unsigned HOST_WIDE_INT first_arg_num; /* number of first arg (zero for varargs) */ } function_format_info; static bool decode_format_attr (tree, function_format_info *, int); -static enum format_type decode_format_type (const char *); +static int decode_format_type (const char *); static bool check_format_string (tree argument, unsigned HOST_WIDE_INT format_num, @@ -230,33 +232,6 @@ decode_format_attr (tree args, function_format_info *info, int validated_p) /* Check a call to a format function against a parameter list. */ -/* The meaningfully distinct length modifiers for format checking recognized - by GCC. */ -enum format_lengths -{ - FMT_LEN_none, - FMT_LEN_hh, - FMT_LEN_h, - FMT_LEN_l, - FMT_LEN_ll, - FMT_LEN_L, - FMT_LEN_z, - FMT_LEN_t, - FMT_LEN_j, - FMT_LEN_MAX -}; - - -/* The standard versions in which various format features appeared. */ -enum format_std_version -{ - STD_C89, - STD_C94, - STD_C9L, /* C99, but treat as C89 if -Wno-long-long. */ - STD_C99, - STD_EXT -}; - /* The C standard version C++ is treated as equivalent to or inheriting from, for the purpose of format features supported. */ #define CPLUSPLUS_STD_VER STD_C94 @@ -280,195 +255,6 @@ enum format_std_version ? (warn_long_long ? STD_C99 : STD_C89) \ : (VER))) -/* Flags that may apply to a particular kind of format checked by GCC. */ -enum -{ - /* This format converts arguments of types determined by the - format string. */ - FMT_FLAG_ARG_CONVERT = 1, - /* The scanf allocation 'a' kludge applies to this format kind. */ - FMT_FLAG_SCANF_A_KLUDGE = 2, - /* A % during parsing a specifier is allowed to be a modified % rather - that indicating the format is broken and we are out-of-sync. */ - FMT_FLAG_FANCY_PERCENT_OK = 4, - /* With $ operand numbers, it is OK to reference the same argument more - than once. */ - FMT_FLAG_DOLLAR_MULTIPLE = 8, - /* This format type uses $ operand numbers (strfmon doesn't). */ - FMT_FLAG_USE_DOLLAR = 16, - /* Zero width is bad in this type of format (scanf). */ - FMT_FLAG_ZERO_WIDTH_BAD = 32, - /* Empty precision specification is OK in this type of format (printf). */ - FMT_FLAG_EMPTY_PREC_OK = 64, - /* Gaps are allowed in the arguments with $ operand numbers if all - arguments are pointers (scanf). */ - FMT_FLAG_DOLLAR_GAP_POINTER_OK = 128 - /* Not included here: details of whether width or precision may occur - (controlled by width_char and precision_char); details of whether - '*' can be used for these (width_type and precision_type); details - 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. */ - const char *name; - /* Index into a format_char_info.types array. */ - enum format_lengths index; - /* Standard version this length appears in. */ - enum format_std_version std; - /* Same, if the modifier can be repeated, or NULL if it can't. */ - const char *double_name; - enum format_lengths double_index; - enum format_std_version double_std; -} format_length_info; - - -/* Structure describing the combination of a conversion specifier - (or a set of specifiers which act identically) and a length modifier. */ -typedef struct -{ - /* The standard version this combination of length and type appeared in. - This is only relevant if greater than those for length and type - individually; otherwise it is ignored. */ - enum format_std_version std; - /* The name to use for the type, if different from that generated internally - (e.g., "signed size_t"). */ - const char *name; - /* The type itself. */ - tree *type; -} format_type_detail; - - -/* Macros to fill out tables of these. */ -#define NOARGUMENTS { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN } -#define BADLEN { 0, NULL, NULL } -#define NOLENGTHS { BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN } - - -/* Structure describing a format conversion specifier (or a set of specifiers - which act identically), and the length modifiers used with it. */ -typedef struct -{ - const char *format_chars; - int pointer_count; - enum format_std_version std; - /* Types accepted for each length modifier. */ - format_type_detail types[FMT_LEN_MAX]; - /* List of other modifier characters allowed with these specifiers. - This lists flags, and additionally "w" for width, "p" for precision - (right precision, for strfmon), "#" for left precision (strfmon), - "a" for scanf "a" allocation extension (not applicable in C99 mode), - "*" for scanf suppression, and "E" and "O" for those strftime - modifiers. */ - const char *flag_chars; - /* List of additional flags describing these conversion specifiers. - "c" for generic character pointers being allowed, "2" for strftime - two digit year formats, "3" for strftime formats giving two digit - years in some locales, "4" for "2" which becomes "3" with an "E" modifier, - "o" if use of strftime "O" is a GNU extension beyond C99, - "W" if the argument is a pointer which is dereferenced and written into, - "R" if the argument is a pointer which is dereferenced and read from, - "i" for printf integer formats where the '0' flag is ignored with - precision, and "[" for the starting character of a scanf scanset. */ - const char *flags2; -} format_char_info; - - -/* Structure describing a flag accepted by some kind of format. */ -typedef struct -{ - /* The flag character in question (0 for end of array). */ - int flag_char; - /* Zero if this entry describes the flag character in general, or a - nonzero character that may be found in flags2 if it describes the - flag when used with certain formats only. If the latter, only - the first such entry found that applies to the current conversion - specifier is used; the values of `name' and `long_name' it supplies - will be used, if non-NULL and the standard version is higher than - the unpredicated one, for any pedantic warning. For example, 'o' - for strftime formats (meaning 'O' is an extension over C99). */ - int predicate; - /* Nonzero if the next character after this flag in the format should - be skipped ('=' in strfmon), zero otherwise. */ - int skip_next_char; - /* The name to use for this flag in diagnostic messages. For example, - N_("`0' flag"), N_("field width"). */ - const char *name; - /* Long name for this flag in diagnostic messages; currently only used for - "ISO C does not support ...". For example, N_("the `I' printf flag"). */ - const char *long_name; - /* The standard version in which it appeared. */ - enum format_std_version std; -} format_flag_spec; - - -/* Structure describing a combination of flags that is bad for some kind - of format. */ -typedef struct -{ - /* The first flag character in question (0 for end of array). */ - int flag_char1; - /* The second flag character. */ - int flag_char2; - /* Nonzero if the message should say that the first flag is ignored with - the second, zero if the combination should simply be objected to. */ - int ignored; - /* Zero if this entry applies whenever this flag combination occurs, - a nonzero character from flags2 if it only applies in some - circumstances (e.g. 'i' for printf formats ignoring 0 with precision). */ - int predicate; -} format_flag_pair; - - -/* Structure describing a particular kind of format processed by GCC. */ -typedef struct -{ - /* The name of this kind of format, for use in diagnostics. Also - the name of the attribute (without preceding and following __). */ - const char *name; - /* Specifications of the length modifiers accepted; possibly NULL. */ - const format_length_info *length_char_specs; - /* Details of the conversion specification characters accepted. */ - const format_char_info *conversion_specs; - /* String listing the flag characters that are accepted. */ - const char *flag_chars; - /* String listing modifier characters (strftime) accepted. May be NULL. */ - const char *modifier_chars; - /* Details of the flag characters, including pseudo-flags. */ - const format_flag_spec *flag_specs; - /* Details of bad combinations of flags. */ - const format_flag_pair *bad_flag_pairs; - /* Flags applicable to this kind of format. */ - int flags; - /* Flag character to treat a width as, or 0 if width not used. */ - int width_char; - /* Flag character to treat a left precision (strfmon) as, - or 0 if left precision not used. */ - int left_precision_char; - /* Flag character to treat a precision (for strfmon, right precision) as, - or 0 if precision not used. */ - int precision_char; - /* If a flag character has the effect of suppressing the conversion of - an argument ('*' in scanf), that flag character, otherwise 0. */ - int suppression_char; - /* Flag character to treat a length modifier as (ignored if length - modifiers not used). Need not be placed in flag_chars for conversion - specifiers, but is used to check for bad combinations such as length - modifier with assignment suppression in scanf. */ - int length_code_char; - /* Pointer to type of argument expected if '*' is used for a width, - or NULL if '*' not used for widths. */ - tree *width_type; - /* Pointer to type of argument expected if '*' is used for a precision, - or NULL if '*' not used for precisions. */ - tree *precision_type; -} format_kind_info; - - /* Structure describing details of a type expected in format checking, and the type to check against it. */ typedef struct format_wanted_type @@ -698,229 +484,174 @@ static const format_flag_pair strfmon_flag_pairs[] = }; -#define T_I &integer_type_node -#define T89_I { STD_C89, NULL, T_I } -#define T_L &long_integer_type_node -#define T89_L { STD_C89, NULL, T_L } -#define T_LL &long_long_integer_type_node -#define T9L_LL { STD_C9L, NULL, T_LL } -#define TEX_LL { STD_EXT, NULL, T_LL } -#define T_S &short_integer_type_node -#define T89_S { STD_C89, NULL, T_S } -#define T_UI &unsigned_type_node -#define T89_UI { STD_C89, NULL, T_UI } -#define T_UL &long_unsigned_type_node -#define T89_UL { STD_C89, NULL, T_UL } -#define T_ULL &long_long_unsigned_type_node -#define T9L_ULL { STD_C9L, NULL, T_ULL } -#define TEX_ULL { STD_EXT, NULL, T_ULL } -#define T_US &short_unsigned_type_node -#define T89_US { STD_C89, NULL, T_US } -#define T_F &float_type_node -#define T89_F { STD_C89, NULL, T_F } -#define T99_F { STD_C99, NULL, T_F } -#define T_D &double_type_node -#define T89_D { STD_C89, NULL, T_D } -#define T99_D { STD_C99, NULL, T_D } -#define T_LD &long_double_type_node -#define T89_LD { STD_C89, NULL, T_LD } -#define T99_LD { STD_C99, NULL, T_LD } -#define T_C &char_type_node -#define T89_C { STD_C89, NULL, T_C } -#define T_SC &signed_char_type_node -#define T99_SC { STD_C99, NULL, T_SC } -#define T_UC &unsigned_char_type_node -#define T99_UC { STD_C99, NULL, T_UC } -#define T_V &void_type_node -#define T89_V { STD_C89, NULL, T_V } -#define T_W &wchar_type_node -#define T94_W { STD_C94, "wchar_t", T_W } -#define TEX_W { STD_EXT, "wchar_t", T_W } -#define T_WI &wint_type_node -#define T94_WI { STD_C94, "wint_t", T_WI } -#define TEX_WI { STD_EXT, "wint_t", T_WI } -#define T_ST &size_type_node -#define T99_ST { STD_C99, "size_t", T_ST } -#define T_SST &signed_size_type_node -#define T99_SST { STD_C99, "signed size_t", T_SST } -#define T_PD &ptrdiff_type_node -#define T99_PD { STD_C99, "ptrdiff_t", T_PD } -#define T_UPD &unsigned_ptrdiff_type_node -#define T99_UPD { STD_C99, "unsigned ptrdiff_t", T_UPD } -#define T_IM &intmax_type_node -#define T99_IM { STD_C99, "intmax_t", T_IM } -#define T_UIM &uintmax_type_node -#define T99_UIM { STD_C99, "uintmax_t", T_UIM } - static const format_char_info 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 }, "-wp0 +'I", "i" }, - { "oxX", 0, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_ULL, T99_ST, T99_UPD, T99_UIM }, "-wp0#", "i" }, - { "u", 0, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_ULL, T99_ST, T99_UPD, T99_UIM }, "-wp0'I", "i" }, - { "fgG", 0, STD_C89, { T89_D, BADLEN, BADLEN, T99_D, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN }, "-wp0 +#'I", "" }, - { "eE", 0, STD_C89, { T89_D, BADLEN, BADLEN, T99_D, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN }, "-wp0 +#I", "" }, - { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, T94_WI, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "" }, - { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "cR" }, - { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "c" }, - { "n", 1, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, BADLEN, T99_SST, T99_PD, T99_IM }, "", "W" }, + { "di", 0, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, TEX_LL, T99_SST, T99_PD, T99_IM }, "-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 }, "-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 }, "-wp0'I", "i", NULL }, + { "fgG", 0, STD_C89, { T89_D, BADLEN, BADLEN, T99_D, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN }, "-wp0 +#'I", "", NULL }, + { "eE", 0, STD_C89, { T89_D, BADLEN, BADLEN, T99_D, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN }, "-wp0 +#I", "", NULL }, + { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, T94_WI, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "", NULL }, + { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "cR", NULL }, + { "p", 1, STD_C89, { T89_V, 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 }, "", "W", NULL }, /* C99 conversion specifiers. */ - { "F", 0, STD_C99, { T99_D, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN }, "-wp0 +#'I", "" }, - { "aA", 0, STD_C99, { T99_D, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN }, "-wp0 +#", "" }, + { "F", 0, STD_C99, { T99_D, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN }, "-wp0 +#'I", "", NULL }, + { "aA", 0, STD_C99, { T99_D, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN }, "-wp0 +#", "", NULL }, /* X/Open conversion specifiers. */ - { "C", 0, STD_EXT, { TEX_WI, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "" }, - { "S", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "R" }, + { "C", 0, STD_EXT, { TEX_WI, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "", NULL }, + { "S", 1, STD_EXT, { TEX_W, 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 }, "-wp", "" }, - { NULL, 0, 0, NOLENGTHS, NULL, NULL } + { "m", 0, STD_EXT, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "", NULL }, + { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL } }; static const format_char_info asm_fprintf_char_table[] = { /* C89 conversion specifiers. */ - { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0 +", "i" }, - { "oxX", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0#", "i" }, - { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0", "i" }, - { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "" }, - { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "cR" }, + { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0 +", "i", NULL }, + { "oxX", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0#", "i", NULL }, + { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp0", "i", NULL }, + { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-w", "", NULL }, + { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "-wp", "cR", NULL }, /* asm_fprintf conversion specifiers. */ - { "O", 0, STD_C89, NOARGUMENTS, "", "" }, - { "R", 0, STD_C89, NOARGUMENTS, "", "" }, - { "I", 0, STD_C89, NOARGUMENTS, "", "" }, - { "L", 0, STD_C89, NOARGUMENTS, "", "" }, - { "U", 0, STD_C89, NOARGUMENTS, "", "" }, - { "r", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "" }, - { "@", 0, STD_C89, NOARGUMENTS, "", "" }, - { NULL, 0, 0, NOLENGTHS, NULL, NULL } + { "O", 0, STD_C89, NOARGUMENTS, "", "", NULL }, + { "R", 0, STD_C89, NOARGUMENTS, "", "", NULL }, + { "I", 0, STD_C89, NOARGUMENTS, "", "", NULL }, + { "L", 0, STD_C89, NOARGUMENTS, "", "", NULL }, + { "U", 0, STD_C89, NOARGUMENTS, "", "", NULL }, + { "r", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "", NULL }, + { "@", 0, STD_C89, NOARGUMENTS, "", "", NULL }, + { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL } }; static const format_char_info gcc_diag_char_table[] = { /* C89 conversion specifiers. */ - { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "" }, - { "ox", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "" }, - { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "" }, - { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "" }, - { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "pq", "cR" }, - { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "c" }, + { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, + { "ox", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, + { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, + { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, + { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "pq", "cR", NULL }, + { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "c", NULL }, /* 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", "" }, + { "H", 0, STD_C89, { T89_V, 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 }, "q", "" }, + { "J", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - { "<>'", 0, STD_C89, NOARGUMENTS, "", "" }, - { "m", 0, STD_C89, NOARGUMENTS, "q", "" }, - { NULL, 0, 0, NOLENGTHS, NULL, NULL } + { "<>'", 0, STD_C89, NOARGUMENTS, "", "", NULL }, + { "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL }, + { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL } }; static const format_char_info gcc_cdiag_char_table[] = { /* C89 conversion specifiers. */ - { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "" }, - { "ox", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "" }, - { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "" }, - { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "" }, - { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "pq", "cR" }, - { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "c" }, + { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, + { "ox", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, + { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, + { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, + { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "pq", "cR", NULL }, + { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "c", NULL }, /* 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", "" }, + { "H", 0, STD_C89, { T89_V, 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 }, "q", "" }, + { "DEFJT", 0, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - { "<>'", 0, STD_C89, NOARGUMENTS, "", "" }, - { "m", 0, STD_C89, NOARGUMENTS, "q", "" }, - { NULL, 0, 0, NOLENGTHS, NULL, NULL } + { "<>'", 0, STD_C89, NOARGUMENTS, "", "", NULL }, + { "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL }, + { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL } }; static const format_char_info gcc_cxxdiag_char_table[] = { /* C89 conversion specifiers. */ - { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "" }, - { "ox", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "" }, - { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "" }, - { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "" }, - { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "pq", "cR" }, - { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "c" }, + { "di", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, + { "ox", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, + { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, + { "c", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, + { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "pq", "cR", NULL }, + { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "c", NULL }, /* 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", "" }, + { "H", 0, STD_C89, { T89_V, 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 }, "q+#", "" }, + { "ADEFJTV",0,STD_C89,{ T89_V, 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 }, "q", "" }, + { "CLOPQ",0,STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "", NULL }, - { "<>'", 0, STD_C89, NOARGUMENTS, "", "" }, - { "m", 0, STD_C89, NOARGUMENTS, "q", "" }, - { NULL, 0, 0, NOLENGTHS, NULL, NULL } + { "<>'", 0, STD_C89, NOARGUMENTS, "", "", NULL }, + { "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL }, + { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL } }; static const format_char_info 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 }, "*w'I", "W" }, - { "u", 1, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_ULL, T99_ST, T99_UPD, T99_UIM }, "*w'I", "W" }, - { "oxX", 1, STD_C89, { T89_UI, T99_UC, T89_US, T89_UL, T9L_ULL, TEX_ULL, T99_ST, T99_UPD, T99_UIM }, "*w", "W" }, - { "efgEG", 1, STD_C89, { T89_F, BADLEN, BADLEN, T89_D, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN }, "*w'", "W" }, - { "c", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w", "cW" }, - { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*aw", "cW" }, - { "[", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*aw", "cW[" }, - { "p", 2, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w", "W" }, - { "n", 1, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, BADLEN, T99_SST, T99_PD, T99_IM }, "", "W" }, + { "di", 1, STD_C89, { T89_I, T99_SC, T89_S, T89_L, T9L_LL, TEX_LL, T99_SST, T99_PD, T99_IM }, "*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 }, "*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 }, "*w", "W", NULL }, + { "efgEG", 1, STD_C89, { T89_F, BADLEN, BADLEN, T89_D, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN }, "*w'", "W", NULL }, + { "c", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w", "cW", NULL }, + { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*aw", "cW", NULL }, + { "[", 1, STD_C89, { T89_C, BADLEN, BADLEN, T94_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*aw", "cW[", NULL }, + { "p", 2, STD_C89, { T89_V, 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 }, "", "W", NULL }, /* C99 conversion specifiers. */ - { "FaA", 1, STD_C99, { T99_F, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN }, "*w'", "W" }, + { "FaA", 1, STD_C99, { T99_F, BADLEN, BADLEN, T99_D, BADLEN, T99_LD, BADLEN, BADLEN, BADLEN }, "*w'", "W", NULL }, /* X/Open conversion specifiers. */ - { "C", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*w", "W" }, - { "S", 1, STD_EXT, { TEX_W, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "*aw", "W" }, - { NULL, 0, 0, NOLENGTHS, NULL, NULL } + { "C", 1, STD_EXT, { TEX_W, 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 }, "*aw", "W", NULL }, + { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL } }; static const format_char_info time_char_table[] = { /* C89 conversion specifiers. */ - { "ABZab", 0, STD_C89, NOLENGTHS, "^#", "" }, - { "cx", 0, STD_C89, NOLENGTHS, "E", "3" }, - { "HIMSUWdmw", 0, STD_C89, NOLENGTHS, "-_0Ow", "" }, - { "j", 0, STD_C89, NOLENGTHS, "-_0Ow", "o" }, - { "p", 0, STD_C89, NOLENGTHS, "#", "" }, - { "X", 0, STD_C89, NOLENGTHS, "E", "" }, - { "y", 0, STD_C89, NOLENGTHS, "EO-_0w", "4" }, - { "Y", 0, STD_C89, NOLENGTHS, "-_0EOw", "o" }, - { "%", 0, STD_C89, NOLENGTHS, "", "" }, + { "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. */ - { "C", 0, STD_C99, NOLENGTHS, "-_0EOw", "o" }, - { "D", 0, STD_C99, NOLENGTHS, "", "2" }, - { "eVu", 0, STD_C99, NOLENGTHS, "-_0Ow", "" }, - { "FRTnrt", 0, STD_C99, NOLENGTHS, "", "" }, - { "g", 0, STD_C99, NOLENGTHS, "O-_0w", "2o" }, - { "G", 0, STD_C99, NOLENGTHS, "-_0Ow", "o" }, - { "h", 0, STD_C99, NOLENGTHS, "^#", "" }, - { "z", 0, STD_C99, NOLENGTHS, "O", "o" }, + { "C", 0, STD_C99, NOLENGTHS, "-_0EOw", "o", NULL }, + { "D", 0, STD_C99, NOLENGTHS, "", "2", NULL }, + { "eVu", 0, STD_C99, NOLENGTHS, "-_0Ow", "", NULL }, + { "FRTnrt", 0, STD_C99, NOLENGTHS, "", "", NULL }, + { "g", 0, STD_C99, NOLENGTHS, "O-_0w", "2o", NULL }, + { "G", 0, STD_C99, NOLENGTHS, "-_0Ow", "o", NULL }, + { "h", 0, STD_C99, NOLENGTHS, "^#", "", NULL }, + { "z", 0, STD_C99, NOLENGTHS, "O", "o", NULL }, /* GNU conversion specifiers. */ - { "kls", 0, STD_EXT, NOLENGTHS, "-_0Ow", "" }, - { "P", 0, STD_EXT, NOLENGTHS, "", "" }, - { NULL, 0, 0, NOLENGTHS, NULL, NULL } + { "kls", 0, STD_EXT, NOLENGTHS, "-_0Ow", "", NULL }, + { "P", 0, STD_EXT, NOLENGTHS, "", "", NULL }, + { NULL, 0, 0, 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 }, "=^+(!-w#p", "" }, - { NULL, 0, 0, NOLENGTHS, NULL, NULL } + { "in", 0, STD_C89, { T89_D, BADLEN, BADLEN, BADLEN, BADLEN, T89_LD, BADLEN, BADLEN, BADLEN }, "=^+(!-w#p", "", NULL }, + { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL } }; - /* This must be in the same order as enum format_type. */ static const format_kind_info format_types_orig[] = { @@ -976,9 +707,12 @@ static const format_kind_info format_types_orig[] = new data if necessary, while still allowing the original data to be const. */ static const format_kind_info *format_types = format_types_orig; -/* We can modify this one. */ +/* We can modify this one. We also add target-specific format types + to the end of the array. */ static format_kind_info *dynamic_format_types; +static int n_format_types = ARRAY_SIZE (format_types_orig); + /* Structure detailing the results of checking a format function call where the format expression may be a conditional expression with many leaves resulting from nested conditional expressions. */ @@ -1036,24 +770,24 @@ static void format_type_warning (const char *, const char *, int, tree, /* Decode a format type from a string, returning the type, or format_type_error if not valid, in which case the caller should print an error message. */ -static enum format_type +static int decode_format_type (const char *s) { int i; int slen; slen = strlen (s); - for (i = 0; i < (int) format_type_error; i++) + for (i = 0; i < n_format_types; i++) { int alen; if (!strcmp (s, format_types[i].name)) - break; + return i; alen = strlen (format_types[i].name); if (slen == alen + 4 && s[0] == '_' && s[1] == '_' && s[slen - 1] == '_' && s[slen - 2] == '_' && !strncmp (s + 2, format_types[i].name, alen)) - break; + return i; } - return ((enum format_type) i); + return format_type_error; } @@ -2188,6 +1922,8 @@ check_format_info_main (format_check_results *res, } } + main_wanted_type.next = NULL; + /* Finally. . .check type of argument against desired type! */ if (info->first_arg_num == 0) continue; @@ -2204,6 +1940,8 @@ check_format_info_main (format_check_results *res, } else { + format_wanted_type *wanted_type_ptr; + if (main_arg_num != 0) { arg_num = main_arg_num; @@ -2219,46 +1957,72 @@ check_format_info_main (format_check_results *res, } else has_operand_number = 0; + } + + wanted_type_ptr = &main_wanted_type; + while (fci) + { if (params == 0) { warning ("too few arguments for format"); return; } + + cur_param = TREE_VALUE (params); + params = TREE_CHAIN (params); + + 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->char_lenient_flag = 0; + if (strchr (fci->flags2, 'c') != 0) + wanted_type_ptr->char_lenient_flag = 1; + wanted_type_ptr->writing_in_flag = 0; + wanted_type_ptr->reading_from_flag = 0; + if (aflag) + wanted_type_ptr->writing_in_flag = 1; + else + { + if (strchr (fci->flags2, 'W') != 0) + wanted_type_ptr->writing_in_flag = 1; + if (strchr (fci->flags2, 'R') != 0) + wanted_type_ptr->reading_from_flag = 1; + } + wanted_type_ptr->name = NULL; + wanted_type_ptr->param = cur_param; + wanted_type_ptr->arg_num = arg_num; + wanted_type_ptr->next = NULL; + if (last_wanted_type != 0) + last_wanted_type->next = wanted_type_ptr; + if (first_wanted_type == 0) + first_wanted_type = wanted_type_ptr; + last_wanted_type = wanted_type_ptr; + + fci = fci->chain; + if (fci) + { + wanted_type_ptr = ggc_alloc (sizeof (main_wanted_type)); + arg_num++; + wanted_type = *fci->types[length_chars_val].type; + wanted_type_name = fci->types[length_chars_val].name; + } } - cur_param = TREE_VALUE (params); - params = TREE_CHAIN (params); - main_wanted_type.wanted_type = wanted_type; - main_wanted_type.wanted_type_name = wanted_type_name; - main_wanted_type.pointer_count = fci->pointer_count + aflag; - main_wanted_type.char_lenient_flag = 0; - if (strchr (fci->flags2, 'c') != 0) - main_wanted_type.char_lenient_flag = 1; - main_wanted_type.writing_in_flag = 0; - main_wanted_type.reading_from_flag = 0; - if (aflag) - main_wanted_type.writing_in_flag = 1; - else - { - if (strchr (fci->flags2, 'W') != 0) - main_wanted_type.writing_in_flag = 1; - if (strchr (fci->flags2, 'R') != 0) - main_wanted_type.reading_from_flag = 1; - } - main_wanted_type.name = NULL; - main_wanted_type.param = cur_param; - main_wanted_type.arg_num = arg_num; - main_wanted_type.next = NULL; - if (last_wanted_type != 0) - last_wanted_type->next = &main_wanted_type; - if (first_wanted_type == 0) - first_wanted_type = &main_wanted_type; - last_wanted_type = &main_wanted_type; } 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; + } + } } } @@ -2686,6 +2450,10 @@ init_dynamic_diag_info (void) } } +#ifdef TARGET_FORMAT_TYPES +extern const format_kind_info TARGET_FORMAT_TYPES[]; +#endif + /* Handle a "format" attribute; arguments as in struct attribute_spec.handler. */ tree @@ -2696,6 +2464,23 @@ handle_format_attribute (tree *node, tree name ATTRIBUTE_UNUSED, tree args, function_format_info info; tree argument; +#ifdef TARGET_FORMAT_TYPES + /* If the target provides additional format types, we need to + 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])); + memcpy (dynamic_format_types, format_types_orig, + sizeof (format_types_orig)); + memcpy (&dynamic_format_types[n_format_types], TARGET_FORMAT_TYPES, + TARGET_N_FORMAT_TYPES * sizeof (dynamic_format_types[0])); + + format_types = dynamic_format_types; + n_format_types += TARGET_N_FORMAT_TYPES; + } +#endif + if (!decode_format_attr (args, &info, 0)) { *no_add_attrs = true; diff --git a/gcc/c-format.h b/gcc/c-format.h new file mode 100644 index 00000000000..a1861b54477 --- /dev/null +++ b/gcc/c-format.h @@ -0,0 +1,299 @@ +/* Check calls to formatted I/O functions (-Wformat). + Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + 2001, 2002, 2003, 2004 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 2, 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 COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#ifndef GCC_C_FORMAT_H +#define GCC_C_FORMAT_H + +/* The meaningfully distinct length modifiers for format checking recognized + by GCC. */ +enum format_lengths +{ + FMT_LEN_none, + FMT_LEN_hh, + FMT_LEN_h, + FMT_LEN_l, + FMT_LEN_ll, + FMT_LEN_L, + FMT_LEN_z, + FMT_LEN_t, + FMT_LEN_j, + FMT_LEN_MAX +}; + + +/* The standard versions in which various format features appeared. */ +enum format_std_version +{ + STD_C89, + STD_C94, + STD_C9L, /* C99, but treat as C89 if -Wno-long-long. */ + STD_C99, + STD_EXT +}; + +/* Flags that may apply to a particular kind of format checked by GCC. */ +enum +{ + /* This format converts arguments of types determined by the + format string. */ + FMT_FLAG_ARG_CONVERT = 1, + /* The scanf allocation 'a' kludge applies to this format kind. */ + FMT_FLAG_SCANF_A_KLUDGE = 2, + /* A % during parsing a specifier is allowed to be a modified % rather + that indicating the format is broken and we are out-of-sync. */ + FMT_FLAG_FANCY_PERCENT_OK = 4, + /* With $ operand numbers, it is OK to reference the same argument more + than once. */ + FMT_FLAG_DOLLAR_MULTIPLE = 8, + /* This format type uses $ operand numbers (strfmon doesn't). */ + FMT_FLAG_USE_DOLLAR = 16, + /* Zero width is bad in this type of format (scanf). */ + FMT_FLAG_ZERO_WIDTH_BAD = 32, + /* Empty precision specification is OK in this type of format (printf). */ + FMT_FLAG_EMPTY_PREC_OK = 64, + /* Gaps are allowed in the arguments with $ operand numbers if all + arguments are pointers (scanf). */ + FMT_FLAG_DOLLAR_GAP_POINTER_OK = 128 + /* Not included here: details of whether width or precision may occur + (controlled by width_char and precision_char); details of whether + '*' can be used for these (width_type and precision_type); details + 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. */ + const char *name; + /* Index into a format_char_info.types array. */ + enum format_lengths index; + /* Standard version this length appears in. */ + enum format_std_version std; + /* Same, if the modifier can be repeated, or NULL if it can't. */ + const char *double_name; + enum format_lengths double_index; + enum format_std_version double_std; +} format_length_info; + + +/* Structure describing the combination of a conversion specifier + (or a set of specifiers which act identically) and a length modifier. */ +typedef struct +{ + /* The standard version this combination of length and type appeared in. + This is only relevant if greater than those for length and type + individually; otherwise it is ignored. */ + enum format_std_version std; + /* The name to use for the type, if different from that generated internally + (e.g., "signed size_t"). */ + const char *name; + /* The type itself. */ + tree *type; +} format_type_detail; + + +/* Macros to fill out tables of these. */ +#define NOARGUMENTS { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN } +#define BADLEN { 0, NULL, NULL } +#define NOLENGTHS { BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN } + + +/* Structure describing a format conversion specifier (or a set of specifiers + which act identically), and the length modifiers used with it. */ +typedef struct format_char_info +{ + const char *format_chars; + int pointer_count; + enum format_std_version std; + /* Types accepted for each length modifier. */ + format_type_detail types[FMT_LEN_MAX]; + /* List of other modifier characters allowed with these specifiers. + This lists flags, and additionally "w" for width, "p" for precision + (right precision, for strfmon), "#" for left precision (strfmon), + "a" for scanf "a" allocation extension (not applicable in C99 mode), + "*" for scanf suppression, and "E" and "O" for those strftime + modifiers. */ + const char *flag_chars; + /* List of additional flags describing these conversion specifiers. + "c" for generic character pointers being allowed, "2" for strftime + two digit year formats, "3" for strftime formats giving two digit + years in some locales, "4" for "2" which becomes "3" with an "E" modifier, + "o" if use of strftime "O" is a GNU extension beyond C99, + "W" if the argument is a pointer which is dereferenced and written into, + "R" if the argument is a pointer which is dereferenced and read from, + "i" for printf integer formats where the '0' flag is ignored with + precision, and "[" for the starting character of a scanf scanset. */ + const char *flags2; + /* If this format conversion character consumes more than one argument, + CHAIN points to information about the next argument. For later + arguments, only POINTER_COUNT, TYPES, and the "c", "R", and "W" flags + in FLAGS2 are used. */ + const struct format_char_info *chain; +} format_char_info; + + +/* Structure describing a flag accepted by some kind of format. */ +typedef struct +{ + /* The flag character in question (0 for end of array). */ + int flag_char; + /* Zero if this entry describes the flag character in general, or a + nonzero character that may be found in flags2 if it describes the + flag when used with certain formats only. If the latter, only + the first such entry found that applies to the current conversion + specifier is used; the values of `name' and `long_name' it supplies + will be used, if non-NULL and the standard version is higher than + the unpredicated one, for any pedantic warning. For example, 'o' + for strftime formats (meaning 'O' is an extension over C99). */ + int predicate; + /* Nonzero if the next character after this flag in the format should + be skipped ('=' in strfmon), zero otherwise. */ + int skip_next_char; + /* The name to use for this flag in diagnostic messages. For example, + N_("`0' flag"), N_("field width"). */ + const char *name; + /* Long name for this flag in diagnostic messages; currently only used for + "ISO C does not support ...". For example, N_("the `I' printf flag"). */ + const char *long_name; + /* The standard version in which it appeared. */ + enum format_std_version std; +} format_flag_spec; + + +/* Structure describing a combination of flags that is bad for some kind + of format. */ +typedef struct +{ + /* The first flag character in question (0 for end of array). */ + int flag_char1; + /* The second flag character. */ + int flag_char2; + /* Nonzero if the message should say that the first flag is ignored with + the second, zero if the combination should simply be objected to. */ + int ignored; + /* Zero if this entry applies whenever this flag combination occurs, + a nonzero character from flags2 if it only applies in some + circumstances (e.g. 'i' for printf formats ignoring 0 with precision). */ + int predicate; +} format_flag_pair; + + +/* Structure describing a particular kind of format processed by GCC. */ +typedef struct +{ + /* The name of this kind of format, for use in diagnostics. Also + the name of the attribute (without preceding and following __). */ + const char *name; + /* Specifications of the length modifiers accepted; possibly NULL. */ + const format_length_info *length_char_specs; + /* Details of the conversion specification characters accepted. */ + const format_char_info *conversion_specs; + /* String listing the flag characters that are accepted. */ + const char *flag_chars; + /* String listing modifier characters (strftime) accepted. May be NULL. */ + const char *modifier_chars; + /* Details of the flag characters, including pseudo-flags. */ + const format_flag_spec *flag_specs; + /* Details of bad combinations of flags. */ + const format_flag_pair *bad_flag_pairs; + /* Flags applicable to this kind of format. */ + int flags; + /* Flag character to treat a width as, or 0 if width not used. */ + int width_char; + /* Flag character to treat a left precision (strfmon) as, + or 0 if left precision not used. */ + int left_precision_char; + /* Flag character to treat a precision (for strfmon, right precision) as, + or 0 if precision not used. */ + int precision_char; + /* If a flag character has the effect of suppressing the conversion of + an argument ('*' in scanf), that flag character, otherwise 0. */ + int suppression_char; + /* Flag character to treat a length modifier as (ignored if length + modifiers not used). Need not be placed in flag_chars for conversion + specifiers, but is used to check for bad combinations such as length + modifier with assignment suppression in scanf. */ + int length_code_char; + /* Pointer to type of argument expected if '*' is used for a width, + or NULL if '*' not used for widths. */ + tree *width_type; + /* Pointer to type of argument expected if '*' is used for a precision, + or NULL if '*' not used for precisions. */ + tree *precision_type; +} format_kind_info; + +#define T_I &integer_type_node +#define T89_I { STD_C89, NULL, T_I } +#define T_L &long_integer_type_node +#define T89_L { STD_C89, NULL, T_L } +#define T_LL &long_long_integer_type_node +#define T9L_LL { STD_C9L, NULL, T_LL } +#define TEX_LL { STD_EXT, NULL, T_LL } +#define T_S &short_integer_type_node +#define T89_S { STD_C89, NULL, T_S } +#define T_UI &unsigned_type_node +#define T89_UI { STD_C89, NULL, T_UI } +#define T_UL &long_unsigned_type_node +#define T89_UL { STD_C89, NULL, T_UL } +#define T_ULL &long_long_unsigned_type_node +#define T9L_ULL { STD_C9L, NULL, T_ULL } +#define TEX_ULL { STD_EXT, NULL, T_ULL } +#define T_US &short_unsigned_type_node +#define T89_US { STD_C89, NULL, T_US } +#define T_F &float_type_node +#define T89_F { STD_C89, NULL, T_F } +#define T99_F { STD_C99, NULL, T_F } +#define T_D &double_type_node +#define T89_D { STD_C89, NULL, T_D } +#define T99_D { STD_C99, NULL, T_D } +#define T_LD &long_double_type_node +#define T89_LD { STD_C89, NULL, T_LD } +#define T99_LD { STD_C99, NULL, T_LD } +#define T_C &char_type_node +#define T89_C { STD_C89, NULL, T_C } +#define T_SC &signed_char_type_node +#define T99_SC { STD_C99, NULL, T_SC } +#define T_UC &unsigned_char_type_node +#define T99_UC { STD_C99, NULL, T_UC } +#define T_V &void_type_node +#define T89_V { STD_C89, NULL, T_V } +#define T_W &wchar_type_node +#define T94_W { STD_C94, "wchar_t", T_W } +#define TEX_W { STD_EXT, "wchar_t", T_W } +#define T_WI &wint_type_node +#define T94_WI { STD_C94, "wint_t", T_WI } +#define TEX_WI { STD_EXT, "wint_t", T_WI } +#define T_ST &size_type_node +#define T99_ST { STD_C99, "size_t", T_ST } +#define T_SST &signed_size_type_node +#define T99_SST { STD_C99, "signed size_t", T_SST } +#define T_PD &ptrdiff_type_node +#define T99_PD { STD_C99, "ptrdiff_t", T_PD } +#define T_UPD &unsigned_ptrdiff_type_node +#define T99_UPD { STD_C99, "unsigned ptrdiff_t", T_UPD } +#define T_IM &intmax_type_node +#define T99_IM { STD_C99, "intmax_t", T_IM } +#define T_UIM &uintmax_type_node +#define T99_UIM { STD_C99, "uintmax_t", T_UIM } + +#endif /* GCC_C_FORMAT_H */ diff --git a/gcc/config.gcc b/gcc/config.gcc index 26b4897ee43..9ce6d4eda1c 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -972,7 +972,9 @@ i[34567]86-*-sco3.2v5*) # 80386 running SCO Open Server 5 i[34567]86-*-solaris2*) xm_defines="SMALL_ARG_MAX" tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h svr4.h i386/sysv4.h sol2.h i386/sol2.h" - tmake_file="i386/t-sol2 t-svr4" + tmake_file="t-sol2 i386/t-sol2 t-svr4" + c_target_objs="sol2-c.o" + cxx_target_objs="sol2-c.o" if test x$gnu_ld = xyes; then tmake_file="$tmake_file t-slibgcc-elf-ver" else @@ -1851,12 +1853,14 @@ sparc64-*-solaris2* | sparcv9-*-solaris2*) if test x$gas = xyes; then tm_file="${tm_file} sparc/sol2-gas-bi.h" fi - tmake_file="sparc/t-sol2 sparc/t-sol2-64 sparc/t-crtfm" + tmake_file="t-sol2 sparc/t-sol2 sparc/t-sol2-64 sparc/t-crtfm" if test x$gnu_ld = xyes; then tmake_file="$tmake_file t-slibgcc-elf-ver" else tmake_file="$tmake_file t-slibgcc-sld" fi + c_target_objs="sol2-c.o" + cxx_target_objs="sol2-c.o" extra_parts="crt1.o crti.o crtn.o gcrt1.o crtbegin.o crtend.o" case ${enable_threads}:${have_pthread_h}:${have_thread_h} in no:*:*) ;; @@ -1870,7 +1874,7 @@ sparc-*-solaris2*) if test x$gnu_ld = xyes; then tm_file="${tm_file} sparc/sol2-gld.h" fi - tmake_file="sparc/t-sol2 sparc/t-crtfm" + tmake_file="t-sol2 sparc/t-sol2 sparc/t-crtfm" if test x$gnu_ld = xyes; then tmake_file="$tmake_file t-slibgcc-elf-ver" else @@ -1894,6 +1898,8 @@ sparc-*-solaris2*) need_64bit_hwint=yes ;; esac + c_target_objs="sol2-c.o" + cxx_target_objs="sol2-c.o" extra_parts="crt1.o crti.o crtn.o gcrt1.o gmon.o crtbegin.o crtend.o" case ${enable_threads}:${have_pthread_h}:${have_thread_h} in no:*:*) ;; diff --git a/gcc/config/sol2-c.c b/gcc/config/sol2-c.c new file mode 100644 index 00000000000..70fdb377a48 --- /dev/null +++ b/gcc/config/sol2-c.c @@ -0,0 +1,72 @@ +/* Solaris support needed only by C/C++ frontends. + Copyright (C) 2004 Free Software Foundation, Inc. + Contributed by CodeSourcery, LLC. + +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 2, 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 COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tree.h" + +#include "c-format.h" +#include "intl.h" + +/* cmn_err only accepts "l" and "ll". */ +static const format_length_info cmn_err_length_specs[] = +{ + { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C89 }, + { NULL, 0, 0, NULL, 0, 0 } +}; + +static const format_flag_spec cmn_err_flag_specs[] = +{ + { 'w', 0, 0, N_("field width"), N_("field width 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 cmn_err_flag_pairs[] = +{ + { 0, 0, 0, 0 } +}; + +static const format_char_info bitfield_string_type = + { "b", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "cR", NULL }; + +static const format_char_info cmn_err_char_table[] = +{ + /* C89 conversion specifiers. */ + { "dD", 0, STD_C89, { T89_I, BADLEN, BADLEN, T89_L, T9L_LL, BADLEN, BADLEN, BADLEN, BADLEN }, "w", "", NULL }, + { "oOxX",0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "w", "", NULL }, + { "u", 0, STD_C89, { T89_UI, BADLEN, BADLEN, T89_UL, T9L_ULL, BADLEN, BADLEN, BADLEN, BADLEN }, "w", "", NULL }, + { "c", 0, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "w", "", NULL }, + { "s", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "w", "cR", NULL }, + { "b", 0, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "", &bitfield_string_type }, + { NULL, 0, 0, NOLENGTHS, NULL, NULL, NULL } +}; + +const format_kind_info solaris_format_types[] = { + { "cmn_err", cmn_err_length_specs, cmn_err_char_table, "", NULL, + cmn_err_flag_specs, cmn_err_flag_pairs, + FMT_FLAG_ARG_CONVERT|FMT_FLAG_EMPTY_PREC_OK, + 'w', 0, 0, 0, 'L', + &integer_type_node, &integer_type_node + } +}; diff --git a/gcc/config/sol2.h b/gcc/config/sol2.h index aa567bc4780..f595395befb 100644 --- a/gcc/config/sol2.h +++ b/gcc/config/sol2.h @@ -205,3 +205,6 @@ __enable_execute_stack (void *addr) \ perror ("mprotect of trampoline code"); \ } \ } + +#define TARGET_N_FORMAT_TYPES 1 +#define TARGET_FORMAT_TYPES solaris_format_types diff --git a/gcc/config/sparc/elf.h b/gcc/config/sparc/elf.h index 5f01a34b590..150f0979375 100644 --- a/gcc/config/sparc/elf.h +++ b/gcc/config/sparc/elf.h @@ -48,3 +48,7 @@ Boston, MA 02111-1307, USA. */ #undef SUN_INTEGER_MULTIPLY_64 #define SUN_INTEGER_MULTIPLY_64 0 + +/* Don't include Solaris-specific format checks. */ +#undef TARGET_N_FORMAT_TYPES +#undef TARGET_FORMAT_TYPES diff --git a/gcc/config/sparc/sp64-elf.h b/gcc/config/sparc/sp64-elf.h index 650c3ff907b..16fa8e06a4e 100644 --- a/gcc/config/sparc/sp64-elf.h +++ b/gcc/config/sparc/sp64-elf.h @@ -122,3 +122,7 @@ crtbegin.o%s \ #undef PREFERRED_DEBUGGING_TYPE #define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG + +/* Don't include Solaris-specific format checks. */ +#undef TARGET_N_FORMAT_TYPES +#undef TARGET_FORMAT_TYPES diff --git a/gcc/config/t-sol2 b/gcc/config/t-sol2 new file mode 100644 index 00000000000..022e4704511 --- /dev/null +++ b/gcc/config/t-sol2 @@ -0,0 +1,5 @@ +# Solaris-specific format checking +sol2-c.o: $(srcdir)/config/sol2-c.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ + tree.h c-format.h intl.h + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/config/sol2-c.c diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 1df022107be..3374bab49a5 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -472,6 +472,7 @@ extensions, accepted by GCC in C89 mode and in C++. * Offsetof:: Special syntax for implementing @code{offsetof}. * Other Builtins:: Other built-in functions. * Target Builtins:: Built-in functions specific to particular targets. +* Target Format Checks:: Format checks specific to particular targets. * Pragmas:: Pragmas accepted by GCC. * Unnamed Fields:: Unnamed struct/union fields within structs/unions. * Thread-Local:: Per-thread variables. @@ -2173,6 +2174,10 @@ standard modes, the X/Open function @code{strfmon} is also checked as are @code{printf_unlocked} and @code{fprintf_unlocked}. @xref{C Dialect Options,,Options Controlling C Dialect}. +The target may provide additional types of format checks. +@xref{Target Format Checks,,Format Checks Specific to Particular +Target Machines}. + @item format_arg (@var{string-index}) @cindex @code{format_arg} function attribute @opindex Wformat-nonliteral @@ -7209,6 +7214,25 @@ vector signed int vec_any_numeric (vector float); vector signed int vec_any_out (vector float, vector float); @end smallexample +@node Target Format Checks +@section Format Checks Specific to Particular Target Machines + +For some target machines, GCC supports additional options to the +format attribute +(@pxref{Function Attributes,,Declaring Attributes of Functions}). + +@menu +* Solaris Format Checks:: +@end menu + +@node Solaris Format Checks +@subsection Solaris Format Checks + +Solaris targets support the @code{cmn_err} (or @code{__cmn_err__}) format +check. @code{cmn_err} accepts a subset of the standard @code{printf} +conversions, and the two-argument @code{%b} conversion for displaying +bit-fields. See the Solaris man page for @code{cmn_err} for more information. + @node Pragmas @section Pragmas Accepted by GCC @cindex pragmas diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 14f756b1c4d..43f2df66ddb 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -2113,7 +2113,7 @@ specified, and that the conversions specified in the format string make sense. This includes standard functions, and others specified by format attributes (@pxref{Function Attributes}), in the @code{printf}, @code{scanf}, @code{strftime} and @code{strfmon} (an X/Open extension, -not in the C standard) families. +not in the C standard) families (or other target-specific families). The formats are checked against the format features supported by GNU libc version 2.2. These include all ISO C90 and C99 features, as well diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi index d2b834ad6d2..f985e503a6e 100644 --- a/gcc/doc/sourcebuild.texi +++ b/gcc/doc/sourcebuild.texi @@ -766,6 +766,9 @@ pragmas supported. Documentation in @file{gcc/doc/extend.texi} of any target-specific built-in functions supported. @item +Documentation in @file{gcc/doc/extend.texi} of any target-specific +format checking styles supported. +@item Documentation in @file{gcc/doc/md.texi} of any target-specific constraint letters (@pxref{Machine Constraints, , Constraints for Particular Machines}). diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index c7aade3edbf..a8c410f8ec8 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -9278,3 +9278,14 @@ for a virtual function @var{fndecl} when constructing thunks, functions, if a target supports aliases (ie. defines @code{ASM_OUTPUT_DEF}), @code{false} otherwise, @end deftypefn + +@defmac TARGET_FORMAT_TYPES +If defined, this macro is the name of a global variable containing +target-specific format checking information for the @option{-Wformat} +option. The default is to have no target-specific format checks. +@end defmac + +@defmac TARGET_N_FORMAT_TYPES +If defined, this macro is the number of entries in +@code{TARGET_FORMAT_TYPES}. +@end defmac diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 6df5bc92478..1ca5cb5d13c 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2004-07-19 Daniel Jacobowitz + + * gcc.dg/format/cmn-err-1.c: New test. + 2004-07-19 Joseph S. Myers * g++.dg/warn/Wparentheses-1.C, g++.dg/warn/Wparentheses-2.C, diff --git a/gcc/testsuite/gcc.dg/format/cmn-err-1.c b/gcc/testsuite/gcc.dg/format/cmn-err-1.c new file mode 100644 index 00000000000..ac4b1f0f442 --- /dev/null +++ b/gcc/testsuite/gcc.dg/format/cmn-err-1.c @@ -0,0 +1,36 @@ +/* { dg-do compile { target *-*-solaris2.* } } */ +/* { dg-options "-Wformat" } */ + +#include "format.h" + +void cmn_err_func (int level, char * format, ...) + __attribute__((format (cmn_err, 2, 3))); + +void cmn_err_func (int level, char * format, ...) +{ +} + +const char *string = "foo"; + +int main() +{ + int i = 1; + long l = 2; + llong ll = 3; + + cmn_err_func (0, "%s", string); + cmn_err_func (0, "%d %D %o %O %x %X %u", i, i, i, i, i, i, i); + cmn_err_func (0, "%ld %lD %lo %lO %lx %lX %lu", l, l, l, l, l, l, l); + cmn_err_func (0, "%lld %llD %llo %llO %llx %llX %llu", + ll, ll, ll, ll, ll, ll, ll); + cmn_err_func (0, "%b %s", i, "\01Foo", string); + + cmn_err_func (0, "%i", i); /* { dg-error "unknown|too many" } */ + cmn_err_func (0, "%d", l); /* { dg-error "expects type" } */ + cmn_err_func (0, "%b"); /* { dg-error "too few" } */ + cmn_err_func (0, "%b", i); /* { dg-error "too few" } */ + cmn_err_func (0, "%b", i, i); /* { dg-error "expects type" } */ + cmn_err_func (0, "%b", string, i); /* { dg-error "expects type" } */ + + return 0; +}