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,4122 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "ast"
4
+ require_relative "constant_evaluator"
5
+ require_relative "initializer_resolver"
6
+ require_relative "../type"
7
+ require_relative "../compile_error"
8
+
9
+ module Rubycc
10
+ module Front
11
+ # Recursive-descent parser for the C subset. Nonterminals follow the
12
+ # grammar productions of ISO C (6.5.x / 6.7 / 6.8.x):
13
+ #
14
+ # translation-unit = external-declaration*
15
+ # external-declaration = type-specifier ";" -- tag only
16
+ # | type-specifier declarator
17
+ # ( (";" | compound-statement) -- function
18
+ # (declarator
19
+ # is a
20
+ # function)
21
+ # | ("=" initializer)?
22
+ # ("," declarator ("=" initializer)?)*
23
+ # ";" ) -- variables
24
+ # declaration-specifiers = (storage-class-specifier | type-specifier)+
25
+ # storage-class-specifier = "typedef"
26
+ # type-specifier = "void" | "char" | "short" | "int" | "long"
27
+ # | "signed" | "unsigned" | "_Bool"
28
+ # | struct-or-union-specifier | enum-specifier
29
+ # | typedef-name
30
+ # typedef-name = identifier
31
+ # struct-or-union-specifier = struct-or-union identifier?
32
+ # "{" struct-declaration+ "}"
33
+ # | struct-or-union identifier
34
+ # struct-or-union = "struct" | "union"
35
+ # enum-specifier = "enum" identifier? "{" enumerator-list ","? "}"
36
+ # | "enum" identifier
37
+ # enumerator-list = enumerator ("," enumerator)*
38
+ # enumerator = identifier ("=" constant-expression)?
39
+ # struct-declaration = type-specifier declarator
40
+ # ("," declarator)* ";"
41
+ # | struct-or-union-specifier ";" -- anonymous
42
+ # parameter-type-list = "void"
43
+ # | parameter-declaration
44
+ # ("," parameter-declaration)*
45
+ # parameter-declaration = type-specifier declarator
46
+ # identifier-list = identifier ("," identifier)*
47
+ # declarator = "*"* direct-declarator
48
+ # direct-declarator = (identifier | "(" declarator ")")
49
+ # direct-declarator-suffix*
50
+ # direct-declarator-suffix = "[" constant-expression? "]"
51
+ # | "(" parameter-type-list? ")"
52
+ # | "(" identifier-list ")" -- old style
53
+ # function-definition = declaration-specifiers declarator
54
+ # declaration-list? compound-statement
55
+ # declaration-list = declaration+
56
+ # abstract-declarator = "*"* direct-abstract-declarator?
57
+ # direct-abstract-declarator = ("(" abstract-declarator ")")?
58
+ # direct-declarator-suffix*
59
+ # compound-statement = "{" block-item* "}"
60
+ # block-item = declaration | statement
61
+ # declaration = type-specifier ";"
62
+ # | type-specifier init-declarator
63
+ # ("," init-declarator)* ";"
64
+ # init-declarator = declarator ("=" initializer)?
65
+ # initializer = assignment-expression
66
+ # | "{" initializer-list ","? "}"
67
+ # initializer-list = designation? initializer
68
+ # ("," designation? initializer)*
69
+ # designation = designator+ "="
70
+ # designator = "[" constant-expression "]" | "." identifier
71
+ # statement = labeled-statement | return-statement
72
+ # | expression-statement | selection-statement
73
+ # | iteration-statement | jump-statement
74
+ # | compound-statement
75
+ # labeled-statement = identifier ":" statement
76
+ # | "case" constant-expression ":" statement
77
+ # | "default" ":" statement
78
+ # return-statement = "return" expression? ";"
79
+ # expression-statement = expression? ";"
80
+ # selection-statement = "if" "(" expression ")" statement
81
+ # ("else" statement)?
82
+ # | "switch" "(" expression ")" statement
83
+ # iteration-statement = "while" "(" expression ")" statement
84
+ # | "do" statement "while" "(" expression ")" ";"
85
+ # | "for" "(" for-init expression? ";"
86
+ # expression? ")" statement
87
+ # for-init = declaration | expression? ";"
88
+ # jump-statement = "break" ";" | "continue" ";"
89
+ # | "goto" identifier ";"
90
+ # expression = assignment-expression
91
+ # ("," assignment-expression)*
92
+ # assignment-expression = conditional-expression
93
+ # (("=" | "+=" | "-=" | "*=" | "/=" | "%="
94
+ # | "&=" | "|=" | "^=" | "<<=" | ">>=")
95
+ # assignment-expression)?
96
+ # conditional-expression = logical-OR-expression
97
+ # ("?" expression ":" conditional-expression)?
98
+ # constant-expression = conditional-expression
99
+ # logical-OR-expression = logical-AND-expression
100
+ # ("||" logical-AND-expression)*
101
+ # logical-AND-expression = inclusive-OR-expression
102
+ # ("&&" inclusive-OR-expression)*
103
+ # inclusive-OR-expression = exclusive-OR-expression
104
+ # ("|" exclusive-OR-expression)*
105
+ # exclusive-OR-expression = AND-expression ("^" AND-expression)*
106
+ # AND-expression = equality-expression ("&" equality-expression)*
107
+ # equality-expression = relational-expression
108
+ # (("==" | "!=") relational-expression)*
109
+ # relational-expression = shift-expression
110
+ # (("<" | ">" | "<=" | ">=") shift-expression)*
111
+ # shift-expression = additive-expression
112
+ # (("<<" | ">>") additive-expression)*
113
+ # additive-expression = multiplicative-expression
114
+ # (("+" | "-") multiplicative-expression)*
115
+ # multiplicative-expression = cast-expression
116
+ # (("*" | "/" | "%") cast-expression)*
117
+ # cast-expression = "(" type-name ")" cast-expression
118
+ # | unary-expression
119
+ # unary-expression = ("+" | "-" | "!" | "~" | "&" | "*")* cast-expression
120
+ # | ("++" | "--") unary-expression
121
+ # | "sizeof" unary-expression
122
+ # | "sizeof" "(" type-name ")"
123
+ # type-name = type-specifier abstract-declarator?
124
+ # postfix-expression = primary-expression
125
+ # ("[" expression "]"
126
+ # | "(" argument-expression-list? ")"
127
+ # | "." identifier | "->" identifier
128
+ # | "++" | "--")*
129
+ # argument-expression-list = assignment-expression
130
+ # ("," assignment-expression)*
131
+ # primary-expression = integer-constant | string-literal
132
+ # | identifier | "(" expression ")"
133
+ #
134
+ # Binary precedence levels are parsed by a single table-driven
135
+ # left-associative loop (see #parse_left_associative) rather than one
136
+ # hand-written loop per level, so adding an operator or a precedence
137
+ # tier only requires a new table entry. assignment-expression is
138
+ # right-associative and is handled separately (see #parse_assignment_expression),
139
+ # as is conditional-expression (see #parse_conditional_expression), whose
140
+ # third operand recurses back into itself rather than into the tier above.
141
+ class Parser
142
+ # Punctuator → AST operator tables, one per precedence tier
143
+ # (weakest binding first).
144
+ COMPOUND_ASSIGNMENT_OPERATORS = {
145
+ "+=" => :add, "-=" => :sub, "*=" => :mul, "/=" => :div, "%=" => :mod,
146
+ "&=" => :and, "|=" => :or, "^=" => :xor, "<<=" => :shl, ">>=" => :shr
147
+ }.freeze
148
+ INCLUSIVE_OR_OPERATORS = { "|" => :or }.freeze
149
+ EXCLUSIVE_OR_OPERATORS = { "^" => :xor }.freeze
150
+ AND_OPERATORS = { "&" => :and }.freeze
151
+ EQUALITY_OPERATORS = { "==" => :eq, "!=" => :ne }.freeze
152
+ RELATIONAL_OPERATORS = { "<" => :lt, ">" => :gt, "<=" => :le, ">=" => :ge }.freeze
153
+ # ">>" desugars to an arithmetic shift (:shr here names the source
154
+ # operator, which the generator lowers to a signed :sar); a future
155
+ # unsigned type will lower the same :shr to a logical shift instead.
156
+ SHIFT_OPERATORS = { "<<" => :shl, ">>" => :shr }.freeze
157
+ ADDITIVE_OPERATORS = { "+" => :add, "-" => :sub }.freeze
158
+ MULTIPLICATIVE_OPERATORS = { "*" => :mul, "/" => :div, "%" => :mod }.freeze
159
+
160
+ # The keywords that make up an integer/void type-specifier list (a "struct"
161
+ # specifier is handled on its own). A declaration begins with one or more
162
+ # of these; #normalize_type_specifiers collapses the collected multiset
163
+ # into a single Rubycc::Type. "void" is only ever valid as a function's
164
+ # return type or as the target of a pointer; every other use is rejected
165
+ # by #reject_void_type.
166
+ DECL_SPECIFIER_KEYWORDS = %w[void char short int long signed unsigned _Bool float double __int128].freeze
167
+
168
+ # The x86_64 "biggest alignment" gcc gives a bare
169
+ # `__attribute__((aligned))` with no argument (BIGGEST_ALIGNMENT, 16
170
+ # bytes): the most useful boundary, enough for any scalar or vector type.
171
+ BIGGEST_ALIGNMENT = 16
172
+
173
+ # The GNU attribute names Step 28 gives real layout meaning; every other
174
+ # attribute is accepted and silently discarded. Kept in sync with the
175
+ # preprocessor's __has_attribute answer (see Preprocessor#fold_has_attribute).
176
+ LAYOUT_ATTRIBUTES = %w[aligned packed].freeze
177
+
178
+ # The GNU attribute names that register a function with the runtime rather
179
+ # than describe it: `constructor` puts it in the object's .init_array (the
180
+ # loader calls it before main / at dlopen) and `destructor` in .fini_array
181
+ # (at exit / dlclose). Mapped to the array kind the later stages use.
182
+ # Kept in sync with the preprocessor's __has_attribute answer.
183
+ INIT_ATTRIBUTES = { "constructor" => :constructor, "destructor" => :destructor }.freeze
184
+
185
+ # The priority window these attributes accept, measured by handing
186
+ # `__attribute__((constructor(N)))` to gcc and reading back what it emitted:
187
+ # 0..65535 inclusive is taken (0..100 only with a -Wprio-ctor-dtor warning,
188
+ # that range being reserved for the implementation), and anything outside is
189
+ # the hard error "constructor priorities must be integers from 0 to 65535
190
+ # inclusive". The same measurement showed 65535 is gcc's *default*:
191
+ # `constructor(65535)` emits the plain, unnumbered `.init_array`, exactly as
192
+ # a bare `constructor` does, so an absent priority is represented as 65535
193
+ # here and the two spellings coincide downstream just as they do in gcc.
194
+ # ObjFile::ELFWriter::DEFAULT_ARRAY_PRIORITY is the same number on the
195
+ # other side of the IR, where it decides the section's name.
196
+ MIN_INIT_PRIORITY = 0
197
+ MAX_INIT_PRIORITY = 65535
198
+ DEFAULT_INIT_PRIORITY = 65535
199
+
200
+ # The spellings of the "restrict" type qualifier this subset recognizes.
201
+ # ISO "restrict" is not a keyword here (it never gains semantics — a
202
+ # restricted pointer is treated like any other), and glibc prototypes use
203
+ # the reserved GNU spellings "__restrict"/"__restrict__" unconditionally, so
204
+ # all three arrive as ordinary identifiers and are accepted and discarded
205
+ # wherever a pointer or array-parameter qualifier may appear.
206
+ RESTRICT_SPELLINGS = %w[restrict __restrict __restrict__].freeze
207
+
208
+ # The gcc __atomic_* builtins this subset lowers, mapping each keyword to
209
+ # its [AST::BuiltinAtomic kind, argument count]. The nine object forms
210
+ # cover <ruby/atomic.h>; the fence is also supported because C11 library
211
+ # headers and libev use it without an _Atomic object. The test-and-set and
212
+ # the generic (non-"_n") address-taking forms remain deliberately absent,
213
+ # so a program using one of those gets an "undeclared identifier" rather
214
+ # than a silently wrong lowering. (The legacy __sync_* family has its own
215
+ # table below.)
216
+ #
217
+ # The counts include the trailing memory-order argument(s) gcc's signatures
218
+ # take — one for every form but __atomic_compare_exchange_n, which takes a
219
+ # `weak` flag and *two* orders (success and failure).
220
+ ATOMIC_BUILTINS = {
221
+ "__atomic_load_n" => [:load, 2],
222
+ "__atomic_store_n" => [:store, 3],
223
+ "__atomic_exchange_n" => [:exchange, 3],
224
+ "__atomic_compare_exchange_n" => [:compare_exchange, 6],
225
+ "__atomic_fetch_add" => [:fetch_add, 3],
226
+ "__atomic_fetch_sub" => [:fetch_sub, 3],
227
+ "__atomic_add_fetch" => [:add_fetch, 3],
228
+ "__atomic_sub_fetch" => [:sub_fetch, 3],
229
+ "__atomic_or_fetch" => [:or_fetch, 3],
230
+ "__atomic_thread_fence" => [:fence, 1]
231
+ }.freeze
232
+
233
+ # The legacy gcc __sync_* builtins this subset lowers, mapping each keyword
234
+ # to its [AST::BuiltinSync kind, argument count]. These predate the
235
+ # __atomic_* family and differ from it in two ways that matter here: each
236
+ # one is a *full barrier* by definition, so none takes a memory-order
237
+ # argument, and the two compare-and-swap forms take the value they expect
238
+ # directly rather than through a pointer.
239
+ #
240
+ # The set is exactly the forms an existing IR op already gives the right
241
+ # meaning for. The bitwise members with no matching op — __sync_fetch_and_or,
242
+ # __sync_fetch_and_and, __sync_fetch_and_xor, __sync_fetch_and_nand,
243
+ # __sync_and_and_fetch, __sync_xor_and_fetch and __sync_nand_and_fetch —
244
+ # stay deliberately absent for the same reason the missing __atomic_* forms
245
+ # do: a program using one gets an "undeclared identifier" instead of a
246
+ # silently wrong lowering.
247
+ #
248
+ # gcc tolerates extra trailing arguments on all of these (its documented
249
+ # but ignored list of variables to protect). rubycc requires the exact
250
+ # count, so a miscount is reported here rather than quietly dropped.
251
+ SYNC_BUILTINS = {
252
+ "__sync_fetch_and_add" => [:fetch_add, 2],
253
+ "__sync_fetch_and_sub" => [:fetch_sub, 2],
254
+ "__sync_add_and_fetch" => [:add_fetch, 2],
255
+ "__sync_sub_and_fetch" => [:sub_fetch, 2],
256
+ "__sync_or_and_fetch" => [:or_fetch, 2],
257
+ "__sync_lock_test_and_set" => [:exchange, 2],
258
+ "__sync_lock_release" => [:release, 1],
259
+ "__sync_synchronize" => [:fence, 0],
260
+ "__sync_bool_compare_and_swap" => [:bool_compare_and_swap, 3],
261
+ "__sync_val_compare_and_swap" => [:val_compare_and_swap, 3]
262
+ }.freeze
263
+
264
+ # The gcc overflow-checked arithmetic builtins, mapping each keyword to its
265
+ # AST::BuiltinOverflow operator. All three take the same three arguments
266
+ # (the two operands and the pointer the result is stored through), so the
267
+ # operator is the only thing the spelling decides. The width-suffixed forms
268
+ # (__builtin_uaddll_overflow and kin) are deliberately absent: the generic
269
+ # forms cover every use here, and a missing one is an "undeclared
270
+ # identifier" rather than a wrong lowering.
271
+ OVERFLOW_BUILTINS = {
272
+ "__builtin_add_overflow" => :add,
273
+ "__builtin_sub_overflow" => :sub,
274
+ "__builtin_mul_overflow" => :mul
275
+ }.freeze
276
+
277
+ # The hard ceiling on how deeply the recursive descent will nest before it
278
+ # rejects an input rather than recurse further. A hostile source (tens of
279
+ # thousands of nested parentheses, unary operators, braces, ...) would
280
+ # otherwise drive the descent until the Ruby machine stack overflows,
281
+ # raising a bare SystemStackError that escapes as an unhandled crash
282
+ # instead of a diagnostic. Capping the depth turns that into an ordinary
283
+ # located CompileError.
284
+ #
285
+ # The value is deliberately well below the depth at which the stack
286
+ # actually gives out. On this toolchain the full pipeline (parser plus IR
287
+ # generation plus the backend, all of which recurse over the same AST)
288
+ # overflows at roughly 330 nested parentheses — the parenthesized-
289
+ # expression path is the most expensive, spending the entire binary-
290
+ # precedence chain per level. A single counter is shared across every
291
+ # recursive path — parenthesized/unary/cast/ternary/assignment expressions,
292
+ # compound statements, initializer lists, nested declarators and
293
+ # struct/union bodies — because these forms interleave (an expression
294
+ # inside a statement inside an initializer ...), so it is their *combined*
295
+ # live depth that threatens the stack, and bounding it here also bounds the
296
+ # AST depth every later pass recurses over.
297
+ #
298
+ # Because the expression grammar's right-recursive tiers each carry their
299
+ # own guard (assignment, conditional, unary, cast), one parenthesized level
300
+ # descends through several of them, so the counter climbs about 4 per
301
+ # nested parenthesis — the worst multiplier of any construct. 500 therefore
302
+ # admits roughly 122 nested parentheses: comfortably above C11 §5.2.4.1's
303
+ # 63-level implementation minimum, and about 12x the deepest nesting real
304
+ # inputs reach (measured: 41 in the c-testsuite, 32 for the ruby.h smoke
305
+ # header graph, 22 in the examples). At that ceiling the parser rejects
306
+ # after ~4900 live frames, well under the ~13000 at which Ruby's stack
307
+ # gives out, leaving headroom for a caller that starts from a deeper stack.
308
+ MAX_NESTING_DEPTH = 500
309
+
310
+ # The storage-class specifiers (6.7.1): at most one may appear in a
311
+ # declaration. "typedef", "static" and "extern" are recorded in
312
+ # DeclSpecInfo#storage and consumed downstream, while "register" and "auto"
313
+ # are accepted for compatibility but carry no effect in this subset, so
314
+ # they are consumed without being recorded; all five still participate in
315
+ # the "at most one storage class" duplicate check.
316
+ STORAGE_CLASS_KEYWORDS = %w[typedef static extern register auto].freeze
317
+
318
+ # The non-type parts of a declaration's specifier run, collected by
319
+ # #parse_declaration_specifiers alongside the base type. `storage` is the
320
+ # recorded storage class (nil, :typedef, :static or :extern); `const` is
321
+ # whether the declaration is const-qualified (const seen among the
322
+ # specifiers, or folded in from a const typedef name); `inline_p` and
323
+ # `noreturn_p` are whether "inline" or "_Noreturn" appeared (the two
324
+ # function specifiers, 6.7.4, accepted on functions and rejected on
325
+ # objects). `attributes` holds the GNU attributes written among the
326
+ # specifiers (position a), which apply to every declarator of the
327
+ # declaration; only the init attributes are read back from it, and only
328
+ # where they are admitted at all (see #parse_declaration_specifiers).
329
+ # `alignas` is the strongest _Alignas the run asked for (an Alignas, or nil
330
+ # when none appeared). volatile and register/auto leave no trace here.
331
+ DeclSpecInfo = Data.define(:storage, :const, :inline_p, :noreturn_p, :attributes, :alignas)
332
+
333
+ # One parsed GNU attribute: its normalized `name`, the folded `argument`
334
+ # (an integer for "aligned" and for the init attributes' priority, nil for
335
+ # every other attribute, whose arguments are skipped) and the `token` that
336
+ # spelled it, so a diagnostic about the attribute can be located.
337
+ Attribute = Data.define(:name, :argument, :token)
338
+
339
+ # The alignment an _Alignas specifier run asks for (6.7.5): `alignment` is
340
+ # the strongest boundary requested — a declaration may carry several
341
+ # alignment-specifiers and the largest wins (measured: gcc gives
342
+ # "_Alignas(8) _Alignas(16) int a" a 16-byte boundary whichever order the
343
+ # two are written in) — and `token` is the "_Alignas" that asked for it, so
344
+ # a diagnostic about the request can be located.
345
+ Alignas = Data.define(:alignment, :token)
346
+
347
+ # The identifier list of an old-style (K&R) function declarator — the
348
+ # "(a, b)" of "int add(a, b)", whose parentheses hold parameter *names*
349
+ # with no types at all (6.7.6.3, identifier-list form). `names` are the
350
+ # identifier tokens in order and `token` is the "(" that opened the list,
351
+ # both wanted by the declaration-list checks below.
352
+ #
353
+ # It rides the very channel a prototype's Parameter array does (the
354
+ # `function_params` a declarator reports), so it reaches every declarator
355
+ # position a parameter list can — and each of those refuses it (see
356
+ # #reject_identifier_list) except the one 6.7.6.3p3 allows, the definition
357
+ # of that same function.
358
+ IdentifierList = Data.define(:names, :token)
359
+
360
+ # A tag scope entry for an enum tag. C keeps struct, union and enum tags in
361
+ # one shared namespace, so enum tags live in @tag_scopes alongside the
362
+ # StructType objects that stand for struct tags. An enum contributes no
363
+ # distinct type — an enum object is just an int (6.7.2.2) — so this marker
364
+ # only records that the tag names an enum, which lets a later "struct X"
365
+ # (or "enum X" against a struct tag) be diagnosed as the wrong kind of tag.
366
+ EnumTag = Data.define(:tag)
367
+
368
+ # An entry in the ordinary-identifier scope (see @ordinary_scopes). `kind`
369
+ # is :typedef for a typedef name (`value` a [resolved Rubycc::Type, const?]
370
+ # pair, the flag carrying a "typedef const int" so a use folds it back into
371
+ # the object's const-ness), :enum
372
+ # for an enumeration constant (`value` its Integer value), or :ordinary for
373
+ # a variable, parameter or function name (`value` nil). The ordinary
374
+ # entries carry no payload; they exist only so a declarator can shadow a
375
+ # typedef name or an enum constant of the same name from an outer scope,
376
+ # keeping "typedef int T; { int T; ... }" from misreading the inner T as a
377
+ # type.
378
+ OrdinaryName = Data.define(:kind, :value)
379
+
380
+ # `plain_char` is the Rubycc::Type a bare `char` type-specifier resolves
381
+ # to. Its signedness is implementation-defined and pinned per ABI, so the
382
+ # caller that knows the target hands it in (see Compiler#compile);
383
+ # defaulting to the signed instance keeps a target-less caller on the
384
+ # x86-64 System V choice. `signed char` and `unsigned char` are unaffected —
385
+ # both are separate types with a fixed signedness.
386
+ #
387
+ # `unnamed_bitfields_align` is the second such per-ABI trait: whether an
388
+ # unnamed bit-field's type raises its aggregate's alignment (it does under
389
+ # AAPCS64, not under the x86-64 System V psABI). It is passed straight to
390
+ # StructType#define, which documents the rule.
391
+ #
392
+ # `builtin_va_list` is the third: the type `__builtin_va_list` names, whose
393
+ # tag layout differs between the ABIs (four fields on System V, five on
394
+ # AAPCS64). The caller hands in the target's from its CallConvention so the
395
+ # typedef the parser seeds below reserves the right-sized object and, being
396
+ # the same tag instance the generator type-checks against, is recognized by
397
+ # identity there.
398
+ def initialize(tokens, plain_char: Type::Char, unnamed_bitfields_align: false,
399
+ builtin_va_list: Type::BuiltinVaList)
400
+ @tokens = tokens
401
+ @plain_char = plain_char
402
+ @unnamed_bitfields_align = unnamed_bitfields_align
403
+ @builtin_va_list = builtin_va_list
404
+ @pos = 0
405
+ # The number of recursive-descent nesting levels currently live, capped
406
+ # at MAX_NESTING_DEPTH by #with_nesting_guard. One counter is shared by
407
+ # every recursive construct so their interleaved depth is what is bounded.
408
+ @nesting_depth = 0
409
+ # Struct and enum tags live in their own namespace, separate from
410
+ # variables and functions, and follow the same block scoping.
411
+ # @tag_scopes is a stack of "tag name -> Type::StructType | EnumTag"
412
+ # maps, innermost last, with the file scope at the bottom; a
413
+ # compound-statement (and a for-loop's own parentheses, and a function
414
+ # body) pushes a fresh map so a tag defined inside a block shadows an
415
+ # outer one and vanishes at the block's end. Tag resolution happens here,
416
+ # at parse time, because every other type is built here too — the
417
+ # generator only ever consumes finished Type objects.
418
+ @tag_scopes = [{}]
419
+ # The ordinary-identifier namespace, scoped in lockstep with @tag_scopes:
420
+ # a stack of "name -> OrdinaryName" maps. It records typedef names
421
+ # (resolved to a Type), enum constants (resolved to an Integer) and the
422
+ # plain declarator names that shadow them, so a name is looked up here to
423
+ # decide whether an identifier opens a declaration (a typedef name), folds
424
+ # to a constant (an enumerator) or is an ordinary reference. The outermost
425
+ # scope is pre-seeded with `__builtin_va_list` as a typedef for the
426
+ # target's va_list type (a one-element __va_list_tag array), exactly as
427
+ # gcc predeclares it, so "__builtin_va_list ap;" is parsed as a
428
+ # declaration with no dedicated keyword and a program may still shadow the
429
+ # name.
430
+ @ordinary_scopes = [{ "__builtin_va_list" => OrdinaryName.new(:typedef, [@builtin_va_list, false]) }]
431
+ # The constructor/destructor registrations the unit asked for, keyed by
432
+ # function name (see #register_init_attributes). Filled as declarations
433
+ # are read and handed to AST::Program whole, because the attribute may be
434
+ # written on a prototype that precedes *or* follows the definition, so no
435
+ # single declaration node can be the one that carries it.
436
+ @init_attributes = {}
437
+ # GNU visibility attributes are also declaration-order independent:
438
+ # Ruby's exported-function macro puts the explicit default visibility
439
+ # on a prototype, while the definition appears later without it.
440
+ @visibility_attributes = {}
441
+ # The parameter types each file-scope function *prototype* declared,
442
+ # keyed by name. Only one construct reads them: an old-style definition
443
+ # of a name a prototype already declared, which 6.7.6.3p14 checks
444
+ # against that prototype and which is then passed its arguments in the
445
+ # prototype's form rather than the promoted one (see
446
+ # #old_style_parameter_abi_types). Every other agreement between
447
+ # declarations of one function is the generator's to enforce.
448
+ @prototype_param_types = {}
449
+ end
450
+
451
+ # Parses the whole translation unit into an AST::Program. An external
452
+ # declaration yields a single node (a function) or, for a comma-separated
453
+ # run of global variables, an array of GlobalDecl; both are flattened into
454
+ # one source-ordered list.
455
+ def parse
456
+ declarations = []
457
+ until peek.eof?
458
+ # GCC accepts a stray semicolon at file scope as an empty external
459
+ # declaration. X-macro headers commonly leave one after a macro that
460
+ # already emits semicolon-terminated declarations (for example pg's
461
+ # GVL wrapper table), so consume the GNU extension here.
462
+ if peek.punct?(";")
463
+ advance
464
+ next
465
+ end
466
+
467
+ node = parse_external_declaration
468
+ node.is_a?(Array) ? declarations.concat(node) : declarations << node
469
+ end
470
+ AST::Program.new(declarations, @init_attributes, @visibility_attributes)
471
+ end
472
+
473
+ private
474
+
475
+ def peek
476
+ @tokens[@pos]
477
+ end
478
+
479
+ # Looks ahead `offset` tokens without consuming; used to disambiguate a
480
+ # parenthesized declarator from a parameter list, a cast/sizeof type-name
481
+ # from a parenthesized expression, and a labeled statement from an
482
+ # expression-statement.
483
+ def peek_ahead(offset)
484
+ @tokens[@pos + offset]
485
+ end
486
+
487
+ def advance
488
+ tok = @tokens[@pos]
489
+ @pos += 1 unless tok.eof?
490
+ tok
491
+ end
492
+
493
+ # Runs `block` one recursive-descent level deeper, first rejecting the
494
+ # input with a located CompileError once MAX_NESTING_DEPTH levels are
495
+ # already live — so a pathologically nested source is diagnosed rather than
496
+ # left to overflow the Ruby stack with a bare SystemStackError. The counter
497
+ # is decremented in an ensure, so a parse error thrown from within the
498
+ # block still unwinds the depth correctly. `token` locates the diagnostic
499
+ # and `what` names the construct (e.g. "expression", "block").
500
+ def with_nesting_guard(token, what)
501
+ error_at(token, "#{what} nested too deeply") if @nesting_depth >= MAX_NESTING_DEPTH
502
+
503
+ @nesting_depth += 1
504
+ begin
505
+ yield
506
+ ensure
507
+ @nesting_depth -= 1
508
+ end
509
+ end
510
+
511
+ # An external declaration is either a function (a prototype ending in ";"
512
+ # or a definition ending in a compound-statement) or a file-scope variable
513
+ # declaration. Both begin with a type-specifier and a declarator; the
514
+ # declarator's built type settles the form — a function type is the
515
+ # function form (its declarator having read the "(" parameter list), any
516
+ # other type the variable form.
517
+ def parse_external_declaration
518
+ # A leading "__extension__" (a GNU marker that silences pedantic
519
+ # warnings) prefixes a declaration with no semantic effect; every
520
+ # external declaration is a declaration, so any run of them is discarded.
521
+ skip_extension_markers
522
+
523
+ # A file-scope "_Static_assert(expr, "msg");" is a declaration that binds
524
+ # nothing; it is checked and flattened away here (see #parse_static_assert).
525
+ return parse_static_assert if peek.keyword?("_Static_assert")
526
+
527
+ type_tok = peek
528
+ # A file-scope declaration is the one place a constructor/destructor
529
+ # attribute means something, so it is the one place the specifier run
530
+ # admits it; everywhere else it is refused rather than dropped.
531
+ base_type, spec_info = parse_declaration_specifiers(allow_storage_class: true,
532
+ allow_init_attributes: true)
533
+
534
+ # "struct point { ... };" (or "struct node;", or a tag-only "enum E { ...
535
+ # };") with no declarator only declares or defines the tag, which the
536
+ # specifier parse already registered; it contributes no object and no
537
+ # code, so it flattens away to an empty run of declarations. A stray
538
+ # "typedef int;" with no declarator flattens away the same way. A
539
+ # declaration with no declarator declares no function either, so an init
540
+ # attribute the specifier run admitted has nothing to register.
541
+ if peek.punct?(";")
542
+ reject_init_attributes(spec_info.attributes)
543
+ advance
544
+ return []
545
+ end
546
+
547
+ # A typedef declaration binds each declarator's name as a type; it
548
+ # yields no object and no code (see #parse_typedef_declaration).
549
+ if spec_info.storage == :typedef
550
+ # A typedef binds a name, not a function, so an init attribute among
551
+ # its specifiers has nothing to register; the specifier run admitted it
552
+ # only because a file-scope *function* declaration may start the same
553
+ # way, so it is refused here rather than dropped.
554
+ reject_init_attributes(spec_info.attributes)
555
+ return parse_typedef_declaration(base_type, spec_info)
556
+ end
557
+
558
+ name_tok, type, function_params, pointer_quals =
559
+ parse_declarator(base_type, allow_incomplete_array: true)
560
+ # A GNU attribute may trail the declarator (position d):
561
+ # "int f(void) __attribute__((noreturn));". Accepted and discarded, on a
562
+ # function prototype/definition or a variable alike — except an init
563
+ # attribute, which is claimed below. The specifier-position attributes
564
+ # belong to every declarator of this declaration, so they join it here.
565
+ #
566
+ # gcc rejects the *definition* form ("void f(void)
567
+ # __attribute__((constructor)) { }") with "attributes should be specified
568
+ # before the declarator in a function definition"; this parser accepts it,
569
+ # a deliberate superset — refusing a form whose intent is unambiguous
570
+ # would buy nothing, while dropping it silently is the failure this whole
571
+ # position-by-position handling exists to avoid.
572
+ attributes = spec_info.attributes + parse_attribute_specifiers(init_attributes: :allow)
573
+
574
+ # An old-style declarator ("int add(a, b)") names its parameters without
575
+ # typing them, so what follows is not a "{" but the declaration-list that
576
+ # supplies those types (6.9.1). This is the one position where such a
577
+ # declarator is legal at all, so it branches off before the ordinary
578
+ # "declarator then {" test below.
579
+ if function_params.is_a?(IdentifierList)
580
+ return parse_old_style_function_definition(name_tok, type, function_params, spec_info,
581
+ type_tok, attributes)
582
+ end
583
+
584
+ # A function definition is the one external declaration whose declarator
585
+ # is followed by a compound statement (6.9.1); the declarator must be a
586
+ # function type and it stands alone. Every other shape — a function
587
+ # prototype, an object, or a comma-separated run mixing the two
588
+ # ("int f(int a), g(int a), a;") — is a declaration list, so a
589
+ # function-typed *first* declarator does not by itself commit the line to
590
+ # a definition: only a following "{" does.
591
+ if type.function? && peek.punct?("{")
592
+ # A function's parameters must be declared by the definition's own
593
+ # declarator (6.9.1p2): a function type reached through a typedef
594
+ # ("typedef int F(int); F f { ... }") supplies no parameter list of
595
+ # its own — `function_params` is nil — so it may declare a prototype
596
+ # but not a definition.
597
+ if function_params.nil?
598
+ error_at(name_tok, "function definition through a typedef is not allowed")
599
+ end
600
+ # A function reserves no object to align (6.7.5p2).
601
+ reject_alignas(spec_info.alignas, "function '#{name_tok.value}'")
602
+ declare_ordinary_name(name_tok.value, type)
603
+ register_visibility_attributes(name_tok.value, attributes)
604
+ register_init_attributes(name_tok.value, attributes)
605
+ return parse_function_definition(name_tok.value, type.return_type, function_params,
606
+ type_tok, spec_info.storage, type.variadic)
607
+ end
608
+
609
+ parse_external_declaration_list(base_type, name_tok, type, function_params,
610
+ pointer_quals, spec_info, type_tok, attributes)
611
+ end
612
+
613
+ # An old-style (K&R) function definition, 6.9.1's second form: a declarator
614
+ # whose parentheses hold an identifier-list, then the declaration-list that
615
+ # gives those identifiers their types, then the body —
616
+ #
617
+ # int add(a, b)
618
+ # int a;
619
+ # int b;
620
+ # { return a + b; }
621
+ #
622
+ # The declarator has already been read (`type` is the function type its
623
+ # suffix built with an empty parameter list, a placeholder this rebuilds).
624
+ # Three rules of 6.9.1 shape what follows: an identifier the
625
+ # declaration-list never declares has type `int` (p6); the parameters are
626
+ # adjusted and default-argument promoted, because a function defined this
627
+ # way has no prototype and its arguments therefore arrive promoted (p10
628
+ # with 6.5.2.2p6); and the identifier list is only legal here, in the
629
+ # definition of that very function (6.7.6.3p3).
630
+ #
631
+ # The declaration-list is read in the *enclosing* scope rather than the
632
+ # body's, so a tag first mentioned there ("int f(p) struct s *p; {...}")
633
+ # lands at file scope. That is a superset of what C scopes it to, and the
634
+ # alternative — a scope the body then inherits — would need the body's
635
+ # scope opened before the declaration-list is even seen; gcc warns about
636
+ # such a tag rather than making it useful, so nothing real depends on the
637
+ # difference.
638
+ def parse_old_style_function_definition(name_tok, type, identifier_list, spec_info,
639
+ return_tok, attributes)
640
+ # Every suffix that could have wrapped the identifier list into something
641
+ # other than a function type is already refused where it is applied (a
642
+ # function returning a function, an array of functions), so this only
643
+ # guards the invariant the rebuild below depends on.
644
+ error_at(name_tok, "expected a function declarator") unless type.function?
645
+
646
+ declared = parse_parameter_declaration_list(identifier_list)
647
+ params = old_style_parameters(identifier_list, declared)
648
+ abi_types = old_style_parameter_abi_types(name_tok.value, params.map(&:type))
649
+ params = params.each_with_index.map do |param, i|
650
+ next param if abi_types[i] == param.type
651
+
652
+ AST::Parameter.new(param.name, param.type, param.token, param.const, abi_types[i])
653
+ end
654
+ # The declarator's own suffix could only build "returning T" with an
655
+ # empty parameter list; the types are known now, so the function's real
656
+ # type is put together here. An old-style definition is never variadic —
657
+ # an identifier list has no "..." — so the flag is false throughout.
658
+ type = Type::FunctionType.new(type.return_type, abi_types, false)
659
+
660
+ # A function reserves no object to align (6.7.5p2).
661
+ reject_alignas(spec_info.alignas, "function '#{name_tok.value}'")
662
+ declare_ordinary_name(name_tok.value, type)
663
+ register_visibility_attributes(name_tok.value, attributes)
664
+ register_init_attributes(name_tok.value, attributes)
665
+ parse_function_definition(name_tok.value, type.return_type, params, return_tok,
666
+ spec_info.storage, false)
667
+ end
668
+
669
+ # The declaration-list of an old-style definition: the run of declarations
670
+ # between the declarator and the body, each declaring one or more of the
671
+ # identifiers the list named. Returns a "name => [type, const, token]" map
672
+ # for #old_style_parameters, and leaves the stream on the body's "{".
673
+ #
674
+ # These are parameter declarations, so they take a parameter's specifiers —
675
+ # const/volatile but no storage class other than `register`, the only one
676
+ # 6.9.1p6 admits (the shared specifier parse raises "'static' is not
677
+ # allowed here" for the rest) — and a parameter's adjustments, an array or
678
+ # function declarator becoming a pointer (6.7.6.3p7-8), which is what makes
679
+ # "int f(a) int a[10];" a pointer parameter exactly as the prototyped
680
+ # spelling is.
681
+ def parse_parameter_declaration_list(identifier_list)
682
+ names = identifier_list.names.map(&:value)
683
+ declared = {}
684
+ until peek.punct?("{")
685
+ unless type_specifier?(peek)
686
+ # A ";", "," or "=" here ends the declarator as a *declaration*, so
687
+ # this was never a definition and 6.7.6.3p3 has the last word on the
688
+ # identifier list. Anything else (a stray token, end of file) is a
689
+ # definition that simply broke off, and says so.
690
+ reject_identifier_list(identifier_list) if peek.punct?(";") || peek.punct?(",") ||
691
+ peek.punct?("=")
692
+ error_at(peek, "expected a parameter declaration or '{'")
693
+ end
694
+ parse_one_parameter_declaration(names, declared)
695
+ end
696
+ declared
697
+ end
698
+
699
+ # One declaration of the declaration-list: shared specifiers, then a
700
+ # comma-separated run of named declarators ("int a, *b;"), each of which
701
+ # must name a parameter of the identifier list exactly once.
702
+ def parse_one_parameter_declaration(names, declared)
703
+ base_type, spec_info = parse_declaration_specifiers(allow_storage_class: false,
704
+ allow_register: true)
705
+ loop do
706
+ # A parameter's array declarator adjusts to a pointer, so "[]" is
707
+ # admitted here for the same reason #parse_parameter_declaration admits
708
+ # it in a prototype.
709
+ name_tok, param_type, params, pointer_quals =
710
+ parse_declarator(base_type, allow_incomplete_array: true)
711
+ reject_identifier_list(params)
712
+ parse_attribute_specifiers # position d: a trailing attribute on this declarator
713
+ # A parameter's boundary belongs to the calling convention, not to the
714
+ # declaration (6.7.5p2) — the same refusal a prototyped parameter gets.
715
+ reject_alignas(spec_info.alignas, "parameter '#{name_tok.value}'")
716
+ if peek.punct?("=")
717
+ error_at(name_tok, "parameter '#{name_tok.value}' must not be initialized")
718
+ end
719
+ unless names.include?(name_tok.value)
720
+ error_at(name_tok, "declaration for '#{name_tok.value}', which is not a parameter")
721
+ end
722
+ if declared.key?(name_tok.value)
723
+ error_at(name_tok, "redefinition of parameter '#{name_tok.value}'")
724
+ end
725
+ param_type = adjust_parameter_type(param_type)
726
+ reject_void_type(param_type, name_tok)
727
+ declared[name_tok.value] = [param_type,
728
+ declarator_object_const(param_type, spec_info.const, pointer_quals),
729
+ name_tok]
730
+ break unless peek.punct?(",")
731
+
732
+ advance # ","
733
+ end
734
+ expect_punct(";")
735
+ end
736
+
737
+ # The parameters of an old-style definition, in the identifier list's
738
+ # order: each name's declared entry, or — for a name the declaration-list
739
+ # left out — type `int`, located at the identifier itself (6.9.1p6). C90
740
+ # spelled that default out; C11 instead requires every identifier to be
741
+ # declared, but gcc keeps accepting the omission with a -Wimplicit-int
742
+ # warning (measured), and a warning is not a channel this compiler has, so
743
+ # the older, permissive reading is the one implemented.
744
+ def old_style_parameters(identifier_list, declared)
745
+ identifier_list.names.map do |name_tok|
746
+ type, const, decl_tok = declared[name_tok.value]
747
+ if type
748
+ AST::Parameter.new(name_tok.value, type, decl_tok, const)
749
+ else
750
+ AST::Parameter.new(name_tok.value, Type::Int, name_tok, false)
751
+ end
752
+ end
753
+ end
754
+
755
+ # The types an old-style definition's parameters are actually *passed* as,
756
+ # which is also its function type's parameter list.
757
+ #
758
+ # Normally these are the default-argument promotions of the declared types:
759
+ # the definition supplies no prototype, so every call to it promotes its
760
+ # arguments (6.5.2.2p6) and 6.9.1p10 makes the definition receive them that
761
+ # way — a `float` parameter is handed a `double`, a `char`/`short`/`_Bool`
762
+ # parameter an `int`.
763
+ #
764
+ # A prototype already declared for the same name overrides that, because
765
+ # calls compiled against it pass what *it* says (measured: gcc's
766
+ # "double h(float); double h(f) float f; {...}" receives a bare float in
767
+ # xmm0, while the same definition without the prototype receives a double
768
+ # and narrows it). 6.7.6.3p14 requires each prototype parameter to be
769
+ # compatible with the promoted declared type; gcc additionally accepts the
770
+ # unpromoted declared type there, warning only under -Wpedantic, and that
771
+ # is the case this branch exists for. Anything else is left to reach the
772
+ # generator's "conflicting types" check as the promoted form, which rejects
773
+ # exactly the mismatches gcc rejects ("int f(long); int f(a) int a;").
774
+ def old_style_parameter_abi_types(name, declared_types)
775
+ promoted = declared_types.map { |type| default_argument_promotion(type) }
776
+ prototype = @prototype_param_types[name]
777
+ return promoted unless prototype && prototype.size == declared_types.size
778
+
779
+ adoptable = prototype.each_with_index.all? do |type, i|
780
+ type == declared_types[i] || type == promoted[i]
781
+ end
782
+ adoptable ? prototype : promoted
783
+ end
784
+
785
+ # The default argument promotions (6.5.2.2p6) applied to one parameter
786
+ # type: `float` widens to `double` and an integer type narrower than `int`
787
+ # (char, short, their unsigned forms and _Bool) to `int`, which every such
788
+ # type fits since `int` is 32 bits on both targets. Everything else — int,
789
+ # long, their unsigned forms, __int128, double, pointers and structs —
790
+ # passes through unchanged. The array/function adjustments are not applied
791
+ # here: the declaration-list already made them (see
792
+ # #parse_one_parameter_declaration), exactly as a prototype's parameters do.
793
+ def default_argument_promotion(type)
794
+ return Type::Double if type.float? && type.size < 8
795
+ return Type::Int if type.integer? && type.size < 4
796
+
797
+ type
798
+ end
799
+
800
+ # Refuses an identifier list at a declarator position that cannot be the
801
+ # definition of that function. 6.7.6.3p3 lets a non-empty identifier list
802
+ # appear only there, so a prototype, a typedef, a member, a parameter or a
803
+ # local written that way ("int f(a, b);") names parameters whose types it
804
+ # never supplies. gcc only warns and reads such a declarator as the
805
+ # unprototyped "int f()"; this compiler models no unprototyped function
806
+ # type, so reading it that way would silently give the name a "(void)"
807
+ # signature and then check every call against it — a confident wrong
808
+ # diagnosis in place of an accurate one.
809
+ def reject_identifier_list(params)
810
+ return unless params.is_a?(IdentifierList)
811
+
812
+ error_at(params.token,
813
+ "parameter names without types are only allowed in a function definition")
814
+ end
815
+
816
+ # The declaration-list form of an external declaration: a comma-separated
817
+ # run of init-declarators sharing `base_type`, the first already read into
818
+ # `first_*`. Each declarator independently becomes a FunctionDecl (a
819
+ # function prototype) or a GlobalDecl (a file-scope object), so one
820
+ # declaration may mix the two ("int f(int a), g(int a), a;"). The run ends
821
+ # at ";".
822
+ def parse_external_declaration_list(base_type, first_name_tok, first_type, first_params,
823
+ first_pointer_quals, spec_info, return_tok, first_attributes)
824
+ decls = [parse_external_declarator(first_name_tok, first_type, first_params,
825
+ first_pointer_quals, spec_info, return_tok, first_attributes)]
826
+ while peek.punct?(",")
827
+ advance
828
+ name_tok, type, params, pointer_quals = parse_declarator(base_type, allow_incomplete_array: true)
829
+ # position d: a trailing attribute on this declarator, joined by the
830
+ # specifier-position ones the whole declaration shares.
831
+ attributes = spec_info.attributes + parse_attribute_specifiers(init_attributes: :allow)
832
+ decls << parse_external_declarator(name_tok, type, params, pointer_quals, spec_info,
833
+ return_tok, attributes)
834
+ end
835
+ expect_punct(";")
836
+ decls
837
+ end
838
+
839
+ # One init-declarator of an external declaration list. A function-typed
840
+ # declarator is a prototype — a FunctionDecl whose name is recorded as an
841
+ # ordinary identifier (so an inner block shadowing it is told from a typedef
842
+ # use); every other declarator is a file-scope object (see
843
+ # #parse_global_declarator, which reads any "=" initializer). `spec_info`
844
+ # carries the shared storage class and the "inline"/"_Noreturn" flags,
845
+ # legal only on the function declarators (an object declarator rejects
846
+ # them downstream).
847
+ def parse_external_declarator(name_tok, type, params, pointer_quals, spec_info, return_tok,
848
+ attributes)
849
+ # This declarator ends at a "," or a ";", so it is a declaration and not
850
+ # a definition — the one place 6.7.6.3p3 allows a non-empty identifier
851
+ # list.
852
+ reject_identifier_list(params)
853
+ if type.function?
854
+ # A function reserves no object to align (6.7.5p2).
855
+ reject_alignas(spec_info.alignas, "function '#{name_tok.value}'")
856
+ declare_ordinary_name(name_tok.value, type)
857
+ # A prototype's parameter types are kept for the one construct that
858
+ # consults them, an old-style definition of the same name.
859
+ @prototype_param_types[name_tok.value] = type.param_types
860
+ register_visibility_attributes(name_tok.value, attributes)
861
+ register_init_attributes(name_tok.value, attributes)
862
+ AST::FunctionDecl.new(name_tok.value, type.return_type,
863
+ declarator_prototype_params(type, params, return_tok), return_tok,
864
+ spec_info.storage, type.variadic)
865
+ else
866
+ # An init attribute on an object has nothing to register — there is no
867
+ # function to call — so it is refused here. gcc only warns ("attribute
868
+ # ignored"), but a warning this compiler has no channel for would be a
869
+ # silent drop, and a dropped initializer is invisible until the program
870
+ # misbehaves at run time.
871
+ reject_init_attributes(attributes)
872
+ register_visibility_attributes(name_tok.value, attributes)
873
+ parse_global_declarator(type, name_tok, pointer_quals, spec_info)
874
+ end
875
+ end
876
+
877
+ # The Parameter list a function-typed declarator contributes to its
878
+ # prototype. When the declarator carries its own "( parameter-list )"
879
+ # suffix, `params` is that list (each with the declared name). When the
880
+ # function type instead arrives through a typedef — "typedef VALUE
881
+ # getter_t(ID, VALUE *); getter_t g;" — the declarator has no parameter
882
+ # suffix of its own, so `params` is nil; the prototype's parameters are
883
+ # then synthesized from the typedef's parameter types as unnamed
884
+ # parameters (6.7.6.3), exactly as an explicit "int f(int, int);"
885
+ # prototype models its own. Such a declaration is always a prototype: a
886
+ # function may not be *defined* through a typedef (6.9.1p2), which the
887
+ # definition path rejects separately.
888
+ def declarator_prototype_params(type, params, token)
889
+ return params if params
890
+
891
+ type.param_types.map { |param_type| AST::Parameter.new(nil, param_type, token, false) }
892
+ end
893
+
894
+ # One global declarator's tail, its type (array suffix included) already
895
+ # built: the void/incomplete checks and an optional "=" initializer.
896
+ # A plain scalar-integer initializer is a constant-expression (6.6) folded
897
+ # to a Ruby Integer on the spot (initializer_value). Every other admitted
898
+ # form is deferred to the generator as a raw node (initializer_node): a
899
+ # brace initializer-list for an aggregate or scalar, a string for a char
900
+ # array, or an address constant for a pointer (a null pointer, a "&global",
901
+ # a decayed global array name, or a string literal). A structural
902
+ # initializer also completes an inferred "[]" bound here. A non-constant
903
+ # scalar-integer initializer (a call, another variable, ...) is still
904
+ # rejected with "unsupported initializer for global variable"; the deferred
905
+ # forms the generator cannot fold reach the same diagnostic there.
906
+ def parse_global_declarator(type, name_tok, pointer_quals, spec_info)
907
+ reject_void_type(type, name_tok)
908
+ reject_object_specifiers(name_tok, spec_info)
909
+ const = declarator_object_const(type, spec_info.const, pointer_quals)
910
+ initializer_value = nil
911
+ initializer_node = nil
912
+ if peek.punct?("=")
913
+ # An "extern" object with an initializer is a definition, not a mere
914
+ # reference; the two together are contradictory, so reject them.
915
+ if spec_info.storage == :extern
916
+ error_at(name_tok, "'#{name_tok.value}' has both 'extern' and initializer")
917
+ end
918
+ advance # "="
919
+ init = parse_initializer
920
+ if InitializerResolver.structural?(type, init)
921
+ # A file-scope object always has static storage duration, which is
922
+ # what lets a trailing flexible array member be initialized.
923
+ type = InitializerResolver.resolve(type, init, static_storage: true).type
924
+ initializer_node = init
925
+ elsif type.integer? && !references_sizeof_expr?(init) && !references_address_of?(init)
926
+ # An integer scalar initializer is folded to a value here, where the
927
+ # constant evaluator carries no type table. A `sizeof <expression>`
928
+ # operand needs the operand's type, and an address-of (the
929
+ # "(size_t)&((T*)0)->m" offsetof idiom) needs the generator's
930
+ # address-constant machinery, so an initializer that uses either is
931
+ # deferred as a raw node for the generator to fold instead (it reaches
932
+ # the same "unsupported initializer" diagnostic there when genuinely
933
+ # not a constant).
934
+ initializer_value = evaluate_constant_expression(init, "unsupported initializer for global variable")
935
+ else
936
+ initializer_node = init
937
+ end
938
+ elsif type.array? && type.length.nil? && spec_info.storage != :extern
939
+ # An `extern T a[];` is a reference to an array defined elsewhere, an
940
+ # incomplete type the defining unit completes (6.7.6.2p1, 6.9.2); it is
941
+ # kept as-is. A non-extern `T a[];` is a tentative definition whose
942
+ # bound the standard completes to [1] — a completion M1 does not
943
+ # perform — so it stays a diagnostic here.
944
+ error_at(name_tok, "array size missing in '#{name_tok.value}'")
945
+ end
946
+ declare_ordinary_name(name_tok.value, type)
947
+ # The boundary is settled against the *finished* type, so an inferred
948
+ # "[]" bound is already in place when the "cannot reduce" check runs.
949
+ AST::GlobalDecl.new(name_tok.value, type, initializer_value, initializer_node, name_tok, const,
950
+ spec_info.storage,
951
+ alignas_boundary(spec_info.alignas, type, "'#{name_tok.value}'"))
952
+ end
953
+
954
+ # A bare type-specifier list with no storage class, used where a type is
955
+ # written with no declaration to hang it on: the type-name of a cast,
956
+ # sizeof, _Alignof or compound literal. It resolves to a single
957
+ # Rubycc::Type, discarding the (always-false) typedef flag. A type-name
958
+ # declares no object, so it has nothing for an _Alignas to align
959
+ # (6.7.5p2) — gcc refuses one here and so does this.
960
+ def parse_type_specifier
961
+ type, spec_info = parse_declaration_specifiers(allow_storage_class: false)
962
+ reject_alignas(spec_info.alignas, "type name")
963
+ type
964
+ end
965
+
966
+ # declaration-specifiers = (storage-class-specifier | type-qualifier |
967
+ # function-specifier | type-specifier)+. Consumes the whole specifier run —
968
+ # at most one storage class (6.7.1), any const/volatile/inline, and the
969
+ # type itself, all in any order. The base type any
970
+ # leading "*" run then builds a pointer from is one of: a run of
971
+ # integer/void keywords collected and normalized by
972
+ # #normalize_type_specifiers; a "struct"/"enum" specifier, which resolves
973
+ # or defines its tag; or a single typedef name, an identifier bound to a
974
+ # type in the ordinary namespace. A typedef name is recognized only as the
975
+ # first (and only) type-specifier — once any type keyword has been seen, a
976
+ # following identifier is the declarator, so "int T" declares a variable T
977
+ # even where T names a type (the standard rule that keeps typedef names
978
+ # shadowable). "_Atomic" appears in both of the roles C11 gives it — a
979
+ # qualifier written among the other specifiers ("_Atomic int x", "int
980
+ # _Atomic x") and the parenthesized atomic-type-specifier
981
+ # ("_Atomic(int) x"), the two told apart by #atomic_type_specifier? — and
982
+ # #reject_unsupported_atomic_type settles which types it may name. Mixing
983
+ # categories ("unsigned struct", "enum T", ...) is a
984
+ # diagnostic; `allow_storage_class` is false in the contexts a storage
985
+ # class or a function specifier ("inline"/"_Noreturn") cannot appear (a
986
+ # member, a parameter, a type-name), where const/volatile are still
987
+ # admitted ("int f(const int x)",
988
+ # "sizeof(const int)"). `allow_init_attributes` opens the
989
+ # constructor/destructor attributes, which only a file-scope declaration
990
+ # can act on; every other context refuses them rather than dropping them.
991
+ # Returns [base_type, DeclSpecInfo].
992
+ def parse_declaration_specifiers(allow_storage_class:, allow_register: false,
993
+ allow_init_attributes: false)
994
+ start_tok = peek
995
+ specs = [] # collected integer/void keyword strings
996
+ composite = nil # a struct/enum/typedef-name Type (excludes `specs`)
997
+ attributes = [] # GNU attributes written among the specifiers (position a)
998
+ storage = nil # recorded storage class: :typedef / :static / :extern
999
+ storage_seen = false # any storage-class specifier (for the 6.7.1 check)
1000
+ const_p = false
1001
+ inline_p = false
1002
+ noreturn_p = false
1003
+ typedef_const = false # const folded in from a const typedef name
1004
+ atomic_tok = nil # the first "_Atomic" written as a qualifier, for its diagnostic
1005
+ alignas = nil # the strongest _Alignas the run asked for
1006
+ loop do
1007
+ tok = peek
1008
+ if tok.type == :keyword && STORAGE_CLASS_KEYWORDS.include?(tok.value)
1009
+ # A parameter declaration admits exactly one storage class, `register`
1010
+ # (6.7.6.3p2), and no other — so `allow_register` opens that one
1011
+ # keyword without letting typedef/static/extern/auto through.
1012
+ unless allow_storage_class || (allow_register && tok.value == "register")
1013
+ error_at(tok, "'#{tok.value}' is not allowed here")
1014
+ end
1015
+ error_at(tok, "multiple storage classes in declaration specifiers") if storage_seen
1016
+ storage_seen = true
1017
+ # register/auto have no effect in this subset: they are consumed but
1018
+ # left unrecorded, only typedef/static/extern reaching later stages.
1019
+ storage = tok.value.to_sym if %w[typedef static extern].include?(tok.value)
1020
+ advance
1021
+ elsif tok.keyword?("const")
1022
+ const_p = true
1023
+ advance
1024
+ elsif tok.keyword?("volatile")
1025
+ advance # accepted and ignored: M1 carries no qualified types
1026
+ elsif tok.keyword?("_Atomic")
1027
+ if atomic_type_specifier?
1028
+ # "_Atomic ( type-name )" — a type-specifier, so it excludes every
1029
+ # other one exactly as a struct or enum specifier does.
1030
+ error_at(tok, "two or more data types in declaration specifiers") if composite || !specs.empty?
1031
+ composite = parse_atomic_type_specifier
1032
+ else
1033
+ # "_Atomic" written as a bare type qualifier, before or after the
1034
+ # type it qualifies. The type it lands on is only known once the
1035
+ # whole run is read, so the token is kept for the check below.
1036
+ atomic_tok ||= tok
1037
+ advance
1038
+ end
1039
+ elsif tok.keyword?("_Alignas")
1040
+ # An alignment-specifier may sit anywhere among the specifiers
1041
+ # ("_Alignas(8) int x", "int _Alignas(8) x"). Where it may appear at
1042
+ # all is the declarator's business — a typedef, function, parameter,
1043
+ # bit-field or type-name refuses it (6.7.5p2) — so it is only
1044
+ # collected here, strongest request winning.
1045
+ alignas = stronger_alignas(alignas, parse_alignment_specifier)
1046
+ elsif tok.keyword?("inline")
1047
+ error_at(tok, "'inline' is not allowed here") unless allow_storage_class
1048
+ inline_p = true
1049
+ advance
1050
+ elsif tok.keyword?("_Noreturn")
1051
+ # The second function specifier (6.7.4): rides the same "may only
1052
+ # appear where 'inline' may" rule and, like it, is only an
1053
+ # optimization hint (see include/stdnoreturn.h) so it is recorded
1054
+ # only for the object-declarator check below and otherwise dropped.
1055
+ # C11 permits repeating a function specifier, so a second
1056
+ # "_Noreturn" here simply re-sets the same flag.
1057
+ error_at(tok, "'_Noreturn' is not allowed here") unless allow_storage_class
1058
+ noreturn_p = true
1059
+ advance
1060
+ elsif tok.type == :keyword && DECL_SPECIFIER_KEYWORDS.include?(tok.value)
1061
+ error_at(tok, "two or more data types in declaration specifiers") if composite
1062
+ specs << advance.value
1063
+ elsif tok.keyword?("struct") || tok.keyword?("union")
1064
+ error_at(tok, "two or more data types in declaration specifiers") if composite || !specs.empty?
1065
+ composite = parse_struct_or_union_specifier
1066
+ elsif tok.keyword?("enum")
1067
+ error_at(tok, "two or more data types in declaration specifiers") if composite || !specs.empty?
1068
+ composite = parse_enum_specifier
1069
+ elsif tok.keyword?("__attribute__")
1070
+ # A GNU attribute may open the specifier run or sit between
1071
+ # specifiers (position a): "__attribute__((const)) int f(...)",
1072
+ # "int __attribute__((unused)) x;". None affects an object's type, so
1073
+ # the collected attributes are only kept for the caller's sake (the
1074
+ # init attributes, where this context admits them at all).
1075
+ attributes.concat(
1076
+ parse_attribute_specifiers(init_attributes: allow_init_attributes ? :allow : :reject)
1077
+ )
1078
+ elsif composite.nil? && specs.empty? && tok.type == :ident && typedef_name?(tok.value)
1079
+ composite, typedef_const = lookup_ordinary(tok.value).value
1080
+ advance
1081
+ else
1082
+ break
1083
+ end
1084
+ end
1085
+
1086
+ # A "const" typedef name ("typedef const int ci; ci x;") contributes its
1087
+ # const to the declaration, OR-ed with any const written here directly.
1088
+ spec_info = DeclSpecInfo.new(storage: storage, const: const_p || typedef_const,
1089
+ inline_p: inline_p, noreturn_p: noreturn_p, attributes: attributes,
1090
+ alignas: alignas)
1091
+ base = if composite
1092
+ composite
1093
+ else
1094
+ error_at(start_tok, "expected type specifier") if specs.empty?
1095
+ normalize_type_specifiers(specs, start_tok)
1096
+ end
1097
+ # A qualifier-spelled "_Atomic" qualifies whatever the run resolved to,
1098
+ # so its admissibility is settled here, once that type is known. The
1099
+ # parenthesized spelling checked its own operand in
1100
+ # #parse_atomic_type_specifier, where the type-name's own token locates
1101
+ # the diagnostic.
1102
+ reject_unsupported_atomic_type(base, atomic_tok) if atomic_tok
1103
+ [base, spec_info]
1104
+ end
1105
+
1106
+ # alignment-specifier = "_Alignas" "(" (type-name | constant-expression) ")"
1107
+ # (6.7.5). The type-name spelling asks for that type's own boundary, the
1108
+ # expression spelling for the folded value; the two are told apart exactly
1109
+ # as sizeof tells its operands apart, by whether a type-specifier opens the
1110
+ # parentheses. A request of zero "has no effect" (6.7.5p3) and so yields
1111
+ # nil, and any other non-power-of-two is a constraint violation gcc words
1112
+ # the same way an aligned(N) attribute's is. Returns an Alignas or nil.
1113
+ def parse_alignment_specifier
1114
+ alignas_tok = advance # "_Alignas"
1115
+ expect_punct("(")
1116
+ value = if type_specifier?(peek)
1117
+ alignment_of_type_name(alignas_tok)
1118
+ else
1119
+ evaluate_constant_expression(parse_conditional_expression,
1120
+ "'_Alignas' operand is not an integer constant",
1121
+ sizeof_expr: method(:fold_time_sizeof))
1122
+ end
1123
+ expect_punct(")")
1124
+ return nil if value.zero?
1125
+
1126
+ unless value.positive? && (value & (value - 1)).zero?
1127
+ error_at(alignas_tok, "requested alignment '#{value}' is not a positive power of 2")
1128
+ end
1129
+ Alignas.new(alignment: value, token: alignas_tok)
1130
+ end
1131
+
1132
+ # The boundary the "_Alignas ( type-name )" spelling asks for: the written
1133
+ # type's own alignment, read here at parse time (the expression spelling's
1134
+ # value is available just as early, so both reach the declarator as a plain
1135
+ # Integer). A type with no alignment to speak of — void, a function, or an
1136
+ # aggregate whose body this unit has not seen — is rejected the way
1137
+ # _Alignof rejects the same operands rather than reaching Type's "incomplete
1138
+ # struct has no alignment" guard.
1139
+ def alignment_of_type_name(alignas_tok)
1140
+ type = parse_type_name
1141
+ unless alignment_known?(type)
1142
+ error_at(alignas_tok, "invalid application of '_Alignas' to an incomplete type")
1143
+ end
1144
+ type.alignment
1145
+ end
1146
+
1147
+ # Whether `type` has a boundary that can be read right now. Void and a
1148
+ # function type have none at all, and an aggregate this unit has not
1149
+ # defined (directly or as an array's element) has none *yet* — asking any
1150
+ # of them for #alignment would trip Type's own guard.
1151
+ def alignment_known?(type)
1152
+ return false if type.void? || type.function?
1153
+ return type.complete? if type.struct?
1154
+ return alignment_known?(type.element) if type.array?
1155
+
1156
+ true
1157
+ end
1158
+
1159
+ # The stronger of two alignment requests from one specifier run, either of
1160
+ # which may be nil (no request). The larger boundary wins; on a tie the
1161
+ # earlier token is kept, so a diagnostic points at the first spelling.
1162
+ def stronger_alignas(current, addition)
1163
+ return current if addition.nil?
1164
+ return addition if current.nil?
1165
+
1166
+ addition.alignment > current.alignment ? addition : current
1167
+ end
1168
+
1169
+ # Rejects an _Alignas written where 6.7.5p2 forbids one, naming the
1170
+ # construct that refused it ("typedef", "parameter 'x'", ...). gcc's
1171
+ # wording, which names the same five constructs.
1172
+ def reject_alignas(alignas, what)
1173
+ return if alignas.nil?
1174
+
1175
+ error_at(alignas.token, "alignment specified for #{what}")
1176
+ end
1177
+
1178
+ # Enforces 6.7.5p4: an _Alignas may raise a declaration's boundary but
1179
+ # never lower it, so a request weaker than the declared type's own
1180
+ # alignment is a constraint violation rather than a silently ignored one.
1181
+ # Returns the requested boundary (an Integer), or nil when nothing was
1182
+ # asked for. `what` names the declarator in the diagnostic (gcc's wording:
1183
+ # "'x'" for a named one, "unnamed field" for an anonymous member).
1184
+ def alignas_boundary(alignas, type, what)
1185
+ return nil if alignas.nil?
1186
+
1187
+ # An incomplete declared type has no boundary to compare against; such a
1188
+ # declarator is refused for being incomplete downstream, so the check is
1189
+ # skipped rather than tripping Type's guard here.
1190
+ if alignment_known?(type) && alignas.alignment < type.alignment
1191
+ error_at(alignas.token, "'_Alignas' specifiers cannot reduce alignment of #{what}")
1192
+ end
1193
+ alignas.alignment
1194
+ end
1195
+
1196
+ # Whether the "_Atomic" at `peek` opens the parenthesized
1197
+ # atomic-type-specifier "_Atomic ( type-name )" rather than standing as a
1198
+ # bare type qualifier. C11 6.7.2.4 spells the two identically up to the
1199
+ # "(", and the grammar separates them by what follows it: a type-name
1200
+ # makes it the specifier, anything else leaves the "_Atomic" a qualifier
1201
+ # of the surrounding declaration ("_Atomic (*p)" qualifies the pointee).
1202
+ def atomic_type_specifier?
1203
+ peek_ahead(1)&.punct?("(") && !peek_ahead(2).nil? && type_specifier?(peek_ahead(2))
1204
+ end
1205
+
1206
+ # atomic-type-specifier = "_Atomic" "(" type-name ")" (6.7.2.4), the
1207
+ # "_Atomic" not yet consumed. The type-name is an ordinary one, so it may
1208
+ # itself be a pointer or a typedef name ("_Atomic(const upb_ArenaRef *)"
1209
+ # is how upb spells one), and it goes through the same admissibility check
1210
+ # the qualifier spelling does.
1211
+ def parse_atomic_type_specifier
1212
+ keyword_tok = advance # "_Atomic"
1213
+ # The type-name nests a full declarator, which may nest further
1214
+ # specifiers, so the shared recursion counter bounds it here just as it
1215
+ # bounds a struct body.
1216
+ with_nesting_guard(keyword_tok, "_Atomic type specifier") do
1217
+ expect_punct("(")
1218
+ type_tok = peek
1219
+ type = parse_type_name
1220
+ expect_punct(")")
1221
+ reject_unsupported_atomic_type(type, type_tok)
1222
+ type
1223
+ end
1224
+ end
1225
+
1226
+ # The object widths a plain machine access is indivisible at on both
1227
+ # targets: one naturally aligned load or store instruction covers each of
1228
+ # them, and #reject_unsupported_atomic_type admits an _Atomic type only at
1229
+ # these widths. Wider than 8 there is no such instruction on either
1230
+ # baseline ISA rubycc emits for (x86-64 without cmpxchg16b, armv8-a
1231
+ # without LSE), so an _Atomic 16-byte object would be a plainly
1232
+ # non-atomic one.
1233
+ ATOMIC_TYPE_WIDTHS = [1, 2, 4, 8].freeze
1234
+
1235
+ # Rejects an `_Atomic T` this subset cannot honestly represent.
1236
+ #
1237
+ # rubycc compiles `_Atomic T` as plain `T`: same layout, same ABI. That is
1238
+ # a measurement, not an assumption — gcc's sizeof and _Alignof for
1239
+ # `_Atomic(T)` equal those of `T` for every integer, floating and pointer
1240
+ # type (verified type by type in test/test_header_abi.rb's STDATOMIC
1241
+ # spec) — but it holds only for the types listed there. It fails for an
1242
+ # aggregate: gcc raises a power-of-two-sized struct's alignment to its
1243
+ # size under _Atomic (measured: a 2-byte struct goes from _Alignof 1 to 2,
1244
+ # a 16-byte one from 8 to 16), and an aggregate of any other size is not
1245
+ # lock-free at all, so gcc routes it through libatomic's locked path.
1246
+ # Compiling either as a plain struct would silently drop both the layout
1247
+ # and the atomicity, so an aggregate is refused here instead.
1248
+ #
1249
+ # The same reasoning bounds the widths: 16-byte scalars (`__int128`, and
1250
+ # `long double` on a target that has one) do share `T`'s layout, but no
1251
+ # single instruction accesses them on the ISA baselines rubycc emits, so
1252
+ # they are refused too. C11 6.7.2.4p3 already forbids `_Atomic` on an
1253
+ # array or a function type, and gcc diagnoses the array form
1254
+ # ("'_Atomic'-qualified array type", measured), so those get their own
1255
+ # message.
1256
+ def reject_unsupported_atomic_type(type, tok)
1257
+ if type.array? || type.function?
1258
+ error_at(tok, "'_Atomic' cannot be applied to #{type.array? ? "an array" : "a function"} type")
1259
+ end
1260
+ # "_Atomic void" names no object at all — the only way to write it is
1261
+ # "_Atomic void *", where the qualifier lands on a pointee nothing ever
1262
+ # loads — so gcc accepts it (measured) and so does this, leaving the
1263
+ # existing void-object rules to refuse a real "_Atomic void v;".
1264
+ return if type.void?
1265
+ return if (type.arithmetic? || type.pointer?) && ATOMIC_TYPE_WIDTHS.include?(type.size)
1266
+
1267
+ error_at(tok, "'_Atomic' is not supported on '#{type}': this subset applies it only to " \
1268
+ "integer, floating and pointer types of #{ATOMIC_TYPE_WIDTHS.join(", ")} bytes")
1269
+ end
1270
+
1271
+ # Collapses a multiset of integer type-specifier keywords (in any order:
1272
+ # "unsigned long", "long unsigned int", "long long int", ...) into a
1273
+ # single Rubycc::Type per 6.7.2. `void` and `_Bool` stand alone;
1274
+ # signed/unsigned choose the signedness; short/long (up to two longs, LP64
1275
+ # folding "long long" onto "long") and int/char choose the width, with a
1276
+ # bare "signed"/"unsigned" meaning int. Every ill-formed combination
1277
+ # ("short char", "long short", "signed unsigned", ...) is a diagnostic.
1278
+ def normalize_type_specifiers(specs, tok)
1279
+ counts = Hash.new(0)
1280
+ specs.each { |s| counts[s] += 1 }
1281
+
1282
+ return normalize_standalone(Type::Void, "void", specs, tok) if counts["void"].positive?
1283
+ return normalize_standalone(Type::Bool, "_Bool", specs, tok) if counts["_Bool"].positive?
1284
+ return normalize_standalone(Type::Float, "float", specs, tok) if counts["float"].positive?
1285
+ # `double` stands alone or pairs with a single `long` ("long double",
1286
+ # treated as `double` here); any other keyword, a second `double` or a
1287
+ # second `long` is an ill-formed combination.
1288
+ if counts["double"].positive?
1289
+ non_long = specs.reject { |s| s == "long" }
1290
+ unless non_long == ["double"] && counts["long"] <= 1
1291
+ error_at(tok, "cannot combine 'double' with other type specifiers")
1292
+ end
1293
+ return Type::Double
1294
+ end
1295
+
1296
+ # `__int128` (a GNU keyword) stands alone or pairs with a single
1297
+ # `signed`/`unsigned`, in any order ("unsigned __int128", "__int128
1298
+ # unsigned", "signed __int128"); no width keyword may join it. Its
1299
+ # signedness follows the same rule the standard integers use — a bare
1300
+ # `__int128` is signed, `unsigned` makes it unsigned.
1301
+ if counts["__int128"].positive?
1302
+ error_at(tok, "duplicate '__int128'") if counts["__int128"] > 1
1303
+ non_sign = specs.reject { |s| s == "signed" || s == "unsigned" }
1304
+ unless non_sign == ["__int128"]
1305
+ error_at(tok, "cannot combine '__int128' with other type specifiers")
1306
+ end
1307
+ if counts["signed"].positive? && counts["unsigned"].positive?
1308
+ error_at(tok, "both 'signed' and 'unsigned' in declaration specifiers")
1309
+ end
1310
+ return counts["unsigned"].positive? ? Type::UInt128 : Type::Int128
1311
+ end
1312
+
1313
+ signed = counts["signed"].positive?
1314
+ unsigned = counts["unsigned"].positive?
1315
+ short = counts["short"].positive?
1316
+ long = counts["long"]
1317
+ %w[signed unsigned short int char].each do |kw|
1318
+ error_at(tok, "duplicate '#{kw}'") if counts[kw] > 1
1319
+ end
1320
+ error_at(tok, "both 'signed' and 'unsigned' in declaration specifiers") if signed && unsigned
1321
+ error_at(tok, "more than two 'long's in declaration specifiers") if long > 2
1322
+
1323
+ if counts["char"].positive?
1324
+ if short || long.positive? || counts["int"].positive?
1325
+ error_at(tok, "both 'char' and a size specifier in declaration specifiers")
1326
+ end
1327
+ # The three character types are distinct: "unsigned char" and "signed
1328
+ # char" name their own fixed-signedness types, while a bare "char"
1329
+ # takes the target's plain-char instance (see #initialize).
1330
+ return Type::UChar if unsigned
1331
+ return Type::SChar if signed
1332
+
1333
+ return @plain_char
1334
+ end
1335
+
1336
+ error_at(tok, "both 'short' and 'long' in declaration specifiers") if short && long.positive?
1337
+
1338
+ if short
1339
+ unsigned ? Type::UShort : Type::Short
1340
+ elsif long.positive?
1341
+ unsigned ? Type::ULong : Type::Long
1342
+ else
1343
+ unsigned ? Type::UInt : Type::Int
1344
+ end
1345
+ end
1346
+
1347
+ # `void` and `_Bool` cannot combine with any other type-specifier keyword;
1348
+ # each must be the whole list.
1349
+ def normalize_standalone(type, keyword, specs, tok)
1350
+ unless specs == [keyword]
1351
+ error_at(tok, "cannot combine '#{keyword}' with other type specifiers")
1352
+ end
1353
+ type
1354
+ end
1355
+
1356
+ # struct-or-union-specifier: a "struct" or "union" keyword (the two differ
1357
+ # only in the aggregate's `kind` and thus its layout), an optional tag,
1358
+ # and an optional "{ ... }" body. Three shapes result:
1359
+ # * "struct tag { ... }" / "struct { ... }" — a definition; the tagged
1360
+ # one is registered (or completed) in the current tag scope, an
1361
+ # anonymous one is a fresh unnamed type. #parse_struct_body lays it out.
1362
+ # * "struct tag" — a reference; resolved through the tag scopes, or, when
1363
+ # the tag is unknown, forward-declared as an incomplete aggregate in
1364
+ # the current scope (so "struct node;" and a pointer to a
1365
+ # not-yet-defined tag both work — the union spellings behave alike).
1366
+ def parse_struct_or_union_specifier
1367
+ keyword_tok = advance # "struct" or "union"
1368
+ kind = keyword_tok.value == "union" ? :union : :struct
1369
+ # A struct/union body may hold members whose own type is a further
1370
+ # struct/union definition ("struct { struct { ... } a; } b;"), which
1371
+ # recurses back here through #parse_struct_body; guarding at the keyword
1372
+ # bounds that nesting on the shared counter.
1373
+ with_nesting_guard(keyword_tok, "type definition") do
1374
+ # A GNU attribute may sit right after the keyword, before the tag or "{"
1375
+ # (position b): "struct __attribute__((aligned(8))) S { ... }". Only its
1376
+ # aligned/packed carry layout meaning, and only on a definition.
1377
+ leading_attrs = parse_attribute_specifiers
1378
+ tag_tok = peek.type == :ident ? advance : nil
1379
+ tag = tag_tok&.value
1380
+
1381
+ if peek.punct?("{")
1382
+ struct_type = tag ? define_struct_tag(tag, kind, keyword_tok) : Type::StructType.new(nil, kind: kind)
1383
+ raw_members = parse_struct_body(kind, keyword_tok)
1384
+ # A second attribute run may follow the closing "}" (position c),
1385
+ # before the declarator list or ";"; the two runs combine on the layout.
1386
+ trailing_attrs = parse_attribute_specifiers
1387
+ aligned, packed = resolve_layout_attributes(leading_attrs + trailing_attrs)
1388
+ # A packed aggregate that also carries a bit-field would need bit-level
1389
+ # packing across storage units this subset does not model, so the
1390
+ # combination is rejected rather than laid out wrongly (Step 28 C2).
1391
+ if packed && raw_members.any? { |triple| triple[2] }
1392
+ error_at(keyword_tok, "packed bit-fields are not supported")
1393
+ end
1394
+ struct_type.define(raw_members, packed: packed, aligned: aligned,
1395
+ unnamed_bitfields_align: @unnamed_bitfields_align)
1396
+ struct_type
1397
+ elsif tag
1398
+ reference_struct_tag(tag, kind, tag_tok)
1399
+ else
1400
+ error_at(keyword_tok, "expected identifier or '{' after '#{keyword_tok.value}'")
1401
+ end
1402
+ end
1403
+ end
1404
+
1405
+ # Consumes a run of GNU __attribute__ specifiers (each
1406
+ # "__attribute__ ( ( attribute-list ) )", ISO C23's attribute-specifier
1407
+ # sequence spelled the GNU way), returning the collected Attributes for the
1408
+ # caller to interpret. A caller that gives attributes no meaning (most
1409
+ # positions) simply discards the result. `__attribute__` is a keyword here,
1410
+ # so it never collides with an ordinary identifier. Nothing is consumed
1411
+ # when no attribute is present.
1412
+ #
1413
+ # `init_attributes` guards the one attribute family whose absence cannot be
1414
+ # noticed: a discarded constructor/destructor leaves a program that links
1415
+ # and runs but never initializes itself. It defaults to :reject, so a
1416
+ # position not explicitly taught to claim them diagnoses instead of
1417
+ # dropping; only the file-scope declaration positions pass :allow.
1418
+ def parse_attribute_specifiers(init_attributes: :reject)
1419
+ attributes = []
1420
+ while peek.keyword?("__attribute__")
1421
+ advance # "__attribute__"
1422
+ expect_punct("(")
1423
+ expect_punct("(")
1424
+ parse_attribute_list(attributes)
1425
+ expect_punct(")")
1426
+ expect_punct(")")
1427
+ end
1428
+ reject_init_attributes(attributes) unless init_attributes == :allow
1429
+ attributes
1430
+ end
1431
+
1432
+ # Refuses a constructor/destructor attribute written where this parser
1433
+ # cannot act on it (a struct/union specifier, a member, a parameter, a
1434
+ # type-name, a typedef name, a block-scope declaration, a file-scope
1435
+ # object). Any of those would otherwise be dropped without a trace.
1436
+ def reject_init_attributes(attributes)
1437
+ attributes.each do |attr|
1438
+ next unless INIT_ATTRIBUTES.key?(attr.name)
1439
+
1440
+ error_at(attr.token,
1441
+ "'#{attr.name}' attribute is only accepted on a file-scope function declaration")
1442
+ end
1443
+ end
1444
+
1445
+ # Records the .init_array / .fini_array registration `attributes` ask for
1446
+ # under the function's name. Both a prototype and the definition may carry
1447
+ # them, in either order — gcc accepts "static void f(void)
1448
+ # __attribute__((constructor)); static void f(void) { }" and the reverse —
1449
+ # so the table is keyed by name and matched against the definitions once
1450
+ # the whole unit is parsed (see AST::Program#init_attributes). A name that
1451
+ # is only declared here registers nothing, since the array slot belongs to
1452
+ # the object that defines the function; gcc emits nothing for it either.
1453
+ #
1454
+ # Repeating an attribute is fine as long as it asks for the same priority.
1455
+ # gcc silently keeps the first of two conflicting ones; that quietly runs
1456
+ # the initializers in an order the source did not ask for, so it is a
1457
+ # diagnostic here instead.
1458
+ def register_init_attributes(name, attributes)
1459
+ attributes.each do |attr|
1460
+ kind = INIT_ATTRIBUTES[attr.name]
1461
+ next unless kind
1462
+
1463
+ priority = attr.argument || DEFAULT_INIT_PRIORITY
1464
+ record = @init_attributes[name] ||= AST::InitAttributes.new(constructor: nil, destructor: nil)
1465
+ previous = record.public_send(kind)
1466
+ if previous && previous != priority
1467
+ error_at(attr.token, "conflicting '#{attr.name}' priorities for '#{name}' " \
1468
+ "(#{previous} and #{priority})")
1469
+ end
1470
+ @init_attributes[name] = record.with(kind => priority)
1471
+ end
1472
+ end
1473
+
1474
+ def register_visibility_attributes(name, attributes)
1475
+ attributes.each do |attribute|
1476
+ next unless attribute.name == "visibility"
1477
+
1478
+ @visibility_attributes[name] = attribute.argument
1479
+ end
1480
+ end
1481
+
1482
+ # attribute-list: a comma-separated sequence of attributes, possibly empty
1483
+ # ("__attribute__(())") and admitting empty elements ("__attribute__((,))",
1484
+ # which gcc allows), each appended to `attributes` as a [name, argument]
1485
+ # pair (argument is the folded aligned value, or nil).
1486
+ def parse_attribute_list(attributes)
1487
+ loop do
1488
+ parse_attribute(attributes) unless peek.punct?(",") || peek.punct?(")")
1489
+ break unless peek.punct?(",")
1490
+
1491
+ advance # ","
1492
+ end
1493
+ end
1494
+
1495
+ # One attribute: an attribute-token (an identifier, or a keyword — gcc
1496
+ # spells several attributes with keywords, e.g. "__attribute__((const))")
1497
+ # optionally followed by a parenthesized argument clause. Its name is
1498
+ # normalized (see #normalize_attribute_name) and paired with the folded
1499
+ # argument value #parse_attribute_arguments returns (meaningful only for
1500
+ # "aligned" and the init attributes; nil otherwise).
1501
+ def parse_attribute(attributes)
1502
+ name_tok = peek
1503
+ unless name_tok.type == :ident || name_tok.type == :keyword
1504
+ error_at(name_tok, "expected attribute name")
1505
+ end
1506
+ advance
1507
+ name = normalize_attribute_name(name_tok.value)
1508
+ argument = peek.punct?("(") ? parse_attribute_arguments(name) : nil
1509
+ attributes << Attribute.new(name: name, argument: argument, token: name_tok)
1510
+ end
1511
+
1512
+ # An attribute's parenthesized argument clause. "aligned(N)" and
1513
+ # "constructor(N)" / "destructor(N)" each carry a single integer
1514
+ # constant-expression that must be folded and range-checked here, so they
1515
+ # are parsed for real; every other attribute's arguments (bare identifiers,
1516
+ # string literals, comma-separated integers such as "format(printf, 1, 2)")
1517
+ # are accepted and discarded, so its balanced parentheses are skipped
1518
+ # verbatim. Returns the folded value, or nil for any other attribute.
1519
+ def parse_attribute_arguments(name)
1520
+ return parse_aligned_argument if name == "aligned"
1521
+ return parse_init_priority_argument(name) if INIT_ATTRIBUTES.key?(name)
1522
+ return parse_visibility_argument if name == "visibility"
1523
+
1524
+ skip_balanced_parentheses && nil
1525
+ end
1526
+
1527
+ def parse_visibility_argument
1528
+ advance # "("
1529
+ tok = peek
1530
+ unless %i[string ident keyword].include?(tok.type)
1531
+ error_at(tok, "visibility attribute requires a string or identifier argument")
1532
+ end
1533
+ value = tok.value.to_s
1534
+ advance
1535
+ expect_punct(")")
1536
+ unless %w[default hidden internal protected].include?(value)
1537
+ error_at(tok, "unknown visibility '#{value}'")
1538
+ end
1539
+ value.to_sym
1540
+ end
1541
+
1542
+ def parse_aligned_argument
1543
+ expr = parse_parenthesized_constant
1544
+ value = evaluate_constant_expression(expr, "'aligned' attribute argument is not an integer constant",
1545
+ sizeof_expr: method(:fold_time_sizeof))
1546
+ unless value.positive? && (value & (value - 1)).zero?
1547
+ error_at(expr.token, "requested alignment '#{value}' is not a positive power of 2")
1548
+ end
1549
+ value
1550
+ end
1551
+
1552
+ # The run-order number of a constructor/destructor. The window and its
1553
+ # wording follow gcc's measured behavior (see MAX_INIT_PRIORITY); the
1554
+ # 0..100 range gcc reserves for the implementation is accepted here, since
1555
+ # gcc only warns about it and this compiler has no warning channel.
1556
+ def parse_init_priority_argument(name)
1557
+ expr = parse_parenthesized_constant
1558
+ value = evaluate_constant_expression(expr, "'#{name}' attribute argument is not an integer constant",
1559
+ sizeof_expr: method(:fold_time_sizeof))
1560
+ unless value.between?(MIN_INIT_PRIORITY, MAX_INIT_PRIORITY)
1561
+ error_at(expr.token, "#{name} priorities must be integers from " \
1562
+ "#{MIN_INIT_PRIORITY} to #{MAX_INIT_PRIORITY} inclusive")
1563
+ end
1564
+ value
1565
+ end
1566
+
1567
+ # "( constant-expression )" — an attribute argument clause holding exactly
1568
+ # one expression, returned unfolded for the caller to evaluate under its
1569
+ # own diagnostic.
1570
+ def parse_parenthesized_constant
1571
+ advance # "("
1572
+ expr = parse_conditional_expression
1573
+ expect_punct(")")
1574
+ expr
1575
+ end
1576
+
1577
+ # Skips a balanced-parenthesis token run (an attribute argument clause we
1578
+ # give no meaning), from the opening "(" through its matching ")". Returns
1579
+ # true so #parse_attribute_arguments can chain it with "&& nil".
1580
+ def skip_balanced_parentheses
1581
+ expect_punct("(")
1582
+ depth = 1
1583
+ until depth.zero?
1584
+ tok = peek
1585
+ error_at(tok, "unterminated attribute argument list") if tok.eof?
1586
+ depth += 1 if tok.punct?("(")
1587
+ depth -= 1 if tok.punct?(")")
1588
+ advance
1589
+ end
1590
+ true
1591
+ end
1592
+
1593
+ # Normalizes a GNU attribute name: a "__name__" spelling collapses to
1594
+ # "name" — exactly one leading and one trailing "__" stripped when both are
1595
+ # present — so "__aligned__" and "aligned" name the same attribute. A name
1596
+ # underscored on only one side, or too short to carry both pairs, is left
1597
+ # as written.
1598
+ def normalize_attribute_name(name)
1599
+ if name.start_with?("__") && name.end_with?("__") && name.length > 4
1600
+ name[2..-3]
1601
+ else
1602
+ name
1603
+ end
1604
+ end
1605
+
1606
+ # Reduces a struct/union specifier's collected attributes to the layout
1607
+ # override StructType#define takes: [aligned, packed]. `aligned` is the
1608
+ # largest power-of-two boundary any "aligned" attribute asked for (a bare
1609
+ # "aligned" with no argument meaning BIGGEST_ALIGNMENT), or nil when none
1610
+ # appeared; `packed` is whether any "packed" attribute was present. Every
1611
+ # unrecognized attribute has already been discarded, so only these two
1612
+ # remain to interpret.
1613
+ def resolve_layout_attributes(attributes)
1614
+ aligned = nil
1615
+ packed = false
1616
+ attributes.each do |attr|
1617
+ case attr.name
1618
+ when "aligned"
1619
+ value = attr.argument || BIGGEST_ALIGNMENT
1620
+ aligned = value if aligned.nil? || value > aligned
1621
+ when "packed"
1622
+ packed = true
1623
+ end
1624
+ end
1625
+ [aligned, packed]
1626
+ end
1627
+
1628
+ # Consumes any run of leading "__extension__" markers (a GNU keyword that
1629
+ # only silences pedantic diagnostics). Used wherever a declaration may be
1630
+ # prefixed by one; the unary-expression prefix form is handled separately
1631
+ # in #parse_cast_expression.
1632
+ def skip_extension_markers
1633
+ advance while peek.keyword?("__extension__")
1634
+ end
1635
+
1636
+ # Whether the token `offset` tokens ahead of a run of "__extension__"
1637
+ # markers opens a declaration, so block-item and for-init can tell a
1638
+ # "__extension__ int x;" declaration from a "__extension__ expr;"
1639
+ # expression statement without committing to either first.
1640
+ def extension_prefixes_declaration?
1641
+ return false unless peek.keyword?("__extension__")
1642
+
1643
+ offset = 1
1644
+ offset += 1 while peek_ahead(offset)&.keyword?("__extension__")
1645
+ following = peek_ahead(offset)
1646
+ !following.nil? && (type_specifier?(following) || following.keyword?("_Static_assert"))
1647
+ end
1648
+
1649
+ # enum-specifier (6.7.2.2): "enum identifier? { enumerator-list ,? }"
1650
+ # defines the enumeration (registering the tag, if named, and every
1651
+ # enumerator as an int constant in the current ordinary scope), while
1652
+ # "enum identifier" references a previously defined enum tag. Either way an
1653
+ # enum object is an int, so the specifier resolves to Type::Int and no
1654
+ # dedicated enum type exists. Unlike a struct, an enum has no incomplete
1655
+ # form: a reference to a tag with no visible definition is an error on the
1656
+ # spot, since an int-sized object cannot be laid out from an unknown set of
1657
+ # constants.
1658
+ def parse_enum_specifier
1659
+ enum_tok = advance # "enum"
1660
+ tag_tok = peek.type == :ident ? advance : nil
1661
+ tag = tag_tok&.value
1662
+
1663
+ if peek.punct?("{")
1664
+ register_enum_tag(tag, tag_tok) if tag
1665
+ parse_enum_body
1666
+ Type::Int
1667
+ elsif tag
1668
+ resolve_enum_tag(tag, tag_tok)
1669
+ else
1670
+ error_at(enum_tok, "expected identifier or '{' after 'enum'")
1671
+ end
1672
+ end
1673
+
1674
+ # Registers an enum tag being defined in the current scope. A name already
1675
+ # taken there by a *complete* enum is a redefinition; one taken by a struct
1676
+ # tag is the wrong kind of tag (struct, union and enum share one namespace).
1677
+ # A tag already forward-declared incomplete in this scope (an EnumType, from
1678
+ # "enum E *p;") is completed here: the marker becomes an EnumTag, so later
1679
+ # "enum E" references resolve to int. Earlier pointer references keep the
1680
+ # incomplete EnumType they captured, which stays valid as a pointer target.
1681
+ def register_enum_tag(tag, token)
1682
+ existing = @tag_scopes.last[tag]
1683
+ if existing
1684
+ if existing.is_a?(EnumTag)
1685
+ error_at(token, "redefinition of 'enum #{tag}'")
1686
+ elsif !existing.is_a?(Type::EnumType)
1687
+ error_at(token, "'#{tag}' defined as wrong kind of tag")
1688
+ else
1689
+ # An earlier forward reference ("enum efoo;", or a prototype's
1690
+ # "enum efoo" return type) captured this incomplete EnumType. Complete
1691
+ # it in place so that captured object now answers as the int an enum
1692
+ # object is — the reference and this definition then agree on the type.
1693
+ existing.complete!
1694
+ end
1695
+ end
1696
+ @tag_scopes.last[tag] = EnumTag.new(tag)
1697
+ end
1698
+
1699
+ # Resolves a bare "enum tag" reference (innermost scope outward). A defined
1700
+ # tag (an EnumTag) resolves to Type::Int, since an enum object is an int; a
1701
+ # tag bound to a struct is the wrong kind of tag. A tag with no visible
1702
+ # binding is forward-declared incomplete — mirroring an incomplete struct —
1703
+ # so "enum E *p;" names a pointer to an as-yet-undefined enum; a later
1704
+ # in-scope forward reference reuses that same incomplete EnumType. The
1705
+ # generator rejects an incomplete enum wherever a size or arithmetic is
1706
+ # actually required.
1707
+ def resolve_enum_tag(tag, token)
1708
+ @tag_scopes.reverse_each do |scope|
1709
+ found = scope[tag]
1710
+ next unless found
1711
+
1712
+ return Type::Int if found.is_a?(EnumTag)
1713
+ return found if found.is_a?(Type::EnumType)
1714
+
1715
+ error_at(token, "'#{tag}' defined as wrong kind of tag")
1716
+ end
1717
+ incomplete = Type::EnumType.new(tag)
1718
+ @tag_scopes.last[tag] = incomplete
1719
+ incomplete
1720
+ end
1721
+
1722
+ # Parses "{ enumerator-list ,? }" (the enumerator-list must be non-empty).
1723
+ # Each enumerator takes the previous value plus one, the first being 0,
1724
+ # unless it names an explicit "= constant"; the folded value is bound as an
1725
+ # int enum constant in the current ordinary scope. A trailing comma before
1726
+ # "}" is allowed (C99).
1727
+ def parse_enum_body
1728
+ expect_punct("{")
1729
+ next_value = 0
1730
+ loop do
1731
+ name_tok = expect_ident
1732
+ value = next_value
1733
+ if peek.punct?("=")
1734
+ advance # "="
1735
+ expr = parse_conditional_expression
1736
+ value = evaluate_constant_expression(expr, "enumerator value is not an integer constant",
1737
+ sizeof_expr: method(:fold_time_sizeof))
1738
+ end
1739
+ declare_enum_constant(name_tok, value)
1740
+ next_value = value + 1
1741
+ break unless peek.punct?(",")
1742
+
1743
+ advance # ","
1744
+ break if peek.punct?("}") # trailing comma ends the list
1745
+ end
1746
+ expect_punct("}")
1747
+ end
1748
+
1749
+ # Binds an enumerator's name to its value as an int constant in the current
1750
+ # ordinary scope. A name already bound there — by another enumerator or by
1751
+ # a variable — is a redefinition.
1752
+ def declare_enum_constant(name_tok, value)
1753
+ if @ordinary_scopes.last.key?(name_tok.value)
1754
+ error_at(name_tok, "redefinition of '#{name_tok.value}'")
1755
+ end
1756
+ @ordinary_scopes.last[name_tok.value] = OrdinaryName.new(:enum, value)
1757
+ end
1758
+
1759
+ # Resolves the tag being *defined* to the StructType #parse_struct_body
1760
+ # will lay out. A tag already declared in the *current* scope is reused
1761
+ # (completing an earlier "struct tag;" forward declaration or the
1762
+ # in-progress self-reference), unless it is already complete, which makes
1763
+ # the second body a redefinition. A tag already taken by a differing kind
1764
+ # (an enum, or the other of struct/union) is the wrong kind of tag. An
1765
+ # unknown tag is created incomplete and registered up front — before its
1766
+ # body is parsed — so a member that points back at the same tag ("struct
1767
+ # node *next;") resolves to this very object.
1768
+ def define_struct_tag(tag, kind, token)
1769
+ existing = @tag_scopes.last[tag]
1770
+ if existing
1771
+ reject_wrong_tag_kind(existing, kind, tag, token)
1772
+ error_at(token, "redefinition of '#{tag_keyword(kind)} #{tag}'") if existing.complete?
1773
+ return existing
1774
+ end
1775
+ struct_type = Type::StructType.new(tag, kind: kind)
1776
+ @tag_scopes.last[tag] = struct_type
1777
+ struct_type
1778
+ end
1779
+
1780
+ # Resolves a bare "struct tag" reference. An in-scope tag (searched
1781
+ # innermost outward) is returned as is — complete or not — provided it is
1782
+ # the same kind of aggregate; a tag bound to an enum or the other of
1783
+ # struct/union is the wrong kind of tag. An unknown tag is forward-declared:
1784
+ # a fresh incomplete aggregate of this kind is registered in the current
1785
+ # scope, so "struct node;" introduces the tag and "struct node *p;" names a
1786
+ # pointer to an as-yet-undefined struct.
1787
+ def reference_struct_tag(tag, kind, token)
1788
+ @tag_scopes.reverse_each do |scope|
1789
+ found = scope[tag]
1790
+ next unless found
1791
+
1792
+ reject_wrong_tag_kind(found, kind, tag, token)
1793
+ return found
1794
+ end
1795
+ struct_type = Type::StructType.new(tag, kind: kind)
1796
+ @tag_scopes.last[tag] = struct_type
1797
+ struct_type
1798
+ end
1799
+
1800
+ # Rejects a tag whose existing binding disagrees with the kind now written
1801
+ # for it: struct, union and enum share one namespace (6.7.2.3), so "union
1802
+ # S" against a "struct S", or either against an "enum S", is the wrong kind
1803
+ # of tag. An enum binding is an EnumTag (a defined enum) or a Type::EnumType
1804
+ # (an incomplete, forward-declared one); a struct/union binding is a
1805
+ # StructType told apart by #union?.
1806
+ def reject_wrong_tag_kind(existing, kind, tag, token)
1807
+ wrong = existing.is_a?(EnumTag) || existing.is_a?(Type::EnumType) ||
1808
+ existing.union? != (kind == :union)
1809
+ error_at(token, "'#{tag}' defined as wrong kind of tag") if wrong
1810
+ end
1811
+
1812
+ # The keyword spelling for an aggregate kind, for diagnostics.
1813
+ def tag_keyword(kind)
1814
+ kind == :union ? "union" : "struct"
1815
+ end
1816
+
1817
+ # Parses a struct/union's "{ struct-declaration+ }" body, returning the
1818
+ # raw [name, Type] member pairs the caller hands to StructType#define
1819
+ # (deferred so an attribute after "}" can still steer the layout). A
1820
+ # struct-declaration is either a type-specifier
1821
+ # followed by one or more comma-separated declarators (each contributing a
1822
+ # "*" run and an optional array suffix), just like a local declaration but
1823
+ # with no initializer, or — for an anonymous member (C11 6.7.2.1p13) — a
1824
+ # tagless struct/union specifier with no declarator at all. A named member
1825
+ # may not be void, an incomplete aggregate by value, or a duplicate name;
1826
+ # a pointer to an incomplete struct (the self-referential case) is fine,
1827
+ # since a pointer is always complete. `seen` tracks every member name
1828
+ # visible from this body, folding in the names an anonymous member exposes
1829
+ # transparently, so a collision through one is diagnosed like any other.
1830
+ def parse_struct_body(kind, keyword_tok)
1831
+ expect_punct("{")
1832
+ raw_members = []
1833
+ seen = {}
1834
+ # Tracks a flexible array member as the body is read (ISO C 6.7.2.1p18):
1835
+ # `token` is the FAM's name once seen, so any further member declared
1836
+ # after it is diagnosed (a FAM must be the struct's last member), and
1837
+ # `others` counts the ordinary members, so a struct whose *only* member
1838
+ # is a FAM is rejected. `kind` lets a FAM in a union be rejected.
1839
+ flex = { kind: kind, token: nil, others: 0 }
1840
+ until peek.punct?("}")
1841
+ # GCC accepts an empty declaration in an aggregate body. Generated C
1842
+ # commonly reaches it when a declaration macro already supplies `;`
1843
+ # and the call site supplies another one (libev's VARx is one such
1844
+ # case). It contributes no member and must not be mistaken for a
1845
+ # declarator-less anonymous member.
1846
+ if peek.punct?(";")
1847
+ advance
1848
+ next
1849
+ end
1850
+
1851
+ spec_tok = peek
1852
+ # An _Alignas among a member declaration's specifiers belongs to every
1853
+ # declarator it introduces, exactly as the base type does, so it is
1854
+ # carried alongside it rather than folded into the type.
1855
+ member_base, member_spec = parse_declaration_specifiers(allow_storage_class: false)
1856
+ alignas = member_spec.alignas
1857
+ if peek.punct?(";")
1858
+ parse_anonymous_member(member_base, spec_tok, raw_members, seen, flex, alignas)
1859
+ else
1860
+ parse_member_declarators(member_base, spec_tok, raw_members, seen, flex, alignas)
1861
+ end
1862
+ expect_punct(";")
1863
+ end
1864
+ expect_punct("}")
1865
+ if flex[:token] && flex[:others].zero?
1866
+ error_at(flex[:token], "flexible array member '#{flex[:token].value}' in a struct with no other members")
1867
+ end
1868
+ raw_members
1869
+ end
1870
+
1871
+ # A struct-declaration with no declarator. It is well-formed only as an
1872
+ # anonymous member — a tagless struct/union specifier (its type is an
1873
+ # aggregate with no tag); a tagged specifier standing alone ("struct Inner
1874
+ # {...};" or "struct Inner;" inside a body) or any other bare type
1875
+ # declares nothing and is rejected. The member is recorded with a nil name
1876
+ # and its inner type; every name it exposes transparently is added to
1877
+ # `seen` so a later member cannot shadow one of them.
1878
+ def parse_anonymous_member(member_base, spec_tok, raw_members, seen, flex, alignas = nil)
1879
+ reject_member_after_flexible_array(flex, spec_tok)
1880
+ unless member_base.struct? && member_base.tag.nil?
1881
+ error_at(spec_tok, "declaration does not declare anything")
1882
+ end
1883
+ transparent_member_names(member_base).each do |name|
1884
+ error_at(spec_tok, "duplicate member '#{name}'") if seen.key?(name)
1885
+ seen[name] = true
1886
+ end
1887
+ flex[:others] += 1
1888
+ raw_members << [nil, member_base, nil, alignas_boundary(alignas, member_base, "unnamed field")]
1889
+ end
1890
+
1891
+ # The comma-separated struct-declarators sharing `member_base`. Each is
1892
+ # either a declarator naming a member (a "*" run, an array suffix, or a
1893
+ # function-pointer shape such as "int (*handler)(int)"), optionally followed
1894
+ # by ": constant-expression" to make it a bit-field, or a bare
1895
+ # ": constant-expression" with no declarator — an unnamed bit-field that
1896
+ # shapes the layout but declares nothing (6.7.2.1). A member may not be a
1897
+ # bare function; a pointer to one is fine. Each named member is checked for
1898
+ # a duplicate against `seen` (which already holds any transparently exposed
1899
+ # names) and then added to it. Every recorded entry is
1900
+ # [name, Type, bit_width, alignas], bit_width nil for a plain member and
1901
+ # alignas the boundary an _Alignas asked for (nil for none).
1902
+ def parse_member_declarators(member_base, spec_tok, raw_members, seen, flex, alignas = nil)
1903
+ loop do
1904
+ reject_member_after_flexible_array(flex, spec_tok)
1905
+ if peek.punct?(":")
1906
+ advance # ":"
1907
+ # A bit-field has no address of its own to align, so 6.7.5p2 forbids
1908
+ # an _Alignas on one.
1909
+ reject_alignas(alignas, "bit-field")
1910
+ # An unnamed bit-field declares no member, so it does not satisfy the
1911
+ # "a FAM needs another named member" rule (flex[:others] untouched).
1912
+ raw_members << [nil, member_base, parse_bitfield_width(member_base, spec_tok)]
1913
+ else
1914
+ parse_named_member(member_base, raw_members, seen, flex, alignas)
1915
+ end
1916
+ break unless peek.punct?(",")
1917
+
1918
+ advance
1919
+ end
1920
+ end
1921
+
1922
+ # One named struct-declarator: a declarator, then either a ": width"
1923
+ # bit-field tail or a plain member. A named bit-field of zero width is a
1924
+ # constraint violation (6.7.2.1p3, "only an unnamed member may be
1925
+ # zero-width"). A plain member may not be a function, void, or an
1926
+ # incomplete aggregate by value.
1927
+ def parse_named_member(member_base, raw_members, seen, flex, alignas = nil)
1928
+ # A trailing "[]" (an incomplete array) is admitted here so the last
1929
+ # member may be a flexible array member; #reject_flexible_array_member
1930
+ # then enforces the 6.7.2.1p18 constraints (struct only, and never
1931
+ # followed by another member — see #reject_member_after_flexible_array).
1932
+ name_tok, type, params = parse_declarator(member_base, allow_incomplete_array: true,
1933
+ allow_zero_length_array: true)
1934
+ # A member is never a function definition, so an identifier list on one
1935
+ # ("struct s { int m(a, b); };") names types that never arrive. The
1936
+ # "declared as a function" refusal below would also catch it, but only
1937
+ # after the declarator had been read as a plain "int m()".
1938
+ reject_identifier_list(params)
1939
+ if peek.punct?(":")
1940
+ advance # ":"
1941
+ reject_alignas(alignas, "bit-field '#{name_tok.value}'")
1942
+ width = parse_bitfield_width(type, name_tok)
1943
+ error_at(name_tok, "named bit-field '#{name_tok.value}' has zero width") if width.zero?
1944
+ register_member_name(name_tok, seen)
1945
+ flex[:others] += 1
1946
+ raw_members << [name_tok.value, type, width]
1947
+ else
1948
+ # A GNU attribute may trail a member declarator (position f):
1949
+ # "int m __attribute__((packed));". Accepted and discarded — a
1950
+ # member-level packed/aligned has no effect on this subset's layout
1951
+ # (only a whole-struct attribute steers #layout_struct, and only an
1952
+ # _Alignas raises a single member's boundary).
1953
+ parse_attribute_specifiers
1954
+ error_at(name_tok, "field '#{name_tok.value}' declared as a function") if type.function?
1955
+ reject_void_type(type, name_tok)
1956
+ reject_incomplete_member(type, name_tok)
1957
+ register_member_name(name_tok, seen)
1958
+ if type.array? && type.incomplete?
1959
+ reject_flexible_array_member(type, name_tok, flex)
1960
+ flex[:token] = name_tok
1961
+ else
1962
+ flex[:others] += 1
1963
+ end
1964
+ raw_members << [name_tok.value, type, nil,
1965
+ alignas_boundary(alignas, type, "'#{name_tok.value}'")]
1966
+ end
1967
+ end
1968
+
1969
+ # Rejects a member declared after a flexible array member: a FAM must be
1970
+ # the struct's last member (6.7.2.1p18), so anything that follows it — a
1971
+ # further declarator in the same list ("int f[], g;"), a later declaration,
1972
+ # or an anonymous member — is a constraint violation reported at the FAM's
1973
+ # own name. Does nothing until a FAM has actually been seen.
1974
+ def reject_member_after_flexible_array(flex, _anchor)
1975
+ return unless flex[:token]
1976
+
1977
+ error_at(flex[:token],
1978
+ "flexible array member '#{flex[:token].value}' must be the last member of the struct")
1979
+ end
1980
+
1981
+ # Enforces the two constraints a flexible array member must satisfy at the
1982
+ # point it is declared (6.7.2.1p18): it is legal only in a struct, never a
1983
+ # union, and only when the element type is complete — an "[]" of an
1984
+ # incomplete struct has no element size to index. The "must be last" and
1985
+ # "needs another member" rules are enforced by the surrounding body parse,
1986
+ # which alone sees the whole member sequence.
1987
+ def reject_flexible_array_member(type, name_tok, flex)
1988
+ if flex[:kind] == :union
1989
+ error_at(name_tok, "flexible array member '#{name_tok.value}' not allowed in union")
1990
+ end
1991
+ if type.element.struct? && !type.element.complete?
1992
+ error_at(name_tok, "flexible array member '#{name_tok.value}' has incomplete element type")
1993
+ end
1994
+ end
1995
+
1996
+ # Records a member name in `seen`, diagnosing a collision with a name
1997
+ # already visible in this body (a directly declared member or one an
1998
+ # anonymous member exposes transparently).
1999
+ def register_member_name(name_tok, seen)
2000
+ error_at(name_tok, "duplicate member '#{name_tok.value}'") if seen.key?(name_tok.value)
2001
+ seen[name_tok.value] = true
2002
+ end
2003
+
2004
+ # Parses and validates a bit-field's ": constant-expression" width, the ":"
2005
+ # already consumed. `type` is the field's declared type and `anchor` the
2006
+ # token a diagnostic points at. The type must be an integer type, and the
2007
+ # width a non-negative integer constant no wider than that type (6.7.2.1p4).
2008
+ def parse_bitfield_width(type, anchor)
2009
+ unless type.integer?
2010
+ error_at(anchor, "bit-field has non-integral type '#{type}'")
2011
+ end
2012
+ expr = parse_conditional_expression
2013
+ width = evaluate_constant_expression(expr, "bit-field width is not an integer constant",
2014
+ sizeof_expr: method(:fold_time_sizeof))
2015
+ error_at(expr.token, "negative width in bit-field") if width.negative?
2016
+ error_at(expr.token, "width of bit-field exceeds its type") if width > type.size * 8
2017
+ width
2018
+ end
2019
+
2020
+ # Every member name an anonymous member exposes to its enclosing
2021
+ # aggregate: its own named members, plus (recursively) the names its own
2022
+ # anonymous members expose. `struct_type` is already laid out here, so its
2023
+ # members are known.
2024
+ def transparent_member_names(struct_type)
2025
+ struct_type.members.flat_map do |m|
2026
+ if m.name.nil? && m.type.struct?
2027
+ transparent_member_names(m.type)
2028
+ else
2029
+ [m.name]
2030
+ end
2031
+ end
2032
+ end
2033
+
2034
+ # Rejects a struct member declared with an incomplete struct type by
2035
+ # value (a whole "struct node" inside "struct node", or before the tag is
2036
+ # defined): its size is unknown, so the layout could not place the fields
2037
+ # after it. An array of such a type is rejected for the same reason; a
2038
+ # pointer to it is allowed.
2039
+ def reject_incomplete_member(type, token)
2040
+ incomplete = (type.struct? && !type.complete?) ||
2041
+ (type.array? && type.element.struct? && !type.element.complete?)
2042
+ error_at(token, "field '#{token.value}' has incomplete type") if incomplete
2043
+ end
2044
+
2045
+ # Whether `token` opens a declaration, letting block-item and for-init tell
2046
+ # a declaration from a statement, and the cast/sizeof parsers tell a
2047
+ # type-name from a parenthesized expression. A declaration begins with an
2048
+ # integer/void type-specifier keyword, "struct"/"union"/"enum", a storage
2049
+ # class ("typedef"/"static"/"extern"/"register"/"auto"), a type qualifier
2050
+ # ("const"/"volatile"/"_Atomic"), the "inline"/"_Noreturn" function
2051
+ # specifiers, or a typedef name
2052
+ # — an identifier bound to a type in the ordinary namespace
2053
+ # whose innermost binding is not shadowed by a variable. The storage-class
2054
+ # and function-specifier keywords never open an expression, so admitting
2055
+ # them here only ever forwards a genuine declaration (a bare "static x;"
2056
+ # then fails in the specifier parse, where it belongs).
2057
+ def type_specifier?(token)
2058
+ if token.type == :keyword
2059
+ return DECL_SPECIFIER_KEYWORDS.include?(token.value) ||
2060
+ STORAGE_CLASS_KEYWORDS.include?(token.value) ||
2061
+ token.value == "struct" || token.value == "union" ||
2062
+ token.value == "enum" ||
2063
+ token.value == "const" || token.value == "volatile" ||
2064
+ token.value == "_Atomic" ||
2065
+ # An alignment-specifier opens a declaration too ("_Alignas(16)
2066
+ # char buf[64];"), and never an expression, so block-item and
2067
+ # for-init must not read one as a statement.
2068
+ token.value == "_Alignas" ||
2069
+ token.value == "inline" || token.value == "_Noreturn" ||
2070
+ # A leading GNU attribute opens a declaration too
2071
+ # ("__attribute__((unused)) int x;"), so block-item and
2072
+ # for-init recognize it as one rather than a statement.
2073
+ token.value == "__attribute__"
2074
+ end
2075
+ token.type == :ident && typedef_name?(token.value)
2076
+ end
2077
+
2078
+ # Rejects `type` when it denotes a bare void or an array of void: this
2079
+ # subset only allows "void" as a function's return type or as the target
2080
+ # of a pointer ("void *", "void **", ...), so a void variable, global,
2081
+ # array element or (non-pointer) parameter is an error.
2082
+ def reject_void_type(type, token)
2083
+ return unless type.void? || (type.array? && type.element.void?)
2084
+
2085
+ error_at(token, "variable or field declared void")
2086
+ end
2087
+
2088
+ def parse_function_definition(name, return_type, params, return_tok, storage, variadic)
2089
+ # A definition, unlike a prototype, must name each parameter so its
2090
+ # value can be bound in the body.
2091
+ params.each do |param|
2092
+ error_at(param.token, "parameter name omitted") if param.name.nil?
2093
+ end
2094
+ expect_punct("{")
2095
+ # The body is a block, so it owns a tag scope and an ordinary scope: a
2096
+ # struct or typedef defined in one function's body is invisible to the
2097
+ # next. The parameters live in this body scope as ordinary names, so a
2098
+ # parameter shadows an outer typedef of the same name inside the body.
2099
+ @tag_scopes.push({})
2100
+ @ordinary_scopes.push({})
2101
+ params.each { |param| declare_ordinary_name(param.name, param.type) }
2102
+ body = []
2103
+ body.concat(parse_block_item) until peek.punct?("}")
2104
+ @ordinary_scopes.pop
2105
+ @tag_scopes.pop
2106
+ expect_punct("}")
2107
+ AST::FunctionDef.new(name, return_type, params, body, return_tok, storage, variadic)
2108
+ end
2109
+
2110
+ # Returns [params, variadic]: an array of AST::Parameter (empty for "()" or
2111
+ # "(void)") and whether the list ends in a "..." variable-argument marker
2112
+ # (6.7.6.3). A bare "void" only means "no parameters" when it is the entire
2113
+ # list (followed immediately by ")"); "void *" or a later "void" parameter
2114
+ # falls through to parse_parameter_declaration, which rejects a non-pointer
2115
+ # void. A "..." is admitted only after at least one named parameter and a
2116
+ # comma ("int a, ..."): a lone "(...)" has no fixed parameter to anchor a
2117
+ # va_start on, and nothing may follow the "...".
2118
+ def parse_parameter_type_list
2119
+ return [[], false] if peek.punct?(")")
2120
+ if peek.keyword?("void") && peek_ahead(1)&.punct?(")")
2121
+ advance
2122
+ return [[], false]
2123
+ end
2124
+ if peek.punct?("...")
2125
+ error_at(peek, "ISO C requires a named parameter before '...'")
2126
+ end
2127
+
2128
+ params = [parse_parameter_declaration]
2129
+ variadic = false
2130
+ while peek.punct?(",")
2131
+ advance
2132
+ if peek.punct?("...")
2133
+ advance
2134
+ variadic = true
2135
+ # "..." terminates the list; a parameter or stray token after it
2136
+ # ("int a, ..., int b") is rejected here rather than left for the
2137
+ # caller's ")" expectation to surface as a vaguer error.
2138
+ error_at(peek, "'...' must be the last parameter") unless peek.punct?(")")
2139
+ break
2140
+ end
2141
+ params << parse_parameter_declaration
2142
+ end
2143
+ [params, variadic]
2144
+ end
2145
+
2146
+ # parameter-declaration = type-specifier declarator?, the declarator being
2147
+ # a full (possibly abstract) one whose name is optional (:optional mode)
2148
+ # so prototypes may omit it. The parsed type is then adjusted per 6.7.6.3
2149
+ # (an array becomes a pointer to its element, a function a pointer to
2150
+ # itself), so "int a[10]" is "int *a" and "int g(int)" is "int (*g)(int)".
2151
+ # An unnamed parameter is located by its type-specifier keyword for
2152
+ # diagnostics.
2153
+ def parse_parameter_declaration
2154
+ type_tok = peek
2155
+ # A parameter's specifiers admit const/volatile but not a storage class
2156
+ # or inline (allow_storage_class: false) — except `register`, the one
2157
+ # storage class 6.7.6.3p2 permits on a parameter, which is consumed and
2158
+ # ignored. Only its const survives.
2159
+ base_type, spec_info = parse_declaration_specifiers(allow_storage_class: false, allow_register: true)
2160
+ # A parameter's array declarator adjusts to a pointer (6.7.6.3p7), so an
2161
+ # empty "[]" is admitted here just as it is for an external declaration's
2162
+ # incomplete array; #adjust_parameter_type resolves it below.
2163
+ name_tok, type, params, pointer_quals =
2164
+ parse_declarator(base_type, name_mode: :optional, allow_incomplete_array: true)
2165
+ # A parameter that is itself a function declarator ("int f(int g(a, b))")
2166
+ # is a declaration, not the definition of g, so its identifier list has
2167
+ # no types to come.
2168
+ reject_identifier_list(params)
2169
+ # A parameter's boundary is the calling convention's to choose, not the
2170
+ # declaration's, so 6.7.5p2 forbids an _Alignas on one.
2171
+ reject_alignas(spec_info.alignas,
2172
+ name_tok ? "parameter '#{name_tok.value}'" : "parameter")
2173
+ # A GNU attribute may trail a parameter declarator (position e):
2174
+ # "int f(int x __attribute__((unused)))". Accepted and discarded; the
2175
+ # specifier-position form is already handled in the specifier parse.
2176
+ parse_attribute_specifiers
2177
+ type = adjust_parameter_type(type)
2178
+ # The const-ness is settled on the adjusted type, so "const int a[10]"
2179
+ # (a pointer to const int after adjustment) yields a non-const parameter,
2180
+ # while "int * const a" stays a const pointer parameter.
2181
+ const = declarator_object_const(type, spec_info.const, pointer_quals)
2182
+ reject_void_type(type, name_tok || type_tok)
2183
+ if name_tok
2184
+ AST::Parameter.new(name_tok.value, type, name_tok, const)
2185
+ else
2186
+ AST::Parameter.new(nil, type, type_tok, const)
2187
+ end
2188
+ end
2189
+
2190
+ # Returns an array of nodes: a declaration expands to one VariableDecl
2191
+ # per init-declarator, while a statement always yields exactly one node.
2192
+ def parse_block_item
2193
+ # A block-scope "_Static_assert(expr, "msg");" is a declaration that
2194
+ # binds nothing; it is checked and flattened away like a bare tag decl.
2195
+ return parse_static_assert if peek.keyword?("_Static_assert")
2196
+
2197
+ # A "__extension__" prefixing a declaration ("__extension__ int x;") is
2198
+ # discarded here; a "__extension__" prefixing an expression statement is
2199
+ # left for #parse_cast_expression, which binds it like a cast prefix.
2200
+ if extension_prefixes_declaration?
2201
+ skip_extension_markers
2202
+ return parse_static_assert if peek.keyword?("_Static_assert")
2203
+
2204
+ return parse_declaration
2205
+ end
2206
+
2207
+ if type_specifier?(peek)
2208
+ parse_declaration
2209
+ else
2210
+ [parse_statement]
2211
+ end
2212
+ end
2213
+
2214
+ def parse_declaration
2215
+ base_type, spec_info = parse_declaration_specifiers(allow_storage_class: true)
2216
+
2217
+ # A bare "struct point { ... };" (or "struct node;", or a tag-only "enum
2218
+ # E { ... };") inside a block just declares or defines the tag, adding no
2219
+ # local; it yields no items.
2220
+ if peek.punct?(";")
2221
+ advance
2222
+ return []
2223
+ end
2224
+
2225
+ # A local typedef binds names as types in this block's scope; like a
2226
+ # file-scope typedef it yields no items.
2227
+ return parse_typedef_declaration(base_type, spec_info) if spec_info.storage == :typedef
2228
+
2229
+ decls = [parse_init_declarator(base_type, spec_info)]
2230
+ while peek.punct?(",")
2231
+ advance
2232
+ decls << parse_init_declarator(base_type, spec_info)
2233
+ end
2234
+ expect_punct(";")
2235
+ decls
2236
+ end
2237
+
2238
+ # A typedef declaration: a run of comma-separated declarators sharing
2239
+ # `base_type`, each binding its name as a type (its "*" run and array
2240
+ # suffix applied) in the current ordinary scope. A typedef declarator may
2241
+ # not have an initializer (6.7.1); the declaration itself contributes no
2242
+ # AST node, so this returns an empty run.
2243
+ def parse_typedef_declaration(base_type, spec_info)
2244
+ loop do
2245
+ name_tok, type, params, pointer_quals = parse_declarator(base_type)
2246
+ # A typedef names a type, never a function this unit defines, so an
2247
+ # identifier list ("typedef int F(a, b);") could not be a definition.
2248
+ reject_identifier_list(params)
2249
+ parse_attribute_specifiers # position d: a trailing attribute on the typedef name
2250
+ # A typedef declares a type, not an object, so there is nothing for an
2251
+ # _Alignas to align (6.7.5p2).
2252
+ reject_alignas(spec_info.alignas, "typedef '#{name_tok.value}'")
2253
+ if peek.punct?("=")
2254
+ error_at(peek, "typedef '#{name_tok.value}' must not be initialized")
2255
+ end
2256
+ # A typedef of a const-qualified object type remembers that const so a
2257
+ # later use ("typedef const int ci; ci x;") makes x const; the same
2258
+ # top-level rule applies, so "typedef const int *cp;" (a pointer to
2259
+ # const) is not itself const.
2260
+ const = declarator_object_const(type, spec_info.const, pointer_quals)
2261
+ declare_typedef_name(name_tok, type, const)
2262
+ break unless peek.punct?(",")
2263
+
2264
+ advance # ","
2265
+ end
2266
+ expect_punct(";")
2267
+ []
2268
+ end
2269
+
2270
+ def parse_init_declarator(base_type, spec_info)
2271
+ name_tok, type, params, pointer_quals = parse_declarator(base_type, allow_incomplete_array: true)
2272
+ # A block-scope declarator declares; a definition never nests (see the
2273
+ # nested-function refusal below), so an identifier list here supplies no
2274
+ # types either.
2275
+ reject_identifier_list(params)
2276
+ parse_attribute_specifiers # position d: a trailing attribute on this local declarator
2277
+ reject_void_type(type, name_tok)
2278
+ # A body here would be a *nested function definition* — a GNU extension,
2279
+ # not the block-scope function *declaration* 6.2.2p5 blesses (which ends
2280
+ # at the ";" and only names an external function). It needs a trampoline
2281
+ # to capture the enclosing frame, is out of scope for this compiler, and
2282
+ # would otherwise surface as a bare "expected ';'" that says nothing about
2283
+ # why. "inline"/"_Noreturn" ride on a function declarator legitimately
2284
+ # (6.7.4), so the object-only specifier check is skipped for one.
2285
+ if type.function?
2286
+ if peek.punct?("{")
2287
+ error_at(name_tok, "nested function definitions are not supported")
2288
+ end
2289
+ # A function reserves no object to align (6.7.5p2).
2290
+ reject_alignas(spec_info.alignas, "function '#{name_tok.value}'")
2291
+ else
2292
+ reject_object_specifiers(name_tok, spec_info)
2293
+ end
2294
+ const = declarator_object_const(type, spec_info.const, pointer_quals)
2295
+ initializer = nil
2296
+ if peek.punct?("=")
2297
+ if spec_info.storage == :extern
2298
+ error_at(name_tok, "'#{name_tok.value}' has both 'extern' and initializer")
2299
+ end
2300
+ advance # "="
2301
+ initializer = parse_initializer
2302
+ # A structural initializer (a brace list, or a string for a char array)
2303
+ # fixes the object's type — completing an inferred "[]" bound — and is
2304
+ # validated for shape here, so a later stage sees a finished type.
2305
+ if InitializerResolver.structural?(type, initializer)
2306
+ type = InitializerResolver.resolve(type, initializer,
2307
+ static_storage: spec_info.storage == :static).type
2308
+ end
2309
+ elsif type.array? && type.length.nil? && spec_info.storage != :extern
2310
+ # A block-scope `extern T a[];` references a file-scope array defined
2311
+ # elsewhere, an incomplete type that unit completes (6.7.6.2p1, 6.9.2),
2312
+ # so it is kept as-is. A non-extern `int a[];` in a block has no
2313
+ # initializer to complete it and no tentative-definition rule at block
2314
+ # scope, so it stays a diagnostic (gcc rejects it likewise).
2315
+ error_at(name_tok, "array size missing in '#{name_tok.value}'")
2316
+ end
2317
+ declare_ordinary_name(name_tok.value, type)
2318
+ # The boundary is settled against the *finished* type, so an inferred
2319
+ # "[]" bound is already in place when the "cannot reduce" check runs.
2320
+ AST::VariableDecl.new(name_tok.value, type, initializer, name_tok, const, spec_info.storage,
2321
+ alignas_boundary(spec_info.alignas, type, "'#{name_tok.value}'"))
2322
+ end
2323
+
2324
+ # Rejects the declaration specifiers that may sit on a function but not on
2325
+ # an object: "inline" or "_Noreturn" on a variable or global is ill-formed
2326
+ # (both are function specifiers, 6.7.4). Storage classes are already
2327
+ # admitted here (recorded for Phase B), so only these two are caught.
2328
+ # Shared by the local and file-scope object declarators.
2329
+ def reject_object_specifiers(name_tok, spec_info)
2330
+ error_at(name_tok, "variable '#{name_tok.value}' declared 'inline'") if spec_info.inline_p
2331
+ return unless spec_info.noreturn_p
2332
+
2333
+ error_at(name_tok, "variable '#{name_tok.value}' declared '_Noreturn'")
2334
+ end
2335
+
2336
+ # Whether the object a declarator declares is top-level const-qualified,
2337
+ # the only qualification M1 tracks. With no pointer/array/function
2338
+ # derivation the specifier's const applies directly ("const int x"); an
2339
+ # array likewise takes the specifier const (M1 treats the whole array
2340
+ # variable as const rather than only its elements, a deliberate
2341
+ # simplification); a pointer is const only when its outermost level bears
2342
+ # the qualifier ("int * const p" is const, "const int *p" is not); a
2343
+ # function type is never a const object. `pointer_quals` is the declarator's
2344
+ # leading "*" run, one const flag per level, so its last entry is the
2345
+ # outermost pointer — empty (a pointer built inside parentheses) reads as
2346
+ # not const, a tolerated M1 gap for "int (* const p)[3]".
2347
+ def declarator_object_const(type, specifier_const, pointer_quals)
2348
+ return pointer_quals.last || false if type.pointer?
2349
+ return false if type.function?
2350
+
2351
+ specifier_const
2352
+ end
2353
+
2354
+ # A file- or block-scope "_Static_assert ( constant-expression ,
2355
+ # string-literal ) ;" (6.7.10). The expression is folded like any other
2356
+ # constant-expression, with the same parse-time "sizeof <expression>"
2357
+ # resolution an array bound gets (#fold_time_sizeof) — asserting a size
2358
+ # relation over an expression is the idiom's main use (ruby.h's
2359
+ # RBIMPL_STATIC_ASSERT(…, sizeof *ptr == sizeof(size_t))). A zero value
2360
+ # fails the assertion, quoting the message the way gcc does. It declares
2361
+ # nothing, so — like a bare tag declaration or a typedef — it returns an
2362
+ # empty run of declarations.
2363
+ def parse_static_assert
2364
+ keyword_tok = advance # "_Static_assert"
2365
+ expect_punct("(")
2366
+ expr = parse_conditional_expression
2367
+ value = evaluate_constant_expression(expr, "static assertion expression is not an integer constant",
2368
+ sizeof_expr: method(:fold_time_sizeof))
2369
+ expect_punct(",")
2370
+ message_tok = peek
2371
+ error_at(message_tok, "expected string literal in '_Static_assert'") unless message_tok.type == :string
2372
+ advance
2373
+ expect_punct(")")
2374
+ expect_punct(";")
2375
+ error_at(keyword_tok, "static assertion failed: \"#{message_tok.value}\"") if value.zero?
2376
+ []
2377
+ end
2378
+
2379
+ # initializer = assignment-expression | "{" initializer-list ","? "}"
2380
+ # (6.7.9). A "{" opens a brace list; anything else is a single assignment
2381
+ # expression (a scalar's value, or a whole string literal for a char
2382
+ # array). The resolver later matches the shape against the object's type.
2383
+ def parse_initializer
2384
+ return parse_initializer_list if peek.punct?("{")
2385
+
2386
+ parse_assignment_expression
2387
+ end
2388
+
2389
+ # initializer-list = designation? initializer ("," designation? initializer)*
2390
+ # with an optional trailing comma before "}". Each element becomes an
2391
+ # InitItem pairing its (possibly empty) designator chain with its value,
2392
+ # which may itself be a nested brace list.
2393
+ def parse_initializer_list
2394
+ brace_tok = expect_punct("{")
2395
+ with_nesting_guard(brace_tok, "initializer") do
2396
+ items = []
2397
+ until peek.punct?("}")
2398
+ designators = parse_designation
2399
+ value = parse_initializer
2400
+ items << AST::InitItem.new(designators, value)
2401
+ break unless peek.punct?(",")
2402
+
2403
+ advance # ","
2404
+ end
2405
+ expect_punct("}")
2406
+ AST::InitializerList.new(items, brace_tok)
2407
+ end
2408
+ end
2409
+
2410
+ # designation = designator+ "=", where designator is "[" constant-expression
2411
+ # "]" or "." identifier (6.7.9). Returns the designator chain, or an empty
2412
+ # array when the next element is positional (no leading "[" or "."). An
2413
+ # array designator's index is folded to a Ruby Integer on the spot, like an
2414
+ # array bound.
2415
+ def parse_designation
2416
+ return [] unless peek.punct?("[") || peek.punct?(".")
2417
+
2418
+ designators = []
2419
+ loop do
2420
+ if peek.punct?("[")
2421
+ bracket_tok = advance # "["
2422
+ expr = parse_conditional_expression
2423
+ index = evaluate_constant_expression(expr, "array designator is not an integer constant",
2424
+ sizeof_expr: method(:fold_time_sizeof))
2425
+ expect_punct("]")
2426
+ designators << AST::ArrayDesignator.new(index, bracket_tok)
2427
+ elsif peek.punct?(".")
2428
+ dot_tok = advance # "."
2429
+ name_tok = expect_ident
2430
+ designators << AST::MemberDesignator.new(name_tok.value, dot_tok)
2431
+ else
2432
+ break
2433
+ end
2434
+ end
2435
+ expect_punct("=")
2436
+ designators
2437
+ end
2438
+
2439
+ # Parses a full declarator (6.7.6) and applies it to `base`, returning
2440
+ # [name_token_or_nil, type, function_params]. The declarator is read
2441
+ # syntactically and turned into a proc that wraps `base` inside-out (see
2442
+ # #parse_declarator_builder); `type` is that proc applied to `base`, and
2443
+ # `function_params` is the parameter list of the function suffix attached
2444
+ # directly to the declared name when the result is a function type (a
2445
+ # function definition or prototype needs those Parameter objects), nil
2446
+ # otherwise.
2447
+ #
2448
+ # `name_mode` governs the identifier: :required in an ordinary declaration
2449
+ # (a missing name is an error), :optional in a parameter (the name may be
2450
+ # omitted), or :forbidden in a type-name (a cast or sizeof, which never
2451
+ # names anything). `allow_incomplete_array` admits a trailing "[]" whose
2452
+ # length an initializer will infer. `allow_zero_length_array` is threaded
2453
+ # only for struct members, where the GNU `[0]` extension is valid.
2454
+ # Returns [name_token_or_nil, type, function_params, pointer_quals], the
2455
+ # last being the declarator's leading "*" run as a list of per-level const
2456
+ # flags (see #parse_pointer_qualifiers) so an object declarator can settle
2457
+ # its top-level const-ness (see #declarator_object_const). Callers that do
2458
+ # not need the qualifiers simply ignore the trailing value.
2459
+ def parse_declarator(base, name_mode: :required, allow_incomplete_array: false,
2460
+ allow_zero_length_array: false)
2461
+ name_tok, build, function_params, pointer_quals =
2462
+ parse_declarator_builder(name_mode: name_mode,
2463
+ allow_incomplete_array: allow_incomplete_array,
2464
+ allow_zero_length_array: allow_zero_length_array)
2465
+ [name_tok, build.call(base), function_params, pointer_quals]
2466
+ end
2467
+
2468
+ # declarator = pointer? direct-declarator. Parses the leading "*" run and
2469
+ # the direct-declarator, returning [name_token, build, function_params]
2470
+ # where `build` maps a base type to the declared type. The pointer prefix
2471
+ # is the outermost derivation textually but binds looser than the postfix
2472
+ # "()"/"[]", so it wraps the *base* first (becoming the innermost target,
2473
+ # e.g. the return or element type) and the direct-declarator's suffixes
2474
+ # then wrap that — which is exactly why "int *f(int)" is a function
2475
+ # returning "int *" while "int (*f)(int)" is a pointer to a function.
2476
+ def parse_declarator_builder(name_mode:, allow_incomplete_array:, allow_zero_length_array:)
2477
+ # A parenthesized declarator recurses back here through
2478
+ # #parse_declarator_core, so guarding this entry bounds "int
2479
+ # ((((x))))"-style nesting (and the matching build-lambda recursion,
2480
+ # which can only run as deep as the syntactic nesting that survived).
2481
+ with_nesting_guard(peek, "declarator") do
2482
+ # A GNU attribute may open a declarator ("int (__attribute__((packed))
2483
+ # *p)"), including the nested declarator inside a "(...)"; it qualifies
2484
+ # nothing this subset models, so it is accepted and discarded here just
2485
+ # as at every other declarator position.
2486
+ parse_attribute_specifiers
2487
+ pointer_quals = parse_pointer_qualifiers
2488
+ name_tok, direct_build, function_params =
2489
+ parse_direct_declarator(name_mode: name_mode,
2490
+ allow_incomplete_array: allow_incomplete_array,
2491
+ allow_zero_length_array: allow_zero_length_array)
2492
+ build = lambda do |base|
2493
+ type = base
2494
+ pointer_quals.each { type = Type::Pointer.new(type) }
2495
+ direct_build.call(type)
2496
+ end
2497
+ [name_tok, build, function_params, pointer_quals]
2498
+ end
2499
+ end
2500
+
2501
+ # A declarator's "*" run, each star optionally followed by a type-qualifier
2502
+ # list ("int * const p", "char * const * volatile q"). Returns one boolean
2503
+ # per star, true when that pointer level is const-qualified; "volatile" and
2504
+ # "_Atomic" are accepted and ignored, since M1 carries no qualified types.
2505
+ # The list is in
2506
+ # textual order, so the first star wraps the base first (the innermost
2507
+ # pointer) and the last is the outermost — the level that qualifies the
2508
+ # declared object.
2509
+ def parse_pointer_qualifiers
2510
+ quals = []
2511
+ while consume_punct("*")
2512
+ const_here = false
2513
+ loop do
2514
+ if peek.keyword?("const")
2515
+ const_here = true
2516
+ advance
2517
+ elsif peek.keyword?("volatile")
2518
+ advance
2519
+ elsif peek.keyword?("_Atomic")
2520
+ # "_Atomic" on this pointer level ("int * _Atomic p"): it qualifies
2521
+ # the pointer itself, which is one of the widths
2522
+ # ATOMIC_TYPE_WIDTHS admits whatever it points at, so there is
2523
+ # nothing to refuse and it is dropped like "volatile".
2524
+ advance
2525
+ elsif peek.keyword?("__attribute__")
2526
+ # A GNU attribute may follow a pointer's "*" ("int * __attribute__
2527
+ # ((x)) p", "int (ATTR *)(void)"); it qualifies nothing modeled
2528
+ # here, so it is accepted and discarded like the other qualifiers.
2529
+ parse_attribute_specifiers
2530
+ elsif restrict_qualifier?(peek)
2531
+ # A "restrict" (or "__restrict"/"__restrict__") qualifier on this
2532
+ # pointer level: carries no semantics in this subset, so consumed
2533
+ # and dropped, exactly as "volatile" is.
2534
+ advance
2535
+ else
2536
+ break
2537
+ end
2538
+ end
2539
+ quals << const_here
2540
+ end
2541
+ quals
2542
+ end
2543
+
2544
+ # Whether `tok` is one of the recognized "restrict" spellings — an ordinary
2545
+ # identifier, since none is a keyword here (see RESTRICT_SPELLINGS).
2546
+ def restrict_qualifier?(tok)
2547
+ tok.type == :ident && RESTRICT_SPELLINGS.include?(tok.value)
2548
+ end
2549
+
2550
+ # direct-declarator = (identifier | "(" declarator ")") suffix*, where a
2551
+ # suffix is a "[" size? "]" array or a "(" parameter-type-list? ")"
2552
+ # function. Returns [name_token, build, function_params].
2553
+ #
2554
+ # The core is a parenthesized declarator when a "(" is followed by a token
2555
+ # that opens a declarator (see #paren_starts_declarator?), an identifier
2556
+ # when one is present and the mode admits a name, or empty (an abstract
2557
+ # declarator's or an unnamed parameter's missing name). The suffixes bind
2558
+ # tighter than the pointer prefix and than an enclosing paren's suffix, so
2559
+ # `build` applies them to the base before the core — and, since a later
2560
+ # suffix binds tighter than an earlier one ("a[2][3]"), in reverse textual
2561
+ # order.
2562
+ #
2563
+ # `function_params` reports the parameter list of the function suffix
2564
+ # attached directly to the name: it is this level's first suffix when the
2565
+ # core is the identifier (or is absent), but the *inner* declarator's when
2566
+ # the core is parenthesized, so a name buried inside parentheses still
2567
+ # surfaces the suffix that makes it a function ("int (*g(int a))(int b)"
2568
+ # reports "int a", g's own parameters, not "int b").
2569
+ def parse_direct_declarator(name_mode:, allow_incomplete_array:, allow_zero_length_array:)
2570
+ name_tok, core_build, inner_params =
2571
+ parse_declarator_core(name_mode: name_mode,
2572
+ allow_incomplete_array: allow_incomplete_array,
2573
+ allow_zero_length_array: allow_zero_length_array)
2574
+
2575
+ suffixes = []
2576
+ loop do
2577
+ if peek.punct?("[")
2578
+ suffixes << parse_array_suffix(allow_incomplete: allow_incomplete_array,
2579
+ allow_zero_length: allow_zero_length_array)
2580
+ elsif peek.punct?("(")
2581
+ suffixes << parse_function_suffix
2582
+ else
2583
+ break
2584
+ end
2585
+ end
2586
+
2587
+ build = lambda do |base|
2588
+ type = base
2589
+ suffixes.reverse_each { |suffix| type = apply_declarator_suffix(suffix, type) }
2590
+ core_build.call(type)
2591
+ end
2592
+
2593
+ # A parenthesized core forwards the buried name's own function suffix;
2594
+ # every other core takes this level's outermost (first textual) suffix.
2595
+ function_params =
2596
+ if inner_params != :none
2597
+ inner_params
2598
+ elsif suffixes.first&.first == :function
2599
+ suffixes.first[1]
2600
+ end
2601
+ reject_unsurfaced_identifier_lists(suffixes, function_params)
2602
+ [name_tok, build, function_params]
2603
+ end
2604
+
2605
+ # Refuses an identifier list written on a suffix that is not the one making
2606
+ # the declared name a function — "int (*g)(a, b);", where the list sits on
2607
+ # the pointer's own suffix, or a second suffix on the same declarator. Only
2608
+ # the surfaced suffix can ever be a definition's parameter list, and only
2609
+ # that one reaches #reject_identifier_list through `function_params`; the
2610
+ # rest would otherwise be quietly read as an empty parameter list, since
2611
+ # that is the placeholder type #apply_declarator_suffix builds for them.
2612
+ def reject_unsurfaced_identifier_lists(suffixes, function_params)
2613
+ suffixes.each do |suffix|
2614
+ next unless suffix[1].is_a?(IdentifierList)
2615
+ next if suffix[1].equal?(function_params)
2616
+
2617
+ reject_identifier_list(suffix[1])
2618
+ end
2619
+ end
2620
+
2621
+ # The core of a direct-declarator, returning [name_token, build,
2622
+ # inner_params]. `inner_params` is the parenthesized inner declarator's
2623
+ # function_params when the core is "( declarator )", or the sentinel :none
2624
+ # when the core is an identifier or empty (so #parse_direct_declarator
2625
+ # knows whether to forward a buried name's suffix or read its own).
2626
+ #
2627
+ # `allow_incomplete_array` is forwarded into a parenthesized inner
2628
+ # declarator: the parentheses are only grouping, so the array buried in
2629
+ # "int (*fp[])(void) = { ... }" is the object's own array and its "[]" is
2630
+ # deducible from the initializer exactly as a bare "int fp[] = { ... }"
2631
+ # would be. Dropping the flag here rejected such declarators (6.7.6.3).
2632
+ def parse_declarator_core(name_mode:, allow_incomplete_array:, allow_zero_length_array:)
2633
+ if peek.punct?("(") && paren_starts_declarator?
2634
+ advance # "("
2635
+ name_tok, build, inner_params =
2636
+ parse_declarator_builder(name_mode: name_mode,
2637
+ allow_incomplete_array: allow_incomplete_array,
2638
+ allow_zero_length_array: allow_zero_length_array)
2639
+ expect_punct(")")
2640
+ [name_tok, build, inner_params]
2641
+ elsif peek.type == :ident && name_mode != :forbidden
2642
+ name_tok = advance
2643
+ [name_tok, ->(base) { base }, :none]
2644
+ elsif name_mode == :required
2645
+ error_at(peek, "expected identifier")
2646
+ else
2647
+ # An abstract declarator or an unnamed parameter: no core, so the type
2648
+ # is whatever the suffixes and pointer prefix make of the base.
2649
+ [nil, ->(base) { base }, :none]
2650
+ end
2651
+ end
2652
+
2653
+ # Whether a "(" at the core position opens a parenthesized declarator
2654
+ # rather than a function suffix's parameter list. It does exactly when the
2655
+ # following token begins a declarator — a "*", a "[", a nested "(", or an
2656
+ # identifier that is not a typedef name (a declared or redundantly
2657
+ # parenthesized name) — which is what disambiguates "int (*f)(int)" (a
2658
+ # parenthesized "*f") from the abstract "int (int)" (a function taking an
2659
+ # int). A type-specifier, a typedef name or a ")" after the "(" instead
2660
+ # opens a parameter list.
2661
+ def paren_starts_declarator?
2662
+ # A GNU attribute may sit right after the "(" and before the inner
2663
+ # declarator ("int (__attribute__((packed)) *p)(void)"); look past it so
2664
+ # the token that actually decides — a "*", "[", "(" or a plain
2665
+ # identifier — is the one classified. A parameter list whose first
2666
+ # parameter opens with an attribute ("(__attribute__((x)) int a)") still
2667
+ # resolves correctly: past the attribute sits a type-specifier, which is
2668
+ # none of those, so it stays a parameter list.
2669
+ nxt = @tokens[index_after_attributes(@pos + 1)]
2670
+ return false if nxt.nil?
2671
+ return true if nxt.punct?("*") || nxt.punct?("[") || nxt.punct?("(")
2672
+
2673
+ nxt.type == :ident && !typedef_name?(nxt.value)
2674
+ end
2675
+
2676
+ # The token index just past any run of "__attribute__ (( ... ))" specifiers
2677
+ # starting at `index`, matching parentheses so an argument list of any
2678
+ # shape is skipped whole. Used only for lookahead (nothing is consumed):
2679
+ # #paren_starts_declarator? peers past an attribute to the token that
2680
+ # classifies a "(". Returns `index` unchanged when no attribute is present.
2681
+ def index_after_attributes(index)
2682
+ while @tokens[index]&.keyword?("__attribute__")
2683
+ index += 1
2684
+ depth = 0
2685
+ loop do
2686
+ tok = @tokens[index]
2687
+ break if tok.nil? || tok.eof?
2688
+
2689
+ index += 1
2690
+ if tok.punct?("(")
2691
+ depth += 1
2692
+ elsif tok.punct?(")")
2693
+ depth -= 1
2694
+ break if depth.zero?
2695
+ end
2696
+ end
2697
+ end
2698
+ index
2699
+ end
2700
+
2701
+ # A direct-declarator's array suffix "[" size? "]". A bracketed length is
2702
+ # a constant-expression (6.6) folded to a positive Ruby Integer. A zero
2703
+ # bound is accepted only for a struct member as the GNU zero-length-array
2704
+ # extension; it has the same zero-size trailing-member layout as a
2705
+ # flexible array while retaining a complete array type. When
2706
+ # `allow_incomplete` is set (a variable or global with an initializer),
2707
+ # empty brackets "[]" leave the length nil for the initializer resolver to
2708
+ # infer (6.7.9p22); everywhere else "[]" is an error. Returns a suffix
2709
+ # descriptor [:array, length, bracket_token] applied later by
2710
+ # #apply_declarator_suffix.
2711
+ def parse_array_suffix(allow_incomplete:, allow_zero_length:)
2712
+ bracket_tok = advance # "["
2713
+ # A parameter's array declarator may carry type qualifiers and/or
2714
+ # "static" inside the brackets (6.7.6.3p7): they qualify the pointer the
2715
+ # parameter adjusts to, and "static" is an optimization hint. This subset
2716
+ # adjusts a parameter array to an *unqualified* pointer, so these are
2717
+ # parsed and discarded. They are accepted in any array declarator here,
2718
+ # not only a parameter's — a mild over-acceptance of a strict-conformance
2719
+ # error this subset does not otherwise diagnose.
2720
+ skip_array_qualifiers
2721
+ if peek.punct?("]")
2722
+ error_at(bracket_tok, "array size must be an integer constant") unless allow_incomplete
2723
+ advance # "]"
2724
+ length = nil
2725
+ elsif peek.punct?("*") && peek_ahead(1)&.punct?("]")
2726
+ # "[*]" is an unspecified-size (VLA) array bound in a function
2727
+ # prototype (6.7.6.2p4); treated like "[]", an incomplete array the
2728
+ # parameter adjustment turns into a pointer.
2729
+ error_at(bracket_tok, "'[*]' not allowed in this context") unless allow_incomplete
2730
+ advance # "*"
2731
+ advance # "]"
2732
+ length = nil
2733
+ else
2734
+ expr = parse_conditional_expression
2735
+ length = evaluate_constant_expression(expr, "array size must be an integer constant",
2736
+ sizeof_expr: method(:fold_time_sizeof))
2737
+ expect_punct("]")
2738
+ error_at(expr.token, "array size must be positive") if length.negative? ||
2739
+ (length.zero? && !allow_zero_length)
2740
+ end
2741
+ [:array, length, bracket_tok]
2742
+ end
2743
+
2744
+ # Consumes the qualifier/"static" run allowed at the start of a parameter's
2745
+ # array declarator brackets (6.7.6.3p7), in any order ("static const 5",
2746
+ # "const static 5"). All are discarded: this subset neither qualifies the
2747
+ # adjusted pointer nor acts on the "static" size hint. "restrict" appears
2748
+ # here in its identifier spellings (see #restrict_qualifier?).
2749
+ def skip_array_qualifiers
2750
+ loop do
2751
+ if peek.keyword?("const") || peek.keyword?("volatile") ||
2752
+ peek.keyword?("_Atomic") || peek.keyword?("static")
2753
+ advance
2754
+ elsif restrict_qualifier?(peek)
2755
+ advance
2756
+ else
2757
+ break
2758
+ end
2759
+ end
2760
+ end
2761
+
2762
+ # A direct-declarator's function suffix: "(" parameter-type-list? ")", or
2763
+ # the old-style "(" identifier-list ")". The parameters are parsed (and
2764
+ # array/function ones adjusted, see #parse_parameter_declaration) here so
2765
+ # the suffix can both build the function type and, when it belongs to a
2766
+ # real function, hand its Parameter objects back for the body. Returns
2767
+ # [:function, params, paren_token, variadic], `params` being either the
2768
+ # Parameter array of a prototype or an IdentifierList; the variadic flag
2769
+ # carries a trailing "..." forward to #apply_declarator_suffix so it lands
2770
+ # on the FunctionType.
2771
+ def parse_function_suffix
2772
+ paren_tok = advance # "("
2773
+ return [:function, parse_identifier_list(paren_tok), paren_tok, false] if identifier_list_ahead?
2774
+
2775
+ params, variadic = parse_parameter_type_list
2776
+ expect_punct(")")
2777
+ [:function, params, paren_tok, variadic]
2778
+ end
2779
+
2780
+ # Whether the just-opened "(" holds an identifier-list rather than a
2781
+ # parameter-type-list. A parameter declaration always begins with a
2782
+ # type-specifier — a keyword, or an identifier bound as a typedef name — so
2783
+ # a plain identifier at this position can only be a parameter *name*, which
2784
+ # is the old-style form. The empty "()" is neither: it stays the
2785
+ # no-parameter list it has always been here (C calls it an empty identifier
2786
+ # list, so "int f() { }" is an old-style definition of a function with no
2787
+ # parameters, which is the same thing this subset already builds).
2788
+ def identifier_list_ahead?
2789
+ peek.type == :ident && !typedef_name?(peek.value)
2790
+ end
2791
+
2792
+ # identifier-list = identifier ("," identifier)*, closed by the ")".
2793
+ # Repeating a name would leave the definition with two parameters of the
2794
+ # same name and no way to refer to either, so it is refused here rather
2795
+ # than at the binding.
2796
+ def parse_identifier_list(paren_tok)
2797
+ names = []
2798
+ loop do
2799
+ name_tok = peek
2800
+ error_at(name_tok, "expected identifier") unless name_tok.type == :ident
2801
+ if names.any? { |seen| seen.value == name_tok.value }
2802
+ error_at(name_tok, "duplicate parameter name '#{name_tok.value}'")
2803
+ end
2804
+ names << advance
2805
+ break unless peek.punct?(",")
2806
+
2807
+ advance # ","
2808
+ end
2809
+ expect_punct(")")
2810
+ IdentifierList.new(names, paren_tok)
2811
+ end
2812
+
2813
+ # Wraps `inner` in one declarator suffix, enforcing the constraints a
2814
+ # function or array derivation cannot satisfy (6.7.6.3): a function's
2815
+ # return type may be neither a function nor an array, and an array's
2816
+ # element may not be a function. A multidimensional array is an array whose
2817
+ # element is itself an array ("int a[2][13]" is a 2-element array of
2818
+ # "int[13]"); the suffixes are applied innermost-first (see
2819
+ # #parse_direct_declarator's reverse_each), so the inner dimension is a
2820
+ # complete array by the time the outer wraps it. Only that inner element
2821
+ # array may not be incomplete -- "int a[2][]" has element type "int[]" of
2822
+ # unknown stride (6.7.6.2p1) -- while the outermost dimension may still be
2823
+ # "[]" (deduced from an initializer or adjusted away on a parameter). The
2824
+ # suffix's own token (the "(" or "[") locates any diagnostic.
2825
+ def apply_declarator_suffix(suffix, inner)
2826
+ kind, data, tok, variadic = suffix
2827
+ if kind == :function
2828
+ error_at(tok, "function returning a function is not allowed") if inner.function?
2829
+ error_at(tok, "function returning an array is not allowed") if inner.array?
2830
+ # An identifier list carries no types yet — the declaration-list that
2831
+ # follows the declarator supplies them — so the type built here is a
2832
+ # placeholder with no parameters, which
2833
+ # #parse_old_style_function_definition replaces once they are known.
2834
+ # It matches what an empty "()" builds, so a declarator that never
2835
+ # reaches a definition still has a usable (if arity-less) type.
2836
+ params = data.is_a?(IdentifierList) ? [] : data.map(&:type)
2837
+ Type::FunctionType.new(inner, params, variadic)
2838
+ else
2839
+ error_at(tok, "array of functions is not allowed") if inner.function?
2840
+ error_at(tok, "array has incomplete element type") if inner.array? && inner.incomplete?
2841
+ # A struct ending in a flexible array member has no fixed size, so it
2842
+ # cannot be an array element (6.7.2.1p18; its stride is unknown).
2843
+ if inner.struct? && inner.flexible_array_member?
2844
+ error_at(tok, "array type has a struct with a flexible array member as its element")
2845
+ end
2846
+ Type::Array.new(inner, data)
2847
+ end
2848
+ end
2849
+
2850
+ # A parameter's declared type after the adjustments of 6.7.6.3: an array
2851
+ # parameter is adjusted to a pointer to its element ("int a[10]" is
2852
+ # "int *a") and a function parameter to a pointer to that function
2853
+ # ("int g(int)" is "int (*g)(int)"), so a call passes an address in either
2854
+ # case. Every other type is left as written.
2855
+ def adjust_parameter_type(type)
2856
+ if type.array?
2857
+ Type::Pointer.new(type.element)
2858
+ elsif type.function?
2859
+ Type::Pointer.new(type)
2860
+ else
2861
+ type
2862
+ end
2863
+ end
2864
+
2865
+ # Consumes and reports a punctuator when it is next, leaving the stream
2866
+ # untouched otherwise; lets the "*" run read one star at a time.
2867
+ def consume_punct(str)
2868
+ return false unless peek.punct?(str)
2869
+
2870
+ advance
2871
+ true
2872
+ end
2873
+
2874
+ def parse_statement
2875
+ if peek.keyword?("return")
2876
+ parse_return
2877
+ elsif peek.keyword?("if")
2878
+ parse_selection_statement
2879
+ elsif peek.keyword?("switch")
2880
+ parse_switch_statement
2881
+ elsif peek.keyword?("case")
2882
+ parse_case_statement
2883
+ elsif peek.keyword?("default")
2884
+ parse_default_statement
2885
+ elsif peek.keyword?("while")
2886
+ parse_while_statement
2887
+ elsif peek.keyword?("do")
2888
+ parse_do_while_statement
2889
+ elsif peek.keyword?("for")
2890
+ parse_for_statement
2891
+ elsif peek.keyword?("break")
2892
+ parse_break_statement
2893
+ elsif peek.keyword?("continue")
2894
+ parse_continue_statement
2895
+ elsif peek.keyword?("goto")
2896
+ parse_goto_statement
2897
+ elsif peek.keyword?("__asm__")
2898
+ parse_asm_statement
2899
+ elsif peek.punct?("{")
2900
+ parse_compound_statement
2901
+ # A bare identifier immediately followed by ":" opens a labeled
2902
+ # statement (a goto target); this two-token lookahead is what tells it
2903
+ # apart from an expression-statement that merely begins with a name.
2904
+ elsif peek.type == :ident && peek_ahead(1)&.punct?(":")
2905
+ parse_labeled_statement
2906
+ else
2907
+ parse_expression_statement
2908
+ end
2909
+ end
2910
+
2911
+ # A control-flow statement's body, parsed one nesting level deeper. The
2912
+ # body of an unbraced `if`/`while`/`do`/`for`/label recurses straight
2913
+ # back into #parse_statement, which would otherwise let a chain like
2914
+ # "if(1)if(1)..." recurse without ever passing through the block guard
2915
+ # and exhaust the Ruby stack (a SystemStackError the driver cannot
2916
+ # report as a diagnostic).
2917
+ def parse_nested_statement(token)
2918
+ with_nesting_guard(token, "statement") { parse_statement }
2919
+ end
2920
+
2921
+ # "return;" (a void return, `expr` nil) or "return expression;"; whether
2922
+ # a void function may omit the value (and a non-void one may not) is the
2923
+ # generator's job.
2924
+ def parse_return
2925
+ ret_tok = advance # "return"
2926
+ expr = peek.punct?(";") ? nil : parse_expression
2927
+ expect_punct(";")
2928
+ AST::Return.new(expr, ret_tok)
2929
+ end
2930
+
2931
+ # "else" binds to the nearest preceding "if": since the else clause is
2932
+ # consumed eagerly by the innermost recursive call, dangling-else
2933
+ # resolves the standard C way without extra bookkeeping.
2934
+ def parse_selection_statement
2935
+ if_tok = advance # "if"
2936
+ expect_punct("(")
2937
+ condition = parse_expression
2938
+ expect_punct(")")
2939
+ then_stmt = parse_nested_statement(if_tok)
2940
+ else_stmt = nil
2941
+ if peek.keyword?("else")
2942
+ else_tok = advance
2943
+ else_stmt = parse_nested_statement(else_tok)
2944
+ end
2945
+ AST::If.new(condition, then_stmt, else_stmt, if_tok)
2946
+ end
2947
+
2948
+ def parse_while_statement
2949
+ while_tok = advance # "while"
2950
+ expect_punct("(")
2951
+ condition = parse_expression
2952
+ expect_punct(")")
2953
+ body = parse_nested_statement(while_tok)
2954
+ AST::While.new(condition, body, while_tok)
2955
+ end
2956
+
2957
+ def parse_do_while_statement
2958
+ do_tok = advance # "do"
2959
+ body = parse_nested_statement(do_tok)
2960
+ expect_keyword("while")
2961
+ expect_punct("(")
2962
+ condition = parse_expression
2963
+ expect_punct(")")
2964
+ expect_punct(";")
2965
+ AST::DoWhile.new(body, condition, do_tok)
2966
+ end
2967
+
2968
+ def parse_for_statement
2969
+ for_tok = advance # "for"
2970
+ expect_punct("(")
2971
+ # C99 gives the for-loop's own parentheses a scope, so a tag, a typedef
2972
+ # or a variable declared in clause-1 is visible only through the loop.
2973
+ @tag_scopes.push({})
2974
+ @ordinary_scopes.push({})
2975
+ init = parse_for_init
2976
+ condition = peek.punct?(";") ? nil : parse_expression
2977
+ expect_punct(";")
2978
+ step = peek.punct?(")") ? nil : parse_expression
2979
+ expect_punct(")")
2980
+ body = parse_nested_statement(for_tok)
2981
+ @ordinary_scopes.pop
2982
+ @tag_scopes.pop
2983
+ AST::For.new(init, condition, step, body, for_tok)
2984
+ end
2985
+
2986
+ # Parses the for-loop's first clause, consuming its trailing ";" (a
2987
+ # declaration already does so; the other two branches do it explicitly).
2988
+ def parse_for_init
2989
+ if type_specifier?(peek)
2990
+ parse_declaration
2991
+ elsif peek.punct?(";")
2992
+ advance
2993
+ nil
2994
+ else
2995
+ expr = parse_expression
2996
+ expect_punct(";")
2997
+ expr
2998
+ end
2999
+ end
3000
+
3001
+ def parse_break_statement
3002
+ break_tok = advance # "break"
3003
+ expect_punct(";")
3004
+ AST::Break.new(break_tok)
3005
+ end
3006
+
3007
+ def parse_continue_statement
3008
+ continue_tok = advance # "continue"
3009
+ expect_punct(";")
3010
+ AST::Continue.new(continue_tok)
3011
+ end
3012
+
3013
+ # "goto identifier;": an unconditional jump to a label defined elsewhere
3014
+ # in the same function. Only the target's name is captured here; whether
3015
+ # it names a defined label is the generator's check, since the label may
3016
+ # appear textually after the goto (a forward jump).
3017
+ def parse_goto_statement
3018
+ goto_tok = advance # "goto"
3019
+ name_tok = expect_ident
3020
+ expect_punct(";")
3021
+ AST::Goto.new(name_tok.value, goto_tok)
3022
+ end
3023
+
3024
+ # A GNU inline-assembly statement (DESIGN R7): only the degenerate barrier
3025
+ # form is supported, spelled `__asm__` (never `asm`/`__asm`). The grammar
3026
+ # is `__asm__ volatile* "(" template (":" section)* ")" ";"`, "volatile"
3027
+ # admitting its GNU "__volatile"/"__volatile__" spellings too (both lex to
3028
+ # the same keyword token, see LexemeReader::KEYWORD_ALIASES). The template
3029
+ # must be an (adjacent run of) empty string literal(s); a non-empty one, or
3030
+ # any real operand in the output/input sections, is diagnosed. The clobber
3031
+ # section's strings ("memory", "cc", ...) are accepted and discarded.
3032
+ # Nothing is lowered — see AST::InlineAsm.
3033
+ def parse_asm_statement
3034
+ asm_tok = advance # "__asm__"
3035
+ # Any number of volatile qualifiers.
3036
+ advance while peek.keyword?("volatile")
3037
+ expect_punct("(")
3038
+ parse_asm_template(asm_tok)
3039
+ parse_asm_operand_sections(asm_tok) if peek.punct?(":")
3040
+ expect_punct(")")
3041
+ expect_punct(";")
3042
+ AST::InlineAsm.new(asm_tok)
3043
+ end
3044
+
3045
+ # The assembly template: one or more adjacent string literals, whose
3046
+ # concatenation must be empty. A non-empty template names real instructions
3047
+ # this backend cannot emit, so it is rejected at the keyword.
3048
+ def parse_asm_template(asm_tok)
3049
+ tok = peek
3050
+ error_at(tok, "expected string literal in inline assembly") unless tok.type == :string
3051
+ empty = true
3052
+ while peek.type == :string
3053
+ empty &&= peek.value.empty?
3054
+ advance
3055
+ end
3056
+ error_at(asm_tok, "non-empty inline assembly is not supported") unless empty
3057
+ end
3058
+
3059
+ # The ":"-separated sections after the template. By position the first is
3060
+ # the output operands and the second the input operands, both of which must
3061
+ # be empty (a real operand is unsupported); the third and any later section
3062
+ # is a clobber list of string literals, accepted and discarded.
3063
+ def parse_asm_operand_sections(asm_tok)
3064
+ section = 0
3065
+ while peek.punct?(":")
3066
+ advance # ":"
3067
+ if section < 2
3068
+ parse_asm_empty_operand_section(asm_tok)
3069
+ else
3070
+ parse_asm_clobbers(asm_tok)
3071
+ end
3072
+ section += 1
3073
+ end
3074
+ end
3075
+
3076
+ # An output/input operand section, which must be empty: the next token ends
3077
+ # the section (":" for the next one, ")" for the whole construct). Anything
3078
+ # else is an operand expression this subset does not support.
3079
+ def parse_asm_empty_operand_section(asm_tok)
3080
+ return if peek.punct?(":") || peek.punct?(")")
3081
+
3082
+ error_at(peek, "inline assembly operands are not supported")
3083
+ end
3084
+
3085
+ # A clobber section: a comma-separated list of string literals (or empty).
3086
+ # The names are discarded — this backend never reorders, so a clobber
3087
+ # constrains nothing.
3088
+ def parse_asm_clobbers(_asm_tok)
3089
+ return if peek.punct?(":") || peek.punct?(")")
3090
+
3091
+ loop do
3092
+ tok = peek
3093
+ unless tok.type == :string
3094
+ error_at(tok, "expected string literal in inline assembly clobber list")
3095
+ end
3096
+ advance
3097
+ break unless peek.punct?(",")
3098
+
3099
+ advance # ","
3100
+ end
3101
+ end
3102
+
3103
+ # "switch (expression) statement": the controlling expression and the body
3104
+ # in which case/default labels sit. The body is one statement (typically a
3105
+ # compound-statement); the parser does not check that any case is present
3106
+ # or well-placed — the generator collects the labels and diagnoses misuse.
3107
+ def parse_switch_statement
3108
+ switch_tok = advance # "switch"
3109
+ expect_punct("(")
3110
+ control = parse_expression
3111
+ expect_punct(")")
3112
+ body = parse_nested_statement(switch_tok)
3113
+ AST::Switch.new(control, body, switch_tok)
3114
+ end
3115
+
3116
+ # "case constant-expression : statement". The case constant is parsed as
3117
+ # a conditional-expression — constant-expression's production (6.6) — and
3118
+ # folded to a Ruby Integer on the spot; the labeled statement follows the
3119
+ # colon. A conditional operand's own ":" (as in "case 1 ? 2 : 3:") is
3120
+ # consumed by conditional-expression itself, leaving exactly the label's
3121
+ # ":" for #expect_punct here. Whether this case sits inside a switch, and
3122
+ # whether its value is unique, is left to the generator.
3123
+ def parse_case_statement
3124
+ case_tok = advance # "case"
3125
+ expr = parse_conditional_expression
3126
+ value = evaluate_constant_expression(expr, "case label does not reduce to an integer constant",
3127
+ sizeof_expr: method(:fold_time_sizeof))
3128
+ expect_punct(":")
3129
+ body = parse_nested_statement(case_tok)
3130
+ AST::Case.new(value, body, case_tok)
3131
+ end
3132
+
3133
+ # "default : statement": the fall-through label of a switch, carrying no
3134
+ # constant. At most one may appear per switch, which the generator checks.
3135
+ def parse_default_statement
3136
+ default_tok = advance # "default"
3137
+ expect_punct(":")
3138
+ body = parse_nested_statement(default_tok)
3139
+ AST::Default.new(body, default_tok)
3140
+ end
3141
+
3142
+ # "identifier : statement": a labeled statement, the target of a goto. The
3143
+ # identifier and its ":" have already been confirmed by the two-token
3144
+ # lookahead in #parse_statement; the prefixed statement follows.
3145
+ def parse_labeled_statement
3146
+ name_tok = advance # identifier
3147
+ advance # ":"
3148
+ body = parse_nested_statement(name_tok)
3149
+ AST::Label.new(name_tok.value, body, name_tok)
3150
+ end
3151
+
3152
+ def parse_compound_statement
3153
+ brace_tok = expect_punct("{")
3154
+ with_nesting_guard(brace_tok, "block") do
3155
+ # A nested block introduces its own tag and ordinary scopes, mirroring
3156
+ # its variable scope: a struct, an enum constant or a typedef defined
3157
+ # here shadows an outer one and is gone at "}".
3158
+ @tag_scopes.push({})
3159
+ @ordinary_scopes.push({})
3160
+ items = []
3161
+ items.concat(parse_block_item) until peek.punct?("}")
3162
+ @ordinary_scopes.pop
3163
+ @tag_scopes.pop
3164
+ expect_punct("}")
3165
+ AST::Block.new(items, brace_tok)
3166
+ end
3167
+ end
3168
+
3169
+ def parse_expression_statement
3170
+ tok = peek
3171
+ if tok.punct?(";")
3172
+ advance
3173
+ AST::EmptyStmt.new(tok)
3174
+ else
3175
+ expr = parse_expression
3176
+ expect_punct(";")
3177
+ AST::ExpressionStmt.new(expr, tok)
3178
+ end
3179
+ end
3180
+
3181
+ # expression = assignment-expression ("," assignment-expression)*: the
3182
+ # comma operator, left-associative. Each left operand is evaluated for its
3183
+ # side effects and discarded; the last operand's value and type are the
3184
+ # whole expression's. Every context where a comma is a *separator* rather
3185
+ # than the operator (a call's arguments, a run of declarators, a global
3186
+ # initializer) bypasses this and calls #parse_assignment_expression
3187
+ # directly, so those commas keep their meaning; only the contexts that
3188
+ # take a full expression (a parenthesized expression, a subscript, an
3189
+ # expression-statement, the for-clauses, a control condition, a return,
3190
+ # the middle of "?:") reach the comma operator here.
3191
+ def parse_expression
3192
+ node = parse_assignment_expression
3193
+ while peek.punct?(",")
3194
+ tok = advance
3195
+ node = AST::Comma.new(node, parse_assignment_expression, tok)
3196
+ end
3197
+ node
3198
+ end
3199
+
3200
+ # Right-associative: "a = b = c" parses as "a = (b = c)"; likewise for
3201
+ # the compound-assignment operators. The right operand recurses back here,
3202
+ # so a long "a = b = c = ..." chain deepens through this method rather than
3203
+ # through #parse_cast_expression (which has already returned by the time the
3204
+ # "=" is seen); it therefore carries its own nesting guard.
3205
+ def parse_assignment_expression
3206
+ with_nesting_guard(peek, "expression") do
3207
+ node = parse_conditional_expression
3208
+ tok = peek
3209
+ if tok.punct?("=")
3210
+ advance
3211
+ error_at(tok, "expression is not assignable") unless assignable?(node)
3212
+ AST::Assignment.new(node, parse_assignment_expression, tok)
3213
+ elsif (op = tok.type == :punct ? COMPOUND_ASSIGNMENT_OPERATORS[tok.value] : nil)
3214
+ advance
3215
+ error_at(tok, "expression is not assignable") unless assignable?(node)
3216
+ AST::CompoundAssignment.new(op, node, parse_assignment_expression, tok)
3217
+ else
3218
+ node
3219
+ end
3220
+ end
3221
+ end
3222
+
3223
+ # Syntactically, only a variable reference, a subscript "e[i]", a struct
3224
+ # member access "e.m"/"e->m" or a dereference "*expr" can appear on the
3225
+ # left of "=" (or "++"/"--", or a compound-assignment operator). Whether
3226
+ # the target's type is actually assignable (e.g. not an array) is checked
3227
+ # later by the generator.
3228
+ def assignable?(node)
3229
+ node.is_a?(AST::VariableRef) ||
3230
+ node.is_a?(AST::Subscript) ||
3231
+ node.is_a?(AST::MemberAccess) ||
3232
+ (node.is_a?(AST::Unary) && node.op == :deref)
3233
+ end
3234
+
3235
+ # "?:" is right-associative: "a ? b : c ? d : e" parses as
3236
+ # "a ? b : (c ? d : e)". The middle operand is a full expression (not a
3237
+ # conditional-expression), per ISO C, so a bare assignment may appear
3238
+ # there without parentheses.
3239
+ # Both arms recurse — the "then" through #parse_expression and the "else"
3240
+ # directly — so a "a ? b : c ? d : ..." chain deepens through this method,
3241
+ # above where #parse_cast_expression's guard would catch it; it is guarded
3242
+ # here on the shared counter.
3243
+ def parse_conditional_expression
3244
+ with_nesting_guard(peek, "expression") do
3245
+ node = parse_logical_or_expression
3246
+ if peek.punct?("?")
3247
+ question_tok = advance
3248
+ then_expr = parse_expression
3249
+ expect_punct(":")
3250
+ else_expr = parse_conditional_expression
3251
+ AST::Conditional.new(node, then_expr, else_expr, question_tok)
3252
+ else
3253
+ node
3254
+ end
3255
+ end
3256
+ end
3257
+
3258
+ def parse_logical_or_expression
3259
+ node = parse_logical_and_expression
3260
+ while peek.punct?("||")
3261
+ tok = advance
3262
+ node = AST::LogicalOr.new(node, parse_logical_and_expression, tok)
3263
+ end
3264
+ node
3265
+ end
3266
+
3267
+ def parse_logical_and_expression
3268
+ node = parse_inclusive_or_expression
3269
+ while peek.punct?("&&")
3270
+ tok = advance
3271
+ node = AST::LogicalAnd.new(node, parse_inclusive_or_expression, tok)
3272
+ end
3273
+ node
3274
+ end
3275
+
3276
+ # The three bitwise tiers sit between logical-AND and equality, in ISO C
3277
+ # order (inclusive-OR loosest, then exclusive-OR, then AND). The binary
3278
+ # "&" is recognized only here, between two operands; a "&" that opens a
3279
+ # unary-expression is the address-of operator, parsed far deeper, so the
3280
+ # two never collide (and the lexer has already split off "&&" and "&=").
3281
+ def parse_inclusive_or_expression
3282
+ parse_left_associative(INCLUSIVE_OR_OPERATORS) { parse_exclusive_or_expression }
3283
+ end
3284
+
3285
+ def parse_exclusive_or_expression
3286
+ parse_left_associative(EXCLUSIVE_OR_OPERATORS) { parse_and_expression }
3287
+ end
3288
+
3289
+ def parse_and_expression
3290
+ parse_left_associative(AND_OPERATORS) { parse_equality_expression }
3291
+ end
3292
+
3293
+ def parse_equality_expression
3294
+ parse_left_associative(EQUALITY_OPERATORS) { parse_relational_expression }
3295
+ end
3296
+
3297
+ def parse_relational_expression
3298
+ parse_left_associative(RELATIONAL_OPERATORS) { parse_shift_expression }
3299
+ end
3300
+
3301
+ # shift-expression sits between relational and additive, so "1 << 2 + 3"
3302
+ # shifts by 5 (additive binds tighter) while "1 + 2 << 3" adds first
3303
+ # (shift is looser than additive but tighter than relational).
3304
+ def parse_shift_expression
3305
+ parse_left_associative(SHIFT_OPERATORS) { parse_additive_expression }
3306
+ end
3307
+
3308
+ def parse_additive_expression
3309
+ parse_left_associative(ADDITIVE_OPERATORS) { parse_multiplicative_expression }
3310
+ end
3311
+
3312
+ def parse_multiplicative_expression
3313
+ parse_left_associative(MULTIPLICATIVE_OPERATORS) { parse_cast_expression }
3314
+ end
3315
+
3316
+ # cast-expression = "(" type-name ")" cast-expression | unary-expression.
3317
+ # A "(" begins a cast only when a type-specifier follows it; otherwise it
3318
+ # is an ordinary parenthesized expression, left for unary-expression (and
3319
+ # finally primary-expression) to consume. #type_specifier? settles the
3320
+ # choice with a single token of lookahead — a type keyword or a typedef
3321
+ # name after "(" — so "(int)x" and "(T)x" are casts while "(x)(y)", x
3322
+ # being neither, is a call.
3323
+ # This is the single choke point every deepening expression form re-enters
3324
+ # exactly once per nesting level — a parenthesized "( expression )" (via
3325
+ # primary-expression), a "!"/"-"/"*"/... unary chain, a "( type-name )"
3326
+ # cast chain, a "?:" arm, a subscript or a call argument all descend back
3327
+ # through here — so guarding it alone bounds the depth of the whole
3328
+ # expression grammar with no double counting.
3329
+ def parse_cast_expression
3330
+ with_nesting_guard(peek, "expression") do
3331
+ # A "__extension__" prefix (a GNU marker with no semantic effect) binds
3332
+ # like a cast operator: it is consumed here and the cast-expression it
3333
+ # governs is parsed in its place ("__extension__ x", "y = __extension__ z").
3334
+ if peek.keyword?("__extension__")
3335
+ advance
3336
+ parse_cast_expression
3337
+ elsif peek.punct?("(") && peek_ahead(1) && type_specifier?(peek_ahead(1))
3338
+ paren_tok = advance # "("
3339
+ # An unsized "[]" is admitted here so a compound literal can infer its
3340
+ # bound ("(int[]){1,2,3}"); a plain cast to that incomplete type is
3341
+ # rejected below, once the following "{" (or its absence) settles the
3342
+ # two forms apart.
3343
+ type = parse_type_name(allow_incomplete_array: true)
3344
+ expect_punct(")")
3345
+ # A "{" after "( type-name )" opens a compound literal (6.5.2.5),
3346
+ # not a cast: "( type-name ) { initializer-list }" builds an unnamed
3347
+ # object of that type. It is a postfix-expression, so any trailing
3348
+ # postfix suffix ("(json_frame){...}.type") binds to it. Every other
3349
+ # token keeps the ordinary cast reading "( type-name ) cast-expr".
3350
+ if peek.punct?("{")
3351
+ parse_postfix_suffixes(parse_compound_literal(type, paren_tok))
3352
+ else
3353
+ if type.array? && type.length.nil?
3354
+ error_at(paren_tok, "array size missing in cast to array type")
3355
+ end
3356
+ AST::Cast.new(type, parse_cast_expression, paren_tok)
3357
+ end
3358
+ else
3359
+ parse_unary_expression
3360
+ end
3361
+ end
3362
+ end
3363
+
3364
+ # Generic left-associative binary parser: the block parses one operand
3365
+ # at the next-tighter precedence tier; `operator_table` maps the
3366
+ # punctuators of this tier to AST operators.
3367
+ def parse_left_associative(operator_table)
3368
+ node = yield
3369
+ loop do
3370
+ tok = peek
3371
+ ast_op = tok.type == :punct ? operator_table[tok.value] : nil
3372
+ return node unless ast_op
3373
+
3374
+ advance
3375
+ node = AST::Binary.new(ast_op, node, yield, tok)
3376
+ end
3377
+ end
3378
+
3379
+ # The unary tier recurses through several forms that never pass through
3380
+ # #parse_cast_expression — "sizeof sizeof ... x" recurses back here, and a
3381
+ # prefix "++"/"--" likewise — so a chain of them would escape a guard placed
3382
+ # only on the cast tier. Guarding the unary entry catches those, and the
3383
+ # "!"/"-"/... operators (which do recurse through the cast tier) as well.
3384
+ def parse_unary_expression
3385
+ with_nesting_guard(peek, "expression") do
3386
+ if peek.keyword?("sizeof")
3387
+ parse_sizeof
3388
+ elsif peek.keyword?("_Alignof")
3389
+ parse_alignof
3390
+ elsif peek.keyword?("__builtin_va_start")
3391
+ parse_va_start
3392
+ elsif peek.keyword?("__builtin_va_arg")
3393
+ parse_va_arg
3394
+ elsif peek.keyword?("__builtin_va_end")
3395
+ parse_va_end
3396
+ elsif peek.keyword?("__builtin_va_copy")
3397
+ parse_va_copy
3398
+ elsif peek.keyword?("__builtin_expect")
3399
+ parse_builtin_expect
3400
+ elsif peek.keyword?("__builtin_alloca")
3401
+ parse_builtin_alloca
3402
+ elsif peek.keyword?("__builtin_offsetof")
3403
+ parse_builtin_offsetof
3404
+ elsif peek.keyword?("__builtin_constant_p")
3405
+ parse_builtin_constant_p
3406
+ elsif peek.keyword?("__builtin_choose_expr")
3407
+ parse_builtin_choose_expr
3408
+ elsif peek.keyword?("__builtin_ctz")
3409
+ parse_builtin_bit_scan(:forward, 4)
3410
+ elsif peek.keyword?("__builtin_ctzll")
3411
+ parse_builtin_bit_scan(:forward, 8)
3412
+ elsif peek.keyword?("__builtin_clz")
3413
+ parse_builtin_bit_scan(:reverse, 4)
3414
+ elsif peek.keyword?("__builtin_clzll")
3415
+ parse_builtin_bit_scan(:reverse, 8)
3416
+ elsif peek.keyword?("__builtin_unreachable")
3417
+ parse_builtin_unreachable
3418
+ elsif peek.keyword?("__builtin_memcpy")
3419
+ parse_builtin_memcpy
3420
+ elsif peek.type == :keyword && OVERFLOW_BUILTINS.key?(peek.value)
3421
+ parse_builtin_overflow
3422
+ elsif peek.type == :keyword && ATOMIC_BUILTINS.key?(peek.value)
3423
+ parse_builtin_atomic
3424
+ elsif peek.type == :keyword && SYNC_BUILTINS.key?(peek.value)
3425
+ parse_builtin_sync
3426
+ elsif peek.punct?("+")
3427
+ advance # unary + is a no-op; fold it away
3428
+ parse_cast_expression
3429
+ elsif peek.punct?("-")
3430
+ op_tok = advance
3431
+ AST::Unary.new(:neg, parse_cast_expression, op_tok)
3432
+ elsif peek.punct?("!")
3433
+ op_tok = advance
3434
+ AST::Unary.new(:not, parse_cast_expression, op_tok)
3435
+ elsif peek.punct?("~")
3436
+ parse_bitwise_not
3437
+ elsif peek.punct?("&")
3438
+ op_tok = advance
3439
+ AST::Unary.new(:addr, parse_cast_expression, op_tok)
3440
+ elsif peek.punct?("*")
3441
+ op_tok = advance
3442
+ AST::Unary.new(:deref, parse_cast_expression, op_tok)
3443
+ elsif peek.punct?("++") || peek.punct?("--")
3444
+ parse_prefix_inc_dec
3445
+ else
3446
+ parse_postfix_expression
3447
+ end
3448
+ end
3449
+ end
3450
+
3451
+ # "~x" is the one's-complement of an arithmetic operand. Rather than carry
3452
+ # a dedicated bitwise-not through the IR, it is desugared here to the
3453
+ # exclusive-or "x ^ -1": flipping every bit is an xor with all-ones, and
3454
+ # -1 is all-ones in every integer width. The generator then type-checks
3455
+ # and lowers it as an ordinary ":xor", so a pointer or struct operand is
3456
+ # rejected as an invalid binary operand exactly like "x ^ 1" would be. The
3457
+ # "~" token locates both the literal and the node for diagnostics.
3458
+ def parse_bitwise_not
3459
+ op_tok = advance # "~"
3460
+ operand = parse_cast_expression
3461
+ AST::Binary.new(:xor, operand, AST::IntLit.new(-1, op_tok, Type::Int), op_tok)
3462
+ end
3463
+
3464
+ def parse_prefix_inc_dec
3465
+ op_tok = advance
3466
+ op = op_tok.value == "++" ? :add : :sub
3467
+ operand = parse_unary_expression
3468
+ error_at(op_tok, "expression is not assignable") unless assignable?(operand)
3469
+ AST::IncDec.new(op, operand, true, op_tok)
3470
+ end
3471
+
3472
+ # "sizeof" measures either a parenthesized type-name ("sizeof(char *)")
3473
+ # or the result type of a unary-expression ("sizeof x", "sizeof(a)"). A
3474
+ # "(" right after the keyword is only a type-name when a type-specifier
3475
+ # ("int" or "char") follows; otherwise it is an ordinary parenthesized
3476
+ # operand, so it is left for unary-expression to consume.
3477
+ def parse_sizeof
3478
+ sizeof_tok = advance # "sizeof"
3479
+ if peek.punct?("(") && peek_ahead(1) && type_specifier?(peek_ahead(1))
3480
+ advance # "("
3481
+ type = parse_type_name
3482
+ expect_punct(")")
3483
+ AST::SizeofType.new(type, sizeof_tok)
3484
+ else
3485
+ AST::SizeofExpr.new(parse_unary_expression, sizeof_tok)
3486
+ end
3487
+ end
3488
+
3489
+ # "_Alignof ( type-name )" (6.5.3.4): the alignment of a written type. Only
3490
+ # the parenthesized type-name form exists — there is no operand form as
3491
+ # sizeof has — so the "(" and type-name are read unconditionally. The
3492
+ # generator folds it to a size_t constant, like sizeof of a type.
3493
+ def parse_alignof
3494
+ alignof_tok = advance # "_Alignof"
3495
+ expect_punct("(")
3496
+ type = parse_type_name
3497
+ expect_punct(")")
3498
+ AST::AlignofType.new(type, alignof_tok)
3499
+ end
3500
+
3501
+ # "__builtin_va_start ( assignment-expression , identifier )": the va_list
3502
+ # to initialize and the name of the last fixed parameter (a bare
3503
+ # identifier, not an expression, since the ABI locates the variable part
3504
+ # relative to that parameter). The generator checks the name against the
3505
+ # enclosing function's last named parameter.
3506
+ def parse_va_start
3507
+ keyword_tok = advance # "__builtin_va_start"
3508
+ expect_punct("(")
3509
+ ap = parse_assignment_expression
3510
+ expect_punct(",")
3511
+ name_tok = expect_ident
3512
+ expect_punct(")")
3513
+ AST::VaStart.new(ap, name_tok.value, keyword_tok)
3514
+ end
3515
+
3516
+ # "__builtin_va_arg ( assignment-expression , type-name )": the va_list and
3517
+ # the type-name the next argument is fetched as. The type-name uses the
3518
+ # same abstract-declarator grammar as sizeof/casts.
3519
+ def parse_va_arg
3520
+ keyword_tok = advance # "__builtin_va_arg"
3521
+ expect_punct("(")
3522
+ ap = parse_assignment_expression
3523
+ expect_punct(",")
3524
+ type = parse_type_name
3525
+ expect_punct(")")
3526
+ AST::VaArg.new(ap, type, keyword_tok)
3527
+ end
3528
+
3529
+ # "__builtin_va_end ( assignment-expression )": the va_list whose traversal
3530
+ # ends. A no-op on System V beyond the operand's type check.
3531
+ def parse_va_end
3532
+ keyword_tok = advance # "__builtin_va_end"
3533
+ expect_punct("(")
3534
+ ap = parse_assignment_expression
3535
+ expect_punct(")")
3536
+ AST::VaEnd.new(ap, keyword_tok)
3537
+ end
3538
+
3539
+ # "__builtin_va_copy ( assignment-expression , assignment-expression )":
3540
+ # the destination and source va_lists, whose state the generator copies as
3541
+ # a whole tag from the second to the first.
3542
+ def parse_va_copy
3543
+ keyword_tok = advance # "__builtin_va_copy"
3544
+ expect_punct("(")
3545
+ dest = parse_assignment_expression
3546
+ expect_punct(",")
3547
+ src = parse_assignment_expression
3548
+ expect_punct(")")
3549
+ AST::VaCopy.new(dest, src, keyword_tok)
3550
+ end
3551
+
3552
+ # "__builtin_expect ( exp , c )": exactly two arguments, parsed as an
3553
+ # ordinary argument list so a wrong count is reported as an arity error
3554
+ # rather than a bare punctuator-mismatch. The generator settles their
3555
+ # conversion to `long`.
3556
+ def parse_builtin_expect
3557
+ keyword_tok = advance # "__builtin_expect"
3558
+ expect_punct("(")
3559
+ args = parse_argument_expression_list
3560
+ expect_punct(")")
3561
+ unless args.size == 2
3562
+ error_at(keyword_tok, "'__builtin_expect' expects 2 arguments, have #{args.size}")
3563
+ end
3564
+ AST::BuiltinExpect.new(args[0], args[1], keyword_tok)
3565
+ end
3566
+
3567
+ # "__builtin_alloca ( n )": exactly one argument, the byte count. Like
3568
+ # __builtin_expect it is parsed as an argument list so a wrong count is an
3569
+ # arity diagnostic.
3570
+ def parse_builtin_alloca
3571
+ keyword_tok = advance # "__builtin_alloca"
3572
+ expect_punct("(")
3573
+ args = parse_argument_expression_list
3574
+ expect_punct(")")
3575
+ unless args.size == 1
3576
+ error_at(keyword_tok, "'__builtin_alloca' expects 1 argument, have #{args.size}")
3577
+ end
3578
+ AST::BuiltinAlloca.new(args[0], keyword_tok)
3579
+ end
3580
+
3581
+ # "__builtin_offsetof ( type-name , member-designator )": the aggregate
3582
+ # type and the member whose offset is wanted. The member-designator is a
3583
+ # leading member name followed by any run of ".name" and "[ expression ]"
3584
+ # steps (the gcc extension over a bare identifier, so "s.a.b[2].c" is
3585
+ # writable). The steps are collected into a designator array the constant
3586
+ # evaluator later walks to fold the offset; the array is never empty, since
3587
+ # a designator always begins with a member name.
3588
+ def parse_builtin_offsetof
3589
+ keyword_tok = advance # "__builtin_offsetof"
3590
+ expect_punct("(")
3591
+ type = parse_type_name
3592
+ expect_punct(",")
3593
+ designator = parse_member_designator
3594
+ expect_punct(")")
3595
+ AST::BuiltinOffsetof.new(type, designator, keyword_tok)
3596
+ end
3597
+
3598
+ # "__builtin_constant_p ( assignment-expression )": one operand, which is
3599
+ # never evaluated — the fold to 1/0 happens later (the constant evaluator
3600
+ # and the generator), so any expression at all is accepted here, including
3601
+ # one that references a variable or calls a function. The value is int.
3602
+ def parse_builtin_constant_p
3603
+ keyword_tok = advance # "__builtin_constant_p"
3604
+ expect_punct("(")
3605
+ expr = parse_assignment_expression
3606
+ expect_punct(")")
3607
+ AST::BuiltinConstantP.new(expr, keyword_tok)
3608
+ end
3609
+
3610
+ # "__builtin_choose_expr ( const-expr , expr-true , expr-false )": the
3611
+ # first operand is an integer constant-expression evaluated now; the whole
3612
+ # form is replaced at parse time by whichever of the two remaining operands
3613
+ # it selects (non-zero picks expr-true, zero picks expr-false), so no AST
3614
+ # node of its own is needed and the chosen operand's type flows through
3615
+ # unchanged. All three are still parsed, so a syntax error in the branch
3616
+ # that loses is still caught; only the winner reaches code generation. A
3617
+ # non-constant first operand is diagnosed.
3618
+ def parse_builtin_choose_expr
3619
+ advance # "__builtin_choose_expr"
3620
+ expect_punct("(")
3621
+ condition = parse_assignment_expression
3622
+ expect_punct(",")
3623
+ when_true = parse_assignment_expression
3624
+ expect_punct(",")
3625
+ when_false = parse_assignment_expression
3626
+ expect_punct(")")
3627
+ selector = evaluate_constant_expression(
3628
+ condition, "first argument to '__builtin_choose_expr' is not a constant expression",
3629
+ sizeof_expr: method(:fold_time_sizeof)
3630
+ )
3631
+ selector.zero? ? when_false : when_true
3632
+ end
3633
+
3634
+ # "__builtin_ctz/ctzll/clz/clzll ( assignment-expression )": one integer
3635
+ # operand whose trailing (`:forward`) or leading (`:reverse`) zero bits are
3636
+ # counted over `width` bytes. The generator settles the operand's integer
3637
+ # type check and lowers the bit scan; the result is int.
3638
+ def parse_builtin_bit_scan(direction, width)
3639
+ keyword_tok = advance # the "__builtin_ctz"/... keyword
3640
+ expect_punct("(")
3641
+ operand = parse_assignment_expression
3642
+ expect_punct(")")
3643
+ AST::BuiltinBitScan.new(operand, direction, width, keyword_tok)
3644
+ end
3645
+
3646
+ # "__builtin_add/sub/mul_overflow ( a , b , res )": exactly three arguments,
3647
+ # parsed as an ordinary argument list so a wrong count is an arity
3648
+ # diagnostic. The keyword decides only the operator; the operand types are
3649
+ # the generator's to check.
3650
+ def parse_builtin_overflow
3651
+ keyword_tok = advance # the "__builtin_..._overflow" keyword
3652
+ op = OVERFLOW_BUILTINS.fetch(keyword_tok.value)
3653
+ expect_punct("(")
3654
+ args = parse_argument_expression_list
3655
+ expect_punct(")")
3656
+ unless args.size == 3
3657
+ error_at(keyword_tok, "'#{keyword_tok.value}' expects 3 arguments, have #{args.size}")
3658
+ end
3659
+ AST::BuiltinOverflow.new(op, args, keyword_tok)
3660
+ end
3661
+
3662
+ # "__atomic_xxx ( ... )": one of the nine gcc atomic builtins rubycc
3663
+ # lowers. The keyword decides the kind and the exact argument count, both
3664
+ # of which ATOMIC_BUILTINS records; everything else (operand types, the
3665
+ # 4-or-8-byte width restriction) needs resolved types and is the
3666
+ # generator's to diagnose.
3667
+ def parse_builtin_atomic
3668
+ keyword_tok = advance # the "__atomic_..." keyword
3669
+ kind, arity = ATOMIC_BUILTINS.fetch(keyword_tok.value)
3670
+ expect_punct("(")
3671
+ args = parse_argument_expression_list
3672
+ expect_punct(")")
3673
+ unless args.size == arity
3674
+ error_at(keyword_tok, "'#{keyword_tok.value}' expects #{arity} arguments, have #{args.size}")
3675
+ end
3676
+ AST::BuiltinAtomic.new(kind, args, keyword_tok)
3677
+ end
3678
+
3679
+ # "__sync_xxx ( ... )": one of the legacy gcc atomic builtins rubycc
3680
+ # lowers. Shaped like #parse_builtin_atomic — SYNC_BUILTINS records the
3681
+ # kind and the exact argument count, and everything type-dependent is the
3682
+ # generator's to diagnose — but the counts here are the operand counts
3683
+ # alone, no memory order being part of these signatures.
3684
+ #
3685
+ # gcc lets a caller append extra arguments (the "protected variables" its
3686
+ # manual describes and then ignores); rubycc holds every form to its exact
3687
+ # arity, so a call that drifted from the intended shape is reported instead
3688
+ # of silently accepted.
3689
+ def parse_builtin_sync
3690
+ keyword_tok = advance # the "__sync_..." keyword
3691
+ kind, arity = SYNC_BUILTINS.fetch(keyword_tok.value)
3692
+ expect_punct("(")
3693
+ args = parse_argument_expression_list
3694
+ expect_punct(")")
3695
+ unless args.size == arity
3696
+ error_at(keyword_tok, "'#{keyword_tok.value}' expects #{arity} arguments, have #{args.size}")
3697
+ end
3698
+ AST::BuiltinSync.new(kind, args, keyword_tok)
3699
+ end
3700
+
3701
+ # "__builtin_unreachable ()": no operands. Lowers to no code (rubycc does
3702
+ # not optimize); its value is void.
3703
+ def parse_builtin_unreachable
3704
+ keyword_tok = advance # "__builtin_unreachable"
3705
+ expect_punct("(")
3706
+ expect_punct(")")
3707
+ AST::BuiltinUnreachable.new(keyword_tok)
3708
+ end
3709
+
3710
+ # "__builtin_memcpy ( dst , src , n )": rewritten to an ordinary call of
3711
+ # the libc function "memcpy", so it links against the C library's memcpy
3712
+ # like the plain call would. The generator seeds a builtin prototype for
3713
+ # "memcpy" (void *(void *, const void *, unsigned long)), so this compiles
3714
+ # even when <string.h> is not included, matching gcc's builtin.
3715
+ def parse_builtin_memcpy
3716
+ keyword_tok = advance # "__builtin_memcpy"
3717
+ expect_punct("(")
3718
+ args = parse_argument_expression_list
3719
+ expect_punct(")")
3720
+ unless args.size == 3
3721
+ error_at(keyword_tok, "'__builtin_memcpy' expects 3 arguments, have #{args.size}")
3722
+ end
3723
+ AST::Call.new(AST::VariableRef.new("memcpy", keyword_tok), args, keyword_tok)
3724
+ end
3725
+
3726
+ # member-designator = identifier ( "." identifier | "[" expression "]" )*:
3727
+ # the leading member name has no ".", every following member step does, and
3728
+ # a subscript step takes a constant-expression closed by "]". Any other
3729
+ # token where a "." or "[" is expected ends the designator, leaving the ")"
3730
+ # for the caller.
3731
+ def parse_member_designator
3732
+ first_tok = expect_ident
3733
+ designator = [AST::OffsetofMember.new(first_tok.value, first_tok)]
3734
+ loop do
3735
+ if peek.punct?(".")
3736
+ advance # "."
3737
+ member_tok = expect_ident
3738
+ designator << AST::OffsetofMember.new(member_tok.value, member_tok)
3739
+ elsif peek.punct?("[")
3740
+ bracket_tok = advance # "["
3741
+ index = parse_conditional_expression
3742
+ expect_punct("]")
3743
+ designator << AST::OffsetofIndex.new(index, bracket_tok)
3744
+ else
3745
+ return designator
3746
+ end
3747
+ end
3748
+ end
3749
+
3750
+ # type-name = type-specifier abstract-declarator?: a base type-specifier
3751
+ # and an abstract declarator (no name). Shared by "sizeof ( type-name )"
3752
+ # and the cast "( type-name )", so a function pointer, an array pointer or
3753
+ # a plain pointer type can be written there ("sizeof(int (*)(int))",
3754
+ # "(int (*)(int))p").
3755
+ def parse_type_name(allow_incomplete_array: false)
3756
+ _name_tok, type = parse_declarator(parse_type_specifier, name_mode: :forbidden,
3757
+ allow_incomplete_array: allow_incomplete_array)
3758
+ type
3759
+ end
3760
+
3761
+ # A compound literal "( type-name ) { initializer-list }" (6.5.2.5), the
3762
+ # "(" and type-name already consumed by the cast tier. The brace list is
3763
+ # parsed with the ordinary initializer machinery; when it structurally
3764
+ # fits `type` (a brace list always does, a string an aggregate char array)
3765
+ # the type is resolved once here so an inferred "(int[]){...}" bound is
3766
+ # filled in — the same completion #parse_init_declarator performs — and the
3767
+ # finished type rides on the node. The generator lays out the object and
3768
+ # re-resolves the placements.
3769
+ def parse_compound_literal(type, paren_tok)
3770
+ initializer = parse_initializer_list
3771
+ if InitializerResolver.structural?(type, initializer)
3772
+ type = InitializerResolver.resolve(type, initializer).type
3773
+ end
3774
+ AST::CompoundLiteral.new(type, initializer, paren_tok)
3775
+ end
3776
+
3777
+ # A postfix-expression is a primary-expression followed by any run of
3778
+ # postfix suffixes in source order: a call "( args )", a subscript
3779
+ # "[ i ]", a member access "." / "->" and a postfix "++"/"--". A call is
3780
+ # just another suffix, so its callee may be any postfix-expression —
3781
+ # "f(x)", "(*fp)(x)", "table[i](x)" and "s.fp(x)" all parse the same way,
3782
+ # with the AST::Call carrying the callee expression it followed.
3783
+ def parse_postfix_expression
3784
+ parse_postfix_suffixes(parse_primary_expression)
3785
+ end
3786
+
3787
+ # Applies any run of postfix suffixes (call, subscript, member access,
3788
+ # postfix "++"/"--") to an already-parsed postfix-expression head. Split
3789
+ # out from #parse_postfix_expression so a compound literal — which the cast
3790
+ # tier builds after "( type-name )" and which is itself a
3791
+ # postfix-expression (6.5.2p1) — can carry the same suffixes, letting
3792
+ # "(json_frame){...}.type" and "(int[]){1,2,3}[i]" parse.
3793
+ def parse_postfix_suffixes(node)
3794
+ loop do
3795
+ if peek.punct?("(")
3796
+ paren_tok = advance # "("
3797
+ args = parse_argument_expression_list
3798
+ expect_punct(")")
3799
+ node = AST::Call.new(node, args, paren_tok)
3800
+ elsif peek.punct?("[")
3801
+ bracket_tok = advance # "["
3802
+ index = parse_expression
3803
+ expect_punct("]")
3804
+ node = AST::Subscript.new(node, index, bracket_tok)
3805
+ elsif peek.punct?(".") || peek.punct?("->")
3806
+ op_tok = advance
3807
+ member_tok = expect_ident
3808
+ node = AST::MemberAccess.new(node, member_tok.value, op_tok.value == "->", op_tok)
3809
+ elsif peek.punct?("++") || peek.punct?("--")
3810
+ op_tok = advance
3811
+ op = op_tok.value == "++" ? :add : :sub
3812
+ error_at(op_tok, "expression is not assignable") unless assignable?(node)
3813
+ node = AST::IncDec.new(op, node, false, op_tok)
3814
+ else
3815
+ return node
3816
+ end
3817
+ end
3818
+ end
3819
+
3820
+ # Returns an array of expression nodes; empty for an argument-less "()".
3821
+ def parse_argument_expression_list
3822
+ return [] if peek.punct?(")")
3823
+
3824
+ args = [parse_assignment_expression]
3825
+ while peek.punct?(",")
3826
+ advance
3827
+ args << parse_assignment_expression
3828
+ end
3829
+ args
3830
+ end
3831
+
3832
+ def parse_primary_expression
3833
+ tok = peek
3834
+ if tok.type == :num
3835
+ advance
3836
+ AST::IntLit.new(tok.value, tok, integer_literal_type(tok.value, tok.base, tok.suffix, tok))
3837
+ elsif tok.type == :float
3838
+ advance
3839
+ # The suffix (from the lexer) fixes the constant's type: "f"/"F" is
3840
+ # float, everything else (plain, or "l"/"L" long double) is double.
3841
+ type = tok.suffix == "f" ? Type::Float : Type::Double
3842
+ AST::FloatLit.new(tok.value, type, tok)
3843
+ elsif tok.type == :string
3844
+ advance
3845
+ AST::StringLit.new(tok.value, tok)
3846
+ elsif tok.type == :ident
3847
+ advance
3848
+ # An identifier bound to an enum constant folds to its int value on the
3849
+ # spot, so the rest of the pipeline never sees an enumerator; one bound
3850
+ # to (or shadowed by) an ordinary name stays a variable reference.
3851
+ entry = lookup_ordinary(tok.value)
3852
+ if entry&.kind == :enum
3853
+ AST::IntLit.new(entry.value, tok, Type::Int)
3854
+ else
3855
+ AST::VariableRef.new(tok.value, tok)
3856
+ end
3857
+ elsif tok.punct?("(")
3858
+ # A "(" immediately followed by "{" opens a GNU statement expression
3859
+ # "( { block-item* } )" (a GCC extension): the braces enclose a
3860
+ # compound-statement, and its last expression-statement (if any) gives
3861
+ # the whole construct its value and type. Every other "(" is an
3862
+ # ordinary parenthesized expression. #parse_compound_statement carries
3863
+ # its own nesting guard and pushes the block's tag/ordinary scopes.
3864
+ if peek_ahead(1)&.punct?("{")
3865
+ advance # "("
3866
+ body = parse_compound_statement
3867
+ expect_punct(")")
3868
+ AST::StatementExpr.new(body, tok)
3869
+ else
3870
+ advance
3871
+ node = parse_expression
3872
+ expect_punct(")")
3873
+ node
3874
+ end
3875
+ else
3876
+ error_at(tok, "expected expression")
3877
+ end
3878
+ end
3879
+
3880
+ # The type of an integer constant (6.4.4.1): the first type in a
3881
+ # base/suffix-specific candidate list whose range holds the value. A `u`
3882
+ # suffix admits the unsigned types; a decimal constant is never unsigned
3883
+ # without one, while hex and octal constants may fall through to an
3884
+ # unsigned type. `l`/`ll` (folded to one "long" width under LP64) demote
3885
+ # the int candidates. A value beyond even unsigned long is rejected.
3886
+ def integer_literal_type(value, base, suffix, tok)
3887
+ has_u = suffix.include?("u")
3888
+ has_l = suffix.include?("l")
3889
+ decimal = base == 10
3890
+ candidates =
3891
+ if has_u && has_l then [Type::ULong]
3892
+ elsif has_u then [Type::UInt, Type::ULong]
3893
+ elsif has_l then decimal ? [Type::Long] : [Type::Long, Type::ULong]
3894
+ elsif decimal then [Type::Int, Type::Long]
3895
+ else [Type::Int, Type::UInt, Type::Long, Type::ULong]
3896
+ end
3897
+
3898
+ candidates.find { |type| integer_fits?(value, type) } ||
3899
+ # gcc widens an out-of-range constant to unsigned long rather than
3900
+ # reject it outright; only a value past unsigned long is an error.
3901
+ (integer_fits?(value, Type::ULong) ? Type::ULong : error_at(tok, "integer constant is too large"))
3902
+ end
3903
+
3904
+ # Whether the non-negative `value` fits in integer type `type`.
3905
+ def integer_fits?(value, type)
3906
+ limit = type.signed? ? (1 << (type.size * 8 - 1)) - 1 : (1 << (type.size * 8)) - 1
3907
+ value <= limit
3908
+ end
3909
+
3910
+ # --- ordinary-identifier namespace ---------------------------------
3911
+
3912
+ # Records a variable, parameter or function name in the current ordinary
3913
+ # scope. Its main job is to shadow a typedef name or enum constant of the
3914
+ # same name from an outer scope, so a redeclaration of an ordinary name (a
3915
+ # genuine error the generator reports) is deliberately not diagnosed here.
3916
+ # The declared `type` is kept as the entry's payload so a constant
3917
+ # expression folded during parsing can resolve "sizeof <variable>" (see
3918
+ # #fold_time_sizeof), which the type-table-free ConstantEvaluator otherwise
3919
+ # cannot; it is nil only for the synthetic entries that predate a type.
3920
+ def declare_ordinary_name(name, type = nil)
3921
+ @ordinary_scopes.last[name] = OrdinaryName.new(:ordinary, type)
3922
+ end
3923
+
3924
+ # Binds a typedef name to its resolved type (and whether it names a
3925
+ # const-qualified object type) in the current ordinary scope. C permits a
3926
+ # typedef name to be redeclared in the same scope when the new declaration
3927
+ # names the same type; a different type remains a redefinition diagnostic.
3928
+ def declare_typedef_name(name_tok, type, const)
3929
+ existing = @ordinary_scopes.last[name_tok.value]
3930
+ if existing
3931
+ return if existing.kind == :typedef && existing.value == [type, const]
3932
+
3933
+ error_at(name_tok, "redefinition of typedef '#{name_tok.value}'")
3934
+ end
3935
+ @ordinary_scopes.last[name_tok.value] = OrdinaryName.new(:typedef, [type, const])
3936
+ end
3937
+
3938
+ # The innermost ordinary-scope entry for `name`, or nil when none binds it.
3939
+ def lookup_ordinary(name)
3940
+ @ordinary_scopes.reverse_each do |scope|
3941
+ entry = scope[name]
3942
+ return entry if entry
3943
+ end
3944
+ nil
3945
+ end
3946
+
3947
+ # Whether `name`'s innermost ordinary binding is a typedef name — false
3948
+ # when it is unbound or shadowed by a nearer variable or enum constant.
3949
+ def typedef_name?(name)
3950
+ entry = lookup_ordinary(name)
3951
+ !entry.nil? && entry.kind == :typedef
3952
+ end
3953
+
3954
+ # --- token consumption helpers -------------------------------------
3955
+
3956
+ def expect_keyword(str)
3957
+ tok = peek
3958
+ error_at(tok, "expected '#{str}'") unless tok.keyword?(str)
3959
+ advance
3960
+ end
3961
+
3962
+ def expect_ident
3963
+ tok = peek
3964
+ error_at(tok, "expected identifier") unless tok.type == :ident
3965
+ advance
3966
+ end
3967
+
3968
+ def expect_punct(str)
3969
+ tok = peek
3970
+ error_at(tok, "expected '#{str}'") unless tok.punct?(str)
3971
+ advance
3972
+ end
3973
+
3974
+ def error_at(token, description)
3975
+ raise CompileError.new(
3976
+ description,
3977
+ filename: token.filename,
3978
+ line: token.line,
3979
+ column: token.column,
3980
+ source_line: token.source_line
3981
+ )
3982
+ end
3983
+
3984
+ # Folds `node` — a conditional-expression already parsed as a
3985
+ # constant-expression (6.6) — to a Ruby Integer via ConstantEvaluator.
3986
+ # A sub-expression that is not itself a constant expression is reported
3987
+ # with `message` at its own token; a division/remainder by zero that is
3988
+ # actually reached is reported at the operator's token, independent of
3989
+ # `message`, since it is a different failure than "not a constant".
3990
+ def evaluate_constant_expression(node, message, sizeof_expr: nil)
3991
+ ConstantEvaluator.evaluate(node, sizeof_expr: sizeof_expr)
3992
+ rescue ConstantEvaluator::NotConstant => e
3993
+ error_at(e.token, message)
3994
+ rescue ConstantEvaluator::DivisionByZero => e
3995
+ error_at(e.token, "division by zero in constant expression")
3996
+ end
3997
+
3998
+ # Resolves a "sizeof <expression>" operand to its byte size at parse time.
3999
+ # This is passed as ConstantEvaluator's `sizeof_expr:` in every constant
4000
+ # (or integer-constant) expression context the parser folds on the spot --
4001
+ # an array bound, an enumerator, a bit-field width, a case label, an array
4002
+ # designator, an "aligned" attribute argument, and the like -- since none
4003
+ # of them carries a type table the way "sizeof x" would otherwise need.
4004
+ # The operand's type is inferred by #sizeof_operand_type over the forms a
4005
+ # real constant expression's "sizeof <expr>" reaches (a named object, a
4006
+ # string literal, a subscript, a dereference, a cast -- notably ruby.h's
4007
+ # rb_strlen_lit, "(sizeof(s "") / sizeof(s ""[0])) - 1", which sizes both a
4008
+ # string literal and its element). sizeof measures its immediate operand
4009
+ # undecayed (6.5.3.4), so "sizeof arr" is the whole array. An operand whose
4010
+ # type cannot be inferred, or one of incomplete/void/function type with no
4011
+ # size, stays a NotConstant so the surrounding context reports "not an
4012
+ # integer constant" rather than a wrong value.
4013
+ def fold_time_sizeof(node)
4014
+ type = sizeof_operand_type(node.operand)
4015
+ if type.nil? || type.void? || type.function? || (type.array? && type.incomplete?)
4016
+ raise ConstantEvaluator::NotConstant, node.token
4017
+ end
4018
+
4019
+ type.size
4020
+ end
4021
+
4022
+ # The type a "sizeof" operand expression has, inferred without the
4023
+ # generator's symbol table, or nil when a form outside this small set is
4024
+ # met. A subscript and a dereference each decay their base (an array to a
4025
+ # pointer to its element) and yield the pointed-to type; a cast is its named
4026
+ # type; a named object's type is the one the ordinary scope recorded; a
4027
+ # member access ("." or "->") resolves against its base's struct/union type
4028
+ # -- sqlite3's "char dbFileVers[sizeof(pPager->dbFileVers)]" is exactly this
4029
+ # shape, an array bound sized from a pointer parameter's member. Only what
4030
+ # an array-bound constant expression realistically uses is covered.
4031
+ def sizeof_operand_type(node)
4032
+ case node
4033
+ when AST::StringLit
4034
+ Type::Array.new(Type::Char, node.value.bytesize + 1)
4035
+ when AST::VariableRef
4036
+ entry = lookup_ordinary(node.name)
4037
+ entry && entry.kind == :ordinary ? entry.value : nil
4038
+ when AST::Subscript
4039
+ element_of(sizeof_operand_type(node.target))
4040
+ when AST::Unary
4041
+ node.op == :deref ? element_of(sizeof_operand_type(node.operand)) : nil
4042
+ when AST::Cast
4043
+ node.type
4044
+ when AST::MemberAccess
4045
+ base = sizeof_operand_type(node.base)
4046
+ base = element_of(base) if node.arrow
4047
+ member_sizeof_type(base, node.member)
4048
+ end
4049
+ end
4050
+
4051
+ # The element type reached by subscripting or dereferencing a base of type
4052
+ # `type`: an array decays to a pointer first, so both an array and a pointer
4053
+ # yield their element/pointee. Anything else (or an unknown base) has none.
4054
+ def element_of(type)
4055
+ return nil if type.nil?
4056
+ return type.element if type.array?
4057
+
4058
+ type.target if type.pointer?
4059
+ end
4060
+
4061
+ # The type of member `name` in a struct/union `type`, for #sizeof_operand_type
4062
+ # resolving "sizeof base.member"/"sizeof base->member" -- nil when `type`
4063
+ # is not a completed struct/union, the member does not exist, or it is a
4064
+ # bit-field, since a bit-field has no size to take (6.5.3.4p1) and so must
4065
+ # stay a NotConstant rather than fold to a wrong value. #struct? alone
4066
+ # tells a struct/union base apart from every other type (it answers true
4067
+ # for both, see Type::StructType), so a plain `sizeof x.m` with `x` of a
4068
+ # non-aggregate type -- syntactically parseable, only later rejected by
4069
+ # the generator -- stops here rather than reaching #union?, which only
4070
+ # Type::StructType implements.
4071
+ def member_sizeof_type(type, name)
4072
+ return nil if type.nil? || !type.struct?
4073
+
4074
+ member = type.member(name)
4075
+ member && member.bit_width.nil? ? member.type : nil
4076
+ end
4077
+
4078
+ # Whether the initializer subtree uses `sizeof <expression>` (as opposed to
4079
+ # `sizeof(type-name)`) anywhere. Such an operand's type can only be
4080
+ # inferred with the symbol table the generator holds, so its presence tells
4081
+ # #parse_global_declarator to defer folding to the generator rather than
4082
+ # evaluate the initializer here. The walk descends only through AST nodes
4083
+ # (each a `Data` under this AST module), so it never recurses into the
4084
+ # Type or Token objects a node's fields also carry.
4085
+ def references_sizeof_expr?(node)
4086
+ return true if node.is_a?(AST::SizeofExpr)
4087
+ return false unless ast_node?(node)
4088
+
4089
+ node.deconstruct_keys(nil).each_value do |field|
4090
+ values = field.is_a?(Array) ? field : [field]
4091
+ return true if values.any? { |value| references_sizeof_expr?(value) }
4092
+ end
4093
+ false
4094
+ end
4095
+
4096
+ # Whether the initializer subtree takes an address ("&x") anywhere. Such an
4097
+ # expression reduces only through the generator's address-constant
4098
+ # machinery (the "(size_t)&((T*)0)->m" offsetof idiom folds to a member's
4099
+ # byte offset), not the parser's type-table-free evaluator, so its presence
4100
+ # defers folding of an integer initializer to the generator — mirroring
4101
+ # #references_sizeof_expr?. The walk descends only through AST nodes.
4102
+ def references_address_of?(node)
4103
+ return true if node.is_a?(AST::Unary) && node.op == :addr
4104
+ return false unless ast_node?(node)
4105
+
4106
+ node.deconstruct_keys(nil).each_value do |field|
4107
+ values = field.is_a?(Array) ? field : [field]
4108
+ return true if values.any? { |value| references_address_of?(value) }
4109
+ end
4110
+ false
4111
+ end
4112
+
4113
+ # Whether `value` is one of this module's AST nodes — a `Data` instance
4114
+ # whose class lives under `Rubycc::Front::AST` — so the initializer walk
4115
+ # descends into it but not into the tokens, types or literals a field may
4116
+ # hold.
4117
+ def ast_node?(value)
4118
+ value.is_a?(Data) && AST.constants.any? { |c| AST.const_get(c).equal?(value.class) }
4119
+ end
4120
+ end
4121
+ end
4122
+ end