Skip to content

Commit 61f5ca7

Browse files
committed
Auto merge of #54703 - davidtwco:issue-52086, r=nikomatsakis
error message when trying to move from an Rc or Arc is ungreat Fixes #52086. r? @nikomatsakis
2 parents b8bea5a + 8c6d08b commit 61f5ca7

13 files changed

+216
-12
lines changed

src/doc/unstable-book/src/language-features/lang-items.md

+2
Original file line numberDiff line numberDiff line change
@@ -311,3 +311,5 @@ the source code.
311311
- `freeze`: `libcore/marker.rs`
312312
- `debug_trait`: `libcore/fmt/mod.rs`
313313
- `non_zero`: `libcore/nonzero.rs`
314+
- `arc`: `liballoc/sync.rs`
315+
- `rc`: `liballoc/rc.rs`

src/liballoc/rc.rs

+1
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@ struct RcBox<T: ?Sized> {
282282
/// type `T`.
283283
///
284284
/// [get_mut]: #method.get_mut
285+
#[cfg_attr(all(not(stage0), not(test)), lang = "rc")]
285286
#[stable(feature = "rust1", since = "1.0.0")]
286287
pub struct Rc<T: ?Sized> {
287288
ptr: NonNull<RcBox<T>>,

src/liballoc/sync.rs

+1
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ const MAX_REFCOUNT: usize = (isize::MAX) as usize;
199199
/// counting in general.
200200
///
201201
/// [rc_examples]: ../../std/rc/index.html#examples
202+
#[cfg_attr(all(not(stage0), not(test)), lang = "arc")]
202203
#[stable(feature = "rust1", since = "1.0.0")]
203204
pub struct Arc<T: ?Sized> {
204205
ptr: NonNull<ArcInner<T>>,

src/librustc/middle/lang_items.rs

+3
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,9 @@ language_item_table! {
362362
AlignOffsetLangItem, "align_offset", align_offset_fn;
363363

364364
TerminationTraitLangItem, "termination", termination;
365+
366+
Arc, "arc", arc;
367+
Rc, "rc", rc;
365368
}
366369

367370
impl<'a, 'tcx, 'gcx> TyCtxt<'a, 'tcx, 'gcx> {

src/librustc/ty/mod.rs

+21-1
Original file line numberDiff line numberDiff line change
@@ -1706,9 +1706,13 @@ bitflags! {
17061706
const IS_FUNDAMENTAL = 1 << 2;
17071707
const IS_UNION = 1 << 3;
17081708
const IS_BOX = 1 << 4;
1709+
/// Indicates whether the type is an `Arc`.
1710+
const IS_ARC = 1 << 5;
1711+
/// Indicates whether the type is an `Rc`.
1712+
const IS_RC = 1 << 6;
17091713
/// Indicates whether the variant list of this ADT is `#[non_exhaustive]`.
17101714
/// (i.e., this flag is never set unless this ADT is an enum).
1711-
const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 5;
1715+
const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 7;
17121716
}
17131717
}
17141718

@@ -2028,6 +2032,12 @@ impl<'a, 'gcx, 'tcx> AdtDef {
20282032
if Some(did) == tcx.lang_items().owned_box() {
20292033
flags = flags | AdtFlags::IS_BOX;
20302034
}
2035+
if Some(did) == tcx.lang_items().arc() {
2036+
flags = flags | AdtFlags::IS_ARC;
2037+
}
2038+
if Some(did) == tcx.lang_items().rc() {
2039+
flags = flags | AdtFlags::IS_RC;
2040+
}
20312041
if kind == AdtKind::Enum && tcx.has_attr(did, "non_exhaustive") {
20322042
debug!("found non-exhaustive variant list for {:?}", did);
20332043
flags = flags | AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE;
@@ -2106,6 +2116,16 @@ impl<'a, 'gcx, 'tcx> AdtDef {
21062116
self.flags.intersects(AdtFlags::IS_PHANTOM_DATA)
21072117
}
21082118

2119+
/// Returns `true` if this is `Arc<T>`.
2120+
pub fn is_arc(&self) -> bool {
2121+
self.flags.intersects(AdtFlags::IS_ARC)
2122+
}
2123+
2124+
/// Returns `true` if this is `Rc<T>`.
2125+
pub fn is_rc(&self) -> bool {
2126+
self.flags.intersects(AdtFlags::IS_RC)
2127+
}
2128+
21092129
/// Returns true if this is Box<T>.
21102130
#[inline]
21112131
pub fn is_box(&self) -> bool {

src/librustc/ty/sty.rs

+16
Original file line numberDiff line numberDiff line change
@@ -1602,6 +1602,22 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
16021602
}
16031603
}
16041604

1605+
/// Returns `true` if this type is an `Arc<T>`.
1606+
pub fn is_arc(&self) -> bool {
1607+
match self.sty {
1608+
Adt(def, _) => def.is_arc(),
1609+
_ => false,
1610+
}
1611+
}
1612+
1613+
/// Returns `true` if this type is an `Rc<T>`.
1614+
pub fn is_rc(&self) -> bool {
1615+
match self.sty {
1616+
Adt(def, _) => def.is_rc(),
1617+
_ => false,
1618+
}
1619+
}
1620+
16051621
pub fn is_box(&self) -> bool {
16061622
match self.sty {
16071623
Adt(def, _) => def.is_box(),

src/librustc_mir/borrow_check/move_errors.rs

+118-5
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,19 @@
99
// except according to those terms.
1010

1111
use core::unicode::property::Pattern_White_Space;
12+
use std::fmt::{self, Display};
13+
1214
use rustc::mir::*;
1315
use rustc::ty;
1416
use rustc_errors::{DiagnosticBuilder,Applicability};
1517
use syntax_pos::Span;
1618

1719
use borrow_check::MirBorrowckCtxt;
1820
use borrow_check::prefixes::PrefixSet;
19-
use dataflow::move_paths::{IllegalMoveOrigin, IllegalMoveOriginKind};
20-
use dataflow::move_paths::{LookupResult, MoveError, MovePathIndex};
21+
use dataflow::move_paths::{
22+
IllegalMoveOrigin, IllegalMoveOriginKind, InitLocation,
23+
LookupResult, MoveError, MovePathIndex,
24+
};
2125
use util::borrowck_errors::{BorrowckErrors, Origin};
2226

2327
// Often when desugaring a pattern match we may have many individual moves in
@@ -61,6 +65,22 @@ enum GroupedMoveError<'tcx> {
6165
},
6266
}
6367

68+
enum BorrowedContentSource {
69+
Arc,
70+
Rc,
71+
Other,
72+
}
73+
74+
impl Display for BorrowedContentSource {
75+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
76+
match *self {
77+
BorrowedContentSource::Arc => write!(f, "an `Arc`"),
78+
BorrowedContentSource::Rc => write!(f, "an `Rc`"),
79+
BorrowedContentSource::Other => write!(f, "borrowed content"),
80+
}
81+
}
82+
}
83+
6484
impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
6585
pub(crate) fn report_move_errors(&mut self, move_errors: Vec<(Place<'tcx>, MoveError<'tcx>)>) {
6686
let grouped_errors = self.group_move_errors(move_errors);
@@ -305,9 +325,12 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
305325

306326
diag
307327
}
308-
_ => self.infcx.tcx.cannot_move_out_of(
309-
span, "borrowed content", origin
310-
),
328+
_ => {
329+
let source = self.borrowed_content_source(place);
330+
self.infcx.tcx.cannot_move_out_of(
331+
span, &format!("{}", source), origin
332+
)
333+
},
311334
}
312335
}
313336
IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => {
@@ -471,4 +494,94 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
471494
);
472495
}
473496
}
497+
498+
fn borrowed_content_source(&self, place: &Place<'tcx>) -> BorrowedContentSource {
499+
// Look up the provided place and work out the move path index for it,
500+
// we'll use this to work back through where this value came from and check whether it
501+
// was originally part of an `Rc` or `Arc`.
502+
let initial_mpi = match self.move_data.rev_lookup.find(place) {
503+
LookupResult::Exact(mpi) | LookupResult::Parent(Some(mpi)) => mpi,
504+
_ => return BorrowedContentSource::Other,
505+
};
506+
507+
let mut queue = vec![initial_mpi];
508+
let mut visited = Vec::new();
509+
debug!("borrowed_content_source: queue={:?}", queue);
510+
while let Some(mpi) = queue.pop() {
511+
debug!(
512+
"borrowed_content_source: mpi={:?} queue={:?} visited={:?}",
513+
mpi, queue, visited
514+
);
515+
516+
// Don't visit the same path twice.
517+
if visited.contains(&mpi) {
518+
continue;
519+
}
520+
visited.push(mpi);
521+
522+
for i in &self.move_data.init_path_map[mpi] {
523+
let init = &self.move_data.inits[*i];
524+
debug!("borrowed_content_source: init={:?}", init);
525+
// We're only interested in statements that initialized a value, not the
526+
// initializations from arguments.
527+
let loc = match init.location {
528+
InitLocation::Statement(stmt) => stmt,
529+
_ => continue,
530+
};
531+
532+
let bbd = &self.mir[loc.block];
533+
let is_terminator = bbd.statements.len() == loc.statement_index;
534+
debug!("borrowed_content_source: loc={:?} is_terminator={:?}", loc, is_terminator);
535+
if !is_terminator {
536+
let stmt = &bbd.statements[loc.statement_index];
537+
debug!("borrowed_content_source: stmt={:?}", stmt);
538+
// We're only interested in assignments (in particular, where the
539+
// assignment came from - was it an `Rc` or `Arc`?).
540+
if let StatementKind::Assign(_, box Rvalue::Ref(_, _, source)) = &stmt.kind {
541+
let ty = source.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx);
542+
let ty = match ty.sty {
543+
ty::TyKind::Ref(_, ty, _) => ty,
544+
_ => ty,
545+
};
546+
debug!("borrowed_content_source: ty={:?}", ty);
547+
548+
if ty.is_arc() {
549+
return BorrowedContentSource::Arc;
550+
} else if ty.is_rc() {
551+
return BorrowedContentSource::Rc;
552+
} else {
553+
queue.push(init.path);
554+
}
555+
}
556+
} else if let Some(Terminator {
557+
kind: TerminatorKind::Call { args, .. },
558+
..
559+
}) = &bbd.terminator {
560+
for arg in args {
561+
let source = match arg {
562+
Operand::Copy(place) | Operand::Move(place) => place,
563+
_ => continue,
564+
};
565+
566+
let ty = source.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx);
567+
let ty = match ty.sty {
568+
ty::TyKind::Ref(_, ty, _) => ty,
569+
_ => ty,
570+
};
571+
debug!("borrowed_content_source: ty={:?}", ty);
572+
573+
if ty.is_arc() {
574+
return BorrowedContentSource::Arc;
575+
} else if ty.is_rc() {
576+
return BorrowedContentSource::Rc;
577+
} else {
578+
queue.push(init.path);
579+
}
580+
}
581+
}
582+
}
583+
}
584+
585+
BorrowedContentSource::Other
586+
}
474587
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0507]: cannot move out of an `Rc`
2+
--> $DIR/borrowck-move-out-of-overloaded-auto-deref.rs:17:14
3+
|
4+
LL | let _x = Rc::new(vec![1, 2]).into_iter();
5+
| ^^^^^^^^^^^^^^^^^^^ cannot move out of an `Rc`
6+
7+
error: aborting due to previous error
8+
9+
For more information about this error, try `rustc --explain E0507`.

