| author | |
| committer | |
| log | 85d4c8620f602726b159efe1fe2ea0e07e3c5b59 |
| tree | 73399f38f3a9782a9ecf067eec3cc612d79a4591 |
| parent | 042b770d6272391a9c25f3444991b439ae07a1b5 |
6 files changed, 138 insertions(+), 107 deletions(-)
src/Sema.zig+24-3| ... | @@ -13014,7 +13014,25 @@ fn coerceInMemoryAllowed( | ... | @@ -13014,7 +13014,25 @@ fn coerceInMemoryAllowed( |
| 13014 | return try sema.coerceInMemoryAllowedErrorSets(dest_ty, src_ty); | 13014 | return try sema.coerceInMemoryAllowedErrorSets(dest_ty, src_ty); |
| 13015 | } | 13015 | } |
| 13016 | 13016 | ||
| 13017 | // TODO: arrays | 13017 | // Arrays |
| 13018 | if (dest_tag == .Array and src_tag == .Array) arrays: { | ||
| 13019 | const dest_info = dest_ty.arrayInfo(); | ||
| 13020 | const src_info = src_ty.arrayInfo(); | ||
| 13021 | if (dest_info.len != src_info.len) break :arrays; | ||
| 13022 | |||
| 13023 | const child = try sema.coerceInMemoryAllowed(block, dest_info.elem_type, src_info.elem_type, dest_is_mut, target, dest_src, src_src); | ||
| 13024 | if (child == .no_match) { | ||
| 13025 | return child; | ||
| 13026 | } | ||
| 13027 | const ok_sent = dest_info.sentinel == null or | ||
| 13028 | (src_info.sentinel != null and | ||
| 13029 | dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.elem_type)); | ||
| 13030 | if (!ok_sent) { | ||
| 13031 | return .no_match; | ||
| 13032 | } | ||
| 13033 | return .ok; | ||
| 13034 | } | ||
| 13035 | |||
| 13018 | // TODO: non-pointer-like optionals | 13036 | // TODO: non-pointer-like optionals |
| 13019 | // TODO: vectors | 13037 | // TODO: vectors |
| 13020 | 13038 | ||
| ... | @@ -13399,8 +13417,11 @@ fn beginComptimePtrMutation( | ... | @@ -13399,8 +13417,11 @@ fn beginComptimePtrMutation( |
| 13399 | defer parent.finishArena(); | 13417 | defer parent.finishArena(); |
| 13400 | 13418 | ||
| 13401 | const bytes = parent.val.castTag(.bytes).?.data; | 13419 | const bytes = parent.val.castTag(.bytes).?.data; |
| 13402 | assert(bytes.len == parent.ty.arrayLenIncludingSentinel()); | 13420 | const dest_len = parent.ty.arrayLenIncludingSentinel(); |
| 13403 | const elems = try arena.alloc(Value, bytes.len); | 13421 | // bytes.len may be one greater than dest_len because of the case when |
| 13422 | // assigning `[N:S]T` to `[N]T`. This is allowed; the sentinel is omitted. | ||
| 13423 | assert(bytes.len >= dest_len); | ||
| 13424 | const elems = try arena.alloc(Value, dest_len); | ||
| 13404 | for (elems) |*elem, i| { | 13425 | for (elems) |*elem, i| { |
| 13405 | elem.* = try Value.Tag.int_u64.create(arena, bytes[i]); | 13426 | elem.* = try Value.Tag.int_u64.create(arena, bytes[i]); |
| 13406 | } | 13427 | } |
src/type.zig+25-15| ... | @@ -2189,8 +2189,8 @@ pub const Type = extern union { | ... | @@ -2189,8 +2189,8 @@ pub const Type = extern union { |
| 2189 | } | 2189 | } |
| 2190 | 2190 | ||
| 2191 | /// Asserts the type has the bit size already resolved. | 2191 | /// Asserts the type has the bit size already resolved. |
| 2192 | pub fn bitSize(self: Type, target: Target) u64 { | 2192 | pub fn bitSize(ty: Type, target: Target) u64 { |
| 2193 | return switch (self.tag()) { | 2193 | return switch (ty.tag()) { |
| 2194 | .fn_noreturn_no_args => unreachable, // represents machine code; not a pointer | 2194 | .fn_noreturn_no_args => unreachable, // represents machine code; not a pointer |
| 2195 | .fn_void_no_args => unreachable, // represents machine code; not a pointer | 2195 | .fn_void_no_args => unreachable, // represents machine code; not a pointer |
| 2196 | .fn_naked_noreturn_no_args => unreachable, // represents machine code; not a pointer | 2196 | .fn_naked_noreturn_no_args => unreachable, // represents machine code; not a pointer |
| ... | @@ -2216,11 +2216,21 @@ pub const Type = extern union { | ... | @@ -2216,11 +2216,21 @@ pub const Type = extern union { |
| 2216 | .bound_fn => unreachable, | 2216 | .bound_fn => unreachable, |
| 2217 | 2217 | ||
| 2218 | .@"struct" => { | 2218 | .@"struct" => { |
| 2219 | @panic("TODO bitSize struct"); | 2219 | const field_count = ty.structFieldCount(); |
| 2220 | if (field_count == 0) return 0; | ||
| 2221 | |||
| 2222 | const struct_obj = ty.castTag(.@"struct").?.data; | ||
| 2223 | assert(struct_obj.status == .have_layout); | ||
| 2224 | |||
| 2225 | var total: u64 = 0; | ||
| 2226 | for (struct_obj.fields.values()) |field| { | ||
| 2227 | total += field.ty.bitSize(target); | ||
| 2228 | } | ||
| 2229 | return total; | ||
| 2220 | }, | 2230 | }, |
| 2221 | .enum_simple, .enum_full, .enum_nonexhaustive, .enum_numbered => { | 2231 | .enum_simple, .enum_full, .enum_nonexhaustive, .enum_numbered => { |
| 2222 | var buffer: Payload.Bits = undefined; | 2232 | var buffer: Payload.Bits = undefined; |
| 2223 | const int_tag_ty = self.intTagType(&buffer); | 2233 | const int_tag_ty = ty.intTagType(&buffer); |
| 2224 | return int_tag_ty.bitSize(target); | 2234 | return int_tag_ty.bitSize(target); |
| 2225 | }, | 2235 | }, |
| 2226 | .@"union", .union_tagged => { | 2236 | .@"union", .union_tagged => { |
| ... | @@ -2232,21 +2242,21 @@ pub const Type = extern union { | ... | @@ -2232,21 +2242,21 @@ pub const Type = extern union { |
| 2232 | .bool, .u1 => 1, | 2242 | .bool, .u1 => 1, |
| 2233 | 2243 | ||
| 2234 | .vector => { | 2244 | .vector => { |
| 2235 | const payload = self.castTag(.vector).?.data; | 2245 | const payload = ty.castTag(.vector).?.data; |
| 2236 | const elem_bit_size = payload.elem_type.bitSize(target); | 2246 | const elem_bit_size = payload.elem_type.bitSize(target); |
| 2237 | return elem_bit_size * payload.len; | 2247 | return elem_bit_size * payload.len; |
| 2238 | }, | 2248 | }, |
| 2239 | .array_u8 => 8 * self.castTag(.array_u8).?.data, | 2249 | .array_u8 => 8 * ty.castTag(.array_u8).?.data, |
| 2240 | .array_u8_sentinel_0 => 8 * (self.castTag(.array_u8_sentinel_0).?.data + 1), | 2250 | .array_u8_sentinel_0 => 8 * (ty.castTag(.array_u8_sentinel_0).?.data + 1), |
| 2241 | .array => { | 2251 | .array => { |
| 2242 | const payload = self.castTag(.array).?.data; | 2252 | const payload = ty.castTag(.array).?.data; |
| 2243 | const elem_size = std.math.max(payload.elem_type.abiAlignment(target), payload.elem_type.abiSize(target)); | 2253 | const elem_size = std.math.max(payload.elem_type.abiAlignment(target), payload.elem_type.abiSize(target)); |
| 2244 | if (elem_size == 0 or payload.len == 0) | 2254 | if (elem_size == 0 or payload.len == 0) |
| 2245 | return 0; | 2255 | return 0; |
| 2246 | return (payload.len - 1) * 8 * elem_size + payload.elem_type.bitSize(target); | 2256 | return (payload.len - 1) * 8 * elem_size + payload.elem_type.bitSize(target); |
| 2247 | }, | 2257 | }, |
| 2248 | .array_sentinel => { | 2258 | .array_sentinel => { |
| 2249 | const payload = self.castTag(.array_sentinel).?.data; | 2259 | const payload = ty.castTag(.array_sentinel).?.data; |
| 2250 | const elem_size = std.math.max( | 2260 | const elem_size = std.math.max( |
| 2251 | payload.elem_type.abiAlignment(target), | 2261 | payload.elem_type.abiAlignment(target), |
| 2252 | payload.elem_type.abiSize(target), | 2262 | payload.elem_type.abiSize(target), |
| ... | @@ -2267,7 +2277,7 @@ pub const Type = extern union { | ... | @@ -2267,7 +2277,7 @@ pub const Type = extern union { |
| 2267 | .const_slice, | 2277 | .const_slice, |
| 2268 | .mut_slice, | 2278 | .mut_slice, |
| 2269 | => { | 2279 | => { |
| 2270 | if (self.elemType().hasCodeGenBits()) { | 2280 | if (ty.elemType().hasCodeGenBits()) { |
| 2271 | return target.cpu.arch.ptrBitWidth() * 2; | 2281 | return target.cpu.arch.ptrBitWidth() * 2; |
| 2272 | } else { | 2282 | } else { |
| 2273 | return target.cpu.arch.ptrBitWidth(); | 2283 | return target.cpu.arch.ptrBitWidth(); |
| ... | @@ -2280,7 +2290,7 @@ pub const Type = extern union { | ... | @@ -2280,7 +2290,7 @@ pub const Type = extern union { |
| 2280 | .optional_single_const_pointer, | 2290 | .optional_single_const_pointer, |
| 2281 | .optional_single_mut_pointer, | 2291 | .optional_single_mut_pointer, |
| 2282 | => { | 2292 | => { |
| 2283 | if (self.elemType().hasCodeGenBits()) { | 2293 | if (ty.elemType().hasCodeGenBits()) { |
| 2284 | return target.cpu.arch.ptrBitWidth(); | 2294 | return target.cpu.arch.ptrBitWidth(); |
| 2285 | } else { | 2295 | } else { |
| 2286 | return 1; | 2296 | return 1; |
| ... | @@ -2295,7 +2305,7 @@ pub const Type = extern union { | ... | @@ -2295,7 +2305,7 @@ pub const Type = extern union { |
| 2295 | .c_mut_pointer, | 2305 | .c_mut_pointer, |
| 2296 | .pointer, | 2306 | .pointer, |
| 2297 | => { | 2307 | => { |
| 2298 | if (self.elemType().hasCodeGenBits()) { | 2308 | if (ty.elemType().hasCodeGenBits()) { |
| 2299 | return target.cpu.arch.ptrBitWidth(); | 2309 | return target.cpu.arch.ptrBitWidth(); |
| 2300 | } else { | 2310 | } else { |
| 2301 | return 0; | 2311 | return 0; |
| ... | @@ -2325,11 +2335,11 @@ pub const Type = extern union { | ... | @@ -2325,11 +2335,11 @@ pub const Type = extern union { |
| 2325 | .error_set_merged, | 2335 | .error_set_merged, |
| 2326 | => return 16, // TODO revisit this when we have the concept of the error tag type | 2336 | => return 16, // TODO revisit this when we have the concept of the error tag type |
| 2327 | 2337 | ||
| 2328 | .int_signed, .int_unsigned => self.cast(Payload.Bits).?.data, | 2338 | .int_signed, .int_unsigned => ty.cast(Payload.Bits).?.data, |
| 2329 | 2339 | ||
| 2330 | .optional => { | 2340 | .optional => { |
| 2331 | var buf: Payload.ElemType = undefined; | 2341 | var buf: Payload.ElemType = undefined; |
| 2332 | const child_type = self.optionalChild(&buf); | 2342 | const child_type = ty.optionalChild(&buf); |
| 2333 | if (!child_type.hasCodeGenBits()) return 8; | 2343 | if (!child_type.hasCodeGenBits()) return 8; |
| 2334 | 2344 | ||
| 2335 | if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr()) | 2345 | if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr()) |
| ... | @@ -2343,7 +2353,7 @@ pub const Type = extern union { | ... | @@ -2343,7 +2353,7 @@ pub const Type = extern union { |
| 2343 | }, | 2353 | }, |
| 2344 | 2354 | ||
| 2345 | .error_union => { | 2355 | .error_union => { |
| 2346 | const payload = self.castTag(.error_union).?.data; | 2356 | const payload = ty.castTag(.error_union).?.data; |
| 2347 | if (!payload.error_set.hasCodeGenBits() and !payload.payload.hasCodeGenBits()) { | 2357 | if (!payload.error_set.hasCodeGenBits() and !payload.payload.hasCodeGenBits()) { |
| 2348 | return 0; | 2358 | return 0; |
| 2349 | } else if (!payload.error_set.hasCodeGenBits()) { | 2359 | } else if (!payload.error_set.hasCodeGenBits()) { |
test/behavior/array.zig+50| ... | @@ -164,3 +164,53 @@ test "read/write through global variable array of struct fields initialized via | ... | @@ -164,3 +164,53 @@ test "read/write through global variable array of struct fields initialized via |
| 164 | }; | 164 | }; |
| 165 | try S.doTheTest(); | 165 | try S.doTheTest(); |
| 166 | } | 166 | } |
| 167 | |||
| 168 | test "single-item pointer to array indexing and slicing" { | ||
| 169 | try testSingleItemPtrArrayIndexSlice(); | ||
| 170 | comptime try testSingleItemPtrArrayIndexSlice(); | ||
| 171 | } | ||
| 172 | |||
| 173 | fn testSingleItemPtrArrayIndexSlice() !void { | ||
| 174 | { | ||
| 175 | var array: [4]u8 = "aaaa".*; | ||
| 176 | doSomeMangling(&array); | ||
| 177 | try expect(mem.eql(u8, "azya", &array)); | ||
| 178 | } | ||
| 179 | { | ||
| 180 | var array = "aaaa".*; | ||
| 181 | doSomeMangling(&array); | ||
| 182 | try expect(mem.eql(u8, "azya", &array)); | ||
| 183 | } | ||
| 184 | } | ||
| 185 | |||
| 186 | fn doSomeMangling(array: *[4]u8) void { | ||
| 187 | array[1] = 'z'; | ||
| 188 | array[2..3][0] = 'y'; | ||
| 189 | } | ||
| 190 | |||
| 191 | test "implicit cast zero sized array ptr to slice" { | ||
| 192 | { | ||
| 193 | var b = "".*; | ||
| 194 | const c: []const u8 = &b; | ||
| 195 | try expect(c.len == 0); | ||
| 196 | } | ||
| 197 | { | ||
| 198 | var b: [0]u8 = "".*; | ||
| 199 | const c: []const u8 = &b; | ||
| 200 | try expect(c.len == 0); | ||
| 201 | } | ||
| 202 | } | ||
| 203 | |||
| 204 | test "anonymous list literal syntax" { | ||
| 205 | const S = struct { | ||
| 206 | fn doTheTest() !void { | ||
| 207 | var array: [4]u8 = .{ 1, 2, 3, 4 }; | ||
| 208 | try expect(array[0] == 1); | ||
| 209 | try expect(array[1] == 2); | ||
| 210 | try expect(array[2] == 3); | ||
| 211 | try expect(array[3] == 4); | ||
| 212 | } | ||
| 213 | }; | ||
| 214 | try S.doTheTest(); | ||
| 215 | comptime try S.doTheTest(); | ||
| 216 | } |
test/behavior/array_stage1.zig-50| ... | @@ -4,29 +4,6 @@ const mem = std.mem; | ... | @@ -4,29 +4,6 @@ const mem = std.mem; |
| 4 | const expect = testing.expect; | 4 | const expect = testing.expect; |
| 5 | const expectEqual = testing.expectEqual; | 5 | const expectEqual = testing.expectEqual; |
| 6 | 6 | ||
| 7 | test "single-item pointer to array indexing and slicing" { | ||
| 8 | try testSingleItemPtrArrayIndexSlice(); | ||
| 9 | comptime try testSingleItemPtrArrayIndexSlice(); | ||
| 10 | } | ||
| 11 | |||
| 12 | fn testSingleItemPtrArrayIndexSlice() !void { | ||
| 13 | { | ||
| 14 | var array: [4]u8 = "aaaa".*; | ||
| 15 | doSomeMangling(&array); | ||
| 16 | try expect(mem.eql(u8, "azya", &array)); | ||
| 17 | } | ||
| 18 | { | ||
| 19 | var array = "aaaa".*; | ||
| 20 | doSomeMangling(&array); | ||
| 21 | try expect(mem.eql(u8, "azya", &array)); | ||
| 22 | } | ||
| 23 | } | ||
| 24 | |||
| 25 | fn doSomeMangling(array: *[4]u8) void { | ||
| 26 | array[1] = 'z'; | ||
| 27 | array[2..3][0] = 'y'; | ||
| 28 | } | ||
| 29 | |||
| 30 | test "implicit cast single-item pointer" { | 7 | test "implicit cast single-item pointer" { |
| 31 | try testImplicitCastSingleItemPtr(); | 8 | try testImplicitCastSingleItemPtr(); |
| 32 | comptime try testImplicitCastSingleItemPtr(); | 9 | comptime try testImplicitCastSingleItemPtr(); |
| ... | @@ -136,33 +113,6 @@ test "double nested array to const slice cast in array literal" { | ... | @@ -136,33 +113,6 @@ test "double nested array to const slice cast in array literal" { |
| 136 | comptime try S.entry(2); | 113 | comptime try S.entry(2); |
| 137 | } | 114 | } |
| 138 | 115 | ||
| 139 | test "implicit cast zero sized array ptr to slice" { | ||
| 140 | { | ||
| 141 | var b = "".*; | ||
| 142 | const c: []const u8 = &b; | ||
| 143 | try expect(c.len == 0); | ||
| 144 | } | ||
| 145 | { | ||
| 146 | var b: [0]u8 = "".*; | ||
| 147 | const c: []const u8 = &b; | ||
| 148 | try expect(c.len == 0); | ||
| 149 | } | ||
| 150 | } | ||
| 151 | |||
| 152 | test "anonymous list literal syntax" { | ||
| 153 | const S = struct { | ||
| 154 | fn doTheTest() !void { | ||
| 155 | var array: [4]u8 = .{ 1, 2, 3, 4 }; | ||
| 156 | try expect(array[0] == 1); | ||
| 157 | try expect(array[1] == 2); | ||
| 158 | try expect(array[2] == 3); | ||
| 159 | try expect(array[3] == 4); | ||
| 160 | } | ||
| 161 | }; | ||
| 162 | try S.doTheTest(); | ||
| 163 | comptime try S.doTheTest(); | ||
| 164 | } | ||
| 165 | |||
| 166 | test "anonymous literal in array" { | 116 | test "anonymous literal in array" { |
| 167 | const S = struct { | 117 | const S = struct { |
| 168 | const Foo = struct { | 118 | const Foo = struct { |
test/behavior/struct_llvm.zig+39| ... | @@ -246,3 +246,42 @@ test "packed struct with non-ABI-aligned field" { | ... | @@ -246,3 +246,42 @@ test "packed struct with non-ABI-aligned field" { |
| 246 | try expect(s.x == 1); | 246 | try expect(s.x == 1); |
| 247 | try expect(s.y == 42); | 247 | try expect(s.y == 42); |
| 248 | } | 248 | } |
| 249 | |||
| 250 | const BitField1 = packed struct { | ||
| 251 | a: u3, | ||
| 252 | b: u3, | ||
| 253 | c: u2, | ||
| 254 | }; | ||
| 255 | |||
| 256 | const bit_field_1 = BitField1{ | ||
| 257 | .a = 1, | ||
| 258 | .b = 2, | ||
| 259 | .c = 3, | ||
| 260 | }; | ||
| 261 | |||
| 262 | test "bit field access" { | ||
| 263 | var data = bit_field_1; | ||
| 264 | try expect(getA(&data) == 1); | ||
| 265 | try expect(getB(&data) == 2); | ||
| 266 | try expect(getC(&data) == 3); | ||
| 267 | comptime try expect(@sizeOf(BitField1) == 1); | ||
| 268 | |||
| 269 | data.b += 1; | ||
| 270 | try expect(data.b == 3); | ||
| 271 | |||
| 272 | data.a += 1; | ||
| 273 | try expect(data.a == 2); | ||
| 274 | try expect(data.b == 3); | ||
| 275 | } | ||
| 276 | |||
| 277 | fn getA(data: *const BitField1) u3 { | ||
| 278 | return data.a; | ||
| 279 | } | ||
| 280 | |||
| 281 | fn getB(data: *const BitField1) u3 { | ||
| 282 | return data.b; | ||
| 283 | } | ||
| 284 | |||
| 285 | fn getC(data: *const BitField1) u2 { | ||
| 286 | return data.c; | ||
| 287 | } |
test/behavior/struct_stage1.zig-39| ... | @@ -6,45 +6,6 @@ const expectEqual = std.testing.expectEqual; | ... | @@ -6,45 +6,6 @@ const expectEqual = std.testing.expectEqual; |
| 6 | const expectEqualSlices = std.testing.expectEqualSlices; | 6 | const expectEqualSlices = std.testing.expectEqualSlices; |
| 7 | const maxInt = std.math.maxInt; | 7 | const maxInt = std.math.maxInt; |
| 8 | 8 | ||
| 9 | const BitField1 = packed struct { | ||
| 10 | a: u3, | ||
| 11 | b: u3, | ||
| 12 | c: u2, | ||
| 13 | }; | ||
| 14 | |||
| 15 | const bit_field_1 = BitField1{ | ||
| 16 | .a = 1, | ||
| 17 | .b = 2, | ||
| 18 | .c = 3, | ||
| 19 | }; | ||
| 20 | |||
| 21 | test "bit field access" { | ||
| 22 | var data = bit_field_1; | ||
| 23 | try expect(getA(&data) == 1); | ||
| 24 | try expect(getB(&data) == 2); | ||
| 25 | try expect(getC(&data) == 3); | ||
| 26 | comptime try expect(@sizeOf(BitField1) == 1); | ||
| 27 | |||
| 28 | data.b += 1; | ||
| 29 | try expect(data.b == 3); | ||
| 30 | |||
| 31 | data.a += 1; | ||
| 32 | try expect(data.a == 2); | ||
| 33 | try expect(data.b == 3); | ||
| 34 | } | ||
| 35 | |||
| 36 | fn getA(data: *const BitField1) u3 { | ||
| 37 | return data.a; | ||
| 38 | } | ||
| 39 | |||
| 40 | fn getB(data: *const BitField1) u3 { | ||
| 41 | return data.b; | ||
| 42 | } | ||
| 43 | |||
| 44 | fn getC(data: *const BitField1) u2 { | ||
| 45 | return data.c; | ||
| 46 | } | ||
| 47 | |||
| 48 | const Foo32Bits = packed struct { | 9 | const Foo32Bits = packed struct { |
| 49 | field: u24, | 10 | field: u24, |
| 50 | pad: u8, | 11 | pad: u8, |