Skip to content

Commit 4f03f4a

Browse files
committed
Auto merge of #65608 - matthewjasper:mir-eval-order, r=pnkfelix
Fix MIR lowering evaluation order and soundness bug * Fixes a soundness issue with built-in index operations * Ensures correct evaluation order of assignment expressions where the RHS is a FRU or is a use of a local of reference type. * Removes an unnecessary symbol to string conversion closes #65909 closes #65910
2 parents 5dda3ee + 4bf0685 commit 4f03f4a

16 files changed

+687
-223
lines changed

src/librustc/mir/mod.rs

+11-3
Original file line numberDiff line numberDiff line change
@@ -1665,6 +1665,15 @@ pub enum FakeReadCause {
16651665
/// Therefore, we insert a "fake read" here to ensure that we get
16661666
/// appropriate errors.
16671667
ForLet,
1668+
1669+
/// If we have an index expression like
1670+
///
1671+
/// (*x)[1][{ x = y; 4}]
1672+
///
1673+
/// then the first bounds check is invalidated when we evaluate the second
1674+
/// index expression. Thus we create a fake borrow of `x` across the second
1675+
/// indexer, which will cause a borrow check error.
1676+
ForIndex,
16681677
}
16691678

16701679
#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
@@ -1764,9 +1773,8 @@ impl_stable_hash_for!(struct Static<'tcx> {
17641773
def_id
17651774
});
17661775

