From 6b1b5c255f859e75a2d74ae58a011e846d87a277 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Thu, 8 Oct 2020 00:05:36 -0400 Subject: [PATCH] c++: Set the constraints of a class type sooner [PR96229] In the testcase below, during processing (at parse time) of Y's base class X, 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 caches this result into 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 because according to the cached normal form, Y is not constrained. This patch fixes this issue by moving up the call to associate_classtype_constraints so that we set constraints before we start processing a class's bases. 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. * 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. --- 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 7a61abf..592ce95 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -24044,10 +24044,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) { @@ -24815,6 +24811,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 d9cc776..fc4b9bb 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -8127,9 +8127,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 0000000..0ed9eb0 --- /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 concept Int = requires { T{0}; }; +template