diff mbox series

c++: Fix ICE on constexpr placement new [PR115754]

Message ID ZoRbDh2OH27tDYhQ@tucnak
State New
Headers show
Series c++: Fix ICE on constexpr placement new [PR115754] | expand

Commit Message

Jakub Jelinek July 2, 2024, 7:54 p.m. UTC
Hi!

C++26 is making in P2747R2 paper placement new constexpr.
While working on a patch for that, I've noticed we ICE starting with
GCC 14 on the following testcase.
The problem is that e.g. for the void * to sometype * casts checks,
we really assume the casts have their operand constant evaluated
as prvalue, but on the testcase the cast itself is evaluated with
vc_discard and that means op can end up e.g. a VAR_DECL which the
later code doesn't like and asserts on.
If the result type is void, we don't really need the cast operand
for anything, so can use vc_discard for the recursive call,
VIEW_CONVERT_EXPR can appear on the lhs, so we need to honor the
lval but otherwise the patch uses vc_prvalue.
I'd like to get this patch in before the rest of P2747R2 implementation,
so that it can be backported to 14.2 later on.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2024-07-02  Jakub Jelinek  <jakub@redhat.com>
	    Jason Merrill  <jason@redhat.com>

	PR c++/115754
	* constexpr.cc (cxx_eval_constant_expression) <case CONVERT_EXPR>:
	For conversions to void, pass vc_discard to the recursive call
	and otherwise for tcode other than VIEW_CONVERT_EXPR pass vc_prvalue.

	* g++.dg/cpp26/pr115754.C: New test.


	Jakub

Comments

Jason Merrill July 2, 2024, 8:02 p.m. UTC | #1
On 7/2/24 3:54 PM, Jakub Jelinek wrote:
> Hi!
> 
> C++26 is making in P2747R2 paper placement new constexpr.
> While working on a patch for that, I've noticed we ICE starting with
> GCC 14 on the following testcase.
> The problem is that e.g. for the void * to sometype * casts checks,
> we really assume the casts have their operand constant evaluated
> as prvalue, but on the testcase the cast itself is evaluated with
> vc_discard and that means op can end up e.g. a VAR_DECL which the
> later code doesn't like and asserts on.
> If the result type is void, we don't really need the cast operand
> for anything, so can use vc_discard for the recursive call,
> VIEW_CONVERT_EXPR can appear on the lhs, so we need to honor the
> lval but otherwise the patch uses vc_prvalue.
> I'd like to get this patch in before the rest of P2747R2 implementation,
> so that it can be backported to 14.2 later on.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

OK.

> 2024-07-02  Jakub Jelinek  <jakub@redhat.com>
> 	    Jason Merrill  <jason@redhat.com>
> 
> 	PR c++/115754
> 	* constexpr.cc (cxx_eval_constant_expression) <case CONVERT_EXPR>:
> 	For conversions to void, pass vc_discard to the recursive call
> 	and otherwise for tcode other than VIEW_CONVERT_EXPR pass vc_prvalue.
> 
> 	* g++.dg/cpp26/pr115754.C: New test.
> 
> --- gcc/cp/constexpr.cc.jj	2024-05-08 10:16:53.966824718 +0200
> +++ gcc/cp/constexpr.cc	2024-07-02 18:47:49.646843559 +0200
> @@ -8103,7 +8103,10 @@ cxx_eval_constant_expression (const cons
>   	tree oldop = TREE_OPERAND (t, 0);
>   
>   	tree op = cxx_eval_constant_expression (ctx, oldop,
> -						lval,
> +						VOID_TYPE_P (TREE_TYPE (t))
> +						? vc_discard
> +						: tcode == VIEW_CONVERT_EXPR
> +						? lval : vc_prvalue,
>   						non_constant_p, overflow_p);
>   	if (*non_constant_p)
>   	  return t;
> --- gcc/testsuite/g++.dg/cpp26/pr115754.C.jj	2024-07-02 18:40:08.107750189 +0200
> +++ gcc/testsuite/g++.dg/cpp26/pr115754.C	2024-07-02 18:39:57.110890921 +0200
> @@ -0,0 +1,36 @@
> +// PR c++/115754
> +// { dg-do compile { target c++26 } }
> +
> +namespace std
> +{
> +  using size_t = decltype (sizeof 0);
> +
> +  template <typename T>
> +  struct allocator
> +  {
> +    constexpr allocator () noexcept {}
> +
> +    constexpr T *allocate (size_t n)
> +    { return static_cast<T *> (::operator new (n * sizeof(T))); }
> +
> +    constexpr void
> +    deallocate (T *p, size_t n)
> +    { ::operator delete (p); }
> +  };
> +}
> +
> +constexpr void *
> +operator new (std::size_t, void *p) noexcept
> +{ return p; }
> +
> +constexpr bool
> +foo ()
> +{
> +  std::allocator<int> a;
> +  auto b = a.allocate (1);
> +  ::new (b) int ();
> +  a.deallocate (b, 1);
> +  return true;
> +}
> +
> +constexpr bool a = foo ();
> 
> 	Jakub
>
diff mbox series

Patch

--- gcc/cp/constexpr.cc.jj	2024-05-08 10:16:53.966824718 +0200
+++ gcc/cp/constexpr.cc	2024-07-02 18:47:49.646843559 +0200
@@ -8103,7 +8103,10 @@  cxx_eval_constant_expression (const cons
 	tree oldop = TREE_OPERAND (t, 0);
 
 	tree op = cxx_eval_constant_expression (ctx, oldop,
-						lval,
+						VOID_TYPE_P (TREE_TYPE (t))
+						? vc_discard
+						: tcode == VIEW_CONVERT_EXPR
+						? lval : vc_prvalue,
 						non_constant_p, overflow_p);
 	if (*non_constant_p)
 	  return t;
--- gcc/testsuite/g++.dg/cpp26/pr115754.C.jj	2024-07-02 18:40:08.107750189 +0200
+++ gcc/testsuite/g++.dg/cpp26/pr115754.C	2024-07-02 18:39:57.110890921 +0200
@@ -0,0 +1,36 @@ 
+// PR c++/115754
+// { dg-do compile { target c++26 } }
+
+namespace std
+{
+  using size_t = decltype (sizeof 0);
+
+  template <typename T>
+  struct allocator
+  {
+    constexpr allocator () noexcept {}
+
+    constexpr T *allocate (size_t n)
+    { return static_cast<T *> (::operator new (n * sizeof(T))); }
+
+    constexpr void
+    deallocate (T *p, size_t n)
+    { ::operator delete (p); }
+  };
+}
+
+constexpr void *
+operator new (std::size_t, void *p) noexcept
+{ return p; }
+
+constexpr bool
+foo ()
+{
+  std::allocator<int> a;
+  auto b = a.allocate (1);
+  ::new (b) int ();
+  a.deallocate (b, 1);
+  return true;
+}
+
+constexpr bool a = foo ();