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)
154155// 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.
165pub ferrocene::UNVALIDATED,
166 Allow,
167"a verified function called an unverified function",
168 report_in_external_macro: true
169}170171// 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]);
173174pub use post_mono::lint_validated_roots;
175176mod diagnostics;
177mod dynamic_casts;
178mod post_mono;
179mod thir;
180181use 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};
191192use crate::ferrocene::post_mono::InstantiationSite;
193use crate::ferrocene::thir::LintThir;
194use crate::{LateContext, LateLintPass};
195196// for intra-doc links
197#[rustfmt::skip]
198#[allow(unused_imports)]
199use rustc_middle::{
200mir::TerminatorKind,
201 ty::{GenericArgsRef, ParamEnv},
202};
203204impl<'tcx> LateLintPass<'tcx> for LintUnvalidated {
205fn check_item_post(&mut self, cx: &LateContext<'tcx>, item: &Item<'tcx>) {
206LintThir::check_item(cx.tcx, item.owner_id, item.owner_id.def_id);
207 }
208209fn check_impl_item_post(
210&mut self,
211 cx: &LateContext<'tcx>,
212 item: &'tcx rustc_hir::ImplItem<'tcx>,
213 ) {
214LintThir::check_item(cx.tcx, item.owner_id, item.owner_id.def_id);
215 }
216}
217218struct LintState<'tcx> {
219 tcx: TyCtxt<'tcx>,
220/// The item we are currently linting.
221item: LocalDefId,
222/// For diagnostics; used to point to the `#[ferrocene::prevalidated]` attribute.
223annotation: Option<Span>,
224/// For diagnostics; see [`lint_use`](LintState::lint_use).
225shown_item: bool,
226/// For deduplication; see [`check_use`](LintState::check_use).
227shown_lints: FxHashSet<DefId>,
228}
229230impl<'tcx> LintState<'tcx> {
231/// Check whether `item` needs to be linted at all. If so, return a new `LintState`.
232fn new(tcx: TyCtxt<'tcx>, item: LocalDefId) -> Option<Self> {
233let ValidatedStatus::Validated { annotation } = item_is_validated(tcx, item.into()) else {
234return None;
235 };
236237if tcx.hir_node_by_def_id(item).associated_body().is_none() {
238match tcx.def_kind(item) {
239// We don't care if types are unvalidated, only the functions that are called.
240DefKind::Struct | DefKind::Enum | DefKind::Union => {}
241 kind => {
242let item_span = tcx.def_span(item);
243let span = match annotation {
244Some(ref span) => span.with_hi(item_span.hi()),
245None => 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:?}");
252return None;
253 }
254255{
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:?}");
256Some(LintState {
257tcx,
258item,
259annotation,
260 shown_item: false,
261 shown_lints: FxHashSet::default(),
262 })
263 }
264265/// Check whether an item use needs to be linted. If so, lint it.
266fn check_use(&mut self, lint_node: HirId, use_: Use<'tcx>) {
267let tcx = self.tcx;
268let callee = use_.def_id();
269270if #[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:?}");
272return;
273 }
274275// We have conditional logic below that -Z deduplicate-diagnostics doesn't know about.
276 // Deduplicate lints manually.
277if 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:?}");
279return;
280 }
281282self.lint_use(lint_node, use_);
283 }
284}
285286#[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.
289Err,
290/// We found the instance.
291Resolved(Instance<'tcx>),
292/// We don't yet have enough info to resolve this to a concrete function.
293Indeterminate,
294}
295296impl<'tcx> InstantiateResult<'tcx> {
297fn instance(self) -> Option<Instance<'tcx>> {
298match self {
299 InstantiateResult::Err | InstantiateResult::Indeterminate => None,
300 InstantiateResult::Resolved(instance) => Some(instance),
301 }
302 }
303}
304305/// 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}
312313#[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.
318AssocFn(DefId),
319/// Only occurs pre-mono.
320UnresolvedGenericImpl(rustc_middle::ty::PolyTraitRef<'tcx>),
321}
322323#[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.
328TraitObjectCast(UnvalidatedImplCause<'tcx>, Ty<'tcx>),
329/// Only occurs for consts and statics.
330ContainsFnPtr(DefId, Ty<'tcx>),
331}
332333impl<'tcx> Use<'tcx> {
334fn def_id(self) -> DefId {
335match 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), _) => {
340trait_ref.def_id()
341 }
342 }
343 }
344345fn opt_instance(self) -> Option<Instance<'tcx>> {
346match self.kind {
347 UseKind::FnPtrCast(instance) | UseKind::Called(instance) => Some(instance),
348 UseKind::TraitObjectCast(..) | UseKind::ContainsFnPtr(..) => None,
349 }
350 }
351}