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;
2323pub const version = backend.version;
2424
2525test {
26 _ = @import("aro/annex_g.zig");
2627 _ = @import("aro/Builtins.zig");
2728 _ = @import("aro/char_info.zig");
2829 _ = @import("aro/Compilation.zig");
lib/compiler/aro/aro/Attribute.zig+97-47
......@@ -38,12 +38,64 @@ pub const Kind = enum {
3838 }
3939};
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
4192pub const ArgumentType = enum {
4293 string,
4394 identifier,
4495 int,
4596 alignment,
4697 float,
98 complex_float,
4799 expression,
48100 nullptr_t,
49101
......@@ -54,6 +106,7 @@ pub const ArgumentType = enum {
54106 .int, .alignment => "an integer constant",
55107 .nullptr_t => "nullptr",
56108 .float => "a floating point number",
109 .complex_float => "a complex floating point number",
57110 .expression => "an expression",
58111 };
59112 }
......@@ -65,7 +118,7 @@ pub fn requiredArgCount(attr: Tag) u32 {
65118 inline else => |tag| {
66119 comptime var needed = 0;
67120 comptime {
68 const fields = std.meta.fields(@field(attributes, @tagName(tag)));
121 const fields = @typeInfo(@field(attributes, @tagName(tag))).@"struct".fields;
69122 for (fields) |arg_field| {
70123 if (!mem.eql(u8, arg_field.name, "__name_tok") and @typeInfo(arg_field.type) != .optional) needed += 1;
71124 }
......@@ -81,7 +134,7 @@ pub fn maxArgCount(attr: Tag) u32 {
81134 inline else => |tag| {
82135 comptime var max = 0;
83136 comptime {
84 const fields = std.meta.fields(@field(attributes, @tagName(tag)));
137 const fields = @typeInfo(@field(attributes, @tagName(tag))).@"struct".fields;
85138 for (fields) |arg_field| {
86139 if (!mem.eql(u8, arg_field.name, "__name_tok")) max += 1;
87140 }
......@@ -106,7 +159,7 @@ pub const Formatting = struct {
106159 switch (attr) {
107160 .calling_convention => unreachable,
108161 inline else => |tag| {
109 const fields = std.meta.fields(@field(attributes, @tagName(tag)));
162 const fields = @typeInfo(@field(attributes, @tagName(tag))).@"struct".fields;
110163
111164 if (fields.len == 0) unreachable;
112165 const Unwrapped = UnwrapOptional(fields[0].type);
......@@ -123,14 +176,13 @@ pub const Formatting = struct {
123176 switch (attr) {
124177 .calling_convention => unreachable,
125178 inline else => |tag| {
126 const fields = std.meta.fields(@field(attributes, @tagName(tag)));
179 const fields = @typeInfo(@field(attributes, @tagName(tag))).@"struct".fields;
127180
128181 if (fields.len == 0) unreachable;
129182 const Unwrapped = UnwrapOptional(fields[0].type);
130183 if (@typeInfo(Unwrapped) != .@"enum") unreachable;
131184
132185 const enum_fields = @typeInfo(Unwrapped).@"enum".fields;
133 @setEvalBranchQuota(3000);
134186 const quote = comptime quoteChar(@enumFromInt(@intFromEnum(tag)));
135187 comptime var values: []const u8 = quote ++ enum_fields[0].name ++ quote;
136188 inline for (enum_fields[1..]) |enum_field| {
......@@ -148,7 +200,7 @@ pub fn wantsIdentEnum(attr: Tag) bool {
148200 switch (attr) {
149201 .calling_convention => return false,
150202 inline else => |tag| {
151 const fields = std.meta.fields(@field(attributes, @tagName(tag)));
203 const fields = @typeInfo(@field(attributes, @tagName(tag))).@"struct".fields;
152204
153205 if (fields.len == 0) return false;
154206 const Unwrapped = UnwrapOptional(fields[0].type);
......@@ -162,7 +214,7 @@ pub fn wantsIdentEnum(attr: Tag) bool {
162214pub fn diagnoseIdent(attr: Tag, arguments: *Arguments, ident: []const u8) ?Diagnostics.Message {
163215 switch (attr) {
164216 inline else => |tag| {
165 const fields = std.meta.fields(@field(attributes, @tagName(tag)));
217 const fields = @typeInfo(@field(attributes, @tagName(tag))).@"struct".fields;
166218 if (fields.len == 0) unreachable;
167219 const Unwrapped = UnwrapOptional(fields[0].type);
168220 if (@typeInfo(Unwrapped) != .@"enum") unreachable;
......@@ -181,7 +233,7 @@ pub fn diagnoseIdent(attr: Tag, arguments: *Arguments, ident: []const u8) ?Diagn
181233pub fn wantsAlignment(attr: Tag, idx: usize) bool {
182234 switch (attr) {
183235 inline else => |tag| {
184 const fields = std.meta.fields(@field(attributes, @tagName(tag)));
236 const fields = @typeInfo(@field(attributes, @tagName(tag))).@"struct".fields;
185237 if (fields.len == 0) return false;
186238
187239 return switch (idx) {
......@@ -195,7 +247,7 @@ pub fn wantsAlignment(attr: Tag, idx: usize) bool {
195247pub fn diagnoseAlignment(attr: Tag, arguments: *Arguments, arg_idx: u32, res: Parser.Result, p: *Parser) !?Diagnostics.Message {
196248 switch (attr) {
197249 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;
199251 if (arg_fields.len == 0) unreachable;
200252
201253 switch (arg_idx) {
......@@ -249,8 +301,7 @@ fn diagnoseField(
249301 },
250302 .bytes => |bytes| {
251303 if (Wanted == Value) {
252 std.debug.assert(node.tag == .string_literal_expr);
253 if (!node.ty.elemType().is(.char) and !node.ty.elemType().is(.uchar)) {
304 if (node.tag != .string_literal_expr or (!node.ty.elemType().is(.char) and !node.ty.elemType().is(.uchar))) {
254305 return .{
255306 .tag = .attribute_requires_string,
256307 .extra = .{ .str = decl.name },
......@@ -264,7 +315,6 @@ fn diagnoseField(
264315 @field(@field(arguments, decl.name), field.name) = enum_val;
265316 return null;
266317 } else {
267 @setEvalBranchQuota(3000);
268318 return .{
269319 .tag = .unknown_attr_enum,
270320 .extra = .{ .attr_enum = .{ .tag = std.meta.stringToEnum(Tag, decl.name).? } },
......@@ -278,8 +328,19 @@ fn diagnoseField(
278328 .int => .int,
279329 .bytes => .string,
280330 .float => .float,
331 .complex => .complex_float,
281332 .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,
283344 });
284345}
285346
......@@ -309,7 +370,7 @@ pub fn diagnose(attr: Tag, arguments: *Arguments, arg_idx: u32, res: Parser.Resu
309370 .tag = .attribute_too_many_args,
310371 .extra = .{ .attr_arg_count = .{ .attribute = attr, .expected = max_arg_count } },
311372 };
312 const arg_fields = std.meta.fields(@field(attributes, decl.name));
373 const arg_fields = @typeInfo(@field(attributes, decl.name)).@"struct".fields;
313374 switch (arg_idx) {
314375 inline 0...arg_fields.len - 1 => |arg_i| {
315376 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: {
645706 var union_fields: [decls.len]ZigType.UnionField = undefined;
646707 for (decls, &union_fields) |decl, *field| {
647708 field.* = .{
648 .name = decl.name ++ "",
709 .name = decl.name,
649710 .type = @field(attributes, decl.name),
650711 .alignment = 0,
651712 };
......@@ -730,7 +791,6 @@ pub fn applyVariableAttributes(p: *Parser, ty: Type, attr_buf_start: usize, tag:
730791 const toks = p.attr_buf.items(.tok)[attr_buf_start..];
731792 p.attr_application_buf.items.len = 0;
732793 var base_ty = ty;
733 if (base_ty.specifier == .attributed) base_ty = base_ty.data.attributed.base;
734794 var common = false;
735795 var nocommon = false;
736796 for (attrs, toks) |attr, tok| switch (attr.tag) {
......@@ -772,15 +832,10 @@ pub fn applyVariableAttributes(p: *Parser, ty: Type, attr_buf_start: usize, tag:
772832 .copy,
773833 .tls_model,
774834 .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 } }),
776836 else => try ignoredAttrErr(p, tok, attr.tag, "variables"),
777837 };
778 const existing = ty.getAttributes();
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 } };
838 return base_ty.withAttributes(p.arena, p.attr_application_buf.items);
784839}
785840
786841pub 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)
789844 p.attr_application_buf.items.len = 0;
790845 for (attrs, toks) |attr, tok| switch (attr.tag) {
791846 // 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,
793848 => try p.attr_application_buf.append(p.gpa, attr),
794849 // zig fmt: on
795850 .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
805860 const toks = p.attr_buf.items(.tok)[attr_buf_start..];
806861 p.attr_application_buf.items.len = 0;
807862 var base_ty = ty;
808 if (base_ty.specifier == .attributed) base_ty = base_ty.data.attributed.base;
809863 for (attrs, toks) |attr, tok| switch (attr.tag) {
810864 // zig fmt: off
811865 .@"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
823877 .copy,
824878 .scalar_storage_order,
825879 .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 } }),
827881 else => try ignoredAttrErr(p, tok, attr.tag, "types"),
828882 };
829
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;
883 return base_ty.withAttributes(p.arena, p.attr_application_buf.items);
842884}
843885
844886pub 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
846888 const toks = p.attr_buf.items(.tok)[attr_buf_start..];
847889 p.attr_application_buf.items.len = 0;
848890 var base_ty = ty;
849 if (base_ty.specifier == .attributed) base_ty = base_ty.data.attributed.base;
850891 var hot = false;
851892 var cold = false;
852893 var @"noinline" = false;
......@@ -896,6 +937,13 @@ pub fn applyFunctionAttributes(p: *Parser, ty: Type, attr_buf_start: usize) !Typ
896937 else => try p.errStr(.callconv_not_supported, tok, p.tok_ids[tok].lexeme().?),
897938 },
898939 },
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 },
899947 .access,
900948 .alloc_align,
901949 .alloc_size,
......@@ -908,7 +956,6 @@ pub fn applyFunctionAttributes(p: *Parser, ty: Type, attr_buf_start: usize) !Typ
908956 .ifunc,
909957 .interrupt,
910958 .interrupt_handler,
911 .malloc,
912959 .no_address_safety_analysis,
913960 .no_icf,
914961 .no_instrument_function,
......@@ -937,7 +984,7 @@ pub fn applyFunctionAttributes(p: *Parser, ty: Type, attr_buf_start: usize) !Typ
937984 .visibility,
938985 .weakref,
939986 .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 } }),
941988 else => try ignoredAttrErr(p, tok, attr.tag, "functions"),
942989 };
943990 return ty.withAttributes(p.arena, p.attr_application_buf.items);
......@@ -1043,11 +1090,14 @@ fn applyTransparentUnion(attr: Attribute, p: *Parser, tok: TokenIndex, ty: Type)
10431090}
10441091
10451092fn applyVectorSize(attr: Attribute, p: *Parser, tok: TokenIndex, ty: *Type) !void {
1046 if (!(ty.isInt() or ty.isFloat()) or !ty.isReal()) {
1047 const orig_ty = try p.typeStr(ty.*);
1048 ty.* = Type.invalid;
1049 return p.errStr(.invalid_vec_elem_ty, tok, orig_ty);
1093 const base = ty.base();
1094 const is_enum = ty.is(.@"enum");
1095 if (!(ty.isInt() or ty.isFloat()) or !ty.isReal() or (is_enum and p.comp.langopts.emulate == .gcc)) {
1096 try p.errStr(.invalid_vec_elem_ty, tok, try p.typeStr(ty.*));
1097 return error.ParsingFailed;
10501098 }
1099 if (is_enum) return;
1100
10511101 const vec_bytes = attr.args.vector_size.bytes;
10521102 const ty_size = ty.sizeof(p.comp).?;
10531103 if (vec_bytes % ty_size != 0) {
......@@ -1057,7 +1107,7 @@ fn applyVectorSize(attr: Attribute, p: *Parser, tok: TokenIndex, ty: *Type) !voi
10571107
10581108 const arr_ty = try p.arena.create(Type.Array);
10591109 arr_ty.* = .{ .elem = ty.*, .len = vec_size };
1060 ty.* = Type{
1110 base.* = .{
10611111 .specifier = .vector,
10621112 .data = .{ .array = arr_ty },
10631113 };
lib/compiler/aro/aro/Attribute/names.zig+2-1
......@@ -69,6 +69,7 @@ pub const longest_name = 30;
6969/// If found, returns the index of the node within the `dafsa` array.
7070/// Otherwise, returns `null`.
7171pub fn findInList(first_child_index: u16, char: u8) ?u16 {
72 @setEvalBranchQuota(206);
7273 var index = first_child_index;
7374 while (true) {
7475 if (dafsa[index].char == char) return index;
......@@ -787,7 +788,7 @@ const dafsa = [_]Node{
787788 .{ .char = 'i', .end_of_word = false, .end_of_list = true, .number = 1, .child_index = 215 },
788789};
789790pub const data = blk: {
790 @setEvalBranchQuota(103);
791 @setEvalBranchQuota(721);
791792 break :blk [_]@This(){
792793 // access
793794 .{ .tag = @enumFromInt(0), .properties = .{ .tag = .access, .gnu = true } },
lib/compiler/aro/aro/Builtins.zig+2-2
......@@ -350,7 +350,7 @@ test Iterator {
350350}
351351
352352test "All builtins" {
353 var comp = Compilation.init(std.testing.allocator);
353 var comp = Compilation.init(std.testing.allocator, std.fs.cwd());
354354 defer comp.deinit();
355355 _ = try comp.generateBuiltinMacros(.include_system_defines);
356356 var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
......@@ -373,7 +373,7 @@ test "All builtins" {
373373test "Allocation failures" {
374374 const Test = struct {
375375 fn testOne(allocator: std.mem.Allocator) !void {
376 var comp = Compilation.init(allocator);
376 var comp = Compilation.init(allocator, std.fs.cwd());
377377 defer comp.deinit();
378378 _ = try comp.generateBuiltinMacros(.include_system_defines);
379379 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;
7171/// If found, returns the index of the node within the `dafsa` array.
7272/// Otherwise, returns `null`.
7373pub fn findInList(first_child_index: u16, char: u8) ?u16 {
74 @setEvalBranchQuota(7972);
7475 var index = first_child_index;
7576 while (true) {
7677 if (dafsa[index].char == char) return index;
......@@ -5165,7 +5166,7 @@ const dafsa = [_]Node{
51655166 .{ .char = 'e', .end_of_word = false, .end_of_list = true, .number = 1, .child_index = 4913 },
51665167};
51675168pub const data = blk: {
5168 @setEvalBranchQuota(30_000);
5169 @setEvalBranchQuota(27902);
51695170 break :blk [_]@This(){
51705171 // _Block_object_assign
51715172 .{ .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 {
127127} = .{},
128128string_interner: StrInt = .{},
129129interner: 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.
130132ms_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 {
133136 return .{
134137 .gpa = gpa,
135138 .diagnostics = Diagnostics.init(gpa),
139 .cwd = cwd,
136140 };
137141}
138142
139143/// Initialize Compilation with default environment,
140144/// pragma handlers and emulation mode set to target.
141pub fn initDefault(gpa: Allocator) !Compilation {
145pub fn initDefault(gpa: Allocator, cwd: std.fs.Dir) !Compilation {
142146 var comp: Compilation = .{
143147 .gpa = gpa,
144148 .environment = try Environment.loadAll(gpa),
145149 .diagnostics = Diagnostics.init(gpa),
150 .cwd = cwd,
146151 };
147152 errdefer comp.deinit();
148153 try comp.addDefaultPragmaHandlers();
......@@ -534,7 +539,7 @@ pub fn generateBuiltinMacros(comp: *Compilation, system_defines_mode: SystemDefi
534539 if (system_defines_mode == .include_system_defines) {
535540 try buf.appendSlice(
536541 \\#define __VERSION__ "Aro
537 ++ @import("../backend.zig").version_str ++ "\"\n" ++
542 ++ " " ++ @import("../backend.zig").version_str ++ "\"\n" ++
538543 \\#define __Aro__
539544 \\
540545 );
......@@ -550,6 +555,9 @@ pub fn generateBuiltinMacros(comp: *Compilation, system_defines_mode: SystemDefi
550555 \\#define __STDC_NO_VLA__ 1
551556 \\#define __STDC_UTF_16__ 1
552557 \\#define __STDC_UTF_32__ 1
558 \\#define __STDC_EMBED_NOT_FOUND__ 0
559 \\#define __STDC_EMBED_FOUND__ 1
560 \\#define __STDC_EMBED_EMPTY__ 2
553561 \\
554562 );
555563 if (comp.langopts.standard.StdCVersionMacro()) |stdc_version| {
......@@ -719,8 +727,13 @@ fn generateBuiltinTypes(comp: *Compilation) !void {
719727 try comp.generateNsConstantStringType();
720728}
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
722735/// 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 {
724737 if (bits == 64 and (comp.target.isDarwin() or comp.target.isWasm())) {
725738 // WebAssembly and Darwin use `long long` for `int_least64_t` and `int_fast64_t`.
726739 return .{ .specifier = if (signedness == .signed) .long_long else .ulong_long };
......@@ -903,7 +916,7 @@ fn generateNsConstantStringType(comp: *Compilation) !void {
903916 comp.types.ns_constant_string.fields[2] = .{ .name = try StrInt.intern(comp, "str"), .ty = const_char_ptr };
904917 comp.types.ns_constant_string.fields[3] = .{ .name = try StrInt.intern(comp, "length"), .ty = .{ .specifier = .long } };
905918 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;
907920}
908921
909922fn generateVaListType(comp: *Compilation) !Type {
......@@ -911,12 +924,12 @@ fn generateVaListType(comp: *Compilation) !Type {
911924 const kind: Kind = switch (comp.target.cpu.arch) {
912925 .aarch64 => switch (comp.target.os.tag) {
913926 .windows => @as(Kind, .char_ptr),
914 .ios, .macos, .tvos, .watchos, .visionos => .char_ptr,
927 .ios, .macos, .tvos, .watchos => .char_ptr,
915928 else => .aarch64_va_list,
916929 },
917930 .sparc, .wasm32, .wasm64, .bpfel, .bpfeb, .riscv32, .riscv64, .avr, .spirv32, .spirv64 => .void_ptr,
918931 .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),
920933 else => return Type{ .specifier = .void }, // unknown
921934 },
922935 .x86, .msp430 => .char_ptr,
......@@ -951,7 +964,7 @@ fn generateVaListType(comp: *Compilation) !Type {
951964 record_ty.fields[3] = .{ .name = try StrInt.intern(comp, "__gr_offs"), .ty = .{ .specifier = .int } };
952965 record_ty.fields[4] = .{ .name = try StrInt.intern(comp, "__vr_offs"), .ty = .{ .specifier = .int } };
953966 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;
955968 },
956969 .x86_64_va_list => {
957970 const record_ty = try arena.create(Type.Record);
......@@ -969,7 +982,7 @@ fn generateVaListType(comp: *Compilation) !Type {
969982 record_ty.fields[2] = .{ .name = try StrInt.intern(comp, "overflow_arg_area"), .ty = void_ptr };
970983 record_ty.fields[3] = .{ .name = try StrInt.intern(comp, "reg_save_area"), .ty = void_ptr };
971984 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;
973986 },
974987 }
975988 if (kind == .char_ptr or kind == .void_ptr) {
......@@ -988,13 +1001,28 @@ fn generateVaListType(comp: *Compilation) !Type {
9881001fn generateIntMax(comp: *const Compilation, w: anytype, name: []const u8, ty: Type) !void {
9891002 const bit_count: u8 = @intCast(ty.sizeof(comp).? * 8);
9901003 const unsigned = ty.isUnsignedInt(comp);
991 const max = if (bit_count == 128)
992 @as(u128, if (unsigned) std.math.maxInt(u128) else std.math.maxInt(u128))
993 else
994 ty.maxInt(comp);
1004 const max: u128 = switch (bit_count) {
1005 8 => if (unsigned) std.math.maxInt(u8) else std.math.maxInt(i8),
1006 16 => if (unsigned) std.math.maxInt(u16) else std.math.maxInt(i16),
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 };
9951012 try w.print("#define __{s}_MAX__ {d}{s}\n", .{ name, max, ty.intValueSuffix(comp) });
9961013}
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
9981026fn generateExactWidthIntMax(comp: *const Compilation, w: anytype, specifier: Type.Specifier) !void {
9991027 var ty = Type{ .specifier = specifier };
10001028 const bit_count: u8 = @intCast(ty.sizeof(comp).? * 8);
......@@ -1039,6 +1067,12 @@ pub fn nextLargestIntSameSign(comp: *const Compilation, ty: Type) ?Type {
10391067 return null;
10401068}
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
10421076/// If `enum E { ... }` syntax has a fixed underlying integer type regardless of the presence of
10431077/// __attribute__((packed)) or the range of values of the corresponding enumerator constants,
10441078/// specify it here.
......@@ -1060,7 +1094,7 @@ pub fn getCharSignedness(comp: *const Compilation) std.builtin.Signedness {
10601094pub fn addBuiltinIncludeDir(comp: *Compilation, aro_dir: []const u8) !void {
10611095 var search_path = aro_dir;
10621096 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;
10641098 defer base_dir.close();
10651099
10661100 base_dir.access("include/stddef.h", .{}) catch continue;
......@@ -1266,7 +1300,7 @@ fn addSourceFromPathExtra(comp: *Compilation, path: []const u8, kind: Source.Kin
12661300 return error.FileNotFound;
12671301 }
12681302
1269 const file = try std.fs.cwd().openFile(path, .{});
1303 const file = try comp.cwd.openFile(path, .{});
12701304 defer file.close();
12711305
12721306 const contents = file.readToEndAlloc(comp.gpa, std.math.maxInt(u32)) catch |err| switch (err) {
......@@ -1349,10 +1383,9 @@ pub fn hasInclude(
13491383 return false;
13501384 }
13511385
1352 const cwd = std.fs.cwd();
13531386 if (std.fs.path.isAbsolute(filename)) {
13541387 if (which == .next) return false;
1355 return !std.meta.isError(cwd.access(filename, .{}));
1388 return !std.meta.isError(comp.cwd.access(filename, .{}));
13561389 }
13571390
13581391 const cwd_source_id = switch (include_type) {
......@@ -1372,7 +1405,7 @@ pub fn hasInclude(
13721405
13731406 while (try it.nextWithFile(filename, sf_allocator)) |found| {
13741407 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;
13761409 }
13771410 return false;
13781411}
......@@ -1392,7 +1425,7 @@ fn getFileContents(comp: *Compilation, path: []const u8, limit: ?u32) ![]const u
13921425 return error.FileNotFound;
13931426 }
13941427
1395 const file = try std.fs.cwd().openFile(path, .{});
1428 const file = try comp.cwd.openFile(path, .{});
13961429 defer file.close();
13971430
13981431 var buf = std.ArrayList(u8).init(comp.gpa);
......@@ -1571,6 +1604,17 @@ pub fn hasBuiltinFunction(comp: *const Compilation, builtin: Builtin) bool {
15711604 }
15721605}
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
15741618pub const CharUnitSize = enum(u32) {
15751619 @"1" = 1,
15761620 @"2" = 2,
......@@ -1590,7 +1634,7 @@ pub const addDiagnostic = Diagnostics.add;
15901634test "addSourceFromReader" {
15911635 const Test = struct {
15921636 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());
15941638 defer comp.deinit();
15951639
15961640 var buf_reader = std.io.fixedBufferStream(str);
......@@ -1602,7 +1646,7 @@ test "addSourceFromReader" {
16021646 }
16031647
16041648 fn withAllocationFailures(allocator: std.mem.Allocator) !void {
1605 var comp = Compilation.init(allocator);
1649 var comp = Compilation.init(allocator, std.fs.cwd());
16061650 defer comp.deinit();
16071651
16081652 _ = try comp.addSourceFromBuffer("path", "spliced\\\nbuffer\n");
......@@ -1644,7 +1688,7 @@ test "addSourceFromReader - exhaustive check for carriage return elimination" {
16441688 const alen = alphabet.len;
16451689 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());
16481692 defer comp.deinit();
16491693
16501694 var source_count: u32 = 0;
......@@ -1672,7 +1716,7 @@ test "ignore BOM at beginning of file" {
16721716
16731717 const Test = struct {
16741718 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());
16761720 defer comp.deinit();
16771721
16781722 var buf_reader = std.io.fixedBufferStream(buf);
lib/compiler/aro/aro/Diagnostics.zig+13-2
......@@ -47,6 +47,10 @@ pub const Message = struct {
4747 tag: Attribute.Tag,
4848 specifier: enum { @"struct", @"union", @"enum" },
4949 },
50 attribute_todo: struct {
51 tag: Attribute.Tag,
52 kind: enum { variables, fields, types, functions },
53 },
5054 builtin_with_header: struct {
5155 builtin: Builtin.Tag,
5256 header: Header,
......@@ -210,6 +214,9 @@ pub const Options = struct {
210214 normalized: Kind = .default,
211215 @"shift-count-negative": Kind = .default,
212216 @"shift-count-overflow": Kind = .default,
217 @"constant-conversion": Kind = .default,
218 @"sign-conversion": Kind = .default,
219 nonnull: Kind = .default,
213220};
214221
215222const Diagnostics = @This();
......@@ -222,14 +229,14 @@ errors: u32 = 0,
222229macro_backtrace_limit: u32 = 6,
223230
224231pub fn warningExists(name: []const u8) bool {
225 inline for (std.meta.fields(Options)) |f| {
232 inline for (@typeInfo(Options).@"struct".fields) |f| {
226233 if (mem.eql(u8, f.name, name)) return true;
227234 }
228235 return false;
229236}
230237
231238pub 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| {
233240 if (mem.eql(u8, f.name, name)) {
234241 @field(d.options, f.name) = to;
235242 return;
......@@ -422,6 +429,10 @@ pub fn renderMessage(comp: *Compilation, m: anytype, msg: Message) void {
422429 @tagName(msg.extra.ignored_record_attr.tag),
423430 @tagName(msg.extra.ignored_record_attr.specifier),
424431 }),
432 .attribute_todo => printRt(m, prop.msg, .{ "{s}", "{s}" }, .{
433 @tagName(msg.extra.attribute_todo.tag),
434 @tagName(msg.extra.attribute_todo.kind),
435 }),
425436 .builtin_with_header => printRt(m, prop.msg, .{ "{s}", "{s}" }, .{
426437 @tagName(msg.extra.builtin_with_header.header),
427438 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 {
107107 multiple_default,
108108 previous_case,
109109 expected_arguments,
110 callee_with_static_array,
111 array_argument_too_small,
112 non_null_argument,
110113 expected_arguments_old,
111114 expected_at_least_arguments,
112115 invalid_static_star,
......@@ -214,6 +217,7 @@ pub const Tag = enum {
214217 pre_c23_compat,
215218 unbound_vla,
216219 array_too_large,
220 record_too_large,
217221 incompatible_ptr_init,
218222 incompatible_ptr_init_sign,
219223 incompatible_ptr_assign,
......@@ -349,6 +353,8 @@ pub const Tag = enum {
349353 non_standard_escape_char,
350354 invalid_pp_stringify_escape,
351355 vla,
356 int_value_changed,
357 sign_conversion,
352358 float_overflow_conversion,
353359 float_out_of_range,
354360 float_zero_conversion,
......@@ -425,7 +431,8 @@ pub const Tag = enum {
425431 bit_int,
426432 unsigned_bit_int_too_small,
427433 signed_bit_int_too_small,
428 bit_int_too_big,
434 unsigned_bit_int_too_big,
435 signed_bit_int_too_big,
429436 keyword_macro,
430437 ptr_arithmetic_incomplete,
431438 callconv_not_supported,
......@@ -509,6 +516,9 @@ pub const Tag = enum {
509516 complex_conj,
510517 overflow_builtin_requires_int,
511518 overflow_result_requires_ptr,
519 attribute_todo,
520 invalid_type_underlying_enum,
521 auto_type_self_initialized,
512522
513523 pub fn property(tag: Tag) Properties {
514524 return named_data[@intFromEnum(tag)];
......@@ -613,6 +623,9 @@ pub const Tag = enum {
613623 .{ .msg = "multiple default cases in the same switch", .kind = .@"error" },
614624 .{ .msg = "previous case defined here", .kind = .note },
615625 .{ .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") },
616629 .{ .msg = expected_arguments, .extra = .arguments, .kind = .warning },
617630 .{ .msg = "expected at least {d} argument(s) got {d}", .extra = .arguments, .kind = .warning },
618631 .{ .msg = "'static' may not be used with an unspecified variable length array size", .kind = .@"error" },
......@@ -720,6 +733,7 @@ pub const Tag = enum {
720733 .{ .msg = "{s} is incompatible with C standards before C23", .extra = .str, .kind = .off, .suppress_unless_version = .c23, .opt = W("pre-c23-compat") },
721734 .{ .msg = "variable length array must be bound in function definition", .kind = .@"error" },
722735 .{ .msg = "array is too large", .kind = .@"error" },
736 .{ .msg = "type '{s}' is too large", .kind = .@"error", .extra = .str },
723737 .{ .msg = "incompatible pointer types initializing {s}", .extra = .str, .opt = W("incompatible-pointer-types"), .kind = .warning },
724738 .{ .msg = "incompatible pointer types initializing {s}" ++ pointer_sign_message, .extra = .str, .opt = W("pointer-sign"), .kind = .warning },
725739 .{ .msg = "incompatible pointer types assigning to {s}", .extra = .str, .opt = W("incompatible-pointer-types"), .kind = .warning },
......@@ -855,6 +869,8 @@ pub const Tag = enum {
855869 .{ .msg = "use of non-standard escape character '\\{s}'", .kind = .off, .opt = W("pedantic"), .extra = .invalid_escape },
856870 .{ .msg = "invalid string literal, ignoring final '\\'", .kind = .warning },
857871 .{ .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") },
858874 .{ .msg = "implicit conversion of non-finite value from {s} is undefined", .extra = .str, .kind = .off, .opt = W("float-overflow-conversion") },
859875 .{ .msg = "implicit conversion of out of range value from {s} is undefined", .extra = .str, .kind = .warning, .opt = W("literal-conversion") },
860876 .{ .msg = "implicit conversion from {s}", .extra = .str, .kind = .off, .opt = W("float-zero-conversion") },
......@@ -929,9 +945,10 @@ pub const Tag = enum {
929945 .{ .msg = "this declarator", .kind = .note },
930946 .{ .msg = "{s} is not supported on this target", .extra = .str, .kind = .@"error" },
931947 .{ .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" },
933 .{ .msg = "{s} 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" },
948 .{ .msg = "{s}unsigned _BitInt must have a bit size of at least 1", .extra = .str, .kind = .@"error" },
949 .{ .msg = "{s}signed _BitInt must have a bit size of at least 2", .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" },
935952 .{ .msg = "keyword is hidden by macro definition", .kind = .off, .pedantic = true, .opt = W("keyword-macro") },
936953 .{ .msg = "arithmetic on a pointer to an incomplete type '{s}'", .extra = .str, .kind = .@"error" },
937954 .{ .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 {
10151032 .{ .msg = "ISO C does not support '~' for complex conjugation of '{s}'", .opt = W("pedantic"), .extra = .str, .kind = .off },
10161033 .{ .msg = "operand argument to overflow builtin must be an integer ('{s}' invalid)", .extra = .str, .kind = .@"error" },
10171034 .{ .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" },
10181038 };
10191039};
10201040};
lib/compiler/aro/aro/Driver.zig+30-2
......@@ -47,6 +47,20 @@ color: ?bool = null,
4747nobuiltininc: bool = false,
4848nostdinc: bool = false,
4949nostdlibinc: 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
5165/// Full path to the aro executable
5266aro_name: []const u8 = "",
......@@ -92,6 +106,9 @@ pub const usage =
92106 \\
93107 \\Compile options:
94108 \\ -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.
95112 \\ -D <macro>=<value> Define <macro> to <value> (defaults to 1)
96113 \\ -E Only run the preprocessor
97114 \\ -fchar8_t Enable char8_t (enabled by default in C23 and later)
......@@ -234,6 +251,12 @@ pub fn parseArgs(
234251 d.system_defines = .no_system_defines;
235252 } else if (mem.eql(u8, arg, "-c") or mem.eql(u8, arg, "--compile")) {
236253 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;
237260 } else if (mem.eql(u8, arg, "-E")) {
238261 d.only_preprocess = true;
239262 } else if (mem.eql(u8, arg, "-P") or mem.eql(u8, arg, "--no-line-commands")) {
......@@ -636,13 +659,17 @@ fn processSource(
636659 if (d.comp.langopts.ms_extensions) {
637660 d.comp.ms_cwd_source_id = source.id;
638661 }
639
662 const dump_mode = d.debug_dump_letters.getPreprocessorDumpMode();
640663 if (d.verbose_pp) pp.verbose = true;
641664 if (d.only_preprocess) {
642665 pp.preserve_whitespace = true;
643666 if (d.line_commands) {
644667 pp.linemarkers = if (d.use_line_directives) .line_directives else .numeric_directives;
645668 }
669 switch (dump_mode) {
670 .macros_and_result, .macro_names_and_result => pp.store_macro_tokens = true,
671 .result_only, .macros_only => {},
672 }
646673 }
647674
648675 try pp.preprocessSources(&.{ source, builtin, user_macros });
......@@ -663,7 +690,8 @@ fn processSource(
663690 defer if (d.output_name != null) file.close();
664691
665692 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|
667695 return d.fatal("unable to write result: {s}", .{errorDescription(er)});
668696
669697 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 {
5656}
5757
5858fn 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;
6060 // Todo: ensure path is not a directory
6161 return true;
6262}
......@@ -173,7 +173,7 @@ pub const Filesystem = union(enum) {
173173 pub fn exists(fs: Filesystem, path: []const u8) bool {
174174 switch (fs) {
175175 .real => {
176 std.os.access(path, std.os.F_OK) catch return false;
176 std.fs.cwd().access(path, .{}) catch return false;
177177 return true;
178178 },
179179 .fake => |paths| return existsFake(paths, path),
lib/compiler/aro/aro/Hideset.zig+27-22
......@@ -46,15 +46,15 @@ const Item = struct {
4646 const List = std.MultiArrayList(Item);
4747};
4848
49const Index = enum(u32) {
49pub const Index = enum(u32) {
5050 none = std.math.maxInt(u32),
5151 _,
5252};
5353
5454map: std.AutoHashMapUnmanaged(Identifier, Index) = .{},
55/// Used for computing intersection of two lists; stored here so that allocations can be retained
55/// Used for computing union/intersection of two lists; stored here so that allocations can be retained
5656/// until hideset is deinit'ed
57intersection_map: std.AutoHashMapUnmanaged(Identifier, void) = .{},
57tmp_map: std.AutoHashMapUnmanaged(Identifier, void) = .{},
5858linked_list: Item.List = .{},
5959comp: *const Compilation,
6060
......@@ -72,7 +72,7 @@ const Iterator = struct {
7272
7373pub fn deinit(self: *Hideset) void {
7474 self.map.deinit(self.comp.gpa);
75 self.intersection_map.deinit(self.comp.gpa);
75 self.tmp_map.deinit(self.comp.gpa);
7676 self.linked_list.deinit(self.comp.gpa);
7777}
7878
......@@ -83,7 +83,7 @@ pub fn clearRetainingCapacity(self: *Hideset) void {
8383
8484pub fn clearAndFree(self: *Hideset) void {
8585 self.map.clearAndFree(self.comp.gpa);
86 self.intersection_map.clearAndFree(self.comp.gpa);
86 self.tmp_map.clearAndFree(self.comp.gpa);
8787 self.linked_list.shrinkAndFree(self.comp.gpa, 0);
8888}
8989
......@@ -109,8 +109,13 @@ fn ensureUnusedCapacity(self: *Hideset, new_size: usize) !void {
109109
110110/// Creates a one-item list with contents `identifier`
111111fn 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 {
112117 const next_idx = self.linked_list.len;
113 self.linked_list.appendAssumeCapacity(.{ .identifier = identifier });
118 self.linked_list.appendAssumeCapacity(.{ .identifier = identifier, .next = next });
114119 return @enumFromInt(next_idx);
115120}
116121
......@@ -121,24 +126,24 @@ pub fn prepend(self: *Hideset, loc: Source.Location, tail: Index) !Index {
121126 return @enumFromInt(new_idx);
122127}
123128
124/// Copy a, then attach b at the end
129/// Attach elements of `b` to the front of `a` (if they're not in `a`)
125130pub 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
127140 var head: Index = b;
128141 try self.ensureUnusedCapacity(self.len(a));
129 var it = self.iterator(a);
142 it = self.iterator(a);
130143 while (it.next()) |identifier| {
131 const new_idx = self.createNodeAssumeCapacity(identifier);
132 if (head == b) {
133 head = new_idx;
144 if (!self.tmp_map.contains(identifier)) {
145 head = self.createNodeAssumeCapacityExtra(identifier, head);
134146 }
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;
142147 }
143148 return head;
144149}
......@@ -163,20 +168,20 @@ fn len(self: *const Hideset, list: Index) usize {
163168
164169pub fn intersection(self: *Hideset, a: Index, b: Index) !Index {
165170 if (a == .none or b == .none) return .none;
166 self.intersection_map.clearRetainingCapacity();
171 self.tmp_map.clearRetainingCapacity();
167172
168173 var cur: Index = .none;
169174 var head: Index = .none;
170175 var it = self.iterator(a);
171176 var a_len: usize = 0;
172177 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, {});
174179 }
175180 try self.ensureUnusedCapacity(@min(a_len, self.len(b)));
176181
177182 it = self.iterator(b);
178183 while (it.next()) |identifier| {
179 if (self.intersection_map.contains(identifier)) {
184 if (self.tmp_map.contains(identifier)) {
180185 const new_idx = self.createNodeAssumeCapacity(identifier);
181186 if (head == .none) {
182187 head = new_idx;
lib/compiler/aro/aro/Parser.zig+572-261
......@@ -28,6 +28,7 @@ const StrInt = @import("StringInterner.zig");
2828const StringId = StrInt.StringId;
2929const Builtins = @import("Builtins.zig");
3030const Builtin = Builtins.Builtin;
31const evalBuiltin = @import("Builtins/eval.zig").eval;
3132const target_util = @import("target.zig");
3233
3334const Switch = struct {
......@@ -100,7 +101,7 @@ value_map: Tree.ValueMap,
100101
101102// buffers used during compilation
102103syms: SymbolStack = .{},
103strings: std.ArrayList(u8),
104strings: std.ArrayListAligned(u8, 4),
104105labels: std.ArrayList(Label),
105106list_buf: NodeList,
106107decl_buf: NodeList,
......@@ -130,6 +131,10 @@ const_decl_folding: ConstDeclFoldingMode = .fold_const_decls,
130131/// address-of-label expression (tracked with contains_address_of_label)
131132computed_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
133138/// Various variables that are different for each function.
134139func: struct {
135140 /// null if not in function, will always be plain func, var_args_func or old_style_func
......@@ -160,7 +165,7 @@ record: struct {
160165 }
161166
162167 fn addFieldsFromAnonymous(r: @This(), p: *Parser, ty: Type) Error!void {
163 for (ty.data.record.fields) |f| {
168 for (ty.getRecord().?.fields) |f| {
164169 if (f.isAnonymousRecord()) {
165170 try r.addFieldsFromAnonymous(p, f.ty.canonicalize(.standard));
166171 } else if (f.name_tok != 0) {
......@@ -470,7 +475,7 @@ pub fn typePairStrExtra(p: *Parser, a: Type, msg: []const u8, b: Type) ![]const
470475 return try p.comp.diagnostics.arena.allocator().dupe(u8, p.strings.items[strings_top..]);
471476}
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 {
474479 const strings_top = p.strings.items.len;
475480 defer p.strings.items.len = strings_top;
476481
......@@ -572,6 +577,14 @@ fn nodeIs(p: *Parser, node: NodeIndex, tag: Tree.Tag) bool {
572577 return p.getNode(node, tag) != null;
573578}
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
575588fn getNode(p: *Parser, node: NodeIndex, tag: Tree.Tag) ?NodeIndex {
576589 var cur = node;
577590 const tags = p.nodes.items(.tag);
......@@ -680,7 +693,7 @@ pub fn parse(pp: *Preprocessor) Compilation.Error!Tree {
680693 .gpa = pp.comp.gpa,
681694 .arena = arena.allocator(),
682695 .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),
684697 .value_map = Tree.ValueMap.init(pp.comp.gpa),
685698 .data = NodeList.init(pp.comp.gpa),
686699 .labels = std.ArrayList(Label).init(pp.comp.gpa),
......@@ -725,7 +738,7 @@ pub fn parse(pp: *Preprocessor) Compilation.Error!Tree {
725738 defer p.syms.popScope();
726739
727740 // 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
730743 {
731744 if (p.comp.langopts.hasChar8_T()) {
......@@ -747,6 +760,10 @@ pub fn parse(pp: *Preprocessor) Compilation.Error!Tree {
747760 if (ty.isArray()) ty.decayArray();
748761
749762 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 }
750767 }
751768
752769 while (p.eatToken(.eof) == null) {
......@@ -862,6 +879,8 @@ fn nextExternDecl(p: *Parser) void {
862879 .keyword_int,
863880 .keyword_long,
864881 .keyword_signed,
882 .keyword_signed1,
883 .keyword_signed2,
865884 .keyword_unsigned,
866885 .keyword_float,
867886 .keyword_double,
......@@ -1018,10 +1037,8 @@ fn decl(p: *Parser) Error!bool {
10181037
10191038 // Collect old style parameter declarations.
10201039 if (init_d.d.old_style_func != null) {
1021 const attrs = init_d.d.ty.getAttributes();
1022 var base_ty = if (init_d.d.ty.specifier == .attributed) init_d.d.ty.data.attributed.base else init_d.d.ty;
1040 var base_ty = init_d.d.ty.base();
10231041 base_ty.specifier = .func;
1024 init_d.d.ty = try base_ty.withAttributes(p.arena, attrs);
10251042
10261043 const param_buf_top = p.param_buf.items.len;
10271044 defer p.param_buf.items.len = param_buf_top;
......@@ -1116,6 +1133,7 @@ fn decl(p: *Parser) Error!bool {
11161133 .ty = init_d.d.ty,
11171134 .tag = try decl_spec.validateFnDef(p),
11181135 .data = .{ .decl = .{ .name = init_d.d.name, .node = body } },
1136 .loc = @enumFromInt(init_d.d.name),
11191137 });
11201138 try p.decl_buf.append(node);
11211139
......@@ -1142,9 +1160,18 @@ fn decl(p: *Parser) Error!bool {
11421160 if (init_d.d.old_style_func) |tok_i| try p.errTok(.invalid_old_style_params, tok_i);
11431161 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 = .{
1146 .decl = .{ .name = init_d.d.name, .node = init_d.initializer.node },
1147 } });
1163 const tok = switch (decl_spec.storage_class) {
1164 .auto, .@"extern", .register, .static, .typedef => |tok| tok,
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 });
11481175 try p.decl_buf.append(node);
11491176
11501177 const interned_name = try StrInt.intern(p.comp, p.tokSlice(init_d.d.name));
......@@ -1287,6 +1314,7 @@ fn staticAssert(p: *Parser) Error!bool {
12871314 .lhs = res.node,
12881315 .rhs = str.node,
12891316 } },
1317 .loc = @enumFromInt(static_assert),
12901318 });
12911319 try p.decl_buf.append(node);
12921320 return true;
......@@ -1407,6 +1435,8 @@ fn typeof(p: *Parser) Error!?Type {
14071435 const l_paren = try p.expectToken(.l_paren);
14081436 if (try p.typeName()) |ty| {
14091437 try p.expectClosing(l_paren, .r_paren);
1438 if (ty.is(.invalid)) return null;
1439
14101440 const typeof_ty = try p.arena.create(Type);
14111441 typeof_ty.* = .{
14121442 .data = ty.data,
......@@ -1428,6 +1458,8 @@ fn typeof(p: *Parser) Error!?Type {
14281458 .specifier = .nullptr_t,
14291459 .qual = if (unqual) .{} else typeof_expr.ty.qual.inheritFromTypeof(),
14301460 };
1461 } else if (typeof_expr.ty.is(.invalid)) {
1462 return null;
14311463 }
14321464
14331465 const inner = try p.arena.create(Type.Expr);
......@@ -1774,6 +1806,8 @@ fn initDeclarator(p: *Parser, decl_spec: *DeclSpec, attr_buf_top: usize) Error!?
17741806 } else {
17751807 apply_var_attributes = true;
17761808 }
1809 const c23_auto = init_d.d.ty.is(.c23_auto);
1810 const auto_type = init_d.d.ty.is(.auto_type);
17771811
17781812 if (p.eatToken(.equal)) |eq| init: {
17791813 if (decl_spec.storage_class == .typedef or
......@@ -1801,19 +1835,21 @@ fn initDeclarator(p: *Parser, decl_spec: *DeclSpec, attr_buf_top: usize) Error!?
18011835
18021836 const interned_name = try StrInt.intern(p.comp, p.tokSlice(init_d.d.name));
18031837 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
18041843 var init_list_expr = try p.initializer(init_d.d.ty);
18051844 init_d.initializer = init_list_expr;
18061845 if (!init_list_expr.ty.isArray()) break :init;
1807 if (init_d.d.ty.specifier == .incomplete_array) {
1808 // Modifying .data is exceptionally allowed for .incomplete_array.
1809 init_d.d.ty.data.array.len = init_list_expr.ty.arrayLen() orelse break :init;
1810 init_d.d.ty.specifier = .array;
1846 if (init_d.d.ty.is(.incomplete_array)) {
1847 init_d.d.ty.setIncompleteArrayLen(init_list_expr.ty.arrayLen() orelse break :init);
18111848 }
18121849 }
18131850
18141851 const name = init_d.d.name;
1815 const c23_auto = init_d.d.ty.is(.c23_auto);
1816 if (init_d.d.ty.is(.auto_type) or c23_auto) {
1852 if (auto_type or c23_auto) {
18171853 if (init_d.initializer.node == .none) {
18181854 init_d.d.ty = Type.invalid;
18191855 if (c23_auto) {
......@@ -1872,6 +1908,8 @@ fn initDeclarator(p: *Parser, decl_spec: *DeclSpec, attr_buf_top: usize) Error!?
18721908/// | keyword_float
18731909/// | keyword_double
18741910/// | keyword_signed
1911/// | keyword_signed1
1912/// | keyword_signed2
18751913/// | keyword_unsigned
18761914/// | keyword_bool
18771915/// | keyword_c23_bool
......@@ -1911,14 +1949,13 @@ fn typeSpec(p: *Parser, ty: *Type.Builder) Error!bool {
19111949 .keyword_long => try ty.combine(p, .long, p.tok_i),
19121950 .keyword_int64, .keyword_int64_2 => try ty.combine(p, .long_long, p.tok_i),
19131951 .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),
19151953 .keyword_unsigned => try ty.combine(p, .unsigned, p.tok_i),
19161954 .keyword_fp16 => try ty.combine(p, .fp16, p.tok_i),
19171955 .keyword_float16 => try ty.combine(p, .float16, p.tok_i),
19181956 .keyword_float => try ty.combine(p, .float, p.tok_i),
19191957 .keyword_double => try ty.combine(p, .double, p.tok_i),
19201958 .keyword_complex => try ty.combine(p, .complex, p.tok_i),
1921 .keyword_float80 => try ty.combine(p, .float80, p.tok_i),
19221959 .keyword_float128_1, .keyword_float128_2 => {
19231960 if (!p.comp.hasFloat128()) {
19241961 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 {
21282165 .tag = if (is_struct) .struct_forward_decl else .union_forward_decl,
21292166 .ty = ty,
21302167 .data = .{ .decl_ref = ident },
2168 .loc = @enumFromInt(ident),
21312169 }));
21322170 return ty;
21332171 }
......@@ -2248,19 +2286,22 @@ fn recordSpec(p: *Parser) Error!Type {
22482286 // TODO: msvc considers `#pragma pack` on a per-field basis
22492287 .msvc => p.pragma_pack,
22502288 };
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 };
22522292 }
22532293
22542294 // finish by creating a node
22552295 var node: Tree.Node = .{
22562296 .tag = if (is_struct) .struct_decl_two else .union_decl_two,
22572297 .ty = ty,
2258 .data = .{ .bin = .{ .lhs = .none, .rhs = .none } },
2298 .data = .{ .two = .{ .none, .none } },
2299 .loc = @enumFromInt(maybe_ident orelse kind_tok),
22592300 };
22602301 switch (record_decls.len) {
22612302 0 => {},
2262 1 => node.data = .{ .bin = .{ .lhs = record_decls[0], .rhs = .none } },
2263 2 => node.data = .{ .bin = .{ .lhs = record_decls[0], .rhs = record_decls[1] } },
2303 1 => node.data = .{ .two = .{ record_decls[0], .none } },
2304 2 => node.data = .{ .two = .{ record_decls[0], record_decls[1] } },
22642305 else => {
22652306 node.tag = if (is_struct) .struct_decl else .union_decl;
22662307 node.data = .{ .range = try p.addList(record_decls) };
......@@ -2383,6 +2424,7 @@ fn recordDeclarator(p: *Parser) Error!bool {
23832424 .tag = .indirect_record_field_decl,
23842425 .ty = ty,
23852426 .data = undefined,
2427 .loc = @enumFromInt(first_tok),
23862428 });
23872429 try p.decl_buf.append(node);
23882430 try p.record.addFieldsFromAnonymous(p, ty);
......@@ -2402,6 +2444,7 @@ fn recordDeclarator(p: *Parser) Error!bool {
24022444 .tag = .record_field_decl,
24032445 .ty = ty,
24042446 .data = .{ .decl = .{ .name = name_tok, .node = bits_node } },
2447 .loc = @enumFromInt(if (name_tok != 0) name_tok else first_tok),
24052448 });
24062449 try p.decl_buf.append(node);
24072450 }
......@@ -2461,7 +2504,8 @@ fn enumSpec(p: *Parser) Error!Type {
24612504
24622505 const maybe_ident = try p.eatIdentifier();
24632506 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 {
24652509 if (p.record.kind != .invalid) {
24662510 // This is a bit field.
24672511 p.tok_i -= 1;
......@@ -2471,6 +2515,12 @@ fn enumSpec(p: *Parser) Error!Type {
24712515 try p.errTok(.enum_fixed, colon);
24722516 break :fixed null;
24732517 };
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
24742524 try p.errTok(.enum_fixed, colon);
24752525 break :fixed fixed;
24762526 } else null;
......@@ -2505,6 +2555,7 @@ fn enumSpec(p: *Parser) Error!Type {
25052555 .tag = .enum_forward_decl,
25062556 .ty = ty,
25072557 .data = .{ .decl_ref = ident },
2558 .loc = @enumFromInt(ident),
25082559 }));
25092560 return ty;
25102561 }
......@@ -2587,7 +2638,7 @@ fn enumSpec(p: *Parser) Error!Type {
25872638 continue;
25882639
25892640 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);
25912642 symbol.ty = dest_ty;
25922643 p.nodes.items(.ty)[@intFromEnum(field_nodes[i])] = dest_ty;
25932644 field.ty = dest_ty;
......@@ -2615,13 +2666,18 @@ fn enumSpec(p: *Parser) Error!Type {
26152666 }
26162667
26172668 // finish by creating a node
2618 var node: Tree.Node = .{ .tag = .enum_decl_two, .ty = ty, .data = .{
2619 .bin = .{ .lhs = .none, .rhs = .none },
2620 } };
2669 var node: Tree.Node = .{
2670 .tag = .enum_decl_two,
2671 .ty = ty,
2672 .data = .{
2673 .two = .{ .none, .none },
2674 },
2675 .loc = @enumFromInt(maybe_ident orelse enum_tok),
2676 };
26212677 switch (field_nodes.len) {
26222678 0 => {},
2623 1 => node.data = .{ .bin = .{ .lhs = field_nodes[0], .rhs = .none } },
2624 2 => node.data = .{ .bin = .{ .lhs = field_nodes[0], .rhs = field_nodes[1] } },
2679 1 => node.data = .{ .two = .{ field_nodes[0], .none } },
2680 2 => node.data = .{ .two = .{ field_nodes[0], field_nodes[1] } },
26252681 else => {
26262682 node.tag = .enum_decl;
26272683 node.data = .{ .range = try p.addList(field_nodes) };
......@@ -2679,8 +2735,6 @@ const Enumerator = struct {
26792735 return;
26802736 }
26812737 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);
26842738 if (e.fixed) {
26852739 try p.errStr(.enum_not_representable_fixed, tok, try p.typeStr(e.res.ty));
26862740 return;
......@@ -2689,6 +2743,8 @@ const Enumerator = struct {
26892743 try p.errTok(.enumerator_overflow, tok);
26902744 break :blk larger;
26912745 } 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));
26922748 try p.errExtra(.enum_not_representable, tok, .{ .pow_2_as_string = bit_size });
26932749 break :blk Type{ .specifier = .ulong_long };
26942750 };
......@@ -2792,14 +2848,12 @@ fn enumerator(p: *Parser, e: *Enumerator) Error!?EnumFieldAndNode {
27922848 if (err_start == p.comp.diagnostics.list.items.len) {
27932849 // only do these warnings if we didn't already warn about overflow or non-representable values
27942850 if (e.res.val.compare(.lt, Value.zero, p.comp)) {
2795 const min_int = (Type{ .specifier = .int }).minInt(p.comp);
2796 const min_val = try Value.int(min_int, p.comp);
2851 const min_val = try Value.minInt(Type.int, p.comp);
27972852 if (e.res.val.compare(.lt, min_val, p.comp)) {
27982853 try p.errStr(.enumerator_too_small, name_tok, try e.res.str(p));
27992854 }
28002855 } else {
2801 const max_int = (Type{ .specifier = .int }).maxInt(p.comp);
2802 const max_val = try Value.int(max_int, p.comp);
2856 const max_val = try Value.maxInt(Type.int, p.comp);
28032857 if (e.res.val.compare(.gt, max_val, p.comp)) {
28042858 try p.errStr(.enumerator_too_large, name_tok, try e.res.str(p));
28052859 }
......@@ -2815,6 +2869,7 @@ fn enumerator(p: *Parser, e: *Enumerator) Error!?EnumFieldAndNode {
28152869 .name = name_tok,
28162870 .node = res.node,
28172871 } },
2872 .loc = @enumFromInt(name_tok),
28182873 });
28192874 try p.value_map.put(node, e.res.val);
28202875 return EnumFieldAndNode{ .field = .{
......@@ -2991,15 +3046,12 @@ fn directDeclarator(p: *Parser, base_type: Type, d: *Declarator, kind: Declarato
29913046 }
29923047
29933048 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
29983050 if (!size.ty.isInt()) {
29993051 try p.errStr(.array_size_non_int, size_tok, try p.typeStr(size.ty));
30003052 return error.ParsingFailed;
30013053 }
3002 if (base_type.is(.c23_auto)) {
3054 if (base_type.is(.c23_auto) or outer.is(.invalid)) {
30033055 // issue error later
30043056 return Type.invalid;
30053057 } else if (size.val.opt_ref == .none) {
......@@ -3030,7 +3082,7 @@ fn directDeclarator(p: *Parser, base_type: Type, d: *Declarator, kind: Declarato
30303082 } else {
30313083 // `outer` is validated later so it may be invalid here
30323084 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
30353087 var size_val = size.val;
30363088 if (size_val.isZero(p.comp)) {
......@@ -3047,7 +3099,7 @@ fn directDeclarator(p: *Parser, base_type: Type, d: *Declarator, kind: Declarato
30473099 arr_ty.len = max_elems;
30483100 }
30493101 res_ty.data = .{ .array = arr_ty };
3050 res_ty.specifier = .array;
3102 res_ty.specifier = if (static != null) .static_array else .array;
30513103 }
30523104
30533105 try res_ty.combine(outer);
......@@ -3120,12 +3172,14 @@ fn directDeclarator(p: *Parser, base_type: Type, d: *Declarator, kind: Declarato
31203172fn pointer(p: *Parser, base_ty: Type) Error!Type {
31213173 var ty = base_ty;
31223174 while (p.eatToken(.asterisk)) |_| {
3123 const elem_ty = try p.arena.create(Type);
3124 elem_ty.* = ty;
3125 ty = Type{
3126 .specifier = .pointer,
3127 .data = .{ .sub_type = elem_ty },
3128 };
3175 if (!ty.is(.invalid)) {
3176 const elem_ty = try p.arena.create(Type);
3177 elem_ty.* = ty;
3178 ty = Type{
3179 .specifier = .pointer,
3180 .data = .{ .sub_type = elem_ty },
3181 };
3182 }
31293183 var quals = Type.Qualifiers.Builder{};
31303184 _ = try p.typeQual(&quals);
31313185 try quals.finish(p, &ty);
......@@ -3237,6 +3291,75 @@ fn typeName(p: *Parser) Error!?Type {
32373291 return try Attribute.applyTypeAttributes(p, ty, attr_buf_top, .align_ignored);
32383292}
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
32403363/// initializer
32413364/// : assignExpr
32423365/// | '{' initializerItems '}'
......@@ -3255,6 +3378,9 @@ fn initializer(p: *Parser, init_ty: Type) Error!Result {
32553378 return error.ParsingFailed;
32563379 }
32573380
3381 if (init_ty.isComplex()) {
3382 return p.complexInitializer(init_ty);
3383 }
32583384 var il: InitList = .{};
32593385 defer il.deinit(p.gpa);
32603386
......@@ -3754,9 +3880,15 @@ fn convertInitList(p: *Parser, il: InitList, init_ty: Type) Error!NodeIndex {
37543880 var arr_init_node: Tree.Node = .{
37553881 .tag = .array_init_expr_two,
37563882 .ty = init_ty,
3757 .data = .{ .bin = .{ .lhs = .none, .rhs = .none } },
3883 .data = .{ .two = .{ .none, .none } },
37583884 };
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
37603892 if (init_ty.specifier == .incomplete_array) {
37613893 arr_init_node.ty.specifier = .array;
37623894 arr_init_node.ty.data.array.len = start;
......@@ -3767,8 +3899,6 @@ fn convertInitList(p: *Parser, il: InitList, init_ty: Type) Error!NodeIndex {
37673899 .specifier = .array,
37683900 .data = .{ .array = arr_ty },
37693901 };
3770 const attrs = init_ty.getAttributes();
3771 arr_init_node.ty = try arr_init_node.ty.withAttributes(p.arena, attrs);
37723902 } else if (start < max_items) {
37733903 const elem = try p.addNode(.{
37743904 .tag = .array_filler_expr,
......@@ -3781,8 +3911,8 @@ fn convertInitList(p: *Parser, il: InitList, init_ty: Type) Error!NodeIndex {
37813911 const items = p.list_buf.items[list_buf_top..];
37823912 switch (items.len) {
37833913 0 => {},
3784 1 => arr_init_node.data.bin.lhs = items[0],
3785 2 => arr_init_node.data.bin = .{ .lhs = items[0], .rhs = items[1] },
3914 1 => arr_init_node.data.two[0] = items[0],
3915 2 => arr_init_node.data.two = .{ items[0], items[1] },
37863916 else => {
37873917 arr_init_node.tag = .array_init_expr;
37883918 arr_init_node.data = .{ .range = try p.addList(items) };
......@@ -3813,13 +3943,13 @@ fn convertInitList(p: *Parser, il: InitList, init_ty: Type) Error!NodeIndex {
38133943 var struct_init_node: Tree.Node = .{
38143944 .tag = .struct_init_expr_two,
38153945 .ty = init_ty,
3816 .data = .{ .bin = .{ .lhs = .none, .rhs = .none } },
3946 .data = .{ .two = .{ .none, .none } },
38173947 };
38183948 const items = p.list_buf.items[list_buf_top..];
38193949 switch (items.len) {
38203950 0 => {},
3821 1 => struct_init_node.data.bin.lhs = items[0],
3822 2 => struct_init_node.data.bin = .{ .lhs = items[0], .rhs = items[1] },
3951 1 => struct_init_node.data.two[0] = items[0],
3952 2 => struct_init_node.data.two = .{ items[0], items[1] },
38233953 else => {
38243954 struct_init_node.tag = .struct_init_expr;
38253955 struct_init_node.data = .{ .range = try p.addList(items) };
......@@ -3894,7 +4024,7 @@ fn asmOperand(p: *Parser, names: *std.ArrayList(?TokenIndex), constraints: *Node
38944024/// | asmStr ':' asmOperand* ':' asmOperand*
38954025/// | asmStr ':' asmOperand* ':' asmOperand* : asmStr? (',' asmStr)*
38964026/// | 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 {
38984028 const asm_str = try p.asmStr();
38994029 try p.checkAsmStr(asm_str.val, l_paren);
39004030
......@@ -3903,6 +4033,7 @@ fn gnuAsmStmt(p: *Parser, quals: Tree.GNUAssemblyQualifiers, l_paren: TokenIndex
39034033 .tag = .gnu_asm_simple,
39044034 .ty = .{ .specifier = .void },
39054035 .data = .{ .un = asm_str.node },
4036 .loc = @enumFromInt(asm_tok),
39064037 });
39074038 }
39084039
......@@ -4007,6 +4138,7 @@ fn gnuAsmStmt(p: *Parser, quals: Tree.GNUAssemblyQualifiers, l_paren: TokenIndex
40074138 .tag = .addr_of_label,
40084139 .data = .{ .decl_ref = label },
40094140 .ty = result_ty,
4141 .loc = @enumFromInt(ident),
40104142 });
40114143 try exprs.append(label_addr_node);
40124144
......@@ -4088,9 +4220,10 @@ fn assembly(p: *Parser, kind: enum { global, decl_label, stmt }) Error!?NodeInde
40884220 .tag = .file_scope_asm,
40894221 .ty = .{ .specifier = .void },
40904222 .data = .{ .decl = .{ .name = asm_tok, .node = asm_str.node } },
4223 .loc = @enumFromInt(asm_tok),
40914224 });
40924225 },
4093 .stmt => result_node = try p.gnuAsmStmt(quals, l_paren),
4226 .stmt => result_node = try p.gnuAsmStmt(quals, asm_tok, l_paren),
40944227 }
40954228 try p.expectClosing(l_paren, .r_paren);
40964229
......@@ -4141,7 +4274,7 @@ fn asmStr(p: *Parser) Error!Result {
41414274fn stmt(p: *Parser) Error!NodeIndex {
41424275 if (try p.labeledStmt()) |some| return some;
41434276 if (try p.compoundStmt(false, null)) |some| return some;
4144 if (p.eatToken(.keyword_if)) |_| {
4277 if (p.eatToken(.keyword_if)) |kw_if| {
41454278 const l_paren = try p.expectToken(.l_paren);
41464279 const cond_tok = p.tok_i;
41474280 var cond = try p.expr();
......@@ -4160,14 +4293,16 @@ fn stmt(p: *Parser) Error!NodeIndex {
41604293 return try p.addNode(.{
41614294 .tag = .if_then_else_stmt,
41624295 .data = .{ .if3 = .{ .cond = cond.node, .body = (try p.addList(&.{ then, @"else" })).start } },
4296 .loc = @enumFromInt(kw_if),
41634297 })
41644298 else
41654299 return try p.addNode(.{
41664300 .tag = .if_then_stmt,
41674301 .data = .{ .bin = .{ .lhs = cond.node, .rhs = then } },
4302 .loc = @enumFromInt(kw_if),
41684303 });
41694304 }
4170 if (p.eatToken(.keyword_switch)) |_| {
4305 if (p.eatToken(.keyword_switch)) |kw_switch| {
41714306 const l_paren = try p.expectToken(.l_paren);
41724307 const cond_tok = p.tok_i;
41734308 var cond = try p.expr();
......@@ -4197,9 +4332,10 @@ fn stmt(p: *Parser) Error!NodeIndex {
41974332 return try p.addNode(.{
41984333 .tag = .switch_stmt,
41994334 .data = .{ .bin = .{ .lhs = cond.node, .rhs = body } },
4335 .loc = @enumFromInt(kw_switch),
42004336 });
42014337 }
4202 if (p.eatToken(.keyword_while)) |_| {
4338 if (p.eatToken(.keyword_while)) |kw_while| {
42034339 const l_paren = try p.expectToken(.l_paren);
42044340 const cond_tok = p.tok_i;
42054341 var cond = try p.expr();
......@@ -4221,9 +4357,10 @@ fn stmt(p: *Parser) Error!NodeIndex {
42214357 return try p.addNode(.{
42224358 .tag = .while_stmt,
42234359 .data = .{ .bin = .{ .lhs = cond.node, .rhs = body } },
4360 .loc = @enumFromInt(kw_while),
42244361 });
42254362 }
4226 if (p.eatToken(.keyword_do)) |_| {
4363 if (p.eatToken(.keyword_do)) |kw_do| {
42274364 const body = body: {
42284365 const old_loop = p.in_loop;
42294366 p.in_loop = true;
......@@ -4248,9 +4385,10 @@ fn stmt(p: *Parser) Error!NodeIndex {
42484385 return try p.addNode(.{
42494386 .tag = .do_while_stmt,
42504387 .data = .{ .bin = .{ .lhs = cond.node, .rhs = body } },
4388 .loc = @enumFromInt(kw_do),
42514389 });
42524390 }
4253 if (p.eatToken(.keyword_for)) |_| {
4391 if (p.eatToken(.keyword_for)) |kw_for| {
42544392 try p.syms.pushScope(p);
42554393 defer p.syms.popScope();
42564394 const decl_buf_top = p.decl_buf.items.len;
......@@ -4301,16 +4439,22 @@ fn stmt(p: *Parser) Error!NodeIndex {
43014439 return try p.addNode(.{
43024440 .tag = .for_decl_stmt,
43034441 .data = .{ .range = .{ .start = start, .end = end } },
4442 .loc = @enumFromInt(kw_for),
43044443 });
43054444 } else if (init.node == .none and cond.node == .none and incr.node == .none) {
43064445 return try p.addNode(.{
43074446 .tag = .forever_stmt,
43084447 .data = .{ .un = body },
4448 .loc = @enumFromInt(kw_for),
43094449 });
4310 } else return try p.addNode(.{ .tag = .for_stmt, .data = .{ .if3 = .{
4311 .cond = body,
4312 .body = (try p.addList(&.{ init.node, cond.node, incr.node })).start,
4313 } } });
4450 } else return try p.addNode(.{
4451 .tag = .for_stmt,
4452 .data = .{ .if3 = .{
4453 .cond = body,
4454 .body = (try p.addList(&.{ init.node, cond.node, incr.node })).start,
4455 } },
4456 .loc = @enumFromInt(kw_for),
4457 });
43144458 }
43154459 if (p.eatToken(.keyword_goto)) |goto_tok| {
43164460 if (p.eatToken(.asterisk)) |_| {
......@@ -4338,7 +4482,7 @@ fn stmt(p: *Parser) Error!NodeIndex {
43384482 }
43394483 }
43404484
4341 try e.un(p, .computed_goto_stmt);
4485 try e.un(p, .computed_goto_stmt, goto_tok);
43424486 _ = try p.expectToken(.semicolon);
43434487 return e.node;
43444488 }
......@@ -4351,17 +4495,18 @@ fn stmt(p: *Parser) Error!NodeIndex {
43514495 return try p.addNode(.{
43524496 .tag = .goto_stmt,
43534497 .data = .{ .decl_ref = name_tok },
4498 .loc = @enumFromInt(goto_tok),
43544499 });
43554500 }
43564501 if (p.eatToken(.keyword_continue)) |cont| {
43574502 if (!p.in_loop) try p.errTok(.continue_not_in_loop, cont);
43584503 _ = 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) });
43604505 }
43614506 if (p.eatToken(.keyword_break)) |br| {
43624507 if (!p.in_loop and p.@"switch" == null) try p.errTok(.break_not_in_loop_or_switch, br);
43634508 _ = 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) });
43654510 }
43664511 if (try p.returnStmt()) |some| return some;
43674512 if (try p.assembly(.stmt)) |some| return some;
......@@ -4380,8 +4525,8 @@ fn stmt(p: *Parser) Error!NodeIndex {
43804525 defer p.attr_buf.len = attr_buf_top;
43814526 try p.attributeSpecifier();
43824527
4383 if (p.eatToken(.semicolon)) |_| {
4384 var null_node: Tree.Node = .{ .tag = .null_stmt, .data = undefined };
4528 if (p.eatToken(.semicolon)) |semicolon| {
4529 var null_node: Tree.Node = .{ .tag = .null_stmt, .data = undefined, .loc = @enumFromInt(semicolon) };
43854530 null_node.ty = try Attribute.applyStatementAttributes(p, null_node.ty, expr_start, attr_buf_top);
43864531 return p.addNode(null_node);
43874532 }
......@@ -4422,6 +4567,7 @@ fn labeledStmt(p: *Parser) Error!?NodeIndex {
44224567 var labeled_stmt = Tree.Node{
44234568 .tag = .labeled_stmt,
44244569 .data = .{ .decl = .{ .name = name_tok, .node = try p.labelableStmt() } },
4570 .loc = @enumFromInt(name_tok),
44254571 };
44264572 labeled_stmt.ty = try Attribute.applyLabelAttributes(p, labeled_stmt.ty, attr_buf_top);
44274573 return try p.addNode(labeled_stmt);
......@@ -4464,9 +4610,11 @@ fn labeledStmt(p: *Parser) Error!?NodeIndex {
44644610 if (second_item) |some| return try p.addNode(.{
44654611 .tag = .case_range_stmt,
44664612 .data = .{ .if3 = .{ .cond = s, .body = (try p.addList(&.{ first_item.node, some.node })).start } },
4613 .loc = @enumFromInt(case),
44674614 }) else return try p.addNode(.{
44684615 .tag = .case_stmt,
44694616 .data = .{ .bin = .{ .lhs = first_item.node, .rhs = s } },
4617 .loc = @enumFromInt(case),
44704618 });
44714619 } else if (p.eatToken(.keyword_default)) |default| {
44724620 _ = try p.expectToken(.colon);
......@@ -4474,6 +4622,7 @@ fn labeledStmt(p: *Parser) Error!?NodeIndex {
44744622 const node = try p.addNode(.{
44754623 .tag = .default_stmt,
44764624 .data = .{ .un = s },
4625 .loc = @enumFromInt(default),
44774626 });
44784627 const @"switch" = p.@"switch" orelse {
44794628 try p.errStr(.case_not_in_switch, default, "default");
......@@ -4492,7 +4641,7 @@ fn labeledStmt(p: *Parser) Error!?NodeIndex {
44924641fn labelableStmt(p: *Parser) Error!NodeIndex {
44934642 if (p.tok_ids[p.tok_i] == .r_brace) {
44944643 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) });
44964645 }
44974646 return p.stmt();
44984647}
......@@ -4557,6 +4706,7 @@ fn compoundStmt(p: *Parser, is_fn_body: bool, stmt_expr_state: ?*StmtExprState)
45574706 else => {},
45584707 }
45594708 }
4709 const r_brace = p.tok_i - 1;
45604710
45614711 if (noreturn_index) |some| {
45624712 // 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)
45804730 try p.errStr(.func_does_not_return, p.tok_i - 1, func_name);
45814731 }
45824732 }
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) }));
45844734 }
45854735 if (p.func.ident) |some| try p.decl_buf.insert(decl_buf_top, some.node);
45864736 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)
45884738
45894739 var node: Tree.Node = .{
45904740 .tag = .compound_stmt_two,
4591 .data = .{ .bin = .{ .lhs = .none, .rhs = .none } },
4741 .data = .{ .two = .{ .none, .none } },
4742 .loc = @enumFromInt(l_brace),
45924743 };
45934744 const statements = p.decl_buf.items[decl_buf_top..];
45944745 switch (statements.len) {
45954746 0 => {},
4596 1 => node.data = .{ .bin = .{ .lhs = statements[0], .rhs = .none } },
4597 2 => node.data = .{ .bin = .{ .lhs = statements[0], .rhs = statements[1] } },
4747 1 => node.data = .{ .two = .{ statements[0], .none } },
4748 2 => node.data = .{ .two = .{ statements[0], statements[1] } },
45984749 else => {
45994750 node.tag = .compound_stmt;
46004751 node.data = .{ .range = try p.addList(statements) };
......@@ -4618,8 +4769,8 @@ fn nodeIsNoreturn(p: *Parser, node: NodeIndex) NoreturnKind {
46184769 },
46194770 .compound_stmt_two => {
46204771 const data = p.nodes.items(.data)[@intFromEnum(node)];
4621 const lhs_type = if (data.bin.lhs != .none) p.nodeIsNoreturn(data.bin.lhs) else .no;
4622 const rhs_type = if (data.bin.rhs != .none) p.nodeIsNoreturn(data.bin.rhs) else .no;
4772 const lhs_type = if (data.two[0] != .none) p.nodeIsNoreturn(data.two[0]) else .no;
4773 const rhs_type = if (data.two[1] != .none) p.nodeIsNoreturn(data.two[1]) else .no;
46234774 if (lhs_type == .complex or rhs_type == .complex) return .complex;
46244775 if (lhs_type == .yes or rhs_type == .yes) return .yes;
46254776 return .no;
......@@ -4704,6 +4855,8 @@ fn nextStmt(p: *Parser, l_brace: TokenIndex) !void {
47044855 .keyword_int,
47054856 .keyword_long,
47064857 .keyword_signed,
4858 .keyword_signed1,
4859 .keyword_signed2,
47074860 .keyword_unsigned,
47084861 .keyword_float,
47094862 .keyword_double,
......@@ -4743,17 +4896,17 @@ fn returnStmt(p: *Parser) Error!?NodeIndex {
47434896
47444897 if (e.node == .none) {
47454898 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) });
47474900 } else if (ret_ty.is(.void)) {
47484901 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) });
47504903 }
47514904
47524905 try e.lvalConversion(p);
47534906 try e.coerce(p, ret_ty, e_tok, .ret);
47544907
47554908 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) });
47574910}
47584911
47594912// ====== expressions ======
......@@ -4802,7 +4955,6 @@ const CallExpr = union(enum) {
48024955 }
48034956
48044957 fn shouldPromoteVarArg(self: CallExpr, arg_idx: u32) bool {
4805 @setEvalBranchQuota(2000);
48064958 return switch (self) {
48074959 .standard => true,
48084960 .builtin => |builtin| switch (builtin.tag) {
......@@ -4810,10 +4962,13 @@ const CallExpr = union(enum) {
48104962 Builtin.tagFromName("__va_start").?,
48114963 Builtin.tagFromName("va_start").?,
48124964 => arg_idx != 1,
4813 Builtin.tagFromName("__builtin_complex").?,
48144965 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").?,
48164969 Builtin.tagFromName("__builtin_mul_overflow").?,
4970 Builtin.tagFromName("__builtin_isnan").?,
4971 Builtin.tagFromName("__builtin_sub_overflow").?,
48174972 => false,
48184973 else => true,
48194974 },
......@@ -4827,7 +4982,6 @@ const CallExpr = union(enum) {
48274982 }
48284983
48294984 fn checkVarArg(self: CallExpr, p: *Parser, first_after: TokenIndex, param_tok: TokenIndex, arg: *Result, arg_idx: u32) !void {
4830 @setEvalBranchQuota(10_000);
48314985 if (self == .standard) return;
48324986
48334987 const builtin_tok = p.nodes.items(.data)[@intFromEnum(self.builtin.node)].decl.name;
......@@ -4852,13 +5006,15 @@ const CallExpr = union(enum) {
48525006 /// of arguments, `paramCountOverride` is used to tell us how many arguments we should actually expect to see for
48535007 /// these custom-typechecked functions.
48545008 fn paramCountOverride(self: CallExpr) ?u32 {
4855 @setEvalBranchQuota(10_000);
48565009 return switch (self) {
48575010 .standard => null,
48585011 .builtin => |builtin| switch (builtin.tag) {
48595012 Builtin.tagFromName("__c11_atomic_thread_fence").?,
48605013 Builtin.tagFromName("__c11_atomic_signal_fence").?,
48615014 Builtin.tagFromName("__c11_atomic_is_lock_free").?,
5015 Builtin.tagFromName("__builtin_isinf").?,
5016 Builtin.tagFromName("__builtin_isinf_sign").?,
5017 Builtin.tagFromName("__builtin_isnan").?,
48625018 => 1,
48635019
48645020 Builtin.tagFromName("__builtin_complex").?,
......@@ -4903,7 +5059,6 @@ const CallExpr = union(enum) {
49035059 }
49045060
49055061 fn returnType(self: CallExpr, p: *Parser, callable_ty: Type) Type {
4906 @setEvalBranchQuota(6000);
49075062 return switch (self) {
49085063 .standard => callable_ty.returnType(),
49095064 .builtin => |builtin| switch (builtin.tag) {
......@@ -4977,12 +5132,12 @@ const CallExpr = union(enum) {
49775132 var call_node: Tree.Node = .{
49785133 .tag = .call_expr_one,
49795134 .ty = ret_ty,
4980 .data = .{ .bin = .{ .lhs = func_node, .rhs = .none } },
5135 .data = .{ .two = .{ func_node, .none } },
49815136 };
49825137 const args = p.list_buf.items[list_buf_top..];
49835138 switch (arg_count) {
49845139 0 => {},
4985 1 => call_node.data.bin.rhs = args[1], // args[0] == func.node
5140 1 => call_node.data.two[1] = args[1], // args[0] == func.node
49865141 else => {
49875142 call_node.tag = .call_expr;
49885143 call_node.data = .{ .range = try p.addList(args) };
......@@ -5005,7 +5160,8 @@ const CallExpr = union(enum) {
50055160 call_node.data = .{ .range = try p.addList(args) };
50065161 },
50075162 }
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 };
50095165 },
50105166 }
50115167 }
......@@ -5016,6 +5172,8 @@ pub const Result = struct {
50165172 ty: Type = .{ .specifier = .int },
50175173 val: Value = .{},
50185174
5175 const invalid: Result = .{ .ty = Type.invalid };
5176
50195177 pub fn str(res: Result, p: *Parser) ![]const u8 {
50205178 switch (res.val.opt_ref) {
50215179 .none => return "(none)",
......@@ -5073,30 +5231,21 @@ pub const Result = struct {
50735231 .post_inc_expr,
50745232 .post_dec_expr,
50755233 => return,
5076 .call_expr_one => {
5077 const fn_ptr = p.nodes.items(.data)[@intFromEnum(cur_node)].bin.lhs;
5078 const fn_ty = p.nodes.items(.ty)[@intFromEnum(fn_ptr)].elemType();
5079 const cast_info = p.nodes.items(.data)[@intFromEnum(fn_ptr)].cast.operand;
5080 const decl_ref = p.nodes.items(.data)[@intFromEnum(cast_info)].decl_ref;
5081 if (fn_ty.hasAttribute(.nodiscard)) try p.errStr(.nodiscard_unused, expr_start, p.tokSlice(decl_ref));
5082 if (fn_ty.hasAttribute(.warn_unused_result)) try p.errStr(.warn_unused_result, expr_start, p.tokSlice(decl_ref));
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));
5234 .call_expr, .call_expr_one => {
5235 const tmp_tree = p.tmpTree();
5236 const child_nodes = tmp_tree.childNodes(cur_node);
5237 const fn_ptr = child_nodes[0];
5238 const call_info = tmp_tree.callableResultUsage(fn_ptr) orelse return;
5239 if (call_info.nodiscard) try p.errStr(.nodiscard_unused, expr_start, p.tokSlice(call_info.tok));
5240 if (call_info.warn_unused_result) try p.errStr(.warn_unused_result, expr_start, p.tokSlice(call_info.tok));
50925241 return;
50935242 },
50945243 .stmt_expr => {
50955244 const body = p.nodes.items(.data)[@intFromEnum(cur_node)].un;
50965245 switch (p.nodes.items(.tag)[@intFromEnum(body)]) {
50975246 .compound_stmt_two => {
5098 const body_stmt = p.nodes.items(.data)[@intFromEnum(body)].bin;
5099 cur_node = if (body_stmt.rhs != .none) body_stmt.rhs else body_stmt.lhs;
5247 const body_stmt = p.nodes.items(.data)[@intFromEnum(body)].two;
5248 cur_node = if (body_stmt[1] != .none) body_stmt[1] else body_stmt[0];
51005249 },
51015250 .compound_stmt => {
51025251 const data = p.nodes.items(.data)[@intFromEnum(body)];
......@@ -5112,29 +5261,31 @@ pub const Result = struct {
51125261 try p.errTok(.unused_value, expr_start);
51135262 }
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 {
51165265 if (lhs.val.opt_ref == .null) {
51175266 lhs.val = Value.zero;
51185267 }
51195268 if (lhs.ty.specifier != .invalid) {
51205269 lhs.ty = Type.int;
51215270 }
5122 return lhs.bin(p, tag, rhs);
5271 return lhs.bin(p, tag, rhs, tok_i);
51235272 }
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 {
51265275 lhs.node = try p.addNode(.{
51275276 .tag = tag,
51285277 .ty = lhs.ty,
51295278 .data = .{ .bin = .{ .lhs = lhs.node, .rhs = rhs.node } },
5279 .loc = @enumFromInt(tok_i),
51305280 });
51315281 }
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 {
51345284 operand.node = try p.addNode(.{
51355285 .tag = tag,
51365286 .ty = operand.ty,
51375287 .data = .{ .un = operand.node },
5288 .loc = @enumFromInt(tok_i),
51385289 });
51395290 }
51405291
......@@ -5368,10 +5519,14 @@ pub const Result = struct {
53685519
53695520 fn lvalConversion(res: *Result, p: *Parser) Error!void {
53705521 if (res.ty.isFunc()) {
5371 const elem_ty = try p.arena.create(Type);
5372 elem_ty.* = res.ty;
5373 res.ty.specifier = .pointer;
5374 res.ty.data = .{ .sub_type = elem_ty };
5522 if (res.ty.isInvalidFunc()) {
5523 res.ty = .{ .specifier = .invalid };
5524 } else {
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 }
53755530 try res.implicitCast(p, .function_to_pointer);
53765531 } else if (res.ty.isArray()) {
53775532 res.val = .{};
......@@ -5455,7 +5610,14 @@ pub const Result = struct {
54555610 try res.implicitCast(p, .complex_float_to_complex_int);
54565611 }
54575612 } 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
54595621 const old_real = res.ty.isReal();
54605622 const new_real = int_ty.isReal();
54615623 if (old_real and new_real) {
......@@ -5486,8 +5648,8 @@ pub const Result = struct {
54865648 .none => return p.errStr(.float_to_int, tok, try p.typePairStrExtra(res.ty, " to ", int_ty)),
54875649 .out_of_range => return p.errStr(.float_out_of_range, tok, try p.typePairStrExtra(res.ty, " to ", int_ty)),
54885650 .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)),
5490 .value_changed => return p.errStr(.float_value_changed, 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)),
5652 .value_changed => return p.errStr(.float_value_changed, tok, try p.valueChangedStr(res, old_value, int_ty)),
54915653 }
54925654 }
54935655
......@@ -5555,7 +5717,7 @@ pub const Result = struct {
55555717 res.ty = ptr_ty;
55565718 try res.implicitCast(p, .bool_to_pointer);
55575719 } else if (res.ty.isInt()) {
5558 try res.val.intCast(ptr_ty, p.comp);
5720 _ = try res.val.intCast(ptr_ty, p.comp);
55595721 res.ty = ptr_ty;
55605722 try res.implicitCast(p, .int_to_pointer);
55615723 }
......@@ -5620,16 +5782,14 @@ pub const Result = struct {
56205782
56215783 // if either is a float cast to that type
56225784 if (a.ty.isFloat() or b.ty.isFloat()) {
5623 const float_types = [7][2]Type.Specifier{
5785 const float_types = [6][2]Type.Specifier{
56245786 .{ .complex_long_double, .long_double },
56255787 .{ .complex_float128, .float128 },
5626 .{ .complex_float80, .float80 },
56275788 .{ .complex_double, .double },
56285789 .{ .complex_float, .float },
56295790 // No `_Complex __fp16` type
56305791 .{ .invalid, .fp16 },
5631 // No `_Complex _Float16`
5632 .{ .invalid, .float16 },
5792 .{ .complex_float16, .float16 },
56335793 };
56345794 const a_spec = a.ty.canonicalize(.standard).specifier;
56355795 const b_spec = b.ty.canonicalize(.standard).specifier;
......@@ -5647,7 +5807,7 @@ pub const Result = struct {
56475807 if (try a.floatConversion(b, a_spec, b_spec, p, float_types[3])) return;
56485808 if (try a.floatConversion(b, a_spec, b_spec, p, float_types[4])) return;
56495809 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;
56515811 }
56525812
56535813 if (a.ty.eql(b.ty, p.comp, true)) {
......@@ -5875,6 +6035,10 @@ pub const Result = struct {
58756035 if (to.is(.bool)) {
58766036 res.val.boolCast(p.comp);
58776037 } 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 }
58786042 // Explicit cast, no conversion warning
58796043 _ = try res.val.floatToInt(to, p.comp);
58806044 } else if (new_float and old_int) {
......@@ -5886,7 +6050,7 @@ pub const Result = struct {
58866050 try p.errStr(.cast_to_incomplete_type, l_paren, try p.typeStr(to));
58876051 return error.ParsingFailed;
58886052 }
5889 try res.val.intCast(to, p.comp);
6053 _ = try res.val.intCast(to, p.comp);
58906054 }
58916055 } else if (to.get(.@"union")) |union_ty| {
58926056 if (union_ty.data.record.hasFieldOfType(res.ty, p.comp)) {
......@@ -5918,12 +6082,13 @@ pub const Result = struct {
59186082 .tag = .explicit_cast,
59196083 .ty = res.ty,
59206084 .data = .{ .cast = .{ .operand = res.node, .kind = cast_kind } },
6085 .loc = @enumFromInt(l_paren),
59216086 });
59226087 }
59236088
59246089 fn intFitsInType(res: Result, p: *Parser, ty: Type) !bool {
5925 const max_int = try Value.int(ty.maxInt(p.comp), p.comp);
5926 const min_int = try Value.int(ty.minInt(p.comp), p.comp);
6090 const max_int = try Value.maxInt(ty, p.comp);
6091 const min_int = try Value.minInt(ty, p.comp);
59276092 return res.val.compare(.lte, max_int, p.comp) and
59286093 (res.ty.isUnsignedInt(p.comp) or res.val.compare(.gte, min_int, p.comp));
59296094 }
......@@ -6091,7 +6256,7 @@ fn expr(p: *Parser) Error!Result {
60916256 var err_start = p.comp.diagnostics.list.items.len;
60926257 var lhs = try p.assignExpr();
60936258 if (p.tok_ids[p.tok_i] == .comma) try lhs.expect(p);
6094 while (p.eatToken(.comma)) |_| {
6259 while (p.eatToken(.comma)) |comma| {
60956260 try lhs.maybeWarnUnused(p, expr_start, err_start);
60966261 expr_start = p.tok_i;
60976262 err_start = p.comp.diagnostics.list.items.len;
......@@ -6101,7 +6266,7 @@ fn expr(p: *Parser) Error!Result {
61016266 try rhs.lvalConversion(p);
61026267 lhs.val = rhs.val;
61036268 lhs.ty = rhs.ty;
6104 try lhs.bin(p, .comma_expr, rhs);
6269 try lhs.bin(p, .comma_expr, rhs, comma);
61056270 }
61066271 return lhs;
61076272}
......@@ -6183,7 +6348,7 @@ fn assignExpr(p: *Parser) Error!Result {
61836348 }
61846349 }
61856350 _ = 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.?);
61876352 return lhs;
61886353 },
61896354 .sub_assign_expr,
......@@ -6194,7 +6359,7 @@ fn assignExpr(p: *Parser) Error!Result {
61946359 } else {
61956360 _ = try lhs_copy.adjustTypes(tok, &rhs, p, .arithmetic);
61966361 }
6197 try lhs.bin(p, tag, rhs);
6362 try lhs.bin(p, tag, rhs, bit_or.?);
61986363 return lhs;
61996364 },
62006365 .shl_assign_expr,
......@@ -6204,7 +6369,7 @@ fn assignExpr(p: *Parser) Error!Result {
62046369 .bit_or_assign_expr,
62056370 => {
62066371 _ = try lhs_copy.adjustTypes(tok, &rhs, p, .integer);
6207 try lhs.bin(p, tag, rhs);
6372 try lhs.bin(p, tag, rhs, bit_or.?);
62086373 return lhs;
62096374 },
62106375 else => unreachable,
......@@ -6212,7 +6377,7 @@ fn assignExpr(p: *Parser) Error!Result {
62126377
62136378 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.?);
62166381 return lhs;
62176382}
62186383
......@@ -6280,6 +6445,7 @@ fn condExpr(p: *Parser) Error!Result {
62806445 .tag = .binary_cond_expr,
62816446 .ty = cond.ty,
62826447 .data = .{ .if3 = .{ .cond = cond.node, .body = (try p.addList(&.{ cond_then.node, then_expr.node })).start } },
6448 .loc = @enumFromInt(cond_tok),
62836449 });
62846450 return cond;
62856451 }
......@@ -6305,6 +6471,7 @@ fn condExpr(p: *Parser) Error!Result {
63056471 .tag = .cond_expr,
63066472 .ty = cond.ty,
63076473 .data = .{ .if3 = .{ .cond = cond.node, .body = (try p.addList(&.{ then_expr.node, else_expr.node })).start } },
6474 .loc = @enumFromInt(cond_tok),
63086475 });
63096476 return cond;
63106477}
......@@ -6324,8 +6491,10 @@ fn lorExpr(p: *Parser) Error!Result {
63246491 if (try lhs.adjustTypes(tok, &rhs, p, .boolean_logic)) {
63256492 const res = lhs.val.toBool(p.comp) or rhs.val.toBool(p.comp);
63266493 lhs.val = Value.fromBool(res);
6494 } else {
6495 lhs.val.boolCast(p.comp);
63276496 }
6328 try lhs.boolRes(p, .bool_or_expr, rhs);
6497 try lhs.boolRes(p, .bool_or_expr, rhs, tok);
63296498 }
63306499 return lhs;
63316500}
......@@ -6345,8 +6514,10 @@ fn landExpr(p: *Parser) Error!Result {
63456514 if (try lhs.adjustTypes(tok, &rhs, p, .boolean_logic)) {
63466515 const res = lhs.val.toBool(p.comp) and rhs.val.toBool(p.comp);
63476516 lhs.val = Value.fromBool(res);
6517 } else {
6518 lhs.val.boolCast(p.comp);
63486519 }
6349 try lhs.boolRes(p, .bool_and_expr, rhs);
6520 try lhs.boolRes(p, .bool_and_expr, rhs, tok);
63506521 }
63516522 return lhs;
63526523}
......@@ -6362,7 +6533,7 @@ fn orExpr(p: *Parser) Error!Result {
63626533 if (try lhs.adjustTypes(tok, &rhs, p, .integer)) {
63636534 lhs.val = try lhs.val.bitOr(rhs.val, p.comp);
63646535 }
6365 try lhs.bin(p, .bit_or_expr, rhs);
6536 try lhs.bin(p, .bit_or_expr, rhs, tok);
63666537 }
63676538 return lhs;
63686539}
......@@ -6378,7 +6549,7 @@ fn xorExpr(p: *Parser) Error!Result {
63786549 if (try lhs.adjustTypes(tok, &rhs, p, .integer)) {
63796550 lhs.val = try lhs.val.bitXor(rhs.val, p.comp);
63806551 }
6381 try lhs.bin(p, .bit_xor_expr, rhs);
6552 try lhs.bin(p, .bit_xor_expr, rhs, tok);
63826553 }
63836554 return lhs;
63846555}
......@@ -6394,7 +6565,7 @@ fn andExpr(p: *Parser) Error!Result {
63946565 if (try lhs.adjustTypes(tok, &rhs, p, .integer)) {
63956566 lhs.val = try lhs.val.bitAnd(rhs.val, p.comp);
63966567 }
6397 try lhs.bin(p, .bit_and_expr, rhs);
6568 try lhs.bin(p, .bit_and_expr, rhs, tok);
63986569 }
63996570 return lhs;
64006571}
......@@ -6414,8 +6585,10 @@ fn eqExpr(p: *Parser) Error!Result {
64146585 const op: std.math.CompareOperator = if (tag == .equal_expr) .eq else .neq;
64156586 const res = lhs.val.compare(op, rhs.val, p.comp);
64166587 lhs.val = Value.fromBool(res);
6588 } else {
6589 lhs.val.boolCast(p.comp);
64176590 }
6418 try lhs.boolRes(p, tag, rhs);
6591 try lhs.boolRes(p, tag, rhs, ne.?);
64196592 }
64206593 return lhs;
64216594}
......@@ -6443,8 +6616,10 @@ fn compExpr(p: *Parser) Error!Result {
64436616 };
64446617 const res = lhs.val.compare(op, rhs.val, p.comp);
64456618 lhs.val = Value.fromBool(res);
6619 } else {
6620 lhs.val.boolCast(p.comp);
64466621 }
6447 try lhs.boolRes(p, tag, rhs);
6622 try lhs.boolRes(p, tag, rhs, ge.?);
64486623 }
64496624 return lhs;
64506625}
......@@ -6474,7 +6649,7 @@ fn shiftExpr(p: *Parser) Error!Result {
64746649 lhs.val = try lhs.val.shr(rhs.val, lhs.ty, p.comp);
64756650 }
64766651 }
6477 try lhs.bin(p, tag, rhs);
6652 try lhs.bin(p, tag, rhs, shr.?);
64786653 }
64796654 return lhs;
64806655}
......@@ -6504,7 +6679,7 @@ fn addExpr(p: *Parser) Error!Result {
65046679 try p.errStr(.ptr_arithmetic_incomplete, minus.?, try p.typeStr(lhs_ty.elemType()));
65056680 lhs.ty = Type.invalid;
65066681 }
6507 try lhs.bin(p, tag, rhs);
6682 try lhs.bin(p, tag, rhs, minus.?);
65086683 }
65096684 return lhs;
65106685}
......@@ -6538,7 +6713,7 @@ fn mulExpr(p: *Parser) Error!Result {
65386713 lhs.ty.signedness(p.comp) != .unsigned) try p.errOverflow(mul.?, lhs);
65396714 } else if (div != null) {
65406715 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);
65426717 } else {
65436718 var res = try Value.rem(lhs.val, rhs.val, lhs.ty, p.comp);
65446719 if (res.opt_ref == .none) {
......@@ -6554,7 +6729,7 @@ fn mulExpr(p: *Parser) Error!Result {
65546729 }
65556730 }
65566731
6557 try lhs.bin(p, tag, rhs);
6732 try lhs.bin(p, tag, rhs, percent.?);
65586733 }
65596734 return lhs;
65606735}
......@@ -6573,7 +6748,7 @@ fn removeUnusedWarningForTok(p: *Parser, last_expr_tok: TokenIndex) void {
65736748}
65746749
65756750/// castExpr
6576/// : '(' compoundStmt ')'
6751/// : '(' compoundStmt ')' suffixExpr*
65776752/// | '(' typeName ')' castExpr
65786753/// | '(' typeName ')' '{' initializerItems '}'
65796754/// | __builtin_choose_expr '(' integerConstExpr ',' assignExpr ',' assignExpr ')'
......@@ -6584,6 +6759,7 @@ fn removeUnusedWarningForTok(p: *Parser, last_expr_tok: TokenIndex) void {
65846759fn castExpr(p: *Parser) Error!Result {
65856760 if (p.eatToken(.l_paren)) |l_paren| cast_expr: {
65866761 if (p.tok_ids[p.tok_i] == .l_brace) {
6762 const tok = p.tok_i;
65876763 try p.err(.gnu_statement_expression);
65886764 if (p.func.ty == null) {
65896765 try p.err(.stmt_expr_not_allowed_file_scope);
......@@ -6599,7 +6775,12 @@ fn castExpr(p: *Parser) Error!Result {
65996775 .val = stmt_expr_state.last_expr_res.val,
66006776 };
66016777 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 }
66036784 return res;
66046785 }
66056786 const ty = (try p.typeName()) orelse {
......@@ -6634,23 +6815,26 @@ fn castExpr(p: *Parser) Error!Result {
66346815}
66356816
66366817fn typesCompatible(p: *Parser) Error!Result {
6818 const builtin_tok = p.tok_i;
66376819 p.tok_i += 1;
66386820 const l_paren = try p.expectToken(.l_paren);
66396821
6822 const first_tok = p.tok_i;
66406823 const first = (try p.typeName()) orelse {
66416824 try p.err(.expected_type);
66426825 p.skipTo(.r_paren);
66436826 return error.ParsingFailed;
66446827 };
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) });
66466829 _ = try p.expectToken(.comma);
66476830
6831 const second_tok = p.tok_i;
66486832 const second = (try p.typeName()) orelse {
66496833 try p.err(.expected_type);
66506834 p.skipTo(.r_paren);
66516835 return error.ParsingFailed;
66526836 };
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
66556839 try p.expectClosing(l_paren, .r_paren);
66566840
......@@ -6665,10 +6849,15 @@ fn typesCompatible(p: *Parser) Error!Result {
66656849
66666850 const res = Result{
66676851 .val = Value.fromBool(compatible),
6668 .node = try p.addNode(.{ .tag = .builtin_types_compatible_p, .ty = Type.int, .data = .{ .bin = .{
6669 .lhs = lhs,
6670 .rhs = rhs,
6671 } } }),
6852 .node = try p.addNode(.{
6853 .tag = .builtin_types_compatible_p,
6854 .ty = Type.int,
6855 .data = .{ .bin = .{
6856 .lhs = lhs,
6857 .rhs = rhs,
6858 } },
6859 .loc = @enumFromInt(builtin_tok),
6860 }),
66726861 };
66736862 try p.value_map.put(res.node, res.val);
66746863 return res;
......@@ -6786,11 +6975,11 @@ fn offsetofMemberDesignator(p: *Parser, base_ty: Type, want_bits: bool) Error!Re
67866975 errdefer p.skipTo(.r_paren);
67876976 const base_field_name_tok = try p.expectIdentifier();
67886977 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);
67906980 const base_node = try p.addNode(.{ .tag = .default_init_expr, .ty = base_ty, .data = undefined });
67916981
67926982 var cur_offset: u64 = 0;
6793 const base_record_ty = base_ty.canonicalize(.standard);
67946983 var lhs = try p.fieldAccessExtra(base_node, base_record_ty, base_field_name, false, &cur_offset);
67956984
67966985 var total_offset = cur_offset;
......@@ -6800,13 +6989,12 @@ fn offsetofMemberDesignator(p: *Parser, base_ty: Type, want_bits: bool) Error!Re
68006989 const field_name_tok = try p.expectIdentifier();
68016990 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 {
68046993 try p.errStr(.offsetof_ty, field_name_tok, try p.typeStr(lhs.ty));
68056994 return error.ParsingFailed;
6806 }
6807 try p.validateFieldAccess(lhs.ty, lhs.ty, field_name_tok, field_name);
6808 const record_ty = lhs.ty.canonicalize(.standard);
6809 lhs = try p.fieldAccessExtra(lhs.node, record_ty, field_name, false, &cur_offset);
6995 };
6996 try p.validateFieldAccess(lhs_record_ty, lhs.ty, field_name_tok, field_name);
6997 lhs = try p.fieldAccessExtra(lhs.node, lhs_record_ty, field_name, false, &cur_offset);
68106998 total_offset += cur_offset;
68116999 },
68127000 .l_bracket => {
......@@ -6824,11 +7012,14 @@ fn offsetofMemberDesignator(p: *Parser, base_ty: Type, want_bits: bool) Error!Re
68247012 try ptr.lvalConversion(p);
68257013 try index.lvalConversion(p);
68267014
6827 if (!index.ty.isInt()) try p.errTok(.invalid_index, l_bracket_tok);
6828 try p.checkArrayBounds(index, lhs, l_bracket_tok);
7015 if (index.ty.isInt()) {
7016 try p.checkArrayBounds(index, lhs, l_bracket_tok);
7017 } else {
7018 try p.errTok(.invalid_index, l_bracket_tok);
7019 }
68297020
68307021 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);
68327023 lhs = ptr;
68337024 },
68347025 else => break,
......@@ -6867,6 +7058,7 @@ fn unExpr(p: *Parser) Error!Result {
68677058 .tag = .addr_of_label,
68687059 .data = .{ .decl_ref = name_tok },
68697060 .ty = result_ty,
7061 .loc = @enumFromInt(address_tok),
68707062 }),
68717063 .ty = result_ty,
68727064 };
......@@ -6886,19 +7078,21 @@ fn unExpr(p: *Parser) Error!Result {
68867078 {
68877079 if (tree.isBitfield(member_node)) try p.errTok(.addr_of_bitfield, tok);
68887080 }
6889 if (!tree.isLval(operand.node)) {
7081 if (!tree.isLval(operand.node) and !operand.ty.is(.invalid)) {
68907082 try p.errTok(.addr_of_rvalue, tok);
68917083 }
68927084 if (operand.ty.qual.register) try p.errTok(.addr_of_register, tok);
68937085
6894 const elem_ty = try p.arena.create(Type);
6895 elem_ty.* = operand.ty;
6896 operand.ty = Type{
6897 .specifier = .pointer,
6898 .data = .{ .sub_type = elem_ty },
6899 };
7086 if (!operand.ty.is(.invalid)) {
7087 const elem_ty = try p.arena.create(Type);
7088 elem_ty.* = operand.ty;
7089 operand.ty = Type{
7090 .specifier = .pointer,
7091 .data = .{ .sub_type = elem_ty },
7092 };
7093 }
69007094 try operand.saveValue(p);
6901 try operand.un(p, .addr_of_expr);
7095 try operand.un(p, .addr_of_expr, tok);
69027096 return operand;
69037097 },
69047098 .asterisk => {
......@@ -6917,7 +7111,7 @@ fn unExpr(p: *Parser) Error!Result {
69177111 try p.errStr(.deref_incomplete_ty_ptr, asterisk_loc, try p.typeStr(operand.ty));
69187112 }
69197113 operand.ty.qual = .{};
6920 try operand.un(p, .deref_expr);
7114 try operand.un(p, .deref_expr, tok);
69217115 return operand;
69227116 },
69237117 .plus => {
......@@ -6943,12 +7137,12 @@ fn unExpr(p: *Parser) Error!Result {
69437137 try p.errStr(.invalid_argument_un, tok, try p.typeStr(operand.ty));
69447138
69457139 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)) {
69477141 _ = try operand.val.sub(Value.zero, operand.val, operand.ty, p.comp);
69487142 } else {
69497143 operand.val = .{};
69507144 }
6951 try operand.un(p, .negate_expr);
7145 try operand.un(p, .negate_expr, tok);
69527146 return operand;
69537147 },
69547148 .plus_plus => {
......@@ -6974,7 +7168,7 @@ fn unExpr(p: *Parser) Error!Result {
69747168 operand.val = .{};
69757169 }
69767170
6977 try operand.un(p, .pre_inc_expr);
7171 try operand.un(p, .pre_inc_expr, tok);
69787172 return operand;
69797173 },
69807174 .minus_minus => {
......@@ -7000,7 +7194,7 @@ fn unExpr(p: *Parser) Error!Result {
70007194 operand.val = .{};
70017195 }
70027196
7003 try operand.un(p, .pre_dec_expr);
7197 try operand.un(p, .pre_dec_expr, tok);
70047198 return operand;
70057199 },
70067200 .tilde => {
......@@ -7016,11 +7210,14 @@ fn unExpr(p: *Parser) Error!Result {
70167210 }
70177211 } else if (operand.ty.isComplex()) {
70187212 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 }
70197216 } else {
70207217 try p.errStr(.invalid_argument_un, tok, try p.typeStr(operand.ty));
70217218 operand.val = .{};
70227219 }
7023 try operand.un(p, .bit_not_expr);
7220 try operand.un(p, .bit_not_expr, tok);
70247221 return operand;
70257222 },
70267223 .bang => {
......@@ -7045,7 +7242,7 @@ fn unExpr(p: *Parser) Error!Result {
70457242 }
70467243 }
70477244 operand.ty = .{ .specifier = .int };
7048 try operand.un(p, .bool_not_expr);
7245 try operand.un(p, .bool_not_expr, tok);
70497246 return operand;
70507247 },
70517248 .keyword_sizeof => {
......@@ -7089,7 +7286,7 @@ fn unExpr(p: *Parser) Error!Result {
70897286 res.ty = p.comp.types.size;
70907287 }
70917288 }
7092 try res.un(p, .sizeof_expr);
7289 try res.un(p, .sizeof_expr, tok);
70937290 return res;
70947291 },
70957292 .keyword_alignof,
......@@ -7127,7 +7324,7 @@ fn unExpr(p: *Parser) Error!Result {
71277324 try p.errStr(.invalid_alignof, expected_paren, try p.typeStr(res.ty));
71287325 res.ty = Type.invalid;
71297326 }
7130 try res.un(p, .alignof_expr);
7327 try res.un(p, .alignof_expr, tok);
71317328 return res;
71327329 },
71337330 .keyword_extension => {
......@@ -7147,15 +7344,18 @@ fn unExpr(p: *Parser) Error!Result {
71477344 var operand = try p.castExpr();
71487345 try operand.expect(p);
71497346 try operand.lvalConversion(p);
7347 if (operand.ty.is(.invalid)) return Result.invalid;
71507348 if (!operand.ty.isInt() and !operand.ty.isFloat()) {
71517349 try p.errStr(.invalid_imag, imag_tok, try p.typeStr(operand.ty));
71527350 }
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()) {
71547354 switch (p.comp.langopts.emulate) {
71557355 .msvc => {}, // Doesn't support `_Complex` or `__imag` in the first place
71567356 .gcc => operand.val = Value.zero,
71577357 .clang => {
7158 if (operand.val.is(.int, p.comp)) {
7358 if (operand.val.is(.int, p.comp) or operand.val.is(.float, p.comp)) {
71597359 operand.val = Value.zero;
71607360 } else {
71617361 operand.val = .{};
......@@ -7165,7 +7365,7 @@ fn unExpr(p: *Parser) Error!Result {
71657365 }
71667366 // convert _Complex T to T
71677367 operand.ty = operand.ty.makeReal();
7168 try operand.un(p, .imag_expr);
7368 try operand.un(p, .imag_expr, tok);
71697369 return operand;
71707370 },
71717371 .keyword_real1, .keyword_real2 => {
......@@ -7175,12 +7375,14 @@ fn unExpr(p: *Parser) Error!Result {
71757375 var operand = try p.castExpr();
71767376 try operand.expect(p);
71777377 try operand.lvalConversion(p);
7378 if (operand.ty.is(.invalid)) return Result.invalid;
71787379 if (!operand.ty.isInt() and !operand.ty.isFloat()) {
71797380 try p.errStr(.invalid_real, real_tok, try p.typeStr(operand.ty));
71807381 }
71817382 // convert _Complex T to T
71827383 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);
71847386 return operand;
71857387 },
71867388 else => {
......@@ -7253,7 +7455,7 @@ fn compoundLiteral(p: *Parser) Error!Result {
72537455 if (d.constexpr) |_| {
72547456 // TODO error if not constexpr
72557457 }
7256 try init_list_expr.un(p, tag);
7458 try init_list_expr.un(p, tag, l_paren);
72577459 return init_list_expr;
72587460}
72597461
......@@ -7284,7 +7486,7 @@ fn suffixExpr(p: *Parser, lhs: Result) Error!Result {
72847486 }
72857487 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);
72887490 return operand;
72897491 },
72907492 .minus_minus => {
......@@ -7302,7 +7504,7 @@ fn suffixExpr(p: *Parser, lhs: Result) Error!Result {
73027504 }
73037505 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);
73067508 return operand;
73077509 },
73087510 .l_bracket => {
......@@ -7319,12 +7521,18 @@ fn suffixExpr(p: *Parser, lhs: Result) Error!Result {
73197521 try index.lvalConversion(p);
73207522 if (ptr.ty.isPtr()) {
73217523 ptr.ty = ptr.ty.elemType();
7322 if (!index.ty.isInt()) try p.errTok(.invalid_index, l_bracket);
7323 try p.checkArrayBounds(index_before_conversion, array_before_conversion, l_bracket);
7524 if (index.ty.isInt()) {
7525 try p.checkArrayBounds(index_before_conversion, array_before_conversion, l_bracket);
7526 } else {
7527 try p.errTok(.invalid_index, l_bracket);
7528 }
73247529 } else if (index.ty.isPtr()) {
73257530 index.ty = index.ty.elemType();
7326 if (!ptr.ty.isInt()) try p.errTok(.invalid_index, l_bracket);
7327 try p.checkArrayBounds(array_before_conversion, index_before_conversion, l_bracket);
7531 if (ptr.ty.isInt()) {
7532 try p.checkArrayBounds(array_before_conversion, index_before_conversion, l_bracket);
7533 } else {
7534 try p.errTok(.invalid_index, l_bracket);
7535 }
73287536 std.mem.swap(Result, &ptr, &index);
73297537 } else {
73307538 try p.errTok(.invalid_subscript, l_bracket);
......@@ -7332,7 +7540,7 @@ fn suffixExpr(p: *Parser, lhs: Result) Error!Result {
73327540
73337541 try ptr.saveValue(p);
73347542 try index.saveValue(p);
7335 try ptr.bin(p, .array_access_expr, index);
7543 try ptr.bin(p, .array_access_expr, index, l_bracket);
73367544 return ptr;
73377545 },
73387546 .period => {
......@@ -7364,16 +7572,12 @@ fn fieldAccess(
73647572 const expr_ty = lhs.ty;
73657573 const is_ptr = expr_ty.isPtr();
73667574 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) {
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()) {
7580 if (record_ty.isIncomplete()) {
73777581 try p.errStr(.deref_incomplete_ty_ptr, field_name_tok - 2, try p.typeStr(expr_base_ty));
73787582 return error.ParsingFailed;
73797583 }
......@@ -7386,7 +7590,7 @@ fn fieldAccess(
73867590 return p.fieldAccessExtra(lhs.node, record_ty, field_name, is_arrow, &discard);
73877591}
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 {
73907594 if (record_ty.hasField(field_name)) return;
73917595
73927596 p.strings.items.len = 0;
......@@ -7401,8 +7605,8 @@ fn validateFieldAccess(p: *Parser, record_ty: Type, expr_ty: Type, field_name_to
74017605 return error.ParsingFailed;
74027606}
74037607
7404fn fieldAccessExtra(p: *Parser, lhs: NodeIndex, record_ty: Type, field_name: StringId, is_arrow: bool, offset_bits: *u64) Error!Result {
7405 for (record_ty.data.record.fields, 0..) |f, i| {
7608fn fieldAccessExtra(p: *Parser, lhs: NodeIndex, record_ty: *const Type.Record, field_name: StringId, is_arrow: bool, offset_bits: *u64) Error!Result {
7609 for (record_ty.fields, 0..) |f, i| {
74067610 if (f.isAnonymousRecord()) {
74077611 if (!f.ty.hasField(field_name)) continue;
74087612 const inner = try p.addNode(.{
......@@ -7410,7 +7614,7 @@ fn fieldAccessExtra(p: *Parser, lhs: NodeIndex, record_ty: Type, field_name: Str
74107614 .ty = f.ty,
74117615 .data = .{ .member = .{ .lhs = lhs, .index = @intCast(i) } },
74127616 });
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);
74147618 offset_bits.* = f.layout.offset_bits;
74157619 return ret;
74167620 }
......@@ -7527,6 +7731,23 @@ fn callExpr(p: *Parser, lhs: Result) Error!Result {
75277731 continue;
75287732 }
75297733 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
75307751 if (call_expr.shouldCoerceArg(arg_count)) {
75317752 try arg.coerce(p, p_ty, param_tok, .{ .arg = params[arg_count].name_tok });
75327753 }
......@@ -7618,7 +7839,7 @@ fn primaryExpr(p: *Parser) Error!Result {
76187839 var e = try p.expr();
76197840 try e.expect(p);
76207841 try p.expectClosing(l_paren, .r_paren);
7621 try e.un(p, .paren_expr);
7842 try e.un(p, .paren_expr, l_paren);
76227843 return e;
76237844 }
76247845 switch (p.tok_ids[p.tok_i]) {
......@@ -7626,6 +7847,10 @@ fn primaryExpr(p: *Parser) Error!Result {
76267847 const name_tok = try p.expectIdentifier();
76277848 const name = p.tokSlice(name_tok);
76287849 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 }
76297854 if (p.syms.findSymbol(interned_name)) |sym| {
76307855 try p.checkDeprecatedUnavailable(sym.ty, name_tok, sym.tok);
76317856 if (sym.kind == .constexpr) {
......@@ -7636,6 +7861,7 @@ fn primaryExpr(p: *Parser) Error!Result {
76367861 .tag = .decl_ref_expr,
76377862 .ty = sym.ty,
76387863 .data = .{ .decl_ref = name_tok },
7864 .loc = @enumFromInt(name_tok),
76397865 }),
76407866 };
76417867 }
......@@ -7653,6 +7879,7 @@ fn primaryExpr(p: *Parser) Error!Result {
76537879 .tag = if (sym.kind == .enumeration) .enumeration_ref else .decl_ref_expr,
76547880 .ty = sym.ty,
76557881 .data = .{ .decl_ref = name_tok },
7882 .loc = @enumFromInt(name_tok),
76567883 }),
76577884 };
76587885 }
......@@ -7679,6 +7906,7 @@ fn primaryExpr(p: *Parser) Error!Result {
76797906 .tag = .builtin_call_expr_one,
76807907 .ty = some.ty,
76817908 .data = .{ .decl = .{ .name = name_tok, .node = .none } },
7909 .loc = @enumFromInt(name_tok),
76827910 }),
76837911 };
76847912 }
......@@ -7696,6 +7924,7 @@ fn primaryExpr(p: *Parser) Error!Result {
76967924 .ty = ty,
76977925 .tag = .fn_proto,
76987926 .data = .{ .decl = .{ .name = name_tok } },
7927 .loc = @enumFromInt(name_tok),
76997928 });
77007929
77017930 try p.decl_buf.append(node);
......@@ -7707,6 +7936,7 @@ fn primaryExpr(p: *Parser) Error!Result {
77077936 .tag = .decl_ref_expr,
77087937 .ty = ty,
77097938 .data = .{ .decl_ref = name_tok },
7939 .loc = @enumFromInt(name_tok),
77107940 }),
77117941 };
77127942 }
......@@ -7714,11 +7944,12 @@ fn primaryExpr(p: *Parser) Error!Result {
77147944 return error.ParsingFailed;
77157945 },
77167946 .keyword_true, .keyword_false => |id| {
7947 const tok_i = p.tok_i;
77177948 p.tok_i += 1;
77187949 const res = Result{
77197950 .val = Value.fromBool(id == .keyword_true),
77207951 .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) }),
77227953 };
77237954 std.debug.assert(!p.in_macro); // Should have been replaced with .one / .zero
77247955 try p.value_map.put(res.node, res.val);
......@@ -7734,6 +7965,7 @@ fn primaryExpr(p: *Parser) Error!Result {
77347965 .tag = .nullptr_literal,
77357966 .ty = .{ .specifier = .nullptr_t },
77367967 .data = undefined,
7968 .loc = @enumFromInt(p.tok_i),
77377969 }),
77387970 };
77397971 },
......@@ -7770,6 +8002,7 @@ fn primaryExpr(p: *Parser) Error!Result {
77708002 .tag = .decl_ref_expr,
77718003 .ty = ty,
77728004 .data = .{ .decl_ref = tok },
8005 .loc = @enumFromInt(tok),
77738006 }),
77748007 };
77758008 },
......@@ -7805,6 +8038,7 @@ fn primaryExpr(p: *Parser) Error!Result {
78058038 .tag = .decl_ref_expr,
78068039 .ty = ty,
78078040 .data = .{ .decl_ref = p.tok_i },
8041 .loc = @enumFromInt(p.tok_i),
78088042 }),
78098043 };
78108044 },
......@@ -7824,16 +8058,16 @@ fn primaryExpr(p: *Parser) Error!Result {
78248058 .unterminated_char_literal,
78258059 => return p.charLiteral(),
78268060 .zero => {
7827 p.tok_i += 1;
8061 defer p.tok_i += 1;
78288062 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) });
78308064 if (!p.in_macro) try p.value_map.put(res.node, res.val);
78318065 return res;
78328066 },
78338067 .one => {
7834 p.tok_i += 1;
8068 defer p.tok_i += 1;
78358069 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) });
78378071 if (!p.in_macro) try p.value_map.put(res.node, res.val);
78388072 return res;
78398073 },
......@@ -7841,7 +8075,7 @@ fn primaryExpr(p: *Parser) Error!Result {
78418075 .embed_byte => {
78428076 assert(!p.in_macro);
78438077 const loc = p.pp.tokens.items(.loc)[p.tok_i];
7844 p.tok_i += 1;
8078 defer p.tok_i += 1;
78458079 const buf = p.comp.getSource(.generated).buf[loc.byte_offset..];
78468080 var byte: u8 = buf[0] - '0';
78478081 for (buf[1..]) |c| {
......@@ -7850,7 +8084,7 @@ fn primaryExpr(p: *Parser) Error!Result {
78508084 byte += c - '0';
78518085 }
78528086 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) });
78548088 try p.value_map.put(res.node, res.val);
78558089 return res;
78568090 },
......@@ -7869,17 +8103,19 @@ fn makePredefinedIdentifier(p: *Parser, strings_top: usize) !Result {
78698103 const slice = p.strings.items[strings_top..];
78708104 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) });
78738107 if (!p.in_macro) try p.value_map.put(str_lit, val);
78748108
78758109 return Result{ .ty = ty, .node = try p.addNode(.{
78768110 .tag = .implicit_static_var,
78778111 .ty = ty,
78788112 .data = .{ .decl = .{ .name = p.tok_i, .node = str_lit } },
8113 .loc = @enumFromInt(p.tok_i),
78798114 }) };
78808115}
78818116
78828117fn stringLiteral(p: *Parser) Error!Result {
8118 const string_start = p.tok_i;
78838119 var string_end = p.tok_i;
78848120 var string_kind: text_literal.Kind = .char;
78858121 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 {
78948130 return error.ParsingFailed;
78958131 }
78968132 }
7897 assert(string_end > p.tok_i);
8133 const count = string_end - p.tok_i;
8134 assert(count > 0);
78988135
78998136 const char_width = string_kind.charUnitSize(p.comp);
79008137
79018138 const strings_top = p.strings.items.len;
79028139 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
79048144 while (p.tok_i < string_end) : (p.tok_i += 1) {
79058145 const this_kind = text_literal.Kind.classify(p.tok_ids[p.tok_i], .string_literal).?;
79068146 const slice = this_kind.contentSlice(p.tokSlice(p.tok_i));
......@@ -7940,12 +8180,18 @@ fn stringLiteral(p: *Parser) Error!Result {
79408180 },
79418181 }
79428182 },
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 },
79448190 .utf8_text => |view| {
79458191 switch (char_width) {
79468192 .@"1" => p.strings.appendSliceAssumeCapacity(view.bytes),
79478193 .@"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..]);
79498195 const dest_len = std.mem.alignBackward(usize, capacity_slice.len, 2);
79508196 const dest = std.mem.bytesAsSlice(u16, capacity_slice[0..dest_len]);
79518197 const words_written = std.unicode.utf8ToUtf16Le(dest, view.bytes) catch unreachable;
......@@ -7966,7 +8212,7 @@ fn stringLiteral(p: *Parser) Error!Result {
79668212 }
79678213 }
79688214 p.strings.appendNTimesAssumeCapacity(0, @intFromEnum(char_width));
7969 const slice = p.strings.items[strings_top..];
8215 const slice = p.strings.items[literal_start..];
79708216
79718217 // TODO this won't do anything if there is a cache hit
79728218 const interned_align = mem.alignForward(
......@@ -7987,7 +8233,7 @@ fn stringLiteral(p: *Parser) Error!Result {
79878233 },
79888234 .val = val,
79898235 };
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) });
79918237 if (!p.in_macro) try p.value_map.put(res.node, res.val);
79928238 return res;
79938239}
......@@ -8004,7 +8250,7 @@ fn charLiteral(p: *Parser) Error!Result {
80048250 return .{
80058251 .ty = Type.int,
80068252 .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) }),
80088254 };
80098255 };
80108256 if (char_kind == .utf_8) try p.err(.u8_char_lit);
......@@ -8013,7 +8259,7 @@ fn charLiteral(p: *Parser) Error!Result {
80138259 const slice = char_kind.contentSlice(p.tokSlice(p.tok_i));
80148260
80158261 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])) {
80178263 // fast path: single unescaped ASCII char
80188264 val = slice[0];
80198265 } else {
......@@ -8096,25 +8342,25 @@ fn charLiteral(p: *Parser) Error!Result {
80968342 // > that of the single character or escape sequence is converted to type int.
80978343 // This conversion only matters if `char` is signed and has a high-order bit of `1`
80988344 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);
81008346 }
81018347
81028348 const res = Result{
81038349 .ty = if (p.in_macro) macro_ty else ty,
81048350 .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) }),
81068352 };
81078353 if (!p.in_macro) try p.value_map.put(res.node, res.val);
81088354 return res;
81098355}
81108356
8111fn parseFloat(p: *Parser, buf: []const u8, suffix: NumberSuffix) !Result {
8357fn parseFloat(p: *Parser, buf: []const u8, suffix: NumberSuffix, tok_i: TokenIndex) !Result {
81128358 const ty = Type{ .specifier = switch (suffix) {
81138359 .None, .I => .double,
81148360 .F, .IF => .float,
8115 .F16 => .float16,
8361 .F16, .IF16 => .float16,
81168362 .L, .IL => .long_double,
8117 .W, .IW => .float80,
8363 .W, .IW => p.comp.float80Type().?.specifier,
81188364 .Q, .IQ, .F128, .IF128 => .float128,
81198365 else => unreachable,
81208366 } };
......@@ -8140,21 +8386,29 @@ fn parseFloat(p: *Parser, buf: []const u8, suffix: NumberSuffix) !Result {
81408386 });
81418387 var res = Result{
81428388 .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) }),
81448390 .val = val,
81458391 };
81468392 if (suffix.isImaginary()) {
81478393 try p.err(.gnu_imaginary_constant);
81488394 res.ty = .{ .specifier = switch (suffix) {
81498395 .I => .complex_double,
8396 .IF16 => .complex_float16,
81508397 .IF => .complex_float,
81518398 .IL => .complex_long_double,
8152 .IW => .complex_float80,
8399 .IW => p.comp.float80Type().?.makeComplex().specifier,
81538400 .IQ, .IF128 => .complex_float128,
81548401 else => unreachable,
81558402 } };
8156 res.val = .{}; // TODO add complex values
8157 try res.un(p, .imaginary_literal);
8403 res.val = try Value.intern(p.comp, switch (res.ty.bitSizeof(p.comp).?) {
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);
81588412 }
81598413 return res;
81608414}
......@@ -8233,12 +8487,14 @@ fn fixedSizeInt(p: *Parser, base: u8, buf: []const u8, suffix: NumberSuffix, tok
82338487 if (overflow) {
82348488 try p.errTok(.int_literal_too_big, tok_i);
82358489 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) });
82378491 if (!p.in_macro) try p.value_map.put(res.node, res.val);
82388492 return res;
82398493 }
8494 const interned_val = try Value.int(val, p.comp);
82408495 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)) {
82428498 try p.errTok(.implicitly_unsigned_literal, tok_i);
82438499 }
82448500 }
......@@ -8266,13 +8522,23 @@ fn fixedSizeInt(p: *Parser, base: u8, buf: []const u8, suffix: NumberSuffix, tok
82668522 for (specs) |spec| {
82678523 res.ty = Type{ .specifier = spec };
82688524 if (res.ty.compareIntegerRanks(suffix_ty, p.comp).compare(.lt)) continue;
8269 const max_int = res.ty.maxInt(p.comp);
8270 if (val <= max_int) break;
8525 const max_int = try Value.maxInt(res.ty, p.comp);
8526 if (interned_val.compare(.lte, max_int, p.comp)) break;
82718527 } 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 } };
82738539 }
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) });
82768542 if (!p.in_macro) try p.value_map.put(res.node, res.val);
82778543 return res;
82788544}
......@@ -8291,7 +8557,7 @@ fn parseInt(p: *Parser, prefix: NumberPrefix, buf: []const u8, suffix: NumberSuf
82918557 try p.errTok(.gnu_imaginary_constant, tok_i);
82928558 res.ty = res.ty.makeComplex();
82938559 res.val = .{};
8294 try res.un(p, .imaginary_literal);
8560 try res.un(p, .imaginary_literal, tok_i);
82958561 }
82968562 return res;
82978563}
......@@ -8326,17 +8592,6 @@ fn bitInt(p: *Parser, base: u8, buf: []const u8, suffix: NumberSuffix, tok_i: To
83268592 // value of the constant is positive or was specified in hexadecimal or octal notation.
83278593 const sign_bits = @intFromBool(suffix.isSignedInteger());
83288594 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 }
83408595 break :blk @intCast(bits_needed);
83418596 };
83428597
......@@ -8347,7 +8602,7 @@ fn bitInt(p: *Parser, base: u8, buf: []const u8, suffix: NumberSuffix, tok_i: To
83478602 .data = .{ .int = .{ .bits = bits_needed, .signedness = suffix.signedness() } },
83488603 },
83498604 };
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) });
83518606 if (!p.in_macro) try p.value_map.put(res.node, res.val);
83528607 return res;
83538608}
......@@ -8420,6 +8675,10 @@ pub fn parseNumberToken(p: *Parser, tok_i: TokenIndex) !Result {
84208675 }
84218676 return error.ParsingFailed;
84228677 };
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
84248683 if (is_float) {
84258684 assert(prefix == .hex or prefix == .decimal);
......@@ -8428,7 +8687,7 @@ pub fn parseNumberToken(p: *Parser, tok_i: TokenIndex) !Result {
84288687 return error.ParsingFailed;
84298688 }
84308689 const number = buf[0 .. buf.len - suffix_str.len];
8431 return p.parseFloat(number, suffix);
8690 return p.parseFloat(number, suffix, tok_i);
84328691 } else {
84338692 return p.parseInt(prefix, int_part, suffix, tok_i);
84348693 }
......@@ -8444,7 +8703,6 @@ fn ppNum(p: *Parser) Error!Result {
84448703 }
84458704 res.ty = if (res.ty.isUnsignedInt(p.comp)) p.comp.types.intmax.makeIntegerUnsigned() else p.comp.types.intmax;
84468705 } else if (res.val.opt_ref != .none) {
8447 // TODO add complex values
84488706 try p.value_map.put(res.node, res.val);
84498707 }
84508708 return res;
......@@ -8465,6 +8723,7 @@ fn parseNoEval(p: *Parser, comptime func: fn (*Parser) Error!Result) Error!Resul
84658723/// : typeName ':' assignExpr
84668724/// | keyword_default ':' assignExpr
84678725fn genericSelection(p: *Parser) Error!Result {
8726 const kw_generic = p.tok_i;
84688727 p.tok_i += 1;
84698728 const l_paren = try p.expectToken(.l_paren);
84708729 const controlling_tok = p.tok_i;
......@@ -8508,17 +8767,23 @@ fn genericSelection(p: *Parser) Error!Result {
85088767 try p.errStr(.generic_duplicate, start, try p.typeStr(ty));
85098768 try p.errStr(.generic_duplicate_here, chosen_tok, try p.typeStr(ty));
85108769 }
8511 for (p.list_buf.items[list_buf_top + 1 ..], p.decl_buf.items[decl_buf_top..]) |item, prev_tok| {
8512 const prev_ty = p.nodes.items(.ty)[@intFromEnum(item)];
8513 if (prev_ty.eql(ty, p.comp, true)) {
8514 try p.errStr(.generic_duplicate, start, try p.typeStr(ty));
8515 try p.errStr(.generic_duplicate_here, @intFromEnum(prev_tok), try p.typeStr(ty));
8770 const list_buf = p.list_buf.items[list_buf_top + 1 ..];
8771 const decl_buf = p.decl_buf.items[decl_buf_top..];
8772 if (list_buf.len == decl_buf.len) {
8773 // If these do not have the same length, there is already an error
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 }
85168780 }
85178781 }
85188782 try p.list_buf.append(try p.addNode(.{
85198783 .tag = .generic_association_expr,
85208784 .ty = ty,
85218785 .data = .{ .un = node.node },
8786 .loc = @enumFromInt(start),
85228787 }));
85238788 try p.decl_buf.append(@enumFromInt(start));
85248789 } else if (p.eatToken(.keyword_default)) |tok| {
......@@ -8542,10 +8807,12 @@ fn genericSelection(p: *Parser) Error!Result {
85428807 try p.expectClosing(l_paren, .r_paren);
85438808
85448809 if (chosen.node == .none) {
8545 if (default_tok != null) {
8810 if (default_tok) |tok| {
85468811 try p.list_buf.insert(list_buf_top + 1, try p.addNode(.{
85478812 .tag = .generic_default_expr,
85488813 .data = .{ .un = default.node },
8814 .ty = default.ty,
8815 .loc = @enumFromInt(tok),
85498816 }));
85508817 chosen = default;
85518818 } else {
......@@ -8556,11 +8823,15 @@ fn genericSelection(p: *Parser) Error!Result {
85568823 try p.list_buf.insert(list_buf_top + 1, try p.addNode(.{
85578824 .tag = .generic_association_expr,
85588825 .data = .{ .un = chosen.node },
8826 .ty = chosen.ty,
8827 .loc = @enumFromInt(chosen_tok),
85598828 }));
8560 if (default_tok != null) {
8829 if (default_tok) |tok| {
85618830 try p.list_buf.append(try p.addNode(.{
85628831 .tag = .generic_default_expr,
8563 .data = .{ .un = chosen.node },
8832 .data = .{ .un = default.node },
8833 .ty = default.ty,
8834 .loc = @enumFromInt(tok),
85648835 }));
85658836 }
85668837 }
......@@ -8568,7 +8839,8 @@ fn genericSelection(p: *Parser) Error!Result {
85688839 var generic_node: Tree.Node = .{
85698840 .tag = .generic_expr_one,
85708841 .ty = chosen.ty,
8571 .data = .{ .bin = .{ .lhs = controlling.node, .rhs = chosen.node } },
8842 .data = .{ .two = .{ controlling.node, chosen.node } },
8843 .loc = @enumFromInt(kw_generic),
85728844 };
85738845 const associations = p.list_buf.items[list_buf_top..];
85748846 if (associations.len > 2) { // associations[0] == controlling.node
......@@ -8578,3 +8850,42 @@ fn genericSelection(p: *Parser) Error!Result {
85788850 chosen.node = try p.addNode(generic_node);
85798851 return chosen;
85808852}
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),
9797/// Map from Source.Id to macro name in the `#ifndef` condition which guards the source, if any
9898include_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
100105/// Memory is retained to avoid allocation on every single token.
101106top_expansion_buf: ExpandBuf,
102107
......@@ -622,9 +627,12 @@ fn preprocessExtra(pp: *Preprocessor, source: Source) MacroError!TokenWithExpans
622627 }
623628 if_level -= 1;
624629 },
625 .keyword_define => try pp.define(&tokenizer),
630 .keyword_define => try pp.define(&tokenizer, directive),
626631 .keyword_undef => {
627632 const macro_name = (try pp.expectMacroName(&tokenizer)) orelse continue;
633 if (pp.store_macro_tokens) {
634 try pp.addToken(tokFromRaw(directive));
635 }
628636
629637 _ = pp.defines.remove(macro_name);
630638 try pp.expectNl(&tokenizer);
......@@ -975,7 +983,7 @@ fn expr(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!bool {
975983 .tok_i = @intCast(token_state.tokens_len),
976984 .arena = pp.arena.allocator(),
977985 .in_macro = true,
978 .strings = std.ArrayList(u8).init(pp.comp.gpa),
986 .strings = std.ArrayListAligned(u8, 4).init(pp.comp.gpa),
979987
980988 .data = undefined,
981989 .value_map = undefined,
......@@ -1328,19 +1336,41 @@ fn stringify(pp: *Preprocessor, tokens: []const TokenWithExpansionLocs) !void {
13281336 try pp.char_buf.append(c);
13291337 }
13301338 }
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) {
13321354 const tok = tokens[tokens.len - 1];
13331355 try pp.comp.addDiagnostic(.{
13341356 .tag = .invalid_pp_stringify_escape,
13351357 .loc = tok.loc,
13361358 }, 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('"');
13381361 }
1339 try pp.char_buf.appendSlice("\"\n");
1362 pp.char_buf.appendAssumeCapacity('\n');
13401363}
13411364
13421365fn 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
13441374 const char_top = pp.char_buf.items.len;
13451375 defer pp.char_buf.items.len = char_top;
13461376
......@@ -1539,11 +1569,13 @@ fn getPasteArgs(args: []const TokenWithExpansionLocs) []const TokenWithExpansion
15391569
15401570fn expandFuncMacro(
15411571 pp: *Preprocessor,
1542 loc: Source.Location,
1572 macro_tok: TokenWithExpansionLocs,
15431573 func_macro: *const Macro,
15441574 args: *const MacroArguments,
15451575 expanded_args: *const MacroArguments,
1576 hideset_arg: Hideset.Index,
15461577) MacroError!ExpandBuf {
1578 var hideset = hideset_arg;
15471579 var buf = ExpandBuf.init(pp.gpa);
15481580 try buf.ensureTotalCapacity(func_macro.tokens.len);
15491581 errdefer buf.deinit();
......@@ -1594,16 +1626,21 @@ fn expandFuncMacro(
15941626 },
15951627 else => &[1]TokenWithExpansionLocs{tokFromRaw(raw_next)},
15961628 };
1597
15981629 try pp.pasteTokens(&buf, next);
15991630 if (next.len != 0) break;
16001631 },
16011632 .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 }
16021636 const slice = getPasteArgs(args.items[raw.end]);
16031637 const raw_loc = Source.Location{ .id = raw.source, .byte_offset = raw.start, .line = raw.line };
16041638 try bufCopyTokens(&buf, slice, &.{raw_loc});
16051639 },
16061640 .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 }
16071644 const arg = expanded_args.items[raw.end];
16081645 const raw_loc = Source.Location{ .id = raw.source, .byte_offset = raw.start, .line = raw.line };
16091646 try bufCopyTokens(&buf, arg, &.{raw_loc});
......@@ -1642,9 +1679,9 @@ fn expandFuncMacro(
16421679 const arg = expanded_args.items[0];
16431680 const result = if (arg.len == 0) blk: {
16441681 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 }, &.{});
16461683 break :blk false;
1647 } else try pp.handleBuiltinMacro(raw.id, arg, loc);
1684 } else try pp.handleBuiltinMacro(raw.id, arg, macro_tok.loc);
16481685 const start = pp.comp.generated_buf.items.len;
16491686 const w = pp.comp.generated_buf.writer(pp.gpa);
16501687 try w.print("{}\n", .{@intFromBool(result)});
......@@ -1655,7 +1692,7 @@ fn expandFuncMacro(
16551692 const not_found = "0\n";
16561693 const result = if (arg.len == 0) blk: {
16571694 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 }, &.{});
16591696 break :blk not_found;
16601697 } else res: {
16611698 var invalid: ?TokenWithExpansionLocs = null;
......@@ -1687,7 +1724,7 @@ fn expandFuncMacro(
16871724 if (vendor_ident != null and attr_ident == null) {
16881725 invalid = vendor_ident;
16891726 } else if (attr_ident == null and invalid == null) {
1690 invalid = .{ .id = .eof, .loc = loc };
1727 invalid = .{ .id = .eof, .loc = macro_tok.loc };
16911728 }
16921729 if (invalid) |some| {
16931730 try pp.comp.addDiagnostic(
......@@ -1731,7 +1768,7 @@ fn expandFuncMacro(
17311768 const not_found = "0\n";
17321769 const result = if (arg.len == 0) blk: {
17331770 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 }, &.{});
17351772 break :blk not_found;
17361773 } else res: {
17371774 var embed_args: []const TokenWithExpansionLocs = &.{};
......@@ -1877,11 +1914,11 @@ fn expandFuncMacro(
18771914 break;
18781915 },
18791916 };
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 };
18811918 if (invalid) |some| try pp.comp.addDiagnostic(
18821919 .{ .tag = .pragma_operator_string_literal, .loc = some.loc },
18831920 some.expansionSlice(),
1884 ) else try pp.pragmaOperator(string.?, loc);
1921 ) else try pp.pragmaOperator(string.?, macro_tok.loc);
18851922 },
18861923 .comma => {
18871924 if (tok_i + 2 < func_macro.tokens.len and func_macro.tokens[tok_i + 1].id == .hash_hash) {
......@@ -1930,6 +1967,15 @@ fn expandFuncMacro(
19301967 }
19311968 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
19331979 return buf;
19341980}
19351981
......@@ -2207,8 +2253,10 @@ fn expandMacroExhaustive(
22072253 else => |e| return e,
22082254 };
22092255 assert(r_paren.id == .r_paren);
2256 var free_arg_expansion_locs = false;
22102257 defer {
22112258 for (args.items) |item| {
2259 if (free_arg_expansion_locs) for (item) |tok| TokenWithExpansionLocs.free(tok.expansion_locs, pp.gpa);
22122260 pp.gpa.free(item);
22132261 }
22142262 args.deinit();
......@@ -2234,6 +2282,7 @@ fn expandMacroExhaustive(
22342282 .arguments = .{ .expected = @intCast(macro.params.len), .actual = args_count },
22352283 };
22362284 if (macro.var_args and args_count < macro.params.len) {
2285 free_arg_expansion_locs = true;
22372286 try pp.comp.addDiagnostic(
22382287 .{ .tag = .expected_at_least_arguments, .loc = buf.items[idx].loc, .extra = extra },
22392288 buf.items[idx].expansionSlice(),
......@@ -2243,6 +2292,7 @@ fn expandMacroExhaustive(
22432292 continue;
22442293 }
22452294 if (!macro.var_args and args_count != macro.params.len) {
2295 free_arg_expansion_locs = true;
22462296 try pp.comp.addDiagnostic(
22472297 .{ .tag = .expected_arguments, .loc = buf.items[idx].loc, .extra = extra },
22482298 buf.items[idx].expansionSlice(),
......@@ -2264,19 +2314,9 @@ fn expandMacroExhaustive(
22642314 expanded_args.appendAssumeCapacity(try expand_buf.toOwnedSlice());
22652315 }
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);
22682318 defer res.deinit();
22692319 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
22802320 const tokens_removed = macro_scan_idx - idx + 1;
22812321 for (buf.items[idx .. idx + tokens_removed]) |tok| TokenWithExpansionLocs.free(tok.expansion_locs, pp.gpa);
22822322 try buf.replaceRange(idx, tokens_removed, res.items);
......@@ -2476,7 +2516,7 @@ fn makeGeneratedToken(pp: *Preprocessor, start: usize, id: Token.Id, source: Tok
24762516}
24772517
24782518/// 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 {
24802520 const name_str = pp.tokSlice(name_tok);
24812521 const gop = try pp.defines.getOrPut(pp.gpa, name_str);
24822522 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 {
24972537 if (pp.verbose) {
24982538 pp.verboseLog(name_tok, "macro {s} defined", .{name_str});
24992539 }
2540 if (pp.store_macro_tokens) {
2541 try pp.addToken(tokFromRaw(define_tok));
2542 }
25002543 gop.value_ptr.* = macro;
25012544}
25022545
25032546/// Handle a #define directive.
2504fn define(pp: *Preprocessor, tokenizer: *Tokenizer) Error!void {
2547fn define(pp: *Preprocessor, tokenizer: *Tokenizer, define_tok: RawToken) Error!void {
25052548 // Get macro name and validate it.
25062549 const macro_name = tokenizer.nextNoWS();
25072550 if (macro_name.id == .keyword_defined) {
......@@ -2524,7 +2567,7 @@ fn define(pp: *Preprocessor, tokenizer: *Tokenizer) Error!void {
25242567 // Check for function macros and empty defines.
25252568 var first = tokenizer.next();
25262569 switch (first.id) {
2527 .nl, .eof => return pp.defineMacro(macro_name, .{
2570 .nl, .eof => return pp.defineMacro(define_tok, macro_name, .{
25282571 .params = &.{},
25292572 .tokens = &.{},
25302573 .var_args = false,
......@@ -2532,7 +2575,7 @@ fn define(pp: *Preprocessor, tokenizer: *Tokenizer) Error!void {
25322575 .is_func = false,
25332576 }),
25342577 .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),
25362579 else => try pp.err(first, .whitespace_after_macro_name),
25372580 }
25382581 if (first.id == .hash_hash) {
......@@ -2591,7 +2634,7 @@ fn define(pp: *Preprocessor, tokenizer: *Tokenizer) Error!void {
25912634 }
25922635
25932636 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, .{
25952638 .loc = tokFromRaw(macro_name).loc,
25962639 .tokens = list,
25972640 .params = undefined,
......@@ -2601,7 +2644,7 @@ fn define(pp: *Preprocessor, tokenizer: *Tokenizer) Error!void {
26012644}
26022645
26032646/// 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 {
26052648 assert(macro_name.id.isMacroIdentifier());
26062649 var params = std.ArrayList([]const u8).init(pp.gpa);
26072650 defer params.deinit();
......@@ -2778,7 +2821,7 @@ fn defineFn(pp: *Preprocessor, tokenizer: *Tokenizer, macro_name: RawToken, l_pa
27782821
27792822 const param_list = try pp.arena.allocator().dupe([]const u8, params.items);
27802823 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, .{
27822825 .is_func = true,
27832826 .params = param_list,
27842827 .var_args = var_args or gnu_var_args.len != 0,
......@@ -3241,8 +3284,78 @@ fn printLinemarker(
32413284// After how many empty lines are needed to replace them with linemarkers.
32423285const 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
32443353/// 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
32463359 const tok_ids = pp.tokens.items(.id);
32473360
32483361 var i: u32 = 0;
......@@ -3334,6 +3447,17 @@ pub fn prettyPrintTokens(pp: *Preprocessor, w: anytype) !void {
33343447 try pp.printLinemarker(w, line_col.line_no, source, .@"resume");
33353448 last_nl = true;
33363449 },
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 },
33373461 else => {
33383462 const slice = pp.expandedSlice(cur);
33393463 try w.writeAll(slice);
......@@ -3350,7 +3474,7 @@ test "Preserve pragma tokens sometimes" {
33503474 var buf = std.ArrayList(u8).init(allocator);
33513475 defer buf.deinit();
33523476
3353 var comp = Compilation.init(allocator);
3477 var comp = Compilation.init(allocator, std.fs.cwd());
33543478 defer comp.deinit();
33553479
33563480 try comp.addDefaultPragmaHandlers();
......@@ -3364,7 +3488,7 @@ test "Preserve pragma tokens sometimes" {
33643488 const test_runner_macros = try comp.addSourceFromBuffer("<test_runner>", source_text);
33653489 const eof = try pp.preprocess(test_runner_macros);
33663490 try pp.addToken(eof);
3367 try pp.prettyPrintTokens(buf.writer());
3491 try pp.prettyPrintTokens(buf.writer(), .result_only);
33683492 return allocator.dupe(u8, buf.items);
33693493 }
33703494
......@@ -3410,7 +3534,7 @@ test "destringify" {
34103534 try std.testing.expectEqualStrings(destringified, pp.char_buf.items);
34113535 }
34123536 };
3413 var comp = Compilation.init(allocator);
3537 var comp = Compilation.init(allocator, std.fs.cwd());
34143538 defer comp.deinit();
34153539 var pp = Preprocessor.init(&comp);
34163540 defer pp.deinit();
......@@ -3468,7 +3592,7 @@ test "Include guards" {
34683592 }
34693593
34703594 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());
34723596 defer comp.deinit();
34733597 var pp = Preprocessor.init(&comp);
34743598 defer pp.deinit();
lib/compiler/aro/aro/Source.zig+11-1
......@@ -75,7 +75,17 @@ pub fn lineCol(source: Source, loc: Location) LineCol {
7575 i += 1;
7676 continue;
7777 };
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 {
7989 i += 1;
8090 continue;
8191 };
lib/compiler/aro/aro/SymbolStack.zig+11-4
......@@ -178,9 +178,11 @@ pub fn defineTypedef(
178178 if (s.get(name, .vars)) |prev| {
179179 switch (prev.kind) {
180180 .typedef => {
181 if (!ty.eql(prev.ty, p.comp, true)) {
182 try p.errStr(.redefinition_of_typedef, tok, try p.typePairStrExtra(ty, " vs ", prev.ty));
183 if (prev.tok != 0) try p.errTok(.previous_definition, prev.tok);
181 if (!prev.ty.is(.invalid)) {
182 if (!ty.eql(prev.ty, p.comp, true)) {
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 }
184186 }
185187 },
186188 .enumeration, .decl, .def, .constexpr => {
......@@ -194,7 +196,12 @@ pub fn defineTypedef(
194196 .kind = .typedef,
195197 .name = name,
196198 .tok = tok,
197 .ty = ty,
199 .ty = .{
200 .name = name,
201 .specifier = ty.specifier,
202 .qual = ty.qual,
203 .data = ty.data,
204 },
198205 .node = node,
199206 .val = .{},
200207 });
lib/compiler/aro/aro/Tokenizer.zig+43-13
......@@ -178,6 +178,8 @@ pub const Token = struct {
178178 keyword_return,
179179 keyword_short,
180180 keyword_signed,
181 keyword_signed1,
182 keyword_signed2,
181183 keyword_sizeof,
182184 keyword_static,
183185 keyword_struct,
......@@ -258,7 +260,6 @@ pub const Token = struct {
258260 keyword_asm,
259261 keyword_asm1,
260262 keyword_asm2,
261 keyword_float80,
262263 /// _Float128
263264 keyword_float128_1,
264265 /// __float128
......@@ -369,6 +370,8 @@ pub const Token = struct {
369370 .keyword_return,
370371 .keyword_short,
371372 .keyword_signed,
373 .keyword_signed1,
374 .keyword_signed2,
372375 .keyword_sizeof,
373376 .keyword_static,
374377 .keyword_struct,
......@@ -417,7 +420,6 @@ pub const Token = struct {
417420 .keyword_asm,
418421 .keyword_asm1,
419422 .keyword_asm2,
420 .keyword_float80,
421423 .keyword_float128_1,
422424 .keyword_float128_2,
423425 .keyword_int128,
......@@ -627,6 +629,8 @@ pub const Token = struct {
627629 .keyword_return => "return",
628630 .keyword_short => "short",
629631 .keyword_signed => "signed",
632 .keyword_signed1 => "__signed",
633 .keyword_signed2 => "__signed__",
630634 .keyword_sizeof => "sizeof",
631635 .keyword_static => "static",
632636 .keyword_struct => "struct",
......@@ -702,7 +706,6 @@ pub const Token = struct {
702706 .keyword_asm => "asm",
703707 .keyword_asm1 => "__asm",
704708 .keyword_asm2 => "__asm__",
705 .keyword_float80 => "__float80",
706709 .keyword_float128_1 => "_Float128",
707710 .keyword_float128_2 => "__float128",
708711 .keyword_int128 => "__int128",
......@@ -732,7 +735,8 @@ pub const Token = struct {
732735
733736 pub fn symbol(id: Id) []const u8 {
734737 return switch (id) {
735 .macro_string, .invalid => unreachable,
738 .macro_string => unreachable,
739 .invalid => "invalid bytes",
736740 .identifier,
737741 .extended_identifier,
738742 .macro_func,
......@@ -873,10 +877,7 @@ pub const Token = struct {
873877 }
874878
875879 const all_kws = std.StaticStringMap(Id).initComptime(.{
876 .{ "auto", auto: {
877 @setEvalBranchQuota(3000);
878 break :auto .keyword_auto;
879 } },
880 .{ "auto", .keyword_auto },
880881 .{ "break", .keyword_break },
881882 .{ "case", .keyword_case },
882883 .{ "char", .keyword_char },
......@@ -898,6 +899,8 @@ pub const Token = struct {
898899 .{ "return", .keyword_return },
899900 .{ "short", .keyword_short },
900901 .{ "signed", .keyword_signed },
902 .{ "__signed", .keyword_signed1 },
903 .{ "__signed__", .keyword_signed2 },
901904 .{ "sizeof", .keyword_sizeof },
902905 .{ "static", .keyword_static },
903906 .{ "struct", .keyword_struct },
......@@ -982,7 +985,6 @@ pub const Token = struct {
982985 .{ "asm", .keyword_asm },
983986 .{ "__asm", .keyword_asm1 },
984987 .{ "__asm__", .keyword_asm2 },
985 .{ "__float80", .keyword_float80 },
986988 .{ "_Float128", .keyword_float128_1 },
987989 .{ "__float128", .keyword_float128_2 },
988990 .{ "__int128", .keyword_int128 },
......@@ -1300,11 +1302,17 @@ pub fn next(self: *Tokenizer) Token {
13001302 else => {},
13011303 },
13021304 .char_escape_sequence => switch (c) {
1303 '\r', '\n' => unreachable, // removed by line splicing
1305 '\r', '\n' => {
1306 id = .unterminated_char_literal;
1307 break;
1308 },
13041309 else => state = .char_literal,
13051310 },
13061311 .string_escape_sequence => switch (c) {
1307 '\r', '\n' => unreachable, // removed by line splicing
1312 '\r', '\n' => {
1313 id = .unterminated_string_literal;
1314 break;
1315 },
13081316 else => state = .string_literal,
13091317 },
13101318 .identifier, .extended_identifier => switch (c) {
......@@ -1792,7 +1800,7 @@ pub fn nextNoWSComments(self: *Tokenizer) Token {
17921800/// Try to tokenize a '::' even if not supported by the current language standard.
17931801pub fn colonColon(self: *Tokenizer) Token {
17941802 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] == ':') {
17961804 self.index += 1;
17971805 tok.id = .colon_colon;
17981806 }
......@@ -2142,8 +2150,30 @@ test "C23 keywords" {
21422150 }, .c23);
21432151}
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
21452175fn 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());
21472177 defer comp.deinit();
21482178 if (standard) |provided| {
21492179 comp.langopts.standard = provided;
lib/compiler/aro/aro/Tree.zig+172-76
......@@ -137,15 +137,22 @@ pub const Node = struct {
137137 tag: Tag,
138138 ty: Type = .{ .specifier = .void },
139139 data: Data,
140 loc: Loc = .none,
140141
141142 pub const Range = struct { start: u32, end: u32 };
142143
144 pub const Loc = enum(u32) {
145 none = std.math.maxInt(u32),
146 _,
147 };
148
143149 pub const Data = union {
144150 decl: struct {
145151 name: TokenIndex,
146152 node: NodeIndex = .none,
147153 },
148154 decl_ref: TokenIndex,
155 two: [2]NodeIndex,
149156 range: Range,
150157 if3: struct {
151158 cond: NodeIndex,
......@@ -277,7 +284,8 @@ pub const Tag = enum(u8) {
277284
278285 // ====== Decl ======
279286
280 // _Static_assert
287 /// _Static_assert
288 /// loc is token index of _Static_assert
281289 static_assert,
282290
283291 // function prototype
......@@ -303,17 +311,18 @@ pub const Tag = enum(u8) {
303311 threadlocal_static_var,
304312
305313 /// __asm__("...") at file scope
314 /// loc is token index of __asm__ keyword
306315 file_scope_asm,
307316
308317 // typedef declaration
309318 typedef,
310319
311320 // container declarations
312 /// { lhs; rhs; }
321 /// { two[0]; two[1]; }
313322 struct_decl_two,
314 /// { lhs; rhs; }
323 /// { two[0]; two[1]; }
315324 union_decl_two,
316 /// { lhs, rhs, }
325 /// { two[0], two[1], }
317326 enum_decl_two,
318327 /// { range }
319328 struct_decl,
......@@ -339,7 +348,7 @@ pub const Tag = enum(u8) {
339348 // ====== Stmt ======
340349
341350 labeled_stmt,
342 /// { first; second; } first and second may be null
351 /// { two[0]; two[1]; } first and second may be null
343352 compound_stmt_two,
344353 /// { data }
345354 compound_stmt,
......@@ -476,7 +485,7 @@ pub const Tag = enum(u8) {
476485 real_expr,
477486 /// lhs[rhs] lhs is pointer/array type, rhs is integer type
478487 array_access_expr,
479 /// first(second) second may be 0
488 /// two[0](two[1]) two[1] may be 0
480489 call_expr_one,
481490 /// data[0](data[1..])
482491 call_expr,
......@@ -515,7 +524,7 @@ pub const Tag = enum(u8) {
515524 sizeof_expr,
516525 /// _Alignof(un?)
517526 alignof_expr,
518 /// _Generic(controlling lhs, chosen rhs)
527 /// _Generic(controlling two[0], chosen two[1])
519528 generic_expr_one,
520529 /// _Generic(controlling range[0], chosen range[1], rest range[2..])
521530 generic_expr,
......@@ -534,28 +543,34 @@ pub const Tag = enum(u8) {
534543
535544 // ====== Initializer expressions ======
536545
537 /// { lhs, rhs }
546 /// { two[0], two[1] }
538547 array_init_expr_two,
539548 /// { range }
540549 array_init_expr,
541 /// { lhs, rhs }
550 /// { two[0], two[1] }
542551 struct_init_expr_two,
543552 /// { range }
544553 struct_init_expr,
545554 /// { union_init }
546555 union_init_expr,
556
547557 /// (ty){ un }
558 /// loc is token index of l_paren
548559 compound_literal_expr,
549560 /// (static ty){ un }
561 /// loc is token index of l_paren
550562 static_compound_literal_expr,
551563 /// (thread_local ty){ un }
564 /// loc is token index of l_paren
552565 thread_local_compound_literal_expr,
553566 /// (static thread_local ty){ un }
567 /// loc is token index of l_paren
554568 static_thread_local_compound_literal_expr,
555569
556570 /// Inserted at the end of a function body if no return stmt is found.
557571 /// ty is the functions return type
558572 /// 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
559574 implicit_return,
560575
561576 /// 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
608623 }
609624}
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
611677pub fn isLval(tree: *const Tree, node: NodeIndex) bool {
612678 var is_const: bool = undefined;
613679 return tree.isLvalExtra(node, &is_const);
......@@ -672,17 +738,66 @@ pub fn isLvalExtra(tree: *const Tree, node: NodeIndex, is_const: *bool) bool {
672738 }
673739}
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
675783pub fn tokSlice(tree: *const Tree, tok_i: TokenIndex) []const u8 {
676784 if (tree.tokens.items(.id)[tok_i].lexeme()) |some| return some;
677785 const loc = tree.tokens.items(.loc)[tok_i];
678 var tmp_tokenizer = Tokenizer{
679 .buf = tree.comp.getSource(loc.id).buf,
680 .langopts = tree.comp.langopts,
681 .index = loc.byte_offset,
682 .source = .generated,
786 return tree.comp.locSlice(loc);
787}
788
789pub fn nodeTok(tree: *const Tree, node: NodeIndex) ?TokenIndex {
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),
683795 };
684 const tok = tmp_tokenizer.next();
685 return tmp_tokenizer.buf[tok.start..tok.end];
796}
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)];
686801}
687802
688803pub fn dump(tree: *const Tree, config: std.io.tty.Config, writer: anytype) !void {
......@@ -766,6 +881,10 @@ fn dumpNode(
766881 }
767882 try config.setColor(w, TYPE);
768883 try w.writeByte('\'');
884 const name = ty.getName();
885 if (name != .empty) {
886 try w.print("{s}': '", .{mapper.lookup(name)});
887 }
769888 try ty.dump(mapper, tree.comp.langopts, w);
770889 try w.writeByte('\'');
771890
......@@ -794,7 +913,9 @@ fn dumpNode(
794913
795914 if (ty.specifier == .attributed) {
796915 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;
798919 try w.writeByteNTimes(' ', level + half);
799920 try w.print("attr: {s}", .{@tagName(attr.tag)});
800921 try tree.dumpAttribute(attr, w);
......@@ -900,9 +1021,16 @@ fn dumpNode(
9001021 .enum_decl,
9011022 .struct_decl,
9021023 .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,
9031030 => {
1031 const child_nodes = tree.childNodes(node);
9041032 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| {
9061034 if (i != 0) try w.writeByte('\n');
9071035 try tree.dumpNode(stmt, level + delta, mapper, config, w);
9081036 if (maybe_field_attributes) |field_attributes| {
......@@ -914,33 +1042,6 @@ fn dumpNode(
9141042 }
9151043 }
9161044 },
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 },
9441045 .union_init_expr => {
9451046 try w.writeByteNTimes(' ', level + half);
9461047 try w.writeAll("field index: ");
......@@ -1130,23 +1231,21 @@ fn dumpNode(
11301231 try tree.dumpNode(data.un, level + delta, mapper, config, w);
11311232 }
11321233 },
1133 .call_expr => {
1134 try w.writeByteNTimes(' ', level + half);
1135 try w.writeAll("lhs:\n");
1136 try tree.dumpNode(tree.data[data.range.start], level + delta, mapper, config, w);
1234 .call_expr, .call_expr_one => {
1235 const child_nodes = tree.childNodes(node);
1236 const fn_ptr = child_nodes[0];
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 => {
11431239 try w.writeByteNTimes(' ', level + half);
11441240 try w.writeAll("lhs:\n");
1145 try tree.dumpNode(data.bin.lhs, level + delta, mapper, config, w);
1146 if (data.bin.rhs != .none) {
1241 try tree.dumpNode(fn_ptr, level + delta, mapper, config, w);
1242
1243 if (args.len > 0) {
11471244 try w.writeByteNTimes(' ', level + half);
1148 try w.writeAll("arg:\n");
1149 try tree.dumpNode(data.bin.rhs, level + delta, mapper, config, w);
1245 try w.writeAll("args:\n");
1246 for (args) |arg| {
1247 try tree.dumpNode(arg, level + delta, mapper, config, w);
1248 }
11501249 }
11511250 },
11521251 .builtin_call_expr => {
......@@ -1295,28 +1394,25 @@ fn dumpNode(
12951394 try tree.dumpNode(data.un, level + delta, mapper, config, w);
12961395 }
12971396 },
1298 .generic_expr_one => {
1299 try w.writeByteNTimes(' ', level + 1);
1300 try w.writeAll("controlling:\n");
1301 try tree.dumpNode(data.bin.lhs, level + delta, mapper, config, w);
1302 try w.writeByteNTimes(' ', level + 1);
1303 if (data.bin.rhs != .none) {
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];
1397 .generic_expr, .generic_expr_one => {
1398 const child_nodes = tree.childNodes(node);
1399 const controlling = child_nodes[0];
1400 const chosen = child_nodes[1];
1401 const rest = child_nodes[2..];
1402
13101403 try w.writeByteNTimes(' ', level + 1);
13111404 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);
13131406 try w.writeByteNTimes(' ', level + 1);
13141407 try w.writeAll("chosen:\n");
1315 try tree.dumpNode(nodes[1], level + delta, mapper, config, w);
1316 try w.writeByteNTimes(' ', level + 1);
1317 try w.writeAll("rest:\n");
1318 for (nodes[2..]) |expr| {
1319 try tree.dumpNode(expr, level + delta, mapper, config, w);
1408 try tree.dumpNode(chosen, level + delta, mapper, config, w);
1409
1410 if (rest.len > 0) {
1411 try w.writeByteNTimes(' ', level + 1);
1412 try w.writeAll("rest:\n");
1413 for (rest) |expr| {
1414 try tree.dumpNode(expr, level + delta, mapper, config, w);
1415 }
13201416 }
13211417 },
13221418 .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 {
7474 // float and imaginary float
7575 F, IF,
7676
77 // _Float16
78 F16,
77 // _Float16 and imaginary _Float16
78 F16, IF16,
7979
8080 // __float80
8181 W,
......@@ -129,6 +129,7 @@ pub const Suffix = enum {
129129
130130 .{ .I, &.{"I"} },
131131 .{ .IL, &.{ "I", "L" } },
132 .{ .IF16, &.{ "I", "F16" } },
132133 .{ .IF, &.{ "I", "F" } },
133134 .{ .IW, &.{ "I", "W" } },
134135 .{ .IF128, &.{ "I", "F128" } },
......@@ -161,7 +162,7 @@ pub const Suffix = enum {
161162
162163 pub fn isImaginary(suffix: Suffix) bool {
163164 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,
165166 .None, .L, .F16, .F, .U, .UL, .LL, .ULL, .WB, .UWB, .F128, .Q, .W => false,
166167 };
167168 }
......@@ -170,7 +171,7 @@ pub const Suffix = enum {
170171 return switch (suffix) {
171172 .None, .L, .LL, .I, .IL, .ILL, .WB, .IWB => true,
172173 .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,
174175 };
175176 }
176177
......@@ -184,4 +185,8 @@ pub const Suffix = enum {
184185 else => false,
185186 };
186187 }
188
189 pub fn isFloat80(suffix: Suffix) bool {
190 return suffix == .W or suffix == .IW;
191 }
187192};
lib/compiler/aro/aro/Type.zig+170-170
......@@ -146,17 +146,14 @@ pub const Attributed = struct {
146146 attributes: []Attribute,
147147 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 {
150150 const attributed_type = try allocator.create(Attributed);
151151 errdefer allocator.destroy(attributed_type);
152
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);
152 const duped = try allocator.dupe(Attribute, attributes);
156153
157154 attributed_type.* = .{
158 .attributes = all_attrs,
159 .base = base,
155 .attributes = duped,
156 .base = base_ty,
160157 };
161158 return attributed_type;
162159 }
......@@ -190,13 +187,10 @@ pub const Enum = struct {
190187 }
191188};
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.
196190pub const TypeLayout = struct {
197191 /// The size of the type in bits.
198192 ///
199 /// This is the value returned by `sizeof` and C and `std::mem::size_of` in Rust
193 /// This is the value returned by `sizeof` in C
200194 /// (but in bits instead of bytes). This is a multiple of `pointer_alignment_bits`.
201195 size_bits: u64,
202196 /// The alignment of the type, in bits, when used as a field in a record.
......@@ -205,9 +199,7 @@ pub const TypeLayout = struct {
205199 /// cases in GCC where `_Alignof` returns a smaller value.
206200 field_alignment_bits: u32,
207201 /// The alignment, in bits, of valid pointers to this type.
208 ///
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.
202 /// `size_bits` is a multiple of this value.
211203 pointer_alignment_bits: u32,
212204 /// The required alignment of the type in bits.
213205 ///
......@@ -301,6 +293,15 @@ pub const Record = struct {
301293 }
302294 return false;
303295 }
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 }
304305};
305306
306307pub const Specifier = enum {
......@@ -354,12 +355,11 @@ pub const Specifier = enum {
354355 float,
355356 double,
356357 long_double,
357 float80,
358358 float128,
359 complex_float16,
359360 complex_float,
360361 complex_double,
361362 complex_long_double,
362 complex_float80,
363363 complex_float128,
364364
365365 // data.sub_type
......@@ -422,6 +422,8 @@ data: union {
422422specifier: Specifier,
423423qual: Qualifiers = .{},
424424decayed: bool = false,
425/// typedef name, if any
426name: StringId = .empty,
425427
426428pub const int = Type{ .specifier = .int };
427429pub const invalid = Type{ .specifier = .invalid };
......@@ -435,8 +437,8 @@ pub fn is(ty: Type, specifier: Specifier) bool {
435437
436438pub fn withAttributes(self: Type, allocator: std.mem.Allocator, attributes: []const Attribute) !Type {
437439 if (attributes.len == 0) return self;
438 const attributed_type = try Type.Attributed.create(allocator, self, self.getAttributes(), attributes);
439 return Type{ .specifier = .attributed, .data = .{ .attributed = attributed_type }, .decayed = self.decayed };
440 const attributed_type = try Type.Attributed.create(allocator, self, attributes);
441 return .{ .specifier = .attributed, .data = .{ .attributed = attributed_type }, .decayed = self.decayed };
440442}
441443
442444pub fn isCallable(ty: Type) ?Type {
......@@ -470,6 +472,23 @@ pub fn isArray(ty: Type) bool {
470472 };
471473}
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
473492/// Whether the type is promoted if used as a variadic argument or as an argument to a function with no prototype
474493fn undergoesDefaultArgPromotion(ty: Type, comp: *const Compilation) bool {
475494 return switch (ty.specifier) {
......@@ -536,7 +555,7 @@ pub fn isFloat(ty: Type) bool {
536555 return switch (ty.specifier) {
537556 // zig fmt: off
538557 .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,
540559 // zig fmt: on
541560 .typeof_type => ty.data.sub_type.isFloat(),
542561 .typeof_expr => ty.data.expr.ty.isFloat(),
......@@ -548,11 +567,11 @@ pub fn isFloat(ty: Type) bool {
548567pub fn isReal(ty: Type) bool {
549568 return switch (ty.specifier) {
550569 // zig fmt: off
551 .complex_float, .complex_double, .complex_long_double, .complex_float80,
570 .complex_float, .complex_double, .complex_long_double,
552571 .complex_float128, .complex_char, .complex_schar, .complex_uchar, .complex_short,
553572 .complex_ushort, .complex_int, .complex_uint, .complex_long, .complex_ulong,
554573 .complex_long_long, .complex_ulong_long, .complex_int128, .complex_uint128,
555 .complex_bit_int => false,
574 .complex_bit_int, .complex_float16 => false,
556575 // zig fmt: on
557576 .typeof_type => ty.data.sub_type.isReal(),
558577 .typeof_expr => ty.data.expr.ty.isReal(),
......@@ -564,11 +583,11 @@ pub fn isReal(ty: Type) bool {
564583pub fn isComplex(ty: Type) bool {
565584 return switch (ty.specifier) {
566585 // zig fmt: off
567 .complex_float, .complex_double, .complex_long_double, .complex_float80,
586 .complex_float, .complex_double, .complex_long_double,
568587 .complex_float128, .complex_char, .complex_schar, .complex_uchar, .complex_short,
569588 .complex_ushort, .complex_int, .complex_uint, .complex_long, .complex_ulong,
570589 .complex_long_long, .complex_ulong_long, .complex_int128, .complex_uint128,
571 .complex_bit_int => true,
590 .complex_bit_int, .complex_float16 => true,
572591 // zig fmt: on
573592 .typeof_type => ty.data.sub_type.isComplex(),
574593 .typeof_expr => ty.data.expr.ty.isComplex(),
......@@ -671,11 +690,11 @@ pub fn elemType(ty: Type) Type {
671690 .attributed => ty.data.attributed.base.elemType(),
672691 .invalid => Type.invalid,
673692 // zig fmt: off
674 .complex_float, .complex_double, .complex_long_double, .complex_float80,
693 .complex_float, .complex_double, .complex_long_double,
675694 .complex_float128, .complex_char, .complex_schar, .complex_uchar, .complex_short,
676695 .complex_ushort, .complex_int, .complex_uint, .complex_long, .complex_ulong,
677696 .complex_long_long, .complex_ulong_long, .complex_int128, .complex_uint128,
678 .complex_bit_int => ty.makeReal(),
697 .complex_bit_int, .complex_float16 => ty.makeReal(),
679698 // zig fmt: on
680699 else => unreachable,
681700 };
......@@ -703,6 +722,16 @@ pub fn params(ty: Type) []Func.Param {
703722 };
704723}
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
706735pub fn arrayLen(ty: Type) ?u64 {
707736 return switch (ty.specifier) {
708737 .array, .static_array => ty.data.array.len,
......@@ -726,15 +755,6 @@ pub fn anyQual(ty: Type) bool {
726755 };
727756}
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
738758pub fn getRecord(ty: Type) ?*const Type.Record {
739759 return switch (ty.specifier) {
740760 .attributed => ty.data.attributed.base.getRecord(),
......@@ -795,8 +815,8 @@ fn realIntegerConversion(a: Type, b: Type, comp: *const Compilation) Type {
795815
796816pub fn makeIntegerUnsigned(ty: Type) Type {
797817 // TODO discards attributed/typeof
798 var base = ty.canonicalize(.standard);
799 switch (base.specifier) {
818 var base_ty = ty.canonicalize(.standard);
819 switch (base_ty.specifier) {
800820 // zig fmt: off
801821 .uchar, .ushort, .uint, .ulong, .ulong_long, .uint128,
802822 .complex_uchar, .complex_ushort, .complex_uint, .complex_ulong, .complex_ulong_long, .complex_uint128,
......@@ -804,21 +824,21 @@ pub fn makeIntegerUnsigned(ty: Type) Type {
804824 // zig fmt: on
805825
806826 .char, .complex_char => {
807 base.specifier = @enumFromInt(@intFromEnum(base.specifier) + 2);
808 return base;
827 base_ty.specifier = @enumFromInt(@intFromEnum(base_ty.specifier) + 2);
828 return base_ty;
809829 },
810830
811831 // zig fmt: off
812832 .schar, .short, .int, .long, .long_long, .int128,
813833 .complex_schar, .complex_short, .complex_int, .complex_long, .complex_long_long, .complex_int128 => {
814 base.specifier = @enumFromInt(@intFromEnum(base.specifier) + 1);
815 return base;
834 base_ty.specifier = @enumFromInt(@intFromEnum(base_ty.specifier) + 1);
835 return base_ty;
816836 },
817837 // zig fmt: on
818838
819839 .bit_int, .complex_bit_int => {
820 base.data.int.signedness = .unsigned;
821 return base;
840 base_ty.data.int.signedness = .unsigned;
841 return base_ty;
822842 },
823843 else => unreachable,
824844 }
......@@ -837,6 +857,8 @@ pub fn integerPromotion(ty: Type, comp: *Compilation) Type {
837857 switch (specifier) {
838858 .@"enum" => {
839859 if (ty.hasIncompleteSize()) return .{ .specifier = .int };
860 if (ty.data.@"enum".fixed) return ty.data.@"enum".tag_ty.integerPromotion(comp);
861
840862 specifier = ty.data.@"enum".tag_ty.specifier;
841863 },
842864 .bit_int, .complex_bit_int => return .{ .specifier = specifier, .data = ty.data },
......@@ -915,53 +937,7 @@ pub fn hasUnboundVLA(ty: Type) bool {
915937}
916938
917939pub fn hasField(ty: Type, name: StringId) bool {
918 switch (ty.specifier) {
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 };
940 return ty.getRecord().?.hasField(name);
965941}
966942
967943const TypeSizeOrder = enum {
......@@ -1004,16 +980,15 @@ pub fn sizeof(ty: Type, comp: *const Compilation) ?u64 {
1004980 .fp16, .float16 => 2,
1005981 .float => comp.target.cTypeByteSize(.float),
1006982 .double => comp.target.cTypeByteSize(.double),
1007 .float80 => 16,
1008983 .float128 => 16,
1009984 .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));
1011986 },
1012987 // zig fmt: off
1013988 .complex_char, .complex_schar, .complex_uchar, .complex_short, .complex_ushort, .complex_int,
1014989 .complex_uint, .complex_long, .complex_ulong, .complex_long_long, .complex_ulong_long,
1015990 .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,
1017992 => return 2 * ty.makeReal().sizeof(comp).?,
1018993 // zig fmt: on
1019994 .pointer => unreachable,
......@@ -1050,7 +1025,6 @@ pub fn bitSizeof(ty: Type, comp: *const Compilation) ?u64 {
10501025 .attributed => ty.data.attributed.base.bitSizeof(comp),
10511026 .bit_int => return ty.data.int.bits,
10521027 .long_double => comp.target.cTypeBitSize(.longdouble),
1053 .float80 => return 80,
10541028 else => 8 * (ty.sizeof(comp) orelse return null),
10551029 };
10561030}
......@@ -1100,7 +1074,7 @@ pub fn alignof(ty: Type, comp: *const Compilation) u29 {
11001074 .complex_char, .complex_schar, .complex_uchar, .complex_short, .complex_ushort, .complex_int,
11011075 .complex_uint, .complex_long, .complex_ulong, .complex_long_long, .complex_ulong_long,
11021076 .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,
11041078 => return ty.makeReal().alignof(comp),
11051079 // zig fmt: on
11061080
......@@ -1114,10 +1088,15 @@ pub fn alignof(ty: Type, comp: *const Compilation) u29 {
11141088 .long_long => comp.target.cTypeAlignment(.longlong),
11151089 .ulong_long => comp.target.cTypeAlignment(.ulonglong),
11161090
1117 .bit_int => @min(
1118 std.math.ceilPowerOfTwoPromote(u16, (ty.data.int.bits + 7) / 8),
1119 16, // comp.target.maxIntAlignment(), please use your own logic for this value as it is implementation-defined
1120 ),
1091 .bit_int => {
1092 // https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2709.pdf
1093 // _BitInt(N) types align with existing calling conventions. They have the same size and alignment as the
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
11221101 .float => comp.target.cTypeAlignment(.float),
11231102 .double => comp.target.cTypeAlignment(.double),
......@@ -1126,7 +1105,7 @@ pub fn alignof(ty: Type, comp: *const Compilation) u29 {
11261105 .int128, .uint128 => if (comp.target.cpu.arch == .s390x and comp.target.os.tag == .linux and comp.target.isGnu()) 8 else 16,
11271106 .fp16, .float16 => 2,
11281107
1129 .float80, .float128 => 16,
1108 .float128 => 16,
11301109 .pointer,
11311110 .static_array,
11321111 .nullptr_t,
......@@ -1142,7 +1121,11 @@ pub fn alignof(ty: Type, comp: *const Compilation) u29 {
11421121 };
11431122}
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
11471130/// Canonicalize a possibly-typeof() type. If the type is not a typeof() type, simply
11481131/// return it. Otherwise, determine the actual qualified type.
......@@ -1151,17 +1134,12 @@ pub const QualHandling = enum { standard, preserve_quals };
11511134/// arrays and pointers.
11521135pub fn canonicalize(ty: Type, qual_handling: QualHandling) Type {
11531136 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
11601137 var qual = cur.qual;
11611138 while (true) {
11621139 switch (cur.specifier) {
11631140 .typeof_type => cur = cur.data.sub_type.*,
11641141 .typeof_expr => cur = cur.data.expr.ty,
1142 .attributed => cur = cur.data.attributed.base,
11651143 else => break,
11661144 }
11671145 qual = qual.mergeAll(cur.qual);
......@@ -1189,7 +1167,7 @@ pub fn requestedAlignment(ty: Type, comp: *const Compilation) ?u29 {
11891167 return switch (ty.specifier) {
11901168 .typeof_type => ty.data.sub_type.requestedAlignment(comp),
11911169 .typeof_expr => ty.data.expr.ty.requestedAlignment(comp),
1192 .attributed => annotationAlignment(comp, ty.data.attributed.attributes),
1170 .attributed => annotationAlignment(comp, Attribute.Iterator.initType(ty)),
11931171 else => null,
11941172 };
11951173}
......@@ -1199,12 +1177,27 @@ pub fn enumIsPacked(ty: Type, comp: *const Compilation) bool {
11991177 return comp.langopts.short_enums or target_util.packAllEnums(comp.target) or ty.hasAttribute(.@"packed");
12001178}
12011179
1202pub fn annotationAlignment(comp: *const Compilation, attrs: ?[]const Attribute) ?u29 {
1203 const a = attrs orelse return null;
1180pub fn getName(ty: Type) StringId {
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;
12051191 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;
12071195 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;
12081201 const requested = if (attribute.args.aligned.alignment) |alignment| alignment.requested else target_util.defaultAlignment(comp.target);
12091202 if (max_requested == null or max_requested.? < requested) {
12101203 max_requested = requested;
......@@ -1225,6 +1218,10 @@ pub fn eql(a_param: Type, b_param: Type, comp: *const Compilation, check_qualifi
12251218 if (!b.isFunc()) return false;
12261219 } else if (a.isArray()) {
12271220 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);
12281225 } else if (a.specifier != b.specifier) return false;
12291226
12301227 if (a.qual.atomic != b.qual.atomic) return false;
......@@ -1315,6 +1312,12 @@ pub fn integerRank(ty: Type, comp: *const Compilation) usize {
13151312 .long_long, .ulong_long => 6 + (ty.bitSizeof(comp).? << 3),
13161313 .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
13181321 else => unreachable,
13191322 });
13201323}
......@@ -1322,25 +1325,26 @@ pub fn integerRank(ty: Type, comp: *const Compilation) usize {
13221325/// Returns true if `a` and `b` are integer types that differ only in sign
13231326pub fn sameRankDifferentSign(a: Type, b: Type, comp: *const Compilation) bool {
13241327 if (!a.isInt() or !b.isInt()) return false;
1328 if (a.hasIncompleteSize() or b.hasIncompleteSize()) return false;
13251329 if (a.integerRank(comp) != b.integerRank(comp)) return false;
13261330 return a.isUnsignedInt(comp) != b.isUnsignedInt(comp);
13271331}
13281332
13291333pub fn makeReal(ty: Type) Type {
13301334 // TODO discards attributed/typeof
1331 var base = ty.canonicalize(.standard);
1332 switch (base.specifier) {
1333 .complex_float, .complex_double, .complex_long_double, .complex_float80, .complex_float128 => {
1334 base.specifier = @enumFromInt(@intFromEnum(base.specifier) - 5);
1335 return base;
1335 var base_ty = ty.canonicalize(.standard);
1336 switch (base_ty.specifier) {
1337 .complex_float16, .complex_float, .complex_double, .complex_long_double, .complex_float128 => {
1338 base_ty.specifier = @enumFromInt(@intFromEnum(base_ty.specifier) - 5);
1339 return base_ty;
13361340 },
13371341 .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);
1339 return base;
1342 base_ty.specifier = @enumFromInt(@intFromEnum(base_ty.specifier) - 13);
1343 return base_ty;
13401344 },
13411345 .complex_bit_int => {
1342 base.specifier = .bit_int;
1343 return base;
1346 base_ty.specifier = .bit_int;
1347 return base_ty;
13441348 },
13451349 else => return ty,
13461350 }
......@@ -1348,19 +1352,19 @@ pub fn makeReal(ty: Type) Type {
13481352
13491353pub fn makeComplex(ty: Type) Type {
13501354 // TODO discards attributed/typeof
1351 var base = ty.canonicalize(.standard);
1352 switch (base.specifier) {
1353 .float, .double, .long_double, .float80, .float128 => {
1354 base.specifier = @enumFromInt(@intFromEnum(base.specifier) + 5);
1355 return base;
1355 var base_ty = ty.canonicalize(.standard);
1356 switch (base_ty.specifier) {
1357 .float, .double, .long_double, .float128 => {
1358 base_ty.specifier = @enumFromInt(@intFromEnum(base_ty.specifier) + 5);
1359 return base_ty;
13561360 },
13571361 .char, .schar, .uchar, .short, .ushort, .int, .uint, .long, .ulong, .long_long, .ulong_long, .int128, .uint128 => {
1358 base.specifier = @enumFromInt(@intFromEnum(base.specifier) + 13);
1359 return base;
1362 base_ty.specifier = @enumFromInt(@intFromEnum(base_ty.specifier) + 13);
1363 return base_ty;
13601364 },
13611365 .bit_int => {
1362 base.specifier = .complex_bit_int;
1363 return base;
1366 base_ty.specifier = .complex_bit_int;
1367 return base_ty;
13641368 },
13651369 else => return ty,
13661370 }
......@@ -1541,13 +1545,12 @@ pub const Builder = struct {
15411545 float,
15421546 double,
15431547 long_double,
1544 float80,
15451548 float128,
15461549 complex,
1550 complex_float16,
15471551 complex_float,
15481552 complex_double,
15491553 complex_long_double,
1550 complex_float80,
15511554 complex_float128,
15521555
15531556 pointer: *Type,
......@@ -1613,9 +1616,6 @@ pub const Builder = struct {
16131616 .int128 => "__int128",
16141617 .sint128 => "signed __int128",
16151618 .uint128 => "unsigned __int128",
1616 .bit_int => "_BitInt",
1617 .sbit_int => "signed _BitInt",
1618 .ubit_int => "unsigned _BitInt",
16191619 .complex_char => "_Complex char",
16201620 .complex_schar => "_Complex signed char",
16211621 .complex_uchar => "_Complex unsigned char",
......@@ -1645,22 +1645,18 @@ pub const Builder = struct {
16451645 .complex_int128 => "_Complex __int128",
16461646 .complex_sint128 => "_Complex signed __int128",
16471647 .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
16521649 .fp16 => "__fp16",
16531650 .float16 => "_Float16",
16541651 .float => "float",
16551652 .double => "double",
16561653 .long_double => "long double",
1657 .float80 => "__float80",
16581654 .float128 => "__float128",
16591655 .complex => "_Complex",
1656 .complex_float16 => "_Complex _Float16",
16601657 .complex_float => "_Complex float",
16611658 .complex_double => "_Complex double",
16621659 .complex_long_double => "_Complex long double",
1663 .complex_float80 => "_Complex __float80",
16641660 .complex_float128 => "_Complex __float128",
16651661
16661662 .attributed => |attributed| Builder.fromType(attributed.base).str(langopts),
......@@ -1757,19 +1753,20 @@ pub const Builder = struct {
17571753 .complex_uint128 => ty.specifier = .complex_uint128,
17581754 .bit_int, .sbit_int, .ubit_int, .complex_bit_int, .complex_ubit_int, .complex_sbit_int => |bits| {
17591755 const unsigned = b.specifier == .ubit_int or b.specifier == .complex_ubit_int;
1756 const complex_str = if (b.complex_tok != null) "_Complex " else "";
17601757 if (unsigned) {
17611758 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);
17631760 return Type.invalid;
17641761 }
17651762 } else {
17661763 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);
17681765 return Type.invalid;
17691766 }
17701767 }
17711768 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);
17731770 return Type.invalid;
17741771 }
17751772 ty.specifier = if (b.complex_tok != null) .complex_bit_int else .bit_int;
......@@ -1784,12 +1781,11 @@ pub const Builder = struct {
17841781 .float => ty.specifier = .float,
17851782 .double => ty.specifier = .double,
17861783 .long_double => ty.specifier = .long_double,
1787 .float80 => ty.specifier = .float80,
17881784 .float128 => ty.specifier = .float128,
1785 .complex_float16 => ty.specifier = .complex_float16,
17891786 .complex_float => ty.specifier = .complex_float,
17901787 .complex_double => ty.specifier = .complex_double,
17911788 .complex_long_double => ty.specifier = .complex_long_double,
1792 .complex_float80 => ty.specifier = .complex_float80,
17931789 .complex_float128 => ty.specifier = .complex_float128,
17941790 .complex => {
17951791 try p.errTok(.plain_complex, p.tok_i - 1);
......@@ -1907,6 +1903,7 @@ pub const Builder = struct {
19071903
19081904 /// Try to combine type from typedef, returns true if successful.
19091905 pub fn combineTypedef(b: *Builder, p: *Parser, typedef_ty: Type, name_tok: TokenIndex) bool {
1906 if (typedef_ty.is(.invalid)) return false;
19101907 b.error_on_invalid = true;
19111908 defer b.error_on_invalid = false;
19121909
......@@ -2094,6 +2091,7 @@ pub const Builder = struct {
20942091 },
20952092 .long => b.specifier = switch (b.specifier) {
20962093 .none => .long,
2094 .double => .long_double,
20972095 .long => .long_long,
20982096 .unsigned => .ulong,
20992097 .signed => .long,
......@@ -2106,6 +2104,7 @@ pub const Builder = struct {
21062104 .complex_long => .complex_long_long,
21072105 .complex_slong => .complex_slong_long,
21082106 .complex_ulong => .complex_ulong_long,
2107 .complex_double => .complex_long_double,
21092108 else => return b.cannotCombine(p, source_tok),
21102109 },
21112110 .int128 => b.specifier = switch (b.specifier) {
......@@ -2140,6 +2139,7 @@ pub const Builder = struct {
21402139 },
21412140 .float16 => b.specifier = switch (b.specifier) {
21422141 .none => .float16,
2142 .complex => .complex_float16,
21432143 else => return b.cannotCombine(p, source_tok),
21442144 },
21452145 .float => b.specifier = switch (b.specifier) {
......@@ -2154,11 +2154,6 @@ pub const Builder = struct {
21542154 .complex => .complex_double,
21552155 else => return b.cannotCombine(p, source_tok),
21562156 },
2157 .float80 => b.specifier = switch (b.specifier) {
2158 .none => .float80,
2159 .complex => .complex_float80,
2160 else => return b.cannotCombine(p, source_tok),
2161 },
21622157 .float128 => b.specifier = switch (b.specifier) {
21632158 .none => .float128,
21642159 .complex => .complex_float128,
......@@ -2166,10 +2161,10 @@ pub const Builder = struct {
21662161 },
21672162 .complex => b.specifier = switch (b.specifier) {
21682163 .none => .complex,
2164 .float16 => .complex_float16,
21692165 .float => .complex_float,
21702166 .double => .complex_double,
21712167 .long_double => .complex_long_double,
2172 .float80 => .complex_float80,
21732168 .float128 => .complex_float128,
21742169 .char => .complex_char,
21752170 .schar => .complex_schar,
......@@ -2207,7 +2202,6 @@ pub const Builder = struct {
22072202 .complex_float,
22082203 .complex_double,
22092204 .complex_long_double,
2210 .complex_float80,
22112205 .complex_float128,
22122206 .complex_char,
22132207 .complex_schar,
......@@ -2294,13 +2288,12 @@ pub const Builder = struct {
22942288 .float16 => .float16,
22952289 .float => .float,
22962290 .double => .double,
2297 .float80 => .float80,
22982291 .float128 => .float128,
22992292 .long_double => .long_double,
2293 .complex_float16 => .complex_float16,
23002294 .complex_float => .complex_float,
23012295 .complex_double => .complex_double,
23022296 .complex_long_double => .complex_long_double,
2303 .complex_float80 => .complex_float80,
23042297 .complex_float128 => .complex_float128,
23052298
23062299 .pointer => .{ .pointer = ty.data.sub_type },
......@@ -2350,22 +2343,30 @@ pub const Builder = struct {
23502343 }
23512344};
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
23532356pub fn getAttribute(ty: Type, comptime tag: Attribute.Tag) ?Attribute.ArgumentsForTag(tag) {
2354 switch (ty.specifier) {
2355 .typeof_type => return ty.data.sub_type.getAttribute(tag),
2356 .typeof_expr => return ty.data.expr.ty.getAttribute(tag),
2357 .attributed => {
2358 for (ty.data.attributed.attributes) |attribute| {
2359 if (attribute.tag == tag) return @field(attribute.args, @tagName(tag));
2360 }
2361 return null;
2362 },
2363 else => return null,
2357 if (tag == .aligned) @compileError("use requestedAlignment");
2358 var it = Attribute.Iterator.initType(ty);
2359 while (it.next()) |item| {
2360 const attribute, _ = item;
2361 if (attribute.tag == tag) return @field(attribute.args, @tagName(tag));
23642362 }
2363 return null;
23652364}
23662365
23672366pub 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;
23692370 if (attr.tag == tag) return true;
23702371 }
23712372 return false;
......@@ -2489,6 +2490,8 @@ fn printPrologue(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts
24892490 _ = try elem_ty.printPrologue(mapper, langopts, w);
24902491 try w.writeAll("' values)");
24912492 },
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 }),
24922495 else => try w.writeAll(Builder.fromType(ty).str(langopts).?),
24932496 }
24942497 return true;
......@@ -2644,15 +2647,12 @@ pub fn dump(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts, w:
26442647 .attributed => {
26452648 if (ty.isDecayed()) try w.writeAll("*d:");
26462649 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);
26482651 try w.writeAll(")");
26492652 },
2650 else => {
2651 try w.writeAll(Builder.fromType(ty).str(langopts).?);
2652 if (ty.specifier == .bit_int or ty.specifier == .complex_bit_int) {
2653 try w.print("({d})", .{ty.data.int.bits});
2654 }
2655 },
2653 .bit_int => try w.print("{s} _BitInt({d})", .{ @tagName(ty.data.int.signedness), ty.data.int.bits }),
2654 .complex_bit_int => try w.print("_Complex {s} _BitInt({d})", .{ @tagName(ty.data.int.signedness), ty.data.int.bits }),
2655 else => try w.writeAll(Builder.fromType(ty).str(langopts).?),
26562656 }
26572657}
26582658
lib/compiler/aro/aro/Value.zig+358-53
......@@ -8,6 +8,7 @@ const BigIntSpace = Interner.Tag.Int.BigIntSpace;
88const Compilation = @import("Compilation.zig");
99const Type = @import("Type.zig");
1010const target_util = @import("target.zig");
11const annex_g = @import("annex_g.zig");
1112
1213const Value = @This();
1314
......@@ -41,6 +42,14 @@ pub fn is(v: Value, tag: std.meta.Tag(Interner.Key), comp: *const Compilation) b
4142 return comp.interner.get(v.ref()) == tag;
4243}
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
4453/// Number of bits needed to hold `v`.
4554/// Asserts that `v` is not negative
4655pub fn minUnsignedBits(v: Value, comp: *const Compilation) usize {
......@@ -58,7 +67,7 @@ test "minUnsignedBits" {
5867 }
5968 };
6069
61 var comp = Compilation.init(std.testing.allocator);
70 var comp = Compilation.init(std.testing.allocator, std.fs.cwd());
6271 defer comp.deinit();
6372 const target_query = try std.Target.Query.parse(.{ .arch_os_abi = "x86_64-linux-gnu" });
6473 comp.target = try std.zig.system.resolveTargetQuery(target_query);
......@@ -93,7 +102,7 @@ test "minSignedBits" {
93102 }
94103 };
95104
96 var comp = Compilation.init(std.testing.allocator);
105 var comp = Compilation.init(std.testing.allocator, std.fs.cwd());
97106 defer comp.deinit();
98107 const target_query = try std.Target.Query.parse(.{ .arch_os_abi = "x86_64-linux-gnu" });
99108 comp.target = try std.zig.system.resolveTargetQuery(target_query);
......@@ -134,7 +143,7 @@ pub fn floatToInt(v: *Value, dest_ty: Type, comp: *Compilation) !FloatToIntChang
134143 v.* = fromBool(!was_zero);
135144 if (was_zero or was_one) return .none;
136145 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) {
138147 v.* = zero;
139148 return .out_of_range;
140149 }
......@@ -154,7 +163,7 @@ pub fn floatToInt(v: *Value, dest_ty: Type, comp: *Compilation) !FloatToIntChang
154163 };
155164
156165 // 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 };
158167 assert(rational.q.toConst().eqlAbs(big_one));
159168
160169 if (is_negative) {
......@@ -179,6 +188,20 @@ pub fn floatToInt(v: *Value, dest_ty: Type, comp: *Compilation) !FloatToIntChang
179188/// `.none` value remains unchanged.
180189pub fn intToFloat(v: *Value, dest_ty: Type, comp: *Compilation) !void {
181190 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 }
182205 const bits = dest_ty.bitSizeof(comp).?;
183206 return switch (comp.interner.get(v.ref()).int) {
184207 inline .u64, .i64 => |data| {
......@@ -207,40 +230,89 @@ pub fn intToFloat(v: *Value, dest_ty: Type, comp: *Compilation) !void {
207230 };
208231}
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
210242/// Truncates or extends bits based on type.
211243/// `.none` value remains unchanged.
212pub fn intCast(v: *Value, dest_ty: Type, comp: *Compilation) !void {
213 if (v.opt_ref == .none) return;
214 const bits: usize = @intCast(dest_ty.bitSizeof(comp).?);
244pub fn intCast(v: *Value, dest_ty: Type, comp: *Compilation) !IntCastChangeKind {
245 if (v.opt_ref == .none) return .none;
246
247 const dest_bits: usize = @intCast(dest_ty.bitSizeof(comp).?);
248 const dest_signed = dest_ty.signedness(comp) == .signed;
249
215250 var space: BigIntSpace = undefined;
216251 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
218258 const limbs = try comp.gpa.alloc(
219259 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)),
221261 );
222262 defer comp.gpa.free(limbs);
223 var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined };
224 result_bigint.truncate(big, dest_ty.signedness(comp), bits);
263
264 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
265 result_bigint.truncate(big, dest_ty.signedness(comp), dest_bits);
225266
226267 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 }
227277}
228278
229279/// Converts the stored value to a float of the specified type
230280/// `.none` value remains unchanged.
231281pub fn floatCast(v: *Value, dest_ty: Type, comp: *Compilation) !void {
232282 if (v.opt_ref == .none) return;
233 // TODO complex values
234 const bits = dest_ty.makeReal().bitSizeof(comp).?;
235 const f: Interner.Key.Float = switch (bits) {
236 16 => .{ .f16 = v.toFloat(f16, comp) },
237 32 => .{ .f32 = v.toFloat(f32, comp) },
238 64 => .{ .f64 = v.toFloat(f64, comp) },
239 80 => .{ .f80 = v.toFloat(f80, comp) },
240 128 => .{ .f128 = v.toFloat(f128, comp) },
283 const bits = dest_ty.bitSizeof(comp).?;
284 if (dest_ty.isComplex()) {
285 const cf: Interner.Key.Complex = switch (bits) {
286 32 => .{ .cf16 = .{ v.toFloat(f16, comp), v.imag(f16, comp) } },
287 64 => .{ .cf32 = .{ v.toFloat(f32, comp), v.imag(f32, comp) } },
288 128 => .{ .cf64 = .{ v.toFloat(f64, comp), v.imag(f64, comp) } },
289 160 => .{ .cf80 = .{ v.toFloat(f80, comp), v.imag(f80, 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 },
241314 else => unreachable,
242315 };
243 v.* = try intern(comp, .{ .float = f });
244316}
245317
246318pub 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 {
252324 .float => |repr| switch (repr) {
253325 inline else => |data| @floatCast(data),
254326 },
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 }),
255360 else => unreachable,
256361 };
257362}
......@@ -298,11 +403,56 @@ pub fn isZero(v: Value, comp: *const Compilation) bool {
298403 inline .i64, .u64 => |data| return data == 0,
299404 .big_int => |data| return data.eqlZero(),
300405 },
406 .complex => |repr| switch (repr) {
407 inline else => |data| return data[0] == 0.0 and data[1] == 0.0,
408 },
301409 .bytes => return false,
302410 else => unreachable,
303411 }
304412}
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
306456/// Converts value to zero or one;
307457/// `.none` value remains unchanged.
308458pub fn boolCast(v: *Value, comp: *const Compilation) void {
......@@ -326,9 +476,45 @@ pub fn toInt(v: Value, comptime T: type, comp: *const Compilation) ?T {
326476 return big_int.to(T) catch null;
327477}
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
329504pub fn add(res: *Value, lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !bool {
330505 const bits: usize = @intCast(ty.bitSizeof(comp).?);
331506 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 }
332518 const f: Interner.Key.Float = switch (bits) {
333519 16 => .{ .f16 = lhs.toFloat(f16, comp) + rhs.toFloat(f16, comp) },
334520 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
350536 std.math.big.int.calcTwosCompLimbCount(bits),
351537 );
352538 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
355541 const overflowed = result_bigint.addWrap(lhs_bigint, rhs_bigint, ty.signedness(comp), bits);
356542 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
361547pub fn sub(res: *Value, lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !bool {
362548 const bits: usize = @intCast(ty.bitSizeof(comp).?);
363549 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 }
364561 const f: Interner.Key.Float = switch (bits) {
365562 16 => .{ .f16 = lhs.toFloat(f16, comp) - rhs.toFloat(f16, comp) },
366563 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
382579 std.math.big.int.calcTwosCompLimbCount(bits),
383580 );
384581 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
387584 const overflowed = result_bigint.subWrap(lhs_bigint, rhs_bigint, ty.signedness(comp), bits);
388585 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
393590pub fn mul(res: *Value, lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !bool {
394591 const bits: usize = @intCast(ty.bitSizeof(comp).?);
395592 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 }
396605 const f: Interner.Key.Float = switch (bits) {
397606 16 => .{ .f16 = lhs.toFloat(f16, comp) * rhs.toFloat(f16, comp) },
398607 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
438647pub fn div(res: *Value, lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !bool {
439648 const bits: usize = @intCast(ty.bitSizeof(comp).?);
440649 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 }
441662 const f: Interner.Key.Float = switch (bits) {
442663 16 => .{ .f16 = lhs.toFloat(f16, comp) / rhs.toFloat(f16, comp) },
443664 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 {
491712
492713 const signedness = ty.signedness(comp);
493714 if (signedness == .signed) {
494 var spaces: [3]BigIntSpace = undefined;
495 const min_val = BigIntMutable.init(&spaces[0].limbs, ty.minInt(comp)).toConst();
496 const negative = BigIntMutable.init(&spaces[1].limbs, -1).toConst();
497 const big_one = BigIntMutable.init(&spaces[2].limbs, 1).toConst();
498 if (lhs_bigint.eql(min_val) and rhs_bigint.eql(negative)) {
715 var spaces: [2]BigIntSpace = undefined;
716 const min_val = try Value.minInt(ty, comp);
717 const negative = BigIntMutable.init(&spaces[0].limbs, -1).toConst();
718 const big_one = BigIntMutable.init(&spaces[1].limbs, 1).toConst();
719 if (lhs.compare(.eq, min_val, comp) and rhs_bigint.eql(negative)) {
499720 return .{};
500721 } else if (rhs_bigint.order(big_one).compare(.lt)) {
501722 // lhs - @divTrunc(lhs, rhs) * rhs
......@@ -542,7 +763,7 @@ pub fn bitOr(lhs: Value, rhs: Value, comp: *Compilation) !Value {
542763 @max(lhs_bigint.limbs.len, rhs_bigint.limbs.len),
543764 );
544765 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
547768 result_bigint.bitOr(lhs_bigint, rhs_bigint);
548769 return intern(comp, .{ .int = .{ .big_int = result_bigint.toConst() } });
......@@ -554,12 +775,13 @@ pub fn bitXor(lhs: Value, rhs: Value, comp: *Compilation) !Value {
554775 const lhs_bigint = lhs.toBigInt(&lhs_space, comp);
555776 const rhs_bigint = rhs.toBigInt(&rhs_space, comp);
556777
778 const extra = @intFromBool(lhs_bigint.positive != rhs_bigint.positive);
557779 const limbs = try comp.gpa.alloc(
558780 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,
560782 );
561783 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
564786 result_bigint.bitXor(lhs_bigint, rhs_bigint);
565787 return intern(comp, .{ .int = .{ .big_int = result_bigint.toConst() } });
......@@ -571,12 +793,18 @@ pub fn bitAnd(lhs: Value, rhs: Value, comp: *Compilation) !Value {
571793 const lhs_bigint = lhs.toBigInt(&lhs_space, comp);
572794 const rhs_bigint = rhs.toBigInt(&rhs_space, comp);
573795
574 const limbs = try comp.gpa.alloc(
575 std.math.big.Limb,
576 @max(lhs_bigint.limbs.len, rhs_bigint.limbs.len),
577 );
796 const limb_count = if (lhs_bigint.positive and rhs_bigint.positive)
797 @min(lhs_bigint.limbs.len, rhs_bigint.limbs.len)
798 else if (lhs_bigint.positive)
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);
578806 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
581809 result_bigint.bitAnd(lhs_bigint, rhs_bigint);
582810 return intern(comp, .{ .int = .{ .big_int = result_bigint.toConst() } });
......@@ -592,7 +820,7 @@ pub fn bitNot(val: Value, ty: Type, comp: *Compilation) !Value {
592820 std.math.big.int.calcTwosCompLimbCount(bits),
593821 );
594822 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
597825 result_bigint.bitNotWrap(val_bigint, ty.signedness(comp), bits);
598826 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
606834 const bits: usize = @intCast(ty.bitSizeof(comp).?);
607835 if (shift > bits) {
608836 if (lhs_bigint.positive) {
609 res.* = try intern(comp, .{ .int = .{ .u64 = ty.maxInt(comp) } });
837 res.* = try Value.maxInt(ty, comp);
610838 } else {
611 res.* = try intern(comp, .{ .int = .{ .i64 = ty.minInt(comp) } });
839 res.* = try Value.minInt(ty, comp);
612840 }
613841 return true;
614842 }
......@@ -618,7 +846,7 @@ pub fn shl(res: *Value, lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !b
618846 lhs_bigint.limbs.len + (shift / (@sizeOf(std.math.big.Limb) * 8)) + 1,
619847 );
620848 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
623851 result_bigint.shiftLeft(lhs_bigint, shift);
624852 const signedness = ty.signedness(comp);
......@@ -652,12 +880,25 @@ pub fn shr(lhs: Value, rhs: Value, ty: Type, comp: *Compilation) !Value {
652880 std.math.big.int.calcTwosCompLimbCount(bits),
653881 );
654882 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
657885 result_bigint.shiftRight(lhs_bigint, shift);
658886 return intern(comp, .{ .int = .{ .big_int = result_bigint.toConst() } });
659887}
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
661902pub fn compare(lhs: Value, op: std.math.CompareOperator, rhs: Value, comp: *const Compilation) bool {
662903 if (op == .eq) {
663904 return lhs.opt_ref == rhs.opt_ref;
......@@ -672,6 +913,12 @@ pub fn compare(lhs: Value, op: std.math.CompareOperator, rhs: Value, comp: *cons
672913 const rhs_f128 = rhs.toFloat(f128, comp);
673914 return std.math.compare(lhs_f128, op, rhs_f128);
674915 }
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
676923 var lhs_bigint_space: BigIntSpace = undefined;
677924 var rhs_bigint_space: BigIntSpace = undefined;
......@@ -680,6 +927,42 @@ pub fn compare(lhs: Value, op: std.math.CompareOperator, rhs: Value, comp: *cons
680927 return lhs_bigint.order(rhs_bigint).compare(op);
681928}
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
683966pub fn print(v: Value, ty: Type, comp: *const Compilation, w: anytype) @TypeOf(w).Error!void {
684967 if (ty.is(.bool)) {
685968 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
696979 inline else => |x| return w.print("{d}", .{@as(f64, @floatCast(x))}),
697980 },
698981 .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 },
699986 else => unreachable, // not a value
700987 }
701988}
......@@ -703,26 +990,44 @@ pub fn print(v: Value, ty: Type, comp: *const Compilation, w: anytype) @TypeOf(w
703990pub fn printString(bytes: []const u8, ty: Type, comp: *const Compilation, w: anytype) @TypeOf(w).Error!void {
704991 const size: Compilation.CharUnitSize = @enumFromInt(ty.elemType().sizeof(comp).?);
705992 const without_null = bytes[0 .. bytes.len - @intFromEnum(size)];
993 try w.writeByte('"');
706994 switch (size) {
707 inline .@"1", .@"2" => |sz| {
708 const data_slice: []const sz.Type() = @alignCast(std.mem.bytesAsSlice(sz.Type(), without_null));
709 const formatter = if (sz == .@"1") std.zig.fmtEscapes(data_slice) else std.unicode.fmtUtf16Le(data_slice);
710 try w.print("\"{}\"", .{formatter});
995 .@"1" => try w.print("{}", .{std.zig.fmtEscapes(without_null)}),
996 .@"2" => {
997 var items: [2]u16 = undefined;
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 }
7111017 },
7121018 .@"4" => {
713 try w.writeByte('"');
714 const data_slice = std.mem.bytesAsSlice(u32, without_null);
715 var buf: [4]u8 = undefined;
716 for (data_slice) |item| {
717 if (item <= std.math.maxInt(u21) and std.unicode.utf8ValidCodepoint(@intCast(item))) {
718 const codepoint: u21 = @intCast(item);
719 const written = std.unicode.utf8Encode(codepoint, &buf) catch unreachable;
720 try w.print("{s}", .{buf[0..written]});
1019 var item: [1]u32 = undefined;
1020 const data_slice = std.mem.sliceAsBytes(item[0..1]);
1021 for (0..@divExact(without_null.len, 4)) |n| {
1022 @memcpy(data_slice, without_null[n * 4 ..][0..4]);
1023 if (item[0] <= std.math.maxInt(u21) and std.unicode.utf8ValidCodepoint(@intCast(item[0]))) {
1024 const codepoint: u21 = @intCast(item[0]);
1025 try w.print("{u}", .{codepoint});
7211026 } else {
722 try w.print("\\x{x}", .{item});
1027 try w.print("\\x{x}", .{item[0]});
7231028 }
7241029 }
725 try w.writeByte('"');
7261030 },
7271031 }
1032 try w.writeByte('"');
7281033}
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 {
4545 .c_static_assert = comp.langopts.standard.atLeast(.c11),
4646 .c_thread_local = comp.langopts.standard.atLeast(.c11) and target_util.isTlsSupported(comp.target),
4747 };
48 inline for (std.meta.fields(@TypeOf(list))) |f| {
48 inline for (@typeInfo(@TypeOf(list)).@"struct".fields) |f| {
4949 if (std.mem.eql(u8, f.name, ext)) return @field(list, f.name);
5050 }
5151 return false;
......@@ -69,7 +69,7 @@ pub fn hasExtension(comp: *Compilation, ext: []const u8) bool {
6969 .matrix_types = false, // TODO
7070 .matrix_types_scalar_division = false, // TODO
7171 };
72 inline for (std.meta.fields(@TypeOf(list))) |f| {
72 inline for (@typeInfo(@TypeOf(list)).@"struct".fields) |f| {
7373 if (std.mem.eql(u8, f.name, ext)) return @field(list, f.name);
7474 }
7575 return false;
lib/compiler/aro/aro/record_layout.zig+44-46
......@@ -19,6 +19,13 @@ const OngoingBitfield = struct {
1919 unused_size_bits: u64,
2020};
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
2229const SysVContext = struct {
2330 /// Does the record have an __attribute__((packed)) annotation.
2431 attr_packed: bool,
......@@ -36,14 +43,8 @@ const SysVContext = struct {
3643 comp: *const Compilation,
3744
3845 fn init(ty: Type, comp: *const Compilation, pragma_pack: ?u8) SysVContext {
39 var pack_value: ?u64 = null;
40 if (pragma_pack) |pak| {
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 }
46 const pack_value: ?u64 = if (pragma_pack) |pak| @as(u64, pak) * BITS_PER_BYTE else null;
47 const req_align = @as(u32, (ty.requestedAlignment(comp) orelse 1)) * BITS_PER_BYTE;
4748 return SysVContext{
4849 .attr_packed = ty.hasAttribute(.@"packed"),
4950 .max_field_align_bits = pack_value,
......@@ -55,7 +56,7 @@ const SysVContext = struct {
5556 };
5657 }
5758
58 fn layoutFields(self: *SysVContext, rec: *const Record) void {
59 fn layoutFields(self: *SysVContext, rec: *const Record) !void {
5960 for (rec.fields, 0..) |*fld, fld_indx| {
6061 if (fld.ty.specifier == .invalid) continue;
6162 const type_layout = computeLayout(fld.ty, self.comp);
......@@ -65,12 +66,12 @@ const SysVContext = struct {
6566 field_attrs = attrs[fld_indx];
6667 }
6768 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);
6970 } else {
7071 if (fld.isRegularField()) {
71 fld.layout = self.layoutRegularField(field_attrs, type_layout);
72 fld.layout = try self.layoutRegularField(field_attrs, type_layout);
7273 } 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());
7475 }
7576 }
7677 }
......@@ -99,8 +100,8 @@ const SysVContext = struct {
99100 field: *const Field,
100101 field_attrs: ?[]const Attribute,
101102 field_layout: TypeLayout,
102 ) FieldLayout {
103 const annotation_alignment_bits = BITS_PER_BYTE * (Type.annotationAlignment(self.comp, field_attrs) orelse 1);
103 ) !FieldLayout {
104 const annotation_alignment_bits = BITS_PER_BYTE * @as(u32, (Type.annotationAlignment(self.comp, Attribute.Iterator.initSlice(field_attrs)) orelse 1));
104105 const is_attr_packed = self.attr_packed or isPacked(field_attrs);
105106 const ignore_type_alignment = ignoreTypeAlignment(is_attr_packed, field.bit_width, self.ongoing_bitfield, field_layout);
106107
......@@ -157,7 +158,7 @@ const SysVContext = struct {
157158 field_alignment_bits: u64,
158159 is_named: bool,
159160 width: u64,
160 ) FieldLayout {
161 ) !FieldLayout {
161162 std.debug.assert(width <= ty_size_bits); // validated in parser
162163
163164 // In a union, the size of the underlying type does not affect the size of the union.
......@@ -194,8 +195,8 @@ const SysVContext = struct {
194195 .unused_size_bits = ty_size_bits - width,
195196 };
196197 }
197 const offset_bits = std.mem.alignForward(u64, self.size_bits, field_alignment_bits);
198 self.size_bits = if (width == 0) offset_bits else offset_bits + ty_size_bits;
198 const offset_bits = try alignForward(self.size_bits, field_alignment_bits);
199 self.size_bits = if (width == 0) offset_bits else try std.math.add(u64, offset_bits, ty_size_bits);
199200 if (!is_named) return .{};
200201 return .{
201202 .offset_bits = offset_bits,
......@@ -207,16 +208,16 @@ const SysVContext = struct {
207208 self: *SysVContext,
208209 ty_size_bits: u64,
209210 field_alignment_bits: u64,
210 ) FieldLayout {
211 ) !FieldLayout {
211212 self.ongoing_bitfield = null;
212213 // A struct field starts at the next offset in the struct that is properly
213214 // aligned with respect to the start of the struct. See test case 0033.
214215 // 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
217218 // Set the size of the record to the maximum of the current size and the end of
218219 // 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
221222 return .{
222223 .offset_bits = offset_bits,
......@@ -228,7 +229,7 @@ const SysVContext = struct {
228229 self: *SysVContext,
229230 fld_attrs: ?[]const Attribute,
230231 fld_layout: TypeLayout,
231 ) FieldLayout {
232 ) !FieldLayout {
232233 var fld_align_bits = fld_layout.field_alignment_bits;
233234
234235 // If the struct or the field is packed, then the alignment of the underlying type is
......@@ -239,8 +240,8 @@ const SysVContext = struct {
239240
240241 // The field alignment can be increased by __attribute__((aligned)) annotations on the
241242 // field. See test case 0085.
242 if (Type.annotationAlignment(self.comp, fld_attrs)) |anno| {
243 fld_align_bits = @max(fld_align_bits, anno * BITS_PER_BYTE);
243 if (Type.annotationAlignment(self.comp, Attribute.Iterator.initSlice(fld_attrs))) |anno| {
244 fld_align_bits = @max(fld_align_bits, @as(u32, anno) * BITS_PER_BYTE);
244245 }
245246
246247 // #pragma pack takes precedence over all other attributes. See test cases 0084 and
......@@ -251,12 +252,12 @@ const SysVContext = struct {
251252
252253 // A struct field starts at the next offset in the struct that is properly
253254 // 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);
255256 const size_bits = fld_layout.size_bits;
256257
257258 // The alignment of a record is the maximum of its field alignments. See test cases
258259 // 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));
260261 self.aligned_bits = @max(self.aligned_bits, fld_align_bits);
261262
262263 return .{
......@@ -271,7 +272,7 @@ const SysVContext = struct {
271272 fld_layout: TypeLayout,
272273 is_named: bool,
273274 bit_width: u64,
274 ) FieldLayout {
275 ) !FieldLayout {
275276 const ty_size_bits = fld_layout.size_bits;
276277 var ty_fld_algn_bits: u32 = fld_layout.field_alignment_bits;
277278
......@@ -301,7 +302,7 @@ const SysVContext = struct {
301302 const attr_packed = self.attr_packed or isPacked(fld_attrs);
302303 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
306307 const first_unused_bit: u64 = if (self.is_union) 0 else self.size_bits;
307308 var field_align_bits: u64 = 1;
......@@ -322,7 +323,7 @@ const SysVContext = struct {
322323 // - the alignment of the type is larger than its size,
323324 // then it is aligned to the type's field alignment. See test case 0083.
324325 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
327328 const does_field_cross_boundary = start_bit % ty_fld_algn_bits + bit_width > ty_size_bits;
328329
......@@ -349,8 +350,8 @@ const SysVContext = struct {
349350 }
350351 }
351352
352 const offset_bits = std.mem.alignForward(u64, first_unused_bit, field_align_bits);
353 self.size_bits = @max(self.size_bits, offset_bits + bit_width);
353 const offset_bits = try alignForward(first_unused_bit, field_align_bits);
354 self.size_bits = @max(self.size_bits, try std.math.add(u64, offset_bits, bit_width));
354355
355356 // Unnamed fields do not contribute to the record alignment except on a few targets.
356357 // See test case 0079.
......@@ -419,10 +420,7 @@ const MsvcContext = struct {
419420
420421 // The required alignment can be increased by adding a __declspec(align)
421422 // annotation. See test case 0023.
422 var must_align: u29 = BITS_PER_BYTE;
423 if (ty.requestedAlignment(comp)) |req_align| {
424 must_align = req_align * BITS_PER_BYTE;
425 }
423 const must_align = @as(u32, (ty.requestedAlignment(comp) orelse 1)) * BITS_PER_BYTE;
426424 return MsvcContext{
427425 .req_align_bits = must_align,
428426 .pointer_align_bits = must_align,
......@@ -436,15 +434,15 @@ const MsvcContext = struct {
436434 };
437435 }
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 {
440438 const type_layout = computeLayout(fld.ty, self.comp);
441439
442440 // The required alignment of the field is the maximum of the required alignment of the
443441 // underlying type and the __declspec(align) annotation on the field itself.
444442 // See test case 0028.
445443 var req_align = type_layout.required_alignment_bits;
446 if (Type.annotationAlignment(self.comp, fld_attrs)) |anno| {
447 req_align = @max(anno * BITS_PER_BYTE, req_align);
444 if (Type.annotationAlignment(self.comp, Attribute.Iterator.initSlice(fld_attrs))) |anno| {
445 req_align = @max(@as(u32, anno) * BITS_PER_BYTE, req_align);
448446 }
449447
450448 // The required alignment of a record is the maximum of the required alignments of its
......@@ -480,7 +478,7 @@ const MsvcContext = struct {
480478 }
481479 }
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 {
484482 if (bit_width == 0) {
485483 // A zero-sized bit-field that does not follow a non-zero-sized bit-field does not affect
486484 // the overall layout of the record. Even in a union where the order would otherwise
......@@ -522,7 +520,7 @@ const MsvcContext = struct {
522520 self.pointer_align_bits = @max(self.pointer_align_bits, p_align);
523521 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);
526524 self.size_bits = if (bit_width == 0) offset_bits else offset_bits + ty_size_bits;
527525
528526 break :bits offset_bits;
......@@ -534,7 +532,7 @@ const MsvcContext = struct {
534532 return .{ .offset_bits = offset_bits, .size_bits = bit_width };
535533 }
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 {
538536 self.contains_non_bitfield = true;
539537 self.ongoing_bitfield = null;
540538 // The alignment of the field affects both the pointer alignment and the field
......@@ -543,7 +541,7 @@ const MsvcContext = struct {
543541 self.field_align_bits = @max(self.field_align_bits, field_align);
544542 const offset_bits = switch (self.is_union) {
545543 true => 0,
546 false => std.mem.alignForward(u64, self.size_bits, field_align),
544 false => try alignForward(self.size_bits, field_align),
547545 };
548546 self.size_bits = @max(self.size_bits, offset_bits + size_bits);
549547 return .{ .offset_bits = offset_bits, .size_bits = size_bits };
......@@ -569,14 +567,14 @@ const MsvcContext = struct {
569567 }
570568};
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 {
573571 switch (comp.langopts.emulate) {
574572 .gcc, .clang => {
575573 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
581579 rec.type_layout = .{
582580 .size_bits = context.size_bits,
......@@ -594,7 +592,7 @@ pub fn compute(rec: *Type.Record, ty: Type, comp: *const Compilation, pragma_pac
594592 field_attrs = attrs[fld_indx];
595593 }
596594
597 fld.layout = context.layoutField(fld, field_attrs);
595 fld.layout = try context.layoutField(fld, field_attrs);
598596 }
599597 if (context.size_bits == 0) {
600598 // 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
602600 // ensure that there are no zero-sized records.
603601 context.handleZeroSizedRecord();
604602 }
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);
606604 rec.type_layout = .{
607605 .size_bits = context.size_bits,
608606 .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 {
3535
3636/// intptr_t for this target
3737pub fn intPtrType(target: std.Target) Type {
38 switch (target.os.tag) {
39 .haiku => return .{ .specifier = .long },
40 else => {},
41 }
38 if (target.os.tag == .haiku) return .{ .specifier = .long };
4239
4340 switch (target.cpu.arch) {
4441 .aarch64, .aarch64_be => switch (target.os.tag) {
......@@ -127,6 +124,14 @@ pub fn int64Type(target: std.Target) Type {
127124 return .{ .specifier = .long_long };
128125}
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
130135/// This function returns 1 if function alignment is not observable or settable.
131136pub fn defaultFunctionAlignment(target: std.Target) u8 {
132137 return switch (target.cpu.arch) {
......@@ -474,6 +479,7 @@ pub fn get32BitArchVariant(target: std.Target) ?std.Target {
474479 .kalimba,
475480 .lanai,
476481 .wasm32,
482 .spirv,
477483 .spirv32,
478484 .loongarch32,
479485 .dxil,
......@@ -544,6 +550,7 @@ pub fn get64BitArchVariant(target: std.Target) ?std.Target {
544550 .powerpcle => copy.cpu.arch = .powerpc64le,
545551 .riscv32 => copy.cpu.arch = .riscv64,
546552 .sparc => copy.cpu.arch = .sparc64,
553 .spirv => copy.cpu.arch = .spirv64,
547554 .spirv32 => copy.cpu.arch = .spirv64,
548555 .thumb => copy.cpu.arch = .aarch64,
549556 .thumbeb => copy.cpu.arch = .aarch64_be,
......@@ -599,6 +606,7 @@ pub fn toLLVMTriple(target: std.Target, buf: []u8) []const u8 {
599606 .xtensa => "xtensa",
600607 .nvptx => "nvptx",
601608 .nvptx64 => "nvptx64",
609 .spirv => "spirv",
602610 .spirv32 => "spirv32",
603611 .spirv64 => "spirv64",
604612 .kalimba => "kalimba",
......@@ -646,9 +654,10 @@ pub fn toLLVMTriple(target: std.Target, buf: []u8) []const u8 {
646654 .ios => "ios",
647655 .tvos => "tvos",
648656 .watchos => "watchos",
649 .visionos => "xros",
650657 .driverkit => "driverkit",
651658 .shadermodel => "shadermodel",
659 .visionos => "xros",
660 .serenity => "serenity",
652661 .opencl,
653662 .opengl,
654663 .vulkan,
......@@ -707,6 +716,7 @@ pub fn toLLVMTriple(target: std.Target, buf: []u8) []const u8 {
707716 .callable => "callable",
708717 .mesh => "mesh",
709718 .amplification => "amplification",
719 .ohos => "openhos",
710720 };
711721 writer.writeAll(llvm_abi) catch unreachable;
712722 return stream.getWritten();
lib/compiler/aro/aro/text_literal.zig+2-2
......@@ -71,7 +71,7 @@ pub const Kind = enum {
7171 pub fn maxCodepoint(kind: Kind, comp: *const Compilation) u21 {
7272 return @intCast(switch (kind) {
7373 .char => std.math.maxInt(u7),
74 .wide => @min(0x10FFFF, comp.types.wchar.maxInt(comp)),
74 .wide => @min(0x10FFFF, comp.wcharMax()),
7575 .utf_8 => std.math.maxInt(u7),
7676 .utf_16 => std.math.maxInt(u16),
7777 .utf_32 => 0x10FFFF,
......@@ -83,7 +83,7 @@ pub const Kind = enum {
8383 pub fn maxInt(kind: Kind, comp: *const Compilation) u32 {
8484 return @intCast(switch (kind) {
8585 .char, .utf_8 => std.math.maxInt(u8),
86 .wide => comp.types.wchar.maxInt(comp),
86 .wide => comp.wcharMax(),
8787 .utf_16 => std.math.maxInt(u16),
8888 .utf_32 => std.math.maxInt(u32),
8989 .unterminated => unreachable,
lib/compiler/aro/aro/toolchains/Linux.zig+1-1
......@@ -423,7 +423,7 @@ test Linux {
423423 defer arena_instance.deinit();
424424 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());
427427 defer comp.deinit();
428428 comp.environment = .{
429429 .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 {
3434pub const Key = union(enum) {
3535 int_ty: u16,
3636 float_ty: u16,
37 complex_ty: u16,
3738 ptr_ty,
3839 noreturn_ty,
3940 void_ty,
......@@ -62,6 +63,7 @@ pub const Key = union(enum) {
6263 }
6364 },
6465 float: Float,
66 complex: Complex,
6567 bytes: []const u8,
6668
6769 pub const Float = union(enum) {
......@@ -71,6 +73,13 @@ pub const Key = union(enum) {
7173 f80: f80,
7274 f128: f128,
7375 };
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
7584 pub fn hash(key: Key) u32 {
7685 var hasher = Hash.init(0);
......@@ -89,6 +98,12 @@ pub const Key = union(enum) {
8998 @as(std.meta.Int(.unsigned, @bitSizeOf(@TypeOf(data))), @bitCast(data)),
9099 ),
91100 },
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 },
92107 .int => |repr| {
93108 var space: Tag.Int.BigIntSpace = undefined;
94109 const big = repr.toBigInt(&space);
......@@ -154,6 +169,14 @@ pub const Key = union(enum) {
154169 128 => return .f128,
155170 else => unreachable,
156171 },
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 },
157180 .ptr_ty => return .ptr,
158181 .func_ty => return .func,
159182 .noreturn_ty => return .noreturn,
......@@ -199,6 +222,11 @@ pub const Ref = enum(u32) {
199222 zero = max - 16,
200223 one = max - 17,
201224 null = max - 18,
225 cf16 = max - 19,
226 cf32 = max - 20,
227 cf64 = max - 21,
228 cf80 = max - 22,
229 cf128 = max - 23,
202230 _,
203231};
204232
......@@ -224,6 +252,11 @@ pub const OptRef = enum(u32) {
224252 zero = max - 16,
225253 one = max - 17,
226254 null = max - 18,
255 cf16 = max - 19,
256 cf32 = max - 20,
257 cf64 = max - 21,
258 cf80 = max - 22,
259 cf128 = max - 23,
227260 _,
228261};
229262
......@@ -232,6 +265,8 @@ pub const Tag = enum(u8) {
232265 int_ty,
233266 /// `data` is `u16`
234267 float_ty,
268 /// `data` is `u16`
269 complex_ty,
235270 /// `data` is index to `Array`
236271 array_ty,
237272 /// `data` is index to `Vector`
......@@ -254,6 +289,16 @@ pub const Tag = enum(u8) {
254289 f80,
255290 /// `data` is `F128`
256291 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,
257302 /// `data` is `Bytes`
258303 bytes,
259304 /// `data` is `Record`
......@@ -354,6 +399,134 @@ pub const Tag = enum(u8) {
354399 }
355400 };
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
357530 pub const Bytes = struct {
358531 strings_index: u32,
359532 len: u32,
......@@ -407,6 +580,12 @@ pub fn put(i: *Interner, gpa: Allocator, key: Key) !Ref {
407580 .data = bits,
408581 });
409582 },
583 .complex_ty => |bits| {
584 i.items.appendAssumeCapacity(.{
585 .tag = .complex_ty,
586 .data = bits,
587 });
588 },
410589 .array_ty => |info| {
411590 const split_len = PackedU64.init(info.len);
412591 i.items.appendAssumeCapacity(.{
......@@ -493,6 +672,28 @@ pub fn put(i: *Interner, gpa: Allocator, key: Key) !Ref {
493672 .data = try i.addExtra(gpa, Tag.F128.pack(data)),
494673 }),
495674 },
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 },
496697 .bytes => |bytes| {
497698 const strings_index: u32 = @intCast(i.strings.items.len);
498699 try i.strings.appendSlice(gpa, bytes);
......@@ -564,6 +765,10 @@ pub fn get(i: *const Interner, ref: Ref) Key {
564765 .zero => return .{ .int = .{ .u64 = 0 } },
565766 .one => return .{ .int = .{ .u64 = 1 } },
566767 .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 },
567772 else => {},
568773 }
569774
......@@ -572,6 +777,7 @@ pub fn get(i: *const Interner, ref: Ref) Key {
572777 return switch (item.tag) {
573778 .int_ty => .{ .int_ty = @intCast(data) },
574779 .float_ty => .{ .float_ty = @intCast(data) },
780 .complex_ty => .{ .complex_ty = @intCast(data) },
575781 .array_ty => {
576782 const array_ty = i.extraData(Tag.Array, data);
577783 return .{ .array_ty = .{
......@@ -612,6 +818,26 @@ pub fn get(i: *const Interner, ref: Ref) Key {
612818 const float = i.extraData(Tag.F128, data);
613819 return .{ .float = .{ .f128 = float.get() } };
614820 },
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 },
615841 .bytes => {
616842 const bytes = i.extraData(Tag.Bytes, data);
617843 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 {
3737 for (b.decls.values()) |*decl| {
3838 decl.deinit(b.gpa);
3939 }
40 b.decls.deinit(b.gpa);
4041 b.arena.deinit();
4142 b.instructions.deinit(b.gpa);
4243 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 {
1616
1717pub fn deinit(obj: *Object) void {
1818 switch (obj.format) {
19 .elf => @as(*Elf, @fieldParentPtr("obj", obj)).deinit(),
19 .elf => @as(*Elf, @alignCast(@fieldParentPtr("obj", obj))).deinit(),
2020 else => unreachable,
2121 }
2222}
......@@ -32,7 +32,7 @@ pub const Section = union(enum) {
3232
3333pub fn getSection(obj: *Object, section: Section) !*std.ArrayList(u8) {
3434 switch (obj.format) {
35 .elf => return @as(*Elf, @fieldParentPtr("obj", obj)).getSection(section),
35 .elf => return @as(*Elf, @alignCast(@fieldParentPtr("obj", obj))).getSection(section),
3636 else => unreachable,
3737 }
3838}
......@@ -53,21 +53,21 @@ pub fn declareSymbol(
5353 size: u64,
5454) ![]const u8 {
5555 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),
5757 else => unreachable,
5858 }
5959}
6060
6161pub fn addRelocation(obj: *Object, name: []const u8, section: Section, address: u64, addend: i64) !void {
6262 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),
6464 else => unreachable,
6565 }
6666}
6767
6868pub fn finish(obj: *Object, file: std.fs.File) !void {
6969 switch (obj.format) {
70 .elf => return @as(*Elf, @fieldParentPtr("obj", obj)).finish(file),
70 .elf => return @as(*Elf, @alignCast(@fieldParentPtr("obj", obj))).finish(file),
7171 else => unreachable,
7272 }
7373}
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
731731 .float => return ZigTag.type.create(c.arena, "f32"),
732732 .double => return ZigTag.type.create(c.arena, "f64"),
733733 .long_double => return ZigTag.type.create(c.arena, "c_longdouble"),
734 .float80 => return ZigTag.type.create(c.arena, "f80"),
735734 .float128 => return ZigTag.type.create(c.arena, "f128"),
736735 .@"enum" => {
737736 const enum_decl = ty.data.@"enum";
......@@ -1799,7 +1798,7 @@ pub fn main() !void {
17991798
18001799 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());
18031802 defer aro_comp.deinit();
18041803
18051804 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 {
126126 defer aro_arena_state.deinit();
127127 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());
130130 defer comp.deinit();
131131
132132 var argv = std.ArrayList([]const u8).init(comp.gpa);
lib/compiler/resinator/preprocess.zig+1-1
......@@ -59,7 +59,7 @@ pub fn preprocess(
5959
6060 if (hasAnyErrors(comp)) return error.PreprocessError;
6161
62 try pp.prettyPrintTokens(writer);
62 try pp.prettyPrintTokens(writer, .result_only);
6363
6464 if (maybe_dependencies_list) |dependencies_list| {
6565 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 {
230230 };
231231
232232 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());
234234 defer aro_comp.deinit();
235235
236236 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 {
268268 // new scope to ensure definition file is written before passing the path to WriteImportLibrary
269269 const def_final_file = try o_dir.createFile(final_def_basename, .{ .truncate = true });
270270 defer def_final_file.close();
271 try pp.prettyPrintTokens(def_final_file.writer());
271 try pp.prettyPrintTokens(def_final_file.writer(), .result_only);
272272 }
273273
274274 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
52585258 const end_c = c.source_manager.getCharacterData(end_loc);
52595259 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());
52625262 defer comp.deinit();
52635263 const result = comp.addSourceFromBuffer("", begin_c[0..slice_len]) catch return error.OutOfMemory;
52645264