summaryrefslogtreecommitdiffstats
path: root/src/bindgen/ir/ty.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/bindgen/ir/ty.rs')
-rw-r--r--src/bindgen/ir/ty.rs1017
1 files changed, 1017 insertions, 0 deletions
diff --git a/src/bindgen/ir/ty.rs b/src/bindgen/ir/ty.rs
new file mode 100644
index 0000000..5a31fb6
--- /dev/null
+++ b/src/bindgen/ir/ty.rs
@@ -0,0 +1,1017 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use std::borrow::Cow;
+use std::io::Write;
+
+use syn::ext::IdentExt;
+
+use crate::bindgen::cdecl;
+use crate::bindgen::config::{Config, Language};
+use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver;
+use crate::bindgen::dependencies::Dependencies;
+use crate::bindgen::ir::{GenericArgument, GenericParams, GenericPath, Path};
+use crate::bindgen::library::Library;
+use crate::bindgen::monomorph::Monomorphs;
+use crate::bindgen::utilities::IterHelpers;
+use crate::bindgen::writer::{Source, SourceWriter};
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
+pub enum PrimitiveType {
+ Void,
+ Bool,
+ Char,
+ SChar,
+ UChar,
+ Char32,
+ Float,
+ Double,
+ VaList,
+ PtrDiffT,
+ Integer {
+ zeroable: bool,
+ signed: bool,
+ kind: IntKind,
+ },
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
+pub enum IntKind {
+ Short,
+ Int,
+ Long,
+ LongLong,
+ SizeT,
+ Size,
+ B8,
+ B16,
+ B32,
+ B64,
+}
+
+impl PrimitiveType {
+ pub fn maybe(path: &str) -> Option<PrimitiveType> {
+ Some(match path {
+ "c_void" => PrimitiveType::Void,
+ "c_char" => PrimitiveType::Char,
+ "c_schar" => PrimitiveType::SChar,
+ "c_uchar" => PrimitiveType::UChar,
+ "c_float" => PrimitiveType::Float,
+ "c_double" => PrimitiveType::Double,
+ "ptrdiff_t" => PrimitiveType::PtrDiffT,
+ "VaList" => PrimitiveType::VaList,
+ "bool" => PrimitiveType::Bool,
+ "char" => PrimitiveType::Char32,
+
+ "f32" => PrimitiveType::Float,
+ "f64" => PrimitiveType::Double,
+
+ _ => {
+ let (kind, signed) = match path {
+ "c_short" => (IntKind::Short, true),
+ "c_int" => (IntKind::Int, true),
+ "c_long" => (IntKind::Long, true),
+ "c_longlong" => (IntKind::LongLong, true),
+ "ssize_t" => (IntKind::SizeT, true),
+ "c_ushort" => (IntKind::Short, false),
+ "c_uint" => (IntKind::Int, false),
+ "c_ulong" => (IntKind::Long, false),
+ "c_ulonglong" => (IntKind::LongLong, false),
+ "size_t" => (IntKind::SizeT, false),
+ "RawFd" => (IntKind::Int, true),
+
+ "isize" | "intptr_t" => (IntKind::Size, true),
+ "usize" | "uintptr_t" => (IntKind::Size, false),
+
+ "u8" | "uint8_t" => (IntKind::B8, false),
+ "u16" | "uint16_t" => (IntKind::B16, false),
+ "u32" | "uint32_t" => (IntKind::B32, false),
+ "u64" | "uint64_t" => (IntKind::B64, false),
+ "i8" | "int8_t" => (IntKind::B8, true),
+ "i16" | "int16_t" => (IntKind::B16, true),
+ "i32" | "int32_t" => (IntKind::B32, true),
+ "i64" | "int64_t" => (IntKind::B64, true),
+ _ => return None,
+ };
+ PrimitiveType::Integer {
+ zeroable: true,
+ signed,
+ kind,
+ }
+ }
+ })
+ }
+
+ pub fn to_repr_rust(&self) -> &'static str {
+ match *self {
+ PrimitiveType::Bool => "bool",
+ PrimitiveType::Void => "c_void",
+ PrimitiveType::Char => "c_char",
+ PrimitiveType::SChar => "c_schar",
+ PrimitiveType::UChar => "c_uchar",
+ PrimitiveType::Char32 => "char",
+ PrimitiveType::Integer {
+ kind,
+ signed,
+ zeroable: _,
+ } => match kind {
+ IntKind::Short => {
+ if signed {
+ "c_short"
+ } else {
+ "c_ushort"
+ }
+ }
+ IntKind::Int => {
+ if signed {
+ "c_int"
+ } else {
+ "c_uint"
+ }
+ }
+ IntKind::Long => {
+ if signed {
+ "c_long"
+ } else {
+ "c_ulong"
+ }
+ }
+ IntKind::LongLong => {
+ if signed {
+ "c_longlong"
+ } else {
+ "c_ulonglong"
+ }
+ }
+ IntKind::SizeT => {
+ if signed {
+ "ssize_t"
+ } else {
+ "size_t"
+ }
+ }
+ IntKind::Size => {
+ if signed {
+ "isize"
+ } else {
+ "usize"
+ }
+ }
+ IntKind::B8 => {
+ if signed {
+ "i8"
+ } else {
+ "u8"
+ }
+ }
+ IntKind::B16 => {
+ if signed {
+ "i16"
+ } else {
+ "u16"
+ }
+ }
+ IntKind::B32 => {
+ if signed {
+ "i32"
+ } else {
+ "u32"
+ }
+ }
+ IntKind::B64 => {
+ if signed {
+ "i64"
+ } else {
+ "u64"
+ }
+ }
+ },
+ PrimitiveType::Float => "f32",
+ PrimitiveType::Double => "f64",
+ PrimitiveType::PtrDiffT => "ptrdiff_t",
+ PrimitiveType::VaList => "va_list",
+ }
+ }
+
+ pub fn to_repr_c(&self, config: &Config) -> &'static str {
+ match *self {
+ PrimitiveType::Void => "void",
+ PrimitiveType::Bool => "bool",
+ PrimitiveType::Char => "char",
+ PrimitiveType::SChar => "signed char",
+ PrimitiveType::UChar => "unsigned char",
+ // NOTE: It'd be nice to use a char32_t, but:
+ //
+ // * uchar.h is not present on mac (see #423).
+ //
+ // * char32_t isn't required to be compatible with Rust's char, as
+ // the C++ spec only requires it to be the same size as
+ // uint_least32_t, which is _not_ guaranteed to be 4-bytes.
+ //
+ PrimitiveType::Char32 => "uint32_t",
+ PrimitiveType::Integer {
+ kind,
+ signed,
+ zeroable: _,
+ } => match kind {
+ IntKind::Short => {
+ if signed {
+ "short"
+ } else {
+ "unsigned short"
+ }
+ }
+ IntKind::Int => {
+ if signed {
+ "int"
+ } else {
+ "unsigned int"
+ }
+ }
+ IntKind::Long => {
+ if signed {
+ "long"
+ } else {
+ "unsigned long"
+ }
+ }
+ IntKind::LongLong => {
+ if signed {
+ "long long"
+ } else {
+ "unsigned long long"
+ }
+ }
+ IntKind::SizeT => {
+ if signed {
+ "ssize_t"
+ } else {
+ "size_t"
+ }
+ }
+ IntKind::Size => {
+ if config.usize_is_size_t {
+ if signed {
+ "ptrdiff_t"
+ } else {
+ "size_t"
+ }
+ } else if signed {
+ "intptr_t"
+ } else {
+ "uintptr_t"
+ }
+ }
+ IntKind::B8 => {
+ if signed {
+ "int8_t"
+ } else {
+ "uint8_t"
+ }
+ }
+ IntKind::B16 => {
+ if signed {
+ "int16_t"
+ } else {
+ "uint16_t"
+ }
+ }
+ IntKind::B32 => {
+ if signed {
+ "int32_t"
+ } else {
+ "uint32_t"
+ }
+ }
+ IntKind::B64 => {
+ if signed {
+ "int64_t"
+ } else {
+ "uint64_t"
+ }
+ }
+ },
+ PrimitiveType::Float => "float",
+ PrimitiveType::Double => "double",
+ PrimitiveType::PtrDiffT => "ptrdiff_t",
+ PrimitiveType::VaList => "va_list",
+ }
+ }
+
+ fn can_cmp_order(&self) -> bool {
+ !matches!(*self, PrimitiveType::Bool)
+ }
+
+ fn can_cmp_eq(&self) -> bool {
+ true
+ }
+}
+
+/// Constant expressions.
+///
+/// Used for the `U` part of `[T; U]` and const generics. We support a very
+/// limited vocabulary here: only identifiers and literals.
+#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
+pub enum ConstExpr {
+ Name(String),
+ Value(String),
+}
+
+impl ConstExpr {
+ pub fn as_str(&self) -> &str {
+ match *self {
+ ConstExpr::Name(ref string) | ConstExpr::Value(ref string) => string,
+ }
+ }
+
+ pub fn rename_for_config(&mut self, config: &Config) {
+ if let ConstExpr::Name(ref mut name) = self {
+ config.export.rename(name);
+ }
+ }
+
+ pub fn load(expr: &syn::Expr) -> Result<Self, String> {
+ match *expr {
+ syn::Expr::Lit(syn::ExprLit { ref lit, .. }) => {
+ let val = match *lit {
+ syn::Lit::Bool(syn::LitBool { value, .. }) => value.to_string(),
+ syn::Lit::Int(ref len) => len.base10_digits().to_string(),
+ syn::Lit::Byte(ref byte) => u8::to_string(&byte.value()),
+ syn::Lit::Char(ref ch) => u32::to_string(&ch.value().into()),
+ _ => return Err(format!("can't handle const expression {:?}", lit)),
+ };
+ Ok(ConstExpr::Value(val))
+ }
+ syn::Expr::Path(ref path) => {
+ let generic_path = GenericPath::load(&path.path)?;
+ Ok(ConstExpr::Name(generic_path.export_name().to_owned()))
+ }
+ _ => Err(format!("can't handle const expression {:?}", expr)),
+ }
+ }
+
+ pub fn specialize(&self, mappings: &[(&Path, &GenericArgument)]) -> ConstExpr {
+ match *self {
+ ConstExpr::Name(ref name) => {
+ let path = Path::new(name);
+ for &(param, value) in mappings {
+ if path == *param {
+ match *value {
+ GenericArgument::Type(Type::Path(ref path))
+ if path.is_single_identifier() =>
+ {
+ // This happens when the generic argument is a path.
+ return ConstExpr::Name(path.name().to_string());
+ }
+ GenericArgument::Const(ref expr) => {
+ return expr.clone();
+ }
+ _ => {
+ // unsupported argument type - really should be an error
+ }
+ }
+ }
+ }
+ }
+ ConstExpr::Value(_) => {}
+ }
+ self.clone()
+ }
+}
+
+impl Source for ConstExpr {
+ fn write<F: Write>(&self, _config: &Config, out: &mut SourceWriter<F>) {
+ write!(out, "{}", self.as_str());
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
+pub enum Type {
+ Ptr {
+ ty: Box<Type>,
+ is_const: bool,
+ is_nullable: bool,
+ // FIXME: This is a bit of a hack, this is only to get us to codegen
+ // `T&` / `const T&`, but we should probably pass that down as an option
+ // to code generation or something.
+ is_ref: bool,
+ },
+ Path(GenericPath),
+ Primitive(PrimitiveType),
+ Array(Box<Type>, ConstExpr),
+ FuncPtr {
+ ret: Box<Type>,
+ args: Vec<(Option<String>, Type)>,
+ is_nullable: bool,
+ never_return: bool,
+ },
+}
+
+impl Type {
+ pub fn const_ref_to(ty: &Self) -> Self {
+ Type::Ptr {
+ ty: Box::new(ty.clone()),
+ is_const: true,
+ is_nullable: false,
+ is_ref: true,
+ }
+ }
+
+ pub fn load_from_output(output: &syn::ReturnType) -> Result<(Type, bool), String> {
+ let mut never_return = false;
+ let ty = match output {
+ syn::ReturnType::Default => Type::Primitive(PrimitiveType::Void),
+ syn::ReturnType::Type(_, ref ty) => {
+ if let syn::Type::Never(_) = ty.as_ref() {
+ never_return = true;
+ Type::Primitive(PrimitiveType::Void)
+ } else {
+ Type::load(ty)?.unwrap_or(Type::Primitive(PrimitiveType::Void))
+ }
+ }
+ };
+ Ok((ty, never_return))
+ }
+
+ pub fn load(ty: &syn::Type) -> Result<Option<Type>, String> {
+ let converted = match *ty {
+ syn::Type::Reference(ref reference) => {
+ let converted = Type::load(&reference.elem)?;
+
+ let converted = match converted {
+ Some(converted) => converted,
+ None => Type::Primitive(PrimitiveType::Void),
+ };
+
+ // TODO(emilio): we could make these use is_ref: true.
+ let is_const = reference.mutability.is_none();
+ Type::Ptr {
+ ty: Box::new(converted),
+ is_const,
+ is_nullable: false,
+ is_ref: false,
+ }
+ }
+ syn::Type::Ptr(ref pointer) => {
+ let converted = Type::load(&pointer.elem)?;
+
+ let converted = match converted {
+ Some(converted) => converted,
+ None => Type::Primitive(PrimitiveType::Void),
+ };
+
+ let is_const = pointer.mutability.is_none();
+ Type::Ptr {
+ ty: Box::new(converted),
+ is_const,
+ is_nullable: true,
+ is_ref: false,
+ }
+ }
+ syn::Type::Path(ref path) => {
+ let generic_path = GenericPath::load(&path.path)?;
+
+ if generic_path.name() == "PhantomData" || generic_path.name() == "PhantomPinned" {
+ return Ok(None);
+ }
+
+ if let Some(prim) = PrimitiveType::maybe(generic_path.name()) {
+ if !generic_path.generics().is_empty() {
+ return Err("Primitive has generics.".to_owned());
+ }
+ Type::Primitive(prim)
+ } else {
+ Type::Path(generic_path)
+ }
+ }
+ syn::Type::Array(syn::TypeArray {
+ ref elem, ref len, ..
+ }) => {
+ let converted = Type::load(elem)?;
+
+ let converted = match converted {
+ Some(converted) => converted,
+ None => return Err("Cannot have an array of zero sized types.".to_owned()),
+ };
+
+ let len = ConstExpr::load(len)?;
+ Type::Array(Box::new(converted), len)
+ }
+ syn::Type::BareFn(ref function) => {
+ let mut wildcard_counter = 0;
+ let args = function.inputs.iter().try_skip_map(|x| {
+ Type::load(&x.ty).map(|opt_ty| {
+ opt_ty.map(|ty| {
+ (
+ x.name.as_ref().map(|(ref ident, _)| {
+ if ident == "_" {
+ wildcard_counter += 1;
+ if wildcard_counter == 1 {
+ "_".to_owned()
+ } else {
+ format!("_{}", wildcard_counter - 1)
+ }
+ } else {
+ ident.unraw().to_string()
+ }
+ }),
+ ty,
+ )
+ })
+ })
+ })?;
+ let (ret, never_return) = Type::load_from_output(&function.output)?;
+ Type::FuncPtr {
+ ret: Box::new(ret),
+ args,
+ is_nullable: false,
+ never_return,
+ }
+ }
+ syn::Type::Tuple(ref tuple) => {
+ if tuple.elems.is_empty() {
+ return Ok(None);
+ }
+ return Err("Tuples are not supported types.".to_owned());
+ }
+ syn::Type::Verbatim(ref tokens) if tokens.to_string() == "..." => {
+ Type::Primitive(PrimitiveType::VaList)
+ }
+ _ => return Err(format!("Unsupported type: {:?}", ty)),
+ };
+
+ Ok(Some(converted))
+ }
+
+ pub fn is_ptr(&self) -> bool {
+ matches!(*self, Type::Ptr { .. } | Type::FuncPtr { .. })
+ }
+
+ pub fn is_primitive_or_ptr_primitive(&self) -> bool {
+ match *self {
+ Type::Primitive(..) => true,
+ Type::Ptr { ref ty, .. } => matches!(ty.as_ref(), Type::Primitive(..)),
+ _ => false,
+ }
+ }
+
+ pub fn make_zeroable(&self) -> Option<Self> {
+ let (kind, signed) = match *self {
+ Type::Primitive(PrimitiveType::Integer {
+ zeroable: false,
+ kind,
+ signed,
+ }) => (kind, signed),
+ _ => return None,
+ };
+
+ Some(Type::Primitive(PrimitiveType::Integer {
+ kind,
+ signed,
+ zeroable: true,
+ }))
+ }
+
+ pub fn make_nullable(&self) -> Option<Self> {
+ match *self {
+ Type::Ptr {
+ ref ty,
+ is_const,
+ is_ref,
+ is_nullable: false,
+ } => Some(Type::Ptr {
+ ty: ty.clone(),
+ is_const,
+ is_ref,
+ is_nullable: true,
+ }),
+ Type::FuncPtr {
+ ref ret,
+ ref args,
+ is_nullable: false,
+ never_return,
+ } => Some(Type::FuncPtr {
+ ret: ret.clone(),
+ args: args.clone(),
+ is_nullable: true,
+ never_return,
+ }),
+ _ => None,
+ }
+ }
+
+ fn nonzero_to_primitive(&self) -> Option<Self> {
+ let path = match *self {
+ Type::Path(ref p) => p,
+ _ => return None,
+ };
+
+ if !path.generics().is_empty() {
+ return None;
+ }
+
+ let name = path.name();
+ if !name.starts_with("NonZero") {
+ return None;
+ }
+
+ let (kind, signed) = match path.name() {
+ "NonZeroU8" => (IntKind::B8, false),
+ "NonZeroU16" => (IntKind::B16, false),
+ "NonZeroU32" => (IntKind::B32, false),
+ "NonZeroU64" => (IntKind::B64, false),
+ "NonZeroUSize" => (IntKind::Size, false),
+ "NonZeroI8" => (IntKind::B8, true),
+ "NonZeroI16" => (IntKind::B16, true),
+ "NonZeroI32" => (IntKind::B32, true),
+ "NonZeroI64" => (IntKind::B64, true),
+ "NonZeroISize" => (IntKind::Size, true),
+ _ => return None,
+ };
+
+ Some(Type::Primitive(PrimitiveType::Integer {
+ zeroable: false,
+ signed,
+ kind,
+ }))
+ }
+
+ fn simplified_type(&self, config: &Config) -> Option<Self> {
+ let path = match *self {
+ Type::Path(ref p) => p,
+ _ => return None,
+ };
+
+ if path.generics().is_empty() {
+ return self.nonzero_to_primitive();
+ }
+
+ if path.generics().len() != 1 {
+ return None;
+ }
+
+ let unsimplified_generic = match path.generics()[0] {
+ GenericArgument::Type(ref ty) => ty,
+ GenericArgument::Const(_) => return None,
+ };
+
+ let generic = match unsimplified_generic.simplified_type(config) {
+ Some(generic) => Cow::Owned(generic),
+ None => Cow::Borrowed(unsimplified_generic),
+ };
+ match path.name() {
+ "Option" => {
+ if let Some(nullable) = generic.make_nullable() {
+ return Some(nullable);
+ }
+ if let Some(zeroable) = generic.make_zeroable() {
+ return Some(zeroable);
+ }
+ None
+ }
+ "NonNull" => Some(Type::Ptr {
+ ty: Box::new(generic.into_owned()),
+ is_const: false,
+ is_nullable: false,
+ is_ref: false,
+ }),
+ "Box" if config.language != Language::Cxx => Some(Type::Ptr {
+ ty: Box::new(generic.into_owned()),
+ is_const: false,
+ is_nullable: false,
+ is_ref: false,
+ }),
+ "Cell" => Some(generic.into_owned()),
+ "ManuallyDrop" | "MaybeUninit" | "Pin" if config.language != Language::Cxx => {
+ Some(generic.into_owned())
+ }
+ _ => None,
+ }
+ }
+
+ pub fn simplify_standard_types(&mut self, config: &Config) {
+ self.visit_types(|ty| ty.simplify_standard_types(config));
+ if let Some(ty) = self.simplified_type(config) {
+ *self = ty;
+ }
+ }
+
+ pub fn replace_self_with(&mut self, self_ty: &Path) {
+ if let Type::Path(ref mut generic_path) = *self {
+ generic_path.replace_self_with(self_ty);
+ }
+ self.visit_types(|ty| ty.replace_self_with(self_ty))
+ }
+
+ fn visit_types(&mut self, mut visitor: impl FnMut(&mut Type)) {
+ match *self {
+ Type::Array(ref mut ty, ..) | Type::Ptr { ref mut ty, .. } => visitor(ty),
+ Type::Path(ref mut path) => {
+ for generic in path.generics_mut() {
+ match *generic {
+ GenericArgument::Type(ref mut ty) => visitor(ty),
+ GenericArgument::Const(_) => {}
+ }
+ }
+ }
+ Type::Primitive(..) => {}
+ Type::FuncPtr {
+ ref mut ret,
+ ref mut args,
+ ..
+ } => {
+ visitor(ret);
+ for arg in args {
+ visitor(&mut arg.1)
+ }
+ }
+ }
+ }
+
+ pub fn get_root_path(&self) -> Option<Path> {
+ let mut current = self;
+ loop {
+ match *current {
+ Type::Ptr { ref ty, .. } => current = ty,
+ Type::Path(ref generic) => {
+ return Some(generic.path().clone());
+ }
+ Type::Primitive(..) => {
+ return None;
+ }
+ Type::Array(..) => {
+ return None;
+ }
+ Type::FuncPtr { .. } => {
+ return None;
+ }
+ };
+ }
+ }
+
+ pub fn specialize(&self, mappings: &[(&Path, &GenericArgument)]) -> Type {
+ match *self {
+ Type::Ptr {
+ ref ty,
+ is_const,
+ is_nullable,
+ is_ref,
+ } => Type::Ptr {
+ ty: Box::new(ty.specialize(mappings)),
+ is_const,
+ is_nullable,
+ is_ref,
+ },
+ Type::Path(ref generic_path) => {
+ for &(param, value) in mappings {
+ if generic_path.path() == param {
+ if let GenericArgument::Type(ref ty) = *value {
+ return ty.clone();
+ }
+ }
+ }
+
+ let specialized = GenericPath::new(
+ generic_path.path().clone(),
+ generic_path
+ .generics()
+ .iter()
+ .map(|x| x.specialize(mappings))
+ .collect(),
+ );
+ Type::Path(specialized)
+ }
+ Type::Primitive(ref primitive) => Type::Primitive(primitive.clone()),
+ Type::Array(ref ty, ref constant) => Type::Array(
+ Box::new(ty.specialize(mappings)),
+ constant.specialize(mappings),
+ ),
+ Type::FuncPtr {
+ ref ret,
+ ref args,
+ is_nullable,
+ never_return,
+ } => Type::FuncPtr {
+ ret: Box::new(ret.specialize(mappings)),
+ args: args
+ .iter()
+ .cloned()
+ .map(|(name, ty)| (name, ty.specialize(mappings)))
+ .collect(),
+ is_nullable,
+ never_return,
+ },
+ }
+ }
+
+ pub fn add_dependencies_ignoring_generics(
+ &self,
+ generic_params: &GenericParams,
+ library: &Library,
+ out: &mut Dependencies,
+ ) {
+ match *self {
+ Type::Ptr { ref ty, .. } => {
+ ty.add_dependencies_ignoring_generics(generic_params, library, out);
+ }
+ Type::Path(ref generic) => {
+ for generic_value in generic.generics() {
+ if let GenericArgument::Type(ref ty) = *generic_value {
+ ty.add_dependencies_ignoring_generics(generic_params, library, out);
+ }
+ }
+ let path = generic.path();
+ if !generic_params.iter().any(|param| param.name() == path) {
+ if let Some(items) = library.get_items(path) {
+ if !out.items.contains(path) {
+ out.items.insert(path.clone());
+
+ for item in &items {
+ item.deref().add_dependencies(library, out);
+ }
+ for item in items {
+ out.order.push(item);
+ }
+ }
+ } else {
+ warn!(
+ "Can't find {}. This usually means that this type was incompatible or \
+ not found.",
+ path
+ );
+ }
+ }
+ }
+ Type::Primitive(_) => {}
+ Type::Array(ref ty, _) => {
+ ty.add_dependencies_ignoring_generics(generic_params, library, out);
+ }
+ Type::FuncPtr {
+ ref ret, ref args, ..
+ } => {
+ ret.add_dependencies_ignoring_generics(generic_params, library, out);
+ for (_, ref arg) in args {
+ arg.add_dependencies_ignoring_generics(generic_params, library, out);
+ }
+ }
+ }
+ }
+
+ pub fn add_dependencies(&self, library: &Library, out: &mut Dependencies) {
+ self.add_dependencies_ignoring_generics(&GenericParams::default(), library, out)
+ }
+
+ pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) {
+ match *self {
+ Type::Ptr { ref ty, .. } => {
+ ty.add_monomorphs(library, out);
+ }
+ Type::Path(ref generic) => {
+ if generic.generics().is_empty() || out.contains(generic) {
+ return;
+ }
+ let path = generic.path();
+ if let Some(items) = library.get_items(path) {
+ for item in items {
+ item.deref()
+ .instantiate_monomorph(generic.generics(), library, out);
+ }
+ }
+ }
+ Type::Primitive(_) => {}
+ Type::Array(ref ty, _) => {
+ ty.add_monomorphs(library, out);
+ }
+ Type::FuncPtr {
+ ref ret, ref args, ..
+ } => {
+ ret.add_monomorphs(library, out);
+ for (_, ref arg) in args {
+ arg.add_monomorphs(library, out);
+ }
+ }
+ }
+ }
+
+ pub fn rename_for_config(&mut self, config: &Config, generic_params: &GenericParams) {
+ match *self {
+ Type::Ptr { ref mut ty, .. } => {
+ ty.rename_for_config(config, generic_params);
+ }
+ Type::Path(ref mut ty) => {
+ ty.rename_for_config(config, generic_params);
+ }
+ Type::Primitive(_) => {}
+ Type::Array(ref mut ty, ref mut len) => {
+ ty.rename_for_config(config, generic_params);
+ len.rename_for_config(config);
+ }
+ Type::FuncPtr {
+ ref mut ret,
+ ref mut args,
+ ..
+ } => {
+ ret.rename_for_config(config, generic_params);
+ for (_, arg) in args {
+ arg.rename_for_config(config, generic_params);
+ }
+ }
+ }
+ }
+
+ pub fn resolve_declaration_types(&mut self, resolver: &DeclarationTypeResolver) {
+ match *self {
+ Type::Ptr { ref mut ty, .. } => {
+ ty.resolve_declaration_types(resolver);
+ }
+ Type::Path(ref mut generic_path) => {
+ generic_path.resolve_declaration_types(resolver);
+ }
+ Type::Primitive(_) => {}
+ Type::Array(ref mut ty, _) => {
+ ty.resolve_declaration_types(resolver);
+ }
+ Type::FuncPtr {
+ ref mut ret,
+ ref mut args,
+ ..
+ } => {
+ ret.resolve_declaration_types(resolver);
+ for (_, ref mut arg) in args {
+ arg.resolve_declaration_types(resolver);
+ }
+ }
+ }
+ }
+
+ pub fn mangle_paths(&mut self, monomorphs: &Monomorphs) {
+ match *self {
+ Type::Ptr { ref mut ty, .. } => {
+ ty.mangle_paths(monomorphs);
+ }
+ Type::Path(ref mut generic_path) => {
+ if generic_path.generics().is_empty() {
+ return;
+ }
+
+ if let Some(mangled_path) = monomorphs.mangle_path(generic_path) {
+ *generic_path = GenericPath::new(mangled_path.clone(), vec![]);
+ } else {
+ warn!(
+ "Cannot find a mangling for generic path {:?}. This usually means that a \
+ type referenced by this generic was incompatible or not found.",
+ generic_path
+ );
+ }
+ }
+ Type::Primitive(_) => {}
+ Type::Array(ref mut ty, _) => {
+ ty.mangle_paths(monomorphs);
+ }
+ Type::FuncPtr {
+ ref mut ret,
+ ref mut args,
+ ..
+ } => {
+ ret.mangle_paths(monomorphs);
+ for (_, ref mut arg) in args {
+ arg.mangle_paths(monomorphs);
+ }
+ }
+ }
+ }
+
+ pub fn can_cmp_order(&self) -> bool {
+ match *self {
+ // FIXME: Shouldn't this look at ty.can_cmp_order() as well?
+ Type::Ptr { is_ref, .. } => !is_ref,
+ Type::Path(..) => true,
+ Type::Primitive(ref p) => p.can_cmp_order(),
+ Type::Array(..) => false,
+ Type::FuncPtr { .. } => false,
+ }
+ }
+
+ pub fn can_cmp_eq(&self) -> bool {
+ match *self {
+ Type::Ptr { ref ty, is_ref, .. } => !is_ref || ty.can_cmp_eq(),
+ Type::Path(..) => true,
+ Type::Primitive(ref p) => p.can_cmp_eq(),
+ Type::Array(..) => false,
+ Type::FuncPtr { .. } => true,
+ }
+ }
+}
+
+impl Source for String {
+ fn write<F: Write>(&self, _config: &Config, out: &mut SourceWriter<F>) {
+ write!(out, "{}", self);
+ }
+}
+
+impl Source for Type {
+ fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
+ cdecl::write_type(out, self, config);
+ }
+}