Skip to content
55 changes: 39 additions & 16 deletions source/compiler/sc1.c
Original file line number Diff line number Diff line change
Expand Up @@ -2928,7 +2928,9 @@ static void decl_enum(int vclass,int fstatic)
cell val,value,size;
char *str;
int tag,explicittag;
cell increment,multiplier;
int inctok;
int warn_overflow;
cell increment;
constvalue_root *enumroot=NULL;
symbol *enumsym=NULL;
short filenum;
Expand Down Expand Up @@ -2958,18 +2960,22 @@ static void decl_enum(int vclass,int fstatic)
enumname[0]='\0';
} /* if */

/* get increment and multiplier */
/* get the increment */
increment=1;
multiplier=1;
inctok=taADD;
if (matchtoken('(')) {
if (matchtoken(taADD)) {
int tok=lex(&val,&str);
if (tok==taADD || tok==taMULT || tok==taSHL) {
inctok=tok;
constexpr(&increment,NULL,NULL);
} else if (matchtoken(taMULT)) {
constexpr(&multiplier,NULL,NULL);
} else if (matchtoken(taSHL)) {
constexpr(&val,NULL,NULL);
while (val-->0)
multiplier*=2;
if (tok==taSHL) {
if (increment<0 || increment>=PAWN_CELL_SIZE)
error(241); /* negative or too big shift count */
if (increment<0)
increment=0;
} /* if */
} else {
lexpush();
} /* if */
needtoken(')');
} /* if */
Expand All @@ -2991,28 +2997,38 @@ static void decl_enum(int vclass,int fstatic)
needtoken('{');
/* go through all constants */
value=0; /* default starting value */
warn_overflow=FALSE;
do {
int idxtag,fieldtag;
int symline;
symbol *sym;
if (matchtoken('}')) { /* quick exit if '}' follows ',' */
lexpush();
break;
} /* if */
symline=fline;
idxtag=(enumname[0]=='\0') ? tag : pc_addtag(NULL); /* optional explicit item tag */
if (needtoken(tSYMBOL)) { /* read in (new) token */
tokeninfo(&val,&str); /* get the information */
strcpy(constname,str); /* save symbol name */
} else {
constname[0]='\0';
} /* if */
size=increment; /* default increment of 'val' */
size=(inctok==taADD) ? increment : 1;/* default increment of 'val' */
fieldtag=0; /* default field tag */
if (matchtoken('[')) {
constexpr(&size,&fieldtag,NULL); /* get size */
needtoken(']');
} /* if */
if (matchtoken('='))
if (matchtoken('=')) {
constexpr(&value,NULL,NULL); /* get value */
warn_overflow=FALSE;
} else if (warn_overflow) {
errorset(sSETPOS,symline);
error(242,constname); /* shift overflow for enum item */
errorset(sSETPOS,-1);
warn_overflow=FALSE;
} /* if */
/* add_constant() checks whether a variable (global or local) or
* a constant with the same name already exists
*/
Expand All @@ -3027,6 +3043,8 @@ static void decl_enum(int vclass,int fstatic)
sym->parent=enumsym;
if (enumsym)
enumsym->child=sym;
if (vclass==sLOCAL)
sym->compound=nestlevel;

if (fstatic)
sym->fnumber=filenum;
Expand All @@ -3036,10 +3054,15 @@ static void decl_enum(int vclass,int fstatic)
sym->usage |= uENUMFIELD;
append_constval(enumroot,constname,value,tag);
} /* if */
if (multiplier==1)
if (inctok==taADD) {
value+=size;
else
value*=size*multiplier;
} else if (inctok==taMULT) {
value*=(size*increment);
} else { // taSHL
if ((ucell)value>=((ucell)1 << (PAWN_CELL_SIZE-increment)))
warn_overflow=TRUE;
value*=(size << increment);
} /* if */
} while (matchtoken(','));
needtoken('}'); /* terminates the constant list */
matchtoken(';'); /* eat an optional ; */
Expand Down Expand Up @@ -6545,7 +6568,7 @@ static void SC_FASTCALL emit_param_index(emit_outval *p,int isrange,
if (val==valid_values[i])
return;
} /* if */
error(50); /* invalid range */
error(241); /* negative or too big shift count */
}

