diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 8aa90c070acd3..8b25dbfe4e4fa 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -64,7 +64,7 @@ lint_builtin_const_no_mangle = const items should never be `#[no_mangle]` .suggestion = try a static value lint_builtin_decl_unsafe_fn = declaration of an `unsafe` function -lint_builtin_decl_unsafe_method = declaration of an `unsafe` method + .note = declaration of `unsafe` function is allowed when lint `unsafe_op_in_unsafe_fn` is set to `forbid` level lint_builtin_deref_nullptr = dereferencing a null pointer .label = this code causes undefined behavior when executed @@ -91,6 +91,7 @@ lint_builtin_global_asm = usage of `core::arch::global_asm` lint_builtin_global_macro_unsafety = using this macro is unsafe even though it does not need an `unsafe` block lint_builtin_impl_unsafe_method = implementation of an `unsafe` method + .note = implementation of `unsafe` method is allowed when lint `unsafe_op_in_unsafe_fn` is set to `forbid` level lint_builtin_incomplete_features = the feature `{$name}` is incomplete and may not be safe to use and/or cause compiler crashes .note = see issue #{$n} for more information @@ -169,8 +170,6 @@ lint_builtin_unsafe_extern_block = usage of an `unsafe extern` block lint_builtin_unsafe_impl = implementation of an `unsafe` trait -lint_builtin_unsafe_trait = declaration of an `unsafe` trait - lint_builtin_unstable_features = use of an unstable feature lint_builtin_unused_doc_comment = unused doc comment diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 83de7d3892314..7638e5983f0fa 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -216,6 +216,8 @@ declare_lint! { /// #[no_mangle] /// #[link_section = ".example_section"] /// pub static VAR1: u32 = 1; + /// + /// unsafe fn unsafe_func() { } /// ``` /// /// {{produces}} @@ -226,6 +228,20 @@ declare_lint! { /// constructs (including, but not limited to `no_mangle`, `link_section` /// and `export_name` attributes) wrong usage of which causes undefined /// behavior. + /// + /// However, the declaration of an unsafe trait cannot cause any undefined + /// behavior — only its implementations can — that's why it is not covered + /// by this lint, despite the `unsafe` prefix. + /// + /// Along the same line, unsafe declaration of function (or method) cannot + /// cause any undefined behavior. Nevertheless, unsafe functions can contain + /// unsafe operations without `unsafe` block, as checked by the + /// [`unsafe_op_in_unsafe_fn`] lint. As a consequence, unless + /// `unsafe_op_in_unsafe_fn` is set to `forbid`, unsafe function declarations + /// *with a body* are covered by this lint. Declarations of unsafe functions + /// *without body* (e.g., in traits) are always allowed. + /// + /// [`unsafe_op_in_unsafe_fn`]: https://doc.rust-lang.org/rustc/lints/listing/allowed-by-default.html#unsafe-op-in-unsafe-fn UNSAFE_CODE, Allow, "usage of `unsafe` code and other potentially unsound constructs", @@ -263,10 +279,6 @@ impl EarlyLintPass for UnsafeCode { fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) { match it.kind { - ast::ItemKind::Trait(box ast::Trait { safety: ast::Safety::Unsafe(_), .. }) => { - self.report_unsafe(cx, it.span, BuiltinUnsafe::UnsafeTrait); - } - ast::ItemKind::Impl(ast::Impl { of_trait: Some(box ast::TraitImplHeader { safety: ast::Safety::Unsafe(_), .. }), .. @@ -343,6 +355,9 @@ impl EarlyLintPass for UnsafeCode { } fn check_fn(&mut self, cx: &EarlyContext<'_>, fk: FnKind<'_>, span: Span, _: ast::NodeId) { + if cx.get_lint_level(UNSAFE_OP_IN_UNSAFE_FN).level == Level::Forbid { + return; + } if let FnKind::Fn( ctxt, _, @@ -356,7 +371,7 @@ impl EarlyLintPass for UnsafeCode { let decorator = match ctxt { FnCtxt::Foreign => return, FnCtxt::Free => BuiltinUnsafe::DeclUnsafeFn, - FnCtxt::Assoc(_) if body.is_none() => BuiltinUnsafe::DeclUnsafeMethod, + FnCtxt::Assoc(_) if body.is_none() => return, FnCtxt::Assoc(_) => BuiltinUnsafe::ImplUnsafeMethod, }; self.report_unsafe(cx, span, decorator); diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index c55f2b9dd6f24..e82c14aaa6e9d 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -128,8 +128,6 @@ pub(crate) enum BuiltinUnsafe { UnsafeBlock, #[diag(lint_builtin_unsafe_extern_block)] UnsafeExternBlock, - #[diag(lint_builtin_unsafe_trait)] - UnsafeTrait, #[diag(lint_builtin_unsafe_impl)] UnsafeImpl, #[diag(lint_builtin_no_mangle_fn)] @@ -158,8 +156,6 @@ pub(crate) enum BuiltinUnsafe { ExportNameMethod, #[diag(lint_builtin_decl_unsafe_fn)] DeclUnsafeFn, - #[diag(lint_builtin_decl_unsafe_method)] - DeclUnsafeMethod, #[diag(lint_builtin_impl_unsafe_method)] ImplUnsafeMethod, #[diag(lint_builtin_global_asm)] diff --git a/library/alloc/src/vec/spec_extend.rs b/library/alloc/src/vec/spec_extend.rs index 7085bceef5baa..02dd44d6e9c88 100644 --- a/library/alloc/src/vec/spec_extend.rs +++ b/library/alloc/src/vec/spec_extend.rs @@ -1,4 +1,5 @@ use core::iter::TrustedLen; +use core::option::{self}; use core::slice::{self}; use super::{IntoIter, Vec}; @@ -36,6 +37,15 @@ impl SpecExtend> for Vec { } } +impl SpecExtend> for Vec { + #[track_caller] + fn spec_extend(&mut self, mut iterator: option::IntoIter) { + if let Some(element) = iterator.next() { + self.push(element); + } + } +} + impl<'a, T: 'a, I, A: Allocator> SpecExtend<&'a T, I> for Vec where I: Iterator, diff --git a/tests/ui/lint/lint-unsafe-code.rs b/tests/ui/lint/lint-unsafe-code.rs index b72e4c3a9e7fb..bf5bed73bebdf 100644 --- a/tests/ui/lint/lint-unsafe-code.rs +++ b/tests/ui/lint/lint-unsafe-code.rs @@ -62,11 +62,11 @@ impl AssocFnTrait for AssocFnBar { } unsafe fn baz() {} //~ ERROR: declaration of an `unsafe` function -unsafe trait Foo {} //~ ERROR: declaration of an `unsafe` trait +unsafe trait Foo {} unsafe impl Foo for Bar {} //~ ERROR: implementation of an `unsafe` trait trait Baz { - unsafe fn baz(&self); //~ ERROR: declaration of an `unsafe` method + unsafe fn baz(&self); unsafe fn provided(&self) {} //~ ERROR: implementation of an `unsafe` method unsafe fn provided_override(&self) {} //~ ERROR: implementation of an `unsafe` method } @@ -95,33 +95,28 @@ impl Baz for Bar3 { unsafe fn provided_override(&self) {} //~ ERROR: implementation of an `unsafe` method } -#[allow(unsafe_code)] -unsafe trait B { - fn dummy(&self) {} -} - -trait C { +trait B { #[allow(unsafe_code)] unsafe fn baz(&self); unsafe fn provided(&self) {} //~ ERROR: implementation of an `unsafe` method } -impl C for Bar { +impl B for Bar { #[allow(unsafe_code)] unsafe fn baz(&self) {} unsafe fn provided(&self) {} //~ ERROR: implementation of an `unsafe` method } -impl C for Bar2 { +impl B for Bar2 { unsafe fn baz(&self) {} //~ ERROR: implementation of an `unsafe` method } -trait D { +trait C { #[allow(unsafe_code)] unsafe fn unsafe_provided(&self) {} } -impl D for Bar {} +impl C for Bar {} fn main() { unsafe {} //~ ERROR: usage of an `unsafe` block diff --git a/tests/ui/lint/lint-unsafe-code.stderr b/tests/ui/lint/lint-unsafe-code.stderr index 037f0a8323a75..17179597d7c23 100644 --- a/tests/ui/lint/lint-unsafe-code.stderr +++ b/tests/ui/lint/lint-unsafe-code.stderr @@ -89,24 +89,12 @@ error: declaration of an `unsafe` function LL | unsafe fn baz() {} | ^^^^^^^^^^^^^^^^^^ -error: declaration of an `unsafe` trait - --> $DIR/lint-unsafe-code.rs:65:1 - | -LL | unsafe trait Foo {} - | ^^^^^^^^^^^^^^^^^^^ - error: implementation of an `unsafe` trait --> $DIR/lint-unsafe-code.rs:66:1 | LL | unsafe impl Foo for Bar {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: declaration of an `unsafe` method - --> $DIR/lint-unsafe-code.rs:69:5 - | -LL | unsafe fn baz(&self); - | ^^^^^^^^^^^^^^^^^^^^^ - error: implementation of an `unsafe` method --> $DIR/lint-unsafe-code.rs:70:5 | @@ -138,25 +126,25 @@ LL | unsafe fn provided_override(&self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: implementation of an `unsafe` method - --> $DIR/lint-unsafe-code.rs:106:5 + --> $DIR/lint-unsafe-code.rs:101:5 | LL | unsafe fn provided(&self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: implementation of an `unsafe` method - --> $DIR/lint-unsafe-code.rs:112:5 + --> $DIR/lint-unsafe-code.rs:107:5 | LL | unsafe fn provided(&self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: implementation of an `unsafe` method - --> $DIR/lint-unsafe-code.rs:116:5 + --> $DIR/lint-unsafe-code.rs:111:5 | LL | unsafe fn baz(&self) {} | ^^^^^^^^^^^^^^^^^^^^^^^ error: usage of an `unsafe` block - --> $DIR/lint-unsafe-code.rs:127:5 + --> $DIR/lint-unsafe-code.rs:122:5 | LL | unsafe {} | ^^^^^^^^^ @@ -220,5 +208,5 @@ LL | unsafe_in_macro!() | = note: this error originates in the macro `unsafe_in_macro` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 28 previous errors +error: aborting due to 26 previous errors diff --git a/tests/ui/lint/unsafe_code/forbid-unsafe-op-in-unsafe-fn.rs b/tests/ui/lint/unsafe_code/forbid-unsafe-op-in-unsafe-fn.rs new file mode 100644 index 0000000000000..903f9a2a1d233 --- /dev/null +++ b/tests/ui/lint/unsafe_code/forbid-unsafe-op-in-unsafe-fn.rs @@ -0,0 +1,25 @@ +#![forbid(unsafe_op_in_unsafe_fn)] +#![allow(unused_unsafe)] +#![allow(dead_code)] +#![deny(unsafe_code)] + +struct Bar; + +unsafe fn baz() {} + +trait Baz { + unsafe fn baz(&self); + unsafe fn provided(&self) {} + unsafe fn provided_override(&self) {} +} + +impl Baz for Bar { + unsafe fn baz(&self) {} + unsafe fn provided_override(&self) {} +} + +unsafe fn unsafe_op_in_unsafe_fn() { + unsafe {} //~ ERROR: usage of an `unsafe` block +} + +fn main() {} diff --git a/tests/ui/lint/unsafe_code/forbid-unsafe-op-in-unsafe-fn.stderr b/tests/ui/lint/unsafe_code/forbid-unsafe-op-in-unsafe-fn.stderr new file mode 100644 index 0000000000000..927395649c223 --- /dev/null +++ b/tests/ui/lint/unsafe_code/forbid-unsafe-op-in-unsafe-fn.stderr @@ -0,0 +1,14 @@ +error: usage of an `unsafe` block + --> $DIR/forbid-unsafe-op-in-unsafe-fn.rs:22:5 + | +LL | unsafe {} + | ^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/forbid-unsafe-op-in-unsafe-fn.rs:4:9 + | +LL | #![deny(unsafe_code)] + | ^^^^^^^^^^^ + +error: aborting due to 1 previous error +