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

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 (352) hide show
  1. package/LICENSE +19 -0
  2. package/c/fcntl.zig +6 -1
  3. package/c/inttypes.zig +0 -10
  4. package/c/math.zig +138 -114
  5. package/c/pthread.zig +57 -0
  6. package/c/search.zig +1 -27
  7. package/c/stdlib/drand48.zig +0 -57
  8. package/c/stdlib.zig +0 -100
  9. package/c/string.zig +20 -7
  10. package/c/strings.zig +0 -38
  11. package/c/stropts.zig +17 -0
  12. package/c/unistd.zig +27 -26
  13. package/c/wchar.zig +10 -0
  14. package/c.zig +3 -2
  15. package/compiler/aro/aro/Attribute/names.zig +604 -589
  16. package/compiler/aro/aro/Attribute.zig +202 -116
  17. package/compiler/aro/aro/Builtins/common.zig +874 -863
  18. package/compiler/aro/aro/Builtins/eval.zig +15 -7
  19. package/compiler/aro/aro/Builtins.zig +0 -1
  20. package/compiler/aro/aro/CodeGen.zig +8 -7
  21. package/compiler/aro/aro/Compilation.zig +137 -111
  22. package/compiler/aro/aro/Diagnostics.zig +21 -17
  23. package/compiler/aro/aro/Driver/GCCDetector.zig +635 -0
  24. package/compiler/aro/aro/Driver.zig +138 -63
  25. package/compiler/aro/aro/LangOpts.zig +12 -2
  26. package/compiler/aro/aro/Parser/Diagnostic.zig +79 -19
  27. package/compiler/aro/aro/Parser.zig +352 -153
  28. package/compiler/aro/aro/Pragma.zig +3 -2
  29. package/compiler/aro/aro/Preprocessor/Diagnostic.zig +21 -0
  30. package/compiler/aro/aro/Preprocessor.zig +136 -62
  31. package/compiler/aro/aro/Target.zig +17 -12
  32. package/compiler/aro/aro/Tokenizer.zig +31 -14
  33. package/compiler/aro/aro/Toolchain.zig +4 -7
  34. package/compiler/aro/aro/Tree.zig +178 -148
  35. package/compiler/aro/aro/TypeStore.zig +82 -24
  36. package/compiler/aro/aro/Value.zig +13 -17
  37. package/compiler/aro/aro/features.zig +1 -0
  38. package/compiler/aro/aro/pragmas/message.zig +3 -2
  39. package/compiler/aro/aro/pragmas/once.zig +0 -1
  40. package/compiler/aro/aro/record_layout.zig +3 -3
  41. package/compiler/aro/aro/text_literal.zig +3 -2
  42. package/compiler/aro/assembly_backend/x86_64.zig +7 -8
  43. package/compiler/aro/backend/Assembly.zig +1 -2
  44. package/compiler/aro/backend/Interner.zig +2 -2
  45. package/compiler/aro/backend/Ir.zig +100 -92
  46. package/compiler/aro/include/ptrcheck.h +49 -0
  47. package/compiler/aro/main.zig +26 -10
  48. package/compiler/build_runner.zig +1 -2
  49. package/compiler/objdump.zig +93 -0
  50. package/compiler/reduce/Walk.zig +7 -7
  51. package/compiler/reduce.zig +5 -1
  52. package/compiler/resinator/compile.zig +2 -2
  53. package/compiler/resinator/main.zig +7 -1
  54. package/compiler/resinator/preprocess.zig +1 -3
  55. package/compiler/std-docs.zig +8 -1
  56. package/compiler/test_runner.zig +194 -62
  57. package/compiler/translate-c/MacroTranslator.zig +80 -11
  58. package/compiler/translate-c/PatternList.zig +1 -9
  59. package/compiler/translate-c/Scope.zig +43 -6
  60. package/compiler/translate-c/Translator.zig +369 -127
  61. package/compiler/translate-c/ast.zig +19 -11
  62. package/compiler/translate-c/main.zig +76 -17
  63. package/compiler_rt/cos.zig +140 -53
  64. package/compiler_rt/divmodei4.zig +40 -17
  65. package/compiler_rt/exp.zig +1 -6
  66. package/compiler_rt/exp2.zig +1 -6
  67. package/compiler_rt/exp_f128.zig +377 -0
  68. package/compiler_rt/fabs.zig +0 -2
  69. package/compiler_rt/fma.zig +0 -2
  70. package/compiler_rt/fmax.zig +0 -2
  71. package/compiler_rt/fmin.zig +0 -2
  72. package/compiler_rt/fmod.zig +0 -2
  73. package/compiler_rt/limb64.zig +1127 -0
  74. package/compiler_rt/log.zig +0 -2
  75. package/compiler_rt/log10.zig +0 -2
  76. package/compiler_rt/log2.zig +0 -2
  77. package/compiler_rt/long_double.zig +37 -0
  78. package/compiler_rt/mulXi3.zig +1 -1
  79. package/compiler_rt/mulo.zig +6 -1
  80. package/compiler_rt/rem_pio2l.zig +173 -0
  81. package/compiler_rt/round.zig +0 -2
  82. package/compiler_rt/sin.zig +139 -56
  83. package/compiler_rt/sincos.zig +277 -72
  84. package/compiler_rt/sqrt.zig +0 -2
  85. package/compiler_rt/ssp.zig +1 -1
  86. package/compiler_rt/tan.zig +117 -48
  87. package/compiler_rt/trig.zig +256 -6
  88. package/compiler_rt/trunc.zig +0 -2
  89. package/compiler_rt/udivmodei4.zig +28 -0
  90. package/compiler_rt.zig +2 -0
  91. package/fuzzer.zig +857 -307
  92. package/libc/musl/arch/mipsn32/syscall_arch.h +35 -32
  93. package/libc/musl/src/math/pow.c +343 -0
  94. package/package.json +1 -1
  95. package/std/Build/Cache.zig +6 -6
  96. package/std/Build/Fuzz.zig +6 -19
  97. package/std/Build/Module.zig +1 -1
  98. package/std/Build/Step/CheckObject.zig +3 -3
  99. package/std/Build/Step/Compile.zig +18 -1
  100. package/std/Build/Step/ConfigHeader.zig +49 -33
  101. package/std/Build/Step/InstallArtifact.zig +18 -0
  102. package/std/Build/Step/Run.zig +538 -89
  103. package/std/Build/Step/TranslateC.zig +0 -6
  104. package/std/Build/Step.zig +10 -19
  105. package/std/Build/WebServer.zig +31 -19
  106. package/std/Build/abi.zig +47 -11
  107. package/std/Build.zig +17 -17
  108. package/std/Io/Dir.zig +7 -2
  109. package/std/Io/Dispatch.zig +5 -13
  110. package/std/Io/File/Reader.zig +3 -1
  111. package/std/Io/File/Writer.zig +8 -6
  112. package/std/Io/File.zig +1 -0
  113. package/std/Io/Kqueue.zig +2 -2
  114. package/std/Io/Reader.zig +8 -9
  115. package/std/Io/Semaphore.zig +112 -17
  116. package/std/Io/Terminal.zig +1 -1
  117. package/std/Io/Threaded.zig +352 -180
  118. package/std/Io/Uring.zig +15 -16
  119. package/std/Io/Writer.zig +46 -42
  120. package/std/Io/net.zig +11 -11
  121. package/std/Io.zig +1052 -20
  122. package/std/SemanticVersion.zig +1 -1
  123. package/std/Target/Query.zig +2 -2
  124. package/std/Target.zig +53 -7
  125. package/std/Thread.zig +8 -3
  126. package/std/array_hash_map.zig +105 -573
  127. package/std/array_list.zig +22 -31
  128. package/std/bit_set.zig +22 -6
  129. package/std/builtin/assembly.zig +68 -0
  130. package/std/builtin.zig +4 -0
  131. package/std/c/haiku.zig +3 -0
  132. package/std/c/serenity.zig +1 -6
  133. package/std/c.zig +106 -24
  134. package/std/compress/flate/Compress.zig +3 -3
  135. package/std/compress/flate/Decompress.zig +2 -3
  136. package/std/compress/zstd/Decompress.zig +2 -4
  137. package/std/crypto/Certificate/Bundle.zig +15 -1
  138. package/std/crypto/Certificate.zig +13 -1
  139. package/std/crypto/ascon.zig +75 -33
  140. package/std/crypto/codecs/asn1/Oid.zig +12 -1
  141. package/std/crypto/codecs/asn1.zig +33 -18
  142. package/std/crypto/codecs/base64_hex_ct.zig +16 -8
  143. package/std/crypto/ml_kem.zig +2 -9
  144. package/std/crypto/tls/Client.zig +79 -4
  145. package/std/crypto/tls.zig +1 -1
  146. package/std/crypto.zig +1 -0
  147. package/std/debug/Dwarf.zig +29 -9
  148. package/std/debug/Info.zig +4 -0
  149. package/std/debug/MachOFile.zig +46 -8
  150. package/std/debug/Pdb.zig +540 -37
  151. package/std/debug/SelfInfo/Elf.zig +19 -18
  152. package/std/debug/SelfInfo/MachO.zig +18 -7
  153. package/std/debug/SelfInfo/Windows.zig +138 -36
  154. package/std/debug.zig +181 -66
  155. package/std/enums.zig +25 -19
  156. package/std/fmt.zig +8 -3
  157. package/std/fs/path.zig +6 -4
  158. package/std/heap/ArenaAllocator.zig +145 -154
  159. package/std/heap/BufferFirstAllocator.zig +165 -0
  160. package/std/heap/debug_allocator.zig +7 -7
  161. package/std/heap.zig +2 -126
  162. package/std/http/Client.zig +31 -30
  163. package/std/http.zig +14 -13
  164. package/std/json/Scanner.zig +2 -2
  165. package/std/json/Stringify.zig +3 -3
  166. package/std/json/dynamic.zig +4 -4
  167. package/std/math/big/int.zig +16 -17
  168. package/std/mem/Allocator.zig +4 -5
  169. package/std/mem.zig +48 -0
  170. package/std/os/emscripten.zig +2 -18
  171. package/std/os/linux/IoUring.zig +2 -0
  172. package/std/os/linux/aarch64.zig +41 -12
  173. package/std/os/linux/arc.zig +173 -0
  174. package/std/os/linux/arm.zig +41 -12
  175. package/std/os/linux/hexagon.zig +33 -11
  176. package/std/os/linux/loongarch32.zig +41 -13
  177. package/std/os/linux/loongarch64.zig +41 -12
  178. package/std/os/linux/m68k.zig +41 -13
  179. package/std/os/linux/mips.zig +67 -36
  180. package/std/os/linux/mips64.zig +60 -29
  181. package/std/os/linux/mipsn32.zig +60 -29
  182. package/std/os/linux/or1k.zig +41 -12
  183. package/std/os/linux/powerpc.zig +41 -12
  184. package/std/os/linux/powerpc64.zig +41 -12
  185. package/std/os/linux/riscv32.zig +41 -12
  186. package/std/os/linux/riscv64.zig +41 -12
  187. package/std/os/linux/s390x.zig +44 -7
  188. package/std/os/linux/sparc64.zig +83 -52
  189. package/std/os/linux/thumb.zig +52 -36
  190. package/std/os/linux/x32.zig +41 -12
  191. package/std/os/linux/x86.zig +42 -13
  192. package/std/os/linux/x86_64.zig +41 -12
  193. package/std/os/linux.zig +419 -438
  194. package/std/os/uefi/tables/boot_services.zig +9 -8
  195. package/std/os/windows.zig +2 -2
  196. package/std/os.zig +41 -0
  197. package/std/pdb.zig +143 -4
  198. package/std/posix.zig +6 -12
  199. package/std/priority_dequeue.zig +13 -12
  200. package/std/priority_queue.zig +5 -4
  201. package/std/process/Child.zig +1 -1
  202. package/std/process/Environ.zig +1 -1
  203. package/std/process.zig +1 -1
  204. package/std/sort.zig +3 -3
  205. package/std/start.zig +17 -4
  206. package/std/std.zig +19 -6
  207. package/std/testing/FailingAllocator.zig +4 -4
  208. package/std/testing/Smith.zig +37 -2
  209. package/std/zig/Ast/Render.zig +187 -459
  210. package/std/zig/Ast.zig +0 -4
  211. package/std/zig/AstGen.zig +86 -103
  212. package/std/zig/AstRlAnnotate.zig +0 -11
  213. package/std/zig/AstSmith.zig +2602 -0
  214. package/std/zig/BuiltinFn.zig +0 -32
  215. package/std/zig/Client.zig +8 -3
  216. package/std/zig/LibCInstallation.zig +4 -3
  217. package/std/zig/Parse.zig +90 -81
  218. package/std/zig/Server.zig +26 -0
  219. package/std/zig/WindowsSdk.zig +13 -13
  220. package/std/zig/Zir.zig +66 -62
  221. package/std/zig/ZonGen.zig +6 -5
  222. package/std/zig/c_translation/helpers.zig +14 -9
  223. package/std/zig/llvm/Builder.zig +119 -60
  224. package/std/zig/system.zig +20 -4
  225. package/std/zig/tokenizer.zig +2 -1
  226. package/std/zig.zig +7 -10
  227. package/std/zip.zig +5 -5
  228. package/zig.h +340 -1
  229. package/compiler/aro/aro/Driver/Filesystem.zig +0 -241
  230. package/libc/mingw/complex/cabs.c +0 -48
  231. package/libc/mingw/complex/cabsf.c +0 -48
  232. package/libc/mingw/complex/cacos.c +0 -50
  233. package/libc/mingw/complex/cacosf.c +0 -50
  234. package/libc/mingw/complex/carg.c +0 -48
  235. package/libc/mingw/complex/cargf.c +0 -48
  236. package/libc/mingw/complex/casin.c +0 -50
  237. package/libc/mingw/complex/casinf.c +0 -50
  238. package/libc/mingw/complex/catan.c +0 -50
  239. package/libc/mingw/complex/catanf.c +0 -50
  240. package/libc/mingw/complex/ccos.c +0 -50
  241. package/libc/mingw/complex/ccosf.c +0 -50
  242. package/libc/mingw/complex/cexp.c +0 -48
  243. package/libc/mingw/complex/cexpf.c +0 -48
  244. package/libc/mingw/complex/cimag.c +0 -48
  245. package/libc/mingw/complex/cimagf.c +0 -48
  246. package/libc/mingw/complex/clog.c +0 -48
  247. package/libc/mingw/complex/clog10.c +0 -49
  248. package/libc/mingw/complex/clog10f.c +0 -49
  249. package/libc/mingw/complex/clogf.c +0 -48
  250. package/libc/mingw/complex/conj.c +0 -48
  251. package/libc/mingw/complex/conjf.c +0 -48
  252. package/libc/mingw/complex/cpow.c +0 -48
  253. package/libc/mingw/complex/cpowf.c +0 -48
  254. package/libc/mingw/complex/cproj.c +0 -48
  255. package/libc/mingw/complex/cprojf.c +0 -48
  256. package/libc/mingw/complex/creal.c +0 -48
  257. package/libc/mingw/complex/crealf.c +0 -48
  258. package/libc/mingw/complex/csin.c +0 -50
  259. package/libc/mingw/complex/csinf.c +0 -50
  260. package/libc/mingw/complex/csqrt.c +0 -48
  261. package/libc/mingw/complex/csqrtf.c +0 -48
  262. package/libc/mingw/complex/ctan.c +0 -50
  263. package/libc/mingw/complex/ctanf.c +0 -50
  264. package/libc/mingw/math/arm/s_rint.c +0 -86
  265. package/libc/mingw/math/arm/s_rintf.c +0 -51
  266. package/libc/mingw/math/arm/sincos.S +0 -30
  267. package/libc/mingw/math/arm-common/sincosl.c +0 -13
  268. package/libc/mingw/math/arm64/rint.c +0 -12
  269. package/libc/mingw/math/arm64/rintf.c +0 -12
  270. package/libc/mingw/math/arm64/sincos.S +0 -32
  271. package/libc/mingw/math/bsd_private_base.h +0 -148
  272. package/libc/mingw/math/fdiml.c +0 -24
  273. package/libc/mingw/math/frexpf.c +0 -13
  274. package/libc/mingw/math/frexpl.c +0 -71
  275. package/libc/mingw/math/x86/acosf.c +0 -29
  276. package/libc/mingw/math/x86/atanf.c +0 -23
  277. package/libc/mingw/math/x86/atanl.c +0 -18
  278. package/libc/mingw/math/x86/cos.def.h +0 -65
  279. package/libc/mingw/math/x86/cosl.c +0 -46
  280. package/libc/mingw/math/x86/cosl_internal.S +0 -55
  281. package/libc/mingw/math/x86/ldexp.c +0 -23
  282. package/libc/mingw/math/x86/scalbn.S +0 -41
  283. package/libc/mingw/math/x86/scalbnf.S +0 -40
  284. package/libc/mingw/math/x86/sin.def.h +0 -65
  285. package/libc/mingw/math/x86/sinl.c +0 -46
  286. package/libc/mingw/math/x86/sinl_internal.S +0 -58
  287. package/libc/mingw/math/x86/tanl.S +0 -62
  288. package/libc/mingw/misc/btowc.c +0 -28
  289. package/libc/mingw/misc/wcstof.c +0 -66
  290. package/libc/mingw/misc/wcstoimax.c +0 -132
  291. package/libc/mingw/misc/wcstoumax.c +0 -126
  292. package/libc/mingw/misc/wctob.c +0 -29
  293. package/libc/mingw/misc/winbs_uint64.c +0 -6
  294. package/libc/mingw/misc/winbs_ulong.c +0 -6
  295. package/libc/mingw/misc/winbs_ushort.c +0 -6
  296. package/libc/mingw/stdio/_Exit.c +0 -10
  297. package/libc/mingw/stdio/_findfirst64i32.c +0 -21
  298. package/libc/mingw/stdio/_findnext64i32.c +0 -21
  299. package/libc/mingw/stdio/_fstat64i32.c +0 -37
  300. package/libc/mingw/stdio/_stat64i32.c +0 -37
  301. package/libc/mingw/stdio/_wfindfirst64i32.c +0 -21
  302. package/libc/mingw/stdio/_wfindnext64i32.c +0 -21
  303. package/libc/mingw/stdio/_wstat64i32.c +0 -37
  304. package/libc/mingw/winpthreads/spinlock.c +0 -82
  305. package/libc/musl/src/legacy/isastream.c +0 -7
  306. package/libc/musl/src/legacy/valloc.c +0 -8
  307. package/libc/musl/src/linux/tee.c +0 -8
  308. package/libc/musl/src/math/__cosl.c +0 -96
  309. package/libc/musl/src/math/__sinl.c +0 -78
  310. package/libc/musl/src/math/__tanl.c +0 -143
  311. package/libc/musl/src/math/aarch64/lrint.c +0 -10
  312. package/libc/musl/src/math/aarch64/lrintf.c +0 -10
  313. package/libc/musl/src/math/aarch64/rintf.c +0 -7
  314. package/libc/musl/src/math/cosl.c +0 -39
  315. package/libc/musl/src/math/fdim.c +0 -10
  316. package/libc/musl/src/math/fdimf.c +0 -10
  317. package/libc/musl/src/math/fdiml.c +0 -18
  318. package/libc/musl/src/math/finite.c +0 -7
  319. package/libc/musl/src/math/finitef.c +0 -7
  320. package/libc/musl/src/math/frexp.c +0 -23
  321. package/libc/musl/src/math/frexpf.c +0 -23
  322. package/libc/musl/src/math/frexpl.c +0 -29
  323. package/libc/musl/src/math/i386/lrint.c +0 -8
  324. package/libc/musl/src/math/i386/lrintf.c +0 -8
  325. package/libc/musl/src/math/i386/rintf.c +0 -7
  326. package/libc/musl/src/math/lrint.c +0 -72
  327. package/libc/musl/src/math/lrintf.c +0 -8
  328. package/libc/musl/src/math/powerpc64/lrint.c +0 -16
  329. package/libc/musl/src/math/powerpc64/lrintf.c +0 -16
  330. package/libc/musl/src/math/rintf.c +0 -30
  331. package/libc/musl/src/math/s390x/rintf.c +0 -15
  332. package/libc/musl/src/math/sincosl.c +0 -60
  333. package/libc/musl/src/math/sinl.c +0 -41
  334. package/libc/musl/src/math/tanl.c +0 -29
  335. package/libc/musl/src/math/x32/lrint.s +0 -5
  336. package/libc/musl/src/math/x32/lrintf.s +0 -5
  337. package/libc/musl/src/math/x86_64/lrint.c +0 -8
  338. package/libc/musl/src/math/x86_64/lrintf.c +0 -8
  339. package/libc/musl/src/string/strdup.c +0 -10
  340. package/libc/musl/src/string/strndup.c +0 -12
  341. package/libc/musl/src/string/wcsdup.c +0 -10
  342. package/libc/musl/src/thread/pthread_spin_destroy.c +0 -6
  343. package/libc/musl/src/thread/pthread_spin_init.c +0 -6
  344. package/libc/musl/src/thread/pthread_spin_lock.c +0 -8
  345. package/libc/musl/src/thread/pthread_spin_trylock.c +0 -7
  346. package/libc/musl/src/thread/pthread_spin_unlock.c +0 -7
  347. package/libc/musl/src/unistd/dup2.c +0 -20
  348. package/libc/musl/src/unistd/dup3.c +0 -26
  349. package/libc/wasi/libc-bottom-half/sources/reallocarray.c +0 -14
  350. package/libc/wasi/thread-stub/pthread_spin_lock.c +0 -8
  351. package/libc/wasi/thread-stub/pthread_spin_trylock.c +0 -8
  352. package/libc/wasi/thread-stub/pthread_spin_unlock.c +0 -7
