From a9edbfda3287ea0012283f729c5893f5ff11d537 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 8 Apr 2024 10:36:15 +0000 Subject: [PATCH] Stop exporting `TypeckRootCtxt` and `FnCtxt`. While they have many convenient APIs, it is better to expose dedicated functions for them --- compiler/rustc_hir_typeck/src/cast.rs | 41 +++++++++++++++---- compiler/rustc_hir_typeck/src/coercion.rs | 14 +++++++ compiler/rustc_hir_typeck/src/expr.rs | 10 +---- compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs | 2 +- compiler/rustc_hir_typeck/src/lib.rs | 5 ++- .../rustc_hir_typeck/src/typeck_root_ctxt.rs | 2 +- .../src/methods/unnecessary_to_owned.rs | 5 +-- .../transmutes_expressible_as_ptr_casts.rs | 4 +- .../clippy_lints/src/transmute/utils.rs | 37 ----------------- 9 files changed, 57 insertions(+), 63 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index c948b6343b7..07d64918e8b 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -40,17 +40,19 @@ use rustc_middle::mir::Mutability; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::cast::{CastKind, CastTy}; use rustc_middle::ty::error::TypeError; +use rustc_middle::ty::TyCtxt; use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitableExt, VariantDef}; use rustc_session::lint; use rustc_span::def_id::{DefId, LOCAL_CRATE}; use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::DUMMY_SP; use rustc_trait_selection::infer::InferCtxtExt; /// Reifies a cast check to be checked once we have full type information for /// a function context. #[derive(Debug)] -pub struct CastCheck<'tcx> { +pub(crate) struct CastCheck<'tcx> { /// The expression whose value is being casted expr: &'tcx hir::Expr<'tcx>, /// The source type for the cast expression @@ -60,8 +62,6 @@ pub struct CastCheck<'tcx> { cast_ty: Ty<'tcx>, cast_span: Span, span: Span, - /// whether the cast is made in a const context or not. - pub constness: hir::Constness, } /// The kind of pointer and associated metadata (thin, length or vtable) - we @@ -194,18 +194,45 @@ fn make_invalid_casting_error<'a, 'tcx>( ) } +/// If a cast from `from_ty` to `to_ty` is valid, returns a `Some` containing the kind +/// of the cast. +/// +/// This is a helper used from clippy. +pub fn check_cast<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + e: &'tcx hir::Expr<'tcx>, + from_ty: Ty<'tcx>, + to_ty: Ty<'tcx>, +) -> Option { + let hir_id = e.hir_id; + let local_def_id = hir_id.owner.def_id; + + let root_ctxt = crate::TypeckRootCtxt::new(tcx, local_def_id); + let fn_ctxt = FnCtxt::new(&root_ctxt, param_env, local_def_id); + + if let Ok(check) = CastCheck::new( + &fn_ctxt, e, from_ty, to_ty, + // We won't show any errors to the user, so the span is irrelevant here. + DUMMY_SP, DUMMY_SP, + ) { + check.do_check(&fn_ctxt).ok() + } else { + None + } +} + impl<'a, 'tcx> CastCheck<'tcx> { - pub fn new( + pub(crate) fn new( fcx: &FnCtxt<'a, 'tcx>, expr: &'tcx hir::Expr<'tcx>, expr_ty: Ty<'tcx>, cast_ty: Ty<'tcx>, cast_span: Span, span: Span, - constness: hir::Constness, ) -> Result, ErrorGuaranteed> { let expr_span = expr.span.find_ancestor_inside(span).unwrap_or(expr.span); - let check = CastCheck { expr, expr_ty, expr_span, cast_ty, cast_span, span, constness }; + let check = CastCheck { expr, expr_ty, expr_span, cast_ty, cast_span, span }; // For better error messages, check for some obviously unsized // cases now. We do a more thorough check at the end, once @@ -644,7 +671,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { /// Checks a cast, and report an error if one exists. In some cases, this /// can return Ok and create type errors in the fcx rather than returning /// directly. coercion-cast is handled in check instead of here. - pub fn do_check(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result { + fn do_check(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result { use rustc_middle::ty::cast::CastTy::*; use rustc_middle::ty::cast::IntTy::*; diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 44b19318d5d..51d01afc4eb 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1318,6 +1318,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } +/// Check whether `ty` can be coerced to `output_ty`. +/// Used from clippy. +pub fn can_coerce<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + body_id: LocalDefId, + ty: Ty<'tcx>, + output_ty: Ty<'tcx>, +) -> bool { + let root_ctxt = crate::typeck_root_ctxt::TypeckRootCtxt::new(tcx, body_id); + let fn_ctxt = FnCtxt::new(&root_ctxt, param_env, body_id); + fn_ctxt.can_coerce(ty, output_ty) +} + /// CoerceMany encapsulates the pattern you should use when you have /// many expressions that are all getting coerced to a common /// type. This arises, for example, when you have a match (the result diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 4da45303d12..d3df3dd3885 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1390,15 +1390,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { // Defer other checks until we're done type checking. let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut(); - match cast::CastCheck::new( - self, - e, - t_expr, - t_cast, - t.span, - expr.span, - hir::Constness::NotConst, - ) { + match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) { Ok(cast_check) => { debug!( "check_expr_cast: deferring cast from {:?} to {:?}: {:?}", diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 05e7c5b2b41..0b69c7a2431 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -38,7 +38,7 @@ use std::ops::Deref; /// /// [`ItemCtxt`]: rustc_hir_analysis::collect::ItemCtxt /// [`InferCtxt`]: infer::InferCtxt -pub struct FnCtxt<'a, 'tcx> { +pub(crate) struct FnCtxt<'a, 'tcx> { pub(super) body_id: LocalDefId, /// The parameter environment used for proving trait obligations diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 80fd4be53e1..700dde184f2 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -42,8 +42,9 @@ mod typeck_root_ctxt; mod upvar; mod writeback; -pub use fn_ctxt::FnCtxt; -pub use typeck_root_ctxt::TypeckRootCtxt; +pub use coercion::can_coerce; +use fn_ctxt::FnCtxt; +use typeck_root_ctxt::TypeckRootCtxt; use crate::check::check_fn; use crate::coercion::DynamicCoerceMany; diff --git a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs index e493e6a0a7e..88777bf5b02 100644 --- a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs +++ b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs @@ -27,7 +27,7 @@ use std::ops::Deref; /// `bar()` will each have their own `FnCtxt`, but they will /// share the inference context, will process obligations together, /// can access each other's local types (scoping permitted), etc. -pub struct TypeckRootCtxt<'tcx> { +pub(crate) struct TypeckRootCtxt<'tcx> { pub(super) infcx: InferCtxt<'tcx>, pub(super) typeck_results: RefCell>, diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs index 23fc323446e..d3347466be9 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -12,7 +12,6 @@ use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{BorrowKind, Expr, ExprKind, ItemKind, LangItem, Node}; -use rustc_hir_typeck::{FnCtxt, TypeckRootCtxt}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; use rustc_middle::mir::Mutability; @@ -437,9 +436,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< Node::Item(item) => { if let ItemKind::Fn(_, _, body_id) = &item.kind && let output_ty = return_ty(cx, item.owner_id) - && let root_ctxt = TypeckRootCtxt::new(cx.tcx, item.owner_id.def_id) - && let fn_ctxt = FnCtxt::new(&root_ctxt, cx.param_env, item.owner_id.def_id) - && fn_ctxt.can_coerce(ty, output_ty) + && rustc_hir_typeck::can_coerce(cx.tcx, cx.param_env, item.owner_id.def_id, ty, output_ty) { if has_lifetime(output_ty) && has_lifetime(ty) { return false; diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs b/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs index 6f5ac625e35..a6a6e9a3bac 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs @@ -1,4 +1,4 @@ -use super::utils::check_cast; +use rustc_hir_typeck::cast::check_cast; use super::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::sugg::Sugg; @@ -22,7 +22,7 @@ pub(super) fn check<'tcx>( ) -> bool { use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast}; let mut app = Applicability::MachineApplicable; - let mut sugg = match check_cast(cx, e, from_ty, to_ty) { + let mut sugg = match check_cast(cx.tcx, cx.param_env, e, from_ty, to_ty) { Some(FnPtrAddrCast | PtrAddrCast) if const_context => return false, Some(PtrPtrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast) => { Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut app) diff --git a/src/tools/clippy/clippy_lints/src/transmute/utils.rs b/src/tools/clippy/clippy_lints/src/transmute/utils.rs index 15f1890aa39..e8ccd35b4da 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/utils.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/utils.rs @@ -1,10 +1,5 @@ -use rustc_hir as hir; -use rustc_hir::Expr; -use rustc_hir_typeck::{cast, FnCtxt, TypeckRootCtxt}; use rustc_lint::LateContext; -use rustc_middle::ty::cast::CastKind; use rustc_middle::ty::Ty; -use rustc_span::DUMMY_SP; // check if the component types of the transmuted collection and the result have different ABI, // size or alignment @@ -20,35 +15,3 @@ pub(super) fn is_layout_incompatible<'tcx>(cx: &LateContext<'tcx>, from: Ty<'tcx false } } - -/// If a cast from `from_ty` to `to_ty` is valid, returns an Ok containing the kind of -/// the cast. In certain cases, including some invalid casts from array references -/// to pointers, this may cause additional errors to be emitted and/or ICE error -/// messages. This function will panic if that occurs. -pub(super) fn check_cast<'tcx>( - cx: &LateContext<'tcx>, - e: &'tcx Expr<'_>, - from_ty: Ty<'tcx>, - to_ty: Ty<'tcx>, -) -> Option { - let hir_id = e.hir_id; - let local_def_id = hir_id.owner.def_id; - - let root_ctxt = TypeckRootCtxt::new(cx.tcx, local_def_id); - let fn_ctxt = FnCtxt::new(&root_ctxt, cx.param_env, local_def_id); - - if let Ok(check) = cast::CastCheck::new( - &fn_ctxt, - e, - from_ty, - to_ty, - // We won't show any error to the user, so we don't care what the span is here. - DUMMY_SP, - DUMMY_SP, - hir::Constness::NotConst, - ) { - check.do_check(&fn_ctxt).ok() - } else { - None - } -}