[PATCH] Add extra location information - PR43486

Arnaud Charlet charlet@adacore.com
Tue Sep 18 10:59:00 GMT 2012


This is a relatively large patch which tackles the difficult issue of
generating more sloc information in front-ends (in particular C and C++
front-ends), so that "static analyzers" based on GCC can get more useful
and detailed information.

This happens to be related/similar to the need mentioned in PR43486, hence
the mention of this PR in the subject line.

In my work, as I mentioned a few times in the past, this patch is the
first foundation for another patch, which will provide source navigation
capabilities in IDEs/editors, by generating source cross reference information
based on the C and C++ front-ends (introducing a new switch -fdump-xref).
Ideally I'd like to submit both patches.

Since this issue is more general, I have split my changes and introduced a new
tentative switch called -fextra-slocs, which is the subject of this email.

In order to provide more sloc info attached to nodes (and in particular
VAR_DECLs), there are basically two possibilities:

- the one mentioned in comment 4 of PR43486:
  << Jason Merrill 2010-03-23 01:51:34 UTC

  I suppose we could wrap rvalue uses in NOP_EXPR and lvalue uses in
  VIEW_CONVERT_EXPR.
  >>

  I investigated this option, and unfortunately this does not work
  because of folding occurring all over the place in the C and
  C++ front-ends, removing these extra EXPRs very early.

  So I opted for the second approach:
- Keep another data structure which will associate extra slocs with some
  node expressions. The idea is that since you can't associate slocs with
  VAR_DECLs in an expr, instead we store extra slocs in the containing
  expression node. For instance, all binary expressions (add ADD, MINUS, ...)
  will contain two extra slocs: one for the left hand side, and one for the
  right hand side of the expression. One extra sloc for unary operators,
  etc...
  I've used a hash table which associates an array of location_t to some
  expr nodes, which could then be used by static analysis passes (as done
  by my patch to implement a -fdump-xref switch).

I have attached the various patches, split in directories:
- difs.common contains the common parts, introducing the -fextra-slocs
  switch and the generic data structure/API to store/retrieve extra slocs
  (in tree.[hc])
- difs.c contains the C front-end specific parts and add lots of source
  location information, add some extra loc parameters to various parser
  functions, and store these extra slocs when -fextra-slocs is enabled
- difs.cp does the same thing for the C++ front-end and includes testsuite
  updates which are triggered by this patch, showing some of the immediate
  benefits/side effects of generating more accurate "primary" slocs in 
  some cases (the case of Class::Method () references, where we now want to
  reference the sloc pointing to Method rather than Class)

OK on principle? Or is the whole approach not suitable/doomed?

If OK on principle, I'd appreciate a C, C++ front-end maintainers, and
a general maintainer (for the common/general part) to review my patches in
more details, and hopefully give their review/OK.

Here is the ChangeLog (which will be split into the various directories of
course), patches are in attachment.

2012-09-18  Arnaud Charlet  <charlet@adacore.com>

	* tree.h, tree.c (stabilize_reference): Copy source locations.
	(sloc_struct, extra_slocs): New.
	(node_hash, node_eq): Implement extra_slocs hash table.
	(expr_locations, set_expr_locations, set_expr_location2,
	duplicate_expr_locations, expr_location_n): New functions.
	(EXPR_LOCATIONS, SET_EXPR_LOCATION2, SET_EXPR_LOCATIONS): New macros.
	* common.opt: New switch -fextra-slocs.

c/
	* c-parser.c (c_parser_expr_list): New parameter locs, num_locs.
	Set extra locations.
	(c_parser_attributes): Adjust calls to c_parser_expr_list.
	(c_parser_statement_after_labels): Adjust calls to c_finish_return with
	extra expr location.
	(c_parser_expr_no_commas, c_parser_conditional_expression,
	c_parser_binary_expression, c_parser_cast_expression,
	c_parser_unary_expression, c_parser_postfix_expression_after_primary,
	c_parser_expr_list): Set extra locations.
	(c_parser_postfix_expression): Remove extra semicolon.
	(c_parser_objc_keywordexpr): Adjust call to c_parser_expr_list.
	* c-typeck.c (c_finish_return): New parameter loc_expr.
	* c-tree.h (c_finish_return): Add location_t parameter.
	* c-decl.c (finish_function): Update call to c_finish_return.
	(build_function_declarator): Set ret->id_loc.
c-family/
	* c-common.c (c_fully_fold_internal): Copy extra locations on new node.
objc/
	* objc-act.c (objc_synthesize_getter): Update call to c_finish_return.
cp/
	* parser.c (cp_parser_unary_expression, cp_parser_binary_expression,
	cp_parser_question_colon_clause, cp_parser_assignment_expression,
	cp_parser_enumerator_definition): Set extra locations.
	(cp_parser_parenthesized_expression_list): Ditto. New parameters
	locs, num_locs.
	(cp_parser_parse_and_diagnose_invalid_typ): Adjust call to
	cp_parser_id_location.
	(cp_parser_userdef_char_literal, cp_parser_userdef_numeric_literal,
	cp_parser_userdef_string_literal, cp_parser_perform_range_for_lookup,
	cp_parser_range_for_member_function): Adjust calls to finish_call_expr.
	(cp_parser_primary_expression, cp_parser_postfix_dot_deref_expression,
	cp_parser_decltype, cp_parser_type_parameter,
	cp_parser_template_argument, cp_parser_omp_var_list_no_open): Adjust
	calls to cp_parser_id_expression.
	(cp_parser_id_expression, cp_parser_declarator_id): New parameter
	location_t *. Set location to proper sloc for class::method
	declarations.
	(cp_parser_postfix_expression): Set extra locations.
	Update calls to cp_parser_parenthesized_expression_list,
	build_new_method_call and finish_call_expr.
	(cp_parser_postfix_open_square_expression): Add extra locations for
	array refs (e.g. a[i]).
	(cp_parser_direct_declarator): Adjust call to cp_parser_declarator_id
	and adjust sloc of declarator.
	(cp_parser_new_placement, cp_parser_new_initializer,
	cp_parser_mem_initializer, cp_parser_initializer,
	cp_parser_attribute_list, cp_parser_functional_cast): Adjust call to
	cp_parser_parenthesized_expression_list.
	* typeck.c (build_c_cast): Ensure extra sloc information is preserved
	over this function.
	* call.c (build_over_call): New parameter loc.
	(build_new_function_call, build_operator_new_call, build_op_call_1,
	build_new_op_1, convert_like_real): Update call to build_over_call.
	(build_new_method_call, build_new_method_call_1, finish_call_expr):
	New parameter loc.
	(build_special_member_call): Update call to build_new_method_call.
	(perform_implicit_conversion_flags): Ensure line number
	information is preserved over this function.
	* method.c (locate_fn_flags): Update call to build_new_method_call.
	* class.c (build_self_reference): Update decl location of internal type.
	* cp-tree.h (build_new_method_call, finish_call_expr): New parameter
	loc.
	* pt.c (tsubst_copy_and_build): Update call to build_new_method_call
	and finish_call_expr.
	* init.c (build_new_1, build_dtor_call): Ditto.
	* semantics.c (finish_omp_barrier, finish_omp_flush,
	finish_omp_taskyield, finish_omp_taskwait): Ditto.
	(finish_call_expr): Ditto. New parameter loc.
	(finish_id_expression): Add sloc on decl.
testsuite/
	* g++.dg/warn/pr26785.C, g++.old-deja/g++.brendan/crash16.C: Update
	column numbers.
	* g++.dg/tc1/dr52.C: Update baseline.

-------------- next part --------------
Index: common.opt
===================================================================
--- common.opt	(revision 190939)
+++ common.opt	(working copy)
@@ -1098,6 +1098,10 @@ fexcess-precision=
 Common Joined RejectNegative Enum(excess_precision) Var(flag_excess_precision_cmdline) Init(EXCESS_PRECISION_DEFAULT)
 -fexcess-precision=[fast|standard]	Specify handling of excess floating-point precision
 
