@@ -2165,7 +2165,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
@@ -6286,6 +6312,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
@@ -6986,7 +7027,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);
@@ -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 {
@@ -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 " }
@@ -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" }
@@ -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 }
@@ -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:
@@ -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" }
@@ -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);
@@ -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 <>
@@ -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 } }
@@ -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" }
@@ -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" }
};
@@ -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" }
@@ -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
@@ -19,4 +19,3 @@ f()
}
constexpr bool b = f(); // { dg-message "in .constexpr. expansion of " }
-// { dg-message "originally declared" "" { target *-*-* } .-1 }
@@ -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 };
@@ -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>
@@ -20,4 +20,4 @@ struct S {
}
};
-constexpr S<int> p = { 10 }; // { dg-message "originally declared" }
+constexpr S<int> p = { 10 };
@@ -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 };
@@ -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 };
@@ -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" }
@@ -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), "");
@@ -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 {
@@ -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,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;
@@ -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), "");
@@ -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
@@ -4,11 +4,14 @@
auto Fwd = [](int (*fp)(int), auto a) { return fp(a); };
auto C = [](auto a) { return a; };
static_assert( Fwd(C ,3) == 3); // OK
+
// No specialization of the function call operator template can be constexpr
// (because of the local static).
auto NC = [](auto a) { static int s; return a; }; // { dg-error "static" }
-// { dg-message "operator int" "" { target *-*-* } .+1 }
+// { dg-error "called in a constant expression" "" { target *-*-* } .-1 }
+
static_assert( Fwd(NC ,3) == 3); // { dg-error "" }
+// { dg-message "operator int" "" { target *-*-* } .-1 }
// We look for the string "operator int" to check that we aren't trying to do
// template pretty-printing in an expression; that gets incredibly unwieldy
@@ -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 ()
@@ -11,15 +11,14 @@ struct S1
struct alignas(64) S2
{
constexpr S2 ()
- : m_tabS1()
+ : m_tabS1() // { dg-error "used before its definition" }
{}
S1 m_tabS1[7];
};
constinit S2 objX; // { dg-error ".constinit. variable .objX. does not have a constant initializer" }
-// { dg-error "used before its definition" "" { target *-*-* } .-1 }
-// // { dg-message "in .constexpr. expansion of" "" { target *-*-* } .-2 }
+// { dg-message "in .constexpr. expansion of" "" { target *-*-* } .-1 }
constexpr S1::S1 ()
: m_i(14)
@@ -14,8 +14,8 @@ is_corresponding_member (M1 S1::*m1, M2 S2::*m2) noexcept
struct A { int a; };
struct B;
constexpr int B::*n = nullptr;
-constexpr auto a = std::is_corresponding_member (&A::a, n); // { dg-error "invalid use of incomplete type 'struct B'" }
-constexpr auto b = std::is_corresponding_member (n, &A::a); // { dg-error "invalid use of incomplete type 'struct B'" }
+constexpr auto a = std::is_corresponding_member (&A::a, n); // { dg-message "in .constexpr. expansion of" }
+constexpr auto b = std::is_corresponding_member (n, &A::a); // { dg-message "in .constexpr. expansion of" }
void
foo (int B::*m)
@@ -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 " }
@@ -56,12 +56,13 @@ fn3 (int a, int b)
{
if (b != 2)
a = a / b; // { dg-error "..7 / 0.. is not a constant expression" }
+ // { dg-error "overflow in constant expression" "" { target *-*-* } .-1 }
return a;
}
constexpr int k1 = fn3 (8, 4);
constexpr int k2 = fn3 (7, 0); // { dg-message "in .constexpr. expansion" }
-constexpr int k3 = fn3 (INT_MIN, -1); // { dg-error "overflow in constant expression|in .constexpr. expansion of " }
+constexpr int k3 = fn3 (INT_MIN, -1); // { dg-message "in .constexpr. expansion of " }
SA (k1 == 2);
@@ -100,13 +101,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)
@@ -122,15 +123,15 @@ constexpr int
fn9 (int a, int b)
{
if (b != 0)
- return a + b;
+ return a + b; // { dg-error "overflow in constant expression" }
return a;
}
constexpr int p1 = fn9 (42, 7);
-constexpr int p2 = fn9 (__INT_MAX__, 1); // { dg-error "overflow in constant expression|in .constexpr. expansion of " }
+constexpr int p2 = fn9 (__INT_MAX__, 1); // { dg-message "in .constexpr. expansion of " }
constexpr int p3 = fn9 (__INT_MAX__, -1);
constexpr int p4 = fn9 (INT_MIN, 1);
-constexpr int p5 = fn9 (INT_MIN, -1); // { dg-error "overflow in constant expression|in .constexpr. expansion of " }
+constexpr int p5 = fn9 (INT_MIN, -1); // { dg-message "in .constexpr. expansion of " }
SA (p1 == 49);
SA (p3 == __INT_MAX__ - 1);
@@ -140,13 +141,13 @@ constexpr int
fn10 (int a, int b)
{
if (b != 0)
- return a * b;
+ return a * b; // { dg-error "overflow in constant expression" }
return a;
}
constexpr int q1 = fn10 (10, 10);
-constexpr int q2 = fn10 (__INT_MAX__, 2); // { dg-error "overflow in constant expression|in .constexpr. expansion of " }
-constexpr int q3 = fn10 (INT_MIN, 2); // { dg-error "overflow in constant expression|in .constexpr. expansion of " }
+constexpr int q2 = fn10 (__INT_MAX__, 2); // { dg-message "in .constexpr. expansion of " }
+constexpr int q3 = fn10 (INT_MIN, 2); // { dg-message "in .constexpr. expansion of " }
constexpr int q4 = fn10 (-1, -1);
SA (q1 == 100);
@@ -155,14 +156,14 @@ SA (q4 == 1);
constexpr int
fn11 (double d)
{
- int i = d;
+ int i = d; // { dg-error "overflow in constant expression" }
if (i != 0)
return i;
return i * 2;
}
constexpr int r1 = fn11 (3.4);
-constexpr int r2 = fn11 (__builtin_inf ()); // { dg-error "overflow in constant expression|in .constexpr. expansion of " }
+constexpr int r2 = fn11 (__builtin_inf ()); // { dg-message "in .constexpr. expansion of " }
constexpr int
fn12 (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'" }
@@ -13,9 +13,11 @@ static_assert( std::gcd(LLONG_MIN, 2ull) == 2 );
static_assert( std::gcd(2ull, LLONG_MIN) == 2 );
// But |INT_MIN| cannot be represented in common_type<int, int> i.e. int.
-constexpr int a = std::gcd(INT_MIN, 1); // { dg-error "overflow" }
-constexpr int b = std::gcd(1, INT_MIN); // { dg-error "overflow" }
+constexpr int a = std::gcd(INT_MIN, 1); // { dg-error "in .constexpr." }
+constexpr int b = std::gcd(1, INT_MIN); // { dg-error "in .constexpr." }
// And |LLONG_MIN| cannot be represented in long.
-constexpr long long c = std::gcd(LLONG_MIN, 1); // { dg-error "overflow" }
-constexpr long long d = std::gcd(1, LLONG_MIN); // { dg-error "overflow" }
+constexpr long long c = std::gcd(LLONG_MIN, 1); // { dg-error "in .constexpr." }
+constexpr long long d = std::gcd(1, LLONG_MIN); // { dg-error "in .constexpr." }
+
+// { dg-error "overflow" "" { target *-*-* } 0 }
@@ -9,14 +9,16 @@ static_assert( std::lcm(INT_MIN, 1u) == INT_MAX+1u );
static_assert( std::lcm(1u, INT_MIN) == INT_MAX+1u );
// But |INT_MIN| cannot be represented in common_type<int, int> i.e. int.
-constexpr int a = std::lcm(INT_MIN, 1); // { dg-error "overflow" }
-constexpr int b = std::lcm(1, INT_MIN); // { dg-error "overflow" }
+constexpr int a = std::lcm(INT_MIN, 1); // { dg-error "in .constexpr." }
+constexpr int b = std::lcm(1, INT_MIN); // { dg-error "in .constexpr." }
// And the LCM of 50000 and 49999 cannot be represented in int.
-constexpr int c = std::lcm(50000, 49999); // { dg-error "overflow" }
-constexpr int d = std::lcm(49999, 50000); // { dg-error "overflow" }
+constexpr int c = std::lcm(50000, 49999); // { dg-error "in .constexpr." }
+constexpr int d = std::lcm(49999, 50000); // { dg-error "in .constexpr." }
// Similarly for unsigned, but the diagnostic is a failed assertion instead.
-constexpr int e = std::lcm(500000u, 499999); // { dg-error "in 'constexpr'" }
-constexpr int f = std::lcm(499999u, 500000); // { dg-error "in 'constexpr'" }
+constexpr int e = std::lcm(500000u, 499999); // { dg-error "in .constexpr." }
+constexpr int f = std::lcm(499999u, 500000); // { dg-error "in .constexpr." }
+
+// { dg-error "overflow" "" { target *-*-* } 0 }
// { dg-error "unreachable" "" { target *-*-* } 0 }
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. 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> --- gcc/cp/constexpr.cc | 46 ++++++++++++++++++- gcc/testsuite/g++.dg/cpp0x/constexpr-48089.C | 10 ++-- gcc/testsuite/g++.dg/cpp0x/constexpr-70323.C | 8 ++-- gcc/testsuite/g++.dg/cpp0x/constexpr-70323a.C | 8 ++-- .../g++.dg/cpp0x/constexpr-delete2.C | 5 +- gcc/testsuite/g++.dg/cpp0x/constexpr-diag3.C | 2 +- gcc/testsuite/g++.dg/cpp0x/constexpr-ice20.C | 1 + .../g++.dg/cpp0x/constexpr-recursion.C | 6 +-- gcc/testsuite/g++.dg/cpp0x/overflow1.C | 2 +- gcc/testsuite/g++.dg/cpp1y/constexpr-89285.C | 5 +- 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 +- .../g++.dg/cpp1y/constexpr-tracking-const14.C | 3 +- .../g++.dg/cpp1y/constexpr-tracking-const16.C | 3 +- .../g++.dg/cpp1y/constexpr-tracking-const18.C | 4 +- .../g++.dg/cpp1y/constexpr-tracking-const19.C | 4 +- .../g++.dg/cpp1y/constexpr-tracking-const21.C | 4 +- .../g++.dg/cpp1y/constexpr-tracking-const22.C | 4 +- .../g++.dg/cpp1y/constexpr-tracking-const3.C | 3 +- .../g++.dg/cpp1y/constexpr-tracking-const4.C | 3 +- .../g++.dg/cpp1y/constexpr-tracking-const7.C | 3 +- gcc/testsuite/g++.dg/cpp1y/constexpr-union5.C | 4 +- gcc/testsuite/g++.dg/cpp1y/pr68180.C | 4 +- .../g++.dg/cpp1z/constexpr-lambda6.C | 4 +- .../g++.dg/cpp1z/constexpr-lambda8.C | 5 +- 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/cpp2a/constinit10.C | 5 +- .../g++.dg/cpp2a/is-corresponding-member4.C | 4 +- 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 | 23 +++++----- .../25_algorithms/equal/constexpr_neg.cc | 7 +-- .../testsuite/26_numerics/gcd/105844.cc | 10 ++-- .../testsuite/26_numerics/lcm/105844.cc | 14 +++--- 45 files changed, 170 insertions(+), 124 deletions(-)