0
0
mirror of https://github.com/vim/vim.git synced 2025-10-04 05:25:06 -04:00

patch 8.2.1001: Vim9: crash with nested "if" and assignment

Problem:    Vim9: crash with nested "if" and assignment.
Solution:   Skip more of the assignment.  Do not set ctx_skip when code is
            reachable.
This commit is contained in:
Bram Moolenaar
2020-06-18 18:26:24 +02:00
parent 158ea175a9
commit 72abcf42d4
3 changed files with 72 additions and 39 deletions

View File

@@ -1162,6 +1162,26 @@ def Test_if_const_expr_fails()
call CheckDefFailure(["if has('aaa') ? true false"], 'E109:') call CheckDefFailure(["if has('aaa') ? true false"], 'E109:')
enddef enddef
def RunNested(i: number): number
let x: number = 0
if i % 2
if 1
" comment
else
" comment
endif
x += 1
else
x += 1000
endif
return x
enddef
def Test_nested_if()
assert_equal(1, RunNested(1))
assert_equal(1000, RunNested(2))
enddef
def Test_execute_cmd() def Test_execute_cmd()
new new
setline(1, 'default') setline(1, 'default')

View File

@@ -754,6 +754,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1001,
/**/ /**/
1000, 1000,
/**/ /**/

View File

@@ -5067,8 +5067,19 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
if (!heredoc) if (!heredoc)
{ {
if (oplen > 0) if (cctx->ctx_skip == TRUE)
{ {
if (oplen > 0 && var_count == 0)
{
// skip over the "=" and the expression
p = skipwhite(op + oplen);
compile_expr0(&p, cctx);
}
}
else if (oplen > 0)
{
type_T *stacktype;
// For "var = expr" evaluate the expression. // For "var = expr" evaluate the expression.
if (var_count == 0) if (var_count == 0)
{ {
@@ -5113,52 +5124,47 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
return FAIL; return FAIL;
} }
if (cctx->ctx_skip != TRUE) stacktype = stack->ga_len == 0 ? &t_void
: ((type_T **)stack->ga_data)[stack->ga_len - 1];
if (lvar != NULL && (is_decl || !has_type))
{ {
type_T *stacktype; if (new_local && !has_type)
stacktype = stack->ga_len == 0 ? &t_void
: ((type_T **)stack->ga_data)[stack->ga_len - 1];
if (lvar != NULL && (is_decl || !has_type))
{ {
if (new_local && !has_type) if (stacktype->tt_type == VAR_VOID)
{ {
if (stacktype->tt_type == VAR_VOID) emsg(_(e_cannot_use_void));
{ goto theend;
emsg(_(e_cannot_use_void));
goto theend;
}
else
{
// An empty list or dict has a &t_void member,
// for a variable that implies &t_any.
if (stacktype == &t_list_empty)
lvar->lv_type = &t_list_any;
else if (stacktype == &t_dict_empty)
lvar->lv_type = &t_dict_any;
else
lvar->lv_type = stacktype;
}
} }
else else
{ {
type_T *use_type = lvar->lv_type; // An empty list or dict has a &t_void member,
// for a variable that implies &t_any.
if (has_index) if (stacktype == &t_list_empty)
{ lvar->lv_type = &t_list_any;
use_type = use_type->tt_member; else if (stacktype == &t_dict_empty)
if (use_type == NULL) lvar->lv_type = &t_dict_any;
use_type = &t_void; else
} lvar->lv_type = stacktype;
if (need_type(stacktype, use_type, -1, cctx)
== FAIL)
goto theend;
} }
} }
else if (*p != '=' && need_type(stacktype, member_type, -1, else
cctx) == FAIL) {
goto theend; type_T *use_type = lvar->lv_type;
if (has_index)
{
use_type = use_type->tt_member;
if (use_type == NULL)
use_type = &t_void;
}
if (need_type(stacktype, use_type, -1, cctx)
== FAIL)
goto theend;
}
} }
else if (*p != '=' && need_type(stacktype, member_type, -1,
cctx) == FAIL)
goto theend;
} }
else if (cmdidx == CMD_const) else if (cmdidx == CMD_const)
{ {
@@ -5220,6 +5226,10 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
end = p; end = p;
} }
// no need to parse more when skipping
if (cctx->ctx_skip == TRUE)
break;
if (oplen > 0 && *op != '=') if (oplen > 0 && *op != '=')
{ {
type_T *expected = &t_number; type_T *expected = &t_number;
@@ -5806,7 +5816,8 @@ compile_endif(char_u *arg, cctx_T *cctx)
} }
// Fill in the "end" label in jumps at the end of the blocks. // Fill in the "end" label in jumps at the end of the blocks.
compile_fill_jump_to_end(&ifscope->is_end_label, cctx); compile_fill_jump_to_end(&ifscope->is_end_label, cctx);
cctx->ctx_skip = FALSE; // TODO: this should restore the value from before the :if
cctx->ctx_skip = MAYBE;
drop_scope(cctx); drop_scope(cctx);
return arg; return arg;