Skip to main content

rustc_lint/ferrocene/
mod.rs

1//! This module contains the [`ferrocene::unvalidated`](UNVALIDATED) lint pass.
2//!
3//! ## Architecture
4//! There are two main passes: the [THIR pass](thir) and the
5//! [post-monomorphization MIR pass](post_mono).
6//! THIR runs on both `cargo check` and `cargo build`.
7//! post-mono only runs on `cargo build`.
8//!
9//! The THIR pass is exclusively for diagnostics; our soundness argument does not rely on it at all.
10//! It only exists because it sucks to only see errors multiple crates later than they happened,
11//! especially for highly generic crates like core.
12//!
13//! The post-mono pass only runs on code that has been monomorphized for codegen.
14//! In particular, it only runs on reachable code; it's very possible to have dead code that uses an
15//! unvalidated item, which is fine as long as it's never actually sent to LLVM.
16//! In most cases, but not all, this will be caught by the THIR pass.
17//!
18//! ### instantiations
19//!
20//! We need a post-mono pass because we may not be able to resolve all function calls immediately.
21//! Consider this program:
22//! ```rust
23//! fn uninstantiated<T: Clone>(x: T) { x.clone(); }
24//! ```
25//! At the time we first see it, we have no idea what the type of T is, so we cannot resolve
26//! `<T as Clone>::clone`. We have to wait until we see a caller that monomorphizes it as (e.g.)
27//! `uninstantiated::<i32>(0)`. Only then do we know whether the implementation is validated.
28//!
29//! ### macros
30//!
31//! Because we depend on this lint for our validity argument, we report the lint even through
32//! external macros; just because a macro was defined in core does not mean the functions it calls
33//! are validated.
34//!
35//! ### function pointers
36//!
37//! Normally we only lint at call sites. However, once a function is cast to a function pointer, we
38//! no longer have a way to retrieve its `#[ferrocene::prevalidated]` attribute. We want to avoid
39//! having to ban function pointers altogether, so instead we force a decision of whether to lint at
40//! the time of the cast. Consider this program:
41//! ```rust
42//! # #![feature(register_tool)] #![register_tool(ferrocene)]
43//! fn unvalidated() {}
44//! #[ferrocene::prevalidated]
45//! fn returns_ptr() -> fn() { unvalidated } // not ok
46//! ```
47//! We have no idea whether some validated code is going to call `option.map(returns_ptr())`.
48//! So we need to lint at the cast site instead.
49//!
50//! It might be possible to do fancy dataflow analysis to only disallow this if the pointer
51//! "escapes" the current function, but that's complicated, and always checking at the cast site is
52//! simple.
53//!
54//! ### const blocks
55//!
56//! Some function calls occur in the initializer of a `const` or `static`, not in a function body.
57//! Usually this is totally fine: we argue to the assessor that compile-time code doesn't need to
58//! (and can't) have line-coverage.
59//!
60//! ```
61//! const PATH_MAX: usize = 2048;
62//! let buffer = [0; PATH_MAX]; // totally fine
63//! ```
64//!
65//! However, if there's a function pointer anywhere in the constant, we need to make sure that
66//! function can't be called at runtime. In that case, we require the const or static to be marked
67//! with `ferrocene::prevalidated` at each use site:
68//!
69//! ```
70//! # use std::panic::{set_hook, PanicHookInfo};
71//! fn unvalidated_panic(_: &PanicHookInfo) {}
72//! const PANIC_HOOK: fn(&PanicHookInfo) = unvalidated_panic;
73//! set_hook(Box::new(PANIC_HOOK)); //~ ERRROR PANIC_HOOK is unvalidated
74//! ```
75//!
76//! Then, once the user adds the annotation, we walk the const body at the definition site.
77//! ```
78//! # use std::panic::{set_hook, PanicHookInfo};
79//! fn unvalidated_panic(_: &PanicHookInfo) {}
80//! #[ferrocene::prevalidated]
81//! const PANIC_HOOK: fn(&PanicHookInfo) = unvalidated_panic;
82//! //~^ ERROR unvalidated_panic is unvalidated
83//! ```
84//!
85//! ### trait object coercions
86//!
87//! These are similar to function pointers, except trait objects bundle many function pointers
88//! together, and determining which functions those actually are is non-trivial. See
89//! [`LintState::check_dyn_trait_coercion`] for examples of how this works.
90//!
91//! ```
92//! struct Unvalidated;
93//! impl PartialEq<()> for Unvalidated {
94//!     fn eq(&self, _: &()) -> bool { false }
95//! }
96//! // not ok: might call x.eq() later.
97//! let x: &dyn PartialEq<()> = &Unvalidated;
98//! ```
99//!
100//! ### THIR
101//!
102//! The THIR pass runs as a (mostly) standard [LateLintPass].
103//! Unfortunately, LateLintPasses normally work on [HIR](https://rustc-dev-guide.rust-lang.org/hir.html)
104//! *and* run near the end of compilation, which means that
105//! [THIR](https://rustc-dev-guide.rust-lang.org/thir.html#the-thir) would normally not be
106//! available. We preserve THIR all the way through the end of compilation, which causes Ferrocene
107//! to use slightly more memory in exchange for getting better diagnostics.
108//!
109//! If the THIR pass cannot resolve an uninstantiated call (see "instantiations" above), it simply
110//! silences the warning, assuming the post-mono pass will catch it.
111//!
112//! ### post-mono
113//!
114//! This pass is hacked into the
115//! [`collect_and_partition_mono_items`](TyCtxt::collect_and_partition_mono_items)
116//! [query](https://rustc-dev-guide.rust-lang.org/overview.html#queries), which runs on
117//! [MIR](https://rustc-dev-guide.rust-lang.org/mir/index.html) just before the time we actually
118//! generate LLVM IR for a given function. That allows us to assume that all function calls
119//! can be resolved to an [`Instance`] (and error out otherwise). It also runs after ["elaborate
120//! drops"](https://rustc-dev-guide.rust-lang.org/mir/drop-elaboration.html#drop-elaboration)
121//! expands each drop to an explicit [`TerminatorKind::Drop`].
122//!
123//! *However*, it means we cannot depend on the function to be local to the current crate, or that
124//! we have a lint node for the failing call, or that we have source spans or HIR available
125//! for the failing call.
126//!
127//! This sucks a lot! What we do instead is look at the *caller* of the unvalidated function.
128//! For example, in our example above, our lint is on the `uninstantiated(0_i32)` call, not the
129//! `x.clone` call. We show `x.clone` as the primary span, but our decision of whether or not to
130//! emit the lint comes from the `uninstantiated()` call.
131//!
132//! ## Implementation
133//!
134//! First, some background on Rust's type system and compilation model.
135//! Each function in a Rust program is only *defined* in one place, but it may be *instantiated*
136//! many times with different generic arguments. Our definition above was `fn uninstantiated`, and our
137//! generic arguments were `[i32]`, which means our [`Instance`] was `uninstantiated::<i32>`.
138//!
139//! For our purposes, we care only about the instantiations of a function, not about any
140//! declarations in a trait. In order to instantiate a function, we need to know both its
141//! definition ([`DefId`]) and generic arguments
142//! ([`GenericArgsRef`]). We may also need to resolve type
143//! variables in scope. For example, in this program below, we cannot instantiate `inherent` unless
144//! we know the type of `T` from the impl:
145//! ```rust
146//! struct S<T>(T);
147//! impl<T: Default> S<T> { fn inherent() -> T { T::default() } }
148//! ```
149//! We get these type variables from a [`ParamEnv`].
150//!
151//! ## Recommended reading
152//! - [Typing/parameter environments](https://rustc-dev-guide.rust-lang.org/typing-parameter-envs.html)
153//! - [Monomorphization](https://rustc-dev-guide.rust-lang.org/backend/monomorph.html)
154
155// NOTE: UNVALIDATED is public.
156#[doc =
r" The `ferrocene::unvalidated` lint detects verified code that calls unverified functions."]
#[doc =
r" This may result in unverified code running in a safety critical context."]
#[doc = r""]
#[doc =
r" This lint is a Ferrocene addition, and does not exist in upstream rustc."]
#[doc = r""]
#[doc =
r" This lint is allowed-by-default, to avoid loud warnings for people using Ferrocene as a"]
#[doc =
r#" "normal" compiler. To enable it, add `#![warn(ferrocene::unvalidated)]` to each crate in"#]
#[doc = r" your build, or add it to `[lints]` in Cargo.toml."]
pub static UNVALIDATED: &::rustc_lint_defs::Lint =
    &::rustc_lint_defs::Lint {
            name: &"ferrocene::UNVALIDATED",
            default_level: ::rustc_lint_defs::Allow,
            desc: "a verified function called an unverified function",
            edition_lint_opts: None,
            report_in_external_macro: true,
            future_incompatible: None,
            is_externally_loaded: true,
            crate_level_only: false,
            ..::rustc_lint_defs::Lint::default_fields_for_macro()
        };declare_tool_lint! {
157    /// The `ferrocene::unvalidated` lint detects verified code that calls unverified functions.
158    /// This may result in unverified code running in a safety critical context.
159    ///
160    /// This lint is a Ferrocene addition, and does not exist in upstream rustc.
161    ///
162    /// This lint is allowed-by-default, to avoid loud warnings for people using Ferrocene as a
163    /// "normal" compiler. To enable it, add `#![warn(ferrocene::unvalidated)]` to each crate in
164    /// your build, or add it to `[lints]` in Cargo.toml.
165    pub ferrocene::UNVALIDATED,
166    Allow,
167    "a verified function called an unverified function",
168    report_in_external_macro: true
169}
170
171// NOTE: LintUnvalidated is public.
172pub struct LintUnvalidated;
#[automatically_derived]
impl ::core::marker::Copy for LintUnvalidated { }
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for LintUnvalidated { }
#[automatically_derived]
impl ::core::clone::Clone for LintUnvalidated {
    #[inline]
    fn clone(&self) -> LintUnvalidated { *self }
}
impl ::rustc_lint_defs::LintPass for LintUnvalidated {
    fn name(&self) -> &'static str { "LintUnvalidated" }
    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(),
                [UNVALIDATED]))
    }
}
impl LintUnvalidated {
    #[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(),
                [UNVALIDATED]))
    }
}declare_lint_pass!(LintUnvalidated => [UNVALIDATED]);
173
174pub use post_mono::lint_validated_roots;
175
176mod diagnostics;
177mod dynamic_casts;
178mod post_mono;
179mod thir;
180
181use rustc_data_structures::fx::FxHashSet;
182use rustc_hir::def::DefKind;
183use rustc_hir::{HirId, Item};
184use rustc_middle::middle::codegen_fn_attrs::ferrocene::{ValidatedStatus, item_is_validated};
185use rustc_middle::span_bug;
186use rustc_middle::ty::{Instance, Ty, TyCtxt};
187use rustc_session::{declare_lint_pass, declare_tool_lint};
188use rustc_span::Span;
189use rustc_span::def_id::{DefId, LocalDefId};
190use tracing::{debug, info};
191
192use crate::ferrocene::post_mono::InstantiationSite;
193use crate::ferrocene::thir::LintThir;
194use crate::{LateContext, LateLintPass};
195
196// for intra-doc links
197#[rustfmt::skip]
198#[allow(unused_imports)]
199use rustc_middle::{
200    mir::TerminatorKind,
201    ty::{GenericArgsRef, ParamEnv},
202};
203
204impl<'tcx> LateLintPass<'tcx> for LintUnvalidated {
205    fn check_item_post(&mut self, cx: &LateContext<'tcx>, item: &Item<'tcx>) {
206        LintThir::check_item(cx.tcx, item.owner_id, item.owner_id.def_id);
207    }
208
209    fn check_impl_item_post(
210        &mut self,
211        cx: &LateContext<'tcx>,
212        item: &'tcx rustc_hir::ImplItem<'tcx>,
213    ) {
214        LintThir::check_item(cx.tcx, item.owner_id, item.owner_id.def_id);
215    }
216}
217
218struct LintState<'tcx> {
219    tcx: TyCtxt<'tcx>,
220    /// The item we are currently linting.
221    item: LocalDefId,
222    /// For diagnostics; used to point to the `#[ferrocene::prevalidated]` attribute.
223    annotation: Option<Span>,
224    /// For diagnostics; see [`lint_use`](LintState::lint_use).
225    shown_item: bool,
226    /// For deduplication; see [`check_use`](LintState::check_use).
227    shown_lints: FxHashSet<DefId>,
228}
229
230impl<'tcx> LintState<'tcx> {
231    /// Check whether `item` needs to be linted at all. If so, return a new `LintState`.
232    fn new(tcx: TyCtxt<'tcx>, item: LocalDefId) -> Option<Self> {
233        let ValidatedStatus::Validated { annotation } = item_is_validated(tcx, item.into()) else {
234            return None;
235        };
236
237        if tcx.hir_node_by_def_id(item).associated_body().is_none() {
238            match tcx.def_kind(item) {
239                // We don't care if types are unvalidated, only the functions that are called.
240                DefKind::Struct | DefKind::Enum | DefKind::Union => {}
241                kind => {
242                    let item_span = tcx.def_span(item);
243                    let span = match annotation {
244                        Some(ref span) => span.with_hi(item_span.hi()),
245                        None => item_span,
246                    };
247                    // FIXME: this should probably be `WARN unused attibute` instead?
248                    ::rustc_middle::util::bug::span_bug_fmt(span,
    format_args!("annotated validated with no body? {0:?} {1:?}", kind,
        item));span_bug!(span, "annotated validated with no body? {kind:?} {item:?}");
249                }
250            }
251            {
    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/ferrocene/mod.rs:251",
                        "rustc_lint::ferrocene", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/ferrocene/mod.rs"),
                        ::tracing_core::__macro_support::Option::Some(251u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_lint::ferrocene"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::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(&format_args!("ignoring validated item with no body: {0:?}",
                                                    item) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!("ignoring validated item with no body: {item:?}");
252            return None;
253        }
254
255        {
    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/ferrocene/mod.rs:255",
                        "rustc_lint::ferrocene", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/ferrocene/mod.rs"),
                        ::tracing_core::__macro_support::Option::Some(255u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_lint::ferrocene"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::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(&format_args!("check {0:?}",
                                                    item) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!("check {item:?}");
256        Some(LintState {
257            tcx,
258            item,
259            annotation,
260            shown_item: false,
261            shown_lints: FxHashSet::default(),
262        })
263    }
264
265    /// Check whether an item use needs to be linted. If so, lint it.
266    fn check_use(&mut self, lint_node: HirId, use_: Use<'tcx>) {
267        let tcx = self.tcx;
268        let callee = use_.def_id();
269
270        if #[allow(non_exhaustive_omitted_patterns)] match item_is_validated(tcx, callee)
    {
    ValidatedStatus::Validated { .. } => true,
    _ => false,
}matches!(item_is_validated(tcx, callee), ValidatedStatus::Validated { .. }) {
271            {
    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/ferrocene/mod.rs:271",
                        "rustc_lint::ferrocene", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/ferrocene/mod.rs"),
                        ::tracing_core::__macro_support::Option::Some(271u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_lint::ferrocene"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::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(&format_args!("no need to lint call to validated {0:?}",
                                                    callee) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!("no need to lint call to validated {callee:?}");
272            return;
273        }
274
275        // We have conditional logic below that -Z deduplicate-diagnostics doesn't know about.
276        // Deduplicate lints manually.
277        if tcx.sess.opts.unstable_opts.deduplicate_diagnostics && !self.shown_lints.insert(callee) {
278            {
    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/ferrocene/mod.rs:278",
                        "rustc_lint::ferrocene", ::tracing::Level::INFO,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/ferrocene/mod.rs"),
                        ::tracing_core::__macro_support::Option::Some(278u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_lint::ferrocene"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::INFO <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::INFO <=
                    ::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(&format_args!("ignoring duplicate lint for {0:?}",
                                                    callee) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};info!("ignoring duplicate lint for {callee:?}");
279            return;
280        }
281
282        self.lint_use(lint_node, use_);
283    }
284}
285
286#[derive(#[automatically_derived]
impl<'tcx> ::core::fmt::Debug for InstantiateResult<'tcx> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            InstantiateResult::Err =>
                ::core::fmt::Formatter::write_str(f, "Err"),
            InstantiateResult::Resolved(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "Resolved", &__self_0),
            InstantiateResult::Indeterminate =>
                ::core::fmt::Formatter::write_str(f, "Indeterminate"),
        }
    }
}Debug)]
287enum InstantiateResult<'tcx> {
288    /// Compilation is going to fail anyway. No need to do anything fancy.
289    Err,
290    /// We found the instance.
291    Resolved(Instance<'tcx>),
292    /// We don't yet have enough info to resolve this to a concrete function.
293    Indeterminate,
294}
295
296impl<'tcx> InstantiateResult<'tcx> {
297    fn instance(self) -> Option<Instance<'tcx>> {
298        match self {
299            InstantiateResult::Err | InstantiateResult::Indeterminate => None,
300            InstantiateResult::Resolved(instance) => Some(instance),
301        }
302    }
303}
304
305/// A use of an unvalidated item.
306#[derive(#[automatically_derived]
impl<'tcx> ::core::marker::Copy for Use<'tcx> { }Copy, #[automatically_derived]
impl<'tcx> ::core::clone::Clone for Use<'tcx> {
    #[inline]
    fn clone(&self) -> Use<'tcx> {
        let _: ::core::clone::AssertParamIsClone<UseKind<'tcx>>;
        let _: ::core::clone::AssertParamIsClone<Span>;
        let _:
                ::core::clone::AssertParamIsClone<Option<InstantiationSite<'tcx>>>;
        *self
    }
}Clone, #[automatically_derived]
impl<'tcx> ::core::fmt::Debug for Use<'tcx> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field3_finish(f, "Use", "kind",
            &self.kind, "span", &self.span, "from_instantiation",
            &&self.from_instantiation)
    }
}Debug)]
307struct Use<'tcx> {
308    kind: UseKind<'tcx>,
309    span: Span,
310    from_instantiation: Option<InstantiationSite<'tcx>>,
311}
312
313#[derive(#[automatically_derived]
impl<'tcx> ::core::marker::Copy for UnvalidatedImplCause<'tcx> { }Copy, #[automatically_derived]
impl<'tcx> ::core::clone::Clone for UnvalidatedImplCause<'tcx> {
    #[inline]
    fn clone(&self) -> UnvalidatedImplCause<'tcx> {
        let _: ::core::clone::AssertParamIsClone<DefId>;
        let _:
                ::core::clone::AssertParamIsClone<rustc_middle::ty::PolyTraitRef<'tcx>>;
        *self
    }
}Clone, #[automatically_derived]
impl<'tcx> ::core::fmt::Debug for UnvalidatedImplCause<'tcx> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            UnvalidatedImplCause::AssocFn(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "AssocFn", &__self_0),
            UnvalidatedImplCause::UnresolvedGenericImpl(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "UnresolvedGenericImpl", &__self_0),
        }
    }
}Debug)]
314enum UnvalidatedImplCause<'tcx> {
315    /// An associated function from the source type's impl of one of the traits we were casting to.
316    ///
317    /// FIXME(diagnostics): this should have all unvalidated items in the impl, not just the first.
318    AssocFn(DefId),
319    /// Only occurs pre-mono.
320    UnresolvedGenericImpl(rustc_middle::ty::PolyTraitRef<'tcx>),
321}
322
323#[derive(#[automatically_derived]
impl<'tcx> ::core::marker::Copy for UseKind<'tcx> { }Copy, #[automatically_derived]
impl<'tcx> ::core::clone::Clone for UseKind<'tcx> {
    #[inline]
    fn clone(&self) -> UseKind<'tcx> {
        let _: ::core::clone::AssertParamIsClone<Instance<'tcx>>;
        let _: ::core::clone::AssertParamIsClone<Instance<'tcx>>;
        let _: ::core::clone::AssertParamIsClone<UnvalidatedImplCause<'tcx>>;
        let _: ::core::clone::AssertParamIsClone<Ty<'tcx>>;
        let _: ::core::clone::AssertParamIsClone<DefId>;
        let _: ::core::clone::AssertParamIsClone<Ty<'tcx>>;
        *self
    }
}Clone, #[automatically_derived]
impl<'tcx> ::core::fmt::Debug for UseKind<'tcx> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            UseKind::Called(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Called",
                    &__self_0),
            UseKind::FnPtrCast(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "FnPtrCast", &__self_0),
            UseKind::TraitObjectCast(__self_0, __self_1) =>
                ::core::fmt::Formatter::debug_tuple_field2_finish(f,
                    "TraitObjectCast", __self_0, &__self_1),
            UseKind::ContainsFnPtr(__self_0, __self_1) =>
                ::core::fmt::Formatter::debug_tuple_field2_finish(f,
                    "ContainsFnPtr", __self_0, &__self_1),
        }
    }
}Debug)]
324enum UseKind<'tcx> {
325    Called(Instance<'tcx>),
326    FnPtrCast(Instance<'tcx>),
327    /// The `Ty` is the source type of the cast. We don't currently store the destination type.
328    TraitObjectCast(UnvalidatedImplCause<'tcx>, Ty<'tcx>),
329    /// Only occurs for consts and statics.
330    ContainsFnPtr(DefId, Ty<'tcx>),
331}
332
333impl<'tcx> Use<'tcx> {
334    fn def_id(self) -> DefId {
335        match self.kind {
336            UseKind::Called(instance) | UseKind::FnPtrCast(instance) => instance.def_id(),
337            UseKind::ContainsFnPtr(id, _) => id,
338            UseKind::TraitObjectCast(UnvalidatedImplCause::AssocFn(id), _) => id,
339            UseKind::TraitObjectCast(UnvalidatedImplCause::UnresolvedGenericImpl(trait_ref), _) => {
340                trait_ref.def_id()
341            }
342        }
343    }
344
345    fn opt_instance(self) -> Option<Instance<'tcx>> {
346        match self.kind {
347            UseKind::FnPtrCast(instance) | UseKind::Called(instance) => Some(instance),
348            UseKind::TraitObjectCast(..) | UseKind::ContainsFnPtr(..) => None,
349        }
350    }
351}