zig icon indicating copy to clipboard operation
zig copied to clipboard

std.fmt.formatType fails when a field is a function

Open RossComputerGuy opened this issue 2 years ago • 7 comments

Zig Version

0.11.0-dev.1969+d525ecb52

Steps to Reproduce and Observed Behavior

const std = @import("std");

const ExampleStruct = struct {
  method: fn () void,
};

fn method_impl() void {
}

pub fn main() void {
  const s = ExampleStruct {
    .method = method_impl,
  };

  std.debug.print("{}\n", .{ s });
}

Try using this example to print the structure. I believe the expected functionality should be similar to C which is to print the memory address of the method. Instead we get this error:

/nix/store/b9gg248ddpqp5pv26xmz937v2b6vwkc9-zig-0.11.0-dev.1969+d525ecb52/lib/std/fmt.zig:708:73: error: expected pointer, found 'fn() void'
            return format(writer, "{s}@{x}", .{ @typeName(T), @ptrToInt(value) });
                                                                        ^~~~~
referenced by:
    formatType__anon_6727: /nix/store/b9gg248ddpqp5pv26xmz937v2b6vwkc9-zig-0.11.0-dev.1969+d525ecb52/lib/std/fmt.zig:596:21
    format__anon_6715: /nix/store/b9gg248ddpqp5pv26xmz937v2b6vwkc9-zig-0.11.0-dev.1969+d525ecb52/lib/std/fmt.zig:184:13
    remaining reference traces hidden; use '-freference-trace' to see all reference traces

Expected Behavior

Zig should either print the memory address or name of the method instead of failing to compile.

RossComputerGuy avatar Mar 14 '23 23:03 RossComputerGuy

fn () void is a function body type, not a function pointer. It doesn't exist at runtime so it doesn't have an address and the formatting code doesn't have access to the name of the function.

Vexu avatar Mar 15 '23 10:03 Vexu

Why does *const fn () void work but not fn () void? I though all functions have an address or else they couldn't be executed by the CPU?

RossComputerGuy avatar Mar 15 '23 17:03 RossComputerGuy

Because *const fn() void is a function pointer so it can also exist at runtime.

Vexu avatar Mar 15 '23 18:03 Vexu

Now I'm confused, how does adding *const change the function in a way that makes the address accessible? As far as I know, you cannot execute code unless it is mapped into memory. That means it would have an address, so no matter if it's got *const or not, it exists in memory.

RossComputerGuy avatar Mar 15 '23 18:03 RossComputerGuy

fn () void is a function body type, it does not exist at runtime. *const fn () void is a function pointer which has an address at runtime.

Vexu avatar Mar 15 '23 18:03 Vexu

Well, that explains it a bit more but my methods are called at runtime and not at comptime. Adding *const did fix the issue but it also required a few other things in this to make it so it wouldn't error out on saying some structs depend on each other:

  • https://github.com/ExpidusOS/neutron/commit/dd6b4fe71ac5bf6570521a92485b39a751e5a79d
  • https://github.com/ExpidusOS/neutron/commit/33f58941078f7f5f72153e2f070200b33e461b3a
  • https://github.com/ExpidusOS/neutron/commit/3a244cd8b51e885c94e629de75dcf074d2c8fc75

RossComputerGuy avatar Mar 15 '23 19:03 RossComputerGuy

I've figured out how to fix it in my code, maybe it should throw an error differently there like:

Expected constant pointer function, got a function body type.

RossComputerGuy avatar Mar 15 '23 20:03 RossComputerGuy