diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 287a45a21eadf..cf558457999fb 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -2011,53 +2011,6 @@ a (non-transparent) struct containing a single float, while `Grams` is a transparent wrapper around a float. This can make a difference for the ABI. "##, -E0700: r##" -The `impl Trait` return type captures lifetime parameters that do not -appear within the `impl Trait` itself. - -Erroneous code example: - -```compile-fail,E0700 -use std::cell::Cell; - -trait Trait<'a> { } - -impl<'a, 'b> Trait<'b> for Cell<&'a u32> { } - -fn foo<'x, 'y>(x: Cell<&'x u32>) -> impl Trait<'y> -where 'x: 'y -{ - x -} -``` - -Here, the function `foo` returns a value of type `Cell<&'x u32>`, -which references the lifetime `'x`. However, the return type is -declared as `impl Trait<'y>` -- this indicates that `foo` returns -"some type that implements `Trait<'y>`", but it also indicates that -the return type **only captures data referencing the lifetime `'y`**. -In this case, though, we are referencing data with lifetime `'x`, so -this function is in error. - -To fix this, you must reference the lifetime `'x` from the return -type. For example, changing the return type to `impl Trait<'y> + 'x` -would work: - -``` -use std::cell::Cell; - -trait Trait<'a> { } - -impl<'a,'b> Trait<'b> for Cell<&'a u32> { } - -fn foo<'x, 'y>(x: Cell<&'x u32>) -> impl Trait<'y> + 'x -where 'x: 'y -{ - x -} -``` -"##, - E0701: r##" This error indicates that a `#[non_exhaustive]` attribute was incorrectly placed on something other than a struct or enum. @@ -2141,6 +2094,7 @@ register_diagnostics! { E0687, // in-band lifetimes cannot be used in `fn`/`Fn` syntax E0688, // in-band lifetimes cannot be mixed with explicit lifetime binders E0697, // closures cannot be static +// E0700, // `impl Trait` can capture unnamed lifetime parameters now E0707, // multiple elided lifetimes used in arguments of `async fn` E0708, // `async` non-`move` closures with arguments are not currently supported E0709, // multiple different lifetimes used in arguments of `async fn` diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs index 5e94bb1f877fb..a37d47354d22b 100644 --- a/src/librustc/infer/opaque_types/mod.rs +++ b/src/librustc/infer/opaque_types/mod.rs @@ -449,13 +449,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // the function, by replacing invalid regions with 'static, // after producing an error for each of them. let definition_ty = - instantiated_ty.fold_with(&mut ReverseMapper::new( - self.tcx, - self.is_tainted_by_errors(), - def_id, - map, - instantiated_ty, - )); + instantiated_ty.fold_with(&mut ReverseMapper { tcx: self.tcx, map }); + debug!( "infer_opaque_definition_from_instantiation: definition_ty={:?}", definition_ty @@ -472,49 +467,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { struct ReverseMapper<'cx, 'gcx: 'tcx, 'tcx: 'cx> { tcx: TyCtxt<'cx, 'gcx, 'tcx>, - - /// If errors have already been reported in this fn, we suppress - /// our own errors because they are sometimes derivative. - tainted_by_errors: bool, - - opaque_type_def_id: DefId, map: FxHashMap, Kind<'gcx>>, - map_missing_regions_to_empty: bool, - - /// initially `Some`, set to `None` once error has been reported - hidden_ty: Option>, -} - -impl<'cx, 'gcx, 'tcx> ReverseMapper<'cx, 'gcx, 'tcx> { - fn new( - tcx: TyCtxt<'cx, 'gcx, 'tcx>, - tainted_by_errors: bool, - opaque_type_def_id: DefId, - map: FxHashMap, Kind<'gcx>>, - hidden_ty: Ty<'tcx>, - ) -> Self { - Self { - tcx, - tainted_by_errors, - opaque_type_def_id, - map, - map_missing_regions_to_empty: false, - hidden_ty: Some(hidden_ty), - } - } - - fn fold_kind_mapping_missing_regions_to_empty(&mut self, kind: Kind<'tcx>) -> Kind<'tcx> { - assert!(!self.map_missing_regions_to_empty); - self.map_missing_regions_to_empty = true; - let kind = kind.fold_with(self); - self.map_missing_regions_to_empty = false; - kind - } - - fn fold_kind_normally(&mut self, kind: Kind<'tcx>) -> Kind<'tcx> { - assert!(!self.map_missing_regions_to_empty); - kind.fold_with(self) - } } impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for ReverseMapper<'cx, 'gcx, 'tcx> { @@ -542,91 +495,35 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for ReverseMapper<'cx, 'gcx, 'tcx> Some(UnpackedKind::Lifetime(r1)) => r1, Some(u) => panic!("region mapped to unexpected kind: {:?}", u), None => { - if !self.map_missing_regions_to_empty && !self.tainted_by_errors { - if let Some(hidden_ty) = self.hidden_ty.take() { - let span = self.tcx.def_span(self.opaque_type_def_id); - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0700, - "hidden type for `impl Trait` captures lifetime that \ - does not appear in bounds", - ); - - // Assuming regionck succeeded, then we must - // be capturing *some* region from the fn - // header, and hence it must be free, so it's - // ok to invoke this fn (which doesn't accept - // all regions, and would ICE if an - // inappropriate region is given). We check - // `is_tainted_by_errors` by errors above, so - // we don't get in here unless regionck - // succeeded. (Note also that if regionck - // failed, then the regions we are attempting - // to map here may well be giving errors - // *because* the constraints were not - // satisfiable.) - self.tcx.note_and_explain_free_region( - &mut err, - &format!("hidden type `{}` captures ", hidden_ty), - r, - "" - ); - - err.emit(); - } - } + // No mapping was found. This means that it is either a + // disallowed lifetime, which will be caught by regionck, + // a region in a non-upvar closure generic, which is + // explicitly allowed (see below for more on this), + // or a lifetime that does not explicitly appear in + // `impl Trait` bounds but which outlives the lifetimes + // or types which *do* appear in the `impl Trait` bounds. + // + // These lifetimes are explicitly allowed to prevent + // the user from having to add dummy references to the + // unnamed lifetimes in their `impl Trait` bounds + // (e.g. `+ DummyTraitWithALifetimeArg<'a>`). Adding + // the lifetimes via `+` doesn't work because the type + // doesn't outlive those lifetimes, it just contains them. + // + // On closures: there is a somewhat subtle (read: hacky) + // consideration. The problem is that our closure types + // currently include all hte lifetime parameters declared + // on the enclosing function, even if they are unused by + // the closure itself. We can't readily filter them out, + // so we replace them with `empty`. This can't really make + // a diference to the rest of hte compiler; those regions + // are ignored for the outlives relation, and hence don't + // affect trait selection or auto traits, and they are + // erased during trans. self.tcx.types.re_empty }, } } - - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - match ty.sty { - ty::Closure(def_id, substs) => { - // I am a horrible monster and I pray for death. When - // we encounter a closure here, it is always a closure - // from within the function that we are currently - // type-checking -- one that is now being encapsulated - // in an existential abstract type. Ideally, we would - // go through the types/lifetimes that it references - // and treat them just like we would any other type, - // which means we would error out if we find any - // reference to a type/region that is not in the - // "reverse map". - // - // **However,** in the case of closures, there is a - // somewhat subtle (read: hacky) consideration. The - // problem is that our closure types currently include - // all the lifetime parameters declared on the - // enclosing function, even if they are unused by the - // closure itself. We can't readily filter them out, - // so here we replace those values with `'empty`. This - // can't really make a difference to the rest of the - // compiler; those regions are ignored for the - // outlives relation, and hence don't affect trait - // selection or auto traits, and they are erased - // during codegen. - - let generics = self.tcx.generics_of(def_id); - let substs = self.tcx.mk_substs(substs.substs.iter().enumerate().map( - |(index, &kind)| { - if index < generics.parent_count { - // Accommodate missing regions in the parent kinds... - self.fold_kind_mapping_missing_regions_to_empty(kind) - } else { - // ...but not elsewhere. - self.fold_kind_normally(kind) - } - }, - )); - - self.tcx.mk_closure(def_id, ty::ClosureSubsts { substs }) - } - - _ => ty.super_fold_with(self), - } - } } struct Instantiator<'a, 'gcx: 'tcx, 'tcx: 'a> { diff --git a/src/test/ui/impl-trait/issue-55608-captures-empty-region.rs b/src/test/ui/impl-trait/issue-55608-captures-empty-region.rs index 7ebc348996f5e..c48a454a3cb1f 100644 --- a/src/test/ui/impl-trait/issue-55608-captures-empty-region.rs +++ b/src/test/ui/impl-trait/issue-55608-captures-empty-region.rs @@ -1,9 +1,9 @@ +// compile-pass +// // This used to ICE because it creates an `impl Trait` that captures a // hidden empty region. -#![feature(conservative_impl_trait)] - -fn server() -> impl FilterBase2 { //~ ERROR [E0700] +fn server() -> impl FilterBase2 { segment2(|| { loop { } }).map2(|| "") } diff --git a/src/test/ui/impl-trait/issue-55608-captures-empty-region.stderr b/src/test/ui/impl-trait/issue-55608-captures-empty-region.stderr deleted file mode 100644 index d1f147834d2ef..0000000000000 --- a/src/test/ui/impl-trait/issue-55608-captures-empty-region.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/issue-55608-captures-empty-region.rs:6:16 - | -LL | fn server() -> impl FilterBase2 { //~ ERROR [E0700] - | ^^^^^^^^^^^^^^^^ - | - = note: hidden type `Map2<[closure@$DIR/issue-55608-captures-empty-region.rs:7:36: 7:41]>` captures an empty lifetime - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0700`. diff --git a/src/test/ui/impl-trait/region-escape-via-bound.rs b/src/test/ui/impl-trait/region-escape-via-bound.rs index d62aec800e8ce..ca52653c1275e 100644 --- a/src/test/ui/impl-trait/region-escape-via-bound.rs +++ b/src/test/ui/impl-trait/region-escape-via-bound.rs @@ -1,5 +1,7 @@ -// Test that we do not allow the region `'x` to escape in the impl -// trait **even though** `'y` escapes, which outlives `'x`. +// run-pass +// +// Test that we allow the region `'x` to escape in the impl +// because 'y` escapes, which outlives `'x`. // // See https://github.com/rust-lang/rust/issues/46541 for more details. @@ -14,7 +16,8 @@ trait Trait<'a> { } impl Trait<'b> for Cell<&'a u32> { } fn foo(x: Cell<&'x u32>) -> impl Trait<'y> - //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds [E0700] + // ^ hidden type for `impl Trait` captures lifetime that does not appear in bounds + // because it outlives the lifetime that *does* appear in the bounds, `'y` where 'x: 'y { x diff --git a/src/test/ui/impl-trait/region-escape-via-bound.stderr b/src/test/ui/impl-trait/region-escape-via-bound.stderr deleted file mode 100644 index 81b44b7eba7fd..0000000000000 --- a/src/test/ui/impl-trait/region-escape-via-bound.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/region-escape-via-bound.rs:16:29 - | -LL | fn foo(x: Cell<&'x u32>) -> impl Trait<'y> - | ^^^^^^^^^^^^^^ - | -note: hidden type `std::cell::Cell<&'x u32>` captures the lifetime 'x as defined on the function body at 18:7 - --> $DIR/region-escape-via-bound.rs:18:7 - | -LL | where 'x: 'y - | ^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0700`.