Skip to content

Commit 9a641f7

Browse files
Icxoludavidhewitt
authored andcommitted
fix unintentional unsafe_code trigger (#4574)
* Revert "Add missing #[allow(unsafe_code)] attributes (#4396)" This reverts commit 0e03b39. * fix unintentional `unsafe_code` trigger * add newsfragment
1 parent bbceb9f commit 9a641f7

File tree

10 files changed

+45
-23
lines changed

10 files changed

+45
-23
lines changed

newsfragments/4574.fixed.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fixes `#[forbid(unsafe_code)]` regression by reverting #4396.
2+
Fixes unintentional `unsafe_code` trigger by adjusting macro hygiene.

pyo3-macros-backend/src/pyclass.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1659,7 +1659,7 @@ fn impl_pytypeinfo(
16591659

16601660
#[cfg(feature = "gil-refs")]
16611661
let has_py_gil_ref = quote! {
1662-
#[allow(deprecated, unsafe_code)]
1662+
#[allow(deprecated)]
16631663
unsafe impl #pyo3_path::type_object::HasPyGilRef for #cls {
16641664
type AsRefTarget = #pyo3_path::PyCell<Self>;
16651665
}
@@ -1671,7 +1671,6 @@ fn impl_pytypeinfo(
16711671
quote! {
16721672
#has_py_gil_ref
16731673

1674-
#[allow(unsafe_code)]
16751674
unsafe impl #pyo3_path::type_object::PyTypeInfo for #cls {
16761675
const NAME: &'static str = #cls_name;
16771676
const MODULE: ::std::option::Option<&'static str> = #module;

pyo3-macros-backend/src/pymethod.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -781,32 +781,35 @@ pub fn impl_py_getter_def(
781781

782782
// TODO: on MSRV 1.77+, we can use `::std::mem::offset_of!` here, and it should
783783
// make it possible for the `MaybeRuntimePyMethodDef` to be a `Static` variant.
784-
let method_def = quote_spanned! {ty.span()=>
784+
let generator = quote_spanned! { ty.span() =>
785+
#pyo3_path::impl_::pyclass::MaybeRuntimePyMethodDef::Runtime(
786+
|| GENERATOR.generate(#python_name, #doc)
787+
)
788+
};
789+
// This is separate so that the unsafe below does not inherit the span and thus does not
790+
// trigger the `unsafe_code` lint
791+
let method_def = quote! {
785792
#cfg_attrs
786793
{
787794
#[allow(unused_imports)] // might not be used if all probes are positve
788795
use #pyo3_path::impl_::pyclass::Probe;
789796

790797
struct Offset;
791-
#[allow(unsafe_code)]
792798
unsafe impl #pyo3_path::impl_::pyclass::OffsetCalculator<#cls, #ty> for Offset {
793799
fn offset() -> usize {
794800
#pyo3_path::impl_::pyclass::class_offset::<#cls>() +
795801
#pyo3_path::impl_::pyclass::offset_of!(#cls, #field)
796802
}
797803
}
798804

799-
#[allow(unsafe_code)]
800805
const GENERATOR: #pyo3_path::impl_::pyclass::PyClassGetterGenerator::<
801806
#cls,
802807
#ty,
803808
Offset,
804809
{ #pyo3_path::impl_::pyclass::IsPyT::<#ty>::VALUE },
805810
{ #pyo3_path::impl_::pyclass::IsToPyObject::<#ty>::VALUE },
806811
> = unsafe { #pyo3_path::impl_::pyclass::PyClassGetterGenerator::new() };
807-
#pyo3_path::impl_::pyclass::MaybeRuntimePyMethodDef::Runtime(
808-
|| GENERATOR.generate(#python_name, #doc)
809-
)
812+
#generator
810813
}
811814
};
812815

src/exceptions.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ macro_rules! impl_exception_boilerplate {
3434
#[cfg(feature = "gil-refs")]
3535
impl ::std::error::Error for $name {
3636
fn source(&self) -> ::std::option::Option<&(dyn ::std::error::Error + 'static)> {
37-
#[allow(unsafe_code)]
3837
unsafe {
3938
#[allow(deprecated)]
4039
let cause: &$crate::exceptions::PyBaseException = self

src/impl_/pyclass.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,6 @@ slot_fragment_trait! {
353353
#[macro_export]
354354
macro_rules! generate_pyclass_getattro_slot {
355355
($cls:ty) => {{
356-
#[allow(unsafe_code)]
357356
unsafe extern "C" fn __wrap(
358357
_slf: *mut $crate::ffi::PyObject,
359358
attr: *mut $crate::ffi::PyObject,
@@ -437,7 +436,6 @@ macro_rules! define_pyclass_setattr_slot {
437436
#[macro_export]
438437
macro_rules! $generate_macro {
439438
($cls:ty) => {{
440-
#[allow(unsafe_code)]
441439
unsafe extern "C" fn __wrap(
442440
_slf: *mut $crate::ffi::PyObject,
443441
attr: *mut $crate::ffi::PyObject,
@@ -554,7 +552,6 @@ macro_rules! define_pyclass_binary_operator_slot {
554552
#[macro_export]
555553
macro_rules! $generate_macro {
556554
($cls:ty) => {{
557-
#[allow(unsafe_code)]
558555
unsafe extern "C" fn __wrap(
559556
_slf: *mut $crate::ffi::PyObject,
560557
_other: *mut $crate::ffi::PyObject,
@@ -747,7 +744,6 @@ slot_fragment_trait! {
747744
#[macro_export]
748745
macro_rules! generate_pyclass_pow_slot {
749746
($cls:ty) => {{
750-
#[allow(unsafe_code)]
751747
unsafe extern "C" fn __wrap(
752748
_slf: *mut $crate::ffi::PyObject,
753749
_other: *mut $crate::ffi::PyObject,
@@ -872,7 +868,7 @@ macro_rules! generate_pyclass_richcompare_slot {
872868
($cls:ty) => {{
873869
#[allow(unknown_lints, non_local_definitions)]
874870
impl $cls {
875-
#[allow(non_snake_case, unsafe_code)]
871+
#[allow(non_snake_case)]
876872
unsafe extern "C" fn __pymethod___richcmp____(
877873
slf: *mut $crate::ffi::PyObject,
878874
other: *mut $crate::ffi::PyObject,

src/macros.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,6 @@ macro_rules! wrap_pymodule {
207207
#[macro_export]
208208
macro_rules! append_to_inittab {
209209
($module:ident) => {
210-
#[allow(unsafe_code)]
211210
unsafe {
212211
if $crate::ffi::Py_IsInitialized() != 0 {
213212
::std::panic!(

src/tests/hygiene/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#![no_implicit_prelude]
22
#![allow(dead_code, unused_variables, clippy::unnecessary_wraps)]
3-
#![deny(unsafe_code)]
43

54
// The modules in this test are used to check PyO3 macro expansion is hygienic. By locating the test
65
// inside the crate the global `::pyo3` namespace is not available, so in combination with

src/types/mod.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@ pub trait DerefToPyAny {
124124
macro_rules! pyobject_native_type_base(
125125
($name:ty $(;$generics:ident)* ) => {
126126
#[cfg(feature = "gil-refs")]
127-
#[allow(unsafe_code)]
128127
unsafe impl<$($generics,)*> $crate::PyNativeType for $name {
129128
type AsRefSource = Self;
130129
}
@@ -163,7 +162,6 @@ macro_rules! pyobject_native_type_base(
163162
{
164163
#[inline]
165164
fn to_object(&self, py: $crate::Python<'_>) -> $crate::PyObject {
166-
#[allow(unsafe_code)]
167165
unsafe { $crate::PyObject::from_borrowed_ptr(py, self.as_ptr()) }
168166
}
169167
}
@@ -194,7 +192,6 @@ macro_rules! pyobject_native_type_named (
194192
}
195193
}
196194

197-
#[allow(unsafe_code)]
198195
unsafe impl<$($generics,)*> $crate::AsPyPointer for $name {
199196
/// Gets the underlying FFI pointer, returns a borrowed pointer.
200197
#[inline]
@@ -209,7 +206,6 @@ macro_rules! pyobject_native_type_named (
209206
impl<$($generics,)*> $crate::IntoPy<$crate::Py<$name>> for &'_ $name {
210207
#[inline]
211208
fn into_py(self, py: $crate::Python<'_>) -> $crate::Py<$name> {
212-
#[allow(unsafe_code)]
213209
unsafe { $crate::Py::from_borrowed_ptr(py, self.as_ptr()) }
214210
}
215211
}
@@ -221,7 +217,6 @@ macro_rules! pyobject_native_type_named (
221217
#[inline]
222218
fn from(other: &$name) -> Self {
223219
use $crate::PyNativeType;
224-
#[allow(unsafe_code)]
225220
unsafe { $crate::Py::from_borrowed_ptr(other.py(), other.as_ptr()) }
226221
}
227222
}
@@ -231,7 +226,6 @@ macro_rules! pyobject_native_type_named (
231226
#[cfg(feature = "gil-refs")]
232227
impl<'a, $($generics,)*> ::std::convert::From<&'a $name> for &'a $crate::PyAny {
233228
fn from(ob: &'a $name) -> Self {
234-
#[allow(unsafe_code)]
235229
unsafe{&*(ob as *const $name as *const $crate::PyAny)}
236230
}
237231
}
@@ -255,7 +249,6 @@ macro_rules! pyobject_native_static_type_object(
255249
#[macro_export]
256250
macro_rules! pyobject_native_type_info(
257251
($name:ty, $typeobject:expr, $module:expr $(, #checkfunction=$checkfunction:path)? $(;$generics:ident)*) => {
258-
#[allow(unsafe_code)]
259252
unsafe impl<$($generics,)*> $crate::type_object::PyTypeInfo for $name {
260253
const NAME: &'static str = stringify!($name);
261254
const MODULE: ::std::option::Option<&'static str> = $module;

tests/test_compile_error.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ fn test_compile_errors() {
6363
#[cfg(any(not(Py_LIMITED_API), Py_3_10))] // to avoid PyFunctionArgument for &str
6464
t.compile_fail("tests/ui/invalid_cancel_handle.rs");
6565
t.pass("tests/ui/pymodule_missing_docs.rs");
66+
#[cfg(not(Py_LIMITED_API))]
67+
t.pass("tests/ui/forbid_unsafe.rs");
6668
#[cfg(all(Py_LIMITED_API, not(feature = "experimental-async")))]
6769
// output changes with async feature
6870
t.compile_fail("tests/ui/abi3_inheritance.rs");

tests/ui/forbid_unsafe.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#![forbid(unsafe_code)]
2+
3+
use pyo3::*;
4+
5+
#[allow(unexpected_cfgs)]
6+
#[path = "../../src/tests/hygiene/mod.rs"]
7+
mod hygiene;
8+
9+
mod gh_4394 {
10+
use pyo3::prelude::*;
11+
12+
#[derive(Eq, Ord, PartialEq, PartialOrd, Clone)]
13+
#[pyclass(get_all)]
14+
pub struct VersionSpecifier {
15+
pub(crate) operator: Operator,
16+
pub(crate) version: Version,
17+
}
18+
19+
#[derive(Eq, Ord, PartialEq, PartialOrd, Debug, Hash, Clone, Copy)]
20+
#[pyo3::pyclass(eq, eq_int)]
21+
pub enum Operator {
22+
Equal,
23+
}
24+
25+
#[derive(Clone, Eq, PartialEq, PartialOrd, Ord)]
26+
#[pyclass]
27+
pub struct Version;
28+
}
29+
30+
fn main() {}

0 commit comments

Comments
 (0)