@@ -3,18 +3,19 @@ use rustc_ast::ptr::P;
33use rustc_ast:: token;
44use rustc_ast:: tokenstream:: TokenStream ;
55use rustc_ast_pretty:: pprust;
6+ use rustc_data_structures:: sync:: Lrc ;
67use rustc_expand:: base:: {
7- check_zero_tts, get_single_str_from_tts, parse_expr , resolve_path , DummyResult , ExtCtxt ,
8- MacEager , MacResult ,
8+ check_zero_tts, get_single_str_from_tts, get_single_str_spanned_from_tts , parse_expr ,
9+ resolve_path , DummyResult , ExtCtxt , MacEager , MacResult ,
910} ;
1011use rustc_expand:: module:: DirOwnership ;
1112use rustc_parse:: new_parser_from_file;
1213use rustc_parse:: parser:: { ForceCollect , Parser } ;
1314use rustc_session:: lint:: builtin:: INCOMPLETE_INCLUDE ;
1415use rustc_span:: symbol:: Symbol ;
1516use rustc_span:: { Pos , Span } ;
16-
1717use smallvec:: SmallVec ;
18+ use std:: path:: Path ;
1819use std:: rc:: Rc ;
1920
2021// These macros all relate to the file system; they either return
@@ -180,32 +181,22 @@ pub fn expand_include_str(
180181 tts : TokenStream ,
181182) -> Box < dyn MacResult + ' static > {
182183 let sp = cx. with_def_site_ctxt ( sp) ;
183- let file = match get_single_str_from_tts ( cx, sp, tts, "include_str!" ) {
184- Ok ( file ) => file ,
184+ let ( path , path_span ) = match get_single_str_spanned_from_tts ( cx, sp, tts, "include_str!" ) {
185+ Ok ( res ) => res ,
185186 Err ( guar) => return DummyResult :: any ( sp, guar) ,
186187 } ;
187- let file = match resolve_path ( & cx. sess , file. as_str ( ) , sp) {
188- Ok ( f) => f,
189- Err ( err) => {
190- let guar = err. emit ( ) ;
191- return DummyResult :: any ( sp, guar) ;
192- }
193- } ;
194- match cx. source_map ( ) . load_binary_file ( & file) {
188+ match load_binary_file ( cx, path. as_str ( ) , sp, path_span) {
195189 Ok ( bytes) => match std:: str:: from_utf8 ( & bytes) {
196190 Ok ( src) => {
197191 let interned_src = Symbol :: intern ( src) ;
198192 MacEager :: expr ( cx. expr_str ( sp, interned_src) )
199193 }
200194 Err ( _) => {
201- let guar = cx. dcx ( ) . span_err ( sp, format ! ( "{} wasn't a utf-8 file" , file . display ( ) ) ) ;
195+ let guar = cx. dcx ( ) . span_err ( sp, format ! ( "{path } wasn't a utf-8 file" ) ) ;
202196 DummyResult :: any ( sp, guar)
203197 }
204198 } ,
205- Err ( e) => {
206- let guar = cx. dcx ( ) . span_err ( sp, format ! ( "couldn't read {}: {}" , file. display( ) , e) ) ;
207- DummyResult :: any ( sp, guar)
208- }
199+ Err ( dummy) => dummy,
209200 }
210201}
211202
@@ -215,25 +206,57 @@ pub fn expand_include_bytes(
215206 tts : TokenStream ,
216207) -> Box < dyn MacResult + ' static > {
217208 let sp = cx. with_def_site_ctxt ( sp) ;
218- let file = match get_single_str_from_tts ( cx, sp, tts, "include_bytes!" ) {
219- Ok ( file ) => file ,
209+ let ( path , path_span ) = match get_single_str_spanned_from_tts ( cx, sp, tts, "include_bytes!" ) {
210+ Ok ( res ) => res ,
220211 Err ( guar) => return DummyResult :: any ( sp, guar) ,
221212 } ;
222- let file = match resolve_path ( & cx. sess , file. as_str ( ) , sp) {
223- Ok ( f) => f,
224- Err ( err) => {
225- let guar = err. emit ( ) ;
226- return DummyResult :: any ( sp, guar) ;
227- }
228- } ;
229- match cx. source_map ( ) . load_binary_file ( & file) {
213+ match load_binary_file ( cx, path. as_str ( ) , sp, path_span) {
230214 Ok ( bytes) => {
231215 let expr = cx. expr ( sp, ast:: ExprKind :: IncludedBytes ( bytes) ) ;
232216 MacEager :: expr ( expr)
233217 }
234- Err ( e) => {
235- let guar = cx. dcx ( ) . span_err ( sp, format ! ( "couldn't read {}: {}" , file. display( ) , e) ) ;
236- DummyResult :: any ( sp, guar)
218+ Err ( dummy) => dummy,
219+ }
220+ }
221+
222+ fn load_binary_file (
223+ cx : & mut ExtCtxt < ' _ > ,
224+ original_path : & str ,
225+ macro_span : Span ,
226+ path_span : Span ,
227+ ) -> Result < Lrc < [ u8 ] > , Box < dyn MacResult > > {
228+ let resolved_path = match resolve_path ( & cx. sess , original_path, macro_span) {
229+ Ok ( path) => path,
230+ Err ( err) => {
231+ let guar = err. emit ( ) ;
232+ return Err ( DummyResult :: any ( macro_span, guar) ) ;
233+ }
234+ } ;
235+ match cx. source_map ( ) . load_binary_file ( & resolved_path) {
236+ Ok ( data) => Ok ( data) ,
237+ Err ( io_err) => {
238+ let mut err = cx. dcx ( ) . struct_span_err (
239+ macro_span,
240+ format ! ( "couldn't read {}: {io_err}" , resolved_path. display( ) ) ,
241+ ) ;
242+ if Path :: new ( original_path) . is_relative ( ) {
243+ for prefix in [ ".." , "../.." ] {
244+ let parent_path = Path :: new ( prefix) . join ( original_path) ;
245+ if resolve_path ( & cx. sess , & parent_path, macro_span)
246+ . map_or ( false , |p| p. exists ( ) )
247+ {
248+ err. span_suggestion (
249+ path_span,
250+ "it's in a parent directory" ,
251+ format ! ( "\" {}\" " , parent_path. display( ) . to_string( ) . escape_debug( ) ) ,
252+ rustc_lint_defs:: Applicability :: MachineApplicable ,
253+ ) ;
254+ break ;
255+ }
256+ }
257+ }
258+ let guar = err. emit ( ) ;
259+ Err ( DummyResult :: any ( macro_span, guar) )
237260 }
238261 }
239262}
0 commit comments