| author | |
| committer | |
| log | f58cbef1659742e57377d3f8c92a0b9b97af91ad |
| tree | 43bc60f54b5a4252df309d9c3cb5dbe3aca20297 |
| parent | d4468affb751668e156230c32b29c84684825b4f |
* The `indexable_ptr_len` ZIR instruction now uses a `none_or_ref`
ResultLoc. This prevents an unnecessary `ref` instruction from being
emitted.
* Sema: Fix `analyzeCall` using the incorrect ZIR object for the
generic function callee.
* LLVM backend: `genTypedValue` supports a `Slice` type encoded with
the `decl_ref` `Value`.5 files changed, 75 insertions(+), 47 deletions(-)
src/AstGen.zig+1-1| ... | @@ -5423,7 +5423,7 @@ fn forExpr( | ... | @@ -5423,7 +5423,7 @@ fn forExpr( |
| 5423 | const tree = astgen.tree; | 5423 | const tree = astgen.tree; |
| 5424 | const token_tags = tree.tokens.items(.tag); | 5424 | const token_tags = tree.tokens.items(.tag); |
| 5425 | 5425 | ||
| 5426 | const array_ptr = try expr(parent_gz, scope, .ref, for_full.ast.cond_expr); | 5426 | const array_ptr = try expr(parent_gz, scope, .none_or_ref, for_full.ast.cond_expr); |
| 5427 | const len = try parent_gz.addUnNode(.indexable_ptr_len, array_ptr, for_full.ast.cond_expr); | 5427 | const len = try parent_gz.addUnNode(.indexable_ptr_len, array_ptr, for_full.ast.cond_expr); |
| 5428 | 5428 | ||
| 5429 | const index_ptr = blk: { | 5429 | const index_ptr = blk: { |
src/Sema.zig+40-33| ... | @@ -1306,38 +1306,44 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Co | ... | @@ -1306,38 +1306,44 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Co |
| 1306 | 1306 | ||
| 1307 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 1307 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 1308 | const src = inst_data.src(); | 1308 | const src = inst_data.src(); |
| 1309 | const array_ptr = sema.resolveInst(inst_data.operand); | 1309 | const array = sema.resolveInst(inst_data.operand); |
| 1310 | const array_ptr_src = src; | 1310 | const array_ty = sema.typeOf(array); |
| 1311 | 1311 | ||
| 1312 | const elem_ty = sema.typeOf(array_ptr).elemType(); | 1312 | if (array_ty.isSlice()) { |
| 1313 | if (elem_ty.isSlice()) { | 1313 | return sema.analyzeSliceLen(block, src, array); |
| 1314 | const slice_inst = try sema.analyzeLoad(block, src, array_ptr, array_ptr_src); | ||
| 1315 | return sema.analyzeSliceLen(block, src, slice_inst); | ||
| 1316 | } | 1314 | } |
| 1317 | if (!elem_ty.isIndexable()) { | 1315 | |
| 1318 | const cond_src: LazySrcLoc = .{ .node_offset_for_cond = inst_data.src_node }; | 1316 | if (array_ty.isSinglePointer()) { |
| 1319 | const msg = msg: { | 1317 | const elem_ty = array_ty.elemType(); |
| 1320 | const msg = try sema.mod.errMsg( | 1318 | if (elem_ty.isSlice()) { |
| 1321 | &block.base, | 1319 | const slice_inst = try sema.analyzeLoad(block, src, array, src); |
| 1322 | cond_src, | 1320 | return sema.analyzeSliceLen(block, src, slice_inst); |
| 1323 | "type '{}' does not support indexing", | 1321 | } |
| 1324 | .{elem_ty}, | 1322 | if (!elem_ty.isIndexable()) { |
| 1325 | ); | 1323 | const msg = msg: { |
| 1326 | errdefer msg.destroy(sema.gpa); | 1324 | const msg = try sema.mod.errMsg( |
| 1327 | try sema.mod.errNote( | 1325 | &block.base, |
| 1328 | &block.base, | 1326 | src, |
| 1329 | cond_src, | 1327 | "type '{}' does not support indexing", |
| 1330 | msg, | 1328 | .{elem_ty}, |
| 1331 | "for loop operand must be an array, slice, tuple, or vector", | 1329 | ); |
| 1332 | .{}, | 1330 | errdefer msg.destroy(sema.gpa); |
| 1333 | ); | 1331 | try sema.mod.errNote( |
| 1334 | break :msg msg; | 1332 | &block.base, |
| 1335 | }; | 1333 | src, |
| 1336 | return sema.mod.failWithOwnedErrorMsg(&block.base, msg); | 1334 | msg, |
| 1335 | "for loop operand must be an array, slice, tuple, or vector", | ||
| 1336 | .{}, | ||
| 1337 | ); | ||
| 1338 | break :msg msg; | ||
| 1339 | }; | ||
| 1340 | return sema.mod.failWithOwnedErrorMsg(&block.base, msg); | ||
| 1341 | } | ||
| 1342 | const result_ptr = try sema.fieldPtr(block, src, array, "len", src); | ||
| 1343 | return sema.analyzeLoad(block, src, result_ptr, src); | ||
| 1337 | } | 1344 | } |
| 1338 | const result_ptr = try sema.fieldPtr(block, src, array_ptr, "len", src); | 1345 | |
| 1339 | const result_ptr_src = array_ptr_src; | 1346 | return sema.mod.fail(&block.base, src, "TODO implement Sema.zirIndexablePtrLen", .{}); |
| 1340 | return sema.analyzeLoad(block, src, result_ptr, result_ptr_src); | ||
| 1341 | } | 1347 | } |
| 1342 | 1348 | ||
| 1343 | fn zirAllocExtended( | 1349 | fn zirAllocExtended( |
| ... | @@ -2520,10 +2526,11 @@ fn analyzeCall( | ... | @@ -2520,10 +2526,11 @@ fn analyzeCall( |
| 2520 | // generic Scope only to junk it if it matches an existing instantiation. | 2526 | // generic Scope only to junk it if it matches an existing instantiation. |
| 2521 | // TODO | 2527 | // TODO |
| 2522 | 2528 | ||
| 2523 | const fn_info = sema.code.getFnInfo(module_fn.zir_body_inst); | 2529 | const namespace = module_fn.owner_decl.namespace; |
| 2524 | const zir_tags = sema.code.instructions.items(.tag); | 2530 | const fn_zir = namespace.file_scope.zir; |
| 2531 | const fn_info = fn_zir.getFnInfo(module_fn.zir_body_inst); | ||
| 2532 | const zir_tags = fn_zir.instructions.items(.tag); | ||
| 2525 | const new_func = new_func: { | 2533 | const new_func = new_func: { |
| 2526 | const namespace = module_fn.owner_decl.namespace; | ||
| 2527 | try namespace.anon_decls.ensureUnusedCapacity(gpa, 1); | 2534 | try namespace.anon_decls.ensureUnusedCapacity(gpa, 1); |
| 2528 | 2535 | ||
| 2529 | // Create a Decl for the new function. | 2536 | // Create a Decl for the new function. |
| ... | @@ -2558,7 +2565,7 @@ fn analyzeCall( | ... | @@ -2558,7 +2565,7 @@ fn analyzeCall( |
| 2558 | .mod = mod, | 2565 | .mod = mod, |
| 2559 | .gpa = gpa, | 2566 | .gpa = gpa, |
| 2560 | .arena = sema.arena, | 2567 | .arena = sema.arena, |
| 2561 | .code = sema.code, | 2568 | .code = fn_zir, |
| 2562 | .owner_decl = new_decl, | 2569 | .owner_decl = new_decl, |
| 2563 | .namespace = namespace, | 2570 | .namespace = namespace, |
| 2564 | .func = null, | 2571 | .func = null, |
src/codegen/llvm.zig+25-5| ... | @@ -701,11 +701,31 @@ pub const DeclGen = struct { | ... | @@ -701,11 +701,31 @@ pub const DeclGen = struct { |
| 701 | }, | 701 | }, |
| 702 | .Pointer => switch (tv.val.tag()) { | 702 | .Pointer => switch (tv.val.tag()) { |
| 703 | .decl_ref => { | 703 | .decl_ref => { |
| 704 | const decl = tv.val.castTag(.decl_ref).?.data; | 704 | if (tv.ty.isSlice()) { |
| 705 | decl.alive = true; | 705 | var buf: Type.Payload.ElemType = undefined; |
| 706 | const val = try self.resolveGlobalDecl(decl); | 706 | const ptr_ty = tv.ty.slicePtrFieldType(&buf); |
| 707 | const llvm_type = try self.llvmType(tv.ty); | 707 | var slice_len: Value.Payload.U64 = .{ |
| 708 | return val.constBitCast(llvm_type); | 708 | .base = .{ .tag = .int_u64 }, |
| 709 | .data = tv.val.sliceLen(), | ||
| 710 | }; | ||
| 711 | const fields: [2]*const llvm.Value = .{ | ||
| 712 | try self.genTypedValue(.{ | ||
| 713 | .ty = ptr_ty, | ||
| 714 | .val = tv.val, | ||
| 715 | }), | ||
| 716 | try self.genTypedValue(.{ | ||
| 717 | .ty = Type.initTag(.usize), | ||
| 718 | .val = Value.initPayload(&slice_len.base), | ||
| 719 | }), | ||
| 720 | }; | ||
| 721 | return self.context.constStruct(&fields, fields.len, .False); | ||
| 722 | } else { | ||
| 723 | const decl = tv.val.castTag(.decl_ref).?.data; | ||
| 724 | decl.alive = true; | ||
| 725 | const val = try self.resolveGlobalDecl(decl); | ||
| 726 | const llvm_type = try self.llvmType(tv.ty); | ||
| 727 | return val.constBitCast(llvm_type); | ||
| 728 | } | ||
| 709 | }, | 729 | }, |
| 710 | .variable => { | 730 | .variable => { |
| 711 | const decl = tv.val.castTag(.variable).?.data.owner_decl; | 731 | const decl = tv.val.castTag(.variable).?.data.owner_decl; |
test/behavior/basic.zig+9| ... | @@ -1,4 +1,5 @@ | ... | @@ -1,4 +1,5 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const mem = std.mem; | ||
| 2 | const expect = std.testing.expect; | 3 | const expect = std.testing.expect; |
| 3 | 4 | ||
| 4 | // normal comment | 5 | // normal comment |
| ... | @@ -83,3 +84,11 @@ test "unicode escape in character literal" { | ... | @@ -83,3 +84,11 @@ test "unicode escape in character literal" { |
| 83 | test "unicode character in character literal" { | 84 | test "unicode character in character literal" { |
| 84 | try expect('💩' == 128169); | 85 | try expect('💩' == 128169); |
| 85 | } | 86 | } |
| 87 | |||
| 88 | fn first4KeysOfHomeRow() []const u8 { | ||
| 89 | return "aoeu"; | ||
| 90 | } | ||
| 91 | |||
| 92 | test "return string from function" { | ||
| 93 | try expect(mem.eql(u8, first4KeysOfHomeRow(), "aoeu")); | ||
| 94 | } |
test/behavior/misc.zig-8| ... | @@ -5,14 +5,6 @@ const expectEqualStrings = std.testing.expectEqualStrings; | ... | @@ -5,14 +5,6 @@ const expectEqualStrings = std.testing.expectEqualStrings; |
| 5 | const mem = std.mem; | 5 | const mem = std.mem; |
| 6 | const builtin = @import("builtin"); | 6 | const builtin = @import("builtin"); |
| 7 | 7 | ||
| 8 | fn first4KeysOfHomeRow() []const u8 { | ||
| 9 | return "aoeu"; | ||
| 10 | } | ||
| 11 | |||
| 12 | test "return string from function" { | ||
| 13 | try expect(mem.eql(u8, first4KeysOfHomeRow(), "aoeu")); | ||
| 14 | } | ||
| 15 | |||
| 16 | test "memcpy and memset intrinsics" { | 8 | test "memcpy and memset intrinsics" { |
| 17 | var foo: [20]u8 = undefined; | 9 | var foo: [20]u8 = undefined; |
| 18 | var bar: [20]u8 = undefined; | 10 | var bar: [20]u8 = undefined; |