Add hard error and migration lint for unsafe attrs
This commit is contained in:
parent
33422e72c8
commit
a23917cfd0
24 changed files with 473 additions and 53 deletions
|
@ -366,6 +366,10 @@ parse_inner_doc_comment_not_permitted = expected outer doc comment
|
|||
.label_does_not_annotate_this = the inner doc comment doesn't annotate this {$item}
|
||||
.sugg_change_inner_to_outer = to annotate the {$item}, change the doc comment from inner to outer style
|
||||
|
||||
parse_invalid_attr_unsafe = `{$name}` is not an unsafe attribute
|
||||
.suggestion = remove the `unsafe(...)`
|
||||
.note = extraneous unsafe is not allowed in attributes
|
||||
|
||||
parse_invalid_block_macro_segment = cannot use a `block` macro fragment here
|
||||
.label = the `block` fragment is within this context
|
||||
.suggestion = wrap this in another block
|
||||
|
@ -866,6 +870,11 @@ parse_unmatched_angle_brackets = {$num_extra_brackets ->
|
|||
*[other] remove extra angle brackets
|
||||
}
|
||||
|
||||
parse_unsafe_attr_outside_unsafe = unsafe attribute used without unsafe
|
||||
.label = usage of unsafe attribute
|
||||
parse_unsafe_attr_outside_unsafe_suggestion = wrap the attribute in `unsafe(...)`
|
||||
|
||||
|
||||
parse_unskipped_whitespace = whitespace symbol '{$ch}' is not skipped
|
||||
.label = {parse_unskipped_whitespace}
|
||||
|
||||
|
|
|
@ -2997,3 +2997,34 @@ pub(crate) struct DotDotRangeAttribute {
|
|||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_invalid_attr_unsafe)]
|
||||
#[note]
|
||||
pub struct InvalidAttrUnsafe {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub name: Path,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_unsafe_attr_outside_unsafe)]
|
||||
pub struct UnsafeAttrOutsideUnsafe {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub suggestion: UnsafeAttrOutsideUnsafeSuggestion,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(
|
||||
parse_unsafe_attr_outside_unsafe_suggestion,
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
pub struct UnsafeAttrOutsideUnsafeSuggestion {
|
||||
#[suggestion_part(code = "unsafe(")]
|
||||
pub left: Span,
|
||||
#[suggestion_part(code = ")")]
|
||||
pub right: Span,
|
||||
}
|
||||
|
|
|
@ -5,21 +5,73 @@ use crate::{errors, parse_in};
|
|||
use rustc_ast::token::Delimiter;
|
||||
use rustc_ast::tokenstream::DelimSpan;
|
||||
use rustc_ast::MetaItemKind;
|
||||
use rustc_ast::{self as ast, AttrArgs, AttrArgsEq, Attribute, DelimArgs, MetaItem};
|
||||
use rustc_ast::{self as ast, AttrArgs, AttrArgsEq, Attribute, DelimArgs, MetaItem, Safety};
|
||||
use rustc_errors::{Applicability, FatalError, PResult};
|
||||
use rustc_feature::{AttributeTemplate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
|
||||
use rustc_feature::{
|
||||
AttributeSafety, AttributeTemplate, BuiltinAttribute, Features, BUILTIN_ATTRIBUTE_MAP,
|
||||
};
|
||||
use rustc_session::errors::report_lit_error;
|
||||
use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
|
||||
use rustc_session::lint::builtin::{ILL_FORMED_ATTRIBUTE_INPUT, UNSAFE_ATTR_OUTSIDE_UNSAFE};
|
||||
use rustc_session::lint::BuiltinLintDiag;
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::{sym, Span, Symbol};
|
||||
use rustc_span::{sym, BytePos, Span, Symbol};
|
||||
|
||||
pub fn check_attr(psess: &ParseSess, attr: &Attribute) {
|
||||
pub fn check_attr(features: &Features, psess: &ParseSess, attr: &Attribute) {
|
||||
if attr.is_doc_comment() {
|
||||
return;
|
||||
}
|
||||
|
||||
let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
|
||||
let attr_item = attr.get_normal_item();
|
||||
|
||||
let is_unsafe_attr = attr_info.is_some_and(|attr| attr.safety == AttributeSafety::Unsafe);
|
||||
|
||||
if features.unsafe_attributes {
|
||||
if is_unsafe_attr {
|
||||
if let ast::Safety::Default = attr_item.unsafety {
|
||||
let path_span = attr_item.path.span;
|
||||
|
||||
// If the `attr_item`'s span is not from a macro, then just suggest
|
||||
// wrapping it in `unsafe(...)`. Otherwise, we suggest putting the
|
||||
// `unsafe(`, `)` right after and right before the opening and closing
|
||||
// square bracket respectively.
|
||||
let diag_span = if attr_item.span().can_be_used_for_suggestions() {
|
||||
attr_item.span()
|
||||
} else {
|
||||
attr.span
|
||||
.with_lo(attr.span.lo() + BytePos(2))
|
||||
.with_hi(attr.span.hi() - BytePos(1))
|
||||
};
|
||||
|
||||
if attr.span.at_least_rust_2024() {
|
||||
psess.dcx().emit_err(errors::UnsafeAttrOutsideUnsafe {
|
||||
span: path_span,
|
||||
suggestion: errors::UnsafeAttrOutsideUnsafeSuggestion {
|
||||
left: diag_span.shrink_to_lo(),
|
||||
right: diag_span.shrink_to_hi(),
|
||||
},
|
||||
});
|
||||
} else {
|
||||
psess.buffer_lint(
|
||||
UNSAFE_ATTR_OUTSIDE_UNSAFE,
|
||||
path_span,
|
||||
ast::CRATE_NODE_ID,
|
||||
BuiltinLintDiag::UnsafeAttrOutsideUnsafe {
|
||||
attribute_name_span: path_span,
|
||||
sugg_spans: (diag_span.shrink_to_lo(), diag_span.shrink_to_hi()),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if let Safety::Unsafe(unsafe_span) = attr_item.unsafety {
|
||||
psess.dcx().emit_err(errors::InvalidAttrUnsafe {
|
||||
span: unsafe_span,
|
||||
name: attr_item.path.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check input tokens for built-in and key-value attributes.
|
||||
match attr_info {
|
||||
|
@ -32,7 +84,7 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute) {
|
|||
}
|
||||
}
|
||||
}
|
||||
_ if let AttrArgs::Eq(..) = attr.get_normal_item().args => {
|
||||
_ if let AttrArgs::Eq(..) = attr_item.args => {
|
||||
// All key-value attributes are restricted to meta-item syntax.
|
||||
match parse_meta(psess, attr) {
|
||||
Ok(_) => {}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue