Skip to content

Commit c66bd6f

Browse files
eddybbrson
authored andcommitted
rustc_typeck: do not overlap a borrow of TypeckTables with method lookup.
1 parent b28867f commit c66bd6f

File tree

2 files changed

+48
-2
lines changed

2 files changed

+48
-2
lines changed

src/librustc_typeck/check/method/confirm.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -446,9 +446,13 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
446446
// overloaded lvalue ops, and will be fixed by them in order to get
447447
// the correct region.
448448
let mut source = self.node_ty(expr.id);
449-
if let Some(adjustments) = self.tables.borrow_mut().adjustments.get_mut(&expr.id) {
449+
// Do not mutate adjustments in place, but rather take them,
450+
// and replace them after mutating them, to avoid having the
451+
// tables borrowed during (`deref_mut`) method resolution.
452+
let previous_adjustments = self.tables.borrow_mut().adjustments.remove(&expr.id);
453+
if let Some(mut adjustments) = previous_adjustments {
450454
let pref = LvaluePreference::PreferMutLvalue;
451-
for adjustment in adjustments {
455+
for adjustment in &mut adjustments {
452456
if let Adjust::Deref(Some(ref mut deref)) = adjustment.kind {
453457
if let Some(ok) = self.try_overloaded_deref(expr.span, source, pref) {
454458
let method = self.register_infer_ok_obligations(ok);
@@ -462,6 +466,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
462466
}
463467
source = adjustment.target;
464468
}
469+
self.tables.borrow_mut().adjustments.insert(expr.id, adjustments);
465470
}
466471

467472
match expr.node {

src/test/run-pass/issue-42463.rs

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use std::ops::{Deref, DerefMut};
12+
13+
struct CheckedDeref<T, F> {
14+
value: T,
15+
check: F
16+
}
17+
18+
impl<F: Fn(&T) -> bool, T> Deref for CheckedDeref<T, F> {
19+
type Target = T;
20+
fn deref(&self) -> &T {
21+
assert!((self.check)(&self.value));
22+
&self.value
23+
}
24+
}
25+
26+
impl<F: Fn(&T) -> bool, T> DerefMut for CheckedDeref<T, F> {
27+
fn deref_mut(&mut self) -> &mut T {
28+
assert!((self.check)(&self.value));
29+
&mut self.value
30+
}
31+
}
32+
33+
34+
fn main() {
35+
let mut v = CheckedDeref {
36+
value: vec![0],
37+
check: |v: &Vec<_>| !v.is_empty()
38+
};
39+
v.push(1);
40+
assert_eq!(*v, vec![0, 1]);
41+
}

0 commit comments

Comments
 (0)