authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2024-03-06 21:17:41+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-03-06 14:17:41-05:00
log90ab8ea9e681a4ffac0b4dc500e3ec489014e12f
tree5c6d1d6cd24fc5dfca968e11df234cb0db8e83bf
parent1e67f5021159ed1d9888cf2d0b9f04ef73222f7d
signaturebadge-check Signed by PGP key B5690EEEBB952194

Sync Aro sources (#19199)

ref: 02353ad9f17f659e173f68975a442fcec3dd2c94

26 files changed, 851 insertions(+), 275 deletions(-)

.gitattributes+1-1
......@@ -12,4 +12,4 @@ lib/libcxx/** linguist-vendored
1212lib/libcxxabi/** linguist-vendored
1313lib/libunwind/** linguist-vendored
1414lib/tsan/** linguist-vendored
15deps/** linguist-vendored
15lib/compiler/aro/** linguist-vendored
lib/compiler/aro/README.md+1-2
......@@ -20,8 +20,7 @@ int main(void) {
2020 printf("Hello, world!\n");
2121 return 0;
2222}
23$ zig build run -- hello.c -o hello
23$ zig build && ./zig-out/bin/arocc hello.c -o hello
2424$ ./hello
2525Hello, world!
26$
2726```
lib/compiler/aro/aro/Attribute/names.zig+6-16
......@@ -1,4 +1,4 @@
1//! Autogenerated by GenerateDef from deps/aro/aro/Attribute/names.def, do not edit
1//! Autogenerated by GenerateDef from src/aro/Attribute/names.def, do not edit
22// zig fmt: off
33
44const std = @import("std");
......@@ -142,15 +142,7 @@ pub fn nameFromUniqueIndex(index: u16, buf: []u8) []u8 {
142142 return fbs.getWritten();
143143}
144144
145/// We're 1 bit shy of being able to fit this in a u32:
146/// - char only contains 0-9, a-z, A-Z, and _, so it could use a enum(u6) with a way to convert <-> u8
147/// (note: this would have a performance cost that may make the u32 not worth it)
148/// - number has a max value of > 2047 and < 4095 (the first _ node has the largest number),
149/// so it could fit into a u12
150/// - child_index currently has a max of > 4095 and < 8191, so it could fit into a u13
151///
152/// with the end_of_word/end_of_list 2 bools, that makes 33 bits total
153const Node = packed struct(u64) {
145const Node = packed struct(u32) {
154146 char: u8,
155147 /// Nodes are numbered with "an integer which gives the number of words that
156148 /// would be accepted by the automaton starting from that state." This numbering
......@@ -158,18 +150,16 @@ const Node = packed struct(u64) {
158150 /// (L is the number of words accepted by the automaton) and the words themselves."
159151 ///
160152 /// Essentially, this allows us to have a minimal perfect hashing scheme such that
161 /// it's possible to store & lookup the properties of each builtin using a separate array.
162 number: u16,
163 /// If true, this node is the end of a valid builtin.
153 /// it's possible to store & lookup the properties of each name using a separate array.
154 number: u8,
155 /// If true, this node is the end of a valid name.
164156 /// Note: This does not necessarily mean that this node does not have child nodes.
165157 end_of_word: bool,
166158 /// If true, this node is the end of a sibling list.
167159 /// If false, then (index + 1) will contain the next sibling.
168160 end_of_list: bool,
169 /// Padding bits to get to u64, unsure if there's some way to use these to improve something.
170 _extra: u22 = 0,
171161 /// Index of the first child of this node.
172 child_index: u16,
162 child_index: u14,
173163};
174164
175165const dafsa = [_]Node{
lib/compiler/aro/aro/Builtins.zig+1-4
......@@ -99,10 +99,7 @@ fn createType(desc: TypeDescription, it: *TypeDescription.TypeIterator, comp: *c
9999 }
100100 },
101101 .h => builder.combine(undefined, .fp16, 0) catch unreachable,
102 .x => {
103 // Todo: _Float16
104 return .{ .specifier = .invalid };
105 },
102 .x => builder.combine(undefined, .float16, 0) catch unreachable,
106103 .y => {
107104 // Todo: __bf16
108105 return .{ .specifier = .invalid };
lib/compiler/aro/aro/Builtins/Builtin.zig+1-1
......@@ -1,4 +1,4 @@
1//! Autogenerated by GenerateDef from deps/aro/aro/Builtins/Builtin.def, do not edit
1//! Autogenerated by GenerateDef from src/aro/Builtins/Builtin.def, do not edit
22// zig fmt: off
33
44const std = @import("std");
lib/compiler/aro/aro/Compilation.zig+39-20
......@@ -241,6 +241,12 @@ pub const SystemDefinesMode = enum {
241241fn generateSystemDefines(comp: *Compilation, w: anytype) !void {
242242 const ptr_width = comp.target.ptrBitWidth();
243243
244 if (comp.langopts.gnuc_version > 0) {
245 try w.print("#define __GNUC__ {d}\n", .{comp.langopts.gnuc_version / 10_000});
246 try w.print("#define __GNUC_MINOR__ {d}\n", .{comp.langopts.gnuc_version / 100 % 100});
247 try w.print("#define __GNUC_PATCHLEVEL__ {d}\n", .{comp.langopts.gnuc_version % 100});
248 }
249
244250 // os macros
245251 switch (comp.target.os.tag) {
246252 .linux => try w.writeAll(
......@@ -419,6 +425,25 @@ fn generateSystemDefines(comp: *Compilation, w: anytype) !void {
419425 \\
420426 );
421427
428 // TODO: Set these to target-specific constants depending on backend capabilities
429 // For now they are just set to the "may be lock-free" value
430 try w.writeAll(
431 \\#define __ATOMIC_BOOL_LOCK_FREE 1
432 \\#define __ATOMIC_CHAR_LOCK_FREE 1
433 \\#define __ATOMIC_CHAR16_T_LOCK_FREE 1
434 \\#define __ATOMIC_CHAR32_T_LOCK_FREE 1
435 \\#define __ATOMIC_WCHAR_T_LOCK_FREE 1
436 \\#define __ATOMIC_SHORT_LOCK_FREE 1
437 \\#define __ATOMIC_INT_LOCK_FREE 1
438 \\#define __ATOMIC_LONG_LOCK_FREE 1
439 \\#define __ATOMIC_LLONG_LOCK_FREE 1
440 \\#define __ATOMIC_POINTER_LOCK_FREE 1
441 \\
442 );
443 if (comp.langopts.hasChar8_T()) {
444 try w.writeAll("#define __ATOMIC_CHAR8_T_LOCK_FREE 1\n");
445 }
446
422447 // types
423448 if (comp.getCharSignedness() == .unsigned) try w.writeAll("#define __CHAR_UNSIGNED__ 1\n");
424449 try w.writeAll("#define __CHAR_BIT__ 8\n");
......@@ -438,6 +463,7 @@ fn generateSystemDefines(comp: *Compilation, w: anytype) !void {
438463 try comp.generateIntMaxAndWidth(w, "PTRDIFF", comp.types.ptrdiff);
439464 try comp.generateIntMaxAndWidth(w, "INTPTR", comp.types.intptr);
440465 try comp.generateIntMaxAndWidth(w, "UINTPTR", comp.types.intptr.makeIntegerUnsigned());
466 try comp.generateIntMaxAndWidth(w, "SIG_ATOMIC", target_util.sigAtomicType(comp.target));
441467
442468 // int widths
443469 try w.print("#define __BITINT_MAXWIDTH__ {d}\n", .{bit_int_max_bits});
......@@ -474,6 +500,8 @@ fn generateSystemDefines(comp: *Compilation, w: anytype) !void {
474500 try generateTypeMacro(w, mapper, "__PTRDIFF_TYPE__", comp.types.ptrdiff, comp.langopts);
475501 try generateTypeMacro(w, mapper, "__SIZE_TYPE__", comp.types.size, comp.langopts);
476502 try generateTypeMacro(w, mapper, "__WCHAR_TYPE__", comp.types.wchar, comp.langopts);
503 try generateTypeMacro(w, mapper, "__CHAR16_TYPE__", comp.types.uint_least16_t, comp.langopts);
504 try generateTypeMacro(w, mapper, "__CHAR32_TYPE__", comp.types.uint_least32_t, comp.langopts);
477505
478506 try comp.generateExactWidthTypes(w, mapper);
479507 try comp.generateFastAndLeastWidthTypes(w, mapper);
......@@ -518,7 +546,6 @@ pub fn generateBuiltinMacros(comp: *Compilation, system_defines_mode: SystemDefi
518546
519547 // standard macros
520548 try buf.appendSlice(
521 \\#define __STDC_NO_ATOMICS__ 1
522549 \\#define __STDC_NO_COMPLEX__ 1
523550 \\#define __STDC_NO_THREADS__ 1
524551 \\#define __STDC_NO_VLA__ 1
......@@ -1030,9 +1057,8 @@ pub fn getCharSignedness(comp: *const Compilation) std.builtin.Signedness {
10301057 return comp.langopts.char_signedness_override orelse comp.target.charSignedness();
10311058}
10321059
1033pub fn defineSystemIncludes(comp: *Compilation, aro_dir: []const u8) !void {
1034 var stack_fallback = std.heap.stackFallback(path_buf_stack_limit, comp.gpa);
1035 const allocator = stack_fallback.get();
1060/// Add built-in aro headers directory to system include paths
1061pub fn addBuiltinIncludeDir(comp: *Compilation, aro_dir: []const u8) !void {
10361062 var search_path = aro_dir;
10371063 while (std.fs.path.dirname(search_path)) |dirname| : (search_path = dirname) {
10381064 var base_dir = std.fs.cwd().openDir(dirname, .{}) catch continue;
......@@ -1044,23 +1070,12 @@ pub fn defineSystemIncludes(comp: *Compilation, aro_dir: []const u8) !void {
10441070 try comp.system_include_dirs.append(comp.gpa, path);
10451071 break;
10461072 } else return error.AroIncludeNotFound;
1073}
10471074
1048 if (comp.target.os.tag == .linux) {
1049 const triple_str = try comp.target.linuxTriple(allocator);
1050 defer allocator.free(triple_str);
1051
1052 const multiarch_path = try std.fs.path.join(allocator, &.{ "/usr/include", triple_str });
1053 defer allocator.free(multiarch_path);
1054
1055 if (!std.meta.isError(std.fs.accessAbsolute(multiarch_path, .{}))) {
1056 const duped = try comp.gpa.dupe(u8, multiarch_path);
1057 errdefer comp.gpa.free(duped);
1058 try comp.system_include_dirs.append(comp.gpa, duped);
1059 }
1060 }
1061 const usr_include = try comp.gpa.dupe(u8, "/usr/include");
1062 errdefer comp.gpa.free(usr_include);
1063 try comp.system_include_dirs.append(comp.gpa, usr_include);
1075pub fn addSystemIncludeDir(comp: *Compilation, path: []const u8) !void {
1076 const duped = try comp.gpa.dupe(u8, path);
1077 errdefer comp.gpa.free(duped);
1078 try comp.system_include_dirs.append(comp.gpa, duped);
10641079}
10651080
10661081pub fn getSource(comp: *const Compilation, id: Source.Id) Source {
......@@ -1331,6 +1346,10 @@ pub fn hasInclude(
13311346 /// __has_include vs __has_include_next
13321347 which: WhichInclude,
13331348) !bool {
1349 if (mem.indexOfScalar(u8, filename, 0) != null) {
1350 return false;
1351 }
1352
13341353 const cwd = std.fs.cwd();
13351354 if (std.fs.path.isAbsolute(filename)) {
13361355 if (which == .next) return false;
lib/compiler/aro/aro/Diagnostics.zig+3-1
......@@ -208,6 +208,8 @@ pub const Options = struct {
208208 @"unsupported-embed-param": Kind = .default,
209209 @"unused-result": Kind = .default,
210210 normalized: Kind = .default,
211 @"shift-count-negative": Kind = .default,
212 @"shift-count-overflow": Kind = .default,
211213};
212214
213215const Diagnostics = @This();
......@@ -291,7 +293,7 @@ pub fn addExtra(
291293 .kind = .note,
292294 .extra = .{ .unsigned = expansion_locs.len - d.macro_backtrace_limit },
293295 });
294 i = half - 1;
296 i = half -| 1;
295297 while (i > 0) {
296298 i -= 1;
297299 d.list.appendAssumeCapacity(.{
lib/compiler/aro/aro/Diagnostics/messages.zig+11-1
......@@ -1,4 +1,4 @@
1//! Autogenerated by GenerateDef from deps/aro/aro/Diagnostics/messages.def, do not edit
1//! Autogenerated by GenerateDef from src/aro/Diagnostics/messages.def, do not edit
22// zig fmt: off
33
44const std = @import("std");
......@@ -504,6 +504,11 @@ pub const Tag = enum {
504504 c23_auto_single_declarator,
505505 c32_auto_requires_initializer,
506506 c23_auto_scalar_init,
507 negative_shift_count,
508 too_big_shift_count,
509 complex_conj,
510 overflow_builtin_requires_int,
511 overflow_result_requires_ptr,
507512
508513 pub fn property(tag: Tag) Properties {
509514 return named_data[@intFromEnum(tag)];
......@@ -1005,6 +1010,11 @@ pub const Tag = enum {
10051010 .{ .msg = "'auto' can only be used with a single declarator", .kind = .@"error" },
10061011 .{ .msg = "'auto' requires an initializer", .kind = .@"error" },
10071012 .{ .msg = "'auto' requires a scalar initializer", .kind = .@"error" },
1013 .{ .msg = "shift count is negative", .opt = W("shift-count-negative"), .kind = .warning, .all = true },
1014 .{ .msg = "shift count >= width of type", .opt = W("shift-count-overflow"), .kind = .warning, .all = true },
1015 .{ .msg = "ISO C does not support '~' for complex conjugation of '{s}'", .opt = W("pedantic"), .extra = .str, .kind = .off },
1016 .{ .msg = "operand argument to overflow builtin must be an integer ('{s}' invalid)", .extra = .str, .kind = .@"error" },
1017 .{ .msg = "result argument to overflow builtin must be a pointer to a non-const integer ('{s}' invalid)", .extra = .str, .kind = .@"error" },
10081018 };
10091019};
10101020};
lib/compiler/aro/aro/Driver.zig+27-3
......@@ -12,6 +12,7 @@ const Preprocessor = @import("Preprocessor.zig");
1212const Source = @import("Source.zig");
1313const Toolchain = @import("Toolchain.zig");
1414const target_util = @import("target.zig");
15const GCCVersion = @import("Driver/GCCVersion.zig");
1516
1617pub const Linker = enum {
1718 ld,
......@@ -43,6 +44,9 @@ verbose_pp: bool = false,
4344verbose_ir: bool = false,
4445verbose_linker_args: bool = false,
4546color: ?bool = null,
47nobuiltininc: bool = false,
48nostdinc: bool = false,
49nostdlibinc: bool = false,
4650
4751/// Full path to the aro executable
4852aro_name: []const u8 = "",
......@@ -95,6 +99,7 @@ pub const usage =
9599 \\ -fcolor-diagnostics Enable colors in diagnostics
96100 \\ -fno-color-diagnostics Disable colors in diagnostics
97101 \\ -fdeclspec Enable support for __declspec attributes
102 \\ -fgnuc-version=<value> Controls value of __GNUC__ and related macros. Set to 0 or empty to disable them.
98103 \\ -fno-declspec Disable support for __declspec attributes
99104 \\ -ffp-eval-method=[source|double|extended]
100105 \\ Evaluation method to use for floating-point arithmetic
......@@ -127,6 +132,10 @@ pub const usage =
127132 \\ -isystem Add directory to SYSTEM include search path
128133 \\ --emulate=[clang|gcc|msvc]
129134 \\ Select which C compiler to emulate (default clang)
135 \\ -nobuiltininc Do not search the compiler's builtin directory for include files
136 \\ -nostdinc, --no-standard-includes
137 \\ Do not search the standard system directories or compiler builtin directories for include files.
138 \\ -nostdlibinc Do not search the standard system directories for include files, but do search compiler builtin include directories
130139 \\ -o <file> Write output to <file>
131140 \\ -P, --no-line-commands Disable linemarker output in -E mode
132141 \\ -pedantic Warn on language extensions
......@@ -180,6 +189,7 @@ pub fn parseArgs(
180189 var i: usize = 1;
181190 var comment_arg: []const u8 = "";
182191 var hosted: ?bool = null;
192 var gnuc_version: []const u8 = "4.2.1"; // default value set by clang
183193 while (i < args.len) : (i += 1) {
184194 const arg = args[i];
185195 if (mem.startsWith(u8, arg, "-") and arg.len > 1) {
......@@ -303,6 +313,10 @@ pub fn parseArgs(
303313 d.only_syntax = true;
304314 } else if (mem.startsWith(u8, arg, "-fno-syntax-only")) {
305315 d.only_syntax = false;
316 } else if (mem.eql(u8, arg, "-fgnuc-version=")) {
317 gnuc_version = "0";
318 } else if (option(arg, "-fgnuc-version=")) |version| {
319 gnuc_version = version;
306320 } else if (mem.startsWith(u8, arg, "-isystem")) {
307321 var path = arg["-isystem".len..];
308322 if (path.len == 0) {
......@@ -421,6 +435,12 @@ pub fn parseArgs(
421435 d.nodefaultlibs = true;
422436 } else if (mem.eql(u8, arg, "-nolibc")) {
423437 d.nolibc = true;
438 } else if (mem.eql(u8, arg, "-nobuiltininc")) {
439 d.nobuiltininc = true;
440 } else if (mem.eql(u8, arg, "-nostdinc") or mem.eql(u8, arg, "--no-standard-includes")) {
441 d.nostdinc = true;
442 } else if (mem.eql(u8, arg, "-nostdlibinc")) {
443 d.nostdlibinc = true;
424444 } else if (mem.eql(u8, arg, "-nostdlib")) {
425445 d.nostdlib = true;
426446 } else if (mem.eql(u8, arg, "-nostartfiles")) {
......@@ -459,6 +479,11 @@ pub fn parseArgs(
459479 d.comp.target.os.tag = .freestanding;
460480 }
461481 }
482 const version = GCCVersion.parse(gnuc_version);
483 if (version.major == -1) {
484 return d.fatal("invalid value '{0s}' in '-fgnuc-version={0s}'", .{gnuc_version});
485 }
486 d.comp.langopts.gnuc_version = version.toUnsigned();
462487 return false;
463488}
464489
......@@ -558,7 +583,8 @@ pub fn main(d: *Driver, tc: *Toolchain, args: []const []const u8, comptime fast_
558583 try d.comp.addDiagnostic(.{ .tag = .cli_unused_link_object, .extra = .{ .str = obj } }, &.{});
559584 };
560585
561 d.comp.defineSystemIncludes(d.aro_name) catch |er| switch (er) {
586 try tc.discover();
587 tc.defineSystemIncludes() catch |er| switch (er) {
562588 error.OutOfMemory => return error.OutOfMemory,
563589 error.AroIncludeNotFound => return d.fatal("unable to find Aro builtin headers", .{}),
564590 };
......@@ -763,8 +789,6 @@ fn dumpLinkerArgs(items: []const []const u8) !void {
763789/// The entry point of the Aro compiler.
764790/// **MAY call `exit` if `fast_exit` is set.**
765791pub fn invokeLinker(d: *Driver, tc: *Toolchain, comptime fast_exit: bool) !void {
766 try tc.discover();
767
768792 var argv = std.ArrayList([]const u8).init(d.comp.gpa);
769793 defer argv.deinit();
770794
lib/compiler/aro/aro/Driver/GCCVersion.zig+10
......@@ -98,6 +98,16 @@ pub fn order(a: GCCVersion, b: GCCVersion) Order {
9898 return .eq;
9999}
100100
101/// Used for determining __GNUC__ macro values
102/// This matches clang's logic for overflowing values
103pub fn toUnsigned(self: GCCVersion) u32 {
104 var result: u32 = 0;
105 if (self.major > 0) result = @as(u32, @intCast(self.major)) *% 10_000;
106 if (self.minor > 0) result +%= @as(u32, @intCast(self.minor)) *% 100;
107 if (self.patch > 0) result +%= @as(u32, @intCast(self.patch));
108 return result;
109}
110
101111test parse {
102112 const versions = [10]GCCVersion{
103113 parse("5"),
lib/compiler/aro/aro/Hideset.zig created+191
......@@ -0,0 +1,191 @@
1//! A hideset is a linked list (implemented as an array so that elements are identified by 4-byte indices)
2//! of the set of identifiers from which a token was expanded.
3//! During macro expansion, if a token would otherwise be expanded, but its hideset contains
4//! the token itself, then it is not expanded
5//! Most tokens have an empty hideset, and the hideset is not needed once expansion is complete,
6//! so we use a hash map to store them instead of directly storing them with the token.
7//! The C standard underspecifies the algorithm for updating a token's hideset;
8//! we use the one here: https://www.spinellis.gr/blog/20060626/cpp.algo.pdf
9
10const std = @import("std");
11const mem = std.mem;
12const Allocator = mem.Allocator;
13const Source = @import("Source.zig");
14const Compilation = @import("Compilation.zig");
15const Tokenizer = @import("Tokenizer.zig");
16
17pub const Hideset = @This();
18
19const Identifier = struct {
20 id: Source.Id = .unused,
21 byte_offset: u32 = 0,
22
23 fn slice(self: Identifier, comp: *const Compilation) []const u8 {
24 var tmp_tokenizer = Tokenizer{
25 .buf = comp.getSource(self.id).buf,
26 .langopts = comp.langopts,
27 .index = self.byte_offset,
28 .source = .generated,
29 };
30 const res = tmp_tokenizer.next();
31 return tmp_tokenizer.buf[res.start..res.end];
32 }
33
34 fn fromLocation(loc: Source.Location) Identifier {
35 return .{
36 .id = loc.id,
37 .byte_offset = loc.byte_offset,
38 };
39 }
40};
41
42const Item = struct {
43 identifier: Identifier = .{},
44 next: Index = .none,
45
46 const List = std.MultiArrayList(Item);
47};
48
49const Index = enum(u32) {
50 none = std.math.maxInt(u32),
51 _,
52};
53
54map: std.AutoHashMapUnmanaged(Identifier, Index) = .{},
55/// Used for computing intersection of two lists; stored here so that allocations can be retained
56/// until hideset is deinit'ed
57intersection_map: std.AutoHashMapUnmanaged(Identifier, void) = .{},
58linked_list: Item.List = .{},
59comp: *const Compilation,
60
61/// Invalidated if the underlying MultiArrayList slice is reallocated due to resize
62const Iterator = struct {
63 slice: Item.List.Slice,
64 i: Index,
65
66 fn next(self: *Iterator) ?Identifier {
67 if (self.i == .none) return null;
68 defer self.i = self.slice.items(.next)[@intFromEnum(self.i)];
69 return self.slice.items(.identifier)[@intFromEnum(self.i)];
70 }
71};
72
73pub fn deinit(self: *Hideset) void {
74 self.map.deinit(self.comp.gpa);
75 self.intersection_map.deinit(self.comp.gpa);
76 self.linked_list.deinit(self.comp.gpa);
77}
78
79pub fn clearRetainingCapacity(self: *Hideset) void {
80 self.linked_list.shrinkRetainingCapacity(0);
81 self.map.clearRetainingCapacity();
82}
83
84pub fn clearAndFree(self: *Hideset) void {
85 self.map.clearAndFree(self.comp.gpa);
86 self.intersection_map.clearAndFree(self.comp.gpa);
87 self.linked_list.shrinkAndFree(self.comp.gpa, 0);
88}
89
90/// Iterator is invalidated if the underlying MultiArrayList slice is reallocated due to resize
91fn iterator(self: *const Hideset, idx: Index) Iterator {
92 return Iterator{
93 .slice = self.linked_list.slice(),
94 .i = idx,
95 };
96}
97
98pub fn get(self: *const Hideset, loc: Source.Location) Index {
99 return self.map.get(Identifier.fromLocation(loc)) orelse .none;
100}
101
102pub fn put(self: *Hideset, loc: Source.Location, value: Index) !void {
103 try self.map.put(self.comp.gpa, Identifier.fromLocation(loc), value);
104}
105
106fn ensureUnusedCapacity(self: *Hideset, new_size: usize) !void {
107 try self.linked_list.ensureUnusedCapacity(self.comp.gpa, new_size);
108}
109
110/// Creates a one-item list with contents `identifier`
111fn createNodeAssumeCapacity(self: *Hideset, identifier: Identifier) Index {
112 const next_idx = self.linked_list.len;
113 self.linked_list.appendAssumeCapacity(.{ .identifier = identifier });
114 return @enumFromInt(next_idx);
115}
116
117/// Create a new list with `identifier` at the front followed by `tail`
118pub fn prepend(self: *Hideset, loc: Source.Location, tail: Index) !Index {
119 const new_idx = self.linked_list.len;
120 try self.linked_list.append(self.comp.gpa, .{ .identifier = Identifier.fromLocation(loc), .next = tail });
121 return @enumFromInt(new_idx);
122}
123
124/// Copy a, then attach b at the end
125pub fn @"union"(self: *Hideset, a: Index, b: Index) !Index {
126 var cur: Index = .none;
127 var head: Index = b;
128 try self.ensureUnusedCapacity(self.len(a));
129 var it = self.iterator(a);
130 while (it.next()) |identifier| {
131 const new_idx = self.createNodeAssumeCapacity(identifier);
132 if (head == b) {
133 head = new_idx;
134 }
135 if (cur != .none) {
136 self.linked_list.items(.next)[@intFromEnum(cur)] = new_idx;
137 }
138 cur = new_idx;
139 }
140 if (cur != .none) {
141 self.linked_list.items(.next)[@intFromEnum(cur)] = b;
142 }
143 return head;
144}
145
146pub fn contains(self: *const Hideset, list: Index, str: []const u8) bool {
147 var it = self.iterator(list);
148 while (it.next()) |identifier| {
149 if (mem.eql(u8, str, identifier.slice(self.comp))) return true;
150 }
151 return false;
152}
153
154fn len(self: *const Hideset, list: Index) usize {
155 const nexts = self.linked_list.items(.next);
156 var cur = list;
157 var count: usize = 0;
158 while (cur != .none) : (count += 1) {
159 cur = nexts[@intFromEnum(cur)];
160 }
161 return count;
162}
163
164pub fn intersection(self: *Hideset, a: Index, b: Index) !Index {
165 if (a == .none or b == .none) return .none;
166 self.intersection_map.clearRetainingCapacity();
167
168 var cur: Index = .none;
169 var head: Index = .none;
170 var it = self.iterator(a);
171 var a_len: usize = 0;
172 while (it.next()) |identifier| : (a_len += 1) {
173 try self.intersection_map.put(self.comp.gpa, identifier, {});
174 }
175 try self.ensureUnusedCapacity(@min(a_len, self.len(b)));
176
177 it = self.iterator(b);
178 while (it.next()) |identifier| {
179 if (self.intersection_map.contains(identifier)) {
180 const new_idx = self.createNodeAssumeCapacity(identifier);
181 if (head == .none) {
182 head = new_idx;
183 }
184 if (cur != .none) {
185 self.linked_list.items(.next)[@intFromEnum(cur)] = new_idx;
186 }
187 cur = new_idx;
188 }
189 }
190 return head;
191}
lib/compiler/aro/aro/LangOpts.zig+5
......@@ -135,6 +135,11 @@ preserve_comments: bool = false,
135135/// Preserve comments in macros when preprocessing
136136preserve_comments_in_macros: bool = false,
137137
138/// Used ONLY for generating __GNUC__ and related macros. Does not control the presence/absence of any features
139/// Encoded as major * 10,000 + minor * 100 + patch
140/// e.g. 4.2.1 == 40201
141gnuc_version: u32 = 0,
142
138143pub fn setStandard(self: *LangOpts, name: []const u8) error{InvalidStandard}!void {
139144 self.standard = Standard.NameMap.get(name) orelse return error.InvalidStandard;
140145}
lib/compiler/aro/aro/Parser.zig+171-30
......@@ -403,7 +403,7 @@ pub fn errExtra(p: *Parser, tag: Diagnostics.Tag, tok_i: TokenIndex, extra: Diag
403403 .tag = tag,
404404 .loc = loc,
405405 .extra = extra,
406 }, tok.expansionSlice());
406 }, p.pp.expansionSlice(tok_i));
407407}
408408
409409pub fn errTok(p: *Parser, tag: Diagnostics.Tag, tok_i: TokenIndex) Compilation.Error!void {
......@@ -432,6 +432,11 @@ pub fn removeNull(p: *Parser, str: Value) !Value {
432432}
433433
434434pub fn typeStr(p: *Parser, ty: Type) ![]const u8 {
435 if (@import("builtin").mode != .Debug) {
436 if (ty.is(.invalid)) {
437 return "Tried to render invalid type - this is an aro bug.";
438 }
439 }
435440 if (Type.Builder.fromType(ty).str(p.comp.langopts)) |str| return str;
436441 const strings_top = p.strings.items.len;
437442 defer p.strings.items.len = strings_top;
......@@ -446,6 +451,11 @@ pub fn typePairStr(p: *Parser, a: Type, b: Type) ![]const u8 {
446451}
447452
448453pub fn typePairStrExtra(p: *Parser, a: Type, msg: []const u8, b: Type) ![]const u8 {
454 if (@import("builtin").mode != .Debug) {
455 if (a.is(.invalid) or b.is(.invalid)) {
456 return "Tried to render invalid type - this is an aro bug.";
457 }
458 }
449459 const strings_top = p.strings.items.len;
450460 defer p.strings.items.len = strings_top;
451461
......@@ -635,7 +645,6 @@ fn diagnoseIncompleteDefinitions(p: *Parser) !void {
635645 const tys = node_slices.items(.ty);
636646 const data = node_slices.items(.data);
637647
638 const err_start = p.comp.diagnostics.list.items.len;
639648 for (p.decl_buf.items) |decl_node| {
640649 const idx = @intFromEnum(decl_node);
641650 switch (tags[idx]) {
......@@ -656,8 +665,6 @@ fn diagnoseIncompleteDefinitions(p: *Parser) !void {
656665 try p.errStr(.tentative_definition_incomplete, tentative_def_tok, type_str);
657666 try p.errStr(.forward_declaration_here, data[idx].decl_ref, type_str);
658667 }
659 const errors_added = p.comp.diagnostics.list.items.len - err_start;
660 assert(errors_added == 2 * p.tentative_defs.count()); // Each tentative def should add an error + note
661668}
662669
663670/// root : (decl | assembly ';' | staticAssert)*
......@@ -2201,7 +2208,15 @@ fn recordSpec(p: *Parser) Error!Type {
22012208 } else {
22022209 record_ty.fields = try p.arena.dupe(Type.Record.Field, p.record_buf.items[record_buf_top..]);
22032210 }
2204 if (old_field_attr_start < p.field_attr_buf.items.len) {
2211 const attr_count = p.field_attr_buf.items.len - old_field_attr_start;
2212 const record_decls = p.decl_buf.items[decl_buf_top..];
2213 if (attr_count > 0) {
2214 if (attr_count != record_decls.len) {
2215 // A mismatch here means that non-field decls were parsed. This can happen if there were
2216 // parse errors during attribute parsing. Bail here because if there are any field attributes,
2217 // there must be exactly one per field.
2218 return error.ParsingFailed;
2219 }
22052220 const field_attr_slice = p.field_attr_buf.items[old_field_attr_start..];
22062221 const duped = try p.arena.dupe([]const Attribute, field_attr_slice);
22072222 record_ty.field_attributes = duped.ptr;
......@@ -2242,7 +2257,6 @@ fn recordSpec(p: *Parser) Error!Type {
22422257 .ty = ty,
22432258 .data = .{ .bin = .{ .lhs = .none, .rhs = .none } },
22442259 };
2245 const record_decls = p.decl_buf.items[decl_buf_top..];
22462260 switch (record_decls.len) {
22472261 0 => {},
22482262 1 => node.data = .{ .bin = .{ .lhs = record_decls[0], .rhs = .none } },
......@@ -2560,6 +2574,7 @@ fn enumSpec(p: *Parser) Error!Type {
25602574 if (field.ty.eql(Type.int, p.comp, false)) continue;
25612575
25622576 const sym = p.syms.get(field.name, .vars) orelse continue;
2577 if (sym.kind != .enumeration) continue; // already an error
25632578
25642579 var res = Result{ .node = field.node, .ty = field.ty, .val = sym.val };
25652580 const dest_ty = if (p.comp.fixedEnumTagSpecifier()) |some|
......@@ -4603,24 +4618,31 @@ fn nodeIsNoreturn(p: *Parser, node: NodeIndex) NoreturnKind {
46034618 },
46044619 .compound_stmt_two => {
46054620 const data = p.nodes.items(.data)[@intFromEnum(node)];
4606 if (data.bin.rhs != .none) return p.nodeIsNoreturn(data.bin.rhs);
4607 if (data.bin.lhs != .none) return p.nodeIsNoreturn(data.bin.lhs);
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;
4623 if (lhs_type == .complex or rhs_type == .complex) return .complex;
4624 if (lhs_type == .yes or rhs_type == .yes) return .yes;
46084625 return .no;
46094626 },
46104627 .compound_stmt => {
46114628 const data = p.nodes.items(.data)[@intFromEnum(node)];
4612 return p.nodeIsNoreturn(p.data.items[data.range.end - 1]);
4629 var it = data.range.start;
4630 while (it != data.range.end) : (it += 1) {
4631 const kind = p.nodeIsNoreturn(p.data.items[it]);
4632 if (kind != .no) return kind;
4633 }
4634 return .no;
46134635 },
46144636 .labeled_stmt => {
46154637 const data = p.nodes.items(.data)[@intFromEnum(node)];
46164638 return p.nodeIsNoreturn(data.decl.node);
46174639 },
4618 .switch_stmt => {
4640 .default_stmt => {
46194641 const data = p.nodes.items(.data)[@intFromEnum(node)];
4620 if (data.bin.rhs == .none) return .complex;
4621 if (p.nodeIsNoreturn(data.bin.rhs) == .yes) return .yes;
4622 return .complex;
4642 if (data.un == .none) return .no;
4643 return p.nodeIsNoreturn(data.un);
46234644 },
4645 .while_stmt, .do_while_stmt, .for_decl_stmt, .forever_stmt, .for_stmt, .switch_stmt => return .complex,
46244646 else => return .no,
46254647 }
46264648}
......@@ -4787,7 +4809,11 @@ const CallExpr = union(enum) {
47874809 Builtin.tagFromName("__va_start").?,
47884810 Builtin.tagFromName("va_start").?,
47894811 => arg_idx != 1,
4790 Builtin.tagFromName("__builtin_complex").? => false,
4812 Builtin.tagFromName("__builtin_complex").?,
4813 Builtin.tagFromName("__builtin_add_overflow").?,
4814 Builtin.tagFromName("__builtin_sub_overflow").?,
4815 Builtin.tagFromName("__builtin_mul_overflow").?,
4816 => false,
47914817 else => true,
47924818 },
47934819 };
......@@ -4800,6 +4826,7 @@ const CallExpr = union(enum) {
48004826 }
48014827
48024828 fn checkVarArg(self: CallExpr, p: *Parser, first_after: TokenIndex, param_tok: TokenIndex, arg: *Result, arg_idx: u32) !void {
4829 @setEvalBranchQuota(10_000);
48034830 if (self == .standard) return;
48044831
48054832 const builtin_tok = p.nodes.items(.data)[@intFromEnum(self.builtin.node)].decl.name;
......@@ -4809,6 +4836,11 @@ const CallExpr = union(enum) {
48094836 Builtin.tagFromName("va_start").?,
48104837 => return p.checkVaStartArg(builtin_tok, first_after, param_tok, arg, arg_idx),
48114838 Builtin.tagFromName("__builtin_complex").? => return p.checkComplexArg(builtin_tok, first_after, param_tok, arg, arg_idx),
4839 Builtin.tagFromName("__builtin_add_overflow").?,
4840 Builtin.tagFromName("__builtin_sub_overflow").?,
4841 Builtin.tagFromName("__builtin_mul_overflow").?,
4842 => return p.checkArithOverflowArg(builtin_tok, first_after, param_tok, arg, arg_idx),
4843
48124844 else => {},
48134845 }
48144846 }
......@@ -4823,16 +4855,44 @@ const CallExpr = union(enum) {
48234855 return switch (self) {
48244856 .standard => null,
48254857 .builtin => |builtin| switch (builtin.tag) {
4826 Builtin.tagFromName("__builtin_complex").? => 2,
4827
4858 Builtin.tagFromName("__c11_atomic_thread_fence").?,
4859 Builtin.tagFromName("__c11_atomic_signal_fence").?,
4860 Builtin.tagFromName("__c11_atomic_is_lock_free").?,
4861 => 1,
4862
4863 Builtin.tagFromName("__builtin_complex").?,
4864 Builtin.tagFromName("__c11_atomic_load").?,
4865 Builtin.tagFromName("__c11_atomic_init").?,
4866 => 2,
4867
4868 Builtin.tagFromName("__c11_atomic_store").?,
4869 Builtin.tagFromName("__c11_atomic_exchange").?,
4870 Builtin.tagFromName("__c11_atomic_fetch_add").?,
4871 Builtin.tagFromName("__c11_atomic_fetch_sub").?,
4872 Builtin.tagFromName("__c11_atomic_fetch_or").?,
4873 Builtin.tagFromName("__c11_atomic_fetch_xor").?,
4874 Builtin.tagFromName("__c11_atomic_fetch_and").?,
48284875 Builtin.tagFromName("__atomic_fetch_add").?,
48294876 Builtin.tagFromName("__atomic_fetch_sub").?,
48304877 Builtin.tagFromName("__atomic_fetch_and").?,
48314878 Builtin.tagFromName("__atomic_fetch_xor").?,
48324879 Builtin.tagFromName("__atomic_fetch_or").?,
48334880 Builtin.tagFromName("__atomic_fetch_nand").?,
4881 Builtin.tagFromName("__atomic_add_fetch").?,
4882 Builtin.tagFromName("__atomic_sub_fetch").?,
4883 Builtin.tagFromName("__atomic_and_fetch").?,
4884 Builtin.tagFromName("__atomic_xor_fetch").?,
4885 Builtin.tagFromName("__atomic_or_fetch").?,
4886 Builtin.tagFromName("__atomic_nand_fetch").?,
4887 Builtin.tagFromName("__builtin_add_overflow").?,
4888 Builtin.tagFromName("__builtin_sub_overflow").?,
4889 Builtin.tagFromName("__builtin_mul_overflow").?,
48344890 => 3,
48354891
4892 Builtin.tagFromName("__c11_atomic_compare_exchange_strong").?,
4893 Builtin.tagFromName("__c11_atomic_compare_exchange_weak").?,
4894 => 5,
4895
48364896 Builtin.tagFromName("__atomic_compare_exchange").?,
48374897 Builtin.tagFromName("__atomic_compare_exchange_n").?,
48384898 => 6,
......@@ -4845,15 +4905,45 @@ const CallExpr = union(enum) {
48454905 return switch (self) {
48464906 .standard => callable_ty.returnType(),
48474907 .builtin => |builtin| switch (builtin.tag) {
4908 Builtin.tagFromName("__c11_atomic_exchange").? => {
4909 if (p.list_buf.items.len != 4) return Type.invalid; // wrong number of arguments; already an error
4910 const second_param = p.list_buf.items[2];
4911 return p.nodes.items(.ty)[@intFromEnum(second_param)];
4912 },
4913 Builtin.tagFromName("__c11_atomic_load").? => {
4914 if (p.list_buf.items.len != 3) return Type.invalid; // wrong number of arguments; already an error
4915 const first_param = p.list_buf.items[1];
4916 const ty = p.nodes.items(.ty)[@intFromEnum(first_param)];
4917 if (!ty.isPtr()) return Type.invalid;
4918 return ty.elemType();
4919 },
4920
48484921 Builtin.tagFromName("__atomic_fetch_add").?,
4922 Builtin.tagFromName("__atomic_add_fetch").?,
4923 Builtin.tagFromName("__c11_atomic_fetch_add").?,
4924
48494925 Builtin.tagFromName("__atomic_fetch_sub").?,
4926 Builtin.tagFromName("__atomic_sub_fetch").?,
4927 Builtin.tagFromName("__c11_atomic_fetch_sub").?,
4928
48504929 Builtin.tagFromName("__atomic_fetch_and").?,
4930 Builtin.tagFromName("__atomic_and_fetch").?,
4931 Builtin.tagFromName("__c11_atomic_fetch_and").?,
4932
48514933 Builtin.tagFromName("__atomic_fetch_xor").?,
4934 Builtin.tagFromName("__atomic_xor_fetch").?,
4935 Builtin.tagFromName("__c11_atomic_fetch_xor").?,
4936
48524937 Builtin.tagFromName("__atomic_fetch_or").?,
4938 Builtin.tagFromName("__atomic_or_fetch").?,
4939 Builtin.tagFromName("__c11_atomic_fetch_or").?,
4940
48534941 Builtin.tagFromName("__atomic_fetch_nand").?,
4942 Builtin.tagFromName("__atomic_nand_fetch").?,
4943 Builtin.tagFromName("__c11_atomic_fetch_nand").?,
48544944 => {
4855 if (p.list_buf.items.len < 2) return Type.invalid; // not enough arguments; already an error
4856 const second_param = p.list_buf.items[p.list_buf.items.len - 2];
4945 if (p.list_buf.items.len != 3) return Type.invalid; // wrong number of arguments; already an error
4946 const second_param = p.list_buf.items[2];
48574947 return p.nodes.items(.ty)[@intFromEnum(second_param)];
48584948 },
48594949 Builtin.tagFromName("__builtin_complex").? => {
......@@ -4863,8 +4953,17 @@ const CallExpr = union(enum) {
48634953 },
48644954 Builtin.tagFromName("__atomic_compare_exchange").?,
48654955 Builtin.tagFromName("__atomic_compare_exchange_n").?,
4956 Builtin.tagFromName("__c11_atomic_is_lock_free").?,
48664957 => .{ .specifier = .bool },
48674958 else => callable_ty.returnType(),
4959
4960 Builtin.tagFromName("__c11_atomic_compare_exchange_strong").?,
4961 Builtin.tagFromName("__c11_atomic_compare_exchange_weak").?,
4962 => {
4963 if (p.list_buf.items.len != 6) return Type.invalid; // wrong number of arguments
4964 const third_param = p.list_buf.items[3];
4965 return p.nodes.items(.ty)[@intFromEnum(third_param)];
4966 },
48684967 },
48694968 };
48704969 }
......@@ -4975,15 +5074,19 @@ pub const Result = struct {
49755074 .call_expr_one => {
49765075 const fn_ptr = p.nodes.items(.data)[@intFromEnum(cur_node)].bin.lhs;
49775076 const fn_ty = p.nodes.items(.ty)[@intFromEnum(fn_ptr)].elemType();
4978 if (fn_ty.hasAttribute(.nodiscard)) try p.errStr(.nodiscard_unused, expr_start, "TODO get name");
4979 if (fn_ty.hasAttribute(.warn_unused_result)) try p.errStr(.warn_unused_result, expr_start, "TODO get name");
5077 const cast_info = p.nodes.items(.data)[@intFromEnum(fn_ptr)].cast.operand;
5078 const decl_ref = p.nodes.items(.data)[@intFromEnum(cast_info)].decl_ref;
5079 if (fn_ty.hasAttribute(.nodiscard)) try p.errStr(.nodiscard_unused, expr_start, p.tokSlice(decl_ref));
5080 if (fn_ty.hasAttribute(.warn_unused_result)) try p.errStr(.warn_unused_result, expr_start, p.tokSlice(decl_ref));
49805081 return;
49815082 },
49825083 .call_expr => {
49835084 const fn_ptr = p.data.items[p.nodes.items(.data)[@intFromEnum(cur_node)].range.start];
49845085 const fn_ty = p.nodes.items(.ty)[@intFromEnum(fn_ptr)].elemType();
4985 if (fn_ty.hasAttribute(.nodiscard)) try p.errStr(.nodiscard_unused, expr_start, "TODO get name");
4986 if (fn_ty.hasAttribute(.warn_unused_result)) try p.errStr(.warn_unused_result, expr_start, "TODO get name");
5086 const cast_info = p.nodes.items(.data)[@intFromEnum(fn_ptr)].cast.operand;
5087 const decl_ref = p.nodes.items(.data)[@intFromEnum(cast_info)].decl_ref;
5088 if (fn_ty.hasAttribute(.nodiscard)) try p.errStr(.nodiscard_unused, expr_start, p.tokSlice(decl_ref));
5089 if (fn_ty.hasAttribute(.warn_unused_result)) try p.errStr(.warn_unused_result, expr_start, p.tokSlice(decl_ref));
49875090 return;
49885091 },
49895092 .stmt_expr => {
......@@ -6356,8 +6459,15 @@ fn shiftExpr(p: *Parser) Error!Result {
63566459 try rhs.expect(p);
63576460
63586461 if (try lhs.adjustTypes(shr.?, &rhs, p, .integer)) {
6462 if (rhs.val.compare(.lt, Value.zero, p.comp)) {
6463 try p.errStr(.negative_shift_count, shl orelse shr.?, try rhs.str(p));
6464 }
6465 if (rhs.val.compare(.gte, try Value.int(lhs.ty.bitSizeof(p.comp).?, p.comp), p.comp)) {
6466 try p.errStr(.too_big_shift_count, shl orelse shr.?, try rhs.str(p));
6467 }
63596468 if (shl != null) {
6360 if (try lhs.val.shl(lhs.val, rhs.val, lhs.ty, p.comp)) try p.errOverflow(shl.?, lhs);
6469 if (try lhs.val.shl(lhs.val, rhs.val, lhs.ty, p.comp) and
6470 lhs.ty.signedness(p.comp) != .unsigned) try p.errOverflow(shl.?, lhs);
63616471 } else {
63626472 lhs.val = try lhs.val.shr(rhs.val, lhs.ty, p.comp);
63636473 }
......@@ -6381,9 +6491,11 @@ fn addExpr(p: *Parser) Error!Result {
63816491 const lhs_ty = lhs.ty;
63826492 if (try lhs.adjustTypes(minus.?, &rhs, p, if (plus != null) .add else .sub)) {
63836493 if (plus != null) {
6384 if (try lhs.val.add(lhs.val, rhs.val, lhs.ty, p.comp)) try p.errOverflow(plus.?, lhs);
6494 if (try lhs.val.add(lhs.val, rhs.val, lhs.ty, p.comp) and
6495 lhs.ty.signedness(p.comp) != .unsigned) try p.errOverflow(plus.?, lhs);
63856496 } else {
6386 if (try lhs.val.sub(lhs.val, rhs.val, lhs.ty, p.comp)) try p.errOverflow(minus.?, lhs);
6497 if (try lhs.val.sub(lhs.val, rhs.val, lhs.ty, p.comp) and
6498 lhs.ty.signedness(p.comp) != .unsigned) try p.errOverflow(minus.?, lhs);
63876499 }
63886500 }
63896501 if (lhs.ty.specifier != .invalid and lhs_ty.isPtr() and !lhs_ty.isVoidStar() and lhs_ty.elemType().hasIncompleteSize()) {
......@@ -6420,9 +6532,11 @@ fn mulExpr(p: *Parser) Error!Result {
64206532
64216533 if (try lhs.adjustTypes(percent.?, &rhs, p, if (tag == .mod_expr) .integer else .arithmetic)) {
64226534 if (mul != null) {
6423 if (try lhs.val.mul(lhs.val, rhs.val, lhs.ty, p.comp)) try p.errOverflow(mul.?, lhs);
6535 if (try lhs.val.mul(lhs.val, rhs.val, lhs.ty, p.comp) and
6536 lhs.ty.signedness(p.comp) != .unsigned) try p.errOverflow(mul.?, lhs);
64246537 } else if (div != null) {
6425 if (try lhs.val.div(lhs.val, rhs.val, lhs.ty, p.comp)) try p.errOverflow(mul.?, lhs);
6538 if (try lhs.val.div(lhs.val, rhs.val, lhs.ty, p.comp) and
6539 lhs.ty.signedness(p.comp) != .unsigned) try p.errOverflow(mul.?, lhs);
64266540 } else {
64276541 var res = try Value.rem(lhs.val, rhs.val, lhs.ty, p.comp);
64286542 if (res.opt_ref == .none) {
......@@ -6827,7 +6941,7 @@ fn unExpr(p: *Parser) Error!Result {
68276941 try p.errStr(.invalid_argument_un, tok, try p.typeStr(operand.ty));
68286942
68296943 try operand.usualUnaryConversion(p, tok);
6830 if (operand.val.is(.int, p.comp)) {
6944 if (operand.val.is(.int, p.comp) or operand.val.is(.float, p.comp)) {
68316945 _ = try operand.val.sub(Value.zero, operand.val, operand.ty, p.comp);
68326946 } else {
68336947 operand.val = .{};
......@@ -6898,6 +7012,8 @@ fn unExpr(p: *Parser) Error!Result {
68987012 if (operand.val.is(.int, p.comp)) {
68997013 operand.val = try operand.val.bitNot(operand.ty, p.comp);
69007014 }
7015 } else if (operand.ty.isComplex()) {
7016 try p.errStr(.complex_conj, tok, try p.typeStr(operand.ty));
69017017 } else {
69027018 try p.errStr(.invalid_argument_un, tok, try p.typeStr(operand.ty));
69037019 operand.val = .{};
......@@ -7334,6 +7450,20 @@ fn checkVaStartArg(p: *Parser, builtin_tok: TokenIndex, first_after: TokenIndex,
73347450 }
73357451}
73367452
7453fn checkArithOverflowArg(p: *Parser, builtin_tok: TokenIndex, first_after: TokenIndex, param_tok: TokenIndex, arg: *Result, idx: u32) !void {
7454 _ = builtin_tok;
7455 _ = first_after;
7456 if (idx <= 1) {
7457 if (!arg.ty.isInt()) {
7458 return p.errStr(.overflow_builtin_requires_int, param_tok, try p.typeStr(arg.ty));
7459 }
7460 } else if (idx == 2) {
7461 if (!arg.ty.isPtr()) return p.errStr(.overflow_result_requires_ptr, param_tok, try p.typeStr(arg.ty));
7462 const child = arg.ty.elemType();
7463 if (!child.isInt() or child.is(.bool) or child.is(.@"enum") or child.qual.@"const") return p.errStr(.overflow_result_requires_ptr, param_tok, try p.typeStr(arg.ty));
7464 }
7465}
7466
73377467fn checkComplexArg(p: *Parser, builtin_tok: TokenIndex, first_after: TokenIndex, param_tok: TokenIndex, arg: *Result, idx: u32) !void {
73387468 _ = builtin_tok;
73397469 _ = first_after;
......@@ -7880,6 +8010,7 @@ fn charLiteral(p: *Parser) Error!Result {
78808010
78818011 const slice = char_kind.contentSlice(p.tokSlice(p.tok_i));
78828012
8013 var is_multichar = false;
78838014 if (slice.len == 1 and std.ascii.isASCII(slice[0])) {
78848015 // fast path: single unescaped ASCII char
78858016 val = slice[0];
......@@ -7913,7 +8044,7 @@ fn charLiteral(p: *Parser) Error!Result {
79138044 },
79148045 };
79158046
7916 const is_multichar = chars.items.len > 1;
8047 is_multichar = chars.items.len > 1;
79178048 if (is_multichar) {
79188049 if (char_kind == .char and chars.items.len == 4) {
79198050 char_literal_parser.warn(.four_char_char_literal, .{ .none = {} });
......@@ -7956,9 +8087,19 @@ fn charLiteral(p: *Parser) Error!Result {
79568087 else
79578088 p.comp.types.intmax;
79588089
8090 var value = try Value.int(val, p.comp);
8091 // C99 6.4.4.4.10
8092 // > If an integer character constant contains a single character or escape sequence,
8093 // > its value is the one that results when an object with type char whose value is
8094 // > that of the single character or escape sequence is converted to type int.
8095 // This conversion only matters if `char` is signed and has a high-order bit of `1`
8096 if (char_kind == .char and !is_multichar and val > 0x7F and p.comp.getCharSignedness() == .signed) {
8097 try value.intCast(.{ .specifier = .char }, p.comp);
8098 }
8099
79598100 const res = Result{
79608101 .ty = if (p.in_macro) macro_ty else ty,
7961 .val = try Value.int(val, p.comp),
8102 .val = value,
79628103 .node = try p.addNode(.{ .tag = .char_literal, .ty = ty, .data = undefined }),
79638104 };
79648105 if (!p.in_macro) try p.value_map.put(res.node, res.val);
lib/compiler/aro/aro/Preprocessor.zig+269-164
......@@ -9,9 +9,12 @@ const Tokenizer = @import("Tokenizer.zig");
99const RawToken = Tokenizer.Token;
1010const Parser = @import("Parser.zig");
1111const Diagnostics = @import("Diagnostics.zig");
12const Token = @import("Tree.zig").Token;
12const Tree = @import("Tree.zig");
13const Token = Tree.Token;
14const TokenWithExpansionLocs = Tree.TokenWithExpansionLocs;
1315const Attribute = @import("Attribute.zig");
1416const features = @import("features.zig");
17const Hideset = @import("Hideset.zig");
1518
1619const DefineMap = std.StringHashMapUnmanaged(Macro);
1720const RawTokenList = std.ArrayList(RawToken);
......@@ -40,8 +43,6 @@ const Macro = struct {
4043
4144 /// Location of macro in the source
4245 loc: Source.Location,
43 start: u32,
44 end: u32,
4546
4647 fn eql(a: Macro, b: Macro, pp: *Preprocessor) bool {
4748 if (a.tokens.len != b.tokens.len) return false;
......@@ -64,11 +65,24 @@ const Macro = struct {
6465
6566const Preprocessor = @This();
6667
68const ExpansionEntry = struct {
69 idx: Tree.TokenIndex,
70 locs: [*]Source.Location,
71};
72
73const TokenState = struct {
74 tokens_len: usize,
75 expansion_entries_len: usize,
76};
77
6778comp: *Compilation,
6879gpa: mem.Allocator,
6980arena: std.heap.ArenaAllocator,
7081defines: DefineMap = .{},
82/// Do not directly mutate this; use addToken / addTokenAssumeCapacity / ensureTotalTokenCapacity / ensureUnusedTokenCapacity
7183tokens: Token.List = .{},
84/// Do not directly mutate this; must be kept in sync with `tokens`
85expansion_entries: std.MultiArrayList(ExpansionEntry) = .{},
7286token_buf: RawTokenList,
7387char_buf: std.ArrayList(u8),
7488/// Counter that is incremented each time preprocess() is called
......@@ -93,6 +107,8 @@ preserve_whitespace: bool = false,
93107/// linemarker tokens. Must be .none unless in -E mode (parser does not handle linemarkers)
94108linemarkers: Linemarkers = .none,
95109
110hideset: Hideset,
111
96112pub const parse = Parser.parse;
97113
98114pub const Linemarkers = enum {
......@@ -113,6 +129,7 @@ pub fn init(comp: *Compilation) Preprocessor {
113129 .char_buf = std.ArrayList(u8).init(comp.gpa),
114130 .poisoned_identifiers = std.StringHashMap(void).init(comp.gpa),
115131 .top_expansion_buf = ExpandBuf.init(comp.gpa),
132 .hideset = .{ .comp = comp },
116133 };
117134 comp.pragmaEvent(.before_preprocess);
118135 return pp;
......@@ -201,8 +218,6 @@ fn addBuiltinMacro(pp: *Preprocessor, name: []const u8, is_func: bool, tokens: [
201218 .var_args = false,
202219 .is_func = is_func,
203220 .loc = .{ .id = .generated },
204 .start = 0,
205 .end = 0,
206221 .is_builtin = true,
207222 });
208223}
......@@ -228,7 +243,6 @@ pub fn addBuiltinMacros(pp: *Preprocessor) !void {
228243
229244pub fn deinit(pp: *Preprocessor) void {
230245 pp.defines.deinit(pp.gpa);
231 for (pp.tokens.items(.expansion_locs)) |loc| Token.free(loc, pp.gpa);
232246 pp.tokens.deinit(pp.gpa);
233247 pp.arena.deinit();
234248 pp.token_buf.deinit();
......@@ -236,6 +250,33 @@ pub fn deinit(pp: *Preprocessor) void {
236250 pp.poisoned_identifiers.deinit();
237251 pp.include_guards.deinit(pp.gpa);
238252 pp.top_expansion_buf.deinit();
253 pp.hideset.deinit();
254 for (pp.expansion_entries.items(.locs)) |locs| TokenWithExpansionLocs.free(locs, pp.gpa);
255 pp.expansion_entries.deinit(pp.gpa);
256}
257
258/// Free buffers that are not needed after preprocessing
259fn clearBuffers(pp: *Preprocessor) void {
260 pp.token_buf.clearAndFree();
261 pp.char_buf.clearAndFree();
262 pp.top_expansion_buf.clearAndFree();
263 pp.hideset.clearAndFree();
264}
265
266pub fn expansionSlice(pp: *Preprocessor, tok: Tree.TokenIndex) []Source.Location {
267 const S = struct {
268 fn order_token_index(context: void, lhs: Tree.TokenIndex, rhs: Tree.TokenIndex) std.math.Order {
269 _ = context;
270 return std.math.order(lhs, rhs);
271 }
272 };
273
274 const indices = pp.expansion_entries.items(.idx);
275 const idx = std.sort.binarySearch(Tree.TokenIndex, tok, indices, {}, S.order_token_index) orelse return &.{};
276 const locs = pp.expansion_entries.items(.locs)[idx];
277 var i: usize = 0;
278 while (locs[i].id != .unused) : (i += 1) {}
279 return locs[0..i];
239280}
240281
241282/// Preprocess a compilation unit of sources into a parsable list of tokens.
......@@ -247,13 +288,14 @@ pub fn preprocessSources(pp: *Preprocessor, sources: []const Source) Error!void
247288 try pp.addIncludeStart(header);
248289 _ = try pp.preprocess(header);
249290 }
250 try pp.addIncludeResume(first.id, 0, 0);
291 try pp.addIncludeResume(first.id, 0, 1);
251292 const eof = try pp.preprocess(first);
252 try pp.tokens.append(pp.comp.gpa, eof);
293 try pp.addToken(eof);
294 pp.clearBuffers();
253295}
254296
255297/// Preprocess a source file, returns eof token.
256pub fn preprocess(pp: *Preprocessor, source: Source) Error!Token {
298pub fn preprocess(pp: *Preprocessor, source: Source) Error!TokenWithExpansionLocs {
257299 const eof = pp.preprocessExtra(source) catch |er| switch (er) {
258300 // This cannot occur in the main file and is handled in `include`.
259301 error.StopPreprocessing => unreachable,
......@@ -275,27 +317,27 @@ pub fn tokenize(pp: *Preprocessor, source: Source) Error!Token {
275317
276318 // Estimate how many new tokens this source will contain.
277319 const estimated_token_count = source.buf.len / 8;
278 try pp.tokens.ensureTotalCapacity(pp.gpa, pp.tokens.len + estimated_token_count);
320 try pp.ensureTotalTokenCapacity(pp.tokens.len + estimated_token_count);
279321
280322 while (true) {
281323 const tok = tokenizer.next();
282324 if (tok.id == .eof) return tokFromRaw(tok);
283 try pp.tokens.append(pp.gpa, tokFromRaw(tok));
325 try pp.addToken(tokFromRaw(tok));
284326 }
285327}
286328
287329pub fn addIncludeStart(pp: *Preprocessor, source: Source) !void {
288330 if (pp.linemarkers == .none) return;
289 try pp.tokens.append(pp.gpa, .{ .id = .include_start, .loc = .{
331 try pp.addToken(.{ .id = .include_start, .loc = .{
290332 .id = source.id,
291333 .byte_offset = std.math.maxInt(u32),
292 .line = 0,
334 .line = 1,
293335 } });
294336}
295337
296338pub fn addIncludeResume(pp: *Preprocessor, source: Source.Id, offset: u32, line: u32) !void {
297339 if (pp.linemarkers == .none) return;
298 try pp.tokens.append(pp.gpa, .{ .id = .include_resume, .loc = .{
340 try pp.addToken(.{ .id = .include_resume, .loc = .{
299341 .id = source,
300342 .byte_offset = offset,
301343 .line = line,
......@@ -328,7 +370,7 @@ fn findIncludeGuard(pp: *Preprocessor, source: Source) ?[]const u8 {
328370 return pp.tokSlice(guard);
329371}
330372
331fn preprocessExtra(pp: *Preprocessor, source: Source) MacroError!Token {
373fn preprocessExtra(pp: *Preprocessor, source: Source) MacroError!TokenWithExpansionLocs {
332374 var guard_name = pp.findIncludeGuard(source);
333375
334376 pp.preprocess_count += 1;
......@@ -340,7 +382,7 @@ fn preprocessExtra(pp: *Preprocessor, source: Source) MacroError!Token {
340382
341383 // Estimate how many new tokens this source will contain.
342384 const estimated_token_count = source.buf.len / 8;
343 try pp.tokens.ensureTotalCapacity(pp.gpa, pp.tokens.len + estimated_token_count);
385 try pp.ensureTotalTokenCapacity(pp.tokens.len + estimated_token_count);
344386
345387 var if_level: u8 = 0;
346388 var if_kind = std.PackedIntArray(u2, 256).init([1]u2{0} ** 256);
......@@ -352,7 +394,7 @@ fn preprocessExtra(pp: *Preprocessor, source: Source) MacroError!Token {
352394 while (true) {
353395 var tok = tokenizer.next();
354396 switch (tok.id) {
355 .hash => if (!start_of_line) try pp.tokens.append(pp.gpa, tokFromRaw(tok)) else {
397 .hash => if (!start_of_line) try pp.addToken(tokFromRaw(tok)) else {
356398 const directive = tokenizer.nextNoWS();
357399 switch (directive.id) {
358400 .keyword_error, .keyword_warning => {
......@@ -654,13 +696,13 @@ fn preprocessExtra(pp: *Preprocessor, source: Source) MacroError!Token {
654696 }
655697 if (pp.preserve_whitespace) {
656698 tok.id = .nl;
657 try pp.tokens.append(pp.gpa, tokFromRaw(tok));
699 try pp.addToken(tokFromRaw(tok));
658700 }
659701 },
660 .whitespace => if (pp.preserve_whitespace) try pp.tokens.append(pp.gpa, tokFromRaw(tok)),
702 .whitespace => if (pp.preserve_whitespace) try pp.addToken(tokFromRaw(tok)),
661703 .nl => {
662704 start_of_line = true;
663 if (pp.preserve_whitespace) try pp.tokens.append(pp.gpa, tokFromRaw(tok));
705 if (pp.preserve_whitespace) try pp.addToken(tokFromRaw(tok));
664706 },
665707 .eof => {
666708 if (if_level != 0) try pp.err(tok, .unterminated_conditional_directive);
......@@ -696,14 +738,14 @@ fn preprocessExtra(pp: *Preprocessor, source: Source) MacroError!Token {
696738
697739/// Get raw token source string.
698740/// Returned slice is invalidated when comp.generated_buf is updated.
699pub fn tokSlice(pp: *Preprocessor, token: RawToken) []const u8 {
741pub fn tokSlice(pp: *Preprocessor, token: anytype) []const u8 {
700742 if (token.id.lexeme()) |some| return some;
701743 const source = pp.comp.getSource(token.source);
702744 return source.buf[token.start..token.end];
703745}
704746
705747/// Convert a token from the Tokenizer into a token used by the parser.
706fn tokFromRaw(raw: RawToken) Token {
748fn tokFromRaw(raw: RawToken) TokenWithExpansionLocs {
707749 return .{
708750 .id = raw.id,
709751 .loc = .{
......@@ -725,7 +767,7 @@ fn err(pp: *Preprocessor, raw: RawToken, tag: Diagnostics.Tag) !void {
725767 }, &.{});
726768}
727769
728fn errStr(pp: *Preprocessor, tok: Token, tag: Diagnostics.Tag, str: []const u8) !void {
770fn errStr(pp: *Preprocessor, tok: TokenWithExpansionLocs, tag: Diagnostics.Tag, str: []const u8) !void {
729771 try pp.comp.addDiagnostic(.{
730772 .tag = tag,
731773 .loc = tok.loc,
......@@ -747,7 +789,7 @@ fn fatal(pp: *Preprocessor, raw: RawToken, comptime fmt: []const u8, args: anyty
747789 return error.FatalError;
748790}
749791
750fn fatalNotFound(pp: *Preprocessor, tok: Token, filename: []const u8) Compilation.Error {
792fn fatalNotFound(pp: *Preprocessor, tok: TokenWithExpansionLocs, filename: []const u8) Compilation.Error {
751793 const old = pp.comp.diagnostics.fatal_errors;
752794 pp.comp.diagnostics.fatal_errors = true;
753795 defer pp.comp.diagnostics.fatal_errors = old;
......@@ -790,7 +832,7 @@ fn expectNl(pp: *Preprocessor, tokenizer: *Tokenizer) Error!void {
790832 while (true) {
791833 const tok = tokenizer.next();
792834 if (tok.id == .nl or tok.id == .eof) return;
793 if (tok.id == .whitespace) continue;
835 if (tok.id == .whitespace or tok.id == .comment) continue;
794836 if (!sent_err) {
795837 sent_err = true;
796838 try pp.err(tok, .extra_tokens_directive_end);
......@@ -798,12 +840,24 @@ fn expectNl(pp: *Preprocessor, tokenizer: *Tokenizer) Error!void {
798840 }
799841}
800842
843fn getTokenState(pp: *const Preprocessor) TokenState {
844 return .{
845 .tokens_len = pp.tokens.len,
846 .expansion_entries_len = pp.expansion_entries.len,
847 };
848}
849
850fn restoreTokenState(pp: *Preprocessor, state: TokenState) void {
851 pp.tokens.len = state.tokens_len;
852 pp.expansion_entries.len = state.expansion_entries_len;
853}
854
801855/// Consume all tokens until a newline and parse the result into a boolean.
802856fn expr(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!bool {
803 const start = pp.tokens.len;
857 const token_state = pp.getTokenState();
804858 defer {
805 for (pp.top_expansion_buf.items) |tok| Token.free(tok.expansion_locs, pp.gpa);
806 pp.tokens.len = start;
859 for (pp.top_expansion_buf.items) |tok| TokenWithExpansionLocs.free(tok.expansion_locs, pp.gpa);
860 pp.restoreTokenState(token_state);
807861 }
808862
809863 pp.top_expansion_buf.items.len = 0;
......@@ -818,6 +872,7 @@ fn expr(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!bool {
818872 } else unreachable;
819873 if (pp.top_expansion_buf.items.len != 0) {
820874 pp.expansion_source_loc = pp.top_expansion_buf.items[0].loc;
875 pp.hideset.clearRetainingCapacity();
821876 try pp.expandMacroExhaustive(tokenizer, &pp.top_expansion_buf, 0, pp.top_expansion_buf.items.len, false, .expr);
822877 }
823878 for (pp.top_expansion_buf.items) |tok| {
......@@ -836,7 +891,7 @@ fn expr(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!bool {
836891 }
837892
838893 // validate the tokens in the expression
839 try pp.tokens.ensureUnusedCapacity(pp.gpa, pp.top_expansion_buf.items.len);
894 try pp.ensureUnusedTokenCapacity(pp.top_expansion_buf.items.len);
840895 var i: usize = 0;
841896 const items = pp.top_expansion_buf.items;
842897 while (i < items.len) : (i += 1) {
......@@ -905,9 +960,9 @@ fn expr(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!bool {
905960 }
906961 },
907962 }
908 pp.tokens.appendAssumeCapacity(tok);
963 pp.addTokenAssumeCapacity(tok);
909964 }
910 try pp.tokens.append(pp.gpa, .{
965 try pp.addToken(.{
911966 .id = .eof,
912967 .loc = tokFromRaw(eof).loc,
913968 });
......@@ -918,7 +973,7 @@ fn expr(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!bool {
918973 .comp = pp.comp,
919974 .gpa = pp.gpa,
920975 .tok_ids = pp.tokens.items(.id),
921 .tok_i = @intCast(start),
976 .tok_i = @intCast(token_state.tokens_len),
922977 .arena = pp.arena.allocator(),
923978 .in_macro = true,
924979 .strings = std.ArrayList(u8).init(pp.comp.gpa),
......@@ -941,7 +996,7 @@ fn expr(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!bool {
941996
942997/// Turns macro_tok from .keyword_defined into .zero or .one depending on whether the argument is defined
943998/// Returns the number of tokens consumed
944fn handleKeywordDefined(pp: *Preprocessor, macro_tok: *Token, tokens: []const Token, eof: RawToken) !usize {
999fn handleKeywordDefined(pp: *Preprocessor, macro_tok: *TokenWithExpansionLocs, tokens: []const TokenWithExpansionLocs, eof: RawToken) !usize {
9451000 std.debug.assert(macro_tok.id == .keyword_defined);
9461001 var it = TokenIterator.init(tokens);
9471002 const first = it.nextNoWS() orelse {
......@@ -1056,7 +1111,7 @@ fn skip(
10561111 tokenizer.index += 1;
10571112 tokenizer.line += 1;
10581113 if (pp.preserve_whitespace) {
1059 try pp.tokens.append(pp.gpa, .{ .id = .nl, .loc = .{
1114 try pp.addToken(.{ .id = .nl, .loc = .{
10601115 .id = tokenizer.source,
10611116 .line = tokenizer.line,
10621117 } });
......@@ -1079,21 +1134,21 @@ fn skipToNl(tokenizer: *Tokenizer) void {
10791134 }
10801135}
10811136
1082const ExpandBuf = std.ArrayList(Token);
1137const ExpandBuf = std.ArrayList(TokenWithExpansionLocs);
10831138fn removePlacemarkers(buf: *ExpandBuf) void {
10841139 var i: usize = buf.items.len -% 1;
10851140 while (i < buf.items.len) : (i -%= 1) {
10861141 if (buf.items[i].id == .placemarker) {
10871142 const placemarker = buf.orderedRemove(i);
1088 Token.free(placemarker.expansion_locs, buf.allocator);
1143 TokenWithExpansionLocs.free(placemarker.expansion_locs, buf.allocator);
10891144 }
10901145 }
10911146}
10921147
1093const MacroArguments = std.ArrayList([]const Token);
1148const MacroArguments = std.ArrayList([]const TokenWithExpansionLocs);
10941149fn deinitMacroArguments(allocator: Allocator, args: *const MacroArguments) void {
10951150 for (args.items) |item| {
1096 for (item) |tok| Token.free(tok.expansion_locs, allocator);
1151 for (item) |tok| TokenWithExpansionLocs.free(tok.expansion_locs, allocator);
10971152 allocator.free(item);
10981153 }
10991154 args.deinit();
......@@ -1102,6 +1157,10 @@ fn deinitMacroArguments(allocator: Allocator, args: *const MacroArguments) void
11021157fn expandObjMacro(pp: *Preprocessor, simple_macro: *const Macro) Error!ExpandBuf {
11031158 var buf = ExpandBuf.init(pp.gpa);
11041159 errdefer buf.deinit();
1160 if (simple_macro.tokens.len == 0) {
1161 try buf.append(.{ .id = .placemarker, .loc = .{ .id = .generated } });
1162 return buf;
1163 }
11051164 try buf.ensureTotalCapacity(simple_macro.tokens.len);
11061165
11071166 // Add all of the simple_macros tokens to the new buffer handling any concats.
......@@ -1161,7 +1220,7 @@ fn expandObjMacro(pp: *Preprocessor, simple_macro: *const Macro) Error!ExpandBuf
11611220/// Returns error.ExpectedStringLiteral if parentheses are not balanced, a non-string-literal
11621221/// is encountered, or if no string literals are encountered
11631222/// TODO: destringize (replace all '\\' with a single `\` and all '\"' with a '"')
1164fn pasteStringsUnsafe(pp: *Preprocessor, toks: []const Token) ![]const u8 {
1223fn pasteStringsUnsafe(pp: *Preprocessor, toks: []const TokenWithExpansionLocs) ![]const u8 {
11651224 const char_top = pp.char_buf.items.len;
11661225 defer pp.char_buf.items.len = char_top;
11671226 var unwrapped = toks;
......@@ -1180,7 +1239,7 @@ fn pasteStringsUnsafe(pp: *Preprocessor, toks: []const Token) ![]const u8 {
11801239}
11811240
11821241/// Handle the _Pragma operator (implemented as a builtin macro)
1183fn pragmaOperator(pp: *Preprocessor, arg_tok: Token, operator_loc: Source.Location) !void {
1242fn pragmaOperator(pp: *Preprocessor, arg_tok: TokenWithExpansionLocs, operator_loc: Source.Location) !void {
11841243 const arg_slice = pp.expandedSlice(arg_tok);
11851244 const content = arg_slice[1 .. arg_slice.len - 1];
11861245 const directive = "#pragma ";
......@@ -1234,7 +1293,7 @@ fn destringify(pp: *Preprocessor, str: []const u8) void {
12341293
12351294/// Stringify `tokens` into pp.char_buf.
12361295/// See https://gcc.gnu.org/onlinedocs/gcc-11.2.0/cpp/Stringizing.html#Stringizing
1237fn stringify(pp: *Preprocessor, tokens: []const Token) !void {
1296fn stringify(pp: *Preprocessor, tokens: []const TokenWithExpansionLocs) !void {
12381297 try pp.char_buf.append('"');
12391298 var ws_state: enum { start, need, not_needed } = .start;
12401299 for (tokens) |tok| {
......@@ -1281,7 +1340,8 @@ fn stringify(pp: *Preprocessor, tokens: []const Token) !void {
12811340 try pp.char_buf.appendSlice("\"\n");
12821341}
12831342
1284fn reconstructIncludeString(pp: *Preprocessor, param_toks: []const Token, embed_args: ?*[]const Token) !?[]const u8 {
1343fn reconstructIncludeString(pp: *Preprocessor, param_toks: []const TokenWithExpansionLocs, embed_args: ?*[]const TokenWithExpansionLocs, first: TokenWithExpansionLocs) !?[]const u8 {
1344 assert(param_toks.len != 0);
12851345 const char_top = pp.char_buf.items.len;
12861346 defer pp.char_buf.items.len = char_top;
12871347
......@@ -1295,8 +1355,8 @@ fn reconstructIncludeString(pp: *Preprocessor, param_toks: []const Token, embed_
12951355 if (params.len == 0) {
12961356 try pp.comp.addDiagnostic(.{
12971357 .tag = .expected_filename,
1298 .loc = param_toks[0].loc,
1299 }, param_toks[0].expansionSlice());
1358 .loc = first.loc,
1359 }, first.expansionSlice());
13001360 return null;
13011361 }
13021362 // no string pasting
......@@ -1321,6 +1381,13 @@ fn reconstructIncludeString(pp: *Preprocessor, param_toks: []const Token, embed_
13211381
13221382 const include_str = pp.char_buf.items[char_top..];
13231383 if (include_str.len < 3) {
1384 if (include_str.len == 0) {
1385 try pp.comp.addDiagnostic(.{
1386 .tag = .expected_filename,
1387 .loc = first.loc,
1388 }, first.expansionSlice());
1389 return null;
1390 }
13241391 try pp.comp.addDiagnostic(.{
13251392 .tag = .empty_filename,
13261393 .loc = params[0].loc,
......@@ -1356,7 +1423,7 @@ fn reconstructIncludeString(pp: *Preprocessor, param_toks: []const Token, embed_
13561423 }
13571424}
13581425
1359fn handleBuiltinMacro(pp: *Preprocessor, builtin: RawToken.Id, param_toks: []const Token, src_loc: Source.Location) Error!bool {
1426fn handleBuiltinMacro(pp: *Preprocessor, builtin: RawToken.Id, param_toks: []const TokenWithExpansionLocs, src_loc: Source.Location) Error!bool {
13601427 switch (builtin) {
13611428 .macro_param_has_attribute,
13621429 .macro_param_has_declspec_attribute,
......@@ -1364,8 +1431,8 @@ fn handleBuiltinMacro(pp: *Preprocessor, builtin: RawToken.Id, param_toks: []con
13641431 .macro_param_has_extension,
13651432 .macro_param_has_builtin,
13661433 => {
1367 var invalid: ?Token = null;
1368 var identifier: ?Token = null;
1434 var invalid: ?TokenWithExpansionLocs = null;
1435 var identifier: ?TokenWithExpansionLocs = null;
13691436 for (param_toks) |tok| {
13701437 if (tok.id == .macro_ws) continue;
13711438 if (tok.id == .comment) continue;
......@@ -1415,8 +1482,8 @@ fn handleBuiltinMacro(pp: *Preprocessor, builtin: RawToken.Id, param_toks: []con
14151482 return Diagnostics.warningExists(warning_name);
14161483 },
14171484 .macro_param_is_identifier => {
1418 var invalid: ?Token = null;
1419 var identifier: ?Token = null;
1485 var invalid: ?TokenWithExpansionLocs = null;
1486 var identifier: ?TokenWithExpansionLocs = null;
14201487 for (param_toks) |tok| switch (tok.id) {
14211488 .macro_ws => continue,
14221489 .comment => continue,
......@@ -1438,7 +1505,7 @@ fn handleBuiltinMacro(pp: *Preprocessor, builtin: RawToken.Id, param_toks: []con
14381505 return id == .identifier or id == .extended_identifier;
14391506 },
14401507 .macro_param_has_include, .macro_param_has_include_next => {
1441 const include_str = (try pp.reconstructIncludeString(param_toks, null)) orelse return false;
1508 const include_str = (try pp.reconstructIncludeString(param_toks, null, param_toks[0])) orelse return false;
14421509 const include_type: Compilation.IncludeType = switch (include_str[0]) {
14431510 '"' => .quotes,
14441511 '<' => .angle_brackets,
......@@ -1460,6 +1527,17 @@ fn handleBuiltinMacro(pp: *Preprocessor, builtin: RawToken.Id, param_toks: []con
14601527 }
14611528}
14621529
1530/// Treat whitespace-only paste arguments as empty
1531fn getPasteArgs(args: []const TokenWithExpansionLocs) []const TokenWithExpansionLocs {
1532 for (args) |tok| {
1533 if (tok.id != .macro_ws) return args;
1534 }
1535 return &[1]TokenWithExpansionLocs{.{
1536 .id = .placemarker,
1537 .loc = .{ .id = .generated, .byte_offset = 0, .line = 0 },
1538 }};
1539}
1540
14631541fn expandFuncMacro(
14641542 pp: *Preprocessor,
14651543 loc: Source.Location,
......@@ -1482,7 +1560,7 @@ fn expandFuncMacro(
14821560 try variable_arguments.appendSlice(args.items[i]);
14831561 try expanded_variable_arguments.appendSlice(expanded_args.items[i]);
14841562 if (i != expanded_args.items.len - 1) {
1485 const comma = Token{ .id = .comma, .loc = .{ .id = .generated } };
1563 const comma = TokenWithExpansionLocs{ .id = .comma, .loc = .{ .id = .generated } };
14861564 try variable_arguments.append(comma);
14871565 try expanded_variable_arguments.append(comma);
14881566 }
......@@ -1507,28 +1585,22 @@ fn expandFuncMacro(
15071585 .comment => if (!pp.comp.langopts.preserve_comments_in_macros)
15081586 continue
15091587 else
1510 &[1]Token{tokFromRaw(raw_next)},
1511 .macro_param, .macro_param_no_expand => if (args.items[raw_next.end].len > 0)
1512 args.items[raw_next.end]
1513 else
1514 &[1]Token{tokFromRaw(.{ .id = .placemarker, .source = .generated })},
1588 &[1]TokenWithExpansionLocs{tokFromRaw(raw_next)},
1589 .macro_param, .macro_param_no_expand => getPasteArgs(args.items[raw_next.end]),
15151590 .keyword_va_args => variable_arguments.items,
15161591 .keyword_va_opt => blk: {
15171592 try pp.expandVaOpt(&va_opt_buf, raw_next, variable_arguments.items.len != 0);
15181593 if (va_opt_buf.items.len == 0) break;
15191594 break :blk va_opt_buf.items;
15201595 },
1521 else => &[1]Token{tokFromRaw(raw_next)},
1596 else => &[1]TokenWithExpansionLocs{tokFromRaw(raw_next)},
15221597 };
15231598
15241599 try pp.pasteTokens(&buf, next);
15251600 if (next.len != 0) break;
15261601 },
15271602 .macro_param_no_expand => {
1528 const slice = if (args.items[raw.end].len > 0)
1529 args.items[raw.end]
1530 else
1531 &[1]Token{tokFromRaw(.{ .id = .placemarker, .source = .generated })};
1603 const slice = getPasteArgs(args.items[raw.end]);
15321604 const raw_loc = Source.Location{ .id = raw.source, .byte_offset = raw.start, .line = raw.line };
15331605 try bufCopyTokens(&buf, slice, &.{raw_loc});
15341606 },
......@@ -1587,10 +1659,10 @@ fn expandFuncMacro(
15871659 try pp.comp.addDiagnostic(.{ .tag = .expected_arguments, .loc = loc, .extra = extra }, &.{});
15881660 break :blk not_found;
15891661 } else res: {
1590 var invalid: ?Token = null;
1591 var vendor_ident: ?Token = null;
1592 var colon_colon: ?Token = null;
1593 var attr_ident: ?Token = null;
1662 var invalid: ?TokenWithExpansionLocs = null;
1663 var vendor_ident: ?TokenWithExpansionLocs = null;
1664 var colon_colon: ?TokenWithExpansionLocs = null;
1665 var attr_ident: ?TokenWithExpansionLocs = null;
15941666 for (arg) |tok| {
15951667 if (tok.id == .macro_ws) continue;
15961668 if (tok.id == .comment) continue;
......@@ -1663,17 +1735,17 @@ fn expandFuncMacro(
16631735 try pp.comp.addDiagnostic(.{ .tag = .expected_arguments, .loc = loc, .extra = extra }, &.{});
16641736 break :blk not_found;
16651737 } else res: {
1666 var embed_args: []const Token = &.{};
1667 const include_str = (try pp.reconstructIncludeString(arg, &embed_args)) orelse
1738 var embed_args: []const TokenWithExpansionLocs = &.{};
1739 const include_str = (try pp.reconstructIncludeString(arg, &embed_args, arg[0])) orelse
16681740 break :res not_found;
16691741
16701742 var prev = tokFromRaw(raw);
16711743 prev.id = .eof;
16721744 var it: struct {
16731745 i: u32 = 0,
1674 slice: []const Token,
1675 prev: Token,
1676 fn next(it: *@This()) Token {
1746 slice: []const TokenWithExpansionLocs,
1747 prev: TokenWithExpansionLocs,
1748 fn next(it: *@This()) TokenWithExpansionLocs {
16771749 while (it.i < it.slice.len) switch (it.slice[it.i].id) {
16781750 .macro_ws, .whitespace => it.i += 1,
16791751 else => break,
......@@ -1732,7 +1804,7 @@ fn expandFuncMacro(
17321804 };
17331805
17341806 var arg_count: u32 = 0;
1735 var first_arg: Token = undefined;
1807 var first_arg: TokenWithExpansionLocs = undefined;
17361808 while (true) {
17371809 const next = it.next();
17381810 if (next.id == .eof) {
......@@ -1793,8 +1865,8 @@ fn expandFuncMacro(
17931865 // Clang and GCC require exactly one token (so, no parentheses or string pasting)
17941866 // even though their error messages indicate otherwise. Ours is slightly more
17951867 // descriptive.
1796 var invalid: ?Token = null;
1797 var string: ?Token = null;
1868 var invalid: ?TokenWithExpansionLocs = null;
1869 var string: ?TokenWithExpansionLocs = null;
17981870 for (param_toks) |tok| switch (tok.id) {
17991871 .string_literal => {
18001872 if (string) |_| invalid = tok else string = tok;
......@@ -1884,27 +1956,11 @@ fn expandVaOpt(
18841956 }
18851957}
18861958
1887fn shouldExpand(tok: Token, macro: *Macro) bool {
1888 if (tok.loc.id == macro.loc.id and
1889 tok.loc.byte_offset >= macro.start and
1890 tok.loc.byte_offset <= macro.end)
1891 return false;
1892 for (tok.expansionSlice()) |loc| {
1893 if (loc.id == macro.loc.id and
1894 loc.byte_offset >= macro.start and
1895 loc.byte_offset <= macro.end)
1896 return false;
1897 }
1898 if (tok.flags.expansion_disabled) return false;
1899
1900 return true;
1901}
1902
1903fn bufCopyTokens(buf: *ExpandBuf, tokens: []const Token, src: []const Source.Location) !void {
1959fn bufCopyTokens(buf: *ExpandBuf, tokens: []const TokenWithExpansionLocs, src: []const Source.Location) !void {
19041960 try buf.ensureUnusedCapacity(tokens.len);
19051961 for (tokens) |tok| {
19061962 var copy = try tok.dupe(buf.allocator);
1907 errdefer Token.free(copy.expansion_locs, buf.allocator);
1963 errdefer TokenWithExpansionLocs.free(copy.expansion_locs, buf.allocator);
19081964 try copy.addExpansionLocation(buf.allocator, src);
19091965 buf.appendAssumeCapacity(copy);
19101966 }
......@@ -1917,7 +1973,7 @@ fn nextBufToken(
19171973 start_idx: *usize,
19181974 end_idx: *usize,
19191975 extend_buf: bool,
1920) Error!Token {
1976) Error!TokenWithExpansionLocs {
19211977 start_idx.* += 1;
19221978 if (start_idx.* == buf.items.len and start_idx.* >= end_idx.*) {
19231979 if (extend_buf) {
......@@ -1933,7 +1989,7 @@ fn nextBufToken(
19331989 try buf.append(new_tok);
19341990 return new_tok;
19351991 } else {
1936 return Token{ .id = .eof, .loc = .{ .id = .generated } };
1992 return TokenWithExpansionLocs{ .id = .eof, .loc = .{ .id = .generated } };
19371993 }
19381994 } else {
19391995 return buf.items[start_idx.*];
......@@ -1948,6 +2004,7 @@ fn collectMacroFuncArguments(
19482004 end_idx: *usize,
19492005 extend_buf: bool,
19502006 is_builtin: bool,
2007 r_paren: *TokenWithExpansionLocs,
19512008) !MacroArguments {
19522009 const name_tok = buf.items[start_idx.*];
19532010 const saved_tokenizer = tokenizer.*;
......@@ -1974,7 +2031,7 @@ fn collectMacroFuncArguments(
19742031 var parens: u32 = 0;
19752032 var args = MacroArguments.init(pp.gpa);
19762033 errdefer deinitMacroArguments(pp.gpa, &args);
1977 var curArgument = std.ArrayList(Token).init(pp.gpa);
2034 var curArgument = std.ArrayList(TokenWithExpansionLocs).init(pp.gpa);
19782035 defer curArgument.deinit();
19792036 while (true) {
19802037 var tok = try nextBufToken(pp, tokenizer, buf, start_idx, end_idx, extend_buf);
......@@ -1987,13 +2044,13 @@ fn collectMacroFuncArguments(
19872044 try args.append(owned);
19882045 } else {
19892046 const duped = try tok.dupe(pp.gpa);
1990 errdefer Token.free(duped.expansion_locs, pp.gpa);
2047 errdefer TokenWithExpansionLocs.free(duped.expansion_locs, pp.gpa);
19912048 try curArgument.append(duped);
19922049 }
19932050 },
19942051 .l_paren => {
19952052 const duped = try tok.dupe(pp.gpa);
1996 errdefer Token.free(duped.expansion_locs, pp.gpa);
2053 errdefer TokenWithExpansionLocs.free(duped.expansion_locs, pp.gpa);
19972054 try curArgument.append(duped);
19982055 parens += 1;
19992056 },
......@@ -2002,10 +2059,11 @@ fn collectMacroFuncArguments(
20022059 const owned = try curArgument.toOwnedSlice();
20032060 errdefer pp.gpa.free(owned);
20042061 try args.append(owned);
2062 r_paren.* = tok;
20052063 break;
20062064 } else {
20072065 const duped = try tok.dupe(pp.gpa);
2008 errdefer Token.free(duped.expansion_locs, pp.gpa);
2066 errdefer TokenWithExpansionLocs.free(duped.expansion_locs, pp.gpa);
20092067 try curArgument.append(duped);
20102068 parens -= 1;
20112069 }
......@@ -2028,7 +2086,7 @@ fn collectMacroFuncArguments(
20282086 },
20292087 else => {
20302088 const duped = try tok.dupe(pp.gpa);
2031 errdefer Token.free(duped.expansion_locs, pp.gpa);
2089 errdefer TokenWithExpansionLocs.free(duped.expansion_locs, pp.gpa);
20322090 try curArgument.append(duped);
20332091 },
20342092 }
......@@ -2038,7 +2096,7 @@ fn collectMacroFuncArguments(
20382096}
20392097
20402098fn removeExpandedTokens(pp: *Preprocessor, buf: *ExpandBuf, start: usize, len: usize, moving_end_idx: *usize) !void {
2041 for (buf.items[start .. start + len]) |tok| Token.free(tok.expansion_locs, pp.gpa);
2099 for (buf.items[start .. start + len]) |tok| TokenWithExpansionLocs.free(tok.expansion_locs, pp.gpa);
20422100 try buf.replaceRange(start, len, &.{});
20432101 moving_end_idx.* -|= len;
20442102}
......@@ -2054,14 +2112,14 @@ const EvalContext = enum {
20542112
20552113/// Helper for safely iterating over a slice of tokens while skipping whitespace
20562114const TokenIterator = struct {
2057 toks: []const Token,
2115 toks: []const TokenWithExpansionLocs,
20582116 i: usize,
20592117
2060 fn init(toks: []const Token) TokenIterator {
2118 fn init(toks: []const TokenWithExpansionLocs) TokenIterator {
20612119 return .{ .toks = toks, .i = 0 };
20622120 }
20632121
2064 fn nextNoWS(self: *TokenIterator) ?Token {
2122 fn nextNoWS(self: *TokenIterator) ?TokenWithExpansionLocs {
20652123 while (self.i < self.toks.len) : (self.i += 1) {
20662124 const tok = self.toks[self.i];
20672125 if (tok.id == .whitespace or tok.id == .macro_ws) continue;
......@@ -2108,13 +2166,24 @@ fn expandMacroExhaustive(
21082166 idx += it.i;
21092167 continue;
21102168 }
2111 const macro_entry = pp.defines.getPtr(pp.expandedSlice(macro_tok));
2112 if (macro_entry == null or !shouldExpand(buf.items[idx], macro_entry.?)) {
2169 if (!macro_tok.id.isMacroIdentifier() or macro_tok.flags.expansion_disabled) {
21132170 idx += 1;
21142171 continue;
21152172 }
2116 if (macro_entry) |macro| macro_handler: {
2173 const expanded = pp.expandedSlice(macro_tok);
2174 const macro = pp.defines.getPtr(expanded) orelse {
2175 idx += 1;
2176 continue;
2177 };
2178 const macro_hidelist = pp.hideset.get(macro_tok.loc);
2179 if (pp.hideset.contains(macro_hidelist, expanded)) {
2180 idx += 1;
2181 continue;
2182 }
2183
2184 macro_handler: {
21172185 if (macro.is_func) {
2186 var r_paren: TokenWithExpansionLocs = undefined;
21182187 var macro_scan_idx = idx;
21192188 // to be saved in case this doesn't turn out to be a call
21202189 const args = pp.collectMacroFuncArguments(
......@@ -2124,6 +2193,7 @@ fn expandMacroExhaustive(
21242193 &moving_end_idx,
21252194 extend_buf,
21262195 macro.is_builtin,
2196 &r_paren,
21272197 ) catch |er| switch (er) {
21282198 error.MissingLParen => {
21292199 if (!buf.items[idx].flags.is_macro_arg) buf.items[idx].flags.expansion_disabled = true;
......@@ -2137,12 +2207,16 @@ fn expandMacroExhaustive(
21372207 },
21382208 else => |e| return e,
21392209 };
2210 assert(r_paren.id == .r_paren);
21402211 defer {
21412212 for (args.items) |item| {
21422213 pp.gpa.free(item);
21432214 }
21442215 args.deinit();
21452216 }
2217 const r_paren_hidelist = pp.hideset.get(r_paren.loc);
2218 var hs = try pp.hideset.intersection(macro_hidelist, r_paren_hidelist);
2219 hs = try pp.hideset.prepend(macro_tok.loc, hs);
21462220
21472221 var args_count: u32 = @intCast(args.items.len);
21482222 // if the macro has zero arguments g() args_count is still 1
......@@ -2199,10 +2273,13 @@ fn expandMacroExhaustive(
21992273 for (res.items) |*tok| {
22002274 try tok.addExpansionLocation(pp.gpa, &.{macro_tok.loc});
22012275 try tok.addExpansionLocation(pp.gpa, macro_expansion_locs);
2276 const tok_hidelist = pp.hideset.get(tok.loc);
2277 const new_hidelist = try pp.hideset.@"union"(tok_hidelist, hs);
2278 try pp.hideset.put(tok.loc, new_hidelist);
22022279 }
22032280
22042281 const tokens_removed = macro_scan_idx - idx + 1;
2205 for (buf.items[idx .. idx + tokens_removed]) |tok| Token.free(tok.expansion_locs, pp.gpa);
2282 for (buf.items[idx .. idx + tokens_removed]) |tok| TokenWithExpansionLocs.free(tok.expansion_locs, pp.gpa);
22062283 try buf.replaceRange(idx, tokens_removed, res.items);
22072284
22082285 moving_end_idx += tokens_added;
......@@ -2215,12 +2292,19 @@ fn expandMacroExhaustive(
22152292 const res = try pp.expandObjMacro(macro);
22162293 defer res.deinit();
22172294
2295 const hs = try pp.hideset.prepend(macro_tok.loc, macro_hidelist);
2296
22182297 const macro_expansion_locs = macro_tok.expansionSlice();
22192298 var increment_idx_by = res.items.len;
22202299 for (res.items, 0..) |*tok, i| {
22212300 tok.flags.is_macro_arg = macro_tok.flags.is_macro_arg;
22222301 try tok.addExpansionLocation(pp.gpa, &.{macro_tok.loc});
22232302 try tok.addExpansionLocation(pp.gpa, macro_expansion_locs);
2303
2304 const tok_hidelist = pp.hideset.get(tok.loc);
2305 const new_hidelist = try pp.hideset.@"union"(tok_hidelist, hs);
2306 try pp.hideset.put(tok.loc, new_hidelist);
2307
22242308 if (tok.id == .keyword_defined and eval_ctx == .expr) {
22252309 try pp.comp.addDiagnostic(.{
22262310 .tag = .expansion_to_defined,
......@@ -2233,7 +2317,7 @@ fn expandMacroExhaustive(
22332317 }
22342318 }
22352319
2236 Token.free(buf.items[idx].expansion_locs, pp.gpa);
2320 TokenWithExpansionLocs.free(buf.items[idx].expansion_locs, pp.gpa);
22372321 try buf.replaceRange(idx, 1, res.items);
22382322 idx += increment_idx_by;
22392323 moving_end_idx = moving_end_idx + res.items.len - 1;
......@@ -2249,7 +2333,7 @@ fn expandMacroExhaustive(
22492333
22502334 // trim excess buffer
22512335 for (buf.items[moving_end_idx..]) |item| {
2252 Token.free(item.expansion_locs, pp.gpa);
2336 TokenWithExpansionLocs.free(item.expansion_locs, pp.gpa);
22532337 }
22542338 buf.items.len = moving_end_idx;
22552339}
......@@ -2260,30 +2344,35 @@ fn expandMacro(pp: *Preprocessor, tokenizer: *Tokenizer, raw: RawToken) MacroErr
22602344 var source_tok = tokFromRaw(raw);
22612345 if (!raw.id.isMacroIdentifier()) {
22622346 source_tok.id.simplifyMacroKeyword();
2263 return pp.tokens.append(pp.gpa, source_tok);
2347 return pp.addToken(source_tok);
22642348 }
22652349 pp.top_expansion_buf.items.len = 0;
22662350 try pp.top_expansion_buf.append(source_tok);
22672351 pp.expansion_source_loc = source_tok.loc;
22682352
2353 pp.hideset.clearRetainingCapacity();
22692354 try pp.expandMacroExhaustive(tokenizer, &pp.top_expansion_buf, 0, 1, true, .non_expr);
2270 try pp.tokens.ensureUnusedCapacity(pp.gpa, pp.top_expansion_buf.items.len);
2355 try pp.ensureUnusedTokenCapacity(pp.top_expansion_buf.items.len);
22712356 for (pp.top_expansion_buf.items) |*tok| {
22722357 if (tok.id == .macro_ws and !pp.preserve_whitespace) {
2273 Token.free(tok.expansion_locs, pp.gpa);
2358 TokenWithExpansionLocs.free(tok.expansion_locs, pp.gpa);
22742359 continue;
22752360 }
22762361 if (tok.id == .comment and !pp.comp.langopts.preserve_comments_in_macros) {
2277 Token.free(tok.expansion_locs, pp.gpa);
2362 TokenWithExpansionLocs.free(tok.expansion_locs, pp.gpa);
2363 continue;
2364 }
2365 if (tok.id == .placemarker) {
2366 TokenWithExpansionLocs.free(tok.expansion_locs, pp.gpa);
22782367 continue;
22792368 }
22802369 tok.id.simplifyMacroKeywordExtra(true);
2281 pp.tokens.appendAssumeCapacity(tok.*);
2370 pp.addTokenAssumeCapacity(tok.*);
22822371 }
22832372 if (pp.preserve_whitespace) {
2284 try pp.tokens.ensureUnusedCapacity(pp.gpa, pp.add_expansion_nl);
2373 try pp.ensureUnusedTokenCapacity(pp.add_expansion_nl);
22852374 while (pp.add_expansion_nl > 0) : (pp.add_expansion_nl -= 1) {
2286 pp.tokens.appendAssumeCapacity(.{ .id = .nl, .loc = .{
2375 pp.addTokenAssumeCapacity(.{ .id = .nl, .loc = .{
22872376 .id = tokenizer.source,
22882377 .line = tokenizer.line,
22892378 } });
......@@ -2291,7 +2380,7 @@ fn expandMacro(pp: *Preprocessor, tokenizer: *Tokenizer, raw: RawToken) MacroErr
22912380 }
22922381}
22932382
2294fn expandedSliceExtra(pp: *const Preprocessor, tok: Token, macro_ws_handling: enum { single_macro_ws, preserve_macro_ws }) []const u8 {
2383fn expandedSliceExtra(pp: *const Preprocessor, tok: anytype, macro_ws_handling: enum { single_macro_ws, preserve_macro_ws }) []const u8 {
22952384 if (tok.id.lexeme()) |some| {
22962385 if (!tok.id.allowsDigraphs(pp.comp.langopts) and !(tok.id == .macro_ws and macro_ws_handling == .preserve_macro_ws)) return some;
22972386 }
......@@ -2312,18 +2401,18 @@ fn expandedSliceExtra(pp: *const Preprocessor, tok: Token, macro_ws_handling: en
23122401}
23132402
23142403/// Get expanded token source string.
2315pub fn expandedSlice(pp: *Preprocessor, tok: Token) []const u8 {
2404pub fn expandedSlice(pp: *const Preprocessor, tok: anytype) []const u8 {
23162405 return pp.expandedSliceExtra(tok, .single_macro_ws);
23172406}
23182407
23192408/// Concat two tokens and add the result to pp.generated
2320fn pasteTokens(pp: *Preprocessor, lhs_toks: *ExpandBuf, rhs_toks: []const Token) Error!void {
2409fn pasteTokens(pp: *Preprocessor, lhs_toks: *ExpandBuf, rhs_toks: []const TokenWithExpansionLocs) Error!void {
23212410 const lhs = while (lhs_toks.popOrNull()) |lhs| {
23222411 if ((pp.comp.langopts.preserve_comments_in_macros and lhs.id == .comment) or
23232412 (lhs.id != .macro_ws and lhs.id != .comment))
23242413 break lhs;
23252414
2326 Token.free(lhs.expansion_locs, pp.gpa);
2415 TokenWithExpansionLocs.free(lhs.expansion_locs, pp.gpa);
23272416 } else {
23282417 return bufCopyTokens(lhs_toks, rhs_toks, &.{});
23292418 };
......@@ -2338,7 +2427,7 @@ fn pasteTokens(pp: *Preprocessor, lhs_toks: *ExpandBuf, rhs_toks: []const Token)
23382427 } else {
23392428 return lhs_toks.appendAssumeCapacity(lhs);
23402429 };
2341 defer Token.free(lhs.expansion_locs, pp.gpa);
2430 defer TokenWithExpansionLocs.free(lhs.expansion_locs, pp.gpa);
23422431
23432432 const start = pp.comp.generated_buf.items.len;
23442433 const end = start + pp.expandedSlice(lhs).len + pp.expandedSlice(rhs).len;
......@@ -2375,8 +2464,8 @@ fn pasteTokens(pp: *Preprocessor, lhs_toks: *ExpandBuf, rhs_toks: []const Token)
23752464 try bufCopyTokens(lhs_toks, rhs_toks[rhs_rest..], &.{});
23762465}
23772466
2378fn makeGeneratedToken(pp: *Preprocessor, start: usize, id: Token.Id, source: Token) !Token {
2379 var pasted_token = Token{ .id = id, .loc = .{
2467fn makeGeneratedToken(pp: *Preprocessor, start: usize, id: Token.Id, source: TokenWithExpansionLocs) !TokenWithExpansionLocs {
2468 var pasted_token = TokenWithExpansionLocs{ .id = id, .loc = .{
23802469 .id = .generated,
23812470 .byte_offset = @intCast(start),
23822471 .line = pp.generated_line,
......@@ -2441,8 +2530,6 @@ fn define(pp: *Preprocessor, tokenizer: *Tokenizer) Error!void {
24412530 .tokens = &.{},
24422531 .var_args = false,
24432532 .loc = tokFromRaw(macro_name).loc,
2444 .start = 0,
2445 .end = 0,
24462533 .is_func = false,
24472534 }),
24482535 .whitespace => first = tokenizer.next(),
......@@ -2460,7 +2547,7 @@ fn define(pp: *Preprocessor, tokenizer: *Tokenizer) Error!void {
24602547 var need_ws = false;
24612548 // Collect the token body and validate any ## found.
24622549 var tok = first;
2463 const end_index = while (true) {
2550 while (true) {
24642551 tok.id.simplifyMacroKeyword();
24652552 switch (tok.id) {
24662553 .hash_hash => {
......@@ -2479,7 +2566,7 @@ fn define(pp: *Preprocessor, tokenizer: *Tokenizer) Error!void {
24792566 try pp.token_buf.append(tok);
24802567 try pp.token_buf.append(next);
24812568 },
2482 .nl, .eof => break tok.start,
2569 .nl, .eof => break,
24832570 .comment => if (pp.comp.langopts.preserve_comments_in_macros) {
24842571 if (need_ws) {
24852572 need_ws = false;
......@@ -2502,13 +2589,11 @@ fn define(pp: *Preprocessor, tokenizer: *Tokenizer) Error!void {
25022589 },
25032590 }
25042591 tok = tokenizer.next();
2505 } else unreachable;
2592 }
25062593
25072594 const list = try pp.arena.allocator().dupe(RawToken, pp.token_buf.items);
25082595 try pp.defineMacro(macro_name, .{
25092596 .loc = tokFromRaw(macro_name).loc,
2510 .start = first.start,
2511 .end = end_index,
25122597 .tokens = list,
25132598 .params = undefined,
25142599 .is_func = false,
......@@ -2525,9 +2610,9 @@ fn defineFn(pp: *Preprocessor, tokenizer: *Tokenizer, macro_name: RawToken, l_pa
25252610 // Parse the parameter list.
25262611 var gnu_var_args: []const u8 = "";
25272612 var var_args = false;
2528 const start_index = while (true) {
2613 while (true) {
25292614 var tok = tokenizer.nextNoWS();
2530 if (tok.id == .r_paren) break tok.end;
2615 if (tok.id == .r_paren) break;
25312616 if (tok.id == .eof) return pp.err(tok, .unterminated_macro_param_list);
25322617 if (tok.id == .ellipsis) {
25332618 var_args = true;
......@@ -2537,7 +2622,7 @@ fn defineFn(pp: *Preprocessor, tokenizer: *Tokenizer, macro_name: RawToken, l_pa
25372622 try pp.err(l_paren, .to_match_paren);
25382623 return skipToNl(tokenizer);
25392624 }
2540 break r_paren.end;
2625 break;
25412626 }
25422627 if (!tok.id.isMacroIdentifier()) {
25432628 try pp.err(tok, .invalid_token_param_list);
......@@ -2556,22 +2641,22 @@ fn defineFn(pp: *Preprocessor, tokenizer: *Tokenizer, macro_name: RawToken, l_pa
25562641 try pp.err(l_paren, .to_match_paren);
25572642 return skipToNl(tokenizer);
25582643 }
2559 break r_paren.end;
2644 break;
25602645 } else if (tok.id == .r_paren) {
2561 break tok.end;
2646 break;
25622647 } else if (tok.id != .comma) {
25632648 try pp.err(tok, .expected_comma_param_list);
25642649 return skipToNl(tokenizer);
25652650 }
2566 } else unreachable;
2651 }
25672652
25682653 var need_ws = false;
25692654 // Collect the body tokens and validate # and ##'s found.
25702655 pp.token_buf.items.len = 0; // Safe to use since we can only be in one directive at a time.
2571 const end_index = tok_loop: while (true) {
2656 tok_loop: while (true) {
25722657 var tok = tokenizer.next();
25732658 switch (tok.id) {
2574 .nl, .eof => break tok.start,
2659 .nl, .eof => break,
25752660 .whitespace => need_ws = pp.token_buf.items.len != 0,
25762661 .comment => if (!pp.comp.langopts.preserve_comments_in_macros) continue else {
25772662 if (need_ws) {
......@@ -2690,7 +2775,7 @@ fn defineFn(pp: *Preprocessor, tokenizer: *Tokenizer, macro_name: RawToken, l_pa
26902775 try pp.token_buf.append(tok);
26912776 },
26922777 }
2693 } else unreachable;
2778 }
26942779
26952780 const param_list = try pp.arena.allocator().dupe([]const u8, params.items);
26962781 const token_list = try pp.arena.allocator().dupe(RawToken, pp.token_buf.items);
......@@ -2700,8 +2785,6 @@ fn defineFn(pp: *Preprocessor, tokenizer: *Tokenizer, macro_name: RawToken, l_pa
27002785 .var_args = var_args or gnu_var_args.len != 0,
27012786 .tokens = token_list,
27022787 .loc = tokFromRaw(macro_name).loc,
2703 .start = start_index,
2704 .end = end_index,
27052788 });
27062789}
27072790
......@@ -2714,7 +2797,7 @@ fn embed(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!void {
27142797 error.InvalidInclude => return,
27152798 else => |e| return e,
27162799 };
2717 defer Token.free(filename_tok.expansion_locs, pp.gpa);
2800 defer TokenWithExpansionLocs.free(filename_tok.expansion_locs, pp.gpa);
27182801
27192802 // Check for empty filename.
27202803 const tok_slice = pp.expandedSliceExtra(filename_tok, .single_macro_ws);
......@@ -2859,7 +2942,7 @@ fn embed(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!void {
28592942 return;
28602943 }
28612944
2862 try pp.tokens.ensureUnusedCapacity(pp.comp.gpa, 2 * embed_bytes.len - 1); // N bytes and N-1 commas
2945 try pp.ensureUnusedTokenCapacity(2 * embed_bytes.len - 1); // N bytes and N-1 commas
28632946
28642947 // TODO: We currently only support systems with CHAR_BIT == 8
28652948 // If the target's CHAR_BIT is not 8, we need to write out correctly-sized embed_bytes
......@@ -2870,14 +2953,14 @@ fn embed(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!void {
28702953 const byte = embed_bytes[0];
28712954 const start = pp.comp.generated_buf.items.len;
28722955 try writer.print("{d}", .{byte});
2873 pp.tokens.appendAssumeCapacity(try pp.makeGeneratedToken(start, .embed_byte, filename_tok));
2956 pp.addTokenAssumeCapacity(try pp.makeGeneratedToken(start, .embed_byte, filename_tok));
28742957 }
28752958
28762959 for (embed_bytes[1..]) |byte| {
28772960 const start = pp.comp.generated_buf.items.len;
28782961 try writer.print(",{d}", .{byte});
2879 pp.tokens.appendAssumeCapacity(.{ .id = .comma, .loc = .{ .id = .generated, .byte_offset = @intCast(start) } });
2880 pp.tokens.appendAssumeCapacity(try pp.makeGeneratedToken(start + 1, .embed_byte, filename_tok));
2962 pp.addTokenAssumeCapacity(.{ .id = .comma, .loc = .{ .id = .generated, .byte_offset = @intCast(start) } });
2963 pp.addTokenAssumeCapacity(try pp.makeGeneratedToken(start + 1, .embed_byte, filename_tok));
28812964 }
28822965 try pp.comp.generated_buf.append(pp.gpa, '\n');
28832966
......@@ -2911,19 +2994,19 @@ fn include(pp: *Preprocessor, tokenizer: *Tokenizer, which: Compilation.WhichInc
29112994 pp.verboseLog(first, "include file {s}", .{new_source.path});
29122995 }
29132996
2914 const tokens_start = pp.tokens.len;
2997 const token_state = pp.getTokenState();
29152998 try pp.addIncludeStart(new_source);
29162999 const eof = pp.preprocessExtra(new_source) catch |er| switch (er) {
29173000 error.StopPreprocessing => {
2918 for (pp.tokens.items(.expansion_locs)[tokens_start..]) |loc| Token.free(loc, pp.gpa);
2919 pp.tokens.len = tokens_start;
3001 for (pp.expansion_entries.items(.locs)[token_state.expansion_entries_len..]) |loc| TokenWithExpansionLocs.free(loc, pp.gpa);
3002 pp.restoreTokenState(token_state);
29203003 return;
29213004 },
29223005 else => |e| return e,
29233006 };
29243007 try eof.checkMsEof(new_source, pp.comp);
29253008 if (pp.preserve_whitespace and pp.tokens.items(.id)[pp.tokens.len - 1] != .nl) {
2926 try pp.tokens.append(pp.gpa, .{ .id = .nl, .loc = .{
3009 try pp.addToken(.{ .id = .nl, .loc = .{
29273010 .id = tokenizer.source,
29283011 .line = tokenizer.line,
29293012 } });
......@@ -2945,7 +3028,7 @@ fn include(pp: *Preprocessor, tokenizer: *Tokenizer, which: Compilation.WhichInc
29453028/// 3. Via a stringified macro argument which is used as an argument to `_Pragma`
29463029/// operator_loc: Location of `_Pragma`; null if this is from #pragma
29473030/// arg_locs: expansion locations of the argument to _Pragma. empty if #pragma or a raw string literal was used
2948fn makePragmaToken(pp: *Preprocessor, raw: RawToken, operator_loc: ?Source.Location, arg_locs: []const Source.Location) !Token {
3031fn makePragmaToken(pp: *Preprocessor, raw: RawToken, operator_loc: ?Source.Location, arg_locs: []const Source.Location) !TokenWithExpansionLocs {
29493032 var tok = tokFromRaw(raw);
29503033 if (operator_loc) |loc| {
29513034 try tok.addExpansionLocation(pp.gpa, &.{loc});
......@@ -2954,28 +3037,52 @@ fn makePragmaToken(pp: *Preprocessor, raw: RawToken, operator_loc: ?Source.Locat
29543037 return tok;
29553038}
29563039
3040pub fn addToken(pp: *Preprocessor, tok: TokenWithExpansionLocs) !void {
3041 if (tok.expansion_locs) |expansion_locs| {
3042 try pp.expansion_entries.append(pp.gpa, .{ .idx = @intCast(pp.tokens.len), .locs = expansion_locs });
3043 }
3044 try pp.tokens.append(pp.gpa, .{ .id = tok.id, .loc = tok.loc });
3045}
3046
3047pub fn addTokenAssumeCapacity(pp: *Preprocessor, tok: TokenWithExpansionLocs) void {
3048 if (tok.expansion_locs) |expansion_locs| {
3049 pp.expansion_entries.appendAssumeCapacity(.{ .idx = @intCast(pp.tokens.len), .locs = expansion_locs });
3050 }
3051 pp.tokens.appendAssumeCapacity(.{ .id = tok.id, .loc = tok.loc });
3052}
3053
3054pub fn ensureTotalTokenCapacity(pp: *Preprocessor, capacity: usize) !void {
3055 try pp.tokens.ensureTotalCapacity(pp.gpa, capacity);
3056 try pp.expansion_entries.ensureTotalCapacity(pp.gpa, capacity);
3057}
3058
3059pub fn ensureUnusedTokenCapacity(pp: *Preprocessor, capacity: usize) !void {
3060 try pp.tokens.ensureUnusedCapacity(pp.gpa, capacity);
3061 try pp.expansion_entries.ensureUnusedCapacity(pp.gpa, capacity);
3062}
3063
29573064/// Handle a pragma directive
29583065fn pragma(pp: *Preprocessor, tokenizer: *Tokenizer, pragma_tok: RawToken, operator_loc: ?Source.Location, arg_locs: []const Source.Location) !void {
29593066 const name_tok = tokenizer.nextNoWS();
29603067 if (name_tok.id == .nl or name_tok.id == .eof) return;
29613068
29623069 const name = pp.tokSlice(name_tok);
2963 try pp.tokens.append(pp.gpa, try pp.makePragmaToken(pragma_tok, operator_loc, arg_locs));
3070 try pp.addToken(try pp.makePragmaToken(pragma_tok, operator_loc, arg_locs));
29643071 const pragma_start: u32 = @intCast(pp.tokens.len);
29653072
29663073 const pragma_name_tok = try pp.makePragmaToken(name_tok, operator_loc, arg_locs);
2967 try pp.tokens.append(pp.gpa, pragma_name_tok);
3074 try pp.addToken(pragma_name_tok);
29683075 while (true) {
29693076 const next_tok = tokenizer.next();
29703077 if (next_tok.id == .whitespace) continue;
29713078 if (next_tok.id == .eof) {
2972 try pp.tokens.append(pp.gpa, .{
3079 try pp.addToken(.{
29733080 .id = .nl,
29743081 .loc = .{ .id = .generated },
29753082 });
29763083 break;
29773084 }
2978 try pp.tokens.append(pp.gpa, try pp.makePragmaToken(next_tok, operator_loc, arg_locs));
3085 try pp.addToken(try pp.makePragmaToken(next_tok, operator_loc, arg_locs));
29793086 if (next_tok.id == .nl) break;
29803087 }
29813088 if (pp.comp.getPragma(name)) |prag| unknown: {
......@@ -2995,7 +3102,7 @@ fn findIncludeFilenameToken(
29953102 first_token: RawToken,
29963103 tokenizer: *Tokenizer,
29973104 trailing_token_behavior: enum { ignore_trailing_tokens, expect_nl_eof },
2998) !Token {
3105) !TokenWithExpansionLocs {
29993106 var first = first_token;
30003107
30013108 if (first.id == .angle_bracket_left) to_end: {
......@@ -3025,14 +3132,13 @@ fn findIncludeFilenameToken(
30253132 else => expanded: {
30263133 // Try to expand if the argument is a macro.
30273134 pp.top_expansion_buf.items.len = 0;
3028 defer for (pp.top_expansion_buf.items) |tok| Token.free(tok.expansion_locs, pp.gpa);
3135 defer for (pp.top_expansion_buf.items) |tok| TokenWithExpansionLocs.free(tok.expansion_locs, pp.gpa);
30293136 try pp.top_expansion_buf.append(source_tok);
30303137 pp.expansion_source_loc = source_tok.loc;
30313138
30323139 try pp.expandMacroExhaustive(tokenizer, &pp.top_expansion_buf, 0, 1, true, .non_expr);
3033 var trailing_toks: []const Token = &.{};
3034 const include_str = (try pp.reconstructIncludeString(pp.top_expansion_buf.items, &trailing_toks)) orelse {
3035 try pp.err(first, .expected_filename);
3140 var trailing_toks: []const TokenWithExpansionLocs = &.{};
3141 const include_str = (try pp.reconstructIncludeString(pp.top_expansion_buf.items, &trailing_toks, tokFromRaw(first))) orelse {
30363142 try pp.expectNl(tokenizer);
30373143 return error.InvalidInclude;
30383144 };
......@@ -3071,7 +3177,7 @@ fn findIncludeFilenameToken(
30713177
30723178fn findIncludeSource(pp: *Preprocessor, tokenizer: *Tokenizer, first: RawToken, which: Compilation.WhichInclude) !Source {
30733179 const filename_tok = try pp.findIncludeFilenameToken(first, tokenizer, .expect_nl_eof);
3074 defer Token.free(filename_tok.expansion_locs, pp.gpa);
3180 defer TokenWithExpansionLocs.free(filename_tok.expansion_locs, pp.gpa);
30753181
30763182 // Check for empty filename.
30773183 const tok_slice = pp.expandedSliceExtra(filename_tok, .single_macro_ws);
......@@ -3101,8 +3207,7 @@ fn printLinemarker(
31013207) !void {
31023208 try w.writeByte('#');
31033209 if (pp.linemarkers == .line_directives) try w.writeAll("line");
3104 // line_no is 0 indexed
3105 try w.print(" {d} \"", .{line_no + 1});
3210 try w.print(" {d} \"", .{line_no});
31063211 for (source.path) |byte| switch (byte) {
31073212 '\n' => try w.writeAll("\\n"),
31083213 '\r' => try w.writeAll("\\r"),
......@@ -3219,7 +3324,7 @@ pub fn prettyPrintTokens(pp: *Preprocessor, w: anytype) !void {
32193324 .include_start => {
32203325 const source = pp.comp.getSource(cur.loc.id);
32213326
3222 try pp.printLinemarker(w, 0, source, .start);
3327 try pp.printLinemarker(w, 1, source, .start);
32233328 last_nl = true;
32243329 },
32253330 .include_resume => {
......@@ -3259,7 +3364,7 @@ test "Preserve pragma tokens sometimes" {
32593364
32603365 const test_runner_macros = try comp.addSourceFromBuffer("<test_runner>", source_text);
32613366 const eof = try pp.preprocess(test_runner_macros);
3262 try pp.tokens.append(pp.gpa, eof);
3367 try pp.addToken(eof);
32633368 try pp.prettyPrintTokens(buf.writer());
32643369 return allocator.dupe(u8, buf.items);
32653370 }
lib/compiler/aro/aro/Toolchain.zig+19
......@@ -487,3 +487,22 @@ pub fn addRuntimeLibs(tc: *const Toolchain, argv: *std.ArrayList([]const u8)) !v
487487 try argv.append("-ldl");
488488 }
489489}
490
491pub fn defineSystemIncludes(tc: *Toolchain) !void {
492 return switch (tc.inner) {
493 .uninitialized => unreachable,
494 .linux => |*linux| linux.defineSystemIncludes(tc),
495 .unknown => {
496 if (tc.driver.nostdinc) return;
497
498 const comp = tc.driver.comp;
499 if (!tc.driver.nobuiltininc) {
500 try comp.addBuiltinIncludeDir(tc.driver.aro_name);
501 }
502
503 if (!tc.driver.nostdlibinc) {
504 try comp.addSystemIncludeDir("/usr/include");
505 }
506 },
507 };
508}
lib/compiler/aro/aro/Tree.zig+15-10
......@@ -12,6 +12,16 @@ const StringInterner = @import("StringInterner.zig");
1212
1313pub const Token = struct {
1414 id: Id,
15 loc: Source.Location,
16
17 pub const List = std.MultiArrayList(Token);
18 pub const Id = Tokenizer.Token.Id;
19 pub const NumberPrefix = number_affixes.Prefix;
20 pub const NumberSuffix = number_affixes.Suffix;
21};
22
23pub const TokenWithExpansionLocs = struct {
24 id: Token.Id,
1525 flags: packed struct {
1626 expansion_disabled: bool = false,
1727 is_macro_arg: bool = false,
......@@ -22,15 +32,15 @@ pub const Token = struct {
2232 loc: Source.Location,
2333 expansion_locs: ?[*]Source.Location = null,
2434
25 pub fn expansionSlice(tok: Token) []const Source.Location {
35 pub fn expansionSlice(tok: TokenWithExpansionLocs) []const Source.Location {
2636 const locs = tok.expansion_locs orelse return &[0]Source.Location{};
2737 var i: usize = 0;
2838 while (locs[i].id != .unused) : (i += 1) {}
2939 return locs[0..i];
3040 }
3141
32 pub fn addExpansionLocation(tok: *Token, gpa: std.mem.Allocator, new: []const Source.Location) !void {
33 if (new.len == 0 or tok.id == .whitespace) return;
42 pub fn addExpansionLocation(tok: *TokenWithExpansionLocs, gpa: std.mem.Allocator, new: []const Source.Location) !void {
43 if (new.len == 0 or tok.id == .whitespace or tok.id == .macro_ws or tok.id == .placemarker) return;
3444 var list = std.ArrayList(Source.Location).init(gpa);
3545 defer {
3646 @memset(list.items.ptr[list.items.len..list.capacity], .{});
......@@ -70,14 +80,14 @@ pub const Token = struct {
7080 gpa.free(locs[0 .. i + 1]);
7181 }
7282
73 pub fn dupe(tok: Token, gpa: std.mem.Allocator) !Token {
83 pub fn dupe(tok: TokenWithExpansionLocs, gpa: std.mem.Allocator) !TokenWithExpansionLocs {
7484 var copy = tok;
7585 copy.expansion_locs = null;
7686 try copy.addExpansionLocation(gpa, tok.expansionSlice());
7787 return copy;
7888 }
7989
80 pub fn checkMsEof(tok: Token, source: Source, comp: *Compilation) !void {
90 pub fn checkMsEof(tok: TokenWithExpansionLocs, source: Source, comp: *Compilation) !void {
8191 std.debug.assert(tok.id == .eof);
8292 if (source.buf.len > tok.loc.byte_offset and source.buf[tok.loc.byte_offset] == 0x1A) {
8393 try comp.addDiagnostic(.{
......@@ -90,11 +100,6 @@ pub const Token = struct {
90100 }, &.{});
91101 }
92102 }
93
94 pub const List = std.MultiArrayList(Token);
95 pub const Id = Tokenizer.Token.Id;
96 pub const NumberPrefix = number_affixes.Prefix;
97 pub const NumberSuffix = number_affixes.Suffix;
98103};
99104
100105pub const TokenIndex = u32;
lib/compiler/aro/aro/Type.zig+5-2
......@@ -105,6 +105,7 @@ pub const Func = struct {
105105 fn eql(a: *const Func, b: *const Func, a_spec: Specifier, b_spec: Specifier, comp: *const Compilation) bool {
106106 // return type cannot have qualifiers
107107 if (!a.return_type.eql(b.return_type, comp, false)) return false;
108 if (a.params.len == 0 and b.params.len == 0) return true;
108109
109110 if (a.params.len != b.params.len) {
110111 if (a_spec == .old_style_func or b_spec == .old_style_func) {
......@@ -114,6 +115,7 @@ pub const Func = struct {
114115 }
115116 return true;
116117 }
118 return false;
117119 }
118120 if ((a_spec == .func) != (b_spec == .func)) return false;
119121 // TODO validate this
......@@ -887,7 +889,8 @@ pub fn hasIncompleteSize(ty: Type) bool {
887889 .@"struct", .@"union" => ty.data.record.isIncomplete(),
888890 .array, .static_array => ty.data.array.elem.hasIncompleteSize(),
889891 .typeof_type => ty.data.sub_type.hasIncompleteSize(),
890 .typeof_expr => ty.data.expr.ty.hasIncompleteSize(),
892 .typeof_expr, .variable_len_array => ty.data.expr.ty.hasIncompleteSize(),
893 .unspecified_variable_len_array => ty.data.sub_type.hasIncompleteSize(),
891894 .attributed => ty.data.attributed.base.hasIncompleteSize(),
892895 else => false,
893896 };
......@@ -1053,7 +1056,7 @@ pub fn bitSizeof(ty: Type, comp: *const Compilation) ?u64 {
10531056}
10541057
10551058pub fn alignable(ty: Type) bool {
1056 return ty.isArray() or !ty.hasIncompleteSize() or ty.is(.void);
1059 return (ty.isArray() or !ty.hasIncompleteSize() or ty.is(.void)) and !ty.is(.invalid);
10571060}
10581061
10591062/// Get the alignment of a type
lib/compiler/aro/aro/Value.zig+5-3
......@@ -60,7 +60,8 @@ test "minUnsignedBits" {
6060
6161 var comp = Compilation.init(std.testing.allocator);
6262 defer comp.deinit();
63 comp.target = (try std.zig.CrossTarget.parse(.{ .arch_os_abi = "x86_64-linux-gnu" })).toTarget();
63 const target_query = try std.Target.Query.parse(.{ .arch_os_abi = "x86_64-linux-gnu" });
64 comp.target = try std.zig.system.resolveTargetQuery(target_query);
6465
6566 try Test.checkIntBits(&comp, 0, 0);
6667 try Test.checkIntBits(&comp, 1, 1);
......@@ -94,7 +95,8 @@ test "minSignedBits" {
9495
9596 var comp = Compilation.init(std.testing.allocator);
9697 defer comp.deinit();
97 comp.target = (try std.zig.CrossTarget.parse(.{ .arch_os_abi = "x86_64-linux-gnu" })).toTarget();
98 const target_query = try std.Target.Query.parse(.{ .arch_os_abi = "x86_64-linux-gnu" });
99 comp.target = try std.zig.system.resolveTargetQuery(target_query);
98100
99101 try Test.checkIntBits(&comp, -1, 1);
100102 try Test.checkIntBits(&comp, -2, 2);
......@@ -224,7 +226,7 @@ pub fn intCast(v: *Value, dest_ty: Type, comp: *Compilation) !void {
224226 v.* = try intern(comp, .{ .int = .{ .big_int = result_bigint.toConst() } });
225227}
226228
227/// Converts the stored value from an integer to a float.
229/// Converts the stored value to a float of the specified type
228230/// `.none` value remains unchanged.
229231pub fn floatCast(v: *Value, dest_ty: Type, comp: *Compilation) !void {
230232 if (v.opt_ref == .none) return;
lib/compiler/aro/aro/pragmas/gcc.zig+9-9
......@@ -80,7 +80,7 @@ fn diagnosticHandler(self: *GCC, pp: *Preprocessor, start_idx: TokenIndex) Pragm
8080 .tag = .pragma_requires_string_literal,
8181 .loc = diagnostic_tok.loc,
8282 .extra = .{ .str = "GCC diagnostic" },
83 }, diagnostic_tok.expansionSlice());
83 }, pp.expansionSlice(start_idx));
8484 },
8585 else => |e| return e,
8686 };
......@@ -90,7 +90,7 @@ fn diagnosticHandler(self: *GCC, pp: *Preprocessor, start_idx: TokenIndex) Pragm
9090 .tag = .malformed_warning_check,
9191 .loc = next.loc,
9292 .extra = .{ .str = "GCC diagnostic" },
93 }, next.expansionSlice());
93 }, pp.expansionSlice(start_idx + 1));
9494 }
9595 const new_kind: Diagnostics.Kind = switch (diagnostic) {
9696 .ignored => .off,
......@@ -116,7 +116,7 @@ fn preprocessorHandler(pragma: *Pragma, pp: *Preprocessor, start_idx: TokenIndex
116116 return pp.comp.addDiagnostic(.{
117117 .tag = .unknown_gcc_pragma,
118118 .loc = directive_tok.loc,
119 }, directive_tok.expansionSlice());
119 }, pp.expansionSlice(start_idx + 1));
120120
121121 switch (gcc_pragma) {
122122 .warning, .@"error" => {
......@@ -126,7 +126,7 @@ fn preprocessorHandler(pragma: *Pragma, pp: *Preprocessor, start_idx: TokenIndex
126126 .tag = .pragma_requires_string_literal,
127127 .loc = directive_tok.loc,
128128 .extra = .{ .str = @tagName(gcc_pragma) },
129 }, directive_tok.expansionSlice());
129 }, pp.expansionSlice(start_idx + 1));
130130 },
131131 else => |e| return e,
132132 };
......@@ -134,7 +134,7 @@ fn preprocessorHandler(pragma: *Pragma, pp: *Preprocessor, start_idx: TokenIndex
134134 const diagnostic_tag: Diagnostics.Tag = if (gcc_pragma == .warning) .pragma_warning_message else .pragma_error_message;
135135 return pp.comp.addDiagnostic(
136136 .{ .tag = diagnostic_tag, .loc = directive_tok.loc, .extra = extra },
137 directive_tok.expansionSlice(),
137 pp.expansionSlice(start_idx + 1),
138138 );
139139 },
140140 .diagnostic => return self.diagnosticHandler(pp, start_idx + 2) catch |err| switch (err) {
......@@ -143,12 +143,12 @@ fn preprocessorHandler(pragma: *Pragma, pp: *Preprocessor, start_idx: TokenIndex
143143 return pp.comp.addDiagnostic(.{
144144 .tag = .unknown_gcc_pragma_directive,
145145 .loc = tok.loc,
146 }, tok.expansionSlice());
146 }, pp.expansionSlice(start_idx + 2));
147147 },
148148 else => |e| return e,
149149 },
150150 .poison => {
151 var i: usize = 2;
151 var i: u32 = 2;
152152 while (true) : (i += 1) {
153153 const tok = pp.tokens.get(start_idx + i);
154154 if (tok.id == .nl) break;
......@@ -157,14 +157,14 @@ fn preprocessorHandler(pragma: *Pragma, pp: *Preprocessor, start_idx: TokenIndex
157157 return pp.comp.addDiagnostic(.{
158158 .tag = .pragma_poison_identifier,
159159 .loc = tok.loc,
160 }, tok.expansionSlice());
160 }, pp.expansionSlice(start_idx + i));
161161 }
162162 const str = pp.expandedSlice(tok);
163163 if (pp.defines.get(str) != null) {
164164 try pp.comp.addDiagnostic(.{
165165 .tag = .pragma_poison_macro,
166166 .loc = tok.loc,
167 }, tok.expansionSlice());
167 }, pp.expansionSlice(start_idx + i));
168168 }
169169 try pp.poisoned_identifiers.put(str, {});
170170 }
lib/compiler/aro/aro/pragmas/message.zig+1-1
......@@ -28,7 +28,7 @@ fn deinit(pragma: *Pragma, comp: *Compilation) void {
2828
2929fn preprocessorHandler(_: *Pragma, pp: *Preprocessor, start_idx: TokenIndex) Pragma.Error!void {
3030 const message_tok = pp.tokens.get(start_idx);
31 const message_expansion_locs = message_tok.expansionSlice();
31 const message_expansion_locs = pp.expansionSlice(start_idx);
3232
3333 const str = Pragma.pasteTokens(pp, start_idx + 1) catch |err| switch (err) {
3434 error.ExpectedStringLiteral => {
lib/compiler/aro/aro/pragmas/once.zig+1-1
......@@ -45,7 +45,7 @@ fn preprocessorHandler(pragma: *Pragma, pp: *Preprocessor, start_idx: TokenIndex
4545 try pp.comp.addDiagnostic(.{
4646 .tag = .extra_tokens_directive_end,
4747 .loc = name_tok.loc,
48 }, next.expansionSlice());
48 }, pp.expansionSlice(start_idx + 1));
4949 }
5050 const seen = self.preprocess_count == pp.preprocess_count;
5151 const prev = try self.pragma_once.fetchPut(name_tok.loc.id, {});
lib/compiler/aro/aro/pragmas/pack.zig+1-1
......@@ -37,7 +37,7 @@ fn parserHandler(pragma: *Pragma, p: *Parser, start_idx: TokenIndex) Compilation
3737 return p.comp.addDiagnostic(.{
3838 .tag = .pragma_pack_lparen,
3939 .loc = l_paren.loc,
40 }, l_paren.expansionSlice());
40 }, p.pp.expansionSlice(idx));
4141 }
4242 idx += 1;
4343
lib/compiler/aro/aro/target.zig+10
......@@ -102,6 +102,16 @@ pub fn int16Type(target: std.Target) Type {
102102 };
103103}
104104
105/// sig_atomic_t for this target
106pub fn sigAtomicType(target: std.Target) Type {
107 if (target.cpu.arch.isWasm()) return .{ .specifier = .long };
108 return switch (target.cpu.arch) {
109 .avr => .{ .specifier = .schar },
110 .msp430 => .{ .specifier = .long },
111 else => .{ .specifier = .int },
112 };
113}
114
105115/// int64_t for this target
106116pub fn int64Type(target: std.Target) Type {
107117 switch (target.cpu.arch) {
lib/compiler/aro/aro/toolchains/Linux.zig+46-2
......@@ -373,6 +373,50 @@ fn getOSLibDir(target: std.Target) []const u8 {
373373 return "lib64";
374374}
375375
376pub fn defineSystemIncludes(self: *const Linux, tc: *const Toolchain) !void {
377 if (tc.driver.nostdinc) return;
378
379 const comp = tc.driver.comp;
380 const target = tc.getTarget();
381
382 // musl prefers /usr/include before builtin includes, so musl targets will add builtins
383 // at the end of this function (unless disabled with nostdlibinc)
384 if (!tc.driver.nobuiltininc and (!target.isMusl() or tc.driver.nostdlibinc)) {
385 try comp.addBuiltinIncludeDir(tc.driver.aro_name);
386 }
387
388 if (tc.driver.nostdlibinc) return;
389
390 const sysroot = tc.getSysroot();
391 const local_include = try std.fmt.allocPrint(comp.gpa, "{s}{s}", .{ sysroot, "/usr/local/include" });
392 defer comp.gpa.free(local_include);
393 try comp.addSystemIncludeDir(local_include);
394
395 if (self.gcc_detector.is_valid) {
396 const gcc_include_path = try std.fs.path.join(comp.gpa, &.{ self.gcc_detector.parent_lib_path, "..", self.gcc_detector.gcc_triple, "include" });
397 defer comp.gpa.free(gcc_include_path);
398 try comp.addSystemIncludeDir(gcc_include_path);
399 }
400
401 if (getMultiarchTriple(target)) |triple| {
402 const joined = try std.fs.path.join(comp.gpa, &.{ sysroot, "usr", "include", triple });
403 defer comp.gpa.free(joined);
404 if (tc.filesystem.exists(joined)) {
405 try comp.addSystemIncludeDir(joined);
406 }
407 }
408
409 if (target.os.tag == .rtems) return;
410
411 try comp.addSystemIncludeDir("/include");
412 try comp.addSystemIncludeDir("/usr/include");
413
414 std.debug.assert(!tc.driver.nostdlibinc);
415 if (!tc.driver.nobuiltininc and target.isMusl()) {
416 try comp.addBuiltinIncludeDir(tc.driver.aro_name);
417 }
418}
419
376420test Linux {
377421 if (@import("builtin").os.tag == .windows) return error.SkipZigTest;
378422
......@@ -388,8 +432,8 @@ test Linux {
388432 defer comp.environment = .{};
389433
390434 const raw_triple = "x86_64-linux-gnu";
391 const cross = std.zig.CrossTarget.parse(.{ .arch_os_abi = raw_triple }) catch unreachable;
392 comp.target = cross.toTarget(); // TODO deprecated
435 const target_query = try std.Target.Query.parse(.{ .arch_os_abi = raw_triple });
436 comp.target = try std.zig.system.resolveTargetQuery(target_query);
393437 comp.langopts.setEmulatedCompiler(.gcc);
394438
395439 var driver: Driver = .{ .comp = &comp };
lib/compiler/aro/backend/Interner.zig+2-2
......@@ -485,11 +485,11 @@ pub fn put(i: *Interner, gpa: Allocator, key: Key) !Ref {
485485 .data = try i.addExtra(gpa, Tag.F64.pack(data)),
486486 }),
487487 .f80 => |data| i.items.appendAssumeCapacity(.{
488 .tag = .f64,
488 .tag = .f80,
489489 .data = try i.addExtra(gpa, Tag.F80.pack(data)),
490490 }),
491491 .f128 => |data| i.items.appendAssumeCapacity(.{
492 .tag = .f64,
492 .tag = .f128,
493493 .data = try i.addExtra(gpa, Tag.F128.pack(data)),
494494 }),
495495 },
lib/compiler/aro/backend/Ir.zig+1-1
......@@ -649,7 +649,7 @@ fn writeValue(ir: Ir, val: Interner.Ref, config: std.io.tty.Config, w: anytype)
649649 .float => |repr| switch (repr) {
650650 inline else => |x| return w.print("{d}", .{@as(f64, @floatCast(x))}),
651651 },
652 .bytes => |b| return std.zig.fmt.stringEscape(b, "", .{}, w),
652 .bytes => |b| return std.zig.stringEscape(b, "", .{}, w),
653653 else => unreachable, // not a value
654654 }
655655}