diff --git a/Cargo.lock b/Cargo.lock index 5ea45d147..d7ea3627e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -441,7 +441,6 @@ dependencies = [ name = "der_derive" version = "0.7.1" dependencies = [ - "proc-macro-error", "proc-macro2", "quote", "syn 2.0.25", @@ -1079,30 +1078,6 @@ dependencies = [ "elliptic-curve", ] -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - [[package]] name = "proc-macro2" version = "1.0.64" diff --git a/der/derive/Cargo.toml b/der/derive/Cargo.toml index de221f78a..196e0d5d8 100644 --- a/der/derive/Cargo.toml +++ b/der/derive/Cargo.toml @@ -17,6 +17,5 @@ proc-macro = true [dependencies] proc-macro2 = "1" -proc-macro-error = "1" quote = "1" syn = { version = "2", features = ["extra-traits"] } diff --git a/der/derive/src/attributes.rs b/der/derive/src/attributes.rs index 2a50d431a..fa050cbcb 100644 --- a/der/derive/src/attributes.rs +++ b/der/derive/src/attributes.rs @@ -1,8 +1,7 @@ //! Attribute-related types used by the proc macro use crate::{Asn1Type, Tag, TagMode, TagNumber}; -use proc_macro2::TokenStream; -use proc_macro_error::{abort, abort_call_site}; +use proc_macro2::{Span, TokenStream}; use quote::quote; use std::{fmt::Debug, str::FromStr}; use syn::punctuated::Punctuated; @@ -23,31 +22,34 @@ pub(crate) struct TypeAttrs { impl TypeAttrs { /// Parse attributes from a struct field or enum variant. - pub fn parse(attrs: &[Attribute]) -> Self { + pub fn parse(attrs: &[Attribute]) -> syn::Result { let mut tag_mode = None; let mut parsed_attrs = Vec::new(); - AttrNameValue::from_attributes(attrs, &mut parsed_attrs); + AttrNameValue::from_attributes(attrs, &mut parsed_attrs)?; for attr in parsed_attrs { // `tag_mode = "..."` attribute - if let Some(mode) = attr.parse_value("tag_mode") { - if tag_mode.is_some() { - abort!(attr.name, "duplicate ASN.1 `tag_mode` attribute"); - } - - tag_mode = Some(mode); - } else { - abort!( - attr.name, + let mode = attr.parse_value("tag_mode")?.ok_or_else(|| { + syn::Error::new_spanned( + &attr.name, "invalid `asn1` attribute (valid options are `tag_mode`)", - ); + ) + })?; + + if tag_mode.is_some() { + return Err(syn::Error::new_spanned( + &attr.name, + "duplicate ASN.1 `tag_mode` attribute", + )); } + + tag_mode = Some(mode); } - Self { + Ok(Self { tag_mode: tag_mode.unwrap_or_default(), - } + }) } } @@ -90,7 +92,7 @@ impl FieldAttrs { } /// Parse attributes from a struct field or enum variant. - pub fn parse(attrs: &[Attribute], type_attrs: &TypeAttrs) -> Self { + pub fn parse(attrs: &[Attribute], type_attrs: &TypeAttrs) -> syn::Result { let mut asn1_type = None; let mut context_specific = None; let mut default = None; @@ -100,57 +102,60 @@ impl FieldAttrs { let mut constructed = None; let mut parsed_attrs = Vec::new(); - AttrNameValue::from_attributes(attrs, &mut parsed_attrs); + AttrNameValue::from_attributes(attrs, &mut parsed_attrs)?; for attr in parsed_attrs { // `context_specific = "..."` attribute - if let Some(tag_number) = attr.parse_value("context_specific") { + if let Some(tag_number) = attr.parse_value("context_specific")? { if context_specific.is_some() { abort!(attr.name, "duplicate ASN.1 `context_specific` attribute"); } context_specific = Some(tag_number); // `default` attribute - } else if attr.parse_value::("default").is_some() { + } else if attr.parse_value::("default")?.is_some() { if default.is_some() { abort!(attr.name, "duplicate ASN.1 `default` attribute"); } - default = Some(attr.value.parse().unwrap_or_else(|e| { - abort!(attr.value, "error parsing ASN.1 `default` attribute: {}", e) - })); + default = Some(attr.value.parse().map_err(|e| { + syn::Error::new_spanned( + attr.value, + format_args!("error parsing ASN.1 `default` attribute: {e}"), + ) + })?); // `extensible` attribute - } else if let Some(ext) = attr.parse_value("extensible") { + } else if let Some(ext) = attr.parse_value("extensible")? { if extensible.is_some() { abort!(attr.name, "duplicate ASN.1 `extensible` attribute"); } extensible = Some(ext); // `optional` attribute - } else if let Some(opt) = attr.parse_value("optional") { + } else if let Some(opt) = attr.parse_value("optional")? { if optional.is_some() { abort!(attr.name, "duplicate ASN.1 `optional` attribute"); } optional = Some(opt); // `tag_mode` attribute - } else if let Some(mode) = attr.parse_value("tag_mode") { + } else if let Some(mode) = attr.parse_value("tag_mode")? { if tag_mode.is_some() { abort!(attr.name, "duplicate ASN.1 `tag_mode` attribute"); } tag_mode = Some(mode); // `type = "..."` attribute - } else if let Some(ty) = attr.parse_value("type") { + } else if let Some(ty) = attr.parse_value("type")? { if asn1_type.is_some() { - abort!(attr.name, "duplicate ASN.1 `type` attribute: {}"); + abort!(attr.name, "duplicate ASN.1 `type` attribute"); } asn1_type = Some(ty); // `constructed = "..."` attribute - } else if let Some(ty) = attr.parse_value("constructed") { + } else if let Some(ty) = attr.parse_value("constructed")? { if constructed.is_some() { - abort!(attr.name, "duplicate ASN.1 `constructed` attribute: {}"); + abort!(attr.name, "duplicate ASN.1 `constructed` attribute"); } constructed = Some(ty); @@ -163,7 +168,7 @@ impl FieldAttrs { } } - Self { + Ok(Self { asn1_type, context_specific, default, @@ -171,20 +176,23 @@ impl FieldAttrs { optional: optional.unwrap_or_default(), tag_mode: tag_mode.unwrap_or(type_attrs.tag_mode), constructed: constructed.unwrap_or_default(), - } + }) } /// Get the expected [`Tag`] for this field. - pub fn tag(&self) -> Option { + pub fn tag(&self) -> syn::Result> { match self.context_specific { - Some(tag_number) => Some(Tag::ContextSpecific { + Some(tag_number) => Ok(Some(Tag::ContextSpecific { constructed: self.constructed, number: tag_number, - }), + })), None => match self.tag_mode { - TagMode::Explicit => self.asn1_type.map(Tag::Universal), - TagMode::Implicit => abort_call_site!("implicit tagging requires a `tag_number`"), + TagMode::Explicit => Ok(self.asn1_type.map(Tag::Universal)), + TagMode::Implicit => Err(syn::Error::new( + Span::call_site(), + "implicit tagging requires a `tag_number`", + )), }, } } @@ -319,7 +327,7 @@ impl AttrNameValue { } /// Parse a slice of attributes. - pub fn from_attributes(attrs: &[Attribute], out: &mut Vec) { + pub fn from_attributes(attrs: &[Attribute], out: &mut Vec) -> syn::Result<()> { for attr in attrs { if !attr.path().is_ident(ATTR_NAME) { continue; @@ -327,26 +335,28 @@ impl AttrNameValue { match Self::parse_attribute(attr) { Ok(parsed) => out.extend(parsed), - Err(e) => abort!(attr, "{}", e), - }; + Err(e) => abort!(attr, e), + } } + + Ok(()) } /// Parse an attribute value if the name matches the specified one. - pub fn parse_value(&self, name: &str) -> Option + pub fn parse_value(&self, name: &str) -> syn::Result> where T: FromStr + Debug, T::Err: Debug, { - if self.name.is_ident(name) { + Ok(if self.name.is_ident(name) { Some( self.value .value() .parse() - .unwrap_or_else(|_| abort!(self.name, "error parsing attribute")), + .map_err(|_| syn::Error::new_spanned(&self.name, "error parsing attribute"))?, ) } else { None - } + }) } } diff --git a/der/derive/src/choice.rs b/der/derive/src/choice.rs index d0aa6a24a..22ab5ea1d 100644 --- a/der/derive/src/choice.rs +++ b/der/derive/src/choice.rs @@ -7,7 +7,6 @@ mod variant; use self::variant::ChoiceVariant; use crate::{default_lifetime, TypeAttrs}; use proc_macro2::TokenStream; -use proc_macro_error::abort; use quote::quote; use syn::{DeriveInput, Ident, Lifetime}; @@ -25,7 +24,7 @@ pub(crate) struct DeriveChoice { impl DeriveChoice { /// Parse [`DeriveInput`]. - pub fn new(input: DeriveInput) -> Self { + pub fn new(input: DeriveInput) -> syn::Result { let data = match input.data { syn::Data::Enum(data) => data, _ => abort!( @@ -41,18 +40,18 @@ impl DeriveChoice { .next() .map(|lt| lt.lifetime.clone()); - let type_attrs = TypeAttrs::parse(&input.attrs); + let type_attrs = TypeAttrs::parse(&input.attrs)?; let variants = data .variants .iter() .map(|variant| ChoiceVariant::new(variant, &type_attrs)) - .collect(); + .collect::>()?; - Self { + Ok(Self { ident: input.ident, lifetime, variants, - } + }) } /// Lower the derived output into a [`TokenStream`]. @@ -161,7 +160,7 @@ mod tests { } }; - let ir = DeriveChoice::new(input); + let ir = DeriveChoice::new(input).unwrap(); assert_eq!(ir.ident, "Time"); assert_eq!(ir.lifetime, None); assert_eq!(ir.variants.len(), 2); @@ -201,7 +200,7 @@ mod tests { } }; - let ir = DeriveChoice::new(input); + let ir = DeriveChoice::new(input).unwrap(); assert_eq!(ir.ident, "ImplicitChoice"); assert_eq!(ir.lifetime.unwrap().to_string(), "'a"); assert_eq!(ir.variants.len(), 3); diff --git a/der/derive/src/choice/variant.rs b/der/derive/src/choice/variant.rs index d74be6125..c11ecbf36 100644 --- a/der/derive/src/choice/variant.rs +++ b/der/derive/src/choice/variant.rs @@ -2,7 +2,6 @@ use crate::{FieldAttrs, Tag, TypeAttrs}; use proc_macro2::TokenStream; -use proc_macro_error::abort; use quote::quote; use syn::{Fields, Ident, Path, Type, Variant}; @@ -33,20 +32,22 @@ impl From for TagOrPath { } } -impl From<&Variant> for TagOrPath { - fn from(input: &Variant) -> Self { +impl TryFrom<&Variant> for TagOrPath { + type Error = syn::Error; + + fn try_from(input: &Variant) -> syn::Result { if let Fields::Unnamed(fields) = &input.fields { if fields.unnamed.len() == 1 { if let Type::Path(path) = &fields.unnamed[0].ty { - return path.path.clone().into(); + return Ok(path.path.clone().into()); } } } - abort!( + Err(syn::Error::new_spanned( &input.ident, - "no #[asn1(type=...)] specified for enum variant" - ) + "no #[asn1(type=...)] specified for enum variant", + )) } } @@ -73,9 +74,9 @@ pub(super) struct ChoiceVariant { impl ChoiceVariant { /// Create a new [`ChoiceVariant`] from the input [`Variant`]. - pub(super) fn new(input: &Variant, type_attrs: &TypeAttrs) -> Self { + pub(super) fn new(input: &Variant, type_attrs: &TypeAttrs) -> syn::Result { let ident = input.ident.clone(); - let attrs = FieldAttrs::parse(&input.attrs, type_attrs); + let attrs = FieldAttrs::parse(&input.attrs, type_attrs)?; if attrs.extensible { abort!(&ident, "`extensible` is not allowed on CHOICE"); @@ -88,12 +89,12 @@ impl ChoiceVariant { _ => abort!(&ident, "enum variant must be a 1-element tuple struct"), } - let tag = attrs - .tag() - .map(TagOrPath::from) - .unwrap_or_else(|| TagOrPath::from(input)); + let tag = match attrs.tag()? { + Some(x) => x.into(), + None => input.try_into()?, + }; - Self { ident, attrs, tag } + Ok(Self { ident, attrs, tag }) } /// Derive a match arm of the impl body for `TryFrom>`. diff --git a/der/derive/src/enumerated.rs b/der/derive/src/enumerated.rs index 023ccc523..6bdd5fff8 100644 --- a/der/derive/src/enumerated.rs +++ b/der/derive/src/enumerated.rs @@ -5,7 +5,6 @@ use crate::attributes::AttrNameValue; use crate::{default_lifetime, ATTR_NAME}; use proc_macro2::TokenStream; -use proc_macro_error::abort; use quote::quote; use syn::{DeriveInput, Expr, ExprLit, Ident, Lit, LitInt, Variant}; @@ -29,7 +28,7 @@ pub(crate) struct DeriveEnumerated { impl DeriveEnumerated { /// Parse [`DeriveInput`]. - pub fn new(input: DeriveInput) -> Self { + pub fn new(input: DeriveInput) -> syn::Result { let data = match input.data { syn::Data::Enum(data) => data, _ => abort!( @@ -46,14 +45,14 @@ impl DeriveEnumerated { if attr.path().is_ident(ATTR_NAME) { let kvs = match AttrNameValue::parse_attribute(attr) { Ok(kvs) => kvs, - Err(e) => abort!(attr, "{}", e), + Err(e) => abort!(attr, e), }; for anv in kvs { if anv.name.is_ident("type") { match anv.value.value().as_str() { "ENUMERATED" => integer = false, "INTEGER" => integer = true, - s => abort!(anv.value, "`type = \"{}\"` is unsupported", s), + s => abort!(anv.value, format_args!("`type = \"{s}\"` is unsupported")), } } } @@ -65,16 +64,15 @@ impl DeriveEnumerated { ); } - let r = attr - .parse_args::() - .unwrap_or_else(|_| abort!(attr, "error parsing `#[repr]` attribute")); + let r = attr.parse_args::().map_err(|_| { + syn::Error::new_spanned(attr, "error parsing `#[repr]` attribute") + })?; // Validate if !REPR_TYPES.contains(&r.to_string().as_str()) { abort!( attr, - "invalid `#[repr]` type: allowed types are {:?}", - REPR_TYPES + format_args!("invalid `#[repr]` type: allowed types are {REPR_TYPES:?}"), ); } @@ -83,20 +81,23 @@ impl DeriveEnumerated { } // Parse enum variants - let variants = data.variants.iter().map(EnumeratedVariant::new).collect(); + let variants = data + .variants + .iter() + .map(EnumeratedVariant::new) + .collect::>()?; - Self { + Ok(Self { ident: input.ident.clone(), - repr: repr.unwrap_or_else(|| { - abort!( + repr: repr.ok_or_else(|| { + syn::Error::new_spanned( &input.ident, - "no `#[repr]` attribute on enum: must be one of {:?}", - REPR_TYPES + format_args!("no `#[repr]` attribute on enum: must be one of {REPR_TYPES:?}"), ) - }), + })?, variants, integer, - } + }) } /// Lower the derived output into a [`TokenStream`]. @@ -163,7 +164,7 @@ pub struct EnumeratedVariant { impl EnumeratedVariant { /// Create a new [`ChoiceVariant`] from the input [`Variant`]. - fn new(input: &Variant) -> Self { + fn new(input: &Variant) -> syn::Result { for attr in &input.attrs { if attr.path().is_ident(ATTR_NAME) { abort!( @@ -180,10 +181,10 @@ impl EnumeratedVariant { lit: Lit::Int(discriminant), .. }), - )) => Self { + )) => Ok(Self { ident: input.ident.clone(), discriminant: discriminant.clone(), - }, + }), Some((_, other)) => abort!(other, "invalid discriminant for `Enumerated`"), None => abort!(input, "`Enumerated` variant has no discriminant"), } @@ -223,7 +224,7 @@ mod tests { } }; - let ir = DeriveEnumerated::new(input); + let ir = DeriveEnumerated::new(input).unwrap(); assert_eq!(ir.ident, "CrlReason"); assert_eq!(ir.repr, "u32"); assert_eq!(ir.variants.len(), 10); diff --git a/der/derive/src/lib.rs b/der/derive/src/lib.rs index b46191b7f..87409f21d 100644 --- a/der/derive/src/lib.rs +++ b/der/derive/src/lib.rs @@ -121,6 +121,12 @@ unused_qualifications )] +macro_rules! abort { + ( $tokens:expr, $message:expr $(,)? ) => { + return Err(syn::Error::new_spanned($tokens, $message)) + }; +} + mod asn1_type; mod attributes; mod choice; @@ -140,7 +146,6 @@ use crate::{ }; use proc_macro::TokenStream; use proc_macro2::Span; -use proc_macro_error::proc_macro_error; use syn::{parse_macro_input, DeriveInput, Lifetime}; /// Get the default lifetime. @@ -186,10 +191,12 @@ fn default_lifetime() -> Lifetime { /// [3]: https://docs.rs/der/latest/der/trait.Encode.html /// [4]: https://docs.rs/der_derive/ #[proc_macro_derive(Choice, attributes(asn1))] -#[proc_macro_error] pub fn derive_choice(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); - DeriveChoice::new(input).to_tokens().into() + match DeriveChoice::new(input) { + Ok(t) => t.to_tokens().into(), + Err(e) => e.to_compile_error().into(), + } } /// Derive decoders and encoders for ASN.1 [`Enumerated`] types on a @@ -222,10 +229,12 @@ pub fn derive_choice(input: TokenStream) -> TokenStream { /// Note that the derive macro will write a `TryFrom<...>` impl for the /// provided `#[repr]`, which is used by the decoder. #[proc_macro_derive(Enumerated, attributes(asn1))] -#[proc_macro_error] pub fn derive_enumerated(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); - DeriveEnumerated::new(input).to_tokens().into() + match DeriveEnumerated::new(input) { + Ok(t) => t.to_tokens().into(), + Err(e) => e.to_compile_error().into(), + } } /// Derive the [`Sequence`][1] trait on a `struct`. @@ -262,10 +271,12 @@ pub fn derive_enumerated(input: TokenStream) -> TokenStream { /// [1]: https://docs.rs/der/latest/der/trait.Sequence.html /// [2]: https://docs.rs/der_derive/ #[proc_macro_derive(Sequence, attributes(asn1))] -#[proc_macro_error] pub fn derive_sequence(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); - DeriveSequence::new(input).to_tokens().into() + match DeriveSequence::new(input) { + Ok(t) => t.to_tokens().into(), + Err(e) => e.to_compile_error().into(), + } } /// Derive the [`ValueOrd`][1] trait on a `struct`. @@ -275,8 +286,10 @@ pub fn derive_sequence(input: TokenStream) -> TokenStream { /// /// [1]: https://docs.rs/der/latest/der/trait.ValueOrd.html #[proc_macro_derive(ValueOrd, attributes(asn1))] -#[proc_macro_error] pub fn derive_value_ord(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); - DeriveValueOrd::new(input).to_tokens().into() + match DeriveValueOrd::new(input) { + Ok(t) => t.to_tokens().into(), + Err(e) => e.to_compile_error().into(), + } } diff --git a/der/derive/src/sequence.rs b/der/derive/src/sequence.rs index e99ec8c7b..e4ad9dd23 100644 --- a/der/derive/src/sequence.rs +++ b/der/derive/src/sequence.rs @@ -6,7 +6,6 @@ mod field; use crate::{default_lifetime, TypeAttrs}; use field::SequenceField; use proc_macro2::TokenStream; -use proc_macro_error::abort; use quote::quote; use syn::{DeriveInput, GenericParam, Generics, Ident, LifetimeParam}; @@ -24,7 +23,7 @@ pub(crate) struct DeriveSequence { impl DeriveSequence { /// Parse [`DeriveInput`]. - pub fn new(input: DeriveInput) -> Self { + pub fn new(input: DeriveInput) -> syn::Result { let data = match input.data { syn::Data::Struct(data) => data, _ => abort!( @@ -33,19 +32,19 @@ impl DeriveSequence { ), }; - let type_attrs = TypeAttrs::parse(&input.attrs); + let type_attrs = TypeAttrs::parse(&input.attrs)?; let fields = data .fields .iter() .map(|field| SequenceField::new(field, &type_attrs)) - .collect(); + .collect::>()?; - Self { + Ok(Self { ident: input.ident, generics: input.generics.clone(), fields, - } + }) } /// Lower the derived output into a [`TokenStream`]. @@ -143,7 +142,7 @@ mod tests { } }; - let ir = DeriveSequence::new(input); + let ir = DeriveSequence::new(input).unwrap(); assert_eq!(ir.ident, "AlgorithmIdentifier"); assert_eq!( ir.generics.lifetimes().next().unwrap().lifetime.to_string(), @@ -177,7 +176,7 @@ mod tests { } }; - let ir = DeriveSequence::new(input); + let ir = DeriveSequence::new(input).unwrap(); assert_eq!(ir.ident, "SubjectPublicKeyInfo"); assert_eq!( ir.generics.lifetimes().next().unwrap().lifetime.to_string(), @@ -245,7 +244,7 @@ mod tests { } }; - let ir = DeriveSequence::new(input); + let ir = DeriveSequence::new(input).unwrap(); assert_eq!(ir.ident, "OneAsymmetricKey"); assert_eq!( ir.generics.lifetimes().next().unwrap().lifetime.to_string(), @@ -320,7 +319,7 @@ mod tests { } }; - let ir = DeriveSequence::new(input); + let ir = DeriveSequence::new(input).unwrap(); assert_eq!(ir.ident, "ImplicitSequence"); assert_eq!( ir.generics.lifetimes().next().unwrap().lifetime.to_string(), diff --git a/der/derive/src/sequence/field.rs b/der/derive/src/sequence/field.rs index 05945ddf2..3fb183208 100644 --- a/der/derive/src/sequence/field.rs +++ b/der/derive/src/sequence/field.rs @@ -2,7 +2,6 @@ use crate::{Asn1Type, FieldAttrs, TagMode, TagNumber, TypeAttrs}; use proc_macro2::TokenStream; -use proc_macro_error::abort; use quote::quote; use syn::{Field, Ident, Path, Type}; @@ -20,35 +19,35 @@ pub(super) struct SequenceField { impl SequenceField { /// Create a new [`SequenceField`] from the input [`Field`]. - pub(super) fn new(field: &Field, type_attrs: &TypeAttrs) -> Self { - let ident = field.ident.as_ref().cloned().unwrap_or_else(|| { - abort!( + pub(super) fn new(field: &Field, type_attrs: &TypeAttrs) -> syn::Result { + let ident = field.ident.as_ref().cloned().ok_or_else(|| { + syn::Error::new_spanned( field, - "no name on struct field i.e. tuple structs unsupported" + "no name on struct field i.e. tuple structs unsupported", ) - }); + })?; - let attrs = FieldAttrs::parse(&field.attrs, type_attrs); + let attrs = FieldAttrs::parse(&field.attrs, type_attrs)?; if attrs.asn1_type.is_some() && attrs.default.is_some() { - abort!( + return Err(syn::Error::new_spanned( ident, - "ASN.1 `type` and `default` options cannot be combined" - ); + "ASN.1 `type` and `default` options cannot be combined", + )); } if attrs.default.is_some() && attrs.optional { - abort!( + return Err(syn::Error::new_spanned( ident, - "`optional` and `default` field qualifiers are mutually exclusive" - ); + "`optional` and `default` field qualifiers are mutually exclusive", + )); } - Self { + Ok(Self { ident, attrs, field_type: field.ty.clone(), - } + }) } /// Derive code for decoding a field of a sequence. diff --git a/der/derive/src/value_ord.rs b/der/derive/src/value_ord.rs index 97e37cae5..0ba8ddf72 100644 --- a/der/derive/src/value_ord.rs +++ b/der/derive/src/value_ord.rs @@ -7,7 +7,6 @@ use crate::{FieldAttrs, TypeAttrs}; use proc_macro2::TokenStream; -use proc_macro_error::abort; use quote::quote; use syn::{DeriveInput, Field, Ident, Lifetime, Variant}; @@ -28,9 +27,9 @@ pub(crate) struct DeriveValueOrd { impl DeriveValueOrd { /// Parse [`DeriveInput`]. - pub fn new(input: DeriveInput) -> Self { + pub fn new(input: DeriveInput) -> syn::Result { let ident = input.ident; - let type_attrs = TypeAttrs::parse(&input.attrs); + let type_attrs = TypeAttrs::parse(&input.attrs)?; // TODO(tarcieri): properly handle multiple lifetimes let lifetime = input @@ -44,14 +43,14 @@ impl DeriveValueOrd { data.variants .into_iter() .map(|variant| ValueField::new_enum(variant, &type_attrs)) - .collect(), + .collect::>()?, InputType::Enum, ), syn::Data::Struct(data) => ( data.fields .into_iter() .map(|field| ValueField::new_struct(field, &type_attrs)) - .collect(), + .collect::>()?, InputType::Struct, ), _ => abort!( @@ -61,12 +60,12 @@ impl DeriveValueOrd { ), }; - Self { + Ok(Self { ident, lifetime, fields, input_type, - } + }) } /// Lower the derived output into a [`TokenStream`]. @@ -142,31 +141,30 @@ struct ValueField { impl ValueField { /// Create from an `enum` variant. - fn new_enum(variant: Variant, type_attrs: &TypeAttrs) -> Self { + fn new_enum(variant: Variant, type_attrs: &TypeAttrs) -> syn::Result { let ident = variant.ident; - let attrs = FieldAttrs::parse(&variant.attrs, type_attrs); - Self { + let attrs = FieldAttrs::parse(&variant.attrs, type_attrs)?; + Ok(Self { ident, attrs, is_enum: true, - } + }) } /// Create from a `struct` field. - fn new_struct(field: Field, type_attrs: &TypeAttrs) -> Self { - let ident = field - .ident - .as_ref() - .cloned() - .unwrap_or_else(|| abort!(&field, "tuple structs are not supported")); - - let attrs = FieldAttrs::parse(&field.attrs, type_attrs); - Self { + fn new_struct(field: Field, type_attrs: &TypeAttrs) -> syn::Result { + let ident = + field.ident.as_ref().cloned().ok_or_else(|| { + syn::Error::new_spanned(&field, "tuple structs are not supported") + })?; + + let attrs = FieldAttrs::parse(&field.attrs, type_attrs)?; + Ok(Self { ident, attrs, is_enum: false, - } + }) } /// Lower to [`TokenStream`].