aboutsummaryrefslogtreecommitdiff
path: root/src/AstGen.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-09-22 21:02:24 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-09-22 21:06:00 -0700
commit736d14fd5fa5feea83a6efce8b606b62bf165033 (patch)
treeda48c5f1743c7418ed51c5f9769236529a988be8 /src/AstGen.zig
parent0ec01e58b429e96d50411f74a0005076c24dda0c (diff)
downloadzig-736d14fd5fa5feea83a6efce8b606b62bf165033.tar.gz
zig-736d14fd5fa5feea83a6efce8b606b62bf165033.zip
stage2: fix AstGen for some struct syntaxes
* AstGen: fix not emitting `struct_init_empty` when an explicit type is present in struct initialization syntax. * AstGen: these two syntaxes now lower to identical ZIR: - `var a = A{ .b = c };` - `var a = @as(A, .{ .b = c });` * Zir: clarify `auto_enum_tag` in the doc comments. * LLVM Backend: fix lowering of function return types when the type has 0 bits.
Diffstat (limited to 'src/AstGen.zig')
-rw-r--r--src/AstGen.zig110
1 files changed, 79 insertions, 31 deletions
diff --git a/src/AstGen.zig b/src/AstGen.zig
index 6a533dff11..b33c5aad40 100644
--- a/src/AstGen.zig
+++ b/src/AstGen.zig
@@ -1357,7 +1357,14 @@ fn structInitExpr(
const array_type: Ast.full.ArrayType = switch (node_tags[struct_init.ast.type_expr]) {
.array_type => tree.arrayType(struct_init.ast.type_expr),
.array_type_sentinel => tree.arrayTypeSentinel(struct_init.ast.type_expr),
- else => break :array,
+ else => {
+ if (struct_init.ast.fields.len == 0) {
+ const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
+ const result = try gz.addUnNode(.struct_init_empty, ty_inst, node);
+ return rvalue(gz, rl, result, node);
+ }
+ break :array;
+ },
};
const is_inferred_array_len = node_tags[array_type.ast.elem_count] == .identifier and
// This intentionally does not support `@"_"` syntax.
@@ -1419,8 +1426,8 @@ fn structInitExpr(
const result = try structInitExprRlTy(gz, scope, node, struct_init, inner_ty_inst, .struct_init);
return rvalue(gz, rl, result, node);
},
- .ptr, .inferred_ptr => |ptr_inst| return structInitExprRlPtr(gz, scope, node, struct_init, ptr_inst),
- .block_ptr => |block_gz| return structInitExprRlPtr(gz, scope, node, struct_init, block_gz.rl_ptr),
+ .ptr, .inferred_ptr => |ptr_inst| return structInitExprRlPtr(gz, scope, rl, node, struct_init, ptr_inst),
+ .block_ptr => |block_gz| return structInitExprRlPtr(gz, scope, rl, node, struct_init, block_gz.rl_ptr),
}
}
@@ -1461,6 +1468,26 @@ fn structInitExprRlNone(
fn structInitExprRlPtr(
gz: *GenZir,
scope: *Scope,
+ rl: ResultLoc,
+ node: Ast.Node.Index,
+ struct_init: Ast.full.StructInit,
+ result_ptr: Zir.Inst.Ref,
+) InnerError!Zir.Inst.Ref {
+ if (struct_init.ast.type_expr == 0) {
+ return structInitExprRlPtrInner(gz, scope, node, struct_init, result_ptr);
+ }
+ const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
+
+ var as_scope = try gz.makeCoercionScope(scope, ty_inst, result_ptr);
+ defer as_scope.instructions.deinit(gz.astgen.gpa);
+
+ const result = try structInitExprRlPtrInner(&as_scope, scope, node, struct_init, as_scope.rl_ptr);
+ return as_scope.finishCoercion(gz, rl, node, result, ty_inst);
+}
+
+fn structInitExprRlPtrInner(
+ gz: *GenZir,
+ scope: *Scope,
node: Ast.Node.Index,
struct_init: Ast.full.StructInit,
result_ptr: Zir.Inst.Ref,
@@ -1472,9 +1499,6 @@ fn structInitExprRlPtr(
const field_ptr_list = try gpa.alloc(Zir.Inst.Index, struct_init.ast.fields.len);
defer gpa.free(field_ptr_list);
- if (struct_init.ast.type_expr != 0)
- _ = try typeExpr(gz, scope, struct_init.ast.type_expr);
-
for (struct_init.ast.fields) |field_init, i| {
const name_token = tree.firstToken(field_init) - 2;
const str_index = try astgen.identAsString(name_token);
@@ -1489,7 +1513,7 @@ fn structInitExprRlPtr(
.body_len = @intCast(u32, field_ptr_list.len),
});
try astgen.extra.appendSlice(gpa, field_ptr_list);
- return .void_value;
+ return Zir.Inst.Ref.void_value;
}
fn structInitExprRlTy(
@@ -6902,35 +6926,13 @@ fn asRlPtr(
operand_node: Ast.Node.Index,
dest_type: Zir.Inst.Ref,
) InnerError!Zir.Inst.Ref {
- // Detect whether this expr() call goes into rvalue() to store the result into the
- // result location. If it does, elide the coerce_result_ptr instruction
- // as well as the store instruction, instead passing the result as an rvalue.
const astgen = parent_gz.astgen;
- var as_scope = parent_gz.makeSubBlock(scope);
+ var as_scope = try parent_gz.makeCoercionScope(scope, dest_type, result_ptr);
defer as_scope.instructions.deinit(astgen.gpa);
- as_scope.rl_ptr = try as_scope.addBin(.coerce_result_ptr, dest_type, result_ptr);
const result = try reachableExpr(&as_scope, &as_scope.base, .{ .block_ptr = &as_scope }, operand_node, src_node);
- const parent_zir = &parent_gz.instructions;
- if (as_scope.rvalue_rl_count == 1) {
- // Busted! This expression didn't actually need a pointer.
- const zir_tags = astgen.instructions.items(.tag);
- const zir_datas = astgen.instructions.items(.data);
- try parent_zir.ensureUnusedCapacity(astgen.gpa, as_scope.instructions.items.len);
- for (as_scope.instructions.items) |src_inst| {
- if (indexToRef(src_inst) == as_scope.rl_ptr) continue;
- if (zir_tags[src_inst] == .store_to_block_ptr) {
- if (zir_datas[src_inst].bin.lhs == as_scope.rl_ptr) continue;
- }
- parent_zir.appendAssumeCapacity(src_inst);
- }
- const casted_result = try parent_gz.addBin(.as, dest_type, result);
- return rvalue(parent_gz, rl, casted_result, operand_node);
- } else {
- try parent_zir.appendSlice(astgen.gpa, as_scope.instructions.items);
- return result;
- }
+ return as_scope.finishCoercion(parent_gz, rl, operand_node, result, dest_type);
}
fn bitCast(
@@ -9108,6 +9110,52 @@ const GenZir = struct {
};
}
+ fn makeCoercionScope(
+ parent_gz: *GenZir,
+ scope: *Scope,
+ dest_type: Zir.Inst.Ref,
+ result_ptr: Zir.Inst.Ref,
+ ) !GenZir {
+ // Detect whether this expr() call goes into rvalue() to store the result into the
+ // result location. If it does, elide the coerce_result_ptr instruction
+ // as well as the store instruction, instead passing the result as an rvalue.
+ var as_scope = parent_gz.makeSubBlock(scope);
+ errdefer as_scope.instructions.deinit(parent_gz.astgen.gpa);
+ as_scope.rl_ptr = try as_scope.addBin(.coerce_result_ptr, dest_type, result_ptr);
+
+ return as_scope;
+ }
+
+ fn finishCoercion(
+ as_scope: *GenZir,
+ parent_gz: *GenZir,
+ rl: ResultLoc,
+ src_node: Ast.Node.Index,
+ result: Zir.Inst.Ref,
+ dest_type: Zir.Inst.Ref,
+ ) !Zir.Inst.Ref {
+ const astgen = as_scope.astgen;
+ const parent_zir = &parent_gz.instructions;
+ if (as_scope.rvalue_rl_count == 1) {
+ // Busted! This expression didn't actually need a pointer.
+ const zir_tags = astgen.instructions.items(.tag);
+ const zir_datas = astgen.instructions.items(.data);
+ try parent_zir.ensureUnusedCapacity(astgen.gpa, as_scope.instructions.items.len);
+ for (as_scope.instructions.items) |src_inst| {
+ if (indexToRef(src_inst) == as_scope.rl_ptr) continue;
+ if (zir_tags[src_inst] == .store_to_block_ptr) {
+ if (zir_datas[src_inst].bin.lhs == as_scope.rl_ptr) continue;
+ }
+ parent_zir.appendAssumeCapacity(src_inst);
+ }
+ const casted_result = try parent_gz.addBin(.as, dest_type, result);
+ return rvalue(parent_gz, rl, casted_result, src_node);
+ } else {
+ try parent_zir.appendSlice(astgen.gpa, as_scope.instructions.items);
+ return result;
+ }
+ }
+
const Label = struct {
token: Ast.TokenIndex,
block_inst: Zir.Inst.Index,