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