aboutsummaryrefslogtreecommitdiff
path: root/lparser.c
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2018-12-04 15:01:42 -0200
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2018-12-04 15:01:42 -0200
commit28d829c86712ce5bc453feccc5129a32f78d80c0 (patch)
tree58197e763ca643bbe4a042372927bf81092b141c /lparser.c
parent6d04537ea660fd12fc16c328366b701fabaf4919 (diff)
downloadlua-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.c5
1 files changed, 4 insertions, 1 deletions
diff --git a/lparser.c b/lparser.c
index e525e578..eed8bffd 100644
--- a/lparser.c
+++ b/lparser.c
@@ -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 }