use quote::TokenStreamExt; use std::io; use std::str::FromStr;
const RUST_DERIVE_FUNPTR_LIMIT: usize = 12;
/// What kind of a function are we looking at? #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub(crate) enum FunctionKind { /// A plain, free function.
Function, /// A method of some kind.
Method(MethodKind),
}
impl FunctionKind { /// Given a clang cursor, return the kind of function it represents, or /// `None` otherwise. pub(crate) fn from_cursor(cursor: &clang::Cursor) -> Option<FunctionKind> { // FIXME(emilio): Deduplicate logic with `ir::comp`.
Some(match cursor.kind() {
clang_sys::CXCursor_FunctionDecl => FunctionKind::Function,
clang_sys::CXCursor_Constructor => {
FunctionKind::Method(MethodKind::Constructor)
}
clang_sys::CXCursor_Destructor => {
FunctionKind::Method(if cursor.method_is_virtual() {
MethodKind::VirtualDestructor {
pure_virtual: cursor.method_is_pure_virtual(),
}
} else {
MethodKind::Destructor
})
}
clang_sys::CXCursor_CXXMethod => { if cursor.method_is_virtual() {
FunctionKind::Method(MethodKind::Virtual {
pure_virtual: cursor.method_is_pure_virtual(),
})
} elseif cursor.method_is_static() {
FunctionKind::Method(MethodKind::Static)
} else {
FunctionKind::Method(MethodKind::Normal)
}
}
_ => return None,
})
}
}
/// The style of linkage #[derive(Debug, Clone, Copy)] pub(crate) enum Linkage { /// Externally visible and can be linked against
External, /// Not exposed externally. 'static inline' functions will have this kind of linkage
Internal,
}
/// A function declaration, with a signature, arguments, and argument names. /// /// The argument names vector must be the same length as the ones in the /// signature. #[derive(Debug)] pub(crate) struct Function { /// The name of this function.
name: String,
/// The mangled name, that is, the symbol.
mangled_name: Option<String>,
/// The link name. If specified, overwrite mangled_name.
link_name: Option<String>,
/// The ID pointing to the current function signature.
signature: TypeId,
/// The kind of function this is.
kind: FunctionKind,
/// The linkage of the function.
linkage: Linkage,
}
impl Function { /// Construct a new function. pub(crate) fn new(
name: String,
mangled_name: Option<String>,
link_name: Option<String>,
signature: TypeId,
kind: FunctionKind,
linkage: Linkage,
) -> Self {
Function {
name,
mangled_name,
link_name,
signature,
kind,
linkage,
}
}
/// Get this function's name. pub(crate) fn name(&self) -> &str {
&self.name
}
/// Get this function's name. pub(crate) fn mangled_name(&self) -> Option<&str> { self.mangled_name.as_deref()
}
/// Get this function's link name. pubfn link_name(&self) -> Option<&str> { self.link_name.as_deref()
}
/// Get this function's signature type. pub(crate) fn signature(&self) -> TypeId { self.signature
}
/// Get this function's kind. pub(crate) fn kind(&self) -> FunctionKind { self.kind
}
/// Get this function's linkage. pub(crate) fn linkage(&self) -> Linkage { self.linkage
}
}
impl DotAttributes for Function { fn dot_attributes<W>(
&self,
_ctx: &BindgenContext,
out: &mut W,
) -> io::Result<()> where
W: io::Write,
{ iflet Some(ref mangled) = self.mangled_name { let mangled: String =
mangled.chars().flat_map(|c| c.escape_default()).collect();
writeln!(
out, "<tr><td>mangled name</td><td>{}</td></tr>",
mangled
)?;
}
Ok(())
}
}
/// A valid rust ABI. #[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)] pubenum Abi { /// The default C ABI.
C, /// The "stdcall" ABI.
Stdcall, /// The "efiapi" ABI.
EfiApi, /// The "fastcall" ABI.
Fastcall, /// The "thiscall" ABI.
ThisCall, /// The "vectorcall" ABI.
Vectorcall, /// The "aapcs" ABI.
Aapcs, /// The "win64" ABI.
Win64, /// The "C-unwind" ABI.
CUnwind, /// The "system" ABI.
System,
}
impl std::fmt::Display for Abi { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let s = match *self { Self::C => "C", Self::Stdcall => "stdcall", Self::EfiApi => "efiapi", Self::Fastcall => "fastcall", Self::ThisCall => "thiscall", Self::Vectorcall => "vectorcall", Self::Aapcs => "aapcs", Self::Win64 => "win64", Self::CUnwind => "C-unwind",
Abi::System => "system",
};
s.fmt(f)
}
}
impl quote::ToTokens for Abi { fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { let abi = self.to_string();
tokens.append_all(quote! { #abi });
}
}
/// An ABI extracted from a clang cursor. #[derive(Debug, Copy, Clone)] pub(crate) enum ClangAbi { /// An ABI known by Rust.
Known(Abi), /// An unknown or invalid ABI.
Unknown(CXCallingConv),
}
impl ClangAbi { /// Returns whether this Abi is known or not. fn is_unknown(&self) -> bool {
matches!(*self, ClangAbi::Unknown(..))
}
}
impl quote::ToTokens for ClangAbi { fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { match *self { Self::Known(abi) => abi.to_tokens(tokens), Self::Unknown(cc) => panic!( "Cannot turn unknown calling convention to tokens: {:?}",
cc
),
}
}
}
/// A function signature. #[derive(Debug)] pub(crate) struct FunctionSig { /// The name of this function signature.
name: String,
/// The return type of the function.
return_type: TypeId,
/// The type of the arguments, optionally with the name of the argument when /// declared.
argument_types: Vec<(Option<String>, TypeId)>,
/// Whether this function is variadic.
is_variadic: bool,
is_divergent: bool,
/// Whether this function's return value must be used.
must_use: bool,
/// Get the mangled name for the cursor's referent. pub(crate) fn cursor_mangling(
ctx: &BindgenContext,
cursor: &clang::Cursor,
) -> Option<String> { if !ctx.options().enable_mangling { return None;
}
// We early return here because libclang may crash in some case // if we pass in a variable inside a partial specialized template. // See rust-lang/rust-bindgen#67, and rust-lang/rust-bindgen#462. if cursor.is_in_non_fully_specialized_template() { return None;
}
let is_itanium_abi = ctx.abi_kind() == ABIKind::GenericItanium; let is_destructor = cursor.kind() == clang_sys::CXCursor_Destructor; iflet Ok(mut manglings) = cursor.cxx_manglings() { whilelet Some(m) = manglings.pop() { // Only generate the destructor group 1, see below. if is_itanium_abi && is_destructor && !m.ends_with("D1Ev") { continue;
}
return Some(m);
}
}
letmut mangling = cursor.mangling(); if mangling.is_empty() { return None;
}
if is_itanium_abi && is_destructor { // With old (3.8-) libclang versions, and the Itanium ABI, clang returns // the "destructor group 0" symbol, which means that it'll try to free // memory, which definitely isn't what we want. // // Explicitly force the destructor group 1 symbol. // // See http://refspecs.linuxbase.org/cxxabi-1.83.html#mangling-special // for the reference, and http://stackoverflow.com/a/6614369/1091587 for // a more friendly explanation. // // We don't need to do this for constructors since clang seems to always // have returned the C1 constructor. // // FIXME(emilio): Can a legit symbol in other ABIs end with this string? // I don't think so, but if it can this would become a linker error // anyway, not an invalid free at runtime. // // TODO(emilio, #611): Use cpp_demangle if this becomes nastier with // time. if mangling.ends_with("D0Ev") { let new_len = mangling.len() - 4;
mangling.truncate(new_len);
mangling.push_str("D1Ev");
}
}
// Argument types can be found in either the cursor or the type, but argument names may only be // found on the cursor. We often have access to both a type and a cursor for each argument, but // in some cases we may only have one. // // Prefer using the type as the source of truth for the argument's type, but fall back to // inspecting the cursor (this happens for Objective C interfaces). // // Prefer using the cursor for the argument's type, but fall back to using the parent's cursor // (this happens for function pointer return types).
cursor_args
.map(Some)
.chain(std::iter::repeat(None))
.zip(type_args.map(Some).chain(std::iter::repeat(None)))
.take_while(|(cur, ty)| cur.is_some() || ty.is_some())
.map(|(arg_cur, arg_ty)| { let name = arg_cur.map(|a| a.spelling()).and_then(|name| { if name.is_empty() {
None
} else {
Some(name)
}
});
let cursor = arg_cur.unwrap_or(*cursor); let ty = arg_ty.unwrap_or_else(|| cursor.cur_type());
(name, Item::from_ty_or_ref(ty, cursor, None, ctx))
})
.collect()
}
impl FunctionSig { /// Get the function name. pub(crate) fn name(&self) -> &str {
&self.name
}
/// Construct a new function signature from the given Clang type. pub(crate) fn from_ty(
ty: &clang::Type,
cursor: &clang::Cursor,
ctx: &mut BindgenContext,
) -> Result<Self, ParseError> { use clang_sys::*;
debug!("FunctionSig::from_ty {:?} {:?}", ty, cursor);
// Skip function templates let kind = cursor.kind(); if kind == CXCursor_FunctionTemplate { return Err(ParseError::Continue);
}
let spelling = cursor.spelling();
// Don't parse operatorxx functions in C++ let is_operator = |spelling: &str| {
spelling.starts_with("operator") &&
!clang::is_valid_identifier(spelling)
}; if is_operator(&spelling) { return Err(ParseError::Continue);
}
// Constructors of non-type template parameter classes for some reason // include the template parameter in their name. Just skip them, since // we don't handle well non-type template parameters anyway. if (kind == CXCursor_Constructor || kind == CXCursor_Destructor) &&
spelling.contains('<')
{ return Err(ParseError::Continue);
}
let cursor = if cursor.is_valid() {
*cursor
} else {
ty.declaration()
};
letmut args = match kind {
CXCursor_FunctionDecl |
CXCursor_Constructor |
CXCursor_CXXMethod |
CXCursor_ObjCInstanceMethodDecl |
CXCursor_ObjCClassMethodDecl => {
args_from_ty_and_cursor(ty, &cursor, ctx)
}
_ => { // For non-CXCursor_FunctionDecl, visiting the cursor's children // is the only reliable way to get parameter names. letmut args = vec![];
cursor.visit(|c| { if c.kind() == CXCursor_ParmDecl { let ty =
Item::from_ty_or_ref(c.cur_type(), c, None, ctx); let name = c.spelling(); let name = if name.is_empty() { None } else { Some(name) };
args.push((name, ty));
}
CXChildVisit_Continue
});
if args.is_empty() { // FIXME(emilio): Sometimes libclang doesn't expose the // right AST for functions tagged as stdcall and such... // // https://bugs.llvm.org/show_bug.cgi?id=45919
args_from_ty_and_cursor(ty, &cursor, ctx)
} else {
args
}
}
};
let (must_use, mut is_divergent) = if ctx.options().enable_function_attribute_detection { let [must_use, no_return, no_return_cpp] = cursor.has_attrs(&[
Attribute::MUST_USE,
Attribute::NO_RETURN,
Attribute::NO_RETURN_CPP,
]);
(must_use, no_return || no_return_cpp)
} else {
Default::default()
};
// Check if the type contains __attribute__((noreturn)) outside of parentheses. This is // somewhat fragile, but it seems to be the only way to get at this information as of // libclang 9. let ty_spelling = ty.spelling(); let has_attribute_noreturn = ty_spelling
.match_indices("__attribute__((noreturn))")
.any(|(i, _)| { let depth = ty_spelling[..i]
.bytes()
.filter_map(|ch| match ch {
b'(' => Some(1),
b')' => Some(-1),
_ => None,
})
.sum::<isize>();
depth == 0
});
is_divergent = is_divergent || has_attribute_noreturn;
let is_method = kind == CXCursor_CXXMethod; let is_constructor = kind == CXCursor_Constructor; let is_destructor = kind == CXCursor_Destructor; if (is_constructor || is_destructor || is_method) &&
cursor.lexical_parent() != cursor.semantic_parent()
{ // Only parse constructors once. return Err(ParseError::Continue);
}
if is_method || is_constructor || is_destructor { let is_const = is_method && cursor.method_is_const(); let is_virtual = is_method && cursor.method_is_virtual(); let is_static = is_method && cursor.method_is_static(); if !is_static && !is_virtual { let parent = cursor.semantic_parent(); let class = Item::parse(parent, None, ctx)
.expect("Expected to parse the class"); // The `class` most likely is not finished parsing yet, so use // the unchecked variant. let class = class.as_type_id_unchecked();
let class = if is_const { let const_class_id = ctx.next_item_id();
ctx.build_const_wrapper(
const_class_id,
class,
None,
&parent.cur_type(),
)
} else {
class
};
let ptr =
Item::builtin_type(TypeKind::Pointer(class), false, ctx);
args.insert(0, (Some("this".into()), ptr));
} elseif is_virtual { let void = Item::builtin_type(TypeKind::Void, false, ctx); let ptr =
Item::builtin_type(TypeKind::Pointer(void), false, ctx);
args.insert(0, (Some("this".into()), ptr));
}
}
let ret = if is_constructor && ctx.is_target_wasm32() { // Constructors in Clang wasm32 target return a pointer to the object // being constructed. let void = Item::builtin_type(TypeKind::Void, false, ctx);
Item::builtin_type(TypeKind::Pointer(void), false, ctx)
} else {
Item::from_ty_or_ref(ty_ret_type, cursor, None, ctx)
};
// Clang plays with us at "find the calling convention", see #549 and // co. This seems to be a better fix than that commit. letmut call_conv = ty.call_conv(); iflet Some(ty) = cursor.cur_type().canonical_type().pointee_type() { let cursor_call_conv = ty.call_conv(); if cursor_call_conv != CXCallingConv_Invalid {
call_conv = cursor_call_conv;
}
}
let abi = get_abi(call_conv);
if abi.is_unknown() {
warn!("Unknown calling convention: {:?}", call_conv);
}
/// Get this function signature's return type. pub(crate) fn return_type(&self) -> TypeId { self.return_type
}
/// Get this function signature's argument (name, type) pairs. pub(crate) fn argument_types(&self) -> &[(Option<String>, TypeId)] {
&self.argument_types
}
/// Get this function signature's ABI. pub(crate) fn abi(
&self,
ctx: &BindgenContext,
name: Option<&str>,
) -> crate::codegen::error::Result<ClangAbi> { // FIXME (pvdrz): Try to do this check lazily instead. Maybe store the ABI inside `ctx` // instead?. let abi = iflet Some(name) = name { iflet Some((abi, _)) = ctx
.options()
.abi_overrides
.iter()
.find(|(_, regex_set)| regex_set.matches(name))
{
ClangAbi::Known(*abi)
} else { self.abi
}
} elseiflet Some((abi, _)) = ctx
.options()
.abi_overrides
.iter()
.find(|(_, regex_set)| regex_set.matches(&self.name))
{
ClangAbi::Known(*abi)
} else { self.abi
};
match abi {
ClangAbi::Known(Abi::ThisCall) if !ctx.options().rust_features().thiscall_abi =>
{
Err(crate::codegen::error::Error::UnsupportedAbi("thiscall"))
}
ClangAbi::Known(Abi::Vectorcall) if !ctx.options().rust_features().vectorcall_abi =>
{
Err(crate::codegen::error::Error::UnsupportedAbi("vectorcall"))
}
ClangAbi::Known(Abi::CUnwind) if !ctx.options().rust_features().c_unwind_abi =>
{
Err(crate::codegen::error::Error::UnsupportedAbi("C-unwind"))
}
ClangAbi::Known(Abi::EfiApi) if !ctx.options().rust_features().abi_efiapi =>
{
Err(crate::codegen::error::Error::UnsupportedAbi("efiapi"))
}
ClangAbi::Known(Abi::Win64) ifself.is_variadic() => {
Err(crate::codegen::error::Error::UnsupportedAbi("Win64"))
}
abi => Ok(abi),
}
}
/// Is this function signature variadic? pub(crate) fn is_variadic(&self) -> bool { // Clang reports some functions as variadic when they *might* be // variadic. We do the argument check because rust doesn't codegen well // variadic functions without an initial argument. self.is_variadic && !self.argument_types.is_empty()
}
/// Must this function's return value be used? pub(crate) fn must_use(&self) -> bool { self.must_use
}
/// Whether this function has attributes marking it as divergent. pub(crate) fn is_divergent(&self) -> bool { self.is_divergent
}
}
impl ClangSubItemParser for Function { fn parse(
cursor: clang::Cursor,
context: &mut BindgenContext,
) -> Result<ParseResult<Self>, ParseError> { use clang_sys::*;
let kind = match FunctionKind::from_cursor(&cursor) {
None => return Err(ParseError::Continue),
Some(k) => k,
};
debug!("Function::parse({:?}, {:?})", cursor, cursor.cur_type()); let visibility = cursor.visibility(); if visibility != CXVisibility_Default { return Err(ParseError::Continue);
}
if cursor.access_specifier() == CX_CXXPrivate { return Err(ParseError::Continue);
}
let linkage = cursor.linkage(); let linkage = match linkage {
CXLinkage_External | CXLinkage_UniqueExternal => Linkage::External,
CXLinkage_Internal => Linkage::Internal,
_ => return Err(ParseError::Continue),
};
if cursor.is_inlined_function() ||
cursor
.definition()
.map_or(false, |x| x.is_inlined_function())
{ if !context.options().generate_inline_functions &&
!context.options().wrap_static_fns
{ return Err(ParseError::Continue);
}
if cursor.is_deleted_function() { return Err(ParseError::Continue);
}
// We cannot handle `inline` functions that are not `static`. if context.options().wrap_static_fns &&
cursor.is_inlined_function() &&
matches!(linkage, Linkage::External)
{ return Err(ParseError::Continue);
}
}
// Grab the signature using Item::from_ty. let sig = Item::from_ty(&cursor.cur_type(), cursor, None, context)?;
letmut name = cursor.spelling();
assert!(!name.is_empty(), "Empty function name?");
if cursor.kind() == CXCursor_Destructor { // Remove the leading `~`. The alternative to this is special-casing // code-generation for destructor functions, which seems less than // ideal. if name.starts_with('~') {
name.remove(0);
}
// Add a suffix to avoid colliding with constructors. This would be // technically fine (since we handle duplicated functions/methods), // but seems easy enough to handle it here.
name.push_str("_destructor");
} iflet Some(nm) = context.options().last_callback(|callbacks| {
callbacks.generated_name_override(ItemInfo {
name: name.as_str(),
kind: ItemKind::Function,
})
}) {
name = nm;
}
assert!(!name.is_empty(), "Empty function name.");
let mangled_name = cursor_mangling(context, &cursor);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.