1767-
#[derive(
1768-
Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable,
1769-
)]
1776+
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
1777+
#[derive(RustcEncodable, RustcDecodable, HashStable)]
17701778
pub enum ProjectionElem<V, T> {
17711779
Deref,
17721780
Field(Field, T),

src/librustc_mir/borrow_check/conflict_errors.rs

+101-53
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ use rustc::hir;
22
use rustc::hir::def_id::DefId;
33
use rustc::hir::{AsyncGeneratorKind, GeneratorKind};
44
use rustc::mir::{
5-
self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory, Local,
6-
LocalDecl, LocalKind, Location, Operand, Place, PlaceBase, PlaceRef, ProjectionElem, Rvalue,
7-
Statement, StatementKind, TerminatorKind, VarBindingForm,
5+
self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,
6+
FakeReadCause, Local, LocalDecl, LocalKind, Location, Operand, Place, PlaceBase, PlaceRef,
7+
ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm,
88
};
99
use rustc::ty::{self, Ty};
1010
use rustc_data_structures::fx::FxHashSet;
@@ -380,42 +380,38 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
380380
let first_borrow_desc;
381381
let mut err = match (
382382
gen_borrow_kind,
383-
"immutable",
384-
"mutable",
385383
issued_borrow.kind,
386-
"immutable",
387-
"mutable",
388384
) {
389-
(BorrowKind::Shared, lft, _, BorrowKind::Mut { .. }, _, rgt) => {
385+
(BorrowKind::Shared, BorrowKind::Mut { .. }) => {
390386
first_borrow_desc = "mutable ";
391387
self.cannot_reborrow_already_borrowed(
392388
span,
393389
&desc_place,
394390
&msg_place,
395-
lft,
391+
"immutable",
396392
issued_span,
397393
"it",
398-
rgt,
394+
"mutable",
399395
&msg_borrow,
400396
None,
401397
)
402398
}
403-
(BorrowKind::Mut { .. }, _, lft, BorrowKind::Shared, rgt, _) => {
399+
(BorrowKind::Mut { .. }, BorrowKind::Shared) => {
404400
first_borrow_desc = "immutable ";
405401
self.cannot_reborrow_already_borrowed(
406402
span,
407403
&desc_place,
408404
&msg_place,
409-
lft,
405+
"mutable",
410406
issued_span,
411407
"it",
412-
rgt,
408+
"immutable",
413409
&msg_borrow,
414410
None,
415411
)
416412
}
417413

418-
(BorrowKind::Mut { .. }, _, _, BorrowKind::Mut { .. }, _, _) => {
414+
(BorrowKind::Mut { .. }, BorrowKind::Mut { .. }) => {
419415
first_borrow_desc = "first ";
420416
self.cannot_mutably_borrow_multiply(
421417
span,
@@ -427,7 +423,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
427423
)
428424
}
429425

430-
(BorrowKind::Unique, _, _, BorrowKind::Unique, _, _) => {
426+
(BorrowKind::Unique, BorrowKind::Unique) => {
431427
first_borrow_desc = "first ";
432428
self.cannot_uniquely_borrow_by_two_closures(
433429
span,
@@ -437,25 +433,45 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
437433
)
438434
}
439435

440-
(BorrowKind::Mut { .. }, _, _, BorrowKind::Shallow, _, _)
441-
| (BorrowKind::Unique, _, _, BorrowKind::Shallow, _, _) => {
442-
let mut err = self.cannot_mutate_in_match_guard(
443-
span,
444-
issued_span,
445-
&desc_place,
446-
"mutably borrow",
447-
);
448-
borrow_spans.var_span_label(
449-
&mut err,
450-
format!(
451-
"borrow occurs due to use of `{}`{}", desc_place, borrow_spans.describe()
452-
),
453-
);
436+
(BorrowKind::Mut { .. }, BorrowKind::Shallow)
437+
| (BorrowKind::Unique, BorrowKind::Shallow) => {
438+
if let Some(immutable_section_description) = self.classify_immutable_section(
439+
&issued_borrow.assigned_place,
440+
) {
441+
let mut err = self.cannot_mutate_in_immutable_section(
442+
span,
443+
issued_span,
444+
&desc_place,
445+
immutable_section_description,
446+
"mutably borrow",
447+
);
448+
borrow_spans.var_span_label(
449+
&mut err,
450+
format!(
451+
"borrow occurs due to use of `{}`{}",
452+
desc_place,
453+
borrow_spans.describe(),
454+
),
455+
);
454456

455-
return err;
457+
return err;
458+
} else {
459+
first_borrow_desc = "immutable ";
460+
self.cannot_reborrow_already_borrowed(
461+
span,
462+
&desc_place,
463+
&msg_place,
464+
"mutable",
465+
issued_span,
466+
"it",
467+
"immutable",
468+
&msg_borrow,
469+
None,
470+
)
471+
}
456472
}
457473

458-
(BorrowKind::Unique, _, _, _, _, _) => {
474+
(BorrowKind::Unique, _) => {
459475
first_borrow_desc = "first ";
460476
self.cannot_uniquely_borrow_by_one_closure(
461477
span,
@@ -469,42 +485,42 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
469485
)
470486
},
471487

472-
(BorrowKind::Shared, lft, _, BorrowKind::Unique, _, _) => {
488+
(BorrowKind::Shared, BorrowKind::Unique) => {
473489
first_borrow_desc = "first ";
474490
self.cannot_reborrow_already_uniquely_borrowed(
475491
span,
476492
container_name,
477493
&desc_place,
478494
"",
479-
lft,
495+
"immutable",
480496
issued_span,
481497
"",
482498
None,
483499
second_borrow_desc,
484500
)
485501
}
486502

487-
(BorrowKind::Mut { .. }, _, lft, BorrowKind::Unique, _, _) => {
503+
(BorrowKind::Mut { .. }, BorrowKind::Unique) => {
488504
first_borrow_desc = "first ";
489505
self.cannot_reborrow_already_uniquely_borrowed(
490506
span,
491507
container_name,
492508
&desc_place,
493509
"",
494-
lft,
510+
"mutable",
495511
issued_span,
496512
"",
497513
None,
498514
second_borrow_desc,
499515
)
500516
}
501517

502-
(BorrowKind::Shared, _, _, BorrowKind::Shared, _, _)
503-
| (BorrowKind::Shared, _, _, BorrowKind::Shallow, _, _)
504-
| (BorrowKind::Shallow, _, _, BorrowKind::Mut { .. }, _, _)
505-
| (BorrowKind::Shallow, _, _, BorrowKind::Unique, _, _)
506-
| (BorrowKind::Shallow, _, _, BorrowKind::Shared, _, _)
507-
| (BorrowKind::Shallow, _, _, BorrowKind::Shallow, _, _) => unreachable!(),
518+
(BorrowKind::Shared, BorrowKind::Shared)
519+
| (BorrowKind::Shared, BorrowKind::Shallow)
520+
| (BorrowKind::Shallow, BorrowKind::Mut { .. })
521+
| (BorrowKind::Shallow, BorrowKind::Unique)
522+
| (BorrowKind::Shallow, BorrowKind::Shared)
523+
| (BorrowKind::Shallow, BorrowKind::Shallow) => unreachable!(),
508524
};
509525

510526
if issued_spans == borrow_spans {
@@ -1429,20 +1445,23 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
14291445
let loan_span = loan_spans.args_or_use();
14301446

14311447
if loan.kind == BorrowKind::Shallow {
1432-
let mut err = self.cannot_mutate_in_match_guard(
1433-
span,
1434-
loan_span,
1435-
&self.describe_place(place.as_ref()).unwrap_or_else(|| "_".to_owned()),
1436-
"assign",
1437-
);
1438-
loan_spans.var_span_label(
1439-
&mut err,
1440-
format!("borrow occurs due to use{}", loan_spans.describe()),
1441-
);
1448+
if let Some(section) = self.classify_immutable_section(&loan.assigned_place) {
1449+
let mut err = self.cannot_mutate_in_immutable_section(
1450+
span,
1451+
loan_span,
1452+
&self.describe_place(place.as_ref()).unwrap_or_else(|| "_".to_owned()),
1453+
section,
1454+
"assign",
1455+
);
1456+
loan_spans.var_span_label(
1457+
&mut err,
1458+
format!("borrow occurs due to use{}", loan_spans.describe()),
1459+
);
14421460

1443-
err.buffer(&mut self.errors_buffer);
1461+
err.buffer(&mut self.errors_buffer);
14441462

1445-
return;
1463+
return;
1464+
}
14461465
}
14471466

14481467
let mut err = self.cannot_assign_to_borrowed(
@@ -1593,6 +1612,35 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
15931612
}
15941613
}
15951614

1615+
/// Describe the reason for the fake borrow that was assigned to `place`.
1616+
fn classify_immutable_section(&self, place: &Place<'tcx>) -> Option<&'static str> {
1617+
use rustc::mir::visit::Visitor;
1618+
struct FakeReadCauseFinder<'a, 'tcx> {
1619+
place: &'a Place<'tcx>,
1620+
cause: Option<FakeReadCause>,
1621+
}
1622+
impl<'tcx> Visitor<'tcx> for FakeReadCauseFinder<'_, 'tcx> {
1623+
fn visit_statement(&mut self, statement: &Statement<'tcx>, _: Location) {
1624+
match statement {
1625+
Statement {
1626+
kind: StatementKind::FakeRead(cause, box ref place),
1627+
..
1628+
} if *place == *self.place => {
1629+
self.cause = Some(*cause);
1630+
}
1631+
_ => (),
1632+
}
1633+
}
1634+
}
1635+
let mut visitor = FakeReadCauseFinder { place, cause: None };
1636+
visitor.visit_body(&self.body);
1637+
match visitor.cause {
1638+
Some(FakeReadCause::ForMatchGuard) => Some("match guard"),
1639+
Some(FakeReadCause::ForIndex) => Some("indexing expression"),
1640+
_ => None,
1641+
}
1642+
}
1643+
15961644
/// Annotate argument and return type of function and closure with (synthesized) lifetime for
15971645
/// borrow of local value that does not live long enough.
15981646
fn annotate_argument_and_return_for_borrow(

0 commit comments

Comments
 (0)