@@ -19,10 +19,63 @@ const MacroTranslator = @import("MacroTranslator.zig");
19
19
  const PatternList = @import("PatternList.zig");
20
20
  const Scope = @import("Scope.zig");
21
21
 
22
+ const AnonymousRecordFieldNames = struct {
23
+ pub const Key = struct {
24
+ parent: QualType,
25
+ field: QualType,
26
+ };
27
+
28
+ pub const Context = struct {
29
+ pub fn hash(ctx: Context, key: Key) u64 {
30
+ const auto_hash = std.hash_map.getAutoHashFn(Key, Context);
31
+ return auto_hash(ctx, .{
32
+ .parent = key.parent.unqualified(),
33
+ .field = key.field.unqualified(),
34
+ });
35
+ }
36
+
37
+ pub fn eql(ctx: Context, a: Key, b: Key) bool {
38
+ const auto_eql = std.hash_map.getAutoEqlFn(Key, Context);
39
+ return auto_eql(ctx, .{
40
+ .parent = a.parent.unqualified(),
41
+ .field = a.field.unqualified(),
42
+ }, .{
43
+ .parent = b.parent.unqualified(),
44
+ .field = b.field.unqualified(),
45
+ });
46
+ }
47
+ };
48
+ };
49
+
50
+ pub const QualTypeHashContext = struct {
51
+ pub fn hash(ctx: QualTypeHashContext, key: QualType) u64 {
52
+ const auto_hash = std.hash_map.getAutoHashFn(QualType, QualTypeHashContext);
53
+ return auto_hash(ctx, key.unqualified());
54
+ }
55
+
56
+ pub fn eql(ctx: QualTypeHashContext, a: QualType, b: QualType) bool {
57
+ const auto_eql = std.hash_map.getAutoEqlFn(QualType, QualTypeHashContext);
58
+ return auto_eql(ctx, a.unqualified(), b.unqualified());
59
+ }
60
+ };
61
+
22
62
  pub const Error = std.mem.Allocator.Error;
