Skip to content

Commit

Permalink
Rollup merge of rust-lang#127921 - spastorino:stabilize-unsafe-extern…
Browse files Browse the repository at this point in the history
…-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](rust-lang/rfcs#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: rust-lang/rfcs#3484
Tracking issue: rust-lang#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

- rust-lang#124482
- rust-lang#124455
- rust-lang#125077
- rust-lang#125522
- rust-lang#126738
- rust-lang#126749
- rust-lang#126755
- rust-lang#126757
- rust-lang#126758
- rust-lang#126756
- rust-lang#126973
- rust-lang#127535
- rust-lang/rustfmt#6204

## Unresolved questions

I am not aware of any unresolved questions.
  • Loading branch information
matthiaskrgr authored Aug 3, 2024
2 parents edc4dc3 + 8366c7f commit 7d9ed2a
Show file tree
Hide file tree
Showing 41 changed files with 85 additions and 163 deletions.
42 changes: 12 additions & 30 deletions compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
});
}
}
}
Expand Down Expand Up @@ -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() {
Expand Down
4 changes: 0 additions & 4 deletions compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/accepted.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)),
Expand Down
2 changes: 0 additions & 2 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)),
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_lint_defs/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4934,7 +4934,6 @@ declare_lint! {
/// ### Example
///
/// ```rust
/// #![feature(unsafe_extern_blocks)]
/// #![warn(missing_unsafe_on_extern)]
/// #![allow(dead_code)]
///
Expand Down
3 changes: 0 additions & 3 deletions compiler/rustc_parse/src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 1 addition & 2 deletions tests/rustdoc/unsafe-extern-blocks.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// Test to ensure the feature is working as expected.

#![feature(unsafe_extern_blocks)]
#![crate_name = "foo"]

// @has 'foo/index.html'
Expand All @@ -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;
Expand Down
13 changes: 0 additions & 13 deletions tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.rs

This file was deleted.

23 changes: 0 additions & 23 deletions tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.stderr

This file was deleted.

1 change: 0 additions & 1 deletion tests/ui/lint/unsafe_code/unsafe-extern-blocks.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#![feature(unsafe_extern_blocks)]
#![deny(unsafe_code)]

#[allow(unsafe_code)]
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/lint/unsafe_code/unsafe-extern-blocks.stderr
Original file line number Diff line number Diff line change
@@ -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 | |
Expand All @@ -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)]
| ^^^^^^^^^^^
Expand Down
2 changes: 0 additions & 2 deletions tests/ui/parser/unsafe-foreign-mod-2.rs
Original file line number Diff line number Diff line change
@@ -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() {}
18 changes: 1 addition & 17 deletions tests/ui/parser/unsafe-foreign-mod-2.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

6 changes: 3 additions & 3 deletions tests/ui/parser/unsafe-foreign-mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
unsafe extern "C" {
//~^ ERROR extern block cannot be declared unsafe
}
//@ check-pass

unsafe extern "C" {}

fn main() {}
12 changes: 0 additions & 12 deletions tests/ui/parser/unsafe-foreign-mod.stderr

This file was deleted.

8 changes: 0 additions & 8 deletions tests/ui/rust-2024/safe-outside-extern.rs
Original file line number Diff line number Diff line change
@@ -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
Expand Down
38 changes: 38 additions & 0 deletions tests/ui/rust-2024/safe-outside-extern.stderr
Original file line number Diff line number Diff line change
@@ -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

Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
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
|
= 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
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
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
|
= 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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 | |
Expand Down
2 changes: 0 additions & 2 deletions tests/ui/rust-2024/unsafe-extern-blocks/extern-items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 0 additions & 3 deletions tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.rs
Original file line number Diff line number Diff line change
@@ -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`
Expand Down
Original file line number Diff line number Diff line change
@@ -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 `::`
Expand Down
2 changes: 0 additions & 2 deletions tests/ui/rust-2024/unsafe-extern-blocks/safe-items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 0 additions & 3 deletions tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.rs
Original file line number Diff line number Diff line change
@@ -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`

Expand Down
8 changes: 8 additions & 0 deletions tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.stderr
Original file line number Diff line number Diff line change
@@ -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

Loading

0 comments on commit 7d9ed2a

Please sign in to comment.