From 3ce8cfbc58a7cbd0cc01e4c4cc63d269fe8e59d4 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sun, 29 Mar 2026 18:14:53 +0200 Subject: [PATCH] emit error on `#[track_caller]` with `extern fn` such a function implicitly uses `extern "C" --- .../rustc_ast_passes/src/ast_validation.rs | 33 ++++++++++++------- .../error-with-invalid-abi.rs | 6 ++++ .../error-with-invalid-abi.stderr | 19 ++++++++++- 3 files changed, 45 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index dd14e9143569..7d83295cfa65 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1679,19 +1679,28 @@ fn visit_fn(&mut self, fk: FnKind<'a>, attrs: &AttrVec, span: Span, id: NodeId) self.check_item_safety(span, safety); } - if let FnKind::Fn(ctxt, _, fun) = fk - && let Extern::Explicit(str_lit, extern_abi_span) = fun.sig.header.ext - && let Ok(abi) = ExternAbi::from_str(str_lit.symbol.as_str()) - { - self.check_extern_fn_signature(abi, ctxt, &fun.ident, &fun.sig); + if let FnKind::Fn(ctxt, _, fun) = fk { + let ext = match fun.sig.header.ext { + Extern::None => None, + Extern::Implicit(span) => Some((ExternAbi::FALLBACK, span)), + Extern::Explicit(str_lit, span) => { + ExternAbi::from_str(str_lit.symbol.as_str()).ok().map(|abi| (abi, span)) + } + }; - if let Some(attr) = attr::find_by_name(attrs, sym::track_caller) - && abi != ExternAbi::Rust - { - self.dcx().emit_err(errors::RequiresRustAbi { - track_caller_span: attr.span, - extern_abi_span, - }); + if let Some((extern_abi, extern_abi_span)) = ext { + // Some ABIs impose special restrictions on the signature. + self.check_extern_fn_signature(extern_abi, ctxt, &fun.ident, &fun.sig); + + // #[track_caller] can only be used with the rust ABI. + if let Some(attr) = attr::find_by_name(attrs, sym::track_caller) + && extern_abi != ExternAbi::Rust + { + self.dcx().emit_err(errors::RequiresRustAbi { + track_caller_span: attr.span, + extern_abi_span, + }); + } } } diff --git a/tests/ui/rfcs/rfc-2091-track-caller/error-with-invalid-abi.rs b/tests/ui/rfcs/rfc-2091-track-caller/error-with-invalid-abi.rs index 53f99760d88f..a8dfa514d070 100644 --- a/tests/ui/rfcs/rfc-2091-track-caller/error-with-invalid-abi.rs +++ b/tests/ui/rfcs/rfc-2091-track-caller/error-with-invalid-abi.rs @@ -27,4 +27,10 @@ extern "C" fn c_method() {} extern "Rust" fn rust_method() {} } +#[rustfmt::skip] // rustfmt will insert the implicit "C" +#[track_caller] +//~^ ERROR `#[track_caller]` can only be used with the Rust ABI +pub extern fn extern_missing_abi() {} +//~^ WARN `extern` declarations without an explicit ABI are deprecated + fn main() {} diff --git a/tests/ui/rfcs/rfc-2091-track-caller/error-with-invalid-abi.stderr b/tests/ui/rfcs/rfc-2091-track-caller/error-with-invalid-abi.stderr index f5cba7b8a011..2a1fac08b103 100644 --- a/tests/ui/rfcs/rfc-2091-track-caller/error-with-invalid-abi.stderr +++ b/tests/ui/rfcs/rfc-2091-track-caller/error-with-invalid-abi.stderr @@ -24,6 +24,23 @@ LL | LL | extern "C" fn c_method() {} | ---------- not using the Rust ABI because of this -error: aborting due to 3 previous errors +error[E0737]: `#[track_caller]` can only be used with the Rust ABI + --> $DIR/error-with-invalid-abi.rs:31:1 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ using `#[track_caller]` here +LL | +LL | pub extern fn extern_missing_abi() {} + | ------ not using the Rust ABI because of this + +warning: `extern` declarations without an explicit ABI are deprecated + --> $DIR/error-with-invalid-abi.rs:33:5 + | +LL | pub extern fn extern_missing_abi() {} + | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` + | + = note: `#[warn(missing_abi)]` on by default + +error: aborting due to 4 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0737`.