diff --git a/bindgen/clang.rs b/bindgen/clang.rs index 4a4ed89d69..76a449f2d1 100644 --- a/bindgen/clang.rs +++ b/bindgen/clang.rs @@ -8,11 +8,12 @@ use crate::ir::context::BindgenContext; use clang_sys::*; use std::cmp; +use std::convert::{TryFrom, TryInto}; use std::ffi::{CStr, CString}; use std::fmt; use std::hash::Hash; use std::hash::Hasher; -use std::os::raw::{c_char, c_int, c_longlong, c_uint, c_ulong, c_ulonglong}; +use std::os::raw::{c_char, c_int, c_uint}; use std::{mem, ptr, slice}; /// Type representing a clang attribute. @@ -121,13 +122,14 @@ impl Cursor { if manglings.is_null() { return Err(()); } - let count = (*manglings).Count as usize; - - let mut result = Vec::with_capacity(count); - for i in 0..count { - let string_ptr = (*manglings).Strings.add(i); - result.push(cxstring_to_string_leaky(*string_ptr)); - } + let string_set = slice::from_raw_parts( + (*manglings).Strings, + (*manglings).Count.try_into().unwrap(), + ); + let result = string_set + .iter() + .map(|string_ptr| cxstring_to_string_leaky(*string_ptr)) + .collect(); clang_disposeStringSet(manglings); Ok(result) } @@ -194,7 +196,7 @@ impl Cursor { /// /// NOTE: This may not return `Some` for partial template specializations, /// see #193 and #194. - pub(crate) fn num_template_args(&self) -> Option { + pub(crate) fn num_template_args(&self) -> Option { // XXX: `clang_Type_getNumTemplateArguments` is sort of reliable, while // `clang_Cursor_getNumTemplateArguments` is totally unreliable. // Therefore, try former first, and only fallback to the latter if we @@ -204,9 +206,8 @@ impl Cursor { .or_else(|| { let n: c_int = unsafe { clang_Cursor_getNumTemplateArguments(self.x) }; - if n >= 0 { - Some(n as u32) + Some(n as c_uint) } else { debug_assert_eq!(n, -1); None @@ -698,7 +699,7 @@ impl Cursor { /// Get the width of this cursor's referent bit field, or `None` if the /// referent is not a bit field or if the width could not be evaluated. - pub(crate) fn bit_width(&self) -> Option { + pub(crate) fn bit_width(&self) -> Option { // 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 @@ -707,11 +708,12 @@ impl Cursor { } unsafe { - let w = clang_getFieldDeclBitWidth(self.x); - if w == -1 { - None + let n: c_int = clang_getFieldDeclBitWidth(self.x); + if n >= 0 { + Some((n as c_uint).try_into().unwrap()) } else { - Some(w as u32) + debug_assert_eq!(n, -1); + None } } } @@ -844,10 +846,10 @@ impl Cursor { // match self.kind() { // CXCursor_FunctionDecl | // CXCursor_CXXMethod => { - self.num_args().ok().map(|num| { + self.num_args().map(|num| { (0..num) .map(|i| Cursor { - x: unsafe { clang_Cursor_getArgument(self.x, i as c_uint) }, + x: unsafe { clang_Cursor_getArgument(self.x, i) }, }) .collect() }) @@ -858,13 +860,14 @@ impl Cursor { /// /// Returns Err if the cursor's referent is not a function/method call or /// declaration. - pub(crate) fn num_args(&self) -> Result { + pub(crate) fn num_args(&self) -> Option { unsafe { - let w = clang_Cursor_getNumArguments(self.x); - if w == -1 { - Err(()) + let n: c_int = clang_Cursor_getNumArguments(self.x); + if n >= 0 { + Some(n as c_uint) } else { - Ok(w as u32) + debug_assert_eq!(n, -1); + None } } } @@ -892,11 +895,10 @@ impl Cursor { /// Get the offset of the field represented by the Cursor. pub(crate) fn offset_of_field(&self) -> Result { let offset = unsafe { clang_Cursor_getOffsetOfField(self.x) }; - if offset < 0 { - Err(LayoutError::from(offset as i32)) + Err(LayoutError::from(offset)) } else { - Ok(offset as usize) + Ok(offset.try_into().expect("offset does not fit in `usize`")) } } @@ -997,7 +999,12 @@ impl<'a> RawTokens<'a> { if self.tokens.is_null() { return &[]; } - unsafe { slice::from_raw_parts(self.tokens, self.token_count as usize) } + unsafe { + slice::from_raw_parts( + self.tokens, + self.token_count.try_into().unwrap(), + ) + } } /// Get an iterator over these tokens. @@ -1013,11 +1020,7 @@ impl<'a> Drop for RawTokens<'a> { fn drop(&mut self) { if !self.tokens.is_null() { unsafe { - clang_disposeTokens( - self.tu, - self.tokens, - self.token_count as c_uint, - ); + clang_disposeTokens(self.tu, self.tokens, self.token_count); } } } @@ -1183,25 +1186,32 @@ pub(crate) enum LayoutError { /// Asked for the layout of a field in a type that does not have such a /// field. InvalidFieldName, + /// The type is undeduced. + Undeduced, /// An unknown layout error. Unknown, } -impl ::std::convert::From for LayoutError { +impl From for LayoutError { fn from(val: i32) -> Self { - use self::LayoutError::*; - match val { - CXTypeLayoutError_Invalid => Invalid, - CXTypeLayoutError_Incomplete => Incomplete, - CXTypeLayoutError_Dependent => Dependent, - CXTypeLayoutError_NotConstantSize => NotConstantSize, - CXTypeLayoutError_InvalidFieldName => InvalidFieldName, - _ => Unknown, + CXTypeLayoutError_Invalid => Self::Invalid, + CXTypeLayoutError_Incomplete => Self::Incomplete, + CXTypeLayoutError_Dependent => Self::Dependent, + CXTypeLayoutError_NotConstantSize => Self::NotConstantSize, + CXTypeLayoutError_InvalidFieldName => Self::InvalidFieldName, + CXTypeLayoutError_Undeduced => Self::Undeduced, + _ => Self::Unknown, } } } +impl From for LayoutError { + fn from(val: i64) -> Self { + i32::try_from(val).map(Self::from).unwrap_or(Self::Unknown) + } +} + impl Type { /// Get this type's kind. pub(crate) fn kind(&self) -> CXTypeKind { @@ -1268,41 +1278,10 @@ impl Type { self.canonical_type() == *self } - #[inline] - fn clang_size_of(&self, ctx: &BindgenContext) -> c_longlong { - match self.kind() { - // Work-around https://bugs.llvm.org/show_bug.cgi?id=40975 - CXType_RValueReference | CXType_LValueReference => { - ctx.target_pointer_size() as c_longlong - } - // Work-around https://bugs.llvm.org/show_bug.cgi?id=40813 - CXType_Auto if self.is_non_deductible_auto_type() => -6, - _ => unsafe { clang_Type_getSizeOf(self.x) }, - } - } - - #[inline] - fn clang_align_of(&self, ctx: &BindgenContext) -> c_longlong { - match self.kind() { - // Work-around https://bugs.llvm.org/show_bug.cgi?id=40975 - CXType_RValueReference | CXType_LValueReference => { - ctx.target_pointer_size() as c_longlong - } - // Work-around https://bugs.llvm.org/show_bug.cgi?id=40813 - CXType_Auto if self.is_non_deductible_auto_type() => -6, - _ => unsafe { clang_Type_getAlignOf(self.x) }, - } - } - /// What is the size of this type? Paper over invalid types by returning `0` /// for them. pub(crate) fn size(&self, ctx: &BindgenContext) -> usize { - let val = self.clang_size_of(ctx); - if val < 0 { - 0 - } else { - val as usize - } + self.fallible_size(ctx).unwrap_or(0) } /// What is the size of this type? @@ -1310,23 +1289,32 @@ impl Type { &self, ctx: &BindgenContext, ) -> Result { - let val = self.clang_size_of(ctx); - if val < 0 { - Err(LayoutError::from(val as i32)) - } else { - Ok(val as usize) + match self.kind() { + // Work-around for https://github.com/llvm/llvm-project/issues/40320. + CXType_RValueReference | CXType_LValueReference => { + Ok(ctx.target_pointer_size()) + } + // Work-around for https://github.com/llvm/llvm-project/issues/40159. + CXType_Auto if self.is_non_deductible_auto_type() => { + Err(LayoutError::Undeduced) + } + _ => { + let size = unsafe { clang_Type_getSizeOf(self.x) }; + if size < 0 { + Err(LayoutError::from(size)) + } else { + Ok(size + .try_into() + .expect("type size does not fit in `usize`")) + } + } } } /// What is the alignment of this type? Paper over invalid types by /// returning `0`. pub(crate) fn align(&self, ctx: &BindgenContext) -> usize { - let val = self.clang_align_of(ctx); - if val < 0 { - 0 - } else { - val as usize - } + self.fallible_align(ctx).unwrap_or(0) } /// What is the alignment of this type? @@ -1334,11 +1322,25 @@ impl Type { &self, ctx: &BindgenContext, ) -> Result { - let val = self.clang_align_of(ctx); - if val < 0 { - Err(LayoutError::from(val as i32)) - } else { - Ok(val as usize) + match self.kind() { + // Work-around for https://github.com/llvm/llvm-project/issues/40320. + CXType_RValueReference | CXType_LValueReference => { + Ok(ctx.target_pointer_size()) + } + // Work-around for https://github.com/llvm/llvm-project/issues/40159. + CXType_Auto if self.is_non_deductible_auto_type() => { + Err(LayoutError::Undeduced) + } + _ => { + let alignment = unsafe { clang_Type_getAlignOf(self.x) }; + if alignment < 0 { + Err(LayoutError::from(alignment)) + } else { + Ok(alignment + .try_into() + .expect("type alignment does not fit in `usize`")) + } + } } } @@ -1356,10 +1358,10 @@ impl Type { /// Get the number of template arguments this type has, or `None` if it is /// not some kind of template. - pub(crate) fn num_template_args(&self) -> Option { - let n = unsafe { clang_Type_getNumTemplateArguments(self.x) }; + pub(crate) fn num_template_args(&self) -> Option { + let n: c_int = unsafe { clang_Type_getNumTemplateArguments(self.x) }; if n >= 0 { - Some(n as u32) + Some(n as c_uint) } else { debug_assert_eq!(n, -1); None @@ -1380,10 +1382,10 @@ impl Type { /// /// Returns None if the type is not a function prototype. pub(crate) fn args(&self) -> Option> { - self.num_args().ok().map(|num| { + self.num_args().map(|num| { (0..num) .map(|i| Type { - x: unsafe { clang_getArgType(self.x, i as c_uint) }, + x: unsafe { clang_getArgType(self.x, i) }, }) .collect() }) @@ -1392,13 +1394,14 @@ impl Type { /// Given that this type is a function prototype, return the number of arguments it takes. /// /// Returns Err if the type is not a function prototype. - pub(crate) fn num_args(&self) -> Result { + pub(crate) fn num_args(&self) -> Option { unsafe { - let w = clang_getNumArgTypes(self.x); - if w == -1 { - Err(()) + let n: c_int = clang_getNumArgTypes(self.x); + if n >= 0 { + Some(n as c_uint) } else { - Ok(w as u32) + debug_assert_eq!(n, -1); + None } } } @@ -1439,10 +1442,11 @@ impl Type { /// Given that this type is an array or vector type, return its number of /// elements. pub(crate) fn num_elements(&self) -> Option { - let num_elements_returned = unsafe { clang_getNumElements(self.x) }; - if num_elements_returned != -1 { - Some(num_elements_returned as usize) + let n = unsafe { clang_getNumElements(self.x) }; + if n >= 0 { + Some(n.try_into().expect("array size does not fit in `usize`")) } else { + debug_assert_eq!(n, -1); None } } @@ -1567,15 +1571,15 @@ impl CanonicalTypeDeclaration { /// An iterator for a type's template arguments. pub(crate) struct TypeTemplateArgIterator { x: CXType, - length: u32, - index: u32, + length: c_uint, + index: c_uint, } impl Iterator for TypeTemplateArgIterator { type Item = Type; fn next(&mut self) -> Option { if self.index < self.length { - let idx = self.index as c_uint; + let idx = self.index; self.index += 1; Some(Type { x: unsafe { clang_Type_getTemplateArgumentAsType(self.x, idx) }, @@ -1589,7 +1593,7 @@ impl Iterator for TypeTemplateArgIterator { impl ExactSizeIterator for TypeTemplateArgIterator { fn len(&self) -> usize { assert!(self.index <= self.length); - (self.length - self.index) as usize + (self.length - self.index).try_into().unwrap() } } @@ -1611,7 +1615,12 @@ impl SourceLocation { clang_getSpellingLocation( self.x, &mut file, &mut line, &mut col, &mut off, ); - (File { x: file }, line as usize, col as usize, off as usize) + ( + File { x: file }, + line.try_into().unwrap(), + col.try_into().unwrap(), + off.try_into().unwrap(), + ) } } } @@ -1777,7 +1786,7 @@ impl Index { pub(crate) fn new(pch: bool, diag: bool) -> Index { unsafe { Index { - x: clang_createIndex(pch as c_int, diag as c_int), + x: clang_createIndex(pch.into(), diag.into()), } } } @@ -1831,9 +1840,9 @@ impl TranslationUnit { ix.x, fname.as_ptr(), c_args.as_ptr(), - c_args.len() as c_int, + c_args.len().try_into().expect("too many arguments"), c_unsaved.as_mut_ptr(), - c_unsaved.len() as c_uint, + c_unsaved.len().try_into().expect("too many unsaved files"), opts, ) }; @@ -1848,11 +1857,11 @@ impl TranslationUnit { /// unit. pub(crate) fn diags(&self) -> Vec { unsafe { - let num = clang_getNumDiagnostics(self.x) as usize; + let num = clang_getNumDiagnostics(self.x); let mut diags = vec![]; for i in 0..num { diags.push(Diagnostic { - x: clang_getDiagnostic(self.x, i as c_uint), + x: clang_getDiagnostic(self.x, i), }); } diags @@ -1929,7 +1938,11 @@ impl UnsavedFile { let x = CXUnsavedFile { Filename: name.as_ptr(), Contents: contents.as_ptr(), - Length: contents.as_bytes().len() as c_ulong, + Length: contents + .as_bytes() + .len() + .try_into() + .expect("contents too big"), }; UnsavedFile { x, name, contents } } @@ -2006,7 +2019,7 @@ pub(crate) fn ast_dump(c: &Cursor, depth: isize) -> CXChildVisitResult { if let Some(usr) = c.usr() { print_indent(depth, format!(" {}usr = \"{}\"", prefix, usr)); } - if let Ok(num) = c.num_args() { + if let Some(num) = c.num_args() { print_indent(depth, format!(" {}number-of-args = {}", prefix, num)); } if let Some(num) = c.num_template_args() { @@ -2250,22 +2263,13 @@ impl EvalResult { if unsafe { clang_EvalResult_isUnsignedInt(self.x) } != 0 { let value = unsafe { clang_EvalResult_getAsUnsigned(self.x) }; - if value > i64::max_value() as c_ulonglong { - return None; - } - - return Some(value as i64); + #[allow(clippy::useless_conversion)] + return value.try_into().ok(); } let value = unsafe { clang_EvalResult_getAsLongLong(self.x) }; - if value > i64::max_value() as c_longlong { - return None; - } - if value < i64::min_value() as c_longlong { - return None; - } - #[allow(clippy::unnecessary_cast)] - Some(value as i64) + #[allow(clippy::useless_conversion)] + value.try_into().ok() } /// Evaluates the expression as a literal string, that may or may not be @@ -2322,7 +2326,7 @@ impl TargetInfo { /// Tries to obtain target information from libclang. pub(crate) fn new(tu: &TranslationUnit) -> Self { let triple; - let pointer_width; + let pointer_width: c_int; unsafe { let ti = clang_getTranslationUnitTargetInfo(tu.x); triple = cxstring_into_string(clang_TargetInfo_getTriple(ti)); @@ -2331,6 +2335,7 @@ impl TargetInfo { } assert!(pointer_width > 0); assert_eq!(pointer_width % 8, 0); + let pointer_width = pointer_width as c_uint; let abi = if triple.contains("msvc") { ABIKind::Microsoft @@ -2340,7 +2345,7 @@ impl TargetInfo { TargetInfo { triple, - pointer_width: pointer_width as usize, + pointer_width: usize::try_from(pointer_width).unwrap(), abi, } } diff --git a/bindgen/ir/comp.rs b/bindgen/ir/comp.rs index a5d06fa556..fd7f3ef543 100644 --- a/bindgen/ir/comp.rs +++ b/bindgen/ir/comp.rs @@ -145,7 +145,7 @@ pub(crate) trait FieldMethods { fn comment(&self) -> Option<&str>; /// If this is a bitfield, how many bits does it need? - fn bitfield_width(&self) -> Option; + fn bitfield_width(&self) -> Option; /// Is this feild declared public? fn is_public(&self) -> bool; @@ -347,7 +347,7 @@ impl Bitfield { } /// Get the bit width of this bitfield. - pub(crate) fn width(&self) -> u32 { + pub(crate) fn width(&self) -> usize { self.data.bitfield_width().unwrap() } @@ -395,7 +395,7 @@ impl FieldMethods for Bitfield { self.data.comment() } - fn bitfield_width(&self) -> Option { + fn bitfield_width(&self) -> Option { self.data.bitfield_width() } @@ -426,7 +426,7 @@ impl RawField { ty: TypeId, comment: Option, annotations: Option, - bitfield_width: Option, + bitfield_width: Option, public: bool, offset: Option, ) -> RawField { @@ -455,7 +455,7 @@ impl FieldMethods for RawField { self.0.comment() } - fn bitfield_width(&self) -> Option { + fn bitfield_width(&self) -> Option { self.0.bitfield_width() } @@ -592,7 +592,7 @@ where const is_ms_struct: bool = false; for bitfield in raw_bitfields { - let bitfield_width = bitfield.bitfield_width().unwrap() as usize; + let bitfield_width = bitfield.bitfield_width().unwrap(); let bitfield_layout = ctx.resolve_type(bitfield.ty()).layout(ctx).ok_or(())?; let bitfield_size = bitfield_layout.size; @@ -866,7 +866,7 @@ pub(crate) struct FieldData { annotations: Annotations, /// If this field is a bitfield, and how many bits does it contain if it is. - bitfield_width: Option, + bitfield_width: Option, /// If the C++ field is declared `public` public: bool, @@ -888,7 +888,7 @@ impl FieldMethods for FieldData { self.comment.as_deref() } - fn bitfield_width(&self) -> Option { + fn bitfield_width(&self) -> Option { self.bitfield_width } @@ -1797,7 +1797,7 @@ impl IsOpaque for CompInfo { .resolve_type(bf.ty()) .layout(ctx) .expect("Bitfield without layout? Gah!"); - bf.width() / 8 > bitfield_layout.size as u32 + bf.width() / 8 > bitfield_layout.size }), }) { return true;