Skip to content

Commit 3a7e4b8

Browse files
committed
Fix-forward for mir-inlining
plus other minor fixes
1 parent 5a3e3bd commit 3a7e4b8

4 files changed

Lines changed: 118 additions & 10 deletions

File tree

compiler/rustc_lint/src/ferrocene/post_mono.rs

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use rustc_hir::def_id::DefId;
2424
use rustc_hir::{CRATE_HIR_ID, HirId};
2525
use rustc_middle::mir::visit::Visitor as _;
2626
use rustc_middle::mir::{
27-
self, Body, CastKind, ClearCrossCrate, Location, Rvalue, SourceInfo, Terminator, TerminatorKind,
27+
self, Body, CastKind, Location, Rvalue, SourceScope, Terminator, TerminatorKind,
2828
};
2929
use rustc_middle::mono::MonoItem;
3030
use rustc_middle::span_bug;
@@ -126,15 +126,17 @@ impl<'a, 'tcx> mir::visit::Visitor<'tcx> for LintPostMono<'a, 'tcx> {
126126
if let Some((callee_instance, pre_mono_call)) = self.get_call_def_mir(terminator, location)
127127
{
128128
let use_ = self.use_(UseKind::Called(callee_instance), terminator.source_info.span);
129-
self.on_edge(use_, &terminator.source_info, pre_mono_call);
129+
self.on_edge(use_, terminator.source_info.scope, pre_mono_call);
130130
}
131+
self.super_terminator(terminator, location);
131132
}
132133

133134
fn visit_rvalue(&mut self, rval: &Rvalue<'tcx>, location: Location) {
134135
let Some((call_span, use_kind)) = self.find_dynamic_cast(rval) else { return };
135136
let source_info = self.body.source_info(location);
136137
let use_ = self.use_(use_kind, call_span);
137-
self.on_edge(use_, source_info, use_.def_id());
138+
self.on_edge(use_, source_info.scope, use_.def_id());
139+
self.super_rvalue(rval, location);
138140
}
139141
}
140142

@@ -190,16 +192,14 @@ impl<'a, 'tcx> LintPostMono<'a, 'tcx> {
190192
Use { kind, span, from_instantiation: self.from_instantiation }
191193
}
192194

