diff --git a/lapi.c b/lapi.c
index dbd291d7..70e2a44a 100644
--- a/lapi.c
+++ b/lapi.c
@@ -207,7 +207,7 @@ LUA_API void lua_settop (lua_State *L, int idx) {
   }
   newtop = L->top.p + diff;
   if (diff < 0 && L->tbclist.p >= newtop) {
-    lua_assert(hastocloseCfunc(ci->nresults));
+    lua_assert(ci->callstatus & CIST_CLSRET);
     newtop = luaF_close(L, newtop, CLOSEKTOP, 0);
   }
   L->top.p = newtop;  /* correct top only after closing any upvalue */
@@ -219,7 +219,7 @@ LUA_API void lua_closeslot (lua_State *L, int idx) {
   StkId level;
   lua_lock(L);
   level = index2stack(L, idx);
-  api_check(L, hastocloseCfunc(L->ci->nresults) && L->tbclist.p == level,
+  api_check(L, (L->ci->callstatus & CIST_CLSRET) && L->tbclist.p == level,
      "no variable to close at given level");
   level = luaF_close(L, level, CLOSEKTOP, 0);
   setnilvalue(s2v(level));
@@ -1287,9 +1287,7 @@ LUA_API void lua_toclose (lua_State *L, int idx) {
   nresults = L->ci->nresults;
   api_check(L, L->tbclist.p < o, "given index below or equal a marked one");
   luaF_newtbcupval(L, o);  /* create new to-be-closed upvalue */
-  if (!hastocloseCfunc(nresults))  /* function not marked yet? */
-    L->ci->nresults = codeNresults(nresults);  /* mark it */
-  lua_assert(hastocloseCfunc(L->ci->nresults));
+  L->ci->callstatus |= CIST_CLSRET;  /* mark that function has TBC slots */
   lua_unlock(L);
 }
 
diff --git a/lapi.h b/lapi.h
index 21be4a24..9b545344 100644
--- a/lapi.h
+++ b/lapi.h
@@ -62,20 +62,4 @@
                      L->tbclist.p < L->top.p - (n), \
 			  "not enough free elements in the stack")
 
-
-/*
-** To reduce the overhead of returning from C functions, the presence of
-** to-be-closed variables in these functions is coded in the CallInfo's
-** field 'nresults', in a way that functions with no to-be-closed variables
-** with zero, one, or "all" wanted results have no overhead. Functions
-** with other number of wanted results, as well as functions with
-** variables to be closed, have an extra check.
-*/
-
-#define hastocloseCfunc(n)	((n) < LUA_MULTRET)
-
-/* Map [-1, inf) (range of 'nresults') into (-inf, -2] */
-#define codeNresults(n)		(-(n) - 3)
-#define decodeNresults(n)	(-(n) - 3)
-
 #endif
diff --git a/ldo.c b/ldo.c
index 34101ba3..6eaa31a0 100644
--- a/ldo.c
+++ b/ldo.c
@@ -462,22 +462,23 @@ l_sinline void moveresults (lua_State *L, StkId res, int nres, int wanted) {
   StkId firstresult;
   int i;
   switch (wanted) {  /* handle typical cases separately */
-    case 0:  /* no values needed */
+    case 0 + 1:  /* no values needed */
       L->top.p = res;
       return;
-    case 1:  /* one value needed */
+    case 1 + 1:  /* one value needed */
       if (nres == 0)   /* no results? */
         setnilvalue(s2v(res));  /* adjust with nil */
       else  /* at least one result */
         setobjs2s(L, res, L->top.p - nres);  /* move it to proper place */
       L->top.p = res + 1;
       return;
-    case LUA_MULTRET:
+    case LUA_MULTRET + 1:
       wanted = nres;  /* we want all results */
       break;
     default:  /* two/more results and/or to-be-closed variables */
-      if (hastocloseCfunc(wanted)) {  /* to-be-closed variables? */
-        L->ci->callstatus |= CIST_CLSRET;  /* in case of yields */
+      if (!(wanted & CIST_CLSRET))
+        wanted--;
+      else {  /* to-be-closed variables? */
         L->ci->u2.nres = nres;
         res = luaF_close(L, res, CLOSEKTOP, 1);
         L->ci->callstatus &= ~CIST_CLSRET;
@@ -486,7 +487,7 @@ l_sinline void moveresults (lua_State *L, StkId res, int nres, int wanted) {
           rethook(L, L->ci, nres);
           res = restorestack(L, savedres);  /* hook can move stack */
         }
-        wanted = decodeNresults(wanted);
+        wanted = (wanted & ~CIST_CLSRET) - 1;
         if (wanted == LUA_MULTRET)
           wanted = nres;  /* we want all results */
       }
@@ -511,8 +512,10 @@ l_sinline void moveresults (lua_State *L, StkId res, int nres, int wanted) {
 ** that.
 */
 void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
-  int wanted = ci->nresults;
-  if (l_unlikely(L->hookmask && !hastocloseCfunc(wanted)))
+  int wanted = ci->nresults + 1;
+  if (ci->callstatus & CIST_CLSRET)
+    wanted |= CIST_CLSRET;  /* don't check hook in this case */
+  else if (l_unlikely(L->hookmask))
     rethook(L, ci, nres);
   /* move results to proper place */
   moveresults(L, ci->func.p, nres, wanted);
@@ -736,7 +739,6 @@ static int finishpcallk (lua_State *L,  CallInfo *ci) {
 static void finishCcall (lua_State *L, CallInfo *ci) {
   int n;  /* actual number of results from C function */
   if (ci->callstatus & CIST_CLSRET) {  /* was returning? */
-    lua_assert(hastocloseCfunc(ci->nresults));
     n = ci->u2.nres;  /* just redo 'luaD_poscall' */
     /* don't need to reset CIST_CLSRET, as it will be set again anyway */
   }
diff --git a/testes/api.lua b/testes/api.lua
index dc485240..ae2f82dd 100644
--- a/testes/api.lua
+++ b/testes/api.lua
@@ -165,6 +165,23 @@ do  -- test returning more results than fit in the caller stack
 end
 
 
+do  -- testing multipe returns
+  local function foo (n)
+    if n > 0 then return n, foo(n - 1) end
+  end
+
+  local t = {T.testC("call 1 10; return 10", foo, 20)}
+  assert(t[1] == 20 and t[10] == 11 and t[11] == nil)
+
+  local t = table.pack(T.testC("call 1 10; return 10", foo, 2))
+  assert(t[1] == 2 and t[2] == 1 and t[3] == nil and t.n == 10)
+
+  local t = {T.testC([[
+    checkstack 300 "error"; call 1 250; return 250]], foo, 250)}
+  assert(t[1] == 250 and t[250] == 1 and t[251] == nil)
+end
+
+
 -- testing globals
 _G.AA = 14; _G.BB = "a31"
 local a = {T.testC[[