static void SC_FASTCALL emit_param_nonneg(emit_outval *p)
Expand Down
21 changes: 13 additions & 8 deletions source/compiler/sc3.c
Original file line number Diff line number Diff line change
Expand Up @@ -626,15 +626,20 @@ static void plnge2(void (*oper)(void),
if (check_userop(oper,lval1->tag,lval2->tag,2,NULL,&lval1->tag)) {
lval1->ident=iEXPRESSION;
lval1->constval=0;
} else if (lval1->ident==iCONSTEXPR && lval2->ident==iCONSTEXPR) {
/* only constant expression if both constant */
stgdel(index,cidx); /* scratch generated code and calculate */
check_tagmismatch(lval1->tag,lval2->tag,FALSE,-1);
lval1->constval=calc(lval1->constval,oper,lval2->constval,&lval1->boolresult);
} else {
check_tagmismatch(lval1->tag,lval2->tag,FALSE,-1);
(*oper)(); /* do the (signed) operation */
lval1->ident=iEXPRESSION;
if ((oper==ob_sal || oper==os_sar || oper==ou_sar)
&& (lval2->ident==iCONSTEXPR && (lval2->constval<0 || lval2->constval>=PAWN_CELL_SIZE)))
error(241); /* negative or too big shift count */
if (lval1->ident==iCONSTEXPR && lval2->ident==iCONSTEXPR) {
/* only constant expression if both constant */
stgdel(index,cidx); /* scratch generated code and calculate */
check_tagmismatch(lval1->tag,lval2->tag,FALSE,-1);
lval1->constval=calc(lval1->constval,oper,lval2->constval,&lval1->boolresult);
} else {
check_tagmismatch(lval1->tag,lval2->tag,FALSE,-1);
(*oper)(); /* do the (signed) operation */
lval1->ident=iEXPRESSION;
} /* if */
} /* if */
} /* if */
}
Expand Down
4 changes: 3 additions & 1 deletion source/compiler/sc5.c
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,9 @@ static char *warnmsg[] = {
/*237*/ "user warning: %s\n",
/*238*/ "meaningless combination of class specifiers (%s)\n",
/*239*/ "literal array/string passed to a non-const parameter\n",
/*240*/ "previously assigned value is never used (symbol \"%s\")\n"
/*240*/ "previously assigned value is never used (symbol \"%s\")\n",
/*241*/ "negative or too big shift count\n",
/*242*/ "shift overflow in enum item declaration (symbol \"%s\")\n"
};

static char *noticemsg[] = {
Expand Down
24 changes: 12 additions & 12 deletions source/compiler/tests/__emit_p5.meta
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
{
'test_type': 'output_check',
'errors': """
__emit_p5.pwn(25) : error 050: invalid range
__emit_p5.pwn(25) : warning 241: negative or too big shift count
__emit_p5.pwn(26) : error 001: expected token: "-integer value-", but found "-data offset-"
__emit_p5.pwn(27) : error 001: expected token: "-integer value-", but found "-function-"
__emit_p5.pwn(28) : error 001: expected token: "-integer value-", but found "-reference-"
__emit_p5.pwn(29) : error 050: invalid range
__emit_p5.pwn(29) : warning 241: negative or too big shift count
__emit_p5.pwn(30) : error 001: expected token: "-integer value-", but found "-local variable-"
__emit_p5.pwn(31) : error 001: expected token: "-integer value-", but found "-data offset-"
__emit_p5.pwn(32) : error 001: expected token: "-integer value-", but found "-label-"
__emit_p5.pwn(33) : error 050: invalid range
__emit_p5.pwn(34) : error 050: invalid range
__emit_p5.pwn(35) : error 050: invalid range
__emit_p5.pwn(36) : error 050: invalid range
__emit_p5.pwn(37) : error 050: invalid range
__emit_p5.pwn(38) : error 050: invalid range
__emit_p5.pwn(33) : warning 241: negative or too big shift count
__emit_p5.pwn(34) : warning 241: negative or too big shift count
__emit_p5.pwn(35) : warning 241: negative or too big shift count
__emit_p5.pwn(36) : warning 241: negative or too big shift count
__emit_p5.pwn(37) : warning 241: negative or too big shift count
__emit_p5.pwn(38) : warning 241: negative or too big shift count
__emit_p5.pwn(61) : error 001: expected token: "-integer value-", but found "-data offset-"
__emit_p5.pwn(62) : error 001: expected token: "-integer value-", but found "-function-"
__emit_p5.pwn(63) : error 001: expected token: "-integer value-", but found "-reference-"
__emit_p5.pwn(64) : error 001: expected token: "-integer value-", but found "-local variable-"
__emit_p5.pwn(65) : error 001: expected token: "-integer value-", but found "-data offset-"
__emit_p5.pwn(66) : error 001: expected token: "-integer value-", but found "-label-"
__emit_p5.pwn(67) : error 050: invalid range
__emit_p5.pwn(68) : error 050: invalid range
__emit_p5.pwn(69) : error 050: invalid range
__emit_p5.pwn(70) : error 050: invalid range
__emit_p5.pwn(67) : warning 241: negative or too big shift count
__emit_p5.pwn(68) : warning 241: negative or too big shift count
__emit_p5.pwn(69) : warning 241: negative or too big shift count
__emit_p5.pwn(70) : warning 241: negative or too big shift count
"""
}
5 changes: 5 additions & 0 deletions source/compiler/tests/enum_increment.meta
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
'test_type': 'output_check',
'errors': """
"""
}
86 changes: 86 additions & 0 deletions source/compiler/tests/enum_increment.pwn
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#pragma option -d1 // TODO: Remove this line when #544 is merged

