From f4d4994c1481baaf0a6e643bf3d3466d35bf950b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Fri, 6 Jan 2017 12:15:52 +0100 Subject: [PATCH] codegen: ignore aliases for decltypes we can't resolve. We do the same for template parameters with `typename` on aliases. This is not great, but it's better than generating invalid code. --- src/codegen/mod.rs | 25 ++++++++++++++++--- src/ir/ty.rs | 21 ++++++++++++++++ .../expectations/tests/381-decltype-alias.rs | 12 +++++++++ tests/headers/381-decltype-alias.hpp | 7 ++++++ 4 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 tests/expectations/tests/381-decltype-alias.rs create mode 100644 tests/headers/381-decltype-alias.hpp diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 313ca8b0d3..c36dd64448 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -549,6 +549,26 @@ impl CodeGenerator for Type { inner_item.to_rust_ty(ctx) }; + { + // FIXME(emilio): This is a workaround to avoid generating + // incorrect type aliases because of types that we haven't + // been able to resolve (because, eg, they depend on a + // template parameter). + // + // It's kind of a shame not generating them even when they + // could be referenced, but we already do the same for items + // with invalid template parameters, and at least this way + // they can be replaced, instead of generating plain invalid + // code. + let inner_canon_type = + inner_item.expect_type().canonical_type(ctx); + if inner_canon_type.is_invalid_named_type() { + warn!("Item contained invalid named type, skipping: \ + {:?}, {:?}", item, inner_item); + return; + } + } + let rust_name = ctx.rust_ident(&name); let mut typedef = aster::AstBuilder::new().item().pub_(); @@ -586,9 +606,8 @@ impl CodeGenerator for Type { for template_arg in applicable_template_args.iter() { let template_arg = ctx.resolve_type(*template_arg); if template_arg.is_named() { - let name = template_arg.name().unwrap(); - if name.contains("typename ") { - warn!("Item contained `typename`'d template \ + if template_arg.is_invalid_named_type() { + warn!("Item contained invalid template \ parameter: {:?}", item); return; } diff --git a/src/ir/ty.rs b/src/ir/ty.rs index f120e180c5..005caccac7 100644 --- a/src/ir/ty.rs +++ b/src/ir/ty.rs @@ -292,6 +292,27 @@ impl Type { } } + /// Whether this named type is an invalid C++ identifier. This is done to + /// avoid generating invalid code with some cases we can't handle, see: + /// + /// tests/headers/381-decltype-alias.hpp + pub fn is_invalid_named_type(&self) -> bool { + match self.kind { + TypeKind::Named(ref name) => { + assert!(!name.is_empty()); + let mut chars = name.chars(); + let first = chars.next().unwrap(); + let mut remaining = chars; + + let valid = (first.is_alphabetic() || first == '_') && + remaining.all(|c| c.is_alphanumeric() || c == '_'); + + !valid + } + _ => false, + } + } + /// See safe_canonical_type. pub fn canonical_type<'tr>(&'tr self, ctx: &'tr BindgenContext) diff --git a/tests/expectations/tests/381-decltype-alias.rs b/tests/expectations/tests/381-decltype-alias.rs new file mode 100644 index 0000000000..766be3bced --- /dev/null +++ b/tests/expectations/tests/381-decltype-alias.rs @@ -0,0 +1,12 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct std_allocator_traits<_Alloc> { + pub _address: u8, + pub _phantom_0: ::std::marker::PhantomData<_Alloc>, +} diff --git a/tests/headers/381-decltype-alias.hpp b/tests/headers/381-decltype-alias.hpp new file mode 100644 index 0000000000..0bec2fc7d1 --- /dev/null +++ b/tests/headers/381-decltype-alias.hpp @@ -0,0 +1,7 @@ +// bindgen-flags: -- -std=c++11 + +namespace std { + template struct allocator_traits { + typedef decltype ( _S_size_type_helper ( ( _Alloc * ) 0 ) ) __size_type; + }; +}