1
+ //! The implementation of built-in macros which relate to the file system.
2
+
1
3
use std:: path:: { Path , PathBuf } ;
2
4
use std:: rc:: Rc ;
3
5
use std:: sync:: Arc ;
@@ -11,9 +13,11 @@ use rustc_expand::base::{
11
13
} ;
12
14
use rustc_expand:: module:: DirOwnership ;
13
15
use rustc_lint_defs:: BuiltinLintDiag ;
14
- use rustc_parse:: parser:: { ForceCollect , Parser } ;
16
+ use rustc_parse:: lexer:: StripTokens ;
17
+ use rustc_parse:: parser:: ForceCollect ;
15
18
use rustc_parse:: { new_parser_from_file, unwrap_or_emit_fatal, utf8_error} ;
16
19
use rustc_session:: lint:: builtin:: INCOMPLETE_INCLUDE ;
20
+ use rustc_session:: parse:: ParseSess ;
17
21
use rustc_span:: source_map:: SourceMap ;
18
22
use rustc_span:: { ByteSymbol , Pos , Span , Symbol } ;
19
23
use smallvec:: SmallVec ;
@@ -23,11 +27,7 @@ use crate::util::{
23
27
check_zero_tts, get_single_str_from_tts, get_single_str_spanned_from_tts, parse_expr,
24
28
} ;
25
29
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.
31
31
pub ( crate ) fn expand_line (
32
32
cx : & mut ExtCtxt < ' _ > ,
33
33
sp : Span ,
@@ -42,7 +42,7 @@ pub(crate) fn expand_line(
42
42
ExpandResult :: Ready ( MacEager :: expr ( cx. expr_u32 ( topmost, loc. line as u32 ) ) )
43
43
}
44
44
45
- /* column!(): expands to the current column number */
45
+ /// Expand ` column!()` to the current column number.
46
46
pub ( crate ) fn expand_column (
47
47
cx : & mut ExtCtxt < ' _ > ,
48
48
sp : Span ,
@@ -57,9 +57,7 @@ pub(crate) fn expand_column(
57
57
ExpandResult :: Ready ( MacEager :: expr ( cx. expr_u32 ( topmost, loc. col . to_usize ( ) as u32 + 1 ) ) )
58
58
}
59
59
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.
63
61
pub ( crate ) fn expand_file (
64
62
cx : & mut ExtCtxt < ' _ > ,
65
63
sp : Span ,
@@ -81,6 +79,7 @@ pub(crate) fn expand_file(
81
79
) ) )
82
80
}
83
81
82
+ /// Expand `stringify!($input)`.
84
83
pub ( crate ) fn expand_stringify (
85
84
cx : & mut ExtCtxt < ' _ > ,
86
85
sp : Span ,
@@ -91,6 +90,7 @@ pub(crate) fn expand_stringify(
91
90
ExpandResult :: Ready ( MacEager :: expr ( cx. expr_str ( sp, Symbol :: intern ( & s) ) ) )
92
91
}
93
92
93
+ /// Expand `module_path!()` to (a textual representation of) the current module path.
94
94
pub ( crate ) fn expand_mod (
95
95
cx : & mut ExtCtxt < ' _ > ,
96
96
sp : Span ,
@@ -104,9 +104,9 @@ pub(crate) fn expand_mod(
104
104
ExpandResult :: Ready ( MacEager :: expr ( cx. expr_str ( sp, Symbol :: intern ( & string) ) ) )
105
105
}
106
106
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 .
110
110
pub ( crate ) fn expand_include < ' cx > (
111
111
cx : & ' cx mut ExtCtxt < ' _ > ,
112
112
sp : Span ,
@@ -116,64 +116,76 @@ pub(crate) fn expand_include<'cx>(
116
116
let ExpandResult :: Ready ( mac) = get_single_str_from_tts ( cx, sp, tts, "include!" ) else {
117
117
return ExpandResult :: Retry ( ( ) ) ;
118
118
} ;
119
- let file = match mac {
120
- Ok ( file ) => file ,
119
+ let path = match mac {
120
+ Ok ( path ) => path ,
121
121
Err ( guar) => return ExpandResult :: Ready ( DummyResult :: any ( sp, guar) ) ,
122
122
} ;
123
123
// 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 ,
126
126
Err ( err) => {
127
127
let guar = err. emit ( ) ;
128
128
return ExpandResult :: Ready ( DummyResult :: any ( sp, guar) ) ;
129
129
}
130
130
} ;
131
- let p = unwrap_or_emit_fatal ( new_parser_from_file ( cx. psess ( ) , & file, Some ( sp) ) ) ;
132
131
133
132
// 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 `.
135
134
// See https://github.com/rust-lang/rust/pull/69838/files#r395217057 for a discussion.
136
135
// `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 ( ) ;
138
137
cx. current_expansion . module = Rc :: new ( cx. current_expansion . module . with_dir_path ( dir_path) ) ;
139
138
cx. current_expansion . dir_ownership = DirOwnership :: Owned { relative : None } ;
140
139
141
140
struct ExpandInclude < ' a > {
142
- p : Parser < ' a > ,
141
+ psess : & ' a ParseSess ,
142
+ path : PathBuf ,
143
143
node_id : ast:: NodeId ,
144
+ span : Span ,
144
145
}
145
146
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 (
150
159
INCOMPLETE_INCLUDE ,
151
- self . p . token . span ,
160
+ p. token . span ,
152
161
self . node_id ,
153
162
BuiltinLintDiag :: IncompleteInclude ,
154
163
) ;
155
164
}
156
165
Some ( expr)
157
166
}
158
167
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
+ ) ) ;
160
175
let mut ret = SmallVec :: new ( ) ;
161
176
loop {
162
- match self . p . parse_item ( ForceCollect :: No ) {
177
+ match p. parse_item ( ForceCollect :: No ) {
163
178
Err ( err) => {
164
179
err. emit ( ) ;
165
180
break ;
166
181
}
167
182
Ok ( Some ( item) ) => ret. push ( item) ,
168
183
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
+ } ) ;
177
189
}
178
190
179
191
break ;
@@ -184,10 +196,17 @@ pub(crate) fn expand_include<'cx>(
184
196
}
185
197
}
186
198
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
+ } ) )
188
205
}
189
206
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.
191
210
pub ( crate ) fn expand_include_str (
192
211
cx : & mut ExtCtxt < ' _ > ,
193
212
sp : Span ,
@@ -206,6 +225,7 @@ pub(crate) fn expand_include_str(
206
225
Ok ( ( bytes, bsp) ) => match std:: str:: from_utf8 ( & bytes) {
207
226
Ok ( src) => {
208
227
let interned_src = Symbol :: intern ( src) ;
228
+ // MacEager converts the expr into a pat if need be.
209
229
MacEager :: expr ( cx. expr_str ( cx. with_def_site_ctxt ( bsp) , interned_src) )
210
230
}
211
231
Err ( utf8err) => {
@@ -218,6 +238,9 @@ pub(crate) fn expand_include_str(
218
238
} )
219
239
}
220
240
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.
221
244
pub ( crate ) fn expand_include_bytes (
222
245
cx : & mut ExtCtxt < ' _ > ,
223
246
sp : Span ,
@@ -237,6 +260,7 @@ pub(crate) fn expand_include_bytes(
237
260
// Don't care about getting the span for the raw bytes,
238
261
// because the console can't really show them anyway.
239
262
let expr = cx. expr ( sp, ast:: ExprKind :: IncludedBytes ( ByteSymbol :: intern ( & bytes) ) ) ;
263
+ // MacEager converts the expr into a pat if need be.
240
264
MacEager :: expr ( expr)
241
265
}
242
266
Err ( dummy) => dummy,
0 commit comments