Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions compiler/rustc_lint/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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} <https://github.com/rust-lang/rust/issues/{$n}> for more information
Expand Down Expand Up @@ -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
Expand Down
25 changes: 20 additions & 5 deletions compiler/rustc_lint/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,8 @@ declare_lint! {
/// #[no_mangle]
/// #[link_section = ".example_section"]
/// pub static VAR1: u32 = 1;
///
/// unsafe fn unsafe_func() { }
/// ```
///
/// {{produces}}
Expand All @@ -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",
Expand Down Expand Up @@ -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(_), .. }),
..
Expand Down Expand Up @@ -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,
_,
Expand All @@ -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);
Expand Down
4 changes: 0 additions & 4 deletions compiler/rustc_lint/src/lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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)]
Expand Down
10 changes: 10 additions & 0 deletions library/alloc/src/vec/spec_extend.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use core::iter::TrustedLen;
use core::option::{self};
use core::slice::{self};

use super::{IntoIter, Vec};
Expand Down Expand Up @@ -36,6 +37,15 @@ impl<T, A: Allocator> SpecExtend<T, IntoIter<T>> for Vec<T, A> {
}
}

impl<T, A: Allocator> SpecExtend<T, option::IntoIter<T>> for Vec<T, A> {
#[track_caller]
fn spec_extend(&mut self, mut iterator: option::IntoIter<T>) {
if let Some(element) = iterator.next() {
self.push(element);
}
}
}

impl<'a, T: 'a, I, A: Allocator> SpecExtend<&'a T, I> for Vec<T, A>
where
I: Iterator<Item = &'a T>,
Expand Down
19 changes: 7 additions & 12 deletions tests/ui/lint/lint-unsafe-code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -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
Expand Down
22 changes: 5 additions & 17 deletions tests/ui/lint/lint-unsafe-code.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
|
Expand Down Expand Up @@ -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 {}
| ^^^^^^^^^
Expand Down Expand Up @@ -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

25 changes: 25 additions & 0 deletions tests/ui/lint/unsafe_code/forbid-unsafe-op-in-unsafe-fn.rs
Original file line number Diff line number Diff line change
@@ -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() {}
14 changes: 14 additions & 0 deletions tests/ui/lint/unsafe_code/forbid-unsafe-op-in-unsafe-fn.stderr
Original file line number Diff line number Diff line change
@@ -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

Loading