Skip to content

Commit

Permalink
c++: Improve location information in constant evaluation
Browse files Browse the repository at this point in the history
This patch updates 'input_location' during constant evaluation to ensure
that errors in subexpressions that lack location information still
provide accurate diagnostics.

By itself this change causes some small regressions in diagnostic
quality for circumstances where errors used 'input_location' but the
location of the parent subexpression doesn't make sense, so this patch
also includes a couple of other small diagnostic improvements to improve
the most egregious cases.

gcc/cp/ChangeLog:

	* constexpr.cc (modifying_const_object_error): Find the source
	location of the const object's declaration.
	(cxx_eval_store_expression): Fall back to the location of the
	target object when evaluating initialiser.
	(cxx_eval_constant_expression): Update input_location to the location
	of the currently evaluated expression, if possible.

libstdc++-v3/ChangeLog:

	* testsuite/25_algorithms/equal/constexpr_neg.cc: Update diagnostic
	locations.
	* testsuite/26_numerics/gcd/105844.cc: Likewise.
	* testsuite/26_numerics/lcm/105844.cc: Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp0x/constexpr-48089.C: Update diagnostic locations.
	* g++.dg/cpp0x/constexpr-70323.C: Likewise.
	* g++.dg/cpp0x/constexpr-70323a.C: Likewise.
	* g++.dg/cpp0x/constexpr-delete2.C: Likewise.
	* g++.dg/cpp0x/constexpr-diag3.C: Likewise.
	* g++.dg/cpp0x/constexpr-ice20.C: Likewise.
	* g++.dg/cpp0x/constexpr-recursion.C: Likewise.
	* g++.dg/cpp0x/overflow1.C: Likewise.
	* g++.dg/cpp1y/constexpr-89285.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-tracking-const14.C: Likewise.
	* g++.dg/cpp1y/constexpr-tracking-const16.C: Likewise.
	* g++.dg/cpp1y/constexpr-tracking-const18.C: Likewise.
	* g++.dg/cpp1y/constexpr-tracking-const19.C: Likewise.
	* g++.dg/cpp1y/constexpr-tracking-const21.C: Likewise.
	* g++.dg/cpp1y/constexpr-tracking-const22.C: Likewise.
	* g++.dg/cpp1y/constexpr-tracking-const3.C: Likewise.
	* g++.dg/cpp1y/constexpr-tracking-const4.C: Likewise.
	* g++.dg/cpp1y/constexpr-tracking-const7.C: Likewise.
	* g++.dg/cpp1y/constexpr-union5.C: Likewise.
	* g++.dg/cpp1y/pr68180.C: Likewise.
	* g++.dg/cpp1z/constexpr-lambda6.C: Likewise.
	* g++.dg/cpp1z/constexpr-lambda8.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/cpp2a/constinit10.C: Likewise.
	* g++.dg/cpp2a/is-corresponding-member4.C: Likewise.
	* g++.dg/ext/constexpr-vla2.C: Likewise.
	* g++.dg/ext/constexpr-vla3.C: Likewise.
	* g++.dg/ubsan/pr63956.C: Likewise.

Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
  • Loading branch information
wreien authored and ouuleilei-bot committed Jul 20, 2023
1 parent 757b90e commit c87f82f
Show file tree
Hide file tree
Showing 45 changed files with 170 additions and 124 deletions.
46 changes: 45 additions & 1 deletion gcc/cp/constexpr.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2176,7 +2176,33 @@ modifying_const_object_error (tree expr, tree obj)
auto_diagnostic_group d;
error_at (loc, "modifying a const object %qE is not allowed in "
"a constant expression", TREE_OPERAND (expr, 0));
inform (location_of (obj), "originally declared %<const%> here");

/* Find the underlying object that was declared as const. */
location_t decl_loc = UNKNOWN_LOCATION;
for (tree probe = obj; decl_loc == UNKNOWN_LOCATION; )
switch (TREE_CODE (probe))
{
case BIT_FIELD_REF:
case COMPONENT_REF:
{
tree elt = TREE_OPERAND (probe, 1);
if (CP_TYPE_CONST_P (TREE_TYPE (elt)))
decl_loc = DECL_SOURCE_LOCATION (elt);
probe = TREE_OPERAND (probe, 0);
}
break;

case ARRAY_REF:
case REALPART_EXPR:
case IMAGPART_EXPR:
probe = TREE_OPERAND (probe, 0);
break;

default:
decl_loc = location_of (probe);
break;
}
inform (decl_loc, "originally declared %<const%> here");
}

