Skip to content

Commit 8172d6b

Browse files
committed
add tests for track_caller in closures and generators
1 parent a76ad30 commit 8172d6b

File tree

1 file changed

+148
-5
lines changed

1 file changed

+148
-5
lines changed

tests/pass/track-caller-attribute.rs

Lines changed: 148 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,25 @@
11
#![feature(core_intrinsics)]
2+
#![feature(stmt_expr_attributes)]
3+
#![feature(closure_track_caller)]
4+
#![feature(generator_trait)]
5+
#![feature(generators)]
26

7+
use std::ops::{Generator, GeneratorState};
38
use std::panic::Location;
9+
use std::pin::Pin;
10+
11+
type Loc = &'static Location<'static>;
412

513
#[track_caller]
6-
fn tracked() -> &'static Location<'static> {
14+
fn tracked() -> Loc {
715
Location::caller() // most importantly, we never get line 7
816
}
917

10-
fn nested_intrinsic() -> &'static Location<'static> {
18+
fn nested_intrinsic() -> Loc {
1119
Location::caller()
1220
}
1321

14-
fn nested_tracked() -> &'static Location<'static> {
22+
fn nested_tracked() -> Loc {
1523
tracked()
1624
}
1725

@@ -36,12 +44,12 @@ fn test_basic() {
3644

3745
let nested = nested_intrinsic();
3846
assert_eq!(nested.file(), file!());
39-
assert_eq!(nested.line(), 11);
47+
assert_eq!(nested.line(), 19);
4048
assert_eq!(nested.column(), 5);
4149

4250
let contained = nested_tracked();
4351
assert_eq!(contained.file(), file!());
44-
assert_eq!(contained.line(), 15);
52+
assert_eq!(contained.line(), 23);
4553
assert_eq!(contained.column(), 5);
4654

4755
// `Location::caller()` in a macro should behave similarly to `file!` and `line!`,
@@ -125,9 +133,144 @@ fn test_trait_obj2() {
125133
assert_eq!(loc.line(), expected_line);
126134
}
127135

136+
fn test_closure() {
137+
#[track_caller]
138+
fn mono_invoke_fn<F: Fn(&'static str, bool) -> (&'static str, bool, Loc)>(
139+
val: &F,
140+
) -> (&'static str, bool, Loc) {
141+
val("from_mono", false)
142+
}
143+
144+
#[track_caller]
145+
fn mono_invoke_fn_once<F: FnOnce(&'static str, bool) -> (&'static str, bool, Loc)>(
146+
val: F,
147+
) -> (&'static str, bool, Loc) {
148+
val("from_mono", false)
149+
}
150+
151+
#[track_caller]
152+
fn dyn_invoke_fn_mut(
153+
val: &mut dyn FnMut(&'static str, bool) -> (&'static str, bool, Loc),
154+
) -> (&'static str, bool, Loc) {
155+
val("from_dyn", false)
156+
}
157+
158+
#[track_caller]
159+
fn dyn_invoke_fn_once(
160+
val: Box<dyn FnOnce(&'static str, bool) -> (&'static str, bool, Loc)>,
161+
) -> (&'static str, bool, Loc) {
162+
val("from_dyn", false)
163+
}
164+
165+
let mut track_closure = #[track_caller]
166+
|first: &'static str, second: bool| (first, second, Location::caller());
167+
let (first_arg, first_bool, first_loc) = track_closure("first_arg", true);
168+
let first_line = line!() - 1;
169+
assert_eq!(first_arg, "first_arg");
170+
assert_eq!(first_bool, true);
171+
assert_eq!(first_loc.file(), file!());
172+
assert_eq!(first_loc.line(), first_line);
173+
assert_eq!(first_loc.column(), 46);
174+
175+
let (dyn_arg, dyn_bool, dyn_loc) = dyn_invoke_fn_mut(&mut track_closure);
176+
assert_eq!(dyn_arg, "from_dyn");
177+
assert_eq!(dyn_bool, false);
178+
// `FnMut::call_mut` does not have `#[track_caller]`,
179+
// so this will not match
180+
assert_ne!(dyn_loc.file(), file!());
181+
182+
let (dyn_arg, dyn_bool, dyn_loc) = dyn_invoke_fn_once(Box::new(track_closure));
183+
assert_eq!(dyn_arg, "from_dyn");
184+
assert_eq!(dyn_bool, false);
185+
// `FnOnce::call_once` does not have `#[track_caller]`
186+
// so this will not match
187+
assert_ne!(dyn_loc.file(), file!());
188+
189+
let (mono_arg, mono_bool, mono_loc) = mono_invoke_fn(&track_closure);
190+
let mono_line = line!() - 1;
191+
assert_eq!(mono_arg, "from_mono");
192+
assert_eq!(mono_bool, false);
193+
assert_eq!(mono_loc.file(), file!());
194+
assert_eq!(mono_loc.line(), mono_line);
195+
assert_eq!(mono_loc.column(), 43);
196+
197+
let (mono_arg, mono_bool, mono_loc) = mono_invoke_fn_once(track_closure);
198+
let mono_line = line!() - 1;
199+
assert_eq!(mono_arg, "from_mono");
200+
assert_eq!(mono_bool, false);
201+
assert_eq!(mono_loc.file(), file!());
202+
assert_eq!(mono_loc.line(), mono_line);
203+
assert_eq!(mono_loc.column(), 43);
204+
205+
let non_tracked_caller = || Location::caller();
206+
let non_tracked_line = line!() - 1; // This is the line of the closure, not its caller
207+
let non_tracked_loc = non_tracked_caller();
208+
assert_eq!(non_tracked_loc.file(), file!());
209+
assert_eq!(non_tracked_loc.line(), non_tracked_line);
210+
assert_eq!(non_tracked_loc.column(), 33);
211+
}
212+
213+
fn test_generator() {
214+
#[track_caller]
215+
fn mono_generator<F: Generator<String, Yield = (&'static str, String, Loc), Return = ()>>(
216+
val: Pin<&mut F>,
217+
) -> (&'static str, String, Loc) {
218+
match val.resume("Mono".to_string()) {
219+
GeneratorState::Yielded(val) => val,
220+
_ => unreachable!(),
221+
}
222+
}
223+
224+
#[track_caller]
225+
fn dyn_generator(
226+
val: Pin<&mut dyn Generator<String, Yield = (&'static str, String, Loc), Return = ()>>,
227+
) -> (&'static str, String, Loc) {
228+
match val.resume("Dyn".to_string()) {
229+
GeneratorState::Yielded(val) => val,
230+
_ => unreachable!(),
231+
}
232+
}
233+
234+
#[rustfmt::skip]
235+
let generator = #[track_caller] |arg: String| {
236+
yield ("first", arg.clone(), Location::caller());
237+
yield ("second", arg.clone(), Location::caller());
238+
};
239+
240+
let mut pinned = Box::pin(generator);
241+
let (dyn_ret, dyn_arg, dyn_loc) = dyn_generator(pinned.as_mut());
242+
assert_eq!(dyn_ret, "first");
243+
assert_eq!(dyn_arg, "Dyn".to_string());
244+
// The `Generator` trait does not have `#[track_caller]` on `resume`, so
245+
// this will not match.
246+
assert_ne!(dyn_loc.file(), file!());
247+
248+
let (mono_ret, mono_arg, mono_loc) = mono_generator(pinned.as_mut());
249+
let mono_line = line!() - 1;
250+
assert_eq!(mono_ret, "second");
251+
// The generator ignores the argument to the second `resume` call
252+
assert_eq!(mono_arg, "Dyn".to_string());
253+
assert_eq!(mono_loc.file(), file!());
254+
assert_eq!(mono_loc.line(), mono_line);
255+
assert_eq!(mono_loc.column(), 42);
256+
257+
#[rustfmt::skip]
258+
let non_tracked_generator = || { yield Location::caller(); };
259+
let non_tracked_line = line!() - 1; // This is the line of the generator, not its caller
260+
let non_tracked_loc = match Box::pin(non_tracked_generator).as_mut().resume(()) {
261+
GeneratorState::Yielded(val) => val,
262+
_ => unreachable!(),
263+
};
264+
assert_eq!(non_tracked_loc.file(), file!());
265+
assert_eq!(non_tracked_loc.line(), non_tracked_line);
266+
assert_eq!(non_tracked_loc.column(), 44);
267+
}
268+
128269
fn main() {
129270
test_basic();
130271
test_fn_ptr();
131272
test_trait_obj();
132273
test_trait_obj2();
274+
test_closure();
275+
test_generator();
133276
}

0 commit comments

Comments
 (0)