Skip to main content

rustc_lint/types/
improper_ctypes.rs

1use std::cell::RefCell;
2use std::iter;
3use std::ops::ControlFlow;
4
5use bitflags::bitflags;
6use rustc_abi::VariantIdx;
7use rustc_attr_ir::LangItem;
8use rustc_data_structures::fx::FxHashSet;
9use rustc_errors::{DiagMessage, msg};
10use rustc_hashes::Hash128;
11use rustc_hir::def::CtorKind;
12use rustc_hir::intravisit::Visitor;
13use rustc_hir::{self as hir, AmbigArg};
14use rustc_lint_defs::{declare_lint, impl_lint_pass};
15use rustc_middle::ty::{
16    self, Adt, AdtDef, AdtKind, GenericArgs, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
17    TypeVisitableExt, Unnormalized,
18};
19use rustc_span::def_id::LocalDefId;
20use rustc_span::{Span, bug, sym};
21use rustc_target::spec::Os;
22use tracing::debug;
23
24use super::repr_nullable_ptr;
25use crate::diagnostics::{ImproperCTypes, UsesPowerAlignment};
26use crate::{LateContext, LateLintPass, LintContext};
27
28#[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",
            ..
        };declare_lint! {
29    /// The `improper_ctypes` lint detects incorrect use of types in foreign
30    /// modules.
31    ///
32    /// ### Example
33    ///
34    /// ```rust
35    /// unsafe extern "C" {
36    ///     static STATIC: String;
37    /// }
38    /// ```
39    ///
40    /// {{produces}}
41    ///
42    /// ### Explanation
43    ///
44    /// The compiler has several checks to verify that types used in `extern`
45    /// blocks are safe and follow certain rules to ensure proper
46    /// compatibility with the foreign interfaces. This lint is issued when it
47    /// detects a probable mistake in a definition. The lint usually should
48    /// provide a description of the issue, along with possibly a hint on how
49    /// to resolve it.
50    IMPROPER_CTYPES,
51    Warn,
52    "proper use of libc types in foreign modules"
53}
54
55#[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",
            ..
        };declare_lint! {
56    /// The `improper_ctypes_definitions` lint detects incorrect use of
57    /// [`extern` function] definitions.
58    ///
59    /// [`extern` function]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier
60    ///
61    /// ### Example
62    ///
63    /// ```rust
64    /// # #![allow(unused)]
65    /// pub extern "C" fn str_type(p: &str) { }
66    /// ```
67    ///
68    /// {{produces}}
69    ///
70    /// ### Explanation
71    ///
72    /// There are many parameter and return types that may be specified in an
73    /// `extern` function that are not compatible with the given ABI. This
74    /// lint is an alert that these types should not be used. The lint usually
75    /// should provide a description of the issue, along with possibly a hint
76    /// on how to resolve it.
77    IMPROPER_CTYPES_DEFINITIONS,
78    Warn,
79    "proper use of libc types in foreign item definitions"
80}
81
82#[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)",
            ..
        };declare_lint! {
83    /// The `uses_power_alignment` lint detects specific `repr(C)`
84    /// aggregates on AIX.
85    /// In its platform C ABI, AIX uses the "power" (as in PowerPC) alignment
86    /// rule (detailed in https://www.ibm.com/docs/en/xl-c-and-cpp-aix/16.1?topic=data-using-alignment-modes#alignment),
87    /// which can also be set for XLC by `#pragma align(power)` or
88    /// `-qalign=power`. Aggregates with a floating-point type as the
89    /// recursively first field (as in "at offset 0") modify the layout of
90    /// *subsequent* fields of the associated structs to use an alignment value
91    /// where the floating-point type is aligned on a 4-byte boundary.
92    ///
93    /// Effectively, subsequent floating-point fields act as-if they are `repr(packed(4))`. This
94    /// would be unsound to do in a `repr(C)` type without all the restrictions that come with
95    /// `repr(packed)`. Rust instead chooses a layout that maintains soundness of Rust code, at the
96    /// expense of incompatibility with C code.
97    ///
98    /// ### Example
99    ///
100    /// ```rust,ignore (fails on non-powerpc64-ibm-aix)
101    /// #[repr(C)]
102    /// pub struct Floats {
103    ///     a: f64,
104    ///     b: u8,
105    ///     c: f64,
106    /// }
107    /// ```
108    ///
109    /// This will produce:
110    ///
111    /// ```text
112    /// warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
113    ///  --> <source>:5:3
114    ///   |
115    /// 5 |   c: f64,
116    ///   |   ^^^^^^
117    ///   |
118    ///   = note: `#[warn(uses_power_alignment)]` on by default
119    /// ```
120    ///
121    /// ### Explanation
122    ///
123    /// The power alignment rule specifies that the above struct has the
124    /// following alignment:
125    ///  - offset_of!(Floats, a) == 0
126    ///  - offset_of!(Floats, b) == 8
127    ///  - offset_of!(Floats, c) == 12
128    ///
129    /// However, Rust currently aligns `c` at `offset_of!(Floats, c) == 16`.
130    /// Using offset 12 would be unsound since `f64` generally must be 8-aligned on this target.
131    /// Thus, a warning is produced for the above struct.
132    USES_POWER_ALIGNMENT,
133    Warn,
134    "Structs do not follow the power alignment rule under repr(C)"
135}
136
137/// Remembers types we already checked and found FFI-safe, so we don't check the
138/// same type again every time it shows up in another function.
139/// We only remember "safe" types, never "unsafe" ones. That way we never need to
140/// keep the actual type around, just a fingerprint of it.
141#[derive(#[automatically_derived]impl ::core::default::Default for ImproperCTypesLint {
    #[inline]
    fn default() -> Self {
        ImproperCTypesLint { known_safe: ::core::default::Default::default() }
    }
}Default)]
142pub(crate) struct ImproperCTypesLint {
143    /// A fingerprint of the type, not the type itself. Uses a big 128-bit
144    /// fingerprint (not a smaller 64-bit one) so two different types can't
145    /// accidentally get treated as the same one.
146    known_safe: RefCell<FxHashSet<(Hash128, u8)>>,
147}
148
149impl<'tcx> ImproperCTypesLint {
150    fn cache_key(cx: &LateContext<'tcx>, ty: Ty<'tcx>, flags: RootUseFlags) -> (Hash128, u8) {
151        (cx.tcx.type_id_hash(ty), flags.bits())
152    }
153
154    fn check_ffi_type(
155        &self,
156        cx: &LateContext<'tcx>,
157        ty: Ty<'tcx>,
158        state: VisitorState,
159        span: Span,
160        mode: CItemKind,
161        check: impl FnOnce() -> FfiResult<'tcx>,
162    ) {
163        let key = Self::cache_key(cx, ty, state.root_use_flags);
164        if self.known_safe.borrow().contains(&key) {
165            return;
166        }
167
168        let ffi_res = check();
169
170        if #[allow(non_exhaustive_omitted_patterns)] match ffi_res {
    FfiResult::FfiSafe => true,
    _ => false,
}matches!(ffi_res, FfiResult::FfiSafe) {
171            self.known_safe.borrow_mut().insert(key);
172        }
173
174        self.process_ffi_result(cx, span, ffi_res, mode);
175    }
176}
177
178impl ::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]))
    }
}impl_lint_pass!(ImproperCTypesLint => [
179    IMPROPER_CTYPES,
180    IMPROPER_CTYPES_DEFINITIONS,
181    USES_POWER_ALIGNMENT
182]);
183
184/// A common pattern in this lint is to attempt normalize_erasing_regions,
185/// but keep the original type if it were to fail.
186/// This may or may not be supported in the logic behind the `Unnormalized` wrapper,
187/// (FIXME?)
188/// but it should be enough for non-wrapped types to be as normalised as this lint needs them to be.
189fn maybe_normalize_erasing_regions<'tcx>(
190    cx: &LateContext<'tcx>,
191    value: Unnormalized<'tcx, Ty<'tcx>>,
192) -> Ty<'tcx> {
193    // Use `TypingMode::Borrowck` so the new solver doesn't reveal opaque types since we're now
194    // past hir typeck. If we were to attempt to reveal more opaque types, dropping the
195    // `InferCtxt` would ICE (see #156352).
196    let typing_env = if let Some(body_id) = cx.enclosing_body {
197        let body_def_id = cx.tcx.hir_enclosing_body_owner(body_id.hir_id);
198        ty::TypingEnv::new(cx.param_env, ty::TypingMode::borrowck(cx.tcx, body_def_id))
199    } else {
200        cx.typing_env()
201    };
202    cx.tcx.try_normalize_erasing_regions(typing_env, value).unwrap_or(value.skip_norm_wip())
203}
204
205/// Check a variant of a non-exhaustive enum for improper ctypes
206///
207/// We treat `#[non_exhaustive] enum` as "ensure that code will compile if new variants are added".
208/// This includes linting, on a best-effort basis. There are valid additions that are unlikely.
209///
210/// Adding a data-carrying variant to an existing C-like enum that is passed to C is "unlikely",
211/// so we don't need the lint to account for it.
212/// e.g. going from enum Foo { A, B, C } to enum Foo { A, B, C, D(u32) }.
213pub(crate) fn check_non_exhaustive_variant(
214    non_exhaustive_variant_list: bool,
215    variant: &ty::VariantDef,
216) -> ControlFlow<DiagMessage, ()> {
217    // non_exhaustive suggests it is possible that someone might break ABI
218    // see: https://github.com/rust-lang/rust/issues/44109#issuecomment-537583344
219    // so warn on complex enums being used outside their crate
220    if non_exhaustive_variant_list {
221        // which is why we only warn about really_tagged_union reprs from https://rust.tf/rfc2195
222        // with an enum like `#[repr(u8)] enum Enum { A(DataA), B(DataB), }`
223        // but exempt enums with unit ctors like C's (e.g. from rust-bindgen)
224        if variant_has_complex_ctor(variant) {
225            return ControlFlow::Break(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("this enum is non-exhaustive"))msg!("this enum is non-exhaustive"));
226        }
227    }
228
229    if variant.field_list_has_applicable_non_exhaustive() {
230        return ControlFlow::Break(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("this enum has non-exhaustive variants"))msg!("this enum has non-exhaustive variants"));
231    }
232
233    ControlFlow::Continue(())
234}
235
236fn variant_has_complex_ctor(variant: &ty::VariantDef) -> bool {
237    // CtorKind::Const means a "unit" ctor
238    !#[allow(non_exhaustive_omitted_patterns)] match variant.ctor_kind() {
    Some(CtorKind::Const) => true,
    _ => false,
}matches!(variant.ctor_kind(), Some(CtorKind::Const))
239}
240
241/// Per-struct-field function that checks if a struct definition follows
242/// the Power alignment Rule (see the `check_struct_for_power_alignment` function).
243fn check_arg_for_power_alignment<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
244    let tcx = cx.tcx;
245    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);
246
247    // Structs (under repr(C)) follow the power alignment rule if:
248    //   - the first field of the struct is a floating-point type that
249    //     is greater than 4-bytes, or
250    //   - the first field of the struct is an aggregate whose
251    //     recursively first field is a floating-point type greater than
252    //     4 bytes.
253    if ty.is_floating_point() && ty.primitive_size(tcx).bytes() > 4 {
254        return true;
255    } else if let Adt(adt_def, _) = ty.kind()
256        && adt_def.is_struct()
257        && adt_def.repr().c()
258        && !adt_def.repr().packed()
259        && adt_def.repr().align.is_none()
260    {
261        let struct_variant = adt_def.variant(VariantIdx::ZERO);
262        // Within a nested struct, all fields are examined to correctly
263        // report if any fields after the nested struct within the
264        // original struct are misaligned.
265        for struct_field in &struct_variant.fields {
266            let field_ty = tcx.type_of(struct_field.did).instantiate_identity().skip_norm_wip();
267            if check_arg_for_power_alignment(cx, field_ty) {
268                return true;
269            }
270        }
271    }
272    return false;
273}
274
275/// Check a struct definition for respect of the Power alignment Rule (as in PowerPC),
276/// which should be respected in the "aix" target OS.
277/// To do so, we must follow one of the two following conditions:
278/// - The first field of the struct must be floating-point type that
279///    is greater than 4-bytes.
280///  - The first field of the struct must be an aggregate whose
281///    recursively first field is a floating-point type greater than
282///    4 bytes.
283fn check_struct_for_power_alignment<'tcx>(
284    cx: &LateContext<'tcx>,
285    item: &'tcx hir::Item<'tcx>,
286    adt_def: AdtDef<'tcx>,
287) {
288    let tcx = cx.tcx;
289
290    // Only consider structs (not enums or unions) on AIX.
291    if tcx.sess.target.os != Os::Aix || !adt_def.is_struct() {
292        return;
293    }
294
295    // The struct must be repr(C), but ignore it if it explicitly specifies its alignment with
296    // either `align(N)` or `packed(N)`.
297    if adt_def.repr().c() && !adt_def.repr().packed() && adt_def.repr().align.is_none() {
298        let struct_variant_data = item.expect_struct().2;
299        for field_def in struct_variant_data.fields().iter().skip(1) {
300            // Struct fields (after the first field) are checked for the
301            // power alignment rule, as fields after the first are likely
302            // to be the fields that are misaligned.
303            let ty = tcx.type_of(field_def.def_id).instantiate_identity().skip_norm_wip();
304            if check_arg_for_power_alignment(cx, ty) {
305                cx.emit_span_lint(USES_POWER_ALIGNMENT, field_def.span, UsesPowerAlignment);
306            }
307        }
308    }
309}
310
311/// Annotates whether we are in the context of an item *defined* in rust
312/// and exposed to an FFI boundary,
313/// or the context of an item from elsewhere, whose interface is re-*declared* in rust.
314#[derive(#[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
    for CItemKind {
}
#[automatically_derived]impl ::core::clone::Clone for CItemKind {
    #[inline]
    #[rustc_trivial_field_reads]
    fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]impl ::core::marker::Copy for CItemKind { }Copy)]
