Repository navigation
Run element destructors on refcount map iterator erase - #585
perfloop-agent wants to merge 2 commits into
Conversation
| Map::erase(a0, &a1) | ||
| Map::erase(a0, &a1, |__key, __value| { | ||
| use libcc2rs::__swap::{Destroy, DestroyNone, DestroyWithDtor}; | ||
| (&&Destroy(&__value)).destroy(); |
There was a problem hiding this comment.
this is not a pretty solution to pass a destroy function to every call. We would need to pass destructors in quite a few places (including map destructor)
There was a problem hiding this comment.
The callback parameter is removed. Map::erase returns the successor and an owning handle to the removed entry, and the expanded iterator rules run its destructors before yielding the successor. This avoids per-map hook initialization while leaving whole-map destruction unchanged. The callback removal revises the previously reviewed proposal, and this PR covers destruction of an erased entry only; would you like whole-map destruction (clear and map drop) handled in this PR or in a follow-up?
There was a problem hiding this comment.
I don't like any solution that requires calling destructors manually. That is not safe because after translation, if someone modifies the code by hand, it's very error prone. C++ destructors should be called automatically by Drop or similar. Might be a larger change than what you had planned.
Signed-off-by: Perfloop Agent <agent@perfloop.ai> Signed-off-by: Tomás Senart <ts@perfloop.ai>
Signed-off-by: Perfloop Agent <agent@perfloop.ai> Signed-off-by: Tomás Senart <ts@perfloop.ai>
c8a7b42 to
7a77c54
Compare
|
I would replace the destructor calls in the erase rules with automatic destruction owned by the map entries:
Rough estimate: 400–700 handwritten lines across Is this map-entry RAII design what you mean by automatic destruction, and would you prefer it to replace the approach in #585 or be developed in a new PR? |
|
Yeah, this is too much for you. Let me close this. |
Refcount map iterator erase now calls the stored key and mapped-value C++ destructors before returning. Releasing Rust storage is not a substitute for these explicit callbacks, and unused iterator copies can keep that storage alive.
Map::erasereturns the successor and a strong owner of the removed entry. The mutable and const iterator rules finish destruction after the runtime has unlinked the entry, removed its ordered-index reference and released its borrows. The rules reuse the existing destructor dispatch, which does nothing for trivial types. No finalizer is passed into the runtime or stored in the map, and neither key nor mapped value needs a newClonebound. The rule-writing documentation explains the ownership boundary.Testing
The scoped map iterator-erase lit runner reports 5 passed and 1 expected failure, with no unexpected failures or skips.
tests/unit/map_erase_destructor.cppcompares native C++ with generated code for record/record, record/int, int/record and int/int entries. It checks callbacks at return and after unused iterator copies leave scope, plus successor, size, remaining element order and untouched live positions. It also erases a move-only key from a nested default-constructed map using a temporary iterator and no retained copy. The existing map fixtures check trivial-type behavior and key-copy counts.Runtime and rules Clippy, Rust formatting, fixture C++ formatting and documentation formatting checks pass. The destructor fixture also compiles as generated Rust with unsafe code forbidden; without the fix it fails the callback assertion.
This repair covers refcount iterator erase. Key-based erase, whole-map destruction and unsafe output are unchanged; the destructor fixture remains an expected failure in the unsafe model. Unused iterator copies may still retain Rust storage.
Case and evidence
Made by Perfloop. Human sponsor: Tomás Senart. To ask for a change, comment or review in plain words. How Perfloop handles pull requests.