diff mbox

C++: use an optional vec<location_t> for callsites

Message ID 1503519354-20921-1-git-send-email-dmalcolm@redhat.com
State New
Headers show

Commit Message

David Malcolm Aug. 23, 2017, 8:15 p.m. UTC
This patch extends various call-handling locations within the C++
frontend so that they can accept a possibly NULL vec<location_t> *,
using the location information if available in various diagnostics.

It updates the C++ frontend's parser for this production:

   postfix-expression:
     postfix-expression ( expression-list [opt] )

within cp_parser_postfix_expression so that it captures an
auto_vec<location_t> for the arguments (via
cp_parser_parenthesized_expression_list), and passes that around
within the parser, so that e.g.

  error: invalid conversion from 'int' to 'const char*' [-fpermissive]
     return callee_1 (first, second, third);
                                          ^

becomes:

  error: invalid conversion from 'int' to 'const char*' [-fpermissive]
     return callee_1 (first, second, third);
                             ^~~~~~

The vec<location_t> * are also passed to the arg-checking
code of r251238 ( https://gcc.gnu.org/ml/gcc-patches/2017-08/msg01164.html )
so that -Wformat can underline mismatching arguments for C++.

Doing this for C++ requires handling of the case where the vec<location_t>
from the expression-list needs to be offset by 1 relative to the args due
to the "this" parameter not being part of the expression-list, e.g. in:

  logger->log ("%i %s %i", 100, 101, 102);   [1]
                   ^~           ~~~

hence the patch adds a new "argument_locs" class to be responsible for
this in various places in c-family.

Successfully bootstrapped&regrtested on x86_64-pc-linux-gnu;
OK for trunk?

[1] We don't yet underline the "%s" in C++; I plan to fix that as a
separate patch.

gcc/c-family/ChangeLog:
	* c-common.c (argument_locs::get_param_location): New method.
	(check_function_arguments): Convert param "arglocs" from
	vec<location_t> * to argument_locs.
	* c-common.h (class argument_locs): New class.
	(check_function_arguments): Convert final param from
	vec<location_t> * to argument_locs.
	(check_function_format): Likewise.
	* c-format.c (struct format_check_results): Add ctor; convert
	field "arglocs" from vec<location_t> * to argument_locs.
	(check_function_format): Convert param "arglocs" from
	vec<location_t> * to argument_locs.
	(check_format_info): Likewise.  Use a ctor when initializing
	format_ctx.
	(check_format_arg): Convert local "arglocs" from vec<location_t> *
	to argument_locs.
	(class argument_parser): Likewise for field "arglocs".
	(argument_parser::argument_parser): Likewise.
	(check_format_info_main): Likewise for param "arglocs".
	(check_format_types): Likewise.  Replace logic for looking up
	locations within arglocs with a call to
	argument_locs::get_param_location.

gcc/c/ChangeLog:
	* c-typeck.c (build_function_call_vec): Update for conversion
	of final parameter of check_function_arguments.

gcc/cp/ChangeLog:
	* call.c (print_z_candidate): Add optional "arglocs" param and
	pass it to fn_type_unification.
	(print_z_candidates): Add optional "arglocs" param and pass it to
	print_z_candidate.
	(print_error_for_call_failure): Add optional "arglocs" param and
	pass it to print_z_candidates.
	(build_new_function_call): Add "arglocs" param and
	pass it to print_error_for_call_failure and build_over_call.
	(convert_like_real): Convert param "expr" from tree to cp_expr.
	(build_over_call): Add optional "arglocs" param.  Use it if
	available when calling convert_like_with_context, by converting
	"arg" to a cp_expr. Use arglocs when calling
	check_function_arguments, determining the appropriate offset to
	use based on whether there was a "first_arg".
	(build_new_method_call_1): Add "arglocs" param and pass it to
	build_over_call.
	(build_new_method_call): Add "arglocs" param and pass it to
	build_new_method_call_1.
	* cp-tree.h (build_new_function_call): Add optional
	vec<location_t> * param.
	(build_new_method_call): Likewise.
	(fn_type_unification): Likewise.
	(finish_call_expr): Likewise.
	(cp_build_function_call_vec): Likewise.
	* parser.c (cp_parser_postfix_expression): Within handling of
	"postfix-expression ( expression-list [opt] )" production, add
	auto_vec<location_t> and pass it to be built to
	cp_parser_parenthesized_expression_list; pass it for use to
	calls to build_new_method_call and finish_call_expr.
	(cp_parser_parenthesized_expression_list): Add optional "arglocs"
	param.  Convert local "expr" to cp_expr, using it to populate
	"arglocs" if non-NULL.
	* pt.c (unify_type_mismatch): Convert final param from tree to
	cp_expr to fix the location of the "inform".
	(unify_arg_conversion): Likewise.
	(fn_type_unification): Add "arglocs" param and pass it to
	type_unification_real.
	(check_non_deducible_conversion): Convert "arg" from tree to
	cp_expr.
	(type_unification_real): Add optional "arglocs" param.
	Convert local "arg" from tree to cp_expr, reading its location
	from arglocs, or, failing that, from input_location.
	* semantics.c (finish_call_expr): Add optional
	vec<location_t> * param and pass to calls to build_new_method_call
	and build_new_function_call.
	* typeck.c (cp_build_function_call_vec): Add optional
	vec<location_t> * param and pass to call to
	check_function_arguments.

gcc/testsuite/ChangeLog:
	* g++.dg/Wformat-on-method.C: New test case.
	* g++.dg/diagnostic/param-type-mismatch.C: Update expected results
	to reflect underlining of pertinent arguments.
---
 gcc/c-family/c-common.c                            | 27 +++++++-
 gcc/c-family/c-common.h                            | 39 ++++++++++-
 gcc/c-family/c-format.c                            | 53 ++++++++-------
 gcc/c/c-typeck.c                                   |  3 +-
 gcc/cp/call.c                                      | 77 ++++++++++++++--------
 gcc/cp/cp-tree.h                                   | 15 +++--
 gcc/cp/parser.c                                    | 30 ++++++---
 gcc/cp/pt.c                                        | 54 ++++++++++-----
 gcc/cp/semantics.c                                 |  9 +--
 gcc/cp/typeck.c                                    |  6 +-
 gcc/testsuite/g++.dg/Wformat-on-method.C           | 31 +++++++++
 .../g++.dg/diagnostic/param-type-mismatch.C        | 18 ++---
 12 files changed, 261 insertions(+), 101 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/Wformat-on-method.C
diff mbox

Patch

diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 156c89d..d238064 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -5534,12 +5534,35 @@  attribute_fallthrough_p (tree attr)
 }
 
 
