Switch #[track_caller]
back to a no-op unless feature gate is enabled
This patch fixes a regression, in which `#[track_caller]`, which was previously a no-op, was changed to actually turn on the behavior. This should instead only happen behind the `closure_track_caller` feature gate. Also, add a warning for the user to understand how their code will compile depending on the feature gate being turned on or not. Fixes #104588
This commit is contained in:
parent
1d12c3cea3
commit
04926e0534
6 changed files with 157 additions and 1 deletions
|
@ -350,6 +350,8 @@ lint_builtin_mutable_transmutes =
|
||||||
|
|
||||||
lint_builtin_unstable_features = unstable feature
|
lint_builtin_unstable_features = unstable feature
|
||||||
|
|
||||||
|
lint_ungated_async_fn_track_caller = `#[track_caller]` on async functions is a no-op, unless the `closure_track_caller` feature is enabled
|
||||||
|
|
||||||
lint_builtin_unreachable_pub = unreachable `pub` {$what}
|
lint_builtin_unreachable_pub = unreachable `pub` {$what}
|
||||||
.suggestion = consider restricting its visibility
|
.suggestion = consider restricting its visibility
|
||||||
.help = or consider exporting it for use by other crates
|
.help = or consider exporting it for use by other crates
|
||||||
|
|
|
@ -25,6 +25,7 @@ use crate::{
|
||||||
types::{transparent_newtype_field, CItemKind},
|
types::{transparent_newtype_field, CItemKind},
|
||||||
EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext,
|
EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext,
|
||||||
};
|
};
|
||||||
|
use hir::IsAsync;
|
||||||
use rustc_ast::attr;
|
use rustc_ast::attr;
|
||||||
use rustc_ast::tokenstream::{TokenStream, TokenTree};
|
use rustc_ast::tokenstream::{TokenStream, TokenTree};
|
||||||
use rustc_ast::visit::{FnCtxt, FnKind};
|
use rustc_ast::visit::{FnCtxt, FnKind};
|
||||||
|
@ -40,7 +41,10 @@ use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, Gate
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID};
|
use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID};
|
||||||
use rustc_hir::{ForeignItemKind, GenericParamKind, HirId, Node, PatKind, PredicateOrigin};
|
use rustc_hir::intravisit::FnKind as HirFnKind;
|
||||||
|
use rustc_hir::{
|
||||||
|
Body, FnDecl, ForeignItemKind, GenericParamKind, HirId, Node, PatKind, PredicateOrigin,
|
||||||
|
};
|
||||||
use rustc_index::vec::Idx;
|
use rustc_index::vec::Idx;
|
||||||
use rustc_middle::lint::in_external_macro;
|
use rustc_middle::lint::in_external_macro;
|
||||||
use rustc_middle::ty::layout::{LayoutError, LayoutOf};
|
use rustc_middle::ty::layout::{LayoutError, LayoutOf};
|
||||||
|
@ -1370,6 +1374,45 @@ impl<'tcx> LateLintPass<'tcx> for UnstableFeatures {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare_lint! {
|
||||||
|
/// `#[track_caller]` is a no-op without corresponding feature flag
|
||||||
|
UNGATED_ASYNC_FN_TRACK_CALLER,
|
||||||
|
Warn,
|
||||||
|
"enabling track_caller on an async fn is a no-op unless the closure_track_caller feature is enabled"
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_lint_pass!(
|
||||||
|
/// Explains corresponding feature flag must be enabled for the `#[track_caller] attribute to
|
||||||
|
/// do anything
|
||||||
|
UngatedAsyncFnTrackCaller => [UNGATED_ASYNC_FN_TRACK_CALLER]
|
||||||
|
);
|
||||||
|
|
||||||
|
impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller {
|
||||||
|
fn check_fn(
|
||||||
|
&mut self,
|
||||||
|
cx: &LateContext<'_>,
|
||||||
|
fn_kind: HirFnKind<'_>,
|
||||||
|
_: &'tcx FnDecl<'_>,
|
||||||
|
_: &'tcx Body<'_>,
|
||||||
|
span: Span,
|
||||||
|
hir_id: HirId,
|
||||||
|
) {
|
||||||
|
if let HirFnKind::ItemFn(_, _, _) = fn_kind && fn_kind.asyncness() == IsAsync::Async && !cx.tcx.features().closure_track_caller {
|
||||||
|
// Now, check if the function has the `#[track_caller]` attribute
|
||||||
|
let attrs = cx.tcx.hir().attrs(hir_id);
|
||||||
|
let maybe_track_caller = attrs.iter().find(|attr| attr.has_name(sym::track_caller));
|
||||||
|
if let Some(attr) = maybe_track_caller {
|
||||||
|
cx.struct_span_lint(
|
||||||
|
UNGATED_ASYNC_FN_TRACK_CALLER,
|
||||||
|
span.with_hi(attr.span.hi()),
|
||||||
|
fluent::lint_ungated_async_fn_track_caller,
|
||||||
|
|lint| lint,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
/// The `unreachable_pub` lint triggers for `pub` items not reachable from
|
/// The `unreachable_pub` lint triggers for `pub` items not reachable from
|
||||||
/// the crate root.
|
/// the crate root.
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
// run-pass
|
||||||
|
// edition:2021
|
||||||
|
// needs-unwind
|
||||||
|
|
||||||
|
|
||||||
|
use std::future::Future;
|
||||||
|
use std::panic;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
use std::task::{Context, Poll, Wake};
|
||||||
|
use std::thread::{self, Thread};
|
||||||
|
|
||||||
|
/// A waker that wakes up the current thread when called.
|
||||||
|
struct ThreadWaker(Thread);
|
||||||
|
|
||||||
|
impl Wake for ThreadWaker {
|
||||||
|
fn wake(self: Arc<Self>) {
|
||||||
|
self.0.unpark();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run a future to completion on the current thread.
|
||||||
|
fn block_on<T>(fut: impl Future<Output = T>) -> T {
|
||||||
|
// Pin the future so it can be polled.
|
||||||
|
let mut fut = Box::pin(fut);
|
||||||
|
|
||||||
|
// Create a new context to be passed to the future.
|
||||||
|
let t = thread::current();
|
||||||
|
let waker = Arc::new(ThreadWaker(t)).into();
|
||||||
|
let mut cx = Context::from_waker(&waker);
|
||||||
|
|
||||||
|
// Run the future to completion.
|
||||||
|
loop {
|
||||||
|
match fut.as_mut().poll(&mut cx) {
|
||||||
|
Poll::Ready(res) => return res,
|
||||||
|
Poll::Pending => thread::park(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn bar() {
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn foo() {
|
||||||
|
bar().await
|
||||||
|
}
|
||||||
|
|
||||||
|
#[track_caller] //~ WARN `#[track_caller]` on async functions is a no-op, unless the `closure_track_caller` feature is enabled [ungated_async_fn_track_caller]
|
||||||
|
async fn bar_track_caller() {
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn foo_track_caller() {
|
||||||
|
bar_track_caller().await
|
||||||
|
}
|
||||||
|
|
||||||
|
fn panicked_at(f: impl FnOnce() + panic::UnwindSafe) -> u32 {
|
||||||
|
let loc = Arc::new(Mutex::new(None));
|
||||||
|
|
||||||
|
let hook = panic::take_hook();
|
||||||
|
{
|
||||||
|
let loc = loc.clone();
|
||||||
|
panic::set_hook(Box::new(move |info| {
|
||||||
|
*loc.lock().unwrap() = info.location().map(|loc| loc.line())
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
panic::catch_unwind(f).unwrap_err();
|
||||||
|
panic::set_hook(hook);
|
||||||
|
let x = loc.lock().unwrap().unwrap();
|
||||||
|
x
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
assert_eq!(panicked_at(|| block_on(foo())), 41);
|
||||||
|
// Since the `closure_track_caller` feature is not enabled, the
|
||||||
|
// `track_caller annotation does nothing.
|
||||||
|
assert_eq!(panicked_at(|| block_on(foo_track_caller())), 50);
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
warning: `#[track_caller]` on async functions is a no-op, unless the `closure_track_caller` feature is enabled
|
||||||
|
--> $DIR/issue-104588-no-op-panic-track-caller.rs:48:16
|
||||||
|
|
|
||||||
|
LL | #[track_caller]
|
||||||
|
| ________________^
|
||||||
|
LL | | async fn bar_track_caller() {
|
||||||
|
| |_
|
||||||
|
|
|
||||||
|
= note: `#[warn(ungated_async_fn_track_caller)]` on by default
|
||||||
|
|
||||||
|
warning: 1 warning emitted
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
// check-pass
|
||||||
|
// edition:2021
|
||||||
|
|
||||||
|
#[track_caller] //~ WARN `#[track_caller]` on async functions is a no-op, unless the `closure_track_caller` feature is enabled
|
||||||
|
async fn foo() {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
foo();
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
warning: `#[track_caller]` on async functions is a no-op, unless the `closure_track_caller` feature is enabled
|
||||||
|
--> $DIR/issue-104588-no-op-track-caller.rs:4:16
|
||||||
|
|
|
||||||
|
LL | #[track_caller]
|
||||||
|
| ________________^
|
||||||
|
LL | | async fn foo() {}
|
||||||
|
| |_
|
||||||
|
|
|
||||||
|
= note: `#[warn(ungated_async_fn_track_caller)]` on by default
|
||||||
|
|
||||||
|
warning: 1 warning emitted
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue