@@ -24,9 +24,10 @@ pub use self::LintSource::*;
2424use rustc_data_structures:: sync:: { self , Lrc } ;
2525
2626use errors:: { DiagnosticBuilder , DiagnosticId } ;
27- use hir:: def_id:: { CrateNum , LOCAL_CRATE } ;
27+ use hir:: def_id:: { CrateNum , DefId , LOCAL_CRATE } ;
2828use hir:: intravisit;
2929use hir;
30+ use hir:: CRATE_HIR_ID ;
3031use lint:: builtin:: BuiltinLintDiagnostics ;
3132use lint:: builtin:: parser:: { QUESTION_MARK_MACRO_SEP , ILL_FORMED_ATTRIBUTE_INPUT } ;
3233use session:: { Session , DiagnosticMessageId } ;
@@ -540,7 +541,7 @@ impl Level {
540541}
541542
542543/// How a lint level was set.
543- #[ derive( Clone , Copy , PartialEq , Eq ) ]
544+ #[ derive( Clone , Copy , PartialEq , Eq , Debug ) ]
544545pub enum LintSource {
545546 /// Lint is at the default level as declared
546547 /// in rustc or a plugin.
@@ -722,11 +723,32 @@ fn lint_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cnum: CrateNum)
722723 } ;
723724 let krate = tcx. hir ( ) . krate ( ) ;
724725
725- builder. with_lint_attrs ( ast:: CRATE_NODE_ID , & krate. attrs , |builder| {
726- intravisit:: walk_crate ( builder, krate) ;
727- } ) ;
726+ let push = builder. levels . push ( & krate. attrs ) ;
727+ builder. levels . register_id ( CRATE_HIR_ID ) ;
728+ intravisit:: walk_crate ( & mut builder, krate) ;
729+ builder. levels . pop ( push) ;
728730
729- Lrc :: new ( builder. levels . build_map ( ) )
731+ let r = Lrc :: new ( builder. levels . build_map ( ) ) ;
732+ if tcx. sess . verbose ( ) {
733+ eprintln ! ( "lint level map: {:#?}" , r) ;
734+ }
735+ r
736+ }
737+
738+ fn lint_level_root_for_def_id ( tcx : TyCtxt < ' a , ' tcx , ' tcx > , def_id : DefId ) -> hir:: HirId {
739+ let mut id = tcx. hir ( ) . as_local_hir_id ( def_id) . unwrap ( ) ;
740+ let sets = tcx. lint_levels ( LOCAL_CRATE ) ;
741+ loop {
742+ if sets. lint_level_set ( id) . is_some ( ) {
743+ return id
744+ }
745+ let node_id = tcx. hir ( ) . hir_to_node_id ( id) ;
746+ let next = tcx. hir ( ) . node_to_hir_id ( tcx. hir ( ) . get_parent_node ( node_id) ) ;
747+ if next == id {
748+ bug ! ( "lint traversal reached the root of the crate" ) ;
749+ }
750+ id = next;
751+ }
730752}
731753
732754struct LintLevelMapBuilder < ' a , ' tcx : ' a > {
@@ -742,7 +764,9 @@ impl<'a, 'tcx> LintLevelMapBuilder<'a, 'tcx> {
742764 where F : FnOnce ( & mut Self )
743765 {
744766 let push = self . levels . push ( attrs) ;
745- self . levels . register_id ( self . tcx . hir ( ) . definitions ( ) . node_to_hir_id ( id) ) ;
767+ if push. changed {
768+ self . levels . register_id ( self . tcx . hir ( ) . definitions ( ) . node_to_hir_id ( id) ) ;
769+ }
746770 f ( self ) ;
747771 self . levels . pop ( push) ;
748772 }
@@ -807,6 +831,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'a, 'tcx> {
807831
808832pub fn provide ( providers : & mut Providers < ' _ > ) {
809833 providers. lint_levels = lint_levels;
834+ providers. lint_level_root_for_def_id = lint_level_root_for_def_id;
810835}
811836
812837/// Returns whether `span` originates in a foreign crate's external macro.
0 commit comments