1use std::cell::RefCell;
2use std::iter;
3use std::ops::ControlFlow;
45use 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::{selfas hir, AmbigArg};
13use rustc_lint_defs::{declare_lint, impl_lint_pass};
14use rustc_middle::ty::{
15self, Adt, AdtDef, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
16TypeVisitableExt, Unnormalized,
17};
18use rustc_span::def_id::LocalDefId;
19use rustc_span::{Span, bug, sym};
20use rustc_target::spec::Os;
21use tracing::debug;
2223use super::repr_nullable_ptr;
24use crate::diagnostics::{ImproperCTypes, UsesPowerAlignment};
25use crate::{LateContext, LateLintPass, LintContext};
2627#[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.
49IMPROPER_CTYPES,
50 Warn,
51"proper use of libc types in foreign modules"
52}5354#[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.
76IMPROPER_CTYPES_DEFINITIONS,
77 Warn,
78"proper use of libc types in foreign item definitions"
79}8081#[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.
131USES_POWER_ALIGNMENT,
132 Warn,
133"Structs do not follow the power alignment rule under repr(C)"
134}135136/// 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.
145known_safe: RefCell<FxHashSet<(Hash128, u8)>>,
146}
147148impl<'tcx> ImproperCTypesLint {
149fn cache_key(cx: &LateContext<'tcx>, ty: Ty<'tcx>, flags: RootUseFlags) -> (Hash128, u8) {
150 (cx.tcx.type_id_hash(ty), flags.bits())
151 }
152153fn 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 ) {
162let key = Self::cache_key(cx, ty, state.root_use_flags);
163if self.known_safe.borrow().contains(&key) {
164return;
165 }
166167let ffi_res = check();
168169if #[allow(non_exhaustive_omitted_patterns)] match ffi_res {
FfiResult::FfiSafe => true,
_ => false,
}matches!(ffi_res, FfiResult::FfiSafe) {
170self.known_safe.borrow_mut().insert(key);
171 }
172173self.process_ffi_result(cx, span, ffi_res, mode);
174 }
175}
176177impl ::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]);
182183/// 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).
195let typing_env = if let Some(body_id) = cx.enclosing_body {
196let 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 {
199cx.typing_env()
200 };
201cx.tcx.try_normalize_erasing_regions(typing_env, value).unwrap_or(value.skip_norm_wip())
202}
203204/// 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
219if 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)
223if variant_has_complex_ctor(variant) {
224return ControlFlow::Break(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("this enum is non-exhaustive"))msg!("this enum is non-exhaustive"));
225 }
226 }
227228if variant.field_list_has_applicable_non_exhaustive() {
229return ControlFlow::Break(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("this enum has non-exhaustive variants"))msg!("this enum has non-exhaustive variants"));
230 }
231232 ControlFlow::Continue(())
233}
234235fn 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}
239240/// 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 {
243let tcx = cx.tcx;
244if !(tcx.sess.target.os == Os::Aix) {
::core::panicking::panic("assertion failed: tcx.sess.target.os == Os::Aix")
};assert!(tcx.sess.target.os == Os::Aix);
245246// 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.
252if ty.is_floating_point() && ty.primitive_size(tcx).bytes() > 4 {
253return 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 {
260let 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.
264for struct_field in &struct_variant.fields {
265let field_ty = tcx.type_of(struct_field.did).instantiate_identity().skip_norm_wip();
266if check_arg_for_power_alignment(cx, field_ty) {
267return true;
268 }
269 }
270 }
271return false;
272}
273274/// 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) {
287let tcx = cx.tcx;
288289// Only consider structs (not enums or unions) on AIX.
290if tcx.sess.target.os != Os::Aix || !adt_def.is_struct() {
291return;
292 }
293294// The struct must be repr(C), but ignore it if it explicitly specifies its alignment with
295 // either `align(N)` or `packed(N)`.
296if adt_def.repr().c() && !adt_def.repr().packed() && adt_def.repr().align.is_none() {
297let struct_variant_data = item.expect_struct().2;
298for 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.
302let ty = tcx.type_of(field_def.def_id).instantiate_identity().skip_norm_wip();
303if check_arg_for_power_alignment(cx, ty) {
304 cx.emit_span_lint(USES_POWER_ALIGNMENT, field_def.span, UsesPowerAlignment);
305 }
306 }
307 }
308}
309310/// 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}
318319/// 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}
325326enum FfiResult<'tcx> {
327 FfiSafe,
328 FfiPhantom(Ty<'tcx>),
329 FfiUnsafe { ty: Ty<'tcx>, reason: DiagMessage, help: Option<DiagMessage> },
330}
331332/// 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>>;
336337/// 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).
341Box,
342/// Ref (valid non-null pointer, borrows pointee).
343Ref,
344/// Raw pointer (not necessarily non-null or valid. no info on ownership).
345RawPtr,
346}
347348#[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)]
352struct RootUseFlags: u8 {
353/// For use in (externally-linked) static variables.
354const STATIC = 0b000001;
355/// For use in functions in general.
356const FUNC = 0b000010;
357/// For variables in function returns (implicitly: not for static variables).
358const FN_RETURN = 0b000100;
359/// For variables in functions/variables which are defined in rust.
360const DEFINED = 0b001000;
361/// For times where we are only defining the type of something
362 /// (struct/enum/union definitions, FnPtrs).
363const THEORETICAL = 0b010000;
364 }
365}366367/// 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 {
371None,
372/// A variant that should not exist,
373 /// but is needed because we don't change the lint's behavior yet
374NoneThroughFnPtr,
375/// Placeholder for properties that will be used eventually
376Other,
377}
378379impl OuterTyKind {
380/// Computes the relationship by providing the containing Ty itself
381fn from_ty<'tcx>(ty: Ty<'tcx>) -> Self {
382match 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}
394395#[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.
399root_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).
402outer_ty_kind: OuterTyKind,
403/// Type recursion depth, to prevent infinite recursion
404depth: usize,
405}
406407impl RootUseFlags {
408// The values that can be set.
409const STATIC_TY: Self = Self::STATIC;
410const ARGUMENT_TY_IN_DEFINITION: Self =
411Self::from_bits(Self::FUNC.bits() | Self::DEFINED.bits()).unwrap();
412const RETURN_TY_IN_DEFINITION: Self =
413Self::from_bits(Self::FUNC.bits() | Self::FN_RETURN.bits() | Self::DEFINED.bits()).unwrap();
414const ARGUMENT_TY_IN_DECLARATION: Self = Self::FUNC;
415const RETURN_TY_IN_DECLARATION: Self =
416Self::from_bits(Self::FUNC.bits() | Self::FN_RETURN.bits()).unwrap();
417const ARGUMENT_TY_IN_FNPTR: Self =
418Self::from_bits(Self::FUNC.bits() | Self::THEORETICAL.bits()).unwrap();
419const RETURN_TY_IN_FNPTR: Self =
420Self::from_bits(Self::FUNC.bits() | Self::THEORETICAL.bits() | Self::FN_RETURN.bits())
421 .unwrap();
422}
423424impl 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`.)
427fn next(&self, current_ty: Ty<'_>) -> Self {
428if !!#[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(..)));
429VisitorState {
430 root_use_flags: self.root_use_flags,
431 outer_ty_kind: OuterTyKind::from_ty(current_ty),
432 depth: self.depth + 1,
433 }
434 }
435436/// 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.)
439fn next_in_fnptr(&self, current_ty: Ty<'_>, fn_pos: FnPos) -> Self {
440if !#[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(..)));
441VisitorState {
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 }
450451/// Get the proper visitor state for a given function's arguments or return type.
452fn fn_entry_point(fn_mode: CItemKind, fn_pos: FnPos) -> Self {
453let 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 };
459VisitorState { root_use_flags: p_flags, outer_ty_kind: OuterTyKind::None, depth: 0 }
460 }
461462/// Get the proper visitor state for a static variable's type
463fn static_entry_point() -> Self {
464VisitorState {
465 root_use_flags: RootUseFlags::STATIC_TY,
466 outer_ty_kind: OuterTyKind::None,
467 depth: 0,
468 }
469 }
470471/// Whether the type is used in a function.
472fn is_in_function(&self) -> bool {
473let ret = self.root_use_flags.contains(RootUseFlags::FUNC);
474if ret {
475if 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 }
477ret478 }
479480/// Whether the type is used (directly or not) in a function, in return position.
481fn is_in_function_return(&self) -> bool {
482let ret = self.root_use_flags.contains(RootUseFlags::FN_RETURN);
483if ret {
484if true {
if !self.is_in_function() {
::core::panicking::panic("assertion failed: self.is_in_function()")
};
};debug_assert!(self.is_in_function());
485 }
486ret487 }
488489/// 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.
492fn is_in_defined_function(&self) -> bool {
493self.root_use_flags.contains(RootUseFlags::DEFINED) && self.is_in_function()
494 }
495496/// 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.
499fn is_in_fnptr(&self) -> bool {
500self.root_use_flags.contains(RootUseFlags::THEORETICAL) && self.is_in_function()
501 }
502503/// Whether we can expect type parameters and co in a given type.
504fn can_expect_ty_params(&self) -> bool {
505// rust-defined functions, as well as FnPtrs
506self.root_use_flags.contains(RootUseFlags::THEORETICAL) || self.is_in_defined_function()
507 }
508}
509510/// 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.
517cache: FxHashSet<Ty<'tcx>>,
518/// The original type being checked, before we recursed
519 /// to any other types it contains.
520base_ty: Ty<'tcx>,
521 base_fn_mode: CItemKind,
522}
523524impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
525fn 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).
533let base_ty = if base_ty.skip_norm_wip().has_opaque_types() {
534base_ty.skip_norm_wip()
535 } else {
536maybe_normalize_erasing_regions(cx, base_ty)
537 };
538ImproperCTypesVisitor { cx, base_ty, base_fn_mode, cache: FxHashSet::default() }
539 }
540541/// Checks if the given indirection (box,ref,pointer) is "ffi-safe".
542fn visit_indirection(
543&mut self,
544 state: VisitorState,
545 ty: Ty<'tcx>,
546 inner_ty: Ty<'tcx>,
547 indirection_kind: IndirectionKind,
548 ) -> FfiResult<'tcx> {
549use FfiResult::*;
550let tcx = self.cx.tcx;
551552match 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.
560if 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 {
563if inner_ty.is_sized(tcx, self.cx.typing_env()) {
564return FfiSafe;
565 } else {
566return FfiUnsafe {
567ty,
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
575if let ty::Adt(def, args) = ty.kind() {
576self.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 {
580FfiSafe581 }
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
602if (state.is_in_defined_function() || state.is_in_fnptr())
603 && inner_ty.is_sized(self.cx.tcx, self.cx.typing_env())
604 {
605FfiSafe606 } else {
607self.visit_type(state.next(ty), inner_ty)
608 }
609 }
610 }
611 }
612613/// Checks if the given `VariantDef`'s field types are "ffi-safe".
614fn 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> {
622use FfiResult::*;
623624let transparent_with_all_zst_fields = if def.repr().transparent() {
625if 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..
627let field_ty =
628maybe_normalize_erasing_regions(self.cx, field.ty(self.cx.tcx, args));
629match self.visit_type(state.next(ty), field_ty) {
630FfiUnsafe { ty, .. } if ty.is_unit() => (),
631 r => return r,
632 }
633634false
635} else {
636// ..or have only ZST fields, which is FFI-unsafe (unless those fields are all
637 // `PhantomData`).
638true
639}
640 } else {
641false
642};
643644// We can't completely trust `repr(C)` markings, so make sure the fields are actually safe.
645let mut all_phantom = !variant.fields.is_empty();
646for field in &variant.fields {
647let 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!
651FfiUnsafe { ty, .. } if ty.is_unit() => false,
652 FfiPhantom(..) => true,
653 r @ FfiUnsafe { .. } => return r,
654 }
655 }
656657if all_phantom {
658FfiPhantom(ty)
659 } else if transparent_with_all_zst_fields {
660FfiUnsafe {
661ty,
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 {
666FfiSafe667 }
668 }
669670fn 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> {
677if 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));
678use FfiResult::*;
679680if !def.repr().c() && !def.repr().transparent() {
681return FfiUnsafe {
682ty,
683 reason: if def.is_struct() {
684rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("this struct has unspecified layout"))msg!("this struct has unspecified layout")685 } else {
686rustc_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() {
689Some(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
694Some(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 }
700701if def.non_enum_variant().field_list_has_applicable_non_exhaustive() {
702return FfiUnsafe {
703ty,
704 reason: if def.is_struct() {
705rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("this struct is non-exhaustive"))msg!("this struct is non-exhaustive")706 } else {
707rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("this union is non-exhaustive"))msg!("this union is non-exhaustive")708 },
709 help: None,
710 };
711 }
712713if def.non_enum_variant().fields.is_empty() {
714FfiUnsafe {
715ty,
716 reason: if def.is_struct() {
717rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("this struct has no fields"))msg!("this struct has no fields")718 } else {
719rustc_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() {
722Some(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 {
724Some(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 {
728self.visit_variant_fields(state, ty, def, def.non_enum_variant(), args)
729 }
730 }
731732fn visit_enum(
733&mut self,
734 state: VisitorState,
735 ty: Ty<'tcx>,
736 def: AdtDef<'tcx>,
737 args: GenericArgsRef<'tcx>,
738 ) -> FfiResult<'tcx> {
739if 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));
740use FfiResult::*;
741742if def.variants().is_empty() {
743// Empty enums are okay... although sort of useless.
744return FfiSafe;
745 }
746// Check for a repr() attribute to specify the size of the
747 // discriminant.
748if !def.repr().c() && !def.repr().transparent() && def.repr().int.is_none() {
749// Special-case types like `Option<extern fn()>` and `Result<extern fn(), ()>`
750if let Some(inner_ty) = repr_nullable_ptr(self.cx.tcx, self.cx.typing_env(), ty) {
751return self.visit_type(state.next(ty), inner_ty);
752 }
753754return FfiUnsafe {
755ty,
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 }
762763let non_exhaustive = def.variant_list_has_applicable_non_exhaustive();
764// Check the contained variants.
765let 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 })?;
768769match self.visit_variant_fields(state, ty, def, variant, args) {
770FfiSafe => ControlFlow::Continue(()),
771 r => ControlFlow::Break(r),
772 }
773 });
774if let ControlFlow::Break(result) = ret {
775return result;
776 }
777778FfiSafe779 }
780781/// Checks if the given type is "ffi-safe" (has a stable, well-defined
782 /// representation which can be exported to C code).
783fn visit_type(&mut self, state: VisitorState, ty: Ty<'tcx>) -> FfiResult<'tcx> {
784use FfiResult::*;
785786let tcx = self.cx.tcx;
787788// Protect against infinite recursion, for example
789 // `struct S(*mut S);`.
790if !(self.cache.insert(ty) && self.cx.tcx.recursion_limit().value_within_limit(state.depth))
791 {
792return FfiSafe;
793 }
794795match *ty.kind() {
796 ty::Adt(def, args) => {
797if let Some(inner_ty) = ty.boxed_ty() {
798return self.visit_indirection(state, ty, inner_ty, IndirectionKind::Box);
799 }
800if def.is_phantom_data() {
801return FfiPhantom(ty);
802 }
803match def.adt_kind() {
804 AdtKind::Struct | AdtKind::Union => {
805if let Some(sym::cstring_type | sym::cstr_type) =
806tcx.get_diagnostic_name(def.did())
807 && !self.base_ty.is_mutable_ptr()
808 {
809return FfiUnsafe {
810ty,
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 }
817self.visit_struct_or_union(state, ty, def, args)
818 }
819 AdtKind::Enum => self.visit_enum(state, ty, def, args),
820 }
821 }
822823// 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)
827ty::Pat(pat_ty, _) => self.visit_type(state, pat_ty),
828829// 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
831ty::Int(..) | ty::Uint(..) | ty::Float(..) => FfiResult::FfiSafe,
832833 ty::Bool => FfiResult::FfiSafe,
834835 ty::Char => FfiResult::FfiUnsafe {
836ty,
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 },
840841 ty::Slice(_) => FfiUnsafe {
842ty,
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 },
846847 ty::Dynamic(..) => {
848FfiUnsafe { 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 }
850851 ty::Str => FfiUnsafe {
852ty,
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 },
856857 ty::Tuple(tuple) => {
858if 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
866FfiSafe867 } else {
868FfiUnsafe {
869ty,
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 }
875876 ty::RawPtr(ty, _)
877if match ty.kind() {
878 ty::Tuple(tuple) => tuple.is_empty(),
879_ => false,
880 } =>
881 {
882FfiSafe883 }
884885 ty::RawPtr(inner_ty, _) => {
886return self.visit_indirection(state, ty, inner_ty, IndirectionKind::RawPtr);
887 }
888 ty::Ref(_, inner_ty, _) => {
889return self.visit_indirection(state, ty, inner_ty, IndirectionKind::Ref);
890 }
891892 ty::Array(inner_ty, _) => {
893if 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.
899FfiResult::FfiUnsafe {
900ty,
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
907self.visit_type(state.next(ty), inner_ty)
908 }
909 }
910911 ty::FnPtr(sig_tys, hdr) => {
912let sig = sig_tys.with(hdr);
913if sig.abi().is_rustic_abi() {
914return FfiUnsafe {
915ty,
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 }
922923let sig = tcx.instantiate_bound_regions_with_erased(sig);
924for arg in sig.inputs() {
925match self.visit_type(state.next_in_fnptr(ty, FnPos::Arg), *arg) {
926 FfiSafe => {}
927 r => return r,
928 }
929 }
930931let ret_ty = sig.output();
932self.visit_type(state.next_in_fnptr(ty, FnPos::Ret), ret_ty)
933 }
934935 ty::Foreign(..) => FfiSafe,
936937 ty::Never => FfiSafe,
938939// 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.
941ty::Alias(_, ty::AliasTy { kind: ty::Opaque { .. }, .. }) => {
942FfiUnsafe { 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 }
944945// `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.
947ty::Param(..)
948 | ty::Alias(_, ty::AliasTy { kind: ty::Projection { .. } | ty::Inherent { .. }, .. })
949if state.can_expect_ty_params() =>
950 {
951FfiSafe952 }
953954 ty::UnsafeBinder(_) => FfiUnsafe {
955ty,
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 },
959960// 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).
964ty::Closure(..)
965 | ty::CoroutineClosure(..)
966 | ty::Coroutine(..)
967 | ty::CoroutineWitness(..) => FfiUnsafe {
968ty,
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 },
972973 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 }
988989fn visit_for_opaque_ty(&mut self, ty: Ty<'tcx>) -> PartialFfiResult<'tcx> {
990struct ProhibitOpaqueTypes;
991impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for ProhibitOpaqueTypes {
992type Result = ControlFlow<Ty<'tcx>>;
993994fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
995if !ty.has_opaque_types() {
996return ControlFlow::Continue(());
997 }
998999if let ty::Alias(_, ty::AliasTy { kind: ty::Opaque { .. }, .. }) = ty.kind() {
1000 ControlFlow::Break(ty)
1001 } else {
1002ty.super_visit_with(self)
1003 }
1004 }
1005 }
10061007ty.visit_with(&mut ProhibitOpaqueTypes).break_value().map(|ty| FfiResult::FfiUnsafe {
1008ty,
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 }
10131014fn 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.
1022if let Some(res) = self.visit_for_opaque_ty(ty.skip_norm_wip()) {
1023return res;
1024 }
1025let ty = maybe_normalize_erasing_regions(self.cx, ty);
1026if let Some(res) = self.visit_for_opaque_ty(ty) {
1027return res;
1028 }
10291030self.visit_type(state, ty)
1031 }
1032}
10331034impl<'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()`.
1037fn 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 ) {
1045struct FnPtrFinder<'tcx> {
1046 current_depth: usize,
1047 depths: Vec<usize>,
1048 spans: Vec<Span>,
1049 tys: Vec<Ty<'tcx>>,
1050 }
10511052impl<'tcx> hir::intravisit::Visitor<'_> for FnPtrFinder<'tcx> {
1053fn 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);
1055self.current_depth += 1;
1056if let hir::TyKind::FnPtr(hir::FnPtrTy { abi, .. }) = ty.kind
1057 && !abi.is_rustic_abi()
1058 {
1059self.depths.push(self.current_depth);
1060self.spans.push(ty.span);
1061 }
10621063 hir::intravisit::walk_ty(self, ty);
1064self.current_depth -= 1;
1065 }
1066 }
10671068impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for FnPtrFinder<'tcx> {
1069type Result = ();
10701071fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
1072if let ty::FnPtr(_, hdr) = ty.kind()
1073 && !hdr.abi().is_rustic_abi()
1074 {
1075self.tys.push(ty);
1076 }
10771078ty.super_visit_with(self)
1079 }
1080 }
10811082let mut visitor = FnPtrFinder {
1083 spans: Vec::new(),
1084 tys: Vec::new(),
1085 depths: Vec::new(),
1086 current_depth: 0,
1087 };
1088ty.visit_with(&mut visitor);
1089visitor.visit_ty_unambig(hir_ty);
10901091let all_types = iter::zip(
1092visitor.depths.drain(..),
1093 iter::zip(visitor.tys.drain(..), visitor.spans.drain(..)),
1094 );
1095for (depth, (fn_ptr_ty, span)) in all_types {
1096let fn_ptr_ty = Unnormalized::new_wip(fn_ptr_ty);
1097let mut visitor = ImproperCTypesVisitor::new(cx, fn_ptr_ty, fn_mode);
1098let bridge_state = VisitorState { depth, ..state };
1099// FIXME(ctypes): make a check_for_fnptr
1100let ffi_res = visitor.check_type(bridge_state, fn_ptr_ty);
11011102self.process_ffi_result(cx, span, ffi_res, fn_mode);
1103 }
1104 }
11051106/// 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.
1108fn 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 ) {
1115let sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_norm_wip();
1116let sig = cx.tcx.instantiate_bound_regions_with_erased(sig);
11171118for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) {
1119let state = VisitorState::fn_entry_point(fn_mode, FnPos::Arg);
1120self.check_type_for_external_abi_fnptr(cx, state, input_hir, *input_ty, fn_mode);
1121 }
11221123if let hir::FnRetTy::Return(ret_hir) = decl.output {
1124let state = VisitorState::fn_entry_point(fn_mode, FnPos::Ret);
1125self.check_type_for_external_abi_fnptr(cx, state, ret_hir, sig.output(), fn_mode);
1126 }
1127 }
11281129/// For a local definition of a #[repr(C)] struct/enum/union, check that it is indeed FFI-safe.
1130fn check_reprc_adt(
1131&mut self,
1132 cx: &LateContext<'tcx>,
1133 item: &'tcx hir::Item<'tcx>,
1134 adt_def: AdtDef<'tcx>,
1135 ) {
1136if 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 );
11391140// 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)
1143check_struct_for_power_alignment(cx, item, adt_def);
1144 }
11451146fn check_foreign_static(&mut self, cx: &LateContext<'tcx>, id: hir::OwnerId, span: Span) {
1147let ty = cx.tcx.type_of(id).instantiate_identity();
1148let state = VisitorState::static_entry_point();
1149self.check_ffi_type(cx, ty.skip_norm_wip(), state, span, CItemKind::Declaration, || {
1150let mut visitor = ImproperCTypesVisitor::new(cx, ty, CItemKind::Declaration);
1151visitor.check_type(state, ty)
1152 });
1153 }
11541155/// Check if a function's argument types and result type are "ffi-safe".
1156fn check_foreign_fn(
1157&mut self,
1158 cx: &LateContext<'tcx>,
1159 fn_mode: CItemKind,
1160 def_id: LocalDefId,
1161 decl: &'tcx hir::FnDecl<'_>,
1162 ) {
1163let sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_norm_wip();
1164let sig = cx.tcx.instantiate_bound_regions_with_erased(sig);
11651166for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) {
1167let state = VisitorState::fn_entry_point(fn_mode, FnPos::Arg);
1168self.check_ffi_type(cx, *input_ty, state, input_hir.span, fn_mode, || {
1169let input_ty = Unnormalized::new_wip(*input_ty);
1170let mut visitor = ImproperCTypesVisitor::new(cx, input_ty, fn_mode);
1171 visitor.check_type(state, input_ty)
1172 });
1173 }
11741175if let hir::FnRetTy::Return(ret_hir) = decl.output {
1176let state = VisitorState::fn_entry_point(fn_mode, FnPos::Ret);
1177self.check_ffi_type(cx, sig.output(), state, ret_hir.span, fn_mode, || {
1178let output_ty = Unnormalized::new_wip(sig.output());
1179let mut visitor = ImproperCTypesVisitor::new(cx, output_ty, fn_mode);
1180visitor.check_type(state, output_ty)
1181 });
1182 }
1183 }
11841185fn process_ffi_result(
1186&self,
1187 cx: &LateContext<'tcx>,
1188 sp: Span,
1189 res: FfiResult<'tcx>,
1190 fn_mode: CItemKind,
1191 ) {
1192match res {
1193 FfiResult::FfiSafe => {}
1194 FfiResult::FfiPhantom(ty) => {
1195self.emit_ffi_unsafe_type_lint(
1196cx,
1197ty,
1198sp,
1199rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("composed only of `PhantomData`"))msg!("composed only of `PhantomData`"),
1200None,
1201fn_mode,
1202 );
1203 }
1204 FfiResult::FfiUnsafe { ty, reason, help } => {
1205self.emit_ffi_unsafe_type_lint(cx, ty, sp, reason, help, fn_mode);
1206 }
1207 }
1208 }
12091210fn 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 ) {
1219let lint = match fn_mode {
1220 CItemKind::Declaration => IMPROPER_CTYPES,
1221 CItemKind::Definition => IMPROPER_CTYPES_DEFINITIONS,
1222 };
1223let desc = match fn_mode {
1224 CItemKind::Declaration => "block",
1225 CItemKind::Definition => "fn",
1226 };
1227let span_note = if let ty::Adt(def, _) = ty.kind()
1228 && let Some(sp) = cx.tcx.hir_span_if_local(def.did())
1229 {
1230Some(sp)
1231 } else {
1232None1233 };
1234cx.emit_span_lint(lint, sp, ImproperCTypes { ty, desc, label: sp, help, note, span_note });
1235 }
1236}
12371238/// `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 {
1246fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, it: &hir::ForeignItem<'tcx>) {
1247let abi = cx.tcx.hir_get_foreign_abi(it.hir_id());
12481249match 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
1254if !abi.is_rustic_abi() {
1255self.check_foreign_fn(cx, CItemKind::Declaration, it.owner_id.def_id, sig.decl);
1256 } else {
1257self.check_fn_for_external_abi_fnptr(
1258cx,
1259 CItemKind::Declaration,
1260it.owner_id.def_id,
1261sig.decl,
1262 );
1263 }
1264 }
1265 hir::ForeignItemKind::Static(ty, _, _) if !abi.is_rustic_abi() => {
1266self.check_foreign_static(cx, it.owner_id, ty.span);
1267 }
1268 hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => (),
1269 }
1270 }
12711272fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
1273match item.kind {
1274 hir::ItemKind::Static(_, _, ty, _)
1275 | hir::ItemKind::Const(_, _, ty, _)
1276 | hir::ItemKind::TyAlias(_, _, ty) => {
1277self.check_type_for_external_abi_fnptr(
1278cx,
1279VisitorState::static_entry_point(),
1280ty,
1281cx.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
1286hir::ItemKind::Fn { .. } => {}
1287 hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) | hir::ItemKind::Enum(..) => {
1288// looking for extern FnPtr:s is delegated to `check_field_def`.
1289let adt_def: AdtDef<'tcx> = cx.tcx.adt_def(item.owner_id.to_def_id());
12901291if adt_def.repr().c() && !adt_def.repr().packed() && adt_def.repr().align.is_none()
1292 {
1293self.check_reprc_adt(cx, item, adt_def);
1294 }
1295 }
12961297// Doesn't define something that can contain a external type to be checked.
1298hir::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 }
13101311fn check_field_def(&mut self, cx: &LateContext<'tcx>, field: &'tcx hir::FieldDef<'tcx>) {
1312self.check_type_for_external_abi_fnptr(
1313cx,
1314VisitorState::static_entry_point(),
1315field.ty,
1316cx.tcx.type_of(field.def_id).instantiate_identity().skip_norm_wip(),
1317 CItemKind::Definition,
1318 );
1319 }
13201321fn 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 ) {
1330use hir::intravisit::FnKind;
13311332let abi = match kind {
1333 FnKind::ItemFn(_, _, header, ..) => header.abi,
1334 FnKind::Method(_, sig, ..) => sig.header.abi,
1335_ => return,
1336 };
13371338// 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
1341if !abi.is_rustic_abi() {
1342self.check_foreign_fn(cx, CItemKind::Definition, id, decl);
1343 } else {
1344self.check_fn_for_external_abi_fnptr(cx, CItemKind::Definition, id, decl);
1345 }
1346 }
1347}