1use std::iter;
2use std::ops::ControlFlow;
34use bitflags::bitflags;
5use rustc_abi::VariantIdx;
6use rustc_data_structures::fx::FxHashSet;
7use rustc_errors::DiagMessage;
8use rustc_hir::def::CtorKind;
9use rustc_hir::intravisit::VisitorExt;
10use rustc_hir::{selfas hir, AmbigArg};
11use rustc_middle::bug;
12use rustc_middle::ty::{
13self, Adt, AdtDef, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
14TypeVisitableExt,
15};
16use rustc_session::{declare_lint, declare_lint_pass};
17use rustc_span::def_id::LocalDefId;
18use rustc_span::{Span, sym};
19use rustc_target::spec::Os;
20use tracing::debug;
2122use super::repr_nullable_ptr;
23use crate::lints::{ImproperCTypes, UsesPowerAlignment};
24use crate::{LateContext, LateLintPass, LintContext, fluent_generatedas fluent};
2526#[doc =
r" The `improper_ctypes` lint detects incorrect use of types in foreign"]
#[doc = r" modules."]
#[doc = r""]
#[doc = r" ### Example"]
#[doc = r""]
#[doc = r" ```rust"]
#[doc = r#" unsafe extern "C" {"#]
#[doc = r" static STATIC: String;"]
#[doc = r" }"]
#[doc = r" ```"]
#[doc = r""]
#[doc = r" {{produces}}"]
#[doc = r""]
#[doc = r" ### Explanation"]
#[doc = r""]
#[doc =
r" The compiler has several checks to verify that types used in `extern`"]
#[doc = r" blocks are safe and follow certain rules to ensure proper"]
#[doc =
r" compatibility with the foreign interfaces. This lint is issued when it"]
#[doc =
r" detects a probable mistake in a definition. The lint usually should"]
#[doc =
r" provide a description of the issue, along with possibly a hint on how"]
#[doc = r" to resolve it."]
static IMPROPER_CTYPES: &::rustc_lint_defs::Lint =
&::rustc_lint_defs::Lint {
name: "IMPROPER_CTYPES",
default_level: ::rustc_lint_defs::Warn,
desc: "proper use of libc types in foreign modules",
is_externally_loaded: false,
..::rustc_lint_defs::Lint::default_fields_for_macro()
};declare_lint! {
27/// The `improper_ctypes` lint detects incorrect use of types in foreign
28 /// modules.
29 ///
30 /// ### Example
31 ///
32 /// ```rust
33 /// unsafe extern "C" {
34 /// static STATIC: String;
35 /// }
36 /// ```
37 ///
38 /// {{produces}}
39 ///
40 /// ### Explanation
41 ///
42 /// The compiler has several checks to verify that types used in `extern`
43 /// blocks are safe and follow certain rules to ensure proper
44 /// compatibility with the foreign interfaces. This lint is issued when it
45 /// detects a probable mistake in a definition. The lint usually should
46 /// provide a description of the issue, along with possibly a hint on how
47 /// to resolve it.
48IMPROPER_CTYPES,
49 Warn,
50"proper use of libc types in foreign modules"
51}5253#[doc = r" The `improper_ctypes_definitions` lint detects incorrect use of"]
#[doc = r" [`extern` function] definitions."]
#[doc = r""]
#[doc =
r" [`extern` function]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier"]
#[doc = r""]
#[doc = r" ### Example"]
#[doc = r""]
#[doc = r" ```rust"]
#[doc = r" # #![allow(unused)]"]
#[doc = r#" pub extern "C" fn str_type(p: &str) { }"#]
#[doc = r" ```"]
#[doc = r""]
#[doc = r" {{produces}}"]
#[doc = r""]
#[doc = r" ### Explanation"]
#[doc = r""]
#[doc =
r" There are many parameter and return types that may be specified in an"]
#[doc =
r" `extern` function that are not compatible with the given ABI. This"]
#[doc =
r" lint is an alert that these types should not be used. The lint usually"]
#[doc =
r" should provide a description of the issue, along with possibly a hint"]
#[doc = r" on how to resolve it."]
static IMPROPER_CTYPES_DEFINITIONS: &::rustc_lint_defs::Lint =
&::rustc_lint_defs::Lint {
name: "IMPROPER_CTYPES_DEFINITIONS",
default_level: ::rustc_lint_defs::Warn,
desc: "proper use of libc types in foreign item definitions",
is_externally_loaded: false,
..::rustc_lint_defs::Lint::default_fields_for_macro()
};declare_lint! {
54/// The `improper_ctypes_definitions` lint detects incorrect use of
55 /// [`extern` function] definitions.
56 ///
57 /// [`extern` function]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier
58 ///
59 /// ### Example
60 ///
61 /// ```rust
62 /// # #![allow(unused)]
63 /// pub extern "C" fn str_type(p: &str) { }
64 /// ```
65 ///
66 /// {{produces}}
67 ///
68 /// ### Explanation
69 ///
70 /// There are many parameter and return types that may be specified in an
71 /// `extern` function that are not compatible with the given ABI. This
72 /// lint is an alert that these types should not be used. The lint usually
73 /// should provide a description of the issue, along with possibly a hint
74 /// on how to resolve it.
75IMPROPER_CTYPES_DEFINITIONS,
76 Warn,
77"proper use of libc types in foreign item definitions"
78}7980#[doc = r" The `uses_power_alignment` lint detects specific `repr(C)`"]
#[doc = r" aggregates on AIX."]
#[doc =
r#" In its platform C ABI, AIX uses the "power" (as in PowerPC) alignment"#]
#[doc =
r" rule (detailed in https://www.ibm.com/docs/en/xl-c-and-cpp-aix/16.1?topic=data-using-alignment-modes#alignment),"]
#[doc = r" which can also be set for XLC by `#pragma align(power)` or"]
#[doc = r" `-qalign=power`. Aggregates with a floating-point type as the"]
#[doc =
r#" recursively first field (as in "at offset 0") modify the layout of"#]
#[doc =
r" *subsequent* fields of the associated structs to use an alignment value"]
#[doc = r" where the floating-point type is aligned on a 4-byte boundary."]
#[doc = r""]
#[doc =
r" Effectively, subsequent floating-point fields act as-if they are `repr(packed(4))`. This"]
#[doc =
r" would be unsound to do in a `repr(C)` type without all the restrictions that come with"]
#[doc =
r" `repr(packed)`. Rust instead chooses a layout that maintains soundness of Rust code, at the"]
#[doc = r" expense of incompatibility with C code."]
#[doc = r""]
#[doc = r" ### Example"]
#[doc = r""]
#[doc = r" ```rust,ignore (fails on non-powerpc64-ibm-aix)"]
#[doc = r" #[repr(C)]"]
#[doc = r" pub struct Floats {"]
#[doc = r" a: f64,"]
#[doc = r" b: u8,"]
#[doc = r" c: f64,"]
#[doc = r" }"]
#[doc = r" ```"]
#[doc = r""]
#[doc = r" This will produce:"]
#[doc = r""]
#[doc = r" ```text"]
#[doc =
r" warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type"]
#[doc = r" --> <source>:5:3"]
#[doc = r" |"]
#[doc = r" 5 | c: f64,"]
#[doc = r" | ^^^^^^"]
#[doc = r" |"]
#[doc = r" = note: `#[warn(uses_power_alignment)]` on by default"]
#[doc = r" ```"]
#[doc = r""]
#[doc = r" ### Explanation"]
#[doc = r""]
#[doc = r" The power alignment rule specifies that the above struct has the"]
#[doc = r" following alignment:"]
#[doc = r" - offset_of!(Floats, a) == 0"]
#[doc = r" - offset_of!(Floats, b) == 8"]
#[doc = r" - offset_of!(Floats, c) == 12"]
#[doc = r""]
#[doc =
r" However, Rust currently aligns `c` at `offset_of!(Floats, c) == 16`."]
#[doc =
r" Using offset 12 would be unsound since `f64` generally must be 8-aligned on this target."]
#[doc = r" Thus, a warning is produced for the above struct."]
static USES_POWER_ALIGNMENT: &::rustc_lint_defs::Lint =
&::rustc_lint_defs::Lint {
name: "USES_POWER_ALIGNMENT",
default_level: ::rustc_lint_defs::Warn,
desc: "Structs do not follow the power alignment rule under repr(C)",
is_externally_loaded: false,
..::rustc_lint_defs::Lint::default_fields_for_macro()
};declare_lint! {
81/// The `uses_power_alignment` lint detects specific `repr(C)`
82 /// aggregates on AIX.
83 /// In its platform C ABI, AIX uses the "power" (as in PowerPC) alignment
84 /// rule (detailed in https://www.ibm.com/docs/en/xl-c-and-cpp-aix/16.1?topic=data-using-alignment-modes#alignment),
85 /// which can also be set for XLC by `#pragma align(power)` or
86 /// `-qalign=power`. Aggregates with a floating-point type as the
87 /// recursively first field (as in "at offset 0") modify the layout of
88 /// *subsequent* fields of the associated structs to use an alignment value
89 /// where the floating-point type is aligned on a 4-byte boundary.
90 ///
91 /// Effectively, subsequent floating-point fields act as-if they are `repr(packed(4))`. This
92 /// would be unsound to do in a `repr(C)` type without all the restrictions that come with
93 /// `repr(packed)`. Rust instead chooses a layout that maintains soundness of Rust code, at the
94 /// expense of incompatibility with C code.
95 ///
96 /// ### Example
97 ///
98 /// ```rust,ignore (fails on non-powerpc64-ibm-aix)
99 /// #[repr(C)]
100 /// pub struct Floats {
101 /// a: f64,
102 /// b: u8,
103 /// c: f64,
104 /// }
105 /// ```
106 ///
107 /// This will produce:
108 ///
109 /// ```text
110 /// warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
111 /// --> <source>:5:3
112 /// |
113 /// 5 | c: f64,
114 /// | ^^^^^^
115 /// |
116 /// = note: `#[warn(uses_power_alignment)]` on by default
117 /// ```
118 ///
119 /// ### Explanation
120 ///
121 /// The power alignment rule specifies that the above struct has the
122 /// following alignment:
123 /// - offset_of!(Floats, a) == 0
124 /// - offset_of!(Floats, b) == 8
125 /// - offset_of!(Floats, c) == 12
126 ///
127 /// However, Rust currently aligns `c` at `offset_of!(Floats, c) == 16`.
128 /// Using offset 12 would be unsound since `f64` generally must be 8-aligned on this target.
129 /// Thus, a warning is produced for the above struct.
130USES_POWER_ALIGNMENT,
131 Warn,
132"Structs do not follow the power alignment rule under repr(C)"
133}134135pub struct ImproperCTypesLint;
#[automatically_derived]
impl ::core::marker::Copy for ImproperCTypesLint { }
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for ImproperCTypesLint { }
#[automatically_derived]
impl ::core::clone::Clone for ImproperCTypesLint {
#[inline]
fn clone(&self) -> ImproperCTypesLint { *self }
}
impl ::rustc_lint_defs::LintPass for ImproperCTypesLint {
fn name(&self) -> &'static str { "ImproperCTypesLint" }
fn get_lints(&self) -> ::rustc_lint_defs::LintVec {
<[_]>::into_vec(::alloc::boxed::box_new([IMPROPER_CTYPES,
IMPROPER_CTYPES_DEFINITIONS, USES_POWER_ALIGNMENT]))
}
}
impl ImproperCTypesLint {
#[allow(unused)]
pub fn lint_vec() -> ::rustc_lint_defs::LintVec {
<[_]>::into_vec(::alloc::boxed::box_new([IMPROPER_CTYPES,
IMPROPER_CTYPES_DEFINITIONS, USES_POWER_ALIGNMENT]))
}
}declare_lint_pass!(ImproperCTypesLint => [
136 IMPROPER_CTYPES,
137 IMPROPER_CTYPES_DEFINITIONS,
138 USES_POWER_ALIGNMENT
139]);
140141/// Check a variant of a non-exhaustive enum for improper ctypes
142///
143/// We treat `#[non_exhaustive] enum` as "ensure that code will compile if new variants are added".
144/// This includes linting, on a best-effort basis. There are valid additions that are unlikely.
145///
146/// Adding a data-carrying variant to an existing C-like enum that is passed to C is "unlikely",
147/// so we don't need the lint to account for it.
148/// e.g. going from enum Foo { A, B, C } to enum Foo { A, B, C, D(u32) }.
149pub(crate) fn check_non_exhaustive_variant(
150 non_exhaustive_variant_list: bool,
151 variant: &ty::VariantDef,
152) -> ControlFlow<DiagMessage, ()> {
153// non_exhaustive suggests it is possible that someone might break ABI
154 // see: https://github.com/rust-lang/rust/issues/44109#issuecomment-537583344
155 // so warn on complex enums being used outside their crate
156if non_exhaustive_variant_list {
157// which is why we only warn about really_tagged_union reprs from https://rust.tf/rfc2195
158 // with an enum like `#[repr(u8)] enum Enum { A(DataA), B(DataB), }`
159 // but exempt enums with unit ctors like C's (e.g. from rust-bindgen)
160if variant_has_complex_ctor(variant) {
161return ControlFlow::Break(fluent::lint_improper_ctypes_non_exhaustive);
162 }
163 }
164165if variant.field_list_has_applicable_non_exhaustive() {
166return ControlFlow::Break(fluent::lint_improper_ctypes_non_exhaustive_variant);
167 }
168169 ControlFlow::Continue(())
170}
171172fn variant_has_complex_ctor(variant: &ty::VariantDef) -> bool {
173// CtorKind::Const means a "unit" ctor
174 !#[allow(non_exhaustive_omitted_patterns)] match variant.ctor_kind() {
Some(CtorKind::Const) => true,
_ => false,
}matches!(variant.ctor_kind(), Some(CtorKind::Const))175}
176177/// Per-struct-field function that checks if a struct definition follows
178/// the Power alignment Rule (see the `check_struct_for_power_alignment` function).
179fn check_arg_for_power_alignment<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
180let tcx = cx.tcx;
181if !(tcx.sess.target.os == Os::Aix) {
::core::panicking::panic("assertion failed: tcx.sess.target.os == Os::Aix")
};assert!(tcx.sess.target.os == Os::Aix);
182// Structs (under repr(C)) follow the power alignment rule if:
183 // - the first field of the struct is a floating-point type that
184 // is greater than 4-bytes, or
185 // - the first field of the struct is an aggregate whose
186 // recursively first field is a floating-point type greater than
187 // 4 bytes.
188if ty.is_floating_point() && ty.primitive_size(tcx).bytes() > 4 {
189return true;
190 } else if let Adt(adt_def, _) = ty.kind()
191 && adt_def.is_struct()
192 && adt_def.repr().c()
193 && !adt_def.repr().packed()
194 && adt_def.repr().align.is_none()
195 {
196let struct_variant = adt_def.variant(VariantIdx::ZERO);
197// Within a nested struct, all fields are examined to correctly
198 // report if any fields after the nested struct within the
199 // original struct are misaligned.
200for struct_field in &struct_variant.fields {
201let field_ty = tcx.type_of(struct_field.did).instantiate_identity();
202if check_arg_for_power_alignment(cx, field_ty) {
203return true;
204 }
205 }
206 }
207return false;
208}
209210/// Check a struct definition for respect of the Power alignment Rule (as in PowerPC),
211/// which should be respected in the "aix" target OS.
212/// To do so, we must follow one of the two following conditions:
213/// - The first field of the struct must be floating-point type that
214/// is greater than 4-bytes.
215/// - The first field of the struct must be an aggregate whose
216/// recursively first field is a floating-point type greater than
217/// 4 bytes.
218fn check_struct_for_power_alignment<'tcx>(
219 cx: &LateContext<'tcx>,
220 item: &'tcx hir::Item<'tcx>,
221 adt_def: AdtDef<'tcx>,
222) {
223let tcx = cx.tcx;
224225// Only consider structs (not enums or unions) on AIX.
226if tcx.sess.target.os != Os::Aix || !adt_def.is_struct() {
227return;
228 }
229230// The struct must be repr(C), but ignore it if it explicitly specifies its alignment with
231 // either `align(N)` or `packed(N)`.
232if adt_def.repr().c() && !adt_def.repr().packed() && adt_def.repr().align.is_none() {
233let struct_variant_data = item.expect_struct().2;
234for field_def in struct_variant_data.fields().iter().skip(1) {
235// Struct fields (after the first field) are checked for the
236 // power alignment rule, as fields after the first are likely
237 // to be the fields that are misaligned.
238let ty = tcx.type_of(field_def.def_id).instantiate_identity();
239if check_arg_for_power_alignment(cx, ty) {
240 cx.emit_span_lint(USES_POWER_ALIGNMENT, field_def.span, UsesPowerAlignment);
241 }
242 }
243 }
244}
245246#[derive(#[automatically_derived]
impl ::core::clone::Clone for CItemKind {
#[inline]
fn clone(&self) -> CItemKind { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for CItemKind { }Copy)]
247enum CItemKind {
248 Declaration,
249 Definition,
250}
251252enum FfiResult<'tcx> {
253 FfiSafe,
254 FfiPhantom(Ty<'tcx>),
255 FfiUnsafe { ty: Ty<'tcx>, reason: DiagMessage, help: Option<DiagMessage> },
256}
257258/// The result when a type has been checked but perhaps not completely. `None` indicates that
259/// FFI safety/unsafety has not yet been determined, `Some(res)` indicates that the safety/unsafety
260/// in the `FfiResult` is final.
261type PartialFfiResult<'tcx> = Option<FfiResult<'tcx>>;
262263bitflags! {
264#[derive(#[automatically_derived]
impl ::core::clone::Clone for VisitorState {
#[inline]
fn clone(&self) -> VisitorState {
let _:
::core::clone::AssertParamIsClone<<VisitorState as
::bitflags::__private::PublicFlags>::Internal>;
*self
}
}
impl VisitorState {
#[doc = r" For use in (externally-linked) static variables."]
#[allow(deprecated, non_upper_case_globals,)]
pub const STATIC: Self = Self::from_bits_retain(0b000001);
#[doc = r" For use in functions in general."]
#[allow(deprecated, non_upper_case_globals,)]
pub const FUNC: Self = Self::from_bits_retain(0b000010);
#[doc =
r" For variables in function returns (implicitly: not for static variables)."]
#[allow(deprecated, non_upper_case_globals,)]
pub const FN_RETURN: Self = Self::from_bits_retain(0b000100);
#[doc =
r" For variables in functions/variables which are defined in rust."]
#[allow(deprecated, non_upper_case_globals,)]
pub const DEFINED: Self = Self::from_bits_retain(0b001000);
#[doc = r" For times where we are only defining the type of something"]
#[doc = r" (struct/enum/union definitions, FnPtrs)."]
#[allow(deprecated, non_upper_case_globals,)]
pub const THEORETICAL: Self = Self::from_bits_retain(0b010000);
}
impl ::bitflags::Flags for VisitorState {
const FLAGS: &'static [::bitflags::Flag<VisitorState>] =
&[{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("STATIC", VisitorState::STATIC)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("FUNC", VisitorState::FUNC)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("FN_RETURN", VisitorState::FN_RETURN)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("DEFINED", VisitorState::DEFINED)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("THEORETICAL",
VisitorState::THEORETICAL)
}];
type Bits = u8;
fn bits(&self) -> u8 { VisitorState::bits(self) }
fn from_bits_retain(bits: u8) -> VisitorState {
VisitorState::from_bits_retain(bits)
}
}
#[allow(dead_code, deprecated, unused_doc_comments, unused_attributes,
unused_mut, unused_imports, non_upper_case_globals, clippy ::
assign_op_pattern, clippy :: indexing_slicing, clippy :: same_name_method,
clippy :: iter_without_into_iter,)]
const _: () =
{
#[repr(transparent)]
struct InternalBitFlags(u8);
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for InternalBitFlags { }
#[automatically_derived]
impl ::core::clone::Clone for InternalBitFlags {
#[inline]
fn clone(&self) -> InternalBitFlags {
let _: ::core::clone::AssertParamIsClone<u8>;
*self
}
}
#[automatically_derived]
impl ::core::marker::Copy for InternalBitFlags { }
#[automatically_derived]
impl ::core::marker::StructuralPartialEq for InternalBitFlags { }
#[automatically_derived]
impl ::core::cmp::PartialEq for InternalBitFlags {
#[inline]
fn eq(&self, other: &InternalBitFlags) -> bool {
self.0 == other.0
}
}
#[automatically_derived]
impl ::core::cmp::Eq for InternalBitFlags {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<u8>;
}
}
#[automatically_derived]
impl ::core::cmp::PartialOrd for InternalBitFlags {
#[inline]
fn partial_cmp(&self, other: &InternalBitFlags)
-> ::core::option::Option<::core::cmp::Ordering> {
::core::cmp::PartialOrd::partial_cmp(&self.0, &other.0)
}
}
#[automatically_derived]
impl ::core::cmp::Ord for InternalBitFlags {
#[inline]
fn cmp(&self, other: &InternalBitFlags) -> ::core::cmp::Ordering {
::core::cmp::Ord::cmp(&self.0, &other.0)
}
}
#[automatically_derived]
impl ::core::hash::Hash for InternalBitFlags {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
::core::hash::Hash::hash(&self.0, state)
}
}
impl ::bitflags::__private::PublicFlags for VisitorState {
type Primitive = u8;
type Internal = InternalBitFlags;
}
impl ::bitflags::__private::core::default::Default for
InternalBitFlags {
#[inline]
fn default() -> Self { InternalBitFlags::empty() }
}
impl ::bitflags::__private::core::fmt::Debug for InternalBitFlags {
fn fmt(&self,
f: &mut ::bitflags::__private::core::fmt::Formatter<'_>)
-> ::bitflags::__private::core::fmt::Result {
if self.is_empty() {
f.write_fmt(format_args!("{0:#x}",
<u8 as ::bitflags::Bits>::EMPTY))
} else {
::bitflags::__private::core::fmt::Display::fmt(self, f)
}
}
}
impl ::bitflags::__private::core::fmt::Display for InternalBitFlags {
fn fmt(&self,
f: &mut ::bitflags::__private::core::fmt::Formatter<'_>)
-> ::bitflags::__private::core::fmt::Result {
::bitflags::parser::to_writer(&VisitorState(*self), f)
}
}
impl ::bitflags::__private::core::str::FromStr for InternalBitFlags {
type Err = ::bitflags::parser::ParseError;
fn from_str(s: &str)
->
::bitflags::__private::core::result::Result<Self,
Self::Err> {
::bitflags::parser::from_str::<VisitorState>(s).map(|flags|
flags.0)
}
}
impl ::bitflags::__private::core::convert::AsRef<u8> for
InternalBitFlags {
fn as_ref(&self) -> &u8 { &self.0 }
}
impl ::bitflags::__private::core::convert::From<u8> for
InternalBitFlags {
fn from(bits: u8) -> Self { Self::from_bits_retain(bits) }
}
#[allow(dead_code, deprecated, unused_attributes)]
impl InternalBitFlags {
/// Get a flags value with all bits unset.
#[inline]
pub const fn empty() -> Self {
Self(<u8 as ::bitflags::Bits>::EMPTY)
}
/// Get a flags value with all known bits set.
#[inline]
pub const fn all() -> Self {
let mut truncated = <u8 as ::bitflags::Bits>::EMPTY;
let mut i = 0;
{
{
let flag =
<VisitorState as
::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<VisitorState as
::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<VisitorState as
::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<VisitorState as
::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<VisitorState as
::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
let _ = i;
Self(truncated)
}
/// Get the underlying bits value.
///
/// The returned value is exactly the bits set in this flags value.
#[inline]
pub const fn bits(&self) -> u8 { self.0 }
/// Convert from a bits value.
///
/// This method will return `None` if any unknown bits are set.
#[inline]
pub const fn from_bits(bits: u8)
-> ::bitflags::__private::core::option::Option<Self> {
let truncated = Self::from_bits_truncate(bits).0;
if truncated == bits {
::bitflags::__private::core::option::Option::Some(Self(bits))
} else { ::bitflags::__private::core::option::Option::None }
}
/// Convert from a bits value, unsetting any unknown bits.
#[inline]
pub const fn from_bits_truncate(bits: u8) -> Self {
Self(bits & Self::all().0)
}
/// Convert from a bits value exactly.
#[inline]
pub const fn from_bits_retain(bits: u8) -> Self { Self(bits) }
/// Get a flags value with the bits of a flag with the given name set.
///
/// This method will return `None` if `name` is empty or doesn't
/// correspond to any named flag.
#[inline]
pub fn from_name(name: &str)
-> ::bitflags::__private::core::option::Option<Self> {
{
if name == "STATIC" {
return ::bitflags::__private::core::option::Option::Some(Self(VisitorState::STATIC.bits()));
}
};
;
{
if name == "FUNC" {
return ::bitflags::__private::core::option::Option::Some(Self(VisitorState::FUNC.bits()));
}
};
;
{
if name == "FN_RETURN" {
return ::bitflags::__private::core::option::Option::Some(Self(VisitorState::FN_RETURN.bits()));
}
};
;
{
if name == "DEFINED" {
return ::bitflags::__private::core::option::Option::Some(Self(VisitorState::DEFINED.bits()));
}
};
;
{
if name == "THEORETICAL" {
return ::bitflags::__private::core::option::Option::Some(Self(VisitorState::THEORETICAL.bits()));
}
};
;
let _ = name;
::bitflags::__private::core::option::Option::None
}
/// Whether all bits in this flags value are unset.
#[inline]
pub const fn is_empty(&self) -> bool {
self.0 == <u8 as ::bitflags::Bits>::EMPTY
}
/// Whether all known bits in this flags value are set.
#[inline]
pub const fn is_all(&self) -> bool {
Self::all().0 | self.0 == self.0
}
/// Whether any set bits in a source flags value are also set in a target flags value.
#[inline]
pub const fn intersects(&self, other: Self) -> bool {
self.0 & other.0 != <u8 as ::bitflags::Bits>::EMPTY
}
/// Whether all set bits in a source flags value are also set in a target flags value.
#[inline]
pub const fn contains(&self, other: Self) -> bool {
self.0 & other.0 == other.0
}
/// The bitwise or (`|`) of the bits in two flags values.
#[inline]
pub fn insert(&mut self, other: Self) {
*self = Self(self.0).union(other);
}
/// The intersection of a source flags value with the complement of a target flags
/// value (`&!`).
///
/// This method is not equivalent to `self & !other` when `other` has unknown bits set.
/// `remove` won't truncate `other`, but the `!` operator will.
#[inline]
pub fn remove(&mut self, other: Self) {
*self = Self(self.0).difference(other);
}
/// The bitwise exclusive-or (`^`) of the bits in two flags values.
#[inline]
pub fn toggle(&mut self, other: Self) {
*self = Self(self.0).symmetric_difference(other);
}
/// Call `insert` when `value` is `true` or `remove` when `value` is `false`.
#[inline]
pub fn set(&mut self, other: Self, value: bool) {
if value { self.insert(other); } else { self.remove(other); }
}
/// The bitwise and (`&`) of the bits in two flags values.
#[inline]
#[must_use]
pub const fn intersection(self, other: Self) -> Self {
Self(self.0 & other.0)
}
/// The bitwise or (`|`) of the bits in two flags values.
#[inline]
#[must_use]
pub const fn union(self, other: Self) -> Self {
Self(self.0 | other.0)
}
/// The intersection of a source flags value with the complement of a target flags
/// value (`&!`).
///
/// This method is not equivalent to `self & !other` when `other` has unknown bits set.
/// `difference` won't truncate `other`, but the `!` operator will.
#[inline]
#[must_use]
pub const fn difference(self, other: Self) -> Self {
Self(self.0 & !other.0)
}
/// The bitwise exclusive-or (`^`) of the bits in two flags values.
#[inline]
#[must_use]
pub const fn symmetric_difference(self, other: Self) -> Self {
Self(self.0 ^ other.0)
}
/// The bitwise negation (`!`) of the bits in a flags value, truncating the result.
#[inline]
#[must_use]
pub const fn complement(self) -> Self {
Self::from_bits_truncate(!self.0)
}
}
impl ::bitflags::__private::core::fmt::Binary for InternalBitFlags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::Binary::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::fmt::Octal for InternalBitFlags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::Octal::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::fmt::LowerHex for InternalBitFlags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::LowerHex::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::fmt::UpperHex for InternalBitFlags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::UpperHex::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::ops::BitOr for InternalBitFlags {
type Output = Self;
/// The bitwise or (`|`) of the bits in two flags values.
#[inline]
fn bitor(self, other: InternalBitFlags) -> Self {
self.union(other)
}
}
impl ::bitflags::__private::core::ops::BitOrAssign for
InternalBitFlags {
/// The bitwise or (`|`) of the bits in two flags values.
#[inline]
fn bitor_assign(&mut self, other: Self) { self.insert(other); }
}
impl ::bitflags::__private::core::ops::BitXor for InternalBitFlags {
type Output = Self;
/// The bitwise exclusive-or (`^`) of the bits in two flags values.
#[inline]
fn bitxor(self, other: Self) -> Self {
self.symmetric_difference(other)
}
}
impl ::bitflags::__private::core::ops::BitXorAssign for
InternalBitFlags {
/// The bitwise exclusive-or (`^`) of the bits in two flags values.
#[inline]
fn bitxor_assign(&mut self, other: Self) { self.toggle(other); }
}
impl ::bitflags::__private::core::ops::BitAnd for InternalBitFlags {
type Output = Self;
/// The bitwise and (`&`) of the bits in two flags values.
#[inline]
fn bitand(self, other: Self) -> Self { self.intersection(other) }
}
impl ::bitflags::__private::core::ops::BitAndAssign for
InternalBitFlags {
/// The bitwise and (`&`) of the bits in two flags values.
#[inline]
fn bitand_assign(&mut self, other: Self) {
*self =
Self::from_bits_retain(self.bits()).intersection(other);
}
}
impl ::bitflags::__private::core::ops::Sub for InternalBitFlags {
type Output = Self;
/// The intersection of a source flags value with the complement of a target flags value (`&!`).
///
/// This method is not equivalent to `self & !other` when `other` has unknown bits set.
/// `difference` won't truncate `other`, but the `!` operator will.
#[inline]
fn sub(self, other: Self) -> Self { self.difference(other) }
}
impl ::bitflags::__private::core::ops::SubAssign for InternalBitFlags
{
/// The intersection of a source flags value with the complement of a target flags value (`&!`).
///
/// This method is not equivalent to `self & !other` when `other` has unknown bits set.
/// `difference` won't truncate `other`, but the `!` operator will.
#[inline]
fn sub_assign(&mut self, other: Self) { self.remove(other); }
}
impl ::bitflags::__private::core::ops::Not for InternalBitFlags {
type Output = Self;
/// The bitwise negation (`!`) of the bits in a flags value, truncating the result.
#[inline]
fn not(self) -> Self { self.complement() }
}
impl ::bitflags::__private::core::iter::Extend<InternalBitFlags> for
InternalBitFlags {
/// The bitwise or (`|`) of the bits in each flags value.
fn extend<T: ::bitflags::__private::core::iter::IntoIterator<Item
= Self>>(&mut self, iterator: T) {
for item in iterator { self.insert(item) }
}
}
impl ::bitflags::__private::core::iter::FromIterator<InternalBitFlags>
for InternalBitFlags {
/// The bitwise or (`|`) of the bits in each flags value.
fn from_iter<T: ::bitflags::__private::core::iter::IntoIterator<Item
= Self>>(iterator: T) -> Self {
use ::bitflags::__private::core::iter::Extend;
let mut result = Self::empty();
result.extend(iterator);
result
}
}
impl InternalBitFlags {
/// Yield a set of contained flags values.
///
/// Each yielded flags value will correspond to a defined named flag. Any unknown bits
/// will be yielded together as a final flags value.
#[inline]
pub const fn iter(&self) -> ::bitflags::iter::Iter<VisitorState> {
::bitflags::iter::Iter::__private_const_new(<VisitorState as
::bitflags::Flags>::FLAGS,
VisitorState::from_bits_retain(self.bits()),
VisitorState::from_bits_retain(self.bits()))
}
/// Yield a set of contained named flags values.
///
/// This method is like [`iter`](#method.iter), except only yields bits in contained named flags.
/// Any unknown bits, or bits not corresponding to a contained flag will not be yielded.
#[inline]
pub const fn iter_names(&self)
-> ::bitflags::iter::IterNames<VisitorState> {
::bitflags::iter::IterNames::__private_const_new(<VisitorState
as ::bitflags::Flags>::FLAGS,
VisitorState::from_bits_retain(self.bits()),
VisitorState::from_bits_retain(self.bits()))
}
}
impl ::bitflags::__private::core::iter::IntoIterator for
InternalBitFlags {
type Item = VisitorState;
type IntoIter = ::bitflags::iter::Iter<VisitorState>;
fn into_iter(self) -> Self::IntoIter { self.iter() }
}
impl InternalBitFlags {
/// Returns a mutable reference to the raw value of the flags currently stored.
#[inline]
pub fn bits_mut(&mut self) -> &mut u8 { &mut self.0 }
}
#[allow(dead_code, deprecated, unused_attributes)]
impl VisitorState {
/// Get a flags value with all bits unset.
#[inline]
pub const fn empty() -> Self { Self(InternalBitFlags::empty()) }
/// Get a flags value with all known bits set.
#[inline]
pub const fn all() -> Self { Self(InternalBitFlags::all()) }
/// Get the underlying bits value.
///
/// The returned value is exactly the bits set in this flags value.
#[inline]
pub const fn bits(&self) -> u8 { self.0.bits() }
/// Convert from a bits value.
///
/// This method will return `None` if any unknown bits are set.
#[inline]
pub const fn from_bits(bits: u8)
-> ::bitflags::__private::core::option::Option<Self> {
match InternalBitFlags::from_bits(bits) {
::bitflags::__private::core::option::Option::Some(bits) =>
::bitflags::__private::core::option::Option::Some(Self(bits)),
::bitflags::__private::core::option::Option::None =>
::bitflags::__private::core::option::Option::None,
}
}
/// Convert from a bits value, unsetting any unknown bits.
#[inline]
pub const fn from_bits_truncate(bits: u8) -> Self {
Self(InternalBitFlags::from_bits_truncate(bits))
}
/// Convert from a bits value exactly.
#[inline]
pub const fn from_bits_retain(bits: u8) -> Self {
Self(InternalBitFlags::from_bits_retain(bits))
}
/// Get a flags value with the bits of a flag with the given name set.
///
/// This method will return `None` if `name` is empty or doesn't
/// correspond to any named flag.
#[inline]
pub fn from_name(name: &str)
-> ::bitflags::__private::core::option::Option<Self> {
match InternalBitFlags::from_name(name) {
::bitflags::__private::core::option::Option::Some(bits) =>
::bitflags::__private::core::option::Option::Some(Self(bits)),
::bitflags::__private::core::option::Option::None =>
::bitflags::__private::core::option::Option::None,
}
}
/// Whether all bits in this flags value are unset.
#[inline]
pub const fn is_empty(&self) -> bool { self.0.is_empty() }
/// Whether all known bits in this flags value are set.
#[inline]
pub const fn is_all(&self) -> bool { self.0.is_all() }
/// Whether any set bits in a source flags value are also set in a target flags value.
#[inline]
pub const fn intersects(&self, other: Self) -> bool {
self.0.intersects(other.0)
}
/// Whether all set bits in a source flags value are also set in a target flags value.
#[inline]
pub const fn contains(&self, other: Self) -> bool {
self.0.contains(other.0)
}
/// The bitwise or (`|`) of the bits in two flags values.
#[inline]
pub fn insert(&mut self, other: Self) { self.0.insert(other.0) }
/// The intersection of a source flags value with the complement of a target flags
/// value (`&!`).
///
/// This method is not equivalent to `self & !other` when `other` has unknown bits set.
/// `remove` won't truncate `other`, but the `!` operator will.
#[inline]
pub fn remove(&mut self, other: Self) { self.0.remove(other.0) }
/// The bitwise exclusive-or (`^`) of the bits in two flags values.
#[inline]
pub fn toggle(&mut self, other: Self) { self.0.toggle(other.0) }
/// Call `insert` when `value` is `true` or `remove` when `value` is `false`.
#[inline]
pub fn set(&mut self, other: Self, value: bool) {
self.0.set(other.0, value)
}
/// The bitwise and (`&`) of the bits in two flags values.
#[inline]
#[must_use]
pub const fn intersection(self, other: Self) -> Self {
Self(self.0.intersection(other.0))
}
/// The bitwise or (`|`) of the bits in two flags values.
#[inline]
#[must_use]
pub const fn union(self, other: Self) -> Self {
Self(self.0.union(other.0))
}
/// The intersection of a source flags value with the complement of a target flags
/// value (`&!`).
///
/// This method is not equivalent to `self & !other` when `other` has unknown bits set.
/// `difference` won't truncate `other`, but the `!` operator will.
#[inline]
#[must_use]
pub const fn difference(self, other: Self) -> Self {
Self(self.0.difference(other.0))
}
/// The bitwise exclusive-or (`^`) of the bits in two flags values.
#[inline]
#[must_use]
pub const fn symmetric_difference(self, other: Self) -> Self {
Self(self.0.symmetric_difference(other.0))
}
/// The bitwise negation (`!`) of the bits in a flags value, truncating the result.
#[inline]
#[must_use]
pub const fn complement(self) -> Self {
Self(self.0.complement())
}
}
impl ::bitflags::__private::core::fmt::Binary for VisitorState {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::Binary::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::fmt::Octal for VisitorState {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::Octal::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::fmt::LowerHex for VisitorState {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::LowerHex::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::fmt::UpperHex for VisitorState {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::UpperHex::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::ops::BitOr for VisitorState {
type Output = Self;
/// The bitwise or (`|`) of the bits in two flags values.
#[inline]
fn bitor(self, other: VisitorState) -> Self { self.union(other) }
}
impl ::bitflags::__private::core::ops::BitOrAssign for VisitorState {
/// The bitwise or (`|`) of the bits in two flags values.
#[inline]
fn bitor_assign(&mut self, other: Self) { self.insert(other); }
}
impl ::bitflags::__private::core::ops::BitXor for VisitorState {
type Output = Self;
/// The bitwise exclusive-or (`^`) of the bits in two flags values.
#[inline]
fn bitxor(self, other: Self) -> Self {
self.symmetric_difference(other)
}
}
impl ::bitflags::__private::core::ops::BitXorAssign for VisitorState {
/// The bitwise exclusive-or (`^`) of the bits in two flags values.
#[inline]
fn bitxor_assign(&mut self, other: Self) { self.toggle(other); }
}
impl ::bitflags::__private::core::ops::BitAnd for VisitorState {
type Output = Self;
/// The bitwise and (`&`) of the bits in two flags values.
#[inline]
fn bitand(self, other: Self) -> Self { self.intersection(other) }
}
impl ::bitflags::__private::core::ops::BitAndAssign for VisitorState {
/// The bitwise and (`&`) of the bits in two flags values.
#[inline]
fn bitand_assign(&mut self, other: Self) {
*self =
Self::from_bits_retain(self.bits()).intersection(other);
}
}
impl ::bitflags::__private::core::ops::Sub for VisitorState {
type Output = Self;
/// The intersection of a source flags value with the complement of a target flags value (`&!`).
///
/// This method is not equivalent to `self & !other` when `other` has unknown bits set.
/// `difference` won't truncate `other`, but the `!` operator will.
#[inline]
fn sub(self, other: Self) -> Self { self.difference(other) }
}
impl ::bitflags::__private::core::ops::SubAssign for VisitorState {
/// The intersection of a source flags value with the complement of a target flags value (`&!`).
///
/// This method is not equivalent to `self & !other` when `other` has unknown bits set.
/// `difference` won't truncate `other`, but the `!` operator will.
#[inline]
fn sub_assign(&mut self, other: Self) { self.remove(other); }
}
impl ::bitflags::__private::core::ops::Not for VisitorState {
type Output = Self;
/// The bitwise negation (`!`) of the bits in a flags value, truncating the result.
#[inline]
fn not(self) -> Self { self.complement() }
}
impl ::bitflags::__private::core::iter::Extend<VisitorState> for
VisitorState {
/// The bitwise or (`|`) of the bits in each flags value.
fn extend<T: ::bitflags::__private::core::iter::IntoIterator<Item
= Self>>(&mut self, iterator: T) {
for item in iterator { self.insert(item) }
}
}
impl ::bitflags::__private::core::iter::FromIterator<VisitorState> for
VisitorState {
/// The bitwise or (`|`) of the bits in each flags value.
fn from_iter<T: ::bitflags::__private::core::iter::IntoIterator<Item
= Self>>(iterator: T) -> Self {
use ::bitflags::__private::core::iter::Extend;
let mut result = Self::empty();
result.extend(iterator);
result
}
}
impl VisitorState {
/// Yield a set of contained flags values.
///
/// Each yielded flags value will correspond to a defined named flag. Any unknown bits
/// will be yielded together as a final flags value.
#[inline]
pub const fn iter(&self) -> ::bitflags::iter::Iter<VisitorState> {
::bitflags::iter::Iter::__private_const_new(<VisitorState as
::bitflags::Flags>::FLAGS,
VisitorState::from_bits_retain(self.bits()),
VisitorState::from_bits_retain(self.bits()))
}
/// Yield a set of contained named flags values.
///
/// This method is like [`iter`](#method.iter), except only yields bits in contained named flags.
/// Any unknown bits, or bits not corresponding to a contained flag will not be yielded.
#[inline]
pub const fn iter_names(&self)
-> ::bitflags::iter::IterNames<VisitorState> {
::bitflags::iter::IterNames::__private_const_new(<VisitorState
as ::bitflags::Flags>::FLAGS,
VisitorState::from_bits_retain(self.bits()),
VisitorState::from_bits_retain(self.bits()))
}
}
impl ::bitflags::__private::core::iter::IntoIterator for VisitorState
{
type Item = VisitorState;
type IntoIter = ::bitflags::iter::Iter<VisitorState>;
fn into_iter(self) -> Self::IntoIter { self.iter() }
}
};Clone, #[automatically_derived]
impl ::core::marker::Copy for VisitorState { }Copy, #[automatically_derived]
impl ::core::fmt::Debug for VisitorState {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_tuple_field1_finish(f, "VisitorState",
&&self.0)
}
}Debug, #[automatically_derived]
impl ::core::cmp::PartialEq for VisitorState {
#[inline]
fn eq(&self, other: &VisitorState) -> bool { self.0 == other.0 }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for VisitorState {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) {
let _:
::core::cmp::AssertParamIsEq<<VisitorState as
::bitflags::__private::PublicFlags>::Internal>;
}
}Eq)]
265struct VisitorState: u8 {
266/// For use in (externally-linked) static variables.
267const STATIC = 0b000001;
268/// For use in functions in general.
269const FUNC = 0b000010;
270/// For variables in function returns (implicitly: not for static variables).
271const FN_RETURN = 0b000100;
272/// For variables in functions/variables which are defined in rust.
273const DEFINED = 0b001000;
274/// For times where we are only defining the type of something
275 /// (struct/enum/union definitions, FnPtrs).
276const THEORETICAL = 0b010000;
277 }
278}
279280impl VisitorState {
281// The values that can be set.
282const STATIC_TY: Self = Self::STATIC;
283const ARGUMENT_TY_IN_DEFINITION: Self =
284Self::from_bits(Self::FUNC.bits() | Self::DEFINED.bits()).unwrap();
285const RETURN_TY_IN_DEFINITION: Self =
286Self::from_bits(Self::FUNC.bits() | Self::FN_RETURN.bits() | Self::DEFINED.bits()).unwrap();
287const ARGUMENT_TY_IN_DECLARATION: Self = Self::FUNC;
288const RETURN_TY_IN_DECLARATION: Self =
289Self::from_bits(Self::FUNC.bits() | Self::FN_RETURN.bits()).unwrap();
290const ARGUMENT_TY_IN_FNPTR: Self =
291Self::from_bits(Self::FUNC.bits() | Self::THEORETICAL.bits()).unwrap();
292const RETURN_TY_IN_FNPTR: Self =
293Self::from_bits(Self::FUNC.bits() | Self::THEORETICAL.bits() | Self::FN_RETURN.bits())
294 .unwrap();
295296/// Get the proper visitor state for a given function's arguments.
297fn argument_from_fnmode(fn_mode: CItemKind) -> Self {
298match fn_mode {
299 CItemKind::Definition => VisitorState::ARGUMENT_TY_IN_DEFINITION,
300 CItemKind::Declaration => VisitorState::ARGUMENT_TY_IN_DECLARATION,
301 }
302 }
303304/// Get the proper visitor state for a given function's return type.
305fn return_from_fnmode(fn_mode: CItemKind) -> Self {
306match fn_mode {
307 CItemKind::Definition => VisitorState::RETURN_TY_IN_DEFINITION,
308 CItemKind::Declaration => VisitorState::RETURN_TY_IN_DECLARATION,
309 }
310 }
311312/// Whether the type is used in a function.
313fn is_in_function(self) -> bool {
314let ret = self.contains(Self::FUNC);
315if ret {
316if true {
if !!self.contains(Self::STATIC) {
::core::panicking::panic("assertion failed: !self.contains(Self::STATIC)")
};
};debug_assert!(!self.contains(Self::STATIC));
317 }
318ret319 }
320/// Whether the type is used (directly or not) in a function, in return position.
321fn is_in_function_return(self) -> bool {
322let ret = self.contains(Self::FN_RETURN);
323if ret {
324if true {
if !self.is_in_function() {
::core::panicking::panic("assertion failed: self.is_in_function()")
};
};debug_assert!(self.is_in_function());
325 }
326ret327 }
328/// Whether the type is used (directly or not) in a defined function.
329 /// In other words, whether or not we allow non-FFI-safe types behind a C pointer,
330 /// to be treated as an opaque type on the other side of the FFI boundary.
331fn is_in_defined_function(self) -> bool {
332self.contains(Self::DEFINED) && self.is_in_function()
333 }
334335/// Whether the type is used (directly or not) in a function pointer type.
336 /// Here, we also allow non-FFI-safe types behind a C pointer,
337 /// to be treated as an opaque type on the other side of the FFI boundary.
338fn is_in_fnptr(self) -> bool {
339self.contains(Self::THEORETICAL) && self.is_in_function()
340 }
341342/// Whether we can expect type parameters and co in a given type.
343fn can_expect_ty_params(self) -> bool {
344// rust-defined functions, as well as FnPtrs
345self.contains(Self::THEORETICAL) || self.is_in_defined_function()
346 }
347}
348349/// Visitor used to recursively traverse MIR types and evaluate FFI-safety.
350/// It uses ``check_*`` methods as entrypoints to be called elsewhere,
351/// and ``visit_*`` methods to recurse.
352struct ImproperCTypesVisitor<'a, 'tcx> {
353 cx: &'a LateContext<'tcx>,
354/// To prevent problems with recursive types,
355 /// add a types-in-check cache.
356cache: FxHashSet<Ty<'tcx>>,
357/// The original type being checked, before we recursed
358 /// to any other types it contains.
359base_ty: Ty<'tcx>,
360 base_fn_mode: CItemKind,
361}
362363impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
364fn new(cx: &'a LateContext<'tcx>, base_ty: Ty<'tcx>, base_fn_mode: CItemKind) -> Self {
365Self { cx, base_ty, base_fn_mode, cache: FxHashSet::default() }
366 }
367368/// Checks if the given field's type is "ffi-safe".
369fn check_field_type_for_ffi(
370&mut self,
371 state: VisitorState,
372 field: &ty::FieldDef,
373 args: GenericArgsRef<'tcx>,
374 ) -> FfiResult<'tcx> {
375let field_ty = field.ty(self.cx.tcx, args);
376let field_ty = self377 .cx
378 .tcx
379 .try_normalize_erasing_regions(self.cx.typing_env(), field_ty)
380 .unwrap_or(field_ty);
381self.visit_type(state, field_ty)
382 }
383384/// Checks if the given `VariantDef`'s field types are "ffi-safe".
385fn check_variant_for_ffi(
386&mut self,
387 state: VisitorState,
388 ty: Ty<'tcx>,
389 def: ty::AdtDef<'tcx>,
390 variant: &ty::VariantDef,
391 args: GenericArgsRef<'tcx>,
392 ) -> FfiResult<'tcx> {
393use FfiResult::*;
394let transparent_with_all_zst_fields = if def.repr().transparent() {
395if let Some(field) = super::transparent_newtype_field(self.cx.tcx, variant) {
396// Transparent newtypes have at most one non-ZST field which needs to be checked..
397match self.check_field_type_for_ffi(state, field, args) {
398FfiUnsafe { ty, .. } if ty.is_unit() => (),
399 r => return r,
400 }
401402false
403} else {
404// ..or have only ZST fields, which is FFI-unsafe (unless those fields are all
405 // `PhantomData`).
406true
407}
408 } else {
409false
410};
411412// We can't completely trust `repr(C)` markings, so make sure the fields are actually safe.
413let mut all_phantom = !variant.fields.is_empty();
414for field in &variant.fields {
415 all_phantom &= match self.check_field_type_for_ffi(state, field, args) {
416 FfiSafe => false,
417// `()` fields are FFI-safe!
418FfiUnsafe { ty, .. } if ty.is_unit() => false,
419 FfiPhantom(..) => true,
420 r @ FfiUnsafe { .. } => return r,
421 }
422 }
423424if all_phantom {
425FfiPhantom(ty)
426 } else if transparent_with_all_zst_fields {
427FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_struct_zst, help: None }
428 } else {
429FfiSafe430 }
431 }
432433/// Checks if the given type is "ffi-safe" (has a stable, well-defined
434 /// representation which can be exported to C code).
435fn visit_type(&mut self, state: VisitorState, ty: Ty<'tcx>) -> FfiResult<'tcx> {
436use FfiResult::*;
437438let tcx = self.cx.tcx;
439440// Protect against infinite recursion, for example
441 // `struct S(*mut S);`.
442 // FIXME: A recursion limit is necessary as well, for irregular
443 // recursive types.
444if !self.cache.insert(ty) {
445return FfiSafe;
446 }
447448match *ty.kind() {
449 ty::Adt(def, args) => {
450if let Some(boxed) = ty.boxed_ty()
451 && (
452// FIXME(ctypes): this logic is broken, but it still fits the current tests
453state.is_in_defined_function()
454 || (state.is_in_fnptr()
455 && #[allow(non_exhaustive_omitted_patterns)] match self.base_fn_mode {
CItemKind::Definition => true,
_ => false,
}matches!(self.base_fn_mode, CItemKind::Definition))
456 )
457 {
458if boxed.is_sized(tcx, self.cx.typing_env()) {
459return FfiSafe;
460 } else {
461return FfiUnsafe {
462ty,
463 reason: fluent::lint_improper_ctypes_box,
464 help: None,
465 };
466 }
467 }
468if def.is_phantom_data() {
469return FfiPhantom(ty);
470 }
471match def.adt_kind() {
472 AdtKind::Struct | AdtKind::Union => {
473if let Some(sym::cstring_type | sym::cstr_type) =
474tcx.get_diagnostic_name(def.did())
475 && !self.base_ty.is_mutable_ptr()
476 {
477return FfiUnsafe {
478ty,
479 reason: fluent::lint_improper_ctypes_cstr_reason,
480 help: Some(fluent::lint_improper_ctypes_cstr_help),
481 };
482 }
483484if !def.repr().c() && !def.repr().transparent() {
485return FfiUnsafe {
486ty,
487 reason: if def.is_struct() {
488 fluent::lint_improper_ctypes_struct_layout_reason489 } else {
490 fluent::lint_improper_ctypes_union_layout_reason491 },
492 help: if def.is_struct() {
493Some(fluent::lint_improper_ctypes_struct_layout_help)
494 } else {
495Some(fluent::lint_improper_ctypes_union_layout_help)
496 },
497 };
498 }
499500if def.non_enum_variant().field_list_has_applicable_non_exhaustive() {
501return FfiUnsafe {
502ty,
503 reason: if def.is_struct() {
504 fluent::lint_improper_ctypes_struct_non_exhaustive505 } else {
506 fluent::lint_improper_ctypes_union_non_exhaustive507 },
508 help: None,
509 };
510 }
511512if def.non_enum_variant().fields.is_empty() {
513return FfiUnsafe {
514ty,
515 reason: if def.is_struct() {
516 fluent::lint_improper_ctypes_struct_fieldless_reason517 } else {
518 fluent::lint_improper_ctypes_union_fieldless_reason519 },
520 help: if def.is_struct() {
521Some(fluent::lint_improper_ctypes_struct_fieldless_help)
522 } else {
523Some(fluent::lint_improper_ctypes_union_fieldless_help)
524 },
525 };
526 }
527528self.check_variant_for_ffi(state, ty, def, def.non_enum_variant(), args)
529 }
530 AdtKind::Enum => {
531if def.variants().is_empty() {
532// Empty enums are okay... although sort of useless.
533return FfiSafe;
534 }
535// Check for a repr() attribute to specify the size of the
536 // discriminant.
537if !def.repr().c() && !def.repr().transparent() && def.repr().int.is_none()
538 {
539// Special-case types like `Option<extern fn()>` and `Result<extern fn(), ()>`
540if let Some(ty) =
541repr_nullable_ptr(self.cx.tcx, self.cx.typing_env(), ty)
542 {
543return self.visit_type(state, ty);
544 }
545546return FfiUnsafe {
547ty,
548 reason: fluent::lint_improper_ctypes_enum_repr_reason,
549 help: Some(fluent::lint_improper_ctypes_enum_repr_help),
550 };
551 }
552553let non_exhaustive = def.variant_list_has_applicable_non_exhaustive();
554// Check the contained variants.
555let ret = def.variants().iter().try_for_each(|variant| {
556check_non_exhaustive_variant(non_exhaustive, variant)
557 .map_break(|reason| FfiUnsafe { ty, reason, help: None })?;
558559match self.check_variant_for_ffi(state, ty, def, variant, args) {
560FfiSafe => ControlFlow::Continue(()),
561 r => ControlFlow::Break(r),
562 }
563 });
564if let ControlFlow::Break(result) = ret {
565return result;
566 }
567568FfiSafe569 }
570 }
571 }
572573 ty::Char => FfiUnsafe {
574ty,
575 reason: fluent::lint_improper_ctypes_char_reason,
576 help: Some(fluent::lint_improper_ctypes_char_help),
577 },
578579// It's just extra invariants on the type that you need to uphold,
580 // but only the base type is relevant for being representable in FFI.
581ty::Pat(base, ..) => self.visit_type(state, base),
582583// Primitive types with a stable representation.
584ty::Bool | ty::Int(..) | ty::Uint(..) | ty::Float(..) | ty::Never => FfiSafe,
585586 ty::Slice(_) => FfiUnsafe {
587ty,
588 reason: fluent::lint_improper_ctypes_slice_reason,
589 help: Some(fluent::lint_improper_ctypes_slice_help),
590 },
591592 ty::Dynamic(..) => {
593FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_dyn, help: None }
594 }
595596 ty::Str => FfiUnsafe {
597ty,
598 reason: fluent::lint_improper_ctypes_str_reason,
599 help: Some(fluent::lint_improper_ctypes_str_help),
600 },
601602 ty::Tuple(..) => FfiUnsafe {
603ty,
604 reason: fluent::lint_improper_ctypes_tuple_reason,
605 help: Some(fluent::lint_improper_ctypes_tuple_help),
606 },
607608 ty::RawPtr(ty, _) | ty::Ref(_, ty, _)
609if {
610 (state.is_in_defined_function() || state.is_in_fnptr())
611 && ty.is_sized(self.cx.tcx, self.cx.typing_env())
612 } =>
613 {
614FfiSafe615 }
616617 ty::RawPtr(ty, _)
618if match ty.kind() {
619 ty::Tuple(tuple) => tuple.is_empty(),
620_ => false,
621 } =>
622 {
623FfiSafe624 }
625626 ty::RawPtr(ty, _) | ty::Ref(_, ty, _) => self.visit_type(state, ty),
627628 ty::Array(inner_ty, _) => self.visit_type(state, inner_ty),
629630 ty::FnPtr(sig_tys, hdr) => {
631let sig = sig_tys.with(hdr);
632if sig.abi().is_rustic_abi() {
633return FfiUnsafe {
634ty,
635 reason: fluent::lint_improper_ctypes_fnptr_reason,
636 help: Some(fluent::lint_improper_ctypes_fnptr_help),
637 };
638 }
639640let sig = tcx.instantiate_bound_regions_with_erased(sig);
641for arg in sig.inputs() {
642match self.visit_type(VisitorState::ARGUMENT_TY_IN_FNPTR, *arg) {
643 FfiSafe => {}
644 r => return r,
645 }
646 }
647648let ret_ty = sig.output();
649if ret_ty.is_unit() {
650return FfiSafe;
651 }
652653self.visit_type(VisitorState::RETURN_TY_IN_FNPTR, ret_ty)
654 }
655656 ty::Foreign(..) => FfiSafe,
657658// While opaque types are checked for earlier, if a projection in a struct field
659 // normalizes to an opaque type, then it will reach this branch.
660ty::Alias(ty::Opaque, ..) => {
661FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_opaque, help: None }
662 }
663664// `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe,
665 // so they are currently ignored for the purposes of this lint.
666ty::Param(..) | ty::Alias(ty::Projection | ty::Inherent, ..)
667if state.can_expect_ty_params() =>
668 {
669FfiSafe670 }
671672 ty::UnsafeBinder(_) => {
673FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_unsafe_binder, help: None }
674 }
675676 ty::Param(..)
677 | ty::Alias(ty::Projection | ty::Inherent | ty::Free, ..)
678 | ty::Infer(..)
679 | ty::Bound(..)
680 | ty::Error(_)
681 | ty::Closure(..)
682 | ty::CoroutineClosure(..)
683 | ty::Coroutine(..)
684 | ty::CoroutineWitness(..)
685 | ty::Placeholder(..)
686 | ty::FnDef(..) => ::rustc_middle::util::bug::bug_fmt(format_args!("unexpected type in foreign function: {0:?}",
ty))bug!("unexpected type in foreign function: {:?}", ty),
687 }
688 }
689690fn visit_for_opaque_ty(&mut self, ty: Ty<'tcx>) -> PartialFfiResult<'tcx> {
691struct ProhibitOpaqueTypes;
692impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for ProhibitOpaqueTypes {
693type Result = ControlFlow<Ty<'tcx>>;
694695fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
696if !ty.has_opaque_types() {
697return ControlFlow::Continue(());
698 }
699700if let ty::Alias(ty::Opaque, ..) = ty.kind() {
701 ControlFlow::Break(ty)
702 } else {
703ty.super_visit_with(self)
704 }
705 }
706 }
707708if let Some(ty) = self709 .cx
710 .tcx
711 .try_normalize_erasing_regions(self.cx.typing_env(), ty)
712 .unwrap_or(ty)
713 .visit_with(&mut ProhibitOpaqueTypes)
714 .break_value()
715 {
716Some(FfiResult::FfiUnsafe {
717ty,
718 reason: fluent::lint_improper_ctypes_opaque,
719 help: None,
720 })
721 } else {
722None723 }
724 }
725726/// Check if the type is array and emit an unsafe type lint.
727fn check_for_array_ty(&mut self, ty: Ty<'tcx>) -> PartialFfiResult<'tcx> {
728if let ty::Array(..) = ty.kind() {
729Some(FfiResult::FfiUnsafe {
730ty,
731 reason: fluent::lint_improper_ctypes_array_reason,
732 help: Some(fluent::lint_improper_ctypes_array_help),
733 })
734 } else {
735None736 }
737 }
738739/// Determine the FFI-safety of a single (MIR) type, given the context of how it is used.
740fn check_type(&mut self, state: VisitorState, ty: Ty<'tcx>) -> FfiResult<'tcx> {
741if let Some(res) = self.visit_for_opaque_ty(ty) {
742return res;
743 }
744745let ty = self.cx.tcx.try_normalize_erasing_regions(self.cx.typing_env(), ty).unwrap_or(ty);
746747// C doesn't really support passing arrays by value - the only way to pass an array by value
748 // is through a struct. So, first test that the top level isn't an array, and then
749 // recursively check the types inside.
750if state.is_in_function() {
751if let Some(res) = self.check_for_array_ty(ty) {
752return res;
753 }
754 }
755756// Don't report FFI errors for unit return types. This check exists here, and not in
757 // the caller (where it would make more sense) so that normalization has definitely
758 // happened.
759if state.is_in_function_return() && ty.is_unit() {
760return FfiResult::FfiSafe;
761 }
762763self.visit_type(state, ty)
764 }
765}
766767impl<'tcx> ImproperCTypesLint {
768/// Find any fn-ptr types with external ABIs in `ty`, and FFI-checks them.
769 /// For example, `Option<extern "C" fn()>` FFI-checks `extern "C" fn()`.
770fn check_type_for_external_abi_fnptr(
771&mut self,
772 cx: &LateContext<'tcx>,
773 state: VisitorState,
774 hir_ty: &hir::Ty<'tcx>,
775 ty: Ty<'tcx>,
776 fn_mode: CItemKind,
777 ) {
778struct FnPtrFinder<'tcx> {
779 spans: Vec<Span>,
780 tys: Vec<Ty<'tcx>>,
781 }
782783impl<'tcx> hir::intravisit::Visitor<'_> for FnPtrFinder<'tcx> {
784fn visit_ty(&mut self, ty: &'_ hir::Ty<'_, AmbigArg>) {
785{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_lint/src/types/improper_ctypes.rs:785",
"rustc_lint::types::improper_ctypes",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/types/improper_ctypes.rs"),
::tracing_core::__macro_support::Option::Some(785u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::types::improper_ctypes"),
::tracing_core::field::FieldSet::new(&["ty"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&debug(&ty) as
&dyn Value))])
});
} else { ; }
};debug!(?ty);
786if let hir::TyKind::FnPtr(hir::FnPtrTy { abi, .. }) = ty.kind
787 && !abi.is_rustic_abi()
788 {
789self.spans.push(ty.span);
790 }
791792 hir::intravisit::walk_ty(self, ty)
793 }
794 }
795796impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for FnPtrFinder<'tcx> {
797type Result = ();
798799fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
800if let ty::FnPtr(_, hdr) = ty.kind()
801 && !hdr.abi.is_rustic_abi()
802 {
803self.tys.push(ty);
804 }
805806ty.super_visit_with(self)
807 }
808 }
809810let mut visitor = FnPtrFinder { spans: Vec::new(), tys: Vec::new() };
811ty.visit_with(&mut visitor);
812visitor.visit_ty_unambig(hir_ty);
813814let all_types = iter::zip(visitor.tys.drain(..), visitor.spans.drain(..));
815for (fn_ptr_ty, span) in all_types {
816let mut visitor = ImproperCTypesVisitor::new(cx, fn_ptr_ty, fn_mode);
817// FIXME(ctypes): make a check_for_fnptr
818let ffi_res = visitor.check_type(state, fn_ptr_ty);
819820self.process_ffi_result(cx, span, ffi_res, fn_mode);
821 }
822 }
823824/// Regardless of a function's need to be "ffi-safe", look for fn-ptr argument/return types
825 /// that need to be checked for ffi-safety.
826fn check_fn_for_external_abi_fnptr(
827&mut self,
828 cx: &LateContext<'tcx>,
829 fn_mode: CItemKind,
830 def_id: LocalDefId,
831 decl: &'tcx hir::FnDecl<'_>,
832 ) {
833let sig = cx.tcx.fn_sig(def_id).instantiate_identity();
834let sig = cx.tcx.instantiate_bound_regions_with_erased(sig);
835836for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) {
837let state = VisitorState::argument_from_fnmode(fn_mode);
838self.check_type_for_external_abi_fnptr(cx, state, input_hir, *input_ty, fn_mode);
839 }
840841if let hir::FnRetTy::Return(ret_hir) = decl.output {
842let state = VisitorState::return_from_fnmode(fn_mode);
843self.check_type_for_external_abi_fnptr(cx, state, ret_hir, sig.output(), fn_mode);
844 }
845 }
846847/// For a local definition of a #[repr(C)] struct/enum/union, check that it is indeed FFI-safe.
848fn check_reprc_adt(
849&mut self,
850 cx: &LateContext<'tcx>,
851 item: &'tcx hir::Item<'tcx>,
852 adt_def: AdtDef<'tcx>,
853 ) {
854if 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!(
855 adt_def.repr().c() && !adt_def.repr().packed() && adt_def.repr().align.is_none()
856 );
857858// FIXME(ctypes): this following call is awkward.
859 // is there a way to perform its logic in MIR space rather than HIR space?
860 // (so that its logic can be absorbed into visitor.visit_struct_or_union)
861check_struct_for_power_alignment(cx, item, adt_def);
862 }
863864fn check_foreign_static(&mut self, cx: &LateContext<'tcx>, id: hir::OwnerId, span: Span) {
865let ty = cx.tcx.type_of(id).instantiate_identity();
866let mut visitor = ImproperCTypesVisitor::new(cx, ty, CItemKind::Declaration);
867let ffi_res = visitor.check_type(VisitorState::STATIC_TY, ty);
868self.process_ffi_result(cx, span, ffi_res, CItemKind::Declaration);
869 }
870871/// Check if a function's argument types and result type are "ffi-safe".
872fn check_foreign_fn(
873&mut self,
874 cx: &LateContext<'tcx>,
875 fn_mode: CItemKind,
876 def_id: LocalDefId,
877 decl: &'tcx hir::FnDecl<'_>,
878 ) {
879let sig = cx.tcx.fn_sig(def_id).instantiate_identity();
880let sig = cx.tcx.instantiate_bound_regions_with_erased(sig);
881882for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) {
883let state = VisitorState::argument_from_fnmode(fn_mode);
884let mut visitor = ImproperCTypesVisitor::new(cx, *input_ty, fn_mode);
885let ffi_res = visitor.check_type(state, *input_ty);
886self.process_ffi_result(cx, input_hir.span, ffi_res, fn_mode);
887 }
888889if let hir::FnRetTy::Return(ret_hir) = decl.output {
890let state = VisitorState::return_from_fnmode(fn_mode);
891let mut visitor = ImproperCTypesVisitor::new(cx, sig.output(), fn_mode);
892let ffi_res = visitor.check_type(state, sig.output());
893self.process_ffi_result(cx, ret_hir.span, ffi_res, fn_mode);
894 }
895 }
896897fn process_ffi_result(
898&self,
899 cx: &LateContext<'tcx>,
900 sp: Span,
901 res: FfiResult<'tcx>,
902 fn_mode: CItemKind,
903 ) {
904match res {
905 FfiResult::FfiSafe => {}
906 FfiResult::FfiPhantom(ty) => {
907self.emit_ffi_unsafe_type_lint(
908cx,
909ty,
910sp,
911 fluent::lint_improper_ctypes_only_phantomdata,
912None,
913fn_mode,
914 );
915 }
916 FfiResult::FfiUnsafe { ty, reason, help } => {
917self.emit_ffi_unsafe_type_lint(cx, ty, sp, reason, help, fn_mode);
918 }
919 }
920 }
921922fn emit_ffi_unsafe_type_lint(
923&self,
924 cx: &LateContext<'tcx>,
925 ty: Ty<'tcx>,
926 sp: Span,
927 note: DiagMessage,
928 help: Option<DiagMessage>,
929 fn_mode: CItemKind,
930 ) {
931let lint = match fn_mode {
932 CItemKind::Declaration => IMPROPER_CTYPES,
933 CItemKind::Definition => IMPROPER_CTYPES_DEFINITIONS,
934 };
935let desc = match fn_mode {
936 CItemKind::Declaration => "block",
937 CItemKind::Definition => "fn",
938 };
939let span_note = if let ty::Adt(def, _) = ty.kind()
940 && let Some(sp) = cx.tcx.hir_span_if_local(def.did())
941 {
942Some(sp)
943 } else {
944None945 };
946cx.emit_span_lint(lint, sp, ImproperCTypes { ty, desc, label: sp, help, note, span_note });
947 }
948}
949950/// `ImproperCTypesDefinitions` checks items outside of foreign items (e.g. stuff that isn't in
951/// `extern "C" { }` blocks):
952///
953/// - `extern "<abi>" fn` definitions are checked in the same way as the
954/// `ImproperCtypesDeclarations` visitor checks functions if `<abi>` is external (e.g. "C").
955/// - All other items which contain types (e.g. other functions, struct definitions, etc) are
956/// checked for extern fn-ptrs with external ABIs.
957impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
958fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, it: &hir::ForeignItem<'tcx>) {
959let abi = cx.tcx.hir_get_foreign_abi(it.hir_id());
960961match it.kind {
962 hir::ForeignItemKind::Fn(sig, _, _) => {
963// fnptrs are a special case, they always need to be treated as
964 // "the element rendered unsafe" because their unsafety doesn't affect
965 // their surroundings, and their type is often declared inline
966if !abi.is_rustic_abi() {
967self.check_foreign_fn(cx, CItemKind::Declaration, it.owner_id.def_id, sig.decl);
968 } else {
969self.check_fn_for_external_abi_fnptr(
970cx,
971 CItemKind::Declaration,
972it.owner_id.def_id,
973sig.decl,
974 );
975 }
976 }
977 hir::ForeignItemKind::Static(ty, _, _) if !abi.is_rustic_abi() => {
978self.check_foreign_static(cx, it.owner_id, ty.span);
979 }
980 hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => (),
981 }
982 }
983984fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
985match item.kind {
986 hir::ItemKind::Static(_, _, ty, _)
987 | hir::ItemKind::Const(_, _, ty, _)
988 | hir::ItemKind::TyAlias(_, _, ty) => {
989self.check_type_for_external_abi_fnptr(
990cx,
991VisitorState::STATIC_TY,
992ty,
993cx.tcx.type_of(item.owner_id).instantiate_identity(),
994 CItemKind::Definition,
995 );
996 }
997// See `check_fn` for declarations, `check_foreign_items` for definitions in extern blocks
998hir::ItemKind::Fn { .. } => {}
999 hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) | hir::ItemKind::Enum(..) => {
1000// looking for extern FnPtr:s is delegated to `check_field_def`.
1001let adt_def: AdtDef<'tcx> = cx.tcx.adt_def(item.owner_id.to_def_id());
10021003if adt_def.repr().c() && !adt_def.repr().packed() && adt_def.repr().align.is_none()
1004 {
1005self.check_reprc_adt(cx, item, adt_def);
1006 }
1007 }
10081009// Doesn't define something that can contain a external type to be checked.
1010hir::ItemKind::Impl(..)
1011 | hir::ItemKind::TraitAlias(..)
1012 | hir::ItemKind::Trait(..)
1013 | hir::ItemKind::GlobalAsm { .. }
1014 | hir::ItemKind::ForeignMod { .. }
1015 | hir::ItemKind::Mod(..)
1016 | hir::ItemKind::Macro(..)
1017 | hir::ItemKind::Use(..)
1018 | hir::ItemKind::ExternCrate(..) => {}
1019 }
1020 }
10211022fn check_field_def(&mut self, cx: &LateContext<'tcx>, field: &'tcx hir::FieldDef<'tcx>) {
1023self.check_type_for_external_abi_fnptr(
1024cx,
1025VisitorState::STATIC_TY,
1026field.ty,
1027cx.tcx.type_of(field.def_id).instantiate_identity(),
1028 CItemKind::Definition,
1029 );
1030 }
10311032fn check_fn(
1033&mut self,
1034 cx: &LateContext<'tcx>,
1035 kind: hir::intravisit::FnKind<'tcx>,
1036 decl: &'tcx hir::FnDecl<'_>,
1037_: &'tcx hir::Body<'_>,
1038_: Span,
1039 id: LocalDefId,
1040 ) {
1041use hir::intravisit::FnKind;
10421043let abi = match kind {
1044 FnKind::ItemFn(_, _, header, ..) => header.abi,
1045 FnKind::Method(_, sig, ..) => sig.header.abi,
1046_ => return,
1047 };
10481049// fnptrs are a special case, they always need to be treated as
1050 // "the element rendered unsafe" because their unsafety doesn't affect
1051 // their surroundings, and their type is often declared inline
1052if !abi.is_rustic_abi() {
1053self.check_foreign_fn(cx, CItemKind::Definition, id, decl);
1054 } else {
1055self.check_fn_for_external_abi_fnptr(cx, CItemKind::Definition, id, decl);
1056 }
1057 }
1058}