diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 8f95a0178090d..b8c92a1a8a572 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -224,6 +224,9 @@ pub enum AttributeKind { /// Represents `#[rustc_macro_transparency]`. MacroTransparency(Transparency), + /// Represents [`#[may_dangle]`](https://std-dev-guide.rust-lang.org/tricky/may-dangle.html). + MayDangle(Span), + /// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations). Repr(ThinVec<(ReprAttr, Span)>), diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index df488c89a34fa..aedfd2f431c7e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -31,6 +31,7 @@ pub(crate) mod confusables; pub(crate) mod deprecation; pub(crate) mod lint_helpers; pub(crate) mod repr; +pub(crate) mod semantics; pub(crate) mod stability; pub(crate) mod transparency; pub(crate) mod util; diff --git a/compiler/rustc_attr_parsing/src/attributes/semantics.rs b/compiler/rustc_attr_parsing/src/attributes/semantics.rs new file mode 100644 index 0000000000000..ba774075db7c7 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/semantics.rs @@ -0,0 +1,20 @@ +use rustc_attr_data_structures::AttributeKind; +use rustc_span::{Symbol, sym}; + +use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; +use crate::context::{AcceptContext, Stage}; +use crate::parser::ArgParser; + +pub(crate) struct MayDangleParser; +impl SingleAttributeParser for MayDangleParser { + const PATH: &[Symbol] = &[sym::may_dangle]; + + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; + + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + + fn convert(cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option { + // FIXME: check that there's no args (this is currently checked elsewhere) + Some(AttributeKind::MayDangle(cx.attr_span)) + } +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 3193d8975e9fe..d39bc4e3965ed 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -20,6 +20,7 @@ use crate::attributes::confusables::ConfusablesParser; use crate::attributes::deprecation::DeprecationParser; use crate::attributes::lint_helpers::AsPtrParser; use crate::attributes::repr::ReprParser; +use crate::attributes::semantics::MayDangleParser; use crate::attributes::stability::{ BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser, }; @@ -106,6 +107,7 @@ attribute_parsers!( Single, Single, Single, + Single, Single, // tidy-alphabetical-end ]; diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 556f50a85af7d..1a526d5bce0bb 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1302,6 +1302,7 @@ impl AttributeExt for Attribute { // FIXME: should not be needed anymore when all attrs are parsed Attribute::Parsed(AttributeKind::Deprecation { span, .. }) => *span, Attribute::Parsed(AttributeKind::DocComment { span, .. }) => *span, + Attribute::Parsed(AttributeKind::MayDangle(span)) => *span, a => panic!("can't get the span of an arbitrary parsed attribute: {a:?}"), } } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index dddbf65db72ea..3b107b247b603 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -150,6 +150,27 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::AsPtr(attr_span)) => { self.check_applied_to_fn_or_method(hir_id, *attr_span, span, target) } + &Attribute::Parsed(AttributeKind::MayDangle(attr_span)) => { + // Check if `#[may_dangle]` is applied to a lifetime or type generic parameter in `Drop` impl. + if let hir::Node::GenericParam(param) = self.tcx.hir_node(hir_id) + && matches!( + param.kind, + hir::GenericParamKind::Lifetime { .. } + | hir::GenericParamKind::Type { .. } + ) + && matches!(param.source, hir::GenericParamSource::Generics) + && let parent_hir_id = self.tcx.parent_hir_id(hir_id) + && let hir::Node::Item(item) = self.tcx.hir_node(parent_hir_id) + && let hir::ItemKind::Impl(impl_) = item.kind + && let Some(trait_) = impl_.of_trait + && let Some(def_id) = trait_.trait_def_id() + && self.tcx.is_lang_item(def_id, hir::LangItem::Drop) + { + // OK + } else { + self.dcx().emit_err(errors::InvalidMayDangle { attr_span }); + } + } Attribute::Unparsed(_) => { match attr.path().as_slice() { [sym::diagnostic, sym::do_not_recommend, ..] => { @@ -225,7 +246,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target), [sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target), [sym::must_use, ..] => self.check_must_use(hir_id, attr, target), - [sym::may_dangle, ..] => self.check_may_dangle(hir_id, attr), [sym::rustc_pass_by_value, ..] => self.check_pass_by_value(attr, span, target), [sym::rustc_allow_incoherent_impl, ..] => { self.check_allow_incoherent_impl(attr, span, target) @@ -1589,27 +1609,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - /// Checks if `#[may_dangle]` is applied to a lifetime or type generic parameter in `Drop` impl. - fn check_may_dangle(&self, hir_id: HirId, attr: &Attribute) { - if let hir::Node::GenericParam(param) = self.tcx.hir_node(hir_id) - && matches!( - param.kind, - hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } - ) - && matches!(param.source, hir::GenericParamSource::Generics) - && let parent_hir_id = self.tcx.parent_hir_id(hir_id) - && let hir::Node::Item(item) = self.tcx.hir_node(parent_hir_id) - && let hir::ItemKind::Impl(impl_) = item.kind - && let Some(trait_) = impl_.of_trait - && let Some(def_id) = trait_.trait_def_id() - && self.tcx.is_lang_item(def_id, hir::LangItem::Drop) - { - return; - } - - self.dcx().emit_err(errors::InvalidMayDangle { attr_span: attr.span() }); - } - /// Checks if `#[cold]` is applied to a non-function. fn check_cold(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) { match target {