diff options
| author | bors <bors@rust-lang.org> | 2019-12-23 21:49:44 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2019-12-23 21:49:44 +0000 |
| commit | a4cd03dee2b57216b5c95084a0b46de130946ad7 (patch) | |
| tree | f7b088dc1993e10a614283fbecc7a7bef4d6e552 /src | |
| parent | 9ae6cedb8d1e37469be1434642a3e403fce50a03 (diff) | |
| parent | acfe58272cb188e2da69d2bf1285bf2d954de9a2 (diff) | |
| download | rust-a4cd03dee2b57216b5c95084a0b46de130946ad7.tar.gz rust-a4cd03dee2b57216b5c95084a0b46de130946ad7.zip | |
Auto merge of #66296 - Centril:bindings_after_at-init, r=pnkfelix
Initial implementation of `#![feature(bindings_after_at)]` Following up on #16053, under the gate `#![feature(bindings_after_at)]`, `x @ Some(y)` is allowed subject to restrictions necessary for soundness. The implementation and test suite should be fairly complete now. One aspect that is not covered is the interaction with nested `#![feature(or_patterns)]`. This is not possible to test at the moment in a good way because that feature has not progressed sufficiently and has fatal errors in MIR building. We should make sure to add such tests before we stabilize both features (but shipping one of them is fine). r? @pnkfelix cc @nikomatsakis @matthewjasper @pcwalton cc https://github.com/rust-lang/rust/issues/65490
Diffstat (limited to 'src')
53 files changed, 2412 insertions, 187 deletions
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index bf95324d776..e955b7058e3 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 c0aa54beac2..8d3b464a8ff 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 0806e2d7765..e36b11ae005 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<BindingMode> { + 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 20a6c078f4f..700a66438e0 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 a386cbf56af..36664af8782 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 3b85a5d3c91..3a2a2dc412e 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 4ebf41fb9d2..67c89c7293c 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<Span> 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 9b5bf7e2378..1540e6d7c05 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 8abfc2981a6..149f27ed305 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 8ed8751f65c..5ef5f4c648e 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 6c7e3658365..f3f5e54edd1 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 7e0308ee356..8fdc199d9ed 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 9157fe0b070..ff00aa8caa8 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 d53547178db..3e8358da350 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 267a9dff926..00e0c70d649 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 cdda735ba44..022ac5fc113 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 89a6298c875..31af9171725 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<std::string::String>`, 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 f8acb9a09d9..446a436d647 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 af537ce5625..00000000000 --- 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 0032f60a221..9cb034e7592 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 00000000000..75d7af58e70 --- /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 00000000000..22d62ff4f00 --- /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 00000000000..86fb04e2edf --- /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<u8>); + +fn f(a @ A(u): A) -> Box<u8> { + //~^ 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 00000000000..b039708fd3e --- /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<u8> { + | ^^^^^^^^ 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<u8> { + | ------^- + | | | + | | 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 00000000000..1d9f341c514 --- /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 00000000000..f3f8fd655ce --- /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<main::U, main::U>`, 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<main::U, main::U>`, 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 00000000000..afac8d990b4 --- /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<C>) { // 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<NC>) { // 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<C, NC>; 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<C>, Box<NC>>; 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 00000000000..fce31409e16 --- /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<C>) {} + //~^ 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<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); + } + + 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 00000000000..5772fadd1e7 --- /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<C>) {} + | ^^^^^^^^^ 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<NC>) { + | ---------^^^^^^^----- + | | | + | | 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<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: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<C>`, 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<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[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<NC>) { + | ----------------^^^^^ + | | | + | | 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 00000000000..be19e5f2a85 --- /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>(A, B); + +enum E<A, B> { 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 index 0530d43b653..abe5ed81b71 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 00000000000..1f70a6c437e --- /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 00000000000..edf9fb31458 --- /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<U, U> = 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 00000000000..88eda9afec7 --- /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<T> { + 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 00000000000..b068a6125b6 --- /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<main::U, 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[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 00000000000..6b8b7545e68 --- /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 00000000000..1b5e6c74117 --- /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 00000000000..db5aabc7a14 --- /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>(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 00000000000..cfc35d6c32a --- /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<C, C>`, 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<C, NC<C, C>>`, 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<C, C>`, 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 00000000000..1127d114145 --- /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 00000000000..b6709a8a40e --- /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 00000000000..d655f15af1e --- /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 00000000000..5408f6b5fb5 --- /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 00000000000..6296652c112 --- /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 00000000000..dbec2f135fb --- /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 00000000000..1e957ed0689 --- /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 00000000000..89ea2d51819 --- /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 00000000000..c568d2a3aa2 --- /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 00000000000..50ac0ef2783 --- /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 00000000000..2f45415844d --- /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 aff7264752d..00000000000 --- a/src/test/ui/pattern/pattern-bindings-after-at.rs +++ /dev/null @@ -1,16 +0,0 @@ -enum Option<T> { - 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 35ee7877f2f..00000000000 --- 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 8a1ded1d5b9..ebc6ff5d8c3 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 |
