Skip to content

Commit 82b44c3

Browse files
committed
mentioned_items: walk all types, not just consts
1 parent 33d2d93 commit 82b44c3

10 files changed

+172
-12
lines changed

compiler/rustc_middle/src/mir/mod.rs

+12
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ use std::ops::{Index, IndexMut};
4545
use std::{iter, mem};
4646

4747
pub use self::query::*;
48+
use self::visit::TyContext;
4849
pub use basic_blocks::BasicBlocks;
4950

5051
mod basic_blocks;
@@ -607,6 +608,17 @@ impl<'tcx> Body<'tcx> {
607608
}
608609
}
609610

611+
pub fn span_for_ty_context(&self, ty_context: TyContext) -> Span {
612+
match ty_context {
613+
TyContext::UserTy(span) => span,
614+
TyContext::ReturnTy(source_info)
615+
| TyContext::LocalDecl { source_info, .. }
616+
| TyContext::YieldTy(source_info)
617+
| TyContext::ResumeTy(source_info) => source_info.span,
618+
TyContext::Location(loc) => self.source_info(loc).span,
619+
}
620+
}
621+
610622
/// Returns the return type; it always return first element from `local_decls` array.
611623
#[inline]
612624
pub fn return_ty(&self) -> Ty<'tcx> {

compiler/rustc_mir_transform/src/mentioned_items.rs

+10-10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use rustc_middle::mir::visit::Visitor;
2-
use rustc_middle::mir::{self, ConstOperand, Location, MentionedItem, MirPass};
2+
use rustc_middle::mir::{self, Location, MentionedItem, MirPass};
3+
use rustc_middle::ty::Ty;
34
use rustc_middle::ty::{self, adjustment::PointerCoercion, TyCtxt};
45
use rustc_session::Session;
56
use rustc_span::source_map::Spanned;
@@ -30,22 +31,21 @@ impl<'tcx> MirPass<'tcx> for MentionedItems {
3031
}
3132

