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