Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

continue inside inline for cause compiler crash #2604

Closed
hcff opened this issue May 31, 2019 · 5 comments
Closed

continue inside inline for cause compiler crash #2604

hcff opened this issue May 31, 2019 · 5 comments
Labels
bug Observed behavior contradicts documented or intended behavior stage1 The process of building from source via WebAssembly and the C backend.
Milestone

Comments

@hcff
Copy link
Contributor

hcff commented May 31, 2019

Version : 0.4.0+d1b6f29d
This is similar to #834.

const std = @import("std");

const ints = []u32{ 42, 1337, 0xdeadbeef };

fn do_thing(int: u32) error{IsALeet}!void {
    std.debug.warn("{}\n", int);
    if (int == 1337) return error.IsALeet;
}

pub fn main() void {
    inline for (ints) |int| {
        do_thing(int) catch |_| continue;
        std.debug.warn("not a leet\n");
    }
}

The code above gives a compiler crash.

 $ gdb zig
GNU gdb (GDB) Fedora 8.2-6.fc29
...
(gdb) run build-exe main.zig
Starting program: zig build-exe main.zig

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff634a220 in llvm::BasicBlock::getContext() const ()
(gdb) bt
#0  0x00007ffff634a220 in llvm::BasicBlock::getContext() const ()
#1  0x00007ffff63dea89 in llvm::BranchInst::BranchInst(llvm::BasicBlock*, llvm::BasicBlock*, llvm::Value*, llvm::Instruction*) ()
#2  0x00007ffff63761e8 in LLVMBuildCondBr ()
#3  0x00007ffff250249a in ir_render_instruction(CodeGen*, IrExecutable*, IrInstruction*) [clone .isra.206] ()
#4  0x00007ffff2503cf5 in do_code_gen(CodeGen*) ()
#5  0x00007ffff2507407 in codegen_build_and_link(CodeGen*) ()
#6  0x00007ffff24302bd in main ()

A if on the error union will give a comptime control flow inside runtime block error :

pub fn main() void {
    inline for (ints) |int| {
        if (do_thing(int)) |_| {}
        else |_| { continue; }
        std.debug.warn("not a leet\n");
    }
}

By the way, I don't think doing that should be an error since breaking on the inner block compile correctly, and is essentially the same thing.

pub fn main() void {
    inline for (ints) |int| blk: {
        do_thing(int) catch |_| break :blk;
        std.debug.warn("not a leet\n");
    }
}
 $ zig build-exe main.zig
 $ ./main 
42
not a leet
1337
3735928559
not a leet
@andrewrk andrewrk added this to the 0.5.0 milestone Jun 5, 2019
@andrewrk andrewrk added the bug Observed behavior contradicts documented or intended behavior label Jun 5, 2019
@Sahnvour
Copy link
Member

Sahnvour commented Jul 2, 2019

I think I had more or less the same bug on another snippet:

const std = @import("std");
const builtin = @import("builtin");
const meta = std.meta;
test "foo" {
    const Foo = union(enum) {
        A: u32,
        B: u32,
    };

    const key = Foo{ .A = 1 };

    switch (@typeInfo(Foo)) {
        // builtin.TypeId.Union => |info| {
        builtin.TypeId.Union => |info| blk: {
            if (info.tag_type) |tag_type| {
                const tag = meta.activeTag(key);
                inline for (info.fields) |field| {
                    const enum_field = field.enum_field.?;
                    if (enum_field.value == @enumToInt(tag)) {
                        std.debug.warn("{}", enum_field.name);
                        // return;
                        break :blk;
                    }
                }
            }
        },
        else => {},
    }
}

break :blk; causes a crash.

Callstack:

>	zig.exe!llvm::Value::getType() Line 245	C++
 	zig.exe!llvm::BasicBlock::getContext() Line 34	C++
 	zig.exe!llvm::BranchInst::BranchInst(llvm::BasicBlock * IfTrue, llvm::Instruction * InsertBefore) Line 987	C++
 	zig.exe!llvm::BranchInst::Create(llvm::BasicBlock * IfTrue, llvm::Instruction * InsertBefore) Line 3023	C++
 	zig.exe!llvm::IRBuilder<llvm::ConstantFolder,llvm::IRBuilderDefaultInserter>::CreateBr(llvm::BasicBlock * Dest) Line 849	C++
 	zig.exe!LLVMBuildBr(LLVMOpaqueBuilder * B, LLVMOpaqueBasicBlock * Dest) Line 2960	C++
 	zig.exe!ir_render_br(CodeGen * g, IrExecutable * executable, IrInstructionBr * br_instruction) Line 3323	C++
 	zig.exe!ir_render_instruction(CodeGen * g, IrExecutable * executable, IrInstruction * instruction) Line 5652	C++
 	zig.exe!ir_render(CodeGen * g, ZigFn * fn_entry) Line 5834	C++
 	zig.exe!do_code_gen(CodeGen * g) Line 6849	C++
 	zig.exe!codegen_build_and_link(CodeGen * g) Line 9616	C++
 	zig.exe!main(int argc, char * * argv) Line 1204	C++

