diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 4aa8c12a219ca..a85685caf7d7a 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -921,6 +921,16 @@ impl Pat { pub fn walk(&self, mut it: impl FnMut(&Pat) -> bool) { self.walk_(&mut it) } + + /// Walk the pattern in left-to-right order. + /// + /// If you always want to recurse, prefer this method over `walk`. + pub fn walk_always(&self, mut it: impl FnMut(&Pat)) { + self.walk(|p| { + it(p); + true + }) + } } /// A single field in a struct pattern. diff --git a/src/librustc/hir/pat_util.rs b/src/librustc/hir/pat_util.rs index c0aa54beac275..8d3b464a8ffa1 100644 --- a/src/librustc/hir/pat_util.rs +++ b/src/librustc/hir/pat_util.rs @@ -79,11 +79,10 @@ impl hir::Pat { /// Call `f` on every "binding" in a pattern, e.g., on `a` in /// `match foo() { Some(a) => (), None => () }` pub fn each_binding(&self, mut f: impl FnMut(hir::BindingAnnotation, HirId, Span, ast::Ident)) { - self.walk(|p| { + self.walk_always(|p| { if let PatKind::Binding(binding_mode, _, ident, _) = p.kind { f(binding_mode, p.hir_id, p.span, ident); } - true }); } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 0806e2d77650e..e36b11ae0050c 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -648,6 +648,13 @@ impl<'tcx> TypeckTables<'tcx> { } } + pub fn extract_binding_mode(&self, s: &Session, id: HirId, sp: Span) -> Option { + self.pat_binding_modes().get(id).copied().or_else(|| { + s.delay_span_bug(sp, "missing binding mode"); + None + }) + } + pub fn pat_binding_modes(&self) -> LocalTableInContext<'_, BindingMode> { LocalTableInContext { local_id_root: self.local_id_root, diff --git a/src/librustc_error_codes/error_codes/E0303.md b/src/librustc_error_codes/error_codes/E0303.md index 20a6c078f4fa2..700a66438e060 100644 --- a/src/librustc_error_codes/error_codes/E0303.md +++ b/src/librustc_error_codes/error_codes/E0303.md @@ -1,10 +1,18 @@ +#### Note: this error code is no longer emitted by the compiler. + +Sub-bindings, e.g. `ref x @ Some(ref y)` are now allowed under +`#![feature(bindings_after_at)]` and checked to make sure that +memory safety is upheld. + +-------------- + In certain cases it is possible for sub-bindings to violate memory safety. Updates to the borrow checker in a future version of Rust may remove this restriction, but for now patterns must be rewritten without sub-bindings. Before: -```compile_fail,E0303 +```compile_fail match Some("hi".to_string()) { ref op_string_ref @ Some(s) => {}, None => {}, diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs index a386cbf56af85..36664af8782f4 100644 --- a/src/librustc_feature/active.rs +++ b/src/librustc_feature/active.rs @@ -539,6 +539,10 @@ declare_features! ( /// Allows the use of `loop` and `while` in constants. (active, const_loop, "1.41.0", Some(52000), None), + /// Allows bindings in the subpattern of a binding pattern. + /// For example, you can write `x @ Some(y)`. + (active, bindings_after_at, "1.41.0", Some(65490), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 3b85a5d3c911b..3a2a2dc412e72 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -816,15 +816,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if let Some(Node::Binding(pat)) = tcx_hir.find(var_id) { if let hir::PatKind::Binding(_, _, ident, _) = pat.kind { name = ident.name; - - if let Some(&bm) = hir_tables.pat_binding_modes().get(pat.hir_id) { - if bm == ty::BindByValue(hir::Mutability::Mut) { + match hir_tables.extract_binding_mode(tcx.sess, pat.hir_id, pat.span) { + Some(ty::BindByValue(hir::Mutability::Mut)) => { mutability = Mutability::Mut; - } else { - mutability = Mutability::Not; } - } else { - tcx.sess.delay_span_bug(pat.span, "missing binding mode"); + Some(_) => mutability = Mutability::Not, + _ => {} } } } diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index 4ebf41fb9d21f..67c89c7293c43 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -4,23 +4,23 @@ use super::_match::{expand_pattern, is_useful, MatchCheckCtxt, Matrix, PatStack} use super::{PatCtxt, PatKind, PatternError}; -use rustc::lint; -use rustc::session::Session; -use rustc::ty::subst::{InternalSubsts, SubstsRef}; -use rustc::ty::{self, Ty, TyCtxt}; -use rustc_errors::{Applicability, DiagnosticBuilder}; - use rustc::hir::def::*; use rustc::hir::def_id::DefId; use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc::hir::HirId; use rustc::hir::{self, Pat}; - -use std::slice; - +use rustc::lint; +use rustc::session::Session; +use rustc::ty::subst::{InternalSubsts, SubstsRef}; +use rustc::ty::{self, Ty, TyCtxt}; +use rustc_error_codes::*; +use rustc_errors::{Applicability, DiagnosticBuilder}; +use syntax::ast::Mutability; +use syntax::feature_gate::feature_err; +use syntax_pos::symbol::sym; use syntax_pos::{MultiSpan, Span}; -use rustc_error_codes::*; +use std::slice; crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) { let body_id = match tcx.hir().as_local_hir_id(def_id) { @@ -123,7 +123,10 @@ impl PatCtxt<'_, '_> { impl<'tcx> MatchVisitor<'_, 'tcx> { fn check_patterns(&mut self, has_guard: bool, pat: &Pat) { check_legality_of_move_bindings(self, has_guard, pat); - check_legality_of_bindings_in_at_patterns(self, pat); + check_borrow_conflicts_in_at_patterns(self, pat); + if !self.tcx.features().bindings_after_at { + check_legality_of_bindings_in_at_patterns(self, pat); + } } fn check_match(&mut self, scrut: &hir::Expr, arms: &'tcx [hir::Arm], source: hir::MatchSource) { @@ -266,13 +269,11 @@ fn const_not_var(err: &mut DiagnosticBuilder<'_>, tcx: TyCtxt<'_>, pat: &Pat, pa } fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_>, pat: &Pat) { - pat.walk(|p| { + pat.walk_always(|p| { if let hir::PatKind::Binding(_, _, ident, None) = p.kind { - if let Some(&bm) = cx.tables.pat_binding_modes().get(p.hir_id) { - if bm != ty::BindByValue(hir::Mutability::Not) { - // Nothing to check. - return true; - } + if let Some(ty::BindByValue(hir::Mutability::Not)) = + cx.tables.extract_binding_mode(cx.tcx.sess, p.hir_id, p.span) + { let pat_ty = cx.tables.pat_ty(p); if let ty::Adt(edef, _) = pat_ty.kind { if edef.is_enum() @@ -280,6 +281,7 @@ fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_>, pat: &Pa variant.ident == ident && variant.ctor_kind == CtorKind::Const }) { + // FIXME(Centril): Should be a lint? let ty_path = cx.tcx.def_path_str(edef.did); let mut err = struct_span_warn!( cx.tcx.sess, @@ -299,11 +301,8 @@ fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_>, pat: &Pa err.emit(); } } - } else { - cx.tcx.sess.delay_span_bug(p.span, "missing binding mode"); } } - true }); } @@ -318,7 +317,7 @@ fn pat_is_catchall(pat: &Pat) -> bool { } } -// Check for unreachable patterns +/// Check for unreachable patterns. fn check_arms<'p, 'tcx>( cx: &mut MatchCheckCtxt<'p, 'tcx>, arms: &[(&'p super::Pat<'tcx>, &hir::Pat, bool)], @@ -575,105 +574,176 @@ fn maybe_point_at_variant(ty: Ty<'_>, patterns: &[super::Pat<'_>]) -> Vec covered } -// Check the legality of legality of by-move bindings. +/// Check the legality of legality of by-move bindings. fn check_legality_of_move_bindings(cx: &mut MatchVisitor<'_, '_>, has_guard: bool, pat: &Pat) { - let mut by_ref_span = None; + let sess = cx.tcx.sess; + let tables = cx.tables; + + // Find all by-ref spans. + let mut by_ref_spans = Vec::new(); pat.each_binding(|_, hir_id, span, _| { - if let Some(&bm) = cx.tables.pat_binding_modes().get(hir_id) { - if let ty::BindByReference(..) = bm { - by_ref_span = Some(span); - } - } else { - cx.tcx.sess.delay_span_bug(pat.span, "missing binding mode"); + if let Some(ty::BindByReference(_)) = tables.extract_binding_mode(sess, hir_id, span) { + by_ref_spans.push(span); } }); - let span_vec = &mut Vec::new(); + // Find bad by-move spans: + let by_move_spans = &mut Vec::new(); let mut check_move = |p: &Pat, sub: Option<&Pat>| { // Check legality of moving out of the enum. // // `x @ Foo(..)` is legal, but `x @ Foo(y)` isn't. if sub.map_or(false, |p| p.contains_bindings()) { - struct_span_err!(cx.tcx.sess, p.span, E0007, "cannot bind by-move with sub-bindings") + struct_span_err!(sess, p.span, E0007, "cannot bind by-move with sub-bindings") .span_label(p.span, "binds an already bound by-move value by moving it") .emit(); - } else if !has_guard && by_ref_span.is_some() { - span_vec.push(p.span); + } else if !has_guard && !by_ref_spans.is_empty() { + by_move_spans.push(p.span); } }; - - pat.walk(|p| { + pat.walk_always(|p| { if let hir::PatKind::Binding(.., sub) = &p.kind { - if let Some(&bm) = cx.tables.pat_binding_modes().get(p.hir_id) { - if let ty::BindByValue(..) = bm { - let pat_ty = cx.tables.node_type(p.hir_id); - if !pat_ty.is_copy_modulo_regions(cx.tcx, cx.param_env, pat.span) { - check_move(p, sub.as_deref()); - } + if let Some(ty::BindByValue(_)) = tables.extract_binding_mode(sess, p.hir_id, p.span) { + let pat_ty = tables.node_type(p.hir_id); + if !pat_ty.is_copy_modulo_regions(cx.tcx, cx.param_env, pat.span) { + check_move(p, sub.as_deref()); } - } else { - cx.tcx.sess.delay_span_bug(pat.span, "missing binding mode"); } } - true }); - if !span_vec.is_empty() { + // Found some bad by-move spans, error! + if !by_move_spans.is_empty() { let mut err = struct_span_err!( - cx.tcx.sess, - MultiSpan::from_spans(span_vec.clone()), + sess, + MultiSpan::from_spans(by_move_spans.clone()), E0009, "cannot bind by-move and by-ref in the same pattern", ); - if let Some(by_ref_span) = by_ref_span { - err.span_label(by_ref_span, "both by-ref and by-move used"); + for span in by_ref_spans.iter() { + err.span_label(*span, "by-ref pattern here"); } - for span in span_vec.iter() { + for span in by_move_spans.iter() { err.span_label(*span, "by-move pattern here"); } err.emit(); } } -/// Forbids bindings in `@` patterns. This is necessary for memory safety, -/// because of the way rvalues are handled in the borrow check. (See issue -/// #14587.) -fn check_legality_of_bindings_in_at_patterns(cx: &MatchVisitor<'_, '_>, pat: &Pat) { - AtBindingPatternVisitor { cx, bindings_allowed: true }.visit_pat(pat); -} +/// Check that there are no borrow conflicts in `binding @ subpat` patterns. +/// +/// For example, this would reject: +/// - `ref x @ Some(ref mut y)`, +/// - `ref mut x @ Some(ref y)` +/// - `ref mut x @ Some(ref mut y)`. +/// +/// This analysis is *not* subsumed by NLL. +fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_>, pat: &Pat) { + let tab = cx.tables; + let sess = cx.tcx.sess; + // Get the mutability of `p` if it's by-ref. + let extract_binding_mut = |hir_id, span| match tab.extract_binding_mode(sess, hir_id, span)? { + ty::BindByValue(_) => None, + ty::BindByReference(m) => Some(m), + }; + pat.walk_always(|pat| { + // Extract `sub` in `binding @ sub`. + let (name, sub) = match &pat.kind { + hir::PatKind::Binding(.., name, Some(sub)) => (*name, sub), + _ => return, + }; + + // Extract the mutability. + let mut_outer = match extract_binding_mut(pat.hir_id, pat.span) { + None => return, + Some(m) => m, + }; + + // We now have `ref $mut_outer binding @ sub` (semantically). + // Recurse into each binding in `sub` and find mutability conflicts. + let mut conflicts_mut_mut = Vec::new(); + let mut conflicts_mut_ref = Vec::new(); + sub.each_binding(|_, hir_id, span, _| { + if let Some(mut_inner) = extract_binding_mut(hir_id, span) { + match (mut_outer, mut_inner) { + (Mutability::Not, Mutability::Not) => {} + (Mutability::Mut, Mutability::Mut) => conflicts_mut_mut.push(span), + _ => conflicts_mut_ref.push(span), + } + } + }); -struct AtBindingPatternVisitor<'a, 'b, 'tcx> { - cx: &'a MatchVisitor<'b, 'tcx>, - bindings_allowed: bool, + // Report errors if any. + let binding_span = pat.span.with_hi(name.span.hi()); + if !conflicts_mut_mut.is_empty() { + // Report mutability conflicts for e.g. `ref mut x @ Some(ref mut y)`. + let msg = &format!("cannot borrow `{}` as mutable more than once at a time", name); + let mut err = sess.struct_span_err(pat.span, msg); + err.span_label(binding_span, "first mutable borrow occurs here"); + for sp in conflicts_mut_mut { + err.span_label(sp, "another mutable borrow occurs here"); + } + for sp in conflicts_mut_ref { + err.span_label(sp, "also borrowed as immutable here"); + } + err.emit(); + } else if !conflicts_mut_ref.is_empty() { + // Report mutability conflicts for e.g. `ref x @ Some(ref mut y)` or the converse. + let (primary, also) = match mut_outer { + Mutability::Mut => ("mutable", "immutable"), + Mutability::Not => ("immutable", "mutable"), + }; + let msg = &format!( + "cannot borrow `{}` as {} because it is also borrowed as {}", + name, also, primary, + ); + let mut err = sess.struct_span_err(pat.span, msg); + err.span_label(binding_span, &format!("{} borrow occurs here", primary)); + for sp in conflicts_mut_ref { + err.span_label(sp, &format!("{} borrow occurs here", also)); + } + err.emit(); + } + }); } -impl<'v> Visitor<'v> for AtBindingPatternVisitor<'_, '_, '_> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> { - NestedVisitorMap::None +/// Forbids bindings in `@` patterns. This used to be is necessary for memory safety, +/// because of the way rvalues were handled in the borrow check. (See issue #14587.) +fn check_legality_of_bindings_in_at_patterns(cx: &MatchVisitor<'_, '_>, pat: &Pat) { + AtBindingPatternVisitor { cx, bindings_allowed: true }.visit_pat(pat); + + struct AtBindingPatternVisitor<'a, 'b, 'tcx> { + cx: &'a MatchVisitor<'b, 'tcx>, + bindings_allowed: bool, } - fn visit_pat(&mut self, pat: &Pat) { - match pat.kind { - hir::PatKind::Binding(.., ref subpat) => { - if !self.bindings_allowed { - struct_span_err!( - self.cx.tcx.sess, - pat.span, - E0303, - "pattern bindings are not allowed after an `@`" - ) - .span_label(pat.span, "not allowed after `@`") - .emit(); - } + impl<'v> Visitor<'v> for AtBindingPatternVisitor<'_, '_, '_> { + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> { + NestedVisitorMap::None + } - if subpat.is_some() { - let bindings_were_allowed = self.bindings_allowed; - self.bindings_allowed = false; - intravisit::walk_pat(self, pat); - self.bindings_allowed = bindings_were_allowed; + fn visit_pat(&mut self, pat: &Pat) { + match pat.kind { + hir::PatKind::Binding(.., ref subpat) => { + if !self.bindings_allowed { + feature_err( + &self.cx.tcx.sess.parse_sess, + sym::bindings_after_at, + pat.span, + "pattern bindings after an `@` are unstable", + ) + .emit(); + } + + if subpat.is_some() { + let bindings_were_allowed = self.bindings_allowed; + self.bindings_allowed = false; + intravisit::walk_pat(self, pat); + self.bindings_allowed = bindings_were_allowed; + } } + _ => intravisit::walk_pat(self, pat), } - _ => intravisit::walk_pat(self, pat), } } } diff --git a/src/librustc_parse/parser/pat.rs b/src/librustc_parse/parser/pat.rs index 9b5bf7e2378f5..1540e6d7c053f 100644 --- a/src/librustc_parse/parser/pat.rs +++ b/src/librustc_parse/parser/pat.rs @@ -406,6 +406,7 @@ impl<'a> Parser<'a> { if let PatKind::Ident(_, _, ref mut sub @ None) = rhs.kind { // The user inverted the order, so help them fix that. let mut applicability = Applicability::MachineApplicable; + // FIXME(bindings_after_at): Remove this code when stabilizing the feature. lhs.walk(&mut |p| match p.kind { // `check_match` is unhappy if the subpattern has a binding anywhere. PatKind::Ident(..) => { diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 8abfc2981a6a4..149f27ed305fb 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -1007,20 +1007,13 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { fn link_pattern(&self, discr_cmt: mc::Place<'tcx>, root_pat: &hir::Pat) { debug!("link_pattern(discr_cmt={:?}, root_pat={:?})", discr_cmt, root_pat); ignore_err!(self.with_mc(|mc| { - mc.cat_pattern(discr_cmt, root_pat, |sub_cmt, sub_pat| { + mc.cat_pattern(discr_cmt, root_pat, |sub_cmt, hir::Pat { kind, span, hir_id }| { // `ref x` pattern - if let PatKind::Binding(..) = sub_pat.kind { - if let Some(&bm) = mc.tables.pat_binding_modes().get(sub_pat.hir_id) { - if let ty::BindByReference(mutbl) = bm { - self.link_region_from_node_type( - sub_pat.span, - sub_pat.hir_id, - mutbl, - &sub_cmt, - ); - } - } else { - self.tcx.sess.delay_span_bug(sub_pat.span, "missing binding mode"); + if let PatKind::Binding(..) = kind { + if let Some(ty::BindByReference(mutbl)) = + mc.tables.extract_binding_mode(self.tcx.sess, *hir_id, *span) + { + self.link_region_from_node_type(*span, *hir_id, mutbl, &sub_cmt); } } }) diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 8ed8751f65c9a..5ef5f4c648e8c 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -284,10 +284,9 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { fn visit_pat(&mut self, p: &'tcx hir::Pat) { match p.kind { hir::PatKind::Binding(..) => { - if let Some(&bm) = self.fcx.tables.borrow().pat_binding_modes().get(p.hir_id) { + let tables = self.fcx.tables.borrow(); + if let Some(bm) = tables.extract_binding_mode(self.tcx().sess, p.hir_id, p.span) { self.tables.pat_binding_modes_mut().insert(p.hir_id, bm); - } else { - self.tcx().sess.delay_span_bug(p.span, "missing binding mode"); } } hir::PatKind::Struct(_, ref fields, _) => { diff --git a/src/librustc_typeck/expr_use_visitor.rs b/src/librustc_typeck/expr_use_visitor.rs index 58baf24438bd0..788dda1cd5a0e 100644 --- a/src/librustc_typeck/expr_use_visitor.rs +++ b/src/librustc_typeck/expr_use_visitor.rs @@ -534,7 +534,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { return_if_err!(mc.cat_pattern(discr_place.clone(), pat, |place, pat| { if let PatKind::Binding(_, canonical_id, ..) = pat.kind { debug!("walk_pat: binding place={:?} pat={:?}", place, pat,); - if let Some(&bm) = mc.tables.pat_binding_modes().get(pat.hir_id) { + if let Some(bm) = mc.tables.extract_binding_mode(tcx.sess, pat.hir_id, pat.span) { debug!("walk_pat: pat.hir_id={:?} bm={:?}", pat.hir_id, bm); // pat_ty: the type of the binding being produced. @@ -560,8 +560,6 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { delegate.consume(place, mode); } } - } else { - tcx.sess.delay_span_bug(pat.span, "missing binding mode"); } } })); diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 7e0308ee356df..8fdc199d9ed7c 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -165,6 +165,7 @@ symbols! { bench, bin, bind_by_move_pattern_guards, + bindings_after_at, block, bool, borrowck_graphviz_postflow, diff --git a/src/test/ui/bind-by-move/bind-by-move-neither-can-live-while-the-other-survives-2.stderr b/src/test/ui/bind-by-move/bind-by-move-neither-can-live-while-the-other-survives-2.stderr index 9157fe0b070d0..ff00aa8caa8d3 100644 --- a/src/test/ui/bind-by-move/bind-by-move-neither-can-live-while-the-other-survives-2.stderr +++ b/src/test/ui/bind-by-move/bind-by-move-neither-can-live-while-the-other-survives-2.stderr @@ -4,7 +4,7 @@ error[E0009]: cannot bind by-move and by-ref in the same pattern LL | Some((ref _y, _z)) => { }, | ------ ^^ by-move pattern here | | - | both by-ref and by-move used + | by-ref pattern here error: aborting due to previous error diff --git a/src/test/ui/bind-by-move/bind-by-move-neither-can-live-while-the-other-survives-3.stderr b/src/test/ui/bind-by-move/bind-by-move-neither-can-live-while-the-other-survives-3.stderr index d53547178db11..3e8358da3507d 100644 --- a/src/test/ui/bind-by-move/bind-by-move-neither-can-live-while-the-other-survives-3.stderr +++ b/src/test/ui/bind-by-move/bind-by-move-neither-can-live-while-the-other-survives-3.stderr @@ -4,7 +4,7 @@ error[E0009]: cannot bind by-move and by-ref in the same pattern LL | DoubleOption::Some2(ref _y, _z) => { }, | ------ ^^ by-move pattern here | | - | both by-ref and by-move used + | by-ref pattern here error: aborting due to previous error diff --git a/src/test/ui/bind-by-move/bind-by-move-neither-can-live-while-the-other-survives-4.stderr b/src/test/ui/bind-by-move/bind-by-move-neither-can-live-while-the-other-survives-4.stderr index 267a9dff926a2..00e0c70d6494b 100644 --- a/src/test/ui/bind-by-move/bind-by-move-neither-can-live-while-the-other-survives-4.stderr +++ b/src/test/ui/bind-by-move/bind-by-move-neither-can-live-while-the-other-survives-4.stderr @@ -2,7 +2,7 @@ error[E0009]: cannot bind by-move and by-ref in the same pattern --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-4.rs:12:15 | LL | Some((_y, ref _z)) => { }, - | ^^ ------ both by-ref and by-move used + | ^^ ------ by-ref pattern here | | | by-move pattern here diff --git a/src/test/ui/error-codes/E0007.rs b/src/test/ui/error-codes/E0007.rs index cdda735ba4435..022ac5fc113dd 100644 --- a/src/test/ui/error-codes/E0007.rs +++ b/src/test/ui/error-codes/E0007.rs @@ -1,9 +1,10 @@ +#![feature(bindings_after_at)] + fn main() { let x = Some("s".to_string()); match x { op_string @ Some(s) => {}, //~^ ERROR E0007 - //~| ERROR E0303 //~| ERROR E0382 None => {}, } diff --git a/src/test/ui/error-codes/E0007.stderr b/src/test/ui/error-codes/E0007.stderr index 89a6298c8752f..31af9171725bb 100644 --- a/src/test/ui/error-codes/E0007.stderr +++ b/src/test/ui/error-codes/E0007.stderr @@ -1,17 +1,11 @@ error[E0007]: cannot bind by-move with sub-bindings - --> $DIR/E0007.rs:4:9 + --> $DIR/E0007.rs:6:9 | LL | op_string @ Some(s) => {}, | ^^^^^^^^^^^^^^^^^^^ binds an already bound by-move value by moving it -error[E0303]: pattern bindings are not allowed after an `@` - --> $DIR/E0007.rs:4:26 - | -LL | op_string @ Some(s) => {}, - | ^ not allowed after `@` - error[E0382]: use of moved value - --> $DIR/E0007.rs:4:26 + --> $DIR/E0007.rs:6:26 | LL | let x = Some("s".to_string()); | - move occurs because `x` has type `std::option::Option`, which does not implement the `Copy` trait @@ -22,7 +16,7 @@ LL | op_string @ Some(s) => {}, | | value used here after move | value moved here -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0007, E0303, E0382. +Some errors have detailed explanations: E0007, E0382. For more information about an error, try `rustc --explain E0007`. diff --git a/src/test/ui/error-codes/E0009.stderr b/src/test/ui/error-codes/E0009.stderr index f8acb9a09d978..446a436d64779 100644 --- a/src/test/ui/error-codes/E0009.stderr +++ b/src/test/ui/error-codes/E0009.stderr @@ -2,7 +2,7 @@ error[E0009]: cannot bind by-move and by-ref in the same pattern --> $DIR/E0009.rs:5:15 | LL | Some((y, ref z)) => {}, - | ^ ----- both by-ref and by-move used + | ^ ----- by-ref pattern here | | | by-move pattern here diff --git a/src/test/ui/error-codes/E0303.stderr b/src/test/ui/error-codes/E0303.stderr deleted file mode 100644 index af537ce5625ca..0000000000000 --- a/src/test/ui/error-codes/E0303.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0009]: cannot bind by-move and by-ref in the same pattern - --> $DIR/E0303.rs:3:34 - | -LL | ref op_string_ref @ Some(s) => {}, - | -------------------------^- - | | | - | | by-move pattern here - | both by-ref and by-move used - -error[E0303]: pattern bindings are not allowed after an `@` - --> $DIR/E0303.rs:3:34 - | -LL | ref op_string_ref @ Some(s) => {}, - | ^ not allowed after `@` - -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0009, E0303. -For more information about an error, try `rustc --explain E0009`. diff --git a/src/test/ui/issues/issue-53840.stderr b/src/test/ui/issues/issue-53840.stderr index 0032f60a221f8..9cb034e7592da 100644 --- a/src/test/ui/issues/issue-53840.stderr +++ b/src/test/ui/issues/issue-53840.stderr @@ -2,7 +2,7 @@ error[E0009]: cannot bind by-move and by-ref in the same pattern --> $DIR/issue-53840.rs:13:16 | LL | E::Foo(a, b, ref c) => {} - | ^ ^ ----- both by-ref and by-move used + | ^ ^ ----- by-ref pattern here | | | | | by-move pattern here | by-move pattern here @@ -11,7 +11,7 @@ error[E0009]: cannot bind by-move and by-ref in the same pattern --> $DIR/issue-53840.rs:17:14 | LL | Bar {a, ref b} => {} - | ^ ----- both by-ref and by-move used + | ^ ----- by-ref pattern here | | | by-move pattern here diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs new file mode 100644 index 0000000000000..75d7af58e706d --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs @@ -0,0 +1,35 @@ +// This test is taken directly from #16053. +// It checks that you cannot use an AND-pattern (`binding @ pat`) +// where one side is by-ref and the other is by-move. + +#![feature(bindings_after_at)] + +struct X { x: () } + +fn main() { + let x = Some(X { x: () }); + match x { + Some(ref _y @ _z) => { }, //~ ERROR cannot bind by-move and by-ref in the same pattern + None => panic!() + } + + let x = Some(X { x: () }); + match x { + Some(_z @ ref _y) => { }, //~ ERROR cannot bind by-move with sub-bindings + //~^ ERROR borrow of moved value + None => panic!() + } + + let mut x = Some(X { x: () }); + match x { + Some(ref mut _y @ _z) => { }, //~ ERROR cannot bind by-move and by-ref in the same pattern + None => panic!() + } + + let mut x = Some(X { x: () }); + match x { + Some(_z @ ref mut _y) => { }, //~ ERROR cannot bind by-move with sub-bindings + //~^ ERROR borrow of moved value + None => panic!() + } +} diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr new file mode 100644 index 0000000000000..22d62ff4f003f --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr @@ -0,0 +1,56 @@ +error[E0009]: cannot bind by-move and by-ref in the same pattern + --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:12:23 + | +LL | Some(ref _y @ _z) => { }, + | ---------^^ + | | | + | | by-move pattern here + | by-ref pattern here + +error[E0007]: cannot bind by-move with sub-bindings + --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:18:14 + | +LL | Some(_z @ ref _y) => { }, + | ^^^^^^^^^^^ binds an already bound by-move value by moving it + +error[E0009]: cannot bind by-move and by-ref in the same pattern + --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:25:27 + | +LL | Some(ref mut _y @ _z) => { }, + | -------------^^ + | | | + | | by-move pattern here + | by-ref pattern here + +error[E0007]: cannot bind by-move with sub-bindings + --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:31:14 + | +LL | Some(_z @ ref mut _y) => { }, + | ^^^^^^^^^^^^^^^ binds an already bound by-move value by moving it + +error[E0382]: borrow of moved value + --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:18:19 + | +LL | Some(_z @ ref _y) => { }, + | -----^^^^^^ + | | | + | | value borrowed here after move + | value moved here + | + = note: move occurs because value has type `X`, which does not implement the `Copy` trait + +error[E0382]: borrow of moved value + --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:31:19 + | +LL | Some(_z @ ref mut _y) => { }, + | -----^^^^^^^^^^ + | | | + | | value borrowed here after move + | value moved here + | + = note: move occurs because value has type `X`, which does not implement the `Copy` trait + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0007, E0009, E0382. +For more information about an error, try `rustc --explain E0007`. diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs b/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs new file mode 100644 index 0000000000000..86fb04e2edf5b --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs @@ -0,0 +1,14 @@ +// See issue #12534. + +#![feature(bindings_after_at)] + +fn main() {} + +struct A(Box); + +fn f(a @ A(u): A) -> Box { + //~^ ERROR cannot bind by-move with sub-bindings + //~| ERROR use of moved value + drop(a); + u +} diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr b/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr new file mode 100644 index 0000000000000..b039708fd3e0a --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr @@ -0,0 +1,20 @@ +error[E0007]: cannot bind by-move with sub-bindings + --> $DIR/bind-by-move-no-subbindings-fun-param.rs:9:6 + | +LL | fn f(a @ A(u): A) -> Box { + | ^^^^^^^^ binds an already bound by-move value by moving it + +error[E0382]: use of moved value + --> $DIR/bind-by-move-no-subbindings-fun-param.rs:9:12 + | +LL | fn f(a @ A(u): A) -> Box { + | ------^- + | | | + | | value used here after move + | value moved here + | move occurs because value has type `A`, which does not implement the `Copy` trait + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0007, E0382. +For more information about an error, try `rustc --explain E0007`. diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.rs b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.rs new file mode 100644 index 0000000000000..1d9f341c5146a --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.rs @@ -0,0 +1,47 @@ +// Test that moving on both sides of an `@` pattern is not allowed. + +#![feature(bindings_after_at)] +#![feature(slice_patterns)] + +fn main() { + struct U; // Not copy! + + // Prevent promotion: + fn u() -> U { U } + + let a @ b = U; + //~^ ERROR cannot bind by-move with sub-bindings + //~| ERROR use of moved value + + let a @ (b, c) = (U, U); + //~^ ERROR cannot bind by-move with sub-bindings + //~| ERROR use of moved value + + let a @ (b, c) = (u(), u()); + //~^ ERROR cannot bind by-move with sub-bindings + //~| ERROR use of moved value + + match Ok(U) { + a @ Ok(b) | a @ Err(b) => {} + //~^ ERROR cannot bind by-move with sub-bindings + //~| ERROR use of moved value + //~| ERROR cannot bind by-move with sub-bindings + //~| ERROR use of moved value + } + + fn fun(a @ b: U) {} + //~^ ERROR cannot bind by-move with sub-bindings + //~| ERROR use of moved value + + match [u(), u(), u(), u()] { + xs @ [a, .., b] => {} + //~^ ERROR cannot bind by-move with sub-bindings + //~| ERROR use of moved value + } + + match [u(), u(), u(), u()] { + xs @ [_, ys @ .., _] => {} + //~^ ERROR cannot bind by-move with sub-bindings + //~| ERROR use of moved value + } +} diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr new file mode 100644 index 0000000000000..f3f8fd655ce0c --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr @@ -0,0 +1,133 @@ +error[E0007]: cannot bind by-move with sub-bindings + --> $DIR/borrowck-move-and-move.rs:12:9 + | +LL | let a @ b = U; + | ^^^^^ binds an already bound by-move value by moving it + +error[E0007]: cannot bind by-move with sub-bindings + --> $DIR/borrowck-move-and-move.rs:16:9 + | +LL | let a @ (b, c) = (U, U); + | ^^^^^^^^^^ binds an already bound by-move value by moving it + +error[E0007]: cannot bind by-move with sub-bindings + --> $DIR/borrowck-move-and-move.rs:20:9 + | +LL | let a @ (b, c) = (u(), u()); + | ^^^^^^^^^^ binds an already bound by-move value by moving it + +error[E0007]: cannot bind by-move with sub-bindings + --> $DIR/borrowck-move-and-move.rs:25:9 + | +LL | a @ Ok(b) | a @ Err(b) => {} + | ^^^^^^^^^ binds an already bound by-move value by moving it + +error[E0007]: cannot bind by-move with sub-bindings + --> $DIR/borrowck-move-and-move.rs:25:21 + | +LL | a @ Ok(b) | a @ Err(b) => {} + | ^^^^^^^^^^ binds an already bound by-move value by moving it + +error[E0007]: cannot bind by-move with sub-bindings + --> $DIR/borrowck-move-and-move.rs:37:9 + | +LL | xs @ [a, .., b] => {} + | ^^^^^^^^^^^^^^^ binds an already bound by-move value by moving it + +error[E0007]: cannot bind by-move with sub-bindings + --> $DIR/borrowck-move-and-move.rs:43:9 + | +LL | xs @ [_, ys @ .., _] => {} + | ^^^^^^^^^^^^^^^^^^^^ binds an already bound by-move value by moving it + +error[E0007]: cannot bind by-move with sub-bindings + --> $DIR/borrowck-move-and-move.rs:32:12 + | +LL | fn fun(a @ b: U) {} + | ^^^^^ binds an already bound by-move value by moving it + +error[E0382]: use of moved value + --> $DIR/borrowck-move-and-move.rs:12:13 + | +LL | let a @ b = U; + | ----^ - move occurs because value has type `main::U`, which does not implement the `Copy` trait + | | | + | | value used here after move + | value moved here + +error[E0382]: use of moved value + --> $DIR/borrowck-move-and-move.rs:16:17 + | +LL | let a @ (b, c) = (U, U); + | --------^- ------ move occurs because value has type `(main::U, main::U)`, which does not implement the `Copy` trait + | | | + | | value used here after move + | value moved here + +error[E0382]: use of moved value + --> $DIR/borrowck-move-and-move.rs:20:17 + | +LL | let a @ (b, c) = (u(), u()); + | --------^- ---------- move occurs because value has type `(main::U, main::U)`, which does not implement the `Copy` trait + | | | + | | value used here after move + | value moved here + +error[E0382]: use of moved value + --> $DIR/borrowck-move-and-move.rs:25:16 + | +LL | match Ok(U) { + | ----- move occurs because value has type `std::result::Result`, which does not implement the `Copy` trait +LL | a @ Ok(b) | a @ Err(b) => {} + | -------^- + | | | + | | value used here after move + | value moved here + +error[E0382]: use of moved value + --> $DIR/borrowck-move-and-move.rs:25:29 + | +LL | match Ok(U) { + | ----- move occurs because value has type `std::result::Result`, which does not implement the `Copy` trait +LL | a @ Ok(b) | a @ Err(b) => {} + | --------^- + | | | + | | value used here after move + | value moved here + +error[E0382]: use of moved value + --> $DIR/borrowck-move-and-move.rs:37:22 + | +LL | match [u(), u(), u(), u()] { + | -------------------- move occurs because value has type `[main::U; 4]`, which does not implement the `Copy` trait +LL | xs @ [a, .., b] => {} + | -------------^- + | | | + | | value used here after move + | value moved here + +error[E0382]: use of moved value + --> $DIR/borrowck-move-and-move.rs:43:18 + | +LL | match [u(), u(), u(), u()] { + | -------------------- move occurs because value has type `[main::U; 4]`, which does not implement the `Copy` trait +LL | xs @ [_, ys @ .., _] => {} + | ---------^^^^^^^---- + | | | + | | value used here after move + | value moved here + +error[E0382]: use of moved value + --> $DIR/borrowck-move-and-move.rs:32:16 + | +LL | fn fun(a @ b: U) {} + | ----^ + | | | + | | value used here after move + | value moved here + | move occurs because value has type `main::U`, which does not implement the `Copy` trait + +error: aborting due to 16 previous errors + +Some errors have detailed explanations: E0007, E0382. +For more information about an error, try `rustc --explain E0007`. diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs new file mode 100644 index 0000000000000..afac8d990b474 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs @@ -0,0 +1,76 @@ +// check-pass + +// Test `@` patterns combined with `box` patterns. + +#![feature(bindings_after_at)] +#![feature(box_patterns)] +#![feature(slice_patterns)] + +#[derive(Copy, Clone)] +struct C; + +fn c() -> C { C } + +struct NC; + +fn nc() -> NC { NC } + +fn main() { + let ref a @ box b = Box::new(C); // OK; the type is `Copy`. + drop(b); + drop(b); + drop(a); + + let ref a @ box b = Box::new(c()); // OK; the type is `Copy`. + drop(b); + drop(b); + drop(a); + + fn f3(ref a @ box b: Box) { // OK; the type is `Copy`. + drop(b); + drop(b); + drop(a); + } + match Box::new(c()) { + ref a @ box b => { // OK; the type is `Copy`. + drop(b); + drop(b); + drop(a); + } + } + + let ref a @ box ref b = Box::new(NC); // OK. + drop(a); + drop(b); + + fn f4(ref a @ box ref b: Box) { // OK. + drop(a); + drop(b) + } + + match Box::new(nc()) { + ref a @ box ref b => { // OK. + drop(a); + drop(b); + } + } + + match Box::new([Ok(c()), Err(nc()), Ok(c())]) { + box [Ok(a), ref xs @ .., Err(ref b)] => { + let _: C = a; + let _: &[Result; 1] = xs; + let _: &NC = b; + } + _ => {} + } + + match [Ok(Box::new(c())), Err(Box::new(nc())), Ok(Box::new(c())), Ok(Box::new(c()))] { + [Ok(box a), ref xs @ .., Err(box ref b), Err(box ref c)] => { + let _: C = a; + let _: &[Result, Box>; 1] = xs; + let _: &NC = b; + let _: &NC = c; + } + _ => {} + } +} diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.rs new file mode 100644 index 0000000000000..fce31409e16c4 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.rs @@ -0,0 +1,85 @@ +// Test `@` patterns combined with `box` patterns. + +#![feature(bindings_after_at)] +#![feature(box_patterns)] +#![feature(slice_patterns)] + +#[derive(Copy, Clone)] +struct C; + +fn c() -> C { C } + +struct NC; + +fn nc() -> NC { NC } + +fn main() { + let a @ box &b = Box::new(&C); + //~^ ERROR cannot bind by-move with sub-bindings + //~| ERROR use of moved value + + let a @ box b = Box::new(C); + //~^ ERROR cannot bind by-move with sub-bindings + //~| ERROR use of moved value + + fn f1(a @ box &b: Box<&C>) {} + //~^ ERROR cannot bind by-move with sub-bindings + //~| ERROR use of moved value + + fn f2(a @ box b: Box) {} + //~^ ERROR cannot bind by-move with sub-bindings + //~| ERROR use of moved value + + match Box::new(C) { a @ box b => {} } + //~^ ERROR cannot bind by-move with sub-bindings + //~| ERROR use of moved value + + let ref a @ box b = Box::new(NC); //~ ERROR cannot bind by-move and by-ref in the same pattern + + let ref a @ box ref mut b = Box::new(nc()); + //~^ ERROR cannot borrow `a` as mutable because it is also borrowed as immutable + let ref a @ box ref mut b = Box::new(NC); + //~^ ERROR cannot borrow `a` as mutable because it is also borrowed as immutable + let ref a @ box ref mut b = Box::new(NC); + //~^ ERROR cannot borrow `a` as mutable because it is also borrowed as immutable + *b = NC; + let ref a @ box ref mut b = Box::new(NC); + //~^ ERROR cannot borrow `a` as mutable because it is also borrowed as immutable + //~| ERROR cannot borrow `_` as mutable because it is also borrowed as immutable + *b = NC; + drop(a); + + let ref mut a @ box ref b = Box::new(NC); + //~^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable + //~| ERROR cannot borrow `_` as immutable because it is also borrowed as mutable + *a = Box::new(NC); + drop(b); + + fn f5(ref mut a @ box ref b: Box) { + //~^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable + //~| ERROR cannot borrow `_` as immutable because it is also borrowed as mutable + *a = Box::new(NC); + drop(b); + } + + match Box::new(nc()) { + ref mut a @ box ref b => { + //~^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable + //~| ERROR cannot borrow `_` as immutable because it is also borrowed as mutable + *a = Box::new(NC); + drop(b); + } + } + + match Box::new([Ok(c()), Err(nc()), Ok(c())]) { + box [Ok(a), ref xs @ .., Err(b)] => {} + //~^ ERROR cannot bind by-move and by-ref in the same pattern + _ => {} + } + + match [Ok(Box::new(c())), Err(Box::new(nc())), Ok(Box::new(c())), Ok(Box::new(c()))] { + [Ok(box ref a), ref xs @ .., Err(box b), Err(box ref mut c)] => {} + //~^ ERROR cannot bind by-move and by-ref in the same pattern + _ => {} + } +} diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr new file mode 100644 index 0000000000000..5772fadd1e741 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr @@ -0,0 +1,220 @@ +error[E0007]: cannot bind by-move with sub-bindings + --> $DIR/borrowck-pat-at-and-box.rs:17:9 + | +LL | let a @ box &b = Box::new(&C); + | ^^^^^^^^^^ binds an already bound by-move value by moving it + +error[E0007]: cannot bind by-move with sub-bindings + --> $DIR/borrowck-pat-at-and-box.rs:21:9 + | +LL | let a @ box b = Box::new(C); + | ^^^^^^^^^ binds an already bound by-move value by moving it + +error[E0007]: cannot bind by-move with sub-bindings + --> $DIR/borrowck-pat-at-and-box.rs:33:25 + | +LL | match Box::new(C) { a @ box b => {} } + | ^^^^^^^^^ binds an already bound by-move value by moving it + +error[E0009]: cannot bind by-move and by-ref in the same pattern + --> $DIR/borrowck-pat-at-and-box.rs:37:21 + | +LL | let ref a @ box b = Box::new(NC); + | ------------^ + | | | + | | by-move pattern here + | by-ref pattern here + +error: cannot borrow `a` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-at-and-box.rs:39:9 + | +LL | let ref a @ box ref mut b = Box::new(nc()); + | -----^^^^^^^--------- + | | | + | | mutable borrow occurs here + | immutable borrow occurs here + +error: cannot borrow `a` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-at-and-box.rs:41:9 + | +LL | let ref a @ box ref mut b = Box::new(NC); + | -----^^^^^^^--------- + | | | + | | mutable borrow occurs here + | immutable borrow occurs here + +error: cannot borrow `a` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-at-and-box.rs:43:9 + | +LL | let ref a @ box ref mut b = Box::new(NC); + | -----^^^^^^^--------- + | | | + | | mutable borrow occurs here + | immutable borrow occurs here + +error: cannot borrow `a` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-at-and-box.rs:46:9 + | +LL | let ref a @ box ref mut b = Box::new(NC); + | -----^^^^^^^--------- + | | | + | | mutable borrow occurs here + | immutable borrow occurs here + +error: cannot borrow `a` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-at-and-box.rs:52:9 + | +LL | let ref mut a @ box ref b = Box::new(NC); + | ---------^^^^^^^----- + | | | + | | immutable borrow occurs here + | mutable borrow occurs here + +error: cannot borrow `a` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-at-and-box.rs:66:9 + | +LL | ref mut a @ box ref b => { + | ---------^^^^^^^----- + | | | + | | immutable borrow occurs here + | mutable borrow occurs here + +error[E0009]: cannot bind by-move and by-ref in the same pattern + --> $DIR/borrowck-pat-at-and-box.rs:75:38 + | +LL | box [Ok(a), ref xs @ .., Err(b)] => {} + | ----------- ^ by-move pattern here + | | + | by-ref pattern here + +error[E0009]: cannot bind by-move and by-ref in the same pattern + --> $DIR/borrowck-pat-at-and-box.rs:81:46 + | +LL | [Ok(box ref a), ref xs @ .., Err(box b), Err(box ref mut c)] => {} + | ----- ----------- ^ --------- by-ref pattern here + | | | | + | | | by-move pattern here + | | by-ref pattern here + | by-ref pattern here + +error[E0007]: cannot bind by-move with sub-bindings + --> $DIR/borrowck-pat-at-and-box.rs:25:11 + | +LL | fn f1(a @ box &b: Box<&C>) {} + | ^^^^^^^^^^ binds an already bound by-move value by moving it + +error[E0007]: cannot bind by-move with sub-bindings + --> $DIR/borrowck-pat-at-and-box.rs:29:11 + | +LL | fn f2(a @ box b: Box) {} + | ^^^^^^^^^ binds an already bound by-move value by moving it + +error: cannot borrow `a` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-at-and-box.rs:58:11 + | +LL | fn f5(ref mut a @ box ref b: Box) { + | ---------^^^^^^^----- + | | | + | | immutable borrow occurs here + | mutable borrow occurs here + +error[E0382]: use of moved value + --> $DIR/borrowck-pat-at-and-box.rs:17:18 + | +LL | let a @ box &b = Box::new(&C); + | ---------^ ------------ move occurs because value has type `std::boxed::Box<&C>`, which does not implement the `Copy` trait + | | | + | | value used here after move + | value moved here + +error[E0382]: use of moved value + --> $DIR/borrowck-pat-at-and-box.rs:21:17 + | +LL | let a @ box b = Box::new(C); + | --------^ ----------- move occurs because value has type `std::boxed::Box`, which does not implement the `Copy` trait + | | | + | | value used here after move + | value moved here + +error[E0382]: use of moved value + --> $DIR/borrowck-pat-at-and-box.rs:33:33 + | +LL | match Box::new(C) { a @ box b => {} } + | ----------- --------^ + | | | | + | | | value used here after move + | | value moved here + | move occurs because value has type `std::boxed::Box`, which does not implement the `Copy` trait + +error[E0502]: cannot borrow `_` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-at-and-box.rs:46:21 + | +LL | let ref a @ box ref mut b = Box::new(NC); + | ------------^^^^^^^^^ + | | | + | | mutable borrow occurs here + | immutable borrow occurs here +... +LL | drop(a); + | - immutable borrow later used here + +error[E0502]: cannot borrow `_` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-at-and-box.rs:52:25 + | +LL | let ref mut a @ box ref b = Box::new(NC); + | ----------------^^^^^ + | | | + | | immutable borrow occurs here + | mutable borrow occurs here +... +LL | *a = Box::new(NC); + | -- mutable borrow later used here + +error[E0502]: cannot borrow `_` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-at-and-box.rs:66:25 + | +LL | ref mut a @ box ref b => { + | ----------------^^^^^ + | | | + | | immutable borrow occurs here + | mutable borrow occurs here +... +LL | *a = Box::new(NC); + | -- mutable borrow later used here + +error[E0382]: use of moved value + --> $DIR/borrowck-pat-at-and-box.rs:25:20 + | +LL | fn f1(a @ box &b: Box<&C>) {} + | ---------^ + | | | + | | value used here after move + | value moved here + | move occurs because value has type `std::boxed::Box<&C>`, which does not implement the `Copy` trait + +error[E0382]: use of moved value + --> $DIR/borrowck-pat-at-and-box.rs:29:19 + | +LL | fn f2(a @ box b: Box) {} + | --------^ + | | | + | | value used here after move + | value moved here + | move occurs because value has type `std::boxed::Box`, which does not implement the `Copy` trait + +error[E0502]: cannot borrow `_` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-at-and-box.rs:58:27 + | +LL | fn f5(ref mut a @ box ref b: Box) { + | ----------------^^^^^ + | | | + | | immutable borrow occurs here + | mutable borrow occurs here +... +LL | *a = Box::new(NC); + | -- mutable borrow later used here + +error: aborting due to 24 previous errors + +Some errors have detailed explanations: E0007, E0009, E0382, E0502. +For more information about an error, try `rustc --explain E0007`. diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-copy-bindings-in-at.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-copy-bindings-in-at.rs new file mode 100644 index 0000000000000..be19e5f2a85ca --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-copy-bindings-in-at.rs @@ -0,0 +1,52 @@ +// check-pass + +// Test `Copy` bindings in the rhs of `@` patterns. + +#![feature(slice_patterns)] +#![feature(bindings_after_at)] + +#[derive(Copy, Clone)] +struct C; + +fn mk_c() -> C { C } + +#[derive(Copy, Clone)] +struct P(A, B); + +enum E { L(A), R(B) } + +fn main() { + let a @ b @ c @ d = C; + let a @ (b, c) = (C, mk_c()); + let a @ P(b, P(c, d)) = P(mk_c(), P(C, C)); + let a @ [b, c] = [C, C]; + let a @ [b, .., c] = [C, mk_c(), C]; + let a @ [b, mid @ .., c] = [C, mk_c(), C]; + let a @ &(b, c) = &(C, C); + let a @ &(b, &P(c, d)) = &(mk_c(), &P(C, C)); + + fn foo(a @ [b, mid @ .., c]: [C; 3]) {} + + use self::E::*; + match L(C) { + L(a) | R(a) => { + let a: C = a; + drop(a); + drop(a); + } + } + match R(&L(&mk_c())) { + L(L(&a)) | L(R(&a)) | R(L(&a)) | R(R(&a)) => { + let a: C = a; + drop(a); + drop(a); + } + } + + match Ok(mk_c()) { + Ok(ref a @ b) | Err(b @ ref a) => { + let _: &C = a; + let _: C = b; + } + } +} diff --git a/src/test/ui/error-codes/E0303.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs similarity index 51% rename from src/test/ui/error-codes/E0303.rs rename to src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs index 0530d43b653f5..abe5ed81b71a2 100644 --- a/src/test/ui/error-codes/E0303.rs +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs @@ -1,8 +1,9 @@ +#![feature(bindings_after_at)] + fn main() { match Some("hi".to_string()) { ref op_string_ref @ Some(s) => {}, - //~^ ERROR pattern bindings are not allowed after an `@` [E0303] - //~| ERROR E0009 + //~^ ERROR cannot bind by-move and by-ref in the same pattern [E0009] None => {}, } } diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr new file mode 100644 index 0000000000000..1f70a6c437e92 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr @@ -0,0 +1,12 @@ +error[E0009]: cannot bind by-move and by-ref in the same pattern + --> $DIR/borrowck-pat-by-move-and-ref.rs:5:34 + | +LL | ref op_string_ref @ Some(s) => {}, + | -------------------------^- + | | | + | | by-move pattern here + | by-ref pattern here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0009`. diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-both-sides.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-both-sides.rs new file mode 100644 index 0000000000000..edf9fb3145890 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-both-sides.rs @@ -0,0 +1,48 @@ +// check-pass + +// Test that `ref` patterns may be used on both sides +// of an `@` pattern according to NLL borrowck. + +#![feature(bindings_after_at)] +#![feature(slice_patterns)] + +fn main() { + struct U; // Not copy! + + // Promotion: + let ref a @ ref b = U; + let _: &U = a; + let _: &U = b; + + // Prevent promotion: + fn u() -> U { U } + + let ref a @ ref b = u(); + let _: &U = a; + let _: &U = b; + + let ref a @ (ref b, [ref c, ref d]) = (u(), [u(), u()]); + let _: &(U, [U; 2]) = a; + let _: &U = b; + let _: &U = c; + let _: &U = d; + + fn f1(ref a @ (ref b, [ref c, ref mid @ .., ref d]): (U, [U; 4])) {} + + let a @ (b, [c, d]) = &(u(), [u(), u()]); + let _: &(U, [U; 2]) = a; + let _: &U = b; + let _: &U = c; + let _: &U = d; + + let ref a @ &ref b = &u(); + let _: &&U = a; + let _: &U = b; + + match Ok(u()) { + ref a @ Ok(ref b) | ref a @ Err(ref b) => { + let _: &Result = a; + let _: &U = b; + } + } +} diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs new file mode 100644 index 0000000000000..88eda9afec7eb --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs @@ -0,0 +1,133 @@ +#![feature(bindings_after_at)] +#![feature(slice_patterns)] + +enum Option { + None, + Some(T), +} + +fn main() { + match &mut Some(1) { + ref mut z @ &mut Some(ref a) => { + //~^ ERROR cannot borrow `z` as immutable because it is also borrowed as mutable + //~| ERROR cannot borrow `_` as immutable because it is also borrowed as mutable + **z = None; + println!("{}", *a); + } + _ => () + } + + struct U; + + // Prevent promotion: + fn u() -> U { U } + + fn f1(ref a @ ref mut b: U) {} + //~^ ERROR cannot borrow `a` as mutable because it is also borrowed as immutable + fn f2(ref mut a @ ref b: U) {} + //~^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable + fn f3(ref a @ [ref b, ref mut mid @ .., ref c]: [U; 4]) {} + //~^ ERROR cannot borrow `a` as mutable because it is also borrowed as immutable + + let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub + //~^ ERROR cannot borrow `a` as mutable more than once at a time + //~| ERROR cannot borrow `b` as mutable because it is also borrowed as immutable + + let ref a @ ref mut b = U; + //~^ ERROR cannot borrow `a` as mutable because it is also borrowed as immutable + let ref mut a @ ref b = U; + //~^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable + let ref a @ (ref mut b, ref mut c) = (U, U); + //~^ ERROR cannot borrow `a` as mutable because it is also borrowed as immutable + let ref mut a @ (ref b, ref c) = (U, U); + //~^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable + + let ref mut a @ ref b = u(); + //~^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable + //~| ERROR cannot borrow `_` as immutable because it is also borrowed as mutable + *a = u(); + drop(b); + let ref a @ ref mut b = u(); + //~^ ERROR cannot borrow `a` as mutable because it is also borrowed as immutable + //~| ERROR cannot borrow `_` as mutable because it is also borrowed as immutable + *b = u(); + drop(a); + + let ref mut a @ ref b = U; + //~^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable + *a = U; + drop(b); + let ref a @ ref mut b = U; + //~^ ERROR cannot borrow `a` as mutable because it is also borrowed as immutable + *b = U; + drop(a); + + match Ok(U) { + ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => { + //~^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable + //~| ERROR cannot borrow `a` as immutable because it is also borrowed as mutable + *a = Err(U); + drop(b); + } + } + + match Ok(U) { + ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => { + //~^ ERROR cannot borrow `a` as mutable because it is also borrowed as immutable + //~| ERROR cannot borrow `a` as mutable because it is also borrowed as immutable + //~| ERROR cannot borrow `_` as mutable because it is also borrowed as immutable + //~| ERROR cannot borrow `_` as mutable because it is also borrowed as immutable + *b = U; + drop(a); + } + } + + match Ok(U) { + ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {} + //~^ ERROR cannot borrow `a` as mutable because it is also borrowed as immutable + //~| ERROR cannot borrow `a` as mutable because it is also borrowed as immutable + //~| ERROR cannot assign to `*b`, as it is immutable for the pattern guard + _ => {} + } + match Ok(U) { + ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {} + //~^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable + //~| ERROR cannot borrow `a` as immutable because it is also borrowed as mutable + //~| ERROR cannot assign to `*a`, as it is immutable for the pattern guard + _ => {} + } + match Ok(U) { + ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} + //~^ ERROR cannot borrow `a` as mutable because it is also borrowed as immutable + //~| ERROR cannot borrow `a` as mutable because it is also borrowed as immutable + //~| ERROR cannot move out of `b` in pattern guard + _ => {} + } + match Ok(U) { + ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {} + //~^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable + //~| ERROR cannot borrow `a` as immutable because it is also borrowed as mutable + //~| ERROR cannot move out of `a` in pattern guard + _ => {} + } + + let ref a @ (ref mut b, ref mut c) = (U, U); + //~^ ERROR cannot borrow `a` as mutable because it is also borrowed as immutable + *b = U; + *c = U; + + let ref a @ (ref mut b, ref mut c) = (U, U); + //~^ ERROR cannot borrow `a` as mutable because it is also borrowed as immutable + //~| ERROR cannot borrow `_` as mutable because it is also borrowed as immutable + //~| ERROR cannot borrow `_` as mutable because it is also borrowed as immutable + *b = U; + drop(a); + + let ref a @ (ref mut b, ref mut c) = (U, U); + //~^ ERROR cannot borrow `a` as mutable because it is also borrowed as immutable + *b = U; //~| ERROR cannot borrow `_` as mutable because it is also borrowed as immutable + *c = U; //~| ERROR cannot borrow `_` as mutable because it is also borrowed as immutable + drop(a); + let ref mut a @ (ref b, ref c) = (U, U); + //~^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable +} diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr new file mode 100644 index 0000000000000..b068a6125b670 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr @@ -0,0 +1,421 @@ +error: cannot borrow `z` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:11:9 + | +LL | ref mut z @ &mut Some(ref a) => { + | ---------^^^^^^^^^^^^^-----^ + | | | + | | immutable borrow occurs here + | mutable borrow occurs here + +error: cannot borrow `a` as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:32:9 + | +LL | let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub + | ---------^^^^-----------------^ + | | | | + | | | another mutable borrow occurs here + | | also borrowed as immutable here + | first mutable borrow occurs here + +error: cannot borrow `b` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:32:22 + | +LL | let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub + | -----^^^--------- + | | | + | | mutable borrow occurs here + | immutable borrow occurs here + +error: cannot borrow `a` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:36:9 + | +LL | let ref a @ ref mut b = U; + | -----^^^--------- + | | | + | | mutable borrow occurs here + | immutable borrow occurs here + +error: cannot borrow `a` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:38:9 + | +LL | let ref mut a @ ref b = U; + | ---------^^^----- + | | | + | | immutable borrow occurs here + | mutable borrow occurs here + +error: cannot borrow `a` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:40:9 + | +LL | let ref a @ (ref mut b, ref mut c) = (U, U); + | -----^^^^---------^^---------^ + | | | | + | | | mutable borrow occurs here + | | mutable borrow occurs here + | immutable borrow occurs here + +error: cannot borrow `a` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:42:9 + | +LL | let ref mut a @ (ref b, ref c) = (U, U); + | ---------^^^^-----^^-----^ + | | | | + | | | immutable borrow occurs here + | | immutable borrow occurs here + | mutable borrow occurs here + +error: cannot borrow `a` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:45:9 + | +LL | let ref mut a @ ref b = u(); + | ---------^^^----- + | | | + | | immutable borrow occurs here + | mutable borrow occurs here + +error: cannot borrow `a` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:50:9 + | +LL | let ref a @ ref mut b = u(); + | -----^^^--------- + | | | + | | mutable borrow occurs here + | immutable borrow occurs here + +error: cannot borrow `a` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:56:9 + | +LL | let ref mut a @ ref b = U; + | ---------^^^----- + | | | + | | immutable borrow occurs here + | mutable borrow occurs here + +error: cannot borrow `a` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:60:9 + | +LL | let ref a @ ref mut b = U; + | -----^^^--------- + | | | + | | mutable borrow occurs here + | immutable borrow occurs here + +error: cannot borrow `a` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:66:9 + | +LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => { + | ---------^^^^^^-----^ + | | | + | | immutable borrow occurs here + | mutable borrow occurs here + +error: cannot borrow `a` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:66:33 + | +LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => { + | ---------^^^^^^^-----^ + | | | + | | immutable borrow occurs here + | mutable borrow occurs here + +error: cannot borrow `a` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:75:9 + | +LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => { + | -----^^^^^^---------^ + | | | + | | mutable borrow occurs here + | immutable borrow occurs here + +error: cannot borrow `a` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:75:33 + | +LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => { + | -----^^^^^^^---------^ + | | | + | | mutable borrow occurs here + | immutable borrow occurs here + +error: cannot borrow `a` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:86:9 + | +LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {} + | -----^^^^^^---------^ + | | | + | | mutable borrow occurs here + | immutable borrow occurs here + +error: cannot borrow `a` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:86:33 + | +LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {} + | -----^^^^^^^---------^ + | | | + | | mutable borrow occurs here + | immutable borrow occurs here + +error: cannot borrow `a` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:93:9 + | +LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {} + | ---------^^^^^^-----^ + | | | + | | immutable borrow occurs here + | mutable borrow occurs here + +error: cannot borrow `a` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:93:33 + | +LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {} + | ---------^^^^^^^-----^ + | | | + | | immutable borrow occurs here + | mutable borrow occurs here + +error: cannot borrow `a` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:100:9 + | +LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} + | -----^^^^^^---------^ + | | | + | | mutable borrow occurs here + | immutable borrow occurs here + +error: cannot borrow `a` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:100:33 + | +LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} + | -----^^^^^^^---------^ + | | | + | | mutable borrow occurs here + | immutable borrow occurs here + +error: cannot borrow `a` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:107:9 + | +LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {} + | ---------^^^^^^-----^ + | | | + | | immutable borrow occurs here + | mutable borrow occurs here + +error: cannot borrow `a` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:107:33 + | +LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {} + | ---------^^^^^^^-----^ + | | | + | | immutable borrow occurs here + | mutable borrow occurs here + +error: cannot borrow `a` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:114:9 + | +LL | let ref a @ (ref mut b, ref mut c) = (U, U); + | -----^^^^---------^^---------^ + | | | | + | | | mutable borrow occurs here + | | mutable borrow occurs here + | immutable borrow occurs here + +error: cannot borrow `a` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:119:9 + | +LL | let ref a @ (ref mut b, ref mut c) = (U, U); + | -----^^^^---------^^---------^ + | | | | + | | | mutable borrow occurs here + | | mutable borrow occurs here + | immutable borrow occurs here + +error: cannot borrow `a` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:126:9 + | +LL | let ref a @ (ref mut b, ref mut c) = (U, U); + | -----^^^^---------^^---------^ + | | | | + | | | mutable borrow occurs here + | | mutable borrow occurs here + | immutable borrow occurs here + +error: cannot borrow `a` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:131:9 + | +LL | let ref mut a @ (ref b, ref c) = (U, U); + | ---------^^^^-----^^-----^ + | | | | + | | | immutable borrow occurs here + | | immutable borrow occurs here + | mutable borrow occurs here + +error: cannot borrow `a` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:25:11 + | +LL | fn f1(ref a @ ref mut b: U) {} + | -----^^^--------- + | | | + | | mutable borrow occurs here + | immutable borrow occurs here + +error: cannot borrow `a` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:27:11 + | +LL | fn f2(ref mut a @ ref b: U) {} + | ---------^^^----- + | | | + | | immutable borrow occurs here + | mutable borrow occurs here + +error: cannot borrow `a` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:29:11 + | +LL | fn f3(ref a @ [ref b, ref mut mid @ .., ref c]: [U; 4]) {} + | -----^^^^^^^^^^^----------------^^^^^^^^ + | | | + | | mutable borrow occurs here + | immutable borrow occurs here + +error[E0502]: cannot borrow `_` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:11:31 + | +LL | ref mut z @ &mut Some(ref a) => { + | ----------------------^^^^^- + | | | + | | immutable borrow occurs here + | mutable borrow occurs here +... +LL | **z = None; + | ---------- mutable borrow later used here + +error[E0502]: cannot borrow `_` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:45:21 + | +LL | let ref mut a @ ref b = u(); + | ------------^^^^^ + | | | + | | immutable borrow occurs here + | mutable borrow occurs here +... +LL | *a = u(); + | -------- mutable borrow later used here + +error[E0502]: cannot borrow `_` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:50:17 + | +LL | let ref a @ ref mut b = u(); + | --------^^^^^^^^^ + | | | + | | mutable borrow occurs here + | immutable borrow occurs here +... +LL | drop(a); + | - immutable borrow later used here + +error[E0502]: cannot borrow `_` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:75:20 + | +LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => { + | -----------^^^^^^^^^- + | | | + | | mutable borrow occurs here + | immutable borrow occurs here +... +LL | drop(a); + | - immutable borrow later used here + +error[E0502]: cannot borrow `_` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:75:45 + | +LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => { + | ------------^^^^^^^^^- + | | | + | | mutable borrow occurs here + | immutable borrow occurs here +... +LL | drop(a); + | - immutable borrow later used here + +error[E0594]: cannot assign to `*b`, as it is immutable for the pattern guard + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:86:61 + | +LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {} + | ^^^^^^ cannot assign + | + = note: variables bound in patterns are immutable until the end of the pattern guard + +error[E0594]: cannot assign to `*a`, as it is immutable for the pattern guard + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:93:61 + | +LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {} + | ^^^^^^^^^^^ cannot assign + | + = note: variables bound in patterns are immutable until the end of the pattern guard + +error[E0507]: cannot move out of `b` in pattern guard + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:100:66 + | +LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} + | ^ move occurs because `b` has type `&mut main::U`, which does not implement the `Copy` trait + | + = note: variables bound in patterns cannot be moved from until after the end of the pattern guard + +error[E0507]: cannot move out of `a` in pattern guard + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:107:66 + | +LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {} + | ^ move occurs because `a` has type `&mut std::result::Result`, which does not implement the `Copy` trait + | + = note: variables bound in patterns cannot be moved from until after the end of the pattern guard + +error[E0502]: cannot borrow `_` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:119:18 + | +LL | let ref a @ (ref mut b, ref mut c) = (U, U); + | ---------^^^^^^^^^------------ + | | | + | | mutable borrow occurs here + | immutable borrow occurs here +... +LL | drop(a); + | - immutable borrow later used here + +error[E0502]: cannot borrow `_` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:119:29 + | +LL | let ref a @ (ref mut b, ref mut c) = (U, U); + | --------------------^^^^^^^^^- + | | | + | | mutable borrow occurs here + | immutable borrow occurs here +... +LL | drop(a); + | - immutable borrow later used here + +error[E0502]: cannot borrow `_` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:126:18 + | +LL | let ref a @ (ref mut b, ref mut c) = (U, U); + | ---------^^^^^^^^^------------ + | | | + | | mutable borrow occurs here + | immutable borrow occurs here +... +LL | drop(a); + | - immutable borrow later used here + +error[E0502]: cannot borrow `_` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:126:29 + | +LL | let ref a @ (ref mut b, ref mut c) = (U, U); + | --------------------^^^^^^^^^- + | | | + | | mutable borrow occurs here + | immutable borrow occurs here +... +LL | drop(a); + | - immutable borrow later used here + +error: aborting due to 43 previous errors + +Some errors have detailed explanations: E0502, E0507, E0594. +For more information about an error, try `rustc --explain E0502`. diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs new file mode 100644 index 0000000000000..6b8b7545e687d --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs @@ -0,0 +1,112 @@ +// Test that `ref mut x @ ref mut y` and varieties of that are not allowed. + +#![feature(bindings_after_at)] +#![feature(slice_patterns)] + +fn main() { + struct U; + + fn u() -> U { U } + + fn f1(ref mut a @ ref mut b: U) {} + //~^ ERROR cannot borrow `a` as mutable more than once at a time + fn f2(ref mut a @ ref mut b: U) {} + //~^ ERROR cannot borrow `a` as mutable more than once at a time + fn f3( + ref mut a @ [ + //~^ ERROR cannot borrow `a` as mutable more than once at a time + [ref b @ .., _], + [_, ref mut mid @ ..], + .., + [..], + ] : [[U; 4]; 5] + ) {} + + let ref mut a @ ref mut b = U; + //~^ ERROR cannot borrow `a` as mutable more than once at a time + //~| ERROR cannot borrow `_` as mutable more than once at a time + drop(a); + let ref mut a @ ref mut b = U; + //~^ ERROR cannot borrow `a` as mutable more than once at a time + drop(b); + let ref mut a @ ref mut b = U; + //~^ ERROR cannot borrow `a` as mutable more than once at a time + + let ref mut a @ ref mut b = U; + //~^ ERROR cannot borrow `a` as mutable more than once at a time + //~| ERROR cannot borrow `_` as mutable more than once at a time + *a = U; + let ref mut a @ ref mut b = U; + //~^ ERROR cannot borrow `a` as mutable more than once at a time + *b = U; + + let ref mut a @ ( + //~^ ERROR cannot borrow `a` as mutable more than once at a time + ref mut b, + [ + ref mut c, + ref mut d, + ref e, + ] + ) = (U, [U, U, U]); + + let ref mut a @ ( + //~^ ERROR cannot borrow `a` as mutable more than once at a time + ref mut b, + [ + ref mut c, + ref mut d, + ref e, + ] + ) = (u(), [u(), u(), u()]); + + let a @ (ref mut b, ref mut c) = (U, U); + //~^ ERROR cannot bind by-move with sub-bindings + //~| ERROR borrow of moved value + let mut val = (U, [U, U]); + let a @ (b, [c, d]) = &mut val; // Same as ^-- + //~^ ERROR cannot bind by-move with sub-bindings + //~| ERROR borrow of moved value + + let a @ &mut ref mut b = &mut U; + //~^ ERROR cannot bind by-move with sub-bindings + //~| ERROR borrow of moved value + let a @ &mut (ref mut b, ref mut c) = &mut (U, U); + //~^ ERROR cannot bind by-move with sub-bindings + //~| ERROR borrow of moved value + + match Ok(U) { + ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { + //~^ ERROR cannot borrow `a` as mutable more than once at a time + //~| ERROR cannot borrow `a` as mutable more than once at a time + } + } + match Ok(U) { + ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { + //~^ ERROR cannot borrow `a` as mutable more than once at a time + //~| ERROR cannot borrow `a` as mutable more than once at a time + *b = U; + } + } + match Ok(U) { + ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { + //~^ ERROR cannot borrow `a` as mutable more than once at a time + //~| ERROR cannot borrow `a` as mutable more than once at a time + //~| ERROR cannot borrow `_` as mutable more than once at a time + //~| ERROR cannot borrow `_` as mutable more than once at a time + *a = Err(U); + + // FIXME: The binding name `_` used above makes for problematic diagnostics. + // Resolve that somehow... + } + } + match Ok(U) { + ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { + //~^ ERROR cannot borrow `a` as mutable more than once at a time + //~| ERROR cannot borrow `a` as mutable more than once at a time + //~| ERROR cannot borrow `_` as mutable more than once at a time + //~| ERROR cannot borrow `_` as mutable more than once at a time + drop(a); + } + } +} diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr new file mode 100644 index 0000000000000..1b5e6c7411703 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr @@ -0,0 +1,333 @@ +error: cannot borrow `a` as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:25:9 + | +LL | let ref mut a @ ref mut b = U; + | ---------^^^--------- + | | | + | | another mutable borrow occurs here + | first mutable borrow occurs here + +error: cannot borrow `a` as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:29:9 + | +LL | let ref mut a @ ref mut b = U; + | ---------^^^--------- + | | | + | | another mutable borrow occurs here + | first mutable borrow occurs here + +error: cannot borrow `a` as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:32:9 + | +LL | let ref mut a @ ref mut b = U; + | ---------^^^--------- + | | | + | | another mutable borrow occurs here + | first mutable borrow occurs here + +error: cannot borrow `a` as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:35:9 + | +LL | let ref mut a @ ref mut b = U; + | ---------^^^--------- + | | | + | | another mutable borrow occurs here + | first mutable borrow occurs here + +error: cannot borrow `a` as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:39:9 + | +LL | let ref mut a @ ref mut b = U; + | ---------^^^--------- + | | | + | | another mutable borrow occurs here + | first mutable borrow occurs here + +error: cannot borrow `a` as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:43:9 + | +LL | let ref mut a @ ( + | ^-------- + | | + | _________first mutable borrow occurs here + | | +LL | | +LL | | ref mut b, + | | --------- another mutable borrow occurs here +LL | | [ +LL | | ref mut c, + | | --------- another mutable borrow occurs here +LL | | ref mut d, + | | --------- another mutable borrow occurs here +LL | | ref e, + | | ----- also borrowed as immutable here +LL | | ] +LL | | ) = (U, [U, U, U]); + | |_____^ + +error: cannot borrow `a` as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:53:9 + | +LL | let ref mut a @ ( + | ^-------- + | | + | _________first mutable borrow occurs here + | | +LL | | +LL | | ref mut b, + | | --------- another mutable borrow occurs here +LL | | [ +LL | | ref mut c, + | | --------- another mutable borrow occurs here +LL | | ref mut d, + | | --------- another mutable borrow occurs here +LL | | ref e, + | | ----- also borrowed as immutable here +LL | | ] +LL | | ) = (u(), [u(), u(), u()]); + | |_________^ + +error[E0007]: cannot bind by-move with sub-bindings + --> $DIR/borrowck-pat-ref-mut-twice.rs:63:9 + | +LL | let a @ (ref mut b, ref mut c) = (U, U); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ binds an already bound by-move value by moving it + +error[E0007]: cannot bind by-move with sub-bindings + --> $DIR/borrowck-pat-ref-mut-twice.rs:67:9 + | +LL | let a @ (b, [c, d]) = &mut val; // Same as ^-- + | ^^^^^^^^^^^^^^^ binds an already bound by-move value by moving it + +error[E0007]: cannot bind by-move with sub-bindings + --> $DIR/borrowck-pat-ref-mut-twice.rs:71:9 + | +LL | let a @ &mut ref mut b = &mut U; + | ^^^^^^^^^^^^^^^^^^ binds an already bound by-move value by moving it + +error[E0007]: cannot bind by-move with sub-bindings + --> $DIR/borrowck-pat-ref-mut-twice.rs:74:9 + | +LL | let a @ &mut (ref mut b, ref mut c) = &mut (U, U); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ binds an already bound by-move value by moving it + +error: cannot borrow `a` as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:79:9 + | +LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { + | ---------^^^^^^---------^ + | | | + | | another mutable borrow occurs here + | first mutable borrow occurs here + +error: cannot borrow `a` as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:79:37 + | +LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { + | ---------^^^^^^^---------^ + | | | + | | another mutable borrow occurs here + | first mutable borrow occurs here + +error: cannot borrow `a` as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:85:9 + | +LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { + | ---------^^^^^^---------^ + | | | + | | another mutable borrow occurs here + | first mutable borrow occurs here + +error: cannot borrow `a` as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:85:37 + | +LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { + | ---------^^^^^^^---------^ + | | | + | | another mutable borrow occurs here + | first mutable borrow occurs here + +error: cannot borrow `a` as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:92:9 + | +LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { + | ---------^^^^^^---------^ + | | | + | | another mutable borrow occurs here + | first mutable borrow occurs here + +error: cannot borrow `a` as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:92:37 + | +LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { + | ---------^^^^^^^---------^ + | | | + | | another mutable borrow occurs here + | first mutable borrow occurs here + +error: cannot borrow `a` as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:104:9 + | +LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { + | ---------^^^^^^---------^ + | | | + | | another mutable borrow occurs here + | first mutable borrow occurs here + +error: cannot borrow `a` as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:104:37 + | +LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { + | ---------^^^^^^^---------^ + | | | + | | another mutable borrow occurs here + | first mutable borrow occurs here + +error: cannot borrow `a` as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:11:11 + | +LL | fn f1(ref mut a @ ref mut b: U) {} + | ---------^^^--------- + | | | + | | another mutable borrow occurs here + | first mutable borrow occurs here + +error: cannot borrow `a` as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:13:11 + | +LL | fn f2(ref mut a @ ref mut b: U) {} + | ---------^^^--------- + | | | + | | another mutable borrow occurs here + | first mutable borrow occurs here + +error: cannot borrow `a` as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:16:9 + | +LL | ref mut a @ [ + | ^-------- + | | + | _________first mutable borrow occurs here + | | +LL | | +LL | | [ref b @ .., _], + | | ---------- also borrowed as immutable here +LL | | [_, ref mut mid @ ..], + | | ---------------- another mutable borrow occurs here +LL | | .., +LL | | [..], +LL | | ] : [[U; 4]; 5] + | |_________^ + +error[E0499]: cannot borrow `_` as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:25:21 + | +LL | let ref mut a @ ref mut b = U; + | ------------^^^^^^^^^ + | | | + | | second mutable borrow occurs here + | first mutable borrow occurs here +... +LL | drop(a); + | - first borrow later used here + +error[E0499]: cannot borrow `_` as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:35:21 + | +LL | let ref mut a @ ref mut b = U; + | ------------^^^^^^^^^ + | | | + | | second mutable borrow occurs here + | first mutable borrow occurs here +... +LL | *a = U; + | ------ first borrow later used here + +error[E0382]: borrow of moved value + --> $DIR/borrowck-pat-ref-mut-twice.rs:63:25 + | +LL | let a @ (ref mut b, ref mut c) = (U, U); + | ----------------^^^^^^^^^- ------ move occurs because value has type `(main::U, main::U)`, which does not implement the `Copy` trait + | | | + | | value borrowed here after move + | value moved here + +error[E0382]: borrow of moved value + --> $DIR/borrowck-pat-ref-mut-twice.rs:67:21 + | +LL | let a @ (b, [c, d]) = &mut val; // Same as ^-- + | ------------^-- -------- move occurs because value has type `&mut (main::U, [main::U; 2])`, which does not implement the `Copy` trait + | | | + | | value borrowed here after move + | value moved here + +error[E0382]: borrow of moved value + --> $DIR/borrowck-pat-ref-mut-twice.rs:71:18 + | +LL | let a @ &mut ref mut b = &mut U; + | ---------^^^^^^^^^ ------ move occurs because value has type `&mut main::U`, which does not implement the `Copy` trait + | | | + | | value borrowed here after move + | value moved here + +error[E0382]: borrow of moved value + --> $DIR/borrowck-pat-ref-mut-twice.rs:74:30 + | +LL | let a @ &mut (ref mut b, ref mut c) = &mut (U, U); + | ---------------------^^^^^^^^^- ----------- move occurs because value has type `&mut (main::U, main::U)`, which does not implement the `Copy` trait + | | | + | | value borrowed here after move + | value moved here + +error[E0499]: cannot borrow `_` as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:92:24 + | +LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { + | ---------------^^^^^^^^^- + | | | + | | second mutable borrow occurs here + | first mutable borrow occurs here +... +LL | *a = Err(U); + | ----------- first borrow later used here + +error[E0499]: cannot borrow `_` as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:92:53 + | +LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { + | ----------------^^^^^^^^^- + | | | + | | second mutable borrow occurs here + | first mutable borrow occurs here +... +LL | *a = Err(U); + | ----------- first borrow later used here + +error[E0499]: cannot borrow `_` as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:104:24 + | +LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { + | ---------------^^^^^^^^^- + | | | + | | second mutable borrow occurs here + | first mutable borrow occurs here +... +LL | drop(a); + | - first borrow later used here + +error[E0499]: cannot borrow `_` as mutable more than once at a time + --> $DIR/borrowck-pat-ref-mut-twice.rs:104:53 + | +LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { + | ----------------^^^^^^^^^- + | | | + | | second mutable borrow occurs here + | first mutable borrow occurs here +... +LL | drop(a); + | - first borrow later used here + +error: aborting due to 32 previous errors + +Some errors have detailed explanations: E0007, E0382, E0499. +For more information about an error, try `rustc --explain E0007`. diff --git a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.rs b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.rs new file mode 100644 index 0000000000000..db5aabc7a1453 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.rs @@ -0,0 +1,20 @@ +// Test that mixing `Copy` and non-`Copy` types in `@` patterns is forbidden. + +#![feature(bindings_after_at)] + +#[derive(Copy, Clone)] +struct C; + +struct NC(A, B); + +fn main() { + let a @ NC(b, c) = NC(C, C); + //~^ ERROR cannot bind by-move with sub-bindings + //~| ERROR use of moved value + + let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C)); + //~^ ERROR cannot bind by-move with sub-bindings + //~| ERROR use of moved value + //~| ERROR cannot bind by-move with sub-bindings + //~| ERROR use of moved value +} diff --git a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr new file mode 100644 index 0000000000000..cfc35d6c32a72 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr @@ -0,0 +1,51 @@ +error[E0007]: cannot bind by-move with sub-bindings + --> $DIR/copy-and-move-mixed.rs:11:9 + | +LL | let a @ NC(b, c) = NC(C, C); + | ^^^^^^^^^^^^ binds an already bound by-move value by moving it + +error[E0007]: cannot bind by-move with sub-bindings + --> $DIR/copy-and-move-mixed.rs:15:9 + | +LL | let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C)); + | ^^^^^^^^^^^^^^^^^^^^^^^ binds an already bound by-move value by moving it + +error[E0007]: cannot bind by-move with sub-bindings + --> $DIR/copy-and-move-mixed.rs:15:19 + | +LL | let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C)); + | ^^^^^^^^^^^^ binds an already bound by-move value by moving it + +error[E0382]: use of moved value + --> $DIR/copy-and-move-mixed.rs:11:19 + | +LL | let a @ NC(b, c) = NC(C, C); + | ----------^- -------- move occurs because value has type `NC`, which does not implement the `Copy` trait + | | | + | | value used here after move + | value moved here + +error[E0382]: use of moved value + --> $DIR/copy-and-move-mixed.rs:15:19 + | +LL | let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C)); + | ----------^^^^^^^^^^^^- --------------- move occurs because value has type `NC>`, which does not implement the `Copy` trait + | | | + | | value used here after move + | value moved here + +error[E0382]: use of moved value + --> $DIR/copy-and-move-mixed.rs:15:29 + | +LL | let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C)); + | ----------^- + | | | + | | value used here after move + | value moved here + | + = note: move occurs because value has type `NC`, which does not implement the `Copy` trait + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0007, E0382. +For more information about an error, try `rustc --explain E0007`. diff --git a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.rs b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.rs new file mode 100644 index 0000000000000..1127d114145cd --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.rs @@ -0,0 +1,37 @@ +// Ensures the independence of each side in `binding @ subpat` +// determine their binding modes independently of each other. +// +// That is, `binding` does not influence `subpat`. +// This is important because we might want to allow `p1 @ p2`, +// where both `p1` and `p2` are syntactically unrestricted patterns. +// If `binding` is allowed to influence `subpat`, +// this would create problems for the generalization aforementioned. + +#![feature(bindings_after_at)] + +fn main() { + struct NotCopy; + + fn f1(a @ b: &NotCopy) { // OK + let _: &NotCopy = a; + } + fn f2(ref a @ b: &NotCopy) { + let _: &&NotCopy = a; // Ok + } + + let a @ b = &NotCopy; // OK + let _: &NotCopy = a; + let ref a @ b = &NotCopy; // OK + let _: &&NotCopy = a; + + let ref a @ b = NotCopy; //~ ERROR cannot bind by-move and by-ref in the same pattern + let ref mut a @ b = NotCopy; //~ ERROR cannot bind by-move and by-ref in the same pattern + match Ok(NotCopy) { + Ok(ref a @ b) | Err(ref a @ b) => {} + //~^ ERROR cannot bind by-move and by-ref in the same pattern + } + match NotCopy { + ref a @ b => {} + //~^ ERROR cannot bind by-move and by-ref in the same pattern + } +} diff --git a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr new file mode 100644 index 0000000000000..b6709a8a40e23 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr @@ -0,0 +1,41 @@ +error[E0009]: cannot bind by-move and by-ref in the same pattern + --> $DIR/default-binding-modes-both-sides-independent.rs:27:17 + | +LL | let ref a @ b = NotCopy; + | --------^ + | | | + | | by-move pattern here + | by-ref pattern here + +error[E0009]: cannot bind by-move and by-ref in the same pattern + --> $DIR/default-binding-modes-both-sides-independent.rs:28:21 + | +LL | let ref mut a @ b = NotCopy; + | ------------^ + | | | + | | by-move pattern here + | by-ref pattern here + +error[E0009]: cannot bind by-move and by-ref in the same pattern + --> $DIR/default-binding-modes-both-sides-independent.rs:30:20 + | +LL | Ok(ref a @ b) | Err(ref a @ b) => {} + | --------^ --------^ + | | | | | + | | | | by-move pattern here + | | | by-ref pattern here + | | by-move pattern here + | by-ref pattern here + +error[E0009]: cannot bind by-move and by-ref in the same pattern + --> $DIR/default-binding-modes-both-sides-independent.rs:34:17 + | +LL | ref a @ b => {} + | --------^ + | | | + | | by-move pattern here + | by-ref pattern here + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0009`. diff --git a/src/test/ui/pattern/bindings-after-at/feature-gate-bindings_after_at.rs b/src/test/ui/pattern/bindings-after-at/feature-gate-bindings_after_at.rs new file mode 100644 index 0000000000000..d655f15af1eba --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/feature-gate-bindings_after_at.rs @@ -0,0 +1,3 @@ +fn main() { + let x @ y = 0; //~ ERROR pattern bindings after an `@` are unstable +} diff --git a/src/test/ui/pattern/bindings-after-at/feature-gate-bindings_after_at.stderr b/src/test/ui/pattern/bindings-after-at/feature-gate-bindings_after_at.stderr new file mode 100644 index 0000000000000..5408f6b5fb56d --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/feature-gate-bindings_after_at.stderr @@ -0,0 +1,12 @@ +error[E0658]: pattern bindings after an `@` are unstable + --> $DIR/feature-gate-bindings_after_at.rs:2:13 + | +LL | let x @ y = 0; + | ^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/65490 + = help: add `#![feature(bindings_after_at)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/pattern/bindings-after-at/nested-patterns.rs b/src/test/ui/pattern/bindings-after-at/nested-patterns.rs new file mode 100644 index 0000000000000..6296652c11212 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/nested-patterns.rs @@ -0,0 +1,15 @@ +// run-pass + +#![feature(bindings_after_at)] + +struct A { a: u8, b: u8 } + +pub fn main() { + match (A { a: 10, b: 20 }) { + ref x @ A { ref a, b: 20 } => { + assert_eq!(x.a, 10); + assert_eq!(*a, 10); + } + A { b: ref _b, .. } => panic!(), + } +} diff --git a/src/test/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.rs b/src/test/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.rs new file mode 100644 index 0000000000000..dbec2f135fbbe --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.rs @@ -0,0 +1,34 @@ +// Here we check that type ascription is syntactically invalid when +// not in the top position of a ascribing a let binding or function parameter. + +#![feature(bindings_after_at)] + +// This has no effect. +// We include it to demonstrate that this is the case: +#![feature(type_ascription)] + +fn main() {} + +fn _ok() { + let _a @ _b: u8 = 0; // OK. + fn _f(_a @ _b: u8) {} // OK. +} + +#[cfg(FALSE)] +fn case_1() { + let a: u8 @ b = 0; + //~^ ERROR expected one of `!` +} + +#[cfg(FALSE)] +fn case_2() { + let a @ (b: u8); + //~^ ERROR expected one of `!` + //~| ERROR expected one of `)` +} + +#[cfg(FALSE)] +fn case_3() { + let a: T1 @ Outer(b: T2); + //~^ ERROR expected one of `!` +} diff --git a/src/test/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.stderr b/src/test/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.stderr new file mode 100644 index 0000000000000..1e957ed06892c --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.stderr @@ -0,0 +1,26 @@ +error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `=`, found `@` + --> $DIR/nested-type-ascription-syntactically-invalid.rs:19:15 + | +LL | let a: u8 @ b = 0; + | ^ expected one of 7 possible tokens + +error: expected one of `)`, `,`, `@`, or `|`, found `:` + --> $DIR/nested-type-ascription-syntactically-invalid.rs:25:15 + | +LL | let a @ (b: u8); + | ^ expected one of `)`, `,`, `@`, or `|` + +error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `=`, found `)` + --> $DIR/nested-type-ascription-syntactically-invalid.rs:25:19 + | +LL | let a @ (b: u8); + | ^ expected one of 7 possible tokens + +error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `=`, found `@` + --> $DIR/nested-type-ascription-syntactically-invalid.rs:32:15 + | +LL | let a: T1 @ Outer(b: T2); + | ^ expected one of 7 possible tokens + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/pattern/bindings-after-at/pat-at-same-name-both.rs b/src/test/ui/pattern/bindings-after-at/pat-at-same-name-both.rs new file mode 100644 index 0000000000000..89ea2d5181945 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/pat-at-same-name-both.rs @@ -0,0 +1,32 @@ +// Test that `binding @ subpat` acts as a product context with respect to duplicate binding names. +// The code that is tested here lives in resolve (see `resolve_pattern_inner`). + +#![feature(bindings_after_at)] +#![feature(or_patterns)] +//~^ WARN the feature `or_patterns` is incomplete and may cause the compiler to crash + +fn main() { + fn f(a @ a @ a: ()) {} + //~^ ERROR identifier `a` is bound more than once in this parameter list + //~| ERROR identifier `a` is bound more than once in this parameter list + + match Ok(0) { + Ok(a @ b @ a) + //~^ ERROR identifier `a` is bound more than once in the same pattern + | Err(a @ b @ a) + //~^ ERROR identifier `a` is bound more than once in the same pattern + => {} + } + + let a @ a @ a = (); + //~^ ERROR identifier `a` is bound more than once in the same pattern + //~| ERROR identifier `a` is bound more than once in the same pattern + let ref a @ ref a = (); + //~^ ERROR identifier `a` is bound more than once in the same pattern + let ref mut a @ ref mut a = (); + //~^ ERROR identifier `a` is bound more than once in the same pattern + + let a @ (Ok(a) | Err(a)) = Ok(()); + //~^ ERROR identifier `a` is bound more than once in the same pattern + //~| ERROR identifier `a` is bound more than once in the same pattern +} diff --git a/src/test/ui/pattern/bindings-after-at/pat-at-same-name-both.stderr b/src/test/ui/pattern/bindings-after-at/pat-at-same-name-both.stderr new file mode 100644 index 0000000000000..c568d2a3aa2b8 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/pat-at-same-name-both.stderr @@ -0,0 +1,72 @@ +error[E0415]: identifier `a` is bound more than once in this parameter list + --> $DIR/pat-at-same-name-both.rs:9:14 + | +LL | fn f(a @ a @ a: ()) {} + | ^ used as parameter more than once + +error[E0415]: identifier `a` is bound more than once in this parameter list + --> $DIR/pat-at-same-name-both.rs:9:18 + | +LL | fn f(a @ a @ a: ()) {} + | ^ used as parameter more than once + +error[E0416]: identifier `a` is bound more than once in the same pattern + --> $DIR/pat-at-same-name-both.rs:14:20 + | +LL | Ok(a @ b @ a) + | ^ used in a pattern more than once + +error[E0416]: identifier `a` is bound more than once in the same pattern + --> $DIR/pat-at-same-name-both.rs:16:23 + | +LL | | Err(a @ b @ a) + | ^ used in a pattern more than once + +error[E0416]: identifier `a` is bound more than once in the same pattern + --> $DIR/pat-at-same-name-both.rs:21:13 + | +LL | let a @ a @ a = (); + | ^ used in a pattern more than once + +error[E0416]: identifier `a` is bound more than once in the same pattern + --> $DIR/pat-at-same-name-both.rs:21:17 + | +LL | let a @ a @ a = (); + | ^ used in a pattern more than once + +error[E0416]: identifier `a` is bound more than once in the same pattern + --> $DIR/pat-at-same-name-both.rs:24:21 + | +LL | let ref a @ ref a = (); + | ^ used in a pattern more than once + +error[E0416]: identifier `a` is bound more than once in the same pattern + --> $DIR/pat-at-same-name-both.rs:26:29 + | +LL | let ref mut a @ ref mut a = (); + | ^ used in a pattern more than once + +error[E0416]: identifier `a` is bound more than once in the same pattern + --> $DIR/pat-at-same-name-both.rs:29:17 + | +LL | let a @ (Ok(a) | Err(a)) = Ok(()); + | ^ used in a pattern more than once + +error[E0416]: identifier `a` is bound more than once in the same pattern + --> $DIR/pat-at-same-name-both.rs:29:26 + | +LL | let a @ (Ok(a) | Err(a)) = Ok(()); + | ^ used in a pattern more than once + +warning: the feature `or_patterns` is incomplete and may cause the compiler to crash + --> $DIR/pat-at-same-name-both.rs:5:12 + | +LL | #![feature(or_patterns)] + | ^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + +error: aborting due to 10 previous errors + +Some errors have detailed explanations: E0415, E0416. +For more information about an error, try `rustc --explain E0415`. diff --git a/src/test/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.rs b/src/test/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.rs new file mode 100644 index 0000000000000..50ac0ef27834e --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.rs @@ -0,0 +1,16 @@ +// Here we check that `_ @ sub` is syntactically invalid +// and comes with a nice actionable suggestion. + +fn main() {} + +#[cfg(FALSE)] +fn wild_before_at_is_bad_syntax() { + let _ @ a = 0; + //~^ ERROR pattern on wrong side of `@` + let _ @ ref a = 0; + //~^ ERROR pattern on wrong side of `@` + let _ @ ref mut a = 0; + //~^ ERROR pattern on wrong side of `@` + let _ @ (a, .., b) = (0, 1, 2, 3); + //~^ ERROR left-hand side of `@` must be a binding +} diff --git a/src/test/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.stderr b/src/test/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.stderr new file mode 100644 index 0000000000000..2f45415844d86 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.stderr @@ -0,0 +1,43 @@ +error: pattern on wrong side of `@` + --> $DIR/wild-before-at-syntactically-rejected.rs:8:9 + | +LL | let _ @ a = 0; + | -^^^- + | | | + | | binding on the right, should be on the left + | pattern on the left, should be on the right + | help: switch the order: `a @ _` + +error: pattern on wrong side of `@` + --> $DIR/wild-before-at-syntactically-rejected.rs:10:9 + | +LL | let _ @ ref a = 0; + | -^^^----- + | | | + | | binding on the right, should be on the left + | pattern on the left, should be on the right + | help: switch the order: `ref a @ _` + +error: pattern on wrong side of `@` + --> $DIR/wild-before-at-syntactically-rejected.rs:12:9 + | +LL | let _ @ ref mut a = 0; + | -^^^--------- + | | | + | | binding on the right, should be on the left + | pattern on the left, should be on the right + | help: switch the order: `ref mut a @ _` + +error: left-hand side of `@` must be a binding + --> $DIR/wild-before-at-syntactically-rejected.rs:14:9 + | +LL | let _ @ (a, .., b) = (0, 1, 2, 3); + | -^^^---------- + | | | + | | also a pattern + | interpreted as a pattern, not a binding + | + = note: bindings are `x`, `mut x`, `ref x`, and `ref mut x` + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/pattern/pattern-bindings-after-at.rs b/src/test/ui/pattern/pattern-bindings-after-at.rs deleted file mode 100644 index aff7264752de2..0000000000000 --- a/src/test/ui/pattern/pattern-bindings-after-at.rs +++ /dev/null @@ -1,16 +0,0 @@ -enum Option { - None, - Some(T), -} - -fn main() { - match &mut Some(1) { - ref mut z @ &mut Some(ref a) => { - //~^ ERROR pattern bindings are not allowed after an `@` - //~| ERROR cannot borrow `_` as immutable because it is also borrowed as mutable - **z = None; - println!("{}", *a); - } - _ => () - } -} diff --git a/src/test/ui/pattern/pattern-bindings-after-at.stderr b/src/test/ui/pattern/pattern-bindings-after-at.stderr deleted file mode 100644 index 35ee7877f2f78..0000000000000 --- a/src/test/ui/pattern/pattern-bindings-after-at.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error[E0303]: pattern bindings are not allowed after an `@` - --> $DIR/pattern-bindings-after-at.rs:8:31 - | -LL | ref mut z @ &mut Some(ref a) => { - | ^^^^^ not allowed after `@` - -error[E0502]: cannot borrow `_` as immutable because it is also borrowed as mutable - --> $DIR/pattern-bindings-after-at.rs:8:31 - | -LL | ref mut z @ &mut Some(ref a) => { - | ----------------------^^^^^- - | | | - | | immutable borrow occurs here - | mutable borrow occurs here -... -LL | **z = None; - | ---------- mutable borrow later used here - -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0303, E0502. -For more information about an error, try `rustc --explain E0303`. diff --git a/src/test/ui/rfc-2005-default-binding-mode/for.stderr b/src/test/ui/rfc-2005-default-binding-mode/for.stderr index 8a1ded1d5b94a..ebc6ff5d8c3fe 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/for.stderr +++ b/src/test/ui/rfc-2005-default-binding-mode/for.stderr @@ -4,7 +4,7 @@ error[E0009]: cannot bind by-move and by-ref in the same pattern LL | for (n, mut m) in &tups { | - ^^^^^ by-move pattern here | | - | both by-ref and by-move used + | by-ref pattern here error[E0507]: cannot move out of a shared reference --> $DIR/for.rs:6:23