https://gcc.gnu.org/g:745e36a9acc6eb1d814ddd838dbcb5a7b724b3e2

commit r16-7041-g745e36a9acc6eb1d814ddd838dbcb5a7b724b3e2
Author: Marek Polacek <[email protected]>
Date:   Thu Jan 22 11:31:35 2026 -0500

    c++/reflection: fix fnptr extraction [PR123620]
    
    When extracting a function pointer, removing noexcept should be
    allowed (but not the other way round):
    
      int fn (int) noexcept;
      constexpr auto a = extract<int (*)(int)>(^^fn);
    
    but currently we reject this code -- I didn't realize that fnptr_conv_p
    allows things that same_type_p doesn't allow, and in can_extract_* we
    should check both.  And then we need to perform the actual conversion.
    
            PR c++/123620
    
    gcc/cp/ChangeLog:
    
            * reflect.cc (can_extract_member_or_function_p): Also check
            fnptr_conv_p.
            (extract_member_or_function): Call perform_implicit_conversion.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/reflect/extract1.C: Test removing noexcept.
            * g++.dg/reflect/extract2.C: Adjust static_assert.
    
    Reviewed-by: Jason Merrill <[email protected]>

Diff:
---
 gcc/cp/reflect.cc                       | 9 ++++++---
 gcc/testsuite/g++.dg/reflect/extract1.C | 7 ++-----
 gcc/testsuite/g++.dg/reflect/extract2.C | 4 ++--
 3 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/gcc/cp/reflect.cc b/gcc/cp/reflect.cc
index c1173ced1688..2f9aa36c7872 100644
--- a/gcc/cp/reflect.cc
+++ b/gcc/cp/reflect.cc
@@ -7206,7 +7206,7 @@ can_extract_member_or_function_p (tree T, tree r, 
reflect_kind kind)
       tree F = TREE_TYPE (r);
       F = build_pointer_type (F);
       F = build_ptrmemfunc_type (F);
-      if (same_type_p (T, F))
+      if (same_type_p (T, F) || fnptr_conv_p (T, F))
        return true;
       return false;
     }
@@ -7214,7 +7214,7 @@ can_extract_member_or_function_p (tree T, tree r, 
reflect_kind kind)
     {
       tree F = TREE_TYPE (r);
       F = build_pointer_type (F);
-      if (same_type_p (T, F))
+      if (same_type_p (T, F) || fnptr_conv_p (T, F))
        return true;
       return false;
     }
@@ -7250,7 +7250,10 @@ extract_member_or_function (location_t loc, const 
constexpr_ctx *ctx,
 
   const tsubst_flags_t complain = complain_flags (ctx);
   if (POINTER_TYPE_P (T))
-    return cp_build_addr_expr (r, complain);
+    {
+      r = cp_build_addr_expr (r, complain);
+      return perform_implicit_conversion (T, r, complain);
+    }
   else
     {
       if (!mark_used (r, complain))
diff --git a/gcc/testsuite/g++.dg/reflect/extract1.C 
b/gcc/testsuite/g++.dg/reflect/extract1.C
index 6eaf9ffe4b9a..4f05fce40a55 100644
--- a/gcc/testsuite/g++.dg/reflect/extract1.C
+++ b/gcc/testsuite/g++.dg/reflect/extract1.C
@@ -171,13 +171,10 @@ constexpr auto a4 = extract<int (*)() noexcept>(^^B::fn4);
 constexpr auto a5 = extract<int (*)(B)>(^^B::fn5);
 constexpr auto a6 = extract<int (B::*)(int) &>(^^B::fn6);
 constexpr auto a7 = extract<int (B::*)(int) &&>(^^B::fn7);
-
 constexpr auto a8 = extract<int B::*>(^^B::m);
 constexpr auto a9 = extract<int const B::*>(^^B::m);
 constexpr auto a10 = extract<int* B::*>(^^B::p);
 constexpr auto a11 = extract<int* const B::*>(^^B::p);
 constexpr auto a12 = extract<int const* const B::*>(^^B::p);
-
-// FIXME removing noexcept should be allowed
-// constexpr auto a13 = extract<int (*)()>(^^B::fn4);
-// constexpr auto a14 = extract<int (B::*)()>(^^B::fn2);
+constexpr auto a13 = extract<int (*)()>(^^B::fn4);
+constexpr auto a14 = extract<int (B::*)()>(^^B::fn2);
diff --git a/gcc/testsuite/g++.dg/reflect/extract2.C 
b/gcc/testsuite/g++.dg/reflect/extract2.C
index edb5382ce398..9de23d1e931d 100644
--- a/gcc/testsuite/g++.dg/reflect/extract2.C
+++ b/gcc/testsuite/g++.dg/reflect/extract2.C
@@ -130,11 +130,11 @@ struct C {
 };
 static_assert (!can_extract<void (C::*)()>(^^C::fn));
 static_assert (!can_extract<int (C::*)() noexcept>(^^C::fn));
-static_assert (!can_extract<int (C::*)()>(^^C::fn2));
+static_assert (can_extract<int (C::*)()>(^^C::fn2));
 static_assert (!can_extract<int (C::*)()>(^^C::fn3));
 static_assert (!can_extract<int (C::*)()>(^^C::fn4));
 static_assert (!can_extract<int (*)() noexcept>(^^C::fn3));
-static_assert (!can_extract<int (*)()>(^^C::fn4));
+static_assert (can_extract<int (*)()>(^^C::fn4));
 static_assert (!can_extract<int (*)()>(^^C::fn5));
 static_assert (!can_extract<int (C::*)(int) &&>(^^C::fn6));
 static_assert (!can_extract<int (C::*)(int) &>(^^C::fn7));

Reply via email to