Skip to content

Commit efc8f65

Browse files
committed
Try to fix issue 68049
1 parent 1773f14 commit efc8f65

File tree

5 files changed

+170
-10
lines changed

5 files changed

+170
-10
lines changed

compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs

+103-10
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
66
use rustc_middle::ty::{self, Ty, TyCtxt};
77
use rustc_middle::{
88
hir::place::PlaceBase,
9-
mir::{self, ClearCrossCrate, Local, LocalDecl, LocalInfo, Location},
9+
mir::{self, ClearCrossCrate, Local, LocalDecl, LocalInfo, LocalKind, Location},
1010
};
1111
use rustc_span::source_map::DesugaringKind;
1212
use rustc_span::symbol::{kw, Symbol};
@@ -424,15 +424,108 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
424424

425425
match label {
426426
Some((true, err_help_span, suggested_code)) => {
427-
err.span_suggestion(
428-
err_help_span,
429-
&format!(
430-
"consider changing this to be a mutable {}",
431-
pointer_desc
432-
),
433-
suggested_code,
434-
Applicability::MachineApplicable,
435-
);
427+
/// User cannot make signature of a trait mutable
428+
/// without changing the trait. So we find if this
429+
/// error belongs to a trait and if so we move
430+
/// suggestion to the trait or disable it if it is
431+
/// out of scope of this crate
432+
let (is_trait_sig, local_trait) = {
433+
if self.body.local_kind(local) != LocalKind::Arg {
434+
(false, None)
435+
} else {
436+
let hir_map = self.infcx.tcx.hir();
437+
let my_hir = hir_map.local_def_id_to_hir_id(
438+
self.body.source.def_id().as_local().unwrap(),
439+
);
440+
match hir_map.find(hir_map.get_parent_node(my_hir)) {
441+
Some(Node::Item(hir::Item {
442+
kind:
443+
hir::ItemKind::Impl(hir::Impl {
444+
of_trait:
445+
Some(hir::TraitRef {
446+
path:
447+
hir::Path {
448+
res:
449+
hir::def::Res::Def(_, td),
450+
..
451+
},
452+
..
453+
}),
454+
..
455+
}),
456+
..
457+
})) => {
458+
(true, td.as_local().and_then(|tld| {
459+
let h = hir_map.local_def_id_to_hir_id(tld);
460+
match hir_map.find(h) {
461+
Some(Node::Item(hir::Item {
462+
kind: hir::ItemKind::Trait(
463+
_, _, _, _,
464+
items
465+
),
466+
..
467+
})) => {
468+
let mut f_in_trait_opt = None;
469+
for hir::TraitItemRef { id: fi, kind: k, .. } in *items {
470+
let hi = fi.hir_id();
471+
if !matches!(k, hir::AssocItemKind::Fn { .. }) {
472+
continue;
473+
}
474+
if hir_map.name(hi) != hir_map.name(my_hir) {
475+
continue;
476+
}
477+
f_in_trait_opt = Some(hi);
478+
break;
479+
}
480+
f_in_trait_opt.and_then(|f_in_trait| {
481+
match hir_map.find(f_in_trait) {
482+
Some(Node::TraitItem(hir::TraitItem {
483+
kind: hir::TraitItemKind::Fn(hir::FnSig {
484+
decl: hir::FnDecl {
485+
inputs,
486+
..
487+
},
488+
..
489+
}, _),
490+
..
491+
})) => {
492+
let hir::Ty { span, .. } = inputs[local.index() - 1];
493+
Some(span)
494+
},
495+
_ => None,
496+
}
497+
})
498+
//Some(hir_map.span(h))
499+
}
500+
_ => None
501+
}
502+
}))
503+
}
504+
_ => (false, None),
505+
}
506+
}
507+
};
508+
if !is_trait_sig {
509+
err.span_suggestion(
510+
err_help_span,
511+
&format!(
512+
"consider changing this to be a mutable {}",
513+
pointer_desc
514+
),
515+
suggested_code,
516+
Applicability::MachineApplicable,
517+
);
518+
} else if let Some(x) = local_trait {
519+
err.span_suggestion(
520+
x,
521+
&format!(
522+
"consider changing that to be a mutable {}",
523+
pointer_desc
524+
),
525+
suggested_code,
526+
Applicability::MachineApplicable,
527+
);
528+
}
436529
}
437530
Some((false, err_label_span, message)) => {
438531
err.span_label(err_label_span, &message);
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
use std::alloc::{GlobalAlloc, Layout};
2+
3+
struct Test(u32);
4+
5+
unsafe impl GlobalAlloc for Test {
6+
unsafe fn alloc(&self, _layout: Layout) -> *mut u8 {
7+
self.0 += 1;
8+
0 as *mut u8
9+
}
10+
11+
unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {
12+
unimplemented!();
13+
}
14+
}
15+
16+
fn main() { }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0594]: cannot assign to `self.0` which is behind a `&` reference
2+
--> $DIR/issue-68049-1.rs:7:9
3+
|
4+
LL | self.0 += 1;
5+
| ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be written
6+
7+
error: aborting due to previous error
8+
9+
For more information about this error, try `rustc --explain E0594`.
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
trait Hello {
2+
fn example(&self, input: &i32); // should suggest here
3+
}
4+
5+
struct Test1(i32);
6+
7+
impl Hello for Test1 {
8+
fn example(&self, input: &i32) { // should not suggest here
9+
*input = self.0;
10+
}
11+
}
12+
13+
struct Test2(i32);
14+
15+
impl Hello for Test2 {
16+
fn example(&self, input: &i32) { // should not suggest here
17+
self.0 += *input;
18+
}
19+
}
20+
21+
fn main() { }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error[E0594]: cannot assign to `*input` which is behind a `&` reference
2+
--> $DIR/issue-68049-2.rs:9:7
3+
|
4+
LL | fn example(&self, input: &i32); // should suggest here
5+
| ---- help: consider changing that to be a mutable reference: `&mut i32`
6+
...
7+
LL | *input = self.0;
8+
| ^^^^^^^^^^^^^^^ `input` is a `&` reference, so the data it refers to cannot be written
9+
10+
error[E0594]: cannot assign to `self.0` which is behind a `&` reference
11+
--> $DIR/issue-68049-2.rs:17:5
12+
|
13+
LL | fn example(&self, input: &i32); // should suggest here
14+
| ----- help: consider changing that to be a mutable reference: `&mut self`
15+
...
16+
LL | self.0 += *input;
17+
| ^^^^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be written
18+
19+
error: aborting due to 2 previous errors
20+
21+
For more information about this error, try `rustc --explain E0594`.

0 commit comments

Comments
 (0)