@@ -8,12 +8,12 @@ use rustc_middle::hir::map::Map;
88use rustc_middle:: ty:: query:: Providers ;
99use rustc_middle:: ty:: TyCtxt ;
1010
11- use rustc_ast:: { Attribute , NestedMetaItem } ;
12- use rustc_errors:: struct_span_err;
11+ use rustc_ast:: { Attribute , LitKind , NestedMetaItem } ;
12+ use rustc_errors:: { pluralize , struct_span_err} ;
1313use rustc_hir as hir;
1414use rustc_hir:: def_id:: LocalDefId ;
1515use rustc_hir:: intravisit:: { self , NestedVisitorMap , Visitor } ;
16- use rustc_hir:: { self , HirId , Item , ItemKind , TraitItem } ;
16+ use rustc_hir:: { self , FnSig , ForeignItem , ForeignItemKind , HirId , Item , ItemKind , TraitItem } ;
1717use rustc_hir:: { MethodKind , Target } ;
1818use rustc_session:: lint:: builtin:: { CONFLICTING_REPR_HINTS , UNUSED_ATTRIBUTES } ;
1919use rustc_session:: parse:: feature_err;
@@ -43,6 +43,12 @@ pub(crate) fn target_from_impl_item<'tcx>(
4343 }
4444}
4545
46+ #[ derive( Clone , Copy ) ]
47+ enum ItemLike < ' tcx > {
48+ Item ( & ' tcx Item < ' tcx > ) ,
49+ ForeignItem ( & ' tcx ForeignItem < ' tcx > ) ,
50+ }
51+
4652struct CheckAttrVisitor < ' tcx > {
4753 tcx : TyCtxt < ' tcx > ,
4854}
@@ -55,7 +61,7 @@ impl CheckAttrVisitor<'tcx> {
5561 attrs : & ' hir [ Attribute ] ,
5662 span : & Span ,
5763 target : Target ,
58- item : Option < & Item < ' _ > > ,
64+ item : Option < ItemLike < ' _ > > ,
5965 ) {
6066 let mut is_valid = true ;
6167 for attr in attrs {
@@ -75,6 +81,8 @@ impl CheckAttrVisitor<'tcx> {
7581 self . check_no_link ( & attr, span, target)
7682 } else if self . tcx . sess . check_name ( attr, sym:: export_name) {
7783 self . check_export_name ( & attr, span, target)
84+ } else if self . tcx . sess . check_name ( attr, sym:: rustc_args_required_const) {
85+ self . check_rustc_args_required_const ( & attr, span, target, item)
7886 } else {
7987 // lint-only checks
8088 if self . tcx . sess . check_name ( attr, sym:: cold) {
@@ -400,6 +408,71 @@ impl CheckAttrVisitor<'tcx> {
400408 }
401409 }
402410
411+ /// Checks if `#[rustc_args_required_const]` is applied to a function and has a valid argument.
412+ fn check_rustc_args_required_const (
413+ & self ,
414+ attr : & Attribute ,
415+ span : & Span ,
416+ target : Target ,
417+ item : Option < ItemLike < ' _ > > ,
418+ ) -> bool {
419+ if let Target :: Fn | Target :: Method ( ..) | Target :: ForeignFn = target {
420+ let mut invalid_args = vec ! [ ] ;
421+ for meta in attr. meta_item_list ( ) . expect ( "no meta item list" ) {
422+ if let Some ( LitKind :: Int ( val, _) ) = meta. literal ( ) . map ( |lit| & lit. kind ) {
423+ if let Some ( ItemLike :: Item ( Item {
424+ kind : ItemKind :: Fn ( FnSig { decl, .. } , ..) ,
425+ ..
426+ } ) )
427+ | Some ( ItemLike :: ForeignItem ( ForeignItem {
428+ kind : ForeignItemKind :: Fn ( decl, ..) ,
429+ ..
430+ } ) ) = item
431+ {
432+ let arg_count = decl. inputs . len ( ) as u128 ;
433+ if * val >= arg_count {
434+ let span = meta. span ( ) ;
435+ self . tcx
436+ . sess
437+ . struct_span_err ( span, "index exceeds number of arguments" )
438+ . span_label (
439+ span,
440+ format ! (
441+ "there {} only {} argument{}" ,
442+ if arg_count != 1 { "are" } else { "is" } ,
443+ arg_count,
444+ pluralize!( arg_count)
445+ ) ,
446+ )
447+ . emit ( ) ;
448+ return false ;
449+ }
450+ } else {
451+ bug ! ( "should be a function item" ) ;
452+ }
453+ } else {
454+ invalid_args. push ( meta. span ( ) ) ;
455+ }
456+ }
457+ if !invalid_args. is_empty ( ) {
458+ self . tcx
459+ . sess
460+ . struct_span_err ( invalid_args, "arguments should be non-negative integers" )
461+ . emit ( ) ;
462+ false
463+ } else {
464+ true
465+ }
466+ } else {
467+ self . tcx
468+ . sess
469+ . struct_span_err ( attr. span , "attribute should be applied to a function" )
470+ . span_label ( * span, "not a function" )
471+ . emit ( ) ;
472+ false
473+ }
474+ }
475+
403476 /// Checks if `#[link_section]` is applied to a function or static.
404477 fn check_link_section ( & self , hir_id : HirId , attr : & Attribute , span : & Span , target : Target ) {
405478 match target {
@@ -448,7 +521,7 @@ impl CheckAttrVisitor<'tcx> {
448521 attrs : & ' hir [ Attribute ] ,
449522 span : & Span ,
450523 target : Target ,
451- item : Option < & Item < ' _ > > ,
524+ item : Option < ItemLike < ' _ > > ,
452525 hir_id : HirId ,
453526 ) {
454527 // Extract the names of all repr hints, e.g., [foo, bar, align] for:
@@ -564,7 +637,14 @@ impl CheckAttrVisitor<'tcx> {
564637 // Warn on repr(u8, u16), repr(C, simd), and c-like-enum-repr(C, u8)
565638 if ( int_reprs > 1 )
566639 || ( is_simd && is_c)
567- || ( int_reprs == 1 && is_c && item. map_or ( false , |item| is_c_like_enum ( item) ) )
640+ || ( int_reprs == 1
641+ && is_c
642+ && item. map_or ( false , |item| {
643+ if let ItemLike :: Item ( item) = item {
644+ return is_c_like_enum ( item) ;
645+ }
646+ return false ;
647+ } ) )
568648 {
569649 self . tcx . struct_span_lint_hir (
570650 CONFLICTING_REPR_HINTS ,
@@ -649,7 +729,13 @@ impl Visitor<'tcx> for CheckAttrVisitor<'tcx> {
649729
650730 fn visit_item ( & mut self , item : & ' tcx Item < ' tcx > ) {
651731 let target = Target :: from_item ( item) ;
652- self . check_attributes ( item. hir_id , item. attrs , & item. span , target, Some ( item) ) ;
732+ self . check_attributes (
733+ item. hir_id ,
734+ item. attrs ,
735+ & item. span ,
736+ target,
737+ Some ( ItemLike :: Item ( item) ) ,
738+ ) ;
653739 intravisit:: walk_item ( self , item)
654740 }
655741
@@ -659,9 +745,15 @@ impl Visitor<'tcx> for CheckAttrVisitor<'tcx> {
659745 intravisit:: walk_trait_item ( self , trait_item)
660746 }
661747
662- fn visit_foreign_item ( & mut self , f_item : & ' tcx hir :: ForeignItem < ' tcx > ) {
748+ fn visit_foreign_item ( & mut self , f_item : & ' tcx ForeignItem < ' tcx > ) {
663749 let target = Target :: from_foreign_item ( f_item) ;
664- self . check_attributes ( f_item. hir_id , & f_item. attrs , & f_item. span , target, None ) ;
750+ self . check_attributes (
751+ f_item. hir_id ,
752+ & f_item. attrs ,
753+ & f_item. span ,
754+ target,
755+ Some ( ItemLike :: ForeignItem ( f_item) ) ,
756+ ) ;
665757 intravisit:: walk_foreign_item ( self , f_item)
666758 }
667759
0 commit comments