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