Zig: Crash with switch on float inside inline for

Created on 28 Aug 2019  路  5Comments  路  Source: ziglang/zig

Segfaults during LLVM codegen.

Reduced repro:

pub fn float() f32 {
    return 0.2;
}

pub fn foo(comptime args: var) void {
    inline for (args) |a| {
        switch (float()) {
            0.0...100.0 => {},
            else => {},
        }
    }
}

test "foo" {
    foo([_]u32{ 20, 30, 57 });
}

This worked some time ago, does on 0.4.0 and still does with the trunk version available on godbolt.

bug stage1

Most helpful comment

I think it shouldn't be possible to switch on a float, because internally a float is always an approximation. Also the C standard prohibits the use of a float inside a switch expression.

Thus I think this should add a compile error when a float is used inside a switch expression.

All 5 comments

I think it shouldn't be possible to switch on a float, because internally a float is always an approximation. Also the C standard prohibits the use of a float inside a switch expression.

Thus I think this should add a compile error when a float is used inside a switch expression.

This should be a compiler error for floats, but the issue is reproduced even with an i32.

pub fn float() i32 {
    return 2;
}

pub fn foo(comptime args: var) void {
    inline for (args) |a| {
        switch (float()) {
            0...1 => {},
            else => {},
        }
    }
}

test "foo" {
    foo([_]u32{ 20, 30, 57 });
}
#0  0x0000000004afbb50 in llvm::BasicBlock::getTerminator() const ()
#1  0x0000000004b62073 in llvm::DomTreeBuilder::SemiNCAInfo<llvm::DominatorTreeBase<llvm::BasicBlock, true> >::ChildrenGetter<false>::Get(llvm::BasicBlock*, std::integral_constant<bool, false>) [clone .isra.343] ()
#2  0x0000000004b687cc in llvm::DomTreeBuilder::SemiNCAInfo<llvm::DominatorTreeBase<llvm::BasicBlock, false> >::ChildrenGetter<false>::Get(llvm::BasicBlock*, llvm::DomTreeBuilder::SemiNCAInfo<llvm::DominatorTreeBase<llvm::BasicBlock, false> >::BatchUpdateInfo*) ()
#3  0x0000000004b6b962 in unsigned int llvm::DomTreeBuilder::SemiNCAInfo<llvm::DominatorTreeBase<llvm::BasicBlock, false> >::runDFS<false, bool (*)(llvm::BasicBlock*, llvm::BasicBlock*)>(llvm::BasicBlock*, unsigned int, bool (*)(llvm::BasicBlock*, llvm::BasicBlock*), unsigned int) [clone .constprop.397] ()
#4  0x0000000004b6bb88 in llvm::DomTreeBuilder::SemiNCAInfo<llvm::DominatorTreeBase<llvm::BasicBlock, false> >::CalculateFromScratch(llvm::DominatorTreeBase<llvm::BasicBlock, false>&, llvm::DomTreeBuilder::SemiNCAInfo<llvm::DominatorTreeBase<llvm::BasicBlock, false> >::BatchUpdateInfo*) ()

Switching on floats came up in an issue regarding switch range syntax #359. I don't think any consensus was reached.

This program also segfaults the compiler:

const std = @import("std");

pub fn main() anyerror!void {
    var bar: f32 = 1.0;

    const my_bool = switch (bar) {
        1 => true,
        0 => false,
        else => false,
    };
    std.debug.warn("{}\n", .{my_bool});
}

Your problem is similar to #4074, some custom kind of lowering must be implemented during the codegen phase as LLVM can only switch on integer types.
But I think that switching on a float should be forbidden at the Zig level too.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

andrewrk picture andrewrk  路  3Comments

daurnimator picture daurnimator  路  3Comments

andrewrk picture andrewrk  路  3Comments

fengb picture fengb  路  3Comments

dobkeratops picture dobkeratops  路  3Comments