diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 96ede89664fea..b2255c8d9679a 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -234,7 +234,7 @@ impl<'tcx> TypeInformationCtxt<'tcx> for (&LateContext<'tcx>, LocalDefId) { type Error = !; fn typeck_results(&self) -> Self::TypeckResults<'_> { - self.0.maybe_typeck_results().expect("expected typeck results") + self.0.typeck_results() } fn structurally_resolve_type(&self, _span: Span, ty: Ty<'tcx>) -> Ty<'tcx> { diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index e992f1ed385e7..84166ed589ad1 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -3,7 +3,6 @@ //! See for an //! overview of how lints are implemented. -use std::cell::Cell; use std::slice; use rustc_abi as abi; @@ -484,11 +483,8 @@ pub struct LateContext<'tcx> { /// Current body, or `None` if outside a body. pub enclosing_body: Option, - /// Type-checking results for the current body. Access using the `typeck_results` - /// and `maybe_typeck_results` methods, which handle querying the typeck results on demand. - // FIXME(eddyb) move all the code accessing internal fields like this, - // to this module, to avoid exposing it to lint logic. - pub(super) cached_typeck_results: Cell>>, + /// Type-checking results for the current body. + pub typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>, /// Parameter environment for the item we are in. pub param_env: ty::ParamEnv<'tcx>, @@ -663,24 +659,13 @@ impl<'tcx> LateContext<'tcx> { 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>> { - self.cached_typeck_results.get().or_else(|| { - self.enclosing_body.map(|body| { - let typeck_results = self.tcx.typeck_body(body); - self.cached_typeck_results.set(Some(typeck_results)); - typeck_results - }) - }) - } - /// Gets the type-checking results for the current body. /// As this will ICE if called outside bodies, only call when working with /// `Expr` or `Pat` nodes (they are guaranteed to be found only in bodies). + #[inline] #[track_caller] pub fn typeck_results(&self) -> &'tcx ty::TypeckResults<'tcx> { - self.maybe_typeck_results().expect("`LateContext::typeck_results` called outside of body") + self.typeck_results.expect("`LateContext::typeck_results` called outside of body") } /// Returns the final resolution of a `QPath`, or `Res::Err` if unavailable. @@ -690,7 +675,7 @@ impl<'tcx> LateContext<'tcx> { match *qpath { hir::QPath::Resolved(_, path) => path.res, hir::QPath::TypeRelative(..) => self - .maybe_typeck_results() + .typeck_results .filter(|typeck_results| typeck_results.hir_owner == id.owner) .or_else(|| { self.tcx diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index b8eb4910df248..b330c7859794b 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -4,7 +4,6 @@ //! borrow checking, etc.). These lints have full type information available. use std::any::Any; -use std::cell::Cell; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::sync::par_join; @@ -37,6 +36,12 @@ macro_rules! lint_callback { ($cx:expr, $f:ident, $($args:expr),*) => ({ struct LateContextAndPass<'tcx, T: LateLintPass<'tcx>> { context: LateContext<'tcx>, pass: T, + + /// Rustdoc parses functions which are behind failing `#[cfg]` checks and may not pass + /// type checking. See: + /// Inlined from the session variables to avoid the indirection and cache pressure in the + /// lint visitor. + actually_rustdoc: bool, } impl<'tcx, T: LateLintPass<'tcx>> LateContextAndPass<'tcx, T> { @@ -89,23 +94,18 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas fn visit_nested_body(&mut self, body_id: hir::BodyId) { let old_enclosing_body = self.context.enclosing_body.replace(body_id); - let old_cached_typeck_results = self.context.cached_typeck_results.get(); + let old_typeck_results = self.context.typeck_results; - // HACK(eddyb) avoid trashing `cached_typeck_results` when we're - // nested in `visit_fn`, which may have already resulted in them - // being queried. - if old_enclosing_body != Some(body_id) { - self.context.cached_typeck_results.set(None); + // The body and typeck results are also set in `visit_fn`. + // Only fetch the results if this is for a new body. + if old_enclosing_body != Some(body_id) && !self.actually_rustdoc { + self.context.typeck_results = Some(self.context.tcx.typeck_body(body_id)); } let body = self.context.tcx.hir_body(body_id); self.visit_body(body); self.context.enclosing_body = old_enclosing_body; - - // See HACK comment above. - if old_enclosing_body != Some(body_id) { - self.context.cached_typeck_results.set(old_cached_typeck_results); - } + self.context.typeck_results = old_typeck_results; } fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { @@ -123,7 +123,7 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) { let generics = self.context.generics.take(); self.context.generics = it.kind.generics(); - let old_cached_typeck_results = self.context.cached_typeck_results.take(); + let old_typeck_results = self.context.typeck_results.take(); let old_enclosing_body = self.context.enclosing_body.take(); self.with_lint_attrs(it.hir_id(), |cx| { cx.with_param_env(it.owner_id, |cx| { @@ -133,7 +133,7 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas }); }); self.context.enclosing_body = old_enclosing_body; - self.context.cached_typeck_results.set(old_cached_typeck_results); + self.context.typeck_results = old_typeck_results; self.context.generics = generics; } @@ -189,12 +189,15 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas // Wrap in typeck results here, not just in visit_nested_body, // in order for `check_fn` to be able to use them. let old_enclosing_body = self.context.enclosing_body.replace(body_id); - let old_cached_typeck_results = self.context.cached_typeck_results.take(); + let old_typeck_results = self.context.typeck_results; + if !self.actually_rustdoc { + self.context.typeck_results = Some(self.context.tcx.typeck_body(body_id)); + } let body = self.context.tcx.hir_body(body_id); lint_callback!(self, check_fn, fk, decl, body, span, id); hir_visit::walk_fn(self, fk, decl, body_id, id); self.context.enclosing_body = old_enclosing_body; - self.context.cached_typeck_results.set(old_cached_typeck_results); + self.context.typeck_results = old_typeck_results; } fn visit_variant_data(&mut self, s: &'tcx hir::VariantData<'tcx>) { @@ -341,7 +344,7 @@ pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>( let context = LateContext { tcx, enclosing_body: None, - cached_typeck_results: Cell::new(None), + typeck_results: None, param_env: ty::ParamEnv::empty(), effective_visibilities: tcx.effective_visibilities(()), last_node_with_lint_attrs: tcx.local_def_id_to_hir_id(mod_id), @@ -380,7 +383,11 @@ fn late_lint_mod_inner<'tcx, T: LateLintPass<'tcx>>( context: LateContext<'tcx>, pass: T, ) { - let mut cx = LateContextAndPass { context, pass }; + let mut cx = LateContextAndPass::<'tcx, T> { + context, + pass, + actually_rustdoc: tcx.sess.opts.actually_rustdoc, + }; let (module, _span, hir_id) = tcx.hir_get_module(mod_id); @@ -415,7 +422,7 @@ fn late_lint_crate<'tcx>(tcx: TyCtxt<'tcx>) { let context = LateContext { tcx, enclosing_body: None, - cached_typeck_results: Cell::new(None), + typeck_results: None, param_env: ty::ParamEnv::empty(), effective_visibilities: tcx.effective_visibilities(()), last_node_with_lint_attrs: hir::CRATE_HIR_ID, @@ -424,7 +431,8 @@ fn late_lint_crate<'tcx>(tcx: TyCtxt<'tcx>) { }; let pass = RuntimeCombinedLateLintPass { passes }; - let mut cx = LateContextAndPass { context, pass }; + let mut cx = + LateContextAndPass { context, pass, actually_rustdoc: tcx.sess.opts.actually_rustdoc }; // Visit the whole crate. cx.with_lint_attrs(hir::CRATE_HIR_ID, |cx| { diff --git a/compiler/rustc_lint/src/unit_bindings.rs b/compiler/rustc_lint/src/unit_bindings.rs index ed015908ae54a..61c4a95c995b4 100644 --- a/compiler/rustc_lint/src/unit_bindings.rs +++ b/compiler/rustc_lint/src/unit_bindings.rs @@ -53,7 +53,7 @@ impl<'tcx> LateLintPass<'tcx> for UnitBindings { // - explicitly wrote `let pat = ();` // - explicitly wrote `let () = init;`. if !local.span.from_expansion() - && let Some(tyck_results) = cx.maybe_typeck_results() + && let Some(tyck_results) = cx.typeck_results && let Some(init) = local.init && let init_ty = tyck_results.expr_ty(init) && let local_ty = tyck_results.node_type(local.hir_id) diff --git a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs index f3952b2687a56..c2dd6e681b002 100644 --- a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs +++ b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs @@ -78,7 +78,7 @@ fn check_raw_ptr<'tcx>( fn raw_ptr_arg(cx: &LateContext<'_>, arg: &hir::Param<'_>) -> Option { if let (&hir::PatKind::Binding(_, id, _, _), Some(&ty::RawPtr(_, _))) = ( &arg.pat.kind, - cx.maybe_typeck_results() + cx.typeck_results .map(|typeck_results| typeck_results.pat_ty(arg.pat).kind()), ) { Some(id) diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs index bf2c7a007644c..03a48bc08612a 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs @@ -303,7 +303,7 @@ impl<'a, 'b, 'tcx> ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> { fn new(cx: &'a LateContext<'tcx>, target: &'b ImplicitHasherType<'tcx>) -> Self { Self { cx, - maybe_typeck_results: cx.maybe_typeck_results(), + maybe_typeck_results: cx.typeck_results, target, suggestions: BTreeMap::new(), } diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs index 039da4cc4757a..d8bff9e9f1703 100644 --- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs +++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs @@ -174,7 +174,7 @@ impl PassByRefOrValue { && size <= self.ref_min_size && let hir::TyKind::Ref(_, MutTy { ty: decl_ty, .. }) = input.kind { - if let Some(typeck) = cx.maybe_typeck_results() + if let Some(typeck) = cx.typeck_results // Don't lint if a raw pointer is created. // TODO: Limit the check only to raw pointers to the argument (or part of the argument) // which escape the current function. diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 7c3fa51228bc9..e9695668d75c1 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -69,7 +69,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { pub fn new(cx: &'a LateContext<'tcx>) -> Self { Self { cx, - maybe_typeck_results: cx.maybe_typeck_results().map(|x| (x, x)), + maybe_typeck_results: cx.typeck_results.map(|x| (x, x)), allow_side_effects: true, expr_fallback: None, path_check: PathCheck::default(), @@ -1140,7 +1140,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { pub fn new(cx: &'a LateContext<'tcx>) -> Self { Self { cx, - maybe_typeck_results: cx.maybe_typeck_results(), + maybe_typeck_results: cx.typeck_results, s: FxHasher::default(), path_check: PathCheck::default(), } diff --git a/src/tools/clippy/clippy_utils/src/res.rs b/src/tools/clippy/clippy_utils/src/res.rs index 23afb25f1bbfe..59571a929887a 100644 --- a/src/tools/clippy/clippy_utils/src/res.rs +++ b/src/tools/clippy/clippy_utils/src/res.rs @@ -72,7 +72,7 @@ impl<'tcx> MaybeTypeckRes<'tcx> for LateContext<'tcx> { #[inline] #[cfg_attr(debug_assertions, track_caller)] fn typeck_res(&self) -> Option<&TypeckResults<'tcx>> { - if let Some(typeck) = self.maybe_typeck_results() { + if let Some(typeck) = self.typeck_results { Some(typeck) } else { // It's possible to get the `TypeckResults` for any other body, but diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs index f9a21deeca19d..14054e8d96d43 100644 --- a/src/tools/clippy/clippy_utils/src/ty/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs @@ -41,7 +41,7 @@ pub use type_certainty::expr_type_is_certain; /// Lower a [`hir::Ty`] to a [`rustc_middle::ty::Ty`]. pub fn ty_from_hir_ty<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { - cx.maybe_typeck_results() + cx.typeck_results .filter(|results| results.hir_owner == hir_ty.hir_id.owner) .and_then(|results| results.node_type_opt(hir_ty.hir_id)) .unwrap_or_else(|| lower_ty(cx.tcx, hir_ty))