[clang] [Clang] Consider preferred_type in bitfield warnings (#116760) (PR #116785)

Oliver Hunt via cfe-commits cfe-commits at lists.llvm.org
Tue Nov 19 05:53:24 PST 2024


https://github.com/ojhunt updated https://github.com/llvm/llvm-project/pull/116785

>From 5f260726253e78a00d2dff02c22837ce02b49075 Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Tue, 19 Nov 2024 11:55:11 +0100
Subject: [PATCH 1/3] [Clang] Consider preferred_type in bitfield warnings
 (#116760)

Very simply extends the bitfield sema checks for assignment to fields
with a preferred type specified to consider the preferred type if the
decl storage type is not explicitly an enum type.

This does mean that if the preferred and explicit types have different
storage requirements we may not warn in all possible cases, but that's
a scenario for which the warnings are much more complex and confusing.
---
 .../clang/Basic/DiagnosticSemaKinds.td        |   9 +-
 clang/lib/Sema/SemaChecking.cpp               |  23 +-
 .../Sema/bitfield-preferred-type-sizing.c     | 108 +++++
 .../bitfield-preferred-type-sizing.cpp        | 413 ++++++++++++++++++
 4 files changed, 546 insertions(+), 7 deletions(-)
 create mode 100644 clang/test/Sema/bitfield-preferred-type-sizing.c
 create mode 100644 clang/test/SemaCXX/bitfield-preferred-type-sizing.cpp

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 3caf471d3037f9..226b52f58d88d9 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6404,20 +6404,23 @@ def warn_bitfield_width_exceeds_type_width: Warning<
 def err_bitfield_too_wide : Error<
   "%select{bit-field %1|anonymous bit-field}0 is too wide (%2 bits)">;
 def warn_bitfield_too_small_for_enum : Warning<
-  "bit-field %0 is not wide enough to store all enumerators of %1">,
+  "bit-field %0 is not wide enough to store all enumerators of %select{|preferred type }1%2">,
   InGroup<BitFieldEnumConversion>, DefaultIgnore;
 def note_widen_bitfield : Note<
   "widen this field to %0 bits to store all values of %1">;
 def warn_unsigned_bitfield_assigned_signed_enum : Warning<
-  "assigning value of signed enum type %1 to unsigned bit-field %0; "
+  "assigning value of %select{|preferred }1signed enum type %2 to unsigned bit-field %0; "
   "negative enumerators of enum %1 will be converted to positive values">,
   InGroup<BitFieldEnumConversion>, DefaultIgnore;
 def warn_signed_bitfield_enum_conversion : Warning<
   "signed bit-field %0 needs an extra bit to represent the largest positive "
-  "enumerators of %1">,
+  "enumerators of %select{|preferred type }1%2">,
   InGroup<BitFieldEnumConversion>, DefaultIgnore;
 def note_change_bitfield_sign : Note<
   "consider making the bitfield type %select{unsigned|signed}0">;
+def note_bitfield_preferred_type : Note<
+  "preferred type for bitfield %0 specified here"
+>;
 
 def warn_missing_braces : Warning<
   "suggest braces around initialization of subobject">,
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 2d4a7cd287b70d..254284e950c7e5 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -10488,7 +10488,14 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
     // The RHS is not constant.  If the RHS has an enum type, make sure the
     // bitfield is wide enough to hold all the values of the enum without
     // truncation.
-    if (const auto *EnumTy = OriginalInit->getType()->getAs<EnumType>()) {
+    const auto *EnumTy = OriginalInit->getType()->getAs<EnumType>();
+    const PreferredTypeAttr *PTAttr = nullptr;
+    if (!EnumTy) {
+      PTAttr = Bitfield->getAttr<PreferredTypeAttr>();
+      if (PTAttr)
+        EnumTy = PTAttr->getType()->getAs<EnumType>();
+    }
+    if (EnumTy) {
       EnumDecl *ED = EnumTy->getDecl();
       bool SignedBitfield = BitfieldType->isSignedIntegerType();
 
@@ -10509,14 +10516,18 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
                  ED->getNumPositiveBits() == FieldWidth) {
         DiagID = diag::warn_signed_bitfield_enum_conversion;
       }
-
+      unsigned PreferredTypeDiagIndex = PTAttr != nullptr;
       if (DiagID) {
-        S.Diag(InitLoc, DiagID) << Bitfield << ED;
+        S.Diag(InitLoc, DiagID) << Bitfield << PreferredTypeDiagIndex << ED;
         TypeSourceInfo *TSI = Bitfield->getTypeSourceInfo();
         SourceRange TypeRange =
             TSI ? TSI->getTypeLoc().getSourceRange() : SourceRange();
         S.Diag(Bitfield->getTypeSpecStartLoc(), diag::note_change_bitfield_sign)
             << SignedEnum << TypeRange;
+        if (PTAttr) {
+          S.Diag(PTAttr->getLocation(), diag::note_bitfield_preferred_type)
+              << ED;
+        }
       }
 
       // Compute the required bitwidth. If the enum has negative values, we need
@@ -10530,9 +10541,13 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
       if (BitsNeeded > FieldWidth) {
         Expr *WidthExpr = Bitfield->getBitWidth();
         S.Diag(InitLoc, diag::warn_bitfield_too_small_for_enum)
-            << Bitfield << ED;
+            << Bitfield << PreferredTypeDiagIndex << ED;
         S.Diag(WidthExpr->getExprLoc(), diag::note_widen_bitfield)
             << BitsNeeded << ED << WidthExpr->getSourceRange();
+        if (PTAttr) {
+          S.Diag(PTAttr->getLocation(), diag::note_bitfield_preferred_type)
+              << ED;
+        }
       }
     }
 
diff --git a/clang/test/Sema/bitfield-preferred-type-sizing.c b/clang/test/Sema/bitfield-preferred-type-sizing.c
new file mode 100644
index 00000000000000..16d48bc0692dfa
--- /dev/null
+++ b/clang/test/Sema/bitfield-preferred-type-sizing.c
@@ -0,0 +1,108 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify -std=c11 -Wno-unused-value -Wno-unused-but-set-variable -Wbitfield-width -Wbitfield-enum-conversion
+
+enum A {
+  A_a,
+  A_b,
+  A_c,
+  A_d
+};
+
+struct S {
+  enum A a1 : 1; // #1
+  enum A a2 : 2;
+  enum A a3 : 8;
+  __attribute__((preferred_type(enum A))) // #preferred_a4
+  unsigned a4 : 1; // #2
+  __attribute__((preferred_type(enum A)))
+  unsigned a5 : 2;
+  __attribute__((preferred_type(enum A)))
+  unsigned a6 : 8;
+  __attribute__((preferred_type(enum A)))  // #preferred_a7
+  int a7 : 1; // #3
+  __attribute__((preferred_type(enum A))) // #preferred_a8
+  int a8 : 2; // #4
+  __attribute__((preferred_type(enum A)))
+  int a9 : 8;
+};
+
+void read_enum(struct S *s) {
+  enum A x;
+  x = s->a1;
+  x = s->a2;
+  x = s->a3;
+  x = s->a4;
+  x = s->a5;
+  x = s->a6;
+  x = s->a7;
+  x = s->a8;
+  x = s->a9;
+}
+
+void write_enum(struct S *s, enum A x) {
+  s->a1 = x;
+  // expected-warning at -1 {{bit-field 'a1' is not wide enough to store all enumerators of 'A'}}
+  // expected-note@#1 {{widen this field to 2 bits to store all values of 'A'}}
+  s->a2 = x;
+  s->a3 = x;
+  s->a4 = x;
+  // expected-warning at -1 {{bit-field 'a4' is not wide enough to store all enumerators of 'A'}}
+  // expected-note@#2 {{widen this field to 2 bits to store all values of 'A'}}
+  s->a5 = x;
+  s->a6 = x;
+  s->a7 = x;
+  // expected-warning at -1 {{bit-field 'a7' is not wide enough to store all enumerators of 'A'}}
+  // expected-note@#3 {{widen this field to 2 bits to store all values of 'A'}}
+  s->a8 = x;
+  // expected-warning at -1 {{signed bit-field 'a8' needs an extra bit to represent the largest positive enumerators of 'A'}}
+  // expected-note@#4 {{consider making the bitfield type unsigned}}
+  s->a9 = x;
+}
+
+void write_enum_int(struct S *s, int x) {
+  s->a1 = x;
+  s->a2 = x;
+  s->a3 = x;
+  s->a4 = x;
+  // expected-warning at -1 {{bit-field 'a4' is not wide enough to store all enumerators of preferred type 'A'}}
+  // expected-note@#2 {{widen this field to 2 bits to store all values of 'A'}}
+  // expected-note@#preferred_a4 {{preferred type for bitfield 'A' specified here}}
+  s->a5 = x;
+  s->a6 = x;
+  s->a7 = x;
+  // expected-warning at -1 {{bit-field 'a7' is not wide enough to store all enumerators of preferred type 'A'}}
+  // expected-note@#3 {{widen this field to 2 bits to store all values of 'A'}}
+  // expected-note@#preferred_a7 {{preferred type for bitfield 'A' specified here}}
+  s->a8 = x;
+  // expected-warning at -1 {{signed bit-field 'a8' needs an extra bit to represent the largest positive enumerators of preferred type 'A'}}
+  // expected-note@#4 {{consider making the bitfield type unsigned}}
+  // expected-note@#preferred_a8 {{preferred type for bitfield 'A' specified here}}
+  s->a9 = x;
+}
+
+void write_low_constant(struct S *s) {
+  s->a1 = A_a;
+  s->a2 = A_a;
+  s->a3 = A_a;
+  s->a4 = A_a;
+  s->a5 = A_a;
+  s->a6 = A_a;
+  s->a7 = A_a;
+  s->a8 = A_a;
+  s->a9 = A_a;
+};
+
+void write_high_constant(struct S *s) {
+  s->a1 = A_d;
+  // expected-warning at -1 {{implicit truncation from 'int' to bit-field changes value from 3 to 1}}
+  s->a2 = A_d;
+  s->a3 = A_d;
+  s->a4 = A_d;
+  // expected-warning at -1 {{implicit truncation from 'int' to bit-field changes value from 3 to 1}}
+  s->a5 = A_d;
+  s->a6 = A_d;
+  s->a7 = A_d;
+  // expected-warning at -1 {{implicit truncation from 'int' to bit-field changes value from 3 to -1}}
+  s->a8 = A_d;
+  // expected-warning at -1 {{implicit truncation from 'int' to bit-field changes value from 3 to -1}}
+  s->a9 = A_d;
+};
diff --git a/clang/test/SemaCXX/bitfield-preferred-type-sizing.cpp b/clang/test/SemaCXX/bitfield-preferred-type-sizing.cpp
new file mode 100644
index 00000000000000..5e39d2ac2ba324
--- /dev/null
+++ b/clang/test/SemaCXX/bitfield-preferred-type-sizing.cpp
@@ -0,0 +1,413 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify -std=c++23 -Wno-unused-value -Wno-unused-but-set-variable -Wbitfield-width -Wbitfield-enum-conversion
+
+// This is more complex than the C version because the user can specify the
+// storage type 
+
+enum A {
+  A_a,
+  A_b,
+  A_c,
+  A_d
+};
+
+enum class B : int {
+  a,
+  b,
+  c,
+  d
+};
+
+enum class C : unsigned {
+  a,
+  b,
+  c,
+  d
+};
+
+enum class Derp : unsigned {
+  a,
+  b
+};
+
+// Not using templates here so we can more easily distinguish the responsible
+// party for each warning
+
+struct S_A {
+  A field1 : 1; // #S_A_field1
+  A field2 : 2; // #S_A_field2
+  A field3 : 8; // #S_A_field3
+  __attribute__((preferred_type(A))) // #preferred_S_A_field4
+  unsigned field4 : 1; // #S_A_field4
+  __attribute__((preferred_type(A)))
+  unsigned field5 : 2; // #S_A_field5
+  __attribute__((preferred_type(A)))
+  unsigned field6 : 8; // #S_A_field6
+  __attribute__((preferred_type(A))) // #preferred_S_A_field7
+  int field7 : 1; // #S_A_field7
+  __attribute__((preferred_type(A))) // #preferred_S_A_field8
+  int field8 : 2; // #S_A_field8
+  __attribute__((preferred_type(A)))
+  int field9 : 8; // #S_A_field9
+  __attribute__((preferred_type(A)))
+  Derp field10 : 1; // #S_A_field10
+  __attribute__((preferred_type(A))) // #preferred_S_A_field11
+  Derp field11 : 2; // #S_A_field11
+  __attribute__((preferred_type(A)))
+  Derp field12 : 8; // #S_A_field12
+};
+
+struct S_B {
+  B field1 : 1; // #S_B_field1
+  B field2 : 2; // #S_B_field2
+  B field3 : 8; // #S_B_field3
+  __attribute__((preferred_type(B))) // #preferred_S_B_field4
+  unsigned field4 : 1; // #S_B_field4
+  __attribute__((preferred_type(B)))
+  unsigned field5 : 2; // #S_B_field5
+  __attribute__((preferred_type(B)))
+  unsigned field6 : 8; // #S_B_field6
+  __attribute__((preferred_type(B))) // #preferred_S_B_field7
+  int field7 : 1; // #S_B_field7
+  __attribute__((preferred_type(B))) // #preferred_S_B_field8
+  int field8 : 2; // #S_B_field8
+  __attribute__((preferred_type(B)))
+  int field9 : 8; // #S_B_field9
+  __attribute__((preferred_type(B)))
+  Derp field10 : 1; // #S_B_field10
+  __attribute__((preferred_type(B))) // #preferred_S_B_field11
+  Derp field11 : 2; // #S_B_field11
+  __attribute__((preferred_type(B)))
+  Derp field12 : 8; // #S_B_field12
+};
+
+struct S_C {
+  C field1 : 1; // #S_C_field1
+  C field2 : 2; // #S_C_field2
+  C field3 : 8; // #S_C_field3
+  __attribute__((preferred_type(C))) // #preferred_S_C_field4
+  unsigned field4 : 1; // #S_C_field4
+  __attribute__((preferred_type(C)))
+  unsigned field5 : 2; // #S_C_field5
+  __attribute__((preferred_type(C)))
+  unsigned field6 : 8; // #S_C_field6
+  __attribute__((preferred_type(C))) // #preferred_S_C_field7
+  int field7 : 1; // #S_C_field7
+  __attribute__((preferred_type(C))) // #preferred_S_C_field8
+  int field8 : 2; // #S_C_field8
+  __attribute__((preferred_type(C)))
+  int field9 : 8; // #S_C_field9
+  __attribute__((preferred_type(C)))
+  Derp field10 : 1; // #S_C_field10
+  __attribute__((preferred_type(C))) // #preferred_S_C_field11
+  Derp field11 : 2; // #S_C_field11
+  __attribute__((preferred_type(C)))
+  Derp field12 : 8; // #S_C_field12
+};
+
+void read_enum(S_A *s) {
+  using EnumType = A;
+  EnumType x;
+  x = s->field1;
+  x = s->field2;
+  x = s->field3;
+  x = (EnumType)s->field4;
+  x = (EnumType)s->field5;
+  x = (EnumType)s->field6;
+  x = (EnumType)s->field7;
+  x = (EnumType)s->field8;
+  x = (EnumType)s->field9;
+  x = (EnumType)s->field10;
+  x = (EnumType)s->field11;
+  x = (EnumType)s->field12;
+}
+
+void read_enum(S_B *s) {
+  using EnumType = B;
+  EnumType x;
+  x = s->field1;
+  x = s->field2;
+  x = s->field3;
+  x = (EnumType)s->field4;
+  x = (EnumType)s->field5;
+  x = (EnumType)s->field6;
+  x = (EnumType)s->field7;
+  x = (EnumType)s->field8;
+  x = (EnumType)s->field9;
+  x = (EnumType)s->field10;
+  x = (EnumType)s->field11;
+  x = (EnumType)s->field12;
+}
+
+void read_enum(S_C *s) {
+  using EnumType = C;
+  EnumType x;
+  x = s->field1;
+  x = s->field2;
+  x = s->field3;
+  x = (EnumType)s->field4;
+  x = (EnumType)s->field5;
+  x = (EnumType)s->field6;
+  x = (EnumType)s->field7;
+  x = (EnumType)s->field8;
+  x = (EnumType)s->field9;
+  x = (EnumType)s->field10;
+  x = (EnumType)s->field11;
+  x = (EnumType)s->field12;
+}
+
+void write_enum(S_A *s, A x) {
+  s->field1 = x;
+  // expected-warning at -1 {{bit-field 'field1' is not wide enough to store all enumerators of 'A'}}
+  // expected-note@#S_A_field1 {{widen this field to 2 bits to store all values of 'A'}}
+  s->field2 = x;
+  s->field3 = x;
+  s->field4 = x;
+  // expected-warning at -1 {{bit-field 'field4' is not wide enough to store all enumerators of 'A'}}
+  // expected-note@#S_A_field4 {{widen this field to 2 bits to store all values of 'A'}}
+  s->field5 = x;
+  s->field6 = x;
+  s->field7 = x;
+  // expected-warning at -1 {{bit-field 'field7' is not wide enough to store all enumerators of 'A'}}
+  // expected-note@#S_A_field7 {{widen this field to 2 bits to store all values of 'A'}}
+  s->field8 = x;
+  // expected-warning at -1 {{signed bit-field 'field8' needs an extra bit to represent the largest positive enumerators of 'A'}}
+  // expected-note@#S_A_field8 {{consider making the bitfield type unsigned}}
+  s->field9 = x;
+  s->field10 = (Derp)x;
+  s->field11 = (Derp)x;
+  s->field12 = (Derp)x;
+}
+
+void write_enum(S_B *s, B x) {
+  s->field1 = x;
+  // expected-warning at -1 {{bit-field 'field1' is not wide enough to store all enumerators of 'B'}}
+  // expected-note@#S_B_field1 {{widen this field to 2 bits to store all values of 'B'}}
+  s->field2 = x;
+  s->field3 = x;
+  s->field4 = (unsigned)x;
+  // expected-warning at -1 {{bit-field 'field4' is not wide enough to store all enumerators of preferred type 'B'}}
+  // expected-note@#S_B_field4 {{widen this field to 2 bits to store all values of 'B'}}
+  // expected-note@#preferred_S_B_field4 {{preferred type for bitfield 'B' specified here}}
+  s->field5 = (unsigned)x;
+  s->field6 = (unsigned)x;
+  s->field7 = (int)x;
+  // expected-warning at -1 {{bit-field 'field7' is not wide enough to store all enumerators of preferred type 'B'}}
+  // expected-note@#S_B_field7 {{widen this field to 2 bits to store all values of 'B'}}
+  // expected-note@#preferred_S_B_field7 {{preferred type for bitfield 'B' specified here}}
+  s->field8 = (int)x;
+  // expected-warning at -1 {{signed bit-field 'field8' needs an extra bit to represent the largest positive enumerators of preferred type 'B'}}
+  // expected-note@#S_B_field8 {{consider making the bitfield type unsigned}}
+  // expected-note@#preferred_S_B_field8 {{preferred type for bitfield 'B' specified here}}
+  s->field9 = (int)x;
+  s->field10 = (Derp)x;
+  s->field11 = (Derp)x;
+  s->field12 = (Derp)x;
+}
+void write_enum(S_C *s, C x) {
+  s->field1 = x;
+  // expected-warning at -1 {{bit-field 'field1' is not wide enough to store all enumerators of 'C'}}
+  // expected-note@#S_C_field1 {{widen this field to 2 bits to store all values of 'C'}}
+  s->field2 = x;
+  s->field3 = x;
+  s->field4 = (unsigned)x;
+  // expected-warning at -1 {{bit-field 'field4' is not wide enough to store all enumerators of preferred type 'C'}}
+  // expected-note@#S_C_field4 {{widen this field to 2 bits to store all values of 'C'}}
+  // expected-note@#preferred_S_C_field4 {{preferred type for bitfield 'C' specified here}}
+  s->field5 = (unsigned)x;
+  s->field6 = (unsigned)x;
+  s->field7 = (int)x;
+  // expected-warning at -1 {{bit-field 'field7' is not wide enough to store all enumerators of preferred type 'C'}}
+  // expected-note@#S_C_field7 {{widen this field to 2 bits to store all values of 'C'}}
+  // expected-note@#preferred_S_C_field7 {{preferred type for bitfield 'C' specified here}}
+  s->field8 = (int)x;
+  // expected-warning at -1 {{signed bit-field 'field8' needs an extra bit to represent the largest positive enumerators of preferred type 'C'}}
+  // expected-note@#S_C_field8 {{consider making the bitfield type unsigned}}
+  // expected-note@#preferred_S_C_field8 {{preferred type for bitfield 'C' specified here}}
+  s->field9 = (int)x;
+  s->field10 = (Derp)x;
+  s->field11 = (Derp)x;
+  s->field12 = (Derp)x;
+}
+
+void write_enum_int(struct S_A *s, int x) {
+  using EnumType = A;
+  s->field1 = (EnumType)x;
+  // expected-warning at -1 {{bit-field 'field1' is not wide enough to store all enumerators of 'A'}}
+  // expected-note@#S_A_field1 {{widen this field to 2 bits to store all values of 'A'}}
+  s->field2 = (EnumType)x;
+  s->field3 = (EnumType)x;
+  s->field4 = x;
+  // expected-warning at -1 {{bit-field 'field4' is not wide enough to store all enumerators of preferred type 'A'}}
+  // expected-note@#S_A_field4 {{widen this field to 2 bits to store all values of 'A'}}
+  // expected-note@#preferred_S_A_field4 {{preferred type for bitfield 'A' specified here}}
+  s->field5 = x;
+  s->field6 = x;
+  s->field7 = x;
+  // expected-warning at -1 {{bit-field 'field7' is not wide enough to store all enumerators of preferred type 'A'}}
+  // expected-note@#S_A_field7 {{widen this field to 2 bits to store all values of 'A'}}
+  // expected-note@#preferred_S_A_field7 {{preferred type for bitfield 'A' specified here}}
+  s->field8 = x;
+  // expected-warning at -1 {{signed bit-field 'field8' needs an extra bit to represent the largest positive enumerators of preferred type 'A'}}
+  // expected-note@#S_A_field8 {{consider making the bitfield type unsigned}}
+  // expected-note@#preferred_S_A_field8 {{preferred type for bitfield 'A' specified here}}
+  s->field9 = x;
+  s->field10 = (Derp)x;
+  s->field11 = (Derp)x;
+  s->field12 = (Derp)x;
+}
+
+void write_enum_int(struct S_B *s, int x) {
+  using EnumType = B;
+  s->field1 = (EnumType)x;
+  // expected-warning at -1 {{bit-field 'field1' is not wide enough to store all enumerators of 'B'}}
+  // expected-note@#S_B_field1 {{widen this field to 2 bits to store all values of 'B'}}
+  s->field2 = (EnumType)x;
+  s->field3 = (EnumType)x;
+  s->field4 = x;
+  // expected-warning at -1 {{bit-field 'field4' is not wide enough to store all enumerators of preferred type 'B'}}
+  // expected-note@#S_B_field4 {{widen this field to 2 bits to store all values of 'B'}}
+  // expected-note@#preferred_S_B_field4 {{preferred type for bitfield 'B' specified here}}
+  s->field5 = x;
+  s->field6 = x;
+  s->field7 = x;
+  // expected-warning at -1 {{bit-field 'field7' is not wide enough to store all enumerators of preferred type 'B'}}
+  // expected-note@#S_B_field7 {{widen this field to 2 bits to store all values of 'B'}}
+  // expected-note@#preferred_S_B_field7 {{preferred type for bitfield 'B' specified here}}
+  s->field8 = x;
+  // expected-warning at -1 {{signed bit-field 'field8' needs an extra bit to represent the largest positive enumerators of preferred type 'B'}}
+  // expected-note@#S_B_field8 {{consider making the bitfield type unsigned}}
+  // expected-note@#preferred_S_B_field8 {{preferred type for bitfield 'B' specified here}}
+  s->field9 = x;
+  s->field10 = (Derp)x;
+  s->field11 = (Derp)x;
+  s->field12 = (Derp)x;
+}
+
+void write_enum_int(struct S_C *s, int x) {
+  using EnumType = C;
+  s->field1 = (EnumType)x;
+  // expected-warning at -1 {{bit-field 'field1' is not wide enough to store all enumerators of 'C'}}
+  // expected-note@#S_C_field1 {{widen this field to 2 bits to store all values of 'C'}}
+  s->field2 = (EnumType)x;
+  s->field3 = (EnumType)x;
+  s->field4 = x;
+  // expected-warning at -1 {{bit-field 'field4' is not wide enough to store all enumerators of preferred type 'C'}}
+  // expected-note@#S_C_field4 {{widen this field to 2 bits to store all values of 'C'}}
+  // expected-note@#preferred_S_C_field4 {{preferred type for bitfield 'C' specified here}}
+  s->field5 = x;
+  s->field6 = x;
+  s->field7 = x;
+  // expected-warning at -1 {{bit-field 'field7' is not wide enough to store all enumerators of preferred type 'C'}}
+  // expected-note@#S_C_field7 {{widen this field to 2 bits to store all values of 'C'}}
+  // expected-note@#preferred_S_C_field7 {{preferred type for bitfield 'C' specified here}}
+  s->field8 = x;
+  // expected-warning at -1 {{signed bit-field 'field8' needs an extra bit to represent the largest positive enumerators of preferred type 'C'}}
+  // expected-note@#S_C_field8 {{consider making the bitfield type unsigned}}
+  // expected-note@#preferred_S_C_field8 {{preferred type for bitfield 'C' specified here}}
+  s->field9 = x;
+  s->field10 = (Derp)x;
+  s->field11 = (Derp)x;
+  s->field12 = (Derp)x;
+}
+
+void write_low_constant(S_A *s) {
+  s->field1 = A_a;
+  s->field2 = A_a;
+  s->field3 = A_a;
+  s->field4 = A_a;
+  s->field5 = A_a;
+  s->field6 = A_a;
+  s->field7 = A_a;
+  s->field8 = A_a;
+  s->field9 = A_a;
+  s->field10 = (Derp)A_a;
+  s->field11 = (Derp)A_a;
+  s->field12 = (Derp)A_a;
+};
+
+void write_low_constant(S_B *s) {
+  using EnumType = B;
+  s->field1 = EnumType::a;
+  s->field2 = EnumType::a;
+  s->field3 = EnumType::a;
+  s->field4 = (unsigned)EnumType::a;
+  s->field5 = (unsigned)EnumType::a;
+  s->field6 = (unsigned)EnumType::a;
+  s->field7 = (int)EnumType::a;
+  s->field8 = (int)EnumType::a;
+  s->field9 = (int)EnumType::a;
+  s->field10 = (Derp)EnumType::a;
+  s->field11 = (Derp)EnumType::a;
+  s->field12 = (Derp)EnumType::a;
+};
+
+void write_low_constant(S_C *s) {
+  using EnumType = C;
+  s->field1 = EnumType::a;
+  s->field2 = EnumType::a;
+  s->field3 = EnumType::a;
+  s->field4 = (unsigned)EnumType::a;
+  s->field5 = (unsigned)EnumType::a;
+  s->field6 = (unsigned)EnumType::a;
+  s->field7 = (int)EnumType::a;
+  s->field8 = (int)EnumType::a;
+  s->field9 = (int)EnumType::a;
+  s->field10 = (Derp)EnumType::a;
+  s->field11 = (Derp)EnumType::a;
+  s->field12 = (Derp)EnumType::a;
+};
+
+void write_high_constant(S_A *s) {
+  s->field1 = A_d;
+  // expected-warning at -1 {{implicit truncation from 'A' to bit-field changes value from 3 to 1}}
+  s->field2 = A_d;
+  s->field3 = A_d;
+  s->field4 = A_d;
+  // expected-warning at -1 {{implicit truncation from 'A' to bit-field changes value from 3 to 1}}
+  s->field5 = A_d;
+  s->field6 = A_d;
+  s->field7 = A_d;
+  // expected-warning at -1 {{implicit truncation from 'A' to bit-field changes value from 3 to -1}}
+  s->field8 = A_d;
+  // expected-warning at -1 {{implicit truncation from 'A' to bit-field changes value from 3 to -1}}
+  s->field9 = A_d;
+  s->field10 = (Derp)A_d;
+  // expected-warning at -1 {{implicit truncation from 'Derp' to bit-field changes value from 3 to 1}}
+  s->field11 = (Derp)A_d;
+  s->field12 = (Derp)A_d;
+};
+
+void write_high_constant(S_B *s) {
+  using EnumType = B;
+  s->field1 = EnumType::d;
+  // expected-warning at -1 {{implicit truncation from 'B' to bit-field changes value from 3 to 1}}
+  s->field2 = EnumType::d;
+  s->field3 = EnumType::d;
+  s->field4 = (unsigned)EnumType::d;
+  // expected-warning at -1 {{implicit truncation from 'unsigned int' to bit-field changes value from 3 to 1}}
+  s->field5 = (unsigned)EnumType::d;
+  s->field6 = (unsigned)EnumType::d;
+  s->field7 = (int)EnumType::d;
+  // expected-warning at -1 {{implicit truncation from 'int' to bit-field changes value from 3 to -1}}
+  s->field8 = (int)EnumType::d;
+  // expected-warning at -1 {{implicit truncation from 'int' to bit-field changes value from 3 to -1}}
+  s->field9 = (int)EnumType::d;
+};
+
+
+void write_high_constant(S_C *s) {
+  using EnumType = C;
+  s->field1 = EnumType::d;
+  // expected-warning at -1 {{implicit truncation from 'C' to bit-field changes value from 3 to 1}}
+  s->field2 = EnumType::d;
+  s->field3 = EnumType::d;
+  s->field4 = (unsigned)EnumType::d;
+  // expected-warning at -1 {{implicit truncation from 'unsigned int' to bit-field changes value from 3 to 1}}
+  s->field5 = (unsigned)EnumType::d;
+  s->field6 = (unsigned)EnumType::d;
+  s->field7 = (int)EnumType::d;
+  // expected-warning at -1 {{implicit truncation from 'int' to bit-field changes value from 3 to -1}}
+  s->field8 = (int)EnumType::d;
+  // expected-warning at -1 {{implicit truncation from 'int' to bit-field changes value from 3 to -1}}
+  s->field9 = (int)EnumType::d;
+};

>From e9aa6125ee71927ac5a4c0a0524bc1194e7ceb4c Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Tue, 19 Nov 2024 13:14:40 +0100
Subject: [PATCH 2/3] Attempt to appease the windows bot

---
 clang/test/Sema/bitfield-preferred-type-sizing.c      | 2 +-
 clang/test/SemaCXX/bitfield-preferred-type-sizing.cpp | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/test/Sema/bitfield-preferred-type-sizing.c b/clang/test/Sema/bitfield-preferred-type-sizing.c
index 16d48bc0692dfa..a8d207d94a797a 100644
--- a/clang/test/Sema/bitfield-preferred-type-sizing.c
+++ b/clang/test/Sema/bitfield-preferred-type-sizing.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify -std=c11 -Wno-unused-value -Wno-unused-but-set-variable -Wbitfield-width -Wbitfield-enum-conversion
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -fsyntax-only -verify -std=c11 -Wno-unused-value -Wno-unused-but-set-variable -Wbitfield-width -Wbitfield-enum-conversion
 
 enum A {
   A_a,
diff --git a/clang/test/SemaCXX/bitfield-preferred-type-sizing.cpp b/clang/test/SemaCXX/bitfield-preferred-type-sizing.cpp
index 5e39d2ac2ba324..7dfbbdae031d12 100644
--- a/clang/test/SemaCXX/bitfield-preferred-type-sizing.cpp
+++ b/clang/test/SemaCXX/bitfield-preferred-type-sizing.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify -std=c++23 -Wno-unused-value -Wno-unused-but-set-variable -Wbitfield-width -Wbitfield-enum-conversion
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -fsyntax-only -verify -std=c++23 -Wno-unused-value -Wno-unused-but-set-variable -Wbitfield-width -Wbitfield-enum-conversion
 
 // This is more complex than the C version because the user can specify the
 // storage type 

>From 55e70a443b36f6bd6bd1389d4048fd8d500b404d Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Tue, 19 Nov 2024 14:53:04 +0100
Subject: [PATCH 3/3] Tidy up test cases

---
 .../Sema/bitfield-preferred-type-sizing.c     | 34 +++++++++----------
 1 file changed, 17 insertions(+), 17 deletions(-)

diff --git a/clang/test/Sema/bitfield-preferred-type-sizing.c b/clang/test/Sema/bitfield-preferred-type-sizing.c
index a8d207d94a797a..af04f431ba046e 100644
--- a/clang/test/Sema/bitfield-preferred-type-sizing.c
+++ b/clang/test/Sema/bitfield-preferred-type-sizing.c
@@ -8,19 +8,19 @@ enum A {
 };
 
 struct S {
-  enum A a1 : 1; // #1
+  enum A a1 : 1; // #S_a1_decl
   enum A a2 : 2;
   enum A a3 : 8;
-  __attribute__((preferred_type(enum A))) // #preferred_a4
-  unsigned a4 : 1; // #2
+  __attribute__((preferred_type(enum A))) // #preferred_S_a4
+  unsigned a4 : 1; // #S_a4_decl
   __attribute__((preferred_type(enum A)))
   unsigned a5 : 2;
   __attribute__((preferred_type(enum A)))
   unsigned a6 : 8;
-  __attribute__((preferred_type(enum A)))  // #preferred_a7
-  int a7 : 1; // #3
-  __attribute__((preferred_type(enum A))) // #preferred_a8
-  int a8 : 2; // #4
+  __attribute__((preferred_type(enum A)))  // #preferred_S_a7
+  int a7 : 1; // #S_a7_decl
+  __attribute__((preferred_type(enum A))) // #preferred_S_a8
+  int a8 : 2; // #S_a8_decl
   __attribute__((preferred_type(enum A)))
   int a9 : 8;
 };
@@ -41,20 +41,20 @@ void read_enum(struct S *s) {
 void write_enum(struct S *s, enum A x) {
   s->a1 = x;
   // expected-warning at -1 {{bit-field 'a1' is not wide enough to store all enumerators of 'A'}}
-  // expected-note@#1 {{widen this field to 2 bits to store all values of 'A'}}
+  // expected-note@#S_a1_decl {{widen this field to 2 bits to store all values of 'A'}}
   s->a2 = x;
   s->a3 = x;
   s->a4 = x;
   // expected-warning at -1 {{bit-field 'a4' is not wide enough to store all enumerators of 'A'}}
-  // expected-note@#2 {{widen this field to 2 bits to store all values of 'A'}}
+  // expected-note@#S_a4_decl {{widen this field to 2 bits to store all values of 'A'}}
   s->a5 = x;
   s->a6 = x;
   s->a7 = x;
   // expected-warning at -1 {{bit-field 'a7' is not wide enough to store all enumerators of 'A'}}
-  // expected-note@#3 {{widen this field to 2 bits to store all values of 'A'}}
+  // expected-note@#S_a7_decl {{widen this field to 2 bits to store all values of 'A'}}
   s->a8 = x;
   // expected-warning at -1 {{signed bit-field 'a8' needs an extra bit to represent the largest positive enumerators of 'A'}}
-  // expected-note@#4 {{consider making the bitfield type unsigned}}
+  // expected-note@#S_a8_decl {{consider making the bitfield type unsigned}}
   s->a9 = x;
 }
 
@@ -64,18 +64,18 @@ void write_enum_int(struct S *s, int x) {
   s->a3 = x;
   s->a4 = x;
   // expected-warning at -1 {{bit-field 'a4' is not wide enough to store all enumerators of preferred type 'A'}}
-  // expected-note@#2 {{widen this field to 2 bits to store all values of 'A'}}
-  // expected-note@#preferred_a4 {{preferred type for bitfield 'A' specified here}}
+  // expected-note@#S_a4_decl {{widen this field to 2 bits to store all values of 'A'}}
+  // expected-note@#preferred_S_a4 {{preferred type for bitfield 'A' specified here}}
   s->a5 = x;
   s->a6 = x;
   s->a7 = x;
   // expected-warning at -1 {{bit-field 'a7' is not wide enough to store all enumerators of preferred type 'A'}}
-  // expected-note@#3 {{widen this field to 2 bits to store all values of 'A'}}
-  // expected-note@#preferred_a7 {{preferred type for bitfield 'A' specified here}}
+  // expected-note@#S_a7_decl {{widen this field to 2 bits to store all values of 'A'}}
+  // expected-note@#preferred_S_a7 {{preferred type for bitfield 'A' specified here}}
   s->a8 = x;
   // expected-warning at -1 {{signed bit-field 'a8' needs an extra bit to represent the largest positive enumerators of preferred type 'A'}}
-  // expected-note@#4 {{consider making the bitfield type unsigned}}
-  // expected-note@#preferred_a8 {{preferred type for bitfield 'A' specified here}}
+  // expected-note@#S_a8_decl {{consider making the bitfield type unsigned}}
+  // expected-note@#preferred_S_a8 {{preferred type for bitfield 'A' specified here}}
   s->a9 = x;
 }
 



More information about the cfe-commits mailing list