https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90205
Jakub Jelinek <jakub at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- Status|ASSIGNED |NEW CC| |dmalcolm at gcc dot gnu.org Assignee|jakub at gcc dot gnu.org |unassigned at gcc dot gnu.org --- Comment #5 from Jakub Jelinek <jakub at gcc dot gnu.org> --- I've been thinking about something like: --- gcc/c/c-format.c.jj 2019-02-26 00:43:18.000000000 +0100 +++ gcc/c/c-format.c 2019-04-23 16:44:54.552064471 +0200 @@ -1060,7 +1060,7 @@ static void check_format_types (const su vec<location_t> *arglocs); static void format_type_warning (const substring_loc &fmt_loc, location_t param_loc, - format_wanted_type *, tree, + format_wanted_type *, tree, tree, tree, const format_kind_info *fki, int offset_to_type_start, @@ -3109,7 +3109,7 @@ check_format_types (const substring_loc if (!cur_param) { format_type_warning (fmt_loc, UNKNOWN_LOCATION, types, wanted_type, - NULL, fki, offset_to_type_start, + NULL, NULL, fki, offset_to_type_start, conversion_char); continue; } @@ -3197,8 +3197,8 @@ check_format_types (const substring_loc } else { - format_type_warning (fmt_loc, param_loc, - types, wanted_type, orig_cur_type, fki, + format_type_warning (fmt_loc, param_loc, types, wanted_type, + orig_cur_type, NULL, fki, offset_to_type_start, conversion_char); break; } @@ -3268,7 +3268,7 @@ check_format_types (const substring_loc continue; /* Now we have a type mismatch. */ format_type_warning (fmt_loc, param_loc, types, - wanted_type, orig_cur_type, fki, + wanted_type, orig_cur_type, cur_param, fki, offset_to_type_start, conversion_char); } } @@ -3339,7 +3339,7 @@ test_get_modifier_for_format_len () Wformat type errors where the argument has type ARG_TYPE. */ static bool -matching_type_p (tree spec_type, tree arg_type) +matching_type_p (tree spec_type, tree arg_type, tree cur_param) { gcc_assert (spec_type); gcc_assert (arg_type); @@ -3353,14 +3353,29 @@ matching_type_p (tree spec_type, tree ar spec_type = TYPE_CANONICAL (spec_type); arg_type = TYPE_CANONICAL (arg_type); + if (spec_type == arg_type) + return true; + if (TREE_CODE (spec_type) == INTEGER_TYPE && TREE_CODE (arg_type) == INTEGER_TYPE && (TYPE_UNSIGNED (spec_type) ? spec_type == c_common_unsigned_type (arg_type) : spec_type == c_common_signed_type (arg_type))) - return true; + { + if (!warn_format_signedness) + return true; + if (TYPE_UNSIGNED (spec_type) + && cur_param != NULL_TREE + && TREE_CODE (cur_param) == NOP_EXPR) + { + tree t = TREE_TYPE (TREE_OPERAND (cur_param, 0)); + if (TYPE_UNSIGNED (t) + && spec_type == lang_hooks.types.type_promotes_to (t)) + return true; + } + } - return spec_type == arg_type; + return false; } /* Subroutine of get_format_for_type. @@ -3380,7 +3395,7 @@ matching_type_p (tree spec_type, tree ar static char * get_format_for_type_1 (const format_kind_info *fki, tree arg_type, - char conversion_char) + tree cur_param, char conversion_char) { gcc_assert (arg_type); @@ -3402,7 +3417,7 @@ get_format_for_type_1 (const format_kind const format_type_detail *ftd = &spec->types[i]; if (!ftd->type) continue; - if (matching_type_p (*ftd->type, effective_arg_type)) + if (matching_type_p (*ftd->type, effective_arg_type, cur_param)) { const char *len_modifier = get_modifier_for_format_len (fki->length_char_specs, @@ -3439,7 +3454,7 @@ get_format_for_type_1 (const format_kind static char * get_format_for_type (const format_kind_info *fki, tree arg_type, - char conversion_char) + tree cur_param, char conversion_char) { gcc_assert (arg_type); gcc_assert (conversion_char); @@ -3447,13 +3462,14 @@ get_format_for_type (const format_kind_i /* First pass: look for a format_char_info containing CONVERSION_CHAR If we find one, then presumably the length modifier was incorrect (or absent). */ - char *result = get_format_for_type_1 (fki, arg_type, conversion_char); + char *result = get_format_for_type_1 (fki, arg_type, cur_param, + conversion_char); if (result) return result; /* Second pass: we didn't find a match for CONVERSION_CHAR, so try matching just on the type. */ - return get_format_for_type_1 (fki, arg_type, '\0'); + return get_format_for_type_1 (fki, arg_type, cur_param, '\0'); } /* Attempt to get a string for use as a replacement fix-it hint for the @@ -3489,7 +3505,7 @@ get_format_for_type (const format_kind_i static char * get_corrected_substring (const substring_loc &fmt_loc, format_wanted_type *type, tree arg_type, - const format_kind_info *fki, + tree cur_param, const format_kind_info *fki, int offset_to_type_start, char conversion_char) { /* Attempt to provide hints for argument types, but not for field widths @@ -3554,7 +3570,8 @@ get_corrected_substring (const substring (length modifier and conversion char), based on ARG_TYPE and CONVERSION_CHAR. In the above example, this would be "ld". */ - char *format_for_type = get_format_for_type (fki, arg_type, conversion_char); + char *format_for_type = get_format_for_type (fki, arg_type, cur_param, + conversion_char); if (!format_for_type) { free (prefix); @@ -3656,7 +3673,7 @@ class range_label_for_format_type_mismat precision"), the placement in the format string, a possibly more friendly name of WANTED_TYPE, and the number of pointer dereferences are taken from TYPE. ARG_TYPE is the type of the actual argument, - or NULL if it is missing. + or NULL if it is missing. CUR_PARAM is the actual argument tree. OFFSET_TO_TYPE_START is the offset within the execution-charset encoded format string to where type information begins for the conversion @@ -3683,6 +3700,7 @@ format_type_warning (const substring_loc location_t param_loc, format_wanted_type *type, tree wanted_type, tree arg_type, + tree cur_param, const format_kind_info *fki, int offset_to_type_start, char conversion_char) @@ -3723,7 +3741,7 @@ format_type_warning (const substring_loc /* Get a string for use as a replacement fix-it hint for the range in fmt_loc, or NULL. */ char *corrected_substring - = get_corrected_substring (fmt_loc, type, arg_type, fki, + = get_corrected_substring (fmt_loc, type, arg_type, cur_param, fki, offset_to_type_start, conversion_char); format_string_diagnostic_t diag (fmt_loc, &fmt_label, param_loc, ¶m_label, corrected_substring); @@ -4285,7 +4303,7 @@ assert_format_for_type_streq (const loca gcc_assert (expected_format); gcc_assert (type); - char *actual_format = get_format_for_type (fki, type, conversion_char); + char *actual_format = get_format_for_type (fki, type, NULL, conversion_char); ASSERT_STREQ_AT (loc, expected_format, actual_format); free (actual_format); } but that actually suggests %o instead of %u, I'd say if one writes %d or %i then %u is a better suggestion.