Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not allow safe/unsafe on static and fn items #126758

Merged
merged 1 commit into from
Jun 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions compiler/rustc_ast_passes/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ ast_passes_auto_super_lifetime = auto traits cannot have super traits or lifetim

ast_passes_bad_c_variadic = only foreign or `unsafe extern "C"` functions may be C-variadic

ast_passes_bare_fn_invalid_safety = function pointers cannot be declared with `safe` safety qualifier
.suggestion = remove safe from this item

ast_passes_body_in_extern = incorrect `{$kind}` inside `extern` block
.cannot_have = cannot have a body
.invalid = the invalid body
Expand Down Expand Up @@ -167,6 +170,9 @@ ast_passes_invalid_unnamed_field_ty =
unnamed fields can only have struct or union types
.label = not a struct or union

ast_passes_item_invalid_safety = items outside of `unsafe extern {"{ }"}` cannot be declared with `safe` safety qualifier
.suggestion = remove safe from this item

ast_passes_item_underscore = `{$kind}` items in this context need a name
.label = `_` is not a valid name for this `{$kind}` item

Expand Down
54 changes: 38 additions & 16 deletions compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -456,15 +456,29 @@ impl<'a> AstValidator<'a> {
}
}

fn check_foreign_item_safety(&self, item_span: Span, safety: Safety) {
if matches!(safety, Safety::Unsafe(_) | Safety::Safe(_))
&& (self.extern_mod_safety == Some(Safety::Default)
|| !self.features.unsafe_extern_blocks)
{
self.dcx().emit_err(errors::InvalidSafetyOnExtern {
item_span,
block: self.current_extern_span(),
});
fn check_item_safety(&self, span: Span, safety: Safety) {
match self.extern_mod_safety {
Some(extern_safety) => {
if matches!(safety, Safety::Unsafe(_) | Safety::Safe(_))
&& (extern_safety == Safety::Default || !self.features.unsafe_extern_blocks)
{
self.dcx().emit_err(errors::InvalidSafetyOnExtern {
item_span: span,
block: self.current_extern_span(),
});
}
}
None => {
if matches!(safety, Safety::Safe(_)) {
self.dcx().emit_err(errors::InvalidSafetyOnItem { span });
}
}
}
}

fn check_bare_fn_safety(&self, span: Span, safety: Safety) {
if matches!(safety, Safety::Safe(_)) {
self.dcx().emit_err(errors::InvalidSafetyOnBareFn { span });
}
}

Expand Down Expand Up @@ -746,6 +760,7 @@ impl<'a> AstValidator<'a> {
fn visit_ty_common(&mut self, ty: &'a Ty) {
match &ty.kind {
TyKind::BareFn(bfty) => {
self.check_bare_fn_safety(bfty.decl_span, bfty.safety);
self.check_fn_decl(&bfty.decl, SelfSemantic::No);
Self::check_decl_no_pat(&bfty.decl, |span, _, _| {
self.dcx().emit_err(errors::PatternFnPointer { span });
Expand Down Expand Up @@ -1174,11 +1189,15 @@ 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, .. }) => {
self.check_item_safety(item.span, *safety);

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, .. },
Expand Down Expand Up @@ -1212,7 +1231,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
match &fi.kind {
ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => {
self.check_foreign_item_safety(fi.span, sig.header.safety);
self.check_defaultness(fi.span, *defaultness);
self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
self.check_foreign_fn_headerless(sig.header);
Expand All @@ -1233,7 +1251,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
self.check_foreign_item_ascii_only(fi.ident);
}
ForeignItemKind::Static(box StaticItem { expr, safety, .. }) => {
self.check_foreign_item_safety(fi.span, *safety);
self.check_item_safety(fi.span, *safety);
self.check_foreign_kind_bodyless(fi.ident, "static", expr.as_ref().map(|b| b.span));
self.check_foreign_item_ascii_only(fi.ident);
}
Expand Down Expand Up @@ -1453,6 +1471,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
};
self.check_fn_decl(fk.decl(), self_semantic);

if let Some(&FnHeader { safety, .. }) = fk.header() {
self.check_item_safety(span, safety);
}

self.check_c_variadic_type(fk);

// Functions cannot both be `const async` or `const gen`
Expand Down
14 changes: 14 additions & 0 deletions compiler/rustc_ast_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,20 @@ pub struct InvalidSafetyOnExtern {
pub block: Span,
}

#[derive(Diagnostic)]
#[diag(ast_passes_item_invalid_safety)]
pub struct InvalidSafetyOnItem {
#[primary_span]
pub span: Span,
}

#[derive(Diagnostic)]
#[diag(ast_passes_bare_fn_invalid_safety)]
pub struct InvalidSafetyOnBareFn {
#[primary_span]
pub span: Span,
}

#[derive(Diagnostic)]
#[diag(ast_passes_bound_in_context)]
pub struct BoundInContext<'a> {
Expand Down
18 changes: 9 additions & 9 deletions tests/ui/parser/fn-header-semantic-fail.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -105,15 +105,6 @@ LL | extern "C" {
LL | extern "C" fn fe4();
| ^^^^^^^^^^ help: remove this qualifier

error: items in unadorned `extern` blocks cannot have safety qualifiers
--> $DIR/fn-header-semantic-fail.rs:50:9
|
LL | extern "C" {
| ---------- help: add unsafe to this `extern` block
...
LL | const async unsafe extern "C" fn fe5();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: functions in `extern` blocks cannot have qualifiers
--> $DIR/fn-header-semantic-fail.rs:50:15
|
Expand Down Expand Up @@ -141,6 +132,15 @@ LL | extern "C" {
LL | const async unsafe extern "C" fn fe5();
| ^^^^^^^^^^ help: remove this qualifier

error: items in unadorned `extern` blocks cannot have safety qualifiers
--> $DIR/fn-header-semantic-fail.rs:50:9
|
LL | extern "C" {
| ---------- help: add unsafe to this `extern` block
...
LL | const async unsafe extern "C" fn fe5();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: functions cannot be both `const` and `async`
--> $DIR/fn-header-semantic-fail.rs:50:9
|
Expand Down
12 changes: 6 additions & 6 deletions tests/ui/parser/no-const-fn-in-extern-block.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,23 @@ LL | extern "C" {
LL | const fn foo();
| ^^^^^ help: remove this qualifier

error: items in unadorned `extern` blocks cannot have safety qualifiers
error: functions in `extern` blocks cannot have qualifiers
--> $DIR/no-const-fn-in-extern-block.rs:4:5
|
LL | extern "C" {
| ---------- help: add unsafe to this `extern` block
| ---------- in this `extern` block
...
LL | const unsafe fn bar();
| ^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^ help: remove this qualifier

error: functions in `extern` blocks cannot have qualifiers
error: items in unadorned `extern` blocks cannot have safety qualifiers
--> $DIR/no-const-fn-in-extern-block.rs:4:5
|
LL | extern "C" {
| ---------- in this `extern` block
| ---------- help: add unsafe to this `extern` block
...
LL | const unsafe fn bar();
| ^^^^^ help: remove this qualifier
| ^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 3 previous errors

32 changes: 32 additions & 0 deletions tests/ui/rust-2024/safe-outside-extern.gated.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
error: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier
--> $DIR/safe-outside-extern.rs:4:1
|
LL | safe fn foo() {}
| ^^^^^^^^^^^^^^^^

error: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier
--> $DIR/safe-outside-extern.rs:8:1
|
LL | safe static FOO: i32 = 1;
| ^^^^^^^^^^^^^^^^^^^^^^^^^

error: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier
--> $DIR/safe-outside-extern.rs:13:5
|
LL | safe fn foo();
| ^^^^^^^^^^^^^^

error: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier
--> $DIR/safe-outside-extern.rs:19:5
|
LL | safe fn foo() {}
| ^^^^^^^^^^^^^^^^

error: function pointers cannot be declared with `safe` safety qualifier
--> $DIR/safe-outside-extern.rs:24:14
|
LL | type FnPtr = safe fn(i32, i32) -> i32;
| ^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 5 previous errors

28 changes: 28 additions & 0 deletions tests/ui/rust-2024/safe-outside-extern.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//@ revisions: gated ungated
#![cfg_attr(gated, feature(unsafe_extern_blocks))]

safe fn foo() {}
spastorino marked this conversation as resolved.
Show resolved Hide resolved
//~^ ERROR: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier
//[ungated]~| ERROR: unsafe extern {}` blocks and `safe` keyword are experimental [E0658]

safe static FOO: i32 = 1;
//~^ ERROR: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier
//[ungated]~| ERROR: unsafe extern {}` blocks and `safe` keyword are experimental [E0658]

trait Foo {
safe fn foo();
//~^ ERROR: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier
//[ungated]~| ERROR: unsafe extern {}` blocks and `safe` keyword are experimental [E0658]
}

impl Foo for () {
safe fn foo() {}
//~^ ERROR: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier
//[ungated]~| ERROR: unsafe extern {}` blocks and `safe` keyword are experimental [E0658]
}

type FnPtr = safe fn(i32, i32) -> i32;
//~^ ERROR: function pointers cannot be declared with `safe` safety qualifier
//[ungated]~| ERROR: unsafe extern {}` blocks and `safe` keyword are experimental [E0658]

fn main() {}
83 changes: 83 additions & 0 deletions tests/ui/rust-2024/safe-outside-extern.ungated.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
error: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier
--> $DIR/safe-outside-extern.rs:4:1
|
LL | safe fn foo() {}
| ^^^^^^^^^^^^^^^^

error: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier
--> $DIR/safe-outside-extern.rs:8:1
|
LL | safe static FOO: i32 = 1;
| ^^^^^^^^^^^^^^^^^^^^^^^^^

error: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier
--> $DIR/safe-outside-extern.rs:13:5
|
LL | safe fn foo();
| ^^^^^^^^^^^^^^

error: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier
--> $DIR/safe-outside-extern.rs:19:5
|
LL | safe fn foo() {}
| ^^^^^^^^^^^^^^^^

error: function pointers cannot be declared with `safe` safety qualifier
--> $DIR/safe-outside-extern.rs:24:14
|
LL | type FnPtr = safe fn(i32, i32) -> i32;
| ^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0658]: `unsafe extern {}` blocks and `safe` keyword are experimental
--> $DIR/safe-outside-extern.rs:4:1
|
LL | safe fn foo() {}
| ^^^^
|
= note: see issue #123743 <https://github.com/rust-lang/rust/issues/123743> for more information
= help: add `#![feature(unsafe_extern_blocks)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error[E0658]: `unsafe extern {}` blocks and `safe` keyword are experimental
--> $DIR/safe-outside-extern.rs:8:1
|
LL | safe static FOO: i32 = 1;
| ^^^^
|
= note: see issue #123743 <https://github.com/rust-lang/rust/issues/123743> for more information
= help: add `#![feature(unsafe_extern_blocks)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error[E0658]: `unsafe extern {}` blocks and `safe` keyword are experimental
--> $DIR/safe-outside-extern.rs:13:5
|
LL | safe fn foo();
| ^^^^
|
= note: see issue #123743 <https://github.com/rust-lang/rust/issues/123743> for more information
= help: add `#![feature(unsafe_extern_blocks)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error[E0658]: `unsafe extern {}` blocks and `safe` keyword are experimental
--> $DIR/safe-outside-extern.rs:19:5
|
LL | safe fn foo() {}
| ^^^^
|
= note: see issue #123743 <https://github.com/rust-lang/rust/issues/123743> for more information
= help: add `#![feature(unsafe_extern_blocks)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error[E0658]: `unsafe extern {}` blocks and `safe` keyword are experimental
--> $DIR/safe-outside-extern.rs:24:14
|
LL | type FnPtr = safe fn(i32, i32) -> i32;
| ^^^^
|
= note: see issue #123743 <https://github.com/rust-lang/rust/issues/123743> for more information
= help: add `#![feature(unsafe_extern_blocks)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error: aborting due to 10 previous errors

For more information about this error, try `rustc --explain E0658`.
Loading