Skip to content

Commit 04ddafc

Browse files
Properly analyze captures from unsafe binders
1 parent 52bf0cf commit 04ddafc

File tree

7 files changed

+51
-5
lines changed

7 files changed

+51
-5
lines changed

compiler/rustc_hir_typeck/src/expr_use_visitor.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use hir::Expr;
1313
use hir::def::DefKind;
1414
use hir::pat_util::EnumerateAndAdjustIterator as _;
1515
use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx};
16+
use rustc_ast::UnsafeBinderCastKind;
1617
use rustc_data_structures::fx::FxIndexMap;
1718
use rustc_hir::def::{CtorOf, Res};
1819
use rustc_hir::def_id::LocalDefId;
@@ -1393,10 +1394,18 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
13931394
self.cat_res(expr.hir_id, expr.span, expr_ty, res)
13941395
}
13951396

1396-
// both type ascription and unsafe binder casts don't affect
1397-
// the place-ness of the subexpression.
1397+
// type ascription doesn't affect the place-ness of the subexpression.
13981398
hir::ExprKind::Type(e, _) => self.cat_expr(e),
1399-
hir::ExprKind::UnsafeBinderCast(_, e, _) => self.cat_expr(e),
1399+
1400+
hir::ExprKind::UnsafeBinderCast(UnsafeBinderCastKind::Unwrap, e, _) => {
1401+
let base = self.cat_expr(e)?;
1402+
Ok(self.cat_projection(
1403+
expr.hir_id,
1404+
base,
1405+
expr_ty,
1406+
ProjectionKind::UnwrapUnsafeBinder,
1407+
))
1408+
}
14001409

14011410
hir::ExprKind::AddrOf(..)
14021411
| hir::ExprKind::Call(..)
@@ -1427,6 +1436,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
14271436
| hir::ExprKind::Repeat(..)
14281437
| hir::ExprKind::InlineAsm(..)
14291438
| hir::ExprKind::OffsetOf(..)
1439+
| hir::ExprKind::UnsafeBinderCast(UnsafeBinderCastKind::Wrap, ..)
14301440
| hir::ExprKind::Err(_) => Ok(self.cat_rvalue(expr.hir_id, expr_ty)),
14311441
}
14321442
}

compiler/rustc_hir_typeck/src/upvar.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -902,7 +902,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
902902
fn is_field<'a>(p: &&Projection<'a>) -> bool {
903903
match p.kind {
904904
ProjectionKind::Field(_, _) => true,
905-
ProjectionKind::Deref | ProjectionKind::OpaqueCast => false,
905+
ProjectionKind::Deref
906+
| ProjectionKind::OpaqueCast
907+
| ProjectionKind::UnwrapUnsafeBinder => false,
906908
p @ (ProjectionKind::Subslice | ProjectionKind::Index) => {
907909
bug!("ProjectionKind {:?} was unexpected", p)
908910
}
@@ -2197,7 +2199,8 @@ fn restrict_capture_precision(
21972199
}
21982200
ProjectionKind::Deref => {}
21992201
ProjectionKind::OpaqueCast => {}
2200-
ProjectionKind::Field(..) => {} // ignore
2202+
ProjectionKind::Field(..) => {}
2203+
ProjectionKind::UnwrapUnsafeBinder => {}
22012204
}
22022205
}
22032206

@@ -2268,6 +2271,7 @@ fn construct_place_string<'tcx>(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String
22682271
ProjectionKind::Index => String::from("Index"),
22692272
ProjectionKind::Subslice => String::from("Subslice"),
22702273
ProjectionKind::OpaqueCast => String::from("OpaqueCast"),
2274+
ProjectionKind::UnwrapUnsafeBinder => String::from("UnwrapUnsafeBinder"),
22712275
};
22722276
if i != 0 {
22732277
projections_str.push(',');

compiler/rustc_middle/src/hir/place.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ pub enum ProjectionKind {
4343
///
4444
/// This is unused if `-Znext-solver` is enabled.
4545
OpaqueCast,
46+
47+
/// `unwrap_binder!(expr)`
48+
UnwrapUnsafeBinder,
4649
}
4750

4851
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]

compiler/rustc_mir_build/src/builder/expr/as_place.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,9 @@ fn strip_prefix<'tcx>(
240240
HirProjectionKind::OpaqueCast => {
241241
assert_matches!(iter.next(), Some(ProjectionElem::OpaqueCast(..)));
242242
}
243+
HirProjectionKind::UnwrapUnsafeBinder => {
244+
assert_matches!(iter.next(), Some(ProjectionElem::UnwrapUnsafeBinder(..)));
245+
}
243246
HirProjectionKind::Index | HirProjectionKind::Subslice => {
244247
bug!("unexpected projection kind: {:?}", projection);
245248
}

compiler/rustc_mir_build/src/thir/cx/expr.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1220,6 +1220,9 @@ impl<'tcx> ThirBuildCx<'tcx> {
12201220
HirProjectionKind::OpaqueCast => {
12211221
ExprKind::Use { source: self.thir.exprs.push(captured_place_expr) }
12221222
}
1223+
HirProjectionKind::UnwrapUnsafeBinder => ExprKind::PlaceUnwrapUnsafeBinder {
1224+
source: self.thir.exprs.push(captured_place_expr),
1225+
},
12231226
HirProjectionKind::Index | HirProjectionKind::Subslice => {
12241227
// We don't capture these projections, so we can ignore them here
12251228
continue;

src/tools/clippy/clippy_utils/src/sugg.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -941,6 +941,8 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
941941
ProjectionKind::Subslice |
942942
// Doesn't have surface syntax. Only occurs in patterns.
943943
ProjectionKind::OpaqueCast => (),
944+
// Only occurs in closure captures.
945+
ProjectionKind::UnwrapUnsafeBinder => (),
944946
ProjectionKind::Deref => {
945947
// Explicit derefs are typically handled later on, but
946948
// some items do not need explicit deref, such as array accesses,
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//@ check-pass
2+
3+
#![feature(unsafe_binders)]
4+
#![allow(incomplete_features)]
5+
6+
use std::unsafe_binder::unwrap_binder;
7+
8+
#[derive(Copy, Clone)]
9+
pub struct S([usize; 8]);
10+
11+
// Regression test for <https://github.com/rust-lang/rust/issues/141418>.
12+
pub fn by_value(x: unsafe<'a> S) -> usize {
13+
unsafe { (|| unwrap_binder!(x).0[0])() }
14+
}
15+
16+
// Regression test for <https://github.com/rust-lang/rust/issues/141417>.
17+
pub fn by_ref(x: unsafe<'a> &'a S) -> usize {
18+
unsafe { (|| unwrap_binder!(x).0[0])() }
19+
}
20+
21+
fn main() {}

0 commit comments

Comments
 (0)