1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5use std::borrow::Cow;
6use std::io::Write;
7
8use syn::ext::IdentExt;
9
10use crate::bindgen::cdecl;
11use crate::bindgen::config::{Config, Language};
12use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver;
13use crate::bindgen::dependencies::Dependencies;
14use crate::bindgen::ir::{GenericArgument, GenericParams, GenericPath, Path};
15use crate::bindgen::library::Library;
16use crate::bindgen::monomorph::Monomorphs;
17use crate::bindgen::utilities::IterHelpers;
18use crate::bindgen::writer::{Source, SourceWriter};
19
20#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
21pub enum PrimitiveType {
22 Void,
23 Bool,
24 Char,
25 SChar,
26 UChar,
27 Char32,
28 Float,
29 Double,
30 VaList,
31 PtrDiffT,
32 Integer {
33 zeroable: bool,
34 signed: bool,
35 kind: IntKind,
36 },
37}
38
39#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
40pub enum IntKind {
41 Short,
42 Int,
43 Long,
44 LongLong,
45 SizeT,
46 Size,
47 B8,
48 B16,
49 B32,
50 B64,
51}
52
53impl PrimitiveType {
54 pub fn maybe(path: &str) -> Option<PrimitiveType> {
55 Some(match path {
56 "c_void" => PrimitiveType::Void,
57 "c_char" => PrimitiveType::Char,
58 "c_schar" => PrimitiveType::SChar,
59 "c_uchar" => PrimitiveType::UChar,
60 "c_float" => PrimitiveType::Float,
61 "c_double" => PrimitiveType::Double,
62 "ptrdiff_t" => PrimitiveType::PtrDiffT,
63 "VaList" => PrimitiveType::VaList,
64 "bool" => PrimitiveType::Bool,
65 "char" => PrimitiveType::Char32,
66
67 "f32" => PrimitiveType::Float,
68 "f64" => PrimitiveType::Double,
69
70 _ => {
71 let (kind, signed) = match path {
72 "c_short" => (IntKind::Short, true),
73 "c_int" => (IntKind::Int, true),
74 "c_long" => (IntKind::Long, true),
75 "c_longlong" => (IntKind::LongLong, true),
76 "ssize_t" => (IntKind::SizeT, true),
77 "c_ushort" => (IntKind::Short, false),
78 "c_uint" => (IntKind::Int, false),
79 "c_ulong" => (IntKind::Long, false),
80 "c_ulonglong" => (IntKind::LongLong, false),
81 "size_t" => (IntKind::SizeT, false),
82 "RawFd" => (IntKind::Int, true),
83
84 "isize" | "intptr_t" => (IntKind::Size, true),
85 "usize" | "uintptr_t" => (IntKind::Size, false),
86
87 "u8" | "uint8_t" => (IntKind::B8, false),
88 "u16" | "uint16_t" => (IntKind::B16, false),
89 "u32" | "uint32_t" => (IntKind::B32, false),
90 "u64" | "uint64_t" => (IntKind::B64, false),
91 "i8" | "int8_t" => (IntKind::B8, true),
92 "i16" | "int16_t" => (IntKind::B16, true),
93 "i32" | "int32_t" => (IntKind::B32, true),
94 "i64" | "int64_t" => (IntKind::B64, true),
95 _ => return None,
96 };
97 PrimitiveType::Integer {
98 zeroable: true,
99 signed,
100 kind,
101 }
102 }
103 })
104 }
105
106 pub fn to_repr_rust(&self) -> &'static str {
107 match *self {
108 PrimitiveType::Bool => "bool",
109 PrimitiveType::Void => "c_void",
110 PrimitiveType::Char => "c_char",
111 PrimitiveType::SChar => "c_schar",
112 PrimitiveType::UChar => "c_uchar",
113 PrimitiveType::Char32 => "char",
114 PrimitiveType::Integer {
115 kind,
116 signed,
117 zeroable: _,
118 } => match kind {
119 IntKind::Short => {
120 if signed {
121 "c_short"
122 } else {
123 "c_ushort"
124 }
125 }
126 IntKind::Int => {
127 if signed {
128 "c_int"
129 } else {
130 "c_uint"
131 }
132 }
133 IntKind::Long => {
134 if signed {
135 "c_long"
136 } else {
137 "c_ulong"
138 }
139 }
140 IntKind::LongLong => {
141 if signed {
142 "c_longlong"
143 } else {
144 "c_ulonglong"
145 }
146 }
147 IntKind::SizeT => {
148 if signed {
149 "ssize_t"
150 } else {
151 "size_t"
152 }
153 }
154 IntKind::Size => {
155 if signed {
156 "isize"
157 } else {
158 "usize"
159 }
160 }
161 IntKind::B8 => {
162 if signed {
163 "i8"
164 } else {
165 "u8"
166 }
167 }
168 IntKind::B16 => {
169 if signed {
170 "i16"
171 } else {
172 "u16"
173 }
174 }
175 IntKind::B32 => {
176 if signed {
177 "i32"
178 } else {
179 "u32"
180 }
181 }
182 IntKind::B64 => {
183 if signed {
184 "i64"
185 } else {
186 "u64"
187 }
188 }
189 },
190 PrimitiveType::Float => "f32",
191 PrimitiveType::Double => "f64",
192 PrimitiveType::PtrDiffT => "ptrdiff_t",
193 PrimitiveType::VaList => "va_list",
194 }
195 }
196
197 pub fn to_repr_c(&self, config: &Config) -> &'static str {
198 match *self {
199 PrimitiveType::Void => "void",
200 PrimitiveType::Bool => "bool",
201 PrimitiveType::Char => "char",
202 PrimitiveType::SChar => "signed char",
203 PrimitiveType::UChar => "unsigned char",
204 // NOTE: It'd be nice to use a char32_t, but:
205 //
206 // * uchar.h is not present on mac (see #423).
207 //
208 // * char32_t isn't required to be compatible with Rust's char, as
209 // the C++ spec only requires it to be the same size as
210 // uint_least32_t, which is _not_ guaranteed to be 4-bytes.
211 //
212 PrimitiveType::Char32 => "uint32_t",
213 PrimitiveType::Integer {
214 kind,
215 signed,
216 zeroable: _,
217 } => match kind {
218 IntKind::Short => {
219 if signed {
220 "short"
221 } else {
222 "unsigned short"
223 }
224 }
225 IntKind::Int => {
226 if signed {
227 "int"
228 } else {
229 "unsigned int"
230 }
231 }
232 IntKind::Long => {
233 if signed {
234 "long"
235 } else {
236 "unsigned long"
237 }
238 }
239 IntKind::LongLong => {
240 if signed {
241 "long long"
242 } else {
243 "unsigned long long"
244 }
245 }
246 IntKind::SizeT => {
247 if signed {
248 "ssize_t"
249 } else {
250 "size_t"
251 }
252 }
253 IntKind::Size => {
254 if config.usize_is_size_t {
255 if signed {
256 "ptrdiff_t"
257 } else {
258 "size_t"
259 }
260 } else if signed {
261 "intptr_t"
262 } else {
263 "uintptr_t"
264 }
265 }
266 IntKind::B8 => {
267 if signed {
268 "int8_t"
269 } else {
270 "uint8_t"
271 }
272 }
273 IntKind::B16 => {
274 if signed {
275 "int16_t"
276 } else {
277 "uint16_t"
278 }
279 }
280 IntKind::B32 => {
281 if signed {
282 "int32_t"
283 } else {
284 "uint32_t"
285 }
286 }
287 IntKind::B64 => {
288 if signed {
289 "int64_t"
290 } else {
291 "uint64_t"
292 }
293 }
294 },
295 PrimitiveType::Float => "float",
296 PrimitiveType::Double => "double",
297 PrimitiveType::PtrDiffT => "ptrdiff_t",
298 PrimitiveType::VaList => "va_list",
299 }
300 }
301
302 fn can_cmp_order(&self) -> bool {
303 !matches!(*self, PrimitiveType::Bool)
304 }
305
306 fn can_cmp_eq(&self) -> bool {
307 true
308 }
309}
310
311/// Constant expressions.
312///
313/// Used for the `U` part of `[T; U]` and const generics. We support a very
314/// limited vocabulary here: only identifiers and literals.
315#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
316pub enum ConstExpr {
317 Name(String),
318 Value(String),
319}
320
321impl ConstExpr {
322 pub fn as_str(&self) -> &str {
323 match *self {
324 ConstExpr::Name(ref string) | ConstExpr::Value(ref string) => string,
325 }
326 }
327
328 pub fn rename_for_config(&mut self, config: &Config) {
329 if let ConstExpr::Name(ref mut name) = self {
330 config.export.rename(name);
331 }
332 }
333
334 pub fn load(expr: &syn::Expr) -> Result<Self, String> {
335 match *expr {
336 syn::Expr::Lit(syn::ExprLit { ref lit, .. }) => {
337 let val = match *lit {
338 syn::Lit::Bool(syn::LitBool { value, .. }) => value.to_string(),
339 syn::Lit::Int(ref len) => len.base10_digits().to_string(),
340 syn::Lit::Byte(ref byte) => u8::to_string(&byte.value()),
341 syn::Lit::Char(ref ch) => u32::to_string(&ch.value().into()),
342 _ => return Err(format!("can't handle const expression {:?}", lit)),
343 };
344 Ok(ConstExpr::Value(val))
345 }
346 syn::Expr::Path(ref path) => {
347 let generic_path = GenericPath::load(&path.path)?;
348 Ok(ConstExpr::Name(generic_path.export_name().to_owned()))
349 }
350 _ => Err(format!("can't handle const expression {:?}", expr)),
351 }
352 }
353
354 pub fn specialize(&self, mappings: &[(&Path, &GenericArgument)]) -> ConstExpr {
355 match *self {
356 ConstExpr::Name(ref name) => {
357 let path = Path::new(name);
358 for &(param, value) in mappings {
359 if path == *param {
360 match *value {
361 GenericArgument::Type(Type::Path(ref path))
362 if path.is_single_identifier() =>
363 {
364 // This happens when the generic argument is a path.
365 return ConstExpr::Name(path.name().to_string());
366 }
367 GenericArgument::Const(ref expr) => {
368 return expr.clone();
369 }
370 _ => {
371 // unsupported argument type - really should be an error
372 }
373 }
374 }
375 }
376 }
377 ConstExpr::Value(_) => {}
378 }
379 self.clone()
380 }
381}
382
383impl Source for ConstExpr {
384 fn write<F: Write>(&self, _config: &Config, out: &mut SourceWriter<F>) {
385 write!(out, "{}", self.as_str());
386 }
387}
388
389#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
390pub enum Type {
391 Ptr {
392 ty: Box<Type>,
393 is_const: bool,
394 is_nullable: bool,
395 // FIXME: This is a bit of a hack, this is only to get us to codegen
396 // `T&` / `const T&`, but we should probably pass that down as an option
397 // to code generation or something.
398 is_ref: bool,
399 },
400 Path(GenericPath),
401 Primitive(PrimitiveType),
402 Array(Box<Type>, ConstExpr),
403 FuncPtr {
404 ret: Box<Type>,
405 args: Vec<(Option<String>, Type)>,
406 is_nullable: bool,
407 never_return: bool,
408 },
409}
410
411impl Type {
412 pub fn const_ref_to(ty: &Self) -> Self {
413 Type::Ptr {
414 ty: Box::new(ty.clone()),
415 is_const: true,
416 is_nullable: false,
417 is_ref: true,
418 }
419 }
420
421 pub fn load_from_output(output: &syn::ReturnType) -> Result<(Type, bool), String> {
422 let mut never_return = false;
423 let ty = match output {
424 syn::ReturnType::Default => Type::Primitive(PrimitiveType::Void),
425 syn::ReturnType::Type(_, ref ty) => {
426 if let syn::Type::Never(_) = ty.as_ref() {
427 never_return = true;
428 Type::Primitive(PrimitiveType::Void)
429 } else {
430 Type::load(ty)?.unwrap_or(Type::Primitive(PrimitiveType::Void))
431 }
432 }
433 };
434 Ok((ty, never_return))
435 }
436
437 pub fn load(ty: &syn::Type) -> Result<Option<Type>, String> {
438 let converted = match *ty {
439 syn::Type::Reference(ref reference) => {
440 let converted = Type::load(&reference.elem)?;
441
442 let converted = match converted {
443 Some(converted) => converted,
444 None => Type::Primitive(PrimitiveType::Void),
445 };
446
447 // TODO(emilio): we could make these use is_ref: true.
448 let is_const = reference.mutability.is_none();
449 Type::Ptr {
450 ty: Box::new(converted),
451 is_const,
452 is_nullable: false,
453 is_ref: false,
454 }
455 }
456 syn::Type::Ptr(ref pointer) => {
457 let converted = Type::load(&pointer.elem)?;
458
459 let converted = match converted {
460 Some(converted) => converted,
461 None => Type::Primitive(PrimitiveType::Void),
462 };
463
464 let is_const = pointer.mutability.is_none();
465 Type::Ptr {
466 ty: Box::new(converted),
467 is_const,
468 is_nullable: true,
469 is_ref: false,
470 }
471 }
472 syn::Type::Path(ref path) => {
473 let generic_path = GenericPath::load(&path.path)?;
474
475 if generic_path.name() == "PhantomData" || generic_path.name() == "PhantomPinned" {
476 return Ok(None);
477 }
478
479 if let Some(prim) = PrimitiveType::maybe(generic_path.name()) {
480 if !generic_path.generics().is_empty() {
481 return Err("Primitive has generics.".to_owned());
482 }
483 Type::Primitive(prim)
484 } else {
485 Type::Path(generic_path)
486 }
487 }
488 syn::Type::Array(syn::TypeArray {
489 ref elem, ref len, ..
490 }) => {
491 let converted = Type::load(elem)?;
492
493 let converted = match converted {
494 Some(converted) => converted,
495 None => return Err("Cannot have an array of zero sized types.".to_owned()),
496 };
497
498 let len = ConstExpr::load(len)?;
499 Type::Array(Box::new(converted), len)
500 }
501 syn::Type::BareFn(ref function) => {
502 let mut wildcard_counter = 0;
503 let args = function.inputs.iter().try_skip_map(|x| {
504 Type::load(&x.ty).map(|opt_ty| {
505 opt_ty.map(|ty| {
506 (
507 x.name.as_ref().map(|(ref ident, _)| {
508 if ident == "_" {
509 wildcard_counter += 1;
510 if wildcard_counter == 1 {
511 "_".to_owned()
512 } else {
513 format!("_{}", wildcard_counter - 1)
514 }
515 } else {
516 ident.unraw().to_string()
517 }
518 }),
519 ty,
520 )
521 })
522 })
523 })?;
524 let (ret, never_return) = Type::load_from_output(&function.output)?;
525 Type::FuncPtr {
526 ret: Box::new(ret),
527 args,
528 is_nullable: false,
529 never_return,
530 }
531 }
532 syn::Type::Tuple(ref tuple) => {
533 if tuple.elems.is_empty() {
534 return Ok(None);
535 }
536 return Err("Tuples are not supported types.".to_owned());
537 }
538 syn::Type::Verbatim(ref tokens) if tokens.to_string() == "..." => {
539 Type::Primitive(PrimitiveType::VaList)
540 }
541 _ => return Err(format!("Unsupported type: {:?}", ty)),
542 };
543
544 Ok(Some(converted))
545 }
546
547 pub fn is_ptr(&self) -> bool {
548 matches!(*self, Type::Ptr { .. } | Type::FuncPtr { .. })
549 }
550
551 pub fn is_primitive_or_ptr_primitive(&self) -> bool {
552 match *self {
553 Type::Primitive(..) => true,
554 Type::Ptr { ref ty, .. } => matches!(ty.as_ref(), Type::Primitive(..)),
555 _ => false,
556 }
557 }
558
559 pub fn make_zeroable(&self) -> Option<Self> {
560 let (kind, signed) = match *self {
561 Type::Primitive(PrimitiveType::Integer {
562 zeroable: false,
563 kind,
564 signed,
565 }) => (kind, signed),
566 _ => return None,
567 };
568
569 Some(Type::Primitive(PrimitiveType::Integer {
570 kind,
571 signed,
572 zeroable: true,
573 }))
574 }
575
576 pub fn make_nullable(&self) -> Option<Self> {
577 match *self {
578 Type::Ptr {
579 ref ty,
580 is_const,
581 is_ref,
582 is_nullable: false,
583 } => Some(Type::Ptr {
584 ty: ty.clone(),
585 is_const,
586 is_ref,
587 is_nullable: true,
588 }),
589 Type::FuncPtr {
590 ref ret,
591 ref args,
592 is_nullable: false,
593 never_return,
594 } => Some(Type::FuncPtr {
595 ret: ret.clone(),
596 args: args.clone(),
597 is_nullable: true,
598 never_return,
599 }),
600 _ => None,
601 }
602 }
603
604 fn nonzero_to_primitive(&self) -> Option<Self> {
605 let path = match *self {
606 Type::Path(ref p) => p,
607 _ => return None,
608 };
609
610 if !path.generics().is_empty() {
611 return None;
612 }
613
614 let name = path.name();
615 if !name.starts_with("NonZero") {
616 return None;
617 }
618
619 let (kind, signed) = match path.name() {
620 "NonZeroU8" => (IntKind::B8, false),
621 "NonZeroU16" => (IntKind::B16, false),
622 "NonZeroU32" => (IntKind::B32, false),
623 "NonZeroU64" => (IntKind::B64, false),
624 "NonZeroUSize" => (IntKind::Size, false),
625 "NonZeroI8" => (IntKind::B8, true),
626 "NonZeroI16" => (IntKind::B16, true),
627 "NonZeroI32" => (IntKind::B32, true),
628 "NonZeroI64" => (IntKind::B64, true),
629 "NonZeroISize" => (IntKind::Size, true),
630 _ => return None,
631 };
632
633 Some(Type::Primitive(PrimitiveType::Integer {
634 zeroable: false,
635 signed,
636 kind,
637 }))
638 }
639
640 fn simplified_type(&self, config: &Config) -> Option<Self> {
641 let path = match *self {
642 Type::Path(ref p) => p,
643 _ => return None,
644 };
645
646 if path.generics().is_empty() {
647 return self.nonzero_to_primitive();
648 }
649
650 if path.generics().len() != 1 {
651 return None;
652 }
653
654 let unsimplified_generic = match path.generics()[0] {
655 GenericArgument::Type(ref ty) => ty,
656 GenericArgument::Const(_) => return None,
657 };
658
659 let generic = match unsimplified_generic.simplified_type(config) {
660 Some(generic) => Cow::Owned(generic),
661 None => Cow::Borrowed(unsimplified_generic),
662 };
663 match path.name() {
664 "Option" => {
665 if let Some(nullable) = generic.make_nullable() {
666 return Some(nullable);
667 }
668 if let Some(zeroable) = generic.make_zeroable() {
669 return Some(zeroable);
670 }
671 None
672 }
673 "NonNull" => Some(Type::Ptr {
674 ty: Box::new(generic.into_owned()),
675 is_const: false,
676 is_nullable: false,
677 is_ref: false,
678 }),
679 "Box" if config.language != Language::Cxx => Some(Type::Ptr {
680 ty: Box::new(generic.into_owned()),
681 is_const: false,
682 is_nullable: false,
683 is_ref: false,
684 }),
685 "Cell" => Some(generic.into_owned()),
686 "ManuallyDrop" | "MaybeUninit" | "Pin" if config.language != Language::Cxx => {
687 Some(generic.into_owned())
688 }
689 _ => None,
690 }
691 }
692
693 pub fn simplify_standard_types(&mut self, config: &Config) {
694 self.visit_types(|ty| ty.simplify_standard_types(config));
695 if let Some(ty) = self.simplified_type(config) {
696 *self = ty;
697 }
698 }
699
700 pub fn replace_self_with(&mut self, self_ty: &Path) {
701 if let Type::Path(ref mut generic_path) = *self {
702 generic_path.replace_self_with(self_ty);
703 }
704 self.visit_types(|ty| ty.replace_self_with(self_ty))
705 }
706
707 fn visit_types(&mut self, mut visitor: impl FnMut(&mut Type)) {
708 match *self {
709 Type::Array(ref mut ty, ..) | Type::Ptr { ref mut ty, .. } => visitor(ty),
710 Type::Path(ref mut path) => {
711 for generic in path.generics_mut() {
712 match *generic {
713 GenericArgument::Type(ref mut ty) => visitor(ty),
714 GenericArgument::Const(_) => {}
715 }
716 }
717 }
718 Type::Primitive(..) => {}
719 Type::FuncPtr {
720 ref mut ret,
721 ref mut args,
722 ..
723 } => {
724 visitor(ret);
725 for arg in args {
726 visitor(&mut arg.1)
727 }
728 }
729 }
730 }
731
732 pub fn get_root_path(&self) -> Option<Path> {
733 let mut current = self;
734 loop {
735 match *current {
736 Type::Ptr { ref ty, .. } => current = ty,
737 Type::Path(ref generic) => {
738 return Some(generic.path().clone());
739 }
740 Type::Primitive(..) => {
741 return None;
742 }
743 Type::Array(..) => {
744 return None;
745 }
746 Type::FuncPtr { .. } => {
747 return None;
748 }
749 };
750 }
751 }
752
753 pub fn specialize(&self, mappings: &[(&Path, &GenericArgument)]) -> Type {
754 match *self {
755 Type::Ptr {
756 ref ty,
757 is_const,
758 is_nullable,
759 is_ref,
760 } => Type::Ptr {
761 ty: Box::new(ty.specialize(mappings)),
762 is_const,
763 is_nullable,
764 is_ref,
765 },
766 Type::Path(ref generic_path) => {
767 for &(param, value) in mappings {
768 if generic_path.path() == param {
769 if let GenericArgument::Type(ref ty) = *value {
770 return ty.clone();
771 }
772 }
773 }
774
775 let specialized = GenericPath::new(
776 generic_path.path().clone(),
777 generic_path
778 .generics()
779 .iter()
780 .map(|x| x.specialize(mappings))
781 .collect(),
782 );
783 Type::Path(specialized)
784 }
785 Type::Primitive(ref primitive) => Type::Primitive(primitive.clone()),
786 Type::Array(ref ty, ref constant) => Type::Array(
787 Box::new(ty.specialize(mappings)),
788 constant.specialize(mappings),
789 ),
790 Type::FuncPtr {
791 ref ret,
792 ref args,
793 is_nullable,
794 never_return,
795 } => Type::FuncPtr {
796 ret: Box::new(ret.specialize(mappings)),
797 args: args
798 .iter()
799 .cloned()
800 .map(|(name, ty)| (name, ty.specialize(mappings)))
801 .collect(),
802 is_nullable,
803 never_return,
804 },
805 }
806 }
807
808 pub fn add_dependencies_ignoring_generics(
809 &self,
810 generic_params: &GenericParams,
811 library: &Library,
812 out: &mut Dependencies,
813 ) {
814 match *self {
815 Type::Ptr { ref ty, .. } => {
816 ty.add_dependencies_ignoring_generics(generic_params, library, out);
817 }
818 Type::Path(ref generic) => {
819 for generic_value in generic.generics() {
820 if let GenericArgument::Type(ref ty) = *generic_value {
821 ty.add_dependencies_ignoring_generics(generic_params, library, out);
822 }
823 }
824 let path = generic.path();
825 if !generic_params.iter().any(|param| param.name() == path) {
826 if let Some(items) = library.get_items(path) {
827 if !out.items.contains(path) {
828 out.items.insert(path.clone());
829
830 for item in &items {
831 item.deref().add_dependencies(library, out);
832 }
833 for item in items {
834 out.order.push(item);
835 }
836 }
837 } else {
838 warn!(
839 "Can't find {}. This usually means that this type was incompatible or \
840 not found.",
841 path
842 );
843 }
844 }
845 }
846 Type::Primitive(_) => {}
847 Type::Array(ref ty, _) => {
848 ty.add_dependencies_ignoring_generics(generic_params, library, out);
849 }
850 Type::FuncPtr {
851 ref ret, ref args, ..
852 } => {
853 ret.add_dependencies_ignoring_generics(generic_params, library, out);
854 for (_, ref arg) in args {
855 arg.add_dependencies_ignoring_generics(generic_params, library, out);
856 }
857 }
858 }
859 }
860
861 pub fn add_dependencies(&self, library: &Library, out: &mut Dependencies) {
862 self.add_dependencies_ignoring_generics(&GenericParams::default(), library, out)
863 }
864
865 pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) {
866 match *self {
867 Type::Ptr { ref ty, .. } => {
868 ty.add_monomorphs(library, out);
869 }
870 Type::Path(ref generic) => {
871 if generic.generics().is_empty() || out.contains(generic) {
872 return;
873 }
874 let path = generic.path();
875 if let Some(items) = library.get_items(path) {
876 for item in items {
877 item.deref()
878 .instantiate_monomorph(generic.generics(), library, out);
879 }
880 }
881 }
882 Type::Primitive(_) => {}
883 Type::Array(ref ty, _) => {
884 ty.add_monomorphs(library, out);
885 }
886 Type::FuncPtr {
887 ref ret, ref args, ..
888 } => {
889 ret.add_monomorphs(library, out);
890 for (_, ref arg) in args {
891 arg.add_monomorphs(library, out);
892 }
893 }
894 }
895 }
896
897 pub fn rename_for_config(&mut self, config: &Config, generic_params: &GenericParams) {
898 match *self {
899 Type::Ptr { ref mut ty, .. } => {
900 ty.rename_for_config(config, generic_params);
901 }
902 Type::Path(ref mut ty) => {
903 ty.rename_for_config(config, generic_params);
904 }
905 Type::Primitive(_) => {}
906 Type::Array(ref mut ty, ref mut len) => {
907 ty.rename_for_config(config, generic_params);
908 len.rename_for_config(config);
909 }
910 Type::FuncPtr {
911 ref mut ret,
912 ref mut args,
913 ..
914 } => {
915 ret.rename_for_config(config, generic_params);
916 for (_, arg) in args {
917 arg.rename_for_config(config, generic_params);
918 }
919 }
920 }
921 }
922
923 pub fn resolve_declaration_types(&mut self, resolver: &DeclarationTypeResolver) {
924 match *self {
925 Type::Ptr { ref mut ty, .. } => {
926 ty.resolve_declaration_types(resolver);
927 }
928 Type::Path(ref mut generic_path) => {
929 generic_path.resolve_declaration_types(resolver);
930 }
931 Type::Primitive(_) => {}
932 Type::Array(ref mut ty, _) => {
933 ty.resolve_declaration_types(resolver);
934 }
935 Type::FuncPtr {
936 ref mut ret,
937 ref mut args,
938 ..
939 } => {
940 ret.resolve_declaration_types(resolver);
941 for (_, ref mut arg) in args {
942 arg.resolve_declaration_types(resolver);
943 }
944 }
945 }
946 }
947
948 pub fn mangle_paths(&mut self, monomorphs: &Monomorphs) {
949 match *self {
950 Type::Ptr { ref mut ty, .. } => {
951 ty.mangle_paths(monomorphs);
952 }
953 Type::Path(ref mut generic_path) => {
954 if generic_path.generics().is_empty() {
955 return;
956 }
957
958 if let Some(mangled_path) = monomorphs.mangle_path(generic_path) {
959 *generic_path = GenericPath::new(mangled_path.clone(), vec![]);
960 } else {
961 warn!(
962 "Cannot find a mangling for generic path {:?}. This usually means that a \
963 type referenced by this generic was incompatible or not found.",
964 generic_path
965 );
966 }
967 }
968 Type::Primitive(_) => {}
969 Type::Array(ref mut ty, _) => {
970 ty.mangle_paths(monomorphs);
971 }
972 Type::FuncPtr {
973 ref mut ret,
974 ref mut args,
975 ..
976 } => {
977 ret.mangle_paths(monomorphs);
978 for (_, ref mut arg) in args {
979 arg.mangle_paths(monomorphs);
980 }
981 }
982 }
983 }
984
985 pub fn can_cmp_order(&self) -> bool {
986 match *self {
987 // FIXME: Shouldn't this look at ty.can_cmp_order() as well?
988 Type::Ptr { is_ref, .. } => !is_ref,
989 Type::Path(..) => true,
990 Type::Primitive(ref p) => p.can_cmp_order(),
991 Type::Array(..) => false,
992 Type::FuncPtr { .. } => false,
993 }
994 }
995
996 pub fn can_cmp_eq(&self) -> bool {
997 match *self {
998 Type::Ptr { ref ty, is_ref, .. } => !is_ref || ty.can_cmp_eq(),
999 Type::Path(..) => true,
1000 Type::Primitive(ref p) => p.can_cmp_eq(),
1001 Type::Array(..) => false,
1002 Type::FuncPtr { .. } => true,
1003 }
1004 }
1005}
1006
1007impl Source for String {
1008 fn write<F: Write>(&self, _config: &Config, out: &mut SourceWriter<F>) {
1009 write!(out, "{}", self);
1010 }
1011}
1012
1013impl Source for Type {
1014 fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
1015 cdecl::write_type(out, self, config);
1016 }
1017}
1018