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(
12371237 i = 0;
12381238 continue;
12391239 } 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);
12431240 break always_noreturn;
12441241 }
12451242 },
......@@ -2188,7 +2185,6 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
21882185 defer trash_block.instructions.deinit(sema.gpa);
21892186 const operand = try trash_block.addBitCast(pointee_ty, .void_value);
21902187
2191 try sema.requireFunctionBlock(block, src);
21922188 const ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
21932189 .pointee_type = pointee_ty,
21942190 .@"align" = inferred_alloc.alignment,
......@@ -3221,7 +3217,6 @@ fn zirAllocExtended(
32213217 try sema.validateVarType(block, ty_src, var_ty, false);
32223218 }
32233219 const target = sema.mod.getTarget();
3224 try sema.requireFunctionBlock(block, src);
32253220 try sema.resolveTypeLayout(block, src, var_ty);
32263221 const ptr_type = try Type.ptr(sema.arena, sema.mod, .{
32273222 .pointee_type = var_ty,
......@@ -3239,7 +3234,6 @@ fn zirAllocExtended(
32393234 inferred_alloc_ty,
32403235 try Value.Tag.inferred_alloc.create(sema.arena, .{ .alignment = alignment }),
32413236 );
3242 try sema.requireFunctionBlock(block, src);
32433237 try block.instructions.append(sema.gpa, Air.refToIndex(result).?);
32443238 try sema.unresolved_inferred_allocs.putNoClobber(sema.gpa, Air.refToIndex(result).?, {});
32453239 return result;
......@@ -3321,7 +3315,6 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
33213315 return sema.addConstant(const_ptr_ty, val);
33223316 }
33233317
3324 try sema.requireFunctionBlock(block, src);
33253318 return block.addBitCast(const_ptr_ty, alloc);
33263319}
33273320
......@@ -3348,7 +3341,6 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
33483341
33493342 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
33503343 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
3351 const var_decl_src = inst_data.src();
33523344 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
33533345 if (block.is_comptime) {
33543346 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
33583350 .pointee_type = var_ty,
33593351 .@"addrspace" = target_util.defaultAddressSpace(target, .local),
33603352 });
3361 try sema.requireFunctionBlock(block, var_decl_src);
33623353 try sema.queueFullTypeResolution(var_ty);
33633354 return block.addTy(.alloc, ptr_type);
33643355}
......@@ -3368,7 +3359,6 @@ fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
33683359 defer tracy.end();
33693360
33703361 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
3371 const var_decl_src = inst_data.src();
33723362 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
33733363 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
33743364 if (block.is_comptime) {
......@@ -3380,7 +3370,6 @@ fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
33803370 .pointee_type = var_ty,
33813371 .@"addrspace" = target_util.defaultAddressSpace(target, .local),
33823372 });
3383 try sema.requireFunctionBlock(block, var_decl_src);
33843373 try sema.queueFullTypeResolution(var_ty);
33853374 return block.addTy(.alloc, ptr_type);
33863375}
......@@ -3416,7 +3405,6 @@ fn zirAllocInferred(
34163405 inferred_alloc_ty,
34173406 try Value.Tag.inferred_alloc.create(sema.arena, .{ .alignment = 0 }),
34183407 );
3419 try sema.requireFunctionBlock(block, src);
34203408 try block.instructions.append(sema.gpa, Air.refToIndex(result).?);
34213409 try sema.unresolved_inferred_allocs.putNoClobber(sema.gpa, Air.refToIndex(result).?, {});
34223410 return result;
......@@ -3571,7 +3559,6 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
35713559 return;
35723560 }
35733561
3574 try sema.requireFunctionBlock(block, src);
35753562 try sema.queueFullTypeResolution(final_elem_ty);
35763563
35773564 // Change it to a normal alloc.
......@@ -3917,7 +3904,6 @@ fn validateUnionInit(
39173904 return;
39183905 }
39193906
3920 try sema.requireFunctionBlock(block, init_src);
39213907 const new_tag = try sema.addConstant(tag_ty, tag_val);
39223908 _ = try block.addBinOp(.set_union_tag, union_ptr, new_tag);
39233909}
......@@ -4653,7 +4639,10 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v
46534639 try sema.addToInferredErrorSet(operand);
46544640 }
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);
46574646}
46584647
46594648fn 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
48134802 if (block.is_comptime or force_comptime) {
48144803 return sema.fail(block, src, "encountered @panic at comptime", .{});
48154804 }
4816 try sema.requireFunctionBlock(block, src);
48174805 return sema.panicWithMsg(block, src, msg_inst);
48184806}
48194807
......@@ -6293,7 +6281,6 @@ fn analyzeCall(
62936281 break :res res2;
62946282 } else res: {
62956283 assert(!func_ty_info.is_generic);
6296 try sema.requireFunctionBlock(block, call_src);
62976284
62986285 const args = try sema.arena.alloc(Air.Inst.Ref, uncasted_args.len);
62996286 for (uncasted_args) |uncasted_arg, i| {
......@@ -6931,8 +6918,6 @@ fn instantiateGenericCall(
69316918 const callee_inst = try sema.analyzeDeclVal(block, func_src, callee.owner_decl);
69326919
69336920 // Make a runtime call to the new function, making sure to omit the comptime args.
6934 try sema.requireFunctionBlock(block, call_src);
6935
69366921 const comptime_args = callee.comptime_args.?;
69376922 const func_ty = mod.declPtr(callee.owner_decl).ty;
69386923 const new_fn_info = func_ty.fnInfo();
......@@ -7476,7 +7461,6 @@ fn analyzeOptionalPayloadPtr(
74767461 // If the pointer resulting from this function was stored at comptime,
74777462 // the optional non-null bit would be set that way. But in this case,
74787463 // we need to emit a runtime instruction to do it.
7479 try sema.requireFunctionBlock(block, src);
74807464 _ = try block.addTyOp(.optional_payload_ptr_set, child_pointer, optional_ptr);
74817465 }
74827466 return sema.addConstant(
......@@ -16036,7 +16020,6 @@ fn zirUnreachable(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1603616020 if (block.is_comptime or inst_data.force_comptime) {
1603716021 return sema.fail(block, src, "reached unreachable code", .{});
1603816022 }
16039 try sema.requireFunctionBlock(block, src);
1604016023 // TODO Add compile error for @optimizeFor occurring too late in a scope.
1604116024 try block.addUnreachable(src, true);
1604216025 return always_noreturn;
......@@ -16211,6 +16194,7 @@ fn analyzeRet(
1621116194
1621216195 if (block.inlining) |inlining| {
1621316196 if (block.is_comptime) {
16197 _ = try sema.resolveConstMaybeUndefVal(block, src, operand, "value being returned at comptime must be comptime-known");
1621416198 inlining.comptime_result = operand;
1621516199 return error.ComptimeReturn;
1621616200 }
......@@ -21157,14 +21141,6 @@ fn zirBuiltinExtern(
2115721141 return block.addBitCast(ty, ref);
2115821142}
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
2116821144fn requireRuntimeBlock(sema: *Sema, block: *Block, src: LazySrcLoc, runtime_src: ?LazySrcLoc) !void {
2116921145 if (block.is_comptime) {
2117021146 const msg = msg: {
......@@ -21178,7 +21154,6 @@ fn requireRuntimeBlock(sema: *Sema, block: *Block, src: LazySrcLoc, runtime_src:
2117821154 };
2117921155 return sema.failWithOwnedErrorMsg(msg);
2118021156 }
21181 try sema.requireFunctionBlock(block, src);
2118221157}
2118321158
2118421159/// Emit a compile error if type cannot be used for a runtime variable.
......@@ -25151,11 +25126,6 @@ fn storePtr2(
2515125126 return;
2515225127 }
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
2515925129 try sema.requireRuntimeBlock(block, src, runtime_src);
2516025130 try sema.queueFullTypeResolution(elem_ty);
2516125131 if (is_ret) {
......@@ -27063,12 +27033,6 @@ fn analyzeLoad(
2706327033 }
2706427034 }
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);
2707227036 return block.addTyOp(.load, elem_ty, ptr);
2707327037}
2707427038
test/behavior/eval.zig+11
......@@ -1414,3 +1414,14 @@ test "continue nested inline for loop" {
14141414 }
14151415 try expect(a == 2);
14161416}
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 {
1414// backend=llvm
1515// target=native
1616//
17// :2:14: error: cannot load runtime value in comptime block
17// :2:14: error: expected type 'f32', found 'f64'
1818// :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)); }
1414// backend=stage2
1515// target=native
1616//
17// :6:26: error: cannot store to runtime value in comptime block
17// :6:26: error: unable to evaluate comptime expression
18// :6:26: note: operation is runtime due to this operand
1819// :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 {
2121// backend=stage2
2222// target=native
2323//
24// :3:7: error: cannot load runtime value in comptime block
24// :3:7: error: unable to evaluate comptime expression
25// :3:5: note: operation is runtime due to this operand
2526// :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"); }
1010// backend=stage2
1111// target=native
1212//
13// :5:25: error: cannot load runtime value in comptime block
13// :5:18: error: unable to resolve comptime value
14// :5:18: note: value being returned at comptime must be comptime-known
1415// :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;
66
77// error
88//
9// :2:15: error: cannot load runtime value in comptime block
9// :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 {
5151 \\}
5252 \\var y: @import("std").builtin.CallingConvention = .C;
5353 , &.{
54 ":2:22: error: cannot load runtime value in comptime block",
55 ":5:26: error: cannot load runtime value in comptime block",
54 ":2:22: error: expected type 'type', found 'i32'",
55 ":5:26: error: unable to resolve comptime value",
56 ":5:26: note: calling convention must be comptime-known",
5657 });
5758 }
5859