Skip to content
Open
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
17 changes: 17 additions & 0 deletions compiler/rustc_hir_typeck/src/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ use rustc_hir::def::DefKind;
use rustc_hir_analysis::check::check_function_signature;
use rustc_infer::infer::RegionVariableOrigin;
use rustc_infer::traits::WellFormedLoc;
use rustc_lint_defs::builtin::UNSAFE_PANIC_HANDLERS;
use rustc_middle::ty::{self, Binder, Ty, TyCtxt};
use rustc_span::def_id::LocalDefId;
use rustc_span::sym;
use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
use tracing::{debug, instrument};

use crate::coercion::CoerceMany;
use crate::diagnostics::UnsafePanicHandlers;
use crate::gather_locals::GatherLocalsVisitor;
use crate::{CoroutineTypes, Diverges, FnCtxt};

Expand Down Expand Up @@ -177,6 +179,21 @@ fn check_panic_info_fn(tcx: TyCtxt<'_>, fn_id: LocalDefId, fn_sig: ty::FnSig<'_>
tcx.dcx().span_err(span, "should have no const parameters");
}

if fn_sig.safety().is_unsafe() {
let hir_id = tcx.local_def_id_to_hir_id(fn_id);
let span = tcx.def_span(fn_id);
// If the function is implicitly "unsafe" because it has a `#[target_feature]` attribute,
// then we should already have emitted an error. Don't also emit a warning.
// See `tests/ui/panic-handler/panic-handler-with-target-feature.rs`
if let Some(hir_fn_sig) = tcx.hir_fn_sig_by_hir_id(hir_id)
&& hir_fn_sig.header.safety == hir::HeaderSafety::SafeTargetFeatures
{
tcx.dcx().span_delayed_bug(span, "`unsafe_panic_handlers` lint suppressed because there should already be an error for `#[target_feature]`");
} else {
tcx.emit_node_span_lint(UNSAFE_PANIC_HANDLERS, hir_id, span, UnsafePanicHandlers);
}
}

let panic_info_did = tcx.require_lang_item(LangItem::PanicInfo, span);

// build type `for<'a, 'b> fn(&'a PanicInfo<'b>) -> !`
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_hir_typeck/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1337,3 +1337,7 @@ impl ExprParenthesesNeeded {
ExprParenthesesNeeded { left: s.shrink_to_lo(), right: s.shrink_to_hi() }
}
}

#[derive(Diagnostic)]
#[diag("`#[panic_handler]` functions can't be `unsafe`")]
pub(crate) struct UnsafePanicHandlers;
39 changes: 39 additions & 0 deletions compiler/rustc_lint_defs/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5858,3 +5858,42 @@ declare_lint! {
"`repr(C, align)` types nested inside `repr(C, packed)` types \
do not always have a C-compatible layout",
}

declare_lint! {
/// The `unsafe_panic_handlers` lint detects unsafe functions with
/// the `#[panic_handler]` attribute.
///
/// ### Example
///
/// ```rust,compile_fail
/// #![no_std]
///
/// use core::panic::PanicInfo;
///
/// #[panic_handler]
/// unsafe fn handle(_: &PanicInfo<'_>) -> ! {
/// loop {}
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Unsafe functions (declared as `unsafe fn`) are functions that can only be called
/// when the caller ensures that their safety requirements are met. On the other hand,
/// `#[panic_handler]` functions get called automatically by the compiler without
/// checking for any preconditions. Therefore, using the `#[panic_handler]` attribute
/// on unsafe functions is either incorrect or a misuse of `unsafe fn`.
///
/// This is a [future-incompatible] lint to transition this to a hard
/// error in the future. See [issue #163263] for more details.
///
/// [issue #163263]: https://github.com/rust-lang/rust/issues/163263
pub UNSAFE_PANIC_HANDLERS,
Warn,
"detects unsafe functions with the `#[panic_handler]` attribute",
@future_incompatible = FutureIncompatibleInfo {
reason: fcw!(FutureReleaseError #163263),
};
}
2 changes: 1 addition & 1 deletion tests/ui/codegen/no-mangle-on-panic-handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ use core::panic::PanicInfo;

#[unsafe(no_mangle)] //~ ERROR `#[no_mangle]` cannot be used on internal language items
#[panic_handler]
pub unsafe fn panic_fmt(pi: &PanicInfo) -> ! {
pub fn panic_fmt(pi: &PanicInfo) -> ! {
loop {}
}
4 changes: 2 additions & 2 deletions tests/ui/codegen/no-mangle-on-panic-handler.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ error: `#[no_mangle]` cannot be used on internal language items
LL | #[unsafe(no_mangle)]
| ^^^^^^^^^^^^^^^^^^^^
LL | #[panic_handler]
LL | pub unsafe fn panic_fmt(pi: &PanicInfo) -> ! {
| -------------------------------------------- should be the internal language item
LL | pub fn panic_fmt(pi: &PanicInfo) -> ! {
| ------------------------------------- should be the internal language item
|
= note: Rustc requires this item to have a specific mangled name.
= note: If you are trying to prevent mangling to ease debugging, many
Expand Down
12 changes: 12 additions & 0 deletions tests/ui/panic-handler/unsafe_panic_handler.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//@ check-pass
#![crate_type = "lib"]
#![no_std]

use core::panic::PanicInfo;

#[panic_handler]
unsafe fn handle(_: &PanicInfo) -> ! {
//~^ WARN `#[panic_handler]` functions can't be `unsafe`
//~| WARN this was previously accepted by the compiler but is being phased out
loop {}
}
12 changes: 12 additions & 0 deletions tests/ui/panic-handler/unsafe_panic_handler.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
warning: `#[panic_handler]` functions can't be `unsafe`
--> $DIR/unsafe_panic_handler.rs:8:1
|
LL | unsafe fn handle(_: &PanicInfo) -> ! {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #163263 <https://github.com/rust-lang/rust/issues/163263>
= note: `#[warn(unsafe_panic_handlers)]` on by default

warning: 1 warning emitted

Loading