Add hard error and migration lint for unsafe attrs
This commit is contained in:
parent
33422e72c8
commit
a23917cfd0
@ -899,7 +899,7 @@ fn validate_generic_param_order(dcx: DiagCtxtHandle<'_>, generics: &[GenericPara
|
|||||||
|
|
||||||
impl<'a> Visitor<'a> for AstValidator<'a> {
|
impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
fn visit_attribute(&mut self, attr: &Attribute) {
|
fn visit_attribute(&mut self, attr: &Attribute) {
|
||||||
validate_attr::check_attr(&self.session.psess, attr);
|
validate_attr::check_attr(&self.features, &self.session.psess, attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_ty(&mut self, ty: &'a Ty) {
|
fn visit_ty(&mut self, ty: &'a Ty) {
|
||||||
|
@ -1882,7 +1882,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
|||||||
let mut span: Option<Span> = None;
|
let mut span: Option<Span> = None;
|
||||||
while let Some(attr) = attrs.next() {
|
while let Some(attr) = attrs.next() {
|
||||||
rustc_ast_passes::feature_gate::check_attribute(attr, self.cx.sess, features);
|
rustc_ast_passes::feature_gate::check_attribute(attr, self.cx.sess, features);
|
||||||
validate_attr::check_attr(&self.cx.sess.psess, attr);
|
validate_attr::check_attr(features, &self.cx.sess.psess, attr);
|
||||||
|
|
||||||
let current_span = if let Some(sp) = span { sp.to(attr.span) } else { attr.span };
|
let current_span = if let Some(sp) = span { sp.to(attr.span) } else { attr.span };
|
||||||
span = Some(current_span);
|
span = Some(current_span);
|
||||||
|
@ -1145,10 +1145,6 @@ pub fn is_valid_for_get_attr(name: Symbol) -> bool {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_unsafe_attr(name: Symbol) -> bool {
|
|
||||||
BUILTIN_ATTRIBUTE_MAP.get(&name).is_some_and(|attr| attr.safety == AttributeSafety::Unsafe)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub static BUILTIN_ATTRIBUTE_MAP: LazyLock<FxHashMap<Symbol, &BuiltinAttribute>> =
|
pub static BUILTIN_ATTRIBUTE_MAP: LazyLock<FxHashMap<Symbol, &BuiltinAttribute>> =
|
||||||
LazyLock::new(|| {
|
LazyLock::new(|| {
|
||||||
let mut map = FxHashMap::default();
|
let mut map = FxHashMap::default();
|
||||||
|
@ -125,7 +125,7 @@ pub use accepted::ACCEPTED_FEATURES;
|
|||||||
pub use builtin_attrs::AttributeDuplicates;
|
pub use builtin_attrs::AttributeDuplicates;
|
||||||
pub use builtin_attrs::{
|
pub use builtin_attrs::{
|
||||||
deprecated_attributes, encode_cross_crate, find_gated_cfg, is_builtin_attr_name,
|
deprecated_attributes, encode_cross_crate, find_gated_cfg, is_builtin_attr_name,
|
||||||
is_unsafe_attr, is_valid_for_get_attr, AttributeGate, AttributeTemplate, AttributeType,
|
is_valid_for_get_attr, AttributeGate, AttributeSafety, AttributeTemplate, AttributeType,
|
||||||
BuiltinAttribute, GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP,
|
BuiltinAttribute, GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP,
|
||||||
};
|
};
|
||||||
pub use removed::REMOVED_FEATURES;
|
pub use removed::REMOVED_FEATURES;
|
||||||
|
@ -825,6 +825,10 @@ lint_unnameable_test_items = cannot test inner items
|
|||||||
lint_unnecessary_qualification = unnecessary qualification
|
lint_unnecessary_qualification = unnecessary qualification
|
||||||
.suggestion = remove the unnecessary path segments
|
.suggestion = remove the unnecessary path segments
|
||||||
|
|
||||||
|
lint_unsafe_attr_outside_unsafe = unsafe attribute used without unsafe
|
||||||
|
.label = usage of unsafe attribute
|
||||||
|
lint_unsafe_attr_outside_unsafe_suggestion = wrap the attribute in `unsafe(...)`
|
||||||
|
|
||||||
lint_unsupported_group = `{$lint_group}` lint group is not supported with ´--force-warn´
|
lint_unsupported_group = `{$lint_group}` lint group is not supported with ´--force-warn´
|
||||||
|
|
||||||
lint_untranslatable_diag = diagnostics should be created using translatable messages
|
lint_untranslatable_diag = diagnostics should be created using translatable messages
|
||||||
|
@ -319,6 +319,16 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: &
|
|||||||
BuiltinLintDiag::UnusedQualifications { removal_span } => {
|
BuiltinLintDiag::UnusedQualifications { removal_span } => {
|
||||||
lints::UnusedQualifications { removal_span }.decorate_lint(diag);
|
lints::UnusedQualifications { removal_span }.decorate_lint(diag);
|
||||||
}
|
}
|
||||||
|
BuiltinLintDiag::UnsafeAttrOutsideUnsafe {
|
||||||
|
attribute_name_span,
|
||||||
|
sugg_spans: (left, right),
|
||||||
|
} => {
|
||||||
|
lints::UnsafeAttrOutsideUnsafe {
|
||||||
|
span: attribute_name_span,
|
||||||
|
suggestion: lints::UnsafeAttrOutsideUnsafeSuggestion { left, right },
|
||||||
|
}
|
||||||
|
.decorate_lint(diag);
|
||||||
|
}
|
||||||
BuiltinLintDiag::AssociatedConstElidedLifetime {
|
BuiltinLintDiag::AssociatedConstElidedLifetime {
|
||||||
elided,
|
elided,
|
||||||
span: lt_span,
|
span: lt_span,
|
||||||
|
@ -2890,3 +2890,24 @@ pub struct RedundantImportVisibility {
|
|||||||
pub import_vis: String,
|
pub import_vis: String,
|
||||||
pub max_vis: String,
|
pub max_vis: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(LintDiagnostic)]
|
||||||
|
#[diag(lint_unsafe_attr_outside_unsafe)]
|
||||||
|
pub struct UnsafeAttrOutsideUnsafe {
|
||||||
|
#[label]
|
||||||
|
pub span: Span,
|
||||||
|
#[subdiagnostic]
|
||||||
|
pub suggestion: UnsafeAttrOutsideUnsafeSuggestion,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
#[multipart_suggestion(
|
||||||
|
lint_unsafe_attr_outside_unsafe_suggestion,
|
||||||
|
applicability = "machine-applicable"
|
||||||
|
)]
|
||||||
|
pub struct UnsafeAttrOutsideUnsafeSuggestion {
|
||||||
|
#[suggestion_part(code = "unsafe(")]
|
||||||
|
pub left: Span,
|
||||||
|
#[suggestion_part(code = ")")]
|
||||||
|
pub right: Span,
|
||||||
|
}
|
||||||
|
@ -115,6 +115,7 @@ declare_lint_pass! {
|
|||||||
UNNAMEABLE_TYPES,
|
UNNAMEABLE_TYPES,
|
||||||
UNREACHABLE_CODE,
|
UNREACHABLE_CODE,
|
||||||
UNREACHABLE_PATTERNS,
|
UNREACHABLE_PATTERNS,
|
||||||
|
UNSAFE_ATTR_OUTSIDE_UNSAFE,
|
||||||
UNSAFE_OP_IN_UNSAFE_FN,
|
UNSAFE_OP_IN_UNSAFE_FN,
|
||||||
UNSTABLE_NAME_COLLISIONS,
|
UNSTABLE_NAME_COLLISIONS,
|
||||||
UNSTABLE_SYNTAX_PRE_EXPANSION,
|
UNSTABLE_SYNTAX_PRE_EXPANSION,
|
||||||
@ -4902,3 +4903,45 @@ declare_lint! {
|
|||||||
reference: "issue #123743 <https://github.com/rust-lang/rust/issues/123743>",
|
reference: "issue #123743 <https://github.com/rust-lang/rust/issues/123743>",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare_lint! {
|
||||||
|
/// The `unsafe_attr_outside_unsafe` lint detects a missing unsafe keyword
|
||||||
|
/// on attributes considered unsafe.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// #![feature(unsafe_attributes)]
|
||||||
|
/// #![warn(unsafe_attr_outside_unsafe)]
|
||||||
|
///
|
||||||
|
/// #[no_mangle]
|
||||||
|
/// extern "C" fn foo() {}
|
||||||
|
///
|
||||||
|
/// fn main() {}
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// {{produces}}
|
||||||
|
///
|
||||||
|
/// ### Explanation
|
||||||
|
///
|
||||||
|
/// Some attributes (e.g. `no_mangle`, `export_name`, `link_section` -- see
|
||||||
|
/// [issue #82499] for a more complete list) are considered "unsafe" attributes.
|
||||||
|
/// An unsafe attribute must only be used inside unsafe(...).
|
||||||
|
///
|
||||||
|
/// This lint can automatically wrap the attributes in `unsafe(...)` , but this
|
||||||
|
/// obviously cannot verify that the preconditions of the `unsafe`
|
||||||
|
/// attributes are fulfilled, so that is still up to the user.
|
||||||
|
///
|
||||||
|
/// The lint is currently "allow" by default, but that might change in the
|
||||||
|
/// future.
|
||||||
|
///
|
||||||
|
/// [editions]: https://doc.rust-lang.org/edition-guide/
|
||||||
|
/// [issue #82499]: https://github.com/rust-lang/rust/issues/82499
|
||||||
|
pub UNSAFE_ATTR_OUTSIDE_UNSAFE,
|
||||||
|
Allow,
|
||||||
|
"detects unsafe attributes outside of unsafe",
|
||||||
|
@future_incompatible = FutureIncompatibleInfo {
|
||||||
|
reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024),
|
||||||
|
reference: "issue #123757 <https://github.com/rust-lang/rust/issues/123757>",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@ -691,6 +691,10 @@ pub enum BuiltinLintDiag {
|
|||||||
/// The span of the unnecessarily-qualified path to remove.
|
/// The span of the unnecessarily-qualified path to remove.
|
||||||
removal_span: Span,
|
removal_span: Span,
|
||||||
},
|
},
|
||||||
|
UnsafeAttrOutsideUnsafe {
|
||||||
|
attribute_name_span: Span,
|
||||||
|
sugg_spans: (Span, Span),
|
||||||
|
},
|
||||||
AssociatedConstElidedLifetime {
|
AssociatedConstElidedLifetime {
|
||||||
elided: bool,
|
elided: bool,
|
||||||
span: Span,
|
span: Span,
|
||||||
|
@ -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}
|
.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
|
.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
|
parse_invalid_block_macro_segment = cannot use a `block` macro fragment here
|
||||||
.label = the `block` fragment is within this context
|
.label = the `block` fragment is within this context
|
||||||
.suggestion = wrap this in another block
|
.suggestion = wrap this in another block
|
||||||
@ -866,6 +870,11 @@ parse_unmatched_angle_brackets = {$num_extra_brackets ->
|
|||||||
*[other] remove extra angle 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
|
parse_unskipped_whitespace = whitespace symbol '{$ch}' is not skipped
|
||||||
.label = {parse_unskipped_whitespace}
|
.label = {parse_unskipped_whitespace}
|
||||||
|
|
||||||
|
@ -2997,3 +2997,34 @@ pub(crate) struct DotDotRangeAttribute {
|
|||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: 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::token::Delimiter;
|
||||||
use rustc_ast::tokenstream::DelimSpan;
|
use rustc_ast::tokenstream::DelimSpan;
|
||||||
use rustc_ast::MetaItemKind;
|
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_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::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::lint::BuiltinLintDiag;
|
||||||
use rustc_session::parse::ParseSess;
|
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() {
|
if attr.is_doc_comment() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
|
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.
|
// Check input tokens for built-in and key-value attributes.
|
||||||
match attr_info {
|
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.
|
// All key-value attributes are restricted to meta-item syntax.
|
||||||
match parse_meta(psess, attr) {
|
match parse_meta(psess, attr) {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
|
@ -384,10 +384,6 @@ passes_invalid_attr_at_crate_level =
|
|||||||
passes_invalid_attr_at_crate_level_item =
|
passes_invalid_attr_at_crate_level_item =
|
||||||
the inner attribute doesn't annotate this {$kind}
|
the inner attribute doesn't annotate this {$kind}
|
||||||
|
|
||||||
passes_invalid_attr_unsafe = `{$name}` is not an unsafe attribute
|
|
||||||
.suggestion = remove the `unsafe(...)`
|
|
||||||
.note = extraneous unsafe is not allowed in attributes
|
|
||||||
|
|
||||||
passes_invalid_macro_export_arguments = `{$name}` isn't a valid `#[macro_export]` argument
|
passes_invalid_macro_export_arguments = `{$name}` isn't a valid `#[macro_export]` argument
|
||||||
|
|
||||||
passes_invalid_macro_export_arguments_too_many_items = `#[macro_export]` can only take 1 or 0 arguments
|
passes_invalid_macro_export_arguments_too_many_items = `#[macro_export]` can only take 1 or 0 arguments
|
||||||
|
@ -10,9 +10,7 @@ use rustc_ast::{MetaItemKind, MetaItemLit, NestedMetaItem};
|
|||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_errors::{Applicability, IntoDiagArg, MultiSpan};
|
use rustc_errors::{Applicability, IntoDiagArg, MultiSpan};
|
||||||
use rustc_errors::{DiagCtxtHandle, StashKey};
|
use rustc_errors::{DiagCtxtHandle, StashKey};
|
||||||
use rustc_feature::{
|
use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
|
||||||
is_unsafe_attr, AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP,
|
|
||||||
};
|
|
||||||
use rustc_hir::def_id::LocalModDefId;
|
use rustc_hir::def_id::LocalModDefId;
|
||||||
use rustc_hir::intravisit::{self, Visitor};
|
use rustc_hir::intravisit::{self, Visitor};
|
||||||
use rustc_hir::{self as hir};
|
use rustc_hir::{self as hir};
|
||||||
@ -116,8 +114,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||||||
let mut seen = FxHashMap::default();
|
let mut seen = FxHashMap::default();
|
||||||
let attrs = self.tcx.hir().attrs(hir_id);
|
let attrs = self.tcx.hir().attrs(hir_id);
|
||||||
for attr in attrs {
|
for attr in attrs {
|
||||||
self.check_unsafe_attr(attr);
|
|
||||||
|
|
||||||
match attr.path().as_slice() {
|
match attr.path().as_slice() {
|
||||||
[sym::diagnostic, sym::do_not_recommend] => {
|
[sym::diagnostic, sym::do_not_recommend] => {
|
||||||
self.check_do_not_recommend(attr.span, hir_id, target)
|
self.check_do_not_recommend(attr.span, hir_id, target)
|
||||||
@ -312,21 +308,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if `unsafe()` is applied to an invalid attribute.
|
|
||||||
fn check_unsafe_attr(&self, attr: &Attribute) {
|
|
||||||
if !attr.is_doc_comment() {
|
|
||||||
let attr_item = attr.get_normal_item();
|
|
||||||
if let ast::Safety::Unsafe(unsafe_span) = attr_item.unsafety {
|
|
||||||
if !is_unsafe_attr(attr.name_or_empty()) {
|
|
||||||
self.dcx().emit_err(errors::InvalidAttrUnsafe {
|
|
||||||
span: unsafe_span,
|
|
||||||
name: attr_item.path.clone(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks if `#[diagnostic::on_unimplemented]` is applied to a trait definition
|
/// Checks if `#[diagnostic::on_unimplemented]` is applied to a trait definition
|
||||||
fn check_diagnostic_on_unimplemented(
|
fn check_diagnostic_on_unimplemented(
|
||||||
&self,
|
&self,
|
||||||
|
@ -4,7 +4,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::fluent_generated as fluent;
|
use crate::fluent_generated as fluent;
|
||||||
use rustc_ast::{ast, Label};
|
use rustc_ast::Label;
|
||||||
use rustc_errors::{
|
use rustc_errors::{
|
||||||
codes::*, Applicability, Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee,
|
codes::*, Applicability, Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee,
|
||||||
Level, MultiSpan, SubdiagMessageOp, Subdiagnostic,
|
Level, MultiSpan, SubdiagMessageOp, Subdiagnostic,
|
||||||
@ -863,15 +863,6 @@ pub struct InvalidAttrAtCrateLevel {
|
|||||||
pub item: Option<ItemFollowingInnerAttr>,
|
pub item: Option<ItemFollowingInnerAttr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
|
||||||
#[diag(passes_invalid_attr_unsafe)]
|
|
||||||
#[note]
|
|
||||||
pub struct InvalidAttrUnsafe {
|
|
||||||
#[primary_span]
|
|
||||||
pub span: Span,
|
|
||||||
pub name: ast::Path,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct ItemFollowingInnerAttr {
|
pub struct ItemFollowingInnerAttr {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
@ -9,12 +9,6 @@ help: escape `unsafe` to use it as an identifier
|
|||||||
LL | #[unsafe(r#unsafe(no_mangle))]
|
LL | #[unsafe(r#unsafe(no_mangle))]
|
||||||
| ++
|
| ++
|
||||||
|
|
||||||
error: cannot find attribute `r#unsafe` in this scope
|
|
||||||
--> $DIR/double-unsafe-attributes.rs:3:10
|
|
||||||
|
|
|
||||||
LL | #[unsafe(unsafe(no_mangle))]
|
|
||||||
| ^^^^^^
|
|
||||||
|
|
||||||
error: `r#unsafe` is not an unsafe attribute
|
error: `r#unsafe` is not an unsafe attribute
|
||||||
--> $DIR/double-unsafe-attributes.rs:3:3
|
--> $DIR/double-unsafe-attributes.rs:3:3
|
||||||
|
|
|
|
||||||
@ -23,5 +17,11 @@ LL | #[unsafe(unsafe(no_mangle))]
|
|||||||
|
|
|
|
||||||
= note: extraneous unsafe is not allowed in attributes
|
= note: extraneous unsafe is not allowed in attributes
|
||||||
|
|
||||||
|
error: cannot find attribute `r#unsafe` in this scope
|
||||||
|
--> $DIR/double-unsafe-attributes.rs:3:10
|
||||||
|
|
|
||||||
|
LL | #[unsafe(unsafe(no_mangle))]
|
||||||
|
| ^^^^^^
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
#![deny(rust_2024_compatibility)]
|
||||||
|
#![feature(unsafe_attributes)]
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
//~^ ERROR: unsafe attribute used without unsafe
|
||||||
|
//~| WARN this is accepted in the current edition
|
||||||
|
extern "C" fn foo() {}
|
||||||
|
|
||||||
|
fn main() {}
|
@ -0,0 +1,21 @@
|
|||||||
|
error: unsafe attribute used without unsafe
|
||||||
|
--> $DIR/in_2024_compatibility.rs:4:3
|
||||||
|
|
|
||||||
|
LL | #[no_mangle]
|
||||||
|
| ^^^^^^^^^ usage of unsafe attribute
|
||||||
|
|
|
||||||
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
|
||||||
|
= note: for more information, see issue #123757 <https://github.com/rust-lang/rust/issues/123757>
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/in_2024_compatibility.rs:1:9
|
||||||
|
|
|
||||||
|
LL | #![deny(rust_2024_compatibility)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
= note: `#[deny(unsafe_attr_outside_unsafe)]` implied by `#[deny(rust_2024_compatibility)]`
|
||||||
|
help: wrap the attribute in `unsafe(...)`
|
||||||
|
|
|
||||||
|
LL | #[unsafe(no_mangle)]
|
||||||
|
| +++++++ +
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
@ -0,0 +1,12 @@
|
|||||||
|
//@ revisions: edition2021 edition2024
|
||||||
|
//@[edition2021] edition:2021
|
||||||
|
//@[edition2024] edition:2024
|
||||||
|
//@[edition2024] compile-flags: -Zunstable-options
|
||||||
|
//@ check-pass
|
||||||
|
|
||||||
|
#![feature(unsafe_attributes)]
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
extern "C" fn foo() {}
|
||||||
|
|
||||||
|
fn main() {}
|
@ -0,0 +1,61 @@
|
|||||||
|
//@ run-rustfix
|
||||||
|
#![feature(unsafe_attributes)]
|
||||||
|
#![deny(unsafe_attr_outside_unsafe)]
|
||||||
|
|
||||||
|
macro_rules! tt {
|
||||||
|
($e:tt) => {
|
||||||
|
#$e
|
||||||
|
extern fn foo() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! ident {
|
||||||
|
($e:ident) => {
|
||||||
|
#[unsafe($e)]
|
||||||
|
//~^ ERROR: unsafe attribute used without unsafe
|
||||||
|
//~| WARN this is accepted in the current edition
|
||||||
|
extern fn bar() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! ident2 {
|
||||||
|
($e:ident, $l:literal) => {
|
||||||
|
#[unsafe($e = $l)]
|
||||||
|
//~^ ERROR: unsafe attribute used without unsafe
|
||||||
|
//~| WARN this is accepted in the current edition
|
||||||
|
extern fn bars() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! meta {
|
||||||
|
($m:meta) => {
|
||||||
|
#[$m]
|
||||||
|
extern fn baz() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! meta2 {
|
||||||
|
($m:meta) => {
|
||||||
|
#[$m]
|
||||||
|
extern fn baw() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tt!([unsafe(no_mangle)]);
|
||||||
|
//~^ ERROR: unsafe attribute used without unsafe
|
||||||
|
//~| WARN this is accepted in the current edition
|
||||||
|
ident!(no_mangle);
|
||||||
|
meta!(unsafe(no_mangle));
|
||||||
|
//~^ ERROR: unsafe attribute used without unsafe
|
||||||
|
//~| WARN this is accepted in the current edition
|
||||||
|
meta2!(unsafe(export_name = "baw"));
|
||||||
|
//~^ ERROR: unsafe attribute used without unsafe
|
||||||
|
//~| WARN this is accepted in the current edition
|
||||||
|
ident2!(export_name, "bars");
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
//~^ ERROR: unsafe attribute used without unsafe
|
||||||
|
//~| WARN this is accepted in the current edition
|
||||||
|
extern "C" fn one() {}
|
||||||
|
|
||||||
|
fn main() {}
|
@ -0,0 +1,61 @@
|
|||||||
|
//@ run-rustfix
|
||||||
|
#![feature(unsafe_attributes)]
|
||||||
|
#![deny(unsafe_attr_outside_unsafe)]
|
||||||
|
|
||||||
|
macro_rules! tt {
|
||||||
|
($e:tt) => {
|
||||||
|
#$e
|
||||||
|
extern fn foo() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! ident {
|
||||||
|
($e:ident) => {
|
||||||
|
#[$e]
|
||||||
|
//~^ ERROR: unsafe attribute used without unsafe
|
||||||
|
//~| WARN this is accepted in the current edition
|
||||||
|
extern fn bar() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! ident2 {
|
||||||
|
($e:ident, $l:literal) => {
|
||||||
|
#[$e = $l]
|
||||||
|
//~^ ERROR: unsafe attribute used without unsafe
|
||||||
|
//~| WARN this is accepted in the current edition
|
||||||
|
extern fn bars() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! meta {
|
||||||
|
($m:meta) => {
|
||||||
|
#[$m]
|
||||||
|
extern fn baz() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! meta2 {
|
||||||
|
($m:meta) => {
|
||||||
|
#[$m]
|
||||||
|
extern fn baw() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tt!([no_mangle]);
|
||||||
|
//~^ ERROR: unsafe attribute used without unsafe
|
||||||
|
//~| WARN this is accepted in the current edition
|
||||||
|
ident!(no_mangle);
|
||||||
|
meta!(no_mangle);
|
||||||
|
//~^ ERROR: unsafe attribute used without unsafe
|
||||||
|
//~| WARN this is accepted in the current edition
|
||||||
|
meta2!(export_name = "baw");
|
||||||
|
//~^ ERROR: unsafe attribute used without unsafe
|
||||||
|
//~| WARN this is accepted in the current edition
|
||||||
|
ident2!(export_name, "bars");
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
//~^ ERROR: unsafe attribute used without unsafe
|
||||||
|
//~| WARN this is accepted in the current edition
|
||||||
|
extern "C" fn one() {}
|
||||||
|
|
||||||
|
fn main() {}
|
@ -0,0 +1,93 @@
|
|||||||
|
error: unsafe attribute used without unsafe
|
||||||
|
--> $DIR/unsafe-attributes-fix.rs:44:6
|
||||||
|
|
|
||||||
|
LL | tt!([no_mangle]);
|
||||||
|
| ^^^^^^^^^ usage of unsafe attribute
|
||||||
|
|
|
||||||
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
|
||||||
|
= note: for more information, see issue #123757 <https://github.com/rust-lang/rust/issues/123757>
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/unsafe-attributes-fix.rs:3:9
|
||||||
|
|
|
||||||
|
LL | #![deny(unsafe_attr_outside_unsafe)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
help: wrap the attribute in `unsafe(...)`
|
||||||
|
|
|
||||||
|
LL | tt!([unsafe(no_mangle)]);
|
||||||
|
| +++++++ +
|
||||||
|
|
||||||
|
error: unsafe attribute used without unsafe
|
||||||
|
--> $DIR/unsafe-attributes-fix.rs:14:11
|
||||||
|
|
|
||||||
|
LL | #[$e]
|
||||||
|
| ^^ usage of unsafe attribute
|
||||||
|
...
|
||||||
|
LL | ident!(no_mangle);
|
||||||
|
| ----------------- in this macro invocation
|
||||||
|
|
|
||||||
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
|
||||||
|
= note: for more information, see issue #123757 <https://github.com/rust-lang/rust/issues/123757>
|
||||||
|
= note: this error originates in the macro `ident` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
help: wrap the attribute in `unsafe(...)`
|
||||||
|
|
|
||||||
|
LL | #[unsafe($e)]
|
||||||
|
| +++++++ +
|
||||||
|
|
||||||
|
error: unsafe attribute used without unsafe
|
||||||
|
--> $DIR/unsafe-attributes-fix.rs:48:7
|
||||||
|
|
|
||||||
|
LL | meta!(no_mangle);
|
||||||
|
| ^^^^^^^^^ usage of unsafe attribute
|
||||||
|
|
|
||||||
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
|
||||||
|
= note: for more information, see issue #123757 <https://github.com/rust-lang/rust/issues/123757>
|
||||||
|
help: wrap the attribute in `unsafe(...)`
|
||||||
|
|
|
||||||
|
LL | meta!(unsafe(no_mangle));
|
||||||
|
| +++++++ +
|
||||||
|
|
||||||
|
error: unsafe attribute used without unsafe
|
||||||
|
--> $DIR/unsafe-attributes-fix.rs:51:8
|
||||||
|
|
|
||||||
|
LL | meta2!(export_name = "baw");
|
||||||
|
| ^^^^^^^^^^^ usage of unsafe attribute
|
||||||
|
|
|
||||||
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
|
||||||
|
= note: for more information, see issue #123757 <https://github.com/rust-lang/rust/issues/123757>
|
||||||
|
help: wrap the attribute in `unsafe(...)`
|
||||||
|
|
|
||||||
|
LL | meta2!(unsafe(export_name = "baw"));
|
||||||
|
| +++++++ +
|
||||||
|
|
||||||
|
error: unsafe attribute used without unsafe
|
||||||
|
--> $DIR/unsafe-attributes-fix.rs:23:11
|
||||||
|
|
|
||||||
|
LL | #[$e = $l]
|
||||||
|
| ^^ usage of unsafe attribute
|
||||||
|
...
|
||||||
|
LL | ident2!(export_name, "bars");
|
||||||
|
| ---------------------------- in this macro invocation
|
||||||
|
|
|
||||||
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
|
||||||
|
= note: for more information, see issue #123757 <https://github.com/rust-lang/rust/issues/123757>
|
||||||
|
= note: this error originates in the macro `ident2` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
help: wrap the attribute in `unsafe(...)`
|
||||||
|
|
|
||||||
|
LL | #[unsafe($e = $l)]
|
||||||
|
| +++++++ +
|
||||||
|
|
||||||
|
error: unsafe attribute used without unsafe
|
||||||
|
--> $DIR/unsafe-attributes-fix.rs:56:3
|
||||||
|
|
|
||||||
|
LL | #[no_mangle]
|
||||||
|
| ^^^^^^^^^ usage of unsafe attribute
|
||||||
|
|
|
||||||
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
|
||||||
|
= note: for more information, see issue #123757 <https://github.com/rust-lang/rust/issues/123757>
|
||||||
|
help: wrap the attribute in `unsafe(...)`
|
||||||
|
|
|
||||||
|
LL | #[unsafe(no_mangle)]
|
||||||
|
| +++++++ +
|
||||||
|
|
||||||
|
error: aborting due to 6 previous errors
|
||||||
|
|
@ -0,0 +1,13 @@
|
|||||||
|
error: unsafe attribute used without unsafe
|
||||||
|
--> $DIR/unsafe-attributes.rs:9:3
|
||||||
|
|
|
||||||
|
LL | #[no_mangle]
|
||||||
|
| ^^^^^^^^^ usage of unsafe attribute
|
||||||
|
|
|
||||||
|
help: wrap the attribute in `unsafe(...)`
|
||||||
|
|
|
||||||
|
LL | #[unsafe(no_mangle)]
|
||||||
|
| +++++++ +
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
12
tests/ui/rust-2024/unsafe-attributes/unsafe-attributes.rs
Normal file
12
tests/ui/rust-2024/unsafe-attributes/unsafe-attributes.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
//@ revisions: edition2021 edition2024
|
||||||
|
//@[edition2021] edition:2021
|
||||||
|
//@[edition2021] check-pass
|
||||||
|
//@[edition2024] edition:2024
|
||||||
|
//@[edition2024] compile-flags: -Zunstable-options
|
||||||
|
|
||||||
|
#![feature(unsafe_attributes)]
|
||||||
|
|
||||||
|
#[no_mangle] //[edition2024]~ ERROR: unsafe attribute used without unsafe
|
||||||
|
extern "C" fn foo() {}
|
||||||
|
|
||||||
|
fn main() {}
|
Loading…
x
Reference in New Issue
Block a user