193-
fn on_edge(&mut self, use_: Use<'tcx>, source_info: &SourceInfo, pre_mono_callee: DefId) {
195+
fn lint(&mut self, use_: Use<'tcx>, scope: SourceScope) -> HirId {
194196
// Try to update the lint node if possible, but use the lint node of the caller if the
195197
// callee is cross-crate.
196198
// FIXME: we have enough info here to show a backtrace of how the function was instantiated,
197199
// maybe pass that in so we can show it?
198-
let lint_node = match self.body.source_scopes[source_info.scope].local_data.as_ref() {
199-
ClearCrossCrate::Set(data) => data.lint_root,
200-
// We assume that all roots come from the current crate.
201-
// This is checked earlier in `lint_validated_roots`.
202-
ClearCrossCrate::Clear => match self.from_instantiation.as_ref() {
200+
let lint_node = match scope.lint_root(&self.body.source_scopes) {
201+
Some(node) => node,
202+
None => match self.from_instantiation.as_ref() {
203203
// This is a bit odd - we use the HIR id of the caller function,
204204
// not the callee that actually caused the error.
205205
// The callee is in another crate so we don't have any choice here.
@@ -213,6 +213,12 @@ impl<'a, 'tcx> LintPostMono<'a, 'tcx> {
213213
// Lint this use.
214214
self.linter.check_use(lint_node, use_);
215215

216+
lint_node
217+
}
218+
219+
fn on_edge(&mut self, use_: Use<'tcx>, scope: SourceScope, pre_mono_callee: DefId) {
220+
let lint_node = self.lint(use_, scope);
221+
216222
// Recurse into the instantiated call.
217223
let callee_instance = match use_.kind {
218224
UseKind::TraitObjectCast(
@@ -333,10 +339,27 @@ impl<'a, 'tcx> LintPostMono<'a, 'tcx> {
333339
}
334340

335341
let body = tcx.instance_mir(instance.def);
342+
trace!(body = ?body, "visiting body");
336343
let mut this = LintPostMono { linter, visited, roots, instance, body, from_instantiation };
337-
for (bb, data) in mir::traversal::reachable(body) {
344+
for (bb, data) in mir::traversal::preorder(body) {
338345
this.visit_basic_block_data(bb, data);
339346
}
347+
348+
// If the MIR inliner ran, we may not see all original function calls.
349+
// Usually these are preserved in the source scopes for each statement, but if the
350+
// inliner has completely deleted every statement in the body we can't rely on that.
351+
// Iterate through every source scope we know about just in case.
352+
for (scope, scope_data) in body.source_scopes.iter_enumerated() {
353+
trace!("saw scope {scope_data:?}");
354+
if let Some((instance, span)) = scope_data.inlined {
355+
debug!("saw inlined instance {instance:?}");
356+
let use_ = this.use_(UseKind::Called(instance), span);
357+
// NOTE: we can't use `on_edge` here because it won't properly substitute generic
358+
// parameters when it recurses. That's ok: since we're visiting every source scope in
359+
// this body, we'll catch all the other inlined calls when we see their `scope_data`.
360+
this.lint(use_, scope);
361+
}
362+
}
340363
}
341364

342365
fn get_call_def_mir(
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
error: validated function calls an unvalidated method
2+
--> $DIR/mir-inlining.rs:17:5
3+
|
4+
LL | f(x);
5+
| ^^^^
6+
|
7+
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
8+
|
9+
= note: `<fn(u32) -> u32 {trailing_ones} as FnOnce<(u32,)>>::call_once` is unvalidated
10+
|
11+
= help: contact Ferrocene support to see if this method is possible to certify
12+
note: `main` is validated
13+
--> $DIR/mir-inlining.rs:25:4
14+
|
15+
LL | fn main() {
16+
| ^^^^
17+
= note: main functions are assumed to be validated
18+
note: the lint level is defined here
19+
--> $DIR/mir-inlining.rs:8:9
20+
|
21+
LL | #![deny(ferrocene::unvalidated)]
22+
| ^^^^^^^^^^^^^^^^^^^^^^
23+
24+
error: validated function calls an unvalidated function
25+
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
26+
|
27+
::: $DIR/mir-inlining.rs:11:14
28+
|
29+
LL | pub const fn trailing_ones(_: u32) -> u32 {
30+
| ------------- `trailing_ones` is unvalidated
31+
32+
error: aborting due to 2 previous errors
33+
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
error: validated function calls an unvalidated function
2+
--> $DIR/mir-inlining.rs:17:5
3+
|
4+
LL | pub const fn trailing_ones(_: u32) -> u32 {
5+
| ------------- `trailing_ones` is unvalidated
6+
...
7+
LL | f(x);
8+
| ^^^^
9+
|
10+
note: `main` is validated
11+
--> $DIR/mir-inlining.rs:25:4
12+
|
13+
LL | fn main() {
14+
| ^^^^
15+
LL | call(123_u32, trailing_ones);
16+
| ---------------------------- generic function `call` instantiated by `main`
17+
= note: main functions are assumed to be validated
18+
note: the lint level is defined here
19+
--> $DIR/mir-inlining.rs:8:9
20+
|
21+
LL | #![deny(ferrocene::unvalidated)]
22+
| ^^^^^^^^^^^^^^^^^^^^^^
23+
24+
error: aborting due to 1 previous error
25+
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//@ revisions: thir post-mono post-mono-inlining
2+
//@[thir] check-pass
3+
//@[post-mono] build-fail
4+
//@[post-mono] compile-flags: -Z inline-mir=no
5+
//@[post-mono-inlining] build-fail
6+
//@[post-mono-inlining] compile-flags: -Z inline-mir=yes
7+
8+
#![deny(ferrocene::unvalidated)]
9+
10+
#[inline(always)]
11+
pub const fn trailing_ones(_: u32) -> u32 {
12+
0
13+
}
14+
15+
#[ferrocene::prevalidated]
16+
fn call(x: u32, f: impl FnOnce(u32) -> u32) {
17+
f(x);
18+
//[post-mono]~^ ERROR unvalidated
19+
//[post-mono-inlining]~^^ ERROR unvalidated
20+
// This error points to `<{trailing_ones} as FnOnce>::call_once`, which kinda sucks, but it's
21+
// ok for now.
22+
//[post-mono-inlining]~? ERROR unvalidated
23+
}
24+
25+
fn main() {
26+
call(123_u32, trailing_ones);
27+
}

0 commit comments

Comments
 (0)