ziglang / zig

General-purpose programming language and toolchain for maintaining robust, optimal, and reusable software.
https://ziglang.org
MIT License
34.41k stars 2.52k forks source link

zig build-exe process Killed #4223

Open GrooveStomp opened 4 years ago

GrooveStomp commented 4 years ago

I've pulled master today (2020-01-18) and have reproduced this on both master and 0.5.0. Here's a gist with the problem program: https://gist.github.com/GrooveStomp/15d8d8b8827d59ece022b325be9c3ac6

Reproduced here:

const Dispatch = struct {
    op: fn() void = undefined,
};

fn A() void {}
fn B() void {}
fn C() void {}
fn D() void {}

pub fn main() void {
    var dispatch = Dispatch{ .op = A };
    switch (dispatch.op) {
        A => A(),
        B => B(),
        C => C(),
        D => D(),
        else => unreachable,
    }
}

This does not build. Output with zig 0.5.0:

zig build-exe main.zig
Killed

And with zig (edge) 0.5.0+b72f85819 from Jay Petacat (jayschwa) refreshed:

zig build-exe main.zig
LLVM Emit Output...Killed
GrooveStomp commented 4 years ago

And, OS specifics, for reference:

Linux pop-os 5.3.0-19-generic #20-Ubuntu SMP Fri Oct 18 09:04:39 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

LemonBoy commented 4 years ago

Switching over function types is not supported as the effective address of a function is not known until link-time.

@andrewrk maybe it's time to define what types are accepted by switch

JesseRMeyer commented 4 years ago

Switching over function types is not supported as the effective address of a function is not known until link-time.

What's the reason why the compiler can't just stub these out for the linker. eg. just jump to a label or whatever address the linker fills in (even as part of LTO)? It would be very nice to not have this be a limitation, especially if Zig wants to allure OOP programmers.

LemonBoy commented 4 years ago

What's the reason why the compiler can't just stub these out for the linker.

Switch lowering is a delicate and complex matter and LLVM tries its best to produce something good. To do so it has to reason about the switch cases values at compile time, hence the LLVM error.

We could lower this kind of switch using a chain of if/else if this turns out to be a supported use case.

JesseRMeyer commented 4 years ago

Huh. I suppose the recent LTO trend blurs the line between compile and link time, only adding to my confusion. I definitely see the issue if compilation and linking are considered two separate steps, which would force the compiler in this case to generate non-optimal code, as well as adhere to some convention the linker understands to satisfy the semantics of the switch statement.

At least in my C code I accomplish this by switching on an enum and then calling the function that enum refers to, which is already straight forwardly doable in Zig.

GrooveStomp commented 4 years ago

Interesting. I can resort to an if-else chain; but aesthetically a switch is more desirable. I am obviously not at all clear on the semantics of switch and have been making do.

FYI, this code compiles and works:

const std = @import("std");

const Dispatch = struct {
    op: fn() void = undefined,
};

fn A() void {
    std.debug.warn("A\n", .{});
}
fn B() void {
    std.debug.warn("B\n", .{});
}
fn C() void {
    std.debug.warn("C\n", .{});
}
fn D() void {
    std.debug.warn("D\n", .{});
}

pub fn main() void {
    var dispatch = Dispatch{ .op = A };
    switch (dispatch.op) {
        A => A(),
        B => B(),
        C => C(),
        else => unreachable,
    }
}
JesseRMeyer commented 4 years ago

@GrooveStomp On Godbolt with release-fast it results in a panic when main is exported.

https://godbolt.org/z/pL3RCn

andrewrk commented 4 years ago

Added "docs" to remind to add which types a switch allows to the language specification before closing the issue.

GrooveStomp commented 4 years ago

I'll try this again when I get home, but the behavior here, even if it's not supposed to work was bad. My processor utilization spiked, the build took several seconds longer than normal before being terminated (without input) by the OS. I'll pull latest and see if this is still true; but it was happening on both 0.5.0 and master when reported here.