diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/clang.rs | 96 | ||||
-rw-r--r-- | src/ir/comp.rs | 26 |
2 files changed, 118 insertions, 4 deletions
diff --git a/src/clang.rs b/src/clang.rs index 587cc0ba..00716a1b 100644 --- a/src/clang.rs +++ b/src/clang.rs @@ -276,6 +276,56 @@ impl Cursor { true } + /// Is the referent any kind of template parameter? + pub fn is_template_parameter(&self) -> bool { + match self.kind() { + CXCursor_TemplateTemplateParameter | + CXCursor_TemplateTypeParameter | + CXCursor_NonTypeTemplateParameter => true, + _ => false, + } + } + + /// Does the referent's type or value depend on a template parameter? + pub fn is_dependent_on_template_parameter(&self) -> bool { + fn visitor( + found_template_parameter: &mut bool, + cur: Cursor, + ) -> CXChildVisitResult { + // If we found a template parameter, it is dependent. + if cur.is_template_parameter() { + *found_template_parameter = true; + return CXChildVisit_Break; + } + + // Get the referent and traverse it as well. + if let Some(referenced) = cur.referenced() { + if referenced.is_template_parameter() { + *found_template_parameter = true; + return CXChildVisit_Break; + } + + referenced + .visit(|next| visitor(found_template_parameter, next)); + if *found_template_parameter { + return CXChildVisit_Break; + } + } + + // Continue traversing the AST at the original cursor. + CXChildVisit_Recurse + } + + if self.is_template_parameter() { + return true; + } + + let mut found_template_parameter = false; + self.visit(|next| visitor(&mut found_template_parameter, next)); + + found_template_parameter + } + /// Is this cursor pointing a valid referent? pub fn is_valid(&self) -> bool { unsafe { clang_isInvalid(self.kind()) == 0 } @@ -485,9 +535,45 @@ impl Cursor { !self.is_defaulted_function() } + /// Is the referent a bit field declaration? + pub fn is_bit_field(&self) -> bool { + unsafe { clang_Cursor_isBitField(self.x) != 0 } + } + + /// Get a cursor to the bit field's width expression, or `None` if it's not + /// a bit field. + pub fn bit_width_expr(&self) -> Option<Cursor> { + if !self.is_bit_field() { + return None; + } + + let mut result = None; + self.visit(|cur| { + // The first child may or may not be a TypeRef, depending on whether + // the field's type is builtin. Skip it. + if cur.kind() == CXCursor_TypeRef { + return CXChildVisit_Continue; + } + + // The next expression or literal is the bit width. + result = Some(cur); + + CXChildVisit_Break + }); + + result + } + /// Get the width of this cursor's referent bit field, or `None` if the - /// referent is not a bit field. + /// referent is not a bit field or if the width could not be evaluated. pub fn bit_width(&self) -> Option<u32> { + // It is not safe to check the bit width without ensuring it doesn't + // depend on a template parameter. See + // https://github.com/rust-lang/rust-bindgen/issues/2239 + if self.bit_width_expr()?.is_dependent_on_template_parameter() { + return None; + } + unsafe { let w = clang_getFieldDeclBitWidth(self.x); if w == -1 { @@ -1789,9 +1875,15 @@ pub fn ast_dump(c: &Cursor, depth: isize) -> CXChildVisitResult { format!(" {}number-of-template-args = {}", prefix, num), ); } - if let Some(width) = c.bit_width() { + + if c.is_bit_field() { + let width = match c.bit_width() { + Some(w) => w.to_string(), + None => "<unevaluable>".to_string(), + }; print_indent(depth, format!(" {}bit-width = {}", prefix, width)); } + if let Some(ty) = c.enum_type() { print_indent( depth, diff --git a/src/ir/comp.rs b/src/ir/comp.rs index a221e520..9808d598 100644 --- a/src/ir/comp.rs +++ b/src/ir/comp.rs @@ -1045,6 +1045,11 @@ pub struct CompInfo { /// size_t) has_non_type_template_params: bool, + /// Whether this type has a bit field member whose width couldn't be + /// evaluated (e.g. if it depends on a template parameter). We generate an + /// opaque type in this case. + has_unevaluable_bit_field_width: bool, + /// Whether we saw `__attribute__((packed))` on or within this type. packed_attr: bool, @@ -1078,6 +1083,7 @@ impl CompInfo { has_destructor: false, has_nonempty_base: false, has_non_type_template_params: false, + has_unevaluable_bit_field_width: false, packed_attr: false, found_unknown_attr: false, is_forward_declaration: false, @@ -1317,7 +1323,21 @@ impl CompInfo { } } - let bit_width = cur.bit_width(); + let bit_width = if cur.is_bit_field() { + let width = cur.bit_width(); + + // Make opaque type if the bit width couldn't be + // evaluated. + if width.is_none() { + ci.has_unevaluable_bit_field_width = true; + return CXChildVisit_Break; + } + + width + } else { + None + }; + let field_type = Item::from_ty_or_ref( cur.cur_type(), cur, @@ -1753,7 +1773,9 @@ impl IsOpaque for CompInfo { type Extra = Option<Layout>; fn is_opaque(&self, ctx: &BindgenContext, layout: &Option<Layout>) -> bool { - if self.has_non_type_template_params { + if self.has_non_type_template_params || + self.has_unevaluable_bit_field_width + { return true; } |