c++: constexpr new diagnostic location

Presenting the allocation location as the location of the outermost
expression we're trying to evaluate is inaccurate; let's provide both
locations.

gcc/cp/ChangeLog:

	* constexpr.cc (cxx_eval_outermost_constant_expr): Give both
	expression and allocation location in allocated storage diagnostics.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp1y/constexpr-new.C: Adjust diagnostics.
	* g++.dg/cpp1z/constexpr-asm-5.C: Likewise.
	* g++.dg/cpp26/static_assert1.C: Likewise.
	* g++.dg/cpp2a/constexpr-dtor7.C: Likewise.
	* g++.dg/cpp2a/constexpr-new26.C: Likewise.
	* g++.dg/cpp2a/constexpr-new3.C: Likewise.
	* g++.dg/cpp2a/constinit14.C: Likewise.
This commit is contained in:
Jason Merrill 2025-03-10 11:49:57 -04:00
parent 53d4e355db
commit 4cff0434e8
8 changed files with 31 additions and 21 deletions

View file

@ -9262,9 +9262,11 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
if (heap_var)
{
if (!allow_non_constant && !non_constant_p)
error_at (DECL_SOURCE_LOCATION (heap_var),
"%qE is not a constant expression because it refers to "
"a result of %<operator new%>", t);
{
error ("%qE is not a constant expression because it refers to "
"a result of %<operator new%>", t);
inform (DECL_SOURCE_LOCATION (heap_var), "allocated here");
}
r = t;
non_constant_p = true;
}
@ -9273,9 +9275,11 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
if (DECL_NAME (heap_var) != heap_deleted_identifier)
{
if (!allow_non_constant && !non_constant_p)
error_at (DECL_SOURCE_LOCATION (heap_var),
"%qE is not a constant expression because allocated "
"storage has not been deallocated", t);
{
error ("%qE is not a constant expression because allocated "
"storage has not been deallocated", t);
inform (DECL_SOURCE_LOCATION (heap_var), "allocated here");
}
r = t;
non_constant_p = true;
}

View file

@ -6,7 +6,9 @@ constexpr int *f4(bool b) {
return nullptr;
} else {
return new int{42}; // { dg-error "call to non-.constexpr." "" { target c++17_down } }
} // { dg-error "is not a constant expression because allocated storage has not been deallocated" "" { target c++2a } .-1 }
// { dg-message "allocated here" "" { target c++20 } .-1 }
}
}
static_assert(f4(true) == nullptr, "");
static_assert(f4(false) == nullptr, ""); // { dg-error "non-.constant. condition|" }
static_assert(f4(false) == nullptr, ""); // { dg-error "non-constant condition" }
// { dg-error "is not a constant expression because allocated storage has not been deallocated" "" { target c++20 } .-1 }

View file

