1+ //! The implementation of built-in macros which relate to the file system.
2+
13use std:: path:: { Path , PathBuf } ;
24use std:: rc:: Rc ;
35use std:: sync:: Arc ;
@@ -11,9 +13,11 @@ use rustc_expand::base::{
1113} ;
1214use rustc_expand:: module:: DirOwnership ;
1315use rustc_lint_defs:: BuiltinLintDiag ;
14- use rustc_parse:: parser:: { ForceCollect , Parser } ;
16+ use rustc_parse:: lexer:: StripTokens ;
17+ use rustc_parse:: parser:: ForceCollect ;
1518use rustc_parse:: { new_parser_from_file, unwrap_or_emit_fatal, utf8_error} ;
1619use rustc_session:: lint:: builtin:: INCOMPLETE_INCLUDE ;
20+ use rustc_session:: parse:: ParseSess ;
1721use rustc_span:: source_map:: SourceMap ;
1822use rustc_span:: { ByteSymbol , Pos , Span , Symbol } ;
1923use smallvec:: SmallVec ;
@@ -23,11 +27,7 @@ use crate::util::{
2327 check_zero_tts, get_single_str_from_tts, get_single_str_spanned_from_tts, parse_expr,
2428} ;
2529
26- // These macros all relate to the file system; they either return
27- // the column/row/filename of the expression, or they include
28- // a given file into the current one.
29-
30- /// line!(): expands to the current line number
30+ /// Expand `line!()` to the current line number.
3131pub ( crate ) fn expand_line (
3232 cx : & mut ExtCtxt < ' _ > ,
3333 sp : Span ,
@@ -42,7 +42,7 @@ pub(crate) fn expand_line(
4242 ExpandResult :: Ready ( MacEager :: expr ( cx. expr_u32 ( topmost, loc. line as u32 ) ) )
4343}
4444
45- /* column!(): expands to the current column number */
45+ /// Expand ` column!()` to the current column number.
4646pub ( crate ) fn expand_column (
4747 cx : & mut ExtCtxt < ' _ > ,
4848 sp : Span ,
@@ -57,9 +57,7 @@ pub(crate) fn expand_column(
5757 ExpandResult :: Ready ( MacEager :: expr ( cx. expr_u32 ( topmost, loc. col . to_usize ( ) as u32 + 1 ) ) )
5858}
5959
60- /// file!(): expands to the current filename */
61- /// The source_file (`loc.file`) contains a bunch more information we could spit
62- /// out if we wanted.
60+ /// Expand `file!()` to the current filename.
6361pub ( crate ) fn expand_file (
6462 cx : & mut ExtCtxt < ' _ > ,
6563 sp : Span ,
@@ -81,6 +79,7 @@ pub(crate) fn expand_file(
8179 ) ) )
8280}
8381
82+ /// Expand `stringify!($input)`.
8483pub ( crate ) fn expand_stringify (
8584 cx : & mut ExtCtxt < ' _ > ,
8685 sp : Span ,
@@ -91,6 +90,7 @@ pub(crate) fn expand_stringify(
9190 ExpandResult :: Ready ( MacEager :: expr ( cx. expr_str ( sp, Symbol :: intern ( & s) ) ) )
9291}
9392
93+ /// Expand `module_path!()` to (a textual representation of) the current module path.
9494pub ( crate ) fn expand_mod (
9595 cx : & mut ExtCtxt < ' _ > ,
9696 sp : Span ,
@@ -104,9 +104,9 @@ pub(crate) fn expand_mod(
104104 ExpandResult :: Ready ( MacEager :: expr ( cx. expr_str ( sp, Symbol :: intern ( & string) ) ) )
105105}
106106
107- /// include! : parse the given file as an expr
108- /// This is generally a bad idea because it's going to behave
109- /// unhygienically .
107+ /// Expand ` include!($input)`.
108+ ///
109+ /// This works in item and expression position. Notably, it doesn't work in pattern position .
110110pub ( crate ) fn expand_include < ' cx > (
111111 cx : & ' cx mut ExtCtxt < ' _ > ,
112112 sp : Span ,
@@ -116,64 +116,76 @@ pub(crate) fn expand_include<'cx>(
116116 let ExpandResult :: Ready ( mac) = get_single_str_from_tts ( cx, sp, tts, "include!" ) else {
117117 return ExpandResult :: Retry ( ( ) ) ;
118118 } ;
119- let file = match mac {
120- Ok ( file ) => file ,
119+ let path = match mac {
120+ Ok ( path ) => path ,
121121 Err ( guar) => return ExpandResult :: Ready ( DummyResult :: any ( sp, guar) ) ,
122122 } ;
123123 // The file will be added to the code map by the parser
124- let file = match resolve_path ( & cx. sess , file . as_str ( ) , sp) {
125- Ok ( f ) => f ,
124+ let path = match resolve_path ( & cx. sess , path . as_str ( ) , sp) {
125+ Ok ( path ) => path ,
126126 Err ( err) => {
127127 let guar = err. emit ( ) ;
128128 return ExpandResult :: Ready ( DummyResult :: any ( sp, guar) ) ;
129129 }
130130 } ;
131- let p = unwrap_or_emit_fatal ( new_parser_from_file ( cx. psess ( ) , & file, Some ( sp) ) ) ;
132131
133132 // If in the included file we have e.g., `mod bar;`,
134- // then the path of `bar.rs` should be relative to the directory of `file `.
133+ // then the path of `bar.rs` should be relative to the directory of `path `.
135134 // See https://github.com/rust-lang/rust/pull/69838/files#r395217057 for a discussion.
136135 // `MacroExpander::fully_expand_fragment` later restores, so "stack discipline" is maintained.
137- let dir_path = file . parent ( ) . unwrap_or ( & file ) . to_owned ( ) ;
136+ let dir_path = path . parent ( ) . unwrap_or ( & path ) . to_owned ( ) ;
138137 cx. current_expansion . module = Rc :: new ( cx. current_expansion . module . with_dir_path ( dir_path) ) ;
139138 cx. current_expansion . dir_ownership = DirOwnership :: Owned { relative : None } ;
140139
141140 struct ExpandInclude < ' a > {
142- p : Parser < ' a > ,
141+ psess : & ' a ParseSess ,
142+ path : PathBuf ,
143143 node_id : ast:: NodeId ,
144+ span : Span ,
144145 }
145146 impl < ' a > MacResult for ExpandInclude < ' a > {
146- fn make_expr ( mut self : Box < ExpandInclude < ' a > > ) -> Option < Box < ast:: Expr > > {
147- let expr = parse_expr ( & mut self . p ) . ok ( ) ?;
148- if self . p . token != token:: Eof {
149- self . p . psess . buffer_lint (
147+ fn make_expr ( self : Box < ExpandInclude < ' a > > ) -> Option < Box < ast:: Expr > > {
148+ let mut p = unwrap_or_emit_fatal ( new_parser_from_file (
149+ self . psess ,
150+ & self . path ,
151+ // Don't strip frontmatter for backward compatibility, `---` may be the start of a
152+ // manifold negation. FIXME: Ideally, we wouldn't strip shebangs here either.
153+ StripTokens :: Shebang ,
154+ Some ( self . span ) ,
155+ ) ) ;
156+ let expr = parse_expr ( & mut p) . ok ( ) ?;
157+ if p. token != token:: Eof {
158+ p. psess . buffer_lint (
150159 INCOMPLETE_INCLUDE ,
151- self . p . token . span ,
160+ p. token . span ,
152161 self . node_id ,
153162 BuiltinLintDiag :: IncompleteInclude ,
154163 ) ;
155164 }
156165 Some ( expr)
157166 }
158167
159- fn make_items ( mut self : Box < ExpandInclude < ' a > > ) -> Option < SmallVec < [ Box < ast:: Item > ; 1 ] > > {
168+ fn make_items ( self : Box < ExpandInclude < ' a > > ) -> Option < SmallVec < [ Box < ast:: Item > ; 1 ] > > {
169+ let mut p = unwrap_or_emit_fatal ( new_parser_from_file (
170+ self . psess ,
171+ & self . path ,
172+ StripTokens :: ShebangAndFrontmatter ,
173+ Some ( self . span ) ,
174+ ) ) ;
160175 let mut ret = SmallVec :: new ( ) ;
161176 loop {
162- match self . p . parse_item ( ForceCollect :: No ) {
177+ match p. parse_item ( ForceCollect :: No ) {
163178 Err ( err) => {
164179 err. emit ( ) ;
165180 break ;
166181 }
167182 Ok ( Some ( item) ) => ret. push ( item) ,
168183 Ok ( None ) => {
169- if self . p . token != token:: Eof {
170- self . p
171- . dcx ( )
172- . create_err ( errors:: ExpectedItem {
173- span : self . p . token . span ,
174- token : & pprust:: token_to_string ( & self . p . token ) ,
175- } )
176- . emit ( ) ;
184+ if p. token != token:: Eof {
185+ p. dcx ( ) . emit_err ( errors:: ExpectedItem {
186+ span : p. token . span ,
187+ token : & pprust:: token_to_string ( & p. token ) ,
188+ } ) ;
177189 }
178190
179191 break ;
@@ -184,10 +196,17 @@ pub(crate) fn expand_include<'cx>(
184196 }
185197 }
186198
187- ExpandResult :: Ready ( Box :: new ( ExpandInclude { p, node_id : cx. current_expansion . lint_node_id } ) )
199+ ExpandResult :: Ready ( Box :: new ( ExpandInclude {
200+ psess : cx. psess ( ) ,
201+ path,
202+ node_id : cx. current_expansion . lint_node_id ,
203+ span : sp,
204+ } ) )
188205}
189206
190- /// `include_str!`: read the given file, insert it as a literal string expr
207+ /// Expand `include_str!($input)` to the content of the UTF-8-encoded file given by path `$input` as a string literal.
208+ ///
209+ /// This works in expression, pattern and statement position.
191210pub ( crate ) fn expand_include_str (
192211 cx : & mut ExtCtxt < ' _ > ,
193212 sp : Span ,
@@ -206,6 +225,7 @@ pub(crate) fn expand_include_str(
206225 Ok ( ( bytes, bsp) ) => match std:: str:: from_utf8 ( & bytes) {
207226 Ok ( src) => {
208227 let interned_src = Symbol :: intern ( src) ;
228+ // MacEager converts the expr into a pat if need be.
209229 MacEager :: expr ( cx. expr_str ( cx. with_def_site_ctxt ( bsp) , interned_src) )
210230 }
211231 Err ( utf8err) => {
@@ -218,6 +238,9 @@ pub(crate) fn expand_include_str(
218238 } )
219239}
220240
241+ /// Expand `include_bytes!($input)` to the content of the file given by path `$input`.
242+ ///
243+ /// This works in expression, pattern and statement position.
221244pub ( crate ) fn expand_include_bytes (
222245 cx : & mut ExtCtxt < ' _ > ,
223246 sp : Span ,
@@ -237,6 +260,7 @@ pub(crate) fn expand_include_bytes(
237260 // Don't care about getting the span for the raw bytes,
238261 // because the console can't really show them anyway.
239262 let expr = cx. expr ( sp, ast:: ExprKind :: IncludedBytes ( ByteSymbol :: intern ( & bytes) ) ) ;
263+ // MacEager converts the expr into a pat if need be.
240264 MacEager :: expr ( expr)
241265 }
242266 Err ( dummy) => dummy,
0 commit comments