@@ -12,13 +12,15 @@ use rustc_ast::visit::{self, try_visit, walk_list, AssocCtxt, Visitor, VisitorRe
1212use rustc_ast:: {
1313 AssocItemKind , AstNodeWrapper , AttrArgs , AttrStyle , AttrVec , ExprKind , ForeignItemKind ,
1414 HasAttrs , HasNodeId , Inline , ItemKind , MacStmtStyle , MetaItemKind , ModKind , NestedMetaItem ,
15- NodeId , PatKind , StmtKind , TyKind ,
15+ NodeId , PatKind , StmtKind , TyKind , DUMMY_NODE_ID ,
1616} ;
1717use rustc_ast_pretty:: pprust;
1818use rustc_data_structures:: flat_map_in_place:: FlatMapInPlace ;
1919use rustc_data_structures:: sync:: Lrc ;
2020use rustc_errors:: PResult ;
2121use rustc_feature:: Features ;
22+ use rustc_middle:: expand:: CanRetry ;
23+ use rustc_middle:: ty:: TyCtxt ;
2224use rustc_parse:: parser:: {
2325 AttemptLocalParseRecovery , CommaRecoveryMode , ForceCollect , Parser , RecoverColon , RecoverComma ,
2426} ;
@@ -31,6 +33,7 @@ use rustc_span::hygiene::SyntaxContext;
3133use rustc_span:: symbol:: { sym, Ident } ;
3234use rustc_span:: { ErrorGuaranteed , FileName , LocalExpnId , Span } ;
3335use smallvec:: SmallVec ;
36+ use tracing:: debug;
3437
3538use crate :: base:: * ;
3639use crate :: config:: StripUnconfigured ;
@@ -40,6 +43,7 @@ use crate::errors::{
4043 WrongFragmentKind ,
4144} ;
4245use crate :: mbe:: diagnostics:: annotate_err_with_kind;
46+ use crate :: mbe:: macro_rules:: { trace_macros_note, ParserAnyMacro } ;
4347use crate :: module:: { mod_dir_path, parse_external_mod, DirOwnership , ParsedExternalMod } ;
4448use crate :: placeholders:: { placeholder, PlaceholderExpander } ;
4549
@@ -394,6 +398,18 @@ pub struct MacroExpander<'a, 'b> {
394398 monotonic : bool , // cf. `cx.monotonic_expander()`
395399}
396400
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+
397413impl < ' a , ' b > MacroExpander < ' a , ' b > {
398414 pub fn new ( cx : & ' a mut ExtCtxt < ' b > , monotonic : bool ) -> Self {
399415 MacroExpander { cx, monotonic }
@@ -679,6 +695,67 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
679695 Err ( guar) => return ExpandResult :: Ready ( fragment_kind. dummy ( span, guar) ) ,
680696 }
681697 }
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+ }
682759 SyntaxExtensionKind :: LegacyBang ( expander) => {
683760 let tok_result = match expander. expand ( self . cx , span, mac. args . tokens . clone ( ) ) {
684761 ExpandResult :: Ready ( tok_result) => tok_result,
0 commit comments