Sema: implement @typeInfo for functions

The goal is to get start code to be able to inspect the calling
convention of `main` in order to determine whether to export a main for
libc to call, or to allow the root source file to do it.
This commit is contained in:
Andrew Kelley 2021-05-06 22:30:44 -07:00
parent 3acd98fa34
commit a7221ef4e9
5 changed files with 66 additions and 4 deletions

View File

@ -5,6 +5,9 @@
* modify stage2 CBE tests so that only 1 uses pub export main and the
rest use pub fn main
* get the test runner and `zig test` working
* get behavior tests passing for stage2
* use a hash map for instructions because the array is too big
- no, actually modify the Zir.Inst.Ref strategy so that each decl gets
their indexes starting at 0 so that we can use an array to store Sema

View File

@ -28,8 +28,10 @@ comptime {
// self-hosted is capable enough to handle all of the real start.zig logic.
if (builtin.zig_is_stage2) {
if (builtin.output_mode == .Exe) {
if (builtin.link_libc or builtin.object_format == .c) {
@export(main2, .{ .name = "main" });
if ((builtin.link_libc or builtin.object_format == .c) and @hasDecl(root, "main")) {
if (@typeInfo(@TypeOf(root.main)).Fn.calling_convention != .C) {
@export(main2, .{ .name = "main" });
}
} else {
if (!@hasDecl(root, "_start")) {
@export(_start2, .{ .name = "_start" });

View File

@ -4708,7 +4708,44 @@ fn zirBuiltinSrc(
fn zirTypeInfo(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const src = inst_data.src();
return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirTypeInfo", .{});
const ty = try sema.resolveType(block, src, inst_data.operand);
const type_info_ty = try sema.getBuiltinType(block, src, "TypeInfo");
const target = sema.mod.getTarget();
switch (ty.zigTypeTag()) {
.Fn => {
const field_values = try sema.arena.alloc(Value, 6);
// calling_convention: CallingConvention,
field_values[0] = try Value.Tag.enum_field_index.create(
sema.arena,
@enumToInt(ty.fnCallingConvention()),
);
// alignment: comptime_int,
field_values[1] = try Value.Tag.int_u64.create(sema.arena, ty.ptrAlignment(target));
// is_generic: bool,
field_values[2] = Value.initTag(.bool_false); // TODO
// is_var_args: bool,
field_values[3] = Value.initTag(.bool_false); // TODO
// return_type: ?type,
field_values[4] = try Value.Tag.ty.create(sema.arena, ty.fnReturnType());
// args: []const FnArg,
field_values[5] = Value.initTag(.null_value); // TODO
return sema.mod.constInst(sema.arena, src, .{
.ty = type_info_ty,
.val = try Value.Tag.@"union".create(sema.arena, .{
.tag = try Value.Tag.enum_field_index.create(
sema.arena,
@enumToInt(@typeInfo(std.builtin.TypeInfo).Union.tag_type.?.Fn),
),
.val = try Value.Tag.@"struct".create(sema.arena, field_values.ptr),
}),
});
},
else => |t| return sema.mod.fail(&block.base, src, "TODO: implement zirTypeInfo for {s}", .{
@tagName(t),
}),
}
}
fn zirTypeof(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {

View File

@ -1214,7 +1214,7 @@ pub const Type = extern union {
if (ptr_info.@"align" != 0) {
return ptr_info.@"align";
} else {
return ptr_info.pointee_type.abiAlignment();
return ptr_info.pointee_type.abiAlignment(target);
}
},

View File

@ -120,6 +120,8 @@ pub const Value = extern union {
error_union,
/// An instance of a struct.
@"struct",
/// An instance of a union.
@"union",
/// This is a special value that tracks a set of types that have been stored
/// to an inferred allocation. It does not support any of the normal value queries.
inferred_alloc,
@ -228,6 +230,7 @@ pub const Value = extern union {
.@"error" => Payload.Error,
.inferred_alloc => Payload.InferredAlloc,
.@"struct" => Payload.Struct,
.@"union" => Payload.Union,
};
}
@ -446,6 +449,7 @@ pub const Value = extern union {
return Value{ .ptr_otherwise = &new_payload.base };
},
.@"struct" => @panic("TODO can't copy struct value without knowing the type"),
.@"union" => @panic("TODO can't copy union value without knowing the type"),
.inferred_alloc => unreachable,
}
@ -528,6 +532,9 @@ pub const Value = extern union {
.@"struct" => {
return out_stream.writeAll("(struct value)");
},
.@"union" => {
return out_stream.writeAll("(union value)");
},
.null_value => return out_stream.writeAll("null"),
.undef => return out_stream.writeAll("undefined"),
.zero => return out_stream.writeAll("0"),
@ -709,6 +716,7 @@ pub const Value = extern union {
.error_union,
.empty_struct_value,
.@"struct",
.@"union",
.inferred_alloc,
.abi_align_default,
=> unreachable,
@ -1225,6 +1233,7 @@ pub const Value = extern union {
.export_options_type,
.extern_options_type,
.@"struct",
.@"union",
=> @panic("TODO this hash function looks pretty broken. audit it"),
}
return hasher.final();
@ -1413,6 +1422,7 @@ pub const Value = extern union {
.error_union,
.empty_struct_value,
.@"struct",
.@"union",
.null_value,
.abi_align_default,
=> false,
@ -1564,6 +1574,16 @@ pub const Value = extern union {
/// Field values. The number and type are according to the struct type.
data: [*]Value,
};
pub const Union = struct {
pub const base_tag = Tag.@"union";
base: Payload = .{ .tag = base_tag },
data: struct {
tag: Value,
val: Value,
},
};
};
/// Big enough to fit any non-BigInt value