Skip to content

Commit

Permalink
Merge #3142
Browse files Browse the repository at this point in the history
3142: Do not store return values in locals so that holders benefit from lifetime extension for temporaries. r=davidhewitt a=adamreichold

Closes #3138

Co-authored-by: Adam Reichold <adam.reichold@t-online.de>
  • Loading branch information
bors[bot] and adamreichold authored May 9, 2023
2 parents 6281b47 + a60945f commit c9f383a
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 6 deletions.
1 change: 1 addition & 0 deletions newsfragments/3142.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Extend lifetime of holder variables to avoid "temporary value dropped while borrowed" errors when `#[pyfunction]`s take references into `#[pyclass]`es
5 changes: 2 additions & 3 deletions pyo3-macros-backend/src/method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -425,9 +425,8 @@ impl<'a> FnSpec<'a> {

let rust_call = |args: Vec<TokenStream>| {
quote! {
let mut ret = function(#self_arg #(#args),*);
let owned = _pyo3::impl_::pymethods::OkWrap::wrap(ret, #py);
owned.map(|obj| _pyo3::conversion::IntoPyPointer::into_ptr(obj))
_pyo3::impl_::pymethods::OkWrap::wrap(function(#self_arg #(#args),*), #py)
.map(|obj| _pyo3::conversion::IntoPyPointer::into_ptr(obj))
.map_err(::core::convert::Into::into)
}
};
Expand Down
5 changes: 2 additions & 3 deletions pyo3-macros-backend/src/pymethod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -456,9 +456,8 @@ fn impl_py_class_attribute(cls: &syn::Type, spec: &FnSpec<'_>) -> syn::Result<Me
fn #wrapper_ident(py: _pyo3::Python<'_>) -> _pyo3::PyResult<_pyo3::PyObject> {
let function = #cls::#name; // Shadow the method name to avoid #3017
#deprecations
let mut ret = #fncall;
let owned = _pyo3::impl_::pymethods::OkWrap::wrap(ret, py);
owned.map_err(::core::convert::Into::into)
_pyo3::impl_::pymethods::OkWrap::wrap(#fncall, py)
.map_err(::core::convert::Into::into)
}
};

Expand Down
33 changes: 33 additions & 0 deletions tests/test_pyfunction.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#![cfg(feature = "macros")]

use std::collections::HashMap;

#[cfg(not(Py_LIMITED_API))]
use pyo3::buffer::PyBuffer;
use pyo3::prelude::*;
Expand Down Expand Up @@ -512,3 +514,34 @@ fn required_argument_after_option() {
py_assert!(py, f, "f(x=None, y=5) == 5");
})
}

#[pyclass]
struct Key(String);

#[pyclass]
struct Value(i32);

#[pyfunction]
fn return_value_borrows_from_arguments<'py>(
py: Python<'py>,
key: &'py Key,
value: &'py Value,
) -> HashMap<&'py str, i32> {
py.allow_threads(move || {
let mut map = HashMap::new();
map.insert(key.0.as_str(), value.0);
map
})
}

#[test]
fn test_return_value_borrows_from_arguments() {
Python::with_gil(|py| {
let function = wrap_pyfunction!(return_value_borrows_from_arguments, py).unwrap();

let key = Py::new(py, Key("key".to_owned())).unwrap();
let value = Py::new(py, Value(42)).unwrap();

py_assert!(py, function key value, "function(key, value) == { \"key\": 42 }");
});
}

0 comments on commit c9f383a

Please sign in to comment.