c++: Fix up extract_ref [PR125111]

Message ID afme3af1KpPWKi2O@tucnak
State New
Headers
Series c++: Fix up extract_ref [PR125111] |

Commit Message

Jakub Jelinek May 5, 2026, 7:40 a.m. UTC
  Hi!

https://eel.is/c++draft/meta.reflection.extract#5.2 requests that
is_convertible_v<remove_reference_t<U>(*)[], remove_reference_t<T>(*)[]>
is tested and if it not true, the function throws.
If U/T are references to function/method/array[], we try to build
array of types which are not valid in arrays and ICE shortly after that.
The following patch makes sure we don't create arrays in that case
and instead just throw the exception.  We can't have references to void
or references to references, so I think the other problematic cases
of creating arrays can't trigger.

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

2026-05-05  Jakub Jelinek  <jakub@redhat.com>

	PR c++/125111
	* reflect.cc (extract_ref): Throw instead of trying to build
	arrays of functions, methods or arrays with NULL TYPE_DOMAIN.

	* g++.dg/reflect/extract12.C: New test.


	Jakub
  

Comments

Marek Polacek May 5, 2026, 1:33 p.m. UTC | #1
On Tue, May 05, 2026 at 09:40:13AM +0200, Jakub Jelinek wrote:
> Hi!
> 
> https://eel.is/c++draft/meta.reflection.extract#5.2 requests that
> is_convertible_v<remove_reference_t<U>(*)[], remove_reference_t<T>(*)[]>
> is tested and if it not true, the function throws.
> If U/T are references to function/method/array[], we try to build
> array of types which are not valid in arrays and ICE shortly after that.
> The following patch makes sure we don't create arrays in that case
> and instead just throw the exception.  We can't have references to void
> or references to references, so I think the other problematic cases
> of creating arrays can't trigger.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk/16.2?

Looks good (not an approval).
 
