mirror of
https://github.com/cc65/cc65.git
synced 2025-01-10 19:29:45 +00:00
Fixed type promotion of switch case values.
This commit is contained in:
parent
bb1b5c363e
commit
df392fc104
@ -64,7 +64,7 @@
|
|||||||
typedef struct SwitchCtrl SwitchCtrl;
|
typedef struct SwitchCtrl SwitchCtrl;
|
||||||
struct SwitchCtrl {
|
struct SwitchCtrl {
|
||||||
Collection* Nodes; /* CaseNode tree */
|
Collection* Nodes; /* CaseNode tree */
|
||||||
TypeCode ExprType; /* Basic switch expression type */
|
const Type* ExprType; /* Switch controlling expression type */
|
||||||
unsigned Depth; /* Number of bytes the selector type has */
|
unsigned Depth; /* Number of bytes the selector type has */
|
||||||
unsigned DefaultLabel; /* Label for the default branch */
|
unsigned DefaultLabel; /* Label for the default branch */
|
||||||
|
|
||||||
@ -133,7 +133,7 @@ void SwitchStatement (void)
|
|||||||
|
|
||||||
/* Setup the control structure, save the old and activate the new one */
|
/* Setup the control structure, save the old and activate the new one */
|
||||||
SwitchData.Nodes = NewCollection ();
|
SwitchData.Nodes = NewCollection ();
|
||||||
SwitchData.ExprType = GetUnqualTypeCode (&SwitchExpr.Type[0]);
|
SwitchData.ExprType = SwitchExpr.Type;
|
||||||
SwitchData.Depth = SizeOf (SwitchExpr.Type);
|
SwitchData.Depth = SizeOf (SwitchExpr.Type);
|
||||||
SwitchData.DefaultLabel = 0;
|
SwitchData.DefaultLabel = 0;
|
||||||
OldSwitch = Switch;
|
OldSwitch = Switch;
|
||||||
@ -152,7 +152,7 @@ void SwitchStatement (void)
|
|||||||
|
|
||||||
/* Check if we had any labels */
|
/* Check if we had any labels */
|
||||||
if (CollCount (SwitchData.Nodes) == 0 && SwitchData.DefaultLabel == 0) {
|
if (CollCount (SwitchData.Nodes) == 0 && SwitchData.DefaultLabel == 0) {
|
||||||
Warning ("No case labels");
|
Warning ("No reachable case labels for switch");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the last statement did not have a break, we may have an open
|
/* If the last statement did not have a break, we may have an open
|
||||||
@ -209,62 +209,64 @@ void CaseLabel (void)
|
|||||||
/* Handle a case label */
|
/* Handle a case label */
|
||||||
{
|
{
|
||||||
ExprDesc CaseExpr; /* Case label expression */
|
ExprDesc CaseExpr; /* Case label expression */
|
||||||
long Val; /* Case label value */
|
|
||||||
unsigned CodeLabel; /* Code label for this case */
|
|
||||||
|
|
||||||
/* Skip the "case" token */
|
/* Skip the "case" token */
|
||||||
NextToken ();
|
NextToken ();
|
||||||
|
|
||||||
/* Read the selector expression */
|
/* Read the selector expression */
|
||||||
CaseExpr = NoCodeConstAbsIntExpr (hie1);
|
CaseExpr = NoCodeConstAbsIntExpr (hie1);
|
||||||
Val = CaseExpr.IVal;
|
|
||||||
|
|
||||||
/* Now check if we're inside a switch statement */
|
/* Now check if we're inside a switch statement */
|
||||||
if (Switch != 0) {
|
if (Switch != 0) {
|
||||||
|
|
||||||
/* Check the range of the expression */
|
/* Check the range of the expression */
|
||||||
switch (Switch->ExprType) {
|
const Type* CaseT = CaseExpr.Type;
|
||||||
|
long CaseVal = CaseExpr.IVal;
|
||||||
|
int OutOfRange = 0;
|
||||||
|
const char* DiagMsg = 0;
|
||||||
|
|
||||||
case T_SCHAR:
|
CaseExpr.Type = IntPromotion (Switch->ExprType);
|
||||||
/* Signed char */
|
LimitExprValue (&CaseExpr, 1);
|
||||||
if (Val < -128 || Val > 127) {
|
|
||||||
Error ("Range error");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case T_UCHAR:
|
if (CaseVal != CaseExpr.IVal ||
|
||||||
if (Val < 0 || Val > 255) {
|
(IsSignSigned (CaseT) != IsSignSigned (CaseExpr.Type) &&
|
||||||
Error ("Range error");
|
(IsSignSigned (CaseT) ? CaseVal < 0 : CaseExpr.IVal < 0))) {
|
||||||
}
|
Warning (IsSignSigned (CaseT) ?
|
||||||
break;
|
IsSignSigned (CaseExpr.Type) ?
|
||||||
|
"Case value is implicitly converted (%ld to %ld)" :
|
||||||
case T_SHORT:
|
"Case value is implicitly converted (%ld to %lu)" :
|
||||||
case T_INT:
|
IsSignSigned (CaseExpr.Type) ?
|
||||||
if (Val < -32768 || Val > 32767) {
|
"Case value is implicitly converted (%lu to %ld)" :
|
||||||
Error ("Range error");
|
"Case value is implicitly converted (%lu to %lu)",
|
||||||
}
|
CaseVal, CaseExpr.IVal);
|
||||||
break;
|
|
||||||
|
|
||||||
case T_USHORT:
|
|
||||||
case T_UINT:
|
|
||||||
if (Val < 0 || Val > 65535) {
|
|
||||||
Error ("Range error");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case T_LONG:
|
|
||||||
case T_ULONG:
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
Internal ("Invalid type: %06lX", Switch->ExprType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Insert the case selector into the selector table */
|
/* Check the range of the expression */
|
||||||
CodeLabel = InsertCaseValue (Switch->Nodes, Val, Switch->Depth);
|
if (IsSignSigned (CaseExpr.Type)) {
|
||||||
|
if (CaseExpr.IVal < GetIntegerTypeMin (Switch->ExprType)) {
|
||||||
|
DiagMsg = "Case value (%ld) out of range for switch condition type";
|
||||||
|
OutOfRange = 1;
|
||||||
|
} else if (IsSignSigned (Switch->ExprType) ?
|
||||||
|
CaseExpr.IVal > (long)GetIntegerTypeMax (Switch->ExprType) :
|
||||||
|
SizeOf (CaseExpr.Type) > SizeOf (Switch->ExprType) &&
|
||||||
|
(unsigned long)CaseExpr.IVal > GetIntegerTypeMax (Switch->ExprType)) {
|
||||||
|
DiagMsg = "Case value (%ld) out of range for switch condition type";
|
||||||
|
OutOfRange = 1;
|
||||||
|
}
|
||||||
|
} else if ((unsigned long)CaseExpr.IVal > GetIntegerTypeMax (Switch->ExprType)) {
|
||||||
|
DiagMsg = "Case value (%lu) out of range for switch condition type";
|
||||||
|
OutOfRange = 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Define this label */
|
if (OutOfRange == 0) {
|
||||||
g_defcodelabel (CodeLabel);
|
/* Insert the case selector into the selector table */
|
||||||
|
unsigned CodeLabel = InsertCaseValue (Switch->Nodes, CaseExpr.IVal, Switch->Depth);
|
||||||
|
|
||||||
|
/* Define this label */
|
||||||
|
g_defcodelabel (CodeLabel);
|
||||||
|
} else {
|
||||||
|
Warning (DiagMsg, CaseExpr.IVal);
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
77
test/val/bug2019-case-value.c
Normal file
77
test/val/bug2019-case-value.c
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
/* Bug #2019 - Type promotion in switch statements seems to be broken */
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
unsigned failures;
|
||||||
|
|
||||||
|
int f1(void)
|
||||||
|
{
|
||||||
|
unsigned char c = 0xFF;
|
||||||
|
switch (c) {
|
||||||
|
case (signed char)0xFF: break;
|
||||||
|
case (unsigned char)0xFF: return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int f2(void)
|
||||||
|
{
|
||||||
|
signed char c = SCHAR_MIN;
|
||||||
|
switch (c) {
|
||||||
|
case (unsigned char)SCHAR_MIN: break;
|
||||||
|
case SCHAR_MIN: return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int f3(void)
|
||||||
|
{
|
||||||
|
signed int c = (int)UINT_MAX;
|
||||||
|
switch (c) {
|
||||||
|
case UINT_MAX: return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int f4(void)
|
||||||
|
{
|
||||||
|
unsigned int c = UINT_MAX;
|
||||||
|
switch (c) {
|
||||||
|
case -1L: return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
if (f1())
|
||||||
|
{
|
||||||
|
++failures;
|
||||||
|
printf("f1() failed\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f2())
|
||||||
|
{
|
||||||
|
++failures;
|
||||||
|
printf("f2() failed\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f3())
|
||||||
|
{
|
||||||
|
++failures;
|
||||||
|
printf("f3() failed\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f4())
|
||||||
|
{
|
||||||
|
++failures;
|
||||||
|
printf("f4() failed\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (failures > 0)
|
||||||
|
{
|
||||||
|
printf("failures: %u\n", failures);
|
||||||
|
}
|
||||||
|
return failures;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user