Skip to content

Commit fcae626

Browse files
committed
Auto merge of #126758 - spastorino:avoid-safe-outside-unsafe-blocks, r=compiler-errors
Do not allow safe/unsafe on static and fn items Fixes #126749 r? `@compiler-errors` Tracking: - #123743
2 parents c1b336c + 22831ed commit fcae626

8 files changed

+216
-31
lines changed

compiler/rustc_ast_passes/messages.ftl

+6
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ ast_passes_auto_super_lifetime = auto traits cannot have super traits or lifetim
3030
3131
ast_passes_bad_c_variadic = only foreign or `unsafe extern "C"` functions may be C-variadic
3232
33+
ast_passes_bare_fn_invalid_safety = function pointers cannot be declared with `safe` safety qualifier
34+
.suggestion = remove safe from this item
35+
3336
ast_passes_body_in_extern = incorrect `{$kind}` inside `extern` block
3437
.cannot_have = cannot have a body
3538
.invalid = the invalid body
@@ -167,6 +170,9 @@ ast_passes_invalid_unnamed_field_ty =
167170
unnamed fields can only have struct or union types
168171
.label = not a struct or union
169172
173+
ast_passes_item_invalid_safety = items outside of `unsafe extern {"{ }"}` cannot be declared with `safe` safety qualifier
174+
.suggestion = remove safe from this item
175+
170176
ast_passes_item_underscore = `{$kind}` items in this context need a name
171177
.label = `_` is not a valid name for this `{$kind}` item
172178

compiler/rustc_ast_passes/src/ast_validation.rs

+38-16
Original file line numberDiff line numberDiff line change
@@ -456,15 +456,29 @@ impl<'a> AstValidator<'a> {
456456
}
457457
}
458458

459-
fn check_foreign_item_safety(&self, item_span: Span, safety: Safety) {
460-
if matches!(safety, Safety::Unsafe(_) | Safety::Safe(_))
461-
&& (self.extern_mod_safety == Some(Safety::Default)
462-
|| !self.features.unsafe_extern_blocks)
463-
{
464-
self.dcx().emit_err(errors::InvalidSafetyOnExtern {
465-
item_span,
466-
block: self.current_extern_span(),
467-
});
459+
fn check_item_safety(&self, span: Span, safety: Safety) {
460+
match self.extern_mod_safety {
461+
Some(extern_safety) => {
462+
if matches!(safety, Safety::Unsafe(_) | Safety::Safe(_))
463+
&& (extern_safety == Safety::Default || !self.features.unsafe_extern_blocks)
464+
{
465+
self.dcx().emit_err(errors::InvalidSafetyOnExtern {
466+
item_span: span,
467+
block: self.current_extern_span(),
468+
});
469+
}
470+
}
471+
None => {
472+
if matches!(safety, Safety::Safe(_)) {
473+
self.dcx().emit_err(errors::InvalidSafetyOnItem { span });
474+
}
475+
}
476+
}
477+
}
478+
479+
fn check_bare_fn_safety(&self, span: Span, safety: Safety) {
480+
if matches!(safety, Safety::Safe(_)) {
481+
self.dcx().emit_err(errors::InvalidSafetyOnBareFn { span });
468482
}
469483
}
470484

@@ -746,6 +760,7 @@ impl<'a> AstValidator<'a> {
746760
fn visit_ty_common(&mut self, ty: &'a Ty) {
747761
match &ty.kind {
748762
TyKind::BareFn(bfty) => {
763+
self.check_bare_fn_safety(bfty.decl_span, bfty.safety);
749764
self.check_fn_decl(&bfty.decl, SelfSemantic::No);
750765
Self::check_decl_no_pat(&bfty.decl, |span, _, _| {
751766
self.dcx().emit_err(errors::PatternFnPointer { span });
@@ -1174,11 +1189,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
11741189
});
11751190
}
11761191
}
1177-
ItemKind::Static(box StaticItem { expr: None, .. }) => {
1178-
self.dcx().emit_err(errors::StaticWithoutBody {
1179-
span: item.span,
1180-
replace_span: self.ending_semi_or_hi(item.span),
1181-
});
1192+
ItemKind::Static(box StaticItem { expr, safety, .. }) => {
1193+
self.check_item_safety(item.span, *safety);
1194+
1195+
if expr.is_none() {
1196+
self.dcx().emit_err(errors::StaticWithoutBody {
1197+
span: item.span,
1198+
replace_span: self.ending_semi_or_hi(item.span),
1199+
});
1200+
}
11821201
}
11831202
ItemKind::TyAlias(
11841203
ty_alias @ box TyAlias { defaultness, bounds, where_clauses, ty, .. },
@@ -1212,7 +1231,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
12121231
fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
12131232
match &fi.kind {
12141233
ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => {
1215-
self.check_foreign_item_safety(fi.span, sig.header.safety);
12161234
self.check_defaultness(fi.span, *defaultness);
12171235
self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
12181236
self.check_foreign_fn_headerless(sig.header);
@@ -1233,7 +1251,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
12331251
self.check_foreign_item_ascii_only(fi.ident);
12341252
}
12351253
ForeignItemKind::Static(box StaticItem { expr, safety, .. }) => {
1236-
self.check_foreign_item_safety(fi.span, *safety);
1254+
self.check_item_safety(fi.span, *safety);
12371255
self.check_foreign_kind_bodyless(fi.ident, "static", expr.as_ref().map(|b| b.span));
12381256
self.check_foreign_item_ascii_only(fi.ident);
12391257
}
@@ -1453,6 +1471,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
14531471
};
14541472
self.check_fn_decl(fk.decl(), self_semantic);
14551473

1474+
if let Some(&FnHeader { safety, .. }) = fk.header() {
1475+
self.check_item_safety(span, safety);
1476+
}
1477+
14561478
self.check_c_variadic_type(fk);
14571479

14581480
// Functions cannot both be `const async` or `const gen`

compiler/rustc_ast_passes/src/errors.rs

+14
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,20 @@ pub struct InvalidSafetyOnExtern {
225225
pub block: Span,
226226
}
227227

228+
#[derive(Diagnostic)]
229+
#[diag(ast_passes_item_invalid_safety)]
230+
pub struct InvalidSafetyOnItem {
231+
#[primary_span]
232+
pub span: Span,
233+
}
234+
235+
#[derive(Diagnostic)]
236+
#[diag(ast_passes_bare_fn_invalid_safety)]
237+
pub struct InvalidSafetyOnBareFn {
238+
#[primary_span]
239+
pub span: Span,
240+
}
241+
228242
#[derive(Diagnostic)]
229243
#[diag(ast_passes_bound_in_context)]
230244
pub struct BoundInContext<'a> {

tests/ui/parser/fn-header-semantic-fail.stderr

+9-9
Original file line numberDiff line numberDiff line change
@@ -105,15 +105,6 @@ LL | extern "C" {
105105
LL | extern "C" fn fe4();
106106
| ^^^^^^^^^^ help: remove this qualifier
107107

108-
error: items in unadorned `extern` blocks cannot have safety qualifiers
109-
--> $DIR/fn-header-semantic-fail.rs:50:9
110-
|
111-
LL | extern "C" {
112-
| ---------- help: add unsafe to this `extern` block
113-
...
114-
LL | const async unsafe extern "C" fn fe5();
115-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
116-
117108
error: functions in `extern` blocks cannot have qualifiers
118109
--> $DIR/fn-header-semantic-fail.rs:50:15
119110
|
@@ -141,6 +132,15 @@ LL | extern "C" {
141132
LL | const async unsafe extern "C" fn fe5();
142133
| ^^^^^^^^^^ help: remove this qualifier
143134

135+
error: items in unadorned `extern` blocks cannot have safety qualifiers
136+
--> $DIR/fn-header-semantic-fail.rs:50:9
137+
|
138+
LL | extern "C" {
139+
| ---------- help: add unsafe to this `extern` block
140+
...
141+
LL | const async unsafe extern "C" fn fe5();
142+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
143+
144144
error: functions cannot be both `const` and `async`
145145
--> $DIR/fn-header-semantic-fail.rs:50:9
146146
|

tests/ui/parser/no-const-fn-in-extern-block.stderr

+6-6
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,23 @@ LL | extern "C" {
66
LL | const fn foo();
77
| ^^^^^ help: remove this qualifier
88

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

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

2727
error: aborting due to 3 previous errors
2828

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
error: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier
2+
--> $DIR/safe-outside-extern.rs:4:1
3+
|
4+
LL | safe fn foo() {}
5+
| ^^^^^^^^^^^^^^^^
6+
7+
error: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier
8+
--> $DIR/safe-outside-extern.rs:8:1
9+
|
10+
LL | safe static FOO: i32 = 1;
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
12+
13+
error: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier
14+
--> $DIR/safe-outside-extern.rs:13:5
15+
|
16+
LL | safe fn foo();
17+
| ^^^^^^^^^^^^^^
18+
19+
error: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier
20+
--> $DIR/safe-outside-extern.rs:19:5
21+
|
22+
LL | safe fn foo() {}
23+
| ^^^^^^^^^^^^^^^^
24+
25+
error: function pointers cannot be declared with `safe` safety qualifier
26+
--> $DIR/safe-outside-extern.rs:24:14
27+
|
28+
LL | type FnPtr = safe fn(i32, i32) -> i32;
29+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
30+
31+
error: aborting due to 5 previous errors
32+
+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//@ revisions: gated ungated
2+
#![cfg_attr(gated, feature(unsafe_extern_blocks))]
3+
4+
safe fn foo() {}
5+
//~^ ERROR: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier
6+
//[ungated]~| ERROR: unsafe extern {}` blocks and `safe` keyword are experimental [E0658]
7+
8+
safe static FOO: i32 = 1;
9+
//~^ ERROR: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier
10+
//[ungated]~| ERROR: unsafe extern {}` blocks and `safe` keyword are experimental [E0658]
11+
12+
trait Foo {
13+
safe fn foo();
14+
//~^ ERROR: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier
15+
//[ungated]~| ERROR: unsafe extern {}` blocks and `safe` keyword are experimental [E0658]
16+
}
17+
18+
impl Foo for () {
19+
safe fn foo() {}
20+
//~^ ERROR: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier
21+
//[ungated]~| ERROR: unsafe extern {}` blocks and `safe` keyword are experimental [E0658]
22+
}
23+
24+
type FnPtr = safe fn(i32, i32) -> i32;
25+
//~^ ERROR: function pointers cannot be declared with `safe` safety qualifier
26+
//[ungated]~| ERROR: unsafe extern {}` blocks and `safe` keyword are experimental [E0658]
27+
28+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
error: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier
2+
--> $DIR/safe-outside-extern.rs:4:1
3+
|
4+
LL | safe fn foo() {}
5+
| ^^^^^^^^^^^^^^^^
6+
7+
error: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier
8+
--> $DIR/safe-outside-extern.rs:8:1
9+
|
10+
LL | safe static FOO: i32 = 1;
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
12+
13+
error: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier
14+
--> $DIR/safe-outside-extern.rs:13:5
15+
|
16+
LL | safe fn foo();
17+
| ^^^^^^^^^^^^^^
18+
19+
error: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier
20+
--> $DIR/safe-outside-extern.rs:19:5
21+
|
22+
LL | safe fn foo() {}
23+
| ^^^^^^^^^^^^^^^^
24+
25+
error: function pointers cannot be declared with `safe` safety qualifier
26+
--> $DIR/safe-outside-extern.rs:24:14
27+
|
28+
LL | type FnPtr = safe fn(i32, i32) -> i32;
29+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
30+
31+
error[E0658]: `unsafe extern {}` blocks and `safe` keyword are experimental
32+
--> $DIR/safe-outside-extern.rs:4:1
33+
|
34+
LL | safe fn foo() {}
35+
| ^^^^
36+
|
37+
= note: see issue #123743 <https://github.com/rust-lang/rust/issues/123743> for more information
38+
= help: add `#![feature(unsafe_extern_blocks)]` to the crate attributes to enable
39+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
40+
41+
error[E0658]: `unsafe extern {}` blocks and `safe` keyword are experimental
42+
--> $DIR/safe-outside-extern.rs:8:1
43+
|
44+
LL | safe static FOO: i32 = 1;
45+
| ^^^^
46+
|
47+
= note: see issue #123743 <https://github.com/rust-lang/rust/issues/123743> for more information
48+
= help: add `#![feature(unsafe_extern_blocks)]` to the crate attributes to enable
49+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
50+
51+
error[E0658]: `unsafe extern {}` blocks and `safe` keyword are experimental
52+
--> $DIR/safe-outside-extern.rs:13:5
53+
|
54+
LL | safe fn foo();
55+
| ^^^^
56+
|
57+
= note: see issue #123743 <https://github.com/rust-lang/rust/issues/123743> for more information
58+
= help: add `#![feature(unsafe_extern_blocks)]` to the crate attributes to enable
59+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
60+
61+
error[E0658]: `unsafe extern {}` blocks and `safe` keyword are experimental
62+
--> $DIR/safe-outside-extern.rs:19:5
63+
|
64+
LL | safe fn foo() {}
65+
| ^^^^
66+
|
67+
= note: see issue #123743 <https://github.com/rust-lang/rust/issues/123743> for more information
68+
= help: add `#![feature(unsafe_extern_blocks)]` to the crate attributes to enable
69+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
70+
71+
error[E0658]: `unsafe extern {}` blocks and `safe` keyword are experimental
72+
--> $DIR/safe-outside-extern.rs:24:14
73+
|
74+
LL | type FnPtr = safe fn(i32, i32) -> i32;
75+
| ^^^^
76+
|
77+
= note: see issue #123743 <https://github.com/rust-lang/rust/issues/123743> for more information
78+
= help: add `#![feature(unsafe_extern_blocks)]` to the crate attributes to enable
79+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
80+
81+
error: aborting due to 10 previous errors
82+
83+
For more information about this error, try `rustc --explain E0658`.

0 commit comments

Comments
 (0)