/* Return true if FNDECL is a replaceable global allocation function that
Expand Down Expand Up @@ -6263,6 +6289,21 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
if (TREE_CODE (init) == TARGET_EXPR)
if (tree tinit = TARGET_EXPR_INITIAL (init))
init = tinit;

/* Improve error messages for initialisers when the initialising
expression has no location information by pointing to the decl
that is getting initialised. */
location_t target_loc = cp_expr_loc_or_input_loc (init);
if (!EXPR_HAS_LOCATION (init))
{
if (DECL_P (target))
target_loc = DECL_SOURCE_LOCATION (target);
else if (TREE_CODE (target) == COMPONENT_REF
|| TREE_CODE (target) == BIT_FIELD_REF)
target_loc = DECL_SOURCE_LOCATION (TREE_OPERAND (target, 1));
}
iloc_sentinel sentinel = target_loc;

init = cxx_eval_constant_expression (&new_ctx, init, vc_prvalue,
non_constant_p, overflow_p);
/* The hash table might have moved since the get earlier, and the
Expand Down Expand Up @@ -6951,7 +6992,10 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
return t;
}

/* Change the input location to the currently processed expression for
better error messages when a subexpression has no location. */
location_t loc = cp_expr_loc_or_input_loc (t);
iloc_sentinel sentinel (loc);

STRIP_ANY_LOCATION_WRAPPER (t);

