@zigc/lib 0.16.0-test.1 → 0.16.0

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 (241) 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 +1 -17
  111. package/std/os/linux.zig +7 -2
  112. package/std/os/windows.zig +2 -2
  113. package/std/pdb.zig +143 -4
  114. package/std/posix.zig +6 -12
  115. package/std/priority_dequeue.zig +13 -12
  116. package/std/priority_queue.zig +5 -4
  117. package/std/process/Child.zig +1 -1
  118. package/std/process/Environ.zig +1 -1
  119. package/std/start.zig +17 -4
  120. package/std/std.zig +19 -6
  121. package/std/testing/FailingAllocator.zig +4 -4
  122. package/std/testing/Smith.zig +37 -2
  123. package/std/zig/Ast/Render.zig +186 -458
  124. package/std/zig/Ast.zig +0 -4
  125. package/std/zig/AstGen.zig +44 -7
  126. package/std/zig/AstSmith.zig +2602 -0
  127. package/std/zig/Client.zig +8 -3
  128. package/std/zig/Parse.zig +83 -74
  129. package/std/zig/Server.zig +26 -0
  130. package/std/zig/Zir.zig +17 -0
  131. package/std/zig/c_translation/helpers.zig +14 -9
  132. package/std/zig/llvm/Builder.zig +107 -48
  133. package/std/zig/system.zig +20 -4
  134. package/std/zig/tokenizer.zig +2 -1
  135. package/std/zig.zig +6 -0
  136. package/compiler/aro/aro/Driver/Filesystem.zig +0 -241
  137. package/libc/mingw/complex/cabs.c +0 -48
  138. package/libc/mingw/complex/cabsf.c +0 -48
  139. package/libc/mingw/complex/cacos.c +0 -50
  140. package/libc/mingw/complex/cacosf.c +0 -50
  141. package/libc/mingw/complex/carg.c +0 -48
  142. package/libc/mingw/complex/cargf.c +0 -48
  143. package/libc/mingw/complex/casin.c +0 -50
  144. package/libc/mingw/complex/casinf.c +0 -50
  145. package/libc/mingw/complex/catan.c +0 -50
  146. package/libc/mingw/complex/catanf.c +0 -50
  147. package/libc/mingw/complex/ccos.c +0 -50
  148. package/libc/mingw/complex/ccosf.c +0 -50
  149. package/libc/mingw/complex/cexp.c +0 -48
  150. package/libc/mingw/complex/cexpf.c +0 -48
  151. package/libc/mingw/complex/cimag.c +0 -48
  152. package/libc/mingw/complex/cimagf.c +0 -48
  153. package/libc/mingw/complex/clog.c +0 -48
  154. package/libc/mingw/complex/clog10.c +0 -49
  155. package/libc/mingw/complex/clog10f.c +0 -49
  156. package/libc/mingw/complex/clogf.c +0 -48
  157. package/libc/mingw/complex/conj.c +0 -48
  158. package/libc/mingw/complex/conjf.c +0 -48
  159. package/libc/mingw/complex/cpow.c +0 -48
  160. package/libc/mingw/complex/cpowf.c +0 -48
  161. package/libc/mingw/complex/cproj.c +0 -48
  162. package/libc/mingw/complex/cprojf.c +0 -48
  163. package/libc/mingw/complex/creal.c +0 -48
  164. package/libc/mingw/complex/crealf.c +0 -48
  165. package/libc/mingw/complex/csin.c +0 -50
  166. package/libc/mingw/complex/csinf.c +0 -50
  167. package/libc/mingw/complex/csqrt.c +0 -48
  168. package/libc/mingw/complex/csqrtf.c +0 -48
  169. package/libc/mingw/complex/ctan.c +0 -50
  170. package/libc/mingw/complex/ctanf.c +0 -50
  171. package/libc/mingw/math/arm/s_rint.c +0 -86
  172. package/libc/mingw/math/arm/s_rintf.c +0 -51
  173. package/libc/mingw/math/arm/sincos.S +0 -30
  174. package/libc/mingw/math/arm-common/sincosl.c +0 -13
  175. package/libc/mingw/math/arm64/rint.c +0 -12
  176. package/libc/mingw/math/arm64/rintf.c +0 -12
  177. package/libc/mingw/math/arm64/sincos.S +0 -32
  178. package/libc/mingw/math/bsd_private_base.h +0 -148
  179. package/libc/mingw/math/frexpf.c +0 -13
  180. package/libc/mingw/math/frexpl.c +0 -71
  181. package/libc/mingw/math/x86/acosf.c +0 -29
  182. package/libc/mingw/math/x86/atanf.c +0 -23
  183. package/libc/mingw/math/x86/atanl.c +0 -18
  184. package/libc/mingw/math/x86/cos.def.h +0 -65
  185. package/libc/mingw/math/x86/cosl.c +0 -46
  186. package/libc/mingw/math/x86/cosl_internal.S +0 -55
  187. package/libc/mingw/math/x86/ldexp.c +0 -23
  188. package/libc/mingw/math/x86/scalbn.S +0 -41
  189. package/libc/mingw/math/x86/scalbnf.S +0 -40
  190. package/libc/mingw/math/x86/sin.def.h +0 -65
  191. package/libc/mingw/math/x86/sinl.c +0 -46
  192. package/libc/mingw/math/x86/sinl_internal.S +0 -58
  193. package/libc/mingw/math/x86/tanl.S +0 -62
  194. package/libc/mingw/misc/btowc.c +0 -28
  195. package/libc/mingw/misc/wcstof.c +0 -66
  196. package/libc/mingw/misc/wcstoimax.c +0 -132
  197. package/libc/mingw/misc/wcstoumax.c +0 -126
  198. package/libc/mingw/misc/wctob.c +0 -29
  199. package/libc/mingw/misc/winbs_uint64.c +0 -6
  200. package/libc/mingw/misc/winbs_ulong.c +0 -6
  201. package/libc/mingw/misc/winbs_ushort.c +0 -6
  202. package/libc/mingw/stdio/_Exit.c +0 -10
  203. package/libc/mingw/stdio/_findfirst64i32.c +0 -21
  204. package/libc/mingw/stdio/_findnext64i32.c +0 -21
  205. package/libc/mingw/stdio/_fstat64i32.c +0 -37
  206. package/libc/mingw/stdio/_stat64i32.c +0 -37
  207. package/libc/mingw/stdio/_wfindfirst64i32.c +0 -21
  208. package/libc/mingw/stdio/_wfindnext64i32.c +0 -21
  209. package/libc/mingw/stdio/_wstat64i32.c +0 -37
  210. package/libc/musl/src/legacy/isastream.c +0 -7
  211. package/libc/musl/src/legacy/valloc.c +0 -8
  212. package/libc/musl/src/math/__cosl.c +0 -96
  213. package/libc/musl/src/math/__sinl.c +0 -78
  214. package/libc/musl/src/math/__tanl.c +0 -143
  215. package/libc/musl/src/math/aarch64/lrint.c +0 -10
  216. package/libc/musl/src/math/aarch64/lrintf.c +0 -10
  217. package/libc/musl/src/math/aarch64/rintf.c +0 -7
  218. package/libc/musl/src/math/cosl.c +0 -39
  219. package/libc/musl/src/math/fdim.c +0 -10
  220. package/libc/musl/src/math/finite.c +0 -7
  221. package/libc/musl/src/math/finitef.c +0 -7
  222. package/libc/musl/src/math/frexp.c +0 -23
  223. package/libc/musl/src/math/frexpf.c +0 -23
  224. package/libc/musl/src/math/frexpl.c +0 -29
  225. package/libc/musl/src/math/i386/lrint.c +0 -8
  226. package/libc/musl/src/math/i386/lrintf.c +0 -8
  227. package/libc/musl/src/math/i386/rintf.c +0 -7
  228. package/libc/musl/src/math/lrint.c +0 -72
  229. package/libc/musl/src/math/lrintf.c +0 -8
  230. package/libc/musl/src/math/powerpc64/lrint.c +0 -16
  231. package/libc/musl/src/math/powerpc64/lrintf.c +0 -16
  232. package/libc/musl/src/math/rintf.c +0 -30
  233. package/libc/musl/src/math/s390x/rintf.c +0 -15
  234. package/libc/musl/src/math/sincosl.c +0 -60
  235. package/libc/musl/src/math/sinl.c +0 -41
  236. package/libc/musl/src/math/tanl.c +0 -29
  237. package/libc/musl/src/math/x32/lrint.s +0 -5
  238. package/libc/musl/src/math/x32/lrintf.s +0 -5
  239. package/libc/musl/src/math/x86_64/lrint.c +0 -8
  240. package/libc/musl/src/math/x86_64/lrintf.c +0 -8
  241. package/libc/wasi/libc-bottom-half/sources/reallocarray.c +0 -14
