Skip to content

Commit f13fc5f

Browse files
committed
Add rustc_panic_entrypoint
1 parent 9415853 commit f13fc5f

39 files changed

Lines changed: 276 additions & 158 deletions

File tree

compiler/rustc_codegen_cranelift/src/base.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use rustc_middle::ty::layout::FnAbiOf;
1414
use rustc_middle::ty::print::with_no_trimmed_paths;
1515
use rustc_session::config::OutputFilenames;
1616
use rustc_span::Symbol;
17+
use rustc_target::spec::PanicStrategy;
1718

1819
use crate::constant::ConstantCx;
1920
use crate::debuginfo::{FunctionDebugContext, TypeDebugContext};
@@ -384,6 +385,11 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
384385
fx.bcx.switch_to_block(failure);
385386
fx.bcx.ins().nop();
386387

388+
if fx.tcx.sess.panic_strategy() == PanicStrategy::ImmediateAbort {
389+
fx.bcx.ins().trap(TrapCode::user(1 /* unreachable */).unwrap());
390+
continue;
391+
}
392+
387393
match &**msg {
388394
AssertKind::BoundsCheck { len, index } => {
389395
let len = codegen_operand(fx, len).load_scalar(fx);
@@ -1052,6 +1058,10 @@ pub(crate) fn codegen_panic_nounwind<'tcx>(
10521058
msg_str: &str,
10531059
span: Span,
10541060
) {
1061+
if fx.tcx.sess.panic_strategy() == PanicStrategy::ImmediateAbort {
1062+
fx.bcx.ins().trap(TrapCode::user(1 /* unreachable */).unwrap());
1063+
}
1064+
10551065
let msg_ptr = crate::constant::pointer_for_anonymous_str(fx, msg_str);
10561066
let msg_len = fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(msg_str.len()).unwrap());
10571067
let args = [msg_ptr, msg_len];

compiler/rustc_codegen_ssa/src/codegen_attrs.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use rustc_abi::{Align, ExternAbi};
44
use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode};
55
use rustc_ast::{LitKind, MetaItem, MetaItemInner};
66
use rustc_hir::attrs::{
7-
AttributeKind, EiiImplResolution, InlineAttr, Linkage, RtsanSetting, UsedBy,
7+
AttributeKind, EiiImplResolution, InlineAttr, Linkage, OptimizeAttr, RtsanSetting, UsedBy,
88
};
99
use rustc_hir::def::DefKind;
1010
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
@@ -19,7 +19,7 @@ use rustc_middle::ty::{self as ty, TyCtxt};
1919
use rustc_session::lint;
2020
use rustc_session::parse::feature_err;
2121
use rustc_span::{Span, sym};
22-
use rustc_target::spec::Os;
22+
use rustc_target::spec::{Os, PanicStrategy};
2323

2424
use crate::errors;
2525
use crate::target_features::{
@@ -391,6 +391,24 @@ fn apply_overrides(tcx: TyCtxt<'_>, did: LocalDefId, codegen_fn_attrs: &mut Code
391391
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
392392
}
393393
}
394+
395+
if tcx.is_panic_entrypoint(did) {
396+
// Panic entrypoints are always cold.
397+
//
398+
// If we have immediate-abort enabled, we want them to be inlined.
399+
// They shouldn't be called, but on the off-chance that they are, they should be inlined.
400+
//
401+
// When the panic strategies that support panic messages are enabled, we want panic
402+
// entrypoints outlined and optimized for size.
403+
// Most panic entrypoints want #[track_caller] but not all, so we do not add it.
404+
codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD;
405+
if tcx.sess.panic_strategy() == PanicStrategy::ImmediateAbort {
406+
codegen_fn_attrs.inline = InlineAttr::Always;
407+
} else {
408+
codegen_fn_attrs.inline = InlineAttr::Never;
409+
codegen_fn_attrs.optimize = OptimizeAttr::Size;
410+
}
411+
}
394412
}
395413

