Fix lifetime safety bug of AsPyRef::as_ref(). (#876)
* Fix lifetime safety bug of AsPyRef::as_ref(). Fixes #875. * Add test for AsPyRef's lifetimes.
This commit is contained in:
parent
a58a1cf4c6
commit
dcab478d66
|
@ -167,7 +167,7 @@ impl<T> Py<T> {
|
||||||
pub trait AsPyRef: Sized {
|
pub trait AsPyRef: Sized {
|
||||||
type Target;
|
type Target;
|
||||||
/// Return reference to object.
|
/// Return reference to object.
|
||||||
fn as_ref(&self, py: Python<'_>) -> &Self::Target;
|
fn as_ref<'p>(&'p self, py: Python<'p>) -> &'p Self::Target;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> AsPyRef for Py<T>
|
impl<T> AsPyRef for Py<T>
|
||||||
|
@ -175,7 +175,7 @@ where
|
||||||
T: PyTypeInfo,
|
T: PyTypeInfo,
|
||||||
{
|
{
|
||||||
type Target = T::AsRefTarget;
|
type Target = T::AsRefTarget;
|
||||||
fn as_ref(&self, _py: Python) -> &Self::Target {
|
fn as_ref<'p>(&'p self, _py: Python<'p>) -> &'p Self::Target {
|
||||||
let any = self as *const Py<T> as *const PyAny;
|
let any = self as *const Py<T> as *const PyAny;
|
||||||
unsafe { PyDowncastImpl::unchecked_downcast(&*any) }
|
unsafe { PyDowncastImpl::unchecked_downcast(&*any) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -267,7 +267,7 @@ impl PyObject {
|
||||||
|
|
||||||
impl AsPyRef for PyObject {
|
impl AsPyRef for PyObject {
|
||||||
type Target = PyAny;
|
type Target = PyAny;
|
||||||
fn as_ref(&self, _py: Python) -> &PyAny {
|
fn as_ref<'p>(&'p self, _py: Python<'p>) -> &'p PyAny {
|
||||||
unsafe { &*(self as *const _ as *const PyAny) }
|
unsafe { &*(self as *const _ as *const PyAny) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ fn test_compile_errors() {
|
||||||
t.compile_fail("tests/ui/invalid_pymethod_names.rs");
|
t.compile_fail("tests/ui/invalid_pymethod_names.rs");
|
||||||
t.compile_fail("tests/ui/missing_clone.rs");
|
t.compile_fail("tests/ui/missing_clone.rs");
|
||||||
t.compile_fail("tests/ui/reject_generics.rs");
|
t.compile_fail("tests/ui/reject_generics.rs");
|
||||||
|
t.compile_fail("tests/ui/wrong_aspyref_lifetimes.rs");
|
||||||
// Since the current minimum nightly(2020-01-20) has a different error message,
|
// Since the current minimum nightly(2020-01-20) has a different error message,
|
||||||
// we skip this test.
|
// we skip this test.
|
||||||
// TODO(kngwyu): Remove this `if` when we update minimum nightly.
|
// TODO(kngwyu): Remove this `if` when we update minimum nightly.
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
use pyo3::{types::PyDict, AsPyRef, Py, PyNativeType, Python};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let gil = Python::acquire_gil();
|
||||||
|
let dict: Py<PyDict> = PyDict::new(gil.python()).into();
|
||||||
|
let dict: &PyDict = dict.as_ref(gil.python());
|
||||||
|
drop(gil);
|
||||||
|
|
||||||
|
let _py: Python = dict.py(); // Obtain a Python<'p> without GIL.
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
error[E0505]: cannot move out of `gil` because it is borrowed
|
||||||
|
--> $DIR/wrong_aspyref_lifetimes.rs:7:10
|
||||||
|
|
|
||||||
|
6 | let dict: &PyDict = dict.as_ref(gil.python());
|
||||||
|
| --- borrow of `gil` occurs here
|
||||||
|
7 | drop(gil);
|
||||||
|
| ^^^ move out of `gil` occurs here
|
||||||
|
8 |
|
||||||
|
9 | let _py: Python = dict.py(); // Obtain a Python<'p> without GIL.
|
||||||
|
| ---- borrow later used here
|
Loading…
Reference in New Issue