Tested x86_64-pc-linux-gnu, applying to trunk.

-- 8< --

We weren't properly considering the function pointer conversions in
deduction between FUNCTION_TYPE; we just hardcoded the
UNIFY_ALLOW_MORE_CV_QUAL semantics, which are backwards when deducing for a
template conversion function like the one in a generic lambda.  And when I
started checking the ALLOW flags, I needed to make sure they stay set to
avoid breaking trailing13.C.

        PR c++/105221

gcc/cp/ChangeLog:

        * pt.cc (unify) [FUNCTION_TYPE]: Handle function pointer
        conversions.

gcc/testsuite/ChangeLog:

        * g++.dg/cpp1z/noexcept-type27.C: New test.
---
 gcc/cp/pt.cc                                 | 33 ++++++++++++++++++--
 gcc/testsuite/g++.dg/cpp1z/noexcept-type27.C |  8 +++++
 2 files changed, 38 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1z/noexcept-type27.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index e514a277872..dd7f0db9658 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -24472,9 +24472,12 @@ unify (tree tparms, tree targs, tree parm, tree arg, 
int strict,
     return unify_cv_qual_mismatch (explain_p, parm, arg);
 
   if (!(strict & UNIFY_ALLOW_OUTER_LEVEL)
-      && TYPE_P (parm) && !CP_TYPE_CONST_P (parm))
+      && TYPE_P (parm) && !CP_TYPE_CONST_P (parm)
+      && !FUNC_OR_METHOD_TYPE_P (parm))
     strict &= ~UNIFY_ALLOW_MORE_CV_QUAL;
-  strict &= ~UNIFY_ALLOW_OUTER_LEVEL;
+  /* PMFs recurse at the same level, so don't strip this yet.  */
+  if (!TYPE_PTRMEMFUNC_P (parm))
+    strict &= ~UNIFY_ALLOW_OUTER_LEVEL;
   strict &= ~UNIFY_ALLOW_DERIVED;
   strict &= ~UNIFY_ALLOW_OUTER_MORE_CV_QUAL;
   strict &= ~UNIFY_ALLOW_OUTER_LESS_CV_QUAL;
@@ -25022,7 +25025,31 @@ unify (tree tparms, tree targs, tree parm, tree arg, 
int strict,
              RECUR_AND_CHECK_FAILURE (tparms, targs, TREE_PURPOSE (pspec),
                                       TREE_PURPOSE (aspec),
                                       UNIFY_ALLOW_NONE, explain_p);
-           else if (nothrow_spec_p (pspec) && !nothrow_spec_p (aspec))
+           else
+             {
+               bool pn = nothrow_spec_p (pspec);
+               bool an = nothrow_spec_p (aspec);
+               /* Here "less cv-qual" means the deduced arg (i.e. parm) has
+                  /more/ noexcept, since function pointer conversions are the
+                  reverse of qualification conversions.  */
+               if (an == pn
+                   || (an < pn && (strict & UNIFY_ALLOW_LESS_CV_QUAL))
+                   || (an > pn && (strict & UNIFY_ALLOW_MORE_CV_QUAL)))
+                 /* OK.  */;
+               else
+                 return unify_type_mismatch (explain_p, parm, arg);
+             }
+         }
+       if (flag_tm)
+         {
+           /* As for noexcept.  */
+           bool pn = tx_safe_fn_type_p (parm);
+           bool an = tx_safe_fn_type_p (arg);
+           if (an == pn
+               || (an < pn && (strict & UNIFY_ALLOW_LESS_CV_QUAL))
+               || (an > pn && (strict & UNIFY_ALLOW_MORE_CV_QUAL)))
+             /* OK.  */;
+           else
              return unify_type_mismatch (explain_p, parm, arg);
          }
 
diff --git a/gcc/testsuite/g++.dg/cpp1z/noexcept-type27.C 
b/gcc/testsuite/g++.dg/cpp1z/noexcept-type27.C
new file mode 100644
index 00000000000..a691f695389
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/noexcept-type27.C
@@ -0,0 +1,8 @@
+// PR c++/105221
+// { dg-do compile { target c++14 } }
+
+void (*p)(int) = [](auto) noexcept {};
+
+int main() {
+  true ? [](auto) noexcept {} : [](int) {};
+}

base-commit: 83d2b1ccd17d394d546a38562815ef83daa05e85
-- 
2.31.1

Reply via email to