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_data_structures::fx::FxHashSet;
8use rustc_errors::{DiagMessage, msg};
9use rustc_hashes::Hash128;
10use rustc_hir::def::CtorKind;
11use rustc_hir::intravisit::Visitor;
12use rustc_hir::{self as hir, AmbigArg};
13use rustc_lint_defs::{declare_lint, impl_lint_pass};
14use rustc_middle::ty::{
15    self, Adt, AdtDef, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
16    TypeVisitableExt, Unnormalized,
17};
18use rustc_span::def_id::LocalDefId;
19use rustc_span::{Span, bug, sym};
20use rustc_target::spec::Os;
21use tracing::debug;
22
23use super::repr_nullable_ptr;
24use crate::diagnostics::{ImproperCTypes, UsesPowerAlignment};
25use crate::{LateContext, LateLintPass, LintContext};
26
27#[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! {
28    /// The `improper_ctypes` lint detects incorrect use of types in foreign
29    /// modules.
30    ///
31    /// ### Example
32    ///
33    /// ```rust
34    /// unsafe extern "C" {
35    ///     static STATIC: String;
36    /// }
37    /// ```
38    ///
39    /// {{produces}}
40    ///
41    /// ### Explanation
42    ///
43    /// The compiler has several checks to verify that types used in `extern`
44    /// blocks are safe and follow certain rules to ensure proper
45    /// compatibility with the foreign interfaces. This lint is issued when it
46    /// detects a probable mistake in a definition. The lint usually should
47    /// provide a description of the issue, along with possibly a hint on how
48    /// to resolve it.
49    IMPROPER_CTYPES,
50    Warn,
51    "proper use of libc types in foreign modules"
52}
53
54#[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! {
55    /// The `improper_ctypes_definitions` lint detects incorrect use of
56    /// [`extern` function] definitions.
57    ///
58    /// [`extern` function]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier
59    ///
60    /// ### Example
61    ///
62    /// ```rust
63    /// # #![allow(unused)]
64    /// pub extern "C" fn str_type(p: &str) { }
65    /// ```
66    ///
67    /// {{produces}}
68    ///
69    /// ### Explanation
70    ///
71    /// There are many parameter and return types that may be specified in an
72    /// `extern` function that are not compatible with the given ABI. This
73    /// lint is an alert that these types should not be used. The lint usually
74    /// should provide a description of the issue, along with possibly a hint
75    /// on how to resolve it.
76    IMPROPER_CTYPES_DEFINITIONS,
77    Warn,
78    "proper use of libc types in foreign item definitions"
79}
80
81#[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! {
82    /// The `uses_power_alignment` lint detects specific `repr(C)`
83    /// aggregates on AIX.
84    /// In its platform C ABI, AIX uses the "power" (as in PowerPC) alignment
85    /// rule (detailed in https://www.ibm.com/docs/en/xl-c-and-cpp-aix/16.1?topic=data-using-alignment-modes#alignment),
86    /// which can also be set for XLC by `#pragma align(power)` or
87    /// `-qalign=power`. Aggregates with a floating-point type as the
88    /// recursively first field (as in "at offset 0") modify the layout of
89    /// *subsequent* fields of the associated structs to use an alignment value
90    /// where the floating-point type is aligned on a 4-byte boundary.
91    ///
92    /// Effectively, subsequent floating-point fields act as-if they are `repr(packed(4))`. This
93    /// would be unsound to do in a `repr(C)` type without all the restrictions that come with
94    /// `repr(packed)`. Rust instead chooses a layout that maintains soundness of Rust code, at the
95    /// expense of incompatibility with C code.
96    ///
97    /// ### Example
98    ///
99    /// ```rust,ignore (fails on non-powerpc64-ibm-aix)
100    /// #[repr(C)]
101    /// pub struct Floats {
102    ///     a: f64,
103    ///     b: u8,
104    ///     c: f64,
105    /// }
106    /// ```
107    ///
108    /// This will produce:
109    ///
110    /// ```text
111    /// warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
112    ///  --> <source>:5:3
113    ///   |
114    /// 5 |   c: f64,
115    ///   |   ^^^^^^
116    ///   |
117    ///   = note: `#[warn(uses_power_alignment)]` on by default
118    /// ```
119    ///
120    /// ### Explanation
121    ///
122    /// The power alignment rule specifies that the above struct has the
123    /// following alignment:
124    ///  - offset_of!(Floats, a) == 0
125    ///  - offset_of!(Floats, b) == 8
126    ///  - offset_of!(Floats, c) == 12
127    ///
128    /// However, Rust currently aligns `c` at `offset_of!(Floats, c) == 16`.
129    /// Using offset 12 would be unsound since `f64` generally must be 8-aligned on this target.
130    /// Thus, a warning is produced for the above struct.
131    USES_POWER_ALIGNMENT,
132    Warn,
133    "Structs do not follow the power alignment rule under repr(C)"
134}
135
136/// Remembers types we already checked and found FFI-safe, so we don't check the
137/// same type again every time it shows up in another function.
138/// We only remember "safe" types, never "unsafe" ones. That way we never need to
139/// keep the actual type around, just a fingerprint of it.
140#[derive(#[automatically_derived]
impl ::core::default::Default for ImproperCTypesLint {
    #[inline]
    fn default() -> Self {
        ImproperCTypesLint { known_safe: ::core::default::Default::default() }
    }
}Default)]
141pub(crate) struct ImproperCTypesLint {
142    /// A fingerprint of the type, not the type itself. Uses a big 128-bit
143    /// fingerprint (not a smaller 64-bit one) so two different types can't
144    /// accidentally get treated as the same one.
145    known_safe: RefCell<FxHashSet<(Hash128, u8)>>,
146}
147
148impl<'tcx> ImproperCTypesLint {
149    fn cache_key(cx: &LateContext<'tcx>, ty: Ty<'tcx>, flags: RootUseFlags) -> (Hash128, u8) {
150        (cx.tcx.type_id_hash(ty), flags.bits())
151    }
152
153    fn check_ffi_type(
154        &self,
155        cx: &LateContext<'tcx>,
156        ty: Ty<'tcx>,
157        state: VisitorState,
158        span: Span,
159        mode: CItemKind,
160        check: impl FnOnce() -> FfiResult<'tcx>,
161    ) {
162        let key = Self::cache_key(cx, ty, state.root_use_flags);
163        if self.known_safe.borrow().contains(&key) {
164            return;
165        }
166
167        let ffi_res = check();
168
169        if #[allow(non_exhaustive_omitted_patterns)] match ffi_res {
    FfiResult::FfiSafe => true,
    _ => false,
}matches!(ffi_res, FfiResult::FfiSafe) {
170            self.known_safe.borrow_mut().insert(key);
171        }
172
173        self.process_ffi_result(cx, span, ffi_res, mode);
174    }
175}
176
177impl ::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 => [
178    IMPROPER_CTYPES,
179    IMPROPER_CTYPES_DEFINITIONS,
180    USES_POWER_ALIGNMENT
181]);
182
183/// A common pattern in this lint is to attempt normalize_erasing_regions,
184/// but keep the original type if it were to fail.
185/// This may or may not be supported in the logic behind the `Unnormalized` wrapper,
186/// (FIXME?)
187/// but it should be enough for non-wrapped types to be as normalised as this lint needs them to be.
188fn maybe_normalize_erasing_regions<'tcx>(
189    cx: &LateContext<'tcx>,
190    value: Unnormalized<'tcx, Ty<'tcx>>,
191) -> Ty<'tcx> {
192    // Use `TypingMode::Borrowck` so the new solver doesn't reveal opaque types since we're now
193    // past hir typeck. If we were to attempt to reveal more opaque types, dropping the
194    // `InferCtxt` would ICE (see #156352).
195    let typing_env = if let Some(body_id) = cx.enclosing_body {
196        let body_def_id = cx.tcx.hir_enclosing_body_owner(body_id.hir_id);
197        ty::TypingEnv::new(cx.param_env, ty::TypingMode::borrowck(cx.tcx, body_def_id))
198    } else {
199        cx.typing_env()
200    };
201    cx.tcx.try_normalize_erasing_regions(typing_env, value).unwrap_or(value.skip_norm_wip())
202}
203
204/// Check a variant of a non-exhaustive enum for improper ctypes
205///
206/// We treat `#[non_exhaustive] enum` as "ensure that code will compile if new variants are added".
207/// This includes linting, on a best-effort basis. There are valid additions that are unlikely.
208///
209/// Adding a data-carrying variant to an existing C-like enum that is passed to C is "unlikely",
210/// so we don't need the lint to account for it.
211/// e.g. going from enum Foo { A, B, C } to enum Foo { A, B, C, D(u32) }.
212pub(crate) fn check_non_exhaustive_variant(
213    non_exhaustive_variant_list: bool,
214    variant: &ty::VariantDef,
215) -> ControlFlow<DiagMessage, ()> {
216    // non_exhaustive suggests it is possible that someone might break ABI
217    // see: https://github.com/rust-lang/rust/issues/44109#issuecomment-537583344
218    // so warn on complex enums being used outside their crate
219    if non_exhaustive_variant_list {
220        // which is why we only warn about really_tagged_union reprs from https://rust.tf/rfc2195
221        // with an enum like `#[repr(u8)] enum Enum { A(DataA), B(DataB), }`
222        // but exempt enums with unit ctors like C's (e.g. from rust-bindgen)
223        if variant_has_complex_ctor(variant) {
224            return ControlFlow::Break(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("this enum is non-exhaustive"))msg!("this enum is non-exhaustive"));
225        }
226    }
227
228    if variant.field_list_has_applicable_non_exhaustive() {
229        return ControlFlow::Break(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("this enum has non-exhaustive variants"))msg!("this enum has non-exhaustive variants"));
230    }
231
232    ControlFlow::Continue(())
233}
234
235fn variant_has_complex_ctor(variant: &ty::VariantDef) -> bool {
236    // CtorKind::Const means a "unit" ctor
237    !#[allow(non_exhaustive_omitted_patterns)] match variant.ctor_kind() {
    Some(CtorKind::Const) => true,
    _ => false,
}matches!(variant.ctor_kind(), Some(CtorKind::Const))
238}
239
240/// Per-struct-field function that checks if a struct definition follows
241/// the Power alignment Rule (see the `check_struct_for_power_alignment` function).
242fn check_arg_for_power_alignment<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
243    let tcx = cx.tcx;
244    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);
245
246    // Structs (under repr(C)) follow the power alignment rule if:
247    //   - the first field of the struct is a floating-point type that
248    //     is greater than 4-bytes, or
249    //   - the first field of the struct is an aggregate whose
250    //     recursively first field is a floating-point type greater than
251    //     4 bytes.
252    if ty.is_floating_point() && ty.primitive_size(tcx).bytes() > 4 {
253        return true;
254    } else if let Adt(adt_def, _) = ty.kind()
255        && adt_def.is_struct()
256        && adt_def.repr().c()
257        && !adt_def.repr().packed()
258        && adt_def.repr().align.is_none()
259    {
260        let struct_variant = adt_def.variant(VariantIdx::ZERO);
261        // Within a nested struct, all fields are examined to correctly
262        // report if any fields after the nested struct within the
263        // original struct are misaligned.
264        for struct_field in &struct_variant.fields {
265            let field_ty = tcx.type_of(struct_field.did).instantiate_identity().skip_norm_wip();
266            if check_arg_for_power_alignment(cx, field_ty) {
267                return true;
268            }
269        }
270    }
271    return false;
272}
273
274/// Check a struct definition for respect of the Power alignment Rule (as in PowerPC),
275/// which should be respected in the "aix" target OS.
276/// To do so, we must follow one of the two following conditions:
277/// - The first field of the struct must be floating-point type that
278///    is greater than 4-bytes.
279///  - The first field of the struct must be an aggregate whose
280///    recursively first field is a floating-point type greater than
281///    4 bytes.
282fn check_struct_for_power_alignment<'tcx>(
283    cx: &LateContext<'tcx>,
284    item: &'tcx hir::Item<'tcx>,
285    adt_def: AdtDef<'tcx>,
286) {
287    let tcx = cx.tcx;
288
289    // Only consider structs (not enums or unions) on AIX.
290    if tcx.sess.target.os != Os::Aix || !adt_def.is_struct() {
291        return;
292    }
293
294    // The struct must be repr(C), but ignore it if it explicitly specifies its alignment with
295    // either `align(N)` or `packed(N)`.
296    if adt_def.repr().c() && !adt_def.repr().packed() && adt_def.repr().align.is_none() {
297        let struct_variant_data = item.expect_struct().2;
298        for field_def in struct_variant_data.fields().iter().skip(1) {
299            // Struct fields (after the first field) are checked for the
300            // power alignment rule, as fields after the first are likely
301            // to be the fields that are misaligned.
302            let ty = tcx.type_of(field_def.def_id).instantiate_identity().skip_norm_wip();
303            if check_arg_for_power_alignment(cx, ty) {
304                cx.emit_span_lint(USES_POWER_ALIGNMENT, field_def.span, UsesPowerAlignment);
305            }
306        }
307    }
308}
309
310/// Annotates whether we are in the context of an item *defined* in rust
311/// and exposed to an FFI boundary,
312/// or the context of an item from elsewhere, whose interface is re-*declared* in rust.
313#[derive(#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for CItemKind { }
#[automatically_derived]
impl ::core::clone::Clone for CItemKind {
    #[inline]
    fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for CItemKind { }Copy)]
