diff --git a/bindgen/clang.rs b/bindgen/clang.rs index 26c02acec9..7a451c0dc3 100644 --- a/bindgen/clang.rs +++ b/bindgen/clang.rs @@ -8,12 +8,13 @@ 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::fs::OpenOptions; 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_longlong, c_uint, c_ulonglong}; use std::sync::OnceLock; use std::{mem, ptr, slice}; @@ -123,13 +124,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) } @@ -196,7 +198,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 @@ -206,12 +208,15 @@ impl Cursor { .or_else(|| { let n: c_int = unsafe { clang_Cursor_getNumTemplateArguments(self.x) }; - - if n >= 0 { - Some(n as u32) - } else { - debug_assert_eq!(n, -1); - None + match c_uint::try_from(n) { + Ok(n) => Some(n), + Err(_) => { + debug_assert_eq!( + n, -1, + "-1 is the only expected error" + ); + None + } } }) .or_else(|| { @@ -700,7 +705,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 @@ -709,11 +714,13 @@ impl Cursor { } unsafe { - let w = clang_getFieldDeclBitWidth(self.x); - if w == -1 { - None - } else { - Some(w as u32) + let n: c_int = clang_getFieldDeclBitWidth(self.x); + match c_uint::try_from(n) { + Ok(n) => Some(n.try_into().unwrap()), + Err(_) => { + debug_assert_eq!(n, -1, "-1 is the only expected error"); + None + } } } } @@ -752,8 +759,7 @@ impl Cursor { pub(crate) fn enum_val_signed(&self) -> Option { unsafe { if self.kind() == CXCursor_EnumConstantDecl { - #[allow(clippy::unnecessary_cast)] - Some(clang_getEnumConstantDeclValue(self.x) as i64) + Some(clang_getEnumConstantDeclValue(self.x).try_into().unwrap()) } else { None } @@ -766,8 +772,11 @@ impl Cursor { pub(crate) fn enum_val_unsigned(&self) -> Option { unsafe { if self.kind() == CXCursor_EnumConstantDecl { - #[allow(clippy::unnecessary_cast)] - Some(clang_getEnumConstantDeclUnsignedValue(self.x) as u64) + Some( + clang_getEnumConstantDeclUnsignedValue(self.x) + .try_into() + .unwrap(), + ) } else { None } @@ -846,10 +855,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() }) @@ -860,13 +869,15 @@ 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(()) - } else { - Ok(w as u32) + let n: c_int = clang_Cursor_getNumArguments(self.x); + match c_uint::try_from(n) { + Ok(n) => Some(n), + Err(_) => { + debug_assert_eq!(n, -1, "-1 is the only expected error"); + None + } } } } @@ -893,12 +904,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)) - } else { - Ok(offset as usize) + let n: c_longlong = unsafe { clang_Cursor_getOffsetOfField(self.x) }; + match c_ulonglong::try_from(n) { + Ok(offset) => Ok(offset.try_into().unwrap()), + Err(_) => Err(LayoutError::from(n)), } } @@ -999,7 +1008,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. @@ -1015,11 +1029,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); } } } @@ -1185,25 +1195,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 { @@ -1270,41 +1287,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? @@ -1312,23 +1298,29 @@ 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 n: c_longlong = unsafe { clang_Type_getSizeOf(self.x) }; + match c_ulonglong::try_from(n) { + Ok(size) => Ok(size.try_into().unwrap()), + Err(_) => Err(LayoutError::from(n)), + } + } } } /// 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? @@ -1336,11 +1328,22 @@ 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 n: c_longlong = unsafe { clang_Type_getAlignOf(self.x) }; + match c_ulonglong::try_from(n) { + Ok(alignment) => Ok(alignment.try_into().unwrap()), + Err(_) => Err(LayoutError::from(n)), + } + } } } @@ -1358,13 +1361,14 @@ 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) }; - if n >= 0 { - Some(n as u32) - } else { - debug_assert_eq!(n, -1); - None + pub(crate) fn num_template_args(&self) -> Option { + let n: c_int = unsafe { clang_Type_getNumTemplateArguments(self.x) }; + match c_uint::try_from(n) { + Ok(n) => Some(n), + Err(_) => { + debug_assert_eq!(n, -1, "-1 is the only expected error"); + None + } } } @@ -1382,10 +1386,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() }) @@ -1394,13 +1398,15 @@ 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(()) - } else { - Ok(w as u32) + let n: c_int = clang_getNumArgTypes(self.x); + match c_uint::try_from(n) { + Ok(n) => Some(n), + Err(_) => { + debug_assert_eq!(n, -1, "-1 is the only expected error"); + None + } } } } @@ -1441,11 +1447,13 @@ 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) - } else { - None + let n: c_longlong = unsafe { clang_getNumElements(self.x) }; + match c_ulonglong::try_from(n) { + Ok(n) => Some(n.try_into().unwrap()), + Err(_) => { + debug_assert_eq!(n, -1, "-1 is the only expected error"); + None + } } } @@ -1569,15 +1577,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) }, @@ -1591,7 +1599,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() } } @@ -1613,7 +1621,12 @@ impl SourceLocation { clang_getFileLocation( 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(), + ) } } } @@ -1779,7 +1792,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()), } } } @@ -1833,9 +1846,9 @@ impl TranslationUnit { ix.x, fname.as_ptr(), c_args.as_ptr(), - c_args.len() as c_int, + c_args.len().try_into().unwrap(), c_unsaved.as_mut_ptr(), - c_unsaved.len() as c_uint, + c_unsaved.len().try_into().unwrap(), opts, ) }; @@ -1850,11 +1863,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 @@ -1969,7 +1982,7 @@ impl FallbackTranslationUnit { let ret = unsafe { clang_reparseTranslationUnit( self.tu.x, - unsaved.len() as c_uint, + unsaved.len().try_into().unwrap(), c_unsaved.as_mut_ptr(), clang_defaultReparseOptions(self.tu.x), ) @@ -2037,7 +2050,7 @@ 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().unwrap(), }; UnsavedFile { x, name, contents } } @@ -2114,7 +2127,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() { @@ -2358,22 +2371,13 @@ impl EvalResult { if unsafe { clang_EvalResult_isUnsignedInt(self.x) } != 0 { let value = unsafe { clang_EvalResult_getAsUnsigned(self.x) }; - if value > i64::MAX 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 as c_longlong { - return None; - } - if value < i64::MIN 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 @@ -2430,14 +2434,14 @@ 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)); pointer_width = clang_TargetInfo_getPointerWidth(ti); clang_TargetInfo_dispose(ti); } - assert!(pointer_width > 0); + let pointer_width = c_uint::try_from(pointer_width).unwrap(); assert_eq!(pointer_width % 8, 0); let abi = if triple.contains("msvc") { @@ -2448,7 +2452,7 @@ impl TargetInfo { TargetInfo { triple, - pointer_width: pointer_width as usize, + pointer_width: pointer_width.try_into().unwrap(), abi, } } diff --git a/bindgen/ir/comp.rs b/bindgen/ir/comp.rs index 13a8184fc5..1f5c0ea758 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 field 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; @@ -883,7 +883,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, @@ -905,7 +905,7 @@ impl FieldMethods for FieldData { self.comment.as_deref() } - fn bitfield_width(&self) -> Option { + fn bitfield_width(&self) -> Option { self.bitfield_width } @@ -1842,7 +1842,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;