Skip to main content

rustc_lint/types/
improper_ctypes.rs

1use std::iter;
2use std::ops::ControlFlow;
3
4use bitflags::bitflags;
5use rustc_abi::VariantIdx;
6use rustc_data_structures::fx::FxHashSet;
7use rustc_errors::{DiagMessage, msg};
8use rustc_hir::def::CtorKind;
9use rustc_hir::intravisit::VisitorExt;
10use rustc_hir::{self as hir, AmbigArg};
11use rustc_middle::bug;
12use rustc_middle::ty::{
13    self, Adt, AdtDef, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
14    TypeVisitableExt, Unnormalized,
15};
16use rustc_session::{declare_lint, declare_lint_pass};
17use rustc_span::def_id::LocalDefId;
18use rustc_span::{Span, sym};
19use rustc_target::spec::Os;
20use tracing::debug;
21
22use super::repr_nullable_ptr;
23use crate::lints::{ImproperCTypes, UsesPowerAlignment};
24use crate::{LateContext, LateLintPass, LintContext};
25
26#[doc =
r" The `improper_ctypes` lint detects incorrect use of types in foreign"]
#[doc = r" modules."]
#[doc = r""]
#[doc = r" ### Example"]
#[doc = r""]
#[doc = r" ```rust"]
#[doc = r#" unsafe extern "C" {"#]
#[doc = r"     static STATIC: String;"]
#[doc = r" }"]
#[doc = r" ```"]
#[doc = r""]
#[doc = r" {{produces}}"]
#[doc = r""]
#[doc = r" ### Explanation"]
#[doc = r""]
#[doc =
r" The compiler has several checks to verify that types used in `extern`"]
#[doc = r" blocks are safe and follow certain rules to ensure proper"]
#[doc =
r" compatibility with the foreign interfaces. This lint is issued when it"]
#[doc =
r" detects a probable mistake in a definition. The lint usually should"]
#[doc =
r" provide a description of the issue, along with possibly a hint on how"]
#[doc = r" to resolve it."]
static IMPROPER_CTYPES: &::rustc_lint_defs::Lint =
    &::rustc_lint_defs::Lint {
            name: "IMPROPER_CTYPES",
            default_level: ::rustc_lint_defs::Warn,
            desc: "proper use of libc types in foreign modules",
            is_externally_loaded: false,
            ..::rustc_lint_defs::Lint::default_fields_for_macro()
        };declare_lint! {
27    /// The `improper_ctypes` lint detects incorrect use of types in foreign
28    /// modules.
29    ///
30    /// ### Example
31    ///
32    /// ```rust
33    /// unsafe extern "C" {
34    ///     static STATIC: String;
35    /// }
36    /// ```
37    ///
38    /// {{produces}}
39    ///
40    /// ### Explanation
41    ///
42    /// The compiler has several checks to verify that types used in `extern`
43    /// blocks are safe and follow certain rules to ensure proper
44    /// compatibility with the foreign interfaces. This lint is issued when it
45    /// detects a probable mistake in a definition. The lint usually should
46    /// provide a description of the issue, along with possibly a hint on how
47    /// to resolve it.
48    IMPROPER_CTYPES,
49    Warn,
50    "proper use of libc types in foreign modules"
51}
52
53#[doc = r" The `improper_ctypes_definitions` lint detects incorrect use of"]
#[doc = r" [`extern` function] definitions."]
#[doc = r""]
#[doc =
r" [`extern` function]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier"]
#[doc = r""]
#[doc = r" ### Example"]
#[doc = r""]
#[doc = r" ```rust"]
#[doc = r" # #![allow(unused)]"]
#[doc = r#" pub extern "C" fn str_type(p: &str) { }"#]
#[doc = r" ```"]
#[doc = r""]
#[doc = r" {{produces}}"]
#[doc = r""]
#[doc = r" ### Explanation"]
#[doc = r""]
#[doc =
r" There are many parameter and return types that may be specified in an"]
#[doc =
r" `extern` function that are not compatible with the given ABI. This"]
#[doc =
r" lint is an alert that these types should not be used. The lint usually"]
#[doc =
r" should provide a description of the issue, along with possibly a hint"]
#[doc = r" on how to resolve it."]
static IMPROPER_CTYPES_DEFINITIONS: &::rustc_lint_defs::Lint =
    &::rustc_lint_defs::Lint {
            name: "IMPROPER_CTYPES_DEFINITIONS",
            default_level: ::rustc_lint_defs::Warn,
            desc: "proper use of libc types in foreign item definitions",
            is_externally_loaded: false,
            ..::rustc_lint_defs::Lint::default_fields_for_macro()
        };declare_lint! {
54    /// The `improper_ctypes_definitions` lint detects incorrect use of
55    /// [`extern` function] definitions.
56    ///
57    /// [`extern` function]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier
58    ///
59    /// ### Example
60    ///
61    /// ```rust
62    /// # #![allow(unused)]
63    /// pub extern "C" fn str_type(p: &str) { }
64    /// ```
65    ///
66    /// {{produces}}
67    ///
68    /// ### Explanation
69    ///
70    /// There are many parameter and return types that may be specified in an
71    /// `extern` function that are not compatible with the given ABI. This
72    /// lint is an alert that these types should not be used. The lint usually
73    /// should provide a description of the issue, along with possibly a hint
74    /// on how to resolve it.
75    IMPROPER_CTYPES_DEFINITIONS,
76    Warn,
77    "proper use of libc types in foreign item definitions"
78}
79
80#[doc = r" The `uses_power_alignment` lint detects specific `repr(C)`"]
#[doc = r" aggregates on AIX."]
#[doc =
r#" In its platform C ABI, AIX uses the "power" (as in PowerPC) alignment"#]
#[doc =
r" rule (detailed in https://www.ibm.com/docs/en/xl-c-and-cpp-aix/16.1?topic=data-using-alignment-modes#alignment),"]
#[doc = r" which can also be set for XLC by `#pragma align(power)` or"]
#[doc = r" `-qalign=power`. Aggregates with a floating-point type as the"]
#[doc =
r#" recursively first field (as in "at offset 0") modify the layout of"#]
#[doc =
r" *subsequent* fields of the associated structs to use an alignment value"]
#[doc = r" where the floating-point type is aligned on a 4-byte boundary."]
#[doc = r""]
#[doc =
r" Effectively, subsequent floating-point fields act as-if they are `repr(packed(4))`. This"]
#[doc =
r" would be unsound to do in a `repr(C)` type without all the restrictions that come with"]
#[doc =
r" `repr(packed)`. Rust instead chooses a layout that maintains soundness of Rust code, at the"]
#[doc = r" expense of incompatibility with C code."]
#[doc = r""]
#[doc = r" ### Example"]
#[doc = r""]
#[doc = r" ```rust,ignore (fails on non-powerpc64-ibm-aix)"]
#[doc = r" #[repr(C)]"]
#[doc = r" pub struct Floats {"]
#[doc = r"     a: f64,"]
#[doc = r"     b: u8,"]
#[doc = r"     c: f64,"]
#[doc = r" }"]
#[doc = r" ```"]
#[doc = r""]
#[doc = r" This will produce:"]
#[doc = r""]
#[doc = r" ```text"]
#[doc =
r" warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type"]
#[doc = r"  --> <source>:5:3"]
#[doc = r"   |"]
#[doc = r" 5 |   c: f64,"]
#[doc = r"   |   ^^^^^^"]
#[doc = r"   |"]
#[doc = r"   = note: `#[warn(uses_power_alignment)]` on by default"]
#[doc = r" ```"]
#[doc = r""]
#[doc = r" ### Explanation"]
#[doc = r""]
#[doc = r" The power alignment rule specifies that the above struct has the"]
#[doc = r" following alignment:"]
#[doc = r"  - offset_of!(Floats, a) == 0"]
#[doc = r"  - offset_of!(Floats, b) == 8"]
#[doc = r"  - offset_of!(Floats, c) == 12"]
#[doc = r""]
#[doc =
r" However, Rust currently aligns `c` at `offset_of!(Floats, c) == 16`."]
#[doc =
r" Using offset 12 would be unsound since `f64` generally must be 8-aligned on this target."]
#[doc = r" Thus, a warning is produced for the above struct."]
static USES_POWER_ALIGNMENT: &::rustc_lint_defs::Lint =
    &::rustc_lint_defs::Lint {
            name: "USES_POWER_ALIGNMENT",
            default_level: ::rustc_lint_defs::Warn,
            desc: "Structs do not follow the power alignment rule under repr(C)",
            is_externally_loaded: false,
            ..::rustc_lint_defs::Lint::default_fields_for_macro()
        };declare_lint! {
81    /// The `uses_power_alignment` lint detects specific `repr(C)`
82    /// aggregates on AIX.
83    /// In its platform C ABI, AIX uses the "power" (as in PowerPC) alignment
84    /// rule (detailed in https://www.ibm.com/docs/en/xl-c-and-cpp-aix/16.1?topic=data-using-alignment-modes#alignment),
85    /// which can also be set for XLC by `#pragma align(power)` or
86    /// `-qalign=power`. Aggregates with a floating-point type as the
87    /// recursively first field (as in "at offset 0") modify the layout of
88    /// *subsequent* fields of the associated structs to use an alignment value
89    /// where the floating-point type is aligned on a 4-byte boundary.
90    ///
91    /// Effectively, subsequent floating-point fields act as-if they are `repr(packed(4))`. This
92    /// would be unsound to do in a `repr(C)` type without all the restrictions that come with
93    /// `repr(packed)`. Rust instead chooses a layout that maintains soundness of Rust code, at the
94    /// expense of incompatibility with C code.
95    ///
96    /// ### Example
97    ///
98    /// ```rust,ignore (fails on non-powerpc64-ibm-aix)
99    /// #[repr(C)]
100    /// pub struct Floats {
101    ///     a: f64,
102    ///     b: u8,
103    ///     c: f64,
104    /// }
105    /// ```
106    ///
107    /// This will produce:
108    ///
109    /// ```text
110    /// warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
111    ///  --> <source>:5:3
112    ///   |
113    /// 5 |   c: f64,
114    ///   |   ^^^^^^
115    ///   |
116    ///   = note: `#[warn(uses_power_alignment)]` on by default
117    /// ```
118    ///
119    /// ### Explanation
120    ///
121    /// The power alignment rule specifies that the above struct has the
122    /// following alignment:
123    ///  - offset_of!(Floats, a) == 0
124    ///  - offset_of!(Floats, b) == 8
125    ///  - offset_of!(Floats, c) == 12
126    ///
127    /// However, Rust currently aligns `c` at `offset_of!(Floats, c) == 16`.
128    /// Using offset 12 would be unsound since `f64` generally must be 8-aligned on this target.
129    /// Thus, a warning is produced for the above struct.
130    USES_POWER_ALIGNMENT,
131    Warn,
132    "Structs do not follow the power alignment rule under repr(C)"
133}
134
135pub struct ImproperCTypesLint;
#[automatically_derived]
impl ::core::marker::Copy for ImproperCTypesLint { }
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for ImproperCTypesLint { }
#[automatically_derived]
impl ::core::clone::Clone for ImproperCTypesLint {
    #[inline]
    fn clone(&self) -> ImproperCTypesLint { *self }
}
impl ::rustc_lint_defs::LintPass for ImproperCTypesLint {
    fn name(&self) -> &'static str { "ImproperCTypesLint" }
    fn get_lints(&self) -> ::rustc_lint_defs::LintVec {
        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
                [IMPROPER_CTYPES, IMPROPER_CTYPES_DEFINITIONS,
                        USES_POWER_ALIGNMENT]))
    }
}
impl ImproperCTypesLint {
    #[allow(unused)]
    pub fn lint_vec() -> ::rustc_lint_defs::LintVec {
        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
                [IMPROPER_CTYPES, IMPROPER_CTYPES_DEFINITIONS,
                        USES_POWER_ALIGNMENT]))
    }
}declare_lint_pass!(ImproperCTypesLint => [
136    IMPROPER_CTYPES,
137    IMPROPER_CTYPES_DEFINITIONS,
138    USES_POWER_ALIGNMENT
139]);
140
141/// Getting the (normalized) type out of a field (for, e.g., an enum variant or a tuple).
142#[inline]
143fn get_type_from_field<'tcx>(
144    cx: &LateContext<'tcx>,
145    field: &ty::FieldDef,
146    args: GenericArgsRef<'tcx>,
147) -> Ty<'tcx> {
148    let field_ty = field.ty(cx.tcx, args);
149    cx.tcx
150        .try_normalize_erasing_regions(cx.typing_env(), Unnormalized::new_wip(field_ty))
151        .unwrap_or(field_ty)
152}
153
154/// Check a variant of a non-exhaustive enum for improper ctypes
155///
156/// We treat `#[non_exhaustive] enum` as "ensure that code will compile if new variants are added".
157/// This includes linting, on a best-effort basis. There are valid additions that are unlikely.
158///
159/// Adding a data-carrying variant to an existing C-like enum that is passed to C is "unlikely",
160/// so we don't need the lint to account for it.
161/// e.g. going from enum Foo { A, B, C } to enum Foo { A, B, C, D(u32) }.
162pub(crate) fn check_non_exhaustive_variant(
163    non_exhaustive_variant_list: bool,
164    variant: &ty::VariantDef,
165) -> ControlFlow<DiagMessage, ()> {
166    // non_exhaustive suggests it is possible that someone might break ABI
167    // see: https://github.com/rust-lang/rust/issues/44109#issuecomment-537583344
168    // so warn on complex enums being used outside their crate
169    if non_exhaustive_variant_list {
170        // which is why we only warn about really_tagged_union reprs from https://rust.tf/rfc2195
171        // with an enum like `#[repr(u8)] enum Enum { A(DataA), B(DataB), }`
172        // but exempt enums with unit ctors like C's (e.g. from rust-bindgen)
173        if variant_has_complex_ctor(variant) {
174            return ControlFlow::Break(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("this enum is non-exhaustive"))msg!("this enum is non-exhaustive"));
175        }
176    }
177
178    if variant.field_list_has_applicable_non_exhaustive() {
179        return ControlFlow::Break(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("this enum has non-exhaustive variants"))msg!("this enum has non-exhaustive variants"));
180    }
181
182    ControlFlow::Continue(())
183}
184
185fn variant_has_complex_ctor(variant: &ty::VariantDef) -> bool {
186    // CtorKind::Const means a "unit" ctor
187    !#[allow(non_exhaustive_omitted_patterns)] match variant.ctor_kind() {
    Some(CtorKind::Const) => true,
    _ => false,
}matches!(variant.ctor_kind(), Some(CtorKind::Const))
188}
189
190/// Per-struct-field function that checks if a struct definition follows
191/// the Power alignment Rule (see the `check_struct_for_power_alignment` function).
192fn check_arg_for_power_alignment<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
193    let tcx = cx.tcx;
194    if !(tcx.sess.target.os == Os::Aix) {
    ::core::panicking::panic("assertion failed: tcx.sess.target.os == Os::Aix")
};assert!(tcx.sess.target.os == Os::Aix);
195
196    // Structs (under repr(C)) follow the power alignment rule if:
197    //   - the first field of the struct is a floating-point type that
198    //     is greater than 4-bytes, or
199    //   - the first field of the struct is an aggregate whose
200    //     recursively first field is a floating-point type greater than
201    //     4 bytes.
202    if ty.is_floating_point() && ty.primitive_size(tcx).bytes() > 4 {
203        return true;
204    } else if let Adt(adt_def, _) = ty.kind()
205        && adt_def.is_struct()
206        && adt_def.repr().c()
207        && !adt_def.repr().packed()
208        && adt_def.repr().align.is_none()
209    {
210        let struct_variant = adt_def.variant(VariantIdx::ZERO);
211        // Within a nested struct, all fields are examined to correctly
212        // report if any fields after the nested struct within the
213        // original struct are misaligned.
214        for struct_field in &struct_variant.fields {
215            let field_ty = tcx.type_of(struct_field.did).instantiate_identity().skip_norm_wip();
216            if check_arg_for_power_alignment(cx, field_ty) {
217                return true;
218            }
219        }
220    }
221    return false;
222}
223
224/// Check a struct definition for respect of the Power alignment Rule (as in PowerPC),
225/// which should be respected in the "aix" target OS.
226/// To do so, we must follow one of the two following conditions:
227/// - The first field of the struct must be floating-point type that
228///    is greater than 4-bytes.
229///  - The first field of the struct must be an aggregate whose
230///    recursively first field is a floating-point type greater than
231///    4 bytes.
232fn check_struct_for_power_alignment<'tcx>(
233    cx: &LateContext<'tcx>,
234    item: &'tcx hir::Item<'tcx>,
235    adt_def: AdtDef<'tcx>,
236) {
237    let tcx = cx.tcx;
238
239    // Only consider structs (not enums or unions) on AIX.
240    if tcx.sess.target.os != Os::Aix || !adt_def.is_struct() {
241        return;
242    }
243
244    // The struct must be repr(C), but ignore it if it explicitly specifies its alignment with
245    // either `align(N)` or `packed(N)`.
246    if adt_def.repr().c() && !adt_def.repr().packed() && adt_def.repr().align.is_none() {
247        let struct_variant_data = item.expect_struct().2;
248        for field_def in struct_variant_data.fields().iter().skip(1) {
249            // Struct fields (after the first field) are checked for the
250            // power alignment rule, as fields after the first are likely
251            // to be the fields that are misaligned.
252            let ty = tcx.type_of(field_def.def_id).instantiate_identity().skip_norm_wip();
253            if check_arg_for_power_alignment(cx, ty) {
254                cx.emit_span_lint(USES_POWER_ALIGNMENT, field_def.span, UsesPowerAlignment);
255            }
256        }
257    }
258}
259
260#[derive(#[automatically_derived]
impl ::core::clone::Clone for CItemKind {
    #[inline]
    fn clone(&self) -> CItemKind { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for CItemKind { }Copy)]
