authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-06-30 18:03:54-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-02 13:27:35-07:00
log3f680abbe2c4d2eeefd0eb73b8af25d1768e6ceb
tree06d67e5aa40cede2686d492445d4d32c2f69a33c
parent8ce880ca753ce95138bf03d956cf363ea2dfde5a

stage2: tokenizer: require null terminated source

By requiring the source file to be null-terminated, we avoid extra branching while simplifying the logic at the same time. Running ast-check on a large zig source file (udivmodti4_test.zig), master branch compared to this commit: * 4% faster wall clock * 7% fewer cache misses * 1% fewer branches

6 files changed, 56 insertions(+), 181 deletions(-)

lib/std/zig/ast.zig+1-1
...@@ -20,7 +20,7 @@ pub const NodeList = std.MultiArrayList(Node);...@@ -20,7 +20,7 @@ pub const NodeList = std.MultiArrayList(Node);
2020
21pub const Tree = struct {21pub const Tree = struct {
22 /// Reference to externally-owned data.22 /// Reference to externally-owned data.
23 source: []const u8,23 source: [:0]const u8,
2424
25 tokens: TokenList.Slice,25 tokens: TokenList.Slice,
26 /// The root AST node is assumed to be index 0. Since there can be no26 /// The root AST node is assumed to be index 0. Since there can be no
lib/std/zig/parse.zig+1-1
...@@ -17,7 +17,7 @@ pub const Error = error{ParseError} || Allocator.Error;...@@ -17,7 +17,7 @@ pub const Error = error{ParseError} || Allocator.Error;
1717
18/// Result should be freed with tree.deinit() when there are18/// Result should be freed with tree.deinit() when there are
19/// no more references to any of the tokens or nodes.19/// no more references to any of the tokens or nodes.
20pub fn parse(gpa: *Allocator, source: []const u8) Allocator.Error!Tree {20pub fn parse(gpa: *Allocator, source: [:0]const u8) Allocator.Error!Tree {
21 var tokens = ast.TokenList{};21 var tokens = ast.TokenList{};
22 defer tokens.deinit(gpa);22 defer tokens.deinit(gpa);
2323
lib/std/zig/parser_test.zig+4-4
...@@ -5194,7 +5194,7 @@ const maxInt = std.math.maxInt;...@@ -5194,7 +5194,7 @@ const maxInt = std.math.maxInt;
51945194
5195var fixed_buffer_mem: [100 * 1024]u8 = undefined;5195var fixed_buffer_mem: [100 * 1024]u8 = undefined;
51965196
5197fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *bool) ![]u8 {5197fn testParse(source: [:0]const u8, allocator: *mem.Allocator, anything_changed: *bool) ![]u8 {
5198 const stderr = io.getStdErr().writer();5198 const stderr = io.getStdErr().writer();
51995199
5200 var tree = try std.zig.parse(allocator, source);5200 var tree = try std.zig.parse(allocator, source);
...@@ -5222,7 +5222,7 @@ fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *b...@@ -5222,7 +5222,7 @@ fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *b
5222 anything_changed.* = !mem.eql(u8, formatted, source);5222 anything_changed.* = !mem.eql(u8, formatted, source);
5223 return formatted;5223 return formatted;
5224}5224}
5225fn testTransform(source: []const u8, expected_source: []const u8) !void {5225fn testTransform(source: [:0]const u8, expected_source: []const u8) !void {
5226 const needed_alloc_count = x: {5226 const needed_alloc_count = x: {
5227 // Try it once with unlimited memory, make sure it works5227 // Try it once with unlimited memory, make sure it works
5228 var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);5228 var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
...@@ -5268,13 +5268,13 @@ fn testTransform(source: []const u8, expected_source: []const u8) !void {...@@ -5268,13 +5268,13 @@ fn testTransform(source: []const u8, expected_source: []const u8) !void {
5268 }5268 }
5269 }5269 }
5270}5270}
5271fn testCanonical(source: []const u8) !void {5271fn testCanonical(source: [:0]const u8) !void {
5272 return testTransform(source, source);5272 return testTransform(source, source);
5273}5273}
52745274
5275const Error = std.zig.ast.Error.Tag;5275const Error = std.zig.ast.Error.Tag;
52765276
5277fn testError(source: []const u8, expected_errors: []const Error) !void {5277fn testError(source: [:0]const u8, expected_errors: []const Error) !void {
5278 var tree = try std.zig.parse(std.testing.allocator, source);5278 var tree = try std.zig.parse(std.testing.allocator, source);
5279 defer tree.deinit(std.testing.allocator);5279 defer tree.deinit(std.testing.allocator);
52805280
lib/std/zig/tokenizer.zig+48-173
...@@ -326,7 +326,7 @@ pub const Token = struct {...@@ -326,7 +326,7 @@ pub const Token = struct {
326};326};
327327
328pub const Tokenizer = struct {328pub const Tokenizer = struct {
329 buffer: []const u8,329 buffer: [:0]const u8,
330 index: usize,330 index: usize,
331 pending_invalid_token: ?Token,331 pending_invalid_token: ?Token,
332332
...@@ -335,7 +335,7 @@ pub const Tokenizer = struct {...@@ -335,7 +335,7 @@ pub const Tokenizer = struct {
335 std.debug.warn("{s} \"{s}\"\n", .{ @tagName(token.tag), self.buffer[token.start..token.end] });335 std.debug.warn("{s} \"{s}\"\n", .{ @tagName(token.tag), self.buffer[token.start..token.end] });
336 }336 }
337337
338 pub fn init(buffer: []const u8) Tokenizer {338 pub fn init(buffer: [:0]const u8) Tokenizer {
339 // Skip the UTF-8 BOM if present339 // Skip the UTF-8 BOM if present
340 const src_start = if (mem.startsWith(u8, buffer, "\xEF\xBB\xBF")) 3 else @as(usize, 0);340 const src_start = if (mem.startsWith(u8, buffer, "\xEF\xBB\xBF")) 3 else @as(usize, 0);
341 return Tokenizer{341 return Tokenizer{
...@@ -373,7 +373,6 @@ pub const Tokenizer = struct {...@@ -373,7 +373,6 @@ pub const Tokenizer = struct {
373 line_comment,373 line_comment,
374 doc_comment_start,374 doc_comment_start,
375 doc_comment,375 doc_comment,
376 container_doc_comment,
377 zero,376 zero,
378 int_literal_dec,377 int_literal_dec,
379 int_literal_dec_no_underscore,378 int_literal_dec_no_underscore,
...@@ -407,10 +406,6 @@ pub const Tokenizer = struct {...@@ -407,10 +406,6 @@ pub const Tokenizer = struct {
407 saw_at_sign,406 saw_at_sign,
408 };407 };
409408
410 fn isIdentifierChar(char: u8) bool {
411 return std.ascii.isAlNum(char) or char == '_';
412 }
413
414 pub fn next(self: *Tokenizer) Token {409 pub fn next(self: *Tokenizer) Token {
415 if (self.pending_invalid_token) |token| {410 if (self.pending_invalid_token) |token| {
416 self.pending_invalid_token = null;411 self.pending_invalid_token = null;
...@@ -426,10 +421,11 @@ pub const Tokenizer = struct {...@@ -426,10 +421,11 @@ pub const Tokenizer = struct {
426 };421 };
427 var seen_escape_digits: usize = undefined;422 var seen_escape_digits: usize = undefined;
428 var remaining_code_units: usize = undefined;423 var remaining_code_units: usize = undefined;
429 while (self.index < self.buffer.len) : (self.index += 1) {424 while (true) : (self.index += 1) {
430 const c = self.buffer[self.index];425 const c = self.buffer[self.index];
431 switch (state) {426 switch (state) {
432 .start => switch (c) {427 .start => switch (c) {
428 0 => break,
433 ' ', '\n', '\t', '\r' => {429 ' ', '\n', '\t', '\r' => {
434 result.loc.start = self.index + 1;430 result.loc.start = self.index + 1;
435 },431 },
...@@ -705,18 +701,22 @@ pub const Tokenizer = struct {...@@ -705,18 +701,22 @@ pub const Tokenizer = struct {
705 self.index += 1;701 self.index += 1;
706 break;702 break;
707 },703 },
708 '\n', '\r' => break, // Look for this error later.704 0, '\n', '\r' => break, // Look for this error later.
709 else => self.checkLiteralCharacter(),705 else => self.checkLiteralCharacter(),
710 },706 },
711707
712 .string_literal_backslash => switch (c) {708 .string_literal_backslash => switch (c) {
713 '\n', '\r' => break, // Look for this error later.709 0, '\n', '\r' => break, // Look for this error later.
714 else => {710 else => {
715 state = .string_literal;711 state = .string_literal;
716 },712 },
717 },713 },
718714
719 .char_literal => switch (c) {715 .char_literal => switch (c) {
716 0 => {
717 result.tag = .invalid;
718 break;
719 },
720 '\\' => {720 '\\' => {
721 state = .char_literal_backslash;721 state = .char_literal_backslash;
722 },722 },
...@@ -742,7 +742,7 @@ pub const Tokenizer = struct {...@@ -742,7 +742,7 @@ pub const Tokenizer = struct {
742 },742 },
743743
744 .char_literal_backslash => switch (c) {744 .char_literal_backslash => switch (c) {
745 '\n' => {745 0, '\n' => {
746 result.tag = .invalid;746 result.tag = .invalid;
747 break;747 break;
748 },748 },
...@@ -834,6 +834,7 @@ pub const Tokenizer = struct {...@@ -834,6 +834,7 @@ pub const Tokenizer = struct {
834 },834 },
835835
836 .multiline_string_literal_line => switch (c) {836 .multiline_string_literal_line => switch (c) {
837 0 => break,
837 '\n' => {838 '\n' => {
838 self.index += 1;839 self.index += 1;
839 break;840 break;
...@@ -1025,12 +1026,13 @@ pub const Tokenizer = struct {...@@ -1025,12 +1026,13 @@ pub const Tokenizer = struct {
1025 },1026 },
1026 },1027 },
1027 .line_comment_start => switch (c) {1028 .line_comment_start => switch (c) {
1029 0 => break,
1028 '/' => {1030 '/' => {
1029 state = .doc_comment_start;1031 state = .doc_comment_start;
1030 },1032 },
1031 '!' => {1033 '!' => {
1032 result.tag = .container_doc_comment;1034 result.tag = .container_doc_comment;
1033 state = .container_doc_comment;1035 state = .doc_comment;
1034 },1036 },
1035 '\n' => {1037 '\n' => {
1036 state = .start;1038 state = .start;
...@@ -1046,7 +1048,7 @@ pub const Tokenizer = struct {...@@ -1046,7 +1048,7 @@ pub const Tokenizer = struct {
1046 '/' => {1048 '/' => {
1047 state = .line_comment;1049 state = .line_comment;
1048 },1050 },
1049 '\n' => {1051 0, '\n' => {
1050 result.tag = .doc_comment;1052 result.tag = .doc_comment;
1051 break;1053 break;
1052 },1054 },
...@@ -1061,6 +1063,7 @@ pub const Tokenizer = struct {...@@ -1061,6 +1063,7 @@ pub const Tokenizer = struct {
1061 },1063 },
1062 },1064 },
1063 .line_comment => switch (c) {1065 .line_comment => switch (c) {
1066 0 => break,
1064 '\n' => {1067 '\n' => {
1065 state = .start;1068 state = .start;
1066 result.loc.start = self.index + 1;1069 result.loc.start = self.index + 1;
...@@ -1068,8 +1071,8 @@ pub const Tokenizer = struct {...@@ -1068,8 +1071,8 @@ pub const Tokenizer = struct {
1068 '\t', '\r' => {},1071 '\t', '\r' => {},
1069 else => self.checkLiteralCharacter(),1072 else => self.checkLiteralCharacter(),
1070 },1073 },
1071 .doc_comment, .container_doc_comment => switch (c) {1074 .doc_comment => switch (c) {
1072 '\n' => break,1075 0, '\n' => break,
1073 '\t', '\r' => {},1076 '\t', '\r' => {},
1074 else => self.checkLiteralCharacter(),1077 else => self.checkLiteralCharacter(),
1075 },1078 },
...@@ -1088,12 +1091,11 @@ pub const Tokenizer = struct {...@@ -1088,12 +1091,11 @@ pub const Tokenizer = struct {
1088 self.index -= 1;1091 self.index -= 1;
1089 state = .int_literal_dec;1092 state = .int_literal_dec;
1090 },1093 },
1091 else => {1094 'a', 'c', 'd', 'f'...'n', 'p'...'w', 'y', 'z', 'A'...'D', 'F'...'Z' => {
1092 if (isIdentifierChar(c)) {1095 result.tag = .invalid;
1093 result.tag = .invalid;
1094 }
1095 break;1096 break;
1096 },1097 },
1098 else => break,
1097 },1099 },
1098 .int_literal_bin_no_underscore => switch (c) {1100 .int_literal_bin_no_underscore => switch (c) {
1099 '0'...'1' => {1101 '0'...'1' => {
...@@ -1109,12 +1111,11 @@ pub const Tokenizer = struct {...@@ -1109,12 +1111,11 @@ pub const Tokenizer = struct {
1109 state = .int_literal_bin_no_underscore;1111 state = .int_literal_bin_no_underscore;
1110 },1112 },
1111 '0'...'1' => {},1113 '0'...'1' => {},
1112 else => {1114 '2'...'9', 'a'...'z', 'A'...'Z' => {
1113 if (isIdentifierChar(c)) {1115 result.tag = .invalid;
1114 result.tag = .invalid;
1115 }
1116 break;1116 break;
1117 },1117 },
1118 else => break,
1118 },1119 },
1119 .int_literal_oct_no_underscore => switch (c) {1120 .int_literal_oct_no_underscore => switch (c) {
1120 '0'...'7' => {1121 '0'...'7' => {
...@@ -1130,12 +1131,11 @@ pub const Tokenizer = struct {...@@ -1130,12 +1131,11 @@ pub const Tokenizer = struct {
1130 state = .int_literal_oct_no_underscore;1131 state = .int_literal_oct_no_underscore;
1131 },1132 },
1132 '0'...'7' => {},1133 '0'...'7' => {},
1133 else => {1134 '8', '9', 'a'...'z', 'A'...'Z' => {
1134 if (isIdentifierChar(c)) {1135 result.tag = .invalid;
1135 result.tag = .invalid;
1136 }
1137 break;1136 break;
1138 },1137 },
1138 else => break,
1139 },1139 },
1140 .int_literal_dec_no_underscore => switch (c) {1140 .int_literal_dec_no_underscore => switch (c) {
1141 '0'...'9' => {1141 '0'...'9' => {
...@@ -1159,12 +1159,11 @@ pub const Tokenizer = struct {...@@ -1159,12 +1159,11 @@ pub const Tokenizer = struct {
1159 result.tag = .float_literal;1159 result.tag = .float_literal;
1160 },1160 },
1161 '0'...'9' => {},1161 '0'...'9' => {},
1162 else => {1162 'a'...'d', 'f'...'z', 'A'...'D', 'F'...'Z' => {
1163 if (isIdentifierChar(c)) {1163 result.tag = .invalid;
1164 result.tag = .invalid;
1165 }
1166 break;1164 break;
1167 },1165 },
1166 else => break,
1168 },1167 },
1169 .int_literal_hex_no_underscore => switch (c) {1168 .int_literal_hex_no_underscore => switch (c) {
1170 '0'...'9', 'a'...'f', 'A'...'F' => {1169 '0'...'9', 'a'...'f', 'A'...'F' => {
...@@ -1188,12 +1187,11 @@ pub const Tokenizer = struct {...@@ -1188,12 +1187,11 @@ pub const Tokenizer = struct {
1188 result.tag = .float_literal;1187 result.tag = .float_literal;
1189 },1188 },
1190 '0'...'9', 'a'...'f', 'A'...'F' => {},1189 '0'...'9', 'a'...'f', 'A'...'F' => {},
1191 else => {1190 'g'...'o', 'q'...'z', 'G'...'O', 'Q'...'Z' => {
1192 if (isIdentifierChar(c)) {1191 result.tag = .invalid;
1193 result.tag = .invalid;
1194 }
1195 break;1192 break;
1196 },1193 },
1194 else => break,
1197 },1195 },
1198 .num_dot_dec => switch (c) {1196 .num_dot_dec => switch (c) {
1199 '.' => {1197 '.' => {
...@@ -1206,12 +1204,11 @@ pub const Tokenizer = struct {...@@ -1206,12 +1204,11 @@ pub const Tokenizer = struct {
1206 result.tag = .float_literal;1204 result.tag = .float_literal;
1207 state = .float_fraction_dec;1205 state = .float_fraction_dec;
1208 },1206 },
1209 else => {1207 '_', 'a'...'z', 'A'...'Z' => {
1210 if (isIdentifierChar(c)) {1208 result.tag = .invalid;
1211 result.tag = .invalid;
1212 }
1213 break;1209 break;
1214 },1210 },
1211 else => break,
1215 },1212 },
1216 .num_dot_hex => switch (c) {1213 .num_dot_hex => switch (c) {
1217 '.' => {1214 '.' => {
...@@ -1224,12 +1221,11 @@ pub const Tokenizer = struct {...@@ -1224,12 +1221,11 @@ pub const Tokenizer = struct {
1224 result.tag = .float_literal;1221 result.tag = .float_literal;
1225 state = .float_fraction_hex;1222 state = .float_fraction_hex;
1226 },1223 },
1227 else => {1224 '_', 'g'...'z', 'G'...'Z' => {
1228 if (isIdentifierChar(c)) {1225 result.tag = .invalid;
1229 result.tag = .invalid;
1230 }
1231 break;1226 break;
1232 },1227 },
1228 else => break,
1233 },1229 },
1234 .float_fraction_dec_no_underscore => switch (c) {1230 .float_fraction_dec_no_underscore => switch (c) {
1235 '0'...'9' => {1231 '0'...'9' => {
...@@ -1248,12 +1244,11 @@ pub const Tokenizer = struct {...@@ -1248,12 +1244,11 @@ pub const Tokenizer = struct {
1248 state = .float_exponent_unsigned;1244 state = .float_exponent_unsigned;
1249 },1245 },
1250 '0'...'9' => {},1246 '0'...'9' => {},
1251 else => {1247 'a'...'d', 'f'...'z', 'A'...'D', 'F'...'Z' => {
1252 if (isIdentifierChar(c)) {1248 result.tag = .invalid;
1253 result.tag = .invalid;
1254 }
1255 break;1249 break;
1256 },1250 },
1251 else => break,
1257 },1252 },
1258 .float_fraction_hex_no_underscore => switch (c) {1253 .float_fraction_hex_no_underscore => switch (c) {
1259 '0'...'9', 'a'...'f', 'A'...'F' => {1254 '0'...'9', 'a'...'f', 'A'...'F' => {
...@@ -1272,12 +1267,11 @@ pub const Tokenizer = struct {...@@ -1272,12 +1267,11 @@ pub const Tokenizer = struct {
1272 state = .float_exponent_unsigned;1267 state = .float_exponent_unsigned;
1273 },1268 },
1274 '0'...'9', 'a'...'f', 'A'...'F' => {},1269 '0'...'9', 'a'...'f', 'A'...'F' => {},
1275 else => {1270 'g'...'o', 'q'...'z', 'G'...'O', 'Q'...'Z' => {
1276 if (isIdentifierChar(c)) {1271 result.tag = .invalid;
1277 result.tag = .invalid;
1278 }
1279 break;1272 break;
1280 },1273 },
1274 else => break,
1281 },1275 },
1282 .float_exponent_unsigned => switch (c) {1276 .float_exponent_unsigned => switch (c) {
1283 '+', '-' => {1277 '+', '-' => {
...@@ -1303,130 +1297,11 @@ pub const Tokenizer = struct {...@@ -1303,130 +1297,11 @@ pub const Tokenizer = struct {
1303 state = .float_exponent_num_no_underscore;1297 state = .float_exponent_num_no_underscore;
1304 },1298 },
1305 '0'...'9' => {},1299 '0'...'9' => {},
1306 else => {1300 'a'...'z', 'A'...'Z' => {
1307 if (isIdentifierChar(c)) {1301 result.tag = .invalid;
1308 result.tag = .invalid;
1309 }
1310 break;1302 break;
1311 },1303 },
1312 },1304 else => break,
1313 }
1314 } else if (self.index == self.buffer.len) {
1315 switch (state) {
1316 .start,
1317 .int_literal_dec,
1318 .int_literal_bin,
1319 .int_literal_oct,
1320 .int_literal_hex,
1321 .num_dot_dec,
1322 .num_dot_hex,
1323 .float_fraction_dec,
1324 .float_fraction_hex,
1325 .float_exponent_num,
1326 .string_literal, // find this error later
1327 .multiline_string_literal_line,
1328 .builtin,
1329 .line_comment,
1330 .line_comment_start,
1331 => {},
1332
1333 .identifier => {
1334 if (Token.getKeyword(self.buffer[result.loc.start..self.index])) |tag| {
1335 result.tag = tag;
1336 }
1337 },
1338 .doc_comment, .doc_comment_start => {
1339 result.tag = .doc_comment;
1340 },
1341 .container_doc_comment => {
1342 result.tag = .container_doc_comment;
1343 },
1344
1345 .int_literal_dec_no_underscore,
1346 .int_literal_bin_no_underscore,
1347 .int_literal_oct_no_underscore,
1348 .int_literal_hex_no_underscore,
1349 .float_fraction_dec_no_underscore,
1350 .float_fraction_hex_no_underscore,
1351 .float_exponent_num_no_underscore,
1352 .float_exponent_unsigned,
1353 .saw_at_sign,
1354 .backslash,
1355 .char_literal,
1356 .char_literal_backslash,
1357 .char_literal_hex_escape,
1358 .char_literal_unicode_escape_saw_u,
1359 .char_literal_unicode_escape,
1360 .char_literal_unicode_invalid,
1361 .char_literal_end,
1362 .char_literal_unicode,
1363 .string_literal_backslash,
1364 => {
1365 result.tag = .invalid;
1366 },
1367
1368 .equal => {
1369 result.tag = .equal;
1370 },
1371 .bang => {
1372 result.tag = .bang;
1373 },
1374 .minus => {
1375 result.tag = .minus;
1376 },
1377 .slash => {
1378 result.tag = .slash;
1379 },
1380 .zero => {
1381 result.tag = .integer_literal;
1382 },
1383 .ampersand => {
1384 result.tag = .ampersand;
1385 },
1386 .period => {
1387 result.tag = .period;
1388 },
1389 .period_2 => {
1390 result.tag = .ellipsis2;
1391 },
1392 .period_asterisk => {
1393 result.tag = .period_asterisk;
1394 },
1395 .pipe => {
1396 result.tag = .pipe;
1397 },
1398 .angle_bracket_angle_bracket_right => {
1399 result.tag = .angle_bracket_angle_bracket_right;
1400 },
1401 .angle_bracket_right => {
1402 result.tag = .angle_bracket_right;
1403 },
1404 .angle_bracket_angle_bracket_left => {
1405 result.tag = .angle_bracket_angle_bracket_left;
1406 },
1407 .angle_bracket_left => {
1408 result.tag = .angle_bracket_left;
1409 },
1410 .plus_percent => {
1411 result.tag = .plus_percent;
1412 },
1413 .plus => {
1414 result.tag = .plus;
1415 },
1416 .percent => {
1417 result.tag = .percent;
1418 },
1419 .caret => {
1420 result.tag = .caret;
1421 },
1422 .asterisk_percent => {
1423 result.tag = .asterisk_percent;
1424 },
1425 .asterisk => {
1426 result.tag = .asterisk;
1427 },
1428 .minus_percent => {
1429 result.tag = .minus_percent;
1430 },1305 },
1431 }1306 }
1432 }1307 }
src/Compilation.zig+1-1
...@@ -1541,7 +1541,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -1541,7 +1541,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
1541 }1541 }
1542 }1542 }
15431543
1544 if (comp.bin_file.options.use_stage1) {1544 if (comp.bin_file.options.use_stage1 and comp.bin_file.options.module != null) {
1545 try comp.work_queue.writeItem(.{ .stage1_module = {} });1545 try comp.work_queue.writeItem(.{ .stage1_module = {} });
1546 }1546 }
15471547
src/translate_c/ast.zig+1-1
...@@ -754,7 +754,7 @@ pub fn render(gpa: *Allocator, nodes: []const Node) !std.zig.ast.Tree {...@@ -754,7 +754,7 @@ pub fn render(gpa: *Allocator, nodes: []const Node) !std.zig.ast.Tree {
754 });754 });
755755
756 return std.zig.ast.Tree{756 return std.zig.ast.Tree{
757 .source = ctx.buf.toOwnedSlice(),757 .source = try ctx.buf.toOwnedSliceSentinel(0),
758 .tokens = ctx.tokens.toOwnedSlice(),758 .tokens = ctx.tokens.toOwnedSlice(),
759 .nodes = ctx.nodes.toOwnedSlice(),759 .nodes = ctx.nodes.toOwnedSlice(),
760 .extra_data = ctx.extra_data.toOwnedSlice(gpa),760 .extra_data = ctx.extra_data.toOwnedSlice(gpa),