@@ -58,8 +58,7 @@ use syntax::parse::{self, token};
58
58
use syntax:: symbol:: { keywords, Symbol } ;
59
59
use syntax:: tokenstream;
60
60
use syntax:: parse:: lexer:: { self , comments} ;
61
- use syntax_pos:: { FileMap , Pos , SyntaxContext , FileName } ;
62
- use syntax_pos:: hygiene:: Mark ;
61
+ use syntax_pos:: { FileMap , Pos , FileName } ;
63
62
64
63
/// The main type provided by this crate, representing an abstract stream of
65
64
/// tokens, or, more specifically, a sequence of token trees.
@@ -109,6 +108,7 @@ impl TokenStream {
109
108
/// Attempts to break the string into tokens and parse those tokens into a token stream.
110
109
/// May fail for a number of reasons, for example, if the string contains unbalanced delimiters
111
110
/// or characters not existing in the language.
111
+ /// All tokens in the parsed stream get `Span::call_site()` spans.
112
112
///
113
113
/// NOTE: Some errors may cause panics instead of returning `LexError`. We reserve the right to
114
114
/// change these errors into `LexError`s later.
@@ -117,17 +117,10 @@ impl FromStr for TokenStream {
117
117
type Err = LexError ;
118
118
119
119
fn from_str ( src : & str ) -> Result < TokenStream , LexError > {
120
- __internal:: with_sess ( |( sess, mark) | {
121
- let src = src. to_string ( ) ;
122
- let name = FileName :: ProcMacroSourceCode ;
123
- let expn_info = mark. expn_info ( ) . unwrap ( ) ;
124
- let call_site = expn_info. call_site ;
125
- // notify the expansion info that it is unhygienic
126
- let mark = Mark :: fresh ( mark) ;
127
- mark. set_expn_info ( expn_info) ;
128
- let span = call_site. with_ctxt ( SyntaxContext :: empty ( ) . apply_mark ( mark) ) ;
129
- let stream = parse:: parse_stream_from_source_str ( name, src, sess, Some ( span) ) ;
130
- Ok ( __internal:: token_stream_wrap ( stream) )
120
+ __internal:: with_sess ( |sess, data| {
121
+ Ok ( __internal:: token_stream_wrap ( parse:: parse_stream_from_source_str (
122
+ FileName :: ProcMacroSourceCode , src. to_string ( ) , sess, Some ( data. call_site . 0 )
123
+ ) ) )
131
124
} )
132
125
}
133
126
}
@@ -184,8 +177,6 @@ impl iter::FromIterator<TokenStream> for TokenStream {
184
177
#[ unstable( feature = "proc_macro" , issue = "38356" ) ]
185
178
pub mod token_stream {
186
179
use syntax:: tokenstream;
187
- use syntax_pos:: DUMMY_SP ;
188
-
189
180
use { TokenTree , TokenStream , Delimiter } ;
190
181
191
182
/// An iterator over `TokenStream`'s `TokenTree`s.
@@ -214,7 +205,7 @@ pub mod token_stream {
214
205
// need to flattened during iteration over stream's token trees.
215
206
// Eventually this needs to be removed in favor of keeping original token trees
216
207
// and not doing the roundtrip through AST.
217
- if tree. span ( ) . 0 == DUMMY_SP {
208
+ if tree. span ( ) . 0 . is_dummy ( ) {
218
209
if let TokenTree :: Group ( ref group) = tree {
219
210
if group. delimiter ( ) == Delimiter :: None {
220
211
self . cursor . insert ( group. stream . clone ( ) . 0 ) ;
@@ -284,10 +275,7 @@ impl Span {
284
275
/// A span that resolves at the macro definition site.
285
276
#[ unstable( feature = "proc_macro" , issue = "38356" ) ]
286
277
pub fn def_site ( ) -> Span {
287
- :: __internal:: with_sess ( |( _, mark) | {
288
- let call_site = mark. expn_info ( ) . unwrap ( ) . call_site ;
289
- Span ( call_site. with_ctxt ( SyntaxContext :: empty ( ) . apply_mark ( mark) ) )
290
- } )
278
+ :: __internal:: with_sess ( |_, data| data. def_site )
291
279
}
292
280
293
281
/// The span of the invocation of the current procedural macro.
@@ -296,7 +284,7 @@ impl Span {
296
284
/// at the macro call site will be able to refer to them as well.
297
285
#[ unstable( feature = "proc_macro" , issue = "38356" ) ]
298
286
pub fn call_site ( ) -> Span {
299
- :: __internal:: with_sess ( |( _, mark ) | Span ( mark . expn_info ( ) . unwrap ( ) . call_site ) )
287
+ :: __internal:: with_sess ( |_, data| data . call_site )
300
288
}
301
289
302
290
/// The original source file into which this span points.
@@ -1243,7 +1231,7 @@ impl TokenTree {
1243
1231
}
1244
1232
1245
1233
Interpolated ( _) => {
1246
- __internal:: with_sess ( |( sess, _) | {
1234
+ __internal:: with_sess ( |sess, _| {
1247
1235
let tts = token. interpolated_to_tokenstream ( sess, span) ;
1248
1236
tt ! ( Group :: new( Delimiter :: None , TokenStream ( tts) ) )
1249
1237
} )
@@ -1354,20 +1342,21 @@ pub mod __internal {
1354
1342
pub use quote:: { LiteralKind , SpannedSymbol , Quoter , unquote} ;
1355
1343
1356
1344
use std:: cell:: Cell ;
1345
+ use std:: ptr;
1357
1346
1358
1347
use syntax:: ast;
1359
1348
use syntax:: ext:: base:: ExtCtxt ;
1360
- use syntax:: ext:: hygiene:: Mark ;
1361
1349
use syntax:: ptr:: P ;
1362
1350
use syntax:: parse:: { self , ParseSess } ;
1363
1351
use syntax:: parse:: token:: { self , Token } ;
1364
1352
use syntax:: tokenstream;
1365
1353
use syntax_pos:: { BytePos , Loc , DUMMY_SP } ;
1354
+ use syntax_pos:: hygiene:: { Mark , SyntaxContext , Transparency } ;
1366
1355
1367
- use super :: { TokenStream , LexError } ;
1356
+ use super :: { TokenStream , LexError , Span } ;
1368
1357
1369
1358
pub fn lookup_char_pos ( pos : BytePos ) -> Loc {
1370
- with_sess ( |( sess, _) | sess. codemap ( ) . lookup_char_pos ( pos) )
1359
+ with_sess ( |sess, _| sess. codemap ( ) . lookup_char_pos ( pos) )
1371
1360
}
1372
1361
1373
1362
pub fn new_token_stream ( item : P < ast:: Item > ) -> TokenStream {
@@ -1380,7 +1369,7 @@ pub mod __internal {
1380
1369
}
1381
1370
1382
1371
pub fn token_stream_parse_items ( stream : TokenStream ) -> Result < Vec < P < ast:: Item > > , LexError > {
1383
- with_sess ( move |( sess, _) | {
1372
+ with_sess ( move |sess, _| {
1384
1373
let mut parser = parse:: stream_to_parser ( sess, stream. 0 ) ;
1385
1374
let mut items = Vec :: new ( ) ;
1386
1375
@@ -1411,16 +1400,30 @@ pub mod __internal {
1411
1400
expand : fn ( TokenStream ) -> TokenStream ) ;
1412
1401
}
1413
1402
1403
+ #[ derive( Clone , Copy ) ]
1404
+ pub struct ProcMacroData {
1405
+ pub def_site : Span ,
1406
+ pub call_site : Span ,
1407
+ }
1408
+
1409
+ #[ derive( Clone , Copy ) ]
1410
+ struct ProcMacroSess {
1411
+ parse_sess : * const ParseSess ,
1412
+ data : ProcMacroData ,
1413
+ }
1414
+
1414
1415
// Emulate scoped_thread_local!() here essentially
1415
1416
thread_local ! {
1416
- static CURRENT_SESS : Cell <( * const ParseSess , Mark ) > =
1417
- Cell :: new( ( 0 as * const _, Mark :: root( ) ) ) ;
1417
+ static CURRENT_SESS : Cell <ProcMacroSess > = Cell :: new( ProcMacroSess {
1418
+ parse_sess: ptr:: null( ) ,
1419
+ data: ProcMacroData { def_site: Span ( DUMMY_SP ) , call_site: Span ( DUMMY_SP ) } ,
1420
+ } ) ;
1418
1421
}
1419
1422
1420
1423
pub fn set_sess < F , R > ( cx : & ExtCtxt , f : F ) -> R
1421
1424
where F : FnOnce ( ) -> R
1422
1425
{
1423
- struct Reset { prev : ( * const ParseSess , Mark ) }
1426
+ struct Reset { prev : ProcMacroSess }
1424
1427
1425
1428
impl Drop for Reset {
1426
1429
fn drop ( & mut self ) {
@@ -1430,24 +1433,42 @@ pub mod __internal {
1430
1433
1431
1434
CURRENT_SESS . with ( |p| {
1432
1435
let _reset = Reset { prev : p. get ( ) } ;
1433
- p. set ( ( cx. parse_sess , cx. current_expansion . mark ) ) ;
1436
+
1437
+ // No way to determine def location for a proc macro right now, so use call location.
1438
+ let location = cx. current_expansion . mark . expn_info ( ) . unwrap ( ) . call_site ;
1439
+ // Opaque mark was already created by expansion, now create its transparent twin.
1440
+ // We can't use the call-site span literally here, even if it appears to provide
1441
+ // correct name resolution, because it has all the `ExpnInfo` wrong, so the edition
1442
+ // checks, lint macro checks, macro backtraces will all break.
1443
+ let opaque_mark = cx. current_expansion . mark ;
1444
+ let transparent_mark = Mark :: fresh_cloned ( opaque_mark) ;
1445
+ transparent_mark. set_transparency ( Transparency :: Transparent ) ;
1446
+
1447
+ let to_span = |mark| Span ( location. with_ctxt ( SyntaxContext :: empty ( ) . apply_mark ( mark) ) ) ;
1448
+ p. set ( ProcMacroSess {
1449
+ parse_sess : cx. parse_sess ,
1450
+ data : ProcMacroData {
1451
+ def_site : to_span ( opaque_mark) ,
1452
+ call_site : to_span ( transparent_mark) ,
1453
+ } ,
1454
+ } ) ;
1434
1455
f ( )
1435
1456
} )
1436
1457
}
1437
1458
1438
1459
pub fn in_sess ( ) -> bool
1439
1460
{
1440
- let p = CURRENT_SESS . with ( |p| p. get ( ) ) ;
1441
- !p. 0 . is_null ( )
1461
+ !CURRENT_SESS . with ( |sess| sess. get ( ) ) . parse_sess . is_null ( )
1442
1462
}
1443
1463
1444
1464
pub fn with_sess < F , R > ( f : F ) -> R
1445
- where F : FnOnce ( ( & ParseSess , Mark ) ) -> R
1465
+ where F : FnOnce ( & ParseSess , & ProcMacroData ) -> R
1446
1466
{
1447
- let p = CURRENT_SESS . with ( |p| p. get ( ) ) ;
1448
- assert ! ( !p. 0 . is_null( ) , "proc_macro::__internal::with_sess() called \
1449
- before set_parse_sess()!") ;
1450
- f ( unsafe { ( & * p. 0 , p. 1 ) } )
1467
+ let sess = CURRENT_SESS . with ( |sess| sess. get ( ) ) ;
1468
+ if sess. parse_sess . is_null ( ) {
1469
+ panic ! ( "procedural macro API is used outside of a procedural macro" ) ;
1470
+ }
1471
+ f ( unsafe { & * sess. parse_sess } , & sess. data )
1451
1472
}
1452
1473
}
1453
1474
0 commit comments