396414
fn check_result(

compiler/rustc_codegen_ssa/src/mir/block.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use rustc_session::config::OptLevel;
1515
use rustc_span::Span;
1616
use rustc_span::source_map::Spanned;
1717
use rustc_target::callconv::{ArgAbi, ArgAttributes, CastTarget, FnAbi, PassMode};
18+
use rustc_target::spec::PanicStrategy;
1819
use tracing::{debug, info};
1920

2021
use super::operand::OperandRef;
@@ -737,6 +738,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
737738
bx.switch_to_block(panic_block);
738739
self.set_debug_loc(bx, terminator.source_info);
739740

741+
if bx.tcx().sess.panic_strategy() == PanicStrategy::ImmediateAbort {
742+
bx.abort();
743+
bx.unreachable();
744+
return MergingSucc::False;
745+
}
746+
740747
// Get the location information.
741748
let location = self.get_caller_location(bx, terminator.source_info).immediate();
742749

compiler/rustc_feature/src/builtin_attrs.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1329,6 +1329,10 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
13291329
"`#[rustc_has_incoherent_inherent_impls]` allows the addition of incoherent inherent impls for \
13301330
the given type by annotating all impl items with `#[rustc_allow_incoherent_impl]`"
13311331
),
1332+
rustc_attr!(
1333+
rustc_panic_entrypoint, Normal, template!(Word), WarnFollowing,
1334+
EncodeCrossCrate::Yes, "`#[rustc_panic_entrypoint]` makes this function patchable by panic=immediate-abort",
1335+
),
13321336

13331337
BuiltinAttribute {
13341338
name: sym::rustc_diagnostic_item,

compiler/rustc_hir/src/lang_items.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,7 @@ language_item_table! {
247247
FnMut, sym::fn_mut, fn_mut_trait, Target::Trait, GenericRequirement::Exact(1);
248248
FnOnce, sym::fn_once, fn_once_trait, Target::Trait, GenericRequirement::Exact(1);
249249

250+
AbortIntrinsic, sym::abort_intrinsic, abort_intrinsic, Target::Fn, GenericRequirement::Exact(0);
250251
AsyncFn, sym::async_fn, async_fn_trait, Target::Trait, GenericRequirement::Exact(1);
251252
AsyncFnMut, sym::async_fn_mut, async_fn_mut_trait, Target::Trait, GenericRequirement::Exact(1);
252253
AsyncFnOnce, sym::async_fn_once, async_fn_once_trait, Target::Trait, GenericRequirement::Exact(1);

compiler/rustc_lint/messages.ftl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,8 @@ lint_missing_gpu_kernel_export_name = function with the "gpu-kernel" ABI has a m
614614
.note = mangled names make it hard to find the kernel, this is usually not intended
615615
.help = use `unsafe(no_mangle)` or `unsafe(export_name = "<name>")`
616616
617+
lint_missing_panic_entrypoint = "diverging functions should usually have #[inline] or #[rustc_panic_entrypoint]"
618+
617619
lint_mixed_script_confusables =
618620
the usage of Script Group `{$set}` in this crate consists solely of mixed script confusables
619621
.includes_note = the usage includes {$includes}

compiler/rustc_lint/src/internal.rs

Lines changed: 85 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
//! Some lints that are only useful in the compiler or crates that use compiler internals, such as
22
//! Clippy.
33
4-
use rustc_hir::attrs::AttributeKind;
4+
use rustc_hir::attrs::{AttributeKind, InlineAttr};
55
use rustc_hir::def::Res;
66
use rustc_hir::def_id::DefId;
7-
use rustc_hir::{Expr, ExprKind, HirId, find_attr};
7+
use rustc_hir::intravisit::FnKind;
8+
use rustc_hir::{AttrPath, Body, Expr, ExprKind, FnDecl, HirId, find_attr};
89
use rustc_middle::ty::{self, GenericArgsRef, PredicatePolarity};
910
use rustc_session::{declare_lint_pass, declare_tool_lint};
11+
use rustc_span::def_id::LocalDefId;
1012
use rustc_span::hygiene::{ExpnKind, MacroKind};
1113
use rustc_span::{Span, sym};
1214
use {rustc_ast as ast, rustc_hir as hir};
@@ -627,3 +629,84 @@ impl EarlyLintPass for ImplicitSysrootCrateImport {
627629
}
628630
}
629631
}
632+
633+
declare_tool_lint! {
634+
/// The `missing_panic_entrypoint` lint detects forgotten use of #[rustc_panic_entrypoint].
635+
///
636+
/// This lint is intended to ensure that panic=immediate-abort can function as designed,
637+
/// because it uses #[rustc_panic_entrypoint] to locate functions that should be outlined
638+
/// for other panic modes, and be deleted entirely when immediate-abort is enabled.
639+
pub rustc::MISSING_PANIC_ENTRYPOINT,
640+
Allow,
641+
"detects missing #[rustc_panic_entrypoint]",
642+
report_in_external_macro: true
643+
}
644+
645+
declare_lint_pass!(MissingPanicEntrypoint => [MISSING_PANIC_ENTRYPOINT]);
646+
647+
fn has_panic_entrypoint(attrs: &[hir::Attribute]) -> bool {
648+
attrs.iter().any(|attr| {
649+
if let hir::Attribute::Unparsed(box hir::AttrItem {
650+
path: AttrPath { segments, .. }, ..
651+
}) = attr
652+
{
653+
if segments[0] == sym::rustc_panic_entrypoint {
654+
return true;
655+
}
656+
}
657+
false
658+
})
659+
}
660+
661+
fn has_inline_encouragement(attrs: &[hir::Attribute]) -> bool {
662+
attrs.iter().any(|attr| {
663+
matches!(
664+
attr,
665+
hir::Attribute::Parsed(hir::attrs::AttributeKind::Inline(
666+
InlineAttr::Hint | InlineAttr::Always | InlineAttr::Force { .. },
667+
_
668+
))
669+
)
670+
})
671+
}
672+
673+
fn has_rustc_intrinsic(attrs: &[hir::Attribute]) -> bool {
674+
attrs.iter().any(|attr| {
675+
if let hir::Attribute::Unparsed(box hir::AttrItem {
676+
path: AttrPath { segments, .. }, ..
677+
}) = attr
678+
{
679+
if segments[0] == sym::rustc_intrinsic {
680+
return true;
681+
}
682+
}
683+
false
684+
})
685+
}
686+
687+
impl<'tcx> LateLintPass<'tcx> for MissingPanicEntrypoint {
688+
fn check_fn(
689+
&mut self,
690+
cx: &LateContext<'tcx>,
691+
_: FnKind<'tcx>,
692+
fn_decl: &'tcx FnDecl<'tcx>,
693+
_: &'tcx Body<'tcx>,
694+
span: Span,
695+
def_id: LocalDefId,
696+
) {
697+
if matches!(fn_decl.output, hir::FnRetTy::Return(hir::Ty { kind: hir::TyKind::Never, .. }))
698+
{
699+
let attrs = cx.tcx.hir_attrs(cx.tcx.local_def_id_to_hir_id(def_id));
700+
if has_rustc_intrinsic(attrs) {
701+
return;
702+
}
703+
if !has_inline_encouragement(attrs) && !has_panic_entrypoint(attrs) {
704+
cx.emit_span_lint(
705+
MISSING_PANIC_ENTRYPOINT,
706+
span,
707+
crate::lints::MissingPanicEntrypoint,
708+
);
709+
}
710+
}
711+
}
712+
}

