@@ -8,7 +8,7 @@ use rustc_ast::token::NtPatKind::*;
88use rustc_ast:: token:: TokenKind :: * ;
99use rustc_ast:: token:: { self , Delimiter , NonterminalKind , Token , TokenKind } ;
1010use rustc_ast:: tokenstream:: { self , DelimSpan , TokenStream } ;
11- use rustc_ast:: { self as ast, DUMMY_NODE_ID , NodeId } ;
11+ use rustc_ast:: { self as ast, DUMMY_NODE_ID , NodeId , Safety } ;
1212use rustc_ast_pretty:: pprust;
1313use rustc_data_structures:: fx:: { FxHashMap , FxIndexMap } ;
1414use rustc_errors:: { Applicability , Diag , ErrorGuaranteed , MultiSpan } ;
@@ -131,6 +131,7 @@ pub(super) enum MacroRule {
131131 Func { lhs : Vec < MatcherLoc > , lhs_span : Span , rhs : mbe:: TokenTree } ,
132132 /// An attr rule, for use with `#[m]`
133133 Attr {
134+ unsafe_rule : bool ,
134135 args : Vec < MatcherLoc > ,
135136 args_span : Span ,
136137 body : Vec < MatcherLoc > ,
@@ -247,8 +248,19 @@ impl TTMacroExpander for MacroRulesMacroExpander {
247248
248249impl AttrProcMacro for MacroRulesMacroExpander {
249250 fn expand (
251+ & self ,
252+ _cx : & mut ExtCtxt < ' _ > ,
253+ _sp : Span ,
254+ _args : TokenStream ,
255+ _body : TokenStream ,
256+ ) -> Result < TokenStream , ErrorGuaranteed > {
257+ unreachable ! ( "`expand` called on `MacroRulesMacroExpander`, expected `expand_with_safety`" )
258+ }
259+
260+ fn expand_with_safety (
250261 & self ,
251262 cx : & mut ExtCtxt < ' _ > ,
263+ safety : Safety ,
252264 sp : Span ,
253265 args : TokenStream ,
254266 body : TokenStream ,
@@ -260,6 +272,7 @@ impl AttrProcMacro for MacroRulesMacroExpander {
260272 self . node_id ,
261273 self . name ,
262274 self . transparency ,
275+ safety,
263276 args,
264277 body,
265278 & self . rules ,
@@ -408,6 +421,7 @@ fn expand_macro_attr(
408421 node_id : NodeId ,
409422 name : Ident ,
410423 transparency : Transparency ,
424+ safety : Safety ,
411425 args : TokenStream ,
412426 body : TokenStream ,
413427 rules : & [ MacroRule ] ,
@@ -429,13 +443,26 @@ fn expand_macro_attr(
429443 // Track nothing for the best performance.
430444 match try_match_macro_attr ( psess, name, & args, & body, rules, & mut NoopTracker ) {
431445 Ok ( ( i, rule, named_matches) ) => {
432- let MacroRule :: Attr { rhs, .. } = rule else {
446+ let MacroRule :: Attr { rhs, unsafe_rule , .. } = rule else {
433447 panic ! ( "try_macro_match_attr returned non-attr rule" ) ;
434448 } ;
435449 let mbe:: TokenTree :: Delimited ( rhs_span, _, rhs) = rhs else {
436450 cx. dcx ( ) . span_bug ( sp, "malformed macro rhs" ) ;
437451 } ;
438452
453+ match ( safety, unsafe_rule) {
454+ ( Safety :: Default , false ) | ( Safety :: Unsafe ( _) , true ) => { }
455+ ( Safety :: Default , true ) => {
456+ cx. dcx ( ) . span_err ( sp, "unsafe attribute invocation requires `unsafe`" ) ;
457+ }
458+ ( Safety :: Unsafe ( span) , false ) => {
459+ cx. dcx ( ) . span_err ( span, "unnecessary `unsafe` on safe attribute invocation" ) ;
460+ }
461+ ( Safety :: Safe ( span) , _) => {
462+ cx. dcx ( ) . span_bug ( span, "unexpected `safe` keyword" ) ;
463+ }
464+ }
465+
439466 let id = cx. current_expansion . id ;
440467 let tts = transcribe ( psess, & named_matches, rhs, * rhs_span, transparency, id)
441468 . map_err ( |e| e. emit ( ) ) ?;
@@ -681,6 +708,11 @@ pub fn compile_declarative_macro(
681708 let mut rules = Vec :: new ( ) ;
682709
683710 while p. token != token:: Eof {
711+ let unsafe_rule = p. eat_keyword_noexpect ( kw:: Unsafe ) ;
712+ let unsafe_keyword_span = p. prev_token . span ;
713+ if unsafe_rule && let Some ( guar) = check_no_eof ( sess, & p, "expected `attr`" ) {
714+ return dummy_syn_ext ( guar) ;
715+ }
684716 let ( args, is_derive) = if p. eat_keyword_noexpect ( sym:: attr) {
685717 kinds |= MacroKinds :: ATTR ;
686718 if !features. macro_attr ( ) {
@@ -705,6 +737,10 @@ pub fn compile_declarative_macro(
705737 feature_err ( sess, sym:: macro_derive, span, "`macro_rules!` derives are unstable" )
706738 . emit ( ) ;
707739 }
740+ if unsafe_rule {
741+ sess. dcx ( )
742+ . span_err ( unsafe_keyword_span, "`unsafe` is only supported on `attr` rules" ) ;
743+ }
708744 if let Some ( guar) = check_no_eof ( sess, & p, "expected `()` after `derive`" ) {
709745 return dummy_syn_ext ( guar) ;
710746 }
@@ -730,6 +766,10 @@ pub fn compile_declarative_macro(
730766 ( None , true )
731767 } else {
732768 kinds |= MacroKinds :: BANG ;
769+ if unsafe_rule {
770+ sess. dcx ( )
771+ . span_err ( unsafe_keyword_span, "`unsafe` is only supported on `attr` rules" ) ;
772+ }
733773 ( None , false )
734774 } ;
735775 let lhs_tt = p. parse_token_tree ( ) ;
@@ -741,10 +781,10 @@ pub fn compile_declarative_macro(
741781 if let Some ( guar) = check_no_eof ( sess, & p, "expected right-hand side of macro rule" ) {
742782 return dummy_syn_ext ( guar) ;
743783 }
744- let rhs_tt = p. parse_token_tree ( ) ;
745- let rhs_tt = parse_one_tt ( rhs_tt , RulePart :: Body , sess, node_id, features, edition) ;
746- check_emission ( check_rhs ( sess, & rhs_tt ) ) ;
747- check_emission ( check_meta_variables ( & sess. psess , node_id, args. as_ref ( ) , & lhs_tt, & rhs_tt ) ) ;
784+ let rhs = p. parse_token_tree ( ) ;
785+ let rhs = parse_one_tt ( rhs , RulePart :: Body , sess, node_id, features, edition) ;
786+ check_emission ( check_rhs ( sess, & rhs ) ) ;
787+ check_emission ( check_meta_variables ( & sess. psess , node_id, args. as_ref ( ) , & lhs_tt, & rhs ) ) ;
748788 let lhs_span = lhs_tt. span ( ) ;
749789 // Convert the lhs into `MatcherLoc` form, which is better for doing the
750790 // actual matching.
@@ -760,11 +800,11 @@ pub fn compile_declarative_macro(
760800 } ;
761801 let args = mbe:: macro_parser:: compute_locs ( & delimited. tts ) ;
762802 let body_span = lhs_span;
763- rules. push ( MacroRule :: Attr { args, args_span, body : lhs, body_span, rhs : rhs_tt } ) ;
803+ rules. push ( MacroRule :: Attr { unsafe_rule , args, args_span, body : lhs, body_span, rhs } ) ;
764804 } else if is_derive {
765- rules. push ( MacroRule :: Derive { body : lhs, body_span : lhs_span, rhs : rhs_tt } ) ;
805+ rules. push ( MacroRule :: Derive { body : lhs, body_span : lhs_span, rhs } ) ;
766806 } else {
767- rules. push ( MacroRule :: Func { lhs, lhs_span, rhs : rhs_tt } ) ;
807+ rules. push ( MacroRule :: Func { lhs, lhs_span, rhs } ) ;
768808 }
769809 if p. token == token:: Eof {
770810 break ;
0 commit comments