From f86f03263cb2de5090ac71663327fba3bd452315 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Thu, 16 Apr 2020 23:18:44 +0300 Subject: [PATCH] outlives: ignore lifetimes shallowly found in `ty::FnDef`s. --- src/librustc_infer/infer/outlives/verify.rs | 25 +++++++++++++++ src/librustc_middle/ty/outlives.rs | 32 +++++++++++++++---- .../issue-70917-lifetimes-in-fn-def.rs | 13 ++++++++ 3 files changed, 64 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/lifetimes/issue-70917-lifetimes-in-fn-def.rs diff --git a/src/librustc_infer/infer/outlives/verify.rs b/src/librustc_infer/infer/outlives/verify.rs index 5b6db324e6c85..3a7ae0c66312f 100644 --- a/src/librustc_infer/infer/outlives/verify.rs +++ b/src/librustc_infer/infer/outlives/verify.rs @@ -42,6 +42,31 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { match ty.kind { ty::Param(p) => self.param_bound(p), ty::Projection(data) => self.projection_bound(data), + ty::FnDef(_, substs) => { + // HACK(eddyb) ignore lifetimes found shallowly in `substs`. + // This is inconsistent with `ty::Adt` (including all substs), + // but consistent with previous (accidental) behavior. + // See https://github.com/rust-lang/rust/issues/70917 + // for further background and discussion. + let mut bounds = substs + .iter() + .filter_map(|&child| match child.unpack() { + GenericArgKind::Type(ty) => Some(self.type_bound(ty)), + GenericArgKind::Lifetime(_) => None, + GenericArgKind::Const(_) => Some(self.recursive_bound(child)), + }) + .filter(|bound| { + // Remove bounds that must hold, since they are not interesting. + !bound.must_hold() + }); + + match (bounds.next(), bounds.next()) { + (Some(first), None) => first, + (first, second) => VerifyBound::AllBounds( + first.into_iter().chain(second).chain(bounds).collect(), + ), + } + } _ => self.recursive_bound(ty.into()), } } diff --git a/src/librustc_middle/ty/outlives.rs b/src/librustc_middle/ty/outlives.rs index 950539fbb0a16..4fd4d0d1f0627 100644 --- a/src/librustc_middle/ty/outlives.rs +++ b/src/librustc_middle/ty/outlives.rs @@ -62,6 +62,27 @@ fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Compo // in the `subtys` iterator (e.g., when encountering a // projection). match ty.kind { + ty::FnDef(_, substs) => { + // HACK(eddyb) ignore lifetimes found shallowly in `substs`. + // This is inconsistent with `ty::Adt` (including all substs) + // and with `ty::Closure` (ignoring all substs other than + // upvars, of which a `ty::FnDef` doesn't have any), but + // consistent with previous (accidental) behavior. + // See https://github.com/rust-lang/rust/issues/70917 + // for further background and discussion. + for &child in substs { + match child.unpack() { + GenericArgKind::Type(ty) => { + compute_components(tcx, ty, out); + } + GenericArgKind::Lifetime(_) => {} + GenericArgKind::Const(_) => { + compute_components_recursive(tcx, child, out); + } + } + } + } + ty::Closure(_, ref substs) => { for upvar_ty in substs.as_closure().upvar_tys() { compute_components(tcx, upvar_ty, out); @@ -136,7 +157,7 @@ fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Compo ty::Float(..) | // OutlivesScalar ty::Never | // ... ty::Adt(..) | // OutlivesNominalType - ty::Opaque(..) | // OutlivesNominalType (ish) + ty::Opaque(..) | // OutlivesNominalType (ish) ty::Foreign(..) | // OutlivesNominalType ty::Str | // OutlivesScalar (ish) ty::Array(..) | // ... @@ -144,15 +165,14 @@ fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Compo ty::RawPtr(..) | // ... ty::Ref(..) | // OutlivesReference ty::Tuple(..) | // ... - ty::FnDef(..) | // OutlivesFunction (*) ty::FnPtr(_) | // OutlivesFunction (*) - ty::Dynamic(..) | // OutlivesObject, OutlivesFragment (*) + ty::Dynamic(..) | // OutlivesObject, OutlivesFragment (*) ty::Placeholder(..) | ty::Bound(..) | ty::Error => { - // (*) Bare functions and traits are both binders. In the - // RFC, this means we would add the bound regions to the - // "bound regions list". In our representation, no such + // (*) Function pointers and trait objects are both binders. + // In the RFC, this means we would add the bound regions to + // the "bound regions list". In our representation, no such // list is maintained explicitly, because bound regions // themselves can be readily identified. compute_components_recursive(tcx, ty.into(), out); diff --git a/src/test/ui/lifetimes/issue-70917-lifetimes-in-fn-def.rs b/src/test/ui/lifetimes/issue-70917-lifetimes-in-fn-def.rs new file mode 100644 index 0000000000000..b9aab27142e31 --- /dev/null +++ b/src/test/ui/lifetimes/issue-70917-lifetimes-in-fn-def.rs @@ -0,0 +1,13 @@ +// check-pass + +fn assert_static(_: T) {} + +// NOTE(eddyb) the `'a: 'a` may look a bit strange, but we *really* want +// `'a` to be an *early-bound* parameter, otherwise it doesn't matter anyway. +fn capture_lifetime<'a: 'a>() {} + +fn test_lifetime<'a>() { + assert_static(capture_lifetime::<'a>); +} + +fn main() {}