authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-10-18 13:11:35+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-10-20 20:11:00+03:00
log34e4b07d0c3cafd0aad15b217e8c56ab9af5de40
treedd705ac25d93cdaa0d2aadfac0c2cfba9e670262
parent13897be0abfeddf7bdfbdc1600bd8279c26004de

Sema: allow runtime only instructions to be emitted in outside functions

It is possible to get comptime-known values from runtime-known values for example the length of array. Allowing runtime only instructions to be emitted outside function bodies allows these operations to happen. In places where comptime-known values are required we have other methods to ensure that and they usually result in more specific compile errors too. Closes #12240

10 files changed, 37 insertions(+), 68 deletions(-)

src/Sema.zig+5-41
...@@ -1237,9 +1237,6 @@ fn analyzeBodyInner(...@@ -1237,9 +1237,6 @@ fn analyzeBodyInner(
1237 i = 0;1237 i = 0;
1238 continue;1238 continue;
1239 } else {1239 } else {
1240 const src_node = sema.code.instructions.items(.data)[inst].node;
1241 const src = LazySrcLoc.nodeOffset(src_node);
1242 try sema.requireFunctionBlock(block, src);
1243 break always_noreturn;1240 break always_noreturn;
1244 }1241 }
1245 },1242 },
...@@ -2188,7 +2185,6 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE...@@ -2188,7 +2185,6 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
2188 defer trash_block.instructions.deinit(sema.gpa);2185 defer trash_block.instructions.deinit(sema.gpa);
2189 const operand = try trash_block.addBitCast(pointee_ty, .void_value);2186 const operand = try trash_block.addBitCast(pointee_ty, .void_value);
21902187
2191 try sema.requireFunctionBlock(block, src);
2192 const ptr_ty = try Type.ptr(sema.arena, sema.mod, .{2188 const ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
2193 .pointee_type = pointee_ty,2189 .pointee_type = pointee_ty,
2194 .@"align" = inferred_alloc.alignment,2190 .@"align" = inferred_alloc.alignment,
...@@ -3221,7 +3217,6 @@ fn zirAllocExtended(...@@ -3221,7 +3217,6 @@ fn zirAllocExtended(
3221 try sema.validateVarType(block, ty_src, var_ty, false);3217 try sema.validateVarType(block, ty_src, var_ty, false);
3222 }3218 }
3223 const target = sema.mod.getTarget();3219 const target = sema.mod.getTarget();
3224 try sema.requireFunctionBlock(block, src);
3225 try sema.resolveTypeLayout(block, src, var_ty);3220 try sema.resolveTypeLayout(block, src, var_ty);
3226 const ptr_type = try Type.ptr(sema.arena, sema.mod, .{3221 const ptr_type = try Type.ptr(sema.arena, sema.mod, .{
3227 .pointee_type = var_ty,3222 .pointee_type = var_ty,
...@@ -3239,7 +3234,6 @@ fn zirAllocExtended(...@@ -3239,7 +3234,6 @@ fn zirAllocExtended(
3239 inferred_alloc_ty,3234 inferred_alloc_ty,
3240 try Value.Tag.inferred_alloc.create(sema.arena, .{ .alignment = alignment }),3235 try Value.Tag.inferred_alloc.create(sema.arena, .{ .alignment = alignment }),
3241 );3236 );
3242 try sema.requireFunctionBlock(block, src);
3243 try block.instructions.append(sema.gpa, Air.refToIndex(result).?);3237 try block.instructions.append(sema.gpa, Air.refToIndex(result).?);
3244 try sema.unresolved_inferred_allocs.putNoClobber(sema.gpa, Air.refToIndex(result).?, {});3238 try sema.unresolved_inferred_allocs.putNoClobber(sema.gpa, Air.refToIndex(result).?, {});
3245 return result;3239 return result;
...@@ -3321,7 +3315,6 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro...@@ -3321,7 +3315,6 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
3321 return sema.addConstant(const_ptr_ty, val);3315 return sema.addConstant(const_ptr_ty, val);
3322 }3316 }
33233317
3324 try sema.requireFunctionBlock(block, src);
3325 return block.addBitCast(const_ptr_ty, alloc);3318 return block.addBitCast(const_ptr_ty, alloc);
3326}3319}
33273320
...@@ -3348,7 +3341,6 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I...@@ -3348,7 +3341,6 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
33483341
3349 const inst_data = sema.code.instructions.items(.data)[inst].un_node;3342 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
3350 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };3343 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
3351 const var_decl_src = inst_data.src();
3352 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);3344 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
3353 if (block.is_comptime) {3345 if (block.is_comptime) {
3354 return sema.analyzeComptimeAlloc(block, var_ty, 0, ty_src);3346 return sema.analyzeComptimeAlloc(block, var_ty, 0, ty_src);
...@@ -3358,7 +3350,6 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I...@@ -3358,7 +3350,6 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
3358 .pointee_type = var_ty,3350 .pointee_type = var_ty,
3359 .@"addrspace" = target_util.defaultAddressSpace(target, .local),3351 .@"addrspace" = target_util.defaultAddressSpace(target, .local),
3360 });3352 });
3361 try sema.requireFunctionBlock(block, var_decl_src);
3362 try sema.queueFullTypeResolution(var_ty);3353 try sema.queueFullTypeResolution(var_ty);
3363 return block.addTy(.alloc, ptr_type);3354 return block.addTy(.alloc, ptr_type);
3364}3355}
...@@ -3368,7 +3359,6 @@ fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -3368,7 +3359,6 @@ fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
3368 defer tracy.end();3359 defer tracy.end();
33693360
3370 const inst_data = sema.code.instructions.items(.data)[inst].un_node;3361 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
3371 const var_decl_src = inst_data.src();
3372 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };3362 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
3373 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);3363 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
3374 if (block.is_comptime) {3364 if (block.is_comptime) {
...@@ -3380,7 +3370,6 @@ fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -3380,7 +3370,6 @@ fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
3380 .pointee_type = var_ty,3370 .pointee_type = var_ty,
3381 .@"addrspace" = target_util.defaultAddressSpace(target, .local),3371 .@"addrspace" = target_util.defaultAddressSpace(target, .local),
3382 });3372 });
3383 try sema.requireFunctionBlock(block, var_decl_src);
3384 try sema.queueFullTypeResolution(var_ty);3373 try sema.queueFullTypeResolution(var_ty);
3385 return block.addTy(.alloc, ptr_type);3374 return block.addTy(.alloc, ptr_type);
3386}3375}
...@@ -3416,7 +3405,6 @@ fn zirAllocInferred(...@@ -3416,7 +3405,6 @@ fn zirAllocInferred(
3416 inferred_alloc_ty,3405 inferred_alloc_ty,
3417 try Value.Tag.inferred_alloc.create(sema.arena, .{ .alignment = 0 }),3406 try Value.Tag.inferred_alloc.create(sema.arena, .{ .alignment = 0 }),
3418 );3407 );
3419 try sema.requireFunctionBlock(block, src);
3420 try block.instructions.append(sema.gpa, Air.refToIndex(result).?);3408 try block.instructions.append(sema.gpa, Air.refToIndex(result).?);
3421 try sema.unresolved_inferred_allocs.putNoClobber(sema.gpa, Air.refToIndex(result).?, {});3409 try sema.unresolved_inferred_allocs.putNoClobber(sema.gpa, Air.refToIndex(result).?, {});
3422 return result;3410 return result;
...@@ -3571,7 +3559,6 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -3571,7 +3559,6 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
3571 return;3559 return;
3572 }3560 }
35733561
3574 try sema.requireFunctionBlock(block, src);
3575 try sema.queueFullTypeResolution(final_elem_ty);3562 try sema.queueFullTypeResolution(final_elem_ty);
35763563
3577 // Change it to a normal alloc.3564 // Change it to a normal alloc.
...@@ -3917,7 +3904,6 @@ fn validateUnionInit(...@@ -3917,7 +3904,6 @@ fn validateUnionInit(
3917 return;3904 return;
3918 }3905 }
39193906
3920 try sema.requireFunctionBlock(block, init_src);
3921 const new_tag = try sema.addConstant(tag_ty, tag_val);3907 const new_tag = try sema.addConstant(tag_ty, tag_val);
3922 _ = try block.addBinOp(.set_union_tag, union_ptr, new_tag);3908 _ = try block.addBinOp(.set_union_tag, union_ptr, new_tag);
3923}3909}
...@@ -4653,7 +4639,10 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v...@@ -4653,7 +4639,10 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v
4653 try sema.addToInferredErrorSet(operand);4639 try sema.addToInferredErrorSet(operand);
4654 }4640 }
46554641
4656 return sema.storePtr2(block, src, ptr, src, operand, src, if (is_ret) .ret_ptr else .store);4642 const ptr_src = src; // TODO better soruce location
4643 const operand_src = src; // TODO better soruce location
4644 const air_tag: Air.Inst.Tag = if (is_ret) .ret_ptr else .store;
4645 return sema.storePtr2(block, src, ptr, ptr_src, operand, operand_src, air_tag);
4657}4646}
46584647
4659fn zirStr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {4648fn zirStr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -4813,7 +4802,6 @@ fn zirPanic(sema: *Sema, block: *Block, inst: Zir.Inst.Index, force_comptime: bo...@@ -4813,7 +4802,6 @@ fn zirPanic(sema: *Sema, block: *Block, inst: Zir.Inst.Index, force_comptime: bo
4813 if (block.is_comptime or force_comptime) {4802 if (block.is_comptime or force_comptime) {
4814 return sema.fail(block, src, "encountered @panic at comptime", .{});4803 return sema.fail(block, src, "encountered @panic at comptime", .{});
4815 }4804 }
4816 try sema.requireFunctionBlock(block, src);
4817 return sema.panicWithMsg(block, src, msg_inst);4805 return sema.panicWithMsg(block, src, msg_inst);
4818}4806}
48194807
...@@ -6293,7 +6281,6 @@ fn analyzeCall(...@@ -6293,7 +6281,6 @@ fn analyzeCall(
6293 break :res res2;6281 break :res res2;
6294 } else res: {6282 } else res: {
6295 assert(!func_ty_info.is_generic);6283 assert(!func_ty_info.is_generic);
6296 try sema.requireFunctionBlock(block, call_src);
62976284
6298 const args = try sema.arena.alloc(Air.Inst.Ref, uncasted_args.len);6285 const args = try sema.arena.alloc(Air.Inst.Ref, uncasted_args.len);
6299 for (uncasted_args) |uncasted_arg, i| {6286 for (uncasted_args) |uncasted_arg, i| {
...@@ -6931,8 +6918,6 @@ fn instantiateGenericCall(...@@ -6931,8 +6918,6 @@ fn instantiateGenericCall(
6931 const callee_inst = try sema.analyzeDeclVal(block, func_src, callee.owner_decl);6918 const callee_inst = try sema.analyzeDeclVal(block, func_src, callee.owner_decl);
69326919
6933 // Make a runtime call to the new function, making sure to omit the comptime args.6920 // Make a runtime call to the new function, making sure to omit the comptime args.
6934 try sema.requireFunctionBlock(block, call_src);
6935
6936 const comptime_args = callee.comptime_args.?;6921 const comptime_args = callee.comptime_args.?;
6937 const func_ty = mod.declPtr(callee.owner_decl).ty;6922 const func_ty = mod.declPtr(callee.owner_decl).ty;
6938 const new_fn_info = func_ty.fnInfo();6923 const new_fn_info = func_ty.fnInfo();
...@@ -7476,7 +7461,6 @@ fn analyzeOptionalPayloadPtr(...@@ -7476,7 +7461,6 @@ fn analyzeOptionalPayloadPtr(
7476 // If the pointer resulting from this function was stored at comptime,7461 // If the pointer resulting from this function was stored at comptime,
7477 // the optional non-null bit would be set that way. But in this case,7462 // the optional non-null bit would be set that way. But in this case,
7478 // we need to emit a runtime instruction to do it.7463 // we need to emit a runtime instruction to do it.
7479 try sema.requireFunctionBlock(block, src);
7480 _ = try block.addTyOp(.optional_payload_ptr_set, child_pointer, optional_ptr);7464 _ = try block.addTyOp(.optional_payload_ptr_set, child_pointer, optional_ptr);
7481 }7465 }
7482 return sema.addConstant(7466 return sema.addConstant(
...@@ -16036,7 +16020,6 @@ fn zirUnreachable(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -16036,7 +16020,6 @@ fn zirUnreachable(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
16036 if (block.is_comptime or inst_data.force_comptime) {16020 if (block.is_comptime or inst_data.force_comptime) {
16037 return sema.fail(block, src, "reached unreachable code", .{});16021 return sema.fail(block, src, "reached unreachable code", .{});
16038 }16022 }
16039 try sema.requireFunctionBlock(block, src);
16040 // TODO Add compile error for @optimizeFor occurring too late in a scope.16023 // TODO Add compile error for @optimizeFor occurring too late in a scope.
16041 try block.addUnreachable(src, true);16024 try block.addUnreachable(src, true);
16042 return always_noreturn;16025 return always_noreturn;
...@@ -16211,6 +16194,7 @@ fn analyzeRet(...@@ -16211,6 +16194,7 @@ fn analyzeRet(
1621116194
16212 if (block.inlining) |inlining| {16195 if (block.inlining) |inlining| {
16213 if (block.is_comptime) {16196 if (block.is_comptime) {
16197 _ = try sema.resolveConstMaybeUndefVal(block, src, operand, "value being returned at comptime must be comptime-known");
16214 inlining.comptime_result = operand;16198 inlining.comptime_result = operand;
16215 return error.ComptimeReturn;16199 return error.ComptimeReturn;
16216 }16200 }
...@@ -21157,14 +21141,6 @@ fn zirBuiltinExtern(...@@ -21157,14 +21141,6 @@ fn zirBuiltinExtern(
21157 return block.addBitCast(ty, ref);21141 return block.addBitCast(ty, ref);
21158}21142}
2115921143
21160/// Asserts that the block is not comptime.
21161fn requireFunctionBlock(sema: *Sema, block: *Block, src: LazySrcLoc) !void {
21162 assert(!block.is_comptime);
21163 if (sema.func == null and !block.is_typeof and !block.is_coerce_result_ptr) {
21164 return sema.fail(block, src, "instruction illegal outside function body", .{});
21165 }
21166}
21167
21168fn requireRuntimeBlock(sema: *Sema, block: *Block, src: LazySrcLoc, runtime_src: ?LazySrcLoc) !void {21144fn requireRuntimeBlock(sema: *Sema, block: *Block, src: LazySrcLoc, runtime_src: ?LazySrcLoc) !void {
21169 if (block.is_comptime) {21145 if (block.is_comptime) {
21170 const msg = msg: {21146 const msg = msg: {
...@@ -21178,7 +21154,6 @@ fn requireRuntimeBlock(sema: *Sema, block: *Block, src: LazySrcLoc, runtime_src:...@@ -21178,7 +21154,6 @@ fn requireRuntimeBlock(sema: *Sema, block: *Block, src: LazySrcLoc, runtime_src:
21178 };21154 };
21179 return sema.failWithOwnedErrorMsg(msg);21155 return sema.failWithOwnedErrorMsg(msg);
21180 }21156 }
21181 try sema.requireFunctionBlock(block, src);
21182}21157}
2118321158
21184/// Emit a compile error if type cannot be used for a runtime variable.21159/// Emit a compile error if type cannot be used for a runtime variable.
...@@ -25151,11 +25126,6 @@ fn storePtr2(...@@ -25151,11 +25126,6 @@ fn storePtr2(
25151 return;25126 return;
25152 }25127 }
2515325128
25154 if (block.is_comptime) {
25155 // TODO ideally this would tell why the block is comptime
25156 return sema.fail(block, ptr_src, "cannot store to runtime value in comptime block", .{});
25157 }
25158
25159 try sema.requireRuntimeBlock(block, src, runtime_src);25129 try sema.requireRuntimeBlock(block, src, runtime_src);
25160 try sema.queueFullTypeResolution(elem_ty);25130 try sema.queueFullTypeResolution(elem_ty);
25161 if (is_ret) {25131 if (is_ret) {
...@@ -27063,12 +27033,6 @@ fn analyzeLoad(...@@ -27063,12 +27033,6 @@ fn analyzeLoad(
27063 }27033 }
27064 }27034 }
2706527035
27066 if (block.is_comptime) {
27067 // TODO ideally this would tell why the block is comptime
27068 return sema.fail(block, ptr_src, "cannot load runtime value in comptime block", .{});
27069 }
27070
27071 try sema.requireFunctionBlock(block, src);
27072 return block.addTyOp(.load, elem_ty, ptr);27036 return block.addTyOp(.load, elem_ty, ptr);
27073}27037}
2707427038
test/behavior/eval.zig+11
...@@ -1414,3 +1414,14 @@ test "continue nested inline for loop" {...@@ -1414,3 +1414,14 @@ test "continue nested inline for loop" {
1414 }1414 }
1415 try expect(a == 2);1415 try expect(a == 2);
1416}1416}
1417
1418test "length of global array is determinable at comptime" {
1419 const S = struct {
1420 var bytes: [1024]u8 = undefined;
1421
1422 fn foo() !void {
1423 try std.testing.expect(bytes.len == 1024);
1424 }
1425 };
1426 comptime try S.foo();
1427}
test/cases/compile_errors/call method on bound fn referring to var instance.zig deleted-20
...@@ -1,20 +0,0 @@
1export fn entry() void {
2 bad(bound_fn() == 1237);
3}
4const SimpleStruct = struct {
5 field: i32,
6
7 fn method(self: *const SimpleStruct) i32 {
8 return self.field + 3;
9 }
10};
11var simple_struct = SimpleStruct{ .field = 1234 };
12const bound_fn = simple_struct.method;
13fn bad(ok: bool) void {
14 _ = ok;
15}
16// error
17// target=native
18// backend=stage2
19//
20// :12:18: error: cannot load runtime value in comptime block
test/cases/compile_errors/callconv_from_global_variable.zig created+9
...@@ -0,0 +1,9 @@
1var cc: @import("std").builtin.CallingConvention = .C;
2export fn foo() callconv(cc) void {}
3
4// error
5// backend=stage2
6// target=native
7//
8// :2:26: error: unable to resolve comptime value
9// :2:26: note: calling convention must be comptime-known
test/cases/compile_errors/implicit_cast_from_f64_to_f32.zig+1-1
...@@ -14,5 +14,5 @@ export fn entry2() void {...@@ -14,5 +14,5 @@ export fn entry2() void {
14// backend=llvm14// backend=llvm
15// target=native15// target=native
16//16//
17// :2:14: error: cannot load runtime value in comptime block17// :2:14: error: expected type 'f32', found 'f64'
18// :9:19: error: expected type 'f32', found 'f64'18// :9:19: error: expected type 'f32', found 'f64'
test/cases/compile_errors/non-const_expression_function_call_with_struct_return_value_outside_function.zig+2-1
...@@ -14,5 +14,6 @@ export fn entry() usize { return @sizeOf(@TypeOf(a)); }...@@ -14,5 +14,6 @@ export fn entry() usize { return @sizeOf(@TypeOf(a)); }
14// backend=stage214// backend=stage2
15// target=native15// target=native
16//16//
17// :6:26: error: cannot store to runtime value in comptime block17// :6:26: error: unable to evaluate comptime expression
18// :6:26: note: operation is runtime due to this operand
18// :4:17: note: called from here19// :4:17: note: called from here
test/cases/compile_errors/non-pure_function_returns_type.zig+2-1
...@@ -21,5 +21,6 @@ export fn function_with_return_type_type() void {...@@ -21,5 +21,6 @@ export fn function_with_return_type_type() void {
21// backend=stage221// backend=stage2
22// target=native22// target=native
23//23//
24// :3:7: error: cannot load runtime value in comptime block24// :3:7: error: unable to evaluate comptime expression
25// :3:5: note: operation is runtime due to this operand
25// :16:19: note: called from here26// :16:19: note: called from here
test/cases/compile_errors/non_constant_expression_in_array_size.zig+2-1
...@@ -10,5 +10,6 @@ export fn entry() usize { return @offsetOf(Foo, "y"); }...@@ -10,5 +10,6 @@ export fn entry() usize { return @offsetOf(Foo, "y"); }
10// backend=stage210// backend=stage2
11// target=native11// target=native
12//12//
13// :5:25: error: cannot load runtime value in comptime block13// :5:18: error: unable to resolve comptime value
14// :5:18: note: value being returned at comptime must be comptime-known
14// :2:12: note: called from here15// :2:12: note: called from here
test/cases/extern_variable_has_no_type.0.zig+2-1
...@@ -6,4 +6,5 @@ extern var foo: i32;...@@ -6,4 +6,5 @@ extern var foo: i32;
66
7// error7// error
8//8//
9// :2:15: error: cannot load runtime value in comptime block9// :2:19: error: unable to evaluate comptime expression
10// :2:15: note: operation is runtime due to this operand
test/stage2/cbe.zig+3-2
...@@ -51,8 +51,9 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -51,8 +51,9 @@ pub fn addCases(ctx: *TestContext) !void {
51 \\}51 \\}
52 \\var y: @import("std").builtin.CallingConvention = .C;52 \\var y: @import("std").builtin.CallingConvention = .C;
53 , &.{53 , &.{
54 ":2:22: error: cannot load runtime value in comptime block",54 ":2:22: error: expected type 'type', found 'i32'",
55 ":5:26: error: cannot load runtime value in comptime block",55 ":5:26: error: unable to resolve comptime value",
56 ":5:26: note: calling convention must be comptime-known",
56 });57 });
57 }58 }
5859