261enum CItemKind {
262    Declaration,
263    Definition,
264}
265
266enum FfiResult<'tcx> {
267    FfiSafe,
268    FfiPhantom(Ty<'tcx>),
269    FfiUnsafe { ty: Ty<'tcx>, reason: DiagMessage, help: Option<DiagMessage> },
270}
271
272/// The result when a type has been checked but perhaps not completely. `None` indicates that
273/// FFI safety/unsafety has not yet been determined, `Some(res)` indicates that the safety/unsafety
274/// in the `FfiResult` is final.
275type PartialFfiResult<'tcx> = Option<FfiResult<'tcx>>;
276
277/// What type indirection points to a given type.
278#[derive(#[automatically_derived]
impl ::core::clone::Clone for IndirectionKind {
    #[inline]
    fn clone(&self) -> IndirectionKind { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for IndirectionKind { }Copy)]
279enum IndirectionKind {
280    /// Box (valid non-null pointer, owns pointee).
281    Box,
282    /// Ref (valid non-null pointer, borrows pointee).
283    Ref,
284    /// Raw pointer (not necessarily non-null or valid. no info on ownership).
285    RawPtr,
286}
287
288bitflags! {
289    #[derive(#[automatically_derived]
impl ::core::clone::Clone for VisitorState {
    #[inline]
    fn clone(&self) -> VisitorState {
        let _:
                ::core::clone::AssertParamIsClone<<VisitorState as
                ::bitflags::__private::PublicFlags>::Internal>;
        *self
    }
}
impl VisitorState {
    #[doc = r" For use in (externally-linked) static variables."]
    #[allow(deprecated, non_upper_case_globals,)]
    pub const STATIC: Self = Self::from_bits_retain(0b000001);
    #[doc = r" For use in functions in general."]
    #[allow(deprecated, non_upper_case_globals,)]
    pub const FUNC: Self = Self::from_bits_retain(0b000010);
    #[doc =
    r" For variables in function returns (implicitly: not for static variables)."]
    #[allow(deprecated, non_upper_case_globals,)]
    pub const FN_RETURN: Self = Self::from_bits_retain(0b000100);
    #[doc =
    r" For variables in functions/variables which are defined in rust."]
    #[allow(deprecated, non_upper_case_globals,)]
    pub const DEFINED: Self = Self::from_bits_retain(0b001000);
    #[doc = r" For times where we are only defining the type of something"]
    #[doc = r" (struct/enum/union definitions, FnPtrs)."]
    #[allow(deprecated, non_upper_case_globals,)]
    pub const THEORETICAL: Self = Self::from_bits_retain(0b010000);
}
impl ::bitflags::Flags for VisitorState {
    const FLAGS: &'static [::bitflags::Flag<VisitorState>] =
        &[{

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("STATIC", VisitorState::STATIC)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("FUNC", VisitorState::FUNC)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("FN_RETURN", VisitorState::FN_RETURN)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("DEFINED", VisitorState::DEFINED)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("THEORETICAL",
                            VisitorState::THEORETICAL)
                    }];
    type Bits = u8;
    fn bits(&self) -> u8 { VisitorState::bits(self) }
    fn from_bits_retain(bits: u8) -> VisitorState {
        VisitorState::from_bits_retain(bits)
    }
}
#[allow(dead_code, deprecated, unused_doc_comments, unused_attributes,
unused_mut, unused_imports, non_upper_case_globals, clippy ::
assign_op_pattern, clippy :: indexing_slicing, clippy :: same_name_method,
clippy :: iter_without_into_iter,)]
const _: () =
    {
        #[repr(transparent)]
        struct InternalBitFlags(u8);
        #[automatically_derived]
        #[doc(hidden)]
        unsafe impl ::core::clone::TrivialClone for InternalBitFlags { }
        #[automatically_derived]
        impl ::core::clone::Clone for InternalBitFlags {
            #[inline]
            fn clone(&self) -> InternalBitFlags {
                let _: ::core::clone::AssertParamIsClone<u8>;
                *self
            }
        }
        #[automatically_derived]
        impl ::core::marker::Copy for InternalBitFlags { }
        #[automatically_derived]
        impl ::core::marker::StructuralPartialEq for InternalBitFlags { }
        #[automatically_derived]
        impl ::core::cmp::PartialEq for InternalBitFlags {
            #[inline]
            fn eq(&self, other: &InternalBitFlags) -> bool {
                self.0 == other.0
            }
        }
        #[automatically_derived]
        impl ::core::cmp::Eq for InternalBitFlags {
            #[inline]
            #[doc(hidden)]
            #[coverage(off)]
            fn assert_fields_are_eq(&self) {
                let _: ::core::cmp::AssertParamIsEq<u8>;
            }
        }
        #[automatically_derived]
        impl ::core::cmp::PartialOrd for InternalBitFlags {
            #[inline]
            fn partial_cmp(&self, other: &InternalBitFlags)
                -> ::core::option::Option<::core::cmp::Ordering> {
                ::core::cmp::PartialOrd::partial_cmp(&self.0, &other.0)
            }
        }
        #[automatically_derived]
        impl ::core::cmp::Ord for InternalBitFlags {
            #[inline]
            fn cmp(&self, other: &InternalBitFlags) -> ::core::cmp::Ordering {
                ::core::cmp::Ord::cmp(&self.0, &other.0)
            }
        }
        #[automatically_derived]
        impl ::core::hash::Hash for InternalBitFlags {
            #[inline]
            fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
                ::core::hash::Hash::hash(&self.0, state)
            }
        }
        impl ::bitflags::__private::PublicFlags for VisitorState {
            type Primitive = u8;
            type Internal = InternalBitFlags;
        }
        impl ::bitflags::__private::core::default::Default for
            InternalBitFlags {
            #[inline]
            fn default() -> Self { InternalBitFlags::empty() }
        }
        impl ::bitflags::__private::core::fmt::Debug for InternalBitFlags {
            fn fmt(&self,
                f: &mut ::bitflags::__private::core::fmt::Formatter<'_>)
                -> ::bitflags::__private::core::fmt::Result {
                if self.is_empty() {
                    f.write_fmt(format_args!("{0:#x}",
                            <u8 as ::bitflags::Bits>::EMPTY))
                } else {
                    ::bitflags::__private::core::fmt::Display::fmt(self, f)
                }
            }
        }
        impl ::bitflags::__private::core::fmt::Display for InternalBitFlags {
            fn fmt(&self,
                f: &mut ::bitflags::__private::core::fmt::Formatter<'_>)
                -> ::bitflags::__private::core::fmt::Result {
                ::bitflags::parser::to_writer(&VisitorState(*self), f)
            }
        }
        impl ::bitflags::__private::core::str::FromStr for InternalBitFlags {
            type Err = ::bitflags::parser::ParseError;
            fn from_str(s: &str)
                ->
                    ::bitflags::__private::core::result::Result<Self,
                    Self::Err> {
                ::bitflags::parser::from_str::<VisitorState>(s).map(|flags|
                        flags.0)
            }
        }
        impl ::bitflags::__private::core::convert::AsRef<u8> for
            InternalBitFlags {
            fn as_ref(&self) -> &u8 { &self.0 }
        }
        impl ::bitflags::__private::core::convert::From<u8> for
            InternalBitFlags {
            fn from(bits: u8) -> Self { Self::from_bits_retain(bits) }
        }
        #[allow(dead_code, deprecated, unused_attributes)]
        impl InternalBitFlags {
            /// Get a flags value with all bits unset.
            #[inline]
            pub const fn empty() -> Self {
                Self(<u8 as ::bitflags::Bits>::EMPTY)
            }
            /// Get a flags value with all known bits set.
            #[inline]
            pub const fn all() -> Self {
                let mut truncated = <u8 as ::bitflags::Bits>::EMPTY;
                let mut i = 0;
                {
                    {
                        let flag =
                            <VisitorState as
                                            ::bitflags::Flags>::FLAGS[i].value().bits();
                        truncated = truncated | flag;
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            <VisitorState as
                                            ::bitflags::Flags>::FLAGS[i].value().bits();
                        truncated = truncated | flag;
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            <VisitorState as
                                            ::bitflags::Flags>::FLAGS[i].value().bits();
                        truncated = truncated | flag;
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            <VisitorState as
                                            ::bitflags::Flags>::FLAGS[i].value().bits();
                        truncated = truncated | flag;
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            <VisitorState as
                                            ::bitflags::Flags>::FLAGS[i].value().bits();
                        truncated = truncated | flag;
                        i += 1;
                    }
                };
                let _ = i;
                Self(truncated)
            }
            /// Get the underlying bits value.
            ///
            /// The returned value is exactly the bits set in this flags value.
            #[inline]
            pub const fn bits(&self) -> u8 { self.0 }
            /// Convert from a bits value.
            ///
            /// This method will return `None` if any unknown bits are set.
            #[inline]
            pub const fn from_bits(bits: u8)
                -> ::bitflags::__private::core::option::Option<Self> {
                let truncated = Self::from_bits_truncate(bits).0;
                if truncated == bits {
                    ::bitflags::__private::core::option::Option::Some(Self(bits))
                } else { ::bitflags::__private::core::option::Option::None }
            }
            /// Convert from a bits value, unsetting any unknown bits.
            #[inline]
            pub const fn from_bits_truncate(bits: u8) -> Self {
                Self(bits & Self::all().0)
            }
            /// Convert from a bits value exactly.
            #[inline]
            pub const fn from_bits_retain(bits: u8) -> Self { Self(bits) }
            /// Get a flags value with the bits of a flag with the given name set.
            ///
            /// This method will return `None` if `name` is empty or doesn't
            /// correspond to any named flag.
            #[inline]
            pub fn from_name(name: &str)
                -> ::bitflags::__private::core::option::Option<Self> {
                {
                    if name == "STATIC" {
                        return ::bitflags::__private::core::option::Option::Some(Self(VisitorState::STATIC.bits()));
                    }
                };
                ;
                {
                    if name == "FUNC" {
                        return ::bitflags::__private::core::option::Option::Some(Self(VisitorState::FUNC.bits()));
                    }
                };
                ;
                {
                    if name == "FN_RETURN" {
                        return ::bitflags::__private::core::option::Option::Some(Self(VisitorState::FN_RETURN.bits()));
                    }
                };
                ;
                {
                    if name == "DEFINED" {
                        return ::bitflags::__private::core::option::Option::Some(Self(VisitorState::DEFINED.bits()));
                    }
                };
                ;
                {
                    if name == "THEORETICAL" {
                        return ::bitflags::__private::core::option::Option::Some(Self(VisitorState::THEORETICAL.bits()));
                    }
                };
                ;
                let _ = name;
                ::bitflags::__private::core::option::Option::None
            }
            /// Whether all bits in this flags value are unset.
            #[inline]
            pub const fn is_empty(&self) -> bool {
                self.0 == <u8 as ::bitflags::Bits>::EMPTY
            }
            /// Whether all known bits in this flags value are set.
            #[inline]
            pub const fn is_all(&self) -> bool {
                Self::all().0 | self.0 == self.0
            }
            /// Whether any set bits in a source flags value are also set in a target flags value.
            #[inline]
            pub const fn intersects(&self, other: Self) -> bool {
                self.0 & other.0 != <u8 as ::bitflags::Bits>::EMPTY
            }
            /// Whether all set bits in a source flags value are also set in a target flags value.
            #[inline]
            pub const fn contains(&self, other: Self) -> bool {
                self.0 & other.0 == other.0
            }
            /// The bitwise or (`|`) of the bits in two flags values.
            #[inline]
            pub fn insert(&mut self, other: Self) {
                *self = Self(self.0).union(other);
            }
            /// The intersection of a source flags value with the complement of a target flags
            /// value (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `remove` won't truncate `other`, but the `!` operator will.
            #[inline]
            pub fn remove(&mut self, other: Self) {
                *self = Self(self.0).difference(other);
            }
            /// The bitwise exclusive-or (`^`) of the bits in two flags values.
            #[inline]
            pub fn toggle(&mut self, other: Self) {
                *self = Self(self.0).symmetric_difference(other);
            }
            /// Call `insert` when `value` is `true` or `remove` when `value` is `false`.
            #[inline]
            pub fn set(&mut self, other: Self, value: bool) {
                if value { self.insert(other); } else { self.remove(other); }
            }
            /// The bitwise and (`&`) of the bits in two flags values.
            #[inline]
            #[must_use]
            pub const fn intersection(self, other: Self) -> Self {
                Self(self.0 & other.0)
            }
            /// The bitwise or (`|`) of the bits in two flags values.
            #[inline]
            #[must_use]
            pub const fn union(self, other: Self) -> Self {
                Self(self.0 | other.0)
            }
            /// The intersection of a source flags value with the complement of a target flags
            /// value (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            #[must_use]
            pub const fn difference(self, other: Self) -> Self {
                Self(self.0 & !other.0)
            }
            /// The bitwise exclusive-or (`^`) of the bits in two flags values.
            #[inline]
            #[must_use]
            pub const fn symmetric_difference(self, other: Self) -> Self {
                Self(self.0 ^ other.0)
            }
            /// The bitwise negation (`!`) of the bits in a flags value, truncating the result.
            #[inline]
            #[must_use]
            pub const fn complement(self) -> Self {
                Self::from_bits_truncate(!self.0)
            }
        }
        impl ::bitflags::__private::core::fmt::Binary for InternalBitFlags {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::Binary::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::Octal for InternalBitFlags {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::Octal::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::LowerHex for InternalBitFlags {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::LowerHex::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::UpperHex for InternalBitFlags {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::UpperHex::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::ops::BitOr for InternalBitFlags {
            type Output = Self;
            /// The bitwise or (`|`) of the bits in two flags values.
            #[inline]
            fn bitor(self, other: InternalBitFlags) -> Self {
                self.union(other)
            }
        }
        impl ::bitflags::__private::core::ops::BitOrAssign for
            InternalBitFlags {
            /// The bitwise or (`|`) of the bits in two flags values.
            #[inline]
            fn bitor_assign(&mut self, other: Self) { self.insert(other); }
        }
        impl ::bitflags::__private::core::ops::BitXor for InternalBitFlags {
            type Output = Self;
            /// The bitwise exclusive-or (`^`) of the bits in two flags values.
            #[inline]
            fn bitxor(self, other: Self) -> Self {
                self.symmetric_difference(other)
            }
        }
        impl ::bitflags::__private::core::ops::BitXorAssign for
            InternalBitFlags {
            /// The bitwise exclusive-or (`^`) of the bits in two flags values.
            #[inline]
            fn bitxor_assign(&mut self, other: Self) { self.toggle(other); }
        }
        impl ::bitflags::__private::core::ops::BitAnd for InternalBitFlags {
            type Output = Self;
            /// The bitwise and (`&`) of the bits in two flags values.
            #[inline]
            fn bitand(self, other: Self) -> Self { self.intersection(other) }
        }
        impl ::bitflags::__private::core::ops::BitAndAssign for
            InternalBitFlags {
            /// The bitwise and (`&`) of the bits in two flags values.
            #[inline]
            fn bitand_assign(&mut self, other: Self) {
                *self =
                    Self::from_bits_retain(self.bits()).intersection(other);
            }
        }
        impl ::bitflags::__private::core::ops::Sub for InternalBitFlags {
            type Output = Self;
            /// The intersection of a source flags value with the complement of a target flags value (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            fn sub(self, other: Self) -> Self { self.difference(other) }
        }
        impl ::bitflags::__private::core::ops::SubAssign for InternalBitFlags
            {
            /// The intersection of a source flags value with the complement of a target flags value (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            fn sub_assign(&mut self, other: Self) { self.remove(other); }
        }
        impl ::bitflags::__private::core::ops::Not for InternalBitFlags {
            type Output = Self;
            /// The bitwise negation (`!`) of the bits in a flags value, truncating the result.
            #[inline]
            fn not(self) -> Self { self.complement() }
        }
        impl ::bitflags::__private::core::iter::Extend<InternalBitFlags> for
            InternalBitFlags {
            /// The bitwise or (`|`) of the bits in each flags value.
            fn extend<T: ::bitflags::__private::core::iter::IntoIterator<Item
                = Self>>(&mut self, iterator: T) {
                for item in iterator { self.insert(item) }
            }
        }
        impl ::bitflags::__private::core::iter::FromIterator<InternalBitFlags>
            for InternalBitFlags {
            /// The bitwise or (`|`) of the bits in each flags value.
            fn from_iter<T: ::bitflags::__private::core::iter::IntoIterator<Item
                = Self>>(iterator: T) -> Self {
                use ::bitflags::__private::core::iter::Extend;
                let mut result = Self::empty();
                result.extend(iterator);
                result
            }
        }
        impl InternalBitFlags {
            /// Yield a set of contained flags values.
            ///
            /// Each yielded flags value will correspond to a defined named flag. Any unknown bits
            /// will be yielded together as a final flags value.
            #[inline]
            pub const fn iter(&self) -> ::bitflags::iter::Iter<VisitorState> {
                ::bitflags::iter::Iter::__private_const_new(<VisitorState as
                        ::bitflags::Flags>::FLAGS,
                    VisitorState::from_bits_retain(self.bits()),
                    VisitorState::from_bits_retain(self.bits()))
            }
            /// Yield a set of contained named flags values.
            ///
            /// This method is like [`iter`](#method.iter), except only yields bits in contained named flags.
            /// Any unknown bits, or bits not corresponding to a contained flag will not be yielded.
            #[inline]
            pub const fn iter_names(&self)
                -> ::bitflags::iter::IterNames<VisitorState> {
                ::bitflags::iter::IterNames::__private_const_new(<VisitorState
                        as ::bitflags::Flags>::FLAGS,
                    VisitorState::from_bits_retain(self.bits()),
                    VisitorState::from_bits_retain(self.bits()))
            }
        }
        impl ::bitflags::__private::core::iter::IntoIterator for
            InternalBitFlags {
            type Item = VisitorState;
            type IntoIter = ::bitflags::iter::Iter<VisitorState>;
            fn into_iter(self) -> Self::IntoIter { self.iter() }
        }
        impl InternalBitFlags {
            /// Returns a mutable reference to the raw value of the flags currently stored.
            #[inline]
            pub fn bits_mut(&mut self) -> &mut u8 { &mut self.0 }
        }
        #[allow(dead_code, deprecated, unused_attributes)]
        impl VisitorState {
            /// Get a flags value with all bits unset.
            #[inline]
            pub const fn empty() -> Self { Self(InternalBitFlags::empty()) }
            /// Get a flags value with all known bits set.
            #[inline]
            pub const fn all() -> Self { Self(InternalBitFlags::all()) }
            /// Get the underlying bits value.
            ///
            /// The returned value is exactly the bits set in this flags value.
            #[inline]
            pub const fn bits(&self) -> u8 { self.0.bits() }
            /// Convert from a bits value.
            ///
            /// This method will return `None` if any unknown bits are set.
            #[inline]
            pub const fn from_bits(bits: u8)
                -> ::bitflags::__private::core::option::Option<Self> {
                match InternalBitFlags::from_bits(bits) {
                    ::bitflags::__private::core::option::Option::Some(bits) =>
                        ::bitflags::__private::core::option::Option::Some(Self(bits)),
                    ::bitflags::__private::core::option::Option::None =>
                        ::bitflags::__private::core::option::Option::None,
                }
            }
            /// Convert from a bits value, unsetting any unknown bits.
            #[inline]
            pub const fn from_bits_truncate(bits: u8) -> Self {
                Self(InternalBitFlags::from_bits_truncate(bits))
            }
            /// Convert from a bits value exactly.
            #[inline]
            pub const fn from_bits_retain(bits: u8) -> Self {
                Self(InternalBitFlags::from_bits_retain(bits))
            }
            /// Get a flags value with the bits of a flag with the given name set.
            ///
            /// This method will return `None` if `name` is empty or doesn't
            /// correspond to any named flag.
            #[inline]
            pub fn from_name(name: &str)
                -> ::bitflags::__private::core::option::Option<Self> {
                match InternalBitFlags::from_name(name) {
                    ::bitflags::__private::core::option::Option::Some(bits) =>
                        ::bitflags::__private::core::option::Option::Some(Self(bits)),
                    ::bitflags::__private::core::option::Option::None =>
                        ::bitflags::__private::core::option::Option::None,
                }
            }
            /// Whether all bits in this flags value are unset.
            #[inline]
            pub const fn is_empty(&self) -> bool { self.0.is_empty() }
            /// Whether all known bits in this flags value are set.
            #[inline]
            pub const fn is_all(&self) -> bool { self.0.is_all() }
            /// Whether any set bits in a source flags value are also set in a target flags value.
            #[inline]
            pub const fn intersects(&self, other: Self) -> bool {
                self.0.intersects(other.0)
            }
            /// Whether all set bits in a source flags value are also set in a target flags value.
            #[inline]
            pub const fn contains(&self, other: Self) -> bool {
                self.0.contains(other.0)
            }
            /// The bitwise or (`|`) of the bits in two flags values.
            #[inline]
            pub fn insert(&mut self, other: Self) { self.0.insert(other.0) }
            /// The intersection of a source flags value with the complement of a target flags
            /// value (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `remove` won't truncate `other`, but the `!` operator will.
            #[inline]
            pub fn remove(&mut self, other: Self) { self.0.remove(other.0) }
            /// The bitwise exclusive-or (`^`) of the bits in two flags values.
            #[inline]
            pub fn toggle(&mut self, other: Self) { self.0.toggle(other.0) }
            /// Call `insert` when `value` is `true` or `remove` when `value` is `false`.
            #[inline]
            pub fn set(&mut self, other: Self, value: bool) {
                self.0.set(other.0, value)
            }
            /// The bitwise and (`&`) of the bits in two flags values.
            #[inline]
            #[must_use]
            pub const fn intersection(self, other: Self) -> Self {
                Self(self.0.intersection(other.0))
            }
            /// The bitwise or (`|`) of the bits in two flags values.
            #[inline]
            #[must_use]
            pub const fn union(self, other: Self) -> Self {
                Self(self.0.union(other.0))
            }
            /// The intersection of a source flags value with the complement of a target flags
            /// value (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            #[must_use]
            pub const fn difference(self, other: Self) -> Self {
                Self(self.0.difference(other.0))
            }
            /// The bitwise exclusive-or (`^`) of the bits in two flags values.
            #[inline]
            #[must_use]
            pub const fn symmetric_difference(self, other: Self) -> Self {
                Self(self.0.symmetric_difference(other.0))
            }
            /// The bitwise negation (`!`) of the bits in a flags value, truncating the result.
            #[inline]
            #[must_use]
            pub const fn complement(self) -> Self {
                Self(self.0.complement())
            }
        }
        impl ::bitflags::__private::core::fmt::Binary for VisitorState {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::Binary::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::Octal for VisitorState {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::Octal::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::LowerHex for VisitorState {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::LowerHex::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::UpperHex for VisitorState {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::UpperHex::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::ops::BitOr for VisitorState {
            type Output = Self;
            /// The bitwise or (`|`) of the bits in two flags values.
            #[inline]
            fn bitor(self, other: VisitorState) -> Self { self.union(other) }
        }
        impl ::bitflags::__private::core::ops::BitOrAssign for VisitorState {
            /// The bitwise or (`|`) of the bits in two flags values.
            #[inline]
            fn bitor_assign(&mut self, other: Self) { self.insert(other); }
        }
        impl ::bitflags::__private::core::ops::BitXor for VisitorState {
            type Output = Self;
            /// The bitwise exclusive-or (`^`) of the bits in two flags values.
            #[inline]
            fn bitxor(self, other: Self) -> Self {
                self.symmetric_difference(other)
            }
        }
        impl ::bitflags::__private::core::ops::BitXorAssign for VisitorState {
            /// The bitwise exclusive-or (`^`) of the bits in two flags values.
            #[inline]
            fn bitxor_assign(&mut self, other: Self) { self.toggle(other); }
        }
        impl ::bitflags::__private::core::ops::BitAnd for VisitorState {
            type Output = Self;
            /// The bitwise and (`&`) of the bits in two flags values.
            #[inline]
            fn bitand(self, other: Self) -> Self { self.intersection(other) }
        }
        impl ::bitflags::__private::core::ops::BitAndAssign for VisitorState {
            /// The bitwise and (`&`) of the bits in two flags values.
            #[inline]
            fn bitand_assign(&mut self, other: Self) {
                *self =
                    Self::from_bits_retain(self.bits()).intersection(other);
            }
        }
        impl ::bitflags::__private::core::ops::Sub for VisitorState {
            type Output = Self;
            /// The intersection of a source flags value with the complement of a target flags value (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            fn sub(self, other: Self) -> Self { self.difference(other) }
        }
        impl ::bitflags::__private::core::ops::SubAssign for VisitorState {
            /// The intersection of a source flags value with the complement of a target flags value (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            fn sub_assign(&mut self, other: Self) { self.remove(other); }
        }
        impl ::bitflags::__private::core::ops::Not for VisitorState {
            type Output = Self;
            /// The bitwise negation (`!`) of the bits in a flags value, truncating the result.
            #[inline]
            fn not(self) -> Self { self.complement() }
        }
        impl ::bitflags::__private::core::iter::Extend<VisitorState> for
            VisitorState {
            /// The bitwise or (`|`) of the bits in each flags value.
            fn extend<T: ::bitflags::__private::core::iter::IntoIterator<Item
                = Self>>(&mut self, iterator: T) {
                for item in iterator { self.insert(item) }
            }
        }
        impl ::bitflags::__private::core::iter::FromIterator<VisitorState> for
            VisitorState {
            /// The bitwise or (`|`) of the bits in each flags value.
            fn from_iter<T: ::bitflags::__private::core::iter::IntoIterator<Item
                = Self>>(iterator: T) -> Self {
                use ::bitflags::__private::core::iter::Extend;
                let mut result = Self::empty();
                result.extend(iterator);
                result
            }
        }
        impl VisitorState {
            /// Yield a set of contained flags values.
            ///
            /// Each yielded flags value will correspond to a defined named flag. Any unknown bits
            /// will be yielded together as a final flags value.
            #[inline]
            pub const fn iter(&self) -> ::bitflags::iter::Iter<VisitorState> {
                ::bitflags::iter::Iter::__private_const_new(<VisitorState as
                        ::bitflags::Flags>::FLAGS,
                    VisitorState::from_bits_retain(self.bits()),
                    VisitorState::from_bits_retain(self.bits()))
            }
            /// Yield a set of contained named flags values.
            ///
            /// This method is like [`iter`](#method.iter), except only yields bits in contained named flags.
            /// Any unknown bits, or bits not corresponding to a contained flag will not be yielded.
            #[inline]
            pub const fn iter_names(&self)
                -> ::bitflags::iter::IterNames<VisitorState> {
                ::bitflags::iter::IterNames::__private_const_new(<VisitorState
                        as ::bitflags::Flags>::FLAGS,
                    VisitorState::from_bits_retain(self.bits()),
                    VisitorState::from_bits_retain(self.bits()))
            }
        }
        impl ::bitflags::__private::core::iter::IntoIterator for VisitorState
            {
            type Item = VisitorState;
            type IntoIter = ::bitflags::iter::Iter<VisitorState>;
            fn into_iter(self) -> Self::IntoIter { self.iter() }
        }
    };Clone, #[automatically_derived]
impl ::core::marker::Copy for VisitorState { }Copy, #[automatically_derived]
impl ::core::fmt::Debug for VisitorState {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f, "VisitorState",
            &&self.0)
    }
}Debug, #[automatically_derived]
impl ::core::cmp::PartialEq for VisitorState {
    #[inline]
    fn eq(&self, other: &VisitorState) -> bool { self.0 == other.0 }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for VisitorState {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _:
                ::core::cmp::AssertParamIsEq<<VisitorState as
                ::bitflags::__private::PublicFlags>::Internal>;
    }
}Eq)]
290    struct VisitorState: u8 {
291        /// For use in (externally-linked) static variables.
292        const STATIC = 0b000001;
293        /// For use in functions in general.
294        const FUNC = 0b000010;
295        /// For variables in function returns (implicitly: not for static variables).
296        const FN_RETURN = 0b000100;
297        /// For variables in functions/variables which are defined in rust.
298        const DEFINED = 0b001000;
299        /// For times where we are only defining the type of something
300        /// (struct/enum/union definitions, FnPtrs).
301        const THEORETICAL = 0b010000;
302    }
303}
304
305impl VisitorState {
306    // The values that can be set.
307    const STATIC_TY: Self = Self::STATIC;
308    const ARGUMENT_TY_IN_DEFINITION: Self =
309        Self::from_bits(Self::FUNC.bits() | Self::DEFINED.bits()).unwrap();
310    const RETURN_TY_IN_DEFINITION: Self =
311        Self::from_bits(Self::FUNC.bits() | Self::FN_RETURN.bits() | Self::DEFINED.bits()).unwrap();
312    const ARGUMENT_TY_IN_DECLARATION: Self = Self::FUNC;
313    const RETURN_TY_IN_DECLARATION: Self =
314        Self::from_bits(Self::FUNC.bits() | Self::FN_RETURN.bits()).unwrap();
315    const ARGUMENT_TY_IN_FNPTR: Self =
316        Self::from_bits(Self::FUNC.bits() | Self::THEORETICAL.bits()).unwrap();
317    const RETURN_TY_IN_FNPTR: Self =
318        Self::from_bits(Self::FUNC.bits() | Self::THEORETICAL.bits() | Self::FN_RETURN.bits())
319            .unwrap();
320
321    /// Get the proper visitor state for a given function's arguments.
322    fn argument_from_fnmode(fn_mode: CItemKind) -> Self {
323        match fn_mode {
324            CItemKind::Definition => VisitorState::ARGUMENT_TY_IN_DEFINITION,
325            CItemKind::Declaration => VisitorState::ARGUMENT_TY_IN_DECLARATION,
326        }
327    }
328
329    /// Get the proper visitor state for a given function's return type.
330    fn return_from_fnmode(fn_mode: CItemKind) -> Self {
331        match fn_mode {
332            CItemKind::Definition => VisitorState::RETURN_TY_IN_DEFINITION,
333            CItemKind::Declaration => VisitorState::RETURN_TY_IN_DECLARATION,
334        }
335    }
336
337    /// Whether the type is used in a function.
338    fn is_in_function(self) -> bool {
339        let ret = self.contains(Self::FUNC);
340        if ret {
341            if true {
    if !!self.contains(Self::STATIC) {
        ::core::panicking::panic("assertion failed: !self.contains(Self::STATIC)")
    };
};debug_assert!(!self.contains(Self::STATIC));
342        }
343        ret
344    }
345    /// Whether the type is used (directly or not) in a function, in return position.
346    fn is_in_function_return(self) -> bool {
347        let ret = self.contains(Self::FN_RETURN);
348        if ret {
349            if true {
    if !self.is_in_function() {
        ::core::panicking::panic("assertion failed: self.is_in_function()")
    };
};debug_assert!(self.is_in_function());
350        }
351        ret
352    }
353    /// Whether the type is used (directly or not) in a defined function.
354    /// In other words, whether or not we allow non-FFI-safe types behind a C pointer,
355    /// to be treated as an opaque type on the other side of the FFI boundary.
356    fn is_in_defined_function(self) -> bool {
357        self.contains(Self::DEFINED) && self.is_in_function()
358    }
359
360    /// Whether the type is used (directly or not) in a function pointer type.
361    /// Here, we also allow non-FFI-safe types behind a C pointer,
362    /// to be treated as an opaque type on the other side of the FFI boundary.
363    fn is_in_fnptr(self) -> bool {
364        self.contains(Self::THEORETICAL) && self.is_in_function()
365    }
366
367    /// Whether we can expect type parameters and co in a given type.
368    fn can_expect_ty_params(self) -> bool {
369        // rust-defined functions, as well as FnPtrs
370        self.contains(Self::THEORETICAL) || self.is_in_defined_function()
371    }
372}
373
374bitflags! {
375    /// Data that summarises how an "outer type" surrounds its inner type(s)
376    #[derive(#[automatically_derived]
impl ::core::clone::Clone for OuterTyData {
    #[inline]
    fn clone(&self) -> OuterTyData {
        let _:
                ::core::clone::AssertParamIsClone<<OuterTyData as
                ::bitflags::__private::PublicFlags>::Internal>;
        *self
    }
}
impl OuterTyData {
    #[doc =
    r" To show that there is no outer type, the current type is directly used by a `static`"]
    #[doc = r" variable or a function/FnPtr"]
    #[allow(deprecated, non_upper_case_globals,)]
    pub const NO_OUTER_TY: Self = Self::from_bits_retain(0b01);
    #[doc =
    r" For NO_OUTER_TY cases, show that we are being directly used by a FnPtr specifically"]
    #[doc =
    r#" FIXME(ctypes): this is only used for "bad behaviour" reproduced for compatibility's sake"#]
    #[allow(deprecated, non_upper_case_globals,)]
    pub const NO_OUTER_TY_FNPTR: Self = Self::from_bits_retain(0b10);
}
impl ::bitflags::Flags for OuterTyData {
    const FLAGS: &'static [::bitflags::Flag<OuterTyData>] =
        &[{

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("NO_OUTER_TY",
                            OuterTyData::NO_OUTER_TY)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("NO_OUTER_TY_FNPTR",
                            OuterTyData::NO_OUTER_TY_FNPTR)
                    }];
    type Bits = u8;
    fn bits(&self) -> u8 { OuterTyData::bits(self) }
    fn from_bits_retain(bits: u8) -> OuterTyData {
        OuterTyData::from_bits_retain(bits)
    }
}
#[allow(dead_code, deprecated, unused_doc_comments, unused_attributes,
unused_mut, unused_imports, non_upper_case_globals, clippy ::
assign_op_pattern, clippy :: indexing_slicing, clippy :: same_name_method,
clippy :: iter_without_into_iter,)]
const _: () =
    {
        #[repr(transparent)]
        struct InternalBitFlags(u8);
        #[automatically_derived]
        #[doc(hidden)]
        unsafe impl ::core::clone::TrivialClone for InternalBitFlags { }
        #[automatically_derived]
        impl ::core::clone::Clone for InternalBitFlags {
            #[inline]
            fn clone(&self) -> InternalBitFlags {
                let _: ::core::clone::AssertParamIsClone<u8>;
                *self
            }
        }
        #[automatically_derived]
        impl ::core::marker::Copy for InternalBitFlags { }
        #[automatically_derived]
        impl ::core::marker::StructuralPartialEq for InternalBitFlags { }
        #[automatically_derived]
        impl ::core::cmp::PartialEq for InternalBitFlags {
            #[inline]
            fn eq(&self, other: &InternalBitFlags) -> bool {
                self.0 == other.0
            }
        }
        #[automatically_derived]
        impl ::core::cmp::Eq for InternalBitFlags {
            #[inline]
            #[doc(hidden)]
            #[coverage(off)]
            fn assert_fields_are_eq(&self) {
                let _: ::core::cmp::AssertParamIsEq<u8>;
            }
        }
        #[automatically_derived]
        impl ::core::cmp::PartialOrd for InternalBitFlags {
            #[inline]
            fn partial_cmp(&self, other: &InternalBitFlags)
                -> ::core::option::Option<::core::cmp::Ordering> {
                ::core::cmp::PartialOrd::partial_cmp(&self.0, &other.0)
            }
        }
        #[automatically_derived]
        impl ::core::cmp::Ord for InternalBitFlags {
            #[inline]
            fn cmp(&self, other: &InternalBitFlags) -> ::core::cmp::Ordering {
                ::core::cmp::Ord::cmp(&self.0, &other.0)
            }
        }
        #[automatically_derived]
        impl ::core::hash::Hash for InternalBitFlags {
            #[inline]
            fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
                ::core::hash::Hash::hash(&self.0, state)
            }
        }
        impl ::bitflags::__private::PublicFlags for OuterTyData {
            type Primitive = u8;
            type Internal = InternalBitFlags;
        }
        impl ::bitflags::__private::core::default::Default for
            InternalBitFlags {
            #[inline]
            fn default() -> Self { InternalBitFlags::empty() }
        }
        impl ::bitflags::__private::core::fmt::Debug for InternalBitFlags {
            fn fmt(&self,
                f: &mut ::bitflags::__private::core::fmt::Formatter<'_>)
                -> ::bitflags::__private::core::fmt::Result {
                if self.is_empty() {
                    f.write_fmt(format_args!("{0:#x}",
                            <u8 as ::bitflags::Bits>::EMPTY))
                } else {
                    ::bitflags::__private::core::fmt::Display::fmt(self, f)
                }
            }
        }
        impl ::bitflags::__private::core::fmt::Display for InternalBitFlags {
            fn fmt(&self,
                f: &mut ::bitflags::__private::core::fmt::Formatter<'_>)
                -> ::bitflags::__private::core::fmt::Result {
                ::bitflags::parser::to_writer(&OuterTyData(*self), f)
            }
        }
        impl ::bitflags::__private::core::str::FromStr for InternalBitFlags {
            type Err = ::bitflags::parser::ParseError;
            fn from_str(s: &str)
                ->
                    ::bitflags::__private::core::result::Result<Self,
                    Self::Err> {
                ::bitflags::parser::from_str::<OuterTyData>(s).map(|flags|
                        flags.0)
            }
        }
        impl ::bitflags::__private::core::convert::AsRef<u8> for
            InternalBitFlags {
            fn as_ref(&self) -> &u8 { &self.0 }
        }
        impl ::bitflags::__private::core::convert::From<u8> for
            InternalBitFlags {
            fn from(bits: u8) -> Self { Self::from_bits_retain(bits) }
        }
        #[allow(dead_code, deprecated, unused_attributes)]
        impl InternalBitFlags {
            /// Get a flags value with all bits unset.
            #[inline]
            pub const fn empty() -> Self {
                Self(<u8 as ::bitflags::Bits>::EMPTY)
            }
            /// Get a flags value with all known bits set.
            #[inline]
            pub const fn all() -> Self {
                let mut truncated = <u8 as ::bitflags::Bits>::EMPTY;
                let mut i = 0;
                {
                    {
                        let flag =
                            <OuterTyData as ::bitflags::Flags>::FLAGS[i].value().bits();
                        truncated = truncated | flag;
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            <OuterTyData as ::bitflags::Flags>::FLAGS[i].value().bits();
                        truncated = truncated | flag;
                        i += 1;
                    }
                };
                let _ = i;
                Self(truncated)
            }
            /// Get the underlying bits value.
            ///
            /// The returned value is exactly the bits set in this flags value.
            #[inline]
            pub const fn bits(&self) -> u8 { self.0 }
            /// Convert from a bits value.
            ///
            /// This method will return `None` if any unknown bits are set.
            #[inline]
            pub const fn from_bits(bits: u8)
                -> ::bitflags::__private::core::option::Option<Self> {
                let truncated = Self::from_bits_truncate(bits).0;
                if truncated == bits {
                    ::bitflags::__private::core::option::Option::Some(Self(bits))
                } else { ::bitflags::__private::core::option::Option::None }
            }
            /// Convert from a bits value, unsetting any unknown bits.
            #[inline]
            pub const fn from_bits_truncate(bits: u8) -> Self {
                Self(bits & Self::all().0)
            }
            /// Convert from a bits value exactly.
            #[inline]
            pub const fn from_bits_retain(bits: u8) -> Self { Self(bits) }
            /// Get a flags value with the bits of a flag with the given name set.
            ///
            /// This method will return `None` if `name` is empty or doesn't
            /// correspond to any named flag.
            #[inline]
            pub fn from_name(name: &str)
                -> ::bitflags::__private::core::option::Option<Self> {
                {
                    if name == "NO_OUTER_TY" {
                        return ::bitflags::__private::core::option::Option::Some(Self(OuterTyData::NO_OUTER_TY.bits()));
                    }
                };
                ;
                {
                    if name == "NO_OUTER_TY_FNPTR" {
                        return ::bitflags::__private::core::option::Option::Some(Self(OuterTyData::NO_OUTER_TY_FNPTR.bits()));
                    }
                };
                ;
                let _ = name;
                ::bitflags::__private::core::option::Option::None
            }
            /// Whether all bits in this flags value are unset.
            #[inline]
            pub const fn is_empty(&self) -> bool {
                self.0 == <u8 as ::bitflags::Bits>::EMPTY
            }
            /// Whether all known bits in this flags value are set.
            #[inline]
            pub const fn is_all(&self) -> bool {
                Self::all().0 | self.0 == self.0
            }
            /// Whether any set bits in a source flags value are also set in a target flags value.
            #[inline]
            pub const fn intersects(&self, other: Self) -> bool {
                self.0 & other.0 != <u8 as ::bitflags::Bits>::EMPTY
            }
            /// Whether all set bits in a source flags value are also set in a target flags value.
            #[inline]
            pub const fn contains(&self, other: Self) -> bool {
                self.0 & other.0 == other.0
            }
            /// The bitwise or (`|`) of the bits in two flags values.
            #[inline]
            pub fn insert(&mut self, other: Self) {
                *self = Self(self.0).union(other);
            }
            /// The intersection of a source flags value with the complement of a target flags
            /// value (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `remove` won't truncate `other`, but the `!` operator will.
            #[inline]
            pub fn remove(&mut self, other: Self) {
                *self = Self(self.0).difference(other);
            }
            /// The bitwise exclusive-or (`^`) of the bits in two flags values.
            #[inline]
            pub fn toggle(&mut self, other: Self) {
                *self = Self(self.0).symmetric_difference(other);
            }
            /// Call `insert` when `value` is `true` or `remove` when `value` is `false`.
            #[inline]
            pub fn set(&mut self, other: Self, value: bool) {
                if value { self.insert(other); } else { self.remove(other); }
            }
            /// The bitwise and (`&`) of the bits in two flags values.
            #[inline]
            #[must_use]
            pub const fn intersection(self, other: Self) -> Self {
                Self(self.0 & other.0)
            }
            /// The bitwise or (`|`) of the bits in two flags values.
            #[inline]
            #[must_use]
            pub const fn union(self, other: Self) -> Self {
                Self(self.0 | other.0)
            }
            /// The intersection of a source flags value with the complement of a target flags
            /// value (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            #[must_use]
            pub const fn difference(self, other: Self) -> Self {
                Self(self.0 & !other.0)
            }
            /// The bitwise exclusive-or (`^`) of the bits in two flags values.
            #[inline]
            #[must_use]
            pub const fn symmetric_difference(self, other: Self) -> Self {
                Self(self.0 ^ other.0)
            }
            /// The bitwise negation (`!`) of the bits in a flags value, truncating the result.
            #[inline]
            #[must_use]
            pub const fn complement(self) -> Self {
                Self::from_bits_truncate(!self.0)
            }
        }
        impl ::bitflags::__private::core::fmt::Binary for InternalBitFlags {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::Binary::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::Octal for InternalBitFlags {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::Octal::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::LowerHex for InternalBitFlags {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::LowerHex::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::UpperHex for InternalBitFlags {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::UpperHex::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::ops::BitOr for InternalBitFlags {
            type Output = Self;
            /// The bitwise or (`|`) of the bits in two flags values.
            #[inline]
            fn bitor(self, other: InternalBitFlags) -> Self {
                self.union(other)
            }
        }
        impl ::bitflags::__private::core::ops::BitOrAssign for
            InternalBitFlags {
            /// The bitwise or (`|`) of the bits in two flags values.
            #[inline]
            fn bitor_assign(&mut self, other: Self) { self.insert(other); }
        }
        impl ::bitflags::__private::core::ops::BitXor for InternalBitFlags {
            type Output = Self;
            /// The bitwise exclusive-or (`^`) of the bits in two flags values.
            #[inline]
            fn bitxor(self, other: Self) -> Self {
                self.symmetric_difference(other)
            }
        }
        impl ::bitflags::__private::core::ops::BitXorAssign for
            InternalBitFlags {
            /// The bitwise exclusive-or (`^`) of the bits in two flags values.
            #[inline]
            fn bitxor_assign(&mut self, other: Self) { self.toggle(other); }
        }
        impl ::bitflags::__private::core::ops::BitAnd for InternalBitFlags {
            type Output = Self;
            /// The bitwise and (`&`) of the bits in two flags values.
            #[inline]
            fn bitand(self, other: Self) -> Self { self.intersection(other) }
        }
        impl ::bitflags::__private::core::ops::BitAndAssign for
            InternalBitFlags {
            /// The bitwise and (`&`) of the bits in two flags values.
            #[inline]
            fn bitand_assign(&mut self, other: Self) {
                *self =
                    Self::from_bits_retain(self.bits()).intersection(other);
            }
        }
        impl ::bitflags::__private::core::ops::Sub for InternalBitFlags {
            type Output = Self;
            /// The intersection of a source flags value with the complement of a target flags value (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            fn sub(self, other: Self) -> Self { self.difference(other) }
        }
        impl ::bitflags::__private::core::ops::SubAssign for InternalBitFlags
            {
            /// The intersection of a source flags value with the complement of a target flags value (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            fn sub_assign(&mut self, other: Self) { self.remove(other); }
        }
        impl ::bitflags::__private::core::ops::Not for InternalBitFlags {
            type Output = Self;
            /// The bitwise negation (`!`) of the bits in a flags value, truncating the result.
            #[inline]
            fn not(self) -> Self { self.complement() }
        }
        impl ::bitflags::__private::core::iter::Extend<InternalBitFlags> for
            InternalBitFlags {
            /// The bitwise or (`|`) of the bits in each flags value.
            fn extend<T: ::bitflags::__private::core::iter::IntoIterator<Item
                = Self>>(&mut self, iterator: T) {
                for item in iterator { self.insert(item) }
            }
        }
        impl ::bitflags::__private::core::iter::FromIterator<InternalBitFlags>
            for InternalBitFlags {
            /// The bitwise or (`|`) of the bits in each flags value.
            fn from_iter<T: ::bitflags::__private::core::iter::IntoIterator<Item
                = Self>>(iterator: T) -> Self {
                use ::bitflags::__private::core::iter::Extend;
                let mut result = Self::empty();
                result.extend(iterator);
                result
            }
        }
        impl InternalBitFlags {
            /// Yield a set of contained flags values.
            ///
            /// Each yielded flags value will correspond to a defined named flag. Any unknown bits
            /// will be yielded together as a final flags value.
            #[inline]
            pub const fn iter(&self) -> ::bitflags::iter::Iter<OuterTyData> {
                ::bitflags::iter::Iter::__private_const_new(<OuterTyData as
                        ::bitflags::Flags>::FLAGS,
                    OuterTyData::from_bits_retain(self.bits()),
                    OuterTyData::from_bits_retain(self.bits()))
            }
            /// Yield a set of contained named flags values.
            ///
            /// This method is like [`iter`](#method.iter), except only yields bits in contained named flags.
            /// Any unknown bits, or bits not corresponding to a contained flag will not be yielded.
            #[inline]
            pub const fn iter_names(&self)
                -> ::bitflags::iter::IterNames<OuterTyData> {
                ::bitflags::iter::IterNames::__private_const_new(<OuterTyData
                        as ::bitflags::Flags>::FLAGS,
                    OuterTyData::from_bits_retain(self.bits()),
                    OuterTyData::from_bits_retain(self.bits()))
            }
        }
        impl ::bitflags::__private::core::iter::IntoIterator for
            InternalBitFlags {
            type Item = OuterTyData;
            type IntoIter = ::bitflags::iter::Iter<OuterTyData>;
            fn into_iter(self) -> Self::IntoIter { self.iter() }
        }
        impl InternalBitFlags {
            /// Returns a mutable reference to the raw value of the flags currently stored.
            #[inline]
            pub fn bits_mut(&mut self) -> &mut u8 { &mut self.0 }
        }
        #[allow(dead_code, deprecated, unused_attributes)]
        impl OuterTyData {
            /// Get a flags value with all bits unset.
            #[inline]
            pub const fn empty() -> Self { Self(InternalBitFlags::empty()) }
            /// Get a flags value with all known bits set.
            #[inline]
            pub const fn all() -> Self { Self(InternalBitFlags::all()) }
            /// Get the underlying bits value.
            ///
            /// The returned value is exactly the bits set in this flags value.
            #[inline]
            pub const fn bits(&self) -> u8 { self.0.bits() }
            /// Convert from a bits value.
            ///
            /// This method will return `None` if any unknown bits are set.
            #[inline]
            pub const fn from_bits(bits: u8)
                -> ::bitflags::__private::core::option::Option<Self> {
                match InternalBitFlags::from_bits(bits) {
                    ::bitflags::__private::core::option::Option::Some(bits) =>
                        ::bitflags::__private::core::option::Option::Some(Self(bits)),
                    ::bitflags::__private::core::option::Option::None =>
                        ::bitflags::__private::core::option::Option::None,
                }
            }
            /// Convert from a bits value, unsetting any unknown bits.
            #[inline]
            pub const fn from_bits_truncate(bits: u8) -> Self {
                Self(InternalBitFlags::from_bits_truncate(bits))
            }
            /// Convert from a bits value exactly.
            #[inline]
            pub const fn from_bits_retain(bits: u8) -> Self {
                Self(InternalBitFlags::from_bits_retain(bits))
            }
            /// Get a flags value with the bits of a flag with the given name set.
            ///
            /// This method will return `None` if `name` is empty or doesn't
            /// correspond to any named flag.
            #[inline]
            pub fn from_name(name: &str)
                -> ::bitflags::__private::core::option::Option<Self> {
                match InternalBitFlags::from_name(name) {
                    ::bitflags::__private::core::option::Option::Some(bits) =>
                        ::bitflags::__private::core::option::Option::Some(Self(bits)),
                    ::bitflags::__private::core::option::Option::None =>
                        ::bitflags::__private::core::option::Option::None,
                }
            }
            /// Whether all bits in this flags value are unset.
            #[inline]
            pub const fn is_empty(&self) -> bool { self.0.is_empty() }
            /// Whether all known bits in this flags value are set.
            #[inline]
            pub const fn is_all(&self) -> bool { self.0.is_all() }
            /// Whether any set bits in a source flags value are also set in a target flags value.
            #[inline]
            pub const fn intersects(&self, other: Self) -> bool {
                self.0.intersects(other.0)
            }
            /// Whether all set bits in a source flags value are also set in a target flags value.
            #[inline]
            pub const fn contains(&self, other: Self) -> bool {
                self.0.contains(other.0)
            }
            /// The bitwise or (`|`) of the bits in two flags values.
            #[inline]
            pub fn insert(&mut self, other: Self) { self.0.insert(other.0) }
            /// The intersection of a source flags value with the complement of a target flags
            /// value (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `remove` won't truncate `other`, but the `!` operator will.
            #[inline]
            pub fn remove(&mut self, other: Self) { self.0.remove(other.0) }
            /// The bitwise exclusive-or (`^`) of the bits in two flags values.
            #[inline]
            pub fn toggle(&mut self, other: Self) { self.0.toggle(other.0) }
            /// Call `insert` when `value` is `true` or `remove` when `value` is `false`.
            #[inline]
            pub fn set(&mut self, other: Self, value: bool) {
                self.0.set(other.0, value)
            }
            /// The bitwise and (`&`) of the bits in two flags values.
            #[inline]
            #[must_use]
            pub const fn intersection(self, other: Self) -> Self {
                Self(self.0.intersection(other.0))
            }
            /// The bitwise or (`|`) of the bits in two flags values.
            #[inline]
            #[must_use]
            pub const fn union(self, other: Self) -> Self {
                Self(self.0.union(other.0))
            }
            /// The intersection of a source flags value with the complement of a target flags
            /// value (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            #[must_use]
            pub const fn difference(self, other: Self) -> Self {
                Self(self.0.difference(other.0))
            }
            /// The bitwise exclusive-or (`^`) of the bits in two flags values.
            #[inline]
            #[must_use]
            pub const fn symmetric_difference(self, other: Self) -> Self {
                Self(self.0.symmetric_difference(other.0))
            }
            /// The bitwise negation (`!`) of the bits in a flags value, truncating the result.
            #[inline]
            #[must_use]
            pub const fn complement(self) -> Self {
                Self(self.0.complement())
            }
        }
        impl ::bitflags::__private::core::fmt::Binary for OuterTyData {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::Binary::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::Octal for OuterTyData {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::Octal::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::LowerHex for OuterTyData {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::LowerHex::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::UpperHex for OuterTyData {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::UpperHex::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::ops::BitOr for OuterTyData {
            type Output = Self;
            /// The bitwise or (`|`) of the bits in two flags values.
            #[inline]
            fn bitor(self, other: OuterTyData) -> Self { self.union(other) }
        }
        impl ::bitflags::__private::core::ops::BitOrAssign for OuterTyData {
            /// The bitwise or (`|`) of the bits in two flags values.
            #[inline]
            fn bitor_assign(&mut self, other: Self) { self.insert(other); }
        }
        impl ::bitflags::__private::core::ops::BitXor for OuterTyData {
            type Output = Self;
            /// The bitwise exclusive-or (`^`) of the bits in two flags values.
            #[inline]
            fn bitxor(self, other: Self) -> Self {
                self.symmetric_difference(other)
            }
        }
        impl ::bitflags::__private::core::ops::BitXorAssign for OuterTyData {
            /// The bitwise exclusive-or (`^`) of the bits in two flags values.
            #[inline]
            fn bitxor_assign(&mut self, other: Self) { self.toggle(other); }
        }
        impl ::bitflags::__private::core::ops::BitAnd for OuterTyData {
            type Output = Self;
            /// The bitwise and (`&`) of the bits in two flags values.
            #[inline]
            fn bitand(self, other: Self) -> Self { self.intersection(other) }
        }
        impl ::bitflags::__private::core::ops::BitAndAssign for OuterTyData {
            /// The bitwise and (`&`) of the bits in two flags values.
            #[inline]
            fn bitand_assign(&mut self, other: Self) {
                *self =
                    Self::from_bits_retain(self.bits()).intersection(other);
            }
        }
        impl ::bitflags::__private::core::ops::Sub for OuterTyData {
            type Output = Self;
            /// The intersection of a source flags value with the complement of a target flags value (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            fn sub(self, other: Self) -> Self { self.difference(other) }
        }
        impl ::bitflags::__private::core::ops::SubAssign for OuterTyData {
            /// The intersection of a source flags value with the complement of a target flags value (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            fn sub_assign(&mut self, other: Self) { self.remove(other); }
        }
        impl ::bitflags::__private::core::ops::Not for OuterTyData {
            type Output = Self;
            /// The bitwise negation (`!`) of the bits in a flags value, truncating the result.
            #[inline]
            fn not(self) -> Self { self.complement() }
        }
        impl ::bitflags::__private::core::iter::Extend<OuterTyData> for
            OuterTyData {
            /// The bitwise or (`|`) of the bits in each flags value.
            fn extend<T: ::bitflags::__private::core::iter::IntoIterator<Item
                = Self>>(&mut self, iterator: T) {
                for item in iterator { self.insert(item) }
            }
        }
        impl ::bitflags::__private::core::iter::FromIterator<OuterTyData> for
            OuterTyData {
            /// The bitwise or (`|`) of the bits in each flags value.
            fn from_iter<T: ::bitflags::__private::core::iter::IntoIterator<Item
                = Self>>(iterator: T) -> Self {
                use ::bitflags::__private::core::iter::Extend;
                let mut result = Self::empty();
                result.extend(iterator);
                result
            }
        }
        impl OuterTyData {
            /// Yield a set of contained flags values.
            ///
            /// Each yielded flags value will correspond to a defined named flag. Any unknown bits
            /// will be yielded together as a final flags value.
            #[inline]
            pub const fn iter(&self) -> ::bitflags::iter::Iter<OuterTyData> {
                ::bitflags::iter::Iter::__private_const_new(<OuterTyData as
                        ::bitflags::Flags>::FLAGS,
                    OuterTyData::from_bits_retain(self.bits()),
                    OuterTyData::from_bits_retain(self.bits()))
            }
            /// Yield a set of contained named flags values.
            ///
            /// This method is like [`iter`](#method.iter), except only yields bits in contained named flags.
            /// Any unknown bits, or bits not corresponding to a contained flag will not be yielded.
            #[inline]
            pub const fn iter_names(&self)
                -> ::bitflags::iter::IterNames<OuterTyData> {
                ::bitflags::iter::IterNames::__private_const_new(<OuterTyData
                        as ::bitflags::Flags>::FLAGS,
                    OuterTyData::from_bits_retain(self.bits()),
                    OuterTyData::from_bits_retain(self.bits()))
            }
        }
        impl ::bitflags::__private::core::iter::IntoIterator for OuterTyData {
            type Item = OuterTyData;
            type IntoIter = ::bitflags::iter::Iter<OuterTyData>;
            fn into_iter(self) -> Self::IntoIter { self.iter() }
        }
    };Clone, #[automatically_derived]
impl ::core::marker::Copy for OuterTyData { }Copy, #[automatically_derived]
impl ::core::fmt::Debug for OuterTyData {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f, "OuterTyData",
            &&self.0)
    }
}Debug, #[automatically_derived]
impl ::core::cmp::PartialEq for OuterTyData {
    #[inline]
    fn eq(&self, other: &OuterTyData) -> bool { self.0 == other.0 }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for OuterTyData {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _:
                ::core::cmp::AssertParamIsEq<<OuterTyData as
                ::bitflags::__private::PublicFlags>::Internal>;
    }
}Eq)]
377    struct OuterTyData: u8 {
378        /// To show that there is no outer type, the current type is directly used by a `static`
379        /// variable or a function/FnPtr
380        const NO_OUTER_TY = 0b01;
381        /// For NO_OUTER_TY cases, show that we are being directly used by a FnPtr specifically
382        /// FIXME(ctypes): this is only used for "bad behaviour" reproduced for compatibility's sake
383        const NO_OUTER_TY_FNPTR = 0b10;
384    }
385}
386
387impl OuterTyData {
388    /// Get the proper data for a given outer type.
389    fn from_ty<'tcx>(ty: Ty<'tcx>) -> Self {
390        match ty.kind() {
391            ty::FnPtr(..) => Self::NO_OUTER_TY | Self::NO_OUTER_TY_FNPTR,
392            ty::RawPtr(..)
393            | ty::Ref(..)
394            | ty::Adt(..)
395            | ty::Tuple(..)
396            | ty::Array(..)
397            | ty::Slice(_) => Self::empty(),
398            k @ _ => ::rustc_middle::util::bug::bug_fmt(format_args!("unexpected outer type {0:?} of kind {1:?}",
        ty, k))bug!("unexpected outer type {:?} of kind {:?}", ty, k),
399        }
400    }
401}
402
403/// Visitor used to recursively traverse MIR types and evaluate FFI-safety.
404/// It uses ``check_*`` methods as entrypoints to be called elsewhere,
405/// and ``visit_*`` methods to recurse.
406struct ImproperCTypesVisitor<'a, 'tcx> {
407    cx: &'a LateContext<'tcx>,
408    /// To prevent problems with recursive types,
409    /// add a types-in-check cache.
410    cache: FxHashSet<Ty<'tcx>>,
411    /// The original type being checked, before we recursed
412    /// to any other types it contains.
413    base_ty: Ty<'tcx>,
414    base_fn_mode: CItemKind,
415}
416
417impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
418    fn new(cx: &'a LateContext<'tcx>, base_ty: Ty<'tcx>, base_fn_mode: CItemKind) -> Self {
419        Self { cx, base_ty, base_fn_mode, cache: FxHashSet::default() }
420    }
421
422    /// Checks if the given indirection (box,ref,pointer) is "ffi-safe".
423    fn visit_indirection(
424        &mut self,
425        state: VisitorState,
426        ty: Ty<'tcx>,
427        inner_ty: Ty<'tcx>,
428        indirection_kind: IndirectionKind,
429    ) -> FfiResult<'tcx> {
430        use FfiResult::*;
431        let tcx = self.cx.tcx;
432
433        match indirection_kind {
434            IndirectionKind::Box => {
435                // FIXME(ctypes): this logic is broken, but it still fits the current tests:
436                // - for some reason `Box<_>`es in `extern "ABI" {}` blocks
437                //   (including within FnPtr:s)
438                //   are not treated as pointers but as FFI-unsafe structs
439                // - otherwise, treat the box itself correctly, and follow pointee safety logic
440                //   as described in the other `indirection_type` match branch.
441                if state.is_in_defined_function()
442                    || (state.is_in_fnptr() && #[allow(non_exhaustive_omitted_patterns)] match self.base_fn_mode {
    CItemKind::Definition => true,
    _ => false,
}matches!(self.base_fn_mode, CItemKind::Definition))
443                {
444                    if inner_ty.is_sized(tcx, self.cx.typing_env()) {
445                        return FfiSafe;
446                    } else {
447                        return FfiUnsafe {
448                            ty,
449                            reason: rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("box cannot be represented as a single pointer"))msg!("box cannot be represented as a single pointer"),
450                            help: None,
451                        };
452                    }
453                } else {
454                    // (mid-retcon-commit-chain comment:)
455                    // this is the original fallback behavior, which is wrong
456                    if let ty::Adt(def, args) = ty.kind() {
457                        self.visit_struct_or_union(state, ty, *def, args)
458                    } else if truecfg!(debug_assertions) {
459                        ::rustc_middle::util::bug::bug_fmt(format_args!("ImproperCTypes: this retcon commit was badly written"))bug!("ImproperCTypes: this retcon commit was badly written")
460                    } else {
461                        FfiSafe
462                    }
463                }
464            }
465            IndirectionKind::Ref | IndirectionKind::RawPtr => {
466                // Weird behaviour for pointee safety. the big question here is
467                // "if you have a FFI-unsafe pointee behind a FFI-safe pointer type, is it ok?"
468                // The answer until now is:
469                // "It's OK for rust-defined functions and callbacks, we'll assume those are
470                // meant to be opaque types on the other side of the FFI boundary".
471                //
472                // Reasoning:
473                // For extern function declarations, the actual definition of the function is
474                // written somewhere else, meaning the declaration is free to express this
475                // opaqueness with an extern type (opaque caller-side) or a std::ffi::c_void
476                // (opaque callee-side). For extern function definitions, however, in the case
477                // where the type is opaque caller-side, it is not opaque callee-side,
478                // and having the full type information is necessary to compile the function.
479                //
480                // It might be better to rething this, or even ignore pointee safety for a first
481                // batch of behaviour changes. See the discussion that ends with
482                // https://github.com/rust-lang/rust/pull/134697#issuecomment-2692610258
483                if (state.is_in_defined_function() || state.is_in_fnptr())
484                    && inner_ty.is_sized(self.cx.tcx, self.cx.typing_env())
485                {
486                    FfiSafe
487                } else {
488                    self.visit_type(state, OuterTyData::from_ty(ty), inner_ty)
489                }
490            }
491        }
492    }
493
494    /// Checks if the given `VariantDef`'s field types are "ffi-safe".
495    fn visit_variant_fields(
496        &mut self,
497        state: VisitorState,
498        ty: Ty<'tcx>,
499        def: AdtDef<'tcx>,
500        variant: &ty::VariantDef,
501        args: GenericArgsRef<'tcx>,
502    ) -> FfiResult<'tcx> {
503        use FfiResult::*;
504
505        let transparent_with_all_zst_fields = if def.repr().transparent() {
506            if let Some(field) = super::transparent_newtype_field(self.cx.tcx, variant) {
507                // Transparent newtypes have at most one non-ZST field which needs to be checked..
508                let field_ty = get_type_from_field(self.cx, field, args);
509                match self.visit_type(state, OuterTyData::from_ty(ty), field_ty) {
510                    FfiUnsafe { ty, .. } if ty.is_unit() => (),
511                    r => return r,
512                }
513
514                false
515            } else {
516                // ..or have only ZST fields, which is FFI-unsafe (unless those fields are all
517                // `PhantomData`).
518                true
519            }
520        } else {
521            false
522        };
523
524        // We can't completely trust `repr(C)` markings, so make sure the fields are actually safe.
525        let mut all_phantom = !variant.fields.is_empty();
526        for field in &variant.fields {
527            let field_ty = get_type_from_field(self.cx, field, args);
528            all_phantom &= match self.visit_type(state, OuterTyData::from_ty(ty), field_ty) {
529                FfiSafe => false,
530                // `()` fields are FFI-safe!
531                FfiUnsafe { ty, .. } if ty.is_unit() => false,
532                FfiPhantom(..) => true,
533                r @ FfiUnsafe { .. } => return r,
534            }
535        }
536
537        if all_phantom {
538            FfiPhantom(ty)
539        } else if transparent_with_all_zst_fields {
540            FfiUnsafe {
541                ty,
542                reason: rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("this struct contains only zero-sized fields"))msg!("this struct contains only zero-sized fields"),
543                help: None,
544            }
545        } else {
546            FfiSafe
547        }
548    }
549
550    fn visit_struct_or_union(
551        &mut self,
552        state: VisitorState,
553        ty: Ty<'tcx>,
554        def: AdtDef<'tcx>,
555        args: GenericArgsRef<'tcx>,
556    ) -> FfiResult<'tcx> {
557        if true {
    if !#[allow(non_exhaustive_omitted_patterns)] match def.adt_kind() {
                AdtKind::Struct | AdtKind::Union => true,
                _ => false,
            } {
        ::core::panicking::panic("assertion failed: matches!(def.adt_kind(), AdtKind::Struct | AdtKind::Union)")
    };
};debug_assert!(matches!(def.adt_kind(), AdtKind::Struct | AdtKind::Union));
558        use FfiResult::*;
559
560        if !def.repr().c() && !def.repr().transparent() {
561            return FfiUnsafe {
562                ty,
563                reason: if def.is_struct() {
564                    rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("this struct has unspecified layout"))msg!("this struct has unspecified layout")
565                } else {
566                    rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("this union has unspecified layout"))msg!("this union has unspecified layout")
567                },
568                help: if def.is_struct() {
569                    Some(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct"))msg!(
570                        "consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct"
571                    ))
572                } else {
573                    // FIXME(ctypes): confirm that this makes sense for unions once #60405 / RFC2645 stabilises
574                    Some(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this union"))msg!(
575                        "consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this union"
576                    ))
577                },
578            };
579        }
580
581        if def.non_enum_variant().field_list_has_applicable_non_exhaustive() {
582            return FfiUnsafe {
583                ty,
584                reason: if def.is_struct() {
585                    rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("this struct is non-exhaustive"))msg!("this struct is non-exhaustive")
586                } else {
587                    rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("this union is non-exhaustive"))msg!("this union is non-exhaustive")
588                },
589                help: None,
590            };
591        }
592
593        if def.non_enum_variant().fields.is_empty() {
594            FfiUnsafe {
595                ty,
596                reason: if def.is_struct() {
597                    rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("this struct has no fields"))msg!("this struct has no fields")
598                } else {
599                    rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("this union has no fields"))msg!("this union has no fields")
600                },
601                help: if def.is_struct() {
602                    Some(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("consider adding a member to this struct"))msg!("consider adding a member to this struct"))
603                } else {
604                    Some(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("consider adding a member to this union"))msg!("consider adding a member to this union"))
605                },
606            }
607        } else {
608            self.visit_variant_fields(state, ty, def, def.non_enum_variant(), args)
609        }
610    }
611
612    fn visit_enum(
613        &mut self,
614        state: VisitorState,
615        ty: Ty<'tcx>,
616        def: AdtDef<'tcx>,
617        args: GenericArgsRef<'tcx>,
618    ) -> FfiResult<'tcx> {
619        if true {
    if !#[allow(non_exhaustive_omitted_patterns)] match def.adt_kind() {
                AdtKind::Enum => true,
                _ => false,
            } {
        ::core::panicking::panic("assertion failed: matches!(def.adt_kind(), AdtKind::Enum)")
    };
};debug_assert!(matches!(def.adt_kind(), AdtKind::Enum));
620        use FfiResult::*;
621
622        if def.variants().is_empty() {
623            // Empty enums are okay... although sort of useless.
624            return FfiSafe;
625        }
626        // Check for a repr() attribute to specify the size of the
627        // discriminant.
628        if !def.repr().c() && !def.repr().transparent() && def.repr().int.is_none() {
629            // Special-case types like `Option<extern fn()>` and `Result<extern fn(), ()>`
630            if let Some(inner_ty) = repr_nullable_ptr(self.cx.tcx, self.cx.typing_env(), ty) {
631                return self.visit_type(state, OuterTyData::from_ty(ty), inner_ty);
632            }
633
634            return FfiUnsafe {
635                ty,
636                reason: rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("enum has no representation hint"))msg!("enum has no representation hint"),
637                help: Some(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum"))msg!(
638                    "consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum"
639                )),
640            };
641        }
642
643        let non_exhaustive = def.variant_list_has_applicable_non_exhaustive();
644        // Check the contained variants.
645        let ret = def.variants().iter().try_for_each(|variant| {
646            check_non_exhaustive_variant(non_exhaustive, variant)
647                .map_break(|reason| FfiUnsafe { ty, reason, help: None })?;
648
649            match self.visit_variant_fields(state, ty, def, variant, args) {
650                FfiSafe => ControlFlow::Continue(()),
651                r => ControlFlow::Break(r),
652            }
653        });
654        if let ControlFlow::Break(result) = ret {
655            return result;
656        }
657
658        FfiSafe
659    }
660
661    /// Checks if the given type is "ffi-safe" (has a stable, well-defined
662    /// representation which can be exported to C code).
663    fn visit_type(
664        &mut self,
665        state: VisitorState,
666        outer_ty: OuterTyData,
667        ty: Ty<'tcx>,
668    ) -> FfiResult<'tcx> {
669        use FfiResult::*;
670
671        let tcx = self.cx.tcx;
672
673        // Protect against infinite recursion, for example
674        // `struct S(*mut S);`.
675        // FIXME: A recursion limit is necessary as well, for irregular
676        // recursive types.
677        if !self.cache.insert(ty) {
678            return FfiSafe;
679        }
680
681        match *ty.kind() {
682            ty::Adt(def, args) => {
683                if let Some(inner_ty) = ty.boxed_ty() {
684                    return self.visit_indirection(state, ty, inner_ty, IndirectionKind::Box);
685                }
686                if def.is_phantom_data() {
687                    return FfiPhantom(ty);
688                }
689                match def.adt_kind() {
690                    AdtKind::Struct | AdtKind::Union => {
691                        if let Some(sym::cstring_type | sym::cstr_type) =
692                            tcx.get_diagnostic_name(def.did())
693                            && !self.base_ty.is_mutable_ptr()
694                        {
695                            return FfiUnsafe {
696                                ty,
697                                reason: rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("`CStr`/`CString` do not have a guaranteed layout"))msg!("`CStr`/`CString` do not have a guaranteed layout"),
698                                help: Some(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`"))msg!(
699                                    "consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`"
700                                )),
701                            };
702                        }
703                        self.visit_struct_or_union(state, ty, def, args)
704                    }
705                    AdtKind::Enum => self.visit_enum(state, ty, def, args),
706                }
707            }
708
709            // Pattern types are just extra invariants on the type that you need to uphold,
710            // but only the base type is relevant for being representable in FFI.
711            // (note: this lint was written when pattern types could only be integers constrained to ranges)
712            ty::Pat(pat_ty, _) => self.visit_type(state, outer_ty, pat_ty),
713
714            // types which likely have a stable representation, if the target architecture defines those
715            // note: before rust 1.77, 128-bit ints were not FFI-safe on x86_64
716            ty::Int(..) | ty::Uint(..) | ty::Float(..) => FfiResult::FfiSafe,
717
718            ty::Bool => FfiResult::FfiSafe,
719
720            ty::Char => FfiResult::FfiUnsafe {
721                ty,
722                reason: rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("the `char` type has no C equivalent"))msg!("the `char` type has no C equivalent"),
723                help: Some(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("consider using `u32` or `libc::wchar_t` instead"))msg!("consider using `u32` or `libc::wchar_t` instead")),
724            },
725
726            ty::Slice(_) => FfiUnsafe {
727                ty,
728                reason: rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("slices have no C equivalent"))msg!("slices have no C equivalent"),
729                help: Some(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("consider using a raw pointer instead"))msg!("consider using a raw pointer instead")),
730            },
731
732            ty::Dynamic(..) => {
733                FfiUnsafe { ty, reason: rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("trait objects have no C equivalent"))msg!("trait objects have no C equivalent"), help: None }
734            }
735
736            ty::Str => FfiUnsafe {
737                ty,
738                reason: rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("string slices have no C equivalent"))msg!("string slices have no C equivalent"),
739                help: Some(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("consider using `*const u8` and a length instead"))msg!("consider using `*const u8` and a length instead")),
740            },
741
742            ty::Tuple(tuple) => {
743                // C functions can return void
744                let empty_and_safe = tuple.is_empty()
745                    && outer_ty.contains(OuterTyData::NO_OUTER_TY)
746                    && state.is_in_function_return();
747
748                if empty_and_safe {
749                    FfiSafe
750                } else {
751                    FfiUnsafe {
752                        ty,
753                        reason: rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("tuples have unspecified layout"))msg!("tuples have unspecified layout"),
754                        help: Some(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("consider using a struct instead"))msg!("consider using a struct instead")),
755                    }
756                }
757            }
758
759            ty::RawPtr(ty, _)
760                if match ty.kind() {
761                    ty::Tuple(tuple) => tuple.is_empty(),
762                    _ => false,
763                } =>
764            {
765                FfiSafe
766            }
767
768            ty::RawPtr(inner_ty, _) => {
769                return self.visit_indirection(state, ty, inner_ty, IndirectionKind::RawPtr);
770            }
771            ty::Ref(_, inner_ty, _) => {
772                return self.visit_indirection(state, ty, inner_ty, IndirectionKind::Ref);
773            }
774
775            ty::Array(inner_ty, _) => {
776                if state.is_in_function()
777                    && outer_ty.contains(OuterTyData::NO_OUTER_TY)
778                    // FIXME(ctypes): VVV-this-VVV shouldn't be the case
779                    && !outer_ty.contains(OuterTyData::NO_OUTER_TY_FNPTR)
780                {
781                    // C doesn't really support passing arrays by value - the only way to pass an array by value
782                    // is through a struct.
783                    FfiResult::FfiUnsafe {
784                        ty,
785                        reason: rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("passing raw arrays by value is not FFI-safe"))msg!("passing raw arrays by value is not FFI-safe"),
786                        help: Some(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("consider passing a pointer to the array"))msg!("consider passing a pointer to the array")),
787                    }
788                } else {
789                    // let's allow phantoms to go through,
790                    // since an array of 1-ZSTs is also a 1-ZST
791                    self.visit_type(state, OuterTyData::from_ty(ty), inner_ty)
792                }
793            }
794
795            ty::FnPtr(sig_tys, hdr) => {
796                let sig = sig_tys.with(hdr);
797                if sig.abi().is_rustic_abi() {
798                    return FfiUnsafe {
799                        ty,
800                        reason: rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("this function pointer has Rust-specific calling convention"))msg!("this function pointer has Rust-specific calling convention"),
801                        help: Some(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("consider using an `extern fn(...) -> ...` function pointer instead"))msg!(
802                            "consider using an `extern fn(...) -> ...` function pointer instead"
803                        )),
804                    };
805                }
806
807                let sig = tcx.instantiate_bound_regions_with_erased(sig);
808                for arg in sig.inputs() {
809                    match self.visit_type(
810                        VisitorState::ARGUMENT_TY_IN_FNPTR,
811                        OuterTyData::from_ty(ty),
812                        *arg,
813                    ) {
814                        FfiSafe => {}
815                        r => return r,
816                    }
817                }
818
819                let ret_ty = sig.output();
820
821                self.visit_type(VisitorState::RETURN_TY_IN_FNPTR, OuterTyData::from_ty(ty), ret_ty)
822            }
823
824            ty::Foreign(..) => FfiSafe,
825
826            ty::Never => FfiSafe,
827
828            // While opaque types are checked for earlier, if a projection in a struct field
829            // normalizes to an opaque type, then it will reach this branch.
830            ty::Alias(ty::AliasTy { kind: ty::Opaque { .. }, .. }) => {
831                FfiUnsafe { ty, reason: rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("opaque types have no C equivalent"))msg!("opaque types have no C equivalent"), help: None }
832            }
833
834            // `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe,
835            //  so they are currently ignored for the purposes of this lint.
836            ty::Param(..)
837            | ty::Alias(ty::AliasTy {
838                kind: ty::Projection { .. } | ty::Inherent { .. }, ..
839            }) if state.can_expect_ty_params() => FfiSafe,
840
841            ty::UnsafeBinder(_) => FfiUnsafe {
842                ty,
843                reason: rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("unsafe binders are incompatible with foreign function interfaces"))msg!("unsafe binders are incompatible with foreign function interfaces"),
844                help: None,
845            },
846
847            ty::Param(..)
848            | ty::Alias(ty::AliasTy {
849                kind: ty::Projection { .. } | ty::Inherent { .. } | ty::Free { .. },
850                ..
851            })
852            | ty::Infer(..)
853            | ty::Bound(..)
854            | ty::Error(_)
855            | ty::Closure(..)
856            | ty::CoroutineClosure(..)
857            | ty::Coroutine(..)
858            | ty::CoroutineWitness(..)
859            | ty::Placeholder(..)
860            | ty::FnDef(..) => ::rustc_middle::util::bug::bug_fmt(format_args!("unexpected type in foreign function: {0:?}",
        ty))bug!("unexpected type in foreign function: {:?}", ty),
