Skip to content
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

WIP Add a shim for functions annotated with #[track_caller] (RFC 2091 #2/N) #65082

Closed
wants to merge 14 commits into from
Closed
5 changes: 5 additions & 0 deletions src/doc/unstable-book/src/language-features/track-caller.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# `track_caller`

The tracking issue for this feature is: [#47809](https://github.com/rust-lang/rust/issues/47809).

------------------------
20 changes: 20 additions & 0 deletions src/librustc/error_codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2234,6 +2234,25 @@ These attributes are meant to only be used by the standard library and are
rejected in your own crates.
"##,

E0736: r##"
#[track_caller] and #[naked] cannot be applied to the same function.
anp marked this conversation as resolved.
Show resolved Hide resolved

Erroneous code example:

```compile_fail,E0736
#![feature(track_caller)]

#[naked]
#[track_caller]
fn foo() {}
```

This is primarily due to ABI incompatibilities between the two attributes.
See [RFC 2091] for details on this and other limitations.

[RFC 2091]: https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md
"##,

;
// E0006, // merged with E0005
// E0101, // replaced with E0282
Expand Down Expand Up @@ -2296,4 +2315,5 @@ rejected in your own crates.
E0726, // non-explicit (not `'_`) elided lifetime in unsupported position
E0727, // `async` generators are not yet supported
E0728, // `await` must be in an `async` function or block
E0739, // invalid track_caller application/syntax
}
30 changes: 29 additions & 1 deletion src/librustc/hir/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::ty::TyCtxt;
use crate::ty::query::Providers;

use std::fmt::{self, Display};
use syntax::symbol::sym;
use syntax::{attr, symbol::sym};
use syntax_pos::Span;

#[derive(Copy, Clone, PartialEq)]
Expand Down Expand Up @@ -103,6 +103,8 @@ impl CheckAttrVisitor<'tcx> {
self.check_marker(attr, item, target)
} else if attr.check_name(sym::target_feature) {
self.check_target_feature(attr, item, target)
} else if attr.check_name(sym::track_caller) {
self.check_track_caller(attr, &item, target)
} else {
true
};
Expand Down Expand Up @@ -135,6 +137,32 @@ impl CheckAttrVisitor<'tcx> {
}
}

/// Checks if a `#[track_caller]` is applied to a non-naked function. Returns `true` if valid.
fn check_track_caller(&self, attr: &hir::Attribute, item: &hir::Item, target: Target) -> bool {
if target != Target::Fn {
struct_span_err!(
self.tcx.sess,
attr.span,
E0739,
anp marked this conversation as resolved.
Show resolved Hide resolved
"attribute should be applied to function"
)
.span_label(item.span, "not a function")
.emit();
false
} else if attr::contains_name(&item.attrs, sym::naked) {
struct_span_err!(
self.tcx.sess,
attr.span,
E0736,
"cannot use `#[track_caller]` with `#[naked]`",
)
.emit();
false
} else {
true
}
}

/// Checks if the `#[non_exhaustive]` attribute on an `item` is valid. Returns `true` if valid.
fn check_non_exhaustive(
&self,
Expand Down
4 changes: 3 additions & 1 deletion src/librustc/hir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2716,7 +2716,9 @@ bitflags! {
const USED = 1 << 9;
/// #[ffi_returns_twice], indicates that an extern function can return
/// multiple times
const FFI_RETURNS_TWICE = 1 << 10;
const FFI_RETURNS_TWICE = 1 << 10;
/// #[track_caller]: allow access to the caller location
const TRACK_CALLER = 1 << 11;
}
}

Expand Down
1 change: 1 addition & 0 deletions src/librustc/mir/mono.rs
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,7 @@ impl<'tcx> CodegenUnit<'tcx> {
tcx.hir().as_local_hir_id(def_id)
}
InstanceDef::VtableShim(..) |
InstanceDef::ReifyShim(..) |
InstanceDef::Intrinsic(..) |
InstanceDef::FnPtrShim(..) |
InstanceDef::Virtual(..) |
Expand Down
29 changes: 29 additions & 0 deletions src/librustc/ty/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ pub enum InstanceDef<'tcx> {
/// `<T as Trait>::method` where `method` receives unsizeable `self: Self`.
VtableShim(DefId),

/// `fn()` pointer where the function is annotated with `#[track_caller]`.
ReifyShim(DefId),

