Skip to content

Commit 16fd406

Browse files
chqrliebvdberg
authored andcommitted
Analyser: use precise enum bit width for bitfield width validation
* add `precise` argument to `QualType.getBitFieldWidth` * accept bitfield widths smaller than enum implementation type but sufficiently large for akk enum values
1 parent 2a31629 commit 16fd406

File tree

3 files changed

+30
-13
lines changed

3 files changed

+30
-13
lines changed

analyser/module_analyser_struct.c2

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,15 @@ fn void Analyser.analyseStructMembers(Analyser* ma, StructTypeDecl* d) {
104104
u32 field_width = value.as_u32();
105105
vd.setBitfieldWidth((u8)field_width);
106106

107-
if (qt.isEnum() && field_width < type_width) {
108-
if (name)
109-
ma.errorRange(bitfield.getLoc(), bitfield.getRange(), "bit-field '%s' has insufficient bits for enum '%s'", name, qt.diagName());
110-
else
111-
ma.errorRange(bitfield.getLoc(), bitfield.getRange(), "unnamed bit-field has insufficient bits for enum '%s'", qt.diagName());
107+
u32 minimum_type_width = qt.getBitFieldWidth(true);
108+
if (qt.isEnum() && field_width < minimum_type_width) {
109+
if (name) {
110+
ma.errorRange(bitfield.getLoc(), bitfield.getRange(), "bit-field '%s' has insufficient bits for enum '%s' (need %d bits)",
111+
name, qt.diagName(), minimum_type_width);
112+
} else {
113+
ma.errorRange(bitfield.getLoc(), bitfield.getRange(), "unnamed bit-field has insufficient bits for enum '%s' (need %d bits)",
114+
qt.diagName(), minimum_type_width);
115+
}
112116
return;
113117
}
114118

ast/qualtype.c2

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,18 +88,29 @@ public fn bool QualType.isValid(const QualType qt) { return qt.ptr != 0; }
8888
public fn bool QualType.isInvalid(const QualType qt) { return qt.ptr == 0; }
8989

9090
// Note: assumes type is valid
91-
public fn u32 QualType.getBitFieldWidth(const QualType qt) {
91+
public fn u32 QualType.getBitFieldWidth(const QualType qt, bool precise = false) {
9292
QualType canon = qt.getCanonicalType();
9393
const Type* t = canon.getTypeOrNil();
9494
if (t.isBuiltinType()) {
9595
BuiltinType* bi = (BuiltinType*)t;
9696
return bi.getWidth();
9797
}
9898
if (t.isEnumType()) {
99-
// TODO return bits needed for max value to allow use in bitfields
100-
EnumType* et = (EnumType*)t;
101-
QualType impl = et.getImplType();
102-
return impl.getBitFieldWidth();
99+
EnumTypeDecl* d = ((EnumType*)t).getDecl();
100+
if (d.isRegular() && precise) {
101+
u32 n = d.getNumConstants() - 1;
102+
u32 bits = 1;
103+
for (u32 i = 16; i != 0; i >>= 1) {
104+
if (u32 m = n >> i) {
105+
n = m;
106+
bits += i;
107+
}
108+
}
109+
return bits;
110+
}
111+
// TODO handle non regular enums and signed implementation types
112+
QualType impl = d.getImplType();
113+
return impl.getBitFieldWidth(precise);
103114
}
104115
return 0;
105116
}
Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
// @warnings{no-unused}
22
module test;
33

4-
type B enum u8 { AA, BB }
4+
type B enum u8 { AA, BB, CC, DD }
55

66
type A struct {
7-
B a : 8;
8-
B b : 7; // @error{bit-field 'b' has insufficient bits for enum 'test.B'}
7+
B a8 : 8;
8+
B a3 : 3;
9+
B a2 : 2;
10+
B b : 1; // @error{bit-field 'b' has insufficient bits for enum 'test.B' (need 2 bits)}
911
}
1012

0 commit comments

Comments
 (0)