In ir_render_br, dest_block->llvm_block is null, but I didn't have time to investigate further. Or rather, to make substantial findings.

@andrewrk
Copy link
Member

andrewrk commented Jul 3, 2019

I just pushed a fix for the original test case, which now gives error: comptime control flow inside runtime block.

By the way, I don't think doing that should be an error since breaking on the inner block compile correctly, and is essentially the same thing.

Making this not a compile error needs to be a separate proposal. More examples need to be examined and an implementation will be nontrivial.

@Sahnvour your test case still crashes, turns out it is a separate issue.

@andrewrk andrewrk modified the milestones: 0.5.0, 0.6.0 Sep 26, 2019
@andrewrk andrewrk added the stage1 The process of building from source via WebAssembly and the C backend. label Jan 7, 2020
@andrewrk andrewrk modified the milestones: 0.6.0, 0.7.0 Jan 7, 2020
@xxxbxxx
Copy link
Contributor

xxxbxxx commented Jan 11, 2020

I think I had the same issue?

this fails to compile:

export fn func() u32 {
    var s : u32 = 0;
    inline for ([_]u8{1,2}) |phase| {
        var i: u32 = 0;
        while (i<4) : (i+=1) {
            if (phase == i) 
                continue;
            s += i;
        }
    }
    return s;
}

And, if I reverse the if to avoid the continue, it compiles and works:
(and the same workaround works on my more complex actual code)

export fn func() u32 {
    var s : u32 = 0;
    inline for ([_]u8{1,2}) |phase| {
        var i: u32 = 0;
        while (i<4) : (i+=1) {
            if (phase != i)  {
                 s += i;
            }
        }
    }
    return s;
}

I'd guess it is related to control flow with 'goto' like constructs (had similar issues with break :label value when trying to find a workaournd).
I have the feeling it tries to jump to the label from the wrong iteration of the unrolled for or something..

@andrewrk andrewrk modified the milestones: 0.7.0, 0.8.0 Aug 13, 2020
@aarvay
Copy link
Contributor

aarvay commented Oct 17, 2020

I encountered this compiler error too while I was toying around, implementing a small parser combinator. Here's the implementation of OneOf()

fn OneOf(comptime rezolvrs: anytype) Rezolvr(RezolvrType(rezolvrs)) {
    return struct {
        fn rezolve(input: []const u8) Error!Result(RezolvrType(rezolvrs)) {
            inline for (rezolvrs) |r| {
                return r(input) catch continue;
            }
            return Error.TermRejected;

            // Worked around it like this:
            // if (rezolvrs.len == 0) return Error.TermRejected;
            // return rezolvrs[0](input) catch OneOf(rezolvrs[1..])(input);
        }
    }.rezolve;
}

I expected that the inline for version would work.

@andrewrk andrewrk modified the milestones: 0.8.0, 0.9.0 Nov 6, 2020
@Vexu Vexu mentioned this issue Dec 20, 2020
@andrewrk andrewrk modified the milestones: 0.9.0, 0.10.0 May 19, 2021
@andrewrk
Copy link
Member

Works fine with 0.11.0-dev.971+19056cb68. Test coverage here:

[nix-shell:~/dev/zig/build-release]$ grep -RI 'comptime control flow inside runtime block' ../test/
../test/cases/compile_errors/comptime_continue_to_outer_inline_loop.zig:// :9:30: error: comptime control flow inside runtime block
../test/cases/compile_errors/comptime_continue_inside_runtime_orelse.zig:// :4:22: error: comptime control flow inside runtime block
../test/cases/compile_errors/comptime_continue_inside_runtime_if_bool.zig:// :5:22: error: comptime control flow inside runtime block
../test/cases/compile_errors/comptime_continue_inside_runtime_if_error.zig:// :5:20: error: comptime control flow inside runtime block
../test/cases/compile_errors/comptime_continue_inside_runtime_while_optional.zig:// :5:23: error: comptime control flow inside runtime block
../test/cases/compile_errors/comptime_continue_inside_runtime_switch.zig:// :6:19: error: comptime control flow inside runtime block
../test/cases/compile_errors/comptime_continue_inside_runtime_catch.zig:// :4:21: error: comptime control flow inside runtime block
../test/cases/compile_errors/comptime_continue_inside_runtime_if_optional.zig:// :5:20: error: comptime control flow inside runtime block
../test/cases/compile_errors/comptime_continue_inside_runtime_while_error.zig:// :6:13: error: comptime control flow inside runtime block
../test/cases/compile_errors/comptime_continue_inside_runtime_while_bool.zig:// :5:25: error: comptime control flow inside runtime block

@andrewrk andrewrk modified the milestones: 0.12.0, 0.11.0 Dec 27, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Observed behavior contradicts documented or intended behavior stage1 The process of building from source via WebAssembly and the C backend.
Projects
None yet
Development

No branches or pull requests

5 participants