@@ -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 {
131131Func  {  lhs :  Vec < MatcherLoc > ,  lhs_span :  Span ,  rhs :  mbe:: TokenTree  } , 
132132    /// An attr rule, for use with `#[m]` 
133133Attr  { 
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