diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index c94de9aec30..9c0234953bb 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -89,6 +89,8 @@ impl CheckAttrVisitor<'tcx> { self.check_allow_internal_unstable(&attr, span, target, &attrs) } else if self.tcx.sess.check_name(attr, sym::rustc_allow_const_fn_unstable) { self.check_rustc_allow_const_fn_unstable(hir_id, &attr, span, target) + } else if self.tcx.sess.check_name(attr, sym::naked) { + self.check_naked(attr, span, target) } else { // lint-only checks if self.tcx.sess.check_name(attr, sym::cold) { @@ -162,6 +164,25 @@ impl CheckAttrVisitor<'tcx> { } } + /// Checks if `#[naked]` is applied to a function definition. + fn check_naked(&self, attr: &Attribute, span: &Span, target: Target) -> bool { + match target { + Target::Fn + | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true, + _ => { + self.tcx + .sess + .struct_span_err( + attr.span, + "attribute should be applied to a function definition", + ) + .span_label(*span, "not a function definition") + .emit(); + false + } + } + } + /// Checks if a `#[track_caller]` is applied to a non-naked function. Returns `true` if valid. fn check_track_caller( &self, diff --git a/src/test/ui/asm/naked-invalid-attr.rs b/src/test/ui/asm/naked-invalid-attr.rs new file mode 100644 index 00000000000..cdb6c17454b --- /dev/null +++ b/src/test/ui/asm/naked-invalid-attr.rs @@ -0,0 +1,51 @@ +// Checks that #[naked] attribute can be placed on function definitions only. +// +// ignore-wasm32 asm unsupported +#![feature(asm)] +#![feature(naked_functions)] +#![naked] //~ ERROR should be applied to a function definition + +extern "C" { + #[naked] //~ ERROR should be applied to a function definition + fn f(); +} + +#[naked] //~ ERROR should be applied to a function definition +#[repr(C)] +struct S { + a: u32, + b: u32, +} + +trait Invoke { + #[naked] //~ ERROR should be applied to a function definition + extern "C" fn invoke(&self); +} + +impl Invoke for S { + #[naked] + extern "C" fn invoke(&self) { + unsafe { asm!("", options(noreturn)) } + } +} + +#[naked] +extern "C" fn ok() { + unsafe { asm!("", options(noreturn)) } +} + +impl S { + #[naked] + extern "C" fn g() { + unsafe { asm!("", options(noreturn)) } + } + + #[naked] + extern "C" fn h(&self) { + unsafe { asm!("", options(noreturn)) } + } +} + +fn main() { + #[naked] || {}; //~ ERROR should be applied to a function definition +} diff --git a/src/test/ui/asm/naked-invalid-attr.stderr b/src/test/ui/asm/naked-invalid-attr.stderr new file mode 100644 index 00000000000..beaa34140c9 --- /dev/null +++ b/src/test/ui/asm/naked-invalid-attr.stderr @@ -0,0 +1,42 @@ +error: attribute should be applied to a function definition + --> $DIR/naked-invalid-attr.rs:9:5 + | +LL | #[naked] + | ^^^^^^^^ +LL | fn f(); + | ------- not a function definition + +error: attribute should be applied to a function definition + --> $DIR/naked-invalid-attr.rs:13:1 + | +LL | #[naked] + | ^^^^^^^^ +LL | #[repr(C)] +LL | / struct S { +LL | | a: u32, +LL | | b: u32, +LL | | } + | |_- not a function definition + +error: attribute should be applied to a function definition + --> $DIR/naked-invalid-attr.rs:50:5 + | +LL | #[naked] || {}; + | ^^^^^^^^ ----- not a function definition + +error: attribute should be applied to a function definition + --> $DIR/naked-invalid-attr.rs:21:5 + | +LL | #[naked] + | ^^^^^^^^ +LL | extern "C" fn invoke(&self); + | ---------------------------- not a function definition + +error: attribute should be applied to a function definition + --> $DIR/naked-invalid-attr.rs:6:1 + | +LL | #![naked] + | ^^^^^^^^^ + +error: aborting due to 5 previous errors + diff --git a/src/test/ui/rfc-2091-track-caller/error-with-naked.rs b/src/test/ui/rfc-2091-track-caller/error-with-naked.rs index 2b110c9a325..c60ff7dc934 100644 --- a/src/test/ui/rfc-2091-track-caller/error-with-naked.rs +++ b/src/test/ui/rfc-2091-track-caller/error-with-naked.rs @@ -12,10 +12,4 @@ impl S { fn g() {} } -extern "Rust" { - #[track_caller] //~ ERROR cannot use `#[track_caller]` with `#[naked]` - #[naked] - fn h(); -} - fn main() {} diff --git a/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr b/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr index 1249d1df071..211cd3f16ba 100644 --- a/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr +++ b/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr @@ -4,18 +4,12 @@ error[E0736]: cannot use `#[track_caller]` with `#[naked]` LL | #[track_caller] | ^^^^^^^^^^^^^^^ -error[E0736]: cannot use `#[track_caller]` with `#[naked]` - --> $DIR/error-with-naked.rs:16:5 - | -LL | #[track_caller] - | ^^^^^^^^^^^^^^^ - error[E0736]: cannot use `#[track_caller]` with `#[naked]` --> $DIR/error-with-naked.rs:10:5 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0736`.