Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for trunk?
-- >8 -- Here during declaration matching we undesirably consider the two TT{42} CTAD expressions to be non-equivalent ultimately because for CTAD placeholder equivalence we compare the TEMPLATE_DECLs (which uses pointer identity) and here the corresponding TEMPLATE_DECLs for TT are different since they're from different scopes. On the other hand, the corresponding TEMPLATE_TEMPLATE_PARMs are deemed equivalent (since they have the same position and template parameters). This turns out to be the root cause of some of the xtreme-header modules regressions. We don't have this ttp equivalence issue in other contexts because either the TEMPLATE_TEMPLATE_PARM is used instead of the TEMPLATE_DECL already (e.g. when a ttp is used as a targ), or the equivalence logic is relaxed (e.g. for bound ttps), it seems. So this patch relaxes ttp CTAD placeholder equivalence accordingly, by comparing the TEMPLATE_TEMPLATE_PARM instead of the TEMPLATE_DECL. The ctp_hasher doesn't need to be adjusted since it currently doesn't include CLASS_PLACEHOLDER_TEMPLATE in the hash anyway. PR c++/112737 gcc/cp/ChangeLog: * typeck.cc (structural_comptypes) <case TEMPLATE_TYPE_PARM>: If CLASS_PLACEHOLDER_TEMPLATE is a ttp, compare its TEMPLATE_TEMPLATE_PARM instead of its TEMPLATE_DECL. gcc/testsuite/ChangeLog: * g++.dg/template/ttp42: New test. --- gcc/cp/typeck.cc | 20 +++++++++++++++++--- gcc/testsuite/g++.dg/template/ttp42.C | 14 ++++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/g++.dg/template/ttp42.C diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc index a15eda3f5f8..be82877e35c 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -1573,9 +1573,23 @@ structural_comptypes (tree t1, tree t2, int strict) return false; /* If T1 and T2 don't represent the same class template deduction, they aren't equal. */ - if (CLASS_PLACEHOLDER_TEMPLATE (t1) - != CLASS_PLACEHOLDER_TEMPLATE (t2)) - return false; + if (CLASS_PLACEHOLDER_TEMPLATE (t1) || CLASS_PLACEHOLDER_TEMPLATE (t2)) + { + tree tmpl1 = CLASS_PLACEHOLDER_TEMPLATE (t1); + tree tmpl2 = CLASS_PLACEHOLDER_TEMPLATE (t2); + if (!tmpl1 || !tmpl2) + return false; + if (DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl1) + != DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl2)) + return false; + if (DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl1) + /* Treat two CTAD placeholders that use equivalent ttps + from different scopes as equivalent by comparing their + TEMPLATE_TEMPLATE_PARMs instead of their TEMPLATE_DECLs. */ + ? !same_type_p (TREE_TYPE (tmpl1), TREE_TYPE (tmpl2)) + : tmpl1 != tmpl2) + return false; + } /* Constrained 'auto's are distinct from parms that don't have the same constraints. */ if (!equivalent_placeholder_constraints (t1, t2)) diff --git a/gcc/testsuite/g++.dg/template/ttp42.C b/gcc/testsuite/g++.dg/template/ttp42.C new file mode 100644 index 00000000000..da08e857fc5 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/ttp42.C @@ -0,0 +1,14 @@ +// PR c++/112737 +// { dg-do compile { target c++17 } } + +template<template<class> class TT> +decltype(TT{42}) f(); // #1 + +template<template<class> class TT> +decltype(TT{42}) f(); // redeclaration of #1 + +template<class T> struct A { A(T); }; + +int main() { + f<A>(); +} -- 2.43.0.493.gbc7ee2e5e1