diff --git a/source/compiler/sc1.c b/source/compiler/sc1.c index 41084d1f..ff711bad 100644 --- a/source/compiler/sc1.c +++ b/source/compiler/sc1.c @@ -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; @@ -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 */ @@ -2991,13 +2997,16 @@ 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 */ @@ -3005,14 +3014,21 @@ static void decl_enum(int vclass,int fstatic) } 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 */ @@ -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; @@ -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 ; */ @@ -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) diff --git a/source/compiler/sc3.c b/source/compiler/sc3.c index 46486997..9eda02aa 100644 --- a/source/compiler/sc3.c +++ b/source/compiler/sc3.c @@ -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 */ } diff --git a/source/compiler/sc5.c b/source/compiler/sc5.c index c5b31845..7aa845ad 100644 --- a/source/compiler/sc5.c +++ b/source/compiler/sc5.c @@ -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[] = { diff --git a/source/compiler/tests/__emit_p5.meta b/source/compiler/tests/__emit_p5.meta index 6652ac2e..fb6118e5 100644 --- a/source/compiler/tests/__emit_p5.meta +++ b/source/compiler/tests/__emit_p5.meta @@ -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 """ } diff --git a/source/compiler/tests/enum_increment.meta b/source/compiler/tests/enum_increment.meta new file mode 100644 index 00000000..bfdf2528 --- /dev/null +++ b/source/compiler/tests/enum_increment.meta @@ -0,0 +1,5 @@ +{ + 'test_type': 'output_check', + 'errors': """ + """ +} diff --git a/source/compiler/tests/enum_increment.pwn b/source/compiler/tests/enum_increment.pwn new file mode 100644 index 00000000..c549d713 --- /dev/null +++ b/source/compiler/tests/enum_increment.pwn @@ -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 +} diff --git a/source/compiler/tests/warning_241_242.meta b/source/compiler/tests/warning_241_242.meta new file mode 100644 index 00000000..b9aba086 --- /dev/null +++ b/source/compiler/tests/warning_241_242.meta @@ -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 +""" +} diff --git a/source/compiler/tests/warning_241_242.pwn b/source/compiler/tests/warning_241_242.pwn new file mode 100644 index 00000000..74daa095 --- /dev/null +++ b/source/compiler/tests/warning_241_242.pwn @@ -0,0 +1,158 @@ +#include + +enum (<<= 32) +{ + a0 = 0 +}; + +enum (<<= -1) +{ + b0 = 0 +}; + +enum (<<= 1) +{ + c0 = 0 +}; +enum (<<= 31) +{ + d0 = 0 +}; + +enum (<<= 1) +{ + e0 = 1, + e1, + e2, + e3, + e4, + e5, + e6, + e7, + e8, + e9, + e10, + e11, + e12, + e13, + e14, + e15, + e16, + e17, + e18, + e19, + e20, + e21, + e22, + e23, + e24, + e25, + e26, + e27, + e28, + e29, + e30, // 0b01000000000000000000000000000000 + e31, // 0b10000000000000000000000000000000 + e32, // 0b00000000000000000000000000000000 (overflow) + e33 // 0b00000000000000000000000000000000 +}; + +enum (<<= 1) +{ + f0 = 1, + f1, + f2, + f3, + f4, + f5, + f6, + f7, + f8, + f9, + f10, + f11, + f12, + f13, + f14, + f15, + f16, + f17, + f18, + f19, + f20, + f21, + f22, + f23, + f24, + f25, + f26, + f27, + f28, + f29, + f30, + f31, // 0b10000000000000000000000000000000 + f32 = f31-1,// 0b01111111111111111111111111111111 + f33, // 0b11111111111111111111111111111110 + f34, // 0b11111111111111111111111111111100 (overflow) + f35 // 0b11111111111111111111111111111000 (overflow) +}; + +main() +{ + new var = 1; + + // Case 1: Both values are compile-time constants + printf("%d", 1 << -1); // warning 241 + printf("%d", 1 << -2); // warning 241 + printf("%d", 1 >> -1); // warning 241 + printf("%d", 1 >> -2); // warning 241 + printf("%d", 1 >>> -1); // warning 241 + printf("%d", 1 >>> -2); // warning 241 + printf("%d", 1 << 0); + printf("%d", 1 << 1); + printf("%d", 1 >> 0); + printf("%d", 1 >> 1); + printf("%d", 1 >>> 0); + printf("%d", 1 >>> 1); + printf("%d", 1 << 30); + printf("%d", 1 << 31); + printf("%d", 1 >> 30); + printf("%d", 1 >> 31); + printf("%d", 1 >>> 30); + printf("%d", 1 >>> 31); + printf("%d", 1 << 32); // warning 241 + printf("%d", 1 << 33); // warning 241 + printf("%d", 1 >> 32); // warning 241 + printf("%d", 1 >> 33); // warning 241 + printf("%d", 1 >>> 32); // warning 241 + printf("%d", 1 >>> 33); // warning 241 + + // Case 2: Only the shift count is constant + printf("%d", var << -1); // warning 241 + printf("%d", var << -2); // warning 241 + printf("%d", var >> -1); // warning 241 + printf("%d", var >> -2); // warning 241 + printf("%d", var >>> -1); // warning 241 + printf("%d", var >>> -2); // warning 241 + printf("%d", var << 0); + printf("%d", var << 1); + printf("%d", var >> 0); + printf("%d", var >> 1); + printf("%d", var >>> 0); + printf("%d", var >>> 1); + printf("%d", var << 30); + printf("%d", var << 31); + printf("%d", var >> 30); + printf("%d", var >> 31); + printf("%d", var >>> 30); + printf("%d", var >>> 31); + printf("%d", var << 32); // warning 241 + printf("%d", var << 33); // warning 241 + printf("%d", var >> 32); // warning 241 + printf("%d", var >> 33); // warning 241 + printf("%d", var >>> 32); // warning 241 + printf("%d", var >>> 33); // warning 241 + + printf("%d", 1 << var); // Just to make sure the warning works only + // if the shift count is a constant value +}