diff --git a/src/cc65/assignment.c b/src/cc65/assignment.c index 549e18e95..ab501523d 100644 --- a/src/cc65/assignment.c +++ b/src/cc65/assignment.c @@ -315,19 +315,37 @@ static void OpAssignBitField (const GenDesc* Gen, ExprDesc* Expr, const char* Op } else if (Gen->Func == g_sub) { g_dec (Flags | CF_CONST, Expr2.IVal); } else { - if (Expr2.IVal == 0) { - /* Check for div by zero/mod by zero */ - if (Gen->Func == g_div) { - Error ("Division by zero"); - } else if (Gen->Func == g_mod) { - Error ("Modulo operation with zero"); - } - } else if (Gen->Func == g_asl || Gen->Func == g_asr) { - if (Expr2.IVal < 0) { - Warning ("Shift count '%ld' is negative", Expr2.IVal); - } else if (Expr2.IVal >= (long)(SizeOf (Expr->Type) * 8)) { - Warning ("Shift count '%ld' >= width of type", Expr2.IVal); - } + if (!ED_IsUneval (Expr)) { + if (Expr2.IVal == 0) { + /* Check for div by zero/mod by zero */ + if (Gen->Func == g_div) { + Error ("Division by zero"); + } else if (Gen->Func == g_mod) { + Error ("Modulo operation with zero"); + } + } else if (Gen->Func == g_asl || Gen->Func == g_asr) { + const Type* CalType = IntPromotion (Expr->Type); + unsigned ExprBits = BitSizeOf (CalType); + + /* If the shift count is greater than or equal to the width of the + ** promoted left operand, the behaviour is undefined according to + ** the standard. + */ + if (Expr2.IVal < 0) { + Warning ("Negative shift count %ld treated as %u for %s", + Expr2.IVal, + (unsigned)Expr2.IVal & (ExprBits - 1), + GetBasicTypeName (CalType)); + } else if (Expr2.IVal >= (long)ExprBits) { + Warning ("Shift count %ld >= width of %s treated as %u", + Expr2.IVal, + GetBasicTypeName (CalType), + (unsigned)Expr2.IVal & (ExprBits - 1)); + } + + /* Here we simply "wrap" the shift count around the width */ + Expr2.IVal &= ExprBits - 1; + } } /* Adjust the types of the operands if needed */ @@ -501,18 +519,36 @@ static void OpAssignArithmetic (const GenDesc* Gen, ExprDesc* Expr, const char* } else if (Gen->Func == g_sub) { g_dec (Flags | CF_CONST, Expr2.IVal); } else { - if (Expr2.IVal == 0) { - /* Check for div by zero/mod by zero */ - if (Gen->Func == g_div) { - Error ("Division by zero"); - } else if (Gen->Func == g_mod) { - Error ("Modulo operation with zero"); - } - } else if (Gen->Func == g_asl || Gen->Func == g_asr) { - if (Expr2.IVal < 0) { - Warning ("Shift count '%ld' is negative", Expr2.IVal); - } else if (Expr2.IVal >= (long)(SizeOf (Expr->Type) * 8)) { - Warning ("Shift count '%ld' >= width of type", Expr2.IVal); + if (!ED_IsUneval (Expr)) { + if (Expr2.IVal == 0 && !ED_IsUneval (Expr)) { + /* Check for div by zero/mod by zero */ + if (Gen->Func == g_div) { + Error ("Division by zero"); + } else if (Gen->Func == g_mod) { + Error ("Modulo operation with zero"); + } + } else if (Gen->Func == g_asl || Gen->Func == g_asr) { + const Type* CalType = IntPromotion (Expr->Type); + unsigned ExprBits = BitSizeOf (CalType); + + /* If the shift count is greater than or equal to the width of the + ** promoted left operand, the behaviour is undefined according to + ** the standard. + */ + if (Expr2.IVal < 0) { + Warning ("Negative shift count %ld treated as %u for %s", + Expr2.IVal, + (unsigned)Expr2.IVal & (ExprBits - 1), + GetBasicTypeName (CalType)); + } else if (Expr2.IVal >= (long)ExprBits) { + Warning ("Shift count %ld >= width of %s treated as %u", + Expr2.IVal, + GetBasicTypeName (CalType), + (unsigned)Expr2.IVal & (ExprBits - 1)); + } + + /* Here we simply "wrap" the shift count around the width */ + Expr2.IVal &= ExprBits - 1; } } Gen->Func (Flags | CF_CONST, Expr2.IVal); diff --git a/src/cc65/datatype.c b/src/cc65/datatype.c index 9a661c037..023aefaf7 100644 --- a/src/cc65/datatype.c +++ b/src/cc65/datatype.c @@ -203,6 +203,14 @@ unsigned long GetIntegerTypeMax (const Type* Type) +unsigned BitSizeOf (const Type* T) +/* Return the size (in bit-width) of a data type */ +{ + return IsTypeBitField (T) ? T->A.B.Width : CHAR_BITS * SizeOf (T); +} + + + unsigned SizeOf (const Type* T) /* Compute size (in bytes) of object represented by type array */ { @@ -288,6 +296,17 @@ unsigned PSizeOf (const Type* T) +unsigned CheckedBitSizeOf (const Type* T) +/* Return the size (in bit-width) of a data type. If the size is zero, emit an +** error and return some valid size instead (so the rest of the compiler +** doesn't have to work with invalid sizes). +*/ +{ + return IsTypeBitField (T) ? T->A.B.Width : CHAR_BITS * CheckedSizeOf (T); +} + + + unsigned CheckedSizeOf (const Type* T) /* Return the size (in bytes) of a data type. If the size is zero, emit an ** error and return some valid size instead (so the rest of the compiler diff --git a/src/cc65/datatype.h b/src/cc65/datatype.h index 5e4e2e39b..4a20422fb 100644 --- a/src/cc65/datatype.h +++ b/src/cc65/datatype.h @@ -287,12 +287,21 @@ unsigned long GetIntegerTypeMax (const Type* Type); ** The type must have a known size. */ +unsigned BitSizeOf (const Type* T); +/* Return the size (in bit-width) of a data type */ + unsigned SizeOf (const Type* T); /* Compute size (in bytes) of object represented by type array */ unsigned PSizeOf (const Type* T); /* Compute size (in bytes) of pointee object */ +unsigned CheckedBitSizeOf (const Type* T); +/* Return the size (in bit-width) of a data type. If the size is zero, emit an +** error and return some valid size instead (so the rest of the compiler +** doesn't have to work with invalid sizes). +*/ + unsigned CheckedSizeOf (const Type* T); /* Return the size (in bytes) of a data type. If the size is zero, emit an ** error and return some valid size instead (so the rest of the compiler diff --git a/src/cc65/expr.c b/src/cc65/expr.c index f7180c020..45dc9cc37 100644 --- a/src/cc65/expr.c +++ b/src/cc65/expr.c @@ -2177,6 +2177,10 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */ /* Check for const operands */ if (lconst && rconst) { + /* Evaluate the result for operands */ + unsigned long Val1 = Expr->IVal; + unsigned long Val2 = Expr2.IVal; + /* Both operands are constant, remove the generated code */ RemoveCode (&Mark1); @@ -2184,80 +2188,51 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */ Expr->Type = ArithmeticConvert (Expr->Type, Expr2.Type); /* Handle the op differently for signed and unsigned types */ - if (IsSignSigned (Expr->Type)) { - - /* Evaluate the result for signed operands */ - signed long Val1 = Expr->IVal; - signed long Val2 = Expr2.IVal; - switch (Tok) { - case TOK_OR: - Expr->IVal = (Val1 | Val2); - break; - case TOK_XOR: - Expr->IVal = (Val1 ^ Val2); - break; - case TOK_AND: - Expr->IVal = (Val1 & Val2); - break; - case TOK_STAR: - Expr->IVal = (Val1 * Val2); - break; - case TOK_DIV: - if (Val2 == 0) { + switch (Tok) { + case TOK_OR: + Expr->IVal = (Val1 | Val2); + break; + case TOK_XOR: + Expr->IVal = (Val1 ^ Val2); + break; + case TOK_AND: + Expr->IVal = (Val1 & Val2); + break; + case TOK_STAR: + Expr->IVal = (Val1 * Val2); + break; + case TOK_DIV: + if (Val2 == 0) { + if (!ED_IsUneval (Expr)) { Error ("Division by zero"); - Expr->IVal = 0x7FFFFFFF; + } + Expr->IVal = 0xFFFFFFFF; + } else { + /* Handle signed and unsigned operands differently */ + if (IsSignSigned (Expr->Type)) { + Expr->IVal = ((long)Val1 / (long)Val2); } else { Expr->IVal = (Val1 / Val2); } - break; - case TOK_MOD: - if (Val2 == 0) { + } + break; + case TOK_MOD: + if (Val2 == 0) { + if (!ED_IsUneval (Expr)) { Error ("Modulo operation with zero"); - Expr->IVal = 0; + } + Expr->IVal = 0; + } else { + /* Handle signed and unsigned operands differently */ + if (IsSignSigned (Expr->Type)) { + Expr->IVal = ((long)Val1 % (long)Val2); } else { Expr->IVal = (Val1 % Val2); } - break; - default: - Internal ("hie_internal: got token 0x%X\n", Tok); - } - } else { - - /* Evaluate the result for unsigned operands */ - unsigned long Val1 = Expr->IVal; - unsigned long Val2 = Expr2.IVal; - switch (Tok) { - case TOK_OR: - Expr->IVal = (Val1 | Val2); - break; - case TOK_XOR: - Expr->IVal = (Val1 ^ Val2); - break; - case TOK_AND: - Expr->IVal = (Val1 & Val2); - break; - case TOK_STAR: - Expr->IVal = (Val1 * Val2); - break; - case TOK_DIV: - if (Val2 == 0) { - Error ("Division by zero"); - Expr->IVal = 0xFFFFFFFF; - } else { - Expr->IVal = (Val1 / Val2); - } - break; - case TOK_MOD: - if (Val2 == 0) { - Error ("Modulo operation with zero"); - Expr->IVal = 0; - } else { - Expr->IVal = (Val1 % Val2); - } - break; - default: - Internal ("hie_internal: got token 0x%X\n", Tok); - } + } + break; + default: + Internal ("hie_internal: got token 0x%X\n", Tok); } /* Limit the calculated value to the range of its type */ @@ -2314,10 +2289,12 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */ /* Second value is constant - check for div */ type |= CF_CONST; rtype |= CF_CONST; - if (Tok == TOK_DIV && Expr2.IVal == 0) { - Error ("Division by zero"); - } else if (Tok == TOK_MOD && Expr2.IVal == 0) { - Error ("Modulo operation with zero"); + if (Expr2.IVal == 0 && !ED_IsUneval (Expr)) { + if (Tok == TOK_DIV) { + Error ("Division by zero"); + } else if (Tok == TOK_MOD) { + Error ("Modulo operation with zero"); + } } if ((Gen->Flags & GEN_NOPUSH) != 0) { RemoveCode (&Mark2); diff --git a/src/cc65/ppexpr.c b/src/cc65/ppexpr.c index 0942dc8f8..73ec69de8 100644 --- a/src/cc65/ppexpr.c +++ b/src/cc65/ppexpr.c @@ -305,97 +305,60 @@ static void PPhie_internal (const token_t* Ops, /* List of generators */ if (PPEvaluationEnabled && !PPEvaluationFailed) { + /* Evaluate the result for operands */ + unsigned long Val1 = Expr->IVal; + unsigned long Val2 = Rhs.IVal; + /* If either side is unsigned, the result is unsigned */ Expr->Flags |= Rhs.Flags & PPEXPR_UNSIGNED; - /* Handle the op differently for signed and unsigned integers */ - if ((Expr->Flags & PPEXPR_UNSIGNED) == 0) { - - /* Evaluate the result for signed operands */ - signed long Val1 = Expr->IVal; - signed long Val2 = Rhs.IVal; - switch (Tok) { - case TOK_OR: - Expr->IVal = (Val1 | Val2); - break; - case TOK_XOR: - Expr->IVal = (Val1 ^ Val2); - break; - case TOK_AND: - Expr->IVal = (Val1 & Val2); - break; - case TOK_PLUS: - Expr->IVal = (Val1 + Val2); - break; - case TOK_MINUS: - Expr->IVal = (Val1 - Val2); - break; - case TOK_MUL: - Expr->IVal = (Val1 * Val2); - break; - case TOK_DIV: - if (Val2 == 0) { - PPError ("Division by zero"); - Expr->IVal = 0; + switch (Tok) { + case TOK_OR: + Expr->IVal = (Val1 | Val2); + break; + case TOK_XOR: + Expr->IVal = (Val1 ^ Val2); + break; + case TOK_AND: + Expr->IVal = (Val1 & Val2); + break; + case TOK_PLUS: + Expr->IVal = (Val1 + Val2); + break; + case TOK_MINUS: + Expr->IVal = (Val1 - Val2); + break; + case TOK_MUL: + Expr->IVal = (Val1 * Val2); + break; + case TOK_DIV: + if (Val2 == 0) { + PPError ("Division by zero"); + Expr->IVal = 0; + } else { + /* Handle signed and unsigned operands differently */ + if ((Expr->Flags & PPEXPR_UNSIGNED) == 0) { + Expr->IVal = ((long)Val1 / (long)Val2); } else { Expr->IVal = (Val1 / Val2); } - break; - case TOK_MOD: - if (Val2 == 0) { - PPError ("Modulo operation with zero"); - Expr->IVal = 0; + } + break; + case TOK_MOD: + if (Val2 == 0) { + PPError ("Modulo operation with zero"); + Expr->IVal = 0; + } else { + /* Handle signed and unsigned operands differently */ + if ((Expr->Flags & PPEXPR_UNSIGNED) == 0) { + Expr->IVal = ((long)Val1 % (long)Val2); } else { Expr->IVal = (Val1 % Val2); } - break; - default: - Internal ("PPhie_internal: got token 0x%X\n", Tok); - } - - } else { - - /* Evaluate the result for unsigned operands */ - unsigned long Val1 = Expr->IVal; - unsigned long Val2 = Rhs.IVal; - switch (Tok) { - case TOK_OR: - Expr->IVal = (Val1 | Val2); - break; - case TOK_XOR: - Expr->IVal = (Val1 ^ Val2); - break; - case TOK_AND: - Expr->IVal = (Val1 & Val2); - break; - case TOK_PLUS: - Expr->IVal = (Val1 + Val2); - break; - case TOK_MINUS: - Expr->IVal = (Val1 - Val2); - break; - case TOK_MUL: - Expr->IVal = (Val1 * Val2); - break; - case TOK_DIV: - if (Val2 == 0) { - PPError ("Division by zero"); - Expr->IVal = 0; - } else { - Expr->IVal = (Val1 / Val2); - } - break; - case TOK_MOD: - if (Val2 == 0) { - PPError ("Modulo operation with zero"); - Expr->IVal = 0; - } else { - Expr->IVal = (Val1 % Val2); - } - break; - default: - Internal ("PPhie_internal: got token 0x%X\n", Tok); - } + } + break; + default: + Internal ("PPhie_internal: got token 0x%X\n", Tok); } } } diff --git a/src/cc65/shiftexpr.c b/src/cc65/shiftexpr.c index 312086f3c..48426f1f2 100644 --- a/src/cc65/shiftexpr.c +++ b/src/cc65/shiftexpr.c @@ -139,22 +139,27 @@ void ShiftExpr (struct ExprDesc* Expr) /* Remove the code that pushes the rhs onto the stack. */ RemoveCode (&Mark2); - /* If the shift count is greater or equal than the bit count of - ** the operand, the behaviour is undefined according to the - ** standard. + /* If the shift count is greater than or equal to the width of the + ** promoted left operand, the behaviour is undefined according to + ** the standard. */ - if (Expr2.IVal < 0) { - - Warning ("Shift count '%ld' is negative", Expr2.IVal); - Expr2.IVal &= ExprBits - 1; - - } else if (Expr2.IVal >= (long) ExprBits) { - - Warning ("Shift count '%ld' >= width of type", Expr2.IVal); - Expr2.IVal &= ExprBits - 1; - + if (!ED_IsUneval (Expr)) { + if (Expr2.IVal < 0) { + Warning ("Negative shift count %ld treated as %u for %s", + Expr2.IVal, + (unsigned)Expr2.IVal & (ExprBits - 1), + GetBasicTypeName (ResultType)); + } else if (Expr2.IVal >= (long) ExprBits) { + Warning ("Shift count %ld >= width of %s treated as %u", + Expr2.IVal, + GetBasicTypeName (ResultType), + (unsigned)Expr2.IVal & (ExprBits - 1)); + } } + /* Here we simply "wrap" the shift count around the width */ + Expr2.IVal &= ExprBits - 1; + /* If the shift count is zero, nothing happens. If the left hand ** side is a constant, the result is constant. */