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