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                    constant: false,
312                    init: None,
313                    params: DeclList::EMPTY,
314                    body: None,
315                },
316                Span::DUMMY,
317            );
318            self.tast.expr(Expr::new(ExprKind::Decl(decl), ty, Category::Lvalue), Span::DUMMY)
319        }
320
321        /// A use of the one member of a `struct` that has one, which is a bit-field of `bits`.
322        fn bit_field(&mut self, ty: TypeId, bits: u32) -> ExprId {
323            let fields = [rucc_types::FieldDecl::bit_field(None, ty, bits)];
324            let id = self.types.declare_record(rucc_types::RecordKind::Struct, None);
325            let laid_out = rucc_types::layout_record(
326                &self.types,
327                rucc_types::RecordKind::Struct,
328                &fields,
329                &rucc_types::RecordOptions::default(),
330                &self.target,
331            )
332            .expect("a layout");
333            self.types.complete_record(id, laid_out);
334            let record = self.types.record(id);
335            let base = self.object(record);
336            self.tast.expr(
337                Expr::new(ExprKind::Member { base, field: 0 }, ty, Category::Bitfield),
338                Span::DUMMY,
339            )
340        }
341
342        fn zero(&mut self, ty: TypeId) -> ExprId {
343            let value = self.tast.add_const(Const::Int(0));
344            self.tast.expr(Expr::new(ExprKind::Const(value), ty, Category::Rvalue), Span::DUMMY)
345        }
346
347        fn text(&self, expr: ExprId) -> String {
348            let mut printer = Printer::new(&self.tast, &self.types, &self.names);
349            printer.expr(expr);
350            printer.finish()
351        }
352    }
353
354    #[test]
355    fn reading_an_object_drops_the_qualifiers_because_they_are_not_part_of_a_value() {
356        let mut f = Fixture::new();
357        let int = f.types.int(IntKind::Int);
358        let constant = f.types.qualified(int, Qualifiers::CONST);
359        let object = f.object(constant);
360        let read = f.conv().value(object);
361
362        assert_eq!(f.tast[read].ty, int);
363        assert_eq!(f.tast[read].category, Category::Rvalue);
364        assert_eq!(f.text(read), "convert lvalue : int\n  decl #0 : const int lvalue\n");
365    }
366
367    #[test]
368    fn an_atomic_object_reads_as_the_type_it_wraps() {
369        let mut f = Fixture::new();
370        let int = f.types.int(IntKind::Int);
371        let atomic = f.types.atomic(int);
372        let object = f.object(atomic);
373        let read = f.conv().value(object);
374
375        assert_eq!(f.tast[read].ty, int);
376    }
377
378    #[test]
379    fn an_array_decays_and_is_not_read() {
380        let mut f = Fixture::new();
381        let int = f.types.int(IntKind::Int);
382        let array = f.types.array(int, ArrayLen::Fixed(3));
383        let object = f.object(array);
384        let decayed = f.conv().value(object);
385
386        // Not an lvalue conversion, which is why `sizeof a` is the array's size: the decay is a
387        // step of its own and `sizeof` is the operator that does not take it.
388        assert_eq!(f.text(decayed), "convert array-decay : int *\n  decl #0 : int[3] lvalue\n");
389    }
390
391    #[test]
392    fn a_function_decays_to_a_pointer_to_itself() {
393        let mut f = Fixture::new();
394        let void = f.types.void();
395        let signature =
396            FunctionType { ret: void, params: Vec::new(), variadic: false, prototyped: true };
397        let function = f.types.function(signature);
398        let designator =
399            f.tast.expr(Expr::new(ExprKind::Error, function, Category::Function), Span::DUMMY);
400        let decayed = f.conv().value(designator);
401
402        assert_eq!(
403            f.text(decayed),
404            "convert function-decay : void (*)(void)\n  error : void(void) function\n"
405        );
406    }
407
408    #[test]
409    fn a_narrow_integer_promotes_and_an_int_does_not_move() {
410        let mut f = Fixture::new();
411        let char_type = f.types.int(IntKind::Char);
412        let int = f.types.int(IntKind::Int);
413        let narrow = f.object(char_type);
414        let wide = f.object(int);
415
416        let promoted = f.conv().promote(narrow);
417        assert_eq!(f.tast[promoted].ty, int);
418        assert_eq!(
419            f.text(promoted),
420            "convert arithmetic : int\n  convert lvalue : char\n    decl #0 : char lvalue\n"
421        );
422
423        // Nothing is written where nothing happens, so a dump has no noise in it.
424        let already = f.conv().promote(wide);
425        assert_eq!(f.text(already), "convert lvalue : int\n  decl #1 : int lvalue\n");
426    }
427
428    #[test]
429    fn a_bit_field_promotes_by_its_width_and_not_by_its_type() {
430        let mut f = Fixture::new();
431        let unsigned = f.types.int(IntKind::UInt);
432        let int = f.types.int(IntKind::Int);
433        let three = f.object(unsigned);
434        let full = f.object(unsigned);
435
436        // Every three bit value fits in an `int`, so the promotion changes the signedness.
437        let narrow = f.conv().promote_bits(three, 3);
438        assert_eq!(f.tast[narrow].ty, int);
439        // Thirty two bit values no longer do.
440        let wide = f.conv().promote_bits(full, 32);
441        assert_eq!(f.tast[wide].ty, unsigned);
442    }
443
444    #[test]
445    fn a_bit_field_operand_promotes_by_its_width_without_being_asked() {
446        // The width is not on the operand, so this is the one promotion that has to be found
447        // rather than read off the node, and forgetting it makes `b.flag + 1` come out unsigned
448        // for a one bit field. gcc says `int`, and so does 6.3.1.1p2.
449        let mut f = Fixture::new();
450        let unsigned = f.types.int(IntKind::UInt);
451        let int = f.types.int(IntKind::Int);
452        let one = f.zero(int);
453        let again = f.zero(int);
454
455        let narrow = f.bit_field(unsigned, 1);
456        let (lhs, rhs) = f.conv().usual_arithmetic(narrow, one).expect("both are arithmetic");
457        assert_eq!(f.tast[lhs].ty, int);
458        assert_eq!(f.tast[rhs].ty, int);
459
460        // A field as wide as the type it was declared with keeps that type, which is the case
461        // that says the width is what decides and not the fact of being a bit-field.
462        let full = f.bit_field(unsigned, 32);
463        let (lhs, rhs) = f.conv().usual_arithmetic(full, again).expect("both are arithmetic");
464        assert_eq!(f.tast[lhs].ty, unsigned);
465        assert_eq!(f.tast[rhs].ty, unsigned);
466    }
467
468    #[test]
469    fn a_bit_field_that_has_already_been_read_still_promotes_by_its_width() {
470        // Almost every caller reads the object before it knows it is about to promote, so the
471        // member is under an lvalue conversion by the time the promotion looks for it.
472        let mut f = Fixture::new();
473        let unsigned = f.types.int(IntKind::UInt);
474        let int = f.types.int(IntKind::Int);
475        let narrow = f.bit_field(unsigned, 1);
476        let read = f.conv().value(narrow);
477
478        let promoted = f.conv().promote(read);
479        assert_eq!(f.tast[promoted].ty, int);
480    }
481
482    #[test]
483    fn the_usual_arithmetic_conversions_move_both_sides_to_one_type() {
484        let mut f = Fixture::new();
485        let int = f.types.int(IntKind::Int);
486        let long = f.types.int(IntKind::Long);
487        let narrow = f.object(int);
488        let wide = f.object(long);
489
490        let (lhs, rhs) = f.conv().usual_arithmetic(narrow, wide).expect("both are arithmetic");
491        assert_eq!(f.tast[lhs].ty, long);
492        assert_eq!(f.tast[rhs].ty, long);
493    }
494
495    #[test]
496    fn a_pointer_pair_has_no_usual_arithmetic_conversion() {
497        let mut f = Fixture::new();
498        let int = f.types.int(IntKind::Int);
499        let pointer = f.types.pointer(int);
500        let left = f.object(pointer);
501        let right = f.object(int);
502
503        assert!(f.conv().usual_arithmetic(left, right).is_none());
504    }
505
506    #[test]
507    fn a_condition_is_a_comparison_against_zero_and_not_a_truncation() {
508        let mut f = Fixture::new();
509        let int = f.types.int(IntKind::Int);
510        let object = f.object(int);
511        let condition = f.conv().to_bool(object);
512
513        // `(bool) 256` is true and `(char) 256` is zero, which is why this is its own kind.
514        assert_eq!(
515            f.text(condition),
516            "convert bool : _Bool\n  convert lvalue : int\n    decl #0 : int lvalue\n"
517        );
518    }
519
520    #[test]
521    fn a_zero_of_any_integer_type_is_a_null_pointer_constant() {
522        let mut f = Fixture::new();
523        let long = f.types.int(IntKind::Long);
524        let int = f.types.int(IntKind::Int);
525        let pointer = f.types.pointer(int);
526        let zero = f.zero(long);
527        let null = f.conv().to_type(zero, pointer);
528
529        assert_eq!(f.text(null), "convert null-pointer : int *\n  const 0 : long\n");
530    }
531
532    #[test]
533    fn a_pointer_that_is_not_a_constant_zero_is_an_ordinary_pointer_conversion() {
534        let mut f = Fixture::new();
535        let int = f.types.int(IntKind::Int);
536        let void = f.types.void();
537        let from = f.types.pointer(void);
538        let to = f.types.pointer(int);
539        let object = f.object(from);
540        let converted = f.conv().to_type(object, to);
541
542        assert_eq!(
543            f.text(converted),
544            "convert pointer : int *\n  convert lvalue : void *\n    decl #0 : void * lvalue\n"
545        );
546    }
547
548    #[test]
549    fn converting_to_the_type_it_already_has_writes_nothing() {
550        let mut f = Fixture::new();
551        let int = f.types.int(IntKind::Int);
552        let object = f.object(int);
553        let read = f.conv().value(object);
554        let again = f.conv().to_type(read, int);
555
556        assert_eq!(read, again);
557    }
558
559    #[test]
560    fn a_value_is_discarded_by_a_node_rather_than_by_being_ignored() {
561        let mut f = Fixture::new();
562        let int = f.types.int(IntKind::Int);
563        let object = f.object(int);
564        let dropped = f.conv().to_void(object);
565
566        assert_eq!(f.text(dropped), "convert void : void\n  decl #0 : int lvalue\n");
567    }
568}