diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-12-04 15:01:42 -0200 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-12-04 15:01:42 -0200 |
commit | 28d829c86712ce5bc453feccc5129a32f78d80c0 (patch) | |
tree | 58197e763ca643bbe4a042372927bf81092b141c /lparser.c | |
parent | 6d04537ea660fd12fc16c328366b701fabaf4919 (diff) | |
download | lua-28d829c86712ce5bc453feccc5129a32f78d80c0.tar.gz lua-28d829c86712ce5bc453feccc5129a32f78d80c0.tar.bz2 lua-28d829c86712ce5bc453feccc5129a32f78d80c0.zip |
Calls cannot be tail in the scope of a to-be-closed variable
A to-be-closed variable must be closed when a block ends, so even
a 'return foo()' cannot directly returns the results of 'foo'; the
function must close the scope before returning.
Diffstat (limited to 'lparser.c')
-rw-r--r-- | lparser.c | 5 |
1 files changed, 4 insertions, 1 deletions
@@ -53,6 +53,7 @@ typedef struct BlockCnt { | |||
53 | lu_byte nactvar; /* # active locals outside the block */ | 53 | lu_byte nactvar; /* # active locals outside the block */ |
54 | lu_byte upval; /* true if some variable in the block is an upvalue */ | 54 | lu_byte upval; /* true if some variable in the block is an upvalue */ |
55 | lu_byte isloop; /* true if 'block' is a loop */ | 55 | lu_byte isloop; /* true if 'block' is a loop */ |
56 | lu_byte insidetbc; /* true if inside the scope of a to-be-closed var. */ | ||
56 | } BlockCnt; | 57 | } BlockCnt; |
57 | 58 | ||
58 | 59 | ||
@@ -510,6 +511,7 @@ static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) { | |||
510 | bl->firstlabel = fs->ls->dyd->label.n; | 511 | bl->firstlabel = fs->ls->dyd->label.n; |
511 | bl->firstgoto = fs->ls->dyd->gt.n; | 512 | bl->firstgoto = fs->ls->dyd->gt.n; |
512 | bl->upval = 0; | 513 | bl->upval = 0; |
514 | bl->insidetbc = (fs->bl != NULL && fs->bl->insidetbc); | ||
513 | bl->previous = fs->bl; | 515 | bl->previous = fs->bl; |
514 | fs->bl = bl; | 516 | fs->bl = bl; |
515 | lua_assert(fs->freereg == fs->nactvar); | 517 | lua_assert(fs->freereg == fs->nactvar); |
@@ -1631,6 +1633,7 @@ static void tocloselocalstat (LexState *ls) { | |||
1631 | checknext(ls, '='); | 1633 | checknext(ls, '='); |
1632 | exp1(ls, 0); | 1634 | exp1(ls, 0); |
1633 | markupval(fs, fs->nactvar); | 1635 | markupval(fs, fs->nactvar); |
1636 | fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */ | ||
1634 | adjustlocalvars(ls, 1); | 1637 | adjustlocalvars(ls, 1); |
1635 | luaK_codeABC(fs, OP_TBC, fs->nactvar - 1, 0, 0); | 1638 | luaK_codeABC(fs, OP_TBC, fs->nactvar - 1, 0, 0); |
1636 | } | 1639 | } |
@@ -1701,7 +1704,7 @@ static void retstat (LexState *ls) { | |||
1701 | nret = explist(ls, &e); /* optional return values */ | 1704 | nret = explist(ls, &e); /* optional return values */ |
1702 | if (hasmultret(e.k)) { | 1705 | if (hasmultret(e.k)) { |
1703 | luaK_setmultret(fs, &e); | 1706 | luaK_setmultret(fs, &e); |
1704 | if (e.k == VCALL && nret == 1) { /* tail call? */ | 1707 | if (e.k == VCALL && nret == 1 && !fs->bl->insidetbc) { /* tail call? */ |
1705 | SET_OPCODE(getinstruction(fs,&e), OP_TAILCALL); | 1708 | SET_OPCODE(getinstruction(fs,&e), OP_TAILCALL); |
1706 | lua_assert(GETARG_A(getinstruction(fs,&e)) == fs->nactvar); | 1709 | lua_assert(GETARG_A(getinstruction(fs,&e)) == fs->nactvar); |
1707 | } | 1710 | } |