diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2021-04-06 23:19:46 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2021-04-06 23:19:46 -0700 |
| commit | 19cf987198ff4de0b1460263a62ff6c41e1e3915 (patch) | |
| tree | 1acbb85972fbef799c1deb4de6a8c753b9b28a9e | |
| parent | acf9151008d5a97e5d91b34cc29f73af79062b48 (diff) | |
| download | zig-19cf987198ff4de0b1460263a62ff6c41e1e3915.tar.gz zig-19cf987198ff4de0b1460263a62ff6c41e1e3915.zip | |
C backend: implement Enum types and values
They are lowered directly as the integer tag type, with no typedef.
| -rw-r--r-- | src/Sema.zig | 19 | ||||
| -rw-r--r-- | src/codegen/c.zig | 37 | ||||
| -rw-r--r-- | src/type.zig | 6 |
3 files changed, 53 insertions, 9 deletions
diff --git a/src/Sema.zig b/src/Sema.zig index 8ff71ce8f2..115ca11858 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -1918,11 +1918,20 @@ fn zirEnumToInt(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErr switch (enum_tag.ty.tag()) { .enum_full => { const enum_full = enum_tag.ty.castTag(.enum_full).?.data; - const val = enum_full.values.entries.items[field_index].key; - return mod.constInst(arena, src, .{ - .ty = int_tag_ty, - .val = val, - }); + if (enum_full.values.count() != 0) { + const val = enum_full.values.entries.items[field_index].key; + return mod.constInst(arena, src, .{ + .ty = int_tag_ty, + .val = val, + }); + } else { + // Field index and integer values are the same. + const val = try Value.Tag.int_u64.create(arena, field_index); + return mod.constInst(arena, src, .{ + .ty = int_tag_ty, + .val = val, + }); + } }, .enum_simple => { // Field index and integer values are the same. diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 876f86ed02..d5d18baa1c 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -172,7 +172,10 @@ pub const DeclGen = struct { val: Value, ) error{ OutOfMemory, AnalysisFail }!void { if (val.isUndef()) { - return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: properly handle undefined in all cases (with debug safety?)", .{}); + // This should lower to 0xaa bytes in safe modes, and for unsafe modes should + // lower to leaving variables uninitialized (that might need to be implemented + // outside of this function). + return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement renderValue undef", .{}); } switch (t.zigTypeTag()) { .Int => { @@ -288,6 +291,31 @@ pub const DeclGen = struct { try writer.writeAll(", .error = 0 }"); } }, + .Enum => { + switch (val.tag()) { + .enum_field_index => { + const field_index = val.castTag(.enum_field_index).?.data; + switch (t.tag()) { + .enum_simple => return writer.print("{d}", .{field_index}), + .enum_full, .enum_nonexhaustive => { + const enum_full = t.cast(Type.Payload.EnumFull).?.data; + if (enum_full.values.count() != 0) { + const tag_val = enum_full.values.entries.items[field_index].key; + return dg.renderValue(writer, enum_full.tag_ty, tag_val); + } else { + return writer.print("{d}", .{field_index}); + } + }, + else => unreachable, + } + }, + else => { + var int_tag_ty_buffer: Type.Payload.Bits = undefined; + const int_tag_ty = t.intTagType(&int_tag_ty_buffer); + return dg.renderValue(writer, int_tag_ty, val); + }, + } + }, else => |e| return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement value {s}", .{ @tagName(e), }), @@ -472,6 +500,13 @@ pub const DeclGen = struct { try w.writeAll(name); dg.typedefs.putAssumeCapacityNoClobber(t, .{ .name = name, .rendered = rendered }); }, + .Enum => { + // For enums, we simply use the integer tag type. + var int_tag_ty_buffer: Type.Payload.Bits = undefined; + const int_tag_ty = t.intTagType(&int_tag_ty_buffer); + + try dg.renderType(w, int_tag_ty); + }, .Null, .Undefined => unreachable, // must be const or comptime else => |e| return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type {s}", .{ @tagName(e), diff --git a/src/type.zig b/src/type.zig index 576dc46e7e..6173c0b800 100644 --- a/src/type.zig +++ b/src/type.zig @@ -691,7 +691,7 @@ pub const Type = extern union { return struct_obj.owner_decl.renderFullyQualifiedName(writer); }, .enum_full, .enum_nonexhaustive => { - const enum_full = ty.castTag(.enum_full).?.data; + const enum_full = ty.cast(Payload.EnumFull).?.data; return enum_full.owner_decl.renderFullyQualifiedName(writer); }, .enum_simple => { @@ -1344,7 +1344,7 @@ pub const Type = extern union { /// Asserts the type is an enum. pub fn intTagType(self: Type, buffer: *Payload.Bits) Type { switch (self.tag()) { - .enum_full, .enum_nonexhaustive => return self.castTag(.enum_full).?.data.tag_ty, + .enum_full, .enum_nonexhaustive => return self.cast(Payload.EnumFull).?.data.tag_ty, .enum_simple => { const enum_simple = self.castTag(.enum_simple).?.data; const bits = std.math.log2_int_ceil(usize, enum_simple.fields.count()); @@ -1969,7 +1969,7 @@ pub const Type = extern union { return null; } }, - .enum_nonexhaustive => ty = ty.castTag(.enum_full).?.data.tag_ty, + .enum_nonexhaustive => ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty, .empty_struct, .empty_struct_literal => return Value.initTag(.empty_struct_value), .void => return Value.initTag(.void_value), |
