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.
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.
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.