about summary refs log tree commit diff
path: root/compiler/rustc_parse/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-06-24 06:06:16 +0000
committerbors <bors@rust-lang.org>2024-06-24 06:06:16 +0000
commitb8e1d7ef6fcec31db99ef82d8a913a2a703e8944 (patch)
tree475052c1564920a30d5c4612177eafb17e7b72de /compiler/rustc_parse/src
parentaded2be375993cfb08c8d13be71c046bd048c5d2 (diff)
parentc660016cc1879d9714d134604856b5914f5d0aa0 (diff)
downloadrust-b8e1d7ef6fcec31db99ef82d8a913a2a703e8944.tar.gz
rust-b8e1d7ef6fcec31db99ef82d8a913a2a703e8944.zip
Auto merge of #3706 - rust-lang:rustup-2024-06-24, r=oli-obk
Automatic Rustup
Diffstat (limited to 'compiler/rustc_parse/src')
-rw-r--r--compiler/rustc_parse/src/errors.rs31
-rw-r--r--compiler/rustc_parse/src/parser/nonterminal.rs28
-rw-r--r--compiler/rustc_parse/src/validate_attr.rs64
3 files changed, 101 insertions, 22 deletions
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 46e15734853..8d49887f164 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -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,
+}
diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs
index 59f6eff07b3..4a78b427832 100644
--- a/compiler/rustc_parse/src/parser/nonterminal.rs
+++ b/compiler/rustc_parse/src/parser/nonterminal.rs
@@ -1,5 +1,7 @@
 use rustc_ast::ptr::P;
-use rustc_ast::token::{self, Delimiter, Nonterminal::*, NonterminalKind, Token};
+use rustc_ast::token::{
+    self, Delimiter, Nonterminal::*, NonterminalKind, NtExprKind::*, NtPatKind::*, Token,
+};
 use rustc_ast::HasTokens;
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::sync::Lrc;
@@ -36,14 +38,14 @@ impl<'a> Parser<'a> {
         }
 
         match kind {
-            NonterminalKind::Expr2021 { inferred: _ } => {
+            NonterminalKind::Expr(Expr2021 { .. }) => {
                 token.can_begin_expr()
                 // This exception is here for backwards compatibility.
                 && !token.is_keyword(kw::Let)
                 // This exception is here for backwards compatibility.
                 && !token.is_keyword(kw::Const)
             }
-            NonterminalKind::Expr => {
+            NonterminalKind::Expr(Expr) => {
                 token.can_begin_expr()
                 // This exception is here for backwards compatibility.
                 && !token.is_keyword(kw::Let)
@@ -74,7 +76,7 @@ impl<'a> Parser<'a> {
                 token::Interpolated(nt) => may_be_ident(nt),
                 _ => false,
             },
-            NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr => match &token.kind {
+            NonterminalKind::Pat(pat_kind) => match &token.kind {
                 // box, ref, mut, and other identifiers (can stricten)
                 token::Ident(..) | token::NtIdent(..) |
                 token::OpenDelim(Delimiter::Parenthesis) |  // tuple pattern
@@ -89,7 +91,7 @@ impl<'a> Parser<'a> {
                 token::Lt |                                 // path (UFCS constant)
                 token::BinOp(token::Shl) => true,           // path (double UFCS)
                 // leading vert `|` or-pattern
-                token::BinOp(token::Or) => matches!(kind, NonterminalKind::PatWithOr),
+                token::BinOp(token::Or) => matches!(pat_kind, PatWithOr),
                 token::Interpolated(nt) => may_be_ident(nt),
                 _ => false,
             },
@@ -135,31 +137,25 @@ impl<'a> Parser<'a> {
                         .create_err(UnexpectedNonterminal::Statement(self.token.span)));
                 }
             },
-            NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr => {
-                NtPat(self.collect_tokens_no_attrs(|this| match kind {
-                    NonterminalKind::PatParam { .. } => this.parse_pat_no_top_alt(None, None),
-                    NonterminalKind::PatWithOr => this.parse_pat_allow_top_alt(
+            NonterminalKind::Pat(pat_kind) => {
+                NtPat(self.collect_tokens_no_attrs(|this| match pat_kind {
+                    PatParam { .. } => this.parse_pat_no_top_alt(None, None),
+                    PatWithOr => this.parse_pat_allow_top_alt(
                         None,
                         RecoverComma::No,
                         RecoverColon::No,
                         CommaRecoveryMode::EitherTupleOrPipe,
                     ),
-                    _ => unreachable!(),
                 })?)
             }
-
-            NonterminalKind::Expr | NonterminalKind::Expr2021 { inferred: _ } => {
-                NtExpr(self.parse_expr_force_collect()?)
-            }
+            NonterminalKind::Expr(_) => NtExpr(self.parse_expr_force_collect()?),
             NonterminalKind::Literal => {
                 // The `:literal` matcher does not support attributes
                 NtLiteral(self.collect_tokens_no_attrs(|this| this.parse_literal_maybe_minus())?)
             }
-
             NonterminalKind::Ty => {
                 NtTy(self.collect_tokens_no_attrs(|this| this.parse_ty_no_question_mark_recover())?)
             }
-
             // this could be handled like a token, since it is one
             NonterminalKind::Ident => {
                 return if let Some((ident, is_raw)) = get_macro_ident(&self.token) {
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index 4ca52146039..bcb1131cc19 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -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(_) => {}