Skip to main content

rucc_sema/check/
stmt.rs

1//! Statements: what happens, in what order, and where control is allowed to go instead.
2//!
3//! Design: `spec/07-types-and-semantics.md` section 7.14.
4//!
5//! An expression is checked against the types of its operands and nothing else, which is why the
6//! expression checking is a walk with no state in it. A statement is not. Whether `break` is
7//! allowed depends on what encloses it, what `return` may carry depends on the function it is in,
8//! and a `goto` may name a label that is fifty lines further down. So this walk carries a [`Body`]
9//! for as long as it is inside one, and everything a statement needs to know that is not in the
10//! statement itself is in there.
11//!
12//! # Labels are resolved over the whole function and not in order
13//!
14//! A label is one namespace, scoped to the function, and a `goto` is allowed to come first. So a
15//! label is created where its name is first met, whether that is the `goto` or the label itself,
16//! and the statement it names is filled in later. What is left over at the end of the function is
17//! the labels that were used and never defined, which is the one diagnostic here that cannot be
18//! written where it is found.
19//!
20//! GNU's `__label__` is the exception: it declares a label local to the block, which is what lets
21//! a macro that jumps to its own end be expanded twice in one function without the two colliding.
22//! Those are undone when the block ends, which is what the saved bindings in the body are for.
23//!
24//! # Why the case table is patched
25//!
26//! A `switch` holds its cases as a run, so that the walk to the IR builds a jump table from a
27//! table rather than by searching the body for labels. The run is not known until the body has
28//! been walked, and the `case` statements in the body are built while it is being walked, so each
29//! of them is written with a placeholder and given its real entry once the run exists. Collecting
30//! the whole run at the end is also what keeps a nested `switch` from interleaving its cases with
31//! the ones outside it, since each `switch` adds its cases in one go.
32//!
33//! # What is not here
34//!
35//! Reachability. `control reaches end of non-void function` and the unreachable code warnings are
36//! questions about a control flow graph, and the answer to them is in the IR rather than in the
37//! tree, so they wait for it. A label that is defined and never used is a warning gcc only gives
38//! under `-Wall`, and it waits for the flag rather than for anything here.
39
40use std::collections::{HashMap, HashSet};
41use std::mem;
42
43use rucc_ast::{self as ast, AsmQuals, ForInit, StorageClass};
44use rucc_base::Symbol;
45use rucc_diag::{Diagnostic, Span};
46use rucc_lex::{Encoding, Remarks, StringLiteral};
47use rucc_session::Std;
48use rucc_types::{IntegerInfo, Qualifiers, TypeId, is_integer, is_pointer, is_record, is_void};
49
50use crate::asm::{Asm, AsmOperand, AsmOperandList, LabelList};
51use crate::check::Checker;
52use crate::check::expr::Target;
53use crate::decl::{DeclId, DeclList};
54use crate::eval;
55use crate::expr::{Category, Expr, ExprId, ExprKind};
56use crate::stmt::{Case, Stmt, StmtId};
57use crate::tast::{Const, Label, LabelId, StrId};
58
59/// The spellings that stand for the name of the function they are written in. The first is the
60/// one C99 added and the other two are GNU's, which are the same thing in C and differ only in
61/// C++, where the pretty one spells out the signature.
62pub(in crate::check) const FUNCTION_NAMES: [&str; 3] =
63    ["__func__", "__FUNCTION__", "__PRETTY_FUNCTION__"];
64
65/// What the statements of one function body are checked against.
66#[derive(Debug)]
67pub(in crate::check) struct Body {
68    /// The return type, which every `return` in it answers to.
69    ret: TypeId,
70    /// Where the function was named, for the `declared here` note under a `return` that
71    /// disagrees with the return type.
72    at: Span,
73    /// Whether the parameter list ends in `...`, which is what says whether there is anything
74    /// for a `va_start` in here to start reading.
75    variadic: bool,
76    /// The last named parameter, which is what `va_start`'s second argument ought to name.
77    last_param: Option<DeclId>,
78    /// Every parameter, which is what tells an assignment to one of them from an assignment to
79    /// a local: gcc says `read-only parameter` for the first and `read-only variable` for the
80    /// second, and there is nothing on a declaration itself that says which it is.
81    params: DeclList,
82    /// The name the definition was written with, which is what `__func__` answers.
83    name: Option<Symbol>,
84    /// The string each of the three spellings was made into, so that every mention of one of them
85    /// in a function is one object rather than one per use. They are three objects and not one,
86    /// because gcc gives each spelling its own and a program is allowed to notice: comparing
87    /// `__func__` with `__FUNCTION__` there is false.
88    func_name: [Option<StrId>; FUNCTION_NAMES.len()],
89    /// The labels of the function, by the name they were written with.
90    labels: HashMap<Symbol, Labelled>,
91    /// What the enclosing blocks bound the names of their `__label__` declarations to, so that a
92    /// block-local label can be undone when the block ends.
93    shadowed: Vec<(Symbol, Option<Labelled>)>,
94    /// Where each enclosing block's run of those starts.
95    blocks: Vec<usize>,
96    /// The `switch` statements this one is inside, innermost last.
97    switches: Vec<Switch>,
98    /// How many loops it is inside, which is what `continue` asks and half of what `break` asks.
99    loops: usize,
100    /// The names this function has already been told about, so that a name nobody declared is
101    /// reported once rather than once per use. The message says `first use in this function`
102    /// and gcc means it: a typo in a loop body is one mistake however many times it is written.
103    undeclared: HashSet<Symbol>,
104    /// Every declaration of a variably modified type met so far, each one saying which of them
105    /// it was written inside.
106    modified: Vec<Modified>,
107    /// The innermost of those the walk is inside. The chain out of it through the entries above
108    /// is every one of them whose scope is open here.
109    inside: Option<usize>,
110    /// Where each label of the function is, filled in as the labels are met.
111    landings: HashMap<LabelId, Landing>,
112    /// Every `goto` met so far, kept until the whole function has been walked.
113    jumps: Vec<Jump>,
114}
115
116/// One declaration of a variably modified type, which is one a jump may not enter the scope of.
117#[derive(Debug, Clone, Copy)]
118struct Modified {
119    /// What it is called, absent for a declaration that names nothing.
120    name: Option<Symbol>,
121    /// Where it was written, for the note under the jump that skips it.
122    at: Span,
123    /// The one it was written inside, absent for one at the top of the function.
124    outer: Option<usize>,
125}
126
127/// Where a label is, which is what says whether a jump to it is allowed.
128#[derive(Debug, Clone, Copy)]
129struct Landing {
130    /// Where the label was written.
131    at: Span,
132    /// The innermost variably modified declaration whose scope it is in.
133    inside: Option<usize>,
134}
135
136/// One `goto`, which is checked when the function ends rather than where it is written.
137#[derive(Debug, Clone, Copy)]
138struct Jump {
139    /// The label it names.
140    to: LabelId,
141    /// Where it was written.
142    at: Span,
143    /// The innermost variably modified declaration whose scope it is in.
144    inside: Option<usize>,
145}
146
147/// What a body is opened with, which is what the enclosing function says about itself.
148#[derive(Debug, Clone, Copy)]
149pub(in crate::check) struct Enclosing {
150    /// The return type, which every `return` answers to.
151    pub ret: TypeId,
152    /// Where the function was named.
153    pub at: Span,
154    /// Whether the parameter list ends in `...`.
155    pub variadic: bool,
156    /// The last named parameter, absent when there are none.
157    pub last_param: Option<DeclId>,
158    /// Every parameter of the definition, empty for a body that is not one.
159    pub params: DeclList,
160    /// The name the function was written with, absent for a body that is not a definition.
161    pub name: Option<Symbol>,
162}
163
164impl Enclosing {
165    /// A function returning `ret` and saying nothing else about itself, which is what a caller
166    /// that has a statement rather than a definition in its hand has.
167    pub(in crate::check) fn returning(ret: TypeId) -> Enclosing {
168        Enclosing {
169            ret,
170            at: Span::DUMMY,
171            variadic: false,
172            last_param: None,
173            params: DeclList::EMPTY,
174            name: None,
175        }
176    }
177}
178
179/// One label of a function.
180#[derive(Debug, Clone, Copy)]
181struct Labelled {
182    /// The label in the typed tree, made where the name was first met.
183    id: LabelId,
184    /// Whether the statement it names has been seen, and where the label was written.
185    defined: Option<Span>,
186    /// Where the name was first met, which is what an undefined label is reported at.
187    at: Span,
188}
189
190/// One `switch` being checked, and the case table it is collecting.
191#[derive(Debug)]
192struct Switch {
193    /// The promoted type of the controlling expression, which every case value is held in.
194    ty: TypeId,
195    /// The shape of the type before that promotion, which is the range a case value is warned
196    /// about for leaving. gcc measures against what was written rather than against what the
197    /// promotion widened it to, so `case 300` on a `char` is worth saying even though 300 is a
198    /// perfectly good `int`.
199    range: Option<IntegerInfo>,
200    /// The cases so far, in the order they were written.
201    cases: Vec<Case>,
202    /// Where each of them was written, for the note under a duplicate.
203    spans: Vec<Span>,
204    /// The statements those cases label, which are patched with their table entries once the
205    /// table exists. Each one says which entry is its own, so the order here does not matter.
206    labels: Vec<StmtId>,
207    /// The `default`, and where it was written, once one has been seen.
208    default: Option<(StmtId, Span)>,
209}
210
211impl Checker<'_> {
212    /// Checks one statement, as though it were the body of a function returning `ret`.
213    ///
214    /// The entry for a caller that has a statement rather than a translation unit, which is what
215    /// the tests here are built on. A body is opened around it and closed after, so that the
216    /// labels are resolved and reported the way they are in a real function.
217    pub fn check_stmt(&mut self, ret: TypeId, id: ast::StmtId) -> StmtId {
218        let previous = self.open_body(Enclosing::returning(ret));
219        let stmt = self.stmt(id);
220        self.close_body(previous);
221        stmt
222    }
223
224    /// Checks one statement and gives back the node it became.
225    pub(in crate::check) fn stmt(&mut self, id: ast::StmtId) -> StmtId {
226        let span = self.ast.stmt_span(id);
227        let node = match self.ast[id] {
228            ast::Stmt::Error => Stmt::Error,
229            ast::Stmt::Empty => Stmt::Empty,
230            ast::Stmt::Expr(value) => {
231                let value = self.expr(value);
232                Stmt::Expr(self.value(value))
233            }
234            ast::Stmt::Decl(decl) => {
235                let decls = self.check_decl(decl);
236                self.variably_modified(decls);
237                Stmt::Decls(decls)
238            }
239            ast::Stmt::Compound(body) => Stmt::Block(self.block(body)),
240            ast::Stmt::If { cond, then, otherwise } => {
241                let cond = self.controlling(cond);
242                let then = self.stmt(then);
243                Stmt::If { cond, then, otherwise: otherwise.map(|id| self.stmt(id)) }
244            }
245            ast::Stmt::Switch { scrutinee, body } => self.switch(scrutinee, body),
246            ast::Stmt::While { cond, body } => {
247                let cond = self.controlling(cond);
248                Stmt::While { cond, body: self.loop_body(body) }
249            }
250            ast::Stmt::DoWhile { body, cond } => {
251                let body = self.loop_body(body);
252                Stmt::DoWhile { body, cond: self.controlling(cond) }
253            }
254            ast::Stmt::For { init, cond, step, body } => self.for_loop(init, cond, step, body),
255            ast::Stmt::Goto(name) => Stmt::Goto(self.jump(name, span)),
256            ast::Stmt::GotoExpr(target) => self.computed_goto(target),
257            ast::Stmt::Continue => self.continue_stmt(span),
258            ast::Stmt::Break => self.break_stmt(span),
259            ast::Stmt::Return(value) => self.return_stmt(value, span),
260            ast::Stmt::Label { name, body, .. } => self.labelled(name, body, span),
261            ast::Stmt::Case { lo, hi, body } => self.case(lo, hi, body, span),
262            ast::Stmt::Default { body } => self.default(body, span),
263            ast::Stmt::LocalLabels(names) => {
264                self.local_labels(names, span);
265                Stmt::Empty
266            }
267            ast::Stmt::Asm(asm) => self.asm(asm, span),
268        };
269        let stmt = self.tast.stmt(node, span);
270        // The `switch` patches its cases once it has a table, and what it has to patch is the
271        // node that ended up in the body rather than the one the arm above built, so the case
272        // is registered here where that node exists.
273        if matches!(node, Stmt::Case { .. }) {
274            if let Some(switch) = self.switches() {
275                switch.labels.push(stmt);
276            }
277        }
278        stmt
279    }
280
281    /// `({ ... })`, GNU's statement expression, whose value is its last statement's.
282    ///
283    /// The type is the last statement's if that statement is an expression, and `void` otherwise,
284    /// which is gcc's rule and which makes `({ })` and `({ int x; })` both `void`. This works
285    /// because an expression statement holds the value of its expression rather than a conversion
286    /// of it to `void`: the statement is what discards the value, and here is where the value is
287    /// wanted instead.
288    pub(in crate::check) fn stmt_expr(&mut self, id: ast::StmtId, span: Span) -> ExprId {
289        let stmt = self.stmt(id);
290        let ty = match self.tast[stmt] {
291            Stmt::Block(body) => match self.tast[body].last() {
292                Some(&last) => match self.tast[last] {
293                    Stmt::Expr(value) => self.tast[value].ty,
294                    _ => self.types.void(),
295                },
296                None => self.types.void(),
297            },
298            _ => self.types.void(),
299        };
300        self.tast.expr(Expr::new(ExprKind::StmtExpr(stmt), ty, Category::Rvalue), span)
301    }
302
303    /// `&&name`, GNU's label address, whose type is `void *` and whose target is a label.
304    ///
305    /// Mentioning a label here is a use of it and not a definition, so a function that takes the
306    /// address of a label it never defines is reported the same way a `goto` to one is.
307    pub(in crate::check) fn label_addr(&mut self, name: Symbol, span: Span) -> ExprId {
308        let label = self.label(name, span);
309        let ty = self.types.pointer(self.types.void());
310        self.tast.expr(Expr::new(ExprKind::LabelAddr(label), ty, Category::Rvalue), span)
311    }
312
313    /// Opens a body, and gives back the one it displaced so that it can be put back.
314    ///
315    /// Displaced rather than asserted absent, because GNU's nested functions are a body inside a
316    /// body and each has its own labels, its own return type and its own loops.
317    pub(in crate::check) fn open_body(&mut self, func: Enclosing) -> Option<Body> {
318        let body = Body {
319            ret: func.ret,
320            at: func.at,
321            variadic: func.variadic,
322            last_param: func.last_param,
323            params: func.params,
324            name: func.name,
325            func_name: [None; FUNCTION_NAMES.len()],
326            labels: HashMap::new(),
327            shadowed: Vec::new(),
328            blocks: Vec::new(),
329            switches: Vec::new(),
330            loops: 0,
331            undeclared: HashSet::new(),
332            modified: Vec::new(),
333            inside: None,
334            landings: HashMap::new(),
335            jumps: Vec::new(),
336        };
337        self.body.replace(body)
338    }
339
340    /// Whether the function being checked takes arguments past its named ones.
341    ///
342    /// False outside a function, where `va_start` is as wrong as it is in one with a fixed
343    /// parameter list and is reported in the same words.
344    pub(in crate::check) fn in_variadic_function(&self) -> bool {
345        self.body.as_ref().is_some_and(|body| body.variadic)
346    }
347
348    /// The last named parameter of the function being checked, which is what `va_start`'s
349    /// second argument ought to name.
350    pub(in crate::check) fn last_named_parameter(&self) -> Option<DeclId> {
351        self.body.as_ref().and_then(|body| body.last_param)
352    }
353
354    /// The string the `which`th spelling stands for in the function being checked, made on first
355    /// use.
356    ///
357    /// `None` outside a function, where the name is not declared at all. gcc gives it the empty
358    /// string there and warns, which is a warning nothing here can select yet, so a use outside
359    /// a function is left to the ordinary undeclared-name error.
360    pub(in crate::check) fn function_name_string(&mut self, which: usize) -> Option<StrId> {
361        let name = self.body.as_ref()?.name?;
362        if let Some(id) = self.body.as_ref().and_then(|body| body.func_name[which]) {
363            return Some(id);
364        }
365        let elements = self.text(name).chars().map(|c| c as u32).collect();
366        let literal =
367            StringLiteral { elements, encoding: Encoding::Plain, remarks: Remarks::default() };
368        let id = self.tast.add_string(literal);
369        if let Some(body) = &mut self.body {
370            body.func_name[which] = Some(id);
371        }
372        Some(id)
373    }
374
375    /// Whether a declaration is one of the parameters of the function being checked.
376    ///
377    /// False outside a function body, where every name in sight belongs to something else.
378    pub(in crate::check) fn is_parameter(&self, decl: DeclId) -> bool {
379        self.body.as_ref().is_some_and(|body| self.tast[body.params].contains(&decl))
380    }
381
382    /// Whether this is the first time the function being checked has used the undeclared name
383    /// `name`, and records it either way.
384    ///
385    /// Always true outside a function body, where there is nothing to remember it in and where
386    /// each declaration is its own context anyway.
387    pub(in crate::check) fn first_undeclared_use(&mut self, name: Symbol) -> bool {
388        match &mut self.body {
389            Some(body) => body.undeclared.insert(name),
390            None => true,
391        }
392    }
393
394    /// Closes a body, reporting the labels that were used and never defined.
395    pub(in crate::check) fn close_body(&mut self, previous: Option<Body>) {
396        let Some(body) = mem::replace(&mut self.body, previous) else {
397            return;
398        };
399        // Sorted, because a map has no order and a compiler whose diagnostics come out in a
400        // different order on two runs of the same input is one nobody can write a test against.
401        let mut undefined: Vec<Labelled> =
402            body.labels.into_values().filter(|label| label.defined.is_none()).collect();
403        undefined.sort_by_key(|label| label.at.lo);
404        for label in undefined {
405            self.undefined_label(label);
406        }
407
408        // Where each `goto` lands, which is the one thing about one that cannot be answered
409        // where it is written, since the label it names may be fifty lines further down.
410        for jump in &body.jumps {
411            let Some(landing) = body.landings.get(&jump.to) else { continue };
412            let Some(entered) = landing.inside else { continue };
413            if open_at(&body.modified, jump.inside, entered) {
414                continue;
415            }
416            self.jumped_into_scope(*jump, *landing, body.modified[entered]);
417        }
418    }
419
420    /// The diagnostic for a `goto` that jumps into the scope of a variably modified declaration.
421    ///
422    /// The wording is gcc's, and so are the two notes, which are what make it readable: the
423    /// label says where control lands and the declaration says what is not there when it does.
424    fn jumped_into_scope(&mut self, jump: Jump, landing: Landing, entered: Modified) {
425        let label = self.text(self.tast[jump.to].name).to_owned();
426        let mut diag =
427            Diagnostic::error("jump into scope of identifier with variably modified type", jump.at)
428                .with_code("E0684")
429                .note(format!("label '{label}' defined here"), landing.at);
430        if let Some(name) = entered.name {
431            let spelled = self.text(name).to_owned();
432            diag = diag.note(format!("'{spelled}' declared here"), entered.at);
433        }
434        self.report(diag);
435    }
436
437    /// The body of a function definition, walked in the scope its parameters are already in.
438    ///
439    /// A function body is one scope with the parameters, which is why this exists rather than
440    /// the caller reaching [`Checker::stmt`]: that would open a second scope and make
441    /// `void f(int a) { int a; }` two declarations of `a` that never meet.
442    pub(in crate::check) fn body_block(&mut self, body: ast::StmtId) -> StmtId {
443        let span = self.ast.stmt_span(body);
444        let ast::Stmt::Compound(list) = self.ast[body] else {
445            return self.stmt(body);
446        };
447        let list = self.statements(list);
448        self.tast.stmt(Stmt::Block(list), span)
449    }
450
451    /// A block, which is a scope.
452    fn block(&mut self, body: ast::StmtList) -> crate::stmt::StmtList {
453        self.scopes.push();
454        let outer = self.open_scope();
455        let list = self.statements(body);
456        self.close_scope(outer);
457        self.scopes.pop();
458        list
459    }
460
461    /// What the walk is inside as a scope opens, so that what the scope declares is out of scope
462    /// again when it ends.
463    ///
464    /// Every scope a jump can leave has to do this, which is a block and a `for` clause. The
465    /// function body is not one of them: nothing in it is outside it.
466    fn open_scope(&self) -> Option<usize> {
467        self.body.as_ref().and_then(|state| state.inside)
468    }
469
470    /// Puts that back.
471    fn close_scope(&mut self, outer: Option<usize>) {
472        if let Some(state) = self.body.as_mut() {
473            state.inside = outer;
474        }
475    }
476
477    /// Records what a declaration declares that is variably modified.
478    ///
479    /// C11 6.8.6.1p1 says a jump may not enter the scope of one of these, and the reason is that
480    /// the size is a value the program worked out where the declaration is: a jump that lands
481    /// past the declaration without going through it lands somewhere that value was never
482    /// computed. What is recorded here is what a jump is checked against at the end.
483    fn variably_modified(&mut self, decls: DeclList) {
484        let ids = self.tast[decls].to_vec();
485        for decl in ids {
486            if !self.is_variably_modified(self.tast[decl].ty) {
487                continue;
488            }
489            let name = self.tast[decl].name;
490            let at = self.tast.decl_span(decl);
491            if let Some(state) = self.body.as_mut() {
492                let outer = state.inside;
493                state.modified.push(Modified { name, at, outer });
494                state.inside = Some(state.modified.len() - 1);
495            }
496        }
497    }
498
499    /// The statements of a block, with the block-local labels undone at the end of it.
500    fn statements(&mut self, body: ast::StmtList) -> crate::stmt::StmtList {
501        if let Some(state) = self.body.as_mut() {
502            let mark = state.shadowed.len();
503            state.blocks.push(mark);
504        }
505        let ids = self.ast[body].to_vec();
506        let mut stmts = Vec::with_capacity(ids.len());
507        for id in ids {
508            stmts.push(self.stmt(id));
509        }
510        self.end_block();
511        self.tast.add_stmt_refs(&stmts)
512    }
513
514    /// Undoes what `__label__` declared in the block that is ending.
515    fn end_block(&mut self) {
516        let Some(body) = self.body.as_mut() else {
517            return;
518        };
519        let Some(mark) = body.blocks.pop() else {
520            return;
521        };
522        let mut gone = Vec::new();
523        while body.shadowed.len() > mark {
524            let (name, previous) = body.shadowed.pop().expect("a saved binding");
525            let local = match previous {
526                Some(previous) => body.labels.insert(name, previous),
527                None => body.labels.remove(&name),
528            };
529            if let Some(local) = local {
530                if local.defined.is_none() {
531                    gone.push(local);
532                }
533            }
534        }
535        gone.sort_by_key(|label| label.at.lo);
536        for label in gone {
537            self.undefined_label(label);
538        }
539    }
540
541    /// The body of a loop, inside which `break` and `continue` both mean something.
542    fn loop_body(&mut self, body: ast::StmtId) -> StmtId {
543        if let Some(state) = self.body.as_mut() {
544            state.loops += 1;
545        }
546        let body = self.stmt(body);
547        if let Some(state) = self.body.as_mut() {
548            state.loops -= 1;
549        }
550        body
551    }
552
553    /// `for (init; cond; step) body`, whose first clause is in a scope of its own.
554    fn for_loop(
555        &mut self,
556        init: ForInit,
557        cond: Option<ast::ExprId>,
558        step: Option<ast::ExprId>,
559        body: ast::StmtId,
560    ) -> Stmt {
561        // The scope is the loop's rather than the body's, which is what makes the `i` in
562        // `for (int i = 0; ...)` visible to the condition and gone after the loop.
563        self.scopes.push();
564        let outer = self.open_scope();
565        let init = match init {
566            ForInit::None => None,
567            ForInit::Expr(value) => {
568                let span = self.ast.expr_span(value);
569                let value = self.expr(value);
570                let value = self.value(value);
571                Some(self.tast.stmt(Stmt::Expr(value), span))
572            }
573            ForInit::Decl(decl) => {
574                let span = self.ast.decl_span(decl);
575                let decls = self.check_decl(decl);
576                self.variably_modified(decls);
577                self.check_loop_declaration(decl);
578                Some(self.tast.stmt(Stmt::Decls(decls), span))
579            }
580        };
581        let cond = cond.map(|cond| self.controlling(cond));
582        let step = step.map(|step| {
583            let step = self.expr(step);
584            self.value(step)
585        });
586        let body = self.loop_body(body);
587        self.close_scope(outer);
588        self.scopes.pop();
589        Stmt::For { init, cond, step, body }
590    }
591
592    /// What a `for` loop's first clause is not allowed to declare.
593    ///
594    /// C99 6.8.5p3 says the declaration there declares objects with automatic storage and nothing
595    /// else, which rules out a `static`, an `extern` and a `typedef`. The point of the rule is
596    /// that the clause scopes to the loop, and a name that outlives the loop has no business
597    /// being written where it looks like it does not.
598    ///
599    /// gcc accepts all three without a word unless `-pedantic` is on, and enough code declares a
600    /// `static` counter there that following the letter of the rule by default would reject
601    /// programs everyone else builds.
602    fn check_loop_declaration(&mut self, decl: ast::DeclId) {
603        if !self.cx.pedantic {
604            return;
605        }
606        let ast::Decl::Var { specs, declarators } = self.ast[decl] else {
607            return;
608        };
609        let specs = self.ast[specs];
610        let word = match specs.storage {
611            _ if specs.is_typedef() => "non-variable",
612            Some(StorageClass::Static) => "static variable",
613            Some(StorageClass::Extern) => "'extern' variable",
614            _ => return,
615        };
616        let ast = self.ast;
617        for &item in &ast[declarators] {
618            let node = ast[item.declarator];
619            let Some(name) = node.name else { continue };
620            let spelled = self.text(name).to_owned();
621            self.report(
622                Diagnostic::warning(
623                    format!("declaration of {word} '{spelled}' in 'for' loop initial declaration"),
624                    node.name_span,
625                )
626                .with_code("E0619"),
627            );
628        }
629    }
630
631    /// `switch (cond) body`, with the case table collected while the body is walked.
632    fn switch(&mut self, scrutinee: ast::ExprId, body: ast::StmtId) -> Stmt {
633        let at = self.ast.expr_span(scrutinee);
634        let cond = self.expr(scrutinee);
635        let cond = self.value(cond);
636        // Read before the promotion and not after it, because the range a case value is measured
637        // against is the one that was written. `switch (c)` on a `char` and `case 300` is worth
638        // saying, and by the time the promotion has run there is nothing left to say it about.
639        let range = eval::int_shape(&self.types, self.tast[cond].ty, self.cx.target);
640        let cond = self.conv().promote(cond);
641        let ty = self.tast[cond].ty;
642        let cond = if self.is_poisoned(cond) || is_integer(&self.types, ty) {
643            cond
644        } else {
645            self.report(Diagnostic::error("switch quantity not an integer", at).with_code("E0620"));
646            self.poison(at)
647        };
648        // The controlling type is the promoted one even where it was not an integer, so that the
649        // cases in the body are still folded and checked against each other rather than being
650        // reported a second time for something the `switch` itself already answered for.
651        let ty = if is_integer(&self.types, ty) { ty } else { self.int() };
652        if let Some(state) = self.body.as_mut() {
653            state.switches.push(Switch {
654                ty,
655                range,
656                cases: Vec::new(),
657                spans: Vec::new(),
658                labels: Vec::new(),
659                default: None,
660            });
661        }
662        let body = self.stmt(body);
663        let Some(switch) = self.body.as_mut().and_then(|state| state.switches.pop()) else {
664            return Stmt::Error;
665        };
666        let cases = self.tast.add_cases(&switch.cases);
667        for &labelled in &switch.labels {
668            let Stmt::Case { case: entry, body } = self.tast[labelled] else {
669                continue;
670            };
671            // The node is holding the place its label took in the table, which is where the
672            // label was written. It is not where the node was checked: two labels on one
673            // statement are checked inside out.
674            let case = cases.iter().nth(entry.index()).expect("a case for every label");
675            self.tast.set_stmt(labelled, Stmt::Case { case, body });
676        }
677        Stmt::Switch { cond, body, cases, default: switch.default.map(|(stmt, _)| stmt) }
678    }
679
680    /// `case lo:`, or GNU's `case lo ... hi:`.
681    fn case(
682        &mut self,
683        lo: ast::ExprId,
684        hi: Option<ast::ExprId>,
685        body: Option<ast::StmtId>,
686        span: Span,
687    ) -> Stmt {
688        // The label joins the table before the statement it labels is checked, so that the
689        // table comes out in the order the labels were written. `case 1: case 2: s;` is one
690        // labelled statement nested inside another, and checking inside out would leave the
691        // table holding 2 before 1.
692        let entry = self.enter_case(lo, hi, span);
693        let body = self.labelled_body(body, span);
694        let Some(entry) = entry else {
695            return Stmt::Error;
696        };
697        self.switches().expect("a switch").cases[entry].body = body;
698        // The node holds its place in the table until the `switch` knows where the table went,
699        // which is what the walk over its body ends with. The node this becomes is registered
700        // by [`Checker::stmt`], since that is where it is written into the arena and only the
701        // node that ends up in the body is worth patching.
702        Stmt::Case { case: rucc_base::Idx::from_usize(entry), body }
703    }
704
705    /// The place in the enclosing switch's table that this label takes, with a body for
706    /// [`Checker::case`] to fill in, or `None` for a label the switch cannot have.
707    fn enter_case(
708        &mut self,
709        lo: ast::ExprId,
710        hi: Option<ast::ExprId>,
711        span: Span,
712    ) -> Option<usize> {
713        if self.body.as_ref().is_none_or(|state| state.switches.is_empty()) {
714            self.report(
715                Diagnostic::error("case label not within a switch statement", span)
716                    .with_code("E0621"),
717            );
718            return None;
719        }
720        let low = self.case_value(lo, span)?;
721        let high = match hi {
722            Some(hi) => self.case_value(hi, span)?,
723            None => low,
724        };
725        if high < low {
726            self.report(Diagnostic::warning("empty range specified", span).with_code("E0622"));
727            return None;
728        }
729        if let Some(at) = self.overlapping_case(low, high) {
730            self.report(
731                Diagnostic::error("duplicate case value", span)
732                    .with_code("E0623")
733                    .note("previously used here".to_owned(), at),
734            );
735            return None;
736        }
737        let switch = self.switches().expect("a switch");
738        let entry = switch.cases.len();
739        // The body is filled in by the caller once it has been checked. Nothing reads it in
740        // between: the table is only looked at for overlap, which is a question about values.
741        switch.cases.push(Case { low, high, body: rucc_base::Idx::from_usize(0) });
742        switch.spans.push(span);
743        Some(entry)
744    }
745
746    /// The value of one case label, folded and converted to the controlling type.
747    fn case_value(&mut self, value: ast::ExprId, span: Span) -> Option<i128> {
748        let at = self.ast.expr_span(value);
749        let value = self.expr(value);
750        let value = self.value(value);
751        let folded = match self.eval_integer(value) {
752            Ok(folded) => folded,
753            Err(failed) => {
754                if !failed.poisoned {
755                    self.report(
756                        Diagnostic::error("case label does not reduce to an integer constant", at)
757                            .with_code("E0624"),
758                    );
759                }
760                return None;
761            }
762        };
763        let switch = self.switches()?;
764        let (ty, range) = (switch.ty, switch.range);
765        if let Some(range) = range {
766            if eval::overflows(Const::Int(folded), range) {
767                self.report(
768                    Diagnostic::warning("case label value exceeds maximum value for type", span)
769                        .with_code("E0625"),
770                );
771            }
772        }
773        let info = eval::int_shape(&self.types, ty, self.cx.target)?;
774        Some(eval::narrowed(Const::Int(folded), info))
775    }
776
777    /// Where a case that already covers part of this range was written, if there is one.
778    fn overlapping_case(&mut self, low: i128, high: i128) -> Option<Span> {
779        let switch = self.switches()?;
780        switch
781            .cases
782            .iter()
783            .position(|case| case.low <= high && low <= case.high)
784            .map(|index| switch.spans[index])
785    }
786
787    /// `default:`.
788    fn default(&mut self, body: Option<ast::StmtId>, span: Span) -> Stmt {
789        let body = self.labelled_body(body, span);
790        if self.body.as_ref().is_none_or(|state| state.switches.is_empty()) {
791            self.report(
792                Diagnostic::error("'default' label not within a switch statement", span)
793                    .with_code("E0626"),
794            );
795            return Stmt::Error;
796        }
797        if let Some((_, at)) = self.switches().expect("a switch").default {
798            self.report(
799                Diagnostic::error("multiple default labels in one switch", span)
800                    .with_code("E0627")
801                    .note("this is the first default label".to_owned(), at),
802            );
803            return Stmt::Error;
804        }
805        self.switches().expect("a switch").default = Some((body, span));
806        Stmt::Default { body }
807    }
808
809    /// `name: body`, which defines a label.
810    fn labelled(&mut self, name: Symbol, body: Option<ast::StmtId>, span: Span) -> Stmt {
811        // Where control lands, taken before the labelled statement is walked, because a C23
812        // label on a declaration is a label outside the scope of what that declaration declares.
813        let inside = self.open_scope();
814        let body = self.labelled_body(body, span);
815        let label = self.label(name, span);
816        let defined = self.body.as_ref().and_then(|state| state.labels[&name].defined);
817        if let Some(at) = defined {
818            let spelled = self.text(name).to_owned();
819            self.report(
820                Diagnostic::error(format!("duplicate label '{spelled}'"), span)
821                    .with_code("E0628")
822                    .note(format!("previous definition of '{spelled}' with type 'void'"), at),
823            );
824            return Stmt::Error;
825        }
826        if let Some(state) = self.body.as_mut() {
827            state.labels.entry(name).and_modify(|known| known.defined = Some(span));
828            state.landings.insert(label, Landing { at: span, inside });
829        }
830        self.tast.define_label(label, body);
831        Stmt::Label { label, body }
832    }
833
834    /// The statement a label labels, which C23 allows to be absent at the end of a block.
835    fn labelled_body(&mut self, body: Option<ast::StmtId>, span: Span) -> StmtId {
836        match body {
837            Some(body) => self.stmt(body),
838            None => self.tast.stmt(Stmt::Empty, span),
839        }
840    }
841
842    /// `__label__ a, b;`, which declares labels local to the block it is written in.
843    fn local_labels(&mut self, names: ast::SymbolList, span: Span) {
844        let ast = self.ast;
845        for &name in &ast[names] {
846            let id = self.tast.add_label(Label { name, stmt: None });
847            let local = Labelled { id, defined: None, at: span };
848            if let Some(state) = self.body.as_mut() {
849                let previous = state.labels.insert(name, local);
850                state.shadowed.push((name, previous));
851            }
852        }
853    }
854
855    /// `goto name;`, which is a use of the label and a jump to be looked at once every label of
856    /// the function is known.
857    fn jump(&mut self, name: Symbol, span: Span) -> LabelId {
858        let to = self.label(name, span);
859        if let Some(state) = self.body.as_mut() {
860            state.jumps.push(Jump { to, at: span, inside: state.inside });
861        }
862        to
863    }
864
865    /// The label of a name, made where the name is first met.
866    fn label(&mut self, name: Symbol, span: Span) -> LabelId {
867        if let Some(known) = self.body.as_ref().and_then(|state| state.labels.get(&name)) {
868            return known.id;
869        }
870        let id = self.tast.add_label(Label { name, stmt: None });
871        if let Some(state) = self.body.as_mut() {
872            state.labels.insert(name, Labelled { id, defined: None, at: span });
873        }
874        id
875    }
876
877    /// The diagnostic for a label that something jumped to and nothing defined.
878    ///
879    /// gcc points at the function rather than at the jump, which is a choice about a message
880    /// written at the end of a function and not about which one is the mistake. This points at
881    /// the jump, since that is what has to be changed and since a `__label__` is reported at the
882    /// end of a block that a function has no way to name.
883    fn undefined_label(&mut self, label: Labelled) {
884        let name = self.tast[label.id].name;
885        let spelled = self.text(name).to_owned();
886        self.report(
887            Diagnostic::error(format!("label '{spelled}' used but not defined"), label.at)
888                .with_code("E0629"),
889        );
890    }
891
892    /// `goto *expr;`, GNU's computed goto.
893    fn computed_goto(&mut self, target: ast::ExprId) -> Stmt {
894        let at = self.ast.expr_span(target);
895        let target = self.expr(target);
896        let target = self.value(target);
897        if self.is_poisoned(target) {
898            return Stmt::Error;
899        }
900        let ty = self.tast[target].ty;
901        // An integer is allowed through because a null pointer constant is one, and `goto *0;`
902        // is what a macro expands to where the target is decided elsewhere.
903        if !is_pointer(&self.types, ty) && !is_integer(&self.types, ty) {
904            self.report(
905                Diagnostic::error("computed goto must be pointer type", at).with_code("E0630"),
906            );
907            return Stmt::Error;
908        }
909        let void = self.types.pointer(self.types.void());
910        let target = self.conv().to_type(target, void);
911        Stmt::IndirectGoto(target)
912    }
913
914    /// `asm(...)`, GNU's inline assembly.
915    ///
916    /// Nothing here reads a constraint the way a target will. What is checked is the part that
917    /// belongs to the language rather than to the machine: an output has to be something the
918    /// program is allowed to assign to, an output constraint has to say it is one with `=` or
919    /// `+`, an input constraint has to not say it, and the labels of an `asm goto` are labels of
920    /// the function it is in. Whether the target has a register that fits a `"r"` is a question
921    /// for the backend, which is the only place a wrong answer to it can be given.
922    ///
923    /// The operands keep the order they were written in, because the template names them by
924    /// position: the outputs are numbered from zero and the inputs carry on from there, which is
925    /// the numbering `%0` counts in.
926    fn asm(&mut self, id: ast::AsmId, span: Span) -> Stmt {
927        let node = self.ast[id];
928        let outputs = self.asm_operands(node.outputs, 0, true);
929        let first_input = self.ast[node.outputs].len();
930        let inputs = self.asm_operands(node.inputs, first_input, false);
931
932        let mut clobbers = Vec::with_capacity(self.ast[node.clobbers].len());
933        for index in 0..self.ast[node.clobbers].len() {
934            let clobber = self.ast[node.clobbers][index];
935            clobbers.push(self.asm_string(clobber, span));
936        }
937        let clobbers = self.tast.add_str_refs(&clobbers);
938
939        let mut labels = Vec::with_capacity(self.ast[node.labels].len());
940        for index in 0..self.ast[node.labels].len() {
941            let name = self.ast[node.labels][index];
942            labels.push(self.label(name, span));
943        }
944        let labels = self.tast.add_label_refs(&labels);
945        let template = self.asm_template(node.template, outputs, inputs, labels, span);
946
947        // A statement with no outputs is `volatile` whether it said so or not, since one whose
948        // results nothing reads is otherwise one that may be dropped, and an `asm goto` is
949        // volatile for the same reason: what it does is jump, and no output records that.
950        let mut quals = node.quals;
951        if self.ast[node.outputs].is_empty() || quals.has(AsmQuals::GOTO) {
952            quals = quals.with(AsmQuals::VOLATILE);
953        }
954        Stmt::Asm(self.tast.add_asm(Asm { template, outputs, inputs, clobbers, labels, quals }))
955    }
956
957    /// One section of operands, numbered from `first` for the messages that count them.
958    fn asm_operands(
959        &mut self,
960        list: ast::AsmOperandList,
961        first: usize,
962        output: bool,
963    ) -> AsmOperandList {
964        let mut operands = Vec::with_capacity(self.ast[list].len());
965        for index in 0..self.ast[list].len() {
966            let operand = self.ast[list][index];
967            let operand = self.asm_operand(operand, first + index, output);
968            operands.push(operand);
969        }
970        self.tast.add_asm_operands(&operands)
971    }
972
973    /// One operand, checked against what its constraint says it is.
974    fn asm_operand(&mut self, operand: ast::AsmOperand, number: usize, output: bool) -> AsmOperand {
975        let span = operand.span;
976        let constraint = self.asm_string(operand.constraint, span);
977        let text = spelling(&self.tast[constraint]);
978        let value = self.expr(operand.value);
979        let ty = self.tast[value].ty;
980        let lvalue = matches!(self.tast[value].category, Category::Lvalue | Category::Bitfield);
981
982        // A structure has no register to sit in, so it travels the only way it can whatever the
983        // constraint says, and a constraint that does not allow memory is turned down rather
984        // than lowered to an address the backend has no reason to expect.
985        let record = is_record(&self.types, ty);
986        let memory = memory_only(&text) || record;
987        if record && !memory_only(&text) {
988            self.statement_unsupported("a structure or a union in a register constraint", span);
989        }
990
991        if output {
992            if !text.starts_with(['=', '+']) {
993                self.report(
994                    Diagnostic::error("output operand constraint lacks '='", span)
995                        .with_code("E0653"),
996                );
997            }
998            if !lvalue {
999                self.report(
1000                    Diagnostic::error("lvalue required in 'asm' statement", span)
1001                        .with_code("E0654"),
1002                );
1003            } else if self.types.quals(ty).has(Qualifiers::CONST) {
1004                let what = self.read_only(value);
1005                self.report(
1006                    Diagnostic::error(format!("read-only {what} used as 'asm' output"), span)
1007                        .with_code("E0655"),
1008                );
1009            }
1010        } else {
1011            if let Some(sign) = text.chars().find(|&ch| ch == '=' || ch == '+') {
1012                self.report(
1013                    Diagnostic::error(format!("input operand constraint contains '{sign}'"), span)
1014                        .with_code("E0656"),
1015                );
1016            }
1017            if memory && !lvalue {
1018                self.report(
1019                    Diagnostic::error(
1020                        format!("memory input {number} is not directly addressable"),
1021                        span,
1022                    )
1023                    .with_code("E0657"),
1024                );
1025            }
1026        }
1027
1028        // An output is written through, and an operand in memory is addressed, so both of those
1029        // stay the object they name. Everything else is read, which is what turns an array into
1030        // a pointer and a variable into its value.
1031        let value = if output || memory { value } else { self.value(value) };
1032        AsmOperand { name: operand.name, constraint, value, memory }
1033    }
1034
1035    /// One of the strings of an assembly statement, copied into the typed tree.
1036    fn asm_string(&mut self, id: ast::StrId, span: Span) -> StrId {
1037        let literal = self.ast[id].clone();
1038        self.asm_narrow(&literal, span);
1039        self.tast.add_string(literal)
1040    }
1041
1042    /// Reports a string of an assembly statement that is not one an assembler can be handed.
1043    fn asm_narrow(&mut self, literal: &StringLiteral, span: Span) {
1044        if !matches!(literal.encoding, Encoding::Plain) {
1045            self.report(Diagnostic::error("wide string literal in 'asm'", span).with_code("E0658"));
1046        }
1047    }
1048
1049    /// The template, with every name in it replaced by the number of the thing it names.
1050    ///
1051    /// gcc numbers the operands and the labels in one sequence, the outputs first and the labels
1052    /// last, and `%[name]` is a way of writing one of those numbers without having to count. So
1053    /// the numbers are what is kept here: the template that reaches an assembler refers to its
1054    /// operands by position, which is what a position is for, and nothing downstream has to
1055    /// carry the names around in order to be able to read one.
1056    fn asm_template(
1057        &mut self,
1058        id: ast::StrId,
1059        outputs: AsmOperandList,
1060        inputs: AsmOperandList,
1061        labels: LabelList,
1062        span: Span,
1063    ) -> StrId {
1064        let mut names: Vec<(String, usize)> = Vec::new();
1065        let mut number = 0;
1066        for list in [outputs, inputs] {
1067            for index in 0..self.tast[list].len() {
1068                if let Some(name) = self.tast[list][index].name {
1069                    names.push((self.text(name).to_owned(), number));
1070                }
1071                number += 1;
1072            }
1073        }
1074        for index in 0..self.tast[labels].len() {
1075            let label = self.tast[labels][index];
1076            let name = self.tast[label].name;
1077            names.push((self.text(name).to_owned(), number));
1078            number += 1;
1079        }
1080        for at in 1..names.len() {
1081            if names[..at].iter().any(|(earlier, _)| *earlier == names[at].0) {
1082                let name = names[at].0.clone();
1083                self.report(
1084                    Diagnostic::error(format!("duplicate asm operand name '{name}'"), span)
1085                        .with_code("E0659"),
1086                );
1087            }
1088        }
1089
1090        let literal = self.ast[id].clone();
1091        self.asm_narrow(&literal, span);
1092        let text = self.asm_numbers(spelling(&literal), &names, span);
1093        let elements = text.chars().map(|ch| ch as u32).collect();
1094        self.tast.add_string(StringLiteral { elements, ..literal })
1095    }
1096
1097    /// One template, with the names in it resolved.
1098    ///
1099    /// A name comes straight after the `%` or after one modifier letter, which is what makes
1100    /// `%[x]`, `%w[x]` and `%l[x]` all one reference and the letter in the middle none of this
1101    /// walk's business. `%%` is a percent sign and is stepped over whole, so the brackets in
1102    /// `%%[x]` are two characters of assembly and not a name.
1103    fn asm_numbers(&mut self, text: String, names: &[(String, usize)], span: Span) -> String {
1104        let chars: Vec<char> = text.chars().collect();
1105        let mut out = String::with_capacity(text.len());
1106        let mut index = 0;
1107        while index < chars.len() {
1108            let ch = chars[index];
1109            out.push(ch);
1110            index += 1;
1111            if ch != '%' {
1112                continue;
1113            }
1114            let letter = chars.get(index).copied();
1115            let open = match letter {
1116                Some('[') => index,
1117                Some(modifier)
1118                    if modifier.is_ascii_alphabetic() && chars.get(index + 1) == Some(&'[') =>
1119                {
1120                    out.push(modifier);
1121                    index += 1;
1122                    index
1123                }
1124                // `%%` is the one escape that hides what comes after it.
1125                Some('%') => {
1126                    out.push('%');
1127                    index += 1;
1128                    continue;
1129                }
1130                _ => continue,
1131            };
1132            let Some(close) = chars[open..].iter().position(|&ch| ch == ']').map(|at| open + at)
1133            else {
1134                continue;
1135            };
1136            let name: String = chars[open + 1..close].iter().collect();
1137            index = close + 1;
1138            match names.iter().find(|(known, _)| *known == name) {
1139                Some(&(_, number)) => out.push_str(&number.to_string()),
1140                None => {
1141                    self.report(
1142                        Diagnostic::error(format!("undefined named operand '{name}'"), span)
1143                            .with_code("E0660"),
1144                    );
1145                    out.push_str(&chars[open..=close].iter().collect::<String>());
1146                }
1147            }
1148        }
1149        out
1150    }
1151
1152    /// `break;`, which needs a loop or a `switch` around it.
1153    fn break_stmt(&mut self, span: Span) -> Stmt {
1154        let inside =
1155            self.body.as_ref().is_some_and(|state| state.loops > 0 || !state.switches.is_empty());
1156        if inside {
1157            return Stmt::Break;
1158        }
1159        self.report(
1160            Diagnostic::error("break statement not within loop or switch", span).with_code("E0631"),
1161        );
1162        Stmt::Error
1163    }
1164
1165    /// `continue;`, which needs a loop and is not satisfied by a `switch`.
1166    fn continue_stmt(&mut self, span: Span) -> Stmt {
1167        if self.body.as_ref().is_some_and(|state| state.loops > 0) {
1168            return Stmt::Continue;
1169        }
1170        self.report(
1171            Diagnostic::error("continue statement not within a loop", span).with_code("E0632"),
1172        );
1173        Stmt::Error
1174    }
1175
1176    /// `return;` or `return expr;`, checked against the return type.
1177    ///
1178    /// Both mismatches are errors. They were warnings for as long as C has had prototypes, and
1179    /// gcc 14 turned them into errors along with the rest of `-Wreturn-mismatch`, because a
1180    /// function that returns nothing where a value was promised hands its caller whatever was in
1181    /// the return register.
1182    fn return_stmt(&mut self, value: Option<ast::ExprId>, span: Span) -> Stmt {
1183        let Some((ret, at)) = self.body.as_ref().map(|state| (state.ret, state.at)) else {
1184            return Stmt::Return(None);
1185        };
1186        let void = is_void(&self.types, ret);
1187        // C89 let a function return without the value it promised and let one return a value it
1188        // had no way to give back, and gcc still takes both at that dialect: the first silently
1189        // and the second with a warning. C99 removed them and gcc has made them errors.
1190        let old = self.cx.std < Std::C99;
1191        let Some(value) = value else {
1192            if !void && !old {
1193                self.report(
1194                    Diagnostic::error(
1195                        "'return' with no value, in function returning non-void",
1196                        span,
1197                    )
1198                    .with_code("E0633")
1199                    .note("declared here".to_owned(), at),
1200                );
1201            }
1202            return Stmt::Return(None);
1203        };
1204        let where_from = self.ast.expr_span(value);
1205        let value = self.expr(value);
1206        let value = self.value(value);
1207        if !void {
1208            return Stmt::Return(Some(self.assign_to(ret, value, where_from, Target::Return)));
1209        }
1210        // C23 6.8.6.4 lets a function returning `void` say `return f();` where `f` returns
1211        // `void`, which is what a wrapper does and what gcc has always accepted.
1212        if !is_void(&self.types, self.tast[value].ty) && !self.is_poisoned(value) {
1213            let said = "'return' with a value, in function returning void";
1214            let diagnostic = if old {
1215                Diagnostic::warning(said, where_from)
1216            } else {
1217                Diagnostic::error(said, where_from)
1218            };
1219            self.report(diagnostic.with_code("E0634").note("declared here".to_owned(), at));
1220        }
1221        let value = self.conv().to_void(value);
1222        Stmt::Return(Some(value))
1223    }
1224
1225    /// The controlling expression of an `if`, a `while`, a `do` or a `for`.
1226    fn controlling(&mut self, cond: ast::ExprId) -> ExprId {
1227        let span = self.ast.expr_span(cond);
1228        let cond = self.expr(cond);
1229        self.condition(cond, span)
1230    }
1231
1232    /// The innermost `switch` being checked.
1233    fn switches(&mut self) -> Option<&mut Switch> {
1234        self.body.as_mut()?.switches.last_mut()
1235    }
1236
1237    /// A statement form that is recognised and not checked yet.
1238    fn statement_unsupported(&mut self, what: &str, span: Span) {
1239        self.report(
1240            Diagnostic::error(format!("{what} is not supported yet"), span).with_code("E0519"),
1241        );
1242    }
1243}
1244
1245/// Whether the scope of one variably modified declaration is open somewhere.
1246///
1247/// The chain from `at` outwards through the declarations it was written inside is every one of
1248/// them whose scope is open there, so this is a walk up that chain looking for the one asked
1249/// about. A jump is allowed when everything the label is inside is something the jump is inside
1250/// as well, and since these nest, asking it of the innermost is asking it of all of them.
1251fn open_at(modified: &[Modified], at: Option<usize>, entered: usize) -> bool {
1252    let mut at = at;
1253    while let Some(index) = at {
1254        if index == entered {
1255            return true;
1256        }
1257        at = modified[index].outer;
1258    }
1259    false
1260}
1261
1262/// The text of one of the strings of an assembly statement.
1263///
1264/// The elements of a narrow literal are its bytes, which is what the assembler is handed. One
1265/// that is not narrow was reported where it was read, and reading it here as characters rather
1266/// than refusing to read it keeps one mistake from becoming two messages.
1267fn spelling(literal: &StringLiteral) -> String {
1268    literal.elements.iter().filter_map(|&element| char::from_u32(element)).collect()
1269}
1270
1271/// Whether a constraint allows memory and allows nothing else.
1272///
1273/// The letters that mean memory are the machine independent ones, `m`, `o` and `V`, and the two
1274/// that mean an address the instruction modifies. Everything else is a register class, a
1275/// constant, a matching operand or a letter the target invented, and each of those is a value.
1276/// A constraint that allows either, `"rm"`, is a value here, which is the answer gcc reaches for
1277/// as well and which is free to give: a value the target cannot hold in a register is a question
1278/// the backend gets to ask about a machine it knows.
1279fn memory_only(constraint: &str) -> bool {
1280    let letters: Vec<char> =
1281        constraint.chars().filter(|ch| !"=+&%#*!?, \t".contains(*ch)).collect();
1282    !letters.is_empty() && letters.iter().all(|ch| "moV<>".contains(*ch))
1283}
1284
1285#[cfg(test)]
1286mod tests {
1287    use rucc_ast::{
1288        ArraySize, AttrList, Builtin, BuiltinSet, DeclSpecs, DeclSpecsId, Declarator, DeclaratorId,
1289        Derived, Quals, TypeSpec,
1290    };
1291    use rucc_base::Interner;
1292    use rucc_lex::{IntConstant, IntConstantType, Remarks};
1293    use rucc_session::Std;
1294    use rucc_target::{TargetInfo, Triple};
1295    use rucc_types::IntKind;
1296
1297    use super::*;
1298    use crate::check::Context;
1299    use crate::print::Printer;
1300
1301    /// The untyped tree a test checks, built by hand.
1302    ///
1303    /// The same shape as the fixtures next door and for the same reason: the checker borrows the
1304    /// interner for as long as it lives, so everything a test needs to name is named before the
1305    /// checker exists.
1306    struct Fixture {
1307        ast: rucc_ast::Ast,
1308        names: Interner,
1309        target: TargetInfo,
1310    }
1311
1312    impl Fixture {
1313        fn new() -> Fixture {
1314            let target =
1315                TargetInfo::new("x86_64-unknown-linux-gnu".parse::<Triple>().expect("a triple"));
1316            Fixture { ast: rucc_ast::Ast::new(), names: Interner::new(), target }
1317        }
1318
1319        fn name(&mut self, text: &str) -> Symbol {
1320            self.names.intern(text)
1321        }
1322
1323        fn int(&mut self, value: u128) -> ast::ExprId {
1324            let ty = IntConstantType::Standard(IntKind::Int);
1325            let id = self.ast.add_int(IntConstant { value, ty, remarks: Remarks::default() });
1326            self.ast.expr(ast::Expr::Int(id), Span::DUMMY)
1327        }
1328
1329        fn use_name(&mut self, text: &str) -> ast::ExprId {
1330            let name = self.name(text);
1331            self.ast.expr(ast::Expr::Name(name), Span::DUMMY)
1332        }
1333
1334        /// A specifier list naming a built-in type, as the keywords that were written.
1335        fn keywords(&mut self, written: &[BuiltinSet]) -> DeclSpecsId {
1336            let mut builtin = Builtin::NONE;
1337            for &keyword in written {
1338                builtin = builtin.add(keyword).expect("a keyword written once");
1339            }
1340            let mut specs = DeclSpecs::empty(Span::DUMMY);
1341            specs.ty = TypeSpec::Builtin(builtin);
1342            self.ast.add_specs(specs)
1343        }
1344
1345        /// `int`, which is what most of these declarations are made of.
1346        fn int_specs(&mut self) -> DeclSpecsId {
1347            self.keywords(&[BuiltinSet::INT])
1348        }
1349
1350        fn declarator(&mut self, name: Option<&str>, derived: &[Derived]) -> DeclaratorId {
1351            let name = name.map(|text| self.name(text));
1352            let derived = self.ast.add_derived_list(derived);
1353            self.ast.add_declarator(Declarator {
1354                name,
1355                name_span: Span::DUMMY,
1356                derived,
1357                span: Span::DUMMY,
1358            })
1359        }
1360
1361        /// `int x;` and the like, as a statement.
1362        fn local(&mut self, specs: DeclSpecsId, name: &str) -> ast::DeclId {
1363            let declarator = self.declarator(Some(name), &[]);
1364            let item = ast::InitDeclarator {
1365                declarator,
1366                init: None,
1367                asm_label: None,
1368                attrs: AttrList::EMPTY,
1369                span: Span::DUMMY,
1370            };
1371            let declarators = self.ast.add_init_declarator_list(&[item]);
1372            self.ast.decl(ast::Decl::Var { specs, declarators }, Span::DUMMY)
1373        }
1374
1375        /// `int name[size];`, which is a variable length array when the size is not a constant.
1376        fn array(&mut self, specs: DeclSpecsId, name: &str, size: ast::ExprId) -> ast::DeclId {
1377            let derived = [Derived::Array {
1378                size: ArraySize::Expr(size),
1379                quals: Quals::NONE,
1380                has_static: false,
1381            }];
1382            let declarator = self.declarator(Some(name), &derived);
1383            let item = ast::InitDeclarator {
1384                declarator,
1385                init: None,
1386                asm_label: None,
1387                attrs: AttrList::EMPTY,
1388                span: Span::DUMMY,
1389            };
1390            let declarators = self.ast.add_init_declarator_list(&[item]);
1391            self.ast.decl(ast::Decl::Var { specs, declarators }, Span::DUMMY)
1392        }
1393
1394        /// `(ty)value`, which is how these tests write an expression of a type they choose.
1395        fn cast(&mut self, specs: DeclSpecsId, value: ast::ExprId) -> ast::ExprId {
1396            let declarator = self.declarator(None, &[]);
1397            let ty = self.ast.add_type_name(ast::TypeName { specs, declarator, span: Span::DUMMY });
1398            self.ast.expr(ast::Expr::Cast { ty, operand: value }, Span::DUMMY)
1399        }
1400
1401        fn stmt(&mut self, stmt: ast::Stmt) -> ast::StmtId {
1402            self.ast.stmt(stmt, Span::DUMMY)
1403        }
1404
1405        /// `{ ... }`, from the statements it holds.
1406        fn block(&mut self, body: &[ast::StmtId]) -> ast::StmtId {
1407            let body = self.ast.add_stmt_list(body);
1408            self.stmt(ast::Stmt::Compound(body))
1409        }
1410
1411        /// `value;`.
1412        fn expr_stmt(&mut self, value: ast::ExprId) -> ast::StmtId {
1413            self.stmt(ast::Stmt::Expr(value))
1414        }
1415
1416        /// `name: body`.
1417        fn labelled(&mut self, text: &str, body: Option<ast::StmtId>) -> ast::StmtId {
1418            let name = self.name(text);
1419            self.stmt(ast::Stmt::Label { name, body, attrs: AttrList::EMPTY })
1420        }
1421
1422        /// `goto name;`.
1423        fn goto(&mut self, text: &str) -> ast::StmtId {
1424            let name = self.name(text);
1425            self.stmt(ast::Stmt::Goto(name))
1426        }
1427
1428        /// `__label__ a, b;`.
1429        fn local_labels(&mut self, names: &[&str]) -> ast::StmtId {
1430            let names: Vec<Symbol> = names.iter().map(|text| self.name(text)).collect();
1431            let names = self.ast.add_symbol_list(&names);
1432            self.stmt(ast::Stmt::LocalLabels(names))
1433        }
1434
1435        /// `case lo: body`, or GNU's `case lo ... hi: body`.
1436        fn case(&mut self, lo: u128, hi: Option<u128>, body: Option<ast::StmtId>) -> ast::StmtId {
1437            let lo = self.int(lo);
1438            let hi = hi.map(|hi| self.int(hi));
1439            self.stmt(ast::Stmt::Case { lo, hi, body })
1440        }
1441
1442        /// `switch (scrutinee) { ... }`.
1443        fn switch(&mut self, scrutinee: ast::ExprId, body: &[ast::StmtId]) -> ast::StmtId {
1444            let body = self.block(body);
1445            self.stmt(ast::Stmt::Switch { scrutinee, body })
1446        }
1447
1448        fn checker(&self) -> Checker<'_> {
1449            Checker::new(&self.ast, Context::new(&self.names, &self.target, Std::C23))
1450        }
1451    }
1452
1453    /// The tree under one statement, which is what most assertions here are about.
1454    fn dump(checker: &Checker<'_>, id: StmtId) -> String {
1455        let mut printer = Printer::new(&checker.tast, &checker.types, checker.cx.names);
1456        printer.stmt(id);
1457        printer.finish()
1458    }
1459
1460    /// What was reported, as the messages alone, notes included.
1461    fn messages(checker: &Checker<'_>) -> Vec<String> {
1462        checker
1463            .errors
1464            .diagnostics()
1465            .iter()
1466            .flat_map(|d| {
1467                std::iter::once(d.message.clone())
1468                    .chain(d.children.iter().map(|n| n.message.clone()))
1469            })
1470            .collect()
1471    }
1472
1473    /// The one message that was reported, which is what most of these tests expect.
1474    fn message(checker: &Checker<'_>) -> String {
1475        let mut reported = messages(checker);
1476        assert_eq!(reported.len(), 1, "expected exactly one diagnostic, got {reported:?}");
1477        reported.pop().expect("one message")
1478    }
1479
1480    /// What was reported, as the severity and the message of each, so that a test can say which
1481    /// of the two a diagnostic is. gcc 14 turned several of these from warnings into errors and
1482    /// the difference is the whole point of some of the tests below.
1483    fn reported(checker: &Checker<'_>) -> Vec<String> {
1484        checker
1485            .errors
1486            .diagnostics()
1487            .iter()
1488            .map(|d| format!("{}: {}", d.severity.as_str(), d.message))
1489            .collect()
1490    }
1491
1492    #[test]
1493    fn a_block_is_a_scope_and_a_name_declared_in_one_is_gone_after_it() {
1494        let mut f = Fixture::new();
1495        let specs = f.int_specs();
1496        let declared = f.local(specs, "x");
1497        let declared = f.stmt(ast::Stmt::Decl(declared));
1498        let inner = f.block(&[declared]);
1499        let use_x = f.use_name("x");
1500        let after = f.expr_stmt(use_x);
1501        let outer = f.block(&[inner, after]);
1502
1503        let mut c = f.checker();
1504        let void = c.types.void();
1505        c.check_stmt(void, outer);
1506
1507        assert_eq!(message(&c), "'x' undeclared (first use in this function)");
1508    }
1509
1510    #[test]
1511    fn a_name_nobody_declared_is_reported_once_per_function_and_not_once_per_use() {
1512        // The wording promises it: `first use in this function` said three times is a sentence
1513        // arguing with itself. A misspelled name written in a loop body is one mistake, and one
1514        // message is what makes the next mistake in the file visible.
1515        let mut f = Fixture::new();
1516        let first = f.use_name("nope");
1517        let first = f.expr_stmt(first);
1518        let second = f.use_name("nope");
1519        let second = f.expr_stmt(second);
1520        let body = f.block(&[first, second]);
1521
1522        let mut c = f.checker();
1523        let void = c.types.void();
1524        let previous = c.open_body(Enclosing::returning(void));
1525        c.check_stmt(void, body);
1526        c.close_body(previous);
1527
1528        assert_eq!(message(&c), "'nope' undeclared (first use in this function)");
1529    }
1530
1531    #[test]
1532    fn an_expression_statement_holds_the_value_and_not_a_conversion_of_it_to_void() {
1533        let mut f = Fixture::new();
1534        let one = f.int(1);
1535        let stmt = f.expr_stmt(one);
1536
1537        let mut c = f.checker();
1538        let void = c.types.void();
1539        let id = c.check_stmt(void, stmt);
1540
1541        assert_eq!(dump(&c, id), "expr\n  const 1 : int\n");
1542        assert!(c.errors.is_empty());
1543    }
1544
1545    #[test]
1546    fn a_statement_expression_has_the_type_of_its_last_statement() {
1547        let mut f = Fixture::new();
1548        let one = f.int(1);
1549        let inner = f.expr_stmt(one);
1550        let body = f.block(&[inner]);
1551        let value = f.ast.expr(ast::Expr::StmtExpr(body), Span::DUMMY);
1552        let stmt = f.expr_stmt(value);
1553
1554        let mut c = f.checker();
1555        let void = c.types.void();
1556        let id = c.check_stmt(void, stmt);
1557
1558        assert_eq!(
1559            dump(&c, id),
1560            "expr\n  stmt-expr : int\n    block\n      expr\n        const 1 : int\n"
1561        );
1562        assert!(c.errors.is_empty());
1563    }
1564
1565    #[test]
1566    fn a_statement_expression_that_ends_in_something_else_is_void() {
1567        let mut f = Fixture::new();
1568        let body = f.block(&[]);
1569        let value = f.ast.expr(ast::Expr::StmtExpr(body), Span::DUMMY);
1570        let stmt = f.expr_stmt(value);
1571
1572        let mut c = f.checker();
1573        let void = c.types.void();
1574        let id = c.check_stmt(void, stmt);
1575
1576        assert_eq!(dump(&c, id), "expr\n  stmt-expr : void\n    block\n");
1577        assert!(c.errors.is_empty());
1578    }
1579
1580    #[test]
1581    fn the_declaration_in_a_for_clause_scopes_to_the_loop_and_not_to_what_follows() {
1582        let mut f = Fixture::new();
1583        let specs = f.int_specs();
1584        let declared = f.local(specs, "i");
1585        let empty = f.stmt(ast::Stmt::Empty);
1586        let loop_stmt = f.stmt(ast::Stmt::For {
1587            init: ForInit::Decl(declared),
1588            cond: None,
1589            step: None,
1590            body: empty,
1591        });
1592        let use_i = f.use_name("i");
1593        let after = f.expr_stmt(use_i);
1594        let outer = f.block(&[loop_stmt, after]);
1595
1596        let mut c = f.checker();
1597        let void = c.types.void();
1598        c.check_stmt(void, outer);
1599
1600        assert_eq!(message(&c), "'i' undeclared (first use in this function)");
1601    }
1602
1603    #[test]
1604    fn a_static_in_a_for_clause_is_accepted_and_only_pedantic_says_anything_about_it() {
1605        let mut f = Fixture::new();
1606        let mut specs = DeclSpecs::empty(Span::DUMMY);
1607        let builtin = Builtin::NONE.add(BuiltinSet::INT).expect("a keyword written once");
1608        specs.ty = TypeSpec::Builtin(builtin);
1609        specs.storage = Some(StorageClass::Static);
1610        let specs = f.ast.add_specs(specs);
1611        let declared = f.local(specs, "i");
1612        let empty = f.stmt(ast::Stmt::Empty);
1613        let loop_stmt = f.stmt(ast::Stmt::For {
1614            init: ForInit::Decl(declared),
1615            cond: None,
1616            step: None,
1617            body: empty,
1618        });
1619
1620        let mut c = f.checker();
1621        let void = c.types.void();
1622        c.check_stmt(void, loop_stmt);
1623        assert!(c.errors.is_empty(), "got {:?}", messages(&c));
1624
1625        let mut c = f.checker();
1626        c.cx.pedantic = true;
1627        let void = c.types.void();
1628        c.check_stmt(void, loop_stmt);
1629        assert_eq!(
1630            reported(&c),
1631            ["warning: declaration of static variable 'i' in 'for' loop initial declaration"]
1632        );
1633    }
1634
1635    #[test]
1636    fn continue_needs_a_loop_and_is_not_satisfied_by_a_switch() {
1637        let mut f = Fixture::new();
1638        let one = f.int(1);
1639        let go_on = f.stmt(ast::Stmt::Continue);
1640        let case = f.stmt(ast::Stmt::Case { lo: one, hi: None, body: Some(go_on) });
1641        let scrutinee = f.int(0);
1642        let switch = f.switch(scrutinee, &[case]);
1643
1644        let mut c = f.checker();
1645        let void = c.types.void();
1646        c.check_stmt(void, switch);
1647
1648        assert_eq!(message(&c), "continue statement not within a loop");
1649    }
1650
1651    #[test]
1652    fn break_is_satisfied_by_a_switch_and_reported_where_there_is_neither() {
1653        let mut f = Fixture::new();
1654        let stop = f.stmt(ast::Stmt::Break);
1655        let scrutinee = f.int(0);
1656        let switch = f.switch(scrutinee, &[stop]);
1657        let loose = f.stmt(ast::Stmt::Break);
1658
1659        let mut c = f.checker();
1660        let void = c.types.void();
1661        c.check_stmt(void, switch);
1662        assert!(c.errors.is_empty(), "got {:?}", messages(&c));
1663
1664        let mut c = f.checker();
1665        let void = c.types.void();
1666        c.check_stmt(void, loose);
1667        assert_eq!(message(&c), "break statement not within loop or switch");
1668    }
1669
1670    #[test]
1671    fn a_goto_resolves_to_a_label_the_function_defines_further_down() {
1672        let mut f = Fixture::new();
1673        let jump = f.goto("done");
1674        let empty = f.stmt(ast::Stmt::Empty);
1675        let target = f.labelled("done", Some(empty));
1676        let body = f.block(&[jump, target]);
1677
1678        let mut c = f.checker();
1679        let void = c.types.void();
1680        let id = c.check_stmt(void, body);
1681
1682        assert_eq!(dump(&c, id), "block\n  goto #0 done\n  label #0 done\n    empty\n");
1683        assert!(c.errors.is_empty());
1684    }
1685
1686    #[test]
1687    fn a_label_that_is_jumped_to_and_never_defined_is_reported_at_the_jump() {
1688        let mut f = Fixture::new();
1689        let jump = f.goto("away");
1690        let body = f.block(&[jump]);
1691
1692        let mut c = f.checker();
1693        let void = c.types.void();
1694        c.check_stmt(void, body);
1695
1696        assert_eq!(message(&c), "label 'away' used but not defined");
1697    }
1698
1699    #[test]
1700    fn the_address_of_a_label_is_a_use_of_it_and_not_a_definition() {
1701        let mut f = Fixture::new();
1702        let away = f.name("away");
1703        let value = f.ast.expr(ast::Expr::LabelAddr(away), Span::DUMMY);
1704        let stmt = f.expr_stmt(value);
1705
1706        let mut c = f.checker();
1707        let void = c.types.void();
1708        let id = c.check_stmt(void, stmt);
1709
1710        assert_eq!(dump(&c, id), "expr\n  label-addr #0 away : void *\n");
1711        assert_eq!(message(&c), "label 'away' used but not defined");
1712    }
1713
1714    #[test]
1715    fn a_goto_into_the_scope_of_a_variable_length_array_is_reported() {
1716        // `int n; goto done; { int a[n]; done: ; }`, which lands in a block where `a` is
1717        // supposed to exist without having gone past the line that makes it.
1718        let mut f = Fixture::new();
1719        let specs = f.int_specs();
1720        let length = f.local(specs, "n");
1721        let length = f.stmt(ast::Stmt::Decl(length));
1722        let jump = f.goto("done");
1723        let size = f.use_name("n");
1724        let array = f.array(specs, "a", size);
1725        let array = f.stmt(ast::Stmt::Decl(array));
1726        let empty = f.stmt(ast::Stmt::Empty);
1727        let target = f.labelled("done", Some(empty));
1728        let inner = f.block(&[array, target]);
1729        let body = f.block(&[length, jump, inner]);
1730
1731        let mut c = f.checker();
1732        let void = c.types.void();
1733        c.check_stmt(void, body);
1734
1735        assert_eq!(
1736            messages(&c),
1737            [
1738                "jump into scope of identifier with variably modified type",
1739                "label 'done' defined here",
1740                "'a' declared here",
1741            ]
1742        );
1743    }
1744
1745    #[test]
1746    fn a_goto_out_of_the_scope_of_a_variable_length_array_is_allowed() {
1747        // `int n; { int a[n]; goto done; } done: ;`, which is the direction C permits: the
1748        // array stops existing rather than starting to.
1749        let mut f = Fixture::new();
1750        let specs = f.int_specs();
1751        let length = f.local(specs, "n");
1752        let length = f.stmt(ast::Stmt::Decl(length));
1753        let size = f.use_name("n");
1754        let array = f.array(specs, "a", size);
1755        let array = f.stmt(ast::Stmt::Decl(array));
1756        let jump = f.goto("done");
1757        let inner = f.block(&[array, jump]);
1758        let empty = f.stmt(ast::Stmt::Empty);
1759        let target = f.labelled("done", Some(empty));
1760        let body = f.block(&[length, inner, target]);
1761
1762        let mut c = f.checker();
1763        let void = c.types.void();
1764        c.check_stmt(void, body);
1765
1766        assert!(c.errors.is_empty(), "got {:?}", messages(&c));
1767    }
1768
1769    #[test]
1770    fn a_goto_into_the_scope_of_an_array_whose_length_is_a_constant_is_allowed() {
1771        // The same shape as the one that is reported, with a length nobody has to work out.
1772        // Nothing about `a` is decided where the declaration is, so there is nothing to skip.
1773        let mut f = Fixture::new();
1774        let specs = f.int_specs();
1775        let jump = f.goto("done");
1776        let size = f.int(4);
1777        let array = f.array(specs, "a", size);
1778        let array = f.stmt(ast::Stmt::Decl(array));
1779        let empty = f.stmt(ast::Stmt::Empty);
1780        let target = f.labelled("done", Some(empty));
1781        let inner = f.block(&[array, target]);
1782        let body = f.block(&[jump, inner]);
1783
1784        let mut c = f.checker();
1785        let void = c.types.void();
1786        c.check_stmt(void, body);
1787
1788        assert!(c.errors.is_empty(), "got {:?}", messages(&c));
1789    }
1790
1791    #[test]
1792    fn one_label_defined_twice_is_an_error_that_points_at_the_first() {
1793        let mut f = Fixture::new();
1794        let first = f.labelled("here", None);
1795        let second = f.labelled("here", None);
1796        let body = f.block(&[first, second]);
1797
1798        let mut c = f.checker();
1799        let void = c.types.void();
1800        c.check_stmt(void, body);
1801
1802        assert_eq!(
1803            messages(&c),
1804            ["duplicate label 'here'", "previous definition of 'here' with type 'void'",]
1805        );
1806    }
1807
1808    #[test]
1809    fn a_local_label_is_undone_when_its_block_ends_so_two_blocks_may_declare_one_name() {
1810        let mut f = Fixture::new();
1811        let sibling = |f: &mut Fixture| {
1812            let declared = f.local_labels(&["done"]);
1813            let jump = f.goto("done");
1814            let target = f.labelled("done", None);
1815            f.block(&[declared, jump, target])
1816        };
1817        let first = sibling(&mut f);
1818        let second = sibling(&mut f);
1819        let body = f.block(&[first, second]);
1820
1821        let mut c = f.checker();
1822        let void = c.types.void();
1823        let id = c.check_stmt(void, body);
1824
1825        assert!(c.errors.is_empty(), "got {:?}", messages(&c));
1826        assert_eq!(
1827            dump(&c, id),
1828            "block\n  block\n    empty\n    goto #0 done\n    label #0 done\n      empty\n  \
1829             block\n    empty\n    goto #1 done\n    label #1 done\n      empty\n"
1830        );
1831    }
1832
1833    #[test]
1834    fn a_local_label_that_nothing_defines_is_reported_when_its_block_ends() {
1835        let mut f = Fixture::new();
1836        let declared = f.local_labels(&["done"]);
1837        let jump = f.goto("done");
1838        let inner = f.block(&[declared, jump]);
1839        let target = f.labelled("done", None);
1840        let body = f.block(&[inner, target]);
1841
1842        let mut c = f.checker();
1843        let void = c.types.void();
1844        c.check_stmt(void, body);
1845
1846        assert_eq!(message(&c), "label 'done' used but not defined");
1847    }
1848
1849    #[test]
1850    fn a_computed_goto_wants_something_that_could_be_an_address() {
1851        let mut f = Fixture::new();
1852        let specs = f.keywords(&[BuiltinSet::DOUBLE]);
1853        let zero = f.int(0);
1854        let target = f.cast(specs, zero);
1855        let stmt = f.stmt(ast::Stmt::GotoExpr(target));
1856
1857        let mut c = f.checker();
1858        let void = c.types.void();
1859        c.check_stmt(void, stmt);
1860
1861        assert_eq!(message(&c), "computed goto must be pointer type");
1862    }
1863
1864    #[test]
1865    fn a_switch_on_something_that_is_not_an_integer_is_an_error() {
1866        let mut f = Fixture::new();
1867        let specs = f.keywords(&[BuiltinSet::DOUBLE]);
1868        let zero = f.int(0);
1869        let scrutinee = f.cast(specs, zero);
1870        let switch = f.switch(scrutinee, &[]);
1871
1872        let mut c = f.checker();
1873        let void = c.types.void();
1874        c.check_stmt(void, switch);
1875
1876        assert_eq!(message(&c), "switch quantity not an integer");
1877    }
1878
1879    #[test]
1880    fn the_cases_of_a_switch_are_one_table_in_the_order_they_were_written() {
1881        let mut f = Fixture::new();
1882        let first = f.case(1, None, None);
1883        let second = f.case(4, Some(6), None);
1884        let default = f.stmt(ast::Stmt::Default { body: None });
1885        let scrutinee = f.int(0);
1886        let switch = f.switch(scrutinee, &[first, second, default]);
1887
1888        let mut c = f.checker();
1889        let void = c.types.void();
1890        let id = c.check_stmt(void, switch);
1891
1892        assert!(c.errors.is_empty(), "got {:?}", messages(&c));
1893        assert_eq!(
1894            dump(&c, id),
1895            "switch\n  cond\n    const 0 : int\n  cases\n    case #0 1\n    case #1 4 ... 6\n    \
1896             default\n  body\n    block\n      case #0\n        empty\n      case #1\n        \
1897             empty\n      default\n        empty\n"
1898        );
1899    }
1900
1901    #[test]
1902    fn two_labels_on_one_statement_are_in_the_table_the_way_round_they_were_written() {
1903        // `case 1: case 2: ;` is one labelled statement inside another, so the checking runs
1904        // inside out. The table is a record of what the user wrote and does not follow it.
1905        let mut f = Fixture::new();
1906        let inner = f.case(2, None, None);
1907        let outer = f.case(1, None, Some(inner));
1908        let scrutinee = f.int(0);
1909        let switch = f.switch(scrutinee, &[outer]);
1910
1911        let mut c = f.checker();
1912        let void = c.types.void();
1913        let id = c.check_stmt(void, switch);
1914
1915        assert!(c.errors.is_empty(), "got {:?}", messages(&c));
1916        assert_eq!(
1917            dump(&c, id),
1918            "switch\n  cond\n    const 0 : int\n  cases\n    case #0 1\n    case #1 2\n  body\n    \
1919             block\n      case #0\n        case #1\n          empty\n"
1920        );
1921    }
1922
1923    #[test]
1924    fn a_case_that_covers_a_value_an_earlier_one_covers_is_a_duplicate() {
1925        let mut f = Fixture::new();
1926        let first = f.case(1, Some(3), None);
1927        let second = f.case(2, None, None);
1928        let scrutinee = f.int(0);
1929        let switch = f.switch(scrutinee, &[first, second]);
1930
1931        let mut c = f.checker();
1932        let void = c.types.void();
1933        c.check_stmt(void, switch);
1934
1935        assert_eq!(messages(&c), ["duplicate case value", "previously used here"]);
1936    }
1937
1938    #[test]
1939    fn a_case_outside_a_switch_is_an_error_and_so_is_a_default() {
1940        let mut f = Fixture::new();
1941        let case = f.case(1, None, None);
1942        let default = f.stmt(ast::Stmt::Default { body: None });
1943        let body = f.block(&[case, default]);
1944
1945        let mut c = f.checker();
1946        let void = c.types.void();
1947        c.check_stmt(void, body);
1948
1949        assert_eq!(
1950            messages(&c),
1951            [
1952                "case label not within a switch statement",
1953                "'default' label not within a switch statement",
1954            ]
1955        );
1956    }
1957
1958    #[test]
1959    fn a_case_label_that_is_not_a_constant_is_an_error() {
1960        let mut f = Fixture::new();
1961        let specs = f.int_specs();
1962        let declared = f.local(specs, "n");
1963        let declared = f.stmt(ast::Stmt::Decl(declared));
1964        let use_n = f.use_name("n");
1965        let case = f.stmt(ast::Stmt::Case { lo: use_n, hi: None, body: None });
1966        let scrutinee = f.int(0);
1967        let switch = f.switch(scrutinee, &[case]);
1968        let body = f.block(&[declared, switch]);
1969
1970        let mut c = f.checker();
1971        let void = c.types.void();
1972        c.check_stmt(void, body);
1973
1974        assert_eq!(message(&c), "case label does not reduce to an integer constant");
1975    }
1976
1977    #[test]
1978    fn a_case_range_that_runs_backwards_is_empty() {
1979        let mut f = Fixture::new();
1980        let case = f.case(6, Some(4), None);
1981        let scrutinee = f.int(0);
1982        let switch = f.switch(scrutinee, &[case]);
1983
1984        let mut c = f.checker();
1985        let void = c.types.void();
1986        c.check_stmt(void, switch);
1987
1988        assert_eq!(reported(&c), ["warning: empty range specified"]);
1989    }
1990
1991    #[test]
1992    fn a_case_is_measured_against_the_type_that_was_written_and_not_the_promoted_one() {
1993        let mut f = Fixture::new();
1994        let specs = f.keywords(&[BuiltinSet::CHAR]);
1995        let zero = f.int(0);
1996        let scrutinee = f.cast(specs, zero);
1997        let case = f.case(300, None, None);
1998        let switch = f.switch(scrutinee, &[case]);
1999
2000        let mut c = f.checker();
2001        let void = c.types.void();
2002        c.check_stmt(void, switch);
2003
2004        assert_eq!(reported(&c), ["warning: case label value exceeds maximum value for type"]);
2005    }
2006
2007    #[test]
2008    fn two_defaults_in_one_switch_are_an_error_that_points_at_the_first() {
2009        let mut f = Fixture::new();
2010        let first = f.stmt(ast::Stmt::Default { body: None });
2011        let second = f.stmt(ast::Stmt::Default { body: None });
2012        let scrutinee = f.int(0);
2013        let switch = f.switch(scrutinee, &[first, second]);
2014
2015        let mut c = f.checker();
2016        let void = c.types.void();
2017        c.check_stmt(void, switch);
2018
2019        assert_eq!(
2020            messages(&c),
2021            ["multiple default labels in one switch", "this is the first default label"]
2022        );
2023    }
2024
2025    #[test]
2026    fn a_nested_switch_keeps_its_cases_to_itself() {
2027        let mut f = Fixture::new();
2028        let inner_case = f.case(1, None, None);
2029        let inner_scrutinee = f.int(0);
2030        let inner = f.switch(inner_scrutinee, &[inner_case]);
2031        let outer_case = f.case(1, None, Some(inner));
2032        let outer_scrutinee = f.int(0);
2033        let outer = f.switch(outer_scrutinee, &[outer_case]);
2034
2035        let mut c = f.checker();
2036        let void = c.types.void();
2037        let id = c.check_stmt(void, outer);
2038
2039        assert!(c.errors.is_empty(), "got {:?}", messages(&c));
2040        assert_eq!(
2041            dump(&c, id),
2042            "switch\n  cond\n    const 0 : int\n  cases\n    case #1 1\n  body\n    block\n      \
2043             case #1\n        switch\n          cond\n            const 0 : int\n          \
2044             cases\n            case #0 1\n          body\n            block\n              case \
2045             #0\n                empty\n"
2046        );
2047    }
2048
2049    #[test]
2050    fn a_bare_return_from_a_function_that_promised_a_value_is_an_error() {
2051        let mut f = Fixture::new();
2052        let stmt = f.stmt(ast::Stmt::Return(None));
2053
2054        let mut c = f.checker();
2055        let int = c.int();
2056        c.check_stmt(int, stmt);
2057
2058        assert_eq!(reported(&c), ["error: 'return' with no value, in function returning non-void"]);
2059        assert_eq!(messages(&c).len(), 2, "the note is attached to it");
2060    }
2061
2062    #[test]
2063    fn a_value_returned_from_a_function_returning_void_is_an_error() {
2064        let mut f = Fixture::new();
2065        let one = f.int(1);
2066        let stmt = f.stmt(ast::Stmt::Return(Some(one)));
2067
2068        let mut c = f.checker();
2069        let void = c.types.void();
2070        c.check_stmt(void, stmt);
2071
2072        assert_eq!(reported(&c), ["error: 'return' with a value, in function returning void"]);
2073    }
2074
2075    #[test]
2076    fn a_void_value_returned_from_a_function_returning_void_is_what_a_wrapper_writes() {
2077        let mut f = Fixture::new();
2078        let specs = f.keywords(&[BuiltinSet::VOID]);
2079        let one = f.int(1);
2080        let value = f.cast(specs, one);
2081        let stmt = f.stmt(ast::Stmt::Return(Some(value)));
2082
2083        let mut c = f.checker();
2084        let void = c.types.void();
2085        c.check_stmt(void, stmt);
2086
2087        assert!(c.errors.is_empty(), "got {:?}", messages(&c));
2088    }
2089
2090    #[test]
2091    fn a_returned_value_is_converted_to_the_return_type() {
2092        let mut f = Fixture::new();
2093        let one = f.int(1);
2094        let stmt = f.stmt(ast::Stmt::Return(Some(one)));
2095
2096        let mut c = f.checker();
2097        let long = c.types.int(IntKind::Long);
2098        let id = c.check_stmt(long, stmt);
2099
2100        assert_eq!(dump(&c, id), "return\n  convert arithmetic : long\n    const 1 : int\n");
2101        assert!(c.errors.is_empty());
2102    }
2103}