/// `<fn() as FnTrait>::call_*`
/// `DefId` is `FnTrait::call_*`
FnPtrShim(DefId, Ty<'tcx>),
Expand Down Expand Up @@ -123,6 +126,7 @@ impl<'tcx> InstanceDef<'tcx> {
match *self {
InstanceDef::Item(def_id) |
InstanceDef::VtableShim(def_id) |
InstanceDef::ReifyShim(def_id) |
InstanceDef::FnPtrShim(def_id, _) |
InstanceDef::Virtual(def_id, _) |
InstanceDef::Intrinsic(def_id, ) |
Expand Down Expand Up @@ -178,6 +182,9 @@ impl<'tcx> fmt::Display for Instance<'tcx> {
InstanceDef::VtableShim(_) => {
write!(f, " - shim(vtable)")
}
InstanceDef::ReifyShim(_) => {
write!(f, " - shim(reify)")
}
InstanceDef::Intrinsic(_) => {
write!(f, " - intrinsic")
}
Expand Down Expand Up @@ -290,6 +297,28 @@ impl<'tcx> Instance<'tcx> {
result
}

pub fn resolve_for_fn_ptr(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
def_id: DefId,
substs: SubstsRef<'tcx>,
) -> Option<Instance<'tcx>> {
debug!("resolve(def_id={:?}, substs={:?})", def_id, substs);
let fn_sig = tcx.fn_sig(def_id);
// let is_reify_shim = fn_sig.inputs().skip_binder().len() > 0
// && fn_sig.input(0).skip_binder().is_param(0)
// && tcx.generics_of(def_id).has_self;
if is_reify_shim {
debug!(" => fn ptr with implicit caller location");
Some(Instance {
def: InstanceDef::ReifyShim(def_id),
substs,
})
} else {
Instance::resolve(tcx, param_env, def_id, substs)
}
}

pub fn resolve_for_vtable(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
Expand Down
1 change: 1 addition & 0 deletions src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3026,6 +3026,7 @@ impl<'tcx> TyCtxt<'tcx> {
self.optimized_mir(did)
}
ty::InstanceDef::VtableShim(..) |
ty::InstanceDef::ReifyShim(..) |
ty::InstanceDef::Intrinsic(..) |
ty::InstanceDef::FnPtrShim(..) |
ty::InstanceDef::Virtual(..) |
Expand Down
5 changes: 4 additions & 1 deletion src/librustc/ty/structural_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -761,6 +761,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::InstanceDef<'a> {
Some(ty::InstanceDef::Item(def_id)),
ty::InstanceDef::VtableShim(def_id) =>
Some(ty::InstanceDef::VtableShim(def_id)),
ty::InstanceDef::ReifyShim(def_id) =>
Some(ty::InstanceDef::ReifyShim(def_id)),
ty::InstanceDef::Intrinsic(def_id) =>
Some(ty::InstanceDef::Intrinsic(def_id)),
ty::InstanceDef::FnPtrShim(def_id, ref ty) =>
Expand Down Expand Up @@ -966,6 +968,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> {
def: match self.def {
Item(did) => Item(did.fold_with(folder)),
VtableShim(did) => VtableShim(did.fold_with(folder)),
ReifyShim(did) => ReifyShim(did.fold_with(folder)),
Intrinsic(did) => Intrinsic(did.fold_with(folder)),
FnPtrShim(did, ty) => FnPtrShim(
did.fold_with(folder),
Expand Down Expand Up @@ -994,7 +997,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> {
use crate::ty::InstanceDef::*;
self.substs.visit_with(visitor) ||
match self.def {
Item(did) | VtableShim(did) | Intrinsic(did) | Virtual(did, _) => {
Item(did) | VtableShim(did) | ReifyShim(did) | Intrinsic(did) | Virtual(did, _) => {
did.visit_with(visitor)
},
FnPtrShim(did, ty) | CloneShim(did, ty) => {
Expand Down
1 change: 1 addition & 0 deletions src/librustc_mir/interpret/terminator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Ok(())
}
ty::InstanceDef::VtableShim(..) |
ty::InstanceDef::ReifyShim(..) |
ty::InstanceDef::ClosureOnceShim { .. } |
ty::InstanceDef::FnPtrShim(..) |
ty::InstanceDef::DropGlue(..) |
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_mir/monomorphize/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,7 @@ fn visit_instance_use<'tcx>(
}
}
ty::InstanceDef::VtableShim(..) |
ty::InstanceDef::ReifyShim(..) |
ty::InstanceDef::Virtual(..) |
ty::InstanceDef::DropGlue(_, None) => {
// don't need to emit shim if we are calling directly.
Expand All @@ -766,6 +767,7 @@ fn should_monomorphize_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx
let def_id = match instance.def {
ty::InstanceDef::Item(def_id) => def_id,
ty::InstanceDef::VtableShim(..) |
ty::InstanceDef::ReifyShim(..) |
ty::InstanceDef::ClosureOnceShim { .. } |
ty::InstanceDef::Virtual(..) |
ty::InstanceDef::FnPtrShim(..) |
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_mir/monomorphize/partitioning.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ fn mono_item_visibility(

// These are all compiler glue and such, never exported, always hidden.
InstanceDef::VtableShim(..) |
InstanceDef::ReifyShim(..) |
InstanceDef::FnPtrShim(..) |
InstanceDef::Virtual(..) |
InstanceDef::Intrinsic(..) |
Expand Down Expand Up @@ -664,6 +665,7 @@ fn characteristic_def_id_of_mono_item<'tcx>(
let def_id = match instance.def {
ty::InstanceDef::Item(def_id) => def_id,
ty::InstanceDef::VtableShim(..) |
ty::InstanceDef::ReifyShim(..) |
ty::InstanceDef::FnPtrShim(..) |
ty::InstanceDef::ClosureOnceShim { .. } |
ty::InstanceDef::Intrinsic(..) |
Expand Down
9 changes: 9 additions & 0 deletions src/librustc_mir/shim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,15 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> &'tcx
None,
)
}
ty::InstanceDef::ReifyShim(def_id) => {
build_call_shim(
tcx,
def_id,
Adjustment::DerefMove,
CallKind::Direct(def_id),
None,
)
}
ty::InstanceDef::FnPtrShim(def_id, ty) => {
let trait_ = tcx.trait_of_item(def_id).unwrap();
let adjustment = match tcx.lang_items().fn_trait_kind(trait_) {
Expand Down
36 changes: 36 additions & 0 deletions src/librustc_typeck/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,18 @@ pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: DefId) {
_ => None
};
check_associated_item(tcx, trait_item.hir_id, trait_item.span, method_sig);

// Prohibits applying `#[track_caller]` to trait decls
for attr in &trait_item.attrs {
if attr.check_name(sym::track_caller) {
struct_span_err!(
tcx.sess,
attr.span,
E0738,
"`#[track_caller]` is not supported in trait declarations."
).emit();
}
}
}

pub fn check_impl_item(tcx: TyCtxt<'_>, def_id: DefId) {
Expand All @@ -182,6 +194,30 @@ pub fn check_impl_item(tcx: TyCtxt<'_>, def_id: DefId) {
hir::ImplItemKind::Method(ref sig, _) => Some(sig),
_ => None
};

// Prohibits applying `#[track_caller]` to trait impls
if method_sig.is_some() {
let track_caller_attr = impl_item.attrs.iter()
.find(|a| a.check_name(sym::track_caller));
if let Some(tc_attr) = track_caller_attr {
let parent_hir_id = tcx.hir().get_parent_item(hir_id);
let containing_item = tcx.hir().expect_item(parent_hir_id);
let containing_impl_is_for_trait = match &containing_item.kind {
hir::ItemKind::Impl(_, _, _, _, tr, _, _) => tr.is_some(),
_ => bug!("parent of an ImplItem must be an Impl"),
};

if containing_impl_is_for_trait {
struct_span_err!(
tcx.sess,
tc_attr.span,
E0738,
"`#[track_caller]` is not supported in traits yet."
).emit();
}
}
}

check_associated_item(tcx, impl_item.hir_id, impl_item.span, method_sig);
}

Expand Down
10 changes: 10 additions & 0 deletions src/librustc_typeck/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2593,6 +2593,16 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED;
} else if attr.check_name(sym::thread_local) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL;
} else if attr.check_name(sym::track_caller) {
if tcx.fn_sig(id).abi() != abi::Abi::Rust {
struct_span_err!(
tcx.sess,
attr.span,
E0737,
"rust ABI is required to use `#[track_caller]`"
).emit();
}
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
} else if attr.check_name(sym::export_name) {
if let Some(s) = attr.value_str() {
if s.as_str().contains("\0") {
Expand Down
69 changes: 69 additions & 0 deletions src/librustc_typeck/error_codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4907,6 +4907,75 @@ fn foo_recursive(n: usize) -> Pin<Box<dyn Future<Output = ()>>> {
The `Box<...>` ensures that the result is of known size,
and the pin is required to keep it in the same place in memory.
"##,

E0737: r##"
#[track_caller] requires functions to have the "Rust" ABI for implicitly
receiving caller location. See [RFC 2091] for details on this and other
restrictions.

Erroneous code example:

```compile_fail,E0737
#![feature(track_caller)]

#[track_caller]
extern "C" fn foo() {}
```

[RFC 2091]: https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md
anp marked this conversation as resolved.
Show resolved Hide resolved
"##,

E0738: r##"
#[track_caller] cannot be used in traits yet. This is due to limitations in the
compiler which are likely to be temporary. See [RFC 2091] for details on this
and other restrictions.

Erroneous example with a trait method implementation:

```compile_fail,E0738
#![feature(track_caller)]

trait Foo {
fn bar(&self);
}

impl Foo for u64 {
#[track_caller]
fn bar(&self) {}
}
```

Erroneous example with a blanket trait method implementation:

```compile_fail,E0738
#![feature(track_caller)]

trait Foo {
#[track_caller]
fn bar(&self) {}
fn baz(&self);
}
```

Erroneous example with a trait method declaration:

```compile_fail,E0738
#[!feature(track_caller)]

trait Foo {
fn bar(&self) {}

#[track_caller]
fn baz(&self);
}
```

Note that while the compiler may be able to support the attribute in traits in
the future, [RFC 2091] prohibits their implementation without a follow-up RFC.

[RFC 2091]: https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md
anp marked this conversation as resolved.
Show resolved Hide resolved
"##,

;
// E0035, merged into E0087/E0089
// E0036, merged into E0087/E0089
Expand Down
Loading