C++: underline parameters in mismatching function calls
authorDavid Malcolm <dmalcolm@redhat.com>
Fri, 22 Sep 2017 14:49:52 +0000 (14:49 +0000)
committerDavid Malcolm <dmalcolm@gcc.gnu.org>
Fri, 22 Sep 2017 14:49:52 +0000 (14:49 +0000)
gcc/cp/ChangeLog:
* call.c (get_fndecl_argument_location): New function.
(convert_like_real): Use it  when complaining about argument type
mismatches.
* cp-tree.h (struct cp_parameter_declarator): Add "loc" field.
* parser.c (make_parameter_declarator): Add "loc" param and use
it to initialize the new field.
(cp_parser_translation_unit): Add UNKNOWN_LOCATION for "loc" of
the "no_parameters" parameter.
(cp_parser_parameter_declaration_list): Set the location of the
result of grokdeclarator to be the parameter's loc, assuming no
errors.
(cp_parser_parameter_declaration): Generate a location for the
parameter and pass to make_parameter_declarator.

gcc/testsuite/ChangeLog:
* g++.dg/diagnostic/param-type-mismatch.C: Update expected results
to reflect highlighting of parameters; add test coverage for
callback parameters.

From-SVN: r253096

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/cp-tree.h
gcc/cp/parser.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/diagnostic/param-type-mismatch.C

index b8d3f04..7705321 100644 (file)
@@ -1,3 +1,19 @@
+2017-09-22  David Malcolm  <dmalcolm@redhat.com>
+
+       * call.c (get_fndecl_argument_location): New function.
+       (convert_like_real): Use it  when complaining about argument type
+       mismatches.
+       * cp-tree.h (struct cp_parameter_declarator): Add "loc" field.
+       * parser.c (make_parameter_declarator): Add "loc" param and use
+       it to initialize the new field.
+       (cp_parser_translation_unit): Add UNKNOWN_LOCATION for "loc" of
+       the "no_parameters" parameter.
+       (cp_parser_parameter_declaration_list): Set the location of the
+       result of grokdeclarator to be the parameter's loc, assuming no
+       errors.
+       (cp_parser_parameter_declaration): Generate a location for the
+       parameter and pass to make_parameter_declarator.
+
 2017-09-20  Nathan Sidwell  <nathan@acm.org>
 
        * name-lookup.c (member_name_cmp): Use DECL_UID for final
index 4fa0d03..e83cf99 100644 (file)
@@ -6579,6 +6579,30 @@ maybe_print_user_conv_context (conversion *convs)
        }
 }
 
+/* Locate the parameter with the given index within FNDECL.
+   ARGNUM is zero based, -1 indicates the `this' argument of a method.
+   Return the location of the FNDECL itself if there are problems.  */
+
+static location_t
+get_fndecl_argument_location (tree fndecl, int argnum)
+{
+  int i;
+  tree param;
+
+  /* Locate param by index within DECL_ARGUMENTS (fndecl).  */
+  for (i = 0, param = FUNCTION_FIRST_USER_PARM (fndecl);
+       i < argnum && param;
+       i++, param = TREE_CHAIN (param))
+    ;
+
+  /* If something went wrong (e.g. if we have a builtin and thus no arguments),
+     return the location of FNDECL.  */
+  if (param == NULL)
+    return DECL_SOURCE_LOCATION (fndecl);
+
+  return DECL_SOURCE_LOCATION (param);
+}
+
 /* Perform the conversions in CONVS on the expression EXPR.  FN and
    ARGNUM are used for diagnostics.  ARGNUM is zero based, -1
    indicates the `this' argument of a method.  INNER is nonzero when
@@ -6680,7 +6704,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
        complained = permerror (loc, "invalid conversion from %qH to %qI",
                                TREE_TYPE (expr), totype);
       if (complained && fn)
-       inform (DECL_SOURCE_LOCATION (fn),
+       inform (get_fndecl_argument_location (fn, argnum),
                "  initializing argument %P of %qD", argnum, fn);
 
       return cp_convert (totype, expr, complain);
index e508598..7c1c54c 100644 (file)
@@ -5659,6 +5659,8 @@ struct cp_parameter_declarator {
   tree default_argument;
   /* True iff this is a template parameter pack.  */
   bool template_parameter_pack_p;
+  /* Location within source.  */
+  location_t loc;
 };
 
 /* A declarator.  */
