11use object:: { File , Object , ObjectSection , ObjectSymbol , RelocationTarget } ;
22use rustc_middle:: mir:: mono:: MonoItem ;
3- use rustc_middle:: ty:: { Instance , TyCtxt } ;
3+ use rustc_middle:: ty:: { Instance , TypingEnv } ;
44use rustc_span:: Span ;
55
6+ use crate :: ctxt:: AnalysisCtxt ;
7+ use crate :: diagnostic:: use_stack:: { UseSite , UseSiteKind } ;
8+
69#[ derive( Diagnostic ) ]
710#[ diag( klint_build_error_referenced_without_symbol) ]
811struct BuildErrorReferencedWithoutSymbol ;
@@ -14,15 +17,20 @@ struct BuildErrorReferencedWithoutInstance<'a> {
1417}
1518
1619#[ derive( Diagnostic ) ]
17- #[ diag( klint_build_error_referenced ) ]
18- struct BuildErrorReferenced < ' tcx > {
20+ #[ diag( klint_build_error_referenced_without_debug ) ]
21+ struct BuildErrorReferencedWithoutDebug < ' tcx > {
1922 #[ primary_span]
2023 pub span : Span ,
2124 pub kind : & ' static str ,
2225 pub instance : Instance < ' tcx > ,
26+ pub err : String ,
2327}
2428
25- pub fn build_error_detection < ' tcx , ' obj > ( tcx : TyCtxt < ' tcx > , file : & File < ' obj > ) {
29+ #[ derive( Diagnostic ) ]
30+ #[ diag( klint_build_error_referenced) ]
31+ struct BuildErrorReferenced ;
32+
33+ pub fn build_error_detection < ' tcx , ' obj > ( cx : & AnalysisCtxt < ' tcx > , file : & File < ' obj > ) {
2634 let Some ( build_error_symbol) = file. symbol_by_name ( "rust_build_error" ) else {
2735 // This object file contains no reference to `build_error`, all good!
2836 return ;
@@ -41,55 +49,42 @@ pub fn build_error_detection<'tcx, 'obj>(tcx: TyCtxt<'tcx>, file: &File<'obj>) {
4149
4250 // Collect all mono items, which we will use to find out which symbol is problematic.
4351 let mono_items = crate :: monomorphize_collector:: collect_crate_mono_items (
44- tcx,
52+ cx . tcx ,
4553 crate :: monomorphize_collector:: MonoItemCollectionStrategy :: Lazy ,
4654 )
4755 . 0 ;
4856
4957 for section in file. sections ( ) {
5058 for ( offset, relocation) in section. relocations ( ) {
5159 if relocation. target ( ) == relo_target_needle {
52- // Found a relocation that points to `build_error`. Emit and error.
60+ // Found a relocation that points to `build_error`. Emit an error.
5361 let Some ( ( symbol, _) ) =
5462 super :: find_symbol_from_section_offset ( file, & section, offset)
5563 else {
56- tcx . dcx ( ) . emit_err ( BuildErrorReferencedWithoutSymbol ) ;
64+ cx . dcx ( ) . emit_err ( BuildErrorReferencedWithoutSymbol ) ;
5765 continue ;
5866 } ;
5967
6068 let Some ( mono) = mono_items
6169 . iter ( )
62- . find ( |item| item. symbol_name ( tcx) . name == symbol)
70+ . find ( |item| item. symbol_name ( cx . tcx ) . name == symbol)
6371 else {
64- tcx . dcx ( )
72+ cx . dcx ( )
6573 . emit_err ( BuildErrorReferencedWithoutInstance { symbol } ) ;
6674 continue ;
6775 } ;
6876
69- let mut diag = tcx. dcx ( ) . create_err ( match mono {
70- MonoItem :: Fn ( instance) => BuildErrorReferenced {
71- span : tcx. def_span ( instance. def_id ( ) ) ,
72- kind : "fn" ,
73- instance : * instance,
74- } ,
75- MonoItem :: Static ( def_id) => BuildErrorReferenced {
76- span : tcx. def_span ( def_id) ,
77- kind : "static" ,
78- instance : Instance :: mono ( tcx, * def_id) ,
79- } ,
80- MonoItem :: GlobalAsm ( _) => {
81- // We're not going to be covered by symbols inside global asm.
82- bug ! ( ) ;
83- }
84- } ) ;
85-
8677 let loader = super :: dwarf:: DwarfLoader :: new ( file)
8778 . expect ( "DWARF loader creation should not fail" ) ;
79+
80+ let mut diag = cx. dcx ( ) . create_err ( BuildErrorReferenced ) ;
8881 let mut frame = match mono {
89- MonoItem :: Fn ( instance) => Some ( * instance) ,
90- _ => None ,
82+ MonoItem :: Fn ( instance) => * instance,
83+ MonoItem :: Static ( def_id) => Instance :: mono ( cx. tcx , * def_id) ,
84+ MonoItem :: GlobalAsm ( _) => bug ! ( ) ,
9185 } ;
9286
87+ let mut recovered_call_stack = Vec :: new ( ) ;
9388 let result: Result < _ , super :: dwarf:: Error > = try {
9489 let call_stack = loader. inline_info ( section. index ( ) , offset) ?;
9590 if let Some ( first) = call_stack. first ( ) {
@@ -100,16 +95,17 @@ pub fn build_error_detection<'tcx, 'obj>(tcx: TyCtxt<'tcx>, file: &File<'obj>) {
10095 }
10196 }
10297 for call in call_stack {
103- if let Some ( caller) = frame. take ( ) {
104- if let Some ( ( callee, span) ) = super :: reconstruct:: recover_fn_call_span (
105- tcx,
106- caller,
107- & call. callee ,
108- call. location . as_ref ( ) ,
109- ) {
110- frame = Some ( callee) ;
111- diag. span_note ( span, format ! ( "which calls `{callee}`" ) ) ;
112- }
98+ if let Some ( ( callee, site) ) = super :: reconstruct:: recover_fn_call_span (
99+ cx. tcx ,
100+ frame,
101+ & call. callee ,
102+ call. location . as_ref ( ) ,
103+ ) {
104+ recovered_call_stack. push ( UseSite {
105+ instance : TypingEnv :: fully_monomorphized ( ) . as_query_input ( frame) ,
106+ kind : site,
107+ } ) ;
108+ frame = callee;
113109 }
114110 }
115111 } ;
@@ -124,34 +120,60 @@ pub fn build_error_detection<'tcx, 'obj>(tcx: TyCtxt<'tcx>, file: &File<'obj>) {
124120 super :: dwarf:: Error :: UnexpectedDwarf ( "cannot find line number info" ) ,
125121 ) ?;
126122
127- if let Some ( frame) = frame
128- && let Some ( ( _, span) ) = super :: reconstruct:: recover_fn_call_span (
129- tcx,
130- frame,
131- "rust_build_error" ,
132- Some ( & loc) ,
133- )
134- {
135- diag. span_note (
136- span,
137- "which contains a `build_error` call that is not optimized out" ,
138- ) ;
123+ if let Some ( ( _, site) ) = super :: reconstruct:: recover_fn_call_span (
124+ cx. tcx ,
125+ frame,
126+ "rust_build_error" ,
127+ Some ( & loc) ,
128+ ) {
129+ recovered_call_stack. push ( UseSite {
130+ instance : TypingEnv :: fully_monomorphized ( ) . as_query_input ( frame) ,
131+ kind : site,
132+ } ) ;
139133 } else {
140- let span = super :: reconstruct:: recover_span_from_line_no ( tcx, & loc) . ok_or (
141- super :: dwarf:: Error :: Other ( "cannot find file in compiler session" ) ,
142- ) ?;
143- diag. span_note (
144- span,
145- "which contains a `build_error` reference that is not optimized out" ,
146- ) ;
134+ let span = super :: reconstruct:: recover_span_from_line_no ( cx. tcx , & loc)
135+ . ok_or ( super :: dwarf:: Error :: Other (
136+ "cannot find file in compiler session" ,
137+ ) ) ?;
138+ recovered_call_stack. push ( UseSite {
139+ instance : TypingEnv :: fully_monomorphized ( ) . as_query_input ( frame) ,
140+ kind : UseSiteKind :: Other (
141+ span,
142+ "which is referenced by this function" . to_string ( ) ,
143+ ) ,
144+ } )
147145 }
148146 } ;
149147 if let Err ( err) = result {
150- diag. note ( format ! (
151- "attempt to reconstruct line information from DWARF failed: {err}"
152- ) ) ;
148+ diag. cancel ( ) ;
149+
150+ // If even line number cannot be recovered, emit a different diagnostic.
151+ cx. dcx ( ) . emit_err ( match mono {
152+ MonoItem :: Fn ( instance) => BuildErrorReferencedWithoutDebug {
153+ span : cx. def_span ( instance. def_id ( ) ) ,
154+ kind : "fn" ,
155+ instance : * instance,
156+ err : err. to_string ( ) ,
157+ } ,
158+ MonoItem :: Static ( def_id) => BuildErrorReferencedWithoutDebug {
159+ span : cx. def_span ( def_id) ,
160+ kind : "static" ,
161+ instance : Instance :: mono ( cx. tcx , * def_id) ,
162+ err : err. to_string ( ) ,
163+ } ,
164+ MonoItem :: GlobalAsm ( _) => {
165+ // We're not going to be covered by symbols inside global asm.
166+ bug ! ( ) ;
167+ }
168+ } ) ;
169+ continue ;
153170 }
154171
172+ cx. note_use_stack ( & mut diag, & recovered_call_stack) ;
173+ diag. span_note (
174+ cx. def_span ( mono. def_id ( ) ) ,
175+ format ! ( "reference contained in `{}`" , mono) ,
176+ ) ;
155177 diag. emit ( ) ;
156178 }
157179 }
0 commit comments