c-family/c/c++: pass optional vec<location_t> to c-format.c
authorDavid Malcolm <dmalcolm@redhat.com>
Mon, 21 Aug 2017 16:53:10 +0000 (16:53 +0000)
committerDavid Malcolm <dmalcolm@gcc.gnu.org>
Mon, 21 Aug 2017 16:53:10 +0000 (16:53 +0000)
This patch passes along the vec<location_t> of argument locations
at a callsite from the C frontend to check_function_arguments and
from there to c-format.c, so that we can underline the pertinent
argument to mismatched format codes even for tree codes like decls
and constants which lack a location_t for their usage sites.

This takes e.g.:

    printf("hello %i %i %i ", foo, bar, baz);
                     ~^
                     %s

to:

    printf("hello %i %i %i ", foo, bar, baz);
                     ~^            ~~~
                     %s

which is useful for cases where there's more than one variadic argument.

gcc/c-family/ChangeLog:
* c-common.c (check_function_arguments): Add "arglogs" param; pass
it to check_function_format.
* c-common.h (check_function_arguments): Add vec<location_t> *
param.
(check_function_format): Likewise.
* c-format.c (struct format_check_context): Add field "arglocs".
(check_function_format): Add param "arglocs"; pass it to
check_format_info.
(check_format_info):  Add param "arglocs"; use it to initialize
new field of format_ctx.
(check_format_arg): Pass format_ctx->arglocs to new param of
check_format_info_main.
(class argument_parser): New field "arglocs".
(argument_parser::argument_parser): Add "arglocs_" param and use
it to initialize new field.
(argument_parser::check_argument_type): Pass new arglocs field to
check_format_types.
(check_format_info_main): Add param "arglocs", and use it when
constructing arg_parser.
(check_format_types): Add param "arglocs"; use it if non-NULL when
!EXPR_HAS_LOCATION (cur_param) to get at location information.

gcc/c/ChangeLog:
* c-typeck.c (build_function_call_vec): Pass arg_loc to call
to check_function_arguments.

gcc/cp/ChangeLog:
* call.c (build_over_call): Pass NULL for new parameter to
check_function_arguments.
* typeck.c (cp_build_function_call_vec): Likewise.

gcc/testsuite/ChangeLog:
* gcc.dg/format/diagnostic-ranges.c: Update expected results
to show underlining of all pertinent params.
* gcc.dg/format/pr72858.c: Likewise.

From-SVN: r251238

12 files changed:
gcc/c-family/ChangeLog
gcc/c-family/c-common.c
gcc/c-family/c-common.h
gcc/c-family/c-format.c
gcc/c/ChangeLog
gcc/c/c-typeck.c
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/typeck.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/format/diagnostic-ranges.c
gcc/testsuite/gcc.dg/format/pr72858.c

index aba158754d6f9a53d7ba14656914e3159bc89bae..86a8f1c28c1ca924de0024316f278e899e848942 100644 (file)
@@ -1,3 +1,27 @@
+2017-08-21  David Malcolm  <dmalcolm@redhat.com>
+
+       * c-common.c (check_function_arguments): Add "arglogs" param; pass
+       it to check_function_format.
+       * c-common.h (check_function_arguments): Add vec<location_t> *
+       param.
+       (check_function_format): Likewise.
+       * c-format.c (struct format_check_context): Add field "arglocs".
+       (check_function_format): Add param "arglocs"; pass it to
+       check_format_info.
+       (check_format_info):  Add param "arglocs"; use it to initialize
+       new field of format_ctx.
+       (check_format_arg): Pass format_ctx->arglocs to new param of
+       check_format_info_main.
+       (class argument_parser): New field "arglocs".
+       (argument_parser::argument_parser): Add "arglocs_" param and use
+       it to initialize new field.
+       (argument_parser::check_argument_type): Pass new arglocs field to
+       check_format_types.
+       (check_format_info_main): Add param "arglocs", and use it when
+       constructing arg_parser.
+       (check_format_types): Add param "arglocs"; use it if non-NULL when
+       !EXPR_HAS_LOCATION (cur_param) to get at location information.
+
 2017-08-18  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR c/53037