+/* Lookup the location of the argument with 0-based index PARAM_IDX,
+   gracefully failing if data is unavailable, and handling
+   offsetting the index for the case where the "this"
+   wasn't in the expression-list.  */
+
+location_t
+argument_locs::get_param_location (unsigned int param_idx) const
+{
+  if (m_locs == NULL)
+    return UNKNOWN_LOCATION;
+
+  if (param_idx < m_offset)
+    return UNKNOWN_LOCATION;
+
+  param_idx -= m_offset;
+
+  gcc_assert (param_idx < m_locs->length ());
+
+  return (*m_locs)[param_idx];
+}
+
 /* Check for valid arguments being passed to a function with FNTYPE.
    There are NARGS arguments in the array ARGARRAY.  LOC should be used for
-   diagnostics.  Return true if -Wnonnull warning has been diagnosed.  */
+   diagnostics.  Return true if -Wnonnull warning has been diagnosed.
+   ARGLOCS gives the locations of the arguments
+   (if its "locs" is non-NULL).  */
 bool
 check_function_arguments (location_t loc, const_tree fndecl, const_tree fntype,
-			  int nargs, tree *argarray, vec<location_t> *arglocs)
+			  int nargs, tree *argarray, argument_locs arglocs)
 {
   bool warned_p = false;
 
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 8e36768..7a0a5a0 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -807,8 +807,43 @@  extern const char *fname_as_string (int);
 extern tree fname_decl (location_t, unsigned, tree);
 
 extern int check_user_alignment (const_tree, bool);
+
+/* Information about the locations of arguments at a callsite,
+   based on parsing an expression-list.
+
+   A bundle of a (possibly NULL) vec<location_t> *, together with
+   an offset for determining how this vec corresponds to the
+   arguments at a callsite.
+
+   We either have an offset of 0:
+     | argarray[0] | argarray[1] | argarray[2] | ...
+     | m_locs  [0] | m_locs  [1] | m_locs  [2] | ...
+
+   or an offset of 1:
+     | argarray[0] | argarray[1] | argarray[2] | argarray[3]
+     | "this"      | m_locs  [0] | m_locs  [1] | m_locs[2]
+
+   for the C++ cases where the expression-list didn't contain "this",
+   such as in "ptr->call (expr0, expr1, expr2)".  */
+
+class argument_locs
+{
+ public:
+  argument_locs (const vec<location_t> *locs, unsigned int offset)
+  : m_locs (locs), m_offset (offset)
+  {
+    gcc_assert (offset == 0 || offset == 1);
+  }
+
+  location_t get_param_location (unsigned int param_idx) const;
+
+ private:
+  const vec<location_t> *m_locs;
+  unsigned int m_offset;
+};
+
 extern bool check_function_arguments (location_t loc, const_tree, const_tree,
-				      int, tree *, vec<location_t> *);
+				      int, tree *, argument_locs);
 extern void check_function_arguments_recurse (void (*)
 					      (void *, tree,
 					       unsigned HOST_WIDE_INT),
@@ -816,7 +851,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 *, vec<location_t> *);
+extern void check_function_format (tree, int, tree *, argument_locs);
 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 *);
diff --git a/gcc/c-family/c-format.c b/gcc/c-family/c-format.c
index 0dba979..e992a06 100644
--- a/gcc/c-family/c-format.c
+++ b/gcc/c-family/c-format.c
@@ -986,10 +986,16 @@  struct format_check_results
 
 struct format_check_context
 {
+  format_check_context (format_check_results *res_,
+			function_format_info *info_,
+			tree params_,
+			argument_locs arglocs_)
+  : res (res_), info (info_), params (params_), arglocs (arglocs_) {}
+
   format_check_results *res;
   function_format_info *info;
   tree params;
-  vec<location_t> *arglocs;
+  argument_locs arglocs;
 };
 
 /* Return the format name (as specified in the original table) for the format
@@ -1012,8 +1018,7 @@  format_flags (int format_num)
   gcc_unreachable ();
 }
 
-static void check_format_info (function_format_info *, tree,
-			       vec<location_t> *);
+static void check_format_info (function_format_info *, tree, argument_locs);
 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 *,
@@ -1021,7 +1026,7 @@  static void check_format_info_main (format_check_results *,
 				    int, tree,
 				    unsigned HOST_WIDE_INT,
 				    object_allocator<format_wanted_type> &,
-				    vec<location_t> *);
+				    argument_locs);
 
 static void init_dollar_format_checking (int, tree);
 static int maybe_read_dollar_number (const char **, int,
@@ -1037,7 +1042,7 @@  static void check_format_types (const substring_loc &fmt_loc,
 				const format_kind_info *fki,
 				int offset_to_type_start,
 				char conversion_char,
-				vec<location_t> *arglocs);
+				argument_locs arglocs);
 static void format_type_warning (const substring_loc &fmt_loc,
 				 source_range *param_range,
 				 format_wanted_type *, tree,
@@ -1081,7 +1086,7 @@  decode_format_type (const char *s)
 
 void
 check_function_format (tree attrs, int nargs, tree *argarray,
-		       vec<location_t> *arglocs)
+		       argument_locs arglocs)
 {
   tree a;
 
@@ -1406,9 +1411,8 @@  get_flag_spec (const format_flag_spec *spec, int flag, const char *predicates)
 
 static void
 check_format_info (function_format_info *info, tree params,
-		   vec<location_t> *arglocs)
+		   argument_locs arglocs)
 {
-  format_check_context format_ctx;
   unsigned HOST_WIDE_INT arg_num;
   tree format_tree;
   format_check_results res;
@@ -1437,10 +1441,7 @@  check_format_info (function_format_info *info, tree params,
   res.number_other = 0;
   res.format_string_loc = input_location;
 
-  format_ctx.res = &res;
-  format_ctx.info = info;
-  format_ctx.params = params;
-  format_ctx.arglocs = arglocs;
+  format_check_context format_ctx (&res, info, params, arglocs);
 
   check_function_arguments_recurse (check_format_arg, &format_ctx,
 				    format_tree, arg_num);
@@ -1525,7 +1526,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;
+  argument_locs arglocs = format_ctx->arglocs;
 
   int format_length;
   HOST_WIDE_INT offset;
@@ -1777,7 +1778,7 @@  class argument_parser
 		   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_,
-		   vec<location_t> *arglocs);
+		   argument_locs arglocs);
 
   bool read_any_dollar ();
 
@@ -1856,7 +1857,7 @@  class argument_parser
  private:
   format_wanted_type *first_wanted_type;
   format_wanted_type *last_wanted_type;
-  vec<location_t> *arglocs;
+  argument_locs arglocs;
 };
 
 /* flag_chars_t's constructor.  */