index 25b91df..f9b6f27 100644 (file)
@@ -1691,6 +1691,7 @@ cp_parameter_declarator *
 make_parameter_declarator (cp_decl_specifier_seq *decl_specifiers,
                           cp_declarator *declarator,
                           tree default_argument,
+                          location_t loc,
                           bool template_parameter_pack_p = false)
 {
   cp_parameter_declarator *parameter;
@@ -1705,6 +1706,7 @@ make_parameter_declarator (cp_decl_specifier_seq *decl_specifiers,
   parameter->declarator = declarator;
   parameter->default_argument = default_argument;
   parameter->template_parameter_pack_p = template_parameter_pack_p;
+  parameter->loc = loc;
 
   return parameter;
 }
@@ -4379,7 +4381,8 @@ cp_parser_translation_unit (cp_parser* parser)
       /* Create the error declarator.  */
       cp_error_declarator = make_declarator (cdk_error);
       /* Create the empty parameter list.  */
-      no_parameters = make_parameter_declarator (NULL, NULL, NULL_TREE);
+      no_parameters = make_parameter_declarator (NULL, NULL, NULL_TREE,
+                                                UNKNOWN_LOCATION);
       /* Remember where the base of the declarator obstack lies.  */
       declarator_obstack_base = obstack_next_free (&declarator_obstack);
     }
@@ -21218,6 +21221,8 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
                                 PARM,
                                 parameter->default_argument != NULL_TREE,
                                 &parameter->decl_specifiers.attributes);
+         if (decl != error_mark_node && parameter->loc != UNKNOWN_LOCATION)
+           DECL_SOURCE_LOCATION (decl) = parameter->loc;
        }
 
       deprecated_state = DEPRECATED_NORMAL;
@@ -21371,6 +21376,7 @@ cp_parser_parameter_declaration (cp_parser *parser,
     = G_("types may not be defined in parameter types");
 
   /* Parse the declaration-specifiers.  */
+  cp_token *decl_spec_token_start = cp_lexer_peek_token (parser->lexer);
   cp_parser_decl_specifier_seq (parser,
                                CP_PARSER_FLAGS_NONE,
                                &decl_specifiers,
@@ -21555,9 +21561,33 @@ cp_parser_parameter_declaration (cp_parser *parser,
   else
     default_argument = NULL_TREE;
 
+  /* Generate a location for the parameter, ranging from the start of the
+     initial token to the end of the final token (using input_location for
+     the latter, set up by cp_lexer_set_source_position_from_token when
+     consuming tokens).
+
+     If we have a identifier, then use it for the caret location, e.g.
+
+       extern int callee (int one, int (*two)(int, int), float three);
+                                   ~~~~~~^~~~~~~~~~~~~~
+
+     otherwise, reuse the start location for the caret location e.g.:
+
+       extern int callee (int one, int (*)(int, int), float three);
+                                   ^~~~~~~~~~~~~~~~~
+
+  */
+  location_t caret_loc = (declarator && declarator->id_loc != UNKNOWN_LOCATION
+                         ? declarator->id_loc
+                         : decl_spec_token_start->location);
+  location_t param_loc = make_location (caret_loc,
+                                       decl_spec_token_start->location,
+                                       input_location);
+
   return make_parameter_declarator (&decl_specifiers,
                                    declarator,
                                    default_argument,
+                                   param_loc,
                                    template_parameter_pack_p);
 }
 
index 161c1bd..baccb95 100644 (file)
@@ -1,3 +1,9 @@
+2017-09-22  David Malcolm  <dmalcolm@redhat.com>
+
+       * g++.dg/diagnostic/param-type-mismatch.C: Update expected results
+       to reflect highlighting of parameters; add test coverage for
+       callback parameters.
+
 2017-09-22  Richard Biener  <rguenther@suse.de>
 
        * gcc.dg/graphite/scop-24.c: New testcase.
index b8833ef..bc3a938 100644 (file)
@@ -3,10 +3,7 @@
 /* A collection of calls where argument 2 is of the wrong type.
 
    TODO: we should put the caret and underline for the diagnostic
-   at the second argument, rather than the close paren.
-
-   TODO: we should highlight the second parameter of the callee, rather
-   than its name.  */
+   at the second argument, rather than the close paren.  */
 
 /* decl, with argname.  */
 
@@ -22,7 +19,7 @@ int test_1 (int first, int second, float third)
   // { dg-message "initializing argument 2 of 'int callee_1\\(int, const char\\*, float\\)'" "" { target *-*-* } callee_1 }
   /* { dg-begin-multiline-output "" }
  extern int callee_1 (int one, const char *two, float three);
-            ^~~~~~~~
+                               ~~~~~~~~~~~~^~~
      { dg-end-multiline-output "" } */
 }
 
@@ -40,7 +37,7 @@ int test_2 (int first, int second, float third)
   // { dg-message "initializing argument 2 of 'int callee_2\\(int, const char\\*, float\\)'" "" { target *-*-* } callee_2 }
   /* { dg-begin-multiline-output "" }
  extern int callee_2 (int, const char *, float);
-            ^~~~~~~~
+                           ^~~~~~~~~~~~
      { dg-end-multiline-output "" } */
 }
 
