Skip to content

Commit 0b72d48

Browse files
committed
Auto merge of #48914 - gaurikholkar:e0389, r=nikomatsakis
Modify compile-fail/E0389 error message WIP This fixes #47388 cc @nikomatsakis @estebank r? @nikomatsakis Certain ui tests were failing locally. I'll check if the same happens here too.
2 parents b2a7b94 + c792d1e commit 0b72d48

File tree

8 files changed

+182
-24
lines changed

8 files changed

+182
-24
lines changed

src/librustc_mir/borrow_check/mod.rs

+79-22
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ use dataflow::indexes::BorrowIndex;
4242
use dataflow::move_paths::{IllegalMoveOriginKind, MoveError};
4343
use dataflow::move_paths::{HasMoveData, LookupResult, MoveData, MovePathIndex};
4444
use util::borrowck_errors::{BorrowckErrors, Origin};
45+
use util::collect_writes::FindAssignments;
4546

4647
use std::iter;
4748

@@ -1550,6 +1551,36 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
15501551
}
15511552
}
15521553

1554+
fn specialized_description(&self, place:&Place<'tcx>) -> Option<String>{
1555+
if let Some(_name) = self.describe_place(place) {
1556+
Some(format!("data in a `&` reference"))
1557+
} else {
1558+
None
1559+
}
1560+
}
1561+
1562+
fn get_default_err_msg(&self, place:&Place<'tcx>) -> String{
1563+
match self.describe_place(place) {
1564+
Some(name) => format!("immutable item `{}`", name),
1565+
None => "immutable item".to_owned(),
1566+
}
1567+
}
1568+
1569+
fn get_secondary_err_msg(&self, place:&Place<'tcx>) -> String{
1570+
match self.specialized_description(place) {
1571+
Some(_) => format!("data in a `&` reference"),
1572+
None => self.get_default_err_msg(place)
1573+
}
1574+
}
1575+
1576+
fn get_primary_err_msg(&self, place:&Place<'tcx>) -> String{
1577+
if let Some(name) = self.describe_place(place) {
1578+
format!("`{}` is a `&` reference, so the data it refers to cannot be written", name)
1579+
} else {
1580+
format!("cannot assign through `&`-reference")
1581+
}
1582+
}
1583+
15531584
/// Check the permissions for the given place and read or write kind
15541585
///
15551586
/// Returns true if an error is reported, false otherwise.
@@ -1576,43 +1607,70 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
15761607
self.is_mutable(place, is_local_mutation_allowed)
15771608
{
15781609
error_reported = true;
1579-
1580-
let item_msg = match self.describe_place(place) {
1581-
Some(name) => format!("immutable item `{}`", name),
1582-
None => "immutable item".to_owned(),
1583-
};
1584-
1610+
let item_msg = self.get_default_err_msg(place);
15851611
let mut err = self.tcx
15861612
.cannot_borrow_path_as_mutable(span, &item_msg, Origin::Mir);
15871613
err.span_label(span, "cannot borrow as mutable");
15881614

15891615
if place != place_err {
15901616
if let Some(name) = self.describe_place(place_err) {
1591-
err.note(&format!("Value not mutable causing this error: `{}`", name));
1617+
err.note(&format!("the value which is causing this path not to be mutable \
1618+
is...: `{}`", name));
15921619
}
15931620
}
15941621

15951622
err.emit();
15961623
},
15971624
Reservation(WriteKind::Mutate) | Write(WriteKind::Mutate) => {
1625+
15981626
if let Err(place_err) = self.is_mutable(place, is_local_mutation_allowed) {
15991627
error_reported = true;
1628+
let mut err_info = None;
1629+
match *place_err {
1630+
1631+
Place::Projection(box Projection {
1632+
ref base, elem:ProjectionElem::Deref}) => {
1633+
match *base {
1634+
Place::Local(local) => {
1635+
let locations = self.mir.find_assignments(local);
1636+
if locations.len() > 0 {
1637+
let item_msg = if error_reported {
1638+
self.get_secondary_err_msg(base)
1639+
} else {
1640+
self.get_default_err_msg(place)
1641+
};
1642+
err_info = Some((
1643+
self.mir.source_info(locations[0]).span,
1644+
"consider changing this to be a \
1645+
mutable reference: `&mut`", item_msg,
1646+
self.get_primary_err_msg(base)));
1647+
}
1648+
},
1649+
_ => {},
1650+
}
1651+
},
1652+
_ => {},
1653+
}
16001654

1601-
let item_msg = match self.describe_place(place) {
1602-
Some(name) => format!("immutable item `{}`", name),
1603-
None => "immutable item".to_owned(),
1604-
};
1605-
1606-
let mut err = self.tcx.cannot_assign(span, &item_msg, Origin::Mir);
1607-
err.span_label(span, "cannot mutate");
1608-
1609-
if place != place_err {
1610-
if let Some(name) = self.describe_place(place_err) {
1611-
err.note(&format!("Value not mutable causing this error: `{}`", name));
1655+
if let Some((err_help_span, err_help_stmt, item_msg, sec_span)) = err_info {
1656+
let mut err = self.tcx.cannot_assign(span, &item_msg, Origin::Mir);
1657+
err.span_suggestion(err_help_span, err_help_stmt, format!(""));
1658+
if place != place_err {
1659+
err.span_label(span, sec_span);
16121660
}
1661+
err.emit()
1662+
} else {
1663+
let item_msg_ = self.get_default_err_msg(place);
1664+
let mut err = self.tcx.cannot_assign(span, &item_msg_, Origin::Mir);
1665+
err.span_label(span, "cannot mutate");
1666+
if place != place_err {
1667+
if let Some(name) = self.describe_place(place_err) {
1668+
err.note(&format!("the value which is causing this path not to be \
1669+
mutable is...: `{}`", name));
1670+
}
1671+
}
1672+
err.emit();
16131673
}
1614-
1615-
err.emit();
16161674
}
16171675
}
16181676
Reservation(WriteKind::Move)
@@ -1631,9 +1689,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
16311689
);
16321690
}
16331691
}
1634-
16351692
Activation(..) => {} // permission checks are done at Reservation point.
1636-
16371693
Read(ReadKind::Borrow(BorrowKind::Unique))
16381694
| Read(ReadKind::Borrow(BorrowKind::Mut { .. }))
16391695
| Read(ReadKind::Borrow(BorrowKind::Shared))
@@ -2255,3 +2311,4 @@ impl ContextKind {
22552311
}
22562312
}
22572313
}
2314+

src/librustc_mir/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
3232
#![feature(rustc_diagnostic_macros)]
3333
#![feature(nonzero)]
3434
#![feature(inclusive_range_fields)]
35+
#![feature(crate_visibility_modifier)]
3536

3637
extern crate arena;
3738
#[macro_use]

src/librustc_mir/util/borrowck_errors.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,8 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
284284
self.cancel_if_wrong_origin(err, o)
285285
}
286286

