authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-02-12 05:59:28-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-02-12 05:59:28-07:00
log3c2a43fdcc2d9aeafafe7ef37c7b805e18fac351
tree99050b8c99b38756448f321c145b926d0efff95c
parentabc9530a88d24350481d9264edcde300f293929a

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.

2 files changed, 8 insertions(+), 35 deletions(-)

lib/std/heap/general_purpose_allocator.zig+2-6
...@@ -397,9 +397,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {...@@ -397,9 +397,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
397 const prev = bucket.prev;397 const prev = bucket.prev;
398 if (config.never_unmap) {398 if (config.never_unmap) {
399 // free page that was intentionally leaked by never_unmap399 // free page that was intentionally leaked by never_unmap
400 const array_ptr = bucket.page[0..page_size];400 self.backing_allocator.free(bucket.page[0..page_size]);
401 comptime assert(@TypeOf(array_ptr) == *align(page_size) [page_size]u8);
402 self.backing_allocator.free(@as([]align(page_size) u8, array_ptr));
403 }401 }
404 // alloc_cursor was set to slot count when bucket added to empty_buckets402 // alloc_cursor was set to slot count when bucket added to empty_buckets
405 self.freeBucket(bucket, @divExact(page_size, bucket.alloc_cursor));403 self.freeBucket(bucket, @divExact(page_size, bucket.alloc_cursor));
...@@ -816,9 +814,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {...@@ -816,9 +814,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
816 self.buckets[bucket_index] = bucket.prev;814 self.buckets[bucket_index] = bucket.prev;
817 }815 }
818 if (!config.never_unmap) {816 if (!config.never_unmap) {
819 const array_ptr = bucket.page[0..page_size];817 self.backing_allocator.free(bucket.page[0..page_size]);
820 comptime assert(@TypeOf(array_ptr) == *align(page_size) [page_size]u8);
821 self.backing_allocator.free(@as([]align(page_size) u8, array_ptr));
822 }818 }
823 if (!config.retain_metadata) {819 if (!config.retain_metadata) {
824 self.freeBucket(bucket, size_class);820 self.freeBucket(bucket, size_class);
lib/std/mem/Allocator.zig+6-29
...@@ -109,7 +109,7 @@ pub fn create(self: Allocator, comptime T: type) Error!*T {...@@ -109,7 +109,7 @@ pub fn create(self: Allocator, comptime T: type) Error!*T {
109/// `ptr` should be the return value of `create`, or otherwise109/// `ptr` should be the return value of `create`, or otherwise
110/// have the same address and alignment property.110/// have the same address and alignment property.
111pub fn destroy(self: Allocator, ptr: anytype) void {111pub fn destroy(self: Allocator, ptr: anytype) void {
112 const info = ensureSlice(@TypeOf(ptr), "destroy", .One);112 const info = @typeInfo(@TypeOf(ptr)).Pointer;
113 const T = info.child;113 const T = info.child;
114 if (@sizeOf(T) == 0) return;114 if (@sizeOf(T) == 0) return;
115 const non_const_ptr = @intToPtr([*]u8, @ptrToInt(ptr));115 const non_const_ptr = @intToPtr([*]u8, @ptrToInt(ptr));
...@@ -224,7 +224,7 @@ pub fn allocAdvancedWithRetAddr(...@@ -224,7 +224,7 @@ pub fn allocAdvancedWithRetAddr(
224/// the pointer, however the allocator implementation may refuse the resize224/// the pointer, however the allocator implementation may refuse the resize
225/// request by returning `false`.225/// request by returning `false`.
226pub fn resize(self: Allocator, old_mem: anytype, new_n: usize) bool {226pub fn resize(self: Allocator, old_mem: anytype, new_n: usize) bool {
227 const Slice = ensureSlice(@TypeOf(old_mem), "resize", .Slice);227 const Slice = @typeInfo(@TypeOf(old_mem)).Pointer;
228 const T = Slice.child;228 const T = Slice.child;
229 if (new_n == 0) {229 if (new_n == 0) {
230 self.free(old_mem);230 self.free(old_mem);
...@@ -245,7 +245,7 @@ pub fn resize(self: Allocator, old_mem: anytype, new_n: usize) bool {...@@ -245,7 +245,7 @@ pub fn resize(self: Allocator, old_mem: anytype, new_n: usize) bool {
245/// can be larger, smaller, or the same size as the old memory allocation.245/// can be larger, smaller, or the same size as the old memory allocation.
246/// If `new_n` is 0, this is the same as `free` and it always succeeds.246/// If `new_n` is 0, this is the same as `free` and it always succeeds.
247pub fn realloc(self: Allocator, old_mem: anytype, new_n: usize) t: {247pub fn realloc(self: Allocator, old_mem: anytype, new_n: usize) t: {
248 const Slice = ensureSlice(@TypeOf(old_mem), "realloc", .Slice);248 const Slice = @typeInfo(@TypeOf(old_mem)).Pointer;
249 break :t Error![]align(Slice.alignment) Slice.child;249 break :t Error![]align(Slice.alignment) Slice.child;
250} {250} {
251 return self.reallocAdvanced(old_mem, new_n, @returnAddress());251 return self.reallocAdvanced(old_mem, new_n, @returnAddress());
...@@ -257,10 +257,10 @@ pub fn reallocAdvanced(...@@ -257,10 +257,10 @@ pub fn reallocAdvanced(
257 new_n: usize,257 new_n: usize,
258 return_address: usize,258 return_address: usize,
259) t: {259) t: {
260 const Slice = ensureSlice(@TypeOf(old_mem), "reallocAdvanced", .Slice);260 const Slice = @typeInfo(@TypeOf(old_mem)).Pointer;
261 break :t Error![]align(Slice.alignment) Slice.child;261 break :t Error![]align(Slice.alignment) Slice.child;
262} {262} {
263 const Slice = ensureSlice(@TypeOf(old_mem), "reallocAdvanced", .Slice);263 const Slice = @typeInfo(@TypeOf(old_mem)).Pointer;
264 const T = Slice.child;264 const T = Slice.child;
265 if (old_mem.len == 0) {265 if (old_mem.len == 0) {
266 return self.allocAdvancedWithRetAddr(T, Slice.alignment, new_n, return_address);266 return self.allocAdvancedWithRetAddr(T, Slice.alignment, new_n, return_address);
...@@ -293,7 +293,7 @@ pub fn reallocAdvanced(...@@ -293,7 +293,7 @@ pub fn reallocAdvanced(
293/// Free an array allocated with `alloc`. To free a single item,293/// Free an array allocated with `alloc`. To free a single item,
294/// see `destroy`.294/// see `destroy`.
295pub fn free(self: Allocator, memory: anytype) void {295pub fn free(self: Allocator, memory: anytype) void {
296 const Slice = ensureSlice(@TypeOf(memory), "free", .Slice);296 const Slice = @typeInfo(@TypeOf(memory)).Pointer;
297 const bytes = mem.sliceAsBytes(memory);297 const bytes = mem.sliceAsBytes(memory);
298 const bytes_len = bytes.len + if (Slice.sentinel != null) @sizeOf(Slice.child) else 0;298 const bytes_len = bytes.len + if (Slice.sentinel != null) @sizeOf(Slice.child) else 0;
299 if (bytes_len == 0) return;299 if (bytes_len == 0) return;
...@@ -318,29 +318,6 @@ pub fn dupeZ(allocator: Allocator, comptime T: type, m: []const T) ![:0]T {...@@ -318,29 +318,6 @@ pub fn dupeZ(allocator: Allocator, comptime T: type, m: []const T) ![:0]T {
318 return new_buf[0..m.len :0];318 return new_buf[0..m.len :0];
319}319}
320320
321inline fn ensureSlice(
322 comptime Type: type,
323 comptime function_name: []const u8,
324 comptime expected_size: std.builtin.Type.Pointer.Size,
325) std.builtin.Type.Pointer {
326 const expectation = switch (expected_size) {
327 .One => "a single item pointer",
328 .Slice => "a slice",
329 else => unreachable,
330 };
331 const type_info = @typeInfo(Type);
332
333 if (type_info == .Pointer) {
334 const pointer = type_info.Pointer;
335
336 if (pointer.size == expected_size) {
337 return pointer;
338 }
339 }
340
341 @compileError(std.fmt.comptimePrint("{s} expects {s} but received a value of type `{s}`", .{ function_name, expectation, @typeName(Type) }));
342}
343
344/// TODO replace callsites with `@log2` after this proposal is implemented:321/// TODO replace callsites with `@log2` after this proposal is implemented:
345/// https://github.com/ziglang/zig/issues/13642322/// https://github.com/ziglang/zig/issues/13642
346inline fn log2a(x: anytype) switch (@typeInfo(@TypeOf(x))) {323inline fn log2a(x: anytype) switch (@typeInfo(@TypeOf(x))) {