Skip to content

Commit 5c1eaf2

Browse files
committed
Auto merge of #65608 - matthewjasper:mir-eval-order, r=<try>
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
2 parents 89e645a + 683d113 commit 5c1eaf2

15 files changed

+640
-209
lines changed

src/librustc/mir/mod.rs

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

16691678
#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
@@ -1761,9 +1770,8 @@ impl_stable_hash_for!(struct Static<'tcx> {
17611770
def_id
17621771
});
17631772

1764-
#[derive(
1765-
Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable,
1766-
)]
1773+
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
1774+
#[derive(RustcEncodable, RustcDecodable, HashStable)]
17671775
pub enum ProjectionElem<V, T> {
17681776
Deref,
17691777
Field(Field, T),

src/librustc_mir/borrow_check/conflict_errors.rs

Lines changed: 101 additions & 53 deletions
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;
@@ -385,42 +385,38 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
385385
let first_borrow_desc;
386386
let mut err = match (
387387
gen_borrow_kind,
388-
"immutable",
389-
"mutable",
390388
issued_borrow.kind,
391-
"immutable",
392-
"mutable",
393389
) {
394-
(BorrowKind::Shared, lft, _, BorrowKind::Mut { .. }, _, rgt) => {
390+
(BorrowKind::Shared, BorrowKind::Mut { .. }) => {
395391
first_borrow_desc = "mutable ";
396392
self.cannot_reborrow_already_borrowed(
397393
span,
398394
&desc_place,
399395
&msg_place,
400-
lft,
396+
"immutable",
401397
issued_span,
402398
"it",
403-
rgt,
399+
"mutable",
404400
&msg_borrow,
405401
None,
406402
)
407403
}
408-
(BorrowKind::Mut { .. }, _, lft, BorrowKind::Shared, rgt, _) => {
404+
(BorrowKind::Mut { .. }, BorrowKind::Shared) => {
409405
first_borrow_desc = "immutable ";
410406
self.cannot_reborrow_already_borrowed(
411407
span,
412408
&desc_place,
413409
&msg_place,
414-
lft,
410+
"mutable",
415411
issued_span,
416412
"it",
417-
rgt,
413+
"immutable",
418414
&msg_borrow,
419415
None,
420416
)
421417
}
422418

423-
(BorrowKind::Mut { .. }, _, _, BorrowKind::Mut { .. }, _, _) => {
419+
(BorrowKind::Mut { .. }, BorrowKind::Mut { .. }) => {
424420
first_borrow_desc = "first ";
425421
self.cannot_mutably_borrow_multiply(
426422
span,
@@ -432,7 +428,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
432428
)
433429
}
434430

435-
(BorrowKind::Unique, _, _, BorrowKind::Unique, _, _) => {
431+
(BorrowKind::Unique, BorrowKind::Unique) => {
436432
first_borrow_desc = "first ";
437433
self.cannot_uniquely_borrow_by_two_closures(
438434
span,
@@ -442,25 +438,45 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
442438
)
443439
}
444440

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

460-
return err;
462+
return err;
463+
} else {
464+
first_borrow_desc = "immutable ";
465+
self.cannot_reborrow_already_borrowed(
466+
span,
467+
&desc_place,
468+
&msg_place,
469+
"mutable",
470+
issued_span,
471+
"it",
472+
"immutable",
473+
&msg_borrow,
474+
None,
475+
)
476+
}
461477
}
462478

463-
(BorrowKind::Unique, _, _, _, _, _) => {
479+
(BorrowKind::Unique, _) => {
464480
first_borrow_desc = "first ";
465481
self.cannot_uniquely_borrow_by_one_closure(
466482
span,
@@ -474,42 +490,42 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
474490
)
475491
},
476492

477-
(BorrowKind::Shared, lft, _, BorrowKind::Unique, _, _) => {
493+
(BorrowKind::Shared, BorrowKind::Unique) => {
478494
first_borrow_desc = "first ";
479495
self.cannot_reborrow_already_uniquely_borrowed(
480496
span,
481497
container_name,
482498
&desc_place,
483499
"",
484-
lft,
500+
"immutable",
485501
issued_span,
486502
"",
487503
None,
488504
second_borrow_desc,
489505
)
490506
}
491507

492-
(BorrowKind::Mut { .. }, _, lft, BorrowKind::Unique, _, _) => {
508+
(BorrowKind::Mut { .. }, BorrowKind::Unique) => {
493509
first_borrow_desc = "first ";
494510
self.cannot_reborrow_already_uniquely_borrowed(
495511
span,
496512
container_name,
497513
&desc_place,
498514
"",
499-
lft,
515+
"mutable",
500516
issued_span,
501517
"",
502518
None,
503519
second_borrow_desc,
504520
)
505521
}
506522

507-
(BorrowKind::Shared, _, _, BorrowKind::Shared, _, _)
508-
| (BorrowKind::Shared, _, _, BorrowKind::Shallow, _, _)
509-
| (BorrowKind::Shallow, _, _, BorrowKind::Mut { .. }, _, _)
510-
| (BorrowKind::Shallow, _, _, BorrowKind::Unique, _, _)
511-
| (BorrowKind::Shallow, _, _, BorrowKind::Shared, _, _)
512-
| (BorrowKind::Shallow, _, _, BorrowKind::Shallow, _, _) => unreachable!(),
523+
(BorrowKind::Shared, BorrowKind::Shared)
524+
| (BorrowKind::Shared, BorrowKind::Shallow)
525+
| (BorrowKind::Shallow, BorrowKind::Mut { .. })
526+
| (BorrowKind::Shallow, BorrowKind::Unique)
527+
| (BorrowKind::Shallow, BorrowKind::Shared)
528+
| (BorrowKind::Shallow, BorrowKind::Shallow) => unreachable!(),
513529
};
514530

515531
if issued_spans == borrow_spans {
@@ -1436,20 +1452,23 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
14361452
let loan_span = loan_spans.args_or_use();
14371453

14381454
if loan.kind == BorrowKind::Shallow {
1439-
let mut err = self.cannot_mutate_in_match_guard(
1440-
span,
1441-
loan_span,
1442-
&self.describe_place(place.as_ref()).unwrap_or_else(|| "_".to_owned()),
1443-
"assign",
1444-
);
1445-
loan_spans.var_span_label(
1446-
&mut err,
1447-
format!("borrow occurs due to use{}", loan_spans.describe()),
1448-
);
1455+
if let Some(section) = self.classify_immutable_section(&loan.assigned_place) {
1456+
let mut err = self.cannot_mutate_in_immutable_section(
1457+
span,
1458+
loan_span,
1459+
&self.describe_place(place.as_ref()).unwrap_or_else(|| "_".to_owned()),
1460+
section,
1461+
"assign",
1462+
);
1463+
loan_spans.var_span_label(
1464+
&mut err,
1465+
format!("borrow occurs due to use{}", loan_spans.describe()),
1466+
);
14491467

1450-
err.buffer(&mut self.errors_buffer);
1468+
err.buffer(&mut self.errors_buffer);
14511469

1452-
return;
1470+
return;
1471+
}
14531472
}
14541473

14551474
let mut err = self.cannot_assign_to_borrowed(
@@ -1603,6 +1622,35 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
16031622
}
16041623
}
16051624

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

0 commit comments

Comments
 (0)