Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk? -- >8 --
When streaming in a nested template-template parameter as in the attached testcase, we end up reaching the containing template-template parameter in 'tpl_parms_fini'. We should not set the DECL_CONTEXT to this (nested) template-template parameter, as it should already be the struct that the outer template-template parameter is declared on. PR c++/98881 gcc/cp/ChangeLog: * module.cc (trees_out::tpl_parms_fini): Clarify logic purely for checking purposes. Don't consider a template template parameter as the owning template. (trees_in::tpl_parms_fini): Don't consider a template template parameter as the owning template. gcc/testsuite/ChangeLog: * g++.dg/modules/tpl-tpl-parm-3_a.H: New test. * g++.dg/modules/tpl-tpl-parm-3_b.C: New test. Signed-off-by: Nathaniel Shead <nathanielosh...@gmail.com> --- gcc/cp/module.cc | 17 ++++++++++++----- gcc/testsuite/g++.dg/modules/tpl-tpl-parm-3_a.H | 11 +++++++++++ gcc/testsuite/g++.dg/modules/tpl-tpl-parm-3_b.C | 13 +++++++++++++ 3 files changed, 36 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/g++.dg/modules/tpl-tpl-parm-3_a.H create mode 100644 gcc/testsuite/g++.dg/modules/tpl-tpl-parm-3_b.C diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 67f132d28d7..5663d01ed9c 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -10126,10 +10126,14 @@ trees_out::tpl_parms_fini (tree tmpl, unsigned tpl_levels) tree dflt = TREE_PURPOSE (parm); tree_node (dflt); - if (streaming_p ()) + if (CHECKING_P && streaming_p ()) { + /* Sanity check that the DECL_CONTEXT we'll infer when + streaming in is correct. */ tree decl = TREE_VALUE (parm); - if (TREE_CODE (decl) == TEMPLATE_DECL) + if (TREE_CODE (decl) == TEMPLATE_DECL + /* A template template parm is not the owning template. */ + && !DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl)) { tree ctx = DECL_CONTEXT (decl); tree inner = DECL_TEMPLATE_RESULT (decl); @@ -10164,8 +10168,13 @@ trees_in::tpl_parms_fini (tree tmpl, unsigned tpl_levels) return false; TREE_PURPOSE (parm) = dflt; + /* Original template template parms have a context + of their owning template. Reduced ones do not. + But if TMPL is itself a template template parm + then it cannot be the owning template. */ tree decl = TREE_VALUE (parm); - if (TREE_CODE (decl) == TEMPLATE_DECL) + if (TREE_CODE (decl) == TEMPLATE_DECL + && !DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl)) { tree inner = DECL_TEMPLATE_RESULT (decl); tree tpi = (TREE_CODE (inner) == TYPE_DECL @@ -10173,8 +10182,6 @@ trees_in::tpl_parms_fini (tree tmpl, unsigned tpl_levels) : DECL_INITIAL (inner)); bool original = (TEMPLATE_PARM_LEVEL (tpi) == TEMPLATE_PARM_ORIG_LEVEL (tpi)); - /* Original template template parms have a context - of their owning template. Reduced ones do not. */ if (original) DECL_CONTEXT (decl) = tmpl; } diff --git a/gcc/testsuite/g++.dg/modules/tpl-tpl-parm-3_a.H b/gcc/testsuite/g++.dg/modules/tpl-tpl-parm-3_a.H new file mode 100644 index 00000000000..21bbc054fa3 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/tpl-tpl-parm-3_a.H @@ -0,0 +1,11 @@ +// PR c++/98881 +// { dg-additional-options "-fmodule-header" } +// { dg-module-cmi {} } + +template <typename P> struct X {}; + +template<template <typename> typename TT> +struct X<TT<int>> { + template<template <typename> typename UU> + void f (X<UU<int>>&); +}; diff --git a/gcc/testsuite/g++.dg/modules/tpl-tpl-parm-3_b.C b/gcc/testsuite/g++.dg/modules/tpl-tpl-parm-3_b.C new file mode 100644 index 00000000000..234e822faa9 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/tpl-tpl-parm-3_b.C @@ -0,0 +1,13 @@ +// PR c++/98881 +// { dg-additional-options "-fmodules-ts" } + +import "tpl-tpl-parm-3_a.H"; + +template <typename T> struct Y {}; +template <typename T> struct Z {}; + +void foo() { + X<Y<int>> y; + X<Z<int>> z; + y.f(z); +} -- 2.43.2