314enum CItemKind {
315    Declaration,
316    Definition,
317}
318
319/// Annotates whether we are in the context of a function's argument types or return type.
320#[derive(#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for FnPos { }
#[automatically_derived]
impl ::core::clone::Clone for FnPos {
    #[inline]
    fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for FnPos { }Copy)]
321enum FnPos {
322    Arg,
323    Ret,
324}
325
326enum FfiResult<'tcx> {
327    FfiSafe,
328    FfiPhantom(Ty<'tcx>),
329    FfiUnsafe { ty: Ty<'tcx>, reason: DiagMessage, help: Option<DiagMessage> },
330}
331
332/// The result when a type has been checked but perhaps not completely. `None` indicates that
333/// FFI safety/unsafety has not yet been determined, `Some(res)` indicates that the safety/unsafety
334/// in the `FfiResult` is final.
335type PartialFfiResult<'tcx> = Option<FfiResult<'tcx>>;
336
337/// What type indirection points to a given type.
338#[derive(#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for IndirectionKind { }
#[automatically_derived]
impl ::core::clone::Clone for IndirectionKind {
    #[inline]
    fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for IndirectionKind { }Copy)]
339enum IndirectionKind {
340    /// Box (valid non-null pointer, owns pointee).
341    Box,
342    /// Ref (valid non-null pointer, borrows pointee).
343    Ref,
344    /// Raw pointer (not necessarily non-null or valid. no info on ownership).
345    RawPtr,
346}
347
348#[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]
    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]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_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]
            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! {
349    /// VisitorState flags that are linked with the root type's use.
350    /// (These are the permanent part of the state, kept when visiting new Ty.)
351    #[derive(Clone, Copy, Debug, PartialEq, Eq)]
352    struct RootUseFlags: u8 {
353        /// For use in (externally-linked) static variables.
354        const STATIC = 0b000001;
355        /// For use in functions in general.
356        const FUNC = 0b000010;
357        /// For variables in function returns (implicitly: not for static variables).
358        const FN_RETURN = 0b000100;
359        /// For variables in functions/variables which are defined in rust.
360        const DEFINED = 0b001000;
361        /// For times where we are only defining the type of something
362        /// (struct/enum/union definitions, FnPtrs).
363        const THEORETICAL = 0b010000;
364    }
365}
366
367/// Description of the relationship between current Ty and
368/// the type (or lack thereof) immediately containing it
369#[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]
    fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for OuterTyKind {
    #[inline]
    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)]
