@@ -18,6 +18,7 @@ use rustc_session::{Session, lint};
1818use rustc_span:: symbol:: Ident ;
1919use rustc_span:: { 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,31 +523,50 @@ 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- match attr. meta_kind ( ) {
529- Some ( MetaItemKind :: Word ) => InlineAttr :: Hint ,
530- Some ( MetaItemKind :: List ( ref items) ) => {
531- inline_span = Some ( attr. span ) ;
532- if items. len ( ) != 1 {
533- struct_span_code_err ! ( tcx. dcx( ) , attr. span, E0534 , "expected one argument" )
534- . emit ( ) ;
535- InlineAttr :: None
536- } else if list_contains_name ( items, sym:: always) {
537- InlineAttr :: Always
538- } else if list_contains_name ( items, sym:: never) {
539- InlineAttr :: Never
540- } else {
541- struct_span_code_err ! ( tcx. dcx( ) , items[ 0 ] . span( ) , E0535 , "invalid argument" )
526+ if attr. has_name ( sym:: inline) {
527+ match attr. meta_kind ( ) {
528+ Some ( MetaItemKind :: Word ) => InlineAttr :: Hint ,
529+ Some ( MetaItemKind :: List ( ref items) ) => {
530+ inline_span = Some ( attr. span ) ;
531+ if items. len ( ) != 1 {
532+ struct_span_code_err ! ( tcx. dcx( ) , attr. span, E0534 , "expected one argument" )
533+ . 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 ! (
541+ tcx. dcx( ) ,
542+ items[ 0 ] . span( ) ,
543+ E0535 ,
544+ "invalid argument"
545+ )
542546 . with_help ( "valid inline arguments are `always` and `never`" )
543547 . emit ( ) ;
544548
545- InlineAttr :: None
549+ InlineAttr :: None
550+ }
546551 }
552+ Some ( MetaItemKind :: NameValue ( _) ) => ia,
553+ None => ia,
547554 }
548- Some ( MetaItemKind :: NameValue ( _) ) => ia,
549- None => ia,
555+ } else if attr. has_name ( sym:: rustc_force_inline) && tcx. features ( ) . rustc_attrs ( ) {
556+ match attr. meta_kind ( ) {
557+ Some ( MetaItemKind :: NameValue ( lit) ) => {
558+ InlineAttr :: Force { attr_span : attr. span , reason : Some ( lit. symbol ) }
559+ }
560+ Some ( MetaItemKind :: Word ) => {
561+ InlineAttr :: Force { attr_span : attr. span , reason : None }
562+ }
563+ _ => {
564+ debug ! ( "`rustc_force_inline` not checked by attribute validation" ) ;
565+ ia
566+ }
567+ }
568+ } else {
569+ ia
550570 }
551571 } ) ;
552572
@@ -601,7 +621,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
601621 // is probably a poor usage of `#[inline(always)]` and easily avoided by not using the attribute.
602622 if tcx. features ( ) . target_feature_11 ( )
603623 && tcx. is_closure_like ( did. to_def_id ( ) )
604- && codegen_fn_attrs. inline != InlineAttr :: Always
624+ && ! codegen_fn_attrs. inline . always ( )
605625 {
606626 let owner_id = tcx. parent ( did. to_def_id ( ) ) ;
607627 if tcx. def_kind ( owner_id) . has_codegen_attrs ( ) {
@@ -611,11 +631,15 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
611631 }
612632 }
613633
614- // If a function uses #[target_feature] it can't be inlined into general
634+ // If a function uses ` #[target_feature]` it can't be inlined into general
615635 // purpose functions as they wouldn't have the right target features
616- // enabled. For that reason we also forbid #[inline(always)] as it can't be
636+ // enabled. For that reason we also forbid ` #[inline(always)]` as it can't be
617637 // respected.
618- if !codegen_fn_attrs. target_features . is_empty ( ) && codegen_fn_attrs. inline == InlineAttr :: Always
638+ //
639+ // `#[rustc_force_inline]` doesn't need to be prohibited here, that
640+ // is implemented entirely in rustc can attempt to inline and error if it cannot.
641+ if !codegen_fn_attrs. target_features . is_empty ( )
642+ && matches ! ( codegen_fn_attrs. inline, InlineAttr :: Always )
619643 {
620644 if let Some ( span) = inline_span {
621645 tcx. dcx ( ) . span_err (
@@ -626,7 +650,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
626650 }
627651 }
628652
629- if !codegen_fn_attrs. no_sanitize . is_empty ( ) && codegen_fn_attrs. inline == InlineAttr :: Always {
653+ if !codegen_fn_attrs. no_sanitize . is_empty ( ) && codegen_fn_attrs. inline . always ( ) {
630654 if let ( Some ( no_sanitize_span) , Some ( inline_span) ) = ( no_sanitize_span, inline_span) {
631655 let hir_id = tcx. local_def_id_to_hir_id ( did) ;
632656 tcx. node_span_lint (
0 commit comments