v: missing -skip-unused fixes (#22978)

This commit is contained in:
Felipe Pena 2024-11-27 20:03:03 -03:00 committed by GitHub
parent 066384ce8c
commit ae4a9047c1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 233 additions and 98 deletions

View File

@ -88,7 +88,7 @@ mut:
values &u8 = unsafe { nil } values &u8 = unsafe { nil }
} }
@[inline; markused] @[inline]
fn new_dense_array(key_bytes int, value_bytes int) DenseArray { fn new_dense_array(key_bytes int, value_bytes int) DenseArray {
cap := 8 cap := 8
return DenseArray{ return DenseArray{
@ -103,18 +103,18 @@ fn new_dense_array(key_bytes int, value_bytes int) DenseArray {
} }
} }
@[inline; markused] @[inline]
fn (d &DenseArray) key(i int) voidptr { fn (d &DenseArray) key(i int) voidptr {
return unsafe { voidptr(d.keys + i * d.key_bytes) } return unsafe { voidptr(d.keys + i * d.key_bytes) }
} }
// for cgen // for cgen
@[inline; markused] @[inline]
fn (d &DenseArray) value(i int) voidptr { fn (d &DenseArray) value(i int) voidptr {
return unsafe { voidptr(d.values + i * d.value_bytes) } return unsafe { voidptr(d.values + i * d.value_bytes) }
} }
@[inline; markused] @[inline]
fn (d &DenseArray) has_index(i int) bool { fn (d &DenseArray) has_index(i int) bool {
return d.deletes == 0 || unsafe { d.all_deleted[i] } == 0 return d.deletes == 0 || unsafe { d.all_deleted[i] } == 0
} }
@ -259,7 +259,6 @@ fn map_free_string(pkey voidptr) {
fn map_free_nop(_ voidptr) { fn map_free_nop(_ voidptr) {
} }
@[markused]
fn new_map(key_bytes int, value_bytes int, hash_fn MapHashFn, key_eq_fn MapEqFn, clone_fn MapCloneFn, free_fn MapFreeFn) map { fn new_map(key_bytes int, value_bytes int, hash_fn MapHashFn, key_eq_fn MapEqFn, clone_fn MapCloneFn, free_fn MapFreeFn) map {
metasize := int(sizeof(u32) * (init_capicity + extra_metas_inc)) metasize := int(sizeof(u32) * (init_capicity + extra_metas_inc))
// for now assume anything bigger than a pointer is a string // for now assume anything bigger than a pointer is a string

View File

@ -12,10 +12,10 @@ pub struct UsedFeatures {
pub mut: pub mut:
interfaces bool // interface interfaces bool // interface
dump bool // dump() dump bool // dump()
builtin_types bool // uses any builtin type
index bool // string[0] index bool // string[0]
range_index bool // string[0..1] range_index bool // string[0..1]
cast_ptr bool // &u8(...) cast_ptr bool // &u8(...)
asserts bool // assert expr
as_cast bool // expr as Type as_cast bool // expr as Type
anon_fn bool // fn () { } anon_fn bool // fn () { }
auto_str bool // auto str fns auto_str bool // auto str fns
@ -24,6 +24,11 @@ pub mut:
arr_first bool // arr.first() arr_first bool // arr.first()
arr_last bool // arr.last() arr_last bool // arr.last()
arr_pop bool // arr.pop() arr_pop bool // arr.pop()
arr_delete bool // arr.delete()
arr_init bool // [1, 2, 3]
arr_map bool // []map[key]value
map_update bool // {...foo}
interpolation bool // '${foo} ${bar}'
option_or_result bool // has panic call option_or_result bool // has panic call
print_types map[int]bool // print() idx types print_types map[int]bool // print() idx types
used_fns map[string]bool // filled in by markused used_fns map[string]bool // filled in by markused
@ -32,6 +37,7 @@ pub mut:
used_veb_types []Type // veb context types, filled in by checker used_veb_types []Type // veb context types, filled in by checker
used_maps int // how many times maps were used, filled in by markused used_maps int // how many times maps were used, filled in by markused
used_arrays int // how many times arrays were used, filled in by markused used_arrays int // how many times arrays were used, filled in by markused
used_modules map[string]bool // filled in checker
// json bool // json is imported // json bool // json is imported
debugger bool // debugger is used debugger bool // debugger is used
comptime_calls map[string]bool // resolved $method() names comptime_calls map[string]bool // resolved $method() names

View File

@ -2302,11 +2302,20 @@ fn (mut c Checker) stmt(mut node ast.Stmt) {
fn (mut c Checker) assert_stmt(mut node ast.AssertStmt) { fn (mut c Checker) assert_stmt(mut node ast.AssertStmt) {
if node.is_used { if node.is_used {
c.table.used_features.auto_str = true c.table.used_features.asserts = true
} }
cur_exp_typ := c.expected_type cur_exp_typ := c.expected_type
c.expected_type = ast.bool_type c.expected_type = ast.bool_type
assert_type := c.check_expr_option_or_result_call(node.expr, c.expr(mut node.expr)) assert_type := c.check_expr_option_or_result_call(node.expr, c.expr(mut node.expr))
if c.pref.skip_unused && !c.table.used_features.auto_str && !c.is_builtin_mod
&& mut node.expr is ast.InfixExpr {
if !c.table.sym(c.unwrap_generic(node.expr.left_type)).has_method('str') {
c.table.used_features.auto_str = true
}
if !c.table.sym(c.unwrap_generic(node.expr.right_type)).has_method('str') {
c.table.used_features.auto_str = true
}
}
if assert_type != ast.bool_type_idx { if assert_type != ast.bool_type_idx {
atype_name := c.table.sym(assert_type).name atype_name := c.table.sym(assert_type).name
c.error('assert can be used only with `bool` expressions, but found `${atype_name}` instead', c.error('assert can be used only with `bool` expressions, but found `${atype_name}` instead',
@ -2949,6 +2958,7 @@ pub fn (mut c Checker) expr(mut node ast.Expr) ast.Type {
return c.concat_expr(mut node) return c.concat_expr(mut node)
} }
ast.DumpExpr { ast.DumpExpr {
c.table.used_features.dump = true
c.expected_type = ast.string_type c.expected_type = ast.string_type
node.expr_type = c.expr(mut node.expr) node.expr_type = c.expr(mut node.expr)
if c.pref.skip_unused && !c.is_builtin_mod { if c.pref.skip_unused && !c.is_builtin_mod {
@ -3268,7 +3278,8 @@ fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
to_type to_type
} }
final_to_is_ptr := to_type.is_ptr() || final_to_type.is_ptr() final_to_is_ptr := to_type.is_ptr() || final_to_type.is_ptr()
if to_type.is_ptr() { if c.pref.skip_unused && !c.is_builtin_mod && c.mod !in ['strings', 'math.bits']
&& to_type.is_ptr() {
c.table.used_features.cast_ptr = true c.table.used_features.cast_ptr = true
} }
if to_type.has_flag(.result) { if to_type.has_flag(.result) {
@ -4763,9 +4774,11 @@ fn (mut c Checker) index_expr(mut node ast.IndexExpr) ast.Type {
} }
else {} else {}
} }
c.table.used_features.index = true if !c.is_builtin_mod && c.mod !in ['strings', 'math.bits'] {
if node.index is ast.RangeExpr { if node.index is ast.RangeExpr {
c.table.used_features.range_index = true c.table.used_features.range_index = true
}
c.table.used_features.index = true
} }
is_aggregate_arr := typ_sym.kind == .aggregate is_aggregate_arr := typ_sym.kind == .aggregate
&& (typ_sym.info as ast.Aggregate).types.filter(c.table.type_kind(it) !in [.array, .array_fixed, .string, .map]).len == 0 && (typ_sym.info as ast.Aggregate).types.filter(c.table.type_kind(it) !in [.array, .array_fixed, .string, .map]).len == 0

View File

@ -13,6 +13,9 @@ fn (mut c Checker) array_init(mut node ast.ArrayInit) ast.Type {
} }
// `x := []string{}` (the type was set in the parser) // `x := []string{}` (the type was set in the parser)
if node.typ != ast.void_type { if node.typ != ast.void_type {
if !c.is_builtin_mod && c.mod !in ['builtin', 'strings', 'strconv', 'math.bits'] {
c.table.used_features.arr_init = true
}
if node.elem_type != 0 { if node.elem_type != 0 {
elem_sym := c.table.sym(node.elem_type) elem_sym := c.table.sym(node.elem_type)
@ -61,6 +64,11 @@ fn (mut c Checker) array_init(mut node ast.ArrayInit) ast.Type {
c.warn('byte is deprecated, use u8 instead', node.elem_type_pos) c.warn('byte is deprecated, use u8 instead', node.elem_type_pos)
} }
} }
ast.Map {
if c.pref.skip_unused && !c.is_builtin_mod {
c.table.used_features.arr_map = true
}
}
else {} else {}
} }
} }
@ -143,6 +151,9 @@ fn (mut c Checker) array_init(mut node ast.ArrayInit) ast.Type {
} }
// `[1,2,3]` // `[1,2,3]`
if node.exprs.len > 0 && node.elem_type == ast.void_type { if node.exprs.len > 0 && node.elem_type == ast.void_type {
if !c.is_builtin_mod && c.mod !in ['builtin', 'strings', 'strconv', 'math.bits'] {
c.table.used_features.arr_init = true
}
mut expected_value_type := ast.void_type mut expected_value_type := ast.void_type
mut expecting_interface_array := false mut expecting_interface_array := false
mut expecting_sumtype_array := false mut expecting_sumtype_array := false
@ -495,6 +506,7 @@ fn (mut c Checker) map_init(mut node ast.MapInit) ast.Type {
} }
if (node.keys.len > 0 && node.vals.len > 0) || node.has_update_expr { if (node.keys.len > 0 && node.vals.len > 0) || node.has_update_expr {
c.table.used_features.map_update = true
mut map_type := ast.void_type mut map_type := ast.void_type
use_expected_type := c.expected_type != ast.void_type && !c.inside_const use_expected_type := c.expected_type != ast.void_type && !c.inside_const
&& c.table.sym(c.expected_type).kind == .map && !(c.inside_fn_arg && c.table.sym(c.expected_type).kind == .map && !(c.inside_fn_arg

View File

@ -751,8 +751,23 @@ fn (mut c Checker) call_expr(mut node ast.CallExpr) ast.Type {
c.inside_or_block_value = true c.inside_or_block_value = true
c.check_or_expr(node.or_block, typ, c.expected_or_type, node) c.check_or_expr(node.or_block, typ, c.expected_or_type, node)
c.inside_or_block_value = old_inside_or_block_value c.inside_or_block_value = old_inside_or_block_value
} else if node.or_block.kind == .propagate_option || node.or_block.kind == .propagate_result {
if c.pref.skip_unused && !c.is_builtin_mod && c.mod != 'strings' {
c.table.used_features.option_or_result = true
}
} }
c.expected_or_type = old_expected_or_type c.expected_or_type = old_expected_or_type
if c.pref.skip_unused && !c.is_builtin_mod && c.mod == 'main' {
if node.is_method {
type_str := c.table.type_to_str(node.left_type)
if c.table.sym(node.left_type).is_builtin()
&& type_str !in c.table.used_features.used_modules {
c.table.used_features.used_modules[type_str] = true
}
} else if node.name.contains('.') {
c.table.used_features.used_modules[node.name.all_before('.')] = true
}
}
if !c.inside_const && c.table.cur_fn != unsafe { nil } && !c.table.cur_fn.is_main if !c.inside_const && c.table.cur_fn != unsafe { nil } && !c.table.cur_fn.is_main
&& !c.table.cur_fn.is_test { && !c.table.cur_fn.is_test {
@ -1401,7 +1416,8 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
// println / eprintln / panic can print anything // println / eprintln / panic can print anything
if node.args.len > 0 && fn_name in print_everything_fns { if node.args.len > 0 && fn_name in print_everything_fns {
c.builtin_args(mut node, fn_name, func) c.builtin_args(mut node, fn_name, func)
if c.pref.skip_unused && !c.is_builtin_mod && node.args[0].expr !is ast.StringLiteral { if c.pref.skip_unused && !c.is_builtin_mod && c.mod != 'math.bits'
&& node.args[0].expr !is ast.StringLiteral {
if !c.table.sym(c.unwrap_generic(node.args[0].typ)).has_method('str') { if !c.table.sym(c.unwrap_generic(node.args[0].typ)).has_method('str') {
c.table.used_features.auto_str = true c.table.used_features.auto_str = true
if node.args[0].typ.is_ptr() { if node.args[0].typ.is_ptr() {
@ -2162,9 +2178,6 @@ fn (mut c Checker) method_call(mut node ast.CallExpr, mut continue_check &bool)
continue_check = false continue_check = false
return ast.void_type return ast.void_type
} }
if c.pref.skip_unused && !c.is_builtin_mod && c.mod != 'strings' {
c.table.used_features.builtin_types = true
}
c.expected_type = left_type c.expected_type = left_type
mut is_generic := left_type.has_flag(.generic) mut is_generic := left_type.has_flag(.generic)
node.left_type = left_type node.left_type = left_type
@ -2949,6 +2962,9 @@ fn (mut c Checker) check_expected_arg_count(mut node ast.CallExpr, f &ast.Fn) !
} }
if f.is_variadic { if f.is_variadic {
min_required_params-- min_required_params--
if c.pref.skip_unused && !c.is_builtin_mod {
c.table.used_features.arr_init = true
}
} else { } else {
has_decompose := node.args.any(it.expr is ast.ArrayDecompose) has_decompose := node.args.any(it.expr is ast.ArrayDecompose)
if has_decompose { if has_decompose {
@ -3565,7 +3581,7 @@ fn (mut c Checker) array_builtin_method_call(mut node ast.CallExpr, left_type as
} }
node.return_type = ast.int_type node.return_type = ast.int_type
} else if method_name in ['first', 'last', 'pop'] { } else if method_name in ['first', 'last', 'pop'] {
if c.pref.skip_unused { if c.pref.skip_unused && !c.is_builtin_mod {
if method_name == 'first' { if method_name == 'first' {
c.table.used_features.arr_first = true c.table.used_features.arr_first = true
} }
@ -3587,6 +3603,9 @@ fn (mut c Checker) array_builtin_method_call(mut node ast.CallExpr, left_type as
node.receiver_type = node.left_type node.receiver_type = node.left_type
} }
} else if method_name == 'delete' { } else if method_name == 'delete' {
if c.pref.skip_unused && !c.is_builtin_mod {
c.table.used_features.arr_delete = true
}
c.check_for_mut_receiver(mut node.left) c.check_for_mut_receiver(mut node.left)
unwrapped_left_sym := c.table.sym(unwrapped_left_type) unwrapped_left_sym := c.table.sym(unwrapped_left_type)
if method := c.table.find_method(unwrapped_left_sym, method_name) { if method := c.table.find_method(unwrapped_left_sym, method_name) {

View File

@ -190,6 +190,9 @@ fn (mut c Checker) for_in_stmt(mut node ast.ForInStmt) {
'declare a key and a value variable when ranging a map: `for key, val in map {`\n' + 'declare a key and a value variable when ranging a map: `for key, val in map {`\n' +
'use `_` if you do not need the variable', node.pos) 'use `_` if you do not need the variable', node.pos)
} }
if !c.is_builtin_mod && c.mod != 'strings' {
c.table.used_features.used_maps++
}
if node.key_var.len > 0 { if node.key_var.len > 0 {
key_type := match sym.kind { key_type := match sym.kind {
.map { sym.map_info().key_type } .map { sym.map_info().key_type }

View File

@ -62,6 +62,7 @@ fn (mut c Checker) string_inter_lit(mut node ast.StringInterLiteral) ast.Type {
} else { } else {
c.table.used_features.print_types[ftyp.idx()] = true c.table.used_features.print_types[ftyp.idx()] = true
} }
c.table.used_features.interpolation = true
} }
c.fail_if_unreadable(expr, ftyp, 'interpolation object') c.fail_if_unreadable(expr, ftyp, 'interpolation object')
node.expr_types << ftyp node.expr_types << ftyp

View File

@ -6660,7 +6660,7 @@ fn (mut g Gen) write_init_function() {
g.write('\tas_cast_type_indexes = ') g.write('\tas_cast_type_indexes = ')
g.writeln(g.as_cast_name_table()) g.writeln(g.as_cast_name_table())
} }
if !g.pref.is_shared && (!g.pref.skip_unused || g.table.used_features.builtin_types) { if !g.pref.is_shared && (!g.pref.skip_unused || g.table.used_features.used_modules.len > 0) {
// shared object does not need this // shared object does not need this
g.writeln('\tbuiltin_init();') g.writeln('\tbuiltin_init();')
} }

View File

@ -13,7 +13,6 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a
defer { defer {
util.timing_measure(@METHOD) util.timing_measure(@METHOD)
} }
mut allow_noscan := true
// Functions that must be generated and can't be skipped // Functions that must be generated and can't be skipped
mut all_fn_root_names := []string{} mut all_fn_root_names := []string{}
if pref_.backend == .native { if pref_.backend == .native {
@ -25,17 +24,19 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a
string_idx_str := '${ast.string_type_idx}' string_idx_str := '${ast.string_type_idx}'
array_idx_str := '${ast.array_type_idx}' array_idx_str := '${ast.array_type_idx}'
map_idx_str := '${ast.map_type_idx}' map_idx_str := '${ast.map_type_idx}'
ref_map_idx_str := '${int(ast.map_type.ref())}'
ref_densearray_idx_str := '${int(table.find_type('DenseArray').ref())}'
ref_array_idx_str := '${int(ast.array_type.ref())}' ref_array_idx_str := '${int(ast.array_type.ref())}'
mut core_fns := [ mut core_fns := [
'main.main', 'main.main',
'init_global_allocator', // needed for linux_bare and wasm_bare 'init_global_allocator', // needed for linux_bare and wasm_bare
'v_realloc', // needed for _STR 'v_realloc', // needed for _STR
'malloc', //'malloc',
'malloc_noscan', //'malloc_noscan',
'vcalloc', //'vcalloc',
'vcalloc_noscan', //'vcalloc_noscan',
'memdup', 'memdup',
'vstrlen', //'vstrlen',
'tos', 'tos',
'tos2', 'tos2',
'error', 'error',
@ -45,26 +46,35 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a
'main.vtest_init', 'main.vtest_init',
'main.vtest_new_metainfo', 'main.vtest_new_metainfo',
'main.vtest_new_filemetainfo', 'main.vtest_new_filemetainfo',
'println',
] ]
$if debug_used_features ? { $if debug_used_features ? {
dump(table.used_features) dump(table.used_features)
} }
panic_deps := [ panic_deps := [
'__new_array_with_default', '__new_array_with_default',
'__new_array_with_default_noscan',
'str_intp', 'str_intp',
ref_array_idx_str + '.push', ref_array_idx_str + '.push',
ref_array_idx_str + '.push_noscan',
string_idx_str + '.substr', string_idx_str + '.substr',
array_idx_str + '.slice', array_idx_str + '.slice',
array_idx_str + '.get', array_idx_str + '.get',
'v_fixed_index', 'v_fixed_index',
charptr_idx_str + '.vstring_literal',
] ]
// real world apps if table.used_features.used_modules.len > 0 {
if table.used_features.builtin_types || table.used_features.as_cast
|| table.used_features.auto_str {
core_fns << panic_deps core_fns << panic_deps
}
if table.used_features.as_cast || table.used_features.auto_str || pref_.is_shared {
core_fns << panic_deps
core_fns << 'isnil'
core_fns << '__new_array' core_fns << '__new_array'
core_fns << '__new_array_noscan'
core_fns << '__new_array_with_multi_default' core_fns << '__new_array_with_multi_default'
core_fns << '__new_array_with_multi_default_noscan'
core_fns << '__new_array_with_array_default' core_fns << '__new_array_with_array_default'
core_fns << '__new_array_with_array_default_noscan'
core_fns << 'new_array_from_c_array' core_fns << 'new_array_from_c_array'
// byteptr and charptr // byteptr and charptr
core_fns << byteptr_idx_str + '.vstring' core_fns << byteptr_idx_str + '.vstring'
@ -73,65 +83,82 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a
core_fns << charptr_idx_str + '.vstring' core_fns << charptr_idx_str + '.vstring'
core_fns << charptr_idx_str + '.vstring_with_len' core_fns << charptr_idx_str + '.vstring_with_len'
core_fns << charptr_idx_str + '.vstring_literal' core_fns << charptr_idx_str + '.vstring_literal'
}
if table.used_features.index { if table.used_features.index || pref_.is_shared {
core_fns << string_idx_str + '.at_with_check' core_fns << string_idx_str + '.at_with_check'
core_fns << string_idx_str + '.clone' core_fns << string_idx_str + '.clone'
core_fns << string_idx_str + '.clone_static' core_fns << string_idx_str + '.clone_static'
core_fns << string_idx_str + '.at' core_fns << string_idx_str + '.at'
core_fns << array_idx_str + '.set' core_fns << array_idx_str + '.set'
core_fns << ref_array_idx_str + '.set' core_fns << ref_array_idx_str + '.set'
core_fns << map_idx_str + '.get' core_fns << map_idx_str + '.get'
core_fns << map_idx_str + '.set' core_fns << map_idx_str + '.set'
} core_fns << '__new_array_noscan'
if table.used_features.range_index { core_fns << ref_array_idx_str + '.push_noscan'
core_fns << string_idx_str + '.substr_with_check' core_fns << ref_array_idx_str + '.push_many_noscan'
core_fns << string_idx_str + '.substr_ni' }
core_fns << array_idx_str + '.slice_ni' if table.used_features.range_index || pref_.is_shared {
core_fns << array_idx_str + '.get_with_check' // used for `x := a[i] or {}` core_fns << string_idx_str + '.substr_with_check'
core_fns << array_idx_str + '.clone_static_to_depth' core_fns << string_idx_str + '.substr_ni'
core_fns << array_idx_str + '.clone_to_depth' core_fns << array_idx_str + '.slice_ni'
} core_fns << array_idx_str + '.get_with_check' // used for `x := a[i] or {}`
if table.used_features.cast_ptr { core_fns << array_idx_str + '.clone_static_to_depth'
core_fns << 'ptr_str' // TODO: remove this. It is currently needed for the auto str methods for &u8, fn types, etc; See `./v -skip-unused vlib/builtin/int_test.v` core_fns << array_idx_str + '.clone_to_depth'
} }
if table.used_features.auto_str { if table.used_features.cast_ptr {
core_fns << string_idx_str + '.repeat' core_fns << 'ptr_str' // TODO: remove this. It is currently needed for the auto str methods for &u8, fn types, etc; See `./v -skip-unused vlib/builtin/int_test.v`
core_fns << 'tos3' }
} if table.used_features.auto_str {
if table.used_features.auto_str_ptr { core_fns << string_idx_str + '.repeat'
core_fns << 'isnil' core_fns << 'tos3'
} }
if table.used_features.arr_prepend { if table.used_features.auto_str_ptr {
core_fns << ref_array_idx_str + '.prepend_many' core_fns << 'isnil'
} }
if table.used_features.arr_pop { if table.used_features.arr_prepend {
core_fns << ref_array_idx_str + '.pop' core_fns << ref_array_idx_str + '.prepend_many'
} }
if table.used_features.arr_first { if table.used_features.arr_pop {
core_fns << array_idx_str + '.first' core_fns << ref_array_idx_str + '.pop'
} }
if table.used_features.arr_last { if table.used_features.arr_first {
core_fns << array_idx_str + '.last' core_fns << array_idx_str + '.first'
} }
} else { if table.used_features.arr_last {
// TODO: this *should not* depend on the used compiler, which is brittle, but only on info in the AST... core_fns << array_idx_str + '.last'
// hello world apps }
if pref_.ccompiler_type != .tinyc && 'no_backtrace' !in pref_.compile_defines { if table.used_features.arr_delete {
// with backtrace on gcc/clang more code needs be generated core_fns << panic_deps
allow_noscan = true }
core_fns << panic_deps if pref_.ccompiler_type != .tinyc && 'no_backtrace' !in pref_.compile_defines {
} else { // with backtrace on gcc/clang more code needs be generated
allow_noscan = false core_fns << panic_deps
} }
if table.used_features.interpolation {
core_fns << panic_deps
}
if table.used_features.dump {
core_fns << panic_deps
builderptr_idx := int(table.find_type('strings.Builder').ref())
core_fns << [
'${builderptr_idx}.str',
'${builderptr_idx}.free',
'${builderptr_idx}.write_rune',
]
}
if table.used_features.arr_init {
core_fns << '__new_array'
core_fns << 'new_array_from_c_array'
core_fns << 'new_array_from_c_array_noscan'
core_fns << '__new_array_with_multi_default'
core_fns << '__new_array_with_multi_default_noscan'
core_fns << '__new_array_with_array_default'
} }
if table.used_features.option_or_result { if table.used_features.option_or_result {
core_fns << '_option_ok' core_fns << '_option_ok'
core_fns << '_result_ok' core_fns << '_result_ok'
if !allow_noscan { core_fns << charptr_idx_str + '.vstring_literal'
core_fns << panic_deps core_fns << panic_deps
allow_noscan = true
}
} }
if table.used_features.as_cast { if table.used_features.as_cast {
core_fns << '__as_cast' core_fns << '__as_cast'
@ -139,9 +166,33 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a
if table.used_features.anon_fn { if table.used_features.anon_fn {
core_fns << 'memdup_uncollectable' core_fns << 'memdup_uncollectable'
} }
if table.used_features.arr_map {
core_fns << '__new_array_with_map_default'
core_fns << 'new_map_noscan_key'
core_fns << ref_map_idx_str + '.clone'
core_fns << ref_densearray_idx_str + '.clone'
core_fns << map_idx_str + '.clone'
table.used_features.used_maps++
}
if table.used_features.map_update {
core_fns << 'new_map_update_init'
table.used_features.used_maps++
}
if table.used_features.asserts {
core_fns << panic_deps
core_fns << '__print_assert_failure'
core_fns << 'isnil'
}
if pref_.trace_calls || pref_.trace_fns.len > 0 {
core_fns << panic_deps
core_fns << 'vgettid'
core_fns << 'C.gettid'
core_fns << 'v.trace_calls.on_c_main'
core_fns << 'v.trace_calls.current_time'
core_fns << 'v.trace_calls.on_call'
}
all_fn_root_names << core_fns all_fn_root_names << core_fns
} }
if pref_.is_bare { if pref_.is_bare {
all_fn_root_names << [ all_fn_root_names << [
'strlen', 'strlen',
@ -154,16 +205,18 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a
} }
is_noscan_whitelisted := pref_.gc_mode in [.boehm_full_opt, .boehm_incr_opt] is_noscan_whitelisted := pref_.gc_mode in [.boehm_full_opt, .boehm_incr_opt]
has_noscan := all_fn_root_names.any(it.contains('noscan')
&& it !in ['vcalloc_noscan', 'malloc_noscan'])
for k, mut mfn in all_fns { for k, mut mfn in all_fns {
$if trace_skip_unused_all_fns ? { $if trace_skip_unused_all_fns ? {
println('k: ${k} | mfn: ${mfn.name}') println('k: ${k} | mfn: ${mfn.name}')
} }
if k in table.used_features.comptime_calls { if k in table.used_features.comptime_calls {
all_fn_root_names << k all_fn_root_names << k
continue
} }
// _noscan functions/methods are selected when the `-gc boehm` is on: // _noscan functions/methods are selected when the `-gc boehm` is on:
if allow_noscan && is_noscan_whitelisted && mfn.name.ends_with('_noscan') { if has_noscan && is_noscan_whitelisted && mfn.name.ends_with('_noscan') {
all_fn_root_names << k all_fn_root_names << k
continue continue
} }
@ -176,8 +229,7 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a
all_fn_root_names << k all_fn_root_names << k
continue continue
} }
if method_receiver_typename == '&strings.Builder' if method_receiver_typename == '&strings.Builder' && table.used_features.auto_str {
&& (table.used_features.builtin_types || table.used_features.auto_str) {
// implicit string builders are generated in auto_eq_methods.v // implicit string builders are generated in auto_eq_methods.v
all_fn_root_names << k all_fn_root_names << k
continue continue
@ -187,7 +239,7 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a
if k.ends_with('.str') || k.ends_with('.auto_str') { if k.ends_with('.str') || k.ends_with('.auto_str') {
if table.used_features.auto_str if table.used_features.auto_str
|| table.used_features.print_types[mfn.receiver.typ.idx()] || table.used_features.print_types[mfn.receiver.typ.idx()]
|| table.used_features.debugger { || table.used_features.debugger || table.used_features.used_modules.len > 0 {
all_fn_root_names << k all_fn_root_names << k
} }
continue continue
@ -196,7 +248,7 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a
all_fn_root_names << k all_fn_root_names << k
continue continue
} }
if table.used_features.builtin_types && k.ends_with('.free') { if table.used_features.used_modules.len > 0 && k.ends_with('.free') {
all_fn_root_names << k all_fn_root_names << k
continue continue
} }
@ -356,19 +408,13 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a
all_globals: all_globals all_globals: all_globals
pref: pref_ pref: pref_
) )
// println( all_fns.keys() )
walker.mark_markused_fn_decls() // tagged with `@[markused]` walker.mark_markused_fn_decls() // tagged with `@[markused]`
walker.mark_markused_consts() // tagged with `@[markused]` walker.mark_markused_consts() // tagged with `@[markused]`
walker.mark_markused_globals() // tagged with `@[markused]` walker.mark_markused_globals() // tagged with `@[markused]`
walker.mark_exported_fns() walker.mark_exported_fns()
walker.mark_root_fns(all_fn_root_names) walker.mark_root_fns(all_fn_root_names)
walker.mark_veb_actions() walker.mark_veb_actions()
if walker.n_asserts > 0 {
unsafe { walker.fn_decl(mut all_fns['__print_assert_failure']) }
}
if table.used_features.used_maps > 0 { if table.used_features.used_maps > 0 {
for k, mut mfn in all_fns { for k, mut mfn in all_fns {
mut method_receiver_typename := '' mut method_receiver_typename := ''
@ -465,6 +511,13 @@ fn all_fn_const_and_global(ast_files []&ast.File) (map[string]ast.FnDecl, map[st
return all_fns, all_consts, all_globals return all_fns, all_consts, all_globals
} }
fn mark_all_methods_used(mut table ast.Table, mut all_fn_root_names []string, typ ast.Type) {
sym := table.sym(typ)
for method in sym.methods {
all_fn_root_names << '${int(typ)}.${method.name}'
}
}
fn handle_vweb(mut table ast.Table, mut all_fn_root_names []string, result_name string, filter_name string, fn handle_vweb(mut table ast.Table, mut all_fn_root_names []string, result_name string, filter_name string,
context_name string) { context_name string) {
// handle vweb magic router methods: // handle vweb magic router methods:
@ -472,7 +525,7 @@ fn handle_vweb(mut table ast.Table, mut all_fn_root_names []string, result_name
if result_type_idx != 0 { if result_type_idx != 0 {
all_fn_root_names << filter_name all_fn_root_names << filter_name
typ_vweb_context := table.find_type(context_name).set_nr_muls(1) typ_vweb_context := table.find_type(context_name).set_nr_muls(1)
all_fn_root_names << '${int(typ_vweb_context)}.html' mark_all_methods_used(mut table, mut all_fn_root_names, typ_vweb_context)
for vgt in table.used_features.used_veb_types { for vgt in table.used_features.used_veb_types {
sym_app := table.sym(vgt) sym_app := table.sym(vgt)
for m in sym_app.methods { for m in sym_app.methods {

View File

@ -299,6 +299,10 @@ fn (mut w Walker) expr(node_ ast.Expr) {
w.fn_decl(mut node.decl) w.fn_decl(mut node.decl)
} }
ast.ArrayInit { ast.ArrayInit {
sym := w.table.final_sym(node.elem_type)
if sym.info is ast.Struct {
w.a_struct_info(sym.name, sym.info)
}
w.expr(node.len_expr) w.expr(node.len_expr)
w.expr(node.cap_expr) w.expr(node.cap_expr)
w.expr(node.init_expr) w.expr(node.init_expr)
@ -419,6 +423,7 @@ fn (mut w Walker) expr(node_ ast.Expr) {
// println('>>> else, ast.Ident kind: $node.kind') // println('>>> else, ast.Ident kind: $node.kind')
} }
} }
w.or_block(node.or_expr)
} }
ast.LambdaExpr { ast.LambdaExpr {
w.expr(node.func) w.expr(node.func)
@ -470,6 +475,7 @@ fn (mut w Walker) expr(node_ ast.Expr) {
w.fn_by_name(method.fkey()) w.fn_by_name(method.fkey())
} }
} }
w.or_block(node.or_block)
} }
ast.SqlExpr { ast.SqlExpr {
w.expr(node.db_expr) w.expr(node.db_expr)
@ -511,7 +517,14 @@ fn (mut w Walker) expr(node_ ast.Expr) {
w.expr(node.orig) w.expr(node.orig)
} }
ast.Comment {} ast.Comment {}
ast.EnumVal {} ast.EnumVal {
if e := w.table.enum_decls[node.enum_name] {
filtered := e.fields.filter(it.name == node.val)
if filtered.len != 0 && filtered[0].expr !is ast.EmptyExpr {
w.expr(filtered[0].expr)
}
}
}
ast.LockExpr { ast.LockExpr {
w.stmts(node.stmts) w.stmts(node.stmts)
} }
@ -557,6 +570,7 @@ pub fn (mut w Walker) a_struct_info(sname string, info ast.Struct) {
pub fn (mut w Walker) fn_decl(mut node ast.FnDecl) { pub fn (mut w Walker) fn_decl(mut node ast.FnDecl) {
if node.language == .c { if node.language == .c {
w.mark_fn_as_used(node.fkey())
return return
} }
fkey := node.fkey() fkey := node.fkey()
@ -587,6 +601,17 @@ pub fn (mut w Walker) call_expr(mut node ast.CallExpr) {
w.mark_aggregate_call_used(fn_name, types) w.mark_aggregate_call_used(fn_name, types)
} }
} }
} else if left_sym.info is ast.Interface {
for typ in left_sym.info.types {
sym := w.table.sym(typ)
_, embed_types := w.table.find_method_from_embeds(sym, node.name) or {
ast.Fn{}, []ast.Type{}
}
if embed_types.len != 0 {
fn_embed := '${int(embed_types.last())}.${node.name}'
w.fn_by_name(fn_embed)
}
}
} }
} }
w.expr(node.left) w.expr(node.left)
@ -609,15 +634,19 @@ pub fn (mut w Walker) call_expr(mut node ast.CallExpr) {
else {} else {}
} }
} }
} else if node.is_fn_a_const {
const_fn_name := '${node.mod}.${fn_name}'
if const_fn_name in w.all_consts {
w.mark_const_as_used(const_fn_name)
}
} }
w.mark_fn_as_used(fn_name) w.mark_fn_as_used(fn_name)
if node.is_method && node.receiver_type.has_flag(.generic) && node.receiver_concrete_type != 0 if node.is_method && node.receiver_type.has_flag(.generic) && node.receiver_concrete_type != 0
&& !node.receiver_concrete_type.has_flag(.generic) { && !node.receiver_concrete_type.has_flag(.generic) {
// if receiver is generic, then cgen requires `node.receiver_type` to be T. // if receiver is generic, then cgen requires `node.receiver_type` to be T.
// We therefore need to get the concrete type from `node.receiver_concrete_type`. // We therefore need to get the concrete type from `node.receiver_concrete_type`.
fkey := '${int(node.receiver_concrete_type)}.${node.name}' fkey := '${int(node.receiver_concrete_type)}.${node.name}'
w.used_fns[fkey] = true w.mark_fn_as_used(fkey)
} }
stmt := w.all_fns[fn_name] or { return } stmt := w.all_fns[fn_name] or { return }
if stmt.name == node.name { if stmt.name == node.name {