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