Rollup merge of #127921 - spastorino:stabilize-unsafe-extern-blocks, r=compiler-errors

Stabilize unsafe extern blocks (RFC 3484)

# Stabilization report

## Summary

This is a tracking issue for the RFC 3484: Unsafe Extern Blocks

We are stabilizing `#![feature(unsafe_extern_blocks)]`, as described in [Unsafe Extern Blocks RFC 3484](https://github.com/rust-lang/rfcs/pull/3484). This feature makes explicit that declaring an extern block is unsafe. Starting in Rust 2024, all extern blocks must be marked as unsafe. In all editions, items within unsafe extern blocks may be marked as safe to use.

RFC: https://github.com/rust-lang/rfcs/pull/3484
Tracking issue: #123743

## What is stabilized

### Summary of stabilization

We now need extern blocks to be marked as unsafe and items inside can also have safety modifiers (unsafe or safe), by default items with no modifiers are unsafe to offer easy migration without surprising results.

```rust
unsafe extern {
    // sqrt (from libm) may be called with any `f64`
    pub safe fn sqrt(x: f64) -> f64;

    // strlen (from libc) requires a valid pointer,
    // so we mark it as being an unsafe fn
    pub unsafe fn strlen(p: *const c_char) -> usize;

    // this function doesn't say safe or unsafe, so it defaults to unsafe
    pub fn free(p: *mut core::ffi::c_void);

    pub safe static IMPORTANT_BYTES: [u8; 256];

    pub safe static LINES: SyncUnsafeCell<i32>;
}
```

## Tests

The relevant tests are in `tests/ui/rust-2024/unsafe-extern-blocks`.

## History

- https://github.com/rust-lang/rust/pull/124482
- https://github.com/rust-lang/rust/pull/124455
- https://github.com/rust-lang/rust/pull/125077
- https://github.com/rust-lang/rust/pull/125522
- https://github.com/rust-lang/rust/issues/126738
- https://github.com/rust-lang/rust/issues/126749
- https://github.com/rust-lang/rust/issues/126755
- https://github.com/rust-lang/rust/pull/126757
- https://github.com/rust-lang/rust/pull/126758
- https://github.com/rust-lang/rust/issues/126756
- https://github.com/rust-lang/rust/pull/126973
- https://github.com/rust-lang/rust/pull/127535
- https://github.com/rust-lang/rustfmt/pull/6204

## Unresolved questions

I am not aware of any unresolved questions.
This commit is contained in:
Matthias Krüger 2024-08-03 20:51:51 +02:00 committed by GitHub
commit 7d9ed2a864
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
41 changed files with 85 additions and 163 deletions

View File

@ -453,11 +453,6 @@ impl<'a> AstValidator<'a> {
item_span: span,
block: Some(self.current_extern_span().shrink_to_lo()),
});
} else if !self.features.unsafe_extern_blocks {
self.dcx().emit_err(errors::InvalidSafetyOnExtern {
item_span: span,
block: None,
});
}
}
}
@ -1054,32 +1049,19 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
errors::VisibilityNotPermittedNote::IndividualForeignItems,
);
if this.features.unsafe_extern_blocks {
if &Safety::Default == safety {
if item.span.at_least_rust_2024() {
this.dcx()
.emit_err(errors::MissingUnsafeOnExtern { span: item.span });
} else {
this.lint_buffer.buffer_lint(
MISSING_UNSAFE_ON_EXTERN,
item.id,
item.span,
BuiltinLintDiag::MissingUnsafeOnExtern {
suggestion: item.span.shrink_to_lo(),
},
);
}
if &Safety::Default == safety {
if item.span.at_least_rust_2024() {
this.dcx().emit_err(errors::MissingUnsafeOnExtern { span: item.span });
} else {
this.lint_buffer.buffer_lint(
MISSING_UNSAFE_ON_EXTERN,
item.id,
item.span,
BuiltinLintDiag::MissingUnsafeOnExtern {
suggestion: item.span.shrink_to_lo(),
},
);
}
} else if let &Safety::Unsafe(span) = safety {
let mut diag = this
.dcx()
.create_err(errors::UnsafeItem { span, kind: "extern block" });
rustc_session::parse::add_feature_diagnostics(
&mut diag,
self.session,
sym::unsafe_extern_blocks,
);
diag.emit();
}
if abi.is_none() {

View File

@ -560,10 +560,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
gate_all!(precise_capturing, "precise captures on `impl Trait` are experimental");
gate_all!(global_registration, "global registration is experimental");
gate_all!(unsafe_attributes, "`#[unsafe()]` markers for attributes are experimental");
gate_all!(
unsafe_extern_blocks,
"`unsafe extern {}` blocks and `safe` keyword are experimental"
);
gate_all!(return_type_notation, "return type notation is experimental");
if !visitor.features.never_patterns {

View File

@ -390,6 +390,8 @@ declare_features! (
(accepted, unrestricted_attribute_tokens, "1.34.0", Some(55208)),
/// The `unsafe_op_in_unsafe_fn` lint (allowed by default): no longer treat an unsafe function as an unsafe block.
(accepted, unsafe_block_in_unsafe_fn, "1.52.0", Some(71668)),
/// Allows unsafe on extern declarations and safety qualifiers over internal items.
(accepted, unsafe_extern_blocks, "CURRENT_RUSTC_VERSION", Some(123743)),
/// Allows importing and reexporting macros with `use`,
/// enables macro modularization in general.
(accepted, use_extern_macros, "1.30.0", Some(35896)),

View File

@ -631,8 +631,6 @@ declare_features! (
(incomplete, unnamed_fields, "1.74.0", Some(49804)),
/// Allows unsafe attributes.
(unstable, unsafe_attributes, "1.80.0", Some(123757)),
/// Allows unsafe on extern declarations and safety qualifiers over internal items.
(unstable, unsafe_extern_blocks, "1.80.0", Some(123743)),
/// Allows const generic parameters to be defined with types that
/// are not `Sized`, e.g. `fn foo<const N: [u8]>() {`.
(incomplete, unsized_const_params, "CURRENT_RUSTC_VERSION", Some(95174)),

View File

@ -4934,7 +4934,6 @@ declare_lint! {
/// ### Example
///
/// ```rust
/// #![feature(unsafe_extern_blocks)]
/// #![warn(missing_unsafe_on_extern)]
/// #![allow(dead_code)]
///

View File

@ -1250,9 +1250,6 @@ impl<'a> Parser<'a> {
if self.eat_keyword_case(kw::Unsafe, case) {
Safety::Unsafe(self.prev_token.uninterpolated_span())
} else if self.eat_keyword_case(kw::Safe, case) {
self.psess
.gated_spans
.gate(sym::unsafe_extern_blocks, self.prev_token.uninterpolated_span());
Safety::Safe(self.prev_token.uninterpolated_span())
} else {
Safety::Default

View File

@ -1,6 +1,5 @@
// Test to ensure the feature is working as expected.
#![feature(unsafe_extern_blocks)]
#![crate_name = "foo"]
// @has 'foo/index.html'
@ -13,7 +12,7 @@
// @count - '//ul[@class="item-table"]//sup[@title="unsafe function"]' 1
// @has - '//ul[@class="item-table"]//sup[@title="unsafe function"]' '⚠'
unsafe extern {
unsafe extern "C" {
// @has 'foo/static.FOO.html'
// @has - '//pre[@class="rust item-decl"]' 'pub static FOO: i32'
pub safe static FOO: i32;

View File

@ -1,13 +0,0 @@
unsafe extern "C" {
//~^ ERROR extern block cannot be declared unsafe
}
// We can't gate `unsafe extern` blocks themselves since they were previously
// allowed, but we should gate the `safe` soft keyword.
#[cfg(any())]
unsafe extern "C" {
safe fn foo();
//~^ ERROR `unsafe extern {}` blocks and `safe` keyword are experimental
}
fn main() {}

View File

@ -1,23 +0,0 @@
error: extern block cannot be declared unsafe
--> $DIR/feature-gate-unsafe-extern-blocks.rs:1:1
|
LL | unsafe extern "C" {
| ^^^^^^
|
= 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/feature-gate-unsafe-extern-blocks.rs:9: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: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0658`.

View File

@ -1,4 +1,3 @@
#![feature(unsafe_extern_blocks)]
#![deny(unsafe_code)]
#[allow(unsafe_code)]

View File

@ -1,5 +1,5 @@
error: usage of an `unsafe extern` block
--> $DIR/unsafe-extern-blocks.rs:9:1
--> $DIR/unsafe-extern-blocks.rs:8:1
|
LL | / unsafe extern "C" {
LL | |
@ -8,7 +8,7 @@ LL | | }
| |_^
|
note: the lint level is defined here
--> $DIR/unsafe-extern-blocks.rs:2:9
--> $DIR/unsafe-extern-blocks.rs:1:9
|
LL | #![deny(unsafe_code)]
| ^^^^^^^^^^^

View File

@ -1,8 +1,6 @@
extern "C" unsafe {
//~^ ERROR expected `{`, found keyword `unsafe`
//~| ERROR extern block cannot be declared unsafe
unsafe fn foo();
//~^ ERROR items in unadorned `extern` blocks cannot have safety qualifiers
}
fn main() {}

View File

@ -4,21 +4,5 @@ error: expected `{`, found keyword `unsafe`
LL | extern "C" unsafe {
| ^^^^^^ expected `{`
error: extern block cannot be declared unsafe
--> $DIR/unsafe-foreign-mod-2.rs:1:12
|
LL | extern "C" unsafe {
| ^^^^^^
|
= 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: items in unadorned `extern` blocks cannot have safety qualifiers
--> $DIR/unsafe-foreign-mod-2.rs:4:5
|
LL | unsafe fn foo();
| ^^^^^^^^^^^^^^^^
error: aborting due to 3 previous errors
error: aborting due to 1 previous error

View File

@ -1,5 +1,5 @@
unsafe extern "C" {
//~^ ERROR extern block cannot be declared unsafe
}
//@ check-pass
unsafe extern "C" {}
fn main() {}

View File

@ -1,12 +0,0 @@
error: extern block cannot be declared unsafe
--> $DIR/unsafe-foreign-mod.rs:1:1
|
LL | unsafe extern "C" {
| ^^^^^^
|
= 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 1 previous error

View File

@ -1,29 +1,21 @@
//@ revisions: gated ungated
#![cfg_attr(gated, feature(unsafe_extern_blocks))]
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]
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]
unsafe static LOL: u8 = 0;
//~^ ERROR: static items cannot be declared with `unsafe` safety qualifier outside of `extern` block

View File

@ -0,0 +1,38 @@
error: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier
--> $DIR/safe-outside-extern.rs:1:1
|
LL | safe fn foo() {}
| ^^^^^^^^^^^^^^^^
error: items outside of `unsafe extern { }` cannot be declared with `safe` safety qualifier
--> $DIR/safe-outside-extern.rs:4: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:8:5
|
LL | safe fn foo();
| ^^^^^^^^^^^^^^
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: function pointers cannot be declared with `safe` safety qualifier
--> $DIR/safe-outside-extern.rs:17:14
|
LL | type FnPtr = safe fn(i32, i32) -> i32;
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: static items cannot be declared with `unsafe` safety qualifier outside of `extern` block
--> $DIR/safe-outside-extern.rs:20:1
|
LL | unsafe static LOL: u8 = 0;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 6 previous errors

View File

@ -1,5 +1,5 @@
error[E0133]: call to unsafe function `test1` is unsafe and requires unsafe function or block
--> $DIR/extern-items-unsafe.rs:14:5
--> $DIR/extern-items-unsafe.rs:12:5
|
LL | test1(TEST1);
| ^^^^^^^^^^^^ call to unsafe function
@ -7,7 +7,7 @@ LL | test1(TEST1);
= note: consult the function's documentation for information on how to avoid undefined behavior
error[E0133]: use of extern static is unsafe and requires unsafe function or block
--> $DIR/extern-items-unsafe.rs:14:11
--> $DIR/extern-items-unsafe.rs:12:11
|
LL | test1(TEST1);
| ^^^^^ use of extern static

View File

@ -1,5 +1,5 @@
error[E0133]: call to unsafe function `test1` is unsafe and requires unsafe block
--> $DIR/extern-items-unsafe.rs:14:5
--> $DIR/extern-items-unsafe.rs:12:5
|
LL | test1(TEST1);
| ^^^^^^^^^^^^ call to unsafe function
@ -7,7 +7,7 @@ LL | test1(TEST1);
= note: consult the function's documentation for information on how to avoid undefined behavior
error[E0133]: use of extern static is unsafe and requires unsafe block
--> $DIR/extern-items-unsafe.rs:14:11
--> $DIR/extern-items-unsafe.rs:12:11
|
LL | test1(TEST1);
| ^^^^^ use of extern static

View File

@ -3,8 +3,6 @@
//@[edition2024] edition:2024
//@[edition2024] compile-flags: -Zunstable-options
#![feature(unsafe_extern_blocks)]
unsafe extern "C" {
static TEST1: i32;
fn test1(i: i32);

View File

@ -1,5 +1,5 @@
error: extern blocks must be unsafe
--> $DIR/extern-items.rs:9:1
--> $DIR/extern-items.rs:7:1
|
LL | / extern "C" {
LL | |

View File

@ -4,8 +4,6 @@
//@[edition2024] edition:2024
//@[edition2024] compile-flags: -Zunstable-options
#![feature(unsafe_extern_blocks)]
extern "C" {
//[edition2024]~^ ERROR extern blocks must be unsafe
static TEST1: i32;

View File

@ -1,6 +1,3 @@
//@ revisions: gated ungated
#![cfg_attr(gated, feature(unsafe_extern_blocks))]
trait Bar {}
safe impl Bar for () { }
//~^ ERROR expected one of `!` or `::`, found keyword `impl`

View File

@ -1,5 +1,5 @@
error: expected one of `!` or `::`, found keyword `impl`
--> $DIR/safe-impl-trait.rs:5:6
--> $DIR/safe-impl-trait.rs:2:6
|
LL | safe impl Bar for () { }
| ^^^^ expected one of `!` or `::`

View File

@ -4,8 +4,6 @@
//@[edition2024] compile-flags: -Zunstable-options
//@ check-pass
#![feature(unsafe_extern_blocks)]
unsafe extern "C" {
safe static TEST1: i32;
safe fn test1(i: i32);

View File

@ -1,6 +1,3 @@
//@ revisions: gated ungated
#![cfg_attr(gated, feature(unsafe_extern_blocks))]
safe trait Foo {}
//~^ ERROR expected one of `!` or `::`, found keyword `trait`

View File

@ -0,0 +1,8 @@
error: expected one of `!` or `::`, found keyword `trait`
--> $DIR/safe-trait.rs:1:6
|
LL | safe trait Foo {}
| ^^^^^ expected one of `!` or `::`
error: aborting due to 1 previous error

View File

@ -1,5 +1,5 @@
error: items in unadorned `extern` blocks cannot have safety qualifiers
--> $DIR/safe-unsafe-on-unadorned-extern-block.rs:10:5
--> $DIR/safe-unsafe-on-unadorned-extern-block.rs:8:5
|
LL | safe static TEST1: i32;
| ^^^^^^^^^^^^^^^^^^^^^^^
@ -10,7 +10,7 @@ LL | unsafe extern "C" {
| ++++++
error: items in unadorned `extern` blocks cannot have safety qualifiers
--> $DIR/safe-unsafe-on-unadorned-extern-block.rs:12:5
--> $DIR/safe-unsafe-on-unadorned-extern-block.rs:10:5
|
LL | safe fn test1(i: i32);
| ^^^^^^^^^^^^^^^^^^^^^^

View File

@ -1,5 +1,5 @@
error: extern blocks must be unsafe
--> $DIR/safe-unsafe-on-unadorned-extern-block.rs:8:1
--> $DIR/safe-unsafe-on-unadorned-extern-block.rs:6:1
|
LL | / extern "C" {
LL | |
@ -11,7 +11,7 @@ LL | | }
| |_^
error: items in unadorned `extern` blocks cannot have safety qualifiers
--> $DIR/safe-unsafe-on-unadorned-extern-block.rs:10:5
--> $DIR/safe-unsafe-on-unadorned-extern-block.rs:8:5
|
LL | safe static TEST1: i32;
| ^^^^^^^^^^^^^^^^^^^^^^^
@ -22,7 +22,7 @@ LL | unsafe extern "C" {
| ++++++
error: items in unadorned `extern` blocks cannot have safety qualifiers
--> $DIR/safe-unsafe-on-unadorned-extern-block.rs:12:5
--> $DIR/safe-unsafe-on-unadorned-extern-block.rs:10:5
|
LL | safe fn test1(i: i32);
| ^^^^^^^^^^^^^^^^^^^^^^

View File

@ -3,8 +3,6 @@
//@[edition2024] edition:2024
//@[edition2024] compile-flags: -Zunstable-options
#![feature(unsafe_extern_blocks)]
extern "C" {
//[edition2024]~^ ERROR extern blocks must be unsafe
safe static TEST1: i32;

View File

@ -1,6 +1,5 @@
//@ run-rustfix
#![feature(unsafe_extern_blocks)]
#![deny(missing_unsafe_on_extern)]
#![allow(unused)]

View File

@ -1,6 +1,5 @@
//@ run-rustfix
#![feature(unsafe_extern_blocks)]
#![deny(missing_unsafe_on_extern)]
#![allow(unused)]

View File

@ -1,5 +1,5 @@
error: extern blocks should be unsafe
--> $DIR/unsafe-extern-suggestion.rs:7:1
--> $DIR/unsafe-extern-suggestion.rs:6:1
|
LL | extern "C" {
| ^
@ -16,7 +16,7 @@ LL | | }
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
= note: for more information, see issue #123743 <https://github.com/rust-lang/rust/issues/123743>
note: the lint level is defined here
--> $DIR/unsafe-extern-suggestion.rs:4:9
--> $DIR/unsafe-extern-suggestion.rs:3:9
|
LL | #![deny(missing_unsafe_on_extern)]
| ^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -1,5 +1,5 @@
error[E0133]: call to unsafe function `test1` is unsafe and requires unsafe function or block
--> $DIR/unsafe-items.rs:20:5
--> $DIR/unsafe-items.rs:18:5
|
LL | test1(TEST1);
| ^^^^^^^^^^^^ call to unsafe function
@ -7,7 +7,7 @@ LL | test1(TEST1);
= note: consult the function's documentation for information on how to avoid undefined behavior
error[E0133]: use of extern static is unsafe and requires unsafe function or block
--> $DIR/unsafe-items.rs:20:11
--> $DIR/unsafe-items.rs:18:11
|
LL | test1(TEST1);
| ^^^^^ use of extern static

View File

@ -1,5 +1,5 @@
error[E0133]: call to unsafe function `test1` is unsafe and requires unsafe block
--> $DIR/unsafe-items.rs:20:5
--> $DIR/unsafe-items.rs:18:5
|
LL | test1(TEST1);
| ^^^^^^^^^^^^ call to unsafe function
@ -7,7 +7,7 @@ LL | test1(TEST1);
= note: consult the function's documentation for information on how to avoid undefined behavior
error[E0133]: use of extern static is unsafe and requires unsafe block
--> $DIR/unsafe-items.rs:20:11
--> $DIR/unsafe-items.rs:18:11
|
LL | test1(TEST1);
| ^^^^^ use of extern static

View File

@ -3,8 +3,6 @@
//@[edition2024] edition:2024
//@[edition2024] compile-flags: -Zunstable-options
#![feature(unsafe_extern_blocks)]
unsafe extern "C" {
unsafe static TEST1: i32;
unsafe fn test1(i: i32);

View File

@ -1,6 +1,5 @@
//@ run-rustfix
#![feature(unsafe_extern_blocks)]
#![allow(dead_code)]
unsafe extern "C" {

View File

@ -1,6 +1,5 @@
//@ run-rustfix
#![feature(unsafe_extern_blocks)]
#![allow(dead_code)]
extern "C" {

View File

@ -1,5 +1,5 @@
error: items in unadorned `extern` blocks cannot have safety qualifiers
--> $DIR/unsafe-on-extern-block-issue-126756.rs:7:5
--> $DIR/unsafe-on-extern-block-issue-126756.rs:6:5
|
LL | unsafe fn foo();
| ^^^^^^^^^^^^^^^^

View File

@ -25,7 +25,6 @@
#![feature(trait_alias)]
#![feature(try_blocks)]
#![feature(unnamed_fields)]
#![feature(unsafe_extern_blocks)]
#![feature(yeet_expr)]
#![allow(incomplete_features)]

View File

@ -26,7 +26,6 @@
#![feature(trait_alias)]
#![feature(try_blocks)]
#![feature(unnamed_fields)]
#![feature(unsafe_extern_blocks)]
#![feature(yeet_expr)]
#![allow(incomplete_features)]
#[prelude_import]