cc65: [bug] Shifts by zero bits are broken

I am assuming that right-shifing an unsigned char should have no effect on an unsigned char. This is the case in my code when compiled with any compiler except CC65.

I have this macro:

#define initial_letter_drop() \
do \
{ \
    uint8_t i; \
    uint8_t k; \
    \
    _XL_PRINTD(0,1,3,(uint8_t) MIN_INITIAL_DROP + (level>>0)); \
    k = MIN_INITIAL_DROP + (level>>0); \
    _XL_WAIT_FOR_INPUT(); \
    for(i=0;i<(uint8_t) MIN_INITIAL_DROP + (level>>0);++i) \
    { \
        drop_letter(); \
        short_pause(); \
    } \
} while(0)

It produces a infinite loop when compiled with CC65. It can be fixed if I use k instead of (uint8_t) MIN_INITIAL_DROP + (level>>0).

I will try to reproduce it with a minimal example.

Has any recent commit changed how the right shift operator works?

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 23 (22 by maintainers)

Commits related to this issue

Most upvoted comments

The rules shall always be followed even we are shifting by 0.

You mean the integer promotion rules, in order to be standards compliant?

If yes: No, the correct sentence is: “The behaviour shall always be AS IF the rules were followed”. The C standard specifically has this “as if” clause. If the implementation can guarantee that not following the rules (or following other rules) has the same effect as if the rules were followed, it is ok.

Thus, if a shift left or right were completely ignored, and the outcome were the same as if the integer promotion was done, then it would be fine to ignore the shift, without doing integer promotion.

Note that I do not know if the behaviour is the same; I only spoke about the hypothetical possibility!

I would also change the title to “Shifting by literal of zero bits is broken”. Because left shift has the same issue.

Minimal testcase:

#include <stdio.h>
#include <stdint.h>

uint8_t foo=1U;
uint8_t bar=3U; // You need it to reproduce the issue

int main(void)
{            
    printf(foo == foo << 0 ? "OK\n" : "FAIL\n");
    return 0;
}