1use super::comp::{MethodKind, SpecialMemberKind};
4use super::context::{BindgenContext, TypeId};
5use super::dot::DotAttributes;
6use super::item::Item;
7use super::traversal::{EdgeKind, Trace, Tracer};
8use super::ty::TypeKind;
9use crate::callbacks::{ItemInfo, ItemKind};
10use crate::clang::{self, ABIKind, Attribute};
11use crate::parse::{ClangSubItemParser, ParseError, ParseResult};
12use clang_sys::{
13 CXCallingConv, CX_CXXAccessSpecifier, CX_CXXPrivate, CX_CXXProtected,
14};
15
16use quote::TokenStreamExt;
17use std::io;
18use std::str::FromStr;
19
20const RUST_DERIVE_FUNPTR_LIMIT: usize = 12;
21
22#[derive(Debug, Copy, Clone, PartialEq, Eq)]
24pub(crate) enum FunctionKind {
25 Function,
27 Method(MethodKind),
29}
30
31impl FunctionKind {
32 pub(crate) fn from_cursor(cursor: &clang::Cursor) -> Option<FunctionKind> {
35 Some(match cursor.kind() {
37 clang_sys::CXCursor_FunctionDecl => FunctionKind::Function,
38 clang_sys::CXCursor_Constructor => {
39 FunctionKind::Method(MethodKind::Constructor)
40 }
41 clang_sys::CXCursor_Destructor => {
42 FunctionKind::Method(if cursor.method_is_virtual() {
43 MethodKind::VirtualDestructor {
44 pure_virtual: cursor.method_is_pure_virtual(),
45 }
46 } else {
47 MethodKind::Destructor
48 })
49 }
50 clang_sys::CXCursor_CXXMethod => {
51 if cursor.method_is_virtual() {
52 FunctionKind::Method(MethodKind::Virtual {
53 pure_virtual: cursor.method_is_pure_virtual(),
54 })
55 } else if cursor.method_is_static() {
56 FunctionKind::Method(MethodKind::Static)
57 } else {
58 FunctionKind::Method(MethodKind::Normal)
59 }
60 }
61 _ => return None,
62 })
63 }
64}
65
66#[derive(Debug, Clone, Copy)]
68pub(crate) enum Linkage {
69 External,
71 Internal,
73}
74
75#[derive(Debug, Clone, Copy)]
77pub enum Visibility {
78 Public,
80 Protected,
82 Private,
84}
85
86impl From<CX_CXXAccessSpecifier> for Visibility {
87 fn from(access_specifier: CX_CXXAccessSpecifier) -> Self {
88 if access_specifier == CX_CXXPrivate {
89 Visibility::Private
90 } else if access_specifier == CX_CXXProtected {
91 Visibility::Protected
92 } else {
93 Visibility::Public
94 }
95 }
96}
97
98#[derive(Debug)]
100pub(crate) struct AutocxxFuncInfo {
101 special_member: Option<SpecialMemberKind>,
103 visibility: Visibility,
105 is_deleted: bool,
107 is_defaulted: bool,
109}
110
111impl AutocxxFuncInfo {
112 fn new(
113 special_member: Option<SpecialMemberKind>,
114 visibility: Visibility,
115 is_deleted: bool,
116 is_defaulted: bool,
117 ) -> Self {
118 Self {
119 special_member,
120 visibility,
121 is_deleted,
122 is_defaulted,
123 }
124 }
125
126 pub fn special_member(&self) -> Option<SpecialMemberKind> {
128 self.special_member
129 }
130
131 pub fn visibility(&self) -> Visibility {
133 self.visibility
134 }
135
136 pub fn deleted_fn(&self) -> bool {
138 self.is_deleted
139 }
140
141 pub fn defaulted_fn(&self) -> bool {
143 self.is_defaulted
144 }
145}
146
147#[derive(Debug)]
152pub(crate) struct Function {
153 name: String,
155
156 mangled_name: Option<String>,
158
159 link_name: Option<String>,
161
162 signature: TypeId,
164
165 kind: FunctionKind,
167
168 linkage: Linkage,
170
171 autocxx: AutocxxFuncInfo,
173}
174
175impl Function {
176 pub(crate) fn new(
178 name: String,
179 mangled_name: Option<String>,
180 link_name: Option<String>,
181 signature: TypeId,
182 kind: FunctionKind,
183 linkage: Linkage,
184 autocxx: AutocxxFuncInfo,
185 ) -> Self {
186 Function {
187 name,
188 mangled_name,
189 link_name,
190 signature,
191 kind,
192 linkage,
193 autocxx,
194 }
195 }
196
197 pub(crate) fn name(&self) -> &str {
199 &self.name
200 }
201
202 pub(crate) fn mangled_name(&self) -> Option<&str> {
204 self.mangled_name.as_deref()
205 }
206
207 pub fn link_name(&self) -> Option<&str> {
209 self.link_name.as_deref()
210 }
211
212 pub(crate) fn signature(&self) -> TypeId {
214 self.signature
215 }
216
217 pub(crate) fn kind(&self) -> FunctionKind {
219 self.kind
220 }
221
222 pub(crate) fn linkage(&self) -> Linkage {
224 self.linkage
225 }
226
227 pub fn special_member(&self) -> Option<SpecialMemberKind> {
229 self.autocxx.special_member()
230 }
231
232 pub fn visibility(&self) -> Visibility {
234 self.autocxx.visibility()
235 }
236
237 pub fn deleted_fn(&self) -> bool {
239 self.autocxx.deleted_fn()
240 }
241
242 pub fn defaulted_fn(&self) -> bool {
244 self.autocxx.defaulted_fn()
245 }
246}
247
248impl DotAttributes for Function {
249 fn dot_attributes<W>(
250 &self,
251 _ctx: &BindgenContext,
252 out: &mut W,
253 ) -> io::Result<()>
254 where
255 W: io::Write,
256 {
257 if let Some(ref mangled) = self.mangled_name {
258 let mangled: String =
259 mangled.chars().flat_map(|c| c.escape_default()).collect();
260 writeln!(out, "<tr><td>mangled name</td><td>{mangled}</td></tr>")?;
261 }
262
263 Ok(())
264 }
265}
266
267#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
269pub enum Abi {
270 C,
272 Stdcall,
274 EfiApi,
276 Fastcall,
278 ThisCall,
280 Vectorcall,
282 Aapcs,
284 Win64,
286 CUnwind,
288 System,
290}
291
292impl FromStr for Abi {
293 type Err = String;
294
295 fn from_str(s: &str) -> Result<Self, Self::Err> {
296 match s {
297 "C" => Ok(Self::C),
298 "stdcall" => Ok(Self::Stdcall),
299 "efiapi" => Ok(Self::EfiApi),
300 "fastcall" => Ok(Self::Fastcall),
301 "thiscall" => Ok(Self::ThisCall),
302 "vectorcall" => Ok(Self::Vectorcall),
303 "aapcs" => Ok(Self::Aapcs),
304 "win64" => Ok(Self::Win64),
305 "C-unwind" => Ok(Self::CUnwind),
306 "system" => Ok(Self::System),
307 _ => Err(format!("Invalid or unknown ABI {s:?}")),
308 }
309 }
310}
311
312impl std::fmt::Display for Abi {
313 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
314 let s = match *self {
315 Self::C => "C",
316 Self::Stdcall => "stdcall",
317 Self::EfiApi => "efiapi",
318 Self::Fastcall => "fastcall",
319 Self::ThisCall => "thiscall",
320 Self::Vectorcall => "vectorcall",
321 Self::Aapcs => "aapcs",
322 Self::Win64 => "win64",
323 Self::CUnwind => "C-unwind",
324 Abi::System => "system",
325 };
326
327 s.fmt(f)
328 }
329}
330
331impl quote::ToTokens for Abi {
332 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
333 let abi = self.to_string();
334 tokens.append_all(quote! { #abi });
335 }
336}
337
338#[derive(Debug, Copy, Clone)]
340pub(crate) enum ClangAbi {
341 Known(Abi),
343 Unknown(CXCallingConv),
345}
346
347impl ClangAbi {
348 fn is_unknown(self) -> bool {
350 matches!(self, ClangAbi::Unknown(..))
351 }
352}
353
354impl quote::ToTokens for ClangAbi {
355 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
356 match *self {
357 Self::Known(abi) => abi.to_tokens(tokens),
358 Self::Unknown(cc) => panic!(
359 "Cannot turn unknown calling convention to tokens: {cc:?}"
360 ),
361 }
362 }
363}
364
365#[derive(Debug)]
367pub(crate) struct FunctionSig {
368 name: String,
370
371 return_type: TypeId,
373
374 argument_types: Vec<(Option<String>, TypeId)>,
377
378 is_variadic: bool,
380 is_divergent: bool,
381
382 must_use: bool,
384
385 abi: ClangAbi,
387}
388
389fn get_abi(cc: CXCallingConv) -> ClangAbi {
390 use clang_sys::*;
391 match cc {
392 CXCallingConv_Default | CXCallingConv_C => ClangAbi::Known(Abi::C),
393 CXCallingConv_X86StdCall => ClangAbi::Known(Abi::Stdcall),
394 CXCallingConv_X86FastCall => ClangAbi::Known(Abi::Fastcall),
395 CXCallingConv_X86ThisCall => ClangAbi::Known(Abi::ThisCall),
396 CXCallingConv_X86VectorCall | CXCallingConv_AArch64VectorCall => {
397 ClangAbi::Known(Abi::Vectorcall)
398 }
399 CXCallingConv_AAPCS => ClangAbi::Known(Abi::Aapcs),
400 CXCallingConv_X86_64Win64 => ClangAbi::Known(Abi::Win64),
401 other => ClangAbi::Unknown(other),
402 }
403}
404
405pub(crate) fn cursor_mangling(
407 ctx: &BindgenContext,
408 cursor: &clang::Cursor,
409) -> Option<String> {
410 if !ctx.options().enable_mangling {
411 return None;
412 }
413
414 if cursor.is_in_non_fully_specialized_template() {
418 return None;
419 }
420
421 let is_itanium_abi = ctx.abi_kind() == ABIKind::GenericItanium;
422 let is_destructor = cursor.kind() == clang_sys::CXCursor_Destructor;
423 if let Ok(mut manglings) = cursor.cxx_manglings() {
424 while let Some(m) = manglings.pop() {
425 if is_itanium_abi && is_destructor && !m.ends_with("D1Ev") {
427 continue;
428 }
429
430 return Some(m);
431 }
432 }
433
434 let mut mangling = cursor.mangling();
435 if mangling.is_empty() {
436 return None;
437 }
438
439 if is_itanium_abi && is_destructor {
440 if mangling.ends_with("D0Ev") {
460 let new_len = mangling.len() - 4;
461 mangling.truncate(new_len);
462 mangling.push_str("D1Ev");
463 }
464 }
465
466 Some(mangling)
467}
468
469fn args_from_ty_and_cursor(
470 ty: &clang::Type,
471 cursor: &clang::Cursor,
472 ctx: &mut BindgenContext,
473) -> Vec<(Option<String>, TypeId)> {
474 let cursor_args = cursor.args().unwrap_or_default().into_iter();
475 let type_args = ty.args().unwrap_or_default().into_iter();
476
477 cursor_args
487 .map(Some)
488 .chain(std::iter::repeat(None))
489 .zip(type_args.map(Some).chain(std::iter::repeat(None)))
490 .take_while(|(cur, ty)| cur.is_some() || ty.is_some())
491 .map(|(arg_cur, arg_ty)| {
492 let name = arg_cur.map(|a| a.spelling()).and_then(|name| {
493 if name.is_empty() {
494 None
495 } else {
496 Some(name)
497 }
498 });
499
500 let cursor = arg_cur.unwrap_or(*cursor);
501 let ty = arg_ty.unwrap_or_else(|| cursor.cur_type());
502 (name, Item::from_ty_or_ref(ty, cursor, None, ctx))
503 })
504 .collect()
505}
506
507impl FunctionSig {
508 pub(crate) fn name(&self) -> &str {
510 &self.name
511 }
512
513 pub(crate) fn from_ty(
515 ty: &clang::Type,
516 cursor: &clang::Cursor,
517 ctx: &mut BindgenContext,
518 ) -> Result<Self, ParseError> {
519 use clang_sys::*;
520 debug!("FunctionSig::from_ty {ty:?} {cursor:?}");
521
522 let kind = cursor.kind();
524 if kind == CXCursor_FunctionTemplate {
525 return Err(ParseError::Continue);
526 }
527
528 let spelling = cursor.spelling();
529
530 let is_operator = |spelling: &str| {
532 spelling.starts_with("operator") &&
533 !clang::is_valid_identifier(spelling)
534 };
535 if is_operator(&spelling) && !ctx.options().represent_cxx_operators {
536 return Err(ParseError::Continue);
537 }
538
539 if (kind == CXCursor_Constructor || kind == CXCursor_Destructor) &&
543 spelling.contains('<')
544 {
545 return Err(ParseError::Continue);
546 }
547
548 let cursor = if cursor.is_valid() {
549 *cursor
550 } else {
551 ty.declaration()
552 };
553
554 let mut args = match kind {
555 CXCursor_FunctionDecl |
556 CXCursor_Constructor |
557 CXCursor_CXXMethod |
558 CXCursor_ObjCInstanceMethodDecl |
559 CXCursor_ObjCClassMethodDecl => {
560 args_from_ty_and_cursor(ty, &cursor, ctx)
561 }
562 _ => {
563 let mut args = vec![];
566 cursor.visit(|c| {
567 if c.kind() == CXCursor_ParmDecl {
568 let ty =
569 Item::from_ty_or_ref(c.cur_type(), c, None, ctx);
570 let name = c.spelling();
571 let name =
572 if name.is_empty() { None } else { Some(name) };
573 args.push((name, ty));
574 }
575 CXChildVisit_Continue
576 });
577
578 if args.is_empty() {
579 args_from_ty_and_cursor(ty, &cursor, ctx)
584 } else {
585 args
586 }
587 }
588 };
589
590 let (must_use, mut is_divergent) =
591 if ctx.options().enable_function_attribute_detection {
592 let [must_use, no_return, no_return_cpp] = cursor.has_attrs(&[
593 Attribute::MUST_USE,
594 Attribute::NO_RETURN,
595 Attribute::NO_RETURN_CPP,
596 ]);
597 (must_use, no_return || no_return_cpp)
598 } else {
599 Default::default()
600 };
601
602 let ty_spelling = ty.spelling();
606 let has_attribute_noreturn = ty_spelling
607 .match_indices("__attribute__((noreturn))")
608 .any(|(i, _)| {
609 let depth = ty_spelling[..i]
610 .bytes()
611 .filter_map(|ch| match ch {
612 b'(' => Some(1),
613 b')' => Some(-1),
614 _ => None,
615 })
616 .sum::<isize>();
617 depth == 0
618 });
619 is_divergent = is_divergent || has_attribute_noreturn;
620
621 let is_method = kind == CXCursor_CXXMethod;
622 let is_constructor = kind == CXCursor_Constructor;
623 let is_destructor = kind == CXCursor_Destructor;
624 if (is_constructor || is_destructor || is_method) &&
625 cursor.lexical_parent() != cursor.semantic_parent()
626 {
627 return Err(ParseError::Continue);
629 }
630
631 if is_method || is_constructor || is_destructor {
632 let is_const = is_method && cursor.method_is_const();
633 let is_virtual = is_method && cursor.method_is_virtual();
634 let is_static = is_method && cursor.method_is_static();
635 if !is_static &&
636 (!is_virtual ||
637 ctx.options().use_specific_virtual_function_receiver)
638 {
639 let parent = cursor.semantic_parent();
640 let class = Item::parse(parent, None, ctx)
641 .expect("Expected to parse the class");
642 let class = class.as_type_id_unchecked();
645
646 let class = if is_const {
647 let const_class_id = ctx.next_item_id();
648 ctx.build_const_wrapper(
649 const_class_id,
650 class,
651 None,
652 &parent.cur_type(),
653 )
654 } else {
655 class
656 };
657
658 let ptr =
659 Item::builtin_type(TypeKind::Pointer(class), false, ctx);
660 args.insert(0, (Some("this".into()), ptr));
661 } else if is_virtual {
662 let void = Item::builtin_type(TypeKind::Void, is_const, ctx);
663 let ptr =
664 Item::builtin_type(TypeKind::Pointer(void), false, ctx);
665 args.insert(0, (Some("this".into()), ptr));
666 }
667 }
668
669 let ty_ret_type = if kind == CXCursor_ObjCInstanceMethodDecl ||
670 kind == CXCursor_ObjCClassMethodDecl
671 {
672 ty.ret_type()
673 .or_else(|| cursor.ret_type())
674 .ok_or(ParseError::Continue)?
675 } else {
676 ty.ret_type().ok_or(ParseError::Continue)?
677 };
678
679 let ret = if is_constructor && ctx.is_target_wasm32() {
680 let void = Item::builtin_type(TypeKind::Void, false, ctx);
683 Item::builtin_type(TypeKind::Pointer(void), false, ctx)
684 } else {
685 Item::from_ty_or_ref(ty_ret_type, cursor, None, ctx)
686 };
687
688 let mut call_conv = ty.call_conv();
691 if let Some(ty) = cursor.cur_type().canonical_type().pointee_type() {
692 let cursor_call_conv = ty.call_conv();
693 if cursor_call_conv != CXCallingConv_Invalid {
694 call_conv = cursor_call_conv;
695 }
696 }
697
698 let abi = get_abi(call_conv);
699
700 if abi.is_unknown() {
701 warn!("Unknown calling convention: {call_conv:?}");
702 }
703
704 Ok(Self {
705 name: spelling,
706 return_type: ret,
707 argument_types: args,
708 is_variadic: ty.is_variadic(),
709 is_divergent,
710 must_use,
711 abi,
712 })
713 }
714
715 pub(crate) fn return_type(&self) -> TypeId {
717 self.return_type
718 }
719
720 pub(crate) fn argument_types(&self) -> &[(Option<String>, TypeId)] {
722 &self.argument_types
723 }
724
725 pub(crate) fn abi(
727 &self,
728 ctx: &BindgenContext,
729 name: Option<&str>,
730 ) -> crate::codegen::error::Result<ClangAbi> {
731 let abi = if let Some(name) = name {
734 if let Some((abi, _)) = ctx
735 .options()
736 .abi_overrides
737 .iter()
738 .find(|(_, regex_set)| regex_set.matches(name))
739 {
740 ClangAbi::Known(*abi)
741 } else {
742 self.abi
743 }
744 } else if let Some((abi, _)) = ctx
745 .options()
746 .abi_overrides
747 .iter()
748 .find(|(_, regex_set)| regex_set.matches(&self.name))
749 {
750 ClangAbi::Known(*abi)
751 } else {
752 self.abi
753 };
754
755 match abi {
756 ClangAbi::Known(Abi::ThisCall)
757 if !ctx.options().rust_features().thiscall_abi =>
758 {
759 Err(crate::codegen::error::Error::UnsupportedAbi("thiscall"))
760 }
761 ClangAbi::Known(Abi::Vectorcall)
762 if !ctx.options().rust_features().vectorcall_abi =>
763 {
764 Err(crate::codegen::error::Error::UnsupportedAbi("vectorcall"))
765 }
766 ClangAbi::Known(Abi::CUnwind)
767 if !ctx.options().rust_features().c_unwind_abi =>
768 {
769 Err(crate::codegen::error::Error::UnsupportedAbi("C-unwind"))
770 }
771 ClangAbi::Known(Abi::EfiApi)
772 if !ctx.options().rust_features().abi_efiapi =>
773 {
774 Err(crate::codegen::error::Error::UnsupportedAbi("efiapi"))
775 }
776 ClangAbi::Known(Abi::Win64) if self.is_variadic() => {
777 Err(crate::codegen::error::Error::UnsupportedAbi("Win64"))
778 }
779 abi => Ok(abi),
780 }
781 }
782
783 pub(crate) fn is_variadic(&self) -> bool {
785 self.is_variadic && !self.argument_types.is_empty()
789 }
790
791 pub(crate) fn must_use(&self) -> bool {
793 self.must_use
794 }
795
796 pub(crate) fn function_pointers_can_derive(&self) -> bool {
806 if self.argument_types.len() > RUST_DERIVE_FUNPTR_LIMIT {
807 return false;
808 }
809
810 matches!(self.abi, ClangAbi::Known(Abi::C) | ClangAbi::Unknown(..))
811 }
812
813 pub(crate) fn is_divergent(&self) -> bool {
815 self.is_divergent
816 }
817}
818
819impl ClangSubItemParser for Function {
820 fn parse(
821 cursor: clang::Cursor,
822 context: &mut BindgenContext,
823 ) -> Result<ParseResult<Self>, ParseError> {
824 use clang_sys::*;
825
826 let kind = match FunctionKind::from_cursor(&cursor) {
827 None => return Err(ParseError::Continue),
828 Some(k) => k,
829 };
830
831 debug!("Function::parse({cursor:?}, {:?})", cursor.cur_type());
832 let visibility = cursor.visibility();
833 if visibility != CXVisibility_Default {
834 return Err(ParseError::Continue);
835 }
836 if cursor.access_specifier() == CX_CXXPrivate && !context.options().generate_private_functions {
837 return Err(ParseError::Continue);
838 }
839
840 let visibility = Visibility::from(cursor.access_specifier());
841
842 let linkage = cursor.linkage();
843 let linkage = match linkage {
844 CXLinkage_External | CXLinkage_UniqueExternal => Linkage::External,
845 CXLinkage_Internal => Linkage::Internal,
846 _ => return Err(ParseError::Continue),
847 };
848
849 if cursor.is_inlined_function() ||
850 cursor.definition().is_some_and(|x| x.is_inlined_function())
851 {
852 if !context.options().generate_inline_functions &&
853 !context.options().wrap_static_fns
854 {
855 return Err(ParseError::Continue);
856 }
857
858 if cursor.is_deleted_function() && !context.options().generate_deleted_functions {
859 return Err(ParseError::Continue);
860 }
861
862 if context.options().wrap_static_fns &&
864 cursor.is_inlined_function() &&
865 matches!(linkage, Linkage::External)
866 {
867 return Err(ParseError::Continue);
868 }
869 }
870
871 let sig = Item::from_ty(&cursor.cur_type(), cursor, None, context)?;
873
874 let mut name = cursor.spelling();
875 assert!(!name.is_empty(), "Empty function name?");
876
877 if cursor.kind() == CXCursor_Destructor {
878 if name.starts_with('~') {
882 name.remove(0);
883 }
884
885 name.push_str("_destructor");
889 }
890 if let Some(nm) = context.options().last_callback(|callbacks| {
891 callbacks.generated_name_override(ItemInfo {
892 name: name.as_str(),
893 kind: ItemKind::Function,
894 })
895 }) {
896 name = nm;
897 }
898 assert!(!name.is_empty(), "Empty function name.");
899
900 let operator_suffix = name.strip_prefix("operator");
901 let special_member = if let Some(operator_suffix) = operator_suffix {
902 if context.options().represent_cxx_operators {
905 let (new_name, special_member) = match operator_suffix {
906 "=" => ("operator_equals", Some(SpecialMemberKind::AssignmentOperator)),
907 _ if clang::is_valid_identifier(&name) => (name.as_str(), None),
908 _ => return Err(ParseError::Continue),
909 };
910 name = new_name.to_string();
911 special_member
912 } else {
913 None
917 }
918 } else {
919 None
920 };
921
922 let link_name = context.options().last_callback(|callbacks| {
923 callbacks.generated_link_name_override(ItemInfo {
924 name: name.as_str(),
925 kind: ItemKind::Function,
926 })
927 });
928
929 let mangled_name = cursor_mangling(context, &cursor);
930
931 let special_member = special_member.or_else(|| {
932 if cursor.is_default_constructor() {
933 Some(SpecialMemberKind::DefaultConstructor)
934 } else if cursor.is_copy_constructor() {
935 Some(SpecialMemberKind::CopyConstructor)
936 } else if cursor.is_move_constructor() {
937 Some(SpecialMemberKind::MoveConstructor)
938 } else if cursor.kind() == CXCursor_Destructor {
939 Some(SpecialMemberKind::Destructor)
940 } else {
941 None
942 }
943 });
944
945 let autocxx_info = AutocxxFuncInfo::new(
946 special_member,
947 visibility,
948 cursor.is_deleted_function(),
949 cursor.is_defaulted_function(),
950 );
951 let function = Self::new(
952 name,
953 mangled_name,
954 link_name,
955 sig,
956 kind,
957 linkage,
958 autocxx_info,
959 );
960
961 Ok(ParseResult::New(function, Some(cursor)))
962 }
963}
964
965impl Trace for FunctionSig {
966 type Extra = ();
967
968 fn trace<T>(&self, _: &BindgenContext, tracer: &mut T, _: &())
969 where
970 T: Tracer,
971 {
972 tracer.visit_kind(self.return_type().into(), EdgeKind::FunctionReturn);
973
974 for &(_, ty) in self.argument_types() {
975 tracer.visit_kind(ty.into(), EdgeKind::FunctionParameter);
976 }
977 }
978}