diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index b8544177bbbbe..7201e26edc9f6 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -314,7 +314,7 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>( // which cannot be outlived. None => return Ok(()), }; - let parent_scope = rcx.tcx.mk_region(ty::ReScope(parent_scope)); + let parent_scope_region = rcx.tcx.mk_region(ty::ReScope(parent_scope)); let origin = || infer::SubregionOrigin::SafeDestructor(span); let cause = &ObligationCause::misc(span, body_id); let infer_ok = rcx.infcx.at(cause, rcx.fcx.param_env).dropck_outlives(ty); @@ -322,8 +322,8 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>( let kinds = rcx.fcx.register_infer_ok_obligations(infer_ok); for kind in kinds { match kind.unpack() { - UnpackedKind::Lifetime(r) => rcx.sub_regions(origin(), parent_scope, r), - UnpackedKind::Type(ty) => rcx.type_must_outlive(origin(), ty, parent_scope), + UnpackedKind::Lifetime(r) => rcx.sub_regions(origin(), parent_scope_region, r), + UnpackedKind::Type(ty) => rcx.type_must_be_valid_for_scope(origin(), ty, parent_scope), } } Ok(()) diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 212ee2698e012..fdd7dabc89902 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -373,10 +373,13 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { body.id(), call_site_scope ); - let call_site_region = self.tcx.mk_region(ty::ReScope(call_site_scope)); let body_hir_id = self.tcx.hir.node_to_hir_id(body_id.node_id); - self.type_of_node_must_outlive(infer::CallReturn(span), body_hir_id, call_site_region); + self.type_of_node_must_be_valid_for_scope( + infer::CallReturn(span), + body_hir_id, + call_site_scope, + ); self.constrain_opaque_types( &self.fcx.opaque_types.borrow(), @@ -434,10 +437,9 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { // that the lifetime of any regions that appear in a // variable's type enclose at least the variable's scope. let var_scope = self.region_scope_tree.var_scope(hir_id.local_id); - let var_region = self.tcx.mk_region(ty::ReScope(var_scope)); let origin = infer::BindingTypeIsNotValidAtDecl(span); - self.type_of_node_must_outlive(origin, hir_id, var_region); + self.type_of_node_must_be_valid_for_scope(origin, hir_id, var_scope); let typ = self.resolve_node_type(hir_id); let body_id = self.body_id; @@ -520,14 +522,15 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { // scope of that expression. This also guarantees basic WF. let expr_ty = self.resolve_node_type(expr.hir_id); // the region corresponding to this expression - let expr_region = self.tcx.mk_region(ty::ReScope(region::Scope { + let expr_scope = region::Scope { id: expr.hir_id.local_id, data: region::ScopeData::Node, - })); - self.type_must_outlive( + }; + let expr_region = self.tcx.mk_region(ty::ReScope(expr_scope)); + self.type_must_be_valid_for_scope( infer::ExprTypeIsNotInScope(expr_ty, expr.span), expr_ty, - expr_region, + expr_scope, ); let is_method_call = self.tables.borrow().is_method_call(expr); @@ -546,7 +549,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { }; let substs = self.tables.borrow().node_substs(expr.hir_id); - self.substs_wf_in_scope(origin, substs, expr.span, expr_region); + self.substs_wf_in_scope(origin, substs, expr.span, expr_scope); // Arguments (sub-expressions) are checked via `constrain_call`, below. } @@ -572,7 +575,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { hir::ExprKind::Path(_) => { let substs = self.tables.borrow().node_substs(expr.hir_id); let origin = infer::ParameterOrigin::Path; - self.substs_wf_in_scope(origin, substs, expr.span, expr_region); + self.substs_wf_in_scope(origin, substs, expr.span, expr_scope); } hir::ExprKind::Call(ref callee, ref args) => { @@ -619,7 +622,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { let lhs_ty = self.resolve_expr_type_adjusted(&lhs); let rhs_ty = self.resolve_expr_type_adjusted(&rhs); for &ty in &[lhs_ty, rhs_ty] { - self.type_must_outlive(infer::Operand(expr.span), ty, expr_region); + self.type_must_be_valid_for_scope(infer::Operand(expr.span), ty, expr_scope); } intravisit::walk_expr(self, expr); } @@ -674,7 +677,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { // FIXME(https://github.com/rust-lang/rfcs/issues/811) // nested method calls requires that this rule change let ty0 = self.resolve_node_type(expr.hir_id); - self.type_must_outlive(infer::AddrOf(expr.span), ty0, expr_region); + self.type_must_be_valid_for_scope(infer::AddrOf(expr.span), ty0, expr_scope); intravisit::walk_expr(self, expr); } @@ -705,16 +708,15 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { } hir::ExprKind::Ret(Some(ref ret_expr)) => { - let call_site_scope = self.call_site_scope; + let call_site_scope = self.call_site_scope.unwrap(); debug!( "visit_expr ExprKind::Ret ret_expr.id {} call_site_scope: {:?}", ret_expr.id, call_site_scope ); - let call_site_region = self.tcx.mk_region(ty::ReScope(call_site_scope.unwrap())); - self.type_of_node_must_outlive( + self.type_of_node_must_be_valid_for_scope( infer::CallReturn(ret_expr.span), ret_expr.hir_id, - call_site_region, + call_site_scope, ); intravisit::walk_expr(self, expr); } @@ -813,26 +815,29 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { id: call_expr.hir_id.local_id, data: region::ScopeData::Node, }; - let callee_region = self.tcx.mk_region(ty::ReScope(callee_scope)); - debug!("callee_region={:?}", callee_region); + debug!("callee_scope={:?}", callee_scope); for arg_expr in arg_exprs { debug!("Argument: {:?}", arg_expr); // ensure that any regions appearing in the argument type are // valid for at least the lifetime of the function: - self.type_of_node_must_outlive( + self.type_of_node_must_be_valid_for_scope( infer::CallArg(arg_expr.span), arg_expr.hir_id, - callee_region, + callee_scope, ); } // as loop above, but for receiver if let Some(r) = receiver { debug!("receiver: {:?}", r); - self.type_of_node_must_outlive(infer::CallRcvr(r.span), r.hir_id, callee_region); + self.type_of_node_must_be_valid_for_scope( + infer::CallRcvr(r.span), + r.hir_id, + callee_scope, + ); } } @@ -867,10 +872,11 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { // expression. self.check_safety_of_rvalue_destructor_if_necessary(&cmt, expr.span); - let expr_region = self.tcx.mk_region(ty::ReScope(region::Scope { + let expr_scope = region::Scope { id: expr.hir_id.local_id, data: region::ScopeData::Node, - })); + }; + let expr_region = self.tcx.mk_region(ty::ReScope(expr_scope)); for adjustment in adjustments { debug!( "constrain_adjustments: adjustment={:?}, cmt={:?}", @@ -905,8 +911,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { ); // Specialized version of constrain_call. - self.type_must_outlive(infer::CallRcvr(expr.span), input, expr_region); - self.type_must_outlive(infer::CallReturn(expr.span), output, expr_region); + self.type_must_be_valid_for_scope(infer::CallRcvr(expr.span), input, expr_scope); + self.type_must_be_valid_for_scope(infer::CallReturn(expr.span), output, expr_scope); } if let adjustment::Adjust::Borrow(ref autoref) = adjustment.kind { @@ -916,10 +922,10 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { // the current node. // // FIXME(#6268) remove to support nested method calls - self.type_of_node_must_outlive( + self.type_of_node_must_be_valid_for_scope( infer::AutoBorrow(expr.span), expr.hir_id, - expr_region, + expr_scope, ); } @@ -999,13 +1005,16 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { } } - /// Guarantees that any lifetimes which appear in the type of the node `id` (after applying - /// adjustments) are valid for at least `minimum_lifetime` - fn type_of_node_must_outlive( + /// Requires that all regions in the (fully adjusted) type of the + /// node `hir_id` are **valid** during the scope. This means that + /// they have to outlive `scope`. This implies `T: scope` but is + /// actually stronger than that in the case of projections. This + /// helps overcome some weakenesses in our inference (see #55756). + fn type_of_node_must_be_valid_for_scope( &mut self, origin: infer::SubregionOrigin<'tcx>, hir_id: hir::HirId, - minimum_lifetime: ty::Region<'tcx>, + scope: region::Scope, ) { // Try to resolve the type. If we encounter an error, then typeck // is going to fail anyway, so just stop here and let typeck @@ -1021,10 +1030,34 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { let ty = self.resolve_type(ty); debug!( "constrain_regions_in_type_of_node(\ - ty={}, ty0={}, id={:?}, minimum_lifetime={:?})", - ty, ty0, hir_id, minimum_lifetime + ty={}, ty0={}, id={:?}, scope={:?})", + ty, ty0, hir_id, scope + ); + + self.type_must_be_valid_for_scope(origin, ty, scope) + } + + /// Requires that all regions in the type `T` are **valid** during + /// the scope. This means that they have to outlive `scope`. This + /// implies `T: scope` but is actually stronger than that in the + /// case of projections. This helps overcome some weakenesses in + /// our inference (see #55756). + /// + /// (This is the lexical equivalent of NLL's "liveness rules", + /// which require that any region which appears at the point P + /// must contain the point P.) + pub fn type_must_be_valid_for_scope( + &self, + origin: infer::SubregionOrigin<'tcx>, + ty: Ty<'tcx>, + scope: region::Scope, + ) { + let scope_region = self.tcx.mk_region(ty::ReScope(scope)); + let ty = self.resolve_type_vars_if_possible(&ty); + self.tcx.for_each_free_region( + &ty, + |ty_region| self.sub_regions(origin.clone(), scope_region, ty_region), ); - self.type_must_outlive(origin, ty, minimum_lifetime); } /// Adds constraints to inference such that `T: 'a` holds (or @@ -1408,25 +1441,26 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { origin: infer::ParameterOrigin, substs: &Substs<'tcx>, expr_span: Span, - expr_region: ty::Region<'tcx>, + expr_scope: region::Scope, ) { debug!( "substs_wf_in_scope(substs={:?}, \ - expr_region={:?}, \ + expr_scope={:?}, \ origin={:?}, \ expr_span={:?})", - substs, expr_region, origin, expr_span + substs, expr_scope, origin, expr_span ); let origin = infer::ParameterInScope(origin, expr_span); + let expr_region = self.tcx.mk_region(ty::ReScope(expr_scope)); for region in substs.regions() { self.sub_regions(origin.clone(), expr_region, region); } for ty in substs.types() { let ty = self.resolve_type(ty); - self.type_must_outlive(origin.clone(), ty, expr_region); + self.type_must_be_valid_for_scope(origin.clone(), ty, expr_scope); } } } diff --git a/src/test/incremental/hashes/closure_expressions.rs b/src/test/incremental/hashes/closure_expressions.rs index 85d1f3df05b1d..90feed214408e 100644 --- a/src/test/incremental/hashes/closure_expressions.rs +++ b/src/test/incremental/hashes/closure_expressions.rs @@ -60,14 +60,14 @@ pub fn add_parameter() { // Change parameter pattern ---------------------------------------------------- #[cfg(cfail1)] pub fn change_parameter_pattern() { - let _ = |x: &u32| x; + let _ = |x: &u32| { println!("{}", x); }; } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, MirValidated, TypeckTables")] +#[rustc_clean(cfg="cfail2", except="HirBody, TypeckTables")] #[rustc_clean(cfg="cfail3")] pub fn change_parameter_pattern() { - let _ = |&x: &u32| x; + let _ = |&x: &u32| { println!("{}", x); }; } diff --git a/src/test/ui/borrowck/borrowck-describe-lvalue.ast.nll.stderr b/src/test/ui/borrowck/borrowck-describe-lvalue.ast.nll.stderr index c3aba793f190e..a1824c698aad6 100644 --- a/src/test/ui/borrowck/borrowck-describe-lvalue.ast.nll.stderr +++ b/src/test/ui/borrowck/borrowck-describe-lvalue.ast.nll.stderr @@ -10,7 +10,7 @@ LL | *y = 1; | ------ first borrow later used here error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/borrowck-describe-lvalue.rs:307:20 + --> $DIR/borrowck-describe-lvalue.rs:308:20 | LL | let y = &mut x; | ------ first mutable borrow occurs here @@ -26,10 +26,10 @@ error: captured variable cannot escape `FnMut` closure body LL | || { | - inferred to be a `FnMut` closure LL | / || { //[mir]~ ERROR captured variable cannot escape `FnMut` closure body +LL | | //[ast]~^ ERROR lifetime of `x` is too short LL | | let y = &mut x; LL | | &mut x; //[ast]~ ERROR cannot borrow `**x` as mutable more than once at a time -LL | | //[mir]~^ ERROR cannot borrow `x` as mutable more than once at a time -LL | | *y = 1; +... | LL | | drop(y); LL | | } | |_________________^ returns a closure that contains a reference to a captured variable, which then escapes the closure body @@ -370,7 +370,7 @@ LL | drop(x); This warning will become a hard error in the future. error[E0382]: use of moved value: `x` - --> $DIR/borrowck-describe-lvalue.rs:318:22 + --> $DIR/borrowck-describe-lvalue.rs:319:22 | LL | drop(x); | - value moved here diff --git a/src/test/ui/borrowck/borrowck-describe-lvalue.ast.stderr b/src/test/ui/borrowck/borrowck-describe-lvalue.ast.stderr index bc6385ffd920b..dcc7c724c4a8e 100644 --- a/src/test/ui/borrowck/borrowck-describe-lvalue.ast.stderr +++ b/src/test/ui/borrowck/borrowck-describe-lvalue.ast.stderr @@ -219,8 +219,31 @@ LL | &mut x; //[ast]~ ERROR cannot borrow `**x` as mutable more than LL | }; | - first borrow ends here +error[E0598]: lifetime of `x` is too short to guarantee its contents can be safely reborrowed + --> $DIR/borrowck-describe-lvalue.rs:305:16 + | +LL | || { //[mir]~ ERROR captured variable cannot escape `FnMut` closure body + | ^^ + | +note: `x` would have to be valid for the expression at 304:12... + --> $DIR/borrowck-describe-lvalue.rs:304:12 + | +LL | / || { +LL | | || { //[mir]~ ERROR captured variable cannot escape `FnMut` closure body +LL | | //[ast]~^ ERROR lifetime of `x` is too short +LL | | let y = &mut x; +... | +LL | | } +LL | | }; + | |____________^ +note: ...but `x` is only valid for the lifetime as defined on the body at 304:12 + --> $DIR/borrowck-describe-lvalue.rs:304:12 + | +LL | || { + | ^^ + error[E0499]: cannot borrow `**x` as mutable more than once at a time - --> $DIR/borrowck-describe-lvalue.rs:307:25 + --> $DIR/borrowck-describe-lvalue.rs:308:25 | LL | let y = &mut x; | - first mutable borrow occurs here @@ -231,7 +254,7 @@ LL | } | - first borrow ends here error[E0382]: use of moved value: `x` - --> $DIR/borrowck-describe-lvalue.rs:318:22 + --> $DIR/borrowck-describe-lvalue.rs:319:22 | LL | drop(x); | - value moved here @@ -240,7 +263,7 @@ LL | drop(x); //[ast]~ ERROR use of moved value: `x` | = note: move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait -error: aborting due to 26 previous errors +error: aborting due to 27 previous errors -Some errors occurred: E0382, E0499, E0502, E0503. +Some errors occurred: E0382, E0499, E0502, E0503, E0598. For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-describe-lvalue.mir.stderr b/src/test/ui/borrowck/borrowck-describe-lvalue.mir.stderr index 5721c52ba2172..89a63b8cbd7c4 100644 --- a/src/test/ui/borrowck/borrowck-describe-lvalue.mir.stderr +++ b/src/test/ui/borrowck/borrowck-describe-lvalue.mir.stderr @@ -10,7 +10,7 @@ LL | *y = 1; | ------ first borrow later used here error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/borrowck-describe-lvalue.rs:307:20 + --> $DIR/borrowck-describe-lvalue.rs:308:20 | LL | let y = &mut x; | ------ first mutable borrow occurs here @@ -26,10 +26,10 @@ error: captured variable cannot escape `FnMut` closure body LL | || { | - inferred to be a `FnMut` closure LL | / || { //[mir]~ ERROR captured variable cannot escape `FnMut` closure body +LL | | //[ast]~^ ERROR lifetime of `x` is too short LL | | let y = &mut x; LL | | &mut x; //[ast]~ ERROR cannot borrow `**x` as mutable more than once at a time -LL | | //[mir]~^ ERROR cannot borrow `x` as mutable more than once at a time -LL | | *y = 1; +... | LL | | drop(y); LL | | } | |_________________^ returns a closure that contains a reference to a captured variable, which then escapes the closure body @@ -362,7 +362,7 @@ LL | drop(x); | - mutable borrow later used here error[E0382]: use of moved value: `x` - --> $DIR/borrowck-describe-lvalue.rs:318:22 + --> $DIR/borrowck-describe-lvalue.rs:319:22 | LL | drop(x); | - value moved here diff --git a/src/test/ui/borrowck/borrowck-describe-lvalue.rs b/src/test/ui/borrowck/borrowck-describe-lvalue.rs index 649de888ab0a2..5dce6f68560fc 100644 --- a/src/test/ui/borrowck/borrowck-describe-lvalue.rs +++ b/src/test/ui/borrowck/borrowck-describe-lvalue.rs @@ -303,6 +303,7 @@ fn main() { let mut x = 0; || { || { //[mir]~ ERROR captured variable cannot escape `FnMut` closure body + //[ast]~^ ERROR lifetime of `x` is too short let y = &mut x; &mut x; //[ast]~ ERROR cannot borrow `**x` as mutable more than once at a time //[mir]~^ ERROR cannot borrow `x` as mutable more than once at a time 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..891696a4b6210 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,22 +1,36 @@ // This used to ICE because it creates an `impl Trait` that captures a // hidden empty region. +// +// compile-pass #![feature(conservative_impl_trait)] -fn server() -> impl FilterBase2 { //~ ERROR [E0700] - segment2(|| { loop { } }).map2(|| "") +fn server() -> impl FilterBase2 { + segment2(|| loop {}).map2(|| "") } trait FilterBase2 { - fn map2(self, _fn: F) -> Map2 where Self: Sized { loop { } } + fn map2(self, _fn: F) -> Map2 + where + Self: Sized, + { + loop {} + } } -struct Map2 { _func: F } +struct Map2 { + _func: F, +} -impl FilterBase2 for Map2 { } +impl FilterBase2 for Map2 {} -fn segment2(_fn: F) -> Map2 where F: Fn() -> Result<(), ()> { - loop { } +fn segment2(_fn: F) -> Map2 +where + F: Fn() -> Result<(), ()>, +{ + loop {} } -fn main() { server(); } +fn main() { + server(); +} 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 index d1f147834d2ef..9b8a697242465 100644 --- a/src/test/ui/impl-trait/issue-55608-captures-empty-region.stderr +++ b/src/test/ui/impl-trait/issue-55608-captures-empty-region.stderr @@ -1,11 +1,8 @@ -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/issue-55608-captures-empty-region.rs:6:16 +warning: the feature `conservative_impl_trait` has been stable since 1.26.0 and no longer requires an attribute to enable + --> $DIR/issue-55608-captures-empty-region.rs:6:12 | -LL | fn server() -> impl FilterBase2 { //~ ERROR [E0700] - | ^^^^^^^^^^^^^^^^ +LL | #![feature(conservative_impl_trait)] + | ^^^^^^^^^^^^^^^^^^^^^^^ | - = note: hidden type `Map2<[closure@$DIR/issue-55608-captures-empty-region.rs:7:36: 7:41]>` captures an empty lifetime + = note: #[warn(stable_features)] on by default -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0700`. diff --git a/src/test/ui/issues/issue-40510-1.nll.stderr b/src/test/ui/issues/issue-40510-1.nll.stderr deleted file mode 100644 index 723b6f3111c62..0000000000000 --- a/src/test/ui/issues/issue-40510-1.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -warning: captured variable cannot escape `FnMut` closure body - --> $DIR/issue-40510-1.rs:18:9 - | -LL | || { - | - inferred to be a `FnMut` closure -LL | &mut x - | ^^^^^^ returns a reference to a captured variable which escapes the closure body - | - = note: `FnMut` closures only have access to their captured variables while they are executing... - = note: ...therefore, they cannot allow references to captured variables to escape - = warning: This error has been downgraded to a warning for backwards compatibility with previous releases. - It represents potential unsoundness in your code. - This warning will become a hard error in the future. - diff --git a/src/test/ui/issues/issue-40510-1.rs b/src/test/ui/issues/issue-40510-1.rs index b053f8e7d807a..04e87a03ef80c 100644 --- a/src/test/ui/issues/issue-40510-1.rs +++ b/src/test/ui/issues/issue-40510-1.rs @@ -8,14 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-pass +// (This regression test *used* to pass, but started to fail once +// #55756 was fixed.) + #![allow(unused)] fn f() { let mut x: Box<()> = Box::new(()); || { - &mut x + &mut x //~ ERROR cannot infer }; } diff --git a/src/test/ui/issues/issue-40510-1.stderr b/src/test/ui/issues/issue-40510-1.stderr new file mode 100644 index 0000000000000..68bd9f999b659 --- /dev/null +++ b/src/test/ui/issues/issue-40510-1.stderr @@ -0,0 +1,34 @@ +error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements + --> $DIR/issue-40510-1.rs:20:9 + | +LL | &mut x //~ ERROR cannot infer + | ^^^^^^ + | +note: first, the lifetime cannot outlive the lifetime as defined on the body at 19:5... + --> $DIR/issue-40510-1.rs:19:5 + | +LL | || { + | ^^ +note: ...so that closure can access `x` + --> $DIR/issue-40510-1.rs:20:9 + | +LL | &mut x //~ ERROR cannot infer + | ^^^^^^ +note: but, the lifetime must be valid for the expression at 19:5... + --> $DIR/issue-40510-1.rs:19:5 + | +LL | / || { +LL | | &mut x //~ ERROR cannot infer +LL | | }; + | |_____^ +note: ...so type `[closure@$DIR/issue-40510-1.rs:19:5: 21:6 x:&mut std::boxed::Box<()>]` of expression is valid during the expression + --> $DIR/issue-40510-1.rs:19:5 + | +LL | / || { +LL | | &mut x //~ ERROR cannot infer +LL | | }; + | |_____^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/issues/issue-40510-3.nll.stderr b/src/test/ui/issues/issue-40510-3.nll.stderr index e8e82ee8fdae2..54b342c92722a 100644 --- a/src/test/ui/issues/issue-40510-3.nll.stderr +++ b/src/test/ui/issues/issue-40510-3.nll.stderr @@ -1,16 +1,15 @@ -warning: captured variable cannot escape `FnMut` closure body - --> $DIR/issue-40510-3.rs:18:9 +error: captured variable cannot escape `FnMut` closure body + --> $DIR/issue-40510-3.rs:20:9 | LL | || { | - inferred to be a `FnMut` closure -LL | / || { +LL | / || { //~ ERROR too short LL | | x.push(()) LL | | } | |_________^ returns a closure that contains a reference to a captured variable, which then escapes the closure body | = note: `FnMut` closures only have access to their captured variables while they are executing... = note: ...therefore, they cannot allow references to captured variables to escape - = warning: This error has been downgraded to a warning for backwards compatibility with previous releases. - It represents potential unsoundness in your code. - This warning will become a hard error in the future. + +error: aborting due to previous error diff --git a/src/test/ui/issues/issue-40510-3.rs b/src/test/ui/issues/issue-40510-3.rs index d4d1d28a1376a..26f89f0c9eeef 100644 --- a/src/test/ui/issues/issue-40510-3.rs +++ b/src/test/ui/issues/issue-40510-3.rs @@ -8,14 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-pass +// (This regression test *used* to pass, but started to fail once +// #55756 was fixed.) + #![allow(unused)] fn f() { let mut x: Vec<()> = Vec::new(); || { - || { + || { //~ ERROR too short x.push(()) } }; diff --git a/src/test/ui/issues/issue-40510-3.stderr b/src/test/ui/issues/issue-40510-3.stderr new file mode 100644 index 0000000000000..e393352ff8c44 --- /dev/null +++ b/src/test/ui/issues/issue-40510-3.stderr @@ -0,0 +1,24 @@ +error[E0598]: lifetime of `x` is too short to guarantee its contents can be safely reborrowed + --> $DIR/issue-40510-3.rs:20:9 + | +LL | || { //~ ERROR too short + | ^^ + | +note: `x` would have to be valid for the expression at 19:5... + --> $DIR/issue-40510-3.rs:19:5 + | +LL | / || { +LL | | || { //~ ERROR too short +LL | | x.push(()) +LL | | } +LL | | }; + | |_____^ +note: ...but `x` is only valid for the lifetime as defined on the body at 19:5 + --> $DIR/issue-40510-3.rs:19:5 + | +LL | || { + | ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0598`. diff --git a/src/test/ui/issues/issue-44056.rs b/src/test/ui/issues/issue-44056.rs deleted file mode 100644 index b2f0e917749d5..0000000000000 --- a/src/test/ui/issues/issue-44056.rs +++ /dev/null @@ -1,16 +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. - -// compile-pass -// only-x86_64 -// no-prefer-dynamic -// compile-flags: -Ctarget-feature=+avx -Clto - -fn main() {} diff --git a/src/test/ui/issues/issue-49824.nll.stderr b/src/test/ui/issues/issue-49824.nll.stderr index 555558c99d933..3fd6854322ab1 100644 --- a/src/test/ui/issues/issue-49824.nll.stderr +++ b/src/test/ui/issues/issue-49824.nll.stderr @@ -1,30 +1,15 @@ -warning: captured variable cannot escape `FnMut` closure body - --> $DIR/issue-49824.rs:22:9 +error: captured variable cannot escape `FnMut` closure body + --> $DIR/issue-49824.rs:23:9 | LL | || { | - inferred to be a `FnMut` closure -LL | / || { +LL | / || { //~ ERROR too short LL | | let _y = &mut x; LL | | } | |_________^ returns a closure that contains a reference to a captured variable, which then escapes the closure body | = note: `FnMut` closures only have access to their captured variables while they are executing... = note: ...therefore, they cannot allow references to captured variables to escape - = warning: This error has been downgraded to a warning for backwards compatibility with previous releases. - It represents potential unsoundness in your code. - This warning will become a hard error in the future. - -error: compilation successful - --> $DIR/issue-49824.rs:18:1 - | -LL | / fn main() { -LL | | //~^ compilation successful -LL | | let mut x = 0; -LL | | || { -... | -LL | | }; -LL | | } - | |_^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-49824.rs b/src/test/ui/issues/issue-49824.rs index 1f3e575288427..985f7bb59dc71 100644 --- a/src/test/ui/issues/issue-49824.rs +++ b/src/test/ui/issues/issue-49824.rs @@ -13,13 +13,14 @@ // This test checks that a failure occurs with NLL but does not fail with the // legacy AST output. Check issue-49824.nll.stderr for expected compilation error // output under NLL and #49824 for more information. +// +// UPDATE: Once #55756 was fixed, this test started to fail in both modes. #[rustc_error] fn main() { - //~^ compilation successful let mut x = 0; || { - || { + || { //~ ERROR too short let _y = &mut x; } }; diff --git a/src/test/ui/issues/issue-49824.stderr b/src/test/ui/issues/issue-49824.stderr index b6cafe5e9e994..d4e0b2f47990c 100644 --- a/src/test/ui/issues/issue-49824.stderr +++ b/src/test/ui/issues/issue-49824.stderr @@ -1,14 +1,24 @@ -error: compilation successful - --> $DIR/issue-49824.rs:18:1 - | -LL | / fn main() { -LL | | //~^ compilation successful -LL | | let mut x = 0; -LL | | || { -... | +error[E0598]: lifetime of `x` is too short to guarantee its contents can be safely reborrowed + --> $DIR/issue-49824.rs:23:9 + | +LL | || { //~ ERROR too short + | ^^ + | +note: `x` would have to be valid for the expression at 22:5... + --> $DIR/issue-49824.rs:22:5 + | +LL | / || { +LL | | || { //~ ERROR too short +LL | | let _y = &mut x; +LL | | } LL | | }; -LL | | } - | |_^ + | |_____^ +note: ...but `x` is only valid for the lifetime as defined on the body at 22:5 + --> $DIR/issue-49824.rs:22:5 + | +LL | || { + | ^^ error: aborting due to previous error +For more information about this error, try `rustc --explain E0598`. diff --git a/src/test/ui/issues/issue-55756.rs b/src/test/ui/issues/issue-55756.rs new file mode 100644 index 0000000000000..4ed533bd4c107 --- /dev/null +++ b/src/test/ui/issues/issue-55756.rs @@ -0,0 +1,47 @@ +// Regression test for #55756. +// +// In this test, the result of `self.callee` is a projection `>::Guard`. As it may contain a destructor, the dropck +// rules require that this type outlivess the scope of `state`. Unfortunately, +// our region inference is not smart enough to figure out how to +// translate a requirement like +// +// >::guard: 'r +// +// into a requirement that `'0: 'r` -- in particular, it fails to do +// so because it *also* knows that `>::Guard: 'a` +// from the trait definition. Faced with so many choices, the current +// solver opts to do nothing. +// +// The problem we were having was that we would observe two +// potentially applicable rules when trying to find bounds for `>::Guard`: +// +// ``` +// >::Guard: 'a // from the where clauses +// for<'b> { >::Guard: 'b } // from the trait definition +// ``` +// +// Because of this, we decided to take no action to influence +// inference, which means that `'0` winds up unconstrained, leading to +// the ultimate error. +// +// compile-pass + +#![crate_type="lib"] + +pub trait Database<'a> { + type Guard: 'a; +} + +pub struct Stateful<'a, D: 'a>(&'a D); + +impl<'b, D: for <'a> Database<'a>> Stateful<'b, D> { + pub fn callee<'a>(&'a self) -> >::Guard { + unimplemented!() + } + pub fn caller<'a>(&'a self) -> >::Guard { + let state = self.callee(); + self.callee() + } +} diff --git a/src/test/ui/regions/region-borrow-params-issue-29793-big.ast.stderr b/src/test/ui/regions/region-borrow-params-issue-29793-big.ast.stderr index 23dc39db129ee..94f08a4a1a7f2 100644 --- a/src/test/ui/regions/region-borrow-params-issue-29793-big.ast.stderr +++ b/src/test/ui/regions/region-borrow-params-issue-29793-big.ast.stderr @@ -7,9 +7,10 @@ LL | WrapB::new().set(|t: bool| if t { x } else { y }) // (separate erro | capture occurs here ... LL | }); - | - borrowed value dropped before borrower - | - = note: values in a scope are dropped in the opposite order they are created + | - borrowed value only lives until here +... +LL | } + | - borrowed value needs to live until here error[E0597]: `y` does not live long enough --> $DIR/region-borrow-params-issue-29793-big.rs:81:54 @@ -20,9 +21,10 @@ LL | WrapB::new().set(|t: bool| if t { x } else { y }) // (separate erro | capture occurs here ... LL | }); - | - borrowed value dropped before borrower - | - = note: values in a scope are dropped in the opposite order they are created + | - borrowed value only lives until here +... +LL | } + | - borrowed value needs to live until here error: aborting due to 2 previous errors diff --git a/src/test/ui/regions/region-borrow-params-issue-29793-small.stderr b/src/test/ui/regions/region-borrow-params-issue-29793-small.stderr index cfe38fe20040c..3f44ef34a60bc 100644 --- a/src/test/ui/regions/region-borrow-params-issue-29793-small.stderr +++ b/src/test/ui/regions/region-borrow-params-issue-29793-small.stderr @@ -7,9 +7,10 @@ LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x | capture occurs here ... LL | }; - | - borrowed value dropped before borrower - | - = note: values in a scope are dropped in the opposite order they are created + | - borrowed value only lives until here +... +LL | } + | - borrowed value needs to live until here error[E0597]: `y` does not live long enough --> $DIR/region-borrow-params-issue-29793-small.rs:19:45 @@ -20,9 +21,10 @@ LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x | capture occurs here ... LL | }; - | - borrowed value dropped before borrower - | - = note: values in a scope are dropped in the opposite order they are created + | - borrowed value only lives until here +... +LL | } + | - borrowed value needs to live until here error[E0597]: `x` does not live long enough --> $DIR/region-borrow-params-issue-29793-small.rs:34:34 @@ -33,9 +35,10 @@ LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x | capture occurs here ... LL | }; - | - borrowed value dropped before borrower - | - = note: values in a scope are dropped in the opposite order they are created + | - borrowed value only lives until here +... +LL | } + | - borrowed value needs to live until here error[E0597]: `y` does not live long enough --> $DIR/region-borrow-params-issue-29793-small.rs:34:45 @@ -46,9 +49,10 @@ LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x | capture occurs here ... LL | }; - | - borrowed value dropped before borrower - | - = note: values in a scope are dropped in the opposite order they are created + | - borrowed value only lives until here +... +LL | } + | - borrowed value needs to live until here error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function --> $DIR/region-borrow-params-issue-29793-small.rs:65:17 diff --git a/src/test/ui/regions/regions-escape-via-trait-or-not.stderr b/src/test/ui/regions/regions-escape-via-trait-or-not.stderr index 60bd14ba4d79c..c13996cd2b08f 100644 --- a/src/test/ui/regions/regions-escape-via-trait-or-not.stderr +++ b/src/test/ui/regions/regions-escape-via-trait-or-not.stderr @@ -12,16 +12,16 @@ LL | with(|o| o) //~ ERROR cannot infer = note: ...so that the expression is assignable: expected &isize found &isize -note: but, the lifetime must be valid for the expression at 28:5... +note: but, the lifetime must be valid for the call at 28:5... --> $DIR/regions-escape-via-trait-or-not.rs:28:5 | LL | with(|o| o) //~ ERROR cannot infer - | ^^^^ -note: ...so type `fn([closure@$DIR/regions-escape-via-trait-or-not.rs:28:10: 28:15]) -> isize {with::<&isize, [closure@$DIR/regions-escape-via-trait-or-not.rs:28:10: 28:15]>}` of expression is valid during the expression - --> $DIR/regions-escape-via-trait-or-not.rs:28:5 + | ^^^^^^^^^^^ +note: ...so that argument is valid for the call + --> $DIR/regions-escape-via-trait-or-not.rs:28:10 | LL | with(|o| o) //~ ERROR cannot infer - | ^^^^ + | ^^^^^ error: aborting due to previous error diff --git a/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.rs b/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.rs index 99e5cc0315383..a2000fa4db86b 100644 --- a/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.rs +++ b/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.rs @@ -14,7 +14,7 @@ fn main() { // Unboxed closure case { let mut x = 0; - let mut f = || &mut x; //~ ERROR cannot infer + let mut f = || &mut x; //~ ERROR borrowed data cannot be stored outside of its closure let x = f(); let y = f(); } diff --git a/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.stderr b/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.stderr index c841c9605bd5f..13c1f69467fe5 100644 --- a/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.stderr +++ b/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.stderr @@ -1,30 +1,11 @@ -error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements +error: borrowed data cannot be stored outside of its closure --> $DIR/regions-return-ref-to-upvar-issue-17403.rs:17:24 | -LL | let mut f = || &mut x; //~ ERROR cannot infer - | ^^^^^^ - | -note: first, the lifetime cannot outlive the lifetime as defined on the body at 17:21... - --> $DIR/regions-return-ref-to-upvar-issue-17403.rs:17:21 - | -LL | let mut f = || &mut x; //~ ERROR cannot infer - | ^^^^^^^^^ -note: ...so that closure can access `x` - --> $DIR/regions-return-ref-to-upvar-issue-17403.rs:17:24 - | -LL | let mut f = || &mut x; //~ ERROR cannot infer - | ^^^^^^ -note: but, the lifetime must be valid for the call at 19:17... - --> $DIR/regions-return-ref-to-upvar-issue-17403.rs:19:17 - | -LL | let y = f(); - | ^^^ -note: ...so type `&mut i32` of expression is valid during the expression - --> $DIR/regions-return-ref-to-upvar-issue-17403.rs:19:17 - | -LL | let y = f(); - | ^^^ +LL | let mut f = || &mut x; //~ ERROR borrowed data cannot be stored outside of its closure + | ----- -- ^^^^^^ cannot be stored outside of its closure + | | | + | | ...because it cannot outlive this closure + | borrowed data cannot be stored into here... error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`.