mirror of
https://github.com/vlang/v.git
synced 2025-09-09 15:27:05 -04:00
cgen: remove unused code generated for unwrapping temp var from callexpr (detect unused return value from CallExpr), fix parser bugs (#22769)
This commit is contained in:
parent
505a247706
commit
dab25cad49
@ -1559,6 +1559,7 @@ fn (t Tree) call_expr(node ast.CallExpr) &Node {
|
||||
obj.add('is_keep_alive', t.bool_node(node.is_keep_alive))
|
||||
obj.add_terse('is_noreturn', t.bool_node(node.is_noreturn))
|
||||
obj.add_terse('is_ctor_new', t.bool_node(node.is_ctor_new))
|
||||
obj.add_terse('is_return_used', t.bool_node(node.is_return_used))
|
||||
obj.add('should_be_skipped', t.bool_node(node.should_be_skipped))
|
||||
obj.add_terse('free_receiver', t.bool_node(node.free_receiver))
|
||||
obj.add('scope', t.number_node(int(node.scope)))
|
||||
|
@ -827,6 +827,7 @@ pub mut:
|
||||
scope &Scope = unsafe { nil }
|
||||
from_embed_types []Type // holds the type of the embed that the method is called from
|
||||
comments []Comment
|
||||
is_return_used bool // return value is used for another expr
|
||||
//
|
||||
is_expand_simple_interpolation bool // true, when the function/method is marked as @[expand_simple_interpolation]
|
||||
// Calls to it with an interpolation argument like `b.f('x ${y}')`, will be converted to `b.f('x ')` followed by `b.f(y)`.
|
||||
|
@ -580,13 +580,14 @@ or use an explicit `unsafe{ a[..] }`, if you do not want a copy of the slice.',
|
||||
right.pos())
|
||||
c.note('an implicit clone of the slice was done here', right.pos())
|
||||
right = ast.CallExpr{
|
||||
name: 'clone'
|
||||
left: right
|
||||
left_type: left_type
|
||||
is_method: true
|
||||
receiver_type: left_type
|
||||
return_type: left_type
|
||||
scope: c.fn_scope
|
||||
name: 'clone'
|
||||
left: right
|
||||
left_type: left_type
|
||||
is_method: true
|
||||
receiver_type: left_type
|
||||
return_type: left_type
|
||||
scope: c.fn_scope
|
||||
is_return_used: true
|
||||
}
|
||||
right_type = c.expr(mut right)
|
||||
node.right[i] = right
|
||||
|
@ -1371,7 +1371,6 @@ fn (mut c Checker) check_or_last_stmt(mut stmt ast.Stmt, ret_type ast.Type, expr
|
||||
c.expected_type = ret_type
|
||||
c.expected_or_type = ret_type.clear_option_and_result()
|
||||
last_stmt_typ := c.expr(mut stmt.expr)
|
||||
|
||||
if last_stmt_typ.has_flag(.option) || last_stmt_typ == ast.none_type {
|
||||
if stmt.expr in [ast.Ident, ast.SelectorExpr, ast.CallExpr, ast.None, ast.CastExpr] {
|
||||
expected_type_name := c.table.type_to_str(ret_type.clear_option_and_result())
|
||||
|
@ -733,13 +733,14 @@ or use an explicit `unsafe{ a[..] }`, if you do not want a copy of the slice.',
|
||||
init_field.expr.pos())
|
||||
c.note('an implicit clone of the slice was done here', init_field.expr.pos())
|
||||
mut right := ast.CallExpr{
|
||||
name: 'clone'
|
||||
left: init_field.expr
|
||||
left_type: got_type
|
||||
is_method: true
|
||||
receiver_type: got_type.ref()
|
||||
return_type: got_type
|
||||
scope: c.fn_scope
|
||||
name: 'clone'
|
||||
left: init_field.expr
|
||||
left_type: got_type
|
||||
is_method: true
|
||||
receiver_type: got_type.ref()
|
||||
return_type: got_type
|
||||
scope: c.fn_scope
|
||||
is_return_used: true
|
||||
}
|
||||
got_type = c.expr(mut right)
|
||||
node.init_fields[i].expr = right
|
||||
|
@ -1,9 +1,9 @@
|
||||
@[flag]
|
||||
pub enum Enum {
|
||||
a
|
||||
a
|
||||
}
|
||||
|
||||
@[flag]
|
||||
pub enum Enum {
|
||||
a
|
||||
a
|
||||
}
|
@ -1041,7 +1041,7 @@ fn (mut g Gen) gen_cross_var_assign(node &ast.AssignStmt) {
|
||||
g.write(' = *(voidptr*)array_get(')
|
||||
} else {
|
||||
styp := g.styp(info.elem_type)
|
||||
string_clone := if needs_clone { '/*1*/string_clone(' } else { '' }
|
||||
string_clone := if needs_clone { 'string_clone(' } else { '' }
|
||||
|
||||
g.write('${styp} _var_${left.pos.pos} = ${string_clone}*(${styp}*)array_get(')
|
||||
}
|
||||
|
@ -2158,7 +2158,11 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
||||
eprintln('cgen: ${g.file.path:-30} | pos: ${node.pos.line_str():-39} | node: ${ntype} | ${node}')
|
||||
}
|
||||
}
|
||||
old_inside_call := g.inside_call
|
||||
g.inside_call = false
|
||||
defer {
|
||||
g.inside_call = old_inside_call
|
||||
}
|
||||
if !g.skip_stmt_pos {
|
||||
g.set_current_pos_as_last_stmt_pos()
|
||||
}
|
||||
@ -7140,6 +7144,10 @@ fn (mut g Gen) gen_or_block_stmts(cvar_name string, cast_typ string, stmts []ast
|
||||
&& expr_stmt.expr.or_block.kind == .absent {
|
||||
g.write('${cvar_name} = ')
|
||||
return_wrapped = true
|
||||
} else if expr_stmt.expr is ast.CallExpr {
|
||||
if expr_stmt.expr.is_return_used {
|
||||
g.write('*(${cast_typ}*) ${cvar_name}.data = ')
|
||||
}
|
||||
} else {
|
||||
g.write('*(${cast_typ}*) ${cvar_name}.data = ')
|
||||
}
|
||||
|
@ -1021,7 +1021,12 @@ fn (mut g Gen) call_expr(node ast.CallExpr) {
|
||||
&& unwrapped_styp.starts_with('_v_') {
|
||||
unwrapped_styp = unwrapped_styp[3..]
|
||||
}
|
||||
g.write('\n ${cur_line} (*(${unwrapped_styp}*)${tmp_opt}.data)')
|
||||
if node.is_return_used {
|
||||
// return value is used, so we need to write the unwrapped temporary var
|
||||
g.write('\n ${cur_line} (*(${unwrapped_styp}*)${tmp_opt}.data)')
|
||||
} else {
|
||||
g.write('\n ${cur_line}')
|
||||
}
|
||||
} else {
|
||||
g.write('\n ${cur_line} ${tmp_opt}')
|
||||
}
|
||||
|
@ -631,12 +631,13 @@ pub fn (mut g Gen) call_expr(node ast.CallExpr, expected ast.Type, existing_rvar
|
||||
}
|
||||
|
||||
expr = ast.CallExpr{
|
||||
name: 'str'
|
||||
left: expr
|
||||
left_type: typ
|
||||
receiver_type: typ
|
||||
return_type: ast.string_type
|
||||
is_method: true
|
||||
name: 'str'
|
||||
left: expr
|
||||
left_type: typ
|
||||
receiver_type: typ
|
||||
return_type: ast.string_type
|
||||
is_method: true
|
||||
is_return_used: true
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@ fn (mut p Parser) assign_stmt() ast.Stmt {
|
||||
mut defer_vars := p.defer_vars.clone()
|
||||
p.defer_vars = []ast.Ident{}
|
||||
|
||||
exprs := p.expr_list()
|
||||
exprs := p.expr_list(true)
|
||||
|
||||
if !(p.inside_defer && p.tok.kind == .decl_assign) {
|
||||
defer_vars << p.defer_vars
|
||||
@ -186,7 +186,10 @@ fn (mut p Parser) partial_assign_stmt(left []ast.Expr) ast.Stmt {
|
||||
mut pos := p.tok.pos()
|
||||
p.next()
|
||||
mut right := []ast.Expr{cap: left.len}
|
||||
right = p.expr_list()
|
||||
old_assign_rhs := p.inside_assign_rhs
|
||||
p.inside_assign_rhs = true
|
||||
right = p.expr_list(true)
|
||||
p.inside_assign_rhs = old_assign_rhs
|
||||
end_comments := p.eat_comments(same_line: true)
|
||||
mut has_cross_var := false
|
||||
mut is_static := false
|
||||
|
@ -15,7 +15,26 @@ fn (mut p Parser) check_expr_level() ! {
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut p Parser) expr_no_value(precedence int) ast.Expr {
|
||||
old_expecting_value := p.expecting_value
|
||||
p.expecting_value = false
|
||||
defer {
|
||||
p.expecting_value = old_expecting_value
|
||||
}
|
||||
return p.check_expr(precedence) or {
|
||||
if token.is_decl(p.tok.kind) && p.disallow_declarations_in_script_mode() {
|
||||
return ast.empty_expr
|
||||
}
|
||||
p.unexpected(prepend_msg: 'invalid expression:')
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut p Parser) expr(precedence int) ast.Expr {
|
||||
old_expecting_value := p.expecting_value
|
||||
p.expecting_value = true
|
||||
defer {
|
||||
p.expecting_value = old_expecting_value
|
||||
}
|
||||
return p.check_expr(precedence) or {
|
||||
if token.is_decl(p.tok.kind) && p.disallow_declarations_in_script_mode() {
|
||||
return ast.empty_expr
|
||||
@ -466,12 +485,13 @@ fn (mut p Parser) check_expr(precedence int) !ast.Expr {
|
||||
p.check(.rpar)
|
||||
or_block := p.gen_or_block()
|
||||
node = ast.CallExpr{
|
||||
name: 'anon'
|
||||
left: node
|
||||
args: args
|
||||
pos: pos
|
||||
or_block: or_block
|
||||
scope: p.scope
|
||||
name: 'anon'
|
||||
left: node
|
||||
args: args
|
||||
pos: pos
|
||||
or_block: or_block
|
||||
scope: p.scope
|
||||
is_return_used: p.expecting_value
|
||||
}
|
||||
}
|
||||
return node
|
||||
@ -572,11 +592,12 @@ fn (mut p Parser) expr_with_left(left ast.Expr, precedence int, is_stmt_ident bo
|
||||
p.check(.rpar)
|
||||
or_block := p.gen_or_block()
|
||||
node = ast.CallExpr{
|
||||
left: node
|
||||
args: args
|
||||
pos: pos
|
||||
scope: p.scope
|
||||
or_block: or_block
|
||||
left: node
|
||||
args: args
|
||||
pos: pos
|
||||
scope: p.scope
|
||||
or_block: or_block
|
||||
is_return_used: p.expecting_value
|
||||
}
|
||||
p.is_stmt_ident = is_stmt_ident
|
||||
if p.tok.kind == .lpar && p.prev_tok.line_nr == p.tok.line_nr {
|
||||
@ -613,7 +634,10 @@ fn (mut p Parser) expr_with_left(left ast.Expr, precedence int, is_stmt_ident bo
|
||||
tok := p.tok
|
||||
mut pos := tok.pos()
|
||||
p.next()
|
||||
old_assign_rhs := p.inside_assign_rhs
|
||||
p.inside_assign_rhs = true
|
||||
right := p.expr(precedence - 1)
|
||||
p.inside_assign_rhs = old_assign_rhs
|
||||
pos.update_last_line(p.prev_tok.line_nr)
|
||||
if mut node is ast.IndexExpr {
|
||||
node.recursive_arraymap_set_is_setter()
|
||||
@ -757,7 +781,10 @@ fn (mut p Parser) infix_expr(left ast.Expr) ast.Expr {
|
||||
}
|
||||
|
||||
right_op_pos := p.tok.pos()
|
||||
old_assign_rhs := p.inside_assign_rhs
|
||||
p.inside_assign_rhs = true
|
||||
right = p.expr(precedence)
|
||||
p.inside_assign_rhs = old_assign_rhs
|
||||
if op in [.plus, .minus, .mul, .div, .mod, .lt, .eq] && mut right is ast.PrefixExpr {
|
||||
mut right_expr := right.right
|
||||
for mut right_expr is ast.ParExpr {
|
||||
|
@ -111,11 +111,12 @@ fn (mut p Parser) call_expr(language ast.Language, mod string) ast.CallExpr {
|
||||
}
|
||||
scope: p.scope
|
||||
comments: comments
|
||||
is_return_used: p.expecting_value
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut p Parser) call_args() []ast.CallArg {
|
||||
prev_inside_call_args := true
|
||||
prev_inside_call_args := p.inside_call_args
|
||||
p.inside_call_args = true
|
||||
defer {
|
||||
p.inside_call_args = prev_inside_call_args
|
||||
@ -1168,7 +1169,8 @@ fn (mut p Parser) spawn_expr() ast.SpawnExpr {
|
||||
} else {
|
||||
p.error_with_pos('expression in `spawn` must be a function call', expr.pos())
|
||||
ast.CallExpr{
|
||||
scope: p.scope
|
||||
scope: p.scope
|
||||
is_return_used: true
|
||||
}
|
||||
}
|
||||
pos := spos.extend(p.prev_tok.pos())
|
||||
@ -1189,7 +1191,8 @@ fn (mut p Parser) go_expr() ast.GoExpr {
|
||||
} else {
|
||||
p.error_with_pos('expression in `go` must be a function call', expr.pos())
|
||||
ast.CallExpr{
|
||||
scope: p.scope
|
||||
scope: p.scope
|
||||
is_return_used: true
|
||||
}
|
||||
}
|
||||
pos := spos.extend(p.prev_tok.pos())
|
||||
|
@ -170,6 +170,13 @@ fn (mut p Parser) if_expr(is_comptime bool) ast.IfExpr {
|
||||
}
|
||||
p.open_scope()
|
||||
stmts := p.parse_block_no_scope(false)
|
||||
// if the last expr is a callexpr mark its return as used
|
||||
if p.inside_assign_rhs && stmts.len > 0 && stmts.last() is ast.ExprStmt {
|
||||
mut last_expr := stmts.last() as ast.ExprStmt
|
||||
if mut last_expr.expr is ast.CallExpr {
|
||||
last_expr.expr.is_return_used = true
|
||||
}
|
||||
}
|
||||
branches << ast.IfBranch{
|
||||
cond: cond
|
||||
stmts: stmts
|
||||
@ -245,11 +252,12 @@ fn (mut p Parser) is_match_sumtype_type() bool {
|
||||
|
||||
fn (mut p Parser) match_expr() ast.MatchExpr {
|
||||
match_first_pos := p.tok.pos()
|
||||
old_inside_match := p.inside_match
|
||||
p.inside_match = true
|
||||
p.check(.key_match)
|
||||
mut is_sum_type := false
|
||||
cond := p.expr(0)
|
||||
p.inside_match = false
|
||||
p.inside_match = old_inside_match
|
||||
no_lcbr := p.tok.kind != .lcbr
|
||||
if !no_lcbr {
|
||||
p.check(.lcbr)
|
||||
@ -353,6 +361,12 @@ fn (mut p Parser) match_expr() ast.MatchExpr {
|
||||
pos := branch_first_pos.extend_with_last_line(branch_last_pos, p.prev_tok.line_nr)
|
||||
branch_pos := branch_first_pos.extend_with_last_line(p.tok.pos(), p.tok.line_nr)
|
||||
post_comments := p.eat_comments()
|
||||
if p.inside_assign_rhs && stmts.len > 0 && stmts.last() is ast.ExprStmt {
|
||||
mut last_expr := stmts.last() as ast.ExprStmt
|
||||
if mut last_expr.expr is ast.CallExpr {
|
||||
last_expr.expr.is_return_used = true
|
||||
}
|
||||
}
|
||||
branches << ast.MatchBranch{
|
||||
exprs: exprs
|
||||
ecmnts: ecmnts
|
||||
@ -430,7 +444,7 @@ fn (mut p Parser) select_expr() ast.SelectExpr {
|
||||
}
|
||||
p.inside_match = true
|
||||
p.inside_select = true
|
||||
exprs := p.expr_list()
|
||||
exprs := p.expr_list(true)
|
||||
if exprs.len != 1 {
|
||||
p.error('only one expression allowed as `select` key')
|
||||
return ast.SelectExpr{}
|
||||
|
@ -54,6 +54,7 @@ mut:
|
||||
inside_array_lit bool
|
||||
inside_in_array bool
|
||||
inside_infix bool
|
||||
inside_assign_rhs bool // rhs assignment
|
||||
inside_match bool // to separate `match A { }` from `Struct{}`
|
||||
inside_select bool // to allow `ch <- Struct{} {` inside `select`
|
||||
inside_match_case bool // to separate `match_expr { }` from `Struct{}`
|
||||
@ -90,6 +91,7 @@ mut:
|
||||
returns bool
|
||||
is_stmt_ident bool // true while the beginning of a statement is an ident/selector
|
||||
expecting_type bool // `is Type`, expecting type
|
||||
expecting_value bool = true // true where a node value will be used
|
||||
cur_fn_name string
|
||||
cur_fn_scope &ast.Scope = unsafe { nil }
|
||||
label_names []string
|
||||
@ -1857,10 +1859,10 @@ fn (mut p Parser) asm_ios(output bool) []ast.AsmIO {
|
||||
return res
|
||||
}
|
||||
|
||||
fn (mut p Parser) expr_list() []ast.Expr {
|
||||
fn (mut p Parser) expr_list(expect_value bool) []ast.Expr {
|
||||
mut exprs := []ast.Expr{}
|
||||
for {
|
||||
expr := p.expr(0)
|
||||
expr := if expect_value { p.expr(0) } else { p.expr_no_value(0) }
|
||||
if expr !is ast.Comment {
|
||||
exprs << expr
|
||||
if p.tok.kind != .comma {
|
||||
@ -2228,7 +2230,7 @@ fn (mut p Parser) parse_multi_expr(is_top_level bool) ast.Stmt {
|
||||
mut defer_vars := p.defer_vars.clone()
|
||||
p.defer_vars = []ast.Ident{}
|
||||
|
||||
left := p.expr_list()
|
||||
left := p.expr_list(p.inside_assign_rhs)
|
||||
|
||||
if !(p.inside_defer && p.tok.kind == .decl_assign) {
|
||||
defer_vars << p.defer_vars
|
||||
@ -2881,11 +2883,12 @@ fn (mut p Parser) name_expr() ast.Expr {
|
||||
p.check(.rpar)
|
||||
or_block := p.gen_or_block()
|
||||
node = ast.CallExpr{
|
||||
left: node
|
||||
args: args
|
||||
pos: pos
|
||||
scope: p.scope
|
||||
or_block: or_block
|
||||
left: node
|
||||
args: args
|
||||
pos: pos
|
||||
scope: p.scope
|
||||
or_block: or_block
|
||||
is_return_used: p.expecting_value
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3325,6 +3328,10 @@ fn (mut p Parser) dot_expr(left ast.Expr) ast.Expr {
|
||||
end_pos := p.prev_tok.pos()
|
||||
pos := name_pos.extend(end_pos)
|
||||
comments := p.eat_comments(same_line: true)
|
||||
mut left_node := unsafe { left }
|
||||
if mut left_node is ast.CallExpr {
|
||||
left_node.is_return_used = true
|
||||
}
|
||||
mcall_expr := ast.CallExpr{
|
||||
left: left
|
||||
name: field_name
|
||||
@ -3337,6 +3344,7 @@ fn (mut p Parser) dot_expr(left ast.Expr) ast.Expr {
|
||||
or_block: or_block
|
||||
scope: p.scope
|
||||
comments: comments
|
||||
is_return_used: p.expecting_value
|
||||
}
|
||||
return mcall_expr
|
||||
}
|
||||
@ -3382,7 +3390,10 @@ fn (mut p Parser) dot_expr(left ast.Expr) ast.Expr {
|
||||
scope: p.scope
|
||||
next_token: p.tok.kind
|
||||
}
|
||||
|
||||
mut left_node := unsafe { left }
|
||||
if mut left_node is ast.CallExpr {
|
||||
left_node.is_return_used = true
|
||||
}
|
||||
return sel_expr
|
||||
}
|
||||
|
||||
@ -3984,7 +3995,10 @@ fn (mut p Parser) return_stmt() ast.Return {
|
||||
}
|
||||
}
|
||||
// return exprs
|
||||
exprs := p.expr_list()
|
||||
old_assign_rhs := p.inside_assign_rhs
|
||||
p.inside_assign_rhs = true
|
||||
exprs := p.expr_list(true)
|
||||
p.inside_assign_rhs = old_assign_rhs
|
||||
end_pos := exprs.last().pos()
|
||||
return ast.Return{
|
||||
exprs: exprs
|
||||
|
Loading…
x
Reference in New Issue
Block a user