Skip to content

Commit 1230ba3

Browse files
committed
fix mentioned constants with fn ptrs that use failing constants
1 parent 6306c17 commit 1230ba3

7 files changed

+181
-27
lines changed

compiler/rustc_monomorphize/src/collector.rs

+29-27
Original file line numberDiff line numberDiff line change
@@ -447,38 +447,38 @@ fn collect_items_rec<'tcx>(
447447
// hide const-eval errors that those calls would otherwise have triggered.
448448
match starting_item.node {
449449
MonoItem::Static(def_id) => {
450-
assert!(
451-
mode == CollectionMode::UsedItems,
452-
"should never encounter static when collecting mentioned items"
453-
);
454-
let instance = Instance::mono(tcx, def_id);
450+
recursion_depth_reset = None;
455451

456-
// Sanity check whether this ended up being collected accidentally
457-
debug_assert!(should_codegen_locally(tcx, &instance));
452+
// Statics always get evaluted (which is possible because they can't be generic), so for
453+
// `MentionedItems` collection there's nothing to do here.
454+
if mode == CollectionMode::UsedItems {
455+
let instance = Instance::mono(tcx, def_id);
458456

459-
let DefKind::Static { nested, .. } = tcx.def_kind(def_id) else { bug!() };
460-
// Nested statics have no type.
461-
if !nested {
462-
let ty = instance.ty(tcx, ty::ParamEnv::reveal_all());
463-
visit_drop_use(tcx, ty, true, starting_item.span, &mut used_items);
464-
}
457+
// Sanity check whether this ended up being collected accidentally
458+
debug_assert!(should_codegen_locally(tcx, &instance));
465459

466-
recursion_depth_reset = None;
460+
let DefKind::Static { nested, .. } = tcx.def_kind(def_id) else { bug!() };
461+
// Nested statics have no type.
462+
if !nested {
463+
let ty = instance.ty(tcx, ty::ParamEnv::reveal_all());
464+
visit_drop_use(tcx, ty, true, starting_item.span, &mut used_items);
465+
}
467466

468-
if let Ok(alloc) = tcx.eval_static_initializer(def_id) {
469-
for &prov in alloc.inner().provenance().ptrs().values() {
470-
collect_alloc(tcx, prov.alloc_id(), &mut used_items);
467+
if let Ok(alloc) = tcx.eval_static_initializer(def_id) {
468+
for &prov in alloc.inner().provenance().ptrs().values() {
469+
collect_alloc(tcx, prov.alloc_id(), &mut used_items);
470+
}
471471
}
472-
}
473472

474-
if tcx.needs_thread_local_shim(def_id) {
475-
used_items.push(respan(
476-
starting_item.span,
477-
MonoItem::Fn(Instance {
478-
def: InstanceDef::ThreadLocalShim(def_id),
479-
args: GenericArgs::empty(),
480-
}),
481-
));
473+
if tcx.needs_thread_local_shim(def_id) {
474+
used_items.push(respan(
475+
starting_item.span,
476+
MonoItem::Fn(Instance {
477+
def: InstanceDef::ThreadLocalShim(def_id),
478+
args: GenericArgs::empty(),
479+
}),
480+
));
481+
}
482482
}
483483

484484
// mentioned_items stays empty since there's no codegen for statics. statics don't get
@@ -1650,7 +1650,9 @@ fn collect_items_of_instance<'tcx>(
16501650
} else {
16511651
// We only need to evaluate all constants, but can ignore the rest of the MIR.
16521652
for const_op in &body.required_consts {
1653-
collector.eval_constant(const_op);
1653+
if let Some(val) = collector.eval_constant(const_op) {
1654+
collect_const_value(tcx, val, mentioned_items);
1655+
}
16541656
}
16551657
}
16561658

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error[E0080]: evaluation of `Late::<i32>::FAIL` failed
2+
--> $DIR/collect-in-dead-fnptr-in-const.rs:8:22
3+
|
4+
LL | const FAIL: () = panic!();
5+
| ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-fnptr-in-const.rs:8:22
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-fnptr-in-const.rs:9:28
11+
|
12+
LL | const FNPTR: fn() = || Self::FAIL;
13+
| ^^^^^^^^^^
14+
15+
note: the above error was encountered while instantiating `fn Late::<i32>::FNPTR::{closure#0}`
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,20 @@
1+
error[E0080]: evaluation of `Late::<i32>::FAIL` failed
2+
--> $DIR/collect-in-dead-fnptr-in-const.rs:8:22
3+
|
4+
LL | const FAIL: () = panic!();
5+
| ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-fnptr-in-const.rs:8:22
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-fnptr-in-const.rs:9:28
11+
|
12+
LL | const FNPTR: fn() = || Self::FAIL;
13+
| ^^^^^^^^^^
14+
15+
note: the above error was encountered while instantiating `fn Late::<i32>::FNPTR::{closure#0}`
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,33 @@
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 Late<T>(T);
7+
impl<T> Late<T> {
8+
const FAIL: () = panic!(); //~ERROR evaluation of `Late::<i32>::FAIL` failed
9+
const FNPTR: fn() = || Self::FAIL;
10+
}
11+
12+
// This function is not actually called, but it is mentioned in dead code in a function that is
13+
// called. The function then mentions a const that evaluates to a fnptr that points to a function
14+
// that used a const that fails to evaluate.
15+
// This tests that when processing mentioned items, we also check the fnptrs in the final values
16+
// of consts that we encounter.
17+
#[inline(never)]
18+
fn not_called<T>() {
19+
if false {
20+
let _ = Late::<T>::FNPTR;
21+
}
22+
}
23+
24+
#[inline(never)]
25+
fn called<T>() {
26+
if false {
27+
not_called::<T>();
28+
}
29+
}
30+
31+
pub fn main() {
32+
called::<i32>();
33+
}
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-fnptr.rs:8:19
3+
|
4+
LL | const C: () = panic!();
5+
| ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-fnptr.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-fnptr.rs:18: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-fnptr.rs:27:28
17+
|
18+
LL | let _fnptr: fn() = not_called::<T>;
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,23 @@
1+
error[E0080]: evaluation of `Fail::<i32>::C` failed
2+
--> $DIR/collect-in-dead-fnptr.rs:8:19
3+
|
4+
LL | const C: () = panic!();
5+
| ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-fnptr.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-fnptr.rs:18: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-fnptr.rs:27:28
17+
|
18+
LL | let _fnptr: fn() = not_called::<T>;
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,33 @@
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+
// This function is not actually called, but it is mentioned in dead code in a function that is
12+
// called. Make sure we still find this error.
13+
// This relies on mono-item collection checking `required_consts` in functions that syntactically
14+
// are called in collected functions (even inside dead code).
15+
#[inline(never)]
16+
fn not_called<T>() {
17+
if false {
18+
let _ = Fail::<T>::C;
19+
}
20+
}
21+
22+
#[inline(never)]
23+
fn called<T>() {
24+
if false {
25+
// We don't call the function, but turn it to a function pointer.
26+
// Make sure it still gest added to `mentioned_items`.
27+
let _fnptr: fn() = not_called::<T>;
28+
}
29+
}
30+
31+
pub fn main() {
32+
called::<i32>();
33+
}

0 commit comments

Comments
 (0)