Skip to content

Port #[track_caller] to the new attribute system #142825

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3282,6 +3282,7 @@ dependencies = [
"rustc_abi",
"rustc_ast",
"rustc_ast_pretty",
"rustc_attr_data_structures",
"rustc_attr_parsing",
"rustc_data_structures",
"rustc_errors",
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_ast_lowering/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ doctest = false
rustc_abi = { path = "../rustc_abi" }
rustc_ast = { path = "../rustc_ast" }
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
rustc_attr_data_structures = { path = "../rustc_attr_data_structures" }
rustc_attr_parsing = { path = "../rustc_attr_parsing" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_ast_lowering/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::sync::Arc;
use rustc_ast::ptr::P as AstP;
use rustc_ast::*;
use rustc_ast_pretty::pprust::expr_to_string;
use rustc_attr_data_structures::{AttributeKind, find_attr};
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir as hir;
use rustc_hir::HirId;
Expand Down Expand Up @@ -831,7 +832,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
) {
if self.tcx.features().async_fn_track_caller()
&& let Some(attrs) = self.attrs.get(&outer_hir_id.local_id)
&& attrs.into_iter().any(|attr| attr.has_name(sym::track_caller))
&& find_attr!(*attrs, AttributeKind::TrackCaller(_))
{
let unstable_span = self.mark_span_with_reason(
DesugaringKind::Async,
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_attr_data_structures/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,5 +265,8 @@ pub enum AttributeKind {
/// Span of the attribute.
span: Span,
},

/// Represents `#[track_caller]`
TrackCaller(Span),
// tidy-alphabetical-end
}
24 changes: 21 additions & 3 deletions compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use rustc_attr_data_structures::{AttributeKind, OptimizeAttr};
use rustc_feature::{AttributeTemplate, template};
use rustc_session::parse::feature_err;
use rustc_span::{Span, sym};
use rustc_span::{Span, Symbol, sym};

use super::{AcceptMapping, AttributeOrder, AttributeParser, OnDuplicate, SingleAttributeParser};
use crate::context::{AcceptContext, FinalizeContext, Stage};
Expand All @@ -11,7 +11,7 @@ use crate::session_diagnostics::NakedFunctionIncompatibleAttribute;
pub(crate) struct OptimizeParser;

impl<S: Stage> SingleAttributeParser<S> for OptimizeParser {
const PATH: &[rustc_span::Symbol] = &[sym::optimize];
const PATH: &[Symbol] = &[sym::optimize];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const TEMPLATE: AttributeTemplate = template!(List: "size|speed|none");
Expand Down Expand Up @@ -44,7 +44,7 @@ impl<S: Stage> SingleAttributeParser<S> for OptimizeParser {
pub(crate) struct ColdParser;

impl<S: Stage> SingleAttributeParser<S> for ColdParser {
const PATH: &[rustc_span::Symbol] = &[sym::cold];
const PATH: &[Symbol] = &[sym::cold];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const TEMPLATE: AttributeTemplate = template!(Word);
Expand Down Expand Up @@ -166,6 +166,24 @@ impl<S: Stage> AttributeParser<S> for NakedParser {
}
}

pub(crate) struct TrackCallerParser;

impl<S: Stage> SingleAttributeParser<S> for TrackCallerParser {
const PATH: &[Symbol] = &[sym::track_caller];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const TEMPLATE: AttributeTemplate = template!(Word);

fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
if !args.no_args() {
cx.expected_no_args(args.span().unwrap_or(cx.attr_span));
return None;
}

Some(AttributeKind::TrackCaller(cx.attr_span))
}
}

pub(crate) struct NoMangleParser;

impl<S: Stage> SingleAttributeParser<S> for NoMangleParser {
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ use rustc_session::Session;
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};

use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser};
use crate::attributes::codegen_attrs::{ColdParser, NakedParser, NoMangleParser, OptimizeParser};
use crate::attributes::codegen_attrs::{
ColdParser, NakedParser, NoMangleParser, OptimizeParser, TrackCallerParser,
};
use crate::attributes::confusables::ConfusablesParser;
use crate::attributes::deprecation::DeprecationParser;
use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
Expand Down Expand Up @@ -119,6 +121,7 @@ attribute_parsers!(
Single<OptimizeParser>,
Single<PubTransparentParser>,
Single<RustcForceInlineParser>,
Single<TrackCallerParser>,
Single<TransparencyParser>,
// tidy-alphabetical-end
];
Expand Down
54 changes: 26 additions & 28 deletions compiler/rustc_codegen_ssa/src/codegen_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,17 +95,15 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
// In these cases, we bail from performing further checks that are only meaningful for
// functions (such as calling `fn_sig`, which ICEs if given a non-function). We also
// report a delayed bug, just in case `check_attr` isn't doing its job.
let fn_sig = || {
let fn_sig = |attr_span| {
use DefKind::*;

let def_kind = tcx.def_kind(did);
if let Fn | AssocFn | Variant | Ctor(..) = def_kind {
Some(tcx.fn_sig(did))
} else {
tcx.dcx().span_delayed_bug(
attr.span(),
"this attribute can only be applied to functions",
);
tcx.dcx()
.span_delayed_bug(attr_span, "this attribute can only be applied to functions");
None
}
};
Expand Down Expand Up @@ -142,6 +140,29 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
});
}
}
AttributeKind::TrackCaller(attr_span) => {
let is_closure = tcx.is_closure_like(did.to_def_id());

if !is_closure
&& let Some(fn_sig) = fn_sig(*attr_span)
&& fn_sig.skip_binder().abi() != ExternAbi::Rust
{
tcx.dcx().emit_err(errors::RequiresRustAbi { span: *attr_span });
}
if is_closure
&& !tcx.features().closure_track_caller()
&& !attr_span.allows_unstable(sym::closure_track_caller)
{
feature_err(
&tcx.sess,
sym::closure_track_caller,
*attr_span,
"`#[track_caller]` on closures is currently unstable",
)
.emit();
}
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER
}
_ => {}
}
}
Expand Down Expand Up @@ -208,29 +229,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
}
}
sym::thread_local => codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL,
sym::track_caller => {
let is_closure = tcx.is_closure_like(did.to_def_id());

if !is_closure
&& let Some(fn_sig) = fn_sig()
&& fn_sig.skip_binder().abi() != ExternAbi::Rust
{
tcx.dcx().emit_err(errors::RequiresRustAbi { span: attr.span() });
}
if is_closure
&& !tcx.features().closure_track_caller()
&& !attr.span().allows_unstable(sym::closure_track_caller)
{
feature_err(
&tcx.sess,
sym::closure_track_caller,
attr.span(),
"`#[track_caller]` on closures is currently unstable",
)
.emit();
}
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER
}
sym::export_name => {
if let Some(s) = attr.value_str() {
if s.as_str().contains('\0') {
Expand Down
9 changes: 6 additions & 3 deletions compiler/rustc_hir_analysis/src/check/entry.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
use std::ops::Not;

use rustc_abi::ExternAbi;
use rustc_attr_data_structures::{AttributeKind, find_attr};
use rustc_hir as hir;
use rustc_hir::Node;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::span_bug;
use rustc_middle::ty::{self, TyCtxt, TypingMode};
use rustc_session::config::EntryFnType;
use rustc_span::Span;
use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
use rustc_span::{Span, sym};
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};

Expand Down Expand Up @@ -98,8 +99,10 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
error = true;
}

for attr in tcx.get_attrs(main_def_id, sym::track_caller) {
tcx.dcx().emit_err(errors::TrackCallerOnMain { span: attr.span(), annotated: main_span });
if let Some(attr_span) =
find_attr!(tcx.get_all_attrs(main_def_id), AttributeKind::TrackCaller(span) => *span)
{
tcx.dcx().emit_err(errors::TrackCallerOnMain { span: attr_span, annotated: main_span });
error = true;
}

Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_lint/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1184,11 +1184,11 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller {
if fn_kind.asyncness().is_async()
&& !cx.tcx.features().async_fn_track_caller()
// Now, check if the function has the `#[track_caller]` attribute
&& let Some(attr) = cx.tcx.get_attr(def_id, sym::track_caller)
&& let Some(attr_span) = find_attr!(cx.tcx.get_all_attrs(def_id), AttributeKind::TrackCaller(span) => *span)
{
cx.emit_span_lint(
UNGATED_ASYNC_FN_TRACK_CALLER,
attr.span(),
attr_span,
BuiltinUngatedAsyncFnTrackCaller { label: span, session: &cx.tcx.sess },
);
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_parse/src/validate_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ fn emit_malformed_attribute(
| sym::optimize
| sym::cold
| sym::must_use
| sym::track_caller
) {
return;
}
Expand Down
10 changes: 4 additions & 6 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
Attribute::Parsed(AttributeKind::Naked(attr_span)) => {
self.check_naked(hir_id, *attr_span, span, target)
}
Attribute::Parsed(AttributeKind::TrackCaller(attr_span)) => {
self.check_track_caller(hir_id, *attr_span, attrs, span, target)
}
Attribute::Parsed(
AttributeKind::BodyStability { .. }
| AttributeKind::ConstStabilityIndirect
Expand Down Expand Up @@ -199,9 +202,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
self.check_target_feature(hir_id, attr, span, target, attrs)
}
[sym::thread_local, ..] => self.check_thread_local(attr, span, target),
[sym::track_caller, ..] => {
self.check_track_caller(hir_id, attr.span(), attrs, span, target)
}
[sym::doc, ..] => self.check_doc_attrs(
attr,
attr_item.style,
Expand Down Expand Up @@ -716,9 +716,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
// erroneously allowed it and some crates used it accidentally, to be compatible
// with crates depending on them, we can't throw an error here.
Target::Field | Target::Arm | Target::MacroDef => {
for attr in attrs {
Copy link
Contributor Author

@jdonszelmann jdonszelmann Jun 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this entire loop is simply wrong and unnecessary

self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "track_caller");
}
self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "track_caller");
}
_ => {
self.dcx().emit_err(errors::TrackedCallerWrongLocation {
Expand Down
5 changes: 3 additions & 2 deletions src/tools/clippy/clippy_lints/src/eta_reduction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use clippy_utils::{
get_path_from_caller_to_method_type, is_adjusted, is_no_std_crate, path_to_local, path_to_local_id,
};
use rustc_abi::ExternAbi;
use rustc_attr_data_structures::{AttributeKind, find_attr};
use rustc_errors::Applicability;
use rustc_hir::{BindingMode, Expr, ExprKind, FnRetTy, GenericArgs, Param, PatKind, QPath, Safety, TyKind};
use rustc_infer::infer::TyCtxtInferExt;
Expand Down Expand Up @@ -155,7 +156,7 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
let sig = match callee_ty_adjusted.kind() {
ty::FnDef(def, _) => {
// Rewriting `x(|| f())` to `x(f)` where f is marked `#[track_caller]` moves the `Location`
if cx.tcx.has_attr(*def, sym::track_caller) {
if find_attr!(cx.tcx.get_all_attrs(*def), AttributeKind::TrackCaller(..)) {
return;
}

Expand Down Expand Up @@ -236,7 +237,7 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
},
ExprKind::MethodCall(path, self_, args, _) if check_inputs(typeck, body.params, Some(self_), args) => {
if let Some(method_def_id) = typeck.type_dependent_def_id(body.value.hir_id)
&& !cx.tcx.has_attr(method_def_id, sym::track_caller)
&& !find_attr!(cx.tcx.get_all_attrs(method_def_id), AttributeKind::TrackCaller(..))
&& check_sig(closure_sig, cx.tcx.fn_sig(method_def_id).skip_binder().skip_binder())
{
let mut app = Applicability::MachineApplicable;
Expand Down
24 changes: 12 additions & 12 deletions tests/ui/lint/unused/unused-attr-duplicate.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -89,18 +89,6 @@ note: attribute also specified here
LL | #[automatically_derived]
| ^^^^^^^^^^^^^^^^^^^^^^^^

error: unused attribute
--> $DIR/unused-attr-duplicate.rs:79:1
|
LL | #[track_caller]
| ^^^^^^^^^^^^^^^ help: remove this attribute
|
note: attribute also specified here
--> $DIR/unused-attr-duplicate.rs:78:1
|
LL | #[track_caller]
| ^^^^^^^^^^^^^^^

error: unused attribute
--> $DIR/unused-attr-duplicate.rs:92:1
|
Expand Down Expand Up @@ -277,6 +265,18 @@ note: attribute also specified here
LL | #[cold]
| ^^^^^^^

error: unused attribute
--> $DIR/unused-attr-duplicate.rs:79:1
|
LL | #[track_caller]
| ^^^^^^^^^^^^^^^ help: remove this attribute
|
note: attribute also specified here
--> $DIR/unused-attr-duplicate.rs:78:1
|
LL | #[track_caller]
| ^^^^^^^^^^^^^^^

error: unused attribute
--> $DIR/unused-attr-duplicate.rs:98:1
|
Expand Down
8 changes: 6 additions & 2 deletions tests/ui/rfcs/rfc-2091-track-caller/error-odd-syntax.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
error: malformed `track_caller` attribute input
error[E0565]: malformed `track_caller` attribute input
--> $DIR/error-odd-syntax.rs:1:1
|
LL | #[track_caller(1)]
| ^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[track_caller]`
| ^^^^^^^^^^^^^^---^
| | |
| | didn't expect any arguments here
| help: must be of the form: `#[track_caller]`

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0565`.
Loading