| author | |
| committer | |
| log | cc3336c7841c48622db855be95a79bbd030bade8 |
| tree | 61e33f1add4655dcc28a25c239d5da27477be0e6 |
| parent | 979910dc38cd15e506218d5175e5a91f56244055 |
12 files changed, 97 insertions(+), 69 deletions(-)
src/AstGen.zig+5-4| ... | @@ -1476,7 +1476,7 @@ fn arrayInitExprRlPtr( | ... | @@ -1476,7 +1476,7 @@ fn arrayInitExprRlPtr( |
| 1476 | return arrayInitExprRlPtrInner(gz, scope, node, base_ptr, elements); | 1476 | return arrayInitExprRlPtrInner(gz, scope, node, base_ptr, elements); |
| 1477 | } | 1477 | } |
| 1478 | 1478 | ||
| 1479 | var as_scope = try gz.makeCoercionScope(scope, array_ty, result_ptr); | 1479 | var as_scope = try gz.makeCoercionScope(scope, array_ty, result_ptr, node); |
| 1480 | defer as_scope.unstack(); | 1480 | defer as_scope.unstack(); |
| 1481 | 1481 | ||
| 1482 | const result = try arrayInitExprRlPtrInner(&as_scope, scope, node, as_scope.rl_ptr, elements); | 1482 | const result = try arrayInitExprRlPtrInner(&as_scope, scope, node, as_scope.rl_ptr, elements); |
| ... | @@ -1697,7 +1697,7 @@ fn structInitExprRlPtr( | ... | @@ -1697,7 +1697,7 @@ fn structInitExprRlPtr( |
| 1697 | const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); | 1697 | const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); |
| 1698 | _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node); | 1698 | _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node); |
| 1699 | 1699 | ||
| 1700 | var as_scope = try gz.makeCoercionScope(scope, ty_inst, result_ptr); | 1700 | var as_scope = try gz.makeCoercionScope(scope, ty_inst, result_ptr, node); |
| 1701 | defer as_scope.unstack(); | 1701 | defer as_scope.unstack(); |
| 1702 | 1702 | ||
| 1703 | const result = try structInitExprRlPtrInner(&as_scope, scope, node, struct_init, as_scope.rl_ptr); | 1703 | const result = try structInitExprRlPtrInner(&as_scope, scope, node, struct_init, as_scope.rl_ptr); |
| ... | @@ -7046,7 +7046,7 @@ fn asRlPtr( | ... | @@ -7046,7 +7046,7 @@ fn asRlPtr( |
| 7046 | operand_node: Ast.Node.Index, | 7046 | operand_node: Ast.Node.Index, |
| 7047 | dest_type: Zir.Inst.Ref, | 7047 | dest_type: Zir.Inst.Ref, |
| 7048 | ) InnerError!Zir.Inst.Ref { | 7048 | ) InnerError!Zir.Inst.Ref { |
| 7049 | var as_scope = try parent_gz.makeCoercionScope(scope, dest_type, result_ptr); | 7049 | var as_scope = try parent_gz.makeCoercionScope(scope, dest_type, result_ptr, src_node); |
| 7050 | defer as_scope.unstack(); | 7050 | defer as_scope.unstack(); |
| 7051 | 7051 | ||
| 7052 | const result = try reachableExpr(&as_scope, &as_scope.base, .{ .block_ptr = &as_scope }, operand_node, src_node); | 7052 | const result = try reachableExpr(&as_scope, &as_scope.base, .{ .block_ptr = &as_scope }, operand_node, src_node); |
| ... | @@ -9903,13 +9903,14 @@ const GenZir = struct { | ... | @@ -9903,13 +9903,14 @@ const GenZir = struct { |
| 9903 | scope: *Scope, | 9903 | scope: *Scope, |
| 9904 | dest_type: Zir.Inst.Ref, | 9904 | dest_type: Zir.Inst.Ref, |
| 9905 | result_ptr: Zir.Inst.Ref, | 9905 | result_ptr: Zir.Inst.Ref, |
| 9906 | src_node: Ast.Node.Index, | ||
| 9906 | ) !GenZir { | 9907 | ) !GenZir { |
| 9907 | // Detect whether this expr() call goes into rvalue() to store the result into the | 9908 | // Detect whether this expr() call goes into rvalue() to store the result into the |
| 9908 | // result location. If it does, elide the coerce_result_ptr instruction | 9909 | // result location. If it does, elide the coerce_result_ptr instruction |
| 9909 | // as well as the store instruction, instead passing the result as an rvalue. | 9910 | // as well as the store instruction, instead passing the result as an rvalue. |
| 9910 | var as_scope = parent_gz.makeSubBlock(scope); | 9911 | var as_scope = parent_gz.makeSubBlock(scope); |
| 9911 | errdefer as_scope.unstack(); | 9912 | errdefer as_scope.unstack(); |
| 9912 | as_scope.rl_ptr = try as_scope.addBin(.coerce_result_ptr, dest_type, result_ptr); | 9913 | as_scope.rl_ptr = try as_scope.addPlNode(.coerce_result_ptr, src_node, Zir.Inst.Bin{ .lhs = dest_type, .rhs = result_ptr }); |
| 9913 | 9914 | ||
| 9914 | // `rl_ty_inst` needs to be set in case the stores to `rl_ptr` are eliminated. | 9915 | // `rl_ty_inst` needs to be set in case the stores to `rl_ptr` are eliminated. |
| 9915 | as_scope.rl_ty_inst = dest_type; | 9916 | as_scope.rl_ty_inst = dest_type; |
src/Sema.zig+36-7| ... | @@ -1913,10 +1913,11 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE | ... | @@ -1913,10 +1913,11 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE |
| 1913 | const tracy = trace(@src()); | 1913 | const tracy = trace(@src()); |
| 1914 | defer tracy.end(); | 1914 | defer tracy.end(); |
| 1915 | 1915 | ||
| 1916 | const src: LazySrcLoc = sema.src; | 1916 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 1917 | const bin_inst = sema.code.instructions.items(.data)[inst].bin; | 1917 | const src = inst_data.src(); |
| 1918 | const pointee_ty = try sema.resolveType(block, src, bin_inst.lhs); | 1918 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 1919 | const ptr = try sema.resolveInst(bin_inst.rhs); | 1919 | const pointee_ty = try sema.resolveType(block, src, extra.lhs); |
| 1920 | const ptr = try sema.resolveInst(extra.rhs); | ||
| 1920 | const target = sema.mod.getTarget(); | 1921 | const target = sema.mod.getTarget(); |
| 1921 | const addr_space = target_util.defaultAddressSpace(target, .local); | 1922 | const addr_space = target_util.defaultAddressSpace(target, .local); |
| 1922 | 1923 | ||
| ... | @@ -10143,7 +10144,10 @@ fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. | ... | @@ -10143,7 +10144,10 @@ fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 10143 | const rhs_ty = sema.typeOf(rhs); | 10144 | const rhs_ty = sema.typeOf(rhs); |
| 10144 | const rhs_scalar_ty = rhs_ty.scalarType(); | 10145 | const rhs_scalar_ty = rhs_ty.scalarType(); |
| 10145 | 10146 | ||
| 10146 | if (rhs_scalar_ty.isUnsignedInt()) { | 10147 | if (rhs_scalar_ty.isUnsignedInt() or switch (rhs_scalar_ty.zigTypeTag()) { |
| 10148 | .Int, .ComptimeInt, .Float, .ComptimeFloat => false, | ||
| 10149 | else => true, | ||
| 10150 | }) { | ||
| 10147 | return sema.fail(block, src, "negation of type '{}'", .{rhs_ty.fmt(sema.mod)}); | 10151 | return sema.fail(block, src, "negation of type '{}'", .{rhs_ty.fmt(sema.mod)}); |
| 10148 | } | 10152 | } |
| 10149 | 10153 | ||
| ... | @@ -10172,6 +10176,12 @@ fn zirNegateWrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! | ... | @@ -10172,6 +10176,12 @@ fn zirNegateWrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 10172 | 10176 | ||
| 10173 | const rhs = try sema.resolveInst(inst_data.operand); | 10177 | const rhs = try sema.resolveInst(inst_data.operand); |
| 10174 | const rhs_ty = sema.typeOf(rhs); | 10178 | const rhs_ty = sema.typeOf(rhs); |
| 10179 | const rhs_scalar_ty = rhs_ty.scalarType(); | ||
| 10180 | |||
| 10181 | switch (rhs_scalar_ty.zigTypeTag()) { | ||
| 10182 | .Int, .ComptimeInt, .Float, .ComptimeFloat => {}, | ||
| 10183 | else => return sema.fail(block, src, "negation of type '{}'", .{rhs_ty.fmt(sema.mod)}), | ||
| 10184 | } | ||
| 10175 | 10185 | ||
| 10176 | const lhs = if (rhs_ty.zigTypeTag() == .Vector) | 10186 | const lhs = if (rhs_ty.zigTypeTag() == .Vector) |
| 10177 | try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, Value.zero)) | 10187 | try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, Value.zero)) |
| ... | @@ -17886,7 +17896,8 @@ fn validateRunTimeType( | ... | @@ -17886,7 +17896,8 @@ fn validateRunTimeType( |
| 17886 | .Pointer => { | 17896 | .Pointer => { |
| 17887 | const elem_ty = ty.childType(); | 17897 | const elem_ty = ty.childType(); |
| 17888 | switch (elem_ty.zigTypeTag()) { | 17898 | switch (elem_ty.zigTypeTag()) { |
| 17889 | .Opaque, .Fn => return true, | 17899 | .Opaque => return true, |
| 17900 | .Fn => return elem_ty.isFnOrHasRuntimeBits(), | ||
| 17890 | else => ty = elem_ty, | 17901 | else => ty = elem_ty, |
| 17891 | } | 17902 | } |
| 17892 | }, | 17903 | }, |
| ... | @@ -17950,7 +17961,25 @@ fn explainWhyTypeIsComptime( | ... | @@ -17950,7 +17961,25 @@ fn explainWhyTypeIsComptime( |
| 17950 | .Optional, | 17961 | .Optional, |
| 17951 | => return, | 17962 | => return, |
| 17952 | 17963 | ||
| 17953 | .Pointer, .Array, .Vector => { | 17964 | .Array, .Vector => { |
| 17965 | try sema.explainWhyTypeIsComptime(block, src, msg, src_loc, ty.elemType()); | ||
| 17966 | }, | ||
| 17967 | .Pointer => { | ||
| 17968 | const elem_ty = ty.elemType2(); | ||
| 17969 | if (elem_ty.zigTypeTag() == .Fn) { | ||
| 17970 | const fn_info = elem_ty.fnInfo(); | ||
| 17971 | if (fn_info.is_generic) { | ||
| 17972 | try mod.errNoteNonLazy(src_loc, msg, "function is generic", .{}); | ||
| 17973 | } | ||
| 17974 | switch (fn_info.cc) { | ||
| 17975 | .Inline => try mod.errNoteNonLazy(src_loc, msg, "function has inline calling convention", .{}), | ||
| 17976 | else => {}, | ||
| 17977 | } | ||
| 17978 | if (fn_info.return_type.comptimeOnly()) { | ||
| 17979 | try mod.errNoteNonLazy(src_loc, msg, "function has a comptime-only return type", .{}); | ||
| 17980 | } | ||
| 17981 | return; | ||
| 17982 | } | ||
| 17954 | try sema.explainWhyTypeIsComptime(block, src, msg, src_loc, ty.elemType()); | 17983 | try sema.explainWhyTypeIsComptime(block, src, msg, src_loc, ty.elemType()); |
| 17955 | }, | 17984 | }, |
| 17956 | 17985 |
src/Zir.zig+2-2| ... | @@ -308,7 +308,7 @@ pub const Inst = struct { | ... | @@ -308,7 +308,7 @@ pub const Inst = struct { |
| 308 | cmp_neq, | 308 | cmp_neq, |
| 309 | /// Coerces a result location pointer to a new element type. It is evaluated "backwards"- | 309 | /// Coerces a result location pointer to a new element type. It is evaluated "backwards"- |
| 310 | /// as type coercion from the new element type to the old element type. | 310 | /// as type coercion from the new element type to the old element type. |
| 311 | /// Uses the `bin` union field. | 311 | /// Uses the `pl_node` union field. Payload is `Bin`. |
| 312 | /// LHS is destination element type, RHS is result pointer. | 312 | /// LHS is destination element type, RHS is result pointer. |
| 313 | coerce_result_ptr, | 313 | coerce_result_ptr, |
| 314 | /// Conditional branch. Splits control flow based on a boolean condition value. | 314 | /// Conditional branch. Splits control flow based on a boolean condition value. |
| ... | @@ -1603,7 +1603,7 @@ pub const Inst = struct { | ... | @@ -1603,7 +1603,7 @@ pub const Inst = struct { |
| 1603 | .cmp_gte = .pl_node, | 1603 | .cmp_gte = .pl_node, |
| 1604 | .cmp_gt = .pl_node, | 1604 | .cmp_gt = .pl_node, |
| 1605 | .cmp_neq = .pl_node, | 1605 | .cmp_neq = .pl_node, |
| 1606 | .coerce_result_ptr = .bin, | 1606 | .coerce_result_ptr = .pl_node, |
| 1607 | .condbr = .pl_node, | 1607 | .condbr = .pl_node, |
| 1608 | .condbr_inline = .pl_node, | 1608 | .condbr_inline = .pl_node, |
| 1609 | .@"try" = .pl_node, | 1609 | .@"try" = .pl_node, |
src/print_zir.zig+1-1| ... | @@ -144,7 +144,6 @@ const Writer = struct { | ... | @@ -144,7 +144,6 @@ const Writer = struct { |
| 144 | switch (tag) { | 144 | switch (tag) { |
| 145 | .array_type, | 145 | .array_type, |
| 146 | .as, | 146 | .as, |
| 147 | .coerce_result_ptr, | ||
| 148 | .elem_ptr, | 147 | .elem_ptr, |
| 149 | .elem_val, | 148 | .elem_val, |
| 150 | .store, | 149 | .store, |
| ... | @@ -355,6 +354,7 @@ const Writer = struct { | ... | @@ -355,6 +354,7 @@ const Writer = struct { |
| 355 | .minimum, | 354 | .minimum, |
| 356 | .elem_ptr_node, | 355 | .elem_ptr_node, |
| 357 | .elem_val_node, | 356 | .elem_val_node, |
| 357 | .coerce_result_ptr, | ||
| 358 | => try self.writePlNodeBin(stream, inst), | 358 | => try self.writePlNodeBin(stream, inst), |
| 359 | 359 | ||
| 360 | .elem_ptr_imm => try self.writeElemPtrImm(stream, inst), | 360 | .elem_ptr_imm => try self.writeElemPtrImm(stream, inst), |
test/cases/compile_errors/assign_inline_fn_to_non-comptime_var.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | export fn entry() void { | ||
| 2 | var a = &b; | ||
| 3 | _ = a; | ||
| 4 | } | ||
| 5 | fn b() callconv(.Inline) void { } | ||
| 6 | |||
| 7 | // error | ||
| 8 | // backend=stage2 | ||
| 9 | // target=native | ||
| 10 | // | ||
| 11 | // :2:9: error: variable of type '*const fn() callconv(.Inline) void' must be const or comptime | ||
| 12 | // :2:9: note: function has inline calling convention | ||
test/cases/compile_errors/attempt_to_negate_a_non-integer_non-float_or_non-vector_type.zig created+14| ... | @@ -0,0 +1,14 @@ | ||
| 1 | fn foo() anyerror!u32 { | ||
| 2 | return 1; | ||
| 3 | } | ||
| 4 | |||
| 5 | export fn entry() void { | ||
| 6 | const x = -foo(); | ||
| 7 | _ = x; | ||
| 8 | } | ||
| 9 | |||
| 10 | // error | ||
| 11 | // backend=stage2 | ||
| 12 | // target=native | ||
| 13 | // | ||
| 14 | // :6:15: error: negation of type 'anyerror!u32' | ||
test/cases/compile_errors/reassign_to_array_parameter.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | fn reassign(a: [3]f32) void { | ||
| 2 | a = [3]f32{4, 5, 6}; | ||
| 3 | } | ||
| 4 | export fn entry() void { | ||
| 5 | reassign(.{1, 2, 3}); | ||
| 6 | } | ||
| 7 | |||
| 8 | // error | ||
| 9 | // backend=stage2 | ||
| 10 | // target=native | ||
| 11 | // | ||
| 12 | // :2:15: error: cannot assign to constant | ||
test/cases/compile_errors/reassign_to_struct_parameter.zig created+15| ... | @@ -0,0 +1,15 @@ | ||
| 1 | const S = struct { | ||
| 2 | x: u32, | ||
| 3 | }; | ||
| 4 | fn reassign(s: S) void { | ||
| 5 | s = S{.x = 2}; | ||
| 6 | } | ||
| 7 | export fn entry() void { | ||
| 8 | reassign(S{.x = 3}); | ||
| 9 | } | ||
| 10 | |||
| 11 | // error | ||
| 12 | // backend=stage2 | ||
| 13 | // target=native | ||
| 14 | // | ||
| 15 | // :5:10: error: cannot assign to constant | ||
test/cases/compile_errors/stage1/obj/assign_inline_fn_to_non-comptime_var.zig deleted-12| ... | @@ -1,12 +0,0 @@ | ||
| 1 | export fn entry() void { | ||
| 2 | var a = b; | ||
| 3 | _ = a; | ||
| 4 | } | ||
| 5 | fn b() callconv(.Inline) void { } | ||
| 6 | |||
| 7 | // error | ||
| 8 | // backend=stage1 | ||
| 9 | // target=native | ||
| 10 | // | ||
| 11 | // tmp.zig:2:5: error: functions marked inline must be stored in const or comptime var | ||
| 12 | // tmp.zig:5:1: note: declared here | ||
test/cases/compile_errors/stage1/obj/attempt_to_negate_a_non-integer_non-float_or_non-vector_type.zig deleted-14| ... | @@ -1,14 +0,0 @@ | ||
| 1 | fn foo() anyerror!u32 { | ||
| 2 | return 1; | ||
| 3 | } | ||
| 4 | |||
| 5 | export fn entry() void { | ||
| 6 | const x = -foo(); | ||
| 7 | _ = x; | ||
| 8 | } | ||
| 9 | |||
| 10 | // error | ||
| 11 | // backend=stage1 | ||
| 12 | // target=native | ||
| 13 | // | ||
| 14 | // tmp.zig:6:15: error: negation of type 'anyerror!u32' | ||
test/cases/compile_errors/stage1/test/reassign_to_array_parameter.zig deleted-13| ... | @@ -1,13 +0,0 @@ | ||
| 1 | fn reassign(a: [3]f32) void { | ||
| 2 | a = [3]f32{4, 5, 6}; | ||
| 3 | } | ||
| 4 | export fn entry() void { | ||
| 5 | reassign(.{1, 2, 3}); | ||
| 6 | } | ||
| 7 | |||
| 8 | // error | ||
| 9 | // backend=stage1 | ||
| 10 | // target=native | ||
| 11 | // is_test=1 | ||
| 12 | // | ||
| 13 | // tmp.zig:2:15: error: cannot assign to constant | ||
test/cases/compile_errors/stage1/test/reassign_to_struct_parameter.zig deleted-16| ... | @@ -1,16 +0,0 @@ | ||
| 1 | const S = struct { | ||
| 2 | x: u32, | ||
| 3 | }; | ||
| 4 | fn reassign(s: S) void { | ||
| 5 | s = S{.x = 2}; | ||
| 6 | } | ||
| 7 | export fn entry() void { | ||
| 8 | reassign(S{.x = 3}); | ||
| 9 | } | ||
| 10 | |||
| 11 | // error | ||
| 12 | // backend=stage1 | ||
| 13 | // target=native | ||
| 14 | // is_test=1 | ||
| 15 | // | ||
| 16 | // tmp.zig:5:10: error: cannot assign to constant | ||