diff mbox series

[v2,3/3] c++: Improve location information in constexpr evaluation

Message ID 20230329023258.13487-4-nathanieloshead@gmail.com
State New
Headers show
Series c++: Track lifetimes in constant evaluation [PR70331, ...] | expand

Commit Message

Nathaniel Shead March 29, 2023, 2:32 a.m. UTC
This patch caches the current expression's location information in the
constexpr_global_ctx struct, which allows subexpressions that have lost
location information to still provide accurate diagnostics. Also
rewrites a number of 'error' calls as 'error_at' to provide more
specific location information.

The primary effect of this change is that many errors within evaluation
of a constexpr function will now point at the offending expression (with
expansion tracing information) rather than just the outermost call.

gcc/cp/ChangeLog:

	* constexpr.cc (constexpr_global_ctx): New field for cached
	tree location, defaulting to input_location.
	(cxx_eval_internal_function): Fall back to ctx->global->loc
	rather than input_location.
	(modifying_const_object_error): Likewise.
	(cxx_eval_dynamic_cast_fn): Likewise.
	(eval_and_check_array_index): Likewise.
	(cxx_eval_array_reference): Likewise.
	(cxx_eval_bit_field_ref): Likewise.
	(cxx_eval_component_reference): Likewise.
	(cxx_eval_indirect_ref): Likewise.
	(cxx_eval_store_expression): Likewise.
	(cxx_eval_increment_expression): Likewise.
	(cxx_eval_loop_expr): Likewise.
	(cxx_eval_binary_expression): Likewise.
	(cxx_eval_constant_expression): Cache location of trees for use
        in errors, and prefer it instead of input_location.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp0x/constexpr-48089.C: Updated diagnostic locations.
	* g++.dg/cpp0x/constexpr-diag3.C: Likewise.
	* g++.dg/cpp0x/constexpr-ice20.C: Likewise.
	* g++.dg/cpp1y/constexpr-89481.C: Likewise.
	* g++.dg/cpp1y/constexpr-lifetime1.C: Likewise.
	* g++.dg/cpp1y/constexpr-lifetime2.C: Likewise.
	* g++.dg/cpp1y/constexpr-lifetime3.C: Likewise.
	* g++.dg/cpp1y/constexpr-lifetime4.C: Likewise.
	* g++.dg/cpp1y/constexpr-lifetime5.C: Likewise.
	* g++.dg/cpp1y/constexpr-union5.C: Likewise.
	* g++.dg/cpp1y/pr68180.C: Likewise.
	* g++.dg/cpp1z/constexpr-lambda6.C: Likewise.
	* g++.dg/cpp2a/bit-cast11.C: Likewise.
	* g++.dg/cpp2a/bit-cast12.C: Likewise.
	* g++.dg/cpp2a/bit-cast14.C: Likewise.
	* g++.dg/cpp2a/constexpr-98122.C: Likewise.
	* g++.dg/cpp2a/constexpr-dynamic17.C: Likewise.
	* g++.dg/cpp2a/constexpr-init1.C: Likewise.
	* g++.dg/cpp2a/constexpr-new12.C: Likewise.
	* g++.dg/cpp2a/constexpr-new3.C: Likewise.
	* g++.dg/ext/constexpr-vla2.C: Likewise.
	* g++.dg/ext/constexpr-vla3.C: Likewise.
	* g++.dg/ubsan/pr63956.C: Likewise.

libstdc++/ChangeLog:

	* testsuite/25_algorithms/equal/constexpr_neg.cc: Updated
	diagnostics locations.

Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
---
 gcc/cp/constexpr.cc                           | 83 +++++++++++--------
 gcc/testsuite/g++.dg/cpp0x/constexpr-48089.C  | 10 +--
 gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C  |  2 +-
 gcc/testsuite/g++.dg/cpp0x/constexpr-ice20.C  |  4 +-
 gcc/testsuite/g++.dg/cpp1y/constexpr-89481.C  |  3 +-
 .../g++.dg/cpp1y/constexpr-lifetime1.C        |  1 +
 .../g++.dg/cpp1y/constexpr-lifetime2.C        |  4 +-
 .../g++.dg/cpp1y/constexpr-lifetime3.C        |  4 +-
 .../g++.dg/cpp1y/constexpr-lifetime4.C        |  2 +-
 .../g++.dg/cpp1y/constexpr-lifetime5.C        |  4 +-
 gcc/testsuite/g++.dg/cpp1y/constexpr-union5.C |  4 +-
 gcc/testsuite/g++.dg/cpp1y/pr68180.C          |  4 +-
 .../g++.dg/cpp1z/constexpr-lambda6.C          |  4 +-
 gcc/testsuite/g++.dg/cpp2a/bit-cast11.C       | 10 +--
 gcc/testsuite/g++.dg/cpp2a/bit-cast12.C       | 10 +--
 gcc/testsuite/g++.dg/cpp2a/bit-cast14.C       | 14 ++--
 gcc/testsuite/g++.dg/cpp2a/constexpr-98122.C  |  4 +-
 .../g++.dg/cpp2a/constexpr-dynamic17.C        |  5 +-
 gcc/testsuite/g++.dg/cpp2a/constexpr-init1.C  |  5 +-
 gcc/testsuite/g++.dg/cpp2a/constexpr-new12.C  |  6 +-
 gcc/testsuite/g++.dg/cpp2a/constexpr-new3.C   | 10 +--
 gcc/testsuite/g++.dg/ext/constexpr-vla2.C     |  4 +-
 gcc/testsuite/g++.dg/ext/constexpr-vla3.C     |  4 +-
 gcc/testsuite/g++.dg/ubsan/pr63956.C          |  4 +-
 .../25_algorithms/equal/constexpr_neg.cc      |  7 +-
 25 files changed, 111 insertions(+), 101 deletions(-)

Comments

Patrick Palka June 23, 2023, 5:09 p.m. UTC | #1
On Wed, 29 Mar 2023, Nathaniel Shead via Gcc-patches wrote:

> This patch caches the current expression's location information in the
> constexpr_global_ctx struct, which allows subexpressions that have lost
> location information to still provide accurate diagnostics. Also
> rewrites a number of 'error' calls as 'error_at' to provide more
> specific location information.
> 
> The primary effect of this change is that many errors within evaluation
> of a constexpr function will now point at the offending expression (with
> expansion tracing information) rather than just the outermost call.

This seems like a great improvement!

In other parts of the frontend, e.g. during substitution from
tsubst_expr or tsubst_copy_and_build, we do something similar by
setting/restoring input_location directly.  (We've since added the RAII
class iloc_sentinel for this.)  I wonder if that'd be preferable here?

