zig icon indicating copy to clipboard operation
zig copied to clipboard

AutoArrayHashMap: Alignment error when key type is single-member enum and value type is void

Open cryptocode opened this issue 4 years ago • 2 comments

Zig Version

0.10.0-dev.295+f19b5ecf4

Steps to Reproduce

This occurs when the AutoArrayHashMap key type is an enum with a single member and the value type is void.

This construct is unlikely to be seen in real-world code, but occurred in a test-case where the hashmap was part of a larger structure taking an enum type argument.

const std = @import("std");

test "alignment error" {
    const E = enum { a };
    var map = std.AutoArrayHashMap(E, void).init(std.testing.allocator);
    defer map.deinit();
}

The compile error disappears if a) another enum member is added, or b) a value type is specified.

Expected Behavior

Successful compilation

Actual Behavior

Fails with

build/lib/zig/std/multi_array_list.zig:19:25: error: alignment must be >= 1
        bytes: [*]align(@alignOf(S)) u8 = undefined,
                        ^
build/lib/zig/std/multi_array_list.zig:19:9: note: referenced here
        bytes: [*]align(@alignOf(S)) u8 = undefined,
        ^
./repro.zig:5:44: note: referenced here
    var map = std.AutoArrayHashMap(E, void).init(std.testing.allocator);

cryptocode avatar Jan 17 '22 23:01 cryptocode

I agree that align(@alignOf(u0)) ought to work, and that making it work would be a better way to solve this issue.

Maybe @alignOf(u0) should return null rather than 0? @alignOf(T) == n implies that ptr % n must equal 0 if ptr is the address of a variable of type T, but the expression ptr % 0 is undefined, and pointers to zero sized types don't have an address.

Or put another way: u0 has neither an address nor a required alignment, so @alignOf(u0) should be null.

Making @alignOf(u0) return null and allowing align specifiers to accept null to indicate natural alignment would also make the interface consistent between align specifiers and allocAdvanced.

riverbl avatar Jan 26 '22 18:01 riverbl

I think using null or 0 for alignment is effectively the same thing according to the way you've described null. ptr % null is undefined in the same mathematical sense that ptr % 0 is undefined. However there's a reason to use 0 to mean "no alignment" - null could potentially have a different meaning than "no alignment" - in some places we use it to mean default alignment, i.e. natural alignment. 0 is unambiguously "undefined alignment" and it could not be mistaken for "natural alignment".

andrewrk avatar Feb 02 '22 23:02 andrewrk

As part of solving this issue, a MultiArrayList with size 0 key type should use a zero-bit type for bytes and capacity as well. In other words, it should effectively become a wrapper around len: usize while preserving the expected API.

andrewrk avatar Jul 13 '23 02:07 andrewrk