c++: ICE with operator new[] in constexpr [PR118775]

Message ID 20250211232432.493636-1-polacek@redhat.com
State New
Headers
Series c++: ICE with operator new[] in constexpr [PR118775] |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_simplebootstrap_build--master-arm-bootstrap success Build passed
linaro-tcwg-bot/tcwg_gcc_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_gcc_check--master-arm success Test passed
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_simplebootstrap_build--master-aarch64-bootstrap success Build passed
linaro-tcwg-bot/tcwg_gcc_check--master-aarch64 success Test passed

Commit Message

Marek Polacek Feb. 11, 2025, 11:24 p.m. UTC
  Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

-- >8 --
Here we ICE since r11-7740 because we no longer say that (long)&a
(where a is a global var) is non_constant_p.  So VERIFY_CONSTANT
does not return and we crash on tree_to_uhwi.  We should check
tree_fits_uhwi_p before calling tree_to_uhwi.

	PR c++/118775

gcc/cp/ChangeLog:

	* constexpr.cc (cxx_eval_call_expression): Check tree_fits_uhwi_p.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp2a/constexpr-new24.C: New test.
	* g++.dg/cpp2a/constexpr-new25.C: New test.
---
 gcc/cp/constexpr.cc                          |  7 +++++
 gcc/testsuite/g++.dg/cpp2a/constexpr-new24.C | 25 ++++++++++++++++++
 gcc/testsuite/g++.dg/cpp2a/constexpr-new25.C | 27 ++++++++++++++++++++
 3 files changed, 59 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/constexpr-new24.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/constexpr-new25.C


base-commit: 299a8e2dc667e795991bc439d2cad5ea5bd379e2
  

Comments

Marek Polacek March 4, 2025, 2:33 p.m. UTC | #1
Ping.

