Skip to content

Commit

Permalink
Fix assertions and bad warnings on extremely wide bit-fields.
Browse files Browse the repository at this point in the history
We used to produce a bogus warning if the width couldn't be represented
in 32 bits, and assert if it couldn't be represented in 64 bits.
  • Loading branch information
zygoloid committed Nov 17, 2020
1 parent a72f11e commit 8e923ec
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 13 deletions.
5 changes: 2 additions & 3 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Expand Up @@ -5649,9 +5649,8 @@ def err_incorrect_number_of_vector_initializers : Error<
def warn_bitfield_width_exceeds_type_width: Warning<
"width of bit-field %0 (%1 bits) exceeds the width of its type; value will "
"be truncated to %2 bit%s2">, InGroup<BitFieldWidth>;
def warn_anon_bitfield_width_exceeds_type_width : Warning<
"width of anonymous bit-field (%0 bits) exceeds width of its type; value "
"will be truncated to %1 bit%s1">, InGroup<BitFieldWidth>;
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">,
InGroup<BitFieldEnumConversion>, DefaultIgnore;
Expand Down
23 changes: 13 additions & 10 deletions clang/lib/Sema/SemaDecl.cpp
Expand Up @@ -16432,6 +16432,13 @@ ExprResult Sema::VerifyBitField(SourceLocation FieldLoc,
<< Value.toString(10);
}

// The size of the bit-field must not exceed our maximum permitted object
// size.
if (Value.getActiveBits() > ConstantArrayType::getMaxSizeBits(Context)) {
return Diag(FieldLoc, diag::err_bitfield_too_wide)
<< !FieldName << FieldName << Value.toString(10);
}

if (!FieldTy->isDependentType()) {
uint64_t TypeStorageSize = Context.getTypeSize(FieldTy);
uint64_t TypeWidth = Context.getIntWidth(FieldTy);
Expand All @@ -16449,25 +16456,21 @@ ExprResult Sema::VerifyBitField(SourceLocation FieldLoc,
CStdConstraintViolation ? TypeWidth : TypeStorageSize;
if (FieldName)
return Diag(FieldLoc, diag::err_bitfield_width_exceeds_type_width)
<< FieldName << (unsigned)Value.getZExtValue()
<< FieldName << Value.toString(10)
<< !CStdConstraintViolation << DiagWidth;

return Diag(FieldLoc, diag::err_anon_bitfield_width_exceeds_type_width)
<< (unsigned)Value.getZExtValue() << !CStdConstraintViolation
<< Value.toString(10) << !CStdConstraintViolation
<< DiagWidth;
}

// Warn on types where the user might conceivably expect to get all
// specified bits as value bits: that's all integral types other than
// 'bool'.
if (BitfieldIsOverwide && !FieldTy->isBooleanType()) {
if (FieldName)
Diag(FieldLoc, diag::warn_bitfield_width_exceeds_type_width)
<< FieldName << (unsigned)Value.getZExtValue()
<< (unsigned)TypeWidth;
else
Diag(FieldLoc, diag::warn_anon_bitfield_width_exceeds_type_width)
<< (unsigned)Value.getZExtValue() << (unsigned)TypeWidth;
if (BitfieldIsOverwide && !FieldTy->isBooleanType() && FieldName) {
Diag(FieldLoc, diag::warn_bitfield_width_exceeds_type_width)
<< FieldName << Value.toString(10)
<< (unsigned)TypeWidth;
}
}

Expand Down
19 changes: 19 additions & 0 deletions clang/test/SemaCXX/bitfield-layout.cpp
Expand Up @@ -10,6 +10,12 @@ struct Test1 {
CHECK_SIZE(Test1, 2);
CHECK_ALIGN(Test1, 1);

struct Test1a {
char : 9; // no warning (there's no value to truncate here)
};
CHECK_SIZE(Test1a, 2);
CHECK_ALIGN(Test1a, 1);

struct Test2 {
char c : 16; // expected-warning {{width of bit-field 'c' (16 bits) exceeds the width of its type; value will be truncated to 8 bits}}
};
Expand All @@ -28,3 +34,16 @@ struct Test4 {
CHECK_SIZE(Test4, 8);
CHECK_ALIGN(Test4, 8);

struct Test5 {
char c : 0x100000001; // expected-warning {{width of bit-field 'c' (4294967297 bits) exceeds the width of its type; value will be truncated to 8 bits}}
};
// Size and align don't really matter here, just make sure we don't crash.
CHECK_SIZE(Test5, 1);
CHECK_ALIGN(Test5, 1);

struct Test6 {
char c : (unsigned __int128)0xffffffffffffffff + 2; // expected-error {{bit-field 'c' is too wide (18446744073709551617 bits)}}
};
// Size and align don't really matter here, just make sure we don't crash.
CHECK_SIZE(Test6, 1);
CHECK_ALIGN(Test6, 1);

0 comments on commit 8e923ec

Please sign in to comment.