From a85071878ef774e711bc951def37e19e00755d7a Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Sat, 30 Nov 2024 20:11:09 -0300 Subject: [PATCH] v: fix all `-skip-unused` issues so that it can be enabled by default (#23002) --- cmd/tools/vcover/cover_test.v | 6 +- vlib/v/ast/table.v | 3 + vlib/v/checker/assign.v | 2 +- vlib/v/checker/checker.v | 10 +++ vlib/v/checker/comptime.v | 29 +++++-- vlib/v/checker/fn.v | 23 ++++-- vlib/v/gen/c/cgen.v | 4 +- vlib/v/gen/c/comptime.v | 8 +- vlib/v/gen/c/testdata/addr.vv | 1 + .../v/gen/c/testdata/alias_char_ptr_to_ptr.vv | 5 +- .../comptime_if_attribute_in_test2.vv | 2 +- .../v/gen/c/testdata/comptime_option_call.out | 2 +- vlib/v/gen/c/testdata/embed.vv | 1 + .../c/testdata/embed_with_prod.c.must_have | 4 +- vlib/v/gen/c/testdata/embed_with_prod.out | 1 + vlib/v/gen/c/testdata/embed_with_prod.vv | 2 +- .../embed_with_prod_and_several_decoders.out | 3 + .../testdata/embed_with_prod_zlib.c.must_have | 4 +- .../v/gen/c/testdata/embed_with_prod_zlib.out | 1 + vlib/v/gen/c/testdata/embed_with_prod_zlib.vv | 2 +- .../gen/c/testdata/global_initializer_nix.vv | 2 +- .../unused_import_aliased_as_underscore.vv | 2 + vlib/v/markused/markused.v | 77 ++++++++++++++----- vlib/v/pref/pref.v | 2 +- .../const_comptime_eval_before_vinit_test.v | 2 +- vlib/v/tests/trace_calls_test.v | 2 +- 26 files changed, 151 insertions(+), 49 deletions(-) diff --git a/cmd/tools/vcover/cover_test.v b/cmd/tools/vcover/cover_test.v index e4d5299ff..6a2c6e9a2 100644 --- a/cmd/tools/vcover/cover_test.v +++ b/cmd/tools/vcover/cover_test.v @@ -45,7 +45,7 @@ fn test_simple() { assert !os.exists(t2), t2 assert !os.exists(t3), t3 - r1 := os.execute('${os.quoted_path(vexe)} -coverage ${os.quoted_path(t1)} cmd/tools/vcover/testdata/simple/t1_test.v') + r1 := os.execute('${os.quoted_path(vexe)} -no-skip-unused -coverage ${os.quoted_path(t1)} cmd/tools/vcover/testdata/simple/t1_test.v') assert r1.exit_code == 0, r1.str() assert r1.output.trim_space() == '10', r1.str() assert os.exists(t1), t1 @@ -72,7 +72,7 @@ fn test_simple() { assert nzeros1.any(it.contains('simple.v:8')), nzeros1.str() assert nzeros1.any(it.contains('simple.v:25')), nzeros1.str() - r2 := os.execute('${os.quoted_path(vexe)} -coverage ${os.quoted_path(t2)} cmd/tools/vcover/testdata/simple/t2_test.v') + r2 := os.execute('${os.quoted_path(vexe)} -no-skip-unused -coverage ${os.quoted_path(t2)} cmd/tools/vcover/testdata/simple/t2_test.v') assert r2.exit_code == 0, r2.str() assert r2.output.trim_space() == '24', r2.str() assert os.exists(t2), t2 @@ -97,7 +97,7 @@ fn test_simple() { assert nzeros2.any(it.contains('simple.v:25')), nzeros2.str() // Run both tests. The coverage should be combined and == 100% - r3 := os.execute('${os.quoted_path(vexe)} -coverage ${os.quoted_path(t3)} test cmd/tools/vcover/testdata/simple/') + r3 := os.execute('${os.quoted_path(vexe)} -no-skip-unused -coverage ${os.quoted_path(t3)} test cmd/tools/vcover/testdata/simple/') assert r3.exit_code == 0, r3.str() assert r3.output.trim_space().contains('Summary for all V _test.v files: '), r3.str() assert os.exists(t3), t3 diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index 92fe2fdbc..1ffe3a8c8 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -21,10 +21,12 @@ pub mut: auto_str bool // auto str fns auto_str_ptr bool // auto str fns for ptr type arr_prepend bool // arr.prepend() + arr_insert bool // arr.insert() arr_first bool // arr.first() arr_last bool // arr.last() arr_pop bool // arr.pop() arr_delete bool // arr.delete() + arr_reverse bool // arr.reverse() arr_init bool // [1, 2, 3] arr_map bool // []map[key]value map_update bool // {...foo} @@ -41,6 +43,7 @@ pub mut: // json bool // json is imported debugger bool // debugger is used comptime_calls map[string]bool // resolved name to call on comptime + comptime_for bool // uses $for } @[unsafe] diff --git a/vlib/v/checker/assign.v b/vlib/v/checker/assign.v index c5c9d97b4..e264f7790 100644 --- a/vlib/v/checker/assign.v +++ b/vlib/v/checker/assign.v @@ -25,7 +25,7 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) { mut right_first_type := ast.void_type for i, mut right in node.right { if right in [ast.CallExpr, ast.IfExpr, ast.LockExpr, ast.MatchExpr, ast.DumpExpr, - ast.SelectorExpr, ast.ParExpr] { + ast.SelectorExpr, ast.ParExpr, ast.ComptimeCall] { if right in [ast.IfExpr, ast.MatchExpr] && node.left.len == node.right.len && !is_decl && node.left[i] in [ast.Ident, ast.SelectorExpr] && !node.left[i].is_blank_ident() { mut expr := node.left[i] diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index b53104013..00f4d766f 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -1728,6 +1728,9 @@ fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type { return field.typ } if mut method := c.table.sym(c.unwrap_generic(typ)).find_method_with_generic_parent(field_name) { + if c.pref.skip_unused && typ.has_flag(.generic) { + c.table.used_features.comptime_calls['${int(method.params[0].typ)}.${field_name}'] = true + } if c.expected_type != 0 && c.expected_type != ast.none_type { fn_type := ast.new_type(c.table.find_or_register_fn_type(method, false, true)) // if the expected type includes the receiver, don't hide it behind a closure @@ -3193,6 +3196,10 @@ pub fn (mut c Checker) expr(mut node ast.Expr) ast.Type { ast.StructInit { if node.unresolved { mut expr_ := c.table.resolve_init(node, c.unwrap_generic(node.typ)) + if c.pref.skip_unused && c.table.used_features.used_maps == 0 + && expr_ is ast.MapInit { + c.table.used_features.used_maps++ + } return c.expr(mut expr_) } mut inited_fields := []string{} @@ -3902,6 +3909,9 @@ fn (mut c Checker) ident(mut node ast.Ident) ast.Type { c.error('`mut` is not allowed with `=` (use `:=` to declare a variable)', node.pos) } + if c.pref.skip_unused && !c.is_builtin_mod && node.language == .v && node.name.contains('.') { + c.table.used_features.used_modules[node.name.all_before('.')] = true + } if mut obj := node.scope.find(node.name) { match mut obj { ast.GlobalField { diff --git a/vlib/v/checker/comptime.v b/vlib/v/checker/comptime.v index d16311759..aee7aea3d 100644 --- a/vlib/v/checker/comptime.v +++ b/vlib/v/checker/comptime.v @@ -133,10 +133,23 @@ fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) ast.Type { // check each arg expression node.args[i].typ = c.expr(mut arg.expr) } - if c.pref.skip_unused && node.method_name == 'method' { - sym := c.table.sym(c.unwrap_generic(node.left_type)) - for m in sym.get_methods() { - c.table.used_features.comptime_calls['${int(c.unwrap_generic(m.receiver_type))}.${m.name}'] = true + if c.pref.skip_unused { + c.table.used_features.comptime_calls['${int(c.unwrap_generic(c.comptime.comptime_for_method.receiver_type))}.${c.comptime.comptime_for_method.name}'] = true + if c.inside_anon_fn { + // $method passed to anon fn, mark all methods as used + sym := c.table.sym(c.unwrap_generic(node.left_type)) + for m in sym.get_methods() { + c.table.used_features.comptime_calls['${int(c.unwrap_generic(m.receiver_type))}.${m.name}'] = true + if node.args.len > 0 && m.params.len > 0 { + last_param := m.params.last().typ + if (last_param.is_int() || last_param.is_bool()) + && c.table.final_sym(node.args.last().typ).kind == .array { + c.table.used_features.comptime_calls['${ast.string_type_idx}.${c.table.type_to_str(m.params.last().typ)}'] = true + } + } + } + } else { + m := c.comptime.comptime_for_method if node.args.len > 0 && m.params.len > 0 { last_param := m.params.last().typ if (last_param.is_int() || last_param.is_bool()) @@ -204,11 +217,15 @@ fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) ast.Type { } else { c.error('todo: not a string literal', node.method_pos) } - left_sym := c.table.sym(c.unwrap_generic(node.left_type)) + left_type := c.unwrap_generic(node.left_type) + left_sym := c.table.sym(left_type) f := left_sym.find_method(method_name) or { c.error('could not find method `${method_name}`', node.method_pos) return ast.void_type } + if c.pref.skip_unused { + c.table.used_features.comptime_calls['${int(left_type)}.${method_name}'] = true + } node.result_type = f.return_type return f.return_type } @@ -331,6 +348,7 @@ fn (mut c Checker) comptime_for(mut node ast.ComptimeFor) { c.comptime.type_map['${node.val_var}.typ'] = node.typ c.stmts(mut node.stmts) c.pop_comptime_info() + c.table.used_features.comptime_for = true } else { c.error('iterating over .values is supported only for enums, and ${sym.name} is not an enum', node.typ_pos) @@ -348,6 +366,7 @@ fn (mut c Checker) comptime_for(mut node ast.ComptimeFor) { c.stmts(mut node.stmts) c.pop_comptime_info() } + c.table.used_features.comptime_for = true } else if node.kind == .params { if !(sym.kind == .function || sym.name == 'FunctionData') { c.error('iterating over `.params` is supported only for functions, and `${sym.name}` is not a function', diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index d3c376108..33901bbab 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -868,6 +868,7 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast. if c.table.cur_fn != unsafe { nil } { node.left_type, fn_name = c.table.convert_generic_static_type_name(fn_name, c.table.cur_fn.generic_names, c.table.cur_concrete_types) + c.table.used_features.comptime_calls[fn_name] = true } } if fn_name == 'main' { @@ -1420,12 +1421,12 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast. && node.args[0].expr !is ast.StringLiteral { if !c.table.sym(c.unwrap_generic(node.args[0].typ)).has_method('str') { c.table.used_features.auto_str = true - if node.args[0].typ.is_ptr() { - c.table.used_features.auto_str_ptr = true - } } else { c.table.used_features.print_types[node.args[0].typ.idx()] = true } + if node.args[0].typ.is_ptr() { + c.table.used_features.auto_str_ptr = true + } } return func.return_type } @@ -2178,9 +2179,13 @@ fn (mut c Checker) method_call(mut node ast.CallExpr, mut continue_check &bool) continue_check = false return ast.void_type } - if c.pref.skip_unused && mut left_expr is ast.Ident { - if left_expr.obj is ast.Var && left_expr.obj.ct_type_var == .smartcast { - c.table.used_features.comptime_calls['${int(left_type)}.${node.name}'] = true + if c.pref.skip_unused { + if !left_type.has_flag(.generic) && mut left_expr is ast.Ident { + if left_expr.obj is ast.Var && left_expr.obj.ct_type_var == .smartcast { + c.table.used_features.comptime_calls['${int(left_type)}.${node.name}'] = true + } + } else if left_type.has_flag(.generic) { + c.table.used_features.comptime_calls['${int(c.unwrap_generic(left_type))}.${node.name}'] = true } } c.expected_type = left_type @@ -2313,6 +2318,9 @@ fn (mut c Checker) method_call(mut node ast.CallExpr, mut continue_check &bool) if embed_types.len != 0 { is_method_from_embed = true node.from_embed_types = embed_types + if c.pref.skip_unused && node.left_type.has_flag(.generic) { + c.table.used_features.comptime_calls['${int(method.receiver_type)}.${method.name}'] = true + } } } if final_left_sym.kind == .aggregate { @@ -3353,6 +3361,7 @@ fn (mut c Checker) array_builtin_method_call(mut node ast.CallExpr, left_type as return ast.void_type } } + c.table.used_features.arr_insert = true } else { c.table.used_features.arr_prepend = true if node.args.len != 1 { @@ -3628,6 +3637,8 @@ fn (mut c Checker) array_builtin_method_call(mut node ast.CallExpr, left_type as } } node.return_type = ast.void_type + } else if method_name == 'reverse' { + c.table.used_features.arr_reverse = true } return node.return_type } diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 85e90aaa3..0c7075bae 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -6769,7 +6769,9 @@ fn (mut g Gen) write_init_function() { for mod_name in reversed_table_modules { g.writeln2('\t// Cleanups for module ${mod_name} :', g.cleanups[mod_name].str()) } - g.writeln('\tarray_free(&as_cast_type_indexes);') + if g.as_cast_type_names.len > 0 { + g.writeln('\tarray_free(&as_cast_type_indexes);') + } } for x in cleaning_up_array.reverse() { g.writeln(x) diff --git a/vlib/v/gen/c/comptime.v b/vlib/v/gen/c/comptime.v index 4e734e34f..c6fa396b0 100644 --- a/vlib/v/gen/c/comptime.v +++ b/vlib/v/gen/c/comptime.v @@ -195,8 +195,12 @@ fn (mut g Gen) comptime_call(mut node ast.ComptimeCall) { } } + mut has_unwrap := false if !g.inside_call && node.or_block.kind != .block && m.return_type.has_option_or_result() { - g.write('(*(${g.base_type(m.return_type)}*)') + if !(g.assign_ct_type != 0 && g.assign_ct_type.has_option_or_result()) { + g.write('(*(${g.base_type(m.return_type)}*)') + has_unwrap = true + } } // TODO: check argument types g.write('${util.no_dots(sym.name)}_${g.comptime.comptime_for_method.name}(') @@ -258,7 +262,7 @@ fn (mut g Gen) comptime_call(mut node ast.ComptimeCall) { } } g.write(')') - if !g.inside_call && node.or_block.kind != .block && m.return_type.has_option_or_result() { + if has_unwrap { g.write('.data)') } if node.or_block.kind != .absent && m.return_type.has_option_or_result() { diff --git a/vlib/v/gen/c/testdata/addr.vv b/vlib/v/gen/c/testdata/addr.vv index a342e6b3f..37b24bba6 100644 --- a/vlib/v/gen/c/testdata/addr.vv +++ b/vlib/v/gen/c/testdata/addr.vv @@ -3,6 +3,7 @@ mut: a int } +@[markused] fn test_addr() { mut a := 4 b := unsafe { __addr(a) } diff --git a/vlib/v/gen/c/testdata/alias_char_ptr_to_ptr.vv b/vlib/v/gen/c/testdata/alias_char_ptr_to_ptr.vv index 836d68b32..0bf59b092 100644 --- a/vlib/v/gen/c/testdata/alias_char_ptr_to_ptr.vv +++ b/vlib/v/gen/c/testdata/alias_char_ptr_to_ptr.vv @@ -1,7 +1,10 @@ +// vtest vflags: -no-skip-unused type ALcharptr = &char + fn return_text_one() ALcharptr { return ALcharptr(''.str) } + fn return_text_two() &char { return ''.str } @@ -14,4 +17,4 @@ fn get_one() string { fn get_two() string { s := return_text_two() return unsafe { cstring_to_vstring(s) } -} \ No newline at end of file +} diff --git a/vlib/v/gen/c/testdata/comptime_if_attribute_in_test2.vv b/vlib/v/gen/c/testdata/comptime_if_attribute_in_test2.vv index 96379a3fa..c86d2dd77 100644 --- a/vlib/v/gen/c/testdata/comptime_if_attribute_in_test2.vv +++ b/vlib/v/gen/c/testdata/comptime_if_attribute_in_test2.vv @@ -1,4 +1,4 @@ -// vtest vflags: -d customflag +// vtest vflags: -d customflag -no-skip-unused @[if customflag ?] fn test_abcdef() { println('this should be in the c code') diff --git a/vlib/v/gen/c/testdata/comptime_option_call.out b/vlib/v/gen/c/testdata/comptime_option_call.out index f9e6dbb56..40d4ce810 100644 --- a/vlib/v/gen/c/testdata/comptime_option_call.out +++ b/vlib/v/gen/c/testdata/comptime_option_call.out @@ -6,5 +6,5 @@ Option(none) Option(none) 1 1 -Option('') +Option(none) Option(none) diff --git a/vlib/v/gen/c/testdata/embed.vv b/vlib/v/gen/c/testdata/embed.vv index 358dbffc9..b73952942 100644 --- a/vlib/v/gen/c/testdata/embed.vv +++ b/vlib/v/gen/c/testdata/embed.vv @@ -1,3 +1,4 @@ +// vtest vflags: -no-skip-unused fn main() { mut my_source := $embed_file('embed.vv') assert my_source.len > 0 diff --git a/vlib/v/gen/c/testdata/embed_with_prod.c.must_have b/vlib/v/gen/c/testdata/embed_with_prod.c.must_have index e043814da..cfbd09e28 100644 --- a/vlib/v/gen/c/testdata/embed_with_prod.c.must_have +++ b/vlib/v/gen/c/testdata/embed_with_prod.c.must_have @@ -1,8 +1,8 @@ #define _VPROD (1) // V embedded data: -static const unsigned char _v_embed_blob_0[138] = { -0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x20,0x7b,0x0a,0x09,0x6d,0x75,0x74, +static const unsigned char _v_embed_blob_0[171] = { +0x2f,0x2f,0x20,0x76,0x74,0x65,0x73,0x74,0x20,0x76,0x66,0x6c,0x61,0x67,0x73,0x3a, const v__embed_file__EmbedFileIndexEntry _v_embed_file_index[] = { {0, { .str=(byteptr)("embed.vv"), .len=8, .is_lit=1 }, { .str=(byteptr)("none"), .len=4, .is_lit=1 }, (byteptr)_v_embed_blob_0}, diff --git a/vlib/v/gen/c/testdata/embed_with_prod.out b/vlib/v/gen/c/testdata/embed_with_prod.out index 358dbffc9..b73952942 100644 --- a/vlib/v/gen/c/testdata/embed_with_prod.out +++ b/vlib/v/gen/c/testdata/embed_with_prod.out @@ -1,3 +1,4 @@ +// vtest vflags: -no-skip-unused fn main() { mut my_source := $embed_file('embed.vv') assert my_source.len > 0 diff --git a/vlib/v/gen/c/testdata/embed_with_prod.vv b/vlib/v/gen/c/testdata/embed_with_prod.vv index f47e6b3dd..345674714 100644 --- a/vlib/v/gen/c/testdata/embed_with_prod.vv +++ b/vlib/v/gen/c/testdata/embed_with_prod.vv @@ -1,4 +1,4 @@ -// vtest vflags: -prod +// vtest vflags: -prod -no-skip-unused fn main() { mut my_source := $embed_file('embed.vv') assert my_source.len > 0 diff --git a/vlib/v/gen/c/testdata/embed_with_prod_and_several_decoders.out b/vlib/v/gen/c/testdata/embed_with_prod_and_several_decoders.out index c77f4dc3f..d10915779 100644 --- a/vlib/v/gen/c/testdata/embed_with_prod_and_several_decoders.out +++ b/vlib/v/gen/c/testdata/embed_with_prod_and_several_decoders.out @@ -1,3 +1,4 @@ +// vtest vflags: -no-skip-unused fn main() { mut my_source := $embed_file('embed.vv') assert my_source.len > 0 @@ -6,6 +7,7 @@ fn main() { print(s) } -------------------------------------- +// vtest vflags: -no-skip-unused fn main() { mut my_source := $embed_file('embed.vv') assert my_source.len > 0 @@ -14,6 +16,7 @@ fn main() { print(s) } -------------------------------------- +// vtest vflags: -no-skip-unused fn main() { mut my_source := $embed_file('embed.vv') assert my_source.len > 0 diff --git a/vlib/v/gen/c/testdata/embed_with_prod_zlib.c.must_have b/vlib/v/gen/c/testdata/embed_with_prod_zlib.c.must_have index 6f880a008..f211c0baf 100644 --- a/vlib/v/gen/c/testdata/embed_with_prod_zlib.c.must_have +++ b/vlib/v/gen/c/testdata/embed_with_prod_zlib.c.must_have @@ -1,8 +1,8 @@ #define _VPROD (1) // V embedded data: -static const unsigned char _v_embed_blob_0[121] = { -0x78,0x01,0x05,0x40,0x4b,0x0a,0x83,0x30,0x10,0x5d,0x67,0x4e,0xf1,0x16,0x05,0x93, +static const unsigned char _v_embed_blob_0[142] = { +0x78,0x01,0x05,0x00,0x41,0x0a,0x84,0x20,0xf0,0xac,0xaf,0x98,0xc3,0xc2,0xea,0x21, const v__embed_file__EmbedFileIndexEntry _v_embed_file_index[] = { {0, { .str=(byteptr)("embed.vv"), .len=8, .is_lit=1 }, { .str=(byteptr)("zlib"), .len=4, .is_lit=1 }, (byteptr)_v_embed_blob_0}, diff --git a/vlib/v/gen/c/testdata/embed_with_prod_zlib.out b/vlib/v/gen/c/testdata/embed_with_prod_zlib.out index 358dbffc9..b73952942 100644 --- a/vlib/v/gen/c/testdata/embed_with_prod_zlib.out +++ b/vlib/v/gen/c/testdata/embed_with_prod_zlib.out @@ -1,3 +1,4 @@ +// vtest vflags: -no-skip-unused fn main() { mut my_source := $embed_file('embed.vv') assert my_source.len > 0 diff --git a/vlib/v/gen/c/testdata/embed_with_prod_zlib.vv b/vlib/v/gen/c/testdata/embed_with_prod_zlib.vv index 9b11972d7..11e2b56ff 100644 --- a/vlib/v/gen/c/testdata/embed_with_prod_zlib.vv +++ b/vlib/v/gen/c/testdata/embed_with_prod_zlib.vv @@ -1,4 +1,4 @@ -// vtest vflags: -prod +// vtest vflags: -prod -no-skip-unused fn main() { mut my_source := $embed_file('embed.vv', .zlib) assert my_source.len > 0 diff --git a/vlib/v/gen/c/testdata/global_initializer_nix.vv b/vlib/v/gen/c/testdata/global_initializer_nix.vv index 6f2ad48dc..cd4e2ccdd 100644 --- a/vlib/v/gen/c/testdata/global_initializer_nix.vv +++ b/vlib/v/gen/c/testdata/global_initializer_nix.vv @@ -1,4 +1,4 @@ -// vtest vflags: -enable-globals +// vtest vflags: -enable-globals -no-skip-unused struct Foo { foo int diff --git a/vlib/v/gen/c/testdata/unused_import_aliased_as_underscore.vv b/vlib/v/gen/c/testdata/unused_import_aliased_as_underscore.vv index dc1265b44..aea392808 100644 --- a/vlib/v/gen/c/testdata/unused_import_aliased_as_underscore.vv +++ b/vlib/v/gen/c/testdata/unused_import_aliased_as_underscore.vv @@ -1 +1,3 @@ +// vtest vflags: -no-skip-unused + import flag as _ diff --git a/vlib/v/markused/markused.v b/vlib/v/markused/markused.v index 99fb2ced4..0ca5a0316 100644 --- a/vlib/v/markused/markused.v +++ b/vlib/v/markused/markused.v @@ -27,22 +27,20 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a 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())}' + is_gc_none := pref_.gc_mode == .no_gc + mut core_fns := [ 'main.main', 'init_global_allocator', // needed for linux_bare and wasm_bare 'v_realloc', // needed for _STR - //'malloc', - //'malloc_noscan', - //'vcalloc', - //'vcalloc_noscan', 'memdup', - //'vstrlen', 'tos', 'tos2', 'error', 'builtin_init', 'fast_string_eq', 'println', + 'ptr_str', ] $if debug_used_features ? { @@ -60,9 +58,30 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a 'v_fixed_index', charptr_idx_str + '.vstring_literal', ] + if ast.float_literal_type.idx() in table.used_features.print_types + || ast.f64_type_idx in table.used_features.print_types + || ast.f32_type_idx in table.used_features.print_types { + core_fns << panic_deps + } + $if windows { + if 'no_backtrace' !in pref_.compile_defines { + core_fns << panic_deps + } + } $else { + if 'use_libbacktrace' in pref_.compile_defines { + core_fns << 'print_libbacktrace' + } + } + if 'callstack' in pref_.compile_defines { + core_fns << ref_array_idx_str + '.push' + core_fns << ref_array_idx_str + '.pop' + } if table.used_features.used_modules.len > 0 { core_fns << panic_deps } + if pref_.autofree { + core_fns << string_idx_str + '.clone_static' + } if table.used_features.as_cast || table.used_features.auto_str || pref_.is_shared { core_fns << panic_deps core_fns << 'isnil' @@ -82,11 +101,13 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a core_fns << charptr_idx_str + '.vstring_literal' } if table.used_features.index || pref_.is_shared { + core_fns << panic_deps core_fns << string_idx_str + '.at_with_check' core_fns << string_idx_str + '.clone' core_fns << string_idx_str + '.clone_static' core_fns << string_idx_str + '.at' core_fns << array_idx_str + '.set' + core_fns << array_idx_str + '.get_with_check' // used for `x := a[i] or {}` core_fns << ref_array_idx_str + '.set' core_fns << map_idx_str + '.get' core_fns << map_idx_str + '.set' @@ -102,19 +123,20 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a core_fns << array_idx_str + '.clone_static_to_depth' core_fns << array_idx_str + '.clone_to_depth' } - if table.used_features.cast_ptr { - 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` - } if table.used_features.auto_str || table.used_features.dump { core_fns << string_idx_str + '.repeat' core_fns << 'tos3' } if table.used_features.auto_str_ptr { core_fns << 'isnil' + core_fns << panic_deps } if table.used_features.arr_prepend { core_fns << ref_array_idx_str + '.prepend_many' } + if table.used_features.arr_reverse { + core_fns << array_idx_str + '.reverse' + } if table.used_features.arr_pop { core_fns << ref_array_idx_str + '.pop' } @@ -127,6 +149,11 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a if table.used_features.arr_delete { core_fns << panic_deps } + if table.used_features.arr_insert { + if is_gc_none { + core_fns << ref_array_idx_str + '.insert_many' + } + } if pref_.ccompiler_type != .tinyc && 'no_backtrace' !in pref_.compile_defines { // with backtrace on gcc/clang more code needs be generated core_fns << panic_deps @@ -143,7 +170,8 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a '${builderptr_idx}.write_rune', ] } - if table.used_features.arr_init { + if table.used_features.arr_init || table.used_features.comptime_for { + core_fns << panic_deps core_fns << '__new_array' core_fns << 'new_array_from_c_array' core_fns << 'new_array_from_c_array_noscan' @@ -164,6 +192,7 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a core_fns << 'memdup_uncollectable' } if table.used_features.arr_map { + core_fns << panic_deps core_fns << '__new_array_with_map_default' core_fns << 'new_map_noscan_key' core_fns << ref_map_idx_str + '.clone' @@ -172,6 +201,7 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a table.used_features.used_maps++ } if table.used_features.map_update { + core_fns << panic_deps core_fns << 'new_map_update_init' table.used_features.used_maps++ } @@ -233,25 +263,24 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a } // auto generated string interpolation functions, may // call .str or .auto_str methods for user types: - if k.ends_with('.str') || k.ends_with('.auto_str') { - if table.used_features.auto_str + if k.ends_with('.str') || k.ends_with('.auto_str') + || (k.starts_with('_Atomic_') && k.ends_with('_str')) { + if table.used_features.auto_str || table.used_features.dump || table.used_features.print_types[mfn.receiver.typ.idx()] - || table.used_features.debugger || table.used_features.used_modules.len > 0 { + || table.used_features.asserts || table.used_features.debugger + || table.used_features.used_modules.len > 0 { all_fn_root_names << k } continue } - if k.ends_with('.init') { + if k.ends_with('.init') || k.ends_with('.cleanup') { all_fn_root_names << k continue } - if table.used_features.used_modules.len > 0 && k.ends_with('.free') { + if (pref_.autofree || table.used_features.used_modules.len > 0) && k.ends_with('.free') { all_fn_root_names << k continue } - // if mfn.name == 'before_request' { - // all_fn_root_names << k - //} // sync: if k == 'sync.new_channel_st' { @@ -359,13 +388,20 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a interface_types := [ptype, ntype] for method in interface_info.methods { for typ in interface_types { - interface_implementation_method_name := '${int(typ)}.${method.name}' + interface_implementation_method_name := '${int(typ.clear_flags())}.${method.name}' $if trace_skip_unused_interface_methods ? { eprintln('>> isym.name: ${isym.name} | interface_implementation_method_name: ${interface_implementation_method_name}') } all_fn_root_names << interface_implementation_method_name } } + for embed_method in table.get_embed_methods(table.sym(itype)) { + interface_implementation_method_name := '${int(embed_method.params[0].typ.clear_flags())}.${embed_method.name}' + $if trace_skip_unused_interface_methods ? { + eprintln('>> isym.name: ${isym.name} | interface_implementation_method_name: ${interface_implementation_method_name} (embeded)') + } + all_fn_root_names << interface_implementation_method_name + } } } @@ -410,6 +446,11 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a walker.mark_markused_consts() // tagged with `@[markused]` walker.mark_markused_globals() // tagged with `@[markused]` walker.mark_exported_fns() + + for k, _ in table.used_features.comptime_calls { + walker.fn_by_name(k) + } + walker.mark_root_fns(all_fn_root_names) walker.mark_veb_actions() diff --git a/vlib/v/pref/pref.v b/vlib/v/pref/pref.v index b91a76b85..2fd0391ca 100644 --- a/vlib/v/pref/pref.v +++ b/vlib/v/pref/pref.v @@ -1141,7 +1141,7 @@ pub fn parse_args_and_show_errors(known_external_commands []string, args []strin // eprintln('>> res.build_options: $res.build_options') res.fill_with_defaults() if res.backend == .c { - // res.skip_unused = true + res.skip_unused = res.build_mode != .build_module if no_skip_unused { res.skip_unused = false } diff --git a/vlib/v/tests/consts/const_comptime_eval_before_vinit_test.v b/vlib/v/tests/consts/const_comptime_eval_before_vinit_test.v index 30d7786f9..780e14594 100644 --- a/vlib/v/tests/consts/const_comptime_eval_before_vinit_test.v +++ b/vlib/v/tests/consts/const_comptime_eval_before_vinit_test.v @@ -71,7 +71,7 @@ fn static_storage(idx int, value int) u8 { // The _constructor attribute ensures that the function will be called // before main by the C compilers that support it. // Currently gcc/clang are known to work. -@[_constructor; unsafe] +@[_constructor; markused; unsafe] fn pre_main() { unsafe { static_storage(0, int(zzz_an_i8_const)) diff --git a/vlib/v/tests/trace_calls_test.v b/vlib/v/tests/trace_calls_test.v index dbe68698f..6b9f0401a 100644 --- a/vlib/v/tests/trace_calls_test.v +++ b/vlib/v/tests/trace_calls_test.v @@ -48,7 +48,7 @@ struct CmdOutput { } fn run(fpath string, compiler_opts string, label string) CmdOutput { - cmd := '${os.quoted_path(vexe)} ${compiler_opts} -trace-calls run ${os.quoted_path(fpath)}' + cmd := '${os.quoted_path(vexe)} ${compiler_opts} -no-skip-unused -trace-calls run ${os.quoted_path(fpath)}' res := os.execute(cmd) if res.exit_code != 0 { eprintln('> ${label} compilation output:\n${res.output}') -- 2.39.5