@@ -18,6 +18,7 @@ use rustc_session::parse::feature_err;
1818use rustc_session:: { Session , lint} ;
1919use rustc_span:: { Ident , Span , sym} ;
2020use rustc_target:: spec:: { SanitizerSet , abi} ;
21+ use tracing:: debug;
2122
2223use crate :: errors;
2324use crate :: target_features:: { check_target_feature_trait_unsafe, from_target_feature_attr} ;
@@ -522,26 +523,36 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
522523 mixed_export_name_no_mangle_lint_state. lint_if_mixed ( tcx) ;
523524
524525 codegen_fn_attrs. inline = attrs. iter ( ) . fold ( InlineAttr :: None , |ia, attr| {
525- if !attr. has_name ( sym:: inline) {
526- return ia;
527- }
528- if attr. is_word ( ) {
529- InlineAttr :: Hint
530- } else if let Some ( ref items) = attr. meta_item_list ( ) {
531- inline_span = Some ( attr. span ) ;
532- if items. len ( ) != 1 {
533- struct_span_code_err ! ( tcx. dcx( ) , attr. span, E0534 , "expected one argument" ) . emit ( ) ;
534- InlineAttr :: None
535- } else if list_contains_name ( items, sym:: always) {
536- InlineAttr :: Always
537- } else if list_contains_name ( items, sym:: never) {
538- InlineAttr :: Never
539- } else {
540- struct_span_code_err ! ( tcx. dcx( ) , items[ 0 ] . span( ) , E0535 , "invalid argument" )
541- . with_help ( "valid inline arguments are `always` and `never`" )
542- . emit ( ) ;
526+ if attr. has_name ( sym:: inline) {
527+ if attr. is_word ( ) {
528+ InlineAttr :: Hint
529+ } else if let Some ( ref items) = attr. meta_item_list ( ) {
530+ inline_span = Some ( attr. span ) ;
531+ if items. len ( ) != 1 {
532+ struct_span_code_err ! ( tcx. dcx( ) , attr. span, E0534 , "expected one argument" ) . emit ( ) ;
533+ InlineAttr :: None
534+ } else if list_contains_name ( items, sym:: always) {
535+ InlineAttr :: Always
536+ } else if list_contains_name ( items, sym:: never) {
537+ InlineAttr :: Never
538+ } else {
539+ struct_span_code_err ! ( tcx. dcx( ) , items[ 0 ] . span( ) , E0535 , "invalid argument" )
540+ . with_help ( "valid inline arguments are `always` and `never`" )
541+ . emit ( ) ;
543542
544- InlineAttr :: None
543+ InlineAttr :: None
544+ }
545+ } else {
546+ ia
547+ }
548+ } else if attr. has_name ( sym:: rustc_force_inline) && tcx. features ( ) . rustc_attrs ( ) {
549+ if attr. is_word ( ) {
550+ InlineAttr :: Force { attr_span : attr. span , reason : None }
551+ } else if let Some ( val) = attr. value_str ( ) {
552+ InlineAttr :: Force { attr_span : attr. span , reason : Some ( val) }
553+ } else {
554+ debug ! ( "`rustc_force_inline` not checked by attribute validation" ) ;
555+ ia
545556 }
546557 } else {
547558 ia
@@ -596,7 +607,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
596607 // is probably a poor usage of `#[inline(always)]` and easily avoided by not using the attribute.
597608 if tcx. features ( ) . target_feature_11 ( )
598609 && tcx. is_closure_like ( did. to_def_id ( ) )
599- && codegen_fn_attrs. inline != InlineAttr :: Always
610+ && ! codegen_fn_attrs. inline . always ( )
600611 {
601612 let owner_id = tcx. parent ( did. to_def_id ( ) ) ;
602613 if tcx. def_kind ( owner_id) . has_codegen_attrs ( ) {
@@ -606,11 +617,15 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
606617 }
607618 }
608619
609- // If a function uses #[target_feature] it can't be inlined into general
620+ // If a function uses ` #[target_feature]` it can't be inlined into general
610621 // purpose functions as they wouldn't have the right target features
611- // enabled. For that reason we also forbid #[inline(always)] as it can't be
622+ // enabled. For that reason we also forbid ` #[inline(always)]` as it can't be
612623 // respected.
613- if !codegen_fn_attrs. target_features . is_empty ( ) && codegen_fn_attrs. inline == InlineAttr :: Always
624+ //
625+ // `#[rustc_force_inline]` doesn't need to be prohibited here, that
626+ // is implemented entirely in rustc can attempt to inline and error if it cannot.
627+ if !codegen_fn_attrs. target_features . is_empty ( )
628+ && matches ! ( codegen_fn_attrs. inline, InlineAttr :: Always )
614629 {
615630 if let Some ( span) = inline_span {
616631 tcx. dcx ( ) . span_err (
@@ -621,7 +636,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
621636 }
622637 }
623638
624- if !codegen_fn_attrs. no_sanitize . is_empty ( ) && codegen_fn_attrs. inline == InlineAttr :: Always {
639+ if !codegen_fn_attrs. no_sanitize . is_empty ( ) && codegen_fn_attrs. inline . always ( ) {
625640 if let ( Some ( no_sanitize_span) , Some ( inline_span) ) = ( no_sanitize_span, inline_span) {
626641 let hir_id = tcx. local_def_id_to_hir_id ( did) ;
627642 tcx. node_span_lint (
0 commit comments