While investigating PIC16 <stdbit.h> regression failures, I found a front-end issue in src/SDCCast.c.</stdbit.h>
An explicit cast can currently be removed when the cast type and the currently decorated operand type compare equal:
if (!tree->values.cast.semDeref &&
compareTypeExact (LTYPE (tree), RTYPE (tree), -1, true) == 1)
{
tree->right->values.cast.removedCast = 1;
return tree->right;
}
This is safe for simple value nodes, but not necessarily for expression nodes.
For expressions, the apparent operand type may depend on the current result-type context. If the explicit cast is removed, the expression can later be decorated again in another context and integer promotions may reappear, changing the value that is eventually passed to another expression or function.
A small reproducer is:
unsigned char nv = 0;
unsigned char nh = 0x80;
void sink(unsigned long long x);
void test(void)
{
sink((unsigned char)(nv - 1));
sink((unsigned char)(nh << 1));
sink((unsigned char)nv);
}
The critical case is:
sink((unsigned char)(nh << 1));
The explicit cast requires the shifted result to be converted to unsigned char before conversion to unsigned long long.
Without the fix, the cast on the expression can be removed too early and the later decoration can restore integer-promotion semantics, so nh << 1 may be passed as 0x0100 instead of the explicitly cast result 0x00.
The proposed fix only removes a redundant explicit cast when the operand is an AST value node:
if (!tree->values.cast.semDeref &&
compareTypeExact (LTYPE (tree), RTYPE (tree), -1, true) == 1 &&
IS_AST_VALUE (tree->right))
{
tree->right->values.cast.removedCast = 1;
return tree->right;
}
After this change, explicit casts on expression nodes are preserved, while redundant casts on values can still be removed.
I also verified the issue with typeof() and volatile-qualified casts.
The attached patch contains only this front-end change:
cast_expression_preservation.patch
It is based on revision r17065 and applies cleanly to a pristine r17065 checkout.