aboutsummaryrefslogtreecommitdiff
path: root/src/Sema.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2022-05-30 21:18:10 -0400
committerGitHub <noreply@github.com>2022-05-30 21:18:10 -0400
commitc3ef4ac15f4aa0a4bbf546fb46745d445b97d717 (patch)
tree98158ea6835297c116bbaf2735d32e556e8741c2 /src/Sema.zig
parentc84f5a5f91d31b20b2e187d84fc8a80a190a1212 (diff)
parentbd89a73d5289536948b052eb7f052d6de193441b (diff)
downloadzig-c3ef4ac15f4aa0a4bbf546fb46745d445b97d717.tar.gz
zig-c3ef4ac15f4aa0a4bbf546fb46745d445b97d717.zip
Merge pull request #11752 from ziglang/zir-fancy-fns
stage2: add missing data to ZIR encoding of functions
Diffstat (limited to 'src/Sema.zig')
-rw-r--r--src/Sema.zig341
1 files changed, 262 insertions, 79 deletions
diff --git a/src/Sema.zig b/src/Sema.zig
index fc64e17789..505810a158 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -747,7 +747,7 @@ fn analyzeBodyInner(
.field_call_bind => try sema.zirFieldCallBind(block, inst),
.func => try sema.zirFunc(block, inst, false),
.func_inferred => try sema.zirFunc(block, inst, true),
- .func_extended => try sema.zirFuncExtended(block, inst),
+ .func_fancy => try sema.zirFuncFancy(block, inst),
.import => try sema.zirImport(block, inst),
.indexable_ptr_len => try sema.zirIndexablePtrLen(block, inst),
.int => try sema.zirInt(block, inst),
@@ -5190,7 +5190,10 @@ fn analyzeCall(
// on parameters, we must now do the same for the return type as we just did with
// each of the parameters, resolving the return type and providing it to the child
// `Sema` so that it can be used for the `ret_ptr` instruction.
- const ret_ty_inst = try sema.resolveBody(&child_block, fn_info.ret_ty_body, module_fn.zir_body_inst);
+ const ret_ty_inst = if (fn_info.ret_ty_body.len != 0)
+ try sema.resolveBody(&child_block, fn_info.ret_ty_body, module_fn.zir_body_inst)
+ else
+ try sema.resolveInst(fn_info.ret_ty_ref);
const ret_ty_src = func_src; // TODO better source location
const bare_return_type = try sema.analyzeAsType(&child_block, ret_ty_src, ret_ty_inst);
// Create a fresh inferred error set type for inline/comptime calls.
@@ -6506,9 +6509,34 @@ fn zirFunc(
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const extra = sema.code.extraData(Zir.Inst.Func, inst_data.payload_index);
+ const target = sema.mod.getTarget();
+ const ret_ty_src = inst_data.src(); // TODO better source location
+
var extra_index = extra.end;
- const ret_ty_body = sema.code.extra[extra_index..][0..extra.data.ret_body_len];
- extra_index += ret_ty_body.len;
+
+ const ret_ty: Type = switch (extra.data.ret_body_len) {
+ 0 => Type.void,
+ 1 => blk: {
+ const ret_ty_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
+ extra_index += 1;
+ if (sema.resolveType(block, ret_ty_src, ret_ty_ref)) |ret_ty| {
+ break :blk ret_ty;
+ } else |err| switch (err) {
+ error.GenericPoison => {
+ break :blk Type.initTag(.generic_poison);
+ },
+ else => |e| return e,
+ }
+ },
+ else => blk: {
+ const ret_ty_body = sema.code.extra[extra_index..][0..extra.data.ret_body_len];
+ extra_index += ret_ty_body.len;
+
+ const ret_ty_val = try sema.resolveGenericBody(block, ret_ty_src, ret_ty_body, inst, Type.type);
+ var buffer: Value.ToTypeBuffer = undefined;
+ break :blk try ret_ty_val.toType(&buffer).copy(sema.arena);
+ },
+ };
var src_locs: Zir.Inst.Func.SrcLocs = undefined;
const has_body = extra.data.body_len != 0;
@@ -6526,9 +6554,11 @@ fn zirFunc(
block,
inst_data.src_node,
inst,
- ret_ty_body,
+ 0,
+ target_util.defaultAddressSpace(target, .function),
+ FuncLinkSection.default,
cc,
- Value.@"null",
+ ret_ty,
false,
inferred_error_set,
false,
@@ -6538,6 +6568,44 @@ fn zirFunc(
);
}
+// TODO this function and its callsites along with funcCommon need to be reworked
+// to handle when callconv, align, linksection, addrspace depend on comptime values
+// (thus triggering error.GenericPoison)
+fn resolveGenericBody(
+ sema: *Sema,
+ block: *Block,
+ src: LazySrcLoc,
+ body: []const Zir.Inst.Index,
+ func_inst: Zir.Inst.Index,
+ dest_ty: Type,
+) !Value {
+ assert(body.len != 0);
+
+ const err = err: {
+ // Make sure any nested param instructions don't clobber our work.
+ const prev_params = block.params;
+ block.params = .{};
+ defer {
+ block.params.deinit(sema.gpa);
+ block.params = prev_params;
+ }
+ const uncasted = sema.resolveBody(block, body, func_inst) catch |err| break :err err;
+ const result = sema.coerce(block, dest_ty, uncasted, src) catch |err| break :err err;
+ const val = sema.resolveConstValue(block, src, result) catch |err| break :err err;
+ return val;
+ };
+ switch (err) {
+ error.GenericPoison => {
+ if (dest_ty.tag() == .type) {
+ return Value.initTag(.generic_poison_type);
+ } else {
+ return Value.initTag(.generic_poison);
+ }
+ },
+ else => |e| return e,
+ }
+}
+
/// Given a library name, examines if the library name should end up in
/// `link.File.Options.system_libs` table (for example, libc is always
/// specified via dedicated flag `link.File.Options.link_libc` instead),
@@ -6601,14 +6669,27 @@ fn handleExternLibName(
return sema.gpa.dupeZ(u8, lib_name);
}
+const FuncLinkSection = union(enum) {
+ generic,
+ default,
+ explicit: [*:0]const u8,
+};
+
fn funcCommon(
sema: *Sema,
block: *Block,
src_node_offset: i32,
func_inst: Zir.Inst.Index,
- ret_ty_body: []const Zir.Inst.Index,
- cc: std.builtin.CallingConvention,
- align_val: Value,
+ /// null means generic poison
+ alignment: ?u32,
+ /// null means generic poison
+ address_space: ?std.builtin.AddressSpace,
+ /// outer null means generic poison; inner null means default link section
+ section: FuncLinkSection,
+ /// null means generic poison
+ cc: ?std.builtin.CallingConvention,
+ /// this might be Type.generic_poison
+ bare_return_type: Type,
var_args: bool,
inferred_error_set: bool,
is_extern: bool,
@@ -6618,42 +6699,15 @@ fn funcCommon(
) CompileError!Air.Inst.Ref {
const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };
- // The return type body might be a type expression that depends on generic parameters.
- // In such case we need to use a generic_poison value for the return type and mark
- // the function as generic.
- var is_generic = false;
- const bare_return_type: Type = ret_ty: {
- if (ret_ty_body.len == 0) break :ret_ty Type.void;
-
- const err = err: {
- // Make sure any nested param instructions don't clobber our work.
- const prev_params = block.params;
- block.params = .{};
- defer {
- block.params.deinit(sema.gpa);
- block.params = prev_params;
- }
- if (sema.resolveBody(block, ret_ty_body, func_inst)) |ret_ty_inst| {
- if (sema.analyzeAsType(block, ret_ty_src, ret_ty_inst)) |ret_ty| {
- break :ret_ty ret_ty;
- } else |err| break :err err;
- } else |err| break :err err;
- // Check for generic params.
- for (block.params.items) |param| {
- if (param.ty.tag() == .generic_poison) is_generic = true;
- }
- };
- switch (err) {
- error.GenericPoison => {
- // The type is not available until the generic instantiation.
- is_generic = true;
- break :ret_ty Type.initTag(.generic_poison);
- },
- else => |e| return e,
- }
- };
-
- const mod = sema.mod;
+ var is_generic = bare_return_type.tag() == .generic_poison or
+ alignment == null or
+ address_space == null or
+ section == .generic or
+ cc == null;
+ // Check for generic params.
+ for (block.params.items) |param| {
+ if (param.ty.tag() == .generic_poison) is_generic = true;
+ }
const new_func: *Module.Fn = new_func: {
if (!has_body) break :new_func undefined;
@@ -6670,36 +6724,28 @@ fn funcCommon(
errdefer if (maybe_inferred_error_set_node) |node| sema.gpa.destroy(node);
// Note: no need to errdefer since this will still be in its default state at the end of the function.
- const target = mod.getTarget();
-
+ const target = sema.mod.getTarget();
const fn_ty: Type = fn_ty: {
- const alignment: u32 = if (align_val.tag() == .null_value) 0 else a: {
- const alignment = @intCast(u32, align_val.toUnsignedInt(target));
- if (alignment == target_util.defaultFunctionAlignment(target)) {
- break :a 0;
- } else {
- break :a alignment;
- }
- };
-
// Hot path for some common function types.
// TODO can we eliminate some of these Type tag values? seems unnecessarily complicated.
- if (!is_generic and block.params.items.len == 0 and !var_args and
- alignment == 0 and !inferred_error_set)
+ if (!is_generic and block.params.items.len == 0 and !var_args and !inferred_error_set and
+ alignment.? == 0 and
+ address_space.? == target_util.defaultAddressSpace(target, .function) and
+ section == .default)
{
- if (bare_return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) {
+ if (bare_return_type.zigTypeTag() == .NoReturn and cc.? == .Unspecified) {
break :fn_ty Type.initTag(.fn_noreturn_no_args);
}
- if (bare_return_type.zigTypeTag() == .Void and cc == .Unspecified) {
+ if (bare_return_type.zigTypeTag() == .Void and cc.? == .Unspecified) {
break :fn_ty Type.initTag(.fn_void_no_args);
}
- if (bare_return_type.zigTypeTag() == .NoReturn and cc == .Naked) {
+ if (bare_return_type.zigTypeTag() == .NoReturn and cc.? == .Naked) {
break :fn_ty Type.initTag(.fn_naked_noreturn_no_args);
}
- if (bare_return_type.zigTypeTag() == .Void and cc == .C) {
+ if (bare_return_type.zigTypeTag() == .Void and cc.? == .C) {
break :fn_ty Type.initTag(.fn_ccc_void_no_args);
}
}
@@ -6745,17 +6791,35 @@ fn funcCommon(
});
};
+ // stage1 bug workaround
+ const cc_workaround = cc orelse undefined;
+ const align_workaround = alignment orelse @as(u32, undefined);
+
break :fn_ty try Type.Tag.function.create(sema.arena, .{
.param_types = param_types,
.comptime_params = comptime_params.ptr,
.return_type = return_type,
- .cc = cc,
- .alignment = alignment,
+ .cc = cc_workaround,
+ .cc_is_generic = cc == null,
+ .alignment = align_workaround,
+ .align_is_generic = alignment == null,
+ .section_is_generic = section == .generic,
+ .addrspace_is_generic = address_space == null,
.is_var_args = var_args,
.is_generic = is_generic,
});
};
+ if (sema.owner_decl.owns_tv) {
+ switch (section) {
+ .generic => sema.owner_decl.@"linksection" = undefined,
+ .default => sema.owner_decl.@"linksection" = null,
+ .explicit => |s| sema.owner_decl.@"linksection" = s,
+ }
+ if (alignment) |a| sema.owner_decl.@"align" = a;
+ if (address_space) |a| sema.owner_decl.@"addrspace" = a;
+ }
+
if (is_extern) {
const new_extern_fn = try sema.gpa.create(Module.ExternFn);
errdefer sema.gpa.destroy(new_extern_fn);
@@ -16750,16 +16814,20 @@ fn zirVarExtended(
return result;
}
-fn zirFuncExtended(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const tracy = trace(@src());
defer tracy.end();
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src = inst_data.src();
- const extra = sema.code.extraData(Zir.Inst.ExtendedFunc, inst_data.payload_index);
+ const extra = sema.code.extraData(Zir.Inst.FuncFancy, inst_data.payload_index);
+ const target = sema.mod.getTarget();
- const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = inst_data.src_node };
const align_src: LazySrcLoc = src; // TODO add a LazySrcLoc that points at align
+ const addrspace_src: LazySrcLoc = src; // TODO add a LazySrcLoc that points at addrspace
+ const section_src: LazySrcLoc = src; // TODO add a LazySrcLoc that points at section
+ const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = inst_data.src_node };
+ const ret_src: LazySrcLoc = src; // TODO add a LazySrcLoc that points at the return type
var extra_index: usize = extra.end;
@@ -16769,22 +16837,135 @@ fn zirFuncExtended(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
break :blk lib_name;
} else null;
- const cc: std.builtin.CallingConvention = if (extra.data.bits.has_cc) blk: {
+ const @"align": ?u32 = if (extra.data.bits.has_align_body) blk: {
+ const body_len = sema.code.extra[extra_index];
+ extra_index += 1;
+ const body = sema.code.extra[extra_index..][0..body_len];
+ extra_index += body.len;
+
+ const val = try sema.resolveGenericBody(block, align_src, body, inst, Type.u16);
+ if (val.tag() == .generic_poison) {
+ break :blk null;
+ }
+ const alignment = @intCast(u32, val.toUnsignedInt(target));
+ if (alignment == target_util.defaultFunctionAlignment(target)) {
+ break :blk 0;
+ } else {
+ break :blk alignment;
+ }
+ } else if (extra.data.bits.has_align_ref) blk: {
+ const align_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
+ extra_index += 1;
+ const align_tv = sema.resolveInstConst(block, align_src, align_ref) catch |err| switch (err) {
+ error.GenericPoison => {
+ break :blk null;
+ },
+ else => |e| return e,
+ };
+ const alignment = @intCast(u32, align_tv.val.toUnsignedInt(target));
+ if (alignment == target_util.defaultFunctionAlignment(target)) {
+ break :blk 0;
+ } else {
+ break :blk alignment;
+ }
+ } else 0;
+
+ const @"addrspace": ?std.builtin.AddressSpace = if (extra.data.bits.has_addrspace_body) blk: {
+ const body_len = sema.code.extra[extra_index];
+ extra_index += 1;
+ const body = sema.code.extra[extra_index..][0..body_len];
+ extra_index += body.len;
+
+ const addrspace_ty = try sema.getBuiltinType(block, addrspace_src, "AddressSpace");
+ const val = try sema.resolveGenericBody(block, addrspace_src, body, inst, addrspace_ty);
+ if (val.tag() == .generic_poison) {
+ break :blk null;
+ }
+ break :blk val.toEnum(std.builtin.AddressSpace);
+ } else if (extra.data.bits.has_addrspace_ref) blk: {
+ const addrspace_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
+ extra_index += 1;
+ const addrspace_tv = sema.resolveInstConst(block, addrspace_src, addrspace_ref) catch |err| switch (err) {
+ error.GenericPoison => {
+ break :blk null;
+ },
+ else => |e| return e,
+ };
+ break :blk addrspace_tv.val.toEnum(std.builtin.AddressSpace);
+ } else target_util.defaultAddressSpace(target, .function);
+
+ const @"linksection": FuncLinkSection = if (extra.data.bits.has_section_body) blk: {
+ const body_len = sema.code.extra[extra_index];
+ extra_index += 1;
+ const body = sema.code.extra[extra_index..][0..body_len];
+ extra_index += body.len;
+
+ const val = try sema.resolveGenericBody(block, section_src, body, inst, Type.initTag(.const_slice_u8));
+ if (val.tag() == .generic_poison) {
+ break :blk FuncLinkSection{ .generic = {} };
+ }
+ _ = val;
+ return sema.fail(block, section_src, "TODO implement linksection on functions", .{});
+ } else if (extra.data.bits.has_section_ref) blk: {
+ const section_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
+ extra_index += 1;
+ const section_tv = sema.resolveInstConst(block, section_src, section_ref) catch |err| switch (err) {
+ error.GenericPoison => {
+ break :blk FuncLinkSection{ .generic = {} };
+ },
+ else => |e| return e,
+ };
+ _ = section_tv;
+ return sema.fail(block, section_src, "TODO implement linksection on functions", .{});
+ } else FuncLinkSection{ .default = {} };
+
+ const cc: ?std.builtin.CallingConvention = if (extra.data.bits.has_cc_body) blk: {
+ const body_len = sema.code.extra[extra_index];
+ extra_index += 1;
+ const body = sema.code.extra[extra_index..][0..body_len];
+ extra_index += body.len;
+
+ const cc_ty = try sema.getBuiltinType(block, addrspace_src, "CallingConvention");
+ const val = try sema.resolveGenericBody(block, cc_src, body, inst, cc_ty);
+ if (val.tag() == .generic_poison) {
+ break :blk null;
+ }
+ break :blk val.toEnum(std.builtin.CallingConvention);
+ } else if (extra.data.bits.has_cc_ref) blk: {
const cc_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
extra_index += 1;
- const cc_tv = try sema.resolveInstConst(block, cc_src, cc_ref);
+ const cc_tv = sema.resolveInstConst(block, cc_src, cc_ref) catch |err| switch (err) {
+ error.GenericPoison => {
+ break :blk null;
+ },
+ else => |e| return e,
+ };
break :blk cc_tv.val.toEnum(std.builtin.CallingConvention);
- } else .Unspecified;
+ } else std.builtin.CallingConvention.Unspecified;
- const align_val: Value = if (extra.data.bits.has_align) blk: {
- const align_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
+ const ret_ty: Type = if (extra.data.bits.has_ret_ty_body) blk: {
+ const body_len = sema.code.extra[extra_index];
extra_index += 1;
- const align_tv = try sema.resolveInstConst(block, align_src, align_ref);
- break :blk align_tv.val;
- } else Value.@"null";
+ const body = sema.code.extra[extra_index..][0..body_len];
+ extra_index += body.len;
- const ret_ty_body = sema.code.extra[extra_index..][0..extra.data.ret_body_len];
- extra_index += ret_ty_body.len;
+ const val = try sema.resolveGenericBody(block, ret_src, body, inst, Type.type);
+ var buffer: Value.ToTypeBuffer = undefined;
+ const ty = try val.toType(&buffer).copy(sema.arena);
+ break :blk ty;
+ } else if (extra.data.bits.has_ret_ty_ref) blk: {
+ const ret_ty_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
+ extra_index += 1;
+ const ret_ty_tv = sema.resolveInstConst(block, ret_src, ret_ty_ref) catch |err| switch (err) {
+ error.GenericPoison => {
+ break :blk Type.initTag(.generic_poison);
+ },
+ else => |e| return e,
+ };
+ var buffer: Value.ToTypeBuffer = undefined;
+ const ty = try ret_ty_tv.val.toType(&buffer).copy(sema.arena);
+ break :blk ty;
+ } else Type.void;
var src_locs: Zir.Inst.Func.SrcLocs = undefined;
const has_body = extra.data.body_len != 0;
@@ -16801,9 +16982,11 @@ fn zirFuncExtended(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
block,
inst_data.src_node,
inst,
- ret_ty_body,
+ @"align",
+ @"addrspace",
+ @"linksection",
cc,
- align_val,
+ ret_ty,
is_var_args,
is_inferred_error,
is_extern,