Skip to main content

rucc_sema/
convert.rs

1//! The conversions the language performs without being asked, as nodes in the tree.
2//!
3//! Design: `spec/07-types-and-semantics.md` section 7.2.
4//!
5//! Every one of these writes a [`Conversion`] node. Nothing downstream is allowed to work out
6//! for itself that an `int` met a `long` somewhere, because a second place that knows the
7//! conversion rules is a second place that is slightly wrong about them, and that is where the
8//! sign extension bugs live.
9//!
10//! # The order the standard puts them in
11//!
12//! An expression used for its value goes through at most three steps, in this order, and the
13//! order is not a convenience:
14//!
15//! First the lvalue conversion of 6.3.2.1, which reads the object and drops the qualifiers and
16//! the atomicity, since neither is part of a value. An array and a function do not take part in
17//! it at all: they decay instead, which is why `sizeof a` on an array is the array's size and
18//! not a pointer's, and why the decay has to be a separate step rather than a special case of
19//! reading.
20//!
21//! Then the integer promotions of 6.3.1.1, which are about one operand.
22//!
23//! Then the usual arithmetic conversions of 6.3.1.8, which are about two.
24//!
25//! [`Conv::value`] is the first step and is what almost every caller wants, because an operand
26//! that is still an lvalue is an operand somebody forgot to read.
27//!
28//! # Bit-fields
29//!
30//! A bit-field's lvalue conversion gives the type it was declared with and its promotion is
31//! decided by its width rather than by that type, which is why [`Conv::promote_bits`] exists
32//! next to [`Conv::promote`]. `unsigned b:3` promotes to `int` because every three bit value
33//! fits in one, and `unsigned b:32` promotes to `unsigned int` because they no longer do.
34//!
35//! No caller has to know that, because [`Conv::promote`] and [`Conv::usual_arithmetic`] look for
36//! the width themselves. A caller that had to remember would be a caller that forgot, and the
37//! symptom is a whole expression coming out unsigned on the strength of one member's declared
38//! type.
39
40use rucc_target::TargetInfo;
41use rucc_types::{TypeId, TypeKind, Types, is_arithmetic, is_pointer, is_void};
42
43use crate::expr::{Category, Conversion, Expr, ExprId, ExprKind};
44use crate::tast::{Const, Tast};
45
46/// Everything a conversion needs: the tree to write the node into and the table to ask.
47///
48/// Three references rather than a pass-wide context, because the conversions are the part of
49/// semantic analysis with no state of its own and nothing else here should be able to reach
50/// the scopes or the diagnostics through them.
51#[derive(Debug)]
52pub struct Conv<'a> {
53    /// The tree the nodes are written into.
54    pub tast: &'a mut Tast,
55    /// The types, which conversions extend.
56    pub types: &'a mut Types,
57    /// What the target's integers are, which is what the promotions are decided by.
58    pub target: &'a TargetInfo,
59}
60
61impl Conv<'_> {
62    /// The value of an expression: 6.3.2.1, with the decays that replace it.
63    ///
64    /// An array becomes a pointer to its first element, a function becomes a pointer to itself,
65    /// and everything else that is an lvalue is read. An expression that is already a value is
66    /// its own answer, so this can be called on any operand without asking what it is first.
67    pub fn value(&mut self, expr: ExprId) -> ExprId {
68        let ty = self.tast[expr].ty;
69        match self.types.kind(self.types.canonical(ty)) {
70            TypeKind::Array { elem, .. } => {
71                let ty = self.types.pointer(elem);
72                self.write(Conversion::ArrayDecay, expr, ty)
73            }
74            TypeKind::Function(_) => {
75                let ty = self.types.pointer(ty);
76                self.write(Conversion::FunctionDecay, expr, ty)
77            }
78            _ if self.tast[expr].category == Category::Rvalue => expr,
79            _ => {
80                let ty = self.read_as(ty);
81                self.write(Conversion::Lvalue, expr, ty)
82            }
83        }
84    }
85
86    /// The value of an expression with the integer promotions applied, 6.3.1.1.
87    ///
88    /// Anything narrower than `int` becomes `int`, or `unsigned int` where `int` cannot hold
89    /// every value it had. A floating type, a pointer and a `_BitInt` are each their own
90    /// answer, the last because C23 6.3.1.1p2 says so and because that is the point of the
91    /// type: it is the one integer type in C that does what it says.
92    pub fn promote(&mut self, expr: ExprId) -> ExprId {
93        let expr = self.value_promoting_bits(expr);
94        let ty = self.tast[expr].ty;
95        let promoted = rucc_types::promote(self.types, ty, self.target);
96        self.arithmetic(expr, promoted)
97    }
98
99    /// The value of a bit-field with the integer promotions applied to its width.
100    ///
101    /// A bit-field is narrower than the type it was declared with, and it is the width that
102    /// decides. The caller passes the width because the tree holds the field index and the
103    /// width is a fact about the record, not about the expression.
104    pub fn promote_bits(&mut self, expr: ExprId, width: u32) -> ExprId {
105        let expr = self.value(expr);
106        let ty = self.tast[expr].ty;
107        let promoted = rucc_types::promote_bit_field(self.types, ty, width, self.target);
108        self.arithmetic(expr, promoted)
109    }
110
111    /// The value of an expression, promoted by its width first where it names a bit-field.
112    ///
113    /// This is what every operand that is about to be promoted goes through, because the type a
114    /// bit-field was declared with is not the type it brings to an operator: `unsigned b:1` is
115    /// an `int` in `b + 1` and not an `unsigned int`, and a whole expression comes out signed or
116    /// unsigned on the strength of that one width.
117    fn value_promoting_bits(&mut self, expr: ExprId) -> ExprId {
118        match self.bit_field_width(expr) {
119            Some(width) => self.promote_bits(expr, width),
120            None => self.value(expr),
121        }
122    }
123
124    /// The width of the bit-field an expression names, or [`None`] where it names none.
125    ///
126    /// The width lives on the record rather than on the expression, so this asks the type table
127    /// rather than reading it off the node. Only a member access can be one: a bit-field has no
128    /// address, so there is no other expression that can arrive still being one.
129    ///
130    /// The lvalue conversion is looked through, because most callers read the object before they
131    /// know they are about to promote it and the value they are left holding is still as wide as
132    /// the field was.
133    fn bit_field_width(&self, expr: ExprId) -> Option<u32> {
134        let expr = match self.tast[expr].kind {
135            ExprKind::Convert { kind: Conversion::Lvalue, operand } => operand,
136            _ => expr,
137        };
138        let ExprKind::Member { base, field } = self.tast[expr].kind else { return None };
139        let base = self.types.canonical(self.tast[base].ty);
140        let TypeKind::Record(record) = self.types.kind(base) else { return None };
141        self.types.record_info(record).fields.get(field as usize)?.bits
142    }
143
144    /// The usual arithmetic conversions, 6.3.1.8: both operands converted to one type.
145    ///
146    /// [`None`] where either operand is not arithmetic, which is not a failure of this rule but
147    /// a question it does not answer, since `p + 1` is pointer arithmetic and never reaches it.
148    pub fn usual_arithmetic(&mut self, lhs: ExprId, rhs: ExprId) -> Option<(ExprId, ExprId)> {
149        let (lhs, rhs) = (self.value_promoting_bits(lhs), self.value_promoting_bits(rhs));
150        let common = rucc_types::usual_arithmetic(
151            self.types,
152            self.tast[lhs].ty,
153            self.tast[rhs].ty,
154            self.target,
155        )?;
156        Some((self.arithmetic(lhs, common), self.arithmetic(rhs, common)))
157    }
158
159    /// A scalar as a condition, which is a comparison against zero and not a truncation.
160    ///
161    /// That is why it is [`Conversion::Bool`] rather than [`Conversion::Arithmetic`]: `(bool)
162    /// 256` is true and `(char) 256` is zero, and a compiler that treats the two the same is
163    /// wrong about one of them.
164    pub fn to_bool(&mut self, expr: ExprId) -> ExprId {
165        let expr = self.value(expr);
166        let boolean = self.types.boolean();
167        if self.tast[expr].ty == boolean {
168            return expr;
169        }
170        self.write(Conversion::Bool, expr, boolean)
171    }
172
173    /// A value discarded, which is what a cast to `void` does.
174    ///
175    /// An expression statement does not write one of these, even though it discards a value too.
176    /// The statement is what does the discarding, and a statement expression's value is the last
177    /// statement's, so an expression statement that had thrown its type away would have nothing
178    /// left to give.
179    pub fn to_void(&mut self, expr: ExprId) -> ExprId {
180        if is_void(self.types, self.tast[expr].ty) {
181            return expr;
182        }
183        let void = self.types.void();
184        self.write(Conversion::Void, expr, void)
185    }
186
187    /// A value converted to a given type, with the kind of conversion worked out from the two.
188    ///
189    /// This is what an assignment, an argument, a `return` and an initializer all do. It writes
190    /// the conversion the pair calls for and does not judge whether the pair is allowed: the
191    /// caller has the span and the wording, and a conversion that should have been diagnosed is
192    /// a diagnostic the caller owes rather than a node this refuses to write.
193    pub fn to_type(&mut self, expr: ExprId, ty: TypeId) -> ExprId {
194        let expr = self.value(expr);
195        let from = self.tast[expr].ty;
196        let target = self.read_as(ty);
197        if from == target {
198            return expr;
199        }
200        if is_void(self.types, target) {
201            return self.to_void(expr);
202        }
203        let boolean = self.types.boolean();
204        if target == boolean {
205            return self.to_bool(expr);
206        }
207        let kind = if is_pointer(self.types, target) {
208            // A null pointer constant is not the integer zero converted. The constant may have
209            // any integer type and `(void *)0` is one of them, so what makes it a null pointer
210            // is what it says rather than what it weighs.
211            if self.is_null_pointer_constant(expr) {
212                Conversion::NullPointer
213            } else {
214                Conversion::Pointer
215            }
216        } else if is_arithmetic(self.types, target) && is_arithmetic(self.types, from) {
217            Conversion::Arithmetic
218        } else {
219            // A record to a record of the same type, or anything else the caller has already
220            // decided about. There is nothing to compute, so the node records that a value of
221            // one type is being used as another and the verifier can see it happened.
222            Conversion::Pointer
223        };
224        self.write(kind, expr, target)
225    }
226
227    /// Whether an expression is a null pointer constant, 6.3.2.3p3.
228    ///
229    /// An integer constant expression with the value zero, or such an expression cast to `void
230    /// *`. The casts and the conversions are looked through because `(void *)0` is one and so
231    /// is `(long)0`, and stopping at the first node would see a cast rather than a zero.
232    #[must_use]
233    pub fn is_null_pointer_constant(&self, expr: ExprId) -> bool {
234        match self.tast[expr].kind {
235            ExprKind::Const(value) => self.tast[value] == Const::Int(0),
236            ExprKind::Cast(inner) | ExprKind::Convert { operand: inner, .. } => {
237                self.is_null_pointer_constant(inner)
238            }
239            _ => false,
240        }
241    }
242
243    /// Writes an arithmetic conversion, or nothing where the type is already the one wanted.
244    fn arithmetic(&mut self, expr: ExprId, ty: TypeId) -> ExprId {
245        if self.tast[expr].ty == ty {
246            return expr;
247        }
248        self.write(Conversion::Arithmetic, expr, ty)
249    }
250
251    /// The type a value has once it has been read out of an object.
252    ///
253    /// The qualifiers and the atomicity come off, because neither is part of a value: `const
254    /// int x; x + 1` has an `int` on the left of the `+` and not a `const int`.
255    pub(crate) fn read_as(&mut self, ty: TypeId) -> TypeId {
256        let stripped = match self.types.kind(self.types.canonical(ty)) {
257            TypeKind::Atomic(inner) => inner,
258            _ => ty,
259        };
260        self.types.unqualified(stripped)
261    }
262
263    /// Writes one conversion node over an operand.
264    fn write(&mut self, kind: Conversion, operand: ExprId, ty: TypeId) -> ExprId {
265        let span = self.tast.expr_span(operand);
266        let node = Expr::new(ExprKind::Convert { kind, operand }, ty, Category::Rvalue);
267        self.tast.expr(node, span)
268    }
269}
270
271#[cfg(test)]
272mod tests {
273    use rucc_base::Interner;
274    use rucc_diag::Span;
275    use rucc_target::{TargetInfo, Triple};
276    use rucc_types::{ArrayLen, FunctionType, IntKind, Qualifiers};
277
278    use super::*;
279    use crate::decl::{Decl, DeclKind, DeclList, Definition, Linkage, StorageDuration};
280    use crate::print::Printer;
281
282    struct Fixture {
283        tast: Tast,
284        types: Types,
285        names: Interner,
286        target: TargetInfo,
287    }
288
289    impl Fixture {
290        fn new() -> Fixture {
291            let target =
292                TargetInfo::new("x86_64-unknown-linux-gnu".parse::<Triple>().expect("a triple"));
293            Fixture { tast: Tast::new(), types: Types::new(), names: Interner::new(), target }
294        }
295
296        fn conv(&mut self) -> Conv<'_> {
297            Conv { tast: &mut self.tast, types: &mut self.types, target: &self.target }
298        }
299
300        /// An lvalue of the given type, which is what a use of an object is.
301        fn object(&mut self, ty: TypeId) -> ExprId {
302            let decl = self.tast.decl(
303                Decl {
304                    name: None,
305                    ty,
306                    kind: DeclKind::Object,
307                    linkage: Linkage::None,
308                    duration: StorageDuration::Automatic,
309                    state: Definition::Defined,
310                    alignment: None,
311                    init: None,
312                    params: DeclList::EMPTY,
313                    body: None,
314                },
315                Span::DUMMY,
316            );
317            self.tast.expr(Expr::new(ExprKind::Decl(decl), ty, Category::Lvalue), Span::DUMMY)
318        }
319
320        /// A use of the one member of a `struct` that has one, which is a bit-field of `bits`.
321        fn bit_field(&mut self, ty: TypeId, bits: u32) -> ExprId {
322            let fields = [rucc_types::FieldDecl::bit_field(None, ty, bits)];
323            let id = self.types.declare_record(rucc_types::RecordKind::Struct, None);
324            let laid_out = rucc_types::layout_record(
325                &self.types,
326                rucc_types::RecordKind::Struct,
327                &fields,
328                &rucc_types::RecordOptions::default(),
329                &self.target,
330            )
331            .expect("a layout");
332            self.types.complete_record(id, laid_out);
333            let record = self.types.record(id);
334            let base = self.object(record);
335            self.tast.expr(
336                Expr::new(ExprKind::Member { base, field: 0 }, ty, Category::Bitfield),
337                Span::DUMMY,
338            )
339        }
340
341        fn zero(&mut self, ty: TypeId) -> ExprId {
342            let value = self.tast.add_const(Const::Int(0));
343            self.tast.expr(Expr::new(ExprKind::Const(value), ty, Category::Rvalue), Span::DUMMY)
344        }
345
346        fn text(&self, expr: ExprId) -> String {
347            let mut printer = Printer::new(&self.tast, &self.types, &self.names);
348            printer.expr(expr);
349            printer.finish()
350        }
351    }
352
353    #[test]
354    fn reading_an_object_drops_the_qualifiers_because_they_are_not_part_of_a_value() {
355        let mut f = Fixture::new();
356        let int = f.types.int(IntKind::Int);
357        let constant = f.types.qualified(int, Qualifiers::CONST);
358        let object = f.object(constant);
359        let read = f.conv().value(object);
360
361        assert_eq!(f.tast[read].ty, int);
362        assert_eq!(f.tast[read].category, Category::Rvalue);
363        assert_eq!(f.text(read), "convert lvalue : int\n  decl #0 : const int lvalue\n");
364    }
365
366    #[test]
367    fn an_atomic_object_reads_as_the_type_it_wraps() {
368        let mut f = Fixture::new();
369        let int = f.types.int(IntKind::Int);
370        let atomic = f.types.atomic(int);
371        let object = f.object(atomic);
372        let read = f.conv().value(object);
373
374        assert_eq!(f.tast[read].ty, int);
375    }
376
377    #[test]
378    fn an_array_decays_and_is_not_read() {
379        let mut f = Fixture::new();
380        let int = f.types.int(IntKind::Int);
381        let array = f.types.array(int, ArrayLen::Fixed(3));
382        let object = f.object(array);
383        let decayed = f.conv().value(object);
384
385        // Not an lvalue conversion, which is why `sizeof a` is the array's size: the decay is a
386        // step of its own and `sizeof` is the operator that does not take it.
387        assert_eq!(f.text(decayed), "convert array-decay : int *\n  decl #0 : int [3] lvalue\n");
388    }
389
390    #[test]
391    fn a_function_decays_to_a_pointer_to_itself() {
392        let mut f = Fixture::new();
393        let void = f.types.void();
394        let signature =
395            FunctionType { ret: void, params: Vec::new(), variadic: false, prototyped: true };
396        let function = f.types.function(signature);
397        let designator =
398            f.tast.expr(Expr::new(ExprKind::Error, function, Category::Function), Span::DUMMY);
399        let decayed = f.conv().value(designator);
400
401        assert_eq!(
402            f.text(decayed),
403            "convert function-decay : void (*)(void)\n  error : void (void) function\n"
404        );
405    }
406
407    #[test]
408    fn a_narrow_integer_promotes_and_an_int_does_not_move() {
409        let mut f = Fixture::new();
410        let char_type = f.types.int(IntKind::Char);
411        let int = f.types.int(IntKind::Int);
412        let narrow = f.object(char_type);
413        let wide = f.object(int);
414
415        let promoted = f.conv().promote(narrow);
416        assert_eq!(f.tast[promoted].ty, int);
417        assert_eq!(
418            f.text(promoted),
419            "convert arithmetic : int\n  convert lvalue : char\n    decl #0 : char lvalue\n"
420        );
421
422        // Nothing is written where nothing happens, so a dump has no noise in it.
423        let already = f.conv().promote(wide);
424        assert_eq!(f.text(already), "convert lvalue : int\n  decl #1 : int lvalue\n");
425    }
426
427    #[test]
428    fn a_bit_field_promotes_by_its_width_and_not_by_its_type() {
429        let mut f = Fixture::new();
430        let unsigned = f.types.int(IntKind::UInt);
431        let int = f.types.int(IntKind::Int);
432        let three = f.object(unsigned);
433        let full = f.object(unsigned);
434
435        // Every three bit value fits in an `int`, so the promotion changes the signedness.
436        let narrow = f.conv().promote_bits(three, 3);
437        assert_eq!(f.tast[narrow].ty, int);
438        // Thirty two bit values no longer do.
439        let wide = f.conv().promote_bits(full, 32);
440        assert_eq!(f.tast[wide].ty, unsigned);
441    }
442
443    #[test]
444    fn a_bit_field_operand_promotes_by_its_width_without_being_asked() {
445        // The width is not on the operand, so this is the one promotion that has to be found
446        // rather than read off the node, and forgetting it makes `b.flag + 1` come out unsigned
447        // for a one bit field. gcc says `int`, and so does 6.3.1.1p2.
448        let mut f = Fixture::new();
449        let unsigned = f.types.int(IntKind::UInt);
450        let int = f.types.int(IntKind::Int);
451        let one = f.zero(int);
452        let again = f.zero(int);
453
454        let narrow = f.bit_field(unsigned, 1);
455        let (lhs, rhs) = f.conv().usual_arithmetic(narrow, one).expect("both are arithmetic");
456        assert_eq!(f.tast[lhs].ty, int);
457        assert_eq!(f.tast[rhs].ty, int);
458
459        // A field as wide as the type it was declared with keeps that type, which is the case
460        // that says the width is what decides and not the fact of being a bit-field.
461        let full = f.bit_field(unsigned, 32);
462        let (lhs, rhs) = f.conv().usual_arithmetic(full, again).expect("both are arithmetic");
463        assert_eq!(f.tast[lhs].ty, unsigned);
464        assert_eq!(f.tast[rhs].ty, unsigned);
465    }
466
467    #[test]
468    fn a_bit_field_that_has_already_been_read_still_promotes_by_its_width() {
469        // Almost every caller reads the object before it knows it is about to promote, so the
470        // member is under an lvalue conversion by the time the promotion looks for it.
471        let mut f = Fixture::new();
472        let unsigned = f.types.int(IntKind::UInt);
473        let int = f.types.int(IntKind::Int);
474        let narrow = f.bit_field(unsigned, 1);
475        let read = f.conv().value(narrow);
476
477        let promoted = f.conv().promote(read);
478        assert_eq!(f.tast[promoted].ty, int);
479    }
480
481    #[test]
482    fn the_usual_arithmetic_conversions_move_both_sides_to_one_type() {
483        let mut f = Fixture::new();
484        let int = f.types.int(IntKind::Int);
485        let long = f.types.int(IntKind::Long);
486        let narrow = f.object(int);
487        let wide = f.object(long);
488
489        let (lhs, rhs) = f.conv().usual_arithmetic(narrow, wide).expect("both are arithmetic");
490        assert_eq!(f.tast[lhs].ty, long);
491        assert_eq!(f.tast[rhs].ty, long);
492    }
493
494    #[test]
495    fn a_pointer_pair_has_no_usual_arithmetic_conversion() {
496        let mut f = Fixture::new();
497        let int = f.types.int(IntKind::Int);
498        let pointer = f.types.pointer(int);
499        let left = f.object(pointer);
500        let right = f.object(int);
501
502        assert!(f.conv().usual_arithmetic(left, right).is_none());
503    }
504
505    #[test]
506    fn a_condition_is_a_comparison_against_zero_and_not_a_truncation() {
507        let mut f = Fixture::new();
508        let int = f.types.int(IntKind::Int);
509        let object = f.object(int);
510        let condition = f.conv().to_bool(object);
511
512        // `(bool) 256` is true and `(char) 256` is zero, which is why this is its own kind.
513        assert_eq!(
514            f.text(condition),
515            "convert bool : _Bool\n  convert lvalue : int\n    decl #0 : int lvalue\n"
516        );
517    }
518
519    #[test]
520    fn a_zero_of_any_integer_type_is_a_null_pointer_constant() {
521        let mut f = Fixture::new();
522        let long = f.types.int(IntKind::Long);
523        let int = f.types.int(IntKind::Int);
524        let pointer = f.types.pointer(int);
525        let zero = f.zero(long);
526        let null = f.conv().to_type(zero, pointer);
527
528        assert_eq!(f.text(null), "convert null-pointer : int *\n  const 0 : long\n");
529    }
530
531    #[test]
532    fn a_pointer_that_is_not_a_constant_zero_is_an_ordinary_pointer_conversion() {
533        let mut f = Fixture::new();
534        let int = f.types.int(IntKind::Int);
535        let void = f.types.void();
536        let from = f.types.pointer(void);
537        let to = f.types.pointer(int);
538        let object = f.object(from);
539        let converted = f.conv().to_type(object, to);
540
541        assert_eq!(
542            f.text(converted),
543            "convert pointer : int *\n  convert lvalue : void *\n    decl #0 : void * lvalue\n"
544        );
545    }
546
547    #[test]
548    fn converting_to_the_type_it_already_has_writes_nothing() {
549        let mut f = Fixture::new();
550        let int = f.types.int(IntKind::Int);
551        let object = f.object(int);
552        let read = f.conv().value(object);
553        let again = f.conv().to_type(read, int);
554
555        assert_eq!(read, again);
556    }
557
558    #[test]
559    fn a_value_is_discarded_by_a_node_rather_than_by_being_ignored() {
560        let mut f = Fixture::new();
561        let int = f.types.int(IntKind::Int);
562        let object = f.object(int);
563        let dropped = f.conv().to_void(object);
564
565        assert_eq!(f.text(dropped), "convert void : void\n  decl #0 : int lvalue\n");
566    }
567}