Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  function.rs   Sprache: unbekannt

 
//! Intermediate representation for C/C++ functions and methods.

use super::comp::MethodKind;
use super::context::{BindgenContext, TypeId};
use super::dot::DotAttributes;
use super::item::Item;
use super::traversal::{EdgeKind, Trace, Tracer};
use super::ty::TypeKind;
use crate::callbacks::{ItemInfo, ItemKind};
use crate::clang::{self, ABIKind, Attribute};
use crate::parse::{ClangSubItemParser, ParseError, ParseResult};
use clang_sys::{self, CXCallingConv};

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(),
                    })
                } else if 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.
    pub fn 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,
    {
        if let 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)]
pub enum 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 FromStr for Abi {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "C" => Ok(Self::C),
            "stdcall" => Ok(Self::Stdcall),
            "efiapi" => Ok(Self::EfiApi),
            "fastcall" => Ok(Self::Fastcall),
            "thiscall" => Ok(Self::ThisCall),
            "vectorcall" => Ok(Self::Vectorcall),
            "aapcs" => Ok(Self::Aapcs),
            "win64" => Ok(Self::Win64),
            "C-unwind" => Ok(Self::CUnwind),
            "system" => Ok(Self::System),
            _ => Err(format!("Invalid or unknown ABI {:?}", s)),
        }
    }
}

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,

    /// The ABI of this function.
    abi: ClangAbi,
}

fn get_abi(cc: CXCallingConv) -> ClangAbi {
    use clang_sys::*;
    match cc {
        CXCallingConv_Default => ClangAbi::Known(Abi::C),
        CXCallingConv_C => ClangAbi::Known(Abi::C),
        CXCallingConv_X86StdCall => ClangAbi::Known(Abi::Stdcall),
        CXCallingConv_X86FastCall => ClangAbi::Known(Abi::Fastcall),
        CXCallingConv_X86ThisCall => ClangAbi::Known(Abi::ThisCall),
        CXCallingConv_X86VectorCall => ClangAbi::Known(Abi::Vectorcall),
        CXCallingConv_AAPCS => ClangAbi::Known(Abi::Aapcs),
        CXCallingConv_X86_64Win64 => ClangAbi::Known(Abi::Win64),
        CXCallingConv_AArch64VectorCall => ClangAbi::Known(Abi::Vectorcall),
        other => ClangAbi::Unknown(other),
    }
}

/// 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;
    if let Ok(mut manglings) = cursor.cxx_manglings() {
        while let 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);
        }
    }

    let mut 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");
        }
    }

    Some(mangling)
}

fn args_from_ty_and_cursor(
    ty: &clang::Type,
    cursor: &clang::Cursor,
    ctx: &mut BindgenContext,
) -> Vec<(Option<String>, TypeId)> {
    let cursor_args = cursor.args().unwrap_or_default().into_iter();
    let type_args = ty.args().unwrap_or_default().into_iter();

    // 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()
        };

        let mut 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.
                let mut 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));
            } else if 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 ty_ret_type = if kind == CXCursor_ObjCInstanceMethodDecl ||
            kind == CXCursor_ObjCClassMethodDecl
        {
            ty.ret_type()
                .or_else(|| cursor.ret_type())
                .ok_or(ParseError::Continue)?
        } else {
            ty.ret_type().ok_or(ParseError::Continue)?
        };

        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.
        let mut call_conv = ty.call_conv();
        if let 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);
        }

        Ok(Self {
            name: spelling,
            return_type: ret,
            argument_types: args,
            is_variadic: ty.is_variadic(),
            is_divergent,
            must_use,
            abi,
        })
    }

    /// 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 = if let Some(name) = name {
            if let Some((abi, _)) = ctx
                .options()
                .abi_overrides
                .iter()
                .find(|(_, regex_set)| regex_set.matches(name))
            {
                ClangAbi::Known(*abi)
            } else {
                self.abi
            }
        } else if let 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) if self.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
    }

    /// Are function pointers with this signature able to derive Rust traits?
    /// Rust only supports deriving traits for function pointers with a limited
    /// number of parameters and a couple ABIs.
    ///
    /// For more details, see:
    ///
    /// * <https://github.com/rust-lang/rust-bindgen/issues/547>,
    /// * <https://github.com/rust-lang/rust/issues/38848>,
    /// * and <https://github.com/rust-lang/rust/issues/40158>
    pub(crate) fn function_pointers_can_derive(&self) -> bool {
        if self.argument_types.len() > RUST_DERIVE_FUNPTR_LIMIT {
            return false;
        }

        matches!(self.abi, ClangAbi::Known(Abi::C) | ClangAbi::Unknown(..))
    }

    /// 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)?;

        let mut 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");
        }
        if let 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);

        let link_name = context.options().last_callback(|callbacks| {
            callbacks.generated_link_name_override(ItemInfo {
                name: name.as_str(),
                kind: ItemKind::Function,
            })
        });

        let function = Self::new(
            name.clone(),
            mangled_name,
            link_name,
            sig,
            kind,
            linkage,
        );

        Ok(ParseResult::New(function, Some(cursor)))
    }
}

impl Trace for FunctionSig {
    type Extra = ();

    fn trace<T>(&self, _: &BindgenContext, tracer: &mut T, _: &())
    where
        T: Tracer,
    {
        tracer.visit_kind(self.return_type().into(), EdgeKind::FunctionReturn);

        for &(_, ty) in self.argument_types() {
            tracer.visit_kind(ty.into(), EdgeKind::FunctionParameter);
        }
    }
}

[ Dauer der Verarbeitung: 0.40 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge