]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: fix __is_invocable for std::reference_wrapper [PR121055]
authorPatrick Palka <ppalka@redhat.com>
Wed, 23 Jul 2025 12:31:46 +0000 (08:31 -0400)
committerPatrick Palka <ppalka@redhat.com>
Thu, 24 Jul 2025 12:57:12 +0000 (08:57 -0400)
Our implementation of the INVOKE spec ([func.require]) was incorrectly
treating reference_wrapper<T>::get() as returning T instead of T&, which
notably makes a difference when invoking a ref-qualified memfn pointer.

PR c++/121055

gcc/cp/ChangeLog:

* method.cc (build_invoke): Correct reference_wrapper handling.

gcc/testsuite/ChangeLog:

* g++.dg/ext/is_invocable5.C: New test.

Reviewed-by: Jason Merrill <jason@redhat.com>
(cherry picked from commit 04a176a1d84a84c630cfd4d232736c12b105957a)

gcc/cp/method.cc
gcc/testsuite/g++.dg/ext/is_invocable5.C [new file with mode: 0644]

index 05c19cf0661e5ed7ee28edac80f246621fdb73a7..cf16fc9fc25b0db281f912fb2cb619c47e74275f 100644 (file)
@@ -2036,10 +2036,11 @@ build_invoke (tree fn_type, const_tree arg_types, tsubst_flags_t complain)
              const_tree name = DECL_NAME (datum_decl);
              if (name && (id_equal (name, "reference_wrapper")))
                {
-                 /* 1.2 & 1.5: Retrieve T from std::reference_wrapper<T>,
+                 /* 1.2 & 1.5: Retrieve T& from std::reference_wrapper<T>,
                     i.e., decltype(datum.get()).  */
                  datum_type =
                    TREE_VEC_ELT (TYPE_TI_ARGS (non_ref_datum_type), 0);
+                 datum_type = cp_build_reference_type (datum_type, false);
                  datum_is_refwrap = true;
                }
            }
diff --git a/gcc/testsuite/g++.dg/ext/is_invocable5.C b/gcc/testsuite/g++.dg/ext/is_invocable5.C
new file mode 100644 (file)
index 0000000..460eed5
--- /dev/null
@@ -0,0 +1,15 @@
+// PR c++/121055
+// { dg-do compile { target c++11 } }
+// { dg-skip-if "requires hosted libstdc++ for functional function" { ! hostedlib } }
+
+#include <functional>
+
+#define SA(X) static_assert((X),#X)
+
+struct F;
+
+SA( __is_invocable(void (F::*)() &, std::reference_wrapper<F>) );
+SA( ! __is_invocable(void (F::*)() &&, std::reference_wrapper<F>) );
+
+SA( __is_invocable(void (F::*)(int) &, std::reference_wrapper<F>, int) );
+SA( ! __is_invocable(void (F::*)(int) &&, std::reference_wrapper<F>, int) );