Auto merge of #65881 - anp:implicit-caller-location, r=eddyb,oli-obk

Implement #[track_caller] attribute. (RFC 2091 4/N)

Implements the `#[track_caller]` attribute in both const and codegen contexts.

The const implementation walks up the stack to find the nearest untracked callsite.

The codegen implementation adds an implicit argument to tracked function calls, and populates it with either a call to the previously-landed intrinsic or if the caller has `#[track_caller]` with a copy of the location passed to the current function.

Also includes a little cleanup and a few comments in the other caller location areas.

[Depends on: 65664](https://github.com/rust-lang/rust/pull/65664)
[RFC 2091 text](https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md)
[Tracking issue](https://github.com/rust-lang/rust/issues/47809)
[Tracking doc](https://paper.dropbox.com/doc/track_rfc_2091_impl-notes--Anf1NwnIb0xcRv31YLIadyj0Ag-rwCdRc2fi2yvRZ7syGZ9q#:uid=863513134494965680023183&h2=TODO-actually-pass-location-to)
This commit is contained in:
bors 2019-12-07 21:14:39 +00:00
commit de17464b14
35 changed files with 286 additions and 141 deletions

View file

@ -1,23 +0,0 @@
// run-pass
#![feature(const_fn, core_intrinsics)]
use std::{intrinsics::caller_location, panic::Location};
const LOCATION: &Location = caller_location();
const NESTED: &Location = {
const fn nested_location() -> &'static Location<'static> {
caller_location()
};
nested_location()
};
fn main() {
assert_eq!(LOCATION.file(), file!());
assert_eq!(LOCATION.line(), 7);
assert_eq!(LOCATION.column(), 29);
assert_eq!(NESTED.file(), file!());
assert_eq!(NESTED.line(), 10);
assert_eq!(NESTED.column(), 9);
}

View file

@ -1,21 +1,27 @@
// run-pass
#![feature(core_intrinsics)]
#![feature(track_caller)]
#[inline(never)]
#[track_caller]
fn defeat_const_prop() -> &'static core::panic::Location<'static> {
core::panic::Location::caller()
}
macro_rules! caller_location_from_macro {
() => (core::intrinsics::caller_location());
() => (defeat_const_prop());
}
fn main() {
let loc = core::intrinsics::caller_location();
let loc = defeat_const_prop();
assert_eq!(loc.file(), file!());
assert_eq!(loc.line(), 10);
assert_eq!(loc.line(), 16);
assert_eq!(loc.column(), 15);
// `caller_location()` in a macro should behave similarly to `file!` and `line!`,
// `Location::caller()` in a macro should behave similarly to `file!` and `line!`,
// i.e. point to where the macro was invoked, instead of the macro itself.
let loc2 = caller_location_from_macro!();
assert_eq!(loc2.file(), file!());
assert_eq!(loc2.line(), 17);
assert_eq!(loc2.line(), 23);
assert_eq!(loc2.column(), 16);
}

View file

@ -0,0 +1,41 @@
// run-pass
#![feature(const_fn, track_caller)]
use std::panic::Location;
const LOCATION: &Location = Location::caller();
const TRACKED: &Location = tracked();
#[track_caller]
const fn tracked() -> &'static Location <'static> {
Location::caller()
}
const NESTED: &Location = nested_location();
const fn nested_location() -> &'static Location<'static> {
Location::caller()
}
const CONTAINED: &Location = contained();
const fn contained() -> &'static Location<'static> {
tracked()
}
fn main() {
assert_eq!(LOCATION.file(), file!());
assert_eq!(LOCATION.line(), 7);
assert_eq!(LOCATION.column(), 29);
assert_eq!(TRACKED.file(), file!());
assert_eq!(TRACKED.line(), 9);
assert_eq!(TRACKED.column(), 28);
assert_eq!(NESTED.file(), file!());
assert_eq!(NESTED.line(), 17);
assert_eq!(NESTED.column(), 5);
assert_eq!(CONTAINED.file(), file!());
assert_eq!(CONTAINED.line(), 22);
assert_eq!(CONTAINED.column(), 5);
}

View file

@ -1,4 +1,4 @@
#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
#![feature(track_caller)]
#[track_caller(1)]
fn f() {}

View file

@ -4,13 +4,5 @@ error: malformed `track_caller` attribute input
LL | #[track_caller(1)]
| ^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[track_caller]`
warning: the feature `track_caller` is incomplete and may cause the compiler to crash
--> $DIR/error-odd-syntax.rs:1:12
|
LL | #![feature(track_caller)]
| ^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
error: aborting due to previous error

View file

@ -1,6 +1,7 @@
#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
#![feature(track_caller)]
#[track_caller] //~ ERROR Rust ABI is required to use `#[track_caller]`
#[track_caller]
extern "C" fn f() {}
//~^^ ERROR `#[track_caller]` requires Rust ABI
fn main() {}

View file

@ -1,12 +1,4 @@
warning: the feature `track_caller` is incomplete and may cause the compiler to crash
--> $DIR/error-with-invalid-abi.rs:1:12
|
LL | #![feature(track_caller)]
| ^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
error[E0737]: Rust ABI is required to use `#[track_caller]`
error[E0737]: `#[track_caller]` requires Rust ABI
--> $DIR/error-with-invalid-abi.rs:3:1
|
LL | #[track_caller]

View file

@ -1,4 +1,4 @@
#![feature(naked_functions, track_caller)] //~ WARN the feature `track_caller` is incomplete
#![feature(naked_functions, track_caller)]
#[track_caller]
#[naked]

View file

@ -1,11 +1,3 @@
warning: the feature `track_caller` is incomplete and may cause the compiler to crash
--> $DIR/error-with-naked.rs:1:29
|
LL | #![feature(naked_functions, track_caller)]
| ^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
error[E0736]: cannot use `#[track_caller]` with `#[naked]`
--> $DIR/error-with-naked.rs:3:1
|

View file

@ -1,4 +1,4 @@
#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
#![feature(track_caller)]
trait Trait {
#[track_caller] //~ ERROR: `#[track_caller]` may not be used on trait methods

View file

@ -1,11 +1,3 @@
warning: the feature `track_caller` is incomplete and may cause the compiler to crash
--> $DIR/error-with-trait-decl.rs:1:12
|
LL | #![feature(track_caller)]
| ^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
error[E0738]: `#[track_caller]` may not be used on trait methods
--> $DIR/error-with-trait-decl.rs:4:5
|

View file

@ -1,4 +1,4 @@
#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
#![feature(track_caller)]
trait Trait {
#[track_caller] //~ ERROR: `#[track_caller]` may not be used on trait methods

View file

@ -1,11 +1,3 @@
warning: the feature `track_caller` is incomplete and may cause the compiler to crash
--> $DIR/error-with-trait-default-impl.rs:1:12
|
LL | #![feature(track_caller)]
| ^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
error[E0738]: `#[track_caller]` may not be used on trait methods
--> $DIR/error-with-trait-default-impl.rs:4:5
|

View file

@ -1,6 +1,6 @@
// check-fail
#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
#![feature(track_caller)]
trait Trait {
fn unwrap(&self);

View file

@ -1,11 +1,3 @@
warning: the feature `track_caller` is incomplete and may cause the compiler to crash
--> $DIR/error-with-trait-fn-impl.rs:3:12
|
LL | #![feature(track_caller)]
| ^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
error[E0738]: `#[track_caller]` may not be used on trait methods
--> $DIR/error-with-trait-fn-impl.rs:10:5
|

View file

@ -0,0 +1,21 @@
// run-pass
#![feature(track_caller)]
macro_rules! caller_location_from_macro {
() => (core::panic::Location::caller());
}
fn main() {
let loc = core::panic::Location::caller();
assert_eq!(loc.file(), file!());
assert_eq!(loc.line(), 10);
assert_eq!(loc.column(), 15);
// `Location::caller()` in a macro should behave similarly to `file!` and `line!`,
// i.e. point to where the macro was invoked, instead of the macro itself.
let loc2 = caller_location_from_macro!();
assert_eq!(loc2.file(), file!());
assert_eq!(loc2.line(), 17);
assert_eq!(loc2.column(), 16);
}

View file

@ -1,4 +1,4 @@
#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
#![feature(track_caller)]
#[track_caller]
struct S;

View file

@ -1,11 +1,3 @@
warning: the feature `track_caller` is incomplete and may cause the compiler to crash
--> $DIR/only-for-fns.rs:1:12
|
LL | #![feature(track_caller)]
| ^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
error[E0739]: attribute should be applied to function
--> $DIR/only-for-fns.rs:3:1
|

View file

@ -1,5 +1,5 @@
// run-pass
#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
#![feature(track_caller)]
#[track_caller]
fn f() {}

View file

@ -1,8 +0,0 @@
warning: the feature `track_caller` is incomplete and may cause the compiler to crash
--> $DIR/pass.rs:2:12
|
LL | #![feature(track_caller)]
| ^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default

View file

@ -0,0 +1,40 @@
// run-pass
#![feature(const_fn, track_caller)]
use std::panic::Location;
#[track_caller]
fn tracked() -> &'static Location<'static> {
Location::caller()
}
fn nested_intrinsic() -> &'static Location<'static> {
Location::caller()
}
fn nested_tracked() -> &'static Location<'static> {
tracked()
}
fn main() {
let location = Location::caller();
assert_eq!(location.file(), file!());
assert_eq!(location.line(), 21);
assert_eq!(location.column(), 20);
let tracked = tracked();
assert_eq!(tracked.file(), file!());
assert_eq!(tracked.line(), 26);
assert_eq!(tracked.column(), 19);
let nested = nested_intrinsic();
assert_eq!(nested.file(), file!());
assert_eq!(nested.line(), 13);
assert_eq!(nested.column(), 5);
let contained = nested_tracked();
assert_eq!(contained.file(), file!());
assert_eq!(contained.line(), 17);
assert_eq!(contained.column(), 5);
}