diff --git a/src/aro/Diagnostics/messages.def b/src/aro/Diagnostics/messages.def index 89faf02e..5d242d32 100644 --- a/src/aro/Diagnostics/messages.def +++ b/src/aro/Diagnostics/messages.def @@ -2482,3 +2482,8 @@ attribute_todo .msg = "TODO: implement '{s}' attribute for {s}" .extra = .attribute_todo .kind = .@"error" + +invalid_type_underlying_enum + .msg = "non-integral type '{s}' is an invalid underlying type" + .extra = .str + .kind = .@"error" diff --git a/src/aro/Parser.zig b/src/aro/Parser.zig index c395ee2a..ef39f075 100644 --- a/src/aro/Parser.zig +++ b/src/aro/Parser.zig @@ -2478,7 +2478,8 @@ fn enumSpec(p: *Parser) Error!Type { const maybe_ident = try p.eatIdentifier(); const fixed_ty = if (p.eatToken(.colon)) |colon| fixed: { - const fixed = (try p.typeName()) orelse { + const ty_start = p.tok_i; + const fixed = (try p.specQual()) orelse { if (p.record.kind != .invalid) { // This is a bit field. p.tok_i -= 1; @@ -2488,6 +2489,12 @@ fn enumSpec(p: *Parser) Error!Type { try p.errTok(.enum_fixed, colon); break :fixed null; }; + + if (!fixed.isInt() or fixed.is(.@"enum")) { + try p.errStr(.invalid_type_underlying_enum, ty_start, try p.typeStr(fixed)); + break :fixed Type.int; + } + try p.errTok(.enum_fixed, colon); break :fixed fixed; } else null; diff --git a/test/cases/enum fixed.c b/test/cases/enum fixed.c index 5c9dd94e..6fa58d4e 100644 --- a/test/cases/enum fixed.c +++ b/test/cases/enum fixed.c @@ -71,6 +71,34 @@ void pointers(void) { enum Incomplete *i2 = &y; } +typedef struct BackingStruct { + int x; +} BackingStruct; + +typedef enum BackingEnum : int { + B0, +} BackingEnum; + +enum Bad1: BackingStruct { + B1, +}; + +enum Bad2: BackingEnum { + B2, +}; + +enum Bad3: unsigned * { + B3, +}; + +void more_pointers(void) { + unsigned y; + + enum SignedEnum: int *p = &y; + enum UnsignedEnum: unsigned *p2 = &y; + enum CharEnum: char signed *p3 = &y; +} + #define EXPECTED_ERRORS "enum fixed.c:2:7: warning: enumeration types with a fixed underlying type are a Clang extension [-Wfixed-enum-extension]" \ "enum fixed.c:4:6: error: enumeration previously declared with fixed underlying type" \ "enum fixed.c:2:6: note: previous definition is here" \ @@ -84,4 +112,9 @@ void pointers(void) { "enum fixed.c:67:25: warning: incompatible pointer types initializing 'enum Unsigned: unsigned int *' from incompatible type 'int *' [-Wincompatible-pointer-types]" \ "enum fixed.c:70:27: warning: incompatible pointer types initializing 'enum Incomplete *' from incompatible type 'int *' [-Wincompatible-pointer-types]" \ "enum fixed.c:71:27: warning: incompatible pointer types initializing 'enum Incomplete *' from incompatible type 'unsigned int *' [-Wincompatible-pointer-types]" \ + "enum fixed.c:82:12: error: non-integral type 'struct BackingStruct' is an invalid underlying type" \ + "enum fixed.c:86:12: error: non-integral type 'enum BackingEnum: int' is an invalid underlying type" \ + "enum fixed.c:90:23: error: expected identifier or '('" \ + "enum fixed.c:97:31: warning: incompatible pointer types initializing 'enum SignedEnum: int *' from incompatible type 'unsigned int *' converts between pointers to integer types with different sign [-Wpointer-sign]" \ + "enum fixed.c:99:38: warning: incompatible pointer types initializing 'enum CharEnum: signed char *' from incompatible type 'unsigned int *' [-Wincompatible-pointer-types]" \