From 68b0b86c5b703f11e4fa139cf60c9addb30dacb0 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 24 Apr 2024 18:53:56 -0300 Subject: [PATCH 01/12] Add unsafe extern blocks failing tests --- .../rust-2024/unsafe-extern-blocks/extern-items.rs | 12 ++++++++++++ .../unsafe-extern-blocks/extern-items.stderr | 8 ++++++++ 2 files changed, 20 insertions(+) create mode 100644 tests/ui/rust-2024/unsafe-extern-blocks/extern-items.rs create mode 100644 tests/ui/rust-2024/unsafe-extern-blocks/extern-items.stderr diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.rs b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.rs new file mode 100644 index 0000000000000..de5947fc07b0b --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.rs @@ -0,0 +1,12 @@ +extern "C" { + static TEST1: i32; + fn test1(i: i32); +} + +unsafe extern "C" { + //~^ ERROR: extern block cannot be declared unsafe + static TEST2: i32; + fn test2(i: i32); +} + +fn main() {} diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.stderr new file mode 100644 index 0000000000000..d9585ed3db669 --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.stderr @@ -0,0 +1,8 @@ +error: extern block cannot be declared unsafe + --> $DIR/extern-items.rs:6:1 + | +LL | unsafe extern "C" { + | ^^^^^^ + +error: aborting due to 1 previous error + From 6d670b74e59de5e2f12e0d19b46b7939e4cd4a31 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 24 Apr 2024 19:10:14 -0300 Subject: [PATCH 02/12] Allow unsafe extern on all editions --- compiler/rustc_ast_passes/src/ast_validation.rs | 5 +---- tests/ui/parser/unsafe-foreign-mod-2.rs | 5 ++--- tests/ui/parser/unsafe-foreign-mod-2.stderr | 12 +++--------- tests/ui/parser/unsafe-foreign-mod.rs | 6 +++--- tests/ui/parser/unsafe-foreign-mod.stderr | 8 -------- .../rust-2024/unsafe-extern-blocks/extern-items.rs | 3 ++- .../unsafe-extern-blocks/extern-items.stderr | 8 -------- 7 files changed, 11 insertions(+), 36 deletions(-) delete mode 100644 tests/ui/parser/unsafe-foreign-mod.stderr delete mode 100644 tests/ui/rust-2024/unsafe-extern-blocks/extern-items.stderr diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 435b0b6a95657..c0011fd9c45e5 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1016,15 +1016,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> { walk_list!(self, visit_attribute, &item.attrs); return; // Avoid visiting again. } - ItemKind::ForeignMod(ForeignMod { abi, safety, .. }) => { + ItemKind::ForeignMod(ForeignMod { abi, .. }) => { let old_item = mem::replace(&mut self.extern_mod, Some(item)); self.visibility_not_permitted( &item.vis, errors::VisibilityNotPermittedNote::IndividualForeignItems, ); - if let &Safety::Unsafe(span) = safety { - self.dcx().emit_err(errors::UnsafeItem { span, kind: "extern block" }); - } if abi.is_none() { self.maybe_lint_missing_abi(item.span, item.id); } diff --git a/tests/ui/parser/unsafe-foreign-mod-2.rs b/tests/ui/parser/unsafe-foreign-mod-2.rs index 77856fb67340e..c0994090eff48 100644 --- a/tests/ui/parser/unsafe-foreign-mod-2.rs +++ b/tests/ui/parser/unsafe-foreign-mod-2.rs @@ -1,8 +1,7 @@ extern "C" unsafe { - //~^ ERROR expected `{`, found keyword `unsafe` - //~| ERROR extern block cannot be declared unsafe + //~^ ERROR expected `{`, found keyword `unsafe` unsafe fn foo(); - //~^ ERROR functions in `extern` blocks cannot have qualifiers + //~^ ERROR functions in `extern` blocks cannot have qualifiers } fn main() {} diff --git a/tests/ui/parser/unsafe-foreign-mod-2.stderr b/tests/ui/parser/unsafe-foreign-mod-2.stderr index fc05184f018f5..620d042540ec1 100644 --- a/tests/ui/parser/unsafe-foreign-mod-2.stderr +++ b/tests/ui/parser/unsafe-foreign-mod-2.stderr @@ -4,20 +4,14 @@ 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 { - | ^^^^^^ - error: functions in `extern` blocks cannot have qualifiers - --> $DIR/unsafe-foreign-mod-2.rs:4:5 + --> $DIR/unsafe-foreign-mod-2.rs:3:5 | LL | extern "C" unsafe { | ----------------- in this `extern` block -... +LL | LL | unsafe fn foo(); | ^^^^^^ help: remove this qualifier -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/parser/unsafe-foreign-mod.rs b/tests/ui/parser/unsafe-foreign-mod.rs index eab134a4a4de4..26015a3c44454 100644 --- a/tests/ui/parser/unsafe-foreign-mod.rs +++ b/tests/ui/parser/unsafe-foreign-mod.rs @@ -1,5 +1,5 @@ -unsafe extern "C" { - //~^ ERROR extern block cannot be declared unsafe -} +//@ build-pass + +unsafe extern "C" {} fn main() {} diff --git a/tests/ui/parser/unsafe-foreign-mod.stderr b/tests/ui/parser/unsafe-foreign-mod.stderr deleted file mode 100644 index 77f6e93be10bb..0000000000000 --- a/tests/ui/parser/unsafe-foreign-mod.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: extern block cannot be declared unsafe - --> $DIR/unsafe-foreign-mod.rs:1:1 - | -LL | unsafe extern "C" { - | ^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.rs b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.rs index de5947fc07b0b..fd2cd29fd748f 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.rs +++ b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.rs @@ -1,10 +1,11 @@ +//@ build-pass + extern "C" { static TEST1: i32; fn test1(i: i32); } unsafe extern "C" { - //~^ ERROR: extern block cannot be declared unsafe static TEST2: i32; fn test2(i: i32); } diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.stderr deleted file mode 100644 index d9585ed3db669..0000000000000 --- a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: extern block cannot be declared unsafe - --> $DIR/extern-items.rs:6:1 - | -LL | unsafe extern "C" { - | ^^^^^^ - -error: aborting due to 1 previous error - From 46cd80b691f0e127076b6dcd1bf9285c3e608d4a Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 25 Apr 2024 16:14:22 -0300 Subject: [PATCH 03/12] Test that unsafe extern defines unsafe fns --- .../extern-items-unsafe.edition2021.stderr | 11 ++++++++++ .../extern-items-unsafe.edition2024.stderr | 11 ++++++++++ .../extern-items-unsafe.rs | 21 +++++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2021.stderr create mode 100644 tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2024.stderr create mode 100644 tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.rs diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2021.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2021.stderr new file mode 100644 index 0000000000000..a94f8d7423609 --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2021.stderr @@ -0,0 +1,11 @@ +error[E0133]: call to unsafe function `test1` is unsafe and requires unsafe function or block + --> $DIR/extern-items-unsafe.rs:11:5 + | +LL | test1(i); + | ^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2024.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2024.stderr new file mode 100644 index 0000000000000..c187dac1152b2 --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2024.stderr @@ -0,0 +1,11 @@ +error[E0133]: call to unsafe function `test1` is unsafe and requires unsafe block + --> $DIR/extern-items-unsafe.rs:11:5 + | +LL | test1(i); + | ^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.rs b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.rs new file mode 100644 index 0000000000000..70f3c0afe7c91 --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.rs @@ -0,0 +1,21 @@ +//@ revisions: edition2021 edition2024 +//@[edition2021] edition:2021 +//@[edition2024] edition:2024 +//@[edition2024] compile-flags: -Zunstable-options + +unsafe extern "C" { + fn test1(i: i32); +} + +fn test2(i: i32) { + test1(i); + //~^ ERROR: call to unsafe function `test1` is unsafe +} + +fn test3(i: i32) { + unsafe { + test1(i); + } +} + +fn main() {} From 3ba8de0b601ee1eaae710510ee8b0b8a9dbd78d8 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 21 May 2024 12:27:21 -0300 Subject: [PATCH 04/12] Make extern blocks without unsafe warn in edition 2024 --- .../rustc_ast_passes/src/ast_validation.rs | 15 +++++++-- compiler/rustc_lint/messages.ftl | 2 ++ .../rustc_lint/src/context/diagnostics.rs | 3 ++ compiler/rustc_lint/src/lints.rs | 4 +++ compiler/rustc_lint_defs/src/builtin.rs | 31 +++++++++++++++++++ compiler/rustc_lint_defs/src/lib.rs | 1 + .../extern-items.edition2024.stderr | 14 +++++++++ .../unsafe-extern-blocks/extern-items.rs | 7 ++++- tests/ui/unpretty/expanded-exhaustive.rs | 4 +-- tests/ui/unpretty/expanded-exhaustive.stdout | 4 +-- 10 files changed, 78 insertions(+), 7 deletions(-) create mode 100644 tests/ui/rust-2024/unsafe-extern-blocks/extern-items.edition2024.stderr diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index c0011fd9c45e5..7e1094da20297 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -15,7 +15,8 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_feature::Features; use rustc_parse::validate_attr; use rustc_session::lint::builtin::{ - DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY, + DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, MISSING_UNSAFE_ON_EXTERN, + PATTERNS_IN_FNS_WITHOUT_BODY, }; use rustc_session::lint::{BuiltinLintDiag, LintBuffer}; use rustc_session::Session; @@ -1016,12 +1017,22 @@ impl<'a> Visitor<'a> for AstValidator<'a> { walk_list!(self, visit_attribute, &item.attrs); return; // Avoid visiting again. } - ItemKind::ForeignMod(ForeignMod { abi, .. }) => { + ItemKind::ForeignMod(ForeignMod { abi, safety, .. }) => { let old_item = mem::replace(&mut self.extern_mod, Some(item)); self.visibility_not_permitted( &item.vis, errors::VisibilityNotPermittedNote::IndividualForeignItems, ); + + if &Safety::Default == safety { + self.lint_buffer.buffer_lint( + MISSING_UNSAFE_ON_EXTERN, + item.id, + item.span, + BuiltinLintDiag::MissingUnsafeOnExtern, + ); + } + if abi.is_none() { self.maybe_lint_missing_abi(item.span, item.id); } diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index fb71cb6014026..bb6ad7c945b27 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -462,6 +462,8 @@ lint_metavariable_wrong_operator = meta-variable repeats with different Kleene o lint_missing_fragment_specifier = missing fragment specifier +lint_missing_unsafe_on_extern = extern blocks should be unsafe + lint_mixed_script_confusables = the usage of Script Group `{$set}` in this crate consists solely of mixed script confusables .includes_note = the usage includes {$includes} diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs index 26f34486a3de4..f824e02dcf9db 100644 --- a/compiler/rustc_lint/src/context/diagnostics.rs +++ b/compiler/rustc_lint/src/context/diagnostics.rs @@ -205,6 +205,9 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: & }; lints::DeprecatedWhereClauseLocation { suggestion }.decorate_lint(diag); } + BuiltinLintDiag::MissingUnsafeOnExtern => { + lints::MissingUnsafeOnExtern.decorate_lint(diag); + } BuiltinLintDiag::SingleUseLifetime { param_span, use_span: Some((use_span, elide)), diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 84d46ef3b65d5..01b455c588ba9 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2738,6 +2738,10 @@ pub enum DeprecatedWhereClauseLocationSugg { }, } +#[derive(LintDiagnostic)] +#[diag(lint_missing_unsafe_on_extern)] +pub struct MissingUnsafeOnExtern; + #[derive(LintDiagnostic)] #[diag(lint_single_use_lifetime)] pub struct SingleUseLifetime { diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index a3044489fdced..b4a34b1407da8 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -66,6 +66,7 @@ declare_lint_pass! { META_VARIABLE_MISUSE, MISSING_ABI, MISSING_FRAGMENT_SPECIFIER, + MISSING_UNSAFE_ON_EXTERN, MUST_NOT_SUSPEND, NAMED_ARGUMENTS_USED_POSITIONALLY, NEVER_TYPE_FALLBACK_FLOWING_INTO_UNSAFE, @@ -4851,3 +4852,33 @@ declare_lint! { reference: "issue #27970 ", }; } + +declare_lint! { + /// The `missing_unsafe_on_extern` lint detects missing unsafe keyword on extern declarations. + /// + /// ### Example + /// + /// ```rust,edition2024 + /// extern "C" { + /// fn foo(_: i32); + /// } + /// + /// fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Declaring extern items, even without ever using them, can cause Undefined Behavior. We + /// should consider all sources of Undefined Behavior to be unsafe. + /// + /// This is a [future-incompatible] lint to transition this to a + /// hard error in the future. + /// + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub MISSING_UNSAFE_ON_EXTERN, + Allow, + "detects missing unsafe keyword on extern declarations", + @edition Edition2024 => Warn; +} diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index c8a9fb02bf2e2..0f13046923eb3 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -630,6 +630,7 @@ pub enum BuiltinLintDiag { UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>), UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>), DeprecatedWhereclauseLocation(Span, Option<(Span, String)>), + MissingUnsafeOnExtern, SingleUseLifetime { /// Span of the parameter which declares this lifetime. param_span: Span, diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.edition2024.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.edition2024.stderr new file mode 100644 index 0000000000000..b19369c0a5515 --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.edition2024.stderr @@ -0,0 +1,14 @@ +warning: extern blocks should be unsafe + --> $DIR/extern-items.rs:7:1 + | +LL | / extern "C" { +LL | | +LL | | static TEST1: i32; +LL | | fn test1(i: i32); +LL | | } + | |_^ + | + = note: `#[warn(missing_unsafe_on_extern)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.rs b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.rs index fd2cd29fd748f..dfb851e276d4a 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.rs +++ b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.rs @@ -1,6 +1,11 @@ -//@ build-pass +//@ revisions: edition2021 edition2024 +//@[edition2021] edition:2021 +//@[edition2024] edition:2024 +//@[edition2024] compile-flags: -Zunstable-options +//@ check-pass extern "C" { + //[edition2024]~^ WARN extern blocks should be unsafe [missing_unsafe_on_extern] static TEST1: i32; fn test1(i: i32); } diff --git a/tests/ui/unpretty/expanded-exhaustive.rs b/tests/ui/unpretty/expanded-exhaustive.rs index 6aa032d7ed83e..29472df897a1f 100644 --- a/tests/ui/unpretty/expanded-exhaustive.rs +++ b/tests/ui/unpretty/expanded-exhaustive.rs @@ -473,8 +473,8 @@ mod items { /// ItemKind::ForeignMod mod item_foreign_mod { - extern "C++" {} - extern {} + unsafe extern "C++" {} + unsafe extern {} } /// ItemKind::GlobalAsm diff --git a/tests/ui/unpretty/expanded-exhaustive.stdout b/tests/ui/unpretty/expanded-exhaustive.stdout index 8737063bf3cc7..0a09a3f6a4233 100644 --- a/tests/ui/unpretty/expanded-exhaustive.stdout +++ b/tests/ui/unpretty/expanded-exhaustive.stdout @@ -451,8 +451,8 @@ mod items { mod item_mod { } /// ItemKind::ForeignMod mod item_foreign_mod { - extern "C++" {} - extern {} + unsafe extern "C++" {} + unsafe extern {} } /// ItemKind::GlobalAsm mod item_global_asm { From bbddc9b58f3b2fcf1b624c2d0cabd49461f94575 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 26 Apr 2024 18:35:54 -0300 Subject: [PATCH 05/12] Allow using unsafe on functions inside extern blocks --- .../rustc_ast_passes/src/ast_validation.rs | 6 +----- tests/ui/parser/fn-header-semantic-fail.rs | 6 +++--- .../ui/parser/fn-header-semantic-fail.stderr | 20 +----------------- .../ui/parser/no-const-fn-in-extern-block.rs | 1 - .../parser/no-const-fn-in-extern-block.stderr | 11 +--------- tests/ui/parser/unsafe-foreign-mod-2.rs | 1 - tests/ui/parser/unsafe-foreign-mod-2.stderr | 11 +--------- .../unsafe-items.edition2021.stderr | 11 ++++++++++ .../unsafe-items.edition2024.stderr | 11 ++++++++++ .../unsafe-extern-blocks/unsafe-items.rs | 21 +++++++++++++++++++ 10 files changed, 50 insertions(+), 49 deletions(-) create mode 100644 tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2021.stderr create mode 100644 tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2024.stderr create mode 100644 tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.rs diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 7e1094da20297..b405e88856114 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -519,7 +519,7 @@ impl<'a> AstValidator<'a> { fn check_foreign_fn_headerless( &self, // Deconstruct to ensure exhaustiveness - FnHeader { safety, coroutine_kind, constness, ext }: FnHeader, + FnHeader { safety: _, coroutine_kind, constness, ext }: FnHeader, ) { let report_err = |span| { self.dcx().emit_err(errors::FnQualifierInExtern { @@ -527,10 +527,6 @@ impl<'a> AstValidator<'a> { block: self.current_extern_span(), }); }; - match safety { - Safety::Unsafe(span) => report_err(span), - Safety::Default => (), - } match coroutine_kind { Some(knd) => report_err(knd.span()), None => (), diff --git a/tests/ui/parser/fn-header-semantic-fail.rs b/tests/ui/parser/fn-header-semantic-fail.rs index 6ed173b6854db..3b98433cdd828 100644 --- a/tests/ui/parser/fn-header-semantic-fail.rs +++ b/tests/ui/parser/fn-header-semantic-fail.rs @@ -44,11 +44,11 @@ fn main() { extern "C" { async fn fe1(); //~ ERROR functions in `extern` blocks cannot have qualifiers - unsafe fn fe2(); //~ ERROR functions in `extern` blocks cannot have qualifiers + unsafe fn fe2(); const fn fe3(); //~ ERROR functions in `extern` blocks cannot have qualifiers extern "C" fn fe4(); //~ ERROR functions in `extern` blocks cannot have qualifiers - const async unsafe extern "C" fn fe5(); //~ ERROR functions in `extern` blocks - //~| ERROR functions in `extern` blocks + const async unsafe extern "C" fn fe5(); + //~^ ERROR functions in `extern` blocks //~| ERROR functions in `extern` blocks //~| ERROR functions in `extern` blocks //~| ERROR functions cannot be both `const` and `async` diff --git a/tests/ui/parser/fn-header-semantic-fail.stderr b/tests/ui/parser/fn-header-semantic-fail.stderr index cfc54839eb752..dc2a216754d26 100644 --- a/tests/ui/parser/fn-header-semantic-fail.stderr +++ b/tests/ui/parser/fn-header-semantic-fail.stderr @@ -78,15 +78,6 @@ LL | extern "C" { LL | async fn fe1(); | ^^^^^ help: remove this qualifier -error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:47:9 - | -LL | extern "C" { - | ---------- in this `extern` block -LL | async fn fe1(); -LL | unsafe fn fe2(); - | ^^^^^^ help: remove this qualifier - error: functions in `extern` blocks cannot have qualifiers --> $DIR/fn-header-semantic-fail.rs:48:9 | @@ -105,15 +96,6 @@ LL | extern "C" { LL | extern "C" fn fe4(); | ^^^^^^^^^^ help: remove this qualifier -error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:50:21 - | -LL | extern "C" { - | ---------- in this `extern` block -... -LL | const async unsafe extern "C" fn fe5(); - | ^^^^^^ help: remove this qualifier - error: functions in `extern` blocks cannot have qualifiers --> $DIR/fn-header-semantic-fail.rs:50:15 | @@ -150,6 +132,6 @@ LL | const async unsafe extern "C" fn fe5(); | | `async` because of this | `const` because of this -error: aborting due to 17 previous errors +error: aborting due to 15 previous errors For more information about this error, try `rustc --explain E0379`. diff --git a/tests/ui/parser/no-const-fn-in-extern-block.rs b/tests/ui/parser/no-const-fn-in-extern-block.rs index d6c578681ccc7..1993124edc394 100644 --- a/tests/ui/parser/no-const-fn-in-extern-block.rs +++ b/tests/ui/parser/no-const-fn-in-extern-block.rs @@ -3,7 +3,6 @@ extern "C" { //~^ ERROR functions in `extern` blocks cannot have qualifiers const unsafe fn bar(); //~^ ERROR functions in `extern` blocks cannot have qualifiers - //~| ERROR functions in `extern` blocks cannot have qualifiers } fn main() {} diff --git a/tests/ui/parser/no-const-fn-in-extern-block.stderr b/tests/ui/parser/no-const-fn-in-extern-block.stderr index 948ce669112c3..2dec6f7693108 100644 --- a/tests/ui/parser/no-const-fn-in-extern-block.stderr +++ b/tests/ui/parser/no-const-fn-in-extern-block.stderr @@ -6,15 +6,6 @@ LL | extern "C" { LL | const fn foo(); | ^^^^^ help: remove this qualifier -error: functions in `extern` blocks cannot have qualifiers - --> $DIR/no-const-fn-in-extern-block.rs:4:11 - | -LL | extern "C" { - | ---------- in this `extern` block -... -LL | const unsafe fn bar(); - | ^^^^^^ help: remove this qualifier - error: functions in `extern` blocks cannot have qualifiers --> $DIR/no-const-fn-in-extern-block.rs:4:5 | @@ -24,5 +15,5 @@ LL | extern "C" { LL | const unsafe fn bar(); | ^^^^^ help: remove this qualifier -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/parser/unsafe-foreign-mod-2.rs b/tests/ui/parser/unsafe-foreign-mod-2.rs index c0994090eff48..6d339cd90881f 100644 --- a/tests/ui/parser/unsafe-foreign-mod-2.rs +++ b/tests/ui/parser/unsafe-foreign-mod-2.rs @@ -1,7 +1,6 @@ extern "C" unsafe { //~^ ERROR expected `{`, found keyword `unsafe` unsafe fn foo(); - //~^ ERROR functions in `extern` blocks cannot have qualifiers } fn main() {} diff --git a/tests/ui/parser/unsafe-foreign-mod-2.stderr b/tests/ui/parser/unsafe-foreign-mod-2.stderr index 620d042540ec1..0625e3362ed72 100644 --- a/tests/ui/parser/unsafe-foreign-mod-2.stderr +++ b/tests/ui/parser/unsafe-foreign-mod-2.stderr @@ -4,14 +4,5 @@ error: expected `{`, found keyword `unsafe` LL | extern "C" unsafe { | ^^^^^^ expected `{` -error: functions in `extern` blocks cannot have qualifiers - --> $DIR/unsafe-foreign-mod-2.rs:3:5 - | -LL | extern "C" unsafe { - | ----------------- in this `extern` block -LL | -LL | unsafe fn foo(); - | ^^^^^^ help: remove this qualifier - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2021.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2021.stderr new file mode 100644 index 0000000000000..67e582c7c565d --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2021.stderr @@ -0,0 +1,11 @@ +error[E0133]: call to unsafe function `test1` is unsafe and requires unsafe function or block + --> $DIR/unsafe-items.rs:17:5 + | +LL | test1(i); + | ^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2024.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2024.stderr new file mode 100644 index 0000000000000..8a9410f8f135e --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2024.stderr @@ -0,0 +1,11 @@ +error[E0133]: call to unsafe function `test1` is unsafe and requires unsafe block + --> $DIR/unsafe-items.rs:17:5 + | +LL | test1(i); + | ^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.rs b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.rs new file mode 100644 index 0000000000000..4b6d077e98773 --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.rs @@ -0,0 +1,21 @@ +//@ revisions: edition2021 edition2024 +//@[edition2021] edition:2021 +//@[edition2024] edition:2024 +//@[edition2024] compile-flags: -Zunstable-options + +unsafe extern "C" { + unsafe fn test1(i: i32); +} + +fn test2(i: i32) { + unsafe { + test1(i); + } +} + +fn test3(i: i32) { + test1(i); + //~^ ERROR: call to unsafe function `test1` is unsafe +} + +fn main() {} From 2a377122dd41291747153ac82289e34a72275138 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 23 May 2024 10:01:05 -0300 Subject: [PATCH 06/12] Handle safety keyword for extern block inner items --- compiler/rustc_ast/src/ast.rs | 4 +++ compiler/rustc_ast/src/mut_visit.rs | 8 +++++- compiler/rustc_ast/src/token.rs | 2 ++ compiler/rustc_ast/src/visit.rs | 7 +++++- compiler/rustc_ast_lowering/src/item.rs | 25 +++++++++++++------ compiler/rustc_ast_lowering/src/lib.rs | 2 +- .../rustc_ast_passes/src/ast_validation.rs | 2 +- compiler/rustc_ast_pretty/src/pprust/state.rs | 1 + .../rustc_ast_pretty/src/pprust/state/item.rs | 8 +++++- compiler/rustc_hir/src/hir.rs | 14 +++++------ compiler/rustc_hir/src/intravisit.rs | 6 +++-- .../rustc_hir_analysis/src/check/check.rs | 2 +- .../rustc_hir_analysis/src/check/intrinsic.rs | 2 +- compiler/rustc_hir_analysis/src/collect.rs | 9 ++++--- .../src/collect/resolve_bound_vars.rs | 2 +- .../rustc_hir_analysis/src/collect/type_of.rs | 2 +- .../rustc_hir_analysis/src/hir_wf_check.rs | 2 +- compiler/rustc_hir_pretty/src/lib.rs | 7 +++--- compiler/rustc_lint/src/types.rs | 6 ++--- compiler/rustc_middle/src/hir/map/mod.rs | 2 +- compiler/rustc_middle/src/hir/mod.rs | 2 +- compiler/rustc_parse/src/parser/item.rs | 21 ++++++++++++++-- compiler/rustc_parse/src/parser/mod.rs | 2 ++ compiler/rustc_resolve/src/def_collector.rs | 9 ++++--- compiler/rustc_span/src/symbol.rs | 1 + src/librustdoc/clean/mod.rs | 8 ++++-- .../clippy/clippy_utils/src/ast_utils.rs | 4 ++- src/tools/rustfmt/src/utils.rs | 1 + tests/pretty/hir-fn-variadic.pp | 2 +- tests/ui/async-await/no-async-const.rs | 2 +- tests/ui/async-await/no-async-const.stderr | 4 +-- tests/ui/coroutine/async_gen_fn.none.stderr | 4 +-- tests/ui/coroutine/async_gen_fn.rs | 2 +- tests/ui/coroutine/gen_fn.none.stderr | 4 +-- tests/ui/coroutine/gen_fn.rs | 2 +- tests/ui/parser/duplicate-visibility.rs | 4 +-- tests/ui/parser/duplicate-visibility.stderr | 4 +-- tests/ui/parser/issues/issue-76437-async.rs | 2 +- .../ui/parser/issues/issue-76437-async.stderr | 4 +-- .../parser/issues/issue-76437-const-async.rs | 2 +- .../issues/issue-76437-const-async.stderr | 4 +-- tests/ui/parser/issues/issue-76437-const.rs | 2 +- .../ui/parser/issues/issue-76437-const.stderr | 4 +-- tests/ui/parser/issues/issue-86895.rs | 2 +- tests/ui/parser/issues/issue-86895.stderr | 4 +-- .../const-async-const.rs | 4 +-- .../const-async-const.stderr | 4 +-- .../issues/issue-87694-duplicated-pub.rs | 4 +-- .../issues/issue-87694-duplicated-pub.stderr | 4 +-- .../issues/issue-87694-misplaced-pub.rs | 4 +-- .../issues/issue-87694-misplaced-pub.stderr | 4 +-- .../unsafe-extern-blocks/safe-items.rs | 15 +++++++++++ 52 files changed, 168 insertions(+), 84 deletions(-) create mode 100644 tests/ui/rust-2024/unsafe-extern-blocks/safe-items.rs diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 7a45d909d0779..042c31fc70f74 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2501,6 +2501,8 @@ pub enum IsAuto { pub enum Safety { /// `unsafe` an item is explicitly marked as `unsafe`. Unsafe(Span), + /// `safe` an item is explicitly marked as `safe`. + Safe(Span), /// Default means no value was provided, it will take a default value given the context in /// which is used. Default, @@ -3171,6 +3173,7 @@ pub struct StaticItem { #[derive(Clone, Encodable, Decodable, Debug)] pub struct StaticForeignItem { pub ty: P, + pub safety: Safety, pub mutability: Mutability, pub expr: Option>, } @@ -3179,6 +3182,7 @@ impl From for StaticForeignItem { fn from(static_item: StaticItem) -> StaticForeignItem { StaticForeignItem { ty: static_item.ty, + safety: Safety::Default, mutability: static_item.mutability, expr: static_item.expr, } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 5c581c270e498..c6814df28400c 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -862,6 +862,7 @@ fn visit_defaultness(defaultness: &mut Defaultness, vis: &mut T) fn visit_safety(safety: &mut Safety, vis: &mut T) { match safety { Safety::Unsafe(span) => vis.visit_span(span), + Safety::Safe(span) => vis.visit_span(span), Safety::Default => {} } } @@ -1289,7 +1290,12 @@ pub fn noop_flat_map_item( impl NoopVisitItemKind for ForeignItemKind { fn noop_visit(&mut self, visitor: &mut impl MutVisitor) { match self { - ForeignItemKind::Static(box StaticForeignItem { ty, mutability: _, expr }) => { + ForeignItemKind::Static(box StaticForeignItem { + ty, + mutability: _, + expr, + safety: _, + }) => { visitor.visit_ty(ty); visit_opt(expr, |expr| visitor.visit_expr(expr)); } diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 099a6096d0b5d..109c401bb6a20 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -210,6 +210,7 @@ pub fn ident_can_begin_expr(name: Symbol, span: Span, is_raw: IdentIsRaw) -> boo kw::Unsafe, kw::While, kw::Yield, + kw::Safe, kw::Static, ] .contains(&name) @@ -577,6 +578,7 @@ impl Token { kw::Impl, kw::Unsafe, kw::Const, + kw::Safe, kw::Static, kw::Union, kw::Macro, diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index b2f3b27c77e90..ccf9f99757e36 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -658,7 +658,12 @@ impl WalkItemKind for ForeignItemKind { ) -> V::Result { let &Item { id, span, ident, ref vis, .. } = item; match self { - ForeignItemKind::Static(box StaticForeignItem { ty, mutability: _, expr }) => { + ForeignItemKind::Static(box StaticForeignItem { + ty, + mutability: _, + expr, + safety: _, + }) => { try_visit!(visitor.visit_ty(ty)); visit_opt!(visitor, visit_expr, expr); } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index a15449409df3a..70bf74e5234dd 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -388,7 +388,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ImplPolarity::Negative(s) => ImplPolarity::Negative(self.lower_span(*s)), }; hir::ItemKind::Impl(self.arena.alloc(hir::Impl { - safety: self.lower_safety(*safety), + safety: self.lower_safety(*safety, hir::Safety::Safe), polarity, defaultness, defaultness_span, @@ -418,7 +418,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let items = this.arena.alloc_from_iter( items.iter().map(|item| this.lower_trait_item_ref(item)), ); - let safety = this.lower_safety(*safety); + let safety = this.lower_safety(*safety, hir::Safety::Safe); (safety, items, bounds) }, ); @@ -660,13 +660,21 @@ impl<'hir> LoweringContext<'_, 'hir> { this.lower_fn_params_to_names(fdec), ) }); + let safety = self.lower_safety(sig.header.safety, hir::Safety::Unsafe); - hir::ForeignItemKind::Fn(fn_dec, fn_args, generics) + hir::ForeignItemKind::Fn(fn_dec, fn_args, generics, safety) } - ForeignItemKind::Static(box StaticForeignItem { ty, mutability, expr: _ }) => { + ForeignItemKind::Static(box StaticForeignItem { + ty, + mutability, + expr: _, + safety, + }) => { let ty = self .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy)); - hir::ForeignItemKind::Static(ty, *mutability) + let safety = self.lower_safety(*safety, hir::Safety::Unsafe); + + hir::ForeignItemKind::Static(ty, *mutability, safety) } ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type, ForeignItemKind::MacCall(_) => panic!("macro shouldn't exist here"), @@ -1360,7 +1368,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::IsAsync::NotAsync }; hir::FnHeader { - safety: self.lower_safety(h.safety), + safety: self.lower_safety(h.safety, hir::Safety::Safe), asyncness: asyncness, constness: self.lower_constness(h.constness), abi: self.lower_extern(h.ext), @@ -1410,10 +1418,11 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - pub(super) fn lower_safety(&mut self, s: Safety) -> hir::Safety { + pub(super) fn lower_safety(&mut self, s: Safety, default: hir::Safety) -> hir::Safety { match s { Safety::Unsafe(_) => hir::Safety::Unsafe, - Safety::Default => hir::Safety::Safe, + Safety::Default => default, + Safety::Safe(_) => hir::Safety::Safe, } } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 5a80fa803f840..023dc6d52c3eb 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1321,7 +1321,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let generic_params = self.lower_lifetime_binder(t.id, &f.generic_params); hir::TyKind::BareFn(self.arena.alloc(hir::BareFnTy { generic_params, - safety: self.lower_safety(f.safety), + safety: self.lower_safety(f.safety, hir::Safety::Safe), abi: self.lower_extern(f.ext), decl: self.lower_fn_decl(&f.decl, t.id, t.span, FnDeclKind::Pointer, None), param_names: self.lower_fn_params_to_names(&f.decl), diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index b405e88856114..29097f7f6afdf 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1184,7 +1184,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.check_foreign_ty_genericless(generics, where_clauses); self.check_foreign_item_ascii_only(fi.ident); } - ForeignItemKind::Static(box StaticForeignItem { ty: _, mutability: _, expr }) => { + ForeignItemKind::Static(box StaticForeignItem { expr, .. }) => { self.check_foreign_kind_bodyless(fi.ident, "static", expr.as_ref().map(|b| b.span)); self.check_foreign_item_ascii_only(fi.ident); } diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 4c29ca0ca4652..ca26b436b82ed 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1973,6 +1973,7 @@ impl<'a> State<'a> { fn print_safety(&mut self, s: ast::Safety) { match s { ast::Safety::Default => {} + ast::Safety::Safe(_) => self.word_nbsp("safe"), ast::Safety::Unsafe(_) => self.word_nbsp("unsafe"), } } diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 59d9b0c1a8ecd..5855972e8c5ae 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -31,7 +31,13 @@ impl<'a> State<'a> { ast::ForeignItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => { self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs); } - ast::ForeignItemKind::Static(box ast::StaticForeignItem { ty, mutability, expr }) => { + ast::ForeignItemKind::Static(box ast::StaticForeignItem { + ty, + mutability, + expr, + safety, + }) => { + self.print_safety(*safety); self.print_item_const( ident, Some(*mutability), diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index e971d0e3c1435..770dfcb98c917 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3475,9 +3475,9 @@ impl ForeignItem<'_> { #[derive(Debug, Clone, Copy, HashStable_Generic)] pub enum ForeignItemKind<'hir> { /// A foreign function. - Fn(&'hir FnDecl<'hir>, &'hir [Ident], &'hir Generics<'hir>), + Fn(&'hir FnDecl<'hir>, &'hir [Ident], &'hir Generics<'hir>, Safety), /// A foreign static item (`static ext: u8`). - Static(&'hir Ty<'hir>, Mutability), + Static(&'hir Ty<'hir>, Mutability, Safety), /// A foreign type. Type, } @@ -3545,7 +3545,7 @@ impl<'hir> OwnerNode<'hir> { | OwnerNode::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. }) | OwnerNode::Item(Item { kind: ItemKind::Fn(fn_sig, _, _), .. }) => Some(fn_sig.decl), OwnerNode::ForeignItem(ForeignItem { - kind: ForeignItemKind::Fn(fn_decl, _, _), + kind: ForeignItemKind::Fn(fn_decl, _, _, _), .. }) => Some(fn_decl), _ => None, @@ -3728,9 +3728,9 @@ impl<'hir> Node<'hir> { | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. }) | Node::Item(Item { kind: ItemKind::Fn(fn_sig, _, _), .. }) => Some(fn_sig.decl), Node::Expr(Expr { kind: ExprKind::Closure(Closure { fn_decl, .. }), .. }) - | Node::ForeignItem(ForeignItem { kind: ForeignItemKind::Fn(fn_decl, _, _), .. }) => { - Some(fn_decl) - } + | Node::ForeignItem(ForeignItem { + kind: ForeignItemKind::Fn(fn_decl, _, _, _), .. + }) => Some(fn_decl), _ => None, } } @@ -3813,7 +3813,7 @@ impl<'hir> Node<'hir> { pub fn generics(self) -> Option<&'hir Generics<'hir>> { match self { Node::ForeignItem(ForeignItem { - kind: ForeignItemKind::Fn(_, _, generics), .. + kind: ForeignItemKind::Fn(_, _, generics, _), .. }) | Node::TraitItem(TraitItem { generics, .. }) | Node::ImplItem(ImplItem { generics, .. }) => Some(generics), diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 9bc2bbe0c6471..e37473df956d0 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -608,12 +608,14 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>( try_visit!(visitor.visit_ident(foreign_item.ident)); match foreign_item.kind { - ForeignItemKind::Fn(ref function_declaration, param_names, ref generics) => { + ForeignItemKind::Fn(ref function_declaration, param_names, ref generics, _) => { try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_fn_decl(function_declaration)); walk_list!(visitor, visit_ident, param_names.iter().copied()); } - ForeignItemKind::Static(ref typ, _) => try_visit!(visitor.visit_ty(typ)), + ForeignItemKind::Static(ref typ, _, _) => { + try_visit!(visitor.visit_ty(typ)); + } ForeignItemKind::Type => (), } V::Result::output() diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 76b6cbd6e5310..8a0623ef93e37 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -801,7 +801,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { let item = tcx.hir().foreign_item(item.id); match &item.kind { - hir::ForeignItemKind::Fn(fn_decl, _, _) => { + hir::ForeignItemKind::Fn(fn_decl, _, _, _) => { require_c_abi_if_c_variadic(tcx, fn_decl, abi, item.span); } hir::ForeignItemKind::Static(..) => { diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index f7989aeab41bb..13180fa2673ba 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -29,7 +29,7 @@ fn equate_intrinsic_type<'tcx>( let (own_counts, span) = match tcx.hir_node_by_def_id(def_id) { hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. }) | hir::Node::ForeignItem(hir::ForeignItem { - kind: hir::ForeignItemKind::Fn(.., generics), + kind: hir::ForeignItemKind::Fn(.., generics, _), .. }) => { let own_counts = tcx.generics_of(def_id).own_counts(); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 7e7460061484e..43e0b945f3420 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1321,9 +1321,11 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn icx.lowerer().lower_fn_ty(hir_id, header.safety, header.abi, decl, Some(generics), None) } - ForeignItem(&hir::ForeignItem { kind: ForeignItemKind::Fn(fn_decl, _, _), .. }) => { + ForeignItem(&hir::ForeignItem { + kind: ForeignItemKind::Fn(fn_decl, _, _, safety), .. + }) => { let abi = tcx.hir().get_foreign_abi(hir_id); - compute_sig_of_foreign_fn_decl(tcx, def_id, fn_decl, abi) + compute_sig_of_foreign_fn_decl(tcx, def_id, fn_decl, abi, safety) } Ctor(data) | Variant(hir::Variant { data, .. }) if data.ctor().is_some() => { @@ -1695,11 +1697,12 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( def_id: LocalDefId, decl: &'tcx hir::FnDecl<'tcx>, abi: abi::Abi, + safety: hir::Safety, ) -> ty::PolyFnSig<'tcx> { let safety = if abi == abi::Abi::RustIntrinsic { intrinsic_operation_unsafety(tcx, def_id) } else { - hir::Safety::Unsafe + safety }; let hir_id = tcx.local_def_id_to_hir_id(def_id); let fty = diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index c1850f78f2fb2..abc3bb838db3e 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -603,7 +603,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { match item.kind { - hir::ForeignItemKind::Fn(_, _, generics) => { + hir::ForeignItemKind::Fn(_, _, generics, _) => { self.visit_early_late(item.hir_id(), generics, |this| { intravisit::walk_foreign_item(this, item); }) diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 71b08e2937699..6811f62de07b7 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -464,7 +464,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ let args = ty::GenericArgs::identity_for_item(tcx, def_id); Ty::new_fn_def(tcx, def_id.to_def_id(), args) } - ForeignItemKind::Static(t, _) => icx.lower_ty(t), + ForeignItemKind::Static(t, _, _) => icx.lower_ty(t), ForeignItemKind::Type => Ty::new_foreign(tcx, def_id.to_def_id()), }, diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index 3e15fddf559f3..13993a1992b7c 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -158,7 +158,7 @@ fn diagnostic_hir_wf_check<'tcx>( }, hir::Node::Field(field) => vec![field.ty], hir::Node::ForeignItem(ForeignItem { - kind: ForeignItemKind::Static(ty, _), .. + kind: ForeignItemKind::Static(ty, _, _), .. }) => vec![*ty], hir::Node::GenericParam(hir::GenericParam { kind: hir::GenericParamKind::Type { default: Some(ty), .. }, diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index a8e0b3fc0793d..6983bbcb052c2 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -345,12 +345,12 @@ impl<'a> State<'a> { self.maybe_print_comment(item.span.lo()); self.print_outer_attributes(self.attrs(item.hir_id())); match item.kind { - hir::ForeignItemKind::Fn(decl, arg_names, generics) => { + hir::ForeignItemKind::Fn(decl, arg_names, generics, safety) => { self.head(""); self.print_fn( decl, hir::FnHeader { - safety: hir::Safety::Safe, + safety, constness: hir::Constness::NotConst, abi: Abi::Rust, asyncness: hir::IsAsync::NotAsync, @@ -364,7 +364,8 @@ impl<'a> State<'a> { self.word(";"); self.end() // end the outer fn box } - hir::ForeignItemKind::Static(t, m) => { + hir::ForeignItemKind::Static(t, m, safety) => { + self.print_safety(safety); self.head("static"); if m.is_mut() { self.word_space("mut"); diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 9d3a838666aff..f3a904022e9ed 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1741,13 +1741,13 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDeclarations { let abi = cx.tcx.hir().get_foreign_abi(it.hir_id()); match it.kind { - hir::ForeignItemKind::Fn(decl, _, _) if !vis.is_internal_abi(abi) => { + hir::ForeignItemKind::Fn(decl, _, _, _) if !vis.is_internal_abi(abi) => { vis.check_foreign_fn(it.owner_id.def_id, decl); } - hir::ForeignItemKind::Static(ty, _) if !vis.is_internal_abi(abi) => { + hir::ForeignItemKind::Static(ty, _, _) if !vis.is_internal_abi(abi) => { vis.check_foreign_static(it.owner_id, ty.span); } - hir::ForeignItemKind::Fn(decl, _, _) => vis.check_fn(it.owner_id.def_id, decl), + hir::ForeignItemKind::Fn(decl, _, _, _) => vis.check_fn(it.owner_id.def_id, decl), hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => (), } } diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 639c98155e705..c7431f377ac3e 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -886,7 +886,7 @@ impl<'hir> Map<'hir> { Node::Variant(variant) => named_span(variant.span, variant.ident, None), Node::ImplItem(item) => named_span(item.span, item.ident, Some(item.generics)), Node::ForeignItem(item) => match item.kind { - ForeignItemKind::Fn(decl, _, _) => until_within(item.span, decl.output.span()), + ForeignItemKind::Fn(decl, _, _, _) => until_within(item.span, decl.output.span()), _ => named_span(item.span, item.ident, None), }, Node::Ctor(_) => return self.span(self.tcx.parent_hir_id(hir_id)), diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index b0c14cdfec938..57c8ba96a20a7 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -201,7 +201,7 @@ pub fn provide(providers: &mut Providers) { .. }) | Node::ForeignItem(&ForeignItem { - kind: ForeignItemKind::Fn(_, idents, _), + kind: ForeignItemKind::Fn(_, idents, _, _), .. }) = tcx.hir_node(tcx.local_def_id_to_hir_id(def_id)) { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 53757c38e8b04..4989985bb10cd 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1221,6 +1221,7 @@ impl<'a> Parser<'a> { ty, mutability: Mutability::Not, expr, + safety: Safety::Default, })) } _ => return self.error_bad_item_kind(span, &kind, "`extern` blocks"), @@ -2400,9 +2401,9 @@ impl<'a> Parser<'a> { // `pub` is added in case users got confused with the ordering like `async pub fn`, // only if it wasn't preceded by `default` as `default pub` is invalid. let quals: &[Symbol] = if check_pub { - &[kw::Pub, kw::Gen, kw::Const, kw::Async, kw::Unsafe, kw::Extern] + &[kw::Pub, kw::Gen, kw::Const, kw::Async, kw::Unsafe, kw::Safe, kw::Extern] } else { - &[kw::Gen, kw::Const, kw::Async, kw::Unsafe, kw::Extern] + &[kw::Gen, kw::Const, kw::Async, kw::Unsafe, kw::Safe, kw::Extern] }; self.check_keyword_case(kw::Fn, case) // Definitely an `fn`. // `$qual fn` or `$qual $qual`: @@ -2537,11 +2538,27 @@ impl<'a> Parser<'a> { } else if self.check_keyword(kw::Unsafe) { match safety { Safety::Unsafe(sp) => Some(WrongKw::Duplicated(sp)), + Safety::Safe(sp) => { + recover_safety = Safety::Unsafe(self.token.span); + Some(WrongKw::Misplaced(sp)) + } Safety::Default => { recover_safety = Safety::Unsafe(self.token.span); Some(WrongKw::Misplaced(ext_start_sp)) } } + } else if self.check_keyword(kw::Safe) { + match safety { + Safety::Safe(sp) => Some(WrongKw::Duplicated(sp)), + Safety::Unsafe(sp) => { + recover_safety = Safety::Safe(self.token.span); + Some(WrongKw::Misplaced(sp)) + } + Safety::Default => { + recover_safety = Safety::Safe(self.token.span); + Some(WrongKw::Misplaced(ext_start_sp)) + } + } } else { None }; diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index bab8b6c06ebee..8f733b4fcbbcd 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1221,6 +1221,8 @@ impl<'a> Parser<'a> { fn parse_safety(&mut self, case: Case) -> Safety { if self.eat_keyword_case(kw::Unsafe, case) { Safety::Unsafe(self.prev_token.uninterpolated_span()) + } else if self.eat_keyword_case(kw::Safe, case) { + Safety::Safe(self.prev_token.uninterpolated_span()) } else { Safety::Default } diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index cad10571afe62..6d506059ad859 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -211,9 +211,12 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { fn visit_foreign_item(&mut self, fi: &'a ForeignItem) { let def_kind = match fi.kind { - ForeignItemKind::Static(box StaticForeignItem { ty: _, mutability, expr: _ }) => { - DefKind::Static { mutability, nested: false } - } + ForeignItemKind::Static(box StaticForeignItem { + ty: _, + mutability, + expr: _, + safety: _, + }) => DefKind::Static { mutability, nested: false }, ForeignItemKind::Fn(_) => DefKind::Fn, ForeignItemKind::TyAlias(_) => DefKind::ForeignTy, ForeignItemKind::MacCall(_) => return self.visit_macro_invoc(fi.id), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 61ca0d54ca490..ede9b852ba84f 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -103,6 +103,7 @@ symbols! { MacroRules: "macro_rules", Raw: "raw", Reuse: "reuse", + Safe: "safe", Union: "union", Yeet: "yeet", } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 839bfdf44af19..59e8dc678d0fd 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -3089,7 +3089,9 @@ fn clean_maybe_renamed_foreign_item<'tcx>( let def_id = item.owner_id.to_def_id(); cx.with_param_env(def_id, |cx| { let kind = match item.kind { - hir::ForeignItemKind::Fn(decl, names, generics) => { + // FIXME(missing_unsafe_on_extern) handle safety of foreign fns. + // Safety was added as part of the implementation of unsafe extern blocks PR #124482 + hir::ForeignItemKind::Fn(decl, names, generics, _) => { let (generics, decl) = enter_impl_trait(cx, |cx| { // NOTE: generics must be cleaned before args let generics = clean_generics(generics, cx); @@ -3099,7 +3101,9 @@ fn clean_maybe_renamed_foreign_item<'tcx>( }); ForeignFunctionItem(Box::new(Function { decl, generics })) } - hir::ForeignItemKind::Static(ty, mutability) => { + // FIXME(missing_unsafe_on_extern) handle safety of foreign statics. + // Safety was added as part of the implementation of unsafe extern blocks PR #124482 + hir::ForeignItemKind::Static(ty, mutability, _) => { ForeignStaticItem(Static { type_: clean_ty(ty, cx), mutability, expr: None }) } hir::ForeignItemKind::Type => ForeignTypeItem, diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index bbdde3049dbd3..14f9ef8966d6a 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs @@ -451,13 +451,15 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool { ty: lt, mutability: lm, expr: le, + safety: ls, }), Static(box StaticForeignItem { ty: rt, mutability: rm, expr: re, + safety: rs, }), - ) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re), + ) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re) && ls == rs, ( Fn(box ast::Fn { defaultness: ld, diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs index 09e1dbde1d05e..fd59aedadfed5 100644 --- a/src/tools/rustfmt/src/utils.rs +++ b/src/tools/rustfmt/src/utils.rs @@ -111,6 +111,7 @@ pub(crate) fn format_defaultness(defaultness: ast::Defaultness) -> &'static str pub(crate) fn format_safety(unsafety: ast::Safety) -> &'static str { match unsafety { ast::Safety::Unsafe(..) => "unsafe ", + ast::Safety::Safe(..) => "safe ", ast::Safety::Default => "", } } diff --git a/tests/pretty/hir-fn-variadic.pp b/tests/pretty/hir-fn-variadic.pp index 978e65c825bb3..dfbaff696440b 100644 --- a/tests/pretty/hir-fn-variadic.pp +++ b/tests/pretty/hir-fn-variadic.pp @@ -9,7 +9,7 @@ extern crate std; extern "C" { - fn foo(x: i32, va1: ...); + unsafe fn foo(x: i32, va1: ...); } unsafe extern "C" fn bar(_: i32, mut va2: ...) -> usize { va2.arg::() } diff --git a/tests/ui/async-await/no-async-const.rs b/tests/ui/async-await/no-async-const.rs index c5485ebc9b624..38a5df3576bb0 100644 --- a/tests/ui/async-await/no-async-const.rs +++ b/tests/ui/async-await/no-async-const.rs @@ -2,5 +2,5 @@ //@ compile-flags: --crate-type lib pub async const fn x() {} -//~^ ERROR expected one of `extern`, `fn`, or `unsafe`, found keyword `const` +//~^ ERROR expected one of `extern`, `fn`, `safe`, or `unsafe`, found keyword `const` //~| ERROR functions cannot be both `const` and `async` diff --git a/tests/ui/async-await/no-async-const.stderr b/tests/ui/async-await/no-async-const.stderr index 524d778c09b85..d692ba8f47375 100644 --- a/tests/ui/async-await/no-async-const.stderr +++ b/tests/ui/async-await/no-async-const.stderr @@ -1,10 +1,10 @@ -error: expected one of `extern`, `fn`, or `unsafe`, found keyword `const` +error: expected one of `extern`, `fn`, `safe`, or `unsafe`, found keyword `const` --> $DIR/no-async-const.rs:4:11 | LL | pub async const fn x() {} | ------^^^^^ | | | - | | expected one of `extern`, `fn`, or `unsafe` + | | expected one of `extern`, `fn`, `safe`, or `unsafe` | help: `const` must come before `async`: `const async` | = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern` diff --git a/tests/ui/coroutine/async_gen_fn.none.stderr b/tests/ui/coroutine/async_gen_fn.none.stderr index 7950251a75daa..047f4d82486d8 100644 --- a/tests/ui/coroutine/async_gen_fn.none.stderr +++ b/tests/ui/coroutine/async_gen_fn.none.stderr @@ -7,11 +7,11 @@ LL | async gen fn foo() {} = help: pass `--edition 2021` to `rustc` = note: for more on editions, read https://doc.rust-lang.org/edition-guide -error: expected one of `extern`, `fn`, or `unsafe`, found `gen` +error: expected one of `extern`, `fn`, `safe`, or `unsafe`, found `gen` --> $DIR/async_gen_fn.rs:4:7 | LL | async gen fn foo() {} - | ^^^ expected one of `extern`, `fn`, or `unsafe` + | ^^^ expected one of `extern`, `fn`, `safe`, or `unsafe` error: aborting due to 2 previous errors diff --git a/tests/ui/coroutine/async_gen_fn.rs b/tests/ui/coroutine/async_gen_fn.rs index 9e96ecf3ea69f..e8be0434b9ef9 100644 --- a/tests/ui/coroutine/async_gen_fn.rs +++ b/tests/ui/coroutine/async_gen_fn.rs @@ -3,7 +3,7 @@ async gen fn foo() {} //[none]~^ ERROR: `async fn` is not permitted in Rust 2015 -//[none]~| ERROR: expected one of `extern`, `fn`, or `unsafe`, found `gen` +//[none]~| ERROR: expected one of `extern`, `fn`, `safe`, or `unsafe`, found `gen` //[e2024]~^^^ ERROR: gen blocks are experimental fn main() {} diff --git a/tests/ui/coroutine/gen_fn.none.stderr b/tests/ui/coroutine/gen_fn.none.stderr index c5342ee22e62f..590210641aed4 100644 --- a/tests/ui/coroutine/gen_fn.none.stderr +++ b/tests/ui/coroutine/gen_fn.none.stderr @@ -1,8 +1,8 @@ -error: expected one of `#`, `async`, `const`, `default`, `extern`, `fn`, `pub`, `unsafe`, or `use`, found `gen` +error: expected one of `#`, `async`, `const`, `default`, `extern`, `fn`, `pub`, `safe`, `unsafe`, or `use`, found `gen` --> $DIR/gen_fn.rs:4:1 | LL | gen fn foo() {} - | ^^^ expected one of 9 possible tokens + | ^^^ expected one of 10 possible tokens error: aborting due to 1 previous error diff --git a/tests/ui/coroutine/gen_fn.rs b/tests/ui/coroutine/gen_fn.rs index 3228650f41524..d47b7e576d002 100644 --- a/tests/ui/coroutine/gen_fn.rs +++ b/tests/ui/coroutine/gen_fn.rs @@ -2,7 +2,7 @@ //@[e2024] compile-flags: --edition 2024 -Zunstable-options gen fn foo() {} -//[none]~^ ERROR: expected one of `#`, `async`, `const`, `default`, `extern`, `fn`, `pub`, `unsafe`, or `use`, found `gen` +//[none]~^ ERROR: expected one of `#`, `async`, `const`, `default`, `extern`, `fn`, `pub`, `safe`, `unsafe`, or `use`, found `gen` //[e2024]~^^ ERROR: gen blocks are experimental fn main() {} diff --git a/tests/ui/parser/duplicate-visibility.rs b/tests/ui/parser/duplicate-visibility.rs index 54955944c7d35..f0ee60873da01 100644 --- a/tests/ui/parser/duplicate-visibility.rs +++ b/tests/ui/parser/duplicate-visibility.rs @@ -2,8 +2,8 @@ fn main() {} extern "C" { //~ NOTE while parsing this item list starting here pub pub fn foo(); - //~^ ERROR expected one of `(`, `async`, `const`, `default`, `extern`, `fn`, `unsafe`, or `use`, found keyword `pub` - //~| NOTE expected one of 8 possible tokens + //~^ ERROR expected one of `(`, `async`, `const`, `default`, `extern`, `fn`, `safe`, `unsafe`, or `use`, found keyword `pub` + //~| NOTE expected one of 9 possible tokens //~| HELP there is already a visibility modifier, remove one //~| NOTE explicit visibility first seen here } //~ NOTE the item list ends here diff --git a/tests/ui/parser/duplicate-visibility.stderr b/tests/ui/parser/duplicate-visibility.stderr index b578b1fe26e8d..0d1421ee7f4e4 100644 --- a/tests/ui/parser/duplicate-visibility.stderr +++ b/tests/ui/parser/duplicate-visibility.stderr @@ -1,4 +1,4 @@ -error: expected one of `(`, `async`, `const`, `default`, `extern`, `fn`, `unsafe`, or `use`, found keyword `pub` +error: expected one of `(`, `async`, `const`, `default`, `extern`, `fn`, `safe`, `unsafe`, or `use`, found keyword `pub` --> $DIR/duplicate-visibility.rs:4:9 | LL | extern "C" { @@ -6,7 +6,7 @@ LL | extern "C" { LL | pub pub fn foo(); | ^^^ | | - | expected one of 8 possible tokens + | expected one of 9 possible tokens | help: there is already a visibility modifier, remove one ... LL | } diff --git a/tests/ui/parser/issues/issue-76437-async.rs b/tests/ui/parser/issues/issue-76437-async.rs index 497e269d634e5..3fafaad0277c5 100644 --- a/tests/ui/parser/issues/issue-76437-async.rs +++ b/tests/ui/parser/issues/issue-76437-async.rs @@ -2,6 +2,6 @@ mod t { async pub fn t() {} - //~^ ERROR expected one of `extern`, `fn`, or `unsafe`, found keyword `pub` + //~^ ERROR expected one of `extern`, `fn`, `safe`, or `unsafe`, found keyword `pub` //~| HELP visibility `pub` must come before `async` } diff --git a/tests/ui/parser/issues/issue-76437-async.stderr b/tests/ui/parser/issues/issue-76437-async.stderr index 7f2df5c873643..483599135f566 100644 --- a/tests/ui/parser/issues/issue-76437-async.stderr +++ b/tests/ui/parser/issues/issue-76437-async.stderr @@ -1,10 +1,10 @@ -error: expected one of `extern`, `fn`, or `unsafe`, found keyword `pub` +error: expected one of `extern`, `fn`, `safe`, or `unsafe`, found keyword `pub` --> $DIR/issue-76437-async.rs:4:11 | LL | async pub fn t() {} | ------^^^ | | | - | | expected one of `extern`, `fn`, or `unsafe` + | | expected one of `extern`, `fn`, `safe`, or `unsafe` | help: visibility `pub` must come before `async`: `pub async` error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-76437-const-async.rs b/tests/ui/parser/issues/issue-76437-const-async.rs index 45d53c6393321..d8eb6cdecf1b1 100644 --- a/tests/ui/parser/issues/issue-76437-const-async.rs +++ b/tests/ui/parser/issues/issue-76437-const-async.rs @@ -2,6 +2,6 @@ mod t { const async pub fn t() {} - //~^ ERROR expected one of `extern`, `fn`, or `unsafe`, found keyword `pub` + //~^ ERROR expected one of `extern`, `fn`, `safe`, or `unsafe`, found keyword `pub` //~| HELP visibility `pub` must come before `const async` } diff --git a/tests/ui/parser/issues/issue-76437-const-async.stderr b/tests/ui/parser/issues/issue-76437-const-async.stderr index a9acccdce1824..81fa8a5f557e0 100644 --- a/tests/ui/parser/issues/issue-76437-const-async.stderr +++ b/tests/ui/parser/issues/issue-76437-const-async.stderr @@ -1,10 +1,10 @@ -error: expected one of `extern`, `fn`, or `unsafe`, found keyword `pub` +error: expected one of `extern`, `fn`, `safe`, or `unsafe`, found keyword `pub` --> $DIR/issue-76437-const-async.rs:4:17 | LL | const async pub fn t() {} | ------------^^^ | | | - | | expected one of `extern`, `fn`, or `unsafe` + | | expected one of `extern`, `fn`, `safe`, or `unsafe` | help: visibility `pub` must come before `const async`: `pub const async` error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-76437-const.rs b/tests/ui/parser/issues/issue-76437-const.rs index c3431e3567bf3..dad63f137c0f4 100644 --- a/tests/ui/parser/issues/issue-76437-const.rs +++ b/tests/ui/parser/issues/issue-76437-const.rs @@ -2,6 +2,6 @@ mod t { const pub fn t() {} - //~^ ERROR expected one of `async`, `extern`, `fn`, or `unsafe`, found keyword `pub` + //~^ ERROR expected one of `async`, `extern`, `fn`, `safe`, or `unsafe`, found keyword `pub` //~| HELP visibility `pub` must come before `const` } diff --git a/tests/ui/parser/issues/issue-76437-const.stderr b/tests/ui/parser/issues/issue-76437-const.stderr index 4c36d773d60e6..005a27b7c2498 100644 --- a/tests/ui/parser/issues/issue-76437-const.stderr +++ b/tests/ui/parser/issues/issue-76437-const.stderr @@ -1,10 +1,10 @@ -error: expected one of `async`, `extern`, `fn`, or `unsafe`, found keyword `pub` +error: expected one of `async`, `extern`, `fn`, `safe`, or `unsafe`, found keyword `pub` --> $DIR/issue-76437-const.rs:4:11 | LL | const pub fn t() {} | ------^^^ | | | - | | expected one of `async`, `extern`, `fn`, or `unsafe` + | | expected one of `async`, `extern`, `fn`, `safe`, or `unsafe` | help: visibility `pub` must come before `const`: `pub const` error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-86895.rs b/tests/ui/parser/issues/issue-86895.rs index 4cd09843107dd..3e5dc41e2f4d0 100644 --- a/tests/ui/parser/issues/issue-86895.rs +++ b/tests/ui/parser/issues/issue-86895.rs @@ -1,3 +1,3 @@ const pub () {} -//~^ ERROR expected one of `async`, `extern`, `fn`, or `unsafe` +//~^ ERROR expected one of `async`, `extern`, `fn`, `safe`, or `unsafe` pub fn main() {} diff --git a/tests/ui/parser/issues/issue-86895.stderr b/tests/ui/parser/issues/issue-86895.stderr index dcde7242d3987..14183ee0a5cf5 100644 --- a/tests/ui/parser/issues/issue-86895.stderr +++ b/tests/ui/parser/issues/issue-86895.stderr @@ -1,8 +1,8 @@ -error: expected one of `async`, `extern`, `fn`, or `unsafe`, found keyword `pub` +error: expected one of `async`, `extern`, `fn`, `safe`, or `unsafe`, found keyword `pub` --> $DIR/issue-86895.rs:1:7 | LL | const pub () {} - | ^^^ expected one of `async`, `extern`, `fn`, or `unsafe` + | ^^^ expected one of `async`, `extern`, `fn`, `safe`, or `unsafe` error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs b/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs index 694729376ba88..e6235b1e8923f 100644 --- a/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs +++ b/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs @@ -3,8 +3,8 @@ // Test that even when `const` is already present, the proposed fix is to remove the second `const` const async const fn test() {} -//~^ ERROR expected one of `extern`, `fn`, or `unsafe`, found keyword `const` -//~| NOTE expected one of `extern`, `fn`, or `unsafe` +//~^ ERROR expected one of `extern`, `fn`, `safe`, or `unsafe`, found keyword `const` +//~| NOTE expected one of `extern`, `fn`, `safe`, or `unsafe` //~| HELP `const` already used earlier, remove this one //~| NOTE `const` first seen here //~| ERROR functions cannot be both `const` and `async` diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.stderr b/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.stderr index 4c55179ce2379..ed2e4d8154929 100644 --- a/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.stderr +++ b/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.stderr @@ -1,10 +1,10 @@ -error: expected one of `extern`, `fn`, or `unsafe`, found keyword `const` +error: expected one of `extern`, `fn`, `safe`, or `unsafe`, found keyword `const` --> $DIR/const-async-const.rs:5:13 | LL | const async const fn test() {} | ^^^^^ | | - | expected one of `extern`, `fn`, or `unsafe` + | expected one of `extern`, `fn`, `safe`, or `unsafe` | help: `const` already used earlier, remove this one | note: `const` first seen here diff --git a/tests/ui/parser/issues/issue-87694-duplicated-pub.rs b/tests/ui/parser/issues/issue-87694-duplicated-pub.rs index e3ea61dc4ada6..816c8ff2a9f5f 100644 --- a/tests/ui/parser/issues/issue-87694-duplicated-pub.rs +++ b/tests/ui/parser/issues/issue-87694-duplicated-pub.rs @@ -1,5 +1,5 @@ pub const pub fn test() {} -//~^ ERROR expected one of `async`, `extern`, `fn`, or `unsafe`, found keyword `pub` -//~| NOTE expected one of `async`, `extern`, `fn`, or `unsafe` +//~^ ERROR expected one of `async`, `extern`, `fn`, `safe`, or `unsafe`, found keyword `pub` +//~| NOTE expected one of `async`, `extern`, `fn`, `safe`, or `unsafe` //~| HELP there is already a visibility modifier, remove one //~| NOTE explicit visibility first seen here diff --git a/tests/ui/parser/issues/issue-87694-duplicated-pub.stderr b/tests/ui/parser/issues/issue-87694-duplicated-pub.stderr index a210238652abb..dd75f32f68ff2 100644 --- a/tests/ui/parser/issues/issue-87694-duplicated-pub.stderr +++ b/tests/ui/parser/issues/issue-87694-duplicated-pub.stderr @@ -1,10 +1,10 @@ -error: expected one of `async`, `extern`, `fn`, or `unsafe`, found keyword `pub` +error: expected one of `async`, `extern`, `fn`, `safe`, or `unsafe`, found keyword `pub` --> $DIR/issue-87694-duplicated-pub.rs:1:11 | LL | pub const pub fn test() {} | ^^^ | | - | expected one of `async`, `extern`, `fn`, or `unsafe` + | expected one of `async`, `extern`, `fn`, `safe`, or `unsafe` | help: there is already a visibility modifier, remove one | note: explicit visibility first seen here diff --git a/tests/ui/parser/issues/issue-87694-misplaced-pub.rs b/tests/ui/parser/issues/issue-87694-misplaced-pub.rs index 3f824617cade1..b5b0bc5b2fc9e 100644 --- a/tests/ui/parser/issues/issue-87694-misplaced-pub.rs +++ b/tests/ui/parser/issues/issue-87694-misplaced-pub.rs @@ -1,5 +1,5 @@ const pub fn test() {} -//~^ ERROR expected one of `async`, `extern`, `fn`, or `unsafe`, found keyword `pub` -//~| NOTE expected one of `async`, `extern`, `fn`, or `unsafe` +//~^ ERROR expected one of `async`, `extern`, `fn`, `safe`, or `unsafe`, found keyword `pub` +//~| NOTE expected one of `async`, `extern`, `fn`, `safe`, or `unsafe` //~| HELP visibility `pub` must come before `const` //~| SUGGESTION pub const diff --git a/tests/ui/parser/issues/issue-87694-misplaced-pub.stderr b/tests/ui/parser/issues/issue-87694-misplaced-pub.stderr index 6f686a7e50437..d35e09dceaf7f 100644 --- a/tests/ui/parser/issues/issue-87694-misplaced-pub.stderr +++ b/tests/ui/parser/issues/issue-87694-misplaced-pub.stderr @@ -1,10 +1,10 @@ -error: expected one of `async`, `extern`, `fn`, or `unsafe`, found keyword `pub` +error: expected one of `async`, `extern`, `fn`, `safe`, or `unsafe`, found keyword `pub` --> $DIR/issue-87694-misplaced-pub.rs:1:7 | LL | const pub fn test() {} | ------^^^ | | | - | | expected one of `async`, `extern`, `fn`, or `unsafe` + | | expected one of `async`, `extern`, `fn`, `safe`, or `unsafe` | help: visibility `pub` must come before `const`: `pub const` error: aborting due to 1 previous error diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-items.rs b/tests/ui/rust-2024/unsafe-extern-blocks/safe-items.rs new file mode 100644 index 0000000000000..c26503a8d1d10 --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-items.rs @@ -0,0 +1,15 @@ +//@ revisions: edition2021 edition2024 +//@[edition2021] edition:2021 +//@[edition2024] edition:2024 +//@[edition2024] compile-flags: -Zunstable-options +//@ check-pass + +unsafe extern "C" { + safe fn test1(i: i32); +} + +fn test2(i: i32) { + test1(i); +} + +fn main() {} From b4cbdb7246c633ab0ebc6ae4bbe4883cde79e787 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Mon, 27 May 2024 15:35:34 -0300 Subject: [PATCH 07/12] Fail when using safe/unsafe items inside unadorned extern blocks --- compiler/rustc_ast_passes/messages.ftl | 3 + .../rustc_ast_passes/src/ast_validation.rs | 66 +++++++++++++------ compiler/rustc_ast_passes/src/errors.rs | 9 +++ tests/ui/parser/fn-header-semantic-fail.rs | 3 +- .../ui/parser/fn-header-semantic-fail.stderr | 20 +++++- .../ui/parser/no-const-fn-in-extern-block.rs | 1 + .../parser/no-const-fn-in-extern-block.stderr | 11 +++- .../safe-unsafe-on-unadorned-extern-block.rs | 10 +++ ...fe-unsafe-on-unadorned-extern-block.stderr | 10 +++ 9 files changed, 111 insertions(+), 22 deletions(-) create mode 100644 tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.rs create mode 100644 tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.stderr diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 3a4c95b250c31..b90b502c22b82 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -67,6 +67,9 @@ ast_passes_extern_fn_qualifiers = functions in `extern` blocks cannot have quali .label = in this `extern` block .suggestion = remove this qualifier +ast_passes_extern_invalid_safety = items in unadorned `extern` blocks cannot have safety qualifiers + .suggestion = add unsafe to this `extern` block + ast_passes_extern_item_ascii = items in `extern` blocks cannot use non-ascii identifiers .label = in this `extern` block .note = this limitation may be lifted in the future; see issue #83942 for more information diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 29097f7f6afdf..a9f06230fafc4 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -87,6 +87,9 @@ struct AstValidator<'a> { /// or `Foo::Bar` is_impl_trait_banned: bool, + /// Used to ban explicit safety on foreign items when the extern block is not marked as unsafe. + extern_mod_safety: Option, + lint_buffer: &'a mut LintBuffer, } @@ -117,6 +120,12 @@ impl<'a> AstValidator<'a> { self.outer_trait_or_trait_impl = old; } + fn with_in_extern_mod(&mut self, extern_mod_safety: Safety, f: impl FnOnce(&mut Self)) { + let old = mem::replace(&mut self.extern_mod_safety, Some(extern_mod_safety)); + f(self); + self.extern_mod_safety = old; + } + fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) { let old = mem::replace(&mut self.is_impl_trait_banned, true); f(self); @@ -430,6 +439,20 @@ impl<'a> AstValidator<'a> { } } + fn check_foreign_item_safety(&self, item_span: Span, safety: Safety) { + match safety { + Safety::Unsafe(_) | Safety::Safe(_) + if self.extern_mod_safety == Some(Safety::Default) => + { + self.dcx().emit_err(errors::InvalidSafetyOnExtern { + item_span, + block: self.current_extern_span(), + }); + } + _ => {} + } + } + fn check_defaultness(&self, span: Span, defaultness: Defaultness) { if let Defaultness::Default(def_span) = defaultness { let span = self.session.source_map().guess_head_span(span); @@ -1014,26 +1037,28 @@ impl<'a> Visitor<'a> for AstValidator<'a> { return; // Avoid visiting again. } ItemKind::ForeignMod(ForeignMod { abi, safety, .. }) => { - let old_item = mem::replace(&mut self.extern_mod, Some(item)); - self.visibility_not_permitted( - &item.vis, - errors::VisibilityNotPermittedNote::IndividualForeignItems, - ); - - if &Safety::Default == safety { - self.lint_buffer.buffer_lint( - MISSING_UNSAFE_ON_EXTERN, - item.id, - item.span, - BuiltinLintDiag::MissingUnsafeOnExtern, + self.with_in_extern_mod(*safety, |this| { + let old_item = mem::replace(&mut this.extern_mod, Some(item)); + this.visibility_not_permitted( + &item.vis, + errors::VisibilityNotPermittedNote::IndividualForeignItems, ); - } - if abi.is_none() { - self.maybe_lint_missing_abi(item.span, item.id); - } - visit::walk_item(self, item); - self.extern_mod = old_item; + if &Safety::Default == safety { + this.lint_buffer.buffer_lint( + MISSING_UNSAFE_ON_EXTERN, + item.id, + item.span, + BuiltinLintDiag::MissingUnsafeOnExtern, + ); + } + + if abi.is_none() { + this.maybe_lint_missing_abi(item.span, item.id); + } + visit::walk_item(this, item); + this.extern_mod = old_item; + }); return; // Avoid visiting again. } ItemKind::Enum(def, _) => { @@ -1165,6 +1190,7 @@ 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); @@ -1184,7 +1210,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.check_foreign_ty_genericless(generics, where_clauses); self.check_foreign_item_ascii_only(fi.ident); } - ForeignItemKind::Static(box StaticForeignItem { expr, .. }) => { + ForeignItemKind::Static(box StaticForeignItem { expr, safety, .. }) => { + self.check_foreign_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); } @@ -1740,6 +1767,7 @@ pub fn check_crate( outer_impl_trait: None, disallow_tilde_const: Some(DisallowTildeConstContext::Item), is_impl_trait_banned: false, + extern_mod_safety: None, lint_buffer: lints, }; visit::walk_crate(&mut validator, krate); diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index c07fbe5b0166e..05e99a3d63613 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -216,6 +216,15 @@ pub enum ExternBlockSuggestion { }, } +#[derive(Diagnostic)] +#[diag(ast_passes_extern_invalid_safety)] +pub struct InvalidSafetyOnExtern { + #[primary_span] + pub item_span: Span, + #[suggestion(code = "", applicability = "maybe-incorrect")] + pub block: Span, +} + #[derive(Diagnostic)] #[diag(ast_passes_bound_in_context)] pub struct BoundInContext<'a> { diff --git a/tests/ui/parser/fn-header-semantic-fail.rs b/tests/ui/parser/fn-header-semantic-fail.rs index 3b98433cdd828..5907ac0526044 100644 --- a/tests/ui/parser/fn-header-semantic-fail.rs +++ b/tests/ui/parser/fn-header-semantic-fail.rs @@ -44,7 +44,7 @@ fn main() { extern "C" { async fn fe1(); //~ ERROR functions in `extern` blocks cannot have qualifiers - unsafe fn fe2(); + unsafe fn fe2(); //~ ERROR items in unadorned `extern` blocks cannot have safety qualifiers const fn fe3(); //~ ERROR functions in `extern` blocks cannot have qualifiers extern "C" fn fe4(); //~ ERROR functions in `extern` blocks cannot have qualifiers const async unsafe extern "C" fn fe5(); @@ -52,5 +52,6 @@ fn main() { //~| ERROR functions in `extern` blocks //~| ERROR functions in `extern` blocks //~| ERROR functions cannot be both `const` and `async` + //~| ERROR items in unadorned `extern` blocks cannot have safety qualifiers } } diff --git a/tests/ui/parser/fn-header-semantic-fail.stderr b/tests/ui/parser/fn-header-semantic-fail.stderr index dc2a216754d26..abaa6527b0aac 100644 --- a/tests/ui/parser/fn-header-semantic-fail.stderr +++ b/tests/ui/parser/fn-header-semantic-fail.stderr @@ -78,6 +78,15 @@ LL | extern "C" { LL | async fn fe1(); | ^^^^^ help: remove this qualifier +error: items in unadorned `extern` blocks cannot have safety qualifiers + --> $DIR/fn-header-semantic-fail.rs:47:9 + | +LL | extern "C" { + | ---------- help: add unsafe to this `extern` block +LL | async fn fe1(); +LL | unsafe fn fe2(); + | ^^^^^^^^^^^^^^^^ + error: functions in `extern` blocks cannot have qualifiers --> $DIR/fn-header-semantic-fail.rs:48:9 | @@ -96,6 +105,15 @@ 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 | @@ -132,6 +150,6 @@ LL | const async unsafe extern "C" fn fe5(); | | `async` because of this | `const` because of this -error: aborting due to 15 previous errors +error: aborting due to 17 previous errors For more information about this error, try `rustc --explain E0379`. diff --git a/tests/ui/parser/no-const-fn-in-extern-block.rs b/tests/ui/parser/no-const-fn-in-extern-block.rs index 1993124edc394..3ad9ba006d3da 100644 --- a/tests/ui/parser/no-const-fn-in-extern-block.rs +++ b/tests/ui/parser/no-const-fn-in-extern-block.rs @@ -3,6 +3,7 @@ extern "C" { //~^ ERROR functions in `extern` blocks cannot have qualifiers const unsafe fn bar(); //~^ ERROR functions in `extern` blocks cannot have qualifiers + //~| ERROR items in unadorned `extern` blocks cannot have safety qualifiers } fn main() {} diff --git a/tests/ui/parser/no-const-fn-in-extern-block.stderr b/tests/ui/parser/no-const-fn-in-extern-block.stderr index 2dec6f7693108..892024ce89340 100644 --- a/tests/ui/parser/no-const-fn-in-extern-block.stderr +++ b/tests/ui/parser/no-const-fn-in-extern-block.stderr @@ -6,6 +6,15 @@ LL | extern "C" { LL | const fn foo(); | ^^^^^ help: remove this qualifier +error: items in unadorned `extern` blocks cannot have safety qualifiers + --> $DIR/no-const-fn-in-extern-block.rs:4:5 + | +LL | extern "C" { + | ---------- help: add unsafe to this `extern` block +... +LL | const unsafe fn bar(); + | ^^^^^^^^^^^^^^^^^^^^^^ + error: functions in `extern` blocks cannot have qualifiers --> $DIR/no-const-fn-in-extern-block.rs:4:5 | @@ -15,5 +24,5 @@ LL | extern "C" { LL | const unsafe fn bar(); | ^^^^^ help: remove this qualifier -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.rs b/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.rs new file mode 100644 index 0000000000000..7c184d092f0de --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.rs @@ -0,0 +1,10 @@ +extern "C" { + safe fn test1(i: i32); + //~^ ERROR items in unadorned `extern` blocks cannot have safety qualifiers +} + +fn test2(i: i32) { + test1(i); +} + +fn main() {} diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.stderr new file mode 100644 index 0000000000000..d96757a17c233 --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.stderr @@ -0,0 +1,10 @@ +error: items in unadorned `extern` blocks cannot have safety qualifiers + --> $DIR/safe-unsafe-on-unadorned-extern-block.rs:2:5 + | +LL | extern "C" { + | ---------- help: add unsafe to this `extern` block +LL | safe fn test1(i: i32); + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + From bac72cf7cf823bbf10e7d093a8225490bf8d1350 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 7 May 2024 14:43:23 +0200 Subject: [PATCH 08/12] Add safe/unsafe to static inside extern blocks --- compiler/rustc_ast/src/ast.rs | 4 +++- compiler/rustc_ast/src/mut_visit.rs | 2 +- compiler/rustc_ast/src/visit.rs | 2 +- compiler/rustc_ast_lowering/src/item.rs | 2 +- .../rustc_ast_pretty/src/pprust/state/item.rs | 3 ++- .../rustc_const_eval/src/interpret/intern.rs | 2 +- .../rustc_const_eval/src/interpret/validity.rs | 4 +++- compiler/rustc_expand/src/build.rs | 5 ++++- compiler/rustc_hir/src/def.rs | 2 ++ compiler/rustc_hir_analysis/src/check/errs.rs | 3 ++- compiler/rustc_metadata/src/rmeta/table.rs | 12 ++++++++---- compiler/rustc_middle/src/hir/map/mod.rs | 4 +++- compiler/rustc_middle/src/mir/pretty.rs | 4 ++-- compiler/rustc_mir_build/src/check_unsafety.rs | 6 +++++- compiler/rustc_parse/src/parser/item.rs | 18 +++++++++++++----- compiler/rustc_resolve/src/def_collector.rs | 18 +++++++++++++++--- .../passes/collect_intra_doc_links.rs | 8 ++++++-- src/tools/clippy/clippy_utils/src/ast_utils.rs | 4 +++- .../extern-items-unsafe.edition2021.stderr | 16 ++++++++++++---- .../extern-items-unsafe.edition2024.stderr | 16 ++++++++++++---- .../extern-items-unsafe.rs | 10 ++++++---- .../unsafe-extern-blocks/safe-items.rs | 5 +++-- .../safe-unsafe-on-unadorned-extern-block.rs | 6 ++++-- ...afe-unsafe-on-unadorned-extern-block.stderr | 11 ++++++++++- .../unsafe-items.edition2021.stderr | 16 ++++++++++++---- .../unsafe-items.edition2024.stderr | 16 ++++++++++++---- .../unsafe-extern-blocks/unsafe-items.rs | 10 ++++++---- 27 files changed, 152 insertions(+), 57 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 042c31fc70f74..910fbb8769741 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3164,6 +3164,7 @@ pub struct DelegationMac { #[derive(Clone, Encodable, Decodable, Debug)] pub struct StaticItem { pub ty: P, + pub safety: Safety, pub mutability: Mutability, pub expr: Option>, } @@ -3182,7 +3183,7 @@ impl From for StaticForeignItem { fn from(static_item: StaticItem) -> StaticForeignItem { StaticForeignItem { ty: static_item.ty, - safety: Safety::Default, + safety: static_item.safety, mutability: static_item.mutability, expr: static_item.expr, } @@ -3193,6 +3194,7 @@ impl From for StaticItem { fn from(static_item: StaticForeignItem) -> StaticItem { StaticItem { ty: static_item.ty, + safety: static_item.safety, mutability: static_item.mutability, expr: static_item.expr, } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index c6814df28400c..a04c648ac731f 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1080,7 +1080,7 @@ impl NoopVisitItemKind for ItemKind { match self { ItemKind::ExternCrate(_orig_name) => {} ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree), - ItemKind::Static(box StaticItem { ty, mutability: _, expr }) => { + ItemKind::Static(box StaticItem { ty, safety: _, mutability: _, expr }) => { vis.visit_ty(ty); visit_opt(expr, |expr| vis.visit_expr(expr)); } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index ccf9f99757e36..de285aed16567 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -334,7 +334,7 @@ impl WalkItemKind for ItemKind { match self { ItemKind::ExternCrate(_) => {} ItemKind::Use(use_tree) => try_visit!(visitor.visit_use_tree(use_tree, item.id, false)), - ItemKind::Static(box StaticItem { ty, mutability: _, expr }) => { + ItemKind::Static(box StaticItem { ty, safety: _, mutability: _, expr }) => { try_visit!(visitor.visit_ty(ty)); visit_opt!(visitor, visit_expr, expr); } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 70bf74e5234dd..8c963e9f8907a 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -181,7 +181,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_use_tree(use_tree, &prefix, id, vis_span, ident, attrs) } - ItemKind::Static(box ast::StaticItem { ty: t, mutability: m, expr: e }) => { + ItemKind::Static(box ast::StaticItem { ty: t, safety: _, mutability: m, expr: e }) => { let (ty, body_id) = self.lower_const_item(t, span, e.as_deref(), ImplTraitPosition::StaticTy); hir::ItemKind::Static(ty, *m, body_id) diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 5855972e8c5ae..474741fb06777 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -171,7 +171,8 @@ impl<'a> State<'a> { self.print_use_tree(tree); self.word(";"); } - ast::ItemKind::Static(box StaticItem { ty, mutability: mutbl, expr: body }) => { + ast::ItemKind::Static(box StaticItem { ty, safety, mutability: mutbl, expr: body }) => { + self.print_safety(*safety); self.print_item_const( item.ident, Some(*mutbl), diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 8d0b267e1a9cc..3066e0933d94d 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -102,7 +102,7 @@ fn intern_as_new_static<'tcx>( let feed = tcx.create_def( static_id, sym::nested, - DefKind::Static { mutability: alloc.0.mutability, nested: true }, + DefKind::Static { safety: hir::Safety::Safe, mutability: alloc.0.mutability, nested: true }, ); tcx.set_nested_alloc_id_static(alloc_id, feed.def_id()); diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index e35ce9ef28d61..3407c7b8c7925 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -711,7 +711,9 @@ fn mutability<'tcx>(ecx: &InterpCx<'tcx, impl Machine<'tcx>>, alloc_id: AllocId) // We're not using `try_global_alloc` since dangling pointers have already been handled. match ecx.tcx.global_alloc(alloc_id) { GlobalAlloc::Static(did) => { - let DefKind::Static { mutability, nested } = ecx.tcx.def_kind(did) else { bug!() }; + let DefKind::Static { safety: _, mutability, nested } = ecx.tcx.def_kind(did) else { + bug!() + }; if nested { assert!( ecx.memory.alloc_map.get(alloc_id).is_none(), diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 1b6e191c2eb09..b3d41908260ed 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -631,7 +631,10 @@ impl<'a> ExtCtxt<'a> { span, name, AttrVec::new(), - ast::ItemKind::Static(ast::StaticItem { ty, mutability, expr: Some(expr) }.into()), + ast::ItemKind::Static( + ast::StaticItem { ty, safety: ast::Safety::Default, mutability, expr: Some(expr) } + .into(), + ), ) } diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 649a08b6972fb..b1854923247f8 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -76,6 +76,8 @@ pub enum DefKind { /// Constant generic parameter: `struct Foo { ... }` ConstParam, Static { + /// Whether it's a `unsafe static`, `safe static` (inside extern only) or just a `static`. + safety: hir::Safety, /// Whether it's a `static mut` or just a `static`. mutability: ast::Mutability, /// Whether it's an anonymous static generated for nested allocations. diff --git a/compiler/rustc_hir_analysis/src/check/errs.rs b/compiler/rustc_hir_analysis/src/check/errs.rs index a49626eed35af..2cdcc06f53c07 100644 --- a/compiler/rustc_hir_analysis/src/check/errs.rs +++ b/compiler/rustc_hir_analysis/src/check/errs.rs @@ -41,7 +41,8 @@ fn path_if_static_mut(tcx: TyCtxt<'_>, expr: &hir::Expr<'_>) -> Option { if let hir::ExprKind::Path(qpath) = expr.kind && let hir::QPath::Resolved(_, path) = qpath && let hir::def::Res::Def(def_kind, _) = path.res - && let hir::def::DefKind::Static { mutability: Mutability::Mut, nested: false } = def_kind + && let hir::def::DefKind::Static { safety: _, mutability: Mutability::Mut, nested: false } = + def_kind { return Some(qpath_to_string(&tcx, &qpath)); } diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index 23a6ceb4d3e5d..dcbddad2dbcad 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -156,10 +156,14 @@ fixed_size_enum! { ( Impl { of_trait: false } ) ( Impl { of_trait: true } ) ( Closure ) - ( Static { mutability: ast::Mutability::Not, nested: false } ) - ( Static { mutability: ast::Mutability::Mut, nested: false } ) - ( Static { mutability: ast::Mutability::Not, nested: true } ) - ( Static { mutability: ast::Mutability::Mut, nested: true } ) + ( Static { safety: hir::Safety::Unsafe, mutability: ast::Mutability::Not, nested: false } ) + ( Static { safety: hir::Safety::Safe, mutability: ast::Mutability::Not, nested: false } ) + ( Static { safety: hir::Safety::Unsafe, mutability: ast::Mutability::Mut, nested: false } ) + ( Static { safety: hir::Safety::Safe, mutability: ast::Mutability::Mut, nested: false } ) + ( Static { safety: hir::Safety::Unsafe, mutability: ast::Mutability::Not, nested: true } ) + ( Static { safety: hir::Safety::Safe, mutability: ast::Mutability::Not, nested: true } ) + ( Static { safety: hir::Safety::Unsafe, mutability: ast::Mutability::Mut, nested: true } ) + ( Static { safety: hir::Safety::Safe, mutability: ast::Mutability::Mut, nested: true } ) ( Ctor(CtorOf::Struct, CtorKind::Fn) ) ( Ctor(CtorOf::Struct, CtorKind::Const) ) ( Ctor(CtorOf::Variant, CtorKind::Fn) ) diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index c7431f377ac3e..0b3423fc1bc0f 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -305,7 +305,9 @@ impl<'hir> Map<'hir> { DefKind::InlineConst => BodyOwnerKind::Const { inline: true }, DefKind::Ctor(..) | DefKind::Fn | DefKind::AssocFn => BodyOwnerKind::Fn, DefKind::Closure => BodyOwnerKind::Closure, - DefKind::Static { mutability, nested: false } => BodyOwnerKind::Static(mutability), + DefKind::Static { safety: _, mutability, nested: false } => { + BodyOwnerKind::Static(mutability) + } dk => bug!("{:?} is not a body node: {:?}", def_id, dk), } } diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index f1c79c0b0391f..978c15f4d73c1 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -559,10 +559,10 @@ fn write_mir_sig(tcx: TyCtxt<'_>, body: &Body<'_>, w: &mut dyn io::Write) -> io: match (kind, body.source.promoted) { (_, Some(_)) => write!(w, "const ")?, // promoteds are the closest to consts (DefKind::Const | DefKind::AssocConst, _) => write!(w, "const ")?, - (DefKind::Static { mutability: hir::Mutability::Not, nested: false }, _) => { + (DefKind::Static { safety: _, mutability: hir::Mutability::Not, nested: false }, _) => { write!(w, "static ")? } - (DefKind::Static { mutability: hir::Mutability::Mut, nested: false }, _) => { + (DefKind::Static { safety: _, mutability: hir::Mutability::Mut, nested: false }, _) => { write!(w, "static mut ")? } (_, _) if is_function => write!(w, "fn ")?, diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 659ae1724603a..5517fc3fd9427 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -2,6 +2,7 @@ use crate::build::ExprCategory; use crate::errors::*; use rustc_errors::DiagArgValue; +use rustc_hir::def::DefKind; use rustc_hir::{self as hir, BindingMode, ByRef, HirId, Mutability}; use rustc_middle::mir::BorrowKind; use rustc_middle::span_bug; @@ -456,7 +457,10 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { if self.tcx.is_mutable_static(def_id) { self.requires_unsafe(expr.span, UseOfMutableStatic); } else if self.tcx.is_foreign_item(def_id) { - self.requires_unsafe(expr.span, UseOfExternStatic); + match self.tcx.def_kind(def_id) { + DefKind::Static { safety: hir::Safety::Safe, .. } => {} + _ => self.requires_unsafe(expr.span, UseOfExternStatic), + } } } else if self.thir[arg].ty.is_unsafe_ptr() { self.requires_unsafe(expr.span, DerefOfRawPointer); diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 4989985bb10cd..37c99958fc88b 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -226,10 +226,11 @@ impl<'a> Parser<'a> { self.expect_keyword(kw::Extern)?; self.parse_item_foreign_mod(attrs, safety)? } else if self.is_static_global() { + let safety = self.parse_safety(Case::Sensitive); // STATIC ITEM self.bump(); // `static` let mutability = self.parse_mutability(); - let (ident, item) = self.parse_static_item(mutability)?; + let (ident, item) = self.parse_static_item(safety, mutability)?; (ident, ItemKind::Static(Box::new(item))) } else if let Const::Yes(const_span) = self.parse_constness(Case::Sensitive) { // CONST ITEM @@ -952,7 +953,7 @@ impl<'a> Parser<'a> { let kind = match AssocItemKind::try_from(kind) { Ok(kind) => kind, Err(kind) => match kind { - ItemKind::Static(box StaticItem { ty, mutability: _, expr }) => { + ItemKind::Static(box StaticItem { ty, safety: _, mutability: _, expr }) => { self.dcx().emit_err(errors::AssociatedStaticItemNotAllowed { span }); AssocItemKind::Const(Box::new(ConstItem { defaultness: Defaultness::Final, @@ -1259,7 +1260,10 @@ impl<'a> Parser<'a> { matches!(token.kind, token::BinOp(token::Or) | token::OrOr) }) } else { - false + let quals: &[Symbol] = &[kw::Unsafe, kw::Safe]; + // `$qual static` + quals.iter().any(|&kw| self.check_keyword(kw)) + && self.look_ahead(1, |t| t.is_keyword(kw::Static)) } } @@ -1320,7 +1324,11 @@ impl<'a> Parser<'a> { /// ```ebnf /// Static = "static" "mut"? $ident ":" $ty (= $expr)? ";" ; /// ``` - fn parse_static_item(&mut self, mutability: Mutability) -> PResult<'a, (Ident, StaticItem)> { + fn parse_static_item( + &mut self, + safety: Safety, + mutability: Mutability, + ) -> PResult<'a, (Ident, StaticItem)> { let ident = self.parse_ident()?; if self.token.kind == TokenKind::Lt && self.may_recover() { @@ -1341,7 +1349,7 @@ impl<'a> Parser<'a> { self.expect_semi()?; - Ok((ident, StaticItem { ty, mutability, expr })) + Ok((ident, StaticItem { ty, safety, mutability, expr })) } /// Parse a constant item with the prefix `"const"` already parsed. diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 6d506059ad859..d7416ead325dd 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -2,6 +2,7 @@ use crate::{ImplTraitContext, Resolver}; use rustc_ast::visit::FnKind; use rustc_ast::*; use rustc_expand::expand::AstFragment; +use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind}; use rustc_hir::def_id::LocalDefId; use rustc_span::hygiene::LocalExpnId; @@ -128,7 +129,11 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { ItemKind::Union(..) => DefKind::Union, ItemKind::ExternCrate(..) => DefKind::ExternCrate, ItemKind::TyAlias(..) => DefKind::TyAlias, - ItemKind::Static(s) => DefKind::Static { mutability: s.mutability, nested: false }, + ItemKind::Static(s) => DefKind::Static { + safety: hir::Safety::Safe, + mutability: s.mutability, + nested: false, + }, ItemKind::Const(..) => DefKind::Const, ItemKind::Fn(..) | ItemKind::Delegation(..) => DefKind::Fn, ItemKind::MacroDef(..) => { @@ -215,8 +220,15 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { ty: _, mutability, expr: _, - safety: _, - }) => DefKind::Static { mutability, nested: false }, + safety, + }) => { + let safety = match safety { + ast::Safety::Unsafe(_) | ast::Safety::Default => hir::Safety::Unsafe, + ast::Safety::Safe(_) => hir::Safety::Safe, + }; + + DefKind::Static { safety, mutability, nested: false } + } ForeignItemKind::Fn(_) => DefKind::Fn, ForeignItemKind::TyAlias(_) => DefKind::ForeignTy, ForeignItemKind::MacCall(_) => return self.visit_macro_invoc(fi.id), diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 8ab24a8c12e58..440b02a1fa75b 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -12,7 +12,7 @@ use rustc_errors::{Applicability, Diag, DiagMessage}; use rustc_hir::def::Namespace::*; use rustc_hir::def::{DefKind, Namespace, PerNS}; use rustc_hir::def_id::{DefId, CRATE_DEF_ID}; -use rustc_hir::Mutability; +use rustc_hir::{Mutability, Safety}; use rustc_middle::ty::{Ty, TyCtxt}; use rustc_middle::{bug, span_bug, ty}; use rustc_resolve::rustdoc::{has_primitive_or_keyword_docs, prepare_to_doc_link_resolution}; @@ -1517,7 +1517,11 @@ impl Disambiguator { "union" => Kind(DefKind::Union), "module" | "mod" => Kind(DefKind::Mod), "const" | "constant" => Kind(DefKind::Const), - "static" => Kind(DefKind::Static { mutability: Mutability::Not, nested: false }), + "static" => Kind(DefKind::Static { + mutability: Mutability::Not, + nested: false, + safety: Safety::Safe, + }), "function" | "fn" | "method" => Kind(DefKind::Fn), "derive" => Kind(DefKind::Macro(MacroKind::Derive)), "type" => NS(Namespace::TypeNS), diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index 14f9ef8966d6a..c70f5c2df8420 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs @@ -308,13 +308,15 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { ty: lt, mutability: lm, expr: le, + safety: ls, }), Static(box StaticItem { ty: rt, mutability: rm, expr: re, + safety: rs, }), - ) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re), + ) => lm == rm && ls == rs && eq_ty(lt, rt) && eq_expr_opt(le, re), ( Const(box ConstItem { defaultness: ld, diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2021.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2021.stderr index a94f8d7423609..77554da10e60b 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2021.stderr +++ b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2021.stderr @@ -1,11 +1,19 @@ error[E0133]: call to unsafe function `test1` is unsafe and requires unsafe function or block - --> $DIR/extern-items-unsafe.rs:11:5 + --> $DIR/extern-items-unsafe.rs:12:5 | -LL | test1(i); - | ^^^^^^^^ call to unsafe function +LL | test1(TEST1); + | ^^^^^^^^^^^^ call to unsafe function | = note: consult the function's documentation for information on how to avoid undefined behavior -error: aborting due to 1 previous error +error[E0133]: use of extern static is unsafe and requires unsafe function or block + --> $DIR/extern-items-unsafe.rs:12:11 + | +LL | test1(TEST1); + | ^^^^^ use of extern static + | + = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2024.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2024.stderr index c187dac1152b2..33b752782d599 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2024.stderr +++ b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2024.stderr @@ -1,11 +1,19 @@ error[E0133]: call to unsafe function `test1` is unsafe and requires unsafe block - --> $DIR/extern-items-unsafe.rs:11:5 + --> $DIR/extern-items-unsafe.rs:12:5 | -LL | test1(i); - | ^^^^^^^^ call to unsafe function +LL | test1(TEST1); + | ^^^^^^^^^^^^ call to unsafe function | = note: consult the function's documentation for information on how to avoid undefined behavior -error: aborting due to 1 previous error +error[E0133]: use of extern static is unsafe and requires unsafe block + --> $DIR/extern-items-unsafe.rs:12:11 + | +LL | test1(TEST1); + | ^^^^^ use of extern static + | + = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.rs b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.rs index 70f3c0afe7c91..721e07acca588 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.rs +++ b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.rs @@ -4,17 +4,19 @@ //@[edition2024] compile-flags: -Zunstable-options unsafe extern "C" { + static TEST1: i32; fn test1(i: i32); } -fn test2(i: i32) { - test1(i); +fn test2() { + test1(TEST1); //~^ ERROR: call to unsafe function `test1` is unsafe + //~| ERROR: use of extern static is unsafe } -fn test3(i: i32) { +fn test3() { unsafe { - test1(i); + test1(TEST1); } } diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-items.rs b/tests/ui/rust-2024/unsafe-extern-blocks/safe-items.rs index c26503a8d1d10..b0b8a8b012a6a 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/safe-items.rs +++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-items.rs @@ -5,11 +5,12 @@ //@ check-pass unsafe extern "C" { + safe static TEST1: i32; safe fn test1(i: i32); } -fn test2(i: i32) { - test1(i); +fn test2() { + test1(TEST1); } fn main() {} diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.rs b/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.rs index 7c184d092f0de..d37a7be452da5 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.rs +++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.rs @@ -1,10 +1,12 @@ extern "C" { + safe static TEST1: i32; + //~^ ERROR items in unadorned `extern` blocks cannot have safety qualifiers safe fn test1(i: i32); //~^ ERROR items in unadorned `extern` blocks cannot have safety qualifiers } -fn test2(i: i32) { - test1(i); +fn test2() { + test1(TEST1); } fn main() {} diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.stderr index d96757a17c233..66624f1fcb16f 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.stderr +++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.stderr @@ -3,8 +3,17 @@ error: items in unadorned `extern` blocks cannot have safety qualifiers | LL | extern "C" { | ---------- help: add unsafe to this `extern` block +LL | safe static TEST1: i32; + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: items in unadorned `extern` blocks cannot have safety qualifiers + --> $DIR/safe-unsafe-on-unadorned-extern-block.rs:4:5 + | +LL | extern "C" { + | ---------- help: add unsafe to this `extern` block +... LL | safe fn test1(i: i32); | ^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 1 previous error +error: aborting due to 2 previous errors diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2021.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2021.stderr index 67e582c7c565d..e3626bb497e4f 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2021.stderr +++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2021.stderr @@ -1,11 +1,19 @@ error[E0133]: call to unsafe function `test1` is unsafe and requires unsafe function or block - --> $DIR/unsafe-items.rs:17:5 + --> $DIR/unsafe-items.rs:18:5 | -LL | test1(i); - | ^^^^^^^^ call to unsafe function +LL | test1(TEST1); + | ^^^^^^^^^^^^ call to unsafe function | = note: consult the function's documentation for information on how to avoid undefined behavior -error: aborting due to 1 previous error +error[E0133]: use of extern static is unsafe and requires unsafe function or block + --> $DIR/unsafe-items.rs:18:11 + | +LL | test1(TEST1); + | ^^^^^ use of extern static + | + = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2024.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2024.stderr index 8a9410f8f135e..89bc501b7b5a5 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2024.stderr +++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2024.stderr @@ -1,11 +1,19 @@ error[E0133]: call to unsafe function `test1` is unsafe and requires unsafe block - --> $DIR/unsafe-items.rs:17:5 + --> $DIR/unsafe-items.rs:18:5 | -LL | test1(i); - | ^^^^^^^^ call to unsafe function +LL | test1(TEST1); + | ^^^^^^^^^^^^ call to unsafe function | = note: consult the function's documentation for information on how to avoid undefined behavior -error: aborting due to 1 previous error +error[E0133]: use of extern static is unsafe and requires unsafe block + --> $DIR/unsafe-items.rs:18:11 + | +LL | test1(TEST1); + | ^^^^^ use of extern static + | + = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.rs b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.rs index 4b6d077e98773..dc2bae892a988 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.rs +++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.rs @@ -4,18 +4,20 @@ //@[edition2024] compile-flags: -Zunstable-options unsafe extern "C" { + unsafe static TEST1: i32; unsafe fn test1(i: i32); } -fn test2(i: i32) { +fn test2() { unsafe { - test1(i); + test1(TEST1); } } -fn test3(i: i32) { - test1(i); +fn test3() { + test1(TEST1); //~^ ERROR: call to unsafe function `test1` is unsafe + //~| ERROR: use of extern static is unsafe } fn main() {} From 0380321e7806bdab232d7e95be2de47fad8f3c09 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 31 May 2024 16:57:07 -0300 Subject: [PATCH 09/12] Add unsafe_extern_blocks feature flag --- .../rustc_ast_passes/src/ast_validation.rs | 36 ++++++++++--------- compiler/rustc_feature/src/unstable.rs | 2 ++ compiler/rustc_lint_defs/src/builtin.rs | 7 ++-- compiler/rustc_span/src/symbol.rs | 1 + .../feature-gate-unsafe-extern-blocks.rs | 5 +++ .../feature-gate-unsafe-extern-blocks.stderr | 8 +++++ tests/ui/parser/unsafe-foreign-mod-2.rs | 2 ++ tests/ui/parser/unsafe-foreign-mod-2.stderr | 17 ++++++++- tests/ui/parser/unsafe-foreign-mod.rs | 6 ++-- tests/ui/parser/unsafe-foreign-mod.stderr | 8 +++++ .../extern-items-unsafe.edition2021.stderr | 4 +-- .../extern-items-unsafe.edition2024.stderr | 4 +-- .../extern-items-unsafe.rs | 2 ++ .../extern-items.edition2024.stderr | 8 ++--- .../unsafe-extern-blocks/extern-items.rs | 6 ++-- .../unsafe-extern-blocks/safe-items.rs | 2 ++ .../unsafe-items.edition2021.stderr | 4 +-- .../unsafe-items.edition2024.stderr | 4 +-- .../unsafe-extern-blocks/unsafe-items.rs | 2 ++ tests/ui/unpretty/expanded-exhaustive.rs | 1 + tests/ui/unpretty/expanded-exhaustive.stdout | 1 + 21 files changed, 93 insertions(+), 37 deletions(-) create mode 100644 tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.rs create mode 100644 tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.stderr create mode 100644 tests/ui/parser/unsafe-foreign-mod.stderr diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index a9f06230fafc4..dc554ba04dfe5 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -440,16 +440,14 @@ impl<'a> AstValidator<'a> { } fn check_foreign_item_safety(&self, item_span: Span, safety: Safety) { - match safety { - Safety::Unsafe(_) | Safety::Safe(_) - if self.extern_mod_safety == Some(Safety::Default) => - { - self.dcx().emit_err(errors::InvalidSafetyOnExtern { - item_span, - block: self.current_extern_span(), - }); - } - _ => {} + 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(), + }); } } @@ -1044,13 +1042,17 @@ impl<'a> Visitor<'a> for AstValidator<'a> { errors::VisibilityNotPermittedNote::IndividualForeignItems, ); - if &Safety::Default == safety { - this.lint_buffer.buffer_lint( - MISSING_UNSAFE_ON_EXTERN, - item.id, - item.span, - BuiltinLintDiag::MissingUnsafeOnExtern, - ); + if this.features.unsafe_extern_blocks { + if &Safety::Default == safety { + this.lint_buffer.buffer_lint( + MISSING_UNSAFE_ON_EXTERN, + item.id, + item.span, + BuiltinLintDiag::MissingUnsafeOnExtern, + ); + } + } else if let &Safety::Unsafe(span) = safety { + this.dcx().emit_err(errors::UnsafeItem { span, kind: "extern block" }); } if abi.is_none() { diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 8de2cdefa81cd..486de706e526a 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -624,6 +624,8 @@ declare_features! ( (unstable, type_changing_struct_update, "1.58.0", Some(86555)), /// Allows unnamed fields of struct and union type (incomplete, unnamed_fields, "1.74.0", Some(49804)), + /// Allows unsafe on extern declarations and safety qualifiers over internal items. + (unstable, unsafe_extern_blocks, "CURRENT_RUSTC_VERSION", Some(123743)), /// Allows unsized fn parameters. (unstable, unsized_fn_params, "1.49.0", Some(48055)), /// Allows unsized rvalues at arguments and parameters. diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index b4a34b1407da8..ec124c3224cbe 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -4858,7 +4858,10 @@ declare_lint! { /// /// ### Example /// - /// ```rust,edition2024 + /// ```rust,edition2024,ignore + /// #![feature(unsafe_extern_blocks)] + /// #![allow(dead_code)] + /// /// extern "C" { /// fn foo(_: i32); /// } @@ -4880,5 +4883,5 @@ declare_lint! { pub MISSING_UNSAFE_ON_EXTERN, Allow, "detects missing unsafe keyword on extern declarations", - @edition Edition2024 => Warn; + @edition Edition2024 => Deny; } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index ede9b852ba84f..f1933806c012d 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1965,6 +1965,7 @@ symbols! { unsafe_block_in_unsafe_fn, unsafe_cell, unsafe_cell_raw_get, + unsafe_extern_blocks, unsafe_no_drop_flag, unsafe_pin_internals, unsize, diff --git a/tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.rs b/tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.rs new file mode 100644 index 0000000000000..eab134a4a4de4 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.rs @@ -0,0 +1,5 @@ +unsafe extern "C" { + //~^ ERROR extern block cannot be declared unsafe +} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.stderr b/tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.stderr new file mode 100644 index 0000000000000..7e9b199a2db55 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.stderr @@ -0,0 +1,8 @@ +error: extern block cannot be declared unsafe + --> $DIR/feature-gate-unsafe-extern-blocks.rs:1:1 + | +LL | unsafe extern "C" { + | ^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/unsafe-foreign-mod-2.rs b/tests/ui/parser/unsafe-foreign-mod-2.rs index 6d339cd90881f..0b63a993c5b9e 100644 --- a/tests/ui/parser/unsafe-foreign-mod-2.rs +++ b/tests/ui/parser/unsafe-foreign-mod-2.rs @@ -1,6 +1,8 @@ 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() {} diff --git a/tests/ui/parser/unsafe-foreign-mod-2.stderr b/tests/ui/parser/unsafe-foreign-mod-2.stderr index 0625e3362ed72..e59352395ed6e 100644 --- a/tests/ui/parser/unsafe-foreign-mod-2.stderr +++ b/tests/ui/parser/unsafe-foreign-mod-2.stderr @@ -4,5 +4,20 @@ error: expected `{`, found keyword `unsafe` LL | extern "C" unsafe { | ^^^^^^ expected `{` -error: aborting due to 1 previous error +error: extern block cannot be declared unsafe + --> $DIR/unsafe-foreign-mod-2.rs:1:12 + | +LL | extern "C" unsafe { + | ^^^^^^ + +error: items in unadorned `extern` blocks cannot have safety qualifiers + --> $DIR/unsafe-foreign-mod-2.rs:4:5 + | +LL | extern "C" unsafe { + | ----------------- help: add unsafe to this `extern` block +... +LL | unsafe fn foo(); + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors diff --git a/tests/ui/parser/unsafe-foreign-mod.rs b/tests/ui/parser/unsafe-foreign-mod.rs index 26015a3c44454..eab134a4a4de4 100644 --- a/tests/ui/parser/unsafe-foreign-mod.rs +++ b/tests/ui/parser/unsafe-foreign-mod.rs @@ -1,5 +1,5 @@ -//@ build-pass - -unsafe extern "C" {} +unsafe extern "C" { + //~^ ERROR extern block cannot be declared unsafe +} fn main() {} diff --git a/tests/ui/parser/unsafe-foreign-mod.stderr b/tests/ui/parser/unsafe-foreign-mod.stderr new file mode 100644 index 0000000000000..77f6e93be10bb --- /dev/null +++ b/tests/ui/parser/unsafe-foreign-mod.stderr @@ -0,0 +1,8 @@ +error: extern block cannot be declared unsafe + --> $DIR/unsafe-foreign-mod.rs:1:1 + | +LL | unsafe extern "C" { + | ^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2021.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2021.stderr index 77554da10e60b..3a99caa719b53 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2021.stderr +++ b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2021.stderr @@ -1,5 +1,5 @@ error[E0133]: call to unsafe function `test1` is unsafe and requires unsafe function or block - --> $DIR/extern-items-unsafe.rs:12:5 + --> $DIR/extern-items-unsafe.rs:14: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:12:11 + --> $DIR/extern-items-unsafe.rs:14:11 | LL | test1(TEST1); | ^^^^^ use of extern static diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2024.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2024.stderr index 33b752782d599..fcf937b7ac577 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2024.stderr +++ b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2024.stderr @@ -1,5 +1,5 @@ error[E0133]: call to unsafe function `test1` is unsafe and requires unsafe block - --> $DIR/extern-items-unsafe.rs:12:5 + --> $DIR/extern-items-unsafe.rs:14: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:12:11 + --> $DIR/extern-items-unsafe.rs:14:11 | LL | test1(TEST1); | ^^^^^ use of extern static diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.rs b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.rs index 721e07acca588..ad569a256db90 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.rs +++ b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.rs @@ -3,6 +3,8 @@ //@[edition2024] edition:2024 //@[edition2024] compile-flags: -Zunstable-options +#![feature(unsafe_extern_blocks)] + unsafe extern "C" { static TEST1: i32; fn test1(i: i32); diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.edition2024.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.edition2024.stderr index b19369c0a5515..8e1ec8146351a 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.edition2024.stderr +++ b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.edition2024.stderr @@ -1,5 +1,5 @@ -warning: extern blocks should be unsafe - --> $DIR/extern-items.rs:7:1 +error: extern blocks should be unsafe + --> $DIR/extern-items.rs:9:1 | LL | / extern "C" { LL | | @@ -8,7 +8,7 @@ LL | | fn test1(i: i32); LL | | } | |_^ | - = note: `#[warn(missing_unsafe_on_extern)]` on by default + = note: `#[deny(missing_unsafe_on_extern)]` on by default -warning: 1 warning emitted +error: aborting due to 1 previous error diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.rs b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.rs index dfb851e276d4a..905d1434155ea 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.rs +++ b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.rs @@ -1,11 +1,13 @@ //@ revisions: edition2021 edition2024 //@[edition2021] edition:2021 +//@[edition2021] check-pass //@[edition2024] edition:2024 //@[edition2024] compile-flags: -Zunstable-options -//@ check-pass + +#![feature(unsafe_extern_blocks)] extern "C" { - //[edition2024]~^ WARN extern blocks should be unsafe [missing_unsafe_on_extern] + //[edition2024]~^ ERROR extern blocks should be unsafe static TEST1: i32; fn test1(i: i32); } diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-items.rs b/tests/ui/rust-2024/unsafe-extern-blocks/safe-items.rs index b0b8a8b012a6a..74cd5621fce93 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/safe-items.rs +++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-items.rs @@ -4,6 +4,8 @@ //@[edition2024] compile-flags: -Zunstable-options //@ check-pass +#![feature(unsafe_extern_blocks)] + unsafe extern "C" { safe static TEST1: i32; safe fn test1(i: i32); diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2021.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2021.stderr index e3626bb497e4f..8bb7ffefeea9e 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2021.stderr +++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2021.stderr @@ -1,5 +1,5 @@ error[E0133]: call to unsafe function `test1` is unsafe and requires unsafe function or block - --> $DIR/unsafe-items.rs:18:5 + --> $DIR/unsafe-items.rs:20: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:18:11 + --> $DIR/unsafe-items.rs:20:11 | LL | test1(TEST1); | ^^^^^ use of extern static diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2024.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2024.stderr index 89bc501b7b5a5..9a30142a632c5 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2024.stderr +++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2024.stderr @@ -1,5 +1,5 @@ error[E0133]: call to unsafe function `test1` is unsafe and requires unsafe block - --> $DIR/unsafe-items.rs:18:5 + --> $DIR/unsafe-items.rs:20: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:18:11 + --> $DIR/unsafe-items.rs:20:11 | LL | test1(TEST1); | ^^^^^ use of extern static diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.rs b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.rs index dc2bae892a988..9066953abc615 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.rs +++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.rs @@ -3,6 +3,8 @@ //@[edition2024] edition:2024 //@[edition2024] compile-flags: -Zunstable-options +#![feature(unsafe_extern_blocks)] + unsafe extern "C" { unsafe static TEST1: i32; unsafe fn test1(i: i32); diff --git a/tests/ui/unpretty/expanded-exhaustive.rs b/tests/ui/unpretty/expanded-exhaustive.rs index 29472df897a1f..92c2e7b488478 100644 --- a/tests/ui/unpretty/expanded-exhaustive.rs +++ b/tests/ui/unpretty/expanded-exhaustive.rs @@ -25,6 +25,7 @@ #![feature(trait_alias)] #![feature(try_blocks)] #![feature(unnamed_fields)] +#![feature(unsafe_extern_blocks)] #![feature(yeet_expr)] #![allow(incomplete_features)] diff --git a/tests/ui/unpretty/expanded-exhaustive.stdout b/tests/ui/unpretty/expanded-exhaustive.stdout index 0a09a3f6a4233..9e45f57af354d 100644 --- a/tests/ui/unpretty/expanded-exhaustive.stdout +++ b/tests/ui/unpretty/expanded-exhaustive.stdout @@ -26,6 +26,7 @@ #![feature(trait_alias)] #![feature(try_blocks)] #![feature(unnamed_fields)] +#![feature(unsafe_extern_blocks)] #![feature(yeet_expr)] #![allow(incomplete_features)] #[prelude_import] From 1afc7d716cfb7858863754217566b785bac179a4 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Mon, 3 Jun 2024 22:27:57 -0300 Subject: [PATCH 10/12] Make MISSING_UNSAFE_ON_EXTERN lint emit future compat info with suggestion to prepend unsafe --- compiler/rustc_ast_passes/messages.ftl | 2 ++ .../rustc_ast_passes/src/ast_validation.rs | 19 +++++++++++++------ compiler/rustc_ast_passes/src/errors.rs | 7 +++++++ compiler/rustc_lint/messages.ftl | 1 + .../rustc_lint/src/context/diagnostics.rs | 4 ++-- compiler/rustc_lint/src/lints.rs | 5 ++++- compiler/rustc_lint_defs/src/builtin.rs | 8 ++++++-- compiler/rustc_lint_defs/src/lib.rs | 4 +++- .../extern-items.edition2024.stderr | 4 +--- .../unsafe-extern-blocks/extern-items.rs | 2 +- 10 files changed, 40 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index b90b502c22b82..9a8689e27c068 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -177,6 +177,8 @@ ast_passes_match_arm_with_no_body = `match` arm with no body .suggestion = add a body after the pattern +ast_passes_missing_unsafe_on_extern = extern blocks must be unsafe + ast_passes_module_nonascii = trying to load file for module `{$name}` with non-ascii identifier name .help = consider using the `#[path]` attribute to specify filesystem path diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index dc554ba04dfe5..0fbb288cc968c 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1044,12 +1044,19 @@ impl<'a> Visitor<'a> for AstValidator<'a> { if this.features.unsafe_extern_blocks { if &Safety::Default == safety { - this.lint_buffer.buffer_lint( - MISSING_UNSAFE_ON_EXTERN, - item.id, - item.span, - BuiltinLintDiag::MissingUnsafeOnExtern, - ); + 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 { this.dcx().emit_err(errors::UnsafeItem { span, kind: "extern block" }); diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 05e99a3d63613..260c182bd9e49 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -494,6 +494,13 @@ pub struct UnsafeItem { pub kind: &'static str, } +#[derive(Diagnostic)] +#[diag(ast_passes_missing_unsafe_on_extern)] +pub struct MissingUnsafeOnExtern { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(ast_passes_fieldless_union)] pub struct FieldlessUnion { diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index bb6ad7c945b27..522f2f84cca68 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -463,6 +463,7 @@ lint_metavariable_wrong_operator = meta-variable repeats with different Kleene o lint_missing_fragment_specifier = missing fragment specifier lint_missing_unsafe_on_extern = extern blocks should be unsafe + .suggestion = needs `unsafe` before the extern keyword lint_mixed_script_confusables = the usage of Script Group `{$set}` in this crate consists solely of mixed script confusables diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs index f824e02dcf9db..c38804e7714b7 100644 --- a/compiler/rustc_lint/src/context/diagnostics.rs +++ b/compiler/rustc_lint/src/context/diagnostics.rs @@ -205,8 +205,8 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: & }; lints::DeprecatedWhereClauseLocation { suggestion }.decorate_lint(diag); } - BuiltinLintDiag::MissingUnsafeOnExtern => { - lints::MissingUnsafeOnExtern.decorate_lint(diag); + BuiltinLintDiag::MissingUnsafeOnExtern { suggestion } => { + lints::MissingUnsafeOnExtern { suggestion }.decorate_lint(diag); } BuiltinLintDiag::SingleUseLifetime { param_span, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 01b455c588ba9..985b66a54e156 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2740,7 +2740,10 @@ pub enum DeprecatedWhereClauseLocationSugg { #[derive(LintDiagnostic)] #[diag(lint_missing_unsafe_on_extern)] -pub struct MissingUnsafeOnExtern; +pub struct MissingUnsafeOnExtern { + #[suggestion(code = "unsafe ", applicability = "machine-applicable")] + pub suggestion: Span, +} #[derive(LintDiagnostic)] #[diag(lint_single_use_lifetime)] diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index ec124c3224cbe..7082a068c4811 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -4858,8 +4858,9 @@ declare_lint! { /// /// ### Example /// - /// ```rust,edition2024,ignore + /// ```rust /// #![feature(unsafe_extern_blocks)] + /// #![warn(missing_unsafe_on_extern)] /// #![allow(dead_code)] /// /// extern "C" { @@ -4883,5 +4884,8 @@ declare_lint! { pub MISSING_UNSAFE_ON_EXTERN, Allow, "detects missing unsafe keyword on extern declarations", - @edition Edition2024 => Deny; + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024), + reference: "issue #123743 ", + }; } diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 0f13046923eb3..67e1bfee620ab 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -630,7 +630,9 @@ pub enum BuiltinLintDiag { UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>), UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>), DeprecatedWhereclauseLocation(Span, Option<(Span, String)>), - MissingUnsafeOnExtern, + MissingUnsafeOnExtern { + suggestion: Span, + }, SingleUseLifetime { /// Span of the parameter which declares this lifetime. param_span: Span, diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.edition2024.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.edition2024.stderr index 8e1ec8146351a..d456cfc6829e1 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.edition2024.stderr +++ b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.edition2024.stderr @@ -1,4 +1,4 @@ -error: extern blocks should be unsafe +error: extern blocks must be unsafe --> $DIR/extern-items.rs:9:1 | LL | / extern "C" { @@ -7,8 +7,6 @@ LL | | static TEST1: i32; LL | | fn test1(i: i32); LL | | } | |_^ - | - = note: `#[deny(missing_unsafe_on_extern)]` on by default error: aborting due to 1 previous error diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.rs b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.rs index 905d1434155ea..16fa1bbb8a404 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.rs +++ b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.rs @@ -7,7 +7,7 @@ #![feature(unsafe_extern_blocks)] extern "C" { - //[edition2024]~^ ERROR extern blocks should be unsafe + //[edition2024]~^ ERROR extern blocks must be unsafe static TEST1: i32; fn test1(i: i32); } From be0726c7c152700a47d91a27a4817c0af770e8e9 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 4 Jun 2024 14:44:57 -0300 Subject: [PATCH 11/12] Add revisions to safe/unsafe on unadorned extern blocks test --- ...unadorned-extern-block.edition2021.stderr} | 5 +-- ...-unadorned-extern-block.edition2024.stderr | 32 +++++++++++++++++++ .../safe-unsafe-on-unadorned-extern-block.rs | 8 +++++ 3 files changed, 43 insertions(+), 2 deletions(-) rename tests/ui/rust-2024/unsafe-extern-blocks/{safe-unsafe-on-unadorned-extern-block.stderr => safe-unsafe-on-unadorned-extern-block.edition2021.stderr} (80%) create mode 100644 tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2024.stderr diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2021.stderr similarity index 80% rename from tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.stderr rename to tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2021.stderr index 66624f1fcb16f..411cf48b4866a 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.stderr +++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2021.stderr @@ -1,13 +1,14 @@ error: items in unadorned `extern` blocks cannot have safety qualifiers - --> $DIR/safe-unsafe-on-unadorned-extern-block.rs:2:5 + --> $DIR/safe-unsafe-on-unadorned-extern-block.rs:10:5 | LL | extern "C" { | ---------- help: add unsafe to this `extern` block +LL | LL | safe static TEST1: i32; | ^^^^^^^^^^^^^^^^^^^^^^^ error: items in unadorned `extern` blocks cannot have safety qualifiers - --> $DIR/safe-unsafe-on-unadorned-extern-block.rs:4:5 + --> $DIR/safe-unsafe-on-unadorned-extern-block.rs:12:5 | LL | extern "C" { | ---------- help: add unsafe to this `extern` block diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2024.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2024.stderr new file mode 100644 index 0000000000000..b634adc299960 --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2024.stderr @@ -0,0 +1,32 @@ +error: extern blocks must be unsafe + --> $DIR/safe-unsafe-on-unadorned-extern-block.rs:8:1 + | +LL | / extern "C" { +LL | | +LL | | safe static TEST1: i32; +LL | | +LL | | safe fn test1(i: i32); +LL | | +LL | | } + | |_^ + +error: items in unadorned `extern` blocks cannot have safety qualifiers + --> $DIR/safe-unsafe-on-unadorned-extern-block.rs:10:5 + | +LL | extern "C" { + | ---------- help: add unsafe to this `extern` block +LL | +LL | safe static TEST1: i32; + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: items in unadorned `extern` blocks cannot have safety qualifiers + --> $DIR/safe-unsafe-on-unadorned-extern-block.rs:12:5 + | +LL | extern "C" { + | ---------- help: add unsafe to this `extern` block +... +LL | safe fn test1(i: i32); + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.rs b/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.rs index d37a7be452da5..11f55cb195f29 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.rs +++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.rs @@ -1,4 +1,12 @@ +//@ revisions: edition2021 edition2024 +//@[edition2021] edition:2021 +//@[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; //~^ ERROR items in unadorned `extern` blocks cannot have safety qualifiers safe fn test1(i: i32); From 525828d5ee9baca7f7e651918df966f6bc38596a Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 4 Jun 2024 15:46:32 -0300 Subject: [PATCH 12/12] Add rustfix test for unsafe extern blocks --- .../unsafe-extern-suggestion.fixed | 19 ++++++++++++++ .../unsafe-extern-suggestion.rs | 19 ++++++++++++++ .../unsafe-extern-suggestion.stderr | 25 +++++++++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.fixed create mode 100644 tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.rs create mode 100644 tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.stderr diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.fixed b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.fixed new file mode 100644 index 0000000000000..10c19759d8aaa --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.fixed @@ -0,0 +1,19 @@ +//@ run-rustfix + +#![feature(unsafe_extern_blocks)] +#![deny(missing_unsafe_on_extern)] +#![allow(unused)] + +unsafe extern "C" { + //~^ ERROR extern blocks should be unsafe [missing_unsafe_on_extern] + //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024! + static TEST1: i32; + fn test1(i: i32); +} + +unsafe extern "C" { + static TEST2: i32; + fn test2(i: i32); +} + +fn main() {} diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.rs b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.rs new file mode 100644 index 0000000000000..b81e52ddc5843 --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.rs @@ -0,0 +1,19 @@ +//@ run-rustfix + +#![feature(unsafe_extern_blocks)] +#![deny(missing_unsafe_on_extern)] +#![allow(unused)] + +extern "C" { + //~^ ERROR extern blocks should be unsafe [missing_unsafe_on_extern] + //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024! + static TEST1: i32; + fn test1(i: i32); +} + +unsafe extern "C" { + static TEST2: i32; + fn test2(i: i32); +} + +fn main() {} diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.stderr new file mode 100644 index 0000000000000..0a3c2cd25e3fe --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.stderr @@ -0,0 +1,25 @@ +error: extern blocks should be unsafe + --> $DIR/unsafe-extern-suggestion.rs:7:1 + | +LL | extern "C" { + | ^ + | | + | _help: needs `unsafe` before the extern keyword: `unsafe` + | | +LL | | +LL | | +LL | | static TEST1: i32; +LL | | fn test1(i: i32); +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 +note: the lint level is defined here + --> $DIR/unsafe-extern-suggestion.rs:4:9 + | +LL | #![deny(missing_unsafe_on_extern)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error +