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 (
3232cx : & mut ExtCtxt < ' _ > ,
3333sp : Span ,
@@ -42,7 +42,7 @@ pub(crate) fn expand_line(
4242ExpandResult :: 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 (
4747cx : & mut ExtCtxt < ' _ > ,
4848sp : Span ,
@@ -57,9 +57,7 @@ pub(crate) fn expand_column(
5757ExpandResult :: 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 (
6462cx : & mut ExtCtxt < ' _ > ,
6563sp : Span ,
@@ -81,6 +79,7 @@ pub(crate) fn expand_file(
8179) ) )
8280}
8381
82+ /// Expand `stringify!($input)`.
8483pub ( crate ) fn expand_stringify (
8584cx : & mut ExtCtxt < ' _ > ,
8685sp : Span ,
@@ -91,6 +90,7 @@ pub(crate) fn expand_stringify(
9190ExpandResult :: 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 (
9595cx : & mut ExtCtxt < ' _ > ,
9696sp : Span ,
@@ -104,9 +104,9 @@ pub(crate) fn expand_mod(
104104ExpandResult :: 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 > (
111111cx : & ' cx mut ExtCtxt < ' _ > ,
112112sp : Span ,
@@ -116,64 +116,76 @@ pub(crate) fn expand_include<'cx>(
116116let ExpandResult :: Ready ( mac) = get_single_str_from_tts ( cx, sp, tts, "include!" ) else {
117117return ExpandResult :: Retry ( ( ) ) ;
118118} ;
119- let file = match mac {
120- Ok ( file ) => file ,
119+ let path = match mac {
120+ Ok ( path ) => path ,
121121Err ( 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 ,
126126Err ( err) => {
127127let guar = err. emit ( ) ;
128128return 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
141140struct ExpandInclude < ' a > {
142- p : Parser < ' a > ,
141+ psess : & ' a ParseSess ,
142+ path : PathBuf ,
143143node_id : ast:: NodeId ,
144+ span : Span ,
144145}
145146impl < ' 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 (
150159INCOMPLETE_INCLUDE ,
151- self . p . token . span ,
160+ p. token . span ,
152161self . node_id ,
153162BuiltinLintDiag :: IncompleteInclude ,
154163) ;
155164}
156165Some ( 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+ ) ) ;
160175let mut ret = SmallVec :: new ( ) ;
161176loop {
162- match self . p . parse_item ( ForceCollect :: No ) {
177+ match p. parse_item ( ForceCollect :: No ) {
163178Err ( err) => {
164179 err. emit ( ) ;
165180break ;
166181}
167182Ok ( Some ( item) ) => ret. push ( item) ,
168183Ok ( 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
179191break ;
@@ -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 (
192211cx : & mut ExtCtxt < ' _ > ,
193212sp : Span ,
@@ -206,6 +225,7 @@ pub(crate) fn expand_include_str(
206225Ok ( ( bytes, bsp) ) => match std:: str:: from_utf8 ( & bytes) {
207226Ok ( src) => {
208227let interned_src = Symbol :: intern ( src) ;
228+ // MacEager converts the expr into a pat if need be.
209229MacEager :: expr ( cx. expr_str ( cx. with_def_site_ctxt ( bsp) , interned_src) )
210230}
211231Err ( 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 (
222245cx : & mut ExtCtxt < ' _ > ,
223246sp : 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.
239262let expr = cx. expr ( sp, ast:: ExprKind :: IncludedBytes ( ByteSymbol :: intern ( & bytes) ) ) ;
263+ // MacEager converts the expr into a pat if need be.
240264MacEager :: expr ( expr)
241265}
242266Err ( dummy) => dummy,
0 commit comments