Skip to content

Commit 05bac93

Browse files
Fix capturing duplicated lifetimes via parent
1 parent 3fba278 commit 05bac93

File tree

3 files changed

+90
-7
lines changed

3 files changed

+90
-7
lines changed

compiler/rustc_hir_analysis/src/check/check.rs

+30-7
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,7 @@ fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDe
492492
};
493493

494494
let mut expected_captures = UnordSet::default();
495+
let mut shadowed_captures = UnordSet::default();
495496
let mut seen_params = UnordMap::default();
496497
let mut prev_non_lifetime_param = None;
497498
for arg in precise_capturing_args {
@@ -530,6 +531,21 @@ fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDe
530531
match tcx.named_bound_var(hir_id) {
531532
Some(ResolvedArg::EarlyBound(def_id)) => {
532533
expected_captures.insert(def_id);
534+
535+
// Make sure we allow capturing these lifetimes through `Self` and
536+
// `T::Assoc` projection syntax, too. These will occur when we only
537+
// see lifetimes are captured after hir-lowering -- this aligns with
538+
// the cases that were stabilized with the `impl_trait_projection`
539+
// feature -- see <https://github.com/rust-lang/rust/pull/115659>.
540+
if let DefKind::LifetimeParam = tcx.def_kind(def_id)
541+
&& let ty::ReEarlyParam(ty::EarlyParamRegion { def_id, .. })
542+
| ty::ReLateParam(ty::LateParamRegion {
543+
bound_region: ty::BoundRegionKind::BrNamed(def_id, _),
544+
..
545+
}) = *tcx.map_opaque_lifetime_to_parent_lifetime(def_id.expect_local())
546+
{
547+
shadowed_captures.insert(def_id);
548+
}
533549
}
534550
_ => {
535551
tcx.dcx().span_delayed_bug(
@@ -555,23 +571,30 @@ fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDe
555571
);
556572
continue;
557573
}
574+
// If a param is shadowed by a early-bound (duplicated) lifetime, then
575+
// it may or may not be captured as invariant, depending on if it shows
576+
// up through `Self` or `T::Assoc` syntax.
577+
if shadowed_captures.contains(&param.def_id) {
578+
continue;
579+
}
558580

559581
match param.kind {
560582
ty::GenericParamDefKind::Lifetime => {
561583
// Check if the lifetime param was captured but isn't named in the precise captures list.
562584
if variances[param.index as usize] == ty::Invariant {
563-
let param_span =
564-
if let ty::ReEarlyParam(ty::EarlyParamRegion { def_id, .. })
585+
let param_span = if let DefKind::OpaqueTy =
586+
tcx.def_kind(tcx.parent(param.def_id))
587+
&& let ty::ReEarlyParam(ty::EarlyParamRegion { def_id, .. })
565588
| ty::ReLateParam(ty::LateParamRegion {
566589
bound_region: ty::BoundRegionKind::BrNamed(def_id, _),
567590
..
568591
}) = *tcx
569592
.map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local())
570-
{
571-
Some(tcx.def_span(def_id))
572-
} else {
573-
None
574-
};
593+
{
594+
Some(tcx.def_span(def_id))
595+
} else {
596+
None
597+
};
575598
// FIXME(precise_capturing): Structured suggestion for this would be useful
576599
tcx.dcx().emit_err(errors::LifetimeNotCaptured {
577600
use_span: tcx.def_span(param.def_id),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#![feature(precise_capturing)]
2+
//~^ WARN the feature `precise_capturing` is incomplete
3+
4+
trait Tr {
5+
type Assoc;
6+
}
7+
8+
struct W<'a>(&'a ());
9+
10+
impl Tr for W<'_> {
11+
type Assoc = ();
12+
}
13+
14+
impl<'a> W<'a> {
15+
fn good1() -> impl use<'a> Into<<W<'a> as Tr>::Assoc> {}
16+
}
17+
18+
impl<'a> W<'a> {
19+
fn good2() -> impl use<'a> Into<<Self as Tr>::Assoc> {}
20+
}
21+
22+
impl<'a> W<'a> {
23+
fn bad1() -> impl use<> Into<<W<'a> as Tr>::Assoc> {}
24+
//~^ ERROR `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list
25+
}
26+
27+
impl<'a> W<'a> {
28+
//~^ ERROR `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list
29+
fn bad2() -> impl use<> Into<<Self as Tr>::Assoc> {}
30+
}
31+
32+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/capture-parent-arg.rs:1:12
3+
|
4+
LL | #![feature(precise_capturing)]
5+
| ^^^^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
8+
= note: `#[warn(incomplete_features)]` on by default
9+
10+
error: `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list
11+
--> $DIR/capture-parent-arg.rs:23:37
12+
|
13+
LL | impl<'a> W<'a> {
14+
| -- this lifetime parameter is captured
15+
LL | fn bad1() -> impl use<> Into<<W<'a> as Tr>::Assoc> {}
16+
| -------------------^^---------------- lifetime captured due to being mentioned in the bounds of the `impl Trait`
17+
18+
error: `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list
19+
--> $DIR/capture-parent-arg.rs:27:6
20+
|
21+
LL | impl<'a> W<'a> {
22+
| ^^
23+
LL |
24+
LL | fn bad2() -> impl use<> Into<<Self as Tr>::Assoc> {}
25+
| ------------------------------------ lifetime captured due to being mentioned in the bounds of the `impl Trait`
26+
27+
error: aborting due to 2 previous errors; 1 warning emitted
28+

0 commit comments

Comments
 (0)