diff options
Diffstat (limited to 'compiler/rustc_parse/src')
| -rw-r--r-- | compiler/rustc_parse/src/errors.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/attr.rs | 21 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/validate_attr.rs | 82 |
3 files changed, 59 insertions, 45 deletions
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 10762803708..e5b0dc804a5 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -3188,6 +3188,7 @@ pub(crate) struct DotDotRangeAttribute { #[note] pub struct InvalidAttrUnsafe { #[primary_span] + #[label] pub span: Span, pub name: Path, } diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index 12b9414d1f7..f34ef071e21 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -31,6 +31,12 @@ enum OuterAttributeType { Attribute, } +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum AllowLeadingUnsafe { + Yes, + No, +} + impl<'a> Parser<'a> { /// Parses attributes that appear before an item. pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, AttrWrapper> { @@ -332,7 +338,7 @@ impl<'a> Parser<'a> { /// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited. pub fn parse_cfg_attr(&mut self) -> PResult<'a, (ast::MetaItem, Vec<(ast::AttrItem, Span)>)> { - let cfg_predicate = self.parse_meta_item()?; + let cfg_predicate = self.parse_meta_item(AllowLeadingUnsafe::No)?; self.expect(&token::Comma)?; // Presumably, the majority of the time there will only be one attr. @@ -368,7 +374,10 @@ impl<'a> Parser<'a> { /// MetaItem = SimplePath ( '=' UNSUFFIXED_LIT | '(' MetaSeq? ')' )? ; /// MetaSeq = MetaItemInner (',' MetaItemInner)* ','? ; /// ``` - pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> { + pub fn parse_meta_item( + &mut self, + unsafe_allowed: AllowLeadingUnsafe, + ) -> PResult<'a, ast::MetaItem> { // We can't use `maybe_whole` here because it would bump in the `None` // case, which we don't want. if let token::Interpolated(nt) = &self.token.kind @@ -384,7 +393,11 @@ impl<'a> Parser<'a> { } let lo = self.token.span; - let is_unsafe = self.eat_keyword(kw::Unsafe); + let is_unsafe = if unsafe_allowed == AllowLeadingUnsafe::Yes { + self.eat_keyword(kw::Unsafe) + } else { + false + }; let unsafety = if is_unsafe { let unsafe_span = self.prev_token.span; self.psess.gated_spans.gate(sym::unsafe_attributes, unsafe_span); @@ -427,7 +440,7 @@ impl<'a> Parser<'a> { Err(err) => err.cancel(), // we provide a better error below } - match self.parse_meta_item() { + match self.parse_meta_item(AllowLeadingUnsafe::No) { Ok(mi) => return Ok(ast::NestedMetaItem::MetaItem(mi)), Err(err) => err.cancel(), // we provide a better error below } diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index af2db171840..a64c00f3b6c 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -163,53 +163,53 @@ pub fn check_attribute_safety( safety: AttributeSafety, attr: &Attribute, ) { - if features.unsafe_attributes { - let attr_item = attr.get_normal_item(); + if !features.unsafe_attributes { + return; + } - if safety == AttributeSafety::Unsafe { - if let ast::Safety::Default = attr_item.unsafety { - let path_span = attr_item.path.span; + let attr_item = attr.get_normal_item(); - // 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 safety == AttributeSafety::Unsafe { + if let ast::Safety::Default = attr_item.unsafety { + let path_span = attr_item.path.span; - 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(), + // 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(), + }); + } } } |
