rubycc 1.0.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 (159) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +56 -0
  3. data/LICENSE.txt +21 -0
  4. data/NOTICE +52 -0
  5. data/README.md +208 -0
  6. data/data/README.md +117 -0
  7. data/data/r10_corpus_scan.json +4082 -0
  8. data/data/r10_manual_classification.json +5342 -0
  9. data/data/r10_verification_m4a.json +1531 -0
  10. data/data/r10_verification_m4b.json +1818 -0
  11. data/data/r10_verification_m4c.json +1489 -0
  12. data/data/r10_verification_m4d.json +318 -0
  13. data/data/r10_verification_rbs.json +192 -0
  14. data/data/verified_gems.json +397 -0
  15. data/exe/rmake +16 -0
  16. data/exe/rubycc +9 -0
  17. data/exe/rubycc-ar +114 -0
  18. data/exe/rubycc-doctor +14 -0
  19. data/exe/rubycc-pkgconf +8 -0
  20. data/include/float.h +87 -0
  21. data/include/iso646.h +18 -0
  22. data/include/libc/alloca.h +18 -0
  23. data/include/libc/arpa/inet.h +61 -0
  24. data/include/libc/assert.h +43 -0
  25. data/include/libc/dirent.h +72 -0
  26. data/include/libc/dlfcn.h +58 -0
  27. data/include/libc/features.h +205 -0
  28. data/include/libc/glibc/aarch64/ctype.h +108 -0
  29. data/include/libc/glibc/aarch64/endian.h +54 -0
  30. data/include/libc/glibc/aarch64/errno.h +154 -0
  31. data/include/libc/glibc/aarch64/fcntl.h +144 -0
  32. data/include/libc/glibc/aarch64/inttypes.h +182 -0
  33. data/include/libc/glibc/aarch64/limits.h +63 -0
  34. data/include/libc/glibc/aarch64/pthread.h +131 -0
  35. data/include/libc/glibc/aarch64/setjmp.h +84 -0
  36. data/include/libc/glibc/aarch64/stdint.h +174 -0
  37. data/include/libc/glibc/aarch64/sys/epoll.h +88 -0
  38. data/include/libc/glibc/aarch64/sys/fcntl.h +19 -0
  39. data/include/libc/glibc/aarch64/sys/select.h +75 -0
  40. data/include/libc/glibc/aarch64/sys/stat.h +136 -0
  41. data/include/libc/glibc/aarch64/sys/syscall.h +167 -0
  42. data/include/libc/glibc/aarch64/sys/time.h +74 -0
  43. data/include/libc/glibc/aarch64/sys/types.h +127 -0
  44. data/include/libc/glibc/aarch64/time.h +113 -0
  45. data/include/libc/glibc/x86_64/ctype.h +108 -0
  46. data/include/libc/glibc/x86_64/endian.h +54 -0
  47. data/include/libc/glibc/x86_64/errno.h +154 -0
  48. data/include/libc/glibc/x86_64/fcntl.h +134 -0
  49. data/include/libc/glibc/x86_64/inttypes.h +182 -0
  50. data/include/libc/glibc/x86_64/limits.h +61 -0
  51. data/include/libc/glibc/x86_64/pthread.h +111 -0
  52. data/include/libc/glibc/x86_64/setjmp.h +82 -0
  53. data/include/libc/glibc/x86_64/stdint.h +163 -0
  54. data/include/libc/glibc/x86_64/sys/epoll.h +91 -0
  55. data/include/libc/glibc/x86_64/sys/fcntl.h +19 -0
  56. data/include/libc/glibc/x86_64/sys/select.h +75 -0
  57. data/include/libc/glibc/x86_64/sys/stat.h +130 -0
  58. data/include/libc/glibc/x86_64/sys/syscall.h +188 -0
  59. data/include/libc/glibc/x86_64/sys/time.h +74 -0
  60. data/include/libc/glibc/x86_64/sys/types.h +123 -0
  61. data/include/libc/glibc/x86_64/time.h +113 -0
  62. data/include/libc/grp.h +50 -0
  63. data/include/libc/langinfo.h +126 -0
  64. data/include/libc/link.h +18 -0
  65. data/include/libc/locale.h +83 -0
  66. data/include/libc/math.h +191 -0
  67. data/include/libc/netinet/in.h +126 -0
  68. data/include/libc/netinet/tcp.h +44 -0
  69. data/include/libc/poll.h +46 -0
  70. data/include/libc/pwd.h +58 -0
  71. data/include/libc/regex.h +53 -0
  72. data/include/libc/sched.h +35 -0
  73. data/include/libc/signal.h +204 -0
  74. data/include/libc/stdio.h +157 -0
  75. data/include/libc/stdlib.h +92 -0
  76. data/include/libc/string.h +74 -0
  77. data/include/libc/strings.h +25 -0
  78. data/include/libc/sys/cdefs.h +126 -0
  79. data/include/libc/sys/inotify.h +111 -0
  80. data/include/libc/sys/ioctl.h +36 -0
  81. data/include/libc/sys/mman.h +65 -0
  82. data/include/libc/sys/param.h +41 -0
  83. data/include/libc/sys/resource.h +109 -0
  84. data/include/libc/sys/socket.h +167 -0
  85. data/include/libc/sys/statfs.h +82 -0
  86. data/include/libc/sys/timerfd.h +55 -0
  87. data/include/libc/sys/uio.h +40 -0
  88. data/include/libc/sys/un.h +25 -0
  89. data/include/libc/sys/utsname.h +35 -0
  90. data/include/libc/sys/wait.h +135 -0
  91. data/include/libc/termios.h +179 -0
  92. data/include/libc/unistd.h +194 -0
  93. data/include/stdalign.h +16 -0
  94. data/include/stdarg.h +31 -0
  95. data/include/stdatomic.h +158 -0
  96. data/include/stdbool.h +15 -0
  97. data/include/stdckdint.h +28 -0
  98. data/include/stddef.h +60 -0
  99. data/include/stdnoreturn.h +18 -0
  100. data/include/x86intrin.h +16 -0
  101. data/lib/rubycc/backend/aarch64.rb +1724 -0
  102. data/lib/rubycc/backend/x86_64.rb +1369 -0
  103. data/lib/rubycc/compile_error.rb +36 -0
  104. data/lib/rubycc/compiler.rb +305 -0
  105. data/lib/rubycc/doctor/builder.rb +151 -0
  106. data/lib/rubycc/doctor/cli.rb +190 -0
  107. data/lib/rubycc/doctor/fetcher.rb +84 -0
  108. data/lib/rubycc/doctor/gemfile.rb +115 -0
  109. data/lib/rubycc/doctor/verified_gems.rb +114 -0
  110. data/lib/rubycc/doctor.rb +16 -0
  111. data/lib/rubycc/driver.rb +463 -0
  112. data/lib/rubycc/front/ast.rb +528 -0
  113. data/lib/rubycc/front/constant_evaluator.rb +631 -0
  114. data/lib/rubycc/front/initializer_resolver.rb +592 -0
  115. data/lib/rubycc/front/lexeme_reader.rb +460 -0
  116. data/lib/rubycc/front/lexer.rb +232 -0
  117. data/lib/rubycc/front/parser.rb +4122 -0
  118. data/lib/rubycc/front/token.rb +49 -0
  119. data/lib/rubycc/ir/call_convention.rb +486 -0
  120. data/lib/rubycc/ir/generator.rb +6036 -0
  121. data/lib/rubycc/ir/ir.rb +417 -0
  122. data/lib/rubycc/link/compat_runtime.rb +89 -0
  123. data/lib/rubycc/link/errors.rb +13 -0
  124. data/lib/rubycc/link/executable_linker.rb +405 -0
  125. data/lib/rubycc/link/library_resolver.rb +437 -0
  126. data/lib/rubycc/link/partial_linker.rb +546 -0
  127. data/lib/rubycc/link/shared_linker.rb +1732 -0
  128. data/lib/rubycc/mkmf_shim.rb +83 -0
  129. data/lib/rubycc/objfile/ar_archive.rb +437 -0
  130. data/lib/rubycc/objfile/elf_reader.rb +646 -0
  131. data/lib/rubycc/objfile/elf_writer.rb +891 -0
  132. data/lib/rubycc/objfile/relocatable_writer.rb +376 -0
  133. data/lib/rubycc/pkgconf/cli.rb +139 -0
  134. data/lib/rubycc/pkgconf/errors.rb +39 -0
  135. data/lib/rubycc/pkgconf/model.rb +28 -0
  136. data/lib/rubycc/pkgconf/parser.rb +109 -0
  137. data/lib/rubycc/pkgconf/pkgconf.rb +15 -0
  138. data/lib/rubycc/pkgconf/resolver.rb +70 -0
  139. data/lib/rubycc/pkgconf/search_path.rb +38 -0
  140. data/lib/rubycc/pkgconf/system_path_filter.rb +131 -0
  141. data/lib/rubycc/preprocess/constant_expression.rb +219 -0
  142. data/lib/rubycc/preprocess/glibc_version.rb +124 -0
  143. data/lib/rubycc/preprocess/pp_token.rb +62 -0
  144. data/lib/rubycc/preprocess/preprocessor.rb +2020 -0
  145. data/lib/rubycc/preprocess/scanner.rb +290 -0
  146. data/lib/rubycc/preprocess/token_converter.rb +157 -0
  147. data/lib/rubycc/rmake/cli.rb +143 -0
  148. data/lib/rubycc/rmake/errors.rb +71 -0
  149. data/lib/rubycc/rmake/executor.rb +818 -0
  150. data/lib/rubycc/rmake/expander.rb +251 -0
  151. data/lib/rubycc/rmake/makefile.rb +352 -0
  152. data/lib/rubycc/rmake/model.rb +137 -0
  153. data/lib/rubycc/rmake/parser.rb +226 -0
  154. data/lib/rubycc/rmake/rmake.rb +15 -0
  155. data/lib/rubycc/type.rb +1236 -0
  156. data/lib/rubycc/version.rb +5 -0
  157. data/lib/rubycc.rb +36 -0
  158. data/lib/rubygems_plugin.rb +102 -0
  159. metadata +219 -0