@@ -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);
@@ -531,13 +624,6 @@ fn transRecordDecl(t: *Translator, scope: *Scope, record_qt: QualType) Error!voi
531
624
  break :init ZigTag.opaque_literal.init();
532
625
  }
533
626
 
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
627
  var field_name = field.name.lookup(t.comp);
542
628
  if (field.name_tok == 0) {
543
629
  field_name = try std.fmt.allocPrint(t.arena, "unnamed_{d}", .{unnamed_field_count});
@@ -548,23 +634,22 @@ fn transRecordDecl(t: *Translator, scope: *Scope, record_qt: QualType) Error!voi
548
634
  }, field_name);
549
635
  }
550
636
 
551
- const field_alignment = if (has_alignment_attributes)
552
- t.alignmentForField(record_ty, head_field_alignment, field_index)
553
- else
554
- null;
555
-
556
637
  const field_type = field_type: {
557
638
  // Check if this is a flexible array member.
558
639
  flexible: {
559
640
  if (field_index != record_ty.fields.len - 1 and container_kind != .@"union") break :flexible;
560
641
  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;
642
+ if (!t.isFlexibleArrayLen(array_ty.len)) break :flexible;
562
643
 
563
644
  const elem_type = t.transType(scope, array_ty.elem, field_loc) catch |err| switch (err) {
564
645
  error.UnsupportedType => break :flexible,
565
646
  else => |e| return e,
566
647
  };
567
- const zero_array = try ZigTag.array_type.create(t.arena, .{ .len = 0, .elem_type = elem_type });
648
+ const backing_array_len: usize = switch (array_ty.len) {
649
+ .fixed => |n| @intCast(n),
650
+ else => 0,
651
+ };
652
+ const backing_array = try ZigTag.array_type.create(t.arena, .{ .len = backing_array_len, .elem_type = elem_type });
568
653
 
569
654
  const member_name = field_name;
570
655
  field_name = try std.fmt.allocPrint(t.arena, "_{s}", .{field_name});
@@ -572,7 +657,7 @@ fn transRecordDecl(t: *Translator, scope: *Scope, record_qt: QualType) Error!voi
572
657
  const member = try t.createFlexibleMemberFn(member_name, field_name);
573
658
  try functions.append(t.gpa, member);
574
659
 
575
- break :field_type zero_array;
660
+ break :field_type backing_array;
576
661
  }
577
662
 
578
663
  break :field_type t.transType(scope, field.qt, field_loc) catch |err| switch (err) {
@@ -588,10 +673,22 @@ fn transRecordDecl(t: *Translator, scope: *Scope, record_qt: QualType) Error!voi
588
673
  };
589
674
  };
590
675
 
676
+ // Demote record to opaque if it contains an opaque field
677
+ if (t.typeWasDemotedToOpaque(field.qt)) {
678
+ try t.opaque_demotes.put(t.gpa, base.qt, {});
679
+ try t.warn(scope, field_loc, "{s} demoted to opaque type - has opaque field", .{container_kind_name});
680
+ break :init ZigTag.opaque_literal.init();
681
+ }
682
+
683
+ const field_alignment = if (has_alignment_attributes)
684
+ t.alignmentForField(record_ty, head_field_alignment, field_index)
685
+ else
686
+ null;
687
+
591
688
  // C99 introduced designated initializers for structs. Omitted fields are implicitly
592
689
  // initialized to zero. Some C APIs are designed with this in mind. Defaulting to zero
593
690
  // values for translated struct fields permits Zig code to comfortably use such an API.
594
- const default_value = if (container_kind == .@"struct")
691
+ const default_value = if (t.default_init and container_kind == .@"struct")
595
692
  try t.createZeroValueNode(field.qt, field_type, .no_as)
596
693
  else
597
694
  null;
@@ -616,7 +713,7 @@ fn transRecordDecl(t: *Translator, scope: *Scope, record_qt: QualType) Error!voi
616
713
  .name = "_padding",
617
714
  .type = try ZigTag.type.create(t.arena, try std.fmt.allocPrint(t.arena, "u{d}", .{padding_bits})),
618
715
  .alignment = @divExact(alignment_bits, 8),
619
- .default_value = if (container_kind == .@"struct")
716
+ .default_value = if (t.default_init and container_kind == .@"struct")
620
717
  ZigTag.zero_literal.init()
621
718
  else
622
719
  null,