index 4dc3b338e5e99236daace7c7a69ab2dcb2f5bc77..156c89d02940ded84bdcc4253df9bbbe687804f0 100644 (file)
@@ -5539,7 +5539,7 @@ attribute_fallthrough_p (tree attr)
    diagnostics.  Return true if -Wnonnull warning has been diagnosed.  */
 bool
 check_function_arguments (location_t loc, const_tree fndecl, const_tree fntype,
-                         int nargs, tree *argarray)
+                         int nargs, tree *argarray, vec<location_t> *arglocs)
 {
   bool warned_p = false;
 
@@ -5553,7 +5553,7 @@ check_function_arguments (location_t loc, const_tree fndecl, const_tree fntype,
   /* Check for errors in format strings.  */
 
   if (warn_format || warn_suggest_attribute_format)
-    check_function_format (TYPE_ATTRIBUTES (fntype), nargs, argarray);
+    check_function_format (TYPE_ATTRIBUTES (fntype), nargs, argarray, arglocs);
 
   if (warn_format)
     check_function_sentinel (fntype, nargs, argarray);
index 980d39662fc936030fc4753cbbd29cc19fc775c9..8e367680600332fd9b4750221d3286468677d269 100644 (file)
@@ -808,7 +808,7 @@ extern tree fname_decl (location_t, unsigned, tree);
 
 extern int check_user_alignment (const_tree, bool);
 extern bool check_function_arguments (location_t loc, const_tree, const_tree,
-                                     int, tree *);
+                                     int, tree *, vec<location_t> *);
 extern void check_function_arguments_recurse (void (*)
                                              (void *, tree,
                                               unsigned HOST_WIDE_INT),
@@ -816,7 +816,7 @@ extern void check_function_arguments_recurse (void (*)
                                              unsigned HOST_WIDE_INT);
 extern bool check_builtin_function_arguments (location_t, vec<location_t>,
                                              tree, int, tree *);
-extern void check_function_format (tree, int, tree *);
+extern void check_function_format (tree, int, tree *, vec<location_t> *);
 extern bool attribute_fallthrough_p (tree);
 extern tree handle_format_attribute (tree *, tree, tree, int, bool *);
 extern tree handle_format_arg_attribute (tree *, tree, tree, int, bool *);
index 7c9095c2a5bab02b6dac1651756676b3d0744dc8..0dba9793311b7fbd1b2f770b6bb5b7a0e662bdff 100644 (file)
@@ -989,6 +989,7 @@ struct format_check_context
   format_check_results *res;
   function_format_info *info;
   tree params;
+  vec<location_t> *arglocs;
 };
 
 /* Return the format name (as specified in the original table) for the format
@@ -1011,14 +1012,16 @@ format_flags (int format_num)
   gcc_unreachable ();
 }
 
-static void check_format_info (function_format_info *, tree);
+static void check_format_info (function_format_info *, tree,
+                              vec<location_t> *);
 static void check_format_arg (void *, tree, unsigned HOST_WIDE_INT);
 static void check_format_info_main (format_check_results *,
                                    function_format_info *, const char *,
                                    location_t, tree,
                                    int, tree,
                                    unsigned HOST_WIDE_INT,
-                                   object_allocator<format_wanted_type> &);
+                                   object_allocator<format_wanted_type> &,
+                                   vec<location_t> *);
 
 static void init_dollar_format_checking (int, tree);
 static int maybe_read_dollar_number (const char **, int,
@@ -1033,7 +1036,8 @@ static void check_format_types (const substring_loc &fmt_loc,
                                format_wanted_type *,
                                const format_kind_info *fki,
                                int offset_to_type_start,
-                               char conversion_char);
+                               char conversion_char,
+                               vec<location_t> *arglocs);
 static void format_type_warning (const substring_loc &fmt_loc,
                                 source_range *param_range,
                                 format_wanted_type *, tree,
@@ -1076,7 +1080,8 @@ decode_format_type (const char *s)
    attribute themselves.  */
 
 void
-check_function_format (tree attrs, int nargs, tree *argarray)
+check_function_format (tree attrs, int nargs, tree *argarray,
+                      vec<location_t> *arglocs)
 {
   tree a;
 
@@ -1097,7 +1102,7 @@ check_function_format (tree attrs, int nargs, tree *argarray)
              int i;
              for (i = nargs - 1; i >= 0; i--)
                params = tree_cons (NULL_TREE, argarray[i], params);
-             check_format_info (&info, params);
+             check_format_info (&info, params, arglocs);
            }
 
          /* Attempt to detect whether the current function might benefit
@@ -1400,7 +1405,8 @@ get_flag_spec (const format_flag_spec *spec, int flag, const char *predicates)
    PARAMS is the list of argument values.  */
 
 static void
-check_format_info (function_format_info *info, tree params)
+check_format_info (function_format_info *info, tree params,
+                  vec<location_t> *arglocs)
 {
   format_check_context format_ctx;
   unsigned HOST_WIDE_INT arg_num;
@@ -1434,6 +1440,7 @@ check_format_info (function_format_info *info, tree params)
   format_ctx.res = &res;
   format_ctx.info = info;
   format_ctx.params = params;
+  format_ctx.arglocs = arglocs;
 
   check_function_arguments_recurse (check_format_arg, &format_ctx,
                                    format_tree, arg_num);
@@ -1518,6 +1525,7 @@ check_format_arg (void *ctx, tree format_tree,
   format_check_results *res = format_ctx->res;
   function_format_info *info = format_ctx->info;
   tree params = format_ctx->params;
+  vec<location_t> *arglocs = format_ctx->arglocs;
 
   int format_length;
   HOST_WIDE_INT offset;
@@ -1703,7 +1711,7 @@ check_format_arg (void *ctx, tree format_tree,
   res->number_other++;
   object_allocator <format_wanted_type> fwt_pool ("format_wanted_type pool");
   check_format_info_main (res, info, format_chars, fmt_param_loc, format_tree,
-                         format_length, params, arg_num, fwt_pool);
+                         format_length, params, arg_num, fwt_pool, arglocs);
 }
 
 /* Support class for argument_parser and check_format_info_main.
@@ -1768,7 +1776,8 @@ class argument_parser
                   const char * const orig_format_chars,
                   location_t format_string_loc, flag_chars_t &flag_chars,
                   int &has_operand_number, tree first_fillin_param,
-                  object_allocator <format_wanted_type> &fwt_pool_);
+                  object_allocator <format_wanted_type> &fwt_pool_,
+                  vec<location_t> *arglocs);
 
   bool read_any_dollar ();
 
@@ -1847,6 +1856,7 @@ class argument_parser
  private:
   format_wanted_type *first_wanted_type;
   format_wanted_type *last_wanted_type;
+  vec<location_t> *arglocs;
 };
 
 /* flag_chars_t's constructor.  */
@@ -1997,7 +2007,8 @@ argument_parser (function_format_info *info_, const char *&format_chars_,
                 flag_chars_t &flag_chars_,
                 int &has_operand_number_,
                 tree first_fillin_param_,
-                object_allocator <format_wanted_type> &fwt_pool_)
+                object_allocator <format_wanted_type> &fwt_pool_,
+                vec<location_t> *arglocs_)
 : info (info_),
   fki (&format_types[info->format_type]),
   flag_specs (fki->flag_specs),
@@ -2013,7 +2024,8 @@ argument_parser (function_format_info *info_, const char *&format_chars_,
   has_operand_number (has_operand_number_),
   first_fillin_param (first_fillin_param_),
   first_wanted_type (NULL),
-  last_wanted_type (NULL)
+  last_wanted_type (NULL),
+  arglocs (arglocs_)
 {
 }
 
@@ -2736,7 +2748,7 @@ check_argument_type (const format_char_info *fci,
       ptrdiff_t offset_to_type_start = type_start - orig_format_chars;
       check_format_types (fmt_loc, first_wanted_type, fki,
                          offset_to_type_start,
-                         conversion_char);
+                         conversion_char, arglocs);
     }
 
   return true;
@@ -2755,7 +2767,8 @@ check_format_info_main (format_check_results *res,
                        location_t fmt_param_loc, tree format_string_cst,
                        int format_length, tree params,
                        unsigned HOST_WIDE_INT arg_num,
-                       object_allocator <format_wanted_type> &fwt_pool)
+                       object_allocator <format_wanted_type> &fwt_pool,
+                       vec<location_t> *arglocs)
 {
   const char * const orig_format_chars = format_chars;
   const tree first_fillin_param = params;
@@ -2802,7 +2815,7 @@ check_format_info_main (format_check_results *res,
       argument_parser arg_parser (info, format_chars, format_string_cst,
                                  orig_format_chars, format_string_loc,
                                  flag_chars, has_operand_number,
-                                 first_fillin_param, fwt_pool);
+                                 first_fillin_param, fwt_pool, arglocs);
 
       if (!arg_parser.read_any_dollar ())
        return;
@@ -3032,7 +3045,8 @@ static void
 check_format_types (const substring_loc &fmt_loc,
                    format_wanted_type *types, const format_kind_info *fki,
                    int offset_to_type_start,
-                   char conversion_char)
+                   char conversion_char,
+                   vec<location_t> *arglocs)
 {
   for (; types != 0; types = types->next)
     {
@@ -3072,11 +3086,19 @@ check_format_types (const substring_loc &fmt_loc,
 
       source_range param_range;
       source_range *param_range_ptr;
-      if (CAN_HAVE_LOCATION_P (cur_param))
+      if (EXPR_HAS_LOCATION (cur_param))
        {
          param_range = EXPR_LOCATION_RANGE (cur_param);
          param_range_ptr = &param_range;
        }
+      else if (arglocs)
+       {
+         /* arg_num is 1-based.  */
+         gcc_assert (types->arg_num > 0);
+         location_t param_loc = (*arglocs)[types->arg_num - 1];
+         param_range = get_range_from_loc (line_table, param_loc);
+         param_range_ptr = &param_range;
+       }
       else
        param_range_ptr = NULL;
 
index 9dcd1c324806daf73e87b5d149cb188dfe7f1c76..64497a259ae97be3e198768c538f71bd332ecc2a 100644 (file)
@@ -1,3 +1,8 @@
+2017-08-21  David Malcolm  <dmalcolm@redhat.com>
+
+       * c-typeck.c (build_function_call_vec): Pass arg_loc to call
+       to check_function_arguments.
+
 2017-08-18  Marek Polacek  <polacek@redhat.com>
 
        * c-parser.c (c_parser_postfix_expression): Remove unused code.  Update
index c33601f6b625025e0376b3508036a7f036b4909b..d7ca14801b93678bf81ab1eb8ab1b9ea04a2868e 100644 (file)
@@ -3118,7 +3118,7 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc,
 
   /* Check that the arguments to the function are valid.  */
   bool warned_p = check_function_arguments (loc, fundecl, fntype,
-                                           nargs, argarray);
+                                           nargs, argarray, &arg_loc);
 
   if (name != NULL_TREE
       && !strncmp (IDENTIFIER_POINTER (name), "__builtin_", 10))
index ba9583aa3b31b8b4e53c694869ac4207067c2d56..2640f84558725de1251c2c6564fb09cc5f7730b7 100644 (file)
@@ -1,3 +1,9 @@
+2017-08-21  David Malcolm  <dmalcolm@redhat.com>
+
+       * call.c (build_over_call): Pass NULL for new parameter to
+       check_function_arguments.
+       * typeck.c (cp_build_function_call_vec): Likewise.
+
 2017-08-21  Nathan Sidwell  <nathan@acm.org>
 
        PR c++/81899
index 37902991f3f8620c2ab8833c4cbeb6ffcae7468e..067db59ae2ccedd46d8970f9423c17bc05e0f7d2 100644 (file)
@@ -7949,7 +7949,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
        fargs[j] = maybe_constant_value (argarray[j]);
 
       warned_p = check_function_arguments (input_location, fn, TREE_TYPE (fn),
-                                          nargs, fargs);
+                                          nargs, fargs, NULL);
     }
 
   if (DECL_INHERITED_CTOR (fn))