@@ -0,0 +1,1236 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rubycc
4
+ # The type system for this C subset: the standard integer types (char and its
5
+ # signed/unsigned variants, short, int, long and _Bool), the incomplete
6
+ # `void` type, pointers to another type, one-dimensional arrays of another
7
+ # type, and structures (Type::StructType). The integer, pointer and array
8
+ # types compare by value, so any two `int *` are equal, and each renders
9
+ # itself the way a C declarator would ("int", "unsigned long", "char *",
10
+ # "int [10]") for use in diagnostics. Structures instead compare by identity
11
+ # (see Type::StructType): a struct type is the same type only when it is the
12
+ # very same tag definition, which is what lets a self-referential struct
13
+ # ("struct node { struct node *next; }") describe itself without a
14
+ # value-equality walk looping forever.
15
+ #
16
+ # Every type but `void` and an incomplete struct reports its storage width in
17
+ # bytes via #size (char/_Bool 1, short 2, int 4, long 8, any pointer 8, an
18
+ # array its element width times its length, a struct its laid-out size) and
19
+ # its required boundary via #alignment (an integer type is aligned to its own
20
+ # width, any pointer 8, an array its element's alignment, a struct its widest
21
+ # member's). `void` has no size or alignment (see Type::VoidType) since it is
22
+ # only ever valid as a function's return type or as the target of a pointer;
23
+ # an incomplete struct likewise has neither until it is completed.
24
+ #
25
+ # #integer? groups the standard integer types that mix freely in expressions
26
+ # and convert to one another implicitly; #float? (FloatType) names the two
27
+ # floating types, and #arithmetic? is the union of the two — every integer or
28
+ # floating type — the notion "arithmetic" the usual arithmetic conversions act
29
+ # on. #signed? / #unsigned? report an integer type's signedness — the axis
30
+ # that decides signed vs unsigned division, right shift and comparison — and
31
+ # #bool? names `_Bool` specifically (whose only values are 0 and 1). #int? and
32
+ # #char? still name those two specific types (never their unsigned cousins),
33
+ # #void? names `void` and #struct? names a structure or a union (both are
34
+ # aggregates that share the same lvalue/copy machinery; #union? tells the two
35
+ # apart).
36
+ module Type
37
+ # A standard integer type, identified by its C spelling (`name`), its width
38
+ # in bytes (`size`, one of 1/2/4/8) and its signedness (`signed`). A single
39
+ # shared instance stands in for each type (Type::Int, Type::ULong, ...), so
40
+ # identity comparison doubles as value comparison; two variables both `int`
41
+ # name the very same object. `bool` singles out `_Bool`, whose values are
42
+ # constrained to 0 and 1.
43
+ #
44
+ # Value representation (see Backend::X86_64): an integer value narrower than
45
+ # 8 bytes lives in its virtual-register slot extended to (at least) 32 bits
46
+ # following this type's signedness — sign-extended when #signed?,
47
+ # zero-extended when #unsigned? — with the slot's bits 32..63 left
48
+ # indeterminate. An 8-byte value (long/unsigned long) uses the whole slot.
49
+ class IntegerType
50
+ attr_reader :name
51
+
52
+ def initialize(name, size, signed, bool: false)
53
+ @name = name
54
+ @size = size
55
+ @signed = signed
56
+ @bool = bool
57
+ end
58
+
59
+ def pointer?
60
+ false
61
+ end
62
+
63
+ # #int? and #char? name the plain `int` and `char` types alone, so an
64
+ # `unsigned int` is not #int? and neither `signed char` nor `unsigned char`
65
+ # is #char?; code that means "any integer" asks #integer? instead, and code
66
+ # that means "any character type" asks Type.character?. Plain `char` is
67
+ # #char? under either signedness, since both instances spell themselves the
68
+ # same way (see Type.plain_char).
69
+ def int?
70
+ @name == "int"
71
+ end
72
+
73
+ def char?
74
+ @name == "char"
75
+ end
76
+
77
+ def void?
78
+ false
79
+ end
80
+
81
+ def integer?
82
+ true
83
+ end
84
+
85
+ # Every integer type is an arithmetic type; #float? tells it apart from a
86
+ # floating one (see Type::FloatType), which is likewise #arithmetic? but
87
+ # not #integer?.
88
+ def arithmetic?
89
+ true
90
+ end
91
+
92
+ def float?
93
+ false
94
+ end
95
+
96
+ def signed?
97
+ @signed
98
+ end
99
+
100
+ def unsigned?
101
+ !@signed
102
+ end
103
+
104
+ def bool?
105
+ @bool
106
+ end
107
+
108
+ def array?
109
+ false
110
+ end
111
+
112
+ def struct?
113
+ false
114
+ end
115
+
116
+ def function?
117
+ false
118
+ end
119
+
120
+ def size
121
+ @size
122
+ end
123
+
124
+ # An integer type is aligned to its own width: char/_Bool 1, short 2,
125
+ # int 4, long 8.
126
+ def alignment
127
+ @size
128
+ end
129
+
130
+ # Each integer type is a shared singleton, so equality is normally
131
+ # identity. The one exception: a completed enum is an int object
132
+ # (6.7.2.2), so the plain `int` singleton is equal to any EnumType
133
+ # completed to int — this makes the equality symmetric with EnumType#==,
134
+ # so a function-type compatibility check matches whichever side holds the
135
+ # `int`. #eql?/#hash are left as identity, so this does not disturb the
136
+ # singletons' use as hash keys.
137
+ def ==(other)
138
+ return true if equal?(other)
139
+
140
+ int? && other.is_a?(EnumType) && other.complete?
141
+ end
142
+
143
+ def to_s
144
+ @name
145
+ end
146
+ end
147
+
148
+ # The incomplete `void` type. A single shared instance (Type::Void) stands
149
+ # in for every `void`. It is valid only as a function's return type or as
150
+ # the target of a pointer (`void *`); every other use (a variable, an
151
+ # array element, a non-pointer parameter, `sizeof(void)`, dereferencing a
152
+ # `void *`) is rejected by the parser or the generator rather than modelled
153
+ # here. It has no storage width: #size raises, since a well-formed program
154
+ # never asks a bare `void` for one.
155
+ class VoidType
156
+ def pointer?
157
+ false
158
+ end
159
+
160
+ def int?
161
+ false
162
+ end
163
+
164
+ def char?
165
+ false
166
+ end
167
+
168
+ def void?
169
+ true
170
+ end
171
+
172
+ def integer?
173
+ false
174
+ end
175
+
176
+ def arithmetic?
177
+ false
178
+ end
179
+
180
+ def float?
181
+ false
182
+ end
183
+
184
+ def bool?
185
+ false
186
+ end
187
+
188
+ def array?
189
+ false
190
+ end
191
+
192
+ def struct?
193
+ false
194
+ end
195
+
196
+ def function?
197
+ false
198
+ end
199
+
200
+ # `void` is incomplete and has no storage width; every call site that
201
+ # might reach a bare `void` here (sizeof, a global's layout, ...) rejects
202
+ # it first with a proper CompileError, so reaching this is a bug.
203
+ def size
204
+ raise "void has no size"
205
+ end
206
+
207
+ # `void` has no alignment for the same reason it has no size; a
208
+ # well-formed program never lays a bare `void` out in storage.
209
+ def alignment
210
+ raise "void has no alignment"
211
+ end
212
+
213
+ def to_s
214
+ "void"
215
+ end
216
+ end
217
+
218
+ # A floating type: `float` (4 bytes, IEEE754 single precision) or `double`
219
+ # (8 bytes, IEEE754 double precision). A single shared instance stands for
220
+ # each (Type::Float, Type::Double); being a Data, identity and value
221
+ # comparison coincide, so two `double`s name the very same type. `long
222
+ # double` normalizes to `double` at parse time (same width here), so no
223
+ # separate instance exists. #arithmetic? is true — a floating type mixes with
224
+ # the integer types under the usual arithmetic conversions — while #integer?
225
+ # is false and #float? true, which is how the generator tells a floating
226
+ # operand apart to emit the f-prefixed IR (:fadd, :flt, ...) and the
227
+ # integer/float conversions (:itof / :ftoi / :ftof).
228
+ #
229
+ # Value representation (see Backend::X86_64): a `float` value lives in its
230
+ # virtual-register slot's low 4 bytes as an IEEE754 single-precision bit
231
+ # pattern, a `double` in the whole 8-byte slot as a double-precision one; a
232
+ # `float`'s spare bits 32..63 follow the same indeterminate rule a narrow
233
+ # integer's do.
234
+ FloatType = Data.define(:name, :size) do
235
+ def pointer?
236
+ false
237
+ end
238
+
239
+ def int?
240
+ false
241
+ end
242
+
243
+ def char?
244
+ false
245
+ end
246
+
247
+ def void?
248
+ false
249
+ end
250
+
251
+ def integer?
252
+ false
253
+ end
254
+
255
+ def arithmetic?
256
+ true
257
+ end
258
+
259
+ def float?
260
+ true
261
+ end
262
+
263
+ def bool?
264
+ false
265
+ end
266
+
267
+ def array?
268
+ false
269
+ end
270
+
271
+ def struct?
272
+ false
273
+ end
274
+
275
+ def function?
276
+ false
277
+ end
278
+
279
+ # A floating type is aligned to its own width: float 4, double 8.
280
+ def alignment
281
+ size
282
+ end
283
+
284
+ def to_s
285
+ name
286
+ end
287
+ end
288
+
289
+ # The shared integer-type instances, one per distinct C type. LP64 governs
290
+ # the widths: int is 4 bytes, long and any pointer 8. `long long` normalizes
291
+ # to `long` (same width under LP64) at the point it is parsed, so no separate
292
+ # instance is needed here.
293
+ #
294
+ # The character types are three distinct types (6.2.5p15): `signed char` and
295
+ # `unsigned char` have a fixed signedness, while plain `char` behaves as one
296
+ # or the other, and which one is implementation-defined — pinned per ABI, so
297
+ # it is a property of the target rather than of this subset: the x86-64
298
+ # System V psABI makes plain `char` signed, AAPCS64 makes it unsigned. Both
299
+ # plain-`char` instances therefore exist side by side and spell themselves
300
+ # "char" (so #char?, #to_s and every diagnostic read alike whichever is in
301
+ # play); Type.plain_char picks the one a target uses, and the front end
302
+ # carries that choice from Compiler#compile down to every place a `char` type
303
+ # is built. Type::Char stays the signed one, which is what a caller with no
304
+ # target in hand (the default x86-64) means by "char".
305
+ Char = IntegerType.new("char", 1, true)
306
+ UnsignedChar = IntegerType.new("char", 1, false)
307
+ SChar = IntegerType.new("signed char", 1, true)
308
+ UChar = IntegerType.new("unsigned char", 1, false)
309
+ Short = IntegerType.new("short", 2, true)
310
+ UShort = IntegerType.new("unsigned short", 2, false)
311
+ Int = IntegerType.new("int", 4, true)
312
+ UInt = IntegerType.new("unsigned int", 4, false)
313
+ Long = IntegerType.new("long", 8, true)
314
+ ULong = IntegerType.new("unsigned long", 8, false)
315
+ # `_Bool` is treated as an unsigned 1-byte type whose stored value is only
316
+ # ever 0 or 1; a conversion to it lowers to "value != 0" (see the generator).
317
+ Bool = IntegerType.new("_Bool", 1, false, bool: true)
318
+
319
+ # The GNU 128-bit integer types (`__int128` and `unsigned __int128`), 16
320
+ # bytes wide and 16-byte aligned. They are ordinary IntegerTypes for
321
+ # classification (#integer?, #signed?, sizeof/_Alignof, the usual arithmetic
322
+ # conversions), but their value does not fit a single 64-bit slot: the
323
+ # generator represents a 128-bit value the way it represents a small struct —
324
+ # as a 16-byte stack object whose low eightbyte lives at +0 and high at +8,
325
+ # its address carried in an ordinary vreg — and lowers each supported
326
+ # operation to 64-bit ops on the two halves. The width alone (size 16) marks
327
+ # them apart from every other integer type; the generator's #wide128? tests it.
328
+ Int128 = IntegerType.new("__int128", 16, true)
329
+ UInt128 = IntegerType.new("unsigned __int128", 16, false)
330
+
331
+ # The shared floating-type instances (Type::Float, Type::Double).
332
+ Float = FloatType.new("float", 4)
333
+ Double = FloatType.new("double", 8)
334
+
335
+ # The lone `void`. Referred to everywhere as Type::Void.
336
+ Void = VoidType.new
337
+
338
+ # A pointer to `target` (itself a Type). Being a Data, two pointers are
339
+ # equal exactly when their targets are, giving "int *" == "int *".
340
+ Pointer = Data.define(:target) do
341
+ def pointer?
342
+ true
343
+ end
344
+
345
+ def int?
346
+ false
347
+ end
348
+
349
+ def char?
350
+ false
351
+ end
352
+
353
+ def void?
354
+ false
355
+ end
356
+
357
+ def integer?
358
+ false
359
+ end
360
+
361
+ def arithmetic?
362
+ false
363
+ end
364
+
365
+ def bool?
366
+ false
367
+ end
368
+
369
+ def array?
370
+ false
371
+ end
372
+
373
+ def struct?
374
+ false
375
+ end
376
+
377
+ def function?
378
+ false
379
+ end
380
+
381
+ def float?
382
+ false
383
+ end
384
+
385
+ # Every pointer is a 64-bit address, so 8 bytes wide.
386
+ def size
387
+ 8
388
+ end
389
+
390
+ # A 64-bit address is 8-byte aligned. A pointer to an incomplete type is
391
+ # still a complete, 8-byte pointer, which is exactly what lets a struct
392
+ # hold a pointer to itself.
393
+ def alignment
394
+ 8
395
+ end
396
+
397
+ # Renders as a C declarator. A pointer to a function or an array cannot be
398
+ # spelled by simply suffixing a "*", since the postfix "()" / "[]" would
399
+ # then bind tighter than the star; C parenthesizes the star instead, so a
400
+ # pointer to "int (int)" is written "int (*)(int)" and a pointer to
401
+ # "int [3]" is "int (*)[3]". Every other target uses the plain suffix form:
402
+ # a space before the first star, deeper levels stacking with no gap
403
+ # ("int *", "int **").
404
+ def to_s
405
+ if target.function?
406
+ "#{target.return_type} (*)(#{target.parameter_list_string})"
407
+ elsif target.array?
408
+ "#{target.element} (*)[#{target.length}]"
409
+ elsif target.pointer?
410
+ "#{target}*"
411
+ else
412
+ "#{target} *"
413
+ end
414
+ end
415
+ end
416
+
417
+ # A one-dimensional array of `length` elements, each of type `element`
418
+ # (itself a Type: an int or a pointer in this subset). Two arrays are equal
419
+ # when both their element type and length match.
420
+ #
421
+ # A `length` of nil is an *incomplete* array type (6.7.2.1): an unbounded
422
+ # "[]" whose element count is unknown. It reaches this subset as a struct's
423
+ # flexible array member (the last member, "T name[];", ISO C 6.7.2.1p18) and
424
+ # nowhere a size is needed — #size raises, and every path that could demand
425
+ # one (a variable, a plain sizeof/_Alignof of the array, an array-of-array
426
+ # element) is rejected first by the parser or the generator's completeness
427
+ # guard. A flexible array member still lays out (at its element's boundary,
428
+ # contributing nothing to the struct's size), and an lvalue of this type
429
+ # decays to a pointer to its element exactly as a bounded array does, so
430
+ # "p->fam[i]" indexes it.
431
+ Array = Data.define(:element, :length) do
432
+ def pointer?
433
+ false
434
+ end
435
+
436
+ def int?
437
+ false
438
+ end
439
+
440
+ def char?
441
+ false
442
+ end
443
+
444
+ def void?
445
+ false
446
+ end
447
+
448
+ def integer?
449
+ false
450
+ end
451
+
452
+ def arithmetic?
453
+ false
454
+ end
455
+
456
+ def bool?
457
+ false
458
+ end
459
+
460
+ def array?
461
+ true
462
+ end
463
+
464
+ def struct?
465
+ false
466
+ end
467
+
468
+ def function?
469
+ false
470
+ end
471
+
472
+ def float?
473
+ false
474
+ end
475
+
476
+ # Whether this is an incomplete array — an unbounded "[]" with no element
477
+ # count, the shape a struct's flexible array member takes. It has no size,
478
+ # so every size-needing use is diagnosed before #size would raise.
479
+ def incomplete?
480
+ length.nil?
481
+ end
482
+
483
+ # The whole array's byte size: the element width times the count. An
484
+ # incomplete array ("[]") has no count and therefore no size; every path
485
+ # that could reach one where a size is needed rejects it first with a
486
+ # proper diagnostic, so a raise here is a missing guard.
487
+ def size
488
+ raise "incomplete array has no size" if length.nil?
489
+
490
+ element.size * length
491
+ end
492
+
493
+ # An array is aligned like one of its elements: an `int [10]` on a 4-byte
494
+ # boundary, a `struct point [3]` on the struct's boundary.
495
+ def alignment
496
+ element.alignment
497
+ end
498
+
499
+ # Renders like a C array declarator: the element type, a space, then the
500
+ # bracketed length ("int [10]", "int * [4]"); an incomplete array shows an
501
+ # empty "[]" ("int []").
502
+ def to_s
503
+ "#{element} [#{length}]"
504
+ end
505
+ end
506
+
507
+ # A function type (6.7.6.3): its `return_type`, the ordered `param_types`
508
+ # (an array of the parameter Types after the array/function adjustments the
509
+ # parser applies — "(void)" and "()" both yield an empty array) and
510
+ # `variadic`, true for a prototype ending in "..." (a variable argument list
511
+ # after the named parameters, "int (const char *, ...)"). For a variadic
512
+ # type `param_types` holds only the fixed, named parameters. Being a Data,
513
+ # two function types are equal exactly when their return type, parameter
514
+ # types and variadic flag all match, so "int (int)" == "int (int)" but a
515
+ # variadic "int (int, ...)" differs from the fixed "int (int)"; this makes a
516
+ # function-pointer signature check reject a variadic/non-variadic mismatch on
517
+ # its own.
518
+ #
519
+ # A function type is not an object type: it has no storage width, so #size
520
+ # and #alignment raise (a well-formed program measures a *pointer* to a
521
+ # function, never the function itself, and the parser rejects a bare
522
+ # function type wherever an object is required). It is reached in this
523
+ # subset only through a pointer (a function pointer, Pointer with a
524
+ # FunctionType target) or as the very type a function declarator builds;
525
+ # #function? tells it apart from every object type.
526
+ FunctionType = Data.define(:return_type, :param_types, :variadic) do
527
+ def pointer?
528
+ false
529
+ end
530
+
531
+ def int?
532
+ false
533
+ end
534
+
535
+ def char?
536
+ false
537
+ end
538
+
539
+ def void?
540
+ false
541
+ end
542
+
543
+ def integer?
544
+ false
545
+ end
546
+
547
+ def arithmetic?
548
+ false
549
+ end
550
+
551
+ def bool?
552
+ false
553
+ end
554
+
555
+ def array?
556
+ false
557
+ end
558
+
559
+ def struct?
560
+ false
561
+ end
562
+
563
+ def function?
564
+ true
565
+ end
566
+
567
+ def float?
568
+ false
569
+ end
570
+
571
+ # A function type has no storage, so it cannot be laid out; every path
572
+ # that could reach one where a size is needed (sizeof, a member layout, a
573
+ # variable) rejects it first with a proper diagnostic, so a raise here is
574
+ # a missing guard.
575
+ def size
576
+ raise "function type has no size"
577
+ end
578
+
579
+ def alignment
580
+ raise "function type has no alignment"
581
+ end
582
+
583
+ # The parenthesized parameter list as it appears in a C declarator, used
584
+ # both by #to_s and by Pointer#to_s for a function pointer. An empty list
585
+ # renders "void" (a prototype taking no arguments); a variadic type ends
586
+ # in ", ..." after its named parameters ("char *, ..."). A variadic type
587
+ # always has at least one named parameter (ISO C forbids a lone "..."), so
588
+ # the empty-list "void" spelling is never variadic.
589
+ def parameter_list_string
590
+ return "..." if param_types.empty? && variadic
591
+
592
+ base = param_types.empty? ? "void" : param_types.map(&:to_s).join(", ")
593
+ variadic ? "#{base}, ..." : base
594
+ end
595
+
596
+ # Renders like a C function declarator with the name elided: the return
597
+ # type, a space, then the bracketed parameter list ("int (int, char *)",
598
+ # "void (void)").
599
+ def to_s
600
+ "#{return_type} (#{parameter_list_string})"
601
+ end
602
+ end
603
+
604
+ # An incomplete enumeration type: a reference to an "enum tag" whose
605
+ # enumerator list is not visible (a forward-referenced tag, or one never
606
+ # defined in the translation unit). A *complete* enum has no dedicated type
607
+ # here — an enum object is an int (6.7.2.2), so #parse_enum_specifier resolves
608
+ # a defined tag straight to Type::Int. This class exists only so an
609
+ # *incomplete* enum can flow exactly where an incomplete struct may (a
610
+ # pointer's target, a prototype's return type, an extern reference) while any
611
+ # use that needs a size or arithmetic still rejects it. It mirrors an
612
+ # incomplete StructType: every category predicate is false, #complete? is
613
+ # false, and #size/#alignment raise behind the generator's completeness
614
+ # guard. Two are equal when their tags match, so "enum E *" == "enum E *".
615
+ class EnumType
616
+ attr_reader :tag
617
+
618
+ def initialize(tag)
619
+ @tag = tag
620
+ @complete = false
621
+ end
622
+
623
+ def pointer?
624
+ false
625
+ end
626
+
627
+ def int?
628
+ false
629
+ end
630
+
631
+ def char?
632
+ false
633
+ end
634
+
635
+ def void?
636
+ false
637
+ end
638
+
639
+ # Once completed, an enum object is an int (6.7.2.2), so the integer
640
+ # predicates and measurements answer as `int` does. Before completion
641
+ # every one is false/raising, exactly as for any other incomplete type.
642
+ def integer?
643
+ @complete
644
+ end
645
+
646
+ def arithmetic?
647
+ @complete
648
+ end
649
+
650
+ def signed?
651
+ raise "incomplete enum has no signedness" unless @complete
652
+
653
+ true
654
+ end
655
+
656
+ def unsigned?
657
+ raise "incomplete enum has no signedness" unless @complete
658
+
659
+ false
660
+ end
661
+
662
+ def bool?
663
+ false
664
+ end
665
+
666
+ def array?
667
+ false
668
+ end
669
+
670
+ def struct?
671
+ false
672
+ end
673
+
674
+ def function?
675
+ false
676
+ end
677
+
678
+ def float?
679
+ false
680
+ end
681
+
682
+ # A forward-referenced enum tag ("enum efoo;" before its "{...}") is
683
+ # incomplete until #register_enum_tag sees the definition. A *defined* enum
684
+ # normally resolves straight to Type::Int, so completion is modeled on the
685
+ # object only for the one case that captured this incomplete type before
686
+ # the definition (a prototype's return type, "enum efoo it_real_fn(void)").
687
+ # #complete! then turns that very object into an int in place, so both the
688
+ # earlier reference and the later "enum efoo" (an int) agree.
689
+ def complete?
690
+ @complete
691
+ end
692
+
693
+ # Completes this forward-referenced enum in place: the object that stood in
694
+ # for an undefined tag starts answering as the `int` an enum object is.
695
+ # Idempotent, since one tag may complete after several incomplete
696
+ # references captured the same object.
697
+ def complete!
698
+ @complete = true
699
+ self
700
+ end
701
+
702
+ # Guarded like Type::Void and an incomplete StructType while incomplete;
703
+ # once completed it measures like `int` (4 bytes, 4-byte aligned).
704
+ def size
705
+ raise "incomplete enum has no size" unless @complete
706
+
707
+ 4
708
+ end
709
+
710
+ def alignment
711
+ raise "incomplete enum has no alignment" unless @complete
712
+
713
+ 4
714
+ end
715
+
716
+ # Value equality by tag while incomplete, so two references to the same
717
+ # undefined tag share a type (which is what a tentative-definition merge
718
+ # and a redeclaration check compare). Once completed, an enum object is an
719
+ # int, so a completed enum is equal to Type::Int (and to any other
720
+ # completed enum) — this is the identity a function-type compatibility
721
+ # check needs when "enum efoo (*)(void)" (resolved to int post-definition)
722
+ # is assigned a function returning the once-incomplete "enum efoo".
723
+ def ==(other)
724
+ if @complete
725
+ return true if other.equal?(Type::Int)
726
+ return other.complete? if other.is_a?(EnumType)
727
+
728
+ return false
729
+ end
730
+ other.is_a?(EnumType) && !other.complete? && other.tag == tag
731
+ end
732
+
733
+ def eql?(other)
734
+ self == other
735
+ end
736
+
737
+ def hash
738
+ [EnumType, tag].hash
739
+ end
740
+
741
+ def to_s
742
+ "enum #{tag}"
743
+ end
744
+ end
745
+
746
+ # One laid-out member of a struct: its `name`, its declared Type and the
747
+ # byte `offset` of its first byte from the start of the enclosing struct.
748
+ #
749
+ # A bit-field member carries two extra fields (both nil for a plain member):
750
+ # `bit_width`, the declared width in bits, and `bit_offset`, the field's bit
751
+ # position measured from the start of the enclosing aggregate. `offset` for a
752
+ # bit-field is the byte containing its first bit (bit_offset / 8), kept only
753
+ # so ABI classification and diagnostics have a byte anchor — this subset
754
+ # diagnoses every bit-field *access*, so no read or write ever consults these
755
+ # bit fields to extract a value (recorded M2 debt). An unnamed bit-field
756
+ # declares no member and is never recorded here; it only shapes the layout.
757
+ Member = Data.define(:name, :type, :offset, :bit_width, :bit_offset) do
758
+ def initialize(name:, type:, offset:, bit_width: nil, bit_offset: nil)
759
+ super
760
+ end
761
+
762
+ # Whether this member is a bit-field, distinguishing it from a plain member
763
+ # occupying whole bytes; the generator consults it to diagnose an access.
764
+ def bitfield?
765
+ !bit_width.nil?
766
+ end
767
+ end
768
+
769
+ # A structure or a union type. Both are aggregates (6.7.2.1) that share this
770
+ # one class, told apart by `kind` (:struct or :union); a union differs only
771
+ # in its layout (every member at offset 0, sized to hold the widest one).
772
+ # Unlike every other type here, one compares by identity, not by value: two
773
+ # such types are the same type exactly when they are the same object, which
774
+ # is the object a single tag definition produces. That is what C means by
775
+ # struct/union type identity (a redeclared "struct point" refers to the one
776
+ # definition, never a structurally equal copy) and it is also what keeps
777
+ # equality and #to_s from looping on a self-referential struct, whose
778
+ # members point back at itself.
779
+ #
780
+ # A StructType is born incomplete: `tag` (the name after "struct"/"union",
781
+ # or nil for an anonymous one) and `kind` are fixed, but its members are
782
+ # unknown until #define lays them out. This mutability is deliberate — a
783
+ # forward declaration ("struct node;") and, above all, a self-referential
784
+ # pointer ("struct node *next;" inside "struct node"'s own body) both take a
785
+ # reference to the still-incomplete object, and #define later fills in the
786
+ # very same object, so those earlier references observe the completed
787
+ # layout. Until then #size and #alignment raise and #complete? is false, so
788
+ # the generator can reject an incomplete type (a variable, a sizeof, a
789
+ # by-value member) with a proper diagnostic rather than lay out nonsense.
790
+ class StructType
791
+ attr_reader :tag, :kind, :members
792
+
793
+ def initialize(tag, kind: :struct)
794
+ @tag = tag
795
+ @kind = kind
796
+ @members = nil
797
+ @size = nil
798
+ @alignment = nil
799
+ @complete = false
800
+ end
801
+
802
+ def pointer?
803
+ false
804
+ end
805
+
806
+ def int?
807
+ false
808
+ end
809
+
810
+ def char?
811
+ false
812
+ end
813
+
814
+ def void?
815
+ false
816
+ end
817
+
818
+ def integer?
819
+ false
820
+ end
821
+
822
+ def arithmetic?
823
+ false
824
+ end
825
+
826
+ def bool?
827
+ false
828
+ end
829
+
830
+ def array?
831
+ false
832
+ end
833
+
834
+ # True for a union as well as a struct: both are aggregates that reuse the
835
+ # same lvalue, member-access and whole-object-copy paths, so every
836
+ # generator site that means "an aggregate" (member address, :memcpy copy,
837
+ # by-value rejection) asks #struct? and needs no union-specific branch.
838
+ # #union? draws the distinction where the layout or a diagnostic depends
839
+ # on it.
840
+ def struct?
841
+ true
842
+ end
843
+
844
+ def function?
845
+ false
846
+ end
847
+
848
+ def float?
849
+ false
850
+ end
851
+
852
+ # Distinguishes a union from a struct; the two share this class and differ
853
+ # only in layout and in the wording of tag-kind diagnostics.
854
+ def union?
855
+ @kind == :union
856
+ end
857
+
858
+ # Whether the tag's body has been laid out yet. A struct only used
859
+ # through a pointer may stay incomplete forever; every other use is a
860
+ # diagnostic error the generator raises against this flag.
861
+ def complete?
862
+ @complete
863
+ end
864
+
865
+ # Whether this aggregate ends in a flexible array member (an unbounded
866
+ # "[]", 6.7.2.1p18). A struct with one taints its uses: it may not be an
867
+ # array element or (this subset) laid out by value inside another
868
+ # aggregate, since its true size depends on a run-time element count the
869
+ # enclosing layout cannot know. Only a defined struct can carry one, so an
870
+ # incomplete type (no members yet) answers false.
871
+ def flexible_array_member?
872
+ return false unless @members
873
+
874
+ last = @members.last
875
+ !last.nil? && last.type.array? && last.type.incomplete?
876
+ end
877
+
878
+ # The member named `name`, or nil when there is none — the generator uses
879
+ # the nil to diagnose "no member named ...". A named member wins directly;
880
+ # failing that, an anonymous struct/union member (name nil, an aggregate
881
+ # per C11 6.7.2.1p13) is searched transparently, and a hit there is
882
+ # returned as a synthesized Member whose offset folds the anonymous
883
+ # member's own offset into the inner one. The search recurses, so an
884
+ # anonymous member nested inside another resolves in the same single step;
885
+ # because the returned Member carries a ready-made offset and type, the
886
+ # generator's "." and "->" lowering reaches a nested field with no
887
+ # awareness that it came through an anonymous member.
888
+ def member(name)
889
+ return nil unless @members
890
+
891
+ direct = @members.find { |m| m.name == name }
892
+ return direct if direct
893
+
894
+ @members.each do |m|
895
+ next unless m.name.nil? && m.type.struct?
896
+
897
+ inner = m.type.member(name)
898
+ if inner
899
+ return Member.new(name: inner.name, type: inner.type, offset: m.offset + inner.offset,
900
+ bit_width: inner.bit_width,
901
+ bit_offset: inner.bit_offset && inner.bit_offset + m.offset * 8)
902
+ end
903
+ end
904
+ nil
905
+ end
906
+
907
+ # Lays out the aggregate from `raw_members` (an array of [name, Type,
908
+ # bit_width, alignas] entries in declaration order; an anonymous
909
+ # struct/union member has a nil name, a plain member a nil bit_width — see
910
+ # #layout_struct for how a bit-field is placed — and `alignas` is the
911
+ # boundary a C11 _Alignas asked for on that one member, nil for none, a
912
+ # trailing field a caller with no such member may leave off entirely).
913
+ # A struct follows the System V AMD64 rules:
914
+ # each member starts at
915
+ # the next offset that satisfies its own alignment (inserting padding as
916
+ # needed), the alignment is the widest member's, and the size is rounded
917
+ # up to that alignment so arrays keep every element aligned. A union
918
+ # overlays every member at offset 0, so its alignment is still the widest
919
+ # member's but its size is the largest member's rounded up to that
920
+ # alignment. Completing the type in place means any reference taken while
921
+ # it was incomplete now sees the finished layout.
922
+ #
923
+ # `packed` and `aligned` carry the GNU __attribute__ layout overrides
924
+ # (Step 28). `packed` drops every member to a 1-byte boundary — no padding
925
+ # between members and no tail padding — and, on its own, the whole
926
+ # aggregate to alignment 1. `aligned` (a power-of-two integer, or nil for
927
+ # none) raises the aggregate's alignment to at least that value, rounding
928
+ # the size up to it; combined with `packed` the members stay packed while
929
+ # the aggregate takes `aligned` as its boundary and tail-rounding.
930
+ #
931
+ # A member's own `alignas` overrides both of those for that one member: it
932
+ # is placed at the boundary the _Alignas names and joins the aggregate's
933
+ # alignment as any member's does, even under `packed` (measured: gcc gives
934
+ # "struct __attribute__((packed)) { char c; _Alignas(8) int a; char b; }"
935
+ # size 16, alignment 8 and "a" at offset 8).
936
+ #
937
+ # `unnamed_bitfields_align` selects the one layout rule the two supported
938
+ # ABIs spell differently (see #layout_struct): whether an unnamed
939
+ # bit-field's declared type raises the aggregate's alignment. It does not
940
+ # under the x86-64 System V psABI (the default) and does under AAPCS64.
941
+ def define(raw_members, packed: false, aligned: nil, unnamed_bitfields_align: false)
942
+ @members, @size, @alignment =
943
+ if union?
944
+ layout_union(raw_members, packed, aligned, unnamed_bitfields_align)
945
+ else
946
+ layout_struct(raw_members, packed, aligned, unnamed_bitfields_align)
947
+ end
948
+ @complete = true
949
+ end
950
+
951
+ # The laid-out byte size. Guarded like Type::Void's: every path that
952
+ # could reach an incomplete struct here rejects it first with a
953
+ # CompileError, so a raise means a missing guard.
954
+ def size
955
+ raise "incomplete struct has no size" unless @complete
956
+
957
+ @size
958
+ end
959
+
960
+ # The struct's alignment (its widest member's), guarded exactly like
961
+ # #size against an incomplete struct.
962
+ def alignment
963
+ raise "incomplete struct has no alignment" unless @complete
964
+
965
+ @alignment
966
+ end
967
+
968
+ # Two struct types are identical only when they are the same object (the
969
+ # same tag definition); a comparison with any other type, or with a
970
+ # different struct, is false. Identity avoids walking members, so a
971
+ # self-referential struct compares without recursing.
972
+ def ==(other)
973
+ equal?(other)
974
+ end
975
+
976
+ # Renders as a C type name for diagnostics. Never inspects members, so a
977
+ # self-referential struct renders in one step; an anonymous struct has no
978
+ # tag to name.
979
+ def to_s
980
+ keyword = union? ? "union" : "struct"
981
+ tag ? "#{keyword} #{tag}" : "#{keyword} <anonymous>"
982
+ end
983
+
984
+ private
985
+
986
+ # The struct layout: plain members placed in order at their own alignment
987
+ # (or at a 1-byte boundary when `packed`), and bit-fields packed into
988
+ # storage units by the System V x86-64 rules, the whole rounded up to the
989
+ # aggregate's alignment. `aligned` (when set) raises that final alignment.
990
+ # Returns [members, size, alignment].
991
+ #
992
+ # A running bit cursor (`bit_pos`, bits from the start) drives both kinds so
993
+ # a bit-field and its neighbours share bytes exactly as gcc lays them out. A
994
+ # bit-field `T name : W` takes the next W bits, but must not straddle a
995
+ # T-sized storage unit: when it would, the cursor advances to the next
996
+ # unit boundary first (6.7.2.1, psABI). A named bit-field always raises the
997
+ # aggregate's alignment to alignof(T). Whether an unnamed one does too is
998
+ # where the two ABIs part company, which is what `unnamed_bitfields_align`
999
+ # selects: the x86-64 System V psABI says "unnamed bit-fields' types do not
1000
+ # affect the alignment of a structure", while AAPCS64 has every bit-field's
1001
+ # container contribute, so `struct { int : 32; }` is 4-byte aligned there
1002
+ # and 1-byte aligned here. Either way an unnamed `T : 0` places nothing and
1003
+ # only forces the cursor to the next unit boundary.
1004
+ # `packed` never coexists with a bit-field here (the parser rejects that
1005
+ # combination), so its 1-byte-boundary branch only governs plain members.
1006
+ def layout_struct(raw_members, packed, aligned, unnamed_bitfields_align)
1007
+ bit_pos = 0
1008
+ max_alignment = 1
1009
+ members = []
1010
+ raw_members.each do |name, type, bit_width, alignas|
1011
+ if bit_width.nil?
1012
+ member_alignment = member_boundary(type, packed, alignas)
1013
+ byte_offset = align_up(bits_to_bytes(bit_pos), member_alignment)
1014
+ members << Member.new(name: name, type: type, offset: byte_offset)
1015
+ # A flexible array member (the trailing "T name[]") sits at its
1016
+ # element's boundary but contributes nothing to the struct's size —
1017
+ # sizeof is as if it were absent (6.7.2.1p18) — so the cursor stops
1018
+ # at its offset. Its element alignment still joins the aggregate's
1019
+ # (raising it when the element is wider than every earlier member).
1020
+ member_size = type.array? && type.incomplete? ? 0 : type.size
1021
+ bit_pos = (byte_offset + member_size) * 8
1022
+ max_alignment = member_alignment if member_alignment > max_alignment
1023
+ else
1024
+ bit_pos = place_bitfield(members, name, type, bit_width, bit_pos,
1025
+ unnamed_bitfields_align) do |alignment|
1026
+ max_alignment = alignment if alignment > max_alignment
1027
+ end
1028
+ end
1029
+ end
1030
+ struct_alignment = final_alignment(max_alignment, aligned)
1031
+ [members, align_up(bits_to_bytes(bit_pos), struct_alignment), struct_alignment]
1032
+ end
1033
+
1034
+ # Places one bit-field at bit cursor `bit_pos`, recording a Member for a
1035
+ # named one and yielding alignof(T) so #layout_struct can raise the
1036
+ # aggregate's alignment — for a named field always, for an unnamed one only
1037
+ # when `unnamed_bitfields_align` (AAPCS64). Returns the advanced cursor.
1038
+ # A zero-width field is always unnamed (the parser rejects a named one) and
1039
+ # merely realigns the cursor to the next storage-unit boundary; it still
1040
+ # contributes its container's alignment under AAPCS64, which is why the
1041
+ # yield precedes the early return.
1042
+ def place_bitfield(members, name, type, bit_width, bit_pos, unnamed_bitfields_align)
1043
+ unit_bits = type.size * 8
1044
+ yield type.alignment if unnamed_bitfields_align && name.nil?
1045
+ return align_up(bit_pos, unit_bits) if bit_width.zero?
1046
+
1047
+ bit_pos = align_up(bit_pos, unit_bits) if (bit_pos % unit_bits) + bit_width > unit_bits
1048
+ if name
1049
+ members << Member.new(name: name, type: type, offset: bit_pos / 8,
1050
+ bit_width: bit_width, bit_offset: bit_pos)
1051
+ yield type.alignment
1052
+ end
1053
+ bit_pos + bit_width
1054
+ end
1055
+
1056
+ # The union layout: every member overlaid at offset 0, the size the widest
1057
+ # member's rounded up to the aggregate alignment. `packed` drops the
1058
+ # aggregate to a 1-byte boundary and `aligned` raises it. A bit-field is
1059
+ # laid at bit 0 and spans ceil(W/8) bytes; a named one raises the alignment
1060
+ # to its type's. An unnamed one contributes only its byte span (and a
1061
+ # `T : 0` nothing at all) under the x86-64 System V psABI, and its
1062
+ # container's alignment as well under AAPCS64 — the same divergence
1063
+ # #layout_struct documents, selected by `unnamed_bitfields_align`.
1064
+ # Returns [members, size, alignment].
1065
+ def layout_union(raw_members, packed, aligned, unnamed_bitfields_align)
1066
+ members = []
1067
+ max_size = 0
1068
+ natural_alignment = 1
1069
+ raw_members.each do |name, type, bit_width, alignas|
1070
+ if bit_width.nil?
1071
+ members << Member.new(name: name, type: type, offset: 0)
1072
+ byte_size = type.size
1073
+ member_alignment = member_boundary(type, packed, alignas)
1074
+ else
1075
+ unnamed_alignment = unnamed_bitfields_align && name.nil? ? type.alignment : 1
1076
+ if bit_width.zero?
1077
+ natural_alignment = unnamed_alignment if unnamed_alignment > natural_alignment
1078
+ next
1079
+ end
1080
+
1081
+ byte_size = bits_to_bytes(bit_width)
1082
+ member_alignment = unnamed_alignment
1083
+ if name
1084
+ members << Member.new(name: name, type: type, offset: 0,
1085
+ bit_width: bit_width, bit_offset: 0)
1086
+ member_alignment = type.alignment
1087
+ end
1088
+ end
1089
+ max_size = byte_size if byte_size > max_size
1090
+ natural_alignment = member_alignment if member_alignment > natural_alignment
1091
+ end
1092
+ union_alignment = final_alignment(natural_alignment, aligned)
1093
+ [members, align_up(max_size, union_alignment), union_alignment]
1094
+ end
1095
+
1096
+ # The number of whole bytes needed to hold `bits` bits (rounding up).
1097
+ def bits_to_bytes(bits)
1098
+ (bits + 7) / 8
1099
+ end
1100
+
1101
+ # The aggregate's final alignment: its natural (or packed) alignment,
1102
+ # raised to `aligned` when a larger __attribute__((aligned(N))) asks for
1103
+ # it. A packed aggregate whose natural alignment is 1 thus still takes N
1104
+ # when aligned(N) is combined with packed.
1105
+ def final_alignment(natural, aligned)
1106
+ aligned && aligned > natural ? aligned : natural
1107
+ end
1108
+
1109
+ # One plain member's boundary: its type's own alignment, dropped to 1 byte
1110
+ # by a `packed` aggregate, and raised by an _Alignas the member itself
1111
+ # carries. The parser refuses an _Alignas weaker than the member's type,
1112
+ # so the request only ever raises; taking the larger of the two keeps that
1113
+ # true against a `packed` 1 as well.
1114
+ def member_boundary(type, packed, alignas)
1115
+ natural = packed ? 1 : type.alignment
1116
+ alignas && alignas > natural ? alignas : natural
1117
+ end
1118
+
1119
+ def align_up(value, alignment)
1120
+ (value + alignment - 1) / alignment * alignment
1121
+ end
1122
+ end
1123
+
1124
+ # The System V AMD64 psABI representation of a `va_list` element: the
1125
+ # `__va_list_tag` structure a call's variable arguments are read through.
1126
+ # Its layout — a 32-bit `gp_offset` (the byte offset of the next integer
1127
+ # argument still in the register-save area), a 32-bit `fp_offset` (the same
1128
+ # for a vector argument), an `overflow_arg_area` pointer (the next argument
1129
+ # that spilled onto the stack) and a `reg_save_area` pointer (the base of the
1130
+ # saved argument registers) — is fixed by the ABI, so building it here from
1131
+ # the ordinary #define layout path (size 24, 8-byte aligned) matches what a
1132
+ # System V compiler and its C library agree on. A single shared instance
1133
+ # stands for the tag, and, being a StructType, it compares by identity, so
1134
+ # the generator recognizes "pointer to __va_list_tag" by object identity when
1135
+ # type-checking a va_start/va_arg/va_end operand.
1136
+ VaListTag = StructType.new("__va_list_tag").tap do |tag|
1137
+ tag.define([
1138
+ ["gp_offset", UInt],
1139
+ ["fp_offset", UInt],
1140
+ ["overflow_arg_area", Pointer.new(Void)],
1141
+ ["reg_save_area", Pointer.new(Void)]
1142
+ ])
1143
+ end
1144
+
1145
+ # The type the built-in `__builtin_va_list` typedef names: a one-element
1146
+ # array of __va_list_tag. The array shape is what makes a `va_list` object
1147
+ # decay to a `__va_list_tag *` in every expression context (so passing one
1148
+ # to a helper hands over a pointer to the same object, and va_start/va_arg
1149
+ # write through it), while a local declaration still reserves the whole
1150
+ # 24-byte tag as a stack object — exactly the System V convention.
1151
+ BuiltinVaList = Array.new(VaListTag, 1)
1152
+
1153
+ # The AAPCS64 representation of a `va_list` element. AArch64 splits the two
1154
+ # register files System V folds into one save area, so the tag has five
1155
+ # fields rather than four (AAPCS64 §B.4 / the Arm-64 va_list): `__stack` the
1156
+ # next stack argument, `__gr_top` and `__vr_top` the *ends* of the integer
1157
+ # and vector save areas, and `__gr_offs` / `__vr_offs` signed byte offsets
1158
+ # from those tops. The offsets run the other way from System V's: they start
1159
+ # negative (the whole file still to be read) and climb toward zero, at which
1160
+ # point the file is spent and the argument comes off `__stack`. The layout
1161
+ # (size 32, 8-byte aligned) is what the AArch64 C library agrees on, and the
1162
+ # tag compares by identity, so the generator recognizes it exactly as it does
1163
+ # the System V one.
1164
+ AArch64VaListTag = StructType.new("__va_list").tap do |tag|
1165
+ tag.define([
1166
+ ["__stack", Pointer.new(Void)],
1167
+ ["__gr_top", Pointer.new(Void)],
1168
+ ["__vr_top", Pointer.new(Void)],
1169
+ ["__gr_offs", Int],
1170
+ ["__vr_offs", Int]
1171
+ ])
1172
+ end
1173
+
1174
+ # The AArch64 counterpart of BuiltinVaList: a one-element array of the
1175
+ # five-field tag. Making it an array (rather than the bare struct gcc's
1176
+ # __builtin_va_list happens to be) has the same decay-to-pointer effect the
1177
+ # System V form relies on, and it is ABI-identical at a call boundary: a
1178
+ # 32-byte va_list is passed by reference under AAPCS64 6.4.2 (a pointer to
1179
+ # the object in a single integer register), which is exactly what the decayed
1180
+ # array pointer already is. Forwarding a va_list to vprintf therefore lands
1181
+ # the same pointer in the same register a gcc caller would.
1182
+ AArch64BuiltinVaList = Array.new(AArch64VaListTag, 1)
1183
+
1184
+ # The plain-`char` instance a target uses: the signed one when its ABI makes
1185
+ # plain `char` signed (x86-64 System V), the unsigned one otherwise
1186
+ # (AAPCS64). Neither is `signed char`/`unsigned char`, which keep their own
1187
+ # fixed-signedness instances whatever the target.
1188
+ def self.plain_char(signed)
1189
+ signed ? Char : UnsignedChar
1190
+ end
1191
+
1192
+ # The *composite type* of two declarations of the same object (6.2.7p3), or
1193
+ # nil when the two types are not compatible — the signal a declaration merge
1194
+ # turns into its "conflicting types" diagnostic.
1195
+ #
1196
+ # One case of that paragraph matters in this subset: when one declaration is
1197
+ # an array type of known size and the other an array type of unspecified
1198
+ # size, the composite type is the array type of *known* size. So
1199
+ #
1200
+ # extern int tbl[]; int tbl[3] = {1, 2, 3};
1201
+ #
1202
+ # declares one object of type "int [3]" in either order, and a later
1203
+ # sizeof/subscript measures the completed type rather than the unbounded
1204
+ # reference. Two known but different sizes are incompatible, and so are
1205
+ # incompatible element types. The recursion into the element type carries the
1206
+ # same rule through a multidimensional array ("extern int m[][4];" against
1207
+ # "int m[2][4]"), whose inner dimensions are always known and so must agree.
1208
+ #
1209
+ # Every other pair of types composes exactly when the two are identical,
1210
+ # which is what the equality comparison at each declaration-merge site meant
1211
+ # before this rule existed. The paragraph's remaining cases — a function type
1212
+ # declared with a parameter type list against one declared without, and a
1213
+ # pointer to either of the above — do not arise here: this subset merges
1214
+ # function signatures by equality (it models no unprototyped declaration),
1215
+ # and a parameter of array type is adjusted to a pointer by the parser.
1216
+ def self.composite(first, second)
1217
+ return first if first == second
1218
+ return nil unless first.array? && second.array?
1219
+
1220
+ element = composite(first.element, second.element)
1221
+ return nil if element.nil?
1222
+ return nil if first.length && second.length && first.length != second.length
1223
+
1224
+ Array.new(element, first.length || second.length)
1225
+ end
1226
+
1227
+ # True for the character types (6.2.5p15): either plain `char` and the two
1228
+ # explicitly signed ones. This is what "an array of character type", the
1229
+ # form a string literal may initialize, means; `_Bool` is one byte wide too
1230
+ # but is not a character type.
1231
+ def self.character?(type)
1232
+ type.equal?(Char) || type.equal?(UnsignedChar) ||
1233
+ type.equal?(SChar) || type.equal?(UChar)
1234
+ end
1235
+ end
1236
+ end