Skip to content

Commit a5cb5f9

Browse files
committed
Account for UseCloned on expr_use_visitor
1 parent 98d51f1 commit a5cb5f9

File tree

6 files changed

+98
-2
lines changed

6 files changed

+98
-2
lines changed

compiler/rustc_hir_typeck/src/expr_use_visitor.rs

+47-1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,21 @@ pub trait Delegate<'tcx> {
4747
/// the id of the binding in the pattern `pat`.
4848
fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId);
4949

50+
/// The value found at `place` is moved, depending
51+
/// on `mode`. Where `diag_expr_id` is the id used for diagnostics for `place`.
52+
///
53+
/// Use of a `Copy` type in a ByValue context is considered a use
54+
/// by `ImmBorrow` and `borrow` is called instead. This is because
55+
/// a shared borrow is the "minimum access" that would be needed
56+
/// to perform a copy.
57+
///
58+
///
59+
/// The parameter `diag_expr_id` indicates the HIR id that ought to be used for
60+
/// diagnostics. Around pattern matching such as `let pat = expr`, the diagnostic
61+
/// id will be the id of the expression `expr` but the place itself will have
62+
/// the id of the binding in the pattern `pat`.
63+
fn use_cloned(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId);
64+
5065
/// The value found at `place` is being borrowed with kind `bk`.
5166
/// `diag_expr_id` is the id used for diagnostics (see `consume` for more details).
5267
fn borrow(
@@ -91,6 +106,10 @@ impl<'tcx, D: Delegate<'tcx>> Delegate<'tcx> for &mut D {
91106
(**self).consume(place_with_id, diag_expr_id)
92107
}
93108

109+
fn use_cloned(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
110+
(**self).use_cloned(place_with_id, diag_expr_id)
111+
}
112+
94113
fn borrow(
95114
&mut self,
96115
place_with_id: &PlaceWithHirId<'tcx>,
@@ -143,6 +162,8 @@ pub trait TypeInformationCtxt<'tcx> {
143162

144163
fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool;
145164

165+
fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool;
166+
146167
fn body_owner_def_id(&self) -> LocalDefId;
147168

148169
fn tcx(&self) -> TyCtxt<'tcx>;
@@ -184,6 +205,10 @@ impl<'tcx> TypeInformationCtxt<'tcx> for &FnCtxt<'_, 'tcx> {
184205
self.infcx.type_is_copy_modulo_regions(self.param_env, ty)
185206
}
186207

208+
fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
209+
self.infcx.type_is_use_cloned_modulo_regions(self.param_env, ty)
210+
}
211+
187212
fn body_owner_def_id(&self) -> LocalDefId {
188213
self.body_id
189214
}
@@ -230,6 +255,10 @@ impl<'tcx> TypeInformationCtxt<'tcx> for (&LateContext<'tcx>, LocalDefId) {
230255
self.0.type_is_copy_modulo_regions(ty)
231256
}
232257

258+
fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
259+
self.0.type_is_use_cloned_modulo_regions(ty)
260+
}
261+
233262
fn body_owner_def_id(&self) -> LocalDefId {
234263
self.1
235264
}
@@ -313,6 +342,23 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
313342
Ok(())
314343
}
315344

345+
pub fn consume_or_clone_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> {
346+
debug!("consume_or_clone_expr(expr={:?})", expr);
347+
348+
let place_with_id = self.cat_expr(expr)?;
349+
350+
if self.cx.type_is_copy_modulo_regions(place_with_id.place.ty()) {
351+
self.delegate.borrow_mut().copy(&place_with_id, place_with_id.hir_id);
352+
} else if self.cx.type_is_use_cloned_modulo_regions(place_with_id.place.ty()) {
353+
self.delegate.borrow_mut().use_cloned(&place_with_id, place_with_id.hir_id);
354+
} else {
355+
self.delegate.borrow_mut().consume(&place_with_id, place_with_id.hir_id);
356+
}
357+
358+
self.walk_expr(expr)?;
359+
Ok(())
360+
}
361+
316362
fn mutate_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> {
317363
let place_with_id = self.cat_expr(expr)?;
318364
self.delegate.borrow_mut().mutate(&place_with_id, place_with_id.hir_id);
@@ -367,7 +413,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
367413
}
368414

369415
hir::ExprKind::Use(expr, _) => {
370-
self.consume_expr(expr)?;
416+
self.consume_or_clone_expr(expr)?;
371417
}
372418

