Skip to content

Commit b12c362

Browse files
Rollup merge of rust-lang#156795 - P8L1:fix-generic-reborrow-expr-use-visitor, r=dingxiangfei2009
Handle generic reborrow in expression-use adjustment walking Fixes an ICE in expression-use adjustment walking where `Adjust::GenericReborrow` could reach a match arm that assumed generic reborrow was unreachable. `GenericReborrow` is already emitted by typeck and classified as rvalue-producing elsewhere in `expr_use_visitor.rs`, so the adjustment walker must handle it explicitly instead of panicking. This PR models `GenericReborrow` as a borrow-like use of the source expression: - `Mutability::Mut` is treated like an exclusive/mutable reborrow use. - `Mutability::Not` is treated like a shared/coerce-shared borrow-like use. - The source is not moved or treated as a mere copy. cc @aapoalas @rustbot label F-reborrow Fixes rust-lang#156339 Tracking: rust-lang#145612
2 parents d9397d0 + a5e4dc9 commit b12c362

3 files changed

Lines changed: 75 additions & 8 deletions

File tree

compiler/rustc_hir_typeck/src/expr_use_visitor.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -727,7 +727,8 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
727727
let typeck_results = self.cx.typeck_results();
728728
let adjustments = typeck_results.expr_adjustments(expr);
729729
let mut place_with_id = self.cat_expr_unadjusted(expr)?;
730-
for adjustment in adjustments {
730+
for (adjustment_index, adjustment) in adjustments.iter().enumerate() {
731+
let is_last_adjustment = adjustment_index + 1 == adjustments.len();
731732
debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment);
732733
match adjustment.kind {
733734
adjustment::Adjust::NeverToAny | adjustment::Adjust::Pointer(_) => {
@@ -752,13 +753,13 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
752753
self.walk_autoref(expr, &place_with_id, autoref);
753754
}
754755

755-
adjustment::Adjust::GenericReborrow(_reborrow) => {
756-
// To build an expression as a place expression, it needs to be a field
757-
// projection or deref at the outmost layer. So it is field projection or deref
758-
// on an adjusted value. But this means that adjustment is applied on a
759-
// subexpression that is not the final operand/rvalue for function call or
760-
// assignment. This is a contradiction.
761-
unreachable!("Reborrow trait usage during adjustment walk");
756+
adjustment::Adjust::GenericReborrow(mutability) if is_last_adjustment => {
757+
let bk = ty::BorrowKind::from_mutbl(mutability);
758+
self.delegate.borrow_mut().borrow(&place_with_id, place_with_id.hir_id, bk);
759+
}
760+
761+
adjustment::Adjust::GenericReborrow(_) => {
762+
span_bug!(expr.span, "generic reborrow adjustment must be terminal");
762763
}
763764
}
764765
place_with_id = self.cat_expr_adjusted(expr, place_with_id, adjustment)?;
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//@ check-pass
2+
3+
#![feature(reborrow)]
4+
5+
use std::marker::{CoerceShared, Reborrow};
6+
7+
#[allow(unused)]
8+
struct CustomMut<'a, T>(&'a mut T);
9+
impl<'a, T> Reborrow for CustomMut<'a, T> {}
10+
impl<'a, T> CoerceShared<CustomRef<'a, T>> for CustomMut<'a, T> {}
11+
12+
#[allow(unused)]
13+
struct CustomRef<'a, T>(&'a T);
14+
impl<'a, T> Clone for CustomRef<'a, T> {
15+
fn clone(&self) -> Self {
16+
Self(self.0)
17+
}
18+
}
19+
impl<'a, T> Copy for CustomRef<'a, T> {}
20+
21+
fn takes_mut(_: CustomMut<'_, ()>) {}
22+
fn takes_shared(_: CustomRef<'_, ()>) {}
23+
24+
fn main() {
25+
let a = CustomMut(&mut ());
26+
27+
let mut f = || {
28+
takes_mut(a);
29+
takes_shared(a);
30+
};
31+
32+
f();
33+
f();
34+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//@ check-pass
2+
3+
#![feature(reborrow)]
4+
5+
use std::marker::{CoerceShared, Reborrow};
6+
7+
#[allow(unused)]
8+
struct CustomMut<'a, T>(&'a mut T);
9+
impl<'a, T> Reborrow for CustomMut<'a, T> {}
10+
impl<'a, T> CoerceShared<CustomRef<'a, T>> for CustomMut<'a, T> {}
11+
12+
#[allow(unused)]
13+
struct CustomRef<'a, T>(&'a T);
14+
impl<'a, T> Clone for CustomRef<'a, T> {
15+
fn clone(&self) -> Self {
16+
Self(self.0)
17+
}
18+
}
19+
impl<'a, T> Copy for CustomRef<'a, T> {}
20+
21+
fn takes_mut(_: CustomMut<'_, ()>) {}
22+
fn takes_shared(_: CustomRef<'_, ()>) {}
23+
24+
fn main() {
25+
let a = CustomMut(&mut ());
26+
27+
takes_mut(a);
28+
takes_mut(a);
29+
30+
takes_shared(a);
31+
takes_shared(a);
32+
}

0 commit comments

Comments
 (0)