aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-05-06 22:30:44 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-05-06 22:30:44 -0700
commita7221ef4e902e63e72524559a067afcf6c1dfd17 (patch)
treee3cbbbd7bd87409c8da573ecefa7174939ed8020
parent3acd98fa3423d67cdce7118bc6abe736309e71df (diff)
downloadzig-a7221ef4e902e63e72524559a067afcf6c1dfd17.tar.gz
zig-a7221ef4e902e63e72524559a067afcf6c1dfd17.zip
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.
-rw-r--r--BRANCH_TODO3
-rw-r--r--lib/std/start.zig6
-rw-r--r--src/Sema.zig39
-rw-r--r--src/type.zig2
-rw-r--r--src/value.zig20
5 files changed, 66 insertions, 4 deletions
diff --git a/BRANCH_TODO b/BRANCH_TODO
index 53faf82205..87fd335803 100644
--- a/BRANCH_TODO
+++ b/BRANCH_TODO
@@ -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
diff --git a/lib/std/start.zig b/lib/std/start.zig
index d34c7365a9..d9ec173bbc 100644
--- a/lib/std/start.zig
+++ b/lib/std/start.zig
@@ -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" });
diff --git a/src/Sema.zig b/src/Sema.zig
index 5b2dc339f6..eb9400e7b1 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -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 {
diff --git a/src/type.zig b/src/type.zig
index bf4b3f7b64..f492eeb3ec 100644
--- a/src/type.zig
+++ b/src/type.zig
@@ -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);
}
},
diff --git a/src/value.zig b/src/value.zig
index e6ce65a9f4..2c7002402b 100644
--- a/src/value.zig
+++ b/src/value.zig
@@ -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