@@ -12,13 +12,15 @@ use rustc_ast::visit::{self, try_visit, walk_list, AssocCtxt, Visitor, VisitorRe
12
12
use rustc_ast:: {
13
13
AssocItemKind , AstNodeWrapper , AttrArgs , AttrStyle , AttrVec , ExprKind , ForeignItemKind ,
14
14
HasAttrs , HasNodeId , Inline , ItemKind , MacStmtStyle , MetaItemKind , ModKind , NestedMetaItem ,
15
- NodeId , PatKind , StmtKind , TyKind ,
15
+ NodeId , PatKind , StmtKind , TyKind , DUMMY_NODE_ID ,
16
16
} ;
17
17
use rustc_ast_pretty:: pprust;
18
18
use rustc_data_structures:: flat_map_in_place:: FlatMapInPlace ;
19
19
use rustc_data_structures:: sync:: Lrc ;
20
20
use rustc_errors:: PResult ;
21
21
use rustc_feature:: Features ;
22
+ use rustc_middle:: expand:: CanRetry ;
23
+ use rustc_middle:: ty:: TyCtxt ;
22
24
use rustc_parse:: parser:: {
23
25
AttemptLocalParseRecovery , CommaRecoveryMode , ForceCollect , Parser , RecoverColon , RecoverComma ,
24
26
} ;
@@ -31,6 +33,7 @@ use rustc_span::hygiene::SyntaxContext;
31
33
use rustc_span:: symbol:: { sym, Ident } ;
32
34
use rustc_span:: { ErrorGuaranteed , FileName , LocalExpnId , Span } ;
33
35
use smallvec:: SmallVec ;
36
+ use tracing:: debug;
34
37
35
38
use crate :: base:: * ;
36
39
use crate :: config:: StripUnconfigured ;
@@ -40,6 +43,7 @@ use crate::errors::{
40
43
WrongFragmentKind ,
41
44
} ;
42
45
use crate :: mbe:: diagnostics:: annotate_err_with_kind;
46
+ use crate :: mbe:: macro_rules:: { trace_macros_note, ParserAnyMacro } ;
43
47
use crate :: module:: { mod_dir_path, parse_external_mod, DirOwnership , ParsedExternalMod } ;
44
48
use crate :: placeholders:: { placeholder, PlaceholderExpander } ;
45
49
@@ -394,6 +398,18 @@ pub struct MacroExpander<'a, 'b> {
394
398
monotonic : bool , // cf. `cx.monotonic_expander()`
395
399
}
396
400
401
+ pub fn expand_legacy_bang < ' tcx > (
402
+ tcx : TyCtxt < ' tcx > ,
403
+ key : ( LocalExpnId , Span , LocalExpnId ) ,
404
+ ) -> Result < ( & ' tcx TokenStream , usize ) , CanRetry > {
405
+ let ( invoc_id, span, current_expansion) = key;
406
+ let map = tcx. macro_map . borrow ( ) ;
407
+ let ( arg, expander) = map. get ( & invoc_id) . as_ref ( ) . unwrap ( ) ;
408
+ expander
409
+ . expand ( & tcx. sess , span, arg. clone ( ) , current_expansion)
410
+ . map ( |( tts, i) | ( tcx. arena . alloc ( tts) as & TokenStream , i) )
411
+ }
412
+
397
413
impl < ' a , ' b > MacroExpander < ' a , ' b > {
398
414
pub fn new ( cx : & ' a mut ExtCtxt < ' b > , monotonic : bool ) -> Self {
399
415
MacroExpander { cx, monotonic }
@@ -679,6 +695,67 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
679
695
Err ( guar) => return ExpandResult :: Ready ( fragment_kind. dummy ( span, guar) ) ,
680
696
}
681
697
}
698
+ SyntaxExtensionKind :: TcxLegacyBang ( expander) => {
699
+ // Macros defined in the current crate have a real node id,
700
+ // whereas macros from an external crate have a dummy id.
701
+ if self . cx . trace_macros ( ) {
702
+ let msg = format ! (
703
+ "expanding `{}! {{ {} }}`" ,
704
+ expander. name( ) ,
705
+ pprust:: tts_to_string( & mac. args. tokens)
706
+ ) ;
707
+ trace_macros_note ( & mut self . cx . expansions , span, msg) ;
708
+ }
709
+
710
+ // Macros defined in the current crate have a real node id,
711
+ // whereas macros from an external crate have a dummy id.\
712
+ let tok_result: Box < dyn MacResult > = match self . cx . resolver . expand_legacy_bang (
713
+ invoc. expansion_data . id ,
714
+ span,
715
+ self . cx . current_expansion . id ,
716
+ ) {
717
+ Ok ( ( tts, i) ) => {
718
+ if self . cx . trace_macros ( ) {
719
+ let msg = format ! ( "to `{}`" , pprust:: tts_to_string( & tts) ) ;
720
+ trace_macros_note ( & mut self . cx . expansions , span, msg) ;
721
+ }
722
+ let is_local = expander. node_id ( ) != DUMMY_NODE_ID ;
723
+ if is_local {
724
+ self . cx . resolver . record_macro_rule_usage ( expander. node_id ( ) , i) ;
725
+ }
726
+
727
+ // Let the context choose how to interpret the result.
728
+ // Weird, but useful for X-macros.
729
+ Box :: new ( ParserAnyMacro :: new (
730
+ Parser :: new ( & self . cx . sess . psess , tts. clone ( ) , None ) ,
731
+ // Pass along the original expansion site and the name of the macro,
732
+ // so we can print a useful error message if the parse of the expanded
733
+ // macro leaves unparsed tokens.
734
+ span,
735
+ expander. name ( ) ,
736
+ self . cx . current_expansion . lint_node_id ,
737
+ self . cx . current_expansion . is_trailing_mac ,
738
+ expander. arm_span ( i) ,
739
+ is_local,
740
+ ) )
741
+ }
742
+ Err ( CanRetry :: No ( guar) ) => {
743
+ debug ! ( "Will not retry matching as an error was emitted already" ) ;
744
+ DummyResult :: any ( span, guar)
745
+ }
746
+ Err ( CanRetry :: Yes ) => {
747
+ // Retry and emit a better error.
748
+ DummyResult :: any_valid ( span)
749
+ }
750
+ } ;
751
+ let result = if let Some ( result) = fragment_kind. make_from ( tok_result) {
752
+ result
753
+ } else {
754
+ let guar = self . error_wrong_fragment_kind ( fragment_kind, & mac, span) ;
755
+ fragment_kind. dummy ( span, guar)
756
+ } ;
757
+ result
758
+ }
682
759
SyntaxExtensionKind :: LegacyBang ( expander) => {
683
760
let tok_result = match expander. expand ( self . cx , span, mac. args . tokens . clone ( ) ) {
684
761
ExpandResult :: Ready ( tok_result) => tok_result,
0 commit comments