Skip to content

Commit

Permalink
Force a reparse when encountering a late forward
Browse files Browse the repository at this point in the history
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 <a_samp>

_: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 -----
  • Loading branch information
Zeex committed Jan 3, 2014
1 parent 1d1244c commit 6592db0
Showing 1 changed file with 19 additions and 13 deletions.
32 changes: 19 additions & 13 deletions source/compiler/sc1.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 ")" */
Expand Down Expand Up @@ -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
*/
Expand Down

0 comments on commit 6592db0

Please sign in to comment.