Can't return local slice stored in stack even with #force_inline

I want to convert constant array of floats into a slice of structs. I know that the returning pointer to the current stack frame will not work. Therefore i use #force_inline, expecting that slice data will be stored in the callers stack frame. But it doesn’t work and I get this error:

Error: Cannot assign value 'raw_data(&varr)' of type '[^]Vertex_Attributes' to '[]Vertex_Attributes' in return statement
        return raw_data(&varr)
               ^~~~~~~~~~~~~~^
Vertex_Attributes :: struct {
    pos: vec3,
    uv: vec2,
}

to_vertex_attributes :: #force_inline proc(arr: $T/[$N]f32) -> []Vertex_Attributes {
    varr := transmute([N/5]Vertex_Attributes)arr
    return varr[:]
}

main :: proc() {
    data := [?]f32{
        1, 2, 3, 4, 5,
        1, 2, 3, 4, 5,
    }

    vas := to_vertex_attributes(data)

    for va in vas {
        fmt.println(va)
    }
}

Am i missing something? Because i think i did similar thing in zig with “inline” keyword, and it just worked

P.s.
I solved my goal with a different approach:

to_vertex_attributes :: proc(fs: []f32) -> []Vertex_Attributes {
    varr := cast([^]Vertex_Attributes)raw_data(fs)
    return varr[:len(fs)/5]
}

main :: proc() {
    data := []f32{
        1, 2, 3, 4, 5,
        1, 2, 3, 4, 5,
    }

    vas := to_vertex_attributes(data)

    for va in vas {
        fmt.println(va)
    }
}

But i still curious on how to make first version to work…

#force_inline doesn’t semantically inline it (and in fact, -o:none/-debug builds still won’t actually inline it, for instance). The semantics don’t change, and returning a pointer to stack memory isn’t valid even in a #force_inline proc.

Reinterpreting the original data, as your updated example is doing, is a solid way of doing it. That also means you don’t have to make a copy of your data. You may also want to take a look at mem.slice_data_cast and slice.reinterpret, which both do the same thing, including recalculating the slice length based on the sizes of the source/destination types.

to_vertex_attributes :: proc(fs: []f32) -> []Vertex_Attributes {
    return slice.reinterpret([]Vertex_Attributes, fs)
}

The closest you can do to the original approach, I think (since N/5 can’t be used in the return type), would be to pass in a pointer to where to store the copied vertex attributes and let the caller control it.

3 Likes

@Barinzaya thank you again! your answers are very helpful :slight_smile: :pray: