@@ -1381,8 +1381,8 @@ fn link_by_ref(rcx: &Rcx,
13811381 expr. repr( tcx) , callee_scope) ;
13821382 let mc = mc:: MemCategorizationContext :: new ( rcx) ;
13831383 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) ;
13861386}
13871387
13881388fn link_region_from_node_type ( rcx : & Rcx ,
@@ -1408,102 +1408,54 @@ fn link_region_from_node_type(rcx: &Rcx,
14081408
14091409fn link_region ( rcx : & Rcx ,
14101410 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 ) {
14141414 /*!
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() `.
14201420 */
14211421
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+
14251425 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;
14621441 }
1463-
1464- _ => {
1465- infer:: Reborrow ( span)
1442+ None => {
1443+ return ;
14661444 }
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) ;
14811445 }
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 ;
14981446 }
1447+
14991448 mc:: cat_discr( cmt_base, _) |
15001449 mc:: cat_downcast( cmt_base) |
15011450 mc:: cat_deref( cmt_base, _, mc:: GcPtr ( ..) ) |
15021451 mc:: cat_deref( cmt_base, _, mc:: OwnedPtr ) |
15031452 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;
15061457 }
1458+
15071459 mc:: cat_deref( _, _, mc:: UnsafePtr ( ..) ) |
15081460 mc:: cat_static_item |
15091461 mc:: cat_copied_upvar( ..) |
@@ -1519,6 +1471,154 @@ fn link_region(rcx: &Rcx,
15191471 }
15201472}
15211473
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+
15221622fn adjust_borrow_kind_for_assignment_lhs ( rcx : & Rcx ,
15231623 lhs : & ast:: Expr ) {
15241624 /*!
@@ -1534,6 +1634,12 @@ fn adjust_borrow_kind_for_assignment_lhs(rcx: &Rcx,
15341634
15351635fn adjust_upvar_borrow_kind_for_mut ( rcx : & Rcx ,
15361636 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+
15371643 let mut cmt = cmt;
15381644 loop {
15391645 debug ! ( "adjust_upvar_borrow_kind_for_mut(cmt={})" ,
0 commit comments