Skip to content

Commit ac78183

Browse files
authored
Rollup merge of rust-lang#70264 - tirr-c:issue-69789-mut-suggestion, r=estebank
Fix invalid suggestion on `&mut` iterators yielding `&` references Fixes rust-lang#69789. rustc suggested an invalid code when `&` reference from `&mut` iterator is mutated. The compiler knew we're mutating a value behind `&` reference, but as the assignment RHS is from desugaring, it could only see the iterator expression from source and inserted `mut` there. r? @estebank
2 parents 320e84a + 1e5d81d commit ac78183

File tree

3 files changed

+82
-23
lines changed

3 files changed

+82
-23
lines changed

Diff for: src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs

+59-23
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
use rustc::mir::{self, ClearCrossCrate, Local, LocalInfo, Location, ReadOnlyBodyAndCache};
1+
use rustc::mir::{self, ClearCrossCrate, Local, LocalInfo, Location};
22
use rustc::mir::{Mutability, Place, PlaceRef, ProjectionElem};
33
use rustc::ty::{self, Ty, TyCtxt};
44
use rustc_hir as hir;
55
use rustc_hir::Node;
66
use rustc_index::vec::Idx;
7+
use rustc_span::source_map::DesugaringKind;
78
use rustc_span::symbol::kw;
89
use rustc_span::Span;
910

@@ -338,24 +339,53 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
338339

339340
match self.local_names[local] {
340341
Some(name) if !local_decl.from_compiler_desugaring() => {
341-
let suggestion = match local_decl.local_info {
342+
let label = match local_decl.local_info {
342343
LocalInfo::User(ClearCrossCrate::Set(
343344
mir::BindingForm::ImplicitSelf(_),
344-
)) => Some(suggest_ampmut_self(self.infcx.tcx, local_decl)),
345+
)) => {
346+
let (span, suggestion) =
347+
suggest_ampmut_self(self.infcx.tcx, local_decl);
348+
Some((true, span, suggestion))
349+
}
345350

346351
LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var(
347352
mir::VarBindingForm {
348353
binding_mode: ty::BindingMode::BindByValue(_),
349354
opt_ty_info,
350355
..
351356
},
352-
))) => Some(suggest_ampmut(
353-
self.infcx.tcx,
354-
self.body,
355-
local,
356-
local_decl,
357-
opt_ty_info,
358-
)),
357+
))) => {
358+
// check if the RHS is from desugaring
359+
let locations = self.body.find_assignments(local);
360+
let opt_assignment_rhs_span = locations
361+
.first()
362+
.map(|&location| self.body.source_info(location).span);
363+
let opt_desugaring_kind =
364+
opt_assignment_rhs_span.and_then(|span| span.desugaring_kind());
365+
match opt_desugaring_kind {
366+
// on for loops, RHS points to the iterator part
367+
Some(DesugaringKind::ForLoop) => Some((
368+
false,
369+
opt_assignment_rhs_span.unwrap(),
370+
format!(
371+
"this iterator yields `{SIGIL}` {DESC}s",
372+
SIGIL = pointer_sigil,
373+
DESC = pointer_desc
374+
),
375+
)),
376+
// don't create labels for compiler-generated spans
377+
Some(_) => None,
378+
None => {
379+
let (span, suggestion) = suggest_ampmut(
380+
self.infcx.tcx,
381+
local_decl,
382+
opt_assignment_rhs_span,
383+
opt_ty_info,
384+
);
385+
Some((true, span, suggestion))
386+
}
387+
}
388+
}
359389

360390
LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var(
361391
mir::VarBindingForm {
@@ -365,7 +395,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
365395
))) => {
366396
let pattern_span = local_decl.source_info.span;
367397
suggest_ref_mut(self.infcx.tcx, pattern_span)
368-
.map(|replacement| (pattern_span, replacement))
398+
.map(|replacement| (true, pattern_span, replacement))
369399
}
370400

371401
LocalInfo::User(ClearCrossCrate::Clear) => {
@@ -375,13 +405,22 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
375405
_ => unreachable!(),
376406
};
377407

378-
if let Some((err_help_span, suggested_code)) = suggestion {
379-
err.span_suggestion(
380-
err_help_span,
381-
&format!("consider changing this to be a mutable {}", pointer_desc),
382-
suggested_code,
383-
Applicability::MachineApplicable,
384-
);
408+
match label {
409+
Some((true, err_help_span, suggested_code)) => {
410+
err.span_suggestion(
411+
err_help_span,
412+
&format!(
413+
"consider changing this to be a mutable {}",
414+
pointer_desc
415+
),
416+
suggested_code,
417+
Applicability::MachineApplicable,
418+
);
419+
}
420+
Some((false, err_label_span, message)) => {
421+
err.span_label(err_label_span, &message);
422+
}
423+
None => {}
385424
}
386425
err.span_label(
387426
span,
@@ -581,14 +620,11 @@ fn suggest_ampmut_self<'tcx>(
581620
// by trying (3.), then (2.) and finally falling back on (1.).
582621
fn suggest_ampmut<'tcx>(
583622
tcx: TyCtxt<'tcx>,
584-
body: ReadOnlyBodyAndCache<'_, 'tcx>,
585-
local: Local,
586623
local_decl: &mir::LocalDecl<'tcx>,
624+
opt_assignment_rhs_span: Option<Span>,
587625
opt_ty_info: Option<Span>,
588626
) -> (Span, String) {
589-
let locations = body.find_assignments(local);
590-
if !locations.is_empty() {
591-
let assignment_rhs_span = body.source_info(locations[0]).span;
627+
if let Some(assignment_rhs_span) = opt_assignment_rhs_span {
592628
if let Ok(src) = tcx.sess.source_map().span_to_snippet(assignment_rhs_span) {
593629
if let (true, Some(ws_pos)) =
594630
(src.starts_with("&'"), src.find(|c: char| -> bool { c.is_whitespace() }))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Regression test for #69789: rustc generated an invalid suggestion
2+
// when `&` reference from `&mut` iterator is mutated.
3+
4+
fn main() {
5+
for item in &mut std::iter::empty::<&'static ()>() {
6+
//~^ NOTE this iterator yields `&` references
7+
*item = ();
8+
//~^ ERROR cannot assign
9+
//~| NOTE cannot be written
10+
}
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0594]: cannot assign to `*item` which is behind a `&` reference
2+
--> $DIR/issue-69789-iterator-mut-suggestion.rs:7:9
3+
|
4+
LL | for item in &mut std::iter::empty::<&'static ()>() {
5+
| -------------------------------------- this iterator yields `&` references
6+
LL |
7+
LL | *item = ();
8+
| ^^^^^^^^^^ `item` is a `&` reference, so the data it refers to cannot be written
9+
10+
error: aborting due to previous error
11+
12+
For more information about this error, try `rustc --explain E0594`.

0 commit comments

Comments
 (0)