| author | |
| committer | |
| log | 90ab8ea9e681a4ffac0b4dc500e3ec489014e12f |
| tree | 5c6d1d6cd24fc5dfca968e11df234cb0db8e83bf |
| parent | 1e67f5021159ed1d9888cf2d0b9f04ef73222f7d |
| signature |
ref: 02353ad9f17f659e173f68975a442fcec3dd2c9426 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 |
| 12 | lib/libcxxabi/** linguist-vendored | 12 | lib/libcxxabi/** linguist-vendored |
| 13 | lib/libunwind/** linguist-vendored | 13 | lib/libunwind/** linguist-vendored |
| 14 | lib/tsan/** linguist-vendored | 14 | lib/tsan/** linguist-vendored |
| 15 | deps/** linguist-vendored | 15 | lib/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 hello | 23 | $ zig build && ./zig-out/bin/arocc hello.c -o hello |
| 24 | $ ./hello | 24 | $ ./hello |
| 25 | Hello, world! | 25 | Hello, 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 edit | 1 | //! Autogenerated by GenerateDef from src/aro/Attribute/names.def, do not edit |
| 2 | // zig fmt: off | 2 | // zig fmt: off |
| 3 | 3 | ||
| 4 | const std = @import("std"); | 4 | const 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 | } |
| 144 | 144 | ||
| 145 | /// We're 1 bit shy of being able to fit this in a u32: | 145 | const 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 | ||
| 153 | const Node = packed struct(u64) { | ||
| 154 | char: u8, | 146 | char: u8, |
| 155 | /// Nodes are numbered with "an integer which gives the number of words that | 147 | /// 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 numbering | 148 | /// 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 that | 152 | /// 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 | }; |
| 174 | 164 | ||
| 175 | const dafsa = [_]Node{ | 165 | const 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: __bf16 | 104 | // 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 edit | 1 | //! Autogenerated by GenerateDef from src/aro/Builtins/Builtin.def, do not edit |
| 2 | // zig fmt: off | 2 | // zig fmt: off |
| 3 | 3 | ||
| 4 | const std = @import("std"); | 4 | const 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 { |
| 241 | fn generateSystemDefines(comp: *Compilation, w: anytype) !void { | 241 | fn generateSystemDefines(comp: *Compilation, w: anytype) !void { |
| 242 | const ptr_width = comp.target.ptrBitWidth(); | 242 | const ptr_width = comp.target.ptrBitWidth(); |
| 243 | 243 | ||
| 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 macros | 250 | // 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 | ); |
| 421 | 427 | ||
| 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 | // types | 447 | // 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)); | ||
| 441 | 467 | ||
| 442 | // int widths | 468 | // 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); | ||
| 477 | 505 | ||
| 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 |
| 518 | 546 | ||
| 519 | // standard macros | 547 | // standard macros |
| 520 | try buf.appendSlice( | 548 | try buf.appendSlice( |
| 521 | \\#define __STDC_NO_ATOMICS__ 1 | ||
| 522 | \\#define __STDC_NO_COMPLEX__ 1 | 549 | \\#define __STDC_NO_COMPLEX__ 1 |
| 523 | \\#define __STDC_NO_THREADS__ 1 | 550 | \\#define __STDC_NO_THREADS__ 1 |
| 524 | \\#define __STDC_NO_VLA__ 1 | 551 | \\#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 | } |
| 1032 | 1059 | ||
| 1033 | pub 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); | 1061 | pub 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 | } | ||
| 1047 | 1074 | ||
| 1048 | if (comp.target.os.tag == .linux) { | 1075 | pub 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); |
| 1051 | 1078 | 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 | } |
| 1065 | 1080 | ||
| 1066 | pub fn getSource(comp: *const Compilation, id: Source.Id) Source { | 1081 | pub 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_next | 1346 | /// __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 | }; |
| 212 | 214 | ||
| 213 | const Diagnostics = @This(); | 215 | const 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 edit | 1 | //! Autogenerated by GenerateDef from src/aro/Diagnostics/messages.def, do not edit |
| 2 | // zig fmt: off | 2 | // zig fmt: off |
| 3 | 3 | ||
| 4 | const std = @import("std"); | 4 | const 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, | ||
| 507 | 512 | ||
| 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"); |
| 12 | const Source = @import("Source.zig"); | 12 | const Source = @import("Source.zig"); |
| 13 | const Toolchain = @import("Toolchain.zig"); | 13 | const Toolchain = @import("Toolchain.zig"); |
| 14 | const target_util = @import("target.zig"); | 14 | const target_util = @import("target.zig"); |
| 15 | const GCCVersion = @import("Driver/GCCVersion.zig"); | ||
| 15 | 16 | ||
| 16 | pub const Linker = enum { | 17 | pub const Linker = enum { |
| 17 | ld, | 18 | ld, |
| ... | @@ -43,6 +44,9 @@ verbose_pp: bool = false, | ... | @@ -43,6 +44,9 @@ verbose_pp: bool = false, |
| 43 | verbose_ir: bool = false, | 44 | verbose_ir: bool = false, |
| 44 | verbose_linker_args: bool = false, | 45 | verbose_linker_args: bool = false, |
| 45 | color: ?bool = null, | 46 | color: ?bool = null, |
| 47 | nobuiltininc: bool = false, | ||
| 48 | nostdinc: bool = false, | ||
| 49 | nostdlibinc: bool = false, | ||
| 46 | 50 | ||
| 47 | /// Full path to the aro executable | 51 | /// Full path to the aro executable |
| 48 | aro_name: []const u8 = "", | 52 | aro_name: []const u8 = "", |
| ... | @@ -95,6 +99,7 @@ pub const usage = | ... | @@ -95,6 +99,7 @@ pub const usage = |
| 95 | \\ -fcolor-diagnostics Enable colors in diagnostics | 99 | \\ -fcolor-diagnostics Enable colors in diagnostics |
| 96 | \\ -fno-color-diagnostics Disable colors in diagnostics | 100 | \\ -fno-color-diagnostics Disable colors in diagnostics |
| 97 | \\ -fdeclspec Enable support for __declspec attributes | 101 | \\ -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 attributes | 103 | \\ -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 arithmetic | 105 | \\ 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 path | 132 | \\ -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 mode | 140 | \\ -P, --no-line-commands Disable linemarker output in -E mode |
| 132 | \\ -pedantic Warn on language extensions | 141 | \\ -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 | } |
| 464 | 489 | ||
| ... | @@ -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 | }; |
| 560 | 585 | ||
| 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.** |
| 765 | pub fn invokeLinker(d: *Driver, tc: *Toolchain, comptime fast_exit: bool) !void { | 791 | pub 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(); |
| 770 | 794 |
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 | } |
| 100 | 100 | ||
| 101 | /// Used for determining __GNUC__ macro values | ||
| 102 | /// This matches clang's logic for overflowing values | ||
| 103 | pub 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 | |||
| 101 | test parse { | 111 | test 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 | |||
| 10 | const std = @import("std"); | ||
| 11 | const mem = std.mem; | ||
| 12 | const Allocator = mem.Allocator; | ||
| 13 | const Source = @import("Source.zig"); | ||
| 14 | const Compilation = @import("Compilation.zig"); | ||
| 15 | const Tokenizer = @import("Tokenizer.zig"); | ||
| 16 | |||
| 17 | pub const Hideset = @This(); | ||
| 18 | |||
| 19 | const 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 | |||
| 42 | const Item = struct { | ||
| 43 | identifier: Identifier = .{}, | ||
| 44 | next: Index = .none, | ||
| 45 | |||
| 46 | const List = std.MultiArrayList(Item); | ||
| 47 | }; | ||
| 48 | |||
| 49 | const Index = enum(u32) { | ||
| 50 | none = std.math.maxInt(u32), | ||
| 51 | _, | ||
| 52 | }; | ||
| 53 | |||
| 54 | map: 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 | ||
| 57 | intersection_map: std.AutoHashMapUnmanaged(Identifier, void) = .{}, | ||
| 58 | linked_list: Item.List = .{}, | ||
| 59 | comp: *const Compilation, | ||
| 60 | |||
| 61 | /// Invalidated if the underlying MultiArrayList slice is reallocated due to resize | ||
| 62 | const 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 | |||
| 73 | pub 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 | |||
| 79 | pub fn clearRetainingCapacity(self: *Hideset) void { | ||
| 80 | self.linked_list.shrinkRetainingCapacity(0); | ||
| 81 | self.map.clearRetainingCapacity(); | ||
| 82 | } | ||
| 83 | |||
| 84 | pub 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 | ||
| 91 | fn iterator(self: *const Hideset, idx: Index) Iterator { | ||
| 92 | return Iterator{ | ||
| 93 | .slice = self.linked_list.slice(), | ||
| 94 | .i = idx, | ||
| 95 | }; | ||
| 96 | } | ||
| 97 | |||
| 98 | pub fn get(self: *const Hideset, loc: Source.Location) Index { | ||
| 99 | return self.map.get(Identifier.fromLocation(loc)) orelse .none; | ||
| 100 | } | ||
| 101 | |||
| 102 | pub fn put(self: *Hideset, loc: Source.Location, value: Index) !void { | ||
| 103 | try self.map.put(self.comp.gpa, Identifier.fromLocation(loc), value); | ||
| 104 | } | ||
| 105 | |||
| 106 | fn 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` | ||
| 111 | fn 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` | ||
| 118 | pub 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 | ||
| 125 | pub 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 | |||
| 146 | pub 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 | |||
| 154 | fn 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 | |||
| 164 | pub 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 preprocessing | 135 | /// Preserve comments in macros when preprocessing |
| 136 | preserve_comments_in_macros: bool = false, | 136 | preserve_comments_in_macros: bool = false, |
| 137 | 137 | ||
| 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 | ||
| 141 | gnuc_version: u32 = 0, | ||
| 142 | |||
| 138 | pub fn setStandard(self: *LangOpts, name: []const u8) error{InvalidStandard}!void { | 143 | pub 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 | } |
| 408 | 408 | ||
| 409 | pub fn errTok(p: *Parser, tag: Diagnostics.Tag, tok_i: TokenIndex) Compilation.Error!void { | 409 | pub 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 | } |
| 433 | 433 | ||
| 434 | pub fn typeStr(p: *Parser, ty: Type) ![]const u8 { | 434 | pub 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 | } |
| 447 | 452 | ||
| 448 | pub fn typePairStrExtra(p: *Parser, a: Type, msg: []const u8, b: Type) ![]const u8 { | 453 | pub 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; |
| 451 | 461 | ||
| ... | @@ -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); |
| 637 | 647 | ||
| 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 | } |
| 662 | 669 | ||
| 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; |
| 2561 | 2575 | ||
| 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 | ||
| 2563 | 2578 | ||
| 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 | } |
| 4801 | 4827 | ||
| 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; |
| 4804 | 4831 | ||
| 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").?, |
| 4827 | 4859 | Builtin.tagFromName("__c11_atomic_signal_fence").?, | |
| 4860 | Builtin.tagFromName("__c11_atomic_is_lock_free").?, | ||
| 4861 | => 1, | ||
| 4862 | |||
| 4863 | Builtin.tagFromName("__builtin_complex").?, | ||
| 4864 | Builtin.tagFromName("__c11_atomic_load").?, | ||
| 4865 | Builtin.tagFromName("__c11_atomic_init").?, | ||
| 4866 | => 2, | ||
| 4867 | |||
| 4868 | Builtin.tagFromName("__c11_atomic_store").?, | ||
| 4869 | Builtin.tagFromName("__c11_atomic_exchange").?, | ||
| 4870 | Builtin.tagFromName("__c11_atomic_fetch_add").?, | ||
| 4871 | Builtin.tagFromName("__c11_atomic_fetch_sub").?, | ||
| 4872 | Builtin.tagFromName("__c11_atomic_fetch_or").?, | ||
| 4873 | Builtin.tagFromName("__c11_atomic_fetch_xor").?, | ||
| 4874 | Builtin.tagFromName("__c11_atomic_fetch_and").?, | ||
| 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, |
| 4835 | 4891 | ||
| 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 error | 4945 | 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); |
| 6357 | 6460 | ||
| 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 { |
| 6420 | 6532 | ||
| 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)); |
| 6828 | 6942 | ||
| 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 | } |
| 7336 | 7452 | ||
| 7453 | fn 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 | |||
| 7337 | fn checkComplexArg(p: *Parser, builtin_tok: TokenIndex, first_after: TokenIndex, param_tok: TokenIndex, arg: *Result, idx: u32) !void { | 7467 | fn 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 { |
| 7880 | 8010 | ||
| 7881 | const slice = char_kind.contentSlice(p.tokSlice(p.tok_i)); | 8011 | const slice = char_kind.contentSlice(p.tokSlice(p.tok_i)); |
| 7882 | 8012 | ||
| 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 char | 8015 | // 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 | }; |
| 7915 | 8046 | ||
| 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 | else | 8087 | else |
| 7957 | p.comp.types.intmax; | 8088 | p.comp.types.intmax; |
| 7958 | 8089 | ||
| 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"); |
| 9 | const RawToken = Tokenizer.Token; | 9 | const RawToken = Tokenizer.Token; |
| 10 | const Parser = @import("Parser.zig"); | 10 | const Parser = @import("Parser.zig"); |
| 11 | const Diagnostics = @import("Diagnostics.zig"); | 11 | const Diagnostics = @import("Diagnostics.zig"); |
| 12 | const Token = @import("Tree.zig").Token; | 12 | const Tree = @import("Tree.zig"); |
| 13 | const Token = Tree.Token; | ||
| 14 | const TokenWithExpansionLocs = Tree.TokenWithExpansionLocs; | ||
| 13 | const Attribute = @import("Attribute.zig"); | 15 | const Attribute = @import("Attribute.zig"); |
| 14 | const features = @import("features.zig"); | 16 | const features = @import("features.zig"); |
| 17 | const Hideset = @import("Hideset.zig"); | ||
| 15 | 18 | ||
| 16 | const DefineMap = std.StringHashMapUnmanaged(Macro); | 19 | const DefineMap = std.StringHashMapUnmanaged(Macro); |
| 17 | const RawTokenList = std.ArrayList(RawToken); | 20 | const RawTokenList = std.ArrayList(RawToken); |
| ... | @@ -40,8 +43,6 @@ const Macro = struct { | ... | @@ -40,8 +43,6 @@ const Macro = struct { |
| 40 | 43 | ||
| 41 | /// Location of macro in the source | 44 | /// Location of macro in the source |
| 42 | loc: Source.Location, | 45 | loc: Source.Location, |
| 43 | start: u32, | ||
| 44 | end: u32, | ||
| 45 | 46 | ||
| 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 { |
| 64 | 65 | ||
| 65 | const Preprocessor = @This(); | 66 | const Preprocessor = @This(); |
| 66 | 67 | ||
| 68 | const ExpansionEntry = struct { | ||
| 69 | idx: Tree.TokenIndex, | ||
| 70 | locs: [*]Source.Location, | ||
| 71 | }; | ||
| 72 | |||
| 73 | const TokenState = struct { | ||
| 74 | tokens_len: usize, | ||
| 75 | expansion_entries_len: usize, | ||
| 76 | }; | ||
| 77 | |||
| 67 | comp: *Compilation, | 78 | comp: *Compilation, |
| 68 | gpa: mem.Allocator, | 79 | gpa: mem.Allocator, |
| 69 | arena: std.heap.ArenaAllocator, | 80 | arena: std.heap.ArenaAllocator, |
| 70 | defines: DefineMap = .{}, | 81 | defines: DefineMap = .{}, |
| 82 | /// Do not directly mutate this; use addToken / addTokenAssumeCapacity / ensureTotalTokenCapacity / ensureUnusedTokenCapacity | ||
| 71 | tokens: Token.List = .{}, | 83 | tokens: Token.List = .{}, |
| 84 | /// Do not directly mutate this; must be kept in sync with `tokens` | ||
| 85 | expansion_entries: std.MultiArrayList(ExpansionEntry) = .{}, | ||
| 72 | token_buf: RawTokenList, | 86 | token_buf: RawTokenList, |
| 73 | char_buf: std.ArrayList(u8), | 87 | char_buf: std.ArrayList(u8), |
| 74 | /// Counter that is incremented each time preprocess() is called | 88 | /// 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) |
| 94 | linemarkers: Linemarkers = .none, | 108 | linemarkers: Linemarkers = .none, |
| 95 | 109 | ||
| 110 | hideset: Hideset, | ||
| 111 | |||
| 96 | pub const parse = Parser.parse; | 112 | pub const parse = Parser.parse; |
| 97 | 113 | ||
| 98 | pub const Linemarkers = enum { | 114 | pub 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 { |
| 228 | 243 | ||
| 229 | pub fn deinit(pp: *Preprocessor) void { | 244 | pub 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 | ||
| 259 | fn 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 | |||
| 266 | pub 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 | } |
| 240 | 281 | ||
| 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 | } |
| 254 | 296 | ||
| 255 | /// Preprocess a source file, returns eof token. | 297 | /// Preprocess a source file, returns eof token. |
| 256 | pub fn preprocess(pp: *Preprocessor, source: Source) Error!Token { | 298 | pub 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 { |
| 275 | 317 | ||
| 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); |
| 279 | 321 | ||
| 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 | } |
| 286 | 328 | ||
| 287 | pub fn addIncludeStart(pp: *Preprocessor, source: Source) !void { | 329 | pub 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 | } |
| 295 | 337 | ||
| 296 | pub fn addIncludeResume(pp: *Preprocessor, source: Source.Id, offset: u32, line: u32) !void { | 338 | pub 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 | } |
| 330 | 372 | ||
| 331 | fn preprocessExtra(pp: *Preprocessor, source: Source) MacroError!Token { | 373 | fn preprocessExtra(pp: *Preprocessor, source: Source) MacroError!TokenWithExpansionLocs { |
| 332 | var guard_name = pp.findIncludeGuard(source); | 374 | var guard_name = pp.findIncludeGuard(source); |
| 333 | 375 | ||
| 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 { |
| 340 | 382 | ||
| 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); |
| 344 | 386 | ||
| 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 { |
| 696 | 738 | ||
| 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. |
| 699 | pub fn tokSlice(pp: *Preprocessor, token: RawToken) []const u8 { | 741 | pub 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 | } |
| 704 | 746 | ||
| 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. |
| 706 | fn tokFromRaw(raw: RawToken) Token { | 748 | fn 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 | } |
| 727 | 769 | ||
| 728 | fn errStr(pp: *Preprocessor, tok: Token, tag: Diagnostics.Tag, str: []const u8) !void { | 770 | fn 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 | } |
| 749 | 791 | ||
| 750 | fn fatalNotFound(pp: *Preprocessor, tok: Token, filename: []const u8) Compilation.Error { | 792 | fn 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 | } |
| 800 | 842 | ||
| 843 | fn getTokenState(pp: *const Preprocessor) TokenState { | ||
| 844 | return .{ | ||
| 845 | .tokens_len = pp.tokens.len, | ||
| 846 | .expansion_entries_len = pp.expansion_entries.len, | ||
| 847 | }; | ||
| 848 | } | ||
| 849 | |||
| 850 | fn 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. |
| 802 | fn expr(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!bool { | 856 | fn 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 | } |
| 808 | 862 | ||
| 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 | } |
| 837 | 892 | ||
| 838 | // validate the tokens in the expression | 893 | // 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 { |
| 941 | 996 | ||
| 942 | /// Turns macro_tok from .keyword_defined into .zero or .one depending on whether the argument is defined | 997 | /// Turns macro_tok from .keyword_defined into .zero or .one depending on whether the argument is defined |
| 943 | /// Returns the number of tokens consumed | 998 | /// Returns the number of tokens consumed |
| 944 | fn handleKeywordDefined(pp: *Preprocessor, macro_tok: *Token, tokens: []const Token, eof: RawToken) !usize { | 999 | fn 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 | } |
| 1081 | 1136 | ||
| 1082 | const ExpandBuf = std.ArrayList(Token); | 1137 | const ExpandBuf = std.ArrayList(TokenWithExpansionLocs); |
| 1083 | fn removePlacemarkers(buf: *ExpandBuf) void { | 1138 | fn 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 | } |
| 1092 | 1147 | ||
| 1093 | const MacroArguments = std.ArrayList([]const Token); | 1148 | const MacroArguments = std.ArrayList([]const TokenWithExpansionLocs); |
| 1094 | fn deinitMacroArguments(allocator: Allocator, args: *const MacroArguments) void { | 1149 | fn 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 |
| 1102 | fn expandObjMacro(pp: *Preprocessor, simple_macro: *const Macro) Error!ExpandBuf { | 1157 | fn 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); |
| 1106 | 1165 | ||
| 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-literal | 1220 | /// Returns error.ExpectedStringLiteral if parentheses are not balanced, a non-string-literal |
| 1162 | /// is encountered, or if no string literals are encountered | 1221 | /// 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 '"') |
| 1164 | fn pasteStringsUnsafe(pp: *Preprocessor, toks: []const Token) ![]const u8 { | 1223 | fn 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 | } |
| 1181 | 1240 | ||
| 1182 | /// Handle the _Pragma operator (implemented as a builtin macro) | 1241 | /// Handle the _Pragma operator (implemented as a builtin macro) |
| 1183 | fn pragmaOperator(pp: *Preprocessor, arg_tok: Token, operator_loc: Source.Location) !void { | 1242 | fn 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 { |
| 1234 | 1293 | ||
| 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#Stringizing | 1295 | /// See https://gcc.gnu.org/onlinedocs/gcc-11.2.0/cpp/Stringizing.html#Stringizing |
| 1237 | fn stringify(pp: *Preprocessor, tokens: []const Token) !void { | 1296 | fn 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 | } |
| 1283 | 1342 | ||
| 1284 | fn reconstructIncludeString(pp: *Preprocessor, param_toks: []const Token, embed_args: ?*[]const Token) !?[]const u8 { | 1343 | fn 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; |
| 1287 | 1347 | ||
| ... | @@ -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 pasting | 1362 | // 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_ |
| 1321 | 1381 | ||
| 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 | } |
| 1358 | 1425 | ||
| 1359 | fn handleBuiltinMacro(pp: *Preprocessor, builtin: RawToken.Id, param_toks: []const Token, src_loc: Source.Location) Error!bool { | 1426 | fn 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 | } |
| 1462 | 1529 | ||
| 1530 | /// Treat whitespace-only paste arguments as empty | ||
| 1531 | fn 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 | |||
| 1463 | fn expandFuncMacro( | 1541 | fn 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 | continue | 1586 | continue |
| 1509 | else | 1587 | 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 | }; |
| 1523 | 1598 | ||
| 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)) orelse | 1739 | const include_str = (try pp.reconstructIncludeString(arg, &embed_args, arg[0])) orelse |
| 1668 | break :res not_found; | 1740 | break :res not_found; |
| 1669 | 1741 | ||
| 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 | }; |
| 1733 | 1805 | ||
| 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 more | 1866 | // 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 | } |
| 1886 | 1958 | ||
| 1887 | fn shouldExpand(tok: Token, macro: *Macro) bool { | 1959 | fn 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 | |||
| 1903 | fn 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 | } |
| 2039 | 2097 | ||
| 2040 | fn removeExpandedTokens(pp: *Preprocessor, buf: *ExpandBuf, start: usize, len: usize, moving_end_idx: *usize) !void { | 2098 | fn 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 { |
| 2054 | 2112 | ||
| 2055 | /// Helper for safely iterating over a slice of tokens while skipping whitespace | 2113 | /// Helper for safely iterating over a slice of tokens while skipping whitespace |
| 2056 | const TokenIterator = struct { | 2114 | const TokenIterator = struct { |
| 2057 | toks: []const Token, | 2115 | toks: []const TokenWithExpansionLocs, |
| 2058 | i: usize, | 2116 | i: usize, |
| 2059 | 2117 | ||
| 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 | } |
| 2063 | 2121 | ||
| 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 call | 2188 | // 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); | ||
| 2146 | 2220 | ||
| 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 1 | 2222 | // 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 | } |
| 2203 | 2280 | ||
| 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); |
| 2207 | 2284 | ||
| 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(); |
| 2217 | 2294 | ||
| 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 | } |
| 2235 | 2319 | ||
| 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( |
| 2249 | 2333 | ||
| 2250 | // trim excess buffer | 2334 | // 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; |
| 2268 | 2352 | ||
| 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 | } |
| 2293 | 2382 | ||
| 2294 | fn expandedSliceExtra(pp: *const Preprocessor, tok: Token, macro_ws_handling: enum { single_macro_ws, preserve_macro_ws }) []const u8 { | 2383 | fn 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 | } |
| 2313 | 2402 | ||
| 2314 | /// Get expanded token source string. | 2403 | /// Get expanded token source string. |
| 2315 | pub fn expandedSlice(pp: *Preprocessor, tok: Token) []const u8 { | 2404 | pub 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 | } |
| 2318 | 2407 | ||
| 2319 | /// Concat two tokens and add the result to pp.generated | 2408 | /// Concat two tokens and add the result to pp.generated |
| 2320 | fn pasteTokens(pp: *Preprocessor, lhs_toks: *ExpandBuf, rhs_toks: []const Token) Error!void { | 2409 | fn 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) or | 2411 | 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; |
| 2325 | 2414 | ||
| 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); |
| 2342 | 2431 | ||
| 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 | } |
| 2377 | 2466 | ||
| 2378 | fn makeGeneratedToken(pp: *Preprocessor, start: usize, id: Token.Id, source: Token) !Token { | 2467 | fn 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 | } |
| 2506 | 2593 | ||
| 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 | } |
| 2567 | 2652 | ||
| 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 | } |
| 2694 | 2779 | ||
| 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 | } |
| 2707 | 2790 | ||
| ... | @@ -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); |
| 2718 | 2801 | ||
| 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 | } |
| 2861 | 2944 | ||
| 2862 | try pp.tokens.ensureUnusedCapacity(pp.comp.gpa, 2 * embed_bytes.len - 1); // N bytes and N-1 commas | 2945 | try pp.ensureUnusedTokenCapacity(2 * embed_bytes.len - 1); // N bytes and N-1 commas |
| 2863 | 2946 | ||
| 2864 | // TODO: We currently only support systems with CHAR_BIT == 8 | 2947 | // 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_bytes | 2948 | // 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 | } |
| 2875 | 2958 | ||
| 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'); |
| 2883 | 2966 | ||
| ... | @@ -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 | } |
| 2913 | 2996 | ||
| 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 #pragma | 3029 | /// 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 used | 3030 | /// arg_locs: expansion locations of the argument to _Pragma. empty if #pragma or a raw string literal was used |
| 2948 | fn makePragmaToken(pp: *Preprocessor, raw: RawToken, operator_loc: ?Source.Location, arg_locs: []const Source.Location) !Token { | 3031 | fn 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 | } |
| 2956 | 3039 | ||
| 3040 | pub 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 | |||
| 3047 | pub 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 | |||
| 3054 | pub 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 | |||
| 3059 | pub 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 directive | 3064 | /// Handle a pragma directive |
| 2958 | fn pragma(pp: *Preprocessor, tokenizer: *Tokenizer, pragma_tok: RawToken, operator_loc: ?Source.Location, arg_locs: []const Source.Location) !void { | 3065 | fn 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; |
| 2961 | 3068 | ||
| 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); |
| 2965 | 3072 | ||
| 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; |
| 3000 | 3107 | ||
| 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; |
| 3031 | 3138 | ||
| 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( |
| 3071 | 3177 | ||
| 3072 | fn findIncludeSource(pp: *Preprocessor, tokenizer: *Tokenizer, first: RawToken, which: Compilation.WhichInclude) !Source { | 3178 | fn 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); |
| 3075 | 3181 | ||
| 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 indexed | 3210 | 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); |
| 3221 | 3326 | ||
| 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" { |
| 3259 | 3364 | ||
| 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 | |||
| 491 | pub 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"); |
| 12 | 12 | ||
| 13 | pub const Token = struct { | 13 | pub 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 | |||
| 23 | pub 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, |
| 24 | 34 | ||
| 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 | } |
| 31 | 41 | ||
| 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 | } |
| 72 | 82 | ||
| 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 | } |
| 79 | 89 | ||
| 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 | }; |
| 99 | 104 | ||
| 100 | pub const TokenIndex = u32; | 105 | pub 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 qualifiers | 106 | // 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; | ||
| 108 | 109 | ||
| 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 this | 121 | // 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 | } |
| 1054 | 1057 | ||
| 1055 | pub fn alignable(ty: Type) bool { | 1058 | pub 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 | } |
| 1058 | 1061 | ||
| 1059 | /// Get the alignment of a type | 1062 | /// 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" { |
| 60 | 60 | ||
| 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); | ||
| 64 | 65 | ||
| 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" { |
| 94 | 95 | ||
| 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); | ||
| 98 | 100 | ||
| 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 | } |
| 226 | 228 | ||
| 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. |
| 229 | pub fn floatCast(v: *Value, dest_ty: Type, comp: *Compilation) !void { | 231 | pub 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)); |
| 120 | 120 | ||
| 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 { |
| 28 | 28 | ||
| 29 | fn preprocessorHandler(_: *Pragma, pp: *Preprocessor, start_idx: TokenIndex) Pragma.Error!void { | 29 | fn 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); |
| 32 | 32 | ||
| 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; |
| 43 | 43 |
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 | } |
| 104 | 104 | ||
| 105 | /// sig_atomic_t for this target | ||
| 106 | pub 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 target | 115 | /// int64_t for this target |
| 106 | pub fn int64Type(target: std.Target) Type { | 116 | pub 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 | } |
| 375 | 375 | ||
| 376 | pub 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 | |||
| 376 | test Linux { | 420 | test Linux { |
| 377 | if (@import("builtin").os.tag == .windows) return error.SkipZigTest; | 421 | if (@import("builtin").os.tag == .windows) return error.SkipZigTest; |
| 378 | 422 | ||
| ... | @@ -388,8 +432,8 @@ test Linux { | ... | @@ -388,8 +432,8 @@ test Linux { |
| 388 | defer comp.environment = .{}; | 432 | defer comp.environment = .{}; |
| 389 | 433 | ||
| 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 deprecated | 436 | comp.target = try std.zig.system.resolveTargetQuery(target_query); |
| 393 | comp.langopts.setEmulatedCompiler(.gcc); | 437 | comp.langopts.setEmulatedCompiler(.gcc); |
| 394 | 438 | ||
| 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 value | 653 | else => unreachable, // not a value |
| 654 | } | 654 | } |
| 655 | } | 655 | } |