Improve POD detection for structs with POD fields
diff --git a/syntax/mod.rs b/syntax/mod.rs
index 3b5b4d7..31c88c9 100644
--- a/syntax/mod.rs
+++ b/syntax/mod.rs
@@ -15,6 +15,7 @@
 mod names;
 pub mod namespace;
 mod parse;
+mod pod;
 pub mod qualified;
 pub mod report;
 pub mod set;
diff --git a/syntax/pod.rs b/syntax/pod.rs
new file mode 100644
index 0000000..d808a99
--- /dev/null
+++ b/syntax/pod.rs
@@ -0,0 +1,35 @@
+use crate::syntax::atom::Atom::{self, *};
+use crate::syntax::{derive, Trait, Type, Types};
+
+impl<'a> Types<'a> {
+    pub fn is_guaranteed_pod(&self, ty: &Type) -> bool {
+        match ty {
+            Type::Ident(ident) => {
+                let ident = &ident.rust;
+                if let Some(atom) = Atom::from(ident) {
+                    match atom {
+                        Bool | Char | U8 | U16 | U32 | U64 | Usize | I8 | I16 | I32 | I64
+                        | Isize | F32 | F64 => true,
+                        CxxString | RustString => false,
+                    }
+                } else if let Some(strct) = self.structs.get(ident) {
+                    derive::contains(&strct.derives, Trait::Copy)
+                        || strct
+                            .fields
+                            .iter()
+                            .all(|field| self.is_guaranteed_pod(&field.ty))
+                } else {
+                    self.enums.contains_key(ident)
+                }
+            }
+            Type::RustBox(_)
+            | Type::RustVec(_)
+            | Type::UniquePtr(_)
+            | Type::SharedPtr(_)
+            | Type::CxxVector(_)
+            | Type::Void(_) => false,
+            Type::Ref(_) | Type::Str(_) | Type::Fn(_) | Type::SliceRef(_) => true,
+            Type::Array(array) => self.is_guaranteed_pod(&array.inner),
+        }
+    }
+}
diff --git a/syntax/types.rs b/syntax/types.rs
index 72216b3..9652eb3 100644
--- a/syntax/types.rs
+++ b/syntax/types.rs
@@ -1,10 +1,8 @@
-use crate::syntax::atom::Atom::{self, *};
 use crate::syntax::improper::ImproperCtype;
 use crate::syntax::report::Errors;
 use crate::syntax::set::{OrderedSet as Set, UnorderedSet};
 use crate::syntax::{
-    derive, toposort, Api, Enum, ExternFn, ExternType, Impl, Pair, RustName, Struct, Trait, Type,
-    TypeAlias,
+    toposort, Api, Enum, ExternFn, ExternType, Impl, Pair, RustName, Struct, Type, TypeAlias,
 };
 use proc_macro2::Ident;
 use quote::ToTokens;
@@ -261,22 +259,12 @@
 
     pub fn needs_indirect_abi(&self, ty: &Type) -> bool {
         match ty {
-            Type::Ident(ident) => {
-                if let Some(strct) = self.structs.get(&ident.rust) {
-                    !self.is_pod(strct)
-                } else {
-                    Atom::from(&ident.rust) == Some(RustString)
-                }
-            }
-            Type::SharedPtr(_) | Type::RustVec(_) | Type::Array(_) => true,
-            _ => false,
+            Type::RustBox(_) | Type::UniquePtr(_) => false,
+            Type::Array(_) => true,
+            _ => !self.is_guaranteed_pod(ty),
         }
     }
 
-    pub fn is_pod(&self, strct: &Struct) -> bool {
-        derive::contains(&strct.derives, Trait::Copy)
-    }
-
     // Types that trigger rustc's default #[warn(improper_ctypes)] lint, even if
     // they may be otherwise unproblematic to mention in an extern signature.
     // For example in a signature like `extern "C" fn(*const String)`, rustc