index a5a363bc9424c13281e97449633fca0ae2429413..63667f34e6af7ffeb9f890aa24c6745649eae3fc 100644 (file)
@@ -3699,7 +3699,7 @@ cp_build_function_call_vec (tree function, vec<tree, va_gc> **params,
   /* Check for errors in format strings and inappropriately
      null parameters.  */
   bool warned_p = check_function_arguments (input_location, fndecl, fntype,
-                                           nargs, argarray);
+                                           nargs, argarray, NULL);
 
   ret = build_cxx_call (function, nargs, argarray, complain);
 
index 006f115c508e8ae5af8533bc2afd6de78f2663cf..8f1eab8cfa35d8b451a71870277565c485a6f342 100644 (file)
@@ -1,3 +1,9 @@
+2017-08-21  David Malcolm  <dmalcolm@redhat.com>
+
+       * gcc.dg/format/diagnostic-ranges.c: Update expected results
+       to show underlining of all pertinent params.
+       * gcc.dg/format/pr72858.c: Likewise.
+
 2017-08-21  Uros Bizjak  <ubizjak@gmail.com>
 
        PR target/46091
index 8cce5b38c9f56d2b8b01ffdf51d421bca2732bac..bc6f665600d5c28fb740f134d10b2fed74daf5de 100644 (file)
@@ -8,28 +8,24 @@ void test_mismatching_types (const char *msg)
 {
   printf("hello %i", msg);  /* { dg-warning "format '%i' expects argument of type 'int', but argument 2 has type 'const char \\*' " } */
 
-/* TODO: ideally would also underline "msg".  */
 /* { dg-begin-multiline-output "" }
    printf("hello %i", msg);
-                 ~^
+                 ~^   ~~~
                  %s
    { dg-end-multiline-output "" } */
 
 
   printf("hello %s", 42);  /* { dg-warning "format '%s' expects argument of type 'char \\*', but argument 2 has type 'int'" } */
-/* TODO: ideally would also underline "42".  */
 /* { dg-begin-multiline-output "" }
    printf("hello %s", 42);
-                 ~^
+                 ~^   ~~
                  %d
    { dg-end-multiline-output "" } */
 
-
   printf("hello %i", (long)0);  /* { dg-warning "format '%i' expects argument of type 'int', but argument 2 has type 'long int' " } */
-/* TODO: ideally would also underline the argument.  */
 /* { dg-begin-multiline-output "" }
    printf("hello %i", (long)0);
-                 ~^
+                 ~^   ~
                  %li
    { dg-end-multiline-output "" } */
 }