@@ -2008,7 +2009,7 @@  argument_parser (function_format_info *info_, const char *&format_chars_,
 		 int &has_operand_number_,
 		 tree first_fillin_param_,
 		 object_allocator <format_wanted_type> &fwt_pool_,
-		 vec<location_t> *arglocs_)
+		 argument_locs arglocs_)
 : info (info_),
   fki (&format_types[info->format_type]),
   flag_specs (fki->flag_specs),
@@ -2768,7 +2769,7 @@  check_format_info_main (format_check_results *res,
 			int format_length, tree params,
 			unsigned HOST_WIDE_INT arg_num,
 			object_allocator <format_wanted_type> &fwt_pool,
-			vec<location_t> *arglocs)
+			argument_locs arglocs)
 {
   const char * const orig_format_chars = format_chars;
   const tree first_fillin_param = params;
@@ -3046,7 +3047,7 @@  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,
-		    vec<location_t> *arglocs)
+		    argument_locs arglocs)
 {
   for (; types != 0; types = types->next)
     {
@@ -3085,22 +3086,24 @@  check_format_types (const substring_loc &fmt_loc,
       char_type_flag = 0;
 
       source_range param_range;
-      source_range *param_range_ptr;
+      source_range *param_range_ptr = NULL;
       if (EXPR_HAS_LOCATION (cur_param))
 	{
 	  param_range = EXPR_LOCATION_RANGE (cur_param);
 	  param_range_ptr = &param_range;
 	}
-      else if (arglocs)
+      else
 	{
 	  /* 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;
+	  unsigned int param_idx = types->arg_num - 1;
+	  location_t param_loc = arglocs.get_param_location (param_idx);
+	  if (param_loc != UNKNOWN_LOCATION)
+	    {
+	      param_range = get_range_from_loc (line_table, param_loc);
+	      param_range_ptr = &param_range;
+	    }
 	}
-      else
-	param_range_ptr = NULL;
 
       STRIP_NOPS (cur_param);
 
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index d7ca148..5999a3b 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -3118,7 +3118,8 @@  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, &arg_loc);
+					    nargs, argarray,
+					    argument_locs (&arg_loc, 0));
 
   if (name != NULL_TREE
       && !strncmp (IDENTIFIER_POINTER (name), "__builtin_", 10))
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 067db59a..afcdd99 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -147,7 +147,8 @@  static int equal_functions (tree, tree);
 static int joust (struct z_candidate *, struct z_candidate *, bool,
 		  tsubst_flags_t);
 static int compare_ics (conversion *, conversion *);
-static tree build_over_call (struct z_candidate *, int, tsubst_flags_t);
+static tree build_over_call (struct z_candidate *, int, tsubst_flags_t,
+			     vec<location_t> * = NULL);
 #define convert_like(CONV, EXPR, COMPLAIN)			\
   convert_like_real ((CONV), (EXPR), NULL_TREE, 0,		\
 		     /*issue_conversion_warnings=*/true,	\
@@ -156,14 +157,16 @@  static tree build_over_call (struct z_candidate *, int, tsubst_flags_t);
   convert_like_real ((CONV), (EXPR), (FN), (ARGNO),			\
 		     /*issue_conversion_warnings=*/true,		\
 		     /*c_cast_p=*/false, (COMPLAIN))
-static tree convert_like_real (conversion *, tree, tree, int, bool,
+static tree convert_like_real (conversion *, cp_expr, tree, int, bool,
 			       bool, tsubst_flags_t);
 static void op_error (location_t, enum tree_code, enum tree_code, tree,
 		      tree, tree, bool);
 static struct z_candidate *build_user_type_conversion_1 (tree, tree, int,
 							 tsubst_flags_t);
-static void print_z_candidate (location_t, const char *, struct z_candidate *);
-static void print_z_candidates (location_t, struct z_candidate *);
+static void print_z_candidate (location_t, const char *, struct z_candidate *,
+			       vec<location_t> * = NULL);
+static void print_z_candidates (location_t, struct z_candidate *,
+				vec<location_t> * = NULL);
 static tree build_this (tree);
 static struct z_candidate *splice_viable (struct z_candidate *, bool, bool *);
 static bool any_strictly_viable (struct z_candidate *);
@@ -3442,7 +3445,8 @@  print_arity_information (location_t loc, unsigned int have, unsigned int want)
 
 static void
 print_z_candidate (location_t loc, const char *msgstr,
-		   struct z_candidate *candidate)
+		   struct z_candidate *candidate,
+		   vec<location_t> *arglocs)
 {
   const char *msg = (msgstr == NULL
 		     ? ""
@@ -3531,7 +3535,7 @@  print_z_candidate (location_t loc, const char *msgstr,
 			       r->u.template_unification.return_type,
 			       r->u.template_unification.strict,
 			       r->u.template_unification.flags,
-			       true, false);
+			       true, false, arglocs);
 	  break;
 	case rr_invalid_copy:
 	  inform (cloc,
@@ -3560,7 +3564,8 @@  print_z_candidate (location_t loc, const char *msgstr,
 }
 
 static void
-print_z_candidates (location_t loc, struct z_candidate *candidates)
+print_z_candidates (location_t loc, struct z_candidate *candidates,
+		    vec<location_t> *arglocs)
 {
   struct z_candidate *cand1;
   struct z_candidate **cand2;
@@ -3606,7 +3611,7 @@  print_z_candidates (location_t loc, struct z_candidate *candidates)
     }
 
   for (; candidates; candidates = candidates->next)
-    print_z_candidate (loc, "candidate:", candidates);
+    print_z_candidate (loc, "candidate:", candidates, arglocs);
 }
 
 /* USER_SEQ is a user-defined conversion sequence, beginning with a
@@ -4212,7 +4217,8 @@  perform_overload_resolution (tree fn,
 
 static void
 print_error_for_call_failure (tree fn, vec<tree, va_gc> *args,
-			      struct z_candidate *candidates)
+			      struct z_candidate *candidates,
+			      vec<location_t> *arglocs = NULL)
 {
   tree targs = NULL_TREE;
   if (TREE_CODE (fn) == TEMPLATE_ID_EXPR)
@@ -4232,7 +4238,7 @@  print_error_for_call_failure (tree fn, vec<tree, va_gc> *args,
     error_at (loc, "call of overloaded %<%D(%A)%> is ambiguous",
 	      name, build_tree_list_vec (args));
   if (candidates)
-    print_z_candidates (loc, candidates);
+    print_z_candidates (loc, candidates, arglocs);
 }
 
 /* Return an expression for a call to FN (a namespace-scope function,
@@ -4241,7 +4247,8 @@  print_error_for_call_failure (tree fn, vec<tree, va_gc> *args,
 
 tree
 build_new_function_call (tree fn, vec<tree, va_gc> **args,
-			 tsubst_flags_t complain)
+			 tsubst_flags_t complain,
+			 vec<location_t> *arglocs)
 {
   struct z_candidate *candidates, *cand;
   bool any_viable_p;
@@ -4275,7 +4282,7 @@  build_new_function_call (tree fn, vec<tree, va_gc> **args,
 	    return cp_build_function_call_vec (candidates->fn, args, complain);
 
 	  // Otherwise, emit notes for non-viable candidates.
-	  print_error_for_call_failure (fn, *args, candidates);
+	  print_error_for_call_failure (fn, *args, candidates, arglocs);
 	}
       result = error_mark_node;
     }
@@ -4307,7 +4314,7 @@  build_new_function_call (tree fn, vec<tree, va_gc> **args,
           flags |= LOOKUP_EXPLICIT_TMPL_ARGS;
         }
 
-      result = build_over_call (cand, flags, complain);
+      result = build_over_call (cand, flags, complain, arglocs);
     }
 
   /* Free all the conversions we allocated.  */
@@ -6588,14 +6595,16 @@  maybe_print_user_conv_context (conversion *convs)
    conversions to inaccessible bases are permitted.  */
 
 static tree
-convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
+convert_like_real (conversion *convs, cp_expr expr, tree fn, int argnum,
 		   bool issue_conversion_warnings,
 		   bool c_cast_p, tsubst_flags_t complain)
 {
   tree totype = convs->type;
   diagnostic_t diag_kind;
   int flags;
-  location_t loc = EXPR_LOC_OR_LOC (expr, input_location);
+  location_t loc = expr.get_location ();
+  if (loc == UNKNOWN_LOCATION)
+    loc = input_location;
 
   if (convs->bad_p && !(complain & tf_error))
     return error_mark_node;
@@ -6983,13 +6992,13 @@  convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
 		   cannot create a temporary.  */
 		if (lvalue & clk_bitfield)
 		  error_at (loc, "cannot bind bitfield %qE to %qT",
-			    expr, ref_type);
+			    expr.get_value (), ref_type);
 		else if (lvalue & clk_packed)
 		  error_at (loc, "cannot bind packed field %qE to %qT",
-			    expr, ref_type);
+			    expr.get_value (), ref_type);
 		else
 		  error_at (loc, "cannot bind rvalue %qE to %qT",
-			    expr, ref_type);
+			    expr.get_value (), ref_type);
 		return error_mark_node;
 	      }
 	    /* If the source is a packed field, and we must use a copy
@@ -7003,7 +7012,7 @@  convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
 		&& type_has_nontrivial_copy_init (type))
 	      {
 		error_at (loc, "cannot bind packed field %qE to %qT",
-			  expr, ref_type);
+			  expr.get_value (), ref_type);
 		return error_mark_node;
 	      }
 	    if (lvalue & clk_bitfield)
@@ -7542,7 +7551,8 @@  unsafe_copy_elision_p (tree target, tree exp)
    bitmask of various LOOKUP_* flags which apply to the call itself.  */
 
 static tree
-build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
+build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain,
+		 vec<location_t> *arglocs)
 {
   tree fn = cand->fn;
   const vec<tree, va_gc> *args = cand->args;
@@ -7687,6 +7697,15 @@  build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
     nargs = parmlen;
   argarray = XALLOCAVEC (tree, nargs);
 
+  /* Determine offset to args covered by ARGLOCS within argarray.
+     We either have an offset of 0:
+       | argarray[0] | argarray[1] | argarray[2] | ...
+       | arglocs [0] | arglocs [1] | arglocs [2] | ...
+     or an offset of 1:
+       | argarray[0] | argarray[1] | argarray[2] | ...
+       | first_arg   | arglocs [0] | arglocs [1] | arglocs[2] ...*/
+  int arglocs_offset = first_arg != NULL_TREE ? 1 : 0;
+
   /* The implicit parameters to a constructor are not considered by overload
      resolution, and must be of the proper type.  */
   if (DECL_CONSTRUCTOR_P (fn))
@@ -7805,7 +7824,9 @@  build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
        parm = TREE_CHAIN (parm), ++arg_index, ++i)
     {
       tree type = TREE_VALUE (parm);
-      tree arg = (*args)[arg_index];
+      cp_expr arg = (*args)[arg_index];
+      if (arglocs)
+	arg.set_location ((*arglocs)[arg_index]);
       bool conversion_warning = true;
 
       conv = convs[i];
@@ -7949,7 +7970,9 @@  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, NULL);
+					   nargs, fargs,
+					   argument_locs (arglocs,
+							  arglocs_offset));
     }
 
   if (DECL_INHERITED_CTOR (fn))
