about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_infer/infer/outlives/verify.rs25
-rw-r--r--src/librustc_middle/ty/outlives.rs32
-rw-r--r--src/test/ui/lifetimes/issue-70917-lifetimes-in-fn-def.rs13
3 files changed, 64 insertions, 6 deletions
diff --git a/src/librustc_infer/infer/outlives/verify.rs b/src/librustc_infer/infer/outlives/verify.rs
index 4adf314c3d4..1a601d723cb 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 950539fbb0a..4fd4d0d1f06 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 00000000000..b9aab27142e
--- /dev/null
+++ b/src/test/ui/lifetimes/issue-70917-lifetimes-in-fn-def.rs
@@ -0,0 +1,13 @@
+// check-pass
+
+fn assert_static<T: '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() {}