@@ -19,6 +19,7 @@ use rustc_session::{Session, lint};
19
19
use rustc_span:: symbol:: Ident ;
20
20
use rustc_span:: { Span , sym} ;
21
21
use rustc_target:: spec:: { SanitizerSet , abi} ;
22
+ use tracing:: debug;
22
23
23
24
use crate :: errors;
24
25
use 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 {
514
515
}
515
516
516
517
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
+ )
534
538
. with_help ( "valid inline arguments are `always` and `never`" )
535
539
. emit ( ) ;
536
540
537
- InlineAttr :: None
541
+ InlineAttr :: None
542
+ }
538
543
}
544
+ Some ( MetaItemKind :: NameValue ( _) ) => ia,
545
+ None => ia,
539
546
}
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
542
562
}
543
563
} ) ;
544
564
@@ -586,7 +606,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
586
606
// is probably a poor usage of `#[inline(always)]` and easily avoided by not using the attribute.
587
607
if tcx. features ( ) . target_feature_11 ( )
588
608
&& tcx. is_closure_like ( did. to_def_id ( ) )
589
- && codegen_fn_attrs. inline != InlineAttr :: Always
609
+ && ! codegen_fn_attrs. inline . always ( )
590
610
{
591
611
let owner_id = tcx. parent ( did. to_def_id ( ) ) ;
592
612
if tcx. def_kind ( owner_id) . has_codegen_attrs ( ) {
@@ -596,11 +616,15 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
596
616
}
597
617
}
598
618
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
600
620
// 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
602
622
// 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 )
604
628
{
605
629
if let Some ( span) = inline_span {
606
630
tcx. dcx ( ) . span_err (
@@ -611,7 +635,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
611
635
}
612
636
}
613
637
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 ( ) {
615
639
if let ( Some ( no_sanitize_span) , Some ( inline_span) ) = ( no_sanitize_span, inline_span) {
616
640
let hir_id = tcx. local_def_id_to_hir_id ( did) ;
617
641
tcx. node_span_lint (
0 commit comments