authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2024-09-08 14:23:03+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2024-09-09 12:35:49+03:00
logde8cece6e7be570a7e622c54c0cbbc7c99308a08
treeabf91cfa0c3d74725a6a6c17496a9999dcd99d81
parent9e6d167bb7878682e99482bfaef12e45376665f9

sync Aro dependency

ref: adfd13c6ffb563b1379052b92f6ae4148b91cc12

35 files changed, 2281 insertions(+), 794 deletions(-)

lib/compiler/aro/aro.zig+1
...@@ -23,6 +23,7 @@ pub const version_str = backend.version_str;...@@ -23,6 +23,7 @@ pub const version_str = backend.version_str;
23pub const version = backend.version;23pub const version = backend.version;
2424
25test {25test {
26 _ = @import("aro/annex_g.zig");
26 _ = @import("aro/Builtins.zig");27 _ = @import("aro/Builtins.zig");
27 _ = @import("aro/char_info.zig");28 _ = @import("aro/char_info.zig");
28 _ = @import("aro/Compilation.zig");29 _ = @import("aro/Compilation.zig");
lib/compiler/aro/aro/Attribute.zig+97-47
...@@ -38,12 +38,64 @@ pub const Kind = enum {...@@ -38,12 +38,64 @@ pub const Kind = enum {
38 }38 }
39};39};
4040
41pub const Iterator = struct {
42 source: union(enum) {
43 ty: Type,
44 slice: []const Attribute,
45 },
46 index: usize,
47
48 pub fn initSlice(slice: ?[]const Attribute) Iterator {
49 return .{ .source = .{ .slice = slice orelse &.{} }, .index = 0 };
50 }
51
52 pub fn initType(ty: Type) Iterator {
53 return .{ .source = .{ .ty = ty }, .index = 0 };
54 }
55
56 /// returns the next attribute as well as its index within the slice or current type
57 /// The index can be used to determine when a nested type has been recursed into
58 pub fn next(self: *Iterator) ?struct { Attribute, usize } {
59 switch (self.source) {
60 .slice => |slice| {
61 if (self.index < slice.len) {
62 defer self.index += 1;
63 return .{ slice[self.index], self.index };
64 }
65 },
66 .ty => |ty| {
67 switch (ty.specifier) {
68 .typeof_type => {
69 self.* = .{ .source = .{ .ty = ty.data.sub_type.* }, .index = 0 };
70 return self.next();
71 },
72 .typeof_expr => {
73 self.* = .{ .source = .{ .ty = ty.data.expr.ty }, .index = 0 };
74 return self.next();
75 },
76 .attributed => {
77 if (self.index < ty.data.attributed.attributes.len) {
78 defer self.index += 1;
79 return .{ ty.data.attributed.attributes[self.index], self.index };
80 }
81 self.* = .{ .source = .{ .ty = ty.data.attributed.base }, .index = 0 };
82 return self.next();
83 },
84 else => {},
85 }
86 },
87 }
88 return null;
89 }
90};
91
41pub const ArgumentType = enum {92pub const ArgumentType = enum {
42 string,93 string,
43 identifier,94 identifier,
44 int,95 int,
45 alignment,96 alignment,
46 float,97 float,
98 complex_float,
47 expression,99 expression,
48 nullptr_t,100 nullptr_t,
49101
...@@ -54,6 +106,7 @@ pub const ArgumentType = enum {...@@ -54,6 +106,7 @@ pub const ArgumentType = enum {
54 .int, .alignment => "an integer constant",106 .int, .alignment => "an integer constant",
55 .nullptr_t => "nullptr",107 .nullptr_t => "nullptr",
56 .float => "a floating point number",108 .float => "a floating point number",
109 .complex_float => "a complex floating point number",
57 .expression => "an expression",110 .expression => "an expression",
58 };111 };
59 }112 }
...@@ -65,7 +118,7 @@ pub fn requiredArgCount(attr: Tag) u32 {...@@ -65,7 +118,7 @@ pub fn requiredArgCount(attr: Tag) u32 {
65 inline else => |tag| {118 inline else => |tag| {
66 comptime var needed = 0;119 comptime var needed = 0;
67 comptime {120 comptime {
68 const fields = std.meta.fields(@field(attributes, @tagName(tag)));121 const fields = @typeInfo(@field(attributes, @tagName(tag))).@"struct".fields;
69 for (fields) |arg_field| {122 for (fields) |arg_field| {
70 if (!mem.eql(u8, arg_field.name, "__name_tok") and @typeInfo(arg_field.type) != .optional) needed += 1;123 if (!mem.eql(u8, arg_field.name, "__name_tok") and @typeInfo(arg_field.type) != .optional) needed += 1;
71 }124 }
...@@ -81,7 +134,7 @@ pub fn maxArgCount(attr: Tag) u32 {...@@ -81,7 +134,7 @@ pub fn maxArgCount(attr: Tag) u32 {
81 inline else => |tag| {134 inline else => |tag| {
82 comptime var max = 0;135 comptime var max = 0;
83 comptime {136 comptime {
84 const fields = std.meta.fields(@field(attributes, @tagName(tag)));137 const fields = @typeInfo(@field(attributes, @tagName(tag))).@"struct".fields;
85 for (fields) |arg_field| {138 for (fields) |arg_field| {
86 if (!mem.eql(u8, arg_field.name, "__name_tok")) max += 1;139 if (!mem.eql(u8, arg_field.name, "__name_tok")) max += 1;
87 }140 }
...@@ -106,7 +159,7 @@ pub const Formatting = struct {...@@ -106,7 +159,7 @@ pub const Formatting = struct {
106 switch (attr) {159 switch (attr) {
107 .calling_convention => unreachable,160 .calling_convention => unreachable,
108 inline else => |tag| {161 inline else => |tag| {
109 const fields = std.meta.fields(@field(attributes, @tagName(tag)));162 const fields = @typeInfo(@field(attributes, @tagName(tag))).@"struct".fields;
110163
111 if (fields.len == 0) unreachable;164 if (fields.len == 0) unreachable;
112 const Unwrapped = UnwrapOptional(fields[0].type);165 const Unwrapped = UnwrapOptional(fields[0].type);
...@@ -123,14 +176,13 @@ pub const Formatting = struct {...@@ -123,14 +176,13 @@ pub const Formatting = struct {
123 switch (attr) {176 switch (attr) {
124 .calling_convention => unreachable,177 .calling_convention => unreachable,
125 inline else => |tag| {178 inline else => |tag| {
126 const fields = std.meta.fields(@field(attributes, @tagName(tag)));179 const fields = @typeInfo(@field(attributes, @tagName(tag))).@"struct".fields;
127180
128 if (fields.len == 0) unreachable;181 if (fields.len == 0) unreachable;
129 const Unwrapped = UnwrapOptional(fields[0].type);182 const Unwrapped = UnwrapOptional(fields[0].type);
130 if (@typeInfo(Unwrapped) != .@"enum") unreachable;183 if (@typeInfo(Unwrapped) != .@"enum") unreachable;
131184
132 const enum_fields = @typeInfo(Unwrapped).@"enum".fields;185 const enum_fields = @typeInfo(Unwrapped).@"enum".fields;
133 @setEvalBranchQuota(3000);
134 const quote = comptime quoteChar(@enumFromInt(@intFromEnum(tag)));186 const quote = comptime quoteChar(@enumFromInt(@intFromEnum(tag)));
135 comptime var values: []const u8 = quote ++ enum_fields[0].name ++ quote;187 comptime var values: []const u8 = quote ++ enum_fields[0].name ++ quote;
136 inline for (enum_fields[1..]) |enum_field| {188 inline for (enum_fields[1..]) |enum_field| {
...@@ -148,7 +200,7 @@ pub fn wantsIdentEnum(attr: Tag) bool {...@@ -148,7 +200,7 @@ pub fn wantsIdentEnum(attr: Tag) bool {
148 switch (attr) {200 switch (attr) {
149 .calling_convention => return false,201 .calling_convention => return false,
150 inline else => |tag| {202 inline else => |tag| {
151 const fields = std.meta.fields(@field(attributes, @tagName(tag)));203 const fields = @typeInfo(@field(attributes, @tagName(tag))).@"struct".fields;
152204
153 if (fields.len == 0) return false;205 if (fields.len == 0) return false;
154 const Unwrapped = UnwrapOptional(fields[0].type);206 const Unwrapped = UnwrapOptional(fields[0].type);
...@@ -162,7 +214,7 @@ pub fn wantsIdentEnum(attr: Tag) bool {...@@ -162,7 +214,7 @@ pub fn wantsIdentEnum(attr: Tag) bool {
162pub fn diagnoseIdent(attr: Tag, arguments: *Arguments, ident: []const u8) ?Diagnostics.Message {214pub fn diagnoseIdent(attr: Tag, arguments: *Arguments, ident: []const u8) ?Diagnostics.Message {
163 switch (attr) {215 switch (attr) {
164 inline else => |tag| {216 inline else => |tag| {
165 const fields = std.meta.fields(@field(attributes, @tagName(tag)));217 const fields = @typeInfo(@field(attributes, @tagName(tag))).@"struct".fields;
166 if (fields.len == 0) unreachable;218 if (fields.len == 0) unreachable;
167 const Unwrapped = UnwrapOptional(fields[0].type);219 const Unwrapped = UnwrapOptional(fields[0].type);
168 if (@typeInfo(Unwrapped) != .@"enum") unreachable;220 if (@typeInfo(Unwrapped) != .@"enum") unreachable;
...@@ -181,7 +233,7 @@ pub fn diagnoseIdent(attr: Tag, arguments: *Arguments, ident: []const u8) ?Diagn...@@ -181,7 +233,7 @@ pub fn diagnoseIdent(attr: Tag, arguments: *Arguments, ident: []const u8) ?Diagn
181pub fn wantsAlignment(attr: Tag, idx: usize) bool {233pub fn wantsAlignment(attr: Tag, idx: usize) bool {
182 switch (attr) {234 switch (attr) {
183 inline else => |tag| {235 inline else => |tag| {
184 const fields = std.meta.fields(@field(attributes, @tagName(tag)));236 const fields = @typeInfo(@field(attributes, @tagName(tag))).@"struct".fields;
185 if (fields.len == 0) return false;237 if (fields.len == 0) return false;
186238
187 return switch (idx) {239 return switch (idx) {
...@@ -195,7 +247,7 @@ pub fn wantsAlignment(attr: Tag, idx: usize) bool {...@@ -195,7 +247,7 @@ pub fn wantsAlignment(attr: Tag, idx: usize) bool {
195pub fn diagnoseAlignment(attr: Tag, arguments: *Arguments, arg_idx: u32, res: Parser.Result, p: *Parser) !?Diagnostics.Message {247pub fn diagnoseAlignment(attr: Tag, arguments: *Arguments, arg_idx: u32, res: Parser.Result, p: *Parser) !?Diagnostics.Message {
196 switch (attr) {248 switch (attr) {
197 inline else => |tag| {249 inline else => |tag| {
198 const arg_fields = std.meta.fields(@field(attributes, @tagName(tag)));250 const arg_fields = @typeInfo(@field(attributes, @tagName(tag))).@"struct".fields;
199 if (arg_fields.len == 0) unreachable;251 if (arg_fields.len == 0) unreachable;
200252
201 switch (arg_idx) {253 switch (arg_idx) {
...@@ -249,8 +301,7 @@ fn diagnoseField(...@@ -249,8 +301,7 @@ fn diagnoseField(
249 },301 },
250 .bytes => |bytes| {302 .bytes => |bytes| {
251 if (Wanted == Value) {303 if (Wanted == Value) {
252 std.debug.assert(node.tag == .string_literal_expr);304 if (node.tag != .string_literal_expr or (!node.ty.elemType().is(.char) and !node.ty.elemType().is(.uchar))) {
253 if (!node.ty.elemType().is(.char) and !node.ty.elemType().is(.uchar)) {
254 return .{305 return .{
255 .tag = .attribute_requires_string,306 .tag = .attribute_requires_string,
256 .extra = .{ .str = decl.name },307 .extra = .{ .str = decl.name },
...@@ -264,7 +315,6 @@ fn diagnoseField(...@@ -264,7 +315,6 @@ fn diagnoseField(
264 @field(@field(arguments, decl.name), field.name) = enum_val;315 @field(@field(arguments, decl.name), field.name) = enum_val;
265 return null;316 return null;
266 } else {317 } else {
267 @setEvalBranchQuota(3000);
268 return .{318 return .{
269 .tag = .unknown_attr_enum,319 .tag = .unknown_attr_enum,
270 .extra = .{ .attr_enum = .{ .tag = std.meta.stringToEnum(Tag, decl.name).? } },320 .extra = .{ .attr_enum = .{ .tag = std.meta.stringToEnum(Tag, decl.name).? } },
...@@ -278,8 +328,19 @@ fn diagnoseField(...@@ -278,8 +328,19 @@ fn diagnoseField(
278 .int => .int,328 .int => .int,
279 .bytes => .string,329 .bytes => .string,
280 .float => .float,330 .float => .float,
331 .complex => .complex_float,
281 .null => .nullptr_t,332 .null => .nullptr_t,
282 else => unreachable,333 .int_ty,
334 .float_ty,
335 .complex_ty,
336 .ptr_ty,
337 .noreturn_ty,
338 .void_ty,
339 .func_ty,
340 .array_ty,
341 .vector_ty,
342 .record_ty,
343 => unreachable,
283 });344 });
284}345}
285346
...@@ -309,7 +370,7 @@ pub fn diagnose(attr: Tag, arguments: *Arguments, arg_idx: u32, res: Parser.Resu...@@ -309,7 +370,7 @@ pub fn diagnose(attr: Tag, arguments: *Arguments, arg_idx: u32, res: Parser.Resu
309 .tag = .attribute_too_many_args,370 .tag = .attribute_too_many_args,
310 .extra = .{ .attr_arg_count = .{ .attribute = attr, .expected = max_arg_count } },371 .extra = .{ .attr_arg_count = .{ .attribute = attr, .expected = max_arg_count } },
311 };372 };
312 const arg_fields = std.meta.fields(@field(attributes, decl.name));373 const arg_fields = @typeInfo(@field(attributes, decl.name)).@"struct".fields;
313 switch (arg_idx) {374 switch (arg_idx) {
314 inline 0...arg_fields.len - 1 => |arg_i| {375 inline 0...arg_fields.len - 1 => |arg_i| {
315 return diagnoseField(decl, arg_fields[arg_i], UnwrapOptional(arg_fields[arg_i].type), arguments, res, node, p);376 return diagnoseField(decl, arg_fields[arg_i], UnwrapOptional(arg_fields[arg_i].type), arguments, res, node, p);
...@@ -645,7 +706,7 @@ pub const Arguments = blk: {...@@ -645,7 +706,7 @@ pub const Arguments = blk: {
645 var union_fields: [decls.len]ZigType.UnionField = undefined;706 var union_fields: [decls.len]ZigType.UnionField = undefined;
646 for (decls, &union_fields) |decl, *field| {707 for (decls, &union_fields) |decl, *field| {
647 field.* = .{708 field.* = .{
648 .name = decl.name ++ "",709 .name = decl.name,
649 .type = @field(attributes, decl.name),710 .type = @field(attributes, decl.name),
650 .alignment = 0,711 .alignment = 0,
651 };712 };
...@@ -730,7 +791,6 @@ pub fn applyVariableAttributes(p: *Parser, ty: Type, attr_buf_start: usize, tag:...@@ -730,7 +791,6 @@ pub fn applyVariableAttributes(p: *Parser, ty: Type, attr_buf_start: usize, tag:
730 const toks = p.attr_buf.items(.tok)[attr_buf_start..];791 const toks = p.attr_buf.items(.tok)[attr_buf_start..];
731 p.attr_application_buf.items.len = 0;792 p.attr_application_buf.items.len = 0;
732 var base_ty = ty;793 var base_ty = ty;
733 if (base_ty.specifier == .attributed) base_ty = base_ty.data.attributed.base;
734 var common = false;794 var common = false;
735 var nocommon = false;795 var nocommon = false;
736 for (attrs, toks) |attr, tok| switch (attr.tag) {796 for (attrs, toks) |attr, tok| switch (attr.tag) {
...@@ -772,15 +832,10 @@ pub fn applyVariableAttributes(p: *Parser, ty: Type, attr_buf_start: usize, tag:...@@ -772,15 +832,10 @@ pub fn applyVariableAttributes(p: *Parser, ty: Type, attr_buf_start: usize, tag:
772 .copy,832 .copy,
773 .tls_model,833 .tls_model,
774 .visibility,834 .visibility,
775 => std.debug.panic("apply variable attribute {s}", .{@tagName(attr.tag)}),835 => |t| try p.errExtra(.attribute_todo, tok, .{ .attribute_todo = .{ .tag = t, .kind = .variables } }),
776 else => try ignoredAttrErr(p, tok, attr.tag, "variables"),836 else => try ignoredAttrErr(p, tok, attr.tag, "variables"),
777 };837 };
778 const existing = ty.getAttributes();838 return base_ty.withAttributes(p.arena, p.attr_application_buf.items);
779 if (existing.len == 0 and p.attr_application_buf.items.len == 0) return base_ty;
780 if (existing.len == 0) return base_ty.withAttributes(p.arena, p.attr_application_buf.items);
781
782 const attributed_type = try Type.Attributed.create(p.arena, base_ty, existing, p.attr_application_buf.items);
783 return Type{ .specifier = .attributed, .data = .{ .attributed = attributed_type } };
784}839}
785840
786pub fn applyFieldAttributes(p: *Parser, field_ty: *Type, attr_buf_start: usize) ![]const Attribute {841pub fn applyFieldAttributes(p: *Parser, field_ty: *Type, attr_buf_start: usize) ![]const Attribute {
...@@ -789,7 +844,7 @@ pub fn applyFieldAttributes(p: *Parser, field_ty: *Type, attr_buf_start: usize)...@@ -789,7 +844,7 @@ pub fn applyFieldAttributes(p: *Parser, field_ty: *Type, attr_buf_start: usize)
789 p.attr_application_buf.items.len = 0;844 p.attr_application_buf.items.len = 0;
790 for (attrs, toks) |attr, tok| switch (attr.tag) {845 for (attrs, toks) |attr, tok| switch (attr.tag) {
791 // zig fmt: off846 // zig fmt: off
792 .@"packed", .may_alias, .deprecated, .unavailable, .unused, .warn_if_not_aligned, .mode,847 .@"packed", .may_alias, .deprecated, .unavailable, .unused, .warn_if_not_aligned, .mode, .warn_unused_result, .nodiscard,
793 => try p.attr_application_buf.append(p.gpa, attr),848 => try p.attr_application_buf.append(p.gpa, attr),
794 // zig fmt: on849 // zig fmt: on
795 .vector_size => try attr.applyVectorSize(p, tok, field_ty),850 .vector_size => try attr.applyVectorSize(p, tok, field_ty),
...@@ -805,7 +860,6 @@ pub fn applyTypeAttributes(p: *Parser, ty: Type, attr_buf_start: usize, tag: ?Di...@@ -805,7 +860,6 @@ pub fn applyTypeAttributes(p: *Parser, ty: Type, attr_buf_start: usize, tag: ?Di
805 const toks = p.attr_buf.items(.tok)[attr_buf_start..];860 const toks = p.attr_buf.items(.tok)[attr_buf_start..];
806 p.attr_application_buf.items.len = 0;861 p.attr_application_buf.items.len = 0;
807 var base_ty = ty;862 var base_ty = ty;
808 if (base_ty.specifier == .attributed) base_ty = base_ty.data.attributed.base;
809 for (attrs, toks) |attr, tok| switch (attr.tag) {863 for (attrs, toks) |attr, tok| switch (attr.tag) {
810 // zig fmt: off864 // zig fmt: off
811 .@"packed", .may_alias, .deprecated, .unavailable, .unused, .warn_if_not_aligned, .mode,865 .@"packed", .may_alias, .deprecated, .unavailable, .unused, .warn_if_not_aligned, .mode,
...@@ -823,22 +877,10 @@ pub fn applyTypeAttributes(p: *Parser, ty: Type, attr_buf_start: usize, tag: ?Di...@@ -823,22 +877,10 @@ pub fn applyTypeAttributes(p: *Parser, ty: Type, attr_buf_start: usize, tag: ?Di
823 .copy,877 .copy,
824 .scalar_storage_order,878 .scalar_storage_order,
825 .nonstring,879 .nonstring,
826 => std.debug.panic("apply type attribute {s}", .{@tagName(attr.tag)}),880 => |t| try p.errExtra(.attribute_todo, tok, .{ .attribute_todo = .{ .tag = t, .kind = .types } }),
827 else => try ignoredAttrErr(p, tok, attr.tag, "types"),881 else => try ignoredAttrErr(p, tok, attr.tag, "types"),
828 };882 };
829883 return base_ty.withAttributes(p.arena, p.attr_application_buf.items);
830 const existing = ty.getAttributes();
831 // TODO: the alignment annotation on a type should override
832 // the decl it refers to. This might not be true for others. Maybe bug.
833
834 // if there are annotations on this type def use those.
835 if (p.attr_application_buf.items.len > 0) {
836 return try base_ty.withAttributes(p.arena, p.attr_application_buf.items);
837 } else if (existing.len > 0) {
838 // else use the ones on the typedef decl we were refering to.
839 return try base_ty.withAttributes(p.arena, existing);
840 }
841 return base_ty;
842}884}
843885
844pub fn applyFunctionAttributes(p: *Parser, ty: Type, attr_buf_start: usize) !Type {886pub fn applyFunctionAttributes(p: *Parser, ty: Type, attr_buf_start: usize) !Type {
...@@ -846,7 +888,6 @@ pub fn applyFunctionAttributes(p: *Parser, ty: Type, attr_buf_start: usize) !Typ...@@ -846,7 +888,6 @@ pub fn applyFunctionAttributes(p: *Parser, ty: Type, attr_buf_start: usize) !Typ
846 const toks = p.attr_buf.items(.tok)[attr_buf_start..];888 const toks = p.attr_buf.items(.tok)[attr_buf_start..];
847 p.attr_application_buf.items.len = 0;889 p.attr_application_buf.items.len = 0;
848 var base_ty = ty;890 var base_ty = ty;
849 if (base_ty.specifier == .attributed) base_ty = base_ty.data.attributed.base;
850 var hot = false;891 var hot = false;
851 var cold = false;892 var cold = false;
852 var @"noinline" = false;893 var @"noinline" = false;
...@@ -896,6 +937,13 @@ pub fn applyFunctionAttributes(p: *Parser, ty: Type, attr_buf_start: usize) !Typ...@@ -896,6 +937,13 @@ pub fn applyFunctionAttributes(p: *Parser, ty: Type, attr_buf_start: usize) !Typ
896 else => try p.errStr(.callconv_not_supported, tok, p.tok_ids[tok].lexeme().?),937 else => try p.errStr(.callconv_not_supported, tok, p.tok_ids[tok].lexeme().?),
897 },938 },
898 },939 },
940 .malloc => {
941 if (base_ty.returnType().isPtr()) {
942 try p.attr_application_buf.append(p.gpa, attr);
943 } else {
944 try ignoredAttrErr(p, tok, attr.tag, "functions that do not return pointers");
945 }
946 },
899 .access,947 .access,
900 .alloc_align,948 .alloc_align,
901 .alloc_size,949 .alloc_size,
...@@ -908,7 +956,6 @@ pub fn applyFunctionAttributes(p: *Parser, ty: Type, attr_buf_start: usize) !Typ...@@ -908,7 +956,6 @@ pub fn applyFunctionAttributes(p: *Parser, ty: Type, attr_buf_start: usize) !Typ
908 .ifunc,956 .ifunc,
909 .interrupt,957 .interrupt,
910 .interrupt_handler,958 .interrupt_handler,
911 .malloc,
912 .no_address_safety_analysis,959 .no_address_safety_analysis,
913 .no_icf,960 .no_icf,
914 .no_instrument_function,961 .no_instrument_function,
...@@ -937,7 +984,7 @@ pub fn applyFunctionAttributes(p: *Parser, ty: Type, attr_buf_start: usize) !Typ...@@ -937,7 +984,7 @@ pub fn applyFunctionAttributes(p: *Parser, ty: Type, attr_buf_start: usize) !Typ
937 .visibility,984 .visibility,
938 .weakref,985 .weakref,
939 .zero_call_used_regs,986 .zero_call_used_regs,
940 => std.debug.panic("apply type attribute {s}", .{@tagName(attr.tag)}),987 => |t| try p.errExtra(.attribute_todo, tok, .{ .attribute_todo = .{ .tag = t, .kind = .functions } }),
941 else => try ignoredAttrErr(p, tok, attr.tag, "functions"),988 else => try ignoredAttrErr(p, tok, attr.tag, "functions"),
942 };989 };
943 return ty.withAttributes(p.arena, p.attr_application_buf.items);990 return ty.withAttributes(p.arena, p.attr_application_buf.items);
...@@ -1043,11 +1090,14 @@ fn applyTransparentUnion(attr: Attribute, p: *Parser, tok: TokenIndex, ty: Type)...@@ -1043,11 +1090,14 @@ fn applyTransparentUnion(attr: Attribute, p: *Parser, tok: TokenIndex, ty: Type)
1043}1090}
10441091
1045fn applyVectorSize(attr: Attribute, p: *Parser, tok: TokenIndex, ty: *Type) !void {1092fn applyVectorSize(attr: Attribute, p: *Parser, tok: TokenIndex, ty: *Type) !void {
1046 if (!(ty.isInt() or ty.isFloat()) or !ty.isReal()) {1093 const base = ty.base();
1047 const orig_ty = try p.typeStr(ty.*);1094 const is_enum = ty.is(.@"enum");
1048 ty.* = Type.invalid;1095 if (!(ty.isInt() or ty.isFloat()) or !ty.isReal() or (is_enum and p.comp.langopts.emulate == .gcc)) {
1049 return p.errStr(.invalid_vec_elem_ty, tok, orig_ty);1096 try p.errStr(.invalid_vec_elem_ty, tok, try p.typeStr(ty.*));
1097 return error.ParsingFailed;
1050 }1098 }
1099 if (is_enum) return;
1100
1051 const vec_bytes = attr.args.vector_size.bytes;1101 const vec_bytes = attr.args.vector_size.bytes;
1052 const ty_size = ty.sizeof(p.comp).?;1102 const ty_size = ty.sizeof(p.comp).?;
1053 if (vec_bytes % ty_size != 0) {1103 if (vec_bytes % ty_size != 0) {
...@@ -1057,7 +1107,7 @@ fn applyVectorSize(attr: Attribute, p: *Parser, tok: TokenIndex, ty: *Type) !voi...@@ -1057,7 +1107,7 @@ fn applyVectorSize(attr: Attribute, p: *Parser, tok: TokenIndex, ty: *Type) !voi
10571107
1058 const arr_ty = try p.arena.create(Type.Array);1108 const arr_ty = try p.arena.create(Type.Array);
1059 arr_ty.* = .{ .elem = ty.*, .len = vec_size };1109 arr_ty.* = .{ .elem = ty.*, .len = vec_size };
1060 ty.* = Type{1110 base.* = .{
1061 .specifier = .vector,1111 .specifier = .vector,
1062 .data = .{ .array = arr_ty },1112 .data = .{ .array = arr_ty },
1063 };1113 };
lib/compiler/aro/aro/Attribute/names.zig+2-1
...@@ -69,6 +69,7 @@ pub const longest_name = 30;...@@ -69,6 +69,7 @@ pub const longest_name = 30;
69/// If found, returns the index of the node within the `dafsa` array.69/// If found, returns the index of the node within the `dafsa` array.
70/// Otherwise, returns `null`.70/// Otherwise, returns `null`.
71pub fn findInList(first_child_index: u16, char: u8) ?u16 {71pub fn findInList(first_child_index: u16, char: u8) ?u16 {
72 @setEvalBranchQuota(206);
72 var index = first_child_index;73 var index = first_child_index;
73 while (true) {74 while (true) {
74 if (dafsa[index].char == char) return index;75 if (dafsa[index].char == char) return index;
...@@ -787,7 +788,7 @@ const dafsa = [_]Node{...@@ -787,7 +788,7 @@ const dafsa = [_]Node{
787 .{ .char = 'i', .end_of_word = false, .end_of_list = true, .number = 1, .child_index = 215 },788 .{ .char = 'i', .end_of_word = false, .end_of_list = true, .number = 1, .child_index = 215 },
788};789};
789pub const data = blk: {790pub const data = blk: {
790 @setEvalBranchQuota(103);791 @setEvalBranchQuota(721);
791 break :blk [_]@This(){792 break :blk [_]@This(){
792 // access793 // access
793 .{ .tag = @enumFromInt(0), .properties = .{ .tag = .access, .gnu = true } },794 .{ .tag = @enumFromInt(0), .properties = .{ .tag = .access, .gnu = true } },
lib/compiler/aro/aro/Builtins.zig+2-2
...@@ -350,7 +350,7 @@ test Iterator {...@@ -350,7 +350,7 @@ test Iterator {
350}350}
351351
352test "All builtins" {352test "All builtins" {
353 var comp = Compilation.init(std.testing.allocator);353 var comp = Compilation.init(std.testing.allocator, std.fs.cwd());
354 defer comp.deinit();354 defer comp.deinit();
355 _ = try comp.generateBuiltinMacros(.include_system_defines);355 _ = try comp.generateBuiltinMacros(.include_system_defines);
356 var arena = std.heap.ArenaAllocator.init(std.testing.allocator);356 var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
...@@ -373,7 +373,7 @@ test "All builtins" {...@@ -373,7 +373,7 @@ test "All builtins" {
373test "Allocation failures" {373test "Allocation failures" {
374 const Test = struct {374 const Test = struct {
375 fn testOne(allocator: std.mem.Allocator) !void {375 fn testOne(allocator: std.mem.Allocator) !void {
376 var comp = Compilation.init(allocator);376 var comp = Compilation.init(allocator, std.fs.cwd());
377 defer comp.deinit();377 defer comp.deinit();
378 _ = try comp.generateBuiltinMacros(.include_system_defines);378 _ = try comp.generateBuiltinMacros(.include_system_defines);
379 var arena = std.heap.ArenaAllocator.init(comp.gpa);379 var arena = std.heap.ArenaAllocator.init(comp.gpa);
lib/compiler/aro/aro/Builtins/Builtin.zig+2-1
...@@ -71,6 +71,7 @@ pub const longest_name = 43;...@@ -71,6 +71,7 @@ pub const longest_name = 43;
71/// If found, returns the index of the node within the `dafsa` array.71/// If found, returns the index of the node within the `dafsa` array.
72/// Otherwise, returns `null`.72/// Otherwise, returns `null`.
73pub fn findInList(first_child_index: u16, char: u8) ?u16 {73pub fn findInList(first_child_index: u16, char: u8) ?u16 {
74 @setEvalBranchQuota(7972);
74 var index = first_child_index;75 var index = first_child_index;
75 while (true) {76 while (true) {
76 if (dafsa[index].char == char) return index;77 if (dafsa[index].char == char) return index;
...@@ -5165,7 +5166,7 @@ const dafsa = [_]Node{...@@ -5165,7 +5166,7 @@ const dafsa = [_]Node{
5165 .{ .char = 'e', .end_of_word = false, .end_of_list = true, .number = 1, .child_index = 4913 },5166 .{ .char = 'e', .end_of_word = false, .end_of_list = true, .number = 1, .child_index = 4913 },
5166};5167};
5167pub const data = blk: {5168pub const data = blk: {
5168 @setEvalBranchQuota(30_000);5169 @setEvalBranchQuota(27902);
5169 break :blk [_]@This(){5170 break :blk [_]@This(){
5170 // _Block_object_assign5171 // _Block_object_assign
5171 .{ .tag = @enumFromInt(0), .properties = .{ .param_str = "vv*vC*iC", .header = .blocks, .attributes = .{ .lib_function_without_prefix = true } } },5172 .{ .tag = @enumFromInt(0), .properties = .{ .param_str = "vv*vC*iC", .header = .blocks, .attributes = .{ .lib_function_without_prefix = true } } },
lib/compiler/aro/aro/Builtins/eval.zig created+86
...@@ -0,0 +1,86 @@
1const std = @import("std");
2const backend = @import("../../backend.zig");
3const Interner = backend.Interner;
4const Builtins = @import("../Builtins.zig");
5const Builtin = Builtins.Builtin;
6const Parser = @import("../Parser.zig");
7const Tree = @import("../Tree.zig");
8const NodeIndex = Tree.NodeIndex;
9const Type = @import("../Type.zig");
10const Value = @import("../Value.zig");
11
12fn makeNan(comptime T: type, str: []const u8) T {
13 const UnsignedSameSize = std.meta.Int(.unsigned, @bitSizeOf(T));
14 const parsed = std.fmt.parseUnsigned(UnsignedSameSize, str[0 .. str.len - 1], 0) catch 0;
15 const bits: switch (T) {
16 f32 => u23,
17 f64 => u52,
18 f80 => u63,
19 f128 => u112,
20 else => @compileError("Invalid type for makeNan"),
21 } = @truncate(parsed);
22 return @bitCast(@as(UnsignedSameSize, bits) | @as(UnsignedSameSize, @bitCast(std.math.nan(T))));
23}
24
25pub fn eval(tag: Builtin.Tag, p: *Parser, args: []const NodeIndex) !Value {
26 const builtin = Builtin.fromTag(tag);
27 if (!builtin.properties.attributes.const_evaluable) return .{};
28
29 switch (tag) {
30 Builtin.tagFromName("__builtin_inff").?,
31 Builtin.tagFromName("__builtin_inf").?,
32 Builtin.tagFromName("__builtin_infl").?,
33 => {
34 const ty: Type = switch (tag) {
35 Builtin.tagFromName("__builtin_inff").? => .{ .specifier = .float },
36 Builtin.tagFromName("__builtin_inf").? => .{ .specifier = .double },
37 Builtin.tagFromName("__builtin_infl").? => .{ .specifier = .long_double },
38 else => unreachable,
39 };
40 const f: Interner.Key.Float = switch (ty.bitSizeof(p.comp).?) {
41 32 => .{ .f32 = std.math.inf(f32) },
42 64 => .{ .f64 = std.math.inf(f64) },
43 80 => .{ .f80 = std.math.inf(f80) },
44 128 => .{ .f128 = std.math.inf(f128) },
45 else => unreachable,
46 };
47 return Value.intern(p.comp, .{ .float = f });
48 },
49 Builtin.tagFromName("__builtin_isinf").? => blk: {
50 if (args.len == 0) break :blk;
51 const val = p.value_map.get(args[0]) orelse break :blk;
52 return Value.fromBool(val.isInf(p.comp));
53 },
54 Builtin.tagFromName("__builtin_isinf_sign").? => blk: {
55 if (args.len == 0) break :blk;
56 const val = p.value_map.get(args[0]) orelse break :blk;
57 switch (val.isInfSign(p.comp)) {
58 .unknown => {},
59 .finite => return Value.zero,
60 .positive => return Value.one,
61 .negative => return Value.int(@as(i64, -1), p.comp),
62 }
63 },
64 Builtin.tagFromName("__builtin_isnan").? => blk: {
65 if (args.len == 0) break :blk;
66 const val = p.value_map.get(args[0]) orelse break :blk;
67 return Value.fromBool(val.isNan(p.comp));
68 },
69 Builtin.tagFromName("__builtin_nan").? => blk: {
70 if (args.len == 0) break :blk;
71 const val = p.getDecayedStringLiteral(args[0]) orelse break :blk;
72 const bytes = p.comp.interner.get(val.ref()).bytes;
73
74 const f: Interner.Key.Float = switch ((Type{ .specifier = .double }).bitSizeof(p.comp).?) {
75 32 => .{ .f32 = makeNan(f32, bytes) },
76 64 => .{ .f64 = makeNan(f64, bytes) },
77 80 => .{ .f80 = makeNan(f80, bytes) },
78 128 => .{ .f128 = makeNan(f128, bytes) },
79 else => unreachable,
80 };
81 return Value.intern(p.comp, .{ .float = f });
82 },
83 else => {},
84 }
85 return .{};
86}
lib/compiler/aro/aro/Compilation.zig+67-23
...@@ -127,22 +127,27 @@ types: struct {...@@ -127,22 +127,27 @@ types: struct {
127} = .{},127} = .{},
128string_interner: StrInt = .{},128string_interner: StrInt = .{},
129interner: Interner = .{},129interner: Interner = .{},
130/// If this is not null, the directory containing the specified Source will be searched for includes
131/// Used by MS extensions which allow searching for includes relative to the directory of the main source file.
130ms_cwd_source_id: ?Source.Id = null,132ms_cwd_source_id: ?Source.Id = null,
133cwd: std.fs.Dir,
131134
132pub fn init(gpa: Allocator) Compilation {135pub fn init(gpa: Allocator, cwd: std.fs.Dir) Compilation {
133 return .{136 return .{
134 .gpa = gpa,137 .gpa = gpa,
135 .diagnostics = Diagnostics.init(gpa),138 .diagnostics = Diagnostics.init(gpa),
139 .cwd = cwd,
136 };140 };
137}141}
138142
139/// Initialize Compilation with default environment,143/// Initialize Compilation with default environment,
140/// pragma handlers and emulation mode set to target.144/// pragma handlers and emulation mode set to target.
141pub fn initDefault(gpa: Allocator) !Compilation {145pub fn initDefault(gpa: Allocator, cwd: std.fs.Dir) !Compilation {
142 var comp: Compilation = .{146 var comp: Compilation = .{
143 .gpa = gpa,147 .gpa = gpa,
144 .environment = try Environment.loadAll(gpa),148 .environment = try Environment.loadAll(gpa),
145 .diagnostics = Diagnostics.init(gpa),149 .diagnostics = Diagnostics.init(gpa),
150 .cwd = cwd,
146 };151 };
147 errdefer comp.deinit();152 errdefer comp.deinit();
148 try comp.addDefaultPragmaHandlers();153 try comp.addDefaultPragmaHandlers();
...@@ -534,7 +539,7 @@ pub fn generateBuiltinMacros(comp: *Compilation, system_defines_mode: SystemDefi...@@ -534,7 +539,7 @@ pub fn generateBuiltinMacros(comp: *Compilation, system_defines_mode: SystemDefi
534 if (system_defines_mode == .include_system_defines) {539 if (system_defines_mode == .include_system_defines) {
535 try buf.appendSlice(540 try buf.appendSlice(
536 \\#define __VERSION__ "Aro541 \\#define __VERSION__ "Aro
537 ++ @import("../backend.zig").version_str ++ "\"\n" ++542 ++ " " ++ @import("../backend.zig").version_str ++ "\"\n" ++
538 \\#define __Aro__543 \\#define __Aro__
539 \\544 \\
540 );545 );
...@@ -550,6 +555,9 @@ pub fn generateBuiltinMacros(comp: *Compilation, system_defines_mode: SystemDefi...@@ -550,6 +555,9 @@ pub fn generateBuiltinMacros(comp: *Compilation, system_defines_mode: SystemDefi
550 \\#define __STDC_NO_VLA__ 1555 \\#define __STDC_NO_VLA__ 1
551 \\#define __STDC_UTF_16__ 1556 \\#define __STDC_UTF_16__ 1
552 \\#define __STDC_UTF_32__ 1557 \\#define __STDC_UTF_32__ 1
558 \\#define __STDC_EMBED_NOT_FOUND__ 0
559 \\#define __STDC_EMBED_FOUND__ 1
560 \\#define __STDC_EMBED_EMPTY__ 2
553 \\561 \\
554 );562 );
555 if (comp.langopts.standard.StdCVersionMacro()) |stdc_version| {563 if (comp.langopts.standard.StdCVersionMacro()) |stdc_version| {
...@@ -719,8 +727,13 @@ fn generateBuiltinTypes(comp: *Compilation) !void {...@@ -719,8 +727,13 @@ fn generateBuiltinTypes(comp: *Compilation) !void {
719 try comp.generateNsConstantStringType();727 try comp.generateNsConstantStringType();
720}728}
721729
730pub fn float80Type(comp: *const Compilation) ?Type {
731 if (comp.langopts.emulate != .gcc) return null;
732 return target_util.float80Type(comp.target);
733}
734
722/// Smallest integer type with at least N bits735/// Smallest integer type with at least N bits
723fn intLeastN(comp: *const Compilation, bits: usize, signedness: std.builtin.Signedness) Type {736pub fn intLeastN(comp: *const Compilation, bits: usize, signedness: std.builtin.Signedness) Type {
724 if (bits == 64 and (comp.target.isDarwin() or comp.target.isWasm())) {737 if (bits == 64 and (comp.target.isDarwin() or comp.target.isWasm())) {
725 // WebAssembly and Darwin use `long long` for `int_least64_t` and `int_fast64_t`.738 // WebAssembly and Darwin use `long long` for `int_least64_t` and `int_fast64_t`.
726 return .{ .specifier = if (signedness == .signed) .long_long else .ulong_long };739 return .{ .specifier = if (signedness == .signed) .long_long else .ulong_long };
...@@ -903,7 +916,7 @@ fn generateNsConstantStringType(comp: *Compilation) !void {...@@ -903,7 +916,7 @@ fn generateNsConstantStringType(comp: *Compilation) !void {
903 comp.types.ns_constant_string.fields[2] = .{ .name = try StrInt.intern(comp, "str"), .ty = const_char_ptr };916 comp.types.ns_constant_string.fields[2] = .{ .name = try StrInt.intern(comp, "str"), .ty = const_char_ptr };
904 comp.types.ns_constant_string.fields[3] = .{ .name = try StrInt.intern(comp, "length"), .ty = .{ .specifier = .long } };917 comp.types.ns_constant_string.fields[3] = .{ .name = try StrInt.intern(comp, "length"), .ty = .{ .specifier = .long } };
905 comp.types.ns_constant_string.ty = .{ .specifier = .@"struct", .data = .{ .record = &comp.types.ns_constant_string.record } };918 comp.types.ns_constant_string.ty = .{ .specifier = .@"struct", .data = .{ .record = &comp.types.ns_constant_string.record } };
906 record_layout.compute(&comp.types.ns_constant_string.record, comp.types.ns_constant_string.ty, comp, null);919 record_layout.compute(&comp.types.ns_constant_string.record, comp.types.ns_constant_string.ty, comp, null) catch unreachable;
907}920}
908921
909fn generateVaListType(comp: *Compilation) !Type {922fn generateVaListType(comp: *Compilation) !Type {
...@@ -911,12 +924,12 @@ fn generateVaListType(comp: *Compilation) !Type {...@@ -911,12 +924,12 @@ fn generateVaListType(comp: *Compilation) !Type {
911 const kind: Kind = switch (comp.target.cpu.arch) {924 const kind: Kind = switch (comp.target.cpu.arch) {
912 .aarch64 => switch (comp.target.os.tag) {925 .aarch64 => switch (comp.target.os.tag) {
913 .windows => @as(Kind, .char_ptr),926 .windows => @as(Kind, .char_ptr),
914 .ios, .macos, .tvos, .watchos, .visionos => .char_ptr,927 .ios, .macos, .tvos, .watchos => .char_ptr,
915 else => .aarch64_va_list,928 else => .aarch64_va_list,
916 },929 },
917 .sparc, .wasm32, .wasm64, .bpfel, .bpfeb, .riscv32, .riscv64, .avr, .spirv32, .spirv64 => .void_ptr,930 .sparc, .wasm32, .wasm64, .bpfel, .bpfeb, .riscv32, .riscv64, .avr, .spirv32, .spirv64 => .void_ptr,
918 .powerpc => switch (comp.target.os.tag) {931 .powerpc => switch (comp.target.os.tag) {
919 .ios, .macos, .tvos, .watchos, .visionos, .aix => @as(Kind, .char_ptr),932 .ios, .macos, .tvos, .watchos, .aix => @as(Kind, .char_ptr),
920 else => return Type{ .specifier = .void }, // unknown933 else => return Type{ .specifier = .void }, // unknown
921 },934 },
922 .x86, .msp430 => .char_ptr,935 .x86, .msp430 => .char_ptr,
...@@ -951,7 +964,7 @@ fn generateVaListType(comp: *Compilation) !Type {...@@ -951,7 +964,7 @@ fn generateVaListType(comp: *Compilation) !Type {
951 record_ty.fields[3] = .{ .name = try StrInt.intern(comp, "__gr_offs"), .ty = .{ .specifier = .int } };964 record_ty.fields[3] = .{ .name = try StrInt.intern(comp, "__gr_offs"), .ty = .{ .specifier = .int } };
952 record_ty.fields[4] = .{ .name = try StrInt.intern(comp, "__vr_offs"), .ty = .{ .specifier = .int } };965 record_ty.fields[4] = .{ .name = try StrInt.intern(comp, "__vr_offs"), .ty = .{ .specifier = .int } };
953 ty = .{ .specifier = .@"struct", .data = .{ .record = record_ty } };966 ty = .{ .specifier = .@"struct", .data = .{ .record = record_ty } };
954 record_layout.compute(record_ty, ty, comp, null);967 record_layout.compute(record_ty, ty, comp, null) catch unreachable;
955 },968 },
956 .x86_64_va_list => {969 .x86_64_va_list => {
957 const record_ty = try arena.create(Type.Record);970 const record_ty = try arena.create(Type.Record);
...@@ -969,7 +982,7 @@ fn generateVaListType(comp: *Compilation) !Type {...@@ -969,7 +982,7 @@ fn generateVaListType(comp: *Compilation) !Type {
969 record_ty.fields[2] = .{ .name = try StrInt.intern(comp, "overflow_arg_area"), .ty = void_ptr };982 record_ty.fields[2] = .{ .name = try StrInt.intern(comp, "overflow_arg_area"), .ty = void_ptr };
970 record_ty.fields[3] = .{ .name = try StrInt.intern(comp, "reg_save_area"), .ty = void_ptr };983 record_ty.fields[3] = .{ .name = try StrInt.intern(comp, "reg_save_area"), .ty = void_ptr };
971 ty = .{ .specifier = .@"struct", .data = .{ .record = record_ty } };984 ty = .{ .specifier = .@"struct", .data = .{ .record = record_ty } };
972 record_layout.compute(record_ty, ty, comp, null);985 record_layout.compute(record_ty, ty, comp, null) catch unreachable;
973 },986 },
974 }987 }
975 if (kind == .char_ptr or kind == .void_ptr) {988 if (kind == .char_ptr or kind == .void_ptr) {
...@@ -988,13 +1001,28 @@ fn generateVaListType(comp: *Compilation) !Type {...@@ -988,13 +1001,28 @@ fn generateVaListType(comp: *Compilation) !Type {
988fn generateIntMax(comp: *const Compilation, w: anytype, name: []const u8, ty: Type) !void {1001fn generateIntMax(comp: *const Compilation, w: anytype, name: []const u8, ty: Type) !void {
989 const bit_count: u8 = @intCast(ty.sizeof(comp).? * 8);1002 const bit_count: u8 = @intCast(ty.sizeof(comp).? * 8);
990 const unsigned = ty.isUnsignedInt(comp);1003 const unsigned = ty.isUnsignedInt(comp);
991 const max = if (bit_count == 128)1004 const max: u128 = switch (bit_count) {
992 @as(u128, if (unsigned) std.math.maxInt(u128) else std.math.maxInt(u128))1005 8 => if (unsigned) std.math.maxInt(u8) else std.math.maxInt(i8),
993 else1006 16 => if (unsigned) std.math.maxInt(u16) else std.math.maxInt(i16),
994 ty.maxInt(comp);1007 32 => if (unsigned) std.math.maxInt(u32) else std.math.maxInt(i32),
1008 64 => if (unsigned) std.math.maxInt(u64) else std.math.maxInt(i64),
1009 128 => if (unsigned) std.math.maxInt(u128) else std.math.maxInt(i128),
1010 else => unreachable,
1011 };
995 try w.print("#define __{s}_MAX__ {d}{s}\n", .{ name, max, ty.intValueSuffix(comp) });1012 try w.print("#define __{s}_MAX__ {d}{s}\n", .{ name, max, ty.intValueSuffix(comp) });
996}1013}
9971014
1015/// Largest value that can be stored in wchar_t
1016pub fn wcharMax(comp: *const Compilation) u32 {
1017 const unsigned = comp.types.wchar.isUnsignedInt(comp);
1018 return switch (comp.types.wchar.bitSizeof(comp).?) {
1019 8 => if (unsigned) std.math.maxInt(u8) else std.math.maxInt(i8),
1020 16 => if (unsigned) std.math.maxInt(u16) else std.math.maxInt(i16),
1021 32 => if (unsigned) std.math.maxInt(u32) else std.math.maxInt(i32),
1022 else => unreachable,
1023 };
1024}
1025
998fn generateExactWidthIntMax(comp: *const Compilation, w: anytype, specifier: Type.Specifier) !void {1026fn generateExactWidthIntMax(comp: *const Compilation, w: anytype, specifier: Type.Specifier) !void {
999 var ty = Type{ .specifier = specifier };1027 var ty = Type{ .specifier = specifier };
1000 const bit_count: u8 = @intCast(ty.sizeof(comp).? * 8);1028 const bit_count: u8 = @intCast(ty.sizeof(comp).? * 8);
...@@ -1039,6 +1067,12 @@ pub fn nextLargestIntSameSign(comp: *const Compilation, ty: Type) ?Type {...@@ -1039,6 +1067,12 @@ pub fn nextLargestIntSameSign(comp: *const Compilation, ty: Type) ?Type {
1039 return null;1067 return null;
1040}1068}
10411069
1070/// Maximum size of an array, in bytes
1071pub fn maxArrayBytes(comp: *const Compilation) u64 {
1072 const max_bits = @min(61, comp.target.ptrBitWidth());
1073 return (@as(u64, 1) << @truncate(max_bits)) - 1;
1074}
1075
1042/// If `enum E { ... }` syntax has a fixed underlying integer type regardless of the presence of1076/// If `enum E { ... }` syntax has a fixed underlying integer type regardless of the presence of
1043/// __attribute__((packed)) or the range of values of the corresponding enumerator constants,1077/// __attribute__((packed)) or the range of values of the corresponding enumerator constants,
1044/// specify it here.1078/// specify it here.
...@@ -1060,7 +1094,7 @@ pub fn getCharSignedness(comp: *const Compilation) std.builtin.Signedness {...@@ -1060,7 +1094,7 @@ pub fn getCharSignedness(comp: *const Compilation) std.builtin.Signedness {
1060pub fn addBuiltinIncludeDir(comp: *Compilation, aro_dir: []const u8) !void {1094pub fn addBuiltinIncludeDir(comp: *Compilation, aro_dir: []const u8) !void {
1061 var search_path = aro_dir;1095 var search_path = aro_dir;
1062 while (std.fs.path.dirname(search_path)) |dirname| : (search_path = dirname) {1096 while (std.fs.path.dirname(search_path)) |dirname| : (search_path = dirname) {
1063 var base_dir = std.fs.cwd().openDir(dirname, .{}) catch continue;1097 var base_dir = comp.cwd.openDir(dirname, .{}) catch continue;
1064 defer base_dir.close();1098 defer base_dir.close();
10651099
1066 base_dir.access("include/stddef.h", .{}) catch continue;1100 base_dir.access("include/stddef.h", .{}) catch continue;
...@@ -1266,7 +1300,7 @@ fn addSourceFromPathExtra(comp: *Compilation, path: []const u8, kind: Source.Kin...@@ -1266,7 +1300,7 @@ fn addSourceFromPathExtra(comp: *Compilation, path: []const u8, kind: Source.Kin
1266 return error.FileNotFound;1300 return error.FileNotFound;
1267 }1301 }
12681302
1269 const file = try std.fs.cwd().openFile(path, .{});1303 const file = try comp.cwd.openFile(path, .{});
1270 defer file.close();1304 defer file.close();
12711305
1272 const contents = file.readToEndAlloc(comp.gpa, std.math.maxInt(u32)) catch |err| switch (err) {1306 const contents = file.readToEndAlloc(comp.gpa, std.math.maxInt(u32)) catch |err| switch (err) {
...@@ -1349,10 +1383,9 @@ pub fn hasInclude(...@@ -1349,10 +1383,9 @@ pub fn hasInclude(
1349 return false;1383 return false;
1350 }1384 }
13511385
1352 const cwd = std.fs.cwd();
1353 if (std.fs.path.isAbsolute(filename)) {1386 if (std.fs.path.isAbsolute(filename)) {
1354 if (which == .next) return false;1387 if (which == .next) return false;
1355 return !std.meta.isError(cwd.access(filename, .{}));1388 return !std.meta.isError(comp.cwd.access(filename, .{}));
1356 }1389 }
13571390
1358 const cwd_source_id = switch (include_type) {1391 const cwd_source_id = switch (include_type) {
...@@ -1372,7 +1405,7 @@ pub fn hasInclude(...@@ -1372,7 +1405,7 @@ pub fn hasInclude(
13721405
1373 while (try it.nextWithFile(filename, sf_allocator)) |found| {1406 while (try it.nextWithFile(filename, sf_allocator)) |found| {
1374 defer sf_allocator.free(found.path);1407 defer sf_allocator.free(found.path);
1375 if (!std.meta.isError(cwd.access(found.path, .{}))) return true;1408 if (!std.meta.isError(comp.cwd.access(found.path, .{}))) return true;
1376 }1409 }
1377 return false;1410 return false;
1378}1411}
...@@ -1392,7 +1425,7 @@ fn getFileContents(comp: *Compilation, path: []const u8, limit: ?u32) ![]const u...@@ -1392,7 +1425,7 @@ fn getFileContents(comp: *Compilation, path: []const u8, limit: ?u32) ![]const u
1392 return error.FileNotFound;1425 return error.FileNotFound;
1393 }1426 }
13941427
1395 const file = try std.fs.cwd().openFile(path, .{});1428 const file = try comp.cwd.openFile(path, .{});
1396 defer file.close();1429 defer file.close();
13971430
1398 var buf = std.ArrayList(u8).init(comp.gpa);1431 var buf = std.ArrayList(u8).init(comp.gpa);
...@@ -1571,6 +1604,17 @@ pub fn hasBuiltinFunction(comp: *const Compilation, builtin: Builtin) bool {...@@ -1571,6 +1604,17 @@ pub fn hasBuiltinFunction(comp: *const Compilation, builtin: Builtin) bool {
1571 }1604 }
1572}1605}
15731606
1607pub fn locSlice(comp: *const Compilation, loc: Source.Location) []const u8 {
1608 var tmp_tokenizer = Tokenizer{
1609 .buf = comp.getSource(loc.id).buf,
1610 .langopts = comp.langopts,
1611 .index = loc.byte_offset,
1612 .source = .generated,
1613 };
1614 const tok = tmp_tokenizer.next();
1615 return tmp_tokenizer.buf[tok.start..tok.end];
1616}
1617
1574pub const CharUnitSize = enum(u32) {1618pub const CharUnitSize = enum(u32) {
1575 @"1" = 1,1619 @"1" = 1,
1576 @"2" = 2,1620 @"2" = 2,
...@@ -1590,7 +1634,7 @@ pub const addDiagnostic = Diagnostics.add;...@@ -1590,7 +1634,7 @@ pub const addDiagnostic = Diagnostics.add;
1590test "addSourceFromReader" {1634test "addSourceFromReader" {
1591 const Test = struct {1635 const Test = struct {
1592 fn addSourceFromReader(str: []const u8, expected: []const u8, warning_count: u32, splices: []const u32) !void {1636 fn addSourceFromReader(str: []const u8, expected: []const u8, warning_count: u32, splices: []const u32) !void {
1593 var comp = Compilation.init(std.testing.allocator);1637 var comp = Compilation.init(std.testing.allocator, std.fs.cwd());
1594 defer comp.deinit();1638 defer comp.deinit();
15951639
1596 var buf_reader = std.io.fixedBufferStream(str);1640 var buf_reader = std.io.fixedBufferStream(str);
...@@ -1602,7 +1646,7 @@ test "addSourceFromReader" {...@@ -1602,7 +1646,7 @@ test "addSourceFromReader" {
1602 }1646 }
16031647
1604 fn withAllocationFailures(allocator: std.mem.Allocator) !void {1648 fn withAllocationFailures(allocator: std.mem.Allocator) !void {
1605 var comp = Compilation.init(allocator);1649 var comp = Compilation.init(allocator, std.fs.cwd());
1606 defer comp.deinit();1650 defer comp.deinit();
16071651
1608 _ = try comp.addSourceFromBuffer("path", "spliced\\\nbuffer\n");1652 _ = try comp.addSourceFromBuffer("path", "spliced\\\nbuffer\n");
...@@ -1644,7 +1688,7 @@ test "addSourceFromReader - exhaustive check for carriage return elimination" {...@@ -1644,7 +1688,7 @@ test "addSourceFromReader - exhaustive check for carriage return elimination" {
1644 const alen = alphabet.len;1688 const alen = alphabet.len;
1645 var buf: [alphabet.len]u8 = [1]u8{alphabet[0]} ** alen;1689 var buf: [alphabet.len]u8 = [1]u8{alphabet[0]} ** alen;
16461690
1647 var comp = Compilation.init(std.testing.allocator);1691 var comp = Compilation.init(std.testing.allocator, std.fs.cwd());
1648 defer comp.deinit();1692 defer comp.deinit();
16491693
1650 var source_count: u32 = 0;1694 var source_count: u32 = 0;
...@@ -1672,7 +1716,7 @@ test "ignore BOM at beginning of file" {...@@ -1672,7 +1716,7 @@ test "ignore BOM at beginning of file" {
16721716
1673 const Test = struct {1717 const Test = struct {
1674 fn run(buf: []const u8) !void {1718 fn run(buf: []const u8) !void {
1675 var comp = Compilation.init(std.testing.allocator);1719 var comp = Compilation.init(std.testing.allocator, std.fs.cwd());
1676 defer comp.deinit();1720 defer comp.deinit();
16771721
1678 var buf_reader = std.io.fixedBufferStream(buf);1722 var buf_reader = std.io.fixedBufferStream(buf);
lib/compiler/aro/aro/Diagnostics.zig+13-2
...@@ -47,6 +47,10 @@ pub const Message = struct {...@@ -47,6 +47,10 @@ pub const Message = struct {
47 tag: Attribute.Tag,47 tag: Attribute.Tag,
48 specifier: enum { @"struct", @"union", @"enum" },48 specifier: enum { @"struct", @"union", @"enum" },
49 },49 },
50 attribute_todo: struct {
51 tag: Attribute.Tag,
52 kind: enum { variables, fields, types, functions },
53 },
50 builtin_with_header: struct {54 builtin_with_header: struct {
51 builtin: Builtin.Tag,55 builtin: Builtin.Tag,
52 header: Header,56 header: Header,
...@@ -210,6 +214,9 @@ pub const Options = struct {...@@ -210,6 +214,9 @@ pub const Options = struct {
210 normalized: Kind = .default,214 normalized: Kind = .default,
211 @"shift-count-negative": Kind = .default,215 @"shift-count-negative": Kind = .default,
212 @"shift-count-overflow": Kind = .default,216 @"shift-count-overflow": Kind = .default,
217 @"constant-conversion": Kind = .default,
218 @"sign-conversion": Kind = .default,
219 nonnull: Kind = .default,
213};220};
214221
215const Diagnostics = @This();222const Diagnostics = @This();
...@@ -222,14 +229,14 @@ errors: u32 = 0,...@@ -222,14 +229,14 @@ errors: u32 = 0,
222macro_backtrace_limit: u32 = 6,229macro_backtrace_limit: u32 = 6,
223230
224pub fn warningExists(name: []const u8) bool {231pub fn warningExists(name: []const u8) bool {
225 inline for (std.meta.fields(Options)) |f| {232 inline for (@typeInfo(Options).@"struct".fields) |f| {
226 if (mem.eql(u8, f.name, name)) return true;233 if (mem.eql(u8, f.name, name)) return true;
227 }234 }
228 return false;235 return false;
229}236}
230237
231pub fn set(d: *Diagnostics, name: []const u8, to: Kind) !void {238pub fn set(d: *Diagnostics, name: []const u8, to: Kind) !void {
232 inline for (std.meta.fields(Options)) |f| {239 inline for (@typeInfo(Options).@"struct".fields) |f| {
233 if (mem.eql(u8, f.name, name)) {240 if (mem.eql(u8, f.name, name)) {
234 @field(d.options, f.name) = to;241 @field(d.options, f.name) = to;
235 return;242 return;
...@@ -422,6 +429,10 @@ pub fn renderMessage(comp: *Compilation, m: anytype, msg: Message) void {...@@ -422,6 +429,10 @@ pub fn renderMessage(comp: *Compilation, m: anytype, msg: Message) void {
422 @tagName(msg.extra.ignored_record_attr.tag),429 @tagName(msg.extra.ignored_record_attr.tag),
423 @tagName(msg.extra.ignored_record_attr.specifier),430 @tagName(msg.extra.ignored_record_attr.specifier),
424 }),431 }),
432 .attribute_todo => printRt(m, prop.msg, .{ "{s}", "{s}" }, .{
433 @tagName(msg.extra.attribute_todo.tag),
434 @tagName(msg.extra.attribute_todo.kind),
435 }),
425 .builtin_with_header => printRt(m, prop.msg, .{ "{s}", "{s}" }, .{436 .builtin_with_header => printRt(m, prop.msg, .{ "{s}", "{s}" }, .{
426 @tagName(msg.extra.builtin_with_header.header),437 @tagName(msg.extra.builtin_with_header.header),
427 Builtin.nameFromTag(msg.extra.builtin_with_header.builtin).span(),438 Builtin.nameFromTag(msg.extra.builtin_with_header.builtin).span(),
lib/compiler/aro/aro/Diagnostics/messages.zig+24-4
...@@ -107,6 +107,9 @@ pub const Tag = enum {...@@ -107,6 +107,9 @@ pub const Tag = enum {
107 multiple_default,107 multiple_default,
108 previous_case,108 previous_case,
109 expected_arguments,109 expected_arguments,
110 callee_with_static_array,
111 array_argument_too_small,
112 non_null_argument,
110 expected_arguments_old,113 expected_arguments_old,
111 expected_at_least_arguments,114 expected_at_least_arguments,
112 invalid_static_star,115 invalid_static_star,
...@@ -214,6 +217,7 @@ pub const Tag = enum {...@@ -214,6 +217,7 @@ pub const Tag = enum {
214 pre_c23_compat,217 pre_c23_compat,
215 unbound_vla,218 unbound_vla,
216 array_too_large,219 array_too_large,
220 record_too_large,
217 incompatible_ptr_init,221 incompatible_ptr_init,
218 incompatible_ptr_init_sign,222 incompatible_ptr_init_sign,
219 incompatible_ptr_assign,223 incompatible_ptr_assign,
...@@ -349,6 +353,8 @@ pub const Tag = enum {...@@ -349,6 +353,8 @@ pub const Tag = enum {
349 non_standard_escape_char,353 non_standard_escape_char,
350 invalid_pp_stringify_escape,354 invalid_pp_stringify_escape,
351 vla,355 vla,
356 int_value_changed,
357 sign_conversion,
352 float_overflow_conversion,358 float_overflow_conversion,
353 float_out_of_range,359 float_out_of_range,
354 float_zero_conversion,360 float_zero_conversion,
...@@ -425,7 +431,8 @@ pub const Tag = enum {...@@ -425,7 +431,8 @@ pub const Tag = enum {
425 bit_int,431 bit_int,
426 unsigned_bit_int_too_small,432 unsigned_bit_int_too_small,
427 signed_bit_int_too_small,433 signed_bit_int_too_small,
428 bit_int_too_big,434 unsigned_bit_int_too_big,
435 signed_bit_int_too_big,
429 keyword_macro,436 keyword_macro,
430 ptr_arithmetic_incomplete,437 ptr_arithmetic_incomplete,
431 callconv_not_supported,438 callconv_not_supported,
...@@ -509,6 +516,9 @@ pub const Tag = enum {...@@ -509,6 +516,9 @@ pub const Tag = enum {
509 complex_conj,516 complex_conj,
510 overflow_builtin_requires_int,517 overflow_builtin_requires_int,
511 overflow_result_requires_ptr,518 overflow_result_requires_ptr,
519 attribute_todo,
520 invalid_type_underlying_enum,
521 auto_type_self_initialized,
512522
513 pub fn property(tag: Tag) Properties {523 pub fn property(tag: Tag) Properties {
514 return named_data[@intFromEnum(tag)];524 return named_data[@intFromEnum(tag)];
...@@ -613,6 +623,9 @@ pub const Tag = enum {...@@ -613,6 +623,9 @@ pub const Tag = enum {
613 .{ .msg = "multiple default cases in the same switch", .kind = .@"error" },623 .{ .msg = "multiple default cases in the same switch", .kind = .@"error" },
614 .{ .msg = "previous case defined here", .kind = .note },624 .{ .msg = "previous case defined here", .kind = .note },
615 .{ .msg = expected_arguments, .extra = .arguments, .kind = .@"error" },625 .{ .msg = expected_arguments, .extra = .arguments, .kind = .@"error" },
626 .{ .msg = "callee declares array parameter as static here", .kind = .note },
627 .{ .msg = "array argument is too small; contains {d} elements, callee requires at least {d}", .extra = .arguments, .kind = .warning, .opt = W("array-bounds") },
628 .{ .msg = "null passed to a callee that requires a non-null argument", .kind = .warning, .opt = W("nonnull") },
616 .{ .msg = expected_arguments, .extra = .arguments, .kind = .warning },629 .{ .msg = expected_arguments, .extra = .arguments, .kind = .warning },
617 .{ .msg = "expected at least {d} argument(s) got {d}", .extra = .arguments, .kind = .warning },630 .{ .msg = "expected at least {d} argument(s) got {d}", .extra = .arguments, .kind = .warning },
618 .{ .msg = "'static' may not be used with an unspecified variable length array size", .kind = .@"error" },631 .{ .msg = "'static' may not be used with an unspecified variable length array size", .kind = .@"error" },
...@@ -720,6 +733,7 @@ pub const Tag = enum {...@@ -720,6 +733,7 @@ pub const Tag = enum {
720 .{ .msg = "{s} is incompatible with C standards before C23", .extra = .str, .kind = .off, .suppress_unless_version = .c23, .opt = W("pre-c23-compat") },733 .{ .msg = "{s} is incompatible with C standards before C23", .extra = .str, .kind = .off, .suppress_unless_version = .c23, .opt = W("pre-c23-compat") },
721 .{ .msg = "variable length array must be bound in function definition", .kind = .@"error" },734 .{ .msg = "variable length array must be bound in function definition", .kind = .@"error" },
722 .{ .msg = "array is too large", .kind = .@"error" },735 .{ .msg = "array is too large", .kind = .@"error" },
736 .{ .msg = "type '{s}' is too large", .kind = .@"error", .extra = .str },
723 .{ .msg = "incompatible pointer types initializing {s}", .extra = .str, .opt = W("incompatible-pointer-types"), .kind = .warning },737 .{ .msg = "incompatible pointer types initializing {s}", .extra = .str, .opt = W("incompatible-pointer-types"), .kind = .warning },
724 .{ .msg = "incompatible pointer types initializing {s}" ++ pointer_sign_message, .extra = .str, .opt = W("pointer-sign"), .kind = .warning },738 .{ .msg = "incompatible pointer types initializing {s}" ++ pointer_sign_message, .extra = .str, .opt = W("pointer-sign"), .kind = .warning },
725 .{ .msg = "incompatible pointer types assigning to {s}", .extra = .str, .opt = W("incompatible-pointer-types"), .kind = .warning },739 .{ .msg = "incompatible pointer types assigning to {s}", .extra = .str, .opt = W("incompatible-pointer-types"), .kind = .warning },
...@@ -855,6 +869,8 @@ pub const Tag = enum {...@@ -855,6 +869,8 @@ pub const Tag = enum {
855 .{ .msg = "use of non-standard escape character '\\{s}'", .kind = .off, .opt = W("pedantic"), .extra = .invalid_escape },869 .{ .msg = "use of non-standard escape character '\\{s}'", .kind = .off, .opt = W("pedantic"), .extra = .invalid_escape },
856 .{ .msg = "invalid string literal, ignoring final '\\'", .kind = .warning },870 .{ .msg = "invalid string literal, ignoring final '\\'", .kind = .warning },
857 .{ .msg = "variable length array used", .kind = .off, .opt = W("vla") },871 .{ .msg = "variable length array used", .kind = .off, .opt = W("vla") },
872 .{ .msg = "implicit conversion from {s}", .extra = .str, .kind = .warning, .opt = W("constant-conversion") },
873 .{ .msg = "implicit conversion changes signedness: {s}", .extra = .str, .kind = .off, .opt = W("sign-conversion") },
858 .{ .msg = "implicit conversion of non-finite value from {s} is undefined", .extra = .str, .kind = .off, .opt = W("float-overflow-conversion") },874 .{ .msg = "implicit conversion of non-finite value from {s} is undefined", .extra = .str, .kind = .off, .opt = W("float-overflow-conversion") },
859 .{ .msg = "implicit conversion of out of range value from {s} is undefined", .extra = .str, .kind = .warning, .opt = W("literal-conversion") },875 .{ .msg = "implicit conversion of out of range value from {s} is undefined", .extra = .str, .kind = .warning, .opt = W("literal-conversion") },
860 .{ .msg = "implicit conversion from {s}", .extra = .str, .kind = .off, .opt = W("float-zero-conversion") },876 .{ .msg = "implicit conversion from {s}", .extra = .str, .kind = .off, .opt = W("float-zero-conversion") },
...@@ -929,9 +945,10 @@ pub const Tag = enum {...@@ -929,9 +945,10 @@ pub const Tag = enum {
929 .{ .msg = "this declarator", .kind = .note },945 .{ .msg = "this declarator", .kind = .note },
930 .{ .msg = "{s} is not supported on this target", .extra = .str, .kind = .@"error" },946 .{ .msg = "{s} is not supported on this target", .extra = .str, .kind = .@"error" },
931 .{ .msg = "'_BitInt' in C17 and earlier is a Clang extension'", .kind = .off, .pedantic = true, .opt = W("bit-int-extension"), .suppress_version = .c23 },947 .{ .msg = "'_BitInt' in C17 and earlier is a Clang extension'", .kind = .off, .pedantic = true, .opt = W("bit-int-extension"), .suppress_version = .c23 },
932 .{ .msg = "{s} must have a bit size of at least 1", .extra = .str, .kind = .@"error" },948 .{ .msg = "{s}unsigned _BitInt must have a bit size of at least 1", .extra = .str, .kind = .@"error" },
933 .{ .msg = "{s} must have a bit size of at least 2", .extra = .str, .kind = .@"error" },949 .{ .msg = "{s}signed _BitInt must have a bit size of at least 2", .extra = .str, .kind = .@"error" },
934 .{ .msg = "{s} of bit sizes greater than " ++ std.fmt.comptimePrint("{d}", .{Properties.max_bits}) ++ " not supported", .extra = .str, .kind = .@"error" },950 .{ .msg = "{s}unsigned _BitInt of bit sizes greater than " ++ std.fmt.comptimePrint("{d}", .{Properties.max_bits}) ++ " not supported", .extra = .str, .kind = .@"error" },
951 .{ .msg = "{s}signed _BitInt of bit sizes greater than " ++ std.fmt.comptimePrint("{d}", .{Properties.max_bits}) ++ " not supported", .extra = .str, .kind = .@"error" },
935 .{ .msg = "keyword is hidden by macro definition", .kind = .off, .pedantic = true, .opt = W("keyword-macro") },952 .{ .msg = "keyword is hidden by macro definition", .kind = .off, .pedantic = true, .opt = W("keyword-macro") },
936 .{ .msg = "arithmetic on a pointer to an incomplete type '{s}'", .extra = .str, .kind = .@"error" },953 .{ .msg = "arithmetic on a pointer to an incomplete type '{s}'", .extra = .str, .kind = .@"error" },
937 .{ .msg = "'{s}' calling convention is not supported for this target", .extra = .str, .opt = W("ignored-attributes"), .kind = .warning },954 .{ .msg = "'{s}' calling convention is not supported for this target", .extra = .str, .opt = W("ignored-attributes"), .kind = .warning },
...@@ -1015,6 +1032,9 @@ pub const Tag = enum {...@@ -1015,6 +1032,9 @@ pub const Tag = enum {
1015 .{ .msg = "ISO C does not support '~' for complex conjugation of '{s}'", .opt = W("pedantic"), .extra = .str, .kind = .off },1032 .{ .msg = "ISO C does not support '~' for complex conjugation of '{s}'", .opt = W("pedantic"), .extra = .str, .kind = .off },
1016 .{ .msg = "operand argument to overflow builtin must be an integer ('{s}' invalid)", .extra = .str, .kind = .@"error" },1033 .{ .msg = "operand argument to overflow builtin must be an integer ('{s}' invalid)", .extra = .str, .kind = .@"error" },
1017 .{ .msg = "result argument to overflow builtin must be a pointer to a non-const integer ('{s}' invalid)", .extra = .str, .kind = .@"error" },1034 .{ .msg = "result argument to overflow builtin must be a pointer to a non-const integer ('{s}' invalid)", .extra = .str, .kind = .@"error" },
1035 .{ .msg = "TODO: implement '{s}' attribute for {s}", .extra = .attribute_todo, .kind = .@"error" },
1036 .{ .msg = "non-integral type '{s}' is an invalid underlying type", .extra = .str, .kind = .@"error" },
1037 .{ .msg = "variable '{s}' declared with deduced type '__auto_type' cannot appear in its own initializer", .extra = .str, .kind = .@"error" },
1018 };1038 };
1019};1039};
1020};1040};
lib/compiler/aro/aro/Driver.zig+30-2
...@@ -47,6 +47,20 @@ color: ?bool = null,...@@ -47,6 +47,20 @@ color: ?bool = null,
47nobuiltininc: bool = false,47nobuiltininc: bool = false,
48nostdinc: bool = false,48nostdinc: bool = false,
49nostdlibinc: bool = false,49nostdlibinc: bool = false,
50debug_dump_letters: packed struct(u3) {
51 d: bool = false,
52 m: bool = false,
53 n: bool = false,
54
55 /// According to GCC, specifying letters whose behavior conflicts is undefined.
56 /// We follow clang in that `-dM` always takes precedence over `-dD`
57 pub fn getPreprocessorDumpMode(self: @This()) Preprocessor.DumpMode {
58 if (self.m) return .macros_only;
59 if (self.d) return .macros_and_result;
60 if (self.n) return .macro_names_and_result;
61 return .result_only;
62 }
63} = .{},
5064
51/// Full path to the aro executable65/// Full path to the aro executable
52aro_name: []const u8 = "",66aro_name: []const u8 = "",
...@@ -92,6 +106,9 @@ pub const usage =...@@ -92,6 +106,9 @@ pub const usage =
92 \\106 \\
93 \\Compile options:107 \\Compile options:
94 \\ -c, --compile Only run preprocess, compile, and assemble steps108 \\ -c, --compile Only run preprocess, compile, and assemble steps
109 \\ -dM Output #define directives for all the macros defined during the execution of the preprocessor
110 \\ -dD Like -dM except that it outputs both the #define directives and the result of preprocessing
111 \\ -dN Like -dD, but emit only the macro names, not their expansions.
95 \\ -D <macro>=<value> Define <macro> to <value> (defaults to 1)112 \\ -D <macro>=<value> Define <macro> to <value> (defaults to 1)
96 \\ -E Only run the preprocessor113 \\ -E Only run the preprocessor
97 \\ -fchar8_t Enable char8_t (enabled by default in C23 and later)114 \\ -fchar8_t Enable char8_t (enabled by default in C23 and later)
...@@ -234,6 +251,12 @@ pub fn parseArgs(...@@ -234,6 +251,12 @@ pub fn parseArgs(
234 d.system_defines = .no_system_defines;251 d.system_defines = .no_system_defines;
235 } else if (mem.eql(u8, arg, "-c") or mem.eql(u8, arg, "--compile")) {252 } else if (mem.eql(u8, arg, "-c") or mem.eql(u8, arg, "--compile")) {
236 d.only_compile = true;253 d.only_compile = true;
254 } else if (mem.eql(u8, arg, "-dD")) {
255 d.debug_dump_letters.d = true;
256 } else if (mem.eql(u8, arg, "-dM")) {
257 d.debug_dump_letters.m = true;
258 } else if (mem.eql(u8, arg, "-dN")) {
259 d.debug_dump_letters.n = true;
237 } else if (mem.eql(u8, arg, "-E")) {260 } else if (mem.eql(u8, arg, "-E")) {
238 d.only_preprocess = true;261 d.only_preprocess = true;
239 } else if (mem.eql(u8, arg, "-P") or mem.eql(u8, arg, "--no-line-commands")) {262 } else if (mem.eql(u8, arg, "-P") or mem.eql(u8, arg, "--no-line-commands")) {
...@@ -636,13 +659,17 @@ fn processSource(...@@ -636,13 +659,17 @@ fn processSource(
636 if (d.comp.langopts.ms_extensions) {659 if (d.comp.langopts.ms_extensions) {
637 d.comp.ms_cwd_source_id = source.id;660 d.comp.ms_cwd_source_id = source.id;
638 }661 }
639662 const dump_mode = d.debug_dump_letters.getPreprocessorDumpMode();
640 if (d.verbose_pp) pp.verbose = true;663 if (d.verbose_pp) pp.verbose = true;
641 if (d.only_preprocess) {664 if (d.only_preprocess) {
642 pp.preserve_whitespace = true;665 pp.preserve_whitespace = true;
643 if (d.line_commands) {666 if (d.line_commands) {
644 pp.linemarkers = if (d.use_line_directives) .line_directives else .numeric_directives;667 pp.linemarkers = if (d.use_line_directives) .line_directives else .numeric_directives;
645 }668 }
669 switch (dump_mode) {
670 .macros_and_result, .macro_names_and_result => pp.store_macro_tokens = true,
671 .result_only, .macros_only => {},
672 }
646 }673 }
647674
648 try pp.preprocessSources(&.{ source, builtin, user_macros });675 try pp.preprocessSources(&.{ source, builtin, user_macros });
...@@ -663,7 +690,8 @@ fn processSource(...@@ -663,7 +690,8 @@ fn processSource(
663 defer if (d.output_name != null) file.close();690 defer if (d.output_name != null) file.close();
664691
665 var buf_w = std.io.bufferedWriter(file.writer());692 var buf_w = std.io.bufferedWriter(file.writer());
666 pp.prettyPrintTokens(buf_w.writer()) catch |er|693
694 pp.prettyPrintTokens(buf_w.writer(), dump_mode) catch |er|
667 return d.fatal("unable to write result: {s}", .{errorDescription(er)});695 return d.fatal("unable to write result: {s}", .{errorDescription(er)});
668696
669 buf_w.flush() catch |er|697 buf_w.flush() catch |er|
lib/compiler/aro/aro/Driver/Filesystem.zig+2-2
...@@ -56,7 +56,7 @@ fn existsFake(entries: []const Filesystem.Entry, path: []const u8) bool {...@@ -56,7 +56,7 @@ fn existsFake(entries: []const Filesystem.Entry, path: []const u8) bool {
56}56}
5757
58fn canExecutePosix(path: []const u8) bool {58fn canExecutePosix(path: []const u8) bool {
59 std.os.access(path, std.os.X_OK) catch return false;59 std.posix.access(path, std.posix.X_OK) catch return false;
60 // Todo: ensure path is not a directory60 // Todo: ensure path is not a directory
61 return true;61 return true;
62}62}
...@@ -173,7 +173,7 @@ pub const Filesystem = union(enum) {...@@ -173,7 +173,7 @@ pub const Filesystem = union(enum) {
173 pub fn exists(fs: Filesystem, path: []const u8) bool {173 pub fn exists(fs: Filesystem, path: []const u8) bool {
174 switch (fs) {174 switch (fs) {
175 .real => {175 .real => {
176 std.os.access(path, std.os.F_OK) catch return false;176 std.fs.cwd().access(path, .{}) catch return false;
177 return true;177 return true;
178 },178 },
179 .fake => |paths| return existsFake(paths, path),179 .fake => |paths| return existsFake(paths, path),
lib/compiler/aro/aro/Hideset.zig+27-22
...@@ -46,15 +46,15 @@ const Item = struct {...@@ -46,15 +46,15 @@ const Item = struct {
46 const List = std.MultiArrayList(Item);46 const List = std.MultiArrayList(Item);
47};47};
4848
49const Index = enum(u32) {49pub const Index = enum(u32) {
50 none = std.math.maxInt(u32),50 none = std.math.maxInt(u32),
51 _,51 _,
52};52};
5353
54map: std.AutoHashMapUnmanaged(Identifier, Index) = .{},54map: std.AutoHashMapUnmanaged(Identifier, Index) = .{},
55/// Used for computing intersection of two lists; stored here so that allocations can be retained55/// Used for computing union/intersection of two lists; stored here so that allocations can be retained
56/// until hideset is deinit'ed56/// until hideset is deinit'ed
57intersection_map: std.AutoHashMapUnmanaged(Identifier, void) = .{},57tmp_map: std.AutoHashMapUnmanaged(Identifier, void) = .{},
58linked_list: Item.List = .{},58linked_list: Item.List = .{},
59comp: *const Compilation,59comp: *const Compilation,
6060
...@@ -72,7 +72,7 @@ const Iterator = struct {...@@ -72,7 +72,7 @@ const Iterator = struct {
7272
73pub fn deinit(self: *Hideset) void {73pub fn deinit(self: *Hideset) void {
74 self.map.deinit(self.comp.gpa);74 self.map.deinit(self.comp.gpa);
75 self.intersection_map.deinit(self.comp.gpa);75 self.tmp_map.deinit(self.comp.gpa);
76 self.linked_list.deinit(self.comp.gpa);76 self.linked_list.deinit(self.comp.gpa);
77}77}
7878
...@@ -83,7 +83,7 @@ pub fn clearRetainingCapacity(self: *Hideset) void {...@@ -83,7 +83,7 @@ pub fn clearRetainingCapacity(self: *Hideset) void {
8383
84pub fn clearAndFree(self: *Hideset) void {84pub fn clearAndFree(self: *Hideset) void {
85 self.map.clearAndFree(self.comp.gpa);85 self.map.clearAndFree(self.comp.gpa);
86 self.intersection_map.clearAndFree(self.comp.gpa);86 self.tmp_map.clearAndFree(self.comp.gpa);
87 self.linked_list.shrinkAndFree(self.comp.gpa, 0);87 self.linked_list.shrinkAndFree(self.comp.gpa, 0);
88}88}
8989
...@@ -109,8 +109,13 @@ fn ensureUnusedCapacity(self: *Hideset, new_size: usize) !void {...@@ -109,8 +109,13 @@ fn ensureUnusedCapacity(self: *Hideset, new_size: usize) !void {
109109
110/// Creates a one-item list with contents `identifier`110/// Creates a one-item list with contents `identifier`
111fn createNodeAssumeCapacity(self: *Hideset, identifier: Identifier) Index {111fn createNodeAssumeCapacity(self: *Hideset, identifier: Identifier) Index {
112 return self.createNodeAssumeCapacityExtra(identifier, .none);
113}
114
115/// Creates a one-item list with contents `identifier`
116fn createNodeAssumeCapacityExtra(self: *Hideset, identifier: Identifier, next: Index) Index {
112 const next_idx = self.linked_list.len;117 const next_idx = self.linked_list.len;
113 self.linked_list.appendAssumeCapacity(.{ .identifier = identifier });118 self.linked_list.appendAssumeCapacity(.{ .identifier = identifier, .next = next });
114 return @enumFromInt(next_idx);119 return @enumFromInt(next_idx);
115}120}
116121
...@@ -121,24 +126,24 @@ pub fn prepend(self: *Hideset, loc: Source.Location, tail: Index) !Index {...@@ -121,24 +126,24 @@ pub fn prepend(self: *Hideset, loc: Source.Location, tail: Index) !Index {
121 return @enumFromInt(new_idx);126 return @enumFromInt(new_idx);
122}127}
123128
124/// Copy a, then attach b at the end129/// Attach elements of `b` to the front of `a` (if they're not in `a`)
125pub fn @"union"(self: *Hideset, a: Index, b: Index) !Index {130pub fn @"union"(self: *Hideset, a: Index, b: Index) !Index {
126 var cur: Index = .none;131 if (a == .none) return b;
132 if (b == .none) return a;
133 self.tmp_map.clearRetainingCapacity();
134
135 var it = self.iterator(b);
136 while (it.next()) |identifier| {
137 try self.tmp_map.put(self.comp.gpa, identifier, {});
138 }
139
127 var head: Index = b;140 var head: Index = b;
128 try self.ensureUnusedCapacity(self.len(a));141 try self.ensureUnusedCapacity(self.len(a));
129 var it = self.iterator(a);142 it = self.iterator(a);
130 while (it.next()) |identifier| {143 while (it.next()) |identifier| {
131 const new_idx = self.createNodeAssumeCapacity(identifier);144 if (!self.tmp_map.contains(identifier)) {
132 if (head == b) {145 head = self.createNodeAssumeCapacityExtra(identifier, head);
133 head = new_idx;
134 }146 }
135 if (cur != .none) {
136 self.linked_list.items(.next)[@intFromEnum(cur)] = new_idx;
137 }
138 cur = new_idx;
139 }
140 if (cur != .none) {
141 self.linked_list.items(.next)[@intFromEnum(cur)] = b;
142 }147 }
143 return head;148 return head;
144}149}
...@@ -163,20 +168,20 @@ fn len(self: *const Hideset, list: Index) usize {...@@ -163,20 +168,20 @@ fn len(self: *const Hideset, list: Index) usize {
163168
164pub fn intersection(self: *Hideset, a: Index, b: Index) !Index {169pub fn intersection(self: *Hideset, a: Index, b: Index) !Index {
165 if (a == .none or b == .none) return .none;170 if (a == .none or b == .none) return .none;
166 self.intersection_map.clearRetainingCapacity();171 self.tmp_map.clearRetainingCapacity();
167172
168 var cur: Index = .none;173 var cur: Index = .none;
169 var head: Index = .none;174 var head: Index = .none;
170 var it = self.iterator(a);175 var it = self.iterator(a);
171 var a_len: usize = 0;176 var a_len: usize = 0;
172 while (it.next()) |identifier| : (a_len += 1) {177 while (it.next()) |identifier| : (a_len += 1) {
173 try self.intersection_map.put(self.comp.gpa, identifier, {});178 try self.tmp_map.put(self.comp.gpa, identifier, {});
174 }179 }
175 try self.ensureUnusedCapacity(@min(a_len, self.len(b)));180 try self.ensureUnusedCapacity(@min(a_len, self.len(b)));
176181
177 it = self.iterator(b);182 it = self.iterator(b);
178 while (it.next()) |identifier| {183 while (it.next()) |identifier| {
179 if (self.intersection_map.contains(identifier)) {184 if (self.tmp_map.contains(identifier)) {
180 const new_idx = self.createNodeAssumeCapacity(identifier);185 const new_idx = self.createNodeAssumeCapacity(identifier);
181 if (head == .none) {186 if (head == .none) {
182 head = new_idx;187 head = new_idx;
lib/compiler/aro/aro/Parser.zig+572-261
...@@ -28,6 +28,7 @@ const StrInt = @import("StringInterner.zig");...@@ -28,6 +28,7 @@ const StrInt = @import("StringInterner.zig");
28const StringId = StrInt.StringId;28const StringId = StrInt.StringId;
29const Builtins = @import("Builtins.zig");29const Builtins = @import("Builtins.zig");
30const Builtin = Builtins.Builtin;30const Builtin = Builtins.Builtin;
31const evalBuiltin = @import("Builtins/eval.zig").eval;
31const target_util = @import("target.zig");32const target_util = @import("target.zig");
3233
33const Switch = struct {34const Switch = struct {
...@@ -100,7 +101,7 @@ value_map: Tree.ValueMap,...@@ -100,7 +101,7 @@ value_map: Tree.ValueMap,
100101
101// buffers used during compilation102// buffers used during compilation
102syms: SymbolStack = .{},103syms: SymbolStack = .{},
103strings: std.ArrayList(u8),104strings: std.ArrayListAligned(u8, 4),
104labels: std.ArrayList(Label),105labels: std.ArrayList(Label),
105list_buf: NodeList,106list_buf: NodeList,
106decl_buf: NodeList,107decl_buf: NodeList,
...@@ -130,6 +131,10 @@ const_decl_folding: ConstDeclFoldingMode = .fold_const_decls,...@@ -130,6 +131,10 @@ const_decl_folding: ConstDeclFoldingMode = .fold_const_decls,
130/// address-of-label expression (tracked with contains_address_of_label)131/// address-of-label expression (tracked with contains_address_of_label)
131computed_goto_tok: ?TokenIndex = null,132computed_goto_tok: ?TokenIndex = null,
132133
134/// __auto_type may only be used with a single declarator. Keep track of the name
135/// so that it is not used in its own initializer.
136auto_type_decl_name: StringId = .empty,
137
133/// Various variables that are different for each function.138/// Various variables that are different for each function.
134func: struct {139func: struct {
135 /// null if not in function, will always be plain func, var_args_func or old_style_func140 /// null if not in function, will always be plain func, var_args_func or old_style_func
...@@ -160,7 +165,7 @@ record: struct {...@@ -160,7 +165,7 @@ record: struct {
160 }165 }
161166
162 fn addFieldsFromAnonymous(r: @This(), p: *Parser, ty: Type) Error!void {167 fn addFieldsFromAnonymous(r: @This(), p: *Parser, ty: Type) Error!void {
163 for (ty.data.record.fields) |f| {168 for (ty.getRecord().?.fields) |f| {
164 if (f.isAnonymousRecord()) {169 if (f.isAnonymousRecord()) {
165 try r.addFieldsFromAnonymous(p, f.ty.canonicalize(.standard));170 try r.addFieldsFromAnonymous(p, f.ty.canonicalize(.standard));
166 } else if (f.name_tok != 0) {171 } else if (f.name_tok != 0) {
...@@ -470,7 +475,7 @@ pub fn typePairStrExtra(p: *Parser, a: Type, msg: []const u8, b: Type) ![]const...@@ -470,7 +475,7 @@ pub fn typePairStrExtra(p: *Parser, a: Type, msg: []const u8, b: Type) ![]const
470 return try p.comp.diagnostics.arena.allocator().dupe(u8, p.strings.items[strings_top..]);475 return try p.comp.diagnostics.arena.allocator().dupe(u8, p.strings.items[strings_top..]);
471}476}
472477
473pub fn floatValueChangedStr(p: *Parser, res: *Result, old_value: Value, int_ty: Type) ![]const u8 {478pub fn valueChangedStr(p: *Parser, res: *Result, old_value: Value, int_ty: Type) ![]const u8 {
474 const strings_top = p.strings.items.len;479 const strings_top = p.strings.items.len;
475 defer p.strings.items.len = strings_top;480 defer p.strings.items.len = strings_top;
476481
...@@ -572,6 +577,14 @@ fn nodeIs(p: *Parser, node: NodeIndex, tag: Tree.Tag) bool {...@@ -572,6 +577,14 @@ fn nodeIs(p: *Parser, node: NodeIndex, tag: Tree.Tag) bool {
572 return p.getNode(node, tag) != null;577 return p.getNode(node, tag) != null;
573}578}
574579
580pub fn getDecayedStringLiteral(p: *Parser, node: NodeIndex) ?Value {
581 const cast_node = p.getNode(node, .implicit_cast) orelse return null;
582 const data = p.nodes.items(.data)[@intFromEnum(cast_node)];
583 if (data.cast.kind != .array_to_pointer) return null;
584 const literal_node = p.getNode(data.cast.operand, .string_literal_expr) orelse return null;
585 return p.value_map.get(literal_node);
586}
587
575fn getNode(p: *Parser, node: NodeIndex, tag: Tree.Tag) ?NodeIndex {588fn getNode(p: *Parser, node: NodeIndex, tag: Tree.Tag) ?NodeIndex {
576 var cur = node;589 var cur = node;
577 const tags = p.nodes.items(.tag);590 const tags = p.nodes.items(.tag);
...@@ -680,7 +693,7 @@ pub fn parse(pp: *Preprocessor) Compilation.Error!Tree {...@@ -680,7 +693,7 @@ pub fn parse(pp: *Preprocessor) Compilation.Error!Tree {
680 .gpa = pp.comp.gpa,693 .gpa = pp.comp.gpa,
681 .arena = arena.allocator(),694 .arena = arena.allocator(),
682 .tok_ids = pp.tokens.items(.id),695 .tok_ids = pp.tokens.items(.id),
683 .strings = std.ArrayList(u8).init(pp.comp.gpa),696 .strings = std.ArrayListAligned(u8, 4).init(pp.comp.gpa),
684 .value_map = Tree.ValueMap.init(pp.comp.gpa),697 .value_map = Tree.ValueMap.init(pp.comp.gpa),
685 .data = NodeList.init(pp.comp.gpa),698 .data = NodeList.init(pp.comp.gpa),
686 .labels = std.ArrayList(Label).init(pp.comp.gpa),699 .labels = std.ArrayList(Label).init(pp.comp.gpa),
...@@ -725,7 +738,7 @@ pub fn parse(pp: *Preprocessor) Compilation.Error!Tree {...@@ -725,7 +738,7 @@ pub fn parse(pp: *Preprocessor) Compilation.Error!Tree {
725 defer p.syms.popScope();738 defer p.syms.popScope();
726739
727 // NodeIndex 0 must be invalid740 // NodeIndex 0 must be invalid
728 _ = try p.addNode(.{ .tag = .invalid, .ty = undefined, .data = undefined });741 _ = try p.addNode(.{ .tag = .invalid, .ty = undefined, .data = undefined, .loc = undefined });
729742
730 {743 {
731 if (p.comp.langopts.hasChar8_T()) {744 if (p.comp.langopts.hasChar8_T()) {
...@@ -747,6 +760,10 @@ pub fn parse(pp: *Preprocessor) Compilation.Error!Tree {...@@ -747,6 +760,10 @@ pub fn parse(pp: *Preprocessor) Compilation.Error!Tree {
747 if (ty.isArray()) ty.decayArray();760 if (ty.isArray()) ty.decayArray();
748761
749 try p.syms.defineTypedef(&p, try StrInt.intern(p.comp, "__NSConstantString"), pp.comp.types.ns_constant_string.ty, 0, .none);762 try p.syms.defineTypedef(&p, try StrInt.intern(p.comp, "__NSConstantString"), pp.comp.types.ns_constant_string.ty, 0, .none);
763
764 if (p.comp.float80Type()) |float80_ty| {
765 try p.syms.defineTypedef(&p, try StrInt.intern(p.comp, "__float80"), float80_ty, 0, .none);
766 }
750 }767 }
751768
752 while (p.eatToken(.eof) == null) {769 while (p.eatToken(.eof) == null) {
...@@ -862,6 +879,8 @@ fn nextExternDecl(p: *Parser) void {...@@ -862,6 +879,8 @@ fn nextExternDecl(p: *Parser) void {
862 .keyword_int,879 .keyword_int,
863 .keyword_long,880 .keyword_long,
864 .keyword_signed,881 .keyword_signed,
882 .keyword_signed1,
883 .keyword_signed2,
865 .keyword_unsigned,884 .keyword_unsigned,
866 .keyword_float,885 .keyword_float,
867 .keyword_double,886 .keyword_double,
...@@ -1018,10 +1037,8 @@ fn decl(p: *Parser) Error!bool {...@@ -1018,10 +1037,8 @@ fn decl(p: *Parser) Error!bool {
10181037
1019 // Collect old style parameter declarations.1038 // Collect old style parameter declarations.
1020 if (init_d.d.old_style_func != null) {1039 if (init_d.d.old_style_func != null) {
1021 const attrs = init_d.d.ty.getAttributes();1040 var base_ty = init_d.d.ty.base();
1022 var base_ty = if (init_d.d.ty.specifier == .attributed) init_d.d.ty.data.attributed.base else init_d.d.ty;
1023 base_ty.specifier = .func;1041 base_ty.specifier = .func;
1024 init_d.d.ty = try base_ty.withAttributes(p.arena, attrs);
10251042
1026 const param_buf_top = p.param_buf.items.len;1043 const param_buf_top = p.param_buf.items.len;
1027 defer p.param_buf.items.len = param_buf_top;1044 defer p.param_buf.items.len = param_buf_top;
...@@ -1116,6 +1133,7 @@ fn decl(p: *Parser) Error!bool {...@@ -1116,6 +1133,7 @@ fn decl(p: *Parser) Error!bool {
1116 .ty = init_d.d.ty,1133 .ty = init_d.d.ty,
1117 .tag = try decl_spec.validateFnDef(p),1134 .tag = try decl_spec.validateFnDef(p),
1118 .data = .{ .decl = .{ .name = init_d.d.name, .node = body } },1135 .data = .{ .decl = .{ .name = init_d.d.name, .node = body } },
1136 .loc = @enumFromInt(init_d.d.name),
1119 });1137 });
1120 try p.decl_buf.append(node);1138 try p.decl_buf.append(node);
11211139
...@@ -1142,9 +1160,18 @@ fn decl(p: *Parser) Error!bool {...@@ -1142,9 +1160,18 @@ fn decl(p: *Parser) Error!bool {
1142 if (init_d.d.old_style_func) |tok_i| try p.errTok(.invalid_old_style_params, tok_i);1160 if (init_d.d.old_style_func) |tok_i| try p.errTok(.invalid_old_style_params, tok_i);
1143 const tag = try decl_spec.validate(p, &init_d.d.ty, init_d.initializer.node != .none);1161 const tag = try decl_spec.validate(p, &init_d.d.ty, init_d.initializer.node != .none);
11441162
1145 const node = try p.addNode(.{ .ty = init_d.d.ty, .tag = tag, .data = .{1163 const tok = switch (decl_spec.storage_class) {
1146 .decl = .{ .name = init_d.d.name, .node = init_d.initializer.node },1164 .auto, .@"extern", .register, .static, .typedef => |tok| tok,
1147 } });1165 .none => init_d.d.name,
1166 };
1167 const node = try p.addNode(.{
1168 .ty = init_d.d.ty,
1169 .tag = tag,
1170 .data = .{
1171 .decl = .{ .name = init_d.d.name, .node = init_d.initializer.node },
1172 },
1173 .loc = @enumFromInt(tok),
1174 });
1148 try p.decl_buf.append(node);1175 try p.decl_buf.append(node);
11491176
1150 const interned_name = try StrInt.intern(p.comp, p.tokSlice(init_d.d.name));1177 const interned_name = try StrInt.intern(p.comp, p.tokSlice(init_d.d.name));
...@@ -1287,6 +1314,7 @@ fn staticAssert(p: *Parser) Error!bool {...@@ -1287,6 +1314,7 @@ fn staticAssert(p: *Parser) Error!bool {
1287 .lhs = res.node,1314 .lhs = res.node,
1288 .rhs = str.node,1315 .rhs = str.node,
1289 } },1316 } },
1317 .loc = @enumFromInt(static_assert),
1290 });1318 });
1291 try p.decl_buf.append(node);1319 try p.decl_buf.append(node);
1292 return true;1320 return true;
...@@ -1407,6 +1435,8 @@ fn typeof(p: *Parser) Error!?Type {...@@ -1407,6 +1435,8 @@ fn typeof(p: *Parser) Error!?Type {
1407 const l_paren = try p.expectToken(.l_paren);1435 const l_paren = try p.expectToken(.l_paren);
1408 if (try p.typeName()) |ty| {1436 if (try p.typeName()) |ty| {
1409 try p.expectClosing(l_paren, .r_paren);1437 try p.expectClosing(l_paren, .r_paren);
1438 if (ty.is(.invalid)) return null;
1439
1410 const typeof_ty = try p.arena.create(Type);1440 const typeof_ty = try p.arena.create(Type);
1411 typeof_ty.* = .{1441 typeof_ty.* = .{
1412 .data = ty.data,1442 .data = ty.data,
...@@ -1428,6 +1458,8 @@ fn typeof(p: *Parser) Error!?Type {...@@ -1428,6 +1458,8 @@ fn typeof(p: *Parser) Error!?Type {
1428 .specifier = .nullptr_t,1458 .specifier = .nullptr_t,
1429 .qual = if (unqual) .{} else typeof_expr.ty.qual.inheritFromTypeof(),1459 .qual = if (unqual) .{} else typeof_expr.ty.qual.inheritFromTypeof(),
1430 };1460 };
1461 } else if (typeof_expr.ty.is(.invalid)) {
1462 return null;
1431 }1463 }
14321464
1433 const inner = try p.arena.create(Type.Expr);1465 const inner = try p.arena.create(Type.Expr);
...@@ -1774,6 +1806,8 @@ fn initDeclarator(p: *Parser, decl_spec: *DeclSpec, attr_buf_top: usize) Error!?...@@ -1774,6 +1806,8 @@ fn initDeclarator(p: *Parser, decl_spec: *DeclSpec, attr_buf_top: usize) Error!?
1774 } else {1806 } else {
1775 apply_var_attributes = true;1807 apply_var_attributes = true;
1776 }1808 }
1809 const c23_auto = init_d.d.ty.is(.c23_auto);
1810 const auto_type = init_d.d.ty.is(.auto_type);
17771811
1778 if (p.eatToken(.equal)) |eq| init: {1812 if (p.eatToken(.equal)) |eq| init: {
1779 if (decl_spec.storage_class == .typedef or1813 if (decl_spec.storage_class == .typedef or
...@@ -1801,19 +1835,21 @@ fn initDeclarator(p: *Parser, decl_spec: *DeclSpec, attr_buf_top: usize) Error!?...@@ -1801,19 +1835,21 @@ fn initDeclarator(p: *Parser, decl_spec: *DeclSpec, attr_buf_top: usize) Error!?
18011835
1802 const interned_name = try StrInt.intern(p.comp, p.tokSlice(init_d.d.name));1836 const interned_name = try StrInt.intern(p.comp, p.tokSlice(init_d.d.name));
1803 try p.syms.declareSymbol(p, interned_name, init_d.d.ty, init_d.d.name, .none);1837 try p.syms.declareSymbol(p, interned_name, init_d.d.ty, init_d.d.name, .none);
1838 if (c23_auto or auto_type) {
1839 p.auto_type_decl_name = interned_name;
1840 }
1841 defer p.auto_type_decl_name = .empty;
1842
1804 var init_list_expr = try p.initializer(init_d.d.ty);1843 var init_list_expr = try p.initializer(init_d.d.ty);
1805 init_d.initializer = init_list_expr;1844 init_d.initializer = init_list_expr;
1806 if (!init_list_expr.ty.isArray()) break :init;1845 if (!init_list_expr.ty.isArray()) break :init;
1807 if (init_d.d.ty.specifier == .incomplete_array) {1846 if (init_d.d.ty.is(.incomplete_array)) {
1808 // Modifying .data is exceptionally allowed for .incomplete_array.1847 init_d.d.ty.setIncompleteArrayLen(init_list_expr.ty.arrayLen() orelse break :init);
1809 init_d.d.ty.data.array.len = init_list_expr.ty.arrayLen() orelse break :init;
1810 init_d.d.ty.specifier = .array;
1811 }1848 }
1812 }1849 }
18131850
1814 const name = init_d.d.name;1851 const name = init_d.d.name;
1815 const c23_auto = init_d.d.ty.is(.c23_auto);1852 if (auto_type or c23_auto) {
1816 if (init_d.d.ty.is(.auto_type) or c23_auto) {
1817 if (init_d.initializer.node == .none) {1853 if (init_d.initializer.node == .none) {
1818 init_d.d.ty = Type.invalid;1854 init_d.d.ty = Type.invalid;
1819 if (c23_auto) {1855 if (c23_auto) {
...@@ -1872,6 +1908,8 @@ fn initDeclarator(p: *Parser, decl_spec: *DeclSpec, attr_buf_top: usize) Error!?...@@ -1872,6 +1908,8 @@ fn initDeclarator(p: *Parser, decl_spec: *DeclSpec, attr_buf_top: usize) Error!?
1872/// | keyword_float1908/// | keyword_float
1873/// | keyword_double1909/// | keyword_double
1874/// | keyword_signed1910/// | keyword_signed
1911/// | keyword_signed1
1912/// | keyword_signed2
1875/// | keyword_unsigned1913/// | keyword_unsigned
1876/// | keyword_bool1914/// | keyword_bool
1877/// | keyword_c23_bool1915/// | keyword_c23_bool
...@@ -1911,14 +1949,13 @@ fn typeSpec(p: *Parser, ty: *Type.Builder) Error!bool {...@@ -1911,14 +1949,13 @@ fn typeSpec(p: *Parser, ty: *Type.Builder) Error!bool {
1911 .keyword_long => try ty.combine(p, .long, p.tok_i),1949 .keyword_long => try ty.combine(p, .long, p.tok_i),
1912 .keyword_int64, .keyword_int64_2 => try ty.combine(p, .long_long, p.tok_i),1950 .keyword_int64, .keyword_int64_2 => try ty.combine(p, .long_long, p.tok_i),
1913 .keyword_int128 => try ty.combine(p, .int128, p.tok_i),1951 .keyword_int128 => try ty.combine(p, .int128, p.tok_i),
1914 .keyword_signed => try ty.combine(p, .signed, p.tok_i),1952 .keyword_signed, .keyword_signed1, .keyword_signed2 => try ty.combine(p, .signed, p.tok_i),
1915 .keyword_unsigned => try ty.combine(p, .unsigned, p.tok_i),1953 .keyword_unsigned => try ty.combine(p, .unsigned, p.tok_i),
1916 .keyword_fp16 => try ty.combine(p, .fp16, p.tok_i),1954 .keyword_fp16 => try ty.combine(p, .fp16, p.tok_i),
1917 .keyword_float16 => try ty.combine(p, .float16, p.tok_i),1955 .keyword_float16 => try ty.combine(p, .float16, p.tok_i),
1918 .keyword_float => try ty.combine(p, .float, p.tok_i),1956 .keyword_float => try ty.combine(p, .float, p.tok_i),
1919 .keyword_double => try ty.combine(p, .double, p.tok_i),1957 .keyword_double => try ty.combine(p, .double, p.tok_i),
1920 .keyword_complex => try ty.combine(p, .complex, p.tok_i),1958 .keyword_complex => try ty.combine(p, .complex, p.tok_i),
1921 .keyword_float80 => try ty.combine(p, .float80, p.tok_i),
1922 .keyword_float128_1, .keyword_float128_2 => {1959 .keyword_float128_1, .keyword_float128_2 => {
1923 if (!p.comp.hasFloat128()) {1960 if (!p.comp.hasFloat128()) {
1924 try p.errStr(.type_not_supported_on_target, p.tok_i, p.tok_ids[p.tok_i].lexeme().?);1961 try p.errStr(.type_not_supported_on_target, p.tok_i, p.tok_ids[p.tok_i].lexeme().?);
...@@ -2128,6 +2165,7 @@ fn recordSpec(p: *Parser) Error!Type {...@@ -2128,6 +2165,7 @@ fn recordSpec(p: *Parser) Error!Type {
2128 .tag = if (is_struct) .struct_forward_decl else .union_forward_decl,2165 .tag = if (is_struct) .struct_forward_decl else .union_forward_decl,
2129 .ty = ty,2166 .ty = ty,
2130 .data = .{ .decl_ref = ident },2167 .data = .{ .decl_ref = ident },
2168 .loc = @enumFromInt(ident),
2131 }));2169 }));
2132 return ty;2170 return ty;
2133 }2171 }
...@@ -2248,19 +2286,22 @@ fn recordSpec(p: *Parser) Error!Type {...@@ -2248,19 +2286,22 @@ fn recordSpec(p: *Parser) Error!Type {
2248 // TODO: msvc considers `#pragma pack` on a per-field basis2286 // TODO: msvc considers `#pragma pack` on a per-field basis
2249 .msvc => p.pragma_pack,2287 .msvc => p.pragma_pack,
2250 };2288 };
2251 record_layout.compute(record_ty, ty, p.comp, pragma_pack_value);2289 record_layout.compute(record_ty, ty, p.comp, pragma_pack_value) catch |er| switch (er) {
2290 error.Overflow => try p.errStr(.record_too_large, maybe_ident orelse kind_tok, try p.typeStr(ty)),
2291 };
2252 }2292 }
22532293
2254 // finish by creating a node2294 // finish by creating a node
2255 var node: Tree.Node = .{2295 var node: Tree.Node = .{
2256 .tag = if (is_struct) .struct_decl_two else .union_decl_two,2296 .tag = if (is_struct) .struct_decl_two else .union_decl_two,
2257 .ty = ty,2297 .ty = ty,
2258 .data = .{ .bin = .{ .lhs = .none, .rhs = .none } },2298 .data = .{ .two = .{ .none, .none } },
2299 .loc = @enumFromInt(maybe_ident orelse kind_tok),
2259 };2300 };
2260 switch (record_decls.len) {2301 switch (record_decls.len) {
2261 0 => {},2302 0 => {},
2262 1 => node.data = .{ .bin = .{ .lhs = record_decls[0], .rhs = .none } },2303 1 => node.data = .{ .two = .{ record_decls[0], .none } },
2263 2 => node.data = .{ .bin = .{ .lhs = record_decls[0], .rhs = record_decls[1] } },2304 2 => node.data = .{ .two = .{ record_decls[0], record_decls[1] } },
2264 else => {2305 else => {
2265 node.tag = if (is_struct) .struct_decl else .union_decl;2306 node.tag = if (is_struct) .struct_decl else .union_decl;
2266 node.data = .{ .range = try p.addList(record_decls) };2307 node.data = .{ .range = try p.addList(record_decls) };
...@@ -2383,6 +2424,7 @@ fn recordDeclarator(p: *Parser) Error!bool {...@@ -2383,6 +2424,7 @@ fn recordDeclarator(p: *Parser) Error!bool {
2383 .tag = .indirect_record_field_decl,2424 .tag = .indirect_record_field_decl,
2384 .ty = ty,2425 .ty = ty,
2385 .data = undefined,2426 .data = undefined,
2427 .loc = @enumFromInt(first_tok),
2386 });2428 });
2387 try p.decl_buf.append(node);2429 try p.decl_buf.append(node);
2388 try p.record.addFieldsFromAnonymous(p, ty);2430 try p.record.addFieldsFromAnonymous(p, ty);
...@@ -2402,6 +2444,7 @@ fn recordDeclarator(p: *Parser) Error!bool {...@@ -2402,6 +2444,7 @@ fn recordDeclarator(p: *Parser) Error!bool {
2402 .tag = .record_field_decl,2444 .tag = .record_field_decl,
2403 .ty = ty,2445 .ty = ty,
2404 .data = .{ .decl = .{ .name = name_tok, .node = bits_node } },2446 .data = .{ .decl = .{ .name = name_tok, .node = bits_node } },
2447 .loc = @enumFromInt(if (name_tok != 0) name_tok else first_tok),
2405 });2448 });
2406 try p.decl_buf.append(node);2449 try p.decl_buf.append(node);
2407 }2450 }
...@@ -2461,7 +2504,8 @@ fn enumSpec(p: *Parser) Error!Type {...@@ -2461,7 +2504,8 @@ fn enumSpec(p: *Parser) Error!Type {
24612504
2462 const maybe_ident = try p.eatIdentifier();2505 const maybe_ident = try p.eatIdentifier();
2463 const fixed_ty = if (p.eatToken(.colon)) |colon| fixed: {2506 const fixed_ty = if (p.eatToken(.colon)) |colon| fixed: {
2464 const fixed = (try p.typeName()) orelse {2507 const ty_start = p.tok_i;
2508 const fixed = (try p.specQual()) orelse {
2465 if (p.record.kind != .invalid) {2509 if (p.record.kind != .invalid) {
2466 // This is a bit field.2510 // This is a bit field.
2467 p.tok_i -= 1;2511 p.tok_i -= 1;
...@@ -2471,6 +2515,12 @@ fn enumSpec(p: *Parser) Error!Type {...@@ -2471,6 +2515,12 @@ fn enumSpec(p: *Parser) Error!Type {
2471 try p.errTok(.enum_fixed, colon);2515 try p.errTok(.enum_fixed, colon);
2472 break :fixed null;2516 break :fixed null;
2473 };2517 };
2518
2519 if (!fixed.isInt() or fixed.is(.@"enum")) {
2520 try p.errStr(.invalid_type_underlying_enum, ty_start, try p.typeStr(fixed));
2521 break :fixed Type.int;
2522 }
2523
2474 try p.errTok(.enum_fixed, colon);2524 try p.errTok(.enum_fixed, colon);
2475 break :fixed fixed;2525 break :fixed fixed;
2476 } else null;2526 } else null;
...@@ -2505,6 +2555,7 @@ fn enumSpec(p: *Parser) Error!Type {...@@ -2505,6 +2555,7 @@ fn enumSpec(p: *Parser) Error!Type {
2505 .tag = .enum_forward_decl,2555 .tag = .enum_forward_decl,
2506 .ty = ty,2556 .ty = ty,
2507 .data = .{ .decl_ref = ident },2557 .data = .{ .decl_ref = ident },
2558 .loc = @enumFromInt(ident),
2508 }));2559 }));
2509 return ty;2560 return ty;
2510 }2561 }
...@@ -2587,7 +2638,7 @@ fn enumSpec(p: *Parser) Error!Type {...@@ -2587,7 +2638,7 @@ fn enumSpec(p: *Parser) Error!Type {
2587 continue;2638 continue;
25882639
2589 const symbol = p.syms.getPtr(field.name, .vars);2640 const symbol = p.syms.getPtr(field.name, .vars);
2590 try symbol.val.intCast(dest_ty, p.comp);2641 _ = try symbol.val.intCast(dest_ty, p.comp);
2591 symbol.ty = dest_ty;2642 symbol.ty = dest_ty;
2592 p.nodes.items(.ty)[@intFromEnum(field_nodes[i])] = dest_ty;2643 p.nodes.items(.ty)[@intFromEnum(field_nodes[i])] = dest_ty;
2593 field.ty = dest_ty;2644 field.ty = dest_ty;
...@@ -2615,13 +2666,18 @@ fn enumSpec(p: *Parser) Error!Type {...@@ -2615,13 +2666,18 @@ fn enumSpec(p: *Parser) Error!Type {
2615 }2666 }
26162667
2617 // finish by creating a node2668 // finish by creating a node
2618 var node: Tree.Node = .{ .tag = .enum_decl_two, .ty = ty, .data = .{2669 var node: Tree.Node = .{
2619 .bin = .{ .lhs = .none, .rhs = .none },2670 .tag = .enum_decl_two,
2620 } };2671 .ty = ty,
2672 .data = .{
2673 .two = .{ .none, .none },
2674 },
2675 .loc = @enumFromInt(maybe_ident orelse enum_tok),
2676 };
2621 switch (field_nodes.len) {2677 switch (field_nodes.len) {
2622 0 => {},2678 0 => {},
2623 1 => node.data = .{ .bin = .{ .lhs = field_nodes[0], .rhs = .none } },2679 1 => node.data = .{ .two = .{ field_nodes[0], .none } },
2624 2 => node.data = .{ .bin = .{ .lhs = field_nodes[0], .rhs = field_nodes[1] } },2680 2 => node.data = .{ .two = .{ field_nodes[0], field_nodes[1] } },
2625 else => {2681 else => {
2626 node.tag = .enum_decl;2682 node.tag = .enum_decl;
2627 node.data = .{ .range = try p.addList(field_nodes) };2683 node.data = .{ .range = try p.addList(field_nodes) };
...@@ -2679,8 +2735,6 @@ const Enumerator = struct {...@@ -2679,8 +2735,6 @@ const Enumerator = struct {
2679 return;2735 return;
2680 }2736 }
2681 if (try e.res.val.add(e.res.val, Value.one, e.res.ty, p.comp)) {2737 if (try e.res.val.add(e.res.val, Value.one, e.res.ty, p.comp)) {
2682 const byte_size = e.res.ty.sizeof(p.comp).?;
2683 const bit_size: u8 = @intCast(if (e.res.ty.isUnsignedInt(p.comp)) byte_size * 8 else byte_size * 8 - 1);
2684 if (e.fixed) {2738 if (e.fixed) {
2685 try p.errStr(.enum_not_representable_fixed, tok, try p.typeStr(e.res.ty));2739 try p.errStr(.enum_not_representable_fixed, tok, try p.typeStr(e.res.ty));
2686 return;2740 return;
...@@ -2689,6 +2743,8 @@ const Enumerator = struct {...@@ -2689,6 +2743,8 @@ const Enumerator = struct {
2689 try p.errTok(.enumerator_overflow, tok);2743 try p.errTok(.enumerator_overflow, tok);
2690 break :blk larger;2744 break :blk larger;
2691 } else blk: {2745 } else blk: {
2746 const signed = !e.res.ty.isUnsignedInt(p.comp);
2747 const bit_size: u8 = @intCast(e.res.ty.bitSizeof(p.comp).? - @intFromBool(signed));
2692 try p.errExtra(.enum_not_representable, tok, .{ .pow_2_as_string = bit_size });2748 try p.errExtra(.enum_not_representable, tok, .{ .pow_2_as_string = bit_size });
2693 break :blk Type{ .specifier = .ulong_long };2749 break :blk Type{ .specifier = .ulong_long };
2694 };2750 };
...@@ -2792,14 +2848,12 @@ fn enumerator(p: *Parser, e: *Enumerator) Error!?EnumFieldAndNode {...@@ -2792,14 +2848,12 @@ fn enumerator(p: *Parser, e: *Enumerator) Error!?EnumFieldAndNode {
2792 if (err_start == p.comp.diagnostics.list.items.len) {2848 if (err_start == p.comp.diagnostics.list.items.len) {
2793 // only do these warnings if we didn't already warn about overflow or non-representable values2849 // only do these warnings if we didn't already warn about overflow or non-representable values
2794 if (e.res.val.compare(.lt, Value.zero, p.comp)) {2850 if (e.res.val.compare(.lt, Value.zero, p.comp)) {
2795 const min_int = (Type{ .specifier = .int }).minInt(p.comp);2851 const min_val = try Value.minInt(Type.int, p.comp);
2796 const min_val = try Value.int(min_int, p.comp);
2797 if (e.res.val.compare(.lt, min_val, p.comp)) {2852 if (e.res.val.compare(.lt, min_val, p.comp)) {
2798 try p.errStr(.enumerator_too_small, name_tok, try e.res.str(p));2853 try p.errStr(.enumerator_too_small, name_tok, try e.res.str(p));
2799 }2854 }
2800 } else {2855 } else {
2801 const max_int = (Type{ .specifier = .int }).maxInt(p.comp);2856 const max_val = try Value.maxInt(Type.int, p.comp);
2802 const max_val = try Value.int(max_int, p.comp);
2803 if (e.res.val.compare(.gt, max_val, p.comp)) {2857 if (e.res.val.compare(.gt, max_val, p.comp)) {
2804 try p.errStr(.enumerator_too_large, name_tok, try e.res.str(p));2858 try p.errStr(.enumerator_too_large, name_tok, try e.res.str(p));
2805 }2859 }
...@@ -2815,6 +2869,7 @@ fn enumerator(p: *Parser, e: *Enumerator) Error!?EnumFieldAndNode {...@@ -2815,6 +2869,7 @@ fn enumerator(p: *Parser, e: *Enumerator) Error!?EnumFieldAndNode {
2815 .name = name_tok,2869 .name = name_tok,
2816 .node = res.node,2870 .node = res.node,
2817 } },2871 } },
2872 .loc = @enumFromInt(name_tok),
2818 });2873 });
2819 try p.value_map.put(node, e.res.val);2874 try p.value_map.put(node, e.res.val);
2820 return EnumFieldAndNode{ .field = .{2875 return EnumFieldAndNode{ .field = .{
...@@ -2991,15 +3046,12 @@ fn directDeclarator(p: *Parser, base_type: Type, d: *Declarator, kind: Declarato...@@ -2991,15 +3046,12 @@ fn directDeclarator(p: *Parser, base_type: Type, d: *Declarator, kind: Declarato
2991 }3046 }
29923047
2993 const outer = try p.directDeclarator(base_type, d, kind);3048 const outer = try p.directDeclarator(base_type, d, kind);
2994 var max_bits = p.comp.target.ptrBitWidth();
2995 if (max_bits > 61) max_bits = 61;
2996 const max_bytes = (@as(u64, 1) << @truncate(max_bits)) - 1;
29973049
2998 if (!size.ty.isInt()) {3050 if (!size.ty.isInt()) {
2999 try p.errStr(.array_size_non_int, size_tok, try p.typeStr(size.ty));3051 try p.errStr(.array_size_non_int, size_tok, try p.typeStr(size.ty));
3000 return error.ParsingFailed;3052 return error.ParsingFailed;
3001 }3053 }
3002 if (base_type.is(.c23_auto)) {3054 if (base_type.is(.c23_auto) or outer.is(.invalid)) {
3003 // issue error later3055 // issue error later
3004 return Type.invalid;3056 return Type.invalid;
3005 } else if (size.val.opt_ref == .none) {3057 } else if (size.val.opt_ref == .none) {
...@@ -3030,7 +3082,7 @@ fn directDeclarator(p: *Parser, base_type: Type, d: *Declarator, kind: Declarato...@@ -3030,7 +3082,7 @@ fn directDeclarator(p: *Parser, base_type: Type, d: *Declarator, kind: Declarato
3030 } else {3082 } else {
3031 // `outer` is validated later so it may be invalid here3083 // `outer` is validated later so it may be invalid here
3032 const outer_size = outer.sizeof(p.comp);3084 const outer_size = outer.sizeof(p.comp);
3033 const max_elems = max_bytes / @max(1, outer_size orelse 1);3085 const max_elems = p.comp.maxArrayBytes() / @max(1, outer_size orelse 1);
30343086
3035 var size_val = size.val;3087 var size_val = size.val;
3036 if (size_val.isZero(p.comp)) {3088 if (size_val.isZero(p.comp)) {
...@@ -3047,7 +3099,7 @@ fn directDeclarator(p: *Parser, base_type: Type, d: *Declarator, kind: Declarato...@@ -3047,7 +3099,7 @@ fn directDeclarator(p: *Parser, base_type: Type, d: *Declarator, kind: Declarato
3047 arr_ty.len = max_elems;3099 arr_ty.len = max_elems;
3048 }3100 }
3049 res_ty.data = .{ .array = arr_ty };3101 res_ty.data = .{ .array = arr_ty };
3050 res_ty.specifier = .array;3102 res_ty.specifier = if (static != null) .static_array else .array;
3051 }3103 }
30523104
3053 try res_ty.combine(outer);3105 try res_ty.combine(outer);
...@@ -3120,12 +3172,14 @@ fn directDeclarator(p: *Parser, base_type: Type, d: *Declarator, kind: Declarato...@@ -3120,12 +3172,14 @@ fn directDeclarator(p: *Parser, base_type: Type, d: *Declarator, kind: Declarato
3120fn pointer(p: *Parser, base_ty: Type) Error!Type {3172fn pointer(p: *Parser, base_ty: Type) Error!Type {
3121 var ty = base_ty;3173 var ty = base_ty;
3122 while (p.eatToken(.asterisk)) |_| {3174 while (p.eatToken(.asterisk)) |_| {
3123 const elem_ty = try p.arena.create(Type);3175 if (!ty.is(.invalid)) {
3124 elem_ty.* = ty;3176 const elem_ty = try p.arena.create(Type);
3125 ty = Type{3177 elem_ty.* = ty;
3126 .specifier = .pointer,3178 ty = Type{
3127 .data = .{ .sub_type = elem_ty },3179 .specifier = .pointer,
3128 };3180 .data = .{ .sub_type = elem_ty },
3181 };
3182 }
3129 var quals = Type.Qualifiers.Builder{};3183 var quals = Type.Qualifiers.Builder{};
3130 _ = try p.typeQual(&quals);3184 _ = try p.typeQual(&quals);
3131 try quals.finish(p, &ty);3185 try quals.finish(p, &ty);
...@@ -3237,6 +3291,75 @@ fn typeName(p: *Parser) Error!?Type {...@@ -3237,6 +3291,75 @@ fn typeName(p: *Parser) Error!?Type {
3237 return try Attribute.applyTypeAttributes(p, ty, attr_buf_top, .align_ignored);3291 return try Attribute.applyTypeAttributes(p, ty, attr_buf_top, .align_ignored);
3238}3292}
32393293
3294fn complexInitializer(p: *Parser, init_ty: Type) Error!Result {
3295 assert(p.tok_ids[p.tok_i] == .l_brace);
3296 assert(init_ty.isComplex());
3297
3298 const real_ty = init_ty.makeReal();
3299 if (real_ty.isInt()) {
3300 return p.todo("Complex integer initializers");
3301 }
3302 const l_brace = p.tok_i;
3303 p.tok_i += 1;
3304 try p.errTok(.complex_component_init, l_brace);
3305
3306 const first_tok = p.tok_i;
3307 var first = try p.assignExpr();
3308 try first.expect(p);
3309 try p.coerceInit(&first, first_tok, real_ty);
3310
3311 var second: Result = .{
3312 .ty = real_ty,
3313 .val = Value.zero,
3314 };
3315 if (p.eatToken(.comma)) |_| {
3316 const second_tok = p.tok_i;
3317 const maybe_second = try p.assignExpr();
3318 if (!maybe_second.empty(p)) {
3319 second = maybe_second;
3320 try p.coerceInit(&second, second_tok, real_ty);
3321 }
3322 }
3323
3324 // Eat excess initializers
3325 var extra_tok: ?TokenIndex = null;
3326 while (p.eatToken(.comma)) |_| {
3327 if (p.tok_ids[p.tok_i] == .r_brace) break;
3328 extra_tok = p.tok_i;
3329 const extra = try p.assignExpr();
3330 if (extra.empty(p)) {
3331 try p.errTok(.expected_expr, p.tok_i);
3332 p.skipTo(.r_brace);
3333 return error.ParsingFailed;
3334 }
3335 }
3336 try p.expectClosing(l_brace, .r_brace);
3337 if (extra_tok) |tok| {
3338 try p.errTok(.excess_scalar_init, tok);
3339 }
3340
3341 const arr_init_node: Tree.Node = .{
3342 .tag = .array_init_expr_two,
3343 .ty = init_ty,
3344 .data = .{ .two = .{ first.node, second.node } },
3345 .loc = @enumFromInt(l_brace),
3346 };
3347 var res: Result = .{
3348 .node = try p.addNode(arr_init_node),
3349 .ty = init_ty,
3350 };
3351 if (first.val.opt_ref != .none and second.val.opt_ref != .none) {
3352 res.val = try Value.intern(p.comp, switch (real_ty.bitSizeof(p.comp).?) {
3353 32 => .{ .complex = .{ .cf32 = .{ first.val.toFloat(f32, p.comp), second.val.toFloat(f32, p.comp) } } },
3354 64 => .{ .complex = .{ .cf64 = .{ first.val.toFloat(f64, p.comp), second.val.toFloat(f64, p.comp) } } },
3355 80 => .{ .complex = .{ .cf80 = .{ first.val.toFloat(f80, p.comp), second.val.toFloat(f80, p.comp) } } },
3356 128 => .{ .complex = .{ .cf128 = .{ first.val.toFloat(f128, p.comp), second.val.toFloat(f128, p.comp) } } },
3357 else => unreachable,
3358 });
3359 }
3360 return res;
3361}
3362
3240/// initializer3363/// initializer
3241/// : assignExpr3364/// : assignExpr
3242/// | '{' initializerItems '}'3365/// | '{' initializerItems '}'
...@@ -3255,6 +3378,9 @@ fn initializer(p: *Parser, init_ty: Type) Error!Result {...@@ -3255,6 +3378,9 @@ fn initializer(p: *Parser, init_ty: Type) Error!Result {
3255 return error.ParsingFailed;3378 return error.ParsingFailed;
3256 }3379 }
32573380
3381 if (init_ty.isComplex()) {
3382 return p.complexInitializer(init_ty);
3383 }
3258 var il: InitList = .{};3384 var il: InitList = .{};
3259 defer il.deinit(p.gpa);3385 defer il.deinit(p.gpa);
32603386
...@@ -3754,9 +3880,15 @@ fn convertInitList(p: *Parser, il: InitList, init_ty: Type) Error!NodeIndex {...@@ -3754,9 +3880,15 @@ fn convertInitList(p: *Parser, il: InitList, init_ty: Type) Error!NodeIndex {
3754 var arr_init_node: Tree.Node = .{3880 var arr_init_node: Tree.Node = .{
3755 .tag = .array_init_expr_two,3881 .tag = .array_init_expr_two,
3756 .ty = init_ty,3882 .ty = init_ty,
3757 .data = .{ .bin = .{ .lhs = .none, .rhs = .none } },3883 .data = .{ .two = .{ .none, .none } },
3758 };3884 };
37593885
3886 const max_elems = p.comp.maxArrayBytes() / (@max(1, elem_ty.sizeof(p.comp) orelse 1));
3887 if (start > max_elems) {
3888 try p.errTok(.array_too_large, il.tok);
3889 start = max_elems;
3890 }
3891
3760 if (init_ty.specifier == .incomplete_array) {3892 if (init_ty.specifier == .incomplete_array) {
3761 arr_init_node.ty.specifier = .array;3893 arr_init_node.ty.specifier = .array;
3762 arr_init_node.ty.data.array.len = start;3894 arr_init_node.ty.data.array.len = start;
...@@ -3767,8 +3899,6 @@ fn convertInitList(p: *Parser, il: InitList, init_ty: Type) Error!NodeIndex {...@@ -3767,8 +3899,6 @@ fn convertInitList(p: *Parser, il: InitList, init_ty: Type) Error!NodeIndex {
3767 .specifier = .array,3899 .specifier = .array,
3768 .data = .{ .array = arr_ty },3900 .data = .{ .array = arr_ty },
3769 };3901 };
3770 const attrs = init_ty.getAttributes();
3771 arr_init_node.ty = try arr_init_node.ty.withAttributes(p.arena, attrs);
3772 } else if (start < max_items) {3902 } else if (start < max_items) {
3773 const elem = try p.addNode(.{3903 const elem = try p.addNode(.{
3774 .tag = .array_filler_expr,3904 .tag = .array_filler_expr,
...@@ -3781,8 +3911,8 @@ fn convertInitList(p: *Parser, il: InitList, init_ty: Type) Error!NodeIndex {...@@ -3781,8 +3911,8 @@ fn convertInitList(p: *Parser, il: InitList, init_ty: Type) Error!NodeIndex {
3781 const items = p.list_buf.items[list_buf_top..];3911 const items = p.list_buf.items[list_buf_top..];
3782 switch (items.len) {3912 switch (items.len) {
3783 0 => {},3913 0 => {},
3784 1 => arr_init_node.data.bin.lhs = items[0],3914 1 => arr_init_node.data.two[0] = items[0],
3785 2 => arr_init_node.data.bin = .{ .lhs = items[0], .rhs = items[1] },3915 2 => arr_init_node.data.two = .{ items[0], items[1] },
3786 else => {3916 else => {
3787 arr_init_node.tag = .array_init_expr;3917 arr_init_node.tag = .array_init_expr;
3788 arr_init_node.data = .{ .range = try p.addList(items) };3918 arr_init_node.data = .{ .range = try p.addList(items) };
...@@ -3813,13 +3943,13 @@ fn convertInitList(p: *Parser, il: InitList, init_ty: Type) Error!NodeIndex {...@@ -3813,13 +3943,13 @@ fn convertInitList(p: *Parser, il: InitList, init_ty: Type) Error!NodeIndex {
3813 var struct_init_node: Tree.Node = .{3943 var struct_init_node: Tree.Node = .{
3814 .tag = .struct_init_expr_two,3944 .tag = .struct_init_expr_two,
3815 .ty = init_ty,3945 .ty = init_ty,
3816 .data = .{ .bin = .{ .lhs = .none, .rhs = .none } },3946 .data = .{ .two = .{ .none, .none } },
3817 };3947 };
3818 const items = p.list_buf.items[list_buf_top..];3948 const items = p.list_buf.items[list_buf_top..];
3819 switch (items.len) {3949 switch (items.len) {
3820 0 => {},3950 0 => {},
3821 1 => struct_init_node.data.bin.lhs = items[0],3951 1 => struct_init_node.data.two[0] = items[0],
3822 2 => struct_init_node.data.bin = .{ .lhs = items[0], .rhs = items[1] },3952 2 => struct_init_node.data.two = .{ items[0], items[1] },
3823 else => {3953 else => {
3824 struct_init_node.tag = .struct_init_expr;3954 struct_init_node.tag = .struct_init_expr;
3825 struct_init_node.data = .{ .range = try p.addList(items) };3955 struct_init_node.data = .{ .range = try p.addList(items) };
...@@ -3894,7 +4024,7 @@ fn asmOperand(p: *Parser, names: *std.ArrayList(?TokenIndex), constraints: *Node...@@ -3894,7 +4024,7 @@ fn asmOperand(p: *Parser, names: *std.ArrayList(?TokenIndex), constraints: *Node
3894/// | asmStr ':' asmOperand* ':' asmOperand*4024/// | asmStr ':' asmOperand* ':' asmOperand*
3895/// | asmStr ':' asmOperand* ':' asmOperand* : asmStr? (',' asmStr)*4025/// | asmStr ':' asmOperand* ':' asmOperand* : asmStr? (',' asmStr)*
3896/// | asmStr ':' asmOperand* ':' asmOperand* : asmStr? (',' asmStr)* : IDENTIFIER (',' IDENTIFIER)*4026/// | asmStr ':' asmOperand* ':' asmOperand* : asmStr? (',' asmStr)* : IDENTIFIER (',' IDENTIFIER)*
3897fn gnuAsmStmt(p: *Parser, quals: Tree.GNUAssemblyQualifiers, l_paren: TokenIndex) Error!NodeIndex {4027fn gnuAsmStmt(p: *Parser, quals: Tree.GNUAssemblyQualifiers, asm_tok: TokenIndex, l_paren: TokenIndex) Error!NodeIndex {
3898 const asm_str = try p.asmStr();4028 const asm_str = try p.asmStr();
3899 try p.checkAsmStr(asm_str.val, l_paren);4029 try p.checkAsmStr(asm_str.val, l_paren);
39004030
...@@ -3903,6 +4033,7 @@ fn gnuAsmStmt(p: *Parser, quals: Tree.GNUAssemblyQualifiers, l_paren: TokenIndex...@@ -3903,6 +4033,7 @@ fn gnuAsmStmt(p: *Parser, quals: Tree.GNUAssemblyQualifiers, l_paren: TokenIndex
3903 .tag = .gnu_asm_simple,4033 .tag = .gnu_asm_simple,
3904 .ty = .{ .specifier = .void },4034 .ty = .{ .specifier = .void },
3905 .data = .{ .un = asm_str.node },4035 .data = .{ .un = asm_str.node },
4036 .loc = @enumFromInt(asm_tok),
3906 });4037 });
3907 }4038 }
39084039
...@@ -4007,6 +4138,7 @@ fn gnuAsmStmt(p: *Parser, quals: Tree.GNUAssemblyQualifiers, l_paren: TokenIndex...@@ -4007,6 +4138,7 @@ fn gnuAsmStmt(p: *Parser, quals: Tree.GNUAssemblyQualifiers, l_paren: TokenIndex
4007 .tag = .addr_of_label,4138 .tag = .addr_of_label,
4008 .data = .{ .decl_ref = label },4139 .data = .{ .decl_ref = label },
4009 .ty = result_ty,4140 .ty = result_ty,
4141 .loc = @enumFromInt(ident),
4010 });4142 });
4011 try exprs.append(label_addr_node);4143 try exprs.append(label_addr_node);
40124144
...@@ -4088,9 +4220,10 @@ fn assembly(p: *Parser, kind: enum { global, decl_label, stmt }) Error!?NodeInde...@@ -4088,9 +4220,10 @@ fn assembly(p: *Parser, kind: enum { global, decl_label, stmt }) Error!?NodeInde
4088 .tag = .file_scope_asm,4220 .tag = .file_scope_asm,
4089 .ty = .{ .specifier = .void },4221 .ty = .{ .specifier = .void },
4090 .data = .{ .decl = .{ .name = asm_tok, .node = asm_str.node } },4222 .data = .{ .decl = .{ .name = asm_tok, .node = asm_str.node } },
4223 .loc = @enumFromInt(asm_tok),
4091 });4224 });
4092 },4225 },
4093 .stmt => result_node = try p.gnuAsmStmt(quals, l_paren),4226 .stmt => result_node = try p.gnuAsmStmt(quals, asm_tok, l_paren),
4094 }4227 }
4095 try p.expectClosing(l_paren, .r_paren);4228 try p.expectClosing(l_paren, .r_paren);
40964229
...@@ -4141,7 +4274,7 @@ fn asmStr(p: *Parser) Error!Result {...@@ -4141,7 +4274,7 @@ fn asmStr(p: *Parser) Error!Result {
4141fn stmt(p: *Parser) Error!NodeIndex {4274fn stmt(p: *Parser) Error!NodeIndex {
4142 if (try p.labeledStmt()) |some| return some;4275 if (try p.labeledStmt()) |some| return some;
4143 if (try p.compoundStmt(false, null)) |some| return some;4276 if (try p.compoundStmt(false, null)) |some| return some;
4144 if (p.eatToken(.keyword_if)) |_| {4277 if (p.eatToken(.keyword_if)) |kw_if| {
4145 const l_paren = try p.expectToken(.l_paren);4278 const l_paren = try p.expectToken(.l_paren);
4146 const cond_tok = p.tok_i;4279 const cond_tok = p.tok_i;
4147 var cond = try p.expr();4280 var cond = try p.expr();
...@@ -4160,14 +4293,16 @@ fn stmt(p: *Parser) Error!NodeIndex {...@@ -4160,14 +4293,16 @@ fn stmt(p: *Parser) Error!NodeIndex {
4160 return try p.addNode(.{4293 return try p.addNode(.{
4161 .tag = .if_then_else_stmt,4294 .tag = .if_then_else_stmt,
4162 .data = .{ .if3 = .{ .cond = cond.node, .body = (try p.addList(&.{ then, @"else" })).start } },4295 .data = .{ .if3 = .{ .cond = cond.node, .body = (try p.addList(&.{ then, @"else" })).start } },
4296 .loc = @enumFromInt(kw_if),
4163 })4297 })
4164 else4298 else
4165 return try p.addNode(.{4299 return try p.addNode(.{
4166 .tag = .if_then_stmt,4300 .tag = .if_then_stmt,
4167 .data = .{ .bin = .{ .lhs = cond.node, .rhs = then } },4301 .data = .{ .bin = .{ .lhs = cond.node, .rhs = then } },
4302 .loc = @enumFromInt(kw_if),
4168 });4303 });
4169 }4304 }
4170 if (p.eatToken(.keyword_switch)) |_| {4305 if (p.eatToken(.keyword_switch)) |kw_switch| {
4171 const l_paren = try p.expectToken(.l_paren);4306 const l_paren = try p.expectToken(.l_paren);
4172 const cond_tok = p.tok_i;4307 const cond_tok = p.tok_i;
4173 var cond = try p.expr();4308 var cond = try p.expr();
...@@ -4197,9 +4332,10 @@ fn stmt(p: *Parser) Error!NodeIndex {...@@ -4197,9 +4332,10 @@ fn stmt(p: *Parser) Error!NodeIndex {
4197 return try p.addNode(.{4332 return try p.addNode(.{
4198 .tag = .switch_stmt,4333 .tag = .switch_stmt,
4199 .data = .{ .bin = .{ .lhs = cond.node, .rhs = body } },4334 .data = .{ .bin = .{ .lhs = cond.node, .rhs = body } },
4335 .loc = @enumFromInt(kw_switch),
4200 });4336 });
4201 }4337 }
4202 if (p.eatToken(.keyword_while)) |_| {4338 if (p.eatToken(.keyword_while)) |kw_while| {
4203 const l_paren = try p.expectToken(.l_paren);4339 const l_paren = try p.expectToken(.l_paren);
4204 const cond_tok = p.tok_i;4340 const cond_tok = p.tok_i;
4205 var cond = try p.expr();4341 var cond = try p.expr();
...@@ -4221,9 +4357,10 @@ fn stmt(p: *Parser) Error!NodeIndex {...@@ -4221,9 +4357,10 @@ fn stmt(p: *Parser) Error!NodeIndex {
4221 return try p.addNode(.{4357 return try p.addNode(.{
4222 .tag = .while_stmt,4358 .tag = .while_stmt,
4223 .data = .{ .bin = .{ .lhs = cond.node, .rhs = body } },4359 .data = .{ .bin = .{ .lhs = cond.node, .rhs = body } },
4360 .loc = @enumFromInt(kw_while),
4224 });4361 });
4225 }4362 }
4226 if (p.eatToken(.keyword_do)) |_| {4363 if (p.eatToken(.keyword_do)) |kw_do| {
4227 const body = body: {4364 const body = body: {
4228 const old_loop = p.in_loop;4365 const old_loop = p.in_loop;
4229 p.in_loop = true;4366 p.in_loop = true;
...@@ -4248,9 +4385,10 @@ fn stmt(p: *Parser) Error!NodeIndex {...@@ -4248,9 +4385,10 @@ fn stmt(p: *Parser) Error!NodeIndex {
4248 return try p.addNode(.{4385 return try p.addNode(.{
4249 .tag = .do_while_stmt,4386 .tag = .do_while_stmt,
4250 .data = .{ .bin = .{ .lhs = cond.node, .rhs = body } },4387 .data = .{ .bin = .{ .lhs = cond.node, .rhs = body } },
4388 .loc = @enumFromInt(kw_do),
4251 });4389 });
4252 }4390 }
4253 if (p.eatToken(.keyword_for)) |_| {4391 if (p.eatToken(.keyword_for)) |kw_for| {
4254 try p.syms.pushScope(p);4392 try p.syms.pushScope(p);
4255 defer p.syms.popScope();4393 defer p.syms.popScope();
4256 const decl_buf_top = p.decl_buf.items.len;4394 const decl_buf_top = p.decl_buf.items.len;
...@@ -4301,16 +4439,22 @@ fn stmt(p: *Parser) Error!NodeIndex {...@@ -4301,16 +4439,22 @@ fn stmt(p: *Parser) Error!NodeIndex {
4301 return try p.addNode(.{4439 return try p.addNode(.{
4302 .tag = .for_decl_stmt,4440 .tag = .for_decl_stmt,
4303 .data = .{ .range = .{ .start = start, .end = end } },4441 .data = .{ .range = .{ .start = start, .end = end } },
4442 .loc = @enumFromInt(kw_for),
4304 });4443 });
4305 } else if (init.node == .none and cond.node == .none and incr.node == .none) {4444 } else if (init.node == .none and cond.node == .none and incr.node == .none) {
4306 return try p.addNode(.{4445 return try p.addNode(.{
4307 .tag = .forever_stmt,4446 .tag = .forever_stmt,
4308 .data = .{ .un = body },4447 .data = .{ .un = body },
4448 .loc = @enumFromInt(kw_for),
4309 });4449 });
4310 } else return try p.addNode(.{ .tag = .for_stmt, .data = .{ .if3 = .{4450 } else return try p.addNode(.{
4311 .cond = body,4451 .tag = .for_stmt,
4312 .body = (try p.addList(&.{ init.node, cond.node, incr.node })).start,4452 .data = .{ .if3 = .{
4313 } } });4453 .cond = body,
4454 .body = (try p.addList(&.{ init.node, cond.node, incr.node })).start,
4455 } },
4456 .loc = @enumFromInt(kw_for),
4457 });
4314 }4458 }
4315 if (p.eatToken(.keyword_goto)) |goto_tok| {4459 if (p.eatToken(.keyword_goto)) |goto_tok| {
4316 if (p.eatToken(.asterisk)) |_| {4460 if (p.eatToken(.asterisk)) |_| {
...@@ -4338,7 +4482,7 @@ fn stmt(p: *Parser) Error!NodeIndex {...@@ -4338,7 +4482,7 @@ fn stmt(p: *Parser) Error!NodeIndex {
4338 }4482 }
4339 }4483 }
43404484
4341 try e.un(p, .computed_goto_stmt);4485 try e.un(p, .computed_goto_stmt, goto_tok);
4342 _ = try p.expectToken(.semicolon);4486 _ = try p.expectToken(.semicolon);
4343 return e.node;4487 return e.node;
4344 }4488 }
...@@ -4351,17 +4495,18 @@ fn stmt(p: *Parser) Error!NodeIndex {...@@ -4351,17 +4495,18 @@ fn stmt(p: *Parser) Error!NodeIndex {
4351 return try p.addNode(.{4495 return try p.addNode(.{
4352 .tag = .goto_stmt,4496 .tag = .goto_stmt,
4353 .data = .{ .decl_ref = name_tok },4497 .data = .{ .decl_ref = name_tok },
4498 .loc = @enumFromInt(goto_tok),
4354 });4499 });
4355 }4500 }
4356 if (p.eatToken(.keyword_continue)) |cont| {4501 if (p.eatToken(.keyword_continue)) |cont| {
4357 if (!p.in_loop) try p.errTok(.continue_not_in_loop, cont);4502 if (!p.in_loop) try p.errTok(.continue_not_in_loop, cont);
4358 _ = try p.expectToken(.semicolon);4503 _ = try p.expectToken(.semicolon);
4359 return try p.addNode(.{ .tag = .continue_stmt, .data = undefined });4504 return try p.addNode(.{ .tag = .continue_stmt, .data = undefined, .loc = @enumFromInt(cont) });
4360 }4505 }
4361 if (p.eatToken(.keyword_break)) |br| {4506 if (p.eatToken(.keyword_break)) |br| {
4362 if (!p.in_loop and p.@"switch" == null) try p.errTok(.break_not_in_loop_or_switch, br);4507 if (!p.in_loop and p.@"switch" == null) try p.errTok(.break_not_in_loop_or_switch, br);
4363 _ = try p.expectToken(.semicolon);4508 _ = try p.expectToken(.semicolon);
4364 return try p.addNode(.{ .tag = .break_stmt, .data = undefined });4509 return try p.addNode(.{ .tag = .break_stmt, .data = undefined, .loc = @enumFromInt(br) });
4365 }4510 }
4366 if (try p.returnStmt()) |some| return some;4511 if (try p.returnStmt()) |some| return some;
4367 if (try p.assembly(.stmt)) |some| return some;4512 if (try p.assembly(.stmt)) |some| return some;
...@@ -4380,8 +4525,8 @@ fn stmt(p: *Parser) Error!NodeIndex {...@@ -4380,8 +4525,8 @@ fn stmt(p: *Parser) Error!NodeIndex {
4380 defer p.attr_buf.len = attr_buf_top;4525 defer p.attr_buf.len = attr_buf_top;
4381 try p.attributeSpecifier();4526 try p.attributeSpecifier();
43824527
4383 if (p.eatToken(.semicolon)) |_| {4528 if (p.eatToken(.semicolon)) |semicolon| {
4384 var null_node: Tree.Node = .{ .tag = .null_stmt, .data = undefined };4529 var null_node: Tree.Node = .{ .tag = .null_stmt, .data = undefined, .loc = @enumFromInt(semicolon) };
4385 null_node.ty = try Attribute.applyStatementAttributes(p, null_node.ty, expr_start, attr_buf_top);4530 null_node.ty = try Attribute.applyStatementAttributes(p, null_node.ty, expr_start, attr_buf_top);
4386 return p.addNode(null_node);4531 return p.addNode(null_node);
4387 }4532 }
...@@ -4422,6 +4567,7 @@ fn labeledStmt(p: *Parser) Error!?NodeIndex {...@@ -4422,6 +4567,7 @@ fn labeledStmt(p: *Parser) Error!?NodeIndex {
4422 var labeled_stmt = Tree.Node{4567 var labeled_stmt = Tree.Node{
4423 .tag = .labeled_stmt,4568 .tag = .labeled_stmt,
4424 .data = .{ .decl = .{ .name = name_tok, .node = try p.labelableStmt() } },4569 .data = .{ .decl = .{ .name = name_tok, .node = try p.labelableStmt() } },
4570 .loc = @enumFromInt(name_tok),
4425 };4571 };
4426 labeled_stmt.ty = try Attribute.applyLabelAttributes(p, labeled_stmt.ty, attr_buf_top);4572 labeled_stmt.ty = try Attribute.applyLabelAttributes(p, labeled_stmt.ty, attr_buf_top);
4427 return try p.addNode(labeled_stmt);4573 return try p.addNode(labeled_stmt);
...@@ -4464,9 +4610,11 @@ fn labeledStmt(p: *Parser) Error!?NodeIndex {...@@ -4464,9 +4610,11 @@ fn labeledStmt(p: *Parser) Error!?NodeIndex {
4464 if (second_item) |some| return try p.addNode(.{4610 if (second_item) |some| return try p.addNode(.{
4465 .tag = .case_range_stmt,4611 .tag = .case_range_stmt,
4466 .data = .{ .if3 = .{ .cond = s, .body = (try p.addList(&.{ first_item.node, some.node })).start } },4612 .data = .{ .if3 = .{ .cond = s, .body = (try p.addList(&.{ first_item.node, some.node })).start } },
4613 .loc = @enumFromInt(case),
4467 }) else return try p.addNode(.{4614 }) else return try p.addNode(.{
4468 .tag = .case_stmt,4615 .tag = .case_stmt,
4469 .data = .{ .bin = .{ .lhs = first_item.node, .rhs = s } },4616 .data = .{ .bin = .{ .lhs = first_item.node, .rhs = s } },
4617 .loc = @enumFromInt(case),
4470 });4618 });
4471 } else if (p.eatToken(.keyword_default)) |default| {4619 } else if (p.eatToken(.keyword_default)) |default| {
4472 _ = try p.expectToken(.colon);4620 _ = try p.expectToken(.colon);
...@@ -4474,6 +4622,7 @@ fn labeledStmt(p: *Parser) Error!?NodeIndex {...@@ -4474,6 +4622,7 @@ fn labeledStmt(p: *Parser) Error!?NodeIndex {
4474 const node = try p.addNode(.{4622 const node = try p.addNode(.{
4475 .tag = .default_stmt,4623 .tag = .default_stmt,
4476 .data = .{ .un = s },4624 .data = .{ .un = s },
4625 .loc = @enumFromInt(default),
4477 });4626 });
4478 const @"switch" = p.@"switch" orelse {4627 const @"switch" = p.@"switch" orelse {
4479 try p.errStr(.case_not_in_switch, default, "default");4628 try p.errStr(.case_not_in_switch, default, "default");
...@@ -4492,7 +4641,7 @@ fn labeledStmt(p: *Parser) Error!?NodeIndex {...@@ -4492,7 +4641,7 @@ fn labeledStmt(p: *Parser) Error!?NodeIndex {
4492fn labelableStmt(p: *Parser) Error!NodeIndex {4641fn labelableStmt(p: *Parser) Error!NodeIndex {
4493 if (p.tok_ids[p.tok_i] == .r_brace) {4642 if (p.tok_ids[p.tok_i] == .r_brace) {
4494 try p.err(.label_compound_end);4643 try p.err(.label_compound_end);
4495 return p.addNode(.{ .tag = .null_stmt, .data = undefined });4644 return p.addNode(.{ .tag = .null_stmt, .data = undefined, .loc = @enumFromInt(p.tok_i) });
4496 }4645 }
4497 return p.stmt();4646 return p.stmt();
4498}4647}
...@@ -4557,6 +4706,7 @@ fn compoundStmt(p: *Parser, is_fn_body: bool, stmt_expr_state: ?*StmtExprState)...@@ -4557,6 +4706,7 @@ fn compoundStmt(p: *Parser, is_fn_body: bool, stmt_expr_state: ?*StmtExprState)
4557 else => {},4706 else => {},
4558 }4707 }
4559 }4708 }
4709 const r_brace = p.tok_i - 1;
45604710
4561 if (noreturn_index) |some| {4711 if (noreturn_index) |some| {
4562 // if new labels were defined we cannot be certain that the code is unreachable4712 // if new labels were defined we cannot be certain that the code is unreachable
...@@ -4580,7 +4730,7 @@ fn compoundStmt(p: *Parser, is_fn_body: bool, stmt_expr_state: ?*StmtExprState)...@@ -4580,7 +4730,7 @@ fn compoundStmt(p: *Parser, is_fn_body: bool, stmt_expr_state: ?*StmtExprState)
4580 try p.errStr(.func_does_not_return, p.tok_i - 1, func_name);4730 try p.errStr(.func_does_not_return, p.tok_i - 1, func_name);
4581 }4731 }
4582 }4732 }
4583 try p.decl_buf.append(try p.addNode(.{ .tag = .implicit_return, .ty = p.func.ty.?.returnType(), .data = .{ .return_zero = return_zero } }));4733 try p.decl_buf.append(try p.addNode(.{ .tag = .implicit_return, .ty = p.func.ty.?.returnType(), .data = .{ .return_zero = return_zero }, .loc = @enumFromInt(r_brace) }));
4584 }4734 }
4585 if (p.func.ident) |some| try p.decl_buf.insert(decl_buf_top, some.node);4735 if (p.func.ident) |some| try p.decl_buf.insert(decl_buf_top, some.node);
4586 if (p.func.pretty_ident) |some| try p.decl_buf.insert(decl_buf_top, some.node);4736 if (p.func.pretty_ident) |some| try p.decl_buf.insert(decl_buf_top, some.node);
...@@ -4588,13 +4738,14 @@ fn compoundStmt(p: *Parser, is_fn_body: bool, stmt_expr_state: ?*StmtExprState)...@@ -4588,13 +4738,14 @@ fn compoundStmt(p: *Parser, is_fn_body: bool, stmt_expr_state: ?*StmtExprState)
45884738
4589 var node: Tree.Node = .{4739 var node: Tree.Node = .{
4590 .tag = .compound_stmt_two,4740 .tag = .compound_stmt_two,
4591 .data = .{ .bin = .{ .lhs = .none, .rhs = .none } },4741 .data = .{ .two = .{ .none, .none } },
4742 .loc = @enumFromInt(l_brace),
4592 };4743 };
4593 const statements = p.decl_buf.items[decl_buf_top..];4744 const statements = p.decl_buf.items[decl_buf_top..];
4594 switch (statements.len) {4745 switch (statements.len) {
4595 0 => {},4746 0 => {},
4596 1 => node.data = .{ .bin = .{ .lhs = statements[0], .rhs = .none } },4747 1 => node.data = .{ .two = .{ statements[0], .none } },
4597 2 => node.data = .{ .bin = .{ .lhs = statements[0], .rhs = statements[1] } },4748 2 => node.data = .{ .two = .{ statements[0], statements[1] } },
4598 else => {4749 else => {
4599 node.tag = .compound_stmt;4750 node.tag = .compound_stmt;
4600 node.data = .{ .range = try p.addList(statements) };4751 node.data = .{ .range = try p.addList(statements) };
...@@ -4618,8 +4769,8 @@ fn nodeIsNoreturn(p: *Parser, node: NodeIndex) NoreturnKind {...@@ -4618,8 +4769,8 @@ fn nodeIsNoreturn(p: *Parser, node: NodeIndex) NoreturnKind {
4618 },4769 },
4619 .compound_stmt_two => {4770 .compound_stmt_two => {
4620 const data = p.nodes.items(.data)[@intFromEnum(node)];4771 const data = p.nodes.items(.data)[@intFromEnum(node)];
4621 const lhs_type = if (data.bin.lhs != .none) p.nodeIsNoreturn(data.bin.lhs) else .no;4772 const lhs_type = if (data.two[0] != .none) p.nodeIsNoreturn(data.two[0]) else .no;
4622 const rhs_type = if (data.bin.rhs != .none) p.nodeIsNoreturn(data.bin.rhs) else .no;4773 const rhs_type = if (data.two[1] != .none) p.nodeIsNoreturn(data.two[1]) else .no;
4623 if (lhs_type == .complex or rhs_type == .complex) return .complex;4774 if (lhs_type == .complex or rhs_type == .complex) return .complex;
4624 if (lhs_type == .yes or rhs_type == .yes) return .yes;4775 if (lhs_type == .yes or rhs_type == .yes) return .yes;
4625 return .no;4776 return .no;
...@@ -4704,6 +4855,8 @@ fn nextStmt(p: *Parser, l_brace: TokenIndex) !void {...@@ -4704,6 +4855,8 @@ fn nextStmt(p: *Parser, l_brace: TokenIndex) !void {
4704 .keyword_int,4855 .keyword_int,
4705 .keyword_long,4856 .keyword_long,
4706 .keyword_signed,4857 .keyword_signed,
4858 .keyword_signed1,
4859 .keyword_signed2,
4707 .keyword_unsigned,4860 .keyword_unsigned,
4708 .keyword_float,4861 .keyword_float,
4709 .keyword_double,4862 .keyword_double,
...@@ -4743,17 +4896,17 @@ fn returnStmt(p: *Parser) Error!?NodeIndex {...@@ -4743,17 +4896,17 @@ fn returnStmt(p: *Parser) Error!?NodeIndex {
47434896
4744 if (e.node == .none) {4897 if (e.node == .none) {
4745 if (!ret_ty.is(.void)) try p.errStr(.func_should_return, ret_tok, p.tokSlice(p.func.name));4898 if (!ret_ty.is(.void)) try p.errStr(.func_should_return, ret_tok, p.tokSlice(p.func.name));
4746 return try p.addNode(.{ .tag = .return_stmt, .data = .{ .un = e.node } });4899 return try p.addNode(.{ .tag = .return_stmt, .data = .{ .un = e.node }, .loc = @enumFromInt(ret_tok) });
4747 } else if (ret_ty.is(.void)) {4900 } else if (ret_ty.is(.void)) {
4748 try p.errStr(.void_func_returns_value, e_tok, p.tokSlice(p.func.name));4901 try p.errStr(.void_func_returns_value, e_tok, p.tokSlice(p.func.name));
4749 return try p.addNode(.{ .tag = .return_stmt, .data = .{ .un = e.node } });4902 return try p.addNode(.{ .tag = .return_stmt, .data = .{ .un = e.node }, .loc = @enumFromInt(ret_tok) });
4750 }4903 }
47514904
4752 try e.lvalConversion(p);4905 try e.lvalConversion(p);
4753 try e.coerce(p, ret_ty, e_tok, .ret);4906 try e.coerce(p, ret_ty, e_tok, .ret);
47544907
4755 try e.saveValue(p);4908 try e.saveValue(p);
4756 return try p.addNode(.{ .tag = .return_stmt, .data = .{ .un = e.node } });4909 return try p.addNode(.{ .tag = .return_stmt, .data = .{ .un = e.node }, .loc = @enumFromInt(ret_tok) });
4757}4910}
47584911
4759// ====== expressions ======4912// ====== expressions ======
...@@ -4802,7 +4955,6 @@ const CallExpr = union(enum) {...@@ -4802,7 +4955,6 @@ const CallExpr = union(enum) {
4802 }4955 }
48034956
4804 fn shouldPromoteVarArg(self: CallExpr, arg_idx: u32) bool {4957 fn shouldPromoteVarArg(self: CallExpr, arg_idx: u32) bool {
4805 @setEvalBranchQuota(2000);
4806 return switch (self) {4958 return switch (self) {
4807 .standard => true,4959 .standard => true,
4808 .builtin => |builtin| switch (builtin.tag) {4960 .builtin => |builtin| switch (builtin.tag) {
...@@ -4810,10 +4962,13 @@ const CallExpr = union(enum) {...@@ -4810,10 +4962,13 @@ const CallExpr = union(enum) {
4810 Builtin.tagFromName("__va_start").?,4962 Builtin.tagFromName("__va_start").?,
4811 Builtin.tagFromName("va_start").?,4963 Builtin.tagFromName("va_start").?,
4812 => arg_idx != 1,4964 => arg_idx != 1,
4813 Builtin.tagFromName("__builtin_complex").?,
4814 Builtin.tagFromName("__builtin_add_overflow").?,4965 Builtin.tagFromName("__builtin_add_overflow").?,
4815 Builtin.tagFromName("__builtin_sub_overflow").?,4966 Builtin.tagFromName("__builtin_complex").?,
4967 Builtin.tagFromName("__builtin_isinf").?,
4968 Builtin.tagFromName("__builtin_isinf_sign").?,
4816 Builtin.tagFromName("__builtin_mul_overflow").?,4969 Builtin.tagFromName("__builtin_mul_overflow").?,
4970 Builtin.tagFromName("__builtin_isnan").?,
4971 Builtin.tagFromName("__builtin_sub_overflow").?,
4817 => false,4972 => false,
4818 else => true,4973 else => true,
4819 },4974 },
...@@ -4827,7 +4982,6 @@ const CallExpr = union(enum) {...@@ -4827,7 +4982,6 @@ const CallExpr = union(enum) {
4827 }4982 }
48284983
4829 fn checkVarArg(self: CallExpr, p: *Parser, first_after: TokenIndex, param_tok: TokenIndex, arg: *Result, arg_idx: u32) !void {4984 fn checkVarArg(self: CallExpr, p: *Parser, first_after: TokenIndex, param_tok: TokenIndex, arg: *Result, arg_idx: u32) !void {
4830 @setEvalBranchQuota(10_000);
4831 if (self == .standard) return;4985 if (self == .standard) return;
48324986
4833 const builtin_tok = p.nodes.items(.data)[@intFromEnum(self.builtin.node)].decl.name;4987 const builtin_tok = p.nodes.items(.data)[@intFromEnum(self.builtin.node)].decl.name;
...@@ -4852,13 +5006,15 @@ const CallExpr = union(enum) {...@@ -4852,13 +5006,15 @@ const CallExpr = union(enum) {
4852 /// of arguments, `paramCountOverride` is used to tell us how many arguments we should actually expect to see for5006 /// of arguments, `paramCountOverride` is used to tell us how many arguments we should actually expect to see for
4853 /// these custom-typechecked functions.5007 /// these custom-typechecked functions.
4854 fn paramCountOverride(self: CallExpr) ?u32 {5008 fn paramCountOverride(self: CallExpr) ?u32 {
4855 @setEvalBranchQuota(10_000);
4856 return switch (self) {5009 return switch (self) {
4857 .standard => null,5010 .standard => null,
4858 .builtin => |builtin| switch (builtin.tag) {5011 .builtin => |builtin| switch (builtin.tag) {
4859 Builtin.tagFromName("__c11_atomic_thread_fence").?,5012 Builtin.tagFromName("__c11_atomic_thread_fence").?,
4860 Builtin.tagFromName("__c11_atomic_signal_fence").?,5013 Builtin.tagFromName("__c11_atomic_signal_fence").?,
4861 Builtin.tagFromName("__c11_atomic_is_lock_free").?,5014 Builtin.tagFromName("__c11_atomic_is_lock_free").?,
5015 Builtin.tagFromName("__builtin_isinf").?,
5016 Builtin.tagFromName("__builtin_isinf_sign").?,
5017 Builtin.tagFromName("__builtin_isnan").?,
4862 => 1,5018 => 1,
48635019
4864 Builtin.tagFromName("__builtin_complex").?,5020 Builtin.tagFromName("__builtin_complex").?,
...@@ -4903,7 +5059,6 @@ const CallExpr = union(enum) {...@@ -4903,7 +5059,6 @@ const CallExpr = union(enum) {
4903 }5059 }
49045060
4905 fn returnType(self: CallExpr, p: *Parser, callable_ty: Type) Type {5061 fn returnType(self: CallExpr, p: *Parser, callable_ty: Type) Type {
4906 @setEvalBranchQuota(6000);
4907 return switch (self) {5062 return switch (self) {
4908 .standard => callable_ty.returnType(),5063 .standard => callable_ty.returnType(),
4909 .builtin => |builtin| switch (builtin.tag) {5064 .builtin => |builtin| switch (builtin.tag) {
...@@ -4977,12 +5132,12 @@ const CallExpr = union(enum) {...@@ -4977,12 +5132,12 @@ const CallExpr = union(enum) {
4977 var call_node: Tree.Node = .{5132 var call_node: Tree.Node = .{
4978 .tag = .call_expr_one,5133 .tag = .call_expr_one,
4979 .ty = ret_ty,5134 .ty = ret_ty,
4980 .data = .{ .bin = .{ .lhs = func_node, .rhs = .none } },5135 .data = .{ .two = .{ func_node, .none } },
4981 };5136 };
4982 const args = p.list_buf.items[list_buf_top..];5137 const args = p.list_buf.items[list_buf_top..];
4983 switch (arg_count) {5138 switch (arg_count) {
4984 0 => {},5139 0 => {},
4985 1 => call_node.data.bin.rhs = args[1], // args[0] == func.node5140 1 => call_node.data.two[1] = args[1], // args[0] == func.node
4986 else => {5141 else => {
4987 call_node.tag = .call_expr;5142 call_node.tag = .call_expr;
4988 call_node.data = .{ .range = try p.addList(args) };5143 call_node.data = .{ .range = try p.addList(args) };
...@@ -5005,7 +5160,8 @@ const CallExpr = union(enum) {...@@ -5005,7 +5160,8 @@ const CallExpr = union(enum) {
5005 call_node.data = .{ .range = try p.addList(args) };5160 call_node.data = .{ .range = try p.addList(args) };
5006 },5161 },
5007 }5162 }
5008 return Result{ .node = builtin.node, .ty = ret_ty };5163 const val = try evalBuiltin(builtin.tag, p, args[1..]);
5164 return Result{ .node = builtin.node, .ty = ret_ty, .val = val };
5009 },5165 },
5010 }5166 }
5011 }5167 }
...@@ -5016,6 +5172,8 @@ pub const Result = struct {...@@ -5016,6 +5172,8 @@ pub const Result = struct {
5016 ty: Type = .{ .specifier = .int },5172 ty: Type = .{ .specifier = .int },
5017 val: Value = .{},5173 val: Value = .{},
50185174
5175 const invalid: Result = .{ .ty = Type.invalid };
5176
5019 pub fn str(res: Result, p: *Parser) ![]const u8 {5177 pub fn str(res: Result, p: *Parser) ![]const u8 {
5020 switch (res.val.opt_ref) {5178 switch (res.val.opt_ref) {
5021 .none => return "(none)",5179 .none => return "(none)",
...@@ -5073,30 +5231,21 @@ pub const Result = struct {...@@ -5073,30 +5231,21 @@ pub const Result = struct {
5073 .post_inc_expr,5231 .post_inc_expr,
5074 .post_dec_expr,5232 .post_dec_expr,
5075 => return,5233 => return,
5076 .call_expr_one => {5234 .call_expr, .call_expr_one => {
5077 const fn_ptr = p.nodes.items(.data)[@intFromEnum(cur_node)].bin.lhs;5235 const tmp_tree = p.tmpTree();
5078 const fn_ty = p.nodes.items(.ty)[@intFromEnum(fn_ptr)].elemType();5236 const child_nodes = tmp_tree.childNodes(cur_node);
5079 const cast_info = p.nodes.items(.data)[@intFromEnum(fn_ptr)].cast.operand;5237 const fn_ptr = child_nodes[0];
5080 const decl_ref = p.nodes.items(.data)[@intFromEnum(cast_info)].decl_ref;5238 const call_info = tmp_tree.callableResultUsage(fn_ptr) orelse return;
5081 if (fn_ty.hasAttribute(.nodiscard)) try p.errStr(.nodiscard_unused, expr_start, p.tokSlice(decl_ref));5239 if (call_info.nodiscard) try p.errStr(.nodiscard_unused, expr_start, p.tokSlice(call_info.tok));
5082 if (fn_ty.hasAttribute(.warn_unused_result)) try p.errStr(.warn_unused_result, expr_start, p.tokSlice(decl_ref));5240 if (call_info.warn_unused_result) try p.errStr(.warn_unused_result, expr_start, p.tokSlice(call_info.tok));
5083 return;
5084 },
5085 .call_expr => {
5086 const fn_ptr = p.data.items[p.nodes.items(.data)[@intFromEnum(cur_node)].range.start];
5087 const fn_ty = p.nodes.items(.ty)[@intFromEnum(fn_ptr)].elemType();
5088 const cast_info = p.nodes.items(.data)[@intFromEnum(fn_ptr)].cast.operand;
5089 const decl_ref = p.nodes.items(.data)[@intFromEnum(cast_info)].decl_ref;
5090 if (fn_ty.hasAttribute(.nodiscard)) try p.errStr(.nodiscard_unused, expr_start, p.tokSlice(decl_ref));
5091 if (fn_ty.hasAttribute(.warn_unused_result)) try p.errStr(.warn_unused_result, expr_start, p.tokSlice(decl_ref));
5092 return;5241 return;
5093 },5242 },
5094 .stmt_expr => {5243 .stmt_expr => {
5095 const body = p.nodes.items(.data)[@intFromEnum(cur_node)].un;5244 const body = p.nodes.items(.data)[@intFromEnum(cur_node)].un;
5096 switch (p.nodes.items(.tag)[@intFromEnum(body)]) {5245 switch (p.nodes.items(.tag)[@intFromEnum(body)]) {
5097 .compound_stmt_two => {5246 .compound_stmt_two => {
5098 const body_stmt = p.nodes.items(.data)[@intFromEnum(body)].bin;5247 const body_stmt = p.nodes.items(.data)[@intFromEnum(body)].two;
5099 cur_node = if (body_stmt.rhs != .none) body_stmt.rhs else body_stmt.lhs;5248 cur_node = if (body_stmt[1] != .none) body_stmt[1] else body_stmt[0];
5100 },5249 },
5101 .compound_stmt => {5250 .compound_stmt => {
5102 const data = p.nodes.items(.data)[@intFromEnum(body)];5251 const data = p.nodes.items(.data)[@intFromEnum(body)];
...@@ -5112,29 +5261,31 @@ pub const Result = struct {...@@ -5112,29 +5261,31 @@ pub const Result = struct {
5112 try p.errTok(.unused_value, expr_start);5261 try p.errTok(.unused_value, expr_start);
5113 }5262 }
51145263
5115 fn boolRes(lhs: *Result, p: *Parser, tag: Tree.Tag, rhs: Result) !void {5264 fn boolRes(lhs: *Result, p: *Parser, tag: Tree.Tag, rhs: Result, tok_i: TokenIndex) !void {
5116 if (lhs.val.opt_ref == .null) {5265 if (lhs.val.opt_ref == .null) {
5117 lhs.val = Value.zero;5266 lhs.val = Value.zero;
5118 }5267 }
5119 if (lhs.ty.specifier != .invalid) {5268 if (lhs.ty.specifier != .invalid) {
5120 lhs.ty = Type.int;5269 lhs.ty = Type.int;
5121 }5270 }
5122 return lhs.bin(p, tag, rhs);5271 return lhs.bin(p, tag, rhs, tok_i);
5123 }5272 }
51245273
5125 fn bin(lhs: *Result, p: *Parser, tag: Tree.Tag, rhs: Result) !void {5274 fn bin(lhs: *Result, p: *Parser, tag: Tree.Tag, rhs: Result, tok_i: TokenIndex) !void {
5126 lhs.node = try p.addNode(.{5275 lhs.node = try p.addNode(.{
5127 .tag = tag,5276 .tag = tag,
5128 .ty = lhs.ty,5277 .ty = lhs.ty,
5129 .data = .{ .bin = .{ .lhs = lhs.node, .rhs = rhs.node } },5278 .data = .{ .bin = .{ .lhs = lhs.node, .rhs = rhs.node } },
5279 .loc = @enumFromInt(tok_i),
5130 });5280 });
5131 }5281 }
51325282
5133 fn un(operand: *Result, p: *Parser, tag: Tree.Tag) Error!void {5283 fn un(operand: *Result, p: *Parser, tag: Tree.Tag, tok_i: TokenIndex) Error!void {
5134 operand.node = try p.addNode(.{5284 operand.node = try p.addNode(.{
5135 .tag = tag,5285 .tag = tag,
5136 .ty = operand.ty,5286 .ty = operand.ty,
5137 .data = .{ .un = operand.node },5287 .data = .{ .un = operand.node },
5288 .loc = @enumFromInt(tok_i),
5138 });5289 });
5139 }5290 }
51405291
...@@ -5368,10 +5519,14 @@ pub const Result = struct {...@@ -5368,10 +5519,14 @@ pub const Result = struct {
53685519
5369 fn lvalConversion(res: *Result, p: *Parser) Error!void {5520 fn lvalConversion(res: *Result, p: *Parser) Error!void {
5370 if (res.ty.isFunc()) {5521 if (res.ty.isFunc()) {
5371 const elem_ty = try p.arena.create(Type);5522 if (res.ty.isInvalidFunc()) {
5372 elem_ty.* = res.ty;5523 res.ty = .{ .specifier = .invalid };
5373 res.ty.specifier = .pointer;5524 } else {
5374 res.ty.data = .{ .sub_type = elem_ty };5525 const elem_ty = try p.arena.create(Type);
5526 elem_ty.* = res.ty;
5527 res.ty.specifier = .pointer;
5528 res.ty.data = .{ .sub_type = elem_ty };
5529 }
5375 try res.implicitCast(p, .function_to_pointer);5530 try res.implicitCast(p, .function_to_pointer);
5376 } else if (res.ty.isArray()) {5531 } else if (res.ty.isArray()) {
5377 res.val = .{};5532 res.val = .{};
...@@ -5455,7 +5610,14 @@ pub const Result = struct {...@@ -5455,7 +5610,14 @@ pub const Result = struct {
5455 try res.implicitCast(p, .complex_float_to_complex_int);5610 try res.implicitCast(p, .complex_float_to_complex_int);
5456 }5611 }
5457 } else if (!res.ty.eql(int_ty, p.comp, true)) {5612 } else if (!res.ty.eql(int_ty, p.comp, true)) {
5458 try res.val.intCast(int_ty, p.comp);5613 const old_val = res.val;
5614 const value_change_kind = try res.val.intCast(int_ty, p.comp);
5615 switch (value_change_kind) {
5616 .none => {},
5617 .truncated => try p.errStr(.int_value_changed, tok, try p.valueChangedStr(res, old_val, int_ty)),
5618 .sign_changed => try p.errStr(.sign_conversion, tok, try p.typePairStrExtra(res.ty, " to ", int_ty)),
5619 }
5620
5459 const old_real = res.ty.isReal();5621 const old_real = res.ty.isReal();
5460 const new_real = int_ty.isReal();5622 const new_real = int_ty.isReal();
5461 if (old_real and new_real) {5623 if (old_real and new_real) {
...@@ -5486,8 +5648,8 @@ pub const Result = struct {...@@ -5486,8 +5648,8 @@ pub const Result = struct {
5486 .none => return p.errStr(.float_to_int, tok, try p.typePairStrExtra(res.ty, " to ", int_ty)),5648 .none => return p.errStr(.float_to_int, tok, try p.typePairStrExtra(res.ty, " to ", int_ty)),
5487 .out_of_range => return p.errStr(.float_out_of_range, tok, try p.typePairStrExtra(res.ty, " to ", int_ty)),5649 .out_of_range => return p.errStr(.float_out_of_range, tok, try p.typePairStrExtra(res.ty, " to ", int_ty)),
5488 .overflow => return p.errStr(.float_overflow_conversion, tok, try p.typePairStrExtra(res.ty, " to ", int_ty)),5650 .overflow => return p.errStr(.float_overflow_conversion, tok, try p.typePairStrExtra(res.ty, " to ", int_ty)),
5489 .nonzero_to_zero => return p.errStr(.float_zero_conversion, tok, try p.floatValueChangedStr(res, old_value, int_ty)),5651 .nonzero_to_zero => return p.errStr(.float_zero_conversion, tok, try p.valueChangedStr(res, old_value, int_ty)),
5490 .value_changed => return p.errStr(.float_value_changed, tok, try p.floatValueChangedStr(res, old_value, int_ty)),5652 .value_changed => return p.errStr(.float_value_changed, tok, try p.valueChangedStr(res, old_value, int_ty)),
5491 }5653 }
5492 }5654 }
54935655
...@@ -5555,7 +5717,7 @@ pub const Result = struct {...@@ -5555,7 +5717,7 @@ pub const Result = struct {
5555 res.ty = ptr_ty;5717 res.ty = ptr_ty;
5556 try res.implicitCast(p, .bool_to_pointer);5718 try res.implicitCast(p, .bool_to_pointer);
5557 } else if (res.ty.isInt()) {5719 } else if (res.ty.isInt()) {
5558 try res.val.intCast(ptr_ty, p.comp);5720 _ = try res.val.intCast(ptr_ty, p.comp);
5559 res.ty = ptr_ty;5721 res.ty = ptr_ty;
5560 try res.implicitCast(p, .int_to_pointer);5722 try res.implicitCast(p, .int_to_pointer);
5561 }5723 }
...@@ -5620,16 +5782,14 @@ pub const Result = struct {...@@ -5620,16 +5782,14 @@ pub const Result = struct {
56205782
5621 // if either is a float cast to that type5783 // if either is a float cast to that type
5622 if (a.ty.isFloat() or b.ty.isFloat()) {5784 if (a.ty.isFloat() or b.ty.isFloat()) {
5623 const float_types = [7][2]Type.Specifier{5785 const float_types = [6][2]Type.Specifier{
5624 .{ .complex_long_double, .long_double },5786 .{ .complex_long_double, .long_double },
5625 .{ .complex_float128, .float128 },5787 .{ .complex_float128, .float128 },
5626 .{ .complex_float80, .float80 },
5627 .{ .complex_double, .double },5788 .{ .complex_double, .double },
5628 .{ .complex_float, .float },5789 .{ .complex_float, .float },
5629 // No `_Complex __fp16` type5790 // No `_Complex __fp16` type
5630 .{ .invalid, .fp16 },5791 .{ .invalid, .fp16 },
5631 // No `_Complex _Float16`5792 .{ .complex_float16, .float16 },
5632 .{ .invalid, .float16 },
5633 };5793 };
5634 const a_spec = a.ty.canonicalize(.standard).specifier;5794 const a_spec = a.ty.canonicalize(.standard).specifier;
5635 const b_spec = b.ty.canonicalize(.standard).specifier;5795 const b_spec = b.ty.canonicalize(.standard).specifier;
...@@ -5647,7 +5807,7 @@ pub const Result = struct {...@@ -5647,7 +5807,7 @@ pub const Result = struct {
5647 if (try a.floatConversion(b, a_spec, b_spec, p, float_types[3])) return;5807 if (try a.floatConversion(b, a_spec, b_spec, p, float_types[3])) return;
5648 if (try a.floatConversion(b, a_spec, b_spec, p, float_types[4])) return;5808 if (try a.floatConversion(b, a_spec, b_spec, p, float_types[4])) return;
5649 if (try a.floatConversion(b, a_spec, b_spec, p, float_types[5])) return;5809 if (try a.floatConversion(b, a_spec, b_spec, p, float_types[5])) return;
5650 if (try a.floatConversion(b, a_spec, b_spec, p, float_types[6])) return;5810 unreachable;
5651 }5811 }
56525812
5653 if (a.ty.eql(b.ty, p.comp, true)) {5813 if (a.ty.eql(b.ty, p.comp, true)) {
...@@ -5875,6 +6035,10 @@ pub const Result = struct {...@@ -5875,6 +6035,10 @@ pub const Result = struct {
5875 if (to.is(.bool)) {6035 if (to.is(.bool)) {
5876 res.val.boolCast(p.comp);6036 res.val.boolCast(p.comp);
5877 } else if (old_float and new_int) {6037 } else if (old_float and new_int) {
6038 if (to.hasIncompleteSize()) {
6039 try p.errStr(.cast_to_incomplete_type, l_paren, try p.typeStr(to));
6040 return error.ParsingFailed;
6041 }
5878 // Explicit cast, no conversion warning6042 // Explicit cast, no conversion warning
5879 _ = try res.val.floatToInt(to, p.comp);6043 _ = try res.val.floatToInt(to, p.comp);
5880 } else if (new_float and old_int) {6044 } else if (new_float and old_int) {
...@@ -5886,7 +6050,7 @@ pub const Result = struct {...@@ -5886,7 +6050,7 @@ pub const Result = struct {
5886 try p.errStr(.cast_to_incomplete_type, l_paren, try p.typeStr(to));6050 try p.errStr(.cast_to_incomplete_type, l_paren, try p.typeStr(to));
5887 return error.ParsingFailed;6051 return error.ParsingFailed;
5888 }6052 }
5889 try res.val.intCast(to, p.comp);6053 _ = try res.val.intCast(to, p.comp);
5890 }6054 }
5891 } else if (to.get(.@"union")) |union_ty| {6055 } else if (to.get(.@"union")) |union_ty| {
5892 if (union_ty.data.record.hasFieldOfType(res.ty, p.comp)) {6056 if (union_ty.data.record.hasFieldOfType(res.ty, p.comp)) {
...@@ -5918,12 +6082,13 @@ pub const Result = struct {...@@ -5918,12 +6082,13 @@ pub const Result = struct {
5918 .tag = .explicit_cast,6082 .tag = .explicit_cast,
5919 .ty = res.ty,6083 .ty = res.ty,
5920 .data = .{ .cast = .{ .operand = res.node, .kind = cast_kind } },6084 .data = .{ .cast = .{ .operand = res.node, .kind = cast_kind } },
6085 .loc = @enumFromInt(l_paren),
5921 });6086 });
5922 }6087 }
59236088
5924 fn intFitsInType(res: Result, p: *Parser, ty: Type) !bool {6089 fn intFitsInType(res: Result, p: *Parser, ty: Type) !bool {
5925 const max_int = try Value.int(ty.maxInt(p.comp), p.comp);6090 const max_int = try Value.maxInt(ty, p.comp);
5926 const min_int = try Value.int(ty.minInt(p.comp), p.comp);6091 const min_int = try Value.minInt(ty, p.comp);
5927 return res.val.compare(.lte, max_int, p.comp) and6092 return res.val.compare(.lte, max_int, p.comp) and
5928 (res.ty.isUnsignedInt(p.comp) or res.val.compare(.gte, min_int, p.comp));6093 (res.ty.isUnsignedInt(p.comp) or res.val.compare(.gte, min_int, p.comp));
5929 }6094 }
...@@ -6091,7 +6256,7 @@ fn expr(p: *Parser) Error!Result {...@@ -6091,7 +6256,7 @@ fn expr(p: *Parser) Error!Result {
6091 var err_start = p.comp.diagnostics.list.items.len;6256 var err_start = p.comp.diagnostics.list.items.len;
6092 var lhs = try p.assignExpr();6257 var lhs = try p.assignExpr();
6093 if (p.tok_ids[p.tok_i] == .comma) try lhs.expect(p);6258 if (p.tok_ids[p.tok_i] == .comma) try lhs.expect(p);
6094 while (p.eatToken(.comma)) |_| {6259 while (p.eatToken(.comma)) |comma| {
6095 try lhs.maybeWarnUnused(p, expr_start, err_start);6260 try lhs.maybeWarnUnused(p, expr_start, err_start);
6096 expr_start = p.tok_i;6261 expr_start = p.tok_i;
6097 err_start = p.comp.diagnostics.list.items.len;6262 err_start = p.comp.diagnostics.list.items.len;
...@@ -6101,7 +6266,7 @@ fn expr(p: *Parser) Error!Result {...@@ -6101,7 +6266,7 @@ fn expr(p: *Parser) Error!Result {
6101 try rhs.lvalConversion(p);6266 try rhs.lvalConversion(p);
6102 lhs.val = rhs.val;6267 lhs.val = rhs.val;
6103 lhs.ty = rhs.ty;6268 lhs.ty = rhs.ty;
6104 try lhs.bin(p, .comma_expr, rhs);6269 try lhs.bin(p, .comma_expr, rhs, comma);
6105 }6270 }
6106 return lhs;6271 return lhs;
6107}6272}
...@@ -6183,7 +6348,7 @@ fn assignExpr(p: *Parser) Error!Result {...@@ -6183,7 +6348,7 @@ fn assignExpr(p: *Parser) Error!Result {
6183 }6348 }
6184 }6349 }
6185 _ = try lhs_copy.adjustTypes(tok, &rhs, p, if (tag == .mod_assign_expr) .integer else .arithmetic);6350 _ = try lhs_copy.adjustTypes(tok, &rhs, p, if (tag == .mod_assign_expr) .integer else .arithmetic);
6186 try lhs.bin(p, tag, rhs);6351 try lhs.bin(p, tag, rhs, bit_or.?);
6187 return lhs;6352 return lhs;
6188 },6353 },
6189 .sub_assign_expr,6354 .sub_assign_expr,
...@@ -6194,7 +6359,7 @@ fn assignExpr(p: *Parser) Error!Result {...@@ -6194,7 +6359,7 @@ fn assignExpr(p: *Parser) Error!Result {
6194 } else {6359 } else {
6195 _ = try lhs_copy.adjustTypes(tok, &rhs, p, .arithmetic);6360 _ = try lhs_copy.adjustTypes(tok, &rhs, p, .arithmetic);
6196 }6361 }
6197 try lhs.bin(p, tag, rhs);6362 try lhs.bin(p, tag, rhs, bit_or.?);
6198 return lhs;6363 return lhs;
6199 },6364 },
6200 .shl_assign_expr,6365 .shl_assign_expr,
...@@ -6204,7 +6369,7 @@ fn assignExpr(p: *Parser) Error!Result {...@@ -6204,7 +6369,7 @@ fn assignExpr(p: *Parser) Error!Result {
6204 .bit_or_assign_expr,6369 .bit_or_assign_expr,
6205 => {6370 => {
6206 _ = try lhs_copy.adjustTypes(tok, &rhs, p, .integer);6371 _ = try lhs_copy.adjustTypes(tok, &rhs, p, .integer);
6207 try lhs.bin(p, tag, rhs);6372 try lhs.bin(p, tag, rhs, bit_or.?);
6208 return lhs;6373 return lhs;
6209 },6374 },
6210 else => unreachable,6375 else => unreachable,
...@@ -6212,7 +6377,7 @@ fn assignExpr(p: *Parser) Error!Result {...@@ -6212,7 +6377,7 @@ fn assignExpr(p: *Parser) Error!Result {
62126377
6213 try rhs.coerce(p, lhs.ty, tok, .assign);6378 try rhs.coerce(p, lhs.ty, tok, .assign);
62146379
6215 try lhs.bin(p, tag, rhs);6380 try lhs.bin(p, tag, rhs, bit_or.?);
6216 return lhs;6381 return lhs;
6217}6382}
62186383
...@@ -6280,6 +6445,7 @@ fn condExpr(p: *Parser) Error!Result {...@@ -6280,6 +6445,7 @@ fn condExpr(p: *Parser) Error!Result {
6280 .tag = .binary_cond_expr,6445 .tag = .binary_cond_expr,
6281 .ty = cond.ty,6446 .ty = cond.ty,
6282 .data = .{ .if3 = .{ .cond = cond.node, .body = (try p.addList(&.{ cond_then.node, then_expr.node })).start } },6447 .data = .{ .if3 = .{ .cond = cond.node, .body = (try p.addList(&.{ cond_then.node, then_expr.node })).start } },
6448 .loc = @enumFromInt(cond_tok),
6283 });6449 });
6284 return cond;6450 return cond;
6285 }6451 }
...@@ -6305,6 +6471,7 @@ fn condExpr(p: *Parser) Error!Result {...@@ -6305,6 +6471,7 @@ fn condExpr(p: *Parser) Error!Result {
6305 .tag = .cond_expr,6471 .tag = .cond_expr,
6306 .ty = cond.ty,6472 .ty = cond.ty,
6307 .data = .{ .if3 = .{ .cond = cond.node, .body = (try p.addList(&.{ then_expr.node, else_expr.node })).start } },6473 .data = .{ .if3 = .{ .cond = cond.node, .body = (try p.addList(&.{ then_expr.node, else_expr.node })).start } },
6474 .loc = @enumFromInt(cond_tok),
6308 });6475 });
6309 return cond;6476 return cond;
6310}6477}
...@@ -6324,8 +6491,10 @@ fn lorExpr(p: *Parser) Error!Result {...@@ -6324,8 +6491,10 @@ fn lorExpr(p: *Parser) Error!Result {
6324 if (try lhs.adjustTypes(tok, &rhs, p, .boolean_logic)) {6491 if (try lhs.adjustTypes(tok, &rhs, p, .boolean_logic)) {
6325 const res = lhs.val.toBool(p.comp) or rhs.val.toBool(p.comp);6492 const res = lhs.val.toBool(p.comp) or rhs.val.toBool(p.comp);
6326 lhs.val = Value.fromBool(res);6493 lhs.val = Value.fromBool(res);
6494 } else {
6495 lhs.val.boolCast(p.comp);
6327 }6496 }
6328 try lhs.boolRes(p, .bool_or_expr, rhs);6497 try lhs.boolRes(p, .bool_or_expr, rhs, tok);
6329 }6498 }
6330 return lhs;6499 return lhs;
6331}6500}
...@@ -6345,8 +6514,10 @@ fn landExpr(p: *Parser) Error!Result {...@@ -6345,8 +6514,10 @@ fn landExpr(p: *Parser) Error!Result {
6345 if (try lhs.adjustTypes(tok, &rhs, p, .boolean_logic)) {6514 if (try lhs.adjustTypes(tok, &rhs, p, .boolean_logic)) {
6346 const res = lhs.val.toBool(p.comp) and rhs.val.toBool(p.comp);6515 const res = lhs.val.toBool(p.comp) and rhs.val.toBool(p.comp);
6347 lhs.val = Value.fromBool(res);6516 lhs.val = Value.fromBool(res);
6517 } else {
6518 lhs.val.boolCast(p.comp);
6348 }6519 }
6349 try lhs.boolRes(p, .bool_and_expr, rhs);6520 try lhs.boolRes(p, .bool_and_expr, rhs, tok);
6350 }6521 }
6351 return lhs;6522 return lhs;
6352}6523}
...@@ -6362,7 +6533,7 @@ fn orExpr(p: *Parser) Error!Result {...@@ -6362,7 +6533,7 @@ fn orExpr(p: *Parser) Error!Result {
6362 if (try lhs.adjustTypes(tok, &rhs, p, .integer)) {6533 if (try lhs.adjustTypes(tok, &rhs, p, .integer)) {
6363 lhs.val = try lhs.val.bitOr(rhs.val, p.comp);6534 lhs.val = try lhs.val.bitOr(rhs.val, p.comp);
6364 }6535 }
6365 try lhs.bin(p, .bit_or_expr, rhs);6536 try lhs.bin(p, .bit_or_expr, rhs, tok);
6366 }6537 }
6367 return lhs;6538 return lhs;
6368}6539}
...@@ -6378,7 +6549,7 @@ fn xorExpr(p: *Parser) Error!Result {...@@ -6378,7 +6549,7 @@ fn xorExpr(p: *Parser) Error!Result {
6378 if (try lhs.adjustTypes(tok, &rhs, p, .integer)) {6549 if (try lhs.adjustTypes(tok, &rhs, p, .integer)) {
6379 lhs.val = try lhs.val.bitXor(rhs.val, p.comp);6550 lhs.val = try lhs.val.bitXor(rhs.val, p.comp);
6380 }6551 }
6381 try lhs.bin(p, .bit_xor_expr, rhs);6552 try lhs.bin(p, .bit_xor_expr, rhs, tok);
6382 }6553 }
6383 return lhs;6554 return lhs;
6384}6555}
...@@ -6394,7 +6565,7 @@ fn andExpr(p: *Parser) Error!Result {...@@ -6394,7 +6565,7 @@ fn andExpr(p: *Parser) Error!Result {
6394 if (try lhs.adjustTypes(tok, &rhs, p, .integer)) {6565 if (try lhs.adjustTypes(tok, &rhs, p, .integer)) {
6395 lhs.val = try lhs.val.bitAnd(rhs.val, p.comp);6566 lhs.val = try lhs.val.bitAnd(rhs.val, p.comp);
6396 }6567 }
6397 try lhs.bin(p, .bit_and_expr, rhs);6568 try lhs.bin(p, .bit_and_expr, rhs, tok);
6398 }6569 }
6399 return lhs;6570 return lhs;
6400}6571}
...@@ -6414,8 +6585,10 @@ fn eqExpr(p: *Parser) Error!Result {...@@ -6414,8 +6585,10 @@ fn eqExpr(p: *Parser) Error!Result {
6414 const op: std.math.CompareOperator = if (tag == .equal_expr) .eq else .neq;6585 const op: std.math.CompareOperator = if (tag == .equal_expr) .eq else .neq;
6415 const res = lhs.val.compare(op, rhs.val, p.comp);6586 const res = lhs.val.compare(op, rhs.val, p.comp);
6416 lhs.val = Value.fromBool(res);6587 lhs.val = Value.fromBool(res);
6588 } else {
6589 lhs.val.boolCast(p.comp);
6417 }6590 }
6418 try lhs.boolRes(p, tag, rhs);6591 try lhs.boolRes(p, tag, rhs, ne.?);
6419 }6592 }
6420 return lhs;6593 return lhs;
6421}6594}
...@@ -6443,8 +6616,10 @@ fn compExpr(p: *Parser) Error!Result {...@@ -6443,8 +6616,10 @@ fn compExpr(p: *Parser) Error!Result {
6443 };6616 };
6444 const res = lhs.val.compare(op, rhs.val, p.comp);6617 const res = lhs.val.compare(op, rhs.val, p.comp);
6445 lhs.val = Value.fromBool(res);6618 lhs.val = Value.fromBool(res);
6619 } else {
6620 lhs.val.boolCast(p.comp);
6446 }6621 }
6447 try lhs.boolRes(p, tag, rhs);6622 try lhs.boolRes(p, tag, rhs, ge.?);
6448 }6623 }
6449 return lhs;6624 return lhs;
6450}6625}
...@@ -6474,7 +6649,7 @@ fn shiftExpr(p: *Parser) Error!Result {...@@ -6474,7 +6649,7 @@ fn shiftExpr(p: *Parser) Error!Result {
6474 lhs.val = try lhs.val.shr(rhs.val, lhs.ty, p.comp);6649 lhs.val = try lhs.val.shr(rhs.val, lhs.ty, p.comp);
6475 }6650 }
6476 }6651 }
6477 try lhs.bin(p, tag, rhs);6652 try lhs.bin(p, tag, rhs, shr.?);
6478 }6653 }
6479 return lhs;6654 return lhs;
6480}6655}
...@@ -6504,7 +6679,7 @@ fn addExpr(p: *Parser) Error!Result {...@@ -6504,7 +6679,7 @@ fn addExpr(p: *Parser) Error!Result {
6504 try p.errStr(.ptr_arithmetic_incomplete, minus.?, try p.typeStr(lhs_ty.elemType()));6679 try p.errStr(.ptr_arithmetic_incomplete, minus.?, try p.typeStr(lhs_ty.elemType()));
6505 lhs.ty = Type.invalid;6680 lhs.ty = Type.invalid;
6506 }6681 }
6507 try lhs.bin(p, tag, rhs);6682 try lhs.bin(p, tag, rhs, minus.?);
6508 }6683 }
6509 return lhs;6684 return lhs;
6510}6685}
...@@ -6538,7 +6713,7 @@ fn mulExpr(p: *Parser) Error!Result {...@@ -6538,7 +6713,7 @@ fn mulExpr(p: *Parser) Error!Result {
6538 lhs.ty.signedness(p.comp) != .unsigned) try p.errOverflow(mul.?, lhs);6713 lhs.ty.signedness(p.comp) != .unsigned) try p.errOverflow(mul.?, lhs);
6539 } else if (div != null) {6714 } else if (div != null) {
6540 if (try lhs.val.div(lhs.val, rhs.val, lhs.ty, p.comp) and6715 if (try lhs.val.div(lhs.val, rhs.val, lhs.ty, p.comp) and
6541 lhs.ty.signedness(p.comp) != .unsigned) try p.errOverflow(mul.?, lhs);6716 lhs.ty.signedness(p.comp) != .unsigned) try p.errOverflow(div.?, lhs);
6542 } else {6717 } else {
6543 var res = try Value.rem(lhs.val, rhs.val, lhs.ty, p.comp);6718 var res = try Value.rem(lhs.val, rhs.val, lhs.ty, p.comp);
6544 if (res.opt_ref == .none) {6719 if (res.opt_ref == .none) {
...@@ -6554,7 +6729,7 @@ fn mulExpr(p: *Parser) Error!Result {...@@ -6554,7 +6729,7 @@ fn mulExpr(p: *Parser) Error!Result {
6554 }6729 }
6555 }6730 }
65566731
6557 try lhs.bin(p, tag, rhs);6732 try lhs.bin(p, tag, rhs, percent.?);
6558 }6733 }
6559 return lhs;6734 return lhs;
6560}6735}
...@@ -6573,7 +6748,7 @@ fn removeUnusedWarningForTok(p: *Parser, last_expr_tok: TokenIndex) void {...@@ -6573,7 +6748,7 @@ fn removeUnusedWarningForTok(p: *Parser, last_expr_tok: TokenIndex) void {
6573}6748}
65746749
6575/// castExpr6750/// castExpr
6576/// : '(' compoundStmt ')'6751/// : '(' compoundStmt ')' suffixExpr*
6577/// | '(' typeName ')' castExpr6752/// | '(' typeName ')' castExpr
6578/// | '(' typeName ')' '{' initializerItems '}'6753/// | '(' typeName ')' '{' initializerItems '}'
6579/// | __builtin_choose_expr '(' integerConstExpr ',' assignExpr ',' assignExpr ')'6754/// | __builtin_choose_expr '(' integerConstExpr ',' assignExpr ',' assignExpr ')'
...@@ -6584,6 +6759,7 @@ fn removeUnusedWarningForTok(p: *Parser, last_expr_tok: TokenIndex) void {...@@ -6584,6 +6759,7 @@ fn removeUnusedWarningForTok(p: *Parser, last_expr_tok: TokenIndex) void {
6584fn castExpr(p: *Parser) Error!Result {6759fn castExpr(p: *Parser) Error!Result {
6585 if (p.eatToken(.l_paren)) |l_paren| cast_expr: {6760 if (p.eatToken(.l_paren)) |l_paren| cast_expr: {
6586 if (p.tok_ids[p.tok_i] == .l_brace) {6761 if (p.tok_ids[p.tok_i] == .l_brace) {
6762 const tok = p.tok_i;
6587 try p.err(.gnu_statement_expression);6763 try p.err(.gnu_statement_expression);
6588 if (p.func.ty == null) {6764 if (p.func.ty == null) {
6589 try p.err(.stmt_expr_not_allowed_file_scope);6765 try p.err(.stmt_expr_not_allowed_file_scope);
...@@ -6599,7 +6775,12 @@ fn castExpr(p: *Parser) Error!Result {...@@ -6599,7 +6775,12 @@ fn castExpr(p: *Parser) Error!Result {
6599 .val = stmt_expr_state.last_expr_res.val,6775 .val = stmt_expr_state.last_expr_res.val,
6600 };6776 };
6601 try p.expectClosing(l_paren, .r_paren);6777 try p.expectClosing(l_paren, .r_paren);
6602 try res.un(p, .stmt_expr);6778 try res.un(p, .stmt_expr, tok);
6779 while (true) {
6780 const suffix = try p.suffixExpr(res);
6781 if (suffix.empty(p)) break;
6782 res = suffix;
6783 }
6603 return res;6784 return res;
6604 }6785 }
6605 const ty = (try p.typeName()) orelse {6786 const ty = (try p.typeName()) orelse {
...@@ -6634,23 +6815,26 @@ fn castExpr(p: *Parser) Error!Result {...@@ -6634,23 +6815,26 @@ fn castExpr(p: *Parser) Error!Result {
6634}6815}
66356816
6636fn typesCompatible(p: *Parser) Error!Result {6817fn typesCompatible(p: *Parser) Error!Result {
6818 const builtin_tok = p.tok_i;
6637 p.tok_i += 1;6819 p.tok_i += 1;
6638 const l_paren = try p.expectToken(.l_paren);6820 const l_paren = try p.expectToken(.l_paren);
66396821
6822 const first_tok = p.tok_i;
6640 const first = (try p.typeName()) orelse {6823 const first = (try p.typeName()) orelse {
6641 try p.err(.expected_type);6824 try p.err(.expected_type);
6642 p.skipTo(.r_paren);6825 p.skipTo(.r_paren);
6643 return error.ParsingFailed;6826 return error.ParsingFailed;
6644 };6827 };
6645 const lhs = try p.addNode(.{ .tag = .invalid, .ty = first, .data = undefined });6828 const lhs = try p.addNode(.{ .tag = .invalid, .ty = first, .data = undefined, .loc = @enumFromInt(first_tok) });
6646 _ = try p.expectToken(.comma);6829 _ = try p.expectToken(.comma);
66476830
6831 const second_tok = p.tok_i;
6648 const second = (try p.typeName()) orelse {6832 const second = (try p.typeName()) orelse {
6649 try p.err(.expected_type);6833 try p.err(.expected_type);
6650 p.skipTo(.r_paren);6834 p.skipTo(.r_paren);
6651 return error.ParsingFailed;6835 return error.ParsingFailed;
6652 };6836 };
6653 const rhs = try p.addNode(.{ .tag = .invalid, .ty = second, .data = undefined });6837 const rhs = try p.addNode(.{ .tag = .invalid, .ty = second, .data = undefined, .loc = @enumFromInt(second_tok) });
66546838
6655 try p.expectClosing(l_paren, .r_paren);6839 try p.expectClosing(l_paren, .r_paren);
66566840
...@@ -6665,10 +6849,15 @@ fn typesCompatible(p: *Parser) Error!Result {...@@ -6665,10 +6849,15 @@ fn typesCompatible(p: *Parser) Error!Result {
66656849
6666 const res = Result{6850 const res = Result{
6667 .val = Value.fromBool(compatible),6851 .val = Value.fromBool(compatible),
6668 .node = try p.addNode(.{ .tag = .builtin_types_compatible_p, .ty = Type.int, .data = .{ .bin = .{6852 .node = try p.addNode(.{
6669 .lhs = lhs,6853 .tag = .builtin_types_compatible_p,
6670 .rhs = rhs,6854 .ty = Type.int,
6671 } } }),6855 .data = .{ .bin = .{
6856 .lhs = lhs,
6857 .rhs = rhs,
6858 } },
6859 .loc = @enumFromInt(builtin_tok),
6860 }),
6672 };6861 };
6673 try p.value_map.put(res.node, res.val);6862 try p.value_map.put(res.node, res.val);
6674 return res;6863 return res;
...@@ -6786,11 +6975,11 @@ fn offsetofMemberDesignator(p: *Parser, base_ty: Type, want_bits: bool) Error!Re...@@ -6786,11 +6975,11 @@ fn offsetofMemberDesignator(p: *Parser, base_ty: Type, want_bits: bool) Error!Re
6786 errdefer p.skipTo(.r_paren);6975 errdefer p.skipTo(.r_paren);
6787 const base_field_name_tok = try p.expectIdentifier();6976 const base_field_name_tok = try p.expectIdentifier();
6788 const base_field_name = try StrInt.intern(p.comp, p.tokSlice(base_field_name_tok));6977 const base_field_name = try StrInt.intern(p.comp, p.tokSlice(base_field_name_tok));
6789 try p.validateFieldAccess(base_ty, base_ty, base_field_name_tok, base_field_name);6978 const base_record_ty = base_ty.getRecord().?;
6979 try p.validateFieldAccess(base_record_ty, base_ty, base_field_name_tok, base_field_name);
6790 const base_node = try p.addNode(.{ .tag = .default_init_expr, .ty = base_ty, .data = undefined });6980 const base_node = try p.addNode(.{ .tag = .default_init_expr, .ty = base_ty, .data = undefined });
67916981
6792 var cur_offset: u64 = 0;6982 var cur_offset: u64 = 0;
6793 const base_record_ty = base_ty.canonicalize(.standard);
6794 var lhs = try p.fieldAccessExtra(base_node, base_record_ty, base_field_name, false, &cur_offset);6983 var lhs = try p.fieldAccessExtra(base_node, base_record_ty, base_field_name, false, &cur_offset);
67956984
6796 var total_offset = cur_offset;6985 var total_offset = cur_offset;
...@@ -6800,13 +6989,12 @@ fn offsetofMemberDesignator(p: *Parser, base_ty: Type, want_bits: bool) Error!Re...@@ -6800,13 +6989,12 @@ fn offsetofMemberDesignator(p: *Parser, base_ty: Type, want_bits: bool) Error!Re
6800 const field_name_tok = try p.expectIdentifier();6989 const field_name_tok = try p.expectIdentifier();
6801 const field_name = try StrInt.intern(p.comp, p.tokSlice(field_name_tok));6990 const field_name = try StrInt.intern(p.comp, p.tokSlice(field_name_tok));
68026991
6803 if (!lhs.ty.isRecord()) {6992 const lhs_record_ty = lhs.ty.getRecord() orelse {
6804 try p.errStr(.offsetof_ty, field_name_tok, try p.typeStr(lhs.ty));6993 try p.errStr(.offsetof_ty, field_name_tok, try p.typeStr(lhs.ty));
6805 return error.ParsingFailed;6994 return error.ParsingFailed;
6806 }6995 };
6807 try p.validateFieldAccess(lhs.ty, lhs.ty, field_name_tok, field_name);6996 try p.validateFieldAccess(lhs_record_ty, lhs.ty, field_name_tok, field_name);
6808 const record_ty = lhs.ty.canonicalize(.standard);6997 lhs = try p.fieldAccessExtra(lhs.node, lhs_record_ty, field_name, false, &cur_offset);
6809 lhs = try p.fieldAccessExtra(lhs.node, record_ty, field_name, false, &cur_offset);
6810 total_offset += cur_offset;6998 total_offset += cur_offset;
6811 },6999 },
6812 .l_bracket => {7000 .l_bracket => {
...@@ -6824,11 +7012,14 @@ fn offsetofMemberDesignator(p: *Parser, base_ty: Type, want_bits: bool) Error!Re...@@ -6824,11 +7012,14 @@ fn offsetofMemberDesignator(p: *Parser, base_ty: Type, want_bits: bool) Error!Re
6824 try ptr.lvalConversion(p);7012 try ptr.lvalConversion(p);
6825 try index.lvalConversion(p);7013 try index.lvalConversion(p);
68267014
6827 if (!index.ty.isInt()) try p.errTok(.invalid_index, l_bracket_tok);7015 if (index.ty.isInt()) {
6828 try p.checkArrayBounds(index, lhs, l_bracket_tok);7016 try p.checkArrayBounds(index, lhs, l_bracket_tok);
7017 } else {
7018 try p.errTok(.invalid_index, l_bracket_tok);
7019 }
68297020
6830 try index.saveValue(p);7021 try index.saveValue(p);
6831 try ptr.bin(p, .array_access_expr, index);7022 try ptr.bin(p, .array_access_expr, index, l_bracket_tok);
6832 lhs = ptr;7023 lhs = ptr;
6833 },7024 },
6834 else => break,7025 else => break,
...@@ -6867,6 +7058,7 @@ fn unExpr(p: *Parser) Error!Result {...@@ -6867,6 +7058,7 @@ fn unExpr(p: *Parser) Error!Result {
6867 .tag = .addr_of_label,7058 .tag = .addr_of_label,
6868 .data = .{ .decl_ref = name_tok },7059 .data = .{ .decl_ref = name_tok },
6869 .ty = result_ty,7060 .ty = result_ty,
7061 .loc = @enumFromInt(address_tok),
6870 }),7062 }),
6871 .ty = result_ty,7063 .ty = result_ty,
6872 };7064 };
...@@ -6886,19 +7078,21 @@ fn unExpr(p: *Parser) Error!Result {...@@ -6886,19 +7078,21 @@ fn unExpr(p: *Parser) Error!Result {
6886 {7078 {
6887 if (tree.isBitfield(member_node)) try p.errTok(.addr_of_bitfield, tok);7079 if (tree.isBitfield(member_node)) try p.errTok(.addr_of_bitfield, tok);
6888 }7080 }
6889 if (!tree.isLval(operand.node)) {7081 if (!tree.isLval(operand.node) and !operand.ty.is(.invalid)) {
6890 try p.errTok(.addr_of_rvalue, tok);7082 try p.errTok(.addr_of_rvalue, tok);
6891 }7083 }
6892 if (operand.ty.qual.register) try p.errTok(.addr_of_register, tok);7084 if (operand.ty.qual.register) try p.errTok(.addr_of_register, tok);
68937085
6894 const elem_ty = try p.arena.create(Type);7086 if (!operand.ty.is(.invalid)) {
6895 elem_ty.* = operand.ty;7087 const elem_ty = try p.arena.create(Type);
6896 operand.ty = Type{7088 elem_ty.* = operand.ty;
6897 .specifier = .pointer,7089 operand.ty = Type{
6898 .data = .{ .sub_type = elem_ty },7090 .specifier = .pointer,
6899 };7091 .data = .{ .sub_type = elem_ty },
7092 };
7093 }
6900 try operand.saveValue(p);7094 try operand.saveValue(p);
6901 try operand.un(p, .addr_of_expr);7095 try operand.un(p, .addr_of_expr, tok);
6902 return operand;7096 return operand;
6903 },7097 },
6904 .asterisk => {7098 .asterisk => {
...@@ -6917,7 +7111,7 @@ fn unExpr(p: *Parser) Error!Result {...@@ -6917,7 +7111,7 @@ fn unExpr(p: *Parser) Error!Result {
6917 try p.errStr(.deref_incomplete_ty_ptr, asterisk_loc, try p.typeStr(operand.ty));7111 try p.errStr(.deref_incomplete_ty_ptr, asterisk_loc, try p.typeStr(operand.ty));
6918 }7112 }
6919 operand.ty.qual = .{};7113 operand.ty.qual = .{};
6920 try operand.un(p, .deref_expr);7114 try operand.un(p, .deref_expr, tok);
6921 return operand;7115 return operand;
6922 },7116 },
6923 .plus => {7117 .plus => {
...@@ -6943,12 +7137,12 @@ fn unExpr(p: *Parser) Error!Result {...@@ -6943,12 +7137,12 @@ fn unExpr(p: *Parser) Error!Result {
6943 try p.errStr(.invalid_argument_un, tok, try p.typeStr(operand.ty));7137 try p.errStr(.invalid_argument_un, tok, try p.typeStr(operand.ty));
69447138
6945 try operand.usualUnaryConversion(p, tok);7139 try operand.usualUnaryConversion(p, tok);
6946 if (operand.val.is(.int, p.comp) or operand.val.is(.float, p.comp)) {7140 if (operand.val.isArithmetic(p.comp)) {
6947 _ = try operand.val.sub(Value.zero, operand.val, operand.ty, p.comp);7141 _ = try operand.val.sub(Value.zero, operand.val, operand.ty, p.comp);
6948 } else {7142 } else {
6949 operand.val = .{};7143 operand.val = .{};
6950 }7144 }
6951 try operand.un(p, .negate_expr);7145 try operand.un(p, .negate_expr, tok);
6952 return operand;7146 return operand;
6953 },7147 },
6954 .plus_plus => {7148 .plus_plus => {
...@@ -6974,7 +7168,7 @@ fn unExpr(p: *Parser) Error!Result {...@@ -6974,7 +7168,7 @@ fn unExpr(p: *Parser) Error!Result {
6974 operand.val = .{};7168 operand.val = .{};
6975 }7169 }
69767170
6977 try operand.un(p, .pre_inc_expr);7171 try operand.un(p, .pre_inc_expr, tok);
6978 return operand;7172 return operand;
6979 },7173 },
6980 .minus_minus => {7174 .minus_minus => {
...@@ -7000,7 +7194,7 @@ fn unExpr(p: *Parser) Error!Result {...@@ -7000,7 +7194,7 @@ fn unExpr(p: *Parser) Error!Result {
7000 operand.val = .{};7194 operand.val = .{};
7001 }7195 }
70027196
7003 try operand.un(p, .pre_dec_expr);7197 try operand.un(p, .pre_dec_expr, tok);
7004 return operand;7198 return operand;
7005 },7199 },
7006 .tilde => {7200 .tilde => {
...@@ -7016,11 +7210,14 @@ fn unExpr(p: *Parser) Error!Result {...@@ -7016,11 +7210,14 @@ fn unExpr(p: *Parser) Error!Result {
7016 }7210 }
7017 } else if (operand.ty.isComplex()) {7211 } else if (operand.ty.isComplex()) {
7018 try p.errStr(.complex_conj, tok, try p.typeStr(operand.ty));7212 try p.errStr(.complex_conj, tok, try p.typeStr(operand.ty));
7213 if (operand.val.is(.complex, p.comp)) {
7214 operand.val = try operand.val.complexConj(operand.ty, p.comp);
7215 }
7019 } else {7216 } else {
7020 try p.errStr(.invalid_argument_un, tok, try p.typeStr(operand.ty));7217 try p.errStr(.invalid_argument_un, tok, try p.typeStr(operand.ty));
7021 operand.val = .{};7218 operand.val = .{};
7022 }7219 }
7023 try operand.un(p, .bit_not_expr);7220 try operand.un(p, .bit_not_expr, tok);
7024 return operand;7221 return operand;
7025 },7222 },
7026 .bang => {7223 .bang => {
...@@ -7045,7 +7242,7 @@ fn unExpr(p: *Parser) Error!Result {...@@ -7045,7 +7242,7 @@ fn unExpr(p: *Parser) Error!Result {
7045 }7242 }
7046 }7243 }
7047 operand.ty = .{ .specifier = .int };7244 operand.ty = .{ .specifier = .int };
7048 try operand.un(p, .bool_not_expr);7245 try operand.un(p, .bool_not_expr, tok);
7049 return operand;7246 return operand;
7050 },7247 },
7051 .keyword_sizeof => {7248 .keyword_sizeof => {
...@@ -7089,7 +7286,7 @@ fn unExpr(p: *Parser) Error!Result {...@@ -7089,7 +7286,7 @@ fn unExpr(p: *Parser) Error!Result {
7089 res.ty = p.comp.types.size;7286 res.ty = p.comp.types.size;
7090 }7287 }
7091 }7288 }
7092 try res.un(p, .sizeof_expr);7289 try res.un(p, .sizeof_expr, tok);
7093 return res;7290 return res;
7094 },7291 },
7095 .keyword_alignof,7292 .keyword_alignof,
...@@ -7127,7 +7324,7 @@ fn unExpr(p: *Parser) Error!Result {...@@ -7127,7 +7324,7 @@ fn unExpr(p: *Parser) Error!Result {
7127 try p.errStr(.invalid_alignof, expected_paren, try p.typeStr(res.ty));7324 try p.errStr(.invalid_alignof, expected_paren, try p.typeStr(res.ty));
7128 res.ty = Type.invalid;7325 res.ty = Type.invalid;
7129 }7326 }
7130 try res.un(p, .alignof_expr);7327 try res.un(p, .alignof_expr, tok);
7131 return res;7328 return res;
7132 },7329 },
7133 .keyword_extension => {7330 .keyword_extension => {
...@@ -7147,15 +7344,18 @@ fn unExpr(p: *Parser) Error!Result {...@@ -7147,15 +7344,18 @@ fn unExpr(p: *Parser) Error!Result {
7147 var operand = try p.castExpr();7344 var operand = try p.castExpr();
7148 try operand.expect(p);7345 try operand.expect(p);
7149 try operand.lvalConversion(p);7346 try operand.lvalConversion(p);
7347 if (operand.ty.is(.invalid)) return Result.invalid;
7150 if (!operand.ty.isInt() and !operand.ty.isFloat()) {7348 if (!operand.ty.isInt() and !operand.ty.isFloat()) {
7151 try p.errStr(.invalid_imag, imag_tok, try p.typeStr(operand.ty));7349 try p.errStr(.invalid_imag, imag_tok, try p.typeStr(operand.ty));
7152 }7350 }
7153 if (operand.ty.isReal()) {7351 if (operand.ty.isComplex()) {
7352 operand.val = try operand.val.imaginaryPart(p.comp);
7353 } else if (operand.ty.isReal()) {
7154 switch (p.comp.langopts.emulate) {7354 switch (p.comp.langopts.emulate) {
7155 .msvc => {}, // Doesn't support `_Complex` or `__imag` in the first place7355 .msvc => {}, // Doesn't support `_Complex` or `__imag` in the first place
7156 .gcc => operand.val = Value.zero,7356 .gcc => operand.val = Value.zero,
7157 .clang => {7357 .clang => {
7158 if (operand.val.is(.int, p.comp)) {7358 if (operand.val.is(.int, p.comp) or operand.val.is(.float, p.comp)) {
7159 operand.val = Value.zero;7359 operand.val = Value.zero;
7160 } else {7360 } else {
7161 operand.val = .{};7361 operand.val = .{};
...@@ -7165,7 +7365,7 @@ fn unExpr(p: *Parser) Error!Result {...@@ -7165,7 +7365,7 @@ fn unExpr(p: *Parser) Error!Result {
7165 }7365 }
7166 // convert _Complex T to T7366 // convert _Complex T to T
7167 operand.ty = operand.ty.makeReal();7367 operand.ty = operand.ty.makeReal();
7168 try operand.un(p, .imag_expr);7368 try operand.un(p, .imag_expr, tok);
7169 return operand;7369 return operand;
7170 },7370 },
7171 .keyword_real1, .keyword_real2 => {7371 .keyword_real1, .keyword_real2 => {
...@@ -7175,12 +7375,14 @@ fn unExpr(p: *Parser) Error!Result {...@@ -7175,12 +7375,14 @@ fn unExpr(p: *Parser) Error!Result {
7175 var operand = try p.castExpr();7375 var operand = try p.castExpr();
7176 try operand.expect(p);7376 try operand.expect(p);
7177 try operand.lvalConversion(p);7377 try operand.lvalConversion(p);
7378 if (operand.ty.is(.invalid)) return Result.invalid;
7178 if (!operand.ty.isInt() and !operand.ty.isFloat()) {7379 if (!operand.ty.isInt() and !operand.ty.isFloat()) {
7179 try p.errStr(.invalid_real, real_tok, try p.typeStr(operand.ty));7380 try p.errStr(.invalid_real, real_tok, try p.typeStr(operand.ty));
7180 }7381 }
7181 // convert _Complex T to T7382 // convert _Complex T to T
7182 operand.ty = operand.ty.makeReal();7383 operand.ty = operand.ty.makeReal();
7183 try operand.un(p, .real_expr);7384 operand.val = try operand.val.realPart(p.comp);
7385 try operand.un(p, .real_expr, tok);
7184 return operand;7386 return operand;
7185 },7387 },
7186 else => {7388 else => {
...@@ -7253,7 +7455,7 @@ fn compoundLiteral(p: *Parser) Error!Result {...@@ -7253,7 +7455,7 @@ fn compoundLiteral(p: *Parser) Error!Result {
7253 if (d.constexpr) |_| {7455 if (d.constexpr) |_| {
7254 // TODO error if not constexpr7456 // TODO error if not constexpr
7255 }7457 }
7256 try init_list_expr.un(p, tag);7458 try init_list_expr.un(p, tag, l_paren);
7257 return init_list_expr;7459 return init_list_expr;
7258}7460}
72597461
...@@ -7284,7 +7486,7 @@ fn suffixExpr(p: *Parser, lhs: Result) Error!Result {...@@ -7284,7 +7486,7 @@ fn suffixExpr(p: *Parser, lhs: Result) Error!Result {
7284 }7486 }
7285 try operand.usualUnaryConversion(p, p.tok_i);7487 try operand.usualUnaryConversion(p, p.tok_i);
72867488
7287 try operand.un(p, .post_inc_expr);7489 try operand.un(p, .post_inc_expr, p.tok_i);
7288 return operand;7490 return operand;
7289 },7491 },
7290 .minus_minus => {7492 .minus_minus => {
...@@ -7302,7 +7504,7 @@ fn suffixExpr(p: *Parser, lhs: Result) Error!Result {...@@ -7302,7 +7504,7 @@ fn suffixExpr(p: *Parser, lhs: Result) Error!Result {
7302 }7504 }
7303 try operand.usualUnaryConversion(p, p.tok_i);7505 try operand.usualUnaryConversion(p, p.tok_i);
73047506
7305 try operand.un(p, .post_dec_expr);7507 try operand.un(p, .post_dec_expr, p.tok_i);
7306 return operand;7508 return operand;
7307 },7509 },
7308 .l_bracket => {7510 .l_bracket => {
...@@ -7319,12 +7521,18 @@ fn suffixExpr(p: *Parser, lhs: Result) Error!Result {...@@ -7319,12 +7521,18 @@ fn suffixExpr(p: *Parser, lhs: Result) Error!Result {
7319 try index.lvalConversion(p);7521 try index.lvalConversion(p);
7320 if (ptr.ty.isPtr()) {7522 if (ptr.ty.isPtr()) {
7321 ptr.ty = ptr.ty.elemType();7523 ptr.ty = ptr.ty.elemType();
7322 if (!index.ty.isInt()) try p.errTok(.invalid_index, l_bracket);7524 if (index.ty.isInt()) {
7323 try p.checkArrayBounds(index_before_conversion, array_before_conversion, l_bracket);7525 try p.checkArrayBounds(index_before_conversion, array_before_conversion, l_bracket);
7526 } else {
7527 try p.errTok(.invalid_index, l_bracket);
7528 }
7324 } else if (index.ty.isPtr()) {7529 } else if (index.ty.isPtr()) {
7325 index.ty = index.ty.elemType();7530 index.ty = index.ty.elemType();
7326 if (!ptr.ty.isInt()) try p.errTok(.invalid_index, l_bracket);7531 if (ptr.ty.isInt()) {
7327 try p.checkArrayBounds(array_before_conversion, index_before_conversion, l_bracket);7532 try p.checkArrayBounds(array_before_conversion, index_before_conversion, l_bracket);
7533 } else {
7534 try p.errTok(.invalid_index, l_bracket);
7535 }
7328 std.mem.swap(Result, &ptr, &index);7536 std.mem.swap(Result, &ptr, &index);
7329 } else {7537 } else {
7330 try p.errTok(.invalid_subscript, l_bracket);7538 try p.errTok(.invalid_subscript, l_bracket);
...@@ -7332,7 +7540,7 @@ fn suffixExpr(p: *Parser, lhs: Result) Error!Result {...@@ -7332,7 +7540,7 @@ fn suffixExpr(p: *Parser, lhs: Result) Error!Result {
73327540
7333 try ptr.saveValue(p);7541 try ptr.saveValue(p);
7334 try index.saveValue(p);7542 try index.saveValue(p);
7335 try ptr.bin(p, .array_access_expr, index);7543 try ptr.bin(p, .array_access_expr, index, l_bracket);
7336 return ptr;7544 return ptr;
7337 },7545 },
7338 .period => {7546 .period => {
...@@ -7364,16 +7572,12 @@ fn fieldAccess(...@@ -7364,16 +7572,12 @@ fn fieldAccess(
7364 const expr_ty = lhs.ty;7572 const expr_ty = lhs.ty;
7365 const is_ptr = expr_ty.isPtr();7573 const is_ptr = expr_ty.isPtr();
7366 const expr_base_ty = if (is_ptr) expr_ty.elemType() else expr_ty;7574 const expr_base_ty = if (is_ptr) expr_ty.elemType() else expr_ty;
7367 const record_ty = expr_base_ty.canonicalize(.standard);7575 const record_ty = expr_base_ty.getRecord() orelse {
7576 try p.errStr(.expected_record_ty, field_name_tok, try p.typeStr(expr_ty));
7577 return error.ParsingFailed;
7578 };
73687579
7369 switch (record_ty.specifier) {7580 if (record_ty.isIncomplete()) {
7370 .@"struct", .@"union" => {},
7371 else => {
7372 try p.errStr(.expected_record_ty, field_name_tok, try p.typeStr(expr_ty));
7373 return error.ParsingFailed;
7374 },
7375 }
7376 if (record_ty.hasIncompleteSize()) {
7377 try p.errStr(.deref_incomplete_ty_ptr, field_name_tok - 2, try p.typeStr(expr_base_ty));7581 try p.errStr(.deref_incomplete_ty_ptr, field_name_tok - 2, try p.typeStr(expr_base_ty));
7378 return error.ParsingFailed;7582 return error.ParsingFailed;
7379 }7583 }
...@@ -7386,7 +7590,7 @@ fn fieldAccess(...@@ -7386,7 +7590,7 @@ fn fieldAccess(
7386 return p.fieldAccessExtra(lhs.node, record_ty, field_name, is_arrow, &discard);7590 return p.fieldAccessExtra(lhs.node, record_ty, field_name, is_arrow, &discard);
7387}7591}
73887592
7389fn validateFieldAccess(p: *Parser, record_ty: Type, expr_ty: Type, field_name_tok: TokenIndex, field_name: StringId) Error!void {7593fn validateFieldAccess(p: *Parser, record_ty: *const Type.Record, expr_ty: Type, field_name_tok: TokenIndex, field_name: StringId) Error!void {
7390 if (record_ty.hasField(field_name)) return;7594 if (record_ty.hasField(field_name)) return;
73917595
7392 p.strings.items.len = 0;7596 p.strings.items.len = 0;
...@@ -7401,8 +7605,8 @@ fn validateFieldAccess(p: *Parser, record_ty: Type, expr_ty: Type, field_name_to...@@ -7401,8 +7605,8 @@ fn validateFieldAccess(p: *Parser, record_ty: Type, expr_ty: Type, field_name_to
7401 return error.ParsingFailed;7605 return error.ParsingFailed;
7402}7606}
74037607
7404fn fieldAccessExtra(p: *Parser, lhs: NodeIndex, record_ty: Type, field_name: StringId, is_arrow: bool, offset_bits: *u64) Error!Result {7608fn fieldAccessExtra(p: *Parser, lhs: NodeIndex, record_ty: *const Type.Record, field_name: StringId, is_arrow: bool, offset_bits: *u64) Error!Result {
7405 for (record_ty.data.record.fields, 0..) |f, i| {7609 for (record_ty.fields, 0..) |f, i| {
7406 if (f.isAnonymousRecord()) {7610 if (f.isAnonymousRecord()) {
7407 if (!f.ty.hasField(field_name)) continue;7611 if (!f.ty.hasField(field_name)) continue;
7408 const inner = try p.addNode(.{7612 const inner = try p.addNode(.{
...@@ -7410,7 +7614,7 @@ fn fieldAccessExtra(p: *Parser, lhs: NodeIndex, record_ty: Type, field_name: Str...@@ -7410,7 +7614,7 @@ fn fieldAccessExtra(p: *Parser, lhs: NodeIndex, record_ty: Type, field_name: Str
7410 .ty = f.ty,7614 .ty = f.ty,
7411 .data = .{ .member = .{ .lhs = lhs, .index = @intCast(i) } },7615 .data = .{ .member = .{ .lhs = lhs, .index = @intCast(i) } },
7412 });7616 });
7413 const ret = p.fieldAccessExtra(inner, f.ty, field_name, false, offset_bits);7617 const ret = p.fieldAccessExtra(inner, f.ty.getRecord().?, field_name, false, offset_bits);
7414 offset_bits.* = f.layout.offset_bits;7618 offset_bits.* = f.layout.offset_bits;
7415 return ret;7619 return ret;
7416 }7620 }
...@@ -7527,6 +7731,23 @@ fn callExpr(p: *Parser, lhs: Result) Error!Result {...@@ -7527,6 +7731,23 @@ fn callExpr(p: *Parser, lhs: Result) Error!Result {
7527 continue;7731 continue;
7528 }7732 }
7529 const p_ty = params[arg_count].ty;7733 const p_ty = params[arg_count].ty;
7734 if (p_ty.specifier == .static_array) {
7735 const arg_array_len: u64 = arg.ty.arrayLen() orelse std.math.maxInt(u64);
7736 const param_array_len: u64 = p_ty.arrayLen().?;
7737 if (arg_array_len < param_array_len) {
7738 const extra = Diagnostics.Message.Extra{ .arguments = .{
7739 .expected = @intCast(arg_array_len),
7740 .actual = @intCast(param_array_len),
7741 } };
7742 try p.errExtra(.array_argument_too_small, param_tok, extra);
7743 try p.errTok(.callee_with_static_array, params[arg_count].name_tok);
7744 }
7745 if (arg.val.isZero(p.comp)) {
7746 try p.errTok(.non_null_argument, param_tok);
7747 try p.errTok(.callee_with_static_array, params[arg_count].name_tok);
7748 }
7749 }
7750
7530 if (call_expr.shouldCoerceArg(arg_count)) {7751 if (call_expr.shouldCoerceArg(arg_count)) {
7531 try arg.coerce(p, p_ty, param_tok, .{ .arg = params[arg_count].name_tok });7752 try arg.coerce(p, p_ty, param_tok, .{ .arg = params[arg_count].name_tok });
7532 }7753 }
...@@ -7618,7 +7839,7 @@ fn primaryExpr(p: *Parser) Error!Result {...@@ -7618,7 +7839,7 @@ fn primaryExpr(p: *Parser) Error!Result {
7618 var e = try p.expr();7839 var e = try p.expr();
7619 try e.expect(p);7840 try e.expect(p);
7620 try p.expectClosing(l_paren, .r_paren);7841 try p.expectClosing(l_paren, .r_paren);
7621 try e.un(p, .paren_expr);7842 try e.un(p, .paren_expr, l_paren);
7622 return e;7843 return e;
7623 }7844 }
7624 switch (p.tok_ids[p.tok_i]) {7845 switch (p.tok_ids[p.tok_i]) {
...@@ -7626,6 +7847,10 @@ fn primaryExpr(p: *Parser) Error!Result {...@@ -7626,6 +7847,10 @@ fn primaryExpr(p: *Parser) Error!Result {
7626 const name_tok = try p.expectIdentifier();7847 const name_tok = try p.expectIdentifier();
7627 const name = p.tokSlice(name_tok);7848 const name = p.tokSlice(name_tok);
7628 const interned_name = try StrInt.intern(p.comp, name);7849 const interned_name = try StrInt.intern(p.comp, name);
7850 if (interned_name == p.auto_type_decl_name) {
7851 try p.errStr(.auto_type_self_initialized, name_tok, name);
7852 return error.ParsingFailed;
7853 }
7629 if (p.syms.findSymbol(interned_name)) |sym| {7854 if (p.syms.findSymbol(interned_name)) |sym| {
7630 try p.checkDeprecatedUnavailable(sym.ty, name_tok, sym.tok);7855 try p.checkDeprecatedUnavailable(sym.ty, name_tok, sym.tok);
7631 if (sym.kind == .constexpr) {7856 if (sym.kind == .constexpr) {
...@@ -7636,6 +7861,7 @@ fn primaryExpr(p: *Parser) Error!Result {...@@ -7636,6 +7861,7 @@ fn primaryExpr(p: *Parser) Error!Result {
7636 .tag = .decl_ref_expr,7861 .tag = .decl_ref_expr,
7637 .ty = sym.ty,7862 .ty = sym.ty,
7638 .data = .{ .decl_ref = name_tok },7863 .data = .{ .decl_ref = name_tok },
7864 .loc = @enumFromInt(name_tok),
7639 }),7865 }),
7640 };7866 };
7641 }7867 }
...@@ -7653,6 +7879,7 @@ fn primaryExpr(p: *Parser) Error!Result {...@@ -7653,6 +7879,7 @@ fn primaryExpr(p: *Parser) Error!Result {
7653 .tag = if (sym.kind == .enumeration) .enumeration_ref else .decl_ref_expr,7879 .tag = if (sym.kind == .enumeration) .enumeration_ref else .decl_ref_expr,
7654 .ty = sym.ty,7880 .ty = sym.ty,
7655 .data = .{ .decl_ref = name_tok },7881 .data = .{ .decl_ref = name_tok },
7882 .loc = @enumFromInt(name_tok),
7656 }),7883 }),
7657 };7884 };
7658 }7885 }
...@@ -7679,6 +7906,7 @@ fn primaryExpr(p: *Parser) Error!Result {...@@ -7679,6 +7906,7 @@ fn primaryExpr(p: *Parser) Error!Result {
7679 .tag = .builtin_call_expr_one,7906 .tag = .builtin_call_expr_one,
7680 .ty = some.ty,7907 .ty = some.ty,
7681 .data = .{ .decl = .{ .name = name_tok, .node = .none } },7908 .data = .{ .decl = .{ .name = name_tok, .node = .none } },
7909 .loc = @enumFromInt(name_tok),
7682 }),7910 }),
7683 };7911 };
7684 }7912 }
...@@ -7696,6 +7924,7 @@ fn primaryExpr(p: *Parser) Error!Result {...@@ -7696,6 +7924,7 @@ fn primaryExpr(p: *Parser) Error!Result {
7696 .ty = ty,7924 .ty = ty,
7697 .tag = .fn_proto,7925 .tag = .fn_proto,
7698 .data = .{ .decl = .{ .name = name_tok } },7926 .data = .{ .decl = .{ .name = name_tok } },
7927 .loc = @enumFromInt(name_tok),
7699 });7928 });
77007929
7701 try p.decl_buf.append(node);7930 try p.decl_buf.append(node);
...@@ -7707,6 +7936,7 @@ fn primaryExpr(p: *Parser) Error!Result {...@@ -7707,6 +7936,7 @@ fn primaryExpr(p: *Parser) Error!Result {
7707 .tag = .decl_ref_expr,7936 .tag = .decl_ref_expr,
7708 .ty = ty,7937 .ty = ty,
7709 .data = .{ .decl_ref = name_tok },7938 .data = .{ .decl_ref = name_tok },
7939 .loc = @enumFromInt(name_tok),
7710 }),7940 }),
7711 };7941 };
7712 }7942 }
...@@ -7714,11 +7944,12 @@ fn primaryExpr(p: *Parser) Error!Result {...@@ -7714,11 +7944,12 @@ fn primaryExpr(p: *Parser) Error!Result {
7714 return error.ParsingFailed;7944 return error.ParsingFailed;
7715 },7945 },
7716 .keyword_true, .keyword_false => |id| {7946 .keyword_true, .keyword_false => |id| {
7947 const tok_i = p.tok_i;
7717 p.tok_i += 1;7948 p.tok_i += 1;
7718 const res = Result{7949 const res = Result{
7719 .val = Value.fromBool(id == .keyword_true),7950 .val = Value.fromBool(id == .keyword_true),
7720 .ty = .{ .specifier = .bool },7951 .ty = .{ .specifier = .bool },
7721 .node = try p.addNode(.{ .tag = .bool_literal, .ty = .{ .specifier = .bool }, .data = undefined }),7952 .node = try p.addNode(.{ .tag = .bool_literal, .ty = .{ .specifier = .bool }, .data = undefined, .loc = @enumFromInt(tok_i) }),
7722 };7953 };
7723 std.debug.assert(!p.in_macro); // Should have been replaced with .one / .zero7954 std.debug.assert(!p.in_macro); // Should have been replaced with .one / .zero
7724 try p.value_map.put(res.node, res.val);7955 try p.value_map.put(res.node, res.val);
...@@ -7734,6 +7965,7 @@ fn primaryExpr(p: *Parser) Error!Result {...@@ -7734,6 +7965,7 @@ fn primaryExpr(p: *Parser) Error!Result {
7734 .tag = .nullptr_literal,7965 .tag = .nullptr_literal,
7735 .ty = .{ .specifier = .nullptr_t },7966 .ty = .{ .specifier = .nullptr_t },
7736 .data = undefined,7967 .data = undefined,
7968 .loc = @enumFromInt(p.tok_i),
7737 }),7969 }),
7738 };7970 };
7739 },7971 },
...@@ -7770,6 +8002,7 @@ fn primaryExpr(p: *Parser) Error!Result {...@@ -7770,6 +8002,7 @@ fn primaryExpr(p: *Parser) Error!Result {
7770 .tag = .decl_ref_expr,8002 .tag = .decl_ref_expr,
7771 .ty = ty,8003 .ty = ty,
7772 .data = .{ .decl_ref = tok },8004 .data = .{ .decl_ref = tok },
8005 .loc = @enumFromInt(tok),
7773 }),8006 }),
7774 };8007 };
7775 },8008 },
...@@ -7805,6 +8038,7 @@ fn primaryExpr(p: *Parser) Error!Result {...@@ -7805,6 +8038,7 @@ fn primaryExpr(p: *Parser) Error!Result {
7805 .tag = .decl_ref_expr,8038 .tag = .decl_ref_expr,
7806 .ty = ty,8039 .ty = ty,
7807 .data = .{ .decl_ref = p.tok_i },8040 .data = .{ .decl_ref = p.tok_i },
8041 .loc = @enumFromInt(p.tok_i),
7808 }),8042 }),
7809 };8043 };
7810 },8044 },
...@@ -7824,16 +8058,16 @@ fn primaryExpr(p: *Parser) Error!Result {...@@ -7824,16 +8058,16 @@ fn primaryExpr(p: *Parser) Error!Result {
7824 .unterminated_char_literal,8058 .unterminated_char_literal,
7825 => return p.charLiteral(),8059 => return p.charLiteral(),
7826 .zero => {8060 .zero => {
7827 p.tok_i += 1;8061 defer p.tok_i += 1;
7828 var res: Result = .{ .val = Value.zero, .ty = if (p.in_macro) p.comp.types.intmax else Type.int };8062 var res: Result = .{ .val = Value.zero, .ty = if (p.in_macro) p.comp.types.intmax else Type.int };
7829 res.node = try p.addNode(.{ .tag = .int_literal, .ty = res.ty, .data = undefined });8063 res.node = try p.addNode(.{ .tag = .int_literal, .ty = res.ty, .data = undefined, .loc = @enumFromInt(p.tok_i) });
7830 if (!p.in_macro) try p.value_map.put(res.node, res.val);8064 if (!p.in_macro) try p.value_map.put(res.node, res.val);
7831 return res;8065 return res;
7832 },8066 },
7833 .one => {8067 .one => {
7834 p.tok_i += 1;8068 defer p.tok_i += 1;
7835 var res: Result = .{ .val = Value.one, .ty = if (p.in_macro) p.comp.types.intmax else Type.int };8069 var res: Result = .{ .val = Value.one, .ty = if (p.in_macro) p.comp.types.intmax else Type.int };
7836 res.node = try p.addNode(.{ .tag = .int_literal, .ty = res.ty, .data = undefined });8070 res.node = try p.addNode(.{ .tag = .int_literal, .ty = res.ty, .data = undefined, .loc = @enumFromInt(p.tok_i) });
7837 if (!p.in_macro) try p.value_map.put(res.node, res.val);8071 if (!p.in_macro) try p.value_map.put(res.node, res.val);
7838 return res;8072 return res;
7839 },8073 },
...@@ -7841,7 +8075,7 @@ fn primaryExpr(p: *Parser) Error!Result {...@@ -7841,7 +8075,7 @@ fn primaryExpr(p: *Parser) Error!Result {
7841 .embed_byte => {8075 .embed_byte => {
7842 assert(!p.in_macro);8076 assert(!p.in_macro);
7843 const loc = p.pp.tokens.items(.loc)[p.tok_i];8077 const loc = p.pp.tokens.items(.loc)[p.tok_i];
7844 p.tok_i += 1;8078 defer p.tok_i += 1;
7845 const buf = p.comp.getSource(.generated).buf[loc.byte_offset..];8079 const buf = p.comp.getSource(.generated).buf[loc.byte_offset..];
7846 var byte: u8 = buf[0] - '0';8080 var byte: u8 = buf[0] - '0';
7847 for (buf[1..]) |c| {8081 for (buf[1..]) |c| {
...@@ -7850,7 +8084,7 @@ fn primaryExpr(p: *Parser) Error!Result {...@@ -7850,7 +8084,7 @@ fn primaryExpr(p: *Parser) Error!Result {
7850 byte += c - '0';8084 byte += c - '0';
7851 }8085 }
7852 var res: Result = .{ .val = try Value.int(byte, p.comp) };8086 var res: Result = .{ .val = try Value.int(byte, p.comp) };
7853 res.node = try p.addNode(.{ .tag = .int_literal, .ty = res.ty, .data = undefined });8087 res.node = try p.addNode(.{ .tag = .int_literal, .ty = res.ty, .data = undefined, .loc = @enumFromInt(p.tok_i) });
7854 try p.value_map.put(res.node, res.val);8088 try p.value_map.put(res.node, res.val);
7855 return res;8089 return res;
7856 },8090 },
...@@ -7869,17 +8103,19 @@ fn makePredefinedIdentifier(p: *Parser, strings_top: usize) !Result {...@@ -7869,17 +8103,19 @@ fn makePredefinedIdentifier(p: *Parser, strings_top: usize) !Result {
7869 const slice = p.strings.items[strings_top..];8103 const slice = p.strings.items[strings_top..];
7870 const val = try Value.intern(p.comp, .{ .bytes = slice });8104 const val = try Value.intern(p.comp, .{ .bytes = slice });
78718105
7872 const str_lit = try p.addNode(.{ .tag = .string_literal_expr, .ty = ty, .data = undefined });8106 const str_lit = try p.addNode(.{ .tag = .string_literal_expr, .ty = ty, .data = undefined, .loc = @enumFromInt(p.tok_i) });
7873 if (!p.in_macro) try p.value_map.put(str_lit, val);8107 if (!p.in_macro) try p.value_map.put(str_lit, val);
78748108
7875 return Result{ .ty = ty, .node = try p.addNode(.{8109 return Result{ .ty = ty, .node = try p.addNode(.{
7876 .tag = .implicit_static_var,8110 .tag = .implicit_static_var,
7877 .ty = ty,8111 .ty = ty,
7878 .data = .{ .decl = .{ .name = p.tok_i, .node = str_lit } },8112 .data = .{ .decl = .{ .name = p.tok_i, .node = str_lit } },
8113 .loc = @enumFromInt(p.tok_i),
7879 }) };8114 }) };
7880}8115}
78818116
7882fn stringLiteral(p: *Parser) Error!Result {8117fn stringLiteral(p: *Parser) Error!Result {
8118 const string_start = p.tok_i;
7883 var string_end = p.tok_i;8119 var string_end = p.tok_i;
7884 var string_kind: text_literal.Kind = .char;8120 var string_kind: text_literal.Kind = .char;
7885 while (text_literal.Kind.classify(p.tok_ids[string_end], .string_literal)) |next| : (string_end += 1) {8121 while (text_literal.Kind.classify(p.tok_ids[string_end], .string_literal)) |next| : (string_end += 1) {
...@@ -7894,13 +8130,17 @@ fn stringLiteral(p: *Parser) Error!Result {...@@ -7894,13 +8130,17 @@ fn stringLiteral(p: *Parser) Error!Result {
7894 return error.ParsingFailed;8130 return error.ParsingFailed;
7895 }8131 }
7896 }8132 }
7897 assert(string_end > p.tok_i);8133 const count = string_end - p.tok_i;
8134 assert(count > 0);
78988135
7899 const char_width = string_kind.charUnitSize(p.comp);8136 const char_width = string_kind.charUnitSize(p.comp);
79008137
7901 const strings_top = p.strings.items.len;8138 const strings_top = p.strings.items.len;
7902 defer p.strings.items.len = strings_top;8139 defer p.strings.items.len = strings_top;
79038140
8141 const literal_start = mem.alignForward(usize, strings_top, @intFromEnum(char_width));
8142 try p.strings.resize(literal_start);
8143
7904 while (p.tok_i < string_end) : (p.tok_i += 1) {8144 while (p.tok_i < string_end) : (p.tok_i += 1) {
7905 const this_kind = text_literal.Kind.classify(p.tok_ids[p.tok_i], .string_literal).?;8145 const this_kind = text_literal.Kind.classify(p.tok_ids[p.tok_i], .string_literal).?;
7906 const slice = this_kind.contentSlice(p.tokSlice(p.tok_i));8146 const slice = this_kind.contentSlice(p.tokSlice(p.tok_i));
...@@ -7940,12 +8180,18 @@ fn stringLiteral(p: *Parser) Error!Result {...@@ -7940,12 +8180,18 @@ fn stringLiteral(p: *Parser) Error!Result {
7940 },8180 },
7941 }8181 }
7942 },8182 },
7943 .improperly_encoded => |bytes| p.strings.appendSliceAssumeCapacity(bytes),8183 .improperly_encoded => |bytes| {
8184 if (count > 1) {
8185 try p.errTok(.illegal_char_encoding_error, p.tok_i);
8186 return error.ParsingFailed;
8187 }
8188 p.strings.appendSliceAssumeCapacity(bytes);
8189 },
7944 .utf8_text => |view| {8190 .utf8_text => |view| {
7945 switch (char_width) {8191 switch (char_width) {
7946 .@"1" => p.strings.appendSliceAssumeCapacity(view.bytes),8192 .@"1" => p.strings.appendSliceAssumeCapacity(view.bytes),
7947 .@"2" => {8193 .@"2" => {
7948 const capacity_slice: []align(@alignOf(u16)) u8 = @alignCast(p.strings.unusedCapacitySlice());8194 const capacity_slice: []align(@alignOf(u16)) u8 = @alignCast(p.strings.allocatedSlice()[literal_start..]);
7949 const dest_len = std.mem.alignBackward(usize, capacity_slice.len, 2);8195 const dest_len = std.mem.alignBackward(usize, capacity_slice.len, 2);
7950 const dest = std.mem.bytesAsSlice(u16, capacity_slice[0..dest_len]);8196 const dest = std.mem.bytesAsSlice(u16, capacity_slice[0..dest_len]);
7951 const words_written = std.unicode.utf8ToUtf16Le(dest, view.bytes) catch unreachable;8197 const words_written = std.unicode.utf8ToUtf16Le(dest, view.bytes) catch unreachable;
...@@ -7966,7 +8212,7 @@ fn stringLiteral(p: *Parser) Error!Result {...@@ -7966,7 +8212,7 @@ fn stringLiteral(p: *Parser) Error!Result {
7966 }8212 }
7967 }8213 }
7968 p.strings.appendNTimesAssumeCapacity(0, @intFromEnum(char_width));8214 p.strings.appendNTimesAssumeCapacity(0, @intFromEnum(char_width));
7969 const slice = p.strings.items[strings_top..];8215 const slice = p.strings.items[literal_start..];
79708216
7971 // TODO this won't do anything if there is a cache hit8217 // TODO this won't do anything if there is a cache hit
7972 const interned_align = mem.alignForward(8218 const interned_align = mem.alignForward(
...@@ -7987,7 +8233,7 @@ fn stringLiteral(p: *Parser) Error!Result {...@@ -7987,7 +8233,7 @@ fn stringLiteral(p: *Parser) Error!Result {
7987 },8233 },
7988 .val = val,8234 .val = val,
7989 };8235 };
7990 res.node = try p.addNode(.{ .tag = .string_literal_expr, .ty = res.ty, .data = undefined });8236 res.node = try p.addNode(.{ .tag = .string_literal_expr, .ty = res.ty, .data = undefined, .loc = @enumFromInt(string_start) });
7991 if (!p.in_macro) try p.value_map.put(res.node, res.val);8237 if (!p.in_macro) try p.value_map.put(res.node, res.val);
7992 return res;8238 return res;
7993}8239}
...@@ -8004,7 +8250,7 @@ fn charLiteral(p: *Parser) Error!Result {...@@ -8004,7 +8250,7 @@ fn charLiteral(p: *Parser) Error!Result {
8004 return .{8250 return .{
8005 .ty = Type.int,8251 .ty = Type.int,
8006 .val = Value.zero,8252 .val = Value.zero,
8007 .node = try p.addNode(.{ .tag = .char_literal, .ty = Type.int, .data = undefined }),8253 .node = try p.addNode(.{ .tag = .char_literal, .ty = Type.int, .data = undefined, .loc = @enumFromInt(p.tok_i) }),
8008 };8254 };
8009 };8255 };
8010 if (char_kind == .utf_8) try p.err(.u8_char_lit);8256 if (char_kind == .utf_8) try p.err(.u8_char_lit);
...@@ -8013,7 +8259,7 @@ fn charLiteral(p: *Parser) Error!Result {...@@ -8013,7 +8259,7 @@ fn charLiteral(p: *Parser) Error!Result {
8013 const slice = char_kind.contentSlice(p.tokSlice(p.tok_i));8259 const slice = char_kind.contentSlice(p.tokSlice(p.tok_i));
80148260
8015 var is_multichar = false;8261 var is_multichar = false;
8016 if (slice.len == 1 and std.ascii.isAscii(slice[0])) {8262 if (slice.len == 1 and std.ascii.isASCII(slice[0])) {
8017 // fast path: single unescaped ASCII char8263 // fast path: single unescaped ASCII char
8018 val = slice[0];8264 val = slice[0];
8019 } else {8265 } else {
...@@ -8096,25 +8342,25 @@ fn charLiteral(p: *Parser) Error!Result {...@@ -8096,25 +8342,25 @@ fn charLiteral(p: *Parser) Error!Result {
8096 // > that of the single character or escape sequence is converted to type int.8342 // > that of the single character or escape sequence is converted to type int.
8097 // This conversion only matters if `char` is signed and has a high-order bit of `1`8343 // This conversion only matters if `char` is signed and has a high-order bit of `1`
8098 if (char_kind == .char and !is_multichar and val > 0x7F and p.comp.getCharSignedness() == .signed) {8344 if (char_kind == .char and !is_multichar and val > 0x7F and p.comp.getCharSignedness() == .signed) {
8099 try value.intCast(.{ .specifier = .char }, p.comp);8345 _ = try value.intCast(.{ .specifier = .char }, p.comp);
8100 }8346 }
81018347
8102 const res = Result{8348 const res = Result{
8103 .ty = if (p.in_macro) macro_ty else ty,8349 .ty = if (p.in_macro) macro_ty else ty,
8104 .val = value,8350 .val = value,
8105 .node = try p.addNode(.{ .tag = .char_literal, .ty = ty, .data = undefined }),8351 .node = try p.addNode(.{ .tag = .char_literal, .ty = ty, .data = undefined, .loc = @enumFromInt(p.tok_i) }),
8106 };8352 };
8107 if (!p.in_macro) try p.value_map.put(res.node, res.val);8353 if (!p.in_macro) try p.value_map.put(res.node, res.val);
8108 return res;8354 return res;
8109}8355}
81108356
8111fn parseFloat(p: *Parser, buf: []const u8, suffix: NumberSuffix) !Result {8357fn parseFloat(p: *Parser, buf: []const u8, suffix: NumberSuffix, tok_i: TokenIndex) !Result {
8112 const ty = Type{ .specifier = switch (suffix) {8358 const ty = Type{ .specifier = switch (suffix) {
8113 .None, .I => .double,8359 .None, .I => .double,
8114 .F, .IF => .float,8360 .F, .IF => .float,
8115 .F16 => .float16,8361 .F16, .IF16 => .float16,
8116 .L, .IL => .long_double,8362 .L, .IL => .long_double,
8117 .W, .IW => .float80,8363 .W, .IW => p.comp.float80Type().?.specifier,
8118 .Q, .IQ, .F128, .IF128 => .float128,8364 .Q, .IQ, .F128, .IF128 => .float128,
8119 else => unreachable,8365 else => unreachable,
8120 } };8366 } };
...@@ -8140,21 +8386,29 @@ fn parseFloat(p: *Parser, buf: []const u8, suffix: NumberSuffix) !Result {...@@ -8140,21 +8386,29 @@ fn parseFloat(p: *Parser, buf: []const u8, suffix: NumberSuffix) !Result {
8140 });8386 });
8141 var res = Result{8387 var res = Result{
8142 .ty = ty,8388 .ty = ty,
8143 .node = try p.addNode(.{ .tag = .float_literal, .ty = ty, .data = undefined }),8389 .node = try p.addNode(.{ .tag = .float_literal, .ty = ty, .data = undefined, .loc = @enumFromInt(tok_i) }),
8144 .val = val,8390 .val = val,
8145 };8391 };
8146 if (suffix.isImaginary()) {8392 if (suffix.isImaginary()) {
8147 try p.err(.gnu_imaginary_constant);8393 try p.err(.gnu_imaginary_constant);
8148 res.ty = .{ .specifier = switch (suffix) {8394 res.ty = .{ .specifier = switch (suffix) {
8149 .I => .complex_double,8395 .I => .complex_double,
8396 .IF16 => .complex_float16,
8150 .IF => .complex_float,8397 .IF => .complex_float,
8151 .IL => .complex_long_double,8398 .IL => .complex_long_double,
8152 .IW => .complex_float80,8399 .IW => p.comp.float80Type().?.makeComplex().specifier,
8153 .IQ, .IF128 => .complex_float128,8400 .IQ, .IF128 => .complex_float128,
8154 else => unreachable,8401 else => unreachable,
8155 } };8402 } };
8156 res.val = .{}; // TODO add complex values8403 res.val = try Value.intern(p.comp, switch (res.ty.bitSizeof(p.comp).?) {
8157 try res.un(p, .imaginary_literal);8404 32 => .{ .complex = .{ .cf16 = .{ 0.0, val.toFloat(f16, p.comp) } } },
8405 64 => .{ .complex = .{ .cf32 = .{ 0.0, val.toFloat(f32, p.comp) } } },
8406 128 => .{ .complex = .{ .cf64 = .{ 0.0, val.toFloat(f64, p.comp) } } },
8407 160 => .{ .complex = .{ .cf80 = .{ 0.0, val.toFloat(f80, p.comp) } } },
8408 256 => .{ .complex = .{ .cf128 = .{ 0.0, val.toFloat(f128, p.comp) } } },
8409 else => unreachable,
8410 });
8411 try res.un(p, .imaginary_literal, tok_i);
8158 }8412 }
8159 return res;8413 return res;
8160}8414}
...@@ -8233,12 +8487,14 @@ fn fixedSizeInt(p: *Parser, base: u8, buf: []const u8, suffix: NumberSuffix, tok...@@ -8233,12 +8487,14 @@ fn fixedSizeInt(p: *Parser, base: u8, buf: []const u8, suffix: NumberSuffix, tok
8233 if (overflow) {8487 if (overflow) {
8234 try p.errTok(.int_literal_too_big, tok_i);8488 try p.errTok(.int_literal_too_big, tok_i);
8235 res.ty = .{ .specifier = .ulong_long };8489 res.ty = .{ .specifier = .ulong_long };
8236 res.node = try p.addNode(.{ .tag = .int_literal, .ty = res.ty, .data = undefined });8490 res.node = try p.addNode(.{ .tag = .int_literal, .ty = res.ty, .data = undefined, .loc = @enumFromInt(tok_i) });
8237 if (!p.in_macro) try p.value_map.put(res.node, res.val);8491 if (!p.in_macro) try p.value_map.put(res.node, res.val);
8238 return res;8492 return res;
8239 }8493 }
8494 const interned_val = try Value.int(val, p.comp);
8240 if (suffix.isSignedInteger()) {8495 if (suffix.isSignedInteger()) {
8241 if (val > p.comp.types.intmax.maxInt(p.comp)) {8496 const max_int = try Value.maxInt(p.comp.types.intmax, p.comp);
8497 if (interned_val.compare(.gt, max_int, p.comp)) {
8242 try p.errTok(.implicitly_unsigned_literal, tok_i);8498 try p.errTok(.implicitly_unsigned_literal, tok_i);
8243 }8499 }
8244 }8500 }
...@@ -8266,13 +8522,23 @@ fn fixedSizeInt(p: *Parser, base: u8, buf: []const u8, suffix: NumberSuffix, tok...@@ -8266,13 +8522,23 @@ fn fixedSizeInt(p: *Parser, base: u8, buf: []const u8, suffix: NumberSuffix, tok
8266 for (specs) |spec| {8522 for (specs) |spec| {
8267 res.ty = Type{ .specifier = spec };8523 res.ty = Type{ .specifier = spec };
8268 if (res.ty.compareIntegerRanks(suffix_ty, p.comp).compare(.lt)) continue;8524 if (res.ty.compareIntegerRanks(suffix_ty, p.comp).compare(.lt)) continue;
8269 const max_int = res.ty.maxInt(p.comp);8525 const max_int = try Value.maxInt(res.ty, p.comp);
8270 if (val <= max_int) break;8526 if (interned_val.compare(.lte, max_int, p.comp)) break;
8271 } else {8527 } else {
8272 res.ty = .{ .specifier = .ulong_long };8528 res.ty = .{ .specifier = spec: {
8529 if (p.comp.langopts.emulate == .gcc) {
8530 if (target_util.hasInt128(p.comp.target)) {
8531 break :spec .int128;
8532 } else {
8533 break :spec .long_long;
8534 }
8535 } else {
8536 break :spec .ulong_long;
8537 }
8538 } };
8273 }8539 }
82748540
8275 res.node = try p.addNode(.{ .tag = .int_literal, .ty = res.ty, .data = undefined });8541 res.node = try p.addNode(.{ .tag = .int_literal, .ty = res.ty, .data = undefined, .loc = @enumFromInt(tok_i) });
8276 if (!p.in_macro) try p.value_map.put(res.node, res.val);8542 if (!p.in_macro) try p.value_map.put(res.node, res.val);
8277 return res;8543 return res;
8278}8544}
...@@ -8291,7 +8557,7 @@ fn parseInt(p: *Parser, prefix: NumberPrefix, buf: []const u8, suffix: NumberSuf...@@ -8291,7 +8557,7 @@ fn parseInt(p: *Parser, prefix: NumberPrefix, buf: []const u8, suffix: NumberSuf
8291 try p.errTok(.gnu_imaginary_constant, tok_i);8557 try p.errTok(.gnu_imaginary_constant, tok_i);
8292 res.ty = res.ty.makeComplex();8558 res.ty = res.ty.makeComplex();
8293 res.val = .{};8559 res.val = .{};
8294 try res.un(p, .imaginary_literal);8560 try res.un(p, .imaginary_literal, tok_i);
8295 }8561 }
8296 return res;8562 return res;
8297}8563}
...@@ -8326,17 +8592,6 @@ fn bitInt(p: *Parser, base: u8, buf: []const u8, suffix: NumberSuffix, tok_i: To...@@ -8326,17 +8592,6 @@ fn bitInt(p: *Parser, base: u8, buf: []const u8, suffix: NumberSuffix, tok_i: To
8326 // value of the constant is positive or was specified in hexadecimal or octal notation.8592 // value of the constant is positive or was specified in hexadecimal or octal notation.
8327 const sign_bits = @intFromBool(suffix.isSignedInteger());8593 const sign_bits = @intFromBool(suffix.isSignedInteger());
8328 const bits_needed = count + sign_bits;8594 const bits_needed = count + sign_bits;
8329 if (bits_needed > Compilation.bit_int_max_bits) {
8330 const specifier: Type.Builder.Specifier = switch (suffix) {
8331 .WB => .{ .bit_int = 0 },
8332 .UWB => .{ .ubit_int = 0 },
8333 .IWB => .{ .complex_bit_int = 0 },
8334 .IUWB => .{ .complex_ubit_int = 0 },
8335 else => unreachable,
8336 };
8337 try p.errStr(.bit_int_too_big, tok_i, specifier.str(p.comp.langopts).?);
8338 return error.ParsingFailed;
8339 }
8340 break :blk @intCast(bits_needed);8595 break :blk @intCast(bits_needed);
8341 };8596 };
83428597
...@@ -8347,7 +8602,7 @@ fn bitInt(p: *Parser, base: u8, buf: []const u8, suffix: NumberSuffix, tok_i: To...@@ -8347,7 +8602,7 @@ fn bitInt(p: *Parser, base: u8, buf: []const u8, suffix: NumberSuffix, tok_i: To
8347 .data = .{ .int = .{ .bits = bits_needed, .signedness = suffix.signedness() } },8602 .data = .{ .int = .{ .bits = bits_needed, .signedness = suffix.signedness() } },
8348 },8603 },
8349 };8604 };
8350 res.node = try p.addNode(.{ .tag = .int_literal, .ty = res.ty, .data = undefined });8605 res.node = try p.addNode(.{ .tag = .int_literal, .ty = res.ty, .data = undefined, .loc = @enumFromInt(tok_i) });
8351 if (!p.in_macro) try p.value_map.put(res.node, res.val);8606 if (!p.in_macro) try p.value_map.put(res.node, res.val);
8352 return res;8607 return res;
8353}8608}
...@@ -8420,6 +8675,10 @@ pub fn parseNumberToken(p: *Parser, tok_i: TokenIndex) !Result {...@@ -8420,6 +8675,10 @@ pub fn parseNumberToken(p: *Parser, tok_i: TokenIndex) !Result {
8420 }8675 }
8421 return error.ParsingFailed;8676 return error.ParsingFailed;
8422 };8677 };
8678 if (suffix.isFloat80() and p.comp.float80Type() == null) {
8679 try p.errStr(.invalid_float_suffix, tok_i, suffix_str);
8680 return error.ParsingFailed;
8681 }
84238682
8424 if (is_float) {8683 if (is_float) {
8425 assert(prefix == .hex or prefix == .decimal);8684 assert(prefix == .hex or prefix == .decimal);
...@@ -8428,7 +8687,7 @@ pub fn parseNumberToken(p: *Parser, tok_i: TokenIndex) !Result {...@@ -8428,7 +8687,7 @@ pub fn parseNumberToken(p: *Parser, tok_i: TokenIndex) !Result {
8428 return error.ParsingFailed;8687 return error.ParsingFailed;
8429 }8688 }
8430 const number = buf[0 .. buf.len - suffix_str.len];8689 const number = buf[0 .. buf.len - suffix_str.len];
8431 return p.parseFloat(number, suffix);8690 return p.parseFloat(number, suffix, tok_i);
8432 } else {8691 } else {
8433 return p.parseInt(prefix, int_part, suffix, tok_i);8692 return p.parseInt(prefix, int_part, suffix, tok_i);
8434 }8693 }
...@@ -8444,7 +8703,6 @@ fn ppNum(p: *Parser) Error!Result {...@@ -8444,7 +8703,6 @@ fn ppNum(p: *Parser) Error!Result {
8444 }8703 }
8445 res.ty = if (res.ty.isUnsignedInt(p.comp)) p.comp.types.intmax.makeIntegerUnsigned() else p.comp.types.intmax;8704 res.ty = if (res.ty.isUnsignedInt(p.comp)) p.comp.types.intmax.makeIntegerUnsigned() else p.comp.types.intmax;
8446 } else if (res.val.opt_ref != .none) {8705 } else if (res.val.opt_ref != .none) {
8447 // TODO add complex values
8448 try p.value_map.put(res.node, res.val);8706 try p.value_map.put(res.node, res.val);
8449 }8707 }
8450 return res;8708 return res;
...@@ -8465,6 +8723,7 @@ fn parseNoEval(p: *Parser, comptime func: fn (*Parser) Error!Result) Error!Resul...@@ -8465,6 +8723,7 @@ fn parseNoEval(p: *Parser, comptime func: fn (*Parser) Error!Result) Error!Resul
8465/// : typeName ':' assignExpr8723/// : typeName ':' assignExpr
8466/// | keyword_default ':' assignExpr8724/// | keyword_default ':' assignExpr
8467fn genericSelection(p: *Parser) Error!Result {8725fn genericSelection(p: *Parser) Error!Result {
8726 const kw_generic = p.tok_i;
8468 p.tok_i += 1;8727 p.tok_i += 1;
8469 const l_paren = try p.expectToken(.l_paren);8728 const l_paren = try p.expectToken(.l_paren);
8470 const controlling_tok = p.tok_i;8729 const controlling_tok = p.tok_i;
...@@ -8508,17 +8767,23 @@ fn genericSelection(p: *Parser) Error!Result {...@@ -8508,17 +8767,23 @@ fn genericSelection(p: *Parser) Error!Result {
8508 try p.errStr(.generic_duplicate, start, try p.typeStr(ty));8767 try p.errStr(.generic_duplicate, start, try p.typeStr(ty));
8509 try p.errStr(.generic_duplicate_here, chosen_tok, try p.typeStr(ty));8768 try p.errStr(.generic_duplicate_here, chosen_tok, try p.typeStr(ty));
8510 }8769 }
8511 for (p.list_buf.items[list_buf_top + 1 ..], p.decl_buf.items[decl_buf_top..]) |item, prev_tok| {8770 const list_buf = p.list_buf.items[list_buf_top + 1 ..];
8512 const prev_ty = p.nodes.items(.ty)[@intFromEnum(item)];8771 const decl_buf = p.decl_buf.items[decl_buf_top..];
8513 if (prev_ty.eql(ty, p.comp, true)) {8772 if (list_buf.len == decl_buf.len) {
8514 try p.errStr(.generic_duplicate, start, try p.typeStr(ty));8773 // If these do not have the same length, there is already an error
8515 try p.errStr(.generic_duplicate_here, @intFromEnum(prev_tok), try p.typeStr(ty));8774 for (list_buf, decl_buf) |item, prev_tok| {
8775 const prev_ty = p.nodes.items(.ty)[@intFromEnum(item)];
8776 if (prev_ty.eql(ty, p.comp, true)) {
8777 try p.errStr(.generic_duplicate, start, try p.typeStr(ty));
8778 try p.errStr(.generic_duplicate_here, @intFromEnum(prev_tok), try p.typeStr(ty));
8779 }
8516 }8780 }
8517 }8781 }
8518 try p.list_buf.append(try p.addNode(.{8782 try p.list_buf.append(try p.addNode(.{
8519 .tag = .generic_association_expr,8783 .tag = .generic_association_expr,
8520 .ty = ty,8784 .ty = ty,
8521 .data = .{ .un = node.node },8785 .data = .{ .un = node.node },
8786 .loc = @enumFromInt(start),
8522 }));8787 }));
8523 try p.decl_buf.append(@enumFromInt(start));8788 try p.decl_buf.append(@enumFromInt(start));
8524 } else if (p.eatToken(.keyword_default)) |tok| {8789 } else if (p.eatToken(.keyword_default)) |tok| {
...@@ -8542,10 +8807,12 @@ fn genericSelection(p: *Parser) Error!Result {...@@ -8542,10 +8807,12 @@ fn genericSelection(p: *Parser) Error!Result {
8542 try p.expectClosing(l_paren, .r_paren);8807 try p.expectClosing(l_paren, .r_paren);
85438808
8544 if (chosen.node == .none) {8809 if (chosen.node == .none) {
8545 if (default_tok != null) {8810 if (default_tok) |tok| {
8546 try p.list_buf.insert(list_buf_top + 1, try p.addNode(.{8811 try p.list_buf.insert(list_buf_top + 1, try p.addNode(.{
8547 .tag = .generic_default_expr,8812 .tag = .generic_default_expr,
8548 .data = .{ .un = default.node },8813 .data = .{ .un = default.node },
8814 .ty = default.ty,
8815 .loc = @enumFromInt(tok),
8549 }));8816 }));
8550 chosen = default;8817 chosen = default;
8551 } else {8818 } else {
...@@ -8556,11 +8823,15 @@ fn genericSelection(p: *Parser) Error!Result {...@@ -8556,11 +8823,15 @@ fn genericSelection(p: *Parser) Error!Result {
8556 try p.list_buf.insert(list_buf_top + 1, try p.addNode(.{8823 try p.list_buf.insert(list_buf_top + 1, try p.addNode(.{
8557 .tag = .generic_association_expr,8824 .tag = .generic_association_expr,
8558 .data = .{ .un = chosen.node },8825 .data = .{ .un = chosen.node },
8826 .ty = chosen.ty,
8827 .loc = @enumFromInt(chosen_tok),
8559 }));8828 }));
8560 if (default_tok != null) {8829 if (default_tok) |tok| {
8561 try p.list_buf.append(try p.addNode(.{8830 try p.list_buf.append(try p.addNode(.{
8562 .tag = .generic_default_expr,8831 .tag = .generic_default_expr,
8563 .data = .{ .un = chosen.node },8832 .data = .{ .un = default.node },
8833 .ty = default.ty,
8834 .loc = @enumFromInt(tok),
8564 }));8835 }));
8565 }8836 }
8566 }8837 }
...@@ -8568,7 +8839,8 @@ fn genericSelection(p: *Parser) Error!Result {...@@ -8568,7 +8839,8 @@ fn genericSelection(p: *Parser) Error!Result {
8568 var generic_node: Tree.Node = .{8839 var generic_node: Tree.Node = .{
8569 .tag = .generic_expr_one,8840 .tag = .generic_expr_one,
8570 .ty = chosen.ty,8841 .ty = chosen.ty,
8571 .data = .{ .bin = .{ .lhs = controlling.node, .rhs = chosen.node } },8842 .data = .{ .two = .{ controlling.node, chosen.node } },
8843 .loc = @enumFromInt(kw_generic),
8572 };8844 };
8573 const associations = p.list_buf.items[list_buf_top..];8845 const associations = p.list_buf.items[list_buf_top..];
8574 if (associations.len > 2) { // associations[0] == controlling.node8846 if (associations.len > 2) { // associations[0] == controlling.node
...@@ -8578,3 +8850,42 @@ fn genericSelection(p: *Parser) Error!Result {...@@ -8578,3 +8850,42 @@ fn genericSelection(p: *Parser) Error!Result {
8578 chosen.node = try p.addNode(generic_node);8850 chosen.node = try p.addNode(generic_node);
8579 return chosen;8851 return chosen;
8580}8852}
8853
8854test "Node locations" {
8855 var comp = Compilation.init(std.testing.allocator, std.fs.cwd());
8856 defer comp.deinit();
8857
8858 const file = try comp.addSourceFromBuffer("file.c",
8859 \\int foo = 5;
8860 \\int bar = 10;
8861 \\int main(void) {}
8862 \\
8863 );
8864
8865 const builtin_macros = try comp.generateBuiltinMacros(.no_system_defines);
8866
8867 var pp = Preprocessor.init(&comp);
8868 defer pp.deinit();
8869 try pp.addBuiltinMacros();
8870
8871 _ = try pp.preprocess(builtin_macros);
8872
8873 const eof = try pp.preprocess(file);
8874 try pp.addToken(eof);
8875
8876 var tree = try Parser.parse(&pp);
8877 defer tree.deinit();
8878
8879 try std.testing.expectEqual(0, comp.diagnostics.list.items.len);
8880 for (tree.root_decls, 0..) |node, i| {
8881 const tok_i = tree.nodeTok(node).?;
8882 const slice = tree.tokSlice(tok_i);
8883 const expected = switch (i) {
8884 0 => "foo",
8885 1 => "bar",
8886 2 => "main",
8887 else => unreachable,
8888 };
8889 try std.testing.expectEqualStrings(expected, slice);
8890 }
8891}
lib/compiler/aro/aro/Preprocessor.zig+162-38
...@@ -97,6 +97,11 @@ poisoned_identifiers: std.StringHashMap(void),...@@ -97,6 +97,11 @@ poisoned_identifiers: std.StringHashMap(void),
97/// Map from Source.Id to macro name in the `#ifndef` condition which guards the source, if any97/// Map from Source.Id to macro name in the `#ifndef` condition which guards the source, if any
98include_guards: std.AutoHashMapUnmanaged(Source.Id, []const u8) = .{},98include_guards: std.AutoHashMapUnmanaged(Source.Id, []const u8) = .{},
9999
100/// Store `keyword_define` and `keyword_undef` tokens.
101/// Used to implement preprocessor debug dump options
102/// Must be false unless in -E mode (parser does not handle those token types)
103store_macro_tokens: bool = false,
104
100/// Memory is retained to avoid allocation on every single token.105/// Memory is retained to avoid allocation on every single token.
101top_expansion_buf: ExpandBuf,106top_expansion_buf: ExpandBuf,
102107
...@@ -622,9 +627,12 @@ fn preprocessExtra(pp: *Preprocessor, source: Source) MacroError!TokenWithExpans...@@ -622,9 +627,12 @@ fn preprocessExtra(pp: *Preprocessor, source: Source) MacroError!TokenWithExpans
622 }627 }
623 if_level -= 1;628 if_level -= 1;
624 },629 },
625 .keyword_define => try pp.define(&tokenizer),630 .keyword_define => try pp.define(&tokenizer, directive),
626 .keyword_undef => {631 .keyword_undef => {
627 const macro_name = (try pp.expectMacroName(&tokenizer)) orelse continue;632 const macro_name = (try pp.expectMacroName(&tokenizer)) orelse continue;
633 if (pp.store_macro_tokens) {
634 try pp.addToken(tokFromRaw(directive));
635 }
628636
629 _ = pp.defines.remove(macro_name);637 _ = pp.defines.remove(macro_name);
630 try pp.expectNl(&tokenizer);638 try pp.expectNl(&tokenizer);
...@@ -975,7 +983,7 @@ fn expr(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!bool {...@@ -975,7 +983,7 @@ fn expr(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!bool {
975 .tok_i = @intCast(token_state.tokens_len),983 .tok_i = @intCast(token_state.tokens_len),
976 .arena = pp.arena.allocator(),984 .arena = pp.arena.allocator(),
977 .in_macro = true,985 .in_macro = true,
978 .strings = std.ArrayList(u8).init(pp.comp.gpa),986 .strings = std.ArrayListAligned(u8, 4).init(pp.comp.gpa),
979987
980 .data = undefined,988 .data = undefined,
981 .value_map = undefined,989 .value_map = undefined,
...@@ -1328,19 +1336,41 @@ fn stringify(pp: *Preprocessor, tokens: []const TokenWithExpansionLocs) !void {...@@ -1328,19 +1336,41 @@ fn stringify(pp: *Preprocessor, tokens: []const TokenWithExpansionLocs) !void {
1328 try pp.char_buf.append(c);1336 try pp.char_buf.append(c);
1329 }1337 }
1330 }1338 }
1331 if (pp.char_buf.items[pp.char_buf.items.len - 1] == '\\') {1339 try pp.char_buf.ensureUnusedCapacity(2);
1340 if (pp.char_buf.items[pp.char_buf.items.len - 1] != '\\') {
1341 pp.char_buf.appendSliceAssumeCapacity("\"\n");
1342 return;
1343 }
1344 pp.char_buf.appendAssumeCapacity('"');
1345 var tokenizer: Tokenizer = .{
1346 .buf = pp.char_buf.items,
1347 .index = 0,
1348 .source = .generated,
1349 .langopts = pp.comp.langopts,
1350 .line = 0,
1351 };
1352 const item = tokenizer.next();
1353 if (item.id == .unterminated_string_literal) {
1332 const tok = tokens[tokens.len - 1];1354 const tok = tokens[tokens.len - 1];
1333 try pp.comp.addDiagnostic(.{1355 try pp.comp.addDiagnostic(.{
1334 .tag = .invalid_pp_stringify_escape,1356 .tag = .invalid_pp_stringify_escape,
1335 .loc = tok.loc,1357 .loc = tok.loc,
1336 }, tok.expansionSlice());1358 }, tok.expansionSlice());
1337 pp.char_buf.items.len -= 1;1359 pp.char_buf.items.len -= 2; // erase unpaired backslash and appended end quote
1360 pp.char_buf.appendAssumeCapacity('"');
1338 }1361 }
1339 try pp.char_buf.appendSlice("\"\n");1362 pp.char_buf.appendAssumeCapacity('\n');
1340}1363}
13411364
1342fn reconstructIncludeString(pp: *Preprocessor, param_toks: []const TokenWithExpansionLocs, embed_args: ?*[]const TokenWithExpansionLocs, first: TokenWithExpansionLocs) !?[]const u8 {1365fn reconstructIncludeString(pp: *Preprocessor, param_toks: []const TokenWithExpansionLocs, embed_args: ?*[]const TokenWithExpansionLocs, first: TokenWithExpansionLocs) !?[]const u8 {
1343 assert(param_toks.len != 0);1366 if (param_toks.len == 0) {
1367 try pp.comp.addDiagnostic(.{
1368 .tag = .expected_filename,
1369 .loc = first.loc,
1370 }, first.expansionSlice());
1371 return null;
1372 }
1373
1344 const char_top = pp.char_buf.items.len;1374 const char_top = pp.char_buf.items.len;
1345 defer pp.char_buf.items.len = char_top;1375 defer pp.char_buf.items.len = char_top;
13461376
...@@ -1539,11 +1569,13 @@ fn getPasteArgs(args: []const TokenWithExpansionLocs) []const TokenWithExpansion...@@ -1539,11 +1569,13 @@ fn getPasteArgs(args: []const TokenWithExpansionLocs) []const TokenWithExpansion
15391569
1540fn expandFuncMacro(1570fn expandFuncMacro(
1541 pp: *Preprocessor,1571 pp: *Preprocessor,
1542 loc: Source.Location,1572 macro_tok: TokenWithExpansionLocs,
1543 func_macro: *const Macro,1573 func_macro: *const Macro,
1544 args: *const MacroArguments,1574 args: *const MacroArguments,
1545 expanded_args: *const MacroArguments,1575 expanded_args: *const MacroArguments,
1576 hideset_arg: Hideset.Index,
1546) MacroError!ExpandBuf {1577) MacroError!ExpandBuf {
1578 var hideset = hideset_arg;
1547 var buf = ExpandBuf.init(pp.gpa);1579 var buf = ExpandBuf.init(pp.gpa);
1548 try buf.ensureTotalCapacity(func_macro.tokens.len);1580 try buf.ensureTotalCapacity(func_macro.tokens.len);
1549 errdefer buf.deinit();1581 errdefer buf.deinit();
...@@ -1594,16 +1626,21 @@ fn expandFuncMacro(...@@ -1594,16 +1626,21 @@ fn expandFuncMacro(
1594 },1626 },
1595 else => &[1]TokenWithExpansionLocs{tokFromRaw(raw_next)},1627 else => &[1]TokenWithExpansionLocs{tokFromRaw(raw_next)},
1596 };1628 };
1597
1598 try pp.pasteTokens(&buf, next);1629 try pp.pasteTokens(&buf, next);
1599 if (next.len != 0) break;1630 if (next.len != 0) break;
1600 },1631 },
1601 .macro_param_no_expand => {1632 .macro_param_no_expand => {
1633 if (tok_i + 1 < func_macro.tokens.len and func_macro.tokens[tok_i + 1].id == .hash_hash) {
1634 hideset = pp.hideset.get(tokFromRaw(func_macro.tokens[tok_i + 1]).loc);
1635 }
1602 const slice = getPasteArgs(args.items[raw.end]);1636 const slice = getPasteArgs(args.items[raw.end]);
1603 const raw_loc = Source.Location{ .id = raw.source, .byte_offset = raw.start, .line = raw.line };1637 const raw_loc = Source.Location{ .id = raw.source, .byte_offset = raw.start, .line = raw.line };
1604 try bufCopyTokens(&buf, slice, &.{raw_loc});1638 try bufCopyTokens(&buf, slice, &.{raw_loc});
1605 },1639 },
1606 .macro_param => {1640 .macro_param => {
1641 if (tok_i + 1 < func_macro.tokens.len and func_macro.tokens[tok_i + 1].id == .hash_hash) {
1642 hideset = pp.hideset.get(tokFromRaw(func_macro.tokens[tok_i + 1]).loc);
1643 }
1607 const arg = expanded_args.items[raw.end];1644 const arg = expanded_args.items[raw.end];
1608 const raw_loc = Source.Location{ .id = raw.source, .byte_offset = raw.start, .line = raw.line };1645 const raw_loc = Source.Location{ .id = raw.source, .byte_offset = raw.start, .line = raw.line };
1609 try bufCopyTokens(&buf, arg, &.{raw_loc});1646 try bufCopyTokens(&buf, arg, &.{raw_loc});
...@@ -1642,9 +1679,9 @@ fn expandFuncMacro(...@@ -1642,9 +1679,9 @@ fn expandFuncMacro(
1642 const arg = expanded_args.items[0];1679 const arg = expanded_args.items[0];
1643 const result = if (arg.len == 0) blk: {1680 const result = if (arg.len == 0) blk: {
1644 const extra = Diagnostics.Message.Extra{ .arguments = .{ .expected = 1, .actual = 0 } };1681 const extra = Diagnostics.Message.Extra{ .arguments = .{ .expected = 1, .actual = 0 } };
1645 try pp.comp.addDiagnostic(.{ .tag = .expected_arguments, .loc = loc, .extra = extra }, &.{});1682 try pp.comp.addDiagnostic(.{ .tag = .expected_arguments, .loc = macro_tok.loc, .extra = extra }, &.{});
1646 break :blk false;1683 break :blk false;
1647 } else try pp.handleBuiltinMacro(raw.id, arg, loc);1684 } else try pp.handleBuiltinMacro(raw.id, arg, macro_tok.loc);
1648 const start = pp.comp.generated_buf.items.len;1685 const start = pp.comp.generated_buf.items.len;
1649 const w = pp.comp.generated_buf.writer(pp.gpa);1686 const w = pp.comp.generated_buf.writer(pp.gpa);
1650 try w.print("{}\n", .{@intFromBool(result)});1687 try w.print("{}\n", .{@intFromBool(result)});
...@@ -1655,7 +1692,7 @@ fn expandFuncMacro(...@@ -1655,7 +1692,7 @@ fn expandFuncMacro(
1655 const not_found = "0\n";1692 const not_found = "0\n";
1656 const result = if (arg.len == 0) blk: {1693 const result = if (arg.len == 0) blk: {
1657 const extra = Diagnostics.Message.Extra{ .arguments = .{ .expected = 1, .actual = 0 } };1694 const extra = Diagnostics.Message.Extra{ .arguments = .{ .expected = 1, .actual = 0 } };
1658 try pp.comp.addDiagnostic(.{ .tag = .expected_arguments, .loc = loc, .extra = extra }, &.{});1695 try pp.comp.addDiagnostic(.{ .tag = .expected_arguments, .loc = macro_tok.loc, .extra = extra }, &.{});
1659 break :blk not_found;1696 break :blk not_found;
1660 } else res: {1697 } else res: {
1661 var invalid: ?TokenWithExpansionLocs = null;1698 var invalid: ?TokenWithExpansionLocs = null;
...@@ -1687,7 +1724,7 @@ fn expandFuncMacro(...@@ -1687,7 +1724,7 @@ fn expandFuncMacro(
1687 if (vendor_ident != null and attr_ident == null) {1724 if (vendor_ident != null and attr_ident == null) {
1688 invalid = vendor_ident;1725 invalid = vendor_ident;
1689 } else if (attr_ident == null and invalid == null) {1726 } else if (attr_ident == null and invalid == null) {
1690 invalid = .{ .id = .eof, .loc = loc };1727 invalid = .{ .id = .eof, .loc = macro_tok.loc };
1691 }1728 }
1692 if (invalid) |some| {1729 if (invalid) |some| {
1693 try pp.comp.addDiagnostic(1730 try pp.comp.addDiagnostic(
...@@ -1731,7 +1768,7 @@ fn expandFuncMacro(...@@ -1731,7 +1768,7 @@ fn expandFuncMacro(
1731 const not_found = "0\n";1768 const not_found = "0\n";
1732 const result = if (arg.len == 0) blk: {1769 const result = if (arg.len == 0) blk: {
1733 const extra = Diagnostics.Message.Extra{ .arguments = .{ .expected = 1, .actual = 0 } };1770 const extra = Diagnostics.Message.Extra{ .arguments = .{ .expected = 1, .actual = 0 } };
1734 try pp.comp.addDiagnostic(.{ .tag = .expected_arguments, .loc = loc, .extra = extra }, &.{});1771 try pp.comp.addDiagnostic(.{ .tag = .expected_arguments, .loc = macro_tok.loc, .extra = extra }, &.{});
1735 break :blk not_found;1772 break :blk not_found;
1736 } else res: {1773 } else res: {
1737 var embed_args: []const TokenWithExpansionLocs = &.{};1774 var embed_args: []const TokenWithExpansionLocs = &.{};
...@@ -1877,11 +1914,11 @@ fn expandFuncMacro(...@@ -1877,11 +1914,11 @@ fn expandFuncMacro(
1877 break;1914 break;
1878 },1915 },
1879 };1916 };
1880 if (string == null and invalid == null) invalid = .{ .loc = loc, .id = .eof };1917 if (string == null and invalid == null) invalid = .{ .loc = macro_tok.loc, .id = .eof };
1881 if (invalid) |some| try pp.comp.addDiagnostic(1918 if (invalid) |some| try pp.comp.addDiagnostic(
1882 .{ .tag = .pragma_operator_string_literal, .loc = some.loc },1919 .{ .tag = .pragma_operator_string_literal, .loc = some.loc },
1883 some.expansionSlice(),1920 some.expansionSlice(),
1884 ) else try pp.pragmaOperator(string.?, loc);1921 ) else try pp.pragmaOperator(string.?, macro_tok.loc);
1885 },1922 },
1886 .comma => {1923 .comma => {
1887 if (tok_i + 2 < func_macro.tokens.len and func_macro.tokens[tok_i + 1].id == .hash_hash) {1924 if (tok_i + 2 < func_macro.tokens.len and func_macro.tokens[tok_i + 1].id == .hash_hash) {
...@@ -1930,6 +1967,15 @@ fn expandFuncMacro(...@@ -1930,6 +1967,15 @@ fn expandFuncMacro(
1930 }1967 }
1931 removePlacemarkers(&buf);1968 removePlacemarkers(&buf);
19321969
1970 const macro_expansion_locs = macro_tok.expansionSlice();
1971 for (buf.items) |*tok| {
1972 try tok.addExpansionLocation(pp.gpa, &.{macro_tok.loc});
1973 try tok.addExpansionLocation(pp.gpa, macro_expansion_locs);
1974 const tok_hidelist = pp.hideset.get(tok.loc);
1975 const new_hidelist = try pp.hideset.@"union"(tok_hidelist, hideset);
1976 try pp.hideset.put(tok.loc, new_hidelist);
1977 }
1978
1933 return buf;1979 return buf;
1934}1980}
19351981
...@@ -2207,8 +2253,10 @@ fn expandMacroExhaustive(...@@ -2207,8 +2253,10 @@ fn expandMacroExhaustive(
2207 else => |e| return e,2253 else => |e| return e,
2208 };2254 };
2209 assert(r_paren.id == .r_paren);2255 assert(r_paren.id == .r_paren);
2256 var free_arg_expansion_locs = false;
2210 defer {2257 defer {
2211 for (args.items) |item| {2258 for (args.items) |item| {
2259 if (free_arg_expansion_locs) for (item) |tok| TokenWithExpansionLocs.free(tok.expansion_locs, pp.gpa);
2212 pp.gpa.free(item);2260 pp.gpa.free(item);
2213 }2261 }
2214 args.deinit();2262 args.deinit();
...@@ -2234,6 +2282,7 @@ fn expandMacroExhaustive(...@@ -2234,6 +2282,7 @@ fn expandMacroExhaustive(
2234 .arguments = .{ .expected = @intCast(macro.params.len), .actual = args_count },2282 .arguments = .{ .expected = @intCast(macro.params.len), .actual = args_count },
2235 };2283 };
2236 if (macro.var_args and args_count < macro.params.len) {2284 if (macro.var_args and args_count < macro.params.len) {
2285 free_arg_expansion_locs = true;
2237 try pp.comp.addDiagnostic(2286 try pp.comp.addDiagnostic(
2238 .{ .tag = .expected_at_least_arguments, .loc = buf.items[idx].loc, .extra = extra },2287 .{ .tag = .expected_at_least_arguments, .loc = buf.items[idx].loc, .extra = extra },
2239 buf.items[idx].expansionSlice(),2288 buf.items[idx].expansionSlice(),
...@@ -2243,6 +2292,7 @@ fn expandMacroExhaustive(...@@ -2243,6 +2292,7 @@ fn expandMacroExhaustive(
2243 continue;2292 continue;
2244 }2293 }
2245 if (!macro.var_args and args_count != macro.params.len) {2294 if (!macro.var_args and args_count != macro.params.len) {
2295 free_arg_expansion_locs = true;
2246 try pp.comp.addDiagnostic(2296 try pp.comp.addDiagnostic(
2247 .{ .tag = .expected_arguments, .loc = buf.items[idx].loc, .extra = extra },2297 .{ .tag = .expected_arguments, .loc = buf.items[idx].loc, .extra = extra },
2248 buf.items[idx].expansionSlice(),2298 buf.items[idx].expansionSlice(),
...@@ -2264,19 +2314,9 @@ fn expandMacroExhaustive(...@@ -2264,19 +2314,9 @@ fn expandMacroExhaustive(
2264 expanded_args.appendAssumeCapacity(try expand_buf.toOwnedSlice());2314 expanded_args.appendAssumeCapacity(try expand_buf.toOwnedSlice());
2265 }2315 }
22662316
2267 var res = try pp.expandFuncMacro(macro_tok.loc, macro, &args, &expanded_args);2317 var res = try pp.expandFuncMacro(macro_tok, macro, &args, &expanded_args, hs);
2268 defer res.deinit();2318 defer res.deinit();
2269 const tokens_added = res.items.len;2319 const tokens_added = res.items.len;
2270
2271 const macro_expansion_locs = macro_tok.expansionSlice();
2272 for (res.items) |*tok| {
2273 try tok.addExpansionLocation(pp.gpa, &.{macro_tok.loc});
2274 try tok.addExpansionLocation(pp.gpa, macro_expansion_locs);
2275 const tok_hidelist = pp.hideset.get(tok.loc);
2276 const new_hidelist = try pp.hideset.@"union"(tok_hidelist, hs);
2277 try pp.hideset.put(tok.loc, new_hidelist);
2278 }
2279
2280 const tokens_removed = macro_scan_idx - idx + 1;2320 const tokens_removed = macro_scan_idx - idx + 1;
2281 for (buf.items[idx .. idx + tokens_removed]) |tok| TokenWithExpansionLocs.free(tok.expansion_locs, pp.gpa);2321 for (buf.items[idx .. idx + tokens_removed]) |tok| TokenWithExpansionLocs.free(tok.expansion_locs, pp.gpa);
2282 try buf.replaceRange(idx, tokens_removed, res.items);2322 try buf.replaceRange(idx, tokens_removed, res.items);
...@@ -2476,7 +2516,7 @@ fn makeGeneratedToken(pp: *Preprocessor, start: usize, id: Token.Id, source: Tok...@@ -2476,7 +2516,7 @@ fn makeGeneratedToken(pp: *Preprocessor, start: usize, id: Token.Id, source: Tok
2476}2516}
24772517
2478/// Defines a new macro and warns if it is a duplicate2518/// Defines a new macro and warns if it is a duplicate
2479fn defineMacro(pp: *Preprocessor, name_tok: RawToken, macro: Macro) Error!void {2519fn defineMacro(pp: *Preprocessor, define_tok: RawToken, name_tok: RawToken, macro: Macro) Error!void {
2480 const name_str = pp.tokSlice(name_tok);2520 const name_str = pp.tokSlice(name_tok);
2481 const gop = try pp.defines.getOrPut(pp.gpa, name_str);2521 const gop = try pp.defines.getOrPut(pp.gpa, name_str);
2482 if (gop.found_existing and !gop.value_ptr.eql(macro, pp)) {2522 if (gop.found_existing and !gop.value_ptr.eql(macro, pp)) {
...@@ -2497,11 +2537,14 @@ fn defineMacro(pp: *Preprocessor, name_tok: RawToken, macro: Macro) Error!void {...@@ -2497,11 +2537,14 @@ fn defineMacro(pp: *Preprocessor, name_tok: RawToken, macro: Macro) Error!void {
2497 if (pp.verbose) {2537 if (pp.verbose) {
2498 pp.verboseLog(name_tok, "macro {s} defined", .{name_str});2538 pp.verboseLog(name_tok, "macro {s} defined", .{name_str});
2499 }2539 }
2540 if (pp.store_macro_tokens) {
2541 try pp.addToken(tokFromRaw(define_tok));
2542 }
2500 gop.value_ptr.* = macro;2543 gop.value_ptr.* = macro;
2501}2544}
25022545
2503/// Handle a #define directive.2546/// Handle a #define directive.
2504fn define(pp: *Preprocessor, tokenizer: *Tokenizer) Error!void {2547fn define(pp: *Preprocessor, tokenizer: *Tokenizer, define_tok: RawToken) Error!void {
2505 // Get macro name and validate it.2548 // Get macro name and validate it.
2506 const macro_name = tokenizer.nextNoWS();2549 const macro_name = tokenizer.nextNoWS();
2507 if (macro_name.id == .keyword_defined) {2550 if (macro_name.id == .keyword_defined) {
...@@ -2524,7 +2567,7 @@ fn define(pp: *Preprocessor, tokenizer: *Tokenizer) Error!void {...@@ -2524,7 +2567,7 @@ fn define(pp: *Preprocessor, tokenizer: *Tokenizer) Error!void {
2524 // Check for function macros and empty defines.2567 // Check for function macros and empty defines.
2525 var first = tokenizer.next();2568 var first = tokenizer.next();
2526 switch (first.id) {2569 switch (first.id) {
2527 .nl, .eof => return pp.defineMacro(macro_name, .{2570 .nl, .eof => return pp.defineMacro(define_tok, macro_name, .{
2528 .params = &.{},2571 .params = &.{},
2529 .tokens = &.{},2572 .tokens = &.{},
2530 .var_args = false,2573 .var_args = false,
...@@ -2532,7 +2575,7 @@ fn define(pp: *Preprocessor, tokenizer: *Tokenizer) Error!void {...@@ -2532,7 +2575,7 @@ fn define(pp: *Preprocessor, tokenizer: *Tokenizer) Error!void {
2532 .is_func = false,2575 .is_func = false,
2533 }),2576 }),
2534 .whitespace => first = tokenizer.next(),2577 .whitespace => first = tokenizer.next(),
2535 .l_paren => return pp.defineFn(tokenizer, macro_name, first),2578 .l_paren => return pp.defineFn(tokenizer, define_tok, macro_name, first),
2536 else => try pp.err(first, .whitespace_after_macro_name),2579 else => try pp.err(first, .whitespace_after_macro_name),
2537 }2580 }
2538 if (first.id == .hash_hash) {2581 if (first.id == .hash_hash) {
...@@ -2591,7 +2634,7 @@ fn define(pp: *Preprocessor, tokenizer: *Tokenizer) Error!void {...@@ -2591,7 +2634,7 @@ fn define(pp: *Preprocessor, tokenizer: *Tokenizer) Error!void {
2591 }2634 }
25922635
2593 const list = try pp.arena.allocator().dupe(RawToken, pp.token_buf.items);2636 const list = try pp.arena.allocator().dupe(RawToken, pp.token_buf.items);
2594 try pp.defineMacro(macro_name, .{2637 try pp.defineMacro(define_tok, macro_name, .{
2595 .loc = tokFromRaw(macro_name).loc,2638 .loc = tokFromRaw(macro_name).loc,
2596 .tokens = list,2639 .tokens = list,
2597 .params = undefined,2640 .params = undefined,
...@@ -2601,7 +2644,7 @@ fn define(pp: *Preprocessor, tokenizer: *Tokenizer) Error!void {...@@ -2601,7 +2644,7 @@ fn define(pp: *Preprocessor, tokenizer: *Tokenizer) Error!void {
2601}2644}
26022645
2603/// Handle a function like #define directive.2646/// Handle a function like #define directive.
2604fn defineFn(pp: *Preprocessor, tokenizer: *Tokenizer, macro_name: RawToken, l_paren: RawToken) Error!void {2647fn defineFn(pp: *Preprocessor, tokenizer: *Tokenizer, define_tok: RawToken, macro_name: RawToken, l_paren: RawToken) Error!void {
2605 assert(macro_name.id.isMacroIdentifier());2648 assert(macro_name.id.isMacroIdentifier());
2606 var params = std.ArrayList([]const u8).init(pp.gpa);2649 var params = std.ArrayList([]const u8).init(pp.gpa);
2607 defer params.deinit();2650 defer params.deinit();
...@@ -2778,7 +2821,7 @@ fn defineFn(pp: *Preprocessor, tokenizer: *Tokenizer, macro_name: RawToken, l_pa...@@ -2778,7 +2821,7 @@ fn defineFn(pp: *Preprocessor, tokenizer: *Tokenizer, macro_name: RawToken, l_pa
27782821
2779 const param_list = try pp.arena.allocator().dupe([]const u8, params.items);2822 const param_list = try pp.arena.allocator().dupe([]const u8, params.items);
2780 const token_list = try pp.arena.allocator().dupe(RawToken, pp.token_buf.items);2823 const token_list = try pp.arena.allocator().dupe(RawToken, pp.token_buf.items);
2781 try pp.defineMacro(macro_name, .{2824 try pp.defineMacro(define_tok, macro_name, .{
2782 .is_func = true,2825 .is_func = true,
2783 .params = param_list,2826 .params = param_list,
2784 .var_args = var_args or gnu_var_args.len != 0,2827 .var_args = var_args or gnu_var_args.len != 0,
...@@ -3241,8 +3284,78 @@ fn printLinemarker(...@@ -3241,8 +3284,78 @@ fn printLinemarker(
3241// After how many empty lines are needed to replace them with linemarkers.3284// After how many empty lines are needed to replace them with linemarkers.
3242const collapse_newlines = 8;3285const collapse_newlines = 8;
32433286
3287pub const DumpMode = enum {
3288 /// Standard preprocessor output; no macros
3289 result_only,
3290 /// Output only #define directives for all the macros defined during the execution of the preprocessor
3291 /// Only macros which are still defined at the end of preprocessing are printed.
3292 /// Only the most recent definition is printed
3293 /// Defines are printed in arbitrary order
3294 macros_only,
3295 /// Standard preprocessor output; but additionally output #define's and #undef's for macros as they are encountered
3296 macros_and_result,
3297 /// Same as macros_and_result, except only the macro name is printed for #define's
3298 macro_names_and_result,
3299};
3300
3301/// Pretty-print the macro define or undef at location `loc`.
3302/// We re-tokenize the directive because we are printing a macro that may have the same name as one in
3303/// `pp.defines` but a different definition (due to being #undef'ed and then redefined)
3304fn prettyPrintMacro(pp: *Preprocessor, w: anytype, loc: Source.Location, parts: enum { name_only, name_and_body }) !void {
3305 const source = pp.comp.getSource(loc.id);
3306 var tokenizer: Tokenizer = .{
3307 .buf = source.buf,
3308 .langopts = pp.comp.langopts,
3309 .source = source.id,
3310 .index = loc.byte_offset,
3311 };
3312 var prev_ws = false; // avoid printing multiple whitespace if /* */ comments are within the macro def
3313 var saw_name = false; // do not print comments before the name token is seen.
3314 while (true) {
3315 const tok = tokenizer.next();
3316 switch (tok.id) {
3317 .comment => {
3318 if (saw_name) {
3319 prev_ws = false;
3320 try w.print("{s}", .{pp.tokSlice(tok)});
3321 }
3322 },
3323 .nl, .eof => break,
3324 .whitespace => {
3325 if (!prev_ws) {
3326 try w.writeByte(' ');
3327 prev_ws = true;
3328 }
3329 },
3330 else => {
3331 prev_ws = false;
3332 try w.print("{s}", .{pp.tokSlice(tok)});
3333 },
3334 }
3335 if (tok.id == .identifier or tok.id == .extended_identifier) {
3336 if (parts == .name_only) break;
3337 saw_name = true;
3338 }
3339 }
3340}
3341
3342fn prettyPrintMacrosOnly(pp: *Preprocessor, w: anytype) !void {
3343 var it = pp.defines.valueIterator();
3344 while (it.next()) |macro| {
3345 if (macro.is_builtin) continue;
3346
3347 try w.writeAll("#define ");
3348 try pp.prettyPrintMacro(w, macro.loc, .name_and_body);
3349 try w.writeByte('\n');
3350 }
3351}
3352
3244/// Pretty print tokens and try to preserve whitespace.3353/// Pretty print tokens and try to preserve whitespace.
3245pub fn prettyPrintTokens(pp: *Preprocessor, w: anytype) !void {3354pub fn prettyPrintTokens(pp: *Preprocessor, w: anytype, macro_dump_mode: DumpMode) !void {
3355 if (macro_dump_mode == .macros_only) {
3356 return pp.prettyPrintMacrosOnly(w);
3357 }
3358
3246 const tok_ids = pp.tokens.items(.id);3359 const tok_ids = pp.tokens.items(.id);
32473360
3248 var i: u32 = 0;3361 var i: u32 = 0;
...@@ -3334,6 +3447,17 @@ pub fn prettyPrintTokens(pp: *Preprocessor, w: anytype) !void {...@@ -3334,6 +3447,17 @@ pub fn prettyPrintTokens(pp: *Preprocessor, w: anytype) !void {
3334 try pp.printLinemarker(w, line_col.line_no, source, .@"resume");3447 try pp.printLinemarker(w, line_col.line_no, source, .@"resume");
3335 last_nl = true;3448 last_nl = true;
3336 },3449 },
3450 .keyword_define, .keyword_undef => {
3451 switch (macro_dump_mode) {
3452 .macros_and_result, .macro_names_and_result => {
3453 try w.writeByte('#');
3454 try pp.prettyPrintMacro(w, cur.loc, if (macro_dump_mode == .macros_and_result) .name_and_body else .name_only);
3455 last_nl = false;
3456 },
3457 .result_only => unreachable, // `pp.store_macro_tokens` should be false for standard preprocessor output
3458 .macros_only => unreachable, // handled by prettyPrintMacrosOnly
3459 }
3460 },
3337 else => {3461 else => {
3338 const slice = pp.expandedSlice(cur);3462 const slice = pp.expandedSlice(cur);
3339 try w.writeAll(slice);3463 try w.writeAll(slice);
...@@ -3350,7 +3474,7 @@ test "Preserve pragma tokens sometimes" {...@@ -3350,7 +3474,7 @@ test "Preserve pragma tokens sometimes" {
3350 var buf = std.ArrayList(u8).init(allocator);3474 var buf = std.ArrayList(u8).init(allocator);
3351 defer buf.deinit();3475 defer buf.deinit();
33523476
3353 var comp = Compilation.init(allocator);3477 var comp = Compilation.init(allocator, std.fs.cwd());
3354 defer comp.deinit();3478 defer comp.deinit();
33553479
3356 try comp.addDefaultPragmaHandlers();3480 try comp.addDefaultPragmaHandlers();
...@@ -3364,7 +3488,7 @@ test "Preserve pragma tokens sometimes" {...@@ -3364,7 +3488,7 @@ test "Preserve pragma tokens sometimes" {
3364 const test_runner_macros = try comp.addSourceFromBuffer("<test_runner>", source_text);3488 const test_runner_macros = try comp.addSourceFromBuffer("<test_runner>", source_text);
3365 const eof = try pp.preprocess(test_runner_macros);3489 const eof = try pp.preprocess(test_runner_macros);
3366 try pp.addToken(eof);3490 try pp.addToken(eof);
3367 try pp.prettyPrintTokens(buf.writer());3491 try pp.prettyPrintTokens(buf.writer(), .result_only);
3368 return allocator.dupe(u8, buf.items);3492 return allocator.dupe(u8, buf.items);
3369 }3493 }
33703494
...@@ -3410,7 +3534,7 @@ test "destringify" {...@@ -3410,7 +3534,7 @@ test "destringify" {
3410 try std.testing.expectEqualStrings(destringified, pp.char_buf.items);3534 try std.testing.expectEqualStrings(destringified, pp.char_buf.items);
3411 }3535 }
3412 };3536 };
3413 var comp = Compilation.init(allocator);3537 var comp = Compilation.init(allocator, std.fs.cwd());
3414 defer comp.deinit();3538 defer comp.deinit();
3415 var pp = Preprocessor.init(&comp);3539 var pp = Preprocessor.init(&comp);
3416 defer pp.deinit();3540 defer pp.deinit();
...@@ -3468,7 +3592,7 @@ test "Include guards" {...@@ -3468,7 +3592,7 @@ test "Include guards" {
3468 }3592 }
34693593
3470 fn testIncludeGuard(allocator: std.mem.Allocator, comptime template: []const u8, tok_id: RawToken.Id, expected_guards: u32) !void {3594 fn testIncludeGuard(allocator: std.mem.Allocator, comptime template: []const u8, tok_id: RawToken.Id, expected_guards: u32) !void {
3471 var comp = Compilation.init(allocator);3595 var comp = Compilation.init(allocator, std.fs.cwd());
3472 defer comp.deinit();3596 defer comp.deinit();
3473 var pp = Preprocessor.init(&comp);3597 var pp = Preprocessor.init(&comp);
3474 defer pp.deinit();3598 defer pp.deinit();
lib/compiler/aro/aro/Source.zig+11-1
...@@ -75,7 +75,17 @@ pub fn lineCol(source: Source, loc: Location) LineCol {...@@ -75,7 +75,17 @@ pub fn lineCol(source: Source, loc: Location) LineCol {
75 i += 1;75 i += 1;
76 continue;76 continue;
77 };77 };
78 const cp = std.unicode.utf8Decode(source.buf[i..][0..len]) catch {78 const slice = source.buf[i..];
79 if (len > slice.len) {
80 break;
81 }
82 const cp = switch (len) {
83 1 => slice[0],
84 2 => std.unicode.utf8Decode2(slice[0..2].*),
85 3 => std.unicode.utf8Decode3(slice[0..3].*),
86 4 => std.unicode.utf8Decode4(slice[0..4].*),
87 else => unreachable,
88 } catch {
79 i += 1;89 i += 1;
80 continue;90 continue;
81 };91 };
lib/compiler/aro/aro/SymbolStack.zig+11-4
...@@ -178,9 +178,11 @@ pub fn defineTypedef(...@@ -178,9 +178,11 @@ pub fn defineTypedef(
178 if (s.get(name, .vars)) |prev| {178 if (s.get(name, .vars)) |prev| {
179 switch (prev.kind) {179 switch (prev.kind) {
180 .typedef => {180 .typedef => {
181 if (!ty.eql(prev.ty, p.comp, true)) {181 if (!prev.ty.is(.invalid)) {
182 try p.errStr(.redefinition_of_typedef, tok, try p.typePairStrExtra(ty, " vs ", prev.ty));182 if (!ty.eql(prev.ty, p.comp, true)) {
183 if (prev.tok != 0) try p.errTok(.previous_definition, prev.tok);183 try p.errStr(.redefinition_of_typedef, tok, try p.typePairStrExtra(ty, " vs ", prev.ty));
184 if (prev.tok != 0) try p.errTok(.previous_definition, prev.tok);
185 }
184 }186 }
185 },187 },
186 .enumeration, .decl, .def, .constexpr => {188 .enumeration, .decl, .def, .constexpr => {
...@@ -194,7 +196,12 @@ pub fn defineTypedef(...@@ -194,7 +196,12 @@ pub fn defineTypedef(
194 .kind = .typedef,196 .kind = .typedef,
195 .name = name,197 .name = name,
196 .tok = tok,198 .tok = tok,
197 .ty = ty,199 .ty = .{
200 .name = name,
201 .specifier = ty.specifier,
202 .qual = ty.qual,
203 .data = ty.data,
204 },
198 .node = node,205 .node = node,
199 .val = .{},206 .val = .{},
200 });207 });
lib/compiler/aro/aro/Tokenizer.zig+43-13
...@@ -178,6 +178,8 @@ pub const Token = struct {...@@ -178,6 +178,8 @@ pub const Token = struct {
178 keyword_return,178 keyword_return,
179 keyword_short,179 keyword_short,
180 keyword_signed,180 keyword_signed,
181 keyword_signed1,
182 keyword_signed2,
181 keyword_sizeof,183 keyword_sizeof,
182 keyword_static,184 keyword_static,
183 keyword_struct,185 keyword_struct,
...@@ -258,7 +260,6 @@ pub const Token = struct {...@@ -258,7 +260,6 @@ pub const Token = struct {
258 keyword_asm,260 keyword_asm,
259 keyword_asm1,261 keyword_asm1,
260 keyword_asm2,262 keyword_asm2,
261 keyword_float80,
262 /// _Float128263 /// _Float128
263 keyword_float128_1,264 keyword_float128_1,
264 /// __float128265 /// __float128
...@@ -369,6 +370,8 @@ pub const Token = struct {...@@ -369,6 +370,8 @@ pub const Token = struct {
369 .keyword_return,370 .keyword_return,
370 .keyword_short,371 .keyword_short,
371 .keyword_signed,372 .keyword_signed,
373 .keyword_signed1,
374 .keyword_signed2,
372 .keyword_sizeof,375 .keyword_sizeof,
373 .keyword_static,376 .keyword_static,
374 .keyword_struct,377 .keyword_struct,
...@@ -417,7 +420,6 @@ pub const Token = struct {...@@ -417,7 +420,6 @@ pub const Token = struct {
417 .keyword_asm,420 .keyword_asm,
418 .keyword_asm1,421 .keyword_asm1,
419 .keyword_asm2,422 .keyword_asm2,
420 .keyword_float80,
421 .keyword_float128_1,423 .keyword_float128_1,
422 .keyword_float128_2,424 .keyword_float128_2,
423 .keyword_int128,425 .keyword_int128,
...@@ -627,6 +629,8 @@ pub const Token = struct {...@@ -627,6 +629,8 @@ pub const Token = struct {
627 .keyword_return => "return",629 .keyword_return => "return",
628 .keyword_short => "short",630 .keyword_short => "short",
629 .keyword_signed => "signed",631 .keyword_signed => "signed",
632 .keyword_signed1 => "__signed",
633 .keyword_signed2 => "__signed__",
630 .keyword_sizeof => "sizeof",634 .keyword_sizeof => "sizeof",
631 .keyword_static => "static",635 .keyword_static => "static",
632 .keyword_struct => "struct",636 .keyword_struct => "struct",
...@@ -702,7 +706,6 @@ pub const Token = struct {...@@ -702,7 +706,6 @@ pub const Token = struct {
702 .keyword_asm => "asm",706 .keyword_asm => "asm",
703 .keyword_asm1 => "__asm",707 .keyword_asm1 => "__asm",
704 .keyword_asm2 => "__asm__",708 .keyword_asm2 => "__asm__",
705 .keyword_float80 => "__float80",
706 .keyword_float128_1 => "_Float128",709 .keyword_float128_1 => "_Float128",
707 .keyword_float128_2 => "__float128",710 .keyword_float128_2 => "__float128",
708 .keyword_int128 => "__int128",711 .keyword_int128 => "__int128",
...@@ -732,7 +735,8 @@ pub const Token = struct {...@@ -732,7 +735,8 @@ pub const Token = struct {
732735
733 pub fn symbol(id: Id) []const u8 {736 pub fn symbol(id: Id) []const u8 {
734 return switch (id) {737 return switch (id) {
735 .macro_string, .invalid => unreachable,738 .macro_string => unreachable,
739 .invalid => "invalid bytes",
736 .identifier,740 .identifier,
737 .extended_identifier,741 .extended_identifier,
738 .macro_func,742 .macro_func,
...@@ -873,10 +877,7 @@ pub const Token = struct {...@@ -873,10 +877,7 @@ pub const Token = struct {
873 }877 }
874878
875 const all_kws = std.StaticStringMap(Id).initComptime(.{879 const all_kws = std.StaticStringMap(Id).initComptime(.{
876 .{ "auto", auto: {880 .{ "auto", .keyword_auto },
877 @setEvalBranchQuota(3000);
878 break :auto .keyword_auto;
879 } },
880 .{ "break", .keyword_break },881 .{ "break", .keyword_break },
881 .{ "case", .keyword_case },882 .{ "case", .keyword_case },
882 .{ "char", .keyword_char },883 .{ "char", .keyword_char },
...@@ -898,6 +899,8 @@ pub const Token = struct {...@@ -898,6 +899,8 @@ pub const Token = struct {
898 .{ "return", .keyword_return },899 .{ "return", .keyword_return },
899 .{ "short", .keyword_short },900 .{ "short", .keyword_short },
900 .{ "signed", .keyword_signed },901 .{ "signed", .keyword_signed },
902 .{ "__signed", .keyword_signed1 },
903 .{ "__signed__", .keyword_signed2 },
901 .{ "sizeof", .keyword_sizeof },904 .{ "sizeof", .keyword_sizeof },
902 .{ "static", .keyword_static },905 .{ "static", .keyword_static },
903 .{ "struct", .keyword_struct },906 .{ "struct", .keyword_struct },
...@@ -982,7 +985,6 @@ pub const Token = struct {...@@ -982,7 +985,6 @@ pub const Token = struct {
982 .{ "asm", .keyword_asm },985 .{ "asm", .keyword_asm },
983 .{ "__asm", .keyword_asm1 },986 .{ "__asm", .keyword_asm1 },
984 .{ "__asm__", .keyword_asm2 },987 .{ "__asm__", .keyword_asm2 },
985 .{ "__float80", .keyword_float80 },
986 .{ "_Float128", .keyword_float128_1 },988 .{ "_Float128", .keyword_float128_1 },
987 .{ "__float128", .keyword_float128_2 },989 .{ "__float128", .keyword_float128_2 },
988 .{ "__int128", .keyword_int128 },990 .{ "__int128", .keyword_int128 },
...@@ -1300,11 +1302,17 @@ pub fn next(self: *Tokenizer) Token {...@@ -1300,11 +1302,17 @@ pub fn next(self: *Tokenizer) Token {
1300 else => {},1302 else => {},
1301 },1303 },
1302 .char_escape_sequence => switch (c) {1304 .char_escape_sequence => switch (c) {
1303 '\r', '\n' => unreachable, // removed by line splicing1305 '\r', '\n' => {
1306 id = .unterminated_char_literal;
1307 break;
1308 },
1304 else => state = .char_literal,1309 else => state = .char_literal,
1305 },1310 },
1306 .string_escape_sequence => switch (c) {1311 .string_escape_sequence => switch (c) {
1307 '\r', '\n' => unreachable, // removed by line splicing1312 '\r', '\n' => {
1313 id = .unterminated_string_literal;
1314 break;
1315 },
1308 else => state = .string_literal,1316 else => state = .string_literal,
1309 },1317 },
1310 .identifier, .extended_identifier => switch (c) {1318 .identifier, .extended_identifier => switch (c) {
...@@ -1792,7 +1800,7 @@ pub fn nextNoWSComments(self: *Tokenizer) Token {...@@ -1792,7 +1800,7 @@ pub fn nextNoWSComments(self: *Tokenizer) Token {
1792/// Try to tokenize a '::' even if not supported by the current language standard.1800/// Try to tokenize a '::' even if not supported by the current language standard.
1793pub fn colonColon(self: *Tokenizer) Token {1801pub fn colonColon(self: *Tokenizer) Token {
1794 var tok = self.nextNoWS();1802 var tok = self.nextNoWS();
1795 if (tok.id == .colon and self.buf[self.index] == ':') {1803 if (tok.id == .colon and self.index < self.buf.len and self.buf[self.index] == ':') {
1796 self.index += 1;1804 self.index += 1;
1797 tok.id = .colon_colon;1805 tok.id = .colon_colon;
1798 }1806 }
...@@ -2142,8 +2150,30 @@ test "C23 keywords" {...@@ -2142,8 +2150,30 @@ test "C23 keywords" {
2142 }, .c23);2150 }, .c23);
2143}2151}
21442152
2153test "Tokenizer fuzz test" {
2154 var comp = Compilation.init(std.testing.allocator, std.fs.cwd());
2155 defer comp.deinit();
2156
2157 const input_bytes = std.testing.fuzzInput(.{});
2158 if (input_bytes.len == 0) return;
2159
2160 const source = try comp.addSourceFromBuffer("fuzz.c", input_bytes);
2161
2162 var tokenizer: Tokenizer = .{
2163 .buf = source.buf,
2164 .source = source.id,
2165 .langopts = comp.langopts,
2166 };
2167 while (true) {
2168 const prev_index = tokenizer.index;
2169 const tok = tokenizer.next();
2170 if (tok.id == .eof) break;
2171 try std.testing.expect(prev_index < tokenizer.index); // ensure that the tokenizer always makes progress
2172 }
2173}
2174
2145fn expectTokensExtra(contents: []const u8, expected_tokens: []const Token.Id, standard: ?LangOpts.Standard) !void {2175fn expectTokensExtra(contents: []const u8, expected_tokens: []const Token.Id, standard: ?LangOpts.Standard) !void {
2146 var comp = Compilation.init(std.testing.allocator);2176 var comp = Compilation.init(std.testing.allocator, std.fs.cwd());
2147 defer comp.deinit();2177 defer comp.deinit();
2148 if (standard) |provided| {2178 if (standard) |provided| {
2149 comp.langopts.standard = provided;2179 comp.langopts.standard = provided;
lib/compiler/aro/aro/Tree.zig+172-76
...@@ -137,15 +137,22 @@ pub const Node = struct {...@@ -137,15 +137,22 @@ pub const Node = struct {
137 tag: Tag,137 tag: Tag,
138 ty: Type = .{ .specifier = .void },138 ty: Type = .{ .specifier = .void },
139 data: Data,139 data: Data,
140 loc: Loc = .none,
140141
141 pub const Range = struct { start: u32, end: u32 };142 pub const Range = struct { start: u32, end: u32 };
142143
144 pub const Loc = enum(u32) {
145 none = std.math.maxInt(u32),
146 _,
147 };
148
143 pub const Data = union {149 pub const Data = union {
144 decl: struct {150 decl: struct {
145 name: TokenIndex,151 name: TokenIndex,
146 node: NodeIndex = .none,152 node: NodeIndex = .none,
147 },153 },
148 decl_ref: TokenIndex,154 decl_ref: TokenIndex,
155 two: [2]NodeIndex,
149 range: Range,156 range: Range,
150 if3: struct {157 if3: struct {
151 cond: NodeIndex,158 cond: NodeIndex,
...@@ -277,7 +284,8 @@ pub const Tag = enum(u8) {...@@ -277,7 +284,8 @@ pub const Tag = enum(u8) {
277284
278 // ====== Decl ======285 // ====== Decl ======
279286
280 // _Static_assert287 /// _Static_assert
288 /// loc is token index of _Static_assert
281 static_assert,289 static_assert,
282290
283 // function prototype291 // function prototype
...@@ -303,17 +311,18 @@ pub const Tag = enum(u8) {...@@ -303,17 +311,18 @@ pub const Tag = enum(u8) {
303 threadlocal_static_var,311 threadlocal_static_var,
304312
305 /// __asm__("...") at file scope313 /// __asm__("...") at file scope
314 /// loc is token index of __asm__ keyword
306 file_scope_asm,315 file_scope_asm,
307316
308 // typedef declaration317 // typedef declaration
309 typedef,318 typedef,
310319
311 // container declarations320 // container declarations
312 /// { lhs; rhs; }321 /// { two[0]; two[1]; }
313 struct_decl_two,322 struct_decl_two,
314 /// { lhs; rhs; }323 /// { two[0]; two[1]; }
315 union_decl_two,324 union_decl_two,
316 /// { lhs, rhs, }325 /// { two[0], two[1], }
317 enum_decl_two,326 enum_decl_two,
318 /// { range }327 /// { range }
319 struct_decl,328 struct_decl,
...@@ -339,7 +348,7 @@ pub const Tag = enum(u8) {...@@ -339,7 +348,7 @@ pub const Tag = enum(u8) {
339 // ====== Stmt ======348 // ====== Stmt ======
340349
341 labeled_stmt,350 labeled_stmt,
342 /// { first; second; } first and second may be null351 /// { two[0]; two[1]; } first and second may be null
343 compound_stmt_two,352 compound_stmt_two,
344 /// { data }353 /// { data }
345 compound_stmt,354 compound_stmt,
...@@ -476,7 +485,7 @@ pub const Tag = enum(u8) {...@@ -476,7 +485,7 @@ pub const Tag = enum(u8) {
476 real_expr,485 real_expr,
477 /// lhs[rhs] lhs is pointer/array type, rhs is integer type486 /// lhs[rhs] lhs is pointer/array type, rhs is integer type
478 array_access_expr,487 array_access_expr,
479 /// first(second) second may be 0488 /// two[0](two[1]) two[1] may be 0
480 call_expr_one,489 call_expr_one,
481 /// data[0](data[1..])490 /// data[0](data[1..])
482 call_expr,491 call_expr,
...@@ -515,7 +524,7 @@ pub const Tag = enum(u8) {...@@ -515,7 +524,7 @@ pub const Tag = enum(u8) {
515 sizeof_expr,524 sizeof_expr,
516 /// _Alignof(un?)525 /// _Alignof(un?)
517 alignof_expr,526 alignof_expr,
518 /// _Generic(controlling lhs, chosen rhs)527 /// _Generic(controlling two[0], chosen two[1])
519 generic_expr_one,528 generic_expr_one,
520 /// _Generic(controlling range[0], chosen range[1], rest range[2..])529 /// _Generic(controlling range[0], chosen range[1], rest range[2..])
521 generic_expr,530 generic_expr,
...@@ -534,28 +543,34 @@ pub const Tag = enum(u8) {...@@ -534,28 +543,34 @@ pub const Tag = enum(u8) {
534543
535 // ====== Initializer expressions ======544 // ====== Initializer expressions ======
536545
537 /// { lhs, rhs }546 /// { two[0], two[1] }
538 array_init_expr_two,547 array_init_expr_two,
539 /// { range }548 /// { range }
540 array_init_expr,549 array_init_expr,
541 /// { lhs, rhs }550 /// { two[0], two[1] }
542 struct_init_expr_two,551 struct_init_expr_two,
543 /// { range }552 /// { range }
544 struct_init_expr,553 struct_init_expr,
545 /// { union_init }554 /// { union_init }
546 union_init_expr,555 union_init_expr,
556
547 /// (ty){ un }557 /// (ty){ un }
558 /// loc is token index of l_paren
548 compound_literal_expr,559 compound_literal_expr,
549 /// (static ty){ un }560 /// (static ty){ un }
561 /// loc is token index of l_paren
550 static_compound_literal_expr,562 static_compound_literal_expr,
551 /// (thread_local ty){ un }563 /// (thread_local ty){ un }
564 /// loc is token index of l_paren
552 thread_local_compound_literal_expr,565 thread_local_compound_literal_expr,
553 /// (static thread_local ty){ un }566 /// (static thread_local ty){ un }
567 /// loc is token index of l_paren
554 static_thread_local_compound_literal_expr,568 static_thread_local_compound_literal_expr,
555569
556 /// Inserted at the end of a function body if no return stmt is found.570 /// Inserted at the end of a function body if no return stmt is found.
557 /// ty is the functions return type571 /// ty is the functions return type
558 /// data is return_zero which is true if the function is called "main" and ty is compatible with int572 /// data is return_zero which is true if the function is called "main" and ty is compatible with int
573 /// loc is token index of closing r_brace of function
559 implicit_return,574 implicit_return,
560575
561 /// Inserted in array_init_expr to represent unspecified elements.576 /// Inserted in array_init_expr to represent unspecified elements.
...@@ -608,6 +623,57 @@ pub fn bitfieldWidth(tree: *const Tree, node: NodeIndex, inspect_lval: bool) ?u3...@@ -608,6 +623,57 @@ pub fn bitfieldWidth(tree: *const Tree, node: NodeIndex, inspect_lval: bool) ?u3
608 }623 }
609}624}
610625
626const CallableResultUsage = struct {
627 /// name token of the thing being called, for diagnostics
628 tok: TokenIndex,
629 /// true if `nodiscard` attribute present
630 nodiscard: bool,
631 /// true if `warn_unused_result` attribute present
632 warn_unused_result: bool,
633};
634
635pub fn callableResultUsage(tree: *const Tree, node: NodeIndex) ?CallableResultUsage {
636 const data = tree.nodes.items(.data);
637
638 var cur_node = node;
639 while (true) switch (tree.nodes.items(.tag)[@intFromEnum(cur_node)]) {
640 .decl_ref_expr => {
641 const tok = data[@intFromEnum(cur_node)].decl_ref;
642 const fn_ty = tree.nodes.items(.ty)[@intFromEnum(node)].elemType();
643 return .{
644 .tok = tok,
645 .nodiscard = fn_ty.hasAttribute(.nodiscard),
646 .warn_unused_result = fn_ty.hasAttribute(.warn_unused_result),
647 };
648 },
649 .paren_expr => cur_node = data[@intFromEnum(cur_node)].un,
650 .comma_expr => cur_node = data[@intFromEnum(cur_node)].bin.rhs,
651
652 .explicit_cast, .implicit_cast => cur_node = data[@intFromEnum(cur_node)].cast.operand,
653 .addr_of_expr, .deref_expr => cur_node = data[@intFromEnum(cur_node)].un,
654 .call_expr_one => cur_node = data[@intFromEnum(cur_node)].two[0],
655 .call_expr => cur_node = tree.data[data[@intFromEnum(cur_node)].range.start],
656 .member_access_expr, .member_access_ptr_expr => {
657 const member = data[@intFromEnum(cur_node)].member;
658 var ty = tree.nodes.items(.ty)[@intFromEnum(member.lhs)];
659 if (ty.isPtr()) ty = ty.elemType();
660 const record = ty.getRecord().?;
661 const field = record.fields[member.index];
662 const attributes = if (record.field_attributes) |attrs| attrs[member.index] else &.{};
663 return .{
664 .tok = field.name_tok,
665 .nodiscard = for (attributes) |attr| {
666 if (attr.tag == .nodiscard) break true;
667 } else false,
668 .warn_unused_result = for (attributes) |attr| {
669 if (attr.tag == .warn_unused_result) break true;
670 } else false,
671 };
672 },
673 else => return null,
674 };
675}
676
611pub fn isLval(tree: *const Tree, node: NodeIndex) bool {677pub fn isLval(tree: *const Tree, node: NodeIndex) bool {
612 var is_const: bool = undefined;678 var is_const: bool = undefined;
613 return tree.isLvalExtra(node, &is_const);679 return tree.isLvalExtra(node, &is_const);
...@@ -672,17 +738,66 @@ pub fn isLvalExtra(tree: *const Tree, node: NodeIndex, is_const: *bool) bool {...@@ -672,17 +738,66 @@ pub fn isLvalExtra(tree: *const Tree, node: NodeIndex, is_const: *bool) bool {
672 }738 }
673}739}
674740
741/// This should only be used for node tags that represent AST nodes which have an arbitrary number of children
742/// It particular it should *not* be used for nodes with .un or .bin data types
743///
744/// For call expressions, child_nodes[0] is the function pointer being called and child_nodes[1..]
745/// are the arguments
746///
747/// For generic selection expressions, child_nodes[0] is the controlling expression,
748/// child_nodes[1] is the chosen expression (it is a syntax error for there to be no chosen expression),
749/// and child_nodes[2..] are the remaining expressions.
750pub fn childNodes(tree: *const Tree, node: NodeIndex) []const NodeIndex {
751 const tags = tree.nodes.items(.tag);
752 const data = tree.nodes.items(.data);
753 switch (tags[@intFromEnum(node)]) {
754 .compound_stmt_two,
755 .array_init_expr_two,
756 .struct_init_expr_two,
757 .enum_decl_two,
758 .struct_decl_two,
759 .union_decl_two,
760 .call_expr_one,
761 .generic_expr_one,
762 => {
763 const index: u32 = @intFromEnum(node);
764 const end = std.mem.indexOfScalar(NodeIndex, &data[index].two, .none) orelse 2;
765 return data[index].two[0..end];
766 },
767 .compound_stmt,
768 .array_init_expr,
769 .struct_init_expr,
770 .enum_decl,
771 .struct_decl,
772 .union_decl,
773 .call_expr,
774 .generic_expr,
775 => {
776 const range = data[@intFromEnum(node)].range;
777 return tree.data[range.start..range.end];
778 },
779 else => unreachable,
780 }
781}
782
675pub fn tokSlice(tree: *const Tree, tok_i: TokenIndex) []const u8 {783pub fn tokSlice(tree: *const Tree, tok_i: TokenIndex) []const u8 {
676 if (tree.tokens.items(.id)[tok_i].lexeme()) |some| return some;784 if (tree.tokens.items(.id)[tok_i].lexeme()) |some| return some;
677 const loc = tree.tokens.items(.loc)[tok_i];785 const loc = tree.tokens.items(.loc)[tok_i];
678 var tmp_tokenizer = Tokenizer{786 return tree.comp.locSlice(loc);
679 .buf = tree.comp.getSource(loc.id).buf,787}
680 .langopts = tree.comp.langopts,788
681 .index = loc.byte_offset,789pub fn nodeTok(tree: *const Tree, node: NodeIndex) ?TokenIndex {
682 .source = .generated,790 std.debug.assert(node != .none);
791 const loc = tree.nodes.items(.loc)[@intFromEnum(node)];
792 return switch (loc) {
793 .none => null,
794 else => |tok_i| @intFromEnum(tok_i),
683 };795 };
684 const tok = tmp_tokenizer.next();796}
685 return tmp_tokenizer.buf[tok.start..tok.end];797
798pub fn nodeLoc(tree: *const Tree, node: NodeIndex) ?Source.Location {
799 const tok_i = tree.nodeTok(node) orelse return null;
800 return tree.tokens.items(.loc)[@intFromEnum(tok_i)];
686}801}
687802
688pub fn dump(tree: *const Tree, config: std.io.tty.Config, writer: anytype) !void {803pub fn dump(tree: *const Tree, config: std.io.tty.Config, writer: anytype) !void {
...@@ -766,6 +881,10 @@ fn dumpNode(...@@ -766,6 +881,10 @@ fn dumpNode(
766 }881 }
767 try config.setColor(w, TYPE);882 try config.setColor(w, TYPE);
768 try w.writeByte('\'');883 try w.writeByte('\'');
884 const name = ty.getName();
885 if (name != .empty) {
886 try w.print("{s}': '", .{mapper.lookup(name)});
887 }
769 try ty.dump(mapper, tree.comp.langopts, w);888 try ty.dump(mapper, tree.comp.langopts, w);
770 try w.writeByte('\'');889 try w.writeByte('\'');
771890
...@@ -794,7 +913,9 @@ fn dumpNode(...@@ -794,7 +913,9 @@ fn dumpNode(
794913
795 if (ty.specifier == .attributed) {914 if (ty.specifier == .attributed) {
796 try config.setColor(w, ATTRIBUTE);915 try config.setColor(w, ATTRIBUTE);
797 for (ty.data.attributed.attributes) |attr| {916 var it = Attribute.Iterator.initType(ty);
917 while (it.next()) |item| {
918 const attr, _ = item;
798 try w.writeByteNTimes(' ', level + half);919 try w.writeByteNTimes(' ', level + half);
799 try w.print("attr: {s}", .{@tagName(attr.tag)});920 try w.print("attr: {s}", .{@tagName(attr.tag)});
800 try tree.dumpAttribute(attr, w);921 try tree.dumpAttribute(attr, w);
...@@ -900,9 +1021,16 @@ fn dumpNode(...@@ -900,9 +1021,16 @@ fn dumpNode(
900 .enum_decl,1021 .enum_decl,
901 .struct_decl,1022 .struct_decl,
902 .union_decl,1023 .union_decl,
1024 .compound_stmt_two,
1025 .array_init_expr_two,
1026 .struct_init_expr_two,
1027 .enum_decl_two,
1028 .struct_decl_two,
1029 .union_decl_two,
903 => {1030 => {
1031 const child_nodes = tree.childNodes(node);
904 const maybe_field_attributes = if (ty.getRecord()) |record| record.field_attributes else null;1032 const maybe_field_attributes = if (ty.getRecord()) |record| record.field_attributes else null;
905 for (tree.data[data.range.start..data.range.end], 0..) |stmt, i| {1033 for (child_nodes, 0..) |stmt, i| {
906 if (i != 0) try w.writeByte('\n');1034 if (i != 0) try w.writeByte('\n');
907 try tree.dumpNode(stmt, level + delta, mapper, config, w);1035 try tree.dumpNode(stmt, level + delta, mapper, config, w);
908 if (maybe_field_attributes) |field_attributes| {1036 if (maybe_field_attributes) |field_attributes| {
...@@ -914,33 +1042,6 @@ fn dumpNode(...@@ -914,33 +1042,6 @@ fn dumpNode(
914 }1042 }
915 }1043 }
916 },1044 },
917 .compound_stmt_two,
918 .array_init_expr_two,
919 .struct_init_expr_two,
920 .enum_decl_two,
921 .struct_decl_two,
922 .union_decl_two,
923 => {
924 var attr_array = [2][]const Attribute{ &.{}, &.{} };
925 const empty: [][]const Attribute = &attr_array;
926 const field_attributes = if (ty.getRecord()) |record| (record.field_attributes orelse empty.ptr) else empty.ptr;
927 if (data.bin.lhs != .none) {
928 try tree.dumpNode(data.bin.lhs, level + delta, mapper, config, w);
929 if (field_attributes[0].len > 0) {
930 try config.setColor(w, ATTRIBUTE);
931 try tree.dumpFieldAttributes(field_attributes[0], level + delta + half, w);
932 try config.setColor(w, .reset);
933 }
934 }
935 if (data.bin.rhs != .none) {
936 try tree.dumpNode(data.bin.rhs, level + delta, mapper, config, w);
937 if (field_attributes[1].len > 0) {
938 try config.setColor(w, ATTRIBUTE);
939 try tree.dumpFieldAttributes(field_attributes[1], level + delta + half, w);
940 try config.setColor(w, .reset);
941 }
942 }
943 },
944 .union_init_expr => {1045 .union_init_expr => {
945 try w.writeByteNTimes(' ', level + half);1046 try w.writeByteNTimes(' ', level + half);
946 try w.writeAll("field index: ");1047 try w.writeAll("field index: ");
...@@ -1130,23 +1231,21 @@ fn dumpNode(...@@ -1130,23 +1231,21 @@ fn dumpNode(
1130 try tree.dumpNode(data.un, level + delta, mapper, config, w);1231 try tree.dumpNode(data.un, level + delta, mapper, config, w);
1131 }1232 }
1132 },1233 },
1133 .call_expr => {1234 .call_expr, .call_expr_one => {
1134 try w.writeByteNTimes(' ', level + half);1235 const child_nodes = tree.childNodes(node);
1135 try w.writeAll("lhs:\n");1236 const fn_ptr = child_nodes[0];
1136 try tree.dumpNode(tree.data[data.range.start], level + delta, mapper, config, w);1237 const args = child_nodes[1..];
11371238
1138 try w.writeByteNTimes(' ', level + half);
1139 try w.writeAll("args:\n");
1140 for (tree.data[data.range.start + 1 .. data.range.end]) |arg| try tree.dumpNode(arg, level + delta, mapper, config, w);
1141 },
1142 .call_expr_one => {
1143 try w.writeByteNTimes(' ', level + half);1239 try w.writeByteNTimes(' ', level + half);
1144 try w.writeAll("lhs:\n");1240 try w.writeAll("lhs:\n");
1145 try tree.dumpNode(data.bin.lhs, level + delta, mapper, config, w);1241 try tree.dumpNode(fn_ptr, level + delta, mapper, config, w);
1146 if (data.bin.rhs != .none) {1242
1243 if (args.len > 0) {
1147 try w.writeByteNTimes(' ', level + half);1244 try w.writeByteNTimes(' ', level + half);
1148 try w.writeAll("arg:\n");1245 try w.writeAll("args:\n");
1149 try tree.dumpNode(data.bin.rhs, level + delta, mapper, config, w);1246 for (args) |arg| {
1247 try tree.dumpNode(arg, level + delta, mapper, config, w);
1248 }
1150 }1249 }
1151 },1250 },
1152 .builtin_call_expr => {1251 .builtin_call_expr => {
...@@ -1295,28 +1394,25 @@ fn dumpNode(...@@ -1295,28 +1394,25 @@ fn dumpNode(
1295 try tree.dumpNode(data.un, level + delta, mapper, config, w);1394 try tree.dumpNode(data.un, level + delta, mapper, config, w);
1296 }1395 }
1297 },1396 },
1298 .generic_expr_one => {1397 .generic_expr, .generic_expr_one => {
1299 try w.writeByteNTimes(' ', level + 1);1398 const child_nodes = tree.childNodes(node);
1300 try w.writeAll("controlling:\n");1399 const controlling = child_nodes[0];
1301 try tree.dumpNode(data.bin.lhs, level + delta, mapper, config, w);1400 const chosen = child_nodes[1];
1302 try w.writeByteNTimes(' ', level + 1);1401 const rest = child_nodes[2..];
1303 if (data.bin.rhs != .none) {1402
1304 try w.writeAll("chosen:\n");
1305 try tree.dumpNode(data.bin.rhs, level + delta, mapper, config, w);
1306 }
1307 },
1308 .generic_expr => {
1309 const nodes = tree.data[data.range.start..data.range.end];
1310 try w.writeByteNTimes(' ', level + 1);1403 try w.writeByteNTimes(' ', level + 1);
1311 try w.writeAll("controlling:\n");1404 try w.writeAll("controlling:\n");
1312 try tree.dumpNode(nodes[0], level + delta, mapper, config, w);1405 try tree.dumpNode(controlling, level + delta, mapper, config, w);
1313 try w.writeByteNTimes(' ', level + 1);1406 try w.writeByteNTimes(' ', level + 1);
1314 try w.writeAll("chosen:\n");1407 try w.writeAll("chosen:\n");
1315 try tree.dumpNode(nodes[1], level + delta, mapper, config, w);1408 try tree.dumpNode(chosen, level + delta, mapper, config, w);
1316 try w.writeByteNTimes(' ', level + 1);1409
1317 try w.writeAll("rest:\n");1410 if (rest.len > 0) {
1318 for (nodes[2..]) |expr| {1411 try w.writeByteNTimes(' ', level + 1);
1319 try tree.dumpNode(expr, level + delta, mapper, config, w);1412 try w.writeAll("rest:\n");
1413 for (rest) |expr| {
1414 try tree.dumpNode(expr, level + delta, mapper, config, w);
1415 }
1320 }1416 }
1321 },1417 },
1322 .generic_association_expr, .generic_default_expr, .stmt_expr, .imaginary_literal => {1418 .generic_association_expr, .generic_default_expr, .stmt_expr, .imaginary_literal => {
lib/compiler/aro/aro/Tree/number_affixes.zig+9-4
...@@ -74,8 +74,8 @@ pub const Suffix = enum {...@@ -74,8 +74,8 @@ pub const Suffix = enum {
74 // float and imaginary float74 // float and imaginary float
75 F, IF,75 F, IF,
7676
77 // _Float1677 // _Float16 and imaginary _Float16
78 F16,78 F16, IF16,
7979
80 // __float8080 // __float80
81 W,81 W,
...@@ -129,6 +129,7 @@ pub const Suffix = enum {...@@ -129,6 +129,7 @@ pub const Suffix = enum {
129129
130 .{ .I, &.{"I"} },130 .{ .I, &.{"I"} },
131 .{ .IL, &.{ "I", "L" } },131 .{ .IL, &.{ "I", "L" } },
132 .{ .IF16, &.{ "I", "F16" } },
132 .{ .IF, &.{ "I", "F" } },133 .{ .IF, &.{ "I", "F" } },
133 .{ .IW, &.{ "I", "W" } },134 .{ .IW, &.{ "I", "W" } },
134 .{ .IF128, &.{ "I", "F128" } },135 .{ .IF128, &.{ "I", "F128" } },
...@@ -161,7 +162,7 @@ pub const Suffix = enum {...@@ -161,7 +162,7 @@ pub const Suffix = enum {
161162
162 pub fn isImaginary(suffix: Suffix) bool {163 pub fn isImaginary(suffix: Suffix) bool {
163 return switch (suffix) {164 return switch (suffix) {
164 .I, .IL, .IF, .IU, .IUL, .ILL, .IULL, .IWB, .IUWB, .IF128, .IQ, .IW => true,165 .I, .IL, .IF, .IU, .IUL, .ILL, .IULL, .IWB, .IUWB, .IF128, .IQ, .IW, .IF16 => true,
165 .None, .L, .F16, .F, .U, .UL, .LL, .ULL, .WB, .UWB, .F128, .Q, .W => false,166 .None, .L, .F16, .F, .U, .UL, .LL, .ULL, .WB, .UWB, .F128, .Q, .W => false,
166 };167 };
167 }168 }
...@@ -170,7 +171,7 @@ pub const Suffix = enum {...@@ -170,7 +171,7 @@ pub const Suffix = enum {
170 return switch (suffix) {171 return switch (suffix) {
171 .None, .L, .LL, .I, .IL, .ILL, .WB, .IWB => true,172 .None, .L, .LL, .I, .IL, .ILL, .WB, .IWB => true,
172 .U, .UL, .ULL, .IU, .IUL, .IULL, .UWB, .IUWB => false,173 .U, .UL, .ULL, .IU, .IUL, .IULL, .UWB, .IUWB => false,
173 .F, .IF, .F16, .F128, .IF128, .Q, .IQ, .W, .IW => unreachable,174 .F, .IF, .F16, .F128, .IF128, .Q, .IQ, .W, .IW, .IF16 => unreachable,
174 };175 };
175 }176 }
176177
...@@ -184,4 +185,8 @@ pub const Suffix = enum {...@@ -184,4 +185,8 @@ pub const Suffix = enum {
184 else => false,185 else => false,
185 };186 };
186 }187 }
188
189 pub fn isFloat80(suffix: Suffix) bool {
190 return suffix == .W or suffix == .IW;
191 }
187};192};
lib/compiler/aro/aro/Type.zig+170-170
...@@ -146,17 +146,14 @@ pub const Attributed = struct {...@@ -146,17 +146,14 @@ pub const Attributed = struct {
146 attributes: []Attribute,146 attributes: []Attribute,
147 base: Type,147 base: Type,
148148
149 pub fn create(allocator: std.mem.Allocator, base: Type, existing_attributes: []const Attribute, attributes: []const Attribute) !*Attributed {149 pub fn create(allocator: std.mem.Allocator, base_ty: Type, attributes: []const Attribute) !*Attributed {
150 const attributed_type = try allocator.create(Attributed);150 const attributed_type = try allocator.create(Attributed);
151 errdefer allocator.destroy(attributed_type);151 errdefer allocator.destroy(attributed_type);
152152 const duped = try allocator.dupe(Attribute, attributes);
153 const all_attrs = try allocator.alloc(Attribute, existing_attributes.len + attributes.len);
154 @memcpy(all_attrs[0..existing_attributes.len], existing_attributes);
155 @memcpy(all_attrs[existing_attributes.len..], attributes);
156153
157 attributed_type.* = .{154 attributed_type.* = .{
158 .attributes = all_attrs,155 .attributes = duped,
159 .base = base,156 .base = base_ty,
160 };157 };
161 return attributed_type;158 return attributed_type;
162 }159 }
...@@ -190,13 +187,10 @@ pub const Enum = struct {...@@ -190,13 +187,10 @@ pub const Enum = struct {
190 }187 }
191};188};
192189
193// might not need all 4 of these when finished,
194// but currently it helps having all 4 when diff-ing
195// the rust code.
196pub const TypeLayout = struct {190pub const TypeLayout = struct {
197 /// The size of the type in bits.191 /// The size of the type in bits.
198 ///192 ///
199 /// This is the value returned by `sizeof` and C and `std::mem::size_of` in Rust193 /// This is the value returned by `sizeof` in C
200 /// (but in bits instead of bytes). This is a multiple of `pointer_alignment_bits`.194 /// (but in bits instead of bytes). This is a multiple of `pointer_alignment_bits`.
201 size_bits: u64,195 size_bits: u64,
202 /// The alignment of the type, in bits, when used as a field in a record.196 /// The alignment of the type, in bits, when used as a field in a record.
...@@ -205,9 +199,7 @@ pub const TypeLayout = struct {...@@ -205,9 +199,7 @@ pub const TypeLayout = struct {
205 /// cases in GCC where `_Alignof` returns a smaller value.199 /// cases in GCC where `_Alignof` returns a smaller value.
206 field_alignment_bits: u32,200 field_alignment_bits: u32,
207 /// The alignment, in bits, of valid pointers to this type.201 /// The alignment, in bits, of valid pointers to this type.
208 ///202 /// `size_bits` is a multiple of this value.
209 /// This is the value returned by `std::mem::align_of` in Rust
210 /// (but in bits instead of bytes). `size_bits` is a multiple of this value.
211 pointer_alignment_bits: u32,203 pointer_alignment_bits: u32,
212 /// The required alignment of the type in bits.204 /// The required alignment of the type in bits.
213 ///205 ///
...@@ -301,6 +293,15 @@ pub const Record = struct {...@@ -301,6 +293,15 @@ pub const Record = struct {
301 }293 }
302 return false;294 return false;
303 }295 }
296
297 pub fn hasField(self: *const Record, name: StringId) bool {
298 std.debug.assert(!self.isIncomplete());
299 for (self.fields) |f| {
300 if (f.isAnonymousRecord() and f.ty.getRecord().?.hasField(name)) return true;
301 if (name == f.name) return true;
302 }
303 return false;
304 }
304};305};
305306
306pub const Specifier = enum {307pub const Specifier = enum {
...@@ -354,12 +355,11 @@ pub const Specifier = enum {...@@ -354,12 +355,11 @@ pub const Specifier = enum {
354 float,355 float,
355 double,356 double,
356 long_double,357 long_double,
357 float80,
358 float128,358 float128,
359 complex_float16,
359 complex_float,360 complex_float,
360 complex_double,361 complex_double,
361 complex_long_double,362 complex_long_double,
362 complex_float80,
363 complex_float128,363 complex_float128,
364364
365 // data.sub_type365 // data.sub_type
...@@ -422,6 +422,8 @@ data: union {...@@ -422,6 +422,8 @@ data: union {
422specifier: Specifier,422specifier: Specifier,
423qual: Qualifiers = .{},423qual: Qualifiers = .{},
424decayed: bool = false,424decayed: bool = false,
425/// typedef name, if any
426name: StringId = .empty,
425427
426pub const int = Type{ .specifier = .int };428pub const int = Type{ .specifier = .int };
427pub const invalid = Type{ .specifier = .invalid };429pub const invalid = Type{ .specifier = .invalid };
...@@ -435,8 +437,8 @@ pub fn is(ty: Type, specifier: Specifier) bool {...@@ -435,8 +437,8 @@ pub fn is(ty: Type, specifier: Specifier) bool {
435437
436pub fn withAttributes(self: Type, allocator: std.mem.Allocator, attributes: []const Attribute) !Type {438pub fn withAttributes(self: Type, allocator: std.mem.Allocator, attributes: []const Attribute) !Type {
437 if (attributes.len == 0) return self;439 if (attributes.len == 0) return self;
438 const attributed_type = try Type.Attributed.create(allocator, self, self.getAttributes(), attributes);440 const attributed_type = try Type.Attributed.create(allocator, self, attributes);
439 return Type{ .specifier = .attributed, .data = .{ .attributed = attributed_type }, .decayed = self.decayed };441 return .{ .specifier = .attributed, .data = .{ .attributed = attributed_type }, .decayed = self.decayed };
440}442}
441443
442pub fn isCallable(ty: Type) ?Type {444pub fn isCallable(ty: Type) ?Type {
...@@ -470,6 +472,23 @@ pub fn isArray(ty: Type) bool {...@@ -470,6 +472,23 @@ pub fn isArray(ty: Type) bool {
470 };472 };
471}473}
472474
475/// Must only be used to set the length of an incomplete array as determined by its initializer
476pub fn setIncompleteArrayLen(ty: *Type, len: u64) void {
477 switch (ty.specifier) {
478 .incomplete_array => {
479 // Modifying .data is exceptionally allowed for .incomplete_array.
480 ty.data.array.len = len;
481 ty.specifier = .array;
482 },
483
484 .typeof_type => ty.data.sub_type.setIncompleteArrayLen(len),
485 .typeof_expr => ty.data.expr.ty.setIncompleteArrayLen(len),
486 .attributed => ty.data.attributed.base.setIncompleteArrayLen(len),
487
488 else => unreachable,
489 }
490}
491
473/// Whether the type is promoted if used as a variadic argument or as an argument to a function with no prototype492/// Whether the type is promoted if used as a variadic argument or as an argument to a function with no prototype
474fn undergoesDefaultArgPromotion(ty: Type, comp: *const Compilation) bool {493fn undergoesDefaultArgPromotion(ty: Type, comp: *const Compilation) bool {
475 return switch (ty.specifier) {494 return switch (ty.specifier) {
...@@ -536,7 +555,7 @@ pub fn isFloat(ty: Type) bool {...@@ -536,7 +555,7 @@ pub fn isFloat(ty: Type) bool {
536 return switch (ty.specifier) {555 return switch (ty.specifier) {
537 // zig fmt: off556 // zig fmt: off
538 .float, .double, .long_double, .complex_float, .complex_double, .complex_long_double,557 .float, .double, .long_double, .complex_float, .complex_double, .complex_long_double,
539 .fp16, .float16, .float80, .float128, .complex_float80, .complex_float128 => true,558 .fp16, .float16, .float128, .complex_float128, .complex_float16 => true,
540 // zig fmt: on559 // zig fmt: on
541 .typeof_type => ty.data.sub_type.isFloat(),560 .typeof_type => ty.data.sub_type.isFloat(),
542 .typeof_expr => ty.data.expr.ty.isFloat(),561 .typeof_expr => ty.data.expr.ty.isFloat(),
...@@ -548,11 +567,11 @@ pub fn isFloat(ty: Type) bool {...@@ -548,11 +567,11 @@ pub fn isFloat(ty: Type) bool {
548pub fn isReal(ty: Type) bool {567pub fn isReal(ty: Type) bool {
549 return switch (ty.specifier) {568 return switch (ty.specifier) {
550 // zig fmt: off569 // zig fmt: off
551 .complex_float, .complex_double, .complex_long_double, .complex_float80,570 .complex_float, .complex_double, .complex_long_double,
552 .complex_float128, .complex_char, .complex_schar, .complex_uchar, .complex_short,571 .complex_float128, .complex_char, .complex_schar, .complex_uchar, .complex_short,
553 .complex_ushort, .complex_int, .complex_uint, .complex_long, .complex_ulong,572 .complex_ushort, .complex_int, .complex_uint, .complex_long, .complex_ulong,
554 .complex_long_long, .complex_ulong_long, .complex_int128, .complex_uint128,573 .complex_long_long, .complex_ulong_long, .complex_int128, .complex_uint128,
555 .complex_bit_int => false,574 .complex_bit_int, .complex_float16 => false,
556 // zig fmt: on575 // zig fmt: on
557 .typeof_type => ty.data.sub_type.isReal(),576 .typeof_type => ty.data.sub_type.isReal(),
558 .typeof_expr => ty.data.expr.ty.isReal(),577 .typeof_expr => ty.data.expr.ty.isReal(),
...@@ -564,11 +583,11 @@ pub fn isReal(ty: Type) bool {...@@ -564,11 +583,11 @@ pub fn isReal(ty: Type) bool {
564pub fn isComplex(ty: Type) bool {583pub fn isComplex(ty: Type) bool {
565 return switch (ty.specifier) {584 return switch (ty.specifier) {
566 // zig fmt: off585 // zig fmt: off
567 .complex_float, .complex_double, .complex_long_double, .complex_float80,586 .complex_float, .complex_double, .complex_long_double,
568 .complex_float128, .complex_char, .complex_schar, .complex_uchar, .complex_short,587 .complex_float128, .complex_char, .complex_schar, .complex_uchar, .complex_short,
569 .complex_ushort, .complex_int, .complex_uint, .complex_long, .complex_ulong,588 .complex_ushort, .complex_int, .complex_uint, .complex_long, .complex_ulong,
570 .complex_long_long, .complex_ulong_long, .complex_int128, .complex_uint128,589 .complex_long_long, .complex_ulong_long, .complex_int128, .complex_uint128,
571 .complex_bit_int => true,590 .complex_bit_int, .complex_float16 => true,
572 // zig fmt: on591 // zig fmt: on
573 .typeof_type => ty.data.sub_type.isComplex(),592 .typeof_type => ty.data.sub_type.isComplex(),
574 .typeof_expr => ty.data.expr.ty.isComplex(),593 .typeof_expr => ty.data.expr.ty.isComplex(),
...@@ -671,11 +690,11 @@ pub fn elemType(ty: Type) Type {...@@ -671,11 +690,11 @@ pub fn elemType(ty: Type) Type {
671 .attributed => ty.data.attributed.base.elemType(),690 .attributed => ty.data.attributed.base.elemType(),
672 .invalid => Type.invalid,691 .invalid => Type.invalid,
673 // zig fmt: off692 // zig fmt: off
674 .complex_float, .complex_double, .complex_long_double, .complex_float80,693 .complex_float, .complex_double, .complex_long_double,
675 .complex_float128, .complex_char, .complex_schar, .complex_uchar, .complex_short,694 .complex_float128, .complex_char, .complex_schar, .complex_uchar, .complex_short,
676 .complex_ushort, .complex_int, .complex_uint, .complex_long, .complex_ulong,695 .complex_ushort, .complex_int, .complex_uint, .complex_long, .complex_ulong,
677 .complex_long_long, .complex_ulong_long, .complex_int128, .complex_uint128,696 .complex_long_long, .complex_ulong_long, .complex_int128, .complex_uint128,
678 .complex_bit_int => ty.makeReal(),697 .complex_bit_int, .complex_float16 => ty.makeReal(),
679 // zig fmt: on698 // zig fmt: on
680 else => unreachable,699 else => unreachable,
681 };700 };
...@@ -703,6 +722,16 @@ pub fn params(ty: Type) []Func.Param {...@@ -703,6 +722,16 @@ pub fn params(ty: Type) []Func.Param {
703 };722 };
704}723}
705724
725/// Returns true if the return value or any param of `ty` is `.invalid`
726/// Asserts that ty is a function type
727pub fn isInvalidFunc(ty: Type) bool {
728 if (ty.returnType().is(.invalid)) return true;
729 for (ty.params()) |param| {
730 if (param.ty.is(.invalid)) return true;
731 }
732 return false;
733}
734
706pub fn arrayLen(ty: Type) ?u64 {735pub fn arrayLen(ty: Type) ?u64 {
707 return switch (ty.specifier) {736 return switch (ty.specifier) {
708 .array, .static_array => ty.data.array.len,737 .array, .static_array => ty.data.array.len,
...@@ -726,15 +755,6 @@ pub fn anyQual(ty: Type) bool {...@@ -726,15 +755,6 @@ pub fn anyQual(ty: Type) bool {
726 };755 };
727}756}
728757
729pub fn getAttributes(ty: Type) []const Attribute {
730 return switch (ty.specifier) {
731 .attributed => ty.data.attributed.attributes,
732 .typeof_type => ty.data.sub_type.getAttributes(),
733 .typeof_expr => ty.data.expr.ty.getAttributes(),
734 else => &.{},
735 };
736}
737
738pub fn getRecord(ty: Type) ?*const Type.Record {758pub fn getRecord(ty: Type) ?*const Type.Record {
739 return switch (ty.specifier) {759 return switch (ty.specifier) {
740 .attributed => ty.data.attributed.base.getRecord(),760 .attributed => ty.data.attributed.base.getRecord(),
...@@ -795,8 +815,8 @@ fn realIntegerConversion(a: Type, b: Type, comp: *const Compilation) Type {...@@ -795,8 +815,8 @@ fn realIntegerConversion(a: Type, b: Type, comp: *const Compilation) Type {
795815
796pub fn makeIntegerUnsigned(ty: Type) Type {816pub fn makeIntegerUnsigned(ty: Type) Type {
797 // TODO discards attributed/typeof817 // TODO discards attributed/typeof
798 var base = ty.canonicalize(.standard);818 var base_ty = ty.canonicalize(.standard);
799 switch (base.specifier) {819 switch (base_ty.specifier) {
800 // zig fmt: off820 // zig fmt: off
801 .uchar, .ushort, .uint, .ulong, .ulong_long, .uint128,821 .uchar, .ushort, .uint, .ulong, .ulong_long, .uint128,
802 .complex_uchar, .complex_ushort, .complex_uint, .complex_ulong, .complex_ulong_long, .complex_uint128,822 .complex_uchar, .complex_ushort, .complex_uint, .complex_ulong, .complex_ulong_long, .complex_uint128,
...@@ -804,21 +824,21 @@ pub fn makeIntegerUnsigned(ty: Type) Type {...@@ -804,21 +824,21 @@ pub fn makeIntegerUnsigned(ty: Type) Type {
804 // zig fmt: on824 // zig fmt: on
805825
806 .char, .complex_char => {826 .char, .complex_char => {
807 base.specifier = @enumFromInt(@intFromEnum(base.specifier) + 2);827 base_ty.specifier = @enumFromInt(@intFromEnum(base_ty.specifier) + 2);
808 return base;828 return base_ty;
809 },829 },
810830
811 // zig fmt: off831 // zig fmt: off
812 .schar, .short, .int, .long, .long_long, .int128,832 .schar, .short, .int, .long, .long_long, .int128,
813 .complex_schar, .complex_short, .complex_int, .complex_long, .complex_long_long, .complex_int128 => {833 .complex_schar, .complex_short, .complex_int, .complex_long, .complex_long_long, .complex_int128 => {
814 base.specifier = @enumFromInt(@intFromEnum(base.specifier) + 1);834 base_ty.specifier = @enumFromInt(@intFromEnum(base_ty.specifier) + 1);
815 return base;835 return base_ty;
816 },836 },
817 // zig fmt: on837 // zig fmt: on
818838
819 .bit_int, .complex_bit_int => {839 .bit_int, .complex_bit_int => {
820 base.data.int.signedness = .unsigned;840 base_ty.data.int.signedness = .unsigned;
821 return base;841 return base_ty;
822 },842 },
823 else => unreachable,843 else => unreachable,
824 }844 }
...@@ -837,6 +857,8 @@ pub fn integerPromotion(ty: Type, comp: *Compilation) Type {...@@ -837,6 +857,8 @@ pub fn integerPromotion(ty: Type, comp: *Compilation) Type {
837 switch (specifier) {857 switch (specifier) {
838 .@"enum" => {858 .@"enum" => {
839 if (ty.hasIncompleteSize()) return .{ .specifier = .int };859 if (ty.hasIncompleteSize()) return .{ .specifier = .int };
860 if (ty.data.@"enum".fixed) return ty.data.@"enum".tag_ty.integerPromotion(comp);
861
840 specifier = ty.data.@"enum".tag_ty.specifier;862 specifier = ty.data.@"enum".tag_ty.specifier;
841 },863 },
842 .bit_int, .complex_bit_int => return .{ .specifier = specifier, .data = ty.data },864 .bit_int, .complex_bit_int => return .{ .specifier = specifier, .data = ty.data },
...@@ -915,53 +937,7 @@ pub fn hasUnboundVLA(ty: Type) bool {...@@ -915,53 +937,7 @@ pub fn hasUnboundVLA(ty: Type) bool {
915}937}
916938
917pub fn hasField(ty: Type, name: StringId) bool {939pub fn hasField(ty: Type, name: StringId) bool {
918 switch (ty.specifier) {940 return ty.getRecord().?.hasField(name);
919 .@"struct" => {
920 std.debug.assert(!ty.data.record.isIncomplete());
921 for (ty.data.record.fields) |f| {
922 if (f.isAnonymousRecord() and f.ty.hasField(name)) return true;
923 if (name == f.name) return true;
924 }
925 },
926 .@"union" => {
927 std.debug.assert(!ty.data.record.isIncomplete());
928 for (ty.data.record.fields) |f| {
929 if (f.isAnonymousRecord() and f.ty.hasField(name)) return true;
930 if (name == f.name) return true;
931 }
932 },
933 .typeof_type => return ty.data.sub_type.hasField(name),
934 .typeof_expr => return ty.data.expr.ty.hasField(name),
935 .attributed => return ty.data.attributed.base.hasField(name),
936 .invalid => return false,
937 else => unreachable,
938 }
939 return false;
940}
941
942// TODO handle bitints
943pub fn minInt(ty: Type, comp: *const Compilation) i64 {
944 std.debug.assert(ty.isInt());
945 if (ty.isUnsignedInt(comp)) return 0;
946 return switch (ty.sizeof(comp).?) {
947 1 => std.math.minInt(i8),
948 2 => std.math.minInt(i16),
949 4 => std.math.minInt(i32),
950 8 => std.math.minInt(i64),
951 else => unreachable,
952 };
953}
954
955// TODO handle bitints
956pub fn maxInt(ty: Type, comp: *const Compilation) u64 {
957 std.debug.assert(ty.isInt());
958 return switch (ty.sizeof(comp).?) {
959 1 => if (ty.isUnsignedInt(comp)) @as(u64, std.math.maxInt(u8)) else std.math.maxInt(i8),
960 2 => if (ty.isUnsignedInt(comp)) @as(u64, std.math.maxInt(u16)) else std.math.maxInt(i16),
961 4 => if (ty.isUnsignedInt(comp)) @as(u64, std.math.maxInt(u32)) else std.math.maxInt(i32),
962 8 => if (ty.isUnsignedInt(comp)) @as(u64, std.math.maxInt(u64)) else std.math.maxInt(i64),
963 else => unreachable,
964 };
965}941}
966942
967const TypeSizeOrder = enum {943const TypeSizeOrder = enum {
...@@ -1004,16 +980,15 @@ pub fn sizeof(ty: Type, comp: *const Compilation) ?u64 {...@@ -1004,16 +980,15 @@ pub fn sizeof(ty: Type, comp: *const Compilation) ?u64 {
1004 .fp16, .float16 => 2,980 .fp16, .float16 => 2,
1005 .float => comp.target.cTypeByteSize(.float),981 .float => comp.target.cTypeByteSize(.float),
1006 .double => comp.target.cTypeByteSize(.double),982 .double => comp.target.cTypeByteSize(.double),
1007 .float80 => 16,
1008 .float128 => 16,983 .float128 => 16,
1009 .bit_int => {984 .bit_int => {
1010 return std.mem.alignForward(u64, (ty.data.int.bits + 7) / 8, ty.alignof(comp));985 return std.mem.alignForward(u64, (@as(u32, ty.data.int.bits) + 7) / 8, ty.alignof(comp));
1011 },986 },
1012 // zig fmt: off987 // zig fmt: off
1013 .complex_char, .complex_schar, .complex_uchar, .complex_short, .complex_ushort, .complex_int,988 .complex_char, .complex_schar, .complex_uchar, .complex_short, .complex_ushort, .complex_int,
1014 .complex_uint, .complex_long, .complex_ulong, .complex_long_long, .complex_ulong_long,989 .complex_uint, .complex_long, .complex_ulong, .complex_long_long, .complex_ulong_long,
1015 .complex_int128, .complex_uint128, .complex_float, .complex_double,990 .complex_int128, .complex_uint128, .complex_float, .complex_double,
1016 .complex_long_double, .complex_float80, .complex_float128, .complex_bit_int,991 .complex_long_double, .complex_float128, .complex_bit_int, .complex_float16,
1017 => return 2 * ty.makeReal().sizeof(comp).?,992 => return 2 * ty.makeReal().sizeof(comp).?,
1018 // zig fmt: on993 // zig fmt: on
1019 .pointer => unreachable,994 .pointer => unreachable,
...@@ -1050,7 +1025,6 @@ pub fn bitSizeof(ty: Type, comp: *const Compilation) ?u64 {...@@ -1050,7 +1025,6 @@ pub fn bitSizeof(ty: Type, comp: *const Compilation) ?u64 {
1050 .attributed => ty.data.attributed.base.bitSizeof(comp),1025 .attributed => ty.data.attributed.base.bitSizeof(comp),
1051 .bit_int => return ty.data.int.bits,1026 .bit_int => return ty.data.int.bits,
1052 .long_double => comp.target.cTypeBitSize(.longdouble),1027 .long_double => comp.target.cTypeBitSize(.longdouble),
1053 .float80 => return 80,
1054 else => 8 * (ty.sizeof(comp) orelse return null),1028 else => 8 * (ty.sizeof(comp) orelse return null),
1055 };1029 };
1056}1030}
...@@ -1100,7 +1074,7 @@ pub fn alignof(ty: Type, comp: *const Compilation) u29 {...@@ -1100,7 +1074,7 @@ pub fn alignof(ty: Type, comp: *const Compilation) u29 {
1100 .complex_char, .complex_schar, .complex_uchar, .complex_short, .complex_ushort, .complex_int,1074 .complex_char, .complex_schar, .complex_uchar, .complex_short, .complex_ushort, .complex_int,
1101 .complex_uint, .complex_long, .complex_ulong, .complex_long_long, .complex_ulong_long,1075 .complex_uint, .complex_long, .complex_ulong, .complex_long_long, .complex_ulong_long,
1102 .complex_int128, .complex_uint128, .complex_float, .complex_double,1076 .complex_int128, .complex_uint128, .complex_float, .complex_double,
1103 .complex_long_double, .complex_float80, .complex_float128, .complex_bit_int,1077 .complex_long_double, .complex_float128, .complex_bit_int, .complex_float16,
1104 => return ty.makeReal().alignof(comp),1078 => return ty.makeReal().alignof(comp),
1105 // zig fmt: on1079 // zig fmt: on
11061080
...@@ -1114,10 +1088,15 @@ pub fn alignof(ty: Type, comp: *const Compilation) u29 {...@@ -1114,10 +1088,15 @@ pub fn alignof(ty: Type, comp: *const Compilation) u29 {
1114 .long_long => comp.target.cTypeAlignment(.longlong),1088 .long_long => comp.target.cTypeAlignment(.longlong),
1115 .ulong_long => comp.target.cTypeAlignment(.ulonglong),1089 .ulong_long => comp.target.cTypeAlignment(.ulonglong),
11161090
1117 .bit_int => @min(1091 .bit_int => {
1118 std.math.ceilPowerOfTwoPromote(u16, (ty.data.int.bits + 7) / 8),1092 // https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2709.pdf
1119 16, // comp.target.maxIntAlignment(), please use your own logic for this value as it is implementation-defined1093 // _BitInt(N) types align with existing calling conventions. They have the same size and alignment as the
1120 ),1094 // smallest basic type that can contain them. Types that are larger than __int64_t are conceptually treated
1095 // as struct of register size chunks. The number of chunks is the smallest number that can contain the type.
1096 if (ty.data.int.bits > 64) return 8;
1097 const basic_type = comp.intLeastN(ty.data.int.bits, ty.data.int.signedness);
1098 return basic_type.alignof(comp);
1099 },
11211100
1122 .float => comp.target.cTypeAlignment(.float),1101 .float => comp.target.cTypeAlignment(.float),
1123 .double => comp.target.cTypeAlignment(.double),1102 .double => comp.target.cTypeAlignment(.double),
...@@ -1126,7 +1105,7 @@ pub fn alignof(ty: Type, comp: *const Compilation) u29 {...@@ -1126,7 +1105,7 @@ pub fn alignof(ty: Type, comp: *const Compilation) u29 {
1126 .int128, .uint128 => if (comp.target.cpu.arch == .s390x and comp.target.os.tag == .linux and comp.target.isGnu()) 8 else 16,1105 .int128, .uint128 => if (comp.target.cpu.arch == .s390x and comp.target.os.tag == .linux and comp.target.isGnu()) 8 else 16,
1127 .fp16, .float16 => 2,1106 .fp16, .float16 => 2,
11281107
1129 .float80, .float128 => 16,1108 .float128 => 16,
1130 .pointer,1109 .pointer,
1131 .static_array,1110 .static_array,
1132 .nullptr_t,1111 .nullptr_t,
...@@ -1142,7 +1121,11 @@ pub fn alignof(ty: Type, comp: *const Compilation) u29 {...@@ -1142,7 +1121,11 @@ pub fn alignof(ty: Type, comp: *const Compilation) u29 {
1142 };1121 };
1143}1122}
11441123
1145pub const QualHandling = enum { standard, preserve_quals };1124// This enum should be kept public because it is used by the downstream zig translate-c
1125pub const QualHandling = enum {
1126 standard,
1127 preserve_quals,
1128};
11461129
1147/// Canonicalize a possibly-typeof() type. If the type is not a typeof() type, simply1130/// Canonicalize a possibly-typeof() type. If the type is not a typeof() type, simply
1148/// return it. Otherwise, determine the actual qualified type.1131/// return it. Otherwise, determine the actual qualified type.
...@@ -1151,17 +1134,12 @@ pub const QualHandling = enum { standard, preserve_quals };...@@ -1151,17 +1134,12 @@ pub const QualHandling = enum { standard, preserve_quals };
1151/// arrays and pointers.1134/// arrays and pointers.
1152pub fn canonicalize(ty: Type, qual_handling: QualHandling) Type {1135pub fn canonicalize(ty: Type, qual_handling: QualHandling) Type {
1153 var cur = ty;1136 var cur = ty;
1154 if (cur.specifier == .attributed) {
1155 cur = cur.data.attributed.base;
1156 cur.decayed = ty.decayed;
1157 }
1158 if (!cur.isTypeof()) return cur;
1159
1160 var qual = cur.qual;1137 var qual = cur.qual;
1161 while (true) {1138 while (true) {
1162 switch (cur.specifier) {1139 switch (cur.specifier) {
1163 .typeof_type => cur = cur.data.sub_type.*,1140 .typeof_type => cur = cur.data.sub_type.*,
1164 .typeof_expr => cur = cur.data.expr.ty,1141 .typeof_expr => cur = cur.data.expr.ty,
1142 .attributed => cur = cur.data.attributed.base,
1165 else => break,1143 else => break,
1166 }1144 }
1167 qual = qual.mergeAll(cur.qual);1145 qual = qual.mergeAll(cur.qual);
...@@ -1189,7 +1167,7 @@ pub fn requestedAlignment(ty: Type, comp: *const Compilation) ?u29 {...@@ -1189,7 +1167,7 @@ pub fn requestedAlignment(ty: Type, comp: *const Compilation) ?u29 {
1189 return switch (ty.specifier) {1167 return switch (ty.specifier) {
1190 .typeof_type => ty.data.sub_type.requestedAlignment(comp),1168 .typeof_type => ty.data.sub_type.requestedAlignment(comp),
1191 .typeof_expr => ty.data.expr.ty.requestedAlignment(comp),1169 .typeof_expr => ty.data.expr.ty.requestedAlignment(comp),
1192 .attributed => annotationAlignment(comp, ty.data.attributed.attributes),1170 .attributed => annotationAlignment(comp, Attribute.Iterator.initType(ty)),
1193 else => null,1171 else => null,
1194 };1172 };
1195}1173}
...@@ -1199,12 +1177,27 @@ pub fn enumIsPacked(ty: Type, comp: *const Compilation) bool {...@@ -1199,12 +1177,27 @@ pub fn enumIsPacked(ty: Type, comp: *const Compilation) bool {
1199 return comp.langopts.short_enums or target_util.packAllEnums(comp.target) or ty.hasAttribute(.@"packed");1177 return comp.langopts.short_enums or target_util.packAllEnums(comp.target) or ty.hasAttribute(.@"packed");
1200}1178}
12011179
1202pub fn annotationAlignment(comp: *const Compilation, attrs: ?[]const Attribute) ?u29 {1180pub fn getName(ty: Type) StringId {
1203 const a = attrs orelse return null;1181 return switch (ty.specifier) {
1182 .typeof_type => if (ty.name == .empty) ty.data.sub_type.getName() else ty.name,
1183 .typeof_expr => if (ty.name == .empty) ty.data.expr.ty.getName() else ty.name,
1184 .attributed => if (ty.name == .empty) ty.data.attributed.base.getName() else ty.name,
1185 else => ty.name,
1186 };
1187}
12041188
1189pub fn annotationAlignment(comp: *const Compilation, attrs: Attribute.Iterator) ?u29 {
1190 var it = attrs;
1205 var max_requested: ?u29 = null;1191 var max_requested: ?u29 = null;
1206 for (a) |attribute| {1192 var last_aligned_index: ?usize = null;
1193 while (it.next()) |item| {
1194 const attribute, const index = item;
1207 if (attribute.tag != .aligned) continue;1195 if (attribute.tag != .aligned) continue;
1196 if (last_aligned_index) |aligned_index| {
1197 // once we recurse into a new type, after an `aligned` attribute was found, we're done
1198 if (index <= aligned_index) break;
1199 }
1200 last_aligned_index = index;
1208 const requested = if (attribute.args.aligned.alignment) |alignment| alignment.requested else target_util.defaultAlignment(comp.target);1201 const requested = if (attribute.args.aligned.alignment) |alignment| alignment.requested else target_util.defaultAlignment(comp.target);
1209 if (max_requested == null or max_requested.? < requested) {1202 if (max_requested == null or max_requested.? < requested) {
1210 max_requested = requested;1203 max_requested = requested;
...@@ -1225,6 +1218,10 @@ pub fn eql(a_param: Type, b_param: Type, comp: *const Compilation, check_qualifi...@@ -1225,6 +1218,10 @@ pub fn eql(a_param: Type, b_param: Type, comp: *const Compilation, check_qualifi
1225 if (!b.isFunc()) return false;1218 if (!b.isFunc()) return false;
1226 } else if (a.isArray()) {1219 } else if (a.isArray()) {
1227 if (!b.isArray()) return false;1220 if (!b.isArray()) return false;
1221 } else if (a.specifier == .@"enum" and b.specifier != .@"enum") {
1222 return a.data.@"enum".tag_ty.eql(b, comp, check_qualifiers);
1223 } else if (b.specifier == .@"enum" and a.specifier != .@"enum") {
1224 return a.eql(b.data.@"enum".tag_ty, comp, check_qualifiers);
1228 } else if (a.specifier != b.specifier) return false;1225 } else if (a.specifier != b.specifier) return false;
12291226
1230 if (a.qual.atomic != b.qual.atomic) return false;1227 if (a.qual.atomic != b.qual.atomic) return false;
...@@ -1315,6 +1312,12 @@ pub fn integerRank(ty: Type, comp: *const Compilation) usize {...@@ -1315,6 +1312,12 @@ pub fn integerRank(ty: Type, comp: *const Compilation) usize {
1315 .long_long, .ulong_long => 6 + (ty.bitSizeof(comp).? << 3),1312 .long_long, .ulong_long => 6 + (ty.bitSizeof(comp).? << 3),
1316 .int128, .uint128 => 7 + (ty.bitSizeof(comp).? << 3),1313 .int128, .uint128 => 7 + (ty.bitSizeof(comp).? << 3),
13171314
1315 .typeof_type => ty.data.sub_type.integerRank(comp),
1316 .typeof_expr => ty.data.expr.ty.integerRank(comp),
1317 .attributed => ty.data.attributed.base.integerRank(comp),
1318
1319 .@"enum" => real.data.@"enum".tag_ty.integerRank(comp),
1320
1318 else => unreachable,1321 else => unreachable,
1319 });1322 });
1320}1323}
...@@ -1322,25 +1325,26 @@ pub fn integerRank(ty: Type, comp: *const Compilation) usize {...@@ -1322,25 +1325,26 @@ pub fn integerRank(ty: Type, comp: *const Compilation) usize {
1322/// Returns true if `a` and `b` are integer types that differ only in sign1325/// Returns true if `a` and `b` are integer types that differ only in sign
1323pub fn sameRankDifferentSign(a: Type, b: Type, comp: *const Compilation) bool {1326pub fn sameRankDifferentSign(a: Type, b: Type, comp: *const Compilation) bool {
1324 if (!a.isInt() or !b.isInt()) return false;1327 if (!a.isInt() or !b.isInt()) return false;
1328 if (a.hasIncompleteSize() or b.hasIncompleteSize()) return false;
1325 if (a.integerRank(comp) != b.integerRank(comp)) return false;1329 if (a.integerRank(comp) != b.integerRank(comp)) return false;
1326 return a.isUnsignedInt(comp) != b.isUnsignedInt(comp);1330 return a.isUnsignedInt(comp) != b.isUnsignedInt(comp);
1327}1331}
13281332
1329pub fn makeReal(ty: Type) Type {1333pub fn makeReal(ty: Type) Type {
1330 // TODO discards attributed/typeof1334 // TODO discards attributed/typeof
1331 var base = ty.canonicalize(.standard);1335 var base_ty = ty.canonicalize(.standard);
1332 switch (base.specifier) {1336 switch (base_ty.specifier) {
1333 .complex_float, .complex_double, .complex_long_double, .complex_float80, .complex_float128 => {1337 .complex_float16, .complex_float, .complex_double, .complex_long_double, .complex_float128 => {
1334 base.specifier = @enumFromInt(@intFromEnum(base.specifier) - 5);1338 base_ty.specifier = @enumFromInt(@intFromEnum(base_ty.specifier) - 5);
1335 return base;1339 return base_ty;
1336 },1340 },
1337 .complex_char, .complex_schar, .complex_uchar, .complex_short, .complex_ushort, .complex_int, .complex_uint, .complex_long, .complex_ulong, .complex_long_long, .complex_ulong_long, .complex_int128, .complex_uint128 => {1341 .complex_char, .complex_schar, .complex_uchar, .complex_short, .complex_ushort, .complex_int, .complex_uint, .complex_long, .complex_ulong, .complex_long_long, .complex_ulong_long, .complex_int128, .complex_uint128 => {
1338 base.specifier = @enumFromInt(@intFromEnum(base.specifier) - 13);1342 base_ty.specifier = @enumFromInt(@intFromEnum(base_ty.specifier) - 13);
1339 return base;1343 return base_ty;
1340 },1344 },
1341 .complex_bit_int => {1345 .complex_bit_int => {
1342 base.specifier = .bit_int;1346 base_ty.specifier = .bit_int;
1343 return base;1347 return base_ty;
1344 },1348 },
1345 else => return ty,1349 else => return ty,
1346 }1350 }
...@@ -1348,19 +1352,19 @@ pub fn makeReal(ty: Type) Type {...@@ -1348,19 +1352,19 @@ pub fn makeReal(ty: Type) Type {
13481352
1349pub fn makeComplex(ty: Type) Type {1353pub fn makeComplex(ty: Type) Type {
1350 // TODO discards attributed/typeof1354 // TODO discards attributed/typeof
1351 var base = ty.canonicalize(.standard);1355 var base_ty = ty.canonicalize(.standard);
1352 switch (base.specifier) {1356 switch (base_ty.specifier) {
1353 .float, .double, .long_double, .float80, .float128 => {1357 .float, .double, .long_double, .float128 => {
1354 base.specifier = @enumFromInt(@intFromEnum(base.specifier) + 5);1358 base_ty.specifier = @enumFromInt(@intFromEnum(base_ty.specifier) + 5);
1355 return base;1359 return base_ty;
1356 },1360 },
1357 .char, .schar, .uchar, .short, .ushort, .int, .uint, .long, .ulong, .long_long, .ulong_long, .int128, .uint128 => {1361 .char, .schar, .uchar, .short, .ushort, .int, .uint, .long, .ulong, .long_long, .ulong_long, .int128, .uint128 => {
1358 base.specifier = @enumFromInt(@intFromEnum(base.specifier) + 13);1362 base_ty.specifier = @enumFromInt(@intFromEnum(base_ty.specifier) + 13);
1359 return base;1363 return base_ty;
1360 },1364 },
1361 .bit_int => {1365 .bit_int => {
1362 base.specifier = .complex_bit_int;1366 base_ty.specifier = .complex_bit_int;
1363 return base;1367 return base_ty;
1364 },1368 },
1365 else => return ty,1369 else => return ty,
1366 }1370 }
...@@ -1541,13 +1545,12 @@ pub const Builder = struct {...@@ -1541,13 +1545,12 @@ pub const Builder = struct {
1541 float,1545 float,
1542 double,1546 double,
1543 long_double,1547 long_double,
1544 float80,
1545 float128,1548 float128,
1546 complex,1549 complex,
1550 complex_float16,
1547 complex_float,1551 complex_float,
1548 complex_double,1552 complex_double,
1549 complex_long_double,1553 complex_long_double,
1550 complex_float80,
1551 complex_float128,1554 complex_float128,
15521555
1553 pointer: *Type,1556 pointer: *Type,
...@@ -1613,9 +1616,6 @@ pub const Builder = struct {...@@ -1613,9 +1616,6 @@ pub const Builder = struct {
1613 .int128 => "__int128",1616 .int128 => "__int128",
1614 .sint128 => "signed __int128",1617 .sint128 => "signed __int128",
1615 .uint128 => "unsigned __int128",1618 .uint128 => "unsigned __int128",
1616 .bit_int => "_BitInt",
1617 .sbit_int => "signed _BitInt",
1618 .ubit_int => "unsigned _BitInt",
1619 .complex_char => "_Complex char",1619 .complex_char => "_Complex char",
1620 .complex_schar => "_Complex signed char",1620 .complex_schar => "_Complex signed char",
1621 .complex_uchar => "_Complex unsigned char",1621 .complex_uchar => "_Complex unsigned char",
...@@ -1645,22 +1645,18 @@ pub const Builder = struct {...@@ -1645,22 +1645,18 @@ pub const Builder = struct {
1645 .complex_int128 => "_Complex __int128",1645 .complex_int128 => "_Complex __int128",
1646 .complex_sint128 => "_Complex signed __int128",1646 .complex_sint128 => "_Complex signed __int128",
1647 .complex_uint128 => "_Complex unsigned __int128",1647 .complex_uint128 => "_Complex unsigned __int128",
1648 .complex_bit_int => "_Complex _BitInt",
1649 .complex_sbit_int => "_Complex signed _BitInt",
1650 .complex_ubit_int => "_Complex unsigned _BitInt",
16511648
1652 .fp16 => "__fp16",1649 .fp16 => "__fp16",
1653 .float16 => "_Float16",1650 .float16 => "_Float16",
1654 .float => "float",1651 .float => "float",
1655 .double => "double",1652 .double => "double",
1656 .long_double => "long double",1653 .long_double => "long double",
1657 .float80 => "__float80",
1658 .float128 => "__float128",1654 .float128 => "__float128",
1659 .complex => "_Complex",1655 .complex => "_Complex",
1656 .complex_float16 => "_Complex _Float16",
1660 .complex_float => "_Complex float",1657 .complex_float => "_Complex float",
1661 .complex_double => "_Complex double",1658 .complex_double => "_Complex double",
1662 .complex_long_double => "_Complex long double",1659 .complex_long_double => "_Complex long double",
1663 .complex_float80 => "_Complex __float80",
1664 .complex_float128 => "_Complex __float128",1660 .complex_float128 => "_Complex __float128",
16651661
1666 .attributed => |attributed| Builder.fromType(attributed.base).str(langopts),1662 .attributed => |attributed| Builder.fromType(attributed.base).str(langopts),
...@@ -1757,19 +1753,20 @@ pub const Builder = struct {...@@ -1757,19 +1753,20 @@ pub const Builder = struct {
1757 .complex_uint128 => ty.specifier = .complex_uint128,1753 .complex_uint128 => ty.specifier = .complex_uint128,
1758 .bit_int, .sbit_int, .ubit_int, .complex_bit_int, .complex_ubit_int, .complex_sbit_int => |bits| {1754 .bit_int, .sbit_int, .ubit_int, .complex_bit_int, .complex_ubit_int, .complex_sbit_int => |bits| {
1759 const unsigned = b.specifier == .ubit_int or b.specifier == .complex_ubit_int;1755 const unsigned = b.specifier == .ubit_int or b.specifier == .complex_ubit_int;
1756 const complex_str = if (b.complex_tok != null) "_Complex " else "";
1760 if (unsigned) {1757 if (unsigned) {
1761 if (bits < 1) {1758 if (bits < 1) {
1762 try p.errStr(.unsigned_bit_int_too_small, b.bit_int_tok.?, b.specifier.str(p.comp.langopts).?);1759 try p.errStr(.unsigned_bit_int_too_small, b.bit_int_tok.?, complex_str);
1763 return Type.invalid;1760 return Type.invalid;
1764 }1761 }
1765 } else {1762 } else {
1766 if (bits < 2) {1763 if (bits < 2) {
1767 try p.errStr(.signed_bit_int_too_small, b.bit_int_tok.?, b.specifier.str(p.comp.langopts).?);1764 try p.errStr(.signed_bit_int_too_small, b.bit_int_tok.?, complex_str);
1768 return Type.invalid;1765 return Type.invalid;
1769 }1766 }
1770 }1767 }
1771 if (bits > Compilation.bit_int_max_bits) {1768 if (bits > Compilation.bit_int_max_bits) {
1772 try p.errStr(.bit_int_too_big, b.bit_int_tok.?, b.specifier.str(p.comp.langopts).?);1769 try p.errStr(if (unsigned) .unsigned_bit_int_too_big else .signed_bit_int_too_big, b.bit_int_tok.?, complex_str);
1773 return Type.invalid;1770 return Type.invalid;
1774 }1771 }
1775 ty.specifier = if (b.complex_tok != null) .complex_bit_int else .bit_int;1772 ty.specifier = if (b.complex_tok != null) .complex_bit_int else .bit_int;
...@@ -1784,12 +1781,11 @@ pub const Builder = struct {...@@ -1784,12 +1781,11 @@ pub const Builder = struct {
1784 .float => ty.specifier = .float,1781 .float => ty.specifier = .float,
1785 .double => ty.specifier = .double,1782 .double => ty.specifier = .double,
1786 .long_double => ty.specifier = .long_double,1783 .long_double => ty.specifier = .long_double,
1787 .float80 => ty.specifier = .float80,
1788 .float128 => ty.specifier = .float128,1784 .float128 => ty.specifier = .float128,
1785 .complex_float16 => ty.specifier = .complex_float16,
1789 .complex_float => ty.specifier = .complex_float,1786 .complex_float => ty.specifier = .complex_float,
1790 .complex_double => ty.specifier = .complex_double,1787 .complex_double => ty.specifier = .complex_double,
1791 .complex_long_double => ty.specifier = .complex_long_double,1788 .complex_long_double => ty.specifier = .complex_long_double,
1792 .complex_float80 => ty.specifier = .complex_float80,
1793 .complex_float128 => ty.specifier = .complex_float128,1789 .complex_float128 => ty.specifier = .complex_float128,
1794 .complex => {1790 .complex => {
1795 try p.errTok(.plain_complex, p.tok_i - 1);1791 try p.errTok(.plain_complex, p.tok_i - 1);
...@@ -1907,6 +1903,7 @@ pub const Builder = struct {...@@ -1907,6 +1903,7 @@ pub const Builder = struct {
19071903
1908 /// Try to combine type from typedef, returns true if successful.1904 /// Try to combine type from typedef, returns true if successful.
1909 pub fn combineTypedef(b: *Builder, p: *Parser, typedef_ty: Type, name_tok: TokenIndex) bool {1905 pub fn combineTypedef(b: *Builder, p: *Parser, typedef_ty: Type, name_tok: TokenIndex) bool {
1906 if (typedef_ty.is(.invalid)) return false;
1910 b.error_on_invalid = true;1907 b.error_on_invalid = true;
1911 defer b.error_on_invalid = false;1908 defer b.error_on_invalid = false;
19121909
...@@ -2094,6 +2091,7 @@ pub const Builder = struct {...@@ -2094,6 +2091,7 @@ pub const Builder = struct {
2094 },2091 },
2095 .long => b.specifier = switch (b.specifier) {2092 .long => b.specifier = switch (b.specifier) {
2096 .none => .long,2093 .none => .long,
2094 .double => .long_double,
2097 .long => .long_long,2095 .long => .long_long,
2098 .unsigned => .ulong,2096 .unsigned => .ulong,
2099 .signed => .long,2097 .signed => .long,
...@@ -2106,6 +2104,7 @@ pub const Builder = struct {...@@ -2106,6 +2104,7 @@ pub const Builder = struct {
2106 .complex_long => .complex_long_long,2104 .complex_long => .complex_long_long,
2107 .complex_slong => .complex_slong_long,2105 .complex_slong => .complex_slong_long,
2108 .complex_ulong => .complex_ulong_long,2106 .complex_ulong => .complex_ulong_long,
2107 .complex_double => .complex_long_double,
2109 else => return b.cannotCombine(p, source_tok),2108 else => return b.cannotCombine(p, source_tok),
2110 },2109 },
2111 .int128 => b.specifier = switch (b.specifier) {2110 .int128 => b.specifier = switch (b.specifier) {
...@@ -2140,6 +2139,7 @@ pub const Builder = struct {...@@ -2140,6 +2139,7 @@ pub const Builder = struct {
2140 },2139 },
2141 .float16 => b.specifier = switch (b.specifier) {2140 .float16 => b.specifier = switch (b.specifier) {
2142 .none => .float16,2141 .none => .float16,
2142 .complex => .complex_float16,
2143 else => return b.cannotCombine(p, source_tok),2143 else => return b.cannotCombine(p, source_tok),
2144 },2144 },
2145 .float => b.specifier = switch (b.specifier) {2145 .float => b.specifier = switch (b.specifier) {
...@@ -2154,11 +2154,6 @@ pub const Builder = struct {...@@ -2154,11 +2154,6 @@ pub const Builder = struct {
2154 .complex => .complex_double,2154 .complex => .complex_double,
2155 else => return b.cannotCombine(p, source_tok),2155 else => return b.cannotCombine(p, source_tok),
2156 },2156 },
2157 .float80 => b.specifier = switch (b.specifier) {
2158 .none => .float80,
2159 .complex => .complex_float80,
2160 else => return b.cannotCombine(p, source_tok),
2161 },
2162 .float128 => b.specifier = switch (b.specifier) {2157 .float128 => b.specifier = switch (b.specifier) {
2163 .none => .float128,2158 .none => .float128,
2164 .complex => .complex_float128,2159 .complex => .complex_float128,
...@@ -2166,10 +2161,10 @@ pub const Builder = struct {...@@ -2166,10 +2161,10 @@ pub const Builder = struct {
2166 },2161 },
2167 .complex => b.specifier = switch (b.specifier) {2162 .complex => b.specifier = switch (b.specifier) {
2168 .none => .complex,2163 .none => .complex,
2164 .float16 => .complex_float16,
2169 .float => .complex_float,2165 .float => .complex_float,
2170 .double => .complex_double,2166 .double => .complex_double,
2171 .long_double => .complex_long_double,2167 .long_double => .complex_long_double,
2172 .float80 => .complex_float80,
2173 .float128 => .complex_float128,2168 .float128 => .complex_float128,
2174 .char => .complex_char,2169 .char => .complex_char,
2175 .schar => .complex_schar,2170 .schar => .complex_schar,
...@@ -2207,7 +2202,6 @@ pub const Builder = struct {...@@ -2207,7 +2202,6 @@ pub const Builder = struct {
2207 .complex_float,2202 .complex_float,
2208 .complex_double,2203 .complex_double,
2209 .complex_long_double,2204 .complex_long_double,
2210 .complex_float80,
2211 .complex_float128,2205 .complex_float128,
2212 .complex_char,2206 .complex_char,
2213 .complex_schar,2207 .complex_schar,
...@@ -2294,13 +2288,12 @@ pub const Builder = struct {...@@ -2294,13 +2288,12 @@ pub const Builder = struct {
2294 .float16 => .float16,2288 .float16 => .float16,
2295 .float => .float,2289 .float => .float,
2296 .double => .double,2290 .double => .double,
2297 .float80 => .float80,
2298 .float128 => .float128,2291 .float128 => .float128,
2299 .long_double => .long_double,2292 .long_double => .long_double,
2293 .complex_float16 => .complex_float16,
2300 .complex_float => .complex_float,2294 .complex_float => .complex_float,
2301 .complex_double => .complex_double,2295 .complex_double => .complex_double,
2302 .complex_long_double => .complex_long_double,2296 .complex_long_double => .complex_long_double,
2303 .complex_float80 => .complex_float80,
2304 .complex_float128 => .complex_float128,2297 .complex_float128 => .complex_float128,
23052298
2306 .pointer => .{ .pointer = ty.data.sub_type },2299 .pointer => .{ .pointer = ty.data.sub_type },
...@@ -2350,22 +2343,30 @@ pub const Builder = struct {...@@ -2350,22 +2343,30 @@ pub const Builder = struct {
2350 }2343 }
2351};2344};
23522345
2346/// Use with caution
2347pub fn base(ty: *Type) *Type {
2348 return switch (ty.specifier) {
2349 .typeof_type => ty.data.sub_type.base(),
2350 .typeof_expr => ty.data.expr.ty.base(),
2351 .attributed => ty.data.attributed.base.base(),
2352 else => ty,
2353 };
2354}
2355
2353pub fn getAttribute(ty: Type, comptime tag: Attribute.Tag) ?Attribute.ArgumentsForTag(tag) {2356pub fn getAttribute(ty: Type, comptime tag: Attribute.Tag) ?Attribute.ArgumentsForTag(tag) {
2354 switch (ty.specifier) {2357 if (tag == .aligned) @compileError("use requestedAlignment");
2355 .typeof_type => return ty.data.sub_type.getAttribute(tag),2358 var it = Attribute.Iterator.initType(ty);
2356 .typeof_expr => return ty.data.expr.ty.getAttribute(tag),2359 while (it.next()) |item| {
2357 .attributed => {2360 const attribute, _ = item;
2358 for (ty.data.attributed.attributes) |attribute| {2361 if (attribute.tag == tag) return @field(attribute.args, @tagName(tag));
2359 if (attribute.tag == tag) return @field(attribute.args, @tagName(tag));
2360 }
2361 return null;
2362 },
2363 else => return null,
2364 }2362 }
2363 return null;
2365}2364}
23662365
2367pub fn hasAttribute(ty: Type, tag: Attribute.Tag) bool {2366pub fn hasAttribute(ty: Type, tag: Attribute.Tag) bool {
2368 for (ty.getAttributes()) |attr| {2367 var it = Attribute.Iterator.initType(ty);
2368 while (it.next()) |item| {
2369 const attr, _ = item;
2369 if (attr.tag == tag) return true;2370 if (attr.tag == tag) return true;
2370 }2371 }
2371 return false;2372 return false;
...@@ -2489,6 +2490,8 @@ fn printPrologue(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts...@@ -2489,6 +2490,8 @@ fn printPrologue(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts
2489 _ = try elem_ty.printPrologue(mapper, langopts, w);2490 _ = try elem_ty.printPrologue(mapper, langopts, w);
2490 try w.writeAll("' values)");2491 try w.writeAll("' values)");
2491 },2492 },
2493 .bit_int => try w.print("{s} _BitInt({d})", .{ @tagName(ty.data.int.signedness), ty.data.int.bits }),
2494 .complex_bit_int => try w.print("_Complex {s} _BitInt({d})", .{ @tagName(ty.data.int.signedness), ty.data.int.bits }),
2492 else => try w.writeAll(Builder.fromType(ty).str(langopts).?),2495 else => try w.writeAll(Builder.fromType(ty).str(langopts).?),
2493 }2496 }
2494 return true;2497 return true;
...@@ -2644,15 +2647,12 @@ pub fn dump(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts, w:...@@ -2644,15 +2647,12 @@ pub fn dump(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts, w:
2644 .attributed => {2647 .attributed => {
2645 if (ty.isDecayed()) try w.writeAll("*d:");2648 if (ty.isDecayed()) try w.writeAll("*d:");
2646 try w.writeAll("attributed(");2649 try w.writeAll("attributed(");
2647 try ty.data.attributed.base.dump(mapper, langopts, w);2650 try ty.data.attributed.base.canonicalize(.standard).dump(mapper, langopts, w);
2648 try w.writeAll(")");2651 try w.writeAll(")");
2649 },2652 },
2650 else => {2653 .bit_int => try w.print("{s} _BitInt({d})", .{ @tagName(ty.data.int.signedness), ty.data.int.bits }),
2651 try w.writeAll(Builder.fromType(ty).str(langopts).?);2654 .complex_bit_int => try w.print("_Complex {s} _BitInt({d})", .{ @tagName(ty.data.int.signedness), ty.data.int.bits }),
2652 if (ty.specifier == .bit_int or ty.specifier == .complex_bit_int) {2655 else => try w.writeAll(Builder.fromType(ty).str(langopts).?),
2653 try w.print("({d})", .{ty.data.int.bits});
2654 }
2655 },
2656 }2656 }
2657}2657}
26582658
lib/compiler/aro/aro/Value.zig+358-53
...@@ -8,6 +8,7 @@ const BigIntSpace = Interner.Tag.Int.BigIntSpace;...@@ -8,6 +8,7 @@ const BigIntSpace = Interner.Tag.Int.BigIntSpace;
8const Compilation = @import("Compilation.zig");8const Compilation = @import("Compilation.zig");
9const Type = @import("Type.zig");9const Type = @import("Type.zig");
10const target_util = @import("target.zig");10const target_util = @import("target.zig");
11const annex_g = @import("annex_g.zig");
1112
12const Value = @This();13const Value = @This();
1314
...@@ -41,6 +42,14 @@ pub fn is(v: Value, tag: std.meta.Tag(Interner.Key), comp: *const Compilation) b...@@ -41,6 +42,14 @@ pub fn is(v: Value, tag: std.meta.Tag(Interner.Key), comp: *const Compilation) b
41 return comp.interner.get(v.ref()) == tag;42 return comp.interner.get(v.ref()) == tag;
42}43}
4344
45pub fn isArithmetic(v: Value, comp: *const Compilation) bool {
46 if (v.opt_ref == .none) return false;
47 return switch (comp.interner.get(v.ref())) {
48 .int, .float, .complex => true,
49 else => false,
50 };
51}
52
44/// Number of bits needed to hold `v`.53/// Number of bits needed to hold `v`.
45/// Asserts that `v` is not negative54/// Asserts that `v` is not negative
46pub fn minUnsignedBits(v: Value, comp: *const Compilation) usize {55pub fn minUnsignedBits(v: Value, comp: *const Compilation) usize {
...@@ -58,7 +67,7 @@ test "minUnsignedBits" {...@@ -58,7 +67,7 @@ test "minUnsignedBits" {
58 }67 }
59 };68 };
6069
61 var comp = Compilation.init(std.testing.allocator);70 var comp = Compilation.init(std.testing.allocator, std.fs.cwd());
62 defer comp.deinit();71 defer comp.deinit();
63 const target_query = try std.Target.Query.parse(.{ .arch_os_abi = "x86_64-linux-gnu" });72 const target_query = try std.Target.Query.parse(.{ .arch_os_abi = "x86_64-linux-gnu" });
64 comp.target = try std.zig.system.resolveTargetQuery(target_query);73 comp.target = try std.zig.system.resolveTargetQuery(target_query);
...@@ -93,7 +102,7 @@ test "minSignedBits" {...@@ -93,7 +102,7 @@ test "minSignedBits" {
93 }102 }
94 };103 };
95104
96 var comp = Compilation.init(std.testing.allocator);105 var comp = Compilation.init(std.testing.allocator, std.fs.cwd());
97 defer comp.deinit();106 defer comp.deinit();
98 const target_query = try std.Target.Query.parse(.{ .arch_os_abi = "x86_64-linux-gnu" });107 const target_query = try std.Target.Query.parse(.{ .arch_os_abi = "x86_64-linux-gnu" });
99 comp.target = try std.zig.system.resolveTargetQuery(target_query);108 comp.target = try std.zig.system.resolveTargetQuery(target_query);
...@@ -134,7 +143,7 @@ pub fn floatToInt(v: *Value, dest_ty: Type, comp: *Compilation) !FloatToIntChang...@@ -134,7 +143,7 @@ pub fn floatToInt(v: *Value, dest_ty: Type, comp: *Compilation) !FloatToIntChang
134 v.* = fromBool(!was_zero);143 v.* = fromBool(!was_zero);
135 if (was_zero or was_one) return .none;144 if (was_zero or was_one) return .none;
136 return .value_changed;145 return .value_changed;
137 } else if (dest_ty.isUnsignedInt(comp) and v.compare(.lt, zero, comp)) {146 } else if (dest_ty.isUnsignedInt(comp) and float_val < 0) {
138 v.* = zero;147 v.* = zero;
139 return .out_of_range;148 return .out_of_range;
140 }149 }
...@@ -154,7 +163,7 @@ pub fn floatToInt(v: *Value, dest_ty: Type, comp: *Compilation) !FloatToIntChang...@@ -154,7 +163,7 @@ pub fn floatToInt(v: *Value, dest_ty: Type, comp: *Compilation) !FloatToIntChang
154 };163 };
155164
156 // The float is reduced in rational.setFloat, so we assert that denominator is equal to one165 // The float is reduced in rational.setFloat, so we assert that denominator is equal to one
157 const big_one = std.math.big.int.Const{ .limbs = &.{1}, .positive = true };166 const big_one = BigIntConst{ .limbs = &.{1}, .positive = true };
158 assert(rational.q.toConst().eqlAbs(big_one));167 assert(rational.q.toConst().eqlAbs(big_one));
159168
160 if (is_negative) {169 if (is_negative) {
...@@ -179,6 +188,20 @@ pub fn floatToInt(v: *Value, dest_ty: Type, comp: *Compilation) !FloatToIntChang...@@ -179,6 +188,20 @@ pub fn floatToInt(v: *Value, dest_ty: Type, comp: *Compilation) !FloatToIntChang
179/// `.none` value remains unchanged.188/// `.none` value remains unchanged.
180pub fn intToFloat(v: *Value, dest_ty: Type, comp: *Compilation) !void {189pub fn intToFloat(v: *Value, dest_ty: Type, comp: *Compilation) !void {
181 if (v.opt_ref == .none) return;190 if (v.opt_ref == .none) return;
191
192 if (dest_ty.isComplex()) {
193 const bits = dest_ty.bitSizeof(comp).?;
194 const cf: Interner.Key.Complex = switch (bits) {
195 32 => .{ .cf16 = .{ v.toFloat(f16, comp), 0 } },
196 64 => .{ .cf32 = .{ v.toFloat(f32, comp), 0 } },
197 128 => .{ .cf64 = .{ v.toFloat(f64, comp), 0 } },
198 160 => .{ .cf80 = .{ v.toFloat(f80, comp), 0 } },
199 256 => .{ .cf128 = .{ v.toFloat(f128, comp), 0 } },
200 else => unreachable,
201 };
202 v.* = try intern(comp, .{ .complex = cf });
203 return;
204 }
182 const bits = dest_ty.bitSizeof(comp).?;205 const bits = dest_ty.bitSizeof(comp).?;
183 return switch (comp.interner.get(v.ref()).int) {206 return switch (comp.interner.get(v.ref()).int) {
184 inline .u64, .i64 => |data| {207 inline .u64, .i64 => |data| {
...@@ -207,40 +230,89 @@ pub fn intToFloat(v: *Value, dest_ty: Type, comp: *Compilation) !void {...@@ -207,40 +230,89 @@ pub fn intToFloat(v: *Value, dest_ty: Type, comp: *Compilation) !void {
207 };230 };
208}231}
209232
233pub const IntCastChangeKind = enum {
234 /// value did not change
235 none,
236 /// Truncation occurred (e.g., i32 to i16)
237 truncated,
238 /// Sign conversion occurred (e.g., i32 to u32)
239 sign_changed,
240};
241
210/// Truncates or extends bits based on type.242/// Truncates or extends bits based on type.
211/// `.none` value remains unchanged.243/// `.none` value remains unchanged.
212pub fn intCast(v: *Value, dest_ty: Type, comp: *Compilation) !void {244pub fn intCast(v: *Value, dest_ty: Type, comp: *Compilation) !IntCastChangeKind {
213 if (v.opt_ref == .none) return;245 if (v.opt_ref == .none) return .none;
214 const bits: usize = @intCast(dest_ty.bitSizeof(comp).?);246
247 const dest_bits: usize = @intCast(dest_ty.bitSizeof(comp).?);
248 const dest_signed = dest_ty.signedness(comp) == .signed;
249
215 var space: BigIntSpace = undefined;250 var space: BigIntSpace = undefined;
216 const big = v.toBigInt(&space, comp);251 const big = v.toBigInt(&space, comp);
252 const value_bits = big.bitCountTwosComp();
253
254 // if big is negative, then is signed.
255 const src_signed = !big.positive;
256 const sign_change = src_signed != dest_signed;
217257
218 const limbs = try comp.gpa.alloc(258 const limbs = try comp.gpa.alloc(
219 std.math.big.Limb,259 std.math.big.Limb,
220 std.math.big.int.calcTwosCompLimbCount(@max(big.bitCountTwosComp(), bits)),260 std.math.big.int.calcTwosCompLimbCount(@max(value_bits, dest_bits)),
221 );261 );
222 defer comp.gpa.free(limbs);262 defer comp.gpa.free(limbs);
223 var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined };263
224 result_bigint.truncate(big, dest_ty.signedness(comp), bits);264 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
265 result_bigint.truncate(big, dest_ty.signedness(comp), dest_bits);
225266
226 v.* = try intern(comp, .{ .int = .{ .big_int = result_bigint.toConst() } });267 v.* = try intern(comp, .{ .int = .{ .big_int = result_bigint.toConst() } });
268
269 const truncation_occurred = value_bits > dest_bits;
270 if (truncation_occurred) {
271 return .truncated;
272 } else if (sign_change) {
273 return .sign_changed;
274 } else {
275 return .none;
276 }
227}277}
228278
229/// Converts the stored value to a float of the specified type279/// Converts the stored value to a float of the specified type
230/// `.none` value remains unchanged.280/// `.none` value remains unchanged.
231pub fn floatCast(v: *Value, dest_ty: Type, comp: *Compilation) !void {281pub fn floatCast(v: *Value, dest_ty: Type, comp: *Compilation) !void {
232 if (v.opt_ref == .none) return;282 if (v.opt_ref == .none) return;
233 // TODO complex values283 const bits = dest_ty.bitSizeof(comp).?;
234 const bits = dest_ty.makeReal().bitSizeof(comp).?;284 if (dest_ty.isComplex()) {
235 const f: Interner.Key.Float = switch (bits) {285 const cf: Interner.Key.Complex = switch (bits) {
236 16 => .{ .f16 = v.toFloat(f16, comp) },286 32 => .{ .cf16 = .{ v.toFloat(f16, comp), v.imag(f16, comp) } },
237 32 => .{ .f32 = v.toFloat(f32, comp) },287 64 => .{ .cf32 = .{ v.toFloat(f32, comp), v.imag(f32, comp) } },
238 64 => .{ .f64 = v.toFloat(f64, comp) },288 128 => .{ .cf64 = .{ v.toFloat(f64, comp), v.imag(f64, comp) } },
239 80 => .{ .f80 = v.toFloat(f80, comp) },289 160 => .{ .cf80 = .{ v.toFloat(f80, comp), v.imag(f80, comp) } },
240 128 => .{ .f128 = v.toFloat(f128, comp) },290 256 => .{ .cf128 = .{ v.toFloat(f128, comp), v.imag(f128, comp) } },
291 else => unreachable,
292 };
293 v.* = try intern(comp, .{ .complex = cf });
294 } else {
295 const f: Interner.Key.Float = switch (bits) {
296 16 => .{ .f16 = v.toFloat(f16, comp) },
297 32 => .{ .f32 = v.toFloat(f32, comp) },
298 64 => .{ .f64 = v.toFloat(f64, comp) },
299 80 => .{ .f80 = v.toFloat(f80, comp) },
300 128 => .{ .f128 = v.toFloat(f128, comp) },
301 else => unreachable,
302 };
303 v.* = try intern(comp, .{ .float = f });
304 }
305}
306
307pub fn imag(v: Value, comptime T: type, comp: *const Compilation) T {
308 return switch (comp.interner.get(v.ref())) {
309 .int => 0.0,
310 .float => 0.0,
311 .complex => |repr| switch (repr) {
312 inline else => |components| return @floatCast(components[1]),
313 },
241 else => unreachable,314 else => unreachable,
242 };315 };
243 v.* = try intern(comp, .{ .float = f });
244}316}
245317
246pub fn toFloat(v: Value, comptime T: type, comp: *const Compilation) T {318pub fn toFloat(v: Value, comptime T: type, comp: *const Compilation) T {
...@@ -252,6 +324,39 @@ pub fn toFloat(v: Value, comptime T: type, comp: *const Compilation) T {...@@ -252,6 +324,39 @@ pub fn toFloat(v: Value, comptime T: type, comp: *const Compilation) T {
252 .float => |repr| switch (repr) {324 .float => |repr| switch (repr) {
253 inline else => |data| @floatCast(data),325 inline else => |data| @floatCast(data),
254 },326 },
327 .complex => |repr| switch (repr) {
328 inline else => |components| @floatCast(components[0]),
329 },
330 else => unreachable,
331 };
332}
333
334pub fn realPart(v: Value, comp: *Compilation) !Value {
335 if (v.opt_ref == .none) return v;
336 return switch (comp.interner.get(v.ref())) {
337 .int, .float => v,
338 .complex => |repr| Value.intern(comp, switch (repr) {
339 .cf16 => |components| .{ .float = .{ .f16 = components[0] } },
340 .cf32 => |components| .{ .float = .{ .f32 = components[0] } },
341 .cf64 => |components| .{ .float = .{ .f64 = components[0] } },
342 .cf80 => |components| .{ .float = .{ .f80 = components[0] } },
343 .cf128 => |components| .{ .float = .{ .f128 = components[0] } },
344 }),
345 else => unreachable,
346 };
347}
348
349pub fn imaginaryPart(v: Value, comp: *Compilation) !Value {
350 if (v.opt_ref == .none) return v;
351 return switch (comp.interner.get(v.ref())) {
352 .int, .float => Value.zero,
353 .complex => |repr| Value.intern(comp, switch (repr) {
354 .cf16 => |components| .{ .float = .{ .f16 = components[1] } },
355 .cf32 => |components| .{ .float = .{ .f32 = components[1] } },
356 .cf64 => |components| .{ .float = .{ .f64 = components[1] } },
357 .cf80 => |components| .{ .float = .{ .f80 = components[1] } },
358 .cf128 => |components| .{ .float = .{ .f128 = components[1] } },
359 }),
255 else => unreachable,360 else => unreachable,
256 };361 };
257}362}
...@@ -298,11 +403,56 @@ pub fn isZero(v: Value, comp: *const Compilation) bool {...@@ -298,11 +403,56 @@ pub fn isZero(v: Value, comp: *const Compilation) bool {
298 inline .i64, .u64 => |data| return data == 0,403 inline .i64, .u64 => |data| return data == 0,
299 .big_int => |data| return data.eqlZero(),404 .big_int => |data| return data.eqlZero(),
300 },405 },
406 .complex => |repr| switch (repr) {
407 inline else => |data| return data[0] == 0.0 and data[1] == 0.0,
408 },
301 .bytes => return false,409 .bytes => return false,
302 else => unreachable,410 else => unreachable,
303 }411 }
304}412}
305413
414const IsInfKind = enum(i32) {
415 negative = -1,
416 finite = 0,
417 positive = 1,
418 unknown = std.math.maxInt(i32),
419};
420
421pub fn isInfSign(v: Value, comp: *const Compilation) IsInfKind {
422 if (v.opt_ref == .none) return .unknown;
423 return switch (comp.interner.get(v.ref())) {
424 .float => |repr| switch (repr) {
425 inline else => |data| if (std.math.isPositiveInf(data)) .positive else if (std.math.isNegativeInf(data)) .negative else .finite,
426 },
427 else => .unknown,
428 };
429}
430pub fn isInf(v: Value, comp: *const Compilation) bool {
431 if (v.opt_ref == .none) return false;
432 return switch (comp.interner.get(v.ref())) {
433 .float => |repr| switch (repr) {
434 inline else => |data| std.math.isInf(data),
435 },
436 .complex => |repr| switch (repr) {
437 inline else => |components| std.math.isInf(components[0]) or std.math.isInf(components[1]),
438 },
439 else => false,
440 };
441}
442
443pub fn isNan(v: Value, comp: *const Compilation) bool {
444 if (v.opt_ref == .none) return false;
445 return switch (comp.interner.get(v.ref())) {
446 .float => |repr| switch (repr) {
447 inline else => |data| std.math.isNan(data),
448 },
449 .complex => |repr| switch (repr) {
450 inline else => |components| std.math.isNan(components[0]) or std.math.isNan(components[1]),
451 },
452 else => false,
453 };
454}
455
306/// Converts value to zero or one;456/// Converts value to zero or one;
307/// `.none` value remains unchanged.457/// `.none` value remains unchanged.
308pub fn boolCast(v: *Value, comp: *const Compilation) void {458pub fn boolCast(v: *Value, comp: *const Compilation) void {
...@@ -326,9 +476,45 @@ pub fn toInt(v: Value, comptime T: type, comp: *const Compilation) ?T {...@@ -326,9 +476,45 @@ pub fn toInt(v: Value, comptime T: type, comp: *const Compilation) ?T {
326 return big_int.to(T) catch null;476 return big_int.to(T) catch null;
327}477}
328478
479const ComplexOp = enum {
480 add,
481 sub,
482};
483
484fn complexAddSub(lhs: Value, rhs: Value, comptime T: type, op: ComplexOp, comp: *Compilation) !Value {
485 const res_re = switch (op) {
486 .add => lhs.toFloat(T, comp) + rhs.toFloat(T, comp),
487 .sub => lhs.toFloat(T, comp) - rhs.toFloat(T, comp),
488 };
489 const res_im = switch (op) {
490 .add => lhs.imag(T, comp) + rhs.imag(T, comp),
491 .sub => lhs.imag(T, comp) - rhs.imag(T, comp),
492 };
493
494 return switch (T) {
495 f16 => intern(comp, .{ .complex = .{ .cf16 = .{ res_re, res_im } } }),
496 f32 => intern(comp, .{ .complex = .{ .cf32 = .{ res_re, res_im } } }),
497 f64 => intern(comp, .{ .complex = .{ .cf64 = .{ res_re, res_im } } }),
498 f80 => intern(comp, .{ .complex = .{ .cf80 = .{ res_re, res_im } } }),
499 f128 => intern(comp, .{ .complex = .{ .cf128 = .{ res_re, res_im } } }),
500 else => unreachable,
501 };
502}
503
329pub fn add(res: *Value, lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !bool {504pub fn add(res: *Value, lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !bool {
330 const bits: usize = @intCast(ty.bitSizeof(comp).?);505 const bits: usize = @intCast(ty.bitSizeof(comp).?);
331 if (ty.isFloat()) {506 if (ty.isFloat()) {
507 if (ty.isComplex()) {
508 res.* = switch (bits) {
509 32 => try complexAddSub(lhs, rhs, f16, .add, comp),
510 64 => try complexAddSub(lhs, rhs, f32, .add, comp),
511 128 => try complexAddSub(lhs, rhs, f64, .add, comp),
512 160 => try complexAddSub(lhs, rhs, f80, .add, comp),
513 256 => try complexAddSub(lhs, rhs, f128, .add, comp),
514 else => unreachable,
515 };
516 return false;
517 }
332 const f: Interner.Key.Float = switch (bits) {518 const f: Interner.Key.Float = switch (bits) {
333 16 => .{ .f16 = lhs.toFloat(f16, comp) + rhs.toFloat(f16, comp) },519 16 => .{ .f16 = lhs.toFloat(f16, comp) + rhs.toFloat(f16, comp) },
334 32 => .{ .f32 = lhs.toFloat(f32, comp) + rhs.toFloat(f32, comp) },520 32 => .{ .f32 = lhs.toFloat(f32, comp) + rhs.toFloat(f32, comp) },
...@@ -350,7 +536,7 @@ pub fn add(res: *Value, lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !b...@@ -350,7 +536,7 @@ pub fn add(res: *Value, lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !b
350 std.math.big.int.calcTwosCompLimbCount(bits),536 std.math.big.int.calcTwosCompLimbCount(bits),
351 );537 );
352 defer comp.gpa.free(limbs);538 defer comp.gpa.free(limbs);
353 var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined };539 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
354540
355 const overflowed = result_bigint.addWrap(lhs_bigint, rhs_bigint, ty.signedness(comp), bits);541 const overflowed = result_bigint.addWrap(lhs_bigint, rhs_bigint, ty.signedness(comp), bits);
356 res.* = try intern(comp, .{ .int = .{ .big_int = result_bigint.toConst() } });542 res.* = try intern(comp, .{ .int = .{ .big_int = result_bigint.toConst() } });
...@@ -361,6 +547,17 @@ pub fn add(res: *Value, lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !b...@@ -361,6 +547,17 @@ pub fn add(res: *Value, lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !b
361pub fn sub(res: *Value, lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !bool {547pub fn sub(res: *Value, lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !bool {
362 const bits: usize = @intCast(ty.bitSizeof(comp).?);548 const bits: usize = @intCast(ty.bitSizeof(comp).?);
363 if (ty.isFloat()) {549 if (ty.isFloat()) {
550 if (ty.isComplex()) {
551 res.* = switch (bits) {
552 32 => try complexAddSub(lhs, rhs, f16, .sub, comp),
553 64 => try complexAddSub(lhs, rhs, f32, .sub, comp),
554 128 => try complexAddSub(lhs, rhs, f64, .sub, comp),
555 160 => try complexAddSub(lhs, rhs, f80, .sub, comp),
556 256 => try complexAddSub(lhs, rhs, f128, .sub, comp),
557 else => unreachable,
558 };
559 return false;
560 }
364 const f: Interner.Key.Float = switch (bits) {561 const f: Interner.Key.Float = switch (bits) {
365 16 => .{ .f16 = lhs.toFloat(f16, comp) - rhs.toFloat(f16, comp) },562 16 => .{ .f16 = lhs.toFloat(f16, comp) - rhs.toFloat(f16, comp) },
366 32 => .{ .f32 = lhs.toFloat(f32, comp) - rhs.toFloat(f32, comp) },563 32 => .{ .f32 = lhs.toFloat(f32, comp) - rhs.toFloat(f32, comp) },
...@@ -382,7 +579,7 @@ pub fn sub(res: *Value, lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !b...@@ -382,7 +579,7 @@ pub fn sub(res: *Value, lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !b
382 std.math.big.int.calcTwosCompLimbCount(bits),579 std.math.big.int.calcTwosCompLimbCount(bits),
383 );580 );
384 defer comp.gpa.free(limbs);581 defer comp.gpa.free(limbs);
385 var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined };582 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
386583
387 const overflowed = result_bigint.subWrap(lhs_bigint, rhs_bigint, ty.signedness(comp), bits);584 const overflowed = result_bigint.subWrap(lhs_bigint, rhs_bigint, ty.signedness(comp), bits);
388 res.* = try intern(comp, .{ .int = .{ .big_int = result_bigint.toConst() } });585 res.* = try intern(comp, .{ .int = .{ .big_int = result_bigint.toConst() } });
...@@ -393,6 +590,18 @@ pub fn sub(res: *Value, lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !b...@@ -393,6 +590,18 @@ pub fn sub(res: *Value, lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !b
393pub fn mul(res: *Value, lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !bool {590pub fn mul(res: *Value, lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !bool {
394 const bits: usize = @intCast(ty.bitSizeof(comp).?);591 const bits: usize = @intCast(ty.bitSizeof(comp).?);
395 if (ty.isFloat()) {592 if (ty.isFloat()) {
593 if (ty.isComplex()) {
594 const cf: Interner.Key.Complex = switch (bits) {
595 32 => .{ .cf16 = annex_g.complexFloatMul(f16, lhs.toFloat(f16, comp), lhs.imag(f16, comp), rhs.toFloat(f16, comp), rhs.imag(f16, comp)) },
596 64 => .{ .cf32 = annex_g.complexFloatMul(f32, lhs.toFloat(f32, comp), lhs.imag(f32, comp), rhs.toFloat(f32, comp), rhs.imag(f32, comp)) },
597 128 => .{ .cf64 = annex_g.complexFloatMul(f64, lhs.toFloat(f64, comp), lhs.imag(f64, comp), rhs.toFloat(f64, comp), rhs.imag(f64, comp)) },
598 160 => .{ .cf80 = annex_g.complexFloatMul(f80, lhs.toFloat(f80, comp), lhs.imag(f80, comp), rhs.toFloat(f80, comp), rhs.imag(f80, comp)) },
599 256 => .{ .cf128 = annex_g.complexFloatMul(f128, lhs.toFloat(f128, comp), lhs.imag(f128, comp), rhs.toFloat(f128, comp), rhs.imag(f128, comp)) },
600 else => unreachable,
601 };
602 res.* = try intern(comp, .{ .complex = cf });
603 return false;
604 }
396 const f: Interner.Key.Float = switch (bits) {605 const f: Interner.Key.Float = switch (bits) {
397 16 => .{ .f16 = lhs.toFloat(f16, comp) * rhs.toFloat(f16, comp) },606 16 => .{ .f16 = lhs.toFloat(f16, comp) * rhs.toFloat(f16, comp) },
398 32 => .{ .f32 = lhs.toFloat(f32, comp) * rhs.toFloat(f32, comp) },607 32 => .{ .f32 = lhs.toFloat(f32, comp) * rhs.toFloat(f32, comp) },
...@@ -438,6 +647,18 @@ pub fn mul(res: *Value, lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !b...@@ -438,6 +647,18 @@ pub fn mul(res: *Value, lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !b
438pub fn div(res: *Value, lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !bool {647pub fn div(res: *Value, lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !bool {
439 const bits: usize = @intCast(ty.bitSizeof(comp).?);648 const bits: usize = @intCast(ty.bitSizeof(comp).?);
440 if (ty.isFloat()) {649 if (ty.isFloat()) {
650 if (ty.isComplex()) {
651 const cf: Interner.Key.Complex = switch (bits) {
652 32 => .{ .cf16 = annex_g.complexFloatDiv(f16, lhs.toFloat(f16, comp), lhs.imag(f16, comp), rhs.toFloat(f16, comp), rhs.imag(f16, comp)) },
653 64 => .{ .cf32 = annex_g.complexFloatDiv(f32, lhs.toFloat(f32, comp), lhs.imag(f32, comp), rhs.toFloat(f32, comp), rhs.imag(f32, comp)) },
654 128 => .{ .cf64 = annex_g.complexFloatDiv(f64, lhs.toFloat(f64, comp), lhs.imag(f64, comp), rhs.toFloat(f64, comp), rhs.imag(f64, comp)) },
655 160 => .{ .cf80 = annex_g.complexFloatDiv(f80, lhs.toFloat(f80, comp), lhs.imag(f80, comp), rhs.toFloat(f80, comp), rhs.imag(f80, comp)) },
656 256 => .{ .cf128 = annex_g.complexFloatDiv(f128, lhs.toFloat(f128, comp), lhs.imag(f128, comp), rhs.toFloat(f128, comp), rhs.imag(f128, comp)) },
657 else => unreachable,
658 };
659 res.* = try intern(comp, .{ .complex = cf });
660 return false;
661 }
441 const f: Interner.Key.Float = switch (bits) {662 const f: Interner.Key.Float = switch (bits) {
442 16 => .{ .f16 = lhs.toFloat(f16, comp) / rhs.toFloat(f16, comp) },663 16 => .{ .f16 = lhs.toFloat(f16, comp) / rhs.toFloat(f16, comp) },
443 32 => .{ .f32 = lhs.toFloat(f32, comp) / rhs.toFloat(f32, comp) },664 32 => .{ .f32 = lhs.toFloat(f32, comp) / rhs.toFloat(f32, comp) },
...@@ -491,11 +712,11 @@ pub fn rem(lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !Value {...@@ -491,11 +712,11 @@ pub fn rem(lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !Value {
491712
492 const signedness = ty.signedness(comp);713 const signedness = ty.signedness(comp);
493 if (signedness == .signed) {714 if (signedness == .signed) {
494 var spaces: [3]BigIntSpace = undefined;715 var spaces: [2]BigIntSpace = undefined;
495 const min_val = BigIntMutable.init(&spaces[0].limbs, ty.minInt(comp)).toConst();716 const min_val = try Value.minInt(ty, comp);
496 const negative = BigIntMutable.init(&spaces[1].limbs, -1).toConst();717 const negative = BigIntMutable.init(&spaces[0].limbs, -1).toConst();
497 const big_one = BigIntMutable.init(&spaces[2].limbs, 1).toConst();718 const big_one = BigIntMutable.init(&spaces[1].limbs, 1).toConst();
498 if (lhs_bigint.eql(min_val) and rhs_bigint.eql(negative)) {719 if (lhs.compare(.eq, min_val, comp) and rhs_bigint.eql(negative)) {
499 return .{};720 return .{};
500 } else if (rhs_bigint.order(big_one).compare(.lt)) {721 } else if (rhs_bigint.order(big_one).compare(.lt)) {
501 // lhs - @divTrunc(lhs, rhs) * rhs722 // lhs - @divTrunc(lhs, rhs) * rhs
...@@ -542,7 +763,7 @@ pub fn bitOr(lhs: Value, rhs: Value, comp: *Compilation) !Value {...@@ -542,7 +763,7 @@ pub fn bitOr(lhs: Value, rhs: Value, comp: *Compilation) !Value {
542 @max(lhs_bigint.limbs.len, rhs_bigint.limbs.len),763 @max(lhs_bigint.limbs.len, rhs_bigint.limbs.len),
543 );764 );
544 defer comp.gpa.free(limbs);765 defer comp.gpa.free(limbs);
545 var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined };766 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
546767
547 result_bigint.bitOr(lhs_bigint, rhs_bigint);768 result_bigint.bitOr(lhs_bigint, rhs_bigint);
548 return intern(comp, .{ .int = .{ .big_int = result_bigint.toConst() } });769 return intern(comp, .{ .int = .{ .big_int = result_bigint.toConst() } });
...@@ -554,12 +775,13 @@ pub fn bitXor(lhs: Value, rhs: Value, comp: *Compilation) !Value {...@@ -554,12 +775,13 @@ pub fn bitXor(lhs: Value, rhs: Value, comp: *Compilation) !Value {
554 const lhs_bigint = lhs.toBigInt(&lhs_space, comp);775 const lhs_bigint = lhs.toBigInt(&lhs_space, comp);
555 const rhs_bigint = rhs.toBigInt(&rhs_space, comp);776 const rhs_bigint = rhs.toBigInt(&rhs_space, comp);
556777
778 const extra = @intFromBool(lhs_bigint.positive != rhs_bigint.positive);
557 const limbs = try comp.gpa.alloc(779 const limbs = try comp.gpa.alloc(
558 std.math.big.Limb,780 std.math.big.Limb,
559 @max(lhs_bigint.limbs.len, rhs_bigint.limbs.len),781 @max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + extra,
560 );782 );
561 defer comp.gpa.free(limbs);783 defer comp.gpa.free(limbs);
562 var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined };784 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
563785
564 result_bigint.bitXor(lhs_bigint, rhs_bigint);786 result_bigint.bitXor(lhs_bigint, rhs_bigint);
565 return intern(comp, .{ .int = .{ .big_int = result_bigint.toConst() } });787 return intern(comp, .{ .int = .{ .big_int = result_bigint.toConst() } });
...@@ -571,12 +793,18 @@ pub fn bitAnd(lhs: Value, rhs: Value, comp: *Compilation) !Value {...@@ -571,12 +793,18 @@ pub fn bitAnd(lhs: Value, rhs: Value, comp: *Compilation) !Value {
571 const lhs_bigint = lhs.toBigInt(&lhs_space, comp);793 const lhs_bigint = lhs.toBigInt(&lhs_space, comp);
572 const rhs_bigint = rhs.toBigInt(&rhs_space, comp);794 const rhs_bigint = rhs.toBigInt(&rhs_space, comp);
573795
574 const limbs = try comp.gpa.alloc(796 const limb_count = if (lhs_bigint.positive and rhs_bigint.positive)
575 std.math.big.Limb,797 @min(lhs_bigint.limbs.len, rhs_bigint.limbs.len)
576 @max(lhs_bigint.limbs.len, rhs_bigint.limbs.len),798 else if (lhs_bigint.positive)
577 );799 lhs_bigint.limbs.len
800 else if (rhs_bigint.positive)
801 rhs_bigint.limbs.len
802 else
803 @max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1;
804
805 const limbs = try comp.gpa.alloc(std.math.big.Limb, limb_count);
578 defer comp.gpa.free(limbs);806 defer comp.gpa.free(limbs);
579 var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined };807 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
580808
581 result_bigint.bitAnd(lhs_bigint, rhs_bigint);809 result_bigint.bitAnd(lhs_bigint, rhs_bigint);
582 return intern(comp, .{ .int = .{ .big_int = result_bigint.toConst() } });810 return intern(comp, .{ .int = .{ .big_int = result_bigint.toConst() } });
...@@ -592,7 +820,7 @@ pub fn bitNot(val: Value, ty: Type, comp: *Compilation) !Value {...@@ -592,7 +820,7 @@ pub fn bitNot(val: Value, ty: Type, comp: *Compilation) !Value {
592 std.math.big.int.calcTwosCompLimbCount(bits),820 std.math.big.int.calcTwosCompLimbCount(bits),
593 );821 );
594 defer comp.gpa.free(limbs);822 defer comp.gpa.free(limbs);
595 var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined };823 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
596824
597 result_bigint.bitNotWrap(val_bigint, ty.signedness(comp), bits);825 result_bigint.bitNotWrap(val_bigint, ty.signedness(comp), bits);
598 return intern(comp, .{ .int = .{ .big_int = result_bigint.toConst() } });826 return intern(comp, .{ .int = .{ .big_int = result_bigint.toConst() } });
...@@ -606,9 +834,9 @@ pub fn shl(res: *Value, lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !b...@@ -606,9 +834,9 @@ pub fn shl(res: *Value, lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !b
606 const bits: usize = @intCast(ty.bitSizeof(comp).?);834 const bits: usize = @intCast(ty.bitSizeof(comp).?);
607 if (shift > bits) {835 if (shift > bits) {
608 if (lhs_bigint.positive) {836 if (lhs_bigint.positive) {
609 res.* = try intern(comp, .{ .int = .{ .u64 = ty.maxInt(comp) } });837 res.* = try Value.maxInt(ty, comp);
610 } else {838 } else {
611 res.* = try intern(comp, .{ .int = .{ .i64 = ty.minInt(comp) } });839 res.* = try Value.minInt(ty, comp);
612 }840 }
613 return true;841 return true;
614 }842 }
...@@ -618,7 +846,7 @@ pub fn shl(res: *Value, lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !b...@@ -618,7 +846,7 @@ pub fn shl(res: *Value, lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !b
618 lhs_bigint.limbs.len + (shift / (@sizeOf(std.math.big.Limb) * 8)) + 1,846 lhs_bigint.limbs.len + (shift / (@sizeOf(std.math.big.Limb) * 8)) + 1,
619 );847 );
620 defer comp.gpa.free(limbs);848 defer comp.gpa.free(limbs);
621 var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined };849 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
622850
623 result_bigint.shiftLeft(lhs_bigint, shift);851 result_bigint.shiftLeft(lhs_bigint, shift);
624 const signedness = ty.signedness(comp);852 const signedness = ty.signedness(comp);
...@@ -652,12 +880,25 @@ pub fn shr(lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !Value {...@@ -652,12 +880,25 @@ pub fn shr(lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !Value {
652 std.math.big.int.calcTwosCompLimbCount(bits),880 std.math.big.int.calcTwosCompLimbCount(bits),
653 );881 );
654 defer comp.gpa.free(limbs);882 defer comp.gpa.free(limbs);
655 var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined };883 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
656884
657 result_bigint.shiftRight(lhs_bigint, shift);885 result_bigint.shiftRight(lhs_bigint, shift);
658 return intern(comp, .{ .int = .{ .big_int = result_bigint.toConst() } });886 return intern(comp, .{ .int = .{ .big_int = result_bigint.toConst() } });
659}887}
660888
889pub fn complexConj(val: Value, ty: Type, comp: *Compilation) !Value {
890 const bits = ty.bitSizeof(comp).?;
891 const cf: Interner.Key.Complex = switch (bits) {
892 32 => .{ .cf16 = .{ val.toFloat(f16, comp), -val.imag(f16, comp) } },
893 64 => .{ .cf32 = .{ val.toFloat(f32, comp), -val.imag(f32, comp) } },
894 128 => .{ .cf64 = .{ val.toFloat(f64, comp), -val.imag(f64, comp) } },
895 160 => .{ .cf80 = .{ val.toFloat(f80, comp), -val.imag(f80, comp) } },
896 256 => .{ .cf128 = .{ val.toFloat(f128, comp), -val.imag(f128, comp) } },
897 else => unreachable,
898 };
899 return intern(comp, .{ .complex = cf });
900}
901
661pub fn compare(lhs: Value, op: std.math.CompareOperator, rhs: Value, comp: *const Compilation) bool {902pub fn compare(lhs: Value, op: std.math.CompareOperator, rhs: Value, comp: *const Compilation) bool {
662 if (op == .eq) {903 if (op == .eq) {
663 return lhs.opt_ref == rhs.opt_ref;904 return lhs.opt_ref == rhs.opt_ref;
...@@ -672,6 +913,12 @@ pub fn compare(lhs: Value, op: std.math.CompareOperator, rhs: Value, comp: *cons...@@ -672,6 +913,12 @@ pub fn compare(lhs: Value, op: std.math.CompareOperator, rhs: Value, comp: *cons
672 const rhs_f128 = rhs.toFloat(f128, comp);913 const rhs_f128 = rhs.toFloat(f128, comp);
673 return std.math.compare(lhs_f128, op, rhs_f128);914 return std.math.compare(lhs_f128, op, rhs_f128);
674 }915 }
916 if (lhs_key == .complex or rhs_key == .complex) {
917 assert(op == .neq);
918 const real_equal = std.math.compare(lhs.toFloat(f128, comp), .eq, rhs.toFloat(f128, comp));
919 const imag_equal = std.math.compare(lhs.imag(f128, comp), .eq, rhs.imag(f128, comp));
920 return !real_equal or !imag_equal;
921 }
675922
676 var lhs_bigint_space: BigIntSpace = undefined;923 var lhs_bigint_space: BigIntSpace = undefined;
677 var rhs_bigint_space: BigIntSpace = undefined;924 var rhs_bigint_space: BigIntSpace = undefined;
...@@ -680,6 +927,42 @@ pub fn compare(lhs: Value, op: std.math.CompareOperator, rhs: Value, comp: *cons...@@ -680,6 +927,42 @@ pub fn compare(lhs: Value, op: std.math.CompareOperator, rhs: Value, comp: *cons
680 return lhs_bigint.order(rhs_bigint).compare(op);927 return lhs_bigint.order(rhs_bigint).compare(op);
681}928}
682929
930fn twosCompIntLimit(limit: std.math.big.int.TwosCompIntLimit, ty: Type, comp: *Compilation) !Value {
931 const signedness = ty.signedness(comp);
932 if (limit == .min and signedness == .unsigned) return Value.zero;
933 const mag_bits: usize = @intCast(ty.bitSizeof(comp).?);
934 switch (mag_bits) {
935 inline 8, 16, 32, 64 => |bits| {
936 if (limit == .min) return Value.int(@as(i64, std.math.minInt(std.meta.Int(.signed, bits))), comp);
937 return switch (signedness) {
938 inline else => |sign| Value.int(std.math.maxInt(std.meta.Int(sign, bits)), comp),
939 };
940 },
941 else => {},
942 }
943
944 const sign_bits = @intFromBool(signedness == .signed);
945 const total_bits = mag_bits + sign_bits;
946
947 const limbs = try comp.gpa.alloc(
948 std.math.big.Limb,
949 std.math.big.int.calcTwosCompLimbCount(total_bits),
950 );
951 defer comp.gpa.free(limbs);
952
953 var result_bigint: BigIntMutable = .{ .limbs = limbs, .positive = undefined, .len = undefined };
954 result_bigint.setTwosCompIntLimit(limit, signedness, mag_bits);
955 return Value.intern(comp, .{ .int = .{ .big_int = result_bigint.toConst() } });
956}
957
958pub fn minInt(ty: Type, comp: *Compilation) !Value {
959 return twosCompIntLimit(.min, ty, comp);
960}
961
962pub fn maxInt(ty: Type, comp: *Compilation) !Value {
963 return twosCompIntLimit(.max, ty, comp);
964}
965
683pub fn print(v: Value, ty: Type, comp: *const Compilation, w: anytype) @TypeOf(w).Error!void {966pub fn print(v: Value, ty: Type, comp: *const Compilation, w: anytype) @TypeOf(w).Error!void {
684 if (ty.is(.bool)) {967 if (ty.is(.bool)) {
685 return w.writeAll(if (v.isZero(comp)) "false" else "true");968 return w.writeAll(if (v.isZero(comp)) "false" else "true");
...@@ -696,6 +979,10 @@ pub fn print(v: Value, ty: Type, comp: *const Compilation, w: anytype) @TypeOf(w...@@ -696,6 +979,10 @@ pub fn print(v: Value, ty: Type, comp: *const Compilation, w: anytype) @TypeOf(w
696 inline else => |x| return w.print("{d}", .{@as(f64, @floatCast(x))}),979 inline else => |x| return w.print("{d}", .{@as(f64, @floatCast(x))}),
697 },980 },
698 .bytes => |b| return printString(b, ty, comp, w),981 .bytes => |b| return printString(b, ty, comp, w),
982 .complex => |repr| switch (repr) {
983 .cf32 => |components| return w.print("{d} + {d}i", .{ @round(@as(f64, @floatCast(components[0])) * 1000000) / 1000000, @round(@as(f64, @floatCast(components[1])) * 1000000) / 1000000 }),
984 inline else => |components| return w.print("{d} + {d}i", .{ @as(f64, @floatCast(components[0])), @as(f64, @floatCast(components[1])) }),
985 },
699 else => unreachable, // not a value986 else => unreachable, // not a value
700 }987 }
701}988}
...@@ -703,26 +990,44 @@ pub fn print(v: Value, ty: Type, comp: *const Compilation, w: anytype) @TypeOf(w...@@ -703,26 +990,44 @@ pub fn print(v: Value, ty: Type, comp: *const Compilation, w: anytype) @TypeOf(w
703pub fn printString(bytes: []const u8, ty: Type, comp: *const Compilation, w: anytype) @TypeOf(w).Error!void {990pub fn printString(bytes: []const u8, ty: Type, comp: *const Compilation, w: anytype) @TypeOf(w).Error!void {
704 const size: Compilation.CharUnitSize = @enumFromInt(ty.elemType().sizeof(comp).?);991 const size: Compilation.CharUnitSize = @enumFromInt(ty.elemType().sizeof(comp).?);
705 const without_null = bytes[0 .. bytes.len - @intFromEnum(size)];992 const without_null = bytes[0 .. bytes.len - @intFromEnum(size)];
993 try w.writeByte('"');
706 switch (size) {994 switch (size) {
707 inline .@"1", .@"2" => |sz| {995 .@"1" => try w.print("{}", .{std.zig.fmtEscapes(without_null)}),
708 const data_slice: []const sz.Type() = @alignCast(std.mem.bytesAsSlice(sz.Type(), without_null));996 .@"2" => {
709 const formatter = if (sz == .@"1") std.zig.fmtEscapes(data_slice) else std.unicode.fmtUtf16Le(data_slice);997 var items: [2]u16 = undefined;
710 try w.print("\"{}\"", .{formatter});998 var i: usize = 0;
999 while (i < without_null.len) {
1000 @memcpy(std.mem.sliceAsBytes(items[0..1]), without_null[i..][0..2]);
1001 i += 2;
1002 const is_surrogate = std.unicode.utf16IsHighSurrogate(items[0]);
1003 if (is_surrogate and i < without_null.len) {
1004 @memcpy(std.mem.sliceAsBytes(items[1..2]), without_null[i..][0..2]);
1005 if (std.unicode.utf16DecodeSurrogatePair(&items)) |decoded| {
1006 i += 2;
1007 try w.print("{u}", .{decoded});
1008 } else |_| {
1009 try w.print("\\x{x}", .{items[0]});
1010 }
1011 } else if (is_surrogate) {
1012 try w.print("\\x{x}", .{items[0]});
1013 } else {
1014 try w.print("{u}", .{items[0]});
1015 }
1016 }
711 },1017 },
712 .@"4" => {1018 .@"4" => {
713 try w.writeByte('"');1019 var item: [1]u32 = undefined;
714 const data_slice = std.mem.bytesAsSlice(u32, without_null);1020 const data_slice = std.mem.sliceAsBytes(item[0..1]);
715 var buf: [4]u8 = undefined;1021 for (0..@divExact(without_null.len, 4)) |n| {
716 for (data_slice) |item| {1022 @memcpy(data_slice, without_null[n * 4 ..][0..4]);
717 if (item <= std.math.maxInt(u21) and std.unicode.utf8ValidCodepoint(@intCast(item))) {1023 if (item[0] <= std.math.maxInt(u21) and std.unicode.utf8ValidCodepoint(@intCast(item[0]))) {
718 const codepoint: u21 = @intCast(item);1024 const codepoint: u21 = @intCast(item[0]);
719 const written = std.unicode.utf8Encode(codepoint, &buf) catch unreachable;1025 try w.print("{u}", .{codepoint});
720 try w.print("{s}", .{buf[0..written]});
721 } else {1026 } else {
722 try w.print("\\x{x}", .{item});1027 try w.print("\\x{x}", .{item[0]});
723 }1028 }
724 }1029 }
725 try w.writeByte('"');
726 },1030 },
727 }1031 }
1032 try w.writeByte('"');
728}1033}
lib/compiler/aro/aro/annex_g.zig created+118
...@@ -0,0 +1,118 @@
1//! Complex arithmetic algorithms from C99 Annex G
2
3const std = @import("std");
4const copysign = std.math.copysign;
5const ilogb = std.math.ilogb;
6const inf = std.math.inf;
7const isFinite = std.math.isFinite;
8const isInf = std.math.isInf;
9const isNan = std.math.isNan;
10const isPositiveZero = std.math.isPositiveZero;
11const scalbn = std.math.scalbn;
12
13/// computes floating point z*w where a_param, b_param are real, imaginary parts of z and c_param, d_param are real, imaginary parts of w
14pub fn complexFloatMul(comptime T: type, a_param: T, b_param: T, c_param: T, d_param: T) [2]T {
15 var a = a_param;
16 var b = b_param;
17 var c = c_param;
18 var d = d_param;
19
20 const ac = a * c;
21 const bd = b * d;
22 const ad = a * d;
23 const bc = b * c;
24 var x = ac - bd;
25 var y = ad + bc;
26 if (isNan(x) and isNan(y)) {
27 var recalc = false;
28 if (isInf(a) or isInf(b)) {
29 // lhs infinite
30 // Box the infinity and change NaNs in the other factor to 0
31 a = copysign(if (isInf(a)) @as(T, 1.0) else @as(T, 0.0), a);
32 b = copysign(if (isInf(b)) @as(T, 1.0) else @as(T, 0.0), b);
33 if (isNan(c)) c = copysign(@as(T, 0.0), c);
34 if (isNan(d)) d = copysign(@as(T, 0.0), d);
35 recalc = true;
36 }
37 if (isInf(c) or isInf(d)) {
38 // rhs infinite
39 // Box the infinity and change NaNs in the other factor to 0
40 c = copysign(if (isInf(c)) @as(T, 1.0) else @as(T, 0.0), c);
41 d = copysign(if (isInf(d)) @as(T, 1.0) else @as(T, 0.0), d);
42 if (isNan(a)) a = copysign(@as(T, 0.0), a);
43 if (isNan(b)) b = copysign(@as(T, 0.0), b);
44 recalc = true;
45 }
46 if (!recalc and (isInf(ac) or isInf(bd) or isInf(ad) or isInf(bc))) {
47 // Recover infinities from overflow by changing NaN's to 0
48 if (isNan(a)) a = copysign(@as(T, 0.0), a);
49 if (isNan(b)) b = copysign(@as(T, 0.0), b);
50 if (isNan(c)) c = copysign(@as(T, 0.0), c);
51 if (isNan(d)) d = copysign(@as(T, 0.0), d);
52 }
53 if (recalc) {
54 x = inf(T) * (a * c - b * d);
55 y = inf(T) * (a * d + b * c);
56 }
57 }
58 return .{ x, y };
59}
60
61/// computes floating point z / w where a_param, b_param are real, imaginary parts of z and c_param, d_param are real, imaginary parts of w
62pub fn complexFloatDiv(comptime T: type, a_param: T, b_param: T, c_param: T, d_param: T) [2]T {
63 var a = a_param;
64 var b = b_param;
65 var c = c_param;
66 var d = d_param;
67 var denom_logb: i32 = 0;
68 const max_cd = @max(@abs(c), @abs(d));
69 if (isFinite(max_cd)) {
70 if (max_cd == 0) {
71 denom_logb = std.math.minInt(i32) + 1;
72 c = 0;
73 d = 0;
74 } else {
75 denom_logb = ilogb(max_cd);
76 c = scalbn(c, -denom_logb);
77 d = scalbn(d, -denom_logb);
78 }
79 }
80 const denom = c * c + d * d;
81 var x = scalbn((a * c + b * d) / denom, -denom_logb);
82 var y = scalbn((b * c - a * d) / denom, -denom_logb);
83 if (isNan(x) and isNan(y)) {
84 if (isPositiveZero(denom) and (!isNan(a) or !isNan(b))) {
85 x = copysign(inf(T), c) * a;
86 y = copysign(inf(T), c) * b;
87 } else if ((isInf(a) or isInf(b)) and isFinite(c) and isFinite(d)) {
88 a = copysign(if (isInf(a)) @as(T, 1.0) else @as(T, 0.0), a);
89 b = copysign(if (isInf(b)) @as(T, 1.0) else @as(T, 0.0), b);
90 x = inf(T) * (a * c + b * d);
91 y = inf(T) * (b * c - a * d);
92 } else if (isInf(max_cd) and isFinite(a) and isFinite(b)) {
93 c = copysign(if (isInf(c)) @as(T, 1.0) else @as(T, 0.0), c);
94 d = copysign(if (isInf(d)) @as(T, 1.0) else @as(T, 0.0), d);
95 x = 0.0 * (a * c + b * d);
96 y = 0.0 * (b * c - a * d);
97 }
98 }
99 return .{ x, y };
100}
101
102test complexFloatMul {
103 // Naive algorithm would produce NaN + NaNi instead of inf + NaNi
104 const result = complexFloatMul(f64, inf(f64), std.math.nan(f64), 2, 0);
105 try std.testing.expect(isInf(result[0]));
106 try std.testing.expect(isNan(result[1]));
107}
108
109test complexFloatDiv {
110 // Naive algorithm would produce NaN + NaNi instead of inf + NaNi
111 var result = complexFloatDiv(f64, inf(f64), std.math.nan(f64), 2, 0);
112 try std.testing.expect(isInf(result[0]));
113 try std.testing.expect(isNan(result[1]));
114
115 result = complexFloatDiv(f64, 2.0, 2.0, 0.0, 0.0);
116 try std.testing.expect(isInf(result[0]));
117 try std.testing.expect(isInf(result[1]));
118}
lib/compiler/aro/aro/features.zig+2-2
...@@ -45,7 +45,7 @@ pub fn hasFeature(comp: *Compilation, ext: []const u8) bool {...@@ -45,7 +45,7 @@ pub fn hasFeature(comp: *Compilation, ext: []const u8) bool {
45 .c_static_assert = comp.langopts.standard.atLeast(.c11),45 .c_static_assert = comp.langopts.standard.atLeast(.c11),
46 .c_thread_local = comp.langopts.standard.atLeast(.c11) and target_util.isTlsSupported(comp.target),46 .c_thread_local = comp.langopts.standard.atLeast(.c11) and target_util.isTlsSupported(comp.target),
47 };47 };
48 inline for (std.meta.fields(@TypeOf(list))) |f| {48 inline for (@typeInfo(@TypeOf(list)).@"struct".fields) |f| {
49 if (std.mem.eql(u8, f.name, ext)) return @field(list, f.name);49 if (std.mem.eql(u8, f.name, ext)) return @field(list, f.name);
50 }50 }
51 return false;51 return false;
...@@ -69,7 +69,7 @@ pub fn hasExtension(comp: *Compilation, ext: []const u8) bool {...@@ -69,7 +69,7 @@ pub fn hasExtension(comp: *Compilation, ext: []const u8) bool {
69 .matrix_types = false, // TODO69 .matrix_types = false, // TODO
70 .matrix_types_scalar_division = false, // TODO70 .matrix_types_scalar_division = false, // TODO
71 };71 };
72 inline for (std.meta.fields(@TypeOf(list))) |f| {72 inline for (@typeInfo(@TypeOf(list)).@"struct".fields) |f| {
73 if (std.mem.eql(u8, f.name, ext)) return @field(list, f.name);73 if (std.mem.eql(u8, f.name, ext)) return @field(list, f.name);
74 }74 }
75 return false;75 return false;
lib/compiler/aro/aro/record_layout.zig+44-46
...@@ -19,6 +19,13 @@ const OngoingBitfield = struct {...@@ -19,6 +19,13 @@ const OngoingBitfield = struct {
19 unused_size_bits: u64,19 unused_size_bits: u64,
20};20};
2121
22pub const Error = error{Overflow};
23
24fn alignForward(addr: u64, alignment: u64) !u64 {
25 const forward_addr = try std.math.add(u64, addr, alignment - 1);
26 return std.mem.alignBackward(u64, forward_addr, alignment);
27}
28
22const SysVContext = struct {29const SysVContext = struct {
23 /// Does the record have an __attribute__((packed)) annotation.30 /// Does the record have an __attribute__((packed)) annotation.
24 attr_packed: bool,31 attr_packed: bool,
...@@ -36,14 +43,8 @@ const SysVContext = struct {...@@ -36,14 +43,8 @@ const SysVContext = struct {
36 comp: *const Compilation,43 comp: *const Compilation,
3744
38 fn init(ty: Type, comp: *const Compilation, pragma_pack: ?u8) SysVContext {45 fn init(ty: Type, comp: *const Compilation, pragma_pack: ?u8) SysVContext {
39 var pack_value: ?u64 = null;46 const pack_value: ?u64 = if (pragma_pack) |pak| @as(u64, pak) * BITS_PER_BYTE else null;
40 if (pragma_pack) |pak| {47 const req_align = @as(u32, (ty.requestedAlignment(comp) orelse 1)) * BITS_PER_BYTE;
41 pack_value = pak * BITS_PER_BYTE;
42 }
43 var req_align: u29 = BITS_PER_BYTE;
44 if (ty.requestedAlignment(comp)) |aln| {
45 req_align = aln * BITS_PER_BYTE;
46 }
47 return SysVContext{48 return SysVContext{
48 .attr_packed = ty.hasAttribute(.@"packed"),49 .attr_packed = ty.hasAttribute(.@"packed"),
49 .max_field_align_bits = pack_value,50 .max_field_align_bits = pack_value,
...@@ -55,7 +56,7 @@ const SysVContext = struct {...@@ -55,7 +56,7 @@ const SysVContext = struct {
55 };56 };
56 }57 }
5758
58 fn layoutFields(self: *SysVContext, rec: *const Record) void {59 fn layoutFields(self: *SysVContext, rec: *const Record) !void {
59 for (rec.fields, 0..) |*fld, fld_indx| {60 for (rec.fields, 0..) |*fld, fld_indx| {
60 if (fld.ty.specifier == .invalid) continue;61 if (fld.ty.specifier == .invalid) continue;
61 const type_layout = computeLayout(fld.ty, self.comp);62 const type_layout = computeLayout(fld.ty, self.comp);
...@@ -65,12 +66,12 @@ const SysVContext = struct {...@@ -65,12 +66,12 @@ const SysVContext = struct {
65 field_attrs = attrs[fld_indx];66 field_attrs = attrs[fld_indx];
66 }67 }
67 if (self.comp.target.isMinGW()) {68 if (self.comp.target.isMinGW()) {
68 fld.layout = self.layoutMinGWField(fld, field_attrs, type_layout);69 fld.layout = try self.layoutMinGWField(fld, field_attrs, type_layout);
69 } else {70 } else {
70 if (fld.isRegularField()) {71 if (fld.isRegularField()) {
71 fld.layout = self.layoutRegularField(field_attrs, type_layout);72 fld.layout = try self.layoutRegularField(field_attrs, type_layout);
72 } else {73 } else {
73 fld.layout = self.layoutBitField(field_attrs, type_layout, fld.isNamed(), fld.specifiedBitWidth());74 fld.layout = try self.layoutBitField(field_attrs, type_layout, fld.isNamed(), fld.specifiedBitWidth());
74 }75 }
75 }76 }
76 }77 }
...@@ -99,8 +100,8 @@ const SysVContext = struct {...@@ -99,8 +100,8 @@ const SysVContext = struct {
99 field: *const Field,100 field: *const Field,
100 field_attrs: ?[]const Attribute,101 field_attrs: ?[]const Attribute,
101 field_layout: TypeLayout,102 field_layout: TypeLayout,
102 ) FieldLayout {103 ) !FieldLayout {
103 const annotation_alignment_bits = BITS_PER_BYTE * (Type.annotationAlignment(self.comp, field_attrs) orelse 1);104 const annotation_alignment_bits = BITS_PER_BYTE * @as(u32, (Type.annotationAlignment(self.comp, Attribute.Iterator.initSlice(field_attrs)) orelse 1));
104 const is_attr_packed = self.attr_packed or isPacked(field_attrs);105 const is_attr_packed = self.attr_packed or isPacked(field_attrs);
105 const ignore_type_alignment = ignoreTypeAlignment(is_attr_packed, field.bit_width, self.ongoing_bitfield, field_layout);106 const ignore_type_alignment = ignoreTypeAlignment(is_attr_packed, field.bit_width, self.ongoing_bitfield, field_layout);
106107
...@@ -157,7 +158,7 @@ const SysVContext = struct {...@@ -157,7 +158,7 @@ const SysVContext = struct {
157 field_alignment_bits: u64,158 field_alignment_bits: u64,
158 is_named: bool,159 is_named: bool,
159 width: u64,160 width: u64,
160 ) FieldLayout {161 ) !FieldLayout {
161 std.debug.assert(width <= ty_size_bits); // validated in parser162 std.debug.assert(width <= ty_size_bits); // validated in parser
162163
163 // In a union, the size of the underlying type does not affect the size of the union.164 // In a union, the size of the underlying type does not affect the size of the union.
...@@ -194,8 +195,8 @@ const SysVContext = struct {...@@ -194,8 +195,8 @@ const SysVContext = struct {
194 .unused_size_bits = ty_size_bits - width,195 .unused_size_bits = ty_size_bits - width,
195 };196 };
196 }197 }
197 const offset_bits = std.mem.alignForward(u64, self.size_bits, field_alignment_bits);198 const offset_bits = try alignForward(self.size_bits, field_alignment_bits);
198 self.size_bits = if (width == 0) offset_bits else offset_bits + ty_size_bits;199 self.size_bits = if (width == 0) offset_bits else try std.math.add(u64, offset_bits, ty_size_bits);
199 if (!is_named) return .{};200 if (!is_named) return .{};
200 return .{201 return .{
201 .offset_bits = offset_bits,202 .offset_bits = offset_bits,
...@@ -207,16 +208,16 @@ const SysVContext = struct {...@@ -207,16 +208,16 @@ const SysVContext = struct {
207 self: *SysVContext,208 self: *SysVContext,
208 ty_size_bits: u64,209 ty_size_bits: u64,
209 field_alignment_bits: u64,210 field_alignment_bits: u64,
210 ) FieldLayout {211 ) !FieldLayout {
211 self.ongoing_bitfield = null;212 self.ongoing_bitfield = null;
212 // A struct field starts at the next offset in the struct that is properly213 // A struct field starts at the next offset in the struct that is properly
213 // aligned with respect to the start of the struct. See test case 0033.214 // aligned with respect to the start of the struct. See test case 0033.
214 // A union field always starts at offset 0.215 // A union field always starts at offset 0.
215 const offset_bits = if (self.is_union) 0 else std.mem.alignForward(u64, self.size_bits, field_alignment_bits);216 const offset_bits = if (self.is_union) 0 else try alignForward(self.size_bits, field_alignment_bits);
216217
217 // Set the size of the record to the maximum of the current size and the end of218 // Set the size of the record to the maximum of the current size and the end of
218 // the field. See test case 0034.219 // the field. See test case 0034.
219 self.size_bits = @max(self.size_bits, offset_bits + ty_size_bits);220 self.size_bits = @max(self.size_bits, try std.math.add(u64, offset_bits, ty_size_bits));
220221
221 return .{222 return .{
222 .offset_bits = offset_bits,223 .offset_bits = offset_bits,
...@@ -228,7 +229,7 @@ const SysVContext = struct {...@@ -228,7 +229,7 @@ const SysVContext = struct {
228 self: *SysVContext,229 self: *SysVContext,
229 fld_attrs: ?[]const Attribute,230 fld_attrs: ?[]const Attribute,
230 fld_layout: TypeLayout,231 fld_layout: TypeLayout,
231 ) FieldLayout {232 ) !FieldLayout {
232 var fld_align_bits = fld_layout.field_alignment_bits;233 var fld_align_bits = fld_layout.field_alignment_bits;
233234
234 // If the struct or the field is packed, then the alignment of the underlying type is235 // If the struct or the field is packed, then the alignment of the underlying type is
...@@ -239,8 +240,8 @@ const SysVContext = struct {...@@ -239,8 +240,8 @@ const SysVContext = struct {
239240
240 // The field alignment can be increased by __attribute__((aligned)) annotations on the241 // The field alignment can be increased by __attribute__((aligned)) annotations on the
241 // field. See test case 0085.242 // field. See test case 0085.
242 if (Type.annotationAlignment(self.comp, fld_attrs)) |anno| {243 if (Type.annotationAlignment(self.comp, Attribute.Iterator.initSlice(fld_attrs))) |anno| {
243 fld_align_bits = @max(fld_align_bits, anno * BITS_PER_BYTE);244 fld_align_bits = @max(fld_align_bits, @as(u32, anno) * BITS_PER_BYTE);
244 }245 }
245246
246 // #pragma pack takes precedence over all other attributes. See test cases 0084 and247 // #pragma pack takes precedence over all other attributes. See test cases 0084 and
...@@ -251,12 +252,12 @@ const SysVContext = struct {...@@ -251,12 +252,12 @@ const SysVContext = struct {
251252
252 // A struct field starts at the next offset in the struct that is properly253 // A struct field starts at the next offset in the struct that is properly
253 // aligned with respect to the start of the struct.254 // aligned with respect to the start of the struct.
254 const offset_bits = if (self.is_union) 0 else std.mem.alignForward(u64, self.size_bits, fld_align_bits);255 const offset_bits = if (self.is_union) 0 else try alignForward(self.size_bits, fld_align_bits);
255 const size_bits = fld_layout.size_bits;256 const size_bits = fld_layout.size_bits;
256257
257 // The alignment of a record is the maximum of its field alignments. See test cases258 // The alignment of a record is the maximum of its field alignments. See test cases
258 // 0084, 0085, 0086.259 // 0084, 0085, 0086.
259 self.size_bits = @max(self.size_bits, offset_bits + size_bits);260 self.size_bits = @max(self.size_bits, try std.math.add(u64, offset_bits, size_bits));
260 self.aligned_bits = @max(self.aligned_bits, fld_align_bits);261 self.aligned_bits = @max(self.aligned_bits, fld_align_bits);
261262
262 return .{263 return .{
...@@ -271,7 +272,7 @@ const SysVContext = struct {...@@ -271,7 +272,7 @@ const SysVContext = struct {
271 fld_layout: TypeLayout,272 fld_layout: TypeLayout,
272 is_named: bool,273 is_named: bool,
273 bit_width: u64,274 bit_width: u64,
274 ) FieldLayout {275 ) !FieldLayout {
275 const ty_size_bits = fld_layout.size_bits;276 const ty_size_bits = fld_layout.size_bits;
276 var ty_fld_algn_bits: u32 = fld_layout.field_alignment_bits;277 var ty_fld_algn_bits: u32 = fld_layout.field_alignment_bits;
277278
...@@ -301,7 +302,7 @@ const SysVContext = struct {...@@ -301,7 +302,7 @@ const SysVContext = struct {
301 const attr_packed = self.attr_packed or isPacked(fld_attrs);302 const attr_packed = self.attr_packed or isPacked(fld_attrs);
302 const has_packing_annotation = attr_packed or self.max_field_align_bits != null;303 const has_packing_annotation = attr_packed or self.max_field_align_bits != null;
303304
304 const annotation_alignment: u32 = if (Type.annotationAlignment(self.comp, fld_attrs)) |anno| anno * BITS_PER_BYTE else 1;305 const annotation_alignment = if (Type.annotationAlignment(self.comp, Attribute.Iterator.initSlice(fld_attrs))) |anno| @as(u32, anno) * BITS_PER_BYTE else 1;
305306
306 const first_unused_bit: u64 = if (self.is_union) 0 else self.size_bits;307 const first_unused_bit: u64 = if (self.is_union) 0 else self.size_bits;
307 var field_align_bits: u64 = 1;308 var field_align_bits: u64 = 1;
...@@ -322,7 +323,7 @@ const SysVContext = struct {...@@ -322,7 +323,7 @@ const SysVContext = struct {
322 // - the alignment of the type is larger than its size,323 // - the alignment of the type is larger than its size,
323 // then it is aligned to the type's field alignment. See test case 0083.324 // then it is aligned to the type's field alignment. See test case 0083.
324 if (!has_packing_annotation) {325 if (!has_packing_annotation) {
325 const start_bit = std.mem.alignForward(u64, first_unused_bit, field_align_bits);326 const start_bit = try alignForward(first_unused_bit, field_align_bits);
326327
327 const does_field_cross_boundary = start_bit % ty_fld_algn_bits + bit_width > ty_size_bits;328 const does_field_cross_boundary = start_bit % ty_fld_algn_bits + bit_width > ty_size_bits;
328329
...@@ -349,8 +350,8 @@ const SysVContext = struct {...@@ -349,8 +350,8 @@ const SysVContext = struct {
349 }350 }
350 }351 }
351352
352 const offset_bits = std.mem.alignForward(u64, first_unused_bit, field_align_bits);353 const offset_bits = try alignForward(first_unused_bit, field_align_bits);
353 self.size_bits = @max(self.size_bits, offset_bits + bit_width);354 self.size_bits = @max(self.size_bits, try std.math.add(u64, offset_bits, bit_width));
354355
355 // Unnamed fields do not contribute to the record alignment except on a few targets.356 // Unnamed fields do not contribute to the record alignment except on a few targets.
356 // See test case 0079.357 // See test case 0079.
...@@ -419,10 +420,7 @@ const MsvcContext = struct {...@@ -419,10 +420,7 @@ const MsvcContext = struct {
419420
420 // The required alignment can be increased by adding a __declspec(align)421 // The required alignment can be increased by adding a __declspec(align)
421 // annotation. See test case 0023.422 // annotation. See test case 0023.
422 var must_align: u29 = BITS_PER_BYTE;423 const must_align = @as(u32, (ty.requestedAlignment(comp) orelse 1)) * BITS_PER_BYTE;
423 if (ty.requestedAlignment(comp)) |req_align| {
424 must_align = req_align * BITS_PER_BYTE;
425 }
426 return MsvcContext{424 return MsvcContext{
427 .req_align_bits = must_align,425 .req_align_bits = must_align,
428 .pointer_align_bits = must_align,426 .pointer_align_bits = must_align,
...@@ -436,15 +434,15 @@ const MsvcContext = struct {...@@ -436,15 +434,15 @@ const MsvcContext = struct {
436 };434 };
437 }435 }
438436
439 fn layoutField(self: *MsvcContext, fld: *const Field, fld_attrs: ?[]const Attribute) FieldLayout {437 fn layoutField(self: *MsvcContext, fld: *const Field, fld_attrs: ?[]const Attribute) !FieldLayout {
440 const type_layout = computeLayout(fld.ty, self.comp);438 const type_layout = computeLayout(fld.ty, self.comp);
441439
442 // The required alignment of the field is the maximum of the required alignment of the440 // The required alignment of the field is the maximum of the required alignment of the
443 // underlying type and the __declspec(align) annotation on the field itself.441 // underlying type and the __declspec(align) annotation on the field itself.
444 // See test case 0028.442 // See test case 0028.
445 var req_align = type_layout.required_alignment_bits;443 var req_align = type_layout.required_alignment_bits;
446 if (Type.annotationAlignment(self.comp, fld_attrs)) |anno| {444 if (Type.annotationAlignment(self.comp, Attribute.Iterator.initSlice(fld_attrs))) |anno| {
447 req_align = @max(anno * BITS_PER_BYTE, req_align);445 req_align = @max(@as(u32, anno) * BITS_PER_BYTE, req_align);
448 }446 }
449447
450 // The required alignment of a record is the maximum of the required alignments of its448 // The required alignment of a record is the maximum of the required alignments of its
...@@ -480,7 +478,7 @@ const MsvcContext = struct {...@@ -480,7 +478,7 @@ const MsvcContext = struct {
480 }478 }
481 }479 }
482480
483 fn layoutBitField(self: *MsvcContext, ty_size_bits: u64, field_align: u32, bit_width: u32) FieldLayout {481 fn layoutBitField(self: *MsvcContext, ty_size_bits: u64, field_align: u32, bit_width: u32) !FieldLayout {
484 if (bit_width == 0) {482 if (bit_width == 0) {
485 // A zero-sized bit-field that does not follow a non-zero-sized bit-field does not affect483 // A zero-sized bit-field that does not follow a non-zero-sized bit-field does not affect
486 // the overall layout of the record. Even in a union where the order would otherwise484 // the overall layout of the record. Even in a union where the order would otherwise
...@@ -522,7 +520,7 @@ const MsvcContext = struct {...@@ -522,7 +520,7 @@ const MsvcContext = struct {
522 self.pointer_align_bits = @max(self.pointer_align_bits, p_align);520 self.pointer_align_bits = @max(self.pointer_align_bits, p_align);
523 self.field_align_bits = @max(self.field_align_bits, field_align);521 self.field_align_bits = @max(self.field_align_bits, field_align);
524522
525 const offset_bits = std.mem.alignForward(u64, self.size_bits, field_align);523 const offset_bits = try alignForward(self.size_bits, field_align);
526 self.size_bits = if (bit_width == 0) offset_bits else offset_bits + ty_size_bits;524 self.size_bits = if (bit_width == 0) offset_bits else offset_bits + ty_size_bits;
527525
528 break :bits offset_bits;526 break :bits offset_bits;
...@@ -534,7 +532,7 @@ const MsvcContext = struct {...@@ -534,7 +532,7 @@ const MsvcContext = struct {
534 return .{ .offset_bits = offset_bits, .size_bits = bit_width };532 return .{ .offset_bits = offset_bits, .size_bits = bit_width };
535 }533 }
536534
537 fn layoutRegularField(self: *MsvcContext, size_bits: u64, field_align: u32) FieldLayout {535 fn layoutRegularField(self: *MsvcContext, size_bits: u64, field_align: u32) !FieldLayout {
538 self.contains_non_bitfield = true;536 self.contains_non_bitfield = true;
539 self.ongoing_bitfield = null;537 self.ongoing_bitfield = null;
540 // The alignment of the field affects both the pointer alignment and the field538 // The alignment of the field affects both the pointer alignment and the field
...@@ -543,7 +541,7 @@ const MsvcContext = struct {...@@ -543,7 +541,7 @@ const MsvcContext = struct {
543 self.field_align_bits = @max(self.field_align_bits, field_align);541 self.field_align_bits = @max(self.field_align_bits, field_align);
544 const offset_bits = switch (self.is_union) {542 const offset_bits = switch (self.is_union) {
545 true => 0,543 true => 0,
546 false => std.mem.alignForward(u64, self.size_bits, field_align),544 false => try alignForward(self.size_bits, field_align),
547 };545 };
548 self.size_bits = @max(self.size_bits, offset_bits + size_bits);546 self.size_bits = @max(self.size_bits, offset_bits + size_bits);
549 return .{ .offset_bits = offset_bits, .size_bits = size_bits };547 return .{ .offset_bits = offset_bits, .size_bits = size_bits };
...@@ -569,14 +567,14 @@ const MsvcContext = struct {...@@ -569,14 +567,14 @@ const MsvcContext = struct {
569 }567 }
570};568};
571569
572pub fn compute(rec: *Type.Record, ty: Type, comp: *const Compilation, pragma_pack: ?u8) void {570pub fn compute(rec: *Type.Record, ty: Type, comp: *const Compilation, pragma_pack: ?u8) Error!void {
573 switch (comp.langopts.emulate) {571 switch (comp.langopts.emulate) {
574 .gcc, .clang => {572 .gcc, .clang => {
575 var context = SysVContext.init(ty, comp, pragma_pack);573 var context = SysVContext.init(ty, comp, pragma_pack);
576574
577 context.layoutFields(rec);575 try context.layoutFields(rec);
578576
579 context.size_bits = std.mem.alignForward(u64, context.size_bits, context.aligned_bits);577 context.size_bits = try alignForward(context.size_bits, context.aligned_bits);
580578
581 rec.type_layout = .{579 rec.type_layout = .{
582 .size_bits = context.size_bits,580 .size_bits = context.size_bits,
...@@ -594,7 +592,7 @@ pub fn compute(rec: *Type.Record, ty: Type, comp: *const Compilation, pragma_pac...@@ -594,7 +592,7 @@ pub fn compute(rec: *Type.Record, ty: Type, comp: *const Compilation, pragma_pac
594 field_attrs = attrs[fld_indx];592 field_attrs = attrs[fld_indx];
595 }593 }
596594
597 fld.layout = context.layoutField(fld, field_attrs);595 fld.layout = try context.layoutField(fld, field_attrs);
598 }596 }
599 if (context.size_bits == 0) {597 if (context.size_bits == 0) {
600 // As an extension, MSVC allows records that only contain zero-sized bitfields and empty598 // As an extension, MSVC allows records that only contain zero-sized bitfields and empty
...@@ -602,7 +600,7 @@ pub fn compute(rec: *Type.Record, ty: Type, comp: *const Compilation, pragma_pac...@@ -602,7 +600,7 @@ pub fn compute(rec: *Type.Record, ty: Type, comp: *const Compilation, pragma_pac
602 // ensure that there are no zero-sized records.600 // ensure that there are no zero-sized records.
603 context.handleZeroSizedRecord();601 context.handleZeroSizedRecord();
604 }602 }
605 context.size_bits = std.mem.alignForward(u64, context.size_bits, context.pointer_align_bits);603 context.size_bits = try alignForward(context.size_bits, context.pointer_align_bits);
606 rec.type_layout = .{604 rec.type_layout = .{
607 .size_bits = context.size_bits,605 .size_bits = context.size_bits,
608 .field_alignment_bits = context.field_align_bits,606 .field_alignment_bits = context.field_align_bits,
lib/compiler/aro/aro/target.zig+15-5
...@@ -35,10 +35,7 @@ pub fn intMaxType(target: std.Target) Type {...@@ -35,10 +35,7 @@ pub fn intMaxType(target: std.Target) Type {
3535
36/// intptr_t for this target36/// intptr_t for this target
37pub fn intPtrType(target: std.Target) Type {37pub fn intPtrType(target: std.Target) Type {
38 switch (target.os.tag) {38 if (target.os.tag == .haiku) return .{ .specifier = .long };
39 .haiku => return .{ .specifier = .long },
40 else => {},
41 }
4239
43 switch (target.cpu.arch) {40 switch (target.cpu.arch) {
44 .aarch64, .aarch64_be => switch (target.os.tag) {41 .aarch64, .aarch64_be => switch (target.os.tag) {
...@@ -127,6 +124,14 @@ pub fn int64Type(target: std.Target) Type {...@@ -127,6 +124,14 @@ pub fn int64Type(target: std.Target) Type {
127 return .{ .specifier = .long_long };124 return .{ .specifier = .long_long };
128}125}
129126
127pub fn float80Type(target: std.Target) ?Type {
128 switch (target.cpu.arch) {
129 .x86, .x86_64 => return .{ .specifier = .long_double },
130 else => {},
131 }
132 return null;
133}
134
130/// This function returns 1 if function alignment is not observable or settable.135/// This function returns 1 if function alignment is not observable or settable.
131pub fn defaultFunctionAlignment(target: std.Target) u8 {136pub fn defaultFunctionAlignment(target: std.Target) u8 {
132 return switch (target.cpu.arch) {137 return switch (target.cpu.arch) {
...@@ -474,6 +479,7 @@ pub fn get32BitArchVariant(target: std.Target) ?std.Target {...@@ -474,6 +479,7 @@ pub fn get32BitArchVariant(target: std.Target) ?std.Target {
474 .kalimba,479 .kalimba,
475 .lanai,480 .lanai,
476 .wasm32,481 .wasm32,
482 .spirv,
477 .spirv32,483 .spirv32,
478 .loongarch32,484 .loongarch32,
479 .dxil,485 .dxil,
...@@ -544,6 +550,7 @@ pub fn get64BitArchVariant(target: std.Target) ?std.Target {...@@ -544,6 +550,7 @@ pub fn get64BitArchVariant(target: std.Target) ?std.Target {
544 .powerpcle => copy.cpu.arch = .powerpc64le,550 .powerpcle => copy.cpu.arch = .powerpc64le,
545 .riscv32 => copy.cpu.arch = .riscv64,551 .riscv32 => copy.cpu.arch = .riscv64,
546 .sparc => copy.cpu.arch = .sparc64,552 .sparc => copy.cpu.arch = .sparc64,
553 .spirv => copy.cpu.arch = .spirv64,
547 .spirv32 => copy.cpu.arch = .spirv64,554 .spirv32 => copy.cpu.arch = .spirv64,
548 .thumb => copy.cpu.arch = .aarch64,555 .thumb => copy.cpu.arch = .aarch64,
549 .thumbeb => copy.cpu.arch = .aarch64_be,556 .thumbeb => copy.cpu.arch = .aarch64_be,
...@@ -599,6 +606,7 @@ pub fn toLLVMTriple(target: std.Target, buf: []u8) []const u8 {...@@ -599,6 +606,7 @@ pub fn toLLVMTriple(target: std.Target, buf: []u8) []const u8 {
599 .xtensa => "xtensa",606 .xtensa => "xtensa",
600 .nvptx => "nvptx",607 .nvptx => "nvptx",
601 .nvptx64 => "nvptx64",608 .nvptx64 => "nvptx64",
609 .spirv => "spirv",
602 .spirv32 => "spirv32",610 .spirv32 => "spirv32",
603 .spirv64 => "spirv64",611 .spirv64 => "spirv64",
604 .kalimba => "kalimba",612 .kalimba => "kalimba",
...@@ -646,9 +654,10 @@ pub fn toLLVMTriple(target: std.Target, buf: []u8) []const u8 {...@@ -646,9 +654,10 @@ pub fn toLLVMTriple(target: std.Target, buf: []u8) []const u8 {
646 .ios => "ios",654 .ios => "ios",
647 .tvos => "tvos",655 .tvos => "tvos",
648 .watchos => "watchos",656 .watchos => "watchos",
649 .visionos => "xros",
650 .driverkit => "driverkit",657 .driverkit => "driverkit",
651 .shadermodel => "shadermodel",658 .shadermodel => "shadermodel",
659 .visionos => "xros",
660 .serenity => "serenity",
652 .opencl,661 .opencl,
653 .opengl,662 .opengl,
654 .vulkan,663 .vulkan,
...@@ -707,6 +716,7 @@ pub fn toLLVMTriple(target: std.Target, buf: []u8) []const u8 {...@@ -707,6 +716,7 @@ pub fn toLLVMTriple(target: std.Target, buf: []u8) []const u8 {
707 .callable => "callable",716 .callable => "callable",
708 .mesh => "mesh",717 .mesh => "mesh",
709 .amplification => "amplification",718 .amplification => "amplification",
719 .ohos => "openhos",
710 };720 };
711 writer.writeAll(llvm_abi) catch unreachable;721 writer.writeAll(llvm_abi) catch unreachable;
712 return stream.getWritten();722 return stream.getWritten();
lib/compiler/aro/aro/text_literal.zig+2-2
...@@ -71,7 +71,7 @@ pub const Kind = enum {...@@ -71,7 +71,7 @@ pub const Kind = enum {
71 pub fn maxCodepoint(kind: Kind, comp: *const Compilation) u21 {71 pub fn maxCodepoint(kind: Kind, comp: *const Compilation) u21 {
72 return @intCast(switch (kind) {72 return @intCast(switch (kind) {
73 .char => std.math.maxInt(u7),73 .char => std.math.maxInt(u7),
74 .wide => @min(0x10FFFF, comp.types.wchar.maxInt(comp)),74 .wide => @min(0x10FFFF, comp.wcharMax()),
75 .utf_8 => std.math.maxInt(u7),75 .utf_8 => std.math.maxInt(u7),
76 .utf_16 => std.math.maxInt(u16),76 .utf_16 => std.math.maxInt(u16),
77 .utf_32 => 0x10FFFF,77 .utf_32 => 0x10FFFF,
...@@ -83,7 +83,7 @@ pub const Kind = enum {...@@ -83,7 +83,7 @@ pub const Kind = enum {
83 pub fn maxInt(kind: Kind, comp: *const Compilation) u32 {83 pub fn maxInt(kind: Kind, comp: *const Compilation) u32 {
84 return @intCast(switch (kind) {84 return @intCast(switch (kind) {
85 .char, .utf_8 => std.math.maxInt(u8),85 .char, .utf_8 => std.math.maxInt(u8),
86 .wide => comp.types.wchar.maxInt(comp),86 .wide => comp.wcharMax(),
87 .utf_16 => std.math.maxInt(u16),87 .utf_16 => std.math.maxInt(u16),
88 .utf_32 => std.math.maxInt(u32),88 .utf_32 => std.math.maxInt(u32),
89 .unterminated => unreachable,89 .unterminated => unreachable,
lib/compiler/aro/aro/toolchains/Linux.zig+1-1
...@@ -423,7 +423,7 @@ test Linux {...@@ -423,7 +423,7 @@ test Linux {
423 defer arena_instance.deinit();423 defer arena_instance.deinit();
424 const arena = arena_instance.allocator();424 const arena = arena_instance.allocator();
425425
426 var comp = Compilation.init(std.testing.allocator);426 var comp = Compilation.init(std.testing.allocator, std.fs.cwd());
427 defer comp.deinit();427 defer comp.deinit();
428 comp.environment = .{428 comp.environment = .{
429 .path = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",429 .path = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
lib/compiler/aro/backend/Interner.zig+226
...@@ -34,6 +34,7 @@ const KeyAdapter = struct {...@@ -34,6 +34,7 @@ const KeyAdapter = struct {
34pub const Key = union(enum) {34pub const Key = union(enum) {
35 int_ty: u16,35 int_ty: u16,
36 float_ty: u16,36 float_ty: u16,
37 complex_ty: u16,
37 ptr_ty,38 ptr_ty,
38 noreturn_ty,39 noreturn_ty,
39 void_ty,40 void_ty,
...@@ -62,6 +63,7 @@ pub const Key = union(enum) {...@@ -62,6 +63,7 @@ pub const Key = union(enum) {
62 }63 }
63 },64 },
64 float: Float,65 float: Float,
66 complex: Complex,
65 bytes: []const u8,67 bytes: []const u8,
6668
67 pub const Float = union(enum) {69 pub const Float = union(enum) {
...@@ -71,6 +73,13 @@ pub const Key = union(enum) {...@@ -71,6 +73,13 @@ pub const Key = union(enum) {
71 f80: f80,73 f80: f80,
72 f128: f128,74 f128: f128,
73 };75 };
76 pub const Complex = union(enum) {
77 cf16: [2]f16,
78 cf32: [2]f32,
79 cf64: [2]f64,
80 cf80: [2]f80,
81 cf128: [2]f128,
82 };
7483
75 pub fn hash(key: Key) u32 {84 pub fn hash(key: Key) u32 {
76 var hasher = Hash.init(0);85 var hasher = Hash.init(0);
...@@ -89,6 +98,12 @@ pub const Key = union(enum) {...@@ -89,6 +98,12 @@ pub const Key = union(enum) {
89 @as(std.meta.Int(.unsigned, @bitSizeOf(@TypeOf(data))), @bitCast(data)),98 @as(std.meta.Int(.unsigned, @bitSizeOf(@TypeOf(data))), @bitCast(data)),
90 ),99 ),
91 },100 },
101 .complex => |repr| switch (repr) {
102 inline else => |data| std.hash.autoHash(
103 &hasher,
104 @as(std.meta.Int(.unsigned, @bitSizeOf(@TypeOf(data))), @bitCast(data)),
105 ),
106 },
92 .int => |repr| {107 .int => |repr| {
93 var space: Tag.Int.BigIntSpace = undefined;108 var space: Tag.Int.BigIntSpace = undefined;
94 const big = repr.toBigInt(&space);109 const big = repr.toBigInt(&space);
...@@ -154,6 +169,14 @@ pub const Key = union(enum) {...@@ -154,6 +169,14 @@ pub const Key = union(enum) {
154 128 => return .f128,169 128 => return .f128,
155 else => unreachable,170 else => unreachable,
156 },171 },
172 .complex_ty => |bits| switch (bits) {
173 16 => return .cf16,
174 32 => return .cf32,
175 64 => return .cf64,
176 80 => return .cf80,
177 128 => return .cf128,
178 else => unreachable,
179 },
157 .ptr_ty => return .ptr,180 .ptr_ty => return .ptr,
158 .func_ty => return .func,181 .func_ty => return .func,
159 .noreturn_ty => return .noreturn,182 .noreturn_ty => return .noreturn,
...@@ -199,6 +222,11 @@ pub const Ref = enum(u32) {...@@ -199,6 +222,11 @@ pub const Ref = enum(u32) {
199 zero = max - 16,222 zero = max - 16,
200 one = max - 17,223 one = max - 17,
201 null = max - 18,224 null = max - 18,
225 cf16 = max - 19,
226 cf32 = max - 20,
227 cf64 = max - 21,
228 cf80 = max - 22,
229 cf128 = max - 23,
202 _,230 _,
203};231};
204232
...@@ -224,6 +252,11 @@ pub const OptRef = enum(u32) {...@@ -224,6 +252,11 @@ pub const OptRef = enum(u32) {
224 zero = max - 16,252 zero = max - 16,
225 one = max - 17,253 one = max - 17,
226 null = max - 18,254 null = max - 18,
255 cf16 = max - 19,
256 cf32 = max - 20,
257 cf64 = max - 21,
258 cf80 = max - 22,
259 cf128 = max - 23,
227 _,260 _,
228};261};
229262
...@@ -232,6 +265,8 @@ pub const Tag = enum(u8) {...@@ -232,6 +265,8 @@ pub const Tag = enum(u8) {
232 int_ty,265 int_ty,
233 /// `data` is `u16`266 /// `data` is `u16`
234 float_ty,267 float_ty,
268 /// `data` is `u16`
269 complex_ty,
235 /// `data` is index to `Array`270 /// `data` is index to `Array`
236 array_ty,271 array_ty,
237 /// `data` is index to `Vector`272 /// `data` is index to `Vector`
...@@ -254,6 +289,16 @@ pub const Tag = enum(u8) {...@@ -254,6 +289,16 @@ pub const Tag = enum(u8) {
254 f80,289 f80,
255 /// `data` is `F128`290 /// `data` is `F128`
256 f128,291 f128,
292 /// `data` is `CF16`
293 cf16,
294 /// `data` is `CF32`
295 cf32,
296 /// `data` is `CF64`
297 cf64,
298 /// `data` is `CF80`
299 cf80,
300 /// `data` is `CF128`
301 cf128,
257 /// `data` is `Bytes`302 /// `data` is `Bytes`
258 bytes,303 bytes,
259 /// `data` is `Record`304 /// `data` is `Record`
...@@ -354,6 +399,134 @@ pub const Tag = enum(u8) {...@@ -354,6 +399,134 @@ pub const Tag = enum(u8) {
354 }399 }
355 };400 };
356401
402 pub const CF16 = struct {
403 piece0: u32,
404
405 pub fn get(self: CF16) [2]f16 {
406 const real: f16 = @bitCast(@as(u16, @truncate(self.piece0 >> 16)));
407 const imag: f16 = @bitCast(@as(u16, @truncate(self.piece0)));
408 return .{
409 real,
410 imag,
411 };
412 }
413
414 fn pack(val: [2]f16) CF16 {
415 const real: u16 = @bitCast(val[0]);
416 const imag: u16 = @bitCast(val[1]);
417 return .{
418 .piece0 = (@as(u32, real) << 16) | @as(u32, imag),
419 };
420 }
421 };
422
423 pub const CF32 = struct {
424 piece0: u32,
425 piece1: u32,
426
427 pub fn get(self: CF32) [2]f32 {
428 return .{
429 @bitCast(self.piece0),
430 @bitCast(self.piece1),
431 };
432 }
433
434 fn pack(val: [2]f32) CF32 {
435 return .{
436 .piece0 = @bitCast(val[0]),
437 .piece1 = @bitCast(val[1]),
438 };
439 }
440 };
441
442 pub const CF64 = struct {
443 piece0: u32,
444 piece1: u32,
445 piece2: u32,
446 piece3: u32,
447
448 pub fn get(self: CF64) [2]f64 {
449 return .{
450 (F64{ .piece0 = self.piece0, .piece1 = self.piece1 }).get(),
451 (F64{ .piece0 = self.piece2, .piece1 = self.piece3 }).get(),
452 };
453 }
454
455 fn pack(val: [2]f64) CF64 {
456 const real = F64.pack(val[0]);
457 const imag = F64.pack(val[1]);
458 return .{
459 .piece0 = real.piece0,
460 .piece1 = real.piece1,
461 .piece2 = imag.piece0,
462 .piece3 = imag.piece1,
463 };
464 }
465 };
466
467 /// TODO pack into 5 pieces
468 pub const CF80 = struct {
469 piece0: u32,
470 piece1: u32,
471 piece2: u32, // u16 part, top bits
472 piece3: u32,
473 piece4: u32,
474 piece5: u32, // u16 part, top bits
475
476 pub fn get(self: CF80) [2]f80 {
477 return .{
478 (F80{ .piece0 = self.piece0, .piece1 = self.piece1, .piece2 = self.piece2 }).get(),
479 (F80{ .piece0 = self.piece3, .piece1 = self.piece4, .piece2 = self.piece5 }).get(),
480 };
481 }
482
483 fn pack(val: [2]f80) CF80 {
484 const real = F80.pack(val[0]);
485 const imag = F80.pack(val[1]);
486 return .{
487 .piece0 = real.piece0,
488 .piece1 = real.piece1,
489 .piece2 = real.piece2,
490 .piece3 = imag.piece0,
491 .piece4 = imag.piece1,
492 .piece5 = imag.piece2,
493 };
494 }
495 };
496
497 pub const CF128 = struct {
498 piece0: u32,
499 piece1: u32,
500 piece2: u32,
501 piece3: u32,
502 piece4: u32,
503 piece5: u32,
504 piece6: u32,
505 piece7: u32,
506
507 pub fn get(self: CF128) [2]f128 {
508 return .{
509 (F128{ .piece0 = self.piece0, .piece1 = self.piece1, .piece2 = self.piece2, .piece3 = self.piece3 }).get(),
510 (F128{ .piece0 = self.piece4, .piece1 = self.piece5, .piece2 = self.piece6, .piece3 = self.piece7 }).get(),
511 };
512 }
513
514 fn pack(val: [2]f128) CF128 {
515 const real = F128.pack(val[0]);
516 const imag = F128.pack(val[1]);
517 return .{
518 .piece0 = real.piece0,
519 .piece1 = real.piece1,
520 .piece2 = real.piece2,
521 .piece3 = real.piece3,
522 .piece4 = imag.piece0,
523 .piece5 = imag.piece1,
524 .piece6 = imag.piece2,
525 .piece7 = imag.piece3,
526 };
527 }
528 };
529
357 pub const Bytes = struct {530 pub const Bytes = struct {
358 strings_index: u32,531 strings_index: u32,
359 len: u32,532 len: u32,
...@@ -407,6 +580,12 @@ pub fn put(i: *Interner, gpa: Allocator, key: Key) !Ref {...@@ -407,6 +580,12 @@ pub fn put(i: *Interner, gpa: Allocator, key: Key) !Ref {
407 .data = bits,580 .data = bits,
408 });581 });
409 },582 },
583 .complex_ty => |bits| {
584 i.items.appendAssumeCapacity(.{
585 .tag = .complex_ty,
586 .data = bits,
587 });
588 },
410 .array_ty => |info| {589 .array_ty => |info| {
411 const split_len = PackedU64.init(info.len);590 const split_len = PackedU64.init(info.len);
412 i.items.appendAssumeCapacity(.{591 i.items.appendAssumeCapacity(.{
...@@ -493,6 +672,28 @@ pub fn put(i: *Interner, gpa: Allocator, key: Key) !Ref {...@@ -493,6 +672,28 @@ pub fn put(i: *Interner, gpa: Allocator, key: Key) !Ref {
493 .data = try i.addExtra(gpa, Tag.F128.pack(data)),672 .data = try i.addExtra(gpa, Tag.F128.pack(data)),
494 }),673 }),
495 },674 },
675 .complex => |repr| switch (repr) {
676 .cf16 => |data| i.items.appendAssumeCapacity(.{
677 .tag = .cf16,
678 .data = try i.addExtra(gpa, Tag.CF16.pack(data)),
679 }),
680 .cf32 => |data| i.items.appendAssumeCapacity(.{
681 .tag = .cf32,
682 .data = try i.addExtra(gpa, Tag.CF32.pack(data)),
683 }),
684 .cf64 => |data| i.items.appendAssumeCapacity(.{
685 .tag = .cf64,
686 .data = try i.addExtra(gpa, Tag.CF64.pack(data)),
687 }),
688 .cf80 => |data| i.items.appendAssumeCapacity(.{
689 .tag = .cf80,
690 .data = try i.addExtra(gpa, Tag.CF80.pack(data)),
691 }),
692 .cf128 => |data| i.items.appendAssumeCapacity(.{
693 .tag = .cf128,
694 .data = try i.addExtra(gpa, Tag.CF128.pack(data)),
695 }),
696 },
496 .bytes => |bytes| {697 .bytes => |bytes| {
497 const strings_index: u32 = @intCast(i.strings.items.len);698 const strings_index: u32 = @intCast(i.strings.items.len);
498 try i.strings.appendSlice(gpa, bytes);699 try i.strings.appendSlice(gpa, bytes);
...@@ -564,6 +765,10 @@ pub fn get(i: *const Interner, ref: Ref) Key {...@@ -564,6 +765,10 @@ pub fn get(i: *const Interner, ref: Ref) Key {
564 .zero => return .{ .int = .{ .u64 = 0 } },765 .zero => return .{ .int = .{ .u64 = 0 } },
565 .one => return .{ .int = .{ .u64 = 1 } },766 .one => return .{ .int = .{ .u64 = 1 } },
566 .null => return .null,767 .null => return .null,
768 .cf16 => return .{ .complex_ty = 16 },
769 .cf32 => return .{ .complex_ty = 32 },
770 .cf64 => return .{ .complex_ty = 64 },
771 .cf80 => return .{ .complex_ty = 80 },
567 else => {},772 else => {},
568 }773 }
569774
...@@ -572,6 +777,7 @@ pub fn get(i: *const Interner, ref: Ref) Key {...@@ -572,6 +777,7 @@ pub fn get(i: *const Interner, ref: Ref) Key {
572 return switch (item.tag) {777 return switch (item.tag) {
573 .int_ty => .{ .int_ty = @intCast(data) },778 .int_ty => .{ .int_ty = @intCast(data) },
574 .float_ty => .{ .float_ty = @intCast(data) },779 .float_ty => .{ .float_ty = @intCast(data) },
780 .complex_ty => .{ .complex_ty = @intCast(data) },
575 .array_ty => {781 .array_ty => {
576 const array_ty = i.extraData(Tag.Array, data);782 const array_ty = i.extraData(Tag.Array, data);
577 return .{ .array_ty = .{783 return .{ .array_ty = .{
...@@ -612,6 +818,26 @@ pub fn get(i: *const Interner, ref: Ref) Key {...@@ -612,6 +818,26 @@ pub fn get(i: *const Interner, ref: Ref) Key {
612 const float = i.extraData(Tag.F128, data);818 const float = i.extraData(Tag.F128, data);
613 return .{ .float = .{ .f128 = float.get() } };819 return .{ .float = .{ .f128 = float.get() } };
614 },820 },
821 .cf16 => {
822 const components = i.extraData(Tag.CF16, data);
823 return .{ .complex = .{ .cf16 = components.get() } };
824 },
825 .cf32 => {
826 const components = i.extraData(Tag.CF32, data);
827 return .{ .complex = .{ .cf32 = components.get() } };
828 },
829 .cf64 => {
830 const components = i.extraData(Tag.CF64, data);
831 return .{ .complex = .{ .cf64 = components.get() } };
832 },
833 .cf80 => {
834 const components = i.extraData(Tag.CF80, data);
835 return .{ .complex = .{ .cf80 = components.get() } };
836 },
837 .cf128 => {
838 const components = i.extraData(Tag.CF128, data);
839 return .{ .complex = .{ .cf128 = components.get() } };
840 },
615 .bytes => {841 .bytes => {
616 const bytes = i.extraData(Tag.Bytes, data);842 const bytes = i.extraData(Tag.Bytes, data);
617 return .{ .bytes = i.strings.items[bytes.strings_index..][0..bytes.len] };843 return .{ .bytes = i.strings.items[bytes.strings_index..][0..bytes.len] };
lib/compiler/aro/backend/Ir.zig+1
...@@ -37,6 +37,7 @@ pub const Builder = struct {...@@ -37,6 +37,7 @@ pub const Builder = struct {
37 for (b.decls.values()) |*decl| {37 for (b.decls.values()) |*decl| {
38 decl.deinit(b.gpa);38 decl.deinit(b.gpa);
39 }39 }
40 b.decls.deinit(b.gpa);
40 b.arena.deinit();41 b.arena.deinit();
41 b.instructions.deinit(b.gpa);42 b.instructions.deinit(b.gpa);
42 b.body.deinit(b.gpa);43 b.body.deinit(b.gpa);
lib/compiler/aro/backend/Object.zig+5-5
...@@ -16,7 +16,7 @@ pub fn create(gpa: Allocator, target: std.Target) !*Object {...@@ -16,7 +16,7 @@ pub fn create(gpa: Allocator, target: std.Target) !*Object {
1616
17pub fn deinit(obj: *Object) void {17pub fn deinit(obj: *Object) void {
18 switch (obj.format) {18 switch (obj.format) {
19 .elf => @as(*Elf, @fieldParentPtr("obj", obj)).deinit(),19 .elf => @as(*Elf, @alignCast(@fieldParentPtr("obj", obj))).deinit(),
20 else => unreachable,20 else => unreachable,
21 }21 }
22}22}
...@@ -32,7 +32,7 @@ pub const Section = union(enum) {...@@ -32,7 +32,7 @@ pub const Section = union(enum) {
3232
33pub fn getSection(obj: *Object, section: Section) !*std.ArrayList(u8) {33pub fn getSection(obj: *Object, section: Section) !*std.ArrayList(u8) {
34 switch (obj.format) {34 switch (obj.format) {
35 .elf => return @as(*Elf, @fieldParentPtr("obj", obj)).getSection(section),35 .elf => return @as(*Elf, @alignCast(@fieldParentPtr("obj", obj))).getSection(section),
36 else => unreachable,36 else => unreachable,
37 }37 }
38}38}
...@@ -53,21 +53,21 @@ pub fn declareSymbol(...@@ -53,21 +53,21 @@ pub fn declareSymbol(
53 size: u64,53 size: u64,
54) ![]const u8 {54) ![]const u8 {
55 switch (obj.format) {55 switch (obj.format) {
56 .elf => return @as(*Elf, @fieldParentPtr("obj", obj)).declareSymbol(section, name, linkage, @"type", offset, size),56 .elf => return @as(*Elf, @alignCast(@fieldParentPtr("obj", obj))).declareSymbol(section, name, linkage, @"type", offset, size),
57 else => unreachable,57 else => unreachable,
58 }58 }
59}59}
6060
61pub fn addRelocation(obj: *Object, name: []const u8, section: Section, address: u64, addend: i64) !void {61pub fn addRelocation(obj: *Object, name: []const u8, section: Section, address: u64, addend: i64) !void {
62 switch (obj.format) {62 switch (obj.format) {
63 .elf => return @as(*Elf, @fieldParentPtr("obj", obj)).addRelocation(name, section, address, addend),63 .elf => return @as(*Elf, @alignCast(@fieldParentPtr("obj", obj))).addRelocation(name, section, address, addend),
64 else => unreachable,64 else => unreachable,
65 }65 }
66}66}
6767
68pub fn finish(obj: *Object, file: std.fs.File) !void {68pub fn finish(obj: *Object, file: std.fs.File) !void {
69 switch (obj.format) {69 switch (obj.format) {
70 .elf => return @as(*Elf, @fieldParentPtr("obj", obj)).finish(file),70 .elf => return @as(*Elf, @alignCast(@fieldParentPtr("obj", obj))).finish(file),
71 else => unreachable,71 else => unreachable,
72 }72 }
73}73}
lib/compiler/aro_translate_c.zig+1-2
...@@ -731,7 +731,6 @@ fn transType(c: *Context, scope: *Scope, raw_ty: Type, qual_handling: Type.QualH...@@ -731,7 +731,6 @@ fn transType(c: *Context, scope: *Scope, raw_ty: Type, qual_handling: Type.QualH
731 .float => return ZigTag.type.create(c.arena, "f32"),731 .float => return ZigTag.type.create(c.arena, "f32"),
732 .double => return ZigTag.type.create(c.arena, "f64"),732 .double => return ZigTag.type.create(c.arena, "f64"),
733 .long_double => return ZigTag.type.create(c.arena, "c_longdouble"),733 .long_double => return ZigTag.type.create(c.arena, "c_longdouble"),
734 .float80 => return ZigTag.type.create(c.arena, "f80"),
735 .float128 => return ZigTag.type.create(c.arena, "f128"),734 .float128 => return ZigTag.type.create(c.arena, "f128"),
736 .@"enum" => {735 .@"enum" => {
737 const enum_decl = ty.data.@"enum";736 const enum_decl = ty.data.@"enum";
...@@ -1799,7 +1798,7 @@ pub fn main() !void {...@@ -1799,7 +1798,7 @@ pub fn main() !void {
17991798
1800 const args = try std.process.argsAlloc(arena);1799 const args = try std.process.argsAlloc(arena);
18011800
1802 var aro_comp = aro.Compilation.init(gpa);1801 var aro_comp = aro.Compilation.init(gpa, std.fs.cwd());
1803 defer aro_comp.deinit();1802 defer aro_comp.deinit();
18041803
1805 var tree = translate(gpa, &aro_comp, args) catch |err| switch (err) {1804 var tree = translate(gpa, &aro_comp, args) catch |err| switch (err) {
lib/compiler/resinator/main.zig+1-1
...@@ -126,7 +126,7 @@ pub fn main() !void {...@@ -126,7 +126,7 @@ pub fn main() !void {
126 defer aro_arena_state.deinit();126 defer aro_arena_state.deinit();
127 const aro_arena = aro_arena_state.allocator();127 const aro_arena = aro_arena_state.allocator();
128128
129 var comp = aro.Compilation.init(aro_arena);129 var comp = aro.Compilation.init(aro_arena, std.fs.cwd());
130 defer comp.deinit();130 defer comp.deinit();
131131
132 var argv = std.ArrayList([]const u8).init(comp.gpa);132 var argv = std.ArrayList([]const u8).init(comp.gpa);
lib/compiler/resinator/preprocess.zig+1-1
...@@ -59,7 +59,7 @@ pub fn preprocess(...@@ -59,7 +59,7 @@ pub fn preprocess(
5959
60 if (hasAnyErrors(comp)) return error.PreprocessError;60 if (hasAnyErrors(comp)) return error.PreprocessError;
6161
62 try pp.prettyPrintTokens(writer);62 try pp.prettyPrintTokens(writer, .result_only);
6363
64 if (maybe_dependencies_list) |dependencies_list| {64 if (maybe_dependencies_list) |dependencies_list| {
65 for (comp.sources.values()) |comp_source| {65 for (comp.sources.values()) |comp_source| {
src/mingw.zig+2-2
...@@ -230,7 +230,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {...@@ -230,7 +230,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
230 };230 };
231231
232 const aro = @import("aro");232 const aro = @import("aro");
233 var aro_comp = aro.Compilation.init(comp.gpa);233 var aro_comp = aro.Compilation.init(comp.gpa, std.fs.cwd());
234 defer aro_comp.deinit();234 defer aro_comp.deinit();
235235
236 const include_dir = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "mingw", "def-include" });236 const include_dir = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "mingw", "def-include" });
...@@ -268,7 +268,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {...@@ -268,7 +268,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
268 // new scope to ensure definition file is written before passing the path to WriteImportLibrary268 // new scope to ensure definition file is written before passing the path to WriteImportLibrary
269 const def_final_file = try o_dir.createFile(final_def_basename, .{ .truncate = true });269 const def_final_file = try o_dir.createFile(final_def_basename, .{ .truncate = true });
270 defer def_final_file.close();270 defer def_final_file.close();
271 try pp.prettyPrintTokens(def_final_file.writer());271 try pp.prettyPrintTokens(def_final_file.writer(), .result_only);
272 }272 }
273273
274 const lib_final_path = try comp.global_cache_directory.join(comp.gpa, &[_][]const u8{274 const lib_final_path = try comp.global_cache_directory.join(comp.gpa, &[_][]const u8{
src/translate_c.zig+1-1
...@@ -5258,7 +5258,7 @@ fn getMacroText(unit: *const clang.ASTUnit, c: *const Context, macro: *const cla...@@ -5258,7 +5258,7 @@ fn getMacroText(unit: *const clang.ASTUnit, c: *const Context, macro: *const cla
5258 const end_c = c.source_manager.getCharacterData(end_loc);5258 const end_c = c.source_manager.getCharacterData(end_loc);
5259 const slice_len = @intFromPtr(end_c) - @intFromPtr(begin_c);5259 const slice_len = @intFromPtr(end_c) - @intFromPtr(begin_c);
52605260
5261 var comp = aro.Compilation.init(c.gpa);5261 var comp = aro.Compilation.init(c.gpa, std.fs.cwd());
5262 defer comp.deinit();5262 defer comp.deinit();
5263 const result = comp.addSourceFromBuffer("", begin_c[0..slice_len]) catch return error.OutOfMemory;5263 const result = comp.addSourceFromBuffer("", begin_c[0..slice_len]) catch return error.OutOfMemory;
52645264