@@ -8917,7 +8940,8 @@  name_as_c_string (tree name, tree type, bool *free_p)
 static tree
 build_new_method_call_1 (tree instance, tree fns, vec<tree, va_gc> **args,
 		         tree conversion_path, int flags,
-		         tree *fn_p, tsubst_flags_t complain)
+		         tree *fn_p, tsubst_flags_t complain,
+			 vec<location_t> *arglocs)
 {
   struct z_candidate *candidates = 0, *cand;
   tree explicit_targs = NULL_TREE;
@@ -9248,7 +9272,7 @@  build_new_method_call_1 (tree instance, tree fns, vec<tree, va_gc> **args,
 	      if (fn_p)
 		*fn_p = fn;
 	      /* Build the actual CALL_EXPR.  */
-	      call = build_over_call (cand, flags, complain);
+	      call = build_over_call (cand, flags, complain, arglocs);
 	      /* In an expression of the form `a->f()' where `f' turns
 		 out to be a static member function, `a' is
 		 none-the-less evaluated.  */
@@ -9313,12 +9337,13 @@  build_new_method_call_1 (tree instance, tree fns, vec<tree, va_gc> **args,
 tree
 build_new_method_call (tree instance, tree fns, vec<tree, va_gc> **args,
 		       tree conversion_path, int flags,
-		       tree *fn_p, tsubst_flags_t complain)
+		       tree *fn_p, tsubst_flags_t complain,
+		       vec<location_t> *arglocs)
 {
   tree ret;
   bool subtime = timevar_cond_start (TV_OVERLOAD);
   ret = build_new_method_call_1 (instance, fns, args, conversion_path, flags,
-                                 fn_p, complain);
+                                 fn_p, complain, arglocs);
   timevar_cond_stop (TV_OVERLOAD, subtime);
   return ret;
 }
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 4dd9fc6..b1ec172 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5862,13 +5862,15 @@  extern tree extract_call_expr			(tree);
 extern tree build_user_type_conversion		(tree, tree, int,
 						 tsubst_flags_t);
 extern tree build_new_function_call		(tree, vec<tree, va_gc> **,
-						 tsubst_flags_t);
+						 tsubst_flags_t,
+						 vec<location_t> * = NULL);
 extern tree build_operator_new_call		(tree, vec<tree, va_gc> **,
 						 tree *, tree *, tree, tree,
 						 tree *, tsubst_flags_t);
 extern tree build_new_method_call		(tree, tree,
 						 vec<tree, va_gc> **, tree,
-						 int, tree *, tsubst_flags_t);
+						 int, tree *, tsubst_flags_t,
+						 vec<location_t> * = NULL);
 extern tree build_special_member_call		(tree, tree,
 						 vec<tree, va_gc> **,
 						 tree, int, tsubst_flags_t);
