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
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.
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.
Thanks for the reference, I've updated https://gcc.gnu.org/projects/cxx-dr-status.html So confirmed.
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),
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.
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!
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.
Should be fixed in GCC 15.