[v2,3/3] c++: Improve location information in constexpr evaluation
Commit Message
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
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
>
>
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
> >
> >
>
@@ -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;
@@ -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 {
@@ -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:
@@ -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" }
@@ -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 }
@@ -11,3 +11,4 @@ constexpr const int& test() {
return local.get();
}
constexpr int x = test(); // { dg-error "accessing object outside its lifetime" }
+
@@ -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
@@ -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" }
@@ -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), "");
@@ -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" }
@@ -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" }
@@ -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;
}
@@ -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
@@ -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" }
@@ -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" }
@@ -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" }
@@ -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 (), "");
@@ -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" }
@@ -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 ()
@@ -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" }
@@ -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 ()
@@ -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 " }
@@ -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 " }
@@ -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)
@@ -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'" }