Allow char bit-fields

These are not required to be supported (only int, signed int, and
unsigned int are required), but most compilers support it.

https://port70.net/~nsz/c/c89/c89-draft.html#3.5.2.1
https://port70.net/~nsz/c/c89/c89-draft.html#A.6.5.8

For consistency with other integral types, plain `char` bit-fields
are unsigned, regardless of the `--signed-chars` option.

Fixes #1047
This commit is contained in:
Jesse Rosenstock
2020-08-30 20:47:25 +02:00
committed by Oliver Schmidt
parent 41cee0eb44
commit 4e4e4c2d21
6 changed files with 401 additions and 5 deletions

View File

@@ -764,9 +764,9 @@ static int ParseFieldWidth (Declaration* Decl)
/* TODO: This can be relaxed to be any integral type, but
** ParseStructInit currently only supports up to int.
*/
if (SizeOf (Decl->Type) != SizeOf (type_uint)) {
/* Only int sized types may be used for bit-fields for now */
Error ("cc65 currently only supports unsigned int bit-fields");
if (SizeOf (Decl->Type) > SizeOf (type_uint)) {
/* Only int-sized or smaller types may be used for bit-fields for now */
Error ("cc65 currently only supports char-sized and int-sized bit-fields");
return -1;
}

View File

@@ -870,9 +870,13 @@ SymEntry* AddBitField (const char* Name, const Type* T, unsigned Offs,
if (!SignednessSpecified) {
/* int is treated as signed int everywhere except bit-fields; switch it to unsigned,
** since this is allowed for bit-fields and avoids sign-extension, so is much faster.
** enums set SignednessSpecified to 1 to avoid this adjustment.
** enums set SignednessSpecified to 1 to avoid this adjustment. Character types
** actually distinguish 3 types of char; char may either be signed or unsigned, which
** is controlled by `--signed-chars`. In bit-fields, however, we perform the same
** `char -> unsigned char` adjustment that is performed with other integral types.
*/
CHECK ((Entry->Type->C & T_MASK_SIGN) == T_SIGN_SIGNED);
CHECK ((Entry->Type->C & T_MASK_SIGN) == T_SIGN_SIGNED ||
IsTypeChar (Entry->Type));
Entry->Type->C &= ~T_MASK_SIGN;
Entry->Type->C |= T_SIGN_UNSIGNED;
}