diff --git a/src/doc/unstable-book/src/language-features/infer-outlives-requirements.md b/src/doc/unstable-book/src/language-features/infer-outlives-requirements.md new file mode 100644 index 0000000000000..73c7eafdb98d5 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/infer-outlives-requirements.md @@ -0,0 +1,67 @@ +# `infer_outlives_requirements` + +The tracking issue for this feature is: [#44493] + +[#44493]: https://github.com/rust-lang/rust/issues/44493 + +------------------------ +The `infer_outlives_requirements` feature indicates that certain +outlives requirements can be infered by the compiler rather than +stating them explicitly. + +For example, currently generic struct definitions that contain +references, require where-clauses of the form T: 'a. By using +this feature the outlives predicates will be infered, although +they may still be written explicitly. + +```rust,ignore (pseudo-Rust) +struct Foo<'a, T> + where T: 'a // <-- currently required + { + bar: &'a T, + } +``` + + +## Examples: + + +```rust,ignore (pseudo-Rust) +#![feature(infer_outlives_requirements)] + +// Implicitly infer T: 'a +struct Foo<'a, T> { + bar: &'a T, +} +``` + +```rust,ignore (pseudo-Rust) +#![feature(infer_outlives_requirements)] + +// Implicitly infer `U: 'b` +struct Foo<'b, U> { + bar: Bar<'b, U> +} + +struct Bar<'a, T> where T: 'a { + x: &'a (), + y: T, +} +``` + +```rust,ignore (pseudo-Rust) +#![feature(infer_outlives_requirements)] + +// Implicitly infer `b': 'a` +struct Foo<'a, 'b, T> { + x: &'a &'b T +} +``` + +```rust,ignore (pseudo-Rust) +#![feature(infer_outlives_requirements)] + +// Implicitly infer `::Item : 'a` +struct Foo<'a, T: Iterator> { + bar: &'a T::Item +``` diff --git a/src/librustc_typeck/outlives/explicit.rs b/src/librustc_typeck/outlives/explicit.rs index 9a8fd46b0efff..bbe47ecee7907 100644 --- a/src/librustc_typeck/outlives/explicit.rs +++ b/src/librustc_typeck/outlives/explicit.rs @@ -8,21 +8,19 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use hir::map as hir_map; use rustc::hir; -use rustc::hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; +use rustc::hir::def_id::{CrateNum, DefId}; use rustc::hir::itemlikevisit::ItemLikeVisitor; -use rustc::ty::maps::Providers; -use rustc::ty::{self, CratePredicatesMap, TyCtxt}; -use rustc_data_structures::sync::Lrc; +use rustc::ty::{self, TyCtxt}; use util::nodemap::FxHashMap; +use super::utils::*; + pub fn explicit_predicates<'tcx>( tcx: TyCtxt<'_, 'tcx, 'tcx>, crate_num: CrateNum, -) -> FxHashMap>>> { - assert_eq!(crate_num, LOCAL_CRATE); - let mut predicates: FxHashMap>>> = FxHashMap(); +) -> FxHashMap> { + let mut predicates = FxHashMap::default(); // iterate over the entire crate tcx.hir.krate().visit_all_item_likes(&mut ExplicitVisitor { @@ -36,7 +34,7 @@ pub fn explicit_predicates<'tcx>( pub struct ExplicitVisitor<'cx, 'tcx: 'cx> { tcx: TyCtxt<'cx, 'tcx, 'tcx>, - explicit_predicates: &'cx mut FxHashMap>>>, + explicit_predicates: &'cx mut FxHashMap>, crate_num: CrateNum, } @@ -47,13 +45,25 @@ impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for ExplicitVisitor<'cx, 'tcx> { index: item.hir_id.owner, }; - let local_explicit_predicate = self.tcx.explicit_predicates_of(def_id); + let mut required_predicates = RequiredPredicates::default(); + let local_explicit_predicate = self.tcx.explicit_predicates_of(def_id).predicates; + + for pred in local_explicit_predicate.into_iter() { + match pred { + ty::Predicate::TypeOutlives(predicate) => { + let ty::OutlivesPredicate(ref ty, ref reg) = predicate.skip_binder(); + insert_outlives_predicate(self.tcx, (*ty).into(), reg, &mut required_predicates) + } - let filtered_predicates = local_explicit_predicate - .predicates - .into_iter() - .filter(|pred| match pred { - ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) => true, + ty::Predicate::RegionOutlives(predicate) => { + let ty::OutlivesPredicate(ref reg1, ref reg2) = predicate.skip_binder(); + insert_outlives_predicate( + self.tcx, + (*reg1).into(), + reg2, + &mut required_predicates, + ) + } ty::Predicate::Trait(..) | ty::Predicate::Projection(..) @@ -61,22 +71,14 @@ impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for ExplicitVisitor<'cx, 'tcx> { | ty::Predicate::ObjectSafe(..) | ty::Predicate::ClosureKind(..) | ty::Predicate::Subtype(..) - | ty::Predicate::ConstEvaluatable(..) => false, - }) - .collect(); - - match item.node { - hir::ItemStruct(..) | hir::ItemEnum(..) => { - self.tcx.adt_def(def_id); + | ty::Predicate::ConstEvaluatable(..) => (), } - _ => {} } - self.explicit_predicates - .insert(def_id, Lrc::new(filtered_predicates)); + self.explicit_predicates.insert(def_id, required_predicates); } - fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {} + fn visit_trait_item(&mut self, _trait_item: &'tcx hir::TraitItem) {} - fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {} + fn visit_impl_item(&mut self, _impl_item: &'tcx hir::ImplItem) {} } diff --git a/src/librustc_typeck/outlives/implicit_empty.rs b/src/librustc_typeck/outlives/implicit_empty.rs deleted file mode 100644 index b2259c63683c6..0000000000000 --- a/src/librustc_typeck/outlives/implicit_empty.rs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2013 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. - -use hir::map as hir_map; -use rustc::hir; -use rustc::hir::def_id::{self, CrateNum, DefId, LOCAL_CRATE}; -use rustc::hir::itemlikevisit::ItemLikeVisitor; -use rustc::ty::maps::Providers; -use rustc::ty::{self, CratePredicatesMap, TyCtxt}; -use rustc_data_structures::sync::Lrc; -use util::nodemap::FxHashMap; - -// Create the sets of inferred predicates for each type. These sets -// are initially empty but will grow during the inference step. -pub fn empty_predicate_map<'tcx>( - tcx: TyCtxt<'_, 'tcx, 'tcx>, -) -> FxHashMap>>> { - let mut predicates = FxHashMap(); - - // iterate over the entire crate - tcx.hir - .krate() - .visit_all_item_likes(&mut EmptyImplicitVisitor { - tcx, - predicates: &mut predicates, - }); - - predicates -} - -pub struct EmptyImplicitVisitor<'cx, 'tcx: 'cx> { - tcx: TyCtxt<'cx, 'tcx, 'tcx>, - predicates: &'cx mut FxHashMap>>>, -} - -impl<'a, 'p, 'v> ItemLikeVisitor<'v> for EmptyImplicitVisitor<'a, 'p> { - fn visit_item(&mut self, item: &hir::Item) { - self.predicates - .insert(self.tcx.hir.local_def_id(item.id), Lrc::new(Vec::new())); - } - - fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) {} - - fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) {} -} diff --git a/src/librustc_typeck/outlives/implicit_infer.rs b/src/librustc_typeck/outlives/implicit_infer.rs index e711598c944c1..c966db98c8e17 100644 --- a/src/librustc_typeck/outlives/implicit_infer.rs +++ b/src/librustc_typeck/outlives/implicit_infer.rs @@ -8,24 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(unused)] - use rustc::hir; -use rustc::hir::def::{CtorKind, Def}; -use rustc::hir::def_id::{self, CrateNum, DefId, LOCAL_CRATE}; +use rustc::hir::def_id::DefId; use rustc::hir::itemlikevisit::ItemLikeVisitor; -use rustc::hir::map as hir_map; -use rustc::ty::Slice; -use rustc::ty::maps::Providers; -use rustc::ty::outlives::Component; use rustc::ty::subst::{Kind, Subst, UnpackedKind}; -use rustc::ty::{self, AdtKind, CratePredicatesMap, Region, RegionKind, ReprOptions, - ToPolyTraitRef, ToPredicate, Ty, TyCtxt}; -use rustc::util::nodemap::{FxHashMap, FxHashSet}; -use rustc_data_structures::sync::Lrc; -use rustc_target::spec::abi; -use syntax::ast; -use syntax_pos::{Span, DUMMY_SP}; +use rustc::ty::{self, Ty, TyCtxt}; +use rustc::util::nodemap::FxHashMap; + +use super::utils::*; /// Infer predicates for the items in the crate. /// @@ -34,7 +24,7 @@ use syntax_pos::{Span, DUMMY_SP}; /// now be filled with inferred predicates. pub fn infer_predicates<'tcx>( tcx: TyCtxt<'_, 'tcx, 'tcx>, - explicit_map: &FxHashMap>>>, + explicit_map: &FxHashMap>, ) -> FxHashMap> { debug!("infer_predicates"); @@ -65,20 +55,17 @@ pub struct InferVisitor<'cx, 'tcx: 'cx> { tcx: TyCtxt<'cx, 'tcx, 'tcx>, global_inferred_outlives: &'cx mut FxHashMap>, predicates_added: &'cx mut bool, - explicit_map: &'cx FxHashMap>>>, + explicit_map: &'cx FxHashMap>, } -/// Tracks the `T: 'a` or `'a: 'a` predicates that we have inferred -/// must be added to the struct header. -type RequiredPredicates<'tcx> = FxHashSet, ty::Region<'tcx>>>; - impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for InferVisitor<'cx, 'tcx> { fn visit_item(&mut self, item: &hir::Item) { let item_did = self.tcx.hir.local_def_id(item.id); debug!("InferVisitor::visit_item(item={:?})", item_did); - let node_id = self.tcx + let node_id = self + .tcx .hir .as_local_node_id(item_did) .expect("expected local def-id"); @@ -120,7 +107,8 @@ impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for InferVisitor<'cx, 'tcx> { // Therefore mark `predicates_added` as true and which will ensure // we walk the crates again and re-calculate predicates for all // items. - let item_predicates_len: usize = self.global_inferred_outlives + let item_predicates_len: usize = self + .global_inferred_outlives .get(&item_did) .map(|p| p.len()) .unwrap_or(0); @@ -131,9 +119,9 @@ impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for InferVisitor<'cx, 'tcx> { } } - fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {} + fn visit_trait_item(&mut self, _trait_item: &'tcx hir::TraitItem) {} - fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {} + fn visit_impl_item(&mut self, _impl_item: &'tcx hir::ImplItem) {} } fn insert_required_predicates_to_be_wf<'tcx>( @@ -141,7 +129,7 @@ fn insert_required_predicates_to_be_wf<'tcx>( field_ty: Ty<'tcx>, global_inferred_outlives: &FxHashMap>, required_predicates: &mut RequiredPredicates<'tcx>, - explicit_map: &FxHashMap>>>, + explicit_map: &FxHashMap>, ) { for ty in field_ty.walk() { match ty.sty { @@ -150,6 +138,7 @@ fn insert_required_predicates_to_be_wf<'tcx>( // // We also want to calculate potential predicates for the T ty::TyRef(region, rty, _) => { + debug!("TyRef"); insert_outlives_predicate(tcx, rty.into(), region, required_predicates); } @@ -157,7 +146,6 @@ fn insert_required_predicates_to_be_wf<'tcx>( // can load the current set of inferred and explicit // predicates from `global_inferred_outlives` and filter the // ones that are TypeOutlives. - // ty::TyAdt(def, substs) => { // First check the inferred predicates // @@ -177,6 +165,7 @@ fn insert_required_predicates_to_be_wf<'tcx>( // round we will get `U: 'b`. We then apply the substitution // `['b => 'a, U => T]` and thus get the requirement that `T: // 'a` holds for `Foo`. + debug!("TyAdt"); if let Some(unsubstituted_predicates) = global_inferred_outlives.get(&def.did) { for unsubstituted_predicate in unsubstituted_predicates { // `unsubstituted_predicate` is `U: 'b` in the @@ -195,33 +184,51 @@ fn insert_required_predicates_to_be_wf<'tcx>( // Check if the type has any explicit predicates that need // to be added to `required_predicates` // let _: () = substs.region_at(0); - check_explicit_predicates(tcx, &def.did, substs, required_predicates, explicit_map); + check_explicit_predicates( + tcx, + &def.did, + substs, + required_predicates, + explicit_map, + false, + ); } - ty::TyDynamic(obj, region) => { - // FIXME This corresponds to `dyn Trait<..>`. In this - // case, we should use the explicit predicates as - // well. - if let Some(p) = obj.principal() { + ty::TyDynamic(obj, ..) => { + // This corresponds to `dyn Trait<..>`. In this case, we should + // use the explicit predicates as well. + + // We are passing type `ty` as a placeholder value with the function + // `with_self_ty`, since there is no concrete type `Self` for a + // `dyn Trait` at this stage. Therefore when checking explicit + // predicates in `check_explicit_predicates` we need to ignore + // checking the explicit_map for Self type. + debug!("TyDynamic"); + debug!("field_ty = {}", &field_ty); + debug!("ty in field = {}", &ty); + if let Some(ex_trait_ref) = obj.principal() { check_explicit_predicates( tcx, - &p.skip_binder().def_id, - &[region.into()], + &ex_trait_ref.skip_binder().def_id, + ex_trait_ref.with_self_ty(tcx, ty).skip_binder().substs, required_predicates, explicit_map, + true, ); } } ty::TyProjection(obj) => { - // FIXME This corresponds to `>::Bar`. In this case, we should use the + // This corresponds to `>::Bar`. In this case, we should use the // explicit predicates as well. + debug!("TyProjection"); check_explicit_predicates( tcx, - &obj.item_def_id, + &tcx.associated_item(obj.item_def_id).container.id(), obj.substs, required_predicates, explicit_map, + false, ); } @@ -245,199 +252,58 @@ fn insert_required_predicates_to_be_wf<'tcx>( /// will give us `U: 'static` and `U: Foo`. The latter we /// can ignore, but we will want to process `U: 'static`, /// applying the substitution as above. -fn check_explicit_predicates<'tcx>( +pub fn check_explicit_predicates<'tcx>( tcx: TyCtxt<'_, 'tcx, 'tcx>, def_id: &DefId, substs: &[Kind<'tcx>], required_predicates: &mut RequiredPredicates<'tcx>, - explicit_map: &FxHashMap>>>, -) { - if let Some(general_predicates) = explicit_map.get(def_id) { - for general_predicate in general_predicates.iter() { - match general_predicate { - // `poly` is `PolyTypeOutlivesPredicate>` - // where OutlivesPredicate is the predicate - // we want to add. - ty::Predicate::TypeOutlives(poly) => { - let predicate = poly.skip_binder().subst(tcx, substs); - insert_outlives_predicate( - tcx, - predicate.0.into(), - predicate.1, - required_predicates, - ); - } - - // `poly` is `PolyRegionOutlivesPredicate>` - // where OutlivesPredicate is the predicate - // we want to add. - ty::Predicate::RegionOutlives(poly) => { - let predicate = poly.skip_binder().subst(tcx, substs); - insert_outlives_predicate( - tcx, - predicate.0.into(), - predicate.1, - required_predicates, - ); - } - - ty::Predicate::Trait(..) - | ty::Predicate::Projection(..) - | ty::Predicate::WellFormed(..) - | ty::Predicate::ObjectSafe(..) - | ty::Predicate::ClosureKind(..) - | ty::Predicate::Subtype(..) - | ty::Predicate::ConstEvaluatable(..) => (), - } - } - } -} - -/// Given a requirement `T: 'a` or `'b: 'a`, deduce the -/// outlives_component and add it to `required_predicates` -fn insert_outlives_predicate<'tcx>( - tcx: TyCtxt<'_, 'tcx, 'tcx>, - kind: Kind<'tcx>, - outlived_region: Region<'tcx>, - required_predicates: &mut RequiredPredicates<'tcx>, + explicit_map: &FxHashMap>, + ignore_self_ty: bool, ) { - // If the `'a` region is bound within the field type itself, we - // don't want to propagate this constraint to the header. - if !is_free_region(outlived_region) { - return; - } - - match kind.unpack() { - UnpackedKind::Type(ty) => { - // `T: 'outlived_region` for some type `T` - // But T could be a lot of things: - // e.g., if `T = &'b u32`, then `'b: 'outlived_region` is - // what we want to add. + debug!("def_id = {:?}", &def_id); + debug!("substs = {:?}", &substs); + debug!("explicit_map = {:?}", explicit_map); + debug!("required_predicates = {:?}", required_predicates); + if let Some(explicit_predicates) = explicit_map.get(def_id) { + for outlives_predicate in explicit_predicates.iter() { + debug!("outlives_predicate = {:?}", &outlives_predicate); + + // Careful: If we are inferring the effects of a `dyn Trait<..>` + // type, then when we look up the predicates for `Trait`, + // we may find some that reference `Self`. e.g., perhaps the + // definition of `Trait` was: // - // Or if within `struct Foo` you had `T = Vec`, then - // we would want to add `U: 'outlived_region` - for component in tcx.outlives_components(ty) { - match component { - Component::Region(r) => { - // This would arise from something like: - // - // ``` - // struct Foo<'a, 'b> { - // x: &'a &'b u32 - // } - // ``` - // - // Here `outlived_region = 'a` and `kind = &'b - // u32`. Decomposing `&'b u32` into - // components would yield `'b`, and we add the - // where clause that `'b: 'a`. - insert_outlives_predicate( - tcx, - r.into(), - outlived_region, - required_predicates, - ); - } - - Component::Param(param_ty) => { - // param_ty: ty::ParamTy - // This would arise from something like: - // - // ``` - // struct Foo<'a, U> { - // x: &'a Vec - // } - // ``` - // - // Here `outlived_region = 'a` and `kind = - // Vec`. Decomposing `Vec` into - // components would yield `U`, and we add the - // where clause that `U: 'a`. - let ty: Ty<'tcx> = tcx.mk_ty_param(param_ty.idx, param_ty.name); - required_predicates - .insert(ty::OutlivesPredicate(ty.into(), outlived_region)); - } - - Component::Projection(proj_ty) => { - // This would arise from something like: - // - // ``` - // struct Foo<'a, T: Iterator> { - // x: &'a ::Item - // } - // ``` - // - // Here we want to add an explicit `where ::Item: 'a`. - let ty: Ty<'tcx> = tcx.mk_projection(proj_ty.item_def_id, proj_ty.substs); - required_predicates - .insert(ty::OutlivesPredicate(ty.into(), outlived_region)); - } - - Component::EscapingProjection(_) => { - // As above, but the projection involves - // late-bound regions. Therefore, the WF - // requirement is not checked in type definition - // but at fn call site, so ignore it. - // - // ``` - // struct Foo<'a, T: Iterator> { - // x: for<'b> fn(<&'b T as Iterator>::Item) - // // ^^^^^^^^^^^^^^^^^^^^^^^^^ - // } - // ``` - // - // Since `'b` is not in scope on `Foo`, can't - // do anything here, ignore it. - } - - Component::UnresolvedInferenceVariable(_) => bug!("not using infcx"), + // ``` + // trait Trait<'a, T> where Self: 'a { .. } + // ``` + // + // we want to ignore such predicates here, because + // there is no type parameter for them to affect. Consider + // a struct containing `dyn Trait`: + // + // ``` + // struct MyStruct<'x, X> { field: Box> } + // ``` + // + // The `where Self: 'a` predicate refers to the *existential, hidden type* + // that is represented by the `dyn Trait`, not to the `X` type parameter + // (or any other generic parameter) declared on `MyStruct`. + // + // Note that we do this check for self **before** applying `substs`. In the + // case that `substs` come from a `dyn Trait` type, our caller will have + // included `Self = dyn Trait<'x, X>` as the value for `Self`. If we were + // to apply the substs, and not filter this predicate, we might then falsely + // conclude that e.g. `X: 'x` was a reasonable inferred requirement. + if let UnpackedKind::Type(ty) = outlives_predicate.0.unpack() { + if ty.is_self() && ignore_self_ty { + debug!("skipping self ty = {:?}", &ty); + continue; } } - } - - UnpackedKind::Lifetime(r) => { - if !is_free_region(r) { - return; - } - required_predicates.insert(ty::OutlivesPredicate(kind, outlived_region)); - } - } -} - -fn is_free_region(region: Region<'_>) -> bool { - // First, screen for regions that might appear in a type header. - match region { - // *These* correspond to `T: 'a` relationships where `'a` is - // either declared on the type or `'static`: - // - // struct Foo<'a, T> { - // field: &'a T, // this would generate a ReEarlyBound referencing `'a` - // field2: &'static T, // this would generate a ReStatic - // } - // - // We care about these, so fall through. - RegionKind::ReStatic | RegionKind::ReEarlyBound(_) => true, - - // Late-bound regions can appear in `fn` types: - // - // struct Foo { - // field: for<'b> fn(&'b T) // e.g., 'b here - // } - // - // The type above might generate a `T: 'b` bound, but we can - // ignore it. We can't put it on the struct header anyway. - RegionKind::ReLateBound(..) => false, - // These regions don't appear in types from type declarations: - RegionKind::ReEmpty - | RegionKind::ReErased - | RegionKind::ReClosureBound(..) - | RegionKind::ReCanonical(..) - | RegionKind::ReScope(..) - | RegionKind::ReVar(..) - | RegionKind::ReSkolemized(..) - | RegionKind::ReFree(..) => { - bug!("unexpected region in outlives inference: {:?}", region); + let predicate = outlives_predicate.subst(tcx, substs); + debug!("predicate = {:?}", &predicate); + insert_outlives_predicate(tcx, predicate.0.into(), predicate.1, required_predicates); } } } diff --git a/src/librustc_typeck/outlives/mod.rs b/src/librustc_typeck/outlives/mod.rs index e5af4c606912b..b5ba59d64cdc4 100644 --- a/src/librustc_typeck/outlives/mod.rs +++ b/src/librustc_typeck/outlives/mod.rs @@ -7,24 +7,20 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(unused)] -#[allow(dead_code)] + use hir::map as hir_map; -use rustc::dep_graph::DepKind; use rustc::hir; -use rustc::hir::Ty_::*; use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc::ty::maps::Providers; use rustc::ty::subst::UnpackedKind; use rustc::ty::{self, CratePredicatesMap, TyCtxt}; use rustc_data_structures::sync::Lrc; -use util::nodemap::FxHashMap; mod explicit; -mod implicit_empty; mod implicit_infer; /// Code to write unit test for outlives. pub mod test; +mod utils; pub fn provide(providers: &mut Providers) { *providers = Providers { @@ -38,7 +34,8 @@ fn inferred_outlives_of<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, item_def_id: DefId, ) -> Lrc>> { - let id = tcx.hir + let id = tcx + .hir .as_local_node_id(item_def_id) .expect("expected local def-id"); @@ -46,14 +43,34 @@ fn inferred_outlives_of<'a, 'tcx>( hir_map::NodeItem(item) => match item.node { hir::ItemStruct(..) | hir::ItemEnum(..) | hir::ItemUnion(..) => { let crate_map = tcx.inferred_outlives_crate(LOCAL_CRATE); - let dep_node = item_def_id.to_dep_node(tcx, DepKind::InferredOutlivesOf); - tcx.dep_graph.read(dep_node); - crate_map + let predicates = crate_map .predicates .get(&item_def_id) .unwrap_or(&crate_map.empty_predicate) - .clone() + .clone(); + + if tcx.has_attr(item_def_id, "rustc_outlives") { + let mut pred: Vec = predicates + .iter() + .map(|out_pred| match out_pred { + ty::Predicate::RegionOutlives(p) => format!("{}", &p), + + ty::Predicate::TypeOutlives(p) => format!("{}", &p), + + err => bug!("unexpected predicate {:?}", err), + }) + .collect(); + pred.sort(); + + let span = tcx.def_span(item_def_id); + let mut err = tcx.sess.struct_span_err(span, "rustc_outlives"); + for p in &pred { + err.note(p); + } + err.emit(); + } + predicates } _ => Lrc::new(Vec::new()), @@ -76,17 +93,18 @@ fn inferred_outlives_crate<'tcx>( // Compute the inferred predicates let exp = explicit::explicit_predicates(tcx, crate_num); - let mut global_inferred_outlives = implicit_infer::infer_predicates(tcx, &exp); + let global_inferred_outlives = implicit_infer::infer_predicates(tcx, &exp); // Convert the inferred predicates into the "collected" form the // global data structure expects. // // FIXME -- consider correcting impedance mismatch in some way, // probably by updating the global data structure. - let mut predicates = global_inferred_outlives + let predicates = global_inferred_outlives .iter() .map(|(&def_id, set)| { - let vec: Vec> = set.iter() + let vec: Vec> = set + .iter() .map( |ty::OutlivesPredicate(kind1, region2)| match kind1.unpack() { UnpackedKind::Type(ty1) => ty::Predicate::TypeOutlives(ty::Binder::bind( diff --git a/src/librustc_typeck/outlives/utils.rs b/src/librustc_typeck/outlives/utils.rs new file mode 100644 index 0000000000000..5cb1822b04e9d --- /dev/null +++ b/src/librustc_typeck/outlives/utils.rs @@ -0,0 +1,167 @@ +// Copyright 2013 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. + +use rustc::ty::outlives::Component; +use rustc::ty::subst::{Kind, UnpackedKind}; +use rustc::ty::{self, Region, RegionKind, Ty, TyCtxt}; +use std::collections::BTreeSet; + +/// Tracks the `T: 'a` or `'a: 'a` predicates that we have inferred +/// must be added to the struct header. +pub type RequiredPredicates<'tcx> = BTreeSet, ty::Region<'tcx>>>; + +/// Given a requirement `T: 'a` or `'b: 'a`, deduce the +/// outlives_component and add it to `required_predicates` +pub fn insert_outlives_predicate<'tcx>( + tcx: TyCtxt<'_, 'tcx, 'tcx>, + kind: Kind<'tcx>, + outlived_region: Region<'tcx>, + required_predicates: &mut RequiredPredicates<'tcx>, +) { + // If the `'a` region is bound within the field type itself, we + // don't want to propagate this constraint to the header. + if !is_free_region(outlived_region) { + return; + } + + match kind.unpack() { + UnpackedKind::Type(ty) => { + // `T: 'outlived_region` for some type `T` + // But T could be a lot of things: + // e.g., if `T = &'b u32`, then `'b: 'outlived_region` is + // what we want to add. + // + // Or if within `struct Foo` you had `T = Vec`, then + // we would want to add `U: 'outlived_region` + for component in tcx.outlives_components(ty) { + match component { + Component::Region(r) => { + // This would arise from something like: + // + // ``` + // struct Foo<'a, 'b> { + // x: &'a &'b u32 + // } + // ``` + // + // Here `outlived_region = 'a` and `kind = &'b + // u32`. Decomposing `&'b u32` into + // components would yield `'b`, and we add the + // where clause that `'b: 'a`. + insert_outlives_predicate( + tcx, + r.into(), + outlived_region, + required_predicates, + ); + } + + Component::Param(param_ty) => { + // param_ty: ty::ParamTy + // This would arise from something like: + // + // ``` + // struct Foo<'a, U> { + // x: &'a Vec + // } + // ``` + // + // Here `outlived_region = 'a` and `kind = + // Vec`. Decomposing `Vec` into + // components would yield `U`, and we add the + // where clause that `U: 'a`. + let ty: Ty<'tcx> = param_ty.to_ty(tcx); + required_predicates + .insert(ty::OutlivesPredicate(ty.into(), outlived_region)); + } + + Component::Projection(proj_ty) => { + // This would arise from something like: + // + // ``` + // struct Foo<'a, T: Iterator> { + // x: &'a ::Item + // } + // ``` + // + // Here we want to add an explicit `where ::Item: 'a`. + let ty: Ty<'tcx> = tcx.mk_projection(proj_ty.item_def_id, proj_ty.substs); + required_predicates + .insert(ty::OutlivesPredicate(ty.into(), outlived_region)); + } + + Component::EscapingProjection(_) => { + // As above, but the projection involves + // late-bound regions. Therefore, the WF + // requirement is not checked in type definition + // but at fn call site, so ignore it. + // + // ``` + // struct Foo<'a, T: Iterator> { + // x: for<'b> fn(<&'b T as Iterator>::Item) + // // ^^^^^^^^^^^^^^^^^^^^^^^^^ + // } + // ``` + // + // Since `'b` is not in scope on `Foo`, can't + // do anything here, ignore it. + } + + Component::UnresolvedInferenceVariable(_) => bug!("not using infcx"), + } + } + } + + UnpackedKind::Lifetime(r) => { + if !is_free_region(r) { + return; + } + required_predicates.insert(ty::OutlivesPredicate(kind, outlived_region)); + } + } +} + +fn is_free_region(region: Region<'_>) -> bool { + // First, screen for regions that might appear in a type header. + match region { + // *These* correspond to `T: 'a` relationships where `'a` is + // either declared on the type or `'static`: + // + // struct Foo<'a, T> { + // field: &'a T, // this would generate a ReEarlyBound referencing `'a` + // field2: &'static T, // this would generate a ReStatic + // } + // + // We care about these, so fall through. + RegionKind::ReStatic | RegionKind::ReEarlyBound(_) => true, + + // Late-bound regions can appear in `fn` types: + // + // struct Foo { + // field: for<'b> fn(&'b T) // e.g., 'b here + // } + // + // The type above might generate a `T: 'b` bound, but we can + // ignore it. We can't put it on the struct header anyway. + RegionKind::ReLateBound(..) => false, + + // These regions don't appear in types from type declarations: + RegionKind::ReEmpty + | RegionKind::ReErased + | RegionKind::ReClosureBound(..) + | RegionKind::ReCanonical(..) + | RegionKind::ReScope(..) + | RegionKind::ReVar(..) + | RegionKind::ReSkolemized(..) + | RegionKind::ReFree(..) => { + bug!("unexpected region in outlives inference: {:?}", region); + } + } +} diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 3a02646d0af5f..4293fe9125dd3 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -795,6 +795,12 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG attribute is an experimental \ feature", cfg_fn!(needs_panic_runtime))), + ("rustc_outlives", Normal, Gated(Stability::Unstable, + "rustc_attrs", + "the `#[rustc_outlives]` attribute \ + is just used for rustc unit tests \ + and will never be stable", + cfg_fn!(rustc_attrs))), ("rustc_variance", Normal, Gated(Stability::Unstable, "rustc_attrs", "the `#[rustc_variance]` attribute \ diff --git a/src/test/compile-fail/outlives-associated-types.rs b/src/test/compile-fail/outlives-associated-types.rs deleted file mode 100644 index 5c392223f88b7..0000000000000 --- a/src/test/compile-fail/outlives-associated-types.rs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2015 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. - -// ignore-tidy-linelength - -// Test that the outlives computation runs for now... - -#![feature(rustc_attrs)] - -//todo add all the test cases -// https://github.com/rust-lang/rfcs/blob/master/text/2093-infer-outlives.md#example-1-a-reference - -#[rustc_outlives] -struct Direct<'a, T> { //~ ERROR 21:1: 23:2: [Binder(OutlivesPredicate(T, ReEarlyBound(0, 'a)))] [E0640] - field: &'a T -} - -fn main() { } diff --git a/src/test/ui/rfc-2093-infer-outlives/multiple-regions.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-dyn.rs similarity index 67% rename from src/test/ui/rfc-2093-infer-outlives/multiple-regions.rs rename to src/test/ui/rfc-2093-infer-outlives/explicit-dyn.rs index 7ea1ce2d3dc1b..445c246a12067 100644 --- a/src/test/ui/rfc-2093-infer-outlives/multiple-regions.rs +++ b/src/test/ui/rfc-2093-infer-outlives/explicit-dyn.rs @@ -8,12 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Needs an explicit where clause stating outlives condition. (RFC 2093) +#![feature(dyn_trait)] +#![feature(rustc_attrs)] +#![feature(infer_outlives_requirements)] -// Lifetime 'b needs to outlive lifetime 'a -struct Foo<'a,'b,T> { - x: &'a &'b T //~ ERROR reference has a longer lifetime than the data it references [E0491] +trait Trait<'x, T> where T: 'x { } -fn main() {} +#[rustc_outlives] +struct Foo<'a, A> //~ ERROR 19:1: 22:2: rustc_outlives +{ + foo: Box> +} +fn main() {} diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-dyn.stderr b/src/test/ui/rfc-2093-infer-outlives/explicit-dyn.stderr new file mode 100644 index 0000000000000..4bb5d90e9644e --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/explicit-dyn.stderr @@ -0,0 +1,13 @@ +error: rustc_outlives + --> $DIR/explicit-dyn.rs:19:1 + | +LL | / struct Foo<'a, A> //~ ERROR 19:1: 22:2: rustc_outlives +LL | | { +LL | | foo: Box> +LL | | } + | |_^ + | + = note: A : 'a + +error: aborting due to previous error + diff --git a/src/test/ui/rfc-2093-infer-outlives/projections-pass.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-enum.rs similarity index 74% rename from src/test/ui/rfc-2093-infer-outlives/projections-pass.rs rename to src/test/ui/rfc-2093-infer-outlives/explicit-enum.rs index 9c6e84cdd6e02..e85b49bb0bf23 100644 --- a/src/test/ui/rfc-2093-infer-outlives/projections-pass.rs +++ b/src/test/ui/rfc-2093-infer-outlives/explicit-enum.rs @@ -8,16 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-pass - +#![feature(rustc_attrs)] #![feature(infer_outlives_requirements)] -// Outlives requirementes are inferred (RFC 2093) -// projections: infer ::Item: 'a -struct ProjFoo<'a, T: Iterator> { - bar: &'a T::Item +#[rustc_outlives] +enum Foo<'a, U> { //~ ERROR 15:1: 17:2: rustc_outlives + One(Bar<'a, U>) } +struct Bar<'x, T> where T: 'x { + x: &'x (), + y: T, +} fn main() {} diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-enum.stderr b/src/test/ui/rfc-2093-infer-outlives/explicit-enum.stderr new file mode 100644 index 0000000000000..d7438758d77af --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/explicit-enum.stderr @@ -0,0 +1,12 @@ +error: rustc_outlives + --> $DIR/explicit-enum.rs:15:1 + | +LL | / enum Foo<'a, U> { //~ ERROR 15:1: 17:2: rustc_outlives +LL | | One(Bar<'a, U>) +LL | | } + | |_^ + | + = note: U : 'a + +error: aborting due to previous error + diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-impl-lifetime-pass.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-impl-lifetime-pass.rs deleted file mode 100644 index 45449fa0cf82d..0000000000000 --- a/src/test/ui/rfc-2093-infer-outlives/explicit-impl-lifetime-pass.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2015 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. - -// ignore-test -// compile-pass - -#![feature(infer_outlives_requirements)] -// Outlives requirementes are inferred (RFC 2093) - -trait MakeRef<'a>: 'a { - type Type; -} -impl<'a, T> MakeRef<'a> for Vec -where T: 'a, -{ - type Type = &'a T; -} -// explicit-impl: T: 'a -struct Foo<'a, T> { - foo: as MakeRef<'a>>::Type, -} - -fn main() {} diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-impl-pass.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-impl-pass.rs deleted file mode 100644 index bfd6db1eb5d4e..0000000000000 --- a/src/test/ui/rfc-2093-infer-outlives/explicit-impl-pass.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2015 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. - -// ignore-test -// compile-pass - -#![feature(infer_outlives_requirements)] -// Outlives requirementes are inferred (RFC 2093) - -trait MakeRef<'a> { - type Type; -} -impl<'a, T> MakeRef<'a> for Vec -where T: 'a, -{ - type Type = &'a T; -} -// explicit-impl: T: 'a -struct Foo<'a, T> { - foo: as MakeRef<'a>>::Type, -} - -fn main() {} diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-impl.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-impl.rs deleted file mode 100644 index 3a10087551c4e..0000000000000 --- a/src/test/ui/rfc-2093-infer-outlives/explicit-impl.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2015 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. - -// ignore-tidy-linelength - -// Needs an explicit where clause stating outlives condition. (RFC 2093) - -trait MakeRef<'a> { - type Type; -} - -impl<'a, T> MakeRef<'a> for Vec - where T: 'a -{ - type Type = &'a T; -} - -// Type T needs to outlive lifetime 'a, as stated in impl. -struct Foo<'a, T> { - foo: as MakeRef<'a>>::Type //~ Error the parameter type `T` may not live long enough [E0309] -} - -fn main() { } diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-impl.stderr b/src/test/ui/rfc-2093-infer-outlives/explicit-impl.stderr deleted file mode 100644 index 498d66ef9a542..0000000000000 --- a/src/test/ui/rfc-2093-infer-outlives/explicit-impl.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0309]: the parameter type `T` may not live long enough - --> $DIR/explicit-impl.rs:27:5 - | -LL | struct Foo<'a, T> { - | - help: consider adding an explicit lifetime bound `T: 'a`... -LL | foo: as MakeRef<'a>>::Type //~ Error the parameter type `T` may not live long enough [E0309] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: ...so that the type `T` will meet its required lifetime bounds - --> $DIR/explicit-impl.rs:27:5 - | -LL | foo: as MakeRef<'a>>::Type //~ Error the parameter type `T` may not live long enough [E0309] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0309`. diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-projection.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-projection.rs new file mode 100644 index 0000000000000..2662043c36d59 --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/explicit-projection.rs @@ -0,0 +1,24 @@ +// Copyright 2018 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. + +#![feature(rustc_attrs)] +#![feature(infer_outlives_requirements)] + +trait Trait<'x, T> where T: 'x { + type Type; +} + +#[rustc_outlives] +struct Foo<'a, A, B> where A: Trait<'a, B> //~ ERROR rustc_outlives +{ + foo: >::Type +} + +fn main() {} diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-projection.stderr b/src/test/ui/rfc-2093-infer-outlives/explicit-projection.stderr new file mode 100644 index 0000000000000..43ab02d01ed57 --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/explicit-projection.stderr @@ -0,0 +1,13 @@ +error: rustc_outlives + --> $DIR/explicit-projection.rs:19:1 + | +LL | / struct Foo<'a, A, B> where A: Trait<'a, B> //~ ERROR rustc_outlives +LL | | { +LL | | foo: >::Type +LL | | } + | |_^ + | + = note: B : 'a + +error: aborting due to previous error + diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-where-pass.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-struct.rs similarity index 75% rename from src/test/ui/rfc-2093-infer-outlives/explicit-where-pass.rs rename to src/test/ui/rfc-2093-infer-outlives/explicit-struct.rs index fd5fc79a2ab1e..d42c9160e1e75 100644 --- a/src/test/ui/rfc-2093-infer-outlives/explicit-where-pass.rs +++ b/src/test/ui/rfc-2093-infer-outlives/explicit-struct.rs @@ -8,20 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-pass - +#![feature(rustc_attrs)] #![feature(infer_outlives_requirements)] -// Outlives requirementes are inferred (RFC 2093) -// explicit-where: infer U: 'b -struct ExFoo<'b, U> { - bar: ExBar<'b, U> +#[rustc_outlives] +struct Foo<'b, U> { //~ ERROR 15:1: 17:2: rustc_outlives + bar: Bar<'b, U> } -struct ExBar<'a, T> where T: 'a { + +struct Bar<'a, T> where T: 'a { x: &'a (), y: T, } - fn main() {} diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-struct.stderr b/src/test/ui/rfc-2093-infer-outlives/explicit-struct.stderr new file mode 100644 index 0000000000000..0223f707e8d9b --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/explicit-struct.stderr @@ -0,0 +1,12 @@ +error: rustc_outlives + --> $DIR/explicit-struct.rs:15:1 + | +LL | / struct Foo<'b, U> { //~ ERROR 15:1: 17:2: rustc_outlives +LL | | bar: Bar<'b, U> +LL | | } + | |_^ + | + = note: U : 'b + +error: aborting due to previous error + diff --git a/src/test/ui/rfc-2093-infer-outlives/nested-structs-pass.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-union.rs similarity index 68% rename from src/test/ui/rfc-2093-infer-outlives/nested-structs-pass.rs rename to src/test/ui/rfc-2093-infer-outlives/explicit-union.rs index 9432804cc42bf..e548b24719383 100644 --- a/src/test/ui/rfc-2093-infer-outlives/nested-structs-pass.rs +++ b/src/test/ui/rfc-2093-infer-outlives/explicit-union.rs @@ -8,17 +8,20 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-pass - +#![feature(rustc_attrs)] #![feature(infer_outlives_requirements)] -// Outlives requirementes are inferred (RFC 2093) +#![feature(untagged_unions)] +#![allow(unions_with_drop_fields)] + -// nested-structs: infer U: 'b and therefore T: 'a -struct NestFoo<'a, T> { - field1: NestBar<'a, T> +#[rustc_outlives] +union Foo<'b, U> { //~ ERROR 18:1: 20:2: rustc_outlives + bar: Bar<'b, U> } -struct NestBar<'b, U> { - field2: &'b U + +union Bar<'a, T> where T: 'a { + x: &'a (), + y: T, } fn main() {} diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-union.stderr b/src/test/ui/rfc-2093-infer-outlives/explicit-union.stderr new file mode 100644 index 0000000000000..8622ae12aa10c --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/explicit-union.stderr @@ -0,0 +1,12 @@ +error: rustc_outlives + --> $DIR/explicit-union.rs:18:1 + | +LL | / union Foo<'b, U> { //~ ERROR 18:1: 20:2: rustc_outlives +LL | | bar: Bar<'b, U> +LL | | } + | |_^ + | + = note: U : 'b + +error: aborting due to previous error + diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-where.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-where.rs deleted file mode 100644 index 81734bf514ef3..0000000000000 --- a/src/test/ui/rfc-2093-infer-outlives/explicit-where.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015 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. - -// Needs an explicit where clause stating outlives condition. (RFC 2093) - -// Type U needs to outlive lifetime 'b. -struct Foo<'b, U> { - bar: Bar<'b, U> //~ Error the parameter type `U` may not live long enough [E0309] -} - -struct Bar<'a, T> where T: 'a { - x: &'a (), - y: T, -} - -fn main() { } diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-where.stderr b/src/test/ui/rfc-2093-infer-outlives/explicit-where.stderr deleted file mode 100644 index 436754c7dc1cd..0000000000000 --- a/src/test/ui/rfc-2093-infer-outlives/explicit-where.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0309]: the parameter type `U` may not live long enough - --> $DIR/explicit-where.rs:15:5 - | -LL | struct Foo<'b, U> { - | - help: consider adding an explicit lifetime bound `U: 'b`... -LL | bar: Bar<'b, U> //~ Error the parameter type `U` may not live long enough [E0309] - | ^^^^^^^^^^^^^^^ - | -note: ...so that the type `U` will meet its required lifetime bounds - --> $DIR/explicit-where.rs:15:5 - | -LL | bar: Bar<'b, U> //~ Error the parameter type `U` may not live long enough [E0309] - | ^^^^^^^^^^^^^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0309`. diff --git a/src/test/ui/rfc-2093-infer-outlives/multiple-regions.stderr b/src/test/ui/rfc-2093-infer-outlives/multiple-regions.stderr deleted file mode 100644 index 3722abd5ad648..0000000000000 --- a/src/test/ui/rfc-2093-infer-outlives/multiple-regions.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0491]: in type `&'a &'b T`, reference has a longer lifetime than the data it references - --> $DIR/multiple-regions.rs:15:5 - | -LL | x: &'a &'b T //~ ERROR reference has a longer lifetime than the data it references [E0491] - | ^^^^^^^^^^^^ - | -note: the pointer is valid for the lifetime 'a as defined on the struct at 14:1 - --> $DIR/multiple-regions.rs:14:1 - | -LL | struct Foo<'a,'b,T> { - | ^^^^^^^^^^^^^^^^^^^ -note: but the referenced data is only valid for the lifetime 'b as defined on the struct at 14:1 - --> $DIR/multiple-regions.rs:14:1 - | -LL | struct Foo<'a,'b,T> { - | ^^^^^^^^^^^^^^^^^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0491`. diff --git a/src/test/ui/rfc-2093-infer-outlives/enum-pass.rs b/src/test/ui/rfc-2093-infer-outlives/nested-enum.rs similarity index 71% rename from src/test/ui/rfc-2093-infer-outlives/enum-pass.rs rename to src/test/ui/rfc-2093-infer-outlives/nested-enum.rs index 2a28bde78a85a..85f381ea515c3 100644 --- a/src/test/ui/rfc-2093-infer-outlives/enum-pass.rs +++ b/src/test/ui/rfc-2093-infer-outlives/nested-enum.rs @@ -8,31 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-pass - +#![feature(rustc_attrs)] #![feature(infer_outlives_requirements)] -// Type T needs to outlive lifetime 'a. -enum Foo<'a, T> { + +#[rustc_outlives] +enum Foo<'a, T> { //~ ERROR 16:1: 19:2: rustc_outlives One(Bar<'a, T>) } -// Type U needs to outlive lifetime 'b struct Bar<'b, U> { field2: &'b U } - - -// Type K needs to outlive lifetime 'c. -enum Ying<'c, K> { - One(&'c Yang) -} - -struct Yang { - field2: V -} - fn main() {} - diff --git a/src/test/ui/rfc-2093-infer-outlives/nested-enum.stderr b/src/test/ui/rfc-2093-infer-outlives/nested-enum.stderr new file mode 100644 index 0000000000000..54a886a92fd40 --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/nested-enum.stderr @@ -0,0 +1,13 @@ +error: rustc_outlives + --> $DIR/nested-enum.rs:16:1 + | +LL | / enum Foo<'a, T> { //~ ERROR 16:1: 19:2: rustc_outlives +LL | | +LL | | One(Bar<'a, T>) +LL | | } + | |_^ + | + = note: T : 'a + +error: aborting due to previous error + diff --git a/src/test/ui/rfc-2093-infer-outlives/multiple-regions-pass.rs b/src/test/ui/rfc-2093-infer-outlives/nested-regions.rs similarity index 80% rename from src/test/ui/rfc-2093-infer-outlives/multiple-regions-pass.rs rename to src/test/ui/rfc-2093-infer-outlives/nested-regions.rs index 290dbd330a26c..792d2a02962dc 100644 --- a/src/test/ui/rfc-2093-infer-outlives/multiple-regions-pass.rs +++ b/src/test/ui/rfc-2093-infer-outlives/nested-regions.rs @@ -8,15 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-pass - +#![feature(rustc_attrs)] #![feature(infer_outlives_requirements)] -// Outlives requirementes are inferred (RFC 2093) -// multiple-regions: infer 'b: 'a -struct MultiFoo<'a, 'b, T> { +#[rustc_outlives] +struct Foo<'a, 'b, T> { //~ ERROR 15:1: 17:2: rustc_outlives x: &'a &'b T } fn main() {} - diff --git a/src/test/ui/rfc-2093-infer-outlives/nested-regions.stderr b/src/test/ui/rfc-2093-infer-outlives/nested-regions.stderr new file mode 100644 index 0000000000000..04fe4814a0415 --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/nested-regions.stderr @@ -0,0 +1,14 @@ +error: rustc_outlives + --> $DIR/nested-regions.rs:15:1 + | +LL | / struct Foo<'a, 'b, T> { //~ ERROR 15:1: 17:2: rustc_outlives +LL | | x: &'a &'b T +LL | | } + | |_^ + | + = note: 'b : 'a + = note: T : 'a + = note: T : 'b + +error: aborting due to previous error + diff --git a/src/test/ui/rfc-2093-infer-outlives/nested-structs.rs b/src/test/ui/rfc-2093-infer-outlives/nested-structs.rs index 7c444dbd3b011..71a36dfb34423 100644 --- a/src/test/ui/rfc-2093-infer-outlives/nested-structs.rs +++ b/src/test/ui/rfc-2093-infer-outlives/nested-structs.rs @@ -1,4 +1,4 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,19 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Needs an explicit where clause stating outlives condition. (RFC 2093) +#![feature(rustc_attrs)] +#![feature(infer_outlives_requirements)] - -// Type T needs to outlive lifetime 'a. This is not reported due to -// a compilation error in Bar. -struct Foo<'a, T> { +#[rustc_outlives] +struct Foo<'a, T> { //~ ERROR 15:1: 17:2: rustc_outlives field1: Bar<'a, T> } -// Type U needs to outlive lifetime 'b struct Bar<'b, U> { - field2: &'b U //~ ERROR the parameter type `U` may not live long enough [E0309] + field2: &'b U } fn main() {} - diff --git a/src/test/ui/rfc-2093-infer-outlives/nested-structs.stderr b/src/test/ui/rfc-2093-infer-outlives/nested-structs.stderr index 94d6cbdb5fe84..abea71f2d12fc 100644 --- a/src/test/ui/rfc-2093-infer-outlives/nested-structs.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/nested-structs.stderr @@ -1,17 +1,12 @@ -error[E0309]: the parameter type `U` may not live long enough - --> $DIR/nested-structs.rs:22:5 +error: rustc_outlives + --> $DIR/nested-structs.rs:15:1 | -LL | struct Bar<'b, U> { - | - help: consider adding an explicit lifetime bound `U: 'b`... -LL | field2: &'b U //~ ERROR the parameter type `U` may not live long enough [E0309] - | ^^^^^^^^^^^^^ +LL | / struct Foo<'a, T> { //~ ERROR 15:1: 17:2: rustc_outlives +LL | | field1: Bar<'a, T> +LL | | } + | |_^ | -note: ...so that the reference type `&'b U` does not outlive the data it points at - --> $DIR/nested-structs.rs:22:5 - | -LL | field2: &'b U //~ ERROR the parameter type `U` may not live long enough [E0309] - | ^^^^^^^^^^^^^ + = note: T : 'a error: aborting due to previous error -For more information about this error, try `rustc --explain E0309`. diff --git a/src/test/ui/rfc-2093-infer-outlives/union-pass.rs b/src/test/ui/rfc-2093-infer-outlives/nested-union.rs similarity index 72% rename from src/test/ui/rfc-2093-infer-outlives/union-pass.rs rename to src/test/ui/rfc-2093-infer-outlives/nested-union.rs index 5e46c2b7f5ca9..0720e581e2c5b 100644 --- a/src/test/ui/rfc-2093-infer-outlives/union-pass.rs +++ b/src/test/ui/rfc-2093-infer-outlives/nested-union.rs @@ -8,15 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-pass - +#![feature(rustc_attrs)] #![feature(infer_outlives_requirements)] #![feature(untagged_unions)] #![allow(unions_with_drop_fields)] -// Type T needs to outlive lifetime 'a. This is not reported due to -// a compilation error in Bar. -union Foo<'a, T> { + +#[rustc_outlives] +union Foo<'a, T> { //~ ERROR 18:1: 20:2: rustc_outlives field1: Bar<'a, T> } @@ -25,15 +24,4 @@ union Bar<'b, U> { field2: &'b U } - -// Type K needs to outlive lifetime 'c. -union Ying<'c, K> { - field1: &'c Yang -} - -union Yang { - field2: V -} - fn main() {} - diff --git a/src/test/ui/rfc-2093-infer-outlives/nested-union.stderr b/src/test/ui/rfc-2093-infer-outlives/nested-union.stderr new file mode 100644 index 0000000000000..b7b50c1506146 --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/nested-union.stderr @@ -0,0 +1,12 @@ +error: rustc_outlives + --> $DIR/nested-union.rs:18:1 + | +LL | / union Foo<'a, T> { //~ ERROR 18:1: 20:2: rustc_outlives +LL | | field1: Bar<'a, T> +LL | | } + | |_^ + | + = note: T : 'a + +error: aborting due to previous error + diff --git a/src/test/ui/rfc-2093-infer-outlives/reference-pass.rs b/src/test/ui/rfc-2093-infer-outlives/projection.rs similarity index 79% rename from src/test/ui/rfc-2093-infer-outlives/reference-pass.rs rename to src/test/ui/rfc-2093-infer-outlives/projection.rs index 903b8a9ddbf59..3abce873b28f9 100644 --- a/src/test/ui/rfc-2093-infer-outlives/reference-pass.rs +++ b/src/test/ui/rfc-2093-infer-outlives/projection.rs @@ -8,16 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-pass - +#![feature(rustc_attrs)] #![feature(infer_outlives_requirements)] -// Outlives requirementes are inferred (RFC 2093) -// reference: infer T: 'a -struct RefFoo<'a, T> { - bar: &'a [T] +#[rustc_outlives] +struct Foo<'a, T: Iterator> { //~ ERROR rustc_outlives + bar: &'a T::Item } - fn main() {} diff --git a/src/test/ui/rfc-2093-infer-outlives/projection.stderr b/src/test/ui/rfc-2093-infer-outlives/projection.stderr new file mode 100644 index 0000000000000..dfaf7793a51f2 --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/projection.stderr @@ -0,0 +1,12 @@ +error: rustc_outlives + --> $DIR/projection.rs:15:1 + | +LL | / struct Foo<'a, T: Iterator> { //~ ERROR rustc_outlives +LL | | bar: &'a T::Item +LL | | } + | |_^ + | + = note: ::Item : 'a + +error: aborting due to previous error + diff --git a/src/test/ui/rfc-2093-infer-outlives/projections.rs b/src/test/ui/rfc-2093-infer-outlives/projections.rs deleted file mode 100644 index f6a557c174c19..0000000000000 --- a/src/test/ui/rfc-2093-infer-outlives/projections.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2015 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. - -// ignore-tidy-linelength - -// Needs an explicit where clause stating outlives condition. RFC 2093 - -// Associated type ::Item needs to outlives lifetime 'a. -struct Foo<'a, T: Iterator> { - bar: &'a T::Item //~ Error the associated type `::Item` may not live long enough [E0309] -} - -fn main() { } diff --git a/src/test/ui/rfc-2093-infer-outlives/projections.stderr b/src/test/ui/rfc-2093-infer-outlives/projections.stderr deleted file mode 100644 index 9969cf48ecd3b..0000000000000 --- a/src/test/ui/rfc-2093-infer-outlives/projections.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0309]: the associated type `::Item` may not live long enough - --> $DIR/projections.rs:17:5 - | -LL | bar: &'a T::Item //~ Error the associated type `::Item` may not live long enough [E0309] - | ^^^^^^^^^^^^^^^^ - | - = help: consider adding an explicit lifetime bound `::Item: 'a`... -note: ...so that the reference type `&'a ::Item` does not outlive the data it points at - --> $DIR/projections.rs:17:5 - | -LL | bar: &'a T::Item //~ Error the associated type `::Item` may not live long enough [E0309] - | ^^^^^^^^^^^^^^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0309`. diff --git a/src/test/ui/rfc-2093-infer-outlives/reference.rs b/src/test/ui/rfc-2093-infer-outlives/reference.rs index 01ccc50a130f2..56b1bc3c7d11e 100644 --- a/src/test/ui/rfc-2093-infer-outlives/reference.rs +++ b/src/test/ui/rfc-2093-infer-outlives/reference.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,11 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Needs an explicit where clause stating outlives condition. (RFC 2093) +#![feature(rustc_attrs)] +#![feature(infer_outlives_requirements)] -// Type T needs to outlive lifetime 'a. -struct Foo<'a, T> { - bar: &'a [T] //~ ERROR the parameter type `T` may not live long enough [E0309] +#[rustc_outlives] +struct Foo<'a, T> { //~ ERROR rustc_outlives + bar: &'a T, } -fn main() { } +fn main() {} diff --git a/src/test/ui/rfc-2093-infer-outlives/reference.stderr b/src/test/ui/rfc-2093-infer-outlives/reference.stderr index 7236bd535c9f2..785d76e8f2275 100644 --- a/src/test/ui/rfc-2093-infer-outlives/reference.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/reference.stderr @@ -1,17 +1,12 @@ -error[E0309]: the parameter type `T` may not live long enough - --> $DIR/reference.rs:15:5 +error: rustc_outlives + --> $DIR/reference.rs:15:1 | -LL | struct Foo<'a, T> { - | - help: consider adding an explicit lifetime bound `T: 'a`... -LL | bar: &'a [T] //~ ERROR the parameter type `T` may not live long enough [E0309] - | ^^^^^^^^^^^^ +LL | / struct Foo<'a, T> { //~ ERROR rustc_outlives +LL | | bar: &'a T, +LL | | } + | |_^ | -note: ...so that the reference type `&'a [T]` does not outlive the data it points at - --> $DIR/reference.rs:15:5 - | -LL | bar: &'a [T] //~ ERROR the parameter type `T` may not live long enough [E0309] - | ^^^^^^^^^^^^ + = note: T : 'a error: aborting due to previous error -For more information about this error, try `rustc --explain E0309`. diff --git a/src/test/ui/rfc-2093-infer-outlives/self-dyn.rs b/src/test/ui/rfc-2093-infer-outlives/self-dyn.rs new file mode 100644 index 0000000000000..a19bcf8afff9a --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/self-dyn.rs @@ -0,0 +1,25 @@ +// Copyright 2018 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. + +#![feature(dyn_trait)] +#![feature(rustc_attrs)] +#![feature(infer_outlives_requirements)] + +trait Trait<'x, 's, T> where T: 'x, + 's: { +} + +#[rustc_outlives] +struct Foo<'a, 'b, A> //~ ERROR 20:1: 23:2: rustc_outlives +{ + foo: Box> +} + +fn main() {} diff --git a/src/test/ui/rfc-2093-infer-outlives/self-dyn.stderr b/src/test/ui/rfc-2093-infer-outlives/self-dyn.stderr new file mode 100644 index 0000000000000..546ba9db64460 --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/self-dyn.stderr @@ -0,0 +1,13 @@ +error: rustc_outlives + --> $DIR/self-dyn.rs:20:1 + | +LL | / struct Foo<'a, 'b, A> //~ ERROR 20:1: 23:2: rustc_outlives +LL | | { +LL | | foo: Box> +LL | | } + | |_^ + | + = note: A : 'a + +error: aborting due to previous error + diff --git a/src/test/ui/rfc-2093-infer-outlives/self-structs.rs b/src/test/ui/rfc-2093-infer-outlives/self-structs.rs new file mode 100644 index 0000000000000..c4f8f83bdcefd --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/self-structs.rs @@ -0,0 +1,24 @@ +// Copyright 2015 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. + +#![feature(rustc_attrs)] +#![feature(infer_outlives_requirements)] + +#[rustc_outlives] +struct Foo<'a, 'b, T> { //~ ERROR 15:1: 17:2: rustc_outlives + field1: Bar<'a, 'b, T> +} + +trait Bar<'x, 's, U> + where U: 'x, + Self:'s +{} + +fn main() {} diff --git a/src/test/ui/rfc-2093-infer-outlives/self-structs.stderr b/src/test/ui/rfc-2093-infer-outlives/self-structs.stderr new file mode 100644 index 0000000000000..04284577a0746 --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/self-structs.stderr @@ -0,0 +1,12 @@ +error: rustc_outlives + --> $DIR/self-structs.rs:15:1 + | +LL | / struct Foo<'a, 'b, T> { //~ ERROR 15:1: 17:2: rustc_outlives +LL | | field1: Bar<'a, 'b, T> +LL | | } + | |_^ + | + = note: T : 'a + +error: aborting due to previous error + diff --git a/src/test/ui/rfc-2093-infer-outlives/union.rs b/src/test/ui/rfc-2093-infer-outlives/union.rs deleted file mode 100644 index 36b1dccb13ebb..0000000000000 --- a/src/test/ui/rfc-2093-infer-outlives/union.rs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2018 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. - -// ignore-tidy-linelength - -// Needs an explicit where clause stating outlives condition. (RFC 2093) - -#![feature(untagged_unions)] - -// Type T needs to outlive lifetime 'a. This is not reported due to -// a compilation error in Bar. -union Foo<'a, T> { - field1: Bar<'a, T> -} - -// Type U needs to outlive lifetime 'b -union Bar<'b, U> { - field2: &'b U //~ ERROR 25:5: 25:18: the parameter type `U` may not live long enough [E0309] -} - - -// Type K needs to outlive lifetime 'c. -union Ying<'c, K> { - field1: &'c Yang //~ ERROR 31:5: 31:24: the parameter type `K` may not live long enough [E0309] -} - -union Yang { - field2: V -} - - -fn main() {} - diff --git a/src/test/ui/rfc-2093-infer-outlives/union.stderr b/src/test/ui/rfc-2093-infer-outlives/union.stderr deleted file mode 100644 index cd13c42329332..0000000000000 --- a/src/test/ui/rfc-2093-infer-outlives/union.stderr +++ /dev/null @@ -1,31 +0,0 @@ -error[E0309]: the parameter type `U` may not live long enough - --> $DIR/union.rs:25:5 - | -LL | union Bar<'b, U> { - | - help: consider adding an explicit lifetime bound `U: 'b`... -LL | field2: &'b U //~ ERROR 25:5: 25:18: the parameter type `U` may not live long enough [E0309] - | ^^^^^^^^^^^^^ - | -note: ...so that the reference type `&'b U` does not outlive the data it points at - --> $DIR/union.rs:25:5 - | -LL | field2: &'b U //~ ERROR 25:5: 25:18: the parameter type `U` may not live long enough [E0309] - | ^^^^^^^^^^^^^ - -error[E0309]: the parameter type `K` may not live long enough - --> $DIR/union.rs:31:5 - | -LL | union Ying<'c, K> { - | - help: consider adding an explicit lifetime bound `K: 'c`... -LL | field1: &'c Yang //~ ERROR 31:5: 31:24: the parameter type `K` may not live long enough [E0309] - | ^^^^^^^^^^^^^^^^^^^ - | -note: ...so that the reference type `&'c Yang` does not outlive the data it points at - --> $DIR/union.rs:31:5 - | -LL | field1: &'c Yang //~ ERROR 31:5: 31:24: the parameter type `K` may not live long enough [E0309] - | ^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0309`.