@@ -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,100 @@ 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+ /// # #![cfg(not(bootstrap))]
3198+ /// #[deny(missing_panic_entrypoint)]
3199+ /// pub fn panic_wrapper() -> ! {
3200+ /// panic!("ouch!")
3201+ /// }
3202+ /// ```
3203+ ///
3204+ /// {{produces}}
3205+ ///
3206+ /// ### Explanation
3207+ ///
3208+ /// This lint is intended to ensure that panic=immediate-abort can function as designed,
3209+ /// because it uses #[rustc_panic_entrypoint] to locate functions that should be outlined
3210+ /// for other panic modes, and be deleted entirely when immediate-abort is enabled.
3211+ pub MISSING_PANIC_ENTRYPOINT ,
3212+ Allow ,
3213+ "detects missing #[rustc_panic_entrypoint]" ,
3214+ }
3215+
3216+ #[ derive( Default ) ]
3217+ pub struct MissingPanicEntrypoint ;
3218+
3219+ impl_lint_pass ! ( MissingPanicEntrypoint => [ MISSING_PANIC_ENTRYPOINT ] ) ;
3220+
3221+ fn has_panic_entrypoint ( attrs : & [ hir:: Attribute ] ) -> bool {
3222+ attrs. iter ( ) . any ( |attr| {
3223+ if let hir:: Attribute :: Unparsed ( box hir:: AttrItem {
3224+ path : AttrPath { segments, .. } , ..
3225+ } ) = attr
3226+ {
3227+ if segments[ 0 ] . name == sym:: rustc_panic_entrypoint {
3228+ return true ;
3229+ }
3230+ }
3231+ false
3232+ } )
3233+ }
3234+
3235+ fn has_inline_encouragement ( attrs : & [ hir:: Attribute ] ) -> bool {
3236+ attrs. iter ( ) . any ( |attr| {
3237+ matches ! (
3238+ attr,
3239+ hir:: Attribute :: Parsed ( hir:: attrs:: AttributeKind :: Inline (
3240+ InlineAttr :: Hint | InlineAttr :: Always | InlineAttr :: Force { .. } ,
3241+ _
3242+ ) )
3243+ )
3244+ } )
3245+ }
3246+
3247+ fn has_rustc_intrinsic ( attrs : & [ hir:: Attribute ] ) -> bool {
3248+ attrs. iter ( ) . any ( |attr| {
3249+ if let hir:: Attribute :: Unparsed ( box hir:: AttrItem {
3250+ path : AttrPath { segments, .. } , ..
3251+ } ) = attr
3252+ {
3253+ if segments[ 0 ] . name == sym:: rustc_intrinsic {
3254+ return true ;
3255+ }
3256+ }
3257+ false
3258+ } )
3259+ }
3260+
3261+ impl < ' tcx > LateLintPass < ' tcx > for MissingPanicEntrypoint {
3262+ fn check_fn (
3263+ & mut self ,
3264+ cx : & LateContext < ' tcx > ,
3265+ _: HirFnKind < ' tcx > ,
3266+ fn_decl : & ' tcx FnDecl < ' tcx > ,
3267+ _: & ' tcx Body < ' tcx > ,
3268+ span : Span ,
3269+ def_id : LocalDefId ,
3270+ ) {
3271+ if matches ! ( fn_decl. output, hir:: FnRetTy :: Return ( hir:: Ty { kind: hir:: TyKind :: Never , .. } ) )
3272+ {
3273+ let attrs = cx. tcx . hir_attrs ( cx. tcx . local_def_id_to_hir_id ( def_id) ) ;
3274+ if has_rustc_intrinsic ( attrs) {
3275+ return ;
3276+ }
3277+ if !has_inline_encouragement ( attrs) && !has_panic_entrypoint ( attrs) {
3278+ cx. emit_span_lint (
3279+ MISSING_PANIC_ENTRYPOINT ,
3280+ span,
3281+ crate :: lints:: MissingPanicEntrypoint ,
3282+ ) ;
3283+ }
3284+ }
3285+ }
3286+ }
0 commit comments