@ -28,7 +28,7 @@ struct M { constexpr K size () const { return {}; }
constexpr L data () const { return {}; } };
#if __cpp_constexpr_dynamic_alloc >= 201907L
struct N { constexpr int size () const { return 3; }
constexpr const char *data () const { return new char[3] { 'b', 'a', 'd' }; } }; // { dg-error "'\\\* N\\\(\\\).N::data\\\(\\\)' is not a constant expression because allocated storage has not been deallocated" "" { target c++20 } }
constexpr const char *data () const { return new char[3] { 'b', 'a', 'd' }; } };
#endif
constexpr const char a[] = { 't', 'e', 's', 't' };
struct O { constexpr int size () const { return 4; }
@ -117,6 +117,7 @@ foo ()
asm ((M {}));
#if __cpp_constexpr_dynamic_alloc >= 201907L
asm ((N {})); // { dg-error "constexpr string 'data\\\(\\\)\\\[0\\\]' must be a constant expression" "" { target c++20 } }
// { dg-error "'\\\* N\\\(\\\).N::data\\\(\\\)' is not a constant expression because allocated storage has not been deallocated" "" { target c++20 } .-1 }
#endif
asm ((O {}));
asm ((P (0)));
@ -190,6 +191,7 @@ bar ()
asm ((M {}));
#if __cpp_constexpr_dynamic_alloc >= 201907L
asm ((N {})); // { dg-error "constexpr string 'data\\\(\\\)\\\[0\\\]' must be a constant expression" "" { target c++20 } }
// { dg-error "'\\\* N\\\(\\\).N::data\\\(\\\)' is not a constant expression because allocated storage has not been deallocated" "" { target c++20 } .-1 }
#endif
asm ((O {}));
asm ((P (0)));

View file

@ -69,10 +69,11 @@ static_assert (false, M {}); // { dg-warning "'static_assert' with non-string me
// { dg-error "static assertion failed: test" "" { target *-*-* } .-1 }
#if __cpp_constexpr_dynamic_alloc >= 201907L
struct N { constexpr int size () const { return 3; }
constexpr const char *data () const { return new char[3] { 'b', 'a', 'd' }; } }; // { dg-error "'\\\* N\\\(\\\).N::data\\\(\\\)' is not a constant expression because allocated storage has not been deallocated" "" { target c++20 } }
constexpr const char *data () const { return new char[3] { 'b', 'a', 'd' }; } };
static_assert (true, N {}); // { dg-warning "'static_assert' with non-string message only available with" "" { target { c++20 && c++23_down } } }
static_assert (false, N {}); // { dg-warning "'static_assert' with non-string message only available with" "" { target { c++20 && c++23_down } } }
// { dg-error "constexpr string 'data\\\(\\\)\\\[0\\\]' must be a constant expression" "" { target c++20 } .-1 }
// { dg-error "'\\\* N\\\(\\\).N::data\\\(\\\)' is not a constant expression because allocated storage has not been deallocated" "" { target c++20 } .-2 }
#endif
constexpr const char a[] = { 't', 'e', 's', 't' };
struct O { constexpr int size () const { return 4; }

View file

@ -3,7 +3,7 @@
struct S {
int *s;
constexpr S () : s(new int) {} // { dg-error "is not a constant expression because allocated storage has not been deallocated" }
constexpr S () : s(new int) {}
S (const S &) = delete;
S &operator= (const S &) = delete;
constexpr ~S () { delete s; }
@ -17,3 +17,4 @@ foo (S v)
}
static_assert (foo (S ())); // { dg-error "non-constant condition for static assertion" }
// { dg-error "is not a constant expression because allocated storage has not been deallocated" "" { target *-*-* } .-1 }

View file

@ -4,7 +4,7 @@
constexpr int *
f7 ()
{
int *p = new int (2); // { dg-error "is not a constant expression because it refers to a result of" }
int *p = new int (2); // { dg-message "allocated here" }
delete p;
return p;
}
@ -12,6 +12,5 @@ f7 ()
void
g ()
{
constexpr auto v7 = f7 ();
constexpr auto v7 = f7 (); // { dg-error "is not a constant expression because it refers to a result of" }
}

View file

@ -5,19 +5,19 @@
constexpr int *
f1 ()
{
return new int (2); // { dg-error "is not a constant expression because it refers to a result of" }
return new int (2); // { dg-message "allocated here" }
}
constexpr auto v1 = f1 ();
constexpr auto v1 = f1 (); // { dg-error "is not a constant expression because it refers to a result of" }
constexpr bool
f2 ()
{
int *p = new int (3); // { dg-error "is not a constant expression because allocated storage has not been deallocated" }
int *p = new int (3); // { dg-message "allocated here" }
return false;
}
constexpr auto v2 = f2 ();
constexpr auto v2 = f2 (); // { dg-error "is not a constant expression because allocated storage has not been deallocated" }
constexpr bool
f3 ()
@ -64,12 +64,12 @@ constexpr auto v6 = f6 (); // { dg-message "in 'constexpr' expansion of" }
constexpr int *
f7 ()
{
int *p = new int (2); // { dg-error "is not a constant expression because it refers to a result of" }
int *p = new int (2); // { dg-message "allocated here" }
delete p;
return p;
}
constexpr auto v7 = f7 ();
constexpr auto v7 = f7 (); // { dg-error "is not a constant expression because it refers to a result of" }
constexpr bool
f8_impl (int *p)

View file

@ -2,12 +2,13 @@
// { dg-do compile { target c++20 } }
struct Value {
Value() : v{new int{42}} {} // { dg-error "result of 'operator new'" "" { target implicit_constexpr } }
Value() : v{new int{42}} {}
int* v;
};
struct S {
static constinit inline Value v{}; // { dg-error "variable .S::v. does not have a constant initializer|call to non-.constexpr. function" }
// { dg-error "result of 'operator new'" "" { target implicit_constexpr } .-1 }
};
int main() { return *S::v.v; }