Auto merge of #140590 - lcnr:closure-in-dead-code, r=compiler-errors · rust-lang/rust@e9f8103 (original) (raw)

11 files changed

lines changed

Original file line number Diff line number Diff line change
@@ -127,6 +127,14 @@ fn mir_borrowck(
127 127 Ok(tcx.arena.alloc(opaque_types))
128 128 } else {
129 129 let mut root_cx = BorrowCheckRootCtxt::new(tcx, def);
130 +// We need to manually borrowck all nested bodies from the HIR as
131 +// we do not generate MIR for dead code. Not doing so causes us to
132 +// never check closures in dead code.
133 +let nested_bodies = tcx.nested_bodies_within(def);
134 +for def_id in nested_bodies {
135 + root_cx.get_or_insert_nested(def_id);
136 +}
137 +
130 138 let PropagatedBorrowCheckResults { closure_requirements, used_mut_upvars } =
131 139 do_mir_borrowck(&mut root_cx, def, None).0;
132 140 debug_assert!(closure_requirements.is_none());
Original file line number Diff line number Diff line change
@@ -62,7 +62,10 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> {
62 62 self.tainted_by_errors = Some(guar);
63 63 }
64 64
65 -fn get_or_insert_nested(&mut self, def_id: LocalDefId) -> &PropagatedBorrowCheckResults<'tcx> {
65 +pub(super) fn get_or_insert_nested(
66 +&mut self,
67 +def_id: LocalDefId,
68 +) -> &PropagatedBorrowCheckResults<'tcx> {
66 69 debug_assert_eq!(
67 70 self.tcx.typeck_root_def_id(def_id.to_def_id()),
68 71 self.root_def_id.to_def_id()
Original file line number Diff line number Diff line change
@@ -387,7 +387,7 @@ rustc_queries! {
387 387 }
388 388 }
389 389
390 - query stalled_generators_within(
390 + query nested_bodies_within(
391 391 key: LocalDefId
392 392 ) -> &'tcx ty::List<LocalDefId> {
393 393 desc {
Original file line number Diff line number Diff line change
@@ -691,15 +691,17 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
691 691 self.opaque_types_defined_by(defining_anchor)
692 692 }
693 693
694 -fn opaque_types_and_generators_defined_by(
694 +fn opaque_types_and_coroutines_defined_by(
695 695 self,
696 696 defining_anchor: Self::LocalDefId,
697 697 ) -> Self::LocalDefIds {
698 698 if self.next_trait_solver_globally() {
699 +let coroutines_defined_by = self
700 +.nested_bodies_within(defining_anchor)
701 +.iter()
702 +.filter(|def_id
699 703 self.mk_local_def_ids_from_iter(
700 -self.opaque_types_defined_by(defining_anchor)
701 -.iter()
702 -.chain(self.stalled_generators_within(defining_anchor)),
704 +self.opaque_types_defined_by(defining_anchor).iter().chain(coroutines_defined_by),
703 705 )
704 706 } else {
705 707 self.opaque_types_defined_by(defining_anchor)
Original file line number Diff line number Diff line change
@@ -29,10 +29,10 @@ mod implied_bounds;
29 29 mod instance;
30 30 mod layout;
31 31 mod needs_drop;
32 +mod nested_bodies;
32 33 mod opaque_types;
33 34 mod representability;
34 35 pub mod sig_types;
35 -mod stalled_generators;
36 36 mod structural_match;
37 37 mod ty;
38 38
@@ -51,5 +51,5 @@ pub fn provide(providers: &mut Providers) {
51 51 ty::provide(providers);
52 52 instance::provide(providers);
53 53 structural_match::provide(providers);
54 -stalled_generators::provide(providers);
54 +nested_bodies::provide(providers);
55 55 }
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
1 +use rustc_hir as hir;
2 +use rustc_hir::def_id::{DefId, LocalDefId};
3 +use rustc_hir::intravisit::Visitor;
4 +use rustc_middle::query::Providers;
5 +use rustc_middle::ty::{self, TyCtxt};
6 +
7 +fn nested_bodies_within<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx ty::List<LocalDefId> {
8 +let body = tcx.hir_body_owned_by(item);
9 +let mut collector =
10 +NestedBodiesVisitor { tcx, root_def_id: item.to_def_id(), nested_bodies: vec![] };
11 + collector.visit_body(body);
12 + tcx.mk_local_def_ids(&collector.nested_bodies)
13 +}
14 +
15 +struct NestedBodiesVisitor<'tcx> {
16 +tcx: TyCtxt<'tcx>,
17 +root_def_id: DefId,
18 +nested_bodies: Vec<LocalDefId>,
19 +}
20 +
21 +impl<'tcx> Visitor<'tcx> for NestedBodiesVisitor<'tcx> {
22 +fn visit_nested_body(&mut self, id: hir::BodyId) {
23 +let body_def_id = self.tcx.hir_body_owner_def_id(id);
24 +if self.tcx.typeck_root_def_id(body_def_id.to_def_id()) == self.root_def_id {
25 +self.nested_bodies.push(body_def_id);
26 +let body = self.tcx.hir_body(id);
27 +self.visit_body(body);
28 +}
29 +}
30 +}
31 +
32 +pub(super) fn provide(providers: &mut Providers) {
33 +*providers = Providers { nested_bodies_within, ..*providers };
34 +}
Original file line number Diff line number Diff line change
@@ -100,7 +100,7 @@ impl<I: Interner> TypingMode {
100 100 pub fn typeck_for_body(cx: I, body_def_id: I::LocalDefId) -> TypingMode<I> {
101 101 TypingMode::Analysis {
102 102 defining_opaque_types_and_generators: cx
103 -.opaque_types_and_generators_defined_by(body_def_id),
103 +.opaque_types_and_coroutines_defined_by(body_def_id),
104 104 }
105 105 }
106 106
Original file line number Diff line number Diff line change
@@ -341,7 +341,7 @@ pub trait Interner:
341 341
342 342 fn opaque_types_defined_by(self, defining_anchor: Self::LocalDefId) -> Self::LocalDefIds;
343 343
344 -fn opaque_types_and_generators_defined_by(
344 +fn opaque_types_and_coroutines_defined_by(
345 345 self,
346 346 defining_anchor: Self::LocalDefId,
347 347 ) -> Self::LocalDefIds;
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
1 +//@ edition: 2024
2 +
3 +// Regression test for #140583. We want to borrowck nested
4 +// bodies even if they are in dead code. While not necessary for
5 +// soundness, it is desirable to error in such cases.
6 +
7 +fn main() {
8 +return;
9 + |x: &str
10 +//~^ ERROR lifetime may not live long enough
11 + |
12 + |
13 +let temp = 1;
14 +let p: &'static u32 = &temp;
15 +//~^ ERROR `temp` does not live long enough
16 +};
17 +};
18 +const {
19 +let temp = 1;
20 +let p: &'static u32 = &temp;
21 +//~^ ERROR `temp` does not live long enough
22 +};
23 +async {
24 +let temp = 1;
25 +let p: &'static u32 = &temp;
26 +//~^ ERROR `temp` does not live long enough
27 +};
28 +}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
1 +error: lifetime may not live long enough
2 + --> $DIR/nested-bodies-in-dead-code.rs:9:33
3 + |
4 +LL |
5 + | - ^ returning this value requires that `'1` must outlive `'static`
6 + |
7 + | let's call the lifetime of this reference `'1`
8 +
9 +error[E0597]: `temp` does not live long enough
10 + --> $DIR/nested-bodies-in-dead-code.rs:14:35
11 + |
12 +LL | let temp = 1;
13 + | ---- binding `temp` declared here
14 +LL | let p: &'static u32 = &temp;
15 + | ------------ ^^^^^ borrowed value does not live long enough
16 + |
17 + | type annotation requires that `temp` is borrowed for `'static`
18 +LL |
19 +LL | };
20 + | - `temp` dropped here while still borrowed
21 +
22 +error[E0597]: `temp` does not live long enough
23 + --> $DIR/nested-bodies-in-dead-code.rs:20:31
24 + |
25 +LL | let temp = 1;
26 + | ---- binding `temp` declared here
27 +LL | let p: &'static u32 = &temp;
28 + | ------------ ^^^^^ borrowed value does not live long enough
29 + |
30 + | type annotation requires that `temp` is borrowed for `'static`
31 +LL |
32 +LL | };
33 + | - `temp` dropped here while still borrowed
34 +
35 +error[E0597]: `temp` does not live long enough
36 + --> $DIR/nested-bodies-in-dead-code.rs:25:31
37 + |
38 +LL | let temp = 1;
39 + | ---- binding `temp` declared here
40 +LL | let p: &'static u32 = &temp;
41 + | ------------ ^^^^^ borrowed value does not live long enough
42 + |
43 + | type annotation requires that `temp` is borrowed for `'static`
44 +LL |
45 +LL | };
46 + | - `temp` dropped here while still borrowed
47 +
48 +error: aborting due to 4 previous errors
49 +
50 +For more information about this error, try `rustc --explain E0597`.