373419
hir::ExprKind::MethodCall(.., receiver, args, _) => {

compiler/rustc_hir_typeck/src/upvar.rs

+15
Original file line numberDiff line numberDiff line change
@@ -2045,6 +2045,21 @@ impl<'tcx> euv::Delegate<'tcx> for InferBorrowKind<'tcx> {
20452045
));
20462046
}
20472047

2048+
#[instrument(skip(self), level = "debug")]
2049+
fn use_cloned(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
2050+
let PlaceBase::Upvar(upvar_id) = place_with_id.place.base else { return };
2051+
assert_eq!(self.closure_def_id, upvar_id.closure_expr_id);
2052+
2053+
self.capture_information.push((
2054+
place_with_id.place.clone(),
2055+
ty::CaptureInfo {
2056+
capture_kind_expr_id: Some(diag_expr_id),
2057+
path_expr_id: Some(diag_expr_id),
2058+
capture_kind: ty::UpvarCapture::ByUse,
2059+
},
2060+
));
2061+
}
2062+
20482063
#[instrument(skip(self), level = "debug")]
20492064
fn borrow(
20502065
&mut self,

compiler/rustc_lint/src/context.rs

+4
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,10 @@ impl<'tcx> LateContext<'tcx> {
685685
self.tcx.type_is_copy_modulo_regions(self.typing_env(), ty)
686686
}
687687

688+
pub fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
689+
self.tcx.type_is_use_cloned_modulo_regions(self.typing_env(), ty)
690+
}
691+
688692
/// Gets the type-checking results for the current body,
689693
/// or `None` if outside a body.
690694
pub fn maybe_typeck_results(&self) -> Option<&'tcx ty::TypeckResults<'tcx>> {

compiler/rustc_middle/src/query/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -1519,6 +1519,11 @@ rustc_queries! {
15191519
query is_copy_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
15201520
desc { "computing whether `{}` is `Copy`", env.value }
15211521
}
1522+
/// Trait selection queries. These are best used by invoking `ty.is_use_cloned_modulo_regions()`,
1523+
/// `ty.is_use_cloned()`, etc, since that will prune the environment where possible.
1524+
query is_use_cloned_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
1525+
desc { "computing whether `{}` is `Copy`", env.value }
1526+
}
15221527
/// Query backing `Ty::is_sized`.
15231528
query is_sized_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
15241529
desc { "computing whether `{}` is `Sized`", env.value }

compiler/rustc_middle/src/ty/util.rs

+12
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,18 @@ impl<'tcx> TyCtxt<'tcx> {
192192
ty.is_trivially_pure_clone_copy() || self.is_copy_raw(typing_env.as_query_input(ty))
193193
}
194194

195+
/// Checks whether `ty: UseCloned` holds while ignoring region constraints.
196+
///
197+
/// This function should not be used if there is an `InferCtxt` available.
198+
/// Use `InferCtxt::type_is_copy_modulo_regions` instead.
199+
pub fn type_is_use_cloned_modulo_regions(
200+
self,
201+
typing_env: ty::TypingEnv<'tcx>,
202+
ty: Ty<'tcx>,
203+
) -> bool {
204+
ty.is_trivially_pure_clone_copy() || self.is_use_cloned_raw(typing_env.as_query_input(ty))
205+
}
206+
195207
/// Returns the deeply last field of nested structures, or the same type if
196208
/// not a structure at all. Corresponds to the only possible unsized field,
197209
/// and its type can be used to determine unsizing strategy.

compiler/rustc_ty_utils/src/common_traits.rs

+15-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@ fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, Ty
1010
is_item_raw(tcx, query, LangItem::Copy)
1111
}
1212

13+
fn is_use_cloned_raw<'tcx>(
14+
tcx: TyCtxt<'tcx>,
15+
query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>,
16+
) -> bool {
17+
is_item_raw(tcx, query, LangItem::UseCloned)
18+
}
19+
1320
fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
1421
is_item_raw(tcx, query, LangItem::Sized)
1522
}
@@ -33,5 +40,12 @@ fn is_item_raw<'tcx>(
3340
}
3441

3542
pub(crate) fn provide(providers: &mut Providers) {
36-
*providers = Providers { is_copy_raw, is_sized_raw, is_freeze_raw, is_unpin_raw, ..*providers };
43+
*providers = Providers {
44+
is_copy_raw,
45+
is_use_cloned_raw,
46+
is_sized_raw,
47+
is_freeze_raw,
48+
is_unpin_raw,
49+
..*providers
50+
};
3751
}

0 commit comments

Comments
 (0)