diff --git a/src/instance.rs b/src/instance.rs index e5bca5d9..f2e0749f 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -167,7 +167,7 @@ impl Py { pub trait AsPyRef: Sized { type Target; /// 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 AsPyRef for Py @@ -175,7 +175,7 @@ where T: PyTypeInfo, { 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 as *const PyAny; unsafe { PyDowncastImpl::unchecked_downcast(&*any) } } diff --git a/src/object.rs b/src/object.rs index edeafd51..642c94c4 100644 --- a/src/object.rs +++ b/src/object.rs @@ -267,7 +267,7 @@ impl PyObject { impl AsPyRef for PyObject { 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) } } } diff --git a/tests/test_compile_error.rs b/tests/test_compile_error.rs index e141853d..a683f5f5 100644 --- a/tests/test_compile_error.rs +++ b/tests/test_compile_error.rs @@ -7,6 +7,7 @@ fn test_compile_errors() { t.compile_fail("tests/ui/invalid_pymethod_names.rs"); t.compile_fail("tests/ui/missing_clone.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, // we skip this test. // TODO(kngwyu): Remove this `if` when we update minimum nightly. diff --git a/tests/ui/wrong_aspyref_lifetimes.rs b/tests/ui/wrong_aspyref_lifetimes.rs new file mode 100644 index 00000000..20d94b23 --- /dev/null +++ b/tests/ui/wrong_aspyref_lifetimes.rs @@ -0,0 +1,10 @@ +use pyo3::{types::PyDict, AsPyRef, Py, PyNativeType, Python}; + +fn main() { + let gil = Python::acquire_gil(); + let dict: Py = 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. +} diff --git a/tests/ui/wrong_aspyref_lifetimes.stderr b/tests/ui/wrong_aspyref_lifetimes.stderr new file mode 100644 index 00000000..7c3b87ce --- /dev/null +++ b/tests/ui/wrong_aspyref_lifetimes.stderr @@ -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