On Tue, 28 Sep 2021, Jakub Jelinek via Gcc-patches wrote:

> Hi!
> 
> The testcases in the patch are either miscompiled or ICE with checking,
> because the defaulted operator== is synthetized too early (but only if
> constexpr), when the corresponding class type is still incomplete type.
> The problem is that at that point the bitfield FIELD_DECLs still have as
> TREE_TYPE their underlying type rather than integral type with their
> precision and when layout_class_type is called for the class soon after
> that, it changes those types but the COMPONENT_REFs type stay the way
> that they were during the operator== synthetize_method type and the
> middle-end is then upset by the mismatch of types.
> As what exact type will be given isn't just a one liner but quite long code
> especially for over-sized bitfields, I think it is best to just not
> synthetize the comparison operators so early (the defaulted_late_check
> change) and call defaulted_late_check for them once again as soon as the
> class is complete.

Nice, this might also fix PR98712.

> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
> 
> 2021-09-28  Jakub Jelinek  <ja...@redhat.com>
> 
>       PR c++/102490
>       * method.c (defaulted_late_check): Don't synthetize constexpr
>       defaulted comparisons if context is still incomplete type.
>       (finish_struct_1): Call defaulted_late_check again for defaulted
>       comparisons.
> 
>       * g++.dg/cpp2a/spaceship-eq11.C: New test.
>       * g++.dg/cpp2a/spaceship-eq12.C: New test.
> 
> --- gcc/cp/method.c.jj        2021-09-15 08:55:37.563497558 +0200
> +++ gcc/cp/method.c   2021-09-27 13:48:12.139271830 +0200
> @@ -3160,8 +3160,11 @@ defaulted_late_check (tree fn)
>    if (kind == sfk_comparison)
>      {
>        /* If the function was declared constexpr, check that the definition
> -      qualifies.  Otherwise we can define the function lazily.  */
> -      if (DECL_DECLARED_CONSTEXPR_P (fn) && !DECL_INITIAL (fn))
> +      qualifies.  Otherwise we can define the function lazily.
> +      Don't do this if the class type is still incomplete.  */
> +      if (DECL_DECLARED_CONSTEXPR_P (fn)
> +       && !DECL_INITIAL (fn)
> +       && COMPLETE_TYPE_P (ctx))
>       {

According to the function comment for defaulted_late_check, won't
COMPLETE_TYPE_P (ctx) always be false here?

>         /* Prevent GC.  */
>         function_depth++;
> --- gcc/cp/class.c.jj 2021-09-03 09:46:28.801428380 +0200
> +++ gcc/cp/class.c    2021-09-27 14:07:03.465562255 +0200
> @@ -7467,7 +7467,14 @@ finish_struct_1 (tree t)
>       for any static member objects of the type we're working on.  */
>    for (x = TYPE_FIELDS (t); x; x = DECL_CHAIN (x))
>      if (DECL_DECLARES_FUNCTION_P (x))
> -      DECL_IN_AGGR_P (x) = false;
> +      {
> +     /* Synthetize constexpr defaulted comparisons.  */
> +     if (!DECL_ARTIFICIAL (x)
> +         && DECL_DEFAULTED_IN_CLASS_P (x)
> +         && special_function_p (x) == sfk_comparison)
> +       defaulted_late_check (x);
> +     DECL_IN_AGGR_P (x) = false;
> +      }
>      else if (VAR_P (x) && TREE_STATIC (x)
>            && TREE_TYPE (x) != error_mark_node
>            && same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (x)), t))
> --- gcc/testsuite/g++.dg/cpp2a/spaceship-eq11.C.jj    2021-09-27 
> 14:20:04.723713371 +0200
> +++ gcc/testsuite/g++.dg/cpp2a/spaceship-eq11.C       2021-09-27 
> 14:20:20.387495858 +0200
> @@ -0,0 +1,43 @@
> +// PR c++/102490
> +// { dg-do run { target c++20 } }
> +
> +struct A
> +{
> +  unsigned char a : 1;
> +  unsigned char b : 1;
> +  constexpr bool operator== (const A &) const = default;
> +};
> +
> +struct B
> +{
> +  unsigned char a : 8;
> +  int : 0;
> +  unsigned char b : 7;
> +  constexpr bool operator== (const B &) const = default;
> +};
> +
> +struct C
> +{
> +  unsigned char a : 3;
> +  unsigned char b : 1;
> +  constexpr bool operator== (const C &) const = default;
> +};
> +
> +void
> +foo (C &x, int y)
> +{
> +  x.b = y;
> +}
> +
> +int
> +main ()
> +{
> +  A a{}, b{};
> +  B c{}, d{};
> +  C e{}, f{};
> +  a.b = 1;
> +  d.b = 1;
> +  foo (e, 0);
> +  foo (f, 1);
> +  return a == b || c == d || e == f;
> +}
> --- gcc/testsuite/g++.dg/cpp2a/spaceship-eq12.C.jj    2021-09-27 
> 14:20:12.050611625 +0200
> +++ gcc/testsuite/g++.dg/cpp2a/spaceship-eq12.C       2021-09-27 
> 14:20:39.633228602 +0200
> @@ -0,0 +1,5 @@
> +// PR c++/102490
> +// { dg-do run { target c++20 } }
> +// { dg-options "-O2" }
> +
> +#include "spaceship-eq11.C"
> 
>       Jakub
> 
> 

Reply via email to