From 4fb1808ab6e8a232be17ba3e74e27fa08bd4f28d Mon Sep 17 00:00:00 2001 From: gaurikholkar Date: Thu, 29 Jun 2017 12:40:04 -0700 Subject: [PATCH] Adding E0623, to detect missing lifetimes when both regions are anonymous --- src/librustc/diagnostics.rs | 1 + .../error_reporting/anon_anon_conflict.rs | 200 ++++++++++++++++++ src/librustc/infer/error_reporting/mod.rs | 51 +++-- .../error_reporting/named_anon_conflict.rs | 107 +--------- src/librustc/infer/error_reporting/util.rs | 120 +++++++++++ .../ex3-both-anon-regions-2.rs | 15 ++ .../ex3-both-anon-regions-2.stderr | 10 + .../ex3-both-anon-regions-3.rs | 15 ++ .../ex3-both-anon-regions-3.stderr | 10 + .../ex3-both-anon-regions-4.rs | 13 ++ .../ex3-both-anon-regions-4.stderr | 20 ++ .../lifetime-errors/ex3-both-anon-regions.rs | 15 ++ .../ex3-both-anon-regions.stderr | 10 + 13 files changed, 462 insertions(+), 125 deletions(-) create mode 100644 src/librustc/infer/error_reporting/anon_anon_conflict.rs create mode 100644 src/librustc/infer/error_reporting/util.rs create mode 100644 src/test/ui/lifetime-errors/ex3-both-anon-regions-2.rs create mode 100644 src/test/ui/lifetime-errors/ex3-both-anon-regions-2.stderr create mode 100644 src/test/ui/lifetime-errors/ex3-both-anon-regions-3.rs create mode 100644 src/test/ui/lifetime-errors/ex3-both-anon-regions-3.stderr create mode 100644 src/test/ui/lifetime-errors/ex3-both-anon-regions-4.rs create mode 100644 src/test/ui/lifetime-errors/ex3-both-anon-regions-4.stderr create mode 100644 src/test/ui/lifetime-errors/ex3-both-anon-regions.rs create mode 100644 src/test/ui/lifetime-errors/ex3-both-anon-regions.stderr diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 3ce39b23b0f..522c1531c59 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -2025,4 +2025,5 @@ register_diagnostics! { E0490, // a value of type `..` is borrowed for too long E0495, // cannot infer an appropriate lifetime due to conflicting requirements E0566, // conflicting representation hints + E0623, // lifetime mismatch where both parameters are anonymous regions } diff --git a/src/librustc/infer/error_reporting/anon_anon_conflict.rs b/src/librustc/infer/error_reporting/anon_anon_conflict.rs new file mode 100644 index 00000000000..1017f2bd0e6 --- /dev/null +++ b/src/librustc/infer/error_reporting/anon_anon_conflict.rs @@ -0,0 +1,200 @@ +// Copyright 2012-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. + +//! Error Reporting for Anonymous Region Lifetime Errors +//! where both the regions are anonymous. +use hir; +use infer::InferCtxt; +use ty::{self, Region}; +use infer::region_inference::RegionResolutionError::*; +use infer::region_inference::RegionResolutionError; +use hir::map as hir_map; +use middle::resolve_lifetime as rl; +use hir::intravisit::{self, Visitor, NestedVisitorMap}; + +impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { + // This method prints the error message for lifetime errors when both the concerned regions + // are anonymous. + // Consider a case where we have + // fn foo(x: &mut Vec<&u8>, y: &u8) + // { x.push(y); }. + // The example gives + // fn foo(x: &mut Vec<&u8>, y: &u8) { + // --- --- these references must have the same lifetime + // x.push(y); + // ^ data from `y` flows into `x` here + // It will later be extended to trait objects and structs. + pub fn try_report_anon_anon_conflict(&self, error: &RegionResolutionError<'tcx>) -> bool { + + let (span, sub, sup) = match *error { + ConcreteFailure(ref origin, sub, sup) => (origin.span(), sub, sup), + _ => return false, // inapplicable + }; + + // Determine whether the sub and sup consist of both anonymous (elided) regions. + let (ty1, ty2) = if self.is_suitable_anonymous_region(sup).is_some() && + self.is_suitable_anonymous_region(sub).is_some() { + if let (Some(anon_reg1), Some(anon_reg2)) = + (self.is_suitable_anonymous_region(sup), self.is_suitable_anonymous_region(sub)) { + let ((_, br1), (_, br2)) = (anon_reg1, anon_reg2); + if self.find_anon_type(sup, &br1).is_some() && + self.find_anon_type(sub, &br2).is_some() { + (self.find_anon_type(sup, &br1).unwrap(), + self.find_anon_type(sub, &br2).unwrap()) + } else { + return false; + } + } else { + return false; + } + } else { + return false; // inapplicable + }; + + if let (Some(sup_arg), Some(sub_arg)) = + (self.find_arg_with_anonymous_region(sup, sup), + self.find_arg_with_anonymous_region(sub, sub)) { + let ((anon_arg1, _, _, _), (anon_arg2, _, _, _)) = (sup_arg, sub_arg); + + let span_label_var1 = if let Some(simple_name) = anon_arg1.pat.simple_name() { + format!(" from `{}` ", simple_name) + } else { + format!(" ") + }; + + let span_label_var2 = if let Some(simple_name) = anon_arg2.pat.simple_name() { + format!(" into `{}` ", simple_name) + } else { + format!(" ") + }; + + struct_span_err!(self.tcx.sess, span, E0623, "lifetime mismatch") + .span_label(ty1.span, + format!("these references must have the same lifetime")) + .span_label(ty2.span, format!("")) + .span_label(span, + format!("data{}flows{}here", span_label_var1, span_label_var2)) + .emit(); + } else { + return false; + } + + return true; + } + + /// This function calls the `visit_ty` method for the parameters + /// corresponding to the anonymous regions. The `nested_visitor.found_type` + /// contains the anonymous type. + /// + /// # Arguments + /// + /// region - the anonymous region corresponding to the anon_anon conflict + /// br - the bound region corresponding to the above region which is of type `BrAnon(_)` + /// + /// # Example + /// ``` + /// fn foo(x: &mut Vec<&u8>, y: &u8) + /// { x.push(y); } + /// ``` + /// The function returns the nested type corresponding to the anonymous region + /// for e.g. `&u8` and Vec<`&u8`. + fn find_anon_type(&self, region: Region<'tcx>, br: &ty::BoundRegion) -> Option<&hir::Ty> { + if let Some(anon_reg) = self.is_suitable_anonymous_region(region) { + let (def_id, _) = anon_reg; + if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) { + let ret_ty = self.tcx.type_of(def_id); + if let ty::TyFnDef(_, _) = ret_ty.sty { + if let hir_map::NodeItem(it) = self.tcx.hir.get(node_id) { + if let hir::ItemFn(ref fndecl, _, _, _, _, _) = it.node { + return fndecl + .inputs + .iter() + .filter_map(|arg| { + let mut nested_visitor = FindNestedTypeVisitor { + infcx: &self, + hir_map: &self.tcx.hir, + bound_region: *br, + found_type: None, + }; + nested_visitor.visit_ty(&**arg); + if nested_visitor.found_type.is_some() { + nested_visitor.found_type + } else { + None + } + }) + .next(); + } + } + } + } + } + None + } +} + +// The FindNestedTypeVisitor captures the corresponding `hir::Ty` of the +// anonymous region. The example above would lead to a conflict between +// the two anonymous lifetimes for &u8 in x and y respectively. This visitor +// would be invoked twice, once for each lifetime, and would +// walk the types like &mut Vec<&u8> and &u8 looking for the HIR +// where that lifetime appears. This allows us to highlight the +// specific part of the type in the error message. +struct FindNestedTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { + infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + hir_map: &'a hir::map::Map<'gcx>, + // The bound_region corresponding to the Refree(freeregion) + // associated with the anonymous region we are looking for. + bound_region: ty::BoundRegion, + // The type where the anonymous lifetime appears + // for e.g. Vec<`&u8`> and <`&u8`> + found_type: Option<&'gcx hir::Ty>, +} + +impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> { + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> { + NestedVisitorMap::OnlyBodies(&self.hir_map) + } + + fn visit_ty(&mut self, arg: &'gcx hir::Ty) { + // Find the index of the anonymous region that was part of the + // error. We will then search the function parameters for a bound + // region at the right depth with the same index. + let br_index = match self.bound_region { + ty::BrAnon(index) => index, + _ => return, + }; + + match arg.node { + hir::TyRptr(ref lifetime, _) => { + match self.infcx.tcx.named_region_map.defs.get(&lifetime.id) { + // the lifetime of the TyRptr + Some(&rl::Region::LateBoundAnon(debuijn_index, anon_index)) => { + if debuijn_index.depth == 1 && anon_index == br_index { + self.found_type = Some(arg); + return; // we can stop visiting now + } + } + Some(&rl::Region::Static) | + Some(&rl::Region::EarlyBound(_, _)) | + Some(&rl::Region::LateBound(_, _)) | + Some(&rl::Region::Free(_, _)) | + None => { + debug!("no arg found"); + } + } + } + _ => {} + } + // walk the embedded contents: e.g., if we are visiting `Vec<&Foo>`, + // go on to visit `&Foo` + intravisit::walk_ty(self, arg); + } +} diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 95722a93bed..77ec866dc80 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -76,7 +76,9 @@ use errors::{DiagnosticBuilder, DiagnosticStyledString}; mod note; mod need_type_info; +mod util; mod named_anon_conflict; +mod anon_anon_conflict; impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn note_and_explain_region(self, @@ -270,29 +272,34 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { for error in errors { debug!("report_region_errors: error = {:?}", error); - if !self.try_report_named_anon_conflict(&error) { - match error.clone() { - // These errors could indicate all manner of different - // problems with many different solutions. Rather - // than generate a "one size fits all" error, what we - // attempt to do is go through a number of specific - // scenarios and try to find the best way to present - // the error. If all of these fails, we fall back to a rather - // general bit of code that displays the error information - ConcreteFailure(origin, sub, sup) => { - self.report_concrete_failure(origin, sub, sup).emit(); - } - GenericBoundFailure(kind, param_ty, sub) => { - self.report_generic_bound_failure(kind, param_ty, sub); - } - SubSupConflict(var_origin, - sub_origin, sub_r, - sup_origin, sup_r) => { + if !self.try_report_named_anon_conflict(&error) && + !self.try_report_anon_anon_conflict(&error) { + + match error.clone() { + // These errors could indicate all manner of different + // problems with many different solutions. Rather + // than generate a "one size fits all" error, what we + // attempt to do is go through a number of specific + // scenarios and try to find the best way to present + // the error. If all of these fails, we fall back to a rather + // general bit of code that displays the error information + ConcreteFailure(origin, sub, sup) => { + + self.report_concrete_failure(origin, sub, sup).emit(); + } + + GenericBoundFailure(kind, param_ty, sub) => { + self.report_generic_bound_failure(kind, param_ty, sub); + } + + SubSupConflict(var_origin, sub_origin, sub_r, sup_origin, sup_r) => { self.report_sub_sup_conflict(var_origin, - sub_origin, sub_r, - sup_origin, sup_r); - } - } + sub_origin, + sub_r, + sup_origin, + sup_r); + } + } } } } diff --git a/src/librustc/infer/error_reporting/named_anon_conflict.rs b/src/librustc/infer/error_reporting/named_anon_conflict.rs index 48f39ac5b3e..491079a1f92 100644 --- a/src/librustc/infer/error_reporting/named_anon_conflict.rs +++ b/src/librustc/infer/error_reporting/named_anon_conflict.rs @@ -8,69 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Error Reporting for Anonymous Region Lifetime Errors. -use hir; +//! Error Reporting for Anonymous Region Lifetime Errors +//! where one region is named and the other is anonymous. use infer::InferCtxt; -use ty::{self, Region}; +use ty; use infer::region_inference::RegionResolutionError::*; use infer::region_inference::RegionResolutionError; -use hir::map as hir_map; -use hir::def_id::DefId; impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { - // This method walks the Type of the function body arguments using - // `fold_regions()` function and returns the - // &hir::Arg of the function argument corresponding to the anonymous - // region and the Ty corresponding to the named region. - // Currently only the case where the function declaration consists of - // one named region and one anonymous region is handled. - // Consider the example `fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32` - // Here, we would return the hir::Arg for y, we return the type &'a - // i32, which is the type of y but with the anonymous region replaced - // with 'a, the corresponding bound region and is_first which is true if - // the hir::Arg is the first argument in the function declaration. - fn find_arg_with_anonymous_region - (&self, - anon_region: Region<'tcx>, - named_region: Region<'tcx>) - -> Option<(&hir::Arg, ty::Ty<'tcx>, ty::BoundRegion, bool)> { - - match *anon_region { - ty::ReFree(ref free_region) => { - let id = free_region.scope; - let node_id = self.tcx.hir.as_local_node_id(id).unwrap(); - let body_id = self.tcx.hir.maybe_body_owned_by(node_id).unwrap(); - let body = self.tcx.hir.body(body_id); - if let Some(tables) = self.in_progress_tables { - body.arguments - .iter() - .enumerate() - .filter_map(|(index, arg)| { - let ty = tables.borrow().node_id_to_type(arg.id); - let mut found_anon_region = false; - let new_arg_ty = self.tcx - .fold_regions(&ty, &mut false, |r, _| if *r == *anon_region { - found_anon_region = true; - named_region - } else { - r - }); - if found_anon_region { - let is_first = index == 0; - Some((arg, new_arg_ty, free_region.bound_region, is_first)) - } else { - None - } - }) - .next() - } else { - None - } - } - _ => None, - } - } - // This method generates the error message for the case when // the function arguments consist of a named region and an anonymous // region and corresponds to `ConcreteFailure(..)` @@ -86,7 +31,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // only introduced anonymous regions in parameters) as well as a // version new_ty of its type where the anonymous region is replaced // with the named one. - let (named, (arg, new_ty, br, is_first), scope_def_id) = + let (named, (arg, new_ty, br, is_first), (scope_def_id, _)) = if sub.is_named_region() && self.is_suitable_anonymous_region(sup).is_some() { (sub, self.find_arg_with_anonymous_region(sup, sub).unwrap(), @@ -145,48 +90,4 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { return true; } - - // This method returns whether the given Region is Anonymous - // and returns the DefId corresponding to the region. - pub fn is_suitable_anonymous_region(&self, region: Region<'tcx>) -> Option { - match *region { - ty::ReFree(ref free_region) => { - match free_region.bound_region { - ty::BrAnon(..) => { - let anonymous_region_binding_scope = free_region.scope; - let node_id = self.tcx - .hir - .as_local_node_id(anonymous_region_binding_scope) - .unwrap(); - match self.tcx.hir.find(node_id) { - Some(hir_map::NodeItem(..)) | - Some(hir_map::NodeTraitItem(..)) => { - // proceed ahead // - } - Some(hir_map::NodeImplItem(..)) => { - let container_id = self.tcx - .associated_item(anonymous_region_binding_scope) - .container - .id(); - if self.tcx.impl_trait_ref(container_id).is_some() { - // For now, we do not try to target impls of traits. This is - // because this message is going to suggest that the user - // change the fn signature, but they may not be free to do so, - // since the signature must match the trait. - // - // FIXME(#42706) -- in some cases, we could do better here. - return None; - } - } - _ => return None, // inapplicable - // we target only top-level functions - } - return Some(anonymous_region_binding_scope); - } - _ => None, - } - } - _ => None, - } - } } diff --git a/src/librustc/infer/error_reporting/util.rs b/src/librustc/infer/error_reporting/util.rs new file mode 100644 index 00000000000..14fe8e699c7 --- /dev/null +++ b/src/librustc/infer/error_reporting/util.rs @@ -0,0 +1,120 @@ +// Copyright 2012-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. + +//! Helper functions corresponding to lifetime errors due to +//! anonymous regions. +use hir; +use infer::InferCtxt; +use ty::{self, Region}; +use hir::def_id::DefId; +use hir::map as hir_map; + +impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { + // This method walks the Type of the function body arguments using + // `fold_regions()` function and returns the + // &hir::Arg of the function argument corresponding to the anonymous + // region and the Ty corresponding to the named region. + // Currently only the case where the function declaration consists of + // one named region and one anonymous region is handled. + // Consider the example `fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32` + // Here, we would return the hir::Arg for y, we return the type &'a + // i32, which is the type of y but with the anonymous region replaced + // with 'a, the corresponding bound region and is_first which is true if + // the hir::Arg is the first argument in the function declaration. + pub fn find_arg_with_anonymous_region + (&self, + anon_region: Region<'tcx>, + replace_region: Region<'tcx>) + -> Option<(&hir::Arg, ty::Ty<'tcx>, ty::BoundRegion, bool)> { + + if let ty::ReFree(ref free_region) = *anon_region { + + let id = free_region.scope; + let hir = &self.tcx.hir; + if let Some(node_id) = hir.as_local_node_id(id) { + if let Some(body_id) = hir.maybe_body_owned_by(node_id) { + let body = hir.body(body_id); + if let Some(tables) = self.in_progress_tables { + body.arguments + .iter() + .enumerate() + .filter_map(|(index, arg)| { + let ty = tables.borrow().node_id_to_type(arg.id); + let mut found_anon_region = false; + let new_arg_ty = self.tcx + .fold_regions(&ty, &mut false, |r, _| if *r == *anon_region { + found_anon_region = true; + replace_region + } else { + r + }); + if found_anon_region { + let is_first = index == 0; + Some((arg, new_arg_ty, free_region.bound_region, is_first)) + } else { + None + } + }) + .next() + } else { + None + } + } else { + None + } + } else { + None + } + } else { + None + } + } + + // This method returns whether the given Region is Anonymous + // and returns the DefId and the BoundRegion corresponding to the given region. + pub fn is_suitable_anonymous_region(&self, + region: Region<'tcx>) + -> Option<(DefId, ty::BoundRegion)> { + if let ty::ReFree(ref free_region) = *region { + if let ty::BrAnon(..) = free_region.bound_region{ + let anonymous_region_binding_scope = free_region.scope; + let node_id = self.tcx + .hir + .as_local_node_id(anonymous_region_binding_scope) + .unwrap(); + match self.tcx.hir.find(node_id) { + Some(hir_map::NodeItem(..)) | + Some(hir_map::NodeTraitItem(..)) => { + // Success -- proceed to return Some below + } + Some(hir_map::NodeImplItem(..)) => { + let container_id = self.tcx + .associated_item(anonymous_region_binding_scope) + .container + .id(); + if self.tcx.impl_trait_ref(container_id).is_some() { + // For now, we do not try to target impls of traits. This is + // because this message is going to suggest that the user + // change the fn signature, but they may not be free to do so, + // since the signature must match the trait. + // + // FIXME(#42706) -- in some cases, we could do better here. + return None; + } + } + _ => return None, // inapplicable + // we target only top-level functions + } + return Some((anonymous_region_binding_scope, free_region.bound_region)); + } + } + None + } +} diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-2.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions-2.rs new file mode 100644 index 00000000000..905eae18d18 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-2.rs @@ -0,0 +1,15 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn foo((v, w): (&u8, &u8), x: &u8) { + v = x; +} + +fn main() { } diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-2.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-2.stderr new file mode 100644 index 00000000000..8dd906afdc4 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-2.stderr @@ -0,0 +1,10 @@ +error[E0623]: lifetime mismatch + --> $DIR/ex3-both-anon-regions-2.rs:12:9 + | +11 | fn foo((v, w): (&u8, &u8), x: &u8) { + | --- --- these references must have the same lifetime +12 | v = x; + | ^ data from `x` flows here + +error: aborting due to previous error + diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-3.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions-3.rs new file mode 100644 index 00000000000..7bd5ebf805f --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-3.rs @@ -0,0 +1,15 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn foo((v, w): (&u8, &u8), (x, y): (&u8, &u8)) { + v = x; +} + +fn main() { } diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-3.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-3.stderr new file mode 100644 index 00000000000..66c3ca45499 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-3.stderr @@ -0,0 +1,10 @@ +error[E0623]: lifetime mismatch + --> $DIR/ex3-both-anon-regions-3.rs:12:9 + | +11 | fn foo((v, w): (&u8, &u8), (x, y): (&u8, &u8)) { + | --- --- these references must have the same lifetime +12 | v = x; + | ^ data flows here + +error: aborting due to previous error + diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-4.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions-4.rs new file mode 100644 index 00000000000..fdb010a04f4 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-4.rs @@ -0,0 +1,13 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) { + z.push((x,y)); +} diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-4.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-4.stderr new file mode 100644 index 00000000000..b969797b374 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-4.stderr @@ -0,0 +1,20 @@ +error[E0601]: main function not found + +error[E0623]: lifetime mismatch + --> $DIR/ex3-both-anon-regions-4.rs:12:13 + | +11 | fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) { + | --- --- these references must have the same lifetime +12 | z.push((x,y)); + | ^ data flows into `z` here + +error[E0623]: lifetime mismatch + --> $DIR/ex3-both-anon-regions-4.rs:12:15 + | +11 | fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) { + | --- --- these references must have the same lifetime +12 | z.push((x,y)); + | ^ data flows into `z` here + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions.rs b/src/test/ui/lifetime-errors/ex3-both-anon-regions.rs new file mode 100644 index 00000000000..9ebff511876 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions.rs @@ -0,0 +1,15 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn foo(x: &mut Vec<&u8>, y: &u8) { + x.push(y); +} + +fn main() { } diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions.stderr new file mode 100644 index 00000000000..e38e2ef07ad --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions.stderr @@ -0,0 +1,10 @@ +error[E0623]: lifetime mismatch + --> $DIR/ex3-both-anon-regions.rs:12:12 + | +11 | fn foo(x: &mut Vec<&u8>, y: &u8) { + | --- --- these references must have the same lifetime +12 | x.push(y); + | ^ data from `y` flows into `x` here + +error: aborting due to previous error +