From 8d8f6663a9ff0ef0df0e9fd6d7a225a6a0fec5f7 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 31 May 2018 10:17:51 -0400 Subject: [PATCH 1/3] change `PointerKind::Implicit` to a note `PointerKind` is included in `LoanPath` and hence forms part of the equality check; this led to having two unequal paths that both represent `*x`, depending on whether the `*` was inserted automatically or explicitly. Bad mojo. The `note` field, in contrast, is intended more-or-less primarily for this purpose of adding extra data. --- src/librustc/middle/expr_use_visitor.rs | 11 ++- src/librustc/middle/mem_categorization.rs | 94 +++++++++---------- src/librustc/traits/project.rs | 31 ++++-- .../borrowck/gather_loans/gather_moves.rs | 1 - .../borrowck/gather_loans/lifetime.rs | 4 +- .../borrowck/gather_loans/move_error.rs | 1 - .../borrowck/gather_loans/restrictions.rs | 2 +- src/librustc_typeck/check/_match.rs | 1 + src/librustc_typeck/check/regionck.rs | 1 - src/librustc_typeck/check/upvar.rs | 13 +-- src/test/ui/borrowck/issue-51117.rs | 25 +++++ src/test/ui/borrowck/issue-51117.stderr | 14 +++ 12 files changed, 128 insertions(+), 70 deletions(-) create mode 100644 src/test/ui/borrowck/issue-51117.rs create mode 100644 src/test/ui/borrowck/issue-51117.stderr diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 28524678e9916..a7e68d807d074 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -845,17 +845,24 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { /// established up front, e.g. via `determine_pat_move_mode` (see /// also `walk_irrefutable_pat` for patterns that stand alone). fn walk_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &hir::Pat, match_mode: MatchMode) { - debug!("walk_pat cmt_discr={:?} pat={:?}", cmt_discr, pat); + debug!("walk_pat(cmt_discr={:?}, pat={:?})", cmt_discr, pat); let ExprUseVisitor { ref mc, ref mut delegate, param_env } = *self; return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |cmt_pat, pat| { if let PatKind::Binding(_, canonical_id, ..) = pat.node { - debug!("binding cmt_pat={:?} pat={:?} match_mode={:?}", cmt_pat, pat, match_mode); + debug!( + "walk_pat: binding cmt_pat={:?} pat={:?} match_mode={:?}", + cmt_pat, + pat, + match_mode, + ); let bm = *mc.tables.pat_binding_modes().get(pat.hir_id) .expect("missing binding mode"); + debug!("walk_pat: pat.hir_id={:?} bm={:?}", pat.hir_id, bm); // pat_ty: the type of the binding being produced. let pat_ty = return_if_err!(mc.node_ty(pat.hir_id)); + debug!("walk_pat: pat_ty={:?}", pat_ty); // Each match binding is effectively an assignment to the // binding being produced. diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 5875e5e4097af..4aaa791cc2e2e 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -95,7 +95,7 @@ pub enum Categorization<'tcx> { StaticItem, Upvar(Upvar), // upvar referenced by closure env Local(ast::NodeId), // local variable - Deref(cmt<'tcx>, PointerKind<'tcx>), // deref of a ptr + Deref(cmt<'tcx>, PointerKind<'tcx>), // deref of a ptr Interior(cmt<'tcx>, InteriorKind), // something interior: field, tuple, etc Downcast(cmt<'tcx>, DefId), // selects a particular enum variant (*1) @@ -120,9 +120,6 @@ pub enum PointerKind<'tcx> { /// `*T` UnsafePtr(hir::Mutability), - - /// Implicit deref of the `&T` that results from an overloaded index `[]`. - Implicit(ty::BorrowKind, ty::Region<'tcx>), } // We use the term "interior" to mean "something reachable from the @@ -161,6 +158,7 @@ pub enum MutabilityCategory { pub enum Note { NoteClosureEnv(ty::UpvarId), // Deref through closure env NoteUpvarRef(ty::UpvarId), // Deref through by-ref upvar + NoteIndex, // Deref as part of desugaring `x[]` into its two components NoteNone // Nothing special } @@ -224,8 +222,7 @@ impl<'tcx> cmt_<'tcx> { pub fn immutability_blame(&self) -> Option> { match self.cat { - Categorization::Deref(ref base_cmt, BorrowedPtr(ty::ImmBorrow, _)) | - Categorization::Deref(ref base_cmt, Implicit(ty::ImmBorrow, _)) => { + Categorization::Deref(ref base_cmt, BorrowedPtr(ty::ImmBorrow, _)) => { // try to figure out where the immutable reference came from match base_cmt.cat { Categorization::Local(node_id) => @@ -321,7 +318,7 @@ impl MutabilityCategory { Unique => { base_mutbl.inherit() } - BorrowedPtr(borrow_kind, _) | Implicit(borrow_kind, _) => { + BorrowedPtr(borrow_kind, _) => { MutabilityCategory::from_borrow_kind(borrow_kind) } UnsafePtr(m) => { @@ -610,7 +607,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } else { previous()? }; - self.cat_deref(expr, base, false) + self.cat_deref(expr, base, NoteNone) } adjustment::Adjust::NeverToAny | @@ -633,10 +630,10 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { match expr.node { hir::ExprUnary(hir::UnDeref, ref e_base) => { if self.tables.is_method_call(expr) { - self.cat_overloaded_place(expr, e_base, false) + self.cat_overloaded_place(expr, e_base, NoteNone) } else { let base_cmt = self.cat_expr(&e_base)?; - self.cat_deref(expr, base_cmt, false) + self.cat_deref(expr, base_cmt, NoteNone) } } @@ -661,7 +658,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // The call to index() returns a `&T` value, which // is an rvalue. That is what we will be // dereferencing. - self.cat_overloaded_place(expr, base, true) + self.cat_overloaded_place(expr, base, NoteIndex) } else { let base_cmt = self.cat_expr(&base)?; self.cat_index(expr, base_cmt, expr_ty, InteriorOffsetKind::Index) @@ -1012,12 +1009,18 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { ret } - fn cat_overloaded_place(&self, - expr: &hir::Expr, - base: &hir::Expr, - implicit: bool) - -> McResult> { - debug!("cat_overloaded_place: implicit={}", implicit); + fn cat_overloaded_place( + &self, + expr: &hir::Expr, + base: &hir::Expr, + note: Note, + ) -> McResult> { + debug!( + "cat_overloaded_place(expr={:?}, base={:?}, note={:?})", + expr, + base, + note, + ); // Reconstruct the output assuming it's a reference with the // same region and mutability as the receiver. This holds for @@ -1037,14 +1040,15 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { }); let base_cmt = self.cat_rvalue_node(expr.id, expr.span, ref_ty); - self.cat_deref(expr, base_cmt, implicit) + self.cat_deref(expr, base_cmt, note) } - pub fn cat_deref(&self, - node: &N, - base_cmt: cmt<'tcx>, - implicit: bool) - -> McResult> { + pub fn cat_deref( + &self, + node: &impl ast_node, + base_cmt: cmt<'tcx>, + note: Note, + ) -> McResult> { debug!("cat_deref: base_cmt={:?}", base_cmt); let base_cmt_ty = base_cmt.ty; @@ -1060,9 +1064,9 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { let ptr = match base_cmt.ty.sty { ty::TyAdt(def, ..) if def.is_box() => Unique, ty::TyRawPtr(ref mt) => UnsafePtr(mt.mutbl), - ty::TyRef(r, mt) => { - let bk = ty::BorrowKind::from_mutbl(mt.mutbl); - if implicit { Implicit(bk, r) } else { BorrowedPtr(bk, r) } + ty::TyRef(r, ty) => { + let bk = ty::BorrowKind::from_mutbl(ty.mutbl); + BorrowedPtr(bk, r) } ref ty => bug!("unexpected type in cat_deref: {:?}", ty) }; @@ -1073,7 +1077,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { mutbl: MutabilityCategory::from_pointer_kind(base_cmt.mutbl, ptr), cat: Categorization::Deref(base_cmt, ptr), ty: deref_ty, - note: NoteNone + note: note, }); debug!("cat_deref ret {:?}", ret); Ok(ret) @@ -1207,7 +1211,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // step out of sync again. So you'll see below that we always // get the type of the *subpattern* and use that. - debug!("cat_pattern: {:?} cmt={:?}", pat, cmt); + debug!("cat_pattern(pat={:?}, cmt={:?})", pat, cmt); // If (pattern) adjustments are active for this pattern, adjust the `cmt` correspondingly. // `cmt`s are constructed differently from patterns. For example, in @@ -1245,10 +1249,13 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { .pat_adjustments() .get(pat.hir_id) .map(|v| v.len()) - .unwrap_or(0) { - cmt = self.cat_deref(pat, cmt, true /* implicit */)?; + .unwrap_or(0) + { + debug!("cat_pattern: applying adjustment to cmt={:?}", cmt); + cmt = self.cat_deref(pat, cmt, NoteNone)?; } let cmt = cmt; // lose mutability + debug!("cat_pattern: applied adjustment derefs to get cmt={:?}", cmt); // Invoke the callback, but only now, after the `cmt` has adjusted. // @@ -1342,7 +1349,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // box p1, &p1, &mut p1. we can ignore the mutability of // PatKind::Ref since that information is already contained // in the type. - let subcmt = self.cat_deref(pat, cmt, false)?; + let subcmt = self.cat_deref(pat, cmt, NoteNone)?; self.cat_pattern_(subcmt, &subpat, op)?; } @@ -1403,7 +1410,6 @@ impl<'tcx> cmt_<'tcx> { Categorization::Local(..) | Categorization::Deref(_, UnsafePtr(..)) | Categorization::Deref(_, BorrowedPtr(..)) | - Categorization::Deref(_, Implicit(..)) | Categorization::Upvar(..) => { Rc::new((*self).clone()) } @@ -1423,9 +1429,7 @@ impl<'tcx> cmt_<'tcx> { match self.cat { Categorization::Deref(ref b, BorrowedPtr(ty::MutBorrow, _)) | - Categorization::Deref(ref b, Implicit(ty::MutBorrow, _)) | Categorization::Deref(ref b, BorrowedPtr(ty::UniqueImmBorrow, _)) | - Categorization::Deref(ref b, Implicit(ty::UniqueImmBorrow, _)) | Categorization::Deref(ref b, Unique) | Categorization::Downcast(ref b, _) | Categorization::Interior(ref b, _) => { @@ -1448,8 +1452,7 @@ impl<'tcx> cmt_<'tcx> { } } - Categorization::Deref(_, BorrowedPtr(ty::ImmBorrow, _)) | - Categorization::Deref(_, Implicit(ty::ImmBorrow, _)) => { + Categorization::Deref(_, BorrowedPtr(ty::ImmBorrow, _)) => { FreelyAliasable(AliasableBorrowed) } } @@ -1471,7 +1474,7 @@ impl<'tcx> cmt_<'tcx> { _ => bug!() }) } - NoteNone => None + NoteIndex | NoteNone => None } } @@ -1500,9 +1503,6 @@ impl<'tcx> cmt_<'tcx> { Some(_) => bug!(), None => { match pk { - Implicit(..) => { - format!("indexed content") - } Unique => { format!("`Box` content") } @@ -1510,7 +1510,10 @@ impl<'tcx> cmt_<'tcx> { format!("dereference of raw pointer") } BorrowedPtr(..) => { - format!("borrowed content") + match self.note { + NoteIndex => format!("indexed content"), + _ => format!("borrowed content"), + } } } } @@ -1541,12 +1544,9 @@ impl<'tcx> cmt_<'tcx> { pub fn ptr_sigil(ptr: PointerKind) -> &'static str { match ptr { Unique => "Box", - BorrowedPtr(ty::ImmBorrow, _) | - Implicit(ty::ImmBorrow, _) => "&", - BorrowedPtr(ty::MutBorrow, _) | - Implicit(ty::MutBorrow, _) => "&mut", - BorrowedPtr(ty::UniqueImmBorrow, _) | - Implicit(ty::UniqueImmBorrow, _) => "&unique", + BorrowedPtr(ty::ImmBorrow, _) => "&", + BorrowedPtr(ty::MutBorrow, _) => "&mut", + BorrowedPtr(ty::UniqueImmBorrow, _) => "&unique", UnsafePtr(_) => "*", } } diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index de336c2922940..441089250a130 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -137,17 +137,30 @@ impl<'tcx> ProjectionTyCandidateSet<'tcx> { fn push_candidate(&mut self, candidate: ProjectionTyCandidate<'tcx>) -> bool { use self::ProjectionTyCandidateSet::*; use self::ProjectionTyCandidate::*; + + // This wacky variable is just used to try and + // make code readable and avoid confusing paths. + // It is assigned a "value" of `()` only on those + // paths in which we wish to convert `*self` to + // ambiguous (and return false, because the candidate + // was not used). On other paths, it is not assigned, + // and hence if those paths *could* reach the code that + // comes after the match, this fn would not compile. + let convert_to_ambigious; + match self { None => { *self = Single(candidate); - true + return true; } + Single(current) => { // Duplicates can happen inside ParamEnv. In the case, we // perform a lazy deduplication. if current == &candidate { return false; } + // Prefer where-clauses. As in select, if there are multiple // candidates, we prefer where-clause candidates over impls. This // may seem a bit surprising, since impls are the source of @@ -156,17 +169,23 @@ impl<'tcx> ProjectionTyCandidateSet<'tcx> { // clauses are the safer choice. See the comment on // `select::SelectionCandidate` and #21974 for more details. match (current, candidate) { - (ParamEnv(..), ParamEnv(..)) => { *self = Ambiguous; } - (ParamEnv(..), _) => {} + (ParamEnv(..), ParamEnv(..)) => convert_to_ambigious = (), + (ParamEnv(..), _) => return false, (_, ParamEnv(..)) => { unreachable!(); } - (_, _) => { *self = Ambiguous; } + (_, _) => convert_to_ambigious = (), } - false } + Ambiguous | Error(..) => { - false + return false; } } + + // We only ever get here when we moved from a single candidate + // to ambiguous. + let () = convert_to_ambigious; + *self = Ambiguous; + false } } diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs index 465457f5ab39a..766c38160ee6d 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs @@ -181,7 +181,6 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, -> Option> { match cmt.cat { Categorization::Deref(_, mc::BorrowedPtr(..)) | - Categorization::Deref(_, mc::Implicit(..)) | Categorization::Deref(_, mc::UnsafePtr(..)) | Categorization::StaticItem => { Some(cmt.clone()) diff --git a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs index 97fa94b5e5cf9..d7bd4762e1ab9 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs @@ -75,7 +75,6 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { Categorization::Local(..) | // L-Local Categorization::Upvar(..) | Categorization::Deref(_, mc::BorrowedPtr(..)) | // L-Deref-Borrowed - Categorization::Deref(_, mc::Implicit(..)) | Categorization::Deref(_, mc::UnsafePtr(..)) => { self.check_scope(self.scope(cmt)) } @@ -123,8 +122,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { Categorization::Deref(_, mc::UnsafePtr(..)) => { self.bccx.tcx.types.re_static } - Categorization::Deref(_, mc::BorrowedPtr(_, r)) | - Categorization::Deref(_, mc::Implicit(_, r)) => { + Categorization::Deref(_, mc::BorrowedPtr(_, r)) => { r } Categorization::Downcast(ref cmt, _) | diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index 1f2b917bdb994..18026a14259de 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -140,7 +140,6 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &'a BorrowckCtxt<'a, 'tcx>, -> DiagnosticBuilder<'a> { match move_from.cat { Categorization::Deref(_, mc::BorrowedPtr(..)) | - Categorization::Deref(_, mc::Implicit(..)) | Categorization::Deref(_, mc::UnsafePtr(..)) | Categorization::StaticItem => { bccx.cannot_move_out_of( diff --git a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs index 5cfbe49f77f11..fc502978685df 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs @@ -147,7 +147,7 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> { let result = self.restrict(cmt_base); self.extend(result, &cmt, LpDeref(pk)) } - mc::Implicit(bk, lt) | mc::BorrowedPtr(bk, lt) => { + mc::BorrowedPtr(bk, lt) => { // R-Deref-[Mut-]Borrowed if !self.bccx.is_subregion_of(self.loan_region, lt) { self.bccx.report( diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index ae373fbad2246..35870432d82ac 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -236,6 +236,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .borrow_mut() .pat_binding_modes_mut() .insert(pat.hir_id, bm); + debug!("check_pat_walk: pat.hir_id={:?} bm={:?}", pat.hir_id, bm); let typ = self.local_ty(pat.span, pat.id); match bm { ty::BindByReference(mutbl) => { diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 9ed4ab45a1ba7..4e9dbd52e5e63 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -1114,7 +1114,6 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { borrow_kind, borrow_cmt); match borrow_cmt.cat.clone() { - Categorization::Deref(ref_cmt, mc::Implicit(ref_kind, ref_region)) | Categorization::Deref(ref_cmt, mc::BorrowedPtr(ref_kind, ref_region)) => { match self.link_reborrowed_region(span, borrow_region, borrow_kind, diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 4fc3344dab2a9..56e088fcb227f 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -328,8 +328,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { guarantor.cat ); match guarantor.cat { - Categorization::Deref(_, mc::BorrowedPtr(..)) | - Categorization::Deref(_, mc::Implicit(..)) => { + Categorization::Deref(_, mc::BorrowedPtr(..)) => { debug!( "adjust_upvar_borrow_kind_for_consume: found deref with note {:?}", cmt.note @@ -367,7 +366,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { var_name(tcx, upvar_id.var_id), ); } - mc::NoteNone => {} + mc::NoteIndex | mc::NoteNone => {} } } _ => {} @@ -389,8 +388,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { self.adjust_upvar_borrow_kind_for_mut(base); } - Categorization::Deref(base, mc::BorrowedPtr(..)) | - Categorization::Deref(base, mc::Implicit(..)) => { + Categorization::Deref(base, mc::BorrowedPtr(..)) => { if !self.try_adjust_upvar_deref(cmt, ty::MutBorrow) { // assignment to deref of an `&mut` // borrowed pointer implies that the @@ -422,8 +420,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { self.adjust_upvar_borrow_kind_for_unique(base); } - Categorization::Deref(base, mc::BorrowedPtr(..)) | - Categorization::Deref(base, mc::Implicit(..)) => { + Categorization::Deref(base, mc::BorrowedPtr(..)) => { if !self.try_adjust_upvar_deref(cmt, ty::UniqueImmBorrow) { // for a borrowed pointer to be unique, its // base must be unique @@ -481,7 +478,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { true } - mc::NoteNone => false, + mc::NoteIndex | mc::NoteNone => false, } } diff --git a/src/test/ui/borrowck/issue-51117.rs b/src/test/ui/borrowck/issue-51117.rs new file mode 100644 index 0000000000000..0a1e672b57761 --- /dev/null +++ b/src/test/ui/borrowck/issue-51117.rs @@ -0,0 +1,25 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Regression test for #51117 in borrowck interaction with match +// default bindings. The borrow of `*bar` created by `baz` was failing +// to register as a conflict with `bar.take()`. + +fn main() { + let mut foo = Some("foo".to_string()); + let bar = &mut foo; + match bar { + Some(baz) => { + bar.take(); //~ ERROR cannot borrow + drop(baz); + }, + None => unreachable!(), + } +} diff --git a/src/test/ui/borrowck/issue-51117.stderr b/src/test/ui/borrowck/issue-51117.stderr new file mode 100644 index 0000000000000..cb434f9b322fe --- /dev/null +++ b/src/test/ui/borrowck/issue-51117.stderr @@ -0,0 +1,14 @@ +error[E0499]: cannot borrow `*bar` as mutable more than once at a time + --> $DIR/issue-51117.rs:20:13 + | +LL | Some(baz) => { + | --- first mutable borrow occurs here +LL | bar.take(); //~ ERROR cannot borrow + | ^^^ second mutable borrow occurs here +... +LL | } + | - first borrow ends here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0499`. From 406d54d534970cd86236be32cbb949e4245c47e1 Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Thu, 31 May 2018 14:38:25 -0600 Subject: [PATCH 2/3] Update release notes for 1.26.2 --- RELEASES.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index 758de62a84823..0403a2ac1feb3 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,13 @@ +Version 1.26.2 (2018-06-05) +========================== + +Compatibility Notes +------------------- + +- [The borrow checker was fixed to avoid unsoundness when using match ergonomics][51117] + +[51117]: https://github.com/rust-lang/rust/issues/51117 + Version 1.26.1 (2018-05-29) ========================== From 7093b11690486e5fd3502b299b5477a83fd3b001 Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Thu, 31 May 2018 14:38:44 -0600 Subject: [PATCH 3/3] Update version to 1.26.2 --- src/bootstrap/channel.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/channel.rs b/src/bootstrap/channel.rs index 6b25a130ae024..fae79730669a6 100644 --- a/src/bootstrap/channel.rs +++ b/src/bootstrap/channel.rs @@ -24,7 +24,7 @@ use Build; use config::Config; // The version number -pub const CFG_RELEASE_NUM: &str = "1.26.1"; +pub const CFG_RELEASE_NUM: &str = "1.26.2"; pub struct GitInfo { inner: Option,