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