Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down Expand Up @@ -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) => {
Expand All @@ -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 <https://github.com/rust-lang/rust/issues/158293>.
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,
});
}
}
}
_ => {}
}
Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_passes/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
29 changes: 29 additions & 0 deletions tests/ui/eii/naked_impl_issue_158293.rs
Original file line number Diff line number Diff line change
@@ -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 <https://github.com/rust-lang/rust/issues/158293>.

//@ 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() {}
18 changes: 18 additions & 0 deletions tests/ui/eii/naked_impl_issue_158293.stderr
Original file line number Diff line number Diff line change
@@ -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

Loading