315enum CItemKind {
316    Declaration,
317    Definition,
318}
319
320/// Annotates whether we are in the context of a function's argument types or return type.
321#[derive(#[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
    for FnPos {
}
#[automatically_derived]impl ::core::clone::Clone for FnPos {
    #[inline]
    #[rustc_trivial_field_reads]
    fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]impl ::core::marker::Copy for FnPos { }Copy)]
322enum FnPos {
323    Arg,
324    Ret,
325}
326
327enum FfiResult<'tcx> {
328    FfiSafe,
329    FfiPhantom(Ty<'tcx>),
330    FfiUnsafe { ty: Ty<'tcx>, reason: DiagMessage, help: Option<DiagMessage> },
331}
332
333/// The result when a type has been checked but perhaps not completely. `None` indicates that
334/// FFI safety/unsafety has not yet been determined, `Some(res)` indicates that the safety/unsafety
335/// in the `FfiResult` is final.
336type PartialFfiResult<'tcx> = Option<FfiResult<'tcx>>;
337
338/// What type indirection points to a given type.
339#[derive(#[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
    for IndirectionKind {
}
#[automatically_derived]impl ::core::clone::Clone for IndirectionKind {
    #[inline]
    #[rustc_trivial_field_reads]
    fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]impl ::core::marker::Copy for IndirectionKind { }Copy)]
340enum IndirectionKind {
341    /// Box (valid non-null pointer, owns pointee).
342    Box,
343    /// Ref (valid non-null pointer, borrows pointee).
344    Ref,
345    /// Raw pointer (not necessarily non-null or valid. no info on ownership).
346    RawPtr,
347}
348
349#[doc = r" VisitorState flags that are linked with the root type's use."]
#[doc =
r" (These are the permanent part of the state, kept when visiting new Ty.)"]
struct RootUseFlags(<RootUseFlags as
    ::bitflags::__private::PublicFlags>::Internal);
#[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
    for RootUseFlags {
}
#[automatically_derived]impl ::core::clone::Clone for RootUseFlags {
    #[inline]
    #[rustc_trivial_field_reads]
    fn clone(&self) -> Self {
        let _:
                ::core::clone::AssertParamIsClone<<RootUseFlags as
                ::bitflags::__private::PublicFlags>::Internal>;
        *self
    }
}
#[automatically_derived]impl ::core::marker::Copy for RootUseFlags { }
#[automatically_derived]impl ::core::fmt::Debug for RootUseFlags {
    #[inline]
    #[rustc_trivial_field_reads]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field1_finish(f, "RootUseFlags",
            &&self.0)
    }
}
#[automatically_derived]impl ::core::marker::StructuralPartialEq for
    RootUseFlags {
}
#[automatically_derived]impl ::core::cmp::PartialEq for RootUseFlags {
    #[inline]
    fn eq(&self, other: &Self) -> bool { self.0 == other.0 }
}
#[automatically_derived]impl ::core::cmp::Eq for RootUseFlags {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _:
                ::core::cmp::AssertParamIsEq<<RootUseFlags as
                ::bitflags::__private::PublicFlags>::Internal>;
    }
}
impl RootUseFlags {
    #[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 RootUseFlags {
    const FLAGS: &'static [::bitflags::Flag<RootUseFlags>] =
        &[{

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

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

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

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

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("THEORETICAL",
                            RootUseFlags::THEORETICAL)
                    }];
    type Bits = u8;
    fn bits(&self) -> u8 { RootUseFlags::bits(self) }
    fn from_bits_retain(bits: u8) -> RootUseFlags {
        RootUseFlags::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]
            #[rustc_trivial_field_reads]
            fn clone(&self) -> Self {
                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: &Self) -> 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: &Self)
                -> ::core::option::Option<::core::cmp::Ordering> {
                ::core::option::Option::Some(::core::cmp::Ord::cmp(self,
                        other))
            }
        }
        #[automatically_derived]
        impl ::core::cmp::Ord for InternalBitFlags {
            #[inline]
            fn cmp(&self, other: &Self) -> ::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 RootUseFlags {
            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(&RootUseFlags(*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::<RootUseFlags>(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 =
                            <RootUseFlags as
                                            ::bitflags::Flags>::FLAGS[i].value().bits();
                        truncated = truncated | flag;
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            <RootUseFlags as
                                            ::bitflags::Flags>::FLAGS[i].value().bits();
                        truncated = truncated | flag;
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            <RootUseFlags as
                                            ::bitflags::Flags>::FLAGS[i].value().bits();
                        truncated = truncated | flag;
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            <RootUseFlags as
                                            ::bitflags::Flags>::FLAGS[i].value().bits();
                        truncated = truncated | flag;
                        i += 1;
                    }
                };
                {
                    {
                        let flag =
                            <RootUseFlags 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(RootUseFlags::STATIC.bits()));
                    }
                };
                ;
                {
                    if name == "FUNC" {
                        return ::bitflags::__private::core::option::Option::Some(Self(RootUseFlags::FUNC.bits()));
                    }
                };
                ;
                {
                    if name == "FN_RETURN" {
                        return ::bitflags::__private::core::option::Option::Some(Self(RootUseFlags::FN_RETURN.bits()));
                    }
                };
                ;
                {
                    if name == "DEFINED" {
                        return ::bitflags::__private::core::option::Option::Some(Self(RootUseFlags::DEFINED.bits()));
                    }
                };
                ;
                {
                    if name == "THEORETICAL" {
                        return ::bitflags::__private::core::option::Option::Some(Self(RootUseFlags::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<RootUseFlags> {
                ::bitflags::iter::Iter::__private_const_new(<RootUseFlags as
                        ::bitflags::Flags>::FLAGS,
                    RootUseFlags::from_bits_retain(self.bits()),
                    RootUseFlags::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<RootUseFlags> {
                ::bitflags::iter::IterNames::__private_const_new(<RootUseFlags
                        as ::bitflags::Flags>::FLAGS,
                    RootUseFlags::from_bits_retain(self.bits()),
                    RootUseFlags::from_bits_retain(self.bits()))
            }
        }
        impl ::bitflags::__private::core::iter::IntoIterator for
            InternalBitFlags {
            type Item = RootUseFlags;
            type IntoIter = ::bitflags::iter::Iter<RootUseFlags>;
            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 RootUseFlags {
            /// 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 RootUseFlags {
            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 RootUseFlags {
            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 RootUseFlags {
            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 RootUseFlags {
            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 RootUseFlags {
            type Output = Self;
            /// The bitwise or (`|`) of the bits in two flags values.
            #[inline]
            fn bitor(self, other: RootUseFlags) -> Self { self.union(other) }
        }
        impl ::bitflags::__private::core::ops::BitOrAssign for RootUseFlags {
            /// 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 RootUseFlags {
            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 RootUseFlags {
            /// 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 RootUseFlags {
            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 RootUseFlags {
            /// 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 RootUseFlags {
            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 RootUseFlags {
            /// 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 RootUseFlags {
            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<RootUseFlags> for
            RootUseFlags {
            /// 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<RootUseFlags> for
            RootUseFlags {
            /// 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 RootUseFlags {
            /// 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<RootUseFlags> {
                ::bitflags::iter::Iter::__private_const_new(<RootUseFlags as
                        ::bitflags::Flags>::FLAGS,
                    RootUseFlags::from_bits_retain(self.bits()),
                    RootUseFlags::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<RootUseFlags> {
                ::bitflags::iter::IterNames::__private_const_new(<RootUseFlags
                        as ::bitflags::Flags>::FLAGS,
                    RootUseFlags::from_bits_retain(self.bits()),
                    RootUseFlags::from_bits_retain(self.bits()))
            }
        }
        impl ::bitflags::__private::core::iter::IntoIterator for RootUseFlags
            {
            type Item = RootUseFlags;
            type IntoIter = ::bitflags::iter::Iter<RootUseFlags>;
            fn into_iter(self) -> Self::IntoIter { self.iter() }
        }
    };bitflags! {
350    /// VisitorState flags that are linked with the root type's use.
351    /// (These are the permanent part of the state, kept when visiting new Ty.)
352    #[derive(Clone, Copy, Debug, PartialEq, Eq)]
353    struct RootUseFlags: u8 {
354        /// For use in (externally-linked) static variables.
355        const STATIC = 0b000001;
356        /// For use in functions in general.
357        const FUNC = 0b000010;
358        /// For variables in function returns (implicitly: not for static variables).
359        const FN_RETURN = 0b000100;
360        /// For variables in functions/variables which are defined in rust.
361        const DEFINED = 0b001000;
362        /// For times where we are only defining the type of something
363        /// (struct/enum/union definitions, FnPtrs).
364        const THEORETICAL = 0b010000;
365    }
366}
367
368/// Description of the relationship between current Ty and
369/// the type (or lack thereof) immediately containing it
370#[derive(#[automatically_derived]impl ::core::marker::Copy for OuterTyKind { }Copy, #[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
    for OuterTyKind {
}
#[automatically_derived]impl ::core::clone::Clone for OuterTyKind {
    #[inline]
    #[rustc_trivial_field_reads]
    fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]impl ::core::fmt::Debug for OuterTyKind {
    #[inline]
    #[rustc_trivial_field_reads]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                OuterTyKind::None => "None",
                OuterTyKind::NoneThroughFnPtr => "NoneThroughFnPtr",
                OuterTyKind::Other => "Other",
            })
    }
}Debug, #[automatically_derived]impl ::core::marker::StructuralPartialEq for
    OuterTyKind {
}
#[automatically_derived]impl ::core::cmp::PartialEq for OuterTyKind {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        ::core::intrinsics::discriminant_value(self) ==
            ::core::intrinsics::discriminant_value(other)
    }
}PartialEq, #[automatically_derived]impl ::core::cmp::Eq for OuterTyKind { }Eq)]
371enum OuterTyKind {
372    None,
373    /// A variant that should not exist,
374    /// but is needed because we don't change the lint's behavior yet
375    NoneThroughFnPtr,
376    /// Placeholder for properties that will be used eventually
377    Other,
378}
379
380impl OuterTyKind {
381    /// Computes the relationship by providing the containing Ty itself
382    fn from_ty<'tcx>(ty: Ty<'tcx>) -> Self {
383        match ty.kind() {
384            ty::FnPtr(..) => Self::NoneThroughFnPtr,
385            ty::RawPtr(..)
386            | ty::Ref(..)
387            | ty::Adt(..)
388            | ty::Tuple(..)
389            | ty::Array(..)
390            | ty::Slice(_) => OuterTyKind::Other,
391            _ => ::rustc_span::macros::bug_impl(None,
    format_args!("Unexpected outer type {0:?}", ty), Location::caller())bug!("Unexpected outer type {ty:?}"),
392        }
393    }
394}
395
396#[derive(#[automatically_derived]impl ::core::marker::Copy for VisitorState { }Copy, #[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
    for VisitorState {
}
#[automatically_derived]impl ::core::clone::Clone for VisitorState {
    #[inline]
    #[rustc_trivial_field_reads]
    fn clone(&self) -> Self {
        let _: ::core::clone::AssertParamIsClone<RootUseFlags>;
        let _: ::core::clone::AssertParamIsClone<OuterTyKind>;
        let _: ::core::clone::AssertParamIsClone<usize>;
        *self
    }
}Clone, #[automatically_derived]impl ::core::fmt::Debug for VisitorState {
    #[inline]
    #[rustc_trivial_field_reads]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field3_finish(f,
            "VisitorState root_use_flags outer_ty_kind depth",
            &self.root_use_flags, &self.outer_ty_kind, &&self.depth)
    }
}Debug, #[automatically_derived]impl ::core::marker::StructuralPartialEq for
    VisitorState {
}
#[automatically_derived]impl ::core::cmp::PartialEq for VisitorState {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        self.root_use_flags == other.root_use_flags &&
                self.outer_ty_kind == other.outer_ty_kind &&
            self.depth == other.depth
    }
}PartialEq, #[automatically_derived]impl ::core::cmp::Eq for VisitorState {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<RootUseFlags>;
        let _: ::core::cmp::AssertParamIsEq<OuterTyKind>;
        let _: ::core::cmp::AssertParamIsEq<usize>;
    }
}Eq)]
397struct VisitorState {
398    /// Flags describing both the overall context in which the current Ty is,
399    /// linked to how the Visitor's original Ty was used.
400    root_use_flags: RootUseFlags,
401    /// Flags describing both the immediate context in which the current Ty is,
402    /// linked to how it relates to its parent Ty (or lack thereof).
403    outer_ty_kind: OuterTyKind,
404    /// Type recursion depth, to prevent infinite recursion
405    depth: usize,
406}
407
408impl RootUseFlags {
409    // The values that can be set.
410    const STATIC_TY: Self = Self::STATIC;
411    const ARGUMENT_TY_IN_DEFINITION: Self =
412        Self::from_bits(Self::FUNC.bits() | Self::DEFINED.bits()).unwrap();
413    const RETURN_TY_IN_DEFINITION: Self =
414        Self::from_bits(Self::FUNC.bits() | Self::FN_RETURN.bits() | Self::DEFINED.bits()).unwrap();
415    const ARGUMENT_TY_IN_DECLARATION: Self = Self::FUNC;
416    const RETURN_TY_IN_DECLARATION: Self =
417        Self::from_bits(Self::FUNC.bits() | Self::FN_RETURN.bits()).unwrap();
418    const ARGUMENT_TY_IN_FNPTR: Self =
419        Self::from_bits(Self::FUNC.bits() | Self::THEORETICAL.bits()).unwrap();
420    const RETURN_TY_IN_FNPTR: Self =
421        Self::from_bits(Self::FUNC.bits() | Self::THEORETICAL.bits() | Self::FN_RETURN.bits())
422            .unwrap();
423}
424
425impl VisitorState {
426    /// From an existing state, compute the state of any subtype of the current type.
427    /// (General case. For the case where the current type is a function pointer, see `next_in_fnptr`.)
428    fn next(&self, current_ty: Ty<'_>) -> Self {
429        if !!#[allow(non_exhaustive_omitted_patterns)] match current_ty.kind() {
                ty::FnPtr(..) => true,
                _ => false,
            } {
    ::core::panicking::panic("assertion failed: !matches!(current_ty.kind(), ty::FnPtr(..))")
};assert!(!matches!(current_ty.kind(), ty::FnPtr(..)));
430        VisitorState {
431            root_use_flags: self.root_use_flags,
432            outer_ty_kind: OuterTyKind::from_ty(current_ty),
433            depth: self.depth + 1,
434        }
435    }
436
437    /// From an existing state, compute the state of any subtype of the current type.
438    /// (Case where the current type is a function pointer,
439    /// meaning we need to specify if the subtype is an argument or the return.)
440    fn next_in_fnptr(&self, current_ty: Ty<'_>, fn_pos: FnPos) -> Self {
441        if !#[allow(non_exhaustive_omitted_patterns)] match current_ty.kind() {
            ty::FnPtr(..) => true,
            _ => false,
        } {
    ::core::panicking::panic("assertion failed: matches!(current_ty.kind(), ty::FnPtr(..))")
};assert!(matches!(current_ty.kind(), ty::FnPtr(..)));
442        VisitorState {
443            root_use_flags: match fn_pos {
444                FnPos::Ret => RootUseFlags::RETURN_TY_IN_FNPTR,
445                FnPos::Arg => RootUseFlags::ARGUMENT_TY_IN_FNPTR,
446            },
447            outer_ty_kind: OuterTyKind::from_ty(current_ty),
448            depth: self.depth + 1,
449        }
450    }
451
452    /// Get the proper visitor state for a given function's arguments or return type.
453    fn fn_entry_point(fn_mode: CItemKind, fn_pos: FnPos) -> Self {
454        let p_flags = match (fn_mode, fn_pos) {
455            (CItemKind::Definition, FnPos::Ret) => RootUseFlags::RETURN_TY_IN_DEFINITION,
456            (CItemKind::Declaration, FnPos::Ret) => RootUseFlags::RETURN_TY_IN_DECLARATION,
457            (CItemKind::Definition, FnPos::Arg) => RootUseFlags::ARGUMENT_TY_IN_DEFINITION,
458            (CItemKind::Declaration, FnPos::Arg) => RootUseFlags::ARGUMENT_TY_IN_DECLARATION,
459        };
460        VisitorState { root_use_flags: p_flags, outer_ty_kind: OuterTyKind::None, depth: 0 }
461    }
462
463    /// Get the proper visitor state for a static variable's type
464    fn static_entry_point() -> Self {
465        VisitorState {
466            root_use_flags: RootUseFlags::STATIC_TY,
467            outer_ty_kind: OuterTyKind::None,
468            depth: 0,
469        }
470    }
471
472    /// Whether the type is used in a function.
473    fn is_in_function(&self) -> bool {
474        let ret = self.root_use_flags.contains(RootUseFlags::FUNC);
475        if ret {
476            if true {
    if !!self.root_use_flags.contains(RootUseFlags::STATIC) {
        ::core::panicking::panic("assertion failed: !self.root_use_flags.contains(RootUseFlags::STATIC)")
    };
};debug_assert!(!self.root_use_flags.contains(RootUseFlags::STATIC));
477        }
478        ret
479    }
480
481    /// Whether the type is used (directly or not) in a function, in return position.
482    fn is_in_function_return(&self) -> bool {
483        let ret = self.root_use_flags.contains(RootUseFlags::FN_RETURN);
484        if ret {
485            if true {
    if !self.is_in_function() {
        ::core::panicking::panic("assertion failed: self.is_in_function()")
    };
};debug_assert!(self.is_in_function());
486        }
487        ret
488    }
489
490    /// Whether the type is used (directly or not) in a defined function.
491    /// In other words, whether or not we allow non-FFI-safe types behind a C pointer,
492    /// to be treated as an opaque type on the other side of the FFI boundary.
493    fn is_in_defined_function(&self) -> bool {
494        self.root_use_flags.contains(RootUseFlags::DEFINED) && self.is_in_function()
495    }
496
497    /// Whether the type is used (directly or not) in a function pointer type.
498    /// Here, we also allow non-FFI-safe types behind a C pointer,
499    /// to be treated as an opaque type on the other side of the FFI boundary.
500    fn is_in_fnptr(&self) -> bool {
501        self.root_use_flags.contains(RootUseFlags::THEORETICAL) && self.is_in_function()
502    }
503
504    /// Whether we can expect type parameters and co in a given type.
505    fn can_expect_ty_params(&self) -> bool {
506        // rust-defined functions, as well as FnPtrs
507        self.root_use_flags.contains(RootUseFlags::THEORETICAL) || self.is_in_defined_function()
508    }
509}
510
511/// Visitor used to recursively traverse MIR types and evaluate FFI-safety.
512/// It uses ``check_*`` methods as entrypoints to be called elsewhere,
513/// and ``visit_*`` methods to recurse.
514struct ImproperCTypesVisitor<'a, 'tcx> {
515    cx: &'a LateContext<'tcx>,
516    /// To prevent problems with recursive types,
517    /// add a types-in-check cache.
518    cache: FxHashSet<Ty<'tcx>>,
519    /// The original type being checked, before we recursed
520    /// to any other types it contains.
521    base_ty: Ty<'tcx>,
522    base_fn_mode: CItemKind,
523}
524
525impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
526    fn new(
527        cx: &'a LateContext<'tcx>,
528        base_ty: Unnormalized<'tcx, Ty<'tcx>>,
529        base_fn_mode: CItemKind,
530    ) -> Self {
531        // Skip normalization for opaques: even in `TypingMode::Borrowck` the body's own
532        // defining opaques still get revealed, leaving entries in `OpaqueTypeStorage` that
533        // ICE on `InferCtxt` drop (issue #156352).
534        let base_ty = if base_ty.skip_norm_wip().has_opaque_types() {
535            base_ty.skip_norm_wip()
536        } else {
537            maybe_normalize_erasing_regions(cx, base_ty)
538        };
539        ImproperCTypesVisitor { cx, base_ty, base_fn_mode, cache: FxHashSet::default() }
540    }
541
542    /// Checks if the given indirection (box,ref,pointer) is "ffi-safe".
543    fn visit_indirection(
544        &mut self,
545        state: VisitorState,
546        ty: Ty<'tcx>,
547        inner_ty: Ty<'tcx>,
548        indirection_kind: IndirectionKind,
549    ) -> FfiResult<'tcx> {
550        use FfiResult::*;
551        let tcx = self.cx.tcx;
552
553        match indirection_kind {
554            IndirectionKind::Box => {
555                // FIXME(ctypes): this logic is broken, but it still fits the current tests:
556                // - for some reason `Box<_>`es in `extern "ABI" {}` blocks
557                //   (including within FnPtr:s)
558                //   are not treated as pointers but as FFI-unsafe structs
559                // - otherwise, treat the box itself correctly, and follow pointee safety logic
560                //   as described in the other `indirection_type` match branch.
561                if state.is_in_defined_function()
562                    || (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))
563                {
564                    if inner_ty.is_sized(tcx, self.cx.typing_env()) {
565                        return FfiSafe;
566                    } else {
567                        return FfiUnsafe {
568                            ty,
569                            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"),
570                            help: None,
571                        };
572                    }
573                } else {
574                    // (mid-retcon-commit-chain comment:)
575                    // this is the original fallback behavior, which is wrong
576                    if let ty::Adt(def, args) = ty.kind() {
577                        self.visit_struct_or_union(state, ty, *def, *args)
578                    } else if truecfg!(debug_assertions) {
579                        ::rustc_span::macros::bug_impl(None,
    format_args!("ImproperCTypes: this retcon commit was badly written"),
    Location::caller())bug!("ImproperCTypes: this retcon commit was badly written")
580                    } else {
581                        FfiSafe
582                    }
583                }
584            }
585            IndirectionKind::Ref | IndirectionKind::RawPtr => {
586                // Weird behaviour for pointee safety. the big question here is
587                // "if you have a FFI-unsafe pointee behind a FFI-safe pointer type, is it ok?"
588                // The answer until now is:
589                // "It's OK for rust-defined functions and callbacks, we'll assume those are
590                // meant to be opaque types on the other side of the FFI boundary".
591                //
592                // Reasoning:
593                // For extern function declarations, the actual definition of the function is
594                // written somewhere else, meaning the declaration is free to express this
595                // opaqueness with an extern type (opaque caller-side) or a std::ffi::c_void
596                // (opaque callee-side). For extern function definitions, however, in the case
597                // where the type is opaque caller-side, it is not opaque callee-side,
598                // and having the full type information is necessary to compile the function.
599                //
600                // It might be better to rething this, or even ignore pointee safety for a first
601                // batch of behaviour changes. See the discussion that ends with
602                // https://github.com/rust-lang/rust/pull/134697#issuecomment-2692610258
603                if (state.is_in_defined_function() || state.is_in_fnptr())
604                    && inner_ty.is_sized(self.cx.tcx, self.cx.typing_env())
605                {
606                    FfiSafe
607                } else {
608                    self.visit_type(state.next(ty), inner_ty)
609                }
610            }
611        }
612    }
613
614    /// Checks if the given `VariantDef`'s field types are "ffi-safe".
615    fn visit_variant_fields(
616        &mut self,
617        state: VisitorState,
618        ty: Ty<'tcx>,
619        def: AdtDef<'tcx>,
620        variant: &ty::VariantDef,
621        args: GenericArgs<'tcx>,
622    ) -> FfiResult<'tcx> {
623        use FfiResult::*;
624
625        let transparent_with_all_zst_fields = if def.repr().transparent() {
626            if let Some(field) = super::transparent_newtype_field(self.cx.tcx, variant) {
627                // Transparent newtypes have at most one non-ZST field which needs to be checked..
628                let field_ty =
629                    maybe_normalize_erasing_regions(self.cx, field.ty(self.cx.tcx, args));
630                match self.visit_type(state.next(ty), field_ty) {
631                    FfiUnsafe { ty, .. } if ty.is_unit() => (),
632                    r => return r,
633                }
634
635                false
636            } else {
637                // ..or have only ZST fields, which is FFI-unsafe (unless those fields are all
638                // `PhantomData`).
639                true
640            }
641        } else {
642            false
643        };
644
645        // We can't completely trust `repr(C)` markings, so make sure the fields are actually safe.
646        let mut all_phantom = !variant.fields.is_empty();
647        for field in &variant.fields {
648            let field_ty = maybe_normalize_erasing_regions(self.cx, field.ty(self.cx.tcx, args));
649            all_phantom &= match self.visit_type(state.next(ty), field_ty) {
650                FfiSafe => false,
651                // `()` fields are FFI-safe!
652                FfiUnsafe { ty, .. } if ty.is_unit() => false,
653                FfiPhantom(..) => true,
654                r @ FfiUnsafe { .. } => return r,
655            }
656        }
657
658        if all_phantom {
659            FfiPhantom(ty)
660        } else if transparent_with_all_zst_fields {
661            FfiUnsafe {
662                ty,
663                reason: rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("this struct contains only zero-sized fields"))msg!("this struct contains only zero-sized fields"),
664                help: None,
665            }
666        } else {
667            FfiSafe
668        }
669    }
670
671    fn visit_struct_or_union(
672        &mut self,
673        state: VisitorState,
674        ty: Ty<'tcx>,
675        def: AdtDef<'tcx>,
676        args: GenericArgs<'tcx>,
677    ) -> FfiResult<'tcx> {
678        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));
679        use FfiResult::*;
680
681        if !def.repr().c() && !def.repr().transparent() && !def.repr().simd() {
682            return FfiUnsafe {
683                ty,
684                reason: if def.is_struct() {
685                    rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("this struct has unspecified layout"))msg!("this struct has unspecified layout")
686                } else {
687                    rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("this union has unspecified layout"))msg!("this union has unspecified layout")
688                },
689                help: if def.is_struct() {
690                    Some(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct"))msg!(
691                        "consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct"
692                    ))
693                } else {
694                    // FIXME(#60405): confirm that this makes sense for unions once #60405 / RFC2645 stabilises
695                    Some(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this union"))msg!(
696                        "consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this union"
697                    ))
698                },
699            };
700        }
701
702        if def.non_enum_variant().field_list_has_applicable_non_exhaustive() {
703            return FfiUnsafe {
704                ty,
705                reason: if def.is_struct() {
706                    rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("this struct is non-exhaustive"))msg!("this struct is non-exhaustive")
707                } else {
708                    rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("this union is non-exhaustive"))msg!("this union is non-exhaustive")
709                },
710                help: None,
711            };
712        }
713
714        if def.non_enum_variant().fields.is_empty() {
715            FfiUnsafe {
716                ty,
717                reason: if def.is_struct() {
718                    rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("this struct has no fields"))msg!("this struct has no fields")
719                } else {
720                    rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("this union has no fields"))msg!("this union has no fields")
721                },
722                help: if def.is_struct() {
723                    Some(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("consider adding a member to this struct"))msg!("consider adding a member to this struct"))
724                } else {
725                    Some(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("consider adding a member to this union"))msg!("consider adding a member to this union"))
726                },
727            }
728        } else {
729            self.visit_variant_fields(state, ty, def, def.non_enum_variant(), args)
730        }
731    }
732
733    fn visit_enum(
734        &mut self,
735        state: VisitorState,
736        ty: Ty<'tcx>,
737        def: AdtDef<'tcx>,
738        args: GenericArgs<'tcx>,
739    ) -> FfiResult<'tcx> {
740        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));
741        use FfiResult::*;
742
743        if def.variants().is_empty() {
744            // Empty enums are okay... although sort of useless.
745            return FfiSafe;
746        }
747        // Check for a repr() attribute to specify the size of the
748        // discriminant.
749        if !def.repr().c() && !def.repr().transparent() && def.repr().int.is_none() {
750            // Special-case types like `Option<extern fn()>` and `Result<extern fn(), ()>`
751            if let Some(inner_ty) = repr_nullable_ptr(self.cx.tcx, self.cx.typing_env(), ty) {
752                return self.visit_type(state.next(ty), inner_ty);
753            }
754
755            return FfiUnsafe {
756                ty,
757                reason: rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("enum has no representation hint"))msg!("enum has no representation hint"),
758                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!(
759                    "consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum"
760                )),
761            };
762        }
763
764        let non_exhaustive = def.variant_list_has_applicable_non_exhaustive();
765        // Check the contained variants.
766        let ret = def.variants().iter().try_for_each(|variant| {
767            check_non_exhaustive_variant(non_exhaustive, variant)
768                .map_break(|reason| FfiUnsafe { ty, reason, help: None })?;
769
770            match self.visit_variant_fields(state, ty, def, variant, args) {
771                FfiSafe => ControlFlow::Continue(()),
772                r => ControlFlow::Break(r),
773            }
774        });
775        if let ControlFlow::Break(result) = ret {
776            return result;
777        }
778
779        FfiSafe
780    }
781
782    /// Checks if the given type is "ffi-safe" (has a stable, well-defined
783    /// representation which can be exported to C code).
784    fn visit_type(&mut self, state: VisitorState, ty: Ty<'tcx>) -> FfiResult<'tcx> {
785        use FfiResult::*;
786
787        let tcx = self.cx.tcx;
788
789        // Protect against infinite recursion, for example
790        // `struct S(*mut S);`.
791        if !(self.cache.insert(ty) && self.cx.tcx.recursion_limit().value_within_limit(state.depth))
792        {
793            return FfiSafe;
794        }
795
796        match *ty.kind() {
797            ty::Adt(def, args) => {
798                if let Some(inner_ty) = ty.boxed_ty() {
799                    return self.visit_indirection(state, ty, inner_ty, IndirectionKind::Box);
800                }
801                if def.is_phantom_data() {
802                    return FfiPhantom(ty);
803                }
804                match def.adt_kind() {
805                    AdtKind::Struct | AdtKind::Union => {
806                        if tcx.is_lang_item(def.did(), LangItem::PpcF128)
807                            || tcx.is_lang_item(def.did(), LangItem::X87F80)
808                        {
809                            return FfiResult::FfiSafe;
810                        }
811                        if let Some(sym::cstring_type | sym::cstr_type) =
812                            tcx.get_diagnostic_name(def.did())
813                            && !self.base_ty.is_mutable_ptr()
814                        {
815                            return FfiUnsafe {
816                                ty,
817                                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"),
818                                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!(
819                                    "consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`"
820                                )),
821                            };
822                        }
823                        self.visit_struct_or_union(state, ty, def, args)
824                    }
825                    AdtKind::Enum => self.visit_enum(state, ty, def, args),
826                }
827            }
828
829            // Pattern types are just extra invariants on the type that you need to uphold,
830            // but only the base type is relevant for being representable in FFI.
831            // (note: this lint was written when pattern types could only be integers constrained to ranges)
832            // (also note: the lack of ".next(ty)" on the state is on purpose)
833            ty::Pat(pat_ty, _) => self.visit_type(state, pat_ty),
834
835            // types which likely have a stable representation, if the target architecture defines those
836            // note: before rust 1.77, 128-bit ints were not FFI-safe on x86_64
837            ty::Int(..) | ty::Uint(..) | ty::Float(..) => FfiResult::FfiSafe,
838
839            ty::Bool => FfiResult::FfiSafe,
840
841            ty::Char => FfiResult::FfiUnsafe {
842                ty,
843                reason: rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("the `char` type has no C equivalent"))msg!("the `char` type has no C equivalent"),
844                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")),
845            },
846
847            ty::Slice(_) => FfiUnsafe {
848                ty,
849                reason: rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("slices have no C equivalent"))msg!("slices have no C equivalent"),
850                help: Some(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("consider using a raw pointer instead"))msg!("consider using a raw pointer instead")),
851            },
852
853            ty::Dynamic(..) => {
854                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 }
855            }
856
857            ty::Str => FfiUnsafe {
858                ty,
859                reason: rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("string slices have no C equivalent"))msg!("string slices have no C equivalent"),
860                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")),
861            },
862
863            ty::Tuple(tuple) => {
864                if tuple.is_empty()
865                    && state.is_in_function_return()
866                    && #[allow(non_exhaustive_omitted_patterns)] match state.outer_ty_kind {
    OuterTyKind::None | OuterTyKind::NoneThroughFnPtr => true,
    _ => false,
}matches!(
867                        state.outer_ty_kind,
868                        OuterTyKind::None | OuterTyKind::NoneThroughFnPtr
869                    )
870                {
871                    // C functions can return void
872                    FfiSafe
873                } else {
874                    FfiUnsafe {
875                        ty,
876                        reason: rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("tuples have unspecified layout"))msg!("tuples have unspecified layout"),
877                        help: Some(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("consider using a struct instead"))msg!("consider using a struct instead")),
878                    }
879                }
880            }
881
882            ty::RawPtr(ty, _)
883                if match ty.kind() {
884                    ty::Tuple(tuple) => tuple.is_empty(),
885                    _ => false,
886                } =>
887            {
888                FfiSafe
889            }
890
891            ty::RawPtr(inner_ty, _) => {
892                return self.visit_indirection(state, ty, inner_ty, IndirectionKind::RawPtr);
893            }
894            ty::Ref(_, inner_ty, _) => {
895                return self.visit_indirection(state, ty, inner_ty, IndirectionKind::Ref);
896            }
897
898            ty::Array(inner_ty, _) => {
899                if state.is_in_function()
900                    // FIXME(ctypes): VVV-this-VVV shouldn't make a difference between ::None and ::NoneThroughFnPtr
901                    && #[allow(non_exhaustive_omitted_patterns)] match state.outer_ty_kind {
    OuterTyKind::None => true,
    _ => false,
}matches!(state.outer_ty_kind, OuterTyKind::None)
902                {
903                    // C doesn't really support passing arrays by value - the only way to pass an array by value
904                    // is through a struct.
905                    FfiResult::FfiUnsafe {
906                        ty,
907                        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"),
908                        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")),
909                    }
910                } else {
911                    // let's allow phantoms to go through,
912                    // since an array of 1-ZSTs is also a 1-ZST
913                    self.visit_type(state.next(ty), inner_ty)
914                }
915            }
916
917            ty::FnPtr(sig_tys, hdr) => {
918                let sig = sig_tys.with(hdr);
919                if sig.abi().is_rustic_abi() {
920                    return FfiUnsafe {
921                        ty,
922                        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"),
923                        help: Some(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("consider using an `extern fn(...) -> ...` function pointer instead"))msg!(
924                            "consider using an `extern fn(...) -> ...` function pointer instead"
925                        )),
926                    };
927                }
928
929                let sig = tcx.instantiate_bound_regions_with_erased(sig);
930                for arg in sig.inputs() {
931                    match self.visit_type(state.next_in_fnptr(ty, FnPos::Arg), *arg) {
932                        FfiSafe => {}
933                        r => return r,
934                    }
935                }
936
937                let ret_ty = sig.output();
938                self.visit_type(state.next_in_fnptr(ty, FnPos::Ret), ret_ty)
939            }
940
941            ty::Foreign(..) => FfiSafe,
942
943            ty::Never => FfiSafe,
944
945            // While opaque types are checked for earlier, if a projection in a struct field
946            // normalizes to an opaque type, then it will reach this branch.
947            ty::Alias(_, ty::AliasTy { kind: ty::Opaque { .. }, .. }) => {
948                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 }
949            }
950
951            // `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe,
952            //  so they are currently ignored for the purposes of this lint.
953            ty::Param(..)
954            | ty::Alias(_, ty::AliasTy { kind: ty::Projection { .. } | ty::Inherent { .. }, .. })
955                if state.can_expect_ty_params() =>
956            {
957                FfiSafe
958            }
959
960            ty::UnsafeBinder(_) => FfiUnsafe {
961                ty,
962                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"),
963                help: None,
964            },
965
966            // Safety net for when normalization reveals a body's own defining opaque
967            // (e.g. `async extern fn`'s `impl Future` → `Coroutine`); the nicer
968            // "opaque types have no C equivalent" message comes from `visit_for_opaque_ty`
969            // in `check_type` before normalization (issue #156352).
970            ty::Closure(..)
971            | ty::CoroutineClosure(..)
972            | ty::Coroutine(..)
973            | ty::CoroutineWitness(..) => FfiUnsafe {
974                ty,
975                reason: rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("closures and coroutines are not FFI-safe"))msg!("closures and coroutines are not FFI-safe"),
976                help: None,
977            },
978
979            ty::Param(..)
980            | ty::Alias(
981                _,
982                ty::AliasTy {
983                    kind: ty::Projection { .. } | ty::Inherent { .. } | ty::Free { .. },
984                    ..
985                },
986            )
987            | ty::Infer(..)
988            | ty::Bound(..)
989            | ty::Error(_)
990            | ty::Placeholder(..)
991            | ty::FnDef(..) => ::rustc_span::macros::bug_impl(None,
    format_args!("unexpected type in foreign function: {0:?}", ty),
    Location::caller())bug!("unexpected type in foreign function: {:?}", ty),