On Tue, Feb 11, 2025 at 06:24:32PM -0500, Marek Polacek wrote:
> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
> 
> -- >8 --
> Here we ICE since r11-7740 because we no longer say that (long)&a
> (where a is a global var) is non_constant_p.  So VERIFY_CONSTANT
> does not return and we crash on tree_to_uhwi.  We should check
> tree_fits_uhwi_p before calling tree_to_uhwi.
> 
> 	PR c++/118775
> 
> gcc/cp/ChangeLog:
> 
> 	* constexpr.cc (cxx_eval_call_expression): Check tree_fits_uhwi_p.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/cpp2a/constexpr-new24.C: New test.
> 	* g++.dg/cpp2a/constexpr-new25.C: New test.
> ---
>  gcc/cp/constexpr.cc                          |  7 +++++
>  gcc/testsuite/g++.dg/cpp2a/constexpr-new24.C | 25 ++++++++++++++++++
>  gcc/testsuite/g++.dg/cpp2a/constexpr-new25.C | 27 ++++++++++++++++++++
>  3 files changed, 59 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/constexpr-new24.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/constexpr-new25.C
> 
> diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
> index f142dd32bc8..f8f9a9df1a2 100644
> --- a/gcc/cp/constexpr.cc
> +++ b/gcc/cp/constexpr.cc
> @@ -2909,6 +2909,13 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
>  	  gcc_assert (arg0);
>  	  if (new_op_p)
>  	    {
> +	      if (!tree_fits_uhwi_p (arg0))
> +		{
> +		  if (!ctx->quiet)
> +		    error_at (loc, "cannot allocate array: size too large");
> +		  *non_constant_p = true;
> +		  return t;
> +		}
>  	      tree type = build_array_type_nelts (char_type_node,
>  						  tree_to_uhwi (arg0));
>  	      tree var = build_decl (loc, VAR_DECL,
> diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new24.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new24.C
> new file mode 100644
> index 00000000000..debb7f0f5c4
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-new24.C
> @@ -0,0 +1,25 @@
> +// PR c++/118775
> +// { dg-do compile { target c++20 } }
> +
> +int a;
> +
> +constexpr char *
> +f1 ()
> +{
> +  constexpr auto p = new char[(long int) &a]; // { dg-error "size too large" }
> +  return p;
> +}
> +
> +constexpr char *
> +f2 ()
> +{
> +  auto p = new char[(long int) &a];  // { dg-error "size too large" }
> +  return p;
> +}
> +
> +void
> +g ()
> +{
> +  auto r1 = f2 ();
> +  constexpr auto r2 = f2 (); // { dg-message "in .constexpr. expansion" }
> +}
> diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new25.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new25.C
> new file mode 100644
> index 00000000000..91c0318abd8
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-new25.C
> @@ -0,0 +1,27 @@
> +// PR c++/118775
> +// { dg-do compile { target c++20 } }
> +
> +namespace std {
> +struct __uniq_ptr_impl {
> +  constexpr __uniq_ptr_impl(char *) {}
> +};
> +template <typename> struct unique_ptr {
> +  __uniq_ptr_impl _M_t;
> +  constexpr ~unique_ptr() {}
> +};
> +template <typename> struct _MakeUniq;
> +template <typename _Tp> struct _MakeUniq<_Tp[]> {
> +  typedef unique_ptr<_Tp[]> __array;
> +};
> +template <typename _Tp> using __unique_ptr_array_t = _MakeUniq<_Tp>::__array;
> +constexpr __unique_ptr_array_t<char[]> make_unique(long __num) {
> +  return unique_ptr<char[]>(new char[__num]);
> +}
> +} // namespace std
> +int a;
> +int
> +main ()
> +{
> +  std::unique_ptr p = std::make_unique((long)&a);
> +  constexpr std::unique_ptr p2 = std::make_unique((long)&a); // { dg-error "conversion" }
> +}
> 
> base-commit: 299a8e2dc667e795991bc439d2cad5ea5bd379e2
> -- 
> 2.48.1
> 

Marek
  
Jason Merrill March 4, 2025, 10:34 p.m. UTC | #2
On 2/11/25 6:24 PM, Marek Polacek wrote:
> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
> 
> -- >8 --
> Here we ICE since r11-7740 because we no longer say that (long)&a
> (where a is a global var) is non_constant_p.  So VERIFY_CONSTANT
> does not return and we crash on tree_to_uhwi.  We should check
> tree_fits_uhwi_p before calling tree_to_uhwi.
> 
> 	PR c++/118775
> 
> gcc/cp/ChangeLog:
> 
> 	* constexpr.cc (cxx_eval_call_expression): Check tree_fits_uhwi_p.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/cpp2a/constexpr-new24.C: New test.
> 	* g++.dg/cpp2a/constexpr-new25.C: New test.
> ---
>   gcc/cp/constexpr.cc                          |  7 +++++
>   gcc/testsuite/g++.dg/cpp2a/constexpr-new24.C | 25 ++++++++++++++++++
>   gcc/testsuite/g++.dg/cpp2a/constexpr-new25.C | 27 ++++++++++++++++++++
>   3 files changed, 59 insertions(+)
>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/constexpr-new24.C
>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/constexpr-new25.C
> 
> diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
> index f142dd32bc8..f8f9a9df1a2 100644
> --- a/gcc/cp/constexpr.cc
> +++ b/gcc/cp/constexpr.cc
> @@ -2909,6 +2909,13 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
>   	  gcc_assert (arg0);
>   	  if (new_op_p)
>   	    {
> +	      if (!tree_fits_uhwi_p (arg0))
> +		{
> +		  if (!ctx->quiet)
> +		    error_at (loc, "cannot allocate array: size too large");

"too large" seems misleading in this case, where it just isn't a 
compile-time constant.

Why didn't the VERIFY_CONSTANT just above already reject this?

> +		  *non_constant_p = true;
> +		  return t;
> +		}
>   	      tree type = build_array_type_nelts (char_type_node,
>   						  tree_to_uhwi (arg0));
>   	      tree var = build_decl (loc, VAR_DECL,
> diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new24.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new24.C
> new file mode 100644
> index 00000000000..debb7f0f5c4
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-new24.C
> @@ -0,0 +1,25 @@
> +// PR c++/118775
> +// { dg-do compile { target c++20 } }
> +
> +int a;
> +
> +constexpr char *
> +f1 ()
> +{
> +  constexpr auto p = new char[(long int) &a]; // { dg-error "size too large" }
> +  return p;
> +}
> +
> +constexpr char *
> +f2 ()
> +{
> +  auto p = new char[(long int) &a];  // { dg-error "size too large" }
> +  return p;
> +}
> +
> +void
> +g ()
> +{
> +  auto r1 = f2 ();
> +  constexpr auto r2 = f2 (); // { dg-message "in .constexpr. expansion" }
> +}
> diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new25.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new25.C
> new file mode 100644
> index 00000000000..91c0318abd8
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-new25.C
> @@ -0,0 +1,27 @@
> +// PR c++/118775
> +// { dg-do compile { target c++20 } }
> +
> +namespace std {
> +struct __uniq_ptr_impl {
> +  constexpr __uniq_ptr_impl(char *) {}
> +};
> +template <typename> struct unique_ptr {
> +  __uniq_ptr_impl _M_t;
> +  constexpr ~unique_ptr() {}
> +};
> +template <typename> struct _MakeUniq;
> +template <typename _Tp> struct _MakeUniq<_Tp[]> {
> +  typedef unique_ptr<_Tp[]> __array;
> +};
> +template <typename _Tp> using __unique_ptr_array_t = _MakeUniq<_Tp>::__array;
> +constexpr __unique_ptr_array_t<char[]> make_unique(long __num) {
> +  return unique_ptr<char[]>(new char[__num]);
> +}
> +} // namespace std
> +int a;
> +int
> +main ()
> +{
> +  std::unique_ptr p = std::make_unique((long)&a);
> +  constexpr std::unique_ptr p2 = std::make_unique((long)&a); // { dg-error "conversion" }
> +}
> 
> base-commit: 299a8e2dc667e795991bc439d2cad5ea5bd379e2
  

Patch

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index f142dd32bc8..f8f9a9df1a2 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -2909,6 +2909,13 @@  cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
 	  gcc_assert (arg0);
 	  if (new_op_p)
 	    {
+	      if (!tree_fits_uhwi_p (arg0))
+		{
+		  if (!ctx->quiet)
+		    error_at (loc, "cannot allocate array: size too large");
+		  *non_constant_p = true;
+		  return t;
+		}
 	      tree type = build_array_type_nelts (char_type_node,
 						  tree_to_uhwi (arg0));
 	      tree var = build_decl (loc, VAR_DECL,
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new24.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new24.C
new file mode 100644
index 00000000000..debb7f0f5c4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-new24.C
@@ -0,0 +1,25 @@ 
+// PR c++/118775
+// { dg-do compile { target c++20 } }
+
+int a;
+
+constexpr char *
+f1 ()
+{
+  constexpr auto p = new char[(long int) &a]; // { dg-error "size too large" }
+  return p;
+}
+
+constexpr char *
+f2 ()
+{
+  auto p = new char[(long int) &a];  // { dg-error "size too large" }
+  return p;
+}
+
+void
+g ()
+{
+  auto r1 = f2 ();
+  constexpr auto r2 = f2 (); // { dg-message "in .constexpr. expansion" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new25.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new25.C
new file mode 100644
index 00000000000..91c0318abd8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-new25.C
@@ -0,0 +1,27 @@ 
+// PR c++/118775
+// { dg-do compile { target c++20 } }
+
+namespace std {
+struct __uniq_ptr_impl {
+  constexpr __uniq_ptr_impl(char *) {}
+};
+template <typename> struct unique_ptr {
+  __uniq_ptr_impl _M_t;
+  constexpr ~unique_ptr() {}
+};
+template <typename> struct _MakeUniq;
+template <typename _Tp> struct _MakeUniq<_Tp[]> {
+  typedef unique_ptr<_Tp[]> __array;
+};
+template <typename _Tp> using __unique_ptr_array_t = _MakeUniq<_Tp>::__array;
+constexpr __unique_ptr_array_t<char[]> make_unique(long __num) {
+  return unique_ptr<char[]>(new char[__num]);
+}
+} // namespace std
+int a;
+int
+main ()
+{
+  std::unique_ptr p = std::make_unique((long)&a);
+  constexpr std::unique_ptr p2 = std::make_unique((long)&a); // { dg-error "conversion" }
+}