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...@@ -12,4 +12,4 @@ lib/libcxx/** linguist-vendored
12lib/libcxxabi/** linguist-vendored12lib/libcxxabi/** linguist-vendored
13lib/libunwind/** linguist-vendored13lib/libunwind/** linguist-vendored
14lib/tsan/** linguist-vendored14lib/tsan/** linguist-vendored
15deps/** linguist-vendored15lib/compiler/aro/** linguist-vendored
lib/compiler/aro/README.md+1-2
...@@ -20,8 +20,7 @@ int main(void) {...@@ -20,8 +20,7 @@ int main(void) {
20 printf("Hello, world!\n");20 printf("Hello, world!\n");
21 return 0;21 return 0;
22}22}
23$ zig build run -- hello.c -o hello23$ zig build && ./zig-out/bin/arocc hello.c -o hello
24$ ./hello24$ ./hello
25Hello, world!25Hello, world!
26$
27```26```
lib/compiler/aro/aro/Attribute/names.zig+6-16
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1//! Autogenerated by GenerateDef from deps/aro/aro/Attribute/names.def, do not edit1//! Autogenerated by GenerateDef from src/aro/Attribute/names.def, do not edit
2// zig fmt: off2// zig fmt: off
33
4const std = @import("std");4const std = @import("std");
...@@ -142,15 +142,7 @@ pub fn nameFromUniqueIndex(index: u16, buf: []u8) []u8 {...@@ -142,15 +142,7 @@ pub fn nameFromUniqueIndex(index: u16, buf: []u8) []u8 {
142 return fbs.getWritten();142 return fbs.getWritten();
143}143}
144144
145/// We're 1 bit shy of being able to fit this in a u32:145const Node = packed struct(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) {
154 char: u8,146 char: u8,
155 /// Nodes are numbered with "an integer which gives the number of words that147 /// Nodes are numbered with "an integer which gives the number of words that
156 /// would be accepted by the automaton starting from that state." This numbering148 /// would be accepted by the automaton starting from that state." This numbering
...@@ -158,18 +150,16 @@ const Node = packed struct(u64) {...@@ -158,18 +150,16 @@ const Node = packed struct(u64) {
158 /// (L is the number of words accepted by the automaton) and the words themselves."150 /// (L is the number of words accepted by the automaton) and the words themselves."
159 ///151 ///
160 /// Essentially, this allows us to have a minimal perfect hashing scheme such that152 /// 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.153 /// it's possible to store & lookup the properties of each name using a separate array.
162 number: u16,154 number: u8,
163 /// If true, this node is the end of a valid builtin.155 /// If true, this node is the end of a valid name.
164 /// Note: This does not necessarily mean that this node does not have child nodes.156 /// Note: This does not necessarily mean that this node does not have child nodes.
165 end_of_word: bool,157 end_of_word: bool,
166 /// If true, this node is the end of a sibling list.158 /// If true, this node is the end of a sibling list.
167 /// If false, then (index + 1) will contain the next sibling.159 /// If false, then (index + 1) will contain the next sibling.
168 end_of_list: bool,160 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,
171 /// Index of the first child of this node.161 /// Index of the first child of this node.
172 child_index: u16,162 child_index: u14,
173};163};
174164
175const dafsa = [_]Node{165const dafsa = [_]Node{
lib/compiler/aro/aro/Builtins.zig+1-4
...@@ -99,10 +99,7 @@ fn createType(desc: TypeDescription, it: *TypeDescription.TypeIterator, comp: *c...@@ -99,10 +99,7 @@ fn createType(desc: TypeDescription, it: *TypeDescription.TypeIterator, comp: *c
99 }99 }
100 },100 },
101 .h => builder.combine(undefined, .fp16, 0) catch unreachable,101 .h => builder.combine(undefined, .fp16, 0) catch unreachable,
102 .x => {102 .x => builder.combine(undefined, .float16, 0) catch unreachable,
103 // Todo: _Float16
104 return .{ .specifier = .invalid };
105 },
106 .y => {103 .y => {
107 // Todo: __bf16104 // Todo: __bf16
108 return .{ .specifier = .invalid };105 return .{ .specifier = .invalid };
lib/compiler/aro/aro/Builtins/Builtin.zig+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1//! Autogenerated by GenerateDef from deps/aro/aro/Builtins/Builtin.def, do not edit1//! Autogenerated by GenerateDef from src/aro/Builtins/Builtin.def, do not edit
2// zig fmt: off2// zig fmt: off
33
4const std = @import("std");4const std = @import("std");
lib/compiler/aro/aro/Compilation.zig+39-20
...@@ -241,6 +241,12 @@ pub const SystemDefinesMode = enum {...@@ -241,6 +241,12 @@ pub const SystemDefinesMode = enum {
241fn generateSystemDefines(comp: *Compilation, w: anytype) !void {241fn generateSystemDefines(comp: *Compilation, w: anytype) !void {
242 const ptr_width = comp.target.ptrBitWidth();242 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
244 // os macros250 // os macros
245 switch (comp.target.os.tag) {251 switch (comp.target.os.tag) {
246 .linux => try w.writeAll(252 .linux => try w.writeAll(
...@@ -419,6 +425,25 @@ fn generateSystemDefines(comp: *Compilation, w: anytype) !void {...@@ -419,6 +425,25 @@ fn generateSystemDefines(comp: *Compilation, w: anytype) !void {
419 \\425 \\
420 );426 );
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
422 // types447 // types
423 if (comp.getCharSignedness() == .unsigned) try w.writeAll("#define __CHAR_UNSIGNED__ 1\n");448 if (comp.getCharSignedness() == .unsigned) try w.writeAll("#define __CHAR_UNSIGNED__ 1\n");
424 try w.writeAll("#define __CHAR_BIT__ 8\n");449 try w.writeAll("#define __CHAR_BIT__ 8\n");
...@@ -438,6 +463,7 @@ fn generateSystemDefines(comp: *Compilation, w: anytype) !void {...@@ -438,6 +463,7 @@ fn generateSystemDefines(comp: *Compilation, w: anytype) !void {
438 try comp.generateIntMaxAndWidth(w, "PTRDIFF", comp.types.ptrdiff);463 try comp.generateIntMaxAndWidth(w, "PTRDIFF", comp.types.ptrdiff);
439 try comp.generateIntMaxAndWidth(w, "INTPTR", comp.types.intptr);464 try comp.generateIntMaxAndWidth(w, "INTPTR", comp.types.intptr);
440 try comp.generateIntMaxAndWidth(w, "UINTPTR", comp.types.intptr.makeIntegerUnsigned());465 try comp.generateIntMaxAndWidth(w, "UINTPTR", comp.types.intptr.makeIntegerUnsigned());
466 try comp.generateIntMaxAndWidth(w, "SIG_ATOMIC", target_util.sigAtomicType(comp.target));
441467
442 // int widths468 // int widths
443 try w.print("#define __BITINT_MAXWIDTH__ {d}\n", .{bit_int_max_bits});469 try w.print("#define __BITINT_MAXWIDTH__ {d}\n", .{bit_int_max_bits});
...@@ -474,6 +500,8 @@ fn generateSystemDefines(comp: *Compilation, w: anytype) !void {...@@ -474,6 +500,8 @@ fn generateSystemDefines(comp: *Compilation, w: anytype) !void {
474 try generateTypeMacro(w, mapper, "__PTRDIFF_TYPE__", comp.types.ptrdiff, comp.langopts);500 try generateTypeMacro(w, mapper, "__PTRDIFF_TYPE__", comp.types.ptrdiff, comp.langopts);
475 try generateTypeMacro(w, mapper, "__SIZE_TYPE__", comp.types.size, comp.langopts);501 try generateTypeMacro(w, mapper, "__SIZE_TYPE__", comp.types.size, comp.langopts);
476 try generateTypeMacro(w, mapper, "__WCHAR_TYPE__", comp.types.wchar, comp.langopts);502 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
478 try comp.generateExactWidthTypes(w, mapper);506 try comp.generateExactWidthTypes(w, mapper);
479 try comp.generateFastAndLeastWidthTypes(w, mapper);507 try comp.generateFastAndLeastWidthTypes(w, mapper);
...@@ -518,7 +546,6 @@ pub fn generateBuiltinMacros(comp: *Compilation, system_defines_mode: SystemDefi...@@ -518,7 +546,6 @@ pub fn generateBuiltinMacros(comp: *Compilation, system_defines_mode: SystemDefi
518546
519 // standard macros547 // standard macros
520 try buf.appendSlice(548 try buf.appendSlice(
521 \\#define __STDC_NO_ATOMICS__ 1
522 \\#define __STDC_NO_COMPLEX__ 1549 \\#define __STDC_NO_COMPLEX__ 1
523 \\#define __STDC_NO_THREADS__ 1550 \\#define __STDC_NO_THREADS__ 1
524 \\#define __STDC_NO_VLA__ 1551 \\#define __STDC_NO_VLA__ 1
...@@ -1030,9 +1057,8 @@ pub fn getCharSignedness(comp: *const Compilation) std.builtin.Signedness {...@@ -1030,9 +1057,8 @@ pub fn getCharSignedness(comp: *const Compilation) std.builtin.Signedness {
1030 return comp.langopts.char_signedness_override orelse comp.target.charSignedness();1057 return comp.langopts.char_signedness_override orelse comp.target.charSignedness();
1031}1058}
10321059
1033pub fn defineSystemIncludes(comp: *Compilation, aro_dir: []const u8) !void {1060/// Add built-in aro headers directory to system include paths
1034 var stack_fallback = std.heap.stackFallback(path_buf_stack_limit, comp.gpa);1061pub fn addBuiltinIncludeDir(comp: *Compilation, aro_dir: []const u8) !void {
1035 const allocator = stack_fallback.get();
1036 var search_path = aro_dir;1062 var search_path = aro_dir;
1037 while (std.fs.path.dirname(search_path)) |dirname| : (search_path = dirname) {1063 while (std.fs.path.dirname(search_path)) |dirname| : (search_path = dirname) {
1038 var base_dir = std.fs.cwd().openDir(dirname, .{}) catch continue;1064 var base_dir = std.fs.cwd().openDir(dirname, .{}) catch continue;
...@@ -1044,23 +1070,12 @@ pub fn defineSystemIncludes(comp: *Compilation, aro_dir: []const u8) !void {...@@ -1044,23 +1070,12 @@ pub fn defineSystemIncludes(comp: *Compilation, aro_dir: []const u8) !void {
1044 try comp.system_include_dirs.append(comp.gpa, path);1070 try comp.system_include_dirs.append(comp.gpa, path);
1045 break;1071 break;
1046 } else return error.AroIncludeNotFound;1072 } else return error.AroIncludeNotFound;
1073}
10471074
1048 if (comp.target.os.tag == .linux) {1075pub fn addSystemIncludeDir(comp: *Compilation, path: []const u8) !void {
1049 const triple_str = try comp.target.linuxTriple(allocator);1076 const duped = try comp.gpa.dupe(u8, path);
1050 defer allocator.free(triple_str);1077 errdefer comp.gpa.free(duped);
10511078 try comp.system_include_dirs.append(comp.gpa, duped);
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);
1064}1079}
10651080
1066pub fn getSource(comp: *const Compilation, id: Source.Id) Source {1081pub fn getSource(comp: *const Compilation, id: Source.Id) Source {
...@@ -1331,6 +1346,10 @@ pub fn hasInclude(...@@ -1331,6 +1346,10 @@ pub fn hasInclude(
1331 /// __has_include vs __has_include_next1346 /// __has_include vs __has_include_next
1332 which: WhichInclude,1347 which: WhichInclude,
1333) !bool {1348) !bool {
1349 if (mem.indexOfScalar(u8, filename, 0) != null) {
1350 return false;
1351 }
1352
1334 const cwd = std.fs.cwd();1353 const cwd = std.fs.cwd();
1335 if (std.fs.path.isAbsolute(filename)) {1354 if (std.fs.path.isAbsolute(filename)) {
1336 if (which == .next) return false;1355 if (which == .next) return false;
lib/compiler/aro/aro/Diagnostics.zig+3-1
...@@ -208,6 +208,8 @@ pub const Options = struct {...@@ -208,6 +208,8 @@ pub const Options = struct {
208 @"unsupported-embed-param": Kind = .default,208 @"unsupported-embed-param": Kind = .default,
209 @"unused-result": Kind = .default,209 @"unused-result": Kind = .default,
210 normalized: Kind = .default,210 normalized: Kind = .default,
211 @"shift-count-negative": Kind = .default,
212 @"shift-count-overflow": Kind = .default,
211};213};
212214
213const Diagnostics = @This();215const Diagnostics = @This();
...@@ -291,7 +293,7 @@ pub fn addExtra(...@@ -291,7 +293,7 @@ pub fn addExtra(
291 .kind = .note,293 .kind = .note,
292 .extra = .{ .unsigned = expansion_locs.len - d.macro_backtrace_limit },294 .extra = .{ .unsigned = expansion_locs.len - d.macro_backtrace_limit },
293 });295 });
294 i = half - 1;296 i = half -| 1;
295 while (i > 0) {297 while (i > 0) {
296 i -= 1;298 i -= 1;
297 d.list.appendAssumeCapacity(.{299 d.list.appendAssumeCapacity(.{
lib/compiler/aro/aro/Diagnostics/messages.zig+11-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1//! Autogenerated by GenerateDef from deps/aro/aro/Diagnostics/messages.def, do not edit1//! Autogenerated by GenerateDef from src/aro/Diagnostics/messages.def, do not edit
2// zig fmt: off2// zig fmt: off
33
4const std = @import("std");4const std = @import("std");
...@@ -504,6 +504,11 @@ pub const Tag = enum {...@@ -504,6 +504,11 @@ pub const Tag = enum {
504 c23_auto_single_declarator,504 c23_auto_single_declarator,
505 c32_auto_requires_initializer,505 c32_auto_requires_initializer,
506 c23_auto_scalar_init,506 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
508 pub fn property(tag: Tag) Properties {513 pub fn property(tag: Tag) Properties {
509 return named_data[@intFromEnum(tag)];514 return named_data[@intFromEnum(tag)];
...@@ -1005,6 +1010,11 @@ pub const Tag = enum {...@@ -1005,6 +1010,11 @@ pub const Tag = enum {
1005 .{ .msg = "'auto' can only be used with a single declarator", .kind = .@"error" },1010 .{ .msg = "'auto' can only be used with a single declarator", .kind = .@"error" },
1006 .{ .msg = "'auto' requires an initializer", .kind = .@"error" },1011 .{ .msg = "'auto' requires an initializer", .kind = .@"error" },
1007 .{ .msg = "'auto' requires a scalar initializer", .kind = .@"error" },1012 .{ .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" },
1008 };1018 };
1009};1019};
1010};1020};
lib/compiler/aro/aro/Driver.zig+27-3
...@@ -12,6 +12,7 @@ const Preprocessor = @import("Preprocessor.zig");...@@ -12,6 +12,7 @@ const Preprocessor = @import("Preprocessor.zig");
12const Source = @import("Source.zig");12const Source = @import("Source.zig");
13const Toolchain = @import("Toolchain.zig");13const Toolchain = @import("Toolchain.zig");
14const target_util = @import("target.zig");14const target_util = @import("target.zig");
15const GCCVersion = @import("Driver/GCCVersion.zig");
1516
16pub const Linker = enum {17pub const Linker = enum {
17 ld,18 ld,
...@@ -43,6 +44,9 @@ verbose_pp: bool = false,...@@ -43,6 +44,9 @@ verbose_pp: bool = false,
43verbose_ir: bool = false,44verbose_ir: bool = false,
44verbose_linker_args: bool = false,45verbose_linker_args: bool = false,
45color: ?bool = null,46color: ?bool = null,
47nobuiltininc: bool = false,
48nostdinc: bool = false,
49nostdlibinc: bool = false,
4650
47/// Full path to the aro executable51/// Full path to the aro executable
48aro_name: []const u8 = "",52aro_name: []const u8 = "",
...@@ -95,6 +99,7 @@ pub const usage =...@@ -95,6 +99,7 @@ pub const usage =
95 \\ -fcolor-diagnostics Enable colors in diagnostics99 \\ -fcolor-diagnostics Enable colors in diagnostics
96 \\ -fno-color-diagnostics Disable colors in diagnostics100 \\ -fno-color-diagnostics Disable colors in diagnostics
97 \\ -fdeclspec Enable support for __declspec attributes101 \\ -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.
98 \\ -fno-declspec Disable support for __declspec attributes103 \\ -fno-declspec Disable support for __declspec attributes
99 \\ -ffp-eval-method=[source|double|extended]104 \\ -ffp-eval-method=[source|double|extended]
100 \\ Evaluation method to use for floating-point arithmetic105 \\ Evaluation method to use for floating-point arithmetic
...@@ -127,6 +132,10 @@ pub const usage =...@@ -127,6 +132,10 @@ pub const usage =
127 \\ -isystem Add directory to SYSTEM include search path132 \\ -isystem Add directory to SYSTEM include search path
128 \\ --emulate=[clang|gcc|msvc]133 \\ --emulate=[clang|gcc|msvc]
129 \\ Select which C compiler to emulate (default clang)134 \\ 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
130 \\ -o <file> Write output to <file>139 \\ -o <file> Write output to <file>
131 \\ -P, --no-line-commands Disable linemarker output in -E mode140 \\ -P, --no-line-commands Disable linemarker output in -E mode
132 \\ -pedantic Warn on language extensions141 \\ -pedantic Warn on language extensions
...@@ -180,6 +189,7 @@ pub fn parseArgs(...@@ -180,6 +189,7 @@ pub fn parseArgs(
180 var i: usize = 1;189 var i: usize = 1;
181 var comment_arg: []const u8 = "";190 var comment_arg: []const u8 = "";
182 var hosted: ?bool = null;191 var hosted: ?bool = null;
192 var gnuc_version: []const u8 = "4.2.1"; // default value set by clang
183 while (i < args.len) : (i += 1) {193 while (i < args.len) : (i += 1) {
184 const arg = args[i];194 const arg = args[i];
185 if (mem.startsWith(u8, arg, "-") and arg.len > 1) {195 if (mem.startsWith(u8, arg, "-") and arg.len > 1) {
...@@ -303,6 +313,10 @@ pub fn parseArgs(...@@ -303,6 +313,10 @@ pub fn parseArgs(
303 d.only_syntax = true;313 d.only_syntax = true;
304 } else if (mem.startsWith(u8, arg, "-fno-syntax-only")) {314 } else if (mem.startsWith(u8, arg, "-fno-syntax-only")) {
305 d.only_syntax = false;315 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;
306 } else if (mem.startsWith(u8, arg, "-isystem")) {320 } else if (mem.startsWith(u8, arg, "-isystem")) {
307 var path = arg["-isystem".len..];321 var path = arg["-isystem".len..];
308 if (path.len == 0) {322 if (path.len == 0) {
...@@ -421,6 +435,12 @@ pub fn parseArgs(...@@ -421,6 +435,12 @@ pub fn parseArgs(
421 d.nodefaultlibs = true;435 d.nodefaultlibs = true;
422 } else if (mem.eql(u8, arg, "-nolibc")) {436 } else if (mem.eql(u8, arg, "-nolibc")) {
423 d.nolibc = true;437 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;
424 } else if (mem.eql(u8, arg, "-nostdlib")) {444 } else if (mem.eql(u8, arg, "-nostdlib")) {
425 d.nostdlib = true;445 d.nostdlib = true;
426 } else if (mem.eql(u8, arg, "-nostartfiles")) {446 } else if (mem.eql(u8, arg, "-nostartfiles")) {
...@@ -459,6 +479,11 @@ pub fn parseArgs(...@@ -459,6 +479,11 @@ pub fn parseArgs(
459 d.comp.target.os.tag = .freestanding;479 d.comp.target.os.tag = .freestanding;
460 }480 }
461 }481 }
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();
462 return false;487 return false;
463}488}
464489
...@@ -558,7 +583,8 @@ pub fn main(d: *Driver, tc: *Toolchain, args: []const []const u8, comptime fast_...@@ -558,7 +583,8 @@ pub fn main(d: *Driver, tc: *Toolchain, args: []const []const u8, comptime fast_
558 try d.comp.addDiagnostic(.{ .tag = .cli_unused_link_object, .extra = .{ .str = obj } }, &.{});583 try d.comp.addDiagnostic(.{ .tag = .cli_unused_link_object, .extra = .{ .str = obj } }, &.{});
559 };584 };
560585
561 d.comp.defineSystemIncludes(d.aro_name) catch |er| switch (er) {586 try tc.discover();
587 tc.defineSystemIncludes() catch |er| switch (er) {
562 error.OutOfMemory => return error.OutOfMemory,588 error.OutOfMemory => return error.OutOfMemory,
563 error.AroIncludeNotFound => return d.fatal("unable to find Aro builtin headers", .{}),589 error.AroIncludeNotFound => return d.fatal("unable to find Aro builtin headers", .{}),
564 };590 };
...@@ -763,8 +789,6 @@ fn dumpLinkerArgs(items: []const []const u8) !void {...@@ -763,8 +789,6 @@ fn dumpLinkerArgs(items: []const []const u8) !void {
763/// The entry point of the Aro compiler.789/// The entry point of the Aro compiler.
764/// **MAY call `exit` if `fast_exit` is set.**790/// **MAY call `exit` if `fast_exit` is set.**
765pub fn invokeLinker(d: *Driver, tc: *Toolchain, comptime fast_exit: bool) !void {791pub fn invokeLinker(d: *Driver, tc: *Toolchain, comptime fast_exit: bool) !void {
766 try tc.discover();
767
768 var argv = std.ArrayList([]const u8).init(d.comp.gpa);792 var argv = std.ArrayList([]const u8).init(d.comp.gpa);
769 defer argv.deinit();793 defer argv.deinit();
770794
lib/compiler/aro/aro/Driver/GCCVersion.zig+10
...@@ -98,6 +98,16 @@ pub fn order(a: GCCVersion, b: GCCVersion) Order {...@@ -98,6 +98,16 @@ pub fn order(a: GCCVersion, b: GCCVersion) Order {
98 return .eq;98 return .eq;
99}99}
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
101test parse {111test parse {
102 const versions = [10]GCCVersion{112 const versions = [10]GCCVersion{
103 parse("5"),113 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,...@@ -135,6 +135,11 @@ preserve_comments: bool = false,
135/// Preserve comments in macros when preprocessing135/// Preserve comments in macros when preprocessing
136preserve_comments_in_macros: bool = false,136preserve_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
138pub fn setStandard(self: *LangOpts, name: []const u8) error{InvalidStandard}!void {143pub fn setStandard(self: *LangOpts, name: []const u8) error{InvalidStandard}!void {
139 self.standard = Standard.NameMap.get(name) orelse return error.InvalidStandard;144 self.standard = Standard.NameMap.get(name) orelse return error.InvalidStandard;
140}145}
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...@@ -403,7 +403,7 @@ pub fn errExtra(p: *Parser, tag: Diagnostics.Tag, tok_i: TokenIndex, extra: Diag
403 .tag = tag,403 .tag = tag,
404 .loc = loc,404 .loc = loc,
405 .extra = extra,405 .extra = extra,
406 }, tok.expansionSlice());406 }, p.pp.expansionSlice(tok_i));
407}407}
408408
409pub fn errTok(p: *Parser, tag: Diagnostics.Tag, tok_i: TokenIndex) Compilation.Error!void {409pub 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 {...@@ -432,6 +432,11 @@ pub fn removeNull(p: *Parser, str: Value) !Value {
432}432}
433433
434pub fn typeStr(p: *Parser, ty: Type) ![]const u8 {434pub 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 }
435 if (Type.Builder.fromType(ty).str(p.comp.langopts)) |str| return str;440 if (Type.Builder.fromType(ty).str(p.comp.langopts)) |str| return str;
436 const strings_top = p.strings.items.len;441 const strings_top = p.strings.items.len;
437 defer p.strings.items.len = strings_top;442 defer p.strings.items.len = strings_top;
...@@ -446,6 +451,11 @@ pub fn typePairStr(p: *Parser, a: Type, b: Type) ![]const u8 {...@@ -446,6 +451,11 @@ pub fn typePairStr(p: *Parser, a: Type, b: Type) ![]const u8 {
446}451}
447452
448pub fn typePairStrExtra(p: *Parser, a: Type, msg: []const u8, b: Type) ![]const u8 {453pub 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 }
449 const strings_top = p.strings.items.len;459 const strings_top = p.strings.items.len;
450 defer p.strings.items.len = strings_top;460 defer p.strings.items.len = strings_top;
451461
...@@ -635,7 +645,6 @@ fn diagnoseIncompleteDefinitions(p: *Parser) !void {...@@ -635,7 +645,6 @@ fn diagnoseIncompleteDefinitions(p: *Parser) !void {
635 const tys = node_slices.items(.ty);645 const tys = node_slices.items(.ty);
636 const data = node_slices.items(.data);646 const data = node_slices.items(.data);
637647
638 const err_start = p.comp.diagnostics.list.items.len;
639 for (p.decl_buf.items) |decl_node| {648 for (p.decl_buf.items) |decl_node| {
640 const idx = @intFromEnum(decl_node);649 const idx = @intFromEnum(decl_node);
641 switch (tags[idx]) {650 switch (tags[idx]) {
...@@ -656,8 +665,6 @@ fn diagnoseIncompleteDefinitions(p: *Parser) !void {...@@ -656,8 +665,6 @@ fn diagnoseIncompleteDefinitions(p: *Parser) !void {
656 try p.errStr(.tentative_definition_incomplete, tentative_def_tok, type_str);665 try p.errStr(.tentative_definition_incomplete, tentative_def_tok, type_str);
657 try p.errStr(.forward_declaration_here, data[idx].decl_ref, type_str);666 try p.errStr(.forward_declaration_here, data[idx].decl_ref, type_str);
658 }667 }
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
661}668}
662669
663/// root : (decl | assembly ';' | staticAssert)*670/// root : (decl | assembly ';' | staticAssert)*
...@@ -2201,7 +2208,15 @@ fn recordSpec(p: *Parser) Error!Type {...@@ -2201,7 +2208,15 @@ fn recordSpec(p: *Parser) Error!Type {
2201 } else {2208 } else {
2202 record_ty.fields = try p.arena.dupe(Type.Record.Field, p.record_buf.items[record_buf_top..]);2209 record_ty.fields = try p.arena.dupe(Type.Record.Field, p.record_buf.items[record_buf_top..]);
2203 }2210 }
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 }
2205 const field_attr_slice = p.field_attr_buf.items[old_field_attr_start..];2220 const field_attr_slice = p.field_attr_buf.items[old_field_attr_start..];
2206 const duped = try p.arena.dupe([]const Attribute, field_attr_slice);2221 const duped = try p.arena.dupe([]const Attribute, field_attr_slice);
2207 record_ty.field_attributes = duped.ptr;2222 record_ty.field_attributes = duped.ptr;
...@@ -2242,7 +2257,6 @@ fn recordSpec(p: *Parser) Error!Type {...@@ -2242,7 +2257,6 @@ fn recordSpec(p: *Parser) Error!Type {
2242 .ty = ty,2257 .ty = ty,
2243 .data = .{ .bin = .{ .lhs = .none, .rhs = .none } },2258 .data = .{ .bin = .{ .lhs = .none, .rhs = .none } },
2244 };2259 };
2245 const record_decls = p.decl_buf.items[decl_buf_top..];
2246 switch (record_decls.len) {2260 switch (record_decls.len) {
2247 0 => {},2261 0 => {},
2248 1 => node.data = .{ .bin = .{ .lhs = record_decls[0], .rhs = .none } },2262 1 => node.data = .{ .bin = .{ .lhs = record_decls[0], .rhs = .none } },
...@@ -2560,6 +2574,7 @@ fn enumSpec(p: *Parser) Error!Type {...@@ -2560,6 +2574,7 @@ fn enumSpec(p: *Parser) Error!Type {
2560 if (field.ty.eql(Type.int, p.comp, false)) continue;2574 if (field.ty.eql(Type.int, p.comp, false)) continue;
25612575
2562 const sym = p.syms.get(field.name, .vars) orelse continue;2576 const sym = p.syms.get(field.name, .vars) orelse continue;
2577 if (sym.kind != .enumeration) continue; // already an error
25632578
2564 var res = Result{ .node = field.node, .ty = field.ty, .val = sym.val };2579 var res = Result{ .node = field.node, .ty = field.ty, .val = sym.val };
2565 const dest_ty = if (p.comp.fixedEnumTagSpecifier()) |some|2580 const dest_ty = if (p.comp.fixedEnumTagSpecifier()) |some|
...@@ -4603,24 +4618,31 @@ fn nodeIsNoreturn(p: *Parser, node: NodeIndex) NoreturnKind {...@@ -4603,24 +4618,31 @@ fn nodeIsNoreturn(p: *Parser, node: NodeIndex) NoreturnKind {
4603 },4618 },
4604 .compound_stmt_two => {4619 .compound_stmt_two => {
4605 const data = p.nodes.items(.data)[@intFromEnum(node)];4620 const data = p.nodes.items(.data)[@intFromEnum(node)];
4606 if (data.bin.rhs != .none) return p.nodeIsNoreturn(data.bin.rhs);4621 const lhs_type = if (data.bin.lhs != .none) p.nodeIsNoreturn(data.bin.lhs) else .no;
4607 if (data.bin.lhs != .none) return p.nodeIsNoreturn(data.bin.lhs);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;
4608 return .no;4625 return .no;
4609 },4626 },
4610 .compound_stmt => {4627 .compound_stmt => {
4611 const data = p.nodes.items(.data)[@intFromEnum(node)];4628 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;
4613 },4635 },
4614 .labeled_stmt => {4636 .labeled_stmt => {
4615 const data = p.nodes.items(.data)[@intFromEnum(node)];4637 const data = p.nodes.items(.data)[@intFromEnum(node)];
4616 return p.nodeIsNoreturn(data.decl.node);4638 return p.nodeIsNoreturn(data.decl.node);
4617 },4639 },
4618 .switch_stmt => {4640 .default_stmt => {
4619 const data = p.nodes.items(.data)[@intFromEnum(node)];4641 const data = p.nodes.items(.data)[@intFromEnum(node)];
4620 if (data.bin.rhs == .none) return .complex;4642 if (data.un == .none) return .no;
4621 if (p.nodeIsNoreturn(data.bin.rhs) == .yes) return .yes;4643 return p.nodeIsNoreturn(data.un);
4622 return .complex;
4623 },4644 },
4645 .while_stmt, .do_while_stmt, .for_decl_stmt, .forever_stmt, .for_stmt, .switch_stmt => return .complex,
4624 else => return .no,4646 else => return .no,
4625 }4647 }
4626}4648}
...@@ -4787,7 +4809,11 @@ const CallExpr = union(enum) {...@@ -4787,7 +4809,11 @@ const CallExpr = union(enum) {
4787 Builtin.tagFromName("__va_start").?,4809 Builtin.tagFromName("__va_start").?,
4788 Builtin.tagFromName("va_start").?,4810 Builtin.tagFromName("va_start").?,
4789 => arg_idx != 1,4811 => 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,
4791 else => true,4817 else => true,
4792 },4818 },
4793 };4819 };
...@@ -4800,6 +4826,7 @@ const CallExpr = union(enum) {...@@ -4800,6 +4826,7 @@ const CallExpr = union(enum) {
4800 }4826 }
48014827
4802 fn checkVarArg(self: CallExpr, p: *Parser, first_after: TokenIndex, param_tok: TokenIndex, arg: *Result, arg_idx: u32) !void {4828 fn checkVarArg(self: CallExpr, p: *Parser, first_after: TokenIndex, param_tok: TokenIndex, arg: *Result, arg_idx: u32) !void {
4829 @setEvalBranchQuota(10_000);
4803 if (self == .standard) return;4830 if (self == .standard) return;
48044831
4805 const builtin_tok = p.nodes.items(.data)[@intFromEnum(self.builtin.node)].decl.name;4832 const builtin_tok = p.nodes.items(.data)[@intFromEnum(self.builtin.node)].decl.name;
...@@ -4809,6 +4836,11 @@ const CallExpr = union(enum) {...@@ -4809,6 +4836,11 @@ const CallExpr = union(enum) {
4809 Builtin.tagFromName("va_start").?,4836 Builtin.tagFromName("va_start").?,
4810 => return p.checkVaStartArg(builtin_tok, first_after, param_tok, arg, arg_idx),4837 => return p.checkVaStartArg(builtin_tok, first_after, param_tok, arg, arg_idx),
4811 Builtin.tagFromName("__builtin_complex").? => return p.checkComplexArg(builtin_tok, first_after, param_tok, arg, arg_idx),4838 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
4812 else => {},4844 else => {},
4813 }4845 }
4814 }4846 }
...@@ -4823,16 +4855,44 @@ const CallExpr = union(enum) {...@@ -4823,16 +4855,44 @@ const CallExpr = union(enum) {
4823 return switch (self) {4855 return switch (self) {
4824 .standard => null,4856 .standard => null,
4825 .builtin => |builtin| switch (builtin.tag) {4857 .builtin => |builtin| switch (builtin.tag) {
4826 Builtin.tagFromName("__builtin_complex").? => 2,4858 Builtin.tagFromName("__c11_atomic_thread_fence").?,
48274859 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").?,
4828 Builtin.tagFromName("__atomic_fetch_add").?,4875 Builtin.tagFromName("__atomic_fetch_add").?,
4829 Builtin.tagFromName("__atomic_fetch_sub").?,4876 Builtin.tagFromName("__atomic_fetch_sub").?,
4830 Builtin.tagFromName("__atomic_fetch_and").?,4877 Builtin.tagFromName("__atomic_fetch_and").?,
4831 Builtin.tagFromName("__atomic_fetch_xor").?,4878 Builtin.tagFromName("__atomic_fetch_xor").?,
4832 Builtin.tagFromName("__atomic_fetch_or").?,4879 Builtin.tagFromName("__atomic_fetch_or").?,
4833 Builtin.tagFromName("__atomic_fetch_nand").?,4880 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").?,
4834 => 3,4890 => 3,
48354891
4892 Builtin.tagFromName("__c11_atomic_compare_exchange_strong").?,
4893 Builtin.tagFromName("__c11_atomic_compare_exchange_weak").?,
4894 => 5,
4895
4836 Builtin.tagFromName("__atomic_compare_exchange").?,4896 Builtin.tagFromName("__atomic_compare_exchange").?,
4837 Builtin.tagFromName("__atomic_compare_exchange_n").?,4897 Builtin.tagFromName("__atomic_compare_exchange_n").?,
4838 => 6,4898 => 6,
...@@ -4845,15 +4905,45 @@ const CallExpr = union(enum) {...@@ -4845,15 +4905,45 @@ const CallExpr = union(enum) {
4845 return switch (self) {4905 return switch (self) {
4846 .standard => callable_ty.returnType(),4906 .standard => callable_ty.returnType(),
4847 .builtin => |builtin| switch (builtin.tag) {4907 .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
4848 Builtin.tagFromName("__atomic_fetch_add").?,4921 Builtin.tagFromName("__atomic_fetch_add").?,
4922 Builtin.tagFromName("__atomic_add_fetch").?,
4923 Builtin.tagFromName("__c11_atomic_fetch_add").?,
4924
4849 Builtin.tagFromName("__atomic_fetch_sub").?,4925 Builtin.tagFromName("__atomic_fetch_sub").?,
4926 Builtin.tagFromName("__atomic_sub_fetch").?,
4927 Builtin.tagFromName("__c11_atomic_fetch_sub").?,
4928
4850 Builtin.tagFromName("__atomic_fetch_and").?,4929 Builtin.tagFromName("__atomic_fetch_and").?,
4930 Builtin.tagFromName("__atomic_and_fetch").?,
4931 Builtin.tagFromName("__c11_atomic_fetch_and").?,
4932
4851 Builtin.tagFromName("__atomic_fetch_xor").?,4933 Builtin.tagFromName("__atomic_fetch_xor").?,
4934 Builtin.tagFromName("__atomic_xor_fetch").?,
4935 Builtin.tagFromName("__c11_atomic_fetch_xor").?,
4936
4852 Builtin.tagFromName("__atomic_fetch_or").?,4937 Builtin.tagFromName("__atomic_fetch_or").?,
4938 Builtin.tagFromName("__atomic_or_fetch").?,
4939 Builtin.tagFromName("__c11_atomic_fetch_or").?,
4940
4853 Builtin.tagFromName("__atomic_fetch_nand").?,4941 Builtin.tagFromName("__atomic_fetch_nand").?,
4942 Builtin.tagFromName("__atomic_nand_fetch").?,
4943 Builtin.tagFromName("__c11_atomic_fetch_nand").?,
4854 => {4944 => {
4855 if (p.list_buf.items.len < 2) return Type.invalid; // not enough arguments; already an error4945 if (p.list_buf.items.len != 3) return Type.invalid; // wrong number of arguments; already an error
4856 const second_param = p.list_buf.items[p.list_buf.items.len - 2];4946 const second_param = p.list_buf.items[2];
4857 return p.nodes.items(.ty)[@intFromEnum(second_param)];4947 return p.nodes.items(.ty)[@intFromEnum(second_param)];
4858 },4948 },
4859 Builtin.tagFromName("__builtin_complex").? => {4949 Builtin.tagFromName("__builtin_complex").? => {
...@@ -4863,8 +4953,17 @@ const CallExpr = union(enum) {...@@ -4863,8 +4953,17 @@ const CallExpr = union(enum) {
4863 },4953 },
4864 Builtin.tagFromName("__atomic_compare_exchange").?,4954 Builtin.tagFromName("__atomic_compare_exchange").?,
4865 Builtin.tagFromName("__atomic_compare_exchange_n").?,4955 Builtin.tagFromName("__atomic_compare_exchange_n").?,
4956 Builtin.tagFromName("__c11_atomic_is_lock_free").?,
4866 => .{ .specifier = .bool },4957 => .{ .specifier = .bool },
4867 else => callable_ty.returnType(),4958 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 },
4868 },4967 },
4869 };4968 };
4870 }4969 }
...@@ -4975,15 +5074,19 @@ pub const Result = struct {...@@ -4975,15 +5074,19 @@ pub const Result = struct {
4975 .call_expr_one => {5074 .call_expr_one => {
4976 const fn_ptr = p.nodes.items(.data)[@intFromEnum(cur_node)].bin.lhs;5075 const fn_ptr = p.nodes.items(.data)[@intFromEnum(cur_node)].bin.lhs;
4977 const fn_ty = p.nodes.items(.ty)[@intFromEnum(fn_ptr)].elemType();5076 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");5077 const cast_info = p.nodes.items(.data)[@intFromEnum(fn_ptr)].cast.operand;
4979 if (fn_ty.hasAttribute(.warn_unused_result)) try p.errStr(.warn_unused_result, expr_start, "TODO get name");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));
4980 return;5081 return;
4981 },5082 },
4982 .call_expr => {5083 .call_expr => {
4983 const fn_ptr = p.data.items[p.nodes.items(.data)[@intFromEnum(cur_node)].range.start];5084 const fn_ptr = p.data.items[p.nodes.items(.data)[@intFromEnum(cur_node)].range.start];
4984 const fn_ty = p.nodes.items(.ty)[@intFromEnum(fn_ptr)].elemType();5085 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");5086 const cast_info = p.nodes.items(.data)[@intFromEnum(fn_ptr)].cast.operand;
4986 if (fn_ty.hasAttribute(.warn_unused_result)) try p.errStr(.warn_unused_result, expr_start, "TODO get name");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));
4987 return;5090 return;
4988 },5091 },
4989 .stmt_expr => {5092 .stmt_expr => {
...@@ -6356,8 +6459,15 @@ fn shiftExpr(p: *Parser) Error!Result {...@@ -6356,8 +6459,15 @@ fn shiftExpr(p: *Parser) Error!Result {
6356 try rhs.expect(p);6459 try rhs.expect(p);
63576460
6358 if (try lhs.adjustTypes(shr.?, &rhs, p, .integer)) {6461 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 }
6359 if (shl != null) {6468 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);
6361 } else {6471 } else {
6362 lhs.val = try lhs.val.shr(rhs.val, lhs.ty, p.comp);6472 lhs.val = try lhs.val.shr(rhs.val, lhs.ty, p.comp);
6363 }6473 }
...@@ -6381,9 +6491,11 @@ fn addExpr(p: *Parser) Error!Result {...@@ -6381,9 +6491,11 @@ fn addExpr(p: *Parser) Error!Result {
6381 const lhs_ty = lhs.ty;6491 const lhs_ty = lhs.ty;
6382 if (try lhs.adjustTypes(minus.?, &rhs, p, if (plus != null) .add else .sub)) {6492 if (try lhs.adjustTypes(minus.?, &rhs, p, if (plus != null) .add else .sub)) {
6383 if (plus != null) {6493 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);
6385 } else {6496 } 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);
6387 }6499 }
6388 }6500 }
6389 if (lhs.ty.specifier != .invalid and lhs_ty.isPtr() and !lhs_ty.isVoidStar() and lhs_ty.elemType().hasIncompleteSize()) {6501 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 {...@@ -6420,9 +6532,11 @@ fn mulExpr(p: *Parser) Error!Result {
64206532
6421 if (try lhs.adjustTypes(percent.?, &rhs, p, if (tag == .mod_expr) .integer else .arithmetic)) {6533 if (try lhs.adjustTypes(percent.?, &rhs, p, if (tag == .mod_expr) .integer else .arithmetic)) {
6422 if (mul != null) {6534 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);
6424 } else if (div != null) {6537 } 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);
6426 } else {6540 } else {
6427 var res = try Value.rem(lhs.val, rhs.val, lhs.ty, p.comp);6541 var res = try Value.rem(lhs.val, rhs.val, lhs.ty, p.comp);
6428 if (res.opt_ref == .none) {6542 if (res.opt_ref == .none) {
...@@ -6827,7 +6941,7 @@ fn unExpr(p: *Parser) Error!Result {...@@ -6827,7 +6941,7 @@ fn unExpr(p: *Parser) Error!Result {
6827 try p.errStr(.invalid_argument_un, tok, try p.typeStr(operand.ty));6941 try p.errStr(.invalid_argument_un, tok, try p.typeStr(operand.ty));
68286942
6829 try operand.usualUnaryConversion(p, tok);6943 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)) {
6831 _ = try operand.val.sub(Value.zero, operand.val, operand.ty, p.comp);6945 _ = try operand.val.sub(Value.zero, operand.val, operand.ty, p.comp);
6832 } else {6946 } else {
6833 operand.val = .{};6947 operand.val = .{};
...@@ -6898,6 +7012,8 @@ fn unExpr(p: *Parser) Error!Result {...@@ -6898,6 +7012,8 @@ fn unExpr(p: *Parser) Error!Result {
6898 if (operand.val.is(.int, p.comp)) {7012 if (operand.val.is(.int, p.comp)) {
6899 operand.val = try operand.val.bitNot(operand.ty, p.comp);7013 operand.val = try operand.val.bitNot(operand.ty, p.comp);
6900 }7014 }
7015 } else if (operand.ty.isComplex()) {
7016 try p.errStr(.complex_conj, tok, try p.typeStr(operand.ty));
6901 } else {7017 } else {
6902 try p.errStr(.invalid_argument_un, tok, try p.typeStr(operand.ty));7018 try p.errStr(.invalid_argument_un, tok, try p.typeStr(operand.ty));
6903 operand.val = .{};7019 operand.val = .{};
...@@ -7334,6 +7450,20 @@ fn checkVaStartArg(p: *Parser, builtin_tok: TokenIndex, first_after: TokenIndex,...@@ -7334,6 +7450,20 @@ fn checkVaStartArg(p: *Parser, builtin_tok: TokenIndex, first_after: TokenIndex,
7334 }7450 }
7335}7451}
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
7337fn checkComplexArg(p: *Parser, builtin_tok: TokenIndex, first_after: TokenIndex, param_tok: TokenIndex, arg: *Result, idx: u32) !void {7467fn checkComplexArg(p: *Parser, builtin_tok: TokenIndex, first_after: TokenIndex, param_tok: TokenIndex, arg: *Result, idx: u32) !void {
7338 _ = builtin_tok;7468 _ = builtin_tok;
7339 _ = first_after;7469 _ = first_after;
...@@ -7880,6 +8010,7 @@ fn charLiteral(p: *Parser) Error!Result {...@@ -7880,6 +8010,7 @@ fn charLiteral(p: *Parser) Error!Result {
78808010
7881 const slice = char_kind.contentSlice(p.tokSlice(p.tok_i));8011 const slice = char_kind.contentSlice(p.tokSlice(p.tok_i));
78828012
8013 var is_multichar = false;
7883 if (slice.len == 1 and std.ascii.isASCII(slice[0])) {8014 if (slice.len == 1 and std.ascii.isASCII(slice[0])) {
7884 // fast path: single unescaped ASCII char8015 // fast path: single unescaped ASCII char
7885 val = slice[0];8016 val = slice[0];
...@@ -7913,7 +8044,7 @@ fn charLiteral(p: *Parser) Error!Result {...@@ -7913,7 +8044,7 @@ fn charLiteral(p: *Parser) Error!Result {
7913 },8044 },
7914 };8045 };
79158046
7916 const is_multichar = chars.items.len > 1;8047 is_multichar = chars.items.len > 1;
7917 if (is_multichar) {8048 if (is_multichar) {
7918 if (char_kind == .char and chars.items.len == 4) {8049 if (char_kind == .char and chars.items.len == 4) {
7919 char_literal_parser.warn(.four_char_char_literal, .{ .none = {} });8050 char_literal_parser.warn(.four_char_char_literal, .{ .none = {} });
...@@ -7956,9 +8087,19 @@ fn charLiteral(p: *Parser) Error!Result {...@@ -7956,9 +8087,19 @@ fn charLiteral(p: *Parser) Error!Result {
7956 else8087 else
7957 p.comp.types.intmax;8088 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
7959 const res = Result{8100 const res = Result{
7960 .ty = if (p.in_macro) macro_ty else ty,8101 .ty = if (p.in_macro) macro_ty else ty,
7961 .val = try Value.int(val, p.comp),8102 .val = value,
7962 .node = try p.addNode(.{ .tag = .char_literal, .ty = ty, .data = undefined }),8103 .node = try p.addNode(.{ .tag = .char_literal, .ty = ty, .data = undefined }),
7963 };8104 };
7964 if (!p.in_macro) try p.value_map.put(res.node, res.val);8105 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");...@@ -9,9 +9,12 @@ const Tokenizer = @import("Tokenizer.zig");
9const RawToken = Tokenizer.Token;9const RawToken = Tokenizer.Token;
10const Parser = @import("Parser.zig");10const Parser = @import("Parser.zig");
11const Diagnostics = @import("Diagnostics.zig");11const Diagnostics = @import("Diagnostics.zig");
12const Token = @import("Tree.zig").Token;12const Tree = @import("Tree.zig");
13const Token = Tree.Token;
14const TokenWithExpansionLocs = Tree.TokenWithExpansionLocs;
13const Attribute = @import("Attribute.zig");15const Attribute = @import("Attribute.zig");
14const features = @import("features.zig");16const features = @import("features.zig");
17const Hideset = @import("Hideset.zig");
1518
16const DefineMap = std.StringHashMapUnmanaged(Macro);19const DefineMap = std.StringHashMapUnmanaged(Macro);
17const RawTokenList = std.ArrayList(RawToken);20const RawTokenList = std.ArrayList(RawToken);
...@@ -40,8 +43,6 @@ const Macro = struct {...@@ -40,8 +43,6 @@ const Macro = struct {
4043
41 /// Location of macro in the source44 /// Location of macro in the source
42 loc: Source.Location,45 loc: Source.Location,
43 start: u32,
44 end: u32,
4546
46 fn eql(a: Macro, b: Macro, pp: *Preprocessor) bool {47 fn eql(a: Macro, b: Macro, pp: *Preprocessor) bool {
47 if (a.tokens.len != b.tokens.len) return false;48 if (a.tokens.len != b.tokens.len) return false;
...@@ -64,11 +65,24 @@ const Macro = struct {...@@ -64,11 +65,24 @@ const Macro = struct {
6465
65const Preprocessor = @This();66const 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
67comp: *Compilation,78comp: *Compilation,
68gpa: mem.Allocator,79gpa: mem.Allocator,
69arena: std.heap.ArenaAllocator,80arena: std.heap.ArenaAllocator,
70defines: DefineMap = .{},81defines: DefineMap = .{},
82/// Do not directly mutate this; use addToken / addTokenAssumeCapacity / ensureTotalTokenCapacity / ensureUnusedTokenCapacity
71tokens: Token.List = .{},83tokens: Token.List = .{},
84/// Do not directly mutate this; must be kept in sync with `tokens`
85expansion_entries: std.MultiArrayList(ExpansionEntry) = .{},
72token_buf: RawTokenList,86token_buf: RawTokenList,
73char_buf: std.ArrayList(u8),87char_buf: std.ArrayList(u8),
74/// Counter that is incremented each time preprocess() is called88/// Counter that is incremented each time preprocess() is called
...@@ -93,6 +107,8 @@ preserve_whitespace: bool = false,...@@ -93,6 +107,8 @@ preserve_whitespace: bool = false,
93/// linemarker tokens. Must be .none unless in -E mode (parser does not handle linemarkers)107/// linemarker tokens. Must be .none unless in -E mode (parser does not handle linemarkers)
94linemarkers: Linemarkers = .none,108linemarkers: Linemarkers = .none,
95109
110hideset: Hideset,
111
96pub const parse = Parser.parse;112pub const parse = Parser.parse;
97113
98pub const Linemarkers = enum {114pub const Linemarkers = enum {
...@@ -113,6 +129,7 @@ pub fn init(comp: *Compilation) Preprocessor {...@@ -113,6 +129,7 @@ pub fn init(comp: *Compilation) Preprocessor {
113 .char_buf = std.ArrayList(u8).init(comp.gpa),129 .char_buf = std.ArrayList(u8).init(comp.gpa),
114 .poisoned_identifiers = std.StringHashMap(void).init(comp.gpa),130 .poisoned_identifiers = std.StringHashMap(void).init(comp.gpa),
115 .top_expansion_buf = ExpandBuf.init(comp.gpa),131 .top_expansion_buf = ExpandBuf.init(comp.gpa),
132 .hideset = .{ .comp = comp },
116 };133 };
117 comp.pragmaEvent(.before_preprocess);134 comp.pragmaEvent(.before_preprocess);
118 return pp;135 return pp;
...@@ -201,8 +218,6 @@ fn addBuiltinMacro(pp: *Preprocessor, name: []const u8, is_func: bool, tokens: [...@@ -201,8 +218,6 @@ fn addBuiltinMacro(pp: *Preprocessor, name: []const u8, is_func: bool, tokens: [
201 .var_args = false,218 .var_args = false,
202 .is_func = is_func,219 .is_func = is_func,
203 .loc = .{ .id = .generated },220 .loc = .{ .id = .generated },
204 .start = 0,
205 .end = 0,
206 .is_builtin = true,221 .is_builtin = true,
207 });222 });
208}223}
...@@ -228,7 +243,6 @@ pub fn addBuiltinMacros(pp: *Preprocessor) !void {...@@ -228,7 +243,6 @@ pub fn addBuiltinMacros(pp: *Preprocessor) !void {
228243
229pub fn deinit(pp: *Preprocessor) void {244pub fn deinit(pp: *Preprocessor) void {
230 pp.defines.deinit(pp.gpa);245 pp.defines.deinit(pp.gpa);
231 for (pp.tokens.items(.expansion_locs)) |loc| Token.free(loc, pp.gpa);
232 pp.tokens.deinit(pp.gpa);246 pp.tokens.deinit(pp.gpa);
233 pp.arena.deinit();247 pp.arena.deinit();
234 pp.token_buf.deinit();248 pp.token_buf.deinit();
...@@ -236,6 +250,33 @@ pub fn deinit(pp: *Preprocessor) void {...@@ -236,6 +250,33 @@ pub fn deinit(pp: *Preprocessor) void {
236 pp.poisoned_identifiers.deinit();250 pp.poisoned_identifiers.deinit();
237 pp.include_guards.deinit(pp.gpa);251 pp.include_guards.deinit(pp.gpa);
238 pp.top_expansion_buf.deinit();252 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];
239}280}
240281
241/// Preprocess a compilation unit of sources into a parsable list of tokens.282/// 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...@@ -247,13 +288,14 @@ pub fn preprocessSources(pp: *Preprocessor, sources: []const Source) Error!void
247 try pp.addIncludeStart(header);288 try pp.addIncludeStart(header);
248 _ = try pp.preprocess(header);289 _ = try pp.preprocess(header);
249 }290 }
250 try pp.addIncludeResume(first.id, 0, 0);291 try pp.addIncludeResume(first.id, 0, 1);
251 const eof = try pp.preprocess(first);292 const eof = try pp.preprocess(first);
252 try pp.tokens.append(pp.comp.gpa, eof);293 try pp.addToken(eof);
294 pp.clearBuffers();
253}295}
254296
255/// Preprocess a source file, returns eof token.297/// 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 {
257 const eof = pp.preprocessExtra(source) catch |er| switch (er) {299 const eof = pp.preprocessExtra(source) catch |er| switch (er) {
258 // This cannot occur in the main file and is handled in `include`.300 // This cannot occur in the main file and is handled in `include`.
259 error.StopPreprocessing => unreachable,301 error.StopPreprocessing => unreachable,
...@@ -275,27 +317,27 @@ pub fn tokenize(pp: *Preprocessor, source: Source) Error!Token {...@@ -275,27 +317,27 @@ pub fn tokenize(pp: *Preprocessor, source: Source) Error!Token {
275317
276 // Estimate how many new tokens this source will contain.318 // Estimate how many new tokens this source will contain.
277 const estimated_token_count = source.buf.len / 8;319 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
280 while (true) {322 while (true) {
281 const tok = tokenizer.next();323 const tok = tokenizer.next();
282 if (tok.id == .eof) return tokFromRaw(tok);324 if (tok.id == .eof) return tokFromRaw(tok);
283 try pp.tokens.append(pp.gpa, tokFromRaw(tok));325 try pp.addToken(tokFromRaw(tok));
284 }326 }
285}327}
286328
287pub fn addIncludeStart(pp: *Preprocessor, source: Source) !void {329pub fn addIncludeStart(pp: *Preprocessor, source: Source) !void {
288 if (pp.linemarkers == .none) return;330 if (pp.linemarkers == .none) return;
289 try pp.tokens.append(pp.gpa, .{ .id = .include_start, .loc = .{331 try pp.addToken(.{ .id = .include_start, .loc = .{
290 .id = source.id,332 .id = source.id,
291 .byte_offset = std.math.maxInt(u32),333 .byte_offset = std.math.maxInt(u32),
292 .line = 0,334 .line = 1,
293 } });335 } });
294}336}
295337
296pub fn addIncludeResume(pp: *Preprocessor, source: Source.Id, offset: u32, line: u32) !void {338pub fn addIncludeResume(pp: *Preprocessor, source: Source.Id, offset: u32, line: u32) !void {
297 if (pp.linemarkers == .none) return;339 if (pp.linemarkers == .none) return;
298 try pp.tokens.append(pp.gpa, .{ .id = .include_resume, .loc = .{340 try pp.addToken(.{ .id = .include_resume, .loc = .{
299 .id = source,341 .id = source,
300 .byte_offset = offset,342 .byte_offset = offset,
301 .line = line,343 .line = line,
...@@ -328,7 +370,7 @@ fn findIncludeGuard(pp: *Preprocessor, source: Source) ?[]const u8 {...@@ -328,7 +370,7 @@ fn findIncludeGuard(pp: *Preprocessor, source: Source) ?[]const u8 {
328 return pp.tokSlice(guard);370 return pp.tokSlice(guard);
329}371}
330372
331fn preprocessExtra(pp: *Preprocessor, source: Source) MacroError!Token {373fn preprocessExtra(pp: *Preprocessor, source: Source) MacroError!TokenWithExpansionLocs {
332 var guard_name = pp.findIncludeGuard(source);374 var guard_name = pp.findIncludeGuard(source);
333375
334 pp.preprocess_count += 1;376 pp.preprocess_count += 1;
...@@ -340,7 +382,7 @@ fn preprocessExtra(pp: *Preprocessor, source: Source) MacroError!Token {...@@ -340,7 +382,7 @@ fn preprocessExtra(pp: *Preprocessor, source: Source) MacroError!Token {
340382
341 // Estimate how many new tokens this source will contain.383 // Estimate how many new tokens this source will contain.
342 const estimated_token_count = source.buf.len / 8;384 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
345 var if_level: u8 = 0;387 var if_level: u8 = 0;
346 var if_kind = std.PackedIntArray(u2, 256).init([1]u2{0} ** 256);388 var if_kind = std.PackedIntArray(u2, 256).init([1]u2{0} ** 256);
...@@ -352,7 +394,7 @@ fn preprocessExtra(pp: *Preprocessor, source: Source) MacroError!Token {...@@ -352,7 +394,7 @@ fn preprocessExtra(pp: *Preprocessor, source: Source) MacroError!Token {
352 while (true) {394 while (true) {
353 var tok = tokenizer.next();395 var tok = tokenizer.next();
354 switch (tok.id) {396 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 {
356 const directive = tokenizer.nextNoWS();398 const directive = tokenizer.nextNoWS();
357 switch (directive.id) {399 switch (directive.id) {
358 .keyword_error, .keyword_warning => {400 .keyword_error, .keyword_warning => {
...@@ -654,13 +696,13 @@ fn preprocessExtra(pp: *Preprocessor, source: Source) MacroError!Token {...@@ -654,13 +696,13 @@ fn preprocessExtra(pp: *Preprocessor, source: Source) MacroError!Token {
654 }696 }
655 if (pp.preserve_whitespace) {697 if (pp.preserve_whitespace) {
656 tok.id = .nl;698 tok.id = .nl;
657 try pp.tokens.append(pp.gpa, tokFromRaw(tok));699 try pp.addToken(tokFromRaw(tok));
658 }700 }
659 },701 },
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)),
661 .nl => {703 .nl => {
662 start_of_line = true;704 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));
664 },706 },
665 .eof => {707 .eof => {
666 if (if_level != 0) try pp.err(tok, .unterminated_conditional_directive);708 if (if_level != 0) try pp.err(tok, .unterminated_conditional_directive);
...@@ -696,14 +738,14 @@ fn preprocessExtra(pp: *Preprocessor, source: Source) MacroError!Token {...@@ -696,14 +738,14 @@ fn preprocessExtra(pp: *Preprocessor, source: Source) MacroError!Token {
696738
697/// Get raw token source string.739/// Get raw token source string.
698/// Returned slice is invalidated when comp.generated_buf is updated.740/// 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 {
700 if (token.id.lexeme()) |some| return some;742 if (token.id.lexeme()) |some| return some;
701 const source = pp.comp.getSource(token.source);743 const source = pp.comp.getSource(token.source);
702 return source.buf[token.start..token.end];744 return source.buf[token.start..token.end];
703}745}
704746
705/// Convert a token from the Tokenizer into a token used by the parser.747/// Convert a token from the Tokenizer into a token used by the parser.
706fn tokFromRaw(raw: RawToken) Token {748fn tokFromRaw(raw: RawToken) TokenWithExpansionLocs {
707 return .{749 return .{
708 .id = raw.id,750 .id = raw.id,
709 .loc = .{751 .loc = .{
...@@ -725,7 +767,7 @@ fn err(pp: *Preprocessor, raw: RawToken, tag: Diagnostics.Tag) !void {...@@ -725,7 +767,7 @@ fn err(pp: *Preprocessor, raw: RawToken, tag: Diagnostics.Tag) !void {
725 }, &.{});767 }, &.{});
726}768}
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 {
729 try pp.comp.addDiagnostic(.{771 try pp.comp.addDiagnostic(.{
730 .tag = tag,772 .tag = tag,
731 .loc = tok.loc,773 .loc = tok.loc,
...@@ -747,7 +789,7 @@ fn fatal(pp: *Preprocessor, raw: RawToken, comptime fmt: []const u8, args: anyty...@@ -747,7 +789,7 @@ fn fatal(pp: *Preprocessor, raw: RawToken, comptime fmt: []const u8, args: anyty
747 return error.FatalError;789 return error.FatalError;
748}790}
749791
750fn fatalNotFound(pp: *Preprocessor, tok: Token, filename: []const u8) Compilation.Error {792fn fatalNotFound(pp: *Preprocessor, tok: TokenWithExpansionLocs, filename: []const u8) Compilation.Error {
751 const old = pp.comp.diagnostics.fatal_errors;793 const old = pp.comp.diagnostics.fatal_errors;
752 pp.comp.diagnostics.fatal_errors = true;794 pp.comp.diagnostics.fatal_errors = true;
753 defer pp.comp.diagnostics.fatal_errors = old;795 defer pp.comp.diagnostics.fatal_errors = old;
...@@ -790,7 +832,7 @@ fn expectNl(pp: *Preprocessor, tokenizer: *Tokenizer) Error!void {...@@ -790,7 +832,7 @@ fn expectNl(pp: *Preprocessor, tokenizer: *Tokenizer) Error!void {
790 while (true) {832 while (true) {
791 const tok = tokenizer.next();833 const tok = tokenizer.next();
792 if (tok.id == .nl or tok.id == .eof) return;834 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;
794 if (!sent_err) {836 if (!sent_err) {
795 sent_err = true;837 sent_err = true;
796 try pp.err(tok, .extra_tokens_directive_end);838 try pp.err(tok, .extra_tokens_directive_end);
...@@ -798,12 +840,24 @@ fn expectNl(pp: *Preprocessor, tokenizer: *Tokenizer) Error!void {...@@ -798,12 +840,24 @@ fn expectNl(pp: *Preprocessor, tokenizer: *Tokenizer) Error!void {
798 }840 }
799}841}
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
801/// Consume all tokens until a newline and parse the result into a boolean.855/// Consume all tokens until a newline and parse the result into a boolean.
802fn expr(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!bool {856fn expr(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!bool {
803 const start = pp.tokens.len;857 const token_state = pp.getTokenState();
804 defer {858 defer {
805 for (pp.top_expansion_buf.items) |tok| Token.free(tok.expansion_locs, pp.gpa);859 for (pp.top_expansion_buf.items) |tok| TokenWithExpansionLocs.free(tok.expansion_locs, pp.gpa);
806 pp.tokens.len = start;860 pp.restoreTokenState(token_state);
807 }861 }
808862
809 pp.top_expansion_buf.items.len = 0;863 pp.top_expansion_buf.items.len = 0;
...@@ -818,6 +872,7 @@ fn expr(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!bool {...@@ -818,6 +872,7 @@ fn expr(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!bool {
818 } else unreachable;872 } else unreachable;
819 if (pp.top_expansion_buf.items.len != 0) {873 if (pp.top_expansion_buf.items.len != 0) {
820 pp.expansion_source_loc = pp.top_expansion_buf.items[0].loc;874 pp.expansion_source_loc = pp.top_expansion_buf.items[0].loc;
875 pp.hideset.clearRetainingCapacity();
821 try pp.expandMacroExhaustive(tokenizer, &pp.top_expansion_buf, 0, pp.top_expansion_buf.items.len, false, .expr);876 try pp.expandMacroExhaustive(tokenizer, &pp.top_expansion_buf, 0, pp.top_expansion_buf.items.len, false, .expr);
822 }877 }
823 for (pp.top_expansion_buf.items) |tok| {878 for (pp.top_expansion_buf.items) |tok| {
...@@ -836,7 +891,7 @@ fn expr(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!bool {...@@ -836,7 +891,7 @@ fn expr(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!bool {
836 }891 }
837892
838 // validate the tokens in the expression893 // 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);
840 var i: usize = 0;895 var i: usize = 0;
841 const items = pp.top_expansion_buf.items;896 const items = pp.top_expansion_buf.items;
842 while (i < items.len) : (i += 1) {897 while (i < items.len) : (i += 1) {
...@@ -905,9 +960,9 @@ fn expr(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!bool {...@@ -905,9 +960,9 @@ fn expr(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!bool {
905 }960 }
906 },961 },
907 }962 }
908 pp.tokens.appendAssumeCapacity(tok);963 pp.addTokenAssumeCapacity(tok);
909 }964 }
910 try pp.tokens.append(pp.gpa, .{965 try pp.addToken(.{
911 .id = .eof,966 .id = .eof,
912 .loc = tokFromRaw(eof).loc,967 .loc = tokFromRaw(eof).loc,
913 });968 });
...@@ -918,7 +973,7 @@ fn expr(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!bool {...@@ -918,7 +973,7 @@ fn expr(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!bool {
918 .comp = pp.comp,973 .comp = pp.comp,
919 .gpa = pp.gpa,974 .gpa = pp.gpa,
920 .tok_ids = pp.tokens.items(.id),975 .tok_ids = pp.tokens.items(.id),
921 .tok_i = @intCast(start),976 .tok_i = @intCast(token_state.tokens_len),
922 .arena = pp.arena.allocator(),977 .arena = pp.arena.allocator(),
923 .in_macro = true,978 .in_macro = true,
924 .strings = std.ArrayList(u8).init(pp.comp.gpa),979 .strings = std.ArrayList(u8).init(pp.comp.gpa),
...@@ -941,7 +996,7 @@ fn expr(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!bool {...@@ -941,7 +996,7 @@ fn expr(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!bool {
941996
942/// Turns macro_tok from .keyword_defined into .zero or .one depending on whether the argument is defined997/// Turns macro_tok from .keyword_defined into .zero or .one depending on whether the argument is defined
943/// Returns the number of tokens consumed998/// 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 {
945 std.debug.assert(macro_tok.id == .keyword_defined);1000 std.debug.assert(macro_tok.id == .keyword_defined);
946 var it = TokenIterator.init(tokens);1001 var it = TokenIterator.init(tokens);
947 const first = it.nextNoWS() orelse {1002 const first = it.nextNoWS() orelse {
...@@ -1056,7 +1111,7 @@ fn skip(...@@ -1056,7 +1111,7 @@ fn skip(
1056 tokenizer.index += 1;1111 tokenizer.index += 1;
1057 tokenizer.line += 1;1112 tokenizer.line += 1;
1058 if (pp.preserve_whitespace) {1113 if (pp.preserve_whitespace) {
1059 try pp.tokens.append(pp.gpa, .{ .id = .nl, .loc = .{1114 try pp.addToken(.{ .id = .nl, .loc = .{
1060 .id = tokenizer.source,1115 .id = tokenizer.source,
1061 .line = tokenizer.line,1116 .line = tokenizer.line,
1062 } });1117 } });
...@@ -1079,21 +1134,21 @@ fn skipToNl(tokenizer: *Tokenizer) void {...@@ -1079,21 +1134,21 @@ fn skipToNl(tokenizer: *Tokenizer) void {
1079 }1134 }
1080}1135}
10811136
1082const ExpandBuf = std.ArrayList(Token);1137const ExpandBuf = std.ArrayList(TokenWithExpansionLocs);
1083fn removePlacemarkers(buf: *ExpandBuf) void {1138fn removePlacemarkers(buf: *ExpandBuf) void {
1084 var i: usize = buf.items.len -% 1;1139 var i: usize = buf.items.len -% 1;
1085 while (i < buf.items.len) : (i -%= 1) {1140 while (i < buf.items.len) : (i -%= 1) {
1086 if (buf.items[i].id == .placemarker) {1141 if (buf.items[i].id == .placemarker) {
1087 const placemarker = buf.orderedRemove(i);1142 const placemarker = buf.orderedRemove(i);
1088 Token.free(placemarker.expansion_locs, buf.allocator);1143 TokenWithExpansionLocs.free(placemarker.expansion_locs, buf.allocator);
1089 }1144 }
1090 }1145 }
1091}1146}
10921147
1093const MacroArguments = std.ArrayList([]const Token);1148const MacroArguments = std.ArrayList([]const TokenWithExpansionLocs);
1094fn deinitMacroArguments(allocator: Allocator, args: *const MacroArguments) void {1149fn deinitMacroArguments(allocator: Allocator, args: *const MacroArguments) void {
1095 for (args.items) |item| {1150 for (args.items) |item| {
1096 for (item) |tok| Token.free(tok.expansion_locs, allocator);1151 for (item) |tok| TokenWithExpansionLocs.free(tok.expansion_locs, allocator);
1097 allocator.free(item);1152 allocator.free(item);
1098 }1153 }
1099 args.deinit();1154 args.deinit();
...@@ -1102,6 +1157,10 @@ fn deinitMacroArguments(allocator: Allocator, args: *const MacroArguments) void...@@ -1102,6 +1157,10 @@ fn deinitMacroArguments(allocator: Allocator, args: *const MacroArguments) void
1102fn expandObjMacro(pp: *Preprocessor, simple_macro: *const Macro) Error!ExpandBuf {1157fn expandObjMacro(pp: *Preprocessor, simple_macro: *const Macro) Error!ExpandBuf {
1103 var buf = ExpandBuf.init(pp.gpa);1158 var buf = ExpandBuf.init(pp.gpa);
1104 errdefer buf.deinit();1159 errdefer buf.deinit();
1160 if (simple_macro.tokens.len == 0) {
1161 try buf.append(.{ .id = .placemarker, .loc = .{ .id = .generated } });
1162 return buf;
1163 }
1105 try buf.ensureTotalCapacity(simple_macro.tokens.len);1164 try buf.ensureTotalCapacity(simple_macro.tokens.len);
11061165
1107 // Add all of the simple_macros tokens to the new buffer handling any concats.1166 // 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...@@ -1161,7 +1220,7 @@ fn expandObjMacro(pp: *Preprocessor, simple_macro: *const Macro) Error!ExpandBuf
1161/// Returns error.ExpectedStringLiteral if parentheses are not balanced, a non-string-literal1220/// Returns error.ExpectedStringLiteral if parentheses are not balanced, a non-string-literal
1162/// is encountered, or if no string literals are encountered1221/// is encountered, or if no string literals are encountered
1163/// TODO: destringize (replace all '\\' with a single `\` and all '\"' with a '"')1222/// 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 {
1165 const char_top = pp.char_buf.items.len;1224 const char_top = pp.char_buf.items.len;
1166 defer pp.char_buf.items.len = char_top;1225 defer pp.char_buf.items.len = char_top;
1167 var unwrapped = toks;1226 var unwrapped = toks;
...@@ -1180,7 +1239,7 @@ fn pasteStringsUnsafe(pp: *Preprocessor, toks: []const Token) ![]const u8 {...@@ -1180,7 +1239,7 @@ fn pasteStringsUnsafe(pp: *Preprocessor, toks: []const Token) ![]const u8 {
1180}1239}
11811240
1182/// Handle the _Pragma operator (implemented as a builtin macro)1241/// 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 {
1184 const arg_slice = pp.expandedSlice(arg_tok);1243 const arg_slice = pp.expandedSlice(arg_tok);
1185 const content = arg_slice[1 .. arg_slice.len - 1];1244 const content = arg_slice[1 .. arg_slice.len - 1];
1186 const directive = "#pragma ";1245 const directive = "#pragma ";
...@@ -1234,7 +1293,7 @@ fn destringify(pp: *Preprocessor, str: []const u8) void {...@@ -1234,7 +1293,7 @@ fn destringify(pp: *Preprocessor, str: []const u8) void {
12341293
1235/// Stringify `tokens` into pp.char_buf.1294/// Stringify `tokens` into pp.char_buf.
1236/// See https://gcc.gnu.org/onlinedocs/gcc-11.2.0/cpp/Stringizing.html#Stringizing1295/// 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 {
1238 try pp.char_buf.append('"');1297 try pp.char_buf.append('"');
1239 var ws_state: enum { start, need, not_needed } = .start;1298 var ws_state: enum { start, need, not_needed } = .start;
1240 for (tokens) |tok| {1299 for (tokens) |tok| {
...@@ -1281,7 +1340,8 @@ fn stringify(pp: *Preprocessor, tokens: []const Token) !void {...@@ -1281,7 +1340,8 @@ fn stringify(pp: *Preprocessor, tokens: []const Token) !void {
1281 try pp.char_buf.appendSlice("\"\n");1340 try pp.char_buf.appendSlice("\"\n");
1282}1341}
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);
1285 const char_top = pp.char_buf.items.len;1345 const char_top = pp.char_buf.items.len;
1286 defer pp.char_buf.items.len = char_top;1346 defer pp.char_buf.items.len = char_top;
12871347
...@@ -1295,8 +1355,8 @@ fn reconstructIncludeString(pp: *Preprocessor, param_toks: []const Token, embed_...@@ -1295,8 +1355,8 @@ fn reconstructIncludeString(pp: *Preprocessor, param_toks: []const Token, embed_
1295 if (params.len == 0) {1355 if (params.len == 0) {
1296 try pp.comp.addDiagnostic(.{1356 try pp.comp.addDiagnostic(.{
1297 .tag = .expected_filename,1357 .tag = .expected_filename,
1298 .loc = param_toks[0].loc,1358 .loc = first.loc,
1299 }, param_toks[0].expansionSlice());1359 }, first.expansionSlice());
1300 return null;1360 return null;
1301 }1361 }
1302 // no string pasting1362 // no string pasting
...@@ -1321,6 +1381,13 @@ fn reconstructIncludeString(pp: *Preprocessor, param_toks: []const Token, embed_...@@ -1321,6 +1381,13 @@ fn reconstructIncludeString(pp: *Preprocessor, param_toks: []const Token, embed_
13211381
1322 const include_str = pp.char_buf.items[char_top..];1382 const include_str = pp.char_buf.items[char_top..];
1323 if (include_str.len < 3) {1383 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 }
1324 try pp.comp.addDiagnostic(.{1391 try pp.comp.addDiagnostic(.{
1325 .tag = .empty_filename,1392 .tag = .empty_filename,
1326 .loc = params[0].loc,1393 .loc = params[0].loc,
...@@ -1356,7 +1423,7 @@ fn reconstructIncludeString(pp: *Preprocessor, param_toks: []const Token, embed_...@@ -1356,7 +1423,7 @@ fn reconstructIncludeString(pp: *Preprocessor, param_toks: []const Token, embed_
1356 }1423 }
1357}1424}
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 {
1360 switch (builtin) {1427 switch (builtin) {
1361 .macro_param_has_attribute,1428 .macro_param_has_attribute,
1362 .macro_param_has_declspec_attribute,1429 .macro_param_has_declspec_attribute,
...@@ -1364,8 +1431,8 @@ fn handleBuiltinMacro(pp: *Preprocessor, builtin: RawToken.Id, param_toks: []con...@@ -1364,8 +1431,8 @@ fn handleBuiltinMacro(pp: *Preprocessor, builtin: RawToken.Id, param_toks: []con
1364 .macro_param_has_extension,1431 .macro_param_has_extension,
1365 .macro_param_has_builtin,1432 .macro_param_has_builtin,
1366 => {1433 => {
1367 var invalid: ?Token = null;1434 var invalid: ?TokenWithExpansionLocs = null;
1368 var identifier: ?Token = null;1435 var identifier: ?TokenWithExpansionLocs = null;
1369 for (param_toks) |tok| {1436 for (param_toks) |tok| {
1370 if (tok.id == .macro_ws) continue;1437 if (tok.id == .macro_ws) continue;
1371 if (tok.id == .comment) continue;1438 if (tok.id == .comment) continue;
...@@ -1415,8 +1482,8 @@ fn handleBuiltinMacro(pp: *Preprocessor, builtin: RawToken.Id, param_toks: []con...@@ -1415,8 +1482,8 @@ fn handleBuiltinMacro(pp: *Preprocessor, builtin: RawToken.Id, param_toks: []con
1415 return Diagnostics.warningExists(warning_name);1482 return Diagnostics.warningExists(warning_name);
1416 },1483 },
1417 .macro_param_is_identifier => {1484 .macro_param_is_identifier => {
1418 var invalid: ?Token = null;1485 var invalid: ?TokenWithExpansionLocs = null;
1419 var identifier: ?Token = null;1486 var identifier: ?TokenWithExpansionLocs = null;
1420 for (param_toks) |tok| switch (tok.id) {1487 for (param_toks) |tok| switch (tok.id) {
1421 .macro_ws => continue,1488 .macro_ws => continue,
1422 .comment => continue,1489 .comment => continue,
...@@ -1438,7 +1505,7 @@ fn handleBuiltinMacro(pp: *Preprocessor, builtin: RawToken.Id, param_toks: []con...@@ -1438,7 +1505,7 @@ fn handleBuiltinMacro(pp: *Preprocessor, builtin: RawToken.Id, param_toks: []con
1438 return id == .identifier or id == .extended_identifier;1505 return id == .identifier or id == .extended_identifier;
1439 },1506 },
1440 .macro_param_has_include, .macro_param_has_include_next => {1507 .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;
1442 const include_type: Compilation.IncludeType = switch (include_str[0]) {1509 const include_type: Compilation.IncludeType = switch (include_str[0]) {
1443 '"' => .quotes,1510 '"' => .quotes,
1444 '<' => .angle_brackets,1511 '<' => .angle_brackets,
...@@ -1460,6 +1527,17 @@ fn handleBuiltinMacro(pp: *Preprocessor, builtin: RawToken.Id, param_toks: []con...@@ -1460,6 +1527,17 @@ fn handleBuiltinMacro(pp: *Preprocessor, builtin: RawToken.Id, param_toks: []con
1460 }1527 }
1461}1528}
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
1463fn expandFuncMacro(1541fn expandFuncMacro(
1464 pp: *Preprocessor,1542 pp: *Preprocessor,
1465 loc: Source.Location,1543 loc: Source.Location,
...@@ -1482,7 +1560,7 @@ fn expandFuncMacro(...@@ -1482,7 +1560,7 @@ fn expandFuncMacro(
1482 try variable_arguments.appendSlice(args.items[i]);1560 try variable_arguments.appendSlice(args.items[i]);
1483 try expanded_variable_arguments.appendSlice(expanded_args.items[i]);1561 try expanded_variable_arguments.appendSlice(expanded_args.items[i]);
1484 if (i != expanded_args.items.len - 1) {1562 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 } };
1486 try variable_arguments.append(comma);1564 try variable_arguments.append(comma);
1487 try expanded_variable_arguments.append(comma);1565 try expanded_variable_arguments.append(comma);
1488 }1566 }
...@@ -1507,28 +1585,22 @@ fn expandFuncMacro(...@@ -1507,28 +1585,22 @@ fn expandFuncMacro(
1507 .comment => if (!pp.comp.langopts.preserve_comments_in_macros)1585 .comment => if (!pp.comp.langopts.preserve_comments_in_macros)
1508 continue1586 continue
1509 else1587 else
1510 &[1]Token{tokFromRaw(raw_next)},1588 &[1]TokenWithExpansionLocs{tokFromRaw(raw_next)},
1511 .macro_param, .macro_param_no_expand => if (args.items[raw_next.end].len > 0)1589 .macro_param, .macro_param_no_expand => getPasteArgs(args.items[raw_next.end]),
1512 args.items[raw_next.end]
1513 else
1514 &[1]Token{tokFromRaw(.{ .id = .placemarker, .source = .generated })},
1515 .keyword_va_args => variable_arguments.items,1590 .keyword_va_args => variable_arguments.items,
1516 .keyword_va_opt => blk: {1591 .keyword_va_opt => blk: {
1517 try pp.expandVaOpt(&va_opt_buf, raw_next, variable_arguments.items.len != 0);1592 try pp.expandVaOpt(&va_opt_buf, raw_next, variable_arguments.items.len != 0);
1518 if (va_opt_buf.items.len == 0) break;1593 if (va_opt_buf.items.len == 0) break;
1519 break :blk va_opt_buf.items;1594 break :blk va_opt_buf.items;
1520 },1595 },
1521 else => &[1]Token{tokFromRaw(raw_next)},1596 else => &[1]TokenWithExpansionLocs{tokFromRaw(raw_next)},
1522 };1597 };
15231598
1524 try pp.pasteTokens(&buf, next);1599 try pp.pasteTokens(&buf, next);
1525 if (next.len != 0) break;1600 if (next.len != 0) break;
1526 },1601 },
1527 .macro_param_no_expand => {1602 .macro_param_no_expand => {
1528 const slice = if (args.items[raw.end].len > 0)1603 const slice = getPasteArgs(args.items[raw.end]);
1529 args.items[raw.end]
1530 else
1531 &[1]Token{tokFromRaw(.{ .id = .placemarker, .source = .generated })};
1532 const raw_loc = Source.Location{ .id = raw.source, .byte_offset = raw.start, .line = raw.line };1604 const raw_loc = Source.Location{ .id = raw.source, .byte_offset = raw.start, .line = raw.line };
1533 try bufCopyTokens(&buf, slice, &.{raw_loc});1605 try bufCopyTokens(&buf, slice, &.{raw_loc});
1534 },1606 },
...@@ -1587,10 +1659,10 @@ fn expandFuncMacro(...@@ -1587,10 +1659,10 @@ fn expandFuncMacro(
1587 try pp.comp.addDiagnostic(.{ .tag = .expected_arguments, .loc = loc, .extra = extra }, &.{});1659 try pp.comp.addDiagnostic(.{ .tag = .expected_arguments, .loc = loc, .extra = extra }, &.{});
1588 break :blk not_found;1660 break :blk not_found;
1589 } else res: {1661 } else res: {
1590 var invalid: ?Token = null;1662 var invalid: ?TokenWithExpansionLocs = null;
1591 var vendor_ident: ?Token = null;1663 var vendor_ident: ?TokenWithExpansionLocs = null;
1592 var colon_colon: ?Token = null;1664 var colon_colon: ?TokenWithExpansionLocs = null;
1593 var attr_ident: ?Token = null;1665 var attr_ident: ?TokenWithExpansionLocs = null;
1594 for (arg) |tok| {1666 for (arg) |tok| {
1595 if (tok.id == .macro_ws) continue;1667 if (tok.id == .macro_ws) continue;
1596 if (tok.id == .comment) continue;1668 if (tok.id == .comment) continue;
...@@ -1663,17 +1735,17 @@ fn expandFuncMacro(...@@ -1663,17 +1735,17 @@ fn expandFuncMacro(
1663 try pp.comp.addDiagnostic(.{ .tag = .expected_arguments, .loc = loc, .extra = extra }, &.{});1735 try pp.comp.addDiagnostic(.{ .tag = .expected_arguments, .loc = loc, .extra = extra }, &.{});
1664 break :blk not_found;1736 break :blk not_found;
1665 } else res: {1737 } else res: {
1666 var embed_args: []const Token = &.{};1738 var embed_args: []const TokenWithExpansionLocs = &.{};
1667 const include_str = (try pp.reconstructIncludeString(arg, &embed_args)) orelse1739 const include_str = (try pp.reconstructIncludeString(arg, &embed_args, arg[0])) orelse
1668 break :res not_found;1740 break :res not_found;
16691741
1670 var prev = tokFromRaw(raw);1742 var prev = tokFromRaw(raw);
1671 prev.id = .eof;1743 prev.id = .eof;
1672 var it: struct {1744 var it: struct {
1673 i: u32 = 0,1745 i: u32 = 0,
1674 slice: []const Token,1746 slice: []const TokenWithExpansionLocs,
1675 prev: Token,1747 prev: TokenWithExpansionLocs,
1676 fn next(it: *@This()) Token {1748 fn next(it: *@This()) TokenWithExpansionLocs {
1677 while (it.i < it.slice.len) switch (it.slice[it.i].id) {1749 while (it.i < it.slice.len) switch (it.slice[it.i].id) {
1678 .macro_ws, .whitespace => it.i += 1,1750 .macro_ws, .whitespace => it.i += 1,
1679 else => break,1751 else => break,
...@@ -1732,7 +1804,7 @@ fn expandFuncMacro(...@@ -1732,7 +1804,7 @@ fn expandFuncMacro(
1732 };1804 };
17331805
1734 var arg_count: u32 = 0;1806 var arg_count: u32 = 0;
1735 var first_arg: Token = undefined;1807 var first_arg: TokenWithExpansionLocs = undefined;
1736 while (true) {1808 while (true) {
1737 const next = it.next();1809 const next = it.next();
1738 if (next.id == .eof) {1810 if (next.id == .eof) {
...@@ -1793,8 +1865,8 @@ fn expandFuncMacro(...@@ -1793,8 +1865,8 @@ fn expandFuncMacro(
1793 // Clang and GCC require exactly one token (so, no parentheses or string pasting)1865 // Clang and GCC require exactly one token (so, no parentheses or string pasting)
1794 // even though their error messages indicate otherwise. Ours is slightly more1866 // even though their error messages indicate otherwise. Ours is slightly more
1795 // descriptive.1867 // descriptive.
1796 var invalid: ?Token = null;1868 var invalid: ?TokenWithExpansionLocs = null;
1797 var string: ?Token = null;1869 var string: ?TokenWithExpansionLocs = null;
1798 for (param_toks) |tok| switch (tok.id) {1870 for (param_toks) |tok| switch (tok.id) {
1799 .string_literal => {1871 .string_literal => {
1800 if (string) |_| invalid = tok else string = tok;1872 if (string) |_| invalid = tok else string = tok;
...@@ -1884,27 +1956,11 @@ fn expandVaOpt(...@@ -1884,27 +1956,11 @@ fn expandVaOpt(
1884 }1956 }
1885}1957}
18861958
1887fn shouldExpand(tok: Token, macro: *Macro) bool {1959fn bufCopyTokens(buf: *ExpandBuf, tokens: []const TokenWithExpansionLocs, src: []const Source.Location) !void {
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 {
1904 try buf.ensureUnusedCapacity(tokens.len);1960 try buf.ensureUnusedCapacity(tokens.len);
1905 for (tokens) |tok| {1961 for (tokens) |tok| {
1906 var copy = try tok.dupe(buf.allocator);1962 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);
1908 try copy.addExpansionLocation(buf.allocator, src);1964 try copy.addExpansionLocation(buf.allocator, src);
1909 buf.appendAssumeCapacity(copy);1965 buf.appendAssumeCapacity(copy);
1910 }1966 }
...@@ -1917,7 +1973,7 @@ fn nextBufToken(...@@ -1917,7 +1973,7 @@ fn nextBufToken(
1917 start_idx: *usize,1973 start_idx: *usize,
1918 end_idx: *usize,1974 end_idx: *usize,
1919 extend_buf: bool,1975 extend_buf: bool,
1920) Error!Token {1976) Error!TokenWithExpansionLocs {
1921 start_idx.* += 1;1977 start_idx.* += 1;
1922 if (start_idx.* == buf.items.len and start_idx.* >= end_idx.*) {1978 if (start_idx.* == buf.items.len and start_idx.* >= end_idx.*) {
1923 if (extend_buf) {1979 if (extend_buf) {
...@@ -1933,7 +1989,7 @@ fn nextBufToken(...@@ -1933,7 +1989,7 @@ fn nextBufToken(
1933 try buf.append(new_tok);1989 try buf.append(new_tok);
1934 return new_tok;1990 return new_tok;
1935 } else {1991 } else {
1936 return Token{ .id = .eof, .loc = .{ .id = .generated } };1992 return TokenWithExpansionLocs{ .id = .eof, .loc = .{ .id = .generated } };
1937 }1993 }
1938 } else {1994 } else {
1939 return buf.items[start_idx.*];1995 return buf.items[start_idx.*];
...@@ -1948,6 +2004,7 @@ fn collectMacroFuncArguments(...@@ -1948,6 +2004,7 @@ fn collectMacroFuncArguments(
1948 end_idx: *usize,2004 end_idx: *usize,
1949 extend_buf: bool,2005 extend_buf: bool,
1950 is_builtin: bool,2006 is_builtin: bool,
2007 r_paren: *TokenWithExpansionLocs,
1951) !MacroArguments {2008) !MacroArguments {
1952 const name_tok = buf.items[start_idx.*];2009 const name_tok = buf.items[start_idx.*];
1953 const saved_tokenizer = tokenizer.*;2010 const saved_tokenizer = tokenizer.*;
...@@ -1974,7 +2031,7 @@ fn collectMacroFuncArguments(...@@ -1974,7 +2031,7 @@ fn collectMacroFuncArguments(
1974 var parens: u32 = 0;2031 var parens: u32 = 0;
1975 var args = MacroArguments.init(pp.gpa);2032 var args = MacroArguments.init(pp.gpa);
1976 errdefer deinitMacroArguments(pp.gpa, &args);2033 errdefer deinitMacroArguments(pp.gpa, &args);
1977 var curArgument = std.ArrayList(Token).init(pp.gpa);2034 var curArgument = std.ArrayList(TokenWithExpansionLocs).init(pp.gpa);
1978 defer curArgument.deinit();2035 defer curArgument.deinit();
1979 while (true) {2036 while (true) {
1980 var tok = try nextBufToken(pp, tokenizer, buf, start_idx, end_idx, extend_buf);2037 var tok = try nextBufToken(pp, tokenizer, buf, start_idx, end_idx, extend_buf);
...@@ -1987,13 +2044,13 @@ fn collectMacroFuncArguments(...@@ -1987,13 +2044,13 @@ fn collectMacroFuncArguments(
1987 try args.append(owned);2044 try args.append(owned);
1988 } else {2045 } else {
1989 const duped = try tok.dupe(pp.gpa);2046 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);
1991 try curArgument.append(duped);2048 try curArgument.append(duped);
1992 }2049 }
1993 },2050 },
1994 .l_paren => {2051 .l_paren => {
1995 const duped = try tok.dupe(pp.gpa);2052 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);
1997 try curArgument.append(duped);2054 try curArgument.append(duped);
1998 parens += 1;2055 parens += 1;
1999 },2056 },
...@@ -2002,10 +2059,11 @@ fn collectMacroFuncArguments(...@@ -2002,10 +2059,11 @@ fn collectMacroFuncArguments(
2002 const owned = try curArgument.toOwnedSlice();2059 const owned = try curArgument.toOwnedSlice();
2003 errdefer pp.gpa.free(owned);2060 errdefer pp.gpa.free(owned);
2004 try args.append(owned);2061 try args.append(owned);
2062 r_paren.* = tok;
2005 break;2063 break;
2006 } else {2064 } else {
2007 const duped = try tok.dupe(pp.gpa);2065 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);
2009 try curArgument.append(duped);2067 try curArgument.append(duped);
2010 parens -= 1;2068 parens -= 1;
2011 }2069 }
...@@ -2028,7 +2086,7 @@ fn collectMacroFuncArguments(...@@ -2028,7 +2086,7 @@ fn collectMacroFuncArguments(
2028 },2086 },
2029 else => {2087 else => {
2030 const duped = try tok.dupe(pp.gpa);2088 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);
2032 try curArgument.append(duped);2090 try curArgument.append(duped);
2033 },2091 },
2034 }2092 }
...@@ -2038,7 +2096,7 @@ fn collectMacroFuncArguments(...@@ -2038,7 +2096,7 @@ fn collectMacroFuncArguments(
2038}2096}
20392097
2040fn removeExpandedTokens(pp: *Preprocessor, buf: *ExpandBuf, start: usize, len: usize, moving_end_idx: *usize) !void {2098fn 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);
2042 try buf.replaceRange(start, len, &.{});2100 try buf.replaceRange(start, len, &.{});
2043 moving_end_idx.* -|= len;2101 moving_end_idx.* -|= len;
2044}2102}
...@@ -2054,14 +2112,14 @@ const EvalContext = enum {...@@ -2054,14 +2112,14 @@ const EvalContext = enum {
20542112
2055/// Helper for safely iterating over a slice of tokens while skipping whitespace2113/// Helper for safely iterating over a slice of tokens while skipping whitespace
2056const TokenIterator = struct {2114const TokenIterator = struct {
2057 toks: []const Token,2115 toks: []const TokenWithExpansionLocs,
2058 i: usize,2116 i: usize,
20592117
2060 fn init(toks: []const Token) TokenIterator {2118 fn init(toks: []const TokenWithExpansionLocs) TokenIterator {
2061 return .{ .toks = toks, .i = 0 };2119 return .{ .toks = toks, .i = 0 };
2062 }2120 }
20632121
2064 fn nextNoWS(self: *TokenIterator) ?Token {2122 fn nextNoWS(self: *TokenIterator) ?TokenWithExpansionLocs {
2065 while (self.i < self.toks.len) : (self.i += 1) {2123 while (self.i < self.toks.len) : (self.i += 1) {
2066 const tok = self.toks[self.i];2124 const tok = self.toks[self.i];
2067 if (tok.id == .whitespace or tok.id == .macro_ws) continue;2125 if (tok.id == .whitespace or tok.id == .macro_ws) continue;
...@@ -2108,13 +2166,24 @@ fn expandMacroExhaustive(...@@ -2108,13 +2166,24 @@ fn expandMacroExhaustive(
2108 idx += it.i;2166 idx += it.i;
2109 continue;2167 continue;
2110 }2168 }
2111 const macro_entry = pp.defines.getPtr(pp.expandedSlice(macro_tok));2169 if (!macro_tok.id.isMacroIdentifier() or macro_tok.flags.expansion_disabled) {
2112 if (macro_entry == null or !shouldExpand(buf.items[idx], macro_entry.?)) {
2113 idx += 1;2170 idx += 1;
2114 continue;2171 continue;
2115 }2172 }
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: {
2117 if (macro.is_func) {2185 if (macro.is_func) {
2186 var r_paren: TokenWithExpansionLocs = undefined;
2118 var macro_scan_idx = idx;2187 var macro_scan_idx = idx;
2119 // to be saved in case this doesn't turn out to be a call2188 // to be saved in case this doesn't turn out to be a call
2120 const args = pp.collectMacroFuncArguments(2189 const args = pp.collectMacroFuncArguments(
...@@ -2124,6 +2193,7 @@ fn expandMacroExhaustive(...@@ -2124,6 +2193,7 @@ fn expandMacroExhaustive(
2124 &moving_end_idx,2193 &moving_end_idx,
2125 extend_buf,2194 extend_buf,
2126 macro.is_builtin,2195 macro.is_builtin,
2196 &r_paren,
2127 ) catch |er| switch (er) {2197 ) catch |er| switch (er) {
2128 error.MissingLParen => {2198 error.MissingLParen => {
2129 if (!buf.items[idx].flags.is_macro_arg) buf.items[idx].flags.expansion_disabled = true;2199 if (!buf.items[idx].flags.is_macro_arg) buf.items[idx].flags.expansion_disabled = true;
...@@ -2137,12 +2207,16 @@ fn expandMacroExhaustive(...@@ -2137,12 +2207,16 @@ fn expandMacroExhaustive(
2137 },2207 },
2138 else => |e| return e,2208 else => |e| return e,
2139 };2209 };
2210 assert(r_paren.id == .r_paren);
2140 defer {2211 defer {
2141 for (args.items) |item| {2212 for (args.items) |item| {
2142 pp.gpa.free(item);2213 pp.gpa.free(item);
2143 }2214 }
2144 args.deinit();2215 args.deinit();
2145 }2216 }
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
2147 var args_count: u32 = @intCast(args.items.len);2221 var args_count: u32 = @intCast(args.items.len);
2148 // if the macro has zero arguments g() args_count is still 12222 // if the macro has zero arguments g() args_count is still 1
...@@ -2199,10 +2273,13 @@ fn expandMacroExhaustive(...@@ -2199,10 +2273,13 @@ fn expandMacroExhaustive(
2199 for (res.items) |*tok| {2273 for (res.items) |*tok| {
2200 try tok.addExpansionLocation(pp.gpa, &.{macro_tok.loc});2274 try tok.addExpansionLocation(pp.gpa, &.{macro_tok.loc});
2201 try tok.addExpansionLocation(pp.gpa, macro_expansion_locs);2275 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);
2202 }2279 }
22032280
2204 const tokens_removed = macro_scan_idx - idx + 1;2281 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);
2206 try buf.replaceRange(idx, tokens_removed, res.items);2283 try buf.replaceRange(idx, tokens_removed, res.items);
22072284
2208 moving_end_idx += tokens_added;2285 moving_end_idx += tokens_added;
...@@ -2215,12 +2292,19 @@ fn expandMacroExhaustive(...@@ -2215,12 +2292,19 @@ fn expandMacroExhaustive(
2215 const res = try pp.expandObjMacro(macro);2292 const res = try pp.expandObjMacro(macro);
2216 defer res.deinit();2293 defer res.deinit();
22172294
2295 const hs = try pp.hideset.prepend(macro_tok.loc, macro_hidelist);
2296
2218 const macro_expansion_locs = macro_tok.expansionSlice();2297 const macro_expansion_locs = macro_tok.expansionSlice();
2219 var increment_idx_by = res.items.len;2298 var increment_idx_by = res.items.len;
2220 for (res.items, 0..) |*tok, i| {2299 for (res.items, 0..) |*tok, i| {
2221 tok.flags.is_macro_arg = macro_tok.flags.is_macro_arg;2300 tok.flags.is_macro_arg = macro_tok.flags.is_macro_arg;
2222 try tok.addExpansionLocation(pp.gpa, &.{macro_tok.loc});2301 try tok.addExpansionLocation(pp.gpa, &.{macro_tok.loc});
2223 try tok.addExpansionLocation(pp.gpa, macro_expansion_locs);2302 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
2224 if (tok.id == .keyword_defined and eval_ctx == .expr) {2308 if (tok.id == .keyword_defined and eval_ctx == .expr) {
2225 try pp.comp.addDiagnostic(.{2309 try pp.comp.addDiagnostic(.{
2226 .tag = .expansion_to_defined,2310 .tag = .expansion_to_defined,
...@@ -2233,7 +2317,7 @@ fn expandMacroExhaustive(...@@ -2233,7 +2317,7 @@ fn expandMacroExhaustive(
2233 }2317 }
2234 }2318 }
22352319
2236 Token.free(buf.items[idx].expansion_locs, pp.gpa);2320 TokenWithExpansionLocs.free(buf.items[idx].expansion_locs, pp.gpa);
2237 try buf.replaceRange(idx, 1, res.items);2321 try buf.replaceRange(idx, 1, res.items);
2238 idx += increment_idx_by;2322 idx += increment_idx_by;
2239 moving_end_idx = moving_end_idx + res.items.len - 1;2323 moving_end_idx = moving_end_idx + res.items.len - 1;
...@@ -2249,7 +2333,7 @@ fn expandMacroExhaustive(...@@ -2249,7 +2333,7 @@ fn expandMacroExhaustive(
22492333
2250 // trim excess buffer2334 // trim excess buffer
2251 for (buf.items[moving_end_idx..]) |item| {2335 for (buf.items[moving_end_idx..]) |item| {
2252 Token.free(item.expansion_locs, pp.gpa);2336 TokenWithExpansionLocs.free(item.expansion_locs, pp.gpa);
2253 }2337 }
2254 buf.items.len = moving_end_idx;2338 buf.items.len = moving_end_idx;
2255}2339}
...@@ -2260,30 +2344,35 @@ fn expandMacro(pp: *Preprocessor, tokenizer: *Tokenizer, raw: RawToken) MacroErr...@@ -2260,30 +2344,35 @@ fn expandMacro(pp: *Preprocessor, tokenizer: *Tokenizer, raw: RawToken) MacroErr
2260 var source_tok = tokFromRaw(raw);2344 var source_tok = tokFromRaw(raw);
2261 if (!raw.id.isMacroIdentifier()) {2345 if (!raw.id.isMacroIdentifier()) {
2262 source_tok.id.simplifyMacroKeyword();2346 source_tok.id.simplifyMacroKeyword();
2263 return pp.tokens.append(pp.gpa, source_tok);2347 return pp.addToken(source_tok);
2264 }2348 }
2265 pp.top_expansion_buf.items.len = 0;2349 pp.top_expansion_buf.items.len = 0;
2266 try pp.top_expansion_buf.append(source_tok);2350 try pp.top_expansion_buf.append(source_tok);
2267 pp.expansion_source_loc = source_tok.loc;2351 pp.expansion_source_loc = source_tok.loc;
22682352
2353 pp.hideset.clearRetainingCapacity();
2269 try pp.expandMacroExhaustive(tokenizer, &pp.top_expansion_buf, 0, 1, true, .non_expr);2354 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);
2271 for (pp.top_expansion_buf.items) |*tok| {2356 for (pp.top_expansion_buf.items) |*tok| {
2272 if (tok.id == .macro_ws and !pp.preserve_whitespace) {2357 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);
2274 continue;2359 continue;
2275 }2360 }
2276 if (tok.id == .comment and !pp.comp.langopts.preserve_comments_in_macros) {2361 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);
2278 continue;2367 continue;
2279 }2368 }
2280 tok.id.simplifyMacroKeywordExtra(true);2369 tok.id.simplifyMacroKeywordExtra(true);
2281 pp.tokens.appendAssumeCapacity(tok.*);2370 pp.addTokenAssumeCapacity(tok.*);
2282 }2371 }
2283 if (pp.preserve_whitespace) {2372 if (pp.preserve_whitespace) {
2284 try pp.tokens.ensureUnusedCapacity(pp.gpa, pp.add_expansion_nl);2373 try pp.ensureUnusedTokenCapacity(pp.add_expansion_nl);
2285 while (pp.add_expansion_nl > 0) : (pp.add_expansion_nl -= 1) {2374 while (pp.add_expansion_nl > 0) : (pp.add_expansion_nl -= 1) {
2286 pp.tokens.appendAssumeCapacity(.{ .id = .nl, .loc = .{2375 pp.addTokenAssumeCapacity(.{ .id = .nl, .loc = .{
2287 .id = tokenizer.source,2376 .id = tokenizer.source,
2288 .line = tokenizer.line,2377 .line = tokenizer.line,
2289 } });2378 } });
...@@ -2291,7 +2380,7 @@ fn expandMacro(pp: *Preprocessor, tokenizer: *Tokenizer, raw: RawToken) MacroErr...@@ -2291,7 +2380,7 @@ fn expandMacro(pp: *Preprocessor, tokenizer: *Tokenizer, raw: RawToken) MacroErr
2291 }2380 }
2292}2381}
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 {
2295 if (tok.id.lexeme()) |some| {2384 if (tok.id.lexeme()) |some| {
2296 if (!tok.id.allowsDigraphs(pp.comp.langopts) and !(tok.id == .macro_ws and macro_ws_handling == .preserve_macro_ws)) return some;2385 if (!tok.id.allowsDigraphs(pp.comp.langopts) and !(tok.id == .macro_ws and macro_ws_handling == .preserve_macro_ws)) return some;
2297 }2386 }
...@@ -2312,18 +2401,18 @@ fn expandedSliceExtra(pp: *const Preprocessor, tok: Token, macro_ws_handling: en...@@ -2312,18 +2401,18 @@ fn expandedSliceExtra(pp: *const Preprocessor, tok: Token, macro_ws_handling: en
2312}2401}
23132402
2314/// Get expanded token source string.2403/// Get expanded token source string.
2315pub fn expandedSlice(pp: *Preprocessor, tok: Token) []const u8 {2404pub fn expandedSlice(pp: *const Preprocessor, tok: anytype) []const u8 {
2316 return pp.expandedSliceExtra(tok, .single_macro_ws);2405 return pp.expandedSliceExtra(tok, .single_macro_ws);
2317}2406}
23182407
2319/// Concat two tokens and add the result to pp.generated2408/// 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 {
2321 const lhs = while (lhs_toks.popOrNull()) |lhs| {2410 const lhs = while (lhs_toks.popOrNull()) |lhs| {
2322 if ((pp.comp.langopts.preserve_comments_in_macros and lhs.id == .comment) or2411 if ((pp.comp.langopts.preserve_comments_in_macros and lhs.id == .comment) or
2323 (lhs.id != .macro_ws and lhs.id != .comment))2412 (lhs.id != .macro_ws and lhs.id != .comment))
2324 break lhs;2413 break lhs;
23252414
2326 Token.free(lhs.expansion_locs, pp.gpa);2415 TokenWithExpansionLocs.free(lhs.expansion_locs, pp.gpa);
2327 } else {2416 } else {
2328 return bufCopyTokens(lhs_toks, rhs_toks, &.{});2417 return bufCopyTokens(lhs_toks, rhs_toks, &.{});
2329 };2418 };
...@@ -2338,7 +2427,7 @@ fn pasteTokens(pp: *Preprocessor, lhs_toks: *ExpandBuf, rhs_toks: []const Token)...@@ -2338,7 +2427,7 @@ fn pasteTokens(pp: *Preprocessor, lhs_toks: *ExpandBuf, rhs_toks: []const Token)
2338 } else {2427 } else {
2339 return lhs_toks.appendAssumeCapacity(lhs);2428 return lhs_toks.appendAssumeCapacity(lhs);
2340 };2429 };
2341 defer Token.free(lhs.expansion_locs, pp.gpa);2430 defer TokenWithExpansionLocs.free(lhs.expansion_locs, pp.gpa);
23422431
2343 const start = pp.comp.generated_buf.items.len;2432 const start = pp.comp.generated_buf.items.len;
2344 const end = start + pp.expandedSlice(lhs).len + pp.expandedSlice(rhs).len;2433 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)...@@ -2375,8 +2464,8 @@ fn pasteTokens(pp: *Preprocessor, lhs_toks: *ExpandBuf, rhs_toks: []const Token)
2375 try bufCopyTokens(lhs_toks, rhs_toks[rhs_rest..], &.{});2464 try bufCopyTokens(lhs_toks, rhs_toks[rhs_rest..], &.{});
2376}2465}
23772466
2378fn makeGeneratedToken(pp: *Preprocessor, start: usize, id: Token.Id, source: Token) !Token {2467fn makeGeneratedToken(pp: *Preprocessor, start: usize, id: Token.Id, source: TokenWithExpansionLocs) !TokenWithExpansionLocs {
2379 var pasted_token = Token{ .id = id, .loc = .{2468 var pasted_token = TokenWithExpansionLocs{ .id = id, .loc = .{
2380 .id = .generated,2469 .id = .generated,
2381 .byte_offset = @intCast(start),2470 .byte_offset = @intCast(start),
2382 .line = pp.generated_line,2471 .line = pp.generated_line,
...@@ -2441,8 +2530,6 @@ fn define(pp: *Preprocessor, tokenizer: *Tokenizer) Error!void {...@@ -2441,8 +2530,6 @@ fn define(pp: *Preprocessor, tokenizer: *Tokenizer) Error!void {
2441 .tokens = &.{},2530 .tokens = &.{},
2442 .var_args = false,2531 .var_args = false,
2443 .loc = tokFromRaw(macro_name).loc,2532 .loc = tokFromRaw(macro_name).loc,
2444 .start = 0,
2445 .end = 0,
2446 .is_func = false,2533 .is_func = false,
2447 }),2534 }),
2448 .whitespace => first = tokenizer.next(),2535 .whitespace => first = tokenizer.next(),
...@@ -2460,7 +2547,7 @@ fn define(pp: *Preprocessor, tokenizer: *Tokenizer) Error!void {...@@ -2460,7 +2547,7 @@ fn define(pp: *Preprocessor, tokenizer: *Tokenizer) Error!void {
2460 var need_ws = false;2547 var need_ws = false;
2461 // Collect the token body and validate any ## found.2548 // Collect the token body and validate any ## found.
2462 var tok = first;2549 var tok = first;
2463 const end_index = while (true) {2550 while (true) {
2464 tok.id.simplifyMacroKeyword();2551 tok.id.simplifyMacroKeyword();
2465 switch (tok.id) {2552 switch (tok.id) {
2466 .hash_hash => {2553 .hash_hash => {
...@@ -2479,7 +2566,7 @@ fn define(pp: *Preprocessor, tokenizer: *Tokenizer) Error!void {...@@ -2479,7 +2566,7 @@ fn define(pp: *Preprocessor, tokenizer: *Tokenizer) Error!void {
2479 try pp.token_buf.append(tok);2566 try pp.token_buf.append(tok);
2480 try pp.token_buf.append(next);2567 try pp.token_buf.append(next);
2481 },2568 },
2482 .nl, .eof => break tok.start,2569 .nl, .eof => break,
2483 .comment => if (pp.comp.langopts.preserve_comments_in_macros) {2570 .comment => if (pp.comp.langopts.preserve_comments_in_macros) {
2484 if (need_ws) {2571 if (need_ws) {
2485 need_ws = false;2572 need_ws = false;
...@@ -2502,13 +2589,11 @@ fn define(pp: *Preprocessor, tokenizer: *Tokenizer) Error!void {...@@ -2502,13 +2589,11 @@ fn define(pp: *Preprocessor, tokenizer: *Tokenizer) Error!void {
2502 },2589 },
2503 }2590 }
2504 tok = tokenizer.next();2591 tok = tokenizer.next();
2505 } else unreachable;2592 }
25062593
2507 const list = try pp.arena.allocator().dupe(RawToken, pp.token_buf.items);2594 const list = try pp.arena.allocator().dupe(RawToken, pp.token_buf.items);
2508 try pp.defineMacro(macro_name, .{2595 try pp.defineMacro(macro_name, .{
2509 .loc = tokFromRaw(macro_name).loc,2596 .loc = tokFromRaw(macro_name).loc,
2510 .start = first.start,
2511 .end = end_index,
2512 .tokens = list,2597 .tokens = list,
2513 .params = undefined,2598 .params = undefined,
2514 .is_func = false,2599 .is_func = false,
...@@ -2525,9 +2610,9 @@ fn defineFn(pp: *Preprocessor, tokenizer: *Tokenizer, macro_name: RawToken, l_pa...@@ -2525,9 +2610,9 @@ fn defineFn(pp: *Preprocessor, tokenizer: *Tokenizer, macro_name: RawToken, l_pa
2525 // Parse the parameter list.2610 // Parse the parameter list.
2526 var gnu_var_args: []const u8 = "";2611 var gnu_var_args: []const u8 = "";
2527 var var_args = false;2612 var var_args = false;
2528 const start_index = while (true) {2613 while (true) {
2529 var tok = tokenizer.nextNoWS();2614 var tok = tokenizer.nextNoWS();
2530 if (tok.id == .r_paren) break tok.end;2615 if (tok.id == .r_paren) break;
2531 if (tok.id == .eof) return pp.err(tok, .unterminated_macro_param_list);2616 if (tok.id == .eof) return pp.err(tok, .unterminated_macro_param_list);
2532 if (tok.id == .ellipsis) {2617 if (tok.id == .ellipsis) {
2533 var_args = true;2618 var_args = true;
...@@ -2537,7 +2622,7 @@ fn defineFn(pp: *Preprocessor, tokenizer: *Tokenizer, macro_name: RawToken, l_pa...@@ -2537,7 +2622,7 @@ fn defineFn(pp: *Preprocessor, tokenizer: *Tokenizer, macro_name: RawToken, l_pa
2537 try pp.err(l_paren, .to_match_paren);2622 try pp.err(l_paren, .to_match_paren);
2538 return skipToNl(tokenizer);2623 return skipToNl(tokenizer);
2539 }2624 }
2540 break r_paren.end;2625 break;
2541 }2626 }
2542 if (!tok.id.isMacroIdentifier()) {2627 if (!tok.id.isMacroIdentifier()) {
2543 try pp.err(tok, .invalid_token_param_list);2628 try pp.err(tok, .invalid_token_param_list);
...@@ -2556,22 +2641,22 @@ fn defineFn(pp: *Preprocessor, tokenizer: *Tokenizer, macro_name: RawToken, l_pa...@@ -2556,22 +2641,22 @@ fn defineFn(pp: *Preprocessor, tokenizer: *Tokenizer, macro_name: RawToken, l_pa
2556 try pp.err(l_paren, .to_match_paren);2641 try pp.err(l_paren, .to_match_paren);
2557 return skipToNl(tokenizer);2642 return skipToNl(tokenizer);
2558 }2643 }
2559 break r_paren.end;2644 break;
2560 } else if (tok.id == .r_paren) {2645 } else if (tok.id == .r_paren) {
2561 break tok.end;2646 break;
2562 } else if (tok.id != .comma) {2647 } else if (tok.id != .comma) {
2563 try pp.err(tok, .expected_comma_param_list);2648 try pp.err(tok, .expected_comma_param_list);
2564 return skipToNl(tokenizer);2649 return skipToNl(tokenizer);
2565 }2650 }
2566 } else unreachable;2651 }
25672652
2568 var need_ws = false;2653 var need_ws = false;
2569 // Collect the body tokens and validate # and ##'s found.2654 // Collect the body tokens and validate # and ##'s found.
2570 pp.token_buf.items.len = 0; // Safe to use since we can only be in one directive at a time.2655 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) {
2572 var tok = tokenizer.next();2657 var tok = tokenizer.next();
2573 switch (tok.id) {2658 switch (tok.id) {
2574 .nl, .eof => break tok.start,2659 .nl, .eof => break,
2575 .whitespace => need_ws = pp.token_buf.items.len != 0,2660 .whitespace => need_ws = pp.token_buf.items.len != 0,
2576 .comment => if (!pp.comp.langopts.preserve_comments_in_macros) continue else {2661 .comment => if (!pp.comp.langopts.preserve_comments_in_macros) continue else {
2577 if (need_ws) {2662 if (need_ws) {
...@@ -2690,7 +2775,7 @@ fn defineFn(pp: *Preprocessor, tokenizer: *Tokenizer, macro_name: RawToken, l_pa...@@ -2690,7 +2775,7 @@ fn defineFn(pp: *Preprocessor, tokenizer: *Tokenizer, macro_name: RawToken, l_pa
2690 try pp.token_buf.append(tok);2775 try pp.token_buf.append(tok);
2691 },2776 },
2692 }2777 }
2693 } else unreachable;2778 }
26942779
2695 const param_list = try pp.arena.allocator().dupe([]const u8, params.items);2780 const param_list = try pp.arena.allocator().dupe([]const u8, params.items);
2696 const token_list = try pp.arena.allocator().dupe(RawToken, pp.token_buf.items);2781 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...@@ -2700,8 +2785,6 @@ fn defineFn(pp: *Preprocessor, tokenizer: *Tokenizer, macro_name: RawToken, l_pa
2700 .var_args = var_args or gnu_var_args.len != 0,2785 .var_args = var_args or gnu_var_args.len != 0,
2701 .tokens = token_list,2786 .tokens = token_list,
2702 .loc = tokFromRaw(macro_name).loc,2787 .loc = tokFromRaw(macro_name).loc,
2703 .start = start_index,
2704 .end = end_index,
2705 });2788 });
2706}2789}
27072790
...@@ -2714,7 +2797,7 @@ fn embed(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!void {...@@ -2714,7 +2797,7 @@ fn embed(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!void {
2714 error.InvalidInclude => return,2797 error.InvalidInclude => return,
2715 else => |e| return e,2798 else => |e| return e,
2716 };2799 };
2717 defer Token.free(filename_tok.expansion_locs, pp.gpa);2800 defer TokenWithExpansionLocs.free(filename_tok.expansion_locs, pp.gpa);
27182801
2719 // Check for empty filename.2802 // Check for empty filename.
2720 const tok_slice = pp.expandedSliceExtra(filename_tok, .single_macro_ws);2803 const tok_slice = pp.expandedSliceExtra(filename_tok, .single_macro_ws);
...@@ -2859,7 +2942,7 @@ fn embed(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!void {...@@ -2859,7 +2942,7 @@ fn embed(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!void {
2859 return;2942 return;
2860 }2943 }
28612944
2862 try pp.tokens.ensureUnusedCapacity(pp.comp.gpa, 2 * embed_bytes.len - 1); // N bytes and N-1 commas2945 try pp.ensureUnusedTokenCapacity(2 * embed_bytes.len - 1); // N bytes and N-1 commas
28632946
2864 // TODO: We currently only support systems with CHAR_BIT == 82947 // TODO: We currently only support systems with CHAR_BIT == 8
2865 // If the target's CHAR_BIT is not 8, we need to write out correctly-sized embed_bytes2948 // 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 {...@@ -2870,14 +2953,14 @@ fn embed(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!void {
2870 const byte = embed_bytes[0];2953 const byte = embed_bytes[0];
2871 const start = pp.comp.generated_buf.items.len;2954 const start = pp.comp.generated_buf.items.len;
2872 try writer.print("{d}", .{byte});2955 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));
2874 }2957 }
28752958
2876 for (embed_bytes[1..]) |byte| {2959 for (embed_bytes[1..]) |byte| {
2877 const start = pp.comp.generated_buf.items.len;2960 const start = pp.comp.generated_buf.items.len;
2878 try writer.print(",{d}", .{byte});2961 try writer.print(",{d}", .{byte});
2879 pp.tokens.appendAssumeCapacity(.{ .id = .comma, .loc = .{ .id = .generated, .byte_offset = @intCast(start) } });2962 pp.addTokenAssumeCapacity(.{ .id = .comma, .loc = .{ .id = .generated, .byte_offset = @intCast(start) } });
2880 pp.tokens.appendAssumeCapacity(try pp.makeGeneratedToken(start + 1, .embed_byte, filename_tok));2963 pp.addTokenAssumeCapacity(try pp.makeGeneratedToken(start + 1, .embed_byte, filename_tok));
2881 }2964 }
2882 try pp.comp.generated_buf.append(pp.gpa, '\n');2965 try pp.comp.generated_buf.append(pp.gpa, '\n');
28832966
...@@ -2911,19 +2994,19 @@ fn include(pp: *Preprocessor, tokenizer: *Tokenizer, which: Compilation.WhichInc...@@ -2911,19 +2994,19 @@ fn include(pp: *Preprocessor, tokenizer: *Tokenizer, which: Compilation.WhichInc
2911 pp.verboseLog(first, "include file {s}", .{new_source.path});2994 pp.verboseLog(first, "include file {s}", .{new_source.path});
2912 }2995 }
29132996
2914 const tokens_start = pp.tokens.len;2997 const token_state = pp.getTokenState();
2915 try pp.addIncludeStart(new_source);2998 try pp.addIncludeStart(new_source);
2916 const eof = pp.preprocessExtra(new_source) catch |er| switch (er) {2999 const eof = pp.preprocessExtra(new_source) catch |er| switch (er) {
2917 error.StopPreprocessing => {3000 error.StopPreprocessing => {
2918 for (pp.tokens.items(.expansion_locs)[tokens_start..]) |loc| Token.free(loc, pp.gpa);3001 for (pp.expansion_entries.items(.locs)[token_state.expansion_entries_len..]) |loc| TokenWithExpansionLocs.free(loc, pp.gpa);
2919 pp.tokens.len = tokens_start;3002 pp.restoreTokenState(token_state);
2920 return;3003 return;
2921 },3004 },
2922 else => |e| return e,3005 else => |e| return e,
2923 };3006 };
2924 try eof.checkMsEof(new_source, pp.comp);3007 try eof.checkMsEof(new_source, pp.comp);
2925 if (pp.preserve_whitespace and pp.tokens.items(.id)[pp.tokens.len - 1] != .nl) {3008 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 = .{
2927 .id = tokenizer.source,3010 .id = tokenizer.source,
2928 .line = tokenizer.line,3011 .line = tokenizer.line,
2929 } });3012 } });
...@@ -2945,7 +3028,7 @@ fn include(pp: *Preprocessor, tokenizer: *Tokenizer, which: Compilation.WhichInc...@@ -2945,7 +3028,7 @@ fn include(pp: *Preprocessor, tokenizer: *Tokenizer, which: Compilation.WhichInc
2945/// 3. Via a stringified macro argument which is used as an argument to `_Pragma`3028/// 3. Via a stringified macro argument which is used as an argument to `_Pragma`
2946/// operator_loc: Location of `_Pragma`; null if this is from #pragma3029/// operator_loc: Location of `_Pragma`; null if this is from #pragma
2947/// arg_locs: expansion locations of the argument to _Pragma. empty if #pragma or a raw string literal was used3030/// 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 {
2949 var tok = tokFromRaw(raw);3032 var tok = tokFromRaw(raw);
2950 if (operator_loc) |loc| {3033 if (operator_loc) |loc| {
2951 try tok.addExpansionLocation(pp.gpa, &.{loc});3034 try tok.addExpansionLocation(pp.gpa, &.{loc});
...@@ -2954,28 +3037,52 @@ fn makePragmaToken(pp: *Preprocessor, raw: RawToken, operator_loc: ?Source.Locat...@@ -2954,28 +3037,52 @@ fn makePragmaToken(pp: *Preprocessor, raw: RawToken, operator_loc: ?Source.Locat
2954 return tok;3037 return tok;
2955}3038}
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
2957/// Handle a pragma directive3064/// Handle a pragma directive
2958fn pragma(pp: *Preprocessor, tokenizer: *Tokenizer, pragma_tok: RawToken, operator_loc: ?Source.Location, arg_locs: []const Source.Location) !void {3065fn pragma(pp: *Preprocessor, tokenizer: *Tokenizer, pragma_tok: RawToken, operator_loc: ?Source.Location, arg_locs: []const Source.Location) !void {
2959 const name_tok = tokenizer.nextNoWS();3066 const name_tok = tokenizer.nextNoWS();
2960 if (name_tok.id == .nl or name_tok.id == .eof) return;3067 if (name_tok.id == .nl or name_tok.id == .eof) return;
29613068
2962 const name = pp.tokSlice(name_tok);3069 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));
2964 const pragma_start: u32 = @intCast(pp.tokens.len);3071 const pragma_start: u32 = @intCast(pp.tokens.len);
29653072
2966 const pragma_name_tok = try pp.makePragmaToken(name_tok, operator_loc, arg_locs);3073 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);
2968 while (true) {3075 while (true) {
2969 const next_tok = tokenizer.next();3076 const next_tok = tokenizer.next();
2970 if (next_tok.id == .whitespace) continue;3077 if (next_tok.id == .whitespace) continue;
2971 if (next_tok.id == .eof) {3078 if (next_tok.id == .eof) {
2972 try pp.tokens.append(pp.gpa, .{3079 try pp.addToken(.{
2973 .id = .nl,3080 .id = .nl,
2974 .loc = .{ .id = .generated },3081 .loc = .{ .id = .generated },
2975 });3082 });
2976 break;3083 break;
2977 }3084 }
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));
2979 if (next_tok.id == .nl) break;3086 if (next_tok.id == .nl) break;
2980 }3087 }
2981 if (pp.comp.getPragma(name)) |prag| unknown: {3088 if (pp.comp.getPragma(name)) |prag| unknown: {
...@@ -2995,7 +3102,7 @@ fn findIncludeFilenameToken(...@@ -2995,7 +3102,7 @@ fn findIncludeFilenameToken(
2995 first_token: RawToken,3102 first_token: RawToken,
2996 tokenizer: *Tokenizer,3103 tokenizer: *Tokenizer,
2997 trailing_token_behavior: enum { ignore_trailing_tokens, expect_nl_eof },3104 trailing_token_behavior: enum { ignore_trailing_tokens, expect_nl_eof },
2998) !Token {3105) !TokenWithExpansionLocs {
2999 var first = first_token;3106 var first = first_token;
30003107
3001 if (first.id == .angle_bracket_left) to_end: {3108 if (first.id == .angle_bracket_left) to_end: {
...@@ -3025,14 +3132,13 @@ fn findIncludeFilenameToken(...@@ -3025,14 +3132,13 @@ fn findIncludeFilenameToken(
3025 else => expanded: {3132 else => expanded: {
3026 // Try to expand if the argument is a macro.3133 // Try to expand if the argument is a macro.
3027 pp.top_expansion_buf.items.len = 0;3134 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);
3029 try pp.top_expansion_buf.append(source_tok);3136 try pp.top_expansion_buf.append(source_tok);
3030 pp.expansion_source_loc = source_tok.loc;3137 pp.expansion_source_loc = source_tok.loc;
30313138
3032 try pp.expandMacroExhaustive(tokenizer, &pp.top_expansion_buf, 0, 1, true, .non_expr);3139 try pp.expandMacroExhaustive(tokenizer, &pp.top_expansion_buf, 0, 1, true, .non_expr);
3033 var trailing_toks: []const Token = &.{};3140 var trailing_toks: []const TokenWithExpansionLocs = &.{};
3034 const include_str = (try pp.reconstructIncludeString(pp.top_expansion_buf.items, &trailing_toks)) orelse {3141 const include_str = (try pp.reconstructIncludeString(pp.top_expansion_buf.items, &trailing_toks, tokFromRaw(first))) orelse {
3035 try pp.err(first, .expected_filename);
3036 try pp.expectNl(tokenizer);3142 try pp.expectNl(tokenizer);
3037 return error.InvalidInclude;3143 return error.InvalidInclude;
3038 };3144 };
...@@ -3071,7 +3177,7 @@ fn findIncludeFilenameToken(...@@ -3071,7 +3177,7 @@ fn findIncludeFilenameToken(
30713177
3072fn findIncludeSource(pp: *Preprocessor, tokenizer: *Tokenizer, first: RawToken, which: Compilation.WhichInclude) !Source {3178fn findIncludeSource(pp: *Preprocessor, tokenizer: *Tokenizer, first: RawToken, which: Compilation.WhichInclude) !Source {
3073 const filename_tok = try pp.findIncludeFilenameToken(first, tokenizer, .expect_nl_eof);3179 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
3076 // Check for empty filename.3182 // Check for empty filename.
3077 const tok_slice = pp.expandedSliceExtra(filename_tok, .single_macro_ws);3183 const tok_slice = pp.expandedSliceExtra(filename_tok, .single_macro_ws);
...@@ -3101,8 +3207,7 @@ fn printLinemarker(...@@ -3101,8 +3207,7 @@ fn printLinemarker(
3101) !void {3207) !void {
3102 try w.writeByte('#');3208 try w.writeByte('#');
3103 if (pp.linemarkers == .line_directives) try w.writeAll("line");3209 if (pp.linemarkers == .line_directives) try w.writeAll("line");
3104 // line_no is 0 indexed3210 try w.print(" {d} \"", .{line_no});
3105 try w.print(" {d} \"", .{line_no + 1});
3106 for (source.path) |byte| switch (byte) {3211 for (source.path) |byte| switch (byte) {
3107 '\n' => try w.writeAll("\\n"),3212 '\n' => try w.writeAll("\\n"),
3108 '\r' => try w.writeAll("\\r"),3213 '\r' => try w.writeAll("\\r"),
...@@ -3219,7 +3324,7 @@ pub fn prettyPrintTokens(pp: *Preprocessor, w: anytype) !void {...@@ -3219,7 +3324,7 @@ pub fn prettyPrintTokens(pp: *Preprocessor, w: anytype) !void {
3219 .include_start => {3324 .include_start => {
3220 const source = pp.comp.getSource(cur.loc.id);3325 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);
3223 last_nl = true;3328 last_nl = true;
3224 },3329 },
3225 .include_resume => {3330 .include_resume => {
...@@ -3259,7 +3364,7 @@ test "Preserve pragma tokens sometimes" {...@@ -3259,7 +3364,7 @@ test "Preserve pragma tokens sometimes" {
32593364
3260 const test_runner_macros = try comp.addSourceFromBuffer("<test_runner>", source_text);3365 const test_runner_macros = try comp.addSourceFromBuffer("<test_runner>", source_text);
3261 const eof = try pp.preprocess(test_runner_macros);3366 const eof = try pp.preprocess(test_runner_macros);
3262 try pp.tokens.append(pp.gpa, eof);3367 try pp.addToken(eof);
3263 try pp.prettyPrintTokens(buf.writer());3368 try pp.prettyPrintTokens(buf.writer());
3264 return allocator.dupe(u8, buf.items);3369 return allocator.dupe(u8, buf.items);
3265 }3370 }
lib/compiler/aro/aro/Toolchain.zig+19
...@@ -487,3 +487,22 @@ pub fn addRuntimeLibs(tc: *const Toolchain, argv: *std.ArrayList([]const u8)) !v...@@ -487,3 +487,22 @@ pub fn addRuntimeLibs(tc: *const Toolchain, argv: *std.ArrayList([]const u8)) !v
487 try argv.append("-ldl");487 try argv.append("-ldl");
488 }488 }
489}489}
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");...@@ -12,6 +12,16 @@ const StringInterner = @import("StringInterner.zig");
1212
13pub const Token = struct {13pub const Token = struct {
14 id: Id,14 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,
15 flags: packed struct {25 flags: packed struct {
16 expansion_disabled: bool = false,26 expansion_disabled: bool = false,
17 is_macro_arg: bool = false,27 is_macro_arg: bool = false,
...@@ -22,15 +32,15 @@ pub const Token = struct {...@@ -22,15 +32,15 @@ pub const Token = struct {
22 loc: Source.Location,32 loc: Source.Location,
23 expansion_locs: ?[*]Source.Location = null,33 expansion_locs: ?[*]Source.Location = null,
2434
25 pub fn expansionSlice(tok: Token) []const Source.Location {35 pub fn expansionSlice(tok: TokenWithExpansionLocs) []const Source.Location {
26 const locs = tok.expansion_locs orelse return &[0]Source.Location{};36 const locs = tok.expansion_locs orelse return &[0]Source.Location{};
27 var i: usize = 0;37 var i: usize = 0;
28 while (locs[i].id != .unused) : (i += 1) {}38 while (locs[i].id != .unused) : (i += 1) {}
29 return locs[0..i];39 return locs[0..i];
30 }40 }
3141
32 pub fn addExpansionLocation(tok: *Token, gpa: std.mem.Allocator, new: []const Source.Location) !void {42 pub fn addExpansionLocation(tok: *TokenWithExpansionLocs, gpa: std.mem.Allocator, new: []const Source.Location) !void {
33 if (new.len == 0 or tok.id == .whitespace) return;43 if (new.len == 0 or tok.id == .whitespace or tok.id == .macro_ws or tok.id == .placemarker) return;
34 var list = std.ArrayList(Source.Location).init(gpa);44 var list = std.ArrayList(Source.Location).init(gpa);
35 defer {45 defer {
36 @memset(list.items.ptr[list.items.len..list.capacity], .{});46 @memset(list.items.ptr[list.items.len..list.capacity], .{});
...@@ -70,14 +80,14 @@ pub const Token = struct {...@@ -70,14 +80,14 @@ pub const Token = struct {
70 gpa.free(locs[0 .. i + 1]);80 gpa.free(locs[0 .. i + 1]);
71 }81 }
7282
73 pub fn dupe(tok: Token, gpa: std.mem.Allocator) !Token {83 pub fn dupe(tok: TokenWithExpansionLocs, gpa: std.mem.Allocator) !TokenWithExpansionLocs {
74 var copy = tok;84 var copy = tok;
75 copy.expansion_locs = null;85 copy.expansion_locs = null;
76 try copy.addExpansionLocation(gpa, tok.expansionSlice());86 try copy.addExpansionLocation(gpa, tok.expansionSlice());
77 return copy;87 return copy;
78 }88 }
7989
80 pub fn checkMsEof(tok: Token, source: Source, comp: *Compilation) !void {90 pub fn checkMsEof(tok: TokenWithExpansionLocs, source: Source, comp: *Compilation) !void {
81 std.debug.assert(tok.id == .eof);91 std.debug.assert(tok.id == .eof);
82 if (source.buf.len > tok.loc.byte_offset and source.buf[tok.loc.byte_offset] == 0x1A) {92 if (source.buf.len > tok.loc.byte_offset and source.buf[tok.loc.byte_offset] == 0x1A) {
83 try comp.addDiagnostic(.{93 try comp.addDiagnostic(.{
...@@ -90,11 +100,6 @@ pub const Token = struct {...@@ -90,11 +100,6 @@ pub const Token = struct {
90 }, &.{});100 }, &.{});
91 }101 }
92 }102 }
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;
98};103};
99104
100pub const TokenIndex = u32;105pub const TokenIndex = u32;
lib/compiler/aro/aro/Type.zig+5-2
...@@ -105,6 +105,7 @@ pub const Func = struct {...@@ -105,6 +105,7 @@ pub const Func = struct {
105 fn eql(a: *const Func, b: *const Func, a_spec: Specifier, b_spec: Specifier, comp: *const Compilation) bool {105 fn eql(a: *const Func, b: *const Func, a_spec: Specifier, b_spec: Specifier, comp: *const Compilation) bool {
106 // return type cannot have qualifiers106 // return type cannot have qualifiers
107 if (!a.return_type.eql(b.return_type, comp, false)) return false;107 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
109 if (a.params.len != b.params.len) {110 if (a.params.len != b.params.len) {
110 if (a_spec == .old_style_func or b_spec == .old_style_func) {111 if (a_spec == .old_style_func or b_spec == .old_style_func) {
...@@ -114,6 +115,7 @@ pub const Func = struct {...@@ -114,6 +115,7 @@ pub const Func = struct {
114 }115 }
115 return true;116 return true;
116 }117 }
118 return false;
117 }119 }
118 if ((a_spec == .func) != (b_spec == .func)) return false;120 if ((a_spec == .func) != (b_spec == .func)) return false;
119 // TODO validate this121 // TODO validate this
...@@ -887,7 +889,8 @@ pub fn hasIncompleteSize(ty: Type) bool {...@@ -887,7 +889,8 @@ pub fn hasIncompleteSize(ty: Type) bool {
887 .@"struct", .@"union" => ty.data.record.isIncomplete(),889 .@"struct", .@"union" => ty.data.record.isIncomplete(),
888 .array, .static_array => ty.data.array.elem.hasIncompleteSize(),890 .array, .static_array => ty.data.array.elem.hasIncompleteSize(),
889 .typeof_type => ty.data.sub_type.hasIncompleteSize(),891 .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(),
891 .attributed => ty.data.attributed.base.hasIncompleteSize(),894 .attributed => ty.data.attributed.base.hasIncompleteSize(),
892 else => false,895 else => false,
893 };896 };
...@@ -1053,7 +1056,7 @@ pub fn bitSizeof(ty: Type, comp: *const Compilation) ?u64 {...@@ -1053,7 +1056,7 @@ pub fn bitSizeof(ty: Type, comp: *const Compilation) ?u64 {
1053}1056}
10541057
1055pub fn alignable(ty: Type) bool {1058pub 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);
1057}1060}
10581061
1059/// Get the alignment of a type1062/// Get the alignment of a type
lib/compiler/aro/aro/Value.zig+5-3
...@@ -60,7 +60,8 @@ test "minUnsignedBits" {...@@ -60,7 +60,8 @@ test "minUnsignedBits" {
6060
61 var comp = Compilation.init(std.testing.allocator);61 var comp = Compilation.init(std.testing.allocator);
62 defer comp.deinit();62 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
65 try Test.checkIntBits(&comp, 0, 0);66 try Test.checkIntBits(&comp, 0, 0);
66 try Test.checkIntBits(&comp, 1, 1);67 try Test.checkIntBits(&comp, 1, 1);
...@@ -94,7 +95,8 @@ test "minSignedBits" {...@@ -94,7 +95,8 @@ test "minSignedBits" {
9495
95 var comp = Compilation.init(std.testing.allocator);96 var comp = Compilation.init(std.testing.allocator);
96 defer comp.deinit();97 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
99 try Test.checkIntBits(&comp, -1, 1);101 try Test.checkIntBits(&comp, -1, 1);
100 try Test.checkIntBits(&comp, -2, 2);102 try Test.checkIntBits(&comp, -2, 2);
...@@ -224,7 +226,7 @@ pub fn intCast(v: *Value, dest_ty: Type, comp: *Compilation) !void {...@@ -224,7 +226,7 @@ pub fn intCast(v: *Value, dest_ty: Type, comp: *Compilation) !void {
224 v.* = try intern(comp, .{ .int = .{ .big_int = result_bigint.toConst() } });226 v.* = try intern(comp, .{ .int = .{ .big_int = result_bigint.toConst() } });
225}227}
226228
227/// Converts the stored value from an integer to a float.229/// Converts the stored value to a float of the specified type
228/// `.none` value remains unchanged.230/// `.none` value remains unchanged.
229pub fn floatCast(v: *Value, dest_ty: Type, comp: *Compilation) !void {231pub fn floatCast(v: *Value, dest_ty: Type, comp: *Compilation) !void {
230 if (v.opt_ref == .none) return;232 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...@@ -80,7 +80,7 @@ fn diagnosticHandler(self: *GCC, pp: *Preprocessor, start_idx: TokenIndex) Pragm
80 .tag = .pragma_requires_string_literal,80 .tag = .pragma_requires_string_literal,
81 .loc = diagnostic_tok.loc,81 .loc = diagnostic_tok.loc,
82 .extra = .{ .str = "GCC diagnostic" },82 .extra = .{ .str = "GCC diagnostic" },
83 }, diagnostic_tok.expansionSlice());83 }, pp.expansionSlice(start_idx));
84 },84 },
85 else => |e| return e,85 else => |e| return e,
86 };86 };
...@@ -90,7 +90,7 @@ fn diagnosticHandler(self: *GCC, pp: *Preprocessor, start_idx: TokenIndex) Pragm...@@ -90,7 +90,7 @@ fn diagnosticHandler(self: *GCC, pp: *Preprocessor, start_idx: TokenIndex) Pragm
90 .tag = .malformed_warning_check,90 .tag = .malformed_warning_check,
91 .loc = next.loc,91 .loc = next.loc,
92 .extra = .{ .str = "GCC diagnostic" },92 .extra = .{ .str = "GCC diagnostic" },
93 }, next.expansionSlice());93 }, pp.expansionSlice(start_idx + 1));
94 }94 }
95 const new_kind: Diagnostics.Kind = switch (diagnostic) {95 const new_kind: Diagnostics.Kind = switch (diagnostic) {
96 .ignored => .off,96 .ignored => .off,
...@@ -116,7 +116,7 @@ fn preprocessorHandler(pragma: *Pragma, pp: *Preprocessor, start_idx: TokenIndex...@@ -116,7 +116,7 @@ fn preprocessorHandler(pragma: *Pragma, pp: *Preprocessor, start_idx: TokenIndex
116 return pp.comp.addDiagnostic(.{116 return pp.comp.addDiagnostic(.{
117 .tag = .unknown_gcc_pragma,117 .tag = .unknown_gcc_pragma,
118 .loc = directive_tok.loc,118 .loc = directive_tok.loc,
119 }, directive_tok.expansionSlice());119 }, pp.expansionSlice(start_idx + 1));
120120
121 switch (gcc_pragma) {121 switch (gcc_pragma) {
122 .warning, .@"error" => {122 .warning, .@"error" => {
...@@ -126,7 +126,7 @@ fn preprocessorHandler(pragma: *Pragma, pp: *Preprocessor, start_idx: TokenIndex...@@ -126,7 +126,7 @@ fn preprocessorHandler(pragma: *Pragma, pp: *Preprocessor, start_idx: TokenIndex
126 .tag = .pragma_requires_string_literal,126 .tag = .pragma_requires_string_literal,
127 .loc = directive_tok.loc,127 .loc = directive_tok.loc,
128 .extra = .{ .str = @tagName(gcc_pragma) },128 .extra = .{ .str = @tagName(gcc_pragma) },
129 }, directive_tok.expansionSlice());129 }, pp.expansionSlice(start_idx + 1));
130 },130 },
131 else => |e| return e,131 else => |e| return e,
132 };132 };
...@@ -134,7 +134,7 @@ fn preprocessorHandler(pragma: *Pragma, pp: *Preprocessor, start_idx: TokenIndex...@@ -134,7 +134,7 @@ fn preprocessorHandler(pragma: *Pragma, pp: *Preprocessor, start_idx: TokenIndex
134 const diagnostic_tag: Diagnostics.Tag = if (gcc_pragma == .warning) .pragma_warning_message else .pragma_error_message;134 const diagnostic_tag: Diagnostics.Tag = if (gcc_pragma == .warning) .pragma_warning_message else .pragma_error_message;
135 return pp.comp.addDiagnostic(135 return pp.comp.addDiagnostic(
136 .{ .tag = diagnostic_tag, .loc = directive_tok.loc, .extra = extra },136 .{ .tag = diagnostic_tag, .loc = directive_tok.loc, .extra = extra },
137 directive_tok.expansionSlice(),137 pp.expansionSlice(start_idx + 1),
138 );138 );
139 },139 },
140 .diagnostic => return self.diagnosticHandler(pp, start_idx + 2) catch |err| switch (err) {140 .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...@@ -143,12 +143,12 @@ fn preprocessorHandler(pragma: *Pragma, pp: *Preprocessor, start_idx: TokenIndex
143 return pp.comp.addDiagnostic(.{143 return pp.comp.addDiagnostic(.{
144 .tag = .unknown_gcc_pragma_directive,144 .tag = .unknown_gcc_pragma_directive,
145 .loc = tok.loc,145 .loc = tok.loc,
146 }, tok.expansionSlice());146 }, pp.expansionSlice(start_idx + 2));
147 },147 },
148 else => |e| return e,148 else => |e| return e,
149 },149 },
150 .poison => {150 .poison => {
151 var i: usize = 2;151 var i: u32 = 2;
152 while (true) : (i += 1) {152 while (true) : (i += 1) {
153 const tok = pp.tokens.get(start_idx + i);153 const tok = pp.tokens.get(start_idx + i);
154 if (tok.id == .nl) break;154 if (tok.id == .nl) break;
...@@ -157,14 +157,14 @@ fn preprocessorHandler(pragma: *Pragma, pp: *Preprocessor, start_idx: TokenIndex...@@ -157,14 +157,14 @@ fn preprocessorHandler(pragma: *Pragma, pp: *Preprocessor, start_idx: TokenIndex
157 return pp.comp.addDiagnostic(.{157 return pp.comp.addDiagnostic(.{
158 .tag = .pragma_poison_identifier,158 .tag = .pragma_poison_identifier,
159 .loc = tok.loc,159 .loc = tok.loc,
160 }, tok.expansionSlice());160 }, pp.expansionSlice(start_idx + i));
161 }161 }
162 const str = pp.expandedSlice(tok);162 const str = pp.expandedSlice(tok);
163 if (pp.defines.get(str) != null) {163 if (pp.defines.get(str) != null) {
164 try pp.comp.addDiagnostic(.{164 try pp.comp.addDiagnostic(.{
165 .tag = .pragma_poison_macro,165 .tag = .pragma_poison_macro,
166 .loc = tok.loc,166 .loc = tok.loc,
167 }, tok.expansionSlice());167 }, pp.expansionSlice(start_idx + i));
168 }168 }
169 try pp.poisoned_identifiers.put(str, {});169 try pp.poisoned_identifiers.put(str, {});
170 }170 }
lib/compiler/aro/aro/pragmas/message.zig+1-1
...@@ -28,7 +28,7 @@ fn deinit(pragma: *Pragma, comp: *Compilation) void {...@@ -28,7 +28,7 @@ fn deinit(pragma: *Pragma, comp: *Compilation) void {
2828
29fn preprocessorHandler(_: *Pragma, pp: *Preprocessor, start_idx: TokenIndex) Pragma.Error!void {29fn preprocessorHandler(_: *Pragma, pp: *Preprocessor, start_idx: TokenIndex) Pragma.Error!void {
30 const message_tok = pp.tokens.get(start_idx);30 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
33 const str = Pragma.pasteTokens(pp, start_idx + 1) catch |err| switch (err) {33 const str = Pragma.pasteTokens(pp, start_idx + 1) catch |err| switch (err) {
34 error.ExpectedStringLiteral => {34 error.ExpectedStringLiteral => {
lib/compiler/aro/aro/pragmas/once.zig+1-1
...@@ -45,7 +45,7 @@ fn preprocessorHandler(pragma: *Pragma, pp: *Preprocessor, start_idx: TokenIndex...@@ -45,7 +45,7 @@ fn preprocessorHandler(pragma: *Pragma, pp: *Preprocessor, start_idx: TokenIndex
45 try pp.comp.addDiagnostic(.{45 try pp.comp.addDiagnostic(.{
46 .tag = .extra_tokens_directive_end,46 .tag = .extra_tokens_directive_end,
47 .loc = name_tok.loc,47 .loc = name_tok.loc,
48 }, next.expansionSlice());48 }, pp.expansionSlice(start_idx + 1));
49 }49 }
50 const seen = self.preprocess_count == pp.preprocess_count;50 const seen = self.preprocess_count == pp.preprocess_count;
51 const prev = try self.pragma_once.fetchPut(name_tok.loc.id, {});51 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...@@ -37,7 +37,7 @@ fn parserHandler(pragma: *Pragma, p: *Parser, start_idx: TokenIndex) Compilation
37 return p.comp.addDiagnostic(.{37 return p.comp.addDiagnostic(.{
38 .tag = .pragma_pack_lparen,38 .tag = .pragma_pack_lparen,
39 .loc = l_paren.loc,39 .loc = l_paren.loc,
40 }, l_paren.expansionSlice());40 }, p.pp.expansionSlice(idx));
41 }41 }
42 idx += 1;42 idx += 1;
4343
lib/compiler/aro/aro/target.zig+10
...@@ -102,6 +102,16 @@ pub fn int16Type(target: std.Target) Type {...@@ -102,6 +102,16 @@ pub fn int16Type(target: std.Target) Type {
102 };102 };
103}103}
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
105/// int64_t for this target115/// int64_t for this target
106pub fn int64Type(target: std.Target) Type {116pub fn int64Type(target: std.Target) Type {
107 switch (target.cpu.arch) {117 switch (target.cpu.arch) {
lib/compiler/aro/aro/toolchains/Linux.zig+46-2
...@@ -373,6 +373,50 @@ fn getOSLibDir(target: std.Target) []const u8 {...@@ -373,6 +373,50 @@ fn getOSLibDir(target: std.Target) []const u8 {
373 return "lib64";373 return "lib64";
374}374}
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
376test Linux {420test Linux {
377 if (@import("builtin").os.tag == .windows) return error.SkipZigTest;421 if (@import("builtin").os.tag == .windows) return error.SkipZigTest;
378422
...@@ -388,8 +432,8 @@ test Linux {...@@ -388,8 +432,8 @@ test Linux {
388 defer comp.environment = .{};432 defer comp.environment = .{};
389433
390 const raw_triple = "x86_64-linux-gnu";434 const raw_triple = "x86_64-linux-gnu";
391 const cross = std.zig.CrossTarget.parse(.{ .arch_os_abi = raw_triple }) catch unreachable;435 const target_query = try std.Target.Query.parse(.{ .arch_os_abi = raw_triple });
392 comp.target = cross.toTarget(); // TODO deprecated436 comp.target = try std.zig.system.resolveTargetQuery(target_query);
393 comp.langopts.setEmulatedCompiler(.gcc);437 comp.langopts.setEmulatedCompiler(.gcc);
394438
395 var driver: Driver = .{ .comp = &comp };439 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 {...@@ -485,11 +485,11 @@ pub fn put(i: *Interner, gpa: Allocator, key: Key) !Ref {
485 .data = try i.addExtra(gpa, Tag.F64.pack(data)),485 .data = try i.addExtra(gpa, Tag.F64.pack(data)),
486 }),486 }),
487 .f80 => |data| i.items.appendAssumeCapacity(.{487 .f80 => |data| i.items.appendAssumeCapacity(.{
488 .tag = .f64,488 .tag = .f80,
489 .data = try i.addExtra(gpa, Tag.F80.pack(data)),489 .data = try i.addExtra(gpa, Tag.F80.pack(data)),
490 }),490 }),
491 .f128 => |data| i.items.appendAssumeCapacity(.{491 .f128 => |data| i.items.appendAssumeCapacity(.{
492 .tag = .f64,492 .tag = .f128,
493 .data = try i.addExtra(gpa, Tag.F128.pack(data)),493 .data = try i.addExtra(gpa, Tag.F128.pack(data)),
494 }),494 }),
495 },495 },
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)...@@ -649,7 +649,7 @@ fn writeValue(ir: Ir, val: Interner.Ref, config: std.io.tty.Config, w: anytype)
649 .float => |repr| switch (repr) {649 .float => |repr| switch (repr) {
650 inline else => |x| return w.print("{d}", .{@as(f64, @floatCast(x))}),650 inline else => |x| return w.print("{d}", .{@as(f64, @floatCast(x))}),
651 },651 },
652 .bytes => |b| return std.zig.fmt.stringEscape(b, "", .{}, w),652 .bytes => |b| return std.zig.stringEscape(b, "", .{}, w),
653 else => unreachable, // not a value653 else => unreachable, // not a value
654 }654 }
655}655}