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 <oli...@apple.com> Date: Tue, 19 Nov 2024 11:55:11 +0100 Subject: [PATCH 1/6] [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@-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@-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@-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@-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@-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@-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@-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@-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@-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@-1 {{implicit truncation from 'int' to bit-field changes value from 3 to -1}} + s->a8 = A_d; + // expected-warning@-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@-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@-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@-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@-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@-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@-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@-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@-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@-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@-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@-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@-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@-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@-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@-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@-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@-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@-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@-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@-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@-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@-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@-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@-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@-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@-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@-1 {{implicit truncation from 'A' to bit-field changes value from 3 to -1}} + s->field8 = A_d; + // expected-warning@-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@-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@-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@-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@-1 {{implicit truncation from 'int' to bit-field changes value from 3 to -1}} + s->field8 = (int)EnumType::d; + // expected-warning@-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@-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@-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@-1 {{implicit truncation from 'int' to bit-field changes value from 3 to -1}} + s->field8 = (int)EnumType::d; + // expected-warning@-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 <oli...@apple.com> Date: Tue, 19 Nov 2024 13:14:40 +0100 Subject: [PATCH 2/6] 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 <oli...@apple.com> Date: Tue, 19 Nov 2024 14:53:04 +0100 Subject: [PATCH 3/6] 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@-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@-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@-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@-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@-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@-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@-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; } >From fe3d82439d427b818ebba6536054f08f2deac560 Mon Sep 17 00:00:00 2001 From: Oliver Hunt <oli...@apple.com> Date: Mon, 2 Dec 2024 12:55:01 -0800 Subject: [PATCH 4/6] Code style --- clang/lib/Sema/SemaChecking.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 5ead1b9242953c..e01994f7dc4543 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -10612,10 +10612,9 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, TSI ? TSI->getTypeLoc().getSourceRange() : SourceRange(); S.Diag(Bitfield->getTypeSpecStartLoc(), diag::note_change_bitfield_sign) << SignedEnum << TypeRange; - if (PTAttr) { + if (PTAttr) S.Diag(PTAttr->getLocation(), diag::note_bitfield_preferred_type) << ED; - } } // Compute the required bitwidth. If the enum has negative values, we need @@ -10632,10 +10631,9 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, << Bitfield << PreferredTypeDiagIndex << ED; S.Diag(WidthExpr->getExprLoc(), diag::note_widen_bitfield) << BitsNeeded << ED << WidthExpr->getSourceRange(); - if (PTAttr) { + if (PTAttr) S.Diag(PTAttr->getLocation(), diag::note_bitfield_preferred_type) << ED; - } } } >From 0cd5127f8e840de59dd5a02a01c10e168d7aaa1c Mon Sep 17 00:00:00 2001 From: Oliver Hunt <oli...@apple.com> Date: Mon, 30 Dec 2024 19:07:32 -0800 Subject: [PATCH 5/6] Redoing diagnostics to make this an error by default --- clang/include/clang/Basic/DiagnosticGroups.td | 6 +- .../clang/Basic/DiagnosticSemaKinds.td | 20 +++- clang/lib/Sema/SemaChecking.cpp | 21 +++- .../Sema/bitfield-preferred-type-sizing.c | 49 ++++---- .../bitfield-preferred-type-sizing.cpp | 109 +++++++++--------- 5 files changed, 117 insertions(+), 88 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 3ac490d30371b1..55e82c905e8437 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -49,6 +49,8 @@ def SingleBitBitFieldConstantConversion : DiagGroup<"single-bit-bitfield-constant-conversion">; def BitFieldConstantConversion : DiagGroup<"bitfield-constant-conversion", [SingleBitBitFieldConstantConversion]>; +def PreferredTypeBitFieldEnumConversion : DiagGroup<"preferred-type-bitfield-enum-conversion">; +def PreferredTypeBitFieldWidth : DiagGroup<"preferred-type-bitfield-width">; def BitFieldEnumConversion : DiagGroup<"bitfield-enum-conversion">; def BitFieldWidth : DiagGroup<"bitfield-width">; def CompoundTokenSplitByMacro : DiagGroup<"compound-token-split-by-macro">; @@ -1114,7 +1116,9 @@ def Most : DiagGroup<"most", [ PrivateExtern, SelTypeCast, ExternCCompat, - UserDefinedWarnings + UserDefinedWarnings, + PreferredTypeBitFieldEnumConversion, + PreferredTypeBitFieldWidth ]>; // Thread Safety warnings diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 6a97cc1ac15f58..8f5e4c3c7a65fd 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6423,24 +6423,34 @@ 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 %select{|preferred type }1%2">, + "bit-field %0 is not wide enough to store all enumerators of %1">, 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 %select{|preferred }1signed enum type %2 to unsigned bit-field %0; " + "assigning value of signed enum type %1 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 %select{|preferred type }1%2">, + "enumerators of %1">, InGroup<BitFieldEnumConversion>, DefaultIgnore; +def warn_preferred_type_bitfield_too_small_for_enum : Warning< + "bit-field %0 is not wide enough to store all enumerators of preferred type %1">, + InGroup<PreferredTypeBitFieldEnumConversion>, DefaultError; +def warn_preferred_type_unsigned_bitfield_assigned_signed_enum : Warning< + "assigning value of preferred signed enum type %1 to unsigned bit-field %0; " + "negative enumerators of enum %1 will be converted to positive values">, + InGroup<PreferredTypeBitFieldEnumConversion>, DefaultIgnore; +def warn_preferred_type_signed_bitfield_enum_conversion : Warning< + "signed bit-field %0 needs an extra bit to represent the largest positive " + "enumerators of preferred type %1">, + InGroup<PreferredTypeBitFieldEnumConversion>, DefaultError; def note_change_bitfield_sign : Note< "consider making the bit-field type %select{unsigned|signed}0">; def note_bitfield_preferred_type : Note< - "preferred type for bitfield %0 specified here" + "preferred type for bit-field %0 specified here" >; - "consider making the bit-field type %select{unsigned|signed}0">; 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 b74c51cca6cb61..2eabd14acc23ff 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -10608,14 +10608,20 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, // on Windows where unfixed enums always use an underlying type of 'int'. unsigned DiagID = 0; if (SignedEnum && !SignedBitfield) { - DiagID = diag::warn_unsigned_bitfield_assigned_signed_enum; + DiagID = + PTAttr == nullptr + ? diag::warn_unsigned_bitfield_assigned_signed_enum + : diag:: + warn_preferred_type_unsigned_bitfield_assigned_signed_enum; } else if (SignedBitfield && !SignedEnum && ED->getNumPositiveBits() == FieldWidth) { - DiagID = diag::warn_signed_bitfield_enum_conversion; + DiagID = + PTAttr == nullptr + ? diag::warn_signed_bitfield_enum_conversion + : diag::warn_preferred_type_signed_bitfield_enum_conversion; } - unsigned PreferredTypeDiagIndex = PTAttr != nullptr; if (DiagID) { - S.Diag(InitLoc, DiagID) << Bitfield << PreferredTypeDiagIndex << ED; + S.Diag(InitLoc, DiagID) << Bitfield << ED; TypeSourceInfo *TSI = Bitfield->getTypeSourceInfo(); SourceRange TypeRange = TSI ? TSI->getTypeLoc().getSourceRange() : SourceRange(); @@ -10636,8 +10642,11 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, // Check the bitwidth. if (BitsNeeded > FieldWidth) { Expr *WidthExpr = Bitfield->getBitWidth(); - S.Diag(InitLoc, diag::warn_bitfield_too_small_for_enum) - << Bitfield << PreferredTypeDiagIndex << ED; + auto DiagID = + PTAttr == nullptr + ? diag::warn_bitfield_too_small_for_enum + : diag::warn_preferred_type_bitfield_too_small_for_enum; + S.Diag(InitLoc, DiagID) << Bitfield << ED; S.Diag(WidthExpr->getExprLoc(), diag::note_widen_bitfield) << BitsNeeded << ED << WidthExpr->getSourceRange(); if (PTAttr) diff --git a/clang/test/Sema/bitfield-preferred-type-sizing.c b/clang/test/Sema/bitfield-preferred-type-sizing.c index af04f431ba046e..ab8c98dc354006 100644 --- a/clang/test/Sema/bitfield-preferred-type-sizing.c +++ b/clang/test/Sema/bitfield-preferred-type-sizing.c @@ -1,4 +1,6 @@ -// 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 +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -fsyntax-only -verify=expected,preferrednotes -std=c11 -Wno-unused-value -Wno-unused-but-set-variable +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -fsyntax-only -verify=expected,bitfieldwarning,preferrednotes -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=noerror,preferrednotes -std=c11 -Wno-unused-value -Wno-unused-but-set-variable -Wno-error=preferred-type-bitfield-enum-conversion -Wno-error=preferred-type-bitfield-width enum A { A_a, @@ -40,21 +42,21 @@ void read_enum(struct S *s) { void write_enum(struct S *s, enum A x) { s->a1 = x; - // expected-warning@-1 {{bit-field 'a1' is not wide enough to store all enumerators of 'A'}} - // expected-note@#S_a1_decl {{widen this field to 2 bits to store all values of 'A'}} + // bitfieldwarning-warning@-1 {{bit-field 'a1' is not wide enough to store all enumerators of 'A'}} + // bitfieldwarning-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@-1 {{bit-field 'a4' is not wide enough to store all enumerators of 'A'}} - // expected-note@#S_a4_decl {{widen this field to 2 bits to store all values of 'A'}} + // bitfieldwarning-warning@-1 {{bit-field 'a4' is not wide enough to store all enumerators of 'A'}} + // bitfieldwarning-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@-1 {{bit-field 'a7' is not wide enough to store all enumerators of 'A'}} - // expected-note@#S_a7_decl {{widen this field to 2 bits to store all values of 'A'}} + // bitfieldwarning-warning@-1 {{bit-field 'a7' is not wide enough to store all enumerators of 'A'}} + // bitfieldwarning-note@#S_a7_decl {{widen this field to 2 bits to store all values of 'A'}} s->a8 = x; - // expected-warning@-1 {{signed bit-field 'a8' needs an extra bit to represent the largest positive enumerators of 'A'}} - // expected-note@#S_a8_decl {{consider making the bitfield type unsigned}} + // bitfieldwarning-warning@-1 {{signed bit-field 'a8' needs an extra bit to represent the largest positive enumerators of 'A'}} + // bitfieldwarning-note@#S_a8_decl {{consider making the bit-field type unsigned}} s->a9 = x; } @@ -63,19 +65,22 @@ void write_enum_int(struct S *s, int x) { s->a2 = x; s->a3 = x; s->a4 = x; - // expected-warning@-1 {{bit-field 'a4' is not wide enough to store all enumerators of preferred type 'A'}} - // 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}} + // expected-error@-1 {{bit-field 'a4' is not wide enough to store all enumerators of preferred type 'A'}} + // noerror-warning@-2 {{bit-field 'a4' is not wide enough to store all enumerators of preferred type 'A'}} + // preferrednotes-note@#S_a4_decl {{widen this field to 2 bits to store all values of 'A'}} + // preferrednotes-note@#preferred_S_a4 {{preferred type for bit-field 'A' specified here}} s->a5 = x; s->a6 = x; s->a7 = x; - // expected-warning@-1 {{bit-field 'a7' is not wide enough to store all enumerators of preferred type 'A'}} - // 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}} + // expected-error@-1 {{bit-field 'a7' is not wide enough to store all enumerators of preferred type 'A'}} + // noerror-warning@-2 {{bit-field 'a7' is not wide enough to store all enumerators of preferred type 'A'}} + // preferrednotes-note@#S_a7_decl {{widen this field to 2 bits to store all values of 'A'}} + // preferrednotes-note@#preferred_S_a7 {{preferred type for bit-field 'A' specified here}} s->a8 = x; - // expected-warning@-1 {{signed bit-field 'a8' needs an extra bit to represent the largest positive enumerators of preferred type 'A'}} - // expected-note@#S_a8_decl {{consider making the bitfield type unsigned}} - // expected-note@#preferred_S_a8 {{preferred type for bitfield 'A' specified here}} + // expected-error@-1 {{signed bit-field 'a8' needs an extra bit to represent the largest positive enumerators of preferred type 'A'}} + // noerror-warning@-2 {{signed bit-field 'a8' needs an extra bit to represent the largest positive enumerators of preferred type 'A'}} + // preferrednotes-note@#S_a8_decl {{consider making the bit-field type unsigned}} + // preferrednotes-note@#preferred_S_a8 {{preferred type for bit-field 'A' specified here}} s->a9 = x; } @@ -93,16 +98,16 @@ void write_low_constant(struct S *s) { void write_high_constant(struct S *s) { s->a1 = A_d; - // expected-warning@-1 {{implicit truncation from 'int' to bit-field changes value from 3 to 1}} + // preferrednotes-warning@-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@-1 {{implicit truncation from 'int' to bit-field changes value from 3 to 1}} + // preferrednotes-warning@-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@-1 {{implicit truncation from 'int' to bit-field changes value from 3 to -1}} + // preferrednotes-warning@-1 {{implicit truncation from 'int' to bit-field changes value from 3 to -1}} s->a8 = A_d; - // expected-warning@-1 {{implicit truncation from 'int' to bit-field changes value from 3 to -1}} + // preferrednotes-warning@-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 index 7dfbbdae031d12..442463c5f23b82 100644 --- a/clang/test/SemaCXX/bitfield-preferred-type-sizing.cpp +++ b/clang/test/SemaCXX/bitfield-preferred-type-sizing.cpp @@ -1,4 +1,5 @@ -// 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 +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -fsyntax-only -verify -std=c++23 -Wno-unused-value -Wno-unused-but-set-variable +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -fsyntax-only -verify=expected,bitfieldwarnings -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 @@ -157,21 +158,21 @@ void read_enum(S_C *s) { void write_enum(S_A *s, A x) { s->field1 = x; - // expected-warning@-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'}} + // bitfieldwarnings-warning@-1 {{bit-field 'field1' is not wide enough to store all enumerators of 'A'}} + // bitfieldwarnings-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@-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'}} + // bitfieldwarnings-warning@-1 {{bit-field 'field4' is not wide enough to store all enumerators of 'A'}} + // bitfieldwarnings-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@-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'}} + // bitfieldwarnings-warning@-1 {{bit-field 'field7' is not wide enough to store all enumerators of 'A'}} + // bitfieldwarnings-note@#S_A_field7 {{widen this field to 2 bits to store all values of 'A'}} s->field8 = x; - // expected-warning@-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}} + // bitfieldwarnings-warning@-1 {{signed bit-field 'field8' needs an extra bit to represent the largest positive enumerators of 'A'}} + // bitfieldwarnings-note@#S_A_field8 {{consider making the bit-field type unsigned}} s->field9 = x; s->field10 = (Derp)x; s->field11 = (Derp)x; @@ -180,24 +181,24 @@ void write_enum(S_A *s, A x) { void write_enum(S_B *s, B x) { s->field1 = x; - // expected-warning@-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'}} + // bitfieldwarnings-warning@-1 {{bit-field 'field1' is not wide enough to store all enumerators of 'B'}} + // bitfieldwarnings-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@-1 {{bit-field 'field4' is not wide enough to store all enumerators of preferred type 'B'}} + // expected-error@-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}} + // expected-note@#preferred_S_B_field4 {{preferred type for bit-field 'B' specified here}} s->field5 = (unsigned)x; s->field6 = (unsigned)x; s->field7 = (int)x; - // expected-warning@-1 {{bit-field 'field7' is not wide enough to store all enumerators of preferred type 'B'}} + // expected-error@-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}} + // expected-note@#preferred_S_B_field7 {{preferred type for bit-field 'B' specified here}} s->field8 = (int)x; - // expected-warning@-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}} + // expected-error@-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 bit-field type unsigned}} + // expected-note@#preferred_S_B_field8 {{preferred type for bit-field 'B' specified here}} s->field9 = (int)x; s->field10 = (Derp)x; s->field11 = (Derp)x; @@ -205,24 +206,24 @@ void write_enum(S_B *s, B x) { } void write_enum(S_C *s, C x) { s->field1 = x; - // expected-warning@-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'}} + // bitfieldwarnings-warning@-1 {{bit-field 'field1' is not wide enough to store all enumerators of 'C'}} + // bitfieldwarnings-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@-1 {{bit-field 'field4' is not wide enough to store all enumerators of preferred type 'C'}} + // expected-error@-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}} + // expected-note@#preferred_S_C_field4 {{preferred type for bit-field 'C' specified here}} s->field5 = (unsigned)x; s->field6 = (unsigned)x; s->field7 = (int)x; - // expected-warning@-1 {{bit-field 'field7' is not wide enough to store all enumerators of preferred type 'C'}} + // expected-error@-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}} + // expected-note@#preferred_S_C_field7 {{preferred type for bit-field 'C' specified here}} s->field8 = (int)x; - // expected-warning@-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}} + // expected-error@-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 bit-field type unsigned}} + // expected-note@#preferred_S_C_field8 {{preferred type for bit-field 'C' specified here}} s->field9 = (int)x; s->field10 = (Derp)x; s->field11 = (Derp)x; @@ -232,24 +233,24 @@ void write_enum(S_C *s, C x) { void write_enum_int(struct S_A *s, int x) { using EnumType = A; s->field1 = (EnumType)x; - // expected-warning@-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'}} + // bitfieldwarnings-warning@-1 {{bit-field 'field1' is not wide enough to store all enumerators of 'A'}} + // bitfieldwarnings-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@-1 {{bit-field 'field4' is not wide enough to store all enumerators of preferred type 'A'}} + // expected-error@-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}} + // expected-note@#preferred_S_A_field4 {{preferred type for bit-field 'A' specified here}} s->field5 = x; s->field6 = x; s->field7 = x; - // expected-warning@-1 {{bit-field 'field7' is not wide enough to store all enumerators of preferred type 'A'}} + // expected-error@-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}} + // expected-note@#preferred_S_A_field7 {{preferred type for bit-field 'A' specified here}} s->field8 = x; - // expected-warning@-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}} + // expected-error@-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 bit-field type unsigned}} + // expected-note@#preferred_S_A_field8 {{preferred type for bit-field 'A' specified here}} s->field9 = x; s->field10 = (Derp)x; s->field11 = (Derp)x; @@ -259,24 +260,24 @@ void write_enum_int(struct S_A *s, int x) { void write_enum_int(struct S_B *s, int x) { using EnumType = B; s->field1 = (EnumType)x; - // expected-warning@-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'}} + // bitfieldwarnings-warning@-1 {{bit-field 'field1' is not wide enough to store all enumerators of 'B'}} + // bitfieldwarnings-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@-1 {{bit-field 'field4' is not wide enough to store all enumerators of preferred type 'B'}} + // expected-error@-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}} + // expected-note@#preferred_S_B_field4 {{preferred type for bit-field 'B' specified here}} s->field5 = x; s->field6 = x; s->field7 = x; - // expected-warning@-1 {{bit-field 'field7' is not wide enough to store all enumerators of preferred type 'B'}} + // expected-error@-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}} + // expected-note@#preferred_S_B_field7 {{preferred type for bit-field 'B' specified here}} s->field8 = x; - // expected-warning@-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}} + // expected-error@-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 bit-field type unsigned}} + // expected-note@#preferred_S_B_field8 {{preferred type for bit-field 'B' specified here}} s->field9 = x; s->field10 = (Derp)x; s->field11 = (Derp)x; @@ -286,24 +287,24 @@ void write_enum_int(struct S_B *s, int x) { void write_enum_int(struct S_C *s, int x) { using EnumType = C; s->field1 = (EnumType)x; - // expected-warning@-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'}} + // bitfieldwarnings-warning@-1 {{bit-field 'field1' is not wide enough to store all enumerators of 'C'}} + // bitfieldwarnings-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@-1 {{bit-field 'field4' is not wide enough to store all enumerators of preferred type 'C'}} + // expected-error@-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}} + // expected-note@#preferred_S_C_field4 {{preferred type for bit-field 'C' specified here}} s->field5 = x; s->field6 = x; s->field7 = x; - // expected-warning@-1 {{bit-field 'field7' is not wide enough to store all enumerators of preferred type 'C'}} + // expected-error@-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}} + // expected-note@#preferred_S_C_field7 {{preferred type for bit-field 'C' specified here}} s->field8 = x; - // expected-warning@-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}} + // expected-error@-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 bit-field type unsigned}} + // expected-note@#preferred_S_C_field8 {{preferred type for bit-field 'C' specified here}} s->field9 = x; s->field10 = (Derp)x; s->field11 = (Derp)x; >From cbb6a203a17fb497c485587a7ac6006f81c2694a Mon Sep 17 00:00:00 2001 From: Oliver Hunt <oli...@apple.com> Date: Sat, 4 Jan 2025 10:22:29 -0800 Subject: [PATCH 6/6] Sigh, i realised this change was not necessary but had not added it to the commit --- clang/include/clang/Basic/DiagnosticGroups.td | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 55e82c905e8437..318f2df11ca082 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -1116,9 +1116,7 @@ def Most : DiagGroup<"most", [ PrivateExtern, SelTypeCast, ExternCCompat, - UserDefinedWarnings, - PreferredTypeBitFieldEnumConversion, - PreferredTypeBitFieldWidth + UserDefinedWarnings ]>; // Thread Safety warnings _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits