@@ -1381,8 +1381,8 @@ fn link_by_ref(rcx: &Rcx,
1381
1381
expr. repr( tcx) , callee_scope) ;
1382
1382
let mc = mc:: MemCategorizationContext :: new ( rcx) ;
1383
1383
let expr_cmt = ignore_err ! ( mc. cat_expr( expr) ) ;
1384
- let region_min = ty:: ReScope ( callee_scope) ;
1385
- link_region ( rcx, expr. span , region_min , ty:: ImmBorrow , expr_cmt) ;
1384
+ let borrow_region = ty:: ReScope ( callee_scope) ;
1385
+ link_region ( rcx, expr. span , borrow_region , ty:: ImmBorrow , expr_cmt) ;
1386
1386
}
1387
1387
1388
1388
fn link_region_from_node_type ( rcx : & Rcx ,
@@ -1408,102 +1408,54 @@ fn link_region_from_node_type(rcx: &Rcx,
1408
1408
1409
1409
fn link_region ( rcx : & Rcx ,
1410
1410
span : Span ,
1411
- region_min : ty:: Region ,
1412
- kind : ty:: BorrowKind ,
1413
- cmt_borrowed : mc:: cmt ) {
1411
+ borrow_region : ty:: Region ,
1412
+ borrow_kind : ty:: BorrowKind ,
1413
+ borrow_cmt : mc:: cmt ) {
1414
1414
/*!
1415
- * Informs the inference engine that a borrow of `cmt`
1416
- * must have the borrow kind `kind ` and lifetime `region_min `.
1417
- * If `cmt` is a deref of a region pointer with
1418
- * lifetime `r_borrowed`, this will add the constraint that
1419
- * `region_min <= r_borrowed `.
1415
+ * Informs the inference engine that `borrow_cmt` is being
1416
+ * borrowed with kind `borrow_kind ` and lifetime `borrow_region `.
1417
+ * In order to ensure borrowck is satisfied, this may create
1418
+ * constraints between regions, as explained in
1419
+ * `link_reborrowed_region() `.
1420
1420
*/
1421
1421
1422
- // Iterate through all the things that must be live at least
1423
- // for the lifetime `region_min` for the borrow to be valid:
1424
- let mut cmt_borrowed = cmt_borrowed ;
1422
+ let mut borrow_cmt = borrow_cmt ;
1423
+ let mut borrow_kind = borrow_kind ;
1424
+
1425
1425
loop {
1426
- debug ! ( "link_region(region_min={}, kind={}, cmt_borrowed={})" ,
1427
- region_min. repr( rcx. tcx( ) ) ,
1428
- kind. repr( rcx. tcx( ) ) ,
1429
- cmt_borrowed. repr( rcx. tcx( ) ) ) ;
1430
- match cmt_borrowed. cat . clone ( ) {
1431
- mc:: cat_deref( base, _, mc:: BorrowedPtr ( _, r_borrowed) ) |
1432
- mc:: cat_deref( base, _, mc:: Implicit ( _, r_borrowed) ) => {
1433
- // References to an upvar `x` are translated to
1434
- // `*x`, since that is what happens in the
1435
- // underlying machine. We detect such references
1436
- // and treat them slightly differently, both to
1437
- // offer better error messages and because we need
1438
- // to infer the kind of borrow (mut, const, etc)
1439
- // to use for each upvar.
1440
- let cause = match base. cat {
1441
- mc:: cat_upvar( ref upvar_id, _) => {
1442
- match rcx. fcx . inh . upvar_borrow_map . borrow_mut ( )
1443
- . find_mut ( upvar_id) {
1444
- Some ( upvar_borrow) => {
1445
- debug ! ( "link_region: {} <= {}" ,
1446
- region_min. repr( rcx. tcx( ) ) ,
1447
- upvar_borrow. region. repr( rcx. tcx( ) ) ) ;
1448
- adjust_upvar_borrow_kind_for_loan (
1449
- * upvar_id,
1450
- upvar_borrow,
1451
- kind) ;
1452
- infer:: ReborrowUpvar ( span, * upvar_id)
1453
- }
1454
- None => {
1455
- rcx. tcx ( ) . sess . span_bug (
1456
- span,
1457
- format ! ( "Illegal upvar id: {}" ,
1458
- upvar_id. repr(
1459
- rcx. tcx( ) ) ) . as_slice ( ) ) ;
1460
- }
1461
- }
1426
+ debug ! ( "link_region(borrow_region={}, borrow_kind={}, borrow_cmt={})" ,
1427
+ borrow_region. repr( rcx. tcx( ) ) ,
1428
+ borrow_kind. repr( rcx. tcx( ) ) ,
1429
+ borrow_cmt. repr( rcx. tcx( ) ) ) ;
1430
+ match borrow_cmt. cat . clone ( ) {
1431
+ mc:: cat_deref( ref_cmt, _,
1432
+ mc:: Implicit ( ref_kind, ref_region) ) |
1433
+ mc:: cat_deref( ref_cmt, _,
1434
+ mc:: BorrowedPtr ( ref_kind, ref_region) ) => {
1435
+ match link_reborrowed_region ( rcx, span,
1436
+ borrow_region, borrow_kind,
1437
+ ref_cmt, ref_region, ref_kind) {
1438
+ Some ( ( c, k) ) => {
1439
+ borrow_cmt = c;
1440
+ borrow_kind = k;
1462
1441
}
1463
-
1464
- _ => {
1465
- infer:: Reborrow ( span)
1442
+ None => {
1443
+ return ;
1466
1444
}
1467
- } ;
1468
-
1469
- debug ! ( "link_region: {} <= {}" ,
1470
- region_min. repr( rcx. tcx( ) ) ,
1471
- r_borrowed. repr( rcx. tcx( ) ) ) ;
1472
- rcx. fcx . mk_subr ( cause, region_min, r_borrowed) ;
1473
-
1474
- if kind != ty:: ImmBorrow {
1475
- // If this is a mutable borrow, then the thing
1476
- // being borrowed will have to be unique.
1477
- // In user code, this means it must be an `&mut`
1478
- // borrow, but for an upvar, we might opt
1479
- // for an immutable-unique borrow.
1480
- adjust_upvar_borrow_kind_for_unique ( rcx, base) ;
1481
1445
}
1482
-
1483
- // Borrowing an `&mut` pointee for `region_min` is
1484
- // only valid if the pointer resides in a unique
1485
- // location which is itself valid for
1486
- // `region_min`. We don't care about the unique
1487
- // part, but we may need to influence the
1488
- // inference to ensure that the location remains
1489
- // valid.
1490
- //
1491
- // FIXME(#8624) fixing borrowck will require this
1492
- // if m == ast::m_mutbl {
1493
- // cmt_borrowed = cmt_base;
1494
- // } else {
1495
- // return;
1496
- // }
1497
- return ;
1498
1446
}
1447
+
1499
1448
mc:: cat_discr( cmt_base, _) |
1500
1449
mc:: cat_downcast( cmt_base) |
1501
1450
mc:: cat_deref( cmt_base, _, mc:: GcPtr ( ..) ) |
1502
1451
mc:: cat_deref( cmt_base, _, mc:: OwnedPtr ) |
1503
1452
mc:: cat_interior( cmt_base, _) => {
1504
- // Interior or owned data requires its base to be valid
1505
- cmt_borrowed = cmt_base;
1453
+ // Borrowing interior or owned data requires the base
1454
+ // to be valid and borrowable in the same fashion.
1455
+ borrow_cmt = cmt_base;
1456
+ borrow_kind = borrow_kind;
1506
1457
}
1458
+
1507
1459
mc:: cat_deref( _, _, mc:: UnsafePtr ( ..) ) |
1508
1460
mc:: cat_static_item |
1509
1461
mc:: cat_copied_upvar( ..) |
@@ -1519,6 +1471,154 @@ fn link_region(rcx: &Rcx,
1519
1471
}
1520
1472
}
1521
1473
1474
+ fn link_reborrowed_region ( rcx : & Rcx ,
1475
+ span : Span ,
1476
+ borrow_region : ty:: Region ,
1477
+ borrow_kind : ty:: BorrowKind ,
1478
+ ref_cmt : mc:: cmt ,
1479
+ ref_region : ty:: Region ,
1480
+ ref_kind : ty:: BorrowKind )
1481
+ -> Option < ( mc:: cmt , ty:: BorrowKind ) >
1482
+ {
1483
+ /*!
1484
+ * This is the most complicated case: the path being borrowed is
1485
+ * itself the referent of a borrowed pointer. Let me give an
1486
+ * example fragment of code to make clear(er) the situation:
1487
+ *
1488
+ * let r: &'a mut T = ...; // the original reference "r" has lifetime 'a
1489
+ * ...
1490
+ * &'z *r // the reborrow has lifetime 'z
1491
+ *
1492
+ * Now, in this case, our primary job is to add the inference
1493
+ * constraint that `'z <= 'a`. Given this setup, let's clarify the
1494
+ * parameters in (roughly) terms of the example:
1495
+ *
1496
+ * A borrow of: `& 'z bk * r` where `r` has type `& 'a bk T`
1497
+ * borrow_region ^~ ref_region ^~
1498
+ * borrow_kind ^~ ref_kind ^~
1499
+ * ref_cmt ^
1500
+ *
1501
+ * Here `bk` stands for some borrow-kind (e.g., `mut`, `uniq`, etc).
1502
+ *
1503
+ * Unfortunately, there are some complications beyond the simple
1504
+ * scenario I just painted:
1505
+ *
1506
+ * 1. The reference `r` might in fact be a "by-ref" upvar. In that
1507
+ * case, we have two jobs. First, we are inferring whether this reference
1508
+ * should be an `&T`, `&mut T`, or `&uniq T` reference, and we must
1509
+ * adjust that based on this borrow (e.g., if this is an `&mut` borrow,
1510
+ * then `r` must be an `&mut` reference). Second, whenever we link
1511
+ * two regions (here, `'z <= 'a`), we supply a *cause*, and in this
1512
+ * case we adjust the cause to indicate that the reference being
1513
+ * "reborrowed" is itself an upvar. This provides a nicer error message
1514
+ * should something go wrong.
1515
+ *
1516
+ * 2. There may in fact be more levels of reborrowing. In the
1517
+ * example, I said the borrow was like `&'z *r`, but it might
1518
+ * in fact be a borrow like `&'z **q` where `q` has type `&'a
1519
+ * &'b mut T`. In that case, we want to ensure that `'z <= 'a`
1520
+ * and `'z <= 'b`. This is explained more below.
1521
+ *
1522
+ * The return value of this function indicates whether we need to
1523
+ * recurse and process `ref_cmt` (see case 2 above).
1524
+ */
1525
+
1526
+ // Detect references to an upvar `x`:
1527
+ let cause = match ref_cmt. cat {
1528
+ mc:: cat_upvar( ref upvar_id, _) => {
1529
+ let mut upvar_borrow_map =
1530
+ rcx. fcx . inh . upvar_borrow_map . borrow_mut ( ) ;
1531
+ match upvar_borrow_map. find_mut ( upvar_id) {
1532
+ Some ( upvar_borrow) => {
1533
+ // Adjust mutability that we infer for the upvar
1534
+ // so it can accommodate being borrowed with
1535
+ // mutability `kind`:
1536
+ adjust_upvar_borrow_kind_for_loan ( * upvar_id,
1537
+ upvar_borrow,
1538
+ borrow_kind) ;
1539
+
1540
+ infer:: ReborrowUpvar ( span, * upvar_id)
1541
+ }
1542
+ None => {
1543
+ rcx. tcx ( ) . sess . span_bug (
1544
+ span,
1545
+ format ! ( "Illegal upvar id: {}" ,
1546
+ upvar_id. repr(
1547
+ rcx. tcx( ) ) ) . as_slice ( ) ) ;
1548
+ }
1549
+ }
1550
+ }
1551
+
1552
+ _ => {
1553
+ infer:: Reborrow ( span)
1554
+ }
1555
+ } ;
1556
+
1557
+ debug ! ( "link_reborrowed_region: {} <= {}" ,
1558
+ borrow_region. repr( rcx. tcx( ) ) ,
1559
+ ref_region. repr( rcx. tcx( ) ) ) ;
1560
+ rcx. fcx . mk_subr ( cause, borrow_region, ref_region) ;
1561
+
1562
+ // Decide whether we need to recurse and link any regions within
1563
+ // the `ref_cmt`. This is concerned for the case where the value
1564
+ // being reborrowed is in fact a borrowed pointer found within
1565
+ // another borrowed pointer. For example:
1566
+ //
1567
+ // let p: &'b &'a mut T = ...;
1568
+ // ...
1569
+ // &'z **p
1570
+ //
1571
+ // What makes this case particularly tricky is that, if the data
1572
+ // being borrowed is a `&mut` or `&uniq` borrow, borrowck requires
1573
+ // not only that `'z <= 'a`, (as before) but also `'z <= 'b`
1574
+ // (otherwise the user might mutate through the `&mut T` reference
1575
+ // after `'b` expires and invalidate the borrow we are looking at
1576
+ // now).
1577
+ //
1578
+ // So let's re-examine our parameters in light of this more
1579
+ // complicated (possible) scenario:
1580
+ //
1581
+ // A borrow of: `& 'z bk * * p` where `p` has type `&'b bk & 'a bk T`
1582
+ // borrow_region ^~ ref_region ^~
1583
+ // borrow_kind ^~ ref_kind ^~
1584
+ // ref_cmt ^~~
1585
+ //
1586
+ // (Note that since we have not examined `ref_cmt.cat`, we don't
1587
+ // know whether this scenario has occurred; but I wanted to show
1588
+ // how all the types get adjusted.)
1589
+ match ref_kind {
1590
+ ty:: ImmBorrow => {
1591
+ // The reference being reborrowed is a sharable ref of
1592
+ // type `&'a T`. In this case, it doesn't matter where we
1593
+ // *found* the `&T` pointer, the memory it references will
1594
+ // be valid and immutable for `'a`. So we can stop here.
1595
+ //
1596
+ // (Note that the `borrow_kind` must also be ImmBorrow or
1597
+ // else the user is borrowed imm memory as mut memory,
1598
+ // which means they'll get an error downstream in borrowck
1599
+ // anyhow.)
1600
+ return None ;
1601
+ }
1602
+
1603
+ ty:: MutBorrow | ty:: UniqueImmBorrow => {
1604
+ // The reference being reborrowed is either an `&mut T` or
1605
+ // `&uniq T`. This is the case where recursion is needed.
1606
+ //
1607
+ // One interesting twist is that we can weaken the borrow
1608
+ // kind when we recurse: to reborrow an `&mut` referent as
1609
+ // mutable, borrowck requires a unique path to the `&mut`
1610
+ // reference but not necessarily a *mutable* path.
1611
+ let new_borrow_kind = match borrow_kind {
1612
+ ty:: ImmBorrow =>
1613
+ ty:: ImmBorrow ,
1614
+ ty:: MutBorrow | ty:: UniqueImmBorrow =>
1615
+ ty:: UniqueImmBorrow
1616
+ } ;
1617
+ return Some ( ( ref_cmt, new_borrow_kind) ) ;
1618
+ }
1619
+ }
1620
+ }
1621
+
1522
1622
fn adjust_borrow_kind_for_assignment_lhs ( rcx : & Rcx ,
1523
1623
lhs : & ast:: Expr ) {
1524
1624
/*!
@@ -1534,6 +1634,12 @@ fn adjust_borrow_kind_for_assignment_lhs(rcx: &Rcx,
1534
1634
1535
1635
fn adjust_upvar_borrow_kind_for_mut ( rcx : & Rcx ,
1536
1636
cmt : mc:: cmt ) {
1637
+ /*!
1638
+ * Indicates that `cmt` is being directly mutated (e.g., assigned
1639
+ * to). If cmt contains any by-ref upvars, this implies that
1640
+ * those upvars must be borrowed using an `&mut` borow.
1641
+ */
1642
+
1537
1643
let mut cmt = cmt;
1538
1644
loop {
1539
1645
debug ! ( "adjust_upvar_borrow_kind_for_mut(cmt={})" ,
0 commit comments