src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.mir.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0507]: cannot move out of borrowed content
1+
error[E0507]: cannot move out of an `Rc`
22
--> $DIR/borrowck-move-out-of-overloaded-auto-deref.rs:17:14
33
|
44
LL | let _x = Rc::new(vec![1, 2]).into_iter();
5-
| ^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
5+
| ^^^^^^^^^^^^^^^^^^^ cannot move out of an `Rc`
66

77
error: aborting due to previous error
88

src/test/ui/borrowck/borrowck-move-out-of-overloaded-deref.nll.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
error[E0507]: cannot move out of borrowed content
1+
error[E0507]: cannot move out of an `Rc`
22
--> $DIR/borrowck-move-out-of-overloaded-deref.rs:14:14
33
|
44
LL | let _x = *Rc::new("hi".to_string());
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
66
| |
7-
| cannot move out of borrowed content
7+
| cannot move out of an `Rc`
88
| help: consider removing the `*`: `Rc::new("hi".to_string())`
99

1010
error: aborting due to previous error

src/test/ui/nll/issue-52086.rs

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
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+
#![feature(nll)]
12+
13+
use std::rc::Rc;
14+
use std::sync::Arc;
15+
16+
struct Bar { field: Vec<i32> }
17+
18+
fn main() {
19+
let x = Rc::new(Bar { field: vec![] });
20+
drop(x.field);
21+
22+
let y = Arc::new(Bar { field: vec![] });
23+
drop(y.field);
24+
}

