Skip to content

cgen: error for unused functions returning fixed arrays of custom structs #26439

@demizer

Description

@demizer

Describe the bug

When skip_unused is enabled (default), functions that return fixed-size arrays of custom structs (e.g., [4]MyStruct) but are never called cause C compilation errors. The V compiler generates a wrapper struct for the return type that references the custom struct, but the custom struct itself is not emitted because it's considered "unused".

This only occurs in larger codebases where skip_unused optimization has an effect.

Reproduction Steps

struct QuadVertex {
    pos [2]f32
    uv  [2]f32
}

// This function is never called
pub fn make_quad_vertices(x f32, y f32, w f32, h f32) [4]QuadVertex {
    return [
        QuadVertex{pos: [x, y]!, uv: [f32(0), 0]!},
        QuadVertex{pos: [x + w, y]!, uv: [f32(1), 0]!},
        QuadVertex{pos: [x + w, y + h]!, uv: [f32(1), 1]!},
        QuadVertex{pos: [x, y + h]!, uv: [f32(0), 1]!},
    ]!
}

fn main() {
    // make_quad_vertices is intentionally not called
    println('hello')
}

Note: This may not reproduce in a small isolated file. The bug manifests in larger codebases (e.g., 57k+ lines) where skip_unused actively removes unused code.

Expected Behavior

The code should compile successfully. If a function is unused, its return type wrapper struct should either:

  1. Not be generated, OR
  2. Have its element type also generated

Current Behavior

C compilation fails with:

error: ';' expected (got "main__QuadVertex")

The generated C code contains:

// In BEGIN_array_fixed_return_structs section:
struct _v_Array_fixed_main__QuadVertex_4 {
    main__QuadVertex ret_arr[4];  // ERROR: main__QuadVertex not defined!
};

But main__QuadVertex is never defined because skip_unused determined it was unused.

Possible Solution

In write_array_fixed_return_types() in vlib/v/gen/c/cgen.v, skip generating wrapper structs when the element type is a non-builtin struct that isn't marked as used:

elem_sym := g.table.sym(info.elem_type)
if g.pref.skip_unused && elem_sym.kind == .struct && !elem_sym.is_builtin()
    && elem_sym.idx !in g.table.used_features.used_syms {
    continue
}

Additional Information/Context

  • The bug only affects functions that RETURN fixed arrays of custom structs
  • Functions that take fixed arrays as PARAMETERS work fine
  • Using -no-skip-unused flag works around the issue
  • Builtin element types (e.g., [4]int, [4]f32) are not affected

V version

V 0.5.0 c3b924c

Environment details (OS name and version, etc.)

V full version V 0.5.0 c3b924c.c2aa96a
OS linux, "Arch Linux" (VM)
Processor 12 cpus, 64bit, little endian, AMD Ryzen Threadripper 7960X 24-Cores
Memory 1.95GB/47GB
V executable /home/jesusa/code/v/v/v
V last modified time 2026-01-25 17:52:50
V home dir OK, value: /home/jesusa/code/v/v
VMODULES OK, value: /home/jesusa/.vmodules
VTMP OK, value: /tmp/v_1000
Current working dir OK, value: /home/jesusa/code/v/vrasta
Git version git version 2.52.0
V git status weekly.2026.04-20-gc2aa96a2-dirty
.git/config present true
cc version cc (GCC) 15.2.1 20260103
gcc version gcc (GCC) 15.2.1 20260103
clang version clang version 21.1.6
tcc version tcc version 0.9.28rc 2025-02-13 HEAD@f8bd136d (x86_64 Linux)
tcc git status thirdparty-linux-amd64 696c1d84
emcc version N/A
glibc version ldd (GNU libc) 2.42

Note

You can use the 👍 reaction to increase the issue's priority for developers.

Please note that only the 👍 reaction to the issue itself counts as a vote.
Other reactions and those to comments will not be taken into account.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions