@@ -108,7 +108,7 @@ pub trait ExpandDatabase: SourceDatabase {
108108 fn macro_arg (
109109 & self ,
110110 id : MacroCallId ,
111- ) -> ValueResult < Option < ( Arc < tt:: Subtree > , SyntaxFixupUndoInfo ) > , Arc < Box < [ SyntaxError ] > > > ;
111+ ) -> ValueResult < ( Arc < tt:: Subtree > , SyntaxFixupUndoInfo ) , Arc < Box < [ SyntaxError ] > > > ;
112112 /// Fetches the expander for this macro.
113113 #[ salsa:: transparent]
114114 #[ salsa:: invoke( TokenExpander :: macro_expander) ]
@@ -326,58 +326,77 @@ fn macro_arg(
326326 db : & dyn ExpandDatabase ,
327327 id : MacroCallId ,
328328 // FIXME: consider the following by putting fixup info into eager call info args
329- // ) -> ValueResult<Option<Arc<(tt::Subtree, SyntaxFixupUndoInfo)>>, Arc<Box<[SyntaxError]>>> {
330- ) -> ValueResult < Option < ( Arc < tt:: Subtree > , SyntaxFixupUndoInfo ) > , Arc < Box < [ SyntaxError ] > > > {
331- let mismatched_delimiters = |arg : & SyntaxNode | {
332- let first = arg. first_child_or_token ( ) . map_or ( T ! [ . ] , |it| it. kind ( ) ) ;
333- let last = arg. last_child_or_token ( ) . map_or ( T ! [ . ] , |it| it. kind ( ) ) ;
334- let well_formed_tt =
335- matches ! ( ( first, last) , ( T ![ '(' ] , T ![ ')' ] ) | ( T ![ '[' ] , T ![ ']' ] ) | ( T ![ '{' ] , T ![ '}' ] ) ) ;
336- if !well_formed_tt {
337- // Don't expand malformed (unbalanced) macro invocations. This is
338- // less than ideal, but trying to expand unbalanced macro calls
339- // sometimes produces pathological, deeply nested code which breaks
340- // all kinds of things.
341- //
342- // Some day, we'll have explicit recursion counters for all
343- // recursive things, at which point this code might be removed.
344- cov_mark:: hit!( issue9358_bad_macro_stack_overflow) ;
345- Some ( Arc :: new ( Box :: new ( [ SyntaxError :: new (
346- "unbalanced token tree" . to_owned ( ) ,
347- arg. text_range ( ) ,
348- ) ] ) as Box < [ _ ] > ) )
349- } else {
350- None
351- }
352- } ;
329+ // ) -> ValueResult<Arc<(tt::Subtree, SyntaxFixupUndoInfo)>, Arc<Box<[SyntaxError]>>> {
330+ ) -> ValueResult < ( Arc < tt:: Subtree > , SyntaxFixupUndoInfo ) , Arc < Box < [ SyntaxError ] > > > {
353331 let loc = db. lookup_intern_macro_call ( id) ;
354332 if let Some ( EagerCallInfo { arg, .. } ) = matches ! ( loc. def. kind, MacroDefKind :: BuiltInEager ( ..) )
355333 . then ( || loc. eager . as_deref ( ) )
356334 . flatten ( )
357335 {
358- ValueResult :: ok ( Some ( ( arg. clone ( ) , SyntaxFixupUndoInfo :: NONE ) ) )
336+ ValueResult :: ok ( ( arg. clone ( ) , SyntaxFixupUndoInfo :: NONE ) )
359337 } else {
360338 let ( parse, map) = parse_with_map ( db, loc. kind . file_id ( ) ) ;
361339 let root = parse. syntax_node ( ) ;
362340
363341 let syntax = match loc. kind {
364342 MacroCallKind :: FnLike { ast_id, .. } => {
343+ let dummy_tt = |kind| {
344+ (
345+ Arc :: new ( tt:: Subtree {
346+ delimiter : tt:: Delimiter {
347+ open : loc. call_site ,
348+ close : loc. call_site ,
349+ kind,
350+ } ,
351+ token_trees : Box :: default ( ) ,
352+ } ) ,
353+ SyntaxFixupUndoInfo :: default ( ) ,
354+ )
355+ } ;
356+
365357 let node = & ast_id. to_ptr ( db) . to_node ( & root) ;
366358 let offset = node. syntax ( ) . text_range ( ) . start ( ) ;
367- match node. token_tree ( ) {
368- Some ( tt) => {
369- let tt = tt. syntax ( ) ;
370- if let Some ( e) = mismatched_delimiters ( tt) {
371- return ValueResult :: only_err ( e) ;
372- }
373- tt. clone ( )
374- }
375- None => {
376- return ValueResult :: only_err ( Arc :: new ( Box :: new ( [
377- SyntaxError :: new_at_offset ( "missing token tree" . to_owned ( ) , offset) ,
378- ] ) ) ) ;
379- }
359+ let Some ( tt) = node. token_tree ( ) else {
360+ return ValueResult :: new (
361+ dummy_tt ( tt:: DelimiterKind :: Invisible ) ,
362+ Arc :: new ( Box :: new ( [ SyntaxError :: new_at_offset (
363+ "missing token tree" . to_owned ( ) ,
364+ offset,
365+ ) ] ) ) ,
366+ ) ;
367+ } ;
368+ let first = tt. left_delimiter_token ( ) . map ( |it| it. kind ( ) ) . unwrap_or ( T ! [ '(' ] ) ;
369+ let last = tt. right_delimiter_token ( ) . map ( |it| it. kind ( ) ) . unwrap_or ( T ! [ . ] ) ;
370+
371+ let mismatched_delimiters = !matches ! (
372+ ( first, last) ,
373+ ( T ![ '(' ] , T ![ ')' ] ) | ( T ![ '[' ] , T ![ ']' ] ) | ( T ![ '{' ] , T ![ '}' ] )
374+ ) ;
375+ if mismatched_delimiters {
376+ // Don't expand malformed (unbalanced) macro invocations. This is
377+ // less than ideal, but trying to expand unbalanced macro calls
378+ // sometimes produces pathological, deeply nested code which breaks
379+ // all kinds of things.
380+ //
381+ // So instead, we'll return an empty subtree here
382+ cov_mark:: hit!( issue9358_bad_macro_stack_overflow) ;
383+
384+ let kind = match first {
385+ _ if loc. def . is_proc_macro ( ) => tt:: DelimiterKind :: Invisible ,
386+ T ! [ '(' ] => tt:: DelimiterKind :: Parenthesis ,
387+ T ! [ '[' ] => tt:: DelimiterKind :: Bracket ,
388+ T ! [ '{' ] => tt:: DelimiterKind :: Brace ,
389+ _ => tt:: DelimiterKind :: Invisible ,
390+ } ;
391+ return ValueResult :: new (
392+ dummy_tt ( kind) ,
393+ Arc :: new ( Box :: new ( [ SyntaxError :: new_at_offset (
394+ "mismatched delimiters" . to_owned ( ) ,
395+ offset,
396+ ) ] ) ) ,
397+ ) ;
380398 }
399+ tt. syntax ( ) . clone ( )
381400 }
382401 MacroCallKind :: Derive { ast_id, .. } => {
383402 ast_id. to_ptr ( db) . to_node ( & root) . syntax ( ) . clone ( )
@@ -427,15 +446,15 @@ fn macro_arg(
427446
428447 if matches ! ( loc. def. kind, MacroDefKind :: BuiltInEager ( ..) ) {
429448 match parse. errors ( ) {
430- [ ] => ValueResult :: ok ( Some ( ( Arc :: new ( tt) , undo_info) ) ) ,
449+ [ ] => ValueResult :: ok ( ( Arc :: new ( tt) , undo_info) ) ,
431450 errors => ValueResult :: new (
432- Some ( ( Arc :: new ( tt) , undo_info) ) ,
451+ ( Arc :: new ( tt) , undo_info) ,
433452 // Box::<[_]>::from(res.errors()), not stable yet
434453 Arc :: new ( errors. to_vec ( ) . into_boxed_slice ( ) ) ,
435454 ) ,
436455 }
437456 } else {
438- ValueResult :: ok ( Some ( ( Arc :: new ( tt) , undo_info) ) )
457+ ValueResult :: ok ( ( Arc :: new ( tt) , undo_info) )
439458 }
440459 }
441460}
@@ -519,21 +538,20 @@ fn macro_expand(
519538 expander. expand ( db, macro_call_id, & node, map. as_ref ( ) )
520539 }
521540 _ => {
522- let ValueResult { value, err } = db. macro_arg ( macro_call_id) ;
523- let Some ( ( macro_arg, undo_info) ) = value else {
524- return ExpandResult {
525- value : CowArc :: Owned ( tt:: Subtree {
526- delimiter : tt:: Delimiter :: invisible_spanned ( loc. call_site ) ,
527- token_trees : Box :: new ( [ ] ) ,
528- } ) ,
529- // FIXME: We should make sure to enforce an invariant that invalid macro
530- // calls do not reach this call path!
531- err : Some ( ExpandError :: other ( "invalid token tree" ) ) ,
532- } ;
541+ let ValueResult { value : ( macro_arg, undo_info) , err } = db. macro_arg ( macro_call_id) ;
542+ let format_parse_err = |err : Arc < Box < [ SyntaxError ] > > | {
543+ let mut buf = String :: new ( ) ;
544+ for err in & * * err {
545+ use std:: fmt:: Write ;
546+ _ = write ! ( buf, "{}, " , err) ;
547+ }
548+ buf. pop ( ) ;
549+ buf. pop ( ) ;
550+ ExpandError :: other ( buf)
533551 } ;
534552
535553 let arg = & * macro_arg;
536- match loc. def . kind {
554+ let res = match loc. def . kind {
537555 MacroDefKind :: Declarative ( id) => {
538556 db. decl_macro_expander ( loc. def . krate , id) . expand ( db, arg. clone ( ) , macro_call_id)
539557 }
@@ -549,16 +567,7 @@ fn macro_expand(
549567 MacroDefKind :: BuiltInEager ( ..) if loc. eager . is_none ( ) => {
550568 return ExpandResult {
551569 value : CowArc :: Arc ( macro_arg. clone ( ) ) ,
552- err : err. map ( |err| {
553- let mut buf = String :: new ( ) ;
554- for err in & * * err {
555- use std:: fmt:: Write ;
556- _ = write ! ( buf, "{}, " , err) ;
557- }
558- buf. pop ( ) ;
559- buf. pop ( ) ;
560- ExpandError :: other ( buf)
561- } ) ,
570+ err : err. map ( format_parse_err) ,
562571 } ;
563572 }
564573 MacroDefKind :: BuiltInEager ( it, _) => {
@@ -570,6 +579,11 @@ fn macro_expand(
570579 res
571580 }
572581 _ => unreachable ! ( ) ,
582+ } ;
583+ ExpandResult {
584+ value : res. value ,
585+ // if the arg had parse errors, show them instead of the expansion errors
586+ err : err. map ( format_parse_err) . or ( res. err ) ,
573587 }
574588 }
575589 } ;
@@ -597,17 +611,7 @@ fn macro_expand(
597611
598612fn expand_proc_macro ( db : & dyn ExpandDatabase , id : MacroCallId ) -> ExpandResult < Arc < tt:: Subtree > > {
599613 let loc = db. lookup_intern_macro_call ( id) ;
600- let Some ( ( macro_arg, undo_info) ) = db. macro_arg ( id) . value else {
601- return ExpandResult {
602- value : Arc :: new ( tt:: Subtree {
603- delimiter : tt:: Delimiter :: invisible_spanned ( loc. call_site ) ,
604- token_trees : Box :: new ( [ ] ) ,
605- } ) ,
606- // FIXME: We should make sure to enforce an invariant that invalid macro
607- // calls do not reach this call path!
608- err : Some ( ExpandError :: other ( "invalid token tree" ) ) ,
609- } ;
610- } ;
614+ let ( macro_arg, undo_info) = db. macro_arg ( id) . value ;
611615
612616 let expander = match loc. def . kind {
613617 MacroDefKind :: ProcMacro ( expander, ..) => expander,
0 commit comments