@@ -534,7 +534,7 @@ impl<'a> Parser<'a> {
534534 match self . parse_delim_args ( ) {
535535 // `( .. )` or `[ .. ]` (followed by `;`), or `{ .. }`.
536536 Ok ( args) => {
537- self . eat_semi_for_macro_if_needed ( & args) ;
537+ self . eat_semi_for_macro_if_needed ( & args, Some ( & path ) ) ;
538538 self . complain_if_pub_macro ( vis, false ) ;
539539 Ok ( MacCall { path, args } )
540540 }
@@ -2392,7 +2392,7 @@ impl<'a> Parser<'a> {
23922392 }
23932393
23942394 let body = self . parse_delim_args ( ) ?;
2395- self . eat_semi_for_macro_if_needed ( & body) ;
2395+ self . eat_semi_for_macro_if_needed ( & body, None ) ;
23962396 self . complain_if_pub_macro ( vis, true ) ;
23972397
23982398 Ok ( ItemKind :: MacroDef (
@@ -2417,13 +2417,13 @@ impl<'a> Parser<'a> {
24172417 }
24182418 }
24192419
2420- fn eat_semi_for_macro_if_needed ( & mut self , args : & DelimArgs ) {
2420+ fn eat_semi_for_macro_if_needed ( & mut self , args : & DelimArgs , path : Option < & Path > ) {
24212421 if args. need_semicolon ( ) && !self . eat ( exp ! ( Semi ) ) {
2422- self . report_invalid_macro_expansion_item ( args) ;
2422+ self . report_invalid_macro_expansion_item ( args, path ) ;
24232423 }
24242424 }
24252425
2426- fn report_invalid_macro_expansion_item ( & self , args : & DelimArgs ) {
2426+ fn report_invalid_macro_expansion_item ( & self , args : & DelimArgs , path : Option < & Path > ) {
24272427 let span = args. dspan . entire ( ) ;
24282428 let mut err = self . dcx ( ) . struct_span_err (
24292429 span,
@@ -2433,17 +2433,32 @@ impl<'a> Parser<'a> {
24332433 // macros within the same crate (that we can fix), which is sad.
24342434 if !span. from_expansion ( ) {
24352435 let DelimSpan { open, close } = args. dspan ;
2436- err. multipart_suggestion (
2437- "change the delimiters to curly braces" ,
2438- vec ! [ ( open, "{" . to_string( ) ) , ( close, '}' . to_string( ) ) ] ,
2439- Applicability :: MaybeIncorrect ,
2440- ) ;
2441- err. span_suggestion (
2442- span. with_neighbor ( self . token . span ) . shrink_to_hi ( ) ,
2443- "add a semicolon" ,
2444- ';' ,
2445- Applicability :: MaybeIncorrect ,
2446- ) ;
2436+ // Check if this looks like `macro_rules!(name) { ... }`
2437+ // a common mistake when trying to define a macro.
2438+ if let Some ( path) = path
2439+ && path. segments . first ( ) . is_some_and ( |seg| seg. ident . name == sym:: macro_rules)
2440+ && args. delim == Delimiter :: Parenthesis
2441+ {
2442+ let replace =
2443+ if path. span . hi ( ) + rustc_span:: BytePos ( 1 ) < open. lo ( ) { "" } else { " " } ;
2444+ err. multipart_suggestion (
2445+ "to define a macro, remove the parentheses around the macro name" ,
2446+ vec ! [ ( open, replace. to_string( ) ) , ( close, String :: new( ) ) ] ,
2447+ Applicability :: MachineApplicable ,
2448+ ) ;
2449+ } else {
2450+ err. multipart_suggestion (
2451+ "change the delimiters to curly braces" ,
2452+ vec ! [ ( open, "{" . to_string( ) ) , ( close, '}' . to_string( ) ) ] ,
2453+ Applicability :: MaybeIncorrect ,
2454+ ) ;
2455+ err. span_suggestion (
2456+ span. with_neighbor ( self . token . span ) . shrink_to_hi ( ) ,
2457+ "add a semicolon" ,
2458+ ';' ,
2459+ Applicability :: MaybeIncorrect ,
2460+ ) ;
2461+ }
24472462 }
24482463 err. emit ( ) ;
24492464 }
0 commit comments