|
1 | 1 | //! Some lints that are only useful in the compiler or crates that use compiler internals, such as |
2 | 2 | //! Clippy. |
3 | 3 |
|
4 | | -use rustc_hir::attrs::AttributeKind; |
| 4 | +use rustc_hir::attrs::{AttributeKind, InlineAttr}; |
5 | 5 | use rustc_hir::def::Res; |
6 | 6 | 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}; |
8 | 9 | use rustc_middle::ty::{self, GenericArgsRef, PredicatePolarity}; |
9 | 10 | use rustc_session::{declare_lint_pass, declare_tool_lint}; |
| 11 | +use rustc_span::def_id::LocalDefId; |
10 | 12 | use rustc_span::hygiene::{ExpnKind, MacroKind}; |
11 | 13 | use rustc_span::{Span, sym}; |
12 | 14 | use {rustc_ast as ast, rustc_hir as hir}; |
@@ -627,3 +629,84 @@ impl EarlyLintPass for ImplicitSysrootCrateImport { |
627 | 629 | } |
628 | 630 | } |
629 | 631 | } |
| 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 | +} |
0 commit comments