| author | |
| committer | |
| log | 581d292381157464ae6f2c88c8a628314f005742 |
| tree | 1d67f07416fb6d45e54267e459ebda5c7581e1d0 |
| parent | bb62d5105ca02a8b1c959ccf79b9f2861505a150 |
| signature |
* allow file level `union {}` to parse as tuple field
this was found while fuzzing zls.
* before this patch the input `union {}` crashed the parser. after
this, it parses correctly just like `struct {}`.
* adds behavior tests for both inputs `struct {}` and `union {}`,
checking that each becomes a file level tuple field.5 files changed, 30 insertions(+), 1 deletions(-)
lib/std/zig/Ast.zig+1-1| ... | ... | @@ -618,7 +618,7 @@ pub fn firstToken(tree: Ast, node: Node.Index) TokenIndex { |
| 618 | 618 | .tagged_union_enum_tag_trailing, |
| 619 | 619 | => { |
| 620 | 620 | const main_token = main_tokens[n]; |
| 621 | switch (token_tags[main_token - 1]) { | |
| 621 | switch (token_tags[main_token -| 1]) { | |
| 622 | 622 | .keyword_packed, .keyword_extern => end_offset += 1, |
| 623 | 623 | else => {}, |
| 624 | 624 | } |
test/behavior.zig+1| ... | ... | @@ -151,6 +151,7 @@ test { |
| 151 | 151 | _ = @import("behavior/const_slice_child.zig"); |
| 152 | 152 | _ = @import("behavior/decltest.zig"); |
| 153 | 153 | _ = @import("behavior/defer.zig"); |
| 154 | _ = @import("behavior/empty_tuple_fields.zig"); | |
| 154 | 155 | _ = @import("behavior/empty_union.zig"); |
| 155 | 156 | _ = @import("behavior/enum.zig"); |
| 156 | 157 | _ = @import("behavior/error.zig"); |
test/behavior/empty_file_level_struct.zig created+1| ... | ... | @@ -0,0 +1 @@ |
| 1 | struct {} |
test/behavior/empty_file_level_union.zig created+1| ... | ... | @@ -0,0 +1 @@ |
| 1 | union {} |
test/behavior/empty_tuple_fields.zig created+26| ... | ... | @@ -0,0 +1,26 @@ |
| 1 | const std = @import("std"); | |
| 2 | const builtin = @import("builtin"); | |
| 3 | ||
| 4 | test "empty file level struct" { | |
| 5 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 6 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | |
| 7 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 8 | ||
| 9 | const T = @import("empty_file_level_struct.zig"); | |
| 10 | const info = @typeInfo(T); | |
| 11 | try std.testing.expectEqual(@as(usize, 1), info.Struct.fields.len); | |
| 12 | try std.testing.expectEqualStrings("0", info.Struct.fields[0].name); | |
| 13 | try std.testing.expect(@typeInfo(info.Struct.fields[0].type) == .Struct); | |
| 14 | } | |
| 15 | ||
| 16 | test "empty file level union" { | |
| 17 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 18 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | |
| 19 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 20 | ||
| 21 | const T = @import("empty_file_level_union.zig"); | |
| 22 | const info = @typeInfo(T); | |
| 23 | try std.testing.expectEqual(@as(usize, 1), info.Struct.fields.len); | |
| 24 | try std.testing.expectEqualStrings("0", info.Struct.fields[0].name); | |
| 25 | try std.testing.expect(@typeInfo(info.Struct.fields[0].type) == .Union); | |
| 26 | } |