From 18f004038867a8ea7c4e26cad4654271b0b1261b Mon Sep 17 00:00:00 2001 From: Joe C Date: Thu, 6 Oct 2022 15:58:07 +1100 Subject: [PATCH] checker/gen/parser: varg with pointer type fix: #15943 (#15944) --- vlib/v/checker/fn.v | 35 ++++++++++++++++++--------------- vlib/v/gen/c/cgen.v | 8 +++----- vlib/v/gen/c/fn.v | 5 ++++- vlib/v/parser/fn.v | 3 ++- vlib/v/tests/fn_variadic_test.v | 17 ++++++++++++++++ 5 files changed, 45 insertions(+), 23 deletions(-) diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index d4a9bf3cd5..9419415cbc 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -236,10 +236,6 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) { } } } - if (c.pref.translated || c.file.is_translated) && node.is_variadic && param.typ.is_ptr() { - // TODO c2v hack to fix `(const char *s, ...)` - param.typ = ast.int_type.ref() - } } } if node.language == .v && node.name.after_char(`.`) == 'init' && !node.is_method @@ -1051,25 +1047,32 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) } } if c.pref.translated || c.file.is_translated { + // in case of variadic make sure to use array elem type for checks + // check_expected_call_arg already does this before checks also. + param_type := if param.typ.has_flag(.variadic) { + c.table.sym(param.typ).array_info().elem_type + } else { + param.typ + } // TODO duplicated logic in check_types() (check_types.v) // Allow enums to be used as ints and vice versa in translated code - if param.typ == ast.int_type && arg_typ_sym.kind == .enum_ { + if param_type.idx() in ast.integer_type_idxs && arg_typ_sym.kind == .enum_ { continue } - if arg_typ == ast.int_type && param_typ_sym.kind == .enum_ { + if arg_typ.idx() in ast.integer_type_idxs && param_typ_sym.kind == .enum_ { continue } - if (arg_typ == ast.bool_type && param.typ.is_int()) - || (arg_typ.is_int() && param.typ == ast.bool_type) { + if (arg_typ == ast.bool_type && param_type.is_int()) + || (arg_typ.is_int() && param_type == ast.bool_type) { continue } // In C unsafe number casts are used all the time (e.g. `char*` where // `int*` is expected etc), so just allow them all. - mut param_is_number := c.table.unaliased_type(param.typ).is_number() - if param.typ.is_ptr() { - param_is_number = param.typ.deref().is_number() + mut param_is_number := c.table.unaliased_type(param_type).is_number() + if param_type.is_ptr() { + param_is_number = param_type.deref().is_number() } mut typ_is_number := c.table.unaliased_type(arg_typ).is_number() if arg_typ.is_ptr() { @@ -1079,18 +1082,18 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) continue } // Allow voidptrs for everything - if param.typ == ast.voidptr_type_idx || arg_typ == ast.voidptr_type_idx { + if param_type == ast.voidptr_type_idx || arg_typ == ast.voidptr_type_idx { continue } - if param.typ.is_any_kind_of_pointer() && arg_typ.is_any_kind_of_pointer() { + if param_type.is_any_kind_of_pointer() && arg_typ.is_any_kind_of_pointer() { continue } - param_typ_sym_ := c.table.sym(c.table.unaliased_type(param.typ)) + param_typ_sym_ := c.table.sym(c.table.unaliased_type(param_type)) arg_typ_sym_ := c.table.sym(c.table.unaliased_type(arg_typ)) // Allow `[32]i8` as `&i8` etc if ((arg_typ_sym_.kind == .array_fixed || arg_typ_sym_.kind == .array) && (param_is_number - || c.table.unaliased_type(param.typ).is_any_kind_of_pointer())) + || c.table.unaliased_type(param_type).is_any_kind_of_pointer())) || ((param_typ_sym_.kind == .array_fixed || param_typ_sym_.kind == .array) && (typ_is_number || c.table.unaliased_type(arg_typ).is_any_kind_of_pointer())) { continue @@ -1107,7 +1110,7 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) } } // Allow `int` as `&i8` - if param.typ.is_any_kind_of_pointer() && typ_is_number { + if param_type.is_any_kind_of_pointer() && typ_is_number { continue } // Allow `&i8` as `int` diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 3fedcc53c6..63434baaaf 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -941,11 +941,9 @@ fn (mut g Gen) base_type(_t ast.Type) string { if t.has_flag(.shared_f) { styp = g.find_or_register_shared(t, styp) } - if !t.has_flag(.variadic) { - nr_muls := g.unwrap_generic(t).nr_muls() - if nr_muls > 0 { - styp += strings.repeat(`*`, nr_muls) - } + nr_muls := g.unwrap_generic(t).nr_muls() + if nr_muls > 0 { + styp += strings.repeat(`*`, nr_muls) } return styp } diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index 352d9f8be0..2316bd78d7 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -559,7 +559,10 @@ fn (mut g Gen) fn_decl_params(params []ast.Param, scope &ast.Scope, is_variadic } else { c_name(param.name) } - typ := g.unwrap_generic(param.typ) + mut typ := g.unwrap_generic(param.typ) + if g.pref.translated && g.file.is_translated && param.typ.has_flag(.variadic) { + typ = g.table.sym(g.unwrap_generic(param.typ)).array_info().elem_type.set_flag(.variadic) + } param_type_sym := g.table.sym(typ) mut param_type_name := g.typ(typ) // util.no_dots(param_type_sym.name) if param_type_sym.kind == .function { diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index 572f8442d3..739a1d43be 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -967,7 +967,8 @@ fn (mut p Parser) fn_args() ([]ast.Param, bool, bool) { } } if is_variadic { - typ = ast.new_type(p.table.find_or_register_array(typ)).derive(typ).set_flag(.variadic) + // derive flags, however nr_muls only needs to be set on the array elem type, so clear it on the arg type + typ = ast.new_type(p.table.find_or_register_array(typ)).derive(typ).set_nr_muls(0).set_flag(.variadic) } for i, arg_name in arg_names { alanguage := p.table.sym(typ).language diff --git a/vlib/v/tests/fn_variadic_test.v b/vlib/v/tests/fn_variadic_test.v index ac610e1063..4ae5ac52b0 100644 --- a/vlib/v/tests/fn_variadic_test.v +++ b/vlib/v/tests/fn_variadic_test.v @@ -97,3 +97,20 @@ fn test_fn_variadic_method_no_args() { a := VaTestStruct{} a.variadic_method_no_args('marko') } + +// test vargs with pointer type +fn take_variadic_string_ptr(strings ...&string) { + take_array_string_ptr(strings) +} + +fn take_array_string_ptr(strings []&string) { + assert strings.len == 2 + assert *strings[0] == 'a' + assert *strings[1] == 'b' +} + +fn test_varg_pointer() { + a := 'a' + b := 'b' + take_variadic_string_ptr(&a, &b) +}