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::clang;
10 use crate::parse::{
11 ClangItemParser, ClangSubItemParser, ParseError, ParseResult,
12 };
13 use clang_sys::{self, CXCallingConv};
14 use proc_macro2;
15 use quote;
16 use quote::TokenStreamExt;
17 use std::io;
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)]
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.
from_cursor(cursor: &clang::Cursor) -> Option<FunctionKind>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.
new( name: String, mangled_name: Option<String>, signature: TypeId, comment: Option<String>, kind: FunctionKind, linkage: Linkage, ) -> Self101 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.
name(&self) -> &str120 pub fn name(&self) -> &str {
121 &self.name
122 }
123
124 /// Get this function's name.
mangled_name(&self) -> Option<&str>125 pub fn mangled_name(&self) -> Option<&str> {
126 self.mangled_name.as_deref()
127 }
128
129 /// Get this function's signature type.
signature(&self) -> TypeId130 pub fn signature(&self) -> TypeId {
131 self.signature
132 }
133
134 /// Get this function's kind.
kind(&self) -> FunctionKind135 pub fn kind(&self) -> FunctionKind {
136 self.kind
137 }
138
139 /// Get this function's linkage.
linkage(&self) -> Linkage140 pub fn linkage(&self) -> Linkage {
141 self.linkage
142 }
143 }
144
145 impl DotAttributes for Function {
dot_attributes<W>( &self, _ctx: &BindgenContext, out: &mut W, ) -> io::Result<()> where W: io::Write,146 fn dot_attributes<W>(
147 &self,
148 _ctx: &BindgenContext,
149 out: &mut W,
150 ) -> io::Result<()>
151 where
152 W: io::Write,
153 {
154 if let Some(ref mangled) = self.mangled_name {
155 let mangled: String =
156 mangled.chars().flat_map(|c| c.escape_default()).collect();
157 writeln!(
158 out,
159 "<tr><td>mangled name</td><td>{}</td></tr>",
160 mangled
161 )?;
162 }
163
164 Ok(())
165 }
166 }
167
168 /// An ABI extracted from a clang cursor.
169 #[derive(Debug, Copy, Clone)]
170 pub enum Abi {
171 /// The default C ABI.
172 C,
173 /// The "stdcall" ABI.
174 Stdcall,
175 /// The "fastcall" ABI.
176 Fastcall,
177 /// The "thiscall" ABI.
178 ThisCall,
179 /// The "aapcs" ABI.
180 Aapcs,
181 /// The "win64" ABI.
182 Win64,
183 /// An unknown or invalid ABI.
184 Unknown(CXCallingConv),
185 }
186
187 impl Abi {
188 /// Returns whether this Abi is known or not.
is_unknown(&self) -> bool189 fn is_unknown(&self) -> bool {
190 matches!(*self, Abi::Unknown(..))
191 }
192 }
193
194 impl quote::ToTokens for Abi {
to_tokens(&self, tokens: &mut proc_macro2::TokenStream)195 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
196 tokens.append_all(match *self {
197 Abi::C => quote! { "C" },
198 Abi::Stdcall => quote! { "stdcall" },
199 Abi::Fastcall => quote! { "fastcall" },
200 Abi::ThisCall => quote! { "thiscall" },
201 Abi::Aapcs => quote! { "aapcs" },
202 Abi::Win64 => quote! { "win64" },
203 Abi::Unknown(cc) => panic!(
204 "Cannot turn unknown calling convention to tokens: {:?}",
205 cc
206 ),
207 });
208 }
209 }
210
211 /// A function signature.
212 #[derive(Debug)]
213 pub struct FunctionSig {
214 /// The return type of the function.
215 return_type: TypeId,
216
217 /// The type of the arguments, optionally with the name of the argument when
218 /// declared.
219 argument_types: Vec<(Option<String>, TypeId)>,
220
221 /// Whether this function is variadic.
222 is_variadic: bool,
223
224 /// Whether this function's return value must be used.
225 must_use: bool,
226
227 /// The ABI of this function.
228 abi: Abi,
229 }
230
get_abi(cc: CXCallingConv) -> Abi231 fn get_abi(cc: CXCallingConv) -> Abi {
232 use clang_sys::*;
233 match cc {
234 CXCallingConv_Default => Abi::C,
235 CXCallingConv_C => Abi::C,
236 CXCallingConv_X86StdCall => Abi::Stdcall,
237 CXCallingConv_X86FastCall => Abi::Fastcall,
238 CXCallingConv_X86ThisCall => Abi::ThisCall,
239 CXCallingConv_AAPCS => Abi::Aapcs,
240 CXCallingConv_X86_64Win64 => Abi::Win64,
241 other => Abi::Unknown(other),
242 }
243 }
244
245 /// Get the mangled name for the cursor's referent.
cursor_mangling( ctx: &BindgenContext, cursor: &clang::Cursor, ) -> Option<String>246 pub fn cursor_mangling(
247 ctx: &BindgenContext,
248 cursor: &clang::Cursor,
249 ) -> Option<String> {
250 if !ctx.options().enable_mangling {
251 return None;
252 }
253
254 // We early return here because libclang may crash in some case
255 // if we pass in a variable inside a partial specialized template.
256 // See rust-lang/rust-bindgen#67, and rust-lang/rust-bindgen#462.
257 if cursor.is_in_non_fully_specialized_template() {
258 return None;
259 }
260
261 let is_destructor = cursor.kind() == clang_sys::CXCursor_Destructor;
262 if let Ok(mut manglings) = cursor.cxx_manglings() {
263 while let Some(m) = manglings.pop() {
264 // Only generate the destructor group 1, see below.
265 if is_destructor && !m.ends_with("D1Ev") {
266 continue;
267 }
268
269 return Some(m);
270 }
271 }
272
273 let mut mangling = cursor.mangling();
274 if mangling.is_empty() {
275 return None;
276 }
277
278 if is_destructor {
279 // With old (3.8-) libclang versions, and the Itanium ABI, clang returns
280 // the "destructor group 0" symbol, which means that it'll try to free
281 // memory, which definitely isn't what we want.
282 //
283 // Explicitly force the destructor group 1 symbol.
284 //
285 // See http://refspecs.linuxbase.org/cxxabi-1.83.html#mangling-special
286 // for the reference, and http://stackoverflow.com/a/6614369/1091587 for
287 // a more friendly explanation.
288 //
289 // We don't need to do this for constructors since clang seems to always
290 // have returned the C1 constructor.
291 //
292 // FIXME(emilio): Can a legit symbol in other ABIs end with this string?
293 // I don't think so, but if it can this would become a linker error
294 // anyway, not an invalid free at runtime.
295 //
296 // TODO(emilio, #611): Use cpp_demangle if this becomes nastier with
297 // time.
298 if mangling.ends_with("D0Ev") {
299 let new_len = mangling.len() - 4;
300 mangling.truncate(new_len);
301 mangling.push_str("D1Ev");
302 }
303 }
304
305 Some(mangling)
306 }
307
args_from_ty_and_cursor( ty: &clang::Type, cursor: &clang::Cursor, ctx: &mut BindgenContext, ) -> Vec<(Option<String>, TypeId)>308 fn args_from_ty_and_cursor(
309 ty: &clang::Type,
310 cursor: &clang::Cursor,
311 ctx: &mut BindgenContext,
312 ) -> Vec<(Option<String>, TypeId)> {
313 let cursor_args = cursor.args().unwrap_or_default().into_iter();
314 let type_args = ty.args().unwrap_or_default().into_iter();
315
316 // Argument types can be found in either the cursor or the type, but argument names may only be
317 // found on the cursor. We often have access to both a type and a cursor for each argument, but
318 // in some cases we may only have one.
319 //
320 // Prefer using the type as the source of truth for the argument's type, but fall back to
321 // inspecting the cursor (this happens for Objective C interfaces).
322 //
323 // Prefer using the cursor for the argument's type, but fall back to using the parent's cursor
324 // (this happens for function pointer return types).
325 cursor_args
326 .map(Some)
327 .chain(std::iter::repeat(None))
328 .zip(type_args.map(Some).chain(std::iter::repeat(None)))
329 .take_while(|(cur, ty)| cur.is_some() || ty.is_some())
330 .map(|(arg_cur, arg_ty)| {
331 let name = arg_cur.map(|a| a.spelling()).and_then(|name| {
332 if name.is_empty() {
333 None
334 } else {
335 Some(name)
336 }
337 });
338
339 let cursor = arg_cur.unwrap_or(*cursor);
340 let ty = arg_ty.unwrap_or_else(|| cursor.cur_type());
341 (name, Item::from_ty_or_ref(ty, cursor, None, ctx))
342 })
343 .collect()
344 }
345
346 impl FunctionSig {
347 /// Construct a new function signature.
new( return_type: TypeId, argument_types: Vec<(Option<String>, TypeId)>, is_variadic: bool, must_use: bool, abi: Abi, ) -> Self348 pub fn new(
349 return_type: TypeId,
350 argument_types: Vec<(Option<String>, TypeId)>,
351 is_variadic: bool,
352 must_use: bool,
353 abi: Abi,
354 ) -> Self {
355 FunctionSig {
356 return_type,
357 argument_types,
358 is_variadic,
359 must_use,
360 abi,
361 }
362 }
363
364 /// Construct a new function signature from the given Clang type.
from_ty( ty: &clang::Type, cursor: &clang::Cursor, ctx: &mut BindgenContext, ) -> Result<Self, ParseError>365 pub fn from_ty(
366 ty: &clang::Type,
367 cursor: &clang::Cursor,
368 ctx: &mut BindgenContext,
369 ) -> Result<Self, ParseError> {
370 use clang_sys::*;
371 debug!("FunctionSig::from_ty {:?} {:?}", ty, cursor);
372
373 // Skip function templates
374 let kind = cursor.kind();
375 if kind == CXCursor_FunctionTemplate {
376 return Err(ParseError::Continue);
377 }
378
379 let spelling = cursor.spelling();
380
381 // Don't parse operatorxx functions in C++
382 let is_operator = |spelling: &str| {
383 spelling.starts_with("operator") &&
384 !clang::is_valid_identifier(spelling)
385 };
386 if is_operator(&spelling) {
387 return Err(ParseError::Continue);
388 }
389
390 // Constructors of non-type template parameter classes for some reason
391 // include the template parameter in their name. Just skip them, since
392 // we don't handle well non-type template parameters anyway.
393 if (kind == CXCursor_Constructor || kind == CXCursor_Destructor) &&
394 spelling.contains('<')
395 {
396 return Err(ParseError::Continue);
397 }
398
399 let cursor = if cursor.is_valid() {
400 *cursor
401 } else {
402 ty.declaration()
403 };
404
405 let mut args = match kind {
406 CXCursor_FunctionDecl |
407 CXCursor_Constructor |
408 CXCursor_CXXMethod |
409 CXCursor_ObjCInstanceMethodDecl |
410 CXCursor_ObjCClassMethodDecl => {
411 args_from_ty_and_cursor(ty, &cursor, ctx)
412 }
413 _ => {
414 // For non-CXCursor_FunctionDecl, visiting the cursor's children
415 // is the only reliable way to get parameter names.
416 let mut args = vec![];
417 cursor.visit(|c| {
418 if c.kind() == CXCursor_ParmDecl {
419 let ty =
420 Item::from_ty_or_ref(c.cur_type(), c, None, ctx);
421 let name = c.spelling();
422 let name =
423 if name.is_empty() { None } else { Some(name) };
424 args.push((name, ty));
425 }
426 CXChildVisit_Continue
427 });
428
429 if args.is_empty() {
430 // FIXME(emilio): Sometimes libclang doesn't expose the
431 // right AST for functions tagged as stdcall and such...
432 //
433 // https://bugs.llvm.org/show_bug.cgi?id=45919
434 args_from_ty_and_cursor(ty, &cursor, ctx)
435 } else {
436 args
437 }
438 }
439 };
440
441 let must_use = ctx.options().enable_function_attribute_detection &&
442 cursor.has_warn_unused_result_attr();
443 let is_method = kind == CXCursor_CXXMethod;
444 let is_constructor = kind == CXCursor_Constructor;
445 let is_destructor = kind == CXCursor_Destructor;
446 if (is_constructor || is_destructor || is_method) &&
447 cursor.lexical_parent() != cursor.semantic_parent()
448 {
449 // Only parse constructors once.
450 return Err(ParseError::Continue);
451 }
452
453 if is_method || is_constructor || is_destructor {
454 let is_const = is_method && cursor.method_is_const();
455 let is_virtual = is_method && cursor.method_is_virtual();
456 let is_static = is_method && cursor.method_is_static();
457 if !is_static && !is_virtual {
458 let parent = cursor.semantic_parent();
459 let class = Item::parse(parent, None, ctx)
460 .expect("Expected to parse the class");
461 // The `class` most likely is not finished parsing yet, so use
462 // the unchecked variant.
463 let class = class.as_type_id_unchecked();
464
465 let class = if is_const {
466 let const_class_id = ctx.next_item_id();
467 ctx.build_const_wrapper(
468 const_class_id,
469 class,
470 None,
471 &parent.cur_type(),
472 )
473 } else {
474 class
475 };
476
477 let ptr =
478 Item::builtin_type(TypeKind::Pointer(class), false, ctx);
479 args.insert(0, (Some("this".into()), ptr));
480 } else if is_virtual {
481 let void = Item::builtin_type(TypeKind::Void, false, ctx);
482 let ptr =
483 Item::builtin_type(TypeKind::Pointer(void), false, ctx);
484 args.insert(0, (Some("this".into()), ptr));
485 }
486 }
487
488 let ty_ret_type = if kind == CXCursor_ObjCInstanceMethodDecl ||
489 kind == CXCursor_ObjCClassMethodDecl
490 {
491 ty.ret_type()
492 .or_else(|| cursor.ret_type())
493 .ok_or(ParseError::Continue)?
494 } else {
495 ty.ret_type().ok_or(ParseError::Continue)?
496 };
497
498 let ret = if is_constructor && ctx.is_target_wasm32() {
499 // Constructors in Clang wasm32 target return a pointer to the object
500 // being constructed.
501 let void = Item::builtin_type(TypeKind::Void, false, ctx);
502 Item::builtin_type(TypeKind::Pointer(void), false, ctx)
503 } else {
504 Item::from_ty_or_ref(ty_ret_type, cursor, None, ctx)
505 };
506
507 // Clang plays with us at "find the calling convention", see #549 and
508 // co. This seems to be a better fix than that commit.
509 let mut call_conv = ty.call_conv();
510 if let Some(ty) = cursor.cur_type().canonical_type().pointee_type() {
511 let cursor_call_conv = ty.call_conv();
512 if cursor_call_conv != CXCallingConv_Invalid {
513 call_conv = cursor_call_conv;
514 }
515 }
516 let abi = get_abi(call_conv);
517
518 if abi.is_unknown() {
519 warn!("Unknown calling convention: {:?}", call_conv);
520 }
521
522 Ok(Self::new(ret, args, ty.is_variadic(), must_use, abi))
523 }
524
525 /// Get this function signature's return type.
return_type(&self) -> TypeId526 pub fn return_type(&self) -> TypeId {
527 self.return_type
528 }
529
530 /// Get this function signature's argument (name, type) pairs.
argument_types(&self) -> &[(Option<String>, TypeId)]531 pub fn argument_types(&self) -> &[(Option<String>, TypeId)] {
532 &self.argument_types
533 }
534
535 /// Get this function signature's ABI.
abi(&self) -> Abi536 pub fn abi(&self) -> Abi {
537 self.abi
538 }
539
540 /// Is this function signature variadic?
is_variadic(&self) -> bool541 pub fn is_variadic(&self) -> bool {
542 // Clang reports some functions as variadic when they *might* be
543 // variadic. We do the argument check because rust doesn't codegen well
544 // variadic functions without an initial argument.
545 self.is_variadic && !self.argument_types.is_empty()
546 }
547
548 /// Must this function's return value be used?
must_use(&self) -> bool549 pub fn must_use(&self) -> bool {
550 self.must_use
551 }
552
553 /// Are function pointers with this signature able to derive Rust traits?
554 /// Rust only supports deriving traits for function pointers with a limited
555 /// number of parameters and a couple ABIs.
556 ///
557 /// For more details, see:
558 ///
559 /// * https://github.com/rust-lang/rust-bindgen/issues/547,
560 /// * https://github.com/rust-lang/rust/issues/38848,
561 /// * and https://github.com/rust-lang/rust/issues/40158
function_pointers_can_derive(&self) -> bool562 pub fn function_pointers_can_derive(&self) -> bool {
563 if self.argument_types.len() > RUST_DERIVE_FUNPTR_LIMIT {
564 return false;
565 }
566
567 matches!(self.abi, Abi::C | Abi::Unknown(..))
568 }
569 }
570
571 impl ClangSubItemParser for Function {
parse( cursor: clang::Cursor, context: &mut BindgenContext, ) -> Result<ParseResult<Self>, ParseError>572 fn parse(
573 cursor: clang::Cursor,
574 context: &mut BindgenContext,
575 ) -> Result<ParseResult<Self>, ParseError> {
576 use clang_sys::*;
577
578 let kind = match FunctionKind::from_cursor(&cursor) {
579 None => return Err(ParseError::Continue),
580 Some(k) => k,
581 };
582
583 debug!("Function::parse({:?}, {:?})", cursor, cursor.cur_type());
584
585 let visibility = cursor.visibility();
586 if visibility != CXVisibility_Default {
587 return Err(ParseError::Continue);
588 }
589
590 if cursor.access_specifier() == CX_CXXPrivate {
591 return Err(ParseError::Continue);
592 }
593
594 if cursor.is_inlined_function() {
595 if !context.options().generate_inline_functions {
596 return Err(ParseError::Continue);
597 }
598 if cursor.is_deleted_function() {
599 return Err(ParseError::Continue);
600 }
601 }
602
603 let linkage = cursor.linkage();
604 let linkage = match linkage {
605 CXLinkage_External | CXLinkage_UniqueExternal => Linkage::External,
606 CXLinkage_Internal => Linkage::Internal,
607 _ => return Err(ParseError::Continue),
608 };
609
610 // Grab the signature using Item::from_ty.
611 let sig = Item::from_ty(&cursor.cur_type(), cursor, None, context)?;
612
613 let mut name = cursor.spelling();
614 assert!(!name.is_empty(), "Empty function name?");
615
616 if cursor.kind() == CXCursor_Destructor {
617 // Remove the leading `~`. The alternative to this is special-casing
618 // code-generation for destructor functions, which seems less than
619 // ideal.
620 if name.starts_with('~') {
621 name.remove(0);
622 }
623
624 // Add a suffix to avoid colliding with constructors. This would be
625 // technically fine (since we handle duplicated functions/methods),
626 // but seems easy enough to handle it here.
627 name.push_str("_destructor");
628 }
629
630 let mangled_name = cursor_mangling(context, &cursor);
631 let comment = cursor.raw_comment();
632
633 let function =
634 Self::new(name, mangled_name, sig, comment, kind, linkage);
635 Ok(ParseResult::New(function, Some(cursor)))
636 }
637 }
638
639 impl Trace for FunctionSig {
640 type Extra = ();
641
trace<T>(&self, _: &BindgenContext, tracer: &mut T, _: &()) where T: Tracer,642 fn trace<T>(&self, _: &BindgenContext, tracer: &mut T, _: &())
643 where
644 T: Tracer,
645 {
646 tracer.visit_kind(self.return_type().into(), EdgeKind::FunctionReturn);
647
648 for &(_, ty) in self.argument_types() {
649 tracer.visit_kind(ty.into(), EdgeKind::FunctionParameter);
650 }
651 }
652 }
653