On Tue, 29 Sep 2020, Patrick Palka wrote: > In the testcase below, during processing (at parse time) of Y's base > class X<Y>, convert_template_argument calls is_compatible_template_arg > to check if the template argument Y is no more constrained than the > parameter P. But at this point we haven't yet set Y's constraints, so > get_normalized_constraints_from_decl yields NULL_TREE as the normal form > and it caches this result in the normalized_map. > > We set Y's constraints later in cp_parser_class_specifier_1 but the > stale normal form in the normalized_map remains. This ultimately causes > us to miss the constraint failure for Y<Z> because according to the > cached normal form, it's not constrained. > > This patch fixes this issue by moving up the call to > associate_classtype_constraints so that we set constraints before we > begin processing its bases. > > Tested on x86_64-pc-linux-gnu, and also on the cmcstlv2 and range-v3 > libraries. Does this look OK to commit? > > gcc/cp/ChangeLog: > > PR c++/96229 > * parser.c (cp_parser_class_specifier_1): Move call to > associate_classtype_constraints from here to ... > (cp_parser_class_head): ... here, before we process bases. > * pt.c (is_compatible_template_arg): Correct documentation to > say "argument is _no_ more constrained than the parameter". > > gcc/testsuite/ChangeLog: > > PR c++/96229 > * g++.dg/cpp2a/concepts-class2.C: New test.
Ping > --- > gcc/cp/parser.c | 8 ++++---- > gcc/cp/pt.c | 7 ++++--- > gcc/testsuite/g++.dg/cpp2a/concepts-class2.C | 11 +++++++++++ > 3 files changed, 19 insertions(+), 7 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-class2.C > > diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c > index 8905833fbd6..b44bdf21e1d 100644 > --- a/gcc/cp/parser.c > +++ b/gcc/cp/parser.c > @@ -23978,10 +23978,6 @@ cp_parser_class_specifier_1 (cp_parser* parser) > = parser->in_unbraced_linkage_specification_p; > parser->in_unbraced_linkage_specification_p = false; > > - // Associate constraints with the type. > - if (flag_concepts) > - type = associate_classtype_constraints (type); > - > /* Start the class. */ > if (nested_name_specifier_p) > { > @@ -24749,6 +24745,10 @@ cp_parser_class_head (cp_parser* parser, > fixup_attribute_variants (type); > } > > + /* Associate constraints with the type. */ > + if (flag_concepts) > + type = associate_classtype_constraints (type); > + > /* We will have entered the scope containing the class; the names of > base classes should be looked up in that context. For example: > > diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c > index 199fe658f71..96ad2025893 100644 > --- a/gcc/cp/pt.c > +++ b/gcc/cp/pt.c > @@ -8126,9 +8126,10 @@ canonicalize_expr_argument (tree arg, tsubst_flags_t > complain) > return canon; > } > > -// A template declaration can be substituted for a constrained > -// template template parameter only when the argument is more > -// constrained than the parameter. > +/* A template declaration can be substituted for a constrained > + template template parameter only when the argument is no more > + constrained than the parameter. */ > + > static bool > is_compatible_template_arg (tree parm, tree arg) > { > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-class2.C > b/gcc/testsuite/g++.dg/cpp2a/concepts-class2.C > new file mode 100644 > index 00000000000..0ed9eb0a386 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-class2.C > @@ -0,0 +1,11 @@ > +// PR c++/96229 > +// { dg-do compile { target c++20 } } > + > +template <class T> concept Int = requires { T{0}; }; > +template <template <Int> class P> struct X { }; > +template <Int> struct Y : X<Y> { }; > + struct Z { }; > + struct W { int i; }; > + > +Y<Z> z; // { dg-error "constraint" } > +Y<W> w; > -- > 2.28.0.618.g9bc233ae1c > >