diff options
Diffstat (limited to 'gcc/c-format.c')
-rw-r--r-- | gcc/c-format.c | 230 |
1 files changed, 110 insertions, 120 deletions
diff --git a/gcc/c-format.c b/gcc/c-format.c index 01814e15467..1a2401955cb 100644 --- a/gcc/c-format.c +++ b/gcc/c-format.c @@ -34,8 +34,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA /* Set format warning options according to a -Wformat=n option. */ void -set_Wformat (setting) - int setting; +set_Wformat (int setting) { warn_format = setting; warn_format_y2k = setting; @@ -67,9 +66,8 @@ typedef struct function_format_info unsigned HOST_WIDE_INT first_arg_num; /* number of first arg (zero for varargs) */ } function_format_info; -static bool decode_format_attr PARAMS ((tree, - function_format_info *, int)); -static enum format_type decode_format_type PARAMS ((const char *)); +static bool decode_format_attr (tree, function_format_info *, int); +static enum format_type decode_format_type (const char *); static bool check_format_string (tree argument, unsigned HOST_WIDE_INT format_num, @@ -81,12 +79,8 @@ static bool get_constant (tree expr, unsigned HOST_WIDE_INT *value, /* Handle a "format_arg" attribute; arguments as in struct attribute_spec.handler. */ tree -handle_format_arg_attribute (node, name, args, flags, no_add_attrs) - tree *node; - tree name ATTRIBUTE_UNUSED; - tree args; - int flags; - bool *no_add_attrs; +handle_format_arg_attribute (tree *node, tree name ATTRIBUTE_UNUSED, + tree args, int flags, bool *no_add_attrs) { tree type = *node; tree format_num_expr = TREE_VALUE (args); @@ -151,7 +145,7 @@ check_format_string (tree argument, unsigned HOST_WIDE_INT format_num, /* Strip any conversions from the expression, verify it is a constant, and store its value. If validated_p is true, abort on errors. - Returns true on success, false otherwise. */ + Returns true on success, false otherwise. */ bool get_constant(tree expr, unsigned HOST_WIDE_INT *value, int validated_p) { @@ -180,10 +174,7 @@ get_constant(tree expr, unsigned HOST_WIDE_INT *value, int validated_p) successfully decoded, false otherwise. */ static bool -decode_format_attr (args, info, validated_p) - tree args; - function_format_info *info; - int validated_p; +decode_format_attr (tree args, function_format_info *info, int validated_p) { tree format_type_id = TREE_VALUE (args); tree format_num_expr = TREE_VALUE (TREE_CHAIN (args)); @@ -855,6 +846,8 @@ 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. */ +static format_kind_info *dynamic_format_types; /* Structure detailing the results of checking a format function call where the format expression may be a conditional expression with @@ -891,32 +884,30 @@ typedef struct int *status; } format_check_context; -static void check_format_info PARAMS ((int *, function_format_info *, tree)); -static void check_format_arg PARAMS ((void *, tree, unsigned HOST_WIDE_INT)); -static void check_format_info_main PARAMS ((int *, format_check_results *, - function_format_info *, - const char *, int, tree, - unsigned HOST_WIDE_INT)); -static void status_warning PARAMS ((int *, const char *, ...)) +static void check_format_info (int *, function_format_info *, tree); +static void check_format_arg (void *, tree, unsigned HOST_WIDE_INT); +static void check_format_info_main (int *, format_check_results *, + function_format_info *, + const char *, int, tree, + unsigned HOST_WIDE_INT); +static void status_warning (int *, const char *, ...) ATTRIBUTE_PRINTF_2; -static void init_dollar_format_checking PARAMS ((int, tree)); -static int maybe_read_dollar_number PARAMS ((int *, const char **, int, - tree, tree *, - const format_kind_info *)); -static void finish_dollar_format_checking PARAMS ((int *, format_check_results *, int)); +static void init_dollar_format_checking (int, tree); +static int maybe_read_dollar_number (int *, const char **, int, + tree, tree *, const format_kind_info *); +static void finish_dollar_format_checking (int *, format_check_results *, int); -static const format_flag_spec *get_flag_spec PARAMS ((const format_flag_spec *, - int, const char *)); +static const format_flag_spec *get_flag_spec (const format_flag_spec *, + int, const char *); -static void check_format_types PARAMS ((int *, format_wanted_type *)); +static void check_format_types (int *, format_wanted_type *); /* 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 -decode_format_type (s) - const char *s; +decode_format_type (const char *s) { int i; int slen; @@ -943,10 +934,7 @@ decode_format_type (s) attribute themselves. */ void -check_function_format (status, attrs, params) - int *status; - tree attrs; - tree params; +check_function_format (int *status, tree attrs, tree params) { tree a; @@ -1039,9 +1027,7 @@ static int dollar_format_warned; function; PARAMS is the list of arguments starting at this argument. */ static void -init_dollar_format_checking (first_arg_num, params) - int first_arg_num; - tree params; +init_dollar_format_checking (int first_arg_num, tree params) { tree oparams = params; @@ -1096,14 +1082,9 @@ init_dollar_format_checking (first_arg_num, params) a $ format is found, *FORMAT is updated to point just after it. */ static int -maybe_read_dollar_number (status, format, dollar_needed, params, param_ptr, - fki) - int *status; - const char **format; - int dollar_needed; - tree params; - tree *param_ptr; - const format_kind_info *fki; +maybe_read_dollar_number (int *status, const char **format, + int dollar_needed, tree params, tree *param_ptr, + const format_kind_info *fki) { int argnum; int overflow_flag; @@ -1208,10 +1189,7 @@ maybe_read_dollar_number (status, format, dollar_needed, params, param_ptr, pointers. */ static void -finish_dollar_format_checking (status, res, pointer_gap_ok) - int *status; - format_check_results *res; - int pointer_gap_ok; +finish_dollar_format_checking (int *status, format_check_results *res, int pointer_gap_ok) { int i; bool found_pointer_gap = false; @@ -1246,10 +1224,7 @@ finish_dollar_format_checking (status, res, pointer_gap_ok) of these is found, it is returned, otherwise NULL is returned. */ static const format_flag_spec * -get_flag_spec (spec, flag, predicates) - const format_flag_spec *spec; - int flag; - const char *predicates; +get_flag_spec (const format_flag_spec *spec, int flag, const char *predicates) { int i; for (i = 0; spec[i].flag_char != 0; i++) @@ -1277,10 +1252,7 @@ get_flag_spec (spec, flag, predicates) PARAMS is the list of argument values. */ static void -check_format_info (status, info, params) - int *status; - function_format_info *info; - tree params; +check_format_info (int *status, function_format_info *info, tree params) { format_check_context format_ctx; unsigned HOST_WIDE_INT arg_num; @@ -1378,10 +1350,8 @@ check_format_info (status, info, params) format_check_context. */ static void -check_format_arg (ctx, format_tree, arg_num) - void *ctx; - tree format_tree; - unsigned HOST_WIDE_INT arg_num; +check_format_arg (void *ctx, tree format_tree, + unsigned HOST_WIDE_INT arg_num) { format_check_context *format_ctx = ctx; format_check_results *res = format_ctx->res; @@ -1537,15 +1507,10 @@ check_format_arg (ctx, format_tree, arg_num) argument in the list of arguments. */ static void -check_format_info_main (status, res, info, format_chars, format_length, - params, arg_num) - int *status; - format_check_results *res; - function_format_info *info; - const char *format_chars; - int format_length; - tree params; - unsigned HOST_WIDE_INT arg_num; +check_format_info_main (int *status, format_check_results *res, + function_format_info *info, const char *format_chars, + int format_length, tree params, + unsigned HOST_WIDE_INT arg_num) { const char *orig_format_chars = format_chars; tree first_fillin_param = params; @@ -2168,9 +2133,7 @@ check_format_info_main (status, res, info, format_chars, format_length, /* Check the argument types from a single format conversion (possibly including width and precision arguments). */ static void -check_format_types (status, types) - int *status; - format_wanted_type *types; +check_format_types (int *status, format_wanted_type *types) { for (; types != 0; types = types->next) { @@ -2367,15 +2330,72 @@ check_format_types (status, types) } } +/* Given a format_length_info array FLI, and a character C, this + function returns the index into the conversion_specs where that + modifier's data is located. If the character isn't found it + aborts. */ +static unsigned int +find_length_info_modifier_index (const format_length_info *fli, int c) +{ + unsigned int i = 0; + + while (fli->name) + { + if (strchr (fli->name, c)) + return i; + i++; fli++; + } + + /* We shouldn't be looking for a non-existent modifier. */ + abort (); +} + +/* Determine the type of HOST_WIDE_INT in the code being compiled for + use in GCC's __asm_fprintf__ custom format attribute. You must + have set dynamic_format_types before calling this function. */ +static void +init_dynamic_asm_fprintf_info (void) +{ + static tree hwi; + + if (!hwi) + { + format_length_info *new_asm_fprintf_length_specs; + unsigned int i; + + /* Find the underlying type for HOST_WIDE_INT. For the %w + length modifier to work, one must have issued: "typedef + HOST_WIDE_INT __gcc_host_wide_int__;" in one's source code + prior to using that modifier. */ + if (!(hwi = maybe_get_identifier ("__gcc_host_wide_int__")) + || !(hwi = DECL_ORIGINAL_TYPE (identifier_global_value (hwi)))) + abort (); + + /* Create a new (writable) copy of asm_fprintf_length_specs. */ + new_asm_fprintf_length_specs = xmemdup (asm_fprintf_length_specs, + sizeof (asm_fprintf_length_specs), + sizeof (asm_fprintf_length_specs)); + + /* HOST_WIDE_INT must be one of 'long' or 'long long'. */ + i = find_length_info_modifier_index (new_asm_fprintf_length_specs, 'w'); + if (hwi == long_integer_type_node) + new_asm_fprintf_length_specs[i].index = FMT_LEN_l; + else if (hwi == long_long_integer_type_node) + new_asm_fprintf_length_specs[i].index = FMT_LEN_ll; + else + abort (); + + /* Assign the new data for use. */ + dynamic_format_types[asm_fprintf_format_type].length_char_specs = + new_asm_fprintf_length_specs; + } +} + /* Handle a "format" attribute; arguments as in struct attribute_spec.handler. */ tree -handle_format_attribute (node, name, args, flags, no_add_attrs) - tree *node; - tree name ATTRIBUTE_UNUSED; - tree args; - int flags; - bool *no_add_attrs; +handle_format_attribute (tree *node, tree name ATTRIBUTE_UNUSED, tree args, + int flags, bool *no_add_attrs) { tree type = *node; function_format_info info; @@ -2424,44 +2444,14 @@ handle_format_attribute (node, name, args, flags, no_add_attrs) GCC's notion of HOST_WIDE_INT for checking %wd. */ if (info.format_type == asm_fprintf_format_type) { - static tree hwi; - tree orig; - - /* For this custom check to work, one must have issued: - "typedef HOST_WIDE_INT __gcc_host_wide_int__;" - in your source code prior to using this attribute. */ - if (!hwi) - { - format_kind_info *new_format_types; - format_length_info *new_asm_fprintf_length_specs; - - if (!(hwi = maybe_get_identifier ("__gcc_host_wide_int__"))) - abort (); - - /* Create a new (writable) copy of asm_fprintf_length_specs. */ - new_asm_fprintf_length_specs = - xmalloc (sizeof (asm_fprintf_length_specs)); - memcpy (new_asm_fprintf_length_specs, asm_fprintf_length_specs, - sizeof (asm_fprintf_length_specs)); - - /* Create a new (writable) copy of format_types. */ - new_format_types = xmalloc (sizeof (format_types_orig)); - memcpy (new_format_types, format_types_orig, sizeof (format_types_orig)); - - /* Find the underlying type for HOST_WIDE_INT. */ - orig = DECL_ORIGINAL_TYPE (identifier_global_value (hwi)); - if (orig == long_integer_type_node) - new_asm_fprintf_length_specs[1].index = FMT_LEN_l; - else if (orig == long_long_integer_type_node) - new_asm_fprintf_length_specs[1].index = FMT_LEN_ll; - else - abort (); - - /* Assign the new data for use. */ - new_format_types[asm_fprintf_format_type].length_char_specs = - new_asm_fprintf_length_specs; - format_types = new_format_types; - } + /* Our first time through, we have to make sure that our + format_type data is allocated dynamically and is modifiable. */ + if (!dynamic_format_types) + format_types = dynamic_format_types = + xmemdup (format_types_orig, sizeof (format_types_orig), + sizeof (format_types_orig)); + + init_dynamic_asm_fprintf_info(); } return NULL_TREE; |