> 2026-05-05  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR c++/125111
> 	* reflect.cc (extract_ref): Throw instead of trying to build
> 	arrays of functions, methods or arrays with NULL TYPE_DOMAIN.
> 
> 	* g++.dg/reflect/extract12.C: New test.
> 
> --- gcc/cp/reflect.cc.jj	2026-05-01 21:47:53.656712280 +0200
> +++ gcc/cp/reflect.cc	2026-05-04 16:27:43.017528465 +0200
> @@ -7453,6 +7453,10 @@ extract_ref (location_t loc, const const
>      {
>        if (TYPE_REF_P (type))
>  	type = TREE_TYPE (type);
> +      if (FUNC_OR_METHOD_TYPE_P (type)
> +	  || (TREE_CODE (type) == ARRAY_TYPE
> +	      && TYPE_DOMAIN (type) == NULL_TREE))
> +	return error_mark_node;
>        type = build_cplus_array_type (type, NULL_TREE);
>        return build_pointer_type (type);
>      };
> @@ -7462,7 +7466,11 @@ extract_ref (location_t loc, const const
>      {
>        /* The wording is saying that U is the type of r.  */
>        tree U = TREE_TYPE (r);
> -      if (is_convertible (adjust_type (U), adjust_type (T))
> +      tree adju = adjust_type (U);
> +      tree adjt = adjust_type (T);
> +      if (adju != error_mark_node
> +	  && adjt != error_mark_node
> +	  && is_convertible (adju, adjt)
>  	  && (!var_p || is_constant_expression (r)))
>  	{
>  	  if (TYPE_REF_P (TREE_TYPE (r)))
> --- gcc/testsuite/g++.dg/reflect/extract12.C.jj	2026-05-04 16:29:25.477853239 +0200
> +++ gcc/testsuite/g++.dg/reflect/extract12.C	2026-05-04 16:30:28.990815200 +0200
> @@ -0,0 +1,14 @@
> +// PR c++/125111
> +// { dg-do compile { target c++26 } }
> +// { dg-additional-options "-freflection" }
> +
> +#include <meta>
> +
> +using A = void ();
> +extern A &a;
> +constexpr auto b = ^^a;
> +constexpr auto c = std::meta::extract <A &> (b);	// { dg-error "uncaught exception of type 'std::meta::exception'; 'what\\\(\\\)': 'value cannot be extracted'" }
> +using B = int [];
> +extern B &d;
> +constexpr auto e = ^^d;
> +constexpr auto f = std::meta::extract <B &> (e);	// { dg-error "uncaught exception of type 'std::meta::exception'; 'what\\\(\\\)': 'value cannot be extracted'" }
> 
> 	Jakub
> 

Marek
  
Jason Merrill May 6, 2026, 10:35 p.m. UTC | #2
On 5/5/26 3:40 AM, Jakub Jelinek wrote:
> Hi!
> 
> https://eel.is/c++draft/meta.reflection.extract#5.2 requests that
> is_convertible_v<remove_reference_t<U>(*)[], remove_reference_t<T>(*)[]>
> is tested and if it not true, the function throws.
> If U/T are references to function/method/array[], we try to build
> array of types which are not valid in arrays and ICE shortly after that.
> The following patch makes sure we don't create arrays in that case
> and instead just throw the exception.  We can't have references to void
> or references to references, so I think the other problematic cases
> of creating arrays can't trigger.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk/16.2?

OK...

> 2026-05-05  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR c++/125111
> 	* reflect.cc (extract_ref): Throw instead of trying to build
> 	arrays of functions, methods or arrays with NULL TYPE_DOMAIN.
> 
> 	* g++.dg/reflect/extract12.C: New test.
> 
> --- gcc/cp/reflect.cc.jj	2026-05-01 21:47:53.656712280 +0200
> +++ gcc/cp/reflect.cc	2026-05-04 16:27:43.017528465 +0200
> @@ -7453,6 +7453,10 @@ extract_ref (location_t loc, const const
>       {
>         if (TYPE_REF_P (type))
>   	type = TREE_TYPE (type);
> +      if (FUNC_OR_METHOD_TYPE_P (type)
> +	  || (TREE_CODE (type) == ARRAY_TYPE
> +	      && TYPE_DOMAIN (type) == NULL_TREE))

...but it would be nice to share this with tsubst.

> +	return error_mark_node;
>         type = build_cplus_array_type (type, NULL_TREE);
>         return build_pointer_type (type);
>       };
> @@ -7462,7 +7466,11 @@ extract_ref (location_t loc, const const
>       {
>         /* The wording is saying that U is the type of r.  */
>         tree U = TREE_TYPE (r);
> -      if (is_convertible (adjust_type (U), adjust_type (T))
> +      tree adju = adjust_type (U);
> +      tree adjt = adjust_type (T);
> +      if (adju != error_mark_node
> +	  && adjt != error_mark_node
> +	  && is_convertible (adju, adjt)
>   	  && (!var_p || is_constant_expression (r)))
>   	{
>   	  if (TYPE_REF_P (TREE_TYPE (r)))
> --- gcc/testsuite/g++.dg/reflect/extract12.C.jj	2026-05-04 16:29:25.477853239 +0200
> +++ gcc/testsuite/g++.dg/reflect/extract12.C	2026-05-04 16:30:28.990815200 +0200
> @@ -0,0 +1,14 @@
> +// PR c++/125111
> +// { dg-do compile { target c++26 } }
> +// { dg-additional-options "-freflection" }
> +
> +#include <meta>
> +
> +using A = void ();
> +extern A &a;
> +constexpr auto b = ^^a;
> +constexpr auto c = std::meta::extract <A &> (b);	// { dg-error "uncaught exception of type 'std::meta::exception'; 'what\\\(\\\)': 'value cannot be extracted'" }
> +using B = int [];
> +extern B &d;
> +constexpr auto e = ^^d;
> +constexpr auto f = std::meta::extract <B &> (e);	// { dg-error "uncaught exception of type 'std::meta::exception'; 'what\\\(\\\)': 'value cannot be extracted'" }
> 
> 	Jakub
>
  

Patch

--- gcc/cp/reflect.cc.jj	2026-05-01 21:47:53.656712280 +0200
+++ gcc/cp/reflect.cc	2026-05-04 16:27:43.017528465 +0200
@@ -7453,6 +7453,10 @@  extract_ref (location_t loc, const const
     {
       if (TYPE_REF_P (type))
 	type = TREE_TYPE (type);
+      if (FUNC_OR_METHOD_TYPE_P (type)
+	  || (TREE_CODE (type) == ARRAY_TYPE
+	      && TYPE_DOMAIN (type) == NULL_TREE))
+	return error_mark_node;
       type = build_cplus_array_type (type, NULL_TREE);
       return build_pointer_type (type);
     };
@@ -7462,7 +7466,11 @@  extract_ref (location_t loc, const const
     {
       /* The wording is saying that U is the type of r.  */
       tree U = TREE_TYPE (r);
-      if (is_convertible (adjust_type (U), adjust_type (T))
+      tree adju = adjust_type (U);
+      tree adjt = adjust_type (T);
+      if (adju != error_mark_node
+	  && adjt != error_mark_node
+	  && is_convertible (adju, adjt)
 	  && (!var_p || is_constant_expression (r)))
 	{
 	  if (TYPE_REF_P (TREE_TYPE (r)))
--- gcc/testsuite/g++.dg/reflect/extract12.C.jj	2026-05-04 16:29:25.477853239 +0200
+++ gcc/testsuite/g++.dg/reflect/extract12.C	2026-05-04 16:30:28.990815200 +0200
@@ -0,0 +1,14 @@ 
+// PR c++/125111
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+using A = void ();
+extern A &a;
+constexpr auto b = ^^a;
+constexpr auto c = std::meta::extract <A &> (b);	// { dg-error "uncaught exception of type 'std::meta::exception'; 'what\\\(\\\)': 'value cannot be extracted'" }
+using B = int [];
+extern B &d;
+constexpr auto e = ^^d;
+constexpr auto f = std::meta::extract <B &> (e);	// { dg-error "uncaught exception of type 'std::meta::exception'; 'what\\\(\\\)': 'value cannot be extracted'" }