diff mbox

Better location info for "incomplete type" error msg (PR c/70756)

Message ID 20160505142215.GN5348@redhat.com
State New
Headers show

Commit Message

Marek Polacek May 5, 2016, 2:22 p.m. UTC
On Wed, May 04, 2016 at 11:52:39AM -0400, Jason Merrill wrote:
> On Wed, May 4, 2016 at 9:00 AM, Marek Polacek <polacek@redhat.com> wrote:
> > On Tue, May 03, 2016 at 08:05:47PM -0400, Jason Merrill wrote:
> >> Looks good.
> >>
> >> But I don't see a C++ testcase; can the test go into c-c++-common?
> >
> > Sadly, no.  As of now, the patch doesn't improve things for C++ (?).  Seems
> > we'd need to pass better locations down to pointer_int_sum / size_in_bytes.
> > It cascades :(.
> 
> Sure.  But can you fix that, too, while you're thinking about it?
> Passing the location to cp_pointer_int_sum and pointer_diff seems
> pretty simple.

That's true, that was pretty simple, actually.  And while at it, I also
added a location parameter to cp_build_modify_expr.  With that, we generate
better diagnostics even for C++, so I could move the test to c-c++-common.
And I also added another test, this time with -Wpointer-arith diagnostics,
which this patch improves as well.

Bootstrapped/regtested on x86_64-linux, ok for trunk?

2016-05-05  Marek Polacek  <polacek@redhat.com>

	PR c/70756
	* c-common.c (pointer_int_sum): Call size_in_bytes_loc instead of
	size_in_bytes and pass LOC to it.

	* c-decl.c (build_compound_literal): Pass LOC down to
	c_incomplete_type_error.
	* c-tree.h (require_complete_type): Adjust declaration.
	(c_incomplete_type_error): Likewise.
	* c-typeck.c (require_complete_type): Add location parameter, pass it
	down to c_incomplete_type_error.
	(c_incomplete_type_error): Add location parameter, pass it down to
	error_at.
	(build_component_ref): Pass location down to c_incomplete_type_error.
	(default_conversion): Pass location down to require_complete_type.
	(build_array_ref): Likewise.
	(build_function_call_vec): Likewise.
	(convert_arguments): Likewise.
	(build_unary_op): Likewise.
	(build_c_cast): Likewise.
	(build_modify_expr): Likewise.
	(convert_for_assignment): Likewise.
	(c_finish_omp_clauses): Likewise.

	* call.c (build_new_op_1): Pass LOC to cp_build_modify_expr.
	* cp-tree.h (cp_build_modify_expr): Update declaration.
	(cxx_incomplete_type_error, cxx_incomplete_type_diagnostic): New inline
	overloads.
	* cp-ubsan.c (cp_ubsan_dfs_initialize_vtbl_ptrs): Pass INPUT_LOCATION to
	cp_build_modify_expr.
	* decl2.c (set_guard): Likewise.
	(handle_tls_init): Likewise.
	* init.c (perform_member_init): Likewise.
	(expand_virtual_init): Likewise.
	(build_new_1): Likewise.
	(build_vec_delete_1): Likewise.
	(get_temp_regvar): Likewise.
	(build_vec_init): Likewise.
	* method.c (do_build_copy_assign): Likewise.
	(assignable_expr): Likewise.
	* semantics.c (finish_omp_for): Likewise.
	* typeck.c (cp_build_binary_op): Pass LOCATION to pointer_diff and
	cp_pointer_int_sum.
	(cp_pointer_int_sum): Add location parameter.  Pass it down to
	pointer_int_sum.
	(pointer_diff): Add location parameter.  Use it.
	(build_modify_expr): Pass location down to cp_build_modify_expr.
	(cp_build_modify_expr): Add location parameter.  Use it.
	(build_x_modify_expr): Pass location down to cp_build_modify_expr.
	* typeck2.c (cxx_incomplete_type_diagnostic,
	cxx_incomplete_type_error): Add location parameter.

	* langhooks-def.h (lhd_incomplete_type_error): Adjust declaration.
	* langhooks.c (lhd_incomplete_type_error): Add location parameter.
	* langhooks.h (incomplete_type_error): Likewise.
	* tree.c (size_in_bytes_loc): Renamed from size_in_bytes.  Add location
	parameter, pass it down to incomplete_type_error.
	* tree.h (size_in_bytes): New inline overload.
	(size_in_bytes_loc): Renamed from size_in_bytes.

	* c-c++-common/pr70756-2.c: New test.
	* c-c++-common/pr70756.c: New test.


	Marek

Comments

Marek Polacek May 12, 2016, 10:37 a.m. UTC | #1
Ping.

On Thu, May 05, 2016 at 04:22:15PM +0200, Marek Polacek wrote:
> On Wed, May 04, 2016 at 11:52:39AM -0400, Jason Merrill wrote:
> > On Wed, May 4, 2016 at 9:00 AM, Marek Polacek <polacek@redhat.com> wrote:
> > > On Tue, May 03, 2016 at 08:05:47PM -0400, Jason Merrill wrote:
> > >> Looks good.
> > >>
> > >> But I don't see a C++ testcase; can the test go into c-c++-common?
> > >
> > > Sadly, no.  As of now, the patch doesn't improve things for C++ (?).  Seems
> > > we'd need to pass better locations down to pointer_int_sum / size_in_bytes.
> > > It cascades :(.
> > 
> > Sure.  But can you fix that, too, while you're thinking about it?
> > Passing the location to cp_pointer_int_sum and pointer_diff seems
> > pretty simple.
> 
> That's true, that was pretty simple, actually.  And while at it, I also
> added a location parameter to cp_build_modify_expr.  With that, we generate
> better diagnostics even for C++, so I could move the test to c-c++-common.
> And I also added another test, this time with -Wpointer-arith diagnostics,
> which this patch improves as well.
> 
> Bootstrapped/regtested on x86_64-linux, ok for trunk?
> 
> 2016-05-05  Marek Polacek  <polacek@redhat.com>
> 
> 	PR c/70756
> 	* c-common.c (pointer_int_sum): Call size_in_bytes_loc instead of
> 	size_in_bytes and pass LOC to it.
> 
> 	* c-decl.c (build_compound_literal): Pass LOC down to
> 	c_incomplete_type_error.
> 	* c-tree.h (require_complete_type): Adjust declaration.
> 	(c_incomplete_type_error): Likewise.
> 	* c-typeck.c (require_complete_type): Add location parameter, pass it
> 	down to c_incomplete_type_error.
> 	(c_incomplete_type_error): Add location parameter, pass it down to
> 	error_at.
> 	(build_component_ref): Pass location down to c_incomplete_type_error.
> 	(default_conversion): Pass location down to require_complete_type.
> 	(build_array_ref): Likewise.
> 	(build_function_call_vec): Likewise.
> 	(convert_arguments): Likewise.
> 	(build_unary_op): Likewise.
> 	(build_c_cast): Likewise.
> 	(build_modify_expr): Likewise.
> 	(convert_for_assignment): Likewise.
> 	(c_finish_omp_clauses): Likewise.
> 
> 	* call.c (build_new_op_1): Pass LOC to cp_build_modify_expr.
> 	* cp-tree.h (cp_build_modify_expr): Update declaration.
> 	(cxx_incomplete_type_error, cxx_incomplete_type_diagnostic): New inline
> 	overloads.
> 	* cp-ubsan.c (cp_ubsan_dfs_initialize_vtbl_ptrs): Pass INPUT_LOCATION to
> 	cp_build_modify_expr.
> 	* decl2.c (set_guard): Likewise.
> 	(handle_tls_init): Likewise.
> 	* init.c (perform_member_init): Likewise.
> 	(expand_virtual_init): Likewise.
> 	(build_new_1): Likewise.
> 	(build_vec_delete_1): Likewise.
> 	(get_temp_regvar): Likewise.
> 	(build_vec_init): Likewise.
> 	* method.c (do_build_copy_assign): Likewise.
> 	(assignable_expr): Likewise.
> 	* semantics.c (finish_omp_for): Likewise.
> 	* typeck.c (cp_build_binary_op): Pass LOCATION to pointer_diff and
> 	cp_pointer_int_sum.
> 	(cp_pointer_int_sum): Add location parameter.  Pass it down to
> 	pointer_int_sum.
> 	(pointer_diff): Add location parameter.  Use it.
> 	(build_modify_expr): Pass location down to cp_build_modify_expr.
> 	(cp_build_modify_expr): Add location parameter.  Use it.
> 	(build_x_modify_expr): Pass location down to cp_build_modify_expr.
> 	* typeck2.c (cxx_incomplete_type_diagnostic,
> 	cxx_incomplete_type_error): Add location parameter.
> 
> 	* langhooks-def.h (lhd_incomplete_type_error): Adjust declaration.
> 	* langhooks.c (lhd_incomplete_type_error): Add location parameter.
> 	* langhooks.h (incomplete_type_error): Likewise.
> 	* tree.c (size_in_bytes_loc): Renamed from size_in_bytes.  Add location
> 	parameter, pass it down to incomplete_type_error.
> 	* tree.h (size_in_bytes): New inline overload.
> 	(size_in_bytes_loc): Renamed from size_in_bytes.
> 
> 	* c-c++-common/pr70756-2.c: New test.
> 	* c-c++-common/pr70756.c: New test.
> 
> diff --git gcc/c-family/c-common.c gcc/c-family/c-common.c
> index 63a18c8..150bdb2 100644
> --- gcc/c-family/c-common.c
> +++ gcc/c-family/c-common.c
> @@ -4269,7 +4269,7 @@ pointer_int_sum (location_t loc, enum tree_code resultcode,
>        size_exp = integer_one_node;
>      }
>    else
> -    size_exp = size_in_bytes (TREE_TYPE (result_type));
> +    size_exp = size_in_bytes_loc (loc, TREE_TYPE (result_type));
>  
>    /* We are manipulating pointer values, so we don't need to warn
>       about relying on undefined signed overflow.  We disable the
> diff --git gcc/c/c-decl.c gcc/c/c-decl.c
> index 7094efc..48fa65c 100644
> --- gcc/c/c-decl.c
> +++ gcc/c/c-decl.c
> @@ -5112,7 +5112,7 @@ build_compound_literal (location_t loc, tree type, tree init, bool non_const)
>  
>    if (type == error_mark_node || !COMPLETE_TYPE_P (type))
>      {
> -      c_incomplete_type_error (NULL_TREE, type);
> +      c_incomplete_type_error (loc, NULL_TREE, type);
>        return error_mark_node;
>      }
>  
> diff --git gcc/c/c-tree.h gcc/c/c-tree.h
> index 07d0f65..1201f42 100644
> --- gcc/c/c-tree.h
> +++ gcc/c/c-tree.h
> @@ -588,13 +588,13 @@ extern tree c_last_sizeof_arg;
>  extern struct c_switch *c_switch_stack;
>  
>  extern tree c_objc_common_truthvalue_conversion (location_t, tree);
> -extern tree require_complete_type (tree);
> +extern tree require_complete_type (location_t, tree);
>  extern int same_translation_unit_p (const_tree, const_tree);
>  extern int comptypes (tree, tree);
>  extern int comptypes_check_different_types (tree, tree, bool *);
>  extern bool c_vla_type_p (const_tree);
>  extern bool c_mark_addressable (tree);
> -extern void c_incomplete_type_error (const_tree, const_tree);
> +extern void c_incomplete_type_error (location_t, const_tree, const_tree);
>  extern tree c_type_promotes_to (tree);
>  extern struct c_expr default_function_array_conversion (location_t,
>  							struct c_expr);
> diff --git gcc/c/c-typeck.c gcc/c/c-typeck.c
> index 861aa12..b037f46 100644
> --- gcc/c/c-typeck.c
> +++ gcc/c/c-typeck.c
> @@ -183,11 +183,12 @@ struct tagged_tu_seen_cache {
>  static const struct tagged_tu_seen_cache * tagged_tu_seen_base;
>  static void free_all_tagged_tu_seen_up_to (const struct tagged_tu_seen_cache *);
>  
> -/* Do `exp = require_complete_type (exp);' to make sure exp
> -   does not have an incomplete type.  (That includes void types.)  */
> +/* Do `exp = require_complete_type (loc, exp);' to make sure exp
> +   does not have an incomplete type.  (That includes void types.)
> +   LOC is the location of the use.  */
>  
>  tree
> -require_complete_type (tree value)
> +require_complete_type (location_t loc, tree value)
>  {
>    tree type = TREE_TYPE (value);
>  
> @@ -198,23 +199,24 @@ require_complete_type (tree value)
>    if (COMPLETE_TYPE_P (type))
>      return value;
>  
> -  c_incomplete_type_error (value, type);
> +  c_incomplete_type_error (loc, value, type);
>    return error_mark_node;
>  }
>  
>  /* Print an error message for invalid use of an incomplete type.
>     VALUE is the expression that was used (or 0 if that isn't known)
> -   and TYPE is the type that was invalid.  */
> +   and TYPE is the type that was invalid.  LOC is the location for
> +   the error.  */
>  
>  void
> -c_incomplete_type_error (const_tree value, const_tree type)
> +c_incomplete_type_error (location_t loc, const_tree value, const_tree type)
>  {
>    /* Avoid duplicate error message.  */
>    if (TREE_CODE (type) == ERROR_MARK)
>      return;
>  
>    if (value != 0 && (VAR_P (value) || TREE_CODE (value) == PARM_DECL))
> -    error ("%qD has an incomplete type %qT", value, type);
> +    error_at (loc, "%qD has an incomplete type %qT", value, type);
>    else
>      {
>      retry:
> @@ -228,7 +230,7 @@ c_incomplete_type_error (const_tree value, const_tree type)
>  	  break;
>  
>  	case VOID_TYPE:
> -	  error ("invalid use of void expression");
> +	  error_at (loc, "invalid use of void expression");
>  	  return;
>  
>  	case ARRAY_TYPE:
> @@ -236,13 +238,13 @@ c_incomplete_type_error (const_tree value, const_tree type)
>  	    {
>  	      if (TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL)
>  		{
> -		  error ("invalid use of flexible array member");
> +		  error_at (loc, "invalid use of flexible array member");
>  		  return;
>  		}
>  	      type = TREE_TYPE (type);
>  	      goto retry;
>  	    }
> -	  error ("invalid use of array with unspecified bounds");
> +	  error_at (loc, "invalid use of array with unspecified bounds");
>  	  return;
>  
>  	default:
> @@ -250,10 +252,10 @@ c_incomplete_type_error (const_tree value, const_tree type)
>  	}
>  
>        if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
> -	error ("invalid use of undefined type %qT", type);
> +	error_at (loc, "invalid use of undefined type %qT", type);
>        else
>  	/* If this type has a typedef-name, the TYPE_NAME is a TYPE_DECL.  */
> -	error ("invalid use of incomplete typedef %qT", type);
> +	error_at (loc, "invalid use of incomplete typedef %qT", type);
>      }
>  }
>  
> @@ -2117,7 +2119,7 @@ default_conversion (tree exp)
>        return error_mark_node;
>      }
>  
> -  exp = require_complete_type (exp);
> +  exp = require_complete_type (EXPR_LOC_OR_LOC (exp, input_location), exp);
>    if (exp == error_mark_node)
>      return error_mark_node;
>  
> @@ -2334,7 +2336,7 @@ build_component_ref (location_t loc, tree datum, tree component)
>      {
>        if (!COMPLETE_TYPE_P (type))
>  	{
> -	  c_incomplete_type_error (NULL_TREE, type);
> +	  c_incomplete_type_error (loc, NULL_TREE, type);
>  	  return error_mark_node;
>  	}
>  
> @@ -2642,7 +2644,7 @@ build_array_ref (location_t loc, tree array, tree index)
>  	       in an inline function.
>  	       Hope it doesn't break something else.  */
>  	    | TREE_THIS_VOLATILE (array));
> -      ret = require_complete_type (rval);
> +      ret = require_complete_type (loc, rval);
>        protected_set_expr_location (ret, loc);
>        if (non_lvalue)
>  	ret = non_lvalue_loc (loc, ret);
> @@ -3088,7 +3090,7 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc,
>  		 "function with qualified void return type called");
>        return result;
>      }
> -  return require_complete_type (result);
> +  return require_complete_type (loc, result);
>  }
>  
>  /* Like build_function_call_vec, but call also resolve_overloaded_builtin.  */
> @@ -3239,7 +3241,7 @@ convert_arguments (location_t loc, vec<location_t> arg_loc, tree typelist,
>        val = c_fully_fold (val, false, NULL);
>        STRIP_TYPE_NOPS (val);
>  
> -      val = require_complete_type (val);
> +      val = require_complete_type (ploc, val);
>  
>        if (type != 0)
>  	{
> @@ -4047,7 +4049,7 @@ build_unary_op (location_t location,
>      arg = remove_c_maybe_const_expr (arg);
>  
>    if (code != ADDR_EXPR)
> -    arg = require_complete_type (arg);
> +    arg = require_complete_type (location, arg);
>  
>    typecode = TREE_CODE (TREE_TYPE (arg));
>    if (typecode == ERROR_MARK)
> @@ -5268,7 +5270,7 @@ build_c_cast (location_t loc, tree type, tree expr)
>  
>    if (!VOID_TYPE_P (type))
>      {
> -      value = require_complete_type (value);
> +      value = require_complete_type (loc, value);
>        if (value == error_mark_node)
>  	return error_mark_node;
>      }
> @@ -5538,7 +5540,7 @@ build_modify_expr (location_t location, tree lhs, tree lhs_origtype,
>    bool is_atomic_op;
>  
>    /* Types that aren't fully specified cannot be used in assignments.  */
> -  lhs = require_complete_type (lhs);
> +  lhs = require_complete_type (location, lhs);
>  
>    /* Avoid duplicate error messages from operands that had errors.  */
>    if (TREE_CODE (lhs) == ERROR_MARK || TREE_CODE (rhs) == ERROR_MARK)
> @@ -6133,7 +6135,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
>        error_at (location, "void value not ignored as it ought to be");
>        return error_mark_node;
>      }
> -  rhs = require_complete_type (rhs);
> +  rhs = require_complete_type (location, rhs);
>    if (rhs == error_mark_node)
>      return error_mark_node;
>  
> @@ -12550,7 +12552,7 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
>  
>  	      t = OMP_CLAUSE_DECL (c);
>  	    }
> -	  t = require_complete_type (t);
> +	  t = require_complete_type (OMP_CLAUSE_LOCATION (c), t);
>  	  if (t == error_mark_node)
>  	    {
>  	      remove = true;
> @@ -13361,7 +13363,7 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
>  
>  	  if (need_complete)
>  	    {
> -	      t = require_complete_type (t);
> +	      t = require_complete_type (OMP_CLAUSE_LOCATION (c), t);
>  	      if (t == error_mark_node)
>  		remove = true;
>  	    }
> diff --git gcc/cp/call.c gcc/cp/call.c
> index e9ebdbc..a49bbb5 100644
> --- gcc/cp/call.c
> +++ gcc/cp/call.c
> @@ -5757,7 +5757,7 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
>    switch (code)
>      {
>      case MODIFY_EXPR:
> -      return cp_build_modify_expr (arg1, code2, arg2, complain);
> +      return cp_build_modify_expr (loc, arg1, code2, arg2, complain);
>  
>      case INDIRECT_REF:
>        return cp_build_indirect_ref (arg1, RO_UNARY_STAR, complain);
> diff --git gcc/cp/cp-tree.h gcc/cp/cp-tree.h
> index 6665355..556c256 100644
> --- gcc/cp/cp-tree.h
> +++ gcc/cp/cp-tree.h
> @@ -6666,7 +6666,8 @@ extern tree cp_build_c_cast			(tree, tree, tsubst_flags_t);
>  extern cp_expr build_x_modify_expr		(location_t, tree,
>  						 enum tree_code, tree,
>  						 tsubst_flags_t);
> -extern tree cp_build_modify_expr		(tree, enum tree_code, tree,
> +extern tree cp_build_modify_expr		(location_t, tree,
> +						 enum tree_code, tree,
>  						 tsubst_flags_t);
>  extern tree convert_for_initialization		(tree, tree, tree, int,
>  						 impl_conv_rhs, tree, int,
> @@ -6726,11 +6727,24 @@ extern tree finish_binary_fold_expr          (tree, tree, int);
>  
>  /* in typeck2.c */
>  extern void require_complete_eh_spec_types	(tree, tree);
> -extern void cxx_incomplete_type_diagnostic	(const_tree, const_tree, diagnostic_t);
> -#undef cxx_incomplete_type_error
> -extern void cxx_incomplete_type_error		(const_tree, const_tree);
> -#define cxx_incomplete_type_error(V,T) \
> -  (cxx_incomplete_type_diagnostic ((V), (T), DK_ERROR))
> +extern void cxx_incomplete_type_diagnostic	(location_t, const_tree,
> +						 const_tree, diagnostic_t);
> +inline void
> +cxx_incomplete_type_diagnostic (const_tree value, const_tree type,
> +				diagnostic_t diag_kind)
> +{
> +  cxx_incomplete_type_diagnostic (EXPR_LOC_OR_LOC (value, input_location),
> +				  value, type, diag_kind);
> +}
> +
> +extern void cxx_incomplete_type_error		(location_t, const_tree,
> +						 const_tree);
> +inline void
> +cxx_incomplete_type_error (const_tree value, const_tree type)
> +{
> +  cxx_incomplete_type_diagnostic (value, type, DK_ERROR);
> +}
> +
>  extern void cxx_incomplete_type_inform 	        (const_tree);
>  extern tree error_not_base_type			(tree, tree);
>  extern tree binfo_or_else			(tree, tree);
> diff --git gcc/cp/cp-ubsan.c gcc/cp/cp-ubsan.c
> index be24a5c..9c8f6e6 100644
> --- gcc/cp/cp-ubsan.c
> +++ gcc/cp/cp-ubsan.c
> @@ -299,8 +299,8 @@ cp_ubsan_dfs_initialize_vtbl_ptrs (tree binfo, void *data)
>  
>        /* Assign NULL to the vptr.  */
>        tree vtbl = build_zero_cst (TREE_TYPE (vtbl_ptr));
> -      tree stmt = cp_build_modify_expr (vtbl_ptr, NOP_EXPR, vtbl,
> -					tf_warning_or_error);
> +      tree stmt = cp_build_modify_expr (input_location, vtbl_ptr, NOP_EXPR,
> +					vtbl, tf_warning_or_error);
>        if (vptr_via_virtual_p (binfo))
>  	/* If this vptr comes from a virtual base of the complete object, only
>  	   clear it if we're in charge of virtual bases.  */
> diff --git gcc/cp/decl2.c gcc/cp/decl2.c
> index 0ea326d..22f9ede 100644
> --- gcc/cp/decl2.c
> +++ gcc/cp/decl2.c
> @@ -3161,7 +3161,7 @@ set_guard (tree guard)
>    guard_init = integer_one_node;
>    if (!same_type_p (TREE_TYPE (guard_init), TREE_TYPE (guard)))
>      guard_init = fold_convert (TREE_TYPE (guard), guard_init);
> -  return cp_build_modify_expr (guard, NOP_EXPR, guard_init, 
> +  return cp_build_modify_expr (input_location, guard, NOP_EXPR, guard_init,
>  			       tf_warning_or_error);
>  }
>  
> @@ -4346,7 +4346,8 @@ handle_tls_init (void)
>    tree cond = cp_build_unary_op (TRUTH_NOT_EXPR, guard, false,
>  				 tf_warning_or_error);
>    finish_if_stmt_cond (cond, if_stmt);
> -  finish_expr_stmt (cp_build_modify_expr (guard, NOP_EXPR, boolean_true_node,
> +  finish_expr_stmt (cp_build_modify_expr (loc, guard, NOP_EXPR,
> +					  boolean_true_node,
>  					  tf_warning_or_error));
>    for (; vars; vars = TREE_CHAIN (vars))
>      {
> diff --git gcc/cp/init.c gcc/cp/init.c
> index 681ca12..8e7541f 100644
> --- gcc/cp/init.c
> +++ gcc/cp/init.c
> @@ -798,7 +798,8 @@ perform_member_init (tree member, tree init)
>  						tf_warning_or_error);
>  
>        if (init)
> -	finish_expr_stmt (cp_build_modify_expr (decl, INIT_EXPR, init,
> +	finish_expr_stmt (cp_build_modify_expr (input_location, decl,
> +						INIT_EXPR, init,
>  						tf_warning_or_error));
>      }
>  
> @@ -1254,8 +1255,8 @@ expand_virtual_init (tree binfo, tree decl)
>  
>    /* Assign the vtable to the vptr.  */
>    vtbl = convert_force (TREE_TYPE (vtbl_ptr), vtbl, 0, tf_warning_or_error);
> -  finish_expr_stmt (cp_build_modify_expr (vtbl_ptr, NOP_EXPR, vtbl,
> -					  tf_warning_or_error));
> +  finish_expr_stmt (cp_build_modify_expr (input_location, vtbl_ptr, NOP_EXPR,
> +					  vtbl, tf_warning_or_error));
>  }
>  
>  /* If an exception is thrown in a constructor, those base classes already
> @@ -3208,8 +3209,8 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
>  
>  	      ie = build_x_compound_expr_from_vec (*init, "new initializer",
>  						   complain);
> -	      init_expr = cp_build_modify_expr (init_expr, INIT_EXPR, ie,
> -						complain);
> +	      init_expr = cp_build_modify_expr (input_location, init_expr,
> +						INIT_EXPR, ie, complain);
>  	    }
>  	  stable = stabilize_init (init_expr, &init_preeval_expr);
>  	}
> @@ -3596,7 +3597,7 @@ build_vec_delete_1 (tree base, tree maxindex, tree type,
>  
>    tbase = create_temporary_var (ptype);
>    tbase_init
> -    = cp_build_modify_expr (tbase, NOP_EXPR,
> +    = cp_build_modify_expr (input_location, tbase, NOP_EXPR,
>  			    fold_build_pointer_plus_loc (input_location,
>  							 fold_convert (ptype,
>  								       base),
> @@ -3613,7 +3614,7 @@ build_vec_delete_1 (tree base, tree maxindex, tree type,
>  			 fold_convert (ptype, base)));
>    tmp = fold_build1_loc (input_location, NEGATE_EXPR, sizetype, size_exp);
>    tmp = fold_build_pointer_plus (tbase, tmp);
> -  tmp = cp_build_modify_expr (tbase, NOP_EXPR, tmp, complain);
> +  tmp = cp_build_modify_expr (input_location, tbase, NOP_EXPR, tmp, complain);
>    if (tmp == error_mark_node)
>      return error_mark_node;
>    body = build_compound_expr (input_location, body, tmp);
> @@ -3735,8 +3736,8 @@ get_temp_regvar (tree type, tree init)
>    decl = create_temporary_var (type);
>    add_decl_expr (decl);
>  
> -  finish_expr_stmt (cp_build_modify_expr (decl, INIT_EXPR, init, 
> -					  tf_warning_or_error));
> +  finish_expr_stmt (cp_build_modify_expr (input_location, decl, INIT_EXPR,
> +					  init, tf_warning_or_error));
>  
>    return decl;
>  }
> @@ -4000,8 +4001,8 @@ build_vec_init (tree base, tree maxindex, tree init,
>  	  else if (MAYBE_CLASS_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE)
>  	    one_init = build_aggr_init (baseref, elt, 0, complain);
>  	  else
> -	    one_init = cp_build_modify_expr (baseref, NOP_EXPR,
> -					     elt, complain);
> +	    one_init = cp_build_modify_expr (input_location, baseref,
> +					     NOP_EXPR, elt, complain);
>  	  if (one_init == error_mark_node)
>  	    errors = true;
>  	  if (try_const)
> @@ -4128,12 +4129,12 @@ build_vec_init (tree base, tree maxindex, tree init,
>  	    from = NULL_TREE;
>  
>  	  if (from_array == 2)
> -	    elt_init = cp_build_modify_expr (to, NOP_EXPR, from, 
> -					     complain);
> +	    elt_init = cp_build_modify_expr (input_location, to, NOP_EXPR,
> +					     from, complain);
>  	  else if (type_build_ctor_call (type))
>  	    elt_init = build_aggr_init (to, from, 0, complain);
>  	  else if (from)
> -	    elt_init = cp_build_modify_expr (to, NOP_EXPR, from,
> +	    elt_init = cp_build_modify_expr (input_location, to, NOP_EXPR, from,
>  					     complain);
>  	  else
>  	    gcc_unreachable ();
> diff --git gcc/cp/method.c gcc/cp/method.c
> index 0e501d9..310e7eb 100644
> --- gcc/cp/method.c
> +++ gcc/cp/method.c
> @@ -741,7 +741,7 @@ do_build_copy_assign (tree fndecl)
>  	    init = move (init);
>  
>  	  if (DECL_NAME (field))
> -	    init = cp_build_modify_expr (comp, NOP_EXPR, init, 
> +	    init = cp_build_modify_expr (input_location, comp, NOP_EXPR, init,
>  					 tf_warning_or_error);
>  	  else
>  	    init = build2 (MODIFY_EXPR, TREE_TYPE (comp), comp, init);
> @@ -1023,7 +1023,7 @@ assignable_expr (tree to, tree from)
>    ++cp_unevaluated_operand;
>    to = build_stub_object (to);
>    from = build_stub_object (from);
> -  tree r = cp_build_modify_expr (to, NOP_EXPR, from, tf_none);
> +  tree r = cp_build_modify_expr (input_location, to, NOP_EXPR, from, tf_none);
>    --cp_unevaluated_operand;
>    return r;
>  }
> diff --git gcc/cp/semantics.c gcc/cp/semantics.c
> index fed7e88..817ef99 100644
> --- gcc/cp/semantics.c
> +++ gcc/cp/semantics.c
> @@ -8073,7 +8073,7 @@ finish_omp_for (location_t locus, enum tree_code code, tree declv,
>  	{
>  	  if (orig_incr)
>  	    TREE_VEC_ELT (orig_incr, i) = incr;
> -	  incr = cp_build_modify_expr (TREE_OPERAND (incr, 0),
> +	  incr = cp_build_modify_expr (elocus, TREE_OPERAND (incr, 0),
>  				       TREE_CODE (TREE_OPERAND (incr, 1)),
>  				       TREE_OPERAND (incr, 2),
>  				       tf_warning_or_error);
> @@ -8107,7 +8107,8 @@ finish_omp_for (location_t locus, enum tree_code code, tree declv,
>        if (!processing_template_decl)
>  	{
>  	  init = fold_build_cleanup_point_expr (TREE_TYPE (init), init);
> -	  init = cp_build_modify_expr (decl, NOP_EXPR, init, tf_warning_or_error);
> +	  init = cp_build_modify_expr (elocus, decl, NOP_EXPR, init,
> +				       tf_warning_or_error);
>  	}
>        else
>  	init = build2 (MODIFY_EXPR, void_type_node, decl, init);
> diff --git gcc/cp/typeck.c gcc/cp/typeck.c
> index 95c777d..0d8a980 100644
> --- gcc/cp/typeck.c
> +++ gcc/cp/typeck.c
> @@ -43,13 +43,14 @@ static tree pfn_from_ptrmemfunc (tree);
>  static tree delta_from_ptrmemfunc (tree);
>  static tree convert_for_assignment (tree, tree, impl_conv_rhs, tree, int,
>  				    tsubst_flags_t, int);
> -static tree cp_pointer_int_sum (enum tree_code, tree, tree, tsubst_flags_t);
> +static tree cp_pointer_int_sum (location_t, enum tree_code, tree, tree,
> +				tsubst_flags_t);
>  static tree rationalize_conditional_expr (enum tree_code, tree, 
>  					  tsubst_flags_t);
>  static int comp_ptr_ttypes_real (tree, tree, int);
>  static bool comp_except_types (tree, tree, bool);
>  static bool comp_array_types (const_tree, const_tree, bool);
> -static tree pointer_diff (tree, tree, tree, tsubst_flags_t);
> +static tree pointer_diff (location_t, tree, tree, tree, tsubst_flags_t);
>  static tree get_delta_difference (tree, tree, bool, bool, tsubst_flags_t);
>  static void casts_away_constness_r (tree *, tree *, tsubst_flags_t);
>  static bool casts_away_constness (tree, tree, tsubst_flags_t);
> @@ -4236,8 +4237,8 @@ cp_build_binary_op (location_t location,
>        if (code0 == POINTER_TYPE && code1 == POINTER_TYPE
>  	  && same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (type0),
>  							TREE_TYPE (type1)))
> -	return pointer_diff (op0, op1, common_pointer_type (type0, type1),
> -			     complain);
> +	return pointer_diff (location, op0, op1,
> +			     common_pointer_type (type0, type1), complain);
>        /* In all other cases except pointer - int, the usual arithmetic
>  	 rules apply.  */
>        else if (!(code0 == POINTER_TYPE && code1 == INTEGER_TYPE))
> @@ -4260,8 +4261,8 @@ cp_build_binary_op (location_t location,
>  	      result_type = TREE_TYPE (ptr_operand);
>  	      break;
>  	    }
> -	  return cp_pointer_int_sum (code,
> -				     ptr_operand, 
> +	  return cp_pointer_int_sum (location, code,
> +				     ptr_operand,
>  				     int_operand,
>  				     complain);
>  	}
> @@ -5226,8 +5227,8 @@ build_x_vec_perm_expr (location_t loc,
>     of pointer PTROP and integer INTOP.  */
>  
>  static tree
> -cp_pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop,
> -		    tsubst_flags_t complain)
> +cp_pointer_int_sum (location_t loc, enum tree_code resultcode, tree ptrop,
> +		    tree intop, tsubst_flags_t complain)
>  {
>    tree res_type = TREE_TYPE (ptrop);
>  
> @@ -5238,7 +5239,7 @@ cp_pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop,
>       pointer_int_sum() anyway.  */
>    complete_type (TREE_TYPE (res_type));
>  
> -  return pointer_int_sum (input_location, resultcode, ptrop,
> +  return pointer_int_sum (loc, resultcode, ptrop,
>  			  intop, complain & tf_warning_or_error);
>  }
>  
> @@ -5246,7 +5247,8 @@ cp_pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop,
>     The resulting tree has type int.  */
>  
>  static tree
> -pointer_diff (tree op0, tree op1, tree ptrtype, tsubst_flags_t complain)
> +pointer_diff (location_t loc, tree op0, tree op1, tree ptrtype,
> +	      tsubst_flags_t complain)
>  {
>    tree result;
>    tree restype = ptrdiff_type_node;
> @@ -5258,7 +5260,7 @@ pointer_diff (tree op0, tree op1, tree ptrtype, tsubst_flags_t complain)
>    if (VOID_TYPE_P (target_type))
>      {
>        if (complain & tf_error)
> -	permerror (input_location, "ISO C++ forbids using pointer of "
> +	permerror (loc, "ISO C++ forbids using pointer of "
>  		   "type %<void *%> in subtraction");
>        else
>  	return error_mark_node;
> @@ -5266,7 +5268,7 @@ pointer_diff (tree op0, tree op1, tree ptrtype, tsubst_flags_t complain)
>    if (TREE_CODE (target_type) == FUNCTION_TYPE)
>      {
>        if (complain & tf_error)
> -	permerror (input_location, "ISO C++ forbids using pointer to "
> +	permerror (loc, "ISO C++ forbids using pointer to "
>  		   "a function in subtraction");
>        else
>  	return error_mark_node;
> @@ -5274,7 +5276,7 @@ pointer_diff (tree op0, tree op1, tree ptrtype, tsubst_flags_t complain)
>    if (TREE_CODE (target_type) == METHOD_TYPE)
>      {
>        if (complain & tf_error)
> -	permerror (input_location, "ISO C++ forbids using pointer to "
> +	permerror (loc, "ISO C++ forbids using pointer to "
>  		   "a method in subtraction");
>        else
>  	return error_mark_node;
> @@ -5283,7 +5285,7 @@ pointer_diff (tree op0, tree op1, tree ptrtype, tsubst_flags_t complain)
>    /* First do the subtraction as integers;
>       then drop through to build the divide operator.  */
>  
> -  op0 = cp_build_binary_op (input_location,
> +  op0 = cp_build_binary_op (loc,
>  			    MINUS_EXPR,
>  			    cp_convert (restype, op0, complain),
>  			    cp_convert (restype, op1, complain),
> @@ -5293,8 +5295,8 @@ pointer_diff (tree op0, tree op1, tree ptrtype, tsubst_flags_t complain)
>    if (!COMPLETE_TYPE_P (TREE_TYPE (TREE_TYPE (op1))))
>      {
>        if (complain & tf_error)
> -	error ("invalid use of a pointer to an incomplete type in "
> -	       "pointer arithmetic");
> +	error_at (loc, "invalid use of a pointer to an incomplete type in "
> +		  "pointer arithmetic");
>        else
>  	return error_mark_node;
>      }
> @@ -5302,19 +5304,19 @@ pointer_diff (tree op0, tree op1, tree ptrtype, tsubst_flags_t complain)
>    if (pointer_to_zero_sized_aggr_p (TREE_TYPE (op1)))
>      {
>        if (complain & tf_error)
> -	error ("arithmetic on pointer to an empty aggregate");
> +	error_at (loc, "arithmetic on pointer to an empty aggregate");
>        else
>  	return error_mark_node;
>      }
>  
>    op1 = (TYPE_PTROB_P (ptrtype)
> -	 ? size_in_bytes (target_type)
> +	 ? size_in_bytes_loc (loc, target_type)
>  	 : integer_one_node);
>  
>    /* Do the division.  */
>  
> -  result = build2 (EXACT_DIV_EXPR, restype, op0,
> -		   cp_convert (restype, op1, complain));
> +  result = build2_loc (loc, EXACT_DIV_EXPR, restype, op0,
> +		       cp_convert (restype, op1, complain));
>    return result;
>  }
>  
> @@ -7470,13 +7472,14 @@ cp_build_c_cast (tree type, tree expr, tsubst_flags_t complain)
>  
>  /* For use from the C common bits.  */
>  tree
> -build_modify_expr (location_t /*location*/,
> +build_modify_expr (location_t location,
>  		   tree lhs, tree /*lhs_origtype*/,
>  		   enum tree_code modifycode, 
>  		   location_t /*rhs_location*/, tree rhs,
>  		   tree /*rhs_origtype*/)
>  {
> -  return cp_build_modify_expr (lhs, modifycode, rhs, tf_warning_or_error);
> +  return cp_build_modify_expr (location, lhs, modifycode, rhs,
> +			       tf_warning_or_error);
>  }
>  
>  /* Build an assignment expression of lvalue LHS from value RHS.
> @@ -7487,8 +7490,8 @@ build_modify_expr (location_t /*location*/,
>     C++: If MODIFYCODE is INIT_EXPR, then leave references unbashed.  */
>  
>  tree
> -cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
> -		      tsubst_flags_t complain)
> +cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
> +		      tree rhs, tsubst_flags_t complain)
>  {
>    tree result;
>    tree newrhs = rhs;
> @@ -7510,7 +7513,7 @@ cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
>  	lhs = build2 (TREE_CODE (lhs), TREE_TYPE (lhs),
>  		      cp_stabilize_reference (TREE_OPERAND (lhs, 0)),
>  		      TREE_OPERAND (lhs, 1));
> -      newrhs = cp_build_modify_expr (TREE_OPERAND (lhs, 0),
> +      newrhs = cp_build_modify_expr (loc, TREE_OPERAND (lhs, 0),
>  				     modifycode, rhs, complain);
>        if (newrhs == error_mark_node)
>  	return error_mark_node;
> @@ -7518,7 +7521,7 @@ cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
>  
>        /* Handle (a, b) used as an "lvalue".  */
>      case COMPOUND_EXPR:
> -      newrhs = cp_build_modify_expr (TREE_OPERAND (lhs, 1),
> +      newrhs = cp_build_modify_expr (loc, TREE_OPERAND (lhs, 1),
>  				     modifycode, rhs, complain);
>        if (newrhs == error_mark_node)
>  	return error_mark_node;
> @@ -7530,8 +7533,8 @@ cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
>  	lhs = build2 (TREE_CODE (lhs), TREE_TYPE (lhs),
>  		      cp_stabilize_reference (TREE_OPERAND (lhs, 0)),
>  		      TREE_OPERAND (lhs, 1));
> -      newrhs = cp_build_modify_expr (TREE_OPERAND (lhs, 0), modifycode, rhs,
> -				     complain);
> +      newrhs = cp_build_modify_expr (loc, TREE_OPERAND (lhs, 0), modifycode,
> +				     rhs, complain);
>        if (newrhs == error_mark_node)
>  	return error_mark_node;
>        return build2 (COMPOUND_EXPR, lhstype, lhs, newrhs);
> @@ -7580,9 +7583,9 @@ cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
>  
>  	cond = build_conditional_expr
>  	  (input_location, TREE_OPERAND (lhs, 0),
> -	   cp_build_modify_expr (TREE_OPERAND (lhs, 1),
> +	   cp_build_modify_expr (loc, TREE_OPERAND (lhs, 1),
>  				 modifycode, rhs, complain),
> -	   cp_build_modify_expr (TREE_OPERAND (lhs, 2),
> +	   cp_build_modify_expr (loc, TREE_OPERAND (lhs, 2),
>  				 modifycode, rhs, complain),
>             complain);
>  
> @@ -7680,9 +7683,7 @@ cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
>  	  lhs = cp_stabilize_reference (lhs);
>  	  rhs = rvalue (rhs);
>  	  rhs = stabilize_expr (rhs, &init);
> -	  newrhs = cp_build_binary_op (input_location,
> -				       modifycode, lhs, rhs,
> -				       complain);
> +	  newrhs = cp_build_binary_op (loc, modifycode, lhs, rhs, complain);
>  	  if (newrhs == error_mark_node)
>  	    {
>  	      if (complain & tf_error)
> @@ -7893,7 +7894,7 @@ build_x_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
>  	  return rval;
>  	}
>      }
> -  return cp_build_modify_expr (lhs, modifycode, rhs, complain);
> +  return cp_build_modify_expr (loc, lhs, modifycode, rhs, complain);
>  }
>  
>  /* Helper function for get_delta_difference which assumes FROM is a base
> diff --git gcc/cp/typeck2.c gcc/cp/typeck2.c
> index e59ad51..1c4e832 100644
> --- gcc/cp/typeck2.c
> +++ gcc/cp/typeck2.c
> @@ -451,8 +451,8 @@ cxx_incomplete_type_inform (const_tree type)
>     type of diagnostic (see diagnostic.def).  */
>  
>  void
> -cxx_incomplete_type_diagnostic (const_tree value, const_tree type, 
> -				diagnostic_t diag_kind)
> +cxx_incomplete_type_diagnostic (location_t loc, const_tree value,
> +				const_tree type, diagnostic_t diag_kind)
>  {
>    bool is_decl = false, complained = false;
>  
> @@ -475,8 +475,6 @@ cxx_incomplete_type_diagnostic (const_tree value, const_tree type,
>   retry:
>    /* We must print an error message.  Be clever about what it says.  */
>  
> -  location_t loc = EXPR_LOC_OR_LOC (value, input_location);
> -
>    switch (TREE_CODE (type))
>      {
>      case RECORD_TYPE:
> @@ -570,13 +568,14 @@ cxx_incomplete_type_diagnostic (const_tree value, const_tree type,
>      }
>  }
>  
> -/* Backward-compatibility interface to incomplete_type_diagnostic;
> -   required by ../tree.c.  */
> -#undef cxx_incomplete_type_error
> +/* Print an error message for invalid use of an incomplete type.
> +   VALUE is the expression that was used (or 0 if that isn't known)
> +   and TYPE is the type that was invalid.  */
> +
>  void
> -cxx_incomplete_type_error (const_tree value, const_tree type)
> +cxx_incomplete_type_error (location_t loc, const_tree value, const_tree type)
>  {
> -  cxx_incomplete_type_diagnostic (value, type, DK_ERROR);
> +  cxx_incomplete_type_diagnostic (loc, value, type, DK_ERROR);
>  }
>  
>  
> diff --git gcc/langhooks-def.h gcc/langhooks-def.h
> index a2566ec..034b3b7 100644
> --- gcc/langhooks-def.h
> +++ gcc/langhooks-def.h
> @@ -52,7 +52,7 @@ extern void lhd_print_error_function (diagnostic_context *,
>  				      const char *, struct diagnostic_info *);
>  extern void lhd_set_decl_assembler_name (tree);
>  extern bool lhd_warn_unused_global_decl (const_tree);
> -extern void lhd_incomplete_type_error (const_tree, const_tree);
> +extern void lhd_incomplete_type_error (location_t, const_tree, const_tree);
>  extern tree lhd_type_promotes_to (tree);
>  extern void lhd_register_builtin_type (tree, const char *);
>  extern bool lhd_decl_ok_for_sibcall (const_tree);
> diff --git gcc/langhooks.c gcc/langhooks.c
> index 7c07175..6444631 100644
> --- gcc/langhooks.c
> +++ gcc/langhooks.c
> @@ -199,7 +199,8 @@ lhd_register_builtin_type (tree ARG_UNUSED (type),
>  
>  /* Invalid use of an incomplete type.  */
>  void
> -lhd_incomplete_type_error (const_tree ARG_UNUSED (value), const_tree type)
> +lhd_incomplete_type_error (location_t ARG_UNUSED (loc),
> +			   const_tree ARG_UNUSED (value), const_tree type)
>  {
>    gcc_assert (TREE_CODE (type) == ERROR_MARK);
>    return;
> diff --git gcc/langhooks.h gcc/langhooks.h
> index bcfd389..0593424 100644
> --- gcc/langhooks.h
> +++ gcc/langhooks.h
> @@ -100,8 +100,9 @@ struct lang_hooks_for_types
>    /* This routine is called in tree.c to print an error message for
>       invalid use of an incomplete type.  VALUE is the expression that
>       was used (or 0 if that isn't known) and TYPE is the type that was
> -     invalid.  */
> -  void (*incomplete_type_error) (const_tree value, const_tree type);
> +     invalid.  LOC is the location of the use.  */
> +  void (*incomplete_type_error) (location_t loc, const_tree value,
> +				 const_tree type);
>  
>    /* Called from assign_temp to return the maximum size, if there is one,
>       for a type.  */
> diff --git gcc/testsuite/c-c++-common/pr70756-2.c gcc/testsuite/c-c++-common/pr70756-2.c
> index e69de29..b7df3b7 100644
> --- gcc/testsuite/c-c++-common/pr70756-2.c
> +++ gcc/testsuite/c-c++-common/pr70756-2.c
> @@ -0,0 +1,12 @@
> +/* PR c/70756 */
> +/* { dg-do compile } */
> +/* { dg-options "-Wpointer-arith" } */
> +
> +extern void bar (void);
> +
> +void
> +fn (void *p)
> +{
> +  void *a = p + 1; /* { dg-warning "15:pointer of type" } */
> +  void (*a2)(void) = &bar + 1; /* { dg-warning "27:pointer to a function" } */
> +}
> diff --git gcc/testsuite/c-c++-common/pr70756.c gcc/testsuite/c-c++-common/pr70756.c
> index e69de29..3725922 100644
> --- gcc/testsuite/c-c++-common/pr70756.c
> +++ gcc/testsuite/c-c++-common/pr70756.c
> @@ -0,0 +1,23 @@
> +/* PR c/70756 */
> +/* { dg-do compile } */
> +/* { dg-options "" } */
> +
> +enum E e; /* { dg-error "storage size|use of enum" } */
> +int (*A)[];
> +
> +void
> +fn0 (void)
> +{
> +  struct
> +  {
> +    int x;
> +    int y[];
> +  } s;
> +  1234 && &s.y + 1; /* { dg-error "16:invalid use of" } */
> +}
> +
> +void
> +fn1 (void)
> +{
> +  1234, A += 1; /* { dg-error "11:invalid use of array with unspecified bounds" } */
> +}
> diff --git gcc/tree.c gcc/tree.c
> index c565337..b63f64c 100644
> --- gcc/tree.c
> +++ gcc/tree.c
> @@ -2939,7 +2939,7 @@ ctor_to_vec (tree ctor)
>     make_unsigned_type).  */
>  
>  tree
> -size_in_bytes (const_tree type)
> +size_in_bytes_loc (location_t loc, const_tree type)
>  {
>    tree t;
>  
> @@ -2951,7 +2951,7 @@ size_in_bytes (const_tree type)
>  
>    if (t == 0)
>      {
> -      lang_hooks.types.incomplete_type_error (NULL_TREE, type);
> +      lang_hooks.types.incomplete_type_error (loc, NULL_TREE, type);
>        return size_zero_node;
>      }
>  
> diff --git gcc/tree.h gcc/tree.h
> index 6e52e3d..37324bf 100644
> --- gcc/tree.h
> +++ gcc/tree.h
> @@ -4224,7 +4224,13 @@ extern tree type_hash_canon (unsigned int, tree);
>  
>  extern tree convert (tree, tree);
>  extern unsigned int expr_align (const_tree);
> -extern tree size_in_bytes (const_tree);
> +extern tree size_in_bytes_loc (location_t, const_tree);
> +inline tree
> +size_in_bytes (const_tree t)
> +{
> +  return size_in_bytes_loc (input_location, t);
> +}
> +
>  extern HOST_WIDE_INT int_size_in_bytes (const_tree);
>  extern HOST_WIDE_INT max_int_size_in_bytes (const_tree);
>  extern tree bit_position (const_tree);
> 
> 	Marek

	Marek
Jason Merrill May 12, 2016, 3:09 p.m. UTC | #2
OK, thanks.

Jason
diff mbox

Patch

diff --git gcc/c-family/c-common.c gcc/c-family/c-common.c
index 63a18c8..150bdb2 100644
--- gcc/c-family/c-common.c
+++ gcc/c-family/c-common.c
@@ -4269,7 +4269,7 @@  pointer_int_sum (location_t loc, enum tree_code resultcode,
       size_exp = integer_one_node;
     }
   else
-    size_exp = size_in_bytes (TREE_TYPE (result_type));
+    size_exp = size_in_bytes_loc (loc, TREE_TYPE (result_type));
 
   /* We are manipulating pointer values, so we don't need to warn
      about relying on undefined signed overflow.  We disable the
diff --git gcc/c/c-decl.c gcc/c/c-decl.c
index 7094efc..48fa65c 100644
--- gcc/c/c-decl.c
+++ gcc/c/c-decl.c
@@ -5112,7 +5112,7 @@  build_compound_literal (location_t loc, tree type, tree init, bool non_const)
 
   if (type == error_mark_node || !COMPLETE_TYPE_P (type))
     {
-      c_incomplete_type_error (NULL_TREE, type);
+      c_incomplete_type_error (loc, NULL_TREE, type);
       return error_mark_node;
     }
 
diff --git gcc/c/c-tree.h gcc/c/c-tree.h
index 07d0f65..1201f42 100644
--- gcc/c/c-tree.h
+++ gcc/c/c-tree.h
@@ -588,13 +588,13 @@  extern tree c_last_sizeof_arg;
 extern struct c_switch *c_switch_stack;
 
 extern tree c_objc_common_truthvalue_conversion (location_t, tree);
-extern tree require_complete_type (tree);
+extern tree require_complete_type (location_t, tree);
 extern int same_translation_unit_p (const_tree, const_tree);
 extern int comptypes (tree, tree);
 extern int comptypes_check_different_types (tree, tree, bool *);
 extern bool c_vla_type_p (const_tree);
 extern bool c_mark_addressable (tree);
-extern void c_incomplete_type_error (const_tree, const_tree);
+extern void c_incomplete_type_error (location_t, const_tree, const_tree);
 extern tree c_type_promotes_to (tree);
 extern struct c_expr default_function_array_conversion (location_t,
 							struct c_expr);
diff --git gcc/c/c-typeck.c gcc/c/c-typeck.c
index 861aa12..b037f46 100644
--- gcc/c/c-typeck.c
+++ gcc/c/c-typeck.c
@@ -183,11 +183,12 @@  struct tagged_tu_seen_cache {
 static const struct tagged_tu_seen_cache * tagged_tu_seen_base;
 static void free_all_tagged_tu_seen_up_to (const struct tagged_tu_seen_cache *);
 
-/* Do `exp = require_complete_type (exp);' to make sure exp
-   does not have an incomplete type.  (That includes void types.)  */
+/* Do `exp = require_complete_type (loc, exp);' to make sure exp
+   does not have an incomplete type.  (That includes void types.)
+   LOC is the location of the use.  */
 
 tree
-require_complete_type (tree value)
+require_complete_type (location_t loc, tree value)
 {
   tree type = TREE_TYPE (value);
 
@@ -198,23 +199,24 @@  require_complete_type (tree value)
   if (COMPLETE_TYPE_P (type))
     return value;
 
-  c_incomplete_type_error (value, type);
+  c_incomplete_type_error (loc, value, type);
   return error_mark_node;
 }
 
 /* Print an error message for invalid use of an incomplete type.
    VALUE is the expression that was used (or 0 if that isn't known)
-   and TYPE is the type that was invalid.  */
+   and TYPE is the type that was invalid.  LOC is the location for
+   the error.  */
 
 void
-c_incomplete_type_error (const_tree value, const_tree type)
+c_incomplete_type_error (location_t loc, const_tree value, const_tree type)
 {
   /* Avoid duplicate error message.  */
   if (TREE_CODE (type) == ERROR_MARK)
     return;
 
   if (value != 0 && (VAR_P (value) || TREE_CODE (value) == PARM_DECL))
-    error ("%qD has an incomplete type %qT", value, type);
+    error_at (loc, "%qD has an incomplete type %qT", value, type);
   else
     {
     retry:
@@ -228,7 +230,7 @@  c_incomplete_type_error (const_tree value, const_tree type)
 	  break;
 
 	case VOID_TYPE:
-	  error ("invalid use of void expression");
+	  error_at (loc, "invalid use of void expression");
 	  return;
 
 	case ARRAY_TYPE:
@@ -236,13 +238,13 @@  c_incomplete_type_error (const_tree value, const_tree type)
 	    {
 	      if (TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL)
 		{
-		  error ("invalid use of flexible array member");
+		  error_at (loc, "invalid use of flexible array member");
 		  return;
 		}
 	      type = TREE_TYPE (type);
 	      goto retry;
 	    }
-	  error ("invalid use of array with unspecified bounds");
+	  error_at (loc, "invalid use of array with unspecified bounds");
 	  return;
 
 	default:
@@ -250,10 +252,10 @@  c_incomplete_type_error (const_tree value, const_tree type)
 	}
 
       if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
-	error ("invalid use of undefined type %qT", type);
+	error_at (loc, "invalid use of undefined type %qT", type);
       else
 	/* If this type has a typedef-name, the TYPE_NAME is a TYPE_DECL.  */
-	error ("invalid use of incomplete typedef %qT", type);
+	error_at (loc, "invalid use of incomplete typedef %qT", type);
     }
 }
 
@@ -2117,7 +2119,7 @@  default_conversion (tree exp)
       return error_mark_node;
     }
 
-  exp = require_complete_type (exp);
+  exp = require_complete_type (EXPR_LOC_OR_LOC (exp, input_location), exp);
   if (exp == error_mark_node)
     return error_mark_node;
 
@@ -2334,7 +2336,7 @@  build_component_ref (location_t loc, tree datum, tree component)
     {
       if (!COMPLETE_TYPE_P (type))
 	{
-	  c_incomplete_type_error (NULL_TREE, type);
+	  c_incomplete_type_error (loc, NULL_TREE, type);
 	  return error_mark_node;
 	}
 
@@ -2642,7 +2644,7 @@  build_array_ref (location_t loc, tree array, tree index)
 	       in an inline function.
 	       Hope it doesn't break something else.  */
 	    | TREE_THIS_VOLATILE (array));
-      ret = require_complete_type (rval);
+      ret = require_complete_type (loc, rval);
       protected_set_expr_location (ret, loc);
       if (non_lvalue)
 	ret = non_lvalue_loc (loc, ret);
@@ -3088,7 +3090,7 @@  build_function_call_vec (location_t loc, vec<location_t> arg_loc,
 		 "function with qualified void return type called");
       return result;
     }
-  return require_complete_type (result);
+  return require_complete_type (loc, result);
 }
 
 /* Like build_function_call_vec, but call also resolve_overloaded_builtin.  */
@@ -3239,7 +3241,7 @@  convert_arguments (location_t loc, vec<location_t> arg_loc, tree typelist,
       val = c_fully_fold (val, false, NULL);
       STRIP_TYPE_NOPS (val);
 
-      val = require_complete_type (val);
+      val = require_complete_type (ploc, val);
 
       if (type != 0)
 	{
@@ -4047,7 +4049,7 @@  build_unary_op (location_t location,
     arg = remove_c_maybe_const_expr (arg);
 
   if (code != ADDR_EXPR)
-    arg = require_complete_type (arg);
+    arg = require_complete_type (location, arg);
 
   typecode = TREE_CODE (TREE_TYPE (arg));
   if (typecode == ERROR_MARK)
@@ -5268,7 +5270,7 @@  build_c_cast (location_t loc, tree type, tree expr)
 
   if (!VOID_TYPE_P (type))
     {
-      value = require_complete_type (value);
+      value = require_complete_type (loc, value);
       if (value == error_mark_node)
 	return error_mark_node;
     }
@@ -5538,7 +5540,7 @@  build_modify_expr (location_t location, tree lhs, tree lhs_origtype,
   bool is_atomic_op;
 
   /* Types that aren't fully specified cannot be used in assignments.  */
-  lhs = require_complete_type (lhs);
+  lhs = require_complete_type (location, lhs);
 
   /* Avoid duplicate error messages from operands that had errors.  */
   if (TREE_CODE (lhs) == ERROR_MARK || TREE_CODE (rhs) == ERROR_MARK)
@@ -6133,7 +6135,7 @@  convert_for_assignment (location_t location, location_t expr_loc, tree type,
       error_at (location, "void value not ignored as it ought to be");
       return error_mark_node;
     }
-  rhs = require_complete_type (rhs);
+  rhs = require_complete_type (location, rhs);
   if (rhs == error_mark_node)
     return error_mark_node;
 
@@ -12550,7 +12552,7 @@  c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 
 	      t = OMP_CLAUSE_DECL (c);
 	    }
-	  t = require_complete_type (t);
+	  t = require_complete_type (OMP_CLAUSE_LOCATION (c), t);
 	  if (t == error_mark_node)
 	    {
 	      remove = true;
@@ -13361,7 +13363,7 @@  c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 
 	  if (need_complete)
 	    {
-	      t = require_complete_type (t);
+	      t = require_complete_type (OMP_CLAUSE_LOCATION (c), t);
 	      if (t == error_mark_node)
 		remove = true;
 	    }
diff --git gcc/cp/call.c gcc/cp/call.c
index e9ebdbc..a49bbb5 100644
--- gcc/cp/call.c
+++ gcc/cp/call.c
@@ -5757,7 +5757,7 @@  build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
   switch (code)
     {
     case MODIFY_EXPR:
-      return cp_build_modify_expr (arg1, code2, arg2, complain);
+      return cp_build_modify_expr (loc, arg1, code2, arg2, complain);
 
     case INDIRECT_REF:
       return cp_build_indirect_ref (arg1, RO_UNARY_STAR, complain);
diff --git gcc/cp/cp-tree.h gcc/cp/cp-tree.h
index 6665355..556c256 100644
--- gcc/cp/cp-tree.h
+++ gcc/cp/cp-tree.h
@@ -6666,7 +6666,8 @@  extern tree cp_build_c_cast			(tree, tree, tsubst_flags_t);
 extern cp_expr build_x_modify_expr		(location_t, tree,
 						 enum tree_code, tree,
 						 tsubst_flags_t);
-extern tree cp_build_modify_expr		(tree, enum tree_code, tree,
+extern tree cp_build_modify_expr		(location_t, tree,
+						 enum tree_code, tree,
 						 tsubst_flags_t);
 extern tree convert_for_initialization		(tree, tree, tree, int,
 						 impl_conv_rhs, tree, int,
@@ -6726,11 +6727,24 @@  extern tree finish_binary_fold_expr          (tree, tree, int);
 
 /* in typeck2.c */
 extern void require_complete_eh_spec_types	(tree, tree);
-extern void cxx_incomplete_type_diagnostic	(const_tree, const_tree, diagnostic_t);
-#undef cxx_incomplete_type_error
-extern void cxx_incomplete_type_error		(const_tree, const_tree);
-#define cxx_incomplete_type_error(V,T) \
-  (cxx_incomplete_type_diagnostic ((V), (T), DK_ERROR))
+extern void cxx_incomplete_type_diagnostic	(location_t, const_tree,
+						 const_tree, diagnostic_t);
+inline void
+cxx_incomplete_type_diagnostic (const_tree value, const_tree type,
+				diagnostic_t diag_kind)
+{
+  cxx_incomplete_type_diagnostic (EXPR_LOC_OR_LOC (value, input_location),
+				  value, type, diag_kind);
+}
+
+extern void cxx_incomplete_type_error		(location_t, const_tree,
+						 const_tree);
+inline void
+cxx_incomplete_type_error (const_tree value, const_tree type)
+{
+  cxx_incomplete_type_diagnostic (value, type, DK_ERROR);
+}
+
 extern void cxx_incomplete_type_inform 	        (const_tree);
 extern tree error_not_base_type			(tree, tree);
 extern tree binfo_or_else			(tree, tree);
diff --git gcc/cp/cp-ubsan.c gcc/cp/cp-ubsan.c
index be24a5c..9c8f6e6 100644
--- gcc/cp/cp-ubsan.c
+++ gcc/cp/cp-ubsan.c
@@ -299,8 +299,8 @@  cp_ubsan_dfs_initialize_vtbl_ptrs (tree binfo, void *data)
 
       /* Assign NULL to the vptr.  */
       tree vtbl = build_zero_cst (TREE_TYPE (vtbl_ptr));
-      tree stmt = cp_build_modify_expr (vtbl_ptr, NOP_EXPR, vtbl,
-					tf_warning_or_error);
+      tree stmt = cp_build_modify_expr (input_location, vtbl_ptr, NOP_EXPR,
+					vtbl, tf_warning_or_error);
       if (vptr_via_virtual_p (binfo))
 	/* If this vptr comes from a virtual base of the complete object, only
 	   clear it if we're in charge of virtual bases.  */
diff --git gcc/cp/decl2.c gcc/cp/decl2.c
index 0ea326d..22f9ede 100644
--- gcc/cp/decl2.c
+++ gcc/cp/decl2.c
@@ -3161,7 +3161,7 @@  set_guard (tree guard)
   guard_init = integer_one_node;
   if (!same_type_p (TREE_TYPE (guard_init), TREE_TYPE (guard)))
     guard_init = fold_convert (TREE_TYPE (guard), guard_init);
-  return cp_build_modify_expr (guard, NOP_EXPR, guard_init, 
+  return cp_build_modify_expr (input_location, guard, NOP_EXPR, guard_init,
 			       tf_warning_or_error);
 }
 
@@ -4346,7 +4346,8 @@  handle_tls_init (void)
   tree cond = cp_build_unary_op (TRUTH_NOT_EXPR, guard, false,
 				 tf_warning_or_error);
   finish_if_stmt_cond (cond, if_stmt);
-  finish_expr_stmt (cp_build_modify_expr (guard, NOP_EXPR, boolean_true_node,
+  finish_expr_stmt (cp_build_modify_expr (loc, guard, NOP_EXPR,
+					  boolean_true_node,
 					  tf_warning_or_error));
   for (; vars; vars = TREE_CHAIN (vars))
     {
diff --git gcc/cp/init.c gcc/cp/init.c
index 681ca12..8e7541f 100644
--- gcc/cp/init.c
+++ gcc/cp/init.c
@@ -798,7 +798,8 @@  perform_member_init (tree member, tree init)
 						tf_warning_or_error);
 
       if (init)
-	finish_expr_stmt (cp_build_modify_expr (decl, INIT_EXPR, init,
+	finish_expr_stmt (cp_build_modify_expr (input_location, decl,
+						INIT_EXPR, init,
 						tf_warning_or_error));
     }
 
@@ -1254,8 +1255,8 @@  expand_virtual_init (tree binfo, tree decl)
 
   /* Assign the vtable to the vptr.  */
   vtbl = convert_force (TREE_TYPE (vtbl_ptr), vtbl, 0, tf_warning_or_error);
-  finish_expr_stmt (cp_build_modify_expr (vtbl_ptr, NOP_EXPR, vtbl,
-					  tf_warning_or_error));
+  finish_expr_stmt (cp_build_modify_expr (input_location, vtbl_ptr, NOP_EXPR,
+					  vtbl, tf_warning_or_error));
 }
 
 /* If an exception is thrown in a constructor, those base classes already
@@ -3208,8 +3209,8 @@  build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
 
 	      ie = build_x_compound_expr_from_vec (*init, "new initializer",
 						   complain);
-	      init_expr = cp_build_modify_expr (init_expr, INIT_EXPR, ie,
-						complain);
+	      init_expr = cp_build_modify_expr (input_location, init_expr,
+						INIT_EXPR, ie, complain);
 	    }
 	  stable = stabilize_init (init_expr, &init_preeval_expr);
 	}
@@ -3596,7 +3597,7 @@  build_vec_delete_1 (tree base, tree maxindex, tree type,
 
   tbase = create_temporary_var (ptype);
   tbase_init
-    = cp_build_modify_expr (tbase, NOP_EXPR,
+    = cp_build_modify_expr (input_location, tbase, NOP_EXPR,
 			    fold_build_pointer_plus_loc (input_location,
 							 fold_convert (ptype,
 								       base),
@@ -3613,7 +3614,7 @@  build_vec_delete_1 (tree base, tree maxindex, tree type,
 			 fold_convert (ptype, base)));
   tmp = fold_build1_loc (input_location, NEGATE_EXPR, sizetype, size_exp);
   tmp = fold_build_pointer_plus (tbase, tmp);
-  tmp = cp_build_modify_expr (tbase, NOP_EXPR, tmp, complain);
+  tmp = cp_build_modify_expr (input_location, tbase, NOP_EXPR, tmp, complain);
   if (tmp == error_mark_node)
     return error_mark_node;
   body = build_compound_expr (input_location, body, tmp);
@@ -3735,8 +3736,8 @@  get_temp_regvar (tree type, tree init)
   decl = create_temporary_var (type);
   add_decl_expr (decl);
 
-  finish_expr_stmt (cp_build_modify_expr (decl, INIT_EXPR, init, 
-					  tf_warning_or_error));
+  finish_expr_stmt (cp_build_modify_expr (input_location, decl, INIT_EXPR,
+					  init, tf_warning_or_error));
 
   return decl;
 }
@@ -4000,8 +4001,8 @@  build_vec_init (tree base, tree maxindex, tree init,
 	  else if (MAYBE_CLASS_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE)
 	    one_init = build_aggr_init (baseref, elt, 0, complain);
 	  else
-	    one_init = cp_build_modify_expr (baseref, NOP_EXPR,
-					     elt, complain);
+	    one_init = cp_build_modify_expr (input_location, baseref,
+					     NOP_EXPR, elt, complain);
 	  if (one_init == error_mark_node)
 	    errors = true;
 	  if (try_const)
@@ -4128,12 +4129,12 @@  build_vec_init (tree base, tree maxindex, tree init,
 	    from = NULL_TREE;
 
 	  if (from_array == 2)
-	    elt_init = cp_build_modify_expr (to, NOP_EXPR, from, 
-					     complain);
+	    elt_init = cp_build_modify_expr (input_location, to, NOP_EXPR,
+					     from, complain);
 	  else if (type_build_ctor_call (type))
 	    elt_init = build_aggr_init (to, from, 0, complain);
 	  else if (from)
-	    elt_init = cp_build_modify_expr (to, NOP_EXPR, from,
+	    elt_init = cp_build_modify_expr (input_location, to, NOP_EXPR, from,
 					     complain);
 	  else
 	    gcc_unreachable ();
diff --git gcc/cp/method.c gcc/cp/method.c
index 0e501d9..310e7eb 100644
--- gcc/cp/method.c
+++ gcc/cp/method.c
@@ -741,7 +741,7 @@  do_build_copy_assign (tree fndecl)
 	    init = move (init);
 
 	  if (DECL_NAME (field))
-	    init = cp_build_modify_expr (comp, NOP_EXPR, init, 
+	    init = cp_build_modify_expr (input_location, comp, NOP_EXPR, init,
 					 tf_warning_or_error);
 	  else
 	    init = build2 (MODIFY_EXPR, TREE_TYPE (comp), comp, init);
@@ -1023,7 +1023,7 @@  assignable_expr (tree to, tree from)
   ++cp_unevaluated_operand;
   to = build_stub_object (to);
   from = build_stub_object (from);
-  tree r = cp_build_modify_expr (to, NOP_EXPR, from, tf_none);
+  tree r = cp_build_modify_expr (input_location, to, NOP_EXPR, from, tf_none);
   --cp_unevaluated_operand;
   return r;
 }
diff --git gcc/cp/semantics.c gcc/cp/semantics.c
index fed7e88..817ef99 100644
--- gcc/cp/semantics.c
+++ gcc/cp/semantics.c
@@ -8073,7 +8073,7 @@  finish_omp_for (location_t locus, enum tree_code code, tree declv,
 	{
 	  if (orig_incr)
 	    TREE_VEC_ELT (orig_incr, i) = incr;
-	  incr = cp_build_modify_expr (TREE_OPERAND (incr, 0),
+	  incr = cp_build_modify_expr (elocus, TREE_OPERAND (incr, 0),
 				       TREE_CODE (TREE_OPERAND (incr, 1)),
 				       TREE_OPERAND (incr, 2),
 				       tf_warning_or_error);
@@ -8107,7 +8107,8 @@  finish_omp_for (location_t locus, enum tree_code code, tree declv,
       if (!processing_template_decl)
 	{
 	  init = fold_build_cleanup_point_expr (TREE_TYPE (init), init);
-	  init = cp_build_modify_expr (decl, NOP_EXPR, init, tf_warning_or_error);
+	  init = cp_build_modify_expr (elocus, decl, NOP_EXPR, init,
+				       tf_warning_or_error);
 	}
       else
 	init = build2 (MODIFY_EXPR, void_type_node, decl, init);
diff --git gcc/cp/typeck.c gcc/cp/typeck.c
index 95c777d..0d8a980 100644
--- gcc/cp/typeck.c
+++ gcc/cp/typeck.c
@@ -43,13 +43,14 @@  static tree pfn_from_ptrmemfunc (tree);
 static tree delta_from_ptrmemfunc (tree);
 static tree convert_for_assignment (tree, tree, impl_conv_rhs, tree, int,
 				    tsubst_flags_t, int);
-static tree cp_pointer_int_sum (enum tree_code, tree, tree, tsubst_flags_t);
+static tree cp_pointer_int_sum (location_t, enum tree_code, tree, tree,
+				tsubst_flags_t);
 static tree rationalize_conditional_expr (enum tree_code, tree, 
 					  tsubst_flags_t);
 static int comp_ptr_ttypes_real (tree, tree, int);
 static bool comp_except_types (tree, tree, bool);
 static bool comp_array_types (const_tree, const_tree, bool);
-static tree pointer_diff (tree, tree, tree, tsubst_flags_t);
+static tree pointer_diff (location_t, tree, tree, tree, tsubst_flags_t);
 static tree get_delta_difference (tree, tree, bool, bool, tsubst_flags_t);
 static void casts_away_constness_r (tree *, tree *, tsubst_flags_t);
 static bool casts_away_constness (tree, tree, tsubst_flags_t);
@@ -4236,8 +4237,8 @@  cp_build_binary_op (location_t location,
       if (code0 == POINTER_TYPE && code1 == POINTER_TYPE
 	  && same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (type0),
 							TREE_TYPE (type1)))
-	return pointer_diff (op0, op1, common_pointer_type (type0, type1),
-			     complain);
+	return pointer_diff (location, op0, op1,
+			     common_pointer_type (type0, type1), complain);
       /* In all other cases except pointer - int, the usual arithmetic
 	 rules apply.  */
       else if (!(code0 == POINTER_TYPE && code1 == INTEGER_TYPE))
@@ -4260,8 +4261,8 @@  cp_build_binary_op (location_t location,
 	      result_type = TREE_TYPE (ptr_operand);
 	      break;
 	    }
-	  return cp_pointer_int_sum (code,
-				     ptr_operand, 
+	  return cp_pointer_int_sum (location, code,
+				     ptr_operand,
 				     int_operand,
 				     complain);
 	}
@@ -5226,8 +5227,8 @@  build_x_vec_perm_expr (location_t loc,
    of pointer PTROP and integer INTOP.  */
 
 static tree
-cp_pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop,
-		    tsubst_flags_t complain)
+cp_pointer_int_sum (location_t loc, enum tree_code resultcode, tree ptrop,
+		    tree intop, tsubst_flags_t complain)
 {
   tree res_type = TREE_TYPE (ptrop);
 
@@ -5238,7 +5239,7 @@  cp_pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop,
      pointer_int_sum() anyway.  */
   complete_type (TREE_TYPE (res_type));
 
-  return pointer_int_sum (input_location, resultcode, ptrop,
+  return pointer_int_sum (loc, resultcode, ptrop,
 			  intop, complain & tf_warning_or_error);
 }
 
@@ -5246,7 +5247,8 @@  cp_pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop,
    The resulting tree has type int.  */
 
 static tree
-pointer_diff (tree op0, tree op1, tree ptrtype, tsubst_flags_t complain)
+pointer_diff (location_t loc, tree op0, tree op1, tree ptrtype,
+	      tsubst_flags_t complain)
 {
   tree result;
   tree restype = ptrdiff_type_node;
@@ -5258,7 +5260,7 @@  pointer_diff (tree op0, tree op1, tree ptrtype, tsubst_flags_t complain)
   if (VOID_TYPE_P (target_type))
     {
       if (complain & tf_error)
-	permerror (input_location, "ISO C++ forbids using pointer of "
+	permerror (loc, "ISO C++ forbids using pointer of "
 		   "type %<void *%> in subtraction");
       else
 	return error_mark_node;
@@ -5266,7 +5268,7 @@  pointer_diff (tree op0, tree op1, tree ptrtype, tsubst_flags_t complain)
   if (TREE_CODE (target_type) == FUNCTION_TYPE)
     {
       if (complain & tf_error)
-	permerror (input_location, "ISO C++ forbids using pointer to "
+	permerror (loc, "ISO C++ forbids using pointer to "
 		   "a function in subtraction");
       else
 	return error_mark_node;
@@ -5274,7 +5276,7 @@  pointer_diff (tree op0, tree op1, tree ptrtype, tsubst_flags_t complain)
   if (TREE_CODE (target_type) == METHOD_TYPE)
     {
       if (complain & tf_error)
-	permerror (input_location, "ISO C++ forbids using pointer to "
+	permerror (loc, "ISO C++ forbids using pointer to "
 		   "a method in subtraction");
       else
 	return error_mark_node;
@@ -5283,7 +5285,7 @@  pointer_diff (tree op0, tree op1, tree ptrtype, tsubst_flags_t complain)
   /* First do the subtraction as integers;
      then drop through to build the divide operator.  */
 
-  op0 = cp_build_binary_op (input_location,
+  op0 = cp_build_binary_op (loc,
 			    MINUS_EXPR,
 			    cp_convert (restype, op0, complain),
 			    cp_convert (restype, op1, complain),
@@ -5293,8 +5295,8 @@  pointer_diff (tree op0, tree op1, tree ptrtype, tsubst_flags_t complain)
   if (!COMPLETE_TYPE_P (TREE_TYPE (TREE_TYPE (op1))))
     {
       if (complain & tf_error)
-	error ("invalid use of a pointer to an incomplete type in "
-	       "pointer arithmetic");
+	error_at (loc, "invalid use of a pointer to an incomplete type in "
+		  "pointer arithmetic");
       else
 	return error_mark_node;
     }
@@ -5302,19 +5304,19 @@  pointer_diff (tree op0, tree op1, tree ptrtype, tsubst_flags_t complain)
   if (pointer_to_zero_sized_aggr_p (TREE_TYPE (op1)))
     {
       if (complain & tf_error)
-	error ("arithmetic on pointer to an empty aggregate");
+	error_at (loc, "arithmetic on pointer to an empty aggregate");
       else
 	return error_mark_node;
     }
 
   op1 = (TYPE_PTROB_P (ptrtype)
-	 ? size_in_bytes (target_type)
+	 ? size_in_bytes_loc (loc, target_type)
 	 : integer_one_node);
 
   /* Do the division.  */
 
-  result = build2 (EXACT_DIV_EXPR, restype, op0,
-		   cp_convert (restype, op1, complain));
+  result = build2_loc (loc, EXACT_DIV_EXPR, restype, op0,
+		       cp_convert (restype, op1, complain));
   return result;
 }
 
@@ -7470,13 +7472,14 @@  cp_build_c_cast (tree type, tree expr, tsubst_flags_t complain)
 
 /* For use from the C common bits.  */
 tree
-build_modify_expr (location_t /*location*/,
+build_modify_expr (location_t location,
 		   tree lhs, tree /*lhs_origtype*/,
 		   enum tree_code modifycode, 
 		   location_t /*rhs_location*/, tree rhs,
 		   tree /*rhs_origtype*/)
 {
-  return cp_build_modify_expr (lhs, modifycode, rhs, tf_warning_or_error);
+  return cp_build_modify_expr (location, lhs, modifycode, rhs,
+			       tf_warning_or_error);
 }
 
 /* Build an assignment expression of lvalue LHS from value RHS.
@@ -7487,8 +7490,8 @@  build_modify_expr (location_t /*location*/,
    C++: If MODIFYCODE is INIT_EXPR, then leave references unbashed.  */
 
 tree
-cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
-		      tsubst_flags_t complain)
+cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
+		      tree rhs, tsubst_flags_t complain)
 {
   tree result;
   tree newrhs = rhs;
@@ -7510,7 +7513,7 @@  cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
 	lhs = build2 (TREE_CODE (lhs), TREE_TYPE (lhs),
 		      cp_stabilize_reference (TREE_OPERAND (lhs, 0)),
 		      TREE_OPERAND (lhs, 1));
-      newrhs = cp_build_modify_expr (TREE_OPERAND (lhs, 0),
+      newrhs = cp_build_modify_expr (loc, TREE_OPERAND (lhs, 0),
 				     modifycode, rhs, complain);
       if (newrhs == error_mark_node)
 	return error_mark_node;
@@ -7518,7 +7521,7 @@  cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
 
       /* Handle (a, b) used as an "lvalue".  */
     case COMPOUND_EXPR:
-      newrhs = cp_build_modify_expr (TREE_OPERAND (lhs, 1),
+      newrhs = cp_build_modify_expr (loc, TREE_OPERAND (lhs, 1),
 				     modifycode, rhs, complain);
       if (newrhs == error_mark_node)
 	return error_mark_node;
@@ -7530,8 +7533,8 @@  cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
 	lhs = build2 (TREE_CODE (lhs), TREE_TYPE (lhs),
 		      cp_stabilize_reference (TREE_OPERAND (lhs, 0)),
 		      TREE_OPERAND (lhs, 1));
-      newrhs = cp_build_modify_expr (TREE_OPERAND (lhs, 0), modifycode, rhs,
-				     complain);
+      newrhs = cp_build_modify_expr (loc, TREE_OPERAND (lhs, 0), modifycode,
+				     rhs, complain);
       if (newrhs == error_mark_node)
 	return error_mark_node;
       return build2 (COMPOUND_EXPR, lhstype, lhs, newrhs);
@@ -7580,9 +7583,9 @@  cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
 
 	cond = build_conditional_expr
 	  (input_location, TREE_OPERAND (lhs, 0),
-	   cp_build_modify_expr (TREE_OPERAND (lhs, 1),
+	   cp_build_modify_expr (loc, TREE_OPERAND (lhs, 1),
 				 modifycode, rhs, complain),
-	   cp_build_modify_expr (TREE_OPERAND (lhs, 2),
+	   cp_build_modify_expr (loc, TREE_OPERAND (lhs, 2),
 				 modifycode, rhs, complain),
            complain);
 
@@ -7680,9 +7683,7 @@  cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
 	  lhs = cp_stabilize_reference (lhs);
 	  rhs = rvalue (rhs);
 	  rhs = stabilize_expr (rhs, &init);
-	  newrhs = cp_build_binary_op (input_location,
-				       modifycode, lhs, rhs,
-				       complain);
+	  newrhs = cp_build_binary_op (loc, modifycode, lhs, rhs, complain);
 	  if (newrhs == error_mark_node)
 	    {
 	      if (complain & tf_error)
@@ -7893,7 +7894,7 @@  build_x_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
 	  return rval;
 	}
     }
-  return cp_build_modify_expr (lhs, modifycode, rhs, complain);
+  return cp_build_modify_expr (loc, lhs, modifycode, rhs, complain);
 }
 
 /* Helper function for get_delta_difference which assumes FROM is a base
diff --git gcc/cp/typeck2.c gcc/cp/typeck2.c
index e59ad51..1c4e832 100644
--- gcc/cp/typeck2.c
+++ gcc/cp/typeck2.c
@@ -451,8 +451,8 @@  cxx_incomplete_type_inform (const_tree type)
    type of diagnostic (see diagnostic.def).  */
 
 void
-cxx_incomplete_type_diagnostic (const_tree value, const_tree type, 
-				diagnostic_t diag_kind)
+cxx_incomplete_type_diagnostic (location_t loc, const_tree value,
+				const_tree type, diagnostic_t diag_kind)
 {
   bool is_decl = false, complained = false;
 
@@ -475,8 +475,6 @@  cxx_incomplete_type_diagnostic (const_tree value, const_tree type,
  retry:
   /* We must print an error message.  Be clever about what it says.  */
 
-  location_t loc = EXPR_LOC_OR_LOC (value, input_location);
-
   switch (TREE_CODE (type))
     {
     case RECORD_TYPE:
@@ -570,13 +568,14 @@  cxx_incomplete_type_diagnostic (const_tree value, const_tree type,
     }
 }
 
-/* Backward-compatibility interface to incomplete_type_diagnostic;
-   required by ../tree.c.  */
-#undef cxx_incomplete_type_error
+/* Print an error message for invalid use of an incomplete type.
+   VALUE is the expression that was used (or 0 if that isn't known)
+   and TYPE is the type that was invalid.  */
+
 void
-cxx_incomplete_type_error (const_tree value, const_tree type)
+cxx_incomplete_type_error (location_t loc, const_tree value, const_tree type)
 {
-  cxx_incomplete_type_diagnostic (value, type, DK_ERROR);
+  cxx_incomplete_type_diagnostic (loc, value, type, DK_ERROR);
 }
 
 
diff --git gcc/langhooks-def.h gcc/langhooks-def.h
index a2566ec..034b3b7 100644
--- gcc/langhooks-def.h
+++ gcc/langhooks-def.h
@@ -52,7 +52,7 @@  extern void lhd_print_error_function (diagnostic_context *,
 				      const char *, struct diagnostic_info *);
 extern void lhd_set_decl_assembler_name (tree);
 extern bool lhd_warn_unused_global_decl (const_tree);
-extern void lhd_incomplete_type_error (const_tree, const_tree);
+extern void lhd_incomplete_type_error (location_t, const_tree, const_tree);
 extern tree lhd_type_promotes_to (tree);
 extern void lhd_register_builtin_type (tree, const char *);
 extern bool lhd_decl_ok_for_sibcall (const_tree);
diff --git gcc/langhooks.c gcc/langhooks.c
index 7c07175..6444631 100644
--- gcc/langhooks.c
+++ gcc/langhooks.c
@@ -199,7 +199,8 @@  lhd_register_builtin_type (tree ARG_UNUSED (type),
 
 /* Invalid use of an incomplete type.  */
 void
-lhd_incomplete_type_error (const_tree ARG_UNUSED (value), const_tree type)
+lhd_incomplete_type_error (location_t ARG_UNUSED (loc),
+			   const_tree ARG_UNUSED (value), const_tree type)
 {
   gcc_assert (TREE_CODE (type) == ERROR_MARK);
   return;
diff --git gcc/langhooks.h gcc/langhooks.h
index bcfd389..0593424 100644
--- gcc/langhooks.h
+++ gcc/langhooks.h
@@ -100,8 +100,9 @@  struct lang_hooks_for_types
   /* This routine is called in tree.c to print an error message for
      invalid use of an incomplete type.  VALUE is the expression that
      was used (or 0 if that isn't known) and TYPE is the type that was
-     invalid.  */
-  void (*incomplete_type_error) (const_tree value, const_tree type);
+     invalid.  LOC is the location of the use.  */
+  void (*incomplete_type_error) (location_t loc, const_tree value,
+				 const_tree type);
 
   /* Called from assign_temp to return the maximum size, if there is one,
      for a type.  */
diff --git gcc/testsuite/c-c++-common/pr70756-2.c gcc/testsuite/c-c++-common/pr70756-2.c
index e69de29..b7df3b7 100644
--- gcc/testsuite/c-c++-common/pr70756-2.c
+++ gcc/testsuite/c-c++-common/pr70756-2.c
@@ -0,0 +1,12 @@ 
+/* PR c/70756 */
+/* { dg-do compile } */
+/* { dg-options "-Wpointer-arith" } */
+
+extern void bar (void);
+
+void
+fn (void *p)
+{
+  void *a = p + 1; /* { dg-warning "15:pointer of type" } */
+  void (*a2)(void) = &bar + 1; /* { dg-warning "27:pointer to a function" } */
+}
diff --git gcc/testsuite/c-c++-common/pr70756.c gcc/testsuite/c-c++-common/pr70756.c
index e69de29..3725922 100644
--- gcc/testsuite/c-c++-common/pr70756.c
+++ gcc/testsuite/c-c++-common/pr70756.c
@@ -0,0 +1,23 @@ 
+/* PR c/70756 */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+enum E e; /* { dg-error "storage size|use of enum" } */
+int (*A)[];
+
+void
+fn0 (void)
+{
+  struct
+  {
+    int x;
+    int y[];
+  } s;
+  1234 && &s.y + 1; /* { dg-error "16:invalid use of" } */
+}
+
+void
+fn1 (void)
+{
+  1234, A += 1; /* { dg-error "11:invalid use of array with unspecified bounds" } */
+}
diff --git gcc/tree.c gcc/tree.c
index c565337..b63f64c 100644
--- gcc/tree.c
+++ gcc/tree.c
@@ -2939,7 +2939,7 @@  ctor_to_vec (tree ctor)
    make_unsigned_type).  */
 
 tree
-size_in_bytes (const_tree type)
+size_in_bytes_loc (location_t loc, const_tree type)
 {
   tree t;
 
@@ -2951,7 +2951,7 @@  size_in_bytes (const_tree type)
 
   if (t == 0)
     {
-      lang_hooks.types.incomplete_type_error (NULL_TREE, type);
+      lang_hooks.types.incomplete_type_error (loc, NULL_TREE, type);
       return size_zero_node;
     }
 
diff --git gcc/tree.h gcc/tree.h
index 6e52e3d..37324bf 100644
--- gcc/tree.h
+++ gcc/tree.h
@@ -4224,7 +4224,13 @@  extern tree type_hash_canon (unsigned int, tree);
 
 extern tree convert (tree, tree);
 extern unsigned int expr_align (const_tree);
-extern tree size_in_bytes (const_tree);
+extern tree size_in_bytes_loc (location_t, const_tree);
+inline tree
+size_in_bytes (const_tree t)
+{
+  return size_in_bytes_loc (input_location, t);
+}
+
 extern HOST_WIDE_INT int_size_in_bytes (const_tree);
 extern HOST_WIDE_INT max_int_size_in_bytes (const_tree);
 extern tree bit_position (const_tree);