diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index b3a904f2f5fec..2fd875c344767 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -2074,6 +2074,58 @@ 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. "##, +E0909: r##" +The `impl Trait` return type captures lifetime parameters that do not +appear within the `impl Trait` itself. + +Erroneous code example: + +```compile-fail,E0909 +#![feature(conservative_impl_trait)] + +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: + +``` +#![feature(conservative_impl_trait)] + +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 +} +``` +"##, + + } diff --git a/src/librustc/infer/anon_types/mod.rs b/src/librustc/infer/anon_types/mod.rs index eb26f0c1188bf..93e8745af1b57 100644 --- a/src/librustc/infer/anon_types/mod.rs +++ b/src/librustc/infer/anon_types/mod.rs @@ -14,10 +14,10 @@ use infer::outlives::free_region_map::FreeRegionRelations; use rustc_data_structures::fx::FxHashMap; use syntax::ast; use traits::{self, PredicateObligation}; -use ty::{self, Ty}; -use ty::fold::{BottomUpFolder, TypeFoldable}; +use ty::{self, Ty, TyCtxt}; +use ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder}; use ty::outlives::Component; -use ty::subst::{Kind, UnpackedKind, Substs}; +use ty::subst::{Kind, Substs, UnpackedKind}; use util::nodemap::DefIdMap; pub type AnonTypeMap<'tcx> = DefIdMap>; @@ -113,10 +113,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ) -> InferOk<'tcx, (T, AnonTypeMap<'tcx>)> { debug!( "instantiate_anon_types(value={:?}, parent_def_id={:?}, body_id={:?}, param_env={:?})", - value, - parent_def_id, - body_id, - param_env, + value, parent_def_id, body_id, param_env, ); let mut instantiator = Instantiator { infcx: self, @@ -458,55 +455,184 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // Convert the type from the function into a type valid outside // the function, by replacing invalid regions with 'static, // after producing an error for each of them. - let definition_ty = gcx.fold_regions(&instantiated_ty, &mut false, |r, _| { - match *r { - // 'static and early-bound regions are valid. - ty::ReStatic | ty::ReEmpty => r, - - // All other regions, we map them appropriately to their adjusted - // indices, erroring if we find any lifetimes that were not mapped - // into the new set. - _ => if let Some(UnpackedKind::Lifetime(r1)) = map.get(&r.into()) - .map(|k| k.unpack()) { - r1 - } else { - // No mapping was found. This means that - // it is either a disallowed lifetime, - // which will be caught by regionck, or it - // is a region in a non-upvar closure - // generic, which is explicitly - // allowed. If that surprises you, read - // on. - // - // The case of closure 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 - // trans. - gcx.types.re_empty - }, - } - }); - + let definition_ty = + instantiated_ty.fold_with(&mut ReverseMapper::new( + self.tcx, + self.is_tainted_by_errors(), + def_id, + map, + instantiated_ty, + )); debug!( "infer_anon_definition_from_instantiation: definition_ty={:?}", definition_ty ); + // We can unwrap here because our reverse mapper always + // produces things with 'gcx lifetime, though the type folder + // obscures that. + let definition_ty = gcx.lift(&definition_ty).unwrap(); + definition_ty } } +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, + + anon_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, + anon_type_def_id: DefId, + map: FxHashMap, Kind<'gcx>>, + hidden_ty: Ty<'tcx>, + ) -> Self { + Self { + tcx, + tainted_by_errors, + anon_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> { + fn tcx(&self) -> TyCtxt<'_, 'gcx, 'tcx> { + self.tcx + } + + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { + match r { + // ignore bound regions that appear in the type (e.g., this + // would ignore `'r` in a type like `for<'r> fn(&'r u32)`. + ty::ReLateBound(..) => return r, + + // ignore `'static`, as that can appear anywhere + ty::ReStatic => return r, + + _ => { } + } + + match self.map.get(&r.into()).map(|k| k.unpack()) { + 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.anon_type_def_id); + let mut err = struct_span_err!( + self.tcx.sess, + span, + E0909, + "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(); + } + } + self.tcx.types.re_empty + }, + } + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + match ty.sty { + ty::TyClosure(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 trans. + + let generics = self.tcx.generics_of(def_id); + let parent_len = generics.parent_count(); + let substs = self.tcx.mk_substs(substs.substs.iter().enumerate().map( + |(index, &kind)| { + if index < parent_len { + // 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> { infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, parent_def_id: DefId, @@ -565,12 +691,13 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> { return self.fold_anon_ty(ty, def_id, substs); } - debug!("instantiate_anon_types_in_map: \ - encountered anon with wrong parent \ - def_id={:?} \ - anon_parent_def_id={:?}", - def_id, - anon_parent_def_id); + debug!( + "instantiate_anon_types_in_map: \ + encountered anon with wrong parent \ + def_id={:?} \ + anon_parent_def_id={:?}", + def_id, anon_parent_def_id + ); } } @@ -590,8 +717,7 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> { debug!( "instantiate_anon_types: TyAnon(def_id={:?}, substs={:?})", - def_id, - substs + def_id, substs ); // Use the same type variable if the exact same TyAnon appears more @@ -600,8 +726,10 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> { return anon_defn.concrete_ty; } let span = tcx.def_span(def_id); - let ty_var = infcx.next_ty_var(ty::UniverseIndex::ROOT, - TypeVariableOrigin::TypeInference(span)); + let ty_var = infcx.next_ty_var( + ty::UniverseIndex::ROOT, + TypeVariableOrigin::TypeInference(span), + ); let predicates_of = tcx.predicates_of(def_id); let bounds = predicates_of.instantiate(tcx, substs); diff --git a/src/librustc/infer/canonical.rs b/src/librustc/infer/canonical.rs index 4e0cf59e8a7fd..22526c7751d50 100644 --- a/src/librustc/infer/canonical.rs +++ b/src/librustc/infer/canonical.rs @@ -40,6 +40,7 @@ use traits::{Obligation, ObligationCause, PredicateObligation}; use ty::{self, CanonicalVar, Lift, Region, Slice, Ty, TyCtxt, TypeFlags}; use ty::subst::{Kind, UnpackedKind}; use ty::fold::{TypeFoldable, TypeFolder}; +use util::captures::Captures; use util::common::CellUsizeExt; use rustc_data_structures::indexed_vec::IndexVec; @@ -382,7 +383,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { param_env: ty::ParamEnv<'tcx>, unsubstituted_region_constraints: &'a QueryRegionConstraints<'tcx>, result_subst: &'a CanonicalVarValues<'tcx>, - ) -> impl Iterator> + 'a { + ) -> impl Iterator> + Captures<'gcx> + 'a { let QueryRegionConstraints { region_outlives, ty_outlives, diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 77259f156e5e2..22b07c8cc044f 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -157,6 +157,7 @@ pub mod traits; pub mod ty; pub mod util { + pub mod captures; pub mod common; pub mod ppaux; pub mod nodemap; diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs index e0d662657b7de..e56a8662f3eb4 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -19,6 +19,7 @@ use ty::{self, TyCtxt, TypeFoldable}; use ty::fast_reject::{self, SimplifiedType}; use rustc_data_structures::sync::Lrc; use syntax::ast::Name; +use util::captures::Captures; use util::nodemap::{DefIdMap, FxHashMap}; /// A per-trait graph of impls in specialization order. At the moment, this @@ -313,9 +314,10 @@ impl<'a, 'gcx, 'tcx> Node { } /// Iterate over the items defined directly by the given (impl or trait) node. - #[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait. - pub fn items(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) - -> impl Iterator + 'a { + pub fn items( + &self, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + ) -> impl Iterator + 'a { tcx.associated_items(self.def_id()) } @@ -367,9 +369,13 @@ impl<'a, 'gcx, 'tcx> Ancestors { /// Search the items from the given ancestors, returning each definition /// with the given name and the given kind. #[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait. - pub fn defs(self, tcx: TyCtxt<'a, 'gcx, 'tcx>, trait_item_name: Name, - trait_item_kind: ty::AssociatedKind, trait_def_id: DefId) - -> impl Iterator> + 'a { + pub fn defs( + self, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + trait_item_name: Name, + trait_item_kind: ty::AssociatedKind, + trait_def_id: DefId, + ) -> impl Iterator> + Captures<'gcx> + Captures<'tcx> + 'a { self.flat_map(move |node| { node.items(tcx).filter(move |impl_item| { impl_item.kind == trait_item_kind && diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index c915022351925..95c5cd377d71f 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -34,6 +34,7 @@ use ty; use ty::subst::{Subst, Substs}; use ty::util::{IntTypeExt, Discr}; use ty::walk::TypeWalker; +use util::captures::Captures; use util::nodemap::{NodeSet, DefIdMap, FxHashMap}; use serialize::{self, Encodable, Encoder}; @@ -1942,8 +1943,10 @@ impl<'a, 'gcx, 'tcx> AdtDef { } #[inline] - pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>) - -> impl Iterator> + 'a { + pub fn discriminants( + &'a self, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + ) -> impl Iterator> + Captures<'gcx> + 'a { let repr_type = self.repr.discr_type(); let initial = repr_type.initial_discriminant(tcx.global_tcx()); let mut prev_discr = None::>; @@ -2290,7 +2293,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Returns an iterator of the def-ids for all body-owners in this /// crate. If you would prefer to iterate over the bodies /// themselves, you can do `self.hir.krate().body_ids.iter()`. - pub fn body_owners(self) -> impl Iterator + 'a { + pub fn body_owners( + self, + ) -> impl Iterator + Captures<'tcx> + Captures<'gcx> + 'a { self.hir.krate() .body_ids .iter() @@ -2394,11 +2399,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - #[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait. - pub fn associated_items(self, def_id: DefId) - -> impl Iterator + 'a { + pub fn associated_items( + self, + def_id: DefId, + ) -> impl Iterator + 'a { let def_ids = self.associated_item_def_ids(def_id); - (0..def_ids.len()).map(move |i| self.associated_item(def_ids[i])) + Box::new((0..def_ids.len()).map(move |i| self.associated_item(def_ids[i]))) + as Box + 'a> } /// Returns true if the impls are the same polarity and are implementing diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index bb5c7b5fd2a5e..d7ab6e39ac5f0 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -18,6 +18,7 @@ use rustc_data_structures::indexed_vec::Idx; use ty::subst::{Substs, Subst, Kind, UnpackedKind}; use ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable}; use ty::{Slice, TyS}; +use util::captures::Captures; use std::iter; use std::cmp::Ordering; @@ -384,9 +385,11 @@ impl<'a, 'gcx, 'tcx> ClosureSubsts<'tcx> { /// This returns the types of the MIR locals which had to be stored across suspension points. /// It is calculated in rustc_mir::transform::generator::StateTransform. /// All the types here must be in the tuple in GeneratorInterior. - pub fn state_tys(self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> - impl Iterator> + 'a - { + pub fn state_tys( + self, + def_id: DefId, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + ) -> impl Iterator> + Captures<'gcx> + 'a { let state = tcx.generator_layout(def_id).fields.iter(); state.map(move |d| d.ty.subst(tcx, self.substs)) } @@ -403,7 +406,7 @@ impl<'a, 'gcx, 'tcx> ClosureSubsts<'tcx> { /// This is the types of all the fields stored in a generator. /// It includes the upvars, state types and the state discriminant which is u32. pub fn field_tys(self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> - impl Iterator> + 'a + impl Iterator> + Captures<'gcx> + 'a { self.pre_transforms_tys(def_id, tcx).chain(self.state_tys(def_id, tcx)) } diff --git a/src/librustc/util/captures.rs b/src/librustc/util/captures.rs new file mode 100644 index 0000000000000..b68cfd278fa9e --- /dev/null +++ b/src/librustc/util/captures.rs @@ -0,0 +1,18 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/// "Signaling" trait used in impl trait to tag lifetimes that you may +/// need to capture but don't really need for other reasons. +/// Basically a workaround; see [this comment] for details. +/// +/// [this comment]: https://github.com/rust-lang/rust/issues/34511#issuecomment-373423999 +pub trait Captures<'a> { } + +impl<'a, T: ?Sized> Captures<'a> for T { } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index e1c17e8260a79..b0c945fbf2a05 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -29,6 +29,7 @@ use rustc::session::Session; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::codec::TyDecoder; use rustc::mir::Mir; +use rustc::util::captures::Captures; use rustc::util::nodemap::FxHashMap; use std::collections::BTreeMap; @@ -146,7 +147,10 @@ impl<'a, 'tcx: 'a, T: Decodable> Lazy { } impl<'a, 'tcx: 'a, T: Decodable> LazySeq { - pub fn decode>(self, meta: M) -> impl Iterator + 'a { + pub fn decode>( + self, + meta: M, + ) -> impl Iterator + Captures<'tcx> + 'a { let mut dcx = meta.decoder(self.position); dcx.lazy_state = LazyState::NodeStart(self.position); (0..self.len).map(move |_| T::decode(&mut dcx).unwrap()) diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index ab148afafbe09..4fc3344dab2a9 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -217,7 +217,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .upvar_tys(closure_def_id, self.tcx) .zip(final_upvar_tys) { - self.demand_eqtype(span, final_upvar_ty, upvar_ty); + self.demand_suptype(span, upvar_ty, final_upvar_ty); } // If we are also inferred the closure kind here, diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index a17b35dec42d7..6f24d06844bb4 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -35,8 +35,9 @@ use rustc::ty::{ToPredicate, ReprOptions}; use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt}; use rustc::ty::maps::Providers; use rustc::ty::util::IntTypeExt; -use rustc::util::nodemap::{FxHashSet, FxHashMap}; use rustc::ty::util::Discr; +use rustc::util::captures::Captures; +use rustc::util::nodemap::{FxHashSet, FxHashMap}; use syntax::{abi, ast}; use syntax::ast::MetaItemKind; @@ -1281,7 +1282,7 @@ fn is_unsized<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, fn early_bound_lifetimes_from_generics<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, ast_generics: &'a hir::Generics) - -> impl Iterator + -> impl Iterator + Captures<'tcx> { ast_generics .lifetimes() diff --git a/src/test/mir-opt/end_region_8.rs b/src/test/mir-opt/end_region_8.rs index 405864aba9436..d621cdb4d58f8 100644 --- a/src/test/mir-opt/end_region_8.rs +++ b/src/test/mir-opt/end_region_8.rs @@ -36,7 +36,7 @@ fn foo(f: F) where F: FnOnce() -> i32 { // let _2: &'21_1rs D; // ... // let mut _3: (); -// let mut _4: [closure@NodeId(22) r:&'21_1rs D]; +// let mut _4: [closure@NodeId(22) r:&'19s D]; // let mut _5: &'21_1rs D; // bb0: { // StorageLive(_1); @@ -54,6 +54,7 @@ fn foo(f: F) where F: FnOnce() -> i32 { // resume; // } // bb2: { +// EndRegion('19s); // StorageDead(_4); // _0 = (); // EndRegion('21_1rs); @@ -61,6 +62,7 @@ fn foo(f: F) where F: FnOnce() -> i32 { // drop(_1) -> [return: bb4, unwind: bb1]; // } // bb3: { +// EndRegion('19s); // EndRegion('21_1rs); // drop(_1) -> bb1; // } @@ -72,7 +74,7 @@ fn foo(f: F) where F: FnOnce() -> i32 { // END rustc.main.SimplifyCfg-qualify-consts.after.mir // START rustc.main-{{closure}}.SimplifyCfg-qualify-consts.after.mir -// fn main::{{closure}}(_1: [closure@NodeId(22) r:&'21_1rs D]) -> i32 { +// fn main::{{closure}}(_1: [closure@NodeId(22) r:&'19s D]) -> i32 { // let mut _0: i32; // let mut _2: i32; // diff --git a/src/test/ui/generator/auto-trait-regions.stderr b/src/test/ui/generator/auto-trait-regions.stderr index cd83915fe82d3..dd78baf927509 100644 --- a/src/test/ui/generator/auto-trait-regions.stderr +++ b/src/test/ui/generator/auto-trait-regions.stderr @@ -1,15 +1,15 @@ -error[E0277]: the trait bound `No: Foo` is not satisfied in `[generator@$DIR/auto-trait-regions.rs:35:15: 39:6 x:&&'static OnlyFooIfStaticRef for<'r> {&'r OnlyFooIfStaticRef, ()}]` +error[E0277]: the trait bound `No: Foo` is not satisfied in `[generator@$DIR/auto-trait-regions.rs:35:15: 39:6 x:&&OnlyFooIfStaticRef for<'r> {&'r OnlyFooIfStaticRef, ()}]` --> $DIR/auto-trait-regions.rs:40:5 | LL | assert_foo(gen); //~ ERROR the trait bound `No: Foo` is not satisfied - | ^^^^^^^^^^ within `[generator@$DIR/auto-trait-regions.rs:35:15: 39:6 x:&&'static OnlyFooIfStaticRef for<'r> {&'r OnlyFooIfStaticRef, ()}]`, the trait `Foo` is not implemented for `No` + | ^^^^^^^^^^ within `[generator@$DIR/auto-trait-regions.rs:35:15: 39:6 x:&&OnlyFooIfStaticRef for<'r> {&'r OnlyFooIfStaticRef, ()}]`, the trait `Foo` is not implemented for `No` | = help: the following implementations were found: = note: required because it appears within the type `OnlyFooIfStaticRef` = note: required because it appears within the type `&OnlyFooIfStaticRef` = note: required because it appears within the type `for<'r> {&'r OnlyFooIfStaticRef, ()}` - = note: required because it appears within the type `[generator@$DIR/auto-trait-regions.rs:35:15: 39:6 x:&&'static OnlyFooIfStaticRef for<'r> {&'r OnlyFooIfStaticRef, ()}]` + = note: required because it appears within the type `[generator@$DIR/auto-trait-regions.rs:35:15: 39:6 x:&&OnlyFooIfStaticRef for<'r> {&'r OnlyFooIfStaticRef, ()}]` note: required by `assert_foo` --> $DIR/auto-trait-regions.rs:30:1 | diff --git a/src/test/ui/impl-trait/region-escape-via-bound-contravariant-closure.rs b/src/test/ui/impl-trait/region-escape-via-bound-contravariant-closure.rs new file mode 100644 index 0000000000000..f554efe903613 --- /dev/null +++ b/src/test/ui/impl-trait/region-escape-via-bound-contravariant-closure.rs @@ -0,0 +1,31 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// In contrast to `region-escape-via-bound-invariant`, in this case we +// *can* return a value of type `&'x u32`, even though `'x` does not +// appear in the bounds. This is because `&` is contravariant, and so +// we are *actually* returning a `&'y u32`. +// +// See https://github.com/rust-lang/rust/issues/46541 for more details. + +// run-pass + +#![allow(dead_code)] +#![feature(conservative_impl_trait)] +#![feature(in_band_lifetimes)] +#![feature(nll)] + +fn foo(x: &'x u32) -> impl Fn() -> &'y u32 +where 'x: 'y +{ + move || x +} + +fn main() { } diff --git a/src/test/ui/impl-trait/region-escape-via-bound-contravariant.rs b/src/test/ui/impl-trait/region-escape-via-bound-contravariant.rs new file mode 100644 index 0000000000000..416bdae517845 --- /dev/null +++ b/src/test/ui/impl-trait/region-escape-via-bound-contravariant.rs @@ -0,0 +1,35 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// In contrast to `region-escape-via-bound-invariant`, in this case we +// *can* return a value of type `&'x u32`, even though `'x` does not +// appear in the bounds. This is because `&` is contravariant, and so +// we are *actually* returning a `&'y u32`. +// +// See https://github.com/rust-lang/rust/issues/46541 for more details. + +// run-pass + +#![allow(dead_code)] +#![feature(conservative_impl_trait)] +#![feature(in_band_lifetimes)] +#![feature(nll)] + +trait Trait<'a> { } + +impl Trait<'b> for &'a u32 { } + +fn foo(x: &'x u32) -> impl Trait<'y> +where 'x: 'y +{ + x +} + +fn main() { } diff --git a/src/test/ui/impl-trait/region-escape-via-bound.rs b/src/test/ui/impl-trait/region-escape-via-bound.rs new file mode 100644 index 0000000000000..38c18ce61044e --- /dev/null +++ b/src/test/ui/impl-trait/region-escape-via-bound.rs @@ -0,0 +1,34 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we do not allow the region `'x` to escape in the impl +// trait **even though** `'y` escapes, which outlives `'x`. +// +// See https://github.com/rust-lang/rust/issues/46541 for more details. + +#![allow(dead_code)] +#![feature(conservative_impl_trait)] +#![feature(in_band_lifetimes)] +#![feature(nll)] + +use std::cell::Cell; + +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 [E0909] +where 'x: 'y +{ + x +} + +fn main() { } diff --git a/src/test/ui/impl-trait/region-escape-via-bound.stderr b/src/test/ui/impl-trait/region-escape-via-bound.stderr new file mode 100644 index 0000000000000..5659fee9bedc6 --- /dev/null +++ b/src/test/ui/impl-trait/region-escape-via-bound.stderr @@ -0,0 +1,20 @@ +error[E0909]: hidden type for `impl Trait` captures lifetime that does not appear in bounds + --> $DIR/region-escape-via-bound.rs:27: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 27:1 + --> $DIR/region-escape-via-bound.rs:27:1 + | +LL | / fn foo(x: Cell<&'x u32>) -> impl Trait<'y> +LL | | //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds [E0909] +LL | | where 'x: 'y +LL | | { +LL | | x +LL | | } + | |_^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0909`.