@@ -61,7 +58,7 @@ int test_3 (int first, int second, float third)
   // { dg-message "initializing argument 2 of 'int callee_3\\(int, const char\\*, float\\)'" "" { target *-*-* } callee_3 }
   /* { dg-begin-multiline-output "" }
  static int callee_3 (int one, const char *two, float three)
-            ^~~~~~~~
+                               ~~~~~~~~~~~~^~~
      { dg-end-multiline-output "" } */
 }
 
@@ -78,7 +75,7 @@ int test_4 (int first, int second, float third)
      { dg-end-multiline-output "" } */
   /* { dg-begin-multiline-output "" }
  struct s4 { static int member_1 (int one, const char *two, float three); };
-                        ^~~~~~~~
+                                           ~~~~~~~~~~~~^~~
      { dg-end-multiline-output "" } */
 }
 
@@ -96,7 +93,7 @@ int test_5 (int first, int second, float third)
      { dg-end-multiline-output "" } */
   /* { dg-begin-multiline-output "" }
  struct s5 { int member_1 (int one, const char *two, float three); };
-                 ^~~~~~~~
+                                    ~~~~~~~~~~~~^~~
      { dg-end-multiline-output "" } */
 }
 
@@ -113,7 +110,7 @@ int test_6 (int first, int second, float third, s6 *ptr)
      { dg-end-multiline-output "" } */
   /* { dg-begin-multiline-output "" }
  struct s6 { int member_1 (int one, const char *two, float three); };
-                 ^~~~~~~~
+                                    ~~~~~~~~~~~~^~~
      { dg-end-multiline-output "" } */
 }
 
@@ -153,7 +150,7 @@ int test_8 (int first, int second, float third)
      { dg-end-multiline-output "" } */
   /* { dg-begin-multiline-output "" }
  struct s8 { static int member_1 (int one, T two, float three); };
-                        ^~~~~~~~
+                                           ~~^~~
      { dg-end-multiline-output "" } */
 }
 
@@ -172,7 +169,43 @@ int test_9 (int first, int second, float third)
      { dg-end-multiline-output "" } */
   /* { dg-begin-multiline-output "" }
  struct s9 { int member_1 (int one, T two, float three); };
-                 ^~~~~~~~
+                                    ~~^~~
+     { dg-end-multiline-output "" } */
+}
+
+/* Callback with name.  */
+
+extern int callee_10 (int one, int (*two)(int, int), float three); // { dg-line callee_10 }
+
+int test_10 (int first, int second, float third)
+{
+  return callee_10 (first, second, third); // { dg-error "invalid conversion from 'int' to 'int \\(\\*\\)\\(int, int\\)'" }
+  /* { dg-begin-multiline-output "" }
+   return callee_10 (first, second, third);
+                                         ^
+     { dg-end-multiline-output "" } */
+  // { dg-message "initializing argument 2 of 'int callee_10\\(int, int \\(\\*\\)\\(int, int\\), float\\)'" "" { target *-*-* } callee_10 }
+  /* { dg-begin-multiline-output "" }
+ extern int callee_10 (int one, int (*two)(int, int), float three);
+                                ~~~~~~^~~~~~~~~~~~~~
+     { dg-end-multiline-output "" } */
+}
+
+/* Callback without name.  */
+
+extern int callee_11 (int one, int (*)(int, int), float three); // { dg-line callee_11 }
+
+int test_11 (int first, int second, float third)
+{
+  return callee_11 (first, second, third); // { dg-error "invalid conversion from 'int' to 'int \\(\\*\\)\\(int, int\\)'" }
+  /* { dg-begin-multiline-output "" }
+   return callee_11 (first, second, third);
+                                         ^
+     { dg-end-multiline-output "" } */
+  // { dg-message "initializing argument 2 of 'int callee_11\\(int, int \\(\\*\\)\\(int, int\\), float\\)'" "" { target *-*-* } callee_11 }
+  /* { dg-begin-multiline-output "" }
+ extern int callee_11 (int one, int (*)(int, int), float three);
+                                ^~~~~~~~~~~~~~~~~
      { dg-end-multiline-output "" } */
 }