[PATCH] c++: Set the constraints of a class type sooner [PR96229]

Jason Merrill jason@redhat.com
Wed Oct 7 20:03:55 GMT 2020


On 9/29/20 10:26 AM, 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?

OK for trunk and 10.

> 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.
> ---
>   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;
> 



More information about the Gcc-patches mailing list