diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 3139c8746b95a..e2df59d927503 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -210,7 +210,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { &AttributeKind::RustcPubTransparent(attr_span) => { self.check_rustc_pub_transparent(attr_span, span, attrs) } - AttributeKind::Naked(..) => self.check_naked(hir_id, target), + AttributeKind::Naked(naked_span) => { + self.check_naked(hir_id, *naked_span, attrs, target) + } AttributeKind::TrackCaller(attr_span) => { self.check_track_caller(hir_id, *attr_span, attrs, target) } @@ -728,7 +730,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if `#[naked]` is applied to a function definition. - fn check_naked(&self, hir_id: HirId, target: Target) { + fn check_naked(&self, hir_id: HirId, naked_span: Span, attrs: &[Attribute], target: Target) { match target { Target::Fn | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => { @@ -746,6 +748,24 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ) .emit(); } + + // EII forwards calls to an implementation through a shim the compiler synthesizes + // around its body. A naked function's body is exactly the user's `naked_asm!`, so + // the shim has nowhere to go. See . + if let Some(impls) = find_attr!(attrs, EiiImpls(impls) => impls) { + for i in impls { + let name = match i.resolution { + EiiImplResolution::Macro(def_id) => self.tcx.item_name(def_id), + EiiImplResolution::Known(def_id) => self.tcx.item_name(def_id), + EiiImplResolution::Error(_eg) => continue, + }; + self.dcx().emit_err(diagnostics::EiiWithNaked { + naked_span, + name, + impl_span: i.span, + }); + } + } } _ => {} } diff --git a/compiler/rustc_passes/src/diagnostics.rs b/compiler/rustc_passes/src/diagnostics.rs index 2589941d7dae1..5b54efa53f0c9 100644 --- a/compiler/rustc_passes/src/diagnostics.rs +++ b/compiler/rustc_passes/src/diagnostics.rs @@ -1087,6 +1087,16 @@ pub(crate) struct EiiWithTrackCaller { pub sig_span: Span, } +#[derive(Diagnostic)] +#[diag("`#[{$name}]` is not allowed to be `#[naked]`")] +pub(crate) struct EiiWithNaked { + #[primary_span] + pub naked_span: Span, + pub name: Symbol, + #[label("`#[{$name}]` implementation cannot be `#[naked]`")] + pub impl_span: Span, +} + #[derive(Diagnostic)] #[diag("`#[{$name}]` {$kind} required, but not found")] pub(crate) struct EiiWithoutImpl { diff --git a/tests/ui/eii/naked_impl_issue_158293.rs b/tests/ui/eii/naked_impl_issue_158293.rs new file mode 100644 index 0000000000000..bc788c69fe939 --- /dev/null +++ b/tests/ui/eii/naked_impl_issue_158293.rs @@ -0,0 +1,29 @@ +// An EII implementation cannot be `#[naked]`: EII forwards calls through a shim the +// compiler synthesizes around the body, which has nowhere to go in a naked function. +// See . + +//@ needs-asm-support +#![feature(extern_item_impls)] +#![allow(dead_code)] + +#[eii(requires_impl)] +unsafe extern "C" fn entry_eh(_: usize); + +#[crate::requires_impl] +#[unsafe(naked)] //~ ERROR `#[requires_impl]` is not allowed to be `#[naked]` +unsafe extern "C" fn eh(_: usize) { + core::arch::naked_asm!("nop"); +} + +#[eii(opt_impl)] +unsafe extern "C" fn entry_default(_: usize) { + println!("called default") +} + +#[crate::opt_impl] +#[unsafe(naked)] //~ ERROR `#[opt_impl]` is not allowed to be `#[naked]` +unsafe extern "C" fn eh_default(_: usize) { + core::arch::naked_asm!("nop"); +} + +fn main() {} diff --git a/tests/ui/eii/naked_impl_issue_158293.stderr b/tests/ui/eii/naked_impl_issue_158293.stderr new file mode 100644 index 0000000000000..21510fe8cdede --- /dev/null +++ b/tests/ui/eii/naked_impl_issue_158293.stderr @@ -0,0 +1,18 @@ +error: `#[requires_impl]` is not allowed to be `#[naked]` + --> $DIR/naked_impl_issue_158293.rs:13:1 + | +LL | #[crate::requires_impl] + | ----------------------- `#[requires_impl]` implementation cannot be `#[naked]` +LL | #[unsafe(naked)] + | ^^^^^^^^^^^^^^^^ + +error: `#[opt_impl]` is not allowed to be `#[naked]` + --> $DIR/naked_impl_issue_158293.rs:24:1 + | +LL | #[crate::opt_impl] + | ------------------ `#[opt_impl]` implementation cannot be `#[naked]` +LL | #[unsafe(naked)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors +