diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 5b2100b5da9d1..131c1963a41fb 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -21,6 +21,7 @@ //! `late_lint_methods!` invocation in `lib.rs`. use crate::fluent_generated as fluent; +use crate::r#unsafe::{UNSAFE_OBLIGATION_DEFINE, UNSAFE_OBLIGATION_DISCHARGE}; use crate::{ errors::BuiltinEllpisisInclusiveRangePatterns, lints::{ @@ -36,9 +37,9 @@ use crate::{ BuiltinTypeAliasGenericBoundsSuggestion, BuiltinTypeAliasWhereClause, BuiltinUnexpectedCliConfigName, BuiltinUnexpectedCliConfigValue, BuiltinUngatedAsyncFnTrackCaller, BuiltinUnnameableTestItems, BuiltinUnpermittedTypeInit, - BuiltinUnpermittedTypeInitSub, BuiltinUnreachablePub, BuiltinUnsafe, - BuiltinUnstableFeatures, BuiltinUnusedDocComment, BuiltinUnusedDocCommentSub, - BuiltinWhileTrue, SuggestChangingAssocTypes, + BuiltinUnpermittedTypeInitSub, BuiltinUnreachablePub, BuiltinUnstableFeatures, + BuiltinUnusedDocComment, BuiltinUnusedDocCommentSub, BuiltinWhileTrue, + SuggestChangingAssocTypes, }, types::{transparent_newtype_field, CItemKind}, EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext, @@ -46,12 +47,11 @@ use crate::{ use hir::IsAsync; use rustc_ast::attr; use rustc_ast::tokenstream::{TokenStream, TokenTree}; -use rustc_ast::visit::{FnCtxt, FnKind}; use rustc_ast::{self as ast, *}; use rustc_ast_pretty::pprust::{self, expr_to_string}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_errors::{Applicability, DecorateLint, MultiSpan}; +use rustc_errors::{Applicability, MultiSpan}; use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, GateIssue, Stability}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -287,140 +287,6 @@ impl<'tcx> LateLintPass<'tcx> for NonShorthandFieldPatterns { } } -declare_lint! { - /// The `unsafe_code` lint catches usage of `unsafe` code. - /// - /// ### Example - /// - /// ```rust,compile_fail - /// #![deny(unsafe_code)] - /// fn main() { - /// unsafe { - /// - /// } - /// } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// This lint is intended to restrict the usage of `unsafe`, which can be - /// difficult to use correctly. - UNSAFE_CODE, - Allow, - "usage of `unsafe` code" -} - -declare_lint_pass!(UnsafeCode => [UNSAFE_CODE]); - -impl UnsafeCode { - fn report_unsafe( - &self, - cx: &EarlyContext<'_>, - span: Span, - decorate: impl for<'a> DecorateLint<'a, ()>, - ) { - // This comes from a macro that has `#[allow_internal_unsafe]`. - if span.allows_unsafe() { - return; - } - - cx.emit_spanned_lint(UNSAFE_CODE, span, decorate); - } -} - -impl EarlyLintPass for UnsafeCode { - fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) { - if attr.has_name(sym::allow_internal_unsafe) { - self.report_unsafe(cx, attr.span, BuiltinUnsafe::AllowInternalUnsafe); - } - } - - #[inline] - fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { - if let ast::ExprKind::Block(ref blk, _) = e.kind { - // Don't warn about generated blocks; that'll just pollute the output. - if blk.rules == ast::BlockCheckMode::Unsafe(ast::UserProvided) { - self.report_unsafe(cx, blk.span, BuiltinUnsafe::UnsafeBlock); - } - } - } - - fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) { - match it.kind { - ast::ItemKind::Trait(box ast::Trait { unsafety: ast::Unsafe::Yes(_), .. }) => { - self.report_unsafe(cx, it.span, BuiltinUnsafe::UnsafeTrait); - } - - ast::ItemKind::Impl(box ast::Impl { unsafety: ast::Unsafe::Yes(_), .. }) => { - self.report_unsafe(cx, it.span, BuiltinUnsafe::UnsafeImpl); - } - - ast::ItemKind::Fn(..) => { - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) { - self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleFn); - } - - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) { - self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameFn); - } - - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::link_section) { - self.report_unsafe(cx, attr.span, BuiltinUnsafe::LinkSectionFn); - } - } - - ast::ItemKind::Static(..) => { - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) { - self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleStatic); - } - - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) { - self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameStatic); - } - - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::link_section) { - self.report_unsafe(cx, attr.span, BuiltinUnsafe::LinkSectionStatic); - } - } - - _ => {} - } - } - - fn check_impl_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) { - if let ast::AssocItemKind::Fn(..) = it.kind { - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) { - self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleMethod); - } - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) { - self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameMethod); - } - } - } - - fn check_fn(&mut self, cx: &EarlyContext<'_>, fk: FnKind<'_>, span: Span, _: ast::NodeId) { - if let FnKind::Fn( - ctxt, - _, - ast::FnSig { header: ast::FnHeader { unsafety: ast::Unsafe::Yes(_), .. }, .. }, - _, - _, - body, - ) = fk - { - let decorator = match ctxt { - FnCtxt::Foreign => return, - FnCtxt::Free => BuiltinUnsafe::DeclUnsafeFn, - FnCtxt::Assoc(_) if body.is_none() => BuiltinUnsafe::DeclUnsafeMethod, - FnCtxt::Assoc(_) => BuiltinUnsafe::ImplUnsafeMethod, - }; - self.report_unsafe(cx, span, decorator); - } - } -} - declare_lint! { /// The `missing_docs` lint detects missing documentation for public items. /// @@ -1633,7 +1499,8 @@ declare_lint_pass!( WHILE_TRUE, BOX_POINTERS, NON_SHORTHAND_FIELD_PATTERNS, - UNSAFE_CODE, + UNSAFE_OBLIGATION_DEFINE, + UNSAFE_OBLIGATION_DISCHARGE, MISSING_DOCS, MISSING_COPY_IMPLEMENTATIONS, MISSING_DEBUG_IMPLEMENTATIONS, diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index b3578540516d0..5b3103baa8734 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -76,6 +76,7 @@ mod passes; mod redundant_semicolon; mod traits; mod types; +mod r#unsafe; mod unused; pub use array_into_iter::ARRAY_INTO_ITER; @@ -92,6 +93,7 @@ use rustc_session::lint::builtin::{ }; use rustc_span::symbol::Ident; use rustc_span::Span; +use r#unsafe::UnsafeCode; use array_into_iter::ArrayIntoIter; use builtin::*; @@ -126,6 +128,8 @@ pub use rustc_session::lint::Level::{self, *}; pub use rustc_session::lint::{BufferedEarlyLint, FutureIncompatibleInfo, Lint, LintId}; pub use rustc_session::lint::{LintArray, LintPass}; +use crate::r#unsafe::{UNSAFE_OBLIGATION_DEFINE, UNSAFE_OBLIGATION_DISCHARGE}; + fluent_messages! { "../messages.ftl" } pub fn provide(providers: &mut Providers) { @@ -272,6 +276,8 @@ fn register_builtins(store: &mut LintStore) { store.register_lints(&BuiltinCombinedModuleLateLintPass::get_lints()); store.register_lints(&BuiltinCombinedLateLintPass::get_lints()); + add_lint_group!("unsafe_code", UNSAFE_OBLIGATION_DEFINE, UNSAFE_OBLIGATION_DISCHARGE); + add_lint_group!( "nonstandard_style", NON_CAMEL_CASE_TYPES, diff --git a/compiler/rustc_lint/src/unsafe.rs b/compiler/rustc_lint/src/unsafe.rs new file mode 100644 index 0000000000000..f987421de0a48 --- /dev/null +++ b/compiler/rustc_lint/src/unsafe.rs @@ -0,0 +1,262 @@ +use rustc_ast::{ + ast, + visit::{FnCtxt, FnKind}, +}; +use rustc_errors::DecorateLint; +use rustc_session::lint::builtin::UNSAFE_OP_IN_UNSAFE_FN; +use rustc_span::{sym, Span}; + +use crate::{lints::BuiltinUnsafe, EarlyContext, EarlyLintPass, LintContext}; + +declare_lint! { + /// The `unsafe_obligation_define` lint triggers when an "unsafe contract" + /// is defined. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(unsafe_obligation_define)] + /// unsafe trait Foo {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// An "unsafe contract" is a set of invariants which must be upheld in + /// order to prevent Undefined Behaviour in unsafe code. This lint triggers + /// when such a contract is defined, for example when defining an + /// `unsafe trait` or unsafe trait method without a body. + pub UNSAFE_OBLIGATION_DEFINE, + Allow, + "definition of unsafe contract" +} + +declare_lint! { + /// The `unsafe_obligation_discharge` lint triggers when an + /// "unsafe contract"'s invariants are consumed. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(unsafe_obligation_discharge)] + /// fn main() { + /// unsafe { + /// + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// An "unsafe contract" is a set of invariants which must be upheld in + /// order to prevent Undefined Behaviour in unsafe code. This lint triggers + /// when such a contract's invariants must be upheld. For example, `unsafe` + /// blocks may call functions which have safety variants which must be + /// upheld. + pub UNSAFE_OBLIGATION_DISCHARGE, + Allow, + "discharge of unsafe responsibilities" +} + +declare_lint_pass!(UnsafeCode => [UNSAFE_OBLIGATION_DEFINE, UNSAFE_OBLIGATION_DISCHARGE]); + +enum ObligationKind { + Discharge, + Define, +} + +impl UnsafeCode { + fn report_unsafe( + &self, + cx: &EarlyContext<'_>, + span: Span, + decorate: impl for<'a> DecorateLint<'a, ()>, + kind: ObligationKind, + ) { + // This comes from a macro that has `#[allow_internal_unsafe]`. + if span.allows_unsafe() { + return; + } + + cx.emit_spanned_lint( + match kind { + ObligationKind::Discharge => UNSAFE_OBLIGATION_DISCHARGE, + ObligationKind::Define => UNSAFE_OBLIGATION_DEFINE, + }, + span, + decorate, + ); + } +} + +impl EarlyLintPass for UnsafeCode { + fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) { + if attr.has_name(sym::allow_internal_unsafe) { + self.report_unsafe( + cx, + attr.span, + BuiltinUnsafe::AllowInternalUnsafe, + ObligationKind::Discharge, + ); + } + } + + #[inline] + fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { + if let ast::ExprKind::Block(ref blk, _) = e.kind { + // Don't warn about generated blocks; that'll just pollute the output. + if blk.rules == ast::BlockCheckMode::Unsafe(ast::UserProvided) { + self.report_unsafe( + cx, + blk.span, + BuiltinUnsafe::UnsafeBlock, + ObligationKind::Discharge, + ); + } + } + } + + fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) { + match it.kind { + ast::ItemKind::Trait(box ast::Trait { unsafety: ast::Unsafe::Yes(_), .. }) => { + self.report_unsafe(cx, it.span, BuiltinUnsafe::UnsafeTrait, ObligationKind::Define); + } + + ast::ItemKind::Impl(box ast::Impl { unsafety: ast::Unsafe::Yes(_), .. }) => { + self.report_unsafe( + cx, + it.span, + BuiltinUnsafe::UnsafeImpl, + ObligationKind::Discharge, + ); + } + + ast::ItemKind::Fn(..) => { + if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) { + self.report_unsafe( + cx, + attr.span, + BuiltinUnsafe::NoMangleFn, + ObligationKind::Discharge, + ); + } + + if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) { + self.report_unsafe( + cx, + attr.span, + BuiltinUnsafe::ExportNameFn, + ObligationKind::Discharge, + ); + } + + if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::link_section) { + self.report_unsafe( + cx, + attr.span, + BuiltinUnsafe::LinkSectionFn, + ObligationKind::Discharge, + ); + } + } + + ast::ItemKind::Static(..) => { + if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) { + self.report_unsafe( + cx, + attr.span, + BuiltinUnsafe::NoMangleStatic, + ObligationKind::Discharge, + ); + } + + if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) { + self.report_unsafe( + cx, + attr.span, + BuiltinUnsafe::ExportNameStatic, + ObligationKind::Discharge, + ); + } + + if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::link_section) { + self.report_unsafe( + cx, + attr.span, + BuiltinUnsafe::LinkSectionStatic, + ObligationKind::Discharge, + ); + } + } + + _ => {} + } + } + + fn check_impl_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) { + if let ast::AssocItemKind::Fn(..) = it.kind { + if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) { + self.report_unsafe( + cx, + attr.span, + BuiltinUnsafe::NoMangleMethod, + ObligationKind::Discharge, + ); + } + if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) { + self.report_unsafe( + cx, + attr.span, + BuiltinUnsafe::ExportNameMethod, + ObligationKind::Discharge, + ); + } + } + } + + fn check_fn(&mut self, cx: &EarlyContext<'_>, fk: FnKind<'_>, span: Span, _: ast::NodeId) { + if let FnKind::Fn( + ctxt, + _, + ast::FnSig { header: ast::FnHeader { unsafety: ast::Unsafe::Yes(_), .. }, .. }, + _, + _, + body, + ) = fk + { + let decorator = match ctxt { + FnCtxt::Foreign => return, + FnCtxt::Free => BuiltinUnsafe::DeclUnsafeFn, + FnCtxt::Assoc(_) if body.is_none() => { + // there is no body, so we know that it cannot contain + // unsafety which does more than simply define an unsafety + // contract, see below. + return self.report_unsafe( + cx, + span, + BuiltinUnsafe::DeclUnsafeMethod, + ObligationKind::Define, + ); + } + FnCtxt::Assoc(_) => BuiltinUnsafe::ImplUnsafeMethod, + }; + + // Unsafe methods can merely define unsafety contracts, but they + // also give free rein for the body of the function to contain + // unsafe code which is not necessarily covered by said contract. + // If unsafe code in the function body is allowed without unsafe + // blocks, then it is just a regular discharge of unsafe + // responibilties. + if cx.get_lint_level(UNSAFE_OP_IN_UNSAFE_FN) + >= cx.get_lint_level(UNSAFE_OBLIGATION_DEFINE) + { + self.report_unsafe(cx, span, decorator, ObligationKind::Define); + } else { + self.report_unsafe(cx, span, decorator, ObligationKind::Discharge); + } + } + } +} diff --git a/src/tools/lint-docs/src/groups.rs b/src/tools/lint-docs/src/groups.rs index 2a923a61b0a70..ce00e2d832e31 100644 --- a/src/tools/lint-docs/src/groups.rs +++ b/src/tools/lint-docs/src/groups.rs @@ -7,6 +7,7 @@ use std::process::Command; /// Descriptions of rustc lint groups. static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[ + ("unsafe-code", "Lints that detect unsafe code"), ("unused", "Lints that detect things being declared but not used, or excess syntax"), ("let-underscore", "Lints that detect wildcard let bindings that are likely to be invalid"), ("rustdoc", "Rustdoc-specific lints"), diff --git a/tests/ui/lint/issue-108926.rs b/tests/ui/lint/issue-108926.rs new file mode 100644 index 0000000000000..0332576b7e48c --- /dev/null +++ b/tests/ui/lint/issue-108926.rs @@ -0,0 +1,21 @@ +#![forbid(unsafe_code)] + +trait Foo { + unsafe fn dangerous(); + //~^ ERROR declaration of an `unsafe` method [unsafe_obligation_define] +} + +struct ImplOk; +impl Foo for ImplOk { + #[forbid(unsafe_op_in_unsafe_fn)] + unsafe fn dangerous() {} + //~^ ERROR implementation of an `unsafe` method [unsafe_obligation_define] +} + +struct ImplBad; +impl Foo for ImplBad { + unsafe fn dangerous() {} + //~^ ERROR implementation of an `unsafe` method [unsafe_obligation_discharge] +} + +fn main() {} diff --git a/tests/ui/lint/issue-108926.stderr b/tests/ui/lint/issue-108926.stderr new file mode 100644 index 0000000000000..a29236daffe4c --- /dev/null +++ b/tests/ui/lint/issue-108926.stderr @@ -0,0 +1,29 @@ +error: declaration of an `unsafe` method + --> $DIR/issue-108926.rs:4:5 + | +LL | unsafe fn dangerous(); + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/issue-108926.rs:1:11 + | +LL | #![forbid(unsafe_code)] + | ^^^^^^^^^^^ + = note: `#[forbid(unsafe_obligation_define)]` implied by `#[forbid(unsafe_code)]` + +error: implementation of an `unsafe` method + --> $DIR/issue-108926.rs:11:5 + | +LL | unsafe fn dangerous() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: implementation of an `unsafe` method + --> $DIR/issue-108926.rs:17:5 + | +LL | unsafe fn dangerous() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[forbid(unsafe_obligation_discharge)]` implied by `#[forbid(unsafe_code)]` + +error: aborting due to 3 previous errors + diff --git a/tests/ui/lint/lint-attr-everywhere-early.stderr b/tests/ui/lint/lint-attr-everywhere-early.stderr index d6c6d5faef284..984d625f15659 100644 --- a/tests/ui/lint/lint-attr-everywhere-early.stderr +++ b/tests/ui/lint/lint-attr-everywhere-early.stderr @@ -50,6 +50,7 @@ note: the lint level is defined here | LL | #![deny(unsafe_code)] | ^^^^^^^^^^^ + = note: `#[deny(unsafe_obligation_discharge)]` implied by `#[deny(unsafe_code)]` error: usage of an `unsafe` block --> $DIR/lint-attr-everywhere-early.rs:43:39 diff --git a/tests/ui/lint/lint-forbid-internal-unsafe.stderr b/tests/ui/lint/lint-forbid-internal-unsafe.stderr index ba425ceb442b2..feea6458e4526 100644 --- a/tests/ui/lint/lint-forbid-internal-unsafe.stderr +++ b/tests/ui/lint/lint-forbid-internal-unsafe.stderr @@ -9,6 +9,7 @@ note: the lint level is defined here | LL | #![forbid(unsafe_code)] | ^^^^^^^^^^^ + = note: `#[forbid(unsafe_obligation_discharge)]` implied by `#[forbid(unsafe_code)]` warning: dereferencing a null pointer --> $DIR/lint-forbid-internal-unsafe.rs:15:26 diff --git a/tests/ui/lint/lint-unsafe-code.stderr b/tests/ui/lint/lint-unsafe-code.stderr index 037f0a8323a75..0e7d063803f10 100644 --- a/tests/ui/lint/lint-unsafe-code.stderr +++ b/tests/ui/lint/lint-unsafe-code.stderr @@ -10,6 +10,7 @@ note: the lint level is defined here | LL | #![deny(unsafe_code)] | ^^^^^^^^^^^ + = note: `#[deny(unsafe_obligation_discharge)]` implied by `#[deny(unsafe_code)]` error: declaration of a `no_mangle` static --> $DIR/lint-unsafe-code.rs:32:1 @@ -94,6 +95,8 @@ error: declaration of an `unsafe` trait | LL | unsafe trait Foo {} | ^^^^^^^^^^^^^^^^^^^ + | + = note: `#[deny(unsafe_obligation_define)]` implied by `#[deny(unsafe_code)]` error: implementation of an `unsafe` trait --> $DIR/lint-unsafe-code.rs:66:1 diff --git a/tests/ui/lint/reasons-forbidden.rs b/tests/ui/lint/reasons-forbidden.rs deleted file mode 100644 index 947099fdd13e7..0000000000000 --- a/tests/ui/lint/reasons-forbidden.rs +++ /dev/null @@ -1,34 +0,0 @@ -#![feature(lint_reasons)] - -// If you turn off deduplicate diagnostics (which rustc turns on by default but -// compiletest turns off when it runs ui tests), then the errors are -// (unfortunately) repeated here because the checking is done as we read in the -// errors, and currently that happens two or three different times, depending on -// compiler flags. -// -// The test is much cleaner if we deduplicate, though. - -// compile-flags: -Z deduplicate-diagnostics=true - -#![forbid( - unsafe_code, - //~^ NOTE `forbid` level set here - //~| NOTE the lint level is defined here - reason = "our errors & omissions insurance policy doesn't cover unsafe Rust" -)] - -use std::ptr; - -fn main() { - let a_billion_dollar_mistake = ptr::null(); - - #[allow(unsafe_code)] - //~^ ERROR allow(unsafe_code) incompatible with previous forbid - //~| NOTE our errors & omissions insurance policy doesn't cover unsafe Rust - //~| NOTE overruled by previous forbid - unsafe { - //~^ ERROR usage of an `unsafe` block - //~| NOTE our errors & omissions insurance policy doesn't cover unsafe Rust - *a_billion_dollar_mistake - } -} diff --git a/tests/ui/lint/reasons-forbidden.stderr b/tests/ui/lint/reasons-forbidden.stderr deleted file mode 100644 index ab6f19a019d43..0000000000000 --- a/tests/ui/lint/reasons-forbidden.stderr +++ /dev/null @@ -1,31 +0,0 @@ -error[E0453]: allow(unsafe_code) incompatible with previous forbid - --> $DIR/reasons-forbidden.rs:25:13 - | -LL | unsafe_code, - | ----------- `forbid` level set here -... -LL | #[allow(unsafe_code)] - | ^^^^^^^^^^^ overruled by previous forbid - | - = note: our errors & omissions insurance policy doesn't cover unsafe Rust - -error: usage of an `unsafe` block - --> $DIR/reasons-forbidden.rs:29:5 - | -LL | / unsafe { -LL | | -LL | | -LL | | *a_billion_dollar_mistake -LL | | } - | |_____^ - | - = note: our errors & omissions insurance policy doesn't cover unsafe Rust -note: the lint level is defined here - --> $DIR/reasons-forbidden.rs:14:5 - | -LL | unsafe_code, - | ^^^^^^^^^^^ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0453`.