@zigc/lib 0.16.0-test.1 → 0.17.0-dev.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (242) hide show
  1. package/LICENSE +19 -0
  2. package/c/math.zig +135 -35
  3. package/c/stropts.zig +17 -0
  4. package/c.zig +1 -0
  5. package/compiler/aro/aro/Attribute/names.zig +604 -589
  6. package/compiler/aro/aro/Attribute.zig +202 -116
  7. package/compiler/aro/aro/Builtins/common.zig +874 -863
  8. package/compiler/aro/aro/Builtins/eval.zig +15 -7
  9. package/compiler/aro/aro/Builtins.zig +0 -1
  10. package/compiler/aro/aro/CodeGen.zig +3 -1
  11. package/compiler/aro/aro/Compilation.zig +120 -97
  12. package/compiler/aro/aro/Diagnostics.zig +21 -17
  13. package/compiler/aro/aro/Driver/GCCDetector.zig +635 -0
  14. package/compiler/aro/aro/Driver.zig +124 -50
  15. package/compiler/aro/aro/LangOpts.zig +12 -2
  16. package/compiler/aro/aro/Parser/Diagnostic.zig +79 -19
  17. package/compiler/aro/aro/Parser.zig +336 -142
  18. package/compiler/aro/aro/Preprocessor/Diagnostic.zig +21 -0
  19. package/compiler/aro/aro/Preprocessor.zig +127 -56
  20. package/compiler/aro/aro/Target.zig +17 -12
  21. package/compiler/aro/aro/Tokenizer.zig +31 -14
  22. package/compiler/aro/aro/Toolchain.zig +4 -7
  23. package/compiler/aro/aro/Tree.zig +178 -148
  24. package/compiler/aro/aro/TypeStore.zig +82 -24
  25. package/compiler/aro/aro/Value.zig +13 -17
  26. package/compiler/aro/aro/features.zig +1 -0
  27. package/compiler/aro/aro/pragmas/once.zig +0 -1
  28. package/compiler/aro/aro/record_layout.zig +3 -3
  29. package/compiler/aro/assembly_backend/x86_64.zig +3 -4
  30. package/compiler/aro/backend/Assembly.zig +1 -2
  31. package/compiler/aro/backend/Interner.zig +2 -2
  32. package/compiler/aro/backend/Ir.zig +100 -92
  33. package/compiler/aro/include/ptrcheck.h +49 -0
  34. package/compiler/aro/main.zig +26 -10
  35. package/compiler/build_runner.zig +1 -0
  36. package/compiler/objdump.zig +93 -0
  37. package/compiler/reduce.zig +5 -1
  38. package/compiler/resinator/compile.zig +2 -2
  39. package/compiler/resinator/main.zig +7 -1
  40. package/compiler/resinator/preprocess.zig +1 -3
  41. package/compiler/std-docs.zig +8 -1
  42. package/compiler/test_runner.zig +193 -61
  43. package/compiler/translate-c/MacroTranslator.zig +80 -11
  44. package/compiler/translate-c/PatternList.zig +1 -9
  45. package/compiler/translate-c/Scope.zig +43 -6
  46. package/compiler/translate-c/Translator.zig +364 -126
  47. package/compiler/translate-c/ast.zig +19 -11
  48. package/compiler/translate-c/main.zig +75 -16
  49. package/compiler_rt/cos.zig +141 -52
  50. package/compiler_rt/limb64.zig +266 -0
  51. package/compiler_rt/long_double.zig +37 -0
  52. package/compiler_rt/mulo.zig +6 -1
  53. package/compiler_rt/rem_pio2l.zig +173 -0
  54. package/compiler_rt/sin.zig +140 -55
  55. package/compiler_rt/sincos.zig +279 -72
  56. package/compiler_rt/tan.zig +118 -47
  57. package/compiler_rt/trig.zig +256 -6
  58. package/compiler_rt.zig +2 -0
  59. package/fuzzer.zig +855 -307
  60. package/libc/musl/src/math/pow.c +343 -0
  61. package/package.json +1 -1
  62. package/std/Build/Fuzz.zig +6 -19
  63. package/std/Build/Module.zig +1 -1
  64. package/std/Build/Step/CheckObject.zig +3 -3
  65. package/std/Build/Step/Compile.zig +18 -0
  66. package/std/Build/Step/ConfigHeader.zig +49 -33
  67. package/std/Build/Step/InstallArtifact.zig +18 -0
  68. package/std/Build/Step/Run.zig +536 -87
  69. package/std/Build/Step/TranslateC.zig +0 -6
  70. package/std/Build/Step.zig +8 -15
  71. package/std/Build/WebServer.zig +29 -17
  72. package/std/Build/abi.zig +47 -11
  73. package/std/Build.zig +17 -14
  74. package/std/Io/Dispatch.zig +2 -0
  75. package/std/Io/File/Reader.zig +3 -1
  76. package/std/Io/File.zig +1 -0
  77. package/std/Io/Kqueue.zig +2 -2
  78. package/std/Io/Threaded.zig +181 -143
  79. package/std/Io/Uring.zig +2 -1
  80. package/std/Io.zig +970 -2
  81. package/std/Target.zig +3 -2
  82. package/std/Thread.zig +8 -3
  83. package/std/array_hash_map.zig +96 -555
  84. package/std/array_list.zig +22 -31
  85. package/std/bit_set.zig +22 -6
  86. package/std/builtin/assembly.zig +68 -0
  87. package/std/c.zig +17 -17
  88. package/std/compress/flate/Compress.zig +3 -3
  89. package/std/crypto/Certificate/Bundle.zig +15 -1
  90. package/std/crypto/codecs/asn1.zig +33 -18
  91. package/std/crypto/codecs/base64_hex_ct.zig +14 -4
  92. package/std/debug/Dwarf.zig +29 -9
  93. package/std/debug/Info.zig +4 -0
  94. package/std/debug/MachOFile.zig +46 -8
  95. package/std/debug/Pdb.zig +539 -36
  96. package/std/debug/SelfInfo/Elf.zig +19 -18
  97. package/std/debug/SelfInfo/MachO.zig +18 -7
  98. package/std/debug/SelfInfo/Windows.zig +138 -36
  99. package/std/debug.zig +179 -65
  100. package/std/enums.zig +25 -19
  101. package/std/heap/ArenaAllocator.zig +145 -154
  102. package/std/heap/debug_allocator.zig +7 -7
  103. package/std/http/Client.zig +10 -6
  104. package/std/http.zig +11 -9
  105. package/std/json/Stringify.zig +3 -3
  106. package/std/json/dynamic.zig +4 -4
  107. package/std/math/big/int.zig +16 -17
  108. package/std/mem/Allocator.zig +4 -5
  109. package/std/mem.zig +48 -0
  110. package/std/os/emscripten.zig +2 -18
  111. package/std/os/linux/arc.zig +144 -0
  112. package/std/os/linux.zig +21 -4
  113. package/std/os/windows.zig +2 -2
  114. package/std/pdb.zig +143 -4
  115. package/std/posix.zig +6 -12
  116. package/std/priority_dequeue.zig +13 -12
  117. package/std/priority_queue.zig +5 -4
  118. package/std/process/Child.zig +1 -1
  119. package/std/process/Environ.zig +1 -1
  120. package/std/start.zig +17 -4
  121. package/std/std.zig +19 -6
  122. package/std/testing/FailingAllocator.zig +4 -4
  123. package/std/testing/Smith.zig +37 -2
  124. package/std/zig/Ast/Render.zig +186 -458
  125. package/std/zig/Ast.zig +0 -4
  126. package/std/zig/AstGen.zig +44 -7
  127. package/std/zig/AstSmith.zig +2602 -0
  128. package/std/zig/Client.zig +8 -3
  129. package/std/zig/Parse.zig +83 -74
  130. package/std/zig/Server.zig +26 -0
  131. package/std/zig/Zir.zig +17 -0
  132. package/std/zig/c_translation/helpers.zig +14 -9
  133. package/std/zig/llvm/Builder.zig +107 -48
  134. package/std/zig/system.zig +20 -4
  135. package/std/zig/tokenizer.zig +2 -1
  136. package/std/zig.zig +6 -0
  137. package/compiler/aro/aro/Driver/Filesystem.zig +0 -241
  138. package/libc/mingw/complex/cabs.c +0 -48
  139. package/libc/mingw/complex/cabsf.c +0 -48
  140. package/libc/mingw/complex/cacos.c +0 -50
  141. package/libc/mingw/complex/cacosf.c +0 -50
  142. package/libc/mingw/complex/carg.c +0 -48
  143. package/libc/mingw/complex/cargf.c +0 -48
  144. package/libc/mingw/complex/casin.c +0 -50
  145. package/libc/mingw/complex/casinf.c +0 -50
  146. package/libc/mingw/complex/catan.c +0 -50
  147. package/libc/mingw/complex/catanf.c +0 -50
  148. package/libc/mingw/complex/ccos.c +0 -50
  149. package/libc/mingw/complex/ccosf.c +0 -50
  150. package/libc/mingw/complex/cexp.c +0 -48
  151. package/libc/mingw/complex/cexpf.c +0 -48
  152. package/libc/mingw/complex/cimag.c +0 -48
  153. package/libc/mingw/complex/cimagf.c +0 -48
  154. package/libc/mingw/complex/clog.c +0 -48
  155. package/libc/mingw/complex/clog10.c +0 -49
  156. package/libc/mingw/complex/clog10f.c +0 -49
  157. package/libc/mingw/complex/clogf.c +0 -48
  158. package/libc/mingw/complex/conj.c +0 -48
  159. package/libc/mingw/complex/conjf.c +0 -48
  160. package/libc/mingw/complex/cpow.c +0 -48
  161. package/libc/mingw/complex/cpowf.c +0 -48
  162. package/libc/mingw/complex/cproj.c +0 -48
  163. package/libc/mingw/complex/cprojf.c +0 -48
  164. package/libc/mingw/complex/creal.c +0 -48
  165. package/libc/mingw/complex/crealf.c +0 -48
  166. package/libc/mingw/complex/csin.c +0 -50
  167. package/libc/mingw/complex/csinf.c +0 -50
  168. package/libc/mingw/complex/csqrt.c +0 -48
  169. package/libc/mingw/complex/csqrtf.c +0 -48
  170. package/libc/mingw/complex/ctan.c +0 -50
  171. package/libc/mingw/complex/ctanf.c +0 -50
  172. package/libc/mingw/math/arm/s_rint.c +0 -86
  173. package/libc/mingw/math/arm/s_rintf.c +0 -51
  174. package/libc/mingw/math/arm/sincos.S +0 -30
  175. package/libc/mingw/math/arm-common/sincosl.c +0 -13
  176. package/libc/mingw/math/arm64/rint.c +0 -12
  177. package/libc/mingw/math/arm64/rintf.c +0 -12
  178. package/libc/mingw/math/arm64/sincos.S +0 -32
  179. package/libc/mingw/math/bsd_private_base.h +0 -148
  180. package/libc/mingw/math/frexpf.c +0 -13
  181. package/libc/mingw/math/frexpl.c +0 -71
  182. package/libc/mingw/math/x86/acosf.c +0 -29
  183. package/libc/mingw/math/x86/atanf.c +0 -23
  184. package/libc/mingw/math/x86/atanl.c +0 -18
  185. package/libc/mingw/math/x86/cos.def.h +0 -65
  186. package/libc/mingw/math/x86/cosl.c +0 -46
  187. package/libc/mingw/math/x86/cosl_internal.S +0 -55
  188. package/libc/mingw/math/x86/ldexp.c +0 -23
  189. package/libc/mingw/math/x86/scalbn.S +0 -41
  190. package/libc/mingw/math/x86/scalbnf.S +0 -40
  191. package/libc/mingw/math/x86/sin.def.h +0 -65
  192. package/libc/mingw/math/x86/sinl.c +0 -46
  193. package/libc/mingw/math/x86/sinl_internal.S +0 -58
  194. package/libc/mingw/math/x86/tanl.S +0 -62
  195. package/libc/mingw/misc/btowc.c +0 -28
  196. package/libc/mingw/misc/wcstof.c +0 -66
  197. package/libc/mingw/misc/wcstoimax.c +0 -132
  198. package/libc/mingw/misc/wcstoumax.c +0 -126
  199. package/libc/mingw/misc/wctob.c +0 -29
  200. package/libc/mingw/misc/winbs_uint64.c +0 -6
  201. package/libc/mingw/misc/winbs_ulong.c +0 -6
  202. package/libc/mingw/misc/winbs_ushort.c +0 -6
  203. package/libc/mingw/stdio/_Exit.c +0 -10
  204. package/libc/mingw/stdio/_findfirst64i32.c +0 -21
  205. package/libc/mingw/stdio/_findnext64i32.c +0 -21
  206. package/libc/mingw/stdio/_fstat64i32.c +0 -37
  207. package/libc/mingw/stdio/_stat64i32.c +0 -37
  208. package/libc/mingw/stdio/_wfindfirst64i32.c +0 -21
  209. package/libc/mingw/stdio/_wfindnext64i32.c +0 -21
  210. package/libc/mingw/stdio/_wstat64i32.c +0 -37
  211. package/libc/musl/src/legacy/isastream.c +0 -7
  212. package/libc/musl/src/legacy/valloc.c +0 -8
  213. package/libc/musl/src/math/__cosl.c +0 -96
  214. package/libc/musl/src/math/__sinl.c +0 -78
  215. package/libc/musl/src/math/__tanl.c +0 -143
  216. package/libc/musl/src/math/aarch64/lrint.c +0 -10
  217. package/libc/musl/src/math/aarch64/lrintf.c +0 -10
  218. package/libc/musl/src/math/aarch64/rintf.c +0 -7
  219. package/libc/musl/src/math/cosl.c +0 -39
  220. package/libc/musl/src/math/fdim.c +0 -10
  221. package/libc/musl/src/math/finite.c +0 -7
  222. package/libc/musl/src/math/finitef.c +0 -7
  223. package/libc/musl/src/math/frexp.c +0 -23
  224. package/libc/musl/src/math/frexpf.c +0 -23
  225. package/libc/musl/src/math/frexpl.c +0 -29
  226. package/libc/musl/src/math/i386/lrint.c +0 -8
  227. package/libc/musl/src/math/i386/lrintf.c +0 -8
  228. package/libc/musl/src/math/i386/rintf.c +0 -7
  229. package/libc/musl/src/math/lrint.c +0 -72
  230. package/libc/musl/src/math/lrintf.c +0 -8
  231. package/libc/musl/src/math/powerpc64/lrint.c +0 -16
  232. package/libc/musl/src/math/powerpc64/lrintf.c +0 -16
  233. package/libc/musl/src/math/rintf.c +0 -30
  234. package/libc/musl/src/math/s390x/rintf.c +0 -15
  235. package/libc/musl/src/math/sincosl.c +0 -60
  236. package/libc/musl/src/math/sinl.c +0 -41
  237. package/libc/musl/src/math/tanl.c +0 -29
  238. package/libc/musl/src/math/x32/lrint.s +0 -5
  239. package/libc/musl/src/math/x32/lrintf.s +0 -5
  240. package/libc/musl/src/math/x86_64/lrint.c +0 -8
  241. package/libc/musl/src/math/x86_64/lrintf.c +0 -8
  242. package/libc/wasi/libc-bottom-half/sources/reallocarray.c +0 -14
