Skip to main content

rucc_sema/
eval.rs

1//! Folding a constant expression, which is what an array bound and a `case` label are made of.
2//!
3//! Design: `spec/07-types-and-semantics.md` section 7.6.
4//!
5//! C has a dozen places where an expression has to have a value at translation time: the size of
6//! an array, a `case` label, an enumerator, a bit-field width, `static_assert`, `alignas`, the
7//! width of a `_BitInt`, and an initializer for an object with static storage duration. This is
8//! the one thing that answers all of them, because a compiler with two constant folders has two
9//! answers to `1 << 31` and only one of them is right.
10//!
11//! It folds the typed tree rather than the untyped one. That is not a detail: every conversion
12//! is already a node here, so folding never has to work out that an `int` met a `long`, and the
13//! width every operation happens in is on the node in front of it. The same walk over the
14//! untyped tree would have to redo the conversion rules, and that is the second implementation
15//! that ends up slightly wrong.
16//!
17//! # What it reports and what it hands back
18//!
19//! Two different things go wrong when a constant is wanted, and they belong to two different
20//! places. A division by zero is wrong wherever it is written, so it is reported here. Not being
21//! a constant at all is only wrong because of where the expression is, and gcc's messages say
22//! so: `case label does not reduce to an integer constant` and `enumerator value for 'x' is not
23//! an integer constant` are two sentences about one failure. So [`NotConstant`] is handed back
24//! with the node that stopped it and the caller writes the sentence.
25//!
26//! # Arithmetic
27//!
28//! Integers are held the way [`Const::Int`] holds them, as the low bits of the type extended
29//! into a hundred and twenty eight by its signedness, so every operation is done in [`i128`] and
30//! then wrapped by the [`IntegerInfo`] of the type it happened in. Signed overflow is warned
31//! about and wrapped, which is what gcc does and is the only useful thing to do: the standard
32//! says the program is undefined and a person who wrote `2147483647 + 1` wants to be told.
33//! Unsigned overflow is silent, because it is not overflow.
34//!
35//! Floating operations go to [`rucc_base::float`], which is correctly rounded and does not ask
36//! the host anything. Nothing here looks at the status those return. A constant that overflows
37//! to an infinity or loses a digit is still a constant and gcc says nothing about either, so the
38//! flags are dropped on purpose rather than by omission.
39//!
40//! # Addresses
41//!
42//! `&x`, `&s.field + 3` and a string literal are constants of a different kind: their value is
43//! an object and an offset rather than a number, because nothing knows where the object is
44//! until the linker puts it somewhere. [`Const::Address`] is that pair, and folding one is a
45//! walk down an lvalue adding up member offsets and scaled subscripts rather than a walk over
46//! values, which is why it is a second function and not another arm.
47//!
48//! Two of the rules are worth stating because they are not the obvious ones. A pointer with no
49//! object behind it is not an address at all: `(int *)4` folds to four, and so does `(int *)4 +
50//! 1` once the scaling is done, which is why an enumerator may be written that way and gcc
51//! accepts it. And an address cast to an integer stays an address only where every bit of it
52//! survives, which is what makes `long n = (long)&a;` a static initializer on a sixty four bit
53//! target and `int n = (int)&a;` not one, exactly as gcc has it.
54//!
55//! An address is not an integer constant expression, whatever type it is wearing. So an array
56//! bound, a `case` label and an enumerator each go through [`Eval::integer`], which asks for a
57//! number and gets [`NotConstant`] for any of these.
58//!
59//! # What is not here
60//!
61//! Folding happens where a constant is wanted, so an expression nothing asks about is not
62//! folded and the warnings below are not produced for it. `1/0;` as a statement is silent here
63//! and gcc warns, and that closes as more of the compiler asks this for values.
64
65use std::cmp::Ordering;
66
67use rucc_ast::{BinaryOp, UnaryOp};
68use rucc_base::Interner;
69use rucc_base::float::{Float, Format, Status};
70use rucc_diag::Diagnostic;
71use rucc_target::TargetInfo;
72use rucc_types::{IntegerInfo, TypeId, TypeKind, Types, float_format, integer_info, layout, spell};
73
74use crate::decl::StorageDuration;
75use crate::expr::{Conversion, ExprId, ExprKind};
76use crate::tast::{Address, Base, Const, Tast};
77
78/// Why an expression is not a constant.
79#[derive(Debug, Clone, Copy, PartialEq, Eq)]
80pub struct NotConstant {
81    /// The node the folding stopped at, which is what a diagnostic should point at. It is the
82    /// subexpression and not the whole thing, so that `case 1 + f():` underlines the call.
83    pub at: ExprId,
84    /// Whether that node had already been diagnosed before the folding reached it.
85    ///
86    /// The poisoning rule of `spec/06-lexer-and-parser.md` section 6.8: a caller says nothing
87    /// about one of these, because something has already been said about the same source. It is
88    /// not the same as the folding having warned, which it does about a division by zero and
89    /// which gcc still follows with the caller's message.
90    pub poisoned: bool,
91}
92
93/// The constant folder, over one typed tree.
94#[derive(Debug)]
95pub struct Eval<'a> {
96    tast: &'a Tast,
97    types: &'a Types,
98    target: &'a TargetInfo,
99    names: &'a Interner,
100    diagnostics: Vec<Diagnostic>,
101}
102
103impl<'a> Eval<'a> {
104    /// A folder over a tree, the types it points into, and the target it is being compiled for.
105    #[must_use]
106    pub fn new(
107        tast: &'a Tast,
108        types: &'a Types,
109        target: &'a TargetInfo,
110        names: &'a Interner,
111    ) -> Eval<'a> {
112        Eval { tast, types, target, names, diagnostics: Vec::new() }
113    }
114
115    /// The value of an expression.
116    ///
117    /// # Errors
118    ///
119    /// [`NotConstant`] when the expression is not one, which is an ordinary answer rather than a
120    /// failure: whether it is a diagnostic depends on where the expression was.
121    pub fn constant(&mut self, expr: ExprId) -> Result<Const, NotConstant> {
122        self.eval(expr)
123    }
124
125    /// The value of an expression that has to be an integer constant expression, 6.6p6.
126    ///
127    /// The type has to be an integer type as well as the value being one, which is what rejects
128    /// `enum { a = nullptr };`: the value folds to zero and the expression is still not an
129    /// integer constant expression.
130    ///
131    /// # Errors
132    ///
133    /// [`NotConstant`] when the expression is not one, or is a constant of some other type.
134    pub fn integer(&mut self, expr: ExprId) -> Result<i128, NotConstant> {
135        let value = self.eval(expr)?;
136        let ty = self.tast[expr].ty;
137        match value {
138            Const::Int(value) if self.int_shape(ty).is_some() => Ok(value),
139            _ => Err(self.stop(expr)),
140        }
141    }
142
143    /// What the folding reported, in the order it was found.
144    #[must_use]
145    pub fn finish(self) -> Vec<Diagnostic> {
146        self.diagnostics
147    }
148
149    /// The value of one node.
150    fn eval(&mut self, expr: ExprId) -> Result<Const, NotConstant> {
151        match self.tast[expr].kind {
152            ExprKind::Error => Err(NotConstant { at: expr, poisoned: true }),
153            ExprKind::Const(value) => Ok(self.tast[value]),
154            // The address of an lvalue, which is the one operator whose operand is not folded
155            // to a value first, because an lvalue does not have one.
156            ExprKind::Unary { op: UnaryOp::AddrOf, operand } => {
157                Ok(Const::Address(self.place(operand)?))
158            }
159            ExprKind::Unary { op, operand } => self.unary(expr, op, operand),
160            ExprKind::Binary { op, lhs, rhs } => self.binary(expr, op, lhs, rhs),
161            ExprKind::Cond { cond, then, otherwise } => {
162                // Only the arm that is taken is folded. `1 ? 2 : f()` is a constant and so is
163                // `0 && f()` below, which is 6.6p3 saying the operands of an unevaluated
164                // subexpression do not have to be constants and is what both compilers do.
165                let cond = self.eval(cond)?;
166                let taken = if truth(cond) { then } else { otherwise };
167                self.eval(taken)
168            }
169            ExprKind::Cast(operand) => self.convert(expr, operand),
170            ExprKind::Convert {
171                kind: Conversion::Arithmetic | Conversion::Bool | Conversion::Pointer,
172                operand,
173            } => self.convert(expr, operand),
174            // An array or a function becoming a pointer is the address of the thing itself,
175            // which is why these two go to the lvalue walk rather than to a value.
176            ExprKind::Convert {
177                kind: Conversion::ArrayDecay | Conversion::FunctionDecay,
178                operand,
179            } => Ok(Const::Address(self.place(operand)?)),
180            // A null pointer constant keeps the value it had, since the whole point of the
181            // conversion is that the value was already zero.
182            ExprKind::Convert { kind: Conversion::NullPointer, operand } => self.eval(operand),
183            // What is left is reading an object, which is not a constant however `const` the
184            // object is: `const int n = 1; int a[n];` is a variable length array in C, and it is
185            // this arm that makes it one. And a value being discarded, a call, an assignment, a
186            // comma, a statement expression, a label address, and an lvalue with no `&` in front
187            // of it. The comma is the interesting one: it is a constant nowhere, by 6.6p3, and
188            // `enum { a = (1, 2) };` is an error in gcc rather than a two.
189            _ => Err(self.stop(expr)),
190        }
191    }
192
193    /// A prefix operator applied to a folded operand.
194    fn unary(&mut self, expr: ExprId, op: UnaryOp, operand: ExprId) -> Result<Const, NotConstant> {
195        let value = self.eval(operand)?;
196        match (op, value) {
197            (UnaryOp::Plus, value) => Ok(value),
198            (UnaryOp::Not, value) => Ok(Const::Int(i128::from(!truth(value)))),
199            // `__real__` of a real operand is the operand, and `__imag__` of one is a zero of
200            // the same type. The complex cases cannot arrive: there is no complex constant for
201            // the operand to have folded to, so it fails above.
202            (UnaryOp::Real, value) => Ok(value),
203            (UnaryOp::Imag, _) => self.zero(expr),
204            (UnaryOp::Minus, Const::Float(value)) => Ok(Const::Float(value.negated())),
205            (UnaryOp::Minus | UnaryOp::BitNot, Const::Int(value)) => {
206                let Some(info) = self.int_shape(self.tast[operand].ty) else {
207                    return Err(self.stop(expr));
208                };
209                if matches!(op, UnaryOp::BitNot) {
210                    return Ok(Const::Int(info.wrap(!value)));
211                }
212                // The only negation that overflows is of the least value, whose negative is one
213                // past the greatest. gcc warns and wraps, and wrapping is what the hardware
214                // does with the same bits.
215                let negated = info.wrap(value.wrapping_neg());
216                if info.signed && value == least(info) {
217                    self.overflow(expr, negated);
218                }
219                Ok(Const::Int(negated))
220            }
221            // A dereference, an address, an increment or a decrement. None of them is a
222            // constant, and the last two are not even allowed to appear in one.
223            _ => Err(self.stop(expr)),
224        }
225    }
226
227    /// A binary operator applied to folded operands.
228    fn binary(
229        &mut self,
230        expr: ExprId,
231        op: BinaryOp,
232        lhs: ExprId,
233        rhs: ExprId,
234    ) -> Result<Const, NotConstant> {
235        match op {
236            BinaryOp::LogAnd | BinaryOp::LogOr => {
237                let wanted = matches!(op, BinaryOp::LogOr);
238                let left = self.eval(lhs)?;
239                if truth(left) == wanted {
240                    return Ok(Const::Int(i128::from(wanted)));
241                }
242                let right = self.eval(rhs)?;
243                Ok(Const::Int(i128::from(truth(right))))
244            }
245            BinaryOp::Shl | BinaryOp::Shr => self.shift(expr, op, lhs, rhs),
246            _ => {
247                let left = self.eval(lhs)?;
248                let right = self.eval(rhs)?;
249                if self.pointee_size(self.tast[lhs].ty).is_some()
250                    || self.pointee_size(self.tast[rhs].ty).is_some()
251                {
252                    return self.pointer_binary(expr, op, lhs, rhs, left, right);
253                }
254                match (left, right) {
255                    (Const::Int(left), Const::Int(right)) => {
256                        // The signedness and the width come from an operand and not from the
257                        // node, because a comparison has type `int` however wide the things it
258                        // compared were.
259                        let Some(info) = self.int_shape(self.tast[lhs].ty) else {
260                            return Err(self.stop(expr));
261                        };
262                        self.int_binary(expr, op, left, right, info)
263                    }
264                    (Const::Float(left), Const::Float(right)) => {
265                        self.float_binary(expr, op, left, right)
266                    }
267                    // The two operands of an arithmetic operator have one type by the time they
268                    // are here, so a mismatched pair is pointer arithmetic or a tree that did
269                    // not check. Neither has a value to give.
270                    _ => Err(self.stop(expr)),
271                }
272            }
273        }
274    }
275
276    /// A binary operator on two integers of the same type.
277    fn int_binary(
278        &mut self,
279        expr: ExprId,
280        op: BinaryOp,
281        left: i128,
282        right: i128,
283        info: IntegerInfo,
284    ) -> Result<Const, NotConstant> {
285        if let Some(ordering) = compare_int(op, left, right, info) {
286            return Ok(Const::Int(i128::from(ordering)));
287        }
288        let value = match op {
289            BinaryOp::BitAnd => left & right,
290            BinaryOp::BitOr => left | right,
291            BinaryOp::BitXor => left ^ right,
292            BinaryOp::Div | BinaryOp::Rem if right == 0 => {
293                // A warning and not an error, because that is what gcc calls it, and then no
294                // value, because there is not one. The caller adds what the context calls it.
295                self.warn(expr, "division by zero", "E0521");
296                return Err(NotConstant { at: expr, poisoned: false });
297            }
298            BinaryOp::Add | BinaryOp::Sub | BinaryOp::Mul | BinaryOp::Div | BinaryOp::Rem => {
299                return self.arithmetic(expr, op, left, right, info);
300            }
301            // The shifts and the logical operators went elsewhere, and the comparisons were
302            // answered above, so what is left is an operator with no meaning on two integers.
303            _ => return Err(self.stop(expr)),
304        };
305        Ok(Const::Int(info.wrap(value)))
306    }
307
308    /// The four operations that can leave the range of the type they happened in, and `%`.
309    fn arithmetic(
310        &mut self,
311        expr: ExprId,
312        op: BinaryOp,
313        left: i128,
314        right: i128,
315        info: IntegerInfo,
316    ) -> Result<Const, NotConstant> {
317        if !info.signed {
318            let (left, right) = (left as u128, right as u128);
319            let value = match op {
320                BinaryOp::Add => left.wrapping_add(right),
321                BinaryOp::Sub => left.wrapping_sub(right),
322                BinaryOp::Mul => left.wrapping_mul(right),
323                BinaryOp::Div => left / right,
324                _ => left % right,
325            };
326            return Ok(Const::Int(info.wrap(value as i128)));
327        }
328        let (exact, wrapped) = match op {
329            BinaryOp::Add => (left.checked_add(right), left.wrapping_add(right)),
330            BinaryOp::Sub => (left.checked_sub(right), left.wrapping_sub(right)),
331            BinaryOp::Mul => (left.checked_mul(right), left.wrapping_mul(right)),
332            BinaryOp::Div => (left.checked_div(right), left.wrapping_div(right)),
333            _ => (left.checked_rem(right), left.wrapping_rem(right)),
334        };
335        let value = info.wrap(wrapped);
336        // The least value divided by minus one is the one signed division that leaves the range,
337        // and gcc calls the remainder of the same pair an overflow too. It is right to: the
338        // remainder is zero and the instruction that computes it traps exactly as the quotient
339        // does, so a program that reaches either has the same problem.
340        let extreme =
341            matches!(op, BinaryOp::Div | BinaryOp::Rem) && right == -1 && left == least(info);
342        if extreme || exact.is_none_or(|exact| !info.holds(exact)) {
343            self.overflow(expr, value);
344        }
345        Ok(Const::Int(value))
346    }
347
348    /// A binary operator on two floating values of the same format.
349    fn float_binary(
350        &mut self,
351        expr: ExprId,
352        op: BinaryOp,
353        left: Float,
354        right: Float,
355    ) -> Result<Const, NotConstant> {
356        if let Some(ordering) = compare_float(op, left, right) {
357            return Ok(Const::Int(i128::from(ordering)));
358        }
359        // The status is dropped on purpose. Overflowing to an infinity and dropping a digit are
360        // both things a constant is allowed to do and neither compiler says a word about either.
361        let (value, _) = match op {
362            BinaryOp::Add => left.sum(right),
363            BinaryOp::Sub => left.difference(right),
364            BinaryOp::Mul => left.product(right),
365            BinaryOp::Div => left.quotient(right),
366            // `%` and the bitwise operators have no floating operands, so a tree with one here
367            // did not check.
368            _ => return Err(self.stop(expr)),
369        };
370        Ok(Const::Float(value))
371    }
372
373    /// `<<` or `>>`, whose operands have their own types and whose result has the left one's.
374    fn shift(
375        &mut self,
376        expr: ExprId,
377        op: BinaryOp,
378        lhs: ExprId,
379        rhs: ExprId,
380    ) -> Result<Const, NotConstant> {
381        let left = self.eval(lhs)?;
382        let right = self.eval(rhs)?;
383        let (Const::Int(value), Const::Int(count)) = (left, right) else {
384            return Err(self.stop(expr));
385        };
386        let (Some(info), Some(counts)) =
387            (self.int_shape(self.tast[lhs].ty), self.int_shape(self.tast[rhs].ty))
388        else {
389            return Err(self.stop(expr));
390        };
391        let side = if matches!(op, BinaryOp::Shl) { "left" } else { "right" };
392        if counts.signed && count < 0 {
393            self.warn(expr, format!("{side} shift count is negative"), "E0522");
394            return Err(NotConstant { at: expr, poisoned: false });
395        }
396        // Negative counts are gone, so the bits are the magnitude whichever type they came from,
397        // which is what makes a hundred and twenty eight bit unsigned count compare correctly.
398        let count = count as u128;
399        if count >= u128::from(info.width) {
400            self.warn(expr, format!("{side} shift count >= width of type"), "E0523");
401            // gcc still gives it a value, and the value is what shifting the whole width away
402            // leaves: nothing, or the sign repeated when the shift was an arithmetic right one.
403            let sign = matches!(op, BinaryOp::Shr) && info.signed && value < 0;
404            return Ok(Const::Int(if sign { -1 } else { 0 }));
405        }
406        let count = count as u32;
407        let value = match (op, info.signed) {
408            (BinaryOp::Shr, true) => value >> count,
409            (BinaryOp::Shr, false) => ((value as u128) >> count) as i128,
410            // A left shift out of the range of a signed type is undefined in C and gcc folds it
411            // without a word, which is the sensible answer: `1 << 31` is how a person writes the
412            // sign bit and warning about it would be noise in every real program.
413            _ => value.wrapping_shl(count),
414        };
415        Ok(Const::Int(info.wrap(value)))
416    }
417
418    /// The address of an lvalue, walked down rather than folded up.
419    ///
420    /// This is the half of the folding that does not have values to work with. A member adds its
421    /// own offset to whatever holds it and a subscript adds its index scaled by the element, so
422    /// what comes out is the object at the bottom and the distance travelled to reach it.
423    fn place(&mut self, expr: ExprId) -> Result<Address, NotConstant> {
424        match self.tast[expr].kind {
425            ExprKind::Error => Err(NotConstant { at: expr, poisoned: true }),
426            // An automatic object has no address until the frame holding it exists, so it is
427            // not a constant, and neither is a parameter for the same reason.
428            ExprKind::Decl(decl) | ExprKind::CompoundLiteral(decl)
429                if self.tast[decl].duration != StorageDuration::Automatic =>
430            {
431                Ok(Address { base: Base::Decl(decl), offset: 0 })
432            }
433            ExprKind::Str(id) => Ok(Address { base: Base::Str(id), offset: 0 }),
434            ExprKind::Member { base, field } => {
435                let mut address = self.place(base)?;
436                let TypeKind::Record(record) = bare(self.types, self.tast[base].ty) else {
437                    return Err(self.stop(expr));
438                };
439                let Some(field) =
440                    self.types.record_info(record).fields.get(field as usize).copied()
441                else {
442                    return Err(self.stop(expr));
443                };
444                address.offset += i128::from(field.byte_offset());
445                Ok(address)
446            }
447            ExprKind::Subscript { base, index } => {
448                let base = self.eval(base)?;
449                let Const::Int(index) = self.eval(index)? else { return Err(self.stop(expr)) };
450                let size = i128::from(self.size_of(self.tast[expr].ty));
451                let Const::Address(mut address) = base else { return Err(self.stop(expr)) };
452                address.offset += index.wrapping_mul(size);
453                Ok(address)
454            }
455            // `&*p` is `p`, which is what makes `int *q = &*a;` a constant and is not a
456            // simplification: the dereference of an address constant is the object it names.
457            ExprKind::Unary { op: UnaryOp::Deref, operand } => match self.eval(operand)? {
458                Const::Address(address) => Ok(address),
459                _ => Err(self.stop(expr)),
460            },
461            _ => Err(self.stop(expr)),
462        }
463    }
464
465    /// An operator with a pointer on at least one side.
466    ///
467    /// Which side the pointer is on is read off the types rather than off the folded values,
468    /// because `(int *)4` folds to a number and is still a pointer, and the scaling that
469    /// `p + 1` does is decided by what `p` points at and not by what it happened to fold to.
470    fn pointer_binary(
471        &mut self,
472        expr: ExprId,
473        op: BinaryOp,
474        lhs: ExprId,
475        rhs: ExprId,
476        left: Const,
477        right: Const,
478    ) -> Result<Const, NotConstant> {
479        let (left_step, right_step) =
480            (self.pointee_size(self.tast[lhs].ty), self.pointee_size(self.tast[rhs].ty));
481        match (op, left_step, right_step) {
482            (BinaryOp::Add, Some(step), None) => self.offset_by(expr, left, right, step),
483            (BinaryOp::Add, None, Some(step)) => self.offset_by(expr, right, left, step),
484            (BinaryOp::Sub, Some(step), None) => self.offset_by(expr, left, negate(right), step),
485            // A difference of two pointers, which is a number and not an address however far
486            // from home the two are. It needs the same object under both, since the distance
487            // between two objects is not decided until they are placed.
488            (BinaryOp::Sub, Some(step), Some(_)) if step != 0 => {
489                let distance = match (left, right) {
490                    (Const::Address(left), Const::Address(right)) if left.base == right.base => {
491                        left.offset - right.offset
492                    }
493                    (Const::Int(left), Const::Int(right)) => left - right,
494                    _ => return Err(self.stop(expr)),
495                };
496                Ok(Const::Int(distance / i128::from(step)))
497            }
498            (_, Some(_), _) | (_, _, Some(_)) => self.pointer_compare(expr, op, left, right),
499            _ => Err(self.stop(expr)),
500        }
501    }
502
503    /// A pointer moved by a number of elements, whichever kind of pointer it folded to.
504    fn offset_by(
505        &mut self,
506        expr: ExprId,
507        pointer: Const,
508        count: Const,
509        step: u64,
510    ) -> Result<Const, NotConstant> {
511        let Const::Int(count) = count else { return Err(self.stop(expr)) };
512        let distance = count.wrapping_mul(i128::from(step));
513        match pointer {
514            Const::Address(address) => Ok(Const::Address(Address {
515                base: address.base,
516                offset: address.offset.wrapping_add(distance),
517            })),
518            Const::Int(value) => Ok(Const::Int(value.wrapping_add(distance))),
519            Const::Float(_) => Err(self.stop(expr)),
520        }
521    }
522
523    /// A comparison with a pointer on at least one side.
524    fn pointer_compare(
525        &mut self,
526        expr: ExprId,
527        op: BinaryOp,
528        left: Const,
529        right: Const,
530    ) -> Result<Const, NotConstant> {
531        let ordering = match (left, right) {
532            (Const::Address(left), Const::Address(right)) if left.base == right.base => {
533                left.offset.cmp(&right.offset)
534            }
535            // Two pointers that are both numbers, which compare as the unsigned values they are.
536            (Const::Int(left), Const::Int(right)) => (left as u128).cmp(&(right as u128)),
537            // An object has an address and a null pointer does not point at one, so the two are
538            // never the same. Which of them was written first does not matter to `==` or `!=`,
539            // and nothing else about the pair can be answered before the object is placed.
540            (Const::Address(_), Const::Int(0)) | (Const::Int(0), Const::Address(_)) => {
541                return match op {
542                    BinaryOp::Eq => Ok(Const::Int(0)),
543                    BinaryOp::Ne => Ok(Const::Int(1)),
544                    _ => Err(self.stop(expr)),
545                };
546            }
547            _ => return Err(self.stop(expr)),
548        };
549        match holds(op, ordering) {
550            Some(value) => Ok(Const::Int(i128::from(value))),
551            None => Err(self.stop(expr)),
552        }
553    }
554
555    /// How far apart two elements of a pointer's target type are, and [`None`] for a non-pointer.
556    ///
557    /// A pointer to `void` or to a function steps by one byte, which is what GNU C says and what
558    /// every program that does arithmetic on a `void *` is written against.
559    fn pointee_size(&self, ty: TypeId) -> Option<u64> {
560        match bare(self.types, ty) {
561            TypeKind::Pointer(target) => Some(match bare(self.types, target) {
562                TypeKind::Void | TypeKind::Function(_) => 1,
563                _ => self.size_of(target),
564            }),
565            _ => None,
566        }
567    }
568
569    /// The size of a type in bytes, and zero for one that has no size to give.
570    fn size_of(&self, ty: TypeId) -> u64 {
571        layout(self.types, ty, self.target).map_or(0, |layout| layout.size)
572    }
573
574    /// A folded value converted to the type of the node it is under.
575    fn convert(&mut self, expr: ExprId, operand: ExprId) -> Result<Const, NotConstant> {
576        let value = self.eval(operand)?;
577        let (from, to) = (self.tast[operand].ty, self.tast[expr].ty);
578        match self.converted(value, from, to) {
579            Some(value) => Ok(value),
580            None => Err(self.stop(expr)),
581        }
582    }
583
584    /// A value converted to `ty`, and [`None`] when `ty` is not one a number converts to.
585    ///
586    /// The conversion that changes the value is the caller's to warn about, not this one's:
587    /// `(char)300` is silent in gcc and `char c = 300;` is not, and both of them come through
588    /// here.
589    fn converted(&self, value: Const, from: TypeId, to: TypeId) -> Option<Const> {
590        match bare(self.types, to) {
591            // Not a truncation to one bit. `(bool)2` is one and `(bool)0.5` is one, which is
592            // why this is a comparison against zero and not the integer case below.
593            TypeKind::Bool => Some(Const::Int(i128::from(truth(value)))),
594            TypeKind::Int(_) | TypeKind::BitInt { .. } | TypeKind::Enum(_) => {
595                let info = self.int_shape(to)?;
596                match value {
597                    Const::Int(value) => Some(Const::Int(info.wrap(value))),
598                    // Out of range is undefined behaviour rather than a value, and what comes
599                    // back is the nearest end of the range with a flag on it. The flag is the
600                    // caller's to warn about and is why this drops it rather than reads it.
601                    Const::Float(value) => {
602                        Some(Const::Int(value.to_integer(info.width, info.signed).0))
603                    }
604                    // An address written as a number is still an address, and it survives only
605                    // where every bit of it does. That is the whole difference between gcc
606                    // taking `long n = (long)&a;` as a static initializer and refusing
607                    // `int n = (int)&a;`, and it is measured in bits and not in names.
608                    Const::Address(address) => (u64::from(info.width) == self.size_of(from) * 8)
609                        .then_some(Const::Address(address)),
610                }
611            }
612            TypeKind::Float(kind) => {
613                let format = float_format(kind, self.target);
614                let (value, _) = match value {
615                    Const::Float(value) => value.to_format(format),
616                    Const::Int(value) => match self.int_shape(from) {
617                        Some(info) if !info.signed => Float::from_unsigned(value as u128, format),
618                        _ => Float::from_signed(value, format),
619                    },
620                    // No cast turns an address into a floating value, so a tree with one here
621                    // did not check.
622                    Const::Address(_) => return None,
623                };
624                Some(Const::Float(value))
625            }
626            // A pointer keeps whatever it was, since a cast between pointer types moves nothing:
627            // an address stays the same address and a number stays the same number.
628            TypeKind::Pointer(_) => match value {
629                Const::Int(_) | Const::Address(_) => Some(value),
630                Const::Float(_) => None,
631            },
632            // `void`, a record, a complex type. None of them has a constant to be.
633            _ => None,
634        }
635    }
636
637    /// A zero of the type of a node, for the `__imag__` of something real.
638    fn zero(&mut self, expr: ExprId) -> Result<Const, NotConstant> {
639        let ty = self.tast[expr].ty;
640        if self.int_shape(ty).is_some() {
641            return Ok(Const::Int(0));
642        }
643        match self.float_shape(ty) {
644            Some(format) => Ok(Const::Float(Float::zero(format, false))),
645            None => Err(self.stop(expr)),
646        }
647    }
648
649    /// The shape of an integer type, over the tree's own types and target.
650    fn int_shape(&self, ty: TypeId) -> Option<IntegerInfo> {
651        int_shape(self.types, ty, self.target)
652    }
653
654    /// The format of a real floating type, and [`None`] for anything else.
655    fn float_shape(&self, ty: TypeId) -> Option<Format> {
656        match bare(self.types, ty) {
657            TypeKind::Float(kind) => Some(float_format(kind, self.target)),
658            _ => None,
659        }
660    }
661
662    /// The answer for a node that is not a constant and that nothing has been said about.
663    fn stop(&self, expr: ExprId) -> NotConstant {
664        NotConstant { at: expr, poisoned: false }
665    }
666
667    /// Warns that an operation left the range of the type it happened in.
668    fn overflow(&mut self, expr: ExprId, value: i128) {
669        let ty = spell(self.types, self.names, self.tast[expr].ty);
670        let message = format!("integer overflow in expression of type '{ty}' results in '{value}'");
671        self.warn(expr, message, "E0524");
672    }
673
674    /// Reports a warning about a node.
675    fn warn(&mut self, expr: ExprId, message: impl Into<String>, code: &'static str) {
676        let span = self.tast.expr_span(expr);
677        self.diagnostics.push(Diagnostic::warning(message.into(), span).with_code(code));
678    }
679}
680
681/// The shape of an integer type, and [`None`] for anything a folded constant cannot hold.
682///
683/// A `_BitInt` wider than a hundred and twenty eight bits is the one integer type in that second
684/// group. It is refused where it is written rather than folded to a wrong answer here.
685pub(crate) fn int_shape(types: &Types, ty: TypeId, target: &TargetInfo) -> Option<IntegerInfo> {
686    let info = integer_info(types, ty, target)?;
687    (info.width > 0 && info.width <= 128).then_some(info)
688}
689
690/// Whether a constant is true, which is a comparison against zero and not a look at the bits.
691///
692/// A nan is true, because it is not equal to zero, and so is a negative zero's negation of
693/// itself: the test is `!= 0` and `-0.0 == 0.0`.
694fn truth(value: Const) -> bool {
695    match value {
696        Const::Int(value) => value != 0,
697        Const::Float(value) => !value.is_zero(),
698        // An object has an address and no object is at zero, so an address is always true.
699        Const::Address(_) => true,
700    }
701}
702
703/// A folded integer negated, for the `p - n` that is written as an offset of minus `n`.
704fn negate(value: Const) -> Const {
705    match value {
706        Const::Int(value) => Const::Int(value.wrapping_neg()),
707        other => other,
708    }
709}
710
711/// The result of a comparison of two integers, and [`None`] when `op` is not a comparison.
712fn compare_int(op: BinaryOp, left: i128, right: i128, info: IntegerInfo) -> Option<bool> {
713    let ordering = if info.signed {
714        left.cmp(&right)
715    } else {
716        // The bits are the value for an unsigned type of any width, including the hundred and
717        // twenty eight bit one whose top bit is sitting in the sign of the `i128`.
718        (left as u128).cmp(&(right as u128))
719    };
720    holds(op, ordering)
721}
722
723/// The result of a comparison of two floating values, and [`None`] when `op` is not one.
724fn compare_float(op: BinaryOp, left: Float, right: Float) -> Option<bool> {
725    match left.compare(right) {
726        Some(ordering) => holds(op, ordering),
727        // Unordered, so one of them is a nan. Every comparison against one is false except the
728        // inequality, which is the whole of why `x != x` is the test for a nan. The ordering
729        // asked about first is only there to answer whether `op` is a comparison at all.
730        None if holds(op, Ordering::Equal).is_some() => Some(matches!(op, BinaryOp::Ne)),
731        None => None,
732    }
733}
734
735/// Whether an ordering satisfies a comparison operator, and [`None`] for anything else.
736fn holds(op: BinaryOp, ordering: Ordering) -> Option<bool> {
737    Some(match op {
738        BinaryOp::Lt => ordering.is_lt(),
739        BinaryOp::Gt => ordering.is_gt(),
740        BinaryOp::Le => ordering.is_le(),
741        BinaryOp::Ge => ordering.is_ge(),
742        BinaryOp::Eq => ordering.is_eq(),
743        BinaryOp::Ne => ordering.is_ne(),
744        _ => return None,
745    })
746}
747
748/// The least value a signed type of this shape holds, which is meaningless for an unsigned one.
749fn least(info: IntegerInfo) -> i128 {
750    info.wrap(1i128 << info.width.saturating_sub(1))
751}
752
753/// What a type is once the sugar, the qualifiers and `_Atomic` are off it.
754///
755/// The same peel `rucc_types` does behind each of its own predicates, spelled out here because
756/// this needs the kind itself rather than an answer about it.
757pub(crate) fn bare(types: &Types, ty: TypeId) -> TypeKind {
758    match types.kind(types.canonical(ty)) {
759        TypeKind::Atomic(inner) => types.kind(types.canonical(inner)),
760        other => other,
761    }
762}
763
764/// A folded integer as a diagnostic writes it, which needs the type to know whether the top bit
765/// is a sign or a digit.
766pub(crate) fn spell_int(value: i128, info: IntegerInfo) -> String {
767    if info.signed { format!("{value}") } else { format!("{}", value as u128) }
768}
769
770/// A folded value stored in an integer type of this shape, which is what the conversion leaves.
771pub(crate) fn narrowed(value: Const, info: IntegerInfo) -> i128 {
772    match value {
773        Const::Int(value) => info.wrap(value),
774        Const::Float(value) => value.to_integer(info.width, info.signed).0,
775        // Nothing narrows an address, since the caller asked for a number and got one of these
776        // instead. Zero is a value it will not use.
777        Const::Address(_) => 0,
778    }
779}
780
781/// A folded constant as a diagnostic writes it.
782///
783/// A floating value is written in hexadecimal, which is the one place the wording here is not
784/// gcc's. gcc prints `1.0e+40` and printing that needs a binary to decimal conversion that this
785/// compiler does not have yet, and `0x1.d6329f1c35ca5p+132` is at least the same number.
786pub(crate) fn spell_const(value: Const, info: Option<IntegerInfo>) -> String {
787    match value {
788        Const::Int(value) => match info {
789            Some(info) => spell_int(value, info),
790            None => format!("{value}"),
791        },
792        Const::Float(value) => value.to_hex(),
793        Const::Address(address) => {
794            let base = match address.base {
795                Base::Decl(decl) => decl.index(),
796                Base::Str(id) => id.index(),
797            };
798            format!("&#{base} + {}", address.offset)
799        }
800    }
801}
802
803/// Whether converting a folded value to a type of this shape changes it, gcc's `-Woverflow`.
804///
805/// The rule is not the obvious one and is worth stating. `signed char c = 200;` and `unsigned
806/// char u = -1;` both change the value and gcc warns about neither, because in each the bits are
807/// all there and it is only the sign that moved, which is a different option's business.
808/// `unsigned char u = 300;` is warned about, because three hundred does not fit in eight bits
809/// whichever way round they are read. So the question is whether the value fits in neither
810/// signedness of the target's width.
811pub(crate) fn overflows(value: Const, info: IntegerInfo) -> bool {
812    match value {
813        Const::Int(value) => {
814            !IntegerInfo::new(true, info.width).holds(value)
815                && !IntegerInfo::new(false, info.width).holds(value)
816        }
817        // A conversion that had to saturate, which is the flag the float arithmetic raises for
818        // a value out of range and for a nan. Dropping a fraction is not overflow and gcc does
819        // not warn about `char c = 3.5;` either.
820        Const::Float(value) => value.to_integer(info.width, info.signed).1.has(Status::INVALID),
821        // An address is as wide as a pointer or it would not have got this far, so nothing about
822        // it is lost.
823        Const::Address(_) => false,
824    }
825}
826
827#[cfg(test)]
828mod tests {
829    use rucc_ast as ast;
830    use rucc_ast::{
831        ArraySize, AttrList, Builtin, BuiltinSet, DeclSpecs, Declarator, Derived, Quals,
832        StorageClass, TypeSpec,
833    };
834    use rucc_base::Symbol;
835    use rucc_base::float::Format;
836    use rucc_diag::Span;
837    use rucc_lex::{
838        Encoding, FloatConstant, FloatConstantType, IntConstant, IntConstantType, Remarks,
839        StringLiteral,
840    };
841    use rucc_session::Std;
842    use rucc_target::{TargetInfo, Triple};
843    use rucc_types::IntKind;
844
845    use super::*;
846    use crate::check::{Checker, Context};
847
848    /// The untyped tree a test folds, built by hand.
849    ///
850    /// The same shape as the one the checking tests use and for the same reason: the checker
851    /// borrows the interner for as long as it lives, so everything a test needs to name is
852    /// named before the checker exists.
853    struct Fixture {
854        ast: ast::Ast,
855        names: Interner,
856        target: TargetInfo,
857    }
858
859    impl Fixture {
860        fn new() -> Fixture {
861            let target =
862                TargetInfo::new("x86_64-unknown-linux-gnu".parse::<Triple>().expect("a triple"));
863            Fixture { ast: ast::Ast::new(), names: Interner::new(), target }
864        }
865
866        fn expr(&mut self, expr: ast::Expr) -> ast::ExprId {
867            self.ast.expr(expr, Span::DUMMY)
868        }
869
870        fn int(&mut self, value: u128, kind: IntKind) -> ast::ExprId {
871            let ty = IntConstantType::Standard(kind);
872            let id = self.ast.add_int(IntConstant { value, ty, remarks: Remarks::default() });
873            self.expr(ast::Expr::Int(id))
874        }
875
876        /// A constant of a bit precise type, which is the one integer type that does not promote.
877        fn bit_int(&mut self, value: u128, signed: bool, width: u32) -> ast::ExprId {
878            let ty = IntConstantType::BitInt { signed, width };
879            let id = self.ast.add_int(IntConstant { value, ty, remarks: Remarks::default() });
880            self.expr(ast::Expr::Int(id))
881        }
882
883        fn double(&mut self, text: &str) -> ast::ExprId {
884            let (value, _) = Float::parse(text, Format::Double).expect("a float");
885            let constant = FloatConstant {
886                value,
887                ty: FloatConstantType::Double,
888                imaginary: false,
889                remarks: Remarks::default(),
890            };
891            let id = self.ast.add_float(constant);
892            self.expr(ast::Expr::Float(id))
893        }
894
895        fn binary(&mut self, op: BinaryOp, lhs: ast::ExprId, rhs: ast::ExprId) -> ast::ExprId {
896            self.expr(ast::Expr::Binary { op, lhs, rhs })
897        }
898
899        fn unary(&mut self, op: UnaryOp, operand: ast::ExprId) -> ast::ExprId {
900            self.expr(ast::Expr::Unary { op, operand })
901        }
902
903        fn name(&mut self, text: &str) -> Symbol {
904            self.names.intern(text)
905        }
906
907        fn use_name(&mut self, text: &str) -> ast::ExprId {
908            let name = self.name(text);
909            self.expr(ast::Expr::Name(name))
910        }
911
912        fn string(&mut self, text: &str) -> ast::ExprId {
913            let elements = text.chars().map(|c| c as u32).collect();
914            let id = self.ast.add_string(StringLiteral {
915                elements,
916                encoding: Encoding::Plain,
917                remarks: Remarks::default(),
918            });
919            self.expr(ast::Expr::Str(id))
920        }
921
922        fn subscript(&mut self, base: ast::ExprId, index: ast::ExprId) -> ast::ExprId {
923            self.expr(ast::Expr::Index { base, index })
924        }
925
926        fn member(&mut self, base: ast::ExprId, field: &str) -> ast::ExprId {
927            let name = self.name(field);
928            self.expr(ast::Expr::Member { base, name, arrow: false })
929        }
930
931        /// One member of a record.
932        fn field(&mut self, specs: DeclSpecs, name: &str) -> ast::Member {
933            let declarator = Some(self.declarator(Some(name), &[]));
934            let specs = self.ast.add_specs(specs);
935            ast::Member::Field(ast::Field {
936                specs,
937                declarator,
938                bits: None,
939                attrs: AttrList::EMPTY,
940                span: Span::DUMMY,
941            })
942        }
943
944        /// `struct S { ... }`, as a specifier list.
945        fn record(&mut self, tag: &str, members: &[ast::Member]) -> DeclSpecs {
946            let tag = Some(self.name(tag));
947            let fields = Some(self.ast.add_member_list(members));
948            let mut specs = DeclSpecs::empty(Span::DUMMY);
949            specs.ty = TypeSpec::Record {
950                kind: ast::RecordKind::Struct,
951                tag,
952                fields,
953                attrs: AttrList::EMPTY,
954            };
955            specs
956        }
957
958        fn cast(
959            &mut self,
960            specs: DeclSpecs,
961            derived: &[Derived],
962            operand: ast::ExprId,
963        ) -> ast::ExprId {
964            let ty = self.type_name(specs, derived);
965            self.expr(ast::Expr::Cast { ty, operand })
966        }
967
968        /// `int`, as a specifier list a test can add words to.
969        fn int_specs(&self) -> DeclSpecs {
970            self.builtin(BuiltinSet::INT)
971        }
972
973        fn builtin(&self, keyword: BuiltinSet) -> DeclSpecs {
974            let mut specs = DeclSpecs::empty(Span::DUMMY);
975            let builtin = Builtin::NONE.add(keyword).expect("a keyword written once");
976            specs.ty = TypeSpec::Builtin(builtin);
977            specs
978        }
979
980        fn type_name(&mut self, specs: DeclSpecs, derived: &[Derived]) -> ast::TypeNameId {
981            let declarator = self.declarator(None, derived);
982            let specs = self.ast.add_specs(specs);
983            self.ast.add_type_name(ast::TypeName { specs, declarator, span: Span::DUMMY })
984        }
985
986        fn declarator(&mut self, name: Option<&str>, derived: &[Derived]) -> ast::DeclaratorId {
987            let name = name.map(|name| self.name(name));
988            let derived = self.ast.add_derived_list(derived);
989            self.ast.add_declarator(Declarator {
990                name,
991                name_span: Span::DUMMY,
992                derived,
993                span: Span::DUMMY,
994            })
995        }
996
997        /// A declaration of one name, which is what an address needs an object to be.
998        fn var(&mut self, specs: DeclSpecs, name: &str, derived: &[Derived]) -> ast::DeclId {
999            let declarator = self.declarator(Some(name), derived);
1000            let item = ast::InitDeclarator {
1001                declarator,
1002                init: None,
1003                asm_label: None,
1004                attrs: AttrList::EMPTY,
1005                span: Span::DUMMY,
1006            };
1007            let declarators = self.ast.add_init_declarator_list(&[item]);
1008            let specs = self.ast.add_specs(specs);
1009            self.ast.decl(ast::Decl::Var { specs, declarators }, Span::DUMMY)
1010        }
1011
1012        fn checker(&self) -> Checker<'_> {
1013            Checker::new(&self.ast, Context::new(&self.names, &self.target, Std::C23))
1014        }
1015    }
1016
1017    /// `[n]`, with a fixed bound.
1018    fn array(size: ast::ExprId) -> Derived {
1019        Derived::Array { size: ArraySize::Expr(size), quals: Quals::NONE, has_static: false }
1020    }
1021
1022    /// `*`.
1023    fn pointer() -> Derived {
1024        Derived::Pointer { quals: Quals::NONE, attrs: AttrList::EMPTY }
1025    }
1026
1027    /// What an expression folds to, whatever kind of constant that is.
1028    fn value(checker: &mut Checker<'_>, expr: ast::ExprId) -> Result<Const, NotConstant> {
1029        let id = checker.check_expr(expr);
1030        checker.eval_constant(id)
1031    }
1032
1033    /// The object an address constant is into, and how far.
1034    fn address(value: Result<Const, NotConstant>) -> Option<(usize, i128)> {
1035        match value {
1036            Ok(Const::Address(address)) => {
1037                let base = match address.base {
1038                    Base::Decl(decl) => decl.index(),
1039                    Base::Str(id) => id.index(),
1040                };
1041                Some((base, address.offset))
1042            }
1043            _ => None,
1044        }
1045    }
1046
1047    /// The integer one expression folds to, checking it first the way the compiler would.
1048    fn fold(checker: &mut Checker<'_>, expr: ast::ExprId) -> Result<i128, NotConstant> {
1049        let id = checker.check_expr(expr);
1050        checker.eval_integer(id)
1051    }
1052
1053    /// What was reported, as the messages alone.
1054    fn messages(checker: &Checker<'_>) -> Vec<String> {
1055        checker.errors.diagnostics().iter().map(|d| d.message.clone()).collect()
1056    }
1057
1058    #[test]
1059    fn the_address_of_a_static_object_is_that_object_and_no_distance() {
1060        let mut f = Fixture::new();
1061        let object = f.var(f.int_specs(), "a", &[]);
1062        let a = f.use_name("a");
1063        let taken = f.unary(UnaryOp::AddrOf, a);
1064
1065        let mut c = f.checker();
1066        c.check_decl(object);
1067        assert_eq!(address(value(&mut c, taken)), Some((0, 0)));
1068        assert!(messages(&c).is_empty());
1069    }
1070
1071    #[test]
1072    fn a_subscript_and_a_member_add_up_into_one_distance() {
1073        let mut f = Fixture::new();
1074        let x = f.int(4, IntKind::Int);
1075        let object = f.var(f.int_specs(), "a", &[array(x)]);
1076        let a = f.use_name("a");
1077        let two = f.int(2, IntKind::Int);
1078        let element = f.subscript(a, two);
1079        let taken = f.unary(UnaryOp::AddrOf, element);
1080
1081        let mut c = f.checker();
1082        c.check_decl(object);
1083        assert_eq!(
1084            address(value(&mut c, taken)),
1085            Some((0, 8)),
1086            "two elements of four bytes each into the object it started at"
1087        );
1088        assert!(messages(&c).is_empty());
1089    }
1090
1091    #[test]
1092    fn a_member_adds_its_own_offset_to_the_object_that_holds_it() {
1093        let mut f = Fixture::new();
1094        let x = f.field(f.int_specs(), "x");
1095        let y = f.field(f.int_specs(), "y");
1096        let specs = f.record("S", &[x, y]);
1097        let object = f.var(specs, "s", &[]);
1098        let s = f.use_name("s");
1099        let member = f.member(s, "y");
1100        let taken = f.unary(UnaryOp::AddrOf, member);
1101
1102        let mut c = f.checker();
1103        c.check_decl(object);
1104        assert_eq!(address(value(&mut c, taken)), Some((0, 4)));
1105        assert!(messages(&c).is_empty());
1106    }
1107
1108    #[test]
1109    fn a_pointer_moves_by_what_it_points_at_and_not_by_bytes() {
1110        let mut f = Fixture::new();
1111        let four = f.int(4, IntKind::Int);
1112        let object = f.var(f.int_specs(), "a", &[array(four)]);
1113        let a = f.use_name("a");
1114        let three = f.int(3, IntKind::Int);
1115        let moved = f.binary(BinaryOp::Add, a, three);
1116        let a = f.use_name("a");
1117        let one = f.int(1, IntKind::Int);
1118        let back = f.binary(BinaryOp::Sub, a, one);
1119
1120        let mut c = f.checker();
1121        c.check_decl(object);
1122        assert_eq!(address(value(&mut c, moved)), Some((0, 12)));
1123        assert_eq!(address(value(&mut c, back)), Some((0, -4)), "and it may go the other way");
1124        assert!(messages(&c).is_empty());
1125    }
1126
1127    #[test]
1128    fn two_pointers_into_one_object_subtract_to_the_elements_between_them() {
1129        let mut f = Fixture::new();
1130        let ten = f.int(10, IntKind::Int);
1131        let object = f.var(f.int_specs(), "a", &[array(ten)]);
1132        let a = f.use_name("a");
1133        let three = f.int(3, IntKind::Int);
1134        let high = f.subscript(a, three);
1135        let high = f.unary(UnaryOp::AddrOf, high);
1136        let a = f.use_name("a");
1137        let one = f.int(1, IntKind::Int);
1138        let low = f.subscript(a, one);
1139        let low = f.unary(UnaryOp::AddrOf, low);
1140        let distance = f.binary(BinaryOp::Sub, high, low);
1141
1142        let mut c = f.checker();
1143        c.check_decl(object);
1144        assert_eq!(
1145            value(&mut c, distance),
1146            Ok(Const::Int(2)),
1147            "a difference is a number, since the two cancel whatever the linker does with them"
1148        );
1149        assert!(messages(&c).is_empty());
1150    }
1151
1152    #[test]
1153    fn two_pointers_into_different_objects_have_no_distance_between_them() {
1154        let mut f = Fixture::new();
1155        let first = f.var(f.int_specs(), "a", &[]);
1156        let second = f.var(f.int_specs(), "b", &[]);
1157        let a = f.use_name("a");
1158        let a = f.unary(UnaryOp::AddrOf, a);
1159        let b = f.use_name("b");
1160        let b = f.unary(UnaryOp::AddrOf, b);
1161        let distance = f.binary(BinaryOp::Sub, a, b);
1162
1163        let mut c = f.checker();
1164        c.check_decl(first);
1165        c.check_decl(second);
1166        assert!(value(&mut c, distance).is_err(), "nothing decides that until the two are placed");
1167    }
1168
1169    #[test]
1170    fn the_address_of_an_automatic_object_is_not_a_constant() {
1171        let mut f = Fixture::new();
1172        let object = f.var(f.int_specs(), "a", &[]);
1173        let a = f.use_name("a");
1174        let taken = f.unary(UnaryOp::AddrOf, a);
1175
1176        let mut c = f.checker();
1177        c.scopes.push();
1178        c.check_decl(object);
1179        assert!(
1180            value(&mut c, taken).is_err(),
1181            "a local has no address until the frame holding it exists"
1182        );
1183    }
1184
1185    #[test]
1186    fn a_static_local_does_have_one_since_it_is_laid_out_once() {
1187        let mut f = Fixture::new();
1188        let mut specs = f.int_specs();
1189        specs.storage = Some(StorageClass::Static);
1190        let object = f.var(specs, "a", &[]);
1191        let a = f.use_name("a");
1192        let taken = f.unary(UnaryOp::AddrOf, a);
1193
1194        let mut c = f.checker();
1195        c.scopes.push();
1196        c.check_decl(object);
1197        assert_eq!(address(value(&mut c, taken)), Some((0, 0)));
1198    }
1199
1200    #[test]
1201    fn a_string_literal_is_an_object_and_its_decay_is_the_address_of_it() {
1202        let mut f = Fixture::new();
1203        let literal = f.string("hi");
1204        let one = f.int(1, IntKind::Int);
1205        let moved = f.binary(BinaryOp::Add, literal, one);
1206
1207        let mut c = f.checker();
1208        assert_eq!(address(value(&mut c, moved)), Some((0, 1)));
1209        assert!(messages(&c).is_empty());
1210    }
1211
1212    #[test]
1213    fn an_address_written_as_an_integer_survives_only_where_all_of_it_does() {
1214        let mut f = Fixture::new();
1215        let object = f.var(f.int_specs(), "a", &[]);
1216        let a = f.use_name("a");
1217        let taken = f.unary(UnaryOp::AddrOf, a);
1218        let wide = f.cast(f.builtin(BuiltinSet::LONG), &[], taken);
1219        let a = f.use_name("a");
1220        let taken = f.unary(UnaryOp::AddrOf, a);
1221        let narrow = f.cast(f.int_specs(), &[], taken);
1222
1223        let mut c = f.checker();
1224        c.check_decl(object);
1225        assert_eq!(
1226            address(value(&mut c, wide)),
1227            Some((0, 0)),
1228            "a `long` holds every bit of a pointer here, so the value is still the object"
1229        );
1230        assert!(
1231            value(&mut c, narrow).is_err(),
1232            "an `int` does not, and half an address is not an address"
1233        );
1234    }
1235
1236    #[test]
1237    fn a_pointer_with_no_object_behind_it_is_a_number_and_stays_one() {
1238        let mut f = Fixture::new();
1239        let four = f.int(4, IntKind::Int);
1240        let pointer = f.cast(f.int_specs(), &[pointer()], four);
1241        let one = f.int(1, IntKind::Int);
1242        let moved = f.binary(BinaryOp::Add, pointer, one);
1243        let back = f.cast(f.builtin(BuiltinSet::LONG), &[], moved);
1244
1245        let mut c = f.checker();
1246        assert_eq!(
1247            value(&mut c, back),
1248            Ok(Const::Int(8)),
1249            "the scaling happens and nothing has to be relocated, so it is an integer throughout"
1250        );
1251    }
1252
1253    #[test]
1254    fn an_address_is_never_null_and_says_so() {
1255        let mut f = Fixture::new();
1256        let object = f.var(f.int_specs(), "a", &[]);
1257        let a = f.use_name("a");
1258        let taken = f.unary(UnaryOp::AddrOf, a);
1259        let zero = f.int(0, IntKind::Int);
1260        let compared = f.binary(BinaryOp::Ne, taken, zero);
1261
1262        let mut c = f.checker();
1263        c.check_decl(object);
1264        assert_eq!(fold(&mut c, compared), Ok(1));
1265    }
1266
1267    #[test]
1268    fn an_address_is_not_an_integer_constant_expression_whatever_type_it_wears() {
1269        let mut f = Fixture::new();
1270        let object = f.var(f.int_specs(), "a", &[]);
1271        let a = f.use_name("a");
1272        let taken = f.unary(UnaryOp::AddrOf, a);
1273        let wide = f.cast(f.builtin(BuiltinSet::LONG), &[], taken);
1274
1275        let mut c = f.checker();
1276        c.check_decl(object);
1277        assert!(
1278            fold(&mut c, wide).is_err(),
1279            "an array bound and a case label want a number, and this is a relocation"
1280        );
1281    }
1282
1283    #[test]
1284    fn reading_an_object_is_not_a_constant_however_const_the_object_is() {
1285        let mut f = Fixture::new();
1286        let mut specs = f.int_specs();
1287        specs.quals = Quals::CONST;
1288        let object = f.var(specs, "n", &[]);
1289        let n = f.use_name("n");
1290
1291        let mut c = f.checker();
1292        c.check_decl(object);
1293        assert!(
1294            value(&mut c, n).is_err(),
1295            "which is the whole reason `const int n = 1; int a[n];` is a variable length array"
1296        );
1297    }
1298
1299    #[test]
1300    fn arithmetic_folds_to_the_value_the_program_wrote() {
1301        let mut f = Fixture::new();
1302        let (one, two, three) =
1303            (f.int(1, IntKind::Int), f.int(2, IntKind::Int), f.int(3, IntKind::Int));
1304        let sum = f.binary(BinaryOp::Add, one, two);
1305        let product = f.binary(BinaryOp::Mul, sum, three);
1306
1307        let mut c = f.checker();
1308        assert_eq!(fold(&mut c, product), Ok(9));
1309        assert!(messages(&c).is_empty());
1310    }
1311
1312    #[test]
1313    fn signed_overflow_is_warned_about_and_wrapped() {
1314        let mut f = Fixture::new();
1315        let (big, one) = (f.int(2_147_483_647, IntKind::Int), f.int(1, IntKind::Int));
1316        let sum = f.binary(BinaryOp::Add, big, one);
1317
1318        let mut c = f.checker();
1319        assert_eq!(fold(&mut c, sum), Ok(-2_147_483_648));
1320        assert_eq!(
1321            messages(&c),
1322            ["integer overflow in expression of type 'int' results in '-2147483648'"]
1323        );
1324    }
1325
1326    #[test]
1327    fn unsigned_arithmetic_wraps_without_a_word_because_it_is_not_overflow() {
1328        let mut f = Fixture::new();
1329        let (big, one) = (f.int(4_294_967_295, IntKind::UInt), f.int(1, IntKind::UInt));
1330        let sum = f.binary(BinaryOp::Add, big, one);
1331
1332        let mut c = f.checker();
1333        assert_eq!(fold(&mut c, sum), Ok(0));
1334        assert!(messages(&c).is_empty());
1335    }
1336
1337    #[test]
1338    fn a_bit_precise_type_overflows_in_its_own_width_and_not_in_an_int() {
1339        let mut f = Fixture::new();
1340        let (a, b) = (f.bit_int(100, true, 8), f.bit_int(100, true, 8));
1341        let sum = f.binary(BinaryOp::Add, a, b);
1342
1343        let mut c = f.checker();
1344        // Two hundred is an ordinary `int` and is not a `_BitInt(8)`, and the whole point of the
1345        // type is that it does what it says rather than promoting out of the question.
1346        assert_eq!(fold(&mut c, sum), Ok(-56));
1347        assert_eq!(messages(&c).len(), 1, "{:?}", messages(&c));
1348    }
1349
1350    #[test]
1351    fn division_by_zero_is_warned_about_and_has_no_value() {
1352        let mut f = Fixture::new();
1353        let (one, zero) = (f.int(1, IntKind::Int), f.int(0, IntKind::Int));
1354        let quotient = f.binary(BinaryOp::Div, one, zero);
1355
1356        let mut c = f.checker();
1357        let folded = fold(&mut c, quotient);
1358        assert!(folded.is_err());
1359        assert!(!folded.expect_err("no value").poisoned, "the caller still names the context");
1360        assert_eq!(messages(&c), ["division by zero"]);
1361    }
1362
1363    #[test]
1364    fn the_least_value_over_minus_one_overflows_and_so_does_its_remainder() {
1365        for op in [BinaryOp::Div, BinaryOp::Rem] {
1366            let mut f = Fixture::new();
1367            let (big, one) = (f.int(2_147_483_647, IntKind::Int), f.int(1, IntKind::Int));
1368            let negated = f.unary(UnaryOp::Minus, big);
1369            let least = f.binary(BinaryOp::Sub, negated, one);
1370            let minus_one = f.unary(UnaryOp::Minus, one);
1371            let divided = f.binary(op, least, minus_one);
1372
1373            let mut c = f.checker();
1374            let expected = if matches!(op, BinaryOp::Div) { -2_147_483_648 } else { 0 };
1375            assert_eq!(fold(&mut c, divided), Ok(expected));
1376            assert_eq!(messages(&c).len(), 1, "{:?}", messages(&c));
1377        }
1378    }
1379
1380    #[test]
1381    fn negating_the_least_value_overflows_onto_itself() {
1382        let mut f = Fixture::new();
1383        let (big, one) = (f.int(2_147_483_647, IntKind::Int), f.int(1, IntKind::Int));
1384        let flipped = f.unary(UnaryOp::Minus, big);
1385        let least = f.binary(BinaryOp::Sub, flipped, one);
1386        let negated = f.unary(UnaryOp::Minus, least);
1387
1388        let mut c = f.checker();
1389        assert_eq!(fold(&mut c, negated), Ok(-2_147_483_648));
1390        assert_eq!(
1391            messages(&c),
1392            ["integer overflow in expression of type 'int' results in '-2147483648'"]
1393        );
1394    }
1395
1396    #[test]
1397    fn a_shift_past_the_width_is_warned_about_and_folded_the_way_gcc_folds_it() {
1398        let mut f = Fixture::new();
1399        let (one, thirty_two) = (f.int(1, IntKind::Int), f.int(32, IntKind::Int));
1400        let shifted = f.binary(BinaryOp::Shl, one, thirty_two);
1401
1402        let mut c = f.checker();
1403        assert_eq!(fold(&mut c, shifted), Ok(0));
1404        assert_eq!(messages(&c), ["left shift count >= width of type"]);
1405    }
1406
1407    #[test]
1408    fn an_arithmetic_right_shift_past_the_width_keeps_the_sign() {
1409        let mut f = Fixture::new();
1410        let (one, forty) = (f.int(1, IntKind::Int), f.int(40, IntKind::Int));
1411        let minus_one = f.unary(UnaryOp::Minus, one);
1412        let shifted = f.binary(BinaryOp::Shr, minus_one, forty);
1413
1414        let mut c = f.checker();
1415        // Measured: gcc 13.3 folds `-1 >> 40` to minus one and `1 >> 40` to zero, which is the
1416        // shift having gone as far as it can rather than the count having wrapped.
1417        assert_eq!(fold(&mut c, shifted), Ok(-1));
1418        assert_eq!(messages(&c), ["right shift count >= width of type"]);
1419    }
1420
1421    #[test]
1422    fn a_negative_shift_count_is_warned_about_and_has_no_value() {
1423        let mut f = Fixture::new();
1424        let (one, two) = (f.int(1, IntKind::Int), f.int(2, IntKind::Int));
1425        let count = f.unary(UnaryOp::Minus, two);
1426        let shifted = f.binary(BinaryOp::Shl, one, count);
1427
1428        let mut c = f.checker();
1429        assert!(fold(&mut c, shifted).is_err());
1430        assert_eq!(messages(&c), ["left shift count is negative"]);
1431    }
1432
1433    #[test]
1434    fn a_shift_folds_in_the_width_of_its_left_operand_alone() {
1435        let mut f = Fixture::new();
1436        let (one, forty) = (f.int(1, IntKind::LongLong), f.int(40, IntKind::Int));
1437        let shifted = f.binary(BinaryOp::Shl, one, forty);
1438
1439        let mut c = f.checker();
1440        // The usual arithmetic conversions do not apply to a shift, so this is a sixty four bit
1441        // one shifted forty places and not an `int` shifted out of existence.
1442        assert_eq!(fold(&mut c, shifted), Ok(1 << 40));
1443        assert!(messages(&c).is_empty());
1444    }
1445
1446    #[test]
1447    fn an_unsigned_comparison_reads_the_top_bit_as_a_digit() {
1448        let mut f = Fixture::new();
1449        let one = f.int(1, IntKind::UInt);
1450        let big = f.unary(UnaryOp::Minus, one);
1451        let other = f.int(1, IntKind::UInt);
1452        let greater = f.binary(BinaryOp::Gt, big, other);
1453
1454        let mut c = f.checker();
1455        // `-1u` is four billion and something. Compared as a signed value it would be less than
1456        // one, and a compiler that folds it that way gets every unsigned bound check wrong.
1457        assert_eq!(fold(&mut c, greater), Ok(1));
1458        assert!(messages(&c).is_empty());
1459    }
1460
1461    #[test]
1462    fn short_circuiting_does_not_fold_what_the_language_did_not_evaluate() {
1463        let mut f = Fixture::new();
1464        let zero = f.int(0, IntKind::Int);
1465        let name = f.names.intern("x");
1466        let x = f.expr(ast::Expr::Name(name));
1467        let and = f.binary(BinaryOp::LogAnd, zero, x);
1468
1469        let mut c = f.checker();
1470        let int = c.types.int(IntKind::Int);
1471        c.declare_object(name, int, Span::DUMMY);
1472        assert_eq!(fold(&mut c, and), Ok(0));
1473        assert!(messages(&c).is_empty(), "{:?}", messages(&c));
1474    }
1475
1476    #[test]
1477    fn only_the_arm_the_condition_takes_is_folded() {
1478        let mut f = Fixture::new();
1479        let (one, two) = (f.int(1, IntKind::Int), f.int(2, IntKind::Int));
1480        let name = f.names.intern("x");
1481        let x = f.expr(ast::Expr::Name(name));
1482        let conditional = f.expr(ast::Expr::Cond { cond: one, then: Some(two), otherwise: x });
1483
1484        let mut c = f.checker();
1485        let int = c.types.int(IntKind::Int);
1486        c.declare_object(name, int, Span::DUMMY);
1487        assert_eq!(fold(&mut c, conditional), Ok(2));
1488        assert!(messages(&c).is_empty(), "{:?}", messages(&c));
1489    }
1490
1491    #[test]
1492    fn reading_an_object_is_not_a_constant_however_const_it_is() {
1493        let mut f = Fixture::new();
1494        let name = f.names.intern("n");
1495        let x = f.expr(ast::Expr::Name(name));
1496
1497        let mut c = f.checker();
1498        let int = c.types.int(IntKind::Int);
1499        let constant = c.types.qualified(int, rucc_types::Qualifiers::CONST);
1500        c.declare_object(name, constant, Span::DUMMY);
1501        // C says `const int n = 1; int a[n];` is a variable length array and C++ says it is not.
1502        // This is the arm that decides which language is being compiled.
1503        assert!(fold(&mut c, x).is_err());
1504        assert!(messages(&c).is_empty());
1505    }
1506
1507    #[test]
1508    fn a_comma_is_a_constant_nowhere() {
1509        let mut f = Fixture::new();
1510        let (one, two) = (f.int(1, IntKind::Int), f.int(2, IntKind::Int));
1511        let comma = f.expr(ast::Expr::Comma { lhs: one, rhs: two });
1512
1513        let mut c = f.checker();
1514        // 6.6p3 lists the comma operator among the things a constant expression shall not
1515        // contain, and gcc refuses `enum { a = (1, 2) };` accordingly.
1516        assert!(fold(&mut c, comma).is_err());
1517        assert!(messages(&c).is_empty());
1518    }
1519
1520    #[test]
1521    fn nothing_is_said_about_an_expression_that_was_already_diagnosed() {
1522        let mut f = Fixture::new();
1523        let name = f.names.intern("undeclared");
1524        let x = f.expr(ast::Expr::Name(name));
1525        let one = f.int(1, IntKind::Int);
1526        let sum = f.binary(BinaryOp::Add, x, one);
1527
1528        let mut c = f.checker();
1529        let folded = fold(&mut c, sum);
1530        assert!(folded.expect_err("no value").poisoned);
1531        assert_eq!(messages(&c).len(), 1, "the undeclared name, and nothing about the addition");
1532    }
1533
1534    #[test]
1535    fn a_floating_constant_is_not_an_integer_constant_expression() {
1536        let mut f = Fixture::new();
1537        let three = f.double("3.0");
1538
1539        let mut c = f.checker();
1540        // Exactly three and still not an integer constant expression, which is 6.6p6 being
1541        // about the type and not about the value. gcc refuses `enum { a = 3.0 };` too.
1542        let id = c.check_expr(three);
1543        assert!(c.eval_integer(id).is_err());
1544        let (three, _) = Float::parse("3.0", Format::Double).expect("a float");
1545        assert_eq!(c.eval_constant(id), Ok(Const::Float(three)));
1546        assert!(messages(&c).is_empty());
1547    }
1548
1549    #[test]
1550    fn floating_arithmetic_is_folded_in_the_target_format() {
1551        let mut f = Fixture::new();
1552        let (one, three) = (f.double("1.0"), f.double("3.0"));
1553        let third = f.binary(BinaryOp::Div, one, three);
1554
1555        let mut c = f.checker();
1556        let id = c.check_expr(third);
1557        let Ok(Const::Float(value)) = c.eval_constant(id) else { panic!("a folded float") };
1558        assert_eq!(value.to_bits(), 0x3fd5_5555_5555_5555, "the correctly rounded double third");
1559        assert!(messages(&c).is_empty());
1560    }
1561
1562    #[test]
1563    fn a_comparison_against_a_nan_is_false_except_for_the_inequality() {
1564        for (op, expected) in [(BinaryOp::Eq, 0), (BinaryOp::Ne, 1), (BinaryOp::Lt, 0)] {
1565            let mut f = Fixture::new();
1566            let (a, b) = (f.double("0.0"), f.double("0.0"));
1567            let nan = f.binary(BinaryOp::Div, a, b);
1568            let (c1, c2) = (f.double("0.0"), f.double("0.0"));
1569            let other = f.binary(BinaryOp::Div, c1, c2);
1570            let compared = f.binary(op, nan, other);
1571
1572            let mut c = f.checker();
1573            assert_eq!(fold(&mut c, compared), Ok(expected));
1574            // A floating division by zero is a nan and not a diagnostic, which is what makes
1575            // `0.0/0.0` a way to write one and what both compilers accept in a constant.
1576            assert!(messages(&c).is_empty());
1577        }
1578    }
1579
1580    #[test]
1581    fn a_conversion_between_arithmetic_types_folds_through_the_node_the_checking_wrote() {
1582        let mut f = Fixture::new();
1583        let (half, one) = (f.double("0.5"), f.int(1, IntKind::Int));
1584        let sum = f.binary(BinaryOp::Add, half, one);
1585
1586        let mut c = f.checker();
1587        let id = c.check_expr(sum);
1588        let Ok(Const::Float(value)) = c.eval_constant(id) else { panic!("a folded float") };
1589        // The `1` became a `1.0` in a conversion node, which is the whole reason the folding
1590        // reads the typed tree: nothing here had to work out that an int met a double.
1591        assert_eq!(value.to_bits(), 0x3ff8_0000_0000_0000, "one and a half, in a double");
1592        assert!(messages(&c).is_empty());
1593    }
1594}