| author | |
| committer | |
| log | bf014d529a8373d43f92b0dd5c8a5d8509150ca9 |
| tree | 483a07e52b3149709935323092268acf86163fd2 |
| parent | bcd04089ebf563659972c1a0fe1864521b128d37 |
4 files changed, 54 insertions(+), 8 deletions(-)
src-self-hosted/astgen.zig+11-1| ... | @@ -274,6 +274,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr | ... | @@ -274,6 +274,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr |
| 274 | .ErrorSetDecl => return errorSetDecl(mod, scope, rl, node.castTag(.ErrorSetDecl).?), | 274 | .ErrorSetDecl => return errorSetDecl(mod, scope, rl, node.castTag(.ErrorSetDecl).?), |
| 275 | .ErrorType => return rlWrap(mod, scope, rl, try errorType(mod, scope, node.castTag(.ErrorType).?)), | 275 | .ErrorType => return rlWrap(mod, scope, rl, try errorType(mod, scope, node.castTag(.ErrorType).?)), |
| 276 | .For => return forExpr(mod, scope, rl, node.castTag(.For).?), | 276 | .For => return forExpr(mod, scope, rl, node.castTag(.For).?), |
| 277 | .ArrayAccess => return arrayAccess(mod, scope, rl, node.castTag(.ArrayAccess).?), | ||
| 277 | 278 | ||
| 278 | .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}), | 279 | .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}), |
| 279 | .Catch => return mod.failNode(scope, node, "TODO implement astgen.expr for .Catch", .{}), | 280 | .Catch => return mod.failNode(scope, node, "TODO implement astgen.expr for .Catch", .{}), |
| ... | @@ -283,7 +284,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr | ... | @@ -283,7 +284,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr |
| 283 | .Resume => return mod.failNode(scope, node, "TODO implement astgen.expr for .Resume", .{}), | 284 | .Resume => return mod.failNode(scope, node, "TODO implement astgen.expr for .Resume", .{}), |
| 284 | .Try => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}), | 285 | .Try => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}), |
| 285 | .Slice => return mod.failNode(scope, node, "TODO implement astgen.expr for .Slice", .{}), | 286 | .Slice => return mod.failNode(scope, node, "TODO implement astgen.expr for .Slice", .{}), |
| 286 | .ArrayAccess => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayAccess", .{}), | ||
| 287 | .ArrayInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayInitializer", .{}), | 287 | .ArrayInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayInitializer", .{}), |
| 288 | .ArrayInitializerDot => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayInitializerDot", .{}), | 288 | .ArrayInitializerDot => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayInitializerDot", .{}), |
| 289 | .StructInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .StructInitializer", .{}), | 289 | .StructInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .StructInitializer", .{}), |
| ... | @@ -797,6 +797,16 @@ fn field(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleInfix | ... | @@ -797,6 +797,16 @@ fn field(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleInfix |
| 797 | return rlWrapPtr(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.FieldPtr, .{ .object_ptr = lhs, .field_name = field_name }, .{})); | 797 | return rlWrapPtr(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.FieldPtr, .{ .object_ptr = lhs, .field_name = field_name }, .{})); |
| 798 | } | 798 | } |
| 799 | 799 | ||
| 800 | fn arrayAccess(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.ArrayAccess) InnerError!*zir.Inst { | ||
| 801 | const tree = scope.tree(); | ||
| 802 | const src = tree.token_locs[node.rtoken].start; | ||
| 803 | |||
| 804 | const array_ptr = try expr(mod, scope, .ref, node.lhs); | ||
| 805 | const index = try expr(mod, scope, .none, node.index_expr); | ||
| 806 | |||
| 807 | return rlWrapPtr(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.ElemPtr, .{ .array_ptr = array_ptr, .index = index }, .{})); | ||
| 808 | } | ||
| 809 | |||
| 800 | fn deref(mod: *Module, scope: *Scope, node: *ast.Node.SimpleSuffixOp) InnerError!*zir.Inst { | 810 | fn deref(mod: *Module, scope: *Scope, node: *ast.Node.SimpleSuffixOp) InnerError!*zir.Inst { |
| 801 | const tree = scope.tree(); | 811 | const tree = scope.tree(); |
| 802 | const src = tree.token_locs[node.rtoken].start; | 812 | const src = tree.token_locs[node.rtoken].start; |
src-self-hosted/zir_sema.zig+13-3| ... | @@ -1076,9 +1076,19 @@ fn analyzeInstElemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inne | ... | @@ -1076,9 +1076,19 @@ fn analyzeInstElemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inne |
| 1076 | const array_ptr = try resolveInst(mod, scope, inst.positionals.array_ptr); | 1076 | const array_ptr = try resolveInst(mod, scope, inst.positionals.array_ptr); |
| 1077 | const uncasted_index = try resolveInst(mod, scope, inst.positionals.index); | 1077 | const uncasted_index = try resolveInst(mod, scope, inst.positionals.index); |
| 1078 | const elem_index = try mod.coerce(scope, Type.initTag(.usize), uncasted_index); | 1078 | const elem_index = try mod.coerce(scope, Type.initTag(.usize), uncasted_index); |
| 1079 | |||
| 1080 | const elem_ty = switch (array_ptr.ty.zigTypeTag()) { | ||
| 1081 | .Pointer => array_ptr.ty.elemType(), | ||
| 1082 | else => return mod.fail(scope, inst.positionals.array_ptr.src, "expected pointer, found '{}'", .{array_ptr.ty}), | ||
| 1083 | }; | ||
| 1084 | if (!elem_ty.isIndexable()) { | ||
| 1085 | return mod.fail(scope, inst.base.src, "array access of non-array type '{}'", .{elem_ty}); | ||
| 1086 | } | ||
| 1079 | 1087 | ||
| 1080 | if (array_ptr.ty.isSinglePointer() and array_ptr.ty.elemType().zigTypeTag() == .Array) { | 1088 | if (elem_ty.isSinglePointer() and elem_ty.elemType().zigTypeTag() == .Array) { |
| 1081 | if (array_ptr.value()) |array_ptr_val| { | 1089 | // we have to deref the ptr operand to get the actual array pointer |
| 1090 | const array_ptr_deref = try mod.analyzeDeref(scope, inst.base.src, array_ptr, inst.positionals.array_ptr.src); | ||
| 1091 | if (array_ptr_deref.value()) |array_ptr_val| { | ||
| 1082 | if (elem_index.value()) |index_val| { | 1092 | if (elem_index.value()) |index_val| { |
| 1083 | // Both array pointer and index are compile-time known. | 1093 | // Both array pointer and index are compile-time known. |
| 1084 | const index_u64 = index_val.toUnsignedInt(); | 1094 | const index_u64 = index_val.toUnsignedInt(); |
| ... | @@ -1089,7 +1099,7 @@ fn analyzeInstElemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inne | ... | @@ -1089,7 +1099,7 @@ fn analyzeInstElemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inne |
| 1089 | const type_payload = try scope.arena().create(Type.Payload.PointerSimple); | 1099 | const type_payload = try scope.arena().create(Type.Payload.PointerSimple); |
| 1090 | type_payload.* = .{ | 1100 | type_payload.* = .{ |
| 1091 | .base = .{ .tag = .single_const_pointer }, | 1101 | .base = .{ .tag = .single_const_pointer }, |
| 1092 | .pointee_type = array_ptr.ty.elemType().elemType(), | 1102 | .pointee_type = elem_ty.elemType().elemType(), |
| 1093 | }; | 1103 | }; |
| 1094 | 1104 | ||
| 1095 | return mod.constInst(scope, inst.base.src, .{ | 1105 | return mod.constInst(scope, inst.base.src, .{ |
test/stage2/test.zig+25| ... | @@ -820,6 +820,31 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -820,6 +820,31 @@ pub fn addCases(ctx: *TestContext) !void { |
| 820 | , | 820 | , |
| 821 | "", | 821 | "", |
| 822 | ); | 822 | ); |
| 823 | |||
| 824 | // Array access. | ||
| 825 | case.addCompareOutput( | ||
| 826 | \\export fn _start() noreturn { | ||
| 827 | \\ assert("hello"[0] == 'h'); | ||
| 828 | \\ | ||
| 829 | \\ exit(); | ||
| 830 | \\} | ||
| 831 | \\ | ||
| 832 | \\pub fn assert(ok: bool) void { | ||
| 833 | \\ if (!ok) unreachable; // assertion failure | ||
| 834 | \\} | ||
| 835 | \\ | ||
| 836 | \\fn exit() noreturn { | ||
| 837 | \\ asm volatile ("syscall" | ||
| 838 | \\ : | ||
| 839 | \\ : [number] "{rax}" (231), | ||
| 840 | \\ [arg1] "{rdi}" (0) | ||
| 841 | \\ : "rcx", "r11", "memory" | ||
| 842 | \\ ); | ||
| 843 | \\ unreachable; | ||
| 844 | \\} | ||
| 845 | , | ||
| 846 | "", | ||
| 847 | ); | ||
| 823 | } | 848 | } |
| 824 | 849 | ||
| 825 | { | 850 | { |
test/stage2/zir.zig+5-4| ... | @@ -43,10 +43,11 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -43,10 +43,11 @@ pub fn addCases(ctx: *TestContext) !void { |
| 43 | \\ | 43 | \\ |
| 44 | \\@entry = fn(@fnty, { | 44 | \\@entry = fn(@fnty, { |
| 45 | \\ %a = str("\x32\x08\x01\x0a") | 45 | \\ %a = str("\x32\x08\x01\x0a") |
| 46 | \\ %eptr0 = elemptr(%a, @0) | 46 | \\ %a_ref = ref(%a) |
| 47 | \\ %eptr1 = elemptr(%a, @1) | 47 | \\ %eptr0 = elemptr(%a_ref, @0) |
| 48 | \\ %eptr2 = elemptr(%a, @2) | 48 | \\ %eptr1 = elemptr(%a_ref, @1) |
| 49 | \\ %eptr3 = elemptr(%a, @3) | 49 | \\ %eptr2 = elemptr(%a_ref, @2) |
| 50 | \\ %eptr3 = elemptr(%a_ref, @3) | ||
| 50 | \\ %v0 = deref(%eptr0) | 51 | \\ %v0 = deref(%eptr0) |
| 51 | \\ %v1 = deref(%eptr1) | 52 | \\ %v1 = deref(%eptr1) |
| 52 | \\ %v2 = deref(%eptr2) | 53 | \\ %v2 = deref(%eptr2) |