diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc
index 7782f38da43..30a6fbe95c9 100644
--- a/gcc/cp/typeck2.cc
+++ b/gcc/cp/typeck2.cc
@@ -1012,6 +1012,18 @@ 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 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),
diff --git a/gcc/testsuite/g++.dg/DRs/dr2627.C b/gcc/testsuite/g++.dg/DRs/dr2627.C
new file mode 100644
index 00000000000..fe7f28613ca
--- /dev/null
+++ b/gcc/testsuite/g++.dg/DRs/dr2627.C
@@ -0,0 +1,13 @@
+// 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;
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/Wnarrowing22.C b/gcc/testsuite/g++.dg/cpp0x/Wnarrowing22.C
new file mode 100644
index 00000000000..dd30451a7cc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/Wnarrowing22.C
@@ -0,0 +1,49 @@
+// 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" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/spaceship-narrowing1.C b/gcc/testsuite/g++.dg/cpp2a/spaceship-narrowing1.C
new file mode 100644
index 00000000000..7769f950bed
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/spaceship-narrowing1.C
@@ -0,0 +1,34 @@
+// 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
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/spaceship-narrowing2.C b/gcc/testsuite/g++.dg/cpp2a/spaceship-narrowing2.C
new file mode 100644
index 00000000000..cfecce69405
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/spaceship-narrowing2.C
@@ -0,0 +1,26 @@
+// 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;
+}
