the check on incomplete struct/union/enum types was too early, disallowing mixed specifiers and qualifiers. Simply rely on the size (->c) field for that. See testcases.
Unified · Split
| @@ -2200,7 +2200,7 @@ ST_FUNC int type_size(CType *type, int *a) · 2199 unmodified lines | |||
| 2200 | *a = 8; | 2200 | *a = 8; |
| 2201 | #endif | 2201 | #endif |
| 2202 | return 8; | 2202 | return 8; |
| 2203 | } else if (bt == VT_INT || bt == VT_ENUM || bt == VT_FLOAT) { | 2203 | } else if (bt == VT_INT || bt == VT_FLOAT) { |
| 2204 | *a = 4; | 2204 | *a = 4; |
| 2205 | return 4; | 2205 | return 4; |
| 2206 | } else if (bt == VT_SHORT) { | 2206 | } else if (bt == VT_SHORT) { |
| @@ -2209,6 +2209,10 @@ ST_FUNC int type_size(CType *type, int *a) · 2 unmodified lines | |||
| 2209 | } else if (bt == VT_QLONG || bt == VT_QFLOAT) { | 2209 | } else if (bt == VT_QLONG || bt == VT_QFLOAT) { |
| 2210 | *a = 8; | 2210 | *a = 8; |
| 2211 | return 16; | 2211 | return 16; |
| 2212 | } else if (bt == VT_ENUM) { | ||
| 2213 | *a = 4; | ||
| 2214 | /* Enums might be incomplete, so don't just return '4' here. */ | ||
| 2215 | return type->ref->c; | ||
| 2212 | } else { | 2216 | } else { |
| 2213 | /* char, void, function, _Bool */ | 2217 | /* char, void, function, _Bool */ |
| 2214 | *a = 1; | 2218 | *a = 1; |
| @@ -2902,7 +2906,7 @@ static void parse_attribute(AttributeDef *ad) · 687 unmodified lines | |||
| 2902 | } | 2906 | } |
| 2903 | 2907 | ||
| 2904 | /* enum/struct/union declaration. u is either VT_ENUM or VT_STRUCT */ | 2908 | /* enum/struct/union declaration. u is either VT_ENUM or VT_STRUCT */ |
| 2905 | static void struct_decl(CType *type, int u, int tdef) | 2909 | static void struct_decl(CType *type, int u) |
| 2906 | { | 2910 | { |
| 2907 | int a, v, size, align, maxalign, c, offset, flexible; | 2911 | int a, v, size, align, maxalign, c, offset, flexible; |
| 2908 | int bit_size, bit_pos, bsize, bt, lbit_pos, prevbt; | 2912 | int bit_size, bit_pos, bsize, bt, lbit_pos, prevbt; |
| @@ -2923,8 +2927,7 @@ static void struct_decl(CType *type, int u, int tdef) · 14 unmodified lines | |||
| 2923 | if (s->type.t != a) | 2927 | if (s->type.t != a) |
| 2924 | tcc_error("invalid type"); | 2928 | tcc_error("invalid type"); |
| 2925 | goto do_decl; | 2929 | goto do_decl; |
| 2926 | } else if (tok >= TOK_IDENT && !tdef) | 2930 | } |
| 2927 | tcc_error("unknown struct/union/enum"); | ||
| 2928 | } else { | 2931 | } else { |
| 2929 | v = anon_sym++; | 2932 | v = anon_sym++; |
| 2930 | } | 2933 | } |
| @@ -3229,14 +3232,14 @@ static int parse_btype(CType *type, AttributeDef *ad) · 298 unmodified lines | |||
| 3229 | } | 3232 | } |
| 3230 | break; | 3233 | break; |
| 3231 | case TOK_ENUM: | 3234 | case TOK_ENUM: |
| 3232 | struct_decl(&type1, VT_ENUM, t & (VT_TYPEDEF | VT_EXTERN)); | 3235 | struct_decl(&type1, VT_ENUM); |
| 3233 | basic_type2: | 3236 | basic_type2: |
| 3234 | u = type1.t; | 3237 | u = type1.t; |
| 3235 | type->ref = type1.ref; | 3238 | type->ref = type1.ref; |
| 3236 | goto basic_type1; | 3239 | goto basic_type1; |
| 3237 | case TOK_STRUCT: | 3240 | case TOK_STRUCT: |
| 3238 | case TOK_UNION: | 3241 | case TOK_UNION: |
| 3239 | struct_decl(&type1, VT_STRUCT, t & (VT_TYPEDEF | VT_EXTERN)); | 3242 | struct_decl(&type1, VT_STRUCT); |
| 3240 | goto basic_type2; | 3243 | goto basic_type2; |
| 3241 | 3244 | ||
| 3242 | /* type modifiers */ | 3245 | /* type modifiers */ |
| @@ -1 +1 @@ | |||
| 1 | 61_undefined_enum.c:1: error: unknown struct/union/enum | 1 | 61_undefined_enum.c:1: error: unknown type size |
| @@ -0,0 +1,9 @@ | |||
| 1 | /* The following are all valid decls, even though some subtypes | ||
| 2 | are incomplete. */ | ||
| 3 | enum E *e; | ||
| 4 | const enum E *e1; | ||
| 5 | enum E const *e2; | ||
| 6 | struct S *s; | ||
| 7 | const struct S *s1; | ||
| 8 | struct S const *s2; | ||
| 9 | int main () { return 0; } | ||
Empty file added.