diff --git a/src/aro/CodeGen.zig b/src/aro/CodeGen.zig index 21fb6a8d..49b07a7e 100644 --- a/src/aro/CodeGen.zig +++ b/src/aro/CodeGen.zig @@ -146,7 +146,7 @@ fn genType(c: *CodeGen, qt: QualType) !Interner.Ref { .func => return .func, .complex => return c.fail("TODO lower complex types", .{}), .atomic => return c.fail("TODO lower atomic types", .{}), - .@"enum" => |@"enum"| return c.genType(@"enum".tag), + .@"enum" => |@"enum"| return c.genType(@"enum".tag.?), .int => |int| .{ .int_ty = int.bits(c.comp) }, .bit_int => |bit_int| .{ .int_ty = bit_int.bits }, .float => |float| .{ .float_ty = float.bits(c.comp) }, diff --git a/src/aro/Parser.zig b/src/aro/Parser.zig index 1750424d..be7fb0d7 100644 --- a/src/aro/Parser.zig +++ b/src/aro/Parser.zig @@ -837,6 +837,7 @@ fn addImplicitTypedef(p: *Parser, name: []const u8, qt: QualType) !void { const typedef_qt = (try p.comp.type_store.put(p.gpa, .{ .typedef = .{ .base = qt, .name = interned_name, + .decl_node = node, } })).withQualifiers(qt); try p.syms.defineTypedef(p, interned_name, typedef_qt, name_tok, node); try p.decl_buf.append(node); @@ -1295,6 +1296,7 @@ fn decl(p: *Parser) Error!bool { (try p.comp.type_store.put(p.gpa, .{ .typedef = .{ .base = init_d.d.qt, .name = interned_name, + .decl_node = decl_node, } })).withQualifiers(init_d.d.qt); try p.syms.defineTypedef(p, interned_name, typedef_qt, init_d.d.name, decl_node); p.typedefDefined(interned_name, typedef_qt); @@ -2244,6 +2246,8 @@ fn recordSpec(p: *Parser) Error!QualType { defer p.attr_buf.len = attr_buf_top; try p.attributeSpecifier(); + const reserved_index = try p.tree.nodes.addOne(p.gpa); + const maybe_ident = try p.eatIdentifier(); const l_brace = p.eatToken(.l_brace) orelse { const ident = maybe_ident orelse { @@ -2259,6 +2263,7 @@ fn recordSpec(p: *Parser) Error!QualType { const record_ty: Type.Record = .{ .name = interned_name, .layout = null, + .decl_node = @enumFromInt(reserved_index), .fields = &.{}, }; const record_qt = try p.comp.type_store.put(p.gpa, if (is_struct) @@ -2280,10 +2285,11 @@ fn recordSpec(p: *Parser) Error!QualType { .container_qt = attributed_qt, .definition = null, }; - try p.decl_buf.append(try p.addNode(if (is_struct) + try p.tree.setNode(if (is_struct) .{ .struct_forward_decl = fw } else - .{ .union_forward_decl = fw })); + .{ .union_forward_decl = fw }, reserved_index); + try p.decl_buf.append(@enumFromInt(reserved_index)); return attributed_qt; } }; @@ -2313,6 +2319,7 @@ fn recordSpec(p: *Parser) Error!QualType { // can be specified after the closing rbrace, which we haven't encountered yet. const record_ty: Type.Record = .{ .name = interned_name, + .decl_node = @enumFromInt(reserved_index), .layout = null, .fields = &.{}, }; @@ -2336,8 +2343,7 @@ fn recordSpec(p: *Parser) Error!QualType { break :blk .{ record_ty, record_qt }; }; - // reserve space for this record - try p.decl_buf.append(undefined); + try p.decl_buf.append(@enumFromInt(reserved_index)); const decl_buf_top = p.decl_buf.items.len; const record_buf_top = p.record_buf.items.len; errdefer p.decl_buf.items.len = decl_buf_top - 1; @@ -2385,6 +2391,7 @@ fn recordSpec(p: *Parser) Error!QualType { .pointer_alignment_bits = 8, .required_alignment_bits = 8, }; + record_ty.decl_node = @enumFromInt(reserved_index); const base_type = qt.base(p.comp); if (is_struct) { @@ -2431,6 +2438,7 @@ fn recordSpec(p: *Parser) Error!QualType { const field_size = 10; comptime std.debug.assert(@sizeOf(Type.Record.Field) == @sizeOf(u32) * field_size); + extra_index += 1; // For decl_node const casted_layout: *const [layout_size]u32 = @ptrCast(&record_ty.layout); ts.extra.items[extra_index..][0..layout_size].* = casted_layout.*; extra_index += layout_size; @@ -2449,7 +2457,7 @@ fn recordSpec(p: *Parser) Error!QualType { .container_qt = attributed_qt, .fields = p.decl_buf.items[decl_buf_top..], }; - p.decl_buf.items[decl_buf_top - 1] = try p.addNode(if (is_struct) .{ .struct_decl = cd } else .{ .union_decl = cd }); + try p.tree.setNode(if (is_struct) .{ .struct_decl = cd } else .{ .union_decl = cd }, reserved_index); if (p.func.qt == null) { _ = p.tentative_defs.remove(record_ty.name); } @@ -2724,6 +2732,8 @@ fn enumSpec(p: *Parser) Error!QualType { break :fixed fixed; } else null; + const reserved_index = try p.tree.nodes.addOne(p.gpa); + const l_brace = p.eatToken(.l_brace) orelse { const ident = maybe_ident orelse { try p.err(.ident_or_l_brace); @@ -2739,9 +2749,10 @@ fn enumSpec(p: *Parser) Error!QualType { } else { const enum_qt = try p.comp.type_store.put(p.gpa, .{ .@"enum" = .{ .name = interned_name, - .tag = fixed_qt orelse .int, + .tag = fixed_qt, .fixed = fixed_qt != null, .incomplete = true, + .decl_node = @enumFromInt(reserved_index), .fields = &.{}, } }); @@ -2791,7 +2802,8 @@ fn enumSpec(p: *Parser) Error!QualType { // can be specified after the closing rbrace, which we haven't encountered yet. const enum_ty: Type.Enum = .{ .name = interned_name, - .tag = fixed_qt orelse undefined, + .decl_node = @enumFromInt(reserved_index), + .tag = fixed_qt, .incomplete = true, .fixed = fixed_qt != null, .fields = &.{}, @@ -2845,8 +2857,8 @@ fn enumSpec(p: *Parser) Error!QualType { some else if (try res.intFitsInType(p, .int)) .int - else if (!res.qt.eql(enum_ty.tag, p.comp)) - enum_ty.tag + else if (!res.qt.eql(enum_ty.tag.?, p.comp)) + enum_ty.tag.? else continue; @@ -2861,10 +2873,9 @@ fn enumSpec(p: *Parser) Error!QualType { var new_field_node = field_node.get(&p.tree); new_field_node.enum_field.qt = dest_ty; - if (field.init.unpack()) |some| { + if (new_field_node.enum_field.init) |some| { res.node = some; try res.implicitCast(p, .int_cast, some.tok(&p.tree)); - field.init = .pack(res.node); new_field_node.enum_field.init = res.node; } @@ -2875,6 +2886,7 @@ fn enumSpec(p: *Parser) Error!QualType { { // Override previous incomplete type enum_ty.fields = enum_fields; enum_ty.incomplete = false; + enum_ty.decl_node = @enumFromInt(reserved_index); const base_type = attributed_qt.base(p.comp); std.debug.assert(base_type.type.@"enum".name == enum_ty.name); try p.comp.type_store.set(p.gpa, .{ .@"enum" = enum_ty }, @intFromEnum(base_type.qt._index)); @@ -2914,8 +2926,8 @@ fn checkEnumFixedTy(p: *Parser, fixed_qt: ?QualType, ident_tok: TokenIndex, prev return error.ParsingFailed; } - if (!enum_ty.tag.eql(some, p.comp)) { - const str = try p.typePairStrExtra(some, " (was ", enum_ty.tag); + if (!enum_ty.tag.?.eql(some, p.comp)) { + const str = try p.typePairStrExtra(some, " (was ", enum_ty.tag.?); try p.errStr(.enum_different_explicit_ty, ident_tok, str); try p.errTok(.previous_definition, prev.tok); return error.ParsingFailed; @@ -3099,7 +3111,6 @@ fn enumerator(p: *Parser, e: *Enumerator) Error!?EnumFieldAndNode { .name = interned_name, .qt = attributed_qt, .name_tok = name_tok, - .init = .packOpt(field_init), }, .node = node }; } @@ -5498,7 +5509,7 @@ const CallExpr = union(enum) { if (p.list_buf.items.len != 3) return .invalid; // wrong number of arguments; already an error const first_param = p.list_buf.items[1]; const qt = first_param.qt(&p.tree); - if (!qt.scalarKind(p.comp).isPointer()) return .invalid; + if (!qt.isPointer(p.comp)) return .invalid; return qt.childType(p.comp); }, diff --git a/src/aro/TypeStore.zig b/src/aro/TypeStore.zig index 6b2a268e..48355f67 100644 --- a/src/aro/TypeStore.zig +++ b/src/aro/TypeStore.zig @@ -288,12 +288,13 @@ pub const QualType = packed struct(u32) { comptime std.debug.assert(@sizeOf(Type.Record.Field) == @sizeOf(u32) * field_size); const extra = comp.type_store.extra.items; - const layout = @as(*Type.Record.Layout, @alignCast(@ptrCast(extra[repr.data[1]..][0..layout_size]))).*; - const fields_len = extra[repr.data[1] + layout_size] * field_size; - const extra_fields = extra[repr.data[1] + layout_size + 1 ..][0..fields_len]; + const layout = @as(*Type.Record.Layout, @ptrCast(extra[repr.data[1] + 1 ..][0..layout_size])).*; + const fields_len = extra[repr.data[1] + layout_size + 1]; + const extra_fields = extra[repr.data[1] + layout_size + 2 ..][0 .. fields_len * field_size]; const record: Type.Record = .{ .name = @enumFromInt(repr.data[0]), + .decl_node = @enumFromInt(extra[repr.data[1]]), .layout = layout, .fields = std.mem.bytesAsSlice(Type.Record.Field, std.mem.sliceAsBytes(extra_fields)), }; @@ -305,37 +306,53 @@ pub const QualType = packed struct(u32) { }, .struct_incomplete => .{ .@"struct" = .{ .name = @enumFromInt(repr.data[0]), + .decl_node = @enumFromInt(repr.data[1]), .layout = null, .fields = &.{}, } }, .union_incomplete => .{ .@"union" = .{ .name = @enumFromInt(repr.data[0]), + .decl_node = @enumFromInt(repr.data[1]), .layout = null, .fields = &.{}, } }, .@"enum", .enum_fixed => { const extra = comp.type_store.extra.items; - const field_size = 4; + const field_size = 3; comptime std.debug.assert(@sizeOf(Type.Enum.Field) == @sizeOf(u32) * field_size); - const fields_len = extra[repr.data[1] + 1] * field_size; - const extra_fields = extra[repr.data[1] + 2 ..][0..fields_len]; + const fields_len = extra[repr.data[1] + 2]; + const extra_fields = extra[repr.data[1] + 3 ..][0 .. fields_len * field_size]; return .{ .@"enum" = .{ .name = @enumFromInt(extra[repr.data[1]]), + .decl_node = @enumFromInt(extra[repr.data[1] + 1]), .tag = @bitCast(repr.data[0]), .incomplete = false, .fixed = repr.tag == .enum_fixed, .fields = std.mem.bytesAsSlice(Type.Enum.Field, std.mem.sliceAsBytes(extra_fields)), } }; }, - .enum_incomplete, .enum_incomplete_fixed => .{ .@"enum" = .{ - .name = @enumFromInt(repr.data[1]), - .tag = @bitCast(repr.data[0]), - .incomplete = true, - .fixed = repr.tag == .enum_incomplete_fixed, - .fields = &.{}, - } }, + .enum_incomplete => .{ + .@"enum" = .{ + .tag = null, + .name = @enumFromInt(repr.data[0]), + .decl_node = @enumFromInt(repr.data[1]), + .incomplete = true, + .fixed = false, + .fields = &.{}, + }, + }, + .enum_incomplete_fixed => .{ + .@"enum" = .{ + .tag = @bitCast(repr.data[0]), + .name = @enumFromInt(comp.type_store.extra.items[repr.data[1]]), + .decl_node = @enumFromInt(comp.type_store.extra.items[repr.data[1] + 1]), + .incomplete = true, + .fixed = true, + .fields = &.{}, + }, + }, .typeof => .{ .typeof = .{ .base = @bitCast(repr.data[0]), .expr = null, @@ -346,7 +363,8 @@ pub const QualType = packed struct(u32) { } }, .typedef => .{ .typedef = .{ .base = @bitCast(repr.data[0]), - .name = @enumFromInt(repr.data[1]), + .name = @enumFromInt(comp.type_store.extra.items[repr.data[1]]), + .decl_node = @enumFromInt(comp.type_store.extra.items[repr.data[1] + 1]), } }, .attributed => { const extra = comp.type_store.extra.items; @@ -399,11 +417,9 @@ pub const QualType = packed struct(u32) { if (qt.isInvalid()) return .invalid; return switch (qt.base(comp).type) { .complex => |complex| complex, - .func => |func| func.return_type, .pointer => |pointer| pointer.child, .array => |array| array.elem, .vector => |vector| vector.elem, - .@"enum" => |@"enum"| @"enum".tag, else => unreachable, }; } @@ -485,8 +501,8 @@ pub const QualType = packed struct(u32) { return layout.size_bits / 8; }, .@"enum" => |enum_ty| { - if (enum_ty.incomplete and !enum_ty.fixed) return null; - continue :loop enum_ty.tag.base(comp).type; + const tag = enum_ty.tag orelse return null; + continue :loop tag.base(comp).type; }, .typeof => unreachable, .typedef => unreachable, @@ -622,8 +638,8 @@ pub const QualType = packed struct(u32) { return layout.field_alignment_bits / 8; }, .@"enum" => |enum_ty| { - if (enum_ty.incomplete and !enum_ty.fixed) return 0; - continue :loop enum_ty.tag.base(comp).type; + const tag = enum_ty.tag orelse return 0; + continue :loop tag.base(comp).type; }, .typeof => unreachable, .typedef => unreachable, @@ -789,7 +805,7 @@ pub const QualType = packed struct(u32) { }, .complex => |complex| continue :loop complex.base(comp).type, .atomic => |atomic| continue :loop atomic.base(comp).type, - .@"enum" => |enum_ty| continue :loop enum_ty.tag.base(comp).type, + .@"enum" => |enum_ty| continue :loop enum_ty.tag.?.base(comp).type, else => unreachable, }; } @@ -825,7 +841,9 @@ pub const QualType = packed struct(u32) { pub fn promoteInt(qt: QualType, comp: *const Compilation) QualType { return loop: switch (qt.base(comp).type) { .bool => return .int, - .@"enum" => |enum_ty| continue :loop enum_ty.tag.base(comp).type, + .@"enum" => |enum_ty| if (enum_ty.tag) |tag| { + continue :loop tag.base(comp).type; + } else return .int, .bit_int => return qt, .complex => return qt, // Assume complex integer type .int => |int_ty| switch (int_ty) { @@ -961,9 +979,9 @@ pub const QualType = packed struct(u32) { // Alignment check also guards against comparing incomplete enums to ints. if (a_type_qt.qt.alignof(comp) != b_type_qt.qt.alignof(comp)) return false; if (a_type == .@"enum" and b_type != .@"enum") { - return a_type.@"enum".tag.eql(b_qt, comp); + return a_type.@"enum".tag.?.eql(b_qt, comp); } else if (a_type != .@"enum" and b_type == .@"enum") { - return b_type.@"enum".tag.eql(a_qt, comp); + return b_type.@"enum".tag.?.eql(a_qt, comp); } if (std.meta.activeTag(a_type) != b_type) return false; @@ -1244,7 +1262,7 @@ pub const QualType = packed struct(u32) { .@"union" => |union_ty| try w.print("union {s}", .{union_ty.name.lookup(comp)}), .@"enum" => |enum_ty| if (enum_ty.fixed) { try w.print("enum {s}: ", .{enum_ty.name.lookup(comp)}); - _ = try enum_ty.tag.printPrologue(comp, w); + _ = try enum_ty.tag.?.printPrologue(comp, w); } else { try w.print("enum {s}", .{enum_ty.name.lookup(comp)}); }, @@ -1374,7 +1392,11 @@ pub const QualType = packed struct(u32) { }, .@"enum" => |enum_ty| { try w.print("enum {s}: ", .{enum_ty.name.lookup(comp)}); - try enum_ty.tag.dump(comp, w); + if (enum_ty.tag) |some| { + try some.dump(comp, w); + } else { + try w.writeAll(""); + } }, else => try qt.unqualified().print(comp, w), } @@ -1510,6 +1532,7 @@ pub const Type = union(enum) { pub const Record = struct { name: StringId, + decl_node: Node.Index, layout: ?Layout = null, fields: []const Field, @@ -1596,17 +1619,18 @@ pub const Type = union(enum) { }; pub const Enum = struct { - tag: QualType, + /// Null if the enum is incomplete and not fixed. + tag: ?QualType, fixed: bool, incomplete: bool, name: StringId, + decl_node: Node.Index, fields: []const Field, pub const Field = extern struct { qt: QualType, name: StringId, name_tok: TokenIndex, - init: Node.OptIndex, }; }; @@ -1618,6 +1642,7 @@ pub const Type = union(enum) { pub const TypeDef = struct { base: QualType, name: StringId, + decl_node: Node.Index, }; pub const Attributed = struct { @@ -1801,6 +1826,7 @@ pub fn set(ts: *TypeStore, gpa: std.mem.Allocator, ty: Type, index: usize) !void .@"union" => .union_incomplete, else => unreachable, }; + repr.data[1] = @intFromEnum(record.decl_node); break :record; }; repr.tag = switch (ty) { @@ -1816,8 +1842,9 @@ pub fn set(ts: *TypeStore, gpa: std.mem.Allocator, ty: Type, index: usize) !void comptime std.debug.assert(@sizeOf(Type.Record.Layout) == @sizeOf(u32) * layout_size); const field_size = 10; comptime std.debug.assert(@sizeOf(Type.Record.Field) == @sizeOf(u32) * field_size); - try ts.extra.ensureUnusedCapacity(gpa, record.fields.len * field_size + layout_size + 1); + try ts.extra.ensureUnusedCapacity(gpa, record.fields.len * field_size + layout_size + 2); + ts.extra.appendAssumeCapacity(@intFromEnum(record.decl_node)); const casted_layout: *const [layout_size]u32 = @ptrCast(&layout); ts.extra.appendSliceAssumeCapacity(casted_layout); ts.extra.appendAssumeCapacity(@intCast(record.fields.len)); @@ -1828,23 +1855,35 @@ pub fn set(ts: *TypeStore, gpa: std.mem.Allocator, ty: Type, index: usize) !void } }, .@"enum" => |@"enum"| @"enum": { - repr.data[0] = @bitCast(@"enum".tag); if (@"enum".incomplete) { std.debug.assert(@"enum".fields.len == 0); - repr.tag = if (@"enum".fixed) .enum_incomplete_fixed else .enum_incomplete; - repr.data[1] = @intFromEnum(@"enum".name); + if (@"enum".fixed) { + repr.tag = .enum_incomplete_fixed; + repr.data[0] = @bitCast(@"enum".tag.?); + repr.data[1] = @intCast(ts.extra.items.len); + try ts.extra.appendSlice(gpa, &.{ + @intFromEnum(@"enum".name), + @intFromEnum(@"enum".decl_node), + }); + } else { + repr.tag = .enum_incomplete; + repr.data[0] = @intFromEnum(@"enum".name); + repr.data[1] = @intFromEnum(@"enum".decl_node); + } break :@"enum"; } repr.tag = if (@"enum".fixed) .enum_fixed else .@"enum"; + repr.data[0] = @bitCast(@"enum".tag.?); const extra_index: u32 = @intCast(ts.extra.items.len); repr.data[1] = extra_index; - const field_size = 4; + const field_size = 3; comptime std.debug.assert(@sizeOf(Type.Enum.Field) == @sizeOf(u32) * field_size); - try ts.extra.ensureUnusedCapacity(gpa, @"enum".fields.len * field_size + 1 + 1); + try ts.extra.ensureUnusedCapacity(gpa, @"enum".fields.len * field_size + 3); ts.extra.appendAssumeCapacity(@intFromEnum(@"enum".name)); + ts.extra.appendAssumeCapacity(@intFromEnum(@"enum".decl_node)); ts.extra.appendAssumeCapacity(@intCast(@"enum".fields.len)); for (@"enum".fields) |*field| { @@ -1864,7 +1903,11 @@ pub fn set(ts: *TypeStore, gpa: std.mem.Allocator, ty: Type, index: usize) !void .typedef => |typedef| { repr.tag = .typedef; repr.data[0] = @bitCast(typedef.base); - repr.data[1] = @intFromEnum(typedef.name); + repr.data[1] = @intCast(ts.extra.items.len); + try ts.extra.appendSlice(gpa, &.{ + @intFromEnum(typedef.name), + @intFromEnum(typedef.decl_node), + }); }, .attributed => |attributed| { repr.data[0] = @bitCast(attributed.base); @@ -1941,6 +1984,7 @@ fn generateNsConstantStringType(ts: *TypeStore, comp: *Compilation) !QualType { var record: Type.Record = .{ .name = try comp.internString("__NSConstantString_tag"), .layout = null, + .decl_node = undefined, // TODO .fields = &.{}, }; const qt = try ts.put(comp.gpa, .{ .@"struct" = record }); @@ -1983,6 +2027,7 @@ fn generateVaListType(ts: *TypeStore, comp: *Compilation) !QualType { .aarch64_va_list => blk: { var record: Type.Record = .{ .name = try comp.internString("__va_list_tag"), + .decl_node = undefined, // TODO .layout = null, .fields = &.{}, }; @@ -2004,6 +2049,7 @@ fn generateVaListType(ts: *TypeStore, comp: *Compilation) !QualType { .x86_64_va_list => blk: { var record: Type.Record = .{ .name = try comp.internString("__va_list_tag"), + .decl_node = undefined, // TODO .layout = null, .fields = &.{}, };