mirror of
https://github.com/vlang/v.git
synced 2025-09-10 16:00:31 -04:00
cgen: force C struct types which does not implement str() to be passed as ptr (#21054)
This commit is contained in:
parent
0b573c5943
commit
24d157205b
@ -30,7 +30,11 @@ pub fn (a Character) == (b Character) bool {
|
|||||||
// to_rune creates a V rune, given a Character
|
// to_rune creates a V rune, given a Character
|
||||||
@[inline]
|
@[inline]
|
||||||
pub fn (c Character) to_rune() rune {
|
pub fn (c Character) to_rune() rune {
|
||||||
|
$if windows {
|
||||||
|
return unsafe { *(&rune(&c)) } & 0xFFFF
|
||||||
|
} $else {
|
||||||
return unsafe { *(&rune(&c)) }
|
return unsafe { *(&rune(&c)) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// from_rune creates a Character, given a V rune
|
// from_rune creates a Character, given a V rune
|
||||||
|
@ -934,6 +934,15 @@ pub fn (t &TypeSymbol) is_array_fixed() bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn (t &TypeSymbol) is_c_struct() bool {
|
||||||
|
if t.info is Struct {
|
||||||
|
return t.language == .c
|
||||||
|
} else if t.info is Alias {
|
||||||
|
return global_table.final_sym(t.info.parent_type).is_c_struct()
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
pub fn (t &TypeSymbol) is_array_fixed_ret() bool {
|
pub fn (t &TypeSymbol) is_array_fixed_ret() bool {
|
||||||
if t.info is ArrayFixed {
|
if t.info is ArrayFixed {
|
||||||
return t.info.is_fn_ret
|
return t.info.is_fn_ret
|
||||||
@ -1707,6 +1716,9 @@ pub fn (t &TypeSymbol) str_method_info() (bool, bool, int) {
|
|||||||
if nr_args > 0 {
|
if nr_args > 0 {
|
||||||
expects_ptr = sym_str_method.params[0].typ.is_ptr()
|
expects_ptr = sym_str_method.params[0].typ.is_ptr()
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// C Struct which does not implement str() are passed as pointer to handle incomplete type
|
||||||
|
expects_ptr = t.is_c_struct()
|
||||||
}
|
}
|
||||||
return has_str_method, expects_ptr, nr_args
|
return has_str_method, expects_ptr, nr_args
|
||||||
}
|
}
|
||||||
|
@ -248,19 +248,25 @@ fn (mut g Gen) gen_str_for_result(typ ast.Type, styp string, str_fn_name string)
|
|||||||
|
|
||||||
fn (mut g Gen) gen_str_for_alias(info ast.Alias, styp string, str_fn_name string) {
|
fn (mut g Gen) gen_str_for_alias(info ast.Alias, styp string, str_fn_name string) {
|
||||||
parent_str_fn_name := g.get_str_fn(info.parent_type)
|
parent_str_fn_name := g.get_str_fn(info.parent_type)
|
||||||
_, str_method_expects_ptr, _ := g.table.sym(info.parent_type).str_method_info()
|
parent_sym := g.table.sym(info.parent_type)
|
||||||
|
_, str_method_expects_ptr, _ := parent_sym.str_method_info()
|
||||||
|
|
||||||
$if trace_autostr ? {
|
$if trace_autostr ? {
|
||||||
eprintln('> gen_str_for_alias: ${parent_str_fn_name} | ${styp} | ${str_fn_name}')
|
eprintln('> gen_str_for_alias: ${parent_str_fn_name} | ${styp} | ${str_fn_name}')
|
||||||
}
|
}
|
||||||
mut clean_type_v_type_name := util.strip_main_name(styp.replace('__', '.'))
|
mut clean_type_v_type_name := util.strip_main_name(styp.replace('__', '.'))
|
||||||
g.definitions.writeln('static string ${str_fn_name}(${styp} it); // auto')
|
|
||||||
g.auto_str_funcs.writeln('static string ${str_fn_name}(${styp} it) { return indent_${str_fn_name}(it, 0); }')
|
is_c_struct := parent_sym.is_c_struct() && str_method_expects_ptr
|
||||||
g.definitions.writeln('static string indent_${str_fn_name}(${styp} it, int indent_count); // auto')
|
arg_def := if is_c_struct { '${styp}* it' } else { '${styp} it' }
|
||||||
g.auto_str_funcs.writeln('static string indent_${str_fn_name}(${styp} it, int indent_count) {')
|
|
||||||
|
g.definitions.writeln('static string ${str_fn_name}(${arg_def}); // auto')
|
||||||
|
g.auto_str_funcs.writeln('static string ${str_fn_name}(${arg_def}) { return indent_${str_fn_name}(it, 0); }')
|
||||||
|
g.definitions.writeln('static string indent_${str_fn_name}(${arg_def}, int indent_count); // auto')
|
||||||
|
g.auto_str_funcs.writeln('static string indent_${str_fn_name}(${arg_def}, int indent_count) {')
|
||||||
g.auto_str_funcs.writeln('\tstring indents = string_repeat(_SLIT(" "), indent_count);')
|
g.auto_str_funcs.writeln('\tstring indents = string_repeat(_SLIT(" "), indent_count);')
|
||||||
if str_method_expects_ptr {
|
if str_method_expects_ptr {
|
||||||
g.auto_str_funcs.writeln('\tstring tmp_ds = ${parent_str_fn_name}(&it);')
|
it_arg := if is_c_struct { 'it' } else { '&it' }
|
||||||
|
g.auto_str_funcs.writeln('\tstring tmp_ds = ${parent_str_fn_name}(${it_arg});')
|
||||||
} else {
|
} else {
|
||||||
deref, _ := deref_kind(str_method_expects_ptr, info.parent_type.is_ptr(), info.parent_type)
|
deref, _ := deref_kind(str_method_expects_ptr, info.parent_type.is_ptr(), info.parent_type)
|
||||||
g.auto_str_funcs.writeln('\tstring tmp_ds = ${parent_str_fn_name}(${deref}it);')
|
g.auto_str_funcs.writeln('\tstring tmp_ds = ${parent_str_fn_name}(${deref}it);')
|
||||||
@ -882,14 +888,17 @@ fn (mut g Gen) gen_str_for_struct(info ast.Struct, lang ast.Language, styp strin
|
|||||||
eprintln('> gen_str_for_struct: ${info.parent_type.debug()} | ${styp} | ${str_fn_name}')
|
eprintln('> gen_str_for_struct: ${info.parent_type.debug()} | ${styp} | ${str_fn_name}')
|
||||||
}
|
}
|
||||||
// _str() functions should have a single argument, the indenting ones take 2:
|
// _str() functions should have a single argument, the indenting ones take 2:
|
||||||
g.definitions.writeln('static string ${str_fn_name}(${styp} it); // auto')
|
is_c_struct := lang == .c
|
||||||
g.auto_str_funcs.writeln('static string ${str_fn_name}(${styp} it) { return indent_${str_fn_name}(it, 0);}')
|
arg_def := if is_c_struct { '${styp}* it' } else { '${styp} it' }
|
||||||
g.definitions.writeln('static string indent_${str_fn_name}(${styp} it, int indent_count); // auto')
|
g.definitions.writeln('static string ${str_fn_name}(${arg_def}); // auto')
|
||||||
|
g.auto_str_funcs.writeln('static string ${str_fn_name}(${arg_def}) { return indent_${str_fn_name}(it, 0);}')
|
||||||
|
g.definitions.writeln('static string indent_${str_fn_name}(${arg_def}, int indent_count); // auto')
|
||||||
mut fn_builder := strings.new_builder(512)
|
mut fn_builder := strings.new_builder(512)
|
||||||
defer {
|
defer {
|
||||||
g.auto_fn_definitions << fn_builder.str()
|
g.auto_fn_definitions << fn_builder.str()
|
||||||
}
|
}
|
||||||
fn_builder.writeln('static string indent_${str_fn_name}(${styp} it, int indent_count) {')
|
fn_builder.writeln('static string indent_${str_fn_name}(${arg_def}, int indent_count) {')
|
||||||
|
|
||||||
clean_struct_v_type_name := if info.is_anon { 'struct ' } else { util.strip_main_name(typ_str) }
|
clean_struct_v_type_name := if info.is_anon { 'struct ' } else { util.strip_main_name(typ_str) }
|
||||||
// generate ident / indent length = 4 spaces
|
// generate ident / indent length = 4 spaces
|
||||||
if info.fields.len == 0 {
|
if info.fields.len == 0 {
|
||||||
@ -997,18 +1006,20 @@ fn (mut g Gen) gen_str_for_struct(info ast.Struct, lang ast.Language, styp strin
|
|||||||
field_styp_fn_name, field.name, sym_has_str_method, str_method_expects_ptr)
|
field_styp_fn_name, field.name, sym_has_str_method, str_method_expects_ptr)
|
||||||
ftyp_nr_muls := field.typ.nr_muls()
|
ftyp_nr_muls := field.typ.nr_muls()
|
||||||
field_name := if lang == .c { field.name } else { c_name(field.name) }
|
field_name := if lang == .c { field.name } else { c_name(field.name) }
|
||||||
|
op := if is_c_struct { '->' } else { '.' }
|
||||||
|
it_field_name := 'it${op}${field_name}'
|
||||||
if ftyp_nr_muls > 1 || field.typ in ast.cptr_types {
|
if ftyp_nr_muls > 1 || field.typ in ast.cptr_types {
|
||||||
if is_opt_field {
|
if is_opt_field {
|
||||||
} else {
|
} else {
|
||||||
func = '(voidptr) it.${field.name}'
|
func = '(voidptr) ${it_field_name}'
|
||||||
caller_should_free = false
|
caller_should_free = false
|
||||||
}
|
}
|
||||||
} else if ftyp_noshared.is_ptr() {
|
} else if ftyp_noshared.is_ptr() {
|
||||||
// reference types can be "nil"
|
// reference types can be "nil"
|
||||||
if ftyp_noshared.has_flag(.option) {
|
if ftyp_noshared.has_flag(.option) {
|
||||||
funcprefix += 'isnil(&it.${field_name}) || isnil(&it.${field_name}.data)'
|
funcprefix += 'isnil(&${it_field_name}) || isnil(&${it_field_name}.data)'
|
||||||
} else {
|
} else {
|
||||||
funcprefix += 'isnil(it.${field_name})'
|
funcprefix += 'isnil(${it_field_name})'
|
||||||
}
|
}
|
||||||
funcprefix += ' ? _SLIT("nil") : '
|
funcprefix += ' ? _SLIT("nil") : '
|
||||||
// struct, floats and ints have a special case through the _str function
|
// struct, floats and ints have a special case through the _str function
|
||||||
@ -1031,9 +1042,9 @@ fn (mut g Gen) gen_str_for_struct(info ast.Struct, lang ast.Language, styp strin
|
|||||||
if is_field_array {
|
if is_field_array {
|
||||||
if is_opt_field {
|
if is_opt_field {
|
||||||
arr_styp := g.base_type(field.typ)
|
arr_styp := g.base_type(field.typ)
|
||||||
fn_body.write_string('it.${field_name}.state != 2 && (*(${arr_styp}*)it.${field_name}.data).len > 0 ? ${funcprefix}_SLIT("[<circular>]") : ${funcprefix}_SLIT("[]")')
|
fn_body.write_string('${it_field_name}.state != 2 && (*(${arr_styp}*)${it_field_name}.data).len > 0 ? ${funcprefix}_SLIT("[<circular>]") : ${funcprefix}_SLIT("[]")')
|
||||||
} else {
|
} else {
|
||||||
fn_body.write_string('it.${field_name}.len > 0 ? ${funcprefix}_SLIT("[<circular>]") : ${funcprefix}_SLIT("[]")')
|
fn_body.write_string('${it_field_name}.len > 0 ? ${funcprefix}_SLIT("[<circular>]") : ${funcprefix}_SLIT("[]")')
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fn_body.write_string('${funcprefix}_SLIT("<circular>")')
|
fn_body.write_string('${funcprefix}_SLIT("<circular>")')
|
||||||
@ -1065,6 +1076,25 @@ fn (mut g Gen) gen_str_for_struct(info ast.Struct, lang ast.Language, styp strin
|
|||||||
fn_body.writeln('\t}));')
|
fn_body.writeln('\t}));')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// c_struct_ptr handles the C struct argument for .str() method
|
||||||
|
@[inline]
|
||||||
|
pub fn c_struct_ptr(sym &ast.TypeSymbol, typ ast.Type, expects_ptr bool) string {
|
||||||
|
if sym.is_c_struct() {
|
||||||
|
if typ.has_flag(.option) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
if typ.nr_muls() >= 1 {
|
||||||
|
if expects_ptr {
|
||||||
|
return '*'.repeat(typ.nr_muls() - 1)
|
||||||
|
} else {
|
||||||
|
return '*'.repeat(typ.nr_muls())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return if expects_ptr { '&' } else { '' }
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
fn struct_auto_str_func(sym &ast.TypeSymbol, lang ast.Language, _field_type ast.Type, fn_name string, field_name string, has_custom_str bool, expects_ptr bool) (string, bool) {
|
fn struct_auto_str_func(sym &ast.TypeSymbol, lang ast.Language, _field_type ast.Type, fn_name string, field_name string, has_custom_str bool, expects_ptr bool) (string, bool) {
|
||||||
$if trace_autostr ? {
|
$if trace_autostr ? {
|
||||||
eprintln('> struct_auto_str_func: ${sym.name} | field_type.debug() | ${fn_name} | ${field_name} | ${has_custom_str} | ${expects_ptr}')
|
eprintln('> struct_auto_str_func: ${sym.name} | field_type.debug() | ${fn_name} | ${field_name} | ${has_custom_str} | ${expects_ptr}')
|
||||||
@ -1073,13 +1103,15 @@ fn struct_auto_str_func(sym &ast.TypeSymbol, lang ast.Language, _field_type ast.
|
|||||||
sufix := if field_type.has_flag(.shared_f) { '->val' } else { '' }
|
sufix := if field_type.has_flag(.shared_f) { '->val' } else { '' }
|
||||||
deref, _ := deref_kind(expects_ptr, field_type.is_ptr(), field_type)
|
deref, _ := deref_kind(expects_ptr, field_type.is_ptr(), field_type)
|
||||||
final_field_name := if lang == .c { field_name } else { c_name(field_name) }
|
final_field_name := if lang == .c { field_name } else { c_name(field_name) }
|
||||||
|
op := if lang == .c { '->' } else { '.' }
|
||||||
|
prefix := if sym.is_c_struct() { c_struct_ptr(sym, _field_type, expects_ptr) } else { deref }
|
||||||
if sym.kind == .enum_ {
|
if sym.kind == .enum_ {
|
||||||
return '${fn_name}(${deref}(it.${final_field_name}))', true
|
return '${fn_name}(${deref}(it${op}${final_field_name}))', true
|
||||||
} else if _field_type.has_flag(.option) || should_use_indent_func(sym.kind) {
|
} else if _field_type.has_flag(.option) || should_use_indent_func(sym.kind) {
|
||||||
obj := '${deref}it.${final_field_name}${sufix}'
|
obj := '${prefix}it${op}${final_field_name}${sufix}'
|
||||||
if has_custom_str {
|
if has_custom_str {
|
||||||
if sym.kind == .interface_ && (sym.info as ast.Interface).defines_method('str') {
|
if sym.kind == .interface_ && (sym.info as ast.Interface).defines_method('str') {
|
||||||
iface_obj := 'it.${final_field_name}${sufix}'
|
iface_obj := '${prefix}it${op}${final_field_name}${sufix}'
|
||||||
dot := if field_type.is_ptr() { '->' } else { '.' }
|
dot := if field_type.is_ptr() { '->' } else { '.' }
|
||||||
return '${fn_name.trim_string_right('_str')}_name_table[${iface_obj}${dot}_typ]._method_str(${iface_obj}${dot}_object)', true
|
return '${fn_name.trim_string_right('_str')}_name_table[${iface_obj}${dot}_typ]._method_str(${iface_obj}${dot}_object)', true
|
||||||
}
|
}
|
||||||
@ -1087,24 +1119,24 @@ fn struct_auto_str_func(sym &ast.TypeSymbol, lang ast.Language, _field_type ast.
|
|||||||
}
|
}
|
||||||
return 'indent_${fn_name}(${obj}, indent_count + 1)', true
|
return 'indent_${fn_name}(${obj}, indent_count + 1)', true
|
||||||
} else if sym.kind in [.array, .array_fixed, .map, .sum_type] {
|
} else if sym.kind in [.array, .array_fixed, .map, .sum_type] {
|
||||||
obj := '${deref}it.${final_field_name}${sufix}'
|
obj := '${prefix}it${op}${final_field_name}${sufix}'
|
||||||
if has_custom_str {
|
if has_custom_str {
|
||||||
return '${fn_name}(${obj})', true
|
return '${fn_name}(${obj})', true
|
||||||
}
|
}
|
||||||
return 'indent_${fn_name}(${obj}, indent_count + 1)', true
|
return 'indent_${fn_name}(${obj}, indent_count + 1)', true
|
||||||
} else if sym.kind == .function {
|
} else if sym.kind == .function {
|
||||||
obj := '${deref}it.${final_field_name}${sufix}'
|
obj := '${deref}it${op}${final_field_name}${sufix}'
|
||||||
return '${fn_name}(${obj})', true
|
return '${fn_name}(${obj})', true
|
||||||
} else if sym.kind == .chan {
|
} else if sym.kind == .chan {
|
||||||
return '${fn_name}(${deref}it.${final_field_name}${sufix})', true
|
return '${fn_name}(${deref}it${op}${final_field_name}${sufix})', true
|
||||||
} else if sym.kind == .thread {
|
} else if sym.kind == .thread {
|
||||||
return '${fn_name}(${deref}it.${final_field_name}${sufix})', false
|
return '${fn_name}(${deref}it${op}${final_field_name}${sufix})', false
|
||||||
} else {
|
} else {
|
||||||
mut method_str := ''
|
mut method_str := ''
|
||||||
if !field_type.is_ptr() && field_type.has_option_or_result() {
|
if !field_type.is_ptr() && field_type.has_option_or_result() {
|
||||||
method_str = '(*(${sym.name}*)it.${final_field_name}.data)'
|
method_str = '(*(${sym.name}*)it${op}${final_field_name}.data)'
|
||||||
} else {
|
} else {
|
||||||
method_str = 'it.${final_field_name}'
|
method_str = 'it${op}${final_field_name}'
|
||||||
}
|
}
|
||||||
if sym.kind == .bool {
|
if sym.kind == .bool {
|
||||||
return '${method_str} ? _SLIT("true") : _SLIT("false")', false
|
return '${method_str} ? _SLIT("true") : _SLIT("false")', false
|
||||||
|
@ -2458,7 +2458,6 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type_raw ast.Type, expected_typ
|
|||||||
lock g.referenced_fns {
|
lock g.referenced_fns {
|
||||||
g.referenced_fns[fname] = true
|
g.referenced_fns[fname] = true
|
||||||
}
|
}
|
||||||
fname = '/*${exp_sym}*/${fname}'
|
|
||||||
if exp_sym.info.is_generic {
|
if exp_sym.info.is_generic {
|
||||||
fname = g.generic_fn_name(exp_sym.info.concrete_types, fname)
|
fname = g.generic_fn_name(exp_sym.info.concrete_types, fname)
|
||||||
}
|
}
|
||||||
|
@ -181,11 +181,21 @@ fn (mut g Gen) dump_expr_definitions() {
|
|||||||
surrounder.add('\tstring value = isnil(&dump_arg.data) ? _SLIT("nil") : ${to_string_fn_name}(${deref}dump_arg);',
|
surrounder.add('\tstring value = isnil(&dump_arg.data) ? _SLIT("nil") : ${to_string_fn_name}(${deref}dump_arg);',
|
||||||
'\tstring_free(&value);')
|
'\tstring_free(&value);')
|
||||||
} else {
|
} else {
|
||||||
surrounder.add('\tstring value = (dump_arg == NULL) ? _SLIT("nil") : ${to_string_fn_name}(${deref}dump_arg);',
|
prefix := if dump_sym.is_c_struct() {
|
||||||
|
c_struct_ptr(dump_sym, dump_type, str_method_expects_ptr)
|
||||||
|
} else {
|
||||||
|
deref
|
||||||
|
}
|
||||||
|
surrounder.add('\tstring value = (dump_arg == NULL) ? _SLIT("nil") : ${to_string_fn_name}(${prefix}dump_arg);',
|
||||||
'\tstring_free(&value);')
|
'\tstring_free(&value);')
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
surrounder.add('\tstring value = ${to_string_fn_name}(${deref}dump_arg);',
|
prefix := if dump_sym.is_c_struct() {
|
||||||
|
c_struct_ptr(dump_sym, dump_type, str_method_expects_ptr)
|
||||||
|
} else {
|
||||||
|
deref
|
||||||
|
}
|
||||||
|
surrounder.add('\tstring value = ${to_string_fn_name}(${prefix}dump_arg);',
|
||||||
'\tstring_free(&value);')
|
'\tstring_free(&value);')
|
||||||
}
|
}
|
||||||
surrounder.add('
|
surrounder.add('
|
||||||
|
@ -151,7 +151,7 @@ fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype ast.Type) {
|
|||||||
}
|
}
|
||||||
g.write('${str_fn_name}(')
|
g.write('${str_fn_name}(')
|
||||||
if str_method_expects_ptr && !is_ptr {
|
if str_method_expects_ptr && !is_ptr {
|
||||||
if is_dump_expr {
|
if is_dump_expr || (g.pref.ccompiler_type != .tinyc && expr is ast.CallExpr) {
|
||||||
g.write('ADDR(${g.typ(typ)}, ')
|
g.write('ADDR(${g.typ(typ)}, ')
|
||||||
defer {
|
defer {
|
||||||
g.write(')')
|
g.write(')')
|
||||||
@ -162,8 +162,14 @@ fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype ast.Type) {
|
|||||||
} else if is_ptr && typ.has_flag(.option) {
|
} else if is_ptr && typ.has_flag(.option) {
|
||||||
g.write('*(${g.typ(typ)}*)&')
|
g.write('*(${g.typ(typ)}*)&')
|
||||||
} else if !str_method_expects_ptr && !is_shared && (is_ptr || is_var_mut) {
|
} else if !str_method_expects_ptr && !is_shared && (is_ptr || is_var_mut) {
|
||||||
|
if sym.is_c_struct() {
|
||||||
|
g.write(c_struct_ptr(sym, typ, str_method_expects_ptr))
|
||||||
|
} else {
|
||||||
g.write('*'.repeat(typ.nr_muls()))
|
g.write('*'.repeat(typ.nr_muls()))
|
||||||
}
|
}
|
||||||
|
} else if sym.is_c_struct() {
|
||||||
|
g.write(c_struct_ptr(sym, typ, str_method_expects_ptr))
|
||||||
|
}
|
||||||
if expr is ast.ArrayInit {
|
if expr is ast.ArrayInit {
|
||||||
if expr.is_fixed {
|
if expr.is_fixed {
|
||||||
s := g.typ(expr.typ)
|
s := g.typ(expr.typ)
|
||||||
@ -199,6 +205,10 @@ fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype ast.Type) {
|
|||||||
g.write('&')
|
g.write('&')
|
||||||
} else if (!str_method_expects_ptr && is_ptr && !is_shared) || is_var_mut {
|
} else if (!str_method_expects_ptr && is_ptr && !is_shared) || is_var_mut {
|
||||||
g.write('*')
|
g.write('*')
|
||||||
|
} else {
|
||||||
|
if sym.is_c_struct() {
|
||||||
|
g.write(c_struct_ptr(sym, typ, str_method_expects_ptr))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
g.expr_with_cast(expr, typ, typ)
|
g.expr_with_cast(expr, typ, typ)
|
||||||
} else if typ.has_flag(.option) {
|
} else if typ.has_flag(.option) {
|
||||||
|
@ -61,7 +61,6 @@ fn (mut g Gen) str_format(node ast.StringInterLiteral, i int, fmts []u8) (u64, s
|
|||||||
mut remove_tail_zeros := false
|
mut remove_tail_zeros := false
|
||||||
fspec := fmts[i]
|
fspec := fmts[i]
|
||||||
mut fmt_type := StrIntpType.si_no_str
|
mut fmt_type := StrIntpType.si_no_str
|
||||||
g.write('/*${fspec} ${sym}*/')
|
|
||||||
// upper cases
|
// upper cases
|
||||||
if (fspec - `A`) <= (`Z` - `A`) {
|
if (fspec - `A`) <= (`Z` - `A`) {
|
||||||
upper_case = true
|
upper_case = true
|
||||||
|
@ -2,3 +2,11 @@
|
|||||||
struct Abc {
|
struct Abc {
|
||||||
int field;
|
int field;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct Test2 {
|
||||||
|
int a;
|
||||||
|
} Test2;
|
||||||
|
|
||||||
|
typedef struct Test1 {
|
||||||
|
Test2 a;
|
||||||
|
} Test1;
|
50
vlib/v/tests/c_structs/cstruct_str_test.v
Normal file
50
vlib/v/tests/c_structs/cstruct_str_test.v
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#include "@VMODROOT/cstruct.h"
|
||||||
|
|
||||||
|
@[typedef]
|
||||||
|
struct C.Test2 {}
|
||||||
|
|
||||||
|
@[typedef]
|
||||||
|
struct C.Test1 {
|
||||||
|
a C.Test2
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (s C.Test2) str() string {
|
||||||
|
return 'test2'
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (s C.Test1) get() C.Test1 {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (s C.Test1) s() string {
|
||||||
|
return '.${s.get()}.'
|
||||||
|
}
|
||||||
|
|
||||||
|
type TestAlias = C.Test2
|
||||||
|
|
||||||
|
fn (s TestAlias) str() string {
|
||||||
|
return 'test_alias'
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (s TestAlias) get() TestAlias {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_main() {
|
||||||
|
x := unsafe { &C.Test1(malloc(1024)) }
|
||||||
|
println(x)
|
||||||
|
assert dump('${x}') == '&C.Test1{
|
||||||
|
a: test2
|
||||||
|
}'
|
||||||
|
println('.${x.get()}.${x.s()}')
|
||||||
|
|
||||||
|
y := unsafe { &TestAlias(malloc(1024)) }
|
||||||
|
println(y)
|
||||||
|
assert dump('${y}') == '&test_alias'
|
||||||
|
println('.${y.get()}.')
|
||||||
|
|
||||||
|
w := TestAlias(*y)
|
||||||
|
assert dump(w.str()) == 'test_alias'
|
||||||
|
|
||||||
|
assert true
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user