From 3c2a43fdcc2d9aeafafe7ef37c7b805e18fac351 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 12 Feb 2023 05:59:28 -0700 Subject: [PATCH] Revert "std: check types of pointers passed to allocator functions" This reverts commit abc9530a88d24350481d9264edcde300f293929a. This patch implies that the idiomatic Zig way of handling anytype parameter is to write a bunch of boilerplate instead of directly accessing type information and relying on the compiler to be useful. I don't want it to be this way. It is the compiler's job to make useful error messages when the wrong field of a type info result is accessed, and it is the zig programmer's job to understand what it means when a compile error points at the field access of `@typeInfo` (along with the relevant callsites). One thing that might be useful would be having the compiler be aware of module boundaries and highlighting the boundaries of them. The first reference note after crossing a module boundary is likely the most interesting one. --- lib/std/heap/general_purpose_allocator.zig | 8 ++--- lib/std/mem/Allocator.zig | 35 ++++------------------ 2 files changed, 8 insertions(+), 35 deletions(-) diff --git a/lib/std/heap/general_purpose_allocator.zig b/lib/std/heap/general_purpose_allocator.zig index 15427dc1ce..4f8be3804c 100644 --- a/lib/std/heap/general_purpose_allocator.zig +++ b/lib/std/heap/general_purpose_allocator.zig @@ -397,9 +397,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { const prev = bucket.prev; if (config.never_unmap) { // free page that was intentionally leaked by never_unmap - const array_ptr = bucket.page[0..page_size]; - comptime assert(@TypeOf(array_ptr) == *align(page_size) [page_size]u8); - self.backing_allocator.free(@as([]align(page_size) u8, array_ptr)); + self.backing_allocator.free(bucket.page[0..page_size]); } // alloc_cursor was set to slot count when bucket added to empty_buckets self.freeBucket(bucket, @divExact(page_size, bucket.alloc_cursor)); @@ -816,9 +814,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { self.buckets[bucket_index] = bucket.prev; } if (!config.never_unmap) { - const array_ptr = bucket.page[0..page_size]; - comptime assert(@TypeOf(array_ptr) == *align(page_size) [page_size]u8); - self.backing_allocator.free(@as([]align(page_size) u8, array_ptr)); + self.backing_allocator.free(bucket.page[0..page_size]); } if (!config.retain_metadata) { self.freeBucket(bucket, size_class); diff --git a/lib/std/mem/Allocator.zig b/lib/std/mem/Allocator.zig index dec1ccbc74..6e56607865 100644 --- a/lib/std/mem/Allocator.zig +++ b/lib/std/mem/Allocator.zig @@ -109,7 +109,7 @@ pub fn create(self: Allocator, comptime T: type) Error!*T { /// `ptr` should be the return value of `create`, or otherwise /// have the same address and alignment property. pub fn destroy(self: Allocator, ptr: anytype) void { - const info = ensureSlice(@TypeOf(ptr), "destroy", .One); + const info = @typeInfo(@TypeOf(ptr)).Pointer; const T = info.child; if (@sizeOf(T) == 0) return; const non_const_ptr = @intToPtr([*]u8, @ptrToInt(ptr)); @@ -224,7 +224,7 @@ pub fn allocAdvancedWithRetAddr( /// the pointer, however the allocator implementation may refuse the resize /// request by returning `false`. pub fn resize(self: Allocator, old_mem: anytype, new_n: usize) bool { - const Slice = ensureSlice(@TypeOf(old_mem), "resize", .Slice); + const Slice = @typeInfo(@TypeOf(old_mem)).Pointer; const T = Slice.child; if (new_n == 0) { self.free(old_mem); @@ -245,7 +245,7 @@ pub fn resize(self: Allocator, old_mem: anytype, new_n: usize) bool { /// can be larger, smaller, or the same size as the old memory allocation. /// If `new_n` is 0, this is the same as `free` and it always succeeds. pub fn realloc(self: Allocator, old_mem: anytype, new_n: usize) t: { - const Slice = ensureSlice(@TypeOf(old_mem), "realloc", .Slice); + const Slice = @typeInfo(@TypeOf(old_mem)).Pointer; break :t Error![]align(Slice.alignment) Slice.child; } { return self.reallocAdvanced(old_mem, new_n, @returnAddress()); @@ -257,10 +257,10 @@ pub fn reallocAdvanced( new_n: usize, return_address: usize, ) t: { - const Slice = ensureSlice(@TypeOf(old_mem), "reallocAdvanced", .Slice); + const Slice = @typeInfo(@TypeOf(old_mem)).Pointer; break :t Error![]align(Slice.alignment) Slice.child; } { - const Slice = ensureSlice(@TypeOf(old_mem), "reallocAdvanced", .Slice); + const Slice = @typeInfo(@TypeOf(old_mem)).Pointer; const T = Slice.child; if (old_mem.len == 0) { return self.allocAdvancedWithRetAddr(T, Slice.alignment, new_n, return_address); @@ -293,7 +293,7 @@ pub fn reallocAdvanced( /// Free an array allocated with `alloc`. To free a single item, /// see `destroy`. pub fn free(self: Allocator, memory: anytype) void { - const Slice = ensureSlice(@TypeOf(memory), "free", .Slice); + const Slice = @typeInfo(@TypeOf(memory)).Pointer; const bytes = mem.sliceAsBytes(memory); const bytes_len = bytes.len + if (Slice.sentinel != null) @sizeOf(Slice.child) else 0; if (bytes_len == 0) return; @@ -318,29 +318,6 @@ pub fn dupeZ(allocator: Allocator, comptime T: type, m: []const T) ![:0]T { return new_buf[0..m.len :0]; } -inline fn ensureSlice( - comptime Type: type, - comptime function_name: []const u8, - comptime expected_size: std.builtin.Type.Pointer.Size, -) std.builtin.Type.Pointer { - const expectation = switch (expected_size) { - .One => "a single item pointer", - .Slice => "a slice", - else => unreachable, - }; - const type_info = @typeInfo(Type); - - if (type_info == .Pointer) { - const pointer = type_info.Pointer; - - if (pointer.size == expected_size) { - return pointer; - } - } - - @compileError(std.fmt.comptimePrint("{s} expects {s} but received a value of type `{s}`", .{ function_name, expectation, @typeName(Type) })); -} - /// TODO replace callsites with `@log2` after this proposal is implemented: /// https://github.com/ziglang/zig/issues/13642 inline fn log2a(x: anytype) switch (@typeInfo(@TypeOf(x))) {