@@ -6433,7 +6435,8 @@  extern tree instantiate_template		(tree, tree, tsubst_flags_t);
 extern tree fn_type_unification			(tree, tree, tree,
 						 const tree *, unsigned int,
 						 tree, unification_kind_t, int,
-						 bool, bool);
+						 bool, bool,
+						 vec<location_t> * = NULL);
 extern void mark_decl_instantiated		(tree, int);
 extern int more_specialized_fn			(tree, tree, int);
 extern void do_decl_instantiation		(tree, tree);
@@ -6720,7 +6723,8 @@  bool empty_expr_stmt_p				(tree);
 extern cp_expr perform_koenig_lookup		(cp_expr, vec<tree, va_gc> *,
 						 tsubst_flags_t);
 extern tree finish_call_expr			(tree, vec<tree, va_gc> **, bool,
-						 bool, tsubst_flags_t);
+						 bool, tsubst_flags_t,
+						 vec<location_t> * = NULL);
 extern tree lookup_and_finish_template_variable (tree, tree, tsubst_flags_t = tf_warning_or_error);
 extern tree finish_template_variable		(tree, tsubst_flags_t = tf_warning_or_error);
 extern cp_expr finish_increment_expr		(cp_expr, enum tree_code);
@@ -7026,7 +7030,8 @@  extern tree get_member_function_from_ptrfunc	(tree *, tree, tsubst_flags_t);
 extern tree cp_build_function_call_nary         (tree, tsubst_flags_t, ...)
 						ATTRIBUTE_SENTINEL;
 extern tree cp_build_function_call_vec		(tree, vec<tree, va_gc> **,
-						 tsubst_flags_t);
+						 tsubst_flags_t,
+						 vec<location_t> * = NULL);
 extern tree build_x_binary_op			(location_t,
 						 enum tree_code, tree,
 						 enum tree_code, tree,
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index b849824..29de054 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -2051,7 +2051,8 @@  static tree cp_parser_postfix_open_square_expression
 static tree cp_parser_postfix_dot_deref_expression
   (cp_parser *, enum cpp_ttype, cp_expr, bool, cp_id_kind *, location_t);
 static vec<tree, va_gc> *cp_parser_parenthesized_expression_list
-  (cp_parser *, int, bool, bool, bool *, location_t * = NULL);
+  (cp_parser *, int, bool, bool, bool *, location_t * = NULL,
+   vec<location_t> * = NULL);
 /* Values for the second parameter of cp_parser_parenthesized_expression_list.  */
 enum { non_attr = 0, normal_attr = 1, id_attr = 2 };
 static void cp_parser_pseudo_destructor_name
@@ -6961,6 +6962,7 @@  cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
 	    bool saved_non_integral_constant_expression_p = false;
 	    tsubst_flags_t complain = complain_flags (decltype_p);
 	    vec<tree, va_gc> *args;
+	    auto_vec<location_t> arglocs;
 	    location_t close_paren_loc = UNKNOWN_LOCATION;
 
             is_member_access = false;
@@ -6981,7 +6983,8 @@  cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
 		    (parser, non_attr,
 		     /*cast_p=*/false, /*allow_expansion_p=*/true,
 		     /*non_constant_p=*/NULL,
-		     /*close_paren_loc=*/&close_paren_loc));
+		     /*close_paren_loc=*/&close_paren_loc,
+		     &arglocs));
 	    if (is_builtin_constant_p)
 	      {
 		parser->integral_constant_expression_p
@@ -7092,14 +7095,16 @@  cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
 			 ? LOOKUP_NORMAL|LOOKUP_NONVIRTUAL
 			 : LOOKUP_NORMAL),
 			/*fn_p=*/NULL,
