@@ -14,7 +14,9 @@ use rustc_ast::ptr::P;
14
14
use rustc_ast:: token:: { self , Delimiter } ;
15
15
use rustc_ast:: tokenstream:: TokenStream ;
16
16
use rustc_ast:: visit:: { self , try_visit, walk_list, AssocCtxt , Visitor , VisitorResult } ;
17
- use rustc_ast:: { AssocItemKind , AstNodeWrapper , AttrArgs , AttrStyle , AttrVec , ExprKind } ;
17
+ use rustc_ast:: {
18
+ AssocItemKind , AstNodeWrapper , AttrArgs , AttrStyle , AttrVec , ExprKind , DUMMY_NODE_ID ,
19
+ } ;
18
20
use rustc_ast:: { ForeignItemKind , HasAttrs , HasNodeId } ;
19
21
use rustc_ast:: { Inline , ItemKind , MacStmtStyle , MetaItemKind , ModKind } ;
20
22
use rustc_ast:: { NestedMetaItem , NodeId , PatKind , StmtKind , TyKind } ;
@@ -35,11 +37,15 @@ use rustc_span::hygiene::SyntaxContext;
35
37
use rustc_span:: symbol:: { sym, Ident } ;
36
38
use rustc_span:: { ErrorGuaranteed , FileName , LocalExpnId , Span } ;
37
39
40
+ use crate :: mbe:: macro_rules:: { trace_macros_note, ParserAnyMacro } ;
41
+ use rustc_middle:: expand:: CanRetry ;
42
+ use rustc_middle:: ty:: TyCtxt ;
38
43
use smallvec:: SmallVec ;
39
44
use std:: ops:: Deref ;
40
45
use std:: path:: PathBuf ;
41
46
use std:: rc:: Rc ;
42
47
use std:: { iter, mem} ;
48
+ use tracing:: debug;
43
49
44
50
macro_rules! ast_fragments {
45
51
(
@@ -387,6 +393,18 @@ pub struct MacroExpander<'a, 'b> {
387
393
monotonic : bool , // cf. `cx.monotonic_expander()`
388
394
}
389
395
396
+ pub fn expand_legacy_bang < ' tcx > (
397
+ tcx : TyCtxt < ' tcx > ,
398
+ key : ( LocalExpnId , Span , LocalExpnId ) ,
399
+ ) -> Result < ( & ' tcx TokenStream , usize ) , CanRetry > {
400
+ let ( invoc_id, span, current_expansion) = key;
401
+ let map = tcx. macro_map . borrow ( ) ;
402
+ let ( arg, expander) = map. get ( & invoc_id) . as_ref ( ) . unwrap ( ) ;
403
+ expander
404
+ . expand ( & tcx. sess , span, arg. clone ( ) , current_expansion)
405
+ . map ( |( tts, i) | ( tcx. arena . alloc ( tts) as & TokenStream , i) )
406
+ }
407
+
390
408
impl < ' a , ' b > MacroExpander < ' a , ' b > {
391
409
pub fn new ( cx : & ' a mut ExtCtxt < ' b > , monotonic : bool ) -> Self {
392
410
MacroExpander { cx, monotonic }
@@ -672,6 +690,67 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
672
690
Err ( guar) => return ExpandResult :: Ready ( fragment_kind. dummy ( span, guar) ) ,
673
691
}
674
692
}
693
+ SyntaxExtensionKind :: TcxLegacyBang ( expander) => {
694
+ // Macros defined in the current crate have a real node id,
695
+ // whereas macros from an external crate have a dummy id.
696
+ if self . cx . trace_macros ( ) {
697
+ let msg = format ! (
698
+ "expanding `{}! {{ {} }}`" ,
699
+ expander. name( ) ,
700
+ pprust:: tts_to_string( & mac. args. tokens)
701
+ ) ;
702
+ trace_macros_note ( & mut self . cx . expansions , span, msg) ;
703
+ }
704
+
705
+ // Macros defined in the current crate have a real node id,
706
+ // whereas macros from an external crate have a dummy id.\
707
+ let tok_result: Box < dyn MacResult > = match self . cx . resolver . expand_legacy_bang (
708
+ invoc. expansion_data . id ,
709
+ span,
710
+ self . cx . current_expansion . id ,
711
+ ) {
712
+ Ok ( ( tts, i) ) => {
713
+ if self . cx . trace_macros ( ) {
714
+ let msg = format ! ( "to `{}`" , pprust:: tts_to_string( & tts) ) ;
715
+ trace_macros_note ( & mut self . cx . expansions , span, msg) ;
716
+ }
717
+ let is_local = expander. node_id ( ) != DUMMY_NODE_ID ;
718
+ if is_local {
719
+ self . cx . resolver . record_macro_rule_usage ( expander. node_id ( ) , i) ;
720
+ }
721
+
722
+ // Let the context choose how to interpret the result.
723
+ // Weird, but useful for X-macros.
724
+ Box :: new ( ParserAnyMacro :: new (
725
+ Parser :: new ( & self . cx . sess . psess , tts. clone ( ) , None ) ,
726
+ // Pass along the original expansion site and the name of the macro,
727
+ // so we can print a useful error message if the parse of the expanded
728
+ // macro leaves unparsed tokens.
729
+ span,
730
+ expander. name ( ) ,
731
+ self . cx . current_expansion . lint_node_id ,
732
+ self . cx . current_expansion . is_trailing_mac ,
733
+ expander. arm_span ( i) ,
734
+ is_local,
735
+ ) )
736
+ }
737
+ Err ( CanRetry :: No ( guar) ) => {
738
+ debug ! ( "Will not retry matching as an error was emitted already" ) ;
739
+ DummyResult :: any ( span, guar)
740
+ }
741
+ Err ( CanRetry :: Yes ) => {
742
+ // Retry and emit a better error.
743
+ DummyResult :: any_valid ( span)
744
+ }
745
+ } ;
746
+ let result = if let Some ( result) = fragment_kind. make_from ( tok_result) {
747
+ result
748
+ } else {
749
+ let guar = self . error_wrong_fragment_kind ( fragment_kind, & mac, span) ;
750
+ fragment_kind. dummy ( span, guar)
751
+ } ;
752
+ result
753
+ }
675
754
SyntaxExtensionKind :: LegacyBang ( expander) => {
676
755
let tok_result = match expander. expand ( self . cx , span, mac. args . tokens . clone ( ) ) {
677
756
ExpandResult :: Ready ( tok_result) => tok_result,
0 commit comments