aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lfunc.c22
-rw-r--r--manual/manual.of11
-rw-r--r--testes/locals.lua21
3 files changed, 32 insertions, 22 deletions
diff --git a/lfunc.c b/lfunc.c
index 68d0632a..cd85cc1f 100644
--- a/lfunc.c
+++ b/lfunc.c
@@ -133,7 +133,8 @@ static int prepclosingmethod (lua_State *L, TValue *obj, TValue *err) {
133** the 'level' of the upvalue being closed, as everything after 133** the 'level' of the upvalue being closed, as everything after
134** that won't be used again. 134** that won't be used again.
135*/ 135*/
136static int callclosemth (lua_State *L, TValue *uv, StkId level, int status) { 136static int callclosemth (lua_State *L, StkId level, int status) {
137 TValue *uv = s2v(level); /* value being closed */
137 if (likely(status == LUA_OK)) { 138 if (likely(status == LUA_OK)) {
138 if (prepclosingmethod(L, uv, &G(L)->nilvalue)) /* something to call? */ 139 if (prepclosingmethod(L, uv, &G(L)->nilvalue)) /* something to call? */
139 callclose(L, NULL); /* call closing method */ 140 callclose(L, NULL); /* call closing method */
@@ -145,9 +146,10 @@ static int callclosemth (lua_State *L, TValue *uv, StkId level, int status) {
145 } 146 }
146 } 147 }
147 else { /* must close the object in protected mode */ 148 else { /* must close the object in protected mode */
148 ptrdiff_t oldtop = savestack(L, level + 1); 149 ptrdiff_t oldtop;
149 /* save error message and set stack top to 'level + 1' */ 150 level++; /* space for error message */
150 luaD_seterrorobj(L, status, level); 151 oldtop = savestack(L, level + 1); /* top will be after that */
152 luaD_seterrorobj(L, status, level); /* set error message */
151 if (prepclosingmethod(L, uv, s2v(level))) { /* something to call? */ 153 if (prepclosingmethod(L, uv, s2v(level))) { /* something to call? */
152 int newstatus = luaD_pcall(L, callclose, NULL, oldtop, 0); 154 int newstatus = luaD_pcall(L, callclose, NULL, oldtop, 0);
153 if (newstatus != LUA_OK && status == CLOSEPROTECT) /* first error? */ 155 if (newstatus != LUA_OK && status == CLOSEPROTECT) /* first error? */
@@ -203,18 +205,18 @@ int luaF_close (lua_State *L, StkId level, int status) {
203 StkId upl = uplevel(uv); 205 StkId upl = uplevel(uv);
204 TValue *slot = &uv->u.value; /* new position for value */ 206 TValue *slot = &uv->u.value; /* new position for value */
205 lua_assert(upl < L->top); 207 lua_assert(upl < L->top);
208 if (uv->tt == LUA_TUPVALTBC && status != NOCLOSINGMETH) {
209 /* must run closing method */
210 ptrdiff_t levelrel = savestack(L, level);
211 status = callclosemth(L, upl, status); /* may change the stack */
212 level = restorestack(L, levelrel);
213 }
206 luaF_unlinkupval(uv); 214 luaF_unlinkupval(uv);
207 setobj(L, slot, uv->v); /* move value to upvalue slot */ 215 setobj(L, slot, uv->v); /* move value to upvalue slot */
208 uv->v = slot; /* now current value lives here */ 216 uv->v = slot; /* now current value lives here */
209 if (!iswhite(uv)) 217 if (!iswhite(uv))
210 gray2black(uv); /* closed upvalues cannot be gray */ 218 gray2black(uv); /* closed upvalues cannot be gray */
211 luaC_barrier(L, uv, slot); 219 luaC_barrier(L, uv, slot);
212 if (uv->tt == LUA_TUPVALTBC && status != NOCLOSINGMETH) {
213 /* must run closing method */
214 ptrdiff_t levelrel = savestack(L, level);
215 status = callclosemth(L, uv->v, upl, status); /* may change the stack */
216 level = restorestack(L, levelrel);
217 }
218 } 220 }
219 return status; 221 return status;
220} 222}
diff --git a/manual/manual.of b/manual/manual.of
index 61fcdaa3..3d2fb4fb 100644
--- a/manual/manual.of
+++ b/manual/manual.of
@@ -1548,14 +1548,15 @@ they are closed in the reverse order that they were declared.
1548 1548
1549If there is any error while running a closing method, 1549If there is any error while running a closing method,
1550that error is handled like an error in the regular code 1550that error is handled like an error in the regular code
1551where the variable was defined; 1551where the variable was defined.
1552in particular, 1552However, Lua may call the method one more time.
1553the other pending closing methods will still be called. 1553
1554After an error, 1554After an error,
1555other errors in closing methods 1555the other pending closing methods will still be called.
1556Errors in these methods
1556interrupt the respective method, 1557interrupt the respective method,
1557but are otherwise ignored; 1558but are otherwise ignored;
1558the error reported is the original one. 1559the error reported is only the original one.
1559 1560
1560If a coroutine yields and is never resumed again, 1561If a coroutine yields and is never resumed again,
1561some variables may never go out of scope, 1562some variables may never go out of scope,
diff --git a/testes/locals.lua b/testes/locals.lua
index 1b82dd7f..73267d02 100644
--- a/testes/locals.lua
+++ b/testes/locals.lua
@@ -295,18 +295,23 @@ do -- errors in __close
295 local <toclose> y = 295 local <toclose> y =
296 func2close(function (self, msg) log[#log + 1] = msg; error(2) end) 296 func2close(function (self, msg) log[#log + 1] = msg; error(2) end)
297 local <toclose> z = 297 local <toclose> z =
298 func2close(function (self, msg) log[#log + 1] = msg or 10; error(3) end) 298 func2close(function (self, msg)
299 log[#log + 1] = (msg or 10) + 1;
300 error(3)
301 end)
299 if err then error(4) end 302 if err then error(4) end
300 end 303 end
301 local stat, msg = pcall(foo, false) 304 local stat, msg = pcall(foo, false)
302 assert(msg == 3) 305 assert(msg == 3)
303 assert(log[1] == 10 and log[2] == 3 and log[3] == 3 and log[4] == 3 306 -- 'z' close is called twice
304 and #log == 4) 307 assert(log[1] == 11 and log[2] == 4 and log[3] == 3 and log[4] == 3
308 and log[5] == 3 and #log == 5)
305 309
306 log = {} 310 log = {}
307 local stat, msg = pcall(foo, true) 311 local stat, msg = pcall(foo, true)
308 assert(msg == 4) 312 assert(msg == 4)
309 assert(log[1] == 4 and log[2] == 4 and log[3] == 4 and log[4] == 4 313 -- 'z' close is called once
314 assert(log[1] == 5 and log[2] == 4 and log[3] == 4 and log[4] == 4
310 and #log == 4) 315 and #log == 4)
311 316
312 -- error in toclose in vararg function 317 -- error in toclose in vararg function
@@ -495,15 +500,17 @@ do
495 local st, msg = pcall(co); assert(x == 2) 500 local st, msg = pcall(co); assert(x == 2)
496 assert(not st and msg == 200) -- should get first error raised 501 assert(not st and msg == 200) -- should get first error raised
497 502
498 x = 0 503 local x = 0
504 local y = 0
499 co = coroutine.wrap(function () 505 co = coroutine.wrap(function ()
500 local <toclose> xx = func2close(function () x = x + 1; error("YYY") end) 506 local <toclose> xx = func2close(function () y = y + 1; error("YYY") end)
501 local <toclose> xv = func2close(function () x = x + 1; error("XXX") end) 507 local <toclose> xv = func2close(function () x = x + 1; error("XXX") end)
502 coroutine.yield(100) 508 coroutine.yield(100)
503 return 200 509 return 200
504 end) 510 end)
505 assert(co() == 100); assert(x == 0) 511 assert(co() == 100); assert(x == 0)
506 local st, msg = pcall(co); assert(x == 2) 512 local st, msg = pcall(co)
513 assert(x == 2 and y == 1) -- first close is called twice
507 -- should get first error raised 514 -- should get first error raised
508 assert(not st and string.find(msg, "%w+%.%w+:%d+: XXX")) 515 assert(not st and string.find(msg, "%w+%.%w+:%d+: XXX"))
509end 516end