aboutsummaryrefslogtreecommitdiff
path: root/src/Sema.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-08-06 19:40:55 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-08-06 19:53:04 -0700
commit7d0de54ad44832589379a4bcbba493db2087bebf (patch)
tree5efb0a82c4ad399e25f603ba25cc6e36566ca845 /src/Sema.zig
parente974d4c4295c4fbdbc239caa2cf2d653f65662f1 (diff)
downloadzig-7d0de54ad44832589379a4bcbba493db2087bebf.tar.gz
zig-7d0de54ad44832589379a4bcbba493db2087bebf.zip
stage2: fix return pointer result locations
* Introduce `ret_load` ZIR instruction which does return semantics based on a corresponding `ret_ptr` instruction. If the return type of the function has storage for the return type, it simply returns. However if the return type of the function is by-value, it loads the return value from the `ret_ptr` allocation and returns that. * AstGen: improve `finishThenElseBlock` to not emit break instructions after a return instruction in the same block. * Sema: `ret_ptr` instruction works correctly in comptime contexts. Same with `alloc_mut`. The test case with a recursive inline function having an implicitly comptime return value now has a runtime return value because of the fact that it calls a function in a non-comptime context.
Diffstat (limited to 'src/Sema.zig')
-rw-r--r--src/Sema.zig66
1 files changed, 49 insertions, 17 deletions
diff --git a/src/Sema.zig b/src/Sema.zig
index 87df3c375f..109c1c9335 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -366,6 +366,7 @@ pub fn analyzeBody(
.compile_error => return sema.zirCompileError(block, inst),
.ret_coerce => return sema.zirRetCoerce(block, inst),
.ret_node => return sema.zirRetNode(block, inst),
+ .ret_load => return sema.zirRetLoad(block, inst),
.ret_err_value => return sema.zirRetErrValue(block, inst),
.@"unreachable" => return sema.zirUnreachable(block, inst),
.repeat => return sema.zirRepeat(block, inst),
@@ -718,8 +719,8 @@ fn resolveMaybeUndefValAllowVariables(
if (try sema.typeHasOnePossibleValue(block, src, sema.typeOf(inst))) |opv| {
return opv;
}
-
- switch (sema.air_instructions.items(.tag)[i]) {
+ const air_tags = sema.air_instructions.items(.tag);
+ switch (air_tags[i]) {
.constant => {
const ty_pl = sema.air_instructions.items(.data)[i].ty_pl;
return sema.air_values.items[ty_pl.payload];
@@ -1248,6 +1249,11 @@ fn zirRetPtr(
const src: LazySrcLoc = .{ .node_offset = @bitCast(i32, extended.operand) };
try sema.requireFunctionBlock(block, src);
+
+ if (block.is_comptime) {
+ return sema.analyzeComptimeAlloc(block, sema.fn_ret_ty);
+ }
+
const ptr_type = try Module.simplePtrType(sema.arena, sema.fn_ret_ty, true, .One);
return block.addTy(.alloc, ptr_type);
}
@@ -1375,21 +1381,7 @@ fn zirAllocComptime(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Comp
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
const var_type = try sema.resolveType(block, ty_src, inst_data.operand);
- const ptr_type = try Module.simplePtrType(sema.arena, var_type, true, .One);
-
- var anon_decl = try block.startAnonDecl();
- defer anon_decl.deinit();
- const decl = try anon_decl.finish(
- try var_type.copy(anon_decl.arena()),
- // AstGen guarantees there will be a store before the first load, so we put a value
- // here indicating there is no valid value.
- Value.initTag(.unreachable_value),
- );
- try sema.mod.declareDeclDependency(sema.owner_decl, decl);
- return sema.addConstant(ptr_type, try Value.Tag.decl_ref_mut.create(sema.arena, .{
- .runtime_index = block.runtime_index,
- .decl = decl,
- }));
+ return sema.analyzeComptimeAlloc(block, var_type);
}
fn zirAllocInferredComptime(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -1419,6 +1411,9 @@ fn zirAllocMut(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr
const var_decl_src = inst_data.src();
const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
const var_type = try sema.resolveType(block, ty_src, inst_data.operand);
+ if (block.is_comptime) {
+ return sema.analyzeComptimeAlloc(block, var_type);
+ }
try sema.validateVarType(block, ty_src, var_type);
const ptr_type = try Module.simplePtrType(sema.arena, var_type, true, .One);
try sema.requireRuntimeBlock(block, var_decl_src);
@@ -6280,6 +6275,21 @@ fn zirRetNode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErr
return sema.analyzeRet(block, operand, src, false);
}
+fn zirRetLoad(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index {
+ const tracy = trace(@src());
+ defer tracy.end();
+
+ const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+ const src = inst_data.src();
+ // TODO: when implementing functions that accept a result location pointer,
+ // this logic will be updated to only do a load in case that the function's return
+ // type in fact does not need a result location pointer. Until then we assume
+ // the `ret_ptr` is the same as an `alloc` and do a load here.
+ const ret_ptr = sema.resolveInst(inst_data.operand);
+ const operand = try sema.analyzeLoad(block, src, ret_ptr, src);
+ return sema.analyzeRet(block, operand, src, false);
+}
+
fn analyzeRet(
sema: *Sema,
block: *Scope.Block,
@@ -9416,3 +9426,25 @@ fn isComptimeKnown(
) !bool {
return (try sema.resolveMaybeUndefVal(block, src, inst)) != null;
}
+
+fn analyzeComptimeAlloc(
+ sema: *Sema,
+ block: *Scope.Block,
+ var_type: Type,
+) CompileError!Air.Inst.Ref {
+ const ptr_type = try Module.simplePtrType(sema.arena, var_type, true, .One);
+
+ var anon_decl = try block.startAnonDecl();
+ defer anon_decl.deinit();
+ const decl = try anon_decl.finish(
+ try var_type.copy(anon_decl.arena()),
+ // AstGen guarantees there will be a store before the first load, so we put a value
+ // here indicating there is no valid value.
+ Value.initTag(.unreachable_value),
+ );
+ try sema.mod.declareDeclDependency(sema.owner_decl, decl);
+ return sema.addConstant(ptr_type, try Value.Tag.decl_ref_mut.create(sema.arena, .{
+ .runtime_index = block.runtime_index,
+ .decl = decl,
+ }));
+}