repr_c_impl/builder/
mod.rs1use 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
16pub 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}