diff options
Diffstat (limited to 'tests/ui/rfc-2091-track-caller')
29 files changed, 906 insertions, 0 deletions
diff --git a/tests/ui/rfc-2091-track-caller/call-chain.rs b/tests/ui/rfc-2091-track-caller/call-chain.rs new file mode 100644 index 000000000..28b3f76c9 --- /dev/null +++ b/tests/ui/rfc-2091-track-caller/call-chain.rs @@ -0,0 +1,30 @@ +// run-pass +// revisions: default mir-opt +//[default] compile-flags: -Zinline-mir=no +//[mir-opt] compile-flags: -Zmir-opt-level=4 + +use std::panic::Location; + +struct Foo; + +impl Foo { + #[inline(always)] + #[track_caller] + fn check_loc(&self, line: u32, col: u32) -> &Self { + let loc = Location::caller(); + assert_eq!(loc.file(), file!(), "file mismatch"); + assert_eq!(loc.line(), line, "line mismatch"); + assert_eq!(loc.column(), col, "column mismatch"); + self + } +} + +fn main() { + // Tests that when `Location::caller` is used in a method chain, + // it points to the start of the correct call (the first character after the dot) + // instead of to the very first expression in the chain + let foo = Foo; + foo. + check_loc(line!(), 9).check_loc(line!(), 31) + .check_loc(line!(), 10); +} diff --git a/tests/ui/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.rs b/tests/ui/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.rs new file mode 100644 index 000000000..a3bed707e --- /dev/null +++ b/tests/ui/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.rs @@ -0,0 +1,32 @@ +// Ensure that a `#[track_caller]` function, returning `caller_location()`, +// which coerced (to a function pointer) and called, inside a `const fn`, +// in turn called, results in the same output irrespective of whether +// we're in a const or runtime context. + +// run-pass +// compile-flags: -Z unleash-the-miri-inside-of-you + +#![feature(core_intrinsics, const_caller_location)] + +type L = &'static std::panic::Location<'static>; + +#[track_caller] +const fn attributed() -> L { + std::intrinsics::caller_location() +} + +const fn calling_attributed() -> L { + // We need `-Z unleash-the-miri-inside-of-you` for this as we don't have `const fn` pointers. + let ptr: fn() -> L = attributed; + ptr() +} + +fn main() { + const CONSTANT: L = calling_attributed(); + let runtime = calling_attributed(); + + assert_eq!( + (runtime.file(), runtime.line(), runtime.column()), + (CONSTANT.file(), CONSTANT.line(), CONSTANT.column()), + ); +} diff --git a/tests/ui/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.stderr b/tests/ui/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.stderr new file mode 100644 index 000000000..cf8ca5771 --- /dev/null +++ b/tests/ui/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.stderr @@ -0,0 +1,10 @@ +warning: skipping const checks + | +help: skipping check that does not even have a feature gate + --> $DIR/caller-location-fnptr-rt-ctfe-equiv.rs:21:5 + | +LL | ptr() + | ^^^^^ + +warning: 1 warning emitted + diff --git a/tests/ui/rfc-2091-track-caller/caller-location-intrinsic.rs b/tests/ui/rfc-2091-track-caller/caller-location-intrinsic.rs new file mode 100644 index 000000000..e5754d355 --- /dev/null +++ b/tests/ui/rfc-2091-track-caller/caller-location-intrinsic.rs @@ -0,0 +1,27 @@ +// run-pass +// revisions: default mir-opt +//[mir-opt] compile-flags: -Zmir-opt-level=4 + +#[inline(never)] +#[track_caller] +fn codegen_caller_loc() -> &'static core::panic::Location<'static> { + core::panic::Location::caller() +} + +macro_rules! caller_location_from_macro { + () => (codegen_caller_loc()); +} + +fn main() { + let loc = codegen_caller_loc(); + assert_eq!(loc.file(), file!()); + assert_eq!(loc.line(), 16); + 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(), 23); + assert_eq!(loc2.column(), 16); +} diff --git a/tests/ui/rfc-2091-track-caller/const-caller-location.rs b/tests/ui/rfc-2091-track-caller/const-caller-location.rs new file mode 100644 index 000000000..6e15cf3fe --- /dev/null +++ b/tests/ui/rfc-2091-track-caller/const-caller-location.rs @@ -0,0 +1,43 @@ +// run-pass +// revisions: default mir-opt +//[mir-opt] compile-flags: -Zmir-opt-level=4 + +#![feature(const_caller_location)] + +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(), 9); + assert_eq!(LOCATION.column(), 29); + + assert_eq!(TRACKED.file(), file!()); + assert_eq!(TRACKED.line(), 11); + assert_eq!(TRACKED.column(), 28); + + assert_eq!(NESTED.file(), file!()); + assert_eq!(NESTED.line(), 19); + assert_eq!(NESTED.column(), 5); + + assert_eq!(CONTAINED.file(), file!()); + assert_eq!(CONTAINED.line(), 24); + assert_eq!(CONTAINED.column(), 5); +} diff --git a/tests/ui/rfc-2091-track-caller/diverging-caller-location.rs b/tests/ui/rfc-2091-track-caller/diverging-caller-location.rs new file mode 100644 index 000000000..668111955 --- /dev/null +++ b/tests/ui/rfc-2091-track-caller/diverging-caller-location.rs @@ -0,0 +1,17 @@ +// run-fail + +//! This test ensures that `#[track_caller]` can be applied directly to diverging functions, as +//! the tracking issue says: https://github.com/rust-lang/rust/issues/47809#issue-292138490. +//! Because the annotated function must diverge and a panic keeps that faster than an infinite loop, +//! we don't inspect the location returned -- it would be difficult to distinguish between the +//! explicit panic and a failed assertion. That it compiles and runs is enough for this one. + +#[track_caller] +fn doesnt_return() -> ! { + let _location = core::panic::Location::caller(); + panic!("huzzah"); +} + +fn main() { + doesnt_return(); +} diff --git a/tests/ui/rfc-2091-track-caller/error-odd-syntax.rs b/tests/ui/rfc-2091-track-caller/error-odd-syntax.rs new file mode 100644 index 000000000..6f4290e2a --- /dev/null +++ b/tests/ui/rfc-2091-track-caller/error-odd-syntax.rs @@ -0,0 +1,5 @@ +#[track_caller(1)] +fn f() {} +//~^^ ERROR malformed `track_caller` attribute input + +fn main() {} diff --git a/tests/ui/rfc-2091-track-caller/error-odd-syntax.stderr b/tests/ui/rfc-2091-track-caller/error-odd-syntax.stderr new file mode 100644 index 000000000..e7ddf8df4 --- /dev/null +++ b/tests/ui/rfc-2091-track-caller/error-odd-syntax.stderr @@ -0,0 +1,8 @@ +error: malformed `track_caller` attribute input + --> $DIR/error-odd-syntax.rs:1:1 + | +LL | #[track_caller(1)] + | ^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[track_caller]` + +error: aborting due to previous error + diff --git a/tests/ui/rfc-2091-track-caller/error-with-invalid-abi.rs b/tests/ui/rfc-2091-track-caller/error-with-invalid-abi.rs new file mode 100644 index 000000000..074e1ceb7 --- /dev/null +++ b/tests/ui/rfc-2091-track-caller/error-with-invalid-abi.rs @@ -0,0 +1,11 @@ +#[track_caller] +extern "C" fn f() {} +//~^^ ERROR `#[track_caller]` requires Rust ABI + +extern "C" { + #[track_caller] + fn g(); + //~^^ ERROR `#[track_caller]` requires Rust ABI +} + +fn main() {} diff --git a/tests/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr b/tests/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr new file mode 100644 index 000000000..bcc0c8170 --- /dev/null +++ b/tests/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr @@ -0,0 +1,15 @@ +error[E0737]: `#[track_caller]` requires Rust ABI + --> $DIR/error-with-invalid-abi.rs:1:1 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ + +error[E0737]: `#[track_caller]` requires Rust ABI + --> $DIR/error-with-invalid-abi.rs:6:5 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0737`. diff --git a/tests/ui/rfc-2091-track-caller/error-with-main.rs b/tests/ui/rfc-2091-track-caller/error-with-main.rs new file mode 100644 index 000000000..b2ea31bb5 --- /dev/null +++ b/tests/ui/rfc-2091-track-caller/error-with-main.rs @@ -0,0 +1,4 @@ +#[track_caller] //~ ERROR `main` function is not allowed to be +fn main() { + panic!("{}: oh no", std::panic::Location::caller()); +} diff --git a/tests/ui/rfc-2091-track-caller/error-with-main.stderr b/tests/ui/rfc-2091-track-caller/error-with-main.stderr new file mode 100644 index 000000000..7e2ec3524 --- /dev/null +++ b/tests/ui/rfc-2091-track-caller/error-with-main.stderr @@ -0,0 +1,10 @@ +error: `main` function is not allowed to be `#[track_caller]` + --> $DIR/error-with-main.rs:1:1 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ +LL | fn main() { + | --------- `main` function is not allowed to be `#[track_caller]` + +error: aborting due to previous error + diff --git a/tests/ui/rfc-2091-track-caller/error-with-naked.rs b/tests/ui/rfc-2091-track-caller/error-with-naked.rs new file mode 100644 index 000000000..43e33cbb1 --- /dev/null +++ b/tests/ui/rfc-2091-track-caller/error-with-naked.rs @@ -0,0 +1,24 @@ +// needs-asm-support +#![feature(naked_functions)] + +use std::arch::asm; + +#[track_caller] //~ ERROR cannot use `#[track_caller]` with `#[naked]` +//~^ ERROR `#[track_caller]` requires Rust ABI +#[naked] +extern "C" fn f() { + asm!("", options(noreturn)); +} + +struct S; + +impl S { + #[track_caller] //~ ERROR cannot use `#[track_caller]` with `#[naked]` + //~^ ERROR `#[track_caller]` requires Rust ABI + #[naked] + extern "C" fn g() { + asm!("", options(noreturn)); + } +} + +fn main() {} diff --git a/tests/ui/rfc-2091-track-caller/error-with-naked.stderr b/tests/ui/rfc-2091-track-caller/error-with-naked.stderr new file mode 100644 index 000000000..3f7d0df42 --- /dev/null +++ b/tests/ui/rfc-2091-track-caller/error-with-naked.stderr @@ -0,0 +1,28 @@ +error[E0736]: cannot use `#[track_caller]` with `#[naked]` + --> $DIR/error-with-naked.rs:6:1 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ + +error[E0736]: cannot use `#[track_caller]` with `#[naked]` + --> $DIR/error-with-naked.rs:16:5 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ + +error[E0737]: `#[track_caller]` requires Rust ABI + --> $DIR/error-with-naked.rs:6:1 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ + +error[E0737]: `#[track_caller]` requires Rust ABI + --> $DIR/error-with-naked.rs:16:5 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0736, E0737. +For more information about an error, try `rustc --explain E0736`. diff --git a/tests/ui/rfc-2091-track-caller/error-with-start.rs b/tests/ui/rfc-2091-track-caller/error-with-start.rs new file mode 100644 index 000000000..0cab47170 --- /dev/null +++ b/tests/ui/rfc-2091-track-caller/error-with-start.rs @@ -0,0 +1,7 @@ +#![feature(start)] + +#[start] +#[track_caller] //~ ERROR `start` is not allowed to be `#[track_caller]` +fn start(_argc: isize, _argv: *const *const u8) -> isize { + panic!("{}: oh no", std::panic::Location::caller()); +} diff --git a/tests/ui/rfc-2091-track-caller/error-with-start.stderr b/tests/ui/rfc-2091-track-caller/error-with-start.stderr new file mode 100644 index 000000000..454c98ff9 --- /dev/null +++ b/tests/ui/rfc-2091-track-caller/error-with-start.stderr @@ -0,0 +1,10 @@ +error: `start` is not allowed to be `#[track_caller]` + --> $DIR/error-with-start.rs:4:1 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ +LL | fn start(_argc: isize, _argv: *const *const u8) -> isize { + | -------------------------------------------------------- `start` is not allowed to be `#[track_caller]` + +error: aborting due to previous error + diff --git a/tests/ui/rfc-2091-track-caller/intrinsic-wrapper.rs b/tests/ui/rfc-2091-track-caller/intrinsic-wrapper.rs new file mode 100644 index 000000000..87e52881c --- /dev/null +++ b/tests/ui/rfc-2091-track-caller/intrinsic-wrapper.rs @@ -0,0 +1,21 @@ +// run-pass +// revisions: default mir-opt +//[mir-opt] compile-flags: -Zmir-opt-level=4 + +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); +} diff --git a/tests/ui/rfc-2091-track-caller/macro-declaration.rs b/tests/ui/rfc-2091-track-caller/macro-declaration.rs new file mode 100644 index 000000000..6ca09fac8 --- /dev/null +++ b/tests/ui/rfc-2091-track-caller/macro-declaration.rs @@ -0,0 +1,10 @@ +// check-pass + +// See https://github.com/rust-lang/rust/issues/95151 +#[track_caller] +macro_rules! _foo { + () => {}; +} + +fn main() { +} diff --git a/tests/ui/rfc-2091-track-caller/only-for-fns.rs b/tests/ui/rfc-2091-track-caller/only-for-fns.rs new file mode 100644 index 000000000..2d2b01b6f --- /dev/null +++ b/tests/ui/rfc-2091-track-caller/only-for-fns.rs @@ -0,0 +1,5 @@ +#[track_caller] +struct S; +//~^^ ERROR attribute should be applied to a function definition + +fn main() {} diff --git a/tests/ui/rfc-2091-track-caller/only-for-fns.stderr b/tests/ui/rfc-2091-track-caller/only-for-fns.stderr new file mode 100644 index 000000000..b36597bde --- /dev/null +++ b/tests/ui/rfc-2091-track-caller/only-for-fns.stderr @@ -0,0 +1,11 @@ +error[E0739]: attribute should be applied to a function definition + --> $DIR/only-for-fns.rs:1:1 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ +LL | struct S; + | --------- not a function definition + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0739`. diff --git a/tests/ui/rfc-2091-track-caller/pass.rs b/tests/ui/rfc-2091-track-caller/pass.rs new file mode 100644 index 000000000..1b13ea3e9 --- /dev/null +++ b/tests/ui/rfc-2091-track-caller/pass.rs @@ -0,0 +1,10 @@ +// run-pass +// revisions: default mir-opt +//[mir-opt] compile-flags: -Zmir-opt-level=4 + +#[track_caller] +fn f() {} + +fn main() { + f(); +} diff --git a/tests/ui/rfc-2091-track-caller/std-panic-locations.rs b/tests/ui/rfc-2091-track-caller/std-panic-locations.rs new file mode 100644 index 000000000..f11456250 --- /dev/null +++ b/tests/ui/rfc-2091-track-caller/std-panic-locations.rs @@ -0,0 +1,64 @@ +// run-pass +// needs-unwind +// revisions: default mir-opt +//[mir-opt] compile-flags: -Zmir-opt-level=4 + +#![allow(unconditional_panic)] + +//! Test that panic locations for `#[track_caller]` functions in std have the correct +//! location reported. + +use std::cell::RefCell; +use std::collections::{BTreeMap, HashMap, VecDeque}; +use std::ops::{Index, IndexMut}; +use std::panic::{AssertUnwindSafe, UnwindSafe}; + +fn main() { + // inspect the `PanicInfo` we receive to ensure the right file is the source + std::panic::set_hook(Box::new(|info| { + let actual = info.location().unwrap(); + if actual.file() != file!() { + eprintln!("expected a location in the test file, found {:?}", actual); + panic!(); + } + })); + + fn assert_panicked(f: impl FnOnce() + UnwindSafe) { + std::panic::catch_unwind(f).unwrap_err(); + } + + let nope: Option<()> = None; + assert_panicked(|| nope.unwrap()); + assert_panicked(|| nope.expect("")); + + let oops: Result<(), ()> = Err(()); + assert_panicked(|| oops.unwrap()); + assert_panicked(|| oops.expect("")); + + let fine: Result<(), ()> = Ok(()); + assert_panicked(|| fine.unwrap_err()); + assert_panicked(|| fine.expect_err("")); + + let mut small = [0]; // the implementation backing str, vec, etc + assert_panicked(move || { small.index(1); }); + assert_panicked(move || { small[1]; }); + assert_panicked(move || { small.index_mut(1); }); + assert_panicked(move || { small[1] += 1; }); + + let sorted: BTreeMap<bool, bool> = Default::default(); + assert_panicked(|| { sorted.index(&false); }); + assert_panicked(|| { sorted[&false]; }); + + let unsorted: HashMap<bool, bool> = Default::default(); + assert_panicked(|| { unsorted.index(&false); }); + assert_panicked(|| { unsorted[&false]; }); + + let weirdo: VecDeque<()> = Default::default(); + assert_panicked(|| { weirdo.index(1); }); + assert_panicked(|| { weirdo[1]; }); + + let refcell: RefCell<()> = Default::default(); + let _conflicting = refcell.borrow_mut(); + assert_panicked(AssertUnwindSafe(|| { refcell.borrow(); })); + assert_panicked(AssertUnwindSafe(|| { refcell.borrow_mut(); })); +} diff --git a/tests/ui/rfc-2091-track-caller/track-caller-attribute.rs b/tests/ui/rfc-2091-track-caller/track-caller-attribute.rs new file mode 100644 index 000000000..9d28eb9de --- /dev/null +++ b/tests/ui/rfc-2091-track-caller/track-caller-attribute.rs @@ -0,0 +1,40 @@ +// run-pass +// revisions: default mir-opt +//[mir-opt] compile-flags: -Zmir-opt-level=4 + +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); +} diff --git a/tests/ui/rfc-2091-track-caller/track-caller-ffi.rs b/tests/ui/rfc-2091-track-caller/track-caller-ffi.rs new file mode 100644 index 000000000..5115f687c --- /dev/null +++ b/tests/ui/rfc-2091-track-caller/track-caller-ffi.rs @@ -0,0 +1,48 @@ +// run-pass + +use std::panic::Location; + +extern "Rust" { + #[track_caller] + fn rust_track_caller_ffi_test_tracked() -> &'static Location<'static>; + fn rust_track_caller_ffi_test_untracked() -> &'static Location<'static>; +} + +fn rust_track_caller_ffi_test_nested_tracked() -> &'static Location<'static> { + unsafe { rust_track_caller_ffi_test_tracked() } +} + +mod provides { + use std::panic::Location; + #[track_caller] // UB if we did not have this! + #[no_mangle] + fn rust_track_caller_ffi_test_tracked() -> &'static Location<'static> { + Location::caller() + } + #[no_mangle] + fn rust_track_caller_ffi_test_untracked() -> &'static Location<'static> { + Location::caller() + } +} + +fn main() { + let location = Location::caller(); + assert_eq!(location.file(), file!()); + assert_eq!(location.line(), 29); + assert_eq!(location.column(), 20); + + let tracked = unsafe { rust_track_caller_ffi_test_tracked() }; + assert_eq!(tracked.file(), file!()); + assert_eq!(tracked.line(), 34); + assert_eq!(tracked.column(), 28); + + let untracked = unsafe { rust_track_caller_ffi_test_untracked() }; + assert_eq!(untracked.file(), file!()); + assert_eq!(untracked.line(), 24); + assert_eq!(untracked.column(), 9); + + let contained = rust_track_caller_ffi_test_nested_tracked(); + assert_eq!(contained.file(), file!()); + assert_eq!(contained.line(), 12); + assert_eq!(contained.column(), 14); +} diff --git a/tests/ui/rfc-2091-track-caller/tracked-closure.rs b/tests/ui/rfc-2091-track-caller/tracked-closure.rs new file mode 100644 index 000000000..670c423a7 --- /dev/null +++ b/tests/ui/rfc-2091-track-caller/tracked-closure.rs @@ -0,0 +1,154 @@ +// run-pass + +#![feature(stmt_expr_attributes)] +#![feature(closure_track_caller)] +#![feature(generator_trait)] +#![feature(generators)] + +use std::ops::{Generator, GeneratorState}; +use std::pin::Pin; +use std::panic::Location; + +type Loc = &'static Location<'static>; + +#[track_caller] +fn mono_invoke_fn<F: Fn(&'static str, bool) -> (&'static str, bool, Loc)>( + val: &F +) -> (&'static str, bool, Loc) { + val("from_mono", false) +} + +#[track_caller] +fn mono_invoke_fn_once<F: FnOnce(&'static str, bool) -> (&'static str, bool, Loc)>( + val: F +) -> (&'static str, bool, Loc) { + val("from_mono", false) +} + +#[track_caller] +fn dyn_invoke_fn_mut( + val: &mut dyn FnMut(&'static str, bool) -> (&'static str, bool, Loc) +) -> (&'static str, bool, Loc) { + val("from_dyn", false) +} + +#[track_caller] +fn dyn_invoke_fn_once( + val: Box<dyn FnOnce(&'static str, bool) -> (&'static str, bool, Loc)> +) -> (&'static str, bool, Loc) { + val("from_dyn", false) +} + + +fn test_closure() { + let mut track_closure = #[track_caller] |first: &'static str, second: bool| { + (first, second, Location::caller()) + }; + let (first_arg, first_bool, first_loc) = track_closure("first_arg", true); + let first_line = line!() - 1; + assert_eq!(first_arg, "first_arg"); + assert_eq!(first_bool, true); + assert_eq!(first_loc.file(), file!()); + assert_eq!(first_loc.line(), first_line); + assert_eq!(first_loc.column(), 46); + + let (dyn_arg, dyn_bool, dyn_loc) = dyn_invoke_fn_mut(&mut track_closure); + assert_eq!(dyn_arg, "from_dyn"); + assert_eq!(dyn_bool, false); + // `FnMut::call_mut` does not have `#[track_caller]`, + // so this will not match + assert_ne!(dyn_loc.file(), file!()); + + let (dyn_arg, dyn_bool, dyn_loc) = dyn_invoke_fn_once(Box::new(track_closure)); + assert_eq!(dyn_arg, "from_dyn"); + assert_eq!(dyn_bool, false); + // `FnOnce::call_once` does not have `#[track_caller]` + // so this will not match + assert_ne!(dyn_loc.file(), file!()); + + + let (mono_arg, mono_bool, mono_loc) = mono_invoke_fn(&track_closure); + let mono_line = line!() - 1; + assert_eq!(mono_arg, "from_mono"); + assert_eq!(mono_bool, false); + assert_eq!(mono_loc.file(), file!()); + assert_eq!(mono_loc.line(), mono_line); + assert_eq!(mono_loc.column(), 43); + + let (mono_arg, mono_bool, mono_loc) = mono_invoke_fn_once(track_closure); + let mono_line = line!() - 1; + assert_eq!(mono_arg, "from_mono"); + assert_eq!(mono_bool, false); + assert_eq!(mono_loc.file(), file!()); + assert_eq!(mono_loc.line(), mono_line); + assert_eq!(mono_loc.column(), 43); + + let non_tracked_caller = || Location::caller(); + let non_tracked_line = line!() - 1; // This is the line of the closure, not its caller + let non_tracked_loc = non_tracked_caller(); + assert_eq!(non_tracked_loc.file(), file!()); + assert_eq!(non_tracked_loc.line(), non_tracked_line); + assert_eq!(non_tracked_loc.column(), 33); +} + + +#[track_caller] +fn mono_generator<F: Generator<String, Yield = (&'static str, String, Loc), Return = ()>>( + val: Pin<&mut F> +) -> (&'static str, String, Loc) { + match val.resume("Mono".to_string()) { + GeneratorState::Yielded(val) => val, + _ => unreachable!() + } +} + +#[track_caller] +fn dyn_generator( + val: Pin<&mut dyn Generator<String, Yield = (&'static str, String, Loc), Return = ()>> +) -> (&'static str, String, Loc) { + match val.resume("Dyn".to_string()) { + GeneratorState::Yielded(val) => val, + _ => unreachable!() + } +} + +fn test_generator() { + let generator = #[track_caller] |arg: String| { + yield ("first", arg.clone(), Location::caller()); + yield ("second", arg.clone(), Location::caller()); + }; + + let mut pinned = Box::pin(generator); + let (dyn_ret, dyn_arg, dyn_loc) = dyn_generator(pinned.as_mut()); + assert_eq!(dyn_ret, "first"); + assert_eq!(dyn_arg, "Dyn".to_string()); + // The `Generator` trait does not have `#[track_caller]` on `resume`, so + // this will not match. + assert_ne!(dyn_loc.file(), file!()); + + + let (mono_ret, mono_arg, mono_loc) = mono_generator(pinned.as_mut()); + let mono_line = line!() - 1; + assert_eq!(mono_ret, "second"); + // The generator ignores the argument to the second `resume` call + assert_eq!(mono_arg, "Dyn".to_string()); + assert_eq!(mono_loc.file(), file!()); + assert_eq!(mono_loc.line(), mono_line); + assert_eq!(mono_loc.column(), 42); + + let non_tracked_generator = || { yield Location::caller(); }; + let non_tracked_line = line!() - 1; // This is the line of the generator, not its caller + let non_tracked_loc = match Box::pin(non_tracked_generator).as_mut().resume(()) { + GeneratorState::Yielded(val) => val, + _ => unreachable!() + }; + assert_eq!(non_tracked_loc.file(), file!()); + assert_eq!(non_tracked_loc.line(), non_tracked_line); + assert_eq!(non_tracked_loc.column(), 44); + +} + +fn main() { + test_closure(); + test_generator(); +} diff --git a/tests/ui/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs b/tests/ui/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs new file mode 100644 index 000000000..658812578 --- /dev/null +++ b/tests/ui/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs @@ -0,0 +1,62 @@ +// run-pass +// revisions: default mir-opt +//[mir-opt] compile-flags: -Zmir-opt-level=4 + +fn pass_to_ptr_call<T>(f: fn(T), x: T) { + f(x); +} + +#[track_caller] +fn tracked_unit(_: ()) { + let expected_line = line!() - 1; + let location = std::panic::Location::caller(); + assert_eq!(location.file(), file!()); + assert_eq!(location.line(), expected_line, "call shims report location as fn definition"); +} + +trait Trait { + fn trait_tracked_unit(_: ()); +} + +impl Trait for () { + #[track_caller] + fn trait_tracked_unit(_: ()) { + let expected_line = line!() - 1; + let location = std::panic::Location::caller(); + assert_eq!(location.file(), file!()); + assert_eq!(location.line(), expected_line, "call shims report location as fn definition"); + } +} + +trait TrackedTrait { + #[track_caller] + fn trait_tracked_unit_default(_: ()) { + let expected_line = line!() - 1; + let location = std::panic::Location::caller(); + assert_eq!(location.file(), file!()); + assert_eq!(location.line(), expected_line, "call shims report location as fn definition"); + } +} + +impl TrackedTrait for () {} + +trait BlanketTrackedTrait { + #[track_caller] + fn tracked_blanket(_: ()); +} + +impl BlanketTrackedTrait for () { + fn tracked_blanket(_: ()) { + let expected_line = line!() - 1; + let location = std::panic::Location::caller(); + assert_eq!(location.file(), file!()); + assert_eq!(location.line(), expected_line, "call shims report location as fn definition"); + } +} + +fn main() { + pass_to_ptr_call(tracked_unit, ()); + pass_to_ptr_call(<() as Trait>::trait_tracked_unit, ()); + pass_to_ptr_call(<() as TrackedTrait>::trait_tracked_unit_default, ()); + pass_to_ptr_call(<() as BlanketTrackedTrait>::tracked_blanket, ()); +} diff --git a/tests/ui/rfc-2091-track-caller/tracked-fn-ptr.rs b/tests/ui/rfc-2091-track-caller/tracked-fn-ptr.rs new file mode 100644 index 000000000..8bb4dd288 --- /dev/null +++ b/tests/ui/rfc-2091-track-caller/tracked-fn-ptr.rs @@ -0,0 +1,62 @@ +// run-pass +// revisions: default mir-opt +//[mir-opt] compile-flags: -Zmir-opt-level=4 + +fn ptr_call(f: fn()) { + f(); +} + +#[track_caller] +fn tracked() { + let expected_line = line!() - 1; + let location = std::panic::Location::caller(); + assert_eq!(location.file(), file!()); + assert_eq!(location.line(), expected_line, "call shims report location as fn definition"); +} + +trait Trait { + fn trait_tracked(); +} + +impl Trait for () { + #[track_caller] + fn trait_tracked() { + let expected_line = line!() - 1; + let location = std::panic::Location::caller(); + assert_eq!(location.file(), file!()); + assert_eq!(location.line(), expected_line, "call shims report location as fn definition"); + } +} + +trait TrackedTrait { + #[track_caller] + fn trait_tracked_default() { + let expected_line = line!() - 1; + let location = std::panic::Location::caller(); + assert_eq!(location.file(), file!()); + assert_eq!(location.line(), expected_line, "call shims report location as fn definition"); + } +} + +impl TrackedTrait for () {} + +trait TraitBlanketTracked { + #[track_caller] + fn tracked_blanket(); +} + +impl TraitBlanketTracked for () { + fn tracked_blanket() { + let expected_line = line!() - 1; + let location = std::panic::Location::caller(); + assert_eq!(location.file(), file!()); + assert_eq!(location.line(), expected_line, "call shims report location as fn definition"); + } +} + +fn main() { + ptr_call(tracked); + ptr_call(<() as Trait>::trait_tracked); + ptr_call(<() as TrackedTrait>::trait_tracked_default); + ptr_call(<() as TraitBlanketTracked>::tracked_blanket); +} diff --git a/tests/ui/rfc-2091-track-caller/tracked-trait-impls.rs b/tests/ui/rfc-2091-track-caller/tracked-trait-impls.rs new file mode 100644 index 000000000..4db4c29e5 --- /dev/null +++ b/tests/ui/rfc-2091-track-caller/tracked-trait-impls.rs @@ -0,0 +1,77 @@ +// run-pass + +macro_rules! assert_expansion_site_is_tracked { + () => {{ + let location = std::panic::Location::caller(); + assert_eq!(location.file(), file!()); + assert_ne!(location.line(), line!(), "line should be outside this fn"); + }} +} + +trait Tracked { + fn local_tracked(&self); + + #[track_caller] + fn blanket_tracked(&self); + + #[track_caller] + fn default_tracked(&self) { + assert_expansion_site_is_tracked!(); + } +} + +impl Tracked for () { + #[track_caller] + fn local_tracked(&self) { + assert_expansion_site_is_tracked!(); + } + + fn blanket_tracked(&self) { + assert_expansion_site_is_tracked!(); + } +} + +impl Tracked for bool { + #[track_caller] + fn local_tracked(&self) { + assert_expansion_site_is_tracked!(); + } + + fn blanket_tracked(&self) { + assert_expansion_site_is_tracked!(); + } + + fn default_tracked(&self) { + assert_expansion_site_is_tracked!(); + } +} + +impl Tracked for u8 { + #[track_caller] + fn local_tracked(&self) { + assert_expansion_site_is_tracked!(); + } + + fn blanket_tracked(&self) { + assert_expansion_site_is_tracked!(); + } + + #[track_caller] + fn default_tracked(&self) { + assert_expansion_site_is_tracked!(); + } +} + +fn main() { + ().local_tracked(); + ().default_tracked(); + ().blanket_tracked(); + + true.local_tracked(); + true.default_tracked(); + true.blanket_tracked(); + + 0u8.local_tracked(); + 0u8.default_tracked(); + 0u8.blanket_tracked(); +} diff --git a/tests/ui/rfc-2091-track-caller/tracked-trait-obj.rs b/tests/ui/rfc-2091-track-caller/tracked-trait-obj.rs new file mode 100644 index 000000000..06883a857 --- /dev/null +++ b/tests/ui/rfc-2091-track-caller/tracked-trait-obj.rs @@ -0,0 +1,61 @@ +// run-pass + +trait Tracked { + #[track_caller] + fn track_caller_trait_method(&self, line: u32, col: u32) { + let location = std::panic::Location::caller(); + assert_eq!(location.file(), file!()); + // The trait method definition is annotated with `#[track_caller]`, + // so caller location information will work through a method + // call on a trait object + assert_eq!(location.line(), line, "Bad line"); + assert_eq!(location.column(), col, "Bad col"); + } + + fn track_caller_not_on_trait_method(&self); + + #[track_caller] + fn track_caller_through_self(self: Box<Self>, line: u32, col: u32); +} + +impl Tracked for () { + // We have `#[track_caller]` on the implementation of the method, + // but not on the definition of the method in the trait. Therefore, + // caller location information will *not* work through a method call + // on a trait object. Instead, we will get the location of this method + #[track_caller] + fn track_caller_not_on_trait_method(&self) { + let location = std::panic::Location::caller(); + assert_eq!(location.file(), file!()); + assert_eq!(location.line(), line!() - 3); + assert_eq!(location.column(), 5); + } + + // We don't have a `#[track_caller]` attribute, but + // `#[track_caller]` is present on the trait definition, + // so we'll still get location information + fn track_caller_through_self(self: Box<Self>, line: u32, col: u32) { + let location = std::panic::Location::caller(); + assert_eq!(location.file(), file!()); + // The trait method definition is annotated with `#[track_caller]`, + // so caller location information will work through a method + // call on a trait object + assert_eq!(location.line(), line, "Bad line"); + assert_eq!(location.column(), col, "Bad col"); + } +} + +fn main() { + let tracked: &dyn Tracked = &(); + // The column is the start of 'track_caller_trait_method' + tracked.track_caller_trait_method(line!(), 13); + + const TRACKED: &dyn Tracked = &(); + // The column is the start of 'track_caller_trait_method' + TRACKED.track_caller_trait_method(line!(), 13); + TRACKED.track_caller_not_on_trait_method(); + + // The column is the start of `track_caller_through_self` + let boxed: Box<dyn Tracked> = Box::new(()); + boxed.track_caller_through_self(line!(), 11); +} |