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,
&param_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.

Reply via email to