Bug 94058 - defaulted three way comparison operator defined as deleted when a member is a small bitfield of long type.
Summary: defaulted three way comparison operator defined as deleted when a member is a...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 10.0
: P3 normal
Target Milestone: ---
Assignee: Marek Polacek
URL:
Keywords: rejects-valid
Depends on: 84516
Blocks:
  Show dependency treegraph
 
Reported: 2020-03-05 17:45 UTC by Olivier Kannengieser
Modified: 2024-07-01 18:37 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2024-06-28 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Olivier Kannengieser 2020-03-05 17:45:45 UTC
Version: GCC 10.0.1 20200229

Exemple of code:
#include <compare>

struct A{
      long i : 48;
      auto operator <=> (const A&) const = default;
      };

struct B{
      long i : 8;
      auto operator <=> (const B&) const = default;
      };

void f(A a, B b){
   a <=> a; //OK
   b <=> b; //error (see bellow)
   }

Error message:
<source>: In function 'void f(A, B)':
<source>:15:11: error: use of deleted function 'constexpr auto B::operator<=>(const B&) const'
   15 |     b <=> b;
      |           ^
<source>:10:10: note: 'constexpr auto B::operator<=>(const B&) const' is implicitly deleted because the default definition would be ill-formed:
   10 |     auto operator <=> (const B&) const = default;
      |          ^~~~~~~~
<source>:10:10: warning: narrowing conversion of '((const B*)this)->B::i' from 'long int' to 'int' [-Wnarrowing]
<source>:10:10: warning: narrowing conversion of '<anonymous>.B::i' from 'long int' to 'int' [-Wnarrowing]
Compiler returned: 1
Comment 1 Andrew Pinski 2021-08-12 20:42:53 UTC
What is interesting is clang also reject this for the same reason.
Also this is related to PR 84516.

Then again this might be invalid based on [conv.prom] (I don't know if this wording has changed in recent C++ versions though):


> A prvalue for an integral bit-field (10.3.10) can be converted to a prvalue of type int if int can represent all the values of the bit-field; otherwise, it can be converted to unsigned int if unsigned int can represent all the values of the bit-field. If the bit-field is larger yet, no integral promotion applies to it.
Comment 2 Mital Ashok 2024-06-28 11:59:32 UTC
This became CWG2627 https://cplusplus.github.io/CWG/issues/2627.html

Where the fix should mean that this shouldn't be narrowing:

```
void f(B b) {
   int{b.i};  // Not narrowing anymore
   b.i <=> b.i;  // Not narrowing anymore
   b <=> b;  // Not deleted anymore
}
```

GCC does not implement this yet, and I don't think this is related to PR 84516.
Comment 3 Marek Polacek 2024-06-28 13:33:53 UTC
Thanks for the reference, I've updated https://gcc.gnu.org/projects/cxx-dr-status.html

So confirmed.
Comment 4 Marek Polacek 2024-06-28 18:18:26 UTC
This may implement that DR:

--- a/gcc/cp/typeck2.cc
+++ b/gcc/cp/typeck2.cc
@@ -1012,6 +1012,14 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain,
       if (TREE_CODE (ftype) == ENUMERAL_TYPE)
    /* Check for narrowing based on the values of the enumeration. */
    ftype = ENUM_UNDERLYING_TYPE (ftype);
+      /* Undo convert_bitfield_to_declared_type.  (STRIP_NOPS would not be
+    enough).  */
+      tree stripped_init = init;
+      while (CONVERT_EXPR_P (stripped_init))
+   stripped_init = TREE_OPERAND (stripped_init, 0);
+      /* Core 2627  */
+      if (is_bitfield_expr_with_lowered_type (stripped_init))
+   ftype = TREE_TYPE (stripped_init);
       if ((tree_int_cst_lt (TYPE_MAX_VALUE (type),
                TYPE_MAX_VALUE (ftype))
       || tree_int_cst_lt (TYPE_MIN_VALUE (ftype),
Comment 5 Mital Ashok 2024-06-28 19:21:02 UTC
Proposed patch doesn't seem to work with bool bit-fields (with width not-1):

```
struct X {
  bool bf : 8;
} x;
signed char x_not_narrow{ x.bf };
```

Currently: Not narrowing
With patch:

```
test.cpp:4:29: warning: narrowing conversion of ‘(bool)x.X::bf’ from ‘unsigned char’ to ‘signed char’ [-Wnarrowing]
    4 | signed char x_not_narrow{ x.bf };
      |                           ~~^~
```

This DR shouldn't affect this case since this is not a conversion "from an integer type or unscoped enumeration type to an integer type that cannot represent all the values of the original type" (bool -> signed char), so the new exception shouldn't be checked.
Comment 6 Marek Polacek 2024-06-28 19:29:59 UTC
Right, I need to handle "the source is a bit-field whose width w is less than that of its type" as well; is_bitfield_expr_with_lowered_type doesn't do that.  Thanks!
Comment 7 GCC Commits 2024-07-01 18:33:03 UTC
The trunk branch has been updated by Marek Polacek <mpolacek@gcc.gnu.org>:

https://gcc.gnu.org/g:52d71b6b1f0f465a6cf064f61b22fc99453ec132

commit r15-1758-g52d71b6b1f0f465a6cf064f61b22fc99453ec132
Author: Marek Polacek <polacek@redhat.com>
Date:   Fri Jun 28 17:51:19 2024 -0400

    c++: DR2627, Bit-fields and narrowing conversions [PR94058]
    
    This DR (https://cplusplus.github.io/CWG/issues/2627.html) says that
    even if we are converting from an integer type or unscoped enumeration type
    to an integer type that cannot represent all the values of the original
    type, it's not narrowing if "the source is a bit-field whose width w is
    less than that of its type (or, for an enumeration type, its underlying
    type) and the target type can represent all the values of a hypothetical
    extended integer type with width w and with the same signedness as the
    original type".
    
            DR 2627
            PR c++/94058
            PR c++/104392
    
    gcc/cp/ChangeLog:
    
            * typeck2.cc (check_narrowing): Don't warn if the conversion isn't
            narrowing as per DR 2627.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/DRs/dr2627.C: New test.
            * g++.dg/cpp0x/Wnarrowing22.C: New test.
            * g++.dg/cpp2a/spaceship-narrowing1.C: New test.
            * g++.dg/cpp2a/spaceship-narrowing2.C: New test.
Comment 8 Marek Polacek 2024-07-01 18:37:15 UTC
Should be fixed in GCC 15.