@@ -57,10 +57,7 @@ impl TokenExpander {
5757 TokenExpander :: BuiltinAttr ( it) => it. expand ( db, id, tt) ,
5858 TokenExpander :: BuiltinDerive ( it) => it. expand ( db, id, tt) ,
5959 TokenExpander :: ProcMacro ( _) => {
60- // We store the result in salsa db to prevent non-deterministic behavior in
61- // some proc-macro implementation
62- // See #4315 for details
63- db. expand_proc_macro ( id)
60+ unreachable ! ( "ExpandDatabase::expand_proc_macro should be used for proc macros" )
6461 }
6562 }
6663 }
@@ -141,8 +138,8 @@ pub trait ExpandDatabase: SourceDatabase {
141138 /// Special case of the previous query for procedural macros. We can't LRU
142139 /// proc macros, since they are not deterministic in general, and
143140 /// non-determinism breaks salsa in a very, very, very bad way.
144- /// @edwin0cheng heroically debugged this once!
145- fn expand_proc_macro ( & self , call : MacroCallId ) -> ExpandResult < tt:: Subtree > ;
141+ /// @edwin0cheng heroically debugged this once! See #4315 for details
142+ fn expand_proc_macro ( & self , call : MacroCallId ) -> ExpandResult < Arc < tt:: Subtree > > ;
146143 /// Firewall query that returns the errors from the `parse_macro_expansion` query.
147144 fn parse_macro_expansion_error (
148145 & self ,
@@ -297,6 +294,14 @@ fn parse_macro_expansion(
297294 ExpandResult { value : ( parse, Arc :: new ( rev_token_map) ) , err }
298295}
299296
297+ fn parse_macro_expansion_error (
298+ db : & dyn ExpandDatabase ,
299+ macro_call_id : MacroCallId ,
300+ ) -> ExpandResult < Box < [ SyntaxError ] > > {
301+ db. parse_macro_expansion ( MacroFile { macro_call_id } )
302+ . map ( |it| it. 0 . errors ( ) . to_vec ( ) . into_boxed_slice ( ) )
303+ }
304+
300305fn macro_arg (
301306 db : & dyn ExpandDatabase ,
302307 id : MacroCallId ,
@@ -445,6 +450,11 @@ fn macro_expand(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<Arc<tt
445450 // This is an input expansion for an eager macro. These are already pre-expanded
446451 return ExpandResult { value : Arc :: new ( arg. 0 . clone ( ) ) , err : error. clone ( ) } ;
447452 }
453+
454+ if let MacroDefKind :: ProcMacro ( ..) = loc. def . kind {
455+ return db. expand_proc_macro ( id) ;
456+ }
457+
448458 let expander = match db. macro_def ( loc. def ) {
449459 Ok ( it) => it,
450460 // FIXME: We should make sure to enforce a variant that invalid macro
@@ -467,7 +477,7 @@ fn macro_expand(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<Arc<tt
467477 token_trees : Vec :: new ( ) ,
468478 } ,
469479 ) ,
470- // FIXME: We should make sure to enforce a variant that invalid macro
480+ // FIXME: We should make sure to enforce an invariant that invalid macro
471481 // calls do not reach this call path!
472482 err : Some ( ExpandError :: other (
473483 "invalid token tree"
@@ -483,47 +493,29 @@ fn macro_expand(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<Arc<tt
483493 }
484494
485495 // Set a hard limit for the expanded tt
486- let count = tt. count ( ) ;
487- if TOKEN_LIMIT . check ( count) . is_err ( ) {
488- return ExpandResult {
489- value : Arc :: new ( tt:: Subtree {
490- delimiter : tt:: Delimiter :: UNSPECIFIED ,
491- token_trees : vec ! [ ] ,
492- } ) ,
493- err : Some ( ExpandError :: other ( format ! (
494- "macro invocation exceeds token limit: produced {} tokens, limit is {}" ,
495- count,
496- TOKEN_LIMIT . inner( ) ,
497- ) ) ) ,
498- } ;
496+ if let Err ( value) = check_tt_count ( & tt) {
497+ return value;
499498 }
500499
501500 fixup:: reverse_fixups ( & mut tt, arg_tm, undo_info) ;
502501
503502 ExpandResult { value : Arc :: new ( tt) , err }
504503}
505504
506- fn parse_macro_expansion_error (
507- db : & dyn ExpandDatabase ,
508- macro_call_id : MacroCallId ,
509- ) -> ExpandResult < Box < [ SyntaxError ] > > {
510- db. parse_macro_expansion ( MacroFile { macro_call_id } )
511- . map ( |it| it. 0 . errors ( ) . to_vec ( ) . into_boxed_slice ( ) )
512- }
513-
514- fn expand_proc_macro ( db : & dyn ExpandDatabase , id : MacroCallId ) -> ExpandResult < tt:: Subtree > {
505+ fn expand_proc_macro ( db : & dyn ExpandDatabase , id : MacroCallId ) -> ExpandResult < Arc < tt:: Subtree > > {
515506 let loc = db. lookup_intern_macro_call ( id) ;
516507 let Some ( macro_arg) = db. macro_arg ( id) else {
517508 return ExpandResult {
518- value : tt:: Subtree {
509+ value : Arc :: new ( tt:: Subtree {
519510 delimiter : tt:: Delimiter :: UNSPECIFIED ,
520511 token_trees : Vec :: new ( ) ,
521- } ,
512+ } ) ,
522513 err : Some ( ExpandError :: other (
523514 "invalid token tree"
524515 ) ) ,
525516 } ;
526517 } ;
518+ let ( arg_tt, arg_tm, undo_info) = & * macro_arg;
527519
528520 let expander = match loc. def . kind {
529521 MacroDefKind :: ProcMacro ( expander, ..) => expander,
@@ -533,13 +525,23 @@ fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<t
533525 let attr_arg = match & loc. kind {
534526 MacroCallKind :: Attr { attr_args, .. } => {
535527 let mut attr_args = attr_args. 0 . clone ( ) ;
536- mbe:: Shift :: new ( & macro_arg . 0 ) . shift_all ( & mut attr_args) ;
528+ mbe:: Shift :: new ( arg_tt ) . shift_all ( & mut attr_args) ;
537529 Some ( attr_args)
538530 }
539531 _ => None ,
540532 } ;
541533
542- expander. expand ( db, loc. def . krate , loc. krate , & macro_arg. 0 , attr_arg. as_ref ( ) )
534+ let ExpandResult { value : mut tt, err } =
535+ expander. expand ( db, loc. def . krate , loc. krate , arg_tt, attr_arg. as_ref ( ) ) ;
536+
537+ // Set a hard limit for the expanded tt
538+ if let Err ( value) = check_tt_count ( & tt) {
539+ return value;
540+ }
541+
542+ fixup:: reverse_fixups ( & mut tt, arg_tm, undo_info) ;
543+
544+ ExpandResult { value : Arc :: new ( tt) , err }
543545}
544546
545547fn hygiene_frame ( db : & dyn ExpandDatabase , file_id : HirFileId ) -> Arc < HygieneFrame > {
@@ -563,3 +565,22 @@ fn token_tree_to_syntax_node(
563565 } ;
564566 mbe:: token_tree_to_syntax_node ( tt, entry_point)
565567}
568+
569+ fn check_tt_count ( tt : & tt:: Subtree ) -> Result < ( ) , ExpandResult < Arc < tt:: Subtree > > > {
570+ let count = tt. count ( ) ;
571+ if TOKEN_LIMIT . check ( count) . is_err ( ) {
572+ Err ( ExpandResult {
573+ value : Arc :: new ( tt:: Subtree {
574+ delimiter : tt:: Delimiter :: UNSPECIFIED ,
575+ token_trees : vec ! [ ] ,
576+ } ) ,
577+ err : Some ( ExpandError :: other ( format ! (
578+ "macro invocation exceeds token limit: produced {} tokens, limit is {}" ,
579+ count,
580+ TOKEN_LIMIT . inner( ) ,
581+ ) ) ) ,
582+ } )
583+ } else {
584+ Ok ( ( ) )
585+ }
586+ }
0 commit comments