@@ -663,14 +760,12 @@ fn transRecordDecl(t: *Translator, scope: *Scope, record_qt: QualType) Error!voi
663
760
  fn transFnDecl(t: *Translator, scope: *Scope, function: Node.Function) Error!void {
664
761
  const func_ty = function.qt.get(t.comp, .func).?;
665
762
 
666
- const is_pub = scope.id == .root;
667
-
668
763
  const fn_name = t.tree.tokSlice(function.name_tok);
669
764
  if (scope.getAlias(fn_name) != null or t.global_scope.containsNow(fn_name))
670
765
  return; // Avoid processing this decl twice
671
766
 
672
767
  const fn_decl_loc = function.name_tok;
673
- const has_body = function.body != null and func_ty.kind != .variadic;
768
+ const has_body = function.body != null and func_ty.kind != .variadic and t.func_bodies;
674
769
  if (function.body != null and func_ty.kind == .variadic) {
675
770
  try t.warn(scope, function.name_tok, "TODO unable to translate variadic function, demoted to extern", .{});
676
771
  }
@@ -681,7 +776,7 @@ fn transFnDecl(t: *Translator, scope: *Scope, function: Node.Function) Error!voi
681
776
  .is_always_inline = is_always_inline,
682
777
  .is_extern = !has_body,
683
778
  .is_export = !function.static and has_body and !is_always_inline and !function.@"inline",
684
- .is_pub = is_pub,
779
+ .is_pub = scope.id == .root and (!function.static or t.pub_static),
685
780
  .has_body = has_body,
686
781
  .cc = if (function.qt.getAttribute(t.comp, .calling_convention)) |some| switch (some.cc) {
687
782
  .c => .c,
@@ -761,6 +856,7 @@ fn transFnDecl(t: *Translator, scope: *Scope, function: Node.Function) Error!voi
761
856
 
762
857
  t.transCompoundStmtInline(body_stmt, &block_scope) catch |err| switch (err) {
763
858
  error.OutOfMemory => |e| return e,
859
+ error.SelfReferential => unreachable,
764
860
  error.UnsupportedTranslation,
765
861
  error.UnsupportedType,
766
862
  => {
@@ -777,7 +873,7 @@ fn transFnDecl(t: *Translator, scope: *Scope, function: Node.Function) Error!voi
777
873
  return t.addTopLevelDecl(fn_name, proto_node);
778
874
  }
779
875
 
780
- fn transVarDecl(t: *Translator, scope: *Scope, variable: Node.Variable) Error!void {
876
+ fn transVarDecl(t: *Translator, scope: *Scope, variable: Node.Variable, decl_node: Node.Index) Error!void {
781
877
  const base_name = t.tree.tokSlice(variable.name_tok);
782
878
  const toplevel = scope.id == .root;
783
879
  const bs: *Scope.Block = if (!toplevel) try scope.findBlockScope(t) else undefined;
@@ -815,24 +911,28 @@ fn transVarDecl(t: *Translator, scope: *Scope, variable: Node.Variable) Error!vo
815
911
  var is_const = variable.qt.@"const" or (array_ty != null and array_ty.?.elem.@"const");
816
912
  var is_extern = variable.storage_class == .@"extern";
817
913
 
914
+ var self_referential = false;
818
915
  const init_node = init: {
819
916
  if (variable.initializer) |init| {
820
917
  const maybe_literal = init.get(t.tree);
918
+ if (!toplevel) try t.wip_var_inits.putNoClobber(t.gpa, decl_node, {});
919
+ defer _ = t.wip_var_inits.remove(decl_node);
920
+
821
921
  const init_node = (if (maybe_literal == .string_literal_expr)
822
922
  t.transStringLiteralInitializer(init, maybe_literal.string_literal_expr, type_node)
823
923
  else
824
924
  t.transExprCoercing(scope, init, .used)) catch |err| switch (err) {
925
+ error.SelfReferential => {
926
+ self_referential = true;
927
+ break :init ZigTag.undefined_literal.init();
928
+ },
825
929
  error.UnsupportedTranslation, error.UnsupportedType => {
826
930
  return t.failDecl(scope, variable.name_tok, name, "unable to resolve var init expr", .{});
827
931
  },
828
932
  else => |e| return e,
829
933
  };
830
934
 
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
- }
935
+ break :init try t.toNonBool(init_node, variable.qt);
836
936
  }
837
937
  if (variable.storage_class == .@"extern") {
838
938
  if (array_ty != null and array_ty.?.len == .incomplete) {
@@ -876,7 +976,7 @@ fn transVarDecl(t: *Translator, scope: *Scope, variable: Node.Variable) Error!vo
876
976
  const alignment: ?c_uint = variable.qt.requestedAlignment(t.comp) orelse null;
877
977
  var node = try ZigTag.var_decl.create(t.arena, .{
878
978
  .is_pub = toplevel,
879
- .is_const = is_const,
979
+ .is_const = is_const and !self_referential,
880
980
  .is_extern = is_extern,
881
981
  .is_export = toplevel and variable.storage_class == .auto and linkage == .strong,
882
982
  .is_threadlocal = variable.thread_local,
@@ -894,6 +994,21 @@ fn transVarDecl(t: *Translator, scope: *Scope, variable: Node.Variable) Error!vo
894
994
  node = try ZigTag.wrapped_local.create(t.arena, .{ .name = name, .init = node });
895
995
  }
896
996
  try scope.appendNode(node);
997
+ if (self_referential) {
998
+ const deferred_init = t.transExprCoercing(scope, variable.initializer.?, .used) catch |err| switch (err) {
999
+ error.SelfReferential => unreachable,
1000
+ error.UnsupportedTranslation, error.UnsupportedType => {
1001
+ return t.failDecl(scope, variable.name_tok, name, "unable to resolve var init expr", .{});
1002
+ },
1003
+ else => |e| return e,
1004
+ };
1005
+
1006
+ const assign = try ZigTag.assign.create(t.arena, .{
1007
+ .lhs = try ZigTag.identifier.create(t.arena, name),
1008
+ .rhs = try t.toNonBool(deferred_init, variable.qt),
1009
+ });
1010
+ try scope.appendNode(assign);
1011
+ }
897
1012
  try bs.discardVariable(name);
898
1013
 
899
1014
  if (variable.qt.getAttribute(t.comp, .cleanup)) |cleanup_attr| {
@@ -1001,6 +1116,7 @@ fn transEnumDecl(t: *Translator, scope: *Scope, enum_qt: QualType) Error!void {
1001
1116
 
1002
1117
  fn transStaticAssert(t: *Translator, scope: *Scope, static_assert: Node.StaticAssert) Error!void {
1003
1118
  const condition = t.transExpr(scope, static_assert.cond, .used) catch |err| switch (err) {
1119
+ error.SelfReferential => unreachable,
1004
1120
  error.UnsupportedTranslation, error.UnsupportedType => {
1005
1121
  return try t.warn(&t.global_scope.base, static_assert.cond.tok(t.tree), "unable to translate _Static_assert condition", .{});
1006
1122
  },
@@ -1084,21 +1200,17 @@ fn transType(t: *Translator, scope: *Scope, qt: QualType, source_loc: TokenIndex
1084
1200
  },
1085
1201
  .float => |float_ty| switch (float_ty) {
1086
1202
  .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"),
1203
+ .float, .float32 => return ZigTag.type.create(t.arena, "f32"),
1204
+ .double, .float64, .float32x => return ZigTag.type.create(t.arena, "f64"),
1205
+ .long_double, .float64x => return ZigTag.type.create(t.arena, "c_longdouble"),
1090
1206
  .float128 => return ZigTag.type.create(t.arena, "f128"),
1091
- .bf16,
1092
- .float32,
1093
- .float64,
1094
- .float32x,
1095
- .float64x,
1096
- .float128x,
1207
+ .bf16 => return t.fail(error.UnsupportedType, source_loc, "TODO support bfloat16", .{}),
1097
1208
  .dfloat32,
1098
1209
  .dfloat64,
1099
1210
  .dfloat128,
1100
1211
  .dfloat64x,
1101
- => return t.fail(error.UnsupportedType, source_loc, "TODO support float type: '{s}'", .{try t.getTypeStr(qt)}),
1212
+ => return t.fail(error.UnsupportedType, source_loc, "TODO support decimal float type: '{s}'", .{try t.getTypeStr(qt)}),
1213
+ .float128x => unreachable, // Unsupported on all targets
1102
1214
  },
1103
1215
  .pointer => |pointer_ty| {
1104
1216
  const child_qt = pointer_ty.child;
@@ -1173,9 +1285,21 @@ fn transType(t: *Translator, scope: *Scope, qt: QualType, source_loc: TokenIndex
1173
1285
  return ZigTag.identifier.create(t.arena, name);
1174
1286
  },
1175
1287
  .attributed => |attributed_ty| continue :loop attributed_ty.base.type(t.comp),
1176
- .typeof => |typeof_ty| continue :loop typeof_ty.base.type(t.comp),
1288
+ .typeof => |typeof_ty| {
1289
+ if (typeof_ty.expr) |expr| {
1290
+ if (t.transExpr(scope, expr, .used)) |node| {
1291
+ return ZigTag.typeof.create(t.arena, node);
1292
+ } else |err| switch (err) {
1293
+ error.SelfReferential => {},
1294
+ error.UnsupportedTranslation => {},
1295
+ error.UnsupportedType => {},
1296
+ error.OutOfMemory => return error.OutOfMemory,
1297
+ }
1298
+ }
1299
+ continue :loop typeof_ty.base.type(t.comp);
1300
+ },
1177
1301
  .vector => |vector_ty| {
1178
- const len = try t.createNumberNode(vector_ty.len, .int);
1302
+ const len = try t.createNumberNode(vector_ty.len);
1179
1303
  const elem_type = try t.transType(scope, vector_ty.elem, source_loc);
1180
1304
  return ZigTag.vector.create(t.arena, .{ .lhs = len, .rhs = elem_type });
1181
1305
  },
@@ -1384,7 +1508,10 @@ fn transFnType(
1384
1508
  .is_var_args = switch (func_ty.kind) {
1385
1509
  .normal => false,
1386
1510
  .variadic => true,
1387
- .old_style => !ctx.is_export and !ctx.is_always_inline and !ctx.has_body,
1511
+ .old_style => if (t.comp.target.cpu.arch.isWasm())
1512
+ false
1513
+ else
1514
+ !ctx.is_export and !ctx.is_always_inline and !ctx.has_body,
1388
1515
  },
1389
1516
  .name = ctx.fn_name,
1390
1517
  .linksection_string = linksection_string,
@@ -1468,7 +1595,7 @@ fn typeIsOpaque(t: *Translator, qt: QualType) bool {
1468
1595
  }
1469
1596
 
1470
1597
  fn typeWasDemotedToOpaque(t: *Translator, qt: QualType) bool {
1471
- return t.opaque_demotes.contains(qt);
1598
+ return t.opaque_demotes.contains(qt.base(t.comp).qt);
1472
1599
  }
1473
1600
 
1474
1601
  fn typeHasWrappingOverflow(t: *Translator, qt: QualType) bool {
@@ -1531,16 +1658,30 @@ fn transStmt(t: *Translator, scope: *Scope, stmt: Node.Index) TransError!ZigNode
1531
1658
  try t.transRecordDecl(scope, record_decl.container_qt);
1532
1659
  return ZigTag.declaration.init();
1533
1660
  },
1661
+ .struct_forward_decl, .union_forward_decl => |record_decl| {
1662
+ if (record_decl.definition) |some| {
1663
+ return t.transStmt(scope, some);
1664
+ }
1665
+ try t.transRecordDecl(scope, record_decl.container_qt);
1666
+ return ZigTag.declaration.init();
1667
+ },
1534
1668
  .enum_decl => |enum_decl| {
1535
1669
  try t.transEnumDecl(scope, enum_decl.container_qt);
1536
1670
  return ZigTag.declaration.init();
1537
1671
  },
1672
+ .enum_forward_decl => |enum_decl| {
1673
+ if (enum_decl.definition) |some| {
1674
+ return t.transStmt(scope, some);
1675
+ }
1676
+ try t.transEnumDecl(scope, enum_decl.container_qt);
1677
+ return ZigTag.declaration.init();
1678
+ },
1538
1679
  .function => |function| {
1539
1680
  try t.transFnDecl(scope, function);
1540
1681
  return ZigTag.declaration.init();
1541
1682
  },
1542
1683
  .variable => |variable| {
1543
- try t.transVarDecl(scope, variable);
1684
+ try t.transVarDecl(scope, variable, stmt);
1544
1685
  return ZigTag.declaration.init();
1545
1686
  },
1546
1687
  .switch_stmt => |switch_stmt| return t.transSwitch(scope, switch_stmt),
@@ -1562,7 +1703,10 @@ fn transCompoundStmtInline(t: *Translator, compound: Node.CompoundStmt, block: *
1562
1703
  const result = try t.transStmt(&block.base, stmt);
1563
1704
  switch (result.tag()) {
1564
1705
  .declaration, .empty_block => {},
1565
- else => try block.statements.append(t.gpa, result),
1706
+ else => {
1707
+ try block.statements.append(t.gpa, result);
1708
+ if (result.isNoreturn()) return;
1709
+ },
1566
1710
  }
1567
1711
  }
1568
1712
  }
@@ -1578,12 +1722,9 @@ fn transReturnStmt(t: *Translator, scope: *Scope, return_stmt: Node.ReturnStmt)
1578
1722
  switch (return_stmt.operand) {
1579
1723
  .none => return ZigTag.return_void.init(),
1580
1724
  .expr => |operand| {
1581
- var rhs = try t.transExprCoercing(scope, operand, .used);
1725
+ const rhs = try t.transExprCoercing(scope, operand, .used);
1582
1726
  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);
1727
+ return ZigTag.@"return".create(t.arena, try t.toNonBool(rhs, return_qt));
1587
1728
  },
1588
1729
  .implicit => |zero| {
1589
1730
  if (zero) return ZigTag.@"return".create(t.arena, ZigTag.zero_literal.init());
@@ -1698,7 +1839,7 @@ fn transDoWhileStmt(t: *Translator, scope: *Scope, do_stmt: Node.DoWhileStmt) Tr
1698
1839
  };
1699
1840
 
1700
1841
  var body_node = try t.transStmt(&loop_scope, do_stmt.body);
1701
- if (body_node.isNoreturn(true)) {
1842
+ if (body_node.isNoreturn()) {
1702
1843
  // The body node ends in a noreturn statement. Simply put it in a while (true)
1703
1844
  // in case it contains breaks or continues.
1704
1845
  } else if (do_stmt.body.get(t.tree) == .compound_stmt) {
@@ -1918,8 +2059,6 @@ fn transSwitchProngStmt(
1918
2059
  body: []const Node.Index,
1919
2060
  ) TransError!ZigNode {
1920
2061
  switch (stmt.get(t.tree)) {
1921
- .break_stmt => return ZigTag.@"break".init(),
1922
- .return_stmt => return t.transStmt(scope, stmt),
1923
2062
  .case_stmt, .default_stmt => unreachable,
1924
2063
  else => {
1925
2064
  var block_scope = try Scope.Block.init(t, scope, false);
@@ -1940,15 +2079,6 @@ fn transSwitchProngStmtInline(
1940
2079
  ) TransError!void {
1941
2080
  for (body) |stmt| {
1942
2081
  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
2082
  .case_stmt => |case_stmt| {
1953
2083
  var sub = case_stmt.body;
1954
2084
  while (true) switch (sub.get(t.tree)) {
@@ -1959,7 +2089,7 @@ fn transSwitchProngStmtInline(
1959
2089
  const result = try t.transStmt(&block.base, sub);
1960
2090
  assert(result.tag() != .declaration);
1961
2091
  try block.statements.append(t.gpa, result);
1962
- if (result.isNoreturn(true)) return;
2092
+ if (result.isNoreturn()) return;
1963
2093
  },
1964
2094
  .default_stmt => |default_stmt| {
1965
2095
  var sub = default_stmt.body;
@@ -1971,18 +2101,16 @@ fn transSwitchProngStmtInline(
1971
2101
  const result = try t.transStmt(&block.base, sub);
1972
2102
  assert(result.tag() != .declaration);
1973
2103
  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;
2104
+ if (result.isNoreturn()) return;
1980
2105
  },
1981
2106
  else => {
1982
2107
  const result = try t.transStmt(&block.base, stmt);
1983
2108
  switch (result.tag()) {
1984
2109
  .declaration, .empty_block => {},
1985
- else => try block.statements.append(t.gpa, result),
2110
+ else => {
2111
+ try block.statements.append(t.gpa, result);
2112
+ if (result.isNoreturn()) return;
2113
+ },
1986
2114
  }
1987
2115
  },
1988
2116
  }
@@ -2015,7 +2143,14 @@ fn transExpr(t: *Translator, scope: *Scope, expr: Node.Index, used: ResultUsed)
2015
2143
  break :res try ZigTag.deref.create(t.arena, try t.transExpr(scope, deref_expr.operand, .used));
2016
2144
  },
2017
2145
  .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)),
2146
+ .bit_not_expr => |bit_not_expr| try ZigTag.bit_not.create(t.arena, op: {
2147
+ const operand = try t.transExpr(scope, bit_not_expr.operand, .used);
2148
+ if (!operand.isBoolRes()) break :op operand;
2149
+
2150
+ const casted = try ZigTag.int_from_bool.create(t.arena, operand);
2151
+ const ty = try t.transType(scope, bit_not_expr.qt, bit_not_expr.op_tok);
2152
+ break :op try ZigTag.as.create(t.arena, .{ .lhs = ty, .rhs = casted });
2153
+ }),
2019
2154
  .plus_expr => |plus_expr| return t.transExpr(scope, plus_expr.operand, used),
2020
2155
  .negate_expr => |negate_expr| res: {
2021
2156
  const operand_qt = negate_expr.operand.qt(t.tree);
@@ -2109,8 +2244,8 @@ fn transExpr(t: *Translator, scope: *Scope, expr: Node.Index, used: ResultUsed)
2109
2244
  .shl_expr => |shl_expr| try t.transShiftExpr(scope, shl_expr, .shl),
2110
2245
  .shr_expr => |shr_expr| try t.transShiftExpr(scope, shr_expr, .shr),
2111
2246
 
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),
2247
+ .member_access_expr => |member_access| try t.transMemberAccess(scope, .normal, member_access, null, .accessor),
2248
+ .member_access_ptr_expr => |member_access| try t.transMemberAccess(scope, .ptr, member_access, null, .accessor),
2114
2249
  .array_access_expr => |array_access| try t.transArrayAccess(scope, array_access, null),
2115
2250
 
2116
2251
  .builtin_ref => unreachable,
@@ -2195,6 +2330,10 @@ fn transExpr(t: *Translator, scope: *Scope, expr: Node.Index, used: ResultUsed)
2195
2330
  .builtin_convertvector => |convertvector| try t.transConvertvectorExpr(scope, convertvector),
2196
2331
  .builtin_shufflevector => |shufflevector| try t.transShufflevectorExpr(scope, shufflevector),
2197
2332
 
2333
+ .builtin_va_arg_pack, .builtin_va_arg_pack_len => |va_arg_pack| {
2334
+ return t.fail(error.UnsupportedTranslation, va_arg_pack.builtin_tok, "TODO va arg pack", .{});
2335
+ },
2336
+
2198
2337
  .compound_stmt,
2199
2338
  .static_assert,
2200
2339
  .return_stmt,
@@ -2293,6 +2432,12 @@ fn transBoolExpr(t: *Translator, scope: *Scope, expr: Node.Index) TransError!Zig
2293
2432
  return t.finishBoolExpr(expr.qt(t.tree), maybe_bool_res);
2294
2433
  }
2295
2434
 
2435
+ fn toNonBool(t: *Translator, node: ZigNode, qt: QualType) Error!ZigNode {
2436
+ if (!node.isBoolRes()) return node;
2437
+ if (qt.is(t.comp, .bool)) return node;
2438
+ return ZigTag.int_from_bool.create(t.arena, node);
2439
+ }
2440
+
2296
2441
  fn finishBoolExpr(t: *Translator, qt: QualType, node: ZigNode) TransError!ZigNode {
2297
2442
  const sk = qt.scalarKind(t.comp);
2298
2443
  if (sk == .bool) return node;
@@ -2385,8 +2530,22 @@ fn transCastExpr(
2385
2530
  else => {},
2386
2531
  }
2387
2532
 
2388
- if (cast.operand.qt(t.tree).arrayLen(t.comp) == null) {
2389
- return try t.transExpr(scope, cast.operand, used);
2533
+ // Flexible array members are translated as member functions returning
2534
+ // [*c]T, so no address-of + @ptrCast wrapping is needed.
2535
+ flexible: {
2536
+ if (cast.operand.qt(t.tree).arrayLen(t.comp) == null) {
2537
+ return try t.transExpr(scope, cast.operand, used);
2538
+ }
2539
+
2540
+ const member_index, const base_qt = switch (cast.operand.get(t.tree)) {
2541
+ .member_access_expr => |ma| .{ ma.member_index, ma.base.qt(t.tree) },
2542
+ .member_access_ptr_expr => |ma| .{ ma.member_index, ma.base.qt(t.tree).childType(t.comp) },
2543
+ else => break :flexible,
2544
+ };
2545
+ const record = base_qt.getRecord(t.comp) orelse break :flexible;
2546
+ if (member_index != record.fields.len - 1 and base_qt.base(t.comp).type != .@"union") break :flexible;
2547
+ const array_ty = record.fields[member_index].qt.get(t.comp, .array) orelse break :flexible;
2548
+ if (t.isFlexibleArrayLen(array_ty.len)) return try t.transExpr(scope, cast.operand, used);
2390
2549
  }
2391
2550
 
2392
2551
  const sub_expr_node = try t.transExpr(scope, cast.operand, .used);
@@ -2402,6 +2561,8 @@ fn transCastExpr(
2402
2561
  .lhs = try ZigTag.type.create(t.arena, "usize"),
2403
2562
  .rhs = try ZigTag.int_cast.create(t.arena, sub_expr_node),
2404
2563
  });
2564
+ } else if (sub_expr_node.isBoolRes()) {
2565
+ sub_expr_node = try ZigTag.int_from_bool.create(t.arena, sub_expr_node);
2405
2566
  }
2406
2567
  break :int_to_pointer try ZigTag.ptr_from_int.create(t.arena, sub_expr_node);
2407
2568
  },
@@ -2560,6 +2721,8 @@ fn transPointerCastExpr(t: *Translator, scope: *Scope, expr: Node.Index) TransEr
2560
2721
  }
2561
2722
 
2562
2723
  fn transDeclRefExpr(t: *Translator, scope: *Scope, decl_ref: Node.DeclRef) TransError!ZigNode {
2724
+ if (t.wip_var_inits.contains(decl_ref.decl)) return error.SelfReferential;
2725
+
2563
2726
  const name = t.tree.tokSlice(decl_ref.name_tok);
2564
2727
  const maybe_alias = scope.getAlias(name);
2565
2728
  const mangled_name = maybe_alias orelse name;
@@ -2631,7 +2794,7 @@ fn transShiftExpr(t: *Translator, scope: *Scope, bin: Node.Binary, op_id: ZigTag
2631
2794
  // lhs >> @intCast(rh)
2632
2795
  const lhs = try t.transExpr(scope, bin.lhs, .used);
2633
2796
 
2634
- const rhs = try t.transExprCoercing(scope, bin.rhs, .used);
2797
+ const rhs = try t.transExpr(scope, bin.rhs, .used);
2635
2798
  const rhs_casted = try ZigTag.int_cast.create(t.arena, rhs);
2636
2799
 
2637
2800
  return t.createBinOpNode(op_id, lhs, rhs_casted);
@@ -2758,7 +2921,7 @@ fn transCommaExpr(t: *Translator, scope: *Scope, bin: Node.Binary, used: ResultU
2758
2921
  const rhs = try t.transExprCoercing(&block_scope.base, bin.rhs, .used);
2759
2922
  const break_node = try ZigTag.break_val.create(t.arena, .{
2760
2923
  .label = block_scope.label,
2761
- .val = rhs,
2924
+ .val = try t.toNonBool(rhs, bin.qt),
2762
2925
  });
2763
2926
  try block_scope.statements.append(t.gpa, break_node);
2764
2927
 
@@ -2768,14 +2931,10 @@ fn transCommaExpr(t: *Translator, scope: *Scope, bin: Node.Binary, used: ResultU
2768
2931
  fn transAssignExpr(t: *Translator, scope: *Scope, bin: Node.Binary, used: ResultUsed) !ZigNode {
2769
2932
  if (used == .unused) {
2770
2933
  const lhs = try t.transExpr(scope, bin.lhs, .used);
2771
- var rhs = try t.transExprCoercing(scope, bin.rhs, .used);
2934
+ const rhs = try t.transExprCoercing(scope, bin.rhs, .used);
2772
2935
 
2773
2936
  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);
2937
+ return t.createBinOpNode(.assign, lhs, try t.toNonBool(rhs, lhs_qt));
2779
2938
  }
2780
2939
 
2781
2940
  var block_scope = try Scope.Block.init(t, scope, true);
@@ -2783,13 +2942,12 @@ fn transAssignExpr(t: *Translator, scope: *Scope, bin: Node.Binary, used: Result
2783
2942
 
2784
2943
  const tmp = try block_scope.reserveMangledName("tmp");
2785
2944
 
2786
- var rhs = try t.transExpr(&block_scope.base, bin.rhs, .used);
2945
+ const rhs = try t.transExpr(&block_scope.base, bin.rhs, .used);
2787
2946
  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 });
2947
+ const tmp_decl = try ZigTag.var_simple.create(t.arena, .{
2948
+ .name = tmp,
2949
+ .init = try t.toNonBool(rhs, lhs_qt),
2950
+ });
2793
2951
  try block_scope.statements.append(t.gpa, tmp_decl);
2794
2952
 
2795
2953
  const lhs = try t.transExprCoercing(&block_scope.base, bin.lhs, .used);
@@ -3040,6 +3198,7 @@ fn transMemberAccess(
3040
3198
  kind: enum { normal, ptr },
3041
3199
  member_access: Node.MemberAccess,
3042
3200
  opt_base: ?ZigNode,
3201
+ flex_array_mode: enum { accessor, backing },
3043
3202
  ) TransError!ZigNode {
3044
3203
  const base_info = switch (kind) {
3045
3204
  .normal => member_access.base.qt(t.tree),
@@ -3068,8 +3227,14 @@ fn transMemberAccess(
3068
3227
  // Flexible array members are translated as member functions.
3069
3228
  if (member_access.member_index == record.fields.len - 1 or base_info.base(t.comp).type == .@"union") {
3070
3229
  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 = &.{} });
3230
+ if (t.isFlexibleArrayLen(array_ty.len)) {
3231
+ switch (flex_array_mode) {
3232
+ .accessor => return ZigTag.call.create(t.arena, .{ .lhs = field_access, .args = &.{} }),
3233
+ .backing => {
3234
+ const backing_name = try std.fmt.allocPrint(t.arena, "_{s}", .{field_name});
3235
+ return ZigTag.field_access.create(t.arena, .{ .lhs = lhs, .field_name = backing_name });
3236
+ },
3237
+ }
3073
3238
  }
3074
3239
  }
3075
3240
  }
@@ -3091,7 +3256,7 @@ fn transArrayAccess(t: *Translator, scope: *Scope, array_access: Node.ArrayAcces
3091
3256
  const index = index: {
3092
3257
  const index = try t.transExpr(scope, array_access.index, .used);
3093
3258
  const index_qt = array_access.index.qt(t.tree);
3094
- const maybe_bigger_than_usize = switch (index_qt.base(t.comp).type) {
3259
+ const maybe_bigger_than_usize = type: switch (index_qt.base(t.comp).type) {
3095
3260
  .bool => {
3096
3261
  break :index try ZigTag.int_from_bool.create(t.arena, index);
3097
3262
  },
@@ -3100,6 +3265,7 @@ fn transArrayAccess(t: *Translator, scope: *Scope, array_access: Node.ArrayAcces
3100
3265
  else => false,
3101
3266
  },
3102
3267
  .bit_int => |bit_int| bit_int.bits > t.comp.target.ptrBitWidth(),
3268
+ .@"enum" => |e| if (e.tag) |tag| continue :type tag.base(t.comp).type else false,
3103
3269
  else => unreachable,
3104
3270
  };
3105
3271
 
@@ -3158,7 +3324,10 @@ fn transMemberDesignator(t: *Translator, scope: *Scope, arg: Node.Index) TransEr
3158
3324
  },
3159
3325
  .member_access_expr => |access| {
3160
3326
  const base = try t.transMemberDesignator(scope, access.base);
3161
- return t.transMemberAccess(scope, .normal, access, base);
3327
+ // In offsetof context, flexible array members must be accessed via
3328
+ // the backing field (`_name`) rather than the accessor function,
3329
+ // because you can't take the address of a function call result.
3330
+ return t.transMemberAccess(scope, .normal, access, base, .backing);
3162
3331
  },
3163
3332
  .cast => |cast| {
3164
3333
  assert(cast.kind == .array_to_pointer);
@@ -3292,6 +3461,51 @@ fn transCall(
3292
3461
 
3293
3462
  const SuppressCast = enum { with_as, no_as };
3294
3463
 
3464
+ /// Attempt to translate literal as the name of the simple macro
3465
+ /// it was expanded from.
3466
+ fn checkLiteralMacro(t: *Translator, tok: TokenIndex, used: ResultUsed) !?ZigNode {
3467
+ if (!t.keep_macro_literals) return null;
3468
+ const expansion_locs = t.pp.expansionSlice(tok);
3469
+ if (expansion_locs.len == 0) return null;
3470
+
3471
+ const last_expand = expansion_locs[0];
3472
+ const source = t.comp.getSource(last_expand.id);
3473
+ var tokenizer: aro.Tokenizer = .{
3474
+ .buf = source.buf,
3475
+ .langopts = t.comp.langopts,
3476
+ .source = last_expand.id,
3477
+ .index = last_expand.byte_offset,
3478
+ .splice_locs = &.{},
3479
+ };
3480
+ const name_tok = tokenizer.next();
3481
+ if (!name_tok.id.isMacroIdentifier()) return null;
3482
+
3483
+ const name = t.pp.tokSlice(name_tok);
3484
+ if (t.global_scope.containsNow(name)) return null;
3485
+ const macro = t.pp.defines.get(name) orelse return null;
3486
+ if (macro.is_func) return null;
3487
+ if (macro.isBuiltin()) return null;
3488
+
3489
+ var tok_count: u8 = 0;
3490
+ for (macro.tokens) |macro_tok| {
3491
+ switch (macro_tok.id) {
3492
+ .invalid => continue,
3493
+ .whitespace => continue,
3494
+ .comment => continue,
3495
+ .macro_ws => continue,
3496
+ else => {
3497
+ if (tok_count != 0) return null;
3498
+ tok_count += 1;
3499
+ },
3500
+ }
3501
+ }
3502
+
3503
+ if (t.checkTranslatableMacro(macro.tokens, macro.params) != null) return null;
3504
+
3505
+ const ident = try ZigTag.identifier.create(t.arena, name);
3506
+ return try t.maybeSuppressResult(used, ident);
3507
+ }
3508
+
3295
3509
  fn transIntLiteral(
3296
3510
  t: *Translator,
3297
3511
  scope: *Scope,
@@ -3299,6 +3513,7 @@ fn transIntLiteral(
3299
3513
  used: ResultUsed,
3300
3514
  suppress_as: SuppressCast,
3301
3515
  ) TransError!ZigNode {
3516
+ if (try t.checkLiteralMacro(literal_index.tok(t.tree), used)) |node| return node;
3302
3517
  const val = t.tree.value_map.get(literal_index).?;
3303
3518
  const int_lit_node = try t.createIntNode(val);
3304
3519
  if (suppress_as == .no_as) {
@@ -3325,6 +3540,7 @@ fn transCharLiteral(
3325
3540
  used: ResultUsed,
3326
3541
  suppress_as: SuppressCast,
3327
3542
  ) TransError!ZigNode {
3543
+ if (try t.checkLiteralMacro(literal_index.tok(t.tree), used)) |node| return node;
3328
3544
  const val = t.tree.value_map.get(literal_index).?;
3329
3545
  const char_literal = literal_index.get(t.tree).char_literal;
3330
3546
  const narrow = char_literal.kind == .ascii or char_literal.kind == .utf8;
@@ -3333,7 +3549,7 @@ fn transCharLiteral(
3333
3549
  // e.g. 'abcd'
3334
3550
  const int_value = val.toInt(u32, t.comp).?;
3335
3551
  const int_lit_node = if (char_literal.kind == .ascii and int_value > 255)
3336
- try t.createNumberNode(int_value, .int)
3552
+ try t.createNumberNode(int_value)
3337
3553
  else
3338
3554
  try t.createCharLiteralNode(narrow, int_value);
3339
3555
 
@@ -3357,12 +3573,16 @@ fn transFloatLiteral(
3357
3573
  used: ResultUsed,
3358
3574
  suppress_as: SuppressCast,
3359
3575
  ) TransError!ZigNode {
3576
+ if (try t.checkLiteralMacro(literal_index.tok(t.tree), used)) |node| return node;
3360
3577
  const val = t.tree.value_map.get(literal_index).?;
3361
3578
  const float_literal = literal_index.get(t.tree).float_literal;
3362
3579
 
3363
3580
  var allocating: std.Io.Writer.Allocating = .init(t.gpa);
3364
3581
  defer allocating.deinit();
3365
3582
  _ = val.print(float_literal.qt, t.comp, &allocating.writer) catch return error.OutOfMemory;
3583
+ if (mem.findScalar(u8, allocating.written(), '.') == null) {
3584
+ allocating.writer.writeAll(".0") catch return error.OutOfMemory;
3585
+ }
3366
3586
 
3367
3587
  const float_lit_node = try ZigTag.float_literal.create(t.arena, try t.arena.dupe(u8, allocating.written()));
3368
3588
  if (suppress_as == .no_as) {
@@ -3588,7 +3808,7 @@ fn transArrayInit(
3588
3808
  while (i < array_init.items.len) : (i += 1) {
3589
3809
  if (array_init.items[i].get(t.tree) == .array_filler_expr) break;
3590
3810
  const expr = try t.transExprCoercing(scope, array_init.items[i], .used);
3591
- try val_list.append(t.gpa, expr);
3811
+ try val_list.append(t.gpa, try t.toNonBool(expr, array_item_qt));
3592
3812
  }
3593
3813
  const array_type = try ZigTag.array_type.create(t.arena, .{
3594
3814
  .elem_type = array_item_type,
@@ -3638,7 +3858,7 @@ fn transUnionInit(
3638
3858
  const field_init = try t.arena.create(ast.Payload.ContainerInit.Initializer);
3639
3859
  field_init.* = .{
3640
3860
  .name = field_name,
3641
- .value = try t.transExprCoercing(scope, init_expr, .used),
3861
+ .value = try t.toNonBool(try t.transExprCoercing(scope, init_expr, .used), field.qt),
3642
3862
  };
3643
3863
  const container_init = try ZigTag.container_init.create(t.arena, .{
3644
3864
  .lhs = union_type,
@@ -3669,7 +3889,7 @@ fn transStructInit(
3669
3889
  }).? else field.name.lookup(t.comp);
3670
3890
  init.* = .{
3671
3891
  .name = field_name,
3672
- .value = try t.transExprCoercing(scope, field_expr, .used),
3892
+ .value = try t.toNonBool(try t.transExprCoercing(scope, field_expr, .used), field.qt),
3673
3893
  };
3674
3894
  }
3675
3895
 
@@ -3766,7 +3986,7 @@ fn transConvertvectorExpr(
3766
3986
  for (items, 0..dest_vec_ty.len) |*item, i| {
3767
3987
  const value = try ZigTag.array_access.create(t.arena, .{
3768
3988
  .lhs = tmp_ident,
3769
- .rhs = try t.createNumberNode(i, .int),
3989
+ .rhs = try t.createNumberNode(i),
3770
3990
  });
3771
3991
 
3772
3992
  if (src_elem_sk == .float and dest_elem_sk == .float) {
@@ -3812,7 +4032,7 @@ fn transShufflevectorExpr(
3812
4032
  const mask_len = shufflevector.indexes.len;
3813
4033
 
3814
4034
  const mask_type = try ZigTag.vector.create(t.arena, .{
3815
- .lhs = try t.createNumberNode(mask_len, .int),
4035
+ .lhs = try t.createNumberNode(mask_len),
3816
4036
  .rhs = try ZigTag.type.create(t.arena, "i32"),
3817
4037
  });
3818
4038
 
@@ -3882,16 +4102,9 @@ fn createIntNode(t: *Translator, int: aro.Value) !ZigNode {
3882
4102
  return res;
3883
4103
  }
3884
4104
 
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);
4105
+ fn createNumberNode(t: *Translator, num: anytype) !ZigNode {
4106
+ const str = try std.fmt.allocPrint(t.arena, "{d}", .{num});
4107
+ return ZigTag.integer_literal.create(t.arena, str);
3895
4108
  }
3896
4109
 
3897
4110
  fn createCharLiteralNode(t: *Translator, narrow: bool, val: u32) TransError!ZigNode {
@@ -3953,6 +4166,25 @@ fn vectorTypeInfo(t: *Translator, vec_node: ZigNode, field: []const u8) TransErr
3953
4166
  return ZigTag.field_access.create(t.arena, .{ .lhs = vector_type_info, .field_name = field });
3954
4167
  }
3955
4168
 
4169
+ /// Returns true if the given array length qualifies as a flexible array member
4170
+ /// under the current -fstrict-flex-arrays level.
4171
+ fn isFlexibleArrayLen(t: *const Translator, len: anytype) bool {
4172
+ return switch (t.strict_flex_arrays) {
4173
+ .@"0" => true,
4174
+ .@"1" => switch (len) {
4175
+ .incomplete => true,
4176
+ .fixed => |n| n <= 1,
4177
+ else => false,
4178
+ },
4179
+ .@"2" => switch (len) {
4180
+ .incomplete => true,
4181
+ .fixed => |n| n == 0,
4182
+ else => false,
4183
+ },
4184
+ .@"3" => len == .incomplete,
4185
+ };
4186
+ }
4187
+
3956
4188
  /// Build a getter function for a flexible array field in a C record
3957
4189
  /// e.g. `T items[]` or `T items[0]`. The generated function returns a [*c] pointer
3958
4190
  /// to the flexible array with the correct const and volatile qualifiers
@@ -3961,7 +4193,13 @@ fn createFlexibleMemberFn(
3961
4193
  member_name: []const u8,
3962
4194
  field_name: []const u8,
3963
4195
  ) Error!ZigNode {
3964
- const self_param_name = "self";
4196
+ // Use `_self` instead of the conventional `self` to avoid the Zig error
4197
+ // "function parameter shadows declaration of 'self'".
4198
+ // `processContainerMemberFns` merges C functions matching a struct's name
4199
+ // prefix into the struct as `pub const` aliases (e.g. `foo_self()` becomes
4200
+ // `pub const self = __root.foo_self`). A parameter also named `self` would
4201
+ // then shadow that declaration, which Zig rejects.
4202
+ const self_param_name = "_self";
3965
4203
  const self_param = try ZigTag.identifier.create(t.arena, self_param_name);
3966
4204
  const self_type = try ZigTag.typeof.create(t.arena, self_param);
3967
4205