repr_c_impl/builder/
mod.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2use std::ops::Not;
3
4use crate::layout::{Annotation, Array, BuiltinType, Record, RecordField, Type, TypeLayout};
5use crate::result::{err, Error, ErrorType, Result};
6use crate::target::Target;
7use crate::util::BITS_PER_BYTE;
8use crate::visitor::{
9    visit_array, visit_builtin_type, visit_opaque_type, visit_record_field, Visitor,
10};
11
12pub mod common;
13mod msvc;
14mod sysv_like;
15
16/// Computes the layout of a type.
17///
18/// See the crate documentation for an example.
19pub fn compute_layout(target: Target, ty: &Type<()>) -> Result<Type<TypeLayout>> {
20    pre_validate(ty)?;
21    use Target::*;
22    match target {
23        | Aarch64PcWindowsMsvc
24        | I586PcWindowsMsvc
25        | I686PcWindowsMsvc
26        | I686UnknownWindows
27        | Thumbv7aPcWindowsMsvc
28        | X86_64UnknownWindows
29        | X86_64PcWindowsMsvc => msvc::compute_layout(target, ty),
30        I686PcWindowsGnu | X86_64PcWindowsGnu => sysv_like::mingw::compute_layout(target, ty),
31        _ => sysv_like::sysv::compute_layout(target, ty),
32    }
33}
34
35fn pre_validate(ty: &Type<()>) -> Result<()> {
36    let mut pv = PreValidator(vec![]);
37    pv.visit_type(ty);
38    match pv.0.pop() {
39        Some(e) => Err(e),
40        None => Ok(()),
41    }
42}
43
44struct PreValidator(Vec<Error>);
45
46impl Visitor<()> for PreValidator {
47    fn visit_annotations(&mut self, a: &[Annotation]) {
48        let mut num_pragma_packed = 0;
49        for a in a {
50            match a {
51                Annotation::PragmaPack(_) => num_pragma_packed += 1,
52                Annotation::AttrPacked => {}
53                Annotation::Align(None) => {}
54                Annotation::Align(Some(n)) => {
55                    self.validate_alignment(*n);
56                }
57            }
58        }
59        if num_pragma_packed > 1 {
60            self.0.push(err(ErrorType::MultiplePragmaPackedAnnotations));
61        }
62    }
63
64    fn visit_builtin_type(&mut self, bi: BuiltinType, ty: &Type<()>) {
65        if ty.annotations.is_empty().not() {
66            self.0.push(err(ErrorType::AnnotatedBuiltinType));
67        }
68        visit_builtin_type(self, bi, ty);
69    }
70
71    fn visit_record_field(&mut self, field: &RecordField<()>, rt: &Record<()>, ty: &Type<()>) {
72        match (field.bit_width, field.named) {
73            (Some(0), true) => self.0.push(err(ErrorType::NamedZeroSizeBitField)),
74            (None, false) => self.0.push(err(ErrorType::UnnamedRegularField)),
75            _ => {}
76        }
77        for a in &field.annotations {
78            if let Annotation::PragmaPack(_) = a {
79                self.0.push(err(ErrorType::PragmaPackedField));
80            }
81        }
82        visit_record_field(self, field, rt, ty);
83    }
84
85    fn visit_array(&mut self, at: &Array<()>, ty: &Type<()>) {
86        if ty.annotations.is_empty().not() {
87            self.0.push(err(ErrorType::AnnotatedArray));
88        }
89        visit_array(self, at, ty);
90    }
91
92    fn visit_opaque_type(&mut self, layout: TypeLayout, ty: &Type<()>) {
93        if ty.annotations.is_empty().not() {
94            self.0.push(err(ErrorType::AnnotatedOpaqueType));
95        }
96        if layout.size_bits % BITS_PER_BYTE != 0 {
97            self.0.push(err(ErrorType::SubByteSize));
98        }
99        self.validate_alignment(layout.field_alignment_bits);
100        self.validate_alignment(layout.pointer_alignment_bits);
101        self.validate_alignment(layout.required_alignment_bits);
102        visit_opaque_type(self, layout, ty);
103    }
104}
105
106impl PreValidator {
107    fn validate_alignment(&mut self, a: u64) {
108        if a < BITS_PER_BYTE {
109            self.0.push(err(ErrorType::SubByteAlignment));
110        }
111        if a.is_power_of_two().not() {
112            self.0.push(err(ErrorType::PowerOfTwoAlignment));
113        }
114    }
115}