Conversation
`insert` is annotated `#[track_caller]`, but it raises its out-of-bounds panic from inside `try_insert`, which is not annotated. The annotation is therefore defeated on that path: a full-vector `insert` blames the caller, while an out-of-bounds `insert` blames src/arrayvec.rs. `remove` and `swap_remove` were never annotated either. bluss#236 added `#[track_caller]` for the capacity-overflow panics and bluss#212 was closed as fixed by it, but the `panic_oob!` family was left behind. Annotate `try_insert`, `remove` and `swap_remove`. `remove` and `swap_remove` raised their panic inside an `unwrap_or_else` closure, and closures do not inherit `#[track_caller]`, so both are rewritten as a `match` that panics directly in the annotated function body. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
ArrayVec::insertis annotated#[track_caller], but only one of its two documented panics honours it.Its doc says "Panics if the array is full or the
indexis out of bounds." The full-array panic comes from the.unwrap()ininsert's own body, so it reports the caller. The out-of-bounds panic comes frompanic_oob!insidetry_insert, which is not annotated — so it reports a line inside arrayvec. Same function, same doc sentence, two different behaviours.removeandswap_removewere never annotated at all.#236 added
#[track_caller]for the capacity-overflow panics — its title is literally "track_caller for capacity overflow panics" — and #212 was then closed as fixed by it. Thepanic_oob!family was left behind.Reproduction
Against
master(8a7c821), capturingPanicHookInfo::location()via a panic hook:With this branch, all five report
tests/repro.rs.The change
#[track_caller]ontry_insert,removeandswap_remove.removeandswap_removeraised their panic from inside anunwrap_or_elseclosure. Closures do not inherit#[track_caller], so annotating the enclosing function alone would not have worked; both are rewritten as amatchthat panics directly in the annotated body. That is the only reason those two hunks are larger than one line.I also added the missing "if the" to
try_insert's panic doc line (***Panics*** \index` is out of bounds.`), since it is the same sentence. Happy to drop that hunk if you would rather keep this to the attribute.Performance
You raised this on #212 in 2022 — "Needs knowledge about the performance impact ... for other hotter methods" — so I measured it rather than assert it.
Wall-clock benchmarking was useless on my machine (shared, ±100% noise), so I compared generated code instead. Release build,
aarch64-apple-darwin,opt-level=3, three#[no_mangle]probe functions calling each method on anArrayVec<u32, 64>:try_insertLocationremovestpswap_removemov w8, w8droppedThere is no cost because these methods are generic over
CAPand get monomorphised and inlined at the call site, where the implicit caller-location argument is constant-folded away; the&Locationonly materialises on the cold panic path, which was already constructing one. Theremove/swap_removeshrink comes from dropping the closure, not from the attribute.Caveat: that measurement is one target and one opt-level, with the calls inlined. I have not checked a forced
#[inline(never)]call, where the extra pointer argument would be real. If you want the probe crate or numbers on x86-64, say so.Testing
cargo test --all-featuresandcargo test --release --all-featuresboth pass on macOS aarch64 (53 + 45 doctests + the integration suites), andcargo build --no-default-featuresbuilds. The new test intests/tests.rsfails onmasterand passes here. I could not check the 1.51 MSRV job locally — no toolchain on this machine and not enough disk to install one — but#[track_caller]is stable since 1.46 and is already used in the crate, so I expect it to be fine; CI will confirm.Not included
ArrayString::remove(panic!("cannot remove a char from the end of a string")) andArrayString::truncate(assert!(self.is_char_boundary(..))) have the same gap, whileArrayString::push/push_strare annotated. I left them out to keep this to one defect — say the word and I will add them here or in a separate PR.Closes the part of #212 that #236 did not cover.
Written with assistance from Claude Code (Claude Opus 5). All reproduction output, benchmark figures and test results above are real runs on my machine, not generated text.