diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2021-05-06 22:30:44 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2021-05-06 22:30:44 -0700 |
| commit | a7221ef4e902e63e72524559a067afcf6c1dfd17 (patch) | |
| tree | e3cbbbd7bd87409c8da573ecefa7174939ed8020 | |
| parent | 3acd98fa3423d67cdce7118bc6abe736309e71df (diff) | |
| download | zig-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_TODO | 3 | ||||
| -rw-r--r-- | lib/std/start.zig | 6 | ||||
| -rw-r--r-- | src/Sema.zig | 39 | ||||
| -rw-r--r-- | src/type.zig | 2 | ||||
| -rw-r--r-- | src/value.zig | 20 |
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 |