src/test/ui/nll/issue-52086.stderr

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0507]: cannot move out of an `Rc`
2+
--> $DIR/issue-52086.rs:20:10
3+
|
4+
LL | drop(x.field);
5+
| ^^^^^^^ cannot move out of an `Rc`
6+
7+
error[E0507]: cannot move out of an `Arc`
8+
--> $DIR/issue-52086.rs:23:10
9+
|
10+
LL | drop(y.field);
11+
| ^^^^^^^ cannot move out of an `Arc`
12+
13+
error: aborting due to 2 previous errors
14+
15+
For more information about this error, try `rustc --explain E0507`.

src/test/ui/nll/move-errors.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,13 @@ LL | let s = **r;
2525
| cannot move out of borrowed content
2626
| help: consider removing the `*`: `*r`
2727

28-
error[E0507]: cannot move out of borrowed content
28+
error[E0507]: cannot move out of an `Rc`
2929
--> $DIR/move-errors.rs:40:13
3030
|
3131
LL | let s = *r;
3232
| ^^
3333
| |
34-
| cannot move out of borrowed content
34+
| cannot move out of an `Rc`
3535
| help: consider removing the `*`: `r`
3636

3737
error[E0508]: cannot move out of type `[A; 1]`, a non-copy array

0 commit comments

Comments
 (0)