-			complain));
+			complain,
+			&arglocs));
 		  }
 		else
 		  postfix_expression
 		    = finish_call_expr (postfix_expression, &args,
 					/*disallow_virtual=*/false,
 					/*koenig_p=*/false,
-					complain);
+					complain,
+					&arglocs);
 	      }
 	    else if (TREE_CODE (postfix_expression) == OFFSET_REF
 		     || TREE_CODE (postfix_expression) == MEMBER_REF
@@ -7114,14 +7119,16 @@  cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
 		= finish_call_expr (postfix_expression, &args,
 				    /*disallow_virtual=*/true,
 				    koenig_p,
-				    complain);
+				    complain,
+				    &arglocs);
 	    else
 	      /* All other function calls.  */
 	      postfix_expression
 		= finish_call_expr (postfix_expression, &args,
 				    /*disallow_virtual=*/false,
 				    koenig_p,
-				    complain);
+				    complain,
+				    &arglocs);
 
 	    if (close_paren_loc != UNKNOWN_LOCATION)
 	      {
@@ -7637,7 +7644,8 @@  cp_parser_parenthesized_expression_list (cp_parser* parser,
 					 bool cast_p,
                                          bool allow_expansion_p,
 					 bool *non_constant_p,
-					 location_t *close_paren_loc)
+					 location_t *close_paren_loc,
+					 vec<location_t> *arglocs)
 {
   vec<tree, va_gc> *expression_list;
   bool fold_expr_p = is_attribute_list != non_attr;
@@ -7664,8 +7672,6 @@  cp_parser_parenthesized_expression_list (cp_parser* parser,
   if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN))
     while (true)
       {
-	tree expr;
-
 	/* At the beginning of attribute lists, check to see if the
 	   next token is an identifier.  */
 	if (is_attribute_list == id_attr
@@ -7680,6 +7686,7 @@  cp_parser_parenthesized_expression_list (cp_parser* parser,
 	  }
 	else
 	  {
+	    cp_expr expr;
 	    bool expr_non_constant_p;
 
 	    /* Parse the next assignment-expression.  */
@@ -7723,7 +7730,10 @@  cp_parser_parenthesized_expression_list (cp_parser* parser,
 		expressions to the list, so that we can still tell if
 		the correct form for a parenthesized expression-list
 		is found. That gives better errors.  */
-	    vec_safe_push (expression_list, expr);
+	    vec_safe_push (expression_list, expr.get_value ());
+
+	    if (arglocs)
+	      arglocs->safe_push (expr.get_location ());
 
 	    if (expr == error_mark_node)
 	      goto skip_comma;
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 8d816c7..c642077 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -155,7 +155,8 @@  static int maybe_adjust_types_for_deduction (unification_kind_t, tree*, tree*,
 static int type_unification_real (tree, tree, tree, const tree *,
 				  unsigned int, int, unification_kind_t, int,
 				  vec<deferred_access_check, va_gc> **,
-				  bool);
+				  bool,
+				  vec<location_t> * = NULL);
 static void note_template_header (int);
 static tree convert_nontype_argument_function (tree, tree, tsubst_flags_t);
 static tree convert_nontype_argument (tree, tree, tsubst_flags_t);
@@ -6191,10 +6192,16 @@  unify_cv_qual_mismatch (bool explain_p, tree parm, tree arg)
 }
 
 static int
-unify_type_mismatch (bool explain_p, tree parm, tree arg)
+unify_type_mismatch (bool explain_p, tree parm, cp_expr arg)
 {
   if (explain_p)
-    inform (input_location, "  mismatched types %qT and %qT", parm, arg);
+    {
+      location_t loc = arg.get_location ();
+      if (loc == UNKNOWN_LOCATION)
+	loc = input_location;
+      inform (loc, "  mismatched types %qT and %qT", parm,
+	      arg.get_value ());
+    }
   return unify_invalid (explain_p);
 }
 
@@ -6310,12 +6317,17 @@  unify_too_few_arguments (bool explain_p, int have, int wanted,
 
 static int
 unify_arg_conversion (bool explain_p, tree to_type,
-		      tree from_type, tree arg)
+		      tree from_type, cp_expr arg)
 {
   if (explain_p)
-    inform (EXPR_LOC_OR_LOC (arg, input_location),
-	    "  cannot convert %qE (type %qT) to type %qT",
-	    arg, from_type, to_type);
+    {
+      location_t loc = arg.get_location ();
+      if (loc == UNKNOWN_LOCATION)
+	loc = input_location;
+      inform (loc,
+	      "  cannot convert %qE (type %qT) to type %qT",
+	      arg.get_value (), from_type, to_type);
+    }
   return unify_invalid (explain_p);
 }
 
@@ -18416,7 +18428,8 @@  fn_type_unification (tree fn,
 		     unification_kind_t strict,
 		     int flags,
 		     bool explain_p,
-		     bool decltype_p)
+		     bool decltype_p,
+		     vec<location_t> *arglocs)
 {
   tree parms;
   tree fntype;
@@ -18625,7 +18638,7 @@  fn_type_unification (tree fn,
 
   ok = !type_unification_real (DECL_INNERMOST_TEMPLATE_PARMS (fn),
 			       full_targs, parms, args, nargs, /*subr=*/0,
-			       strict, flags, &checks, explain_p);
+			       strict, flags, &checks, explain_p, arglocs);
   if (!explain_p)
     pop_tinst_level ();
   if (!ok)
@@ -18860,7 +18873,7 @@  maybe_adjust_types_for_deduction (unification_kind_t strict,
    unify_one_argument.  */
 
 static int
-check_non_deducible_conversion (tree parm, tree arg, int strict,
+check_non_deducible_conversion (tree parm, cp_expr arg, int strict,
 				int flags, bool explain_p)
 {
   tree type;
@@ -18882,7 +18895,7 @@  check_non_deducible_conversion (tree parm, tree arg, int strict,
   else if (strict != DEDUCE_EXACT)
     {
       if (can_convert_arg (parm, type,
-			   TYPE_P (arg) ? NULL_TREE : arg,
+			   TYPE_P (arg) ? NULL_TREE : arg.get_value (),
 			   flags, explain_p ? tf_warning_or_error : tf_none))
 	return unify_success (explain_p);
     }
@@ -19187,9 +19200,10 @@  type_unification_real (tree tparms,
 		       unification_kind_t strict,
 		       int flags,
 		       vec<deferred_access_check, va_gc> **checks,
-		       bool explain_p)
+		       bool explain_p,
+		       vec<location_t> *arglocs)
 {
-  tree parm, arg;
+  tree parm;
   int i;
   int ntparms = TREE_VEC_LENGTH (tparms);
   int saw_undeduced = 0;
@@ -19235,7 +19249,12 @@  type_unification_real (tree tparms,
 	   parameter pack is a non-deduced context.  */
 	continue;
 
-      arg = args[ia];
+      cp_expr arg = args[ia];
+      if (arglocs)
+	arg.set_location ((*arglocs)[ia]);
+      else
+	if (!CAN_HAVE_LOCATION_P (arg.get_value ()))
+	  arg.set_location (input_location);
       ++ia;
 
       if (unify_one_argument (tparms, full_targs, parm, arg, subr, strict,
@@ -19398,7 +19417,12 @@  type_unification_real (tree tparms,
 		 parameter pack is a non-deduced context.  */
 	      continue;
 
-	    arg = args[ia];
+	    cp_expr arg = args[ia];
+	    if (arglocs)
+	      arg.set_location ((*arglocs)[ia]);
+	    else
+	      if (!CAN_HAVE_LOCATION_P (arg.get_value ()))
+		arg.set_location (input_location);
 	    ++ia;
 
 	    if (uses_template_parms (parm))
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 5401e78..d58eef2 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -2304,7 +2304,8 @@  perform_koenig_lookup (cp_expr fn, vec<tree, va_gc> *args,
 
 tree
 finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual,
-		  bool koenig_p, tsubst_flags_t complain)
+		  bool koenig_p, tsubst_flags_t complain,
+		  vec<location_t> *arglocs)
 {
   tree result;
   tree orig_fn;
@@ -2388,7 +2389,7 @@  finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual,
                                          ? LOOKUP_NORMAL | LOOKUP_NONVIRTUAL
 					 : LOOKUP_NORMAL),
 					/*fn_p=*/NULL,
-					complain);
+					complain, arglocs);
 	}
     }
 
@@ -2440,7 +2441,7 @@  finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual,
 				       ? LOOKUP_NORMAL|LOOKUP_NONVIRTUAL
 				       : LOOKUP_NORMAL),
 				      /*fn_p=*/NULL,
-				      complain);
+				      complain, arglocs);
     }
   else if (is_overloaded_fn (fn))
     {
@@ -2483,7 +2484,7 @@  finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual,
 	    }
 
 	  /* A call to a namespace-scope function.  */
-	  result = build_new_function_call (fn, args, complain);
+	  result = build_new_function_call (fn, args, complain, arglocs);
 	}
     }
   else if (TREE_CODE (fn) == PSEUDO_DTOR_EXPR)
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 63667f3..3c8ef7a3 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -3577,7 +3577,8 @@  cp_build_function_call_nary (tree function, tsubst_flags_t complain, ...)
 
 tree
 cp_build_function_call_vec (tree function, vec<tree, va_gc> **params,
-			    tsubst_flags_t complain)
+			    tsubst_flags_t complain,
+			    vec<location_t> *arglocs)
 {
   tree fntype, fndecl;
   int is_method;
@@ -3699,7 +3700,8 @@  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, NULL);
+					    nargs, argarray,
+					    argument_locs (arglocs, 0));
 
   ret = build_cxx_call (function, nargs, argarray, complain);
 
