Commit 5a0cf21775

Mason Remaley <MasonRemaley@users.noreply.github.com>
2025-08-25 18:03:08
Adds non allocating alternatives to ZON parse functions (#22916)
* Adds "flat" alternatives to zon.parse.from* that don't support pointers * Fixes documentation * Removes flat postfix from non allocating functions, adds alloc to others * Stops using alloc variant in tests where not needed
1 parent 37f4bee
Changed files (1)
lib
std
lib/std/zon/parse.zig
@@ -1,11 +1,12 @@
-//! The simplest way to parse ZON at runtime is to use `fromSlice`. If you need to parse ZON at
-//! compile time, you may use `@import`.
+//! The simplest way to parse ZON at runtime is to use `fromSlice`/`fromSliceAlloc`.
+//!
+//! Note that if you need to parse ZON at compile time, you may use `@import`.
 //!
 //! Parsing from individual Zoir nodes is also available:
-//! * `fromZoir`
-//! * `fromZoirNode`
+//! * `fromZoir`/`fromZoirAlloc`
+//! * `fromZoirNode`/`fromZoirNodeAlloc`
 //!
-//! For lower level control, it is possible to operate on `std.zig.Zoir` directly.
+//! For lower level control over parsing, see `std.zig.Zoir`.
 
 const std = @import("std");
 const builtin = @import("builtin");
@@ -254,7 +255,25 @@ pub const Diagnostics = struct {
 ///
 /// When the parser returns `error.ParseZon`, it will also store a human readable explanation in
 /// `diag` if non null. If diag is not null, it must be initialized to `.{}`.
+///
+/// Asserts at compile time that the result type doesn't contain pointers. As such, the result
+/// doesn't need to be freed.
+///
+/// An allocator is still required for temporary allocations made during parsing.
 pub fn fromSlice(
+    T: type,
+    gpa: Allocator,
+    source: [:0]const u8,
+    diag: ?*Diagnostics,
+    options: Options,
+) error{ OutOfMemory, ParseZon }!T {
+    comptime assert(!requiresAllocator(T));
+    return fromSliceAlloc(T, gpa, source, diag, options);
+}
+
+/// Like `fromSlice`, but the result may contain pointers. To automatically free the result, see
+/// `free`.
+pub fn fromSliceAlloc(
     /// The type to deserialize into. May not be or contain any of the following types:
     /// * Any comptime-only type, except in a comptime field
     /// * `type`
@@ -285,11 +304,35 @@ pub fn fromSlice(
     defer if (diag == null) zoir.deinit(gpa);
 
     if (diag) |s| s.* = .{};
-    return fromZoir(T, gpa, ast, zoir, diag, options);
+    return fromZoirAlloc(T, gpa, ast, zoir, diag, options);
 }
 
 /// Like `fromSlice`, but operates on `Zoir` instead of ZON source.
 pub fn fromZoir(
+    T: type,
+    ast: Ast,
+    zoir: Zoir,
+    diag: ?*Diagnostics,
+    options: Options,
+) error{ParseZon}!T {
+    comptime assert(!requiresAllocator(T));
+    var buf: [0]u8 = .{};
+    var failing_allocator = std.heap.FixedBufferAllocator.init(&buf);
+    return fromZoirAlloc(
+        T,
+        failing_allocator.allocator(),
+        ast,
+        zoir,
+        diag,
+        options,
+    ) catch |err| switch (err) {
+        error.OutOfMemory => unreachable, // Checked by comptime assertion above
+        else => |e| return e,
+    };
+}
+
+/// Like `fromSliceAlloc`, but operates on `Zoir` instead of ZON source.
+pub fn fromZoirAlloc(
     T: type,
     gpa: Allocator,
     ast: Ast,
@@ -297,11 +340,37 @@ pub fn fromZoir(
     diag: ?*Diagnostics,
     options: Options,
 ) error{ OutOfMemory, ParseZon }!T {
-    return fromZoirNode(T, gpa, ast, zoir, .root, diag, options);
+    return fromZoirNodeAlloc(T, gpa, ast, zoir, .root, diag, options);
 }
 
-/// Like `fromZoir`, but the parse starts on `node` instead of root.
+/// Like `fromZoir`, but the parse starts at `node` instead of root.
 pub fn fromZoirNode(
+    T: type,
+    ast: Ast,
+    zoir: Zoir,
+    node: Zoir.Node.Index,
+    diag: ?*Diagnostics,
+    options: Options,
+) error{ParseZon}!T {
+    comptime assert(!requiresAllocator(T));
+    var buf: [0]u8 = .{};
+    var failing_allocator = std.heap.FixedBufferAllocator.init(&buf);
+    return fromZoirNodeAlloc(
+        T,
+        failing_allocator.allocator(),
+        ast,
+        zoir,
+        node,
+        diag,
+        options,
+    ) catch |err| switch (err) {
+        error.OutOfMemory => unreachable, // Checked by comptime assertion above
+        else => |e| return e,
+    };
+}
+
+/// Like `fromZoirAlloc`, but the parse starts at `node` instead of root.
+pub fn fromZoirNodeAlloc(
     T: type,
     gpa: Allocator,
     ast: Ast,
@@ -1321,7 +1390,7 @@ test "std.zon failure/oom formatting" {
     });
     var diag: Diagnostics = .{};
     defer diag.deinit(gpa);
-    try std.testing.expectError(error.OutOfMemory, fromSlice(
+    try std.testing.expectError(error.OutOfMemory, fromSliceAlloc(
         []const u8,
         failing_allocator.allocator(),
         "\"foo\"",
@@ -1331,7 +1400,7 @@ test "std.zon failure/oom formatting" {
     try std.testing.expectFmt("", "{f}", .{diag});
 }
 
-test "std.zon fromSlice syntax error" {
+test "std.zon fromSliceAlloc syntax error" {
     try std.testing.expectError(
         error.ParseZon,
         fromSlice(u8, std.testing.allocator, ".{", null, .{}),
@@ -1351,9 +1420,9 @@ test "std.zon optional" {
 
     // Deep free
     {
-        const none = try fromSlice(?[]const u8, gpa, "null", null, .{});
+        const none = try fromSliceAlloc(?[]const u8, gpa, "null", null, .{});
         try std.testing.expect(none == null);
-        const some = try fromSlice(?[]const u8, gpa, "\"foo\"", null, .{});
+        const some = try fromSliceAlloc(?[]const u8, gpa, "\"foo\"", null, .{});
         defer free(gpa, some);
         try std.testing.expectEqualStrings("foo", some.?);
     }
@@ -1386,10 +1455,10 @@ test "std.zon unions" {
     {
         const Union = union(enum) { bar: []const u8, baz: bool };
 
-        const noalloc = try fromSlice(Union, gpa, ".{.baz = false}", null, .{});
+        const noalloc = try fromSliceAlloc(Union, gpa, ".{.baz = false}", null, .{});
         try std.testing.expectEqual(Union{ .baz = false }, noalloc);
 
-        const alloc = try fromSlice(Union, gpa, ".{.bar = \"qux\"}", null, .{});
+        const alloc = try fromSliceAlloc(Union, gpa, ".{.bar = \"qux\"}", null, .{});
         defer free(gpa, alloc);
         try std.testing.expectEqualDeep(Union{ .bar = "qux" }, alloc);
     }
@@ -1401,7 +1470,7 @@ test "std.zon unions" {
         defer diag.deinit(gpa);
         try std.testing.expectError(
             error.ParseZon,
-            fromSlice(Union, gpa, ".{.z=2.5}", &diag, .{}),
+            fromSliceAlloc(Union, gpa, ".{.z=2.5}", &diag, .{}),
         );
         try std.testing.expectFmt(
             \\1:4: error: unexpected field 'z'
@@ -1420,7 +1489,7 @@ test "std.zon unions" {
         defer diag.deinit(gpa);
         try std.testing.expectError(
             error.ParseZon,
-            fromSlice(Union, gpa, ".{.x=1}", &diag, .{}),
+            fromSliceAlloc(Union, gpa, ".{.x=1}", &diag, .{}),
         );
         try std.testing.expectFmt("1:6: error: expected type 'void'\n", "{f}", .{diag});
     }
@@ -1432,7 +1501,7 @@ test "std.zon unions" {
         defer diag.deinit(gpa);
         try std.testing.expectError(
             error.ParseZon,
-            fromSlice(Union, gpa, ".{.x = 1.5, .y = true}", &diag, .{}),
+            fromSliceAlloc(Union, gpa, ".{.x = 1.5, .y = true}", &diag, .{}),
         );
         try std.testing.expectFmt("1:2: error: expected union\n", "{f}", .{diag});
     }
@@ -1444,7 +1513,7 @@ test "std.zon unions" {
         defer diag.deinit(gpa);
         try std.testing.expectError(
             error.ParseZon,
-            fromSlice(Union, gpa, ".{}", &diag, .{}),
+            fromSliceAlloc(Union, gpa, ".{}", &diag, .{}),
         );
         try std.testing.expectFmt("1:2: error: expected union\n", "{f}", .{diag});
     }
@@ -1454,7 +1523,7 @@ test "std.zon unions" {
         const Union = union { x: void };
         var diag: Diagnostics = .{};
         defer diag.deinit(gpa);
-        try std.testing.expectError(error.ParseZon, fromSlice(Union, gpa, ".x", &diag, .{}));
+        try std.testing.expectError(error.ParseZon, fromSliceAlloc(Union, gpa, ".x", &diag, .{}));
         try std.testing.expectFmt("1:2: error: expected union\n", "{f}", .{diag});
     }
 
@@ -1463,7 +1532,7 @@ test "std.zon unions" {
         const Union = union(enum) { x: void };
         var diag: Diagnostics = .{};
         defer diag.deinit(gpa);
-        try std.testing.expectError(error.ParseZon, fromSlice(Union, gpa, ".y", &diag, .{}));
+        try std.testing.expectError(error.ParseZon, fromSliceAlloc(Union, gpa, ".y", &diag, .{}));
         try std.testing.expectFmt(
             \\1:2: error: unexpected field 'y'
             \\1:2: note: supported: 'x'
@@ -1479,7 +1548,7 @@ test "std.zon unions" {
         const Union = union(enum) { x: f32 };
         var diag: Diagnostics = .{};
         defer diag.deinit(gpa);
-        try std.testing.expectError(error.ParseZon, fromSlice(Union, gpa, ".x", &diag, .{}));
+        try std.testing.expectError(error.ParseZon, fromSliceAlloc(Union, gpa, ".x", &diag, .{}));
         try std.testing.expectFmt("1:2: error: expected union\n", "{f}", .{diag});
     }
 }
@@ -1511,7 +1580,7 @@ test "std.zon structs" {
     {
         const Foo = struct { bar: []const u8, baz: []const []const u8 };
 
-        const parsed = try fromSlice(
+        const parsed = try fromSliceAlloc(
             Foo,
             gpa,
             ".{.bar = \"qux\", .baz = .{\"a\", \"b\"}}",
@@ -1668,7 +1737,7 @@ test "std.zon structs" {
         {
             var diag: Diagnostics = .{};
             defer diag.deinit(gpa);
-            const parsed = fromSlice([]u8, gpa, "[]u8{1, 2, 3}", &diag, .{});
+            const parsed = fromSliceAlloc([]u8, gpa, "[]u8{1, 2, 3}", &diag, .{});
             try std.testing.expectError(error.ParseZon, parsed);
             try std.testing.expectFmt(
                 \\1:1: error: types are not available in ZON
@@ -1737,7 +1806,7 @@ test "std.zon tuples" {
     // Deep free
     {
         const Tuple = struct { []const u8, []const u8 };
-        const parsed = try fromSlice(Tuple, gpa, ".{\"hello\", \"world\"}", null, .{});
+        const parsed = try fromSliceAlloc(Tuple, gpa, ".{\"hello\", \"world\"}", null, .{});
         defer free(gpa, parsed);
         try std.testing.expectEqualDeep(Tuple{ "hello", "world" }, parsed);
     }
@@ -1847,27 +1916,27 @@ test "std.zon arrays and slices" {
 
         // Slice literals
         {
-            const zero = try fromSlice([]const u8, gpa, ".{}", null, .{});
+            const zero = try fromSliceAlloc([]const u8, gpa, ".{}", null, .{});
             defer free(gpa, zero);
             try std.testing.expectEqualSlices(u8, @as([]const u8, &.{}), zero);
 
-            const one = try fromSlice([]u8, gpa, ".{'a'}", null, .{});
+            const one = try fromSliceAlloc([]u8, gpa, ".{'a'}", null, .{});
             defer free(gpa, one);
             try std.testing.expectEqualSlices(u8, &.{'a'}, one);
 
-            const two = try fromSlice([]const u8, gpa, ".{'a', 'b'}", null, .{});
+            const two = try fromSliceAlloc([]const u8, gpa, ".{'a', 'b'}", null, .{});
             defer free(gpa, two);
             try std.testing.expectEqualSlices(u8, &.{ 'a', 'b' }, two);
 
-            const two_comma = try fromSlice([]const u8, gpa, ".{'a', 'b',}", null, .{});
+            const two_comma = try fromSliceAlloc([]const u8, gpa, ".{'a', 'b',}", null, .{});
             defer free(gpa, two_comma);
             try std.testing.expectEqualSlices(u8, &.{ 'a', 'b' }, two_comma);
 
-            const three = try fromSlice([]u8, gpa, ".{'a', 'b', 'c'}", null, .{});
+            const three = try fromSliceAlloc([]u8, gpa, ".{'a', 'b', 'c'}", null, .{});
             defer free(gpa, three);
             try std.testing.expectEqualSlices(u8, &.{ 'a', 'b', 'c' }, three);
 
-            const sentinel = try fromSlice([:'z']const u8, gpa, ".{'a', 'b', 'c'}", null, .{});
+            const sentinel = try fromSliceAlloc([:'z']const u8, gpa, ".{'a', 'b', 'c'}", null, .{});
             defer free(gpa, sentinel);
             const expected_sentinel: [:'z']const u8 = &.{ 'a', 'b', 'c' };
             try std.testing.expectEqualSlices(u8, expected_sentinel, sentinel);
@@ -1878,7 +1947,7 @@ test "std.zon arrays and slices" {
     {
         // Arrays
         {
-            const parsed = try fromSlice([1][]const u8, gpa, ".{\"abc\"}", null, .{});
+            const parsed = try fromSliceAlloc([1][]const u8, gpa, ".{\"abc\"}", null, .{});
             defer free(gpa, parsed);
             const expected: [1][]const u8 = .{"abc"};
             try std.testing.expectEqualDeep(expected, parsed);
@@ -1886,7 +1955,7 @@ test "std.zon arrays and slices" {
 
         // Slice literals
         {
-            const parsed = try fromSlice([]const []const u8, gpa, ".{\"abc\"}", null, .{});
+            const parsed = try fromSliceAlloc([]const []const u8, gpa, ".{\"abc\"}", null, .{});
             defer free(gpa, parsed);
             const expected: []const []const u8 = &.{"abc"};
             try std.testing.expectEqualDeep(expected, parsed);
@@ -1905,7 +1974,7 @@ test "std.zon arrays and slices" {
 
         // Slice literals
         {
-            const sentinel = try fromSlice([:2]align(4) u8, gpa, ".{1}", null, .{});
+            const sentinel = try fromSliceAlloc([:2]align(4) u8, gpa, ".{1}", null, .{});
             defer free(gpa, sentinel);
             try std.testing.expectEqual(@as(usize, 1), sentinel.len);
             try std.testing.expectEqual(@as(u8, 1), sentinel[0]);
@@ -1992,7 +2061,7 @@ test "std.zon arrays and slices" {
             defer diag.deinit(gpa);
             try std.testing.expectError(
                 error.ParseZon,
-                fromSlice([]bool, gpa, ".{'a', 'b', 'c'}", &diag, .{}),
+                fromSliceAlloc([]bool, gpa, ".{'a', 'b', 'c'}", &diag, .{}),
             );
             try std.testing.expectFmt("1:3: error: expected type 'bool'\n", "{f}", .{diag});
         }
@@ -2017,7 +2086,7 @@ test "std.zon arrays and slices" {
             defer diag.deinit(gpa);
             try std.testing.expectError(
                 error.ParseZon,
-                fromSlice([]u8, gpa, "'a'", &diag, .{}),
+                fromSliceAlloc([]u8, gpa, "'a'", &diag, .{}),
             );
             try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
         }
@@ -2029,7 +2098,7 @@ test "std.zon arrays and slices" {
         defer diag.deinit(gpa);
         try std.testing.expectError(
             error.ParseZon,
-            fromSlice([]u8, gpa, "  &.{'a', 'b', 'c'}", &diag, .{}),
+            fromSliceAlloc([]u8, gpa, "  &.{'a', 'b', 'c'}", &diag, .{}),
         );
         try std.testing.expectFmt(
             "1:3: error: pointers are not available in ZON\n",
@@ -2044,21 +2113,21 @@ test "std.zon string literal" {
 
     // Basic string literal
     {
-        const parsed = try fromSlice([]const u8, gpa, "\"abc\"", null, .{});
+        const parsed = try fromSliceAlloc([]const u8, gpa, "\"abc\"", null, .{});
         defer free(gpa, parsed);
         try std.testing.expectEqualStrings(@as([]const u8, "abc"), parsed);
     }
 
     // String literal with escape characters
     {
-        const parsed = try fromSlice([]const u8, gpa, "\"ab\\nc\"", null, .{});
+        const parsed = try fromSliceAlloc([]const u8, gpa, "\"ab\\nc\"", null, .{});
         defer free(gpa, parsed);
         try std.testing.expectEqualStrings(@as([]const u8, "ab\nc"), parsed);
     }
 
     // String literal with embedded null
     {
-        const parsed = try fromSlice([]const u8, gpa, "\"ab\\x00c\"", null, .{});
+        const parsed = try fromSliceAlloc([]const u8, gpa, "\"ab\\x00c\"", null, .{});
         defer free(gpa, parsed);
         try std.testing.expectEqualStrings(@as([]const u8, "ab\x00c"), parsed);
     }
@@ -2070,7 +2139,7 @@ test "std.zon string literal" {
             defer diag.deinit(gpa);
             try std.testing.expectError(
                 error.ParseZon,
-                fromSlice([]u8, gpa, "\"abcd\"", &diag, .{}),
+                fromSliceAlloc([]u8, gpa, "\"abcd\"", &diag, .{}),
             );
             try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
         }
@@ -2080,7 +2149,7 @@ test "std.zon string literal" {
             defer diag.deinit(gpa);
             try std.testing.expectError(
                 error.ParseZon,
-                fromSlice([]u8, gpa, "\\\\abcd", &diag, .{}),
+                fromSliceAlloc([]u8, gpa, "\\\\abcd", &diag, .{}),
             );
             try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
         }
@@ -2116,7 +2185,7 @@ test "std.zon string literal" {
     // Zero terminated slices
     {
         {
-            const parsed: [:0]const u8 = try fromSlice(
+            const parsed: [:0]const u8 = try fromSliceAlloc(
                 [:0]const u8,
                 gpa,
                 "\"abc\"",
@@ -2129,7 +2198,7 @@ test "std.zon string literal" {
         }
 
         {
-            const parsed: [:0]const u8 = try fromSlice(
+            const parsed: [:0]const u8 = try fromSliceAlloc(
                 [:0]const u8,
                 gpa,
                 "\\\\abc",
@@ -2149,7 +2218,7 @@ test "std.zon string literal" {
             defer diag.deinit(gpa);
             try std.testing.expectError(
                 error.ParseZon,
-                fromSlice([:1]const u8, gpa, "\"foo\"", &diag, .{}),
+                fromSliceAlloc([:1]const u8, gpa, "\"foo\"", &diag, .{}),
             );
             try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
         }
@@ -2159,7 +2228,7 @@ test "std.zon string literal" {
             defer diag.deinit(gpa);
             try std.testing.expectError(
                 error.ParseZon,
-                fromSlice([:1]const u8, gpa, "\\\\foo", &diag, .{}),
+                fromSliceAlloc([:1]const u8, gpa, "\\\\foo", &diag, .{}),
             );
             try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
         }
@@ -2171,7 +2240,7 @@ test "std.zon string literal" {
         defer diag.deinit(gpa);
         try std.testing.expectError(
             error.ParseZon,
-            fromSlice([]const u8, gpa, "true", &diag, .{}),
+            fromSliceAlloc([]const u8, gpa, "true", &diag, .{}),
         );
         try std.testing.expectFmt("1:1: error: expected string\n", "{f}", .{diag});
     }
@@ -2182,7 +2251,7 @@ test "std.zon string literal" {
         defer diag.deinit(gpa);
         try std.testing.expectError(
             error.ParseZon,
-            fromSlice([]const u8, gpa, ".{false}", &diag, .{}),
+            fromSliceAlloc([]const u8, gpa, ".{false}", &diag, .{}),
         );
         try std.testing.expectFmt("1:3: error: expected type 'u8'\n", "{f}", .{diag});
     }
@@ -2193,7 +2262,7 @@ test "std.zon string literal" {
         defer diag.deinit(gpa);
         try std.testing.expectError(
             error.ParseZon,
-            fromSlice([]const i8, gpa, "\"\\a\"", &diag, .{}),
+            fromSliceAlloc([]const i8, gpa, "\"\\a\"", &diag, .{}),
         );
         try std.testing.expectFmt("1:3: error: invalid escape character: 'a'\n", "{f}", .{diag});
     }
@@ -2205,7 +2274,7 @@ test "std.zon string literal" {
             defer diag.deinit(gpa);
             try std.testing.expectError(
                 error.ParseZon,
-                fromSlice([]const i8, gpa, "\"a\"", &diag, .{}),
+                fromSliceAlloc([]const i8, gpa, "\"a\"", &diag, .{}),
             );
             try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
         }
@@ -2215,7 +2284,7 @@ test "std.zon string literal" {
             defer diag.deinit(gpa);
             try std.testing.expectError(
                 error.ParseZon,
-                fromSlice([]const i8, gpa, "\\\\a", &diag, .{}),
+                fromSliceAlloc([]const i8, gpa, "\\\\a", &diag, .{}),
             );
             try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
         }
@@ -2228,7 +2297,7 @@ test "std.zon string literal" {
             defer diag.deinit(gpa);
             try std.testing.expectError(
                 error.ParseZon,
-                fromSlice([]align(2) const u8, gpa, "\"abc\"", &diag, .{}),
+                fromSliceAlloc([]align(2) const u8, gpa, "\"abc\"", &diag, .{}),
             );
             try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
         }
@@ -2238,7 +2307,7 @@ test "std.zon string literal" {
             defer diag.deinit(gpa);
             try std.testing.expectError(
                 error.ParseZon,
-                fromSlice([]align(2) const u8, gpa, "\\\\abc", &diag, .{}),
+                fromSliceAlloc([]align(2) const u8, gpa, "\\\\abc", &diag, .{}),
             );
             try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
         }
@@ -2253,7 +2322,7 @@ test "std.zon string literal" {
                 message2: String,
                 message3: String,
             };
-            const parsed = try fromSlice(S, gpa,
+            const parsed = try fromSliceAlloc(S, gpa,
                 \\.{
                 \\    .message =
                 \\        \\hello, world!
@@ -2909,7 +2978,7 @@ test "std.zon free on error" {
             y: []const u8,
             z: bool,
         };
-        try std.testing.expectError(error.ParseZon, fromSlice(Struct, std.testing.allocator,
+        try std.testing.expectError(error.ParseZon, fromSliceAlloc(Struct, std.testing.allocator,
             \\.{
             \\    .x = "hello",
             \\    .y = "world",
@@ -2925,7 +2994,7 @@ test "std.zon free on error" {
             []const u8,
             bool,
         };
-        try std.testing.expectError(error.ParseZon, fromSlice(Struct, std.testing.allocator,
+        try std.testing.expectError(error.ParseZon, fromSliceAlloc(Struct, std.testing.allocator,
             \\.{
             \\    "hello",
             \\    "world",
@@ -2940,7 +3009,7 @@ test "std.zon free on error" {
             x: []const u8,
             y: bool,
         };
-        try std.testing.expectError(error.ParseZon, fromSlice(Struct, std.testing.allocator,
+        try std.testing.expectError(error.ParseZon, fromSliceAlloc(Struct, std.testing.allocator,
             \\.{
             \\    .x = "hello",
             \\}
@@ -2949,7 +3018,7 @@ test "std.zon free on error" {
 
     // Test freeing partially allocated arrays
     {
-        try std.testing.expectError(error.ParseZon, fromSlice(
+        try std.testing.expectError(error.ParseZon, fromSliceAlloc(
             [3][]const u8,
             std.testing.allocator,
             \\.{
@@ -2965,7 +3034,7 @@ test "std.zon free on error" {
 
     // Test freeing partially allocated slices
     {
-        try std.testing.expectError(error.ParseZon, fromSlice(
+        try std.testing.expectError(error.ParseZon, fromSliceAlloc(
             [][]const u8,
             std.testing.allocator,
             \\.{
@@ -2989,7 +3058,7 @@ test "std.zon free on error" {
     // We can also parse types that can't be freed if it's impossible for an error to occur after
     // the allocation, as is the case here.
     {
-        const result = try fromSlice(
+        const result = try fromSliceAlloc(
             union { x: []const u8 },
             std.testing.allocator,
             ".{ .x = \"foo\" }",
@@ -3008,7 +3077,7 @@ test "std.zon free on error" {
             union { x: []const u8 },
             bool,
         };
-        const result = try fromSlice(
+        const result = try fromSliceAlloc(
             S,
             std.testing.allocator,
             ".{ .{ .x = \"foo\" }, true }",
@@ -3026,7 +3095,7 @@ test "std.zon free on error" {
             a: union { x: []const u8 },
             b: bool,
         };
-        const result = try fromSlice(
+        const result = try fromSliceAlloc(
             S,
             std.testing.allocator,
             ".{ .a = .{ .x = \"foo\" }, .b = true }",
@@ -3043,7 +3112,7 @@ test "std.zon free on error" {
     // Again but for arrays.
     {
         const S = [2]union { x: []const u8 };
-        const result = try fromSlice(
+        const result = try fromSliceAlloc(
             S,
             std.testing.allocator,
             ".{ .{ .x = \"foo\" }, .{ .x = \"bar\" } }",
@@ -3061,7 +3130,7 @@ test "std.zon free on error" {
     // Again but for slices.
     {
         const S = []union { x: []const u8 };
-        const result = try fromSlice(
+        const result = try fromSliceAlloc(
             S,
             std.testing.allocator,
             ".{ .{ .x = \"foo\" }, .{ .x = \"bar\" } }",
@@ -3114,9 +3183,9 @@ test "std.zon vector" {
     {
         try std.testing.expectEqual(
             @Vector(0, *const u8){},
-            try fromSlice(@Vector(0, *const u8), gpa, ".{}", null, .{}),
+            try fromSliceAlloc(@Vector(0, *const u8), gpa, ".{}", null, .{}),
         );
-        const pointers = try fromSlice(@Vector(3, *const u8), gpa, ".{2, 4, 6}", null, .{});
+        const pointers = try fromSliceAlloc(@Vector(3, *const u8), gpa, ".{2, 4, 6}", null, .{});
         defer free(gpa, pointers);
         try std.testing.expectEqualDeep(@Vector(3, *const u8){ &2, &4, &6 }, pointers);
     }
@@ -3124,9 +3193,9 @@ test "std.zon vector" {
     {
         try std.testing.expectEqual(
             @Vector(0, ?*const u8){},
-            try fromSlice(@Vector(0, ?*const u8), gpa, ".{}", null, .{}),
+            try fromSliceAlloc(@Vector(0, ?*const u8), gpa, ".{}", null, .{}),
         );
-        const pointers = try fromSlice(@Vector(3, ?*const u8), gpa, ".{2, null, 6}", null, .{});
+        const pointers = try fromSliceAlloc(@Vector(3, ?*const u8), gpa, ".{2, null, 6}", null, .{});
         defer free(gpa, pointers);
         try std.testing.expectEqualDeep(@Vector(3, ?*const u8){ &2, null, &6 }, pointers);
     }
@@ -3193,7 +3262,7 @@ test "std.zon vector" {
         defer diag.deinit(gpa);
         try std.testing.expectError(
             error.ParseZon,
-            fromSlice(@Vector(3, *u8), gpa, ".{1, true, 3}", &diag, .{}),
+            fromSliceAlloc(@Vector(3, *u8), gpa, ".{1, true, 3}", &diag, .{}),
         );
         try std.testing.expectFmt("1:6: error: expected type 'u8'\n", "{f}", .{diag});
     }
@@ -3204,77 +3273,77 @@ test "std.zon add pointers" {
 
     // Primitive with varying levels of pointers
     {
-        const result = try fromSlice(*u32, gpa, "10", null, .{});
+        const result = try fromSliceAlloc(*u32, gpa, "10", null, .{});
         defer free(gpa, result);
         try std.testing.expectEqual(@as(u32, 10), result.*);
     }
 
     {
-        const result = try fromSlice(**u32, gpa, "10", null, .{});
+        const result = try fromSliceAlloc(**u32, gpa, "10", null, .{});
         defer free(gpa, result);
         try std.testing.expectEqual(@as(u32, 10), result.*.*);
     }
 
     {
-        const result = try fromSlice(***u32, gpa, "10", null, .{});
+        const result = try fromSliceAlloc(***u32, gpa, "10", null, .{});
         defer free(gpa, result);
         try std.testing.expectEqual(@as(u32, 10), result.*.*.*);
     }
 
     // Primitive optional with varying levels of pointers
     {
-        const some = try fromSlice(?*u32, gpa, "10", null, .{});
+        const some = try fromSliceAlloc(?*u32, gpa, "10", null, .{});
         defer free(gpa, some);
         try std.testing.expectEqual(@as(u32, 10), some.?.*);
 
-        const none = try fromSlice(?*u32, gpa, "null", null, .{});
+        const none = try fromSliceAlloc(?*u32, gpa, "null", null, .{});
         defer free(gpa, none);
         try std.testing.expectEqual(null, none);
     }
 
     {
-        const some = try fromSlice(*?u32, gpa, "10", null, .{});
+        const some = try fromSliceAlloc(*?u32, gpa, "10", null, .{});
         defer free(gpa, some);
         try std.testing.expectEqual(@as(u32, 10), some.*.?);
 
-        const none = try fromSlice(*?u32, gpa, "null", null, .{});
+        const none = try fromSliceAlloc(*?u32, gpa, "null", null, .{});
         defer free(gpa, none);
         try std.testing.expectEqual(null, none.*);
     }
 
     {
-        const some = try fromSlice(?**u32, gpa, "10", null, .{});
+        const some = try fromSliceAlloc(?**u32, gpa, "10", null, .{});
         defer free(gpa, some);
         try std.testing.expectEqual(@as(u32, 10), some.?.*.*);
 
-        const none = try fromSlice(?**u32, gpa, "null", null, .{});
+        const none = try fromSliceAlloc(?**u32, gpa, "null", null, .{});
         defer free(gpa, none);
         try std.testing.expectEqual(null, none);
     }
 
     {
-        const some = try fromSlice(*?*u32, gpa, "10", null, .{});
+        const some = try fromSliceAlloc(*?*u32, gpa, "10", null, .{});
         defer free(gpa, some);
         try std.testing.expectEqual(@as(u32, 10), some.*.?.*);
 
-        const none = try fromSlice(*?*u32, gpa, "null", null, .{});
+        const none = try fromSliceAlloc(*?*u32, gpa, "null", null, .{});
         defer free(gpa, none);
         try std.testing.expectEqual(null, none.*);
     }
 
     {
-        const some = try fromSlice(**?u32, gpa, "10", null, .{});
+        const some = try fromSliceAlloc(**?u32, gpa, "10", null, .{});
         defer free(gpa, some);
         try std.testing.expectEqual(@as(u32, 10), some.*.*.?);
 
-        const none = try fromSlice(**?u32, gpa, "null", null, .{});
+        const none = try fromSliceAlloc(**?u32, gpa, "null", null, .{});
         defer free(gpa, none);
         try std.testing.expectEqual(null, none.*.*);
     }
 
     // Pointer to an array
     {
-        const result = try fromSlice(*[3]u8, gpa, ".{ 1, 2, 3 }", null, .{});
+        const result = try fromSliceAlloc(*[3]u8, gpa, ".{ 1, 2, 3 }", null, .{});
         defer free(gpa, result);
         try std.testing.expectEqual([3]u8{ 1, 2, 3 }, result.*);
     }
@@ -3297,7 +3366,7 @@ test "std.zon add pointers" {
             .f2 = &null,
         };
 
-        const found = try fromSlice(?*Outer, gpa,
+        const found = try fromSliceAlloc(?*Outer, gpa,
             \\.{
             \\    .f1 = .{
             \\        .f1 = null,
@@ -3317,7 +3386,7 @@ test "std.zon add pointers" {
         defer diag.deinit(gpa);
         try std.testing.expectError(
             error.ParseZon,
-            fromSlice(*const ?*const u8, gpa, "true", &diag, .{}),
+            fromSliceAlloc(*const ?*const u8, gpa, "true", &diag, .{}),
         );
         try std.testing.expectFmt("1:1: error: expected type '?u8'\n", "{f}", .{diag});
     }
@@ -3327,7 +3396,7 @@ test "std.zon add pointers" {
         defer diag.deinit(gpa);
         try std.testing.expectError(
             error.ParseZon,
-            fromSlice(*const ?*const f32, gpa, "true", &diag, .{}),
+            fromSliceAlloc(*const ?*const f32, gpa, "true", &diag, .{}),
         );
         try std.testing.expectFmt("1:1: error: expected type '?f32'\n", "{f}", .{diag});
     }
@@ -3337,7 +3406,7 @@ test "std.zon add pointers" {
         defer diag.deinit(gpa);
         try std.testing.expectError(
             error.ParseZon,
-            fromSlice(*const ?*const @Vector(3, u8), gpa, "true", &diag, .{}),
+            fromSliceAlloc(*const ?*const @Vector(3, u8), gpa, "true", &diag, .{}),
         );
         try std.testing.expectFmt("1:1: error: expected type '?@Vector(3, u8)'\n", "{f}", .{diag});
     }
@@ -3347,7 +3416,7 @@ test "std.zon add pointers" {
         defer diag.deinit(gpa);
         try std.testing.expectError(
             error.ParseZon,
-            fromSlice(*const ?*const bool, gpa, "10", &diag, .{}),
+            fromSliceAlloc(*const ?*const bool, gpa, "10", &diag, .{}),
         );
         try std.testing.expectFmt("1:1: error: expected type '?bool'\n", "{f}", .{diag});
     }
@@ -3357,7 +3426,7 @@ test "std.zon add pointers" {
         defer diag.deinit(gpa);
         try std.testing.expectError(
             error.ParseZon,
-            fromSlice(*const ?*const struct { a: i32 }, gpa, "true", &diag, .{}),
+            fromSliceAlloc(*const ?*const struct { a: i32 }, gpa, "true", &diag, .{}),
         );
         try std.testing.expectFmt("1:1: error: expected optional struct\n", "{f}", .{diag});
     }
@@ -3367,7 +3436,7 @@ test "std.zon add pointers" {
         defer diag.deinit(gpa);
         try std.testing.expectError(
             error.ParseZon,
-            fromSlice(*const ?*const struct { i32 }, gpa, "true", &diag, .{}),
+            fromSliceAlloc(*const ?*const struct { i32 }, gpa, "true", &diag, .{}),
         );
         try std.testing.expectFmt("1:1: error: expected optional tuple\n", "{f}", .{diag});
     }
@@ -3377,7 +3446,7 @@ test "std.zon add pointers" {
         defer diag.deinit(gpa);
         try std.testing.expectError(
             error.ParseZon,
-            fromSlice(*const ?*const union { x: void }, gpa, "true", &diag, .{}),
+            fromSliceAlloc(*const ?*const union { x: void }, gpa, "true", &diag, .{}),
         );
         try std.testing.expectFmt("1:1: error: expected optional union\n", "{f}", .{diag});
     }
@@ -3387,7 +3456,7 @@ test "std.zon add pointers" {
         defer diag.deinit(gpa);
         try std.testing.expectError(
             error.ParseZon,
-            fromSlice(*const ?*const [3]u8, gpa, "true", &diag, .{}),
+            fromSliceAlloc(*const ?*const [3]u8, gpa, "true", &diag, .{}),
         );
         try std.testing.expectFmt("1:1: error: expected optional array\n", "{f}", .{diag});
     }
@@ -3397,7 +3466,7 @@ test "std.zon add pointers" {
         defer diag.deinit(gpa);
         try std.testing.expectError(
             error.ParseZon,
-            fromSlice(?[3]u8, gpa, "true", &diag, .{}),
+            fromSliceAlloc(?[3]u8, gpa, "true", &diag, .{}),
         );
         try std.testing.expectFmt("1:1: error: expected optional array\n", "{f}", .{diag});
     }
@@ -3407,7 +3476,7 @@ test "std.zon add pointers" {
         defer diag.deinit(gpa);
         try std.testing.expectError(
             error.ParseZon,
-            fromSlice(*const ?*const []u8, gpa, "true", &diag, .{}),
+            fromSliceAlloc(*const ?*const []u8, gpa, "true", &diag, .{}),
         );
         try std.testing.expectFmt("1:1: error: expected optional array\n", "{f}", .{diag});
     }
@@ -3417,7 +3486,7 @@ test "std.zon add pointers" {
         defer diag.deinit(gpa);
         try std.testing.expectError(
             error.ParseZon,
-            fromSlice(?[]u8, gpa, "true", &diag, .{}),
+            fromSliceAlloc(?[]u8, gpa, "true", &diag, .{}),
         );
         try std.testing.expectFmt("1:1: error: expected optional array\n", "{f}", .{diag});
     }
@@ -3427,7 +3496,7 @@ test "std.zon add pointers" {
         defer diag.deinit(gpa);
         try std.testing.expectError(
             error.ParseZon,
-            fromSlice(*const ?*const []const u8, gpa, "true", &diag, .{}),
+            fromSliceAlloc(*const ?*const []const u8, gpa, "true", &diag, .{}),
         );
         try std.testing.expectFmt("1:1: error: expected optional string\n", "{f}", .{diag});
     }
@@ -3437,7 +3506,7 @@ test "std.zon add pointers" {
         defer diag.deinit(gpa);
         try std.testing.expectError(
             error.ParseZon,
-            fromSlice(*const ?*const enum { foo }, gpa, "true", &diag, .{}),
+            fromSliceAlloc(*const ?*const enum { foo }, gpa, "true", &diag, .{}),
         );
         try std.testing.expectFmt("1:1: error: expected optional enum literal\n", "{f}", .{diag});
     }
@@ -3466,3 +3535,30 @@ test "std.zon stop on node" {
         try std.testing.expectEqual(Zoir.Node{ .float_literal = 1.23 }, result.get(diag.zoir));
     }
 }
+
+test "std.zon no alloc" {
+    const gpa = std.testing.allocator;
+
+    try std.testing.expectEqual(
+        [3]u8{ 1, 2, 3 },
+        try fromSlice([3]u8, gpa, ".{ 1, 2, 3 }", null, .{}),
+    );
+
+    const Nested = struct { u8, u8, struct { u8, u8 } };
+
+    var ast = try std.zig.Ast.parse(gpa, ".{ 1, 2, .{ 3, 4 } }", .zon);
+    defer ast.deinit(gpa);
+
+    var zoir = try ZonGen.generate(gpa, ast, .{ .parse_str_lits = false });
+    defer zoir.deinit(gpa);
+
+    try std.testing.expectEqual(
+        Nested{ 1, 2, .{ 3, 4 } },
+        try fromZoir(Nested, ast, zoir, null, .{}),
+    );
+
+    try std.testing.expectEqual(
+        Nested{ 1, 2, .{ 3, 4 } },
+        try fromZoirNode(Nested, ast, zoir, .root, null, .{}),
+    );
+}