Skip to content

Commit b92c2f7

Browse files
committed
fix incorrect param env in dead code lint
1 parent b95852b commit b92c2f7

File tree

5 files changed

+46
-5
lines changed

5 files changed

+46
-5
lines changed

compiler/rustc_passes/src/dead.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,9 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
242242
let &(container, ref indices) =
243243
data.get(expr.hir_id).expect("no offset_of_data for offset_of");
244244

245-
let mut last_did = expr.hir_id.owner.to_def_id();
245+
let body_did = self.typeck_results().hir_owner.to_def_id();
246+
let param_env = self.tcx.param_env(body_did);
247+
246248
let mut current_ty = container;
247249

248250
for &index in indices {
@@ -253,15 +255,14 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
253255
self.insert_def_id(field.did);
254256
let field_ty = field.ty(self.tcx, subst);
255257

256-
last_did = field.did;
257258
current_ty =
258-
self.tcx.normalize_erasing_regions(self.tcx.param_env(field.did), field_ty);
259+
self.tcx.normalize_erasing_regions(param_env, field_ty);
259260
}
260261
// we don't need to mark tuple fields as live,
261262
// but we may need to mark subfields
262263
ty::Tuple(tys) => {
263264
current_ty = self.tcx.normalize_erasing_regions(
264-
self.tcx.param_env(last_did),
265+
param_env,
265266
tys[index.as_usize()],
266267
);
267268
}

library/core/tests/mem.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -458,4 +458,4 @@ fn offset_of_addr() {
458458
assert_eq!(ptr::addr_of!(base).addr() + offset_of!(Foo, y), ptr::addr_of!(base.y).addr());
459459
assert_eq!(ptr::addr_of!(base).addr() + offset_of!(Foo, z.0), ptr::addr_of!(base.z.0).addr());
460460
assert_eq!(ptr::addr_of!(base).addr() + offset_of!(Foo, z.1), ptr::addr_of!(base.z.1).addr());
461-
}
461+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// check-pass
2+
3+
#![feature(offset_of)]
4+
#![deny(dead_code)]
5+
6+
// This struct contains a projection that can only be normalized after getting the field type.
7+
struct A<T: Project> {
8+
a: <T as Project>::EquateParamTo,
9+
}
10+
11+
// This is the inner struct that we want to get.
12+
struct MyFieldIsNotDead {
13+
not_dead: u8,
14+
}
15+
16+
// These are some helpers.
17+
// Inside the param env of `test`, we want to make it so that it considers T=MyFieldIsNotDead.
18+
struct GenericIsEqual<T>(T);
19+
trait Project {
20+
type EquateParamTo;
21+
}
22+
impl<T> Project for GenericIsEqual<T> {
23+
type EquateParamTo = T;
24+
}
25+
26+
fn test<T>() -> usize
27+
where
28+
GenericIsEqual<T>: Project<EquateParamTo = MyFieldIsNotDead>,
29+
{
30+
// The first field of the A that we construct here is `<GenericIsEqual<T>> as Project>::EquateParamTo`.
31+
// Typeck normalizes this and figures that the not_dead field is totally fine and accessible.
32+
// But importantly, the normalization ends up with T, which, as we've declared in our param env is MyFieldDead.
33+
// When we're in the param env of the `a` field, the where bound above is not in scope, so we don't know what T is - it's generic.
34+
// We cannot access a field on T. Boom!
35+
std::mem::offset_of!(A<GenericIsEqual<T>>, a.not_dead)
36+
}
37+
38+
fn main() {
39+
test::<MyFieldIsNotDead>();
40+
}

0 commit comments

Comments
 (0)