diff --git a/gcc/testsuite/g++.dg/Wformat-on-method.C b/gcc/testsuite/g++.dg/Wformat-on-method.C
new file mode 100644
index 0000000..4ff22fb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/Wformat-on-method.C
@@ -0,0 +1,31 @@ 
+/* { dg-options "-Wformat -fdiagnostics-show-caret" } */
+
+struct logger
+{
+  void log (const char *fmt, ...)
+    __attribute__ ((format (gnu_printf, (2), (3))));
+
+  void test ();
+};
+
+/* Test of location-lookup within method call.  */
+
+void test (logger *logger)
+{
+  logger->log ("%i %s %i", 100, 101, 102); /* { dg-warning "format '%s' expects argument of type 'char\\*', but argument 4 has type 'int'" } */
+/* { dg-begin-multiline-output "" }
+   logger->log ("%i %s %i", 100, 101, 102);
+                                 ~~~     ^
+   { dg-end-multiline-output "" } */
+}
+
+/* Test of location-lookup with implicit "this".  */
+
+void logger::test ()
+{
+  log ("%i %s %i", 100, 101, 102); /* { dg-warning "format '%s' expects argument of type 'char\\*', but argument 4 has type 'int'" } */
+/* { dg-begin-multiline-output "" }
+   log ("%i %s %i", 100, 101, 102);
+                         ~~~     ^
+   { dg-end-multiline-output "" } */
+}
diff --git a/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch.C b/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch.C
index b8833ef..f9f5d74 100644
--- a/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch.C
+++ b/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch.C
@@ -17,7 +17,7 @@  int test_1 (int first, int second, float third)
   return callee_1 (first, second, third); // { dg-error "invalid conversion from 'int' to 'const char\\*'" }
   /* { dg-begin-multiline-output "" }
    return callee_1 (first, second, third);
-                                        ^
+                           ^~~~~~
      { dg-end-multiline-output "" } */
   // { dg-message "initializing argument 2 of 'int callee_1\\(int, const char\\*, float\\)'" "" { target *-*-* } callee_1 }
   /* { dg-begin-multiline-output "" }
@@ -35,7 +35,7 @@  int test_2 (int first, int second, float third)
   return callee_2 (first, second, third); // { dg-error "invalid conversion from 'int' to 'const char\\*'" }
   /* { dg-begin-multiline-output "" }
    return callee_2 (first, second, third);
-                                        ^
+                           ^~~~~~
      { dg-end-multiline-output "" } */
   // { dg-message "initializing argument 2 of 'int callee_2\\(int, const char\\*, float\\)'" "" { target *-*-* } callee_2 }
   /* { dg-begin-multiline-output "" }
@@ -56,7 +56,7 @@  int test_3 (int first, int second, float third)
   return callee_3 (first, second, third); // { dg-error "invalid conversion from 'int' to 'const char\\*'" }
   /* { dg-begin-multiline-output "" }
    return callee_3 (first, second, third);
-                                        ^
+                           ^~~~~~
      { dg-end-multiline-output "" } */
   // { dg-message "initializing argument 2 of 'int callee_3\\(int, const char\\*, float\\)'" "" { target *-*-* } callee_3 }
   /* { dg-begin-multiline-output "" }
@@ -74,7 +74,7 @@  int test_4 (int first, int second, float third)
   return s4::member_1 (first, second, third); // { dg-error "invalid conversion from 'int' to 'const char\\*'" }
   /* { dg-begin-multiline-output "" }
    return s4::member_1 (first, second, third);
-                                            ^
+                               ^~~~~~
      { dg-end-multiline-output "" } */
   /* { dg-begin-multiline-output "" }
  struct s4 { static int member_1 (int one, const char *two, float three); };
@@ -92,7 +92,7 @@  int test_5 (int first, int second, float third)
   return inst.member_1 (first, second, third); // { dg-error "invalid conversion from 'int' to 'const char\\*'" }
   /* { dg-begin-multiline-output "" }
    return inst.member_1 (first, second, third);
-                                             ^
+                                ^~~~~~
      { dg-end-multiline-output "" } */
   /* { dg-begin-multiline-output "" }
  struct s5 { int member_1 (int one, const char *two, float three); };
@@ -109,7 +109,7 @@  int test_6 (int first, int second, float third, s6 *ptr)
   return ptr->member_1 (first, second, third); // { dg-error "invalid conversion from 'int' to 'const char\\*'" }
   /* { dg-begin-multiline-output "" }
    return ptr->member_1 (first, second, third);
-                                             ^
+                                ^~~~~~
      { dg-end-multiline-output "" } */
   /* { dg-begin-multiline-output "" }
  struct s6 { int member_1 (int one, const char *two, float three); };
@@ -131,7 +131,7 @@  int test_7 (int first, int second, float third)
      { dg-end-multiline-output "" } */
   /* { dg-begin-multiline-output "" }
    return test_7 <const char *> (first, second, third);
-                                                     ^
+                                        ^~~~~~
      { dg-end-multiline-output "" } */
   /* { dg-begin-multiline-output "" }
  int test_7 (int one, T two, float three);
@@ -149,7 +149,7 @@  int test_8 (int first, int second, float third)
   return s8 <const char *>::member_1 (first, second, third); // { dg-error "invalid conversion from 'int' to 'const char\\*'" }
   /* { dg-begin-multiline-output "" }
    return s8 <const char *>::member_1 (first, second, third);
-                                                           ^
+                                              ^~~~~~
      { dg-end-multiline-output "" } */
   /* { dg-begin-multiline-output "" }
  struct s8 { static int member_1 (int one, T two, float three); };
@@ -168,7 +168,7 @@  int test_9 (int first, int second, float third)
   return inst.member_1 (first, second, third); // { dg-error "invalid conversion from 'int' to 'const char\\*'" }
   /* { dg-begin-multiline-output "" }
    return inst.member_1 (first, second, third);
-                                             ^
+                                ^~~~~~
      { dg-end-multiline-output "" } */
   /* { dg-begin-multiline-output "" }
  struct s9 { int member_1 (int one, T two, float three); };