mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-14 04:56:49 +00:00
Account for UseCloned on expr_use_visitor
This commit is contained in:
parent
edcbc9b535
commit
b43b700250
@ -47,6 +47,21 @@ pub trait Delegate<'tcx> {
|
||||
/// the id of the binding in the pattern `pat`.
|
||||
fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId);
|
||||
|
||||
/// The value found at `place` is used, depending
|
||||
/// on `mode`. Where `diag_expr_id` is the id used for diagnostics for `place`.
|
||||
///
|
||||
/// Use of a `Copy` type in a ByUse context is considered a use
|
||||
/// by `ImmBorrow` and `borrow` is called instead. This is because
|
||||
/// a shared borrow is the "minimum access" that would be needed
|
||||
/// to perform a copy.
|
||||
///
|
||||
///
|
||||
/// The parameter `diag_expr_id` indicates the HIR id that ought to be used for
|
||||
/// diagnostics. Around pattern matching such as `let pat = expr`, the diagnostic
|
||||
/// id will be the id of the expression `expr` but the place itself will have
|
||||
/// the id of the binding in the pattern `pat`.
|
||||
fn use_cloned(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId);
|
||||
|
||||
/// The value found at `place` is being borrowed with kind `bk`.
|
||||
/// `diag_expr_id` is the id used for diagnostics (see `consume` for more details).
|
||||
fn borrow(
|
||||
@ -91,6 +106,10 @@ impl<'tcx, D: Delegate<'tcx>> Delegate<'tcx> for &mut D {
|
||||
(**self).consume(place_with_id, diag_expr_id)
|
||||
}
|
||||
|
||||
fn use_cloned(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
|
||||
(**self).use_cloned(place_with_id, diag_expr_id)
|
||||
}
|
||||
|
||||
fn borrow(
|
||||
&mut self,
|
||||
place_with_id: &PlaceWithHirId<'tcx>,
|
||||
@ -143,6 +162,8 @@ pub trait TypeInformationCtxt<'tcx> {
|
||||
|
||||
fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool;
|
||||
|
||||
fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool;
|
||||
|
||||
fn body_owner_def_id(&self) -> LocalDefId;
|
||||
|
||||
fn tcx(&self) -> TyCtxt<'tcx>;
|
||||
@ -184,6 +205,10 @@ impl<'tcx> TypeInformationCtxt<'tcx> for &FnCtxt<'_, 'tcx> {
|
||||
self.infcx.type_is_copy_modulo_regions(self.param_env, ty)
|
||||
}
|
||||
|
||||
fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
|
||||
self.infcx.type_is_use_cloned_modulo_regions(self.param_env, ty)
|
||||
}
|
||||
|
||||
fn body_owner_def_id(&self) -> LocalDefId {
|
||||
self.body_id
|
||||
}
|
||||
@ -230,6 +255,10 @@ impl<'tcx> TypeInformationCtxt<'tcx> for (&LateContext<'tcx>, LocalDefId) {
|
||||
self.0.type_is_copy_modulo_regions(ty)
|
||||
}
|
||||
|
||||
fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
|
||||
self.0.type_is_use_cloned_modulo_regions(ty)
|
||||
}
|
||||
|
||||
fn body_owner_def_id(&self) -> LocalDefId {
|
||||
self.1
|
||||
}
|
||||
@ -313,6 +342,23 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn consume_or_clone_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> {
|
||||
debug!("consume_or_clone_expr(expr={:?})", expr);
|
||||
|
||||
let place_with_id = self.cat_expr(expr)?;
|
||||
|
||||
if self.cx.type_is_copy_modulo_regions(place_with_id.place.ty()) {
|
||||
self.delegate.borrow_mut().copy(&place_with_id, place_with_id.hir_id);
|
||||
} else if self.cx.type_is_use_cloned_modulo_regions(place_with_id.place.ty()) {
|
||||
self.delegate.borrow_mut().use_cloned(&place_with_id, place_with_id.hir_id);
|
||||
} else {
|
||||
self.delegate.borrow_mut().consume(&place_with_id, place_with_id.hir_id);
|
||||
}
|
||||
|
||||
self.walk_expr(expr)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn mutate_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> {
|
||||
let place_with_id = self.cat_expr(expr)?;
|
||||
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
|
||||
}
|
||||
|
||||
hir::ExprKind::Use(expr, _) => {
|
||||
self.consume_expr(expr)?;
|
||||
self.consume_or_clone_expr(expr)?;
|
||||
}
|
||||
|
||||
hir::ExprKind::MethodCall(.., receiver, args, _) => {
|
||||
|
@ -2045,6 +2045,21 @@ impl<'tcx> euv::Delegate<'tcx> for InferBorrowKind<'tcx> {
|
||||
));
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn use_cloned(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
|
||||
let PlaceBase::Upvar(upvar_id) = place_with_id.place.base else { return };
|
||||
assert_eq!(self.closure_def_id, upvar_id.closure_expr_id);
|
||||
|
||||
self.capture_information.push((
|
||||
place_with_id.place.clone(),
|
||||
ty::CaptureInfo {
|
||||
capture_kind_expr_id: Some(diag_expr_id),
|
||||
path_expr_id: Some(diag_expr_id),
|
||||
capture_kind: ty::UpvarCapture::ByUse,
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn borrow(
|
||||
&mut self,
|
||||
|
@ -683,6 +683,10 @@ impl<'tcx> LateContext<'tcx> {
|
||||
self.tcx.type_is_copy_modulo_regions(self.typing_env(), ty)
|
||||
}
|
||||
|
||||
pub fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
|
||||
self.tcx.type_is_use_cloned_modulo_regions(self.typing_env(), ty)
|
||||
}
|
||||
|
||||
/// Gets the type-checking results for the current body,
|
||||
/// or `None` if outside a body.
|
||||
pub fn maybe_typeck_results(&self) -> Option<&'tcx ty::TypeckResults<'tcx>> {
|
||||
|
@ -1533,6 +1533,11 @@ rustc_queries! {
|
||||
query is_copy_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
|
||||
desc { "computing whether `{}` is `Copy`", env.value }
|
||||
}
|
||||
/// Trait selection queries. These are best used by invoking `ty.is_use_cloned_modulo_regions()`,
|
||||
/// `ty.is_use_cloned()`, etc, since that will prune the environment where possible.
|
||||
query is_use_cloned_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
|
||||
desc { "computing whether `{}` is `UseCloned`", env.value }
|
||||
}
|
||||
/// Query backing `Ty::is_sized`.
|
||||
query is_sized_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
|
||||
desc { "computing whether `{}` is `Sized`", env.value }
|
||||
|
@ -192,6 +192,18 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
ty.is_trivially_pure_clone_copy() || self.is_copy_raw(typing_env.as_query_input(ty))
|
||||
}
|
||||
|
||||
/// Checks whether `ty: UseCloned` holds while ignoring region constraints.
|
||||
///
|
||||
/// This function should not be used if there is an `InferCtxt` available.
|
||||
/// Use `InferCtxt::type_is_copy_modulo_regions` instead.
|
||||
pub fn type_is_use_cloned_modulo_regions(
|
||||
self,
|
||||
typing_env: ty::TypingEnv<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> bool {
|
||||
ty.is_trivially_pure_clone_copy() || self.is_use_cloned_raw(typing_env.as_query_input(ty))
|
||||
}
|
||||
|
||||
/// Returns the deeply last field of nested structures, or the same type if
|
||||
/// not a structure at all. Corresponds to the only possible unsized field,
|
||||
/// and its type can be used to determine unsizing strategy.
|
||||
|
@ -10,6 +10,13 @@ fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, Ty
|
||||
is_item_raw(tcx, query, LangItem::Copy)
|
||||
}
|
||||
|
||||
fn is_use_cloned_raw<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>,
|
||||
) -> bool {
|
||||
is_item_raw(tcx, query, LangItem::UseCloned)
|
||||
}
|
||||
|
||||
fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
|
||||
is_item_raw(tcx, query, LangItem::Sized)
|
||||
}
|
||||
@ -33,5 +40,12 @@ fn is_item_raw<'tcx>(
|
||||
}
|
||||
|
||||
pub(crate) fn provide(providers: &mut Providers) {
|
||||
*providers = Providers { is_copy_raw, is_sized_raw, is_freeze_raw, is_unpin_raw, ..*providers };
|
||||
*providers = Providers {
|
||||
is_copy_raw,
|
||||
is_use_cloned_raw,
|
||||
is_sized_raw,
|
||||
is_freeze_raw,
|
||||
is_unpin_raw,
|
||||
..*providers
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user