mirror of
https://github.com/Gericom/teak-llvm.git
synced 2025-06-24 22:08:57 -04:00

This adds -Wbitfield-enum-conversion, which warns on implicit conversions that happen on bitfield assignment that change the value of some enumerators. Values of enum type typically take on a very small range of values, so they are frequently stored in bitfields. Unfortunately, there is no convenient way to calculate the minimum number of bits necessary to store all possible values at compile time, so users usually hard code a bitwidth that works today and widen it as necessary to pass basic testing and validation. This is very error-prone, and leads to stale widths as enums grow. This warning aims to catch such bugs. This would have found two real bugs in clang and two instances of questionable code. See r297680 and r297654 for the full description of the issues. This warning is currently disabled by default while we investigate its usefulness outside of LLVM. The major cause of false positives with this warning is this kind of enum: enum E { W, X, Y, Z, SENTINEL_LAST }; The last enumerator is an invalid value used to validate inputs or size an array. Depending on the prevalance of this style of enum across a codebase, this warning may be more or less feasible to deploy. It also has trouble on sentinel values such as ~0U. Reviewers: rsmith, rtrieu, thakis Reviewed By: thakis Subscribers: hfinkel, voskresensky.vladimir, sashab, cfe-commits Differential Revision: https://reviews.llvm.org/D30923 llvm-svn: 297761
60 lines
2.5 KiB
C++
60 lines
2.5 KiB
C++
// RUN: %clang_cc1 -std=c++11 -triple x86_64-windows-msvc -verify %s -Wbitfield-enum-conversion
|
|
// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux -verify %s -Wbitfield-enum-conversion
|
|
|
|
enum TwoBits { Hi1 = 3 } two_bits;
|
|
enum TwoBitsSigned { Lo2 = -2, Hi2 = 1 } two_bits_signed;
|
|
enum ThreeBits { Hi3 = 7 } three_bits;
|
|
enum ThreeBitsSigned { Lo4 = -4, Hi4 = 3 } three_bits_signed;
|
|
enum TwoBitsFixed : unsigned { Hi5 = 3 } two_bits_fixed;
|
|
|
|
struct Foo {
|
|
unsigned two_bits : 2; // expected-note 2 {{widen this field to 3 bits}} expected-note 2 {{type signed}}
|
|
int two_bits_signed : 2; // expected-note 2 {{widen this field to 3 bits}} expected-note 1 {{type unsigned}}
|
|
unsigned three_bits : 3; // expected-note 2 {{type signed}}
|
|
int three_bits_signed : 3; // expected-note 1 {{type unsigned}}
|
|
|
|
#ifdef _WIN32
|
|
// expected-note@+2 {{type unsigned}}
|
|
#endif
|
|
ThreeBits three_bits_enum : 3;
|
|
ThreeBits four_bits_enum : 4;
|
|
};
|
|
|
|
void f() {
|
|
Foo f;
|
|
|
|
f.two_bits = two_bits;
|
|
f.two_bits = two_bits_signed; // expected-warning {{negative enumerators}}
|
|
f.two_bits = three_bits; // expected-warning {{not wide enough}}
|
|
f.two_bits = three_bits_signed; // expected-warning {{negative enumerators}} expected-warning {{not wide enough}}
|
|
f.two_bits = two_bits_fixed;
|
|
|
|
f.two_bits_signed = two_bits; // expected-warning {{needs an extra bit}}
|
|
f.two_bits_signed = two_bits_signed;
|
|
f.two_bits_signed = three_bits; // expected-warning {{not wide enough}}
|
|
f.two_bits_signed = three_bits_signed; // expected-warning {{not wide enough}}
|
|
|
|
f.three_bits = two_bits;
|
|
f.three_bits = two_bits_signed; // expected-warning {{negative enumerators}}
|
|
f.three_bits = three_bits;
|
|
f.three_bits = three_bits_signed; // expected-warning {{negative enumerators}}
|
|
|
|
f.three_bits_signed = two_bits;
|
|
f.three_bits_signed = two_bits_signed;
|
|
f.three_bits_signed = three_bits; // expected-warning {{needs an extra bit}}
|
|
f.three_bits_signed = three_bits_signed;
|
|
|
|
#ifdef _WIN32
|
|
// Enums on Windows are always implicitly 'int', which is signed, so you need
|
|
// an extra bit to store values that set the MSB. This is not true on SysV
|
|
// platforms like Linux.
|
|
// expected-warning@+2 {{needs an extra bit}}
|
|
#endif
|
|
f.three_bits_enum = three_bits;
|
|
f.four_bits_enum = three_bits;
|
|
|
|
// Explicit casts suppress the warning.
|
|
f.two_bits = (unsigned)three_bits_signed;
|
|
f.two_bits = static_cast<unsigned>(three_bits_signed);
|
|
}
|