@@ -8,7 +8,7 @@ use rustc_ast::token::NtPatKind::*;
8
8
use rustc_ast:: token:: TokenKind :: * ;
9
9
use rustc_ast:: token:: { self , Delimiter , NonterminalKind , Token , TokenKind } ;
10
10
use 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 } ;
12
12
use rustc_ast_pretty:: pprust;
13
13
use rustc_data_structures:: fx:: { FxHashMap , FxIndexMap } ;
14
14
use rustc_errors:: { Applicability , Diag , ErrorGuaranteed , MultiSpan } ;
@@ -131,6 +131,7 @@ pub(super) enum MacroRule {
131
131
Func { lhs : Vec < MatcherLoc > , lhs_span : Span , rhs : mbe:: TokenTree } ,
132
132
/// An attr rule, for use with `#[m]`
133
133
Attr {
134
+ unsafe_rule : bool ,
134
135
args : Vec < MatcherLoc > ,
135
136
args_span : Span ,
136
137
body : Vec < MatcherLoc > ,
@@ -247,8 +248,19 @@ impl TTMacroExpander for MacroRulesMacroExpander {
247
248
248
249
impl AttrProcMacro for MacroRulesMacroExpander {
249
250
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 (
250
261
& self ,
251
262
cx : & mut ExtCtxt < ' _ > ,
263
+ safety : Safety ,
252
264
sp : Span ,
253
265
args : TokenStream ,
254
266
body : TokenStream ,
@@ -260,6 +272,7 @@ impl AttrProcMacro for MacroRulesMacroExpander {
260
272
self . node_id ,
261
273
self . name ,
262
274
self . transparency ,
275
+ safety,
263
276
args,
264
277
body,
265
278
& self . rules ,
@@ -408,6 +421,7 @@ fn expand_macro_attr(
408
421
node_id : NodeId ,
409
422
name : Ident ,
410
423
transparency : Transparency ,
424
+ safety : Safety ,
411
425
args : TokenStream ,
412
426
body : TokenStream ,
413
427
rules : & [ MacroRule ] ,
@@ -429,13 +443,26 @@ fn expand_macro_attr(
429
443
// Track nothing for the best performance.
430
444
match try_match_macro_attr ( psess, name, & args, & body, rules, & mut NoopTracker ) {
431
445
Ok ( ( i, rule, named_matches) ) => {
432
- let MacroRule :: Attr { rhs, .. } = rule else {
446
+ let MacroRule :: Attr { rhs, unsafe_rule , .. } = rule else {
433
447
panic ! ( "try_macro_match_attr returned non-attr rule" ) ;
434
448
} ;
435
449
let mbe:: TokenTree :: Delimited ( rhs_span, _, rhs) = rhs else {
436
450
cx. dcx ( ) . span_bug ( sp, "malformed macro rhs" ) ;
437
451
} ;
438
452
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
+
439
466
let id = cx. current_expansion . id ;
440
467
let tts = transcribe ( psess, & named_matches, rhs, * rhs_span, transparency, id)
441
468
. map_err ( |e| e. emit ( ) ) ?;
@@ -681,6 +708,11 @@ pub fn compile_declarative_macro(
681
708
let mut rules = Vec :: new ( ) ;
682
709
683
710
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
+ }
684
716
let ( args, is_derive) = if p. eat_keyword_noexpect ( sym:: attr) {
685
717
kinds |= MacroKinds :: ATTR ;
686
718
if !features. macro_attr ( ) {
@@ -705,6 +737,10 @@ pub fn compile_declarative_macro(
705
737
feature_err ( sess, sym:: macro_derive, span, "`macro_rules!` derives are unstable" )
706
738
. emit ( ) ;
707
739
}
740
+ if unsafe_rule {
741
+ sess. dcx ( )
742
+ . span_err ( unsafe_keyword_span, "`unsafe` is only supported on `attr` rules" ) ;
743
+ }
708
744
if let Some ( guar) = check_no_eof ( sess, & p, "expected `()` after `derive`" ) {
709
745
return dummy_syn_ext ( guar) ;
710
746
}
@@ -730,6 +766,10 @@ pub fn compile_declarative_macro(
730
766
( None , true )
731
767
} else {
732
768
kinds |= MacroKinds :: BANG ;
769
+ if unsafe_rule {
770
+ sess. dcx ( )
771
+ . span_err ( unsafe_keyword_span, "`unsafe` is only supported on `attr` rules" ) ;
772
+ }
733
773
( None , false )
734
774
} ;
735
775
let lhs_tt = p. parse_token_tree ( ) ;
@@ -741,10 +781,10 @@ pub fn compile_declarative_macro(
741
781
if let Some ( guar) = check_no_eof ( sess, & p, "expected right-hand side of macro rule" ) {
742
782
return dummy_syn_ext ( guar) ;
743
783
}
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 ) ) ;
748
788
let lhs_span = lhs_tt. span ( ) ;
749
789
// Convert the lhs into `MatcherLoc` form, which is better for doing the
750
790
// actual matching.
@@ -760,11 +800,11 @@ pub fn compile_declarative_macro(
760
800
} ;
761
801
let args = mbe:: macro_parser:: compute_locs ( & delimited. tts ) ;
762
802
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 } ) ;
764
804
} 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 } ) ;
766
806
} else {
767
- rules. push ( MacroRule :: Func { lhs, lhs_span, rhs : rhs_tt } ) ;
807
+ rules. push ( MacroRule :: Func { lhs, lhs_span, rhs } ) ;
768
808
}
769
809
if p. token == token:: Eof {
770
810
break ;
0 commit comments