Message ID | 20200422185549.2052667-1-ppalka@redhat.com |
---|---|
State | New |
Headers | show |
Series | c++: Inherited constructor template arguments [PR94719] | expand |
On 4/22/20 2:55 PM, Patrick Palka wrote: > My fix for PR94549 broke constraints_satisfied_p in the case where the inherited > constructor decl points to an instantiation of a constructor template coming > from an instantiation of a class template. > > This is because the DECL_TI_ARGS of the inherited constructor decl in this case > contains only the innermost level of template arguments (those for the > constructor template), but constraint satisfaction expects to have the full set > of template arguments. This causes template argument substitution to fail in > various ways. > > On the the hand, the DECL_TI_ARGS of the DECL_INHERITED_CTOR is a full set of > template arguments, but with the innermost level still in its dependent form, > which is the source of PR94549. So if we could combine these two sets of > template arguments then we'd be golden. > > This patch does just that, by effectively reverting the fix for PR94549 and > instead using add_outermost_template_args to combine the template arguments of > the inherited constructor with those of its DECL_INHERITED_CTOR. > > Bootstrapped and regtested successfully on x86_64-pc-linux-gnu, and also > verified that the cmcstl2 testsuite now compiles successfully again. Does this > look OK to commit? OK. > (The fact that the DECL_TI_ARGS of the inherited constructor decl doesn't > contain the full set of template arguments seems to be inconsistent with the > documentation for DECL_TI_ARGS, which says it is "always the full set of > arguments required to instantiate this declaration from the most general > template specialized here." But the full set of arguments for foo<int>::bar<5> > in the testcase below should be {{int},{5}}, not just {5}, I think?) That is strange, yes. The situation with template arguments and inherited constructors seems pretty confused. > gcc/cp/ChangeLog: > > PR c++/94719 > PR c++/94549 > * constraint.cc (satisfy_declaration_constraints): If an inherited > constructor points to an instantiation of a constructor template, > remember and use the attached template arguments. > > gcc/testsuite/ChangeLog: > > PR c++/94719 > PR c++/94549 > * g++.dg/cpp2a/concepts-inherit-ctor9.C: New test. > --- > gcc/cp/constraint.cc | 17 +++++++++++----- > .../g++.dg/cpp2a/concepts-inherit-ctor9.C | 20 +++++++++++++++++++ > 2 files changed, 32 insertions(+), 5 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor9.C > > diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc > index c05fafe5da1..06161b8c8c4 100644 > --- a/gcc/cp/constraint.cc > +++ b/gcc/cp/constraint.cc > @@ -2736,12 +2736,17 @@ static tree > satisfy_declaration_constraints (tree t, subst_info info) > { > gcc_assert (DECL_P (t)); > + const tree saved_t = t; > > - if (!DECL_TEMPLATE_INFO (t)) > - /* For inherited constructors without template information, consider > - the original declaration; it has the correct template information > - attached. */ > - t = strip_inheriting_ctors (t); > + /* For inherited constructors, consider the original declaration; > + it has the correct template information attached. */ > + t = strip_inheriting_ctors (t); > + tree inh_ctor_targs = NULL_TREE; > + if (t != saved_t) > + if (tree ti = DECL_TEMPLATE_INFO (saved_t)) > + /* The inherited constructor points to an instantiation of a constructor > + template; remember its template arguments. */ > + inh_ctor_targs = TI_ARGS (ti); > > /* Update the declaration for diagnostics. */ > info.in_decl = t; > @@ -2761,6 +2766,8 @@ satisfy_declaration_constraints (tree t, subst_info info) > /* The initial parameter mapping is the complete set of > template arguments substituted into the declaration. */ > args = TI_ARGS (ti); > + if (inh_ctor_targs) > + args = add_outermost_template_args (args, inh_ctor_targs); > } > else > { > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor9.C b/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor9.C > new file mode 100644 > index 00000000000..7d3201bff9f > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor9.C > @@ -0,0 +1,20 @@ > +// PR c++/94719 > +// { dg-do compile { target concepts } } > + > +template<typename T> > +struct bar > +{ > + template<int N = 5> requires (N == 5) > + bar() { } > +}; > + > +template<typename T> > +struct foo : bar<T> > +{ > + using foo::bar::bar; > +}; > + > +void baz() > +{ > + foo<int>{}; > +} >
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index c05fafe5da1..06161b8c8c4 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -2736,12 +2736,17 @@ static tree satisfy_declaration_constraints (tree t, subst_info info) { gcc_assert (DECL_P (t)); + const tree saved_t = t; - if (!DECL_TEMPLATE_INFO (t)) - /* For inherited constructors without template information, consider - the original declaration; it has the correct template information - attached. */ - t = strip_inheriting_ctors (t); + /* For inherited constructors, consider the original declaration; + it has the correct template information attached. */ + t = strip_inheriting_ctors (t); + tree inh_ctor_targs = NULL_TREE; + if (t != saved_t) + if (tree ti = DECL_TEMPLATE_INFO (saved_t)) + /* The inherited constructor points to an instantiation of a constructor + template; remember its template arguments. */ + inh_ctor_targs = TI_ARGS (ti); /* Update the declaration for diagnostics. */ info.in_decl = t; @@ -2761,6 +2766,8 @@ satisfy_declaration_constraints (tree t, subst_info info) /* The initial parameter mapping is the complete set of template arguments substituted into the declaration. */ args = TI_ARGS (ti); + if (inh_ctor_targs) + args = add_outermost_template_args (args, inh_ctor_targs); } else { diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor9.C b/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor9.C new file mode 100644 index 00000000000..7d3201bff9f --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor9.C @@ -0,0 +1,20 @@ +// PR c++/94719 +// { dg-do compile { target concepts } } + +template<typename T> +struct bar +{ + template<int N = 5> requires (N == 5) + bar() { } +}; + +template<typename T> +struct foo : bar<T> +{ + using foo::bar::bar; +}; + +void baz() +{ + foo<int>{}; +}