+fextra-slocs
+Common Var(flag_extra_slocs) Init(0)
+Generate extra sloc information on expression trees
+
 Enum
 Name(excess_precision) Type(enum excess_precision) UnknownError(unknown excess precision style %qs)
 
Index: tree.c
===================================================================
--- tree.c	(revision 190939)
+++ tree.c	(working copy)
@@ -3561,6 +3561,8 @@ stabilize_reference (tree ref)
   TREE_READONLY (result) = TREE_READONLY (ref);
   TREE_SIDE_EFFECTS (result) = TREE_SIDE_EFFECTS (ref);
   TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (ref);
+  protected_set_expr_location (result, EXPR_LOCATION (ref));
+  duplicate_expr_locations (result, ref);
 
   return result;
 }
@@ -4157,6 +4159,123 @@ build_block (tree vars, tree subblocks,
   return block;
 }
 
+/* extra location hash table */
+
+typedef struct {
+  const_tree node;
+  unsigned char len;
+  location_t locus[1];
+} sloc_struct;
+
+static htab_t extra_slocs = NULL;
+
+/* Hash function used by extra_slocs htable.  */
+static hashval_t
+node_hash (const void *p)
+{
+  const sloc_struct *m = (const sloc_struct *)p;
+  return htab_hash_pointer (m->node);
+}
+
+/* Comparison function used by extra_slocs htable.  */
+static int
+node_eq (const void *p, const void *q)
+{
+  const sloc_struct *a = (const sloc_struct *)p;
+  const sloc_struct *b = (const sloc_struct *)q;
+
+  return a->node == b->node;
+}
+
+/* Only relevant for EXPR_P nodes and when flag_extra_slocs is enabled.
+   Return secondary locations if any for a given expression. This is useful for
+   getting precise sloc information in particular correct column
+   numbers for each member of an expression. Unary expressions will return one
+   extra location, binary expressions will return two, COND_EXPR 3 extra,
+   etc... CALL_EXPR will return one extra loc for the precise location of the
+   function or method called, and one extra loc per argument.  */
+location_t *
+expr_locations (const_tree node)
+{
+  sloc_struct key;
+  sloc_struct *res;
+
+  if (!extra_slocs)
+    return NULL;
+
+  key.node = node;
+  res = (sloc_struct *) htab_find (extra_slocs, &key);
+  return res ? res->locus : NULL;
+}
+
+/* Return the nth location N associated with NODE, or UNKNOWN_LOCATION if
+   no extra location can be found (or -fextra-slocs is not set).  */
+location_t
+expr_location_n (const_tree node, int n)
+{
+  sloc_struct key;
+  sloc_struct *res;
+
+  if (!extra_slocs)
+    return UNKNOWN_LOCATION;
+
+  key.node = node;
+  res = (sloc_struct *) htab_find (extra_slocs, &key);
+
+  if (res && res->len > n)
+    return res->locus[n];
+  else
+    return UNKNOWN_LOCATION;
+}
+
+/* Set extra locations associated with NODE. LOCUS is an array of LEN
+   locations.  No-op unless -fextra-slocs is set.  */
+void
+set_expr_locations (tree node, location_t *locus, int len)
+{
+  sloc_struct *m;
+
+  if (!flag_extra_slocs)
+    return;
+
+  if (!extra_slocs)
+    extra_slocs = htab_create (8192, node_hash, node_eq, free);
+
+  m = (sloc_struct *)
+       xcalloc (1, sizeof (sloc_struct) + sizeof (location_t) * (len - 1));
+  m->node = node;
+  m->len = len;
+  memcpy (m->locus, locus, sizeof (location_t) * len);
+  *htab_find_slot (extra_slocs, m, INSERT) = m;
+}
+
+/* Set an extra location LOCUS for tree NODE.  No-op unless -fextra-slocs.  */
+void
+set_expr_location2 (tree node, location_t locus)
+{
+  if (!flag_extra_slocs)
+    return;
+
+  location_t l = locus;
+  set_expr_locations (node, &l, 1);
+}
+
+/* Copy extra locations associated with TARGET to SOURCE, if any.  */
+void
+duplicate_expr_locations (tree target, tree source)
+{
+  sloc_struct key;
+  sloc_struct *res;
+
+  if (!extra_slocs || !CAN_HAVE_LOCATION_P (target))
+    return;
+
+  key.node = source;
+  res = (sloc_struct *) htab_find (extra_slocs, &key);
+
+  if (res)
+    set_expr_locations (target, res->locus, res->len);
+}
 
 /* Like SET_EXPR_LOCATION, but make sure the tree can have a location.
 
Index: tree.h
===================================================================
--- tree.h	(revision 190939)
+++ tree.h	(working copy)
@@ -1618,7 +1618,10 @@ struct GTY(()) tree_constructor {
    return nothing.  */
 #define EXPR_LOCATION(NODE) \
   (CAN_HAVE_LOCATION_P ((NODE)) ? (NODE)->exp.locus : UNKNOWN_LOCATION)
+#define EXPR_LOCATIONS(NODE) expr_locations ((NODE))
 #define SET_EXPR_LOCATION(NODE, LOCUS) EXPR_CHECK ((NODE))->exp.locus = (LOCUS)
+#define SET_EXPR_LOCATION2(NODE, FROM) set_expr_location2 ((NODE), (FROM))
+#define SET_EXPR_LOCATIONS(NODE, FROM, LENGTH) set_expr_locations ((NODE), (FROM), (LENGTH))
 #define EXPR_HAS_LOCATION(NODE) (EXPR_LOCATION (NODE) != UNKNOWN_LOCATION)
 /* The location to be used in a diagnostic about this expression.  Do not
    use this macro if the location will be assigned to other expressions.  */
@@ -1631,6 +1634,11 @@ struct GTY(()) tree_constructor {
 #define CAN_HAVE_LOCATION_P(NODE) ((NODE) && EXPR_P (NODE))
 
 extern void protected_set_expr_location (tree, location_t);
+extern location_t *expr_locations (const_tree);
+extern location_t expr_location_n (const_tree, int);
+extern void set_expr_location2 (tree, location_t);
+extern void set_expr_locations (tree, location_t *, int);
+extern void duplicate_expr_locations (tree, tree);
 
 /* In a TARGET_EXPR node.  */
 #define TARGET_EXPR_SLOT(NODE) TREE_OPERAND_CHECK_CODE (NODE, TARGET_EXPR, 0)
-------------- next part --------------
A non-text attachment was scrubbed...
Name: difs.c
Type: text/x-csrc
Size: 21698 bytes
Desc: not available
URL: <http://gcc.gnu.org/pipermail/gcc-patches/attachments/20120918/cd505173/attachment.bin>
-------------- next part --------------
Index: cp/typeck.c
===================================================================
--- cp/typeck.c	(revision 190939)
+++ cp/typeck.c	(working copy)
@@ -6645,9 +6645,14 @@ build_const_cast (tree type, tree expr,
 /* Like cp_build_c_cast, but for the c-common bits.  */
 
 tree
-build_c_cast (location_t loc ATTRIBUTE_UNUSED, tree type, tree expr)
+build_c_cast (location_t loc, tree type, tree expr)
 {
-  return cp_build_c_cast (type, expr, tf_warning_or_error);
+  tree result = cp_build_c_cast (type, expr, tf_warning_or_error);
+
+  if (EXPR_P (result))
+    SET_EXPR_LOCATION2 (result, loc);
+
+  return result;
 }
 
 /* Build an expression representing an explicit C-style cast to type
Index: cp/call.c
===================================================================
--- cp/call.c	(revision 190939)
+++ cp/call.c	(working copy)
@@ -146,7 +146,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,
+			     location_t);
 static tree build_java_interface_fn_ref (tree, tree);
 #define convert_like(CONV, EXPR, COMPLAIN)			\
   convert_like_real ((CONV), (EXPR), NULL_TREE, 0, 0,		\
@@ -3905,7 +3906,7 @@ build_new_function_call (tree fn, VEC(tr
          about peculiar null pointer conversion.  */
       if (TREE_CODE (fn) == TEMPLATE_ID_EXPR)
         flags |= LOOKUP_EXPLICIT_TMPL_ARGS;
-      result = build_over_call (cand, flags, complain);
+      result = build_over_call (cand, flags, complain, input_location);
     }
 
   /* Free all the conversions we allocated.  */
@@ -4024,7 +4025,7 @@ build_operator_new_call (tree fnname, VE
      *fn = cand->fn;
 
    /* Build the CALL_EXPR.  */
-   return build_over_call (cand, LOOKUP_NORMAL, complain);
+   return build_over_call (cand, LOOKUP_NORMAL, complain, input_location);
 }
 
 /* Build a new call to operator().  This may change ARGS.  */
@@ -4145,7 +4146,8 @@ build_op_call_1 (tree obj, VEC(tree,gc)
 	 DECL_NAME here.  */
       else if (TREE_CODE (cand->fn) == FUNCTION_DECL
 	       && DECL_OVERLOADED_OPERATOR_P (cand->fn) == CALL_EXPR)
-	result = build_over_call (cand, LOOKUP_NORMAL, complain);
+	result = build_over_call (cand, LOOKUP_NORMAL, complain,
+				  input_location);
       else
 	{
 	  obj = convert_like_with_context (cand->convs[0], obj, cand->fn, -1,
@@ -5171,7 +5173,8 @@ build_new_op_1 (location_t loc, enum tre
 	  if (resolve_args (arglist, complain) == NULL)
 	    result = error_mark_node;
 	  else
-	    result = build_over_call (cand, LOOKUP_NORMAL, complain);
+	    result = build_over_call (cand, LOOKUP_NORMAL, complain,
+				      input_location);
 	}
       else
 	{
@@ -5783,7 +5786,7 @@ convert_like_real (conversion *convs, tr
 	for (i = 0; i < cand->num_convs; ++i)
 	  cand->convs[i]->user_conv_p = true;
 
-	expr = build_over_call (cand, LOOKUP_NORMAL, complain);
+	expr = build_over_call (cand, LOOKUP_NORMAL, complain, input_location);
 
 	/* If this is a constructor or a function returning an aggr type,
 	   we need to build up a TARGET_EXPR.  */
@@ -6402,7 +6405,8 @@ magic_varargs_p (tree fn)
    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,
+		 location_t loc ATTRIBUTE_UNUSED)
 {
   tree fn = cand->fn;
   const VEC(tree,gc) *args = cand->args;
@@ -7130,7 +7134,7 @@ build_special_member_call (tree instance
   ret = build_new_method_call (instance, fns, args,
 			       TYPE_BINFO (BINFO_TYPE (binfo)),
 			       flags, /*fn=*/NULL,
-			       complain);
+			       complain, input_location);
 
   if (allocated != NULL)
     release_tree_vector (allocated);
@@ -7185,12 +7189,12 @@ name_as_c_string (tree name, tree type,
 
 /* Build a call to "INSTANCE.FN (ARGS)".  If FN_P is non-NULL, it will
    be set, upon return, to the function called.  ARGS may be NULL.
-   This may change ARGS.  */
+   This may change ARGS.  LOC is the source location of the call.  */
 
 static tree
 build_new_method_call_1 (tree instance, tree fns, VEC(tree,gc) **args,
 		         tree conversion_path, int flags,
-		         tree *fn_p, tsubst_flags_t complain)
+		         tree *fn_p, tsubst_flags_t complain, location_t loc)
 {
   struct z_candidate *candidates = 0, *cand;
   tree explicit_targs = NULL_TREE;
@@ -7469,7 +7473,7 @@ build_new_method_call_1 (tree instance,
 	      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, loc);
 	      /* In an expression of the form `a->f()' where `f' turns
 		 out to be a static member function, `a' is
 		 none-the-less evaluated.  */
@@ -7534,12 +7538,12 @@ build_new_method_call_1 (tree instance,
 tree
 build_new_method_call (tree instance, tree fns, VEC(tree,gc) **args,
 		       tree conversion_path, int flags,
-		       tree *fn_p, tsubst_flags_t complain)
+		       tree *fn_p, tsubst_flags_t complain, location_t loc)
 {
   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, loc);
   timevar_cond_stop (TV_OVERLOAD, subtime);
   return ret;
 }
@@ -8562,6 +8566,7 @@ tree
 perform_implicit_conversion_flags (tree type, tree expr,
 				   tsubst_flags_t complain, int flags)
 {
+  tree result = expr;
   conversion *conv;
   void *p;
   location_t loc = EXPR_LOC_OR_HERE (expr);
@@ -8605,6 +8610,9 @@ perform_implicit_conversion_flags (tree
     }
   else
     expr = convert_like (conv, expr, complain);
+  
+  if (expr != error_mark_node)
+    duplicate_expr_locations (expr, result);
 
   /* Free all the conversions we allocated.  */
   obstack_free (&conversion_obstack, p);
Index: cp/method.c
===================================================================
--- cp/method.c	(revision 190939)
+++ cp/method.c	(working copy)
@@ -837,7 +837,8 @@ locate_fn_flags (tree type, tree name, t
     }
 
   fns = lookup_fnfields (binfo, name, 0);
-  rval = build_new_method_call (ob, fns, &args, binfo, flags, &fn, complain);
+  rval = build_new_method_call (ob, fns, &args, binfo, flags, &fn, complain,
+				input_location);
 
   release_tree_vector (args);
   if (fn && rval == error_mark_node)
Index: cp/class.c
===================================================================
--- cp/class.c	(revision 190939)
+++ cp/class.c	(working copy)
@@ -7355,6 +7355,9 @@ build_self_reference (void)
   DECL_CONTEXT (value) = current_class_type;
   DECL_ARTIFICIAL (value) = 1;
   SET_DECL_SELF_REFERENCE_P (value);
+  DECL_SOURCE_LOCATION (value) =
+    DECL_SOURCE_LOCATION (TYPE_NAME (current_class_type));
+
   set_underlying_type (value);
 
   if (processing_template_decl)
Index: cp/pt.c
===================================================================
--- cp/pt.c	(revision 190939)
+++ cp/pt.c	(working copy)
@@ -13788,20 +13788,20 @@ tsubst_copy_and_build (tree t,
 	      ret = finish_call_expr (function, &call_args,
 				       /*disallow_virtual=*/false,
 				       /*koenig_p=*/false,
-				       complain);
+				       complain, input_location);
 	    else
 	      ret = (build_new_method_call
 		      (instance, fn,
 		       &call_args, NULL_TREE,
 		       qualified_p ? LOOKUP_NONVIRTUAL : LOOKUP_NORMAL,
 		       /*fn_p=*/NULL,
-		       complain));
+		       complain, input_location));
 	  }
 	else
 	  ret = finish_call_expr (function, &call_args,
 				  /*disallow_virtual=*/qualified_p,
 				  koenig_p,
-				  complain);
+				  complain, input_location);
 
 	release_tree_vector (call_args);
 
Index: cp/parser.c
===================================================================
--- cp/parser.c	(revision 190939)
+++ cp/parser.c	(working copy)
@@ -1787,7 +1787,7 @@ static bool cp_parser_translation_unit
 static tree cp_parser_primary_expression
   (cp_parser *, bool, bool, bool, cp_id_kind *);
 static tree cp_parser_id_expression
-  (cp_parser *, bool, bool, bool *, bool, bool);
+  (cp_parser *, bool, bool, bool *, bool, bool, location_t *);
 static tree cp_parser_unqualified_id
   (cp_parser *, bool, bool, bool, bool);
 static tree cp_parser_nested_name_specifier_opt
@@ -1803,7 +1803,7 @@ static tree cp_parser_postfix_open_squar
 static tree cp_parser_postfix_dot_deref_expression
   (cp_parser *, enum cpp_ttype, tree, bool, cp_id_kind *, location_t);
 static VEC(tree,gc) *cp_parser_parenthesized_expression_list
-  (cp_parser *, int, bool, bool, bool *);
+  (cp_parser *, int, bool, bool, bool *, location_t *, int *);
 /* 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
@@ -1831,7 +1831,7 @@ static tree cp_parser_cast_expression
 static tree cp_parser_binary_expression
   (cp_parser *, bool, bool, enum cp_parser_prec, cp_id_kind *);
 static tree cp_parser_question_colon_clause
-  (cp_parser *, tree);
+  (cp_parser *, tree, location_t);
 static tree cp_parser_assignment_expression
   (cp_parser *, bool, cp_id_kind *);
 static enum tree_code cp_parser_assignment_operator_opt
@@ -1968,7 +1968,7 @@ static cp_virt_specifiers cp_parser_virt
 static tree cp_parser_late_return_type_opt
   (cp_parser *, cp_cv_quals);
 static tree cp_parser_declarator_id
-  (cp_parser *, bool);
+  (cp_parser *, bool, location_t *);
 static tree cp_parser_type_id
   (cp_parser *);
 static tree cp_parser_template_type_arg
@@ -2844,7 +2844,8 @@ cp_parser_parse_and_diagnose_invalid_typ
 				/*check_dependency_p=*/true,
 				/*template_p=*/NULL,
 				/*declarator_p=*/true,
-				/*optional_p=*/false);
+				/*optional_p=*/false,
+				/*loc=*/NULL);
   /* If the next token is a (, this is a function with no explicit return
      type, i.e. constructor, destructor or conversion op.  */
   if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)