287-
fn cannot_assign(self, span: Span, desc: &str, o: Origin) -> DiagnosticBuilder<'cx>
287+
fn cannot_assign(self, span: Span, desc: &str, o: Origin)
288+
-> DiagnosticBuilder<'cx>
288289
{
289290
let err = struct_span_err!(self, span, E0594,
290291
"cannot assign to {}{OGN}",
+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// Copyright 2018 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 rustc::mir::{Local, Location};
12+
use rustc::mir::Mir;
13+
use rustc::mir::visit::PlaceContext;
14+
use rustc::mir::visit::Visitor;
15+
16+
crate trait FindAssignments {
17+
// Finds all statements that assign directly to local (i.e., X = ...)
18+
// and returns their locations.
19+
fn find_assignments(&self, local: Local) -> Vec<Location>;
20+
}
21+
22+
impl<'tcx> FindAssignments for Mir<'tcx>{
23+
fn find_assignments(&self, local: Local) -> Vec<Location>{
24+
let mut visitor = FindLocalAssignmentVisitor{ needle: local, locations: vec![]};
25+
visitor.visit_mir(self);
26+
visitor.locations
27+
}
28+
}
29+
30+
// The Visitor walks the MIR to return the assignment statements corresponding
31+
// to a Local.
32+
struct FindLocalAssignmentVisitor {
33+
needle: Local,
34+
locations: Vec<Location>,
35+
}
36+
37+
impl<'tcx> Visitor<'tcx> for FindLocalAssignmentVisitor {
38+
fn visit_local(&mut self,
39+
local: &Local,
40+
place_context: PlaceContext<'tcx>,
41+
location: Location) {
42+
if self.needle != *local {
43+
return;
44+
}
45+
46+
match place_context {
47+
PlaceContext::Store | PlaceContext::Call => {
48+
self.locations.push(location);
49+
}
50+
PlaceContext::AsmOutput |
51+
PlaceContext::Drop |
52+
PlaceContext::Inspect |
53+
PlaceContext::Borrow { .. } |
54+
PlaceContext::Projection(..) |
55+
PlaceContext::Copy |
56+
PlaceContext::Move |
57+
PlaceContext::StorageLive |
58+
PlaceContext::StorageDead |
59+
PlaceContext::Validate => {
60+
// TO-DO
61+
// self.super_local(local)
62+
}
63+
}
64+
}
65+
// TO-DO
66+
// fn super_local()
67+
}

src/librustc_mir/util/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ mod alignment;
1717
mod graphviz;
1818
pub(crate) mod pretty;
1919
pub mod liveness;
20+
pub mod collect_writes;
2021

2122
pub use self::alignment::is_disaligned;
2223
pub use self::pretty::{dump_enabled, dump_mir, write_mir_pretty, PassWhere};

src/test/compile-fail/borrowck/borrowck-issue-14498.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ fn indirect_write_to_imm_box() {
2727
let y: Box<_> = box &mut x;
2828
let p = &y;
2929
***p = 2; //[ast]~ ERROR cannot assign to data in a `&` reference
30-
//[mir]~^ ERROR cannot assign to immutable item `***p`
30+
//[mir]~^ ERROR cannot assign to data in a `&` reference
3131
drop(p);
3232
}
3333

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

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2018 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+
#![feature(nll)]
11+
struct FancyNum {
12+
num: u8,
13+
}
14+
15+
fn main() {
16+
let mut fancy = FancyNum{ num: 5 };
17+
let fancy_ref = &(&mut fancy);
18+
fancy_ref.num = 6; //~ ERROR E0594
19+
println!("{}", fancy_ref.num);
20+
}

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

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0594]: cannot assign to data in a `&` reference
2+
--> $DIR/issue-47388.rs:18:5
3+
|
4+
LL | let fancy_ref = &(&mut fancy);
5+
| ------------- help: consider changing this to be a mutable reference: `&mut`
6+
LL | fancy_ref.num = 6; //~ ERROR E0594
7+
| ^^^^^^^^^^^^^^^^^ `fancy_ref` is a `&` reference, so the data it refers to cannot be written
8+
9+
error: aborting due to previous error
10+
11+
For more information about this error, try `rustc --explain E0594`.

0 commit comments

Comments
 (0)