[clang] [clang] [SemaCXX] Implement CWG2627 Bit-fields and narrowing conversions (PR #78112)

Mital Ashok via cfe-commits cfe-commits at lists.llvm.org
Sat Jun 29 03:44:58 PDT 2024


https://github.com/MitalAshok updated https://github.com/llvm/llvm-project/pull/78112

>From 92f8720e3d21521b589d5291f086a2f32b87bfe0 Mon Sep 17 00:00:00 2001
From: Mital Ashok <mital at mitalashok.co.uk>
Date: Sun, 14 Jan 2024 19:52:31 +0000
Subject: [PATCH 1/9] [clang] [SemaCXX] Implement CWG2627 Bit-fields and
 narrowing conversions

---
 clang/docs/ReleaseNotes.rst                   |   5 +
 .../clang/Basic/DiagnosticSemaKinds.td        |   3 +
 clang/include/clang/Sema/Overload.h           |   7 +-
 clang/lib/Sema/SemaExpr.cpp                   |  10 +-
 clang/lib/Sema/SemaInit.cpp                   |  20 ++-
 clang/lib/Sema/SemaOverload.cpp               | 119 +++++++++------
 .../dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp |  24 ++++
 clang/test/CXX/drs/dr26xx.cpp                 | 136 ++++++++++++++++++
 clang/www/cxx_dr_status.html                  |   2 +-
 9 files changed, 278 insertions(+), 48 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 92563262cc673..28202fc604e29 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -157,6 +157,11 @@ Resolutions to C++ Defect Reports
 - Clang now diagnoses declarative nested-name-specifiers with pack-index-specifiers.
   (`CWG2858: Declarative nested-name-specifiers and pack-index-specifiers <https://cplusplus.github.io/CWG/issues/2858.html>`_).
 
+- Casts from a bit-field to an integral type is now not considered narrowing if the
+  width of the bit-field means that all potential values are in the range
+  of the target type, even if the type of the bit-field is larger.
+  (`CWG2627. Bit-fields and narrowing conversions  <https://cplusplus.github.io/CWG/issues/2627.html>`_).
+
 C Language Changes
 ------------------
 
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index fdca82934cb4d..6cdb439be30ae 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6253,6 +6253,9 @@ def ext_init_list_variable_narrowing_const_reference : ExtWarn<
 def ext_init_list_constant_narrowing : ExtWarn<
   "constant expression evaluates to %0 which cannot be narrowed to type %1">,
   InGroup<CXX11Narrowing>, DefaultError, SFINAEFailure;
+def ext_bit_field_narrowing : Extension<
+  "narrowing non-constant-expression from %0 bit-field of width %2 to %1 is a C++23 extension">,
+  InGroup<CXX20CompatPedantic>, SFINAEFailure;
 def ext_init_list_constant_narrowing_const_reference : ExtWarn<
   ext_init_list_constant_narrowing.Summary>,
   InGroup<CXX11NarrowingConstReference>, DefaultError, SFINAEFailure;
diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h
index 76311b00d2fc5..0d94045cc13f7 100644
--- a/clang/include/clang/Sema/Overload.h
+++ b/clang/include/clang/Sema/Overload.h
@@ -244,7 +244,11 @@ class Sema;
     /// Not a narrowing conversion.
     NK_Not_Narrowing,
 
-    /// A narrowing conversion by virtue of the source and destination types.
+    /// Not a narrowing conversion in C++23 because the source is a bit-field
+    /// whose range can fit in the target type
+    NK_BitField_Not_Narrowing,
+
+    /// A narrowing conversion by virtue of the source and target types.
     NK_Type_Narrowing,
 
     /// A narrowing conversion, because a constant expression got narrowed.
@@ -387,6 +391,7 @@ class Sema;
     NarrowingKind
     getNarrowingKind(ASTContext &Context, const Expr *Converted,
                      APValue &ConstantValue, QualType &ConstantType,
+                     unsigned &BitFieldWidth,
                      bool IgnoreFloatToIntegralConversion = false) const;
     bool isPointerConversionToBool() const;
     bool isPointerConversionToVoidPointer(ASTContext& Context) const;
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 50f92c496a539..4c16fcc60fc77 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -12361,8 +12361,9 @@ static bool checkThreeWayNarrowingConversion(Sema &S, QualType ToType, Expr *E,
 
   APValue PreNarrowingValue;
   QualType PreNarrowingType;
+  unsigned BitFieldWidth;
   switch (SCS.getNarrowingKind(S.Context, E, PreNarrowingValue,
-                               PreNarrowingType,
+                               PreNarrowingType, BitFieldWidth,
                                /*IgnoreFloatToIntegralConversion*/ true)) {
   case NK_Dependent_Narrowing:
     // Implicit conversion to a narrower type, but the expression is
@@ -12370,6 +12371,13 @@ static bool checkThreeWayNarrowingConversion(Sema &S, QualType ToType, Expr *E,
   case NK_Not_Narrowing:
     return false;
 
+  case NK_BitField_Not_Narrowing:
+    if (!S.getLangOpts().CPlusPlus23) {
+      return S.Diag(E->getBeginLoc(), diag::ext_bit_field_narrowing)
+             << FromType << ToType << BitFieldWidth;
+    }
+    return false;
+
   case NK_Constant_Narrowing:
     // Implicit conversion to a narrower type, and the value is not a constant
     // expression.
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 003a157990d30..778fe53967bc5 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -10509,13 +10509,27 @@ static void DiagnoseNarrowingInInitList(Sema &S,
   // C++11 [dcl.init.list]p7: Check whether this is a narrowing conversion.
   APValue ConstantValue;
   QualType ConstantType;
+  unsigned BitFieldWidth;
   switch (SCS->getNarrowingKind(S.Context, PostInit, ConstantValue,
-                                ConstantType)) {
+                                ConstantType, BitFieldWidth)) {
   case NK_Not_Narrowing:
   case NK_Dependent_Narrowing:
     // No narrowing occurred.
     return;
 
+  case NK_BitField_Not_Narrowing:
+    // A bit-field was "narrowed" to an integer type which is wider than the
+    // bit-field but the declared type of the bit-field is wider than the target
+    // type. This is not considered narrowing in C++23.
+    if (S.getLangOpts().CPlusPlus23)
+      return;
+    if (!(S.Diag(PostInit->getBeginLoc(), diag::ext_bit_field_narrowing)
+          << PreNarrowingType
+          << EntityType.getNonReferenceType().getLocalUnqualifiedType()
+          << BitFieldWidth))
+      return;
+    break;
+
   case NK_Type_Narrowing: {
     // This was a floating-to-integer conversion, which is always considered a
     // narrowing conversion even if the value is a constant and can be
@@ -10592,9 +10606,10 @@ static void CheckC23ConstexprInitConversion(Sema &S, QualType FromType,
 
   APValue Value;
   QualType PreNarrowingType;
+  unsigned BitFieldWidth;
   // Reuse C++ narrowing check.
   switch (ICS.Standard.getNarrowingKind(
-      S.Context, Init, Value, PreNarrowingType,
+      S.Context, Init, Value, PreNarrowingType, BitFieldWidth,
       /*IgnoreFloatToIntegralConversion*/ false)) {
   // The value doesn't fit.
   case NK_Constant_Narrowing:
@@ -10610,6 +10625,7 @@ static void CheckC23ConstexprInitConversion(Sema &S, QualType FromType,
 
   // Since we only reuse narrowing check for C23 constexpr variables here, we're
   // not really interested in these cases.
+  case NK_BitField_Not_Narrowing:
   case NK_Dependent_Narrowing:
   case NK_Variable_Narrowing:
   case NK_Not_Narrowing:
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 04cd9e78739d2..8bf42a4b1dfa4 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -331,11 +331,14 @@ static const Expr *IgnoreNarrowingConversion(ASTContext &Ctx,
 ///        value of the expression prior to the narrowing conversion.
 /// \param ConstantType  If this is an NK_Constant_Narrowing conversion, the
 ///        type of the expression prior to the narrowing conversion.
+/// \param BitFieldWidth  If this is an NK_BitField_Not_Narrowing conversion,
+///        the width of the source bit-field.
 /// \param IgnoreFloatToIntegralConversion If true type-narrowing conversions
 ///        from floating point types to integral types should be ignored.
 NarrowingKind StandardConversionSequence::getNarrowingKind(
     ASTContext &Ctx, const Expr *Converted, APValue &ConstantValue,
-    QualType &ConstantType, bool IgnoreFloatToIntegralConversion) const {
+    QualType &ConstantType, unsigned &BitFieldWidth,
+    bool IgnoreFloatToIntegralConversion) const {
   assert((Ctx.getLangOpts().CPlusPlus || Ctx.getLangOpts().C23) &&
          "narrowing check outside C++");
 
@@ -463,7 +466,12 @@ NarrowingKind StandardConversionSequence::getNarrowingKind(
 
   // -- from an integer type or unscoped enumeration type to an integer type
   //    that cannot represent all the values of the original type, except where
-  //    the source is a constant expression and the actual value after
+  //    (C++23) -- 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 or
+  //    -- the source is a constant expression and the actual value after
   //    conversion will fit into the target type and will produce the original
   //    value when converted back to the original type.
   case ICK_Integral_Conversion:
@@ -475,49 +483,70 @@ NarrowingKind StandardConversionSequence::getNarrowingKind(
     const bool ToSigned = ToType->isSignedIntegerOrEnumerationType();
     const unsigned ToWidth = Ctx.getIntWidth(ToType);
 
-    if (FromWidth > ToWidth ||
-        (FromWidth == ToWidth && FromSigned != ToSigned) ||
-        (FromSigned && !ToSigned)) {
-      // Not all values of FromType can be represented in ToType.
-      const Expr *Initializer = IgnoreNarrowingConversion(Ctx, Converted);
-
-      // If it's value-dependent, we can't tell whether it's narrowing.
-      if (Initializer->isValueDependent())
-        return NK_Dependent_Narrowing;
+    constexpr auto CanRepresentAll = [](bool FromSigned, unsigned FromWidth,
+                                        bool ToSigned, unsigned ToWidth) {
+      return (FromWidth < ToWidth + (FromSigned == ToSigned)) &&
+             (FromSigned <= ToSigned);
+    };
 
-      std::optional<llvm::APSInt> OptInitializerValue;
-      if (!(OptInitializerValue = Initializer->getIntegerConstantExpr(Ctx))) {
-        // Such conversions on variables are always narrowing.
-        return NK_Variable_Narrowing;
-      }
-      llvm::APSInt &InitializerValue = *OptInitializerValue;
-      bool Narrowing = false;
-      if (FromWidth < ToWidth) {
-        // Negative -> unsigned is narrowing. Otherwise, more bits is never
-        // narrowing.
-        if (InitializerValue.isSigned() && InitializerValue.isNegative())
-          Narrowing = true;
-      } else {
-        // Add a bit to the InitializerValue so we don't have to worry about
-        // signed vs. unsigned comparisons.
-        InitializerValue = InitializerValue.extend(
-          InitializerValue.getBitWidth() + 1);
-        // Convert the initializer to and from the target width and signed-ness.
-        llvm::APSInt ConvertedValue = InitializerValue;
-        ConvertedValue = ConvertedValue.trunc(ToWidth);
-        ConvertedValue.setIsSigned(ToSigned);
-        ConvertedValue = ConvertedValue.extend(InitializerValue.getBitWidth());
-        ConvertedValue.setIsSigned(InitializerValue.isSigned());
-        // If the result is different, this was a narrowing conversion.
-        if (ConvertedValue != InitializerValue)
-          Narrowing = true;
-      }
-      if (Narrowing) {
-        ConstantType = Initializer->getType();
-        ConstantValue = APValue(InitializerValue);
-        return NK_Constant_Narrowing;
+    if (CanRepresentAll(FromSigned, FromWidth, ToSigned, ToWidth))
+      return NK_Not_Narrowing;
+
+    // Not all values of FromType can be represented in ToType.
+    const Expr *Initializer = IgnoreNarrowingConversion(Ctx, Converted);
+
+    // If it's value-dependent, we can't tell whether it's narrowing.
+    if (Initializer->isValueDependent())
+      return NK_Dependent_Narrowing;
+
+    std::optional<llvm::APSInt> OptInitializerValue;
+    if (!(OptInitializerValue = Initializer->getIntegerConstantExpr(Ctx))) {
+      // Check for bit-field whose width means that this would not be narrowing
+      // (This check is after checking for constant expressions because
+      // a constant expression that fits is never narrowing but a non-constant
+      // expression that comes from a bit-field is only not narrowing before
+      // C++23 as an extension)
+      if (const FieldDecl *BitField = Initializer->getSourceBitField()) {
+        if (BitField->getBitWidth()->isValueDependent()) {
+          return NK_Dependent_Narrowing;
+        }
+        BitFieldWidth = BitField->getBitWidthValue(Ctx);
+        if (CanRepresentAll(FromSigned, BitFieldWidth, ToSigned, ToWidth)) {
+          return NK_BitField_Not_Narrowing;
+        }
       }
+
+      // Otherwise, such a conversion is always narrowing
+      return NK_Variable_Narrowing;
+    }
+    llvm::APSInt &InitializerValue = *OptInitializerValue;
+    bool Narrowing = false;
+    if (FromWidth < ToWidth) {
+      // Negative -> unsigned is narrowing. Otherwise, more bits is never
+      // narrowing.
+      if (InitializerValue.isSigned() && InitializerValue.isNegative())
+        Narrowing = true;
+    } else {
+      // Add a bit to the InitializerValue so we don't have to worry about
+      // signed vs. unsigned comparisons.
+      InitializerValue =
+          InitializerValue.extend(InitializerValue.getBitWidth() + 1);
+      // Convert the initializer to and from the target width and signed-ness.
+      llvm::APSInt ConvertedValue = InitializerValue;
+      ConvertedValue = ConvertedValue.trunc(ToWidth);
+      ConvertedValue.setIsSigned(ToSigned);
+      ConvertedValue = ConvertedValue.extend(InitializerValue.getBitWidth());
+      ConvertedValue.setIsSigned(InitializerValue.isSigned());
+      // If the result is different, this was a narrowing conversion.
+      if (ConvertedValue != InitializerValue)
+        Narrowing = true;
+    }
+    if (Narrowing) {
+      ConstantType = Initializer->getType();
+      ConstantValue = APValue(InitializerValue);
+      return NK_Constant_Narrowing;
     }
+
     return NK_Not_Narrowing;
   }
   case ICK_Complex_Real:
@@ -6232,14 +6261,18 @@ static ExprResult BuildConvertedConstantExpression(Sema &S, Expr *From,
   // Check for a narrowing implicit conversion.
   bool ReturnPreNarrowingValue = false;
   QualType PreNarrowingType;
+  unsigned BitFieldWidth;
   switch (SCS->getNarrowingKind(S.Context, Result.get(), PreNarrowingValue,
-                                PreNarrowingType)) {
+                                PreNarrowingType, BitFieldWidth)) {
   case NK_Dependent_Narrowing:
     // Implicit conversion to a narrower type, but the expression is
     // value-dependent so we can't tell whether it's actually narrowing.
   case NK_Variable_Narrowing:
     // Implicit conversion to a narrower type, and the value is not a constant
     // expression. We'll diagnose this in a moment.
+  case NK_BitField_Not_Narrowing:
+    // Implicit conversion where the source is a bit-field and not a constant
+    // expression.
   case NK_Not_Narrowing:
     break;
 
diff --git a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp
index 2bceb3e267790..a3049dc57d9fa 100644
--- a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp
+++ b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp
@@ -203,6 +203,30 @@ void shrink_int() {
   unsigned short usc1 = { c }; // expected-error {{non-constant-expression cannot be narrowed from type 'signed char'}} expected-note {{silence}}
   unsigned short usc2 = { (signed char)'x' }; // OK
   unsigned short usc3 = { (signed char)-1 }; // expected-error {{ -1 which cannot be narrowed}} expected-note {{silence}}
+
+#if __BITINT_MAXWIDTH__ >= 3
+  _BitInt(2) S2 = 0;
+  unsigned _BitInt(2) U2 = 0;
+  _BitInt(3) S3 = 0;
+  unsigned _BitInt(3) U3 = 0;
+
+           _BitInt(2) bi0 = { S2 };
+           _BitInt(2) bi1 = { U2 }; // expected-error {{cannot be narrowed from type 'unsigned _BitInt(2)'}}
+           _BitInt(2) bi2 = { S3 }; // expected-error {{cannot be narrowed from type '_BitInt(3)'}}
+           _BitInt(2) bi3 = { U3 }; // expected-error {{cannot be narrowed from type 'unsigned _BitInt(3)'}}
+  unsigned _BitInt(2) bi4 = { S2 }; // expected-error {{cannot be narrowed from type '_BitInt(2)'}}
+  unsigned _BitInt(2) bi5 = { U2 };
+  unsigned _BitInt(2) bi6 = { S3 }; // expected-error {{cannot be narrowed from type '_BitInt(3)'}}
+  unsigned _BitInt(2) bi7 = { U3 }; // expected-error {{cannot be narrowed from type 'unsigned _BitInt(3)'}}
+           _BitInt(3) bi8 = { S2 };
+           _BitInt(3) bi9 = { U2 };
+           _BitInt(3) bia = { S3 };
+           _BitInt(3) bib = { U3 }; // expected-error {{cannot be narrowed from type 'unsigned _BitInt(3)'}}
+  unsigned _BitInt(3) bic = { S2 }; // expected-error {{cannot be narrowed from type '_BitInt(2)'}}
+  unsigned _BitInt(3) bid = { U2 };
+  unsigned _BitInt(3) bie = { S3 }; // expected-error {{cannot be narrowed from type '_BitInt(3)'}}
+  unsigned _BitInt(3) bif = { U3 };
+#endif
 }
 
 // Be sure that type- and value-dependent expressions in templates get the error
diff --git a/clang/test/CXX/drs/dr26xx.cpp b/clang/test/CXX/drs/dr26xx.cpp
index f7a05b9827a23..3834325d69c4b 100644
--- a/clang/test/CXX/drs/dr26xx.cpp
+++ b/clang/test/CXX/drs/dr26xx.cpp
@@ -1,11 +1,37 @@
 // RUN: %clang_cc1 -std=c++98 -triple x86_64-unknown-unknown %s -verify=expected
 // RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,cxx11
+// RUN: %clang_cc1 -std=c++11 -pedantic -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,cxx11,until-cxx23-pedantic
 // RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11
+// RUN: %clang_cc1 -std=c++14 -pedantic -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,until-cxx23-pedantic
 // RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11
+// RUN: %clang_cc1 -std=c++17 -pedantic -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,until-cxx23-pedantic
 // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx20
+// RUN: %clang_cc1 -std=c++20 -pedantic -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx20,until-cxx23-pedantic
 // RUN: %clang_cc1 -std=c++23 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx20,since-cxx23
+// RUN: %clang_cc1 -std=c++23 -pedantic -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx20,since-cxx23
 // RUN: %clang_cc1 -std=c++2c -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx20,since-cxx23
+// RUN: %clang_cc1 -std=c++2c -pedantic -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx20,since-cxx23
 
+namespace std {
+#if __cplusplus >= 202002L
+  struct strong_ordering {
+    int n;
+    constexpr operator int() const { return n; }
+    static const strong_ordering less, equal, greater;
+  };
+  constexpr strong_ordering strong_ordering::less{-1},
+      strong_ordering::equal{0}, strong_ordering::greater{1};
+#endif
+
+  typedef __INT16_TYPE__ int16_t;
+  typedef __UINT16_TYPE__ uint16_t;
+  typedef __INT32_TYPE__ int32_t;
+  typedef __UINT32_TYPE__ uint32_t;
+  typedef __INT64_TYPE__ int64_t;
+  typedef __UINT64_TYPE__ uint64_t;
+
+  template<typename T> T declval();
+}
 
 namespace cwg2621 { // cwg2621: 16
 #if __cplusplus >= 202002L
@@ -24,6 +50,116 @@ using enum E;
 #endif
 }
 
+namespace cwg2627 { // cwg2627: 19
+#if __cplusplus >= 202002L
+struct C {
+  long long i : 8;
+  friend auto operator<=>(C, C) = default; // #cwg2627-3way-def
+};
+
+void f() {
+  C x{1}, y{2};
+  static_cast<void>(x <=> y);
+// until-cxx23-pedantic-warning@#cwg2627-3way-def 2 {{narrowing non-constant-expression from 'long long' bit-field of width 8 to 'int' is a C++23 extension}}
+// until-cxx23-pedantic-note at -2 {{in defaulted three-way comparison operator for 'C' first required here}}
+  static_cast<void>(x.i <=> y.i);
+// until-cxx23-pedantic-warning at -1 2 {{narrowing non-constant-expression from 'long long' bit-field of width 8 to 'int' is a C++23 extension}}
+}
+
+template<typename T>
+struct CDependent {
+  T i : 8;
+  friend auto operator<=>(CDependent, CDependent) = default;
+};
+
+template<typename T>
+concept three_way_comparable = requires(T t) { { t <=> t }; };
+template<typename T>
+concept bf_three_way_comparable = requires(T t) { { t.i <=> t.i }; };
+static_assert(three_way_comparable<CDependent<long long>> == (__cplusplus >= 202302L));
+static_assert(bf_three_way_comparable<CDependent<long long>> == (__cplusplus >= 202302L));
+#endif
+
+#if __cplusplus >= 201103L
+template<int W>
+struct D {
+  __int128 i : W;
+};
+
+template<int W>
+std::int64_t f(D<W> d) {
+    return std::int64_t{ d.i }; // #cwg2627-f
+}
+
+template std::int64_t f(D<63>);
+// until-cxx23-pedantic-warning-re@#cwg2627-f {{narrowing non-constant-expression from '__int128' bit-field of width 63 to 'std::int64_t' (aka '{{.+}}') is a C++23 extension}}
+//   until-cxx23-pedantic-note at -2 {{in instantiation of function template specialization 'cwg2627::f<63>' requested here}}
+//   until-cxx23-pedantic-note@#cwg2627-f {{insert an explicit cast to silence this issue}}
+template std::int64_t f(D<64>);
+// until-cxx23-pedantic-warning-re@#cwg2627-f {{narrowing non-constant-expression from '__int128' bit-field of width 64 to 'std::int64_t' (aka '{{.+}}') is a C++23 extension}}
+//   until-cxx23-pedantic-note at -2 {{in instantiation of function template specialization 'cwg2627::f<64>' requested here}}
+//   until-cxx23-pedantic-note@#cwg2627-f {{insert an explicit cast to silence this issue}}
+template std::int64_t f(D<65>);
+// since-cxx11-error-re@#cwg2627-f {{non-constant-expression cannot be narrowed from type '__int128' to 'std::int64_t' (aka '{{.+}}') in initializer list}}
+//   since-cxx11-note at -2 {{in instantiation of function template specialization 'cwg2627::f<65>' requested here}}
+//   since-cxx11-note@#cwg2627-f {{insert an explicit cast to silence this issue}}
+
+template<typename Target, typename Source>
+Target g(Source x) {
+    return Target{ x.i }; // #cwg2627-g
+}
+
+template<typename T, int N>
+struct E {
+  T i : N;
+};
+
+template std::int16_t g(E<int, 16>);
+// until-cxx23-pedantic-warning-re@#cwg2627-g {{narrowing non-constant-expression from 'int' bit-field of width 16 to '{{.+}}' is a C++23 extension}}
+//   until-cxx23-pedantic-note-re at -2 {{in instantiation of function template specialization 'cwg2627::g<{{.+}}, cwg2627::E<int, 16>>' requested here}}
+//   until-cxx23-pedantic-note@#cwg2627-g {{insert an explicit cast to silence this issue}}
+template std::int16_t g(E<unsigned, 15>);
+// until-cxx23-pedantic-warning-re@#cwg2627-g {{narrowing non-constant-expression from 'unsigned int' bit-field of width 15 to '{{.+}}' is a C++23 extension}}
+//   until-cxx23-pedantic-note-re at -2 {{in instantiation of function template specialization 'cwg2627::g<{{.+}}, cwg2627::E<unsigned int, 15>>' requested here}}
+//   until-cxx23-pedantic-note@#cwg2627-g {{insert an explicit cast to silence this issue}}
+template std::int16_t g(E<unsigned, 16>);
+// since-cxx11-error-re@#cwg2627-g {{non-constant-expression cannot be narrowed from type 'unsigned int' to '{{.+}}' in initializer list}}
+//   since-cxx11-note-re at -2 {{in instantiation of function template specialization 'cwg2627::g<{{.+}}, cwg2627::E<unsigned int, 16>>' requested here}}
+//   since-cxx11-note@#cwg2627-g {{insert an explicit cast to silence this issue}}
+template std::uint16_t g(E<unsigned, 16>);
+// until-cxx23-pedantic-warning-re@#cwg2627-g {{narrowing non-constant-expression from 'unsigned int' bit-field of width 16 to '{{.+}}' is a C++23 extension}}
+//   until-cxx23-pedantic-note-re at -2 {{in instantiation of function template specialization 'cwg2627::g<{{.+}}, cwg2627::E<unsigned int, 16>>' requested here}}
+//   until-cxx23-pedantic-note@#cwg2627-g {{insert an explicit cast to silence this issue}}
+template std::uint16_t g(E<int, 1>);
+// since-cxx11-error-re@#cwg2627-g {{non-constant-expression cannot be narrowed from type 'int' to '{{.+}}' in initializer list}}
+//   since-cxx11-note-re at -2 {{in instantiation of function template specialization 'cwg2627::g<{{.+}}, cwg2627::E<int, 1>>' requested here}}
+//   since-cxx11-note@#cwg2627-g {{insert an explicit cast to silence this issue}}
+
+template bool g(E<unsigned, 1>);
+// until-cxx23-pedantic-warning@#cwg2627-g {{narrowing non-constant-expression from 'unsigned int' bit-field of width 1 to 'bool' is a C++23 extension}}
+//   until-cxx23-pedantic-note at -2 {{in instantiation of function template specialization 'cwg2627::g<bool, cwg2627::E<unsigned int, 1>>' requested here}}
+//   until-cxx23-pedantic-note@#cwg2627-g {{insert an explicit cast to silence this issue}}
+template bool g(E<int, 1>);
+// since-cxx11-error@#cwg2627-g {{non-constant-expression cannot be narrowed from type 'int' to 'bool' in initializer list}}
+//   since-cxx11-note at -2 {{in instantiation of function template specialization 'cwg2627::g<bool, cwg2627::E<int, 1>>' requested here}}
+//   since-cxx11-note@#cwg2627-g {{insert an explicit cast to silence this issue}}
+
+template<typename Target, typename Source>
+constexpr decltype(Target{ std::declval<Source>().i }, false) is_narrowing(int) { return false; }
+template<typename Target, typename Source>
+constexpr bool is_narrowing(long) { return true; }
+
+constexpr bool is_cxx23 = __cplusplus >= 202302L;
+static_assert(is_narrowing<std::int16_t, E<int, 16>>(0) == !is_cxx23, "");
+static_assert(is_narrowing<std::int16_t, E<unsigned, 15>>(0) == !is_cxx23, "");
+static_assert(is_narrowing<std::int16_t, E<unsigned, 16>>(0), "");
+static_assert(is_narrowing<std::uint16_t, E<unsigned, 16>>(0) == !is_cxx23, "");
+static_assert(is_narrowing<std::uint16_t, E<int, 1>>(0), "");
+static_assert(is_narrowing<bool, E<unsigned, 1>>(0) == !is_cxx23, "");
+static_assert(is_narrowing<bool, E<int, 1>>(0), "");
+#endif
+}
+
 namespace cwg2628 { // cwg2628: no
                    // this was reverted for the 16.x release
                    // due to regressions, see the issue for more details:
diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html
index ea8872c91be60..d1f28bad64279 100755
--- a/clang/www/cxx_dr_status.html
+++ b/clang/www/cxx_dr_status.html
@@ -15570,7 +15570,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
     <td><a href="https://cplusplus.github.io/CWG/issues/2627.html">2627</a></td>
     <td>C++23</td>
     <td>Bit-fields and narrowing conversions</td>
-    <td class="unknown" align="center">Unknown</td>
+    <td class="unreleased" align="center">Clang 19</td>
   </tr>
   <tr id="2628">
     <td><a href="https://cplusplus.github.io/CWG/issues/2628.html">2628</a></td>

>From 21ef4781616b8cc2d26db0d60c17c1835effd179 Mon Sep 17 00:00:00 2001
From: Mital Ashok <mital at mitalashok.co.uk>
Date: Wed, 22 May 2024 19:31:00 +0100
Subject: [PATCH 2/9] [NFC] style changes

---
 clang/lib/Sema/SemaOverload.cpp | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 49ccbeb60b32c..258bb43ccf3bf 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -500,19 +500,23 @@ NarrowingKind StandardConversionSequence::getNarrowingKind(
     if (Initializer->isValueDependent())
       return NK_Dependent_Narrowing;
 
-    std::optional<llvm::APSInt> OptInitializerValue;
-    if (!(OptInitializerValue = Initializer->getIntegerConstantExpr(Ctx))) {
+    std::optional<llvm::APSInt> OptInitializerValue =
+        Initializer->getIntegerConstantExpr(Ctx);
+    if (!OptInitializerValue) {
       // Check for bit-field whose width means that this would not be narrowing
       // (This check is after checking for constant expressions because
       // a constant expression that fits is never narrowing but a non-constant
       // expression that comes from a bit-field is only not narrowing before
       // C++23 as an extension)
       if (const FieldDecl *BitField = Initializer->getSourceBitField()) {
-        if (BitField->getBitWidth()->isValueDependent()) {
+        if (BitField->getBitWidth()->isValueDependent())
           return NK_Dependent_Narrowing;
-        }
+
         BitFieldWidth = BitField->getBitWidthValue(Ctx);
         if (CanRepresentAll(FromSigned, BitFieldWidth, ToSigned, ToWidth)) {
+          assert(BitFieldWidth < FromWidth &&
+                 "Oversized bit-field can represent all but smaller field type "
+                 "couldn't?");
           return NK_BitField_Not_Narrowing;
         }
       }

>From 2f5ae05a55f5ff582846d45485388b105dc6f9ef Mon Sep 17 00:00:00 2001
From: Mital Ashok <mital at mitalashok.co.uk>
Date: Fri, 24 May 2024 09:22:05 +0100
Subject: [PATCH 3/9] Remove pedantic warning since this is a DR

---
 .../clang/Basic/DiagnosticSemaKinds.td        |  3 -
 clang/include/clang/Sema/Overload.h           |  7 +--
 clang/lib/Sema/SemaExpr.cpp                   | 10 +---
 clang/lib/Sema/SemaInit.cpp                   | 20 +------
 clang/lib/Sema/SemaOverload.cpp               | 57 +++++++++----------
 clang/test/CXX/drs/cwg26xx.cpp                | 51 ++++++-----------
 6 files changed, 48 insertions(+), 100 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 2d6522cb483b9..5a32463763aa6 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6279,9 +6279,6 @@ def ext_init_list_variable_narrowing_const_reference : ExtWarn<
 def ext_init_list_constant_narrowing : ExtWarn<
   "constant expression evaluates to %0 which cannot be narrowed to type %1">,
   InGroup<CXX11Narrowing>, DefaultError, SFINAEFailure;
-def ext_bit_field_narrowing : Extension<
-  "narrowing non-constant-expression from %0 bit-field of width %2 to %1 is a C++23 extension">,
-  InGroup<CXX20CompatPedantic>, SFINAEFailure;
 def ext_init_list_constant_narrowing_const_reference : ExtWarn<
   ext_init_list_constant_narrowing.Summary>,
   InGroup<CXX11NarrowingConstReference>, DefaultError, SFINAEFailure;
diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h
index 0d94045cc13f7..76311b00d2fc5 100644
--- a/clang/include/clang/Sema/Overload.h
+++ b/clang/include/clang/Sema/Overload.h
@@ -244,11 +244,7 @@ class Sema;
     /// Not a narrowing conversion.
     NK_Not_Narrowing,
 
-    /// Not a narrowing conversion in C++23 because the source is a bit-field
-    /// whose range can fit in the target type
-    NK_BitField_Not_Narrowing,
-
-    /// A narrowing conversion by virtue of the source and target types.
+    /// A narrowing conversion by virtue of the source and destination types.
     NK_Type_Narrowing,
 
     /// A narrowing conversion, because a constant expression got narrowed.
@@ -391,7 +387,6 @@ class Sema;
     NarrowingKind
     getNarrowingKind(ASTContext &Context, const Expr *Converted,
                      APValue &ConstantValue, QualType &ConstantType,
-                     unsigned &BitFieldWidth,
                      bool IgnoreFloatToIntegralConversion = false) const;
     bool isPointerConversionToBool() const;
     bool isPointerConversionToVoidPointer(ASTContext& Context) const;
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 9339335cf38c8..326879b0883fa 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -11968,9 +11968,8 @@ static bool checkThreeWayNarrowingConversion(Sema &S, QualType ToType, Expr *E,
 
   APValue PreNarrowingValue;
   QualType PreNarrowingType;
-  unsigned BitFieldWidth;
   switch (SCS.getNarrowingKind(S.Context, E, PreNarrowingValue,
-                               PreNarrowingType, BitFieldWidth,
+                               PreNarrowingType,
                                /*IgnoreFloatToIntegralConversion*/ true)) {
   case NK_Dependent_Narrowing:
     // Implicit conversion to a narrower type, but the expression is
@@ -11978,13 +11977,6 @@ static bool checkThreeWayNarrowingConversion(Sema &S, QualType ToType, Expr *E,
   case NK_Not_Narrowing:
     return false;
 
-  case NK_BitField_Not_Narrowing:
-    if (!S.getLangOpts().CPlusPlus23) {
-      return S.Diag(E->getBeginLoc(), diag::ext_bit_field_narrowing)
-             << FromType << ToType << BitFieldWidth;
-    }
-    return false;
-
   case NK_Constant_Narrowing:
     // Implicit conversion to a narrower type, and the value is not a constant
     // expression.
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index a87ee3049462b..353e911c5cc33 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -10531,27 +10531,13 @@ static void DiagnoseNarrowingInInitList(Sema &S,
   // C++11 [dcl.init.list]p7: Check whether this is a narrowing conversion.
   APValue ConstantValue;
   QualType ConstantType;
-  unsigned BitFieldWidth;
   switch (SCS->getNarrowingKind(S.Context, PostInit, ConstantValue,
-                                ConstantType, BitFieldWidth)) {
+                                ConstantType)) {
   case NK_Not_Narrowing:
   case NK_Dependent_Narrowing:
     // No narrowing occurred.
     return;
 
-  case NK_BitField_Not_Narrowing:
-    // A bit-field was "narrowed" to an integer type which is wider than the
-    // bit-field but the declared type of the bit-field is wider than the target
-    // type. This is not considered narrowing in C++23.
-    if (S.getLangOpts().CPlusPlus23)
-      return;
-    if (!(S.Diag(PostInit->getBeginLoc(), diag::ext_bit_field_narrowing)
-          << PreNarrowingType
-          << EntityType.getNonReferenceType().getLocalUnqualifiedType()
-          << BitFieldWidth))
-      return;
-    break;
-
   case NK_Type_Narrowing: {
     // This was a floating-to-integer conversion, which is always considered a
     // narrowing conversion even if the value is a constant and can be
@@ -10628,10 +10614,9 @@ static void CheckC23ConstexprInitConversion(Sema &S, QualType FromType,
 
   APValue Value;
   QualType PreNarrowingType;
-  unsigned BitFieldWidth;
   // Reuse C++ narrowing check.
   switch (ICS.Standard.getNarrowingKind(
-      S.Context, Init, Value, PreNarrowingType, BitFieldWidth,
+      S.Context, Init, Value, PreNarrowingType,
       /*IgnoreFloatToIntegralConversion*/ false)) {
   // The value doesn't fit.
   case NK_Constant_Narrowing:
@@ -10647,7 +10632,6 @@ static void CheckC23ConstexprInitConversion(Sema &S, QualType FromType,
 
   // Since we only reuse narrowing check for C23 constexpr variables here, we're
   // not really interested in these cases.
-  case NK_BitField_Not_Narrowing:
   case NK_Dependent_Narrowing:
   case NK_Variable_Narrowing:
   case NK_Not_Narrowing:
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 258bb43ccf3bf..046442a34367f 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -332,14 +332,11 @@ static const Expr *IgnoreNarrowingConversion(ASTContext &Ctx,
 ///        value of the expression prior to the narrowing conversion.
 /// \param ConstantType  If this is an NK_Constant_Narrowing conversion, the
 ///        type of the expression prior to the narrowing conversion.
-/// \param BitFieldWidth  If this is an NK_BitField_Not_Narrowing conversion,
-///        the width of the source bit-field.
 /// \param IgnoreFloatToIntegralConversion If true type-narrowing conversions
 ///        from floating point types to integral types should be ignored.
 NarrowingKind StandardConversionSequence::getNarrowingKind(
     ASTContext &Ctx, const Expr *Converted, APValue &ConstantValue,
-    QualType &ConstantType, unsigned &BitFieldWidth,
-    bool IgnoreFloatToIntegralConversion) const {
+    QualType &ConstantType, bool IgnoreFloatToIntegralConversion) const {
   assert((Ctx.getLangOpts().CPlusPlus || Ctx.getLangOpts().C23) &&
          "narrowing check outside C++");
 
@@ -467,8 +464,8 @@ NarrowingKind StandardConversionSequence::getNarrowingKind(
 
   // -- from an integer type or unscoped enumeration type to an integer type
   //    that cannot represent all the values of the original type, except where
-  //    (C++23) -- 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
+  //    (CWG2627) -- 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 or
@@ -480,7 +477,7 @@ NarrowingKind StandardConversionSequence::getNarrowingKind(
     assert(FromType->isIntegralOrUnscopedEnumerationType());
     assert(ToType->isIntegralOrUnscopedEnumerationType());
     const bool FromSigned = FromType->isSignedIntegerOrEnumerationType();
-    const unsigned FromWidth = Ctx.getIntWidth(FromType);
+    unsigned FromWidth = Ctx.getIntWidth(FromType);
     const bool ToSigned = ToType->isSignedIntegerOrEnumerationType();
     const unsigned ToWidth = Ctx.getIntWidth(ToType);
 
@@ -496,6 +493,24 @@ NarrowingKind StandardConversionSequence::getNarrowingKind(
     // Not all values of FromType can be represented in ToType.
     const Expr *Initializer = IgnoreNarrowingConversion(Ctx, Converted);
 
+    bool DependentBitField = false;
+    if (const FieldDecl *BitField = Initializer->getSourceBitField()) {
+      if (BitField->getBitWidth()->isValueDependent())
+        DependentBitField = true;
+      else {
+        unsigned BitFieldWidth = BitField->getBitWidthValue(Ctx);
+        if (CanRepresentAll(FromSigned, BitFieldWidth, ToSigned, ToWidth)) {
+          assert(BitFieldWidth < FromWidth &&
+                 "Oversized bit-field can fit in target type but smaller field "
+                 "type couldn't?");
+          return NK_Not_Narrowing;
+        }
+
+        // The initializer will be truncated to the bit-field width
+        FromWidth = BitFieldWidth;
+      }
+    }
+
     // If it's value-dependent, we can't tell whether it's narrowing.
     if (Initializer->isValueDependent())
       return NK_Dependent_Narrowing;
@@ -503,23 +518,11 @@ NarrowingKind StandardConversionSequence::getNarrowingKind(
     std::optional<llvm::APSInt> OptInitializerValue =
         Initializer->getIntegerConstantExpr(Ctx);
     if (!OptInitializerValue) {
-      // Check for bit-field whose width means that this would not be narrowing
-      // (This check is after checking for constant expressions because
-      // a constant expression that fits is never narrowing but a non-constant
-      // expression that comes from a bit-field is only not narrowing before
-      // C++23 as an extension)
-      if (const FieldDecl *BitField = Initializer->getSourceBitField()) {
-        if (BitField->getBitWidth()->isValueDependent())
-          return NK_Dependent_Narrowing;
-
-        BitFieldWidth = BitField->getBitWidthValue(Ctx);
-        if (CanRepresentAll(FromSigned, BitFieldWidth, ToSigned, ToWidth)) {
-          assert(BitFieldWidth < FromWidth &&
-                 "Oversized bit-field can represent all but smaller field type "
-                 "couldn't?");
-          return NK_BitField_Not_Narrowing;
-        }
-      }
+      // If the bit-field width was dependent, it might end up being small
+      // enough to fit in the target type (unless the target type is unsigned
+      // and the source type is signed, in which case it will never fit)
+      if (DependentBitField && (FromSigned <= ToSigned))
+        return NK_Dependent_Narrowing;
 
       // Otherwise, such a conversion is always narrowing
       return NK_Variable_Narrowing;
@@ -6245,18 +6248,14 @@ static ExprResult BuildConvertedConstantExpression(Sema &S, Expr *From,
   // Check for a narrowing implicit conversion.
   bool ReturnPreNarrowingValue = false;
   QualType PreNarrowingType;
-  unsigned BitFieldWidth;
   switch (SCS->getNarrowingKind(S.Context, Result.get(), PreNarrowingValue,
-                                PreNarrowingType, BitFieldWidth)) {
+                                PreNarrowingType)) {
   case NK_Dependent_Narrowing:
     // Implicit conversion to a narrower type, but the expression is
     // value-dependent so we can't tell whether it's actually narrowing.
   case NK_Variable_Narrowing:
     // Implicit conversion to a narrower type, and the value is not a constant
     // expression. We'll diagnose this in a moment.
-  case NK_BitField_Not_Narrowing:
-    // Implicit conversion where the source is a bit-field and not a constant
-    // expression.
   case NK_Not_Narrowing:
     break;
 
diff --git a/clang/test/CXX/drs/cwg26xx.cpp b/clang/test/CXX/drs/cwg26xx.cpp
index 9a9c33616ea8a..21776f0093e0d 100644
--- a/clang/test/CXX/drs/cwg26xx.cpp
+++ b/clang/test/CXX/drs/cwg26xx.cpp
@@ -1,16 +1,10 @@
 // RUN: %clang_cc1 -std=c++98 -triple x86_64-unknown-unknown %s -verify=expected
 // RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,cxx11
-// RUN: %clang_cc1 -std=c++11 -pedantic -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,cxx11,until-cxx23-pedantic
 // RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11
-// RUN: %clang_cc1 -std=c++14 -pedantic -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,until-cxx23-pedantic
 // RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11
-// RUN: %clang_cc1 -std=c++17 -pedantic -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,until-cxx23-pedantic
 // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx20
-// RUN: %clang_cc1 -std=c++20 -pedantic -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx20,until-cxx23-pedantic
 // RUN: %clang_cc1 -std=c++23 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx20,since-cxx23
-// RUN: %clang_cc1 -std=c++23 -pedantic -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx20,since-cxx23
 // RUN: %clang_cc1 -std=c++2c -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx20,since-cxx23
-// RUN: %clang_cc1 -std=c++2c -pedantic -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx20,since-cxx23
 
 namespace std {
 #if __cplusplus >= 202002L
@@ -54,16 +48,13 @@ namespace cwg2627 { // cwg2627: 19
 #if __cplusplus >= 202002L
 struct C {
   long long i : 8;
-  friend auto operator<=>(C, C) = default; // #cwg2627-3way-def
+  friend auto operator<=>(C, C) = default;
 };
 
 void f() {
   C x{1}, y{2};
   static_cast<void>(x <=> y);
-// until-cxx23-pedantic-warning@#cwg2627-3way-def 2 {{narrowing non-constant-expression from 'long long' bit-field of width 8 to 'int' is a C++23 extension}}
-// until-cxx23-pedantic-note at -2 {{in defaulted three-way comparison operator for 'C' first required here}}
   static_cast<void>(x.i <=> y.i);
-// until-cxx23-pedantic-warning at -1 2 {{narrowing non-constant-expression from 'long long' bit-field of width 8 to 'int' is a C++23 extension}}
 }
 
 template<typename T>
@@ -76,8 +67,8 @@ template<typename T>
 concept three_way_comparable = requires(T t) { { t <=> t }; };
 template<typename T>
 concept bf_three_way_comparable = requires(T t) { { t.i <=> t.i }; };
-static_assert(three_way_comparable<CDependent<long long>> == (__cplusplus >= 202302L));
-static_assert(bf_three_way_comparable<CDependent<long long>> == (__cplusplus >= 202302L));
+static_assert(three_way_comparable<CDependent<long long>>);
+static_assert(bf_three_way_comparable<CDependent<long long>>);
 #endif
 
 #if __cplusplus >= 201103L
@@ -92,13 +83,7 @@ std::int64_t f(D<W> d) {
 }
 
 template std::int64_t f(D<63>);
-// until-cxx23-pedantic-warning-re@#cwg2627-f {{narrowing non-constant-expression from '__int128' bit-field of width 63 to 'std::int64_t' (aka '{{.+}}') is a C++23 extension}}
-//   until-cxx23-pedantic-note at -2 {{in instantiation of function template specialization 'cwg2627::f<63>' requested here}}
-//   until-cxx23-pedantic-note@#cwg2627-f {{insert an explicit cast to silence this issue}}
 template std::int64_t f(D<64>);
-// until-cxx23-pedantic-warning-re@#cwg2627-f {{narrowing non-constant-expression from '__int128' bit-field of width 64 to 'std::int64_t' (aka '{{.+}}') is a C++23 extension}}
-//   until-cxx23-pedantic-note at -2 {{in instantiation of function template specialization 'cwg2627::f<64>' requested here}}
-//   until-cxx23-pedantic-note@#cwg2627-f {{insert an explicit cast to silence this issue}}
 template std::int64_t f(D<65>);
 // since-cxx11-error-re@#cwg2627-f {{non-constant-expression cannot be narrowed from type '__int128' to 'std::int64_t' (aka '{{.+}}') in initializer list}}
 //   since-cxx11-note at -2 {{in instantiation of function template specialization 'cwg2627::f<65>' requested here}}
@@ -115,30 +100,18 @@ struct E {
 };
 
 template std::int16_t g(E<int, 16>);
-// until-cxx23-pedantic-warning-re@#cwg2627-g {{narrowing non-constant-expression from 'int' bit-field of width 16 to '{{.+}}' is a C++23 extension}}
-//   until-cxx23-pedantic-note-re at -2 {{in instantiation of function template specialization 'cwg2627::g<{{.+}}, cwg2627::E<int, 16>>' requested here}}
-//   until-cxx23-pedantic-note@#cwg2627-g {{insert an explicit cast to silence this issue}}
 template std::int16_t g(E<unsigned, 15>);
-// until-cxx23-pedantic-warning-re@#cwg2627-g {{narrowing non-constant-expression from 'unsigned int' bit-field of width 15 to '{{.+}}' is a C++23 extension}}
-//   until-cxx23-pedantic-note-re at -2 {{in instantiation of function template specialization 'cwg2627::g<{{.+}}, cwg2627::E<unsigned int, 15>>' requested here}}
-//   until-cxx23-pedantic-note@#cwg2627-g {{insert an explicit cast to silence this issue}}
 template std::int16_t g(E<unsigned, 16>);
 // since-cxx11-error-re@#cwg2627-g {{non-constant-expression cannot be narrowed from type 'unsigned int' to '{{.+}}' in initializer list}}
 //   since-cxx11-note-re at -2 {{in instantiation of function template specialization 'cwg2627::g<{{.+}}, cwg2627::E<unsigned int, 16>>' requested here}}
 //   since-cxx11-note@#cwg2627-g {{insert an explicit cast to silence this issue}}
 template std::uint16_t g(E<unsigned, 16>);
-// until-cxx23-pedantic-warning-re@#cwg2627-g {{narrowing non-constant-expression from 'unsigned int' bit-field of width 16 to '{{.+}}' is a C++23 extension}}
-//   until-cxx23-pedantic-note-re at -2 {{in instantiation of function template specialization 'cwg2627::g<{{.+}}, cwg2627::E<unsigned int, 16>>' requested here}}
-//   until-cxx23-pedantic-note@#cwg2627-g {{insert an explicit cast to silence this issue}}
 template std::uint16_t g(E<int, 1>);
 // since-cxx11-error-re@#cwg2627-g {{non-constant-expression cannot be narrowed from type 'int' to '{{.+}}' in initializer list}}
 //   since-cxx11-note-re at -2 {{in instantiation of function template specialization 'cwg2627::g<{{.+}}, cwg2627::E<int, 1>>' requested here}}
 //   since-cxx11-note@#cwg2627-g {{insert an explicit cast to silence this issue}}
 
 template bool g(E<unsigned, 1>);
-// until-cxx23-pedantic-warning@#cwg2627-g {{narrowing non-constant-expression from 'unsigned int' bit-field of width 1 to 'bool' is a C++23 extension}}
-//   until-cxx23-pedantic-note at -2 {{in instantiation of function template specialization 'cwg2627::g<bool, cwg2627::E<unsigned int, 1>>' requested here}}
-//   until-cxx23-pedantic-note@#cwg2627-g {{insert an explicit cast to silence this issue}}
 template bool g(E<int, 1>);
 // since-cxx11-error@#cwg2627-g {{non-constant-expression cannot be narrowed from type 'int' to 'bool' in initializer list}}
 //   since-cxx11-note at -2 {{in instantiation of function template specialization 'cwg2627::g<bool, cwg2627::E<int, 1>>' requested here}}
@@ -149,14 +122,22 @@ constexpr decltype(Target{ std::declval<Source>().i }, false) is_narrowing(int)
 template<typename Target, typename Source>
 constexpr bool is_narrowing(long) { return true; }
 
-constexpr bool is_cxx23 = __cplusplus >= 202302L;
-static_assert(is_narrowing<std::int16_t, E<int, 16>>(0) == !is_cxx23, "");
-static_assert(is_narrowing<std::int16_t, E<unsigned, 15>>(0) == !is_cxx23, "");
+static_assert(!is_narrowing<std::int16_t, E<int, 16>>(0), "");
+static_assert(!is_narrowing<std::int16_t, E<unsigned, 15>>(0), "");
 static_assert(is_narrowing<std::int16_t, E<unsigned, 16>>(0), "");
-static_assert(is_narrowing<std::uint16_t, E<unsigned, 16>>(0) == !is_cxx23, "");
+static_assert(!is_narrowing<std::uint16_t, E<unsigned, 16>>(0), "");
 static_assert(is_narrowing<std::uint16_t, E<int, 1>>(0), "");
-static_assert(is_narrowing<bool, E<unsigned, 1>>(0) == !is_cxx23, "");
+static_assert(!is_narrowing<bool, E<unsigned, 1>>(0), "");
 static_assert(is_narrowing<bool, E<int, 1>>(0), "");
+
+template<int N>
+struct F {
+  signed int x : N;
+  decltype(std::int16_t{ x }) dependent_narrowing;
+  decltype(unsigned{ x }) always_narrowing;
+// since-cxx11-error at -1 {{non-constant-expression cannot be narrowed from type 'int' to 'unsigned int' in initializer list}}
+//   since-cxx11-note at -2 {{insert an explicit cast to silence this issue}}
+};
 #endif
 }
 

>From 7801e324a5ab3ed49c571e9880137e6a0e7e3528 Mon Sep 17 00:00:00 2001
From: Mital Ashok <mital at mitalashok.co.uk>
Date: Thu, 30 May 2024 18:08:17 +0100
Subject: [PATCH 4/9] Incorporate suggestions

---
 clang/test/CXX/drs/cwg26xx.cpp | 85 ++++++++++++++++------------------
 1 file changed, 39 insertions(+), 46 deletions(-)

diff --git a/clang/test/CXX/drs/cwg26xx.cpp b/clang/test/CXX/drs/cwg26xx.cpp
index 21776f0093e0d..483b8bf895b8c 100644
--- a/clang/test/CXX/drs/cwg26xx.cpp
+++ b/clang/test/CXX/drs/cwg26xx.cpp
@@ -72,66 +72,59 @@ static_assert(bf_three_way_comparable<CDependent<long long>>);
 #endif
 
 #if __cplusplus >= 201103L
-template<int W>
+template<typename T, int N>
 struct D {
-  __int128 i : W;
+  T i : N;
 };
 
-template<int W>
-std::int64_t f(D<W> d) {
-    return std::int64_t{ d.i }; // #cwg2627-f
-}
+template<typename T, int N>
+D<T, N> d();
 
-template std::int64_t f(D<63>);
-template std::int64_t f(D<64>);
-template std::int64_t f(D<65>);
-// since-cxx11-error-re@#cwg2627-f {{non-constant-expression cannot be narrowed from type '__int128' to 'std::int64_t' (aka '{{.+}}') in initializer list}}
-//   since-cxx11-note at -2 {{in instantiation of function template specialization 'cwg2627::f<65>' requested here}}
-//   since-cxx11-note@#cwg2627-f {{insert an explicit cast to silence this issue}}
+#ifdef __SIZEOF_INT128__
+std::int64_t d1{ d<__int128, 63>().i };
+std::int64_t d2{ d<__int128, 64>().i };
+std::int64_t d3{ d<__int128, 65>().i };
+// since-cxx11-error-re at -1 {{non-constant-expression cannot be narrowed from type '__int128' to 'std::int64_t' (aka '{{.+}}') in initializer list}}
+//   since-cxx11-note at -2 {{insert an explicit cast to silence this issue}}
+#endif
 
-template<typename Target, typename Source>
-Target g(Source x) {
-    return Target{ x.i }; // #cwg2627-g
-}
+#if __BITINT_MAXWIDTH__ >= 34
+__extension__ _BitInt(33) d4{ d<_BitInt(34), 33>().i };
+__extension__ _BitInt(33) d5{ d<_BitInt(34), 34>().i };
+// since-cxx11-error at -1 {{non-constant-expression cannot be narrowed from type '_BitInt(34)' to '_BitInt(33)' in initializer list}}
+//   FIXME-since-cxx11-note at -2 {{insert an explicit cast to silence this issue}}
+#endif
 
-template<typename T, int N>
-struct E {
-  T i : N;
-};
+std::int16_t d6{ d<int, 16>().i };
+std::int16_t d7{ d<unsigned, 15>().i };
+std::int16_t d8{ d<unsigned, 16>().i };
+// since-cxx11-error-re at -1 {{non-constant-expression cannot be narrowed from type 'unsigned int' to 'std::int16_t' (aka '{{.+}}') in initializer list}}
+//   since-cxx11-note at -2 {{insert an explicit cast to silence this issue}}
+std::uint16_t d9{ d<unsigned, 16>().i };
+std::uint16_t da{ d<int, 1>().i };
+// since-cxx11-error-re at -1 {{non-constant-expression cannot be narrowed from type 'int' to 'std::uint16_t' (aka '{{.+}}') in initializer list}}
+//   since-cxx11-note at -2 {{insert an explicit cast to silence this issue}}
 
-template std::int16_t g(E<int, 16>);
-template std::int16_t g(E<unsigned, 15>);
-template std::int16_t g(E<unsigned, 16>);
-// since-cxx11-error-re@#cwg2627-g {{non-constant-expression cannot be narrowed from type 'unsigned int' to '{{.+}}' in initializer list}}
-//   since-cxx11-note-re at -2 {{in instantiation of function template specialization 'cwg2627::g<{{.+}}, cwg2627::E<unsigned int, 16>>' requested here}}
-//   since-cxx11-note@#cwg2627-g {{insert an explicit cast to silence this issue}}
-template std::uint16_t g(E<unsigned, 16>);
-template std::uint16_t g(E<int, 1>);
-// since-cxx11-error-re@#cwg2627-g {{non-constant-expression cannot be narrowed from type 'int' to '{{.+}}' in initializer list}}
-//   since-cxx11-note-re at -2 {{in instantiation of function template specialization 'cwg2627::g<{{.+}}, cwg2627::E<int, 1>>' requested here}}
-//   since-cxx11-note@#cwg2627-g {{insert an explicit cast to silence this issue}}
-
-template bool g(E<unsigned, 1>);
-template bool g(E<int, 1>);
-// since-cxx11-error@#cwg2627-g {{non-constant-expression cannot be narrowed from type 'int' to 'bool' in initializer list}}
-//   since-cxx11-note at -2 {{in instantiation of function template specialization 'cwg2627::g<bool, cwg2627::E<int, 1>>' requested here}}
-//   since-cxx11-note@#cwg2627-g {{insert an explicit cast to silence this issue}}
+bool db{ d<unsigned, 1>().i };
+bool dc{ d<int, 1>().i };
+// since-cxx11-error at -1 {{non-constant-expression cannot be narrowed from type 'int' to 'bool' in initializer list}}
+//   since-cxx11-note at -2 {{insert an explicit cast to silence this issue}}
 
 template<typename Target, typename Source>
 constexpr decltype(Target{ std::declval<Source>().i }, false) is_narrowing(int) { return false; }
 template<typename Target, typename Source>
 constexpr bool is_narrowing(long) { return true; }
 
-static_assert(!is_narrowing<std::int16_t, E<int, 16>>(0), "");
-static_assert(!is_narrowing<std::int16_t, E<unsigned, 15>>(0), "");
-static_assert(is_narrowing<std::int16_t, E<unsigned, 16>>(0), "");
-static_assert(!is_narrowing<std::uint16_t, E<unsigned, 16>>(0), "");
-static_assert(is_narrowing<std::uint16_t, E<int, 1>>(0), "");
-static_assert(!is_narrowing<bool, E<unsigned, 1>>(0), "");
-static_assert(is_narrowing<bool, E<int, 1>>(0), "");
+static_assert(!is_narrowing<std::int16_t, D<int, 16>>(0), "");
+static_assert(!is_narrowing<std::int16_t, D<unsigned, 15>>(0), "");
+static_assert(is_narrowing<std::int16_t, D<unsigned, 16>>(0), "");
+static_assert(!is_narrowing<std::uint16_t, D<unsigned, 16>>(0), "");
+static_assert(is_narrowing<std::uint16_t, D<int, 1>>(0), "");
+static_assert(!is_narrowing<bool, D<unsigned, 1>>(0), "");
+static_assert(is_narrowing<bool, D<int, 1>>(0), "");
 
 template<int N>
-struct F {
+struct E {
   signed int x : N;
   decltype(std::int16_t{ x }) dependent_narrowing;
   decltype(unsigned{ x }) always_narrowing;
@@ -139,7 +132,7 @@ struct F {
 //   since-cxx11-note at -2 {{insert an explicit cast to silence this issue}}
 };
 #endif
-}
+} // namespace cwg2627
 
 namespace cwg2628 { // cwg2628: no
                    // this was reverted for the 16.x release

>From bc886bce37cfcf6c7be829b4b2ad2401023e0c5a Mon Sep 17 00:00:00 2001
From: Mital Ashok <mital at mitalashok.co.uk>
Date: Thu, 30 May 2024 18:11:58 +0100
Subject: [PATCH 5/9] Get rid of regex directives

---
 clang/test/CXX/drs/cwg26xx.cpp | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/clang/test/CXX/drs/cwg26xx.cpp b/clang/test/CXX/drs/cwg26xx.cpp
index 483b8bf895b8c..80af56e55b056 100644
--- a/clang/test/CXX/drs/cwg26xx.cpp
+++ b/clang/test/CXX/drs/cwg26xx.cpp
@@ -1,10 +1,10 @@
-// RUN: %clang_cc1 -std=c++98 -triple x86_64-unknown-unknown %s -verify=expected
-// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,cxx11
-// RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11
-// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11
-// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx20
-// RUN: %clang_cc1 -std=c++23 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx20,since-cxx23
-// RUN: %clang_cc1 -std=c++2c -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx20,since-cxx23
+// RUN: %clang_cc1 -std=c++98 -triple %itanium_abi_triple %s -verify=expected
+// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple %s -verify=expected,since-cxx11,cxx11
+// RUN: %clang_cc1 -std=c++14 -triple %itanium_abi_triple %s -verify=expected,since-cxx11
+// RUN: %clang_cc1 -std=c++17 -triple %itanium_abi_triple %s -verify=expected,since-cxx11
+// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple %s -verify=expected,since-cxx11,since-cxx20
+// RUN: %clang_cc1 -std=c++23 -triple %itanium_abi_triple %s -verify=expected,since-cxx11,since-cxx20,since-cxx23
+// RUN: %clang_cc1 -std=c++2c -triple %itanium_abi_triple %s -verify=expected,since-cxx11,since-cxx20,since-cxx23
 
 namespace std {
 #if __cplusplus >= 202002L
@@ -84,7 +84,7 @@ D<T, N> d();
 std::int64_t d1{ d<__int128, 63>().i };
 std::int64_t d2{ d<__int128, 64>().i };
 std::int64_t d3{ d<__int128, 65>().i };
-// since-cxx11-error-re at -1 {{non-constant-expression cannot be narrowed from type '__int128' to 'std::int64_t' (aka '{{.+}}') in initializer list}}
+// since-cxx11-error at -1 {{non-constant-expression cannot be narrowed from type '__int128' to 'std::int64_t' (aka 'long') in initializer list}}
 //   since-cxx11-note at -2 {{insert an explicit cast to silence this issue}}
 #endif
 
@@ -98,11 +98,11 @@ __extension__ _BitInt(33) d5{ d<_BitInt(34), 34>().i };
 std::int16_t d6{ d<int, 16>().i };
 std::int16_t d7{ d<unsigned, 15>().i };
 std::int16_t d8{ d<unsigned, 16>().i };
-// since-cxx11-error-re at -1 {{non-constant-expression cannot be narrowed from type 'unsigned int' to 'std::int16_t' (aka '{{.+}}') in initializer list}}
+// since-cxx11-error at -1 {{non-constant-expression cannot be narrowed from type 'unsigned int' to 'std::int16_t' (aka 'short') in initializer list}}
 //   since-cxx11-note at -2 {{insert an explicit cast to silence this issue}}
 std::uint16_t d9{ d<unsigned, 16>().i };
 std::uint16_t da{ d<int, 1>().i };
-// since-cxx11-error-re at -1 {{non-constant-expression cannot be narrowed from type 'int' to 'std::uint16_t' (aka '{{.+}}') in initializer list}}
+// since-cxx11-error at -1 {{non-constant-expression cannot be narrowed from type 'int' to 'std::uint16_t' (aka 'unsigned short') in initializer list}}
 //   since-cxx11-note at -2 {{insert an explicit cast to silence this issue}}
 
 bool db{ d<unsigned, 1>().i };

>From 516f66494633ab8f094f9f34c84ce52d2ee6845f Mon Sep 17 00:00:00 2001
From: Mital Ashok <mital at mitalashok.co.uk>
Date: Thu, 30 May 2024 19:16:14 +0100
Subject: [PATCH 6/9] Make sure FromWidth doesn't increase with oversized
 bit-fields

---
 clang/lib/Sema/SemaOverload.cpp | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)

diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 046442a34367f..86dae0f7a0f0e 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -497,14 +497,10 @@ NarrowingKind StandardConversionSequence::getNarrowingKind(
     if (const FieldDecl *BitField = Initializer->getSourceBitField()) {
       if (BitField->getBitWidth()->isValueDependent())
         DependentBitField = true;
-      else {
-        unsigned BitFieldWidth = BitField->getBitWidthValue(Ctx);
-        if (CanRepresentAll(FromSigned, BitFieldWidth, ToSigned, ToWidth)) {
-          assert(BitFieldWidth < FromWidth &&
-                 "Oversized bit-field can fit in target type but smaller field "
-                 "type couldn't?");
+      else if (unsigned BitFieldWidth = BitField->getBitWidthValue(Ctx);
+               BitFieldWidth < FromWidth) {
+        if (CanRepresentAll(FromSigned, BitFieldWidth, ToSigned, ToWidth))
           return NK_Not_Narrowing;
-        }
 
         // The initializer will be truncated to the bit-field width
         FromWidth = BitFieldWidth;

>From 6b46fc9794216e0a4c6bb0278b5fc07aa40ef91d Mon Sep 17 00:00:00 2001
From: Mital Ashok <mital at mitalashok.co.uk>
Date: Thu, 30 May 2024 19:30:28 +0100
Subject: [PATCH 7/9] Fix windows test failure

---
 clang/test/CXX/drs/cwg26xx.cpp | 29 ++++++++++++++---------------
 1 file changed, 14 insertions(+), 15 deletions(-)

diff --git a/clang/test/CXX/drs/cwg26xx.cpp b/clang/test/CXX/drs/cwg26xx.cpp
index 80af56e55b056..dbad013309534 100644
--- a/clang/test/CXX/drs/cwg26xx.cpp
+++ b/clang/test/CXX/drs/cwg26xx.cpp
@@ -1,10 +1,10 @@
-// RUN: %clang_cc1 -std=c++98 -triple %itanium_abi_triple %s -verify=expected
-// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple %s -verify=expected,since-cxx11,cxx11
-// RUN: %clang_cc1 -std=c++14 -triple %itanium_abi_triple %s -verify=expected,since-cxx11
-// RUN: %clang_cc1 -std=c++17 -triple %itanium_abi_triple %s -verify=expected,since-cxx11
-// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple %s -verify=expected,since-cxx11,since-cxx20
-// RUN: %clang_cc1 -std=c++23 -triple %itanium_abi_triple %s -verify=expected,since-cxx11,since-cxx20,since-cxx23
-// RUN: %clang_cc1 -std=c++2c -triple %itanium_abi_triple %s -verify=expected,since-cxx11,since-cxx20,since-cxx23
+// RUN: %clang_cc1 -std=c++98 %s -verify=expected
+// RUN: %clang_cc1 -std=c++11 %s -verify=expected,since-cxx11,cxx11
+// RUN: %clang_cc1 -std=c++14 %s -verify=expected,since-cxx11
+// RUN: %clang_cc1 -std=c++17 %s -verify=expected,since-cxx11
+// RUN: %clang_cc1 -std=c++20 %s -verify=expected,since-cxx11,since-cxx20
+// RUN: %clang_cc1 -std=c++23 %s -verify=expected,since-cxx11,since-cxx20,since-cxx23
+// RUN: %clang_cc1 -std=c++2c %s -verify=expected,since-cxx11,since-cxx20,since-cxx23
 
 namespace std {
 #if __cplusplus >= 202002L
@@ -19,10 +19,6 @@ namespace std {
 
   typedef __INT16_TYPE__ int16_t;
   typedef __UINT16_TYPE__ uint16_t;
-  typedef __INT32_TYPE__ int32_t;
-  typedef __UINT32_TYPE__ uint32_t;
-  typedef __INT64_TYPE__ int64_t;
-  typedef __UINT64_TYPE__ uint64_t;
 
   template<typename T> T declval();
 }
@@ -81,10 +77,13 @@ template<typename T, int N>
 D<T, N> d();
 
 #ifdef __SIZEOF_INT128__
-std::int64_t d1{ d<__int128, 63>().i };
-std::int64_t d2{ d<__int128, 64>().i };
-std::int64_t d3{ d<__int128, 65>().i };
-// since-cxx11-error at -1 {{non-constant-expression cannot be narrowed from type '__int128' to 'std::int64_t' (aka 'long') in initializer list}}
+using int64_t = long long;
+static_assert(sizeof(long long) == 8, "long long needs to be 64 bit for this test to work");
+
+int64_t d1{ d<__int128, 63>().i };
+int64_t d2{ d<__int128, 64>().i };
+int64_t d3{ d<__int128, 65>().i };
+// since-cxx11-error at -1 {{non-constant-expression cannot be narrowed from type '__int128' to 'int64_t' (aka 'long long') in initializer list}}
 //   since-cxx11-note at -2 {{insert an explicit cast to silence this issue}}
 #endif
 

>From aa038d01094e916bd8ed52ad03b21d66852b94ac Mon Sep 17 00:00:00 2001
From: Mital Ashok <mital at mitalashok.co.uk>
Date: Thu, 30 May 2024 20:16:03 +0100
Subject: [PATCH 8/9] Moved bitint tests to SemaCXX tests and removed __int128
 from dr tests

---
 .../dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp | 24 ----------
 clang/test/CXX/drs/cwg26xx.cpp                | 33 ++++++--------
 clang/test/SemaCXX/bitint-narrowing.cpp       | 44 +++++++++++++++++++
 3 files changed, 57 insertions(+), 44 deletions(-)
 create mode 100644 clang/test/SemaCXX/bitint-narrowing.cpp

diff --git a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp
index a3049dc57d9fa..2bceb3e267790 100644
--- a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp
+++ b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp
@@ -203,30 +203,6 @@ void shrink_int() {
   unsigned short usc1 = { c }; // expected-error {{non-constant-expression cannot be narrowed from type 'signed char'}} expected-note {{silence}}
   unsigned short usc2 = { (signed char)'x' }; // OK
   unsigned short usc3 = { (signed char)-1 }; // expected-error {{ -1 which cannot be narrowed}} expected-note {{silence}}
-
-#if __BITINT_MAXWIDTH__ >= 3
-  _BitInt(2) S2 = 0;
-  unsigned _BitInt(2) U2 = 0;
-  _BitInt(3) S3 = 0;
-  unsigned _BitInt(3) U3 = 0;
-
-           _BitInt(2) bi0 = { S2 };
-           _BitInt(2) bi1 = { U2 }; // expected-error {{cannot be narrowed from type 'unsigned _BitInt(2)'}}
-           _BitInt(2) bi2 = { S3 }; // expected-error {{cannot be narrowed from type '_BitInt(3)'}}
-           _BitInt(2) bi3 = { U3 }; // expected-error {{cannot be narrowed from type 'unsigned _BitInt(3)'}}
-  unsigned _BitInt(2) bi4 = { S2 }; // expected-error {{cannot be narrowed from type '_BitInt(2)'}}
-  unsigned _BitInt(2) bi5 = { U2 };
-  unsigned _BitInt(2) bi6 = { S3 }; // expected-error {{cannot be narrowed from type '_BitInt(3)'}}
-  unsigned _BitInt(2) bi7 = { U3 }; // expected-error {{cannot be narrowed from type 'unsigned _BitInt(3)'}}
-           _BitInt(3) bi8 = { S2 };
-           _BitInt(3) bi9 = { U2 };
-           _BitInt(3) bia = { S3 };
-           _BitInt(3) bib = { U3 }; // expected-error {{cannot be narrowed from type 'unsigned _BitInt(3)'}}
-  unsigned _BitInt(3) bic = { S2 }; // expected-error {{cannot be narrowed from type '_BitInt(2)'}}
-  unsigned _BitInt(3) bid = { U2 };
-  unsigned _BitInt(3) bie = { S3 }; // expected-error {{cannot be narrowed from type '_BitInt(3)'}}
-  unsigned _BitInt(3) bif = { U3 };
-#endif
 }
 
 // Be sure that type- and value-dependent expressions in templates get the error
diff --git a/clang/test/CXX/drs/cwg26xx.cpp b/clang/test/CXX/drs/cwg26xx.cpp
index dbad013309534..ec2ce1868c41e 100644
--- a/clang/test/CXX/drs/cwg26xx.cpp
+++ b/clang/test/CXX/drs/cwg26xx.cpp
@@ -17,8 +17,13 @@ namespace std {
       strong_ordering::equal{0}, strong_ordering::greater{1};
 #endif
 
-  typedef __INT16_TYPE__ int16_t;
-  typedef __UINT16_TYPE__ uint16_t;
+  typedef short int16_t;
+  typedef unsigned short uint16_t;
+  typedef int int32_t;
+  typedef unsigned uint32_t;
+  typedef long long int64_t;
+  typedef unsigned long long uint64_t;
+  __extension__ _Static_assert(sizeof(int16_t) == 2 && sizeof(int32_t) == 4 && sizeof(int64_t) == 8, "Some tests rely on these sizes");
 
   template<typename T> T declval();
 }
@@ -76,23 +81,11 @@ struct D {
 template<typename T, int N>
 D<T, N> d();
 
-#ifdef __SIZEOF_INT128__
-using int64_t = long long;
-static_assert(sizeof(long long) == 8, "long long needs to be 64 bit for this test to work");
-
-int64_t d1{ d<__int128, 63>().i };
-int64_t d2{ d<__int128, 64>().i };
-int64_t d3{ d<__int128, 65>().i };
-// since-cxx11-error at -1 {{non-constant-expression cannot be narrowed from type '__int128' to 'int64_t' (aka 'long long') in initializer list}}
+std::int32_t d1{ d<std::int64_t, 63>().i };
+std::int32_t d2{ d<std::int64_t, 64>().i };
+std::int32_t d3{ d<std::int64_t, 65>().i };
+// since-cxx11-error at -1 {{non-constant-expression cannot be narrowed from type 'std::int32_t' (aka 'int') to 'std::int64_t' (aka 'long long') in initializer list}}
 //   since-cxx11-note at -2 {{insert an explicit cast to silence this issue}}
-#endif
-
-#if __BITINT_MAXWIDTH__ >= 34
-__extension__ _BitInt(33) d4{ d<_BitInt(34), 33>().i };
-__extension__ _BitInt(33) d5{ d<_BitInt(34), 34>().i };
-// since-cxx11-error at -1 {{non-constant-expression cannot be narrowed from type '_BitInt(34)' to '_BitInt(33)' in initializer list}}
-//   FIXME-since-cxx11-note at -2 {{insert an explicit cast to silence this issue}}
-#endif
 
 std::int16_t d6{ d<int, 16>().i };
 std::int16_t d7{ d<unsigned, 15>().i };
@@ -127,8 +120,8 @@ struct E {
   signed int x : N;
   decltype(std::int16_t{ x }) dependent_narrowing;
   decltype(unsigned{ x }) always_narrowing;
-// since-cxx11-error at -1 {{non-constant-expression cannot be narrowed from type 'int' to 'unsigned int' in initializer list}}
-//   since-cxx11-note at -2 {{insert an explicit cast to silence this issue}}
+  // since-cxx11-error at -1 {{non-constant-expression cannot be narrowed from type 'int' to 'unsigned int' in initializer list}}
+  //   since-cxx11-note at -2 {{insert an explicit cast to silence this issue}}
 };
 #endif
 } // namespace cwg2627
diff --git a/clang/test/SemaCXX/bitint-narrowing.cpp b/clang/test/SemaCXX/bitint-narrowing.cpp
new file mode 100644
index 0000000000000..cf0baefdc6258
--- /dev/null
+++ b/clang/test/SemaCXX/bitint-narrowing.cpp
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -triple x86_64-linux-pc -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -triple x86_64-windows-pc -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -triple i386-linux-pc -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -triple i386-windows-pc -fsyntax-only -verify -std=c++11 %s
+
+#if __BITINT_MAXWIDTH__ >= 35
+struct {
+  _BitInt(35) i : 33;
+} x;
+struct {
+  _BitInt(35) i : 34;
+} y;
+_BitInt(33) xx{ x.i };
+_BitInt(33) yy{ y.i };
+// expected-error at -1 {{non-constant-expression cannot be narrowed from type '_BitInt(35)' to '_BitInt(33)' in initializer list}}
+//   FIXME-expected-note at -2 {{insert an explicit cast to silence this issue}}
+#endif
+
+#if __BITINT_MAXWIDTH__ >= 3
+         _BitInt(2) S2 = 0;
+unsigned _BitInt(2) U2 = 0;
+         _BitInt(3) S3 = 0;
+unsigned _BitInt(3) U3 = 0;
+
+         _BitInt(2) bi0{ S2 };
+         _BitInt(2) bi1{ U2 }; // expected-error {{non-constant-expression cannot be narrowed from type 'unsigned _BitInt(2)' to '_BitInt(2)' in initializer list}}
+         _BitInt(2) bi2{ S3 }; // expected-error {{non-constant-expression cannot be narrowed from type '_BitInt(3)' to '_BitInt(2)' in initializer list}}
+         _BitInt(2) bi3{ U3 }; // expected-error {{non-constant-expression cannot be narrowed from type 'unsigned _BitInt(3)' to '_BitInt(2)' in initializer list}}
+unsigned _BitInt(2) bi4{ S2 }; // expected-error {{non-constant-expression cannot be narrowed from type '_BitInt(2)' to 'unsigned _BitInt(2)' in initializer list}}
+unsigned _BitInt(2) bi5{ U2 };
+unsigned _BitInt(2) bi6{ S3 }; // expected-error {{non-constant-expression cannot be narrowed from type '_BitInt(3)' to 'unsigned _BitInt(2)' in initializer list}}
+unsigned _BitInt(2) bi7{ U3 }; // expected-error {{non-constant-expression cannot be narrowed from type 'unsigned _BitInt(3)' to 'unsigned _BitInt(2)' in initializer list}}
+         _BitInt(3) bi8{ S2 };
+         _BitInt(3) bi9{ U2 };
+         _BitInt(3) bia{ S3 };
+         _BitInt(3) bib{ U3 }; // expected-error {{non-constant-expression cannot be narrowed from type 'unsigned _BitInt(3)' to '_BitInt(3)' in initializer list}}
+unsigned _BitInt(3) bic{ S2 }; // expected-error {{non-constant-expression cannot be narrowed from type '_BitInt(2)' to 'unsigned _BitInt(3)' in initializer list}}
+unsigned _BitInt(3) bid{ U2 };
+unsigned _BitInt(3) bie{ S3 }; // expected-error {{non-constant-expression cannot be narrowed from type '_BitInt(3)' to 'unsigned _BitInt(3)' in initializer list}}
+unsigned _BitInt(3) bif{ U3 };
+#else
+// expected-no-diagnostics
+#endif

>From 362e4342a13d2147494771019b2d1ebb1e30263f Mon Sep 17 00:00:00 2001
From: Mital Ashok <mital at mitalashok.co.uk>
Date: Mon, 10 Jun 2024 16:45:45 +0100
Subject: [PATCH 9/9] _Static_assert -> static_assert

---
 clang/test/CXX/drs/cwg26xx.cpp | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/clang/test/CXX/drs/cwg26xx.cpp b/clang/test/CXX/drs/cwg26xx.cpp
index 751ae71bc26f6..ba9f7757b74dd 100644
--- a/clang/test/CXX/drs/cwg26xx.cpp
+++ b/clang/test/CXX/drs/cwg26xx.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++98 -pedantic-errors %s -verify=expected
+// RUN: %clang_cc1 -std=c++98 -pedantic-errors %s -verify=expected,cxx98
 // RUN: %clang_cc1 -std=c++11 -pedantic-errors %s -verify=expected,since-cxx11,cxx11
 // RUN: %clang_cc1 -std=c++14 -pedantic-errors %s -verify=expected,since-cxx11
 // RUN: %clang_cc1 -std=c++17 -pedantic-errors %s -verify=expected,since-cxx11
@@ -6,6 +6,11 @@
 // RUN: %clang_cc1 -std=c++23 -pedantic-errors %s -verify=expected,since-cxx11,since-cxx20,since-cxx23
 // RUN: %clang_cc1 -std=c++2c -pedantic-errors %s -verify=expected,since-cxx11,since-cxx20,since-cxx23
 
+#if __cplusplus == 199711L
+#define static_assert(...) __extension__ _Static_assert(__VA_ARGS__)
+// cxx98-error at -1 {{variadic macros are a C99 feature}}
+#endif
+
 namespace std {
 #if __cplusplus >= 202002L
   struct strong_ordering {
@@ -22,8 +27,10 @@ namespace std {
   typedef int int32_t;
   typedef unsigned uint32_t;
   typedef long long int64_t;
+  // cxx98-error at -1 {{'long long' is a C++11 extension}}
   typedef unsigned long long uint64_t;
-  __extension__ _Static_assert(sizeof(int16_t) == 2 && sizeof(int32_t) == 4 && sizeof(int64_t) == 8, "Some tests rely on these sizes");
+  // cxx98-error at -1 {{'long long' is a C++11 extension}}
+  static_assert(sizeof(int16_t) == 2 && sizeof(int32_t) == 4 && sizeof(int64_t) == 8, "Some tests rely on these sizes");
 
   template<typename T> T declval();
 }



More information about the cfe-commits mailing list