1//! Run a post-mono pass on MIR, possibly from other crates.
2//! In post-mono MIR, all functions are possible to resolve to an [`Instance`].
3//!
4//! This traverses the callgraph along function call edges, starting from mono roots, and stopping
5//! if it sees a function that's already been checked. See `rustc_monomorphize::collector` for more
6//! info.
7//!
8//! A "mono root" is an externally reachable function, such as `main`, `pub fn`, or weird things
9//! such as `std::rt::lang_start`.
10//!
11//! There are three functions in play during this pass.
12//! 1. The unvalidated function being called, which we call the 'callee'.
13//! 2. The generic function being instantiated, *which may not be in the current crate*, called the
14//! 'caller'.
15//! 3. The functions that instantiated it (recursively, back to the mono root), which we call the
16//! [`InstantiationSite`].
17//!
18//! ## Recommended reading
19//! - [MIR Debugging](https://rustc-dev-guide.rust-lang.org/mir/debugging.html)
2021use rustc_data_structures::fx::FxHashSet;
22use rustc_data_structures::unord::UnordSet;
23use rustc_hir::def_id::DefId;
24use rustc_hir::{CRATE_HIR_ID, HirId};
25use rustc_middle::mir::visit::Visitoras _;
26use rustc_middle::mir::{
27self, Body, CastKind, Location, Rvalue, SourceScope, Terminator, TerminatorKind,
28};
29use rustc_middle::mono::MonoItem;
30use rustc_middle::span_bug;
31use rustc_middle::ty::adjustment::PointerCoercion;
32use rustc_middle::ty::{
33self, EarlyBinder, GenericArgsRef, Instance, InstanceKind, ShimKind, TyCtxt, TypeFoldable,
34TypingEnv,
35};
36use rustc_span::Span;
37use tracing::{debug, info, trace};
3839use crate::ferrocene::{InstantiateResult, LintState, UnvalidatedImplCause, Use, UseKind};
4041struct LintPostMono<'a, 'tcx> {
42/// The function we are currently traversing.
43instance: Instance<'tcx>,
44/// Its body.
45body: &'a Body<'tcx>,
46 linter: &'a mut LintState<'tcx>,
47/// A list of all functions we have previously traversed.
48 /// This needs to store Instances, not DefIds, because different instantiations may call
49 /// different concrete functions, and we want to make sure we lint all of them.
50visited: &'a mut FxHashSet<Instance<'tcx>>,
51/// A list of all items we are going to traverse.
52 /// This is needed to avoid non-determinism in diagnostics; we don't want `from_instantiation`
53 /// to vary based on iteration order.
54roots: &'a [MonoItem<'tcx>],
55/// May be `None` if this is a mono root.
56from_instantiation: Option<InstantiationSite<'tcx>>,
57}
5859/// Used for diagnostics. See [`post_mono`](self).
60#[derive(#[automatically_derived]
impl<'tcx> ::core::marker::Copy for InstantiationSite<'tcx> { }Copy, #[automatically_derived]
impl<'tcx> ::core::clone::Clone for InstantiationSite<'tcx> {
#[inline]
fn clone(&self) -> InstantiationSite<'tcx> {
let _: ::core::clone::AssertParamIsClone<HirId>;
let _: ::core::clone::AssertParamIsClone<Span>;
let _: ::core::clone::AssertParamIsClone<Instance<'tcx>>;
let _: ::core::clone::AssertParamIsClone<DefId>;
let _: ::core::clone::AssertParamIsClone<Option<DefId>>;
*self
}
}Clone, #[automatically_derived]
impl<'tcx> ::core::fmt::Debug for InstantiationSite<'tcx> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field5_finish(f,
"InstantiationSite", "lint_node", &self.lint_node, "caller_span",
&self.caller_span, "caller_instance", &self.caller_instance,
"pre_mono_callee", &self.pre_mono_callee, "drop_fn",
&&self.drop_fn)
}
}Debug)]
61pub(super) struct InstantiationSite<'tcx> {
62/// NOTE: this points to the call site which causes the callee to be monomorphized.
63pub(super) lint_node: HirId,
64pub(super) caller_span: Span,
65pub(super) caller_instance: Instance<'tcx>,
66/// `callee_instance`, but before we called `expect_instance` on it.
67 /// This may not be the same as `use_.def_id()` if we resolved an associated function
68 /// to an implementation.
69pub(super) pre_mono_callee: DefId,
70pub(super) drop_fn: Option<DefId>,
71}
7273/// Lint all used items recursively, starting from validated roots.
74/// Validated roots are calculated in `rustc_monomorphize::collector::ferrocene`, see there for
75/// details.
76///
77/// We can't depend on anything in rustc_monomorphize here because we're too early in [rustc's
78/// dependency graph](https://rustc-dev-guide.rust-lang.org/compiler-src.html#big-picture). Instead
79/// we call this function in a query override in `rustc_interface`.
80pub fn lint_validated_roots<'tcx>(tcx: TyCtxt<'tcx>, roots: UnordSet<MonoItem<'tcx>>) {
81{
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/post_mono.rs:81",
"rustc_lint::ferrocene::post_mono", ::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/ferrocene/post_mono.rs"),
::tracing_core::__macro_support::Option::Some(81u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::ferrocene::post_mono"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::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!("all roots: {0:?}",
roots) as &dyn ::tracing::field::Value))])
});
} else { ; }
};trace!("all roots: {roots:?}");
8283let mut visited = FxHashSet::default();
8485// We need to sort these for query stability.
86let roots = tcx.with_stable_hashing_context(move |mut hcx| roots.into_sorted(&mut hcx, true));
8788// FIXME: reuse linter across roots so we don't emit duplicate diagnostics.
89 // let linter = LintHelper::new(tcx, local);
90for root in &roots {
91let instance = match *root {
92// global asm is always an exported constraint
93MonoItem::GlobalAsm(..) => continue,
94// NOTE: `mono` panics if item has generics rather than silently doing the wrong thing
95MonoItem::Static(def_id) => Instance::mono(tcx, def_id),
96 MonoItem::Fn(instance) => {
97let def = instance.def_id();
9899// Skip std::rt::lang_start. Technically we could lint on it as if it were the span
100 // of `main`, but the lint would never be useful.
101 // In general we treat all shims as part of the compiler qualification rather than
102 // the standard library certification, since they're only accessible through
103 // language features.
104 // Note that we may not have `lang_start` yet if we're still compiling core.
105if Some(def) == tcx.lang_items().start_fn() {
106continue;
107 } else if !def.is_local() && Some(def) == tcx.entry_fn(()).map(|(id, _)| id) {
108// it's possible to have main functions that came from another crate!
109 // FIXME: do we need to lint this somehow?
110 // i think main is required to be fully monomorphic so we would have checked it
111 // when compiling the dependency?
112continue;
113 }
114 instance
115 }
116 };
117{
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/post_mono.rs:117",
"rustc_lint::ferrocene::post_mono", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/ferrocene/post_mono.rs"),
::tracing_core::__macro_support::Option::Some(117u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::ferrocene::post_mono"),
::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!("linting root: {0:?}",
instance) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("linting root: {instance:?}");
118let def_id = instance.def_id().expect_local();
119if let Some(mut linter) = LintState::new(tcx, def_id) {
120 LintPostMono::visit_instance(&mut linter, &mut visited, &roots, instance, None);
121 }
122 }
123}
124125impl<'a, 'tcx> mir::visit::Visitor<'tcx> for LintPostMono<'a, 'tcx> {
126fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
127if let Some((callee_instance, pre_mono_call)) = self.get_call_def_mir(terminator, location)
128 {
129let use_ = self.use_(UseKind::Called(callee_instance), terminator.source_info.span);
130self.on_edge(use_, terminator.source_info.scope, pre_mono_call);
131 }
132self.super_terminator(terminator, location);
133 }
134135fn visit_rvalue(&mut self, rval: &Rvalue<'tcx>, location: Location) {
136let Some((call_span, use_kind)) = self.find_dynamic_cast(rval) else { return };
137let source_info = self.body.source_info(location);
138let use_ = self.use_(use_kind, call_span);
139self.on_edge(use_, source_info.scope, use_.def_id());
140self.super_rvalue(rval, location);
141 }
142}
143144impl<'a, 'tcx> LintPostMono<'a, 'tcx> {
145fn find_dynamic_cast(&self, rval: &Rvalue<'tcx>) -> Option<(Span, UseKind<'tcx>)> {
146let tcx = self.linter.tcx;
147match rval {
148 Rvalue::Cast(
149 CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer(_), _),
150 operand,
151 _fn_ptr_ty,
152 ) => {
153let call_span = operand.span(self.body);
154let Some((pre_mono_callee, generic_args)) = operand.const_fn_def() else {
155::rustc_middle::util::bug::span_bug_fmt(call_span,
format_args!("don\'t know how to handle ReifyFnPointer cast of non-constant fn {0:?}",
operand));span_bug!(
156 call_span,
157"don't know how to handle ReifyFnPointer cast of non-constant fn {operand:?}"
158);
159 };
160161let callee_instance =
162self.monomorphize_instance(pre_mono_callee, generic_args, call_span);
163// FIXME: want to also check this in THIR pass
164Some((call_span, UseKind::FnPtrCast(callee_instance)))
165 }
166 Rvalue::Cast(
167 CastKind::PointerCoercion(PointerCoercion::Unsize, _),
168 operand,
169 dest_ty,
170 ) => {
171let (source_ty, typing_env) = self.monomorphize_args(operand.ty(self.body, tcx));
172let (dest_ty, _) = self.monomorphize_args(*dest_ty);
173let call_span = operand.span(self.body);
174175let mut try_instantiate = |def_id, args| {
176 InstantiateResult::Resolved(self.monomorphize_instance(def_id, args, call_span))
177 };
178179let use_kind = self.linter.check_dyn_trait_coercion(
180 dest_ty,
181 source_ty,
182 typing_env,
183&mut try_instantiate,
184 call_span,
185 )?;
186Some((call_span, use_kind))
187 }
188_ => None,
189 }
190 }
191192fn use_(&self, kind: UseKind<'tcx>, span: Span) -> Use<'tcx> {
193Use { kind, span, from_instantiation: self.from_instantiation }
194 }
195196fn lint(&mut self, use_: Use<'tcx>, scope: SourceScope) -> HirId {
197// Try to update the lint node if possible, but use the lint node of the caller if the
198 // callee is cross-crate.
199 // FIXME: we have enough info here to show a backtrace of how the function was instantiated,
200 // maybe pass that in so we can show it?
201let lint_node = match scope.lint_root(&self.body.source_scopes) {
202Some(node) => node,
203None => match self.from_instantiation.as_ref() {
204// This is a bit odd - we use the HIR id of the caller function,
205 // not the callee that actually caused the error.
206 // The callee is in another crate so we don't have any choice here.
207Some(local) => local.lint_node,
208// A local root can resolve to a cross-crate instantiation when a MIR inline pass runs.
209 // We don't have anywhere to point to, so just point to the crate root.
210None => CRATE_HIR_ID,
211 },
212 };
213214// Lint this use.
215self.linter.check_use(lint_node, use_);
216217lint_node218 }
219220fn on_edge(&mut self, use_: Use<'tcx>, scope: SourceScope, pre_mono_callee: DefId) {
221let lint_node = self.lint(use_, scope);
222223// Recurse into the instantiated call.
224let callee_instance = match use_.kind {
225 UseKind::TraitObjectCast(
226 UnvalidatedImplCause::UnresolvedGenericImpl(trait_ref),
227 source_ty,
228 ) => ::rustc_middle::util::bug::span_bug_fmt(use_.span,
format_args!("failed to resolve generic parameters in cast from {0:?} -> {1:?}",
source_ty, trait_ref))span_bug!(
229 use_.span,
230"failed to resolve generic parameters in cast from {source_ty:?} -> {trait_ref:?}",
231 ),
232// This can happen if we see a function like the following:
233 // ```rust
234 // fn foo<T, I: Iterator<Item = T> + 'static>(x: I) -> Box<dyn Iterator<Item = T>> {
235 // Box::new(x)
236 // }
237 //
238 // fn main() {
239 // let v = foo(std::iter::once(1)).collect::<Vec<_>>();
240 // }
241 // ```
242 // Here, we will notice a TraitObjectCast when we cast `x` to `dyn Iterator`,
243 // getting back a DefId for `<iter::Once as Iterator>::collect` or something like that.
244 // But we are not guaranteed that `collect` is fully monomorphized, because we can
245 // still choose its generic parameters at the call site; we won't know until we check
246 // `main`.
247 //
248 // Therefore we don't have an instance and can't check its body.
249UseKind::TraitObjectCast(UnvalidatedImplCause::AssocFn(_), _) => return,
250// In any other case we should have fully monomorphized the function.
251_ => use_.opt_instance().unwrap_or_else(|| {
252::rustc_middle::util::bug::span_bug_fmt(use_.span,
format_args!("called expect_instance on a THIR-only lint kind"))span_bug!(use_.span, "called expect_instance on a THIR-only lint kind")253 }),
254 };
255256// Keep the call span for diagnostics.
257let site = if Some(self.instance.def_id()) == self.linter.tcx.lang_items().drop_glue_fn() {
258// We want to show a better span; drop_in_place is never interesting since the body is
259 // synthesized by a MIR shim anyway.
260 // Note that we saw it, though, so diagnostics can say "dropped here".
261InstantiationSite { drop_fn: Some(use_.def_id()), ..self.from_instantiation.unwrap() }
262 } else {
263InstantiationSite {
264 drop_fn: None,
265lint_node,
266 caller_instance: self.instance,
267 caller_span: use_.span,
268pre_mono_callee,
269 }
270 };
271272if self.roots.contains(&MonoItem::Fn(callee_instance)) {
273{
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/post_mono.rs:273",
"rustc_lint::ferrocene::post_mono", ::tracing::Level::INFO,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/ferrocene/post_mono.rs"),
::tracing_core::__macro_support::Option::Some(273u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::ferrocene::post_mono"),
::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!("don\'t need to recurse into {0:?}, we\'ll lint it separately",
callee_instance) as &dyn ::tracing::field::Value))])
});
} else { ; }
};info!("don't need to recurse into {callee_instance:?}, we'll lint it separately");
274return;
275 }
276277{
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/post_mono.rs:277",
"rustc_lint::ferrocene::post_mono", ::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/ferrocene/post_mono.rs"),
::tracing_core::__macro_support::Option::Some(277u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::ferrocene::post_mono"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::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!("recurse into {0:?}, lint_node={1:?}",
callee_instance, lint_node) as
&dyn ::tracing::field::Value))])
});
} else { ; }
};trace!("recurse into {callee_instance:?}, lint_node={lint_node:?}");
278LintPostMono::visit_instance(
279self.linter,
280self.visited,
281self.roots,
282callee_instance,
283Some(site),
284 );
285 }
286287fn visit_instance(
288 linter: &'a mut LintState<'tcx>,
289 visited: &mut FxHashSet<Instance<'tcx>>,
290 roots: &'a [MonoItem<'tcx>],
291mut instance: Instance<'tcx>,
292 from_instantiation: Option<InstantiationSite<'tcx>>,
293 ) {
294let tcx = linter.tcx;
295let owner = instance.def_id();
296297if let Some(intrinsic) = tcx.intrinsic(owner) {
298if intrinsic.must_be_overridden {
299// Instrinsics with no fallback body are qualified as part of the compiler,
300 // and will panic in `instance_mir`.
301{
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/post_mono.rs:301",
"rustc_lint::ferrocene::post_mono", ::tracing::Level::INFO,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/ferrocene/post_mono.rs"),
::tracing_core::__macro_support::Option::Some(301u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::ferrocene::post_mono"),
::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 intrinsic {0:?}",
owner) as &dyn ::tracing::field::Value))])
});
} else { ; }
};info!("ignoring intrinsic {owner:?}");
302return;
303 }
304305// See equivalent code in `rustc_monomorphize::collector::visit_instance_use`.
306if tcx.sess.replaced_intrinsics.contains(&intrinsic.name) {
307// This is normal: LLVM in particular has specialized overrides for many
308 // integer operations. But that means the fallback body won't actually be
309 // used, so don't try to check it.
310{
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/post_mono.rs:310",
"rustc_lint::ferrocene::post_mono", ::tracing::Level::INFO,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/ferrocene/post_mono.rs"),
::tracing_core::__macro_support::Option::Some(310u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::ferrocene::post_mono"),
::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 overridden intrinsic body for {0:?}",
owner) as &dyn ::tracing::field::Value))])
});
} else { ; }
};info!("ignoring overridden intrinsic body for {owner:?}");
311return;
312 }
313314{
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/post_mono.rs:314",
"rustc_lint::ferrocene::post_mono", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/ferrocene/post_mono.rs"),
::tracing_core::__macro_support::Option::Some(314u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::ferrocene::post_mono"),
::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!("using fallback body for {0:?}",
owner) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("using fallback body for {owner:?}");
315instance = ty::Instance::new_raw(owner, instance.args);
316 } else if !tcx.is_mir_available(owner) {
317// We've already compiled this item in a previous crate and we didn't save the
318 // MIR between crates.
319 // We must have checked the item when it was compiled, so just ignore it.
320{
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/post_mono.rs:320",
"rustc_lint::ferrocene::post_mono", ::tracing::Level::INFO,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/ferrocene/post_mono.rs"),
::tracing_core::__macro_support::Option::Some(320u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::ferrocene::post_mono"),
::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!("no MIR for {0:?}",
owner) as &dyn ::tracing::field::Value))])
});
} else { ; }
};info!("no MIR for {owner:?}");
321return;
322 }
323324if !visited.insert(instance) {
325// We've already linted this instance (or maybe we're still halfway through linting it).
326 // Don't loop forever.
327 //
328 // NOTE: this means that `-Z deduplicate-diagnostics=no` doesn't work properly for
329 // post-mono errors. I think this isn't worth fixing; just use separate test files if
330 // you need to test the same instance being instantiated more than once.
331 //
332 // NOTE: because of the funny way we calculate lint nodes, this means that if the same
333 // item is instantiated in multiple places, only the lint level of the first
334 // instantiation will be respected. It might be possible to fix this by caching the
335 // lint level in addition to the instance itself?
336{
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/post_mono.rs:336",
"rustc_lint::ferrocene::post_mono", ::tracing::Level::INFO,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/ferrocene/post_mono.rs"),
::tracing_core::__macro_support::Option::Some(336u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::ferrocene::post_mono"),
::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!("already linted {0:?}",
instance) as &dyn ::tracing::field::Value))])
});
} else { ; }
};info!("already linted {instance:?}");
337return;
338 }
339340let body = tcx.instance_mir(instance.def);
341{
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/post_mono.rs:341",
"rustc_lint::ferrocene::post_mono", ::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/ferrocene/post_mono.rs"),
::tracing_core::__macro_support::Option::Some(341u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::ferrocene::post_mono"),
::tracing_core::field::FieldSet::new(&["message",
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("body")
}> =
::tracing::__macro_support::FieldName::new("body");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::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!("visiting body")
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&body)
as &dyn ::tracing::field::Value))])
});
} else { ; }
};trace!(body = ?body, "visiting body");
342let mut this = LintPostMono { linter, visited, roots, instance, body, from_instantiation };
343for (bb, data) in mir::traversal::preorder(body) {
344 this.visit_basic_block_data(bb, data);
345 }
346347// If the MIR inliner ran, we may not see all original function calls.
348 // Usually these are preserved in the source scopes for each statement, but if the
349 // inliner has completely deleted every statement in the body we can't rely on that.
350 // Iterate through every source scope we know about just in case.
351for (scope, scope_data) in body.source_scopes.iter_enumerated() {
352{
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/post_mono.rs:352",
"rustc_lint::ferrocene::post_mono", ::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/ferrocene/post_mono.rs"),
::tracing_core::__macro_support::Option::Some(352u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::ferrocene::post_mono"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::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!("saw scope {0:?}",
scope_data) as &dyn ::tracing::field::Value))])
});
} else { ; }
};trace!("saw scope {scope_data:?}");
353if let Some((instance, span)) = scope_data.inlined {
354{
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/post_mono.rs:354",
"rustc_lint::ferrocene::post_mono", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/ferrocene/post_mono.rs"),
::tracing_core::__macro_support::Option::Some(354u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::ferrocene::post_mono"),
::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!("saw inlined instance {0:?}",
instance) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("saw inlined instance {instance:?}");
355let use_ = this.use_(UseKind::Called(instance), span);
356// NOTE: we can't use `on_edge` here because it won't properly substitute generic
357 // parameters when it recurses. That's ok: since we're visiting every source scope in
358 // this body, we'll catch all the other inlined calls when we see their `scope_data`.
359this.lint(use_, scope);
360 }
361 }
362 }
363364fn get_call_def_mir(
365&self,
366 terminator: &Terminator<'tcx>,
367 _loc: Location,
368 ) -> Option<(Instance<'tcx>, DefId)> {
369let tcx = self.linter.tcx;
370let span = terminator.source_info.span;
371372let (pre_mono_call, call_instance) = match &terminator.kind {
373 TerminatorKind::Call { func, .. } | TerminatorKind::TailCall { func, .. } => {
374let Some((pre_mono_call, generic_args)) = func.const_fn_def() else {
375match func.ty(self.body, tcx).kind() {
376 kind @ ty::FnDef(..) => {
377::rustc_middle::util::bug::span_bug_fmt(span,
format_args!("{0:?} should have been a const_fn_def?", kind))span_bug!(span, "{kind:?} should have been a const_fn_def?")378 }
379// ok: see reasoning in THIR pass, we have checks to ensure all function
380 // pointers we can get came from a validated function.
381ty::FnPtr(..) => {}
382_ => {
383// If this is anything other than a function item, it can't have generics and
384 // therefore must have been checked by the THIR pass.
385 // FIXME: are we sure is this true when we're passed an `impl Fn`?
386tcx.dcx()
387 .span_delayed_bug(span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("called a non-function? {0:?}",
func))
})format!("called a non-function? {func:?}"));
388 }
389 }
390{
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/post_mono.rs:390",
"rustc_lint::ferrocene::post_mono", ::tracing::Level::INFO,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/ferrocene/post_mono.rs"),
::tracing_core::__macro_support::Option::Some(390u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::ferrocene::post_mono"),
::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 call to non-constant function {0:?}",
func) as &dyn ::tracing::field::Value))])
});
} else { ; }
};info!("ignoring call to non-constant function {func:?}");
391return None;
392 };
393let mut instance = self.monomorphize_instance(pre_mono_call, generic_args, span);
394if #[allow(non_exhaustive_omitted_patterns)] match instance.def {
InstanceKind::Virtual(..) => true,
_ => false,
}matches!(instance.def, InstanceKind::Virtual(..)) {
395// This is a call through a vtable: (x as dyn Trait).foo().
396 // We don't know what instance `foo` resolves too, but we linted earlier when
397 // `x` was cast to `dyn Trait`, so we can assume this call here is ok.
398 // See the reasoning in THIR about function pointers.
399return None;
400 }
401402// Look for `<T as Fn>::call` for some T.
403 // If T is a function type, the compiler synthesizes an impl, so we'll check
404 // the trait declaration in libcore which isn't what we want. Check if the
405 // function is annotated instead.
406if let InstanceKind::Shim(ShimKind::FnPtr(_, ty) | ShimKind::FnPtrAddr(_, ty)) =
407instance.def
408 && let ty::FnDef(fn_item, fn_args) = ty.kind()
409 {
410{
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/post_mono.rs:410",
"rustc_lint::ferrocene::post_mono", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/ferrocene/post_mono.rs"),
::tracing_core::__macro_support::Option::Some(410u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::ferrocene::post_mono"),
::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!("found function item {0:?}",
fn_item) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("found function item {fn_item:?}");
411instance = self.monomorphize_instance(
412*fn_item,
413fn_args.no_bound_vars().unwrap(),
414span,
415 );
416 }
417418 (pre_mono_call, instance)
419 }
420 TerminatorKind::Drop { place, .. } => {
421let (ty, _) = self.monomorphize_args(place.ty(self.body, tcx));
422let instance = Instance::resolve_drop_glue(tcx, ty.ty);
423if #[allow(non_exhaustive_omitted_patterns)] match instance.def {
InstanceKind::Shim(ShimKind::DropGlue(_, None)) => true,
_ => false,
}matches!(instance.def, InstanceKind::Shim(ShimKind::DropGlue(_, None))) {
424{
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/post_mono.rs:424",
"rustc_lint::ferrocene::post_mono", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/ferrocene/post_mono.rs"),
::tracing_core::__macro_support::Option::Some(424u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::ferrocene::post_mono"),
::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!("ty `{0:?}` does not need to be dropped",
ty) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("ty `{ty:?}` does not need to be dropped");
425return None;
426 }
427{
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/post_mono.rs:427",
"rustc_lint::ferrocene::post_mono", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/ferrocene/post_mono.rs"),
::tracing_core::__macro_support::Option::Some(427u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::ferrocene::post_mono"),
::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!("resolve drop glue => instance={0:?}, ty={1:?}",
instance, ty) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("resolve drop glue => instance={instance:?}, ty={ty:?}");
428let drop_glue = tcx.lang_items().drop_glue_fn().unwrap();
429 (drop_glue, instance)
430 }
431_ => return None,
432 };
433434Some((call_instance, pre_mono_call))
435 }
436437fn monomorphize_instance(
438&self,
439 def_id: DefId,
440 generic_args: GenericArgsRef<'tcx>,
441 span: Span,
442 ) -> Instance<'tcx> {
443let (mono_args, typing_env) = self.monomorphize_args(generic_args);
444Instance::expect_resolve(self.linter.tcx, typing_env, def_id, mono_args, span)
445 }
446447fn monomorphize_args<T>(&self, generic_args: T) -> (T, TypingEnv<'tcx>)
448where
449T: TypeFoldable<TyCtxt<'tcx>>,
450 {
451let tcx = self.linter.tcx;
452453let env = TypingEnv::codegen(tcx, self.linter.item);
454let args = self.instance.instantiate_mir_and_normalize_erasing_regions(
455tcx,
456env,
457EarlyBinder::bind(tcx, generic_args),
458 );
459 (args, env)
460 }
461}