From 92915a42b55f2916f36ed6b1a2d51363331f47f8 Mon Sep 17 00:00:00 2001 From: Kendall Condon Date: Sun, 22 Mar 2026 17:39:43 -0400 Subject: [PATCH] zig fmt: do not reorder pointer casts with comments This was especially bad as it could crash or duplicate them due to them being moved around "zig fmt: on/off". As a bonus this fixes a crash from reordering at the start of the file. --- lib/std/zig/Ast/Render.zig | 37 +++++++++++++++++++++++++------------ lib/std/zig/parser_test.zig | 21 +++++++++++++++++++++ 2 files changed, 46 insertions(+), 12 deletions(-) diff --git a/lib/std/zig/Ast/Render.zig b/lib/std/zig/Ast/Render.zig index 41cd1e2260e82a8b736ba3f173bee2eb1ac1f1f7..3a420cd3b204a0329040da5ecfee641562324890 100644 --- a/lib/std/zig/Ast/Render.zig +++ b/lib/std/zig/Ast/Render.zig @@ -800,34 +800,47 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void { canonicalize: { if (params.len != 1) break :canonicalize; - const CastKind = enum { + const CastKind = enum(u8) { ptrCast, alignCast, addrSpaceCast, constCast, volatileCast, }; - const kind = meta.stringToEnum(CastKind, tree.tokenSlice(builtin_token)[1..]) orelse break :canonicalize; + const kind = meta.stringToEnum( + CastKind, + tree.tokenSlice(builtin_token)[1..], + ) orelse break :canonicalize; var cast_map = std.EnumMap(CastKind, Ast.TokenIndex).init(.{}); cast_map.put(kind, builtin_token); var casts_before: usize = 0; - if (builtin_token >= 2) { - var prev_builtin_token = builtin_token - 2; - while (tree.tokenTag(prev_builtin_token) == .builtin) : (prev_builtin_token -= 2) { - const prev_kind = meta.stringToEnum(CastKind, tree.tokenSlice(prev_builtin_token)[1..]) orelse break; - if (cast_map.contains(prev_kind)) break :canonicalize; - cast_map.put(prev_kind, prev_builtin_token); - casts_before += 1; - } + var prev_builtin_token = builtin_token; + while (prev_builtin_token >= 2) { + prev_builtin_token -= 2; + if (tree.tokenTag(prev_builtin_token) != .builtin) break; + const builtin_name = tree.tokenSlice(prev_builtin_token)[1..]; + const prev_kind = meta.stringToEnum(CastKind, builtin_name) orelse break; + if (cast_map.contains(prev_kind)) break :canonicalize; + // This must be checked after so that cast builtins as arguments to other + // builtins containing comments are reordered. + if (hasComment(tree, prev_builtin_token, prev_builtin_token + 2)) + break :canonicalize; + cast_map.put(prev_kind, prev_builtin_token); + casts_before += 1; } var next_builtin_token = builtin_token + 2; - while (tree.tokenTag(next_builtin_token) == .builtin) : (next_builtin_token += 2) { - const next_kind = meta.stringToEnum(CastKind, tree.tokenSlice(next_builtin_token)[1..]) orelse break; + while (true) { + if (hasComment(tree, next_builtin_token - 2, next_builtin_token)) + break :canonicalize; + if (tree.tokenTag(next_builtin_token) != .builtin) break; + const builtin_name = tree.tokenSlice(next_builtin_token)[1..]; + const next_kind = meta.stringToEnum(CastKind, builtin_name) orelse break; if (cast_map.contains(next_kind)) break :canonicalize; cast_map.put(next_kind, next_builtin_token); + next_builtin_token += 2; } var it = cast_map.iterator(); diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index dd8b199dc29a7a9f1657f47602b3e65e2f4d3ec3..f44e9ae544b663ac7021c4bd115036cb065d693a 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -6133,6 +6133,16 @@ test "zig fmt: do not canonicalize invalid cast builtins" { ); } +test "zig fmt: canonicalize cast builtins at file start" { + try testTransform( + \\@alignCast(@ptrCast(a)), + \\ + , + \\@ptrCast(@alignCast(a)), + \\ + ); +} + test "zig fmt: extern addrspace in struct" { try testCanonical( \\const namespace = struct { @@ -6909,6 +6919,17 @@ test "zig fmt: render extra colons with comments" { ); } +test "zig fmt: cast builtins are not reordered with comments" { + try testCanonical( + \\const a = @volatileCast(@constCast( // ... + \\ @alignCast(@ptrCast(a)))); + \\ + \\const b = @alignCast(@ptrCast( // zig fmt: off + \\ c)); + \\ + ); +} + test "recovery: top level" { try testError( \\test "" {inline} -- 2.54.0