]> granicus.if.org Git - vim/commitdiff
patch 8.2.4573: a nested function is compiled for debugging without context v8.2.4573
authorBram Moolenaar <Bram@vim.org>
Tue, 15 Mar 2022 15:57:04 +0000 (15:57 +0000)
committerBram Moolenaar <Bram@vim.org>
Tue, 15 Mar 2022 15:57:04 +0000 (15:57 +0000)
Problem:    A nested function (closure) is compiled for debugging without
            context.
Solution:   Check if a nested function is marked for debugging before
            compiling it.  Give an error when trying to compile a closure
            without its context. (closes #9951)

src/errors.h
src/proto/vim9execute.pro
src/version.c
src/vim9compile.c
src/vim9execute.c
src/vim9expr.c

index b021f820470f8f6212e7a4649e0d6986caaaaf07..b8e94197944e40b5a81217151011912e8e6b461e 100644 (file)
@@ -3249,3 +3249,7 @@ EXTERN char e_cannot_create_vim9_script_variable_in_function_str[]
 #endif
 EXTERN char e_cannot_use_s_backslash_in_vim9_script[]
        INIT(= N_("E1270: Cannot use :s\\/sub/ in Vim9 script"));
+#ifdef FEAT_EVAL
+EXTERN char e_compiling_closure_without_context_str[]
+       INIT(= N_("E1271: compiling closure without context: %s"));
+#endif
index 6f42fc8655073064365ff297d3f4c931dfbe5f76..bd670929157fa388e231a877375c14e7c0678597 100644 (file)
@@ -1,5 +1,6 @@
 /* vim9execute.c */
 void to_string_error(vartype_T vartype);
+void update_has_breakpoint(ufunc_T *ufunc);
 void funcstack_check_refcount(funcstack_T *funcstack);
 int set_ref_in_funcstacks(int copyID);
 char_u *char_from_string(char_u *str, varnumber_T index);
index d9752fd101719a509615186125cb3b993ad27402..9e5e142fd295e6c00af84e60b7f3d780ba0454d1 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    4573,
 /**/
     4572,
 /**/
index 696301f0f2c14b684a2d79608238845282fa8234..d8119c566576f9bc9498bb01c2913b44ba479592 100644 (file)
@@ -913,6 +913,7 @@ compile_nested_function(exarg_T *eap, cctx_T *cctx, garray_T *lines_to_free)
        }
     }
 
+    update_has_breakpoint(ufunc);
     compile_type = COMPILE_TYPE(ufunc);
 #ifdef FEAT_PROFILE
     // If the outer function is profiled, also compile the nested function for
@@ -2579,6 +2580,13 @@ compile_def_function(
        new_def_function = TRUE;
     }
 
+    if ((ufunc->uf_flags & FC_CLOSURE) && outer_cctx == NULL)
+    {
+       semsg(_(e_compiling_closure_without_context_str),
+                                                  printable_func_name(ufunc));
+       return FAIL;
+    }
+
     ufunc->uf_def_status = UF_COMPILING;
 
     CLEAR_FIELD(cctx);
index 2cf7e46ed9cbb27abd9787d49ed28144d3a814bd..681847a793e4a859a0bcf71da9422bb5c808248d 100644 (file)
@@ -152,7 +152,7 @@ exe_newlist(int count, ectx_T *ectx)
  * If debug_tick changed check if "ufunc" has a breakpoint and update
  * "uf_has_breakpoint".
  */
-    static void
+    void
 update_has_breakpoint(ufunc_T *ufunc)
 {
     if (ufunc->uf_debug_tick != debug_tick)
index 19cd55d3c8caddd5252c706eb2b15e560c0117ff..e2e4f8e6af19e70d1f9902f993969b31f6e675ee 100644 (file)
@@ -1007,6 +1007,14 @@ compile_lambda(char_u **arg, cctx_T *cctx)
        )
        compile_def_function(ufunc, FALSE, CT_NONE, cctx);
 
+    // if the outer function is not compiled for debugging, this one might be
+    if (cctx->ctx_compile_type != CT_DEBUG)
+    {
+       update_has_breakpoint(ufunc);
+       if (COMPILE_TYPE(ufunc) == CT_DEBUG)
+           compile_def_function(ufunc, FALSE, CT_DEBUG, cctx);
+    }
+
     // The last entry in evalarg.eval_tofree_ga is a copy of the last line and
     // "*arg" may point into it.  Point into the original line to avoid a
     // dangling pointer.