Repository navigation
fix: support implicit value conversions in native trampolines #6204
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
rwgk
merged 3 commits into
pybind:master
from
CAOShurong:codex/fix-implicit-trampoline-value-return
Oct 18, 2026
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
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
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
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
codex GPT-6.1-Sol xhigh narration for this change:
The change supplies temporary-object lifetime support when native C++ calls a Python override that returns a value requiring implicit conversion—for example, a Python list converted to an opaque C++ vector.
Normally, a Python-to-C++ bound call already has a
loader_life_supportframe. Implicit conversion registers its temporary Python wrapper with that frame, keeping the underlying C++ object alive during conversion. A call originating in native C++ can lack that frame, so registration throws. Existing lifetime-support codeThe first two production edits add a query for that situation:
loader_life_support::is_active()is declared in the header and defined in the implementation header. It simply checks whether the existing thread-local current-frame pointer is non-null. It adds no state.The behavioral change is in
detail::cast_safe<T>(), which handles trampoline return conversion. Previously it immediately calledpybind11::cast<T>(). Now it first checks three conditions:type_caster_generic, covering registered C++ types and their holder casters.Tis returned by value, rather than by reference or pointer.When all three hold, it creates a local frame and performs the same cast:
loader_life_support life_support; return pybind11::cast<T>(std::move(o));The order matters: C++ constructs the returned
Tbefore destroyinglife_support. Thus the implicit-conversion temporary survives until its value has been copied or moved into the result. The frame then releases its temporary objects; stack unwinding also cleans it up if conversion throws.If an enclosing frame already exists, execution takes the original cast path, so conversion temporaries remain attached to that longer-lived frame. Reference and pointer returns also keep their previous behavior: a frame ending inside
cast_safe()would expire too early to support a borrowed result. The caster restriction similarly leaves ordinary string-view conversions on their existing path.