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