Inhibit subclassing native types with ABI3 set

This commit is contained in:
kngwyu 2020-09-20 00:42:55 +09:00
parent c07e1aa40a
commit 7644d67ad8
5 changed files with 82 additions and 55 deletions

View File

@ -103,6 +103,8 @@ macro_rules! pyobject_native_type_core {
#[macro_export]
macro_rules! pyobject_native_type_sized {
($name: ty, $layout: path $(,$type_param: ident)*) => {
// To prevent inheriting native types with ABI3
#[cfg(not(Py_LIMITED_API))]
impl $crate::type_object::PySizedLayout<$name> for $layout {}
impl<'a, $($type_param,)*> $crate::derive_utils::PyBaseTypeUtils for $name {
type Dict = $crate::pyclass_slots::PyClassDummySlot;

View File

@ -11,6 +11,9 @@ fn test_compile_errors() {
t.compile_fail("tests/ui/reject_generics.rs");
t.compile_fail("tests/ui/wrong_aspyref_lifetimes.rs");
#[cfg(Py_LIMITED_API)]
t.compile_fail("tests/ui/abi3_nativetype_inheritance.rs");
tests_rust_1_43(&t);
tests_rust_1_46(&t);

View File

@ -3,7 +3,6 @@ use pyo3::py_run;
use pyo3::types::IntoPyDict;
use pyo3::types::{PyDict, PySet};
mod common;
#[pyclass(subclass)]
@ -153,60 +152,63 @@ except Exception as e:
);
}
#[pyclass(extends=PySet)]
#[derive(Debug)]
struct SetWithName {
#[pyo3(get(name))]
_name: &'static str,
}
// Subclassing builtin types is not allowed in the LIMITED API.
#[cfg(not(Py_LIMITED_API))]
mod inheriting_native_type {
use super::*;
use pyo3::types::{PyDict, PySet};
#[pymethods]
impl SetWithName {
#[new]
fn new() -> Self {
SetWithName { _name: "Hello :)" }
#[pyclass(extends=PySet)]
#[derive(Debug)]
struct SetWithName {
#[pyo3(get(name))]
_name: &'static str,
}
#[pymethods]
impl SetWithName {
#[new]
fn new() -> Self {
SetWithName { _name: "Hello :)" }
}
}
#[test]
fn inherit_set() {
let gil = Python::acquire_gil();
let py = gil.python();
let set_sub = pyo3::PyCell::new(py, SetWithName::new()).unwrap();
py_run!(
py,
set_sub,
r#"set_sub.add(10); assert list(set_sub) == [10]; assert set_sub._name == "Hello :)""#
);
}
#[pyclass(extends=PyDict)]
#[derive(Debug)]
struct DictWithName {
#[pyo3(get(name))]
_name: &'static str,
}
#[pymethods]
impl DictWithName {
#[new]
fn new() -> Self {
DictWithName { _name: "Hello :)" }
}
}
#[test]
fn inherit_dict() {
let gil = Python::acquire_gil();
let py = gil.python();
let dict_sub = pyo3::PyCell::new(py, DictWithName::new()).unwrap();
py_run!(
py,
dict_sub,
r#"dict_sub[0] = 1; assert dict_sub[0] == 1; assert dict_sub._name == "Hello :)""#
);
}
}
// Subclassing builtin types is not allowed in the LIMITED API.
#[test]
#[cfg_attr(Py_LIMITED_API, should_panic)]
fn inherit_set() {
let gil = Python::acquire_gil();
let py = gil.python();
let set_sub = pyo3::PyCell::new(py, SetWithName::new()).unwrap();
py_run!(
py,
set_sub,
r#"set_sub.add(10); assert list(set_sub) == [10]; assert set_sub._name == "Hello :)""#
);
}
#[pyclass(extends=PyDict)]
#[derive(Debug)]
struct DictWithName {
#[pyo3(get(name))]
_name: &'static str,
}
#[pymethods]
impl DictWithName {
#[new]
fn new() -> Self {
DictWithName { _name: "Hello :)" }
}
}
// Subclassing builtin types is not allowed in the LIMITED API.
#[test]
#[cfg_attr(Py_LIMITED_API, should_panic)]
fn inherit_dict() {
let gil = Python::acquire_gil();
let py = gil.python();
let dict_sub = pyo3::PyCell::new(py, DictWithName::new()).unwrap();
py_run!(
py,
dict_sub,
r#"dict_sub[0] = 1; assert dict_sub[0] == 1; assert dict_sub._name == "Hello :)""#
);
}

View File

@ -0,0 +1,7 @@
use pyo3::prelude::*;
use pyo3::types::PyDict;
#[pyclass(extends=PyDict)]
struct TestClass {}
fn main() {}

View File

@ -0,0 +1,13 @@
error[E0277]: the trait bound `pyo3::ffi::dictobject::PyDictObject: pyo3::type_object::PySizedLayout<pyo3::types::dict::PyDict>` is not satisfied
--> $DIR/abi3_nativetype_inheritance.rs:4:1
|
4 | #[pyclass(extends=PyDict)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `pyo3::type_object::PySizedLayout<pyo3::types::dict::PyDict>` is not implemented for `pyo3::ffi::dictobject::PyDictObject`
|
::: $WORKSPACE/src/type_object.rs:96:22
|
96 | type BaseLayout: PySizedLayout<Self::BaseType>;
| ----------------------------- required by this bound in `pyo3::type_object::PyTypeInfo`
|
= note: required because of the requirements on the impl of `pyo3::type_object::PySizedLayout<pyo3::types::dict::PyDict>` for `pyo3::pycell::PyCellBase<pyo3::types::dict::PyDict>`
= note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)