@@ -38,11 +34,12 @@ void test_multiple_arguments (void)
 {
   printf ("arg0: %i  arg1: %s arg 2: %i", /* { dg-warning "29: format '%s'" } */
           100, 101, 102);
-/* TODO: ideally would also underline "101".  */
 /* { dg-begin-multiline-output "" }
    printf ("arg0: %i  arg1: %s arg 2: %i",
                             ~^
                             %d
+           100, 101, 102);
+                ~~~           
    { dg-end-multiline-output "" } */
 }
 
@@ -84,10 +81,9 @@ void test_hex (const char *msg)
      "i" is \x69 */
   printf("hello \x25\x69", msg);  /* { dg-warning "format '%i' expects argument of type 'int', but argument 2 has type 'const char \\*' " } */
 
-/* TODO: ideally would also underline "msg".  */
 /* { dg-begin-multiline-output "" }
    printf("hello \x25\x69", msg);
-                 ~~~~^~~~
+                 ~~~~^~~~   ~~~
                  \x25s
    { dg-end-multiline-output "" } */
 }
@@ -98,10 +94,9 @@ void test_oct (const char *msg)
      "i" is octal 151.  */
   printf("hello \045\151", msg);  /* { dg-warning "format '%i' expects argument of type 'int', but argument 2 has type 'const char \\*' " } */
 
-/* TODO: ideally would also underline "msg".  */
 /* { dg-begin-multiline-output "" }
    printf("hello \045\151", msg);
-                 ~~~~^~~~
+                 ~~~~^~~~   ~~~
                  \045s
    { dg-end-multiline-output "" } */
 }
@@ -115,9 +110,10 @@ void test_multiple (const char *msg)
 /* { dg-begin-multiline-output "" }
    printf("prefix"  "\x25"  "\151"  "suffix",
           ^~~~~~~~
+          msg);
+          ~~~
   { dg-end-multiline-output "" } */
 
-/* TODO: ideally would also underline "msg".  */
 /* { dg-begin-multiline-output "" }
    printf("prefix"  "\x25"  "\151"  "suffix",
                      ~~~~~~~~^~~~
@@ -128,10 +124,9 @@ void test_multiple (const char *msg)
 void test_u8 (const char *msg)
 {
   printf(u8"hello %i", msg);/* { dg-warning "format '%i' expects argument of type 'int', but argument 2 has type 'const char \\*' " } */
-/* TODO: ideally would also underline "msg".  */
 /* { dg-begin-multiline-output "" }
    printf(u8"hello %i", msg);
-                   ~^
+                   ~^   ~~~
                    %s
    { dg-end-multiline-output "" } */
 }
@@ -151,7 +146,7 @@ void test_field_width_specifier (long l, int i1, int i2)
   printf (" %*.*d ", l, i1, i2); /* { dg-warning "14: field width specifier '\\*' expects argument of type 'int', but argument 2 has type 'long int'" } */
 /* { dg-begin-multiline-output "" }
    printf (" %*.*d ", l, i1, i2);
-             ~^~~~
+             ~^~~~    ~
    { dg-end-multiline-output "" } */
 }
 
