diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 9a8689e27c068..8291d315f61a7 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -264,6 +264,9 @@ ast_passes_unsafe_negative_impl = negative impls cannot be unsafe .negative = negative because of this .unsafe = unsafe because of this +ast_passes_unsafe_static = + static items cannot be declared with `unsafe` safety qualifier outside of `extern` block + ast_passes_visibility_not_permitted = visibility qualifiers are not permitted here .enum_variant = enum variants and their fields always share the visibility of the enum they are in diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 0fbb288cc968c..f367df40e82a1 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1161,11 +1161,17 @@ impl<'a> Visitor<'a> for AstValidator<'a> { }); } } - ItemKind::Static(box StaticItem { expr: None, .. }) => { - self.dcx().emit_err(errors::StaticWithoutBody { - span: item.span, - replace_span: self.ending_semi_or_hi(item.span), - }); + ItemKind::Static(box StaticItem { expr, safety, .. }) => { + if matches!(safety, Safety::Unsafe(_)) { + self.dcx().emit_err(errors::UnsafeStatic { span: item.span }); + } + + if expr.is_none() { + self.dcx().emit_err(errors::StaticWithoutBody { + span: item.span, + replace_span: self.ending_semi_or_hi(item.span), + }); + } } ItemKind::TyAlias( ty_alias @ box TyAlias { defaultness, bounds, where_clauses, ty, .. }, diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 260c182bd9e49..a51595a611bb1 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -225,6 +225,13 @@ pub struct InvalidSafetyOnExtern { pub block: Span, } +#[derive(Diagnostic)] +#[diag(ast_passes_unsafe_static)] +pub struct UnsafeStatic { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(ast_passes_bound_in_context)] pub struct BoundInContext<'a> { diff --git a/tests/ui/rust-2024/safe-outside-extern.gated.stderr b/tests/ui/rust-2024/safe-outside-extern.gated.stderr new file mode 100644 index 0000000000000..a81f8382859d0 --- /dev/null +++ b/tests/ui/rust-2024/safe-outside-extern.gated.stderr @@ -0,0 +1,8 @@ +error: static items cannot be declared with `unsafe` safety qualifier outside of `extern` block + --> $DIR/safe-outside-extern.rs:6:1 + | +LL | unsafe static LOL: u8 = 0; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/rust-2024/safe-outside-extern.rs b/tests/ui/rust-2024/safe-outside-extern.rs new file mode 100644 index 0000000000000..137331e9d3853 --- /dev/null +++ b/tests/ui/rust-2024/safe-outside-extern.rs @@ -0,0 +1,9 @@ +//@ revisions: gated ungated + +// Very pared down version of the same named test on nightly, since we only want +// to validate that `unsafe static` is not being accidentally accepted by the parser. + +unsafe static LOL: u8 = 0; +//~^ ERROR: static items cannot be declared with `unsafe` safety qualifier outside of `extern` block + +fn main() {} diff --git a/tests/ui/rust-2024/safe-outside-extern.ungated.stderr b/tests/ui/rust-2024/safe-outside-extern.ungated.stderr new file mode 100644 index 0000000000000..a81f8382859d0 --- /dev/null +++ b/tests/ui/rust-2024/safe-outside-extern.ungated.stderr @@ -0,0 +1,8 @@ +error: static items cannot be declared with `unsafe` safety qualifier outside of `extern` block + --> $DIR/safe-outside-extern.rs:6:1 + | +LL | unsafe static LOL: u8 = 0; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error +