summaryrefslogtreecommitdiffstats
path: root/tests/ui/rfc-2091-track-caller
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ui/rfc-2091-track-caller')
-rw-r--r--tests/ui/rfc-2091-track-caller/call-chain.rs30
-rw-r--r--tests/ui/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.rs32
-rw-r--r--tests/ui/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.stderr10
-rw-r--r--tests/ui/rfc-2091-track-caller/caller-location-intrinsic.rs27
-rw-r--r--tests/ui/rfc-2091-track-caller/const-caller-location.rs43
-rw-r--r--tests/ui/rfc-2091-track-caller/diverging-caller-location.rs17
-rw-r--r--tests/ui/rfc-2091-track-caller/error-odd-syntax.rs5
-rw-r--r--tests/ui/rfc-2091-track-caller/error-odd-syntax.stderr8
-rw-r--r--tests/ui/rfc-2091-track-caller/error-with-invalid-abi.rs11
-rw-r--r--tests/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr15
-rw-r--r--tests/ui/rfc-2091-track-caller/error-with-main.rs4
-rw-r--r--tests/ui/rfc-2091-track-caller/error-with-main.stderr10
-rw-r--r--tests/ui/rfc-2091-track-caller/error-with-naked.rs24
-rw-r--r--tests/ui/rfc-2091-track-caller/error-with-naked.stderr28
-rw-r--r--tests/ui/rfc-2091-track-caller/error-with-start.rs7
-rw-r--r--tests/ui/rfc-2091-track-caller/error-with-start.stderr10
-rw-r--r--tests/ui/rfc-2091-track-caller/intrinsic-wrapper.rs21
-rw-r--r--tests/ui/rfc-2091-track-caller/macro-declaration.rs10
-rw-r--r--tests/ui/rfc-2091-track-caller/only-for-fns.rs5
-rw-r--r--tests/ui/rfc-2091-track-caller/only-for-fns.stderr11
-rw-r--r--tests/ui/rfc-2091-track-caller/pass.rs10
-rw-r--r--tests/ui/rfc-2091-track-caller/std-panic-locations.rs64
-rw-r--r--tests/ui/rfc-2091-track-caller/track-caller-attribute.rs40
-rw-r--r--tests/ui/rfc-2091-track-caller/track-caller-ffi.rs48
-rw-r--r--tests/ui/rfc-2091-track-caller/tracked-closure.rs154
-rw-r--r--tests/ui/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs62
-rw-r--r--tests/ui/rfc-2091-track-caller/tracked-fn-ptr.rs62
-rw-r--r--tests/ui/rfc-2091-track-caller/tracked-trait-impls.rs77
-rw-r--r--tests/ui/rfc-2091-track-caller/tracked-trait-obj.rs61
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);
+}