44//! borrow checking, etc.). These lints have full type information available.
55
66use std:: any:: Any ;
7- use std:: cell:: Cell ;
87
98use rustc_data_structures:: stack:: ensure_sufficient_stack;
109use rustc_data_structures:: sync:: par_join;
@@ -17,6 +16,7 @@ use rustc_session::lint::LintPass;
1716use rustc_span:: Span ;
1817use tracing:: debug;
1918
19+ use crate :: builtin:: MissingDoc ;
2020use crate :: passes:: LateLintPassObject ;
2121use crate :: { LateContext , LateLintPass , LintStore , is_lint_pass_required} ;
2222
@@ -34,12 +34,16 @@ macro_rules! lint_callback { ($cx:expr, $f:ident, $($args:expr),*) => ({
3434
3535/// Implements the AST traversal for late lint passes. `T` provides the
3636/// `check_*` methods.
37- struct LateContextAndPass < ' tcx , T : LateLintPass < ' tcx > > {
37+ ///
38+ /// `TYPECK_BODY` determines whether we fetch typeck results while walking the HIR tree.
39+ /// When set to `false` we do not ever assign to the `typeck_results` field during the
40+ /// tree walk. See [`lint_missing_docs`] for why this exists.
41+ struct LateContextAndPass < ' tcx , T : LateLintPass < ' tcx > , const TYPECK_BODY : bool > {
3842 context : LateContext < ' tcx > ,
3943 pass : T ,
4044}
4145
42- impl < ' tcx , T : LateLintPass < ' tcx > > LateContextAndPass < ' tcx , T > {
46+ impl < ' tcx , T : LateLintPass < ' tcx > , const TYPECK_BODY : bool > LateContextAndPass < ' tcx , T , TYPECK_BODY > {
4347 /// Merge the lints specified by any lint attributes into the
4448 /// current lint context, call the provided function, then reset the
4549 /// lints in effect to their previous state.
@@ -77,7 +81,9 @@ impl<'tcx, T: LateLintPass<'tcx>> LateContextAndPass<'tcx, T> {
7781 }
7882}
7983
80- impl < ' tcx , T : LateLintPass < ' tcx > > hir_visit:: Visitor < ' tcx > for LateContextAndPass < ' tcx , T > {
84+ impl < ' tcx , T : LateLintPass < ' tcx > , const TYPECK_BODY : bool > hir_visit:: Visitor < ' tcx >
85+ for LateContextAndPass < ' tcx , T , TYPECK_BODY >
86+ {
8187 type NestedFilter = nested_filter:: All ;
8288
8389 /// Because lints are scoped lexically, we want to walk nested
@@ -89,22 +95,19 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
8995
9096 fn visit_nested_body ( & mut self , body_id : hir:: BodyId ) {
9197 let old_enclosing_body = self . context . enclosing_body . replace ( body_id) ;
92- let old_cached_typeck_results = self . context . cached_typeck_results . get ( ) ;
98+ let old_typeck_results = self . context . typeck_results ;
9399
94- // HACK(eddyb) avoid trashing `cached_typeck_results` when we're
95- // nested in `visit_fn`, which may have already resulted in them
96- // being queried.
97- if old_enclosing_body != Some ( body_id) {
98- self . context . cached_typeck_results . set ( None ) ;
100+ // The body and typeck results are also set in `visit_fn`.
101+ // Only fetch the results if this is for a new body.
102+ if TYPECK_BODY && old_enclosing_body != Some ( body_id) {
103+ self . context . typeck_results = Some ( self . context . tcx . typeck_body ( body_id) ) ;
99104 }
100105
101106 let body = self . context . tcx . hir_body ( body_id) ;
102107 self . visit_body ( body) ;
103108 self . context . enclosing_body = old_enclosing_body;
104-
105- // See HACK comment above.
106- if old_enclosing_body != Some ( body_id) {
107- self . context . cached_typeck_results . set ( old_cached_typeck_results) ;
109+ if TYPECK_BODY {
110+ self . context . typeck_results = old_typeck_results;
108111 }
109112 }
110113
@@ -123,7 +126,10 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
123126 fn visit_item ( & mut self , it : & ' tcx hir:: Item < ' tcx > ) {
124127 let generics = self . context . generics . take ( ) ;
125128 self . context . generics = it. kind . generics ( ) ;
126- let old_cached_typeck_results = self . context . cached_typeck_results . take ( ) ;
129+ let old_typeck_results = self . context . typeck_results ;
130+ if TYPECK_BODY {
131+ self . context . typeck_results = None ;
132+ }
127133 let old_enclosing_body = self . context . enclosing_body . take ( ) ;
128134 self . with_lint_attrs ( it. hir_id ( ) , |cx| {
129135 cx. with_param_env ( it. owner_id , |cx| {
@@ -133,7 +139,9 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
133139 } ) ;
134140 } ) ;
135141 self . context . enclosing_body = old_enclosing_body;
136- self . context . cached_typeck_results . set ( old_cached_typeck_results) ;
142+ if TYPECK_BODY {
143+ self . context . typeck_results = old_typeck_results;
144+ }
137145 self . context . generics = generics;
138146 }
139147
@@ -189,12 +197,17 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
189197 // Wrap in typeck results here, not just in visit_nested_body,
190198 // in order for `check_fn` to be able to use them.
191199 let old_enclosing_body = self . context . enclosing_body . replace ( body_id) ;
192- let old_cached_typeck_results = self . context . cached_typeck_results . take ( ) ;
200+ let old_typeck_results = self . context . typeck_results ;
201+ if TYPECK_BODY {
202+ self . context . typeck_results = Some ( self . context . tcx . typeck_body ( body_id) ) ;
203+ }
193204 let body = self . context . tcx . hir_body ( body_id) ;
194205 lint_callback ! ( self , check_fn, fk, decl, body, span, id) ;
195206 hir_visit:: walk_fn ( self , fk, decl, body_id, id) ;
196207 self . context . enclosing_body = old_enclosing_body;
197- self . context . cached_typeck_results . set ( old_cached_typeck_results) ;
208+ if TYPECK_BODY {
209+ self . context . typeck_results = old_typeck_results;
210+ }
198211 }
199212
200213 fn visit_variant_data ( & mut self , s : & ' tcx hir:: VariantData < ' tcx > ) {
@@ -333,6 +346,27 @@ macro_rules! impl_late_lint_pass {
333346
334347crate :: late_lint_methods!( impl_late_lint_pass, [ ] ) ;
335348
349+ /// Runs only the `MissingDoc` lint pass without type checking bodies.
350+ ///
351+ /// **DO NOT** use this for anything other than rustdoc. This exists solely to workaround
352+ /// the fact that rustdoc parses functions which would not pass type checking. See:
353+ /// <https://github.com/rust-lang/rust/pull/73566>.
354+ pub fn lint_missing_docs < ' tcx > ( tcx : TyCtxt < ' tcx > , mod_id : LocalModId ) {
355+ if is_lint_pass_required ( tcx. skippable_lints ( ( ) ) , & MissingDoc . get_lints ( ) ) {
356+ let context = LateContext {
357+ tcx,
358+ enclosing_body : None ,
359+ typeck_results : None ,
360+ param_env : ty:: ParamEnv :: empty ( ) ,
361+ effective_visibilities : tcx. effective_visibilities ( ( ) ) ,
362+ last_node_with_lint_attrs : tcx. local_def_id_to_hir_id ( mod_id) ,
363+ generics : None ,
364+ only_module : true ,
365+ } ;
366+ late_lint_mod_inner :: < ' _ , _ , false > ( tcx, mod_id, context, MissingDoc ) ;
367+ }
368+ }
369+
336370pub fn late_lint_mod < ' tcx , T : LateLintPass < ' tcx > + ' tcx > (
337371 tcx : TyCtxt < ' tcx > ,
338372 mod_id : LocalModId ,
@@ -341,7 +375,7 @@ pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>(
341375 let context = LateContext {
342376 tcx,
343377 enclosing_body : None ,
344- cached_typeck_results : Cell :: new ( None ) ,
378+ typeck_results : None ,
345379 param_env : ty:: ParamEnv :: empty ( ) ,
346380 effective_visibilities : tcx. effective_visibilities ( ( ) ) ,
347381 last_node_with_lint_attrs : tcx. local_def_id_to_hir_id ( mod_id) ,
@@ -363,24 +397,24 @@ pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>(
363397 let builtin_lints_must_run = is_lint_pass_required ( skippable_lints, & builtin_lints. get_lints ( ) ) ;
364398 if passes. is_empty ( ) {
365399 if builtin_lints_must_run {
366- late_lint_mod_inner ( tcx, mod_id, context, builtin_lints) ;
400+ late_lint_mod_inner :: < ' _ , _ , true > ( tcx, mod_id, context, builtin_lints) ;
367401 }
368402 } else {
369403 if builtin_lints_must_run {
370404 passes. push ( Box :: new ( builtin_lints) as Box < dyn LateLintPass < ' tcx > > ) ;
371405 }
372406 let pass = RuntimeCombinedLateLintPass { passes } ;
373- late_lint_mod_inner ( tcx, mod_id, context, pass) ;
407+ late_lint_mod_inner :: < ' _ , _ , true > ( tcx, mod_id, context, pass) ;
374408 }
375409}
376410
377- fn late_lint_mod_inner < ' tcx , T : LateLintPass < ' tcx > > (
411+ fn late_lint_mod_inner < ' tcx , T : LateLintPass < ' tcx > , const TYPECK_BODY : bool > (
378412 tcx : TyCtxt < ' tcx > ,
379413 mod_id : LocalModId ,
380414 context : LateContext < ' tcx > ,
381415 pass : T ,
382416) {
383- let mut cx = LateContextAndPass { context, pass } ;
417+ let mut cx = LateContextAndPass :: < ' tcx , T , TYPECK_BODY > { context, pass } ;
384418
385419 let ( module, _span, hir_id) = tcx. hir_get_module ( mod_id) ;
386420
@@ -415,7 +449,7 @@ fn late_lint_crate<'tcx>(tcx: TyCtxt<'tcx>) {
415449 let context = LateContext {
416450 tcx,
417451 enclosing_body : None ,
418- cached_typeck_results : Cell :: new ( None ) ,
452+ typeck_results : None ,
419453 param_env : ty:: ParamEnv :: empty ( ) ,
420454 effective_visibilities : tcx. effective_visibilities ( ( ) ) ,
421455 last_node_with_lint_attrs : hir:: CRATE_HIR_ID ,
@@ -424,7 +458,7 @@ fn late_lint_crate<'tcx>(tcx: TyCtxt<'tcx>) {
424458 } ;
425459
426460 let pass = RuntimeCombinedLateLintPass { passes } ;
427- let mut cx = LateContextAndPass { context, pass } ;
461+ let mut cx = LateContextAndPass :: < ' _ , _ , true > { context, pass } ;
428462
429463 // Visit the whole crate.
430464 cx. with_lint_attrs ( hir:: CRATE_HIR_ID , |cx| {
0 commit comments