rucc_lower/unit.rs
1//! The module level of the walk: what a translation unit's declarations become.
2//!
3//! Design: `spec/08-ir.md` section 8.9.
4//!
5//! One typed tree becomes one [`Module`]. A file-scope object becomes a global with an image
6//! built from its initializer, a function becomes a [`Func`] whose body is built by
7//! [`body`](mod@crate::body), and a string literal becomes an unnamed constant global that
8//! whatever mentioned it points at.
9//!
10//! # What an image is
11//!
12//! An initializer arrives here already flattened: one entry per scalar that is stored, each
13//! with the byte offset it goes at, with every designator and every nested brace already
14//! resolved. So building the image is a walk over the entries in offset order, filling the gaps
15//! between them with zeros, and the only thing that has to be worked out per entry is whether
16//! the value is a number, a run of bytes from a string literal, or the address of something the
17//! linker has to place.
18//!
19//! # Names
20//!
21//! An object with linkage is known by the name it was written with, and there is nothing to
22//! invent. A `static` inside a function has no linkage and still needs a name in the object
23//! file, so it gets `name.N`, which is what gcc does and is why two functions may each have a
24//! `static int count;` without colliding. A string literal has no name at all and gets
25//! `.Lstr.N`, whose leading dot keeps it out of the symbol table on every target that has the
26//! convention.
27
28use std::cmp::Ordering;
29use std::collections::{BTreeMap, HashMap, HashSet};
30use std::fmt;
31
32use rucc_base::{Interner, Symbol};
33use rucc_diag::{Diagnostic, Span};
34use rucc_ir::{
35 Alias, AttrSet, DataList, Datum, FpContract, Func, Global, Imm, Linkage as IrLinkage, Meta,
36 Module, Reloc, SymbolRef, TlsModel, Type, Visibility as IrVisibility,
37};
38use rucc_sema::{
39 Address, Base, Const, Conversion, DeclFlags, DeclId, DeclKind, Definition, Effects, Emission,
40 Eval, ExprId, ExprKind, InitEntry, InitList, LabelId, Linkage, Priority, StorageDuration,
41 StrId, Tast, Visibility,
42};
43use rucc_target::{ObjectFormat, TargetInfo};
44use rucc_types::{TypeId, TypeKind, Types, compatible, is_complex, is_scalar};
45
46use crate::abi::{self, Plan};
47use crate::aliasing;
48use crate::body;
49use crate::directives;
50use crate::reach;
51use crate::repr;
52
53/// Which functions get a stack protector, which is what the `-fstack-protector` family decides.
54///
55/// The question is about the locals a function has, so it is answered here and not in the back
56/// end: by the time a frame is laid out the types are gone and every local is a size and an
57/// alignment. What the back end then does about the answer is its own business, and it is carried
58/// to it as [`rucc_ir::AttrSet::STACK_PROTECT`] on the function.
59///
60/// The names are gcc's, and so are the rules. A build that has been compiled with one of these for
61/// twenty years is entitled to the same set of protected functions from a compiler claiming to be
62/// compatible, because the ones left out are the ones an exploit goes looking for.
63#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
64pub enum Protector {
65 /// None of them, which is `-fno-stack-protector` and what a command line that says nothing
66 /// gets.
67 #[default]
68 None,
69 /// A function with a local array of at least eight bytes, or one whose stack grows while it
70 /// runs. `-fstack-protector`, which is the original and the narrowest.
71 Buffers,
72 /// Any of those, and any function with a local array at all, a local holding one, or a local
73 /// whose address is taken. `-fstack-protector-strong`, which is what every distribution builds
74 /// its packages with and therefore the one a real build line carries.
75 Strong,
76 /// Every function that has a frame at all. `-fstack-protector-all`.
77 All,
78}
79
80/// What overflows rather than being undefined, which is `-fwrapv` and its relatives.
81///
82/// Every licence the walk grants the optimizer about overflow is one flag on one instruction, and
83/// withdrawing a licence is not setting it. So this is read where the flags are chosen and nowhere
84/// else, and a unit built with either of these is a unit whose IR carries less rather than a unit
85/// the passes are told something extra about. That is also what makes it correct across link time
86/// optimization: a body from a unit that wraps and a body from one that does not keep their own
87/// answers when they end up in the same module.
88///
89/// `-ftrapv` is the exception and is the reason this is not simply two flags. It is the other
90/// answer to the question `-fwrapv` answers, and it is the only one of the three that asks for
91/// something to be generated rather than for something to be left out.
92#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
93pub struct Wrapping {
94 /// Whether signed arithmetic wraps, from `-fwrapv`. Set, and an add, a subtract, a multiply, a
95 /// shift and a negation in a signed type stop saying they do not wrap.
96 pub signed: bool,
97 /// Whether pointer arithmetic wraps, from `-fwrapv-pointer`. Set, and the multiply that turns
98 /// an index into a number of bytes stops saying so.
99 ///
100 /// That multiply is the whole of it here, because the addition itself never claimed anything: a
101 /// `ptradd` carries no flags in this IR and no pass reads one off it.
102 pub pointer: bool,
103 /// Whether a signed overflow stops the program, from `-ftrapv`. Set, and an add, a subtract, a
104 /// multiply and a negation in a signed type become calls to the routine in the runtime that
105 /// does the arithmetic and checks it.
106 ///
107 /// Never set at the same time as [`Wrapping::signed`], because a program cannot both wrap and
108 /// stop. The driver is what keeps that true.
109 pub trap: bool,
110}
111
112/// Everything the walk reads, which is a checked translation unit and the target it is for.
113///
114/// The interner is mutable because the walk invents names the program never wrote: the label a
115/// string literal is emitted under, and the mangled name of a function-scope `static`.
116pub struct Context<'a> {
117 /// The typed tree.
118 pub tast: &'a Tast,
119 /// The types it points into.
120 pub types: &'a Types,
121 /// What is being compiled for, which is where every width and every alignment comes from.
122 pub target: &'a TargetInfo,
123 /// The name table.
124 pub names: &'a mut Interner,
125 /// What a name that no declaration of it said anything about gets, which is `-fvisibility=`.
126 ///
127 /// A fact about the compilation rather than about any declaration, which is why it arrives
128 /// here rather than on the tree: the checker knows what was written and this knows what the
129 /// command line asked for, and the answer is the first of those where there is one.
130 pub visibility: IrVisibility,
131 /// Which functions get a stack protector, which is `-fstack-protector` and its relatives.
132 pub protector: Protector,
133 /// What overflows rather than being undefined, which is `-fwrapv` and its relatives.
134 ///
135 /// A fact about the compilation for the same reason the two above it are: what was written is
136 /// on the tree and what was asked for is on the command line.
137 pub wrapping: Wrapping,
138 /// Whether an access carries the node for the type it goes through, which is
139 /// `-fstrict-aliasing` and is on unless `-fno-strict-aliasing` cleared it.
140 ///
141 /// Clearing it here rather than in the optimizer is what makes the flag one condition in one
142 /// place: an access with no node conflicts with every other access, so a unit built with the
143 /// flag off is a unit whose IR says less rather than a unit the passes are told something
144 /// extra about. That is also what keeps it right across link time optimization, the way
145 /// [`Context::wrapping`] is: a body from a unit that named its types and a body from one that
146 /// did not keep their own answers when they end up in the same module.
147 pub aliasing: bool,
148 /// Whether an access says how far the padding after it reaches, which is
149 /// `-fsafety-init=nopadding` and is what a build with no safety tier gets too, since nothing
150 /// reads the number then.
151 ///
152 /// Here rather than in the safety pass for the reason [`Context::aliasing`] is here: what the
153 /// number is takes a record's layout, and the layout is a thing the walk has in hand and the
154 /// pass over the IR does not. The pass reads it and does not decide anything, which keeps the
155 /// flag one condition in one place and keeps it right across link time optimization.
156 pub padding: bool,
157 /// How far a multiply and an addition may be fused into one rounding, which is
158 /// `-ffp-contract=`.
159 ///
160 /// A fact about the compilation like the ones above it, and the one of them that is written
161 /// down rather than acted on: it goes onto every function with a body as
162 /// [`rucc_ir::Attrs::fp_contract`], because the place that would fuse anything is the code
163 /// generator and by the time it runs the command line is gone and the two operations it might
164 /// fuse may have come from different statements.
165 pub contract: FpContract,
166 /// What every function in the unit is aligned to unless it asked for more itself, which is
167 /// `-falign-functions` and is `None` for the alignment the target gives anyway.
168 ///
169 /// A fact about the compilation like the ones above it, and it meets a fact about a
170 /// declaration here rather than further down: `__attribute__((aligned(N)))` is a statement
171 /// about one function and this is a preference about all of them, so the function takes the
172 /// larger of the two and everything below reads one number.
173 pub align: Option<u32>,
174 /// How a file named by a `.incbin` in an `asm` at file scope is read, given the name as the
175 /// template wrote it and handing back either the bytes or what went wrong.
176 ///
177 /// Passed in rather than reached for, because the walk has no business opening files and
178 /// because a caller that put its sources somewhere other than a disk has put this file there
179 /// too. The name is resolved the way an assembler resolves it, which is against the directory
180 /// the compiler was run in and not against the directory the source was found in.
181 pub read: &'a mut dyn FnMut(&str) -> Result<Vec<u8>, String>,
182}
183
184// Written out rather than derived because a closure has no `Debug`, and printing one would say
185// nothing anyway. What is worth reading here is the settings, so those are what this prints.
186impl fmt::Debug for Context<'_> {
187 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
188 f.debug_struct("Context")
189 .field("visibility", &self.visibility)
190 .field("protector", &self.protector)
191 .field("wrapping", &self.wrapping)
192 .field("aliasing", &self.aliasing)
193 .field("padding", &self.padding)
194 .field("contract", &self.contract)
195 .field("align", &self.align)
196 .finish_non_exhaustive()
197 }
198}
199
200/// One function that runs without anything calling it, waiting for the section it goes in.
201///
202/// Held back rather than written where the definition is met, because the order they go in is not
203/// always the order the file defined them: a format with one section for all of them is a format
204/// where the only record of the priority is the position in that section, so they have to be
205/// sorted, and sorting means having all of them.
206#[derive(Debug, Clone, Copy)]
207struct Start {
208 /// The function the entry is the address of.
209 func: Symbol,
210 /// Whether it runs in the run-up to `main` rather than in the run-down after it.
211 before: bool,
212 /// Where in the order the attribute asked for it to go.
213 priority: Priority,
214 /// The definition it came from, for the diagnostic a format with no way to say it needs.
215 span: Span,
216}
217
218impl Start {
219 /// Where this goes among the others, which is the order the entries are written in.
220 ///
221 /// A lower number first, and the unnumbered ones after every numbered one, which is the order
222 /// an ELF linker puts the sections in and therefore the order every format has to come out in
223 /// for the three of them to agree. The sort is stable, so two at the same priority stay in the
224 /// order the file defined them, which is all that decides between them.
225 fn order(&self) -> (u8, u16) {
226 match self.priority {
227 Priority::Numbered(number) => (0, number),
228 Priority::Unnumbered => (1, 0),
229 }
230 }
231}
232
233/// What the walk produced.
234#[derive(Debug)]
235pub struct Lowered {
236 /// The module, which is complete even when something was reported: a construct that is not
237 /// supported yet leaves the rest of the function around it intact.
238 pub module: Module,
239 /// What was reported, in the order it was found.
240 pub diagnostics: Vec<Diagnostic>,
241}
242
243/// Walks a checked translation unit and builds the IR for it.
244///
245/// `name` is the module's name, which is the file the tree came from.
246#[must_use]
247pub fn lower(name: &str, cx: Context<'_>) -> Lowered {
248 let Context {
249 tast,
250 types,
251 target,
252 names,
253 visibility,
254 protector,
255 wrapping,
256 aliasing,
257 padding,
258 contract,
259 align,
260 read,
261 } = cx;
262 let module = Module::new(names.intern(name), target);
263 let mut unit = Unit {
264 tast,
265 types,
266 target,
267 names,
268 visibility,
269 protector,
270 wrapping,
271 aliasing,
272 padding,
273 cliques: 0,
274 tree: aliasing::Tree::default(),
275 contract,
276 align,
277 read,
278 module,
279 diagnostics: Vec::new(),
280 strings: HashMap::new(),
281 anonymous: 0,
282 statics: HashMap::new(),
283 labels: HashMap::new(),
284 done: HashSet::new(),
285 aliases: Vec::new(),
286 sets: Vec::new(),
287 aliased: HashSet::new(),
288 starts: Vec::new(),
289 renamed: HashMap::new(),
290 reachable: reach::reachable(tast),
291 };
292 unit.run();
293 Lowered { module: unit.module, diagnostics: unit.diagnostics }
294}
295
296/// The walk over one translation unit, and everything it has built so far.
297pub(crate) struct Unit<'a> {
298 pub(crate) tast: &'a Tast,
299 pub(crate) types: &'a Types,
300 pub(crate) target: &'a TargetInfo,
301 pub(crate) names: &'a mut Interner,
302 /// What a name no declaration said anything about gets. See [`Context::visibility`].
303 visibility: IrVisibility,
304 /// Which functions get a stack protector. See [`Context::protector`].
305 pub(crate) protector: Protector,
306 /// What wraps rather than being undefined. See [`Context::wrapping`].
307 pub(crate) wrapping: Wrapping,
308 /// Whether an access names the type it goes through. See [`Context::aliasing`].
309 aliasing: bool,
310 /// Whether an access says how far the padding after it reaches. See [`Context::padding`].
311 pub(crate) padding: bool,
312 /// How many `restrict` scopes have been handed out, which is a number the whole module shares
313 /// so that no two functions promise different things with the same one. See
314 /// [`restrict`](mod@crate::restrict) for why that matters before there is an inliner.
315 pub(crate) cliques: u16,
316 /// The type based aliasing tree built so far, which is one per module.
317 tree: aliasing::Tree,
318 /// How far a multiply and an addition may be fused. See [`Context::contract`].
319 pub(crate) contract: FpContract,
320 /// What every function is aligned to unless it asked for more. See [`Context::align`].
321 align: Option<u32>,
322 /// How a file a `.incbin` names is read. See [`Context::read`].
323 read: &'a mut dyn FnMut(&str) -> Result<Vec<u8>, String>,
324 pub(crate) module: Module,
325 pub(crate) diagnostics: Vec<Diagnostic>,
326 /// The global each string literal was emitted as, so that two mentions of one literal are
327 /// one object.
328 strings: HashMap<StrId, Symbol>,
329 /// How many runs of bytes written under no label in an `asm` at file scope have been given a
330 /// name, which is what keeps the next one from being given the same one.
331 anonymous: usize,
332 /// The name each object with no linkage was given.
333 statics: HashMap<DeclId, Symbol>,
334 /// The name each label an image holds the address of was given.
335 ///
336 /// A label is a place inside a function and has no name in the object file, because a jump to
337 /// one is a distance the assembler works out and never a symbol. An image is the one thing
338 /// that cannot do that: it is in another section, so what it holds is a relocation, and a
339 /// relocation names a symbol. So a label an image points at gets one, minted here because the
340 /// image is lowered before the body is walked and the block the label starts does not exist
341 /// yet when the name is first asked for.
342 labels: HashMap<LabelId, Symbol>,
343 /// What has been emitted, because a redeclaration is the same declaration seen twice.
344 done: HashSet<DeclId>,
345 /// The declarations that are a second name for something rather than a thing of their own,
346 /// in the order the file made them.
347 ///
348 /// Held back rather than emitted where they are met, because what an alias points at may be
349 /// written below it and whether anything defines it is a question only the whole file
350 /// answers.
351 aliases: Vec<DeclId>,
352 /// The names a `.set` in an `asm` at file scope gave to something else, with the block each
353 /// one was written in, in the order the file wrote them.
354 ///
355 /// Held back for the reason above and written out beside the aliases, since the two are the
356 /// same thing said two ways: a second symbol at an address this object already has.
357 sets: Vec<(directives::Set, Span)>,
358 /// The symbols something in the file is a second name for.
359 ///
360 /// A `static` function nothing calls is not emitted, and being what an alias points at is a
361 /// reason to emit one that no reference in the file says: the string an alias names is not a
362 /// use of anything as far as the walk over the tree is concerned.
363 aliased: HashSet<Symbol>,
364 /// The functions the file asked to have run without anything calling them, in the order it
365 /// defined them.
366 ///
367 /// Held back rather than emitted where they are met, because the entries go in the order the
368 /// priorities put them and a function written at the top of the file may have asked to run
369 /// last. Only the whole file settles that order.
370 starts: Vec<Start>,
371 /// The assembler name the file gave to a name with linkage, kept by the name that was
372 /// written rather than by the declaration that wrote it.
373 ///
374 /// For [`Unit::library_name`], which knows what the C library calls a function and not what
375 /// this file has said about it. The declaration that renames `memcpy` is a different
376 /// declaration from the implicit one the checker made for `__builtin_memcpy`, so the label
377 /// on the first is never reached from the second, and a program that renames a function and
378 /// then calls the builtin means the call to go to the new name.
379 renamed: HashMap<Symbol, Symbol>,
380 /// What something in the file reaches, which is what decides whether a function with
381 /// internal linkage is emitted at all.
382 reachable: HashSet<DeclId>,
383}
384
385// The debug is by hand and short: a translation unit is not something anybody wants printed as
386// a `{:?}`, and the module has a printer of its own for when they do.
387impl fmt::Debug for Unit<'_> {
388 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
389 f.debug_struct("Unit")
390 .field("module", &self.module.counts())
391 .field("diagnostics", &self.diagnostics.len())
392 .finish()
393 }
394}
395
396impl Unit<'_> {
397 /// The aliasing node an access through `ty` carries, and [`None`] when it carries none.
398 ///
399 /// [`None`] is also every answer under `-fno-strict-aliasing`, which is the whole of what that
400 /// flag does here. See [`aliasing`](mod@crate::aliasing) for which types have a node.
401 pub(crate) fn alias_node(&mut self, ty: TypeId) -> Option<Meta> {
402 if !self.aliasing {
403 return None;
404 }
405 self.tree.node(&mut self.module, self.names, self.types, ty)
406 }
407
408 /// The root of the aliasing tree, which is the node an access that may be punned carries.
409 ///
410 /// The root is `char` and it conflicts with everything, so an access carrying it is an access
411 /// nothing may be reordered across and, in the type plane, a byte nothing has settled the type
412 /// of. `crate::body` says which accesses those are.
413 pub(crate) fn alias_root(&mut self) -> Option<Meta> {
414 if !self.aliasing {
415 return None;
416 }
417 Some(self.tree.root(&mut self.module, self.names))
418 }
419
420 /// Every declaration the file made, in the order it made them.
421 fn run(&mut self) {
422 self.file_asms();
423 self.find_aliased();
424 self.find_renamed();
425 for index in 0..self.tast.top_level().len() {
426 let decl = self.tast.top_level()[index];
427 if !self.done.insert(decl) {
428 continue;
429 }
430 match self.tast[decl].kind {
431 DeclKind::Function => self.function(decl),
432 DeclKind::Object => self.object(decl),
433 // A name for a type is only in the tree at block scope and nothing is emitted
434 // for one.
435 DeclKind::Type => {}
436 }
437 }
438 for index in 0..self.aliases.len() {
439 self.alias(self.aliases[index]);
440 }
441 for index in 0..self.sets.len() {
442 let (set, span) = self.sets[index].clone();
443 self.equated(&set, span);
444 }
445 self.startups();
446 }
447
448 /// The `asm` written at file scope, read into the globals they define.
449 ///
450 /// Ahead of the declarations rather than among them. A block usually names more than one
451 /// thing and means them to be next to each other, the object writer lays globals out in the
452 /// order the module holds them, and adding a block's globals together is what makes them a
453 /// run. A declaration of one of those names below the block then finds a definition already
454 /// there and leaves it alone, which is the division the program wrote: the template says what
455 /// the bytes are and the C declaration says what they are to be read as.
456 fn file_asms(&mut self) {
457 for index in 0..self.tast.file_asms().len() {
458 let asm = self.tast.file_asms()[index];
459 let template = self.spelled(asm.template);
460 let read = match directives::assemble(&template, &mut *self.read) {
461 Ok(read) => read,
462 Err(directives::Failed::Unsupported(what)) => {
463 self.unsupported(&format!("{what} in an `asm` at file scope"), asm.span);
464 continue;
465 }
466 Err(directives::Failed::Missing(name, why)) => {
467 let message = format!("cannot open '{name}' for reading: {why}");
468 self.diagnostics.push(Diagnostic::error(message, asm.span).with_code("E0702"));
469 continue;
470 }
471 };
472 // The name of every global of the block first, because a distance one of them writes
473 // is measured to a place in another of them and a relocation names a symbol, so the
474 // name has to be to hand before the bytes that refer to it are built.
475 let symbols: Vec<Symbol> = read
476 .pieces
477 .iter()
478 .map(|piece| match &piece.name {
479 Some(name) => self.names.intern(name),
480 None => {
481 let name = format!(".Lasm.{}", self.anonymous);
482 self.anonymous += 1;
483 self.names.intern(&name)
484 }
485 })
486 .collect();
487 for (index, piece) in read.pieces.into_iter().enumerate() {
488 self.piece(piece, symbols[index], &symbols);
489 }
490 // Held back until the file has been walked, because a name a block equates may be
491 // defined below the block, and remembered as a name something points at, because a
492 // `static` function an equate is the only reference to is one that has to be emitted.
493 for set in read.sets {
494 let target = self.names.intern(&set.target);
495 self.aliased.insert(target);
496 self.sets.push((set, asm.span));
497 }
498 }
499 }
500
501 /// One global an `asm` at file scope defined, under the name minted for it and with the names
502 /// of the whole block to hand.
503 ///
504 /// The bytes a template writes before it writes any label are a global like the rest and a
505 /// global has to have a name, so one is minted for them. Nothing refers to it by that name, so
506 /// the only thing it has to be is one nothing else takes, and the leading dot keeps it out of
507 /// the symbol table the way the name of a string literal does.
508 fn piece(&mut self, piece: directives::Piece, symbol: Symbol, symbols: &[Symbol]) {
509 let mut global = Global::new(symbol, piece.size, piece.align.max(1));
510 global.linkage = piece.linkage;
511 global.visibility = piece.visibility;
512 let bss = matches!(piece.section, directives::Section::Bss);
513 match piece.section {
514 // Which of the sections the object writer has an answer of its own for. Asking for
515 // `.rodata` by name would produce a second section with that spelling and with the
516 // flags of a writable one, so what is said here is what the global is instead.
517 directives::Section::ReadOnly => global.constant = true,
518 directives::Section::Data | directives::Section::Bss => {}
519 directives::Section::Named(name) => global.section = Some(self.names.intern(&name)),
520 // Refused where the template was read, since what goes in that section is
521 // instructions and there is nothing here that makes one.
522 directives::Section::Text => return,
523 }
524 let mut data = Vec::with_capacity(piece.items.len());
525 if piece.items.is_empty() && bss {
526 // A label at the end of the zero filled section, which has nothing under it and
527 // still has to land there rather than in the section of written bytes. An image of
528 // no zeros is what says so, since being all zeros is how a global asks for that
529 // section and an empty image asks for nothing.
530 data.push(Datum::Zero(0));
531 }
532 for item in piece.items {
533 data.push(match item {
534 directives::Item::Bytes(bytes) => Datum::Bytes(self.module.push_bytes(&bytes)),
535 directives::Item::Int { width, value } => {
536 let ty = Type::int(u32::from(width) * 8);
537 Datum::Scalar {
538 ty,
539 value: self.module.add_imm(Imm::int(i128::from(value), ty)),
540 }
541 }
542 directives::Item::Zero(bytes) => Datum::Zero(bytes),
543 // Four bytes holding how far that global is from these bytes, which the reader
544 // said in globals of this block rather than in names because the place it
545 // measures to is usually a label the object file holds no name for.
546 directives::Item::Away { piece, addend } => {
547 let reloc = Reloc { symbol: symbols[piece], addend, size: 4 };
548 Datum::Away(self.module.add_reloc(reloc))
549 }
550 });
551 }
552 global.init = Some(self.module.push_data(&data));
553 self.place_global(global);
554 }
555
556 /// Which symbols the file gives a second name to, before anything is emitted.
557 ///
558 /// Ahead of the walk rather than during it, because a `static` function is emitted or not on
559 /// the strength of what reaches it and the alias that reaches one may be written below it.
560 fn find_aliased(&mut self) {
561 for index in 0..self.tast.top_level().len() {
562 let decl = self.tast.top_level()[index];
563 let Some(target) = self.tast[decl].alias else { continue };
564 let spelling = self.spelled(target);
565 let symbol = self.names.intern(&spelling);
566 self.aliased.insert(symbol);
567 }
568 }
569
570 /// Which names the file gave an assembler name of their own, before anything is emitted.
571 ///
572 /// Ahead of the walk for the reason [`Unit::find_aliased`] is: the call to
573 /// `__builtin_memcpy` may be written above the declaration of `memcpy` that renames it, and
574 /// the two spellings are one function.
575 fn find_renamed(&mut self) {
576 for index in 0..self.tast.top_level().len() {
577 let decl = self.tast.top_level()[index];
578 let node = &self.tast[decl];
579 let (linkage, name, label) = (node.linkage, node.name, node.asm_label);
580 if linkage == Linkage::None {
581 continue;
582 }
583 let (Some(name), Some(label)) = (name, label) else { continue };
584 let spelling = self.spelled(label);
585 let symbol = self.names.intern(&spelling);
586 self.renamed.insert(name, symbol);
587 }
588 }
589
590 /// The bytes of a string literal as a name, which is what a symbol in an attribute is.
591 fn spelled(&self, id: StrId) -> String {
592 self.tast[id].elements.iter().filter_map(|&unit| char::from_u32(unit)).collect()
593 }
594
595 /// One object with static storage duration.
596 fn object(&mut self, decl: DeclId) {
597 let tast = self.tast;
598 let node = &tast[decl];
599 let (ty, state, init) = (node.ty, node.state, node.init);
600 let (linkage, duration, alignment) = (node.linkage, node.duration, node.alignment);
601 let span = tast.decl_span(decl);
602 if duration == StorageDuration::Automatic {
603 // A block-scope object with automatic storage is a slot or a value in the function
604 // that declares it, and the body is what makes it. Nothing is emitted here.
605 return;
606 }
607 // A second name for something else is not an object of its own, so nothing is laid out
608 // and no image is built. It is held back until the rest of the file has been walked,
609 // because what it points at may be below it.
610 if node.alias.is_some() {
611 self.aliases.push(decl);
612 return;
613 }
614
615 let symbol = self.symbol_of(decl);
616 let size = repr::size_of(self.types, self.target, ty);
617 let align = alignment.unwrap_or_else(|| repr::align_of(self.types, self.target, ty));
618 let mut global = Global::new(symbol, size, align);
619 global.linkage = self.told(decl, linkage);
620 // A tentative definition counts as one, because it is one: `int x;` at file scope puts a
621 // symbol in this object and the linker never has to look anywhere else for it.
622 global.visibility = self.seen(decl, state != Definition::Declared);
623 global.tls = (duration == StorageDuration::Thread).then_some(TlsModel::GlobalDynamic);
624 global.constant = repr::is_read_only(self.types, ty);
625 global.init = match state {
626 // `extern int x;` and nothing else names an object another translation unit
627 // defines. The global is here so that a reference to it has something to resolve
628 // against, and it has no image, which is what makes it a declaration.
629 Definition::Declared => None,
630 Definition::Tentative => Some(self.zeros(size)),
631 Definition::Defined => {
632 let (data, covered) = self.image(init, size, span);
633 // The object is as large as its image when the image is the larger of the two.
634 // A structure whose last member is a flexible array is the only way that
635 // happens: `sizeof` answers without the array and an initializer that fills it
636 // makes an object big enough to hold what was written. C 6.7.2.1p18 leaves the
637 // size to the implementation, gcc grows the object, and this does the same
638 // rather than hand the linker a size the image does not fit in.
639 global.size = size.max(covered);
640 Some(data)
641 }
642 };
643 self.place_global(global);
644 }
645
646 /// One function, with its body when it has one.
647 fn function(&mut self, decl: DeclId) {
648 let tast = self.tast;
649 let node = &tast[decl];
650 let (ty, linkage, body, align) = (node.ty, node.linkage, node.body, node.alignment);
651 let noreturn = node.flags.contains(DeclFlags::NORETURN);
652 let naked = node.flags.contains(DeclFlags::NAKED);
653 let effects = node.effects;
654 let startup = node.startup;
655 let span = tast.decl_span(decl);
656 if node.name.is_none() {
657 return;
658 }
659 // The same as for an object: a second name is not a function of its own, and it is held
660 // back until what it points at has been emitted.
661 if node.alias.is_some() {
662 self.aliases.push(decl);
663 return;
664 }
665 // Which asks the one question the reference to it asks, so that a declaration that
666 // renamed the symbol renames the definition as well and the two still meet.
667 let name = self.symbol_of(decl);
668 if self.is_dropped(decl, name) {
669 return;
670 }
671 let Some(plan) = self.plan(ty, &[], span) else { return };
672
673 let mut func = Func::new(name, plan.signature.clone());
674 // The name the source spelled, where an assembler name says the symbol is not it. A
675 // declaration of `strstr` renamed to `my_strstr` is a declaration of `strstr` still, and
676 // once the symbol is the only name left there is nothing to find that out again from.
677 if node.asm_label.is_some() {
678 func.spelled = node.name.filter(|&spelled| spelled != name);
679 }
680 // Where the body begins, which is the line a debugger names over the prologue. gcc says the
681 // line the opening brace is on rather than the line the declarator is on, and the two
682 // differ in the style that puts the brace underneath. No instruction in a prologue has a
683 // span of its own, so this is the only place the fact can come from. A declaration has no
684 // body and produces no prologue, so it falls back to the declarator and nothing reads it.
685 func.declared = body.map_or(span, |body| tast.stmt_span(body));
686 // The larger of what this function asked for and what the command line asked of all of
687 // them, since the attribute is a requirement and the flag is a preference, and a
688 // preference does not get to move a function off a boundary its own source named.
689 func.align = match (align, self.align) {
690 (Some(mine), Some(everyones)) => Some(mine.max(everyones)),
691 (mine, everyones) => mine.or(everyones),
692 };
693 // The one thing a declaration says that nobody downstream can work out for themselves.
694 // What `abort` does belongs to `abort`, and a translation unit that only declares it has
695 // nothing to look at, so the claim has to travel on the declaration or not at all.
696 if noreturn {
697 func.attrs.set |= AttrSet::NORETURN;
698 }
699 // Which is not a claim about what a call to it does but a fact about how the function
700 // itself is written, so unlike the two around it there is nothing here for a declaration
701 // alone to be useful for. It travels the same way because the attribute is written in the
702 // same places. See [`rucc_codegen`] for what reads it, which is the frame.
703 if naked {
704 func.attrs.set |= AttrSet::NAKED;
705 }
706 // And the other one, for the same reason. What a call to `strtol` reads belongs to
707 // `strtol`, and the purity analysis answers opaque for everything it cannot see a body
708 // for, so a unit that only declares the function gets nothing out of it unless the
709 // promise arrives here. `const` says the result comes from the arguments alone, which
710 // is `readnone`, and `pure` says it may read memory, which is `readonly`. The two are
711 // an incompatible pair in the IR and only one of them is ever set.
712 func.attrs.set |= match effects {
713 Effects::Any => AttrSet::NONE,
714 Effects::Pure => AttrSet::READONLY,
715 Effects::Const => AttrSet::READNONE,
716 };
717 // An inline definition this unit calls, which this unit has to put a copy of out of line
718 // because it has no inliner to make the call go away. See [`Self::out_of_line`].
719 let copied = body.is_some() && self.out_of_line(decl, node.inline);
720 func.linkage = if copied { IrLinkage::LinkOnce } else { self.told(decl, linkage) };
721 // The same question as for an object, and the same answer, with one wrinkle: an inline
722 // definition this unit neither emits nor calls is a declaration here, since C 6.7.4p7
723 // sends the calls to whatever unit holds the external definition, so it is not this
724 // file's to describe. That is the condition the body is lowered under, a few lines below.
725 func.visibility = self.seen(decl, body.is_some() && (node.inline.emits() || copied));
726 // An inline definition is not an external definition, so what goes in the module is the
727 // declaration and not the body. C 6.7.4p7 says the calls in this unit go to the definition
728 // some other unit holds, which is what the declaration gives them, and glibc's headers
729 // rely on it: every one of their inline definitions would otherwise be a second definition
730 // of a name the library already defines. Unless this unit is one of the callers, which is
731 // the case [`Self::out_of_line`] is about.
732 if body.is_some() && (node.inline.emits() || copied) {
733 body::lower(self, decl, &mut func, &plan);
734 // Only for a definition, because an entry is an address and a declaration of something
735 // another file defines has none to put there. gcc reads the attribute off whichever
736 // declaration carried it and then waits for the definition in the same way, which is
737 // why writing `__attribute__((constructor)) void f(void);` in a header costs every
738 // file that includes it nothing.
739 if let Some(priority) = startup.before {
740 self.starts.push(Start { func: name, before: true, priority, span });
741 }
742 if let Some(priority) = startup.after {
743 self.starts.push(Start { func: name, before: false, priority, span });
744 }
745 }
746 self.place_func(func);
747 }
748
749 /// Puts a function in the module under a name something may already be under.
750 ///
751 /// Two declarations of one identifier were merged before this, so the only way one name
752 /// arrives twice is an assembler name that renames one identifier onto another: a
753 /// declaration of `f` renamed to `g` beside a definition of `g` is one symbol written two
754 /// ways, which is what the program asked for and what the linker is going to see. The
755 /// definition wins wherever there is one, since what the declaration is here for is to give
756 /// the calls something to resolve against and the definition does that as well.
757 ///
758 /// A name already carrying a definition keeps it. That is the program defining one symbol
759 /// twice, and the assembler says so with the name in front of it, which is a better message
760 /// than anything available here.
761 fn place_func(&mut self, func: Func) {
762 match self.module.lookup(func.name) {
763 None => {
764 self.module.add_func(func);
765 }
766 Some(SymbolRef::Func(id))
767 if self.module[id].is_declaration() && !func.is_declaration() =>
768 {
769 self.module[id] = func;
770 }
771 Some(_) => {}
772 }
773 }
774
775 /// One declaration that is a second name for something the same file defines.
776 ///
777 /// Emitted after everything else, so the target is looked up in a module that already holds
778 /// whatever the file defines whether it was written above the alias or below it.
779 ///
780 /// The target has to be defined here and not merely declared, which is gcc's rule and is
781 /// what the object format can express: an alias is a symbol at another symbol's address, and
782 /// a name this file does not define has no address for one to be at. A program that writes
783 /// an alias of something in another object wants a reference rather than a definition, and
784 /// what it gets from gcc is this same error rather than a name the linker cannot resolve.
785 fn alias(&mut self, decl: DeclId) {
786 let Some(written) = self.tast[decl].alias else { return };
787 let span = self.tast.decl_span(decl);
788 let name = self.symbol_of(decl);
789 let spelling = self.spelled(written);
790 let target = self.names.intern(&spelling);
791 if self.no_address(name, target, span) {
792 return;
793 }
794 // Something already under this name, which is the program defining one symbol twice. The
795 // definition that is there stands, the way it does for a function and for an object.
796 if self.module.lookup(name).is_some() {
797 return;
798 }
799 let mut alias = Alias::new(name, target);
800 alias.linkage = self.told(decl, self.tast[decl].linkage);
801 // Its own answer, because the attribute is written on the alias and an alias is a symbol
802 // of its own. `weak, alias, visibility("hidden")` is a name a library keeps to itself
803 // while the thing it points at stays exported, which is how glibc writes half of them.
804 // Always a definition. An alias is a symbol this object puts at an address in this object,
805 // and one whose target is merely declared was refused a few lines above.
806 alias.visibility = self.seen(decl, true);
807 self.module.add_alias(alias);
808 }
809
810 /// One name a `.set` in an `asm` at file scope gave to something else.
811 ///
812 /// The same thing as the alias above it and written out the same way, with the two answers
813 /// about the name coming from the directives around the `.set` rather than from an attribute:
814 /// `.globl` and `.weak` say how the linker sees it, `.hidden` and `.protected` say how far it
815 /// reaches, and a name no directive spoke about is local, which is what an assembler does with
816 /// one. A name the file also defines keeps its own definition, which is the rule everything
817 /// else here follows and is what gcc's output shows for a `.set` written above a definition of
818 /// the same name.
819 fn equated(&mut self, set: &directives::Set, span: Span) {
820 let name = self.names.intern(&set.name);
821 let target = self.names.intern(&set.target);
822 if self.no_address(name, target, span) {
823 return;
824 }
825 if self.module.lookup(name).is_some() {
826 return;
827 }
828 let mut alias = Alias::new(name, target);
829 alias.linkage = set.linkage;
830 alias.visibility = set.visibility;
831 self.module.add_alias(alias);
832 }
833
834 /// Whether there is no address for a second name to be at, reporting why when there is not.
835 ///
836 /// The target has to be defined here and not merely declared, because an alias is a symbol at
837 /// another symbol's address and a name this file does not define has no address in it. A
838 /// program that writes one of these about something in another object wants a reference rather
839 /// than a definition, and gcc turns that down as well.
840 fn no_address(&mut self, name: Symbol, target: Symbol, span: Span) -> bool {
841 let spelled = self.names.resolve(name).to_owned();
842 if name == target {
843 let what = format!("'{spelled}' is aliased to itself");
844 self.diagnostics.push(Diagnostic::error(what, span).with_code("E0697"));
845 return true;
846 }
847 let defined = match self.module.lookup(target) {
848 Some(SymbolRef::Func(id)) => !self.module[id].is_declaration(),
849 Some(SymbolRef::Global(id)) => self.module[id].init.is_some(),
850 // A chain of them is a thing gcc takes and this does not yet, because resolving one
851 // wants the aliases put in an order that the file they were written in need not be
852 // in. It is reported rather than written out as a name pointing at a name.
853 Some(SymbolRef::Alias(_)) | None => false,
854 };
855 if !defined {
856 let spelling = self.names.resolve(target).to_owned();
857 let what = format!("'{spelled}' is aliased to undefined symbol '{spelling}'");
858 let note = "the target of an alias has to be defined in this same file, since an \
859 alias is a second name for an address and not a reference to one";
860 let refused = Diagnostic::error(what, span).with_code("E0697");
861 self.diagnostics.push(refused.note(note, span));
862 return true;
863 }
864 false
865 }
866
867 /// The list of functions to run around `main`, written out as the entries that run them.
868 ///
869 /// In priority order rather than in the order the file defined them, because two of the three
870 /// formats get their order from the order the entries are in and only ELF sorts anything at
871 /// link time.
872 fn startups(&mut self) {
873 let mut starts = std::mem::take(&mut self.starts);
874 starts.sort_by_key(Start::order);
875 for start in starts {
876 self.start_entry(&start);
877 }
878 }
879
880 /// One entry, which is a pointer wide object in the section the format runs.
881 ///
882 /// A relocation against the function rather than a value, since the address is not known until
883 /// the link. The object has internal linkage and a name nothing refers to: the only thing that
884 /// reads it is the CRT walking the section, which finds it by where it is and not by what it is
885 /// called. gcc emits no symbol at all for one, and a name with a dot in it is the nearest thing
886 /// to that here, being one no C program can write and therefore one no program collides with.
887 fn start_entry(&mut self, start: &Start) {
888 let Some(section) = self.start_section(start) else {
889 self.no_start(start);
890 return;
891 };
892 let size = u64::from(self.target.pointer_width / 8);
893 let align = u32::try_from(size).unwrap_or(1);
894 let called = self.names.resolve(start.func).to_owned();
895 let which = if start.before { "ctor" } else { "dtor" };
896 let name = self.names.intern(&format!("__rucc_{which}.{called}"));
897 let section = self.names.intern(§ion);
898 let mut global = Global::new(name, size, align);
899 global.linkage = IrLinkage::Internal;
900 global.section = Some(section);
901 let size = u32::try_from(size).unwrap_or(0);
902 let reloc = self.module.add_reloc(Reloc { symbol: start.func, addend: 0, size });
903 global.init = Some(self.module.push_data(&[Datum::Addr(reloc)]));
904 self.place_global(global);
905 }
906
907 /// The section an entry goes in, and [`None`] for a format with no way to ask for one.
908 ///
909 /// ELF has both halves and the linker sorts the numbered sections ahead of the plain one, so
910 /// the number goes in the name and the order comes out right however the files were linked.
911 ///
912 /// COFF has the run-up only. The name is sorted by what follows the `$` and the CRT walks
913 /// everything between the `.CRT$XCA` and `.CRT$XCZ` markers, so a numbered entry goes just
914 /// after the first marker and an unnumbered one at `U`, which keeps the numbered ones first.
915 ///
916 /// Mach-O has the run-up only as well, and it has no sorting at all: the entries run in the
917 /// order the section holds them, which is the order [`Self::startups`] put them in.
918 fn start_section(&self, start: &Start) -> Option<String> {
919 match self.target.object_format {
920 ObjectFormat::Elf => {
921 let base = if start.before { ".init_array" } else { ".fini_array" };
922 Some(match start.priority {
923 Priority::Numbered(number) => format!("{base}.{number:05}"),
924 Priority::Unnumbered => base.to_owned(),
925 })
926 }
927 ObjectFormat::Coff if start.before => Some(match start.priority {
928 Priority::Numbered(number) => format!(".CRT$XCA{number:05}"),
929 Priority::Unnumbered => ".CRT$XCU".to_owned(),
930 }),
931 ObjectFormat::MachO if start.before => {
932 Some("__DATA,__mod_init_func,mod_init_funcs".to_owned())
933 }
934 ObjectFormat::Coff | ObjectFormat::MachO | ObjectFormat::Wasm => None,
935 }
936 }
937
938 /// Reports an attribute this format has nowhere to put.
939 ///
940 /// Refused rather than dropped, because the whole point of the attribute is that something
941 /// else calls the function and a program that quietly does not get its call has no way of
942 /// noticing until whatever the function set up is missing.
943 ///
944 /// The run-down is what is missing on the two formats that have a run-up. Mach-O used to have
945 /// a terminator list and dyld stopped running it, so clang registers the call with
946 /// `__cxa_atexit` from a constructor it writes for the purpose, and nothing in the CRT a COFF
947 /// target links against has been confirmed to walk one either. Doing the same here is a
948 /// feature rather than a section name, which is why this is a message and not a branch above.
949 fn no_start(&mut self, start: &Start) {
950 let which = if start.before { "constructor" } else { "destructor" };
951 let format = self.target.object_format.as_str();
952 let what = format!("the '{which}' attribute on a {format} target");
953 self.unsupported(&what, start.span);
954 }
955
956 /// How far a name reaches outside a shared library, which is what a declaration of it said
957 /// where one said anything and what the command line asked for where none did.
958 ///
959 /// gcc's `-fvisibility=` is written as the default rather than as an override, so the
960 /// attribute wins wherever it was written, and that is the whole reason a library compiled
961 /// with `-fvisibility=hidden` can still export the dozen names it means to export.
962 ///
963 /// The default reaches what this unit defines and stops there, which is the `defined`
964 /// argument and is the whole of tamnd/rucc#1234. `-fvisibility=hidden` is a claim about the
965 /// names this file puts into the library, and a name it only mentions is one it knows nothing
966 /// about: `stderr` is in libc however the file that reads it was compiled, and calling it
967 /// hidden tells the linker to resolve it inside this object, which it cannot do. The attribute
968 /// on a declaration is a different thing and still counts, because a program that writes it
969 /// has said where the definition is going to come from.
970 ///
971 /// Measured against gcc 16.2.0 rather than read off the manual, since the manual says the flag
972 /// applies to declarations and does not say which ones. For `extern int plain;` beside
973 /// `__attribute__((visibility("hidden"))) extern int marked;` at `-fPIC -fvisibility=hidden`,
974 /// gcc writes `plain` as `GLOBAL DEFAULT UND` and reaches it through the global offset table,
975 /// and writes `marked` as `GLOBAL HIDDEN UND` and reaches it from the instruction pointer.
976 fn seen(&self, decl: DeclId, defined: bool) -> IrVisibility {
977 match self.tast[decl].visibility {
978 Some(Visibility::Default) => IrVisibility::Default,
979 Some(Visibility::Hidden) => IrVisibility::Hidden,
980 Some(Visibility::Protected) => IrVisibility::Protected,
981 None if defined => self.visibility,
982 None => IrVisibility::Default,
983 }
984 }
985
986 /// What the linker is told about a name, which is its C linkage unless a declaration of it
987 /// wrote `weak`.
988 ///
989 /// The attribute is refused on internal linkage where it is read, so external is the only
990 /// thing it can change, and the two things a program means by it are one thing to the linker.
991 /// On a definition it says another object's definition of the name beats this one, which is
992 /// how a library ships a default. On a reference to something this file does not define it
993 /// says the link may leave the name undefined and hand the reference a zero address, which is
994 /// how a library offers a hook and why zstd's thirty files link at all.
995 fn told(&self, decl: DeclId, linkage: Linkage) -> IrLinkage {
996 match linkage {
997 Linkage::External if self.tast[decl].flags.contains(DeclFlags::WEAK) => IrLinkage::Weak,
998 Linkage::External => IrLinkage::External,
999 Linkage::Internal | Linkage::None => IrLinkage::Internal,
1000 }
1001 }
1002
1003 /// Whether a body this unit is not meant to emit has to be emitted anyway, because this unit
1004 /// calls it and has nothing else to send the call to.
1005 ///
1006 /// C 6.7.4p7 says an inline definition is not an external definition, and the bargain it
1007 /// offers is that the call is replaced by the body, so nobody ever has to resolve the name.
1008 /// A compiler that inlines keeps its end of it. This one does not inline, so a call left
1009 /// standing is a call to a name no object file defines, and the program fails at the link on
1010 /// a function it can see the body of. micropython is a program that does exactly that:
1011 /// `py/misc.h` writes `MP_COMPRESSED_ROM_TEXT` as `inline __attribute__((always_inline))`,
1012 /// nothing anywhere defines it out of line, and every file that reports an error calls it.
1013 ///
1014 /// So a copy goes out of line, under [`IrLinkage::LinkOnce`]. Every unit that calls one emits
1015 /// its own copy of the same body, the linker keeps one and the rest are discarded, and a unit
1016 /// that holds the real external definition beats all of them because a strong definition
1017 /// beats a weak one. What that costs is object size in the units that call one. What it buys
1018 /// is that the address of the function is the same everywhere and that the program links,
1019 /// which is the whole of what the program was asking for.
1020 ///
1021 /// Only when this unit names it, which is why [`reach`] stopped treating one of these as a
1022 /// root. An unreferenced inline definition is still emitted as nothing at all, which is what
1023 /// keeps a file that includes `stdio.h` from carrying its own `vprintf`, `putchar`, `getchar`
1024 /// and the dozen more glibc writes beside them.
1025 fn out_of_line(&self, decl: DeclId, emission: Emission) -> bool {
1026 !emission.emits() && self.reachable.contains(&decl)
1027 }
1028
1029 /// The same for an object, where a global with no image is the declaration.
1030 fn place_global(&mut self, global: Global) {
1031 match self.module.lookup(global.name) {
1032 None => {
1033 self.module.add_global(global);
1034 }
1035 Some(SymbolRef::Global(id))
1036 if self.module[id].init.is_none() && global.init.is_some() =>
1037 {
1038 self.module[id] = global;
1039 }
1040 Some(_) => {}
1041 }
1042 }
1043
1044 /// Whether this function is one nothing can call, which is the set that is not emitted.
1045 ///
1046 /// A name with internal linkage is not visible to another translation unit, so a definition
1047 /// of one that nothing here refers to is a definition of something that can never run.
1048 /// [`reach`](mod@crate::reach) is what worked out which those are, and an attribute that asks
1049 /// for the definition to be kept has already been read into the answer.
1050 ///
1051 /// A second name for it is the one reason to keep it that the walk over the tree cannot see,
1052 /// since what an alias points at is a string and not a reference to anything. So the symbol
1053 /// is what is asked about here rather than the declaration: an alias names what the linker
1054 /// will look for, which is what a declaration that renamed itself with `__asm__` is under.
1055 ///
1056 /// Nothing is said about it. gcc has `-Wunused-function` for a `static` function nobody
1057 /// wrote a call to, which is a warning about the program, and this is not that: the header
1058 /// that defines six of them is not the file being compiled and its author is not the person
1059 /// reading the output.
1060 fn is_dropped(&self, decl: DeclId, symbol: Symbol) -> bool {
1061 self.tast[decl].linkage != Linkage::External
1062 && !self.reachable.contains(&decl)
1063 && !self.aliased.contains(&symbol)
1064 }
1065
1066 /// How everything a call to this function type hands over travels, and [`None`] for one the
1067 /// walk cannot make.
1068 ///
1069 /// `actual` is the types of the arguments at a call site, which matter only past the end of
1070 /// the prototype: what a variadic argument does is decided from what was written there, and
1071 /// there is no parameter to decide it from. A definition passes nothing for it.
1072 pub(crate) fn plan(&mut self, ty: TypeId, actual: &[TypeId], span: Span) -> Option<Plan> {
1073 self.plan_with(ty, actual, false, span)
1074 }
1075
1076 /// The same, as the call site sees it rather than as the function does.
1077 ///
1078 /// The two differ for a type that is not a prototype. An old style definition is the one of
1079 /// those that knows what its parameters are, and 6.5.2.2p6 checks a call against a prototype
1080 /// and against nothing at all otherwise, so a parameter it disagrees with does not make the
1081 /// call wrong and cannot be what the argument travels as either: the value at the call is
1082 /// the argument's own type and nothing converted it. So a parameter the argument facing it
1083 /// is compatible with is used, which is the usual case and is what makes the call go to the
1084 /// name, and one it is not compatible with gives way to what was actually written. A call
1085 /// like that is undefined behaviour if control reaches it and the file still has to
1086 /// translate, which is the same position [`Body::direct`](crate::body) already takes.
1087 pub(crate) fn call_plan(&mut self, ty: TypeId, actual: &[TypeId], span: Span) -> Option<Plan> {
1088 self.plan_with(ty, actual, true, span)
1089 }
1090
1091 fn plan_with(
1092 &mut self,
1093 ty: TypeId,
1094 actual: &[TypeId],
1095 at_call: bool,
1096 span: Span,
1097 ) -> Option<Plan> {
1098 let canonical = self.types.canonical(ty);
1099 let canonical = match self.types.kind(canonical) {
1100 // A call goes through a pointer to a function, and the type in hand may be either.
1101 TypeKind::Pointer(pointee) => self.types.canonical(pointee),
1102 _ => canonical,
1103 };
1104 let TypeKind::Function(id) = self.types.kind(canonical) else {
1105 self.unsupported("a call through something that is not a function", span);
1106 return None;
1107 };
1108 let signature = self.types.signature(id);
1109 let ret = signature.ret;
1110 // A function declared without a prototype takes what it is given, which is what a
1111 // signature with no parameters and no end to them says. C23 removed these and this is
1112 // what `int f();` means in every dialect before it.
1113 let variadic = signature.variadic || !signature.prototyped;
1114 let params = if at_call && !signature.prototyped {
1115 // An argument past the end of the list has no parameter to travel as, which is what
1116 // a call to an unprototyped function with more arguments than the definition takes
1117 // is, so the list ends where the arguments do.
1118 signature
1119 .params
1120 .iter()
1121 .zip(actual)
1122 .map(|(¶m, &arg)| if compatible(self.types, param, arg) { param } else { arg })
1123 .collect()
1124 } else {
1125 signature.params.clone()
1126 };
1127
1128 match abi::plan(self.types, self.target, ret, ¶ms, actual, variadic) {
1129 Ok(plan) => Some(plan),
1130 Err(what) => {
1131 self.unsupported(what, span);
1132 None
1133 }
1134 }
1135 }
1136
1137 /// The image of an initializer: the entries in ascending order, with the gaps zeroed, and
1138 /// how many bytes it covers.
1139 ///
1140 /// The count is the size that was asked for except when a flexible array member was given
1141 /// something to hold, which is the one case where an image is larger than the type it is an
1142 /// image of.
1143 pub(crate) fn image(
1144 &mut self,
1145 init: Option<InitList>,
1146 size: u64,
1147 span: Span,
1148 ) -> (DataList, u64) {
1149 let Some(init) = init else { return (self.zeros(size), size) };
1150 let (data, at) = self.pieces(init, size, span);
1151 (self.module.push_data(&data), at)
1152 }
1153
1154 /// The data an image is made of, before it becomes a [`DataList`].
1155 ///
1156 /// This is apart from [`Self::image`] so that an image can be built inside another one,
1157 /// which is what a compound literal used as a value in an initializer needs.
1158 fn pieces(&mut self, init: InitList, size: u64, span: Span) -> (Vec<Datum>, u64) {
1159 let entries = self.in_image_order(&self.tast[init]);
1160 let mut packed = self.packed(&entries, size);
1161 let mut data: Vec<Datum> = Vec::with_capacity(entries.len());
1162 let mut at = 0;
1163 for entry in entries {
1164 let piece = self.entry(entry, &mut packed, size);
1165 if piece.is_empty() {
1166 continue;
1167 }
1168 let covered: u64 = piece.iter().map(|datum| datum.size(&self.module)).sum();
1169 match entry.offset.cmp(&at) {
1170 Ordering::Greater => data.push(Datum::Zero(entry.offset - at)),
1171 // An entry that begins inside the one before it, which is neither the same
1172 // place nor a later one. A union whose members are initialized through two
1173 // designators is the way to write it. The earlier bytes are already in the
1174 // list and the image cannot take them out again, so this is refused, and
1175 // nothing here is wrong enough to drop the rest of the image.
1176 Ordering::Less => {
1177 self.unsupported("an initializer that writes over an earlier one", span);
1178 continue;
1179 }
1180 Ordering::Equal => {}
1181 }
1182 at = entry.offset + covered;
1183 data.extend(piece);
1184 }
1185 if at < size {
1186 // The tail of a partly initialized object, which C says is zero. So is the tail of
1187 // an array the initializer did not fill, and so is every byte of padding.
1188 data.push(Datum::Zero(size - at));
1189 at = size;
1190 }
1191 (data, at)
1192 }
1193
1194 /// The entries an image is written from, which is not the order they were written in.
1195 ///
1196 /// A designator names a place, and the places may be named in any order at all:
1197 /// `{ .b = 2, .a = 1 }` is the same object as `{ .a = 1, .b = 2 }` and C says so in as many
1198 /// words. An image is bytes in ascending order, so the entries are put in that order here.
1199 /// The sort is stable, which is what makes the rest of the rule work: naming one place
1200 /// twice is legal and the last of them is the one that stands, so among the entries at one
1201 /// offset the written order is kept and all but the last are dropped.
1202 ///
1203 /// A bit-field is never dropped, because several of them share one offset without writing
1204 /// over anything. Which bytes they came to is settled by [`Self::packed`] before this runs
1205 /// and the whole run goes in under the first entry that has a bit in it.
1206 fn in_image_order(&self, entries: &[InitEntry]) -> Vec<InitEntry> {
1207 let mut sorted = entries.to_vec();
1208 sorted.sort_by_key(|entry| entry.offset);
1209 let mut kept: Vec<InitEntry> = Vec::with_capacity(sorted.len());
1210 for entry in sorted {
1211 if !entry.is_bit_field() {
1212 let over = |last: &InitEntry| last.offset == entry.offset && !last.is_bit_field();
1213 while kept.last().is_some_and(over) {
1214 kept.pop();
1215 }
1216 }
1217 kept.push(entry);
1218 }
1219 kept
1220 }
1221
1222 /// What one entry of an initializer puts in the image.
1223 ///
1224 /// A bit-field is not a datum of its own, because two of them can live in one byte and an
1225 /// image is written in bytes. They were put together into their bytes by [`Self::packed`]
1226 /// before this ran, and the whole run of bytes goes in under the first entry that lies in
1227 /// it, which is why a later one in the same run answers with nothing.
1228 ///
1229 /// The zeroes at the end of a run are left off it, and a run that is nothing but zeroes
1230 /// answers with nothing at all. Either way the gap before the next entry covers them, which
1231 /// is the same image and is a smaller one to carry, and it is what keeps an object whose
1232 /// bit-fields are all zero in `.bss`. A zero at the front of a run or inside one stays, since
1233 /// that is where the run starts and what makes it one run. The run comes out of the map
1234 /// whatever is in it, so a later entry lying in it answers with nothing for the usual reason
1235 /// rather than writing the run a second time.
1236 ///
1237 /// An entry is usually one datum and a compound literal read is the reason the answer is a
1238 /// list: that entry is a whole object and puts as many data in as the object it is.
1239 fn entry(&mut self, entry: InitEntry, packed: &mut BTreeMap<u64, u8>, size: u64) -> Vec<Datum> {
1240 if entry.is_bit_field() {
1241 let Some(bytes) = take_run(packed, entry.offset) else { return Vec::new() };
1242 let Some(last) = bytes.iter().rposition(|&byte| byte != 0) else { return Vec::new() };
1243 return vec![Datum::Bytes(self.module.push_bytes(&bytes[..=last]))];
1244 }
1245 if let Some(literal) = self.literal_read(entry.value) {
1246 return self.literal_image(literal, self.tast.expr_span(entry.value));
1247 }
1248 if entry.reverse {
1249 if let Some(reversed) = self.reversed_datum(entry) {
1250 return reversed;
1251 }
1252 }
1253 // How much room is left in the object, which is what a string literal longer than the
1254 // array it initializes is cut down to. An entry that begins where the object ends is the
1255 // initializer of a flexible array member, and there the object grows to hold what was
1256 // written rather than the value being cut to fit, so nothing is taken off it.
1257 let room = if entry.offset < size { size - entry.offset } else { u64::MAX };
1258 if let Some(halves) = self.complex_image(entry.value) {
1259 return halves;
1260 }
1261 self.datum(entry.value, room).into_iter().collect()
1262 }
1263
1264 /// A complex constant as the two data an image holds it in, and [`None`] for anything else.
1265 ///
1266 /// A complex value is two real ones and an image is bytes, so `1.0 + 2.0i` goes in as the two
1267 /// halves one after the other, which is the layout every ABI here already reads it as. It is
1268 /// two data rather than one because a datum is one scalar, and it is here rather than in
1269 /// [`Self::datum`] for the same reason.
1270 fn complex_image(&mut self, value: ExprId) -> Option<Vec<Datum>> {
1271 let ty = self.tast[value].ty;
1272 let part = rucc_types::real_part(self.types, ty)?;
1273 let span = self.tast.expr_span(value);
1274 // Everything below this point answers with something, because the folding reports its own
1275 // failure and asking for the value a second time would report it twice.
1276 let folded = match self.fold(value) {
1277 Some(folded) => folded,
1278 None => return Some(Vec::new()),
1279 };
1280 let Some(ty) = repr::value_type(self.types, self.target, part) else {
1281 self.unsupported("this complex initializer", span);
1282 return Some(Vec::new());
1283 };
1284 // Each half goes in as the half's own type would, which is the bits of a floating value
1285 // and the number of an integer one.
1286 let halves = match folded {
1287 Const::Complex { real, imag } => {
1288 [real, imag].map(|half| Imm::from_bits(half.to_bits()))
1289 }
1290 Const::ComplexInt { real, imag } => [real, imag].map(|half| Imm::int(half, ty)),
1291 _ => {
1292 self.unsupported("this complex initializer", span);
1293 return Some(Vec::new());
1294 }
1295 };
1296 let data = halves
1297 .into_iter()
1298 .map(|half| {
1299 let imm = self.module.add_imm(half);
1300 Datum::Scalar { ty, value: imm }
1301 })
1302 .collect();
1303 Some(data)
1304 }
1305
1306 /// The compound literal an entry reads, if that is what the entry is.
1307 ///
1308 /// Reading an object is a node of its own, so a literal used as a value comes through as a
1309 /// read of a literal. A literal whose address is taken is not a read and is not this: that
1310 /// one folds to an address and goes in as a relocation, with the object it points at emitted
1311 /// on its own.
1312 fn literal_read(&self, value: ExprId) -> Option<DeclId> {
1313 let ExprKind::Convert { kind: Conversion::Lvalue, operand } = self.tast[value].kind else {
1314 return None;
1315 };
1316 match self.tast[operand].kind {
1317 ExprKind::CompoundLiteral(decl) => Some(decl),
1318 _ => None,
1319 }
1320 }
1321
1322 /// The bytes a compound literal contributes where it is read, which are its own image.
1323 ///
1324 /// The literal has static storage duration here, since a file-scope initializer is the only
1325 /// place this is reached from, and C 6.7.11p4 is what lets it stand as a constant element.
1326 /// Its own initializer is built at the offset the entry is at, so the parent image ends up
1327 /// with the literal's bytes laid into it rather than a name pointing at a second object.
1328 fn literal_image(&mut self, literal: DeclId, span: Span) -> Vec<Datum> {
1329 let size = repr::size_of(self.types, self.target, self.tast[literal].ty);
1330 let Some(init) = self.tast[literal].init else {
1331 return if size == 0 { Vec::new() } else { vec![Datum::Zero(size)] };
1332 };
1333 self.pieces(init, size, span).0
1334 }
1335
1336 /// The bit-fields of an initializer, put together into the bytes they lie in.
1337 ///
1338 /// Every byte a field lies in is in the map, whatever the bits it put there are. It is
1339 /// tempting to leave a zero byte out, on the grounds that what an image does not say is zero
1340 /// anyway, and it is wrong: the run a field's bytes make is taken out of the map from the
1341 /// byte the field starts at, so a field whose first byte happens to be zero would have its
1342 /// whole run left behind and `struct { unsigned f : 20; } x = { 0x12300 };` would read as
1343 /// zero. A run that is all zeroes is written as zeroes by [`Self::entry`], so an object that
1344 /// really is zero still costs nothing in the image.
1345 ///
1346 /// A field named twice takes only the bits of the field, so the last of them stands and does
1347 /// not read as the two values together.
1348 fn packed(&mut self, entries: &[InitEntry], size: u64) -> BTreeMap<u64, u8> {
1349 let mut bytes = BTreeMap::new();
1350 for entry in entries.iter().filter(|entry| entry.is_bit_field()) {
1351 let Some(folded) = self.fold(entry.value) else { continue };
1352 let Const::Int(number) = folded else {
1353 let span = self.tast.expr_span(entry.value);
1354 let what = "a bit-field initialized by something that is not an integer";
1355 self.unsupported(what, span);
1356 continue;
1357 };
1358 let width = entry.bit_width;
1359 let ones = if width >= 128 { u128::MAX } else { (1u128 << width) - 1 };
1360 // Which bytes the field lies in and where in them it sits. A reversed field lies in
1361 // the same bytes and is counted from the top of them, and the byte at its address is
1362 // then the most significant of the ones the value is assembled in rather than the
1363 // least, which is why the walk below runs the other way as well.
1364 let span = u64::from((entry.bit_offset + width).div_ceil(8));
1365 let start = if entry.reverse {
1366 u32::try_from(span * 8).unwrap_or(u32::MAX) - entry.bit_offset - width
1367 } else {
1368 entry.bit_offset
1369 };
1370 let mut mask = ones << start;
1371 let mut placed = ((number as u128) & ones) << start;
1372 let mut step = 0;
1373 while mask != 0 && step < span {
1374 let at = if entry.reverse {
1375 entry.offset + span - 1 - step
1376 } else {
1377 entry.offset + step
1378 };
1379 if at < size {
1380 let (bits, keep) = ((placed & 0xff) as u8, !((mask & 0xff) as u8));
1381 let byte = bytes.entry(at).or_insert(0);
1382 *byte = (*byte & keep) | bits;
1383 }
1384 mask >>= 8;
1385 placed >>= 8;
1386 step += 1;
1387 }
1388 }
1389 bytes
1390 }
1391
1392 /// What one entry of a record whose scalars are stored the other way round puts in the image.
1393 ///
1394 /// The bytes of the value, written in the order opposite to the target's, which is the whole of
1395 /// what the attribute asks for. It answers with nothing where the ordinary path is already
1396 /// right: a value one byte wide has only one order, and an aggregate is bytes its own members
1397 /// put there in whatever order each of them is stored in.
1398 ///
1399 /// Two things are refused rather than written the wrong way. A complex value is two scalars and
1400 /// this is one, and an address is a number the linker fills in later and there is nowhere to
1401 /// say it goes in backwards. Both are worth an answer one day and neither is worth a wrong one.
1402 fn reversed_datum(&mut self, entry: InitEntry) -> Option<Vec<Datum>> {
1403 let ty = self.tast[entry.value].ty;
1404 let span = self.tast.expr_span(entry.value);
1405 if is_complex(self.types, ty) {
1406 let what = "a complex member of a record whose scalars are stored the other way round";
1407 self.unsupported(what, span);
1408 return Some(Vec::new());
1409 }
1410 let size = repr::size_of(self.types, self.target, ty);
1411 if size < 2 || !is_scalar(self.types, ty) {
1412 return None;
1413 }
1414 let bits = match self.fold(entry.value) {
1415 Some(Const::Int(number)) => number as u128,
1416 Some(Const::Float(number)) => number.to_bits(),
1417 Some(Const::Address(Address { base: Base::Absolute, offset })) => offset as u128,
1418 Some(_) => {
1419 let what = "an address in a record whose scalars are stored the other way round";
1420 self.unsupported(what, span);
1421 return Some(Vec::new());
1422 }
1423 None => return Some(Vec::new()),
1424 };
1425 let take = cap(size).min(16);
1426 let mut bytes = bits.to_le_bytes()[..take].to_vec();
1427 if self.target.little_endian {
1428 bytes.reverse();
1429 }
1430 Some(vec![Datum::Bytes(self.module.push_bytes(&bytes))])
1431 }
1432
1433 /// One entry of an image, given how many bytes are left in the object it goes in.
1434 fn datum(&mut self, value: ExprId, room: u64) -> Option<Datum> {
1435 let tast = self.tast;
1436 let ty = tast[value].ty;
1437 let span = tast.expr_span(value);
1438 if let TypeKind::Array { .. } = self.types.kind(self.types.canonical(ty)) {
1439 // An array in an initializer is a string literal initializing it, because that is
1440 // the only way an array is ever a value. `char s[2] = "hi";` drops the terminator,
1441 // which is the one case where the literal is longer than what it initializes, and
1442 // the front end has already given the value the type of the array it is filling, so
1443 // the type is what says how many of the literal's bytes are part of it. `room` is
1444 // still consulted because a flexible array member is filled by a literal that keeps
1445 // its own type and there is no size in the object for it to be cut to.
1446 let ExprKind::Str(id) = tast[value].kind else {
1447 self.unsupported("this initializer", span);
1448 return None;
1449 };
1450 let bytes = tast[id].bytes(self.target);
1451 let holds = repr::size_of(self.types, self.target, ty);
1452 let take = bytes.len().min(cap(holds)).min(cap(room));
1453 return Some(Datum::Bytes(self.module.push_bytes(&bytes[..take])));
1454 }
1455
1456 let size = repr::size_of(self.types, self.target, ty);
1457 match self.fold(value)? {
1458 Const::Int(number) => {
1459 let ty = repr::value_type(self.types, self.target, ty)?;
1460 // An integer constant of pointer type is a null pointer constant, which is what
1461 // `NULL` is, or an address the program wrote as a number. An image is bytes and
1462 // `ptr` says nothing about how many, so it goes in as the integer it is at the
1463 // width the target's addresses have. An address the linker has to fill in is
1464 // the arm below, and is the only one that stays a pointer.
1465 let ty = if ty.is_ptr() { Type::int(self.target.pointer_width) } else { ty };
1466 let imm = self.module.add_imm(Imm::int(number, ty));
1467 Some(Datum::Scalar { ty, value: imm })
1468 }
1469 Const::Float(number) => {
1470 let ty = repr::value_type(self.types, self.target, ty)?;
1471 let imm = self.module.add_imm(Imm::from_bits(number.to_bits()));
1472 Some(Datum::Scalar { ty, value: imm })
1473 }
1474 // A complex constant is two scalars and this answers with one, so it is not one of
1475 // these. [`Self::complex_image`] puts one in before this is reached.
1476 Const::Complex { .. } | Const::ComplexInt { .. } => None,
1477 // An address into nothing is a number, so it goes into the image as one and there is
1478 // no relocation for the linker to fill in. `static char *p = &((struct S *)0)->f;` is
1479 // a pointer whose value is known here, and the walk that folded it already said so.
1480 Const::Address(Address { base: Base::Absolute, offset }) => {
1481 let ty = repr::value_type(self.types, self.target, ty)?;
1482 let ty = if ty.is_ptr() { Type::int(self.target.pointer_width) } else { ty };
1483 let imm = self.module.add_imm(Imm::int(offset, ty));
1484 Some(Datum::Scalar { ty, value: imm })
1485 }
1486 Const::Address(address) => {
1487 let symbol = match address.base {
1488 Base::Decl(decl) => {
1489 // A compound literal is an object nothing declares, so the address of
1490 // one is also the only thing that asks for it to be emitted. Without
1491 // this the image names a symbol the module never defines and the link
1492 // is what finds out. Anything with a name of its own is left alone,
1493 // since the walk over the unit reaches those on its own.
1494 if self.tast[decl].name.is_none() {
1495 self.local_static(decl);
1496 }
1497 self.symbol_of(decl)
1498 }
1499 Base::Str(id) => self.string(id),
1500 Base::Label(label) => self.label_name(label),
1501 // Answered above, where it becomes a number rather than a reference.
1502 Base::Absolute => return None,
1503 };
1504 let addend = i64::try_from(address.offset).unwrap_or(0);
1505 let size = u32::try_from(size).unwrap_or(0);
1506 Some(Datum::Addr(self.module.add_reloc(Reloc { symbol, addend, size })))
1507 }
1508 }
1509 }
1510
1511 /// An image of nothing but zeros, which is what a tentative definition has.
1512 fn zeros(&mut self, size: u64) -> DataList {
1513 if size == 0 {
1514 return DataList::EMPTY;
1515 }
1516 self.module.push_data(&[Datum::Zero(size)])
1517 }
1518
1519 /// The global a string literal is emitted as, making it the first time it is asked for.
1520 pub(crate) fn string(&mut self, id: StrId) -> Symbol {
1521 if let Some(&symbol) = self.strings.get(&id) {
1522 return symbol;
1523 }
1524 let literal = &self.tast[id];
1525 let bytes = literal.bytes(self.target);
1526 let align = literal.encoding.element_width(self.target) / 8;
1527 let symbol = self.names.intern(&format!(".Lstr.{}", self.strings.len()));
1528
1529 let mut global = Global::new(symbol, bytes.len() as u64, align.max(1));
1530 global.linkage = IrLinkage::Internal;
1531 // Not because the type says so, since a literal is an array of `char` and not of
1532 // `const char`, but because writing to one is undefined and every target puts them
1533 // somewhere read-only.
1534 global.constant = true;
1535 let range = self.module.push_bytes(&bytes);
1536 global.init = Some(self.module.push_data(&[Datum::Bytes(range)]));
1537 self.module.add_global(global);
1538 self.strings.insert(id, symbol);
1539 symbol
1540 }
1541
1542 /// The name a label an image holds the address of is known by, minting one the first time.
1543 ///
1544 /// The number is what makes two labels in two functions two names, the same way it does for a
1545 /// `static` inside a function. Nothing but the relocation and the definition the back end
1546 /// writes for it ever reads this, so the spelling only has to be one the object format lets a
1547 /// local symbol have, and the leading dot is what keeps it out of the symbol table on the
1548 /// formats that have the convention.
1549 pub(crate) fn label_name(&mut self, label: LabelId) -> Symbol {
1550 if let Some(&symbol) = self.labels.get(&label) {
1551 return symbol;
1552 }
1553 let symbol = self.names.intern(&format!(".Llbl.{}", self.labels.len()));
1554 self.labels.insert(label, symbol);
1555 symbol
1556 }
1557
1558 /// The name a label was given, or `None` for a label no image points at.
1559 pub(crate) fn named_label(&self, label: LabelId) -> Option<Symbol> {
1560 self.labels.get(&label).copied()
1561 }
1562
1563 /// The name the C library gives a function the program named with the `__builtin_` prefix,
1564 /// and nothing for every other name.
1565 ///
1566 /// `__builtin_abort` is a call to `abort`: the prefix is how a program reaches the function
1567 /// the library promises where a macro or a definition of its own has taken the plain name,
1568 /// so the two spellings are one function and the one the linker will look for is the short
1569 /// one. Which names those are is [`rucc_sema::library_name`]'s to say, since it is the same
1570 /// answer the front end declared them out of.
1571 fn library_name(&mut self, name: Symbol) -> Option<Symbol> {
1572 let library = rucc_sema::library_name(self.names.resolve(name))?;
1573 let symbol = self.names.intern(library);
1574 // And then whatever the file said that name is called in the object file. A program is
1575 // allowed to declare `memcpy` with an assembler name of its own and go on calling
1576 // `__builtin_memcpy`, and what it means by that is the renamed one: the prefix picks the
1577 // function out of the library, it does not ask for a symbol the file has renamed away.
1578 Some(self.renamed.get(&symbol).copied().unwrap_or(symbol))
1579 }
1580
1581 /// The name an object or a function is known by in the object file.
1582 pub(crate) fn symbol_of(&mut self, decl: DeclId) -> Symbol {
1583 let tast = self.tast;
1584 let node = &tast[decl];
1585 // The assembler name a declaration wrote, which is the symbol whatever the identifier
1586 // spells. It stands for a `static` and for a local one as well as for a name the linker
1587 // sees, so it is read before anything else here: a program that renames a name has said
1588 // what the symbol is, and the numbering below is for the ones that have not.
1589 if let Some(label) = node.asm_label {
1590 let spelling: String =
1591 tast[label].elements.iter().filter_map(|&unit| char::from_u32(unit)).collect();
1592 return self.names.intern(&spelling);
1593 }
1594 if node.linkage != Linkage::None {
1595 let Some(name) = node.name else { return self.names.intern(".Lanon") };
1596 return self.library_name(name).unwrap_or(name);
1597 }
1598 if let Some(&symbol) = self.statics.get(&decl) {
1599 return symbol;
1600 }
1601 // A `static` in a function, or a compound literal with static storage duration. The
1602 // number is what makes two of them in two functions two objects.
1603 let base = match node.name {
1604 Some(name) => self.names.resolve(name).to_string(),
1605 None => ".Lanon".to_string(),
1606 };
1607 let symbol = self.names.intern(&format!("{base}.{}", self.statics.len()));
1608 self.statics.insert(decl, symbol);
1609 symbol
1610 }
1611
1612 /// Emits the global for an object with static storage duration declared inside a function.
1613 pub(crate) fn local_static(&mut self, decl: DeclId) {
1614 if !self.done.insert(decl) {
1615 return;
1616 }
1617 match self.tast[decl].kind {
1618 // A function declared inside a body is a declaration of the function, not an
1619 // object with static storage that happens to be one.
1620 DeclKind::Function => self.function(decl),
1621 DeclKind::Object => self.object(decl),
1622 DeclKind::Type => {}
1623 }
1624 }
1625
1626 /// The value of a constant expression, reporting what folding it reported.
1627 ///
1628 /// Everything this is asked about is part of the image of an object that exists before the
1629 /// program runs, which is the one place C23 6.6p10 lets a compiler take more than the rest of
1630 /// 6.6 does, so it asks for the reading the front end already accepted there. Asking the
1631 /// strict way instead would refuse here what was allowed a pass earlier, which is a wrong
1632 /// answer arriving late rather than an extra check.
1633 fn fold(&mut self, expr: ExprId) -> Option<Const> {
1634 let mut eval = Eval::new(self.tast, self.types, self.target, self.names);
1635 let folded = eval.initializer(expr);
1636 let reported = eval.finish();
1637 self.diagnostics.extend(reported);
1638 match folded {
1639 Ok(value) => Some(value),
1640 Err(stop) => {
1641 if !stop.poisoned {
1642 let span = self.tast.expr_span(stop.at);
1643 self.unsupported("an initializer this compiler cannot fold", span);
1644 }
1645 None
1646 }
1647 }
1648 }
1649
1650 /// Reports a construct the walk does not build IR for yet.
1651 pub(crate) fn unsupported(&mut self, what: &str, span: Span) {
1652 self.diagnostics.push(
1653 Diagnostic::error(format!("{what} is not supported yet"), span).with_code("E0519"),
1654 );
1655 }
1656
1657 /// Reports a call to a builtin this compiler knows the name of and does nothing with.
1658 ///
1659 /// It is its own message rather than [`Self::unsupported`] because the construct is not the
1660 /// problem: a call is a call, and what is missing is the one function it goes to. The note is
1661 /// what a reader needs, since a builtin is the one name a programmer does not expect to have
1662 /// to provide and the alternative to this message is a linker asking them for it.
1663 pub(crate) fn missing_builtin(&mut self, spelled: &str, span: Span) {
1664 let message = format!("`{spelled}` is not implemented yet");
1665 let note = "a call to it would go to a symbol no object file defines, so this is refused \
1666 here rather than at the link";
1667 self.diagnostics.push(Diagnostic::error(message, span).with_code("E0686").note(note, span));
1668 }
1669}
1670
1671/// A count of bytes as a length of a slice of them, saturating on a target whose addresses are
1672/// wider than this host's.
1673fn cap(bytes: u64) -> usize {
1674 usize::try_from(bytes).unwrap_or(usize::MAX)
1675}
1676
1677/// The run of bytes a bit-field entry starts, taken out of the map.
1678///
1679/// [`None`] when there is no byte at that offset, which means an earlier entry in the same run
1680/// already took it, since [`Unit::packed`] puts every byte a field lies in into the map.
1681fn take_run(bytes: &mut BTreeMap<u64, u8>, start: u64) -> Option<Vec<u8>> {
1682 let mut run = vec![bytes.remove(&start)?];
1683 let mut at = start + 1;
1684 while let Some(byte) = bytes.remove(&at) {
1685 run.push(byte);
1686 at += 1;
1687 }
1688 Some(run)
1689}