Expand Down
10 changes: 5 additions & 5 deletions gcc/testsuite/g++.dg/cpp0x/constexpr-48089.C
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 {
Expand Down
8 changes: 4 additions & 4 deletions gcc/testsuite/g++.dg/cpp0x/constexpr-70323.C
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// PR c++/70323
// { dg-do compile { target c++11 } }

constexpr int overflow_if_0 (int i) { return __INT_MAX__ + !i; }
constexpr int overflow_if_1 (int i) { return __INT_MAX__ + i; }
constexpr int overflow_if_0 (int i) { return __INT_MAX__ + !i; } // { dg-error "overflow in constant expression" }
constexpr int overflow_if_1 (int i) { return __INT_MAX__ + i; } // { dg-error "overflow in constant expression" }

constexpr bool i0_0 = overflow_if_0 (0); // { dg-error "overflow in constant expression|in .constexpr. expansion of " }
constexpr bool i0_0 = overflow_if_0 (0); // { dg-message "in .constexpr. expansion of " }
constexpr bool i0_1 = overflow_if_0 (1);
constexpr bool i1_0 = overflow_if_1 (0);
constexpr bool i1_1 = overflow_if_1 (1); // { dg-error "overflow in constant expression|in .constexpr. expansion of " }
constexpr bool i1_1 = overflow_if_1 (1); // { dg-message "in .constexpr. expansion of " }
8 changes: 4 additions & 4 deletions gcc/testsuite/g++.dg/cpp0x/constexpr-70323a.C
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
// { dg-do compile { target c++11 } }
// { dg-options "-Wall" }

constexpr int overflow_if_0 (int i) { return __INT_MAX__ + !i; }
constexpr int overflow_if_1 (int i) { return __INT_MAX__ + i; }
constexpr int overflow_if_0 (int i) { return __INT_MAX__ + !i; } // { dg-error "overflow in constant expression" }
constexpr int overflow_if_1 (int i) { return __INT_MAX__ + i; } // { dg-error "overflow in constant expression" }

constexpr bool i0_0 = overflow_if_0 (0); // { dg-error "overflow in constant expression|in .constexpr. expansion of" }
constexpr bool i0_0 = overflow_if_0 (0); // { dg-message "in .constexpr. expansion of" }
constexpr bool i0_1 = overflow_if_0 (1);
constexpr bool i1_0 = overflow_if_1 (0);
constexpr bool i1_1 = overflow_if_1 (1); // { dg-error "overflow in constant expression|in .constexpr. expansion of" }
constexpr bool i1_1 = overflow_if_1 (1); // { dg-message "in .constexpr. expansion of" }
5 changes: 3 additions & 2 deletions gcc/testsuite/g++.dg/cpp0x/constexpr-delete2.C
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ constexpr int f(int i) { return i; }
constexpr int g(A* ap)
{
return f((delete[] ap, 42)); // { dg-message "" "" { target c++17_down } }
// { dg-error "" "" { target c++2a } .-1 }
}

A a;
constexpr int i = g(&a); // { dg-error "" }
// { dg-message "in 'constexpr' expansion of" "" { target c++2a } .-1 }
constexpr int i = g(&a); // { dg-error "" "" { target c++17_down } }
// { dg-message "in 'constexpr' expansion of" "" { target c++2a } .-1 }
2 changes: 1 addition & 1 deletion gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
1 change: 1 addition & 0 deletions gcc/testsuite/g++.dg/cpp0x/constexpr-ice20.C
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@

typedef bool (*Function)(int);
constexpr bool check(int x, Function p) { return p(x); } // { dg-message "in .constexpr. expansion of" }
// { dg-error "not a constant expression" "" { target *-*-* } .-1 }

static_assert(check(2, check), ""); // { dg-error "conversion|constant|in .constexpr. expansion of" }
6 changes: 3 additions & 3 deletions gcc/testsuite/g++.dg/cpp0x/constexpr-recursion.C
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Test that we catch excessive recursion.
// { dg-do compile { target c++11 } }
// { dg-options "-fconstexpr-depth=5" }
// { dg-prune-output "in constexpr expansion" }
constexpr int f (int i) { return f (i-1); } // { dg-message "in .constexpr. expansion of " }
constexpr int i = f(42); // { dg-error ".constexpr. evaluation depth|in .constexpr. expansion of " }
// { dg-prune-output "in .constexpr. expansion" }
constexpr int f (int i) { return f (i-1); } // { dg-error ".constexpr. evaluation depth" }
constexpr int i = f(42);
2 changes: 1 addition & 1 deletion gcc/testsuite/g++.dg/cpp0x/overflow1.C
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ template <long long i>
struct Fib
{
static const long long value // { dg-error "overflow" }
= Fib<i-1>::value + Fib<i-2>::value;
= Fib<i-1>::value + Fib<i-2>::value; // { dg-error "overflow" }
};

template <>
Expand Down
5 changes: 3 additions & 2 deletions gcc/testsuite/g++.dg/cpp1y/constexpr-89285.C
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ struct B {
}
};
struct C : A {
B bar {this};
B bar {this}; // { dg-error "" "" { target c++14_down } }
};

constexpr C foo {}; // { dg-message "" }
// error path changes in C++17 due to `C` becoming an aggregate
constexpr C foo {}; // { dg-error "" "" { target c++17 } }
3 changes: 1 addition & 2 deletions gcc/testsuite/g++.dg/cpp1y/constexpr-89481.C
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 }
1 change: 1 addition & 0 deletions gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime1.C
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ constexpr const int& test() {
return local.get();
}
constexpr int x = test(); // { dg-error "accessing object outside its lifetime" }

4 changes: 2 additions & 2 deletions gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime2.C
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime3.C
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
2 changes: 1 addition & 1 deletion gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime4.C
Original file line number Diff line number Diff line change
Expand Up @@ -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), "");
4 changes: 2 additions & 2 deletions gcc/testsuite/g++.dg/cpp1y/constexpr-lifetime5.C
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
3 changes: 1 addition & 2 deletions gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const14.C
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ struct C {

struct A {
int r;
const C c;
const C c; // { dg-message "originally declared" }
constexpr A() : r(11) { r = 14; const_cast<C &>(c).n = 42; } // { dg-error "modifying a const object" }
};

Expand All @@ -34,5 +34,4 @@ struct B {
};

constexpr B b(false); // { dg-message "in .constexpr. expansion of" }
// { dg-message "originally declared" "" { target *-*-* } .-1 }
static_assert(b.e.d.a.c.n == 2, ""); // { dg-error "non-constant condition" }
3 changes: 1 addition & 2 deletions gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const16.C
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ constexpr int& impl(const int (&array)[10], int index) {

struct A {
constexpr int& operator[](int i) { return impl(elems, i); }
const int elems[10];
const int elems[10]; // { dg-message "originally declared" }
};

constexpr bool
Expand All @@ -19,4 +19,3 @@ f()
}

constexpr bool b = f(); // { dg-message "in .constexpr. expansion of " }
// { dg-message "originally declared" "" { target *-*-* } .-1 }
4 changes: 2 additions & 2 deletions gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const18.C
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ struct array
template <typename T>
struct S {
using U = array<T, 4>;
const U m;
const U m; // { dg-message "originally declared" }
constexpr S(int) : m{}
{
const_cast<int &>(const_cast<const U &>(m)[0]) = 42; // { dg-error "modifying a const object" }
}
};

constexpr S<int> p = { 10 }; // { dg-message "originally declared" }
constexpr S<int> p = { 10 };
4 changes: 2 additions & 2 deletions gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const19.C
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ template <typename E, size_t N>
struct array
{
constexpr const E &operator[](size_t n) const noexcept { return elems[n]; }
const E elems[N];
const E elems[N]; // { dg-message "originally declared" }
};

template <typename T>
Expand All @@ -20,4 +20,4 @@ struct S {
}
};

constexpr S<int> p = { 10 }; // { dg-message "originally declared" }
constexpr S<int> p = { 10 };
4 changes: 2 additions & 2 deletions gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const21.C
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ struct array2 {
template <typename T>
struct S {
using U = array2<T, 4>;
const U m;
const U m; // { dg-message "originally declared" }
constexpr S(int) : m{}
{
const_cast<int &>(m.a[0]) = 42; // { dg-error "modifying a const object" }
}
};

constexpr S<int> p = { 10 }; // { dg-message "originally declared" }
constexpr S<int> p = { 10 };
4 changes: 2 additions & 2 deletions gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const22.C
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ struct X {

template <typename T>
struct S {
const X x;
const X x; // { dg-message "originally declared" }
constexpr S(int) : x{}
{
const_cast<X&>(x).i = 19; // { dg-error "modifying a const object" }
}
};

constexpr S<int> p = { 10 }; // { dg-message "originally declared" }
constexpr S<int> p = { 10 };
3 changes: 1 addition & 2 deletions gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const3.C
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ struct A {
};

struct B {
const A a;
const A a; // { dg-message "originally declared" }
constexpr B(bool b) {
if (b)
const_cast<A &>(a).n = 3; // { dg-error "modifying a const object" }
Expand All @@ -18,5 +18,4 @@ constexpr B b(false);
static_assert(b.a.n == 2, "");

constexpr B b2(true); // { dg-message "in .constexpr. expansion of " }
// { dg-message "originally declared" "" { target *-*-* } .-1 }
static_assert((b2.a.n, 1), "");
3 changes: 1 addition & 2 deletions gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const4.C
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// { dg-do compile { target c++14 } }

struct A {
const int n;
const int n; // { dg-message "originally declared" }
constexpr A() : n(1) { }
};
struct B {
Expand All @@ -13,5 +13,4 @@ struct B {
}
};
constexpr B b; // { dg-message "in .constexpr. expansion of " }
// { dg-message "originally declared" "" { target *-*-* } .-1 }
static_assert((b.a.n, 1), "");
3 changes: 1 addition & 2 deletions gcc/testsuite/g++.dg/cpp1y/constexpr-tracking-const7.C
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

struct D { int n; };

struct C { const D d; };
struct C { const D d; }; // { dg-message "originally declared" }

struct A {
C c;
Expand All @@ -19,5 +19,4 @@ struct B {
};

constexpr B b{}; // { dg-message "in .constexpr. expansion of " }
// { dg-message "originally declared" "" { target *-*-* } .-1 }
static_assert((b.a.c.d.n, 1), "");
4 changes: 2 additions & 2 deletions gcc/testsuite/g++.dg/cpp1y/constexpr-union5.C
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
Loading

0 comments on commit c87f82f

Please sign in to comment.