Skip to content

Commit

Permalink
Rollup merge of #124214 - carbotaniuman:parse_unsafe_attrs, r=michael…
Browse files Browse the repository at this point in the history
…woerister

Parse unsafe attributes

Initial parse implementation for #123757

This is the initial work to parse unsafe attributes, which is represented as an extra `unsafety` field in `MetaItem` and `AttrItem`. There's two areas in the code where it appears that parsing is done manually and not using the parser stuff, and I'm not sure how I'm supposed to thread the change there.
  • Loading branch information
matthiaskrgr authored Jun 7, 2024
2 parents 0acb5b8 + f9104f0 commit 6e534c7
Show file tree
Hide file tree
Showing 36 changed files with 357 additions and 34 deletions.
9 changes: 8 additions & 1 deletion compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,7 @@ pub struct Crate {
/// E.g., `#[test]`, `#[derive(..)]`, `#[rustfmt::skip]` or `#[feature = "foo"]`.
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
pub struct MetaItem {
pub unsafety: Safety,
pub path: Path,
pub kind: MetaItemKind,
pub span: Span,
Expand Down Expand Up @@ -2823,14 +2824,20 @@ pub struct NormalAttr {
impl NormalAttr {
pub fn from_ident(ident: Ident) -> Self {
Self {
item: AttrItem { path: Path::from_ident(ident), args: AttrArgs::Empty, tokens: None },
item: AttrItem {
unsafety: Safety::Default,
path: Path::from_ident(ident),
args: AttrArgs::Empty,
tokens: None,
},
tokens: None,
}
}
}

#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
pub struct AttrItem {
pub unsafety: Safety,
pub path: Path,
pub args: AttrArgs,
// Tokens for the meta item, e.g. just the `foo` within `#[foo]` or `#![foo]`.
Expand Down
35 changes: 27 additions & 8 deletions compiler/rustc_ast/src/attr/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//! Functions dealing with attributes and meta items.
use crate::ast::{AttrArgs, AttrArgsEq, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute};
use crate::ast::{
AttrArgs, AttrArgsEq, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute, Safety,
};
use crate::ast::{DelimArgs, Expr, ExprKind, LitKind, MetaItemLit};
use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem, NormalAttr};
use crate::ast::{Path, PathSegment, DUMMY_NODE_ID};
Expand Down Expand Up @@ -238,7 +240,12 @@ impl AttrItem {
}

pub fn meta(&self, span: Span) -> Option<MetaItem> {
Some(MetaItem { path: self.path.clone(), kind: self.meta_kind()?, span })
Some(MetaItem {
unsafety: Safety::Default,
path: self.path.clone(),
kind: self.meta_kind()?,
span,
})
}

pub fn meta_kind(&self) -> Option<MetaItemKind> {
Expand Down Expand Up @@ -371,7 +378,10 @@ impl MetaItem {
_ => path.span.hi(),
};
let span = path.span.with_hi(hi);
Some(MetaItem { path, kind, span })
// FIXME: This parses `unsafe()` not as unsafe attribute syntax in `MetaItem`,
// but as a parenthesized list. This (and likely `MetaItem`) should be changed in
// such a way that builtin macros don't accept extraneous `unsafe()`.
Some(MetaItem { unsafety: Safety::Default, path, kind, span })
}
}

Expand Down Expand Up @@ -555,11 +565,12 @@ pub fn mk_doc_comment(
pub fn mk_attr(
g: &AttrIdGenerator,
style: AttrStyle,
unsafety: Safety,
path: Path,
args: AttrArgs,
span: Span,
) -> Attribute {
mk_attr_from_item(g, AttrItem { path, args, tokens: None }, None, style, span)
mk_attr_from_item(g, AttrItem { unsafety, path, args, tokens: None }, None, style, span)
}

pub fn mk_attr_from_item(
Expand All @@ -577,15 +588,22 @@ pub fn mk_attr_from_item(
}
}

pub fn mk_attr_word(g: &AttrIdGenerator, style: AttrStyle, name: Symbol, span: Span) -> Attribute {
pub fn mk_attr_word(
g: &AttrIdGenerator,
style: AttrStyle,
unsafety: Safety,
name: Symbol,
span: Span,
) -> Attribute {
let path = Path::from_ident(Ident::new(name, span));
let args = AttrArgs::Empty;
mk_attr(g, style, path, args, span)
mk_attr(g, style, unsafety, path, args, span)
}

pub fn mk_attr_nested_word(
g: &AttrIdGenerator,
style: AttrStyle,
unsafety: Safety,
outer: Symbol,
inner: Symbol,
span: Span,
Expand All @@ -601,12 +619,13 @@ pub fn mk_attr_nested_word(
delim: Delimiter::Parenthesis,
tokens: inner_tokens,
});
mk_attr(g, style, path, attr_args, span)
mk_attr(g, style, unsafety, path, attr_args, span)
}

pub fn mk_attr_name_value_str(
g: &AttrIdGenerator,
style: AttrStyle,
unsafety: Safety,
name: Symbol,
val: Symbol,
span: Span,
Expand All @@ -621,7 +640,7 @@ pub fn mk_attr_name_value_str(
});
let path = Path::from_ident(Ident::new(name, span));
let args = AttrArgs::Eq(span, AttrArgsEq::Ast(expr));
mk_attr(g, style, path, args, span)
mk_attr(g, style, unsafety, path, args, span)
}

pub fn filter_by_name(attrs: &[Attribute], name: Symbol) -> impl Iterator<Item = &Attribute> {
Expand Down
10 changes: 6 additions & 4 deletions compiler/rustc_ast/src/mut_visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -647,8 +647,10 @@ fn noop_visit_attribute<T: MutVisitor>(attr: &mut Attribute, vis: &mut T) {
let Attribute { kind, id: _, style: _, span } = attr;
match kind {
AttrKind::Normal(normal) => {
let NormalAttr { item: AttrItem { path, args, tokens }, tokens: attr_tokens } =
&mut **normal;
let NormalAttr {
item: AttrItem { unsafety: _, path, args, tokens },
tokens: attr_tokens,
} = &mut **normal;
vis.visit_path(path);
visit_attr_args(args, vis);
visit_lazy_tts(tokens, vis);
Expand Down Expand Up @@ -678,7 +680,7 @@ fn noop_visit_meta_list_item<T: MutVisitor>(li: &mut NestedMetaItem, vis: &mut T
}

fn noop_visit_meta_item<T: MutVisitor>(mi: &mut MetaItem, vis: &mut T) {
let MetaItem { path: _, kind, span } = mi;
let MetaItem { unsafety: _, path: _, kind, span } = mi;
match kind {
MetaItemKind::Word => {}
MetaItemKind::List(mis) => visit_thin_vec(mis, |mi| vis.visit_meta_list_item(mi)),
Expand Down Expand Up @@ -840,7 +842,7 @@ fn visit_nonterminal<T: MutVisitor>(nt: &mut token::Nonterminal, vis: &mut T) {
token::NtTy(ty) => vis.visit_ty(ty),
token::NtLiteral(expr) => vis.visit_expr(expr),
token::NtMeta(item) => {
let AttrItem { path, args, tokens } = item.deref_mut();
let AttrItem { unsafety: _, path, args, tokens } = item.deref_mut();
vis.visit_path(path);
visit_attr_args(args, vis);
visit_lazy_tts(tokens, vis);
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_ast_lowering/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1805,6 +1805,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let attr = attr::mk_attr_nested_word(
&self.tcx.sess.psess.attr_id_generator,
AttrStyle::Outer,
Safety::Default,
sym::allow,
sym::unreachable_code,
self.lower_span(span),
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -905,6 +905,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let kind = match attr.kind {
AttrKind::Normal(ref normal) => AttrKind::Normal(P(NormalAttr {
item: AttrItem {
unsafety: normal.item.unsafety,
path: normal.item.path.clone(),
args: self.lower_attr_args(&normal.item.args),
tokens: None,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
gate_all!(mut_ref, "mutable by-reference bindings are experimental");
gate_all!(precise_capturing, "precise captures on `impl Trait` are experimental");
gate_all!(global_registration, "global registration is experimental");
gate_all!(unsafe_attributes, "`#[unsafe()]` markers for attributes are experimental");

if !visitor.features.never_patterns {
if let Some(spans) = spans.get(&sym::never_patterns) {
Expand Down
11 changes: 9 additions & 2 deletions compiler/rustc_ast_pretty/src/pprust/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use rustc_ast::token::{self, BinOpToken, CommentKind, Delimiter, Nonterminal, To
use rustc_ast::tokenstream::{Spacing, TokenStream, TokenTree};
use rustc_ast::util::classify;
use rustc_ast::util::comments::{Comment, CommentStyle};
use rustc_ast::{self as ast, AttrArgs, AttrArgsEq, BlockCheckMode, PatKind};
use rustc_ast::{self as ast, AttrArgs, AttrArgsEq, BlockCheckMode, PatKind, Safety};
use rustc_ast::{attr, BindingMode, ByRef, DelimArgs, RangeEnd, RangeSyntax, Term};
use rustc_ast::{GenericArg, GenericBound, SelfKind};
use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass};
Expand Down Expand Up @@ -249,6 +249,7 @@ pub fn print_crate<'a>(
let fake_attr = attr::mk_attr_nested_word(
g,
ast::AttrStyle::Inner,
Safety::Default,
sym::feature,
sym::prelude_import,
DUMMY_SP,
Expand All @@ -259,7 +260,13 @@ pub fn print_crate<'a>(
// root, so this is not needed, and actually breaks things.
if edition.is_rust_2015() {
// `#![no_std]`
let fake_attr = attr::mk_attr_word(g, ast::AttrStyle::Inner, sym::no_std, DUMMY_SP);
let fake_attr = attr::mk_attr_word(
g,
ast::AttrStyle::Inner,
Safety::Default,
sym::no_std,
DUMMY_SP,
);
s.print_attribute(&fake_attr);
}
}
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_builtin_macros/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ builtin_macros_derive_path_args_list = traits in `#[derive(...)]` don't accept a
builtin_macros_derive_path_args_value = traits in `#[derive(...)]` don't accept values
.suggestion = remove the value
builtin_macros_derive_unsafe_path = traits in `#[derive(...)]` don't accept `unsafe(...)`
.suggestion = remove the `unsafe(...)`
builtin_macros_env_not_defined = environment variable `{$var}` not defined at compile time
.cargo = Cargo sets build script variables at run time. Use `std::env::var({$var_expr})` instead
.custom = use `std::env::var({$var_expr})` to read the variable at run time
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_builtin_macros/src/cmdline_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) {
));

let start_span = parser.token.span;
let AttrItem { path, args, tokens: _ } = match parser.parse_attr_item(false) {
let AttrItem { unsafety, path, args, tokens: _ } = match parser.parse_attr_item(false) {
Ok(ai) => ai,
Err(err) => {
err.emit();
Expand All @@ -33,6 +33,7 @@ pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) {
krate.attrs.push(mk_attr(
&psess.attr_id_generator,
AttrStyle::Inner,
unsafety,
path,
args,
start_span.to(end_span),
Expand Down
13 changes: 12 additions & 1 deletion compiler/rustc_builtin_macros/src/derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::cfg_eval::cfg_eval;
use crate::errors;

use rustc_ast as ast;
use rustc_ast::{GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind};
use rustc_ast::{GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, Safety, StmtKind};
use rustc_expand::base::{
Annotatable, DeriveResolution, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier,
};
Expand Down Expand Up @@ -60,6 +60,7 @@ impl MultiItemModifier for Expander {
// Reject `#[derive(Debug = "value", Debug(abc))]`, but recover the
// paths.
report_path_args(sess, meta);
report_unsafe_args(sess, meta);
meta.path.clone()
})
.map(|path| DeriveResolution {
Expand Down Expand Up @@ -159,3 +160,13 @@ fn report_path_args(sess: &Session, meta: &ast::MetaItem) {
}
}
}

fn report_unsafe_args(sess: &Session, meta: &ast::MetaItem) {
match meta.unsafety {
Safety::Unsafe(span) => {
sess.dcx().emit_err(errors::DeriveUnsafePath { span });
}
Safety::Default => {}
Safety::Safe(_) => unreachable!(),
}
}
7 changes: 7 additions & 0 deletions compiler/rustc_builtin_macros/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,13 @@ pub(crate) struct DerivePathArgsValue {
pub(crate) span: Span,
}

#[derive(Diagnostic)]
#[diag(builtin_macros_derive_unsafe_path)]
pub(crate) struct DeriveUnsafePath {
#[primary_span]
pub(crate) span: Span,
}

#[derive(Diagnostic)]
#[diag(builtin_macros_no_default_variant)]
#[help]
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_builtin_macros/src/test_harness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> {
let allow_dead_code = attr::mk_attr_nested_word(
&self.sess.psess.attr_id_generator,
ast::AttrStyle::Outer,
ast::Safety::Default,
sym::allow,
sym::dead_code,
self.def_site,
Expand Down
20 changes: 17 additions & 3 deletions compiler/rustc_expand/src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -666,20 +666,34 @@ impl<'a> ExtCtxt<'a> {
// Builds `#[name]`.
pub fn attr_word(&self, name: Symbol, span: Span) -> ast::Attribute {
let g = &self.sess.psess.attr_id_generator;
attr::mk_attr_word(g, ast::AttrStyle::Outer, name, span)
attr::mk_attr_word(g, ast::AttrStyle::Outer, ast::Safety::Default, name, span)
}

// Builds `#[name = val]`.
//
// Note: `span` is used for both the identifier and the value.
pub fn attr_name_value_str(&self, name: Symbol, val: Symbol, span: Span) -> ast::Attribute {
let g = &self.sess.psess.attr_id_generator;
attr::mk_attr_name_value_str(g, ast::AttrStyle::Outer, name, val, span)
attr::mk_attr_name_value_str(
g,
ast::AttrStyle::Outer,
ast::Safety::Default,
name,
val,
span,
)
}

// Builds `#[outer(inner)]`.
pub fn attr_nested_word(&self, outer: Symbol, inner: Symbol, span: Span) -> ast::Attribute {
let g = &self.sess.psess.attr_id_generator;
attr::mk_attr_nested_word(g, ast::AttrStyle::Outer, outer, inner, span)
attr::mk_attr_nested_word(
g,
ast::AttrStyle::Outer,
ast::Safety::Default,
outer,
inner,
span,
)
}
}
9 changes: 8 additions & 1 deletion compiler/rustc_expand/src/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -778,7 +778,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
if let SyntaxExtensionKind::Derive(..) = ext {
self.gate_proc_macro_input(&item);
}
let meta = ast::MetaItem { kind: MetaItemKind::Word, span, path };
// The `MetaItem` representing the trait to derive can't
// have an unsafe around it (as of now).
let meta = ast::MetaItem {
unsafety: ast::Safety::Default,
kind: MetaItemKind::Word,
span,
path,
};
let items = match expander.expand(self.cx, span, &meta, item, is_const) {
ExpandResult::Ready(items) => items,
ExpandResult::Retry(item) => {
Expand Down
Loading

0 comments on commit 6e534c7

Please sign in to comment.