> 
> gcc/cp/ChangeLog:
> 
> 	* constexpr.cc (constexpr_global_ctx): New field for cached
> 	tree location, defaulting to input_location.
> 	(cxx_eval_internal_function): Fall back to ctx->global->loc
> 	rather than input_location.
> 	(modifying_const_object_error): Likewise.
> 	(cxx_eval_dynamic_cast_fn): Likewise.
> 	(eval_and_check_array_index): Likewise.
> 	(cxx_eval_array_reference): Likewise.
> 	(cxx_eval_bit_field_ref): Likewise.
> 	(cxx_eval_component_reference): Likewise.
> 	(cxx_eval_indirect_ref): Likewise.
> 	(cxx_eval_store_expression): Likewise.
> 	(cxx_eval_increment_expression): Likewise.
> 	(cxx_eval_loop_expr): Likewise.
> 	(cxx_eval_binary_expression): Likewise.
> 	(cxx_eval_constant_expression): Cache location of trees for use
>         in errors, and prefer it instead of input_location.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/cpp0x/constexpr-48089.C: Updated diagnostic locations.
> 	* g++.dg/cpp0x/constexpr-diag3.C: Likewise.
> 	* g++.dg/cpp0x/constexpr-ice20.C: Likewise.
> 	* g++.dg/cpp1y/constexpr-89481.C: Likewise.
> 	* g++.dg/cpp1y/constexpr-lifetime1.C: Likewise.
> 	* g++.dg/cpp1y/constexpr-lifetime2.C: Likewise.
> 	* g++.dg/cpp1y/constexpr-lifetime3.C: Likewise.
> 	* g++.dg/cpp1y/constexpr-lifetime4.C: Likewise.
> 	* g++.dg/cpp1y/constexpr-lifetime5.C: Likewise.
> 	* g++.dg/cpp1y/constexpr-union5.C: Likewise.
> 	* g++.dg/cpp1y/pr68180.C: Likewise.
> 	* g++.dg/cpp1z/constexpr-lambda6.C: Likewise.
> 	* g++.dg/cpp2a/bit-cast11.C: Likewise.
> 	* g++.dg/cpp2a/bit-cast12.C: Likewise.
> 	* g++.dg/cpp2a/bit-cast14.C: Likewise.
> 	* g++.dg/cpp2a/constexpr-98122.C: Likewise.
> 	* g++.dg/cpp2a/constexpr-dynamic17.C: Likewise.
> 	* g++.dg/cpp2a/constexpr-init1.C: Likewise.
> 	* g++.dg/cpp2a/constexpr-new12.C: Likewise.
> 	* g++.dg/cpp2a/constexpr-new3.C: Likewise.
> 	* g++.dg/ext/constexpr-vla2.C: Likewise.
> 	* g++.dg/ext/constexpr-vla3.C: Likewise.
> 	* g++.dg/ubsan/pr63956.C: Likewise.
> 
> libstdc++/ChangeLog:
> 
> 	* testsuite/25_algorithms/equal/constexpr_neg.cc: Updated
> 	diagnostics locations.
> 
> Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
> ---
>  gcc/cp/constexpr.cc                           | 83 +++++++++++--------
>  gcc/testsuite/g++.dg/cpp0x/constexpr-48089.C  | 10 +--
>  gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C  |  2 +-
>  gcc/testsuite/g++.dg/cpp0x/constexpr-ice20.C  |  4 +-
>  gcc/testsuite/g++.dg/cpp1y/constexpr-89481.C  |  3 +-
>  .../g++.dg/cpp1y/constexpr-lifetime1.C        |  1 +
>  .../g++.dg/cpp1y/constexpr-lifetime2.C        |  4 +-
>  .../g++.dg/cpp1y/constexpr-lifetime3.C        |  4 +-
>  .../g++.dg/cpp1y/constexpr-lifetime4.C        |  2 +-
>  .../g++.dg/cpp1y/constexpr-lifetime5.C        |  4 +-
>  gcc/testsuite/g++.dg/cpp1y/constexpr-union5.C |  4 +-
>  gcc/testsuite/g++.dg/cpp1y/pr68180.C          |  4 +-
>  .../g++.dg/cpp1z/constexpr-lambda6.C          |  4 +-
>  gcc/testsuite/g++.dg/cpp2a/bit-cast11.C       | 10 +--
>  gcc/testsuite/g++.dg/cpp2a/bit-cast12.C       | 10 +--
>  gcc/testsuite/g++.dg/cpp2a/bit-cast14.C       | 14 ++--
>  gcc/testsuite/g++.dg/cpp2a/constexpr-98122.C  |  4 +-
>  .../g++.dg/cpp2a/constexpr-dynamic17.C        |  5 +-
>  gcc/testsuite/g++.dg/cpp2a/constexpr-init1.C  |  5 +-
>  gcc/testsuite/g++.dg/cpp2a/constexpr-new12.C  |  6 +-
>  gcc/testsuite/g++.dg/cpp2a/constexpr-new3.C   | 10 +--
>  gcc/testsuite/g++.dg/ext/constexpr-vla2.C     |  4 +-
>  gcc/testsuite/g++.dg/ext/constexpr-vla3.C     |  4 +-
>  gcc/testsuite/g++.dg/ubsan/pr63956.C          |  4 +-
>  .../25_algorithms/equal/constexpr_neg.cc      |  7 +-
>  25 files changed, 111 insertions(+), 101 deletions(-)
> 
> diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
> index bdbc12144a7..74045477a92 100644
> --- a/gcc/cp/constexpr.cc
> +++ b/gcc/cp/constexpr.cc
> @@ -1165,10 +1165,12 @@ public:
>    hash_set<tree> *modifiable;
>    /* Number of heap VAR_DECL deallocations.  */
>    unsigned heap_dealloc_count;
> +  /* Current location in case subtree has no location information.  */
> +  location_t loc;
>    /* Constructor.  */
>    constexpr_global_ctx ()
>      : constexpr_ops_count (0), cleanups (NULL), modifiable (nullptr),
> -      heap_dealloc_count (0) {}
> +      heap_dealloc_count (0), loc (input_location) {}
>  
>   tree get_value (tree t)
>    {
> @@ -2113,7 +2115,7 @@ cxx_eval_internal_function (const constexpr_ctx *ctx, tree t,
>  
>      default:
>        if (!ctx->quiet)
> -	error_at (cp_expr_loc_or_input_loc (t),
> +	error_at (cp_expr_loc_or_loc (t, ctx->global->loc),
>  		  "call to internal function %qE", t);
>        *non_constant_p = true;
>        return t;
> @@ -2128,7 +2130,7 @@ cxx_eval_internal_function (const constexpr_ctx *ctx, tree t,
>  
>    if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST)
>      {
> -      location_t loc = cp_expr_loc_or_input_loc (t);
> +      location_t loc = cp_expr_loc_or_loc (t, ctx->global->loc);
>        tree type = TREE_TYPE (TREE_TYPE (t));
>        tree result = fold_binary_loc (loc, opcode, type,
>  				     fold_convert_loc (loc, type, arg0),
> @@ -2164,9 +2166,9 @@ clear_no_implicit_zero (tree ctor)
>     EXPR is the MODIFY_EXPR expression performing the modification.  */
>  
>  static void
> -modifying_const_object_error (tree expr, tree obj)
> +modifying_const_object_error (const constexpr_ctx* ctx, tree expr, tree obj)
>  {
> -  location_t loc = cp_expr_loc_or_input_loc (expr);
> +  location_t loc = cp_expr_loc_or_loc (expr, ctx->global->loc);
>    auto_diagnostic_group d;
>    error_at (loc, "modifying a const object %qE is not allowed in "
>  	    "a constant expression", TREE_OPERAND (expr, 0));
> @@ -2358,7 +2360,7 @@ cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call,
>    tree obj = CALL_EXPR_ARG (call, 0);
>    tree type = CALL_EXPR_ARG (call, 2);
>    HOST_WIDE_INT hint = int_cst_value (CALL_EXPR_ARG (call, 3));
> -  location_t loc = cp_expr_loc_or_input_loc (call);
> +  location_t loc = cp_expr_loc_or_loc (call, ctx->global->loc);
>  
>    /* Get the target type of the dynamic_cast.  */
>    gcc_assert (TREE_CODE (type) == ADDR_EXPR);
> @@ -3656,7 +3658,7 @@ cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t,
>        && integer_zerop (lhs) && !integer_zerop (rhs))
>      {
>        if (!ctx->quiet)
> -	error ("arithmetic involving a null pointer in %qE", lhs);
> +	error_at (loc, "arithmetic involving a null pointer in %qE", lhs);
>        *non_constant_p = true;
>        return t;
>      }
> @@ -4149,7 +4151,7 @@ eval_and_check_array_index (const constexpr_ctx *ctx,
>  			    tree t, bool allow_one_past,
>  			    bool *non_constant_p, bool *overflow_p)
>  {
> -  location_t loc = cp_expr_loc_or_input_loc (t);
> +  location_t loc = cp_expr_loc_or_loc (t, ctx->global->loc);
>    tree ary = TREE_OPERAND (t, 0);
>    t = TREE_OPERAND (t, 1);
>    tree index = cxx_eval_constant_expression (ctx, t, vc_prvalue,
> @@ -4187,6 +4189,7 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
>  			  value_cat lval,
>  			  bool *non_constant_p, bool *overflow_p)
>  {
> +  location_t loc = cp_expr_loc_or_loc (t, ctx->global->loc);
>    tree oldary = TREE_OPERAND (t, 0);
>    tree ary = cxx_eval_constant_expression (ctx, oldary,
>  					   lval,
> @@ -4274,7 +4277,7 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
>  	 building; if there's no initializer for this element yet,
>  	 that's an error.  */
>        if (!ctx->quiet)
> -	error ("accessing uninitialized array element");
> +	error_at (loc, "accessing uninitialized array element");
>        *non_constant_p = true;
>        return t;
>      }
> @@ -4323,13 +4326,14 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
>    tree whole = cxx_eval_constant_expression (ctx, orig_whole,
>  					     lval,
>  					     non_constant_p, overflow_p);
> +  location_t loc = cp_expr_loc_or_loc (whole, ctx->global->loc);
>    if (*non_constant_p)
>      return t;
>    if (INDIRECT_REF_P (whole)
>        && integer_zerop (TREE_OPERAND (whole, 0)))
>      {
>        if (!ctx->quiet)
> -	error ("dereferencing a null pointer in %qE", orig_whole);
> +	error_at (loc, "dereferencing a null pointer in %qE", orig_whole);
>        *non_constant_p = true;
>        return t;
>      }
> @@ -4348,7 +4352,7 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
>    if (TREE_CODE (whole) != CONSTRUCTOR)
>      {
>        if (!ctx->quiet)
> -	error ("%qE is not a constant expression", orig_whole);
> +	error_at (loc, "%qE is not a constant expression", orig_whole);
>        *non_constant_p = true;
>        return t;
>      }
> @@ -4356,7 +4360,7 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
>        && DECL_MUTABLE_P (part))
>      {
>        if (!ctx->quiet)
> -	error ("mutable %qD is not usable in a constant expression", part);
> +	error_at (loc, "mutable %qD is not usable in a constant expression", part);
>        *non_constant_p = true;
>        return t;
>      }
> @@ -4386,10 +4390,10 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
>  	{
>  	  constructor_elt *cep = CONSTRUCTOR_ELT (whole, 0);
>  	  if (cep->value == NULL_TREE)
> -	    error ("accessing uninitialized member %qD", part);
> +	    error_at (loc, "accessing uninitialized member %qD", part);
>  	  else
> -	    error ("accessing %qD member instead of initialized %qD member in "
> -		   "constant expression", part, cep->index);
> +	    error_at (loc, "accessing %qD member instead of initialized %qD member "
> +		      "in constant expression", part, cep->index);
>  	}
>        *non_constant_p = true;
>        return t;
> @@ -4408,7 +4412,7 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
>  	 building; if there's no initializer for this member yet, that's an
>  	 error.  */
>        if (!ctx->quiet)
> -	error ("accessing uninitialized member %qD", part);
> +	error_at (loc, "accessing uninitialized member %qD", part);
>        *non_constant_p = true;
>        return t;
>      }
> @@ -4436,6 +4440,7 @@ cxx_eval_bit_field_ref (const constexpr_ctx *ctx, tree t,
>    tree whole = cxx_eval_constant_expression (ctx, orig_whole,
>  					     lval,
>  					     non_constant_p, overflow_p);
> +  location_t loc = cp_expr_loc_or_loc (t, ctx->global->loc);
>    tree start, field, value;
>    unsigned HOST_WIDE_INT i;
>  
> @@ -4448,7 +4453,7 @@ cxx_eval_bit_field_ref (const constexpr_ctx *ctx, tree t,
>        && TREE_CODE (whole) != CONSTRUCTOR)
>      {
>        if (!ctx->quiet)
> -	error ("%qE is not a constant expression", orig_whole);
> +	error_at (loc, "%qE is not a constant expression", orig_whole);
>        *non_constant_p = true;
>      }
>    if (*non_constant_p)
> @@ -4460,7 +4465,7 @@ cxx_eval_bit_field_ref (const constexpr_ctx *ctx, tree t,
>  				 TREE_OPERAND (t, 1), TREE_OPERAND (t, 2)))
>  	return r;
>        if (!ctx->quiet)
> -	error ("%qE is not a constant expression", orig_whole);
> +	error_at (loc, "%qE is not a constant expression", orig_whole);
>        *non_constant_p = true;
>        return t;
>      }
> @@ -5609,6 +5614,7 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
>  		       value_cat lval,
>  		       bool *non_constant_p, bool *overflow_p)
>  {
> +  location_t loc = cp_expr_loc_or_loc (t, ctx->global->loc);
>    tree orig_op0 = TREE_OPERAND (t, 0);
>    bool empty_base = false;
>  
> @@ -5639,7 +5645,7 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
>        if (!lval && integer_zerop (op0))
>  	{
>  	  if (!ctx->quiet)
> -	    error ("dereferencing a null pointer");
> +	    error_at (loc, "dereferencing a null pointer");
>  	  *non_constant_p = true;
>  	  return t;
>  	}
> @@ -5658,8 +5664,7 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
>  			  (TREE_TYPE (TREE_TYPE (sub)), TREE_TYPE (t)));
>  	      /* DR 1188 says we don't have to deal with this.  */
>  	      if (!ctx->quiet)
> -		error_at (cp_expr_loc_or_input_loc (t),
> -			  "accessing value of %qE through a %qT glvalue in a "
> +		error_at (loc, "accessing value of %qE through a %qT glvalue in a "
>  			  "constant expression", build_fold_indirect_ref (sub),
>  			  TREE_TYPE (t));
>  	      *non_constant_p = true;
> @@ -5906,6 +5911,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
>  			   value_cat lval,
>  			   bool *non_constant_p, bool *overflow_p)
>  {
> +  location_t loc = cp_expr_loc_or_loc (t, ctx->global->loc);
>    constexpr_ctx new_ctx = *ctx;
>  
>    tree init = TREE_OPERAND (t, 1);
> @@ -6030,7 +6036,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
>        /* A constant-expression cannot modify objects from outside the
>  	 constant-expression.  */
>        if (!ctx->quiet)
> -	error ("modification of %qE is not a constant expression", object);
> +	error_at (loc, "modification of %qE is not a constant expression", object);
>        *non_constant_p = true;
>        return t;
>      }
> @@ -6128,7 +6134,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
>  	  if (cxx_dialect < cxx20)
>  	    {
>  	      if (!ctx->quiet)
> -		error_at (cp_expr_loc_or_input_loc (t),
> +		error_at (cp_expr_loc_or_loc (t, ctx->global->loc),
>  			  "change of the active member of a union "
>  			  "from %qD to %qD",
>  			  CONSTRUCTOR_ELT (*valp, 0)->index,
> @@ -6141,7 +6147,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
>  	      /* Diagnose changing the active union member while the union
>  		 is in the process of being initialized.  */
>  	      if (!ctx->quiet)
> -		error_at (cp_expr_loc_or_input_loc (t),
> +		error_at (cp_expr_loc_or_loc (t, ctx->global->loc),
>  			  "change of the active member of a union "
>  			  "from %qD to %qD during initialization",
>  			  CONSTRUCTOR_ELT (*valp, 0)->index,
> @@ -6224,7 +6230,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
>        if (fail)
>  	{
>  	  if (!ctx->quiet)
> -	    modifying_const_object_error (t, const_object_being_modified);
> +	    modifying_const_object_error (ctx, t, const_object_being_modified);
>  	  *non_constant_p = true;
>  	  return t;
>  	}
> @@ -6381,6 +6387,8 @@ cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t,
>    tree offset = TREE_OPERAND (t, 1);
>    gcc_assert (TREE_CONSTANT (offset));
>  
> +  location_t loc = cp_expr_loc_or_loc (t, ctx->global->loc);
> +
>    /* OFFSET is constant, but perhaps not constant enough.  We need to
>       e.g. bash FLOAT_EXPRs to REAL_CSTs.  */
>    offset = fold_simple (offset);
> @@ -6428,8 +6436,7 @@ cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t,
>      VERIFY_CONSTANT (mod);
>  
>    /* Storing the modified value.  */
> -  tree store = build2_loc (cp_expr_loc_or_loc (t, input_location),
> -			   MODIFY_EXPR, type, op, mod);
> +  tree store = build2_loc (loc, MODIFY_EXPR, type, op, mod);
>    mod = cxx_eval_constant_expression (ctx, store, lval,
>  				      non_constant_p, overflow_p);
>    ggc_free (store);
> @@ -6602,6 +6609,7 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t,
>  		    bool *non_constant_p, bool *overflow_p,
>  		    tree *jump_target)
>  {
> +  location_t loc = cp_expr_loc_or_loc (t, ctx->global->loc);
>    constexpr_ctx new_ctx = *ctx;
>    tree local_target;
>    if (!jump_target)
> @@ -6691,7 +6699,7 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t,
>        if (++count >= constexpr_loop_limit)
>  	{
>  	  if (!ctx->quiet)
> -	    error_at (cp_expr_loc_or_input_loc (t),
> +	    error_at (loc,
>  		      "%<constexpr%> loop iteration count exceeds limit of %d "
>  		      "(use %<-fconstexpr-loop-limit=%> to increase the limit)",
>  		      constexpr_loop_limit);
> @@ -6950,7 +6958,10 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
>        return t;
>      }
>  
> -  location_t loc = cp_expr_loc_or_input_loc (t);
> +  /* Track current location, propagating down from parent calls
> +     in case this expression has no location information.  */
> +  location_t loc = cp_expr_loc_or_loc (t, ctx->global->loc);
> +  ctx->global->loc = loc;
>  
>    STRIP_ANY_LOCATION_WRAPPER (t);
>  
> @@ -6973,8 +6984,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
>  	  && !integer_zerop (t))
>  	{
>  	  if (!ctx->quiet)
> -	    error ("value %qE of type %qT is not a constant expression",
> -		   t, TREE_TYPE (t));
> +	    error_at (loc, "value %qE of type %qT is not a constant expression",
> +		      t, TREE_TYPE (t));
>  	  *non_constant_p = true;
>  	}
>  
> @@ -7222,8 +7233,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
>  	    if (!ctx->quiet)
>  	      {
>  		auto_diagnostic_group d;
> -		error ("temporary of non-literal type %qT in a "
> -		       "constant expression", type);
> +		error_at (loc, "temporary of non-literal type %qT in a "
> +			  "constant expression", type);
>  		explain_non_literal_class (type);
>  	      }
>  	    *non_constant_p = true;
> @@ -8025,8 +8036,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
>  	if (function_concept_p (tmpl))
>  	  {
>  	    if (!ctx->quiet)
> -	      error_at (cp_expr_loc_or_input_loc (t),
> -			"function concept must be called");
> +	      error_at (loc, "function concept must be called");
>  	    r = error_mark_node;
>  	    break;
>  	  }
> @@ -8121,6 +8131,9 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
>        break;
>      }
>  
> +  /* Reset current location in case it was modified in child calls.  */
> +  ctx->global->loc = loc;
> +
>    if (r == error_mark_node)
>      *non_constant_p = true;
>  
> diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-48089.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-48089.C
> index 4574eb83ff7..11630f26ffe 100644
> --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-48089.C
> +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-48089.C
> @@ -10,11 +10,11 @@
>  // R() is well-formed because i is initialized before j.
>  
>  struct s {
> -  constexpr s() : v(v) { }
> +  constexpr s() : v(v) { } // { dg-error "accessing uninitialized member" }
>    int v;
>  };
>  
> -constexpr s bang;		// { dg-error "|" }
> +constexpr s bang;  // { dg-message "in .constexpr. expansion" }
>  
>  struct R {
>    int i,j;
> @@ -26,14 +26,14 @@ constexpr R r;			// { dg-bogus "" }
>  // Ill-formed (no diagnostic required)
>  struct T {
>    int i;
> -  constexpr int f() { return i; }
> +  constexpr int f() { return i; }  // { dg-error "accessing uninitialized member" }
>    constexpr T(): i(0) { }
> -  constexpr T(const T& t) : i(f()) { } // { dg-message "" }
> +  constexpr T(const T& t) : i(f()) { }  // { dg-message "in .constexpr. expansion" }
>  };
>  
>  constexpr T t1;
>  // Ill-formed (diagnostic required)
> -constexpr T t2(t1);		// { dg-message "" }
> +constexpr T t2(t1);		// { dg-message "in .constexpr. expansion" }
>  
>  // Well-formed
>  struct U {
> diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C
> index 5eedf42ba36..50c676c56cd 100644
> --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C
> +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C
> @@ -16,7 +16,7 @@ int main()
>  struct complex 			// { dg-message "no .constexpr. constructor" "" { target { ! implicit_constexpr } } }
>  {
>    complex(double r, double i) : re(r), im(i) { }
> -  constexpr double real() const { return re; } // { dg-error "not a literal type" "" { target c++11_only } }
> +  constexpr double real() const { return re; } // { dg-error "not a literal type|not usable in a constant expression" "" { target { ! implicit_constexpr } } }
>    double imag() const { return im; }
>  
>  private:
> diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ice20.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ice20.C
> index ebaa95e5324..e4e3bf865cd 100644
> --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-ice20.C
> +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ice20.C
> @@ -2,6 +2,6 @@
>  // { dg-do compile { target c++11 } }
>  
>  typedef bool (*Function)(int);
> -constexpr bool check(int x, Function p) { return p(x); }  // { dg-message "in .constexpr. expansion of" }
> +constexpr bool check(int x, Function p) { return p(x); }  // { dg-error "lifetime" }
>  
> -static_assert(check(2, check), "");  // { dg-error "conversion|constant|lifetime|in .constexpr. expansion of" }
> +static_assert(check(2, check), "");  // { dg-error "conversion|constant|in .constexpr. expansion of" }
> diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-89481.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-89481.C
> index 8ac4ef0fd36..6f8f6a8038e 100644
> --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-89481.C
> +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-89481.C
> @@ -6,7 +6,7 @@ foo ()
>  {
>    union U { long long a; int b[2]; } u { 5LL };
>    u.b[1] = 4;		// { dg-error "change of the active member of a union from" "" { target c++17_down } }
> -  return u.b[0];
> +  return u.b[0];	// { dg-error "accessing uninitialized array element" "" { target c++2a } }
>  }
>  
>  constexpr int
> @@ -19,6 +19,5 @@ bar ()
>  
>  static_assert (foo () == 0, "");	// { dg-error "non-constant condition for static assertion" }
>  					// { dg-message "in 'constexpr' expansion of" "" { target *-*-* } .-1 }
> -					// { dg-error "accessing uninitialized array element" "" { target c++2a } .-2 }
>  static_assert (bar () == 4, "");	// { dg-error "non-constant condition for static assertion" "" { target c++17_down } }
>  					// { dg-message "in 'constexpr' expansion of" "" { target c++17_down } .-1 }
> diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime1.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime1.C
> index 43aa7c974c1..f79f1611d5f 100644
> --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime1.C
> +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime1.C
> @@ -11,3 +11,4 @@ constexpr const int& test() {
>    return local.get();
>  }
>  constexpr int x = test();  // { dg-error "accessing object outside its lifetime" }
> +
> diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime2.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime2.C
> index 22cd919fcda..2f5ae8db6d5 100644
> --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime2.C
> +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime2.C
> @@ -8,9 +8,9 @@ struct S {
>  
>  constexpr int error() {
>    const auto& local = S{}.get();  // { dg-message "note: declared here" }
> -  return local;
> +  return local;  // { dg-error "accessing object outside its lifetime" }
>  }
> -constexpr int x = error();  // { dg-error "accessing object outside its lifetime" }
> +constexpr int x = error();  // { dg-message "in .constexpr. expansion" }
>  
>  constexpr int ok() {
>    // temporary should only be destroyed after end of full-expression
> diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime3.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime3.C
> index 6329f8cf6c6..53785521d05 100644
> --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime3.C
> +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime3.C
> @@ -7,7 +7,7 @@ constexpr int f(int i) {
>      int j = 123;  // { dg-message "note: declared here" }
>      p = &j;
>    }
> -  return *p;
> +  return *p;  // { dg-error "accessing object outside its lifetime" }
>  }
>  
> -constexpr int i = f(0);  // { dg-error "accessing object outside its lifetime" }
> +constexpr int i = f(0);  // { dg-message "in .constexpr. expansion" }
> diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime4.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime4.C
> index 181a1201663..4302da1eddc 100644
> --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime4.C
> +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime4.C
> @@ -5,7 +5,7 @@ constexpr const double& test() {
>    return local;
>  }
>  
> -static_assert(test() == 3.0, "");  // { dg-error "constant|accessing object outside its lifetime" }
> +static_assert(test() == 3.0, "");  // { dg-error "non-constant condition|accessing object outside its lifetime" }
>  
>  // no deference, shouldn't error
>  static_assert((test(), true), "");
> diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C
> index ad3ef579f63..a12920c8fba 100644
> --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C
> +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C
> @@ -5,7 +5,7 @@ constexpr const int& id(int x) { return x; }  // { dg-message "note: declared he
>  
>  constexpr bool test() {
>    const int& y = id(3);
> -  return y == 3;
> +  return y == 3;  // { dg-error "accessing object outside its lifetime" }
>  }
>  
> -constexpr bool x = test();  // { dg-error "accessing object outside its lifetime" }
> +constexpr bool x = test();  // { dg-message "in .constexpr. expansion" }
> diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-union5.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-union5.C
> index 55fe9fa2f0b..3d76345d564 100644
> --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-union5.C
> +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-union5.C
> @@ -8,8 +8,8 @@ union U {
>  };
>  
>  constexpr int foo(U *up) {
> -  up->a++;
> +  up->a++; // { dg-error "accessing uninitialized member" }
>    return {42};
>  }
>  
> -extern constexpr U u = {}; // { dg-error "accessing uninitialized member" }
> +extern constexpr U u = {}; // { dg-message "in .constexpr. expansion" }
> diff --git a/gcc/testsuite/g++.dg/cpp1y/pr68180.C b/gcc/testsuite/g++.dg/cpp1y/pr68180.C
> index 9e6e5e984f9..8de1ef3936b 100644
> --- a/gcc/testsuite/g++.dg/cpp1y/pr68180.C
> +++ b/gcc/testsuite/g++.dg/cpp1y/pr68180.C
> @@ -6,11 +6,11 @@ typedef float __attribute__( ( vector_size( 16 ) ) ) float32x4_t;
>  constexpr float32x4_t fill(float x) {
>    float32x4_t v{0};
>    constexpr auto vs = sizeof(v)/sizeof(v[0]);
> -  for (auto i=0U; i<vs; ++i) v[i]=i;
> +  for (auto i=0U; i<vs; ++i) v[i]=i; // { dg-error "not a constant" }
>    return v+x;
>  }
>  
>  float32x4_t foo(float32x4_t x) {
> -  constexpr float32x4_t v = fill(1.f); // { dg-error "not a constant||in .constexpr. expansion of " }
> +  constexpr float32x4_t v = fill(1.f); // { dg-message "in .constexpr. expansion of " }
>    return x+v;
>  }
> diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda6.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda6.C
> index 214d3821299..c46c2d4c7fe 100644
> --- a/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda6.C
> +++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda6.C
> @@ -1,7 +1,7 @@
>  // Testcase from P0170R1
>  // { dg-do compile { target c++17 } }
>  
> -auto monoid = [](auto v) { return [=] { return v; }; };
> +auto monoid = [](auto v) { return [=] { return v; }; };  // { dg-error "not usable in a constant expression" }
>  auto add = [](auto m1) constexpr {
>    auto ret = m1();
>    return [=](auto m2) mutable {
> @@ -22,7 +22,7 @@ int main()
>    // member function call operator can not perform an lvalue-to-rvalue conversion
>    // on one of its subobjects (that represents its capture) in a constant
>    // expression.
> -  auto two = monoid(2);
> +  auto two = monoid(2);  // { dg-message "not declared .constexpr." }
>    if (!(two() == 2)) __builtin_abort(); // OK, not a constant expression.
>    static_assert(add(one)(one)() == two()); // { dg-error "|in .constexpr. expansion of " } two() is not a constant expression
>    static_assert(add(one)(one)() == monoid(2)()); // OK
> diff --git a/gcc/testsuite/g++.dg/cpp2a/bit-cast11.C b/gcc/testsuite/g++.dg/cpp2a/bit-cast11.C
> index a3eb31bc6c7..760c9ca40b4 100644
> --- a/gcc/testsuite/g++.dg/cpp2a/bit-cast11.C
> +++ b/gcc/testsuite/g++.dg/cpp2a/bit-cast11.C
> @@ -28,7 +28,7 @@ f3 ()
>  {
>    T t = { 1, 2 };
>    S s = __builtin_bit_cast (S, t);
> -  return s.a[1] == 0;
> +  return s.a[1] == 0;		// { dg-error "accessing uninitialized array element" }
>  }
>  
>  constexpr bool
> @@ -52,12 +52,12 @@ f6 ()
>  {
>    W t = { 1, 2 };
>    V s = __builtin_bit_cast (V, t);
> -  return s.b.a[1] == 1;
> +  return s.b.a[1] == 1;		// { dg-error "accessing uninitialized array element" }
>  }
>  
>  constexpr bool a = f1 ();
>  constexpr bool b = f2 ();
> -constexpr bool c = f3 ();	// { dg-error "accessing uninitialized array element" }
> -constexpr bool d = f4 ();
> +constexpr bool c = f3 ();	// { dg-message "in .constexpr. expansion" }
> +constexpr bool d = f4 ();	// { dg-message "in .constexpr. expansion" }
>  constexpr bool e = f5 ();
> -constexpr bool f = f6 ();	// { dg-error "accessing uninitialized array element" }
> +constexpr bool f = f6 ();	// { dg-message "in .constexpr. expansion" }
> diff --git a/gcc/testsuite/g++.dg/cpp2a/bit-cast12.C b/gcc/testsuite/g++.dg/cpp2a/bit-cast12.C
> index 9c699dd55f0..e205bc6a8c1 100644
> --- a/gcc/testsuite/g++.dg/cpp2a/bit-cast12.C
> +++ b/gcc/testsuite/g++.dg/cpp2a/bit-cast12.C
> @@ -33,7 +33,7 @@ f3 ()
>  {
>    T t = { 1, 2 };
>    S s = __builtin_bit_cast (S, t);
> -  return s.a[1] == 0;
> +  return s.a[1] == 0;		// { dg-error "accessing uninitialized array element" }
>  }
>  
>  constexpr bool
> @@ -57,12 +57,12 @@ f6 ()
>  {
>    W t = { 1, 2 };
>    V s = __builtin_bit_cast (V, t);
> -  return s.b.a[1] == 1;
> +  return s.b.a[1] == 1;		// { dg-error "accessing uninitialized array element" }
>  }
>  
>  constexpr bool a = f1 ();
>  constexpr bool b = f2 ();
> -constexpr bool c = f3 ();	// { dg-error "accessing uninitialized array element" }
> -constexpr bool d = f4 ();
> +constexpr bool c = f3 ();	// { dg-message "in .constexpr. expansion" }
> +constexpr bool d = f4 ();	// { dg-message "in .constexpr. expansion" }
>  constexpr bool e = f5 ();
> -constexpr bool f = f6 ();	// { dg-error "accessing uninitialized array element" }
> +constexpr bool f = f6 ();	// { dg-message "in .constexpr. expansion" }
> diff --git a/gcc/testsuite/g++.dg/cpp2a/bit-cast14.C b/gcc/testsuite/g++.dg/cpp2a/bit-cast14.C
> index 5e185919be4..e0cc9a39702 100644
> --- a/gcc/testsuite/g++.dg/cpp2a/bit-cast14.C
> +++ b/gcc/testsuite/g++.dg/cpp2a/bit-cast14.C
> @@ -44,7 +44,7 @@ f5 ()
>  {
>    T1 t = { 0, 0, 0, 0, 0, 0, 0 };
>    S s = __builtin_bit_cast (S, t);
> -  unsigned char a = s.a;
> +  unsigned char a = s.a;		// { dg-error "accessing uninitialized member" }
>    return true;
>  }
>  
> @@ -53,7 +53,7 @@ f6 ()
>  {
>    T2 t = { 0, 0, 0, 0, 0, 0, 0 };
>    S s = __builtin_bit_cast (S, t);
> -  unsigned char b = s.b;
> +  unsigned char b = s.b;		// { dg-error "accessing uninitialized member" }
>    return true;
>  }
>  
> @@ -62,14 +62,14 @@ f7 ()
>  {
>    T3 t = { 0, 0, 0, 0, 0, 0, 0 };
>    S s = __builtin_bit_cast (S, t);
> -  unsigned char c = s.c;
> +  unsigned char c = s.c;		// { dg-error "accessing uninitialized member" }
>    return true;
>  }
>  
>  constexpr bool a = f1 ();
>  constexpr bool b = f2 ();
>  constexpr bool c = f3 ();
> -constexpr bool d = f4 ();
> -constexpr bool e = f5 ();	// { dg-error "accessing uninitialized member" }
> -constexpr bool f = f6 ();	// { dg-error "accessing uninitialized member" }
> -constexpr bool g = f7 ();	// { dg-error "accessing uninitialized member" }
> +constexpr bool d = f4 ();	// { dg-message "in .constexpr. expansion" }
> +constexpr bool e = f5 ();	// { dg-message "in .constexpr. expansion" }
> +constexpr bool f = f6 ();	// { dg-message "in .constexpr. expansion" }
> +constexpr bool g = f7 ();	// { dg-message "in .constexpr. expansion" }
> diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-98122.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-98122.C
> index 01bdfa5bd4d..b0c91d5ef97 100644
> --- a/gcc/testsuite/g++.dg/cpp2a/constexpr-98122.C
> +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-98122.C
> @@ -9,7 +9,7 @@ bar ()
>  {
>    V f { .b = 42 };
>    constexpr auto m = &V::a;
> -  return (f.*m) == 42;
> +  return (f.*m) == 42;  // { dg-error "accessing 'V::a' member instead of initialized 'V::b' member in constant expression" }
>  }
>  
>  constexpr bool
> @@ -21,5 +21,5 @@ baz ()
>  }
>  
>  static_assert (bar (), "");	// { dg-error "non-constant condition for static assertion" }
> -				// { dg-error "accessing 'V::a' member instead of initialized 'V::b' member in constant expression" "" { target *-*-* } .-1 }
> +				// { dg-message "in .constexpr. expansion" "" { target *-*-* } .-1 }
>  static_assert (baz (), "");
> diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic17.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic17.C
> index a26678e6ed7..28facf192df 100644
> --- a/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic17.C
> +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic17.C
> @@ -25,8 +25,7 @@ struct D : B, A {
>  
>  constexpr B::B(V* v, A* a)
>  {
> -  dynamic_cast<B*>(a);
> +  dynamic_cast<B*>(a); // { dg-error "accessing uninitialized member" }
>  }
>  
> -constexpr D d; // { dg-error "accessing uninitialized member" }
> -// { dg-message "in 'constexpr' expansion of" "" { target *-*-* } .-1 }
> +constexpr D d; // { dg-message "in 'constexpr' expansion of" }
> diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-init1.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-init1.C
> index e56ecfed48a..b4e39b6f928 100644
> --- a/gcc/testsuite/g++.dg/cpp2a/constexpr-init1.C
> +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-init1.C
> @@ -52,11 +52,10 @@ constexpr int
>  fn5 ()
>  {
>    struct S { int a = 9; int b; } s;
> -  return s.b;
> +  return s.b; // { dg-error "accessing uninitialized member" }
>  }
>  
> -constexpr int b = fn5 (); // { dg-error "accessing uninitialized member" }
> -// { dg-message "in .constexpr. expansion of" "" { target *-*-* } .-1 }
> +constexpr int b = fn5 (); // { dg-message "in .constexpr. expansion of" }
>  
>  constexpr int
>  fn6 ()
> diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new12.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new12.C
> index 5a3d06a5fab..832782e1427 100644
> --- a/gcc/testsuite/g++.dg/cpp2a/constexpr-new12.C
> +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-new12.C
> @@ -17,11 +17,11 @@ struct B : A {
>  constexpr int
>  foo ()
>  {
> -  A *a = new B ();
> +  A *a = new B ();  // { dg-message "allocated here" }
>    a->a = 4;
>    delete a;
> -  int r = a->foo ();
> +  int r = a->foo ();  // { dg-error "constant expression" }
>    return r;
>  }
>  
> -constexpr auto a = foo ();	// { dg-error "constant expression" }
> +constexpr auto a = foo ();  // { dg-message "in .constexpr. expansion" }
> diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new3.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new3.C
> index 70b841208f8..3ba440fec53 100644
> --- a/gcc/testsuite/g++.dg/cpp2a/constexpr-new3.C
> +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-new3.C
> @@ -45,11 +45,10 @@ constexpr bool
>  f5 ()
>  {
>    int *p = new int;		// { dg-message "allocated here" }
> -  return *p == 1;
> +  return *p == 1;		// { dg-error "the content of uninitialized storage is not usable in a constant expression" }
>  }
>  
> -constexpr auto v5 = f5 ();	// { dg-error "the content of uninitialized storage is not usable in a constant expression" }
> -				// { dg-message "in 'constexpr' expansion of" "" { target *-*-* } .-1 }
> +constexpr auto v5 = f5 (); 	// { dg-message "in 'constexpr' expansion of" }
>  
>  constexpr bool
>  f6 ()
> @@ -57,11 +56,10 @@ f6 ()
>    int *p = new int (2);		// { dg-message "allocated here" }
>    int *q = p;
>    delete p;
> -  return *q == 2;
> +  return *q == 2;		// { dg-error "use of allocated storage after deallocation in a constant expression" }
>  }
>  
> -constexpr auto v6 = f6 ();	// { dg-error "use of allocated storage after deallocation in a constant expression" }
> -				// { dg-message "in 'constexpr' expansion of" "" { target *-*-* } .-1  }
> +constexpr auto v6 = f6 (); 	// { dg-message "in 'constexpr' expansion of" }
>  
>  constexpr int *
>  f7 ()
> diff --git a/gcc/testsuite/g++.dg/ext/constexpr-vla2.C b/gcc/testsuite/g++.dg/ext/constexpr-vla2.C
> index d4ea7c58c0d..e09a27af3de 100644
> --- a/gcc/testsuite/g++.dg/ext/constexpr-vla2.C
> +++ b/gcc/testsuite/g++.dg/ext/constexpr-vla2.C
> @@ -4,7 +4,7 @@
>  constexpr int
>  fn_bad (int n)
>  {
> -  __extension__ int a [n] = { 0 };
> +  __extension__ int a [n] = { 0 };  // { dg-error "array subscript" }
>    int z = a [0] + (n ? fn_bad (n - 1) : 0); // { dg-message "in .constexpr. expansion of " } 
>    return z;
>  }
> @@ -18,4 +18,4 @@ fn_ok (int n)
>  }
>  
>  constexpr int i1 = fn_ok (3);
> -constexpr int i2 = fn_bad (3); // { dg-error "array subscript|in .constexpr. expansion of " }
> +constexpr int i2 = fn_bad (3); // { dg-message "in .constexpr. expansion of " }
> diff --git a/gcc/testsuite/g++.dg/ext/constexpr-vla3.C b/gcc/testsuite/g++.dg/ext/constexpr-vla3.C
> index 538b576a825..6f9daa1897f 100644
> --- a/gcc/testsuite/g++.dg/ext/constexpr-vla3.C
> +++ b/gcc/testsuite/g++.dg/ext/constexpr-vla3.C
> @@ -4,11 +4,11 @@
>  constexpr int
>  foo (int n)
>  {
> -  __extension__ int a[n] = { 1, 2, 3, 4, 5, 6 };
> +  __extension__ int a[n] = { 1, 2, 3, 4, 5, 6 }; // { dg-error "array subscript" }
>    int z = 0;
>    for (int i = 0; i <= n; ++i)
>      z += a[i];
>    return z;
>  }
>  
> -constexpr int n = foo (3); // { dg-error "array subscript|in .constexpr. expansion of " }
> +constexpr int n = foo (3); // { dg-message "in .constexpr. expansion of " }
> diff --git a/gcc/testsuite/g++.dg/ubsan/pr63956.C b/gcc/testsuite/g++.dg/ubsan/pr63956.C
> index 3a1596e6e2e..0771732ef00 100644
> --- a/gcc/testsuite/g++.dg/ubsan/pr63956.C
> +++ b/gcc/testsuite/g++.dg/ubsan/pr63956.C
> @@ -100,13 +100,13 @@ constexpr int
>  fn7 (const int *a, int b)
>  {
>    if (b != 3)
> -    return fn6 (*a, b);
> +    return fn6 (*a, b); // { dg-error "null pointer" }
>    return 7;
>  }
>  
>  constexpr int n1 = 7;
>  constexpr int n2 = fn7 (&n1, 5);
> -constexpr int n3 = fn7 ((const int *) 0, 8);  // { dg-error "null pointer|in .constexpr. expansion of " }
> +constexpr int n3 = fn7 ((const int *) 0, 8);  // { dg-message "in .constexpr. expansion of " }
>  
>  constexpr int
>  fn8 (int i)
> diff --git a/libstdc++-v3/testsuite/25_algorithms/equal/constexpr_neg.cc b/libstdc++-v3/testsuite/25_algorithms/equal/constexpr_neg.cc
> index 34ca5c4805c..fd89ac0e166 100644
> --- a/libstdc++-v3/testsuite/25_algorithms/equal/constexpr_neg.cc
> +++ b/libstdc++-v3/testsuite/25_algorithms/equal/constexpr_neg.cc
> @@ -32,7 +32,7 @@ test01()
>    return outa;
>  }
>  
> -static_assert(test01()); // { dg-error "outside the bounds" }
> +static_assert(test01()); // { dg-error "non-constant condition" }
>  
>  constexpr bool
>  test02()
> @@ -44,7 +44,8 @@ test02()
>    return outa;
>  }
>  
> -static_assert(test02()); // { dg-error "outside the bounds" }
> +static_assert(test02()); // { dg-error "non-constant condition" }
>  
> -// { dg-prune-output "non-constant condition" }
> +// Errors occuring within <algorithm> internals:
> +// { dg-error "outside the bounds of array" "" { target *-*-* } 0 }
>  // { dg-prune-output "in 'constexpr'" }
> -- 
> 2.34.1
> 
>
Nathaniel Shead June 30, 2023, 3:50 p.m. UTC | #2
On Fri, Jun 23, 2023 at 01:09:14PM -0400, Patrick Palka wrote:
> On Wed, 29 Mar 2023, Nathaniel Shead via Gcc-patches wrote:
> 
> > This patch caches the current expression's location information in the
> > constexpr_global_ctx struct, which allows subexpressions that have lost
> > location information to still provide accurate diagnostics. Also
> > rewrites a number of 'error' calls as 'error_at' to provide more
> > specific location information.
> > 
> > The primary effect of this change is that many errors within evaluation
> > of a constexpr function will now point at the offending expression (with
> > expansion tracing information) rather than just the outermost call.
> 
> This seems like a great improvement!
> 
> In other parts of the frontend, e.g. during substitution from
> tsubst_expr or tsubst_copy_and_build, we do something similar by
> setting/restoring input_location directly.  (We've since added the RAII
> class iloc_sentinel for this.)  I wonder if that'd be preferable here?

I didn't consider that; I've given it a try and I think it's nicer.
Doing it this way also updated a number of 'error' calls that I hadn't
fixed up in this version; generally this meant nicer error messages, but
I had to override it for a couple of cases where I felt the errors it
raised were worse (by adding context that made no sense).

I'm still bootstrapping/regtesting but I'll send out an updated version
of this sometime tomorrow when it's done. Thanks!

> > 
> > gcc/cp/ChangeLog:
> > 
> > 	* constexpr.cc (constexpr_global_ctx): New field for cached
> > 	tree location, defaulting to input_location.
> > 	(cxx_eval_internal_function): Fall back to ctx->global->loc
> > 	rather than input_location.
> > 	(modifying_const_object_error): Likewise.
> > 	(cxx_eval_dynamic_cast_fn): Likewise.
> > 	(eval_and_check_array_index): Likewise.
> > 	(cxx_eval_array_reference): Likewise.
> > 	(cxx_eval_bit_field_ref): Likewise.
> > 	(cxx_eval_component_reference): Likewise.
> > 	(cxx_eval_indirect_ref): Likewise.
> > 	(cxx_eval_store_expression): Likewise.
> > 	(cxx_eval_increment_expression): Likewise.
> > 	(cxx_eval_loop_expr): Likewise.
> > 	(cxx_eval_binary_expression): Likewise.
> > 	(cxx_eval_constant_expression): Cache location of trees for use
> >         in errors, and prefer it instead of input_location.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > 	* g++.dg/cpp0x/constexpr-48089.C: Updated diagnostic locations.
> > 	* g++.dg/cpp0x/constexpr-diag3.C: Likewise.
> > 	* g++.dg/cpp0x/constexpr-ice20.C: Likewise.
> > 	* g++.dg/cpp1y/constexpr-89481.C: Likewise.
> > 	* g++.dg/cpp1y/constexpr-lifetime1.C: Likewise.
> > 	* g++.dg/cpp1y/constexpr-lifetime2.C: Likewise.
> > 	* g++.dg/cpp1y/constexpr-lifetime3.C: Likewise.
> > 	* g++.dg/cpp1y/constexpr-lifetime4.C: Likewise.
> > 	* g++.dg/cpp1y/constexpr-lifetime5.C: Likewise.
> > 	* g++.dg/cpp1y/constexpr-union5.C: Likewise.
> > 	* g++.dg/cpp1y/pr68180.C: Likewise.
> > 	* g++.dg/cpp1z/constexpr-lambda6.C: Likewise.
> > 	* g++.dg/cpp2a/bit-cast11.C: Likewise.
> > 	* g++.dg/cpp2a/bit-cast12.C: Likewise.
> > 	* g++.dg/cpp2a/bit-cast14.C: Likewise.
> > 	* g++.dg/cpp2a/constexpr-98122.C: Likewise.
> > 	* g++.dg/cpp2a/constexpr-dynamic17.C: Likewise.
> > 	* g++.dg/cpp2a/constexpr-init1.C: Likewise.
> > 	* g++.dg/cpp2a/constexpr-new12.C: Likewise.
> > 	* g++.dg/cpp2a/constexpr-new3.C: Likewise.
> > 	* g++.dg/ext/constexpr-vla2.C: Likewise.
> > 	* g++.dg/ext/constexpr-vla3.C: Likewise.
> > 	* g++.dg/ubsan/pr63956.C: Likewise.
> > 
> > libstdc++/ChangeLog:
> > 
> > 	* testsuite/25_algorithms/equal/constexpr_neg.cc: Updated
> > 	diagnostics locations.
> > 
> > Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
> > ---
> >  gcc/cp/constexpr.cc                           | 83 +++++++++++--------
> >  gcc/testsuite/g++.dg/cpp0x/constexpr-48089.C  | 10 +--
> >  gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C  |  2 +-
> >  gcc/testsuite/g++.dg/cpp0x/constexpr-ice20.C  |  4 +-
> >  gcc/testsuite/g++.dg/cpp1y/constexpr-89481.C  |  3 +-
> >  .../g++.dg/cpp1y/constexpr-lifetime1.C        |  1 +
> >  .../g++.dg/cpp1y/constexpr-lifetime2.C        |  4 +-
> >  .../g++.dg/cpp1y/constexpr-lifetime3.C        |  4 +-
> >  .../g++.dg/cpp1y/constexpr-lifetime4.C        |  2 +-
> >  .../g++.dg/cpp1y/constexpr-lifetime5.C        |  4 +-
> >  gcc/testsuite/g++.dg/cpp1y/constexpr-union5.C |  4 +-
> >  gcc/testsuite/g++.dg/cpp1y/pr68180.C          |  4 +-
> >  .../g++.dg/cpp1z/constexpr-lambda6.C          |  4 +-
> >  gcc/testsuite/g++.dg/cpp2a/bit-cast11.C       | 10 +--
> >  gcc/testsuite/g++.dg/cpp2a/bit-cast12.C       | 10 +--
> >  gcc/testsuite/g++.dg/cpp2a/bit-cast14.C       | 14 ++--
> >  gcc/testsuite/g++.dg/cpp2a/constexpr-98122.C  |  4 +-
> >  .../g++.dg/cpp2a/constexpr-dynamic17.C        |  5 +-
> >  gcc/testsuite/g++.dg/cpp2a/constexpr-init1.C  |  5 +-
> >  gcc/testsuite/g++.dg/cpp2a/constexpr-new12.C  |  6 +-
> >  gcc/testsuite/g++.dg/cpp2a/constexpr-new3.C   | 10 +--
> >  gcc/testsuite/g++.dg/ext/constexpr-vla2.C     |  4 +-
> >  gcc/testsuite/g++.dg/ext/constexpr-vla3.C     |  4 +-
> >  gcc/testsuite/g++.dg/ubsan/pr63956.C          |  4 +-
> >  .../25_algorithms/equal/constexpr_neg.cc      |  7 +-
> >  25 files changed, 111 insertions(+), 101 deletions(-)
> > 
> > diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
> > index bdbc12144a7..74045477a92 100644
> > --- a/gcc/cp/constexpr.cc
> > +++ b/gcc/cp/constexpr.cc
> > @@ -1165,10 +1165,12 @@ public:
> >    hash_set<tree> *modifiable;
> >    /* Number of heap VAR_DECL deallocations.  */
> >    unsigned heap_dealloc_count;
> > +  /* Current location in case subtree has no location information.  */
> > +  location_t loc;
> >    /* Constructor.  */
> >    constexpr_global_ctx ()
> >      : constexpr_ops_count (0), cleanups (NULL), modifiable (nullptr),
> > -      heap_dealloc_count (0) {}
> > +      heap_dealloc_count (0), loc (input_location) {}
> >  
> >   tree get_value (tree t)
> >    {
> > @@ -2113,7 +2115,7 @@ cxx_eval_internal_function (const constexpr_ctx *ctx, tree t,
> >  
> >      default:
> >        if (!ctx->quiet)
> > -	error_at (cp_expr_loc_or_input_loc (t),
> > +	error_at (cp_expr_loc_or_loc (t, ctx->global->loc),
> >  		  "call to internal function %qE", t);
> >        *non_constant_p = true;
> >        return t;
> > @@ -2128,7 +2130,7 @@ cxx_eval_internal_function (const constexpr_ctx *ctx, tree t,
> >  
> >    if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST)
> >      {
> > -      location_t loc = cp_expr_loc_or_input_loc (t);
> > +      location_t loc = cp_expr_loc_or_loc (t, ctx->global->loc);
> >        tree type = TREE_TYPE (TREE_TYPE (t));
> >        tree result = fold_binary_loc (loc, opcode, type,
> >  				     fold_convert_loc (loc, type, arg0),
> > @@ -2164,9 +2166,9 @@ clear_no_implicit_zero (tree ctor)
> >     EXPR is the MODIFY_EXPR expression performing the modification.  */
> >  
> >  static void
> > -modifying_const_object_error (tree expr, tree obj)
> > +modifying_const_object_error (const constexpr_ctx* ctx, tree expr, tree obj)
> >  {
> > -  location_t loc = cp_expr_loc_or_input_loc (expr);
> > +  location_t loc = cp_expr_loc_or_loc (expr, ctx->global->loc);
> >    auto_diagnostic_group d;
> >    error_at (loc, "modifying a const object %qE is not allowed in "
> >  	    "a constant expression", TREE_OPERAND (expr, 0));
> > @@ -2358,7 +2360,7 @@ cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call,
> >    tree obj = CALL_EXPR_ARG (call, 0);
> >    tree type = CALL_EXPR_ARG (call, 2);
> >    HOST_WIDE_INT hint = int_cst_value (CALL_EXPR_ARG (call, 3));
> > -  location_t loc = cp_expr_loc_or_input_loc (call);
> > +  location_t loc = cp_expr_loc_or_loc (call, ctx->global->loc);
> >  
> >    /* Get the target type of the dynamic_cast.  */
> >    gcc_assert (TREE_CODE (type) == ADDR_EXPR);
> > @@ -3656,7 +3658,7 @@ cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t,
> >        && integer_zerop (lhs) && !integer_zerop (rhs))
> >      {
> >        if (!ctx->quiet)
> > -	error ("arithmetic involving a null pointer in %qE", lhs);
> > +	error_at (loc, "arithmetic involving a null pointer in %qE", lhs);
> >        *non_constant_p = true;
> >        return t;
> >      }
> > @@ -4149,7 +4151,7 @@ eval_and_check_array_index (const constexpr_ctx *ctx,
> >  			    tree t, bool allow_one_past,
> >  			    bool *non_constant_p, bool *overflow_p)
> >  {
> > -  location_t loc = cp_expr_loc_or_input_loc (t);
> > +  location_t loc = cp_expr_loc_or_loc (t, ctx->global->loc);
> >    tree ary = TREE_OPERAND (t, 0);
> >    t = TREE_OPERAND (t, 1);
> >    tree index = cxx_eval_constant_expression (ctx, t, vc_prvalue,
> > @@ -4187,6 +4189,7 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
> >  			  value_cat lval,
> >  			  bool *non_constant_p, bool *overflow_p)
> >  {
> > +  location_t loc = cp_expr_loc_or_loc (t, ctx->global->loc);
> >    tree oldary = TREE_OPERAND (t, 0);
> >    tree ary = cxx_eval_constant_expression (ctx, oldary,
> >  					   lval,
> > @@ -4274,7 +4277,7 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
> >  	 building; if there's no initializer for this element yet,
> >  	 that's an error.  */
> >        if (!ctx->quiet)
> > -	error ("accessing uninitialized array element");
> > +	error_at (loc, "accessing uninitialized array element");
> >        *non_constant_p = true;
> >        return t;
> >      }
> > @@ -4323,13 +4326,14 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
> >    tree whole = cxx_eval_constant_expression (ctx, orig_whole,
> >  					     lval,
> >  					     non_constant_p, overflow_p);
> > +  location_t loc = cp_expr_loc_or_loc (whole, ctx->global->loc);
> >    if (*non_constant_p)
> >      return t;
> >    if (INDIRECT_REF_P (whole)
> >        && integer_zerop (TREE_OPERAND (whole, 0)))
> >      {
> >        if (!ctx->quiet)
> > -	error ("dereferencing a null pointer in %qE", orig_whole);
> > +	error_at (loc, "dereferencing a null pointer in %qE", orig_whole);
> >        *non_constant_p = true;
> >        return t;
> >      }
> > @@ -4348,7 +4352,7 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
> >    if (TREE_CODE (whole) != CONSTRUCTOR)
> >      {
> >        if (!ctx->quiet)
> > -	error ("%qE is not a constant expression", orig_whole);
> > +	error_at (loc, "%qE is not a constant expression", orig_whole);
> >        *non_constant_p = true;
> >        return t;
> >      }
> > @@ -4356,7 +4360,7 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
> >        && DECL_MUTABLE_P (part))
> >      {
> >        if (!ctx->quiet)
> > -	error ("mutable %qD is not usable in a constant expression", part);
> > +	error_at (loc, "mutable %qD is not usable in a constant expression", part);
> >        *non_constant_p = true;
> >        return t;
> >      }
> > @@ -4386,10 +4390,10 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
> >  	{
> >  	  constructor_elt *cep = CONSTRUCTOR_ELT (whole, 0);
> >  	  if (cep->value == NULL_TREE)
> > -	    error ("accessing uninitialized member %qD", part);
> > +	    error_at (loc, "accessing uninitialized member %qD", part);
> >  	  else
> > -	    error ("accessing %qD member instead of initialized %qD member in "
> > -		   "constant expression", part, cep->index);
> > +	    error_at (loc, "accessing %qD member instead of initialized %qD member "
> > +		      "in constant expression", part, cep->index);
> >  	}
> >        *non_constant_p = true;
> >        return t;
> > @@ -4408,7 +4412,7 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
> >  	 building; if there's no initializer for this member yet, that's an
> >  	 error.  */
> >        if (!ctx->quiet)
> > -	error ("accessing uninitialized member %qD", part);
> > +	error_at (loc, "accessing uninitialized member %qD", part);
> >        *non_constant_p = true;
> >        return t;
> >      }
> > @@ -4436,6 +4440,7 @@ cxx_eval_bit_field_ref (const constexpr_ctx *ctx, tree t,
> >    tree whole = cxx_eval_constant_expression (ctx, orig_whole,
> >  					     lval,
> >  					     non_constant_p, overflow_p);
> > +  location_t loc = cp_expr_loc_or_loc (t, ctx->global->loc);
> >    tree start, field, value;
> >    unsigned HOST_WIDE_INT i;
> >  
> > @@ -4448,7 +4453,7 @@ cxx_eval_bit_field_ref (const constexpr_ctx *ctx, tree t,
> >        && TREE_CODE (whole) != CONSTRUCTOR)
> >      {
> >        if (!ctx->quiet)
> > -	error ("%qE is not a constant expression", orig_whole);
> > +	error_at (loc, "%qE is not a constant expression", orig_whole);
> >        *non_constant_p = true;
> >      }
> >    if (*non_constant_p)
> > @@ -4460,7 +4465,7 @@ cxx_eval_bit_field_ref (const constexpr_ctx *ctx, tree t,
> >  				 TREE_OPERAND (t, 1), TREE_OPERAND (t, 2)))
> >  	return r;
> >        if (!ctx->quiet)
> > -	error ("%qE is not a constant expression", orig_whole);
> > +	error_at (loc, "%qE is not a constant expression", orig_whole);
> >        *non_constant_p = true;
> >        return t;
> >      }
> > @@ -5609,6 +5614,7 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
> >  		       value_cat lval,
> >  		       bool *non_constant_p, bool *overflow_p)
> >  {
> > +  location_t loc = cp_expr_loc_or_loc (t, ctx->global->loc);
> >    tree orig_op0 = TREE_OPERAND (t, 0);
> >    bool empty_base = false;
> >  
> > @@ -5639,7 +5645,7 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
> >        if (!lval && integer_zerop (op0))
> >  	{
> >  	  if (!ctx->quiet)
> > -	    error ("dereferencing a null pointer");
> > +	    error_at (loc, "dereferencing a null pointer");
> >  	  *non_constant_p = true;
> >  	  return t;
> >  	}
> > @@ -5658,8 +5664,7 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
> >  			  (TREE_TYPE (TREE_TYPE (sub)), TREE_TYPE (t)));
> >  	      /* DR 1188 says we don't have to deal with this.  */
> >  	      if (!ctx->quiet)
> > -		error_at (cp_expr_loc_or_input_loc (t),
> > -			  "accessing value of %qE through a %qT glvalue in a "
> > +		error_at (loc, "accessing value of %qE through a %qT glvalue in a "
> >  			  "constant expression", build_fold_indirect_ref (sub),
> >  			  TREE_TYPE (t));
> >  	      *non_constant_p = true;
> > @@ -5906,6 +5911,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
> >  			   value_cat lval,
> >  			   bool *non_constant_p, bool *overflow_p)
> >  {
> > +  location_t loc = cp_expr_loc_or_loc (t, ctx->global->loc);
> >    constexpr_ctx new_ctx = *ctx;
> >  
> >    tree init = TREE_OPERAND (t, 1);
> > @@ -6030,7 +6036,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
> >        /* A constant-expression cannot modify objects from outside the
> >  	 constant-expression.  */
> >        if (!ctx->quiet)
> > -	error ("modification of %qE is not a constant expression", object);
> > +	error_at (loc, "modification of %qE is not a constant expression", object);
> >        *non_constant_p = true;
> >        return t;
> >      }
> > @@ -6128,7 +6134,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
> >  	  if (cxx_dialect < cxx20)
> >  	    {
> >  	      if (!ctx->quiet)
> > -		error_at (cp_expr_loc_or_input_loc (t),
> > +		error_at (cp_expr_loc_or_loc (t, ctx->global->loc),
> >  			  "change of the active member of a union "
> >  			  "from %qD to %qD",
> >  			  CONSTRUCTOR_ELT (*valp, 0)->index,
> > @@ -6141,7 +6147,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
> >  	      /* Diagnose changing the active union member while the union
> >  		 is in the process of being initialized.  */
> >  	      if (!ctx->quiet)
> > -		error_at (cp_expr_loc_or_input_loc (t),
> > +		error_at (cp_expr_loc_or_loc (t, ctx->global->loc),
> >  			  "change of the active member of a union "
> >  			  "from %qD to %qD during initialization",
> >  			  CONSTRUCTOR_ELT (*valp, 0)->index,
> > @@ -6224,7 +6230,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
> >        if (fail)
> >  	{
> >  	  if (!ctx->quiet)
> > -	    modifying_const_object_error (t, const_object_being_modified);
> > +	    modifying_const_object_error (ctx, t, const_object_being_modified);
> >  	  *non_constant_p = true;
> >  	  return t;
> >  	}
> > @@ -6381,6 +6387,8 @@ cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t,
> >    tree offset = TREE_OPERAND (t, 1);
> >    gcc_assert (TREE_CONSTANT (offset));
> >  
> > +  location_t loc = cp_expr_loc_or_loc (t, ctx->global->loc);
> > +
> >    /* OFFSET is constant, but perhaps not constant enough.  We need to
> >       e.g. bash FLOAT_EXPRs to REAL_CSTs.  */
> >    offset = fold_simple (offset);
> > @@ -6428,8 +6436,7 @@ cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t,
> >      VERIFY_CONSTANT (mod);
> >  
> >    /* Storing the modified value.  */
> > -  tree store = build2_loc (cp_expr_loc_or_loc (t, input_location),
> > -			   MODIFY_EXPR, type, op, mod);
> > +  tree store = build2_loc (loc, MODIFY_EXPR, type, op, mod);
> >    mod = cxx_eval_constant_expression (ctx, store, lval,
> >  				      non_constant_p, overflow_p);
> >    ggc_free (store);
> > @@ -6602,6 +6609,7 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t,
> >  		    bool *non_constant_p, bool *overflow_p,
> >  		    tree *jump_target)
> >  {
> > +  location_t loc = cp_expr_loc_or_loc (t, ctx->global->loc);
> >    constexpr_ctx new_ctx = *ctx;
> >    tree local_target;
> >    if (!jump_target)
> > @@ -6691,7 +6699,7 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t,
> >        if (++count >= constexpr_loop_limit)
> >  	{
> >  	  if (!ctx->quiet)
> > -	    error_at (cp_expr_loc_or_input_loc (t),
> > +	    error_at (loc,
> >  		      "%<constexpr%> loop iteration count exceeds limit of %d "
> >  		      "(use %<-fconstexpr-loop-limit=%> to increase the limit)",
> >  		      constexpr_loop_limit);
> > @@ -6950,7 +6958,10 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
> >        return t;
> >      }
> >  
> > -  location_t loc = cp_expr_loc_or_input_loc (t);
> > +  /* Track current location, propagating down from parent calls
> > +     in case this expression has no location information.  */
> > +  location_t loc = cp_expr_loc_or_loc (t, ctx->global->loc);
> > +  ctx->global->loc = loc;
> >  
> >    STRIP_ANY_LOCATION_WRAPPER (t);
> >  
> > @@ -6973,8 +6984,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
> >  	  && !integer_zerop (t))
> >  	{
> >  	  if (!ctx->quiet)
> > -	    error ("value %qE of type %qT is not a constant expression",
> > -		   t, TREE_TYPE (t));
> > +	    error_at (loc, "value %qE of type %qT is not a constant expression",
> > +		      t, TREE_TYPE (t));
> >  	  *non_constant_p = true;
> >  	}
> >  
> > @@ -7222,8 +7233,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
> >  	    if (!ctx->quiet)
> >  	      {
> >  		auto_diagnostic_group d;
> > -		error ("temporary of non-literal type %qT in a "
> > -		       "constant expression", type);
> > +		error_at (loc, "temporary of non-literal type %qT in a "
> > +			  "constant expression", type);
> >  		explain_non_literal_class (type);
> >  	      }
> >  	    *non_constant_p = true;
> > @@ -8025,8 +8036,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
> >  	if (function_concept_p (tmpl))
> >  	  {
> >  	    if (!ctx->quiet)
> > -	      error_at (cp_expr_loc_or_input_loc (t),
> > -			"function concept must be called");
> > +	      error_at (loc, "function concept must be called");
> >  	    r = error_mark_node;
> >  	    break;
> >  	  }
> > @@ -8121,6 +8131,9 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
> >        break;
> >      }
> >  
> > +  /* Reset current location in case it was modified in child calls.  */
> > +  ctx->global->loc = loc;
> > +
> >    if (r == error_mark_node)
> >      *non_constant_p = true;
> >  
> > diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-48089.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-48089.C
> > index 4574eb83ff7..11630f26ffe 100644
> > --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-48089.C
> > +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-48089.C
> > @@ -10,11 +10,11 @@
> >  // R() is well-formed because i is initialized before j.
> >  
> >  struct s {
> > -  constexpr s() : v(v) { }
> > +  constexpr s() : v(v) { } // { dg-error "accessing uninitialized member" }
> >    int v;
> >  };
> >  
> > -constexpr s bang;		// { dg-error "|" }
> > +constexpr s bang;  // { dg-message "in .constexpr. expansion" }
> >  
> >  struct R {
> >    int i,j;
> > @@ -26,14 +26,14 @@ constexpr R r;			// { dg-bogus "" }
> >  // Ill-formed (no diagnostic required)
> >  struct T {
> >    int i;
> > -  constexpr int f() { return i; }
> > +  constexpr int f() { return i; }  // { dg-error "accessing uninitialized member" }
> >    constexpr T(): i(0) { }
> > -  constexpr T(const T& t) : i(f()) { } // { dg-message "" }
> > +  constexpr T(const T& t) : i(f()) { }  // { dg-message "in .constexpr. expansion" }
> >  };
> >  
> >  constexpr T t1;
> >  // Ill-formed (diagnostic required)
> > -constexpr T t2(t1);		// { dg-message "" }
> > +constexpr T t2(t1);		// { dg-message "in .constexpr. expansion" }
> >  
> >  // Well-formed
> >  struct U {
> > diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C
> > index 5eedf42ba36..50c676c56cd 100644
> > --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C
> > +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C
> > @@ -16,7 +16,7 @@ int main()
> >  struct complex 			// { dg-message "no .constexpr. constructor" "" { target { ! implicit_constexpr } } }
> >  {
> >    complex(double r, double i) : re(r), im(i) { }
> > -  constexpr double real() const { return re; } // { dg-error "not a literal type" "" { target c++11_only } }
> > +  constexpr double real() const { return re; } // { dg-error "not a literal type|not usable in a constant expression" "" { target { ! implicit_constexpr } } }
> >    double imag() const { return im; }
> >  
> >  private:
> > diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ice20.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ice20.C
> > index ebaa95e5324..e4e3bf865cd 100644
> > --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-ice20.C
> > +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ice20.C
> > @@ -2,6 +2,6 @@
> >  // { dg-do compile { target c++11 } }
> >  
> >  typedef bool (*Function)(int);
> > -constexpr bool check(int x, Function p) { return p(x); }  // { dg-message "in .constexpr. expansion of" }
> > +constexpr bool check(int x, Function p) { return p(x); }  // { dg-error "lifetime" }
> >  
> > -static_assert(check(2, check), "");  // { dg-error "conversion|constant|lifetime|in .constexpr. expansion of" }
> > +static_assert(check(2, check), "");  // { dg-error "conversion|constant|in .constexpr. expansion of" }
> > diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-89481.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-89481.C
> > index 8ac4ef0fd36..6f8f6a8038e 100644
> > --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-89481.C
> > +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-89481.C
> > @@ -6,7 +6,7 @@ foo ()
> >  {
> >    union U { long long a; int b[2]; } u { 5LL };
> >    u.b[1] = 4;		// { dg-error "change of the active member of a union from" "" { target c++17_down } }
> > -  return u.b[0];
> > +  return u.b[0];	// { dg-error "accessing uninitialized array element" "" { target c++2a } }
> >  }
> >  
> >  constexpr int
> > @@ -19,6 +19,5 @@ bar ()
> >  
> >  static_assert (foo () == 0, "");	// { dg-error "non-constant condition for static assertion" }
> >  					// { dg-message "in 'constexpr' expansion of" "" { target *-*-* } .-1 }
> > -					// { dg-error "accessing uninitialized array element" "" { target c++2a } .-2 }
> >  static_assert (bar () == 4, "");	// { dg-error "non-constant condition for static assertion" "" { target c++17_down } }
> >  					// { dg-message "in 'constexpr' expansion of" "" { target c++17_down } .-1 }
> > diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime1.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime1.C
> > index 43aa7c974c1..f79f1611d5f 100644
> > --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime1.C
> > +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime1.C
> > @@ -11,3 +11,4 @@ constexpr const int& test() {
> >    return local.get();
> >  }
> >  constexpr int x = test();  // { dg-error "accessing object outside its lifetime" }
> > +
> > diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime2.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime2.C
> > index 22cd919fcda..2f5ae8db6d5 100644
> > --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime2.C
> > +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime2.C
> > @@ -8,9 +8,9 @@ struct S {
> >  
> >  constexpr int error() {
> >    const auto& local = S{}.get();  // { dg-message "note: declared here" }
> > -  return local;
> > +  return local;  // { dg-error "accessing object outside its lifetime" }
> >  }
> > -constexpr int x = error();  // { dg-error "accessing object outside its lifetime" }
> > +constexpr int x = error();  // { dg-message "in .constexpr. expansion" }
> >  
> >  constexpr int ok() {
> >    // temporary should only be destroyed after end of full-expression
> > diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime3.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime3.C
> > index 6329f8cf6c6..53785521d05 100644
> > --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime3.C
> > +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime3.C
> > @@ -7,7 +7,7 @@ constexpr int f(int i) {
> >      int j = 123;  // { dg-message "note: declared here" }
> >      p = &j;
> >    }
> > -  return *p;
> > +  return *p;  // { dg-error "accessing object outside its lifetime" }
> >  }
> >  
> > -constexpr int i = f(0);  // { dg-error "accessing object outside its lifetime" }
> > +constexpr int i = f(0);  // { dg-message "in .constexpr. expansion" }
> > diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime4.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime4.C
> > index 181a1201663..4302da1eddc 100644
> > --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime4.C
> > +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime4.C
> > @@ -5,7 +5,7 @@ constexpr const double& test() {
> >    return local;
> >  }
> >  
> > -static_assert(test() == 3.0, "");  // { dg-error "constant|accessing object outside its lifetime" }
> > +static_assert(test() == 3.0, "");  // { dg-error "non-constant condition|accessing object outside its lifetime" }
> >  
> >  // no deference, shouldn't error
> >  static_assert((test(), true), "");
> > diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C
> > index ad3ef579f63..a12920c8fba 100644
> > --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C
> > +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C
> > @@ -5,7 +5,7 @@ constexpr const int& id(int x) { return x; }  // { dg-message "note: declared he
> >  
> >  constexpr bool test() {
> >    const int& y = id(3);
> > -  return y == 3;
> > +  return y == 3;  // { dg-error "accessing object outside its lifetime" }
> >  }
> >  
> > -constexpr bool x = test();  // { dg-error "accessing object outside its lifetime" }
> > +constexpr bool x = test();  // { dg-message "in .constexpr. expansion" }
> > diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-union5.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-union5.C
> > index 55fe9fa2f0b..3d76345d564 100644
> > --- a/gcc/testsuite/g++.dg/cpp1y/constexpr-union5.C
> > +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-union5.C
> > @@ -8,8 +8,8 @@ union U {
> >  };
> >  
> >  constexpr int foo(U *up) {
> > -  up->a++;
> > +  up->a++; // { dg-error "accessing uninitialized member" }
> >    return {42};
> >  }
> >  
> > -extern constexpr U u = {}; // { dg-error "accessing uninitialized member" }
> > +extern constexpr U u = {}; // { dg-message "in .constexpr. expansion" }
> > diff --git a/gcc/testsuite/g++.dg/cpp1y/pr68180.C b/gcc/testsuite/g++.dg/cpp1y/pr68180.C
> > index 9e6e5e984f9..8de1ef3936b 100644
> > --- a/gcc/testsuite/g++.dg/cpp1y/pr68180.C
> > +++ b/gcc/testsuite/g++.dg/cpp1y/pr68180.C
> > @@ -6,11 +6,11 @@ typedef float __attribute__( ( vector_size( 16 ) ) ) float32x4_t;
> >  constexpr float32x4_t fill(float x) {
> >    float32x4_t v{0};
> >    constexpr auto vs = sizeof(v)/sizeof(v[0]);
> > -  for (auto i=0U; i<vs; ++i) v[i]=i;
> > +  for (auto i=0U; i<vs; ++i) v[i]=i; // { dg-error "not a constant" }
> >    return v+x;
> >  }
> >  
> >  float32x4_t foo(float32x4_t x) {
> > -  constexpr float32x4_t v = fill(1.f); // { dg-error "not a constant||in .constexpr. expansion of " }
> > +  constexpr float32x4_t v = fill(1.f); // { dg-message "in .constexpr. expansion of " }
> >    return x+v;
> >  }
> > diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda6.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda6.C
> > index 214d3821299..c46c2d4c7fe 100644
> > --- a/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda6.C
> > +++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda6.C
> > @@ -1,7 +1,7 @@
> >  // Testcase from P0170R1
> >  // { dg-do compile { target c++17 } }
> >  
> > -auto monoid = [](auto v) { return [=] { return v; }; };
> > +auto monoid = [](auto v) { return [=] { return v; }; };  // { dg-error "not usable in a constant expression" }
> >  auto add = [](auto m1) constexpr {
> >    auto ret = m1();
> >    return [=](auto m2) mutable {
> > @@ -22,7 +22,7 @@ int main()
> >    // member function call operator can not perform an lvalue-to-rvalue conversion
> >    // on one of its subobjects (that represents its capture) in a constant
> >    // expression.
> > -  auto two = monoid(2);
> > +  auto two = monoid(2);  // { dg-message "not declared .constexpr." }
> >    if (!(two() == 2)) __builtin_abort(); // OK, not a constant expression.
> >    static_assert(add(one)(one)() == two()); // { dg-error "|in .constexpr. expansion of " } two() is not a constant expression
> >    static_assert(add(one)(one)() == monoid(2)()); // OK
> > diff --git a/gcc/testsuite/g++.dg/cpp2a/bit-cast11.C b/gcc/testsuite/g++.dg/cpp2a/bit-cast11.C
> > index a3eb31bc6c7..760c9ca40b4 100644
> > --- a/gcc/testsuite/g++.dg/cpp2a/bit-cast11.C
> > +++ b/gcc/testsuite/g++.dg/cpp2a/bit-cast11.C
> > @@ -28,7 +28,7 @@ f3 ()
> >  {
> >    T t = { 1, 2 };
> >    S s = __builtin_bit_cast (S, t);
> > -  return s.a[1] == 0;
> > +  return s.a[1] == 0;		// { dg-error "accessing uninitialized array element" }
> >  }
> >  
> >  constexpr bool
> > @@ -52,12 +52,12 @@ f6 ()
> >  {
> >    W t = { 1, 2 };
> >    V s = __builtin_bit_cast (V, t);
> > -  return s.b.a[1] == 1;
> > +  return s.b.a[1] == 1;		// { dg-error "accessing uninitialized array element" }
> >  }
> >  
> >  constexpr bool a = f1 ();
> >  constexpr bool b = f2 ();
> > -constexpr bool c = f3 ();	// { dg-error "accessing uninitialized array element" }
> > -constexpr bool d = f4 ();
> > +constexpr bool c = f3 ();	// { dg-message "in .constexpr. expansion" }
> > +constexpr bool d = f4 ();	// { dg-message "in .constexpr. expansion" }
> >  constexpr bool e = f5 ();
> > -constexpr bool f = f6 ();	// { dg-error "accessing uninitialized array element" }
> > +constexpr bool f = f6 ();	// { dg-message "in .constexpr. expansion" }
> > diff --git a/gcc/testsuite/g++.dg/cpp2a/bit-cast12.C b/gcc/testsuite/g++.dg/cpp2a/bit-cast12.C
> > index 9c699dd55f0..e205bc6a8c1 100644
> > --- a/gcc/testsuite/g++.dg/cpp2a/bit-cast12.C
> > +++ b/gcc/testsuite/g++.dg/cpp2a/bit-cast12.C
> > @@ -33,7 +33,7 @@ f3 ()
> >  {
> >    T t = { 1, 2 };
> >    S s = __builtin_bit_cast (S, t);
> > -  return s.a[1] == 0;
> > +  return s.a[1] == 0;		// { dg-error "accessing uninitialized array element" }
> >  }
> >  
> >  constexpr bool
> > @@ -57,12 +57,12 @@ f6 ()
> >  {
> >    W t = { 1, 2 };
> >    V s = __builtin_bit_cast (V, t);
> > -  return s.b.a[1] == 1;
> > +  return s.b.a[1] == 1;		// { dg-error "accessing uninitialized array element" }
> >  }
> >  
> >  constexpr bool a = f1 ();
> >  constexpr bool b = f2 ();
> > -constexpr bool c = f3 ();	// { dg-error "accessing uninitialized array element" }
> > -constexpr bool d = f4 ();
> > +constexpr bool c = f3 ();	// { dg-message "in .constexpr. expansion" }
> > +constexpr bool d = f4 ();	// { dg-message "in .constexpr. expansion" }
> >  constexpr bool e = f5 ();
> > -constexpr bool f = f6 ();	// { dg-error "accessing uninitialized array element" }
> > +constexpr bool f = f6 ();	// { dg-message "in .constexpr. expansion" }
> > diff --git a/gcc/testsuite/g++.dg/cpp2a/bit-cast14.C b/gcc/testsuite/g++.dg/cpp2a/bit-cast14.C
> > index 5e185919be4..e0cc9a39702 100644
> > --- a/gcc/testsuite/g++.dg/cpp2a/bit-cast14.C
> > +++ b/gcc/testsuite/g++.dg/cpp2a/bit-cast14.C
> > @@ -44,7 +44,7 @@ f5 ()
> >  {
> >    T1 t = { 0, 0, 0, 0, 0, 0, 0 };
> >    S s = __builtin_bit_cast (S, t);
> > -  unsigned char a = s.a;
> > +  unsigned char a = s.a;		// { dg-error "accessing uninitialized member" }
> >    return true;
> >  }
> >  
> > @@ -53,7 +53,7 @@ f6 ()
> >  {
> >    T2 t = { 0, 0, 0, 0, 0, 0, 0 };
> >    S s = __builtin_bit_cast (S, t);
> > -  unsigned char b = s.b;
> > +  unsigned char b = s.b;		// { dg-error "accessing uninitialized member" }
> >    return true;
> >  }
> >  
> > @@ -62,14 +62,14 @@ f7 ()
> >  {
> >    T3 t = { 0, 0, 0, 0, 0, 0, 0 };
> >    S s = __builtin_bit_cast (S, t);
> > -  unsigned char c = s.c;
> > +  unsigned char c = s.c;		// { dg-error "accessing uninitialized member" }
> >    return true;
> >  }
> >  
> >  constexpr bool a = f1 ();
> >  constexpr bool b = f2 ();
> >  constexpr bool c = f3 ();
> > -constexpr bool d = f4 ();
> > -constexpr bool e = f5 ();	// { dg-error "accessing uninitialized member" }
> > -constexpr bool f = f6 ();	// { dg-error "accessing uninitialized member" }
> > -constexpr bool g = f7 ();	// { dg-error "accessing uninitialized member" }
> > +constexpr bool d = f4 ();	// { dg-message "in .constexpr. expansion" }
> > +constexpr bool e = f5 ();	// { dg-message "in .constexpr. expansion" }
> > +constexpr bool f = f6 ();	// { dg-message "in .constexpr. expansion" }
> > +constexpr bool g = f7 ();	// { dg-message "in .constexpr. expansion" }
> > diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-98122.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-98122.C
> > index 01bdfa5bd4d..b0c91d5ef97 100644
> > --- a/gcc/testsuite/g++.dg/cpp2a/constexpr-98122.C
> > +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-98122.C
> > @@ -9,7 +9,7 @@ bar ()
> >  {
> >    V f { .b = 42 };
> >    constexpr auto m = &V::a;
> > -  return (f.*m) == 42;
> > +  return (f.*m) == 42;  // { dg-error "accessing 'V::a' member instead of initialized 'V::b' member in constant expression" }
> >  }
> >  
> >  constexpr bool
> > @@ -21,5 +21,5 @@ baz ()
> >  }
> >  
> >  static_assert (bar (), "");	// { dg-error "non-constant condition for static assertion" }
> > -				// { dg-error "accessing 'V::a' member instead of initialized 'V::b' member in constant expression" "" { target *-*-* } .-1 }
> > +				// { dg-message "in .constexpr. expansion" "" { target *-*-* } .-1 }
> >  static_assert (baz (), "");
> > diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic17.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic17.C
> > index a26678e6ed7..28facf192df 100644
> > --- a/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic17.C
> > +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic17.C
> > @@ -25,8 +25,7 @@ struct D : B, A {
> >  
> >  constexpr B::B(V* v, A* a)
> >  {
> > -  dynamic_cast<B*>(a);
> > +  dynamic_cast<B*>(a); // { dg-error "accessing uninitialized member" }
> >  }
> >  
> > -constexpr D d; // { dg-error "accessing uninitialized member" }
> > -// { dg-message "in 'constexpr' expansion of" "" { target *-*-* } .-1 }
> > +constexpr D d; // { dg-message "in 'constexpr' expansion of" }
> > diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-init1.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-init1.C
> > index e56ecfed48a..b4e39b6f928 100644
> > --- a/gcc/testsuite/g++.dg/cpp2a/constexpr-init1.C
> > +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-init1.C
> > @@ -52,11 +52,10 @@ constexpr int
> >  fn5 ()
> >  {
> >    struct S { int a = 9; int b; } s;
> > -  return s.b;
> > +  return s.b; // { dg-error "accessing uninitialized member" }
> >  }
> >  
> > -constexpr int b = fn5 (); // { dg-error "accessing uninitialized member" }
> > -// { dg-message "in .constexpr. expansion of" "" { target *-*-* } .-1 }
> > +constexpr int b = fn5 (); // { dg-message "in .constexpr. expansion of" }
> >  
> >  constexpr int
> >  fn6 ()
> > diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new12.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new12.C
> > index 5a3d06a5fab..832782e1427 100644
> > --- a/gcc/testsuite/g++.dg/cpp2a/constexpr-new12.C
> > +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-new12.C
> > @@ -17,11 +17,11 @@ struct B : A {
> >  constexpr int
> >  foo ()
> >  {
> > -  A *a = new B ();
> > +  A *a = new B ();  // { dg-message "allocated here" }
> >    a->a = 4;
> >    delete a;
> > -  int r = a->foo ();
> > +  int r = a->foo ();  // { dg-error "constant expression" }
> >    return r;
> >  }
> >  
> > -constexpr auto a = foo ();	// { dg-error "constant expression" }
> > +constexpr auto a = foo ();  // { dg-message "in .constexpr. expansion" }
> > diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new3.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new3.C
> > index 70b841208f8..3ba440fec53 100644
> > --- a/gcc/testsuite/g++.dg/cpp2a/constexpr-new3.C
> > +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-new3.C
> > @@ -45,11 +45,10 @@ constexpr bool
> >  f5 ()
> >  {
> >    int *p = new int;		// { dg-message "allocated here" }
> > -  return *p == 1;
> > +  return *p == 1;		// { dg-error "the content of uninitialized storage is not usable in a constant expression" }
> >  }
> >  
> > -constexpr auto v5 = f5 ();	// { dg-error "the content of uninitialized storage is not usable in a constant expression" }
> > -				// { dg-message "in 'constexpr' expansion of" "" { target *-*-* } .-1 }
> > +constexpr auto v5 = f5 (); 	// { dg-message "in 'constexpr' expansion of" }
> >  
> >  constexpr bool
> >  f6 ()
> > @@ -57,11 +56,10 @@ f6 ()
> >    int *p = new int (2);		// { dg-message "allocated here" }
> >    int *q = p;
> >    delete p;
> > -  return *q == 2;
> > +  return *q == 2;		// { dg-error "use of allocated storage after deallocation in a constant expression" }
> >  }
> >  
> > -constexpr auto v6 = f6 ();	// { dg-error "use of allocated storage after deallocation in a constant expression" }
> > -				// { dg-message "in 'constexpr' expansion of" "" { target *-*-* } .-1  }
> > +constexpr auto v6 = f6 (); 	// { dg-message "in 'constexpr' expansion of" }
> >  
> >  constexpr int *
> >  f7 ()
> > diff --git a/gcc/testsuite/g++.dg/ext/constexpr-vla2.C b/gcc/testsuite/g++.dg/ext/constexpr-vla2.C
> > index d4ea7c58c0d..e09a27af3de 100644
> > --- a/gcc/testsuite/g++.dg/ext/constexpr-vla2.C
> > +++ b/gcc/testsuite/g++.dg/ext/constexpr-vla2.C
> > @@ -4,7 +4,7 @@
> >  constexpr int
> >  fn_bad (int n)
> >  {
> > -  __extension__ int a [n] = { 0 };
> > +  __extension__ int a [n] = { 0 };  // { dg-error "array subscript" }
> >    int z = a [0] + (n ? fn_bad (n - 1) : 0); // { dg-message "in .constexpr. expansion of " } 
> >    return z;
> >  }
> > @@ -18,4 +18,4 @@ fn_ok (int n)
> >  }
> >  
> >  constexpr int i1 = fn_ok (3);
> > -constexpr int i2 = fn_bad (3); // { dg-error "array subscript|in .constexpr. expansion of " }
> > +constexpr int i2 = fn_bad (3); // { dg-message "in .constexpr. expansion of " }
> > diff --git a/gcc/testsuite/g++.dg/ext/constexpr-vla3.C b/gcc/testsuite/g++.dg/ext/constexpr-vla3.C
> > index 538b576a825..6f9daa1897f 100644
> > --- a/gcc/testsuite/g++.dg/ext/constexpr-vla3.C
> > +++ b/gcc/testsuite/g++.dg/ext/constexpr-vla3.C
> > @@ -4,11 +4,11 @@
> >  constexpr int
> >  foo (int n)
> >  {
> > -  __extension__ int a[n] = { 1, 2, 3, 4, 5, 6 };
> > +  __extension__ int a[n] = { 1, 2, 3, 4, 5, 6 }; // { dg-error "array subscript" }
> >    int z = 0;
> >    for (int i = 0; i <= n; ++i)
> >      z += a[i];
> >    return z;
> >  }
> >  
> > -constexpr int n = foo (3); // { dg-error "array subscript|in .constexpr. expansion of " }
> > +constexpr int n = foo (3); // { dg-message "in .constexpr. expansion of " }
> > diff --git a/gcc/testsuite/g++.dg/ubsan/pr63956.C b/gcc/testsuite/g++.dg/ubsan/pr63956.C
> > index 3a1596e6e2e..0771732ef00 100644
> > --- a/gcc/testsuite/g++.dg/ubsan/pr63956.C
> > +++ b/gcc/testsuite/g++.dg/ubsan/pr63956.C
> > @@ -100,13 +100,13 @@ constexpr int
> >  fn7 (const int *a, int b)
> >  {
> >    if (b != 3)
> > -    return fn6 (*a, b);
> > +    return fn6 (*a, b); // { dg-error "null pointer" }
> >    return 7;
> >  }
> >  
> >  constexpr int n1 = 7;
> >  constexpr int n2 = fn7 (&n1, 5);
> > -constexpr int n3 = fn7 ((const int *) 0, 8);  // { dg-error "null pointer|in .constexpr. expansion of " }
> > +constexpr int n3 = fn7 ((const int *) 0, 8);  // { dg-message "in .constexpr. expansion of " }
> >  
> >  constexpr int
> >  fn8 (int i)
> > diff --git a/libstdc++-v3/testsuite/25_algorithms/equal/constexpr_neg.cc b/libstdc++-v3/testsuite/25_algorithms/equal/constexpr_neg.cc
> > index 34ca5c4805c..fd89ac0e166 100644
> > --- a/libstdc++-v3/testsuite/25_algorithms/equal/constexpr_neg.cc
> > +++ b/libstdc++-v3/testsuite/25_algorithms/equal/constexpr_neg.cc
> > @@ -32,7 +32,7 @@ test01()
> >    return outa;
> >  }
> >  
> > -static_assert(test01()); // { dg-error "outside the bounds" }
> > +static_assert(test01()); // { dg-error "non-constant condition" }
> >  
> >  constexpr bool
> >  test02()
> > @@ -44,7 +44,8 @@ test02()
> >    return outa;
> >  }
> >  
> > -static_assert(test02()); // { dg-error "outside the bounds" }
> > +static_assert(test02()); // { dg-error "non-constant condition" }
> >  
> > -// { dg-prune-output "non-constant condition" }
> > +// Errors occuring within <algorithm> internals:
> > +// { dg-error "outside the bounds of array" "" { target *-*-* } 0 }
> >  // { dg-prune-output "in 'constexpr'" }
> > -- 
> > 2.34.1
> > 
> > 
>
diff mbox series

Patch

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index bdbc12144a7..74045477a92 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -1165,10 +1165,12 @@  public:
   hash_set<tree> *modifiable;
   /* Number of heap VAR_DECL deallocations.  */
   unsigned heap_dealloc_count;
+  /* Current location in case subtree has no location information.  */
+  location_t loc;
   /* Constructor.  */
   constexpr_global_ctx ()
     : constexpr_ops_count (0), cleanups (NULL), modifiable (nullptr),
-      heap_dealloc_count (0) {}
+      heap_dealloc_count (0), loc (input_location) {}
 
  tree get_value (tree t)
   {
@@ -2113,7 +2115,7 @@  cxx_eval_internal_function (const constexpr_ctx *ctx, tree t,
 
     default:
       if (!ctx->quiet)
-	error_at (cp_expr_loc_or_input_loc (t),
+	error_at (cp_expr_loc_or_loc (t, ctx->global->loc),
 		  "call to internal function %qE", t);
       *non_constant_p = true;
       return t;
@@ -2128,7 +2130,7 @@  cxx_eval_internal_function (const constexpr_ctx *ctx, tree t,
 
   if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST)
     {
-      location_t loc = cp_expr_loc_or_input_loc (t);
+      location_t loc = cp_expr_loc_or_loc (t, ctx->global->loc);
       tree type = TREE_TYPE (TREE_TYPE (t));
       tree result = fold_binary_loc (loc, opcode, type,
 				     fold_convert_loc (loc, type, arg0),
@@ -2164,9 +2166,9 @@  clear_no_implicit_zero (tree ctor)
    EXPR is the MODIFY_EXPR expression performing the modification.  */
 
 static void
-modifying_const_object_error (tree expr, tree obj)
+modifying_const_object_error (const constexpr_ctx* ctx, tree expr, tree obj)
 {
-  location_t loc = cp_expr_loc_or_input_loc (expr);
+  location_t loc = cp_expr_loc_or_loc (expr, ctx->global->loc);
   auto_diagnostic_group d;
   error_at (loc, "modifying a const object %qE is not allowed in "
 	    "a constant expression", TREE_OPERAND (expr, 0));
@@ -2358,7 +2360,7 @@  cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call,
   tree obj = CALL_EXPR_ARG (call, 0);
   tree type = CALL_EXPR_ARG (call, 2);
   HOST_WIDE_INT hint = int_cst_value (CALL_EXPR_ARG (call, 3));
-  location_t loc = cp_expr_loc_or_input_loc (call);
+  location_t loc = cp_expr_loc_or_loc (call, ctx->global->loc);
 
   /* Get the target type of the dynamic_cast.  */
   gcc_assert (TREE_CODE (type) == ADDR_EXPR);
@@ -3656,7 +3658,7 @@  cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t,
       && integer_zerop (lhs) && !integer_zerop (rhs))
     {
       if (!ctx->quiet)
-	error ("arithmetic involving a null pointer in %qE", lhs);
+	error_at (loc, "arithmetic involving a null pointer in %qE", lhs);
       *non_constant_p = true;
       return t;
     }
@@ -4149,7 +4151,7 @@  eval_and_check_array_index (const constexpr_ctx *ctx,
 			    tree t, bool allow_one_past,
 			    bool *non_constant_p, bool *overflow_p)
 {
-  location_t loc = cp_expr_loc_or_input_loc (t);
+  location_t loc = cp_expr_loc_or_loc (t, ctx->global->loc);
   tree ary = TREE_OPERAND (t, 0);
   t = TREE_OPERAND (t, 1);
   tree index = cxx_eval_constant_expression (ctx, t, vc_prvalue,
@@ -4187,6 +4189,7 @@  cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
 			  value_cat lval,
 			  bool *non_constant_p, bool *overflow_p)
 {
+  location_t loc = cp_expr_loc_or_loc (t, ctx->global->loc);
   tree oldary = TREE_OPERAND (t, 0);
   tree ary = cxx_eval_constant_expression (ctx, oldary,
 					   lval,
@@ -4274,7 +4277,7 @@  cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
 	 building; if there's no initializer for this element yet,
 	 that's an error.  */
       if (!ctx->quiet)
-	error ("accessing uninitialized array element");
+	error_at (loc, "accessing uninitialized array element");
       *non_constant_p = true;
       return t;
     }
@@ -4323,13 +4326,14 @@  cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
   tree whole = cxx_eval_constant_expression (ctx, orig_whole,
 					     lval,
 					     non_constant_p, overflow_p);
+  location_t loc = cp_expr_loc_or_loc (whole, ctx->global->loc);
   if (*non_constant_p)
     return t;
   if (INDIRECT_REF_P (whole)
       && integer_zerop (TREE_OPERAND (whole, 0)))
     {
       if (!ctx->quiet)
-	error ("dereferencing a null pointer in %qE", orig_whole);
+	error_at (loc, "dereferencing a null pointer in %qE", orig_whole);
       *non_constant_p = true;
       return t;
     }
@@ -4348,7 +4352,7 @@  cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
   if (TREE_CODE (whole) != CONSTRUCTOR)
     {
       if (!ctx->quiet)
-	error ("%qE is not a constant expression", orig_whole);
+	error_at (loc, "%qE is not a constant expression", orig_whole);
       *non_constant_p = true;
       return t;
     }
@@ -4356,7 +4360,7 @@  cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
       && DECL_MUTABLE_P (part))
     {
       if (!ctx->quiet)
-	error ("mutable %qD is not usable in a constant expression", part);
+	error_at (loc, "mutable %qD is not usable in a constant expression", part);
       *non_constant_p = true;
       return t;
     }
@@ -4386,10 +4390,10 @@  cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
 	{
 	  constructor_elt *cep = CONSTRUCTOR_ELT (whole, 0);
 	  if (cep->value == NULL_TREE)
-	    error ("accessing uninitialized member %qD", part);
+	    error_at (loc, "accessing uninitialized member %qD", part);
 	  else
-	    error ("accessing %qD member instead of initialized %qD member in "
-		   "constant expression", part, cep->index);
+	    error_at (loc, "accessing %qD member instead of initialized %qD member "
+		      "in constant expression", part, cep->index);
 	}
       *non_constant_p = true;
       return t;
@@ -4408,7 +4412,7 @@  cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
 	 building; if there's no initializer for this member yet, that's an
 	 error.  */
       if (!ctx->quiet)
-	error ("accessing uninitialized member %qD", part);
+	error_at (loc, "accessing uninitialized member %qD", part);
       *non_constant_p = true;
       return t;
     }
@@ -4436,6 +4440,7 @@  cxx_eval_bit_field_ref (const constexpr_ctx *ctx, tree t,
   tree whole = cxx_eval_constant_expression (ctx, orig_whole,
 					     lval,
 					     non_constant_p, overflow_p);
+  location_t loc = cp_expr_loc_or_loc (t, ctx->global->loc);
   tree start, field, value;
   unsigned HOST_WIDE_INT i;
 
@@ -4448,7 +4453,7 @@  cxx_eval_bit_field_ref (const constexpr_ctx *ctx, tree t,
       && TREE_CODE (whole) != CONSTRUCTOR)
     {
       if (!ctx->quiet)
-	error ("%qE is not a constant expression", orig_whole);
+	error_at (loc, "%qE is not a constant expression", orig_whole);
       *non_constant_p = true;
     }
   if (*non_constant_p)
@@ -4460,7 +4465,7 @@  cxx_eval_bit_field_ref (const constexpr_ctx *ctx, tree t,
 				 TREE_OPERAND (t, 1), TREE_OPERAND (t, 2)))
 	return r;
       if (!ctx->quiet)
-	error ("%qE is not a constant expression", orig_whole);
+	error_at (loc, "%qE is not a constant expression", orig_whole);
       *non_constant_p = true;
       return t;
     }
@@ -5609,6 +5614,7 @@  cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
 		       value_cat lval,
 		       bool *non_constant_p, bool *overflow_p)
 {
+  location_t loc = cp_expr_loc_or_loc (t, ctx->global->loc);
   tree orig_op0 = TREE_OPERAND (t, 0);
   bool empty_base = false;
 
@@ -5639,7 +5645,7 @@  cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
       if (!lval && integer_zerop (op0))
 	{
 	  if (!ctx->quiet)
-	    error ("dereferencing a null pointer");
+	    error_at (loc, "dereferencing a null pointer");
 	  *non_constant_p = true;
 	  return t;
 	}
@@ -5658,8 +5664,7 @@  cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
 			  (TREE_TYPE (TREE_TYPE (sub)), TREE_TYPE (t)));
 	      /* DR 1188 says we don't have to deal with this.  */
 	      if (!ctx->quiet)
-		error_at (cp_expr_loc_or_input_loc (t),
-			  "accessing value of %qE through a %qT glvalue in a "
+		error_at (loc, "accessing value of %qE through a %qT glvalue in a "
 			  "constant expression", build_fold_indirect_ref (sub),
 			  TREE_TYPE (t));
 	      *non_constant_p = true;
@@ -5906,6 +5911,7 @@  cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
 			   value_cat lval,
 			   bool *non_constant_p, bool *overflow_p)
 {
+  location_t loc = cp_expr_loc_or_loc (t, ctx->global->loc);
   constexpr_ctx new_ctx = *ctx;
 
   tree init = TREE_OPERAND (t, 1);
@@ -6030,7 +6036,7 @@  cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
       /* A constant-expression cannot modify objects from outside the
 	 constant-expression.  */
       if (!ctx->quiet)
-	error ("modification of %qE is not a constant expression", object);
+	error_at (loc, "modification of %qE is not a constant expression", object);
       *non_constant_p = true;
       return t;
     }
@@ -6128,7 +6134,7 @@  cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
 	  if (cxx_dialect < cxx20)
 	    {
 	      if (!ctx->quiet)
-		error_at (cp_expr_loc_or_input_loc (t),
+		error_at (cp_expr_loc_or_loc (t, ctx->global->loc),
 			  "change of the active member of a union "
 			  "from %qD to %qD",
 			  CONSTRUCTOR_ELT (*valp, 0)->index,
@@ -6141,7 +6147,7 @@  cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
 	      /* Diagnose changing the active union member while the union
 		 is in the process of being initialized.  */
 	      if (!ctx->quiet)
-		error_at (cp_expr_loc_or_input_loc (t),
+		error_at (cp_expr_loc_or_loc (t, ctx->global->loc),
 			  "change of the active member of a union "
 			  "from %qD to %qD during initialization",
 			  CONSTRUCTOR_ELT (*valp, 0)->index,
@@ -6224,7 +6230,7 @@  cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
       if (fail)
 	{
 	  if (!ctx->quiet)
-	    modifying_const_object_error (t, const_object_being_modified);
+	    modifying_const_object_error (ctx, t, const_object_being_modified);
 	  *non_constant_p = true;
 	  return t;
 	}
@@ -6381,6 +6387,8 @@  cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t,
   tree offset = TREE_OPERAND (t, 1);
   gcc_assert (TREE_CONSTANT (offset));
 
+  location_t loc = cp_expr_loc_or_loc (t, ctx->global->loc);
+
   /* OFFSET is constant, but perhaps not constant enough.  We need to
      e.g. bash FLOAT_EXPRs to REAL_CSTs.  */
   offset = fold_simple (offset);
@@ -6428,8 +6436,7 @@  cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t,
     VERIFY_CONSTANT (mod);
 
   /* Storing the modified value.  */
-  tree store = build2_loc (cp_expr_loc_or_loc (t, input_location),
-			   MODIFY_EXPR, type, op, mod);
+  tree store = build2_loc (loc, MODIFY_EXPR, type, op, mod);
   mod = cxx_eval_constant_expression (ctx, store, lval,
 				      non_constant_p, overflow_p);
   ggc_free (store);
@@ -6602,6 +6609,7 @@  cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t,
 		    bool *non_constant_p, bool *overflow_p,
 		    tree *jump_target)
 {
+  location_t loc = cp_expr_loc_or_loc (t, ctx->global->loc);
   constexpr_ctx new_ctx = *ctx;
   tree local_target;
   if (!jump_target)
@@ -6691,7 +6699,7 @@  cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t,
       if (++count >= constexpr_loop_limit)
 	{
 	  if (!ctx->quiet)
-	    error_at (cp_expr_loc_or_input_loc (t),
+	    error_at (loc,
 		      "%<constexpr%> loop iteration count exceeds limit of %d "
 		      "(use %<-fconstexpr-loop-limit=%> to increase the limit)",
 		      constexpr_loop_limit);
@@ -6950,7 +6958,10 @@  cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       return t;
     }
 
-  location_t loc = cp_expr_loc_or_input_loc (t);
+  /* Track current location, propagating down from parent calls
+     in case this expression has no location information.  */
+  location_t loc = cp_expr_loc_or_loc (t, ctx->global->loc);
+  ctx->global->loc = loc;
 
   STRIP_ANY_LOCATION_WRAPPER (t);
 
@@ -6973,8 +6984,8 @@  cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 	  && !integer_zerop (t))
 	{
 	  if (!ctx->quiet)
-	    error ("value %qE of type %qT is not a constant expression",
-		   t, TREE_TYPE (t));
+	    error_at (loc, "value %qE of type %qT is not a constant expression",
+		      t, TREE_TYPE (t));
 	  *non_constant_p = true;
 	}
 
@@ -7222,8 +7233,8 @@  cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 	    if (!ctx->quiet)
 	      {
 		auto_diagnostic_group d;
-		error ("temporary of non-literal type %qT in a "
-		       "constant expression", type);
+		error_at (loc, "temporary of non-literal type %qT in a "
+			  "constant expression", type);
 		explain_non_literal_class (type);
 	      }
 	    *non_constant_p = true;
@@ -8025,8 +8036,7 @@  cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 	if (function_concept_p (tmpl))
 	  {
 	    if (!ctx->quiet)
-	      error_at (cp_expr_loc_or_input_loc (t),
-			"function concept must be called");
+	      error_at (loc, "function concept must be called");
 	    r = error_mark_node;
 	    break;
 	  }
@@ -8121,6 +8131,9 @@  cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       break;
     }
 
+  /* Reset current location in case it was modified in child calls.  */
+  ctx->global->loc = loc;
+
   if (r == error_mark_node)
     *non_constant_p = true;
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-48089.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-48089.C
index 4574eb83ff7..11630f26ffe 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-48089.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-48089.C
@@ -10,11 +10,11 @@ 
 // R() is well-formed because i is initialized before j.
 
 struct s {
-  constexpr s() : v(v) { }
+  constexpr s() : v(v) { } // { dg-error "accessing uninitialized member" }
   int v;
 };
 
-constexpr s bang;		// { dg-error "|" }
+constexpr s bang;  // { dg-message "in .constexpr. expansion" }
 
 struct R {
   int i,j;
@@ -26,14 +26,14 @@  constexpr R r;			// { dg-bogus "" }
 // Ill-formed (no diagnostic required)
 struct T {
   int i;
-  constexpr int f() { return i; }
+  constexpr int f() { return i; }  // { dg-error "accessing uninitialized member" }
   constexpr T(): i(0) { }
-  constexpr T(const T& t) : i(f()) { } // { dg-message "" }
+  constexpr T(const T& t) : i(f()) { }  // { dg-message "in .constexpr. expansion" }
 };
 
 constexpr T t1;
 // Ill-formed (diagnostic required)
-constexpr T t2(t1);		// { dg-message "" }
+constexpr T t2(t1);		// { dg-message "in .constexpr. expansion" }
 
 // Well-formed
 struct U {
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C
index 5eedf42ba36..50c676c56cd 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C
@@ -16,7 +16,7 @@  int main()
 struct complex 			// { dg-message "no .constexpr. constructor" "" { target { ! implicit_constexpr } } }
 {
   complex(double r, double i) : re(r), im(i) { }
-  constexpr double real() const { return re; } // { dg-error "not a literal type" "" { target c++11_only } }
+  constexpr double real() const { return re; } // { dg-error "not a literal type|not usable in a constant expression" "" { target { ! implicit_constexpr } } }
   double imag() const { return im; }
 
 private:
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ice20.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ice20.C
index ebaa95e5324..e4e3bf865cd 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-ice20.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ice20.C
@@ -2,6 +2,6 @@ 
 // { dg-do compile { target c++11 } }
 
 typedef bool (*Function)(int);
-constexpr bool check(int x, Function p) { return p(x); }  // { dg-message "in .constexpr. expansion of" }
+constexpr bool check(int x, Function p) { return p(x); }  // { dg-error "lifetime" }
 
-static_assert(check(2, check), "");  // { dg-error "conversion|constant|lifetime|in .constexpr. expansion of" }
+static_assert(check(2, check), "");  // { dg-error "conversion|constant|in .constexpr. expansion of" }
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-89481.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-89481.C
index 8ac4ef0fd36..6f8f6a8038e 100644
--- a/gcc/testsuite/g++.dg/cpp1y/constexpr-89481.C
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-89481.C
@@ -6,7 +6,7 @@  foo ()
 {
   union U { long long a; int b[2]; } u { 5LL };
   u.b[1] = 4;		// { dg-error "change of the active member of a union from" "" { target c++17_down } }
-  return u.b[0];
+  return u.b[0];	// { dg-error "accessing uninitialized array element" "" { target c++2a } }
 }
 
 constexpr int
@@ -19,6 +19,5 @@  bar ()
 
 static_assert (foo () == 0, "");	// { dg-error "non-constant condition for static assertion" }
 					// { dg-message "in 'constexpr' expansion of" "" { target *-*-* } .-1 }
-					// { dg-error "accessing uninitialized array element" "" { target c++2a } .-2 }
 static_assert (bar () == 4, "");	// { dg-error "non-constant condition for static assertion" "" { target c++17_down } }
 					// { dg-message "in 'constexpr' expansion of" "" { target c++17_down } .-1 }
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime1.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime1.C
index 43aa7c974c1..f79f1611d5f 100644
--- a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime1.C
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime1.C
@@ -11,3 +11,4 @@  constexpr const int& test() {
   return local.get();
 }
 constexpr int x = test();  // { dg-error "accessing object outside its lifetime" }
+
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime2.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime2.C
index 22cd919fcda..2f5ae8db6d5 100644
--- a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime2.C
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime2.C
@@ -8,9 +8,9 @@  struct S {
 
 constexpr int error() {
   const auto& local = S{}.get();  // { dg-message "note: declared here" }
-  return local;
+  return local;  // { dg-error "accessing object outside its lifetime" }
 }
-constexpr int x = error();  // { dg-error "accessing object outside its lifetime" }
+constexpr int x = error();  // { dg-message "in .constexpr. expansion" }
 
 constexpr int ok() {
   // temporary should only be destroyed after end of full-expression
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime3.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime3.C
index 6329f8cf6c6..53785521d05 100644
--- a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime3.C
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime3.C
@@ -7,7 +7,7 @@  constexpr int f(int i) {
     int j = 123;  // { dg-message "note: declared here" }
     p = &j;
   }
-  return *p;
+  return *p;  // { dg-error "accessing object outside its lifetime" }
 }
 
-constexpr int i = f(0);  // { dg-error "accessing object outside its lifetime" }
+constexpr int i = f(0);  // { dg-message "in .constexpr. expansion" }
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime4.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime4.C
index 181a1201663..4302da1eddc 100644
--- a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime4.C
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime4.C
@@ -5,7 +5,7 @@  constexpr const double& test() {
   return local;
 }
 
-static_assert(test() == 3.0, "");  // { dg-error "constant|accessing object outside its lifetime" }
+static_assert(test() == 3.0, "");  // { dg-error "non-constant condition|accessing object outside its lifetime" }
 
 // no deference, shouldn't error
 static_assert((test(), true), "");
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C
index ad3ef579f63..a12920c8fba 100644
--- a/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C
@@ -5,7 +5,7 @@  constexpr const int& id(int x) { return x; }  // { dg-message "note: declared he
 
 constexpr bool test() {
   const int& y = id(3);
-  return y == 3;
+  return y == 3;  // { dg-error "accessing object outside its lifetime" }
 }
 
-constexpr bool x = test();  // { dg-error "accessing object outside its lifetime" }
+constexpr bool x = test();  // { dg-message "in .constexpr. expansion" }
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-union5.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-union5.C
index 55fe9fa2f0b..3d76345d564 100644
--- a/gcc/testsuite/g++.dg/cpp1y/constexpr-union5.C
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-union5.C
@@ -8,8 +8,8 @@  union U {
 };
 
 constexpr int foo(U *up) {
-  up->a++;
+  up->a++; // { dg-error "accessing uninitialized member" }
   return {42};
 }
 
-extern constexpr U u = {}; // { dg-error "accessing uninitialized member" }
+extern constexpr U u = {}; // { dg-message "in .constexpr. expansion" }
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr68180.C b/gcc/testsuite/g++.dg/cpp1y/pr68180.C
index 9e6e5e984f9..8de1ef3936b 100644
--- a/gcc/testsuite/g++.dg/cpp1y/pr68180.C
+++ b/gcc/testsuite/g++.dg/cpp1y/pr68180.C
@@ -6,11 +6,11 @@  typedef float __attribute__( ( vector_size( 16 ) ) ) float32x4_t;
 constexpr float32x4_t fill(float x) {
   float32x4_t v{0};
   constexpr auto vs = sizeof(v)/sizeof(v[0]);
-  for (auto i=0U; i<vs; ++i) v[i]=i;
+  for (auto i=0U; i<vs; ++i) v[i]=i; // { dg-error "not a constant" }
   return v+x;
 }
 
 float32x4_t foo(float32x4_t x) {
-  constexpr float32x4_t v = fill(1.f); // { dg-error "not a constant||in .constexpr. expansion of " }
+  constexpr float32x4_t v = fill(1.f); // { dg-message "in .constexpr. expansion of " }
   return x+v;
 }
diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda6.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda6.C
index 214d3821299..c46c2d4c7fe 100644
--- a/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda6.C
+++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda6.C
@@ -1,7 +1,7 @@ 
 // Testcase from P0170R1
 // { dg-do compile { target c++17 } }
 
-auto monoid = [](auto v) { return [=] { return v; }; };
+auto monoid = [](auto v) { return [=] { return v; }; };  // { dg-error "not usable in a constant expression" }
 auto add = [](auto m1) constexpr {
   auto ret = m1();
   return [=](auto m2) mutable {
@@ -22,7 +22,7 @@  int main()
   // member function call operator can not perform an lvalue-to-rvalue conversion
   // on one of its subobjects (that represents its capture) in a constant
   // expression.
-  auto two = monoid(2);
+  auto two = monoid(2);  // { dg-message "not declared .constexpr." }
   if (!(two() == 2)) __builtin_abort(); // OK, not a constant expression.
   static_assert(add(one)(one)() == two()); // { dg-error "|in .constexpr. expansion of " } two() is not a constant expression
   static_assert(add(one)(one)() == monoid(2)()); // OK
diff --git a/gcc/testsuite/g++.dg/cpp2a/bit-cast11.C b/gcc/testsuite/g++.dg/cpp2a/bit-cast11.C
index a3eb31bc6c7..760c9ca40b4 100644
--- a/gcc/testsuite/g++.dg/cpp2a/bit-cast11.C
+++ b/gcc/testsuite/g++.dg/cpp2a/bit-cast11.C
@@ -28,7 +28,7 @@  f3 ()
 {
   T t = { 1, 2 };
   S s = __builtin_bit_cast (S, t);
-  return s.a[1] == 0;
+  return s.a[1] == 0;		// { dg-error "accessing uninitialized array element" }
 }
 
 constexpr bool
@@ -52,12 +52,12 @@  f6 ()
 {
   W t = { 1, 2 };
   V s = __builtin_bit_cast (V, t);
-  return s.b.a[1] == 1;
+  return s.b.a[1] == 1;		// { dg-error "accessing uninitialized array element" }
 }
 
 constexpr bool a = f1 ();
 constexpr bool b = f2 ();
-constexpr bool c = f3 ();	// { dg-error "accessing uninitialized array element" }
-constexpr bool d = f4 ();
+constexpr bool c = f3 ();	// { dg-message "in .constexpr. expansion" }
+constexpr bool d = f4 ();	// { dg-message "in .constexpr. expansion" }
 constexpr bool e = f5 ();
-constexpr bool f = f6 ();	// { dg-error "accessing uninitialized array element" }
+constexpr bool f = f6 ();	// { dg-message "in .constexpr. expansion" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/bit-cast12.C b/gcc/testsuite/g++.dg/cpp2a/bit-cast12.C
index 9c699dd55f0..e205bc6a8c1 100644
--- a/gcc/testsuite/g++.dg/cpp2a/bit-cast12.C
+++ b/gcc/testsuite/g++.dg/cpp2a/bit-cast12.C
@@ -33,7 +33,7 @@  f3 ()
 {
   T t = { 1, 2 };
   S s = __builtin_bit_cast (S, t);
-  return s.a[1] == 0;
+  return s.a[1] == 0;		// { dg-error "accessing uninitialized array element" }
 }
 
 constexpr bool
@@ -57,12 +57,12 @@  f6 ()
 {
   W t = { 1, 2 };
   V s = __builtin_bit_cast (V, t);
-  return s.b.a[1] == 1;
+  return s.b.a[1] == 1;		// { dg-error "accessing uninitialized array element" }
 }
 
 constexpr bool a = f1 ();
 constexpr bool b = f2 ();
-constexpr bool c = f3 ();	// { dg-error "accessing uninitialized array element" }
-constexpr bool d = f4 ();
+constexpr bool c = f3 ();	// { dg-message "in .constexpr. expansion" }
+constexpr bool d = f4 ();	// { dg-message "in .constexpr. expansion" }
 constexpr bool e = f5 ();
-constexpr bool f = f6 ();	// { dg-error "accessing uninitialized array element" }
+constexpr bool f = f6 ();	// { dg-message "in .constexpr. expansion" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/bit-cast14.C b/gcc/testsuite/g++.dg/cpp2a/bit-cast14.C
index 5e185919be4..e0cc9a39702 100644
--- a/gcc/testsuite/g++.dg/cpp2a/bit-cast14.C
+++ b/gcc/testsuite/g++.dg/cpp2a/bit-cast14.C
@@ -44,7 +44,7 @@  f5 ()
 {
   T1 t = { 0, 0, 0, 0, 0, 0, 0 };
   S s = __builtin_bit_cast (S, t);
-  unsigned char a = s.a;
+  unsigned char a = s.a;		// { dg-error "accessing uninitialized member" }
   return true;
 }
 
@@ -53,7 +53,7 @@  f6 ()
 {
   T2 t = { 0, 0, 0, 0, 0, 0, 0 };
   S s = __builtin_bit_cast (S, t);
-  unsigned char b = s.b;
+  unsigned char b = s.b;		// { dg-error "accessing uninitialized member" }
   return true;
 }
 
@@ -62,14 +62,14 @@  f7 ()
 {
   T3 t = { 0, 0, 0, 0, 0, 0, 0 };
   S s = __builtin_bit_cast (S, t);
-  unsigned char c = s.c;
+  unsigned char c = s.c;		// { dg-error "accessing uninitialized member" }
   return true;
 }
 
 constexpr bool a = f1 ();
 constexpr bool b = f2 ();
 constexpr bool c = f3 ();
-constexpr bool d = f4 ();
-constexpr bool e = f5 ();	// { dg-error "accessing uninitialized member" }
-constexpr bool f = f6 ();	// { dg-error "accessing uninitialized member" }
-constexpr bool g = f7 ();	// { dg-error "accessing uninitialized member" }
+constexpr bool d = f4 ();	// { dg-message "in .constexpr. expansion" }
+constexpr bool e = f5 ();	// { dg-message "in .constexpr. expansion" }
+constexpr bool f = f6 ();	// { dg-message "in .constexpr. expansion" }
+constexpr bool g = f7 ();	// { dg-message "in .constexpr. expansion" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-98122.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-98122.C
index 01bdfa5bd4d..b0c91d5ef97 100644
--- a/gcc/testsuite/g++.dg/cpp2a/constexpr-98122.C
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-98122.C
@@ -9,7 +9,7 @@  bar ()
 {
   V f { .b = 42 };
   constexpr auto m = &V::a;
-  return (f.*m) == 42;
+  return (f.*m) == 42;  // { dg-error "accessing 'V::a' member instead of initialized 'V::b' member in constant expression" }
 }
 
 constexpr bool
@@ -21,5 +21,5 @@  baz ()
 }
 
 static_assert (bar (), "");	// { dg-error "non-constant condition for static assertion" }
-				// { dg-error "accessing 'V::a' member instead of initialized 'V::b' member in constant expression" "" { target *-*-* } .-1 }
+				// { dg-message "in .constexpr. expansion" "" { target *-*-* } .-1 }
 static_assert (baz (), "");
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic17.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic17.C
index a26678e6ed7..28facf192df 100644
--- a/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic17.C
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic17.C
@@ -25,8 +25,7 @@  struct D : B, A {
 
 constexpr B::B(V* v, A* a)
 {
-  dynamic_cast<B*>(a);
+  dynamic_cast<B*>(a); // { dg-error "accessing uninitialized member" }
 }
 
-constexpr D d; // { dg-error "accessing uninitialized member" }
-// { dg-message "in 'constexpr' expansion of" "" { target *-*-* } .-1 }
+constexpr D d; // { dg-message "in 'constexpr' expansion of" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-init1.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-init1.C
index e56ecfed48a..b4e39b6f928 100644
--- a/gcc/testsuite/g++.dg/cpp2a/constexpr-init1.C
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-init1.C
@@ -52,11 +52,10 @@  constexpr int
 fn5 ()
 {
   struct S { int a = 9; int b; } s;
-  return s.b;
+  return s.b; // { dg-error "accessing uninitialized member" }
 }
 
-constexpr int b = fn5 (); // { dg-error "accessing uninitialized member" }
-// { dg-message "in .constexpr. expansion of" "" { target *-*-* } .-1 }
+constexpr int b = fn5 (); // { dg-message "in .constexpr. expansion of" }
 
 constexpr int
 fn6 ()
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new12.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new12.C
index 5a3d06a5fab..832782e1427 100644
--- a/gcc/testsuite/g++.dg/cpp2a/constexpr-new12.C
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-new12.C
@@ -17,11 +17,11 @@  struct B : A {
 constexpr int
 foo ()
 {
-  A *a = new B ();
+  A *a = new B ();  // { dg-message "allocated here" }
   a->a = 4;
   delete a;
-  int r = a->foo ();
+  int r = a->foo ();  // { dg-error "constant expression" }
   return r;
 }
 
-constexpr auto a = foo ();	// { dg-error "constant expression" }
+constexpr auto a = foo ();  // { dg-message "in .constexpr. expansion" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new3.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new3.C
index 70b841208f8..3ba440fec53 100644
--- a/gcc/testsuite/g++.dg/cpp2a/constexpr-new3.C
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-new3.C
@@ -45,11 +45,10 @@  constexpr bool
 f5 ()
 {
   int *p = new int;		// { dg-message "allocated here" }
-  return *p == 1;
+  return *p == 1;		// { dg-error "the content of uninitialized storage is not usable in a constant expression" }
 }
 
-constexpr auto v5 = f5 ();	// { dg-error "the content of uninitialized storage is not usable in a constant expression" }
-				// { dg-message "in 'constexpr' expansion of" "" { target *-*-* } .-1 }
+constexpr auto v5 = f5 (); 	// { dg-message "in 'constexpr' expansion of" }
 
 constexpr bool
 f6 ()
@@ -57,11 +56,10 @@  f6 ()
   int *p = new int (2);		// { dg-message "allocated here" }
   int *q = p;
   delete p;
-  return *q == 2;
+  return *q == 2;		// { dg-error "use of allocated storage after deallocation in a constant expression" }
 }
 
-constexpr auto v6 = f6 ();	// { dg-error "use of allocated storage after deallocation in a constant expression" }
-				// { dg-message "in 'constexpr' expansion of" "" { target *-*-* } .-1  }
+constexpr auto v6 = f6 (); 	// { dg-message "in 'constexpr' expansion of" }
 
 constexpr int *
 f7 ()
diff --git a/gcc/testsuite/g++.dg/ext/constexpr-vla2.C b/gcc/testsuite/g++.dg/ext/constexpr-vla2.C
index d4ea7c58c0d..e09a27af3de 100644
--- a/gcc/testsuite/g++.dg/ext/constexpr-vla2.C
+++ b/gcc/testsuite/g++.dg/ext/constexpr-vla2.C
@@ -4,7 +4,7 @@ 
 constexpr int
 fn_bad (int n)
 {
-  __extension__ int a [n] = { 0 };
+  __extension__ int a [n] = { 0 };  // { dg-error "array subscript" }
   int z = a [0] + (n ? fn_bad (n - 1) : 0); // { dg-message "in .constexpr. expansion of " } 
   return z;
 }
@@ -18,4 +18,4 @@  fn_ok (int n)
 }
 
 constexpr int i1 = fn_ok (3);
-constexpr int i2 = fn_bad (3); // { dg-error "array subscript|in .constexpr. expansion of " }
+constexpr int i2 = fn_bad (3); // { dg-message "in .constexpr. expansion of " }
diff --git a/gcc/testsuite/g++.dg/ext/constexpr-vla3.C b/gcc/testsuite/g++.dg/ext/constexpr-vla3.C
index 538b576a825..6f9daa1897f 100644
--- a/gcc/testsuite/g++.dg/ext/constexpr-vla3.C
+++ b/gcc/testsuite/g++.dg/ext/constexpr-vla3.C
@@ -4,11 +4,11 @@ 
 constexpr int
 foo (int n)
 {
-  __extension__ int a[n] = { 1, 2, 3, 4, 5, 6 };
+  __extension__ int a[n] = { 1, 2, 3, 4, 5, 6 }; // { dg-error "array subscript" }
   int z = 0;
   for (int i = 0; i <= n; ++i)
     z += a[i];
   return z;
 }
 
-constexpr int n = foo (3); // { dg-error "array subscript|in .constexpr. expansion of " }
+constexpr int n = foo (3); // { dg-message "in .constexpr. expansion of " }
diff --git a/gcc/testsuite/g++.dg/ubsan/pr63956.C b/gcc/testsuite/g++.dg/ubsan/pr63956.C
index 3a1596e6e2e..0771732ef00 100644
--- a/gcc/testsuite/g++.dg/ubsan/pr63956.C
+++ b/gcc/testsuite/g++.dg/ubsan/pr63956.C
@@ -100,13 +100,13 @@  constexpr int
 fn7 (const int *a, int b)
 {
   if (b != 3)
-    return fn6 (*a, b);
+    return fn6 (*a, b); // { dg-error "null pointer" }
   return 7;
 }
 
 constexpr int n1 = 7;
 constexpr int n2 = fn7 (&n1, 5);
-constexpr int n3 = fn7 ((const int *) 0, 8);  // { dg-error "null pointer|in .constexpr. expansion of " }
+constexpr int n3 = fn7 ((const int *) 0, 8);  // { dg-message "in .constexpr. expansion of " }
 
 constexpr int
 fn8 (int i)
diff --git a/libstdc++-v3/testsuite/25_algorithms/equal/constexpr_neg.cc b/libstdc++-v3/testsuite/25_algorithms/equal/constexpr_neg.cc
index 34ca5c4805c..fd89ac0e166 100644
--- a/libstdc++-v3/testsuite/25_algorithms/equal/constexpr_neg.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/equal/constexpr_neg.cc
@@ -32,7 +32,7 @@  test01()
   return outa;
 }
 
-static_assert(test01()); // { dg-error "outside the bounds" }
+static_assert(test01()); // { dg-error "non-constant condition" }
 
 constexpr bool
 test02()
@@ -44,7 +44,8 @@  test02()
   return outa;
 }
 
-static_assert(test02()); // { dg-error "outside the bounds" }
+static_assert(test02()); // { dg-error "non-constant condition" }
 
-// { dg-prune-output "non-constant condition" }
+// Errors occuring within <algorithm> internals:
+// { dg-error "outside the bounds of array" "" { target *-*-* } 0 }
 // { dg-prune-output "in 'constexpr'" }