Repository: mozilla/cbindgen (language: rust)

Issue:
Support std::num::NonZero*
It would be nice to be able to use NonZeroU64 and friends in cbindgen'd APIs
Option<*const T> is incorrectly converted to const T*
The logic in this [function](https://github.com/eqrion/cbindgen/blob/v0.6.4/src/bindgen/ir/ty.rs#L335) is bogus.

This is a safety issue, as dropping the Option is only valid if the pointer is non-nullable.

The problem here is coming from the fact that `cbindgen` is dropping the knowledge of whether the pointer is nullable or not before this function.


Discussion / hints:
@Manishearth Those are `repr(transparent)`, so it should be trivial to do in `simplify_standard_types`
That's where we handle `NonNull` as well.


Fix patch:
diff --git a/src/bindgen/cdecl.rs b/src/bindgen/cdecl.rs
index b915d9d21..8075f97e5 100644
--- a/src/bindgen/cdecl.rs
+++ b/src/bindgen/cdecl.rs
@@ -158,7 +158,11 @@ impl CDecl {
                 self.declarators.push(CDeclarator::Array(len));
                 self.build_type(t, is_const, config);
             }
-            Type::FuncPtr(ref ret, ref args) => {
+            Type::FuncPtr {
+                ref ret,
+                ref args,
+                is_nullable: _,
+            } => {
                 let args = args
                     .iter()
                     .map(|(ref name, ref ty)| (name.clone(), CDecl::from_type(ty, config)))
diff --git a/src/bindgen/ir/repr.rs b/src/bindgen/ir/repr.rs
index fcd8cf272..90b8ac96b 100644
--- a/src/bindgen/ir/repr.rs
+++ b/src/bindgen/ir/repr.rs
@@ -2,7 +2,7 @@
  * 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 crate::bindgen::ir::ty::PrimitiveType;
+use crate::bindgen::ir::ty::{IntKind, PrimitiveType};
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
 pub enum ReprStyle {
@@ -18,32 +18,17 @@ impl Default for ReprStyle {
 }
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub enum ReprType {
-    U8,
-    U16,
-    U32,
-    U64,
-    USize,
-    I8,
-    I16,
-    I32,
-    I64,
-    ISize,
+pub struct ReprType {
+    kind: IntKind,
+    signed: bool,
 }
 
 impl ReprType {
     pub(crate) fn to_primitive(self) -> PrimitiveType {
-        match self {
-            ReprType::U8 => PrimitiveType::UInt8,
-            ReprType::U16 => PrimitiveType::UInt16,
-            ReprType::U32 => PrimitiveType::UInt32,
-            ReprType::U64 => PrimitiveType::UInt64,
-            ReprType::USize => PrimitiveType::USize,
-            ReprType::I8 => PrimitiveType::Int8,
-            ReprType::I16 => PrimitiveType::Int16,
-            ReprType::I32 => PrimitiveType::Int32,
-            ReprType::I64 => PrimitiveType::Int64,
-            ReprType::ISize => PrimitiveType::ISize,
+        PrimitiveType::Integer {
+            kind: self.kind,
+            signed: self.signed,
+            zeroable: true,
         }
     }
 }
@@ -103,17 +88,17 @@ impl Repr {
 
         let mut repr = Repr::default();
         for id in ids {
-            let new_ty = match (id.0.as_ref(), id.1) {
-                ("u8", None) => ReprType::U8,
-                ("u16", None) => ReprType::U16,
-                ("u32", None) => ReprType::U32,
-                ("u64", None) => ReprType::U64,
-                ("usize", None) => ReprType::USize,
-                ("i8", None) => ReprType::I8,
-                ("i16", None) => ReprType::I16,
-                ("i32", None) => ReprType::I32,
-                ("i64", None) => ReprType::I64,
-                ("isize", None) => ReprType::ISize,
+            let (int_kind, signed) = match (id.0.as_ref(), id.1) {
+                ("u8", None) => (IntKind::B8, false),
+                ("u16", None) => (IntKind::B16, false),
+                ("u32", None) => (IntKind::B32, false),
+                ("u64", None) => (IntKind::B64, false),
+                ("usize", None) => (IntKind::Size, false),
+                ("i8", None) => (IntKind::B8, true),
+                ("i16", None) => (IntKind::B16, true),
+                ("i32", None) => (IntKind::B32, true),
+                ("i64", None) => (IntKind::B64, true),
+                ("isize", None) => (IntKind::Size, true),
                 ("C", None) => {
                     repr.style = ReprStyle::C;
                     continue;
@@ -182,13 +167,17 @@ impl Repr {
                     }
                 },
             };
+            let ty = ReprType {
+                kind: int_kind,
+                signed,
+            };
             if let Some(old_ty) = repr.ty {
                 return Err(format!(
                     "Conflicting #[repr(...)] type hints {:?} and {:?}.",
-                    old_ty, new_ty
+                    old_ty, ty
                 ));
             }
-            repr.ty = Some(new_ty);
+            repr.ty = Some(ty);
         }
         Ok(repr)
     }
diff --git a/src/bindgen/ir/ty.rs b/src/bindgen/ir/ty.rs
index e50aa9536..5574d2fdf 100644
--- a/src/bindgen/ir/ty.rs
+++ b/src/bindgen/ir/ty.rs
@@ -2,6 +2,7 @@
  * 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 crate::bindgen::cdecl;
@@ -22,101 +23,169 @@ pub enum PrimitiveType {
     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,
-    UShort,
-    UInt,
-    ULong,
-    ULongLong,
-    USize,
-    UInt8,
-    UInt16,
-    UInt32,
-    UInt64,
-    ISize,
-    Int8,
-    Int16,
-    Int32,
-    Int64,
-    Float,
-    Double,
     SizeT,
-    SSizeT,
-    PtrDiffT,
-    VaList,
+    Size,
+    B8,
+    B16,
+    B32,
+    B64,
 }
 
 impl PrimitiveType {
     pub fn maybe(path: &str) -> Option<PrimitiveType> {
-        match path {
-            "c_void" => Some(PrimitiveType::Void),
-            "c_char" => Some(PrimitiveType::Char),
-            "c_schar" => Some(PrimitiveType::SChar),
-            "c_uchar" => Some(PrimitiveType::UChar),
-            "c_float" => Some(PrimitiveType::Float),
-            "c_double" => Some(PrimitiveType::Double),
-            "c_short" => Some(PrimitiveType::Short),
-            "c_int" => Some(PrimitiveType::Int),
-            "c_long" => Some(PrimitiveType::Long),
-            "c_longlong" => Some(PrimitiveType::LongLong),
-            "c_ushort" => Some(PrimitiveType::UShort),
-            "c_uint" => Some(PrimitiveType::UInt),
-            "c_ulong" => Some(PrimitiveType::ULong),
-            "c_ulonglong" => Some(PrimitiveType::ULongLong),
-            "bool" => Some(PrimitiveType::Bool),
-            "char" => Some(PrimitiveType::Char32),
-            "usize" | "uintptr_t" => Some(PrimitiveType::USize),
-            "u8" | "uint8_t" => Some(PrimitiveType::UInt8),
-            "u16" | "uint16_t" => Some(PrimitiveType::UInt16),
-            "u32" | "uint32_t" => Some(PrimitiveType::UInt32),
-            "u64" | "uint64_t" => Some(PrimitiveType::UInt64),
-            "isize" | "intptr_t" => Some(PrimitiveType::ISize),
-            "i8" | "int8_t" => Some(PrimitiveType::Int8),
-            "i16" | "int16_t" => Some(PrimitiveType::Int16),
-            "i32" | "int32_t" => Some(PrimitiveType::Int32),
-            "i64" | "int64_t" => Some(PrimitiveType::Int64),
-            "f32" => Some(PrimitiveType::Float),
-            "f64" => Some(PrimitiveType::Double),
-            "size_t" => Some(PrimitiveType::SizeT),
-            "ssize_t" => Some(PrimitiveType::SSizeT),
-            "ptrdiff_t" => Some(PrimitiveType::PtrDiffT),
-            "VaList" => Some(PrimitiveType::VaList),
-            _ => None,
-        }
+        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),
+
+                    "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::Short => "c_short",
-            PrimitiveType::Int => "c_int",
-            PrimitiveType::Long => "c_long",
-            PrimitiveType::LongLong => "c_longlong",
-            PrimitiveType::UShort => "c_ushort",
-            PrimitiveType::UInt => "c_uint",
-            PrimitiveType::ULong => "c_ulong",
-            PrimitiveType::ULongLong => "c_ulonglong",
-            PrimitiveType::Bool => "bool",
-            PrimitiveType::USize => "usize",
-            PrimitiveType::UInt8 => "u8",
-            PrimitiveType::UInt16 => "u16",
-            PrimitiveType::UInt32 => "u32",
-            PrimitiveType::UInt64 => "u64",
-            PrimitiveType::ISize => "isize",
-            PrimitiveType::Int8 => "i8",
-            PrimitiveType::Int16 => "i16",
-            PrimitiveType::Int32 => "i32",
-            PrimitiveType::Int64 => "i64",
+            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::SizeT => "size_t",
-            PrimitiveType::SSizeT => "ssize_t",
             PrimitiveType::PtrDiffT => "ptrdiff_t",
             PrimitiveType::VaList => "va_list",
         }
@@ -138,30 +207,90 @@ impl PrimitiveType {
             //    uint_least32_t, which is _not_ guaranteed to be 4-bytes.
             //
             PrimitiveType::Char32 => "uint32_t",
-            PrimitiveType::Short => "short",
-            PrimitiveType::Int => "int",
-            PrimitiveType::Long => "long",
-            PrimitiveType::LongLong => "long long",
-            PrimitiveType::UShort => "unsigned short",
-            PrimitiveType::UInt => "unsigned int",
-            PrimitiveType::ULong => "unsigned long",
-            PrimitiveType::ULongLong => "unsigned long long",
-            PrimitiveType::USize if config.usize_is_size_t => "size_t",
-            PrimitiveType::USize => "uintptr_t",
-            PrimitiveType::UInt8 => "uint8_t",
-            PrimitiveType::UInt16 => "uint16_t",
-            PrimitiveType::UInt32 => "uint32_t",
-            PrimitiveType::UInt64 => "uint64_t",
-            PrimitiveType::ISize if config.usize_is_size_t => "ptrdiff_t",
-            PrimitiveType::ISize => "intptr_t",
-            PrimitiveType::Int8 => "int8_t",
-            PrimitiveType::Int16 => "int16_t",
-            PrimitiveType::Int32 => "int32_t",
-            PrimitiveType::Int64 => "int64_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::SizeT => "size_t",
-            PrimitiveType::SSizeT => "ssize_t",
             PrimitiveType::PtrDiffT => "ptrdiff_t",
             PrimitiveType::VaList => "va_list",
         }
@@ -214,7 +343,11 @@ pub enum Type {
     Path(GenericPath),
     Primitive(PrimitiveType),
     Array(Box<Type>, ArrayLength),
-    FuncPtr(Box<Type>, Vec<(Option<String>, Type)>),
+    FuncPtr {
+        ret: Box<Type>,
+        args: Vec<(Option<String>, Type)>,
+        is_nullable: bool,
+    },
 }
 
 impl Type {
@@ -355,7 +488,11 @@ impl Type {
                     }
                 };
 
-                Type::FuncPtr(Box::new(ret), args)
+                Type::FuncPtr {
+                    ret: Box::new(ret),
+                    args,
+                    is_nullable: false,
+                }
             }
             syn::Type::Tuple(ref tuple) => {
                 if tuple.elems.is_empty() {
@@ -380,62 +517,130 @@ impl Type {
         }
     }
 
-    pub fn is_repr_ptr(&self) -> bool {
-        match *self {
-            Type::Ptr { .. } => true,
-            Type::FuncPtr(..) => true,
-            _ => 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.clone() {
+        match *self {
             Type::Ptr {
-                ty,
+                ref ty,
                 is_const,
                 is_ref,
-                ..
+                is_nullable: false,
             } => Some(Type::Ptr {
-                ty,
+                ty: ty.clone(),
                 is_const,
                 is_ref,
                 is_nullable: true,
             }),
-            Type::FuncPtr(x, y) => Some(Type::FuncPtr(x, y)),
+            Type::FuncPtr {
+                ref ret,
+                ref args,
+                is_nullable: false,
+            } => Some(Type::FuncPtr {
+                ret: ret.clone(),
+                args: args.clone(),
+                is_nullable: true,
+            }),
             _ => 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 mut generic = path.generics()[0].clone();
-        generic.simplify_standard_types(config);
-
+        let unsimplified_generic = &path.generics()[0];
+        let generic = match unsimplified_generic.simplified_type(config) {
+            Some(generic) => Cow::Owned(generic),
+            None => Cow::Borrowed(unsimplified_generic),
+        };
         match path.name() {
-            // FIXME(#223): This is not quite correct.
-            "Option" if generic.is_repr_ptr() => generic.make_nullable(),
+            "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),
+                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),
+                ty: Box::new(generic.into_owned()),
                 is_const: false,
                 is_nullable: false,
                 is_ref: false,
             }),
-            "Cell" => Some(generic),
-            "ManuallyDrop" | "MaybeUninit" if config.language != Language::Cxx => Some(generic),
+            "Cell" => Some(generic.into_owned()),
+            "ManuallyDrop" | "MaybeUninit" if config.language != Language::Cxx => {
+                Some(generic.into_owned())
+            }
             _ => None,
         }
     }
@@ -455,7 +660,11 @@ impl Type {
                 generic_path.replace_self_with(self_ty);
             }
             Type::Primitive(..) => {}
-            Type::FuncPtr(ref mut ret, ref mut args) => {
+            Type::FuncPtr {
+                ref mut ret,
+                ref mut args,
+                ..
+            } => {
                 ret.replace_self_with(self_ty);
                 for arg in args {
                     arg.1.replace_self_with(self_ty);
@@ -478,7 +687,7 @@ impl Type {
                 Type::Array(..) => {
                     return None;
                 }
-                Type::FuncPtr(..) => {
+                Type::FuncPtr { .. } => {
                     return None;
                 }
             };
@@ -519,13 +728,19 @@ impl Type {
             Type::Array(ref ty, ref constant) => {
                 Type::Array(Box::new(ty.specialize(mappings)), constant.clone())
             }
-            Type::FuncPtr(ref ret, ref args) => Type::FuncPtr(
-                Box::new(ret.specialize(mappings)),
-                args.iter()
+            Type::FuncPtr {
+                ref ret,
+                ref args,
+                is_nullable,
+            } => Type::FuncPtr {
+                ret: Box::new(ret.specialize(mappings)),
+                args: args
+                    .iter()
                     .cloned()
                     .map(|(name, ty)| (name, ty.specialize(mappings)))
                     .collect(),
-            ),
+                is_nullable,
+            },
         }
     }
 
@@ -569,7 +784,9 @@ impl Type {
             Type::Array(ref ty, _) => {
                 ty.add_dependencies_ignoring_generics(generic_params, library, out);
             }
-            Type::FuncPtr(ref ret, ref args) => {
+            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);
@@ -603,7 +820,9 @@ impl Type {
             Type::Array(ref ty, _) => {
                 ty.add_monomorphs(library, out);
             }
-            Type::FuncPtr(ref ret, ref args) => {
+            Type::FuncPtr {
+                ref ret, ref args, ..
+            } => {
                 ret.add_monomorphs(library, out);
                 for (_, ref arg) in args {
                     arg.add_monomorphs(library, out);
@@ -625,7 +844,11 @@ impl Type {
                 ty.rename_for_config(config, generic_params);
                 len.rename_for_config(config);
             }
-            Type::FuncPtr(ref mut ret, ref mut args) => {
+            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);
@@ -646,7 +869,11 @@ impl Type {
             Type::Array(ref mut ty, _) => {
                 ty.resolve_declaration_types(resolver);
             }
-            Type::FuncPtr(ref mut ret, ref mut args) => {
+            Type::FuncPtr {
+                ref mut ret,
+                ref mut args,
+                ..
+            } => {
                 ret.resolve_declaration_types(resolver);
                 for (_, ref mut arg) in args {
                     arg.resolve_declaration_types(resolver);
@@ -679,7 +906,11 @@ impl Type {
             Type::Array(ref mut ty, _) => {
                 ty.mangle_paths(monomorphs);
             }
-            Type::FuncPtr(ref mut ret, ref mut args) => {
+            Type::FuncPtr {
+                ref mut ret,
+                ref mut args,
+                ..
+            } => {
                 ret.mangle_paths(monomorphs);
                 for (_, ref mut arg) in args {
                     arg.mangle_paths(monomorphs);
@@ -690,11 +921,12 @@ impl Type {
 
     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,
+            Type::FuncPtr { .. } => false,
         }
     }
 
@@ -704,7 +936,7 @@ impl Type {
             Type::Path(..) => true,
             Type::Primitive(ref p) => p.can_cmp_eq(),
             Type::Array(..) => false,
-            Type::FuncPtr(..) => true,
+            Type::FuncPtr { .. } => true,
         }
     }
 }
diff --git a/src/bindgen/mangle.rs b/src/bindgen/mangle.rs
index 01426714e..909b4659c 100644
--- a/src/bindgen/mangle.rs
+++ b/src/bindgen/mangle.rs
@@ -20,6 +20,9 @@ enum Separator {
     ClosingAngleBracket,
     BeginMutPtr,
     BeginConstPtr,
+    BeginFn,
+    BetweenFnArg,
+    EndFn,
 }
 
 struct Mangler<'a> {
@@ -93,7 +96,21 @@ impl<'a> Mangler<'a> {
                 });
                 self.append_mangled_type(&**ty, last);
             }
-            Type::Array(..) | Type::FuncPtr(..) => {
+            Type::FuncPtr {
+                ref ret, ref args, ..
+            } => {
+                self.push(Separator::BeginFn);
+                self.append_mangled_type(&**ret, args.is_empty());
+                for (i, arg) in args.iter().enumerate() {
+                    self.push(Separator::BetweenFnArg);
+                    let last = last && i == args.len() - 1;
+                    self.append_mangled_type(&arg.1, last);
+                }
+                if !self.last {
+                    self.push(Separator::EndFn);
+                }
+            }
+            Type::Array(..) => {
                 unimplemented!(
                     "Unable to mangle generic parameter {:?} for '{}'",
                     ty,


Test patch:
diff --git a/tests/expectations/nonzero.both.c b/tests/expectations/nonzero.both.c
new file mode 100644
index 000000000..2aa8212f9
--- /dev/null
+++ b/tests/expectations/nonzero.both.c
@@ -0,0 +1,44 @@
+#if 0
+''' '
+#endif
+
+#ifdef __cplusplus
+struct NonZeroI64;
+#endif
+
+#if 0
+' '''
+#endif
+
+
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+typedef struct Option_Option_NonZeroI64 Option_Option_NonZeroI64;
+
+typedef struct NonZeroTest {
+  uint8_t a;
+  uint16_t b;
+  uint32_t c;
+  uint64_t d;
+  int8_t e;
+  int16_t f;
+  int32_t g;
+  int64_t h;
+  int64_t i;
+  const struct Option_Option_NonZeroI64 *j;
+} NonZeroTest;
+
+void root(struct NonZeroTest test,
+          uint8_t a,
+          uint16_t b,
+          uint32_t c,
+          uint64_t d,
+          int8_t e,
+          int16_t f,
+          int32_t g,
+          int64_t h,
+          int64_t i,
+          const struct Option_Option_NonZeroI64 *j);
diff --git a/tests/expectations/nonzero.both.compat.c b/tests/expectations/nonzero.both.compat.c
new file mode 100644
index 000000000..6708cd7e0
--- /dev/null
+++ b/tests/expectations/nonzero.both.compat.c
@@ -0,0 +1,52 @@
+#if 0
+''' '
+#endif
+
+#ifdef __cplusplus
+struct NonZeroI64;
+#endif
+
+#if 0
+' '''
+#endif
+
+
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+typedef struct Option_Option_NonZeroI64 Option_Option_NonZeroI64;
+
+typedef struct NonZeroTest {
+  uint8_t a;
+  uint16_t b;
+  uint32_t c;
+  uint64_t d;
+  int8_t e;
+  int16_t f;
+  int32_t g;
+  int64_t h;
+  int64_t i;
+  const struct Option_Option_NonZeroI64 *j;
+} NonZeroTest;
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+void root(struct NonZeroTest test,
+          uint8_t a,
+          uint16_t b,
+          uint32_t c,
+          uint64_t d,
+          int8_t e,
+          int16_t f,
+          int32_t g,
+          int64_t h,
+          int64_t i,
+          const struct Option_Option_NonZeroI64 *j);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif // __cplusplus
diff --git a/tests/expectations/nonzero.c b/tests/expectations/nonzero.c
new file mode 100644
index 000000000..124b8beac
--- /dev/null
+++ b/tests/expectations/nonzero.c
@@ -0,0 +1,44 @@
+#if 0
+''' '
+#endif
+
+#ifdef __cplusplus
+struct NonZeroI64;
+#endif
+
+#if 0
+' '''
+#endif
+
+
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+typedef struct Option_Option_NonZeroI64 Option_Option_NonZeroI64;
+
+typedef struct {
+  uint8_t a;
+  uint16_t b;
+  uint32_t c;
+  uint64_t d;
+  int8_t e;
+  int16_t f;
+  int32_t g;
+  int64_t h;
+  int64_t i;
+  const Option_Option_NonZeroI64 *j;
+} NonZeroTest;
+
+void root(NonZeroTest test,
+          uint8_t a,
+          uint16_t b,
+          uint32_t c,
+          uint64_t d,
+          int8_t e,
+          int16_t f,
+          int32_t g,
+          int64_t h,
+          int64_t i,
+          const Option_Option_NonZeroI64 *j);
diff --git a/tests/expectations/nonzero.compat.c b/tests/expectations/nonzero.compat.c
new file mode 100644
index 000000000..c4f2587bf
--- /dev/null
+++ b/tests/expectations/nonzero.compat.c
@@ -0,0 +1,52 @@
+#if 0
+''' '
+#endif
+
+#ifdef __cplusplus
+struct NonZeroI64;
+#endif
+
+#if 0
+' '''
+#endif
+
+
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+typedef struct Option_Option_NonZeroI64 Option_Option_NonZeroI64;
+
+typedef struct {
+  uint8_t a;
+  uint16_t b;
+  uint32_t c;
+  uint64_t d;
+  int8_t e;
+  int16_t f;
+  int32_t g;
+  int64_t h;
+  int64_t i;
+  const Option_Option_NonZeroI64 *j;
+} NonZeroTest;
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+void root(NonZeroTest test,
+          uint8_t a,
+          uint16_t b,
+          uint32_t c,
+          uint64_t d,
+          int8_t e,
+          int16_t f,
+          int32_t g,
+          int64_t h,
+          int64_t i,
+          const Option_Option_NonZeroI64 *j);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif // __cplusplus
diff --git a/tests/expectations/nonzero.cpp b/tests/expectations/nonzero.cpp
new file mode 100644
index 000000000..9aef0559a
--- /dev/null
+++ b/tests/expectations/nonzero.cpp
@@ -0,0 +1,50 @@
+#if 0
+''' '
+#endif
+
+#ifdef __cplusplus
+struct NonZeroI64;
+#endif
+
+#if 0
+' '''
+#endif
+
+
+#include <cstdarg>
+#include <cstdint>
+#include <cstdlib>
+#include <ostream>
+#include <new>
+
+template<typename T = void>
+struct Option;
+
+struct NonZeroTest {
+  uint8_t a;
+  uint16_t b;
+  uint32_t c;
+  uint64_t d;
+  int8_t e;
+  int16_t f;
+  int32_t g;
+  int64_t h;
+  int64_t i;
+  const Option<Option<NonZeroI64>> *j;
+};
+
+extern "C" {
+
+void root(NonZeroTest test,
+          uint8_t a,
+          uint16_t b,
+          uint32_t c,
+          uint64_t d,
+          int8_t e,
+          int16_t f,
+          int32_t g,
+          int64_t h,
+          int64_t i,
+          const Option<Option<NonZeroI64>> *j);
+
+} // extern "C"
diff --git a/tests/expectations/nonzero.pyx b/tests/expectations/nonzero.pyx
new file mode 100644
index 000000000..ef05cc184
--- /dev/null
+++ b/tests/expectations/nonzero.pyx
@@ -0,0 +1,47 @@
+#if 0
+''' '
+#endif
+
+#ifdef __cplusplus
+struct NonZeroI64;
+#endif
+
+#if 0
+' '''
+#endif
+
+
+from libc.stdint cimport int8_t, int16_t, int32_t, int64_t, intptr_t
+from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t, uintptr_t
+cdef extern from *:
+  ctypedef bint bool
+  ctypedef struct va_list
+
+cdef extern from *:
+
+  ctypedef struct Option_Option_NonZeroI64:
+    pass
+
+  ctypedef struct NonZeroTest:
+    uint8_t a;
+    uint16_t b;
+    uint32_t c;
+    uint64_t d;
+    int8_t e;
+    int16_t f;
+    int32_t g;
+    int64_t h;
+    int64_t i;
+    const Option_Option_NonZeroI64 *j;
+
+  void root(NonZeroTest test,
+            uint8_t a,
+            uint16_t b,
+            uint32_t c,
+            uint64_t d,
+            int8_t e,
+            int16_t f,
+            int32_t g,
+            int64_t h,
+            int64_t i,
+            const Option_Option_NonZeroI64 *j);
diff --git a/tests/expectations/nonzero.tag.c b/tests/expectations/nonzero.tag.c
new file mode 100644
index 000000000..4e11a12d2
--- /dev/null
+++ b/tests/expectations/nonzero.tag.c
@@ -0,0 +1,44 @@
+#if 0
+''' '
+#endif
+
+#ifdef __cplusplus
+struct NonZeroI64;
+#endif
+
+#if 0
+' '''
+#endif
+
+
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+struct Option_Option_NonZeroI64;
+
+struct NonZeroTest {
+  uint8_t a;
+  uint16_t b;
+  uint32_t c;
+  uint64_t d;
+  int8_t e;
+  int16_t f;
+  int32_t g;
+  int64_t h;
+  int64_t i;
+  const struct Option_Option_NonZeroI64 *j;
+};
+
+void root(struct NonZeroTest test,
+          uint8_t a,
+          uint16_t b,
+          uint32_t c,
+          uint64_t d,
+          int8_t e,
+          int16_t f,
+          int32_t g,
+          int64_t h,
+          int64_t i,
+          const struct Option_Option_NonZeroI64 *j);
diff --git a/tests/expectations/nonzero.tag.compat.c b/tests/expectations/nonzero.tag.compat.c
new file mode 100644
index 000000000..e1ff2fb48
--- /dev/null
+++ b/tests/expectations/nonzero.tag.compat.c
@@ -0,0 +1,52 @@
+#if 0
+''' '
+#endif
+
+#ifdef __cplusplus
+struct NonZeroI64;
+#endif
+
+#if 0
+' '''
+#endif
+
+
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+struct Option_Option_NonZeroI64;
+
+struct NonZeroTest {
+  uint8_t a;
+  uint16_t b;
+  uint32_t c;
+  uint64_t d;
+  int8_t e;
+  int16_t f;
+  int32_t g;
+  int64_t h;
+  int64_t i;
+  const struct Option_Option_NonZeroI64 *j;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+void root(struct NonZeroTest test,
+          uint8_t a,
+          uint16_t b,
+          uint32_t c,
+          uint64_t d,
+          int8_t e,
+          int16_t f,
+          int32_t g,
+          int64_t h,
+          int64_t i,
+          const struct Option_Option_NonZeroI64 *j);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif // __cplusplus
diff --git a/tests/expectations/nonzero.tag.pyx b/tests/expectations/nonzero.tag.pyx
new file mode 100644
index 000000000..b3bba7237
--- /dev/null
+++ b/tests/expectations/nonzero.tag.pyx
@@ -0,0 +1,47 @@
+#if 0
+''' '
+#endif
+
+#ifdef __cplusplus
+struct NonZeroI64;
+#endif
+
+#if 0
+' '''
+#endif
+
+
+from libc.stdint cimport int8_t, int16_t, int32_t, int64_t, intptr_t
+from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t, uintptr_t
+cdef extern from *:
+  ctypedef bint bool
+  ctypedef struct va_list
+
+cdef extern from *:
+
+  cdef struct Option_Option_NonZeroI64:
+    pass
+
+  cdef struct NonZeroTest:
+    uint8_t a;
+    uint16_t b;
+    uint32_t c;
+    uint64_t d;
+    int8_t e;
+    int16_t f;
+    int32_t g;
+    int64_t h;
+    int64_t i;
+    const Option_Option_NonZeroI64 *j;
+
+  void root(NonZeroTest test,
+            uint8_t a,
+            uint16_t b,
+            uint32_t c,
+            uint64_t d,
+            int8_t e,
+            int16_t f,
+            int32_t g,
+            int64_t h,
+            int64_t i,
+            const Option_Option_NonZeroI64 *j);
diff --git a/tests/expectations/simplify_option_ptr.both.c b/tests/expectations/simplify_option_ptr.both.c
index 402e5fe5a..1efe0f8fa 100644
--- a/tests/expectations/simplify_option_ptr.both.c
+++ b/tests/expectations/simplify_option_ptr.both.c
@@ -5,16 +5,26 @@
 
 typedef struct Opaque Opaque;
 
+typedef struct Option_____Opaque Option_____Opaque;
+
+typedef struct Option_______c_void Option_______c_void;
+
 typedef struct Foo {
   const struct Opaque *x;
   struct Opaque *y;
   void (*z)(void);
+  struct Option_______c_void *zz;
 } Foo;
 
 typedef union Bar {
   const struct Opaque *x;
   struct Opaque *y;
   void (*z)(void);
+  struct Option_______c_void *zz;
 } Bar;
 
-void root(const struct Opaque *a, struct Opaque *b, struct Foo c, union Bar d);
+void root(const struct Opaque *a,
+          struct Opaque *b,
+          struct Foo c,
+          union Bar d,
+          struct Option_____Opaque *e);
diff --git a/tests/expectations/simplify_option_ptr.both.compat.c b/tests/expectations/simplify_option_ptr.both.compat.c
index d03e4bc14..3ad00d1eb 100644
--- a/tests/expectations/simplify_option_ptr.both.compat.c
+++ b/tests/expectations/simplify_option_ptr.both.compat.c
@@ -5,23 +5,33 @@
 
 typedef struct Opaque Opaque;
 
+typedef struct Option_____Opaque Option_____Opaque;
+
+typedef struct Option_______c_void Option_______c_void;
+
 typedef struct Foo {
   const struct Opaque *x;
   struct Opaque *y;
   void (*z)(void);
+  struct Option_______c_void *zz;
 } Foo;
 
 typedef union Bar {
   const struct Opaque *x;
   struct Opaque *y;
   void (*z)(void);
+  struct Option_______c_void *zz;
 } Bar;
 
 #ifdef __cplusplus
 extern "C" {
 #endif // __cplusplus
 
-void root(const struct Opaque *a, struct Opaque *b, struct Foo c, union Bar d);
+void root(const struct Opaque *a,
+          struct Opaque *b,
+          struct Foo c,
+          union Bar d,
+          struct Option_____Opaque *e);
 
 #ifdef __cplusplus
 } // extern "C"
diff --git a/tests/expectations/simplify_option_ptr.c b/tests/expectations/simplify_option_ptr.c
index 87b5ce9a2..42d4328fd 100644
--- a/tests/expectations/simplify_option_ptr.c
+++ b/tests/expectations/simplify_option_ptr.c
@@ -5,16 +5,22 @@
 
 typedef struct Opaque Opaque;
 
+typedef struct Option_____Opaque Option_____Opaque;
+
+typedef struct Option_______c_void Option_______c_void;
+
 typedef struct {
   const Opaque *x;
   Opaque *y;
   void (*z)(void);
+  Option_______c_void *zz;
 } Foo;
 
 typedef union {
   const Opaque *x;
   Opaque *y;
   void (*z)(void);
+  Option_______c_void *zz;
 } Bar;
 
-void root(const Opaque *a, Opaque *b, Foo c, Bar d);
+void root(const Opaque *a, Opaque *b, Foo c, Bar d, Option_____Opaque *e);
diff --git a/tests/expectations/simplify_option_ptr.compat.c b/tests/expectations/simplify_option_ptr.compat.c
index f3761ec9e..7c523b5b8 100644
--- a/tests/expectations/simplify_option_ptr.compat.c
+++ b/tests/expectations/simplify_option_ptr.compat.c
@@ -5,23 +5,29 @@
 
 typedef struct Opaque Opaque;
 
+typedef struct Option_____Opaque Option_____Opaque;
+
+typedef struct Option_______c_void Option_______c_void;
+
 typedef struct {
   const Opaque *x;
   Opaque *y;
   void (*z)(void);
+  Option_______c_void *zz;
 } Foo;
 
 typedef union {
   const Opaque *x;
   Opaque *y;
   void (*z)(void);
+  Option_______c_void *zz;
 } Bar;
 
 #ifdef __cplusplus
 extern "C" {
 #endif // __cplusplus
 
-void root(const Opaque *a, Opaque *b, Foo c, Bar d);
+void root(const Opaque *a, Opaque *b, Foo c, Bar d, Option_____Opaque *e);
 
 #ifdef __cplusplus
 } // extern "C"
diff --git a/tests/expectations/simplify_option_ptr.cpp b/tests/expectations/simplify_option_ptr.cpp
index 5ff7f22e6..5b453817f 100644
--- a/tests/expectations/simplify_option_ptr.cpp
+++ b/tests/expectations/simplify_option_ptr.cpp
@@ -6,20 +6,25 @@
 
 struct Opaque;
 
+template<typename T = void>
+struct Option;
+
 struct Foo {
   const Opaque *x;
   Opaque *y;
   void (*z)();
+  Option<void(*)()> *zz;
 };
 
 union Bar {
   const Opaque *x;
   Opaque *y;
   void (*z)();
+  Option<void(*)()> *zz;
 };
 
 extern "C" {
 
-void root(const Opaque *a, Opaque *b, Foo c, Bar d);
+void root(const Opaque *a, Opaque *b, Foo c, Bar d, Option<Opaque*> *e);
 
 } // extern "C"
diff --git a/tests/expectations/simplify_option_ptr.pyx b/tests/expectations/simplify_option_ptr.pyx
index f2f689229..7496142ff 100644
--- a/tests/expectations/simplify_option_ptr.pyx
+++ b/tests/expectations/simplify_option_ptr.pyx
@@ -9,14 +9,22 @@ cdef extern from *:
   ctypedef struct Opaque:
     pass
 
+  ctypedef struct Option_____Opaque:
+    pass
+
+  ctypedef struct Option_______c_void:
+    pass
+
   ctypedef struct Foo:
     const Opaque *x;
     Opaque *y;
     void (*z)();
+    Option_______c_void *zz;
 
   ctypedef union Bar:
     const Opaque *x;
     Opaque *y;
     void (*z)();
+    Option_______c_void *zz;
 
-  void root(const Opaque *a, Opaque *b, Foo c, Bar d);
+  void root(const Opaque *a, Opaque *b, Foo c, Bar d, Option_____Opaque *e);
diff --git a/tests/expectations/simplify_option_ptr.tag.c b/tests/expectations/simplify_option_ptr.tag.c
index 0eb33b103..ce286591b 100644
--- a/tests/expectations/simplify_option_ptr.tag.c
+++ b/tests/expectations/simplify_option_ptr.tag.c
@@ -5,16 +5,26 @@
 
 struct Opaque;
 
+struct Option_____Opaque;
+
+struct Option_______c_void;
+
 struct Foo {
   const struct Opaque *x;
   struct Opaque *y;
   void (*z)(void);
+  struct Option_______c_void *zz;
 };
 
 union Bar {
   const struct Opaque *x;
   struct Opaque *y;
   void (*z)(void);
+  struct Option_______c_void *zz;
 };
 
-void root(const struct Opaque *a, struct Opaque *b, struct Foo c, union Bar d);
+void root(const struct Opaque *a,
+          struct Opaque *b,
+          struct Foo c,
+          union Bar d,
+          struct Option_____Opaque *e);
diff --git a/tests/expectations/simplify_option_ptr.tag.compat.c b/tests/expectations/simplify_option_ptr.tag.compat.c
index 752a99d8c..9288244df 100644
--- a/tests/expectations/simplify_option_ptr.tag.compat.c
+++ b/tests/expectations/simplify_option_ptr.tag.compat.c
@@ -5,23 +5,33 @@
 
 struct Opaque;
 
+struct Option_____Opaque;
+
+struct Option_______c_void;
+
 struct Foo {
   const struct Opaque *x;
   struct Opaque *y;
   void (*z)(void);
+  struct Option_______c_void *zz;
 };
 
 union Bar {
   const struct Opaque *x;
   struct Opaque *y;
   void (*z)(void);
+  struct Option_______c_void *zz;
 };
 
 #ifdef __cplusplus
 extern "C" {
 #endif // __cplusplus
 
-void root(const struct Opaque *a, struct Opaque *b, struct Foo c, union Bar d);
+void root(const struct Opaque *a,
+          struct Opaque *b,
+          struct Foo c,
+          union Bar d,
+          struct Option_____Opaque *e);
 
 #ifdef __cplusplus
 } // extern "C"
diff --git a/tests/expectations/simplify_option_ptr.tag.pyx b/tests/expectations/simplify_option_ptr.tag.pyx
index 72890fbcf..66cb4405b 100644
--- a/tests/expectations/simplify_option_ptr.tag.pyx
+++ b/tests/expectations/simplify_option_ptr.tag.pyx
@@ -9,14 +9,22 @@ cdef extern from *:
   cdef struct Opaque:
     pass
 
+  cdef struct Option_____Opaque:
+    pass
+
+  cdef struct Option_______c_void:
+    pass
+
   cdef struct Foo:
     const Opaque *x;
     Opaque *y;
     void (*z)();
+    Option_______c_void *zz;
 
   cdef union Bar:
     const Opaque *x;
     Opaque *y;
     void (*z)();
+    Option_______c_void *zz;
 
-  void root(const Opaque *a, Opaque *b, Foo c, Bar d);
+  void root(const Opaque *a, Opaque *b, Foo c, Bar d, Option_____Opaque *e);
diff --git a/tests/rust/nonzero.rs b/tests/rust/nonzero.rs
new file mode 100644
index 000000000..9bc2cde27
--- /dev/null
+++ b/tests/rust/nonzero.rs
@@ -0,0 +1,30 @@
+use std::num::*;
+
+#[repr(C)]
+pub struct NonZeroTest {
+    pub a: NonZeroU8,
+    pub b: NonZeroU16,
+    pub c: NonZeroU32,
+    pub d: NonZeroU64,
+    pub e: NonZeroI8,
+    pub f: NonZeroI16,
+    pub g: NonZeroI32,
+    pub h: NonZeroI64,
+    pub i: Option<NonZeroI64>,
+    pub j: *const Option<Option<NonZeroI64>>,
+}
+
+#[no_mangle]
+pub extern "C" fn root(
+    test: NonZeroTest,
+    a: NonZeroU8,
+    b: NonZeroU16,
+    c: NonZeroU32,
+    d: NonZeroU64,
+    e: NonZeroI8,
+    f: NonZeroI16,
+    g: NonZeroI32,
+    h: NonZeroI64,
+    i: Option<NonZeroI64>,
+    j: *const Option<Option<NonZeroI64>>,
+) {}
diff --git a/tests/rust/nonzero.toml b/tests/rust/nonzero.toml
new file mode 100644
index 000000000..3c656dc7c
--- /dev/null
+++ b/tests/rust/nonzero.toml
@@ -0,0 +1,13 @@
+header = """
+#if 0
+''' '
+#endif
+
+#ifdef __cplusplus
+struct NonZeroI64;
+#endif
+
+#if 0
+' '''
+#endif
+"""
diff --git a/tests/rust/simplify_option_ptr.rs b/tests/rust/simplify_option_ptr.rs
index b6e3f5b11..d43be3e14 100644
--- a/tests/rust/simplify_option_ptr.rs
+++ b/tests/rust/simplify_option_ptr.rs
@@ -6,6 +6,7 @@ struct Foo {
     x: Option<&Opaque>,
     y: Option<&mut Opaque>,
     z: Option<fn () -> ()>,
+    zz: *mut Option<fn () -> ()>,
 }
 
 #[repr(C)]
@@ -13,6 +14,7 @@ union Bar {
     x: Option<&Opaque>,
     y: Option<&mut Opaque>,
     z: Option<fn () -> ()>,
+    zz: *mut Option<fn () -> ()>,
 }
 
 #[no_mangle]
@@ -20,5 +22,6 @@ pub extern "C" fn root(
 	a: Option<&Opaque>,
     b: Option<&mut Opaque>,
     c: Foo,
-    d: Bar
+    d: Bar,
+    e: *mut Option<*mut Opaque>,
 ) { }