https://gcc.gnu.org/g:8161c4adea7f1842f9d28633d82e912ebb7a4cf9

commit r15-4366-g8161c4adea7f1842f9d28633d82e912ebb7a4cf9
Author: Patrick Palka <ppa...@redhat.com>
Date:   Tue Oct 15 13:23:17 2024 -0400

    c++: unifying lvalue vs rvalue (non-forwarding) ref [PR116710]
    
    When unifying two (non-forwarding) reference types, unify immediately
    recurses into the referenced type without first comparing rvalueness.
    (Note that at this point forwarding references and other reference
    parameters have already been stripped to their referenced type by
    maybe_adjust_types_for_deduction, so this code path applies only to
    nested reference types.)
    
            PR c++/116710
    
    gcc/cp/ChangeLog:
    
            * pt.cc (unify) <case REFERENCE_TYPE>: Compare rvalueness.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/template/unify12.C: New test.
    
    Reviewed-by: Jason Merrill <ja...@redhat.com>

Diff:
---
 gcc/cp/pt.cc                            |  3 ++-
 gcc/testsuite/g++.dg/template/unify12.C | 24 ++++++++++++++++++++++++
 2 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index c9219d5b3a5a..0141c53b617c 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -25161,7 +25161,8 @@ unify (tree tparms, tree targs, tree parm, tree arg, 
int strict,
       }
 
     case REFERENCE_TYPE:
-      if (!TYPE_REF_P (arg))
+      if (!TYPE_REF_P (arg)
+         || TYPE_REF_IS_RVALUE (parm) != TYPE_REF_IS_RVALUE (arg))
        return unify_type_mismatch (explain_p, parm, arg);
       return unify (tparms, targs, TREE_TYPE (parm), TREE_TYPE (arg),
                    strict & UNIFY_ALLOW_MORE_CV_QUAL, explain_p);
diff --git a/gcc/testsuite/g++.dg/template/unify12.C 
b/gcc/testsuite/g++.dg/template/unify12.C
new file mode 100644
index 000000000000..bed52d0fa36c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/unify12.C
@@ -0,0 +1,24 @@
+// PR c++/116710
+// { dg-do compile { target c++11 } }
+
+template<class T> struct A : T {};
+
+template<class T>
+void f(void (*)(T &), typename A<T>::type * = 0);
+
+void f(...);
+
+void g(int &&);
+
+void q() { f(g); } // OK
+
+template<class T>
+struct B { operator B<T&>(); };
+
+template<class T>
+void h(B<T&>);
+
+int main() {
+  B<int&&> b;
+  h(b); // { dg-error "no match" }
+}

Reply via email to