@@ -1,5 +1,4 @@
1
1
  const std = @import("std");
2
- const Io = std.Io;
3
2
  const mem = std.mem;
4
3
  const Allocator = mem.Allocator;
5
4
  const assert = std.debug.assert;
@@ -204,6 +203,11 @@ string_ids: struct {
204
203
  sigjmp_buf: StringId,
205
204
  ucontext_t: StringId,
206
205
  },
206
+ va_arg_pack_ctx: packed struct {
207
+ valid: bool = false,
208
+ variadic: bool = false,
209
+ typed: bool = false,
210
+ } = .{},
207
211
 
208
212
  /// Checks codepoint for various pedantic warnings
209
213
  /// Returns true if diagnostic issued
@@ -212,7 +216,7 @@ fn checkIdentifierCodepointWarnings(p: *Parser, codepoint: u21, loc: Source.Loca
212
216
 
213
217
  const prev_total = p.diagnostics.total;
214
218
  var sf = std.heap.stackFallback(1024, p.comp.gpa);
215
- var allocating: Io.Writer.Allocating = .init(sf.get());
219
+ var allocating: std.Io.Writer.Allocating = .init(sf.get());
216
220
  defer allocating.deinit();
217
221
 
218
222
  if (!char_info.isC99IdChar(codepoint)) {
@@ -426,7 +430,7 @@ pub fn err(p: *Parser, tok_i: TokenIndex, diagnostic: Diagnostic, args: anytype)
426
430
  if (p.diagnostics.effectiveKind(diagnostic) == .off) return;
427
431
 
428
432
  var sf = std.heap.stackFallback(1024, p.comp.gpa);
429
- var allocating: Io.Writer.Allocating = .init(sf.get());
433
+ var allocating: std.Io.Writer.Allocating = .init(sf.get());
430
434
  defer allocating.deinit();
431
435
 
432
436
  p.formatArgs(&allocating.writer, diagnostic.fmt, args) catch return error.OutOfMemory;
@@ -448,7 +452,7 @@ pub fn err(p: *Parser, tok_i: TokenIndex, diagnostic: Diagnostic, args: anytype)
448
452
  }, p.pp.expansionSlice(tok_i), true);
449
453
  }
450
454
 
