summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2021-04-07 14:59:26 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2021-04-07 14:59:26 -0300
commit47cffdc723c2e0c6dfaf62b7775ca1c1d338c0a4 (patch)
tree54d46a0530aa2ee09db66d57c66bd313a5de530e
parent36de01d9885562444ae2e2a3e0b7e01b3fb8743b (diff)
downloadlua-github-47cffdc723c2e0c6dfaf62b7775ca1c1d338c0a4.tar.gz
Bug: tbc variables in "for" loops don't avoid tail calls
-rw-r--r--lparser.c21
-rw-r--r--testes/locals.lua23
2 files changed, 38 insertions, 6 deletions
diff --git a/lparser.c b/lparser.c
index 284ef1f0..df9473c2 100644
--- a/lparser.c
+++ b/lparser.c
@@ -417,6 +417,17 @@ static void markupval (FuncState *fs, int level) {
/*
+** Mark that current block has a to-be-closed variable.
+*/
+static void marktobeclosed (FuncState *fs) {
+ BlockCnt *bl = fs->bl;
+ bl->upval = 1;
+ bl->insidetbc = 1;
+ fs->needclose = 1;
+}
+
+
+/*
** Find a variable with the given name 'n'. If it is an upvalue, add
** this upvalue into all intermediate functions. If it is a global, set
** 'var' as 'void' as a flag.
@@ -1599,7 +1610,7 @@ static void forlist (LexState *ls, TString *indexname) {
line = ls->linenumber;
adjust_assign(ls, 4, explist(ls, &e), &e);
adjustlocalvars(ls, 4); /* control variables */
- markupval(fs, fs->nactvar); /* last control var. must be closed */
+ marktobeclosed(fs); /* last control var. must be closed */
luaK_checkstack(fs, 3); /* extra space to call generator */
forbody(ls, base, line, nvars - 4, 1);
}
@@ -1703,11 +1714,9 @@ static int getlocalattribute (LexState *ls) {
}
-static void checktoclose (LexState *ls, int level) {
+static void checktoclose (FuncState *fs, int level) {
if (level != -1) { /* is there a to-be-closed variable? */
- FuncState *fs = ls->fs;
- markupval(fs, level + 1);
- fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */
+ marktobeclosed(fs);
luaK_codeABC(fs, OP_TBC, reglevel(fs, level), 0, 0);
}
}
@@ -1751,7 +1760,7 @@ static void localstat (LexState *ls) {
adjust_assign(ls, nvars, nexps, &e);
adjustlocalvars(ls, nvars);
}
- checktoclose(ls, toclose);
+ checktoclose(fs, toclose);
}
diff --git a/testes/locals.lua b/testes/locals.lua
index 2c67edbd..6aad5d25 100644
--- a/testes/locals.lua
+++ b/testes/locals.lua
@@ -335,6 +335,29 @@ do
end
+do
+ -- bug in 5.4.3: previous condition (calls cannot be tail in the
+ -- scope of to-be-closed variables) must be valid for tbc variables
+ -- created by 'for' loops.
+
+ local closed = false
+
+ local function foo ()
+ return function () return true end, 0, 0,
+ func2close(function () closed = true end)
+ end
+
+ local function tail() return closed end
+
+ local function foo1 ()
+ for k in foo() do return tail() end
+ end
+
+ assert(foo1() == false)
+ assert(closed == true)
+end
+
+
do print("testing errors in __close")
-- original error is in __close