Comptime struct function pointer default value

Hello! I’m trying to create a struct definition where the struct fields are function pointers. However, if I try to assign a default value, I get the following error:

error: comptime dereference requires 'fn () void' to have a well-defined layout
    break :blk @Type(.{ .@"struct" = .{
...

The following code is a minimal(ish) reproduction of what I’m trying to accomplish.

const std = @import("std");
const FnT = *const fn () void;

const Goal = struct {
    fn_ptr: FnT = empty,
};

const Attempt = blk: {
    const field = std.builtin.Type.StructField{
        .name = "fn_ptr",
        .is_comptime = false,
        .type = FnT,
        .alignment = @alignOf(FnT),
        .default_value_ptr = empty,
    };

    const fields = &[_]std.builtin.Type.StructField{field};
    break :blk @Type(.{ .@"struct" = .{
        .backing_integer = null,
        .decls = &[_]std.builtin.Type.Declaration{},
        .fields = fields,
        .is_tuple = false,
        .layout = .auto,
    } });
};

pub fn main() void {
    // Compiles.
    // const foo: Goal = .{};
    // foo.fn_ptr();

    // Does not compile.
    const foo: Attempt = .{};
    foo.fn_ptr();
}

fn empty() void {
    std.debug.print("Hello, world", .{});
}

I’ve tried a couple things like assigning the function to a variable, manually casting to an ?*const anyopaque, but I can’t seem to get this to work.

I’m hoping that there is some syntax that I’m missing/misusing, and I would love any and all help in getting this to work.

Thanks.

The default_value_ptr is a pointer to the default value. &empty is the function pointer, it needs another & to get the pointer to the default value.

const std = @import("std");

const FnT = *const fn () void;

fn Attempt() type {
    return @Type(.{ .@"struct" = .{
        .layout = .auto,
        .backing_integer = null,
        .fields = &[_]std.builtin.Type.StructField{
            .{
                .name = "fn_ptr",
                .type = FnT,
                .default_value_ptr = @as(*const anyopaque, @ptrCast(&@as(FnT, &empty))),
                .is_comptime = false,
                .alignment = @alignOf(FnT),
            },
        },
        .decls = &[_]std.builtin.Type.Declaration{},
        .is_tuple = false,
    } });
}

pub fn main() void {
    const foo: Attempt() = .{};
    foo.fn_ptr();
}

fn empty() void {
    std.debug.print("Hello, world", .{});
}

Welcome to ziggit! :slight_smile:

1 Like

Thank you so much for your help! I was indeed missing two &’s.

The explicit type conversion with @as in the solution is not necessary, @ptrCast(&&empty) works.

1 Like