992        }
993    }
994
995    fn visit_for_opaque_ty(&mut self, ty: Ty<'tcx>) -> PartialFfiResult<'tcx> {
996        struct ProhibitOpaqueTypes;
997        impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for ProhibitOpaqueTypes {
998            type Result = ControlFlow<Ty<'tcx>>;
999
1000            fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
1001                if !ty.has_opaque_types() {
1002                    return ControlFlow::Continue(());
1003                }
1004
1005                if let ty::Alias(_, ty::AliasTy { kind: ty::Opaque { .. }, .. }) = ty.kind() {
1006                    ControlFlow::Break(ty)
1007                } else {
1008                    ty.super_visit_with(self)
1009                }
1010            }
1011        }
1012
1013        ty.visit_with(&mut ProhibitOpaqueTypes).break_value().map(|ty| FfiResult::FfiUnsafe {
1014            ty,
1015            reason: rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("opaque types have no C equivalent"))msg!("opaque types have no C equivalent"),
1016            help: None,
1017        })
1018    }
1019
1020    fn check_type(
1021        &mut self,
1022        state: VisitorState,
1023        ty: Unnormalized<'tcx, Ty<'tcx>>,
1024    ) -> FfiResult<'tcx> {
1025        // Catch opaques before normalization so the new solver doesn't reveal them
1026        // (e.g. `async extern fn` return → `Coroutine`) and we get the nicer
1027        // "opaque types have no C equivalent" message.
1028        if let Some(res) = self.visit_for_opaque_ty(ty.skip_norm_wip()) {
1029            return res;
1030        }
1031        let ty = maybe_normalize_erasing_regions(self.cx, ty);
1032        if let Some(res) = self.visit_for_opaque_ty(ty) {
1033            return res;
1034        }
1035
1036        self.visit_type(state, ty)
1037    }
1038}
1039
1040impl<'tcx> ImproperCTypesLint {
1041    /// Find any fn-ptr types with external ABIs in `ty`, and FFI-checks them.
1042    /// For example, `Option<extern "C" fn()>` FFI-checks `extern "C" fn()`.
1043    fn check_type_for_external_abi_fnptr(
1044        &mut self,
1045        cx: &LateContext<'tcx>,
1046        state: VisitorState,
1047        hir_ty: &hir::Ty<'tcx>,
1048        ty: Ty<'tcx>,
1049        fn_mode: CItemKind,
1050    ) {
1051        struct FnPtrFinder<'tcx> {
1052            current_depth: usize,
1053            depths: Vec<usize>,
1054            spans: Vec<Span>,
1055            tys: Vec<Ty<'tcx>>,
1056        }
1057
1058        impl<'tcx> hir::intravisit::Visitor<'_> for FnPtrFinder<'tcx> {
1059            fn visit_ty(&mut self, ty: &'_ hir::Ty<'_, AmbigArg>) {
1060                {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/3ef0c22cdb86ac42dc6b8f0f1ec36857daa6f2a1/compiler/rustc_lint/src/types/improper_ctypes.rs:1060",
                        "rustc_lint::types::improper_ctypes",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/3ef0c22cdb86ac42dc6b8f0f1ec36857daa6f2a1/compiler/rustc_lint/src/types/improper_ctypes.rs"),
                        ::tracing_core::__macro_support::Option::Some(1060u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_lint::types::improper_ctypes"),
                        ::tracing_core::field::FieldSet::new(&[{
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("ty")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("ty");
                                            NAME.as_str()
                                        }], ::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};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&ty)
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!(?ty);
1061                self.current_depth += 1;
1062                if let hir::TyKind::FnPtr(hir::FnPtrTy { abi, .. }) = ty.kind
1063                    && !abi.is_rustic_abi()
1064                {
1065                    self.depths.push(self.current_depth);
1066                    self.spans.push(ty.span);
1067                }
1068
1069                hir::intravisit::walk_ty(self, ty);
1070                self.current_depth -= 1;
1071            }
1072        }
1073
1074        impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for FnPtrFinder<'tcx> {
1075            type Result = ();
1076
1077            fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
1078                if let ty::FnPtr(_, hdr) = ty.kind()
1079                    && !hdr.abi().is_rustic_abi()
1080                {
1081                    self.tys.push(ty);
1082                }
1083
1084                ty.super_visit_with(self)
1085            }
1086        }
1087
1088        let mut visitor = FnPtrFinder {
1089            spans: Vec::new(),
1090            tys: Vec::new(),
1091            depths: Vec::new(),
1092            current_depth: 0,
1093        };
1094        ty.visit_with(&mut visitor);
1095        visitor.visit_ty_unambig(hir_ty);
1096
1097        let all_types = iter::zip(
1098            visitor.depths.drain(..),
1099            iter::zip(visitor.tys.drain(..), visitor.spans.drain(..)),
1100        );
1101        for (depth, (fn_ptr_ty, span)) in all_types {
1102            let fn_ptr_ty = Unnormalized::new_wip(fn_ptr_ty);
1103            let mut visitor = ImproperCTypesVisitor::new(cx, fn_ptr_ty, fn_mode);
1104            let bridge_state = VisitorState { depth, ..state };
1105            // FIXME(ctypes): make a check_for_fnptr
1106            let ffi_res = visitor.check_type(bridge_state, fn_ptr_ty);
1107
1108            self.process_ffi_result(cx, span, ffi_res, fn_mode);
1109        }
1110    }
1111
1112    /// Regardless of a function's need to be "ffi-safe", look for fn-ptr argument/return types
1113    /// that need to be checked for ffi-safety.
1114    fn check_fn_for_external_abi_fnptr(
1115        &mut self,
1116        cx: &LateContext<'tcx>,
1117        fn_mode: CItemKind,
1118        def_id: LocalDefId,
1119        decl: &'tcx hir::FnDecl<'_>,
1120    ) {
1121        let sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_norm_wip();
1122        let sig = cx.tcx.instantiate_bound_regions_with_erased(sig);
1123
1124        for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) {
1125            let state = VisitorState::fn_entry_point(fn_mode, FnPos::Arg);
1126            self.check_type_for_external_abi_fnptr(cx, state, input_hir, *input_ty, fn_mode);
1127        }
1128
1129        if let hir::FnRetTy::Return(ret_hir) = decl.output {
1130            let state = VisitorState::fn_entry_point(fn_mode, FnPos::Ret);
1131            self.check_type_for_external_abi_fnptr(cx, state, ret_hir, sig.output(), fn_mode);
1132        }
1133    }
1134
1135    /// For a local definition of a #[repr(C)] struct/enum/union, check that it is indeed FFI-safe.
1136    fn check_reprc_adt(
1137        &mut self,
1138        cx: &LateContext<'tcx>,
1139        item: &'tcx hir::Item<'tcx>,
1140        adt_def: AdtDef<'tcx>,
1141    ) {
1142        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!(
1143            adt_def.repr().c() && !adt_def.repr().packed() && adt_def.repr().align.is_none()
1144        );
1145
1146        // FIXME(ctypes): this following call is awkward.
1147        // is there a way to perform its logic in MIR space rather than HIR space?
1148        // (so that its logic can be absorbed into visitor.visit_struct_or_union)
1149        check_struct_for_power_alignment(cx, item, adt_def);
1150    }
1151
1152    fn check_foreign_static(&mut self, cx: &LateContext<'tcx>, id: hir::OwnerId, span: Span) {
1153        let ty = cx.tcx.type_of(id).instantiate_identity();
1154        let state = VisitorState::static_entry_point();
1155        self.check_ffi_type(cx, ty.skip_norm_wip(), state, span, CItemKind::Declaration, || {
1156            let mut visitor = ImproperCTypesVisitor::new(cx, ty, CItemKind::Declaration);
1157            visitor.check_type(state, ty)
1158        });
1159    }
1160
1161    /// Check if a function's argument types and result type are "ffi-safe".
1162    fn check_foreign_fn(
1163        &mut self,
1164        cx: &LateContext<'tcx>,
1165        fn_mode: CItemKind,
1166        def_id: LocalDefId,
1167        decl: &'tcx hir::FnDecl<'_>,
1168    ) {
1169        let sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_norm_wip();
1170        let sig = cx.tcx.instantiate_bound_regions_with_erased(sig);
1171
1172        for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) {
1173            let state = VisitorState::fn_entry_point(fn_mode, FnPos::Arg);
1174            self.check_ffi_type(cx, *input_ty, state, input_hir.span, fn_mode, || {
1175                let input_ty = Unnormalized::new_wip(*input_ty);
1176                let mut visitor = ImproperCTypesVisitor::new(cx, input_ty, fn_mode);
1177                visitor.check_type(state, input_ty)
1178            });
1179        }
1180
1181        if let hir::FnRetTy::Return(ret_hir) = decl.output {
1182            let state = VisitorState::fn_entry_point(fn_mode, FnPos::Ret);
1183            self.check_ffi_type(cx, sig.output(), state, ret_hir.span, fn_mode, || {
1184                let output_ty = Unnormalized::new_wip(sig.output());
1185                let mut visitor = ImproperCTypesVisitor::new(cx, output_ty, fn_mode);
1186                visitor.check_type(state, output_ty)
1187            });
1188        }
1189    }
1190
1191    fn process_ffi_result(
1192        &self,
1193        cx: &LateContext<'tcx>,
1194        sp: Span,
1195        res: FfiResult<'tcx>,
1196        fn_mode: CItemKind,
1197    ) {
1198        match res {
1199            FfiResult::FfiSafe => {}
1200            FfiResult::FfiPhantom(ty) => {
1201                self.emit_ffi_unsafe_type_lint(
1202                    cx,
1203                    ty,
1204                    sp,
1205                    rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("composed only of `PhantomData`"))msg!("composed only of `PhantomData`"),
1206                    None,
1207                    fn_mode,
1208                );
1209            }
1210            FfiResult::FfiUnsafe { ty, reason, help } => {
1211                self.emit_ffi_unsafe_type_lint(cx, ty, sp, reason, help, fn_mode);
1212            }
1213        }
1214    }
1215
1216    fn emit_ffi_unsafe_type_lint(
1217        &self,
1218        cx: &LateContext<'tcx>,
1219        ty: Ty<'tcx>,
1220        sp: Span,
1221        note: DiagMessage,
1222        help: Option<DiagMessage>,
1223        fn_mode: CItemKind,
1224    ) {
1225        let lint = match fn_mode {
1226            CItemKind::Declaration => IMPROPER_CTYPES,
1227            CItemKind::Definition => IMPROPER_CTYPES_DEFINITIONS,
1228        };
1229        let desc = match fn_mode {
1230            CItemKind::Declaration => "block",
1231            CItemKind::Definition => "fn",
1232        };
1233        let span_note = if let ty::Adt(def, _) = ty.kind()
1234            && let Some(sp) = cx.tcx.hir_span_if_local(def.did())
1235        {
1236            Some(sp)
1237        } else {
1238            None
1239        };
1240        cx.emit_span_lint(lint, sp, ImproperCTypes { ty, desc, label: sp, help, note, span_note });
1241    }
1242}
1243
1244/// `ImproperCTypesDefinitions` checks items outside of foreign items (e.g. stuff that isn't in
1245/// `extern "C" { }` blocks):
1246///
1247/// - `extern "<abi>" fn` definitions are checked in the same way as the
1248///   `ImproperCtypesDeclarations` visitor checks functions if `<abi>` is external (e.g. "C").
1249/// - All other items which contain types (e.g. other functions, struct definitions, etc) are
1250///   checked for extern fn-ptrs with external ABIs.
1251impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
1252    fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, it: &hir::ForeignItem<'tcx>) {
1253        let abi = cx.tcx.hir_get_foreign_abi(it.hir_id());
1254
1255        match it.kind {
1256            hir::ForeignItemKind::Fn(sig, _, _) => {
1257                // fnptrs are a special case, they always need to be treated as
1258                // "the element rendered unsafe" because their unsafety doesn't affect
1259                // their surroundings, and their type is often declared inline
1260                if !abi.is_rustic_abi() {
1261                    self.check_foreign_fn(cx, CItemKind::Declaration, it.owner_id.def_id, sig.decl);
1262                } else {
1263                    self.check_fn_for_external_abi_fnptr(
1264                        cx,
1265                        CItemKind::Declaration,
1266                        it.owner_id.def_id,
1267                        sig.decl,
1268                    );
1269                }
1270            }
1271            hir::ForeignItemKind::Static(ty, _, _) if !abi.is_rustic_abi() => {
1272                self.check_foreign_static(cx, it.owner_id, ty.span);
1273            }
1274            hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => (),
1275        }
1276    }
1277
1278    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
1279        match item.kind {
1280            hir::ItemKind::Static(_, _, ty, _)
1281            | hir::ItemKind::Const(_, _, ty, _)
1282            | hir::ItemKind::TyAlias(_, _, ty) => {
1283                self.check_type_for_external_abi_fnptr(
1284                    cx,
1285                    VisitorState::static_entry_point(),
1286                    ty,
1287                    cx.tcx.type_of(item.owner_id).instantiate_identity().skip_norm_wip(),
1288                    CItemKind::Definition,
1289                );
1290            }
1291            // See `check_fn` for declarations, `check_foreign_items` for definitions in extern blocks
1292            hir::ItemKind::Fn { .. } => {}
1293            hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) | hir::ItemKind::Enum(..) => {
1294                // looking for extern FnPtr:s is delegated to `check_field_def`.
1295                let adt_def: AdtDef<'tcx> = cx.tcx.adt_def(item.owner_id.to_def_id());
1296
1297                if adt_def.repr().c() && !adt_def.repr().packed() && adt_def.repr().align.is_none()
1298                {
1299                    self.check_reprc_adt(cx, item, adt_def);
1300                }
1301            }
1302
1303            // Doesn't define something that can contain a external type to be checked.
1304            hir::ItemKind::Impl(..)
1305            | hir::ItemKind::TraitAlias(..)
1306            | hir::ItemKind::Trait { .. }
1307            | hir::ItemKind::GlobalAsm { .. }
1308            | hir::ItemKind::ForeignMod { .. }
1309            | hir::ItemKind::Mod(..)
1310            | hir::ItemKind::Macro(..)
1311            | hir::ItemKind::Use(..)
1312            | hir::ItemKind::ExternCrate(..)
1313            | hir::ItemKind::TestBinderConstraints { .. } => {}
1314        }
1315    }
1316
1317    fn check_field_def(&mut self, cx: &LateContext<'tcx>, field: &'tcx hir::FieldDef<'tcx>) {
1318        self.check_type_for_external_abi_fnptr(
1319            cx,
1320            VisitorState::static_entry_point(),
1321            field.ty,
1322            cx.tcx.type_of(field.def_id).instantiate_identity().skip_norm_wip(),
1323            CItemKind::Definition,
1324        );
1325    }
1326
1327    fn check_fn(
1328        &mut self,
1329        cx: &LateContext<'tcx>,
1330        kind: hir::intravisit::FnKind<'tcx>,
1331        decl: &'tcx hir::FnDecl<'_>,
1332        _: &'tcx hir::Body<'_>,
1333        _: Span,
1334        id: LocalDefId,
1335    ) {
1336        use hir::intravisit::FnKind;
1337
1338        let abi = match kind {
1339            FnKind::ItemFn(_, _, header, ..) => header.abi,
1340            FnKind::Method(_, sig, ..) => sig.header.abi,
1341            _ => return,
1342        };
1343
1344        // fnptrs are a special case, they always need to be treated as
1345        // "the element rendered unsafe" because their unsafety doesn't affect
1346        // their surroundings, and their type is often declared inline
1347        if !abi.is_rustic_abi() {
1348            self.check_foreign_fn(cx, CItemKind::Definition, id, decl);
1349        } else {
1350            self.check_fn_for_external_abi_fnptr(cx, CItemKind::Definition, id, decl);
1351        }
1352    }
1353}