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 isn't enough). */
+ tree op = init;
+ while (CONVERT_EXPR_P (op))
+ op = TREE_OPERAND (op, 0);
+ /* Core 2627 says that we shouldn't warn when "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". */
+ if (is_bitfield_expr_with_lowered_type (op)
+ && TYPE_PRECISION (TREE_TYPE (op)) < TYPE_PRECISION (ftype))
+ ftype = TREE_TYPE (op);
if ((tree_int_cst_lt (TYPE_MAX_VALUE (type),
TYPE_MAX_VALUE (ftype))
|| tree_int_cst_lt (TYPE_MIN_VALUE (ftype),
--- /dev/null
+// DR 2627 - Bit-fields and narrowing conversions
+// { dg-do compile { target c++20 } }
+
+#include <compare>
+
+struct C {
+ long long i : 8;
+};
+
+void f() {
+ C x{1}, y{2};
+ x.i <=> y.i;
+}
--- /dev/null
+// DR 2627 - Bit-fields and narrowing conversions
+// PR c++/94058
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wno-error=narrowing" }
+
+using int64_t = __INT64_TYPE__;
+using int32_t = __INT32_TYPE__;
+
+struct A {
+ int64_t i1 : __CHAR_BIT__;
+ int64_t i2 : sizeof (int32_t) * __CHAR_BIT__ - 1;
+ int64_t i3 : sizeof (int32_t) * __CHAR_BIT__;
+ int64_t i4 : sizeof (int32_t) * __CHAR_BIT__ + 1;
+ int64_t i5 : sizeof (int64_t) * __CHAR_BIT__ - 1;
+ int64_t i6 : sizeof (int64_t) * __CHAR_BIT__;
+} a;
+
+int32_t i1{a.i1};
+int32_t i2{a.i2};
+int32_t i3{a.i3};
+int32_t i4{a.i4}; // { dg-warning "narrowing conversion" }
+int32_t i5{a.i5}; // { dg-warning "narrowing conversion" }
+int32_t i6{a.i6}; // { dg-warning "narrowing conversion" }
+
+struct B {
+ bool b1 : sizeof (bool) * __CHAR_BIT__;
+ bool b2 : sizeof (bool);
+} b;
+
+signed char b1{b.b1};
+signed char b2{b.b2};
+
+enum E : int64_t { E1 };
+
+struct C {
+ E e1 : __CHAR_BIT__;
+ E e2 : sizeof (int32_t) * __CHAR_BIT__ - 1;
+ E e3 : sizeof (int32_t) * __CHAR_BIT__;
+ E e4 : sizeof (int32_t) * __CHAR_BIT__ + 1;
+ E e5 : sizeof (int64_t) * __CHAR_BIT__ - 1;
+ E e6 : sizeof (int64_t) * __CHAR_BIT__;
+} c;
+
+int32_t e1{c.e1};
+int32_t e2{c.e2};
+int32_t e3{c.e3};
+int32_t e4{c.e4}; // { dg-warning "narrowing conversion" }
+int32_t e5{c.e5}; // { dg-warning "narrowing conversion" }
+int32_t e6{c.e6}; // { dg-warning "narrowing conversion" }
--- /dev/null
+// PR c++/94058
+// { dg-do compile { target c++20 } }
+
+namespace std {
+struct strong_ordering {
+ int _v;
+ constexpr strong_ordering (int v) :_v(v) {}
+ constexpr operator int (void) const { return _v; }
+ static const strong_ordering less;
+ static const strong_ordering equal;
+ static const strong_ordering greater;
+};
+constexpr strong_ordering strong_ordering::less = -1;
+constexpr strong_ordering strong_ordering::equal = 0;
+constexpr strong_ordering strong_ordering::greater = 1;
+}
+
+struct A {
+ long i : 48;
+ auto operator <=> (const A&) const = default;
+};
+
+struct B {
+ long i : 8;
+ auto operator <=> (const B&) const = default;
+};
+
+void
+f (B b)
+{
+ (void) int{b.i}; // Not narrowing anymore
+ b.i <=> b.i; // Not narrowing anymore
+ b <=> b; // Not deleted anymore
+}
--- /dev/null
+// PR c++/104392
+// { dg-do compile { target c++20 } }
+
+namespace std {
+struct strong_ordering {
+ int _v;
+ constexpr strong_ordering (int v) :_v(v) {}
+ constexpr operator int (void) const { return _v; }
+ static const strong_ordering less;
+ static const strong_ordering equal;
+ static const strong_ordering greater;
+};
+constexpr strong_ordering strong_ordering::less = -1;
+constexpr strong_ordering strong_ordering::equal = 0;
+constexpr strong_ordering strong_ordering::greater = 1;
+}
+
+struct A {
+ unsigned int a:5;
+};
+
+constexpr std::strong_ordering
+operator<=>(const A & left, const A & right)
+{
+ return left.a <=> right.a;
+}