diff options
Diffstat (limited to 'compiler/rustc_expand/src')
| -rw-r--r-- | compiler/rustc_expand/src/base.rs | 17 | ||||
| -rw-r--r-- | compiler/rustc_expand/src/expand.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_expand/src/mbe/macro_rules.rs | 46 |
3 files changed, 64 insertions, 5 deletions
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 33b712e3aed..810a5a21a05 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -10,7 +10,7 @@ use rustc_ast::attr::{AttributeExt, MarkedAttrs}; use rustc_ast::token::MetaVarKind; use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{AssocCtxt, Visitor}; -use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind}; +use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind, Safety}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_data_structures::sync; use rustc_errors::{BufferedEarlyLint, DiagCtxtHandle, ErrorGuaranteed, PResult}; @@ -345,6 +345,21 @@ pub trait AttrProcMacro { annotation: TokenStream, annotated: TokenStream, ) -> Result<TokenStream, ErrorGuaranteed>; + + // Default implementation for safe attributes; override if the attribute can be unsafe. + fn expand_with_safety<'cx>( + &self, + ecx: &'cx mut ExtCtxt<'_>, + safety: Safety, + span: Span, + annotation: TokenStream, + annotated: TokenStream, + ) -> Result<TokenStream, ErrorGuaranteed> { + if let Safety::Unsafe(span) = safety { + ecx.dcx().span_err(span, "unnecessary `unsafe` on safe attribute"); + } + self.expand(ecx, span, annotation, annotated) + } } impl<F> AttrProcMacro for F diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 172bc3d1d9f..a035896d554 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -812,11 +812,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> { _ => item.to_tokens(), }; let attr_item = attr.get_normal_item(); + let safety = attr_item.unsafety; if let AttrArgs::Eq { .. } = attr_item.args { self.cx.dcx().emit_err(UnsupportedKeyValue { span }); } let inner_tokens = attr_item.args.inner_tokens(); - match expander.expand(self.cx, span, inner_tokens, tokens) { + match expander.expand_with_safety(self.cx, safety, span, inner_tokens, tokens) { Ok(tok_result) => { let fragment = self.parse_ast_fragment( tok_result, @@ -882,6 +883,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } } } else if let SyntaxExtensionKind::NonMacroAttr = ext { + if let ast::Safety::Unsafe(span) = attr.get_normal_item().unsafety { + self.cx.dcx().span_err(span, "unnecessary `unsafe` on safe attribute"); + } // `-Zmacro-stats` ignores these because they don't do any real expansion. self.cx.expanded_inert_attrs.mark(&attr); item.visit_attrs(|attrs| attrs.insert(pos, attr)); diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 8ed46a9fe9f..c548cea537f 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -8,7 +8,7 @@ use rustc_ast::token::NtPatKind::*; use rustc_ast::token::TokenKind::*; use rustc_ast::token::{self, Delimiter, NonterminalKind, Token, TokenKind}; use rustc_ast::tokenstream::{self, DelimSpan, TokenStream}; -use rustc_ast::{self as ast, DUMMY_NODE_ID, NodeId}; +use rustc_ast::{self as ast, DUMMY_NODE_ID, NodeId, Safety}; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan}; @@ -131,6 +131,7 @@ pub(super) enum MacroRule { Func { lhs: Vec<MatcherLoc>, lhs_span: Span, rhs: mbe::TokenTree }, /// An attr rule, for use with `#[m]` Attr { + unsafe_rule: bool, args: Vec<MatcherLoc>, args_span: Span, body: Vec<MatcherLoc>, @@ -248,7 +249,18 @@ impl TTMacroExpander for MacroRulesMacroExpander { impl AttrProcMacro for MacroRulesMacroExpander { fn expand( &self, + _cx: &mut ExtCtxt<'_>, + _sp: Span, + _args: TokenStream, + _body: TokenStream, + ) -> Result<TokenStream, ErrorGuaranteed> { + unreachable!("`expand` called on `MacroRulesMacroExpander`, expected `expand_with_safety`") + } + + fn expand_with_safety( + &self, cx: &mut ExtCtxt<'_>, + safety: Safety, sp: Span, args: TokenStream, body: TokenStream, @@ -260,6 +272,7 @@ impl AttrProcMacro for MacroRulesMacroExpander { self.node_id, self.name, self.transparency, + safety, args, body, &self.rules, @@ -408,6 +421,7 @@ fn expand_macro_attr( node_id: NodeId, name: Ident, transparency: Transparency, + safety: Safety, args: TokenStream, body: TokenStream, rules: &[MacroRule], @@ -429,13 +443,26 @@ fn expand_macro_attr( // Track nothing for the best performance. match try_match_macro_attr(psess, name, &args, &body, rules, &mut NoopTracker) { Ok((i, rule, named_matches)) => { - let MacroRule::Attr { rhs, .. } = rule else { + let MacroRule::Attr { rhs, unsafe_rule, .. } = rule else { panic!("try_macro_match_attr returned non-attr rule"); }; let mbe::TokenTree::Delimited(rhs_span, _, rhs) = rhs else { cx.dcx().span_bug(sp, "malformed macro rhs"); }; + match (safety, unsafe_rule) { + (Safety::Default, false) | (Safety::Unsafe(_), true) => {} + (Safety::Default, true) => { + cx.dcx().span_err(sp, "unsafe attribute invocation requires `unsafe`"); + } + (Safety::Unsafe(span), false) => { + cx.dcx().span_err(span, "unnecessary `unsafe` on safe attribute invocation"); + } + (Safety::Safe(span), _) => { + cx.dcx().span_bug(span, "unexpected `safe` keyword"); + } + } + let id = cx.current_expansion.id; let tts = transcribe(psess, &named_matches, rhs, *rhs_span, transparency, id) .map_err(|e| e.emit())?; @@ -681,6 +708,11 @@ pub fn compile_declarative_macro( let mut rules = Vec::new(); while p.token != token::Eof { + let unsafe_rule = p.eat_keyword_noexpect(kw::Unsafe); + let unsafe_keyword_span = p.prev_token.span; + if unsafe_rule && let Some(guar) = check_no_eof(sess, &p, "expected `attr`") { + return dummy_syn_ext(guar); + } let (args, is_derive) = if p.eat_keyword_noexpect(sym::attr) { kinds |= MacroKinds::ATTR; if !features.macro_attr() { @@ -705,6 +737,10 @@ pub fn compile_declarative_macro( feature_err(sess, sym::macro_derive, span, "`macro_rules!` derives are unstable") .emit(); } + if unsafe_rule { + sess.dcx() + .span_err(unsafe_keyword_span, "`unsafe` is only supported on `attr` rules"); + } if let Some(guar) = check_no_eof(sess, &p, "expected `()` after `derive`") { return dummy_syn_ext(guar); } @@ -730,6 +766,10 @@ pub fn compile_declarative_macro( (None, true) } else { kinds |= MacroKinds::BANG; + if unsafe_rule { + sess.dcx() + .span_err(unsafe_keyword_span, "`unsafe` is only supported on `attr` rules"); + } (None, false) }; let lhs_tt = p.parse_token_tree(); @@ -760,7 +800,7 @@ pub fn compile_declarative_macro( }; let args = mbe::macro_parser::compute_locs(&delimited.tts); let body_span = lhs_span; - rules.push(MacroRule::Attr { args, args_span, body: lhs, body_span, rhs }); + rules.push(MacroRule::Attr { unsafe_rule, args, args_span, body: lhs, body_span, rhs }); } else if is_derive { rules.push(MacroRule::Derive { body: lhs, body_span: lhs_span, rhs }); } else { |
