From 6592db03fd2ac7969ec983a2ddd1eea6b95f5795 Mon Sep 17 00:00:00 2001 From: Zeex Date: Fri, 3 Jan 2014 21:57:54 +0700 Subject: [PATCH] Force a reparse when encountering a late forward This hopefully fixes a bug where code for a custom assignment operator wasn't being generated because the compiler thought that it's not used but it still generated a call (which resulting in infinite recursion). It happened only if some function returned a tagged result and wasn't forwarded before its first use. Interestingly the compiler didn't issue a reparse when it encountered the forward declaration and no warning was printed. Perhaps the authors forgot to do this when they were adding the forward syntax (it certainly was added after what is now called "old-style prototypes"). See 8) here: http://forum.sa-mp.com/showthread.php?t=355877 --------- test code -------- #include _:operator=(Taggg:a) { return _:a + 5; } main() { new a = d(); printf("%d", a); } forward Taggg:d(); Taggg:d() { return Taggg:5; } ----- end of test code ----- --- source/compiler/sc1.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/source/compiler/sc1.c b/source/compiler/sc1.c index a7426e9..50dabeb 100644 --- a/source/compiler/sc1.c +++ b/source/compiler/sc1.c @@ -3257,6 +3257,23 @@ SC_FUNC char *funcdisplayname(char *dest,char *funcname) return dest; } +static void check_reparse(symbol *sym) +{ + /* if the function was used before being declared, and it has a tag for the + * result, add a third pass (as second "skimming" parse) because the function + * result may have been used with user-defined operators, which have now + * been incorrectly flagged (as the return tag was unknown at the time of + * the call) + */ + if ((sym->usage & (uPROTOTYPED | uREAD))==uREAD && sym->tag!=0) { + int curstatus=sc_status; + sc_status=statWRITE; /* temporarily set status to WRITE, so the warning isn't blocked */ + error(208); + sc_status=curstatus; + sc_reparse=TRUE; /* must add another pass to "initial scan" phase */ + } /* if */ +} + static void funcstub(int fnative) { int tok,tag,fpublic; @@ -3328,6 +3345,7 @@ static void funcstub(int fnative) sym->usage|=uPUBLIC; } /* if */ sym->usage|=uFORWARD; + check_reparse(sym); declargs(sym,FALSE); /* "declargs()" found the ")" */ @@ -3454,19 +3472,7 @@ static int newfunc(char *firstname,int firsttag,int fpublic,int fstatic,int stoc sym->usage|=uPUBLIC; if (fstatic) sym->fnumber=filenum; - /* if the function was used before being declared, and it has a tag for the - * result, add a third pass (as second "skimming" parse) because the function - * result may have been used with user-defined operators, which have now - * been incorrectly flagged (as the return tag was unknown at the time of - * the call) - */ - if ((sym->usage & (uPROTOTYPED | uREAD))==uREAD && sym->tag!=0) { - int curstatus=sc_status; - sc_status=statWRITE; /* temporarily set status to WRITE, so the warning isn't blocked */ - error(208); - sc_status=curstatus; - sc_reparse=TRUE; /* must add another pass to "initial scan" phase */ - } /* if */ + check_reparse(sym); /* we want public functions to be explicitly prototyped, as they are called * from the outside */