diff --git a/source/compiler/sc.h b/source/compiler/sc.h index 1a517a4..e6e5a26 100644 --- a/source/compiler/sc.h +++ b/source/compiler/sc.h @@ -640,7 +640,7 @@ SC_FUNC void setlinedirect(int line); SC_FUNC void setlineconst(int line); SC_FUNC void setlabel(int index); SC_FUNC void markexpr(optmark type,const char *name,cell offset); -SC_FUNC void startfunc(char *fname); +SC_FUNC void startfunc(char *fname,int generateproc); SC_FUNC void endfunc(void); SC_FUNC void alignframe(int numbytes); SC_FUNC void rvalue(value *lval); diff --git a/source/compiler/sc1.c b/source/compiler/sc1.c index 54878fc..116a65e 100644 --- a/source/compiler/sc1.c +++ b/source/compiler/sc1.c @@ -3150,8 +3150,7 @@ SC_FUNC symbol *fetchfunc(char *name,int tag) sym=addsym(name,code_idx,iFUNCTN,sGLOBAL,tag,0); assert(sym!=NULL); /* fatal error 103 must be given on error */ /* assume no arguments */ - sym->dim.arglist=(arginfo*)malloc(1*sizeof(arginfo)); - sym->dim.arglist[0].ident=0; + sym->dim.arglist=(arginfo*)calloc(1,sizeof(arginfo)); /* set library ID to NULL (only for native functions) */ sym->x.lib=NULL; /* set the required stack size to zero (only for non-native functions) */ @@ -3799,7 +3798,7 @@ static int newfunc(char *firstname,int firsttag,int fpublic,int fstatic,int stoc ptr=ptr->next; } /* while */ } /* if */ - startfunc(sym->name); /* creates stack frame */ + startfunc(sym->name,(sym->flags & flagNAKED)==0); /* creates stack frame */ insert_dbgline(funcline); setline(FALSE); if (sc_alignnext) { @@ -4224,8 +4223,12 @@ static void doarg(char *name,int ident,int offset,int tags[],int numtags, assert(numtags>0); argsym=addvariable(name,offset,ident,sLOCAL,tags[0], arg->dim,arg->numdim,arg->idxtag,0); - if (fpublic) + if (fpublic) { argsym->usage|=uREAD; /* arguments of public functions are always "used" */ + if(argsym->ident==iREFARRAY || argsym->ident==iREFERENCE) + argsym->usage|=uWRITTEN; + } + if (fconst) argsym->usage|=uCONST; } /* if */ @@ -4904,9 +4907,20 @@ static int testsymbols(symbol *root,int level,int testlabs,int testconst) error(204,sym->name); /* value assigned to symbol is never used */ errorset(sSETPOS,-1); } else if ((sym->usage & (uWRITTEN | uPUBLIC | uCONST))==0 && sym->ident==iREFARRAY) { - errorset(sSETPOS,sym->lnumber); - error(214,sym->name); /* make array argument "const" */ - errorset(sSETPOS,-1); + int warn = 1; + symbol* depend = finddepend(sym); + while (depend != NULL) { + if ((depend->usage & (uWRITTEN | uPUBLIC | uCONST)) != 0) { + warn = 0; + break; + } + depend = finddepend(depend); + } /* while */ + if (warn) { + errorset(sSETPOS, sym->lnumber); + error(214, sym->name); /* make array argument "const" */ + errorset(sSETPOS, -1); + } /* if */ } /* if */ /* also mark the variable (local or global) to the debug information */ if ((sym->usage & (uWRITTEN | uREAD))!=0 && (sym->usage & uNATIVE)==0) diff --git a/source/compiler/sc2.c b/source/compiler/sc2.c index 7a123f8..ef9151e 100644 --- a/source/compiler/sc2.c +++ b/source/compiler/sc2.c @@ -396,8 +396,11 @@ static void readline(unsigned char *line) *line='\0'; /* delete line */ cont=FALSE; } else { - /* check whether to erase leading whitespace after '\\' on next line */ + /* check whether to erase leading spaces */ if (cont) { + unsigned char *ptr=line; + while (*ptr<=' ' && *ptr!='\0') + ptr++; if (ptr!=line) memmove(line,ptr,strlen((char*)ptr)+1); } /* if */ @@ -414,6 +417,10 @@ static void readline(unsigned char *line) ptr--; /* skip trailing whitespace */ if (*ptr=='\\') { cont=TRUE; + /* set '\a' at the position of '\\' to make it possible to check + * for a line continuation in a single line comment (error 49) + */ + *ptr++='\a'; *ptr='\0'; /* erase '\n' (and any trailing whitespace) */ } /* if */ } /* if */ @@ -441,6 +448,7 @@ static void readline(unsigned char *line) static void stripcomment(unsigned char *line) { char c; + char* continuation; #if !defined SC_LIGHT #define COMMENT_LIMIT 100 #define COMMENT_MARGIN 40 /* length of the longest word */ @@ -512,6 +520,24 @@ static void stripcomment(unsigned char *line) if (icomment==2) *line++=' '; } else if (*line=='/' && *(line+1)=='/'){ /* comment to end of line */ + continuation=(char*)line; + while ((continuation=strchr(continuation,'\a'))!=NULL){ + /* don't give the error if the next line is also commented out. + it is quite annoying to get an error for commenting out a define using: + + // + // #define LONG_MACRO\ + // did span \ + // multiple lines + // + */ + while (*continuation<=' ' && *continuation!='\0') + continuation++; /* skip whitespace */ + if (*continuation!='/' || *(continuation+1)!='/') { + error(49); /* invalid line continuation */ + break; + } + } #if !defined SC_LIGHT if (*(line+2)=='/' && *(line+3)<=' ') { /* documentation comment */ @@ -903,6 +929,23 @@ static const unsigned char *getstring(unsigned char *dest,int max,const unsigned return line; } +/* strdupwithouta + * + * Duplicate a string, stripping out `\a`s. + */ +static char* strdupwithouta(const char* sourcestring) +{ + char* result=strdup(sourcestring); + char* a=result; + if (result==NULL) { + return NULL; + } + while ((a=strchr(a,'\a'))!=NULL) { + *a=' '; + } + return result; +} + enum { CMD_NONE, CMD_TERM, @@ -1115,7 +1158,7 @@ static int command(void) /* remove leading whitespace */ while (*lptr<=' ' && *lptr!='\0') lptr++; - pc_deprecate=strdup((const char *)lptr); + pc_deprecate=strdupwithouta((const char *)lptr); if (pc_deprecate!=NULL) { char *ptr=pc_deprecate+strlen(pc_deprecate)-1; /* remove trailing whitespace */ @@ -1499,7 +1542,7 @@ static int command(void) while (*lptr<=' ' && *lptr!='\0') lptr++; if (!SKIPPING) { - char *usermsg=strdup((const char *)lptr); + char *usermsg=strdupwithouta((const char *)lptr); if (usermsg!=NULL) { char *ptr=usermsg+strlen(usermsg)-1; /* remove trailing whitespace and newlines */ @@ -1893,6 +1936,10 @@ static const unsigned char *unpackedstring(const unsigned char *lptr,int *flags) while (*lptr==' ' || *lptr=='\t') /* this is as defines with parameters may add them */ lptr++; /* when you use a space after , in a match pattern */ while (*lptr!='\0') { + if (*lptr=='\a') { + lptr++; + continue; + } /* if */ if (!instring) { if (*lptr=='\"') { instring=1; @@ -1963,6 +2010,10 @@ static const unsigned char *packedstring(const unsigned char *lptr,int *flags) i=sizeof(ucell)-(sCHARBITS/8); /* start at most significant byte */ val=0; while (*lptr!='\0') { + if (*lptr=='\a') { /* ignore '\a' (which was inserted at a line concatenation) */ + lptr++; + continue; + } /* if */ if (!instring) { if (*lptr=='\"') { instring=1; @@ -2028,7 +2079,7 @@ static const unsigned char *packedstring(const unsigned char *lptr,int *flags) if (*lptr==',' || *lptr==')' || *lptr=='}' || *lptr==';' || *lptr==':' || *lptr=='\n' || *lptr=='\r') - lptr=stringize; /* backtrack to end of last string for closing " */ + lptr=stringize; /* backtrack to end of last string for closing " */ return lptr; } diff --git a/source/compiler/sc3.c b/source/compiler/sc3.c index 5895db9..719d054 100644 --- a/source/compiler/sc3.c +++ b/source/compiler/sc3.c @@ -2216,7 +2216,7 @@ static int nesting=0; if (arg[argidx].numdim!=1) { error(48); /* array dimensions must match */ } else { - if (lval.sym==NULL && (arg[argidx].usage & uCONST)==0) + if (lval.sym==NULL && (arg[argidx].usage & uCONST)==0 && (sym->usage & uNATIVE)==0) error(239); if (arg[argidx].dim[0]!=0) { assert(arg[argidx].dim[0]>0); diff --git a/source/compiler/sc4.c b/source/compiler/sc4.c index f2dd349..576c16b 100644 --- a/source/compiler/sc4.c +++ b/source/compiler/sc4.c @@ -343,9 +343,12 @@ SC_FUNC void markexpr(optmark type,const char *name,cell offset) * * Global references: funcstatus (referred to only) */ -SC_FUNC void startfunc(char *fname) +SC_FUNC void startfunc(char *fname,int generateproc) { - stgwrite("\tproc"); + if (generateproc) { + stgwrite("\tproc"); + code_idx+=opcodes(1); + } /* if */ if (sc_asmfile) { char symname[2*sNAMEMAX+16]; funcdisplayname(symname,fname); @@ -353,7 +356,6 @@ SC_FUNC void startfunc(char *fname) stgwrite(symname); } /* if */ stgwrite("\n"); - code_idx+=opcodes(1); } /* endfunc diff --git a/source/compiler/tests/CMakeLists.txt b/source/compiler/tests/CMakeLists.txt index bad72be..2cf5a31 100644 --- a/source/compiler/tests/CMakeLists.txt +++ b/source/compiler/tests/CMakeLists.txt @@ -16,12 +16,12 @@ endfunction() # doesn't match the expected pattern. add_compiler_test(gh_217 ${CMAKE_CURRENT_SOURCE_DIR}/gh_217.pwn) -set_tests_properties(gh_217 PROPERTIES PASS_REGULAR_EXPRESSION ".*\\.pwn\\(11\\) : warning 237: user warning: this is warning 1 -.*\\.pwn\\(13\\) : warning 237: user warning: this iswarning 2 -.*\\.pwn\\(15\\) : warning 237: user warning: this is warning 3 -.*\\.pwn\\(17\\) : warning 237: user warning: this is warning 4 -.*\\.pwn\\(27\\) : warning 234: function is deprecated \\(symbol \"f\"\\) don't use this functionplease -.*\\.pwn\\(32\\) : warning 234: function is deprecated \\(symbol \"f\"\\) don't use this functionplease +set_tests_properties(gh_217 PROPERTIES PASS_REGULAR_EXPRESSION ".*\\.pwn\\(11\\) : warning 237: user warning: this is warning 1 +.*\\.pwn\\(13\\) : warning 237: user warning: this is warning 2 +.*\\.pwn\\(15\\) : warning 237: user warning: this is warning 3 +.*\\.pwn\\(17\\) : warning 237: user warning: this is warning 4 +.*\\.pwn\\(28\\) : warning 234: function is deprecated \\(symbol \"f\"\\) don't use this function please +.*\\.pwn\\(33\\) : warning 234: function is deprecated \\(symbol \"f\"\\) don't use this function please ") add_compiler_test(reset_errline_gh_230 ${CMAKE_CURRENT_SOURCE_DIR}/reset_errline_gh_230.pwn) @@ -60,6 +60,16 @@ set_tests_properties(constexpr_result_prop_gh_308 PROPERTIES PASS_REGULAR_EXPRES .*\\.pwn\\(14\\) : warning 237: user warning: \\\"Test passed.\\\" ") +add_compiler_test(const_array_args_and_literals_gh_276 ${CMAKE_CURRENT_SOURCE_DIR}/const_array_args_and_literals_gh_276.pwn) +set_tests_properties(const_array_args_and_literals_gh_276 PROPERTIES PASS_REGULAR_EXPRESSION +".*\\.pwn\\(13\\) : warning 214: possibly a \\\"const\\\" array argument was intended: \\\"arr\\\" +.*\\.pwn\\(18\\) : warning 214: possibly a \\\"const\\\" array argument was intended: \\\"arr\\\" +.*\\.pwn\\(30\\) : warning 214: possibly a \\\"const\\\" array argument was intended: \\\"arr\\\" +.*\\.pwn\\(39\\) : warning 239: literal array/string passed to a non-const parameter +.*\\.pwn\\(40\\) : warning 239: literal array/string passed to a non-const parameter +.*\\.pwn\\(41\\) : warning 239: literal array/string passed to a non-const parameter +") + # Crashers # # These tests simply check that the compiler doesn't crash. diff --git a/source/compiler/tests/const_array_args_and_literals_gh_276.pwn b/source/compiler/tests/const_array_args_and_literals_gh_276.pwn new file mode 100644 index 0000000..fdc990d --- /dev/null +++ b/source/compiler/tests/const_array_args_and_literals_gh_276.pwn @@ -0,0 +1,61 @@ +forward OnDialogResponse(playerid, dialogid, response, listitem, inputtext[]); + +native SetTimer(funcname[], interval, repeating); +public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[]) +{ + +} + +f0(arr[]) { + #pragma unused arr +} + +f1(arr[]) { // line 13 + new a = arr[0]; + #pragma unused a +} + +f2(arr[5]) {// line 18 + new a = arr[0]; + #pragma unused a +} +f3(const arr[]) { + new a = arr[0]; + #pragma unused a +} +f4(const arr[5]) { + new a = arr[0]; + #pragma unused a +} +f5(arr[][]) { // line 30 + new a = arr[0][0]; + #pragma unused a +} +f6(arr[][]) { + arr[0][0] = 0; +} + +main () { + f0("test"); // line 39 + f1("test"); // line 40 + f2("test"); // line 41 + f3("test"); + f4("test"); + + new arr[5]; + f1(arr); + f2(arr); + f3(arr); + f4(arr); + + f1(arr[0]); + //f2(arr[0]); - array size must match + f3(arr[0]); + //f4(arr[0]); - array size must match + + new arr2[1][1]; + f5(arr2); + f6(arr2); + + SetTimer("test", 0, 0); +} diff --git a/source/compiler/tests/gh_217.pwn b/source/compiler/tests/gh_217.pwn index 2d2d24c..c84af2c 100644 --- a/source/compiler/tests/gh_217.pwn +++ b/source/compiler/tests/gh_217.pwn @@ -17,7 +17,8 @@ warning 3 warning 4 // single-line comments can span \ -multiple lines if you really want it +//multiple lines if you really want it +// no they can't, only with more //s. #pragma deprecated don't\ use \