mirror of
https://github.com/cc65/cc65.git
synced 2024-08-17 03:29:15 +00:00
Previously, the following rules were used for binary operators: * If one of the values is a long, the result is long. * If one of the values is unsigned, the result is also unsigned. * Otherwise the result is an int. C89 specifies the "usual arithmetic conversions" as: * The integral promotions are performed on both operands. * Then the following rules are applied: * If either operand has type unsigned long int, the other operand is converted to unsigned long int. * Otherwise, if one operand has type long int and the other has type unsigned int, if a long int can represent all values of an unsigned int, the operand of type unsigned int is converted to long int; if a long int cannot represent all the values of an unsigned int, both operands are converted to unsigned long int. * Otherwise, if either operand has type long int, the other operand is converted to long int. * Otherwise, if either operand has type unsigned int, the other operand is converted to unsigned int. * Otherwise, both operands have type int. https://port70.net/~nsz/c/c89/c89-draft.html#3.2.1.5 As one example, these rules give a different result for an operator with one long operand and one unsigned int operand. Previously, the result type was unsigned long. With C89 semantics, it is just long, since long can represent all unsigned ints. Integral promotions convert types shorter than int to int (or unsigned int). Both char and unsigned char are promoted to int since int can represent all unsigned chars. https://port70.net/~nsz/c/c89/c89-draft.html#3.2.1.1 Rename promoteint to ArithmeticConvert, since this is more accurate. Fixes #170
41 lines
937 B
C
41 lines
937 B
C
/* bug #170 - Wrong implicit conversion of integers */
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
|
|
int main(void)
|
|
{
|
|
uint8_t c = 2;
|
|
uint32_t u = 2;
|
|
int16_t a = -2;
|
|
int32_t l = -2;
|
|
|
|
/* Generated code should use tosmulax but uses tosumulax */
|
|
int16_t r = c * a;
|
|
/* Generated code should use tosmuleax but uses tosumuleax */
|
|
int32_t lr = u * l;
|
|
|
|
int32_t n = -95;
|
|
uint16_t d = 3;
|
|
int16_t r1 = n / d; // produces 21813 instead of -31
|
|
|
|
int16_t r2 = n / (int32_t) d; // workaround
|
|
|
|
printf("r: %d (-4)\n", r);
|
|
#ifdef REFERENCE
|
|
printf("lr: %d (-4)\n", lr);
|
|
#else
|
|
printf("lr: %ld (-4)\n", lr);
|
|
#endif
|
|
printf("r1: %d (-31)\n", r1);
|
|
printf("r2: %d (-31)\n", r2);
|
|
|
|
if (r != -4) { return EXIT_FAILURE; }
|
|
if (lr != -4) { return EXIT_FAILURE; }
|
|
if (r1 != -31) { return EXIT_FAILURE; }
|
|
if (r2 != -31) { return EXIT_FAILURE; }
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|