451
- fn formatArgs(p: *Parser, w: *Io.Writer, fmt: []const u8, args: anytype) !void {
455
+ fn formatArgs(p: *Parser, w: *std.Io.Writer, fmt: []const u8, args: anytype) !void {
452
456
  var i: usize = 0;
453
457
  inline for (std.meta.fields(@TypeOf(args))) |arg_info| {
454
458
  const arg = @field(args, arg_info.name);
@@ -477,13 +481,13 @@ fn formatArgs(p: *Parser, w: *Io.Writer, fmt: []const u8, args: anytype) !void {
477
481
  try w.writeAll(fmt[i..]);
478
482
  }
479
483
 
480
- fn formatTokenId(w: *Io.Writer, fmt: []const u8, tok_id: Tree.Token.Id) !usize {
484
+ fn formatTokenId(w: *std.Io.Writer, fmt: []const u8, tok_id: Tree.Token.Id) !usize {
481
485
  const i = Diagnostics.templateIndex(w, fmt, "{tok_id}");
482
486
  try w.writeAll(tok_id.symbol());
483
487
  return i;
484
488
  }
485
489
 
486
- fn formatQualType(p: *Parser, w: *Io.Writer, fmt: []const u8, qt: QualType) !usize {
490
+ fn formatQualType(p: *Parser, w: *std.Io.Writer, fmt: []const u8, qt: QualType) !usize {
487
491
  const i = Diagnostics.templateIndex(w, fmt, "{qt}");
488
492
  try w.writeByte('\'');
489
493
  try qt.print(p.comp, w);
@@ -502,7 +506,7 @@ fn formatQualType(p: *Parser, w: *Io.Writer, fmt: []const u8, qt: QualType) !usi
502
506
  return i;
503
507
  }
504
508
 
505
- fn formatResult(p: *Parser, w: *Io.Writer, fmt: []const u8, res: Result) !usize {
509
+ fn formatResult(p: *Parser, w: *std.Io.Writer, fmt: []const u8, res: Result) !usize {
506
510
  const i = Diagnostics.templateIndex(w, fmt, "{value}");
507
511
  switch (res.val.opt_ref) {
508
512
  .none => try w.writeAll("(none)"),
@@ -525,7 +529,7 @@ const Normalized = struct {
525
529
  return .{ .str = str };
526
530
  }
527
531
 
528
- pub fn format(ctx: Normalized, w: *Io.Writer, fmt: []const u8) !usize {
532
+ pub fn format(ctx: Normalized, w: *std.Io.Writer, fmt: []const u8) !usize {
529
533
  const i = Diagnostics.templateIndex(w, fmt, "{normalized}");
530
534
  var it: std.unicode.Utf8Iterator = .{
531
535
  .bytes = ctx.str,
@@ -559,7 +563,7 @@ const Codepoint = struct {
559
563
  return .{ .codepoint = codepoint };
560
564
  }
561
565
 
562
- pub fn format(ctx: Codepoint, w: *Io.Writer, fmt: []const u8) !usize {
566
+ pub fn format(ctx: Codepoint, w: *std.Io.Writer, fmt: []const u8) !usize {
563
567
  const i = Diagnostics.templateIndex(w, fmt, "{codepoint}");
564
568
  try w.print("{X:0>4}", .{ctx.codepoint});
565
569
  return i;
@@ -573,7 +577,7 @@ const Escaped = struct {
573
577
  return .{ .str = str };
574
578
  }
575
579
 
576
- pub fn format(ctx: Escaped, w: *Io.Writer, fmt: []const u8) !usize {
580
+ pub fn format(ctx: Escaped, w: *std.Io.Writer, fmt: []const u8) !usize {
577
581
  const i = Diagnostics.templateIndex(w, fmt, "{s}");
578
582
  try std.zig.stringEscape(ctx.str, w);
579
583
  return i;
@@ -740,6 +744,11 @@ fn getNode(p: *Parser, node: Node.Index, comptime tag: std.meta.Tag(Tree.Node))
740
744
  }
741
745
  }
742
746
 
747
+ pub fn isAddressOfStringLiteral(p: *Parser, node: Node.Index) bool {
748
+ const addr_of = p.getNode(node, .addr_of_expr) orelse return false;
749
+ return p.nodeIs(addr_of.operand, .string_literal_expr);
750
+ }
751
+
743
752
  fn pragma(p: *Parser) Compilation.Error!bool {
744
753
  var found_pragma = false;
745
754
  while (p.eatToken(.keyword_pragma)) |_| {
@@ -1070,14 +1079,15 @@ fn decl(p: *Parser) Error!bool {
1070
1079
 
1071
1080
  try p.attributeSpecifier();
1072
1081
 
1082
+ const decl_spec_start = p.tok_i;
1073
1083
  var decl_spec = (try p.declSpec()) orelse blk: {
1074
1084
  if (p.func.qt != null) {
1075
1085
  p.tok_i = first_tok;
1076
1086
  return false;
1077
1087
  }
1078
- switch (p.tok_ids[first_tok]) {
1088
+ switch (p.tok_ids[decl_spec_start]) {
1079
1089
  .asterisk, .l_paren => {},
1080
- .identifier, .extended_identifier => switch (p.tok_ids[first_tok + 1]) {
1090
+ .identifier, .extended_identifier => switch (p.tok_ids[decl_spec_start + 1]) {
1081
1091
  .identifier, .extended_identifier => {
1082
1092
  // The most likely reason for `identifier identifier` is
1083
1093
  // an unknown type name.
@@ -1087,7 +1097,7 @@ fn decl(p: *Parser) Error!bool {
1087
1097
  },
1088
1098
  else => {},
1089
1099
  },
1090
- else => if (p.tok_i != first_tok) {
1100
+ else => if (p.tok_i != decl_spec_start) {
1091
1101
  try p.err(p.tok_i, .expected_ident_or_l_paren, .{});
1092
1102
  return error.ParsingFailed;
1093
1103
  } else return false,
@@ -1167,6 +1177,7 @@ fn decl(p: *Parser) Error!bool {
1167
1177
 
1168
1178
  // Collect old style parameter declarations.
1169
1179
  if (init_d.d.old_style_func != null) {
1180
+ try p.err(init_d.d.name, .def_no_proto_deprecated, .{});
1170
1181
  const param_buf_top = p.param_buf.items.len;
1171
1182
  defer p.param_buf.items.len = param_buf_top;
1172
1183
 
@@ -1340,7 +1351,7 @@ fn decl(p: *Parser) Error!bool {
1340
1351
  if (init_d.d.old_style_func) |tok_i| try p.err(tok_i, .invalid_old_style_params, .{});
1341
1352
 
1342
1353
  if (decl_spec.storage_class == .typedef) {
1343
- try decl_spec.validateDecl(p);
1354
+ try decl_spec.validateDecl(p, init_d.asm_label);
1344
1355
  try p.tree.setNode(.{ .typedef = .{
1345
1356
  .name_tok = init_d.d.name,
1346
1357
  .qt = init_d.d.qt,
@@ -1357,7 +1368,7 @@ fn decl(p: *Parser) Error!bool {
1357
1368
  .definition = null,
1358
1369
  } }, @intFromEnum(decl_node));
1359
1370
  } else {
1360
- try decl_spec.validateDecl(p);
1371
+ try decl_spec.validateDecl(p, init_d.asm_label);
1361
1372
  var node_qt = init_d.d.qt;
1362
1373
  if (p.func.qt == null and decl_spec.storage_class != .@"extern") {
1363
1374
  if (node_qt.get(p.comp, .array)) |array_ty| {
@@ -1454,7 +1465,7 @@ fn decl(p: *Parser) Error!bool {
1454
1465
  return true;
1455
1466
  }
1456
1467
 
1457
- fn staticAssertMessage(p: *Parser, cond_node: Node.Index, maybe_message: ?Result, allocating: *Io.Writer.Allocating) !?[]const u8 {
1468
+ fn staticAssertMessage(p: *Parser, cond_node: Node.Index, maybe_message: ?Result, allocating: *std.Io.Writer.Allocating) !?[]const u8 {
1458
1469
  const w = &allocating.writer;
1459
1470
 
1460
1471
  const cond = cond_node.get(&p.tree);
@@ -1527,7 +1538,7 @@ fn staticAssert(p: *Parser) Error!bool {
1527
1538
  } else {
1528
1539
  if (!res.val.toBool(p.comp)) {
1529
1540
  var sf = std.heap.stackFallback(1024, gpa);
1530
- var allocating: Io.Writer.Allocating = .init(sf.get());
1541
+ var allocating: std.Io.Writer.Allocating = .init(sf.get());
1531
1542
  defer allocating.deinit();
1532
1543
 
1533
1544
  if (p.staticAssertMessage(res_node, str, &allocating) catch return error.OutOfMemory) |message| {
@@ -1597,13 +1608,16 @@ pub const DeclSpec = struct {
1597
1608
  if (d.constexpr) |tok_i| try p.err(tok_i, .illegal_storage_on_func, .{});
1598
1609
  }
1599
1610
 
1600
- fn validateDecl(d: DeclSpec, p: *Parser) Error!void {
1611
+ fn validateDecl(d: DeclSpec, p: *Parser, asm_label: ?Node.Index) Error!void {
1601
1612
  if (d.@"inline") |tok_i| try p.err(tok_i, .func_spec_non_func, .{"inline"});
1602
1613
  // TODO move to attribute validation
1603
1614
  if (d.noreturn) |tok_i| try p.err(tok_i, .func_spec_non_func, .{"_Noreturn"});
1604
1615
  switch (d.storage_class) {
1605
- .auto => std.debug.assert(!p.comp.langopts.standard.atLeast(.c23)),
1606
- .register => if (p.func.qt == null) try p.err(p.tok_i, .illegal_storage_on_global, .{}),
1616
+ .auto => {
1617
+ std.debug.assert(!p.comp.langopts.standard.atLeast(.c23));
1618
+ try p.err(p.tok_i, .auto_on_global, .{});
1619
+ },
1620
+ .register => if (p.func.qt == null and asm_label == null) try p.err(p.tok_i, .register_on_global, .{}),
1607
1621
  else => {},
1608
1622
  }
1609
1623
  }
@@ -1787,7 +1801,11 @@ fn storageClassSpec(p: *Parser, d: *DeclSpec) Error!bool {
1787
1801
  return p.tok_i != start;
1788
1802
  }
1789
1803
 
1790
- const InitDeclarator = struct { d: Declarator, initializer: ?Result = null };
1804
+ const InitDeclarator = struct {
1805
+ d: Declarator,
1806
+ initializer: ?Result = null,
1807
+ asm_label: ?Node.Index = null,
1808
+ };
1791
1809
 
1792
1810
  /// attribute
1793
1811
  /// : attrIdentifier
@@ -1829,18 +1847,18 @@ fn attribute(p: *Parser, kind: Attribute.Kind, namespace: ?[]const u8) Error!?Te
1829
1847
  if (try p.eatIdentifier()) |ident| {
1830
1848
  if (try Attribute.diagnoseIdent(attr, &arguments, ident, p)) {
1831
1849
  p.skipTo(.r_paren);
1832
- return error.ParsingFailed;
1850
+ return null;
1833
1851
  }
1834
1852
  } else {
1835
1853
  try p.err(name_tok, .attribute_requires_identifier, .{name});
1836
- return error.ParsingFailed;
1854
+ return null;
1837
1855
  }
1838
1856
  } else {
1839
1857
  const arg_start = p.tok_i;
1840
1858
  const first_expr = try p.expect(assignExpr);
1841
1859
  if (try p.diagnose(attr, &arguments, arg_idx, first_expr, arg_start)) {
1842
1860
  p.skipTo(.r_paren);
1843
- return error.ParsingFailed;
1861
+ return null;
1844
1862
  }
1845
1863
  }
1846
1864
  arg_idx += 1;
@@ -1851,7 +1869,7 @@ fn attribute(p: *Parser, kind: Attribute.Kind, namespace: ?[]const u8) Error!?Te
1851
1869
  const arg_expr = try p.expect(assignExpr);
1852
1870
  if (try p.diagnose(attr, &arguments, arg_idx, arg_expr, arg_start)) {
1853
1871
  p.skipTo(.r_paren);
1854
- return error.ParsingFailed;
1872
+ return null;
1855
1873
  }
1856
1874
  }
1857
1875
  },
@@ -1861,9 +1879,9 @@ fn attribute(p: *Parser, kind: Attribute.Kind, namespace: ?[]const u8) Error!?Te
1861
1879
  try p.err(name_tok, .attribute_not_enough_args, .{
1862
1880
  @tagName(attr), required_count,
1863
1881
  });
1864
- return error.ParsingFailed;
1882
+ return null;
1865
1883
  }
1866
- return TentativeAttribute{ .attr = .{ .tag = attr, .args = arguments, .syntax = kind.toSyntax() }, .tok = name_tok };
1884
+ return .{ .attr = .{ .tag = attr, .args = arguments, .syntax = kind.toSyntax() }, .tok = name_tok };
1867
1885
  }
1868
1886
 
1869
1887
  fn diagnose(p: *Parser, attr: Attribute.Tag, arguments: *Attribute.Arguments, arg_idx: u32, res: Result, arg_start: TokenIndex) !bool {
@@ -1995,12 +2013,12 @@ fn initDeclarator(p: *Parser, decl_spec: *DeclSpec, attr_buf_top: usize, decl_no
1995
2013
  defer p.attr_buf.len = this_attr_buf_top;
1996
2014
  const gpa = p.comp.gpa;
1997
2015
 
1998
- var init_d = InitDeclarator{
2016
+ var init_d: InitDeclarator = .{
1999
2017
  .d = (try p.declarator(decl_spec.qt, .normal)) orelse return null,
2000
2018
  };
2001
2019
 
2002
2020
  try p.attributeSpecifierExtra(init_d.d.name);
2003
- _ = try p.assembly(.decl_label);
2021
+ init_d.asm_label = try p.assembly(.decl_label);
2004
2022
  try p.attributeSpecifierExtra(init_d.d.name);
2005
2023
 
2006
2024
  switch (init_d.d.declarator_type) {
@@ -2276,14 +2294,13 @@ fn typeSpec(p: *Parser, builder: *TypeStore.Builder) Error!bool {
2276
2294
  }, .syntax = .keyword },
2277
2295
  .tok = align_tok,
2278
2296
  });
2279
- } else {
2297
+ } else check: {
2280
2298
  const arg_start = p.tok_i;
2281
2299
  const res = try p.integerConstExpr(.no_const_decl_folding);
2282
2300
  if (!res.val.isZero(p.comp)) {
2283
2301
  var args = Attribute.initArguments(.aligned, align_tok);
2284
2302
  if (try p.diagnose(.aligned, &args, 0, res, arg_start)) {
2285
- p.skipTo(.r_paren);
2286
- return error.ParsingFailed;
2303
+ break :check;
2287
2304
  }
2288
2305
  args.aligned.alignment.?.node = .pack(res.node);
2289
2306
  try p.attr_buf.append(gpa, .{
@@ -2562,7 +2579,7 @@ fn recordSpec(p: *Parser) Error!QualType {
2562
2579
 
2563
2580
  if (!any_incomplete) {
2564
2581
  const pragma_pack_value = switch (p.comp.langopts.emulate) {
2565
- .clang => starting_pragma_pack,
2582
+ .clang, .no => starting_pragma_pack,
2566
2583
  .gcc => p.pragma_pack,
2567
2584
  // TODO: msvc considers `#pragma pack` on a per-field basis
2568
2585
  .msvc => p.pragma_pack,
@@ -3542,7 +3559,6 @@ fn declarator(
3542
3559
 
3543
3560
  const pointer_qt = try p.comp.type_store.put(p.comp.gpa, .{ .pointer = .{
3544
3561
  .child = d.qt,
3545
- .decayed = null,
3546
3562
  } });
3547
3563
  d.qt = try builder.finishQuals(pointer_qt);
3548
3564
  }
@@ -4141,7 +4157,10 @@ fn designation(p: *Parser, il: *InitList, init_qt: QualType, index_list: *IndexL
4141
4157
  const field = record_ty.fields[field_index];
4142
4158
  if (field.name_tok == 0) if (field.qt.getRecord(p.comp)) |field_record_ty| {
4143
4159
  // Recurse into anonymous field if it has a field by the name.
4144
- if (!field_record_ty.hasField(p.comp, target_name)) continue;
4160
+ if (!field_record_ty.hasField(p.comp, target_name)) {
4161
+ field_index += 1;
4162
+ continue;
4163
+ }
4145
4164
  try index_list.append(gpa, field_index);
4146
4165
  cur_il = try il.find(gpa, field_index);
4147
4166
  record_ty = field_record_ty;
@@ -4983,31 +5002,31 @@ fn assembly(p: *Parser, kind: enum { global, decl_label, stmt }) Error!?Node.Ind
4983
5002
  };
4984
5003
 
4985
5004
  const l_paren = try p.expectToken(.l_paren);
4986
- var result_node: ?Node.Index = null;
4987
- switch (kind) {
4988
- .decl_label => {
5005
+ const res = switch (kind) {
5006
+ .decl_label => blk: {
4989
5007
  const asm_str = try p.asmStr();
4990
5008
  const str = try p.removeNull(asm_str.val);
4991
5009
 
4992
5010
  const attr = Attribute{ .tag = .asm_label, .args = .{ .asm_label = .{ .name = str } }, .syntax = .keyword };
4993
5011
  try p.attr_buf.append(p.comp.gpa, .{ .attr = attr, .tok = asm_tok });
5012
+ break :blk asm_str.node;
4994
5013
  },
4995
- .global => {
5014
+ .global => blk: {
4996
5015
  const asm_str = try p.asmStr();
4997
5016
  try p.checkAsmStr(asm_str.val, l_paren);
4998
- result_node = try p.addNode(.{
5017
+ break :blk try p.addNode(.{
4999
5018
  .global_asm = .{
5000
5019
  .asm_tok = asm_tok,
5001
5020
  .asm_str = asm_str.node,
5002
5021
  },
5003
5022
  });
5004
5023
  },
5005
- .stmt => result_node = try p.gnuAsmStmt(quals, asm_tok, l_paren),
5006
- }
5024
+ .stmt => try p.gnuAsmStmt(quals, asm_tok, l_paren),
5025
+ };
5007
5026
  try p.expectClosing(l_paren, .r_paren);
5008
5027
 
5009
5028
  if (kind != .decl_label) _ = try p.expectToken(.semicolon);
5010
- return result_node;
5029
+ return res;
5011
5030
  }
5012
5031
 
5013
5032
  /// Same as stringLiteral but errors on unicode and wide string literals
@@ -5253,7 +5272,6 @@ fn stmt(p: *Parser) Error!Node.Index {
5253
5272
  if (!goto_expr.qt.isInvalid() and !goto_expr.qt.isPointer(p.comp)) {
5254
5273
  const result_qt = try p.comp.type_store.put(gpa, .{ .pointer = .{
5255
5274
  .child = .{ .@"const" = true, ._index = .void },
5256
- .decayed = null,
5257
5275
  } });
5258
5276
  if (!goto_expr.qt.isRealInt(p.comp)) {
5259
5277
  try p.err(expr_tok, .incompatible_arg, .{ goto_expr.qt, result_qt });
@@ -5905,6 +5923,7 @@ const CallExpr = union(enum) {
5905
5923
  .__builtin_reduce_xor,
5906
5924
  .__builtin_reduce_max,
5907
5925
  .__builtin_reduce_min,
5926
+ .__builtin_constant_p,
5908
5927
  => 1,
5909
5928
 
5910
5929
  .__builtin_complex,
@@ -5922,13 +5941,15 @@ const CallExpr = union(enum) {
5922
5941
 
5923
5942
  .__c11_atomic_store,
5924
5943
  .__atomic_store,
5944
+ .__atomic_store_n,
5945
+ .__atomic_load,
5925
5946
  .__c11_atomic_exchange,
5926
- .__atomic_exchange,
5927
5947
  .__c11_atomic_fetch_add,
5928
5948
  .__c11_atomic_fetch_sub,
5929
5949
  .__c11_atomic_fetch_or,
5930
5950
  .__c11_atomic_fetch_xor,
5931
5951
  .__c11_atomic_fetch_and,
5952
+ .__c11_atomic_fetch_nand,
5932
5953
  .__atomic_fetch_add,
5933
5954
  .__atomic_fetch_sub,
5934
5955
  .__atomic_fetch_and,
@@ -5948,6 +5969,9 @@ const CallExpr = union(enum) {
5948
5969
  .__atomic_exchange_n,
5949
5970
  => 3,
5950
5971
 
5972
+ .__atomic_exchange,
5973
+ => 4,
5974
+
5951
5975
  .__c11_atomic_compare_exchange_strong,
5952
5976
  .__c11_atomic_compare_exchange_weak,
5953
5977
  => 5,
@@ -5964,25 +5988,13 @@ const CallExpr = union(enum) {
5964
5988
 
5965
5989
  fn returnType(self: CallExpr, p: *Parser, args: []const Node.Index, func_qt: QualType) !QualType {
5966
5990
  if (self == .standard) {
5991
+ if (func_qt.isInvalid()) return .invalid;
5967
5992
  return if (func_qt.get(p.comp, .func)) |func_ty| func_ty.return_type else .invalid;
5968
5993
  }
5969
5994
  const builtin = self.builtin;
5970
5995
  const func_ty = func_qt.get(p.comp, .func).?;
5971
5996
  return switch (builtin.expanded.tag) {
5972
5997
  .common => |tag| switch (tag) {
5973
- .__c11_atomic_exchange => {
5974
- if (args.len != 4) return .invalid; // wrong number of arguments; already an error
5975
- const second_param = args[2];
5976
- return second_param.qt(&p.tree);
5977
- },
5978
- .__c11_atomic_load => {
5979
- if (args.len != 3) return .invalid; // wrong number of arguments; already an error
5980
- const first_param = args[1];
5981
- const qt = first_param.qt(&p.tree);
5982
- if (!qt.isPointer(p.comp)) return .invalid;
5983
- return qt.childType(p.comp);
5984
- },
5985
-
5986
5998
  .__atomic_fetch_add,
5987
5999
  .__atomic_add_fetch,
5988
6000
  .__c11_atomic_fetch_add,
@@ -6008,15 +6020,38 @@ const CallExpr = union(enum) {
6008
6020
  .__c11_atomic_fetch_nand,
6009
6021
 
6010
6022
  .__atomic_exchange_n,
6023
+ .__c11_atomic_exchange,
6024
+ => {
6025
+ const second_param = args[1].qt(&p.tree);
6026
+ return second_param;
6027
+ },
6028
+
6029
+ .__sync_fetch_and_add,
6030
+ .__sync_fetch_and_and,
6031
+ .__sync_fetch_and_nand,
6032
+ .__sync_fetch_and_or,
6033
+ .__sync_fetch_and_sub,
6034
+ .__sync_fetch_and_xor,
6035
+
6036
+ .__sync_add_and_fetch,
6037
+ .__sync_and_and_fetch,
6038
+ .__sync_nand_and_fetch,
6039
+ .__sync_or_and_fetch,
6040
+ .__sync_sub_and_fetch,
6041
+ .__sync_xor_and_fetch,
6042
+
6043
+ .__sync_swap,
6044
+ .__sync_lock_test_and_set,
6045
+ .__sync_val_compare_and_swap,
6011
6046
  => {
6012
- if (args.len != 3) return .invalid; // wrong number of arguments; already an error
6013
- const second_param = args[2];
6014
- return second_param.qt(&p.tree);
6047
+ if (args.len < 2) return .invalid;
6048
+ const second_param = args[1].qt(&p.tree);
6049
+ return second_param;
6015
6050
  },
6016
6051
  .__builtin_complex => {
6017
- if (args.len < 1) return .invalid; // not enough arguments; already an error
6018
- const last_param = args[args.len - 1];
6019
- return try last_param.qt(&p.tree).toComplex(p.comp);
6052
+ const last_param = args[args.len - 1].qt(&p.tree);
6053
+ if (last_param.isInvalid()) return .invalid;
6054
+ return try last_param.toComplex(p.comp);
6020
6055
  },
6021
6056
  .__atomic_compare_exchange,
6022
6057
  .__atomic_compare_exchange_n,
@@ -6027,9 +6062,8 @@ const CallExpr = union(enum) {
6027
6062
  .__c11_atomic_compare_exchange_strong,
6028
6063
  .__c11_atomic_compare_exchange_weak,
6029
6064
  => {
6030
- if (args.len != 6) return .invalid; // wrong number of arguments
6031
- const third_param = args[3];
6032
- return third_param.qt(&p.tree);
6065
+ const third_param = args[2].qt(&p.tree);
6066
+ return third_param;
6033
6067
  },
6034
6068
 
6035
6069
  .__builtin_elementwise_abs,
@@ -6058,13 +6092,12 @@ const CallExpr = union(enum) {
6058
6092
  .__builtin_elementwise_sub_sat,
6059
6093
  .__builtin_elementwise_fma,
6060
6094
  .__builtin_elementwise_popcount,
6095
+
6061
6096
  .__builtin_nondeterministic_value,
6062
6097
  => {
6063
- if (args.len < 1) return .invalid; // not enough arguments; already an error
6064
- const last_param = args[args.len - 1];
6065
- return last_param.qt(&p.tree);
6098
+ const first_param = args[0].qt(&p.tree);
6099
+ return first_param;
6066
6100
  },
6067
- .__builtin_nontemporal_load,
6068
6101
  .__builtin_reduce_add,
6069
6102
  .__builtin_reduce_mul,
6070
6103
  .__builtin_reduce_and,
@@ -6073,30 +6106,19 @@ const CallExpr = union(enum) {
6073
6106
  .__builtin_reduce_max,
6074
6107
  .__builtin_reduce_min,
6075
6108
  => {
6076
- if (args.len < 1) return .invalid; // not enough arguments; already an error
6077
- const last_param = args[args.len - 1];
6078
- return last_param.qt(&p.tree).childType(p.comp);
6109
+ const first_param = args[0].qt(&p.tree);
6110
+ if (first_param.isInvalid()) return .invalid;
6111
+ const vector_ty = first_param.get(p.comp, .vector) orelse return .invalid;
6112
+ return vector_ty.elem;
6079
6113
  },
6080
- .__sync_add_and_fetch,
6081
- .__sync_and_and_fetch,
6082
- .__sync_fetch_and_add,
6083
- .__sync_fetch_and_and,
6084
- .__sync_fetch_and_nand,
6085
- .__sync_fetch_and_or,
6086
- .__sync_fetch_and_sub,
6087
- .__sync_fetch_and_xor,
6088
- .__sync_lock_test_and_set,
6089
- .__sync_nand_and_fetch,
6090
- .__sync_or_and_fetch,
6091
- .__sync_sub_and_fetch,
6092
- .__sync_swap,
6093
- .__sync_xor_and_fetch,
6094
- .__sync_val_compare_and_swap,
6095
6114
  .__atomic_load_n,
6115
+ .__c11_atomic_load,
6116
+ .__builtin_nontemporal_load,
6096
6117
  => {
6097
- if (args.len < 1) return .invalid; // not enough arguments; already an error
6098
- const first_param = args[0];
6099
- return first_param.qt(&p.tree).childType(p.comp);
6118
+ const first_param = args[0].qt(&p.tree);
6119
+ if (first_param.isInvalid()) return .invalid;
6120
+ if (!first_param.isPointer(p.comp)) return .invalid;
6121
+ return first_param.childType(p.comp);
6100
6122
  },
6101
6123
  else => func_ty.return_type,
6102
6124
  },
@@ -6104,9 +6126,16 @@ const CallExpr = union(enum) {
6104
6126
  };
6105
6127
  }
6106
6128
 
6107
- fn finish(self: CallExpr, p: *Parser, func_qt: QualType, list_buf_top: usize, l_paren: TokenIndex) Error!Result {
6129
+ fn finish(
6130
+ self: CallExpr,
6131
+ p: *Parser,
6132
+ func_qt: QualType,
6133
+ list_buf_top: usize,
6134
+ l_paren: TokenIndex,
6135
+ args_ok: bool,
6136
+ ) Error!Result {
6108
6137
  const args = p.list_buf.items[list_buf_top..];
6109
- const return_qt = try self.returnType(p, args, func_qt);
6138
+ const return_qt: QualType = if (args_ok) try self.returnType(p, args, func_qt) else .invalid;
6110
6139
  switch (self) {
6111
6140
  .standard => |func_node| return .{
6112
6141
  .qt = return_qt,
@@ -6118,7 +6147,7 @@ const CallExpr = union(enum) {
6118
6147
  } }),
6119
6148
  },
6120
6149
  .builtin => |builtin| return .{
6121
- .val = try evalBuiltin(builtin.expanded, p, args),
6150
+ .val = if (args_ok) try evalBuiltin(builtin.expanded, p, args) else .{},
6122
6151
  .qt = return_qt,
6123
6152
  .node = try p.addNode(.{ .builtin_call_expr = .{
6124
6153
  .builtin_tok = builtin.builtin_tok,
@@ -6283,14 +6312,12 @@ pub const Result = struct {
6283
6312
  if (!adjusted_elem_qt.eqlQualified(a_elem, p.comp)) {
6284
6313
  a.qt = try p.comp.type_store.put(gpa, .{ .pointer = .{
6285
6314
  .child = adjusted_elem_qt,
6286
- .decayed = null,
6287
6315
  } });
6288
6316
  try a.implicitCast(p, .bitcast, tok);
6289
6317
  }
6290
6318
  if (!adjusted_elem_qt.eqlQualified(b_elem, p.comp)) {
6291
6319
  b.qt = try p.comp.type_store.put(gpa, .{ .pointer = .{
6292
6320
  .child = adjusted_elem_qt,
6293
- .decayed = null,
6294
6321
  } });
6295
6322
  try b.implicitCast(p, .bitcast, tok);
6296
6323
  }
@@ -6478,6 +6505,7 @@ pub const Result = struct {
6478
6505
  .add => {
6479
6506
  // if both aren't arithmetic one should be pointer and the other an integer
6480
6507
  if (a_sk.isPointer() == b_sk.isPointer() or a_sk.isInt() == b_sk.isInt()) return a.invalidBinTy(tok, b, p);
6508
+ try p.boundsSafetyCheckPointerArithmetic(a.qt, b.qt, tok, a.node);
6481
6509
 
6482
6510
  if (a_sk == .void_pointer or b_sk == .void_pointer)
6483
6511
  try p.err(tok, .gnu_pointer_arith, .{});
@@ -6496,6 +6524,7 @@ pub const Result = struct {
6496
6524
  .sub => {
6497
6525
  // if both aren't arithmetic then either both should be pointers or just the left one.
6498
6526
  if (!a_sk.isPointer() or !(b_sk.isPointer() or b_sk.isInt())) return a.invalidBinTy(tok, b, p);
6527
+ try p.boundsSafetyCheckPointerArithmetic(a.qt, b.qt, tok, a.node);
6499
6528
 
6500
6529
  if (a_sk == .void_pointer)
6501
6530
  try p.err(tok, .gnu_pointer_arith, .{});
@@ -7087,14 +7116,14 @@ pub const Result = struct {
7087
7116
  } else if (dest_sk.isPointer()) {
7088
7117
  if (src_sk.isPointer()) {
7089
7118
  cast_kind = .bitcast;
7119
+ } else if (src_sk == .bool) {
7120
+ cast_kind = .bool_to_pointer;
7090
7121
  } else if (src_sk.isInt()) {
7091
7122
  if (!src_sk.isReal()) {
7092
7123
  res.qt = res.qt.toReal(p.comp);
7093
7124
  try res.implicitCast(p, .complex_int_to_real, l_paren);
7094
7125
  }
7095
7126
  cast_kind = .int_to_pointer;
7096
- } else if (src_sk == .bool) {
7097
- cast_kind = .bool_to_pointer;
7098
7127
  } else if (res.qt.is(p.comp, .array)) {
7099
7128
  cast_kind = .array_to_pointer;
7100
7129
  } else if (res.qt.is(p.comp, .func)) {
@@ -7497,7 +7526,16 @@ fn issueDeclaredConstHereNote(p: *Parser, decl_ref: Tree.Node.DeclRef, var_name:
7497
7526
  try p.err(location, .declared_const_here, .{var_name});
7498
7527
  }
7499
7528
 
7500
- fn issueConstAssignmetDiagnostics(p: *Parser, node_idx: Node.Index, tok: TokenIndex) Compilation.Error!void {
7529
+ fn issueBoundsDeclaredHereNote(p: *Parser, decl_ref: Tree.Node.DeclRef, var_name: []const u8, bounds: Type.Pointer.Bounds) Compilation.Error!void {
7530
+ const location = switch (decl_ref.decl.get(&p.tree)) {
7531
+ .variable => |variable| variable.name_tok,
7532
+ .param => |param| param.name_tok,
7533
+ else => return,
7534
+ };
7535
+ try p.err(location, .pointer_bounds_declared_here, .{ var_name, @tagName(bounds) });
7536
+ }
7537
+
7538
+ fn issueConstAssignmentDiagnostics(p: *Parser, node_idx: Node.Index, tok: TokenIndex) Compilation.Error!void {
7501
7539
  if (p.unwrapNestedOperation(node_idx)) |unwrapped| {
7502
7540
  const name = p.tokSlice(unwrapped.name_tok);
7503
7541
  try p.err(tok, .const_var_assignment, .{ name, unwrapped.qt });
@@ -7530,7 +7568,7 @@ fn assignExpr(p: *Parser) Error!?Result {
7530
7568
 
7531
7569
  var is_const: bool = undefined;
7532
7570
  if (!p.tree.isLvalExtra(lhs.node, &is_const) or is_const) {
7533
- try p.issueConstAssignmetDiagnostics(lhs.node, tok);
7571
+ try p.issueConstAssignmentDiagnostics(lhs.node, tok);
7534
7572
  lhs.qt = .invalid;
7535
7573
  }
7536
7574
 
@@ -8226,7 +8264,7 @@ fn builtinChooseExpr(p: *Parser) Error!Result {
8226
8264
  return cond;
8227
8265
  }
8228
8266
 
8229
- /// vaStart : __builtin_va_arg '(' assignExpr ',' typeName ')'
8267
+ /// vaArg : __builtin_va_arg '(' assignExpr ',' typeName ')'
8230
8268
  fn builtinVaArg(p: *Parser, builtin_tok: TokenIndex) Error!Result {
8231
8269
  const l_paren = try p.expectToken(.l_paren);
8232
8270
  const va_list_tok = p.tok_i;
@@ -8258,6 +8296,62 @@ fn builtinVaArg(p: *Parser, builtin_tok: TokenIndex) Error!Result {
8258
8296
  };
8259
8297
  }
8260
8298
 
8299
+ /// vaArgPack : __builtin_va_arg_pack '(' ')'
8300
+ fn builtinVaArgPack(p: *Parser, builtin_tok: TokenIndex) Error!Result {
8301
+ const l_paren = try p.expectToken(.l_paren);
8302
+ try p.expectClosing(l_paren, .r_paren);
8303
+
8304
+ var res_qt: QualType = .invalid;
8305
+ if (!try p.checkVaPackFunc(builtin_tok, "__builtin_va_arg_pack")) {
8306
+ // Only add one error.
8307
+ } else if (!p.va_arg_pack_ctx.valid) {
8308
+ try p.err(builtin_tok, .va_pack_non_call, .{});
8309
+ } else if (!p.va_arg_pack_ctx.variadic) {
8310
+ try p.err(builtin_tok, .va_pack_non_variadic_call, .{});
8311
+ } else if (p.va_arg_pack_ctx.typed) {
8312
+ try p.err(builtin_tok, .va_pack_non_variadic_arg, .{});
8313
+ } else {
8314
+ res_qt = .void;
8315
+ }
8316
+ return .{
8317
+ .qt = res_qt,
8318
+ .node = try p.addNode(.{
8319
+ .builtin_va_arg_pack = .{ .builtin_tok = builtin_tok },
8320
+ }),
8321
+ };
8322
+ }
8323
+
8324
+ /// vaArgPackLen : __builtin_va_arg_pack_len '(' ')'
8325
+ fn builtinVaArgPackLen(p: *Parser, builtin_tok: TokenIndex) Error!Result {
8326
+ const l_paren = try p.expectToken(.l_paren);
8327
+ try p.expectClosing(l_paren, .r_paren);
8328
+
8329
+ _ = try p.checkVaPackFunc(builtin_tok, "__builtin_va_arg_pack_len");
8330
+
8331
+ return .{
8332
+ .qt = .int,
8333
+ .node = try p.addNode(.{
8334
+ .builtin_va_arg_pack_len = .{
8335
+ .builtin_tok = builtin_tok,
8336
+ },
8337
+ }),
8338
+ };
8339
+ }
8340
+
8341
+ fn checkVaPackFunc(p: *Parser, builtin_tok: TokenIndex, va_func_name: []const u8) !bool {
8342
+ const func_qt, _ = (try p.checkVaFunc(builtin_tok, va_func_name)) orelse return false;
8343
+
8344
+ var it = Attribute.Iterator.initType(func_qt, p.comp);
8345
+ while (it.next()) |item| switch (item[0].tag) {
8346
+ .always_inline, .gnu_inline => break,
8347
+ else => {},
8348
+ } else {
8349
+ try p.err(builtin_tok, .va_func_not_always_inline, .{va_func_name});
8350
+ return false;
8351
+ }
8352
+ return true;
8353
+ }
8354
+
8261
8355
  const OffsetKind = enum { bits, bytes };
8262
8356
 
8263
8357
  /// offsetof
@@ -8504,7 +8598,6 @@ fn unExpr(p: *Parser) Error!?Result {
8504
8598
 
8505
8599
  operand.qt = try p.comp.type_store.put(gpa, .{ .pointer = .{
8506
8600
  .child = operand.qt,
8507
- .decayed = null,
8508
8601
  } });
8509
8602
  }
8510
8603
  if (p.getNode(operand.node, .decl_ref_expr)) |decl_ref| {
@@ -8596,6 +8689,9 @@ fn unExpr(p: *Parser) Error!?Result {
8596
8689
  try p.err(tok, .not_assignable, .{});
8597
8690
  return error.ParsingFailed;
8598
8691
  }
8692
+ if (operand.qt.get(p.comp, .pointer)) |pointer| {
8693
+ try p.checkPtrArithmeticAllowed(pointer, p.tok_i, operand.node);
8694
+ }
8599
8695
  try operand.usualUnaryConversion(p, tok);
8600
8696
 
8601
8697
  if (operand.val.is(.int, p.comp) or operand.val.is(.int, p.comp)) {
@@ -8624,6 +8720,9 @@ fn unExpr(p: *Parser) Error!?Result {
8624
8720
  try p.err(tok, .not_assignable, .{});
8625
8721
  return error.ParsingFailed;
8626
8722
  }
8723
+ if (operand.qt.get(p.comp, .pointer)) |pointer| {
8724
+ try p.checkPtrArithmeticAllowed(pointer, p.tok_i, operand.node);
8725
+ }
8627
8726
  try operand.usualUnaryConversion(p, tok);
8628
8727
 
8629
8728
  if (operand.val.is(.int, p.comp) or operand.val.is(.int, p.comp)) {
@@ -8826,7 +8925,7 @@ fn unExpr(p: *Parser) Error!?Result {
8826
8925
  } else switch (p.comp.langopts.emulate) {
8827
8926
  .msvc => {}, // Doesn't support `_Complex` or `__imag` in the first place
8828
8927
  .gcc => operand.val = .zero,
8829
- .clang => {
8928
+ .clang, .no => {
8830
8929
  if (operand.val.is(.int, p.comp) or operand.val.is(.float, p.comp)) {
8831
8930
  operand.val = .zero;
8832
8931
  } else {
@@ -8886,7 +8985,7 @@ fn compoundLiteral(p: *Parser, qt_opt: ?QualType, opt_l_paren: ?TokenIndex) Erro
8886
8985
  try p.err(tok, .invalid_compound_literal_storage_class, .{@tagName(d.storage_class)});
8887
8986
  d.storage_class = .none;
8888
8987
  },
8889
- .register => if (p.func.qt == null) try p.err(p.tok_i, .illegal_storage_on_global, .{}),
8988
+ .register => if (p.func.qt == null) try p.err(p.tok_i, .register_on_global_compound_literal, .{}),
8890
8989
  else => {},
8891
8990
  }
8892
8991
 
@@ -8968,6 +9067,9 @@ fn suffixExpr(p: *Parser, lhs: Result) Error!?Result {
8968
9067
  try p.err(p.tok_i, .not_assignable, .{});
8969
9068
  return error.ParsingFailed;
8970
9069
  }
9070
+ if (operand.qt.get(p.comp, .pointer)) |pointer| {
9071
+ try p.checkPtrArithmeticAllowed(pointer, p.tok_i, operand.node);
9072
+ }
8971
9073
  try operand.usualUnaryConversion(p, p.tok_i);
8972
9074
 
8973
9075
  try operand.un(p, .post_inc_expr, p.tok_i);
@@ -8989,6 +9091,9 @@ fn suffixExpr(p: *Parser, lhs: Result) Error!?Result {
8989
9091
  try p.err(p.tok_i, .not_assignable, .{});
8990
9092
  return error.ParsingFailed;
8991
9093
  }
9094
+ if (operand.qt.get(p.comp, .pointer)) |pointer| {
9095
+ try p.checkPtrArithmeticAllowed(pointer, p.tok_i, operand.node);
9096
+ }
8992
9097
  try operand.usualUnaryConversion(p, p.tok_i);
8993
9098
 
8994
9099
  try operand.un(p, .post_dec_expr, p.tok_i);
@@ -9003,6 +9108,7 @@ fn suffixExpr(p: *Parser, lhs: Result) Error!?Result {
9003
9108
  const array_before_conversion = lhs;
9004
9109
  const index_before_conversion = index;
9005
9110
  var ptr = lhs;
9111
+
9006
9112
  try ptr.lvalConversion(p, l_bracket);
9007
9113
  try index.lvalConversion(p, l_bracket);
9008
9114
  if (ptr.qt.get(p.comp, .pointer)) |pointer_ty| {
@@ -9176,14 +9282,7 @@ fn checkVaStartArg(p: *Parser, builtin_tok: TokenIndex, first_after: TokenIndex,
9176
9282
  return error.ParsingFailed;
9177
9283
  }
9178
9284
 
9179
- const func_qt = p.func.qt orelse {
9180
- try p.err(builtin_tok, .va_start_not_in_func, .{});
9181
- return;
9182
- };
9183
- const func_ty = func_qt.get(p.comp, .func) orelse return;
9184
- if (func_ty.kind != .variadic or func_ty.params.len == 0) {
9185
- return p.err(builtin_tok, .va_start_fixed_args, .{});
9186
- }
9285
+ _, const func_ty = (try p.checkVaFunc(builtin_tok, "va_start")) orelse return;
9187
9286
  const last_param_name = func_ty.params[func_ty.params.len - 1].name;
9188
9287
  const decl_ref = p.getNode(arg.node, .decl_ref_expr);
9189
9288
  if (decl_ref == null or last_param_name != try p.comp.internString(p.tokSlice(decl_ref.?.name_tok))) {
@@ -9191,6 +9290,19 @@ fn checkVaStartArg(p: *Parser, builtin_tok: TokenIndex, first_after: TokenIndex,
9191
9290
  }
9192
9291
  }
9193
9292
 
9293
+ fn checkVaFunc(p: *Parser, builtin_tok: TokenIndex, va_func_name: []const u8) !?struct { QualType, Type.Func } {
9294
+ const func_qt = p.func.qt orelse {
9295
+ try p.err(builtin_tok, .va_func_not_in_func, .{va_func_name});
9296
+ return null;
9297
+ };
9298
+ const func_ty = func_qt.get(p.comp, .func) orelse return null;
9299
+ if (func_ty.kind != .variadic or func_ty.params.len == 0) {
9300
+ try p.err(builtin_tok, .va_func_fixed_args, .{va_func_name});
9301
+ return null;
9302
+ }
9303
+ return .{ func_qt, func_ty };
9304
+ }
9305
+
9194
9306
  fn checkArithOverflowArg(p: *Parser, builtin_tok: TokenIndex, first_after: TokenIndex, param_tok: TokenIndex, arg: *Result, idx: u32) !void {
9195
9307
  _ = builtin_tok;
9196
9308
  _ = first_after;
@@ -9320,7 +9432,7 @@ fn callExpr(p: *Parser, lhs: Result) Error!Result {
9320
9432
 
9321
9433
  // We cannot refer to the function type here because the pointer to
9322
9434
  // type_store.extra might get invalidated while parsing args.
9323
- const func_qt, const params_len, const func_kind = blk: {
9435
+ const func_qt, const typed_params_len, const func_kind_base = blk: {
9324
9436
  var base_qt = lhs.qt;
9325
9437
  if (base_qt.get(p.comp, .pointer)) |pointer_ty| base_qt = pointer_ty.child;
9326
9438
  if (base_qt.isInvalid()) break :blk .{ base_qt, std.math.maxInt(usize), undefined };
@@ -9343,9 +9455,44 @@ fn callExpr(p: *Parser, lhs: Result) Error!Result {
9343
9455
 
9344
9456
  const call_expr = CallExpr.init(p, lhs.node, func.node);
9345
9457
 
9458
+ const param_len_override = call_expr.paramCountOverride();
9459
+ const params_len = param_len_override orelse typed_params_len;
9460
+ const func_kind = if (param_len_override != null) .normal else func_kind_base;
9461
+
9346
9462
  while (p.eatToken(.r_paren) == null) {
9347
9463
  const param_tok = p.tok_i;
9348
9464
  if (arg_count == params_len) first_after = p.tok_i;
9465
+
9466
+ // Check for __builtin_va_arg_pack
9467
+ {
9468
+ var i = p.tok_i;
9469
+ loop: switch (p.tok_ids[i]) {
9470
+ .l_paren => {
9471
+ i += 1;
9472
+ continue :loop p.tok_ids[i];
9473
+ },
9474
+ .identifier => if (mem.eql(u8, p.tokSlice(i), "__builtin_va_arg_pack")) {
9475
+ @branchHint(.cold);
9476
+ p.va_arg_pack_ctx = .{
9477
+ .valid = true,
9478
+ .variadic = func_kind != .normal,
9479
+ .typed = arg_count < typed_params_len,
9480
+ };
9481
+ defer p.va_arg_pack_ctx = .{};
9482
+
9483
+ const arg = try p.expect(assignExpr);
9484
+ try p.list_buf.append(gpa, arg.node);
9485
+ arg_count += 1;
9486
+ if (p.eatToken(.comma)) |_| {
9487
+ try p.err(i, .va_pack_non_final_arg, .{});
9488
+ continue;
9489
+ }
9490
+ try p.expectClosing(l_paren, .r_paren);
9491
+ break;
9492
+ },
9493
+ else => {},
9494
+ }
9495
+ }
9349
9496
  var arg = try p.expect(assignExpr);
9350
9497
 
9351
9498
  if (call_expr.shouldPerformLvalConversion(arg_count)) {
@@ -9353,7 +9500,7 @@ fn callExpr(p: *Parser, lhs: Result) Error!Result {
9353
9500
  }
9354
9501
  if ((arg.qt.hasIncompleteSize(p.comp) and !arg.qt.is(p.comp, .void)) or arg.qt.isInvalid()) return error.ParsingFailed;
9355
9502
 
9356
- if (arg_count >= params_len) {
9503
+ if (arg_count >= typed_params_len) {
9357
9504
  if (call_expr.shouldPromoteVarArg(arg_count)) switch (arg.qt.base(p.comp).type) {
9358
9505
  .int => |int_ty| if (int_ty == .int) try arg.castToInt(p, arg.qt.promoteInt(p.comp), param_tok),
9359
9506
  .float => |float_ty| if (float_ty == .double) try arg.castToFloat(p, .double, param_tok),
@@ -9407,19 +9554,23 @@ fn callExpr(p: *Parser, lhs: Result) Error!Result {
9407
9554
  }
9408
9555
  if (func_qt.isInvalid()) {
9409
9556
  // Skip argument count checks.
9410
- return try call_expr.finish(p, func_qt, list_buf_top, l_paren);
9557
+ return try call_expr.finish(p, func_qt, list_buf_top, l_paren, false);
9411
9558
  }
9412
9559
 
9413
- if (call_expr.paramCountOverride()) |expected| {
9414
- if (expected != arg_count) {
9415
- try p.err(first_after, .expected_arguments, .{ expected, arg_count });
9416
- }
9417
- } else switch (func_kind) {
9560
+ const r_paren = p.tok_i - 1;
9561
+ var args_ok = true;
9562
+ switch (func_kind) {
9418
9563
  .normal => if (params_len != arg_count) {
9419
- try p.err(first_after, .expected_arguments, .{ params_len, arg_count });
9564
+ try p.err(
9565
+ if (arg_count < params_len) r_paren else first_after,
9566
+ .expected_arguments,
9567
+ .{ params_len, arg_count },
9568
+ );
9569
+ args_ok = false;
9420
9570
  },
9421
9571
  .variadic => if (arg_count < params_len) {
9422
- try p.err(first_after, .expected_at_least_arguments, .{ params_len, arg_count });
9572
+ try p.err(r_paren, .expected_at_least_arguments, .{ params_len, arg_count });
9573
+ args_ok = false;
9423
9574
  },
9424
9575
  .old_style => if (params_len != arg_count) {
9425
9576
  if (params_len == 0)
@@ -9429,10 +9580,60 @@ fn callExpr(p: *Parser, lhs: Result) Error!Result {
9429
9580
  },
9430
9581
  }
9431
9582
 
9432
- return try call_expr.finish(p, func_qt, list_buf_top, l_paren);
9583
+ return try call_expr.finish(p, func_qt, list_buf_top, l_paren, args_ok);
9584
+ }
9585
+
9586
+ fn boundsSafetyCheckArrayAccess(p: *Parser, lhs: Result, rhs: Result, l_bracket: TokenIndex) !void {
9587
+ if (!p.comp.hasClangStyleBoundsSafety()) return;
9588
+
9589
+ const ptr_res, const pointer, const index = if (lhs.qt.get(p.comp, .pointer)) |pointer| .{ lhs, pointer, rhs } else .{ rhs, rhs.qt.get(p.comp, .pointer).?, lhs };
9590
+
9591
+ switch (pointer.bounds) {
9592
+ .c, .unsafe_indexable => {},
9593
+ .single => {
9594
+ if (!index.val.isZero(p.comp)) {
9595
+ try p.err(l_bracket, .single_requires_zero_index, .{});
9596
+ if (p.unwrapNestedOperation(ptr_res.node)) |unwrapped| {
9597
+ const name = p.tokSlice(unwrapped.name_tok);
9598
+ try p.issueBoundsDeclaredHereNote(unwrapped, name, pointer.bounds);
9599
+ }
9600
+ }
9601
+ },
9602
+ }
9603
+ }
9604
+
9605
+ fn boundsSafetyCheckPointerArithmetic(p: *Parser, lhs: QualType, rhs: QualType, tok: TokenIndex, node: Tree.Node.Index) !void {
9606
+ if (!p.comp.hasClangStyleBoundsSafety()) return;
9607
+
9608
+ const pointer = if (rhs.isInt(p.comp))
9609
+ lhs.get(p.comp, .pointer) orelse return
9610
+ else if (lhs.isInt(p.comp))
9611
+ rhs.get(p.comp, .pointer) orelse return
9612
+ else
9613
+ return;
9614
+
9615
+ try p.checkPtrArithmeticAllowed(pointer, tok, node);
9616
+ }
9617
+
9618
+ fn checkPtrArithmeticAllowed(p: *Parser, pointer: Type.Pointer, tok: TokenIndex, node: Tree.Node.Index) !void {
9619
+ if (!p.comp.hasClangStyleBoundsSafety()) return;
9620
+
9621
+ switch (pointer.bounds) {
9622
+ .c, .unsafe_indexable => {},
9623
+ .single => {
9624
+ // clang issues this diagnostic even with a constant `0` operand
9625
+ try p.err(tok, .pointer_arith_single, .{});
9626
+ if (p.unwrapNestedOperation(node)) |unwrapped| {
9627
+ const name = p.tokSlice(unwrapped.name_tok);
9628
+ try p.issueBoundsDeclaredHereNote(unwrapped, name, pointer.bounds);
9629
+ }
9630
+ },
9631
+ }
9433
9632
  }
9434
9633
 
9435
9634
  fn checkArrayBounds(p: *Parser, index: Result, array: Result, tok: TokenIndex) !void {
9635
+ try p.boundsSafetyCheckArrayAccess(array, index, tok);
9636
+
9436
9637
  if (index.val.opt_ref == .none) return;
9437
9638
 
9438
9639
  const array_len = array.qt.arrayLen(p.comp) orelse return;
@@ -9579,6 +9780,8 @@ fn primaryExpr(p: *Parser) Error!?Result {
9579
9780
  .common => |tag| switch (tag) {
9580
9781
  .__builtin_choose_expr => return try p.builtinChooseExpr(),
9581
9782
  .__builtin_va_arg => return try p.builtinVaArg(name_tok),
9783
+ .__builtin_va_arg_pack => return try p.builtinVaArgPack(name_tok),
9784
+ .__builtin_va_arg_pack_len => return try p.builtinVaArgPackLen(name_tok),
9582
9785
  .__builtin_offsetof => return try p.builtinOffsetof(name_tok, .bytes),
9583
9786
  .__builtin_bitoffsetof => return try p.builtinOffsetof(name_tok, .bits),
9584
9787
  .__builtin_types_compatible_p => return try p.typesCompatible(name_tok),
@@ -9720,7 +9923,7 @@ fn primaryExpr(p: *Parser) Error!?Result {
9720
9923
  qt = some.qt;
9721
9924
  } else if (p.func.qt) |func_qt| {
9722
9925
  var sf = std.heap.stackFallback(1024, gpa);
9723
- var allocating: Io.Writer.Allocating = .init(sf.get());
9926
+ var allocating: std.Io.Writer.Allocating = .init(sf.get());
9724
9927
  defer allocating.deinit();
9725
9928
 
9726
9929
  func_qt.printNamed(p.tokSlice(p.func.name), p.comp, &allocating.writer) catch return error.OutOfMemory;
@@ -10277,16 +10480,13 @@ fn fixedSizeInt(p: *Parser, base: u8, buf: []const u8, suffix: NumberSuffix, tok
10277
10480
  if (res.qt.intRankOrder(suffix_qt, p.comp).compare(.lt)) continue;
10278
10481
  const max_int = try Value.maxInt(res.qt, p.comp);
10279
10482
  if (interned_val.compare(.lte, max_int, p.comp)) break;
10280
- } else {
10281
- if (p.comp.langopts.emulate == .gcc) {
10282
- if (p.comp.target.hasInt128()) {
10283
- res.qt = .int128;
10284
- } else {
10285
- res.qt = .long_long;
10286
- }
10483
+ } else switch (p.comp.langopts.emulate) {
10484
+ .no, .gcc => if (p.comp.target.hasInt128()) {
10485
+ res.qt = .int128;
10287
10486
  } else {
10288
- res.qt = .ulong_long;
10289
- }
10487
+ res.qt = .long_long;
10488
+ },
10489
+ .msvc, .clang => res.qt = .ulong_long,
10290
10490
  }
10291
10491
 
10292
10492
  res.node = try p.addNode(.{ .int_literal = .{ .qt = res.qt, .literal_tok = tok_i } });
@@ -10604,12 +10804,7 @@ fn genericSelection(p: *Parser) Error!?Result {
10604
10804
  }
10605
10805
 
10606
10806
  test "Node locations" {
10607
- var arena_state: std.heap.ArenaAllocator = .init(std.testing.allocator);
10608
- defer arena_state.deinit();
10609
- const arena = arena_state.allocator();
10610
-
10611
- var diagnostics: Diagnostics = .{ .output = .ignore };
10612
- var comp = Compilation.init(std.testing.allocator, arena, std.testing.io, &diagnostics, Io.Dir.cwd());
10807
+ var comp = try Compilation.init(.testing);
10613
10808
  defer comp.deinit();
10614
10809
 
10615
10810
  const file = try comp.addSourceFromBuffer("file.c",
@@ -10621,7 +10816,7 @@ test "Node locations" {
10621
10816
 
10622
10817
  const builtin_macros = try comp.generateBuiltinMacros(.no_system_defines);
10623
10818
 
10624
- var pp = Preprocessor.init(&comp, .default);
10819
+ var pp = try Preprocessor.init(&comp, .testing);
10625
10820
  defer pp.deinit();
10626
10821
  try pp.addBuiltinMacros();
10627
10822
 
@@ -10633,7 +10828,6 @@ test "Node locations" {
10633
10828
  var tree = try Parser.parse(&pp);
10634
10829
  defer tree.deinit();
10635
10830
 
10636
- try std.testing.expectEqual(0, comp.diagnostics.total);
10637
10831
  for (tree.root_decls.items[tree.root_decls.items.len - 3 ..], 0..) |node, i| {
10638
10832
  const slice = tree.tokSlice(node.tok(&tree));
10639
10833
  const expected_slice = switch (i) {