compiler/rustc_lint/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ late_lint_methods!(
240240
MapUnitFn: MapUnitFn,
241241
MissingDebugImplementations: MissingDebugImplementations,
242242
MissingDoc: MissingDoc,
243+
MissingPanicEntrypoint: MissingPanicEntrypoint,
243244
AsyncClosureUsage: AsyncClosureUsage,
244245
AsyncFnInTrait: AsyncFnInTrait,
245246
NonLocalDefinitions: NonLocalDefinitions::default(),

compiler/rustc_lint/src/lints.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3325,3 +3325,7 @@ pub(crate) struct UnknownCrateTypesSuggestion {
33253325
pub span: Span,
33263326
pub snippet: Symbol,
33273327
}
3328+
3329+
#[derive(LintDiagnostic)]
3330+
#[diag(lint_missing_panic_entrypoint)]
3331+
pub(crate) struct MissingPanicEntrypoint;

compiler/rustc_middle/src/ty/context.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ use rustc_session::config::CrateType;
4949
use rustc_session::cstore::{CrateStoreDyn, Untracked};
5050
use rustc_session::lint::Lint;
5151
use rustc_span::def_id::{CRATE_DEF_ID, DefPathHash, StableCrateId};
52-
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw};
52+
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
5353
use rustc_type_ir::TyKind::*;
5454
use rustc_type_ir::lang_items::{SolverAdtLangItem, SolverLangItem, SolverTraitLangItem};
5555
pub use rustc_type_ir::lift::Lift;
@@ -3556,6 +3556,10 @@ impl<'tcx> TyCtxt<'tcx> {
35563556
}
35573557
false
35583558
}
3559+
3560+
pub fn is_panic_entrypoint(self, def_id: impl Into<DefId>) -> bool {
3561+
self.has_attr(def_id, sym::rustc_panic_entrypoint)
3562+
}
35593563
}
35603564

35613565
pub fn provide(providers: &mut Providers) {

0 commit comments

Comments
 (0)