|
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 |
|
@@ -800,3 +803,69 @@ impl<'tcx> LateLintPass<'tcx> for RustcMustMatchExhaustively { |
800 | 803 | } |
801 | 804 | } |
802 | 805 | } |
| 806 | + |
| 807 | +declare_tool_lint! { |
| 808 | + /// The `missing_panic_entrypoint` lint detects forgotten use of #[rustc_panic_entrypoint]. |
| 809 | + /// |
| 810 | + /// This lint is intended to ensure that panic=immediate-abort can function as designed, |
| 811 | + /// because it uses #[rustc_panic_entrypoint] to locate functions that should be outlined |
| 812 | + /// for other panic modes, and be deleted entirely when immediate-abort is enabled. |
| 813 | + /// |
| 814 | + /// The current design of this lint is expected to have a lot of false positives outside of core |
| 815 | + /// and alloc. |
| 816 | + pub rustc::MISSING_PANIC_ENTRYPOINT, |
| 817 | + Allow, |
| 818 | + "detects missing #[rustc_panic_entrypoint]", |
| 819 | + report_in_external_macro: true |
| 820 | +} |
| 821 | + |
| 822 | +declare_lint_pass!(MissingPanicEntrypoint => [MISSING_PANIC_ENTRYPOINT]); |
| 823 | + |
| 824 | +fn has_panic_entrypoint(attrs: &[hir::Attribute]) -> bool { |
| 825 | + attrs |
| 826 | + .iter() |
| 827 | + .any(|attr| matches!(attr, hir::Attribute::Parsed(AttributeKind::RustcPanicEntrypoint))) |
| 828 | +} |
| 829 | + |
| 830 | +fn has_inline_encouragement(attrs: &[hir::Attribute]) -> bool { |
| 831 | + attrs.iter().any(|attr| { |
| 832 | + matches!( |
| 833 | + attr, |
| 834 | + hir::Attribute::Parsed(hir::attrs::AttributeKind::Inline( |
| 835 | + InlineAttr::Hint | InlineAttr::Always | InlineAttr::Force { .. }, |
| 836 | + _ |
| 837 | + )) |
| 838 | + ) |
| 839 | + }) |
| 840 | +} |
| 841 | + |
| 842 | +fn has_rustc_intrinsic(attrs: &[hir::Attribute]) -> bool { |
| 843 | + attrs.iter().any(|attr| matches!(attr, hir::Attribute::Parsed(AttributeKind::RustcIntrinsic))) |
| 844 | +} |
| 845 | + |
| 846 | +impl<'tcx> LateLintPass<'tcx> for MissingPanicEntrypoint { |
| 847 | + fn check_fn( |
| 848 | + &mut self, |
| 849 | + cx: &LateContext<'tcx>, |
| 850 | + _: FnKind<'tcx>, |
| 851 | + fn_decl: &'tcx FnDecl<'tcx>, |
| 852 | + _: &'tcx Body<'tcx>, |
| 853 | + span: Span, |
| 854 | + def_id: LocalDefId, |
| 855 | + ) { |
| 856 | + if matches!(fn_decl.output, hir::FnRetTy::Return(hir::Ty { kind: hir::TyKind::Never, .. })) |
| 857 | + { |
| 858 | + let attrs = cx.tcx.hir_attrs(cx.tcx.local_def_id_to_hir_id(def_id)); |
| 859 | + if has_rustc_intrinsic(attrs) { |
| 860 | + return; |
| 861 | + } |
| 862 | + if !has_inline_encouragement(attrs) && !has_panic_entrypoint(attrs) { |
| 863 | + cx.emit_span_lint( |
| 864 | + MISSING_PANIC_ENTRYPOINT, |
| 865 | + span, |
| 866 | + crate::lints::MissingPanicEntrypoint, |
| 867 | + ); |
| 868 | + } |
| 869 | + } |
| 870 | + } |
| 871 | +} |
0 commit comments