@@ -14,7 +14,9 @@ use rustc_ast::ptr::P;
1414use rustc_ast:: token:: { self , Delimiter } ;
1515use rustc_ast:: tokenstream:: TokenStream ;
1616use 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+ } ;
1820use rustc_ast:: { ForeignItemKind , HasAttrs , HasNodeId } ;
1921use rustc_ast:: { Inline , ItemKind , MacStmtStyle , MetaItemKind , ModKind } ;
2022use rustc_ast:: { NestedMetaItem , NodeId , PatKind , StmtKind , TyKind } ;
@@ -35,11 +37,15 @@ use rustc_span::hygiene::SyntaxContext;
3537use rustc_span:: symbol:: { sym, Ident } ;
3638use rustc_span:: { ErrorGuaranteed , FileName , LocalExpnId , Span } ;
3739
40+ use crate :: mbe:: macro_rules:: { trace_macros_note, ParserAnyMacro } ;
41+ use rustc_middle:: expand:: CanRetry ;
42+ use rustc_middle:: ty:: TyCtxt ;
3843use smallvec:: SmallVec ;
3944use std:: ops:: Deref ;
4045use std:: path:: PathBuf ;
4146use std:: rc:: Rc ;
4247use std:: { iter, mem} ;
48+ use tracing:: debug;
4349
4450macro_rules! ast_fragments {
4551 (
@@ -387,6 +393,18 @@ pub struct MacroExpander<'a, 'b> {
387393 monotonic : bool , // cf. `cx.monotonic_expander()`
388394}
389395
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+
390408impl < ' a , ' b > MacroExpander < ' a , ' b > {
391409 pub fn new ( cx : & ' a mut ExtCtxt < ' b > , monotonic : bool ) -> Self {
392410 MacroExpander { cx, monotonic }
@@ -672,6 +690,67 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
672690 Err ( guar) => return ExpandResult :: Ready ( fragment_kind. dummy ( span, guar) ) ,
673691 }
674692 }
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+ }
675754 SyntaxExtensionKind :: LegacyBang ( expander) => {
676755 let tok_result = match expander. expand ( self . cx , span, mac. args . tokens . clone ( ) ) {
677756 ExpandResult :: Ready ( tok_result) => tok_result,
0 commit comments