11//! Out-of-band attributes attached without source code changes.
22
3- use rustc_hir:: def:: { DefKind , Res } ;
4- use rustc_hir:: def_id:: { CRATE_DEF_ID , DefId , LOCAL_CRATE } ;
3+ use rustc_hir:: def:: DefKind ;
4+ use rustc_hir:: def:: Res ;
5+ use rustc_hir:: def_id:: { DefId , LOCAL_CRATE } ;
56use rustc_hir:: diagnostic_items:: DiagnosticItems ;
67use rustc_middle:: middle:: exported_symbols:: ExportedSymbol ;
78use rustc_middle:: ty:: TyCtxt ;
9+ use rustc_span:: Symbol ;
810
911pub fn infer_missing_items < ' tcx > ( tcx : TyCtxt < ' tcx > , items : & mut DiagnosticItems ) {
10- if !items. name_to_id . contains_key ( & crate :: symbol:: build_error) {
11- if let Some ( def_id) = infer_build_error_diagnostic_item ( tcx) {
12- super :: collect_item ( tcx , items , crate :: symbol :: build_error , def_id ) ;
13- }
12+ if !items. name_to_id . contains_key ( & crate :: symbol:: build_error)
13+ && let Some ( def_id) = infer_build_error_diagnostic_item ( tcx)
14+ {
15+ super :: collect_item ( tcx , items , crate :: symbol :: build_error , def_id ) ;
1416 }
1517
16- if !items. name_to_id . contains_key ( & crate :: symbol:: c_str) {
17- if let Some ( def_id) = infer_c_str_diagnostic_item ( tcx) {
18- super :: collect_item ( tcx, items, crate :: symbol:: c_str, def_id) ;
19- }
18+ if !items. name_to_id . contains_key ( & crate :: symbol:: build_assert)
19+ && let Some ( def_id) = infer_build_assert_diagnostic_item ( tcx)
20+ {
21+ super :: collect_item ( tcx, items, crate :: symbol:: build_assert, def_id) ;
22+ }
23+
24+ if !items. name_to_id . contains_key ( & crate :: symbol:: c_str)
25+ && let Some ( def_id) = infer_c_str_diagnostic_item ( tcx)
26+ {
27+ super :: collect_item ( tcx, items, crate :: symbol:: c_str, def_id) ;
2028 }
2129}
2230
@@ -32,21 +40,89 @@ pub fn infer_build_error_diagnostic_item<'tcx>(tcx: TyCtxt<'tcx>) -> Option<DefI
3240 None
3341}
3442
35- pub fn infer_c_str_diagnostic_item < ' tcx > ( tcx : TyCtxt < ' tcx > ) -> Option < DefId > {
43+ fn infer_local_macro_diagnostic_item < ' tcx > (
44+ tcx : TyCtxt < ' tcx > ,
45+ expected_path : & [ PathSegment ] ,
46+ ) -> Option < DefId > {
47+ let ( root, rest) = expected_path. split_first ( ) ?;
48+ let PathSegment :: Type ( root) = root else {
49+ return None ;
50+ } ;
51+
52+ if * root != tcx. crate_name ( LOCAL_CRATE ) {
53+ return None ;
54+ }
55+
56+ lookup_with_base ( tcx, LOCAL_CRATE . as_def_id ( ) , rest)
57+ }
58+
59+ #[ derive( Clone , Copy ) ]
60+ enum PathSegment {
61+ Type ( Symbol ) ,
62+ Macro ( Symbol ) ,
63+ }
64+
65+ fn lookup_with_base < ' tcx > ( tcx : TyCtxt < ' tcx > , base : DefId , path : & [ PathSegment ] ) -> Option < DefId > {
66+ let ( segment, rest) = path. split_first ( ) ?;
67+
68+ let mut matches = tcx. module_children ( base) . iter ( ) . filter_map ( |child| {
69+ let Res :: Def ( kind, def_id) = child. res else {
70+ return None ;
71+ } ;
72+
73+ match ( * segment, kind, child. ident . name ) {
74+ ( PathSegment :: Type ( expected) , DefKind :: Mod , actual) if actual == expected => {
75+ Some ( def_id)
76+ }
77+ ( PathSegment :: Macro ( expected) , DefKind :: Macro ( _) , actual) if actual == expected => {
78+ Some ( def_id)
79+ }
80+ _ => None ,
81+ }
82+ } ) ;
83+
84+ let def_id = matches. next ( ) ?;
85+
86+ if matches. next ( ) . is_some ( ) {
87+ return None ;
88+ }
89+
90+ if rest. is_empty ( ) {
91+ Some ( def_id)
92+ } else {
93+ lookup_with_base ( tcx, def_id, rest)
94+ }
95+ }
96+
97+ pub fn infer_build_assert_diagnostic_item < ' tcx > ( tcx : TyCtxt < ' tcx > ) -> Option < DefId > {
3698 let name = tcx. crate_name ( LOCAL_CRATE ) ;
3799
38100 if name != crate :: symbol:: kernel {
39101 return None ;
40102 }
41103
42- let c_str = tcx
43- . module_children_local ( CRATE_DEF_ID )
44- . iter ( )
45- . find ( |c| {
46- c. ident . name == crate :: symbol:: c_str && matches ! ( c. res, Res :: Def ( DefKind :: Macro ( _) , _) )
47- } ) ?
48- . res
49- . def_id ( ) ;
104+ infer_local_macro_diagnostic_item (
105+ tcx,
106+ & [
107+ PathSegment :: Type ( crate :: symbol:: kernel) ,
108+ PathSegment :: Type ( rustc_span:: sym:: prelude) ,
109+ PathSegment :: Macro ( crate :: symbol:: build_assert) ,
110+ ] ,
111+ )
112+ }
113+
114+ pub fn infer_c_str_diagnostic_item < ' tcx > ( tcx : TyCtxt < ' tcx > ) -> Option < DefId > {
115+ let name = tcx. crate_name ( LOCAL_CRATE ) ;
116+
117+ if name != crate :: symbol:: kernel {
118+ return None ;
119+ }
50120
51- Some ( c_str)
121+ infer_local_macro_diagnostic_item (
122+ tcx,
123+ & [
124+ PathSegment :: Type ( crate :: symbol:: kernel) ,
125+ PathSegment :: Macro ( crate :: symbol:: c_str) ,
126+ ] ,
127+ )
52128}
0 commit comments