diff --git a/src/doc/unstable-book/src/language-features/track-caller.md b/src/doc/unstable-book/src/language-features/track-caller.md new file mode 100644 index 00000000000..afc11a2b949 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/track-caller.md @@ -0,0 +1,5 @@ +# `track_caller` + +The tracking issue for this feature is: [#47809](https://github.com/rust-lang/rust/issues/47809). + +------------------------ diff --git a/src/librustc/error_codes.rs b/src/librustc/error_codes.rs index 502172db91c..959a06c2e32 100644 --- a/src/librustc/error_codes.rs +++ b/src/librustc/error_codes.rs @@ -1640,6 +1640,16 @@ each method; it is not possible to annotate the entire impl with an `#[inline]` attribute. "##, +E0900: r##" +TODO: change error number +TODO: track_caller: invalid syntax +"##, + +E0901: r##" +TODO: change error number +TODO: track_caller: no naked functions +"##, + E0522: r##" The lang attribute is intended for marking special items that are built-in to Rust itself. This includes special traits (like `Copy` and `Sized`) that affect diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index d5e956555bd..31a09645d16 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -94,6 +94,7 @@ impl CheckAttrVisitor<'tcx> { /// Checks any attribute. fn check_attributes(&self, item: &hir::Item, target: Target) { let mut is_valid = true; + let mut track_caller_span = None; for attr in &item.attrs { is_valid &= if attr.check_name(sym::inline) { self.check_inline(attr, &item.span, target) @@ -103,6 +104,9 @@ 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) { + track_caller_span = Some(attr.span); + self.check_track_caller(attr, &item, target) } else { true }; @@ -118,6 +122,19 @@ impl CheckAttrVisitor<'tcx> { self.check_repr(item, target); self.check_used(item, target); + + // Checks if `#[track_caller]` and `#[naked]` are both used. + if let Some(span) = track_caller_span { + if item.attrs.iter().any(|attr| attr.check_name(sym::naked)) { + struct_span_err!( + self.tcx.sess, + span, + E0901, + "cannot use `#[track_caller]` with `#[naked]`", + ) + .emit(); + } + } } /// Checks if an `#[inline]` is applied to a function or a closure. Returns `true` if valid. @@ -135,6 +152,23 @@ impl CheckAttrVisitor<'tcx> { } } + /// Checks if a `#[target_feature]` can be applied. + 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, + E0900, + "attribute should be applied to function" + ) + .span_label(item.span, "not a function") + .emit(); + false + } else { + true + } + } + /// Checks if the `#[non_exhaustive]` attribute on an `item` is valid. Returns `true` if valid. fn check_non_exhaustive( &self, diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 30b05036688..f7240d6bf82 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -2721,7 +2721,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; } } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index e736a55a5f5..3c9010de5cb 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -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 methods + for attr in &trait_item.attrs { + if attr.check_name(sym::track_caller) { + struct_span_err!( + tcx.sess, + attr.span, + E0903, + "`#[track_caller]` is not supported for trait items yet." + ).emit(); + } + } } pub fn check_impl_item(tcx: TyCtxt<'_>, def_id: DefId) { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 64eca137144..0b98e4b781d 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -2594,6 +2594,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, + E0902, + "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") { diff --git a/src/librustc_typeck/error_codes.rs b/src/librustc_typeck/error_codes.rs index 3a07171b12f..f698427c78a 100644 --- a/src/librustc_typeck/error_codes.rs +++ b/src/librustc_typeck/error_codes.rs @@ -4907,6 +4907,17 @@ fn foo_recursive(n: usize) -> Pin>> { The `Box<...>` ensures that the result is of known size, and the pin is required to keep it in the same place in memory. "##, + +E0902: r##" +TODO: change error number +TODO: track_caller: require Rust ABI to use track_caller +"##, + +E0903: r##" +TODO: change error number +TODO: track_caller: can't apply in traits +"##, + ; // E0035, merged into E0087/E0089 // E0036, merged into E0087/E0089 diff --git a/src/libsyntax/feature_gate/active.rs b/src/libsyntax/feature_gate/active.rs index 19ef430318d..312a9bf6e75 100644 --- a/src/libsyntax/feature_gate/active.rs +++ b/src/libsyntax/feature_gate/active.rs @@ -525,6 +525,9 @@ declare_features! ( // Allows the use of raw-dylibs (RFC 2627). (active, raw_dylib, "1.40.0", Some(58713), None), + /// Enable accurate caller location reporting during panic (RFC 2091). + (active, track_caller, "1.37.0", Some(47809), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/src/libsyntax/feature_gate/builtin_attrs.rs b/src/libsyntax/feature_gate/builtin_attrs.rs index c12d0ce06ff..d6a6450e471 100644 --- a/src/libsyntax/feature_gate/builtin_attrs.rs +++ b/src/libsyntax/feature_gate/builtin_attrs.rs @@ -499,6 +499,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ cfg_fn!(no_debug) ) ), + gated!( + track_caller, Whitelisted, template!(Word), + "the `#[track_caller]` attribute is an experimental feature", + ), gated!( // Used in resolve: prelude_import, Whitelisted, template!(Word), diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index c7230d5ca15..2b005c3fc42 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -674,6 +674,7 @@ symbols! { tool_attributes, tool_lints, trace_macros, + track_caller, trait_alias, transmute, transparent, diff --git a/src/test/ui/feature-gates/feature-gate-track_caller.rs b/src/test/ui/feature-gates/feature-gate-track_caller.rs new file mode 100644 index 00000000000..458df0b2b02 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-track_caller.rs @@ -0,0 +1,6 @@ + +#[track_caller] +fn f() {} +//~^^ ERROR the `#[track_caller]` attribute is an experimental feature + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-track_caller.stderr b/src/test/ui/feature-gates/feature-gate-track_caller.stderr new file mode 100644 index 00000000000..9a058736e50 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-track_caller.stderr @@ -0,0 +1,12 @@ +error[E0658]: the `#[track_caller]` attribute is an experimental feature + --> $DIR/feature-gate-track_caller.rs:2:1 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/47809 + = help: add `#![feature(track_caller)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/rfc-2091-track-caller/error-odd-syntax.rs b/src/test/ui/rfc-2091-track-caller/error-odd-syntax.rs new file mode 100644 index 00000000000..d6560231871 --- /dev/null +++ b/src/test/ui/rfc-2091-track-caller/error-odd-syntax.rs @@ -0,0 +1,7 @@ +#![feature(track_caller)] + +#[track_caller(1)] +fn f() {} +//~^^ ERROR malformed `track_caller` attribute input + +fn main() {} diff --git a/src/test/ui/rfc-2091-track-caller/error-odd-syntax.stderr b/src/test/ui/rfc-2091-track-caller/error-odd-syntax.stderr new file mode 100644 index 00000000000..8906fa59506 --- /dev/null +++ b/src/test/ui/rfc-2091-track-caller/error-odd-syntax.stderr @@ -0,0 +1,8 @@ +error: malformed `track_caller` attribute input + --> $DIR/error-odd-syntax.rs:3:1 + | +LL | #[track_caller(1)] + | ^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[track_caller]` + +error: aborting due to previous error + diff --git a/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs b/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs new file mode 100644 index 00000000000..5c42a1b3faa --- /dev/null +++ b/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs @@ -0,0 +1,7 @@ +#![feature(track_caller)] + +#[track_caller] +extern "C" fn f() {} +//~^^ ERROR rust ABI is required to use `#[track_caller]` + +fn main() {} diff --git a/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr b/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr new file mode 100644 index 00000000000..fc6f4d17dcc --- /dev/null +++ b/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr @@ -0,0 +1,9 @@ +error[E0902]: rust ABI is required to use `#[track_caller]` + --> $DIR/error-with-invalid-abi.rs:3:1 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0902`. diff --git a/src/test/ui/rfc-2091-track-caller/error-with-naked.rs b/src/test/ui/rfc-2091-track-caller/error-with-naked.rs new file mode 100644 index 00000000000..dd9e5d04135 --- /dev/null +++ b/src/test/ui/rfc-2091-track-caller/error-with-naked.rs @@ -0,0 +1,8 @@ +#![feature(naked_functions, track_caller)] + +#[track_caller] +#[naked] +fn f() {} +//~^^^ ERROR cannot use `#[track_caller]` with `#[naked]` + +fn main() {} diff --git a/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr b/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr new file mode 100644 index 00000000000..3566d288ed1 --- /dev/null +++ b/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr @@ -0,0 +1,9 @@ +error[E0901]: cannot use `#[track_caller]` with `#[naked]` + --> $DIR/error-with-naked.rs:3:1 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0901`. diff --git a/src/test/ui/rfc-2091-track-caller/error-with-trait-fns.rs b/src/test/ui/rfc-2091-track-caller/error-with-trait-fns.rs new file mode 100644 index 00000000000..c00cf7367ce --- /dev/null +++ b/src/test/ui/rfc-2091-track-caller/error-with-trait-fns.rs @@ -0,0 +1,13 @@ +#![feature(track_caller)] + +trait Trait { + #[track_caller] + fn unwrap(&self); + //~^^ ERROR: `#[track_caller]` is not supported for trait items yet. +} + +impl Trait for u64 { + fn unwrap(&self) {} +} + +fn main() {} diff --git a/src/test/ui/rfc-2091-track-caller/error-with-trait-fns.stderr b/src/test/ui/rfc-2091-track-caller/error-with-trait-fns.stderr new file mode 100644 index 00000000000..bd3d4043a64 --- /dev/null +++ b/src/test/ui/rfc-2091-track-caller/error-with-trait-fns.stderr @@ -0,0 +1,9 @@ +error[E0903]: `#[track_caller]` is not supported for trait items yet. + --> $DIR/error-with-trait-fns.rs:4:5 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0903`. diff --git a/src/test/ui/rfc-2091-track-caller/only-for-fns.rs b/src/test/ui/rfc-2091-track-caller/only-for-fns.rs new file mode 100644 index 00000000000..0fd59b4bf49 --- /dev/null +++ b/src/test/ui/rfc-2091-track-caller/only-for-fns.rs @@ -0,0 +1,7 @@ +#![feature(track_caller)] + +#[track_caller] +struct S; +//~^^ ERROR attribute should be applied to function + +fn main() {} diff --git a/src/test/ui/rfc-2091-track-caller/only-for-fns.stderr b/src/test/ui/rfc-2091-track-caller/only-for-fns.stderr new file mode 100644 index 00000000000..9ddc99c02bf --- /dev/null +++ b/src/test/ui/rfc-2091-track-caller/only-for-fns.stderr @@ -0,0 +1,11 @@ +error[E0900]: attribute should be applied to function + --> $DIR/only-for-fns.rs:3:1 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ +LL | struct S; + | --------- not a function + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0900`.