autocxx_bindgen/ir/
ty.rs

1//! Everything related to types in our intermediate representation.
2
3use super::comp::CompInfo;
4use super::context::{BindgenContext, ItemId, TypeId};
5use super::dot::DotAttributes;
6use super::enum_ty::Enum;
7use super::function::FunctionSig;
8use super::item::{IsOpaque, Item};
9use super::layout::{Layout, Opaque};
10use super::objc::ObjCInterface;
11use super::template::{
12    AsTemplateParam, TemplateInstantiation, TemplateParameters,
13};
14use super::traversal::{EdgeKind, Trace, Tracer};
15use crate::clang::{self, Cursor};
16use crate::ir::function::Visibility;
17use crate::parse::{ParseError, ParseResult};
18use std::borrow::Cow;
19use std::io;
20
21pub use super::int::IntKind;
22
23/// The base representation of a type in bindgen.
24///
25/// A type has an optional name, which if present cannot be empty, a `layout`
26/// (size, alignment and packedness) if known, a `Kind`, which determines which
27/// kind of type it is, and whether the type is const.
28#[derive(Debug)]
29pub(crate) struct Type {
30    /// The name of the type, or None if it was an unnamed struct or union.
31    name: Option<String>,
32    /// The layout of the type, if known.
33    layout: Option<Layout>,
34    /// The inner kind of the type
35    kind: TypeKind,
36    /// Whether this type is const-qualified.
37    is_const: bool,
38}
39
40/// The maximum number of items in an array for which Rust implements common
41/// traits, and so if we have a type containing an array with more than this
42/// many items, we won't be able to derive common traits on that type.
43///
44pub(crate) const RUST_DERIVE_IN_ARRAY_LIMIT: usize = 32;
45
46impl Type {
47    /// Get the underlying `CompInfo` for this type as a mutable reference, or
48    /// `None` if this is some other kind of type.
49    pub(crate) fn as_comp_mut(&mut self) -> Option<&mut CompInfo> {
50        match self.kind {
51            TypeKind::Comp(ref mut ci) => Some(ci),
52            _ => None,
53        }
54    }
55
56    /// Construct a new `Type`.
57    pub(crate) fn new(
58        name: Option<String>,
59        layout: Option<Layout>,
60        kind: TypeKind,
61        is_const: bool,
62    ) -> Self {
63        Type {
64            name,
65            layout,
66            kind,
67            is_const,
68        }
69    }
70
71    /// Which kind of type is this?
72    pub(crate) fn kind(&self) -> &TypeKind {
73        &self.kind
74    }
75
76    /// Get a mutable reference to this type's kind.
77    pub(crate) fn kind_mut(&mut self) -> &mut TypeKind {
78        &mut self.kind
79    }
80
81    /// Get this type's name.
82    pub(crate) fn name(&self) -> Option<&str> {
83        self.name.as_deref()
84    }
85
86    /// Whether this is a block pointer type.
87    pub(crate) fn is_block_pointer(&self) -> bool {
88        matches!(self.kind, TypeKind::BlockPointer(..))
89    }
90
91    /// Is this an integer type, including `bool` or `char`?
92    pub(crate) fn is_int(&self) -> bool {
93        matches!(self.kind, TypeKind::Int(_))
94    }
95
96    /// Is this a compound type?
97    pub(crate) fn is_comp(&self) -> bool {
98        matches!(self.kind, TypeKind::Comp(..))
99    }
100
101    /// Is this a union?
102    pub(crate) fn is_union(&self) -> bool {
103        match self.kind {
104            TypeKind::Comp(ref comp) => comp.is_union(),
105            _ => false,
106        }
107    }
108
109    /// Is this type of kind `TypeKind::TypeParam`?
110    pub(crate) fn is_type_param(&self) -> bool {
111        matches!(self.kind, TypeKind::TypeParam)
112    }
113
114    /// Is this a template instantiation type?
115    pub(crate) fn is_template_instantiation(&self) -> bool {
116        matches!(self.kind, TypeKind::TemplateInstantiation(..))
117    }
118
119    /// Is this a function type?
120    pub(crate) fn is_function(&self) -> bool {
121        matches!(self.kind, TypeKind::Function(..))
122    }
123
124    /// Is this an enum type?
125    pub(crate) fn is_enum(&self) -> bool {
126        matches!(self.kind, TypeKind::Enum(..))
127    }
128
129    /// Is this void?
130    pub(crate) fn is_void(&self) -> bool {
131        matches!(self.kind, TypeKind::Void)
132    }
133    /// Is this either a builtin or named type?
134    pub(crate) fn is_builtin_or_type_param(&self) -> bool {
135        matches!(
136            self.kind,
137            TypeKind::Void |
138                TypeKind::NullPtr |
139                TypeKind::Function(..) |
140                TypeKind::Array(..) |
141                TypeKind::Reference(..) |
142                TypeKind::Pointer(..) |
143                TypeKind::Int(..) |
144                TypeKind::Float(..) |
145                TypeKind::TypeParam
146        )
147    }
148
149    /// Creates a new named type, with name `name`.
150    pub(crate) fn named(name: String) -> Self {
151        let name = if name.is_empty() { None } else { Some(name) };
152        Self::new(name, None, TypeKind::TypeParam, false)
153    }
154
155    /// Is this a floating point type?
156    pub(crate) fn is_float(&self) -> bool {
157        matches!(self.kind, TypeKind::Float(..))
158    }
159
160    /// Is this a boolean type?
161    pub(crate) fn is_bool(&self) -> bool {
162        matches!(self.kind, TypeKind::Int(IntKind::Bool))
163    }
164
165    /// Is this an integer type?
166    pub(crate) fn is_integer(&self) -> bool {
167        matches!(self.kind, TypeKind::Int(..))
168    }
169
170    /// Cast this type to an integer kind, or `None` if it is not an integer
171    /// type.
172    pub(crate) fn as_integer(&self) -> Option<IntKind> {
173        match self.kind {
174            TypeKind::Int(int_kind) => Some(int_kind),
175            _ => None,
176        }
177    }
178
179    /// Is this a `const` qualified type?
180    pub(crate) fn is_const(&self) -> bool {
181        self.is_const
182    }
183
184    /// Is this an unresolved reference?
185    pub(crate) fn is_unresolved_ref(&self) -> bool {
186        matches!(self.kind, TypeKind::UnresolvedTypeRef(_, _, _))
187    }
188
189    /// Is this a incomplete array type?
190    pub(crate) fn is_incomplete_array(
191        &self,
192        ctx: &BindgenContext,
193    ) -> Option<ItemId> {
194        match self.kind {
195            TypeKind::Array(item, len) => {
196                if len == 0 {
197                    Some(item.into())
198                } else {
199                    None
200                }
201            }
202            TypeKind::ResolvedTypeRef(inner) => {
203                ctx.resolve_type(inner).is_incomplete_array(ctx)
204            }
205            _ => None,
206        }
207    }
208
209    /// What is the layout of this type?
210    pub(crate) fn layout(&self, ctx: &BindgenContext) -> Option<Layout> {
211        self.layout.or_else(|| {
212            match self.kind {
213                TypeKind::Comp(ref ci) => ci.layout(ctx),
214                TypeKind::Array(inner, 0) => Some(Layout::new(
215                    0,
216                    ctx.resolve_type(inner).layout(ctx)?.align,
217                )),
218                // FIXME(emilio): This is a hack for anonymous union templates.
219                // Use the actual pointer size!
220                TypeKind::Pointer(..) => Some(Layout::new(
221                    ctx.target_pointer_size(),
222                    ctx.target_pointer_size(),
223                )),
224                TypeKind::ResolvedTypeRef(inner) => {
225                    ctx.resolve_type(inner).layout(ctx)
226                }
227                _ => None,
228            }
229        })
230    }
231
232    /// Whether this named type is an invalid C++ identifier. This is done to
233    /// avoid generating invalid code with some cases we can't handle, see:
234    ///
235    /// tests/headers/381-decltype-alias.hpp
236    pub(crate) fn is_invalid_type_param(&self) -> bool {
237        match self.kind {
238            TypeKind::TypeParam => {
239                let name = self.name().expect("Unnamed named type?");
240                !clang::is_valid_identifier(name)
241            }
242            _ => false,
243        }
244    }
245
246    /// Takes `name`, and returns a suitable identifier representation for it.
247    fn sanitize_name(name: &str) -> Cow<str> {
248        if clang::is_valid_identifier(name) {
249            return Cow::Borrowed(name);
250        }
251
252        let name = name.replace([' ', ':', '.'], "_");
253        Cow::Owned(name)
254    }
255
256    /// Get this type's sanitized name.
257    pub(crate) fn sanitized_name<'a>(
258        &'a self,
259        ctx: &BindgenContext,
260    ) -> Option<Cow<'a, str>> {
261        let name_info = match *self.kind() {
262            TypeKind::Pointer(inner) => Some((inner, Cow::Borrowed("ptr"))),
263            TypeKind::Reference(inner, _) => {
264                Some((inner, Cow::Borrowed("ref")))
265            }
266            TypeKind::Array(inner, length) => {
267                Some((inner, format!("array{length}").into()))
268            }
269            _ => None,
270        };
271        if let Some((inner, prefix)) = name_info {
272            ctx.resolve_item(inner)
273                .expect_type()
274                .sanitized_name(ctx)
275                .map(|name| format!("{prefix}_{name}").into())
276        } else {
277            self.name().map(Self::sanitize_name)
278        }
279    }
280
281    /// See [`Self::safe_canonical_type`].
282    pub(crate) fn canonical_type<'tr>(
283        &'tr self,
284        ctx: &'tr BindgenContext,
285    ) -> &'tr Type {
286        self.safe_canonical_type(ctx)
287            .expect("Should have been resolved after parsing!")
288    }
289
290    /// Returns the canonical type of this type, that is, the "inner type".
291    ///
292    /// For example, for a `typedef`, the canonical type would be the
293    /// `typedef`ed type, for a template instantiation, would be the template
294    /// its specializing, and so on. Return None if the type is unresolved.
295    pub(crate) fn safe_canonical_type<'tr>(
296        &'tr self,
297        ctx: &'tr BindgenContext,
298    ) -> Option<&'tr Type> {
299        match self.kind {
300            TypeKind::TypeParam |
301            TypeKind::Array(..) |
302            TypeKind::Vector(..) |
303            TypeKind::Comp(..) |
304            TypeKind::Opaque |
305            TypeKind::Int(..) |
306            TypeKind::Float(..) |
307            TypeKind::Complex(..) |
308            TypeKind::Function(..) |
309            TypeKind::Enum(..) |
310            TypeKind::Reference(..) |
311            TypeKind::Void |
312            TypeKind::NullPtr |
313            TypeKind::Pointer(..) |
314            TypeKind::BlockPointer(..) |
315            TypeKind::ObjCId |
316            TypeKind::ObjCSel |
317            TypeKind::ObjCInterface(..) => Some(self),
318
319            TypeKind::ResolvedTypeRef(inner) |
320            TypeKind::Alias(inner) |
321            TypeKind::TemplateAlias(inner, _) => {
322                ctx.resolve_type(inner).safe_canonical_type(ctx)
323            }
324            TypeKind::TemplateInstantiation(ref inst) => ctx
325                .resolve_type(inst.template_definition())
326                .safe_canonical_type(ctx),
327
328            TypeKind::UnresolvedTypeRef(..) => None,
329        }
330    }
331
332    /// There are some types we don't want to stop at when finding an opaque
333    /// item, so we can arrive to the proper item that needs to be generated.
334    pub(crate) fn should_be_traced_unconditionally(&self) -> bool {
335        matches!(
336            self.kind,
337            TypeKind::Comp(..) |
338                TypeKind::Function(..) |
339                TypeKind::Pointer(..) |
340                TypeKind::Array(..) |
341                TypeKind::Reference(..) |
342                TypeKind::TemplateInstantiation(..) |
343                TypeKind::ResolvedTypeRef(..)
344        )
345    }
346}
347
348impl IsOpaque for Type {
349    type Extra = Item;
350
351    fn is_opaque(&self, ctx: &BindgenContext, item: &Item) -> bool {
352        match self.kind {
353            TypeKind::Opaque => true,
354            TypeKind::TemplateInstantiation(ref inst) => {
355                inst.is_opaque(ctx, item)
356            }
357            TypeKind::Comp(ref comp) => comp.is_opaque(ctx, &self.layout),
358            TypeKind::ResolvedTypeRef(to) => to.is_opaque(ctx, &()),
359            _ => false,
360        }
361    }
362}
363
364impl AsTemplateParam for Type {
365    type Extra = Item;
366
367    fn as_template_param(
368        &self,
369        ctx: &BindgenContext,
370        item: &Item,
371    ) -> Option<TypeId> {
372        self.kind.as_template_param(ctx, item)
373    }
374}
375
376impl AsTemplateParam for TypeKind {
377    type Extra = Item;
378
379    fn as_template_param(
380        &self,
381        ctx: &BindgenContext,
382        item: &Item,
383    ) -> Option<TypeId> {
384        match *self {
385            TypeKind::TypeParam => Some(item.id().expect_type_id(ctx)),
386            TypeKind::ResolvedTypeRef(id) => id.as_template_param(ctx, &()),
387            _ => None,
388        }
389    }
390}
391
392impl DotAttributes for Type {
393    fn dot_attributes<W>(
394        &self,
395        ctx: &BindgenContext,
396        out: &mut W,
397    ) -> io::Result<()>
398    where
399        W: io::Write,
400    {
401        if let Some(ref layout) = self.layout {
402            writeln!(
403                out,
404                "<tr><td>size</td><td>{}</td></tr>
405                           <tr><td>align</td><td>{}</td></tr>",
406                layout.size, layout.align
407            )?;
408            if layout.packed {
409                writeln!(out, "<tr><td>packed</td><td>true</td></tr>")?;
410            }
411        }
412
413        if self.is_const {
414            writeln!(out, "<tr><td>const</td><td>true</td></tr>")?;
415        }
416
417        self.kind.dot_attributes(ctx, out)
418    }
419}
420
421impl DotAttributes for TypeKind {
422    fn dot_attributes<W>(
423        &self,
424        ctx: &BindgenContext,
425        out: &mut W,
426    ) -> io::Result<()>
427    where
428        W: io::Write,
429    {
430        writeln!(
431            out,
432            "<tr><td>type kind</td><td>{}</td></tr>",
433            self.kind_name()
434        )?;
435
436        if let TypeKind::Comp(ref comp) = *self {
437            comp.dot_attributes(ctx, out)?;
438        }
439
440        Ok(())
441    }
442}
443
444impl TypeKind {
445    fn kind_name(&self) -> &'static str {
446        match *self {
447            TypeKind::Void => "Void",
448            TypeKind::NullPtr => "NullPtr",
449            TypeKind::Comp(..) => "Comp",
450            TypeKind::Opaque => "Opaque",
451            TypeKind::Int(..) => "Int",
452            TypeKind::Float(..) => "Float",
453            TypeKind::Complex(..) => "Complex",
454            TypeKind::Alias(..) => "Alias",
455            TypeKind::TemplateAlias(..) => "TemplateAlias",
456            TypeKind::Array(..) => "Array",
457            TypeKind::Vector(..) => "Vector",
458            TypeKind::Function(..) => "Function",
459            TypeKind::Enum(..) => "Enum",
460            TypeKind::Pointer(..) => "Pointer",
461            TypeKind::BlockPointer(..) => "BlockPointer",
462            TypeKind::Reference(..) => "Reference",
463            TypeKind::TemplateInstantiation(..) => "TemplateInstantiation",
464            TypeKind::UnresolvedTypeRef(..) => "UnresolvedTypeRef",
465            TypeKind::ResolvedTypeRef(..) => "ResolvedTypeRef",
466            TypeKind::TypeParam => "TypeParam",
467            TypeKind::ObjCInterface(..) => "ObjCInterface",
468            TypeKind::ObjCId => "ObjCId",
469            TypeKind::ObjCSel => "ObjCSel",
470        }
471    }
472}
473
474#[test]
475fn is_invalid_type_param_valid() {
476    let ty = Type::new(Some("foo".into()), None, TypeKind::TypeParam, false);
477    assert!(!ty.is_invalid_type_param());
478}
479
480#[test]
481fn is_invalid_type_param_valid_underscore_and_numbers() {
482    let ty = Type::new(
483        Some("_foo123456789_".into()),
484        None,
485        TypeKind::TypeParam,
486        false,
487    );
488    assert!(!ty.is_invalid_type_param());
489}
490
491#[test]
492fn is_invalid_type_param_valid_unnamed_kind() {
493    let ty = Type::new(Some("foo".into()), None, TypeKind::Void, false);
494    assert!(!ty.is_invalid_type_param());
495}
496
497#[test]
498fn is_invalid_type_param_invalid_start() {
499    let ty = Type::new(Some("1foo".into()), None, TypeKind::TypeParam, false);
500    assert!(ty.is_invalid_type_param());
501}
502
503#[test]
504fn is_invalid_type_param_invalid_remaining() {
505    let ty = Type::new(Some("foo-".into()), None, TypeKind::TypeParam, false);
506    assert!(ty.is_invalid_type_param());
507}
508
509#[test]
510#[should_panic(expected = "Unnamed named type")]
511fn is_invalid_type_param_unnamed() {
512    let ty = Type::new(None, None, TypeKind::TypeParam, false);
513    assert!(ty.is_invalid_type_param());
514}
515
516#[test]
517fn is_invalid_type_param_empty_name() {
518    let ty = Type::new(Some(String::new()), None, TypeKind::TypeParam, false);
519    assert!(ty.is_invalid_type_param());
520}
521
522impl TemplateParameters for Type {
523    fn self_template_params(&self, ctx: &BindgenContext) -> Vec<TypeId> {
524        self.kind.self_template_params(ctx)
525    }
526}
527
528impl TemplateParameters for TypeKind {
529    fn self_template_params(&self, ctx: &BindgenContext) -> Vec<TypeId> {
530        match *self {
531            TypeKind::ResolvedTypeRef(id) => {
532                ctx.resolve_type(id).self_template_params(ctx)
533            }
534            TypeKind::Comp(ref comp) => comp.self_template_params(ctx),
535            TypeKind::TemplateAlias(_, ref args) => args.clone(),
536
537            TypeKind::Opaque |
538            TypeKind::TemplateInstantiation(..) |
539            TypeKind::Void |
540            TypeKind::NullPtr |
541            TypeKind::Int(_) |
542            TypeKind::Float(_) |
543            TypeKind::Complex(_) |
544            TypeKind::Array(..) |
545            TypeKind::Vector(..) |
546            TypeKind::Function(_) |
547            TypeKind::Enum(_) |
548            TypeKind::Pointer(_) |
549            TypeKind::BlockPointer(_) |
550            TypeKind::Reference(..) |
551            TypeKind::UnresolvedTypeRef(..) |
552            TypeKind::TypeParam |
553            TypeKind::Alias(_) |
554            TypeKind::ObjCId |
555            TypeKind::ObjCSel |
556            TypeKind::ObjCInterface(_) => vec![],
557        }
558    }
559}
560
561/// The kind of float this type represents.
562#[derive(Debug, Copy, Clone, PartialEq, Eq)]
563pub(crate) enum FloatKind {
564    /// A half (`_Float16` or `__fp16`)
565    Float16,
566    /// A `float`.
567    Float,
568    /// A `double`.
569    Double,
570    /// A `long double`.
571    LongDouble,
572    /// A `__float128`.
573    Float128,
574}
575
576/// The different kinds of types that we can parse.
577#[derive(Debug)]
578pub(crate) enum TypeKind {
579    /// The void type.
580    Void,
581
582    /// The `nullptr_t` type.
583    NullPtr,
584
585    /// A compound type, that is, a class, struct, or union.
586    Comp(CompInfo),
587
588    /// An opaque type that we just don't understand. All usage of this should
589    /// result in an opaque blob of bytes generated from the containing type's
590    /// layout.
591    Opaque,
592
593    /// An integer type, of a given kind. `bool` and `char` are also considered
594    /// integers.
595    Int(IntKind),
596
597    /// A floating point type.
598    Float(FloatKind),
599
600    /// A complex floating point type.
601    Complex(FloatKind),
602
603    /// A type alias, with a name, that points to another type.
604    Alias(TypeId),
605
606    /// A templated alias, pointing to an inner type, just as `Alias`, but with
607    /// template parameters.
608    TemplateAlias(TypeId, Vec<TypeId>),
609
610    /// A packed vector type: element type, number of elements
611    Vector(TypeId, usize),
612
613    /// An array of a type and a length.
614    Array(TypeId, usize),
615
616    /// A function type, with a given signature.
617    Function(FunctionSig),
618
619    /// An `enum` type.
620    Enum(Enum),
621
622    /// A pointer to a type. The bool field represents whether it's const or
623    /// not.
624    Pointer(TypeId),
625
626    /// A pointer to an Apple block.
627    BlockPointer(TypeId),
628
629    /// A reference to a type, as in: int& `foo()`.
630    /// The bool represents whether it's rvalue.
631    Reference(TypeId, bool),
632
633    /// An instantiation of an abstract template definition with a set of
634    /// concrete template arguments.
635    TemplateInstantiation(TemplateInstantiation),
636
637    /// A reference to a yet-to-resolve type. This stores the clang cursor
638    /// itself, and postpones its resolution.
639    ///
640    /// These are gone in a phase after parsing where these are mapped to
641    /// already known types, and are converted to `ResolvedTypeRef`.
642    ///
643    /// see tests/headers/typeref.hpp to see somewhere where this is a problem.
644    UnresolvedTypeRef(clang::Type, Cursor, /* parent_id */ Option<ItemId>),
645
646    /// An indirection to another type.
647    ///
648    /// These are generated after we resolve a forward declaration, or when we
649    /// replace one type with another.
650    ResolvedTypeRef(TypeId),
651
652    /// A named type, that is, a template parameter.
653    TypeParam,
654
655    /// Objective C interface. Always referenced through a pointer
656    ObjCInterface(ObjCInterface),
657
658    /// Objective C 'id' type, points to any object
659    ObjCId,
660
661    /// Objective C selector type
662    ObjCSel,
663}
664
665impl Type {
666    /// This is another of the nasty methods. This one is the one that takes
667    /// care of the core logic of converting a clang type to a `Type`.
668    ///
669    /// It's sort of nasty and full of special-casing, but hopefully the
670    /// comments in every special case justify why they're there.
671    pub(crate) fn from_clang_ty(
672        potential_id: ItemId,
673        ty: &clang::Type,
674        location: Cursor,
675        parent_id: Option<ItemId>,
676        ctx: &mut BindgenContext,
677    ) -> Result<ParseResult<Self>, ParseError> {
678        use clang_sys::*;
679        {
680            let already_resolved = ctx.builtin_or_resolved_ty(
681                potential_id,
682                parent_id,
683                ty,
684                Some(location),
685            );
686            if let Some(ty) = already_resolved {
687                debug!("{ty:?} already resolved: {location:?}");
688                return Ok(ParseResult::AlreadyResolved(ty.into()));
689            }
690        }
691
692        let layout = ty.fallible_layout(ctx).ok();
693        let cursor = ty.declaration();
694        let is_anonymous = cursor.is_anonymous();
695        let mut name = if is_anonymous {
696            None
697        } else {
698            Some(cursor.spelling()).filter(|n| !n.is_empty())
699        };
700
701        debug!(
702            "from_clang_ty: {potential_id:?}, ty: {ty:?}, loc: {location:?}"
703        );
704        debug!("currently_parsed_types: {:?}", ctx.currently_parsed_types());
705
706        let canonical_ty = ty.canonical_type();
707
708        // Parse objc protocols as if they were interfaces
709        let mut ty_kind = ty.kind();
710        match location.kind() {
711            CXCursor_ObjCProtocolDecl | CXCursor_ObjCCategoryDecl => {
712                ty_kind = CXType_ObjCInterface;
713            }
714            _ => {}
715        }
716
717        // Objective C template type parameter
718        // FIXME: This is probably wrong, we are attempting to find the
719        //        objc template params, which seem to manifest as a typedef.
720        //        We are rewriting them as ID to suppress multiple conflicting
721        //        typedefs at root level
722        if ty_kind == CXType_Typedef {
723            let is_template_type_param =
724                ty.declaration().kind() == CXCursor_TemplateTypeParameter;
725            let is_canonical_objcpointer =
726                canonical_ty.kind() == CXType_ObjCObjectPointer;
727
728            // We have found a template type for objc interface
729            if is_canonical_objcpointer && is_template_type_param {
730                // Objective-C generics are just ids with fancy name.
731                // To keep it simple, just name them ids
732                name = Some("id".to_owned());
733            }
734        }
735
736        if location.kind() == CXCursor_ClassTemplatePartialSpecialization {
737            // Sorry! (Not sorry)
738            warn!(
739                "Found a partial template specialization; bindgen does not \
740                 support partial template specialization! Constructing \
741                 opaque type instead."
742            );
743            return Ok(ParseResult::New(
744                Opaque::from_clang_ty(&canonical_ty, ctx),
745                None,
746            ));
747        }
748
749        let kind = if location.kind() == CXCursor_TemplateRef ||
750            (ty.template_args().is_some() && ty_kind != CXType_Typedef)
751        {
752            // This is a template instantiation.
753            match TemplateInstantiation::from_ty(ty, ctx) {
754                Some(inst) => TypeKind::TemplateInstantiation(inst),
755                None => TypeKind::Opaque,
756            }
757        } else {
758            match ty_kind {
759                CXType_Unexposed
760                    if *ty != canonical_ty &&
761                                    canonical_ty.kind() != CXType_Invalid &&
762                                    ty.ret_type().is_none() &&
763                                    // Sometime clang desugars some types more than
764                                    // what we need, specially with function
765                                    // pointers.
766                                    //
767                                    // We should also try the solution of inverting
768                                    // those checks instead of doing this, that is,
769                                    // something like:
770                                    //
771                                    // CXType_Unexposed if ty.ret_type().is_some()
772                                    //   => { ... }
773                                    //
774                                    // etc.
775                                    !canonical_ty.spelling().contains("type-parameter") =>
776                {
777                    debug!("Looking for canonical type: {canonical_ty:?}");
778                    return Self::from_clang_ty(
779                        potential_id,
780                        &canonical_ty,
781                        location,
782                        parent_id,
783                        ctx,
784                    );
785                }
786                CXType_Unexposed | CXType_Invalid => {
787                    // For some reason Clang doesn't give us any hint in some
788                    // situations where we should generate a function pointer (see
789                    // tests/headers/func_ptr_in_struct.h), so we do a guess here
790                    // trying to see if it has a valid return type.
791                    if ty.ret_type().is_some() {
792                        let signature =
793                            FunctionSig::from_ty(ty, &location, ctx)?;
794                        TypeKind::Function(signature)
795                    // Same here, with template specialisations we can safely
796                    // assume this is a Comp(..)
797                    } else if ty.is_fully_instantiated_template() {
798                        debug!("Template specialization: {ty:?}, {location:?} {canonical_ty:?}");
799                        let complex = CompInfo::from_ty(
800                            potential_id,
801                            ty,
802                            Some(location),
803                            ctx,
804                        )
805                        .expect("C'mon");
806                        TypeKind::Comp(complex)
807                    } else {
808                        match location.kind() {
809                            CXCursor_CXXBaseSpecifier |
810                            CXCursor_ClassTemplate => {
811                                if location.kind() == CXCursor_CXXBaseSpecifier
812                                {
813                                    // In the case we're parsing a base specifier
814                                    // inside an unexposed or invalid type, it means
815                                    // that we're parsing one of two things:
816                                    //
817                                    //  * A template parameter.
818                                    //  * A complex class that isn't exposed.
819                                    //
820                                    // This means, unfortunately, that there's no
821                                    // good way to differentiate between them.
822                                    //
823                                    // Probably we could try to look at the
824                                    // declaration and complicate more this logic,
825                                    // but we'll keep it simple... if it's a valid
826                                    // C++ identifier, we'll consider it as a
827                                    // template parameter.
828                                    //
829                                    // This is because:
830                                    //
831                                    //  * We expect every other base that is a
832                                    //    proper identifier (that is, a simple
833                                    //    struct/union declaration), to be exposed,
834                                    //    so this path can't be reached in that
835                                    //    case.
836                                    //
837                                    //  * Quite conveniently, complex base
838                                    //    specifiers preserve their full names (that
839                                    //    is: Foo<T> instead of Foo). We can take
840                                    //    advantage of this.
841                                    //
842                                    // If we find some edge case where this doesn't
843                                    // work (which I guess is unlikely, see the
844                                    // different test cases[1][2][3][4]), we'd need
845                                    // to find more creative ways of differentiating
846                                    // these two cases.
847                                    //
848                                    // [1]: inherit_named.hpp
849                                    // [2]: forward-inherit-struct-with-fields.hpp
850                                    // [3]: forward-inherit-struct.hpp
851                                    // [4]: inherit-namespaced.hpp
852                                    if location.spelling().chars().all(|c| {
853                                        c.is_alphanumeric() || c == '_'
854                                    }) {
855                                        return Err(ParseError::Recurse);
856                                    }
857                                } else {
858                                    name = Some(location.spelling());
859                                }
860
861                                let complex = CompInfo::from_ty(
862                                    potential_id,
863                                    ty,
864                                    Some(location),
865                                    ctx,
866                                );
867                                if let Ok(complex) = complex {
868                                    TypeKind::Comp(complex)
869                                } else {
870                                    warn!(
871                                        "Could not create complex type \
872                                         from class template or base \
873                                         specifier, using opaque blob"
874                                    );
875                                    let opaque = Opaque::from_clang_ty(ty, ctx);
876                                    return Ok(ParseResult::New(opaque, None));
877                                }
878                            }
879                            CXCursor_TypeAliasTemplateDecl => {
880                                debug!("TypeAliasTemplateDecl");
881
882                                // We need to manually unwind this one.
883                                let mut inner = Err(ParseError::Continue);
884                                let mut args = vec![];
885
886                                location.visit(|cur| {
887                                    match cur.kind() {
888                                        CXCursor_TypeAliasDecl => {
889                                            let current = cur.cur_type();
890
891                                            debug_assert_eq!(
892                                                current.kind(),
893                                                CXType_Typedef
894                                            );
895
896                                            name = Some(location.spelling());
897
898                                            let inner_ty = cur
899                                                .typedef_type()
900                                                .expect("Not valid Type?");
901                                            inner = Ok(Item::from_ty_or_ref(
902                                                inner_ty,
903                                                cur,
904                                                Some(potential_id),
905                                                ctx,
906                                            ));
907                                        }
908                                        CXCursor_TemplateTypeParameter => {
909                                            let param = Item::type_param(
910                                                None, cur, ctx,
911                                            )
912                                            .expect(
913                                                "Item::type_param shouldn't \
914                                                 ever fail if we are looking \
915                                                 at a TemplateTypeParameter",
916                                            );
917                                            args.push(param);
918                                        }
919                                        _ => {}
920                                    }
921                                    CXChildVisit_Continue
922                                });
923
924                                let Ok(inner_type) = inner else {
925                                    warn!(
926                                        "Failed to parse template alias \
927                                             {:?}",
928                                        location
929                                    );
930                                    return Err(ParseError::Continue);
931                                };
932
933                                TypeKind::TemplateAlias(inner_type, args)
934                            }
935                            CXCursor_TemplateRef => {
936                                let referenced = location.referenced().unwrap();
937                                let referenced_ty = referenced.cur_type();
938
939                                debug!("TemplateRef: location = {location:?}; referenced = {referenced:?}; referenced_ty = {referenced_ty:?}");
940
941                                return Self::from_clang_ty(
942                                    potential_id,
943                                    &referenced_ty,
944                                    referenced,
945                                    parent_id,
946                                    ctx,
947                                );
948                            }
949                            CXCursor_TypeRef => {
950                                let referenced = location.referenced().unwrap();
951                                let referenced_ty = referenced.cur_type();
952                                let declaration = referenced_ty.declaration();
953
954                                debug!("TypeRef: location = {location:?}; referenced = {referenced:?}; referenced_ty = {referenced_ty:?}");
955
956                                let id = Item::from_ty_or_ref_with_id(
957                                    potential_id,
958                                    referenced_ty,
959                                    declaration,
960                                    parent_id,
961                                    ctx,
962                                );
963                                return Ok(ParseResult::AlreadyResolved(
964                                    id.into(),
965                                ));
966                            }
967                            CXCursor_NamespaceRef => {
968                                return Err(ParseError::Continue);
969                            }
970                            _ => {
971                                if ty.kind() == CXType_Unexposed {
972                                    warn!("Unexposed type {ty:?}, recursing inside, loc: {location:?}");
973                                    return Err(ParseError::Recurse);
974                                }
975
976                                warn!("invalid type {ty:?}");
977                                return Err(ParseError::Continue);
978                            }
979                        }
980                    }
981                }
982                CXType_Auto => {
983                    if canonical_ty == *ty {
984                        debug!("Couldn't find deduced type: {ty:?}");
985                        return Err(ParseError::Continue);
986                    }
987
988                    return Self::from_clang_ty(
989                        potential_id,
990                        &canonical_ty,
991                        location,
992                        parent_id,
993                        ctx,
994                    );
995                }
996                // NOTE: We don't resolve pointers eagerly because the pointee type
997                // might not have been parsed, and if it contains templates or
998                // something else we might get confused, see the comment inside
999                // TypeRef.
1000                //
1001                // We might need to, though, if the context is already in the
1002                // process of resolving them.
1003                CXType_ObjCObjectPointer |
1004                CXType_MemberPointer |
1005                CXType_Pointer => {
1006                    let mut pointee = ty.pointee_type().unwrap();
1007                    if *ty != canonical_ty {
1008                        let canonical_pointee =
1009                            canonical_ty.pointee_type().unwrap();
1010                        // clang sometimes loses pointee constness here, see
1011                        // #2244.
1012                        if canonical_pointee.is_const() != pointee.is_const() {
1013                            pointee = canonical_pointee;
1014                        }
1015                    }
1016                    let inner =
1017                        Item::from_ty_or_ref(pointee, location, None, ctx);
1018                    TypeKind::Pointer(inner)
1019                }
1020                CXType_BlockPointer => {
1021                    let pointee = ty.pointee_type().expect("Not valid Type?");
1022                    let inner =
1023                        Item::from_ty_or_ref(pointee, location, None, ctx);
1024                    TypeKind::BlockPointer(inner)
1025                }
1026                // XXX: RValueReference is most likely wrong, but I don't think we
1027                // can even add bindings for that, so huh.
1028                CXType_LValueReference => {
1029                    let inner = Item::from_ty_or_ref(
1030                        ty.pointee_type().unwrap(),
1031                        location,
1032                        None,
1033                        ctx,
1034                    );
1035                    TypeKind::Reference(inner, false)
1036                }
1037                CXType_RValueReference => {
1038                    let inner = Item::from_ty_or_ref(
1039                        ty.pointee_type().unwrap(),
1040                        location,
1041                        None,
1042                        ctx,
1043                    );
1044                    TypeKind::Reference(inner, true)
1045                }
1046                // XXX DependentSizedArray is wrong
1047                CXType_VariableArray | CXType_DependentSizedArray => {
1048                    let inner = Item::from_ty(
1049                        ty.elem_type().as_ref().unwrap(),
1050                        location,
1051                        None,
1052                        ctx,
1053                    )
1054                    .expect("Not able to resolve array element?");
1055                    TypeKind::Pointer(inner)
1056                }
1057                CXType_IncompleteArray => {
1058                    let inner = Item::from_ty(
1059                        ty.elem_type().as_ref().unwrap(),
1060                        location,
1061                        None,
1062                        ctx,
1063                    )
1064                    .expect("Not able to resolve array element?");
1065                    TypeKind::Array(inner, 0)
1066                }
1067                CXType_FunctionNoProto | CXType_FunctionProto => {
1068                    let signature = FunctionSig::from_ty(ty, &location, ctx)?;
1069                    TypeKind::Function(signature)
1070                }
1071                CXType_Typedef => {
1072                    let inner = cursor.typedef_type().expect("Not valid Type?");
1073                    let inner_id =
1074                        Item::from_ty_or_ref(inner, location, None, ctx);
1075                    if inner_id == potential_id {
1076                        warn!(
1077                            "Generating opaque type instead of self-referential \
1078                            typedef");
1079                        // This can happen if we bail out of recursive situations
1080                        // within the clang parsing.
1081                        TypeKind::Opaque
1082                    } else {
1083                        // Check if this type definition is an alias to a pointer of a `struct` /
1084                        // `union` / `enum` with the same name and add the `_ptr` suffix to it to
1085                        // avoid name collisions.
1086                        if let Some(ref mut name) = name {
1087                            if inner.kind() == CXType_Pointer &&
1088                                !ctx.options().c_naming
1089                            {
1090                                let pointee = inner.pointee_type().unwrap();
1091                                if pointee.kind() == CXType_Elaborated &&
1092                                    pointee.declaration().spelling() == *name
1093                                {
1094                                    *name += "_ptr";
1095                                }
1096                            }
1097                        }
1098                        TypeKind::Alias(inner_id)
1099                    }
1100                }
1101                CXType_Enum => {
1102                    let visibility =
1103                        Visibility::from(cursor.access_specifier());
1104                    let enum_ = Enum::from_ty(ty, visibility, ctx)
1105                        .expect("Not an enum?");
1106
1107                    if !is_anonymous {
1108                        let pretty_name = ty.spelling();
1109                        if clang::is_valid_identifier(&pretty_name) {
1110                            name = Some(pretty_name);
1111                        }
1112                    }
1113
1114                    TypeKind::Enum(enum_)
1115                }
1116                CXType_Record => {
1117                    let complex = CompInfo::from_ty(
1118                        potential_id,
1119                        ty,
1120                        Some(location),
1121                        ctx,
1122                    )
1123                    .expect("Not a complex type?");
1124
1125                    if !is_anonymous {
1126                        // The pretty-printed name may contain typedefed name,
1127                        // but may also be "struct (anonymous at .h:1)"
1128                        let pretty_name = ty.spelling();
1129                        if clang::is_valid_identifier(&pretty_name) {
1130                            name = Some(pretty_name);
1131                        }
1132                    }
1133
1134                    TypeKind::Comp(complex)
1135                }
1136                CXType_Vector => {
1137                    let inner = Item::from_ty(
1138                        ty.elem_type().as_ref().unwrap(),
1139                        location,
1140                        None,
1141                        ctx,
1142                    )?;
1143                    TypeKind::Vector(inner, ty.num_elements().unwrap())
1144                }
1145                CXType_ConstantArray => {
1146                    let inner = Item::from_ty(
1147                        ty.elem_type().as_ref().unwrap(),
1148                        location,
1149                        None,
1150                        ctx,
1151                    )
1152                    .expect("Not able to resolve array element?");
1153                    TypeKind::Array(inner, ty.num_elements().unwrap())
1154                }
1155                CXType_Atomic => {
1156                    // TODO(emilio): Maybe we can preserve the "is atomic" bit somehow and generate
1157                    // something more useful... But for now this is better than panicking or
1158                    // generating nothing.
1159                    return Self::from_clang_ty(
1160                        potential_id,
1161                        &ty.atomic_value_type(),
1162                        location,
1163                        parent_id,
1164                        ctx,
1165                    );
1166                }
1167                CXType_Elaborated => {
1168                    return Self::from_clang_ty(
1169                        potential_id,
1170                        &ty.named(),
1171                        location,
1172                        parent_id,
1173                        ctx,
1174                    );
1175                }
1176                CXType_ObjCId => TypeKind::ObjCId,
1177                CXType_ObjCSel => TypeKind::ObjCSel,
1178                CXType_ObjCClass | CXType_ObjCInterface => {
1179                    let interface = ObjCInterface::from_ty(&location, ctx)
1180                        .expect("Not a valid objc interface?");
1181                    if !is_anonymous {
1182                        name = Some(interface.rust_name());
1183                    }
1184                    TypeKind::ObjCInterface(interface)
1185                }
1186                CXType_Dependent => {
1187                    return Err(ParseError::Continue);
1188                }
1189                _ => {
1190                    warn!(
1191                        "unsupported type: kind = {:?}; ty = {ty:?}; at {location:?}",
1192                        ty.kind(),
1193                    );
1194                    return Err(ParseError::Continue);
1195                }
1196            }
1197        };
1198
1199        name = name.filter(|n| !n.is_empty());
1200
1201        let is_const = ty.is_const() ||
1202            (ty.kind() == CXType_ConstantArray &&
1203                ty.elem_type().is_some_and(|element| element.is_const()));
1204
1205        let ty = Type::new(name, layout, kind, is_const);
1206        // TODO: maybe declaration.canonical()?
1207        Ok(ParseResult::New(ty, Some(cursor.canonical())))
1208    }
1209}
1210
1211impl Trace for Type {
1212    type Extra = Item;
1213
1214    fn trace<T>(&self, context: &BindgenContext, tracer: &mut T, item: &Item)
1215    where
1216        T: Tracer,
1217    {
1218        if self.name().is_some_and(|name| context.is_stdint_type(name)) {
1219            // These types are special-cased in codegen and don't need to be traversed.
1220            return;
1221        }
1222        match *self.kind() {
1223            TypeKind::Pointer(inner) |
1224            TypeKind::Reference(inner, _) |
1225            TypeKind::Array(inner, _) |
1226            TypeKind::Vector(inner, _) |
1227            TypeKind::BlockPointer(inner) |
1228            TypeKind::Alias(inner) |
1229            TypeKind::ResolvedTypeRef(inner) => {
1230                tracer.visit_kind(inner.into(), EdgeKind::TypeReference);
1231            }
1232            TypeKind::TemplateAlias(inner, ref template_params) => {
1233                tracer.visit_kind(inner.into(), EdgeKind::TypeReference);
1234                for param in template_params {
1235                    tracer.visit_kind(
1236                        param.into(),
1237                        EdgeKind::TemplateParameterDefinition,
1238                    );
1239                }
1240            }
1241            TypeKind::TemplateInstantiation(ref inst) => {
1242                inst.trace(context, tracer, &());
1243            }
1244            TypeKind::Comp(ref ci) => ci.trace(context, tracer, item),
1245            TypeKind::Function(ref sig) => sig.trace(context, tracer, &()),
1246            TypeKind::Enum(ref en) => {
1247                if let Some(repr) = en.repr() {
1248                    tracer.visit(repr.into());
1249                }
1250            }
1251            TypeKind::UnresolvedTypeRef(_, _, Some(id)) => {
1252                tracer.visit(id);
1253            }
1254
1255            TypeKind::ObjCInterface(ref interface) => {
1256                interface.trace(context, tracer, &());
1257            }
1258
1259            // None of these variants have edges to other items and types.
1260            TypeKind::Opaque |
1261            TypeKind::UnresolvedTypeRef(_, _, None) |
1262            TypeKind::TypeParam |
1263            TypeKind::Void |
1264            TypeKind::NullPtr |
1265            TypeKind::Int(_) |
1266            TypeKind::Float(_) |
1267            TypeKind::Complex(_) |
1268            TypeKind::ObjCId |
1269            TypeKind::ObjCSel => {}
1270        }
1271    }
1272}