@@ -160,10 +155,9 @@ void test_field_width_specifier (long l, int i1, int i2)
 void test_field_width_specifier_2 (char *d, long foo, long bar)
 {
   __builtin_sprintf (d, " %*ld ", foo, foo); /* { dg-warning "28: field width specifier '\\*' expects argument of type 'int', but argument 3 has type 'long int'" } */
-  /* TODO: ideally we'd underline the first "foo" here".  */
   /* { dg-begin-multiline-output "" }
    __builtin_sprintf (d, " %*ld ", foo, foo);
-                           ~^~~
+                           ~^~~    ~~~
    { dg-end-multiline-output "" } */
 
   __builtin_sprintf (d, " %*ld ", foo + bar, foo); /* { dg-warning "28: field width specifier '\\*' expects argument of type 'int', but argument 3 has type 'long int'" } */
@@ -176,10 +170,9 @@ void test_field_width_specifier_2 (char *d, long foo, long bar)
 void test_field_precision_specifier (char *d, long foo, long bar)
 {
   __builtin_sprintf (d, " %.*ld ", foo, foo); /* { dg-warning "29: field precision specifier '\\.\\*' expects argument of type 'int', but argument 3 has type 'long int'" } */
-  /* TODO: ideally we'd underline the first "foo" here".  */
   /* { dg-begin-multiline-output "" }
    __builtin_sprintf (d, " %.*ld ", foo, foo);
-                           ~~^~~
+                           ~~^~~    ~~~
    { dg-end-multiline-output "" } */
 
   __builtin_sprintf (d, " %.*ld ", foo + bar, foo); /* { dg-warning "29: field precision specifier '\\.\\*' expects argument of type 'int', but argument 3 has type 'long int'" } */
@@ -247,7 +240,7 @@ void test_macro (const char *msg)
   printf("hello " INT_FMT " world", msg);  /* { dg-warning "10: format '%i' expects argument of type 'int', but argument 2 has type 'const char \\*' " } */
 /* { dg-begin-multiline-output "" }
    printf("hello " INT_FMT " world", msg);
-          ^~~~~~~~
+          ^~~~~~~~                   ~~~
    { dg-end-multiline-output "" } */
 /* { dg-begin-multiline-output "" }
  #define INT_FMT "%i"
@@ -263,7 +256,7 @@ void test_macro_2 (const char *msg)
   printf("hello %" PRIu32 " world", msg);  /* { dg-warning "10: format '%u' expects argument of type 'unsigned int', but argument 2 has type 'const char \\*' " } */
 /* { dg-begin-multiline-output "" }
    printf("hello %" PRIu32 " world", msg);
-          ^~~~~~~~~
+          ^~~~~~~~~                  ~~~
    { dg-end-multiline-output "" } */
 /* { dg-begin-multiline-output "" }
  #define PRIu32 "u"
@@ -313,7 +306,7 @@ void test_non_contiguous_strings (void)
                                     /* { dg-message "26: format string is defined here" "" { target *-*-* } .-1 } */
   /* { dg-begin-multiline-output "" }
    __builtin_printf(" %" "d ", 0.5);
-                    ^~~~
+                    ^~~~       ~~~
    { dg-end-multiline-output "" } */
   /* { dg-begin-multiline-output "" }
    __builtin_printf(" %" "d ", 0.5);
@@ -330,6 +323,6 @@ void test_const_arrays (void)
   __builtin_printf(a, 0.5); /* { dg-warning "20: format .%d. expects argument of type .int., but argument 2 has type .double." } */
   /* { dg-begin-multiline-output "" }
    __builtin_printf(a, 0.5);
-                    ^
+                    ^  ~~~
    { dg-end-multiline-output "" } */
 }
index c142d243ddbbbfe9b87eb75cdd88235b4ddacc11..b8c5829ed23fcdd08c9654567aa6c82b03f73aa6 100644 (file)
@@ -25,56 +25,49 @@ test_x (char *d,
   sprintf (d, " %-8x ", uiexpr);
 
   sprintf (d, " %-8x ", lexpr); /* { dg-warning "20: format '%x' expects argument of type 'unsigned int', but argument 3 has type 'long int'" } */
-/* TODO: ideally would also underline "lexpr".  */
 /* { dg-begin-multiline-output "" }
    sprintf (d, " %-8x ", lexpr);
-                 ~~~^
+                 ~~~^    ~~~~~
                  %-8lx
    { dg-end-multiline-output "" } */
   sprintf (d, " %-8x ", ulexpr); /* { dg-warning "20: format '%x' expects argument of type 'unsigned int', but argument 3 has type 'long unsigned int'" } */
-/* TODO: ideally would also underline "lexpr".  */
 /* { dg-begin-multiline-output "" }
    sprintf (d, " %-8x ", ulexpr);
-                 ~~~^
+                 ~~~^    ~~~~~~
                  %-8lx
    { dg-end-multiline-output "" } */
 
   sprintf (d, " %-8x ", llexpr); /* { dg-warning "20: format '%x' expects argument of type 'unsigned int', but argument 3 has type 'long long int'" } */
-/* TODO: ideally would also underline "lexpr".  */
 /* { dg-begin-multiline-output "" }
    sprintf (d, " %-8x ", llexpr);
-                 ~~~^
+                 ~~~^    ~~~~~~
                  %-8llx
    { dg-end-multiline-output "" } */
   sprintf (d, " %-8x ", ullexpr); /* { dg-warning "20: format '%x' expects argument of type 'unsigned int', but argument 3 has type 'long long unsigned int'" } */
-/* TODO: ideally would also underline "lexpr".  */
 /* { dg-begin-multiline-output "" }
    sprintf (d, " %-8x ", ullexpr);
-                 ~~~^
+                 ~~~^    ~~~~~~~
                  %-8llx
    { dg-end-multiline-output "" } */
 
   /* Floating-point arguments.  */
 
   sprintf (d, " %-8x ", fexpr); /* { dg-warning "20: format '%x' expects argument of type 'unsigned int', but argument 3 has type 'double'" } */
-/* TODO: ideally would also underline "fexpr".  */
 /* { dg-begin-multiline-output "" }
    sprintf (d, " %-8x ", fexpr);
-                 ~~~^
+                 ~~~^    ~~~~~
                  %-8f
    { dg-end-multiline-output "" } */
   sprintf (d, " %-8x ", dexpr); /* { dg-warning "20: format '%x' expects argument of type 'unsigned int', but argument 3 has type 'double'" } */
-/* TODO: ideally would also underline "dexpr".  */
 /* { dg-begin-multiline-output "" }
    sprintf (d, " %-8x ", dexpr);
-                 ~~~^
+                 ~~~^    ~~~~~
                  %-8f
    { dg-end-multiline-output "" } */
   sprintf (d, " %-8x ", ldexpr); /* { dg-warning "20: format '%x' expects argument of type 'unsigned int', but argument 3 has type 'long double'" } */
-/* TODO: ideally would also underline "ldexpr".  */
 /* { dg-begin-multiline-output "" }
    sprintf (d, " %-8x ", ldexpr);
-                 ~~~^
+                 ~~~^    ~~~~~~
                  %-8Lf
    { dg-end-multiline-output "" } */
 
@@ -82,7 +75,7 @@ test_x (char *d,
   sprintf (d, " %-8x ", ptr); /* { dg-warning "20: format '%x' expects argument of type 'unsigned int', but argument 3 has type 'void \\*'" } */
 /* { dg-begin-multiline-output "" }
    sprintf (d, " %-8x ", ptr);
-                 ~~~^
+                 ~~~^    ~~~
                  %-8p
    { dg-end-multiline-output "" } */
 
@@ -92,7 +85,7 @@ test_x (char *d,
   sprintf (d, " %-8x ", s); /* { dg-warning "20: format '%x' expects argument of type 'unsigned int', but argument 3 has type 'struct s'" } */
 /* { dg-begin-multiline-output "" }
    sprintf (d, " %-8x ", s);
-                 ~~~^
+                 ~~~^    ~
    { dg-end-multiline-output "" } */
 }
 
@@ -109,17 +102,15 @@ test_lx (char *d,
   /* Integer arguments.  */
 
   sprintf (d, " %-8lx ", iexpr); /* { dg-warning "21: format '%lx' expects argument of type 'long unsigned int', but argument 3 has type 'int'" } */
-/* TODO: ideally would also underline "iexpr".  */
 /* { dg-begin-multiline-output "" }
    sprintf (d, " %-8lx ", iexpr);
-                 ~~~~^
+                 ~~~~^    ~~~~~
                  %-8x
    { dg-end-multiline-output "" } */
   sprintf (d, " %-8lx ", uiexpr); /* { dg-warning "21: format '%lx' expects argument of type 'long unsigned int', but argument 3 has type 'unsigned int'" } */
-/* TODO: ideally would also underline "uiexpr".  */
 /* { dg-begin-multiline-output "" }
    sprintf (d, " %-8lx ", uiexpr);
-                 ~~~~^
+                 ~~~~^    ~~~~~~
                  %-8x
    { dg-end-multiline-output "" } */
 
@@ -127,41 +118,36 @@ test_lx (char *d,
   sprintf (d, " %-8lx ", ulexpr);
 
   sprintf (d, " %-8lx ", llexpr); /* { dg-warning "21: format '%lx' expects argument of type 'long unsigned int', but argument 3 has type 'long long int'" } */
-/* TODO: ideally would also underline "llexpr".  */
 /* { dg-begin-multiline-output "" }
    sprintf (d, " %-8lx ", llexpr);
-                 ~~~~^
+                 ~~~~^    ~~~~~~
                  %-8llx
    { dg-end-multiline-output "" } */
   sprintf (d, " %-8lx ", ullexpr); /* { dg-warning "21: format '%lx' expects argument of type 'long unsigned int', but argument 3 has type 'long long unsigned int'" } */
-/* TODO: ideally would also underline "ullexpr".  */
 /* { dg-begin-multiline-output "" }
    sprintf (d, " %-8lx ", ullexpr);
-                 ~~~~^
+                 ~~~~^    ~~~~~~~
                  %-8llx
    { dg-end-multiline-output "" } */
 
   /* Floating-point arguments.  */
 
   sprintf (d, " %-8lx ", fexpr); /* { dg-warning "21: format '%lx' expects argument of type 'long unsigned int', but argument 3 has type 'double'" } */
-/* TODO: ideally would also underline "fexpr".  */
 /* { dg-begin-multiline-output "" }
    sprintf (d, " %-8lx ", fexpr);
-                 ~~~~^
+                 ~~~~^    ~~~~~
                  %-8f
    { dg-end-multiline-output "" } */
   sprintf (d, " %-8lx ", dexpr); /* { dg-warning "21: format '%lx' expects argument of type 'long unsigned int', but argument 3 has type 'double'" } */
-/* TODO: ideally would also underline "dexpr".  */
 /* { dg-begin-multiline-output "" }
    sprintf (d, " %-8lx ", dexpr);
-                 ~~~~^
+                 ~~~~^    ~~~~~
                  %-8f
    { dg-end-multiline-output "" } */
   sprintf (d, " %-8lx ", ldexpr); /* { dg-warning "21: format '%lx' expects argument of type 'long unsigned int', but argument 3 has type 'long double'" } */
-/* TODO: ideally would also underline "ldexpr".  */
 /* { dg-begin-multiline-output "" }
    sprintf (d, " %-8lx ", ldexpr);
-                 ~~~~^
+                 ~~~~^    ~~~~~~
                  %-8Lf
    { dg-end-multiline-output "" } */
 }
@@ -181,32 +167,28 @@ test_o (char *d,
   sprintf (d, " %-8o ", uiexpr);
 
   sprintf (d, " %-8o ", lexpr); /* { dg-warning "20: format '%o' expects argument of type 'unsigned int', but argument 3 has type 'long int'" } */
-/* TODO: ideally would also underline "lexpr".  */
 /* { dg-begin-multiline-output "" }
    sprintf (d, " %-8o ", lexpr);
-                 ~~~^
+                 ~~~^    ~~~~~
                  %-8lo
    { dg-end-multiline-output "" } */
   sprintf (d, " %-8o ", ulexpr); /* { dg-warning "20: format '%o' expects argument of type 'unsigned int', but argument 3 has type 'long unsigned int'" } */
-/* TODO: ideally would also underline "lexpr".  */
 /* { dg-begin-multiline-output "" }
    sprintf (d, " %-8o ", ulexpr);
-                 ~~~^
+                 ~~~^    ~~~~~~
                  %-8lo
    { dg-end-multiline-output "" } */
 
   sprintf (d, " %-8o ", llexpr); /* { dg-warning "20: format '%o' expects argument of type 'unsigned int', but argument 3 has type 'long long int'" } */
-/* TODO: ideally would also underline "lexpr".  */
 /* { dg-begin-multiline-output "" }
    sprintf (d, " %-8o ", llexpr);
-                 ~~~^
+                 ~~~^    ~~~~~~
                  %-8llo
    { dg-end-multiline-output "" } */
   sprintf (d, " %-8o ", ullexpr); /* { dg-warning "20: format '%o' expects argument of type 'unsigned int', but argument 3 has type 'long long unsigned int'" } */
-/* TODO: ideally would also underline "lexpr".  */
 /* { dg-begin-multiline-output "" }
    sprintf (d, " %-8o ", ullexpr);
-                 ~~~^
+                 ~~~^    ~~~~~~~
                  %-8llo
    { dg-end-multiline-output "" } */
 }
@@ -223,17 +205,15 @@ test_lo (char *d,
   /* Integer arguments.  */
 
   sprintf (d, " %-8lo ", iexpr); /* { dg-warning "21: format '%lo' expects argument of type 'long unsigned int', but argument 3 has type 'int'" } */
-/* TODO: ideally would also underline "iexpr".  */
 /* { dg-begin-multiline-output "" }
    sprintf (d, " %-8lo ", iexpr);
-                 ~~~~^
+                 ~~~~^    ~~~~~
                  %-8o
    { dg-end-multiline-output "" } */
   sprintf (d, " %-8lo ", uiexpr); /* { dg-warning "21: format '%lo' expects argument of type 'long unsigned int', but argument 3 has type 'unsigned int'" } */
-/* TODO: ideally would also underline "uiexpr".  */
 /* { dg-begin-multiline-output "" }
    sprintf (d, " %-8lo ", uiexpr);
-                 ~~~~^
+                 ~~~~^    ~~~~~~
                  %-8o
    { dg-end-multiline-output "" } */
 
@@ -241,17 +221,15 @@ test_lo (char *d,
   sprintf (d, " %-8lo ", ulexpr);
 
   sprintf (d, " %-8lo ", llexpr); /* { dg-warning "21: format '%lo' expects argument of type 'long unsigned int', but argument 3 has type 'long long int'" } */
-/* TODO: ideally would also underline "llexpr".  */
 /* { dg-begin-multiline-output "" }
    sprintf (d, " %-8lo ", llexpr);
-                 ~~~~^
+                 ~~~~^    ~~~~~~
                  %-8llo
    { dg-end-multiline-output "" } */
   sprintf (d, " %-8lo ", ullexpr); /* { dg-warning "21: format '%lo' expects argument of type 'long unsigned int', but argument 3 has type 'long long unsigned int'" } */
-/* TODO: ideally would also underline "ullexpr".  */
 /* { dg-begin-multiline-output "" }
    sprintf (d, " %-8lo ", ullexpr);
-                 ~~~~^
+                 ~~~~^    ~~~~~~~
                  %-8llo
    { dg-end-multiline-output "" } */
 }
@@ -265,10 +243,9 @@ test_e (char *d, int iexpr, float fexpr, double dexpr, long double ldexpr)
   /* Integer arguments.  */
 
   sprintf (d, " %-8e ", iexpr); /* { dg-warning "20: format '%e' expects argument of type 'double', but argument 3 has type 'int'" } */
-/* TODO: ideally would also underline "iexpr".  */
 /* { dg-begin-multiline-output "" }
    sprintf (d, " %-8e ", iexpr);
-                 ~~~^
+                 ~~~^    ~~~~~
                  %-8d
    { dg-end-multiline-output "" } */
 
@@ -277,10 +254,9 @@ test_e (char *d, int iexpr, float fexpr, double dexpr, long double ldexpr)
   sprintf (d, " %-8e ", fexpr);
   sprintf (d, " %-8e ", dexpr);
   sprintf (d, " %-8e ", ldexpr); /* { dg-warning "20: format '%e' expects argument of type 'double', but argument 3 has type 'long double'" } */
-/* TODO: ideally would also underline "ldexpr".  */
 /* { dg-begin-multiline-output "" }
    sprintf (d, " %-8e ", ldexpr);
-                 ~~~^
+                 ~~~^    ~~~~~~
                  %-8Le
    { dg-end-multiline-output "" } */
 }
@@ -294,10 +270,9 @@ test_Le (char *d, int iexpr, float fexpr, double dexpr, long double ldexpr)
   /* Integer arguments.  */
 
   sprintf (d, " %-8Le ", iexpr); /* { dg-warning "21: format '%Le' expects argument of type 'long double', but argument 3 has type 'int'" } */
-/* TODO: ideally would also underline "iexpr".  */
 /* { dg-begin-multiline-output "" }
    sprintf (d, " %-8Le ", iexpr);
-                 ~~~~^
+                 ~~~~^    ~~~~~
                  %-8d
    { dg-end-multiline-output "" } */
 
@@ -306,14 +281,14 @@ test_Le (char *d, int iexpr, float fexpr, double dexpr, long double ldexpr)
   sprintf (d, " %-8Le ", fexpr); /* { dg-warning "21: format '%Le' expects argument of type 'long double', but argument 3 has type 'double'" } */
 /* { dg-begin-multiline-output "" }
    sprintf (d, " %-8Le ", fexpr);
-                 ~~~~^
+                 ~~~~^    ~~~~~
                  %-8e
    { dg-end-multiline-output "" } */
 
   sprintf (d, " %-8Le ", dexpr); /* { dg-warning "21: format '%Le' expects argument of type 'long double', but argument 3 has type 'double'" } */
 /* { dg-begin-multiline-output "" }
    sprintf (d, " %-8Le ", dexpr);
-                 ~~~~^
+                 ~~~~^    ~~~~~
                  %-8e
    { dg-end-multiline-output "" } */
 
@@ -329,10 +304,9 @@ test_E (char *d, int iexpr, float fexpr, double dexpr, long double ldexpr)
   /* Integer arguments.  */
 
   sprintf (d, " %-8E ", iexpr); /* { dg-warning "20: format '%E' expects argument of type 'double', but argument 3 has type 'int'" } */
-/* TODO: ideally would also underline "iexpr".  */
 /* { dg-begin-multiline-output "" }
    sprintf (d, " %-8E ", iexpr);
-                 ~~~^
+                 ~~~^    ~~~~~
                  %-8d
    { dg-end-multiline-output "" } */
 
@@ -341,10 +315,9 @@ test_E (char *d, int iexpr, float fexpr, double dexpr, long double ldexpr)
   sprintf (d, " %-8E ", fexpr);
   sprintf (d, " %-8E ", dexpr);
   sprintf (d, " %-8E ", ldexpr); /* { dg-warning "20: format '%E' expects argument of type 'double', but argument 3 has type 'long double'" } */
-/* TODO: ideally would also underline "ldexpr".  */
 /* { dg-begin-multiline-output "" }
    sprintf (d, " %-8E ", ldexpr);
-                 ~~~^
+                 ~~~^    ~~~~~~
                  %-8LE
    { dg-end-multiline-output "" } */
 }
@@ -358,24 +331,23 @@ test_LE (char *d, int iexpr, float fexpr, double dexpr, long double ldexpr)
   /* Integer arguments.  */
 
   sprintf (d, " %-8LE ", iexpr); /* { dg-warning "21: format '%LE' expects argument of type 'long double', but argument 3 has type 'int'" } */
-/* TODO: ideally would also underline "iexpr".  */
 /* { dg-begin-multiline-output "" }
    sprintf (d, " %-8LE ", iexpr);
-                 ~~~~^
+                 ~~~~^    ~~~~~
                  %-8d
    { dg-end-multiline-output "" } */
 
   sprintf (d, " %-8LE ", fexpr); /* { dg-warning "21: format '%LE' expects argument of type 'long double', but argument 3 has type 'double'" } */
 /* { dg-begin-multiline-output "" }
    sprintf (d, " %-8LE ", fexpr);
-                 ~~~~^
+                 ~~~~^    ~~~~~
                  %-8E
    { dg-end-multiline-output "" } */
 
   sprintf (d, " %-8LE ", dexpr); /* { dg-warning "21: format '%LE' expects argument of type 'long double', but argument 3 has type 'double'" } */
 /* { dg-begin-multiline-output "" }
    sprintf (d, " %-8LE ", dexpr);
-                 ~~~~^
+                 ~~~~^    ~~~~~
                  %-8E
    { dg-end-multiline-output "" } */
 
@@ -394,19 +366,19 @@ test_everything (char *d, long lexpr)
   /* { dg-warning "26: field width specifier '\\*' expects argument of type 'int', but argument 3 has type 'long int'" "" { target *-*-* } test_everything_sprintf } */
   /* { dg-begin-multiline-output "" }
    sprintf (d, "before %-+*.*lld after", lexpr, lexpr, lexpr);
-                       ~~~^~~~~~
+                       ~~~^~~~~~         ~~~~~
    { dg-end-multiline-output "" } */
 
   /* { dg-warning "28: field precision specifier '\\.\\*' expects argument of type 'int', but argument 4 has type 'long int'" "" { target *-*-* } test_everything_sprintf } */
   /* { dg-begin-multiline-output "" }
    sprintf (d, "before %-+*.*lld after", lexpr, lexpr, lexpr);
-                       ~~~~~^~~~
+                       ~~~~~^~~~                ~~~~~
    { dg-end-multiline-output "" } */
 
   /* { dg-warning "31: format '%lld' expects argument of type 'long long int', but argument 5 has type 'long int'" "" { target *-*-* } test_everything_sprintf } */
   /* { dg-begin-multiline-output "" }
    sprintf (d, "before %-+*.*lld after", lexpr, lexpr, lexpr);
-                       ~~~~~~~~^
+                       ~~~~~~~~^                       ~~~~~
                        %-+*.*ld
    { dg-end-multiline-output "" } */
 }