mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
all: various fixes for [heap]/auto-heap handling (#10033)
This commit is contained in:
parent
5b4eef8010
commit
d26ac5692e
@ -43,7 +43,7 @@ fn (mut ctx Context) println(s string) {
|
||||
}
|
||||
|
||||
fn do_timeout(c &Context) {
|
||||
mut ctx := c
|
||||
mut ctx := unsafe { c }
|
||||
time.sleep(ctx.timeout_ms * time.millisecond)
|
||||
exit(ctx.exitcode)
|
||||
}
|
||||
|
@ -171,7 +171,7 @@ fn (mut context Context) get_changed_vfiles() int {
|
||||
}
|
||||
|
||||
fn change_detection_loop(ocontext &Context) {
|
||||
mut context := ocontext
|
||||
mut context := unsafe { ocontext }
|
||||
for {
|
||||
if context.v_cycles >= max_v_cycles || context.scan_cycles >= max_scan_cycles {
|
||||
context.is_exiting = true
|
||||
|
@ -13,7 +13,7 @@ mut:
|
||||
}
|
||||
|
||||
fn my_audio_stream_callback(buffer &f32, num_frames int, num_channels int, mut acontext AppState) {
|
||||
mut soundbuffer := buffer
|
||||
mut soundbuffer := unsafe { buffer }
|
||||
for frame := 0; frame < num_frames; frame++ {
|
||||
t := int(f32(acontext.frame_0 + frame) * 0.245)
|
||||
// "Techno" by Gabriel Miceli
|
||||
|
@ -16,6 +16,7 @@ const (
|
||||
orange = ui.Color{255, 140, 0}
|
||||
)
|
||||
|
||||
[heap]
|
||||
struct App {
|
||||
mut:
|
||||
tui &ui.Context = 0
|
||||
@ -238,6 +239,7 @@ fn (mut b Ball) update(dt f32) {
|
||||
b.pos.y += b.vel.y * b.acc.y * dt
|
||||
}
|
||||
|
||||
[heap]
|
||||
struct Game {
|
||||
mut:
|
||||
app &App = 0
|
||||
|
@ -256,6 +256,7 @@ fn (mut r Rat) randomize() {
|
||||
r.app.height - block_size - buffer)
|
||||
}
|
||||
|
||||
[heap]
|
||||
struct App {
|
||||
mut:
|
||||
termui &termui.Context = 0
|
||||
|
@ -9,7 +9,7 @@ pub fn memcpy(dest &C.void, src &C.void, n size_t) &C.void {
|
||||
dest_[i] = src_[i]
|
||||
}
|
||||
}
|
||||
return dest
|
||||
return unsafe { dest }
|
||||
}
|
||||
|
||||
[export: 'malloc']
|
||||
@ -37,7 +37,7 @@ fn realloc(old_area &C.void, new_size size_t) &C.void {
|
||||
}
|
||||
old_size := unsafe { *(&u64(old_area - sizeof(u64))) }
|
||||
if u64(new_size) <= old_size {
|
||||
return old_area
|
||||
return unsafe { old_area }
|
||||
} else {
|
||||
new_area := unsafe { malloc(int(new_size)) }
|
||||
unsafe { memmove(new_area, old_area, size_t(old_size)) }
|
||||
@ -54,7 +54,7 @@ fn memset(s &C.void, c int, n size_t) &C.void {
|
||||
s_[i] = char(c)
|
||||
}
|
||||
}
|
||||
return s
|
||||
return unsafe { s }
|
||||
}
|
||||
|
||||
[unsafe]
|
||||
@ -74,7 +74,7 @@ fn memmove(dest &C.void, src &C.void, n size_t) &C.void {
|
||||
}
|
||||
}
|
||||
unsafe { free(temp_buf) }
|
||||
return dest
|
||||
return unsafe { dest }
|
||||
}
|
||||
|
||||
[export: 'calloc']
|
||||
|
@ -77,7 +77,7 @@ pub fn tos(s &byte, len int) string {
|
||||
panic('tos(): nil string')
|
||||
}
|
||||
return string{
|
||||
str: s
|
||||
str: unsafe { s }
|
||||
len: len
|
||||
}
|
||||
}
|
||||
@ -96,7 +96,7 @@ pub fn tos2(s &byte) string {
|
||||
panic('tos2: nil string')
|
||||
}
|
||||
return string{
|
||||
str: s
|
||||
str: unsafe { s }
|
||||
len: unsafe { vstrlen(s) }
|
||||
}
|
||||
}
|
||||
@ -146,7 +146,7 @@ pub fn tos_lit(s &char) string {
|
||||
[unsafe]
|
||||
pub fn (bp &byte) vstring() string {
|
||||
return string{
|
||||
str: bp
|
||||
str: unsafe { bp }
|
||||
len: unsafe { C.strlen(&char(bp)) }
|
||||
}
|
||||
}
|
||||
@ -156,7 +156,7 @@ pub fn (bp &byte) vstring() string {
|
||||
[unsafe]
|
||||
pub fn (bp &byte) vstring_with_len(len int) string {
|
||||
return string{
|
||||
str: bp
|
||||
str: unsafe { bp }
|
||||
len: len
|
||||
is_lit: 0
|
||||
}
|
||||
@ -194,7 +194,7 @@ pub fn (cp &char) vstring_with_len(len int) string {
|
||||
[unsafe]
|
||||
pub fn (bp &byte) vstring_literal() string {
|
||||
return string{
|
||||
str: bp
|
||||
str: unsafe { bp }
|
||||
len: unsafe { C.strlen(&char(bp)) }
|
||||
is_lit: 1
|
||||
}
|
||||
@ -205,7 +205,7 @@ pub fn (bp &byte) vstring_literal() string {
|
||||
[unsafe]
|
||||
pub fn (bp &byte) vstring_literal_with_len(len int) string {
|
||||
return string{
|
||||
str: bp
|
||||
str: unsafe { bp }
|
||||
len: len
|
||||
is_lit: 1
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ pub fn (mut cmd Command) add_command(command Command) {
|
||||
println('Command with the name `$subcmd.name` already exists')
|
||||
exit(1)
|
||||
}
|
||||
subcmd.parent = cmd
|
||||
subcmd.parent = unsafe { cmd }
|
||||
cmd.commands << subcmd
|
||||
}
|
||||
|
||||
@ -102,7 +102,7 @@ pub fn (mut cmd Command) add_command(command Command) {
|
||||
// is linked as a chain.
|
||||
pub fn (mut cmd Command) setup() {
|
||||
for mut subcmd in cmd.commands {
|
||||
subcmd.parent = cmd
|
||||
subcmd.parent = unsafe { cmd }
|
||||
subcmd.setup()
|
||||
}
|
||||
}
|
||||
|
@ -100,6 +100,7 @@ pub:
|
||||
native_rendering bool // Cocoa on macOS/iOS, GDI+ on Windows
|
||||
}
|
||||
|
||||
[heap]
|
||||
pub struct Context {
|
||||
render_text bool
|
||||
mut:
|
||||
|
@ -10,6 +10,7 @@ import sokol
|
||||
import sokol.sgl
|
||||
import stbi
|
||||
|
||||
[heap]
|
||||
pub struct Image {
|
||||
pub mut:
|
||||
id int
|
||||
|
@ -43,7 +43,7 @@ pub fn vec3(x f32, y f32, z f32) Vec3 {
|
||||
|
||||
fn mat4(f &f32) Mat4 {
|
||||
res := Mat4{
|
||||
data: f
|
||||
data: unsafe { f }
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ pub fn (mut r Response) write_string(s string) {
|
||||
[inline]
|
||||
pub fn (mut r Response) http_ok() &Response {
|
||||
r.write_string('HTTP/1.1 200 OK\r\n')
|
||||
return r
|
||||
return unsafe { r }
|
||||
}
|
||||
|
||||
[inline]
|
||||
@ -29,7 +29,7 @@ pub fn (mut r Response) header(k string, v string) &Response {
|
||||
r.write_string(': ')
|
||||
r.write_string(v)
|
||||
r.write_string('\r\n')
|
||||
return r
|
||||
return unsafe { r }
|
||||
}
|
||||
|
||||
[inline]
|
||||
@ -39,13 +39,13 @@ pub fn (mut r Response) header_date() &Response {
|
||||
r.buf += cpy(r.buf, r.date, 29)
|
||||
}
|
||||
r.write_string('\r\n')
|
||||
return r
|
||||
return unsafe { r }
|
||||
}
|
||||
|
||||
[inline]
|
||||
pub fn (mut r Response) header_server() &Response {
|
||||
r.write_string('Server: V\r\n')
|
||||
return r
|
||||
return unsafe { r }
|
||||
}
|
||||
|
||||
[inline]
|
||||
@ -53,25 +53,25 @@ pub fn (mut r Response) content_type(s string) &Response {
|
||||
r.write_string('Content-Type: ')
|
||||
r.write_string(s)
|
||||
r.write_string('\r\n')
|
||||
return r
|
||||
return unsafe { r }
|
||||
}
|
||||
|
||||
[inline]
|
||||
pub fn (mut r Response) html() &Response {
|
||||
r.write_string('Content-Type: text/html\r\n')
|
||||
return r
|
||||
return unsafe { r }
|
||||
}
|
||||
|
||||
[inline]
|
||||
pub fn (mut r Response) plain() &Response {
|
||||
r.write_string('Content-Type: text/plain\r\n')
|
||||
return r
|
||||
return unsafe { r }
|
||||
}
|
||||
|
||||
[inline]
|
||||
pub fn (mut r Response) json() &Response {
|
||||
r.write_string('Content-Type: application/json\r\n')
|
||||
return r
|
||||
return unsafe { r }
|
||||
}
|
||||
|
||||
[inline]
|
||||
|
@ -68,7 +68,7 @@ pub fn get_current_rng() &PRNG {
|
||||
// should be restored if work with the custom RNG is complete. It is not necessary to restore if the
|
||||
// program terminates soon afterwards.
|
||||
pub fn set_rng(rng &PRNG) {
|
||||
default_rng = rng
|
||||
default_rng = unsafe { rng }
|
||||
}
|
||||
|
||||
// seed sets the given array of `u32` values as the seed for the `default_rng`. The default_rng is
|
||||
|
@ -150,6 +150,7 @@ pub fn (b &C.sg_bindings) append_index_buffer(data voidptr, element_size int, el
|
||||
return C.sg_append_buffer(b.index_buffer, &range)
|
||||
}
|
||||
|
||||
[heap]
|
||||
pub struct C.sg_shader_desc {
|
||||
pub mut:
|
||||
_start_canary u32
|
||||
|
@ -510,7 +510,6 @@ pub mut:
|
||||
is_or bool // `x := foo() or { ... }`
|
||||
is_tmp bool // for tmp for loop vars, so that autofree can skip them
|
||||
is_auto_heap bool // value whoes address goes out of scope
|
||||
is_heap_ref bool // *known* to be pointer to heap memory (ptr to [heap] struct)
|
||||
is_stack_obj bool // may be pointer to stack value (`mut` or `&` arg and not [heap] struct)
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
// that can be found in the LICENSE file.
|
||||
module ast
|
||||
|
||||
[heap]
|
||||
pub struct Scope {
|
||||
pub mut:
|
||||
// mut:
|
||||
|
@ -282,7 +282,7 @@ pub fn (t &Table) type_has_method(s &TypeSymbol, name string) bool {
|
||||
// search from current type up through each parent looking for method
|
||||
pub fn (t &Table) type_find_method(s &TypeSymbol, name string) ?Fn {
|
||||
// println('type_find_method($s.name, $name) types.len=$t.types.len s.parent_idx=$s.parent_idx')
|
||||
mut ts := s
|
||||
mut ts := unsafe { s }
|
||||
for {
|
||||
if method := ts.find_method(name) {
|
||||
return method
|
||||
@ -337,7 +337,7 @@ pub fn (t &Table) struct_has_field(s &TypeSymbol, name string) bool {
|
||||
// search from current type up through each parent looking for field
|
||||
pub fn (t &Table) find_field(s &TypeSymbol, name string) ?StructField {
|
||||
// println('find_field($s.name, $name) types.len=$t.types.len s.parent_idx=$s.parent_idx')
|
||||
mut ts := s
|
||||
mut ts := unsafe { s }
|
||||
for {
|
||||
match mut ts.info {
|
||||
Struct {
|
||||
@ -401,7 +401,7 @@ pub fn (t &Table) find_field_with_embeds(sym &TypeSymbol, field_name string) ?St
|
||||
}
|
||||
|
||||
pub fn (t &Table) resolve_common_sumtype_fields(sym_ &TypeSymbol) {
|
||||
mut sym := sym_
|
||||
mut sym := unsafe { sym_ }
|
||||
mut info := sym.info as SumType
|
||||
if info.found_fields {
|
||||
return
|
||||
|
@ -64,6 +64,7 @@ pub fn pref_arch_to_table_language(pref_arch pref.Arch) Language {
|
||||
// * Table.type_kind(typ) not TypeSymbol.kind.
|
||||
// Each TypeSymbol is entered into `Table.types`.
|
||||
// See also: Table.get_type_symbol.
|
||||
|
||||
pub struct TypeSymbol {
|
||||
pub:
|
||||
parent_idx int
|
||||
@ -557,6 +558,15 @@ pub fn (t &TypeSymbol) sumtype_info() SumType {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (t &TypeSymbol) is_heap() bool {
|
||||
if t.kind == .struct_ {
|
||||
info := t.info as Struct
|
||||
return info.is_heap
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
pub fn (t TypeSymbol) str() string {
|
||||
return t.name
|
||||
|
@ -152,7 +152,7 @@ pub fn (mut c Checker) check2(ast_file &ast.File) []errors.Error {
|
||||
}
|
||||
|
||||
pub fn (mut c Checker) change_current_file(file &ast.File) {
|
||||
c.file = file
|
||||
c.file = unsafe { file }
|
||||
c.vmod_file_content = ''
|
||||
c.mod = file.mod.name
|
||||
}
|
||||
@ -666,11 +666,6 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) ast.Type {
|
||||
c.error('struct `$type_sym.name` is declared with a `[noinit]` attribute, so ' +
|
||||
'it cannot be initialized with `$type_sym.name{}`', struct_init.pos)
|
||||
}
|
||||
if info.is_heap && c.inside_decl_rhs && !c.inside_ref_lit && !c.inside_unsafe
|
||||
&& !struct_init.typ.is_ptr() {
|
||||
c.error('`$type_sym.name` type can only be used as a reference `&$type_sym.name` or inside a `struct` reference',
|
||||
struct_init.pos)
|
||||
}
|
||||
}
|
||||
if type_sym.name.len == 1 && c.cur_fn.generic_names.len == 0 {
|
||||
c.error('unknown struct `$type_sym.name`', struct_init.pos)
|
||||
@ -754,9 +749,12 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) ast.Type {
|
||||
continue
|
||||
}
|
||||
}
|
||||
mut expr_type := ast.Type(0)
|
||||
mut expected_type := ast.Type(0)
|
||||
if is_embed {
|
||||
c.expected_type = embed_type
|
||||
expr_type := c.expr(field.expr)
|
||||
expected_type = embed_type
|
||||
c.expected_type = expected_type
|
||||
expr_type = c.expr(field.expr)
|
||||
expr_type_sym := c.table.get_type_symbol(expr_type)
|
||||
if expr_type != ast.void_type && expr_type_sym.kind != .placeholder {
|
||||
c.check_expected(expr_type, embed_type) or {
|
||||
@ -769,8 +767,9 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) ast.Type {
|
||||
} else {
|
||||
inited_fields << field_name
|
||||
field_type_sym := c.table.get_type_symbol(info_field.typ)
|
||||
c.expected_type = info_field.typ
|
||||
mut expr_type := c.expr(field.expr)
|
||||
expected_type = info_field.typ
|
||||
c.expected_type = expected_type
|
||||
expr_type = c.expr(field.expr)
|
||||
if !info_field.typ.has_flag(.optional) {
|
||||
expr_type = c.check_expr_opt_call(field.expr, expr_type)
|
||||
}
|
||||
@ -798,6 +797,28 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) ast.Type {
|
||||
struct_init.fields[i].typ = expr_type
|
||||
struct_init.fields[i].expected_type = info_field.typ
|
||||
}
|
||||
if expr_type.is_ptr() && expected_type.is_ptr() {
|
||||
if mut field.expr is ast.Ident {
|
||||
if mut field.expr.obj is ast.Var {
|
||||
mut obj := unsafe { &field.expr.obj }
|
||||
if c.fn_scope != voidptr(0) {
|
||||
obj = c.fn_scope.find_var(obj.name) or { obj }
|
||||
}
|
||||
if obj.is_stack_obj && !c.inside_unsafe {
|
||||
sym := c.table.get_type_symbol(obj.typ.set_nr_muls(0))
|
||||
if !sym.is_heap() {
|
||||
suggestion := if sym.kind == .struct_ {
|
||||
'declaring `$sym.name` as `[heap]`'
|
||||
} else {
|
||||
'wrapping the `$sym.name` object in a `struct` declared as `[heap]`'
|
||||
}
|
||||
c.error('`$field.expr.name` cannot be assigned outside `unsafe` blocks as it might refer to an object stored on stack. Consider ${suggestion}.',
|
||||
field.expr.pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check uninitialized refs/sum types
|
||||
for field in info.fields {
|
||||
@ -2954,6 +2975,29 @@ pub fn (mut c Checker) return_stmt(mut return_stmt ast.Return) {
|
||||
c.error('fn `$c.cur_fn.name` expects you to return a reference type `${c.table.type_to_str(exp_type)}`, but you are returning `${c.table.type_to_str(got_typ)}` instead',
|
||||
pos)
|
||||
}
|
||||
if exp_type.is_ptr() && got_typ.is_ptr() {
|
||||
mut r_expr := &return_stmt.exprs[i]
|
||||
if mut r_expr is ast.Ident {
|
||||
if mut r_expr.obj is ast.Var {
|
||||
mut obj := unsafe { &r_expr.obj }
|
||||
if c.fn_scope != voidptr(0) {
|
||||
obj = c.fn_scope.find_var(r_expr.obj.name) or { obj }
|
||||
}
|
||||
if obj.is_stack_obj && !c.inside_unsafe {
|
||||
type_sym := c.table.get_type_symbol(obj.typ.set_nr_muls(0))
|
||||
if !type_sym.is_heap() {
|
||||
suggestion := if type_sym.kind == .struct_ {
|
||||
'declaring `$type_sym.name` as `[heap]`'
|
||||
} else {
|
||||
'wrapping the `$type_sym.name` object in a `struct` declared as `[heap]`'
|
||||
}
|
||||
c.error('`$r_expr.name` cannot be returned outside `unsafe` blocks as it might refer to an object stored on stack. Consider ${suggestion}.',
|
||||
r_expr.pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if exp_is_optional && return_stmt.exprs.len > 0 {
|
||||
expr0 := return_stmt.exprs[0]
|
||||
@ -3176,6 +3220,28 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
|
||||
c.fail_if_immutable(left)
|
||||
// left_type = c.expr(left)
|
||||
}
|
||||
if right_type.is_ptr() && left_type.is_ptr() {
|
||||
if mut right is ast.Ident {
|
||||
if mut right.obj is ast.Var {
|
||||
mut obj := unsafe { &right.obj }
|
||||
if c.fn_scope != voidptr(0) {
|
||||
obj = c.fn_scope.find_var(right.obj.name) or { obj }
|
||||
}
|
||||
if obj.is_stack_obj && !c.inside_unsafe {
|
||||
type_sym := c.table.get_type_symbol(obj.typ.set_nr_muls(0))
|
||||
if !type_sym.is_heap() {
|
||||
suggestion := if type_sym.kind == .struct_ {
|
||||
'declaring `$type_sym.name` as `[heap]`'
|
||||
} else {
|
||||
'wrapping the `$type_sym.name` object in a `struct` declared as `[heap]`'
|
||||
}
|
||||
c.error('`$right.name` cannot be assigned outside `unsafe` blocks as it might refer to an object stored on stack. Consider ${suggestion}.',
|
||||
right.pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
assign_stmt.left_types << left_type
|
||||
match mut left {
|
||||
ast.Ident {
|
||||
@ -3216,6 +3282,11 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
|
||||
if left.obj.is_auto_deref {
|
||||
left.obj.is_used = true
|
||||
}
|
||||
if !left_type.is_ptr() {
|
||||
if c.table.get_type_symbol(left_type).is_heap() {
|
||||
left.obj.is_auto_heap = true
|
||||
}
|
||||
}
|
||||
}
|
||||
ast.GlobalField {
|
||||
left.obj.typ = left_type
|
||||
@ -6046,17 +6117,27 @@ pub fn (mut c Checker) mark_as_referenced(mut node ast.Expr) {
|
||||
if mut node.obj is ast.Var {
|
||||
mut obj := unsafe { &node.obj }
|
||||
if c.fn_scope != voidptr(0) {
|
||||
obj = c.fn_scope.find_var(node.obj.name) or { unsafe { &node.obj } }
|
||||
obj = c.fn_scope.find_var(node.obj.name) or { obj }
|
||||
}
|
||||
type_sym := c.table.get_type_symbol(obj.typ)
|
||||
if obj.is_stack_obj {
|
||||
c.error('`$node.name` cannot be referenced outside `unsafe` blocks as it might be stored on stack. Consider declaring `$type_sym.name` as `[heap]`.',
|
||||
type_sym := c.table.get_type_symbol(obj.typ.set_nr_muls(0))
|
||||
if obj.is_stack_obj && !type_sym.is_heap() {
|
||||
suggestion := if type_sym.kind == .struct_ {
|
||||
'declaring `$type_sym.name` as `[heap]`'
|
||||
} else {
|
||||
'wrapping the `$type_sym.name` object in a `struct` declared as `[heap]`'
|
||||
}
|
||||
c.error('`$node.name` cannot be referenced outside `unsafe` blocks as it might be stored on stack. Consider ${suggestion}.',
|
||||
node.pos)
|
||||
} else if type_sym.kind == .array_fixed {
|
||||
c.error('cannot reference fixed array `$node.name` outside `unsafe` blocks as it is supposed to be stored on stack',
|
||||
node.pos)
|
||||
} else {
|
||||
node.obj.is_auto_heap = true
|
||||
if type_sym.kind == .struct_ {
|
||||
info := type_sym.info as ast.Struct
|
||||
if !info.is_heap {
|
||||
node.obj.is_auto_heap = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6930,7 +7011,7 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
|
||||
}
|
||||
}
|
||||
c.expected_type = ast.void_type
|
||||
c.cur_fn = node
|
||||
c.cur_fn = unsafe { node }
|
||||
// Add return if `fn(...) ? {...}` have no return at end
|
||||
if node.return_type != ast.void_type && node.return_type.has_flag(.optional)
|
||||
&& (node.stmts.len == 0 || node.stmts[node.stmts.len - 1] !is ast.Return) {
|
||||
|
@ -1,35 +0,0 @@
|
||||
vlib/v/checker/tests/heap_struct.vv:18:7: error: `Abc` type can only be used as a reference `&Abc` or inside a `struct` reference
|
||||
16 |
|
||||
17 | fn main() {
|
||||
18 | a := Abc{ n: 3 }
|
||||
| ~~~~~~~~~~~
|
||||
19 | b := St{
|
||||
20 | Abc{ n: 7 }
|
||||
vlib/v/checker/tests/heap_struct.vv:19:7: error: `St` type can only be used as a reference `&St` or inside a `struct` reference
|
||||
17 | fn main() {
|
||||
18 | a := Abc{ n: 3 }
|
||||
19 | b := St{
|
||||
| ~~~
|
||||
20 | Abc{ n: 7 }
|
||||
21 | }
|
||||
vlib/v/checker/tests/heap_struct.vv:20:3: error: `Abc` type can only be used as a reference `&Abc` or inside a `struct` reference
|
||||
18 | a := Abc{ n: 3 }
|
||||
19 | b := St{
|
||||
20 | Abc{ n: 7 }
|
||||
| ~~~~~~~~~~~
|
||||
21 | }
|
||||
22 | x := Qwe{
|
||||
vlib/v/checker/tests/heap_struct.vv:22:7: error: `Qwe` type can only be used as a reference `&Qwe` or inside a `struct` reference
|
||||
20 | Abc{ n: 7 }
|
||||
21 | }
|
||||
22 | x := Qwe{
|
||||
| ~~~~
|
||||
23 | f: 12.25
|
||||
24 | a: Abc{ n: 23 }
|
||||
vlib/v/checker/tests/heap_struct.vv:24:6: error: `Abc` type can only be used as a reference `&Abc` or inside a `struct` reference
|
||||
22 | x := Qwe{
|
||||
23 | f: 12.25
|
||||
24 | a: Abc{ n: 23 }
|
||||
| ~~~~~~~~~~~~
|
||||
25 | }
|
||||
26 | println('$a.n $b.n $x.a.n')
|
@ -1,27 +0,0 @@
|
||||
[heap]
|
||||
struct Abc {
|
||||
mut:
|
||||
n int
|
||||
}
|
||||
|
||||
struct St {
|
||||
Abc
|
||||
}
|
||||
|
||||
struct Qwe {
|
||||
mut:
|
||||
f f64
|
||||
a Abc
|
||||
}
|
||||
|
||||
fn main() {
|
||||
a := Abc{ n: 3 }
|
||||
b := St{
|
||||
Abc{ n: 7 }
|
||||
}
|
||||
x := Qwe{
|
||||
f: 12.25
|
||||
a: Abc{ n: 23 }
|
||||
}
|
||||
println('$a.n $b.n $x.a.n')
|
||||
}
|
21
vlib/v/checker/tests/no_heap_struct.out
Normal file
21
vlib/v/checker/tests/no_heap_struct.out
Normal file
@ -0,0 +1,21 @@
|
||||
vlib/v/checker/tests/no_heap_struct.vv:13:6: error: `x` cannot be assigned outside `unsafe` blocks as it might refer to an object stored on stack. Consider declaring `Abc` as `[heap]`.
|
||||
11 | fn f(x &Abc) St {
|
||||
12 | s := St{
|
||||
13 | a: x
|
||||
| ^
|
||||
14 | }
|
||||
15 | return s
|
||||
vlib/v/checker/tests/no_heap_struct.vv:19:9: error: `x` cannot be returned outside `unsafe` blocks as it might refer to an object stored on stack. Consider declaring `Abc` as `[heap]`.
|
||||
17 |
|
||||
18 | fn g(mut x Abc) &Abc {
|
||||
19 | return x
|
||||
| ^
|
||||
20 | }
|
||||
21 |
|
||||
vlib/v/checker/tests/no_heap_struct.vv:23:7: error: `x` cannot be assigned outside `unsafe` blocks as it might refer to an object stored on stack. Consider declaring `Abc` as `[heap]`.
|
||||
21 |
|
||||
22 | fn h(x &Abc) &Abc {
|
||||
23 | y := x
|
||||
| ^
|
||||
24 | return y
|
||||
25 | }
|
25
vlib/v/checker/tests/no_heap_struct.vv
Normal file
25
vlib/v/checker/tests/no_heap_struct.vv
Normal file
@ -0,0 +1,25 @@
|
||||
struct Abc {
|
||||
mut:
|
||||
n int
|
||||
}
|
||||
|
||||
struct St {
|
||||
mut:
|
||||
a &Abc
|
||||
}
|
||||
|
||||
fn f(x &Abc) St {
|
||||
s := St{
|
||||
a: x
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
fn g(mut x Abc) &Abc {
|
||||
return x
|
||||
}
|
||||
|
||||
fn h(x &Abc) &Abc {
|
||||
y := x
|
||||
return y
|
||||
}
|
@ -32,6 +32,7 @@ mut:
|
||||
methods map[string][]ast.FnDecl
|
||||
}
|
||||
|
||||
[heap]
|
||||
struct JsGen {
|
||||
table &ast.Table
|
||||
pref &pref.Preferences
|
||||
|
@ -20,6 +20,7 @@ interface CodeGen {
|
||||
// XXX WHY gen_exit fn (expr ast.Expr)
|
||||
}
|
||||
|
||||
[heap]
|
||||
pub struct Gen {
|
||||
out_name string
|
||||
pref &pref.Preferences // Preferences shared from V struct
|
||||
@ -67,7 +68,7 @@ fn (g &Gen) get_backend() ?CodeGen {
|
||||
}
|
||||
|
||||
pub fn gen(files []ast.File, table &ast.Table, out_name string, pref &pref.Preferences) (int, int) {
|
||||
mut g := Gen{
|
||||
mut g := &Gen{
|
||||
table: table
|
||||
sect_header_name_pos: 0
|
||||
out_name: out_name
|
||||
|
@ -292,19 +292,8 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
||||
scope: 0
|
||||
}
|
||||
}
|
||||
mut is_heap_ref := false // args are only borrowed, so assume maybe on stack
|
||||
mut is_stack_obj := true
|
||||
nr_muls := param.typ.nr_muls()
|
||||
if nr_muls == 1 { // mut a St, b &St
|
||||
base_type_sym := p.table.get_type_symbol(param.typ.set_nr_muls(0))
|
||||
if base_type_sym.kind == .struct_ {
|
||||
info := base_type_sym.info as ast.Struct
|
||||
is_heap_ref = info.is_heap // if type is declared as [heap] we can assume this, too
|
||||
is_stack_obj = !is_heap_ref
|
||||
}
|
||||
}
|
||||
if param.typ.has_flag(.shared_f) {
|
||||
is_heap_ref = true
|
||||
is_stack_obj = false
|
||||
}
|
||||
p.scope.register(ast.Var{
|
||||
@ -312,7 +301,6 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
||||
typ: param.typ
|
||||
is_mut: param.is_mut
|
||||
is_auto_deref: param.is_mut || param.is_auto_rec
|
||||
is_heap_ref: is_heap_ref
|
||||
is_stack_obj: is_stack_obj
|
||||
pos: param.pos
|
||||
is_used: true
|
||||
@ -601,19 +589,8 @@ fn (mut p Parser) anon_fn() ast.AnonFn {
|
||||
if arg.name.len == 0 {
|
||||
p.error_with_pos('use `_` to name an unused parameter', arg.pos)
|
||||
}
|
||||
mut is_heap_ref := false // args are only borrowed, so assume maybe on stack
|
||||
mut is_stack_obj := true
|
||||
nr_muls := arg.typ.nr_muls()
|
||||
if nr_muls == 1 { // mut a St, b &St
|
||||
base_type_sym := p.table.get_type_symbol(arg.typ.set_nr_muls(0))
|
||||
if base_type_sym.kind == .struct_ {
|
||||
info := base_type_sym.info as ast.Struct
|
||||
is_heap_ref = info.is_heap // if type is declared as [heap] we can assume this, too
|
||||
is_stack_obj = !is_heap_ref
|
||||
}
|
||||
}
|
||||
if arg.typ.has_flag(.shared_f) {
|
||||
is_heap_ref = true
|
||||
is_stack_obj = false
|
||||
}
|
||||
p.scope.register(ast.Var{
|
||||
@ -623,7 +600,6 @@ fn (mut p Parser) anon_fn() ast.AnonFn {
|
||||
pos: arg.pos
|
||||
is_used: true
|
||||
is_arg: true
|
||||
is_heap_ref: is_heap_ref
|
||||
is_stack_obj: is_stack_obj
|
||||
})
|
||||
}
|
||||
|
@ -1,18 +1,19 @@
|
||||
struct Qwe {
|
||||
[heap]
|
||||
struct Hwe {
|
||||
mut:
|
||||
n int
|
||||
}
|
||||
|
||||
fn mut_x(mut x Qwe) &Qwe {
|
||||
fn mut_x(mut x Hwe) &Hwe {
|
||||
n := x.n
|
||||
// defer statement should not have run, yet
|
||||
assert n == 10
|
||||
x.n += 5
|
||||
return unsafe { &x }
|
||||
return &x
|
||||
}
|
||||
|
||||
fn deferer() &Qwe {
|
||||
mut s := &Qwe{
|
||||
fn deferer() &Hwe {
|
||||
mut s := &Hwe{
|
||||
n: 10
|
||||
}
|
||||
defer {
|
||||
@ -28,6 +29,15 @@ fn test_defer_in_return() {
|
||||
assert q.n == 17
|
||||
}
|
||||
|
||||
struct Qwe {
|
||||
mut:
|
||||
n int
|
||||
}
|
||||
|
||||
fn ret_ref(mut x Qwe) &Qwe {
|
||||
return unsafe { x }
|
||||
}
|
||||
|
||||
fn defer_multi_ret(mut a Qwe) (int, f64) {
|
||||
defer {
|
||||
a.n *= 2
|
||||
|
@ -5,7 +5,7 @@ mut:
|
||||
}
|
||||
|
||||
fn (mut s MyStruct<T>) add(e &T) bool {
|
||||
s.buffer[0] = e
|
||||
s.buffer[0] = unsafe { e }
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ pub fn (mut gitstructure GitStructure) repo_get(name string) ?&GitRepo {
|
||||
}
|
||||
|
||||
fn test_opt_ref_return() {
|
||||
mut gitstruct := &GitStructure{
|
||||
mut gitstruct := GitStructure{
|
||||
root: 'r'
|
||||
repos: [
|
||||
&GitRepo{
|
||||
|
61
vlib/v/tests/heap_struct_test.v
Normal file
61
vlib/v/tests/heap_struct_test.v
Normal file
@ -0,0 +1,61 @@
|
||||
[heap]
|
||||
struct Abc {
|
||||
mut:
|
||||
n int
|
||||
}
|
||||
|
||||
struct St {
|
||||
Abc
|
||||
}
|
||||
|
||||
struct Qwe {
|
||||
mut:
|
||||
f f64
|
||||
a Abc
|
||||
}
|
||||
|
||||
fn pass_abc(q &Abc) &Abc {
|
||||
return q
|
||||
}
|
||||
|
||||
fn pass_st(q &St) &St {
|
||||
return q
|
||||
}
|
||||
|
||||
fn pass_qwe(q &Qwe) &Qwe {
|
||||
return q
|
||||
}
|
||||
|
||||
fn get_ref_structs() (&Abc, &St, &Qwe) {
|
||||
a := Abc{
|
||||
n: 3
|
||||
}
|
||||
b := St{Abc{
|
||||
n: 7
|
||||
}}
|
||||
x := Qwe{
|
||||
f: 12.25
|
||||
a: Abc{
|
||||
n: 23
|
||||
}
|
||||
}
|
||||
aa := pass_abc(&a)
|
||||
bb := pass_st(&b)
|
||||
xx := pass_qwe(&x)
|
||||
return aa, bb, xx
|
||||
}
|
||||
|
||||
fn owerwrite_stack() f64 {
|
||||
a := 12.5
|
||||
b := 3.5
|
||||
c := a + b
|
||||
return c
|
||||
}
|
||||
|
||||
fn test_ref_struct() {
|
||||
u, v, w := get_ref_structs()
|
||||
d := owerwrite_stack()
|
||||
assert u.n == 3
|
||||
assert v.n == 7
|
||||
assert w.a.n == 23
|
||||
}
|
@ -11,17 +11,17 @@ fn new(x int) &Test {
|
||||
|
||||
fn (mut t Test) inc() &Test {
|
||||
t.val++
|
||||
return t
|
||||
return unsafe { t }
|
||||
}
|
||||
|
||||
fn (mut t Test) add(x int) &Test {
|
||||
t.val += x
|
||||
return t
|
||||
return unsafe { t }
|
||||
}
|
||||
|
||||
fn (mut t Test) div(x int) &Test {
|
||||
t.val /= x
|
||||
return t
|
||||
return unsafe { t }
|
||||
}
|
||||
|
||||
fn test_method_call_chains() {
|
||||
|
@ -7,7 +7,7 @@ mut:
|
||||
|
||||
fn (mut p Player) set_name(name string) &Player {
|
||||
p.name = name
|
||||
return p // because of automatic (de)reference of return values
|
||||
return unsafe { p } // because of automatic (de)reference of return values
|
||||
}
|
||||
|
||||
// NB: `p` is declared as a `mut` parameter,
|
||||
|
@ -231,7 +231,7 @@ fn opt_ptr(a &int) ?&int {
|
||||
if isnil(a) {
|
||||
return none
|
||||
}
|
||||
return a
|
||||
return unsafe { a }
|
||||
}
|
||||
|
||||
fn test_opt_ptr() {
|
||||
|
@ -264,7 +264,7 @@ fn bar_config(c Config, def int) {
|
||||
fn mut_bar_config(mut c Config, def int) &Config {
|
||||
c.n = c.def
|
||||
assert c.n == def
|
||||
return c
|
||||
return unsafe { c }
|
||||
}
|
||||
|
||||
fn foo_user(u User) {}
|
||||
|
@ -37,7 +37,7 @@ pub struct SSEMessage {
|
||||
|
||||
pub fn new_connection(conn &net.TcpConn) &SSEConnection {
|
||||
return &SSEConnection{
|
||||
conn: conn
|
||||
conn: unsafe { conn }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -329,7 +329,7 @@ fn handle_conn<T>(mut conn net.TcpConn, mut app T) {
|
||||
}
|
||||
app.Context = Context{
|
||||
req: req
|
||||
conn: conn
|
||||
conn: unsafe { conn }
|
||||
form: map[string]string{}
|
||||
static_files: app.static_files
|
||||
static_mime_types: app.static_mime_types
|
||||
|
@ -98,8 +98,8 @@ fn (mut s Server) parse_client_handshake(client_handshake string, mut c Client)
|
||||
server_client := &ServerClient{
|
||||
resource_name: get_tokens[1]
|
||||
client_key: key
|
||||
client: c
|
||||
server: s
|
||||
client: unsafe { c }
|
||||
server: unsafe { s }
|
||||
}
|
||||
unsafe {
|
||||
lines.free()
|
||||
|
Loading…
Reference in New Issue
Block a user