861        }
862    }
863
864    fn visit_for_opaque_ty(&mut self, ty: Ty<'tcx>) -> PartialFfiResult<'tcx> {
865        struct ProhibitOpaqueTypes;
866        impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for ProhibitOpaqueTypes {
867            type Result = ControlFlow<Ty<'tcx>>;
868
869            fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
870                if !ty.has_opaque_types() {
871                    return ControlFlow::Continue(());
872                }
873
874                if let ty::Alias(ty::AliasTy { kind: ty::Opaque { .. }, .. }) = ty.kind() {
875                    ControlFlow::Break(ty)
876                } else {
877                    ty.super_visit_with(self)
878                }
879            }
880        }
881
882        ty.visit_with(&mut ProhibitOpaqueTypes).break_value().map(|ty| FfiResult::FfiUnsafe {
883            ty,
884            reason: rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("opaque types have no C equivalent"))msg!("opaque types have no C equivalent"),
885            help: None,
886        })
887    }
888
889    fn check_type(&mut self, state: VisitorState, ty: Ty<'tcx>) -> FfiResult<'tcx> {
890        let ty = self
891            .cx
892            .tcx
893            .try_normalize_erasing_regions(self.cx.typing_env(), Unnormalized::new_wip(ty))
894            .unwrap_or(ty);
895        if let Some(res) = self.visit_for_opaque_ty(ty) {
896            return res;
897        }
898
899        self.visit_type(state, OuterTyData::NO_OUTER_TY, ty)
900    }
901}
902
903impl<'tcx> ImproperCTypesLint {
904    /// Find any fn-ptr types with external ABIs in `ty`, and FFI-checks them.
905    /// For example, `Option<extern "C" fn()>` FFI-checks `extern "C" fn()`.
906    fn check_type_for_external_abi_fnptr(
907        &mut self,
908        cx: &LateContext<'tcx>,
909        state: VisitorState,
910        hir_ty: &hir::Ty<'tcx>,
911        ty: Ty<'tcx>,
912        fn_mode: CItemKind,
913    ) {
914        struct FnPtrFinder<'tcx> {
915            spans: Vec<Span>,
916            tys: Vec<Ty<'tcx>>,
917        }
918
919        impl<'tcx> hir::intravisit::Visitor<'_> for FnPtrFinder<'tcx> {
920            fn visit_ty(&mut self, ty: &'_ hir::Ty<'_, AmbigArg>) {
921                {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_lint/src/types/improper_ctypes.rs:921",
                        "rustc_lint::types::improper_ctypes",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/types/improper_ctypes.rs"),
                        ::tracing_core::__macro_support::Option::Some(921u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_lint::types::improper_ctypes"),
                        ::tracing_core::field::FieldSet::new(&["ty"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&debug(&ty) as
                                            &dyn Value))])
            });
    } else { ; }
};debug!(?ty);
922                if let hir::TyKind::FnPtr(hir::FnPtrTy { abi, .. }) = ty.kind
923                    && !abi.is_rustic_abi()
924                {
925                    self.spans.push(ty.span);
926                }
927
928                hir::intravisit::walk_ty(self, ty)
929            }
930        }
931
932        impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for FnPtrFinder<'tcx> {
933            type Result = ();
934
935            fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
936                if let ty::FnPtr(_, hdr) = ty.kind()
937                    && !hdr.abi().is_rustic_abi()
938                {
939                    self.tys.push(ty);
940                }
941
942                ty.super_visit_with(self)
943            }
944        }
945
946        let mut visitor = FnPtrFinder { spans: Vec::new(), tys: Vec::new() };
947        ty.visit_with(&mut visitor);
948        visitor.visit_ty_unambig(hir_ty);
949
950        let all_types = iter::zip(visitor.tys.drain(..), visitor.spans.drain(..));
951        for (fn_ptr_ty, span) in all_types {
952            let mut visitor = ImproperCTypesVisitor::new(cx, fn_ptr_ty, fn_mode);
953            // FIXME(ctypes): make a check_for_fnptr
954            let ffi_res = visitor.check_type(state, fn_ptr_ty);
955
956            self.process_ffi_result(cx, span, ffi_res, fn_mode);
957        }
958    }
959
960    /// Regardless of a function's need to be "ffi-safe", look for fn-ptr argument/return types
961    /// that need to be checked for ffi-safety.
962    fn check_fn_for_external_abi_fnptr(
963        &mut self,
964        cx: &LateContext<'tcx>,
965        fn_mode: CItemKind,
966        def_id: LocalDefId,
967        decl: &'tcx hir::FnDecl<'_>,
968    ) {
969        let sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_norm_wip();
970        let sig = cx.tcx.instantiate_bound_regions_with_erased(sig);
971
972        for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) {
973            let state = VisitorState::argument_from_fnmode(fn_mode);
974            self.check_type_for_external_abi_fnptr(cx, state, input_hir, *input_ty, fn_mode);
975        }
976
977        if let hir::FnRetTy::Return(ret_hir) = decl.output {
978            let state = VisitorState::return_from_fnmode(fn_mode);
979            self.check_type_for_external_abi_fnptr(cx, state, ret_hir, sig.output(), fn_mode);
980        }
981    }
982
983    /// For a local definition of a #[repr(C)] struct/enum/union, check that it is indeed FFI-safe.
984    fn check_reprc_adt(
985        &mut self,
986        cx: &LateContext<'tcx>,
987        item: &'tcx hir::Item<'tcx>,
988        adt_def: AdtDef<'tcx>,
989    ) {
990        if true {
    if !(adt_def.repr().c() && !adt_def.repr().packed() &&
                adt_def.repr().align.is_none()) {
        ::core::panicking::panic("assertion failed: adt_def.repr().c() && !adt_def.repr().packed() &&\n    adt_def.repr().align.is_none()")
    };
};debug_assert!(
991            adt_def.repr().c() && !adt_def.repr().packed() && adt_def.repr().align.is_none()
992        );
993
994        // FIXME(ctypes): this following call is awkward.
995        // is there a way to perform its logic in MIR space rather than HIR space?
996        // (so that its logic can be absorbed into visitor.visit_struct_or_union)
997        check_struct_for_power_alignment(cx, item, adt_def);
998    }
999
1000    fn check_foreign_static(&mut self, cx: &LateContext<'tcx>, id: hir::OwnerId, span: Span) {
1001        let ty = cx.tcx.type_of(id).instantiate_identity().skip_norm_wip();
1002        let mut visitor = ImproperCTypesVisitor::new(cx, ty, CItemKind::Declaration);
1003        let ffi_res = visitor.check_type(VisitorState::STATIC_TY, ty);
1004        self.process_ffi_result(cx, span, ffi_res, CItemKind::Declaration);
1005    }
1006
1007    /// Check if a function's argument types and result type are "ffi-safe".
1008    fn check_foreign_fn(
1009        &mut self,
1010        cx: &LateContext<'tcx>,
1011        fn_mode: CItemKind,
1012        def_id: LocalDefId,
1013        decl: &'tcx hir::FnDecl<'_>,
1014    ) {
1015        let sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_norm_wip();
1016        let sig = cx.tcx.instantiate_bound_regions_with_erased(sig);
1017
1018        for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) {
1019            let state = VisitorState::argument_from_fnmode(fn_mode);
1020            let mut visitor = ImproperCTypesVisitor::new(cx, *input_ty, fn_mode);
1021            let ffi_res = visitor.check_type(state, *input_ty);
1022            self.process_ffi_result(cx, input_hir.span, ffi_res, fn_mode);
1023        }
1024
1025        if let hir::FnRetTy::Return(ret_hir) = decl.output {
1026            let state = VisitorState::return_from_fnmode(fn_mode);
1027            let mut visitor = ImproperCTypesVisitor::new(cx, sig.output(), fn_mode);
1028            let ffi_res = visitor.check_type(state, sig.output());
1029            self.process_ffi_result(cx, ret_hir.span, ffi_res, fn_mode);
1030        }
1031    }
1032
1033    fn process_ffi_result(
1034        &self,
1035        cx: &LateContext<'tcx>,
1036        sp: Span,
1037        res: FfiResult<'tcx>,
1038        fn_mode: CItemKind,
1039    ) {
1040        match res {
1041            FfiResult::FfiSafe => {}
1042            FfiResult::FfiPhantom(ty) => {
1043                self.emit_ffi_unsafe_type_lint(
1044                    cx,
1045                    ty,
1046                    sp,
1047                    rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("composed only of `PhantomData`"))msg!("composed only of `PhantomData`"),
1048                    None,
1049                    fn_mode,
1050                );
1051            }
1052            FfiResult::FfiUnsafe { ty, reason, help } => {
1053                self.emit_ffi_unsafe_type_lint(cx, ty, sp, reason, help, fn_mode);
1054            }
1055        }
1056    }
1057
1058    fn emit_ffi_unsafe_type_lint(
1059        &self,
1060        cx: &LateContext<'tcx>,
1061        ty: Ty<'tcx>,
1062        sp: Span,
1063        note: DiagMessage,
1064        help: Option<DiagMessage>,
1065        fn_mode: CItemKind,
1066    ) {
1067        let lint = match fn_mode {
1068            CItemKind::Declaration => IMPROPER_CTYPES,
1069            CItemKind::Definition => IMPROPER_CTYPES_DEFINITIONS,
1070        };
1071        let desc = match fn_mode {
1072            CItemKind::Declaration => "block",
1073            CItemKind::Definition => "fn",
1074        };
1075        let span_note = if let ty::Adt(def, _) = ty.kind()
1076            && let Some(sp) = cx.tcx.hir_span_if_local(def.did())
1077        {
1078            Some(sp)
1079        } else {
1080            None
1081        };
1082        cx.emit_span_lint(lint, sp, ImproperCTypes { ty, desc, label: sp, help, note, span_note });
1083    }
1084}
1085
1086/// `ImproperCTypesDefinitions` checks items outside of foreign items (e.g. stuff that isn't in
1087/// `extern "C" { }` blocks):
1088///
1089/// - `extern "<abi>" fn` definitions are checked in the same way as the
1090///   `ImproperCtypesDeclarations` visitor checks functions if `<abi>` is external (e.g. "C").
1091/// - All other items which contain types (e.g. other functions, struct definitions, etc) are
1092///   checked for extern fn-ptrs with external ABIs.
1093impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
1094    fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, it: &hir::ForeignItem<'tcx>) {
1095        let abi = cx.tcx.hir_get_foreign_abi(it.hir_id());
1096
1097        match it.kind {
1098            hir::ForeignItemKind::Fn(sig, _, _) => {
1099                // fnptrs are a special case, they always need to be treated as
1100                // "the element rendered unsafe" because their unsafety doesn't affect
1101                // their surroundings, and their type is often declared inline
1102                if !abi.is_rustic_abi() {
1103                    self.check_foreign_fn(cx, CItemKind::Declaration, it.owner_id.def_id, sig.decl);
1104                } else {
1105                    self.check_fn_for_external_abi_fnptr(
1106                        cx,
1107                        CItemKind::Declaration,
1108                        it.owner_id.def_id,
1109                        sig.decl,
1110                    );
1111                }
1112            }
1113            hir::ForeignItemKind::Static(ty, _, _) if !abi.is_rustic_abi() => {
1114                self.check_foreign_static(cx, it.owner_id, ty.span);
1115            }
1116            hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => (),
1117        }
1118    }
1119
1120    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
1121        match item.kind {
1122            hir::ItemKind::Static(_, _, ty, _)
1123            | hir::ItemKind::Const(_, _, ty, _)
1124            | hir::ItemKind::TyAlias(_, _, ty) => {
1125                self.check_type_for_external_abi_fnptr(
1126                    cx,
1127                    VisitorState::STATIC_TY,
1128                    ty,
1129                    cx.tcx.type_of(item.owner_id).instantiate_identity().skip_norm_wip(),
1130                    CItemKind::Definition,
1131                );
1132            }
1133            // See `check_fn` for declarations, `check_foreign_items` for definitions in extern blocks
1134            hir::ItemKind::Fn { .. } => {}
1135            hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) | hir::ItemKind::Enum(..) => {
1136                // looking for extern FnPtr:s is delegated to `check_field_def`.
1137                let adt_def: AdtDef<'tcx> = cx.tcx.adt_def(item.owner_id.to_def_id());
1138
1139                if adt_def.repr().c() && !adt_def.repr().packed() && adt_def.repr().align.is_none()
1140                {
1141                    self.check_reprc_adt(cx, item, adt_def);
1142                }
1143            }
1144
1145            // Doesn't define something that can contain a external type to be checked.
1146            hir::ItemKind::Impl(..)
1147            | hir::ItemKind::TraitAlias(..)
1148            | hir::ItemKind::Trait(..)
1149            | hir::ItemKind::GlobalAsm { .. }
1150            | hir::ItemKind::ForeignMod { .. }
1151            | hir::ItemKind::Mod(..)
1152            | hir::ItemKind::Macro(..)
1153            | hir::ItemKind::Use(..)
1154            | hir::ItemKind::ExternCrate(..) => {}
1155        }
1156    }
1157
1158    fn check_field_def(&mut self, cx: &LateContext<'tcx>, field: &'tcx hir::FieldDef<'tcx>) {
1159        self.check_type_for_external_abi_fnptr(
1160            cx,
1161            VisitorState::STATIC_TY,
1162            field.ty,
1163            cx.tcx.type_of(field.def_id).instantiate_identity().skip_norm_wip(),
1164            CItemKind::Definition,
1165        );
1166    }
1167
1168    fn check_fn(
1169        &mut self,
1170        cx: &LateContext<'tcx>,
1171        kind: hir::intravisit::FnKind<'tcx>,
1172        decl: &'tcx hir::FnDecl<'_>,
1173        _: &'tcx hir::Body<'_>,
1174        _: Span,
1175        id: LocalDefId,
1176    ) {
1177        use hir::intravisit::FnKind;
1178
1179        let abi = match kind {
1180            FnKind::ItemFn(_, _, header, ..) => header.abi,
1181            FnKind::Method(_, sig, ..) => sig.header.abi,
1182            _ => return,
1183        };
1184
1185        // fnptrs are a special case, they always need to be treated as
1186        // "the element rendered unsafe" because their unsafety doesn't affect
1187        // their surroundings, and their type is often declared inline
1188        if !abi.is_rustic_abi() {
1189            self.check_foreign_fn(cx, CItemKind::Definition, id, decl);
1190        } else {
1191            self.check_fn_for_external_abi_fnptr(cx, CItemKind::Definition, id, decl);
1192        }
1193    }
1194}