@@ -8,12 +8,12 @@ use rustc_middle::hir::map::Map;
8
8
use rustc_middle:: ty:: query:: Providers ;
9
9
use rustc_middle:: ty:: TyCtxt ;
10
10
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} ;
13
13
use rustc_hir as hir;
14
14
use rustc_hir:: def_id:: LocalDefId ;
15
15
use 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 } ;
17
17
use rustc_hir:: { MethodKind , Target } ;
18
18
use rustc_session:: lint:: builtin:: { CONFLICTING_REPR_HINTS , UNUSED_ATTRIBUTES } ;
19
19
use rustc_session:: parse:: feature_err;
@@ -43,6 +43,12 @@ pub(crate) fn target_from_impl_item<'tcx>(
43
43
}
44
44
}
45
45
46
+ #[ derive( Clone , Copy ) ]
47
+ enum ItemLike < ' tcx > {
48
+ Item ( & ' tcx Item < ' tcx > ) ,
49
+ ForeignItem ( & ' tcx ForeignItem < ' tcx > ) ,
50
+ }
51
+
46
52
struct CheckAttrVisitor < ' tcx > {
47
53
tcx : TyCtxt < ' tcx > ,
48
54
}
@@ -55,7 +61,7 @@ impl CheckAttrVisitor<'tcx> {
55
61
attrs : & ' hir [ Attribute ] ,
56
62
span : & Span ,
57
63
target : Target ,
58
- item : Option < & Item < ' _ > > ,
64
+ item : Option < ItemLike < ' _ > > ,
59
65
) {
60
66
let mut is_valid = true ;
61
67
for attr in attrs {
@@ -75,6 +81,8 @@ impl CheckAttrVisitor<'tcx> {
75
81
self . check_no_link ( & attr, span, target)
76
82
} else if self . tcx . sess . check_name ( attr, sym:: export_name) {
77
83
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)
78
86
} else {
79
87
// lint-only checks
80
88
if self . tcx . sess . check_name ( attr, sym:: cold) {
@@ -400,6 +408,71 @@ impl CheckAttrVisitor<'tcx> {
400
408
}
401
409
}
402
410
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
+
403
476
/// Checks if `#[link_section]` is applied to a function or static.
404
477
fn check_link_section ( & self , hir_id : HirId , attr : & Attribute , span : & Span , target : Target ) {
405
478
match target {
@@ -448,7 +521,7 @@ impl CheckAttrVisitor<'tcx> {
448
521
attrs : & ' hir [ Attribute ] ,
449
522
span : & Span ,
450
523
target : Target ,
451
- item : Option < & Item < ' _ > > ,
524
+ item : Option < ItemLike < ' _ > > ,
452
525
hir_id : HirId ,
453
526
) {
454
527
// Extract the names of all repr hints, e.g., [foo, bar, align] for:
@@ -564,7 +637,14 @@ impl CheckAttrVisitor<'tcx> {
564
637
// Warn on repr(u8, u16), repr(C, simd), and c-like-enum-repr(C, u8)
565
638
if ( int_reprs > 1 )
566
639
|| ( 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
+ } ) )
568
648
{
569
649
self . tcx . struct_span_lint_hir (
570
650
CONFLICTING_REPR_HINTS ,
@@ -649,7 +729,13 @@ impl Visitor<'tcx> for CheckAttrVisitor<'tcx> {
649
729
650
730
fn visit_item ( & mut self , item : & ' tcx Item < ' tcx > ) {
651
731
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
+ ) ;
653
739
intravisit:: walk_item ( self , item)
654
740
}
655
741
@@ -659,9 +745,15 @@ impl Visitor<'tcx> for CheckAttrVisitor<'tcx> {
659
745
intravisit:: walk_trait_item ( self , trait_item)
660
746
}
661
747
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 > ) {
663
749
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
+ ) ;
665
757
intravisit:: walk_foreign_item ( self , f_item)
666
758
}
667
759
0 commit comments