@@ -25,11 +25,11 @@ use rustc_attr_parsing::AttributeParser;
2525use rustc_errors:: { Applicability , LintDiagnostic } ;
2626use rustc_feature:: GateIssue ;
2727use rustc_hir as hir;
28- use rustc_hir:: attrs:: { AttributeKind , DocAttribute } ;
28+ use rustc_hir:: attrs:: { AttributeKind , DocAttribute , InlineAttr } ;
2929use rustc_hir:: def:: { DefKind , Res } ;
3030use rustc_hir:: def_id:: { CRATE_DEF_ID , DefId , LocalDefId } ;
3131use rustc_hir:: intravisit:: FnKind as HirFnKind ;
32- use rustc_hir:: { Body , FnDecl , ImplItemImplKind , PatKind , PredicateOrigin , find_attr} ;
32+ use rustc_hir:: { AttrPath , Body , FnDecl , ImplItemImplKind , PatKind , PredicateOrigin , find_attr} ;
3333use rustc_middle:: bug;
3434use rustc_middle:: lint:: LevelAndSource ;
3535use rustc_middle:: ty:: layout:: LayoutOf ;
@@ -3187,3 +3187,97 @@ impl EarlyLintPass for SpecialModuleName {
31873187 }
31883188 }
31893189}
3190+
3191+ declare_lint ! {
3192+ /// The `missing_panic_entrypoint` lint detects forgotten use of #[rustc_panic_entrypoint]
3193+ ///
3194+ /// ### Example
3195+ ///
3196+ /// ```rust,compile_fail
3197+ /// #[deny(missing_panic_entrypoint)]
3198+ /// pub fn panic() -> ! {}
3199+ /// ```
3200+ ///
3201+ /// {{produces}}
3202+ ///
3203+ /// ### Explanation
3204+ ///
3205+ /// This lint is intended to ensure that panic=immediate-abort can function as designed,
3206+ /// because it uses #[rustc_panic_entrypoint] to locate functions that should be outlined
3207+ /// for other panic modes, and be deleted entirely when immediate-abort is enabled.
3208+ pub MISSING_PANIC_ENTRYPOINT ,
3209+ Allow ,
3210+ "detects missing #[rustc_panic_entrypoint]" ,
3211+ }
3212+
3213+ #[ derive( Default ) ]
3214+ pub struct MissingPanicEntrypoint ;
3215+
3216+ impl_lint_pass ! ( MissingPanicEntrypoint => [ MISSING_PANIC_ENTRYPOINT ] ) ;
3217+
3218+ fn has_panic_entrypoint ( attrs : & [ hir:: Attribute ] ) -> bool {
3219+ attrs. iter ( ) . any ( |attr| {
3220+ if let hir:: Attribute :: Unparsed ( box hir:: AttrItem {
3221+ path : AttrPath { segments, .. } , ..
3222+ } ) = attr
3223+ {
3224+ if segments[ 0 ] . name == sym:: rustc_panic_entrypoint {
3225+ return true ;
3226+ }
3227+ }
3228+ false
3229+ } )
3230+ }
3231+
3232+ fn has_inline_encouragement ( attrs : & [ hir:: Attribute ] ) -> bool {
3233+ attrs. iter ( ) . any ( |attr| {
3234+ matches ! (
3235+ attr,
3236+ hir:: Attribute :: Parsed ( hir:: attrs:: AttributeKind :: Inline (
3237+ InlineAttr :: Hint | InlineAttr :: Always | InlineAttr :: Force { .. } ,
3238+ _
3239+ ) )
3240+ )
3241+ } )
3242+ }
3243+
3244+ fn has_rustc_intrinsic ( attrs : & [ hir:: Attribute ] ) -> bool {
3245+ attrs. iter ( ) . any ( |attr| {
3246+ if let hir:: Attribute :: Unparsed ( box hir:: AttrItem {
3247+ path : AttrPath { segments, .. } , ..
3248+ } ) = attr
3249+ {
3250+ if segments[ 0 ] . name == sym:: rustc_intrinsic {
3251+ return true ;
3252+ }
3253+ }
3254+ false
3255+ } )
3256+ }
3257+
3258+ impl < ' tcx > LateLintPass < ' tcx > for MissingPanicEntrypoint {
3259+ fn check_fn (
3260+ & mut self ,
3261+ cx : & LateContext < ' tcx > ,
3262+ _: HirFnKind < ' tcx > ,
3263+ fn_decl : & ' tcx FnDecl < ' tcx > ,
3264+ _: & ' tcx Body < ' tcx > ,
3265+ span : Span ,
3266+ def_id : LocalDefId ,
3267+ ) {
3268+ if matches ! ( fn_decl. output, hir:: FnRetTy :: Return ( hir:: Ty { kind: hir:: TyKind :: Never , .. } ) )
3269+ {
3270+ let attrs = cx. tcx . hir_attrs ( cx. tcx . local_def_id_to_hir_id ( def_id) ) ;
3271+ if has_rustc_intrinsic ( attrs) {
3272+ return ;
3273+ }
3274+ if !has_inline_encouragement ( attrs) && !has_panic_entrypoint ( attrs) {
3275+ cx. emit_span_lint (
3276+ MISSING_PANIC_ENTRYPOINT ,
3277+ span,
3278+ crate :: lints:: MissingPanicEntrypoint ,
3279+ ) ;
3280+ }
3281+ }
3282+ }
3283+ }
0 commit comments