1 | //! Intermediate representation for C/C++ functions and methods. |
2 | |
3 | use super::comp::MethodKind; |
4 | use super::context::{BindgenContext, TypeId}; |
5 | use super::dot::DotAttributes; |
6 | use super::item::Item; |
7 | use super::traversal::{EdgeKind, Trace, Tracer}; |
8 | use super::ty::TypeKind; |
9 | use crate::callbacks::{ItemInfo, ItemKind}; |
10 | use crate::clang::{self, Attribute}; |
11 | use crate::parse::{ClangSubItemParser, ParseError, ParseResult}; |
12 | use clang_sys::{self, CXCallingConv}; |
13 | use proc_macro2; |
14 | use quote; |
15 | use quote::TokenStreamExt; |
16 | use std::io; |
17 | use std::str::FromStr; |
18 | |
19 | const RUST_DERIVE_FUNPTR_LIMIT: usize = 12; |
20 | |
21 | /// What kind of a function are we looking at? |
22 | #[derive (Debug, Copy, Clone, PartialEq, Eq)] |
23 | pub enum FunctionKind { |
24 | /// A plain, free function. |
25 | Function, |
26 | /// A method of some kind. |
27 | Method(MethodKind), |
28 | } |
29 | |
30 | impl FunctionKind { |
31 | /// Given a clang cursor, return the kind of function it represents, or |
32 | /// `None` otherwise. |
33 | pub fn from_cursor(cursor: &clang::Cursor) -> Option<FunctionKind> { |
34 | // FIXME(emilio): Deduplicate logic with `ir::comp`. |
35 | Some(match cursor.kind() { |
36 | clang_sys::CXCursor_FunctionDecl => FunctionKind::Function, |
37 | clang_sys::CXCursor_Constructor => { |
38 | FunctionKind::Method(MethodKind::Constructor) |
39 | } |
40 | clang_sys::CXCursor_Destructor => { |
41 | FunctionKind::Method(if cursor.method_is_virtual() { |
42 | MethodKind::VirtualDestructor { |
43 | pure_virtual: cursor.method_is_pure_virtual(), |
44 | } |
45 | } else { |
46 | MethodKind::Destructor |
47 | }) |
48 | } |
49 | clang_sys::CXCursor_CXXMethod => { |
50 | if cursor.method_is_virtual() { |
51 | FunctionKind::Method(MethodKind::Virtual { |
52 | pure_virtual: cursor.method_is_pure_virtual(), |
53 | }) |
54 | } else if cursor.method_is_static() { |
55 | FunctionKind::Method(MethodKind::Static) |
56 | } else { |
57 | FunctionKind::Method(MethodKind::Normal) |
58 | } |
59 | } |
60 | _ => return None, |
61 | }) |
62 | } |
63 | } |
64 | |
65 | /// The style of linkage |
66 | #[derive (Debug, Clone, Copy)] |
67 | pub enum Linkage { |
68 | /// Externally visible and can be linked against |
69 | External, |
70 | /// Not exposed externally. 'static inline' functions will have this kind of linkage |
71 | Internal, |
72 | } |
73 | |
74 | /// A function declaration, with a signature, arguments, and argument names. |
75 | /// |
76 | /// The argument names vector must be the same length as the ones in the |
77 | /// signature. |
78 | #[derive (Debug)] |
79 | pub struct Function { |
80 | /// The name of this function. |
81 | name: String, |
82 | |
83 | /// The mangled name, that is, the symbol. |
84 | mangled_name: Option<String>, |
85 | |
86 | /// The id pointing to the current function signature. |
87 | signature: TypeId, |
88 | |
89 | /// The doc comment on the function, if any. |
90 | comment: Option<String>, |
91 | |
92 | /// The kind of function this is. |
93 | kind: FunctionKind, |
94 | |
95 | /// The linkage of the function. |
96 | linkage: Linkage, |
97 | } |
98 | |
99 | impl Function { |
100 | /// Construct a new function. |
101 | pub fn new( |
102 | name: String, |
103 | mangled_name: Option<String>, |
104 | signature: TypeId, |
105 | comment: Option<String>, |
106 | kind: FunctionKind, |
107 | linkage: Linkage, |
108 | ) -> Self { |
109 | Function { |
110 | name, |
111 | mangled_name, |
112 | signature, |
113 | comment, |
114 | kind, |
115 | linkage, |
116 | } |
117 | } |
118 | |
119 | /// Get this function's name. |
120 | pub fn name(&self) -> &str { |
121 | &self.name |
122 | } |
123 | |
124 | /// Get this function's name. |
125 | pub fn mangled_name(&self) -> Option<&str> { |
126 | self.mangled_name.as_deref() |
127 | } |
128 | |
129 | /// Get this function's signature type. |
130 | pub fn signature(&self) -> TypeId { |
131 | self.signature |
132 | } |
133 | |
134 | /// Get this function's comment. |
135 | pub fn comment(&self) -> Option<&str> { |
136 | self.comment.as_deref() |
137 | } |
138 | |
139 | /// Get this function's kind. |
140 | pub fn kind(&self) -> FunctionKind { |
141 | self.kind |
142 | } |
143 | |
144 | /// Get this function's linkage. |
145 | pub fn linkage(&self) -> Linkage { |
146 | self.linkage |
147 | } |
148 | } |
149 | |
150 | impl DotAttributes for Function { |
151 | fn dot_attributes<W>( |
152 | &self, |
153 | _ctx: &BindgenContext, |
154 | out: &mut W, |
155 | ) -> io::Result<()> |
156 | where |
157 | W: io::Write, |
158 | { |
159 | if let Some(ref mangled: &String) = self.mangled_name { |
160 | let mangled: String = |
161 | mangled.chars().flat_map(|c: char| c.escape_default()).collect(); |
162 | writeln!( |
163 | out, |
164 | "<tr><td>mangled name</td><td> {}</td></tr>" , |
165 | mangled |
166 | )?; |
167 | } |
168 | |
169 | Ok(()) |
170 | } |
171 | } |
172 | |
173 | /// A valid rust ABI. |
174 | #[derive (Debug, Copy, Clone, Hash, Eq, PartialEq)] |
175 | pub enum Abi { |
176 | /// The default C ABI. |
177 | C, |
178 | /// The "stdcall" ABI. |
179 | Stdcall, |
180 | /// The "fastcall" ABI. |
181 | Fastcall, |
182 | /// The "thiscall" ABI. |
183 | ThisCall, |
184 | /// The "vectorcall" ABI. |
185 | Vectorcall, |
186 | /// The "aapcs" ABI. |
187 | Aapcs, |
188 | /// The "win64" ABI. |
189 | Win64, |
190 | /// The "C-unwind" ABI. |
191 | CUnwind, |
192 | } |
193 | |
194 | impl FromStr for Abi { |
195 | type Err = String; |
196 | |
197 | fn from_str(s: &str) -> Result<Self, Self::Err> { |
198 | match s { |
199 | "C" => Ok(Self::C), |
200 | "stdcall" => Ok(Self::Stdcall), |
201 | "fastcall" => Ok(Self::Fastcall), |
202 | "thiscall" => Ok(Self::ThisCall), |
203 | "vectorcall" => Ok(Self::Vectorcall), |
204 | "aapcs" => Ok(Self::Aapcs), |
205 | "win64" => Ok(Self::Win64), |
206 | "C-unwind" => Ok(Self::CUnwind), |
207 | _ => Err(format!("Invalid or unknown ABI {:?}" , s)), |
208 | } |
209 | } |
210 | } |
211 | |
212 | impl std::fmt::Display for Abi { |
213 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
214 | let s: &str = match *self { |
215 | Self::C => "C" , |
216 | Self::Stdcall => "stdcall" , |
217 | Self::Fastcall => "fastcall" , |
218 | Self::ThisCall => "thiscall" , |
219 | Self::Vectorcall => "vectorcall" , |
220 | Self::Aapcs => "aapcs" , |
221 | Self::Win64 => "win64" , |
222 | Self::CUnwind => "C-unwind" , |
223 | }; |
224 | |
225 | s.fmt(f) |
226 | } |
227 | } |
228 | |
229 | impl quote::ToTokens for Abi { |
230 | fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { |
231 | let abi: String = self.to_string(); |
232 | tokens.append_all(iter:quote! { #abi }); |
233 | } |
234 | } |
235 | |
236 | /// An ABI extracted from a clang cursor. |
237 | #[derive (Debug, Copy, Clone)] |
238 | pub(crate) enum ClangAbi { |
239 | Known(Abi), |
240 | /// An unknown or invalid ABI. |
241 | Unknown(CXCallingConv), |
242 | } |
243 | |
244 | impl ClangAbi { |
245 | /// Returns whether this Abi is known or not. |
246 | fn is_unknown(&self) -> bool { |
247 | matches!(*self, ClangAbi::Unknown(..)) |
248 | } |
249 | } |
250 | |
251 | impl quote::ToTokens for ClangAbi { |
252 | fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { |
253 | match *self { |
254 | Self::Known(abi: Abi) => abi.to_tokens(tokens), |
255 | Self::Unknown(cc: i32) => panic!( |
256 | "Cannot turn unknown calling convention to tokens: {:?}" , |
257 | cc |
258 | ), |
259 | } |
260 | } |
261 | } |
262 | |
263 | /// A function signature. |
264 | #[derive (Debug)] |
265 | pub struct FunctionSig { |
266 | /// The return type of the function. |
267 | return_type: TypeId, |
268 | |
269 | /// The type of the arguments, optionally with the name of the argument when |
270 | /// declared. |
271 | argument_types: Vec<(Option<String>, TypeId)>, |
272 | |
273 | /// Whether this function is variadic. |
274 | is_variadic: bool, |
275 | is_divergent: bool, |
276 | |
277 | /// Whether this function's return value must be used. |
278 | must_use: bool, |
279 | |
280 | /// The ABI of this function. |
281 | abi: ClangAbi, |
282 | } |
283 | |
284 | fn get_abi(cc: CXCallingConv) -> ClangAbi { |
285 | use clang_sys::*; |
286 | match cc { |
287 | CXCallingConv_Default => ClangAbi::Known(Abi::C), |
288 | CXCallingConv_C => ClangAbi::Known(Abi::C), |
289 | CXCallingConv_X86StdCall => ClangAbi::Known(Abi::Stdcall), |
290 | CXCallingConv_X86FastCall => ClangAbi::Known(Abi::Fastcall), |
291 | CXCallingConv_X86ThisCall => ClangAbi::Known(Abi::ThisCall), |
292 | CXCallingConv_X86VectorCall => ClangAbi::Known(Abi::Vectorcall), |
293 | CXCallingConv_AAPCS => ClangAbi::Known(Abi::Aapcs), |
294 | CXCallingConv_X86_64Win64 => ClangAbi::Known(Abi::Win64), |
295 | other: i32 => ClangAbi::Unknown(other), |
296 | } |
297 | } |
298 | |
299 | /// Get the mangled name for the cursor's referent. |
300 | pub fn cursor_mangling( |
301 | ctx: &BindgenContext, |
302 | cursor: &clang::Cursor, |
303 | ) -> Option<String> { |
304 | if !ctx.options().enable_mangling { |
305 | return None; |
306 | } |
307 | |
308 | // We early return here because libclang may crash in some case |
309 | // if we pass in a variable inside a partial specialized template. |
310 | // See rust-lang/rust-bindgen#67, and rust-lang/rust-bindgen#462. |
311 | if cursor.is_in_non_fully_specialized_template() { |
312 | return None; |
313 | } |
314 | |
315 | let is_destructor = cursor.kind() == clang_sys::CXCursor_Destructor; |
316 | if let Ok(mut manglings) = cursor.cxx_manglings() { |
317 | while let Some(m) = manglings.pop() { |
318 | // Only generate the destructor group 1, see below. |
319 | if is_destructor && !m.ends_with("D1Ev" ) { |
320 | continue; |
321 | } |
322 | |
323 | return Some(m); |
324 | } |
325 | } |
326 | |
327 | let mut mangling = cursor.mangling(); |
328 | if mangling.is_empty() { |
329 | return None; |
330 | } |
331 | |
332 | if is_destructor { |
333 | // With old (3.8-) libclang versions, and the Itanium ABI, clang returns |
334 | // the "destructor group 0" symbol, which means that it'll try to free |
335 | // memory, which definitely isn't what we want. |
336 | // |
337 | // Explicitly force the destructor group 1 symbol. |
338 | // |
339 | // See http://refspecs.linuxbase.org/cxxabi-1.83.html#mangling-special |
340 | // for the reference, and http://stackoverflow.com/a/6614369/1091587 for |
341 | // a more friendly explanation. |
342 | // |
343 | // We don't need to do this for constructors since clang seems to always |
344 | // have returned the C1 constructor. |
345 | // |
346 | // FIXME(emilio): Can a legit symbol in other ABIs end with this string? |
347 | // I don't think so, but if it can this would become a linker error |
348 | // anyway, not an invalid free at runtime. |
349 | // |
350 | // TODO(emilio, #611): Use cpp_demangle if this becomes nastier with |
351 | // time. |
352 | if mangling.ends_with("D0Ev" ) { |
353 | let new_len = mangling.len() - 4; |
354 | mangling.truncate(new_len); |
355 | mangling.push_str("D1Ev" ); |
356 | } |
357 | } |
358 | |
359 | Some(mangling) |
360 | } |
361 | |
362 | fn args_from_ty_and_cursor( |
363 | ty: &clang::Type, |
364 | cursor: &clang::Cursor, |
365 | ctx: &mut BindgenContext, |
366 | ) -> Vec<(Option<String>, TypeId)> { |
367 | let cursor_args = cursor.args().unwrap_or_default().into_iter(); |
368 | let type_args = ty.args().unwrap_or_default().into_iter(); |
369 | |
370 | // Argument types can be found in either the cursor or the type, but argument names may only be |
371 | // found on the cursor. We often have access to both a type and a cursor for each argument, but |
372 | // in some cases we may only have one. |
373 | // |
374 | // Prefer using the type as the source of truth for the argument's type, but fall back to |
375 | // inspecting the cursor (this happens for Objective C interfaces). |
376 | // |
377 | // Prefer using the cursor for the argument's type, but fall back to using the parent's cursor |
378 | // (this happens for function pointer return types). |
379 | cursor_args |
380 | .map(Some) |
381 | .chain(std::iter::repeat(None)) |
382 | .zip(type_args.map(Some).chain(std::iter::repeat(None))) |
383 | .take_while(|(cur, ty)| cur.is_some() || ty.is_some()) |
384 | .map(|(arg_cur, arg_ty)| { |
385 | let name = arg_cur.map(|a| a.spelling()).and_then(|name| { |
386 | if name.is_empty() { |
387 | None |
388 | } else { |
389 | Some(name) |
390 | } |
391 | }); |
392 | |
393 | let cursor = arg_cur.unwrap_or(*cursor); |
394 | let ty = arg_ty.unwrap_or_else(|| cursor.cur_type()); |
395 | (name, Item::from_ty_or_ref(ty, cursor, None, ctx)) |
396 | }) |
397 | .collect() |
398 | } |
399 | |
400 | impl FunctionSig { |
401 | /// Construct a new function signature from the given Clang type. |
402 | pub fn from_ty( |
403 | ty: &clang::Type, |
404 | cursor: &clang::Cursor, |
405 | ctx: &mut BindgenContext, |
406 | ) -> Result<Self, ParseError> { |
407 | use clang_sys::*; |
408 | debug!("FunctionSig::from_ty {:?} {:?}" , ty, cursor); |
409 | |
410 | // Skip function templates |
411 | let kind = cursor.kind(); |
412 | if kind == CXCursor_FunctionTemplate { |
413 | return Err(ParseError::Continue); |
414 | } |
415 | |
416 | let spelling = cursor.spelling(); |
417 | |
418 | // Don't parse operatorxx functions in C++ |
419 | let is_operator = |spelling: &str| { |
420 | spelling.starts_with("operator" ) && |
421 | !clang::is_valid_identifier(spelling) |
422 | }; |
423 | if is_operator(&spelling) { |
424 | return Err(ParseError::Continue); |
425 | } |
426 | |
427 | // Constructors of non-type template parameter classes for some reason |
428 | // include the template parameter in their name. Just skip them, since |
429 | // we don't handle well non-type template parameters anyway. |
430 | if (kind == CXCursor_Constructor || kind == CXCursor_Destructor) && |
431 | spelling.contains('<' ) |
432 | { |
433 | return Err(ParseError::Continue); |
434 | } |
435 | |
436 | let cursor = if cursor.is_valid() { |
437 | *cursor |
438 | } else { |
439 | ty.declaration() |
440 | }; |
441 | |
442 | let mut args = match kind { |
443 | CXCursor_FunctionDecl | |
444 | CXCursor_Constructor | |
445 | CXCursor_CXXMethod | |
446 | CXCursor_ObjCInstanceMethodDecl | |
447 | CXCursor_ObjCClassMethodDecl => { |
448 | args_from_ty_and_cursor(ty, &cursor, ctx) |
449 | } |
450 | _ => { |
451 | // For non-CXCursor_FunctionDecl, visiting the cursor's children |
452 | // is the only reliable way to get parameter names. |
453 | let mut args = vec![]; |
454 | cursor.visit(|c| { |
455 | if c.kind() == CXCursor_ParmDecl { |
456 | let ty = |
457 | Item::from_ty_or_ref(c.cur_type(), c, None, ctx); |
458 | let name = c.spelling(); |
459 | let name = |
460 | if name.is_empty() { None } else { Some(name) }; |
461 | args.push((name, ty)); |
462 | } |
463 | CXChildVisit_Continue |
464 | }); |
465 | |
466 | if args.is_empty() { |
467 | // FIXME(emilio): Sometimes libclang doesn't expose the |
468 | // right AST for functions tagged as stdcall and such... |
469 | // |
470 | // https://bugs.llvm.org/show_bug.cgi?id=45919 |
471 | args_from_ty_and_cursor(ty, &cursor, ctx) |
472 | } else { |
473 | args |
474 | } |
475 | } |
476 | }; |
477 | |
478 | let (must_use, mut is_divergent) = |
479 | if ctx.options().enable_function_attribute_detection { |
480 | let [must_use, no_return, no_return_cpp] = cursor.has_attrs(&[ |
481 | Attribute::MUST_USE, |
482 | Attribute::NO_RETURN, |
483 | Attribute::NO_RETURN_CPP, |
484 | ]); |
485 | (must_use, no_return || no_return_cpp) |
486 | } else { |
487 | Default::default() |
488 | }; |
489 | |
490 | // This looks easy to break but the clang parser keeps the type spelling clean even if |
491 | // other attributes are added. |
492 | is_divergent = |
493 | is_divergent || ty.spelling().contains("__attribute__((noreturn))" ); |
494 | |
495 | let is_method = kind == CXCursor_CXXMethod; |
496 | let is_constructor = kind == CXCursor_Constructor; |
497 | let is_destructor = kind == CXCursor_Destructor; |
498 | if (is_constructor || is_destructor || is_method) && |
499 | cursor.lexical_parent() != cursor.semantic_parent() |
500 | { |
501 | // Only parse constructors once. |
502 | return Err(ParseError::Continue); |
503 | } |
504 | |
505 | if is_method || is_constructor || is_destructor { |
506 | let is_const = is_method && cursor.method_is_const(); |
507 | let is_virtual = is_method && cursor.method_is_virtual(); |
508 | let is_static = is_method && cursor.method_is_static(); |
509 | if !is_static && !is_virtual { |
510 | let parent = cursor.semantic_parent(); |
511 | let class = Item::parse(parent, None, ctx) |
512 | .expect("Expected to parse the class" ); |
513 | // The `class` most likely is not finished parsing yet, so use |
514 | // the unchecked variant. |
515 | let class = class.as_type_id_unchecked(); |
516 | |
517 | let class = if is_const { |
518 | let const_class_id = ctx.next_item_id(); |
519 | ctx.build_const_wrapper( |
520 | const_class_id, |
521 | class, |
522 | None, |
523 | &parent.cur_type(), |
524 | ) |
525 | } else { |
526 | class |
527 | }; |
528 | |
529 | let ptr = |
530 | Item::builtin_type(TypeKind::Pointer(class), false, ctx); |
531 | args.insert(0, (Some("this" .into()), ptr)); |
532 | } else if is_virtual { |
533 | let void = Item::builtin_type(TypeKind::Void, false, ctx); |
534 | let ptr = |
535 | Item::builtin_type(TypeKind::Pointer(void), false, ctx); |
536 | args.insert(0, (Some("this" .into()), ptr)); |
537 | } |
538 | } |
539 | |
540 | let ty_ret_type = if kind == CXCursor_ObjCInstanceMethodDecl || |
541 | kind == CXCursor_ObjCClassMethodDecl |
542 | { |
543 | ty.ret_type() |
544 | .or_else(|| cursor.ret_type()) |
545 | .ok_or(ParseError::Continue)? |
546 | } else { |
547 | ty.ret_type().ok_or(ParseError::Continue)? |
548 | }; |
549 | |
550 | let ret = if is_constructor && ctx.is_target_wasm32() { |
551 | // Constructors in Clang wasm32 target return a pointer to the object |
552 | // being constructed. |
553 | let void = Item::builtin_type(TypeKind::Void, false, ctx); |
554 | Item::builtin_type(TypeKind::Pointer(void), false, ctx) |
555 | } else { |
556 | Item::from_ty_or_ref(ty_ret_type, cursor, None, ctx) |
557 | }; |
558 | |
559 | // Clang plays with us at "find the calling convention", see #549 and |
560 | // co. This seems to be a better fix than that commit. |
561 | let mut call_conv = ty.call_conv(); |
562 | if let Some(ty) = cursor.cur_type().canonical_type().pointee_type() { |
563 | let cursor_call_conv = ty.call_conv(); |
564 | if cursor_call_conv != CXCallingConv_Invalid { |
565 | call_conv = cursor_call_conv; |
566 | } |
567 | } |
568 | |
569 | let abi = get_abi(call_conv); |
570 | |
571 | if abi.is_unknown() { |
572 | warn!("Unknown calling convention: {:?}" , call_conv); |
573 | } |
574 | |
575 | Ok(FunctionSig { |
576 | return_type: ret, |
577 | argument_types: args, |
578 | is_variadic: ty.is_variadic(), |
579 | is_divergent, |
580 | must_use, |
581 | abi, |
582 | }) |
583 | } |
584 | |
585 | /// Get this function signature's return type. |
586 | pub fn return_type(&self) -> TypeId { |
587 | self.return_type |
588 | } |
589 | |
590 | /// Get this function signature's argument (name, type) pairs. |
591 | pub fn argument_types(&self) -> &[(Option<String>, TypeId)] { |
592 | &self.argument_types |
593 | } |
594 | |
595 | /// Get this function signature's ABI. |
596 | pub(crate) fn abi( |
597 | &self, |
598 | ctx: &BindgenContext, |
599 | name: Option<&str>, |
600 | ) -> ClangAbi { |
601 | // FIXME (pvdrz): Try to do this check lazily instead. Maybe store the ABI inside `ctx` |
602 | // instead?. |
603 | if let Some(name) = name { |
604 | if let Some((abi, _)) = ctx |
605 | .options() |
606 | .abi_overrides |
607 | .iter() |
608 | .find(|(_, regex_set)| regex_set.matches(name)) |
609 | { |
610 | ClangAbi::Known(*abi) |
611 | } else { |
612 | self.abi |
613 | } |
614 | } else { |
615 | self.abi |
616 | } |
617 | } |
618 | |
619 | /// Is this function signature variadic? |
620 | pub fn is_variadic(&self) -> bool { |
621 | // Clang reports some functions as variadic when they *might* be |
622 | // variadic. We do the argument check because rust doesn't codegen well |
623 | // variadic functions without an initial argument. |
624 | self.is_variadic && !self.argument_types.is_empty() |
625 | } |
626 | |
627 | /// Must this function's return value be used? |
628 | pub fn must_use(&self) -> bool { |
629 | self.must_use |
630 | } |
631 | |
632 | /// Are function pointers with this signature able to derive Rust traits? |
633 | /// Rust only supports deriving traits for function pointers with a limited |
634 | /// number of parameters and a couple ABIs. |
635 | /// |
636 | /// For more details, see: |
637 | /// |
638 | /// * https://github.com/rust-lang/rust-bindgen/issues/547, |
639 | /// * https://github.com/rust-lang/rust/issues/38848, |
640 | /// * and https://github.com/rust-lang/rust/issues/40158 |
641 | pub fn function_pointers_can_derive(&self) -> bool { |
642 | if self.argument_types.len() > RUST_DERIVE_FUNPTR_LIMIT { |
643 | return false; |
644 | } |
645 | |
646 | matches!(self.abi, ClangAbi::Known(Abi::C) | ClangAbi::Unknown(..)) |
647 | } |
648 | |
649 | pub(crate) fn is_divergent(&self) -> bool { |
650 | self.is_divergent |
651 | } |
652 | } |
653 | |
654 | impl ClangSubItemParser for Function { |
655 | fn parse( |
656 | cursor: clang::Cursor, |
657 | context: &mut BindgenContext, |
658 | ) -> Result<ParseResult<Self>, ParseError> { |
659 | use clang_sys::*; |
660 | |
661 | let kind = match FunctionKind::from_cursor(&cursor) { |
662 | None => return Err(ParseError::Continue), |
663 | Some(k) => k, |
664 | }; |
665 | |
666 | debug!("Function::parse( {:?}, {:?})" , cursor, cursor.cur_type()); |
667 | let visibility = cursor.visibility(); |
668 | if visibility != CXVisibility_Default { |
669 | return Err(ParseError::Continue); |
670 | } |
671 | |
672 | if cursor.access_specifier() == CX_CXXPrivate { |
673 | return Err(ParseError::Continue); |
674 | } |
675 | |
676 | let linkage = cursor.linkage(); |
677 | let linkage = match linkage { |
678 | CXLinkage_External | CXLinkage_UniqueExternal => Linkage::External, |
679 | CXLinkage_Internal => Linkage::Internal, |
680 | _ => return Err(ParseError::Continue), |
681 | }; |
682 | |
683 | if cursor.is_inlined_function() || |
684 | cursor |
685 | .definition() |
686 | .map_or(false, |x| x.is_inlined_function()) |
687 | { |
688 | if !context.options().generate_inline_functions && |
689 | !context.options().wrap_static_fns |
690 | { |
691 | return Err(ParseError::Continue); |
692 | } |
693 | |
694 | if cursor.is_deleted_function() { |
695 | return Err(ParseError::Continue); |
696 | } |
697 | |
698 | // We cannot handle `inline` functions that are not `static`. |
699 | if context.options().wrap_static_fns && |
700 | cursor.is_inlined_function() && |
701 | matches!(linkage, Linkage::External) |
702 | { |
703 | return Err(ParseError::Continue); |
704 | } |
705 | } |
706 | |
707 | // Grab the signature using Item::from_ty. |
708 | let sig = Item::from_ty(&cursor.cur_type(), cursor, None, context)?; |
709 | |
710 | let mut name = cursor.spelling(); |
711 | assert!(!name.is_empty(), "Empty function name?" ); |
712 | |
713 | if cursor.kind() == CXCursor_Destructor { |
714 | // Remove the leading `~`. The alternative to this is special-casing |
715 | // code-generation for destructor functions, which seems less than |
716 | // ideal. |
717 | if name.starts_with('~' ) { |
718 | name.remove(0); |
719 | } |
720 | |
721 | // Add a suffix to avoid colliding with constructors. This would be |
722 | // technically fine (since we handle duplicated functions/methods), |
723 | // but seems easy enough to handle it here. |
724 | name.push_str("_destructor" ); |
725 | } |
726 | if let Some(nm) = context.options().last_callback(|callbacks| { |
727 | callbacks.generated_name_override(ItemInfo { |
728 | name: name.as_str(), |
729 | kind: ItemKind::Function, |
730 | }) |
731 | }) { |
732 | name = nm; |
733 | } |
734 | assert!(!name.is_empty(), "Empty function name." ); |
735 | |
736 | let mangled_name = cursor_mangling(context, &cursor); |
737 | let comment = cursor.raw_comment(); |
738 | |
739 | let function = |
740 | Self::new(name.clone(), mangled_name, sig, comment, kind, linkage); |
741 | |
742 | Ok(ParseResult::New(function, Some(cursor))) |
743 | } |
744 | } |
745 | |
746 | impl Trace for FunctionSig { |
747 | type Extra = (); |
748 | |
749 | fn trace<T>(&self, _: &BindgenContext, tracer: &mut T, _: &()) |
750 | where |
751 | T: Tracer, |
752 | { |
753 | tracer.visit_kind(self.return_type().into(), kind:EdgeKind::FunctionReturn); |
754 | |
755 | for &(_, ty: TypeId) in self.argument_types() { |
756 | tracer.visit_kind(item:ty.into(), kind:EdgeKind::FunctionParameter); |
757 | } |
758 | } |
759 | } |
760 | |