@@ -3583,7 +3584,8 @@ cp_parser_userdef_char_literal (cp_parse
       release_tree_vector (args);
       return error_mark_node;
     }
-  result = finish_call_expr (decl, &args, false, true, tf_warning_or_error);
+  result = finish_call_expr
+	     (decl, &args, false, true, tf_warning_or_error, token->location);
   release_tree_vector (args);
   if (result != error_mark_node)
     return result;
@@ -3641,7 +3643,8 @@ cp_parser_userdef_numeric_literal (cp_pa
   decl = lookup_literal_operator (name, args);
   if (decl && decl != error_mark_node)
     {
-      result = finish_call_expr (decl, &args, false, true, tf_none);
+      result = finish_call_expr
+		 (decl, &args, false, true, tf_none, token->location);
       if (result != error_mark_node)
 	{
 	  release_tree_vector (args);
@@ -3658,7 +3661,8 @@ cp_parser_userdef_numeric_literal (cp_pa
   decl = lookup_literal_operator (name, args);
   if (decl && decl != error_mark_node)
     {
-      result = finish_call_expr (decl, &args, false, true, tf_none);
+      result = finish_call_expr
+		 (decl, &args, false, true, tf_none, token->location);
       if (result != error_mark_node)
 	{
 	  release_tree_vector (args);
@@ -3676,7 +3680,8 @@ cp_parser_userdef_numeric_literal (cp_pa
     {
       tree tmpl_args = make_char_string_pack (num_string);
       decl = lookup_template_function (decl, tmpl_args);
-      result = finish_call_expr (decl, &args, false, true, tf_none);
+      result = finish_call_expr
+		 (decl, &args, false, true, tf_none, token->location);
       if (result != error_mark_node)
 	{
 	  release_tree_vector (args);
@@ -3716,7 +3721,7 @@ cp_parser_userdef_string_literal (cp_tok
       release_tree_vector (args);
       return error_mark_node;
     }
-  result = finish_call_expr (decl, &args, false, true, tf_none);
+  result = finish_call_expr (decl, &args, false, true, tf_none, token->location);
   release_tree_vector (args);
   if (result != error_mark_node)
     return result;
@@ -4226,7 +4231,8 @@ cp_parser_primary_expression (cp_parser
 				     /*check_dependency_p=*/true,
 				     &template_p,
 				     /*declarator_p=*/false,
-				     /*optional_p=*/false);
+				     /*optional_p=*/false,
+				     /*loc=*/NULL);
 	if (id_expression == error_mark_node)
 	  return error_mark_node;
 	id_expr_token = token;
@@ -4389,7 +4395,10 @@ cp_parser_primary_expression (cp_parser
    named is a template.
 
    If DECLARATOR_P is true, the id-expression is appearing as part of
-   a declarator, rather than as part of an expression.  */
+   a declarator, rather than as part of an expression.
+
+   If LOC is non-NULL and a qualified-id is found, LOC is set to the location
+   of the unqualified-id.  */
 
 static tree
 cp_parser_id_expression (cp_parser *parser,
@@ -4397,7 +4406,8 @@ cp_parser_id_expression (cp_parser *pars
 			 bool check_dependency_p,
 			 bool *template_p,
 			 bool declarator_p,
-			 bool optional_p)
+			 bool optional_p,
+			 location_t *loc)
 {
   bool global_scope_p;
   bool nested_name_specifier_p;
@@ -4437,6 +4447,10 @@ cp_parser_id_expression (cp_parser *pars
       saved_scope = parser->scope;
       saved_object_scope = parser->object_scope;
       saved_qualifying_scope = parser->qualifying_scope;
+
+      if (loc)
+	*loc = cp_lexer_peek_token (parser->lexer)->location;
+
       /* Process the final unqualified-id.  */
       unqualified_id = cp_parser_unqualified_id (parser, *template_p,
 						 check_dependency_p,
@@ -4459,6 +4473,9 @@ cp_parser_id_expression (cp_parser *pars
       /* Peek at the next token.  */
       token = cp_lexer_peek_token (parser->lexer);
 
+      if (loc)
+	*loc = token->location;
+
       /* If it's an identifier, and the next token is not a "<", then
 	 we can avoid the template-id case.  This is an optimization
 	 for this common case.  */
@@ -4498,10 +4515,15 @@ cp_parser_id_expression (cp_parser *pars
 	}
     }
   else
-    return cp_parser_unqualified_id (parser, template_keyword_p,
-				     /*check_dependency_p=*/true,
-				     declarator_p,
-				     optional_p);
+    {
+      if (loc)
+	*loc = cp_lexer_peek_token (parser->lexer)->location;
+
+      return cp_parser_unqualified_id (parser, template_keyword_p,
+				       /*check_dependency_p=*/true,
+				       declarator_p,
+				       optional_p);
+    }
 }
 
 /* Parse an unqualified-id.
@@ -5326,6 +5348,7 @@ cp_parser_postfix_expression (cp_parser
   cp_id_kind idk = CP_ID_KIND_NONE;
   tree postfix_expression = NULL_TREE;
   bool is_member_access = false;
+  location_t locs[64], member_loc = UNKNOWN_LOCATION;
 
   /* Peek at the next token.  */
   token = cp_lexer_peek_token (parser->lexer);
@@ -5468,7 +5491,8 @@ cp_parser_postfix_expression (cp_parser
 	cp_lexer_consume_token (parser->lexer);
 	vec = cp_parser_parenthesized_expression_list (parser, non_attr,
 		    /*cast_p=*/false, /*allow_expansion_p=*/true,
-		    /*non_constant_p=*/NULL);
+		    /*non_constant_p=*/NULL,
+		    /*locs=*/NULL, /*num_locs=*/NULL);
 	if (vec == NULL)
 	  return error_mark_node;
 
@@ -5603,6 +5627,7 @@ cp_parser_postfix_expression (cp_parser
 	  = unqualified_name_lookup_error (postfix_expression);
 
       /* Peek at the next token.  */
+      locs[0] = token->location;
       token = cp_lexer_peek_token (parser->lexer);
 
       switch (token->type)
@@ -5624,6 +5649,7 @@ cp_parser_postfix_expression (cp_parser
 	    bool saved_integral_constant_expression_p = false;
 	    bool saved_non_integral_constant_expression_p = false;
 	    VEC(tree,gc) *args;
+	    int num_locs = 63;
 
             is_member_access = false;
 
@@ -5642,7 +5668,7 @@ cp_parser_postfix_expression (cp_parser
 	    args = (cp_parser_parenthesized_expression_list
 		    (parser, non_attr,
 		     /*cast_p=*/false, /*allow_expansion_p=*/true,
-		     /*non_constant_p=*/NULL));
+		     /*non_constant_p=*/NULL, &locs[1], &num_locs));
 	    if (is_builtin_constant_p)
 	      {
 		parser->integral_constant_expression_p
@@ -5717,6 +5743,11 @@ cp_parser_postfix_expression (cp_parser
 		tree instance = TREE_OPERAND (postfix_expression, 0);
 		tree fn = TREE_OPERAND (postfix_expression, 1);
 
+		if (member_loc == UNKNOWN_LOCATION)
+		  member_loc = locs[0];
+		else
+		  locs[0] = member_loc;
+
 		if (processing_template_decl
 		    && (type_dependent_expression_p (instance)
 			|| (!BASELINK_P (fn)
@@ -5739,14 +5770,14 @@ cp_parser_postfix_expression (cp_parser
 			 ? LOOKUP_NORMAL|LOOKUP_NONVIRTUAL
 			 : LOOKUP_NORMAL),
 			/*fn_p=*/NULL,
-			tf_warning_or_error));
+			tf_warning_or_error, member_loc));
 		  }
 		else
 		  postfix_expression
 		    = finish_call_expr (postfix_expression, &args,
 					/*disallow_virtual=*/false,
 					/*koenig_p=*/false,
-					tf_warning_or_error);
+					tf_warning_or_error, member_loc);
 	      }
 	    else if (TREE_CODE (postfix_expression) == OFFSET_REF
 		     || TREE_CODE (postfix_expression) == MEMBER_REF
@@ -5760,14 +5791,15 @@ cp_parser_postfix_expression (cp_parser
 		= finish_call_expr (postfix_expression, &args,
 				    /*disallow_virtual=*/true,
 				    koenig_p,
-				    tf_warning_or_error);
+				    tf_warning_or_error, locs[0]);
 	    else
 	      /* All other function calls.  */
 	      postfix_expression
 		= finish_call_expr (postfix_expression, &args,
 				    /*disallow_virtual=*/false,
 				    koenig_p,
-				    tf_warning_or_error);
+				    tf_warning_or_error, locs[0]);
+	    SET_EXPR_LOCATIONS (postfix_expression, locs, num_locs+1);
 
 	    /* The POSTFIX_EXPRESSION is certainly no longer an id.  */
 	    idk = CP_ID_KIND_NONE;
@@ -5785,6 +5817,7 @@ cp_parser_postfix_expression (cp_parser
 
 	  /* Consume the `.' or `->' operator.  */
 	  cp_lexer_consume_token (parser->lexer);
+	  member_loc = locs[1] = cp_lexer_peek_token (parser->lexer)->location;
 
 	  postfix_expression
 	    = cp_parser_postfix_dot_deref_expression (parser, token->type,
@@ -5792,6 +5825,8 @@ cp_parser_postfix_expression (cp_parser
 						      false, &idk,
 						      token->location);
 
+	  protected_set_expr_location (postfix_expression, token->location);
+	  SET_EXPR_LOCATIONS (postfix_expression, locs, 2);
           is_member_access = true;
 	  break;
 
@@ -5799,6 +5834,7 @@ cp_parser_postfix_expression (cp_parser
 	  /* postfix-expression ++  */
 	  /* Consume the `++' token.  */
 	  cp_lexer_consume_token (parser->lexer);
+	  locs[1] = locs [0];
 	  /* Generate a representation for the complete expression.  */
 	  postfix_expression
 	    = finish_increment_expr (postfix_expression,
@@ -5806,6 +5842,11 @@ cp_parser_postfix_expression (cp_parser
 	  /* Increments may not appear in constant-expressions.  */
 	  if (cp_parser_non_integral_constant_expression (parser, NIC_INC))
 	    postfix_expression = error_mark_node;
+	  else
+	    {
+	      protected_set_expr_location (postfix_expression, token->location);
+	      SET_EXPR_LOCATIONS (postfix_expression, locs, 2);
+	    }
 	  idk = CP_ID_KIND_NONE;
           is_member_access = false;
 	  break;
@@ -5814,6 +5855,7 @@ cp_parser_postfix_expression (cp_parser
 	  /* postfix-expression -- */
 	  /* Consume the `--' token.  */
 	  cp_lexer_consume_token (parser->lexer);
+	  locs[1] = locs [0];
 	  /* Generate a representation for the complete expression.  */
 	  postfix_expression
 	    = finish_increment_expr (postfix_expression,
@@ -5821,6 +5863,11 @@ cp_parser_postfix_expression (cp_parser
 	  /* Decrements may not appear in constant-expressions.  */
 	  if (cp_parser_non_integral_constant_expression (parser, NIC_DEC))
 	    postfix_expression = error_mark_node;
+	  else
+	    {
+	      protected_set_expr_location (postfix_expression, token->location);
+	      SET_EXPR_LOCATIONS (postfix_expression, locs, 2);
+	    }
 	  idk = CP_ID_KIND_NONE;
           is_member_access = false;
 	  break;
@@ -5855,10 +5902,13 @@ cp_parser_postfix_open_square_expression
 					  bool for_offsetof)
 {
   tree index;
+  location_t locs[2];
   location_t loc = cp_lexer_peek_token (parser->lexer)->location;
 
+  locs[0] = input_location;
   /* Consume the `[' token.  */
   cp_lexer_consume_token (parser->lexer);
+  locs[1] = cp_lexer_peek_token (parser->lexer)->location;
 
   /* Parse the index expression.  */
   /* ??? For offsetof, there is a question of what to allow here.  If
@@ -5893,6 +5943,10 @@ cp_parser_postfix_open_square_expression
   if (!for_offsetof
       && (cp_parser_non_integral_constant_expression (parser, NIC_ARRAY_REF)))
     postfix_expression = error_mark_node;
+  else if (TREE_CODE (postfix_expression) == INDIRECT_REF)
+    SET_EXPR_LOCATIONS (TREE_OPERAND (postfix_expression, 0), locs, 2);
+  else
+    SET_EXPR_LOCATIONS (postfix_expression, locs, 2);
 
   return postfix_expression;
 }
@@ -6018,7 +6072,8 @@ cp_parser_postfix_dot_deref_expression (
 	       /*check_dependency_p=*/true,
 	       &template_p,
 	       /*declarator_p=*/false,
-	       /*optional_p=*/false));
+	       /*optional_p=*/false,
+	       /*loc=*/NULL));
       /* In general, build a SCOPE_REF if the member name is qualified.
 	 However, if the name was not dependent and has already been
 	 resolved; there is no need to build the SCOPE_REF.  For example;
@@ -6115,12 +6170,14 @@ cp_parser_parenthesized_expression_list
 					 int is_attribute_list,
 					 bool cast_p,
                                          bool allow_expansion_p,
-					 bool *non_constant_p)
+					 bool *non_constant_p,
+					 location_t *locs, int *num_locs)
 {
   VEC(tree,gc) *expression_list;
   bool fold_expr_p = is_attribute_list != non_attr;
   tree identifier = NULL_TREE;
   bool saved_greater_than_is_operator_p;
+  int i = 0;
 
   /* Assume all the expressions will be constant.  */
   if (non_constant_p)
@@ -6143,6 +6200,9 @@ cp_parser_parenthesized_expression_list
       {
 	tree expr;
 
+	if (locs && i < *num_locs)
+	  locs[i++] = cp_lexer_peek_token (parser->lexer)->location;
+
 	/* At the beginning of attribute lists, check to see if the
 	   next token is an identifier.  */
 	if (is_attribute_list == id_attr
@@ -6238,6 +6298,9 @@ cp_parser_parenthesized_expression_list
 	}
     }
 
+  if (locs)
+    *num_locs = i;
+
   parser->greater_than_is_operator_p
     = saved_greater_than_is_operator_p;
 
@@ -6540,9 +6603,11 @@ cp_parser_unary_expression (cp_parser *p
 	  tree identifier;
 	  tree expression;
 	  location_t loc = token->location;
+	  location_t loc2;
 
 	  /* Consume the '&&' token.  */
 	  cp_lexer_consume_token (parser->lexer);
+	  loc2 = cp_lexer_peek_token (parser->lexer)->location;
 	  /* Look for the identifier.  */
 	  identifier = cp_parser_identifier (parser);
 	  /* Create an expression representing the address.  */
@@ -6550,6 +6615,8 @@ cp_parser_unary_expression (cp_parser *p
 	  if (cp_parser_non_integral_constant_expression (parser,
 							  NIC_ADDR_LABEL))
 	    expression = error_mark_node;
+	  else
+	    SET_EXPR_LOCATION2 (expression, loc2);
 	  return expression;
 	}
     }
@@ -6559,9 +6626,11 @@ cp_parser_unary_expression (cp_parser *p
       tree expression = error_mark_node;
       non_integral_constant non_constant_p = NIC_NONE;
       location_t loc = token->location;
+      location_t loc2;
 
       /* Consume the operator token.  */
       token = cp_lexer_consume_token (parser->lexer);
+      loc2 = cp_lexer_peek_token (parser->lexer)->location;
       /* Parse the cast-expression.  */
       cast_expression
 	= cp_parser_cast_expression (parser,
@@ -6606,6 +6675,8 @@ cp_parser_unary_expression (cp_parser *p
 	  && cp_parser_non_integral_constant_expression (parser,
 							 non_constant_p))
 	expression = error_mark_node;
+      else
+	SET_EXPR_LOCATION2 (expression, loc2);
 
       return expression;
     }
@@ -6761,7 +6832,7 @@ cp_parser_new_placement (cp_parser* pars
   expression_list = (cp_parser_parenthesized_expression_list
 		     (parser, non_attr, /*cast_p=*/false,
 		      /*allow_expansion_p=*/true,
-		      /*non_constant_p=*/NULL));
+		      /*non_constant_p=*/NULL, /*locs=*/NULL, /*num_locs=*/NULL));
 
   return expression_list;
 }
@@ -6963,7 +7034,7 @@ cp_parser_new_initializer (cp_parser* pa
     expression_list = (cp_parser_parenthesized_expression_list
 		       (parser, non_attr, /*cast_p=*/false,
 			/*allow_expansion_p=*/true,
-			/*non_constant_p=*/NULL));
+			/*non_constant_p=*/NULL, /*locs=*/NULL, /*num_locs=*/NULL));
 
   return expression_list;
 }
@@ -7281,10 +7352,14 @@ cp_parser_binary_expression (cp_parser*
   enum tree_code rhs_type;
   enum cp_parser_prec new_prec, lookahead_prec;
   tree overload;
+  location_t locs[2];
 
   /* Parse the first expression.  */
+  locs[0] = cp_lexer_peek_token (parser->lexer)->location;
   current.lhs = cp_parser_cast_expression (parser, /*address_p=*/false,
 					   cast_p, pidk);
+  if (EXPR_P (current.lhs))
+    locs[0] = EXPR_LOCATION (current.lhs);
   current.lhs_type = ERROR_MARK;
   current.prec = prec;
 
@@ -7340,6 +7415,7 @@ cp_parser_binary_expression (cp_parser*
 
       /* Extract another operand.  It may be the RHS of this expression
 	 or the LHS of a new, higher priority expression.  */
+      locs[1] = cp_lexer_peek_token (parser->lexer)->location;
       rhs = cp_parser_simple_cast_expression (parser);
       rhs_type = ERROR_MARK;
 
@@ -7359,6 +7435,8 @@ cp_parser_binary_expression (cp_parser*
 	  current.lhs = rhs;
 	  current.lhs_type = rhs_type;
 	  current.prec = new_prec;
+	  current.loc = locs[0];
+	  locs[0] = locs[1];
 	  new_prec = lookahead_prec;
 	  goto get_rhs;
 
@@ -7375,6 +7453,8 @@ cp_parser_binary_expression (cp_parser*
 	  rhs_type = current.lhs_type;
 	  --sp;
 	  current = *sp;
+	  locs[1] = locs[0];
+	  locs[0] = sp->loc;
 	}
 
       /* Undo the disabling of warnings done above.  */
@@ -7402,6 +7482,7 @@ cp_parser_binary_expression (cp_parser*
 					 current.lhs, current.lhs_type,
 					 rhs, rhs_type, &overload,
 					 tf_warning_or_error);
+      SET_EXPR_LOCATIONS (current.lhs, locs, 2);
       current.lhs_type = current.tree_type;
 
       /* If the binary operator required the use of an overloaded operator,
@@ -7423,6 +7504,7 @@ cp_parser_binary_expression (cp_parser*
 /* Parse the `? expression : assignment-expression' part of a
    conditional-expression.  The LOGICAL_OR_EXPR is the
    logical-or-expression that started the conditional-expression.
+   LHS_LOC is the location of the lhs.
    Returns a representation of the entire conditional-expression.
 
    This routine is used by cp_parser_assignment_expression.
@@ -7434,13 +7516,24 @@ cp_parser_binary_expression (cp_parser*
      ? : assignment-expression */
 
 static tree
-cp_parser_question_colon_clause (cp_parser* parser, tree logical_or_expr)
+cp_parser_question_colon_clause (cp_parser* parser,
+				 tree logical_or_expr,
+				 location_t lhs_loc)
 {
   tree expr;
   tree assignment_expr;
+  tree result;
+  /* locations of the conditional expression:
+     locs[0] == location of ?
+     locs[1] == location of lhs
+     locs[2] == location of expression
+     locs[3] == location of assignment-expression.  */
+  location_t locs[4];
   struct cp_token *token;
   location_t loc = cp_lexer_peek_token (parser->lexer)->location;
 
+  locs[0] = cp_lexer_peek_token (parser->lexer)->location;
+  locs[1] = lhs_loc;
   /* Consume the `?' token.  */
   cp_lexer_consume_token (parser->lexer);
   token = cp_lexer_peek_token (parser->lexer);
@@ -7451,6 +7544,7 @@ cp_parser_question_colon_clause (cp_pars
                "ISO C++ does not allow ?: with omitted middle operand");
       /* Implicit true clause.  */
       expr = NULL_TREE;
+      locs[2] = UNKNOWN_LOCATION;
       c_inhibit_evaluation_warnings += logical_or_expr == truthvalue_true_node;
       warn_for_omitted_condop (token->location, logical_or_expr);
     }
@@ -7458,6 +7552,7 @@ cp_parser_question_colon_clause (cp_pars
     {
       bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
       parser->colon_corrects_to_scope_p = false;
+      locs[2] = cp_lexer_peek_token (parser->lexer)->location;
       /* Parse the expression.  */
       c_inhibit_evaluation_warnings += logical_or_expr == truthvalue_false_node;
       expr = cp_parser_expression (parser, /*cast_p=*/false, NULL);
@@ -7469,15 +7564,19 @@ cp_parser_question_colon_clause (cp_pars
 
   /* The next token should be a `:'.  */
   cp_parser_require (parser, CPP_COLON, RT_COLON);
+  locs[3] = cp_lexer_peek_token (parser->lexer)->location;
   /* Parse the assignment-expression.  */
   assignment_expr = cp_parser_assignment_expression (parser, /*cast_p=*/false, NULL);
   c_inhibit_evaluation_warnings -= logical_or_expr == truthvalue_true_node;
 
   /* Build the conditional-expression.  */
-  return build_x_conditional_expr (loc, logical_or_expr,
-				   expr,
-				   assignment_expr,
-                                   tf_warning_or_error);
+  result = build_x_conditional_expr (loc, logical_or_expr,
+				     expr,
+				     assignment_expr,
+                                     tf_warning_or_error);
+  protected_set_expr_location (result, locs[0]);
+  SET_EXPR_LOCATIONS (result, &locs[1], 3);
+  return result;
 }
 
 /* Parse an assignment-expression.
@@ -7496,6 +7595,12 @@ cp_parser_assignment_expression (cp_pars
 				 cp_id_kind * pidk)
 {
   tree expr;
+  /* extra locations of the assignment expression:
+     locs[0] == location of lhs
+     locs[1] == location of rhs.  */
+  location_t locs[2];
+
+  locs[0] = cp_lexer_peek_token (parser->lexer)->location;
 
   /* If the next token is the `throw' keyword, then we're looking at
      a throw-expression.  */
@@ -7511,7 +7616,7 @@ cp_parser_assignment_expression (cp_pars
       /* If the next token is a `?' then we're actually looking at a
 	 conditional-expression.  */
       if (cp_lexer_next_token_is (parser->lexer, CPP_QUERY))
-	return cp_parser_question_colon_clause (parser, expr);
+	return cp_parser_question_colon_clause (parser, expr, locs[0]);
       else
 	{
 	  location_t loc = cp_lexer_peek_token (parser->lexer)->location;
@@ -7524,9 +7629,11 @@ cp_parser_assignment_expression (cp_pars
 	    {
 	      bool non_constant_p;
 	      location_t saved_input_location;
+	      tree rhs;
 
 	      /* Parse the right-hand side of the assignment.  */
-	      tree rhs = cp_parser_initializer_clause (parser, &non_constant_p);
+	      locs[1] = cp_lexer_peek_token (parser->lexer)->location;
+	      rhs = cp_parser_initializer_clause (parser, &non_constant_p);
 
 	      if (BRACE_ENCLOSED_INITIALIZER_P (rhs))
 		maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS);
@@ -7545,6 +7652,7 @@ cp_parser_assignment_expression (cp_pars
 					  rhs,
 					  tf_warning_or_error);
 	      input_location = saved_input_location;
+	      SET_EXPR_LOCATIONS (expr, locs, 2);
 	    }
 	}
     }
@@ -9609,12 +9717,12 @@ cp_parser_perform_range_for_lookup (tree
 						/*include_std=*/true,
 						tf_warning_or_error);
 	  *begin = finish_call_expr (member_begin, &vec, false, true,
-				     tf_warning_or_error);
+				     tf_warning_or_error, input_location);
 	  member_end = perform_koenig_lookup (id_end, vec,
 					      /*include_std=*/true,
 					      tf_warning_or_error);
 	  *end = finish_call_expr (member_end, &vec, false, true,
-				   tf_warning_or_error);
+				   tf_warning_or_error, input_location);
 
 	  release_tree_vector (vec);
 	}
@@ -9658,7 +9766,7 @@ cp_parser_range_for_member_function (tre
   res = finish_call_expr (member, &vec,
 			  /*disallow_virtual=*/false,
 			  /*koenig_p=*/false,
-			  tf_warning_or_error);
+			  tf_warning_or_error, input_location);
   release_tree_vector (vec);
   return res;
 }
@@ -11067,7 +11175,8 @@ cp_parser_decltype (cp_parser *parser)
                                   /*check_dependency_p=*/true,
                                   /*template_p=*/NULL,
                                   /*declarator_p=*/false,
-                                  /*optional_p=*/false);
+                                  /*optional_p=*/false,
+				  /*loc=*/NULL);
 
   if (!cp_parser_error_occurred (parser) && expr != error_mark_node)
     {
@@ -11513,7 +11622,9 @@ cp_parser_mem_initializer (cp_parser* pa
       vec = cp_parser_parenthesized_expression_list (parser, non_attr,
 						     /*cast_p=*/false,
 						     /*allow_expansion_p=*/true,
-						     /*non_constant_p=*/NULL);
+						     /*non_constant_p=*/NULL,
+						     /*locs=*/NULL,
+						     /*num_locs=*/NULL);
       if (vec == NULL)
 	return error_mark_node;
       expression_list = build_tree_list_vec (vec);
@@ -12315,7 +12426,8 @@ cp_parser_type_parameter (cp_parser* par
 					 /*check_dependency_p=*/true,
 					 /*template_p=*/&is_template,
 					 /*declarator_p=*/false,
-					 /*optional_p=*/false);
+					 /*optional_p=*/false,
+					 /*loc=*/NULL);
 	    if (TREE_CODE (default_argument) == TYPE_DECL)
 	      /* If the id-expression was a template-id that refers to
 		 a template-class, we already have the declaration here,
@@ -12943,7 +13055,8 @@ cp_parser_template_argument (cp_parser*
 				      /*check_dependency_p=*/true,
 				      &template_p,
 				      /*declarator_p=*/false,
-				      /*optional_p=*/false);
+				      /*optional_p=*/false,
+				      /*loc=*/NULL);
   /* If the next token isn't a `,' or a `>', then this argument wasn't
      really finished.  */
   if (!cp_parser_next_token_ends_template_argument_p (parser))
@@ -16245,6 +16358,7 @@ cp_parser_direct_declarator (cp_parser*
 	    bool abstract_ok;
 	    bool pack_expansion_p = false;
 	    cp_token *declarator_id_start_token;
+	    location_t loc;
 
 	    /* Parse a declarator-id */
 	    abstract_ok = (dcl_kind == CP_PARSER_DECLARATOR_EITHER);
@@ -16265,7 +16379,8 @@ cp_parser_direct_declarator (cp_parser*
 
 	    declarator_id_start_token = cp_lexer_peek_token (parser->lexer);
 	    unqualified_name
-	      = cp_parser_declarator_id (parser, /*optional_p=*/abstract_ok);
+	      = cp_parser_declarator_id (parser, /*optional_p=*/abstract_ok,
+					 &loc);
 	    qualifying_scope = parser->scope;
 	    if (abstract_ok)
 	      {
@@ -16421,7 +16536,7 @@ cp_parser_direct_declarator (cp_parser*
 	    declarator = make_id_declarator (qualifying_scope,
 					     unqualified_name,
 					     sfk);
-	    declarator->id_loc = token->location;
+	    declarator->id_loc = loc;
 	    declarator->parameter_pack_p = pack_expansion_p;
 
 	    if (pack_expansion_p)
@@ -16772,10 +16887,12 @@ cp_parser_late_return_type_opt (cp_parse
    If the id-expression was a qualified-id, then a SCOPE_REF is
    returned.  The first operand is the scope (either a NAMESPACE_DECL
    or TREE_TYPE), but the second is still just a representation of an
-   unqualified-id.  */
+   unqualified-id.
+
+   if LOC is not-NULL, it is set to the location of the unqualified-id.  */
 
 static tree
-cp_parser_declarator_id (cp_parser* parser, bool optional_p)
+cp_parser_declarator_id (cp_parser* parser, bool optional_p, location_t *loc)
 {
   tree id;
   /* The expression must be an id-expression.  Assume that qualified
@@ -16797,7 +16914,8 @@ cp_parser_declarator_id (cp_parser* pars
 				/*check_dependency_p=*/false,
 				/*template_p=*/NULL,
 				/*declarator_p=*/true,
-				optional_p);
+				optional_p,
+				loc);
   if (id && BASELINK_P (id))
     id = BASELINK_FUNCTIONS (id);
   return id;
@@ -17548,7 +17666,9 @@ cp_parser_initializer (cp_parser* parser
       vec = cp_parser_parenthesized_expression_list (parser, non_attr,
 						     /*cast_p=*/false,
 						     /*allow_expansion_p=*/true,
-						     non_constant_p);
+						     non_constant_p,
+						     /*locs=*/NULL,
+						     /*num_locs=*/NULL);
       if (vec == NULL)
 	return error_mark_node;
       init = build_tree_list_vec (vec);
@@ -20223,7 +20343,7 @@ cp_parser_attribute_list (cp_parser* par
 	      vec = cp_parser_parenthesized_expression_list
 		    (parser, attr_flag, /*cast_p=*/false,
 		     /*allow_expansion_p=*/false,
-		     /*non_constant_p=*/NULL);
+		     /*non_constant_p=*/NULL, /*locs=*/NULL, /*num_locs=*/NULL);
 	      if (vec == NULL)
 		arguments = error_mark_node;
 	      else
@@ -21489,7 +21609,9 @@ cp_parser_functional_cast (cp_parser* pa
   vec = cp_parser_parenthesized_expression_list (parser, non_attr,
 						 /*cast_p=*/true,
 						 /*allow_expansion_p=*/true,
-						 /*non_constant_p=*/NULL);
+						 /*non_constant_p=*/NULL,
+						 /*locs=*/NULL,
+						 /*num_locs=*/NULL);
   if (vec == NULL)
     expression_list = error_mark_node;
   else
@@ -25145,7 +25267,8 @@ cp_parser_omp_var_list_no_open (cp_parse
 				      /*check_dependency_p=*/true,
 				      /*template_p=*/NULL,
 				      /*declarator_p=*/false,
-				      /*optional_p=*/false);
+				      /*optional_p=*/false,
+				      /*loc=*/NULL);
       if (name == error_mark_node)
 	goto skip_comma;
 
Index: cp/init.c
===================================================================
--- cp/init.c	(revision 190939)
+++ cp/init.c	(working copy)
@@ -2482,7 +2482,7 @@ build_new_1 (VEC(tree,gc) **placement, t
 					      /*conversion_path=*/NULL_TREE,
 					      LOOKUP_NORMAL,
 					      &alloc_fn,
-					      complain);
+					      complain, input_location);
 	}
       else
 	{
@@ -3693,7 +3693,7 @@ build_dtor_call (tree exp, special_funct
 				/*conversion_path=*/NULL_TREE,
 				flags,
 				/*fn_p=*/NULL,
-				complain);
+				complain, input_location);
 }
 
 /* Generate a call to a destructor. TYPE is the type to cast ADDR to.
Index: cp/cp-tree.h
===================================================================
--- cp/cp-tree.h	(revision 190939)
+++ cp/cp-tree.h	(working copy)
@@ -4890,7 +4890,7 @@ extern tree build_operator_new_call		(tr
 						 tsubst_flags_t);
 extern tree build_new_method_call		(tree, tree, VEC(tree,gc) **,
 						 tree, int, tree *,
-						 tsubst_flags_t);
+						 tsubst_flags_t, location_t);
 extern tree build_special_member_call		(tree, tree, VEC(tree,gc) **,
 						 tree, int, tsubst_flags_t);
 extern tree build_new_op			(location_t, enum tree_code,
@@ -5594,7 +5594,8 @@ bool empty_expr_stmt_p				(tree);
 extern tree perform_koenig_lookup		(tree, VEC(tree,gc) *, bool,
 						 tsubst_flags_t);
 extern tree finish_call_expr			(tree, VEC(tree,gc) **, bool,
-						 bool, tsubst_flags_t);
+						 bool, tsubst_flags_t,
+						 location_t);
 extern tree finish_increment_expr		(tree, enum tree_code);
 extern tree finish_this_expr			(void);
 extern tree finish_pseudo_destructor_expr       (tree, tree, tree);
Index: cp/semantics.c
===================================================================
--- cp/semantics.c	(revision 190939)
+++ cp/semantics.c	(working copy)
@@ -2047,7 +2047,7 @@ perform_koenig_lookup (tree fn, VEC(tree
 
 tree
 finish_call_expr (tree fn, VEC(tree,gc) **args, bool disallow_virtual,
-		  bool koenig_p, tsubst_flags_t complain)
+		  bool koenig_p, tsubst_flags_t complain, location_t loc)
 {
   tree result;
   tree orig_fn;
@@ -2117,7 +2117,7 @@ finish_call_expr (tree fn, VEC(tree,gc)
                                          ? LOOKUP_NORMAL | LOOKUP_NONVIRTUAL
 					 : LOOKUP_NORMAL),
 					/*fn_p=*/NULL,
-					complain);
+					complain, loc);
 	}
     }
 
@@ -2167,7 +2167,7 @@ finish_call_expr (tree fn, VEC(tree,gc)
 				       ? LOOKUP_NORMAL|LOOKUP_NONVIRTUAL
 				       : LOOKUP_NORMAL),
 				      /*fn_p=*/NULL,
-				      complain);
+				      complain, loc);
     }
   else if (is_overloaded_fn (fn))
     {
@@ -3211,6 +3211,8 @@ finish_id_expression (tree id_expression
 	      decl = finish_non_static_data_member
 		       (decl, NULL_TREE,
 			/*qualifying_scope=*/NULL_TREE);
+	      if (EXPR_P (decl))
+		SET_EXPR_LOCATION (decl, location);
 	      pop_deferring_access_checks ();
 	      return decl;
 	    }
@@ -3288,6 +3290,8 @@ finish_id_expression (tree id_expression
 	  push_deferring_access_checks (dk_no_check);
 	  decl = finish_non_static_data_member (decl, NULL_TREE,
 						/*qualifying_scope=*/NULL_TREE);
+	  if (EXPR_P (decl))
+	    SET_EXPR_LOCATION (decl, location);
 	  pop_deferring_access_checks ();
 	}
       else if (is_overloaded_fn (decl))
@@ -4978,7 +4982,8 @@ finish_omp_barrier (void)
 {
   tree fn = builtin_decl_explicit (BUILT_IN_GOMP_BARRIER);
   VEC(tree,gc) *vec = make_tree_vector ();
-  tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error);
+  tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error,
+				input_location);
   release_tree_vector (vec);
   finish_expr_stmt (stmt);
 }
@@ -4988,7 +4993,8 @@ finish_omp_flush (void)
 {
   tree fn = builtin_decl_explicit (BUILT_IN_SYNC_SYNCHRONIZE);
   VEC(tree,gc) *vec = make_tree_vector ();
-  tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error);
+  tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error,
+				input_location);
   release_tree_vector (vec);
   finish_expr_stmt (stmt);
 }
@@ -4998,7 +5004,8 @@ finish_omp_taskwait (void)
 {
   tree fn = builtin_decl_explicit (BUILT_IN_GOMP_TASKWAIT);
   VEC(tree,gc) *vec = make_tree_vector ();
-  tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error);
+  tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error,
+				input_location);
   release_tree_vector (vec);
   finish_expr_stmt (stmt);
 }
@@ -5008,7 +5015,8 @@ finish_omp_taskyield (void)
 {
   tree fn = builtin_decl_explicit (BUILT_IN_GOMP_TASKYIELD);
   VEC(tree,gc) *vec = make_tree_vector ();
-  tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error);
+  tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error,
+				input_location);
   release_tree_vector (vec);
   finish_expr_stmt (stmt);
 }
Index: testsuite/g++.dg/warn/pr26785.C
===================================================================
--- testsuite/g++.dg/warn/pr26785.C	(revision 190939)
+++ testsuite/g++.dg/warn/pr26785.C	(working copy)
@@ -3,7 +3,7 @@
 // { dg-options "-fshow-column" }
 
 class foo {
-  foo::foo // { dg-error "3:extra qualification" }
+  foo::foo // { dg-error "8:extra qualification" }
   (int a, 
    int b,
    int c);
Index: testsuite/g++.dg/tc1/dr52.C
===================================================================
--- testsuite/g++.dg/tc1/dr52.C	(revision 190939)
+++ testsuite/g++.dg/tc1/dr52.C	(working copy)
@@ -16,8 +16,8 @@ private:
 struct B1 : B {};
 struct B2 : B {};
 
-struct C
-{ // { dg-error "C" }
+struct C  // { dg-error "C" }
+{
   void foo(void);
 };
 
Index: testsuite/g++.old-deja/g++.brendan/crash16.C
===================================================================
--- testsuite/g++.old-deja/g++.brendan/crash16.C	(revision 190939)
+++ testsuite/g++.old-deja/g++.brendan/crash16.C	(working copy)
@@ -8,7 +8,7 @@ public:
       Graph(void) {} // { dg-error "7:'Graph" }
 }
 
-Graph::Graph(void) // { dg-error "18:return type|1: error: redefinition" }
+Graph::Graph(void) // { dg-error "18:return type|8: error: redefinition" }
 {    N = 10;
 }
 


More information about the Gcc-patches mailing list