3233
impl<'tcx> Visitor<'tcx> for MentionedItemsVisitor<'_, 'tcx> {
33-
fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, _: Location) {
34-
let const_ = constant.const_;
35-
// This is how function items get referenced: via constants of `FnDef` type. This handles
36-
// both functions that are called and those that are just turned to function pointers.
37-
if let ty::FnDef(def_id, args) = const_.ty().kind() {
34+
fn visit_ty(&mut self, ty: Ty<'tcx>, ty_context: mir::visit::TyContext) {
35+
if let ty::FnDef(def_id, args) = ty.kind() {
3836
debug!("adding to required_items: {def_id:?}");
39-
self.mentioned_items
40-
.push(Spanned { node: MentionedItem::Fn(*def_id, args), span: constant.span });
37+
self.mentioned_items.push(Spanned {
38+
node: MentionedItem::Fn(*def_id, args),
39+
span: self.body.span_for_ty_context(ty_context),
40+
});
4141
}
4242
}
4343

4444
fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
4545
self.super_terminator(terminator, location);
4646
match terminator.kind {
4747
// We don't need to handle `Call` as we already handled all function type operands in
48-
// `visit_constant`. But we do need to handle `Drop`.
48+
// `visit_ty`. But we do need to handle `Drop`.
4949
mir::TerminatorKind::Drop { place, .. } => {
5050
let ty = place.ty(self.body, self.tcx).ty;
5151
let span = self.body.source_info(location).span;
@@ -90,7 +90,7 @@ impl<'tcx> Visitor<'tcx> for MentionedItemsVisitor<'_, 'tcx> {
9090
_ => bug!(),
9191
}
9292
}
93-
// Function pointer casts are already handled by `visit_constant` above.
93+
// Function pointer casts are already handled by `visit_ty` above.
9494
_ => {}
9595
}
9696
}

tests/ui/consts/required-consts/collect-in-dead-closure.opt.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ note: the above error was encountered while instantiating `fn not_called::<i32>`
1616
--> $DIR/collect-in-dead-closure.rs:23:33
1717
|
1818
LL | let _closure: fn() = || not_called::<T>();
19-
| ^^^^^^^^^^^^^^^
19+
| ^^^^^^^^^^^^^^^^^
2020

2121
error: aborting due to 1 previous error
2222

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error[E0080]: evaluation of `Fail::<i32>::C` failed
2+
--> $DIR/collect-in-dead-fn-behind-generic.rs:8:19
3+
|
4+
LL | const C: () = panic!();
5+
| ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-fn-behind-generic.rs:8:19
6+
|
7+
= note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
8+
9+
note: erroneous constant encountered
10+
--> $DIR/collect-in-dead-fn-behind-generic.rs:13:17
11+
|
12+
LL | let _ = Fail::<T>::C;
13+
| ^^^^^^^^^^^^
14+
15+
note: the above error was encountered while instantiating `fn not_called::<i32>`
16+
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
17+
18+
error: aborting due to 1 previous error
19+
20+
For more information about this error, try `rustc --explain E0080`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
error[E0080]: evaluation of `Fail::<i32>::C` failed
2+
--> $DIR/collect-in-dead-fn-behind-generic.rs:8:19
3+
|
4+
LL | const C: () = panic!();
5+
| ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-fn-behind-generic.rs:8:19
6+
|
7+
= note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
8+
9+
note: erroneous constant encountered
10+
--> $DIR/collect-in-dead-fn-behind-generic.rs:13:17
11+
|
12+
LL | let _ = Fail::<T>::C;
13+
| ^^^^^^^^^^^^
14+
15+
note: the above error was encountered while instantiating `fn not_called::<i32>`
16+
--> $DIR/collect-in-dead-fn-behind-generic.rs:25:9
17+
|
18+
LL | callit_not(not_called::<i32>)
19+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
20+
21+
error: aborting due to 1 previous error
22+
23+
For more information about this error, try `rustc --explain E0080`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//@revisions: noopt opt
2+
//@ build-fail
3+
//@[opt] compile-flags: -O
4+
//! This fails without optimizations, so it should also fail with optimizations.
5+
6+
struct Fail<T>(T);
7+
impl<T> Fail<T> {
8+
const C: () = panic!(); //~ERROR evaluation of `Fail::<i32>::C` failed
9+
}
10+
11+
fn not_called<T>() {
12+
if false {
13+
let _ = Fail::<T>::C;
14+
}
15+
}
16+
17+
fn callit_not(f: impl Fn()) {
18+
if false {
19+
f();
20+
}
21+
}
22+
23+
fn main() {
24+
if false {
25+
callit_not(not_called::<i32>)
26+
}
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error[E0080]: evaluation of `m::Fail::<i32>::C` failed
2+
--> $DIR/collect-in-dead-fn-behind-opaque-type.rs:10:23
3+
|
4+
LL | const C: () = panic!();
5+
| ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-fn-behind-opaque-type.rs:10:23
6+
|
7+
= note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
8+
9+
note: erroneous constant encountered
10+
--> $DIR/collect-in-dead-fn-behind-opaque-type.rs:17:21
11+
|
12+
LL | let _ = Fail::<T>::C;
13+
| ^^^^^^^^^^^^
14+
15+
note: the above error was encountered while instantiating `fn m::not_called::<i32>`
16+
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
17+
18+
error: aborting due to 1 previous error
19+
20+
For more information about this error, try `rustc --explain E0080`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
error[E0080]: evaluation of `m::Fail::<i32>::C` failed
2+
--> $DIR/collect-in-dead-fn-behind-opaque-type.rs:10:23
3+
|
4+
LL | const C: () = panic!();
5+
| ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-fn-behind-opaque-type.rs:10:23
6+
|
7+
= note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
8+
9+
note: erroneous constant encountered
10+
--> $DIR/collect-in-dead-fn-behind-opaque-type.rs:17:21
11+
|
12+
LL | let _ = Fail::<T>::C;
13+
| ^^^^^^^^^^^^
14+
15+
note: the above error was encountered while instantiating `fn m::not_called::<i32>`
16+
--> $DIR/collect-in-dead-fn-behind-opaque-type.rs:32:42
17+
|
18+
LL | let x: m::NotCalledFn = unsafe { std::mem::transmute(()) };
19+
| ^^^^^^^^^^^^^^^^^^^^^^^
20+
21+
error: aborting due to 1 previous error
22+
23+
For more information about this error, try `rustc --explain E0080`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//@revisions: noopt opt
2+
//@ build-fail
3+
//@[opt] compile-flags: -O
4+
//! This fails without optimizations, so it should also fail with optimizations.
5+
#![feature(type_alias_impl_trait)]
6+
7+
mod m {
8+
struct Fail<T>(T);
9+
impl<T> Fail<T> {
10+
const C: () = panic!(); //~ERROR evaluation of `m::Fail::<i32>::C` failed
11+
}
12+
13+
pub type NotCalledFn = impl Fn();
14+
15+
fn not_called<T>() {
16+
if false {
17+
let _ = Fail::<T>::C;
18+
}
19+
}
20+
21+
fn mk_not_called() -> NotCalledFn {
22+
not_called::<i32>
23+
}
24+
}
25+
26+
fn main() {
27+
// This does not involve a constant of `FnDef` type, it generates the value via unsafe
28+
// shenanigans instead. This ensures that we check all `FnDef` types that occur in a function,
29+
// not just those of constants. Furthermore the `FnDef` is behind an opaque type which bust be
30+
// normalized away to reveal the function type.
31+
if false {
32+
let x: m::NotCalledFn = unsafe { std::mem::transmute(()) };
33+
x();
34+
}
35+
}

tests/ui/consts/required-consts/collect-in-dead-fn.opt.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ note: the above error was encountered while instantiating `fn not_called::<i32>`
1616
--> $DIR/collect-in-dead-fn.rs:25:9
1717
|
1818
LL | not_called::<T>();
19-
| ^^^^^^^^^^^^^^^
19+
| ^^^^^^^^^^^^^^^^^
2020

2121
error: aborting due to 1 previous error
2222

0 commit comments

Comments
 (0)