|
4 | 4 | use rustc_ast as ast; |
5 | 5 | use rustc_ast::{Pat, PatKind, Path}; |
6 | 6 | use rustc_hir as hir; |
| 7 | +use rustc_hir::attrs::{AttributeKind, InlineAttr}; |
7 | 8 | use rustc_hir::def::Res; |
8 | 9 | use rustc_hir::def_id::DefId; |
9 | | -use rustc_hir::{Expr, ExprKind, HirId, find_attr}; |
| 10 | +use rustc_hir::intravisit::FnKind; |
| 11 | +use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId, find_attr}; |
10 | 12 | use rustc_middle::ty::{self, GenericArgsRef, PredicatePolarity}; |
11 | 13 | use rustc_session::{declare_lint_pass, declare_tool_lint}; |
| 14 | +use rustc_span::def_id::LocalDefId; |
12 | 15 | use rustc_span::hygiene::{ExpnKind, MacroKind}; |
13 | 16 | use rustc_span::{Span, sym}; |
14 | 17 |
|
@@ -713,3 +716,69 @@ impl EarlyLintPass for BadUseOfFindAttr { |
713 | 716 | } |
714 | 717 | } |
715 | 718 | } |
| 719 | + |
| 720 | +declare_tool_lint! { |
| 721 | + /// The `missing_panic_entrypoint` lint detects forgotten use of #[rustc_panic_entrypoint]. |
| 722 | + /// |
| 723 | + /// This lint is intended to ensure that panic=immediate-abort can function as designed, |
| 724 | + /// because it uses #[rustc_panic_entrypoint] to locate functions that should be outlined |
| 725 | + /// for other panic modes, and be deleted entirely when immediate-abort is enabled. |
| 726 | + /// |
| 727 | + /// The current design of this lint is expected to have a lot of false positives outside of core |
| 728 | + /// and alloc. |
| 729 | + pub rustc::MISSING_PANIC_ENTRYPOINT, |
| 730 | + Allow, |
| 731 | + "detects missing #[rustc_panic_entrypoint]", |
| 732 | + report_in_external_macro: true |
| 733 | +} |
| 734 | + |
| 735 | +declare_lint_pass!(MissingPanicEntrypoint => [MISSING_PANIC_ENTRYPOINT]); |
| 736 | + |
| 737 | +fn has_panic_entrypoint(attrs: &[hir::Attribute]) -> bool { |
| 738 | + attrs |
| 739 | + .iter() |
| 740 | + .any(|attr| matches!(attr, hir::Attribute::Parsed(AttributeKind::RustcPanicEntrypoint))) |
| 741 | +} |
| 742 | + |
| 743 | +fn has_inline_encouragement(attrs: &[hir::Attribute]) -> bool { |
| 744 | + attrs.iter().any(|attr| { |
| 745 | + matches!( |
| 746 | + attr, |
| 747 | + hir::Attribute::Parsed(hir::attrs::AttributeKind::Inline( |
| 748 | + InlineAttr::Hint | InlineAttr::Always | InlineAttr::Force { .. }, |
| 749 | + _ |
| 750 | + )) |
| 751 | + ) |
| 752 | + }) |
| 753 | +} |
| 754 | + |
| 755 | +fn has_rustc_intrinsic(attrs: &[hir::Attribute]) -> bool { |
| 756 | + attrs.iter().any(|attr| matches!(attr, hir::Attribute::Parsed(AttributeKind::RustcIntrinsic))) |
| 757 | +} |
| 758 | + |
| 759 | +impl<'tcx> LateLintPass<'tcx> for MissingPanicEntrypoint { |
| 760 | + fn check_fn( |
| 761 | + &mut self, |
| 762 | + cx: &LateContext<'tcx>, |
| 763 | + _: FnKind<'tcx>, |
| 764 | + fn_decl: &'tcx FnDecl<'tcx>, |
| 765 | + _: &'tcx Body<'tcx>, |
| 766 | + span: Span, |
| 767 | + def_id: LocalDefId, |
| 768 | + ) { |
| 769 | + if matches!(fn_decl.output, hir::FnRetTy::Return(hir::Ty { kind: hir::TyKind::Never, .. })) |
| 770 | + { |
| 771 | + let attrs = cx.tcx.hir_attrs(cx.tcx.local_def_id_to_hir_id(def_id)); |
| 772 | + if has_rustc_intrinsic(attrs) { |
| 773 | + return; |
| 774 | + } |
| 775 | + if !has_inline_encouragement(attrs) && !has_panic_entrypoint(attrs) { |
| 776 | + cx.emit_span_lint( |
| 777 | + MISSING_PANIC_ENTRYPOINT, |
| 778 | + span, |
| 779 | + crate::lints::MissingPanicEntrypoint, |
| 780 | + ); |
| 781 | + } |
| 782 | + } |
| 783 | + } |
| 784 | +} |
0 commit comments