370enum OuterTyKind {
371    None,
372    /// A variant that should not exist,
373    /// but is needed because we don't change the lint's behavior yet
374    NoneThroughFnPtr,
375    /// Placeholder for properties that will be used eventually
376    Other,
377}
378
379impl OuterTyKind {
380    /// Computes the relationship by providing the containing Ty itself
381    fn from_ty<'tcx>(ty: Ty<'tcx>) -> Self {
382        match ty.kind() {
383            ty::FnPtr(..) => Self::NoneThroughFnPtr,
384            ty::RawPtr(..)
385            | ty::Ref(..)
386            | ty::Adt(..)
387            | ty::Tuple(..)
388            | ty::Array(..)
389            | ty::Slice(_) => OuterTyKind::Other,
390            _ => ::rustc_span::macros::bug_impl(None,
    format_args!("Unexpected outer type {0:?}", ty), Location::caller())bug!("Unexpected outer type {ty:?}"),
391        }
392    }
393}
394
395#[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]
    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]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field3_finish(f, "VisitorState",
            "root_use_flags", &self.root_use_flags, "outer_ty_kind",
            &self.outer_ty_kind, "depth", &&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)]
396struct VisitorState {
397    /// Flags describing both the overall context in which the current Ty is,
398    /// linked to how the Visitor's original Ty was used.
399    root_use_flags: RootUseFlags,
400    /// Flags describing both the immediate context in which the current Ty is,
401    /// linked to how it relates to its parent Ty (or lack thereof).
402    outer_ty_kind: OuterTyKind,
403    /// Type recursion depth, to prevent infinite recursion
404    depth: usize,
405}
406
407impl RootUseFlags {
408    // The values that can be set.
409    const STATIC_TY: Self = Self::STATIC;
410    const ARGUMENT_TY_IN_DEFINITION: Self =
411        Self::from_bits(Self::FUNC.bits() | Self::DEFINED.bits()).unwrap();
412    const RETURN_TY_IN_DEFINITION: Self =
413        Self::from_bits(Self::FUNC.bits() | Self::FN_RETURN.bits() | Self::DEFINED.bits()).unwrap();
414    const ARGUMENT_TY_IN_DECLARATION: Self = Self::FUNC;
415    const RETURN_TY_IN_DECLARATION: Self =
416        Self::from_bits(Self::FUNC.bits() | Self::FN_RETURN.bits()).unwrap();
417    const ARGUMENT_TY_IN_FNPTR: Self =
418        Self::from_bits(Self::FUNC.bits() | Self::THEORETICAL.bits()).unwrap();
419    const RETURN_TY_IN_FNPTR: Self =
420        Self::from_bits(Self::FUNC.bits() | Self::THEORETICAL.bits() | Self::FN_RETURN.bits())
421            .unwrap();
422}
423
424impl VisitorState {
425    /// From an existing state, compute the state of any subtype of the current type.
426    /// (General case. For the case where the current type is a function pointer, see `next_in_fnptr`.)
427    fn next(&self, current_ty: Ty<'_>) -> Self {
428        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(..)));
429        VisitorState {
430            root_use_flags: self.root_use_flags,
431            outer_ty_kind: OuterTyKind::from_ty(current_ty),
432            depth: self.depth + 1,
433        }
434    }
435
436    /// From an existing state, compute the state of any subtype of the current type.
437    /// (Case where the current type is a function pointer,
438    /// meaning we need to specify if the subtype is an argument or the return.)
439    fn next_in_fnptr(&self, current_ty: Ty<'_>, fn_pos: FnPos) -> Self {
440        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(..)));
441        VisitorState {
442            root_use_flags: match fn_pos {
443                FnPos::Ret => RootUseFlags::RETURN_TY_IN_FNPTR,
444                FnPos::Arg => RootUseFlags::ARGUMENT_TY_IN_FNPTR,
445            },
446            outer_ty_kind: OuterTyKind::from_ty(current_ty),
447            depth: self.depth + 1,
448        }
449    }
450
451    /// Get the proper visitor state for a given function's arguments or return type.
452    fn fn_entry_point(fn_mode: CItemKind, fn_pos: FnPos) -> Self {
453        let p_flags = match (fn_mode, fn_pos) {
454            (CItemKind::Definition, FnPos::Ret) => RootUseFlags::RETURN_TY_IN_DEFINITION,
455            (CItemKind::Declaration, FnPos::Ret) => RootUseFlags::RETURN_TY_IN_DECLARATION,
456            (CItemKind::Definition, FnPos::Arg) => RootUseFlags::ARGUMENT_TY_IN_DEFINITION,
457            (CItemKind::Declaration, FnPos::Arg) => RootUseFlags::ARGUMENT_TY_IN_DECLARATION,
458        };
459        VisitorState { root_use_flags: p_flags, outer_ty_kind: OuterTyKind::None, depth: 0 }
460    }
461
462    /// Get the proper visitor state for a static variable's type
463    fn static_entry_point() -> Self {
464        VisitorState {
465            root_use_flags: RootUseFlags::STATIC_TY,
466            outer_ty_kind: OuterTyKind::None,
467            depth: 0,
468        }
469    }
470
471    /// Whether the type is used in a function.
472    fn is_in_function(&self) -> bool {
473        let ret = self.root_use_flags.contains(RootUseFlags::FUNC);
474        if ret {
475            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));
476        }
477        ret
478    }
479
480    /// Whether the type is used (directly or not) in a function, in return position.
481    fn is_in_function_return(&self) -> bool {
482        let ret = self.root_use_flags.contains(RootUseFlags::FN_RETURN);
483        if ret {
484            if true {
    if !self.is_in_function() {
        ::core::panicking::panic("assertion failed: self.is_in_function()")
    };
};debug_assert!(self.is_in_function());
485        }
486        ret
487    }
488
489    /// Whether the type is used (directly or not) in a defined function.
490    /// In other words, whether or not we allow non-FFI-safe types behind a C pointer,
491    /// to be treated as an opaque type on the other side of the FFI boundary.
492    fn is_in_defined_function(&self) -> bool {
493        self.root_use_flags.contains(RootUseFlags::DEFINED) && self.is_in_function()
494    }
495
496    /// Whether the type is used (directly or not) in a function pointer type.
497    /// Here, we also allow non-FFI-safe types behind a C pointer,
498    /// to be treated as an opaque type on the other side of the FFI boundary.
499    fn is_in_fnptr(&self) -> bool {
500        self.root_use_flags.contains(RootUseFlags::THEORETICAL) && self.is_in_function()
501    }
502
503    /// Whether we can expect type parameters and co in a given type.
504    fn can_expect_ty_params(&self) -> bool {
505        // rust-defined functions, as well as FnPtrs
506        self.root_use_flags.contains(RootUseFlags::THEORETICAL) || self.is_in_defined_function()
507    }
508}
509
510/// Visitor used to recursively traverse MIR types and evaluate FFI-safety.
511/// It uses ``check_*`` methods as entrypoints to be called elsewhere,
512/// and ``visit_*`` methods to recurse.
513struct ImproperCTypesVisitor<'a, 'tcx> {
514    cx: &'a LateContext<'tcx>,
515    /// To prevent problems with recursive types,
516    /// add a types-in-check cache.
517    cache: FxHashSet<Ty<'tcx>>,
518    /// The original type being checked, before we recursed
519    /// to any other types it contains.
520    base_ty: Ty<'tcx>,
521    base_fn_mode: CItemKind,
522}
523
524impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
525    fn new(
526        cx: &'a LateContext<'tcx>,
527        base_ty: Unnormalized<'tcx, Ty<'tcx>>,
528        base_fn_mode: CItemKind,
529    ) -> Self {
530        // Skip normalization for opaques: even in `TypingMode::Borrowck` the body's own
531        // defining opaques still get revealed, leaving entries in `OpaqueTypeStorage` that
532        // ICE on `InferCtxt` drop (issue #156352).
533        let base_ty = if base_ty.skip_norm_wip().has_opaque_types() {
534            base_ty.skip_norm_wip()
535        } else {
536            maybe_normalize_erasing_regions(cx, base_ty)
537        };
538        ImproperCTypesVisitor { cx, base_ty, base_fn_mode, cache: FxHashSet::default() }
539    }
540
541    /// Checks if the given indirection (box,ref,pointer) is "ffi-safe".
542    fn visit_indirection(
543        &mut self,
544        state: VisitorState,
545        ty: Ty<'tcx>,
546        inner_ty: Ty<'tcx>,
547        indirection_kind: IndirectionKind,
548    ) -> FfiResult<'tcx> {
549        use FfiResult::*;
550        let tcx = self.cx.tcx;
551
552        match indirection_kind {
553            IndirectionKind::Box => {
554                // FIXME(ctypes): this logic is broken, but it still fits the current tests:
555                // - for some reason `Box<_>`es in `extern "ABI" {}` blocks
556                //   (including within FnPtr:s)
557                //   are not treated as pointers but as FFI-unsafe structs
558                // - otherwise, treat the box itself correctly, and follow pointee safety logic
559                //   as described in the other `indirection_type` match branch.
560                if state.is_in_defined_function()
561                    || (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))
562                {
563                    if inner_ty.is_sized(tcx, self.cx.typing_env()) {
564                        return FfiSafe;
565                    } else {
566                        return FfiUnsafe {
567                            ty,
568                            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"),
569                            help: None,
570                        };
571                    }
572                } else {
573                    // (mid-retcon-commit-chain comment:)
574                    // this is the original fallback behavior, which is wrong
575                    if let ty::Adt(def, args) = ty.kind() {
576                        self.visit_struct_or_union(state, ty, *def, args)
577                    } else if truecfg!(debug_assertions) {
578                        ::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")
579                    } else {
580                        FfiSafe
581                    }
582                }
583            }
584            IndirectionKind::Ref | IndirectionKind::RawPtr => {
585                // Weird behaviour for pointee safety. the big question here is
586                // "if you have a FFI-unsafe pointee behind a FFI-safe pointer type, is it ok?"
587                // The answer until now is:
588                // "It's OK for rust-defined functions and callbacks, we'll assume those are
589                // meant to be opaque types on the other side of the FFI boundary".
590                //
591                // Reasoning:
592                // For extern function declarations, the actual definition of the function is
593                // written somewhere else, meaning the declaration is free to express this
594                // opaqueness with an extern type (opaque caller-side) or a std::ffi::c_void
595                // (opaque callee-side). For extern function definitions, however, in the case
596                // where the type is opaque caller-side, it is not opaque callee-side,
597                // and having the full type information is necessary to compile the function.
598                //
599                // It might be better to rething this, or even ignore pointee safety for a first
600                // batch of behaviour changes. See the discussion that ends with
601                // https://github.com/rust-lang/rust/pull/134697#issuecomment-2692610258
602                if (state.is_in_defined_function() || state.is_in_fnptr())
603                    && inner_ty.is_sized(self.cx.tcx, self.cx.typing_env())
604                {
605                    FfiSafe
606                } else {
607                    self.visit_type(state.next(ty), inner_ty)
608                }
609            }
610        }
611    }
612
613    /// Checks if the given `VariantDef`'s field types are "ffi-safe".
614    fn visit_variant_fields(
615        &mut self,
616        state: VisitorState,
617        ty: Ty<'tcx>,
618        def: AdtDef<'tcx>,
619        variant: &ty::VariantDef,
620        args: GenericArgsRef<'tcx>,
621    ) -> FfiResult<'tcx> {
622        use FfiResult::*;
623
624        let transparent_with_all_zst_fields = if def.repr().transparent() {
625            if let Some(field) = super::transparent_newtype_field(self.cx.tcx, variant) {
626                // Transparent newtypes have at most one non-ZST field which needs to be checked..
627                let field_ty =
628                    maybe_normalize_erasing_regions(self.cx, field.ty(self.cx.tcx, args));
629                match self.visit_type(state.next(ty), field_ty) {
630                    FfiUnsafe { ty, .. } if ty.is_unit() => (),
631                    r => return r,
632                }
633
634                false
635            } else {
636                // ..or have only ZST fields, which is FFI-unsafe (unless those fields are all
637                // `PhantomData`).
638                true
639            }
640        } else {
641            false
642        };
643
644        // We can't completely trust `repr(C)` markings, so make sure the fields are actually safe.
645        let mut all_phantom = !variant.fields.is_empty();
646        for field in &variant.fields {
647            let field_ty = maybe_normalize_erasing_regions(self.cx, field.ty(self.cx.tcx, args));
648            all_phantom &= match self.visit_type(state.next(ty), field_ty) {
649                FfiSafe => false,
650                // `()` fields are FFI-safe!
651                FfiUnsafe { ty, .. } if ty.is_unit() => false,
652                FfiPhantom(..) => true,
653                r @ FfiUnsafe { .. } => return r,
654            }
655        }
656
657        if all_phantom {
658            FfiPhantom(ty)
659        } else if transparent_with_all_zst_fields {
660            FfiUnsafe {
661                ty,
662                reason: rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("this struct contains only zero-sized fields"))msg!("this struct contains only zero-sized fields"),
663                help: None,
664            }
665        } else {
666            FfiSafe
667        }
668    }
669
670    fn visit_struct_or_union(
671        &mut self,
672        state: VisitorState,
673        ty: Ty<'tcx>,
674        def: AdtDef<'tcx>,
675        args: GenericArgsRef<'tcx>,
676    ) -> FfiResult<'tcx> {
677        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));
678        use FfiResult::*;
679
680        if !def.repr().c() && !def.repr().transparent() {
681            return FfiUnsafe {
682                ty,
683                reason: if def.is_struct() {
684                    rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("this struct has unspecified layout"))msg!("this struct has unspecified layout")
685                } else {
686                    rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("this union has unspecified layout"))msg!("this union has unspecified layout")
687                },
688                help: if def.is_struct() {
689                    Some(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct"))msg!(
690                        "consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct"
691                    ))
692                } else {
693                    // FIXME(#60405): confirm that this makes sense for unions once #60405 / RFC2645 stabilises
694                    Some(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this union"))msg!(
695                        "consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this union"
696                    ))
697                },
698            };
699        }
700
701        if def.non_enum_variant().field_list_has_applicable_non_exhaustive() {
702            return FfiUnsafe {
703                ty,
704                reason: if def.is_struct() {
705                    rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("this struct is non-exhaustive"))msg!("this struct is non-exhaustive")
706                } else {
707                    rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("this union is non-exhaustive"))msg!("this union is non-exhaustive")
708                },
709                help: None,
710            };
711        }
712
713        if def.non_enum_variant().fields.is_empty() {
714            FfiUnsafe {
715                ty,
716                reason: if def.is_struct() {
717                    rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("this struct has no fields"))msg!("this struct has no fields")
718                } else {
719                    rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("this union has no fields"))msg!("this union has no fields")
720                },
721                help: if def.is_struct() {
722                    Some(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("consider adding a member to this struct"))msg!("consider adding a member to this struct"))
723                } else {
724                    Some(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("consider adding a member to this union"))msg!("consider adding a member to this union"))
725                },
726            }
727        } else {
728            self.visit_variant_fields(state, ty, def, def.non_enum_variant(), args)
729        }
730    }
731
732    fn visit_enum(
733        &mut self,
734        state: VisitorState,
735        ty: Ty<'tcx>,
736        def: AdtDef<'tcx>,
737        args: GenericArgsRef<'tcx>,
738    ) -> FfiResult<'tcx> {
739        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));
740        use FfiResult::*;
741
742        if def.variants().is_empty() {
743            // Empty enums are okay... although sort of useless.
744            return FfiSafe;
745        }
746        // Check for a repr() attribute to specify the size of the
747        // discriminant.
748        if !def.repr().c() && !def.repr().transparent() && def.repr().int.is_none() {
749            // Special-case types like `Option<extern fn()>` and `Result<extern fn(), ()>`
750            if let Some(inner_ty) = repr_nullable_ptr(self.cx.tcx, self.cx.typing_env(), ty) {
751                return self.visit_type(state.next(ty), inner_ty);
752            }
753
754            return FfiUnsafe {
755                ty,
756                reason: rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("enum has no representation hint"))msg!("enum has no representation hint"),
757                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!(
758                    "consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum"
759                )),
760            };
761        }
762
763        let non_exhaustive = def.variant_list_has_applicable_non_exhaustive();
764        // Check the contained variants.
765        let ret = def.variants().iter().try_for_each(|variant| {
766            check_non_exhaustive_variant(non_exhaustive, variant)
767                .map_break(|reason| FfiUnsafe { ty, reason, help: None })?;
768
769            match self.visit_variant_fields(state, ty, def, variant, args) {
770                FfiSafe => ControlFlow::Continue(()),
771                r => ControlFlow::Break(r),
772            }
773        });
774        if let ControlFlow::Break(result) = ret {
775            return result;
776        }
777
778        FfiSafe
779    }
780
781    /// Checks if the given type is "ffi-safe" (has a stable, well-defined
782    /// representation which can be exported to C code).
783    fn visit_type(&mut self, state: VisitorState, ty: Ty<'tcx>) -> FfiResult<'tcx> {
784        use FfiResult::*;
785
786        let tcx = self.cx.tcx;
787
788        // Protect against infinite recursion, for example
789        // `struct S(*mut S);`.
790        if !(self.cache.insert(ty) && self.cx.tcx.recursion_limit().value_within_limit(state.depth))
791        {
792            return FfiSafe;
793        }
794
795        match *ty.kind() {
796            ty::Adt(def, args) => {
797                if let Some(inner_ty) = ty.boxed_ty() {
798                    return self.visit_indirection(state, ty, inner_ty, IndirectionKind::Box);
799                }
800                if def.is_phantom_data() {
801                    return FfiPhantom(ty);
802                }
803                match def.adt_kind() {
804                    AdtKind::Struct | AdtKind::Union => {
805                        if let Some(sym::cstring_type | sym::cstr_type) =
806                            tcx.get_diagnostic_name(def.did())
807                            && !self.base_ty.is_mutable_ptr()
808                        {
809                            return FfiUnsafe {
810                                ty,
811                                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"),
812                                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!(
813                                    "consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`"
814                                )),
815                            };
816                        }
817                        self.visit_struct_or_union(state, ty, def, args)
818                    }
819                    AdtKind::Enum => self.visit_enum(state, ty, def, args),
820                }
821            }
822
823            // Pattern types are just extra invariants on the type that you need to uphold,
824            // but only the base type is relevant for being representable in FFI.
825            // (note: this lint was written when pattern types could only be integers constrained to ranges)
826            // (also note: the lack of ".next(ty)" on the state is on purpose)
827            ty::Pat(pat_ty, _) => self.visit_type(state, pat_ty),
828
829            // types which likely have a stable representation, if the target architecture defines those
830            // note: before rust 1.77, 128-bit ints were not FFI-safe on x86_64
831            ty::Int(..) | ty::Uint(..) | ty::Float(..) => FfiResult::FfiSafe,
832
833            ty::Bool => FfiResult::FfiSafe,
834
835            ty::Char => FfiResult::FfiUnsafe {
836                ty,
837                reason: rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("the `char` type has no C equivalent"))msg!("the `char` type has no C equivalent"),
838                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")),
839            },
840
841            ty::Slice(_) => FfiUnsafe {
842                ty,
843                reason: rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("slices have no C equivalent"))msg!("slices have no C equivalent"),
844                help: Some(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("consider using a raw pointer instead"))msg!("consider using a raw pointer instead")),
845            },
846
847            ty::Dynamic(..) => {
848                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 }
849            }
850
851            ty::Str => FfiUnsafe {
852                ty,
853                reason: rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("string slices have no C equivalent"))msg!("string slices have no C equivalent"),
854                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")),
855            },
856
857            ty::Tuple(tuple) => {
858                if tuple.is_empty()
859                    && state.is_in_function_return()
860                    && #[allow(non_exhaustive_omitted_patterns)] match state.outer_ty_kind {
    OuterTyKind::None | OuterTyKind::NoneThroughFnPtr => true,
    _ => false,
}matches!(
861                        state.outer_ty_kind,
862                        OuterTyKind::None | OuterTyKind::NoneThroughFnPtr
863                    )
864                {
865                    // C functions can return void
866                    FfiSafe
867                } else {
868                    FfiUnsafe {
869                        ty,
870                        reason: rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("tuples have unspecified layout"))msg!("tuples have unspecified layout"),
871                        help: Some(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("consider using a struct instead"))msg!("consider using a struct instead")),
872                    }
873                }
874            }
875
876            ty::RawPtr(ty, _)
877                if match ty.kind() {
878                    ty::Tuple(tuple) => tuple.is_empty(),
879                    _ => false,
880                } =>
881            {
882                FfiSafe
883            }
884
885            ty::RawPtr(inner_ty, _) => {
886                return self.visit_indirection(state, ty, inner_ty, IndirectionKind::RawPtr);
887            }
888            ty::Ref(_, inner_ty, _) => {
889                return self.visit_indirection(state, ty, inner_ty, IndirectionKind::Ref);
890            }
891
892            ty::Array(inner_ty, _) => {
893                if state.is_in_function()
894                    // FIXME(ctypes): VVV-this-VVV shouldn't make a difference between ::None and ::NoneThroughFnPtr
895                    && #[allow(non_exhaustive_omitted_patterns)] match state.outer_ty_kind {
    OuterTyKind::None => true,
    _ => false,
}matches!(state.outer_ty_kind, OuterTyKind::None)
896                {
897                    // C doesn't really support passing arrays by value - the only way to pass an array by value
898                    // is through a struct.
899                    FfiResult::FfiUnsafe {
900                        ty,
901                        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"),
902                        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")),
903                    }
904                } else {
905                    // let's allow phantoms to go through,
906                    // since an array of 1-ZSTs is also a 1-ZST
907                    self.visit_type(state.next(ty), inner_ty)
908                }
909            }
910
911            ty::FnPtr(sig_tys, hdr) => {
912                let sig = sig_tys.with(hdr);
913                if sig.abi().is_rustic_abi() {
914                    return FfiUnsafe {
915                        ty,
916                        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"),
917                        help: Some(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("consider using an `extern fn(...) -> ...` function pointer instead"))msg!(
918                            "consider using an `extern fn(...) -> ...` function pointer instead"
919                        )),
920                    };
921                }
922
923                let sig = tcx.instantiate_bound_regions_with_erased(sig);
924                for arg in sig.inputs() {
925                    match self.visit_type(state.next_in_fnptr(ty, FnPos::Arg), *arg) {
926                        FfiSafe => {}
927                        r => return r,
928                    }
929                }
930
931                let ret_ty = sig.output();
932                self.visit_type(state.next_in_fnptr(ty, FnPos::Ret), ret_ty)
933            }
934
935            ty::Foreign(..) => FfiSafe,
936
937            ty::Never => FfiSafe,
938
939            // While opaque types are checked for earlier, if a projection in a struct field
940            // normalizes to an opaque type, then it will reach this branch.
941            ty::Alias(_, ty::AliasTy { kind: ty::Opaque { .. }, .. }) => {
942                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 }
943            }
944
945            // `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe,
946            //  so they are currently ignored for the purposes of this lint.
947            ty::Param(..)
948            | ty::Alias(_, ty::AliasTy { kind: ty::Projection { .. } | ty::Inherent { .. }, .. })
949                if state.can_expect_ty_params() =>
950            {
951                FfiSafe
952            }
953
954            ty::UnsafeBinder(_) => FfiUnsafe {
955                ty,
956                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"),
957                help: None,
958            },
959
960            // Safety net for when normalization reveals a body's own defining opaque
961            // (e.g. `async extern fn`'s `impl Future` → `Coroutine`); the nicer
962            // "opaque types have no C equivalent" message comes from `visit_for_opaque_ty`
963            // in `check_type` before normalization (issue #156352).
964            ty::Closure(..)
965            | ty::CoroutineClosure(..)
966            | ty::Coroutine(..)
967            | ty::CoroutineWitness(..) => FfiUnsafe {
968                ty,
969                reason: rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("closures and coroutines are not FFI-safe"))msg!("closures and coroutines are not FFI-safe"),
970                help: None,
971            },
972
973            ty::Param(..)
974            | ty::Alias(
975                _,
976                ty::AliasTy {
977                    kind: ty::Projection { .. } | ty::Inherent { .. } | ty::Free { .. },
978                    ..
979                },
980            )
981            | ty::Infer(..)
982            | ty::Bound(..)
983            | ty::Error(_)
984            | ty::Placeholder(..)
985            | 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),
986        }
987    }
988
989    fn visit_for_opaque_ty(&mut self, ty: Ty<'tcx>) -> PartialFfiResult<'tcx> {
990        struct ProhibitOpaqueTypes;
991        impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for ProhibitOpaqueTypes {
992            type Result = ControlFlow<Ty<'tcx>>;
993
994            fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
995                if !ty.has_opaque_types() {
996                    return ControlFlow::Continue(());
997                }
998
999                if let ty::Alias(_, ty::AliasTy { kind: ty::Opaque { .. }, .. }) = ty.kind() {
1000                    ControlFlow::Break(ty)
1001                } else {
1002                    ty.super_visit_with(self)
1003                }
1004            }
1005        }
1006
1007        ty.visit_with(&mut ProhibitOpaqueTypes).break_value().map(|ty| FfiResult::FfiUnsafe {
1008            ty,
1009            reason: rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("opaque types have no C equivalent"))msg!("opaque types have no C equivalent"),
1010            help: None,
1011        })
1012    }
1013
1014    fn check_type(
1015        &mut self,
1016        state: VisitorState,
1017        ty: Unnormalized<'tcx, Ty<'tcx>>,
1018    ) -> FfiResult<'tcx> {
1019        // Catch opaques before normalization so the new solver doesn't reveal them
1020        // (e.g. `async extern fn` return → `Coroutine`) and we get the nicer
1021        // "opaque types have no C equivalent" message.
1022        if let Some(res) = self.visit_for_opaque_ty(ty.skip_norm_wip()) {
1023            return res;
1024        }
1025        let ty = maybe_normalize_erasing_regions(self.cx, ty);
1026        if let Some(res) = self.visit_for_opaque_ty(ty) {
1027            return res;
1028        }
1029
1030        self.visit_type(state, ty)
1031    }
1032}
1033
1034impl<'tcx> ImproperCTypesLint {
1035    /// Find any fn-ptr types with external ABIs in `ty`, and FFI-checks them.
1036    /// For example, `Option<extern "C" fn()>` FFI-checks `extern "C" fn()`.
1037    fn check_type_for_external_abi_fnptr(
1038        &mut self,
1039        cx: &LateContext<'tcx>,
1040        state: VisitorState,
1041        hir_ty: &hir::Ty<'tcx>,
1042        ty: Ty<'tcx>,
1043        fn_mode: CItemKind,
1044    ) {
1045        struct FnPtrFinder<'tcx> {
1046            current_depth: usize,
1047            depths: Vec<usize>,
1048            spans: Vec<Span>,
1049            tys: Vec<Ty<'tcx>>,
1050        }
1051
1052        impl<'tcx> hir::intravisit::Visitor<'_> for FnPtrFinder<'tcx> {
1053            fn visit_ty(&mut self, ty: &'_ hir::Ty<'_, AmbigArg>) {
1054                {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/7189d39d9ce936881b8132c6addeaf3e295cd455/compiler/rustc_lint/src/types/improper_ctypes.rs:1054",
                        "rustc_lint::types::improper_ctypes",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/7189d39d9ce936881b8132c6addeaf3e295cd455/compiler/rustc_lint/src/types/improper_ctypes.rs"),
                        ::tracing_core::__macro_support::Option::Some(1054u32),
                        ::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);
1055                self.current_depth += 1;
1056                if let hir::TyKind::FnPtr(hir::FnPtrTy { abi, .. }) = ty.kind
1057                    && !abi.is_rustic_abi()
1058                {
1059                    self.depths.push(self.current_depth);
1060                    self.spans.push(ty.span);
1061                }
1062
1063                hir::intravisit::walk_ty(self, ty);
1064                self.current_depth -= 1;
1065            }
1066        }
1067
1068        impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for FnPtrFinder<'tcx> {
1069            type Result = ();
1070
1071            fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
1072                if let ty::FnPtr(_, hdr) = ty.kind()
1073                    && !hdr.abi().is_rustic_abi()
1074                {
1075                    self.tys.push(ty);
1076                }
1077
1078                ty.super_visit_with(self)
1079            }
1080        }
1081
1082        let mut visitor = FnPtrFinder {
1083            spans: Vec::new(),
1084            tys: Vec::new(),
1085            depths: Vec::new(),
1086            current_depth: 0,
1087        };
1088        ty.visit_with(&mut visitor);
1089        visitor.visit_ty_unambig(hir_ty);
1090
1091        let all_types = iter::zip(
1092            visitor.depths.drain(..),
1093            iter::zip(visitor.tys.drain(..), visitor.spans.drain(..)),
1094        );
1095        for (depth, (fn_ptr_ty, span)) in all_types {
1096            let fn_ptr_ty = Unnormalized::new_wip(fn_ptr_ty);
1097            let mut visitor = ImproperCTypesVisitor::new(cx, fn_ptr_ty, fn_mode);
1098            let bridge_state = VisitorState { depth, ..state };
1099            // FIXME(ctypes): make a check_for_fnptr
1100            let ffi_res = visitor.check_type(bridge_state, fn_ptr_ty);
1101
1102            self.process_ffi_result(cx, span, ffi_res, fn_mode);
1103        }
1104    }
1105
1106    /// Regardless of a function's need to be "ffi-safe", look for fn-ptr argument/return types
1107    /// that need to be checked for ffi-safety.
1108    fn check_fn_for_external_abi_fnptr(
1109        &mut self,
1110        cx: &LateContext<'tcx>,
1111        fn_mode: CItemKind,
1112        def_id: LocalDefId,
1113        decl: &'tcx hir::FnDecl<'_>,
1114    ) {
1115        let sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_norm_wip();
1116        let sig = cx.tcx.instantiate_bound_regions_with_erased(sig);
1117
1118        for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) {
1119            let state = VisitorState::fn_entry_point(fn_mode, FnPos::Arg);
1120            self.check_type_for_external_abi_fnptr(cx, state, input_hir, *input_ty, fn_mode);
1121        }
1122
1123        if let hir::FnRetTy::Return(ret_hir) = decl.output {
1124            let state = VisitorState::fn_entry_point(fn_mode, FnPos::Ret);
1125            self.check_type_for_external_abi_fnptr(cx, state, ret_hir, sig.output(), fn_mode);
1126        }
1127    }
1128
1129    /// For a local definition of a #[repr(C)] struct/enum/union, check that it is indeed FFI-safe.
1130    fn check_reprc_adt(
1131        &mut self,
1132        cx: &LateContext<'tcx>,
1133        item: &'tcx hir::Item<'tcx>,
1134        adt_def: AdtDef<'tcx>,
1135    ) {
1136        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!(
1137            adt_def.repr().c() && !adt_def.repr().packed() && adt_def.repr().align.is_none()
1138        );
1139
1140        // FIXME(ctypes): this following call is awkward.
1141        // is there a way to perform its logic in MIR space rather than HIR space?
1142        // (so that its logic can be absorbed into visitor.visit_struct_or_union)
1143        check_struct_for_power_alignment(cx, item, adt_def);
1144    }
1145
1146    fn check_foreign_static(&mut self, cx: &LateContext<'tcx>, id: hir::OwnerId, span: Span) {
1147        let ty = cx.tcx.type_of(id).instantiate_identity();
1148        let state = VisitorState::static_entry_point();
1149        self.check_ffi_type(cx, ty.skip_norm_wip(), state, span, CItemKind::Declaration, || {
1150            let mut visitor = ImproperCTypesVisitor::new(cx, ty, CItemKind::Declaration);
1151            visitor.check_type(state, ty)
1152        });
1153    }
1154
1155    /// Check if a function's argument types and result type are "ffi-safe".
1156    fn check_foreign_fn(
1157        &mut self,
1158        cx: &LateContext<'tcx>,
1159        fn_mode: CItemKind,
1160        def_id: LocalDefId,
1161        decl: &'tcx hir::FnDecl<'_>,
1162    ) {
1163        let sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_norm_wip();
1164        let sig = cx.tcx.instantiate_bound_regions_with_erased(sig);
1165
1166        for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) {
1167            let state = VisitorState::fn_entry_point(fn_mode, FnPos::Arg);
1168            self.check_ffi_type(cx, *input_ty, state, input_hir.span, fn_mode, || {
1169                let input_ty = Unnormalized::new_wip(*input_ty);
1170                let mut visitor = ImproperCTypesVisitor::new(cx, input_ty, fn_mode);
1171                visitor.check_type(state, input_ty)
1172            });
1173        }
1174
1175        if let hir::FnRetTy::Return(ret_hir) = decl.output {
1176            let state = VisitorState::fn_entry_point(fn_mode, FnPos::Ret);
1177            self.check_ffi_type(cx, sig.output(), state, ret_hir.span, fn_mode, || {
1178                let output_ty = Unnormalized::new_wip(sig.output());
1179                let mut visitor = ImproperCTypesVisitor::new(cx, output_ty, fn_mode);
1180                visitor.check_type(state, output_ty)
1181            });
1182        }
1183    }
1184
1185    fn process_ffi_result(
1186        &self,
1187        cx: &LateContext<'tcx>,
1188        sp: Span,
1189        res: FfiResult<'tcx>,
1190        fn_mode: CItemKind,
1191    ) {
1192        match res {
1193            FfiResult::FfiSafe => {}
1194            FfiResult::FfiPhantom(ty) => {
1195                self.emit_ffi_unsafe_type_lint(
1196                    cx,
1197                    ty,
1198                    sp,
1199                    rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("composed only of `PhantomData`"))msg!("composed only of `PhantomData`"),
1200                    None,
1201                    fn_mode,
1202                );
1203            }
1204            FfiResult::FfiUnsafe { ty, reason, help } => {
1205                self.emit_ffi_unsafe_type_lint(cx, ty, sp, reason, help, fn_mode);
1206            }
1207        }
1208    }
1209
1210    fn emit_ffi_unsafe_type_lint(
1211        &self,
1212        cx: &LateContext<'tcx>,
1213        ty: Ty<'tcx>,
1214        sp: Span,
1215        note: DiagMessage,
1216        help: Option<DiagMessage>,
1217        fn_mode: CItemKind,
1218    ) {
1219        let lint = match fn_mode {
1220            CItemKind::Declaration => IMPROPER_CTYPES,
1221            CItemKind::Definition => IMPROPER_CTYPES_DEFINITIONS,
1222        };
1223        let desc = match fn_mode {
1224            CItemKind::Declaration => "block",
1225            CItemKind::Definition => "fn",
1226        };
1227        let span_note = if let ty::Adt(def, _) = ty.kind()
1228            && let Some(sp) = cx.tcx.hir_span_if_local(def.did())
1229        {
1230            Some(sp)
1231        } else {
1232            None
1233        };
1234        cx.emit_span_lint(lint, sp, ImproperCTypes { ty, desc, label: sp, help, note, span_note });
1235    }
1236}
1237
1238/// `ImproperCTypesDefinitions` checks items outside of foreign items (e.g. stuff that isn't in
1239/// `extern "C" { }` blocks):
1240///
1241/// - `extern "<abi>" fn` definitions are checked in the same way as the
1242///   `ImproperCtypesDeclarations` visitor checks functions if `<abi>` is external (e.g. "C").
1243/// - All other items which contain types (e.g. other functions, struct definitions, etc) are
1244///   checked for extern fn-ptrs with external ABIs.
1245impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
1246    fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, it: &hir::ForeignItem<'tcx>) {
1247        let abi = cx.tcx.hir_get_foreign_abi(it.hir_id());
1248
1249        match it.kind {
1250            hir::ForeignItemKind::Fn(sig, _, _) => {
1251                // fnptrs are a special case, they always need to be treated as
1252                // "the element rendered unsafe" because their unsafety doesn't affect
1253                // their surroundings, and their type is often declared inline
1254                if !abi.is_rustic_abi() {
1255                    self.check_foreign_fn(cx, CItemKind::Declaration, it.owner_id.def_id, sig.decl);
1256                } else {
1257                    self.check_fn_for_external_abi_fnptr(
1258                        cx,
1259                        CItemKind::Declaration,
1260                        it.owner_id.def_id,
1261                        sig.decl,
1262                    );
1263                }
1264            }
1265            hir::ForeignItemKind::Static(ty, _, _) if !abi.is_rustic_abi() => {
1266                self.check_foreign_static(cx, it.owner_id, ty.span);
1267            }
1268            hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => (),
1269        }
1270    }
1271
1272    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
1273        match item.kind {
1274            hir::ItemKind::Static(_, _, ty, _)
1275            | hir::ItemKind::Const(_, _, ty, _)
1276            | hir::ItemKind::TyAlias(_, _, ty) => {
1277                self.check_type_for_external_abi_fnptr(
1278                    cx,
1279                    VisitorState::static_entry_point(),
1280                    ty,
1281                    cx.tcx.type_of(item.owner_id).instantiate_identity().skip_norm_wip(),
1282                    CItemKind::Definition,
1283                );
1284            }
1285            // See `check_fn` for declarations, `check_foreign_items` for definitions in extern blocks
1286            hir::ItemKind::Fn { .. } => {}
1287            hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) | hir::ItemKind::Enum(..) => {
1288                // looking for extern FnPtr:s is delegated to `check_field_def`.
1289                let adt_def: AdtDef<'tcx> = cx.tcx.adt_def(item.owner_id.to_def_id());
1290
1291                if adt_def.repr().c() && !adt_def.repr().packed() && adt_def.repr().align.is_none()
1292                {
1293                    self.check_reprc_adt(cx, item, adt_def);
1294                }
1295            }
1296
1297            // Doesn't define something that can contain a external type to be checked.
1298            hir::ItemKind::Impl(..)
1299            | hir::ItemKind::TraitAlias(..)
1300            | hir::ItemKind::Trait { .. }
1301            | hir::ItemKind::GlobalAsm { .. }
1302            | hir::ItemKind::ForeignMod { .. }
1303            | hir::ItemKind::Mod(..)
1304            | hir::ItemKind::Macro(..)
1305            | hir::ItemKind::Use(..)
1306            | hir::ItemKind::ExternCrate(..)
1307            | hir::ItemKind::TestBinderConstraints { .. } => {}
1308        }
1309    }
1310
1311    fn check_field_def(&mut self, cx: &LateContext<'tcx>, field: &'tcx hir::FieldDef<'tcx>) {
1312        self.check_type_for_external_abi_fnptr(
1313            cx,
1314            VisitorState::static_entry_point(),
1315            field.ty,
1316            cx.tcx.type_of(field.def_id).instantiate_identity().skip_norm_wip(),
1317            CItemKind::Definition,
1318        );
1319    }
1320
1321    fn check_fn(
1322        &mut self,
1323        cx: &LateContext<'tcx>,
1324        kind: hir::intravisit::FnKind<'tcx>,
1325        decl: &'tcx hir::FnDecl<'_>,
1326        _: &'tcx hir::Body<'_>,
1327        _: Span,
1328        id: LocalDefId,
1329    ) {
1330        use hir::intravisit::FnKind;
1331
1332        let abi = match kind {
1333            FnKind::ItemFn(_, _, header, ..) => header.abi,
1334            FnKind::Method(_, sig, ..) => sig.header.abi,
1335            _ => return,
1336        };
1337
1338        // fnptrs are a special case, they always need to be treated as
1339        // "the element rendered unsafe" because their unsafety doesn't affect
1340        // their surroundings, and their type is often declared inline
1341        if !abi.is_rustic_abi() {
1342            self.check_foreign_fn(cx, CItemKind::Definition, id, decl);
1343        } else {
1344            self.check_fn_for_external_abi_fnptr(cx, CItemKind::Definition, id, decl);
1345        }
1346    }
1347}