@@ -19,6 +19,7 @@ use rustc_session::{Session, lint};
1919use rustc_span:: symbol:: Ident ;
2020use rustc_span:: { Span , sym} ;
2121use rustc_target:: spec:: { SanitizerSet , abi} ;
22+ use tracing:: debug;
2223
2324use crate :: errors;
2425use crate :: target_features:: { check_target_feature_trait_unsafe, from_target_feature_attr} ;
@@ -514,31 +515,50 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
514515 }
515516
516517 codegen_fn_attrs. inline = attrs. iter ( ) . fold ( InlineAttr :: None , |ia, attr| {
517- if !attr. has_name ( sym:: inline) {
518- return ia;
519- }
520- match attr. meta_kind ( ) {
521- Some ( MetaItemKind :: Word ) => InlineAttr :: Hint ,
522- Some ( MetaItemKind :: List ( ref items) ) => {
523- inline_span = Some ( attr. span ) ;
524- if items. len ( ) != 1 {
525- struct_span_code_err ! ( tcx. dcx( ) , attr. span, E0534 , "expected one argument" )
526- . emit ( ) ;
527- InlineAttr :: None
528- } else if list_contains_name ( items, sym:: always) {
529- InlineAttr :: Always
530- } else if list_contains_name ( items, sym:: never) {
531- InlineAttr :: Never
532- } else {
533- struct_span_code_err ! ( tcx. dcx( ) , items[ 0 ] . span( ) , E0535 , "invalid argument" )
518+ if attr. has_name ( sym:: inline) {
519+ match attr. meta_kind ( ) {
520+ Some ( MetaItemKind :: Word ) => InlineAttr :: Hint ,
521+ Some ( MetaItemKind :: List ( ref items) ) => {
522+ inline_span = Some ( attr. span ) ;
523+ if items. len ( ) != 1 {
524+ struct_span_code_err ! ( tcx. dcx( ) , attr. span, E0534 , "expected one argument" )
525+ . emit ( ) ;
526+ InlineAttr :: None
527+ } else if list_contains_name ( items, sym:: always) {
528+ InlineAttr :: Always
529+ } else if list_contains_name ( items, sym:: never) {
530+ InlineAttr :: Never
531+ } else {
532+ struct_span_code_err ! (
533+ tcx. dcx( ) ,
534+ items[ 0 ] . span( ) ,
535+ E0535 ,
536+ "invalid argument"
537+ )
534538 . with_help ( "valid inline arguments are `always` and `never`" )
535539 . emit ( ) ;
536540
537- InlineAttr :: None
541+ InlineAttr :: None
542+ }
538543 }
544+ Some ( MetaItemKind :: NameValue ( _) ) => ia,
545+ None => ia,
539546 }
540- Some ( MetaItemKind :: NameValue ( _) ) => ia,
541- None => ia,
547+ } else if attr. has_name ( sym:: rustc_force_inline) && tcx. features ( ) . rustc_attrs ( ) {
548+ match attr. meta_kind ( ) {
549+ Some ( MetaItemKind :: NameValue ( lit) ) => {
550+ InlineAttr :: Force { attr_span : attr. span , reason : Some ( lit. symbol ) }
551+ }
552+ Some ( MetaItemKind :: Word ) => {
553+ InlineAttr :: Force { attr_span : attr. span , reason : None }
554+ }
555+ _ => {
556+ debug ! ( "`rustc_force_inline` not checked by attribute validation" ) ;
557+ ia
558+ }
559+ }
560+ } else {
561+ ia
542562 }
543563 } ) ;
544564
@@ -586,7 +606,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
586606 // is probably a poor usage of `#[inline(always)]` and easily avoided by not using the attribute.
587607 if tcx. features ( ) . target_feature_11 ( )
588608 && tcx. is_closure_like ( did. to_def_id ( ) )
589- && codegen_fn_attrs. inline != InlineAttr :: Always
609+ && ! codegen_fn_attrs. inline . always ( )
590610 {
591611 let owner_id = tcx. parent ( did. to_def_id ( ) ) ;
592612 if tcx. def_kind ( owner_id) . has_codegen_attrs ( ) {
@@ -596,11 +616,15 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
596616 }
597617 }
598618
599- // If a function uses #[target_feature] it can't be inlined into general
619+ // If a function uses ` #[target_feature]` it can't be inlined into general
600620 // purpose functions as they wouldn't have the right target features
601- // enabled. For that reason we also forbid #[inline(always)] as it can't be
621+ // enabled. For that reason we also forbid ` #[inline(always)]` as it can't be
602622 // respected.
603- if !codegen_fn_attrs. target_features . is_empty ( ) && codegen_fn_attrs. inline == InlineAttr :: Always
623+ //
624+ // `#[rustc_force_inline]` doesn't need to be prohibited here, that
625+ // is implemented entirely in rustc can attempt to inline and error if it cannot.
626+ if !codegen_fn_attrs. target_features . is_empty ( )
627+ && matches ! ( codegen_fn_attrs. inline, InlineAttr :: Always )
604628 {
605629 if let Some ( span) = inline_span {
606630 tcx. dcx ( ) . span_err (
@@ -611,7 +635,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
611635 }
612636 }
613637
614- if !codegen_fn_attrs. no_sanitize . is_empty ( ) && codegen_fn_attrs. inline == InlineAttr :: Always {
638+ if !codegen_fn_attrs. no_sanitize . is_empty ( ) && codegen_fn_attrs. inline . always ( ) {
615639 if let ( Some ( no_sanitize_span) , Some ( inline_span) ) = ( no_sanitize_span, inline_span) {
616640 let hir_id = tcx. local_def_id_to_hir_id ( did) ;
617641 tcx. node_span_lint (
0 commit comments