23
63
  pub const MacroProcessingError = Error || error{UnexpectedMacroToken};
24
64
  pub const TypeError = Error || error{UnsupportedType};
25
- pub const TransError = TypeError || error{UnsupportedTranslation};
65
+ pub const TransError = TypeError || error{ UnsupportedTranslation, SelfReferential };
66
+
67
+ /// Control when to treat a trailing array as a flexible array member.
68
+ /// Mirrors the -fstrict-flex-arrays=<n> compiler flag.
69
+ pub const StrictFlexArraysLevel = enum {
70
+ /// Any trailing array member is a flexible array.
71
+ @"0",
72
+ /// Trailing arrays of size 0, 1, or undefined are flexible.
73
+ @"1",
74
+ /// Trailing arrays of size 0 or undefined are flexible (default).
75
+ @"2",
76
+ /// Only trailing arrays of undefined size are flexible.
77
+ @"3",
78
+ };
26
79
 
27
80
  const Translator = @This();
28
81
 
@@ -33,6 +86,17 @@ comp: *aro.Compilation,
33
86
  /// The Preprocessor that produced the source for `tree`.
34
87
  pp: *const aro.Preprocessor,
35
88
 
89
+ /// Should static functions be translated as `pub`.
90
+ pub_static: bool,
91
+ /// Should function bodies be translated.
92
+ func_bodies: bool,
93
+ /// Should macro names of literals be preserved.
94
+ keep_macro_literals: bool,
95
+ /// Should struct fields be default initialized.
96
+ default_init: bool,
97
+ /// Control when to treat a trailing array as a flexible array member.
98
+ strict_flex_arrays: StrictFlexArraysLevel,
99
+
36
100
  gpa: mem.Allocator,
37
101
  arena: mem.Allocator,
38
102
 
@@ -44,14 +108,16 @@ mangle_count: u32 = 0,
44
108
  /// Table of declarations for enum, struct, union and typedef types.
45
109
  type_decls: std.AutoArrayHashMapUnmanaged(Node.Index, []const u8) = .empty,
46
110
  /// Table of record decls that have been demoted to opaques.
47
- opaque_demotes: std.AutoHashMapUnmanaged(QualType, void) = .empty,
111
+ opaque_demotes: std.HashMapUnmanaged(QualType, void, QualTypeHashContext, std.hash_map.default_max_load_percentage) = .empty,
48
112
  /// Table of unnamed enums and records that are child types of typedefs.
49
- unnamed_typedefs: std.AutoHashMapUnmanaged(QualType, []const u8) = .empty,
113
+ unnamed_typedefs: std.HashMapUnmanaged(QualType, []const u8, QualTypeHashContext, std.hash_map.default_max_load_percentage) = .empty,
50
114
  /// Table of anonymous record to generated field names.
51
- anonymous_record_field_names: std.AutoHashMapUnmanaged(struct {
52
- parent: QualType,
53
- field: QualType,
54
- }, []const u8) = .empty,
115
+ anonymous_record_field_names: std.HashMapUnmanaged(
116
+ AnonymousRecordFieldNames.Key,
117
+ []const u8,
118
+ AnonymousRecordFieldNames.Context,
119
+ std.hash_map.default_max_load_percentage,
120
+ ) = .empty,
55
121
 
56
122
  /// This one is different than the root scope's name table. This contains
57
123
  /// a list of names that we found by visiting all the top level decls without
@@ -75,6 +141,10 @@ typedefs: std.StringArrayHashMapUnmanaged(void) = .empty,
75
141
  /// The lhs lval of a compound assignment expression.
76
142
  compound_assign_dummy: ?ZigNode = null,
77
143
 
