@@ -155,7 +155,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
155
155
[ sym:: rustc_std_internal_symbol] => {
156
156
self . check_rustc_std_internal_symbol ( attr, span, target)
157
157
}
158
- [ sym:: naked] => self . check_naked ( hir_id, attr, span, target) ,
158
+ [ sym:: naked] => self . check_naked ( hir_id, attr, span, target, attrs ) ,
159
159
[ sym:: rustc_never_returns_null_ptr] => {
160
160
self . check_applied_to_fn_or_method ( hir_id, attr, span, target)
161
161
}
@@ -410,12 +410,71 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
410
410
}
411
411
412
412
/// Checks if `#[naked]` is applied to a function definition.
413
- fn check_naked ( & self , hir_id : HirId , attr : & Attribute , span : Span , target : Target ) -> bool {
413
+ fn check_naked (
414
+ & self ,
415
+ hir_id : HirId ,
416
+ attr : & Attribute ,
417
+ span : Span ,
418
+ target : Target ,
419
+ attrs : & [ Attribute ] ,
420
+ ) -> bool {
421
+ // many attributes don't make sense in combination with #[naked].
422
+ // Notable attributes that are incompatible with `#[naked]` are:
423
+ //
424
+ // * `#[inline]`
425
+ // * `#[track_caller]`
426
+ // * `#[test]`, `#[ignore]`, `#[should_panic]`
427
+ //
428
+ // NOTE: when making changes to this list, check that `error_codes/E0736.md` remains accurate
429
+ const ALLOW_LIST : & [ rustc_span:: Symbol ] = & [
430
+ // conditional compilation
431
+ sym:: cfg,
432
+ sym:: cfg_attr,
433
+ // testing (allowed here so better errors can be generated in `rustc_builtin_macros::test`)
434
+ sym:: test,
435
+ sym:: ignore,
436
+ sym:: should_panic,
437
+ sym:: bench,
438
+ // diagnostics
439
+ sym:: allow,
440
+ sym:: warn,
441
+ sym:: deny,
442
+ sym:: forbid,
443
+ sym:: deprecated,
444
+ sym:: must_use,
445
+ // abi, linking and FFI
446
+ sym:: export_name,
447
+ sym:: link_section,
448
+ sym:: linkage,
449
+ sym:: no_mangle,
450
+ sym:: naked,
451
+ sym:: instruction_set,
452
+ // code generation
453
+ sym:: cold,
454
+ sym:: target_feature,
455
+ // documentation
456
+ sym:: doc,
457
+ ] ;
458
+
414
459
match target {
415
460
Target :: Fn
416
- | Target :: Method ( MethodKind :: Trait { body : true } | MethodKind :: Inherent ) => true ,
461
+ | Target :: Method ( MethodKind :: Trait { body : true } | MethodKind :: Inherent ) => {
462
+ for other_attr in attrs {
463
+ if !ALLOW_LIST . iter ( ) . any ( |name| other_attr. has_name ( * name) ) {
464
+ self . dcx ( ) . emit_err ( errors:: NakedFunctionIncompatibleAttribute {
465
+ span : other_attr. span ,
466
+ naked_span : attr. span ,
467
+ attr : other_attr. name_or_empty ( ) ,
468
+ } ) ;
469
+
470
+ return false ;
471
+ }
472
+ }
473
+
474
+ true
475
+ }
417
476
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
418
- // `#[allow_internal_unstable ]` attribute with just a lint, because we previously
477
+ // `#[naked ]` attribute with just a lint, because we previously
419
478
// erroneously allowed it and some crates used it accidentally, to be compatible
420
479
// with crates depending on them, we can't throw an error here.
421
480
Target :: Field | Target :: Arm | Target :: MacroDef => {
@@ -488,7 +547,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
488
547
}
489
548
}
490
549
491
- /// Checks if a `#[track_caller]` is applied to a non-naked function. Returns `true` if valid.
550
+ /// Checks if a `#[track_caller]` is applied to a function. Returns `true` if valid.
492
551
fn check_track_caller (
493
552
& self ,
494
553
hir_id : HirId ,
@@ -498,10 +557,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
498
557
target : Target ,
499
558
) -> bool {
500
559
match target {
501
- _ if attrs. iter ( ) . any ( |attr| attr. has_name ( sym:: naked) ) => {
502
- self . dcx ( ) . emit_err ( errors:: NakedTrackedCaller { attr_span } ) ;
503
- false
504
- }
505
560
Target :: Fn => {
506
561
// `#[track_caller]` is not valid on weak lang items because they are called via
507
562
// `extern` declarations and `#[track_caller]` would alter their ABI.
0 commit comments