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);