144
+ /// Set of variables whose initializers are currently being translated.
145
+ /// Used to detect self-referential initializers.
146
+ wip_var_inits: std.AutoHashMapUnmanaged(Node.Index, void) = .empty,
147
+
78
148
  pub fn getMangle(t: *Translator) u32 {
79
149
  t.mangle_count += 1;
80
150
  return t.mangle_count;
@@ -98,10 +168,9 @@ fn maybeSuppressResult(t: *Translator, used: ResultUsed, result: ZigNode) TransE
98
168
 
99
169
  pub fn addTopLevelDecl(t: *Translator, name: []const u8, decl_node: ZigNode) !void {
100
170
  const gop = try t.global_scope.sym_table.getOrPut(t.gpa, name);
101
- if (!gop.found_existing) {
102
- gop.value_ptr.* = decl_node;
103
- try t.global_scope.nodes.append(t.gpa, decl_node);
104
- }
171
+ if (gop.found_existing) return; // Any duplicate decls are equivalent
172
+ gop.value_ptr.* = decl_node;
173
+ try t.global_scope.nodes.append(t.gpa, decl_node);
105
174
  }
106
175
 
107
176
  fn fail(
@@ -172,6 +241,12 @@ pub const Options = struct {
172
241
  comp: *aro.Compilation,
173
242
  pp: *const aro.Preprocessor,
174
243
  tree: *const aro.Tree,
244
+ module_libs: bool,
245
+ pub_static: bool,
246
+ func_bodies: bool,
247
+ keep_macro_literals: bool,
248
+ default_init: bool,
249
+ strict_flex_arrays: StrictFlexArraysLevel,
175
250
  };
176
251
 
177
252
  pub fn translate(options: Options) mem.Allocator.Error![]u8 {
@@ -188,6 +263,11 @@ pub fn translate(options: Options) mem.Allocator.Error![]u8 {
188
263
  .comp = options.comp,
189
264
  .pp = options.pp,
190
265
  .tree = options.tree,
266
+ .pub_static = options.pub_static,
267
+ .func_bodies = options.func_bodies,
268
+ .keep_macro_literals = options.keep_macro_literals,
269
+ .default_init = options.default_init,
270
+ .strict_flex_arrays = options.strict_flex_arrays,
191
271
  };
192
272
  translator.global_scope.* = Scope.Root.init(&translator);
193
273
  defer {
@@ -200,6 +280,7 @@ pub fn translate(options: Options) mem.Allocator.Error![]u8 {
200
280
  translator.anonymous_record_field_names.deinit(gpa);
201
281
  translator.typedefs.deinit(gpa);
202
282
  translator.global_scope.deinit();
283
+ translator.wip_var_inits.deinit(gpa);
203
284
  }
204
285
 
205
286
  try translator.prepopulateGlobalNameTable();
@@ -227,7 +308,6 @@ pub fn translate(options: Options) mem.Allocator.Error![]u8 {
227
308
  \\pub const __builtin = @import("std").zig.c_translation.builtins;
228
309
  \\pub const __helpers = @import("std").zig.c_translation.helpers;
229
310
  \\
230
- \\
231
311
  ) catch return error.OutOfMemory;
232
312
 
233
313
  var zig_ast = try ast.render(gpa, translator.global_scope.nodes.items);
@@ -261,10 +341,12 @@ fn prepopulateGlobalNameTable(t: *Translator) !void {
261
341
  const gop = try t.unnamed_typedefs.getOrPut(t.gpa, base.qt);
262
342
  if (gop.found_existing) {
263
343
  // One typedef can declare multiple names.
264
- // TODO Don't put this one in `decl_table` so it's processed later.
344
+ // Don't put this one in `decl_table` so it's processed later.
265
345
  continue;
266
346
  }
267
347
  gop.value_ptr.* = decl_name;
348
+ try t.type_decls.put(t.gpa, decl, decl_name);
349
+ try t.typedefs.put(t.gpa, decl_name, {});
268
350
  },
269
351
 
270
352
  .struct_decl,
@@ -344,15 +426,26 @@ fn transDecl(t: *Translator, scope: *Scope, decl: Node.Index) !void {
344
426
  try t.transRecordDecl(scope, record_decl.container_qt);
345
427
  },
346
428
 
429
+ .struct_forward_decl, .union_forward_decl => |record_decl| {
430
+ if (record_decl.definition) |some| {
431
+ return t.transDecl(scope, some);
432
+ }
433
+ try t.transRecordDecl(scope, record_decl.container_qt);
434
+ },
435
+
347
436
  .enum_decl => |enum_decl| {
348
437
  try t.transEnumDecl(scope, enum_decl.container_qt);
349
438
  },
350
439
 
440
+ .enum_forward_decl => |enum_decl| {
441
+ if (enum_decl.definition) |some| {
442
+ return t.transDecl(scope, some);
443
+ }
444
+ try t.transEnumDecl(scope, enum_decl.container_qt);
445
+ },
446
+
351
447
  .enum_field,
352
448
  .record_field,
353
- .struct_forward_decl,
354
- .union_forward_decl,
355
- .enum_forward_decl,
356
449
  => return,
357
450
 
358
451
  .function => |function| {
@@ -364,7 +457,7 @@ fn transDecl(t: *Translator, scope: *Scope, decl: Node.Index) !void {
364
457
 
365
458
  .variable => |variable| {
366
459
  if (variable.definition != null) return;
367
- try t.transVarDecl(scope, variable);
460
+ try t.transVarDecl(scope, variable, decl);
368
461
  },
369
462
  .static_assert => |static_assert| {
370
463
  try t.transStaticAssert(&t.global_scope.base, static_assert);
@@ -382,8 +475,12 @@ pub const builtin_typedef_map = std.StaticStringMap([]const u8).initComptime(.{
382
475
  .{ "int8_t", "i8" },
383
476
  .{ "uint16_t", "u16" },
384
477
  .{ "int16_t", "i16" },
478
+ .{ "uint24_t", "u24" },
479
+ .{ "int24_t", "i24" },
385
480
  .{ "uint32_t", "u32" },
386
481
  .{ "int32_t", "i32" },
482
+ .{ "uint48_t", "u48" },
483
+ .{ "int48_t", "i48" },
387
484
  .{ "uint64_t", "u64" },
388
485
  .{ "int64_t", "i64" },
389
486
  .{ "intptr_t", "isize" },
@@ -531,13 +628,6 @@ fn transRecordDecl(t: *Translator, scope: *Scope, record_qt: QualType) Error!voi
531
628
  break :init ZigTag.opaque_literal.init();
532
629
  }
533
630
 
534
- // Demote record to opaque if it contains an opaque field
535
- if (t.typeWasDemotedToOpaque(field.qt)) {
536
- try t.opaque_demotes.put(t.gpa, base.qt, {});
537
- try t.warn(scope, field_loc, "{s} demoted to opaque type - has opaque field", .{container_kind_name});
538
- break :init ZigTag.opaque_literal.init();
539
- }
540
-
541
631
  var field_name = field.name.lookup(t.comp);
542
632
  if (field.name_tok == 0) {
543
633
  field_name = try std.fmt.allocPrint(t.arena, "unnamed_{d}", .{unnamed_field_count});
@@ -548,23 +638,22 @@ fn transRecordDecl(t: *Translator, scope: *Scope, record_qt: QualType) Error!voi
548
638
  }, field_name);
549
639
  }
550
640
 
551
- const field_alignment = if (has_alignment_attributes)
552
- t.alignmentForField(record_ty, head_field_alignment, field_index)
553
- else
554
- null;
555
-
556
641
  const field_type = field_type: {
557
642
  // Check if this is a flexible array member.
558
643
  flexible: {
559
644
  if (field_index != record_ty.fields.len - 1 and container_kind != .@"union") break :flexible;
560
645
  const array_ty = field.qt.get(t.comp, .array) orelse break :flexible;
561
- if (array_ty.len != .incomplete and (array_ty.len != .fixed or array_ty.len.fixed != 0)) break :flexible;
646
+ if (!t.isFlexibleArrayLen(array_ty.len)) break :flexible;
562
647
 
563
648
  const elem_type = t.transType(scope, array_ty.elem, field_loc) catch |err| switch (err) {
564
649
  error.UnsupportedType => break :flexible,
565
650
  else => |e| return e,
566
651
  };
567
- const zero_array = try ZigTag.array_type.create(t.arena, .{ .len = 0, .elem_type = elem_type });
652
+ const backing_array_len: usize = switch (array_ty.len) {
653
+ .fixed => |n| @intCast(n),
654
+ else => 0,
655
+ };
656
+ const backing_array = try ZigTag.array_type.create(t.arena, .{ .len = backing_array_len, .elem_type = elem_type });
568
657
 
569
658
  const member_name = field_name;
570
659
  field_name = try std.fmt.allocPrint(t.arena, "_{s}", .{field_name});
@@ -572,7 +661,7 @@ fn transRecordDecl(t: *Translator, scope: *Scope, record_qt: QualType) Error!voi
572
661
  const member = try t.createFlexibleMemberFn(member_name, field_name);
573
662
  try functions.append(t.gpa, member);
574
663
 
575
- break :field_type zero_array;
664
+ break :field_type backing_array;
576
665
  }
577
666
 
578
667
  break :field_type t.transType(scope, field.qt, field_loc) catch |err| switch (err) {
@@ -588,10 +677,22 @@ fn transRecordDecl(t: *Translator, scope: *Scope, record_qt: QualType) Error!voi
588
677
  };
589
678
  };
590
679
 
680
+ // Demote record to opaque if it contains an opaque field
681
+ if (t.typeWasDemotedToOpaque(field.qt)) {
682
+ try t.opaque_demotes.put(t.gpa, base.qt, {});
683
+ try t.warn(scope, field_loc, "{s} demoted to opaque type - has opaque field", .{container_kind_name});
684
+ break :init ZigTag.opaque_literal.init();
685
+ }
686
+
687
+ const field_alignment = if (has_alignment_attributes)
688
+ t.alignmentForField(record_ty, head_field_alignment, field_index)
689
+ else
690
+ null;
691
+
591
692
  // C99 introduced designated initializers for structs. Omitted fields are implicitly
592
693
  // initialized to zero. Some C APIs are designed with this in mind. Defaulting to zero
593
694
  // values for translated struct fields permits Zig code to comfortably use such an API.
594
- const default_value = if (container_kind == .@"struct")
695
+ const default_value = if (t.default_init and container_kind == .@"struct")
595
696
  try t.createZeroValueNode(field.qt, field_type, .no_as)
596
697
  else
597
698
  null;
@@ -616,7 +717,7 @@ fn transRecordDecl(t: *Translator, scope: *Scope, record_qt: QualType) Error!voi
616
717
  .name = "_padding",
617
718
  .type = try ZigTag.type.create(t.arena, try std.fmt.allocPrint(t.arena, "u{d}", .{padding_bits})),
618
719
  .alignment = @divExact(alignment_bits, 8),
619
- .default_value = if (container_kind == .@"struct")
720
+ .default_value = if (t.default_init and container_kind == .@"struct")
620
721
  ZigTag.zero_literal.init()
621
722
  else
622
723
  null,
@@ -663,14 +764,12 @@ fn transRecordDecl(t: *Translator, scope: *Scope, record_qt: QualType) Error!voi
663
764
  fn transFnDecl(t: *Translator, scope: *Scope, function: Node.Function) Error!void {
664
765
  const func_ty = function.qt.get(t.comp, .func).?;
665
766
 
666
- const is_pub = scope.id == .root;
667
-
668
767
  const fn_name = t.tree.tokSlice(function.name_tok);
669
768
  if (scope.getAlias(fn_name) != null or t.global_scope.containsNow(fn_name))
670
769
  return; // Avoid processing this decl twice
671
770
 
672
771
  const fn_decl_loc = function.name_tok;
673
- const has_body = function.body != null and func_ty.kind != .variadic;
772
+ const has_body = function.body != null and func_ty.kind != .variadic and t.func_bodies;
674
773
  if (function.body != null and func_ty.kind == .variadic) {
675
774
  try t.warn(scope, function.name_tok, "TODO unable to translate variadic function, demoted to extern", .{});
676
775
  }
@@ -681,7 +780,7 @@ fn transFnDecl(t: *Translator, scope: *Scope, function: Node.Function) Error!voi
681
780
  .is_always_inline = is_always_inline,
682
781
  .is_extern = !has_body,
683
782
  .is_export = !function.static and has_body and !is_always_inline and !function.@"inline",
684
- .is_pub = is_pub,
783
+ .is_pub = scope.id == .root and (!function.static or t.pub_static),
685
784
  .has_body = has_body,
686
785
  .cc = if (function.qt.getAttribute(t.comp, .calling_convention)) |some| switch (some.cc) {
687
786
  .c => .c,
@@ -761,6 +860,7 @@ fn transFnDecl(t: *Translator, scope: *Scope, function: Node.Function) Error!voi
761
860
 
762
861
  t.transCompoundStmtInline(body_stmt, &block_scope) catch |err| switch (err) {
763
862
  error.OutOfMemory => |e| return e,
863
+ error.SelfReferential => unreachable,
764
864
  error.UnsupportedTranslation,
765
865
  error.UnsupportedType,
766
866
  => {
@@ -777,7 +877,7 @@ fn transFnDecl(t: *Translator, scope: *Scope, function: Node.Function) Error!voi
777
877
  return t.addTopLevelDecl(fn_name, proto_node);
778
878
  }
779
879
 
780
- fn transVarDecl(t: *Translator, scope: *Scope, variable: Node.Variable) Error!void {
880
+ fn transVarDecl(t: *Translator, scope: *Scope, variable: Node.Variable, decl_node: Node.Index) Error!void {
781
881
  const base_name = t.tree.tokSlice(variable.name_tok);
782
882
  const toplevel = scope.id == .root;
783
883
  const bs: *Scope.Block = if (!toplevel) try scope.findBlockScope(t) else undefined;
@@ -815,24 +915,28 @@ fn transVarDecl(t: *Translator, scope: *Scope, variable: Node.Variable) Error!vo
815
915
  var is_const = variable.qt.@"const" or (array_ty != null and array_ty.?.elem.@"const");
816
916
  var is_extern = variable.storage_class == .@"extern";
817
917
 
918
+ var self_referential = false;
818
919
  const init_node = init: {
819
920
  if (variable.initializer) |init| {
820
921
  const maybe_literal = init.get(t.tree);
922
+ if (!toplevel) try t.wip_var_inits.putNoClobber(t.gpa, decl_node, {});
923
+ defer _ = t.wip_var_inits.remove(decl_node);
924
+
821
925
  const init_node = (if (maybe_literal == .string_literal_expr)
822
926
  t.transStringLiteralInitializer(init, maybe_literal.string_literal_expr, type_node)
823
927
  else
824
928
  t.transExprCoercing(scope, init, .used)) catch |err| switch (err) {
929
+ error.SelfReferential => {
930
+ self_referential = true;
931
+ break :init ZigTag.undefined_literal.init();
932
+ },
825
933
  error.UnsupportedTranslation, error.UnsupportedType => {
826
934
  return t.failDecl(scope, variable.name_tok, name, "unable to resolve var init expr", .{});
827
935
  },
828
936
  else => |e| return e,
829
937
  };
830
938
 
831
- if (!variable.qt.is(t.comp, .bool) and init_node.isBoolRes()) {
832
- break :init try ZigTag.int_from_bool.create(t.arena, init_node);
833
- } else {
834
- break :init init_node;
835
- }
939
+ break :init try t.toNonBool(init_node, variable.qt);
836
940
  }
837
941
  if (variable.storage_class == .@"extern") {
838
942
  if (array_ty != null and array_ty.?.len == .incomplete) {
@@ -876,7 +980,7 @@ fn transVarDecl(t: *Translator, scope: *Scope, variable: Node.Variable) Error!vo
876
980
  const alignment: ?c_uint = variable.qt.requestedAlignment(t.comp) orelse null;
877
981
  var node = try ZigTag.var_decl.create(t.arena, .{
878
982
  .is_pub = toplevel,
879
- .is_const = is_const,
983
+ .is_const = is_const and !self_referential,
880
984
  .is_extern = is_extern,
881
985
  .is_export = toplevel and variable.storage_class == .auto and linkage == .strong,
882
986
  .is_threadlocal = variable.thread_local,
@@ -894,6 +998,21 @@ fn transVarDecl(t: *Translator, scope: *Scope, variable: Node.Variable) Error!vo
894
998
  node = try ZigTag.wrapped_local.create(t.arena, .{ .name = name, .init = node });
895
999
  }
896
1000
  try scope.appendNode(node);
1001
+ if (self_referential) {
1002
+ const deferred_init = t.transExprCoercing(scope, variable.initializer.?, .used) catch |err| switch (err) {
1003
+ error.SelfReferential => unreachable,
1004
+ error.UnsupportedTranslation, error.UnsupportedType => {
1005
+ return t.failDecl(scope, variable.name_tok, name, "unable to resolve var init expr", .{});
1006
+ },
1007
+ else => |e| return e,
1008
+ };
1009
+
1010
+ const assign = try ZigTag.assign.create(t.arena, .{
1011
+ .lhs = try ZigTag.identifier.create(t.arena, name),
1012
+ .rhs = try t.toNonBool(deferred_init, variable.qt),
1013
+ });
1014
+ try scope.appendNode(assign);
1015
+ }
897
1016
  try bs.discardVariable(name);
898
1017
 
899
1018
  if (variable.qt.getAttribute(t.comp, .cleanup)) |cleanup_attr| {
@@ -1001,6 +1120,7 @@ fn transEnumDecl(t: *Translator, scope: *Scope, enum_qt: QualType) Error!void {
1001
1120
 
1002
1121
  fn transStaticAssert(t: *Translator, scope: *Scope, static_assert: Node.StaticAssert) Error!void {
1003
1122
  const condition = t.transExpr(scope, static_assert.cond, .used) catch |err| switch (err) {
1123
+ error.SelfReferential => unreachable,
1004
1124
  error.UnsupportedTranslation, error.UnsupportedType => {
1005
1125
  return try t.warn(&t.global_scope.base, static_assert.cond.tok(t.tree), "unable to translate _Static_assert condition", .{});
1006
1126
  },
@@ -1084,21 +1204,17 @@ fn transType(t: *Translator, scope: *Scope, qt: QualType, source_loc: TokenIndex
1084
1204
  },
1085
1205
  .float => |float_ty| switch (float_ty) {
1086
1206
  .fp16, .float16 => return ZigTag.type.create(t.arena, "f16"),
1087
- .float => return ZigTag.type.create(t.arena, "f32"),
1088
- .double => return ZigTag.type.create(t.arena, "f64"),
1089
- .long_double => return ZigTag.type.create(t.arena, "c_longdouble"),
1207
+ .float, .float32 => return ZigTag.type.create(t.arena, "f32"),
1208
+ .double, .float64, .float32x => return ZigTag.type.create(t.arena, "f64"),
1209
+ .long_double, .float64x => return ZigTag.type.create(t.arena, "c_longdouble"),
1090
1210
  .float128 => return ZigTag.type.create(t.arena, "f128"),
1091
- .bf16,
1092
- .float32,
1093
- .float64,
1094
- .float32x,
1095
- .float64x,
1096
- .float128x,
1211
+ .bf16 => return t.fail(error.UnsupportedType, source_loc, "TODO support bfloat16", .{}),
1097
1212
  .dfloat32,
1098
1213
  .dfloat64,
1099
1214
  .dfloat128,
1100
1215
  .dfloat64x,
1101
- => return t.fail(error.UnsupportedType, source_loc, "TODO support float type: '{s}'", .{try t.getTypeStr(qt)}),
1216
+ => return t.fail(error.UnsupportedType, source_loc, "TODO support decimal float type: '{s}'", .{try t.getTypeStr(qt)}),
1217
+ .float128x => unreachable, // Unsupported on all targets
1102
1218
  },
1103
1219
  .pointer => |pointer_ty| {
1104
1220
  const child_qt = pointer_ty.child;
@@ -1173,9 +1289,21 @@ fn transType(t: *Translator, scope: *Scope, qt: QualType, source_loc: TokenIndex
1173
1289
  return ZigTag.identifier.create(t.arena, name);
1174
1290
  },
1175
1291
  .attributed => |attributed_ty| continue :loop attributed_ty.base.type(t.comp),
1176
- .typeof => |typeof_ty| continue :loop typeof_ty.base.type(t.comp),
1292
+ .typeof => |typeof_ty| {
1293
+ if (typeof_ty.expr) |expr| {
1294
+ if (t.transExpr(scope, expr, .used)) |node| {
1295
+ return ZigTag.typeof.create(t.arena, node);
1296
+ } else |err| switch (err) {
1297
+ error.SelfReferential => {},
1298
+ error.UnsupportedTranslation => {},
1299
+ error.UnsupportedType => {},
1300
+ error.OutOfMemory => |e| return e,
1301
+ }
1302
+ }
1303
+ continue :loop typeof_ty.base.type(t.comp);
1304
+ },
1177
1305
  .vector => |vector_ty| {
1178
- const len = try t.createNumberNode(vector_ty.len, .int);
1306
+ const len = try t.createNumberNode(vector_ty.len);
1179
1307
  const elem_type = try t.transType(scope, vector_ty.elem, source_loc);
1180
1308
  return ZigTag.vector.create(t.arena, .{ .lhs = len, .rhs = elem_type });
1181
1309
  },
@@ -1384,7 +1512,10 @@ fn transFnType(
1384
1512
  .is_var_args = switch (func_ty.kind) {
1385
1513
  .normal => false,
1386
1514
  .variadic => true,
1387
- .old_style => !ctx.is_export and !ctx.is_always_inline and !ctx.has_body,
1515
+ .old_style => if (t.comp.target.cpu.arch.isWasm())
1516
+ false
1517
+ else
1518
+ !ctx.is_export and !ctx.is_always_inline and !ctx.has_body,
1388
1519
  },
1389
1520
  .name = ctx.fn_name,
1390
1521
  .linksection_string = linksection_string,
@@ -1468,7 +1599,7 @@ fn typeIsOpaque(t: *Translator, qt: QualType) bool {
1468
1599
  }
1469
1600
 
1470
1601
  fn typeWasDemotedToOpaque(t: *Translator, qt: QualType) bool {
1471
- return t.opaque_demotes.contains(qt);
1602
+ return t.opaque_demotes.contains(qt.base(t.comp).qt);
1472
1603
  }
1473
1604
 
1474
1605
  fn typeHasWrappingOverflow(t: *Translator, qt: QualType) bool {
@@ -1531,16 +1662,30 @@ fn transStmt(t: *Translator, scope: *Scope, stmt: Node.Index) TransError!ZigNode
1531
1662
  try t.transRecordDecl(scope, record_decl.container_qt);
1532
1663
  return ZigTag.declaration.init();
1533
1664
  },
1665
+ .struct_forward_decl, .union_forward_decl => |record_decl| {
1666
+ if (record_decl.definition) |some| {
1667
+ return t.transStmt(scope, some);
1668
+ }
1669
+ try t.transRecordDecl(scope, record_decl.container_qt);
1670
+ return ZigTag.declaration.init();
1671
+ },
1534
1672
  .enum_decl => |enum_decl| {
1535
1673
  try t.transEnumDecl(scope, enum_decl.container_qt);
1536
1674
  return ZigTag.declaration.init();
1537
1675
  },
1676
+ .enum_forward_decl => |enum_decl| {
1677
+ if (enum_decl.definition) |some| {
1678
+ return t.transStmt(scope, some);
1679
+ }
1680
+ try t.transEnumDecl(scope, enum_decl.container_qt);
1681
+ return ZigTag.declaration.init();
1682
+ },
1538
1683
  .function => |function| {
1539
1684
  try t.transFnDecl(scope, function);
1540
1685
  return ZigTag.declaration.init();
1541
1686
  },
1542
1687
  .variable => |variable| {
1543
- try t.transVarDecl(scope, variable);
1688
+ try t.transVarDecl(scope, variable, stmt);
1544
1689
  return ZigTag.declaration.init();
1545
1690
  },
1546
1691
  .switch_stmt => |switch_stmt| return t.transSwitch(scope, switch_stmt),
@@ -1562,7 +1707,10 @@ fn transCompoundStmtInline(t: *Translator, compound: Node.CompoundStmt, block: *
1562
1707
  const result = try t.transStmt(&block.base, stmt);
1563
1708
  switch (result.tag()) {
1564
1709
  .declaration, .empty_block => {},
1565
- else => try block.statements.append(t.gpa, result),
1710
+ else => {
1711
+ try block.statements.append(t.gpa, result);
1712
+ if (result.isNoreturn()) return;
1713
+ },
1566
1714
  }
1567
1715
  }
1568
1716
  }
@@ -1578,12 +1726,9 @@ fn transReturnStmt(t: *Translator, scope: *Scope, return_stmt: Node.ReturnStmt)
1578
1726
  switch (return_stmt.operand) {
1579
1727
  .none => return ZigTag.return_void.init(),
1580
1728
  .expr => |operand| {
1581
- var rhs = try t.transExprCoercing(scope, operand, .used);
1729
+ const rhs = try t.transExprCoercing(scope, operand, .used);
1582
1730
  const return_qt = scope.findBlockReturnType();
1583
- if (rhs.isBoolRes() and !return_qt.is(t.comp, .bool)) {
1584
- rhs = try ZigTag.int_from_bool.create(t.arena, rhs);
1585
- }
1586
- return ZigTag.@"return".create(t.arena, rhs);
1731
+ return ZigTag.@"return".create(t.arena, try t.toNonBool(rhs, return_qt));
1587
1732
  },
1588
1733
  .implicit => |zero| {
1589
1734
  if (zero) return ZigTag.@"return".create(t.arena, ZigTag.zero_literal.init());
@@ -1698,7 +1843,7 @@ fn transDoWhileStmt(t: *Translator, scope: *Scope, do_stmt: Node.DoWhileStmt) Tr
1698
1843
  };
1699
1844
 
1700
1845
  var body_node = try t.transStmt(&loop_scope, do_stmt.body);
1701
- if (body_node.isNoreturn(true)) {
1846
+ if (body_node.isNoreturn()) {
1702
1847
  // The body node ends in a noreturn statement. Simply put it in a while (true)
1703
1848
  // in case it contains breaks or continues.
1704
1849
  } else if (do_stmt.body.get(t.tree) == .compound_stmt) {
@@ -1918,8 +2063,6 @@ fn transSwitchProngStmt(
1918
2063
  body: []const Node.Index,
1919
2064
  ) TransError!ZigNode {
1920
2065
  switch (stmt.get(t.tree)) {
1921
- .break_stmt => return ZigTag.@"break".init(),
1922
- .return_stmt => return t.transStmt(scope, stmt),
1923
2066
  .case_stmt, .default_stmt => unreachable,
1924
2067
  else => {
1925
2068
  var block_scope = try Scope.Block.init(t, scope, false);
@@ -1940,15 +2083,6 @@ fn transSwitchProngStmtInline(
1940
2083
  ) TransError!void {
1941
2084
  for (body) |stmt| {
1942
2085
  switch (stmt.get(t.tree)) {
1943
- .return_stmt => {
1944
- const result = try t.transStmt(&block.base, stmt);
1945
- try block.statements.append(t.gpa, result);
1946
- return;
1947
- },
1948
- .break_stmt => {
1949
- try block.statements.append(t.gpa, ZigTag.@"break".init());
1950
- return;
1951
- },
1952
2086
  .case_stmt => |case_stmt| {
1953
2087
  var sub = case_stmt.body;
1954
2088
  while (true) switch (sub.get(t.tree)) {
@@ -1959,7 +2093,7 @@ fn transSwitchProngStmtInline(
1959
2093
  const result = try t.transStmt(&block.base, sub);
1960
2094
  assert(result.tag() != .declaration);
1961
2095
  try block.statements.append(t.gpa, result);
1962
- if (result.isNoreturn(true)) return;
2096
+ if (result.isNoreturn()) return;
1963
2097
  },
1964
2098
  .default_stmt => |default_stmt| {
1965
2099
  var sub = default_stmt.body;
@@ -1971,18 +2105,16 @@ fn transSwitchProngStmtInline(
1971
2105
  const result = try t.transStmt(&block.base, sub);
1972
2106
  assert(result.tag() != .declaration);
1973
2107
  try block.statements.append(t.gpa, result);
1974
- if (result.isNoreturn(true)) return;
1975
- },
1976
- .compound_stmt => |compound_stmt| {
1977
- const result = try t.transCompoundStmt(&block.base, compound_stmt);
1978
- try block.statements.append(t.gpa, result);
1979
- if (result.isNoreturn(true)) return;
2108
+ if (result.isNoreturn()) return;
1980
2109
  },
1981
2110
  else => {
1982
2111
  const result = try t.transStmt(&block.base, stmt);
1983
2112
  switch (result.tag()) {
1984
2113
  .declaration, .empty_block => {},
1985
- else => try block.statements.append(t.gpa, result),
2114
+ else => {
2115
+ try block.statements.append(t.gpa, result);
2116
+ if (result.isNoreturn()) return;
2117
+ },
1986
2118
  }
1987
2119
  },
1988
2120
  }
@@ -2015,7 +2147,14 @@ fn transExpr(t: *Translator, scope: *Scope, expr: Node.Index, used: ResultUsed)
2015
2147
  break :res try ZigTag.deref.create(t.arena, try t.transExpr(scope, deref_expr.operand, .used));
2016
2148
  },
2017
2149
  .bool_not_expr => |bool_not_expr| try ZigTag.not.create(t.arena, try t.transBoolExpr(scope, bool_not_expr.operand)),
2018
- .bit_not_expr => |bit_not_expr| try ZigTag.bit_not.create(t.arena, try t.transExpr(scope, bit_not_expr.operand, .used)),
2150
+ .bit_not_expr => |bit_not_expr| try ZigTag.bit_not.create(t.arena, op: {
2151
+ const operand = try t.transExpr(scope, bit_not_expr.operand, .used);
2152
+ if (!operand.isBoolRes()) break :op operand;
2153
+
2154
+ const casted = try ZigTag.int_from_bool.create(t.arena, operand);
2155
+ const ty = try t.transType(scope, bit_not_expr.qt, bit_not_expr.op_tok);
2156
+ break :op try ZigTag.as.create(t.arena, .{ .lhs = ty, .rhs = casted });
2157
+ }),
2019
2158
  .plus_expr => |plus_expr| return t.transExpr(scope, plus_expr.operand, used),
2020
2159
  .negate_expr => |negate_expr| res: {
2021
2160
  const operand_qt = negate_expr.operand.qt(t.tree);
@@ -2109,8 +2248,8 @@ fn transExpr(t: *Translator, scope: *Scope, expr: Node.Index, used: ResultUsed)
2109
2248
  .shl_expr => |shl_expr| try t.transShiftExpr(scope, shl_expr, .shl),
2110
2249
  .shr_expr => |shr_expr| try t.transShiftExpr(scope, shr_expr, .shr),
2111
2250
 
2112
- .member_access_expr => |member_access| try t.transMemberAccess(scope, .normal, member_access, null),
2113
- .member_access_ptr_expr => |member_access| try t.transMemberAccess(scope, .ptr, member_access, null),
2251
+ .member_access_expr => |member_access| try t.transMemberAccess(scope, .normal, member_access, null, .accessor),
2252
+ .member_access_ptr_expr => |member_access| try t.transMemberAccess(scope, .ptr, member_access, null, .accessor),
2114
2253
  .array_access_expr => |array_access| try t.transArrayAccess(scope, array_access, null),
2115
2254
 
2116
2255
  .builtin_ref => unreachable,
@@ -2195,6 +2334,10 @@ fn transExpr(t: *Translator, scope: *Scope, expr: Node.Index, used: ResultUsed)
2195
2334
  .builtin_convertvector => |convertvector| try t.transConvertvectorExpr(scope, convertvector),
2196
2335
  .builtin_shufflevector => |shufflevector| try t.transShufflevectorExpr(scope, shufflevector),
2197
2336
 
2337
+ .builtin_va_arg_pack, .builtin_va_arg_pack_len => |va_arg_pack| {
2338
+ return t.fail(error.UnsupportedTranslation, va_arg_pack.builtin_tok, "TODO va arg pack", .{});
2339
+ },
2340
+
2198
2341
  .compound_stmt,
2199
2342
  .static_assert,
2200
2343
  .return_stmt,
@@ -2293,6 +2436,12 @@ fn transBoolExpr(t: *Translator, scope: *Scope, expr: Node.Index) TransError!Zig
2293
2436
  return t.finishBoolExpr(expr.qt(t.tree), maybe_bool_res);
2294
2437
  }
2295
2438
 
2439
+ fn toNonBool(t: *Translator, node: ZigNode, qt: QualType) Error!ZigNode {
2440
+ if (!node.isBoolRes()) return node;
2441
+ if (qt.is(t.comp, .bool)) return node;
2442
+ return ZigTag.int_from_bool.create(t.arena, node);
2443
+ }
2444
+
2296
2445
  fn finishBoolExpr(t: *Translator, qt: QualType, node: ZigNode) TransError!ZigNode {
2297
2446
  const sk = qt.scalarKind(t.comp);
2298
2447
  if (sk == .bool) return node;
@@ -2385,8 +2534,22 @@ fn transCastExpr(
2385
2534
  else => {},
2386
2535
  }
2387
2536
 
2388
- if (cast.operand.qt(t.tree).arrayLen(t.comp) == null) {
2389
- return try t.transExpr(scope, cast.operand, used);
2537
+ // Flexible array members are translated as member functions returning
2538
+ // [*c]T, so no address-of + @ptrCast wrapping is needed.
2539
+ flexible: {
2540
+ if (cast.operand.qt(t.tree).arrayLen(t.comp) == null) {
2541
+ return try t.transExpr(scope, cast.operand, used);
2542
+ }
2543
+
2544
+ const member_index, const base_qt = switch (cast.operand.get(t.tree)) {
2545
+ .member_access_expr => |ma| .{ ma.member_index, ma.base.qt(t.tree) },
2546
+ .member_access_ptr_expr => |ma| .{ ma.member_index, ma.base.qt(t.tree).childType(t.comp) },
2547
+ else => break :flexible,
2548
+ };
2549
+ const record = base_qt.getRecord(t.comp) orelse break :flexible;
2550
+ if (member_index != record.fields.len - 1 and base_qt.base(t.comp).type != .@"union") break :flexible;
2551
+ const array_ty = record.fields[member_index].qt.get(t.comp, .array) orelse break :flexible;
2552
+ if (t.isFlexibleArrayLen(array_ty.len)) return try t.transExpr(scope, cast.operand, used);
2390
2553
  }
2391
2554
 
2392
2555
  const sub_expr_node = try t.transExpr(scope, cast.operand, .used);
@@ -2402,6 +2565,8 @@ fn transCastExpr(
2402
2565
  .lhs = try ZigTag.type.create(t.arena, "usize"),
2403
2566
  .rhs = try ZigTag.int_cast.create(t.arena, sub_expr_node),
2404
2567
  });
2568
+ } else if (sub_expr_node.isBoolRes()) {
2569
+ sub_expr_node = try ZigTag.int_from_bool.create(t.arena, sub_expr_node);
2405
2570
  }
2406
2571
  break :int_to_pointer try ZigTag.ptr_from_int.create(t.arena, sub_expr_node);
2407
2572
  },
@@ -2560,6 +2725,8 @@ fn transPointerCastExpr(t: *Translator, scope: *Scope, expr: Node.Index) TransEr
2560
2725
  }
2561
2726
 
2562
2727
  fn transDeclRefExpr(t: *Translator, scope: *Scope, decl_ref: Node.DeclRef) TransError!ZigNode {
2728
+ if (t.wip_var_inits.contains(decl_ref.decl)) return error.SelfReferential;
2729
+
2563
2730
  const name = t.tree.tokSlice(decl_ref.name_tok);
2564
2731
  const maybe_alias = scope.getAlias(name);
2565
2732
  const mangled_name = maybe_alias orelse name;
@@ -2631,7 +2798,7 @@ fn transShiftExpr(t: *Translator, scope: *Scope, bin: Node.Binary, op_id: ZigTag
2631
2798
  // lhs >> @intCast(rh)
2632
2799
  const lhs = try t.transExpr(scope, bin.lhs, .used);
2633
2800
 
2634
- const rhs = try t.transExprCoercing(scope, bin.rhs, .used);
2801
+ const rhs = try t.transExpr(scope, bin.rhs, .used);
2635
2802
  const rhs_casted = try ZigTag.int_cast.create(t.arena, rhs);
2636
2803
 
2637
2804
  return t.createBinOpNode(op_id, lhs, rhs_casted);
@@ -2758,7 +2925,7 @@ fn transCommaExpr(t: *Translator, scope: *Scope, bin: Node.Binary, used: ResultU
2758
2925
  const rhs = try t.transExprCoercing(&block_scope.base, bin.rhs, .used);
2759
2926
  const break_node = try ZigTag.break_val.create(t.arena, .{
2760
2927
  .label = block_scope.label,
2761
- .val = rhs,
2928
+ .val = try t.toNonBool(rhs, bin.qt),
2762
2929
  });
2763
2930
  try block_scope.statements.append(t.gpa, break_node);
2764
2931
 
@@ -2768,14 +2935,10 @@ fn transCommaExpr(t: *Translator, scope: *Scope, bin: Node.Binary, used: ResultU
2768
2935
  fn transAssignExpr(t: *Translator, scope: *Scope, bin: Node.Binary, used: ResultUsed) !ZigNode {
2769
2936
  if (used == .unused) {
2770
2937
  const lhs = try t.transExpr(scope, bin.lhs, .used);
2771
- var rhs = try t.transExprCoercing(scope, bin.rhs, .used);
2938
+ const rhs = try t.transExprCoercing(scope, bin.rhs, .used);
2772
2939
 
2773
2940
  const lhs_qt = bin.lhs.qt(t.tree);
2774
- if (rhs.isBoolRes() and !lhs_qt.is(t.comp, .bool)) {
2775
- rhs = try ZigTag.int_from_bool.create(t.arena, rhs);
2776
- }
2777
-
2778
- return t.createBinOpNode(.assign, lhs, rhs);
2941
+ return t.createBinOpNode(.assign, lhs, try t.toNonBool(rhs, lhs_qt));
2779
2942
  }
2780
2943
 
2781
2944
  var block_scope = try Scope.Block.init(t, scope, true);
@@ -2783,13 +2946,12 @@ fn transAssignExpr(t: *Translator, scope: *Scope, bin: Node.Binary, used: Result
2783
2946
 
2784
2947
  const tmp = try block_scope.reserveMangledName("tmp");
2785
2948
 
2786
- var rhs = try t.transExpr(&block_scope.base, bin.rhs, .used);
2949
+ const rhs = try t.transExpr(&block_scope.base, bin.rhs, .used);
2787
2950
  const lhs_qt = bin.lhs.qt(t.tree);
2788
- if (rhs.isBoolRes() and !lhs_qt.is(t.comp, .bool)) {
2789
- rhs = try ZigTag.int_from_bool.create(t.arena, rhs);
2790
- }
2791
-
2792
- const tmp_decl = try ZigTag.var_simple.create(t.arena, .{ .name = tmp, .init = rhs });
2951
+ const tmp_decl = try ZigTag.var_simple.create(t.arena, .{
2952
+ .name = tmp,
2953
+ .init = try t.toNonBool(rhs, lhs_qt),
2954
+ });
2793
2955
  try block_scope.statements.append(t.gpa, tmp_decl);
2794
2956
 
2795
2957
  const lhs = try t.transExprCoercing(&block_scope.base, bin.lhs, .used);
@@ -3040,6 +3202,7 @@ fn transMemberAccess(
3040
3202
  kind: enum { normal, ptr },
3041
3203
  member_access: Node.MemberAccess,
3042
3204
  opt_base: ?ZigNode,
3205
+ flex_array_mode: enum { accessor, backing },
3043
3206
  ) TransError!ZigNode {
3044
3207
  const base_info = switch (kind) {
3045
3208
  .normal => member_access.base.qt(t.tree),
@@ -3068,8 +3231,14 @@ fn transMemberAccess(
3068
3231
  // Flexible array members are translated as member functions.
3069
3232
  if (member_access.member_index == record.fields.len - 1 or base_info.base(t.comp).type == .@"union") {
3070
3233
  if (field.qt.get(t.comp, .array)) |array_ty| {
3071
- if (array_ty.len == .incomplete or (array_ty.len == .fixed and array_ty.len.fixed == 0)) {
3072
- return ZigTag.call.create(t.arena, .{ .lhs = field_access, .args = &.{} });
3234
+ if (t.isFlexibleArrayLen(array_ty.len)) {
3235
+ switch (flex_array_mode) {
3236
+ .accessor => return ZigTag.call.create(t.arena, .{ .lhs = field_access, .args = &.{} }),
3237
+ .backing => {
3238
+ const backing_name = try std.fmt.allocPrint(t.arena, "_{s}", .{field_name});
3239
+ return ZigTag.field_access.create(t.arena, .{ .lhs = lhs, .field_name = backing_name });
3240
+ },
3241
+ }
3073
3242
  }
3074
3243
  }
3075
3244
  }
@@ -3091,7 +3260,7 @@ fn transArrayAccess(t: *Translator, scope: *Scope, array_access: Node.ArrayAcces
3091
3260
  const index = index: {
3092
3261
  const index = try t.transExpr(scope, array_access.index, .used);
3093
3262
  const index_qt = array_access.index.qt(t.tree);
3094
- const maybe_bigger_than_usize = switch (index_qt.base(t.comp).type) {
3263
+ const maybe_bigger_than_usize = type: switch (index_qt.base(t.comp).type) {
3095
3264
  .bool => {
3096
3265
  break :index try ZigTag.int_from_bool.create(t.arena, index);
3097
3266
  },
@@ -3100,6 +3269,7 @@ fn transArrayAccess(t: *Translator, scope: *Scope, array_access: Node.ArrayAcces
3100
3269
  else => false,
3101
3270
  },
3102
3271
  .bit_int => |bit_int| bit_int.bits > t.comp.target.ptrBitWidth(),
3272
+ .@"enum" => |e| if (e.tag) |tag| continue :type tag.base(t.comp).type else false,
3103
3273
  else => unreachable,
3104
3274
  };
3105
3275
 
@@ -3158,7 +3328,10 @@ fn transMemberDesignator(t: *Translator, scope: *Scope, arg: Node.Index) TransEr
3158
3328
  },
3159
3329
  .member_access_expr => |access| {
3160
3330
  const base = try t.transMemberDesignator(scope, access.base);
3161
- return t.transMemberAccess(scope, .normal, access, base);
3331
+ // In offsetof context, flexible array members must be accessed via
3332
+ // the backing field (`_name`) rather than the accessor function,
3333
+ // because you can't take the address of a function call result.
3334
+ return t.transMemberAccess(scope, .normal, access, base, .backing);
3162
3335
  },
3163
3336
  .cast => |cast| {
3164
3337
  assert(cast.kind == .array_to_pointer);
@@ -3292,6 +3465,51 @@ fn transCall(
3292
3465
 
3293
3466
  const SuppressCast = enum { with_as, no_as };
3294
3467
 
3468
+ /// Attempt to translate literal as the name of the simple macro
3469
+ /// it was expanded from.
3470
+ fn checkLiteralMacro(t: *Translator, tok: TokenIndex, used: ResultUsed) !?ZigNode {
3471
+ if (!t.keep_macro_literals) return null;
3472
+ const expansion_locs = t.pp.expansionSlice(tok);
3473
+ if (expansion_locs.len == 0) return null;
3474
+
3475
+ const last_expand = expansion_locs[0];
3476
+ const source = t.comp.getSource(last_expand.id);
3477
+ var tokenizer: aro.Tokenizer = .{
3478
+ .buf = source.buf,
3479
+ .langopts = t.comp.langopts,
3480
+ .source = last_expand.id,
3481
+ .index = last_expand.byte_offset,
3482
+ .splice_locs = &.{},
3483
+ };
3484
+ const name_tok = tokenizer.next();
3485
+ if (!name_tok.id.isMacroIdentifier()) return null;
3486
+
3487
+ const name = t.pp.tokSlice(name_tok);
3488
+ if (t.global_scope.containsNow(name)) return null;
3489
+ const macro = t.pp.defines.get(name) orelse return null;
3490
+ if (macro.is_func) return null;
3491
+ if (macro.isBuiltin()) return null;
3492
+
3493
+ var tok_count: u8 = 0;
3494
+ for (macro.tokens) |macro_tok| {
3495
+ switch (macro_tok.id) {
3496
+ .invalid => continue,
3497
+ .whitespace => continue,
3498
+ .comment => continue,
3499
+ .macro_ws => continue,
3500
+ else => {
3501
+ if (tok_count != 0) return null;
3502
+ tok_count += 1;
3503
+ },
3504
+ }
3505
+ }
3506
+
3507
+ if (t.checkTranslatableMacro(macro.tokens, macro.params) != null) return null;
3508
+
3509
+ const ident = try ZigTag.identifier.create(t.arena, name);
3510
+ return try t.maybeSuppressResult(used, ident);
3511
+ }
3512
+
3295
3513
  fn transIntLiteral(
3296
3514
  t: *Translator,
3297
3515
  scope: *Scope,
@@ -3299,6 +3517,7 @@ fn transIntLiteral(
3299
3517
  used: ResultUsed,
3300
3518
  suppress_as: SuppressCast,
3301
3519
  ) TransError!ZigNode {
3520
+ if (try t.checkLiteralMacro(literal_index.tok(t.tree), used)) |node| return node;
3302
3521
  const val = t.tree.value_map.get(literal_index).?;
3303
3522
  const int_lit_node = try t.createIntNode(val);
3304
3523
  if (suppress_as == .no_as) {
@@ -3325,6 +3544,7 @@ fn transCharLiteral(
3325
3544
  used: ResultUsed,
3326
3545
  suppress_as: SuppressCast,
3327
3546
  ) TransError!ZigNode {
3547
+ if (try t.checkLiteralMacro(literal_index.tok(t.tree), used)) |node| return node;
3328
3548
  const val = t.tree.value_map.get(literal_index).?;
3329
3549
  const char_literal = literal_index.get(t.tree).char_literal;
3330
3550
  const narrow = char_literal.kind == .ascii or char_literal.kind == .utf8;
@@ -3333,7 +3553,7 @@ fn transCharLiteral(
3333
3553
  // e.g. 'abcd'
3334
3554
  const int_value = val.toInt(u32, t.comp).?;
3335
3555
  const int_lit_node = if (char_literal.kind == .ascii and int_value > 255)
3336
- try t.createNumberNode(int_value, .int)
3556
+ try t.createNumberNode(int_value)
3337
3557
  else
3338
3558
  try t.createCharLiteralNode(narrow, int_value);
3339
3559
 
@@ -3357,12 +3577,16 @@ fn transFloatLiteral(
3357
3577
  used: ResultUsed,
3358
3578
  suppress_as: SuppressCast,
3359
3579
  ) TransError!ZigNode {
3580
+ if (try t.checkLiteralMacro(literal_index.tok(t.tree), used)) |node| return node;
3360
3581
  const val = t.tree.value_map.get(literal_index).?;
3361
3582
  const float_literal = literal_index.get(t.tree).float_literal;
3362
3583
 
3363
3584
  var allocating: std.Io.Writer.Allocating = .init(t.gpa);
3364
3585
  defer allocating.deinit();
3365
3586
  _ = val.print(float_literal.qt, t.comp, &allocating.writer) catch return error.OutOfMemory;
3587
+ if (mem.findScalar(u8, allocating.written(), '.') == null) {
3588
+ allocating.writer.writeAll(".0") catch return error.OutOfMemory;
3589
+ }
3366
3590
 
3367
3591
  const float_lit_node = try ZigTag.float_literal.create(t.arena, try t.arena.dupe(u8, allocating.written()));
3368
3592
  if (suppress_as == .no_as) {
@@ -3588,7 +3812,7 @@ fn transArrayInit(
3588
3812
  while (i < array_init.items.len) : (i += 1) {
3589
3813
  if (array_init.items[i].get(t.tree) == .array_filler_expr) break;
3590
3814
  const expr = try t.transExprCoercing(scope, array_init.items[i], .used);
3591
- try val_list.append(t.gpa, expr);
3815
+ try val_list.append(t.gpa, try t.toNonBool(expr, array_item_qt));
3592
3816
  }
3593
3817
  const array_type = try ZigTag.array_type.create(t.arena, .{
3594
3818
  .elem_type = array_item_type,
@@ -3638,7 +3862,7 @@ fn transUnionInit(
3638
3862
  const field_init = try t.arena.create(ast.Payload.ContainerInit.Initializer);
3639
3863
  field_init.* = .{
3640
3864
  .name = field_name,
3641
- .value = try t.transExprCoercing(scope, init_expr, .used),
3865
+ .value = try t.toNonBool(try t.transExprCoercing(scope, init_expr, .used), field.qt),
3642
3866
  };
3643
3867
  const container_init = try ZigTag.container_init.create(t.arena, .{
3644
3868
  .lhs = union_type,
@@ -3669,7 +3893,7 @@ fn transStructInit(
3669
3893
  }).? else field.name.lookup(t.comp);
3670
3894
  init.* = .{
3671
3895
  .name = field_name,
3672
- .value = try t.transExprCoercing(scope, field_expr, .used),
3896
+ .value = try t.toNonBool(try t.transExprCoercing(scope, field_expr, .used), field.qt),
3673
3897
  };
3674
3898
  }
3675
3899
 
@@ -3766,7 +3990,7 @@ fn transConvertvectorExpr(
3766
3990
  for (items, 0..dest_vec_ty.len) |*item, i| {
3767
3991
  const value = try ZigTag.array_access.create(t.arena, .{
3768
3992
  .lhs = tmp_ident,
3769
- .rhs = try t.createNumberNode(i, .int),
3993
+ .rhs = try t.createNumberNode(i),
3770
3994
  });
3771
3995
 
3772
3996
  if (src_elem_sk == .float and dest_elem_sk == .float) {
@@ -3812,7 +4036,7 @@ fn transShufflevectorExpr(
3812
4036
  const mask_len = shufflevector.indexes.len;
3813
4037
 
3814
4038
  const mask_type = try ZigTag.vector.create(t.arena, .{
3815
- .lhs = try t.createNumberNode(mask_len, .int),
4039
+ .lhs = try t.createNumberNode(mask_len),
3816
4040
  .rhs = try ZigTag.type.create(t.arena, "i32"),
3817
4041
  });
3818
4042
 
@@ -3875,23 +4099,16 @@ fn createIntNode(t: *Translator, int: aro.Value) !ZigNode {
3875
4099
  big.positive = true;
3876
4100
 
3877
4101
  const str = big.toStringAlloc(t.arena, 10, .lower) catch |err| switch (err) {
3878
- error.OutOfMemory => return error.OutOfMemory,
4102
+ error.OutOfMemory => |e| return e,
3879
4103
  };
3880
4104
  const res = try ZigTag.integer_literal.create(t.arena, str);
3881
4105
  if (is_negative) return ZigTag.negate.create(t.arena, res);
3882
4106
  return res;
3883
4107
  }
3884
4108
 
3885
- fn createNumberNode(t: *Translator, num: anytype, num_kind: enum { int, float }) !ZigNode {
3886
- const fmt_s = switch (@typeInfo(@TypeOf(num))) {
3887
- .int, .comptime_int => "{d}",
3888
- else => "{s}",
3889
- };
3890
- const str = try std.fmt.allocPrint(t.arena, fmt_s, .{num});
3891
- if (num_kind == .float)
3892
- return ZigTag.float_literal.create(t.arena, str)
3893
- else
3894
- return ZigTag.integer_literal.create(t.arena, str);
4109
+ fn createNumberNode(t: *Translator, num: anytype) !ZigNode {
4110
+ const str = try std.fmt.allocPrint(t.arena, "{d}", .{num});
4111
+ return ZigTag.integer_literal.create(t.arena, str);
3895
4112
  }
3896
4113
 
3897
4114
  fn createCharLiteralNode(t: *Translator, narrow: bool, val: u32) TransError!ZigNode {
@@ -3953,6 +4170,25 @@ fn vectorTypeInfo(t: *Translator, vec_node: ZigNode, field: []const u8) TransErr
3953
4170
  return ZigTag.field_access.create(t.arena, .{ .lhs = vector_type_info, .field_name = field });
3954
4171
  }
3955
4172
 
4173
+ /// Returns true if the given array length qualifies as a flexible array member
4174
+ /// under the current -fstrict-flex-arrays level.
4175
+ fn isFlexibleArrayLen(t: *const Translator, len: anytype) bool {
4176
+ return switch (t.strict_flex_arrays) {
4177
+ .@"0" => true,
4178
+ .@"1" => switch (len) {
4179
+ .incomplete => true,
4180
+ .fixed => |n| n <= 1,
4181
+ else => false,
4182
+ },
4183
+ .@"2" => switch (len) {
4184
+ .incomplete => true,
4185
+ .fixed => |n| n == 0,
4186
+ else => false,
4187
+ },
4188
+ .@"3" => len == .incomplete,
4189
+ };
4190
+ }
4191
+
3956
4192
  /// Build a getter function for a flexible array field in a C record
3957
4193
  /// e.g. `T items[]` or `T items[0]`. The generated function returns a [*c] pointer
3958
4194
  /// to the flexible array with the correct const and volatile qualifiers
@@ -3961,7 +4197,13 @@ fn createFlexibleMemberFn(
3961
4197
  member_name: []const u8,
3962
4198
  field_name: []const u8,
3963
4199
  ) Error!ZigNode {
3964
- const self_param_name = "self";
4200
+ // Use `_self` instead of the conventional `self` to avoid the Zig error
4201
+ // "function parameter shadows declaration of 'self'".
4202
+ // `processContainerMemberFns` merges C functions matching a struct's name
4203
+ // prefix into the struct as `pub const` aliases (e.g. `foo_self()` becomes
4204
+ // `pub const self = __root.foo_self`). A parameter also named `self` would
4205
+ // then shadow that declaration, which Zig rejects.
4206
+ const self_param_name = "_self";
3965
4207
  const self_param = try ZigTag.identifier.create(t.arena, self_param_name);
3966
4208
  const self_type = try ZigTag.typeof.create(t.arena, self_param);
3967
4209