From 108a57eaca3307583422c70711a25302594272b5 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Tue, 14 May 2024 19:11:25 +0200 Subject: [PATCH] Emit a better error for abi3 inheritance --- pyo3-build-config/src/lib.rs | 5 ++++ src/impl_/pyclass.rs | 7 ++++++ .../diagnostic_namespace/abi3_inheritance.rs | 10 ++++++++ .../abi3_inheritance.stderr | 24 +++++++++++++++++++ tests/test_compile_error.rs | 13 +++++++++- 5 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 tests/diagnostic_namespace/abi3_inheritance.rs create mode 100644 tests/diagnostic_namespace/abi3_inheritance.stderr diff --git a/pyo3-build-config/src/lib.rs b/pyo3-build-config/src/lib.rs index 54aff4d10de..0ce808f5b92 100644 --- a/pyo3-build-config/src/lib.rs +++ b/pyo3-build-config/src/lib.rs @@ -152,6 +152,10 @@ pub fn print_feature_cfgs() { if rustc_minor_version >= 74 { println!("cargo:rustc-cfg=invalid_from_utf8_lint"); } + + if rustc_minor_version >= 78 { + println!("cargo:rustc-cfg=diagnostic_namespace"); + } } /// Registers `pyo3`s config names as reachable cfg expressions @@ -167,6 +171,7 @@ pub fn print_expected_cfgs() { println!("cargo:rustc-check-cfg=cfg(invalid_from_utf8_lint)"); println!("cargo:rustc-check-cfg=cfg(pyo3_disable_reference_pool)"); println!("cargo:rustc-check-cfg=cfg(pyo3_leak_on_drop_without_reference_pool)"); + println!("cargo:rustc-check-cfg=cfg(diagnostic_namespace)"); // allow `Py_3_*` cfgs from the minimum supported version up to the // maximum minor version (+1 for development for the next) diff --git a/src/impl_/pyclass.rs b/src/impl_/pyclass.rs index 3ec2e329e1a..6dae9567d06 100644 --- a/src/impl_/pyclass.rs +++ b/src/impl_/pyclass.rs @@ -1102,6 +1102,13 @@ impl PyClassThreadChecker for ThreadCheckerImpl { } /// Trait denoting that this class is suitable to be used as a base type for PyClass. + +#[cfg_attr( + all(diagnostic_namespace, feature = "abi3"), + diagnostic::on_unimplemented( + note = "with the `abi3` feature enabled native types cannot be subclassed" + ) +)] pub trait PyClassBaseType: Sized { type LayoutAsBase: PyClassObjectLayout; type BaseNativeType; diff --git a/tests/diagnostic_namespace/abi3_inheritance.rs b/tests/diagnostic_namespace/abi3_inheritance.rs new file mode 100644 index 00000000000..60972e4cf7a --- /dev/null +++ b/tests/diagnostic_namespace/abi3_inheritance.rs @@ -0,0 +1,10 @@ +use pyo3::exceptions::PyException; +use pyo3::prelude::*; + +#[pyclass(extends=PyException)] +#[derive(Clone)] +struct MyException { + code: u32, +} + +fn main() {} diff --git a/tests/diagnostic_namespace/abi3_inheritance.stderr b/tests/diagnostic_namespace/abi3_inheritance.stderr new file mode 100644 index 00000000000..b45aa665dcd --- /dev/null +++ b/tests/diagnostic_namespace/abi3_inheritance.stderr @@ -0,0 +1,24 @@ +error[E0277]: the trait bound `PyException: PyClassBaseType` is not satisfied + --> tests/diagnostic_namespace/abi3_inheritance.rs:4:19 + | +4 | #[pyclass(extends=PyException)] + | ^^^^^^^^^^^ the trait `PyClass` is not implemented for `PyException`, which is required by `PyException: PyClassBaseType` + | + = note: with the `abi3` feature enabled native types cannot be subclassed + = help: the trait `PyClassBaseType` is implemented for `PyAny` + = note: required for `PyException` to implement `PyClassBaseType` +note: required by a bound in `PyClassImpl::BaseType` + --> src/impl_/pyclass.rs + | + | type BaseType: PyTypeInfo + PyClassBaseType; + | ^^^^^^^^^^^^^^^ required by this bound in `PyClassImpl::BaseType` + +error[E0277]: the trait bound `PyException: PyClass` is not satisfied + --> tests/diagnostic_namespace/abi3_inheritance.rs:4:1 + | +4 | #[pyclass(extends=PyException)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `PyClass` is not implemented for `PyException`, which is required by `PyException: PyClassBaseType` + | + = help: the trait `PyClass` is implemented for `MyException` + = note: required for `PyException` to implement `PyClassBaseType` + = note: this error originates in the attribute macro `pyclass` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/test_compile_error.rs b/tests/test_compile_error.rs index d31c558f096..4359f03e996 100644 --- a/tests/test_compile_error.rs +++ b/tests/test_compile_error.rs @@ -32,7 +32,7 @@ fn test_compile_errors() { t.compile_fail("tests/ui/invalid_pyfunctions.rs"); t.compile_fail("tests/ui/invalid_pymethods.rs"); // output changes with async feature - #[cfg(all(Py_LIMITED_API, feature = "experimental-async"))] + #[cfg(all(Py_LIMITED_API, feature = "experimental-async", not(diagnostic_namespace)))] t.compile_fail("tests/ui/abi3_nativetype_inheritance.rs"); #[cfg(not(feature = "gil-refs"))] t.compile_fail("tests/ui/invalid_intern_arg.rs"); @@ -65,3 +65,14 @@ fn test_compile_errors() { t.compile_fail("tests/ui/invalid_cancel_handle.rs"); t.pass("tests/ui/pymodule_missing_docs.rs"); } + +#[cfg(all(diagnostic_namespace, not(target_arch = "wasm32")))] // Not possible to invoke compiler from wasm +#[test] +fn test_diagnostics() { + #![allow(unused_variables)] + + let t = trybuild::TestCases::new(); + #[cfg(all(feature = "abi3", not(feature = "experimental-async")))] + // output changes with async feature + t.compile_fail("tests/diagnostic_namespace/abi3_inheritance.rs"); +}