diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index caa8241856..2de86347b6 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -457,6 +457,9 @@ fn (mut g Gen) gen_anon_fn(mut node ast.AnonFn) { for param in node.decl.params { size_sb.write_string('_REG_WIDTH(${g.typ(param.typ)}) + ') } + if g.pref.arch == .amd64 && node.decl.return_type != ast.void_type { + size_sb.write_string('(_REG_WIDTH(${g.typ(node.decl.return_type)}) > 2) + ') + } size_sb.write_string('1') args_size := size_sb.str() g.writeln('') diff --git a/vlib/v/tests/closure_generator_test.v b/vlib/v/tests/closure_generator_test.v index 7fec0db0e2..5df56753d9 100644 --- a/vlib/v/tests/closure_generator_test.v +++ b/vlib/v/tests/closure_generator_test.v @@ -7,6 +7,58 @@ const ( all_param_values = []string{len: max_params, init: '${it + 1}'} ) +struct ReturnType { + name string + init string + assertion string + no_assert_kw bool +} + +const return_types = [ + ReturnType{ + name: '' + init: '' + assertion: '' + no_assert_kw: true + }, + ReturnType{ + name: 'int' + init: '-123' + assertion: ' == -123' + }, + ReturnType{ + name: 'u64' + init: '123' + assertion: ' == 123' + }, + ReturnType{ + name: 'voidptr' + init: 'voidptr(123)' + assertion: ' == voidptr(123)' + }, + ReturnType{ + name: 'string' + init: "'hello'" + assertion: " == 'hello'" + }, + ReturnType{ + name: '?' + init: "error('an error')" + assertion: " or { assert err.msg == 'an error' return }\npanic('got no error')" + no_assert_kw: true + }, + ReturnType{ + name: '?string' + init: "'hello'" + assertion: "? == 'hello'" + }, + ReturnType{ + name: 'BigStruct' + init: 'BigStruct{ a3: 56, a27: 1234, a61: 5555 }' + assertion: ' == BigStruct{ a3: 56, a27: 1234, a61: 5555 }' + }, +] + // test_closures_with_n_args generates a new V file containing closures of `i` // and parameters of type `typ`, to makes sure that all combinations work correctly fn test_closures_with_n_args() ? { @@ -14,6 +66,12 @@ fn test_closures_with_n_args() ? { // NB: the type or value of the captured arg doesn't matter for this test, // as the entire closure context is always passed as one pointer anyways + v_code.write_string('struct BigStruct {') + for i in 0 .. 64 { + v_code.write_string('\ta$i int ') + } + v_code.writeln('}') + for typ in ['byte', 'u16', 'int', 'i64', 'voidptr', 'string'] { for i in 0 .. max_params { param_names := all_param_names[..i] @@ -41,19 +99,59 @@ fn test_closures_with_n_args() ? { // NB: the captured arg doesn't matter for this test, as closures always receive // a pointer to the entire closure context as their last argument anyways v_code.writeln(" - fn test_big_closure_${typ}_${i}() { - println('test_big_closure_${typ}_$i') - mut z := $init_val - c := fn [z] (${params.join(', ')}) $return_type { - mut sum := z") +fn test_big_closure_${typ}_${i}() { + println('test_big_closure_${typ}_$i') + mut local := 123 + mut local_2 := 234 + mut z := $init_val + c := fn [z] (${params.join(', ')}) $return_type { + mut sum := z") for j in 0 .. i { v_code.writeln('\t\tsum += ${return_type}(${param_names[j]})') } - v_code.writeln(' - return sum + v_code.writeln(" + return sum + } + assert c(${values.join(', ')}) == $expected_val + // ensure stack wasn't overwritten: + assert local == 123 + assert local_2 == 234 +}") } - assert c(${values.join(', ')}) == $expected_val - }') + } + + for return_type in return_types { + typ := return_type.name + styp := typ.replace('?', 'option_').to_lower() + init := return_type.init + assertion := return_type.assertion + + for i in 0 .. 10 { + param_names := all_param_names[..i] + params := param_names.map('$it int') + values := all_param_values[..i] + + assert_line := if !return_type.no_assert_kw { + 'assert c(${values.join(', ')}) $assertion' + } else { + 'c(${values.join(', ')}) $assertion' + } + // NB: the captured arg doesn't matter for this test, as closures always receive + // a pointer to the entire closure context as their last argument anyways + v_code.writeln(" +fn test_closure_return_${styp}_${i}() ? { + println('test_closure_return_${styp}_$i') + mut local := 123 + mut local_2 := 234 + mut z := 1234 + c := fn [z] (${params.join(', ')}) $typ { + return $init + } + $assert_line + // ensure stack wasn't overwritten: + assert local == 123 + assert local_2 == 234 +}") } } @@ -62,9 +160,9 @@ fn test_closures_with_n_args() ? { wrkdir := os.join_path(os.temp_dir(), 'vtests', 'closures') os.mkdir_all(wrkdir) ? os.chdir(wrkdir) ? - os.write_file('closure_args_test.v', code) ? + os.write_file('closure_return_test.v', code) ? vexe := os.getenv('VEXE') - res := os.execute('"$vexe" closure_args_test.v') + res := os.execute('"$vexe" -keepc -cg -showcc closure_return_test.v') if res.exit_code != 0 { eprintln(res.output) assert false