From 0b8be7e31ed19c68e287eb8655f166645d420fb0 Mon Sep 17 00:00:00 2001 From: David Hewitt Date: Tue, 29 Oct 2024 08:25:48 +0000 Subject: [PATCH 1/2] use locations with call-site hygiene for UI errors --- pyo3-macros-backend/src/deprecations.rs | 3 +-- pyo3-macros-backend/src/intopyobject.rs | 6 +++--- pyo3-macros-backend/src/method.rs | 12 ++++++------ pyo3-macros-backend/src/params.rs | 10 +++++----- pyo3-macros-backend/src/pyclass.rs | 14 +++++++------- pyo3-macros-backend/src/pymethod.rs | 6 +++--- pyo3-macros-backend/src/quotes.rs | 6 +++--- pyo3-macros-backend/src/utils.rs | 12 +++++++++--- tests/ui/deprecations.stderr | 11 +++++++++++ tests/ui/invalid_cancel_handle.stderr | 6 ++++++ tests/ui/invalid_frozen_pyclass_borrow.stderr | 4 ++++ tests/ui/invalid_property_args.stderr | 4 ++++ tests/ui/invalid_pyclass_args.stderr | 2 ++ tests/ui/invalid_pyclass_enum.stderr | 13 +++++++++++++ tests/ui/invalid_pyfunctions.stderr | 4 ++++ tests/ui/invalid_pymethod_enum.stderr | 8 ++++++++ tests/ui/invalid_pymethod_receiver.stderr | 4 ++++ tests/ui/invalid_pymethods.stderr | 4 ++++ tests/ui/invalid_result_conversion.stderr | 3 +++ tests/ui/missing_intopy.stderr | 9 ++++++++- tests/ui/static_ref.stderr | 14 ++++++++------ 21 files changed, 116 insertions(+), 39 deletions(-) diff --git a/pyo3-macros-backend/src/deprecations.rs b/pyo3-macros-backend/src/deprecations.rs index df48c9da417..d3bc8ff954a 100644 --- a/pyo3-macros-backend/src/deprecations.rs +++ b/pyo3-macros-backend/src/deprecations.rs @@ -1,6 +1,5 @@ use crate::method::{FnArg, FnSpec}; use proc_macro2::TokenStream; -use quote::quote_spanned; pub(crate) fn deprecate_trailing_option_default(spec: &FnSpec<'_>) -> TokenStream { if spec.signature.attribute.is_none() @@ -42,7 +41,7 @@ pub(crate) fn deprecate_trailing_option_default(spec: &FnSpec<'_>) -> TokenStrea deprecation_msg.push_str( "))]` to this function to silence this warning and keep the current behavior", ); - quote_spanned! { spec.name.span() => + quote_at_location! { spec.name.span() => #[deprecated(note = #deprecation_msg)] #[allow(dead_code)] const SIGNATURE: () = (); diff --git a/pyo3-macros-backend/src/intopyobject.rs b/pyo3-macros-backend/src/intopyobject.rs index 3b4b2d376bb..ece5607e754 100644 --- a/pyo3-macros-backend/src/intopyobject.rs +++ b/pyo3-macros-backend/src/intopyobject.rs @@ -1,7 +1,7 @@ use crate::attributes::{self, get_pyo3_options, CrateAttribute}; use crate::utils::Ctx; use proc_macro2::{Span, TokenStream}; -use quote::{format_ident, quote, quote_spanned}; +use quote::{format_ident, quote}; use syn::ext::IdentExt; use syn::parse::{Parse, ParseStream}; use syn::spanned::Spanned as _; @@ -354,7 +354,7 @@ impl<'a> Container<'a> { target: quote! {<#ty as #pyo3_path::conversion::IntoPyObject<'py>>::Target}, output: quote! {<#ty as #pyo3_path::conversion::IntoPyObject<'py>>::Output}, error: quote! {<#ty as #pyo3_path::conversion::IntoPyObject<'py>>::Error}, - body: quote_spanned! { ty.span() => + body: quote_at_location! { ty.span() => #unpack <#ty as #pyo3_path::conversion::IntoPyObject<'py>>::into_pyobject(arg0, py) }, @@ -421,7 +421,7 @@ impl<'a> Container<'a> { .map(|(i, f)| { let ty = &f.field.ty; let value = Ident::new(&format!("arg{i}"), f.field.ty.span()); - quote_spanned! { f.field.ty.span() => + quote_at_location! { f.field.ty.span() => <#ty as #pyo3_path::conversion::IntoPyObject>::into_pyobject(#value, py) .map(#pyo3_path::BoundObject::into_any) .map(#pyo3_path::BoundObject::into_bound)?, diff --git a/pyo3-macros-backend/src/method.rs b/pyo3-macros-backend/src/method.rs index 019fb5e644b..27f1b938d87 100644 --- a/pyo3-macros-backend/src/method.rs +++ b/pyo3-macros-backend/src/method.rs @@ -3,7 +3,7 @@ use std::ffi::CString; use std::fmt::Display; use proc_macro2::{Span, TokenStream}; -use quote::{format_ident, quote, quote_spanned, ToTokens}; +use quote::{format_ident, quote, ToTokens}; use syn::{ext::IdentExt, spanned::Spanned, Ident, Result}; use crate::deprecations::deprecate_trailing_option_default; @@ -265,7 +265,7 @@ impl FnType { let py = syn::Ident::new("py", Span::call_site()); let slf: Ident = syn::Ident::new("_slf", Span::call_site()); let pyo3_path = pyo3_path.to_tokens_spanned(*span); - let ret = quote_spanned! { *span => + let ret = quote_at_location! { *span => #[allow(clippy::useless_conversion)] ::std::convert::Into::into( #pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(#py, &*(&#slf as *const _ as *const *mut _)) @@ -278,7 +278,7 @@ impl FnType { let py = syn::Ident::new("py", Span::call_site()); let slf: Ident = syn::Ident::new("_slf", Span::call_site()); let pyo3_path = pyo3_path.to_tokens_spanned(*span); - let ret = quote_spanned! { *span => + let ret = quote_at_location! { *span => #[allow(clippy::useless_conversion)] ::std::convert::Into::into( #pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(#py, &*(&#slf as *const _ as *const *mut _)) @@ -342,7 +342,7 @@ impl SelfType { let holder = holders.push_holder(*span); let pyo3_path = pyo3_path.to_tokens_spanned(*span); error_mode.handle_error( - quote_spanned! { *span => + quote_at_location! { *span => #pyo3_path::impl_::extract_argument::#method::<#cls>( #pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(#py, &#slf).0, &mut #holder, @@ -354,7 +354,7 @@ impl SelfType { SelfType::TryFromBoundRef(span) => { let pyo3_path = pyo3_path.to_tokens_spanned(*span); error_mode.handle_error( - quote_spanned! { *span => + quote_at_location! { *span => #pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(#py, &#slf).downcast::<#cls>() .map_err(::std::convert::Into::<#pyo3_path::PyErr>::into) .and_then( @@ -824,7 +824,7 @@ impl<'a> FnSpec<'a> { let self_arg = self .tp .self_arg(cls, ExtractErrorMode::Raise, &mut holders, ctx); - let call = quote_spanned! {*output_span=> #rust_name(#self_arg #(#args),*) }; + let call = quote_at_location! {*output_span=> #rust_name(#self_arg #(#args),*) }; let init_holders = holders.init_holders(ctx); quote! { unsafe fn #ident( diff --git a/pyo3-macros-backend/src/params.rs b/pyo3-macros-backend/src/params.rs index ccf725d3760..d72761a7efc 100644 --- a/pyo3-macros-backend/src/params.rs +++ b/pyo3-macros-backend/src/params.rs @@ -5,7 +5,7 @@ use crate::{ quotes::some_wrap, }; use proc_macro2::{Span, TokenStream}; -use quote::{format_ident, quote, quote_spanned}; +use quote::{format_ident, quote}; use syn::spanned::Spanned; pub struct Holders { @@ -61,7 +61,7 @@ pub fn impl_arg_params( .filter_map(|(i, arg)| { let from_py_with = &arg.from_py_with()?.value; let from_py_with_holder = format_ident!("from_py_with_{}", i); - Some(quote_spanned! { from_py_with.span() => + Some(quote_at_location! { from_py_with.span() => let #from_py_with_holder = #from_py_with; }) }) @@ -196,7 +196,7 @@ fn impl_arg_param( FnArg::VarArgs(arg) => { let holder = holders.push_holder(arg.name.span()); let name_str = arg.name.to_string(); - quote_spanned! { arg.name.span() => + quote_at_location! { arg.name.span() => #pyo3_path::impl_::extract_argument::extract_argument( &_args, &mut #holder, @@ -207,7 +207,7 @@ fn impl_arg_param( FnArg::KwArgs(arg) => { let holder = holders.push_holder(arg.name.span()); let name_str = arg.name.to_string(); - quote_spanned! { arg.name.span() => + quote_at_location! { arg.name.span() => #pyo3_path::impl_::extract_argument::extract_optional_argument( _kwargs.as_deref(), &mut #holder, @@ -236,7 +236,7 @@ pub(crate) fn impl_regular_arg_param( // Use this macro inside this function, to ensure that all code generated here is associated // with the function argument macro_rules! quote_arg_span { - ($($tokens:tt)*) => { quote_spanned!(arg.ty.span() => $($tokens)*) } + ($($tokens:tt)*) => { quote_at_location!(arg.ty.span() => $($tokens)*) } } let name_str = arg.name.to_string(); diff --git a/pyo3-macros-backend/src/pyclass.rs b/pyo3-macros-backend/src/pyclass.rs index d7edeb0bf24..4eab13e9684 100644 --- a/pyo3-macros-backend/src/pyclass.rs +++ b/pyo3-macros-backend/src/pyclass.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; use std::fmt::Debug; use proc_macro2::{Ident, Span, TokenStream}; -use quote::{format_ident, quote, quote_spanned, ToTokens}; +use quote::{format_ident, quote, ToTokens}; use syn::ext::IdentExt; use syn::parse::{Parse, ParseStream}; use syn::punctuated::Punctuated; @@ -1835,7 +1835,7 @@ fn pyclass_richcmp_arms( .map(|eq| eq.span) .or(options.eq_int.map(|eq_int| eq_int.span)) .map(|span| { - quote_spanned! { span => + quote_at_location! { span => #pyo3_path::pyclass::CompareOp::Eq => { ::std::result::Result::Ok(#pyo3_path::conversion::IntoPy::into_py(self_val == other, py)) }, @@ -1853,7 +1853,7 @@ fn pyclass_richcmp_arms( let ord_arms = options .ord .map(|ord| { - quote_spanned! { ord.span() => + quote_at_location! { ord.span() => #pyo3_path::pyclass::CompareOp::Gt => { ::std::result::Result::Ok(#pyo3_path::conversion::IntoPy::into_py(self_val > other, py)) }, @@ -1913,7 +1913,7 @@ fn pyclass_richcmp_simple_enum( let arms = pyclass_richcmp_arms(&options, ctx)?; let eq = options.eq.map(|eq| { - quote_spanned! { eq.span() => + quote_at_location! { eq.span() => let self_val = self; if let ::std::result::Result::Ok(other) = #pyo3_path::types::PyAnyMethods::downcast::(other) { let other = &*other.borrow(); @@ -1925,7 +1925,7 @@ fn pyclass_richcmp_simple_enum( }); let eq_int = options.eq_int.map(|eq_int| { - quote_spanned! { eq_int.span() => + quote_at_location! { eq_int.span() => let self_val = self.__pyo3__int__(); if let ::std::result::Result::Ok(other) = #pyo3_path::types::PyAnyMethods::extract::<#repr_type>(other).or_else(|_| { #pyo3_path::types::PyAnyMethods::downcast::(other).map(|o| o.borrow().__pyo3__int__()) @@ -2282,7 +2282,7 @@ impl<'a> PyClassImplsBuilder<'a> { }; let pyclass_base_type_impl = attr.options.subclass.map(|subclass| { - quote_spanned! { subclass.span() => + quote_at_location! { subclass.span() => impl #pyo3_path::impl_::pyclass::PyClassBaseType for #cls { type LayoutAsBase = #pyo3_path::impl_::pycell::PyClassObject; type BaseNativeType = ::BaseNativeType; @@ -2456,7 +2456,7 @@ fn generate_cfg_check(variants: &[PyClassEnumUnitVariant<'_>], cls: &syn::Ident) } } - quote_spanned! { + quote_at_location! { cls.span() => #[cfg(all(#(#conditions),*))] ::core::compile_error!(concat!("#[pyclass] can't be used on enums without any variants - all variants of enum `", stringify!(#cls), "` have been configured out by cfg attributes")); diff --git a/pyo3-macros-backend/src/pymethod.rs b/pyo3-macros-backend/src/pymethod.rs index d825609cd77..3a149729a9d 100644 --- a/pyo3-macros-backend/src/pymethod.rs +++ b/pyo3-macros-backend/src/pymethod.rs @@ -13,7 +13,7 @@ use crate::{ }; use crate::{quotes, utils}; use proc_macro2::{Span, TokenStream}; -use quote::{format_ident, quote, quote_spanned, ToTokens}; +use quote::{format_ident, quote, ToTokens}; use syn::{ext::IdentExt, spanned::Spanned, Result}; /// Generated code for a single pymethod item. @@ -662,7 +662,7 @@ pub fn impl_py_setter_def( if let Some(from_py_with) = &value_arg.from_py_with().as_ref().map(|f| &f.value) { let ident = syn::Ident::new("from_py_with", from_py_with.span()); ( - quote_spanned! { from_py_with.span() => + quote_at_location! { from_py_with.span() => let #ident = #from_py_with; }, ident, @@ -816,7 +816,7 @@ pub fn impl_py_getter_def( // TODO: on MSRV 1.77+, we can use `::std::mem::offset_of!` here, and it should // make it possible for the `MaybeRuntimePyMethodDef` to be a `Static` variant. - let generator = quote_spanned! { ty.span() => + let generator = quote_at_location! { ty.span() => #pyo3_path::impl_::pyclass::MaybeRuntimePyMethodDef::Runtime( || GENERATOR.generate(#python_name, #doc) ) diff --git a/pyo3-macros-backend/src/quotes.rs b/pyo3-macros-backend/src/quotes.rs index 47b82605bd1..616ab4b0660 100644 --- a/pyo3-macros-backend/src/quotes.rs +++ b/pyo3-macros-backend/src/quotes.rs @@ -1,6 +1,6 @@ use crate::utils::Ctx; use proc_macro2::TokenStream; -use quote::{quote, quote_spanned}; +use quote::quote; pub(crate) fn some_wrap(obj: TokenStream, ctx: &Ctx) -> TokenStream { let Ctx { pyo3_path, .. } = ctx; @@ -15,7 +15,7 @@ pub(crate) fn ok_wrap(obj: TokenStream, ctx: &Ctx) -> TokenStream { output_span, } = ctx; let pyo3_path = pyo3_path.to_tokens_spanned(*output_span); - quote_spanned! { *output_span => { + quote_at_location! { *output_span => { let obj = #obj; #pyo3_path::impl_::wrap::converter(&obj).wrap(obj).map_err(::core::convert::Into::<#pyo3_path::PyErr>::into) }} @@ -28,7 +28,7 @@ pub(crate) fn map_result_into_ptr(result: TokenStream, ctx: &Ctx) -> TokenStream } = ctx; let pyo3_path = pyo3_path.to_tokens_spanned(*output_span); let py = syn::Ident::new("py", proc_macro2::Span::call_site()); - quote_spanned! { *output_span => { + quote_at_location! { *output_span => { let result = #result; #pyo3_path::impl_::wrap::converter(&result).map_into_ptr(#py, result) }} diff --git a/pyo3-macros-backend/src/utils.rs b/pyo3-macros-backend/src/utils.rs index 191ee165bbc..90c0d283aff 100644 --- a/pyo3-macros-backend/src/utils.rs +++ b/pyo3-macros-backend/src/utils.rs @@ -42,6 +42,12 @@ macro_rules! ensure_spanned { }; } +macro_rules! quote_at_location { + ($span:expr => $($tokens:tt)*) => { + quote::quote_spanned!(proc_macro2::Span::call_site().located_at($span) => $($tokens)*) + }; +} + /// Check if the given type `ty` is `pyo3::Python`. pub fn is_python(ty: &syn::Type) -> bool { match unwrap_ty_group(ty) { @@ -101,7 +107,7 @@ impl quote::ToTokens for LitCStr { } else { let pyo3_path = &self.pyo3_path; let lit = self.lit.to_str().unwrap(); - tokens.extend(quote::quote_spanned!(self.span => #pyo3_path::ffi::c_str!(#lit))); + tokens.extend(quote_at_location!(self.span => #pyo3_path::ffi::c_str!(#lit))); } } } @@ -258,8 +264,8 @@ pub enum PyO3CratePath { impl PyO3CratePath { pub fn to_tokens_spanned(&self, span: Span) -> TokenStream { match self { - Self::Given(path) => quote::quote_spanned! { span => #path }, - Self::Default => quote::quote_spanned! { span => ::pyo3 }, + Self::Given(path) => quote_at_location! { span => #path }, + Self::Default => quote_at_location! { span => ::pyo3 }, } } } diff --git a/tests/ui/deprecations.stderr b/tests/ui/deprecations.stderr index 567f5697c7f..36f083241d3 100644 --- a/tests/ui/deprecations.stderr +++ b/tests/ui/deprecations.stderr @@ -3,6 +3,8 @@ error: use of deprecated constant `__pyfunction_pyfunction_option_2::SIGNATURE`: = help: add `#[pyo3(signature = (_i, _any=None))]` to this function to silence this warning and keep the current behavior --> tests/ui/deprecations.rs:15:4 | +14 | #[pyfunction] + | ------------- in this procedural macro expansion 15 | fn pyfunction_option_2(_i: u32, _any: Option) {} | ^^^^^^^^^^^^^^^^^^^ | @@ -11,22 +13,31 @@ note: the lint level is defined here | 1 | #![deny(deprecated)] | ^^^^^^^^^^ + = note: this error originates in the attribute macro `pyfunction` (in Nightly builds, run with -Z macro-backtrace for more info) error: use of deprecated constant `__pyfunction_pyfunction_option_3::SIGNATURE`: this function has implicit defaults for the trailing `Option` arguments = note: these implicit defaults are being phased out = help: add `#[pyo3(signature = (_i, _any=None, _foo=None))]` to this function to silence this warning and keep the current behavior --> tests/ui/deprecations.rs:18:4 | +17 | #[pyfunction] + | ------------- in this procedural macro expansion 18 | fn pyfunction_option_3(_i: u32, _any: Option, _foo: Option) {} | ^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the attribute macro `pyfunction` (in Nightly builds, run with -Z macro-backtrace for more info) error: use of deprecated constant `__pyfunction_pyfunction_option_4::SIGNATURE`: this function has implicit defaults for the trailing `Option` arguments = note: these implicit defaults are being phased out = help: add `#[pyo3(signature = (_i, _any=None, _foo=None))]` to this function to silence this warning and keep the current behavior --> tests/ui/deprecations.rs:21:4 | +20 | #[pyfunction] + | ------------- in this procedural macro expansion 21 | fn pyfunction_option_4( | ^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the attribute macro `pyfunction` (in Nightly builds, run with -Z macro-backtrace for more info) error: use of deprecated constant `SimpleEnumWithoutEq::__pyo3__generated____richcmp__::DEPRECATION`: Implicit equality for simple enums is deprecated. Use `#[pyclass(eq, eq_int)]` to keep the current behavior. --> tests/ui/deprecations.rs:28:1 diff --git a/tests/ui/invalid_cancel_handle.stderr b/tests/ui/invalid_cancel_handle.stderr index bd2b588df32..1cd08aed00b 100644 --- a/tests/ui/invalid_cancel_handle.stderr +++ b/tests/ui/invalid_cancel_handle.stderr @@ -41,6 +41,8 @@ note: function defined here error[E0277]: the trait bound `CancelHandle: PyFunctionArgument<'_, '_>` is not satisfied --> tests/ui/invalid_cancel_handle.rs:20:50 | +19 | #[pyfunction] + | ------------- in this procedural macro expansion 20 | async fn missing_cancel_handle_attribute(_param: pyo3::coroutine::CancelHandle) {} | ^^^^ the trait `PyClass` is not implemented for `CancelHandle`, which is required by `CancelHandle: PyFunctionArgument<'_, '_>` | @@ -56,10 +58,13 @@ note: required by a bound in `extract_argument` ... | T: PyFunctionArgument<'a, 'py>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `extract_argument` + = note: this error originates in the attribute macro `pyfunction` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `CancelHandle: PyFunctionArgument<'_, '_>` is not satisfied --> tests/ui/invalid_cancel_handle.rs:20:50 | +19 | #[pyfunction] + | ------------- in this procedural macro expansion 20 | async fn missing_cancel_handle_attribute(_param: pyo3::coroutine::CancelHandle) {} | ^^^^ the trait `Clone` is not implemented for `CancelHandle`, which is required by `CancelHandle: PyFunctionArgument<'_, '_>` | @@ -79,3 +84,4 @@ note: required by a bound in `extract_argument` ... | T: PyFunctionArgument<'a, 'py>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `extract_argument` + = note: this error originates in the attribute macro `pyfunction` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/invalid_frozen_pyclass_borrow.stderr b/tests/ui/invalid_frozen_pyclass_borrow.stderr index 52a0623f282..07809e0ef86 100644 --- a/tests/ui/invalid_frozen_pyclass_borrow.stderr +++ b/tests/ui/invalid_frozen_pyclass_borrow.stderr @@ -7,6 +7,9 @@ error: cannot use `#[pyo3(set)]` on a `frozen` class error[E0271]: type mismatch resolving `::Frozen == False` --> tests/ui/invalid_frozen_pyclass_borrow.rs:11:19 | +9 | #[pymethods] + | ------------ in this procedural macro expansion +10 | impl Foo { 11 | fn mut_method(&mut self) {} | ^ expected `False`, found `True` | @@ -15,6 +18,7 @@ note: required by a bound in `extract_pyclass_ref_mut` | | pub fn extract_pyclass_ref_mut<'a, 'py: 'a, T: PyClass>( | ^^^^^^^^^^^^^^ required by this bound in `extract_pyclass_ref_mut` + = note: this error originates in the attribute macro `pymethods` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0271]: type mismatch resolving `::Frozen == False` --> tests/ui/invalid_frozen_pyclass_borrow.rs:9:1 diff --git a/tests/ui/invalid_property_args.stderr b/tests/ui/invalid_property_args.stderr index 03f3ba963d8..81a736bb7db 100644 --- a/tests/ui/invalid_property_args.stderr +++ b/tests/ui/invalid_property_args.stderr @@ -49,6 +49,9 @@ error: `name` is useless without `get` or `set` error[E0277]: `PhantomData` cannot be converted to a Python object --> tests/ui/invalid_property_args.rs:45:12 | +42 | #[pyclass] + | ---------- in this procedural macro expansion +... 45 | value: ::std::marker::PhantomData, | ^ required by `#[pyo3(get)]` to create a readable property from a field of type `PhantomData` | @@ -73,3 +76,4 @@ note: required by a bound in `PyClassGetterGenerator:: FieldT: PyO3GetField<'py>, | ^^^^^^^^^^^^^^^^^ required by this bound in `PyClassGetterGenerator::::generate` + = note: this error originates in the attribute macro `pyclass` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/invalid_pyclass_args.stderr b/tests/ui/invalid_pyclass_args.stderr index 15aa0387cc6..2e197cf58c1 100644 --- a/tests/ui/invalid_pyclass_args.stderr +++ b/tests/ui/invalid_pyclass_args.stderr @@ -206,6 +206,7 @@ note: an implementation of `PartialEq` might be missing for `EqOptRequiresEq` | 35 | struct EqOptRequiresEq {} | ^^^^^^^^^^^^^^^^^^^^^^ must implement `PartialEq` + = note: this error originates in the attribute macro `pyclass` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `EqOptRequiresEq` with `#[derive(PartialEq)]` | 35 + #[derive(PartialEq)] @@ -223,6 +224,7 @@ note: an implementation of `PartialEq` might be missing for `EqOptRequiresEq` | 35 | struct EqOptRequiresEq {} | ^^^^^^^^^^^^^^^^^^^^^^ must implement `PartialEq` + = note: this error originates in the attribute macro `pyclass` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `EqOptRequiresEq` with `#[derive(PartialEq)]` | 35 + #[derive(PartialEq)] diff --git a/tests/ui/invalid_pyclass_enum.stderr b/tests/ui/invalid_pyclass_enum.stderr index 80dc9539748..5ba60dfaad9 100644 --- a/tests/ui/invalid_pyclass_enum.stderr +++ b/tests/ui/invalid_pyclass_enum.stderr @@ -69,8 +69,13 @@ error: The `ord` option requires the `eq` option. error: #[pyclass] can't be used on enums without any variants - all variants of enum `AllEnumVariantsDisabled` have been configured out by cfg attributes --> tests/ui/invalid_pyclass_enum.rs:98:6 | +96 | #[pyclass(eq)] + | -------------- in this procedural macro expansion +97 | #[derive(PartialEq)] 98 | enum AllEnumVariantsDisabled { | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the attribute macro `pyclass` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0369]: binary operation `==` cannot be applied to type `&SimpleEqOptRequiresPartialEq` --> tests/ui/invalid_pyclass_enum.rs:31:11 @@ -83,6 +88,7 @@ note: an implementation of `PartialEq` might be missing for `SimpleEqOptRequires | 32 | enum SimpleEqOptRequiresPartialEq { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ must implement `PartialEq` + = note: this error originates in the attribute macro `pyclass` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `SimpleEqOptRequiresPartialEq` with `#[derive(PartialEq)]` | 32 + #[derive(PartialEq)] @@ -100,6 +106,7 @@ note: an implementation of `PartialEq` might be missing for `SimpleEqOptRequires | 32 | enum SimpleEqOptRequiresPartialEq { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ must implement `PartialEq` + = note: this error originates in the attribute macro `pyclass` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `SimpleEqOptRequiresPartialEq` with `#[derive(PartialEq)]` | 32 + #[derive(PartialEq)] @@ -117,6 +124,7 @@ note: an implementation of `PartialEq` might be missing for `ComplexEqOptRequire | 38 | enum ComplexEqOptRequiresPartialEq { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ must implement `PartialEq` + = note: this error originates in the attribute macro `pyclass` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `ComplexEqOptRequiresPartialEq` with `#[derive(PartialEq)]` | 38 + #[derive(PartialEq)] @@ -134,6 +142,7 @@ note: an implementation of `PartialEq` might be missing for `ComplexEqOptRequire | 38 | enum ComplexEqOptRequiresPartialEq { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ must implement `PartialEq` + = note: this error originates in the attribute macro `pyclass` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `ComplexEqOptRequiresPartialEq` with `#[derive(PartialEq)]` | 38 + #[derive(PartialEq)] @@ -175,6 +184,7 @@ note: an implementation of `PartialOrd` might be missing for `InvalidOrderedComp | 91 | enum InvalidOrderedComplexEnum2 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ must implement `PartialOrd` + = note: this error originates in the attribute macro `pyclass` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `InvalidOrderedComplexEnum2` with `#[derive(PartialEq, PartialOrd)]` | 91 + #[derive(PartialEq, PartialOrd)] @@ -192,6 +202,7 @@ note: an implementation of `PartialOrd` might be missing for `InvalidOrderedComp | 91 | enum InvalidOrderedComplexEnum2 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ must implement `PartialOrd` + = note: this error originates in the attribute macro `pyclass` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `InvalidOrderedComplexEnum2` with `#[derive(PartialEq, PartialOrd)]` | 91 + #[derive(PartialEq, PartialOrd)] @@ -209,6 +220,7 @@ note: an implementation of `PartialOrd` might be missing for `InvalidOrderedComp | 91 | enum InvalidOrderedComplexEnum2 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ must implement `PartialOrd` + = note: this error originates in the attribute macro `pyclass` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `InvalidOrderedComplexEnum2` with `#[derive(PartialEq, PartialOrd)]` | 91 + #[derive(PartialEq, PartialOrd)] @@ -226,6 +238,7 @@ note: an implementation of `PartialOrd` might be missing for `InvalidOrderedComp | 91 | enum InvalidOrderedComplexEnum2 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ must implement `PartialOrd` + = note: this error originates in the attribute macro `pyclass` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `InvalidOrderedComplexEnum2` with `#[derive(PartialEq, PartialOrd)]` | 91 + #[derive(PartialEq, PartialOrd)] diff --git a/tests/ui/invalid_pyfunctions.stderr b/tests/ui/invalid_pyfunctions.stderr index ab35b086b94..9cb8e290364 100644 --- a/tests/ui/invalid_pyfunctions.stderr +++ b/tests/ui/invalid_pyfunctions.stderr @@ -50,6 +50,9 @@ error: expected `&PyModule` or `Py` as first argument with `pass_modul error[E0277]: the trait bound `&str: From>` is not satisfied --> tests/ui/invalid_pyfunctions.rs:36:14 | +34 | #[pyfunction(pass_module)] + | -------------------------- in this procedural macro expansion +35 | fn first_argument_not_module<'a, 'py>( 36 | _string: &str, | ^ the trait `From>` is not implemented for `&str`, which is required by `BoundRef<'_, '_, pyo3::types::PyModule>: Into<_>` | @@ -61,3 +64,4 @@ error[E0277]: the trait bound `&str: From>` `String` implements `From` = note: required for `BoundRef<'_, '_, pyo3::types::PyModule>` to implement `Into<&str>` + = note: this error originates in the attribute macro `pyfunction` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/invalid_pymethod_enum.stderr b/tests/ui/invalid_pymethod_enum.stderr index bc377d2a055..cc5a8f16dd9 100644 --- a/tests/ui/invalid_pymethod_enum.stderr +++ b/tests/ui/invalid_pymethod_enum.stderr @@ -1,6 +1,9 @@ error[E0271]: type mismatch resolving `::Frozen == False` --> tests/ui/invalid_pymethod_enum.rs:11:24 | +9 | #[pymethods] + | ------------ in this procedural macro expansion +10 | impl ComplexEnum { 11 | fn mutate_in_place(&mut self) { | ^ expected `False`, found `True` | @@ -9,6 +12,7 @@ note: required by a bound in `extract_pyclass_ref_mut` | | pub fn extract_pyclass_ref_mut<'a, 'py: 'a, T: PyClass>( | ^^^^^^^^^^^^^^ required by this bound in `extract_pyclass_ref_mut` + = note: this error originates in the attribute macro `pymethods` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0271]: type mismatch resolving `::Frozen == False` --> tests/ui/invalid_pymethod_enum.rs:9:1 @@ -26,6 +30,9 @@ note: required by a bound in `PyRefMut` error[E0271]: type mismatch resolving `::Frozen == False` --> tests/ui/invalid_pymethod_enum.rs:27:24 | +25 | #[pymethods] + | ------------ in this procedural macro expansion +26 | impl TupleEnum { 27 | fn mutate_in_place(&mut self) { | ^ expected `False`, found `True` | @@ -34,6 +41,7 @@ note: required by a bound in `extract_pyclass_ref_mut` | | pub fn extract_pyclass_ref_mut<'a, 'py: 'a, T: PyClass>( | ^^^^^^^^^^^^^^ required by this bound in `extract_pyclass_ref_mut` + = note: this error originates in the attribute macro `pymethods` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0271]: type mismatch resolving `::Frozen == False` --> tests/ui/invalid_pymethod_enum.rs:25:1 diff --git a/tests/ui/invalid_pymethod_receiver.stderr b/tests/ui/invalid_pymethod_receiver.stderr index 9c998403194..08bd4a819a6 100644 --- a/tests/ui/invalid_pymethod_receiver.stderr +++ b/tests/ui/invalid_pymethod_receiver.stderr @@ -1,6 +1,9 @@ error[E0277]: the trait bound `i32: TryFrom>` is not satisfied --> tests/ui/invalid_pymethod_receiver.rs:8:44 | +6 | #[pymethods] + | ------------ in this procedural macro expansion +7 | impl MyClass { 8 | fn method_with_invalid_self_type(_slf: i32, _py: Python<'_>, _index: u32) {} | ^^^ the trait `From>` is not implemented for `i32`, which is required by `i32: TryFrom>` | @@ -12,3 +15,4 @@ error[E0277]: the trait bound `i32: TryFrom>` is not s `i32` implements `From` = note: required for `BoundRef<'_, '_, MyClass>` to implement `Into` = note: required for `i32` to implement `TryFrom>` + = note: this error originates in the attribute macro `pymethods` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/invalid_pymethods.stderr b/tests/ui/invalid_pymethods.stderr index 845b79ed59a..aafb45b5168 100644 --- a/tests/ui/invalid_pymethods.stderr +++ b/tests/ui/invalid_pymethods.stderr @@ -182,6 +182,9 @@ error: macros cannot be used as items in `#[pymethods]` impl blocks error[E0277]: the trait bound `i32: From>` is not satisfied --> tests/ui/invalid_pymethods.rs:46:45 | +43 | #[pymethods] + | ------------ in this procedural macro expansion +... 46 | fn classmethod_wrong_first_argument(_x: i32) -> Self { | ^^^ the trait `From>` is not implemented for `i32`, which is required by `BoundRef<'_, '_, PyType>: Into<_>` | @@ -192,3 +195,4 @@ error[E0277]: the trait bound `i32: From>` is not satis `i32` implements `From` `i32` implements `From` = note: required for `BoundRef<'_, '_, PyType>` to implement `Into` + = note: this error originates in the attribute macro `pymethods` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/invalid_result_conversion.stderr b/tests/ui/invalid_result_conversion.stderr index 18667138954..040ede84095 100644 --- a/tests/ui/invalid_result_conversion.stderr +++ b/tests/ui/invalid_result_conversion.stderr @@ -1,6 +1,8 @@ error[E0277]: the trait bound `PyErr: From` is not satisfied --> tests/ui/invalid_result_conversion.rs:22:25 | +21 | #[pyfunction] + | ------------- in this procedural macro expansion 22 | fn should_not_work() -> Result<(), MyError> { | ^^^^^^ the trait `From` is not implemented for `PyErr`, which is required by `MyError: Into` | @@ -15,3 +17,4 @@ error[E0277]: the trait bound `PyErr: From` is not satisfied `PyErr` implements `From>` and $N others = note: required for `MyError` to implement `Into` + = note: this error originates in the attribute macro `pyfunction` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/missing_intopy.stderr b/tests/ui/missing_intopy.stderr index 587ebd479de..cedf73c384e 100644 --- a/tests/ui/missing_intopy.stderr +++ b/tests/ui/missing_intopy.stderr @@ -1,6 +1,8 @@ error[E0277]: `Blah` cannot be converted to a Python object --> tests/ui/missing_intopy.rs:4:14 | +3 | #[pyo3::pyfunction] + | ------------------- in this procedural macro expansion 4 | fn blah() -> Blah { | ^^^^ the trait `IntoPyObject<'_>` is not implemented for `Blah` | @@ -25,12 +27,17 @@ note: required by a bound in `UnknownReturnType::::wrap` | where | T: IntoPyObject<'py>, | ^^^^^^^^^^^^^^^^^ required by this bound in `UnknownReturnType::::wrap` + = note: this error originates in the attribute macro `pyo3::pyfunction` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0599]: no method named `map_err` found for struct `Blah` in the current scope --> tests/ui/missing_intopy.rs:4:14 | 1 | struct Blah; | ----------- method `map_err` not found for this struct -... +2 | +3 | #[pyo3::pyfunction] + | ------------------- in this procedural macro expansion 4 | fn blah() -> Blah { | ^^^^ method not found in `Blah` + | + = note: this error originates in the attribute macro `pyo3::pyfunction` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/static_ref.stderr b/tests/ui/static_ref.stderr index 77c3646745e..469e729332c 100644 --- a/tests/ui/static_ref.stderr +++ b/tests/ui/static_ref.stderr @@ -22,18 +22,20 @@ error[E0597]: `output[_]` does not live long enough = note: this error originates in the attribute macro `pyfunction` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0597]: `holder_0` does not live long enough - --> tests/ui/static_ref.rs:5:15 + --> tests/ui/static_ref.rs:5:21 | 4 | #[pyfunction] | ------------- | | | | | `holder_0` dropped here while still borrowed - | binding `holder_0` declared here + | in this procedural macro expansion 5 | fn static_ref(list: &'static Bound<'_, PyList>) -> usize { - | ^^^^^^- - | | | - | | argument requires that `holder_0` is borrowed for `'static` - | borrowed value does not live long enough + | ^ + | | + | borrowed value does not live long enough + | argument requires that `holder_0` is borrowed for `'static` + | + = note: this error originates in the attribute macro `pyfunction` (in Nightly builds, run with -Z macro-backtrace for more info) error: lifetime may not live long enough --> tests/ui/static_ref.rs:9:1 From ed41e48379171101f83e4646c50f88259e379ed8 Mon Sep 17 00:00:00 2001 From: David Hewitt Date: Tue, 29 Oct 2024 08:30:18 +0000 Subject: [PATCH 2/2] add forbid for `unsafe_of_in_unsafe_fn` --- tests/ui/forbid_unsafe.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/forbid_unsafe.rs b/tests/ui/forbid_unsafe.rs index 9b62886b650..88e1b43eb0d 100644 --- a/tests/ui/forbid_unsafe.rs +++ b/tests/ui/forbid_unsafe.rs @@ -1,4 +1,4 @@ -#![forbid(unsafe_code)] +#![forbid(unsafe_code, unsafe_op_in_unsafe_fn)] use pyo3::*;