main()
{
enum e1
{
e1Elem1[3],
e1Elem2,
e1Elem3
};
new arr1[e1];
#pragma unused arr1
#assert sizeof arr1[e1Elem1] == 3
#assert sizeof arr1[e1Elem2] == 1
#assert sizeof arr1[e1Elem3] == 1
#assert _:e1Elem1 == 0
#assert _:e1Elem2 == 3
#assert _:e1Elem3 == 4

enum e2 (+= 2)
{
e2Elem1[3],
e2Elem2,
e2Elem3
};
new arr2[e2];
#pragma unused arr2
#assert sizeof arr2[e2Elem1] == 3
#assert sizeof arr2[e2Elem2] == 2
#assert sizeof arr2[e2Elem3] == 2
#assert _:e2Elem1 == 0
#assert _:e2Elem2 == 3
#assert _:e2Elem3 == 5

enum e3 (*= 2)
{
e3Elem1 = 1,
e3Elem2[3],
e3Elem3
};
new arr3[e3];
#pragma unused arr3
#assert sizeof arr3[e3Elem1] == 1
#assert sizeof arr3[e3Elem2] == 3
#assert sizeof arr3[e3Elem3] == 1
#assert _:e3Elem1 == 1
#assert _:e3Elem2 == 2 // 1 * (1 * 2); the first "1" is the value of the previous
// enum item, the second "1" is the size of the previous
// item, and "2" is the increment (multiplier)
#assert _:e3Elem3 == 12 // 2 * (3 * 2)

enum e4 (<<= 2)
{
e4Elem1 = 1,
e4Elem2[3],
e4Elem3
};
new arr4[e4];
#pragma unused arr4
#assert sizeof arr4[e4Elem1] == 1
#assert sizeof arr4[e4Elem2] == 3
#assert sizeof arr4[e4Elem3] == 1
#assert _:e4Elem1 == 1
#assert _:e4Elem2 == 4 // 1 * (1 << 2) = 4
#assert _:e4Elem3 == 48 // 4 * (3 << 2) = 48

enum (<<= 0)
{
e5Elem1,
e5Elem2,
e5Elem3
};
#assert _:e5Elem1 == 0
#assert _:e5Elem2 == 0
#assert _:e5Elem3 == 0

enum (*= 1)
{
e5Elem1,
e5Elem2,
e5Elem3
};
#assert _:e5Elem1 == 0
#assert _:e5Elem2 == 0
#assert _:e5Elem3 == 0
}
34 changes: 34 additions & 0 deletions source/compiler/tests/warning_241_242.meta
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
'test_type': 'output_check',
'errors': """
warning_241_242.pwn(3) : warning 241: negative or too big shift count
warning_241_242.pwn(8) : warning 241: negative or too big shift count
warning_241_242.pwn(56) : warning 242: shift overflow in enum item declaration (symbol "e32")
warning_241_242.pwn(96) : warning 242: shift overflow in enum item declaration (symbol "f34")
warning_241_242.pwn(97) : warning 242: shift overflow in enum item declaration (symbol "f35")
warning_241_242.pwn(105) : warning 241: negative or too big shift count
warning_241_242.pwn(106) : warning 241: negative or too big shift count
warning_241_242.pwn(107) : warning 241: negative or too big shift count
warning_241_242.pwn(108) : warning 241: negative or too big shift count
warning_241_242.pwn(109) : warning 241: negative or too big shift count
warning_241_242.pwn(110) : warning 241: negative or too big shift count
warning_241_242.pwn(123) : warning 241: negative or too big shift count
warning_241_242.pwn(124) : warning 241: negative or too big shift count
warning_241_242.pwn(125) : warning 241: negative or too big shift count
warning_241_242.pwn(126) : warning 241: negative or too big shift count
warning_241_242.pwn(127) : warning 241: negative or too big shift count
warning_241_242.pwn(128) : warning 241: negative or too big shift count
warning_241_242.pwn(131) : warning 241: negative or too big shift count
warning_241_242.pwn(132) : warning 241: negative or too big shift count
warning_241_242.pwn(133) : warning 241: negative or too big shift count
warning_241_242.pwn(134) : warning 241: negative or too big shift count
warning_241_242.pwn(135) : warning 241: negative or too big shift count
warning_241_242.pwn(136) : warning 241: negative or too big shift count
warning_241_242.pwn(149) : warning 241: negative or too big shift count
warning_241_242.pwn(150) : warning 241: negative or too big shift count
warning_241_242.pwn(151) : warning 241: negative or too big shift count
warning_241_242.pwn(152) : warning 241: negative or too big shift count
warning_241_242.pwn(153) : warning 241: negative or too big shift count
warning_241_242.pwn(154) : warning 241: negative or too big shift count
"""
}
Loading