summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lauxlib.c4
-rw-r--r--lfunc.c6
-rw-r--r--lgc.c7
-rw-r--r--lstate.c16
-rw-r--r--lstate.h1
-rw-r--r--ltests.c10
-rw-r--r--manual/manual.of2
-rw-r--r--testes/all.lua4
-rw-r--r--testes/coroutine.lua5
-rw-r--r--testes/locals.lua152
10 files changed, 164 insertions, 43 deletions
diff --git a/lauxlib.c b/lauxlib.c
index ba1980b7..014e7052 100644
--- a/lauxlib.c
+++ b/lauxlib.c
@@ -1010,9 +1010,9 @@ static int panic (lua_State *L) {
static void warnf (void *ud, const char *message, int tocont) {
int *warnstate = (int *)ud;
if (*warnstate != 2 && !tocont && *message == '@') { /* control message? */
- if (strcmp(message + 1, "off") == 0)
+ if (strcmp(message, "@off") == 0)
*warnstate = 0;
- else if (strcmp(message + 1, "on") == 0)
+ else if (strcmp(message, "@on") == 0)
*warnstate = 1;
return;
}
diff --git a/lfunc.c b/lfunc.c
index 8f39f6b0..1e61f03f 100644
--- a/lfunc.c
+++ b/lfunc.c
@@ -164,8 +164,12 @@ static int callclosemth (lua_State *L, StkId level, int status) {
int newstatus = luaD_pcall(L, callclose, NULL, oldtop, 0);
if (newstatus != LUA_OK && status == CLOSEPROTECT) /* first error? */
status = newstatus; /* this will be the new error */
- else /* leave original error (or nil) on top */
+ else {
+ if (newstatus != LUA_OK) /* supressed error? */
+ luaE_warnerror(L, "__close metamethod");
+ /* leave original error (or nil) on top */
L->top = restorestack(L, oldtop);
+ }
}
/* else no metamethod; ignore this case and keep original error */
}
diff --git a/lgc.c b/lgc.c
index 75670c0a..f24074f9 100644
--- a/lgc.c
+++ b/lgc.c
@@ -854,12 +854,7 @@ static void GCTM (lua_State *L) {
L->allowhook = oldah; /* restore hooks */
g->gcrunning = running; /* restore state */
if (unlikely(status != LUA_OK)) { /* error while running __gc? */
- const char *msg = (ttisstring(s2v(L->top - 1)))
- ? svalue(s2v(L->top - 1))
- : "error object is not a string";
- luaE_warning(L, "error in __gc metamethod (", 1);
- luaE_warning(L, msg, 1);
- luaE_warning(L, ")", 0);
+ luaE_warnerror(L, "__gc metamethod");
L->top--; /* pops error object */
}
}
diff --git a/lstate.c b/lstate.c
index d4bc53eb..86cd5fb8 100644
--- a/lstate.c
+++ b/lstate.c
@@ -443,3 +443,19 @@ void luaE_warning (lua_State *L, const char *msg, int tocont) {
}
+/*
+** Generate a warning from an error message
+*/
+void luaE_warnerror (lua_State *L, const char *where) {
+ TValue *errobj = s2v(L->top - 1); /* error object */
+ const char *msg = (ttisstring(errobj))
+ ? svalue(errobj)
+ : "error object is not a string";
+ /* produce warning "error in %s (%s)" (where, msg) */
+ luaE_warning(L, "error in ", 1);
+ luaE_warning(L, where, 1);
+ luaE_warning(L, " (", 1);
+ luaE_warning(L, msg, 1);
+ luaE_warning(L, ")", 0);
+}
+
diff --git a/lstate.h b/lstate.h
index 03448b82..638c1e5c 100644
--- a/lstate.h
+++ b/lstate.h
@@ -355,6 +355,7 @@ LUAI_FUNC void luaE_freeCI (lua_State *L);
LUAI_FUNC void luaE_shrinkCI (lua_State *L);
LUAI_FUNC void luaE_enterCcall (lua_State *L);
LUAI_FUNC void luaE_warning (lua_State *L, const char *msg, int tocont);
+LUAI_FUNC void luaE_warnerror (lua_State *L, const char *where);
#define luaE_exitCcall(L) ((L)->nCcalls++)
diff --git a/ltests.c b/ltests.c
index fd55fc31..b460d018 100644
--- a/ltests.c
+++ b/ltests.c
@@ -95,15 +95,15 @@ static void warnf (void *ud, const char *msg, int tocont) {
if (!lasttocont && !tocont && *msg == '@') { /* control message? */
if (buff[0] != '\0')
badexit("Control warning during warning: %s\naborting...\n", msg);
- if (strcmp(msg + 1, "off") == 0)
+ if (strcmp(msg, "@off") == 0)
onoff = 0;
- else if (strcmp(msg + 1, "on") == 0)
+ else if (strcmp(msg, "@on") == 0)
onoff = 1;
- else if (strcmp(msg + 1, "normal") == 0)
+ else if (strcmp(msg, "@normal") == 0)
mode = 0;
- else if (strcmp(msg + 1, "allow") == 0)
+ else if (strcmp(msg, "@allow") == 0)
mode = 1;
- else if (strcmp(msg + 1, "store") == 0)
+ else if (strcmp(msg, "@store") == 0)
mode = 2;
else
badexit("Invalid control warning in test mode: %s\naborting...\n", msg);
diff --git a/manual/manual.of b/manual/manual.of
index 8c71c613..bb6ae884 100644
--- a/manual/manual.of
+++ b/manual/manual.of
@@ -1556,7 +1556,7 @@ However, Lua may call the method one more time.
After an error,
the other pending closing methods will still be called.
Errors in these methods
-interrupt the respective method,
+interrupt the respective method and generate a warning,
but are otherwise ignored;
the error reported is only the original one.
diff --git a/testes/all.lua b/testes/all.lua
index 5d698d4b..42809b9a 100644
--- a/testes/all.lua
+++ b/testes/all.lua
@@ -209,12 +209,12 @@ if #msgs > 0 then
warn("#tests not performed:\n ", m, "\n")
end
+print("(there should be two warnings now)")
+warn("#This is ", "an expected", " warning")
warn("@off")
warn("******** THIS WARNING SHOULD NOT APPEAR **********")
warn("******** THIS WARNING ALSO SHOULD NOT APPEAR **********")
warn("@on")
-print("(there should be two warnings now)")
-warn("#This is ", "an expected", " warning")
warn("#This is", " another one")
-- no test module should define 'debug'
diff --git a/testes/coroutine.lua b/testes/coroutine.lua
index 457374ca..79c72a9d 100644
--- a/testes/coroutine.lua
+++ b/testes/coroutine.lua
@@ -168,7 +168,7 @@ do
local y <close> = func2close(function (self,err)
if (err ~= 111) then os.exit(false) end -- should not happen
x = 200
- error(200)
+ error("200")
end)
local x <close> = func2close(function (self, err)
assert(err == nil); error(111)
@@ -177,7 +177,10 @@ do
end)
coroutine.resume(co)
assert(x == 0)
+ _WARN = nil; warn("@off"); warn("@store")
local st, msg = coroutine.close(co)
+ warn("@on"); warn("@normal")
+ assert(_WARN == nil or string.find(_WARN, "200"))
assert(st == false and coroutine.status(co) == "dead" and msg == 111)
assert(x == 200)
diff --git a/testes/locals.lua b/testes/locals.lua
index 99fa79cd..595e107a 100644
--- a/testes/locals.lua
+++ b/testes/locals.lua
@@ -286,57 +286,149 @@ do
end
-do -- errors in __close
- local log = {}
- local function foo (err)
+-- auxiliary functions for testing warnings in '__close'
+local function prepwarn ()
+ warn("@off") -- do not show (lots of) warnings
+ if not T then
+ _WARN = "OFF" -- signal that warnings are not being captured
+ else
+ warn("@store") -- to test the warnings
+ end
+end
+
+
+local function endwarn ()
+ assert(T or _WARN == "OFF")
+ warn("@on") -- back to normal
+ warn("@normal")
+ _WARN = nil
+end
+
+
+local function checkwarn (msg)
+ assert(_WARN == "OFF" or string.find(_WARN, msg))
+end
+
+
+do print("testing errors in __close")
+
+ prepwarn()
+
+ -- original error is in __close
+ local function foo ()
+
local x <close> =
- func2close(function (self, msg) log[#log + 1] = msg; error(1) end)
+ func2close(function (self, msg)
+ assert(string.find(msg, "@z"))
+ error("@x")
+ end)
+
local x1 <close> =
- func2close(function (self, msg) log[#log + 1] = msg; end)
+ func2close(function (self, msg)
+ checkwarn("@y")
+ assert(string.find(msg, "@z"))
+ end)
+
local gc <close> = func2close(function () collectgarbage() end)
+
local y <close> =
- func2close(function (self, msg) log[#log + 1] = msg; error(2) end)
+ func2close(function (self, msg)
+ assert(string.find(msg, "@z")) -- error in 'z'
+ error("@y")
+ end)
+
+ local first = true
local z <close> =
+ -- 'z' close is called twice
func2close(function (self, msg)
- log[#log + 1] = (msg or 10) + 1;
- error(3)
+ if first then
+ assert(msg == nil)
+ first = false
+ else
+ assert(string.find(msg, "@z")) -- own error
+ end
+ error("@z")
end)
- if err then error(4) end
+
+ return 200
end
+
local stat, msg = pcall(foo, false)
- assert(msg == 3)
- -- 'z' close is called twice
- assert(log[1] == 11 and log[2] == 4 and log[3] == 3 and log[4] == 3
- and log[5] == 3 and #log == 5)
+ assert(string.find(msg, "@z"))
+ checkwarn("@x")
+
+
+ -- original error not in __close
+ local function foo ()
+
+ local x <close> =
+ func2close(function (self, msg)
+ assert(msg == 4)
+ end)
+
+ local x1 <close> =
+ func2close(function (self, msg)
+ checkwarn("@y")
+ assert(msg == 4)
+ error("@x1")
+ end)
+
+ local gc <close> = func2close(function () collectgarbage() end)
+
+ local y <close> =
+ func2close(function (self, msg)
+ assert(msg == 4) -- error in body
+ error("@y")
+ end)
+
+ local first = true
+ local z <close> =
+ func2close(function (self, msg)
+ checkwarn("@z")
+ -- 'z' close is called once
+ assert(first and msg == 4)
+ first = false
+ error("@z")
+ end)
+
+ error(4) -- original error
+ end
- log = {}
local stat, msg = pcall(foo, true)
assert(msg == 4)
- -- 'z' close is called once
- assert(log[1] == 5 and log[2] == 4 and log[3] == 4 and log[4] == 4
- and #log == 4)
+ checkwarn("@x1") -- last error
-- error leaving a block
local function foo (...)
do
- local x1 <close> = func2close(function () error("Y") end)
- local x123 <close> = func2close(function () error("X") end)
+ local x1 <close> =
+ func2close(function ()
+ checkwarn("@X")
+ error("@Y")
+ end)
+
+ local x123 <close> =
+ func2close(function ()
+ error("@X")
+ end)
end
+ os.exit(false) -- should not run
end
local st, msg = xpcall(foo, debug.traceback)
- assert(string.match(msg, "^[^ ]* X"))
+ assert(string.match(msg, "^[^ ]* @X"))
assert(string.find(msg, "in metamethod 'close'"))
-- error in toclose in vararg function
local function foo (...)
- local x123 <close> = func2close(function () error("X") end)
+ local x123 <close> = func2close(function () error("@X") end)
end
local st, msg = xpcall(foo, debug.traceback)
- assert(string.match(msg, "^[^ ]* X"))
+ assert(string.match(msg, "^[^ ]* @X"))
assert(string.find(msg, "in metamethod 'close'"))
+ endwarn()
end
@@ -361,6 +453,8 @@ end
if rawget(_G, "T") then
+ warn("@off")
+
-- memory error inside closing function
local function foo ()
local y <close> = func2close(function () T.alloccount() end)
@@ -437,7 +531,7 @@ if rawget(_G, "T") then
local s = string.rep("a", lim)
- -- concat this table needs two buffer resizes (one for each 's')
+ -- concat this table needs two buffer resizes (one for each 's')
local a = {s, s}
collectgarbage()
@@ -472,6 +566,8 @@ if rawget(_G, "T") then
print'+'
end
+
+ warn("@on")
end
@@ -501,17 +597,20 @@ end
do
+ prepwarn()
+
-- error in a wrapped coroutine raising errors when closing a variable
local x = 0
local co = coroutine.wrap(function ()
- local xx <close> = func2close(function () x = x + 1; error("YYY") end)
- local xv <close> = func2close(function () x = x + 1; error("XXX") end)
+ local xx <close> = func2close(function () x = x + 1; error("@YYY") end)
+ local xv <close> = func2close(function () x = x + 1; error("@XXX") end)
coroutine.yield(100)
error(200)
end)
assert(co() == 100); assert(x == 0)
local st, msg = pcall(co); assert(x == 2)
assert(not st and msg == 200) -- should get first error raised
+ checkwarn("@YYY")
local x = 0
local y = 0
@@ -526,6 +625,9 @@ do
assert(x == 2 and y == 1) -- first close is called twice
-- should get first error raised
assert(not st and string.find(msg, "%w+%.%w+:%d+: XXX"))
+ checkwarn("YYY")
+
+ endwarn()
end