Parse extern C++ structs
diff --git a/syntax/check.rs b/syntax/check.rs
index 7b84b18..5980f75 100644
--- a/syntax/check.rs
+++ b/syntax/check.rs
@@ -71,7 +71,10 @@
 
 fn check_type_box(cx: &mut Check, ptr: &Ty1) {
     if let Type::Ident(ident) = &ptr.inner {
-        if cx.types.cxx.contains(ident) && !cx.types.enums.contains_key(ident) {
+        if cx.types.cxx.contains(ident)
+            && !cx.types.structs.contains_key(ident)
+            && !cx.types.enums.contains_key(ident)
+        {
             cx.error(ptr, error::BOX_CXX_TYPE.msg);
         }
 
@@ -85,7 +88,10 @@
 
 fn check_type_rust_vec(cx: &mut Check, ty: &Ty1) {
     if let Type::Ident(ident) = &ty.inner {
-        if cx.types.cxx.contains(ident) && !cx.types.enums.contains_key(ident) {
+        if cx.types.cxx.contains(ident)
+            && !cx.types.structs.contains_key(ident)
+            && !cx.types.enums.contains_key(ident)
+        {
             cx.error(ty, "Rust Vec containing C++ type is not supported yet");
             return;
         }
@@ -168,6 +174,11 @@
         cx.error(span, "structs without any fields are not supported");
     }
 
+    if cx.types.cxx.contains(&strct.ident) {
+        let span = span_for_struct_error(strct);
+        cx.error(span, "extern C++ structs are not implemented yet");
+    }
+
     for field in &strct.fields {
         if is_unsized(cx, &field.ty) {
             let desc = describe(cx, &field.ty);
@@ -321,7 +332,9 @@
         _ => return false,
     };
     ident == CxxString
-        || cx.types.cxx.contains(ident) && !cx.types.enums.contains_key(ident)
+        || cx.types.cxx.contains(ident)
+            && !cx.types.structs.contains_key(ident)
+            && !cx.types.enums.contains_key(ident)
         || cx.types.rust.contains(ident)
 }
 
diff --git a/syntax/types.rs b/syntax/types.rs
index 2f87d96..d579c78 100644
--- a/syntax/types.rs
+++ b/syntax/types.rs
@@ -48,33 +48,54 @@
         let mut type_names = UnorderedSet::new();
         let mut function_names = UnorderedSet::new();
         for api in apis {
+            // The same identifier is permitted to be declared as both a shared
+            // enum and extern C++ type, or shared struct and extern C++ type.
+            // That indicates to not emit the C++ enum/struct definition because
+            // it's defined by the included headers already.
+            //
+            // All other cases of duplicate identifiers are reported as an error.
             match api {
                 Api::Include(_) => {}
                 Api::Struct(strct) => {
                     let ident = &strct.ident;
-                    if type_names.insert(ident) {
-                        structs.insert(ident, strct);
-                    } else {
+                    if !type_names.insert(ident)
+                        && (!cxx.contains(ident)
+                            || structs.contains_key(ident)
+                            || enums.contains_key(ident))
+                    {
+                        // If already declared as a struct or enum, or if
+                        // colliding with something other than an extern C++
+                        // type, then error.
                         duplicate_name(cx, strct, ident);
                     }
+                    structs.insert(ident, strct);
                     for field in &strct.fields {
                         visit(&mut all, &field.ty);
                     }
                 }
                 Api::Enum(enm) => {
                     let ident = &enm.ident;
-                    // We allow declaring the same type as a shared enum and as a Cxxtype, as this
-                    // means not to emit the C++ enum definition.
-                    if !type_names.insert(ident) && !cxx.contains(ident) {
+                    if !type_names.insert(ident)
+                        && (!cxx.contains(ident)
+                            || structs.contains_key(ident)
+                            || enums.contains_key(ident))
+                    {
+                        // If already declared as a struct or enum, or if
+                        // colliding with something other than an extern C++
+                        // type, then error.
                         duplicate_name(cx, enm, ident);
                     }
                     enums.insert(ident, enm);
                 }
                 Api::CxxType(ety) => {
                     let ident = &ety.ident;
-                    // We allow declaring the same type as a shared enum and as a Cxxtype, as this
-                    // means not to emit the C++ enum definition.
-                    if !type_names.insert(ident) && !enums.contains_key(ident) {
+                    if !type_names.insert(ident)
+                        && (cxx.contains(ident)
+                            || !structs.contains_key(ident) && !enums.contains_key(ident))
+                    {
+                        // If already declared as an extern C++ type, or if
+                        // colliding with something which is neither struct nor
+                        // enum, then error.
                         duplicate_name(cx, ety, ident);
                     }
                     cxx.insert(ident);