authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2021-10-19 15:08:28+02:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2021-10-20 03:44:02+02:00
logb65582e834de34f2351fa04a47f20e7f9c16a47c
tree903977d19050915584c568b9a6b04b57e0996d59
parentbfedf40c9267367d6ffdad54050dcbd451136b58

stage2: remove AstGen none_or_ref

The remaining uses of this result location were causing a bunch of errors problems where the pointers returned from rvalue and lvalue expressions would be confused, allowing for extra pointers on rvalue expressions. For example: ```zig const X = struct {a: i32}; var x: X = .{.a = 1}; var ptr = &x; _ = x.a; ``` In the last line, the lookup of x with result location .none_or_ref would return a double pointer (**X). This would be dereferenced one, after which a relative pointer to `a` would be fetched and derefenced to get the final result. However, this also allows us to manually construct a double pointer, and fetch the field of the inner type of that: ```zig _ = &(&(x)).a; ``` This problem also manifests itself with element access. There are two obvious ways to fix the problem, both of which include replacing the usage of .none_or_ref for field- and element accesses with something which deterministically produce either a pointer or value: either result location .ref or .none. In the former case, this would be paired with .elem_ptr, and in the latter case with .elem_val. Note that the stage 1 compiler does not have this problem, because there is no equivalent of .elem_val and .field_val. In this way it is equivalent to using the result location .ref for field- and element accesses. In this case i have used .none, as this matches language behaviour more closely.

1 files changed, 16 insertions(+), 21 deletions(-)

src/AstGen.zig+16-21
...@@ -193,9 +193,6 @@ pub const ResultLoc = union(enum) {...@@ -193,9 +193,6 @@ pub const ResultLoc = union(enum) {
193 /// The expression must generate a pointer rather than a value. For example, the left hand side193 /// The expression must generate a pointer rather than a value. For example, the left hand side
194 /// of an assignment uses this kind of result location.194 /// of an assignment uses this kind of result location.
195 ref,195 ref,
196 /// The callee will accept a ref, but it is not necessary, and the `ResultLoc`
197 /// may be treated as `none` instead.
198 none_or_ref,
199 /// The expression will be coerced into this type, but it will be evaluated as an rvalue.196 /// The expression will be coerced into this type, but it will be evaluated as an rvalue.
200 ty: Zir.Inst.Ref,197 ty: Zir.Inst.Ref,
201 /// Same as `ty` but it is guaranteed that Sema will additionally perform the coercion,198 /// Same as `ty` but it is guaranteed that Sema will additionally perform the coercion,
...@@ -231,7 +228,7 @@ pub const ResultLoc = union(enum) {...@@ -231,7 +228,7 @@ pub const ResultLoc = union(enum) {
231 fn strategy(rl: ResultLoc, block_scope: *GenZir) Strategy {228 fn strategy(rl: ResultLoc, block_scope: *GenZir) Strategy {
232 switch (rl) {229 switch (rl) {
233 // In this branch there will not be any store_to_block_ptr instructions.230 // In this branch there will not be any store_to_block_ptr instructions.
234 .discard, .none, .none_or_ref, .ty, .coerced_ty, .ref => return .{231 .discard, .none, .ty, .coerced_ty, .ref => return .{
235 .tag = .break_operand,232 .tag = .break_operand,
236 .elide_store_to_block_ptr_instructions = false,233 .elide_store_to_block_ptr_instructions = false,
237 },234 },
...@@ -727,7 +724,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr...@@ -727,7 +724,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
727 .start = start,724 .start = start,
728 });725 });
729 switch (rl) {726 switch (rl) {
730 .ref, .none_or_ref => return result,727 .ref => return result,
731 else => {728 else => {
732 const dereffed = try gz.addUnNode(.load, result, node);729 const dereffed = try gz.addUnNode(.load, result, node);
733 return rvalue(gz, rl, dereffed, node);730 return rvalue(gz, rl, dereffed, node);
...@@ -745,7 +742,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr...@@ -745,7 +742,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
745 .end = end,742 .end = end,
746 });743 });
747 switch (rl) {744 switch (rl) {
748 .ref, .none_or_ref => return result,745 .ref => return result,
749 else => {746 else => {
750 const dereffed = try gz.addUnNode(.load, result, node);747 const dereffed = try gz.addUnNode(.load, result, node);
751 return rvalue(gz, rl, dereffed, node);748 return rvalue(gz, rl, dereffed, node);
...@@ -765,7 +762,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr...@@ -765,7 +762,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
765 .sentinel = sentinel,762 .sentinel = sentinel,
766 });763 });
767 switch (rl) {764 switch (rl) {
768 .ref, .none_or_ref => return result,765 .ref => return result,
769 else => {766 else => {
770 const dereffed = try gz.addUnNode(.load, result, node);767 const dereffed = try gz.addUnNode(.load, result, node);
771 return rvalue(gz, rl, dereffed, node);768 return rvalue(gz, rl, dereffed, node);
...@@ -776,7 +773,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr...@@ -776,7 +773,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
776 .deref => {773 .deref => {
777 const lhs = try expr(gz, scope, .none, node_datas[node].lhs);774 const lhs = try expr(gz, scope, .none, node_datas[node].lhs);
778 switch (rl) {775 switch (rl) {
779 .ref, .none_or_ref => return lhs,776 .ref => return lhs,
780 else => {777 else => {
781 const result = try gz.addUnNode(.load, lhs, node);778 const result = try gz.addUnNode(.load, lhs, node);
782 return rvalue(gz, rl, result, node);779 return rvalue(gz, rl, result, node);
...@@ -1273,7 +1270,7 @@ fn arrayInitExpr(...@@ -1273,7 +1270,7 @@ fn arrayInitExpr(
1273 return arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon_ref);1270 return arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon_ref);
1274 }1271 }
1275 },1272 },
1276 .none, .none_or_ref => {1273 .none => {
1277 if (types.array != .none) {1274 if (types.array != .none) {
1278 return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, .array_init);1275 return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, .array_init);
1279 } else {1276 } else {
...@@ -1475,7 +1472,7 @@ fn structInitExpr(...@@ -1475,7 +1472,7 @@ fn structInitExpr(
1475 return structInitExprRlNone(gz, scope, node, struct_init, .struct_init_anon_ref);1472 return structInitExprRlNone(gz, scope, node, struct_init, .struct_init_anon_ref);
1476 }1473 }
1477 },1474 },
1478 .none, .none_or_ref => {1475 .none => {
1479 if (struct_init.ast.type_expr != 0) {1476 if (struct_init.ast.type_expr != 0) {
1480 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);1477 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
1481 return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init);1478 return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init);
...@@ -5133,7 +5130,7 @@ fn fieldAccess(...@@ -5133,7 +5130,7 @@ fn fieldAccess(
5133 if (rl == .ref) {5130 if (rl == .ref) {
5134 return addFieldAccess(.field_ptr, gz, scope, .ref, node);5131 return addFieldAccess(.field_ptr, gz, scope, .ref, node);
5135 } else {5132 } else {
5136 const access = try addFieldAccess(.field_val, gz, scope, .none_or_ref, node);5133 const access = try addFieldAccess(.field_val, gz, scope, .none, node);
5137 return rvalue(gz, rl, access, node);5134 return rvalue(gz, rl, access, node);
5138 }5135 }
5139}5136}
...@@ -5178,7 +5175,7 @@ fn arrayAccess(...@@ -5178,7 +5175,7 @@ fn arrayAccess(
5178 ),5175 ),
5179 else => return rvalue(gz, rl, try gz.addBin(5176 else => return rvalue(gz, rl, try gz.addBin(
5180 .elem_val,5177 .elem_val,
5181 try expr(gz, scope, .none_or_ref, node_datas[node].lhs),5178 try expr(gz, scope, .none, node_datas[node].lhs),
5182 try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].rhs),5179 try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].rhs),
5183 ), node),5180 ), node),
5184 }5181 }
...@@ -6664,7 +6661,7 @@ fn identifier(...@@ -6664,7 +6661,7 @@ fn identifier(
6664 );6661 );
66656662
6666 switch (rl) {6663 switch (rl) {
6667 .ref, .none_or_ref => return ptr_inst,6664 .ref => return ptr_inst,
6668 else => {6665 else => {
6669 const loaded = try gz.addUnNode(.load, ptr_inst, ident);6666 const loaded = try gz.addUnNode(.load, ptr_inst, ident);
6670 return rvalue(gz, rl, loaded, ident);6667 return rvalue(gz, rl, loaded, ident);
...@@ -6700,7 +6697,7 @@ fn identifier(...@@ -6700,7 +6697,7 @@ fn identifier(
6700 // Decl references happen by name rather than ZIR index so that when unrelated6697 // Decl references happen by name rather than ZIR index so that when unrelated
6701 // decls are modified, ZIR code containing references to them can be unmodified.6698 // decls are modified, ZIR code containing references to them can be unmodified.
6702 switch (rl) {6699 switch (rl) {
6703 .ref, .none_or_ref => return gz.addStrTok(.decl_ref, name_str_index, ident_token),6700 .ref => return gz.addStrTok(.decl_ref, name_str_index, ident_token),
6704 else => {6701 else => {
6705 const result = try gz.addStrTok(.decl_val, name_str_index, ident_token);6702 const result = try gz.addStrTok(.decl_val, name_str_index, ident_token);
6706 return rvalue(gz, rl, result, ident);6703 return rvalue(gz, rl, result, ident);
...@@ -7105,7 +7102,7 @@ fn as(...@@ -7105,7 +7102,7 @@ fn as(
7105) InnerError!Zir.Inst.Ref {7102) InnerError!Zir.Inst.Ref {
7106 const dest_type = try typeExpr(gz, scope, lhs);7103 const dest_type = try typeExpr(gz, scope, lhs);
7107 switch (rl) {7104 switch (rl) {
7108 .none, .none_or_ref, .discard, .ref, .ty, .coerced_ty => {7105 .none, .discard, .ref, .ty, .coerced_ty => {
7109 const result = try reachableExpr(gz, scope, .{ .ty = dest_type }, rhs, node);7106 const result = try reachableExpr(gz, scope, .{ .ty = dest_type }, rhs, node);
7110 return rvalue(gz, rl, result, node);7107 return rvalue(gz, rl, result, node);
7111 },7108 },
...@@ -7128,7 +7125,7 @@ fn unionInit(...@@ -7128,7 +7125,7 @@ fn unionInit(
7128 const union_type = try typeExpr(gz, scope, params[0]);7125 const union_type = try typeExpr(gz, scope, params[0]);
7129 const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]);7126 const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]);
7130 switch (rl) {7127 switch (rl) {
7131 .none, .none_or_ref, .discard, .ref, .ty, .coerced_ty, .inferred_ptr => {7128 .none, .discard, .ref, .ty, .coerced_ty, .inferred_ptr => {
7132 _ = try gz.addPlNode(.field_type_ref, params[1], Zir.Inst.FieldTypeRef{7129 _ = try gz.addPlNode(.field_type_ref, params[1], Zir.Inst.FieldTypeRef{
7133 .container_type = union_type,7130 .container_type = union_type,
7134 .field_name = field_name,7131 .field_name = field_name,
...@@ -7192,7 +7189,7 @@ fn bitCast(...@@ -7192,7 +7189,7 @@ fn bitCast(
7192 const astgen = gz.astgen;7189 const astgen = gz.astgen;
7193 const dest_type = try typeExpr(gz, scope, lhs);7190 const dest_type = try typeExpr(gz, scope, lhs);
7194 switch (rl) {7191 switch (rl) {
7195 .none, .none_or_ref, .discard, .ty, .coerced_ty => {7192 .none, .discard, .ty, .coerced_ty => {
7196 const operand = try expr(gz, scope, .none, rhs);7193 const operand = try expr(gz, scope, .none, rhs);
7197 const result = try gz.addPlNode(.bitcast, node, Zir.Inst.Bin{7194 const result = try gz.addPlNode(.bitcast, node, Zir.Inst.Bin{
7198 .lhs = dest_type,7195 .lhs = dest_type,
...@@ -8799,7 +8796,7 @@ fn rvalue(...@@ -8799,7 +8796,7 @@ fn rvalue(
8799) InnerError!Zir.Inst.Ref {8796) InnerError!Zir.Inst.Ref {
8800 if (gz.endsWithNoReturn()) return result;8797 if (gz.endsWithNoReturn()) return result;
8801 switch (rl) {8798 switch (rl) {
8802 .none, .none_or_ref, .coerced_ty => return result,8799 .none, .coerced_ty => return result,
8803 .discard => {8800 .discard => {
8804 // Emit a compile error for discarding error values.8801 // Emit a compile error for discarding error values.
8805 _ = try gz.addUnNode(.ensure_result_non_error, result, src_node);8802 _ = try gz.addUnNode(.ensure_result_non_error, result, src_node);
...@@ -9561,9 +9558,7 @@ const GenZir = struct {...@@ -9561,9 +9558,7 @@ const GenZir = struct {
9561 gz.rl_ty_inst = ty_inst;9558 gz.rl_ty_inst = ty_inst;
9562 gz.break_result_loc = parent_rl;9559 gz.break_result_loc = parent_rl;
9563 },9560 },
9564 .none_or_ref => {9561
9565 gz.break_result_loc = .ref;
9566 },
9567 .discard, .none, .ptr, .ref => {9562 .discard, .none, .ptr, .ref => {
9568 gz.break_result_loc = parent_rl;9563 gz.break_result_loc = parent_rl;
9569 },9564 },