Skip to content

Commit

Permalink
Merge branch 'master' into gc-default
Browse files Browse the repository at this point in the history
  • Loading branch information
kngwyu authored Jul 15, 2019
2 parents ceefa7c + 29b0a02 commit 9c961b4
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 2 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

### Changed

* Implementing the Using the `gc` parameter for `pyclass` (e.g. `#[pyclass(gc)]`) without implementing the `class::PyGCProtocol` trait is now a compile-time error. Failing to implement this trait could lead to segfaults. [#532](https://github.com/PyO3/pyo3/pull/532)

## [0.7.0] - 2018-05-26

### Added
Expand Down
11 changes: 9 additions & 2 deletions guide/src/class.md
Original file line number Diff line number Diff line change
Expand Up @@ -573,9 +573,16 @@ impl PyGCProtocol for ClassWithGCSupport {

Special protocol trait implementations have to be annotated with the `#[pyproto]` attribute.

It is also possible to enable GC for custom class using the `gc` parameter of the `pyclass` attribute.
It is also possible to enable GC for custom classes using the `gc` parameter of the `pyclass` attribute.
i.e. `#[pyclass(gc)]`. In that case instances of custom class participate in Python garbage
collection, and it is possible to track them with `gc` module methods.
collection, and it is possible to track them with `gc` module methods. When using the `gc` parameter,
it is *required* to implement the `PyGCProtocol` trait, failure to do so will result in an error
at compile time:

```compile_fail
#[pyclass(gc)]
struct GCTracked {} // Fails because it does not implement PyGCProtocol
```

### Iterator Types

Expand Down
22 changes: 22 additions & 0 deletions pyo3-derive-backend/src/pyclass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -296,12 +296,15 @@ fn impl_class(
// insert space for weak ref
let mut has_weakref = false;
let mut has_dict = false;
let mut has_gc = false;
for f in attr.flags.iter() {
if let syn::Expr::Path(ref epath) = f {
if epath.path == parse_quote! {pyo3::type_object::PY_TYPE_FLAG_WEAKREF} {
has_weakref = true;
} else if epath.path == parse_quote! {pyo3::type_object::PY_TYPE_FLAG_DICT} {
has_dict = true;
} else if epath.path == parse_quote! {pyo3::type_object::PY_TYPE_FLAG_GC} {
has_gc = true;
}
}
}
Expand All @@ -321,6 +324,22 @@ fn impl_class(
quote! { None }
};

// Enforce at compile time that PyGCProtocol is implemented
let gc_impl = if has_gc {
let closure_name = format!("__assertion_closure_{}", cls.to_string());
let closure_token = syn::Ident::new(&closure_name, Span::call_site());
quote! {
fn #closure_token() {
use pyo3::class;

fn _assert_implements_protocol<'p, T: pyo3::class::PyGCProtocol<'p>>() {}
_assert_implements_protocol::<#cls>();
}
}
} else {
quote! {}
};

let inventory_impl = impl_inventory(&cls);

let base = &attr.base;
Expand Down Expand Up @@ -365,6 +384,9 @@ fn impl_class(
#inventory_impl

#extra

#gc_impl

}
}

Expand Down

0 comments on commit 9c961b4

Please sign in to comment.