From 8f3f0730177e12603b7350f1fbc2662f909f6443 Mon Sep 17 00:00:00 2001 From: hcpl Date: Sat, 17 Nov 2018 18:13:36 +0200 Subject: [PATCH 1/3] Use more spans for error messages --- serde_derive/src/de.rs | 30 ++++++++++++++++++++---------- serde_derive/src/lib.rs | 9 +++++---- serde_derive/src/ser.rs | 24 ++++++++++++++++++------ 3 files changed, 43 insertions(+), 20 deletions(-) diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index e6ff6c95..dc7410f3 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -357,7 +357,10 @@ fn deserialize_transparent(cont: &Container, params: &Parameters) -> Fragment { let path = match transparent_field.attrs.deserialize_with() { Some(path) => quote!(#path), - None => quote!(_serde::Deserialize::deserialize), + None => { + let span = transparent_field.original.span(); + quote_spanned!(span=> _serde::Deserialize::deserialize) + }, }; let assign = fields.iter().map(|field| { @@ -797,8 +800,10 @@ fn deserialize_newtype_struct( let value = match field.attrs.deserialize_with() { None => { + let span = field.original.span(); + let func = quote_spanned!(span=> <#field_ty as _serde::Deserialize>::deserialize); quote! { - try!(<#field_ty as _serde::Deserialize>::deserialize(__e)) + try!(#func(__e)) } } Some(path) => { @@ -1803,10 +1808,10 @@ fn deserialize_externally_tagged_newtype_variant( match field.attrs.deserialize_with() { None => { let field_ty = field.ty; + let span = field.original.span(); + let func = quote_spanned!(span=> _serde::de::VariantAccess::newtype_variant::<#field_ty>); quote_expr! { - _serde::export::Result::map( - _serde::de::VariantAccess::newtype_variant::<#field_ty>(__variant), - #this::#variant_ident) + _serde::export::Result::map(#func(__variant), #this::#variant_ident) } } Some(path) => { @@ -1831,10 +1836,10 @@ fn deserialize_untagged_newtype_variant( let field_ty = field.ty; match field.attrs.deserialize_with() { None => { + let span = field.original.span(); + let func = quote_spanned!(span=> <#field_ty as _serde::Deserialize>::deserialize); quote_expr! { - _serde::export::Result::map( - <#field_ty as _serde::Deserialize>::deserialize(#deserializer), - #this::#variant_ident) + _serde::export::Result::map(#func(#deserializer), #this::#variant_ident) } } Some(path) => { @@ -2441,7 +2446,10 @@ fn deserialize_map( .map(|&(field, ref name)| { let field_ty = field.ty; let func = match field.attrs.deserialize_with() { - None => quote!(_serde::de::Deserialize::deserialize), + None => { + let span = field.original.span(); + quote_spanned!(span=> _serde::de::Deserialize::deserialize) + }, Some(path) => quote!(#path), }; quote! { @@ -2793,7 +2801,9 @@ fn wrap_deserialize_variant_with( fn expr_is_missing(field: &Field, cattrs: &attr::Container) -> Fragment { match *field.attrs.default() { attr::Default::Default => { - return quote_expr!(_serde::export::Default::default()); + let span = field.original.span(); + let func = quote_spanned!(span=> _serde::export::Default::default); + return quote_expr!(#func()); } attr::Default::Path(ref path) => { return quote_expr!(#path()); diff --git a/serde_derive/src/lib.rs b/serde_derive/src/lib.rs index 40f99201..c05a0497 100644 --- a/serde_derive/src/lib.rs +++ b/serde_derive/src/lib.rs @@ -62,6 +62,7 @@ mod internals; use proc_macro::TokenStream; use syn::DeriveInput; +use syn::spanned::Spanned; #[macro_use] mod bound; @@ -77,7 +78,7 @@ mod try; pub fn derive_serialize(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); ser::expand_derive_serialize(&input) - .unwrap_or_else(compile_error) + .unwrap_or_else(|message| compile_error(input.span(), message)) .into() } @@ -85,12 +86,12 @@ pub fn derive_serialize(input: TokenStream) -> TokenStream { pub fn derive_deserialize(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); de::expand_derive_deserialize(&input) - .unwrap_or_else(compile_error) + .unwrap_or_else(|message| compile_error(input.span(), message)) .into() } -fn compile_error(message: String) -> proc_macro2::TokenStream { - quote! { +fn compile_error(span: proc_macro2::Span, message: String) -> proc_macro2::TokenStream { + quote_spanned! {span=> compile_error!(#message); } } diff --git a/serde_derive/src/ser.rs b/serde_derive/src/ser.rs index 5afba924..94d5555f 100644 --- a/serde_derive/src/ser.rs +++ b/serde_derive/src/ser.rs @@ -200,7 +200,10 @@ fn serialize_transparent(cont: &Container, params: &Parameters) -> Fragment { let path = match transparent_field.attrs.serialize_with() { Some(path) => quote!(#path), - None => quote!(_serde::Serialize::serialize), + None => { + let span = transparent_field.original.span(); + quote_spanned!(span=> _serde::Serialize::serialize) + }, }; quote_block! { @@ -505,8 +508,10 @@ fn serialize_externally_tagged_variant( field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr); } + let span = field.original.span(); + let func = quote_spanned!(span=> _serde::Serializer::serialize_newtype_variant); quote_expr! { - _serde::Serializer::serialize_newtype_variant( + #func( __serializer, #type_name, #variant_index, @@ -579,8 +584,10 @@ fn serialize_internally_tagged_variant( field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr); } + let span = field.original.span(); + let func = quote_spanned!(span=> _serde::private::ser::serialize_tagged_newtype); quote_expr! { - _serde::private::ser::serialize_tagged_newtype( + #func( __serializer, #enum_ident_str, #variant_ident_str, @@ -637,12 +644,14 @@ fn serialize_adjacently_tagged_variant( field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr); } + let span = field.original.span(); + let func = quote_spanned!(span=> _serde::ser::SerializeStruct::serialize_field); return quote_block! { let mut __struct = try!(_serde::Serializer::serialize_struct( __serializer, #type_name, 2)); try!(_serde::ser::SerializeStruct::serialize_field( &mut __struct, #tag, #variant_name)); - try!(_serde::ser::SerializeStruct::serialize_field( + try!(#func( &mut __struct, #content, #field_expr)); _serde::ser::SerializeStruct::end(__struct) }; @@ -738,8 +747,10 @@ fn serialize_untagged_variant( field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr); } + let span = field.original.span(); + let func = quote_spanned!(span=> _serde::Serialize::serialize); quote_expr! { - _serde::Serialize::serialize(#field_expr, __serializer) + #func(#field_expr, __serializer) } } Style::Tuple => serialize_tuple_variant(TupleVariant::Untagged, params, &variant.fields), @@ -1079,8 +1090,9 @@ fn serialize_struct_visitor( let span = field.original.span(); let ser = if field.attrs.flatten() { + let func = quote_spanned!(span=> _serde::Serialize::serialize); quote! { - try!(_serde::Serialize::serialize(&#field_expr, _serde::private::ser::FlatMapSerializer(&mut __serde_state))); + try!(#func(&#field_expr, _serde::private::ser::FlatMapSerializer(&mut __serde_state))); } } else { let func = struct_trait.serialize_field(span); From 034db9f20f09afa016ec14933a5f45f23d4b29a6 Mon Sep 17 00:00:00 2001 From: hcpl Date: Thu, 29 Nov 2018 08:01:17 +0200 Subject: [PATCH 2/3] Improve overall quality of `compile_error!` errors Also updates UI tests. --- serde_derive/Cargo.toml | 2 +- serde_derive/src/de.rs | 14 +- serde_derive/src/internals/ast.rs | 12 +- serde_derive/src/internals/attr.rs | 442 ++++++++++++------ serde_derive/src/internals/check.rs | 126 +++-- serde_derive/src/internals/ctxt.rs | 27 +- serde_derive/src/lib.rs | 12 +- serde_derive/src/ser.rs | 11 +- .../tests/ui/borrow/bad_lifetimes.stderr | 6 +- .../tests/ui/borrow/duplicate_lifetime.stderr | 6 +- .../tests/ui/borrow/duplicate_variant.stderr | 6 +- .../tests/ui/borrow/empty_lifetimes.stderr | 6 +- .../tests/ui/borrow/no_lifetimes.stderr | 7 +- .../tests/ui/borrow/struct_variant.stderr | 9 +- .../tests/ui/borrow/wrong_lifetime.stderr | 7 +- .../tests/ui/conflict/adjacent-tag.stderr | 10 +- .../ui/conflict/flatten-newtype-struct.stderr | 6 +- .../flatten-skip-deserializing.stderr | 9 +- .../flatten-skip-serializing-if.stderr | 9 +- .../conflict/flatten-skip-serializing.stderr | 9 +- .../ui/conflict/flatten-tuple-struct.stderr | 6 +- .../tests/ui/conflict/internal-tag.stderr | 14 +- .../tests/ui/default-attribute/enum.stderr | 6 +- .../nameless_struct_fields.stderr | 6 +- .../duplicate-attribute/rename-and-ser.stderr | 6 +- .../rename-rename-de.stderr | 6 +- .../rename-ser-rename-ser.stderr | 6 +- .../rename-ser-rename.stderr | 6 +- .../duplicate-attribute/rename-ser-ser.stderr | 6 +- .../duplicate-attribute/two-rename-ser.stderr | 6 +- .../with-and-serialize-with.stderr | 6 +- .../internal-tuple-variant.stderr | 6 +- .../internally-tagged-struct.stderr | 6 +- .../untagged-and-internal.stderr | 14 +- .../untagged-struct.stderr | 6 +- test_suite/tests/ui/identifier/both.stderr | 16 +- .../tests/ui/identifier/field_struct.stderr | 8 +- .../tests/ui/identifier/field_tuple.stderr | 8 +- .../ui/identifier/newtype_not_last.stderr | 6 +- .../tests/ui/identifier/not_unit.stderr | 7 +- .../tests/ui/identifier/other_not_last.stderr | 9 +- .../tests/ui/identifier/serialize.stderr | 10 +- .../tests/ui/identifier/variant_struct.stderr | 8 +- .../tests/ui/identifier/variant_tuple.stderr | 8 +- .../deserialize_de_lifetime.stderr | 6 +- .../ui/precondition/deserialize_dst.stderr | 9 +- test_suite/tests/ui/remote/bad_getter.stderr | 6 +- test_suite/tests/ui/remote/bad_remote.stderr | 6 +- test_suite/tests/ui/remote/enum_getter.stderr | 12 +- .../tests/ui/remote/nonremote_getter.stderr | 9 +- .../tests/ui/transparent/at_most_one.stderr | 10 +- .../ui/transparent/de_at_least_one.stderr | 14 +- .../ui/transparent/ser_at_least_one.stderr | 10 +- .../tests/ui/type-attribute/from.stderr | 6 +- .../tests/ui/type-attribute/into.stderr | 6 +- .../ui/unknown-attribute/container.stderr | 6 +- .../tests/ui/unknown-attribute/field.stderr | 6 +- .../tests/ui/unknown-attribute/variant.stderr | 6 +- .../with-variant/skip_de_newtype_field.stderr | 9 +- .../with-variant/skip_de_struct_field.stderr | 13 +- .../with-variant/skip_de_tuple_field.stderr | 9 +- .../with-variant/skip_de_whole_variant.stderr | 8 +- .../skip_ser_newtype_field.stderr | 9 +- .../skip_ser_newtype_field_if.stderr | 9 +- .../with-variant/skip_ser_struct_field.stderr | 13 +- .../skip_ser_struct_field_if.stderr | 13 +- .../with-variant/skip_ser_tuple_field.stderr | 9 +- .../skip_ser_tuple_field_if.stderr | 9 +- .../skip_ser_whole_variant.stderr | 8 +- 69 files changed, 714 insertions(+), 429 deletions(-) diff --git a/serde_derive/Cargo.toml b/serde_derive/Cargo.toml index 948ecff4..9a60e945 100644 --- a/serde_derive/Cargo.toml +++ b/serde_derive/Cargo.toml @@ -26,7 +26,7 @@ proc-macro = true [dependencies] proc-macro2 = "0.4" quote = "0.6.3" -syn = { version = "0.15", features = ["visit"] } +syn = { version = "0.15.22", features = ["visit"] } [dev-dependencies] serde = { version = "1.0", path = "../serde" } diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index dc7410f3..ef96c7af 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -13,9 +13,12 @@ use try; use std::collections::BTreeSet; -pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result { +pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result> { let ctxt = Ctxt::new(); - let cont = Container::from_ast(&ctxt, input, Derive::Deserialize); + let cont = match Container::from_ast(&ctxt, input, Derive::Deserialize) { + Some(cont) => cont, + None => return Err(ctxt.check().unwrap_err()), + }; precondition(&ctxt, &cont); try!(ctxt.check()); @@ -86,7 +89,7 @@ fn precondition_sized(cx: &Ctxt, cont: &Container) { if let Data::Struct(_, ref fields) = cont.data { if let Some(last) = fields.last() { if let syn::Type::Slice(_) = *last.ty { - cx.error("cannot deserialize a dynamically sized struct"); + cx.error_spanned_by(cont.original, "cannot deserialize a dynamically sized struct"); } } } @@ -96,7 +99,10 @@ fn precondition_no_de_lifetime(cx: &Ctxt, cont: &Container) { if let BorrowedLifetimes::Borrowed(_) = borrowed_lifetimes(cont) { for param in cont.generics.lifetimes() { if param.lifetime.to_string() == "'de" { - cx.error("cannot deserialize when there is a lifetime parameter called 'de"); + cx.error_spanned_by( + ¶m.lifetime, + "cannot deserialize when there is a lifetime parameter called 'de", + ); return; } } diff --git a/serde_derive/src/internals/ast.rs b/serde_derive/src/internals/ast.rs index c965af67..7e2143d1 100644 --- a/serde_derive/src/internals/ast.rs +++ b/serde_derive/src/internals/ast.rs @@ -17,6 +17,8 @@ pub struct Container<'a> { pub data: Data<'a>, /// Any generics on the struct or enum. pub generics: &'a syn::Generics, + /// Original input. + pub original: &'a syn::DeriveInput, } /// The fields of a struct or enum. @@ -33,6 +35,7 @@ pub struct Variant<'a> { pub attrs: attr::Variant, pub style: Style, pub fields: Vec>, + pub original: &'a syn::Variant, } /// A field of a struct. @@ -57,7 +60,7 @@ pub enum Style { impl<'a> Container<'a> { /// Convert the raw Syn ast into a parsed container object, collecting errors in `cx`. - pub fn from_ast(cx: &Ctxt, item: &'a syn::DeriveInput, derive: Derive) -> Container<'a> { + pub fn from_ast(cx: &Ctxt, item: &'a syn::DeriveInput, derive: Derive) -> Option> { let mut attrs = attr::Container::from_ast(cx, item); let mut data = match item.data { @@ -69,7 +72,8 @@ impl<'a> Container<'a> { Data::Struct(style, fields) } syn::Data::Union(_) => { - panic!("Serde does not support derive for unions"); + cx.error_spanned_by(item, "Serde does not support derive for unions"); + return None; } }; @@ -105,9 +109,10 @@ impl<'a> Container<'a> { attrs: attrs, data: data, generics: &item.generics, + original: item, }; check::check(cx, &mut item, derive); - item + Some(item) } } @@ -142,6 +147,7 @@ fn enum_from_ast<'a>( attrs: attrs, style: style, fields: fields, + original: variant, } }) .collect() diff --git a/serde_derive/src/internals/attr.rs b/serde_derive/src/internals/attr.rs index f87148b1..826f9a48 100644 --- a/serde_derive/src/internals/attr.rs +++ b/serde_derive/src/internals/attr.rs @@ -1,5 +1,6 @@ use internals::Ctxt; use proc_macro2::{Group, Span, TokenStream, TokenTree}; +use quote::ToTokens; use std::collections::BTreeSet; use std::str::FromStr; use syn; @@ -19,10 +20,11 @@ use syn::NestedMeta::{Literal, Meta}; pub use internals::case::RenameRule; -#[derive(Copy, Clone)] +#[derive(Clone)] struct Attr<'c, T> { cx: &'c Ctxt, name: &'static str, + tokens: TokenStream, value: Option, } @@ -31,22 +33,28 @@ impl<'c, T> Attr<'c, T> { Attr { cx: cx, name: name, + tokens: TokenStream::new(), value: None, } } - fn set(&mut self, value: T) { + fn set(&mut self, obj: A, value: T) { + let tokens = obj.into_token_stream(); + if self.value.is_some() { - self.cx - .error(format!("duplicate serde attribute `{}`", self.name)); + self.cx.error_spanned_by( + tokens, + format!("duplicate serde attribute `{}`", self.name), + ); } else { + self.tokens = tokens; self.value = Some(value); } } - fn set_opt(&mut self, value: Option) { + fn set_opt(&mut self, obj: A, value: Option) { if let Some(value) = value { - self.set(value); + self.set(obj, value); } } @@ -59,6 +67,13 @@ impl<'c, T> Attr<'c, T> { fn get(self) -> Option { self.value } + + fn get_with_tokens(self) -> Option<(TokenStream, T)> { + match self.value { + Some(v) => Some((self.tokens, v)), + None => None, + } + } } struct BoolAttr<'c>(Attr<'c, ()>); @@ -68,8 +83,8 @@ impl<'c> BoolAttr<'c> { BoolAttr(Attr::none(cx, name)) } - fn set_true(&mut self) { - self.0.set(()); + fn set_true(&mut self, obj: A) { + self.0.set(obj, ()); } fn get(&self) -> bool { @@ -199,16 +214,16 @@ impl Container { // Parse `#[serde(rename = "foo")]` Meta(NameValue(ref m)) if m.ident == "rename" => { if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) { - ser_name.set(s.value()); - de_name.set(s.value()); + ser_name.set(&m.ident, s.value()); + de_name.set(&m.ident, s.value()); } } // Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]` Meta(List(ref m)) if m.ident == "rename" => { if let Ok((ser, de)) = get_renames(cx, &m.nested) { - ser_name.set_opt(ser.map(syn::LitStr::value)); - de_name.set_opt(de.map(syn::LitStr::value)); + ser_name.set_opt(&m.ident, ser.map(syn::LitStr::value)); + de_name.set_opt(&m.ident, de.map(syn::LitStr::value)); } } @@ -216,11 +231,11 @@ impl Container { Meta(NameValue(ref m)) if m.ident == "rename_all" => { if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) { match RenameRule::from_str(&s.value()) { - Ok(rename_rule) => rename_all.set(rename_rule), - Err(()) => cx.error(format!( + Ok(rename_rule) => rename_all.set(&m.ident, rename_rule), + Err(()) => cx.error_spanned_by(s, format!( "unknown rename rule for #[serde(rename_all \ = {:?})]", - s.value() + s.value(), )), } } @@ -228,23 +243,33 @@ impl Container { // Parse `#[serde(transparent)]` Meta(Word(ref word)) if word == "transparent" => { - transparent.set_true(); + transparent.set_true(word); } // Parse `#[serde(deny_unknown_fields)]` Meta(Word(ref word)) if word == "deny_unknown_fields" => { - deny_unknown_fields.set_true(); + deny_unknown_fields.set_true(word); } // Parse `#[serde(default)]` Meta(Word(ref word)) if word == "default" => match item.data { - syn::Data::Struct(syn::DataStruct { - fields: syn::Fields::Named(_), - .. - }) => { - default.set(Default::Default); - } - _ => cx.error( + syn::Data::Struct(syn::DataStruct { ref fields, .. }) => match *fields { + syn::Fields::Named(_) => { + default.set(word, Default::Default); + } + syn::Fields::Unnamed(_) | syn::Fields::Unit => cx.error_spanned_by( + fields, + "#[serde(default)] can only be used on structs \ + with named fields", + ) + }, + syn::Data::Enum(syn::DataEnum { ref enum_token, .. }) => cx.error_spanned_by( + enum_token, + "#[serde(default)] can only be used on structs \ + with named fields", + ), + syn::Data::Union(syn::DataUnion { ref union_token, .. }) => cx.error_spanned_by( + union_token, "#[serde(default)] can only be used on structs \ with named fields", ), @@ -254,13 +279,23 @@ impl Container { Meta(NameValue(ref m)) if m.ident == "default" => { if let Ok(path) = parse_lit_into_expr_path(cx, &m.ident, &m.lit) { match item.data { - syn::Data::Struct(syn::DataStruct { - fields: syn::Fields::Named(_), - .. - }) => { - default.set(Default::Path(path)); - } - _ => cx.error( + syn::Data::Struct(syn::DataStruct { ref fields, .. }) => match *fields { + syn::Fields::Named(_) => { + default.set(&m.ident, Default::Path(path)); + } + syn::Fields::Unnamed(_) | syn::Fields::Unit => cx.error_spanned_by( + fields, + "#[serde(default = \"...\")] can only be used \ + on structs with named fields", + ) + }, + syn::Data::Enum(syn::DataEnum { ref enum_token, .. }) => cx.error_spanned_by( + enum_token, + "#[serde(default = \"...\")] can only be used \ + on structs with named fields", + ), + syn::Data::Union(syn::DataUnion { ref union_token, .. }) => cx.error_spanned_by( + union_token, "#[serde(default = \"...\")] can only be used \ on structs with named fields", ), @@ -273,26 +308,35 @@ impl Container { if let Ok(where_predicates) = parse_lit_into_where(cx, &m.ident, &m.ident, &m.lit) { - ser_bound.set(where_predicates.clone()); - de_bound.set(where_predicates); + ser_bound.set(&m.ident, where_predicates.clone()); + de_bound.set(&m.ident, where_predicates); } } // Parse `#[serde(bound(serialize = "...", deserialize = "..."))]` Meta(List(ref m)) if m.ident == "bound" => { if let Ok((ser, de)) = get_where_predicates(cx, &m.nested) { - ser_bound.set_opt(ser); - de_bound.set_opt(de); + ser_bound.set_opt(&m.ident, ser); + de_bound.set_opt(&m.ident, de); } } // Parse `#[serde(untagged)]` Meta(Word(ref word)) if word == "untagged" => match item.data { syn::Data::Enum(_) => { - untagged.set_true(); + untagged.set_true(word); } - syn::Data::Struct(_) | syn::Data::Union(_) => { - cx.error("#[serde(untagged)] can only be used on enums") + syn::Data::Struct(syn::DataStruct { ref struct_token, .. }) => { + cx.error_spanned_by( + struct_token, + "#[serde(untagged)] can only be used on enums", + ); + } + syn::Data::Union(syn::DataUnion { ref union_token, .. }) => { + cx.error_spanned_by( + union_token, + "#[serde(untagged)] can only be used on enums", + ); } }, @@ -301,11 +345,20 @@ impl Container { if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) { match item.data { syn::Data::Enum(_) => { - internal_tag.set(s.value()); - } - syn::Data::Struct(_) | syn::Data::Union(_) => { - cx.error("#[serde(tag = \"...\")] can only be used on enums") + internal_tag.set(&m.ident, s.value()); } + syn::Data::Struct(syn::DataStruct { ref struct_token, .. }) => { + cx.error_spanned_by( + struct_token, + "#[serde(tag = \"...\")] can only be used on enums", + ); + }, + syn::Data::Union(syn::DataUnion { ref union_token, .. }) => { + cx.error_spanned_by( + union_token, + "#[serde(tag = \"...\")] can only be used on enums", + ); + }, } } } @@ -315,12 +368,20 @@ impl Container { if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) { match item.data { syn::Data::Enum(_) => { - content.set(s.value()); + content.set(&m.ident, s.value()); } - syn::Data::Struct(_) | syn::Data::Union(_) => cx.error( - "#[serde(content = \"...\")] can only be used on \ - enums", - ), + syn::Data::Struct(syn::DataStruct { ref struct_token, .. }) => { + cx.error_spanned_by( + struct_token, + "#[serde(content = \"...\")] can only be used on enums", + ); + }, + syn::Data::Union(syn::DataUnion { ref union_token, .. }) => { + cx.error_spanned_by( + union_token, + "#[serde(content = \"...\")] can only be used on enums", + ); + }, } } } @@ -328,14 +389,14 @@ impl Container { // Parse `#[serde(from = "Type")] Meta(NameValue(ref m)) if m.ident == "from" => { if let Ok(from_ty) = parse_lit_into_ty(cx, &m.ident, &m.lit) { - type_from.set_opt(Some(from_ty)); + type_from.set_opt(&m.ident, Some(from_ty)); } } // Parse `#[serde(into = "Type")] Meta(NameValue(ref m)) if m.ident == "into" => { if let Ok(into_ty) = parse_lit_into_ty(cx, &m.ident, &m.lit) { - type_into.set_opt(Some(into_ty)); + type_into.set_opt(&m.ident, Some(into_ty)); } } @@ -343,32 +404,32 @@ impl Container { Meta(NameValue(ref m)) if m.ident == "remote" => { if let Ok(path) = parse_lit_into_path(cx, &m.ident, &m.lit) { if is_primitive_path(&path, "Self") { - remote.set(item.ident.clone().into()); + remote.set(&m.ident, item.ident.clone().into()); } else { - remote.set(path); + remote.set(&m.ident, path); } } } // Parse `#[serde(field_identifier)]` Meta(Word(ref word)) if word == "field_identifier" => { - field_identifier.set_true(); + field_identifier.set_true(word); } // Parse `#[serde(variant_identifier)]` Meta(Word(ref word)) if word == "variant_identifier" => { - variant_identifier.set_true(); + variant_identifier.set_true(word); } Meta(ref meta_item) => { - cx.error(format!( + cx.error_spanned_by(meta_item.name(), format!( "unknown serde container attribute `{}`", meta_item.name() )); } - Literal(_) => { - cx.error("unexpected literal in serde container attribute"); + Literal(ref lit) => { + cx.error_spanned_by(lit, "unexpected literal in serde container attribute"); } } } @@ -385,11 +446,11 @@ impl Container { rename_all: rename_all.get().unwrap_or(RenameRule::None), ser_bound: ser_bound.get(), de_bound: de_bound.get(), - tag: decide_tag(cx, item, &untagged, internal_tag, content), + tag: decide_tag(cx, item, untagged, internal_tag, content), type_from: type_from.get(), type_into: type_into.get(), remote: remote.get(), - identifier: decide_identifier(cx, item, &field_identifier, &variant_identifier), + identifier: decide_identifier(cx, item, field_identifier, variant_identifier), has_flatten: false, } } @@ -454,14 +515,14 @@ impl Container { fn decide_tag( cx: &Ctxt, item: &syn::DeriveInput, - untagged: &BoolAttr, + untagged: BoolAttr, internal_tag: Attr, content: Attr, ) -> EnumTag { - match (untagged.get(), internal_tag.get(), content.get()) { - (false, None, None) => EnumTag::External, - (true, None, None) => EnumTag::None, - (false, Some(tag), None) => { + match (untagged.0.get_with_tokens(), internal_tag.get_with_tokens(), content.get_with_tokens()) { + (None, None, None) => EnumTag::External, + (Some(_), None, None) => EnumTag::None, + (None, Some((_, tag)), None) => { // Check that there are no tuple variants. if let syn::Data::Enum(ref data) = item.data { for variant in &data.variants { @@ -469,7 +530,8 @@ fn decide_tag( syn::Fields::Named(_) | syn::Fields::Unit => {} syn::Fields::Unnamed(ref fields) => { if fields.unnamed.len() != 1 { - cx.error( + cx.error_spanned_by( + variant, "#[serde(tag = \"...\")] cannot be used with tuple \ variants", ); @@ -481,24 +543,52 @@ fn decide_tag( } EnumTag::Internal { tag: tag } } - (true, Some(_), None) => { - cx.error("enum cannot be both untagged and internally tagged"); + (Some((untagged_tokens, _)), Some((tag_tokens, _)), None) => { + cx.error_spanned_by( + untagged_tokens, + "enum cannot be both untagged and internally tagged", + ); + cx.error_spanned_by( + tag_tokens, + "enum cannot be both untagged and internally tagged", + ); EnumTag::External // doesn't matter, will error } - (false, None, Some(_)) => { - cx.error("#[serde(tag = \"...\", content = \"...\")] must be used together"); + (None, None, Some((content_tokens, _))) => { + cx.error_spanned_by( + content_tokens, + "#[serde(tag = \"...\", content = \"...\")] must be used together", + ); EnumTag::External } - (true, None, Some(_)) => { - cx.error("untagged enum cannot have #[serde(content = \"...\")]"); + (Some((untagged_tokens, _)), None, Some((content_tokens, _))) => { + cx.error_spanned_by( + untagged_tokens, + "untagged enum cannot have #[serde(content = \"...\")]", + ); + cx.error_spanned_by( + content_tokens, + "untagged enum cannot have #[serde(content = \"...\")]", + ); EnumTag::External } - (false, Some(tag), Some(content)) => EnumTag::Adjacent { + (None, Some((_, tag)), Some((_, content))) => EnumTag::Adjacent { tag: tag, content: content, }, - (true, Some(_), Some(_)) => { - cx.error("untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]"); + (Some((untagged_tokens, _)), Some((tag_tokens, _)), Some((content_tokens, _))) => { + cx.error_spanned_by( + untagged_tokens, + "untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]", + ); + cx.error_spanned_by( + tag_tokens, + "untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]", + ); + cx.error_spanned_by( + content_tokens, + "untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]", + ); EnumTag::External } } @@ -507,23 +597,50 @@ fn decide_tag( fn decide_identifier( cx: &Ctxt, item: &syn::DeriveInput, - field_identifier: &BoolAttr, - variant_identifier: &BoolAttr, + field_identifier: BoolAttr, + variant_identifier: BoolAttr, ) -> Identifier { - match (&item.data, field_identifier.get(), variant_identifier.get()) { - (_, false, false) => Identifier::No, - (_, true, true) => { - cx.error("`field_identifier` and `variant_identifier` cannot both be set"); + match (&item.data, field_identifier.0.get_with_tokens(), variant_identifier.0.get_with_tokens()) { + (_, None, None) => Identifier::No, + (_, Some((field_identifier_tokens, _)), Some((variant_identifier_tokens, _))) => { + cx.error_spanned_by( + field_identifier_tokens, + "#[serde(field_identifier)] and #[serde(variant_identifier)] cannot both be set", + ); + cx.error_spanned_by( + variant_identifier_tokens, + "#[serde(field_identifier)] and #[serde(variant_identifier)] cannot both be set", + ); Identifier::No } - (&syn::Data::Enum(_), true, false) => Identifier::Field, - (&syn::Data::Enum(_), false, true) => Identifier::Variant, - (&syn::Data::Struct(_), true, false) | (&syn::Data::Union(_), true, false) => { - cx.error("`field_identifier` can only be used on an enum"); + (&syn::Data::Enum(_), Some(_), None) => Identifier::Field, + (&syn::Data::Enum(_), None, Some(_)) => Identifier::Variant, + (&syn::Data::Struct(syn::DataStruct { ref struct_token, .. }), Some(_), None) => { + cx.error_spanned_by( + struct_token, + "#[serde(field_identifier)] can only be used on an enum", + ); Identifier::No } - (&syn::Data::Struct(_), false, true) | (&syn::Data::Union(_), false, true) => { - cx.error("`variant_identifier` can only be used on an enum"); + (&syn::Data::Union(syn::DataUnion { ref union_token, .. }), Some(_), None) => { + cx.error_spanned_by( + union_token, + "#[serde(field_identifier)] can only be used on an enum", + ); + Identifier::No + } + (&syn::Data::Struct(syn::DataStruct { ref struct_token, .. }), None, Some(_)) => { + cx.error_spanned_by( + struct_token, + "#[serde(variant_identifier)] can only be used on an enum", + ); + Identifier::No + } + (&syn::Data::Union(syn::DataUnion { ref union_token, .. }), None, Some(_)) => { + cx.error_spanned_by( + union_token, + "#[serde(variant_identifier)] can only be used on an enum", + ); Identifier::No } } @@ -565,16 +682,16 @@ impl Variant { // Parse `#[serde(rename = "foo")]` Meta(NameValue(ref m)) if m.ident == "rename" => { if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) { - ser_name.set(s.value()); - de_name.set(s.value()); + ser_name.set(&m.ident, s.value()); + de_name.set(&m.ident, s.value()); } } // Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]` Meta(List(ref m)) if m.ident == "rename" => { if let Ok((ser, de)) = get_renames(cx, &m.nested) { - ser_name.set_opt(ser.map(syn::LitStr::value)); - de_name.set_opt(de.map(syn::LitStr::value)); + ser_name.set_opt(&m.ident, ser.map(syn::LitStr::value)); + de_name.set_opt(&m.ident, de.map(syn::LitStr::value)); } } @@ -582,8 +699,8 @@ impl Variant { Meta(NameValue(ref m)) if m.ident == "rename_all" => { if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) { match RenameRule::from_str(&s.value()) { - Ok(rename_rule) => rename_all.set(rename_rule), - Err(()) => cx.error(format!( + Ok(rename_rule) => rename_all.set(&m.ident, rename_rule), + Err(()) => cx.error_spanned_by(s, format!( "unknown rename rule for #[serde(rename_all \ = {:?})]", s.value() @@ -594,23 +711,23 @@ impl Variant { // Parse `#[serde(skip)]` Meta(Word(ref word)) if word == "skip" => { - skip_serializing.set_true(); - skip_deserializing.set_true(); + skip_serializing.set_true(word); + skip_deserializing.set_true(word); } // Parse `#[serde(skip_deserializing)]` Meta(Word(ref word)) if word == "skip_deserializing" => { - skip_deserializing.set_true(); + skip_deserializing.set_true(word); } // Parse `#[serde(skip_serializing)]` Meta(Word(ref word)) if word == "skip_serializing" => { - skip_serializing.set_true(); + skip_serializing.set_true(word); } // Parse `#[serde(other)]` Meta(Word(ref word)) if word == "other" => { - other.set_true(); + other.set_true(word); } // Parse `#[serde(bound = "T: SomeBound")]` @@ -618,16 +735,16 @@ impl Variant { if let Ok(where_predicates) = parse_lit_into_where(cx, &m.ident, &m.ident, &m.lit) { - ser_bound.set(where_predicates.clone()); - de_bound.set(where_predicates); + ser_bound.set(&m.ident, where_predicates.clone()); + de_bound.set(&m.ident, where_predicates); } } // Parse `#[serde(bound(serialize = "...", deserialize = "..."))]` Meta(List(ref m)) if m.ident == "bound" => { if let Ok((ser, de)) = get_where_predicates(cx, &m.nested) { - ser_bound.set_opt(ser); - de_bound.set_opt(de); + ser_bound.set_opt(&m.ident, ser); + de_bound.set_opt(&m.ident, de); } } @@ -639,49 +756,55 @@ impl Variant { .path .segments .push(Ident::new("serialize", Span::call_site()).into()); - serialize_with.set(ser_path); + serialize_with.set(&m.ident, ser_path); let mut de_path = path; de_path .path .segments .push(Ident::new("deserialize", Span::call_site()).into()); - deserialize_with.set(de_path); + deserialize_with.set(&m.ident, de_path); } } // Parse `#[serde(serialize_with = "...")]` Meta(NameValue(ref m)) if m.ident == "serialize_with" => { if let Ok(path) = parse_lit_into_expr_path(cx, &m.ident, &m.lit) { - serialize_with.set(path); + serialize_with.set(&m.ident, path); } } // Parse `#[serde(deserialize_with = "...")]` Meta(NameValue(ref m)) if m.ident == "deserialize_with" => { if let Ok(path) = parse_lit_into_expr_path(cx, &m.ident, &m.lit) { - deserialize_with.set(path); + deserialize_with.set(&m.ident, path); } } // Defer `#[serde(borrow)]` and `#[serde(borrow = "'a + 'b")]` Meta(ref m) if m.name() == "borrow" => match variant.fields { syn::Fields::Unnamed(ref fields) if fields.unnamed.len() == 1 => { - borrow.set(m.clone()); + borrow.set(m.name(), m.clone()); } _ => { - cx.error("#[serde(borrow)] may only be used on newtype variants"); + cx.error_spanned_by( + variant, + "#[serde(borrow)] may only be used on newtype variants", + ); } }, Meta(ref meta_item) => { - cx.error(format!( + cx.error_spanned_by(meta_item.name(), format!( "unknown serde variant attribute `{}`", meta_item.name() )); } - Literal(_) => { - cx.error("unexpected literal in serde variant attribute"); + Literal(ref lit) => { + cx.error_spanned_by( + lit, + "unexpected literal in serde variant attribute", + ); } } } @@ -837,65 +960,65 @@ impl Field { // Parse `#[serde(rename = "foo")]` Meta(NameValue(ref m)) if m.ident == "rename" => { if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) { - ser_name.set(s.value()); - de_name.set(s.value()); + ser_name.set(&m.ident, s.value()); + de_name.set(&m.ident, s.value()); } } // Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]` Meta(List(ref m)) if m.ident == "rename" => { if let Ok((ser, de)) = get_renames(cx, &m.nested) { - ser_name.set_opt(ser.map(syn::LitStr::value)); - de_name.set_opt(de.map(syn::LitStr::value)); + ser_name.set_opt(&m.ident, ser.map(syn::LitStr::value)); + de_name.set_opt(&m.ident, de.map(syn::LitStr::value)); } } // Parse `#[serde(default)]` Meta(Word(ref word)) if word == "default" => { - default.set(Default::Default); + default.set(word, Default::Default); } // Parse `#[serde(default = "...")]` Meta(NameValue(ref m)) if m.ident == "default" => { if let Ok(path) = parse_lit_into_expr_path(cx, &m.ident, &m.lit) { - default.set(Default::Path(path)); + default.set(&m.ident, Default::Path(path)); } } // Parse `#[serde(skip_serializing)]` Meta(Word(ref word)) if word == "skip_serializing" => { - skip_serializing.set_true(); + skip_serializing.set_true(word); } // Parse `#[serde(skip_deserializing)]` Meta(Word(ref word)) if word == "skip_deserializing" => { - skip_deserializing.set_true(); + skip_deserializing.set_true(word); } // Parse `#[serde(skip)]` Meta(Word(ref word)) if word == "skip" => { - skip_serializing.set_true(); - skip_deserializing.set_true(); + skip_serializing.set_true(word); + skip_deserializing.set_true(word); } // Parse `#[serde(skip_serializing_if = "...")]` Meta(NameValue(ref m)) if m.ident == "skip_serializing_if" => { if let Ok(path) = parse_lit_into_expr_path(cx, &m.ident, &m.lit) { - skip_serializing_if.set(path); + skip_serializing_if.set(&m.ident, path); } } // Parse `#[serde(serialize_with = "...")]` Meta(NameValue(ref m)) if m.ident == "serialize_with" => { if let Ok(path) = parse_lit_into_expr_path(cx, &m.ident, &m.lit) { - serialize_with.set(path); + serialize_with.set(&m.ident, path); } } // Parse `#[serde(deserialize_with = "...")]` Meta(NameValue(ref m)) if m.ident == "deserialize_with" => { if let Ok(path) = parse_lit_into_expr_path(cx, &m.ident, &m.lit) { - deserialize_with.set(path); + deserialize_with.set(&m.ident, path); } } @@ -907,13 +1030,13 @@ impl Field { .path .segments .push(Ident::new("serialize", Span::call_site()).into()); - serialize_with.set(ser_path); + serialize_with.set(&m.ident, ser_path); let mut de_path = path; de_path .path .segments .push(Ident::new("deserialize", Span::call_site()).into()); - deserialize_with.set(de_path); + deserialize_with.set(&m.ident, de_path); } } @@ -922,39 +1045,39 @@ impl Field { if let Ok(where_predicates) = parse_lit_into_where(cx, &m.ident, &m.ident, &m.lit) { - ser_bound.set(where_predicates.clone()); - de_bound.set(where_predicates); + ser_bound.set(&m.ident, where_predicates.clone()); + de_bound.set(&m.ident, where_predicates); } } // Parse `#[serde(bound(serialize = "...", deserialize = "..."))]` Meta(List(ref m)) if m.ident == "bound" => { if let Ok((ser, de)) = get_where_predicates(cx, &m.nested) { - ser_bound.set_opt(ser); - de_bound.set_opt(de); + ser_bound.set_opt(&m.ident, ser); + de_bound.set_opt(&m.ident, de); } } // Parse `#[serde(borrow)]` Meta(Word(ref word)) if word == "borrow" => { - if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, &field.ty) { - borrowed_lifetimes.set(borrowable); + if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, field) { + borrowed_lifetimes.set(word, borrowable); } } // Parse `#[serde(borrow = "'a + 'b")]` Meta(NameValue(ref m)) if m.ident == "borrow" => { if let Ok(lifetimes) = parse_lit_into_lifetimes(cx, &m.ident, &m.lit) { - if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, &field.ty) { + if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, field) { for lifetime in &lifetimes { if !borrowable.contains(lifetime) { - cx.error(format!( + cx.error_spanned_by(field, format!( "field `{}` does not have lifetime {}", ident, lifetime )); } } - borrowed_lifetimes.set(lifetimes); + borrowed_lifetimes.set(&m.ident, lifetimes); } } } @@ -962,24 +1085,27 @@ impl Field { // Parse `#[serde(getter = "...")]` Meta(NameValue(ref m)) if m.ident == "getter" => { if let Ok(path) = parse_lit_into_expr_path(cx, &m.ident, &m.lit) { - getter.set(path); + getter.set(&m.ident, path); } } // Parse `#[serde(flatten)]` Meta(Word(ref word)) if word == "flatten" => { - flatten.set_true(); + flatten.set_true(word); } Meta(ref meta_item) => { - cx.error(format!( + cx.error_spanned_by(meta_item.name(), format!( "unknown serde field attribute `{}`", meta_item.name() )); } - Literal(_) => { - cx.error("unexpected literal in serde field attribute"); + Literal(ref lit) => { + cx.error_spanned_by( + lit, + "unexpected literal in serde field attribute", + ); } } } @@ -1162,18 +1288,18 @@ where match *meta { Meta(NameValue(ref meta)) if meta.ident == "serialize" => { if let Ok(v) = f(cx, &attr_name, &meta.ident, &meta.lit) { - ser_meta.set(v); + ser_meta.set(&meta.ident, v); } } Meta(NameValue(ref meta)) if meta.ident == "deserialize" => { if let Ok(v) = f(cx, &attr_name, &meta.ident, &meta.lit) { - de_meta.set(v); + de_meta.set(&meta.ident, v); } } _ => { - cx.error(format!( + cx.error_spanned_by(meta, format!( "malformed {0} attribute, expected `{0}(serialize = ..., \ deserialize = ...)`", attr_name @@ -1223,7 +1349,7 @@ fn get_lit_str<'a>( if let syn::Lit::Str(ref lit) = *lit { Ok(lit) } else { - cx.error(format!( + cx.error_spanned_by(lit, format!( "expected serde {} attribute to be a string: `{} = \"...\"`", attr_name, meta_item_name )); @@ -1234,7 +1360,10 @@ fn get_lit_str<'a>( fn parse_lit_into_path(cx: &Ctxt, attr_name: &Ident, lit: &syn::Lit) -> Result { let string = try!(get_lit_str(cx, attr_name, attr_name, lit)); parse_lit_str(string) - .map_err(|_| cx.error(format!("failed to parse path: {:?}", string.value()))) + .map_err(|_| cx.error_spanned_by( + lit, + format!("failed to parse path: {:?}", string.value()), + )) } fn parse_lit_into_expr_path( @@ -1244,7 +1373,10 @@ fn parse_lit_into_expr_path( ) -> Result { let string = try!(get_lit_str(cx, attr_name, attr_name, lit)); parse_lit_str(string) - .map_err(|_| cx.error(format!("failed to parse path: {:?}", string.value()))) + .map_err(|_| cx.error_spanned_by( + lit, + format!("failed to parse path: {:?}", string.value()), + )) } fn parse_lit_into_where( @@ -1262,14 +1394,14 @@ fn parse_lit_into_where( parse_lit_str::(&where_string) .map(|wh| wh.predicates.into_iter().collect()) - .map_err(|err| cx.error(err)) + .map_err(|err| cx.error_spanned_by(lit, err)) } fn parse_lit_into_ty(cx: &Ctxt, attr_name: &Ident, lit: &syn::Lit) -> Result { let string = try!(get_lit_str(cx, attr_name, attr_name, lit)); parse_lit_str(string).map_err(|_| { - cx.error(format!( + cx.error_spanned_by(lit, format!( "failed to parse type: {} = {:?}", attr_name, string.value() @@ -1286,7 +1418,7 @@ fn parse_lit_into_lifetimes( ) -> Result, ()> { let string = try!(get_lit_str(cx, attr_name, attr_name, lit)); if string.value().is_empty() { - cx.error("at least one lifetime must be borrowed"); + cx.error_spanned_by(lit, "at least one lifetime must be borrowed"); return Err(()); } @@ -1302,13 +1434,16 @@ fn parse_lit_into_lifetimes( let mut set = BTreeSet::new(); for lifetime in lifetimes { if !set.insert(lifetime.clone()) { - cx.error(format!("duplicate borrowed lifetime `{}`", lifetime)); + cx.error_spanned_by( + lit, + format!("duplicate borrowed lifetime `{}`", lifetime), + ); } } return Ok(set); } - cx.error(format!( + cx.error_spanned_by(lit, format!( "failed to parse borrowed lifetimes: {:?}", string.value() )); @@ -1461,12 +1596,15 @@ fn is_primitive_path(path: &syn::Path, primitive: &str) -> bool { fn borrowable_lifetimes( cx: &Ctxt, name: &str, - ty: &syn::Type, + field: &syn::Field, ) -> Result, ()> { let mut lifetimes = BTreeSet::new(); - collect_lifetimes(ty, &mut lifetimes); + collect_lifetimes(&field.ty, &mut lifetimes); if lifetimes.is_empty() { - cx.error(format!("field `{}` has no lifetimes to borrow", name)); + cx.error_spanned_by( + field, + format!("field `{}` has no lifetimes to borrow", name), + ); Err(()) } else { Ok(lifetimes) diff --git a/serde_derive/src/internals/check.rs b/serde_derive/src/internals/check.rs index a6c15b87..b5f91c64 100644 --- a/serde_derive/src/internals/check.rs +++ b/serde_derive/src/internals/check.rs @@ -21,12 +21,16 @@ fn check_getter(cx: &Ctxt, cont: &Container) { match cont.data { Data::Enum(_) => { if cont.data.has_getter() { - cx.error("#[serde(getter = \"...\")] is not allowed in an enum"); + cx.error_spanned_by( + cont.original, + "#[serde(getter = \"...\")] is not allowed in an enum", + ); } } Data::Struct(_, _) => { if cont.data.has_getter() && cont.attrs.remote().is_none() { - cx.error( + cx.error_spanned_by( + cont.original, "#[serde(getter = \"...\")] can only be used in structs \ that have #[serde(remote = \"...\")]", ); @@ -59,26 +63,35 @@ fn check_flatten_field(cx: &Ctxt, style: Style, field: &Field) { } match style { Style::Tuple => { - cx.error("#[serde(flatten)] cannot be used on tuple structs"); + cx.error_spanned_by( + field.original, + "#[serde(flatten)] cannot be used on tuple structs", + ); } Style::Newtype => { - cx.error("#[serde(flatten)] cannot be used on newtype structs"); + cx.error_spanned_by( + field.original, + "#[serde(flatten)] cannot be used on newtype structs", + ); } _ => {} } if field.attrs.skip_serializing() { - cx.error( - "#[serde(flatten] can not be combined with \ + cx.error_spanned_by( + field.original, + "#[serde(flatten)] can not be combined with \ #[serde(skip_serializing)]", ); } else if field.attrs.skip_serializing_if().is_some() { - cx.error( - "#[serde(flatten] can not be combined with \ + cx.error_spanned_by( + field.original, + "#[serde(flatten)] can not be combined with \ #[serde(skip_serializing_if = \"...\")]", ); } else if field.attrs.skip_deserializing() { - cx.error( - "#[serde(flatten] can not be combined with \ + cx.error_spanned_by( + field.original, + "#[serde(flatten)] can not be combined with \ #[serde(skip_deserializing)]", ); } @@ -107,24 +120,36 @@ fn check_identifier(cx: &Ctxt, cont: &Container) { ) { // The `other` attribute may not be used in a variant_identifier. (_, Identifier::Variant, true, _) => { - cx.error("#[serde(other)] may not be used on a variant_identifier"); + cx.error_spanned_by( + variant.original, + "#[serde(other)] may not be used on a variant identifier", + ); } // Variant with `other` attribute cannot appear in untagged enum (_, Identifier::No, true, &EnumTag::None) => { - cx.error("#[serde(other)] cannot appear on untagged enum"); + cx.error_spanned_by( + variant.original, + "#[serde(other)] cannot appear on untagged enum", + ); } // Variant with `other` attribute must be the last one. (Style::Unit, Identifier::Field, true, _) | (Style::Unit, Identifier::No, true, _) => { if i < variants.len() - 1 { - cx.error("#[serde(other)] must be the last variant"); + cx.error_spanned_by( + variant.original, + "#[serde(other)] must be on the last variant", + ); } } // Variant with `other` attribute must be a unit variant. (_, Identifier::Field, true, _) | (_, Identifier::No, true, _) => { - cx.error("#[serde(other)] must be on a unit variant"); + cx.error_spanned_by( + variant.original, + "#[serde(other)] must be on a unit variant", + ); } // Any sort of variant is allowed if this is not an identifier. @@ -136,16 +161,25 @@ fn check_identifier(cx: &Ctxt, cont: &Container) { // The last field is allowed to be a newtype catch-all. (Style::Newtype, Identifier::Field, false, _) => { if i < variants.len() - 1 { - cx.error(format!("`{}` must be the last variant", variant.ident)); + cx.error_spanned_by( + variant.original, + format!("`{}` must be the last variant", variant.ident), + ); } } (_, Identifier::Field, false, _) => { - cx.error("field_identifier may only contain unit variants"); + cx.error_spanned_by( + variant.original, + "#[serde(field_identifier)] may only contain unit variants", + ); } (_, Identifier::Variant, false, _) => { - cx.error("variant_identifier may only contain unit variants"); + cx.error_spanned_by( + variant.original, + "#[serde(variant_identifier)] may only contain unit variants", + ); } } } @@ -164,7 +198,7 @@ fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) { for variant in variants.iter() { if variant.attrs.serialize_with().is_some() { if variant.attrs.skip_serializing() { - cx.error(format!( + cx.error_spanned_by(variant.original, format!( "variant `{}` cannot have both #[serde(serialize_with)] and \ #[serde(skip_serializing)]", variant.ident @@ -175,7 +209,7 @@ fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) { let member = member_message(&field.member); if field.attrs.skip_serializing() { - cx.error(format!( + cx.error_spanned_by(variant.original, format!( "variant `{}` cannot have both #[serde(serialize_with)] and \ a field {} marked with #[serde(skip_serializing)]", variant.ident, member @@ -183,7 +217,7 @@ fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) { } if field.attrs.skip_serializing_if().is_some() { - cx.error(format!( + cx.error_spanned_by(variant.original, format!( "variant `{}` cannot have both #[serde(serialize_with)] and \ a field {} marked with #[serde(skip_serializing_if)]", variant.ident, member @@ -194,7 +228,7 @@ fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) { if variant.attrs.deserialize_with().is_some() { if variant.attrs.skip_deserializing() { - cx.error(format!( + cx.error_spanned_by(variant.original, format!( "variant `{}` cannot have both #[serde(deserialize_with)] and \ #[serde(skip_deserializing)]", variant.ident @@ -205,7 +239,7 @@ fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) { if field.attrs.skip_deserializing() { let member = member_message(&field.member); - cx.error(format!( + cx.error_spanned_by(variant.original, format!( "variant `{}` cannot have both #[serde(deserialize_with)] \ and a field {} marked with #[serde(skip_deserializing)]", variant.ident, member @@ -231,10 +265,10 @@ fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) { EnumTag::External | EnumTag::Adjacent { .. } | EnumTag::None => return, }; - let diagnose_conflict = || { - let message = format!("variant field name `{}` conflicts with internal tag", tag); - cx.error(message); - }; + let diagnose_conflict = || cx.error_spanned_by( + cont.original, + format!("variant field name `{}` conflicts with internal tag", tag), + ); for variant in variants { match variant.style { @@ -269,11 +303,10 @@ fn check_adjacent_tag_conflict(cx: &Ctxt, cont: &Container) { }; if type_tag == content_tag { - let message = format!( + cx.error_spanned_by(cont.original, format!( "enum tags `{}` for type and content conflict with each other", type_tag - ); - cx.error(message); + )); } } @@ -284,20 +317,32 @@ fn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) { } if cont.attrs.type_from().is_some() { - cx.error("#[serde(transparent)] is not allowed with #[serde(from = \"...\")]"); + cx.error_spanned_by( + cont.original, + "#[serde(transparent)] is not allowed with #[serde(from = \"...\")]", + ); } if cont.attrs.type_into().is_some() { - cx.error("#[serde(transparent)] is not allowed with #[serde(into = \"...\")]"); + cx.error_spanned_by( + cont.original, + "#[serde(transparent)] is not allowed with #[serde(into = \"...\")]", + ); } let fields = match cont.data { Data::Enum(_) => { - cx.error("#[serde(transparent)] is not allowed on an enum"); + cx.error_spanned_by( + cont.original, + "#[serde(transparent)] is not allowed on an enum", + ); return; } Data::Struct(Style::Unit, _) => { - cx.error("#[serde(transparent)] is not allowed on a unit struct"); + cx.error_spanned_by( + cont.original, + "#[serde(transparent)] is not allowed on a unit struct", + ); return; } Data::Struct(_, ref mut fields) => fields, @@ -308,7 +353,8 @@ fn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) { for field in fields { if allow_transparent(field, derive) { if transparent_field.is_some() { - cx.error( + cx.error_spanned_by( + cont.original, "#[serde(transparent)] requires struct to have at most one transparent field", ); return; @@ -321,10 +367,16 @@ fn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) { Some(transparent_field) => transparent_field.attrs.mark_transparent(), None => match derive { Derive::Serialize => { - cx.error("#[serde(transparent)] requires at least one field that is not skipped"); + cx.error_spanned_by( + cont.original, + "#[serde(transparent)] requires at least one field that is not skipped", + ); } Derive::Deserialize => { - cx.error("#[serde(transparent)] requires at least one field that is neither skipped nor has a default"); + cx.error_spanned_by( + cont.original, + "#[serde(transparent)] requires at least one field that is neither skipped nor has a default", + ); } }, } @@ -333,7 +385,7 @@ fn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) { fn member_message(member: &Member) -> String { match *member { Member::Named(ref ident) => format!("`{}`", ident), - Member::Unnamed(ref i) => i.index.to_string(), + Member::Unnamed(ref i) => format!("#{}", i.index), } } diff --git a/serde_derive/src/internals/ctxt.rs b/serde_derive/src/internals/ctxt.rs index 79d7bbe9..84261cf1 100644 --- a/serde_derive/src/internals/ctxt.rs +++ b/serde_derive/src/internals/ctxt.rs @@ -1,6 +1,8 @@ +use quote::ToTokens; use std::cell::RefCell; use std::fmt::Display; use std::thread; +use syn; /// A type to collect errors together and format them. /// @@ -11,7 +13,7 @@ use std::thread; pub struct Ctxt { // The contents will be set to `None` during checking. This is so that checking can be // enforced. - errors: RefCell>>, + errors: RefCell>>, } impl Ctxt { @@ -24,29 +26,24 @@ impl Ctxt { } } - /// Add an error to the context object. - pub fn error(&self, msg: T) { + /// Add an error to the context object with a tokenenizable object. + /// + /// The object is used for spanning in error messages. + pub fn error_spanned_by(&self, obj: A, msg: T) { self.errors .borrow_mut() .as_mut() .unwrap() - .push(msg.to_string()); + // Curb monomorphization from generating too many identical methods. + .push(syn::Error::new_spanned(obj.into_token_stream(), msg)); } /// Consume this object, producing a formatted error string if there are errors. - pub fn check(self) -> Result<(), String> { - let mut errors = self.errors.borrow_mut().take().unwrap(); + pub fn check(self) -> Result<(), Vec> { + let errors = self.errors.borrow_mut().take().unwrap(); match errors.len() { 0 => Ok(()), - 1 => Err(errors.pop().unwrap()), - n => { - let mut msg = format!("{} errors:", n); - for err in errors { - msg.push_str("\n\t# "); - msg.push_str(&err); - } - Err(msg) - } + _ => Err(errors), } } } diff --git a/serde_derive/src/lib.rs b/serde_derive/src/lib.rs index c05a0497..313a35e6 100644 --- a/serde_derive/src/lib.rs +++ b/serde_derive/src/lib.rs @@ -62,7 +62,6 @@ mod internals; use proc_macro::TokenStream; use syn::DeriveInput; -use syn::spanned::Spanned; #[macro_use] mod bound; @@ -78,7 +77,7 @@ mod try; pub fn derive_serialize(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); ser::expand_derive_serialize(&input) - .unwrap_or_else(|message| compile_error(input.span(), message)) + .unwrap_or_else(to_compile_errors) .into() } @@ -86,12 +85,11 @@ pub fn derive_serialize(input: TokenStream) -> TokenStream { pub fn derive_deserialize(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); de::expand_derive_deserialize(&input) - .unwrap_or_else(|message| compile_error(input.span(), message)) + .unwrap_or_else(to_compile_errors) .into() } -fn compile_error(span: proc_macro2::Span, message: String) -> proc_macro2::TokenStream { - quote_spanned! {span=> - compile_error!(#message); - } +fn to_compile_errors(errors: Vec) -> proc_macro2::TokenStream { + let compile_errors = errors.iter().map(syn::Error::to_compile_error); + quote!(#(#compile_errors)*) } diff --git a/serde_derive/src/ser.rs b/serde_derive/src/ser.rs index 94d5555f..028abe2b 100644 --- a/serde_derive/src/ser.rs +++ b/serde_derive/src/ser.rs @@ -9,9 +9,12 @@ use internals::{attr, Ctxt, Derive}; use pretend; use try; -pub fn expand_derive_serialize(input: &syn::DeriveInput) -> Result { +pub fn expand_derive_serialize(input: &syn::DeriveInput) -> Result> { let ctxt = Ctxt::new(); - let cont = Container::from_ast(&ctxt, input, Derive::Serialize); + let cont = match Container::from_ast(&ctxt, input, Derive::Serialize) { + Some(cont) => cont, + None => return Err(ctxt.check().unwrap_err()), + }; precondition(&ctxt, &cont); try!(ctxt.check()); @@ -72,10 +75,10 @@ fn precondition(cx: &Ctxt, cont: &Container) { match cont.attrs.identifier() { attr::Identifier::No => {} attr::Identifier::Field => { - cx.error("field identifiers cannot be serialized"); + cx.error_spanned_by(cont.original, "field identifiers cannot be serialized"); } attr::Identifier::Variant => { - cx.error("variant identifiers cannot be serialized"); + cx.error_spanned_by(cont.original, "variant identifiers cannot be serialized"); } } } diff --git a/test_suite/tests/ui/borrow/bad_lifetimes.stderr b/test_suite/tests/ui/borrow/bad_lifetimes.stderr index 2e51b446..25b80da3 100644 --- a/test_suite/tests/ui/borrow/bad_lifetimes.stderr +++ b/test_suite/tests/ui/borrow/bad_lifetimes.stderr @@ -1,8 +1,8 @@ error: failed to parse borrowed lifetimes: "zzz" - --> $DIR/bad_lifetimes.rs:4:10 + --> $DIR/bad_lifetimes.rs:6:22 | -4 | #[derive(Deserialize)] - | ^^^^^^^^^^^ +6 | #[serde(borrow = "zzz")] + | ^^^^^ error: aborting due to previous error diff --git a/test_suite/tests/ui/borrow/duplicate_lifetime.stderr b/test_suite/tests/ui/borrow/duplicate_lifetime.stderr index d6170da2..add7082a 100644 --- a/test_suite/tests/ui/borrow/duplicate_lifetime.stderr +++ b/test_suite/tests/ui/borrow/duplicate_lifetime.stderr @@ -1,8 +1,8 @@ error: duplicate borrowed lifetime `'a` - --> $DIR/duplicate_lifetime.rs:4:10 + --> $DIR/duplicate_lifetime.rs:6:22 | -4 | #[derive(Deserialize)] - | ^^^^^^^^^^^ +6 | #[serde(borrow = "'a + 'a")] + | ^^^^^^^^^ error: aborting due to previous error diff --git a/test_suite/tests/ui/borrow/duplicate_variant.stderr b/test_suite/tests/ui/borrow/duplicate_variant.stderr index 8b4c86fc..35a60b53 100644 --- a/test_suite/tests/ui/borrow/duplicate_variant.stderr +++ b/test_suite/tests/ui/borrow/duplicate_variant.stderr @@ -1,8 +1,8 @@ error: duplicate serde attribute `borrow` - --> $DIR/duplicate_variant.rs:7:10 + --> $DIR/duplicate_variant.rs:9:13 | -7 | #[derive(Deserialize)] - | ^^^^^^^^^^^ +9 | #[serde(borrow)] + | ^^^^^^ error: aborting due to previous error diff --git a/test_suite/tests/ui/borrow/empty_lifetimes.stderr b/test_suite/tests/ui/borrow/empty_lifetimes.stderr index 69b7b039..c690e2df 100644 --- a/test_suite/tests/ui/borrow/empty_lifetimes.stderr +++ b/test_suite/tests/ui/borrow/empty_lifetimes.stderr @@ -1,8 +1,8 @@ error: at least one lifetime must be borrowed - --> $DIR/empty_lifetimes.rs:4:10 + --> $DIR/empty_lifetimes.rs:6:22 | -4 | #[derive(Deserialize)] - | ^^^^^^^^^^^ +6 | #[serde(borrow = "")] + | ^^ error: aborting due to previous error diff --git a/test_suite/tests/ui/borrow/no_lifetimes.stderr b/test_suite/tests/ui/borrow/no_lifetimes.stderr index 84ea8f30..937d5d60 100644 --- a/test_suite/tests/ui/borrow/no_lifetimes.stderr +++ b/test_suite/tests/ui/borrow/no_lifetimes.stderr @@ -1,8 +1,9 @@ error: field `s` has no lifetimes to borrow - --> $DIR/no_lifetimes.rs:4:10 + --> $DIR/no_lifetimes.rs:6:5 | -4 | #[derive(Deserialize)] - | ^^^^^^^^^^^ +6 | / #[serde(borrow)] +7 | | s: String, + | |_____________^ error: aborting due to previous error diff --git a/test_suite/tests/ui/borrow/struct_variant.stderr b/test_suite/tests/ui/borrow/struct_variant.stderr index a2c51dc3..3a2a28cc 100644 --- a/test_suite/tests/ui/borrow/struct_variant.stderr +++ b/test_suite/tests/ui/borrow/struct_variant.stderr @@ -1,8 +1,9 @@ error: #[serde(borrow)] may only be used on newtype variants - --> $DIR/struct_variant.rs:7:10 - | -7 | #[derive(Deserialize)] - | ^^^^^^^^^^^ + --> $DIR/struct_variant.rs:9:5 + | +9 | / #[serde(borrow)] +10 | | S { s: Str<'a> }, + | |____________________^ error: aborting due to previous error diff --git a/test_suite/tests/ui/borrow/wrong_lifetime.stderr b/test_suite/tests/ui/borrow/wrong_lifetime.stderr index 3359b180..d69cef4b 100644 --- a/test_suite/tests/ui/borrow/wrong_lifetime.stderr +++ b/test_suite/tests/ui/borrow/wrong_lifetime.stderr @@ -1,8 +1,9 @@ error: field `s` does not have lifetime 'b - --> $DIR/wrong_lifetime.rs:4:10 + --> $DIR/wrong_lifetime.rs:6:5 | -4 | #[derive(Deserialize)] - | ^^^^^^^^^^^ +6 | / #[serde(borrow = "'b")] +7 | | s: &'a str, + | |______________^ error: aborting due to previous error diff --git a/test_suite/tests/ui/conflict/adjacent-tag.stderr b/test_suite/tests/ui/conflict/adjacent-tag.stderr index 89481d88..2576110e 100644 --- a/test_suite/tests/ui/conflict/adjacent-tag.stderr +++ b/test_suite/tests/ui/conflict/adjacent-tag.stderr @@ -1,8 +1,12 @@ error: enum tags `conflict` for type and content conflict with each other - --> $DIR/adjacent-tag.rs:4:10 + --> $DIR/adjacent-tag.rs:5:1 | -4 | #[derive(Serialize)] - | ^^^^^^^^^ +5 | / #[serde(tag = "conflict", content = "conflict")] +6 | | enum E { +7 | | A, +8 | | B, +9 | | } + | |_^ error: aborting due to previous error diff --git a/test_suite/tests/ui/conflict/flatten-newtype-struct.stderr b/test_suite/tests/ui/conflict/flatten-newtype-struct.stderr index 50e93191..a24d003a 100644 --- a/test_suite/tests/ui/conflict/flatten-newtype-struct.stderr +++ b/test_suite/tests/ui/conflict/flatten-newtype-struct.stderr @@ -1,8 +1,8 @@ error: #[serde(flatten)] cannot be used on newtype structs - --> $DIR/flatten-newtype-struct.rs:4:10 + --> $DIR/flatten-newtype-struct.rs:5:12 | -4 | #[derive(Serialize)] - | ^^^^^^^^^ +5 | struct Foo(#[serde(flatten)] HashMap); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/test_suite/tests/ui/conflict/flatten-skip-deserializing.stderr b/test_suite/tests/ui/conflict/flatten-skip-deserializing.stderr index 1c53049c..875c7cb5 100644 --- a/test_suite/tests/ui/conflict/flatten-skip-deserializing.stderr +++ b/test_suite/tests/ui/conflict/flatten-skip-deserializing.stderr @@ -1,8 +1,9 @@ -error: #[serde(flatten] can not be combined with #[serde(skip_deserializing)] - --> $DIR/flatten-skip-deserializing.rs:4:10 +error: #[serde(flatten)] can not be combined with #[serde(skip_deserializing)] + --> $DIR/flatten-skip-deserializing.rs:6:5 | -4 | #[derive(Deserialize)] - | ^^^^^^^^^^^ +6 | / #[serde(flatten, skip_deserializing)] +7 | | other: Other, + | |________________^ error: aborting due to previous error diff --git a/test_suite/tests/ui/conflict/flatten-skip-serializing-if.stderr b/test_suite/tests/ui/conflict/flatten-skip-serializing-if.stderr index 9f2fecc2..7ce4bbf2 100644 --- a/test_suite/tests/ui/conflict/flatten-skip-serializing-if.stderr +++ b/test_suite/tests/ui/conflict/flatten-skip-serializing-if.stderr @@ -1,8 +1,9 @@ -error: #[serde(flatten] can not be combined with #[serde(skip_serializing_if = "...")] - --> $DIR/flatten-skip-serializing-if.rs:4:10 +error: #[serde(flatten)] can not be combined with #[serde(skip_serializing_if = "...")] + --> $DIR/flatten-skip-serializing-if.rs:6:5 | -4 | #[derive(Serialize)] - | ^^^^^^^^^ +6 | / #[serde(flatten, skip_serializing_if = "Option::is_none")] +7 | | other: Option, + | |________________________^ error: aborting due to previous error diff --git a/test_suite/tests/ui/conflict/flatten-skip-serializing.stderr b/test_suite/tests/ui/conflict/flatten-skip-serializing.stderr index 32a34c6f..143466e6 100644 --- a/test_suite/tests/ui/conflict/flatten-skip-serializing.stderr +++ b/test_suite/tests/ui/conflict/flatten-skip-serializing.stderr @@ -1,8 +1,9 @@ -error: #[serde(flatten] can not be combined with #[serde(skip_serializing)] - --> $DIR/flatten-skip-serializing.rs:4:10 +error: #[serde(flatten)] can not be combined with #[serde(skip_serializing)] + --> $DIR/flatten-skip-serializing.rs:6:5 | -4 | #[derive(Serialize)] - | ^^^^^^^^^ +6 | / #[serde(flatten, skip_serializing)] +7 | | other: Other, + | |________________^ error: aborting due to previous error diff --git a/test_suite/tests/ui/conflict/flatten-tuple-struct.stderr b/test_suite/tests/ui/conflict/flatten-tuple-struct.stderr index ce9f3590..ad859a31 100644 --- a/test_suite/tests/ui/conflict/flatten-tuple-struct.stderr +++ b/test_suite/tests/ui/conflict/flatten-tuple-struct.stderr @@ -1,8 +1,8 @@ error: #[serde(flatten)] cannot be used on tuple structs - --> $DIR/flatten-tuple-struct.rs:4:10 + --> $DIR/flatten-tuple-struct.rs:5:17 | -4 | #[derive(Serialize)] - | ^^^^^^^^^ +5 | struct Foo(u32, #[serde(flatten)] HashMap); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/test_suite/tests/ui/conflict/internal-tag.stderr b/test_suite/tests/ui/conflict/internal-tag.stderr index c4b3bb43..dd535ef7 100644 --- a/test_suite/tests/ui/conflict/internal-tag.stderr +++ b/test_suite/tests/ui/conflict/internal-tag.stderr @@ -1,8 +1,14 @@ error: variant field name `conflict` conflicts with internal tag - --> $DIR/internal-tag.rs:4:10 - | -4 | #[derive(Serialize)] - | ^^^^^^^^^ + --> $DIR/internal-tag.rs:5:1 + | +5 | / #[serde(tag = "conflict")] +6 | | enum E { +7 | | A { +8 | | #[serde(rename = "conflict")] +9 | | x: (), +10 | | }, +11 | | } + | |_^ error: aborting due to previous error diff --git a/test_suite/tests/ui/default-attribute/enum.stderr b/test_suite/tests/ui/default-attribute/enum.stderr index 63bdd412..72a8d9d9 100644 --- a/test_suite/tests/ui/default-attribute/enum.stderr +++ b/test_suite/tests/ui/default-attribute/enum.stderr @@ -1,8 +1,8 @@ error: #[serde(default)] can only be used on structs with named fields - --> $DIR/enum.rs:4:10 + --> $DIR/enum.rs:6:1 | -4 | #[derive(Deserialize)] - | ^^^^^^^^^^^ +6 | enum E { + | ^^^^ error: aborting due to previous error diff --git a/test_suite/tests/ui/default-attribute/nameless_struct_fields.stderr b/test_suite/tests/ui/default-attribute/nameless_struct_fields.stderr index e8947395..52984f83 100644 --- a/test_suite/tests/ui/default-attribute/nameless_struct_fields.stderr +++ b/test_suite/tests/ui/default-attribute/nameless_struct_fields.stderr @@ -1,8 +1,8 @@ error: #[serde(default)] can only be used on structs with named fields - --> $DIR/nameless_struct_fields.rs:4:10 + --> $DIR/nameless_struct_fields.rs:6:9 | -4 | #[derive(Deserialize)] - | ^^^^^^^^^^^ +6 | struct T(u8, u8); + | ^^^^^^^^ error: aborting due to previous error diff --git a/test_suite/tests/ui/duplicate-attribute/rename-and-ser.stderr b/test_suite/tests/ui/duplicate-attribute/rename-and-ser.stderr index 6da3593c..46bf2036 100644 --- a/test_suite/tests/ui/duplicate-attribute/rename-and-ser.stderr +++ b/test_suite/tests/ui/duplicate-attribute/rename-and-ser.stderr @@ -1,8 +1,8 @@ error: unknown serde field attribute `serialize` - --> $DIR/rename-and-ser.rs:4:10 + --> $DIR/rename-and-ser.rs:6:27 | -4 | #[derive(Serialize)] - | ^^^^^^^^^ +6 | #[serde(rename = "x", serialize = "y")] + | ^^^^^^^^^ error: aborting due to previous error diff --git a/test_suite/tests/ui/duplicate-attribute/rename-rename-de.stderr b/test_suite/tests/ui/duplicate-attribute/rename-rename-de.stderr index 8ad872da..9c425d82 100644 --- a/test_suite/tests/ui/duplicate-attribute/rename-rename-de.stderr +++ b/test_suite/tests/ui/duplicate-attribute/rename-rename-de.stderr @@ -1,8 +1,8 @@ error: duplicate serde attribute `rename` - --> $DIR/rename-rename-de.rs:4:10 + --> $DIR/rename-rename-de.rs:7:13 | -4 | #[derive(Serialize)] - | ^^^^^^^^^ +7 | #[serde(rename(deserialize = "y"))] + | ^^^^^^ error: aborting due to previous error diff --git a/test_suite/tests/ui/duplicate-attribute/rename-ser-rename-ser.stderr b/test_suite/tests/ui/duplicate-attribute/rename-ser-rename-ser.stderr index 2fd3b014..e0f48d03 100644 --- a/test_suite/tests/ui/duplicate-attribute/rename-ser-rename-ser.stderr +++ b/test_suite/tests/ui/duplicate-attribute/rename-ser-rename-ser.stderr @@ -1,8 +1,8 @@ error: duplicate serde attribute `rename` - --> $DIR/rename-ser-rename-ser.rs:4:10 + --> $DIR/rename-ser-rename-ser.rs:6:38 | -4 | #[derive(Serialize)] - | ^^^^^^^^^ +6 | #[serde(rename(serialize = "x"), rename(serialize = "y"))] + | ^^^^^^ error: aborting due to previous error diff --git a/test_suite/tests/ui/duplicate-attribute/rename-ser-rename.stderr b/test_suite/tests/ui/duplicate-attribute/rename-ser-rename.stderr index 82f5e76b..f4621648 100644 --- a/test_suite/tests/ui/duplicate-attribute/rename-ser-rename.stderr +++ b/test_suite/tests/ui/duplicate-attribute/rename-ser-rename.stderr @@ -1,8 +1,8 @@ error: duplicate serde attribute `rename` - --> $DIR/rename-ser-rename.rs:4:10 + --> $DIR/rename-ser-rename.rs:7:13 | -4 | #[derive(Serialize)] - | ^^^^^^^^^ +7 | #[serde(rename = "y")] + | ^^^^^^ error: aborting due to previous error diff --git a/test_suite/tests/ui/duplicate-attribute/rename-ser-ser.stderr b/test_suite/tests/ui/duplicate-attribute/rename-ser-ser.stderr index 3276c3dd..89a0810b 100644 --- a/test_suite/tests/ui/duplicate-attribute/rename-ser-ser.stderr +++ b/test_suite/tests/ui/duplicate-attribute/rename-ser-ser.stderr @@ -1,8 +1,8 @@ error: duplicate serde attribute `rename` - --> $DIR/rename-ser-ser.rs:4:10 + --> $DIR/rename-ser-ser.rs:6:37 | -4 | #[derive(Serialize)] - | ^^^^^^^^^ +6 | #[serde(rename(serialize = "x", serialize = "y"))] + | ^^^^^^^^^ error: aborting due to previous error diff --git a/test_suite/tests/ui/duplicate-attribute/two-rename-ser.stderr b/test_suite/tests/ui/duplicate-attribute/two-rename-ser.stderr index 7efb8f0b..a8f5fabc 100644 --- a/test_suite/tests/ui/duplicate-attribute/two-rename-ser.stderr +++ b/test_suite/tests/ui/duplicate-attribute/two-rename-ser.stderr @@ -1,8 +1,8 @@ error: duplicate serde attribute `rename` - --> $DIR/two-rename-ser.rs:4:10 + --> $DIR/two-rename-ser.rs:7:13 | -4 | #[derive(Serialize)] - | ^^^^^^^^^ +7 | #[serde(rename(serialize = "y"))] + | ^^^^^^ error: aborting due to previous error diff --git a/test_suite/tests/ui/duplicate-attribute/with-and-serialize-with.stderr b/test_suite/tests/ui/duplicate-attribute/with-and-serialize-with.stderr index fd6dab3e..153cd318 100644 --- a/test_suite/tests/ui/duplicate-attribute/with-and-serialize-with.stderr +++ b/test_suite/tests/ui/duplicate-attribute/with-and-serialize-with.stderr @@ -1,8 +1,8 @@ error: duplicate serde attribute `serialize_with` - --> $DIR/with-and-serialize-with.rs:4:10 + --> $DIR/with-and-serialize-with.rs:6:25 | -4 | #[derive(Serialize)] - | ^^^^^^^^^ +6 | #[serde(with = "w", serialize_with = "s")] + | ^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/test_suite/tests/ui/enum-representation/internal-tuple-variant.stderr b/test_suite/tests/ui/enum-representation/internal-tuple-variant.stderr index ec37e181..b6c823b1 100644 --- a/test_suite/tests/ui/enum-representation/internal-tuple-variant.stderr +++ b/test_suite/tests/ui/enum-representation/internal-tuple-variant.stderr @@ -1,8 +1,8 @@ error: #[serde(tag = "...")] cannot be used with tuple variants - --> $DIR/internal-tuple-variant.rs:4:10 + --> $DIR/internal-tuple-variant.rs:7:5 | -4 | #[derive(Serialize)] - | ^^^^^^^^^ +7 | Tuple(u8, u8), + | ^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/test_suite/tests/ui/enum-representation/internally-tagged-struct.stderr b/test_suite/tests/ui/enum-representation/internally-tagged-struct.stderr index a0b6e4e8..91d5ce1e 100644 --- a/test_suite/tests/ui/enum-representation/internally-tagged-struct.stderr +++ b/test_suite/tests/ui/enum-representation/internally-tagged-struct.stderr @@ -1,8 +1,8 @@ error: #[serde(tag = "...")] can only be used on enums - --> $DIR/internally-tagged-struct.rs:4:10 + --> $DIR/internally-tagged-struct.rs:6:1 | -4 | #[derive(Serialize)] - | ^^^^^^^^^ +6 | struct S; + | ^^^^^^ error: aborting due to previous error diff --git a/test_suite/tests/ui/enum-representation/untagged-and-internal.stderr b/test_suite/tests/ui/enum-representation/untagged-and-internal.stderr index 196b1d01..8091922b 100644 --- a/test_suite/tests/ui/enum-representation/untagged-and-internal.stderr +++ b/test_suite/tests/ui/enum-representation/untagged-and-internal.stderr @@ -1,8 +1,14 @@ error: enum cannot be both untagged and internally tagged - --> $DIR/untagged-and-internal.rs:4:10 + --> $DIR/untagged-and-internal.rs:5:9 | -4 | #[derive(Serialize)] - | ^^^^^^^^^ +5 | #[serde(untagged)] + | ^^^^^^^^ -error: aborting due to previous error +error: enum cannot be both untagged and internally tagged + --> $DIR/untagged-and-internal.rs:6:9 + | +6 | #[serde(tag = "type")] + | ^^^ + +error: aborting due to 2 previous errors diff --git a/test_suite/tests/ui/enum-representation/untagged-struct.stderr b/test_suite/tests/ui/enum-representation/untagged-struct.stderr index 70ad1807..4b6051c1 100644 --- a/test_suite/tests/ui/enum-representation/untagged-struct.stderr +++ b/test_suite/tests/ui/enum-representation/untagged-struct.stderr @@ -1,8 +1,8 @@ error: #[serde(untagged)] can only be used on enums - --> $DIR/untagged-struct.rs:4:10 + --> $DIR/untagged-struct.rs:6:1 | -4 | #[derive(Serialize)] - | ^^^^^^^^^ +6 | struct S; + | ^^^^^^ error: aborting due to previous error diff --git a/test_suite/tests/ui/identifier/both.stderr b/test_suite/tests/ui/identifier/both.stderr index 4d21a047..4a471c7e 100644 --- a/test_suite/tests/ui/identifier/both.stderr +++ b/test_suite/tests/ui/identifier/both.stderr @@ -1,8 +1,14 @@ -error: `field_identifier` and `variant_identifier` cannot both be set - --> $DIR/both.rs:4:10 +error: #[serde(field_identifier)] and #[serde(variant_identifier)] cannot both be set + --> $DIR/both.rs:5:9 | -4 | #[derive(Deserialize)] - | ^^^^^^^^^^^ +5 | #[serde(field_identifier, variant_identifier)] + | ^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: #[serde(field_identifier)] and #[serde(variant_identifier)] cannot both be set + --> $DIR/both.rs:5:27 + | +5 | #[serde(field_identifier, variant_identifier)] + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors diff --git a/test_suite/tests/ui/identifier/field_struct.stderr b/test_suite/tests/ui/identifier/field_struct.stderr index 5463c018..a5c2c6cb 100644 --- a/test_suite/tests/ui/identifier/field_struct.stderr +++ b/test_suite/tests/ui/identifier/field_struct.stderr @@ -1,8 +1,8 @@ -error: `field_identifier` can only be used on an enum - --> $DIR/field_struct.rs:4:10 +error: #[serde(field_identifier)] can only be used on an enum + --> $DIR/field_struct.rs:6:1 | -4 | #[derive(Deserialize)] - | ^^^^^^^^^^^ +6 | struct S; + | ^^^^^^ error: aborting due to previous error diff --git a/test_suite/tests/ui/identifier/field_tuple.stderr b/test_suite/tests/ui/identifier/field_tuple.stderr index d5893a9d..0f36ce7e 100644 --- a/test_suite/tests/ui/identifier/field_tuple.stderr +++ b/test_suite/tests/ui/identifier/field_tuple.stderr @@ -1,8 +1,8 @@ -error: field_identifier may only contain unit variants - --> $DIR/field_tuple.rs:4:10 +error: #[serde(field_identifier)] may only contain unit variants + --> $DIR/field_tuple.rs:8:5 | -4 | #[derive(Deserialize)] - | ^^^^^^^^^^^ +8 | B(u8, u8), + | ^^^^^^^^^ error: aborting due to previous error diff --git a/test_suite/tests/ui/identifier/newtype_not_last.stderr b/test_suite/tests/ui/identifier/newtype_not_last.stderr index 539639b5..d095ab82 100644 --- a/test_suite/tests/ui/identifier/newtype_not_last.stderr +++ b/test_suite/tests/ui/identifier/newtype_not_last.stderr @@ -1,8 +1,8 @@ error: `Other` must be the last variant - --> $DIR/newtype_not_last.rs:4:10 + --> $DIR/newtype_not_last.rs:8:5 | -4 | #[derive(Deserialize)] - | ^^^^^^^^^^^ +8 | Other(String), + | ^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/test_suite/tests/ui/identifier/not_unit.stderr b/test_suite/tests/ui/identifier/not_unit.stderr index 82b7afbc..5ee7dbc6 100644 --- a/test_suite/tests/ui/identifier/not_unit.stderr +++ b/test_suite/tests/ui/identifier/not_unit.stderr @@ -1,8 +1,9 @@ error: #[serde(other)] must be on a unit variant - --> $DIR/not_unit.rs:4:10 + --> $DIR/not_unit.rs:8:5 | -4 | #[derive(Deserialize)] - | ^^^^^^^^^^^ +8 | / #[serde(other)] +9 | | Other(u8, u8), + | |_________________^ error: aborting due to previous error diff --git a/test_suite/tests/ui/identifier/other_not_last.stderr b/test_suite/tests/ui/identifier/other_not_last.stderr index c1eb6c2f..ba83a68b 100644 --- a/test_suite/tests/ui/identifier/other_not_last.stderr +++ b/test_suite/tests/ui/identifier/other_not_last.stderr @@ -1,8 +1,9 @@ -error: #[serde(other)] must be the last variant - --> $DIR/other_not_last.rs:4:10 +error: #[serde(other)] must be on the last variant + --> $DIR/other_not_last.rs:8:5 | -4 | #[derive(Deserialize)] - | ^^^^^^^^^^^ +8 | / #[serde(other)] +9 | | Other, + | |_________^ error: aborting due to previous error diff --git a/test_suite/tests/ui/identifier/serialize.stderr b/test_suite/tests/ui/identifier/serialize.stderr index 2327bb51..474cd57d 100644 --- a/test_suite/tests/ui/identifier/serialize.stderr +++ b/test_suite/tests/ui/identifier/serialize.stderr @@ -1,8 +1,12 @@ error: field identifiers cannot be serialized - --> $DIR/serialize.rs:4:10 + --> $DIR/serialize.rs:5:1 | -4 | #[derive(Serialize)] - | ^^^^^^^^^ +5 | / #[serde(field_identifier)] +6 | | enum F { +7 | | A, +8 | | B, +9 | | } + | |_^ error: aborting due to previous error diff --git a/test_suite/tests/ui/identifier/variant_struct.stderr b/test_suite/tests/ui/identifier/variant_struct.stderr index 9d5d3c1d..e81cf133 100644 --- a/test_suite/tests/ui/identifier/variant_struct.stderr +++ b/test_suite/tests/ui/identifier/variant_struct.stderr @@ -1,8 +1,8 @@ -error: `variant_identifier` can only be used on an enum - --> $DIR/variant_struct.rs:4:10 +error: #[serde(variant_identifier)] can only be used on an enum + --> $DIR/variant_struct.rs:6:1 | -4 | #[derive(Deserialize)] - | ^^^^^^^^^^^ +6 | struct S; + | ^^^^^^ error: aborting due to previous error diff --git a/test_suite/tests/ui/identifier/variant_tuple.stderr b/test_suite/tests/ui/identifier/variant_tuple.stderr index 8a9ff362..b90aed1b 100644 --- a/test_suite/tests/ui/identifier/variant_tuple.stderr +++ b/test_suite/tests/ui/identifier/variant_tuple.stderr @@ -1,8 +1,8 @@ -error: variant_identifier may only contain unit variants - --> $DIR/variant_tuple.rs:4:10 +error: #[serde(variant_identifier)] may only contain unit variants + --> $DIR/variant_tuple.rs:8:5 | -4 | #[derive(Deserialize)] - | ^^^^^^^^^^^ +8 | B(u8, u8), + | ^^^^^^^^^ error: aborting due to previous error diff --git a/test_suite/tests/ui/precondition/deserialize_de_lifetime.stderr b/test_suite/tests/ui/precondition/deserialize_de_lifetime.stderr index 94e2df57..db2d83af 100644 --- a/test_suite/tests/ui/precondition/deserialize_de_lifetime.stderr +++ b/test_suite/tests/ui/precondition/deserialize_de_lifetime.stderr @@ -1,8 +1,8 @@ error: cannot deserialize when there is a lifetime parameter called 'de - --> $DIR/deserialize_de_lifetime.rs:4:10 + --> $DIR/deserialize_de_lifetime.rs:5:10 | -4 | #[derive(Deserialize)] - | ^^^^^^^^^^^ +5 | struct S<'de> { + | ^^^ error: aborting due to previous error diff --git a/test_suite/tests/ui/precondition/deserialize_dst.stderr b/test_suite/tests/ui/precondition/deserialize_dst.stderr index 9447df5c..9efab0e1 100644 --- a/test_suite/tests/ui/precondition/deserialize_dst.stderr +++ b/test_suite/tests/ui/precondition/deserialize_dst.stderr @@ -1,8 +1,11 @@ error: cannot deserialize a dynamically sized struct - --> $DIR/deserialize_dst.rs:4:10 + --> $DIR/deserialize_dst.rs:5:1 | -4 | #[derive(Deserialize)] - | ^^^^^^^^^^^ +5 | / struct S { +6 | | string: String, +7 | | slice: [u8], +8 | | } + | |_^ error: aborting due to previous error diff --git a/test_suite/tests/ui/remote/bad_getter.stderr b/test_suite/tests/ui/remote/bad_getter.stderr index 89a73c76..9971860f 100644 --- a/test_suite/tests/ui/remote/bad_getter.stderr +++ b/test_suite/tests/ui/remote/bad_getter.stderr @@ -1,8 +1,8 @@ error: failed to parse path: "~~~" - --> $DIR/bad_getter.rs:10:10 + --> $DIR/bad_getter.rs:13:22 | -10 | #[derive(Serialize)] - | ^^^^^^^^^ +13 | #[serde(getter = "~~~")] + | ^^^^^ error: aborting due to previous error diff --git a/test_suite/tests/ui/remote/bad_remote.stderr b/test_suite/tests/ui/remote/bad_remote.stderr index a88cfefa..ec87ed41 100644 --- a/test_suite/tests/ui/remote/bad_remote.stderr +++ b/test_suite/tests/ui/remote/bad_remote.stderr @@ -1,8 +1,8 @@ error: failed to parse path: "~~~" - --> $DIR/bad_remote.rs:10:10 + --> $DIR/bad_remote.rs:11:18 | -10 | #[derive(Serialize)] - | ^^^^^^^^^ +11 | #[serde(remote = "~~~")] + | ^^^^^ error: aborting due to previous error diff --git a/test_suite/tests/ui/remote/enum_getter.stderr b/test_suite/tests/ui/remote/enum_getter.stderr index 637955e4..cb22c709 100644 --- a/test_suite/tests/ui/remote/enum_getter.stderr +++ b/test_suite/tests/ui/remote/enum_getter.stderr @@ -1,8 +1,14 @@ error: #[serde(getter = "...")] is not allowed in an enum - --> $DIR/enum_getter.rs:10:10 + --> $DIR/enum_getter.rs:11:1 | -10 | #[derive(Serialize)] - | ^^^^^^^^^ +11 | / #[serde(remote = "remote::E")] +12 | | pub enum E { +13 | | A { +14 | | #[serde(getter = "get_a")] +15 | | a: u8, +16 | | }, +17 | | } + | |_^ error: aborting due to previous error diff --git a/test_suite/tests/ui/remote/nonremote_getter.stderr b/test_suite/tests/ui/remote/nonremote_getter.stderr index 7b0fbdaa..34b504be 100644 --- a/test_suite/tests/ui/remote/nonremote_getter.stderr +++ b/test_suite/tests/ui/remote/nonremote_getter.stderr @@ -1,8 +1,11 @@ error: #[serde(getter = "...")] can only be used in structs that have #[serde(remote = "...")] - --> $DIR/nonremote_getter.rs:4:10 + --> $DIR/nonremote_getter.rs:5:1 | -4 | #[derive(Serialize)] - | ^^^^^^^^^ +5 | / struct S { +6 | | #[serde(getter = "S::get")] +7 | | a: u8, +8 | | } + | |_^ error: aborting due to previous error diff --git a/test_suite/tests/ui/transparent/at_most_one.stderr b/test_suite/tests/ui/transparent/at_most_one.stderr index 76ad5923..904f014d 100644 --- a/test_suite/tests/ui/transparent/at_most_one.stderr +++ b/test_suite/tests/ui/transparent/at_most_one.stderr @@ -1,8 +1,12 @@ error: #[serde(transparent)] requires struct to have at most one transparent field - --> $DIR/at_most_one.rs:4:10 + --> $DIR/at_most_one.rs:5:1 | -4 | #[derive(Serialize)] - | ^^^^^^^^^ +5 | / #[serde(transparent)] +6 | | struct S { +7 | | a: u8, +8 | | b: u8, +9 | | } + | |_^ error: aborting due to previous error diff --git a/test_suite/tests/ui/transparent/de_at_least_one.stderr b/test_suite/tests/ui/transparent/de_at_least_one.stderr index fa04c007..95a8f7ff 100644 --- a/test_suite/tests/ui/transparent/de_at_least_one.stderr +++ b/test_suite/tests/ui/transparent/de_at_least_one.stderr @@ -1,8 +1,14 @@ error: #[serde(transparent)] requires at least one field that is neither skipped nor has a default - --> $DIR/de_at_least_one.rs:4:10 - | -4 | #[derive(Deserialize)] - | ^^^^^^^^^^^ + --> $DIR/de_at_least_one.rs:5:1 + | +5 | / #[serde(transparent)] +6 | | struct S { +7 | | #[serde(skip)] +8 | | a: u8, +9 | | #[serde(default)] +10 | | b: u8, +11 | | } + | |_^ error: aborting due to previous error diff --git a/test_suite/tests/ui/transparent/ser_at_least_one.stderr b/test_suite/tests/ui/transparent/ser_at_least_one.stderr index 0b3cc87b..46226078 100644 --- a/test_suite/tests/ui/transparent/ser_at_least_one.stderr +++ b/test_suite/tests/ui/transparent/ser_at_least_one.stderr @@ -1,8 +1,12 @@ error: #[serde(transparent)] requires at least one field that is not skipped - --> $DIR/ser_at_least_one.rs:4:10 + --> $DIR/ser_at_least_one.rs:5:1 | -4 | #[derive(Serialize)] - | ^^^^^^^^^ +5 | / #[serde(transparent)] +6 | | struct S { +7 | | #[serde(skip)] +8 | | a: u8, +9 | | } + | |_^ error: aborting due to previous error diff --git a/test_suite/tests/ui/type-attribute/from.stderr b/test_suite/tests/ui/type-attribute/from.stderr index 3638329d..acb654f5 100644 --- a/test_suite/tests/ui/type-attribute/from.stderr +++ b/test_suite/tests/ui/type-attribute/from.stderr @@ -1,8 +1,8 @@ error: failed to parse type: from = "Option $DIR/from.rs:4:10 + --> $DIR/from.rs:5:16 | -4 | #[derive(Deserialize)] - | ^^^^^^^^^^^ +5 | #[serde(from = "Option $DIR/into.rs:4:10 + --> $DIR/into.rs:5:16 | -4 | #[derive(Serialize)] - | ^^^^^^^^^ +5 | #[serde(into = "Option $DIR/container.rs:4:10 + --> $DIR/container.rs:5:9 | -4 | #[derive(Serialize)] - | ^^^^^^^^^ +5 | #[serde(abc = "xyz")] + | ^^^ error: aborting due to previous error diff --git a/test_suite/tests/ui/unknown-attribute/field.stderr b/test_suite/tests/ui/unknown-attribute/field.stderr index de38fb24..e5d0ca73 100644 --- a/test_suite/tests/ui/unknown-attribute/field.stderr +++ b/test_suite/tests/ui/unknown-attribute/field.stderr @@ -1,8 +1,8 @@ error: unknown serde field attribute `abc` - --> $DIR/field.rs:4:10 + --> $DIR/field.rs:6:13 | -4 | #[derive(Serialize)] - | ^^^^^^^^^ +6 | #[serde(abc = "xyz")] + | ^^^ error: aborting due to previous error diff --git a/test_suite/tests/ui/unknown-attribute/variant.stderr b/test_suite/tests/ui/unknown-attribute/variant.stderr index e785d7f0..273d7c0d 100644 --- a/test_suite/tests/ui/unknown-attribute/variant.stderr +++ b/test_suite/tests/ui/unknown-attribute/variant.stderr @@ -1,8 +1,8 @@ error: unknown serde variant attribute `abc` - --> $DIR/variant.rs:4:10 + --> $DIR/variant.rs:6:13 | -4 | #[derive(Serialize)] - | ^^^^^^^^^ +6 | #[serde(abc = "xyz")] + | ^^^ error: aborting due to previous error diff --git a/test_suite/tests/ui/with-variant/skip_de_newtype_field.stderr b/test_suite/tests/ui/with-variant/skip_de_newtype_field.stderr index b6a1757f..6fa19d4c 100644 --- a/test_suite/tests/ui/with-variant/skip_de_newtype_field.stderr +++ b/test_suite/tests/ui/with-variant/skip_de_newtype_field.stderr @@ -1,8 +1,9 @@ -error: variant `Newtype` cannot have both #[serde(deserialize_with)] and a field 0 marked with #[serde(skip_deserializing)] - --> $DIR/skip_de_newtype_field.rs:4:10 +error: variant `Newtype` cannot have both #[serde(deserialize_with)] and a field #0 marked with #[serde(skip_deserializing)] + --> $DIR/skip_de_newtype_field.rs:6:5 | -4 | #[derive(Deserialize)] - | ^^^^^^^^^^^ +6 | / #[serde(deserialize_with = "deserialize_some_newtype_variant")] +7 | | Newtype(#[serde(skip_deserializing)] String), + | |________________________________________________^ error: aborting due to previous error diff --git a/test_suite/tests/ui/with-variant/skip_de_struct_field.stderr b/test_suite/tests/ui/with-variant/skip_de_struct_field.stderr index 9f28bdad..a7a848f7 100644 --- a/test_suite/tests/ui/with-variant/skip_de_struct_field.stderr +++ b/test_suite/tests/ui/with-variant/skip_de_struct_field.stderr @@ -1,8 +1,13 @@ error: variant `Struct` cannot have both #[serde(deserialize_with)] and a field `f1` marked with #[serde(skip_deserializing)] - --> $DIR/skip_de_struct_field.rs:4:10 - | -4 | #[derive(Deserialize)] - | ^^^^^^^^^^^ + --> $DIR/skip_de_struct_field.rs:6:5 + | +6 | / #[serde(deserialize_with = "deserialize_some_other_variant")] +7 | | Struct { +8 | | #[serde(skip_deserializing)] +9 | | f1: String, +10 | | f2: u8, +11 | | }, + | |_____^ error: aborting due to previous error diff --git a/test_suite/tests/ui/with-variant/skip_de_tuple_field.stderr b/test_suite/tests/ui/with-variant/skip_de_tuple_field.stderr index 9f853fa4..716e7d12 100644 --- a/test_suite/tests/ui/with-variant/skip_de_tuple_field.stderr +++ b/test_suite/tests/ui/with-variant/skip_de_tuple_field.stderr @@ -1,8 +1,9 @@ -error: variant `Tuple` cannot have both #[serde(deserialize_with)] and a field 0 marked with #[serde(skip_deserializing)] - --> $DIR/skip_de_tuple_field.rs:4:10 +error: variant `Tuple` cannot have both #[serde(deserialize_with)] and a field #0 marked with #[serde(skip_deserializing)] + --> $DIR/skip_de_tuple_field.rs:6:5 | -4 | #[derive(Deserialize)] - | ^^^^^^^^^^^ +6 | / #[serde(deserialize_with = "deserialize_some_other_variant")] +7 | | Tuple(#[serde(skip_deserializing)] String, u8), + | |__________________________________________________^ error: aborting due to previous error diff --git a/test_suite/tests/ui/with-variant/skip_de_whole_variant.stderr b/test_suite/tests/ui/with-variant/skip_de_whole_variant.stderr index 671deb1b..4414d13c 100644 --- a/test_suite/tests/ui/with-variant/skip_de_whole_variant.stderr +++ b/test_suite/tests/ui/with-variant/skip_de_whole_variant.stderr @@ -1,8 +1,10 @@ error: variant `Unit` cannot have both #[serde(deserialize_with)] and #[serde(skip_deserializing)] - --> $DIR/skip_de_whole_variant.rs:4:10 + --> $DIR/skip_de_whole_variant.rs:6:5 | -4 | #[derive(Deserialize)] - | ^^^^^^^^^^^ +6 | / #[serde(deserialize_with = "deserialize_some_unit_variant")] +7 | | #[serde(skip_deserializing)] +8 | | Unit, + | |________^ error: aborting due to previous error diff --git a/test_suite/tests/ui/with-variant/skip_ser_newtype_field.stderr b/test_suite/tests/ui/with-variant/skip_ser_newtype_field.stderr index 4c292fb3..b448c4db 100644 --- a/test_suite/tests/ui/with-variant/skip_ser_newtype_field.stderr +++ b/test_suite/tests/ui/with-variant/skip_ser_newtype_field.stderr @@ -1,8 +1,9 @@ -error: variant `Newtype` cannot have both #[serde(serialize_with)] and a field 0 marked with #[serde(skip_serializing)] - --> $DIR/skip_ser_newtype_field.rs:4:10 +error: variant `Newtype` cannot have both #[serde(serialize_with)] and a field #0 marked with #[serde(skip_serializing)] + --> $DIR/skip_ser_newtype_field.rs:6:5 | -4 | #[derive(Serialize)] - | ^^^^^^^^^ +6 | / #[serde(serialize_with = "serialize_some_newtype_variant")] +7 | | Newtype(#[serde(skip_serializing)] String), + | |______________________________________________^ error: aborting due to previous error diff --git a/test_suite/tests/ui/with-variant/skip_ser_newtype_field_if.stderr b/test_suite/tests/ui/with-variant/skip_ser_newtype_field_if.stderr index 28144158..ff1f717a 100644 --- a/test_suite/tests/ui/with-variant/skip_ser_newtype_field_if.stderr +++ b/test_suite/tests/ui/with-variant/skip_ser_newtype_field_if.stderr @@ -1,8 +1,9 @@ -error: variant `Newtype` cannot have both #[serde(serialize_with)] and a field 0 marked with #[serde(skip_serializing_if)] - --> $DIR/skip_ser_newtype_field_if.rs:4:10 +error: variant `Newtype` cannot have both #[serde(serialize_with)] and a field #0 marked with #[serde(skip_serializing_if)] + --> $DIR/skip_ser_newtype_field_if.rs:6:5 | -4 | #[derive(Serialize)] - | ^^^^^^^^^ +6 | / #[serde(serialize_with = "serialize_some_newtype_variant")] +7 | | Newtype(#[serde(skip_serializing_if = "always")] String), + | |____________________________________________________________^ error: aborting due to previous error diff --git a/test_suite/tests/ui/with-variant/skip_ser_struct_field.stderr b/test_suite/tests/ui/with-variant/skip_ser_struct_field.stderr index 0a2d77d0..4dec7658 100644 --- a/test_suite/tests/ui/with-variant/skip_ser_struct_field.stderr +++ b/test_suite/tests/ui/with-variant/skip_ser_struct_field.stderr @@ -1,8 +1,13 @@ error: variant `Struct` cannot have both #[serde(serialize_with)] and a field `f1` marked with #[serde(skip_serializing)] - --> $DIR/skip_ser_struct_field.rs:4:10 - | -4 | #[derive(Serialize)] - | ^^^^^^^^^ + --> $DIR/skip_ser_struct_field.rs:6:5 + | +6 | / #[serde(serialize_with = "serialize_some_other_variant")] +7 | | Struct { +8 | | #[serde(skip_serializing)] +9 | | f1: String, +10 | | f2: u8, +11 | | }, + | |_____^ error: aborting due to previous error diff --git a/test_suite/tests/ui/with-variant/skip_ser_struct_field_if.stderr b/test_suite/tests/ui/with-variant/skip_ser_struct_field_if.stderr index 2fb86627..51a11453 100644 --- a/test_suite/tests/ui/with-variant/skip_ser_struct_field_if.stderr +++ b/test_suite/tests/ui/with-variant/skip_ser_struct_field_if.stderr @@ -1,8 +1,13 @@ error: variant `Struct` cannot have both #[serde(serialize_with)] and a field `f1` marked with #[serde(skip_serializing_if)] - --> $DIR/skip_ser_struct_field_if.rs:4:10 - | -4 | #[derive(Serialize)] - | ^^^^^^^^^ + --> $DIR/skip_ser_struct_field_if.rs:6:5 + | +6 | / #[serde(serialize_with = "serialize_some_newtype_variant")] +7 | | Struct { +8 | | #[serde(skip_serializing_if = "always")] +9 | | f1: String, +10 | | f2: u8, +11 | | }, + | |_____^ error: aborting due to previous error diff --git a/test_suite/tests/ui/with-variant/skip_ser_tuple_field.stderr b/test_suite/tests/ui/with-variant/skip_ser_tuple_field.stderr index ed671909..1c61e322 100644 --- a/test_suite/tests/ui/with-variant/skip_ser_tuple_field.stderr +++ b/test_suite/tests/ui/with-variant/skip_ser_tuple_field.stderr @@ -1,8 +1,9 @@ -error: variant `Tuple` cannot have both #[serde(serialize_with)] and a field 0 marked with #[serde(skip_serializing)] - --> $DIR/skip_ser_tuple_field.rs:4:10 +error: variant `Tuple` cannot have both #[serde(serialize_with)] and a field #0 marked with #[serde(skip_serializing)] + --> $DIR/skip_ser_tuple_field.rs:6:5 | -4 | #[derive(Serialize)] - | ^^^^^^^^^ +6 | / #[serde(serialize_with = "serialize_some_other_variant")] +7 | | Tuple(#[serde(skip_serializing)] String, u8), + | |________________________________________________^ error: aborting due to previous error diff --git a/test_suite/tests/ui/with-variant/skip_ser_tuple_field_if.stderr b/test_suite/tests/ui/with-variant/skip_ser_tuple_field_if.stderr index 748826c7..b701364f 100644 --- a/test_suite/tests/ui/with-variant/skip_ser_tuple_field_if.stderr +++ b/test_suite/tests/ui/with-variant/skip_ser_tuple_field_if.stderr @@ -1,8 +1,9 @@ -error: variant `Tuple` cannot have both #[serde(serialize_with)] and a field 0 marked with #[serde(skip_serializing_if)] - --> $DIR/skip_ser_tuple_field_if.rs:4:10 +error: variant `Tuple` cannot have both #[serde(serialize_with)] and a field #0 marked with #[serde(skip_serializing_if)] + --> $DIR/skip_ser_tuple_field_if.rs:6:5 | -4 | #[derive(Serialize)] - | ^^^^^^^^^ +6 | / #[serde(serialize_with = "serialize_some_other_variant")] +7 | | Tuple(#[serde(skip_serializing_if = "always")] String, u8), + | |______________________________________________________________^ error: aborting due to previous error diff --git a/test_suite/tests/ui/with-variant/skip_ser_whole_variant.stderr b/test_suite/tests/ui/with-variant/skip_ser_whole_variant.stderr index 56b18a9d..07bd27dc 100644 --- a/test_suite/tests/ui/with-variant/skip_ser_whole_variant.stderr +++ b/test_suite/tests/ui/with-variant/skip_ser_whole_variant.stderr @@ -1,8 +1,10 @@ error: variant `Unit` cannot have both #[serde(serialize_with)] and #[serde(skip_serializing)] - --> $DIR/skip_ser_whole_variant.rs:4:10 + --> $DIR/skip_ser_whole_variant.rs:6:5 | -4 | #[derive(Serialize)] - | ^^^^^^^^^ +6 | / #[serde(serialize_with = "serialize_some_unit_variant")] +7 | | #[serde(skip_serializing)] +8 | | Unit, + | |________^ error: aborting due to previous error From 14a3da9b163871ba0090f415bcdb9135064c8a14 Mon Sep 17 00:00:00 2001 From: hcpl Date: Fri, 30 Nov 2018 03:07:31 +0200 Subject: [PATCH 3/3] Improve UI test coverage With this commit I believe I've covered all `compile_error!`-based errors. --- .../tests/ui/default-attribute/enum_path.rs | 8 ++++++++ .../ui/default-attribute/enum_path.stderr | 8 ++++++++ .../nameless_struct_fields_path.rs | 8 ++++++++ .../nameless_struct_fields_path.stderr | 8 ++++++++ .../ui/enum-representation/content-no-tag.rs | 11 ++++++++++ .../enum-representation/content-no-tag.stderr | 8 ++++++++ .../untagged-and-adjacent.rs | 12 +++++++++++ .../untagged-and-adjacent.stderr | 20 +++++++++++++++++++ .../untagged-and-content.rs | 12 +++++++++++ .../untagged-and-content.stderr | 14 +++++++++++++ .../tests/ui/expected-string/boolean.rs | 10 ++++++++++ .../tests/ui/expected-string/boolean.stderr | 8 ++++++++ .../ui/expected-string/byte_character.rs | 10 ++++++++++ .../ui/expected-string/byte_character.stderr | 8 ++++++++ .../tests/ui/expected-string/byte_string.rs | 10 ++++++++++ .../ui/expected-string/byte_string.stderr | 8 ++++++++ .../tests/ui/expected-string/character.rs | 10 ++++++++++ .../tests/ui/expected-string/character.stderr | 8 ++++++++ test_suite/tests/ui/expected-string/float.rs | 10 ++++++++++ .../tests/ui/expected-string/float.stderr | 8 ++++++++ .../tests/ui/expected-string/integer.rs | 10 ++++++++++ .../tests/ui/expected-string/integer.stderr | 8 ++++++++ .../tests/ui/identifier/other_untagged.rs | 11 ++++++++++ .../tests/ui/identifier/other_untagged.stderr | 9 +++++++++ .../tests/ui/identifier/other_variant.rs | 11 ++++++++++ .../tests/ui/identifier/other_variant.stderr | 9 +++++++++ test_suite/tests/ui/malformed/bound.rs | 10 ++++++++++ test_suite/tests/ui/malformed/bound.stderr | 8 ++++++++ test_suite/tests/ui/malformed/rename.rs | 10 ++++++++++ test_suite/tests/ui/malformed/rename.stderr | 8 ++++++++ .../serialize_field_identifier.rs} | 0 .../serialize_field_identifier.stderr} | 2 +- .../serialize_variant_identifier.rs | 11 ++++++++++ .../serialize_variant_identifier.stderr | 12 +++++++++++ .../rename/container_unknown_rename_rule.rs | 12 +++++++++++ .../container_unknown_rename_rule.stderr | 8 ++++++++ .../ui/rename/variant_unknown_rename_rule.rs | 14 +++++++++++++ .../rename/variant_unknown_rename_rule.stderr | 8 ++++++++ test_suite/tests/ui/transparent/enum.rs | 8 ++++++++ test_suite/tests/ui/transparent/enum.stderr | 9 +++++++++ .../tests/ui/transparent/unit_struct.rs | 8 ++++++++ .../tests/ui/transparent/unit_struct.stderr | 9 +++++++++ test_suite/tests/ui/transparent/with_from.rs | 10 ++++++++++ .../tests/ui/transparent/with_from.stderr | 11 ++++++++++ test_suite/tests/ui/transparent/with_into.rs | 10 ++++++++++ .../tests/ui/transparent/with_into.stderr | 11 ++++++++++ .../tests/ui/unexpected-literal/container.rs | 8 ++++++++ .../ui/unexpected-literal/container.stderr | 8 ++++++++ .../tests/ui/unexpected-literal/field.rs | 10 ++++++++++ .../tests/ui/unexpected-literal/field.stderr | 8 ++++++++ .../tests/ui/unexpected-literal/variant.rs | 10 ++++++++++ .../ui/unexpected-literal/variant.stderr | 8 ++++++++ test_suite/tests/ui/unsupported/union_de.rs | 10 ++++++++++ .../tests/ui/unsupported/union_de.stderr | 11 ++++++++++ test_suite/tests/ui/unsupported/union_ser.rs | 10 ++++++++++ .../tests/ui/unsupported/union_ser.stderr | 11 ++++++++++ 56 files changed, 529 insertions(+), 1 deletion(-) create mode 100644 test_suite/tests/ui/default-attribute/enum_path.rs create mode 100644 test_suite/tests/ui/default-attribute/enum_path.stderr create mode 100644 test_suite/tests/ui/default-attribute/nameless_struct_fields_path.rs create mode 100644 test_suite/tests/ui/default-attribute/nameless_struct_fields_path.stderr create mode 100644 test_suite/tests/ui/enum-representation/content-no-tag.rs create mode 100644 test_suite/tests/ui/enum-representation/content-no-tag.stderr create mode 100644 test_suite/tests/ui/enum-representation/untagged-and-adjacent.rs create mode 100644 test_suite/tests/ui/enum-representation/untagged-and-adjacent.stderr create mode 100644 test_suite/tests/ui/enum-representation/untagged-and-content.rs create mode 100644 test_suite/tests/ui/enum-representation/untagged-and-content.stderr create mode 100644 test_suite/tests/ui/expected-string/boolean.rs create mode 100644 test_suite/tests/ui/expected-string/boolean.stderr create mode 100644 test_suite/tests/ui/expected-string/byte_character.rs create mode 100644 test_suite/tests/ui/expected-string/byte_character.stderr create mode 100644 test_suite/tests/ui/expected-string/byte_string.rs create mode 100644 test_suite/tests/ui/expected-string/byte_string.stderr create mode 100644 test_suite/tests/ui/expected-string/character.rs create mode 100644 test_suite/tests/ui/expected-string/character.stderr create mode 100644 test_suite/tests/ui/expected-string/float.rs create mode 100644 test_suite/tests/ui/expected-string/float.stderr create mode 100644 test_suite/tests/ui/expected-string/integer.rs create mode 100644 test_suite/tests/ui/expected-string/integer.stderr create mode 100644 test_suite/tests/ui/identifier/other_untagged.rs create mode 100644 test_suite/tests/ui/identifier/other_untagged.stderr create mode 100644 test_suite/tests/ui/identifier/other_variant.rs create mode 100644 test_suite/tests/ui/identifier/other_variant.stderr create mode 100644 test_suite/tests/ui/malformed/bound.rs create mode 100644 test_suite/tests/ui/malformed/bound.stderr create mode 100644 test_suite/tests/ui/malformed/rename.rs create mode 100644 test_suite/tests/ui/malformed/rename.stderr rename test_suite/tests/ui/{identifier/serialize.rs => precondition/serialize_field_identifier.rs} (100%) rename test_suite/tests/ui/{identifier/serialize.stderr => precondition/serialize_field_identifier.stderr} (80%) create mode 100644 test_suite/tests/ui/precondition/serialize_variant_identifier.rs create mode 100644 test_suite/tests/ui/precondition/serialize_variant_identifier.stderr create mode 100644 test_suite/tests/ui/rename/container_unknown_rename_rule.rs create mode 100644 test_suite/tests/ui/rename/container_unknown_rename_rule.stderr create mode 100644 test_suite/tests/ui/rename/variant_unknown_rename_rule.rs create mode 100644 test_suite/tests/ui/rename/variant_unknown_rename_rule.stderr create mode 100644 test_suite/tests/ui/transparent/enum.rs create mode 100644 test_suite/tests/ui/transparent/enum.stderr create mode 100644 test_suite/tests/ui/transparent/unit_struct.rs create mode 100644 test_suite/tests/ui/transparent/unit_struct.stderr create mode 100644 test_suite/tests/ui/transparent/with_from.rs create mode 100644 test_suite/tests/ui/transparent/with_from.stderr create mode 100644 test_suite/tests/ui/transparent/with_into.rs create mode 100644 test_suite/tests/ui/transparent/with_into.stderr create mode 100644 test_suite/tests/ui/unexpected-literal/container.rs create mode 100644 test_suite/tests/ui/unexpected-literal/container.stderr create mode 100644 test_suite/tests/ui/unexpected-literal/field.rs create mode 100644 test_suite/tests/ui/unexpected-literal/field.stderr create mode 100644 test_suite/tests/ui/unexpected-literal/variant.rs create mode 100644 test_suite/tests/ui/unexpected-literal/variant.stderr create mode 100644 test_suite/tests/ui/unsupported/union_de.rs create mode 100644 test_suite/tests/ui/unsupported/union_de.stderr create mode 100644 test_suite/tests/ui/unsupported/union_ser.rs create mode 100644 test_suite/tests/ui/unsupported/union_ser.stderr diff --git a/test_suite/tests/ui/default-attribute/enum_path.rs b/test_suite/tests/ui/default-attribute/enum_path.rs new file mode 100644 index 00000000..3c1ff45b --- /dev/null +++ b/test_suite/tests/ui/default-attribute/enum_path.rs @@ -0,0 +1,8 @@ +#[macro_use] +extern crate serde_derive; + +#[derive(Deserialize)] +#[serde(default = "default_e")] +enum E { + S { f: u8 }, +} diff --git a/test_suite/tests/ui/default-attribute/enum_path.stderr b/test_suite/tests/ui/default-attribute/enum_path.stderr new file mode 100644 index 00000000..61e36f68 --- /dev/null +++ b/test_suite/tests/ui/default-attribute/enum_path.stderr @@ -0,0 +1,8 @@ +error: #[serde(default = "...")] can only be used on structs with named fields + --> $DIR/enum_path.rs:6:1 + | +6 | enum E { + | ^^^^ + +error: aborting due to previous error + diff --git a/test_suite/tests/ui/default-attribute/nameless_struct_fields_path.rs b/test_suite/tests/ui/default-attribute/nameless_struct_fields_path.rs new file mode 100644 index 00000000..3dd82f71 --- /dev/null +++ b/test_suite/tests/ui/default-attribute/nameless_struct_fields_path.rs @@ -0,0 +1,8 @@ +#[macro_use] +extern crate serde_derive; + +#[derive(Deserialize)] +#[serde(default = "default_t")] +struct T(u8, u8); + +fn main() {} diff --git a/test_suite/tests/ui/default-attribute/nameless_struct_fields_path.stderr b/test_suite/tests/ui/default-attribute/nameless_struct_fields_path.stderr new file mode 100644 index 00000000..301e8640 --- /dev/null +++ b/test_suite/tests/ui/default-attribute/nameless_struct_fields_path.stderr @@ -0,0 +1,8 @@ +error: #[serde(default = "...")] can only be used on structs with named fields + --> $DIR/nameless_struct_fields_path.rs:6:9 + | +6 | struct T(u8, u8); + | ^^^^^^^^ + +error: aborting due to previous error + diff --git a/test_suite/tests/ui/enum-representation/content-no-tag.rs b/test_suite/tests/ui/enum-representation/content-no-tag.rs new file mode 100644 index 00000000..0506aef4 --- /dev/null +++ b/test_suite/tests/ui/enum-representation/content-no-tag.rs @@ -0,0 +1,11 @@ +#[macro_use] +extern crate serde_derive; + +#[derive(Serialize)] +#[serde(content = "c")] +enum E { + A(u8), + B(String), +} + +fn main() {} diff --git a/test_suite/tests/ui/enum-representation/content-no-tag.stderr b/test_suite/tests/ui/enum-representation/content-no-tag.stderr new file mode 100644 index 00000000..0f05eb9f --- /dev/null +++ b/test_suite/tests/ui/enum-representation/content-no-tag.stderr @@ -0,0 +1,8 @@ +error: #[serde(tag = "...", content = "...")] must be used together + --> $DIR/content-no-tag.rs:5:9 + | +5 | #[serde(content = "c")] + | ^^^^^^^ + +error: aborting due to previous error + diff --git a/test_suite/tests/ui/enum-representation/untagged-and-adjacent.rs b/test_suite/tests/ui/enum-representation/untagged-and-adjacent.rs new file mode 100644 index 00000000..3254735d --- /dev/null +++ b/test_suite/tests/ui/enum-representation/untagged-and-adjacent.rs @@ -0,0 +1,12 @@ +#[macro_use] +extern crate serde_derive; + +#[derive(Serialize)] +#[serde(untagged)] +#[serde(tag = "t", content = "c")] +enum E { + A(u8), + B(String), +} + +fn main() {} diff --git a/test_suite/tests/ui/enum-representation/untagged-and-adjacent.stderr b/test_suite/tests/ui/enum-representation/untagged-and-adjacent.stderr new file mode 100644 index 00000000..8c3d93f9 --- /dev/null +++ b/test_suite/tests/ui/enum-representation/untagged-and-adjacent.stderr @@ -0,0 +1,20 @@ +error: untagged enum cannot have #[serde(tag = "...", content = "...")] + --> $DIR/untagged-and-adjacent.rs:5:9 + | +5 | #[serde(untagged)] + | ^^^^^^^^ + +error: untagged enum cannot have #[serde(tag = "...", content = "...")] + --> $DIR/untagged-and-adjacent.rs:6:9 + | +6 | #[serde(tag = "t", content = "c")] + | ^^^ + +error: untagged enum cannot have #[serde(tag = "...", content = "...")] + --> $DIR/untagged-and-adjacent.rs:6:20 + | +6 | #[serde(tag = "t", content = "c")] + | ^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/test_suite/tests/ui/enum-representation/untagged-and-content.rs b/test_suite/tests/ui/enum-representation/untagged-and-content.rs new file mode 100644 index 00000000..410a84be --- /dev/null +++ b/test_suite/tests/ui/enum-representation/untagged-and-content.rs @@ -0,0 +1,12 @@ +#[macro_use] +extern crate serde_derive; + +#[derive(Serialize)] +#[serde(untagged)] +#[serde(content = "c")] +enum E { + A(u8), + B(String), +} + +fn main() {} diff --git a/test_suite/tests/ui/enum-representation/untagged-and-content.stderr b/test_suite/tests/ui/enum-representation/untagged-and-content.stderr new file mode 100644 index 00000000..a2b0fc0b --- /dev/null +++ b/test_suite/tests/ui/enum-representation/untagged-and-content.stderr @@ -0,0 +1,14 @@ +error: untagged enum cannot have #[serde(content = "...")] + --> $DIR/untagged-and-content.rs:5:9 + | +5 | #[serde(untagged)] + | ^^^^^^^^ + +error: untagged enum cannot have #[serde(content = "...")] + --> $DIR/untagged-and-content.rs:6:9 + | +6 | #[serde(content = "c")] + | ^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/test_suite/tests/ui/expected-string/boolean.rs b/test_suite/tests/ui/expected-string/boolean.rs new file mode 100644 index 00000000..68744bf3 --- /dev/null +++ b/test_suite/tests/ui/expected-string/boolean.rs @@ -0,0 +1,10 @@ +#[macro_use] +extern crate serde_derive; + +#[derive(Serialize)] +struct S { + #[serde(rename = true)] + boolean: (), +} + +fn main() {} diff --git a/test_suite/tests/ui/expected-string/boolean.stderr b/test_suite/tests/ui/expected-string/boolean.stderr new file mode 100644 index 00000000..08ec5caa --- /dev/null +++ b/test_suite/tests/ui/expected-string/boolean.stderr @@ -0,0 +1,8 @@ +error: expected serde rename attribute to be a string: `rename = "..."` + --> $DIR/boolean.rs:6:22 + | +6 | #[serde(rename = true)] + | ^^^^ + +error: aborting due to previous error + diff --git a/test_suite/tests/ui/expected-string/byte_character.rs b/test_suite/tests/ui/expected-string/byte_character.rs new file mode 100644 index 00000000..69c3e8e4 --- /dev/null +++ b/test_suite/tests/ui/expected-string/byte_character.rs @@ -0,0 +1,10 @@ +#[macro_use] +extern crate serde_derive; + +#[derive(Serialize)] +struct S { + #[serde(rename = b'a')] + byte_character: (), +} + +fn main() {} diff --git a/test_suite/tests/ui/expected-string/byte_character.stderr b/test_suite/tests/ui/expected-string/byte_character.stderr new file mode 100644 index 00000000..7e271f9a --- /dev/null +++ b/test_suite/tests/ui/expected-string/byte_character.stderr @@ -0,0 +1,8 @@ +error: expected serde rename attribute to be a string: `rename = "..."` + --> $DIR/byte_character.rs:6:22 + | +6 | #[serde(rename = b'a')] + | ^^^^ + +error: aborting due to previous error + diff --git a/test_suite/tests/ui/expected-string/byte_string.rs b/test_suite/tests/ui/expected-string/byte_string.rs new file mode 100644 index 00000000..6fa365bf --- /dev/null +++ b/test_suite/tests/ui/expected-string/byte_string.rs @@ -0,0 +1,10 @@ +#[macro_use] +extern crate serde_derive; + +#[derive(Serialize)] +struct S { + #[serde(rename = b"byte string")] + byte_string: (), +} + +fn main() {} diff --git a/test_suite/tests/ui/expected-string/byte_string.stderr b/test_suite/tests/ui/expected-string/byte_string.stderr new file mode 100644 index 00000000..44e9dd7f --- /dev/null +++ b/test_suite/tests/ui/expected-string/byte_string.stderr @@ -0,0 +1,8 @@ +error: expected serde rename attribute to be a string: `rename = "..."` + --> $DIR/byte_string.rs:6:22 + | +6 | #[serde(rename = b"byte string")] + | ^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/test_suite/tests/ui/expected-string/character.rs b/test_suite/tests/ui/expected-string/character.rs new file mode 100644 index 00000000..4955a890 --- /dev/null +++ b/test_suite/tests/ui/expected-string/character.rs @@ -0,0 +1,10 @@ +#[macro_use] +extern crate serde_derive; + +#[derive(Serialize)] +struct S { + #[serde(rename = 'a')] + character: (), +} + +fn main() {} diff --git a/test_suite/tests/ui/expected-string/character.stderr b/test_suite/tests/ui/expected-string/character.stderr new file mode 100644 index 00000000..dca61053 --- /dev/null +++ b/test_suite/tests/ui/expected-string/character.stderr @@ -0,0 +1,8 @@ +error: expected serde rename attribute to be a string: `rename = "..."` + --> $DIR/character.rs:6:22 + | +6 | #[serde(rename = 'a')] + | ^^^ + +error: aborting due to previous error + diff --git a/test_suite/tests/ui/expected-string/float.rs b/test_suite/tests/ui/expected-string/float.rs new file mode 100644 index 00000000..c7d895e5 --- /dev/null +++ b/test_suite/tests/ui/expected-string/float.rs @@ -0,0 +1,10 @@ +#[macro_use] +extern crate serde_derive; + +#[derive(Serialize)] +struct S { + #[serde(rename = 3.14)] + float: (), +} + +fn main() {} diff --git a/test_suite/tests/ui/expected-string/float.stderr b/test_suite/tests/ui/expected-string/float.stderr new file mode 100644 index 00000000..a89eb3d3 --- /dev/null +++ b/test_suite/tests/ui/expected-string/float.stderr @@ -0,0 +1,8 @@ +error: expected serde rename attribute to be a string: `rename = "..."` + --> $DIR/float.rs:6:22 + | +6 | #[serde(rename = 3.14)] + | ^^^^ + +error: aborting due to previous error + diff --git a/test_suite/tests/ui/expected-string/integer.rs b/test_suite/tests/ui/expected-string/integer.rs new file mode 100644 index 00000000..664483b4 --- /dev/null +++ b/test_suite/tests/ui/expected-string/integer.rs @@ -0,0 +1,10 @@ +#[macro_use] +extern crate serde_derive; + +#[derive(Serialize)] +struct S { + #[serde(rename = 100)] + integer: (), +} + +fn main() {} diff --git a/test_suite/tests/ui/expected-string/integer.stderr b/test_suite/tests/ui/expected-string/integer.stderr new file mode 100644 index 00000000..2df6df0d --- /dev/null +++ b/test_suite/tests/ui/expected-string/integer.stderr @@ -0,0 +1,8 @@ +error: expected serde rename attribute to be a string: `rename = "..."` + --> $DIR/integer.rs:6:22 + | +6 | #[serde(rename = 100)] + | ^^^ + +error: aborting due to previous error + diff --git a/test_suite/tests/ui/identifier/other_untagged.rs b/test_suite/tests/ui/identifier/other_untagged.rs new file mode 100644 index 00000000..15d12b6e --- /dev/null +++ b/test_suite/tests/ui/identifier/other_untagged.rs @@ -0,0 +1,11 @@ +#[macro_use] +extern crate serde_derive; + +#[derive(Deserialize)] +#[serde(untagged)] +enum F { + #[serde(other)] + Other, +} + +fn main() {} diff --git a/test_suite/tests/ui/identifier/other_untagged.stderr b/test_suite/tests/ui/identifier/other_untagged.stderr new file mode 100644 index 00000000..5b562cbd --- /dev/null +++ b/test_suite/tests/ui/identifier/other_untagged.stderr @@ -0,0 +1,9 @@ +error: #[serde(other)] cannot appear on untagged enum + --> $DIR/other_untagged.rs:7:5 + | +7 | / #[serde(other)] +8 | | Other, + | |_________^ + +error: aborting due to previous error + diff --git a/test_suite/tests/ui/identifier/other_variant.rs b/test_suite/tests/ui/identifier/other_variant.rs new file mode 100644 index 00000000..cbfe9f3e --- /dev/null +++ b/test_suite/tests/ui/identifier/other_variant.rs @@ -0,0 +1,11 @@ +#[macro_use] +extern crate serde_derive; + +#[derive(Deserialize)] +#[serde(variant_identifier)] +enum F { + #[serde(other)] + Other, +} + +fn main() {} diff --git a/test_suite/tests/ui/identifier/other_variant.stderr b/test_suite/tests/ui/identifier/other_variant.stderr new file mode 100644 index 00000000..7fb851c8 --- /dev/null +++ b/test_suite/tests/ui/identifier/other_variant.stderr @@ -0,0 +1,9 @@ +error: #[serde(other)] may not be used on a variant identifier + --> $DIR/other_variant.rs:7:5 + | +7 | / #[serde(other)] +8 | | Other, + | |_________^ + +error: aborting due to previous error + diff --git a/test_suite/tests/ui/malformed/bound.rs b/test_suite/tests/ui/malformed/bound.rs new file mode 100644 index 00000000..b6816b38 --- /dev/null +++ b/test_suite/tests/ui/malformed/bound.rs @@ -0,0 +1,10 @@ +#[macro_use] +extern crate serde_derive; + +#[derive(Serialize)] +struct S { + #[serde(bound(unknown))] + x: (), +} + +fn main() {} diff --git a/test_suite/tests/ui/malformed/bound.stderr b/test_suite/tests/ui/malformed/bound.stderr new file mode 100644 index 00000000..0fb80c8b --- /dev/null +++ b/test_suite/tests/ui/malformed/bound.stderr @@ -0,0 +1,8 @@ +error: malformed bound attribute, expected `bound(serialize = ..., deserialize = ...)` + --> $DIR/bound.rs:6:19 + | +6 | #[serde(bound(unknown))] + | ^^^^^^^ + +error: aborting due to previous error + diff --git a/test_suite/tests/ui/malformed/rename.rs b/test_suite/tests/ui/malformed/rename.rs new file mode 100644 index 00000000..32d86217 --- /dev/null +++ b/test_suite/tests/ui/malformed/rename.rs @@ -0,0 +1,10 @@ +#[macro_use] +extern crate serde_derive; + +#[derive(Serialize)] +struct S { + #[serde(rename(unknown))] + x: (), +} + +fn main() {} diff --git a/test_suite/tests/ui/malformed/rename.stderr b/test_suite/tests/ui/malformed/rename.stderr new file mode 100644 index 00000000..58765222 --- /dev/null +++ b/test_suite/tests/ui/malformed/rename.stderr @@ -0,0 +1,8 @@ +error: malformed rename attribute, expected `rename(serialize = ..., deserialize = ...)` + --> $DIR/rename.rs:6:20 + | +6 | #[serde(rename(unknown))] + | ^^^^^^^ + +error: aborting due to previous error + diff --git a/test_suite/tests/ui/identifier/serialize.rs b/test_suite/tests/ui/precondition/serialize_field_identifier.rs similarity index 100% rename from test_suite/tests/ui/identifier/serialize.rs rename to test_suite/tests/ui/precondition/serialize_field_identifier.rs diff --git a/test_suite/tests/ui/identifier/serialize.stderr b/test_suite/tests/ui/precondition/serialize_field_identifier.stderr similarity index 80% rename from test_suite/tests/ui/identifier/serialize.stderr rename to test_suite/tests/ui/precondition/serialize_field_identifier.stderr index 474cd57d..50726c34 100644 --- a/test_suite/tests/ui/identifier/serialize.stderr +++ b/test_suite/tests/ui/precondition/serialize_field_identifier.stderr @@ -1,5 +1,5 @@ error: field identifiers cannot be serialized - --> $DIR/serialize.rs:5:1 + --> $DIR/serialize_field_identifier.rs:5:1 | 5 | / #[serde(field_identifier)] 6 | | enum F { diff --git a/test_suite/tests/ui/precondition/serialize_variant_identifier.rs b/test_suite/tests/ui/precondition/serialize_variant_identifier.rs new file mode 100644 index 00000000..7abfc209 --- /dev/null +++ b/test_suite/tests/ui/precondition/serialize_variant_identifier.rs @@ -0,0 +1,11 @@ +#[macro_use] +extern crate serde_derive; + +#[derive(Serialize)] +#[serde(variant_identifier)] +enum F { + A, + B, +} + +fn main() {} diff --git a/test_suite/tests/ui/precondition/serialize_variant_identifier.stderr b/test_suite/tests/ui/precondition/serialize_variant_identifier.stderr new file mode 100644 index 00000000..d5ef4650 --- /dev/null +++ b/test_suite/tests/ui/precondition/serialize_variant_identifier.stderr @@ -0,0 +1,12 @@ +error: variant identifiers cannot be serialized + --> $DIR/serialize_variant_identifier.rs:5:1 + | +5 | / #[serde(variant_identifier)] +6 | | enum F { +7 | | A, +8 | | B, +9 | | } + | |_^ + +error: aborting due to previous error + diff --git a/test_suite/tests/ui/rename/container_unknown_rename_rule.rs b/test_suite/tests/ui/rename/container_unknown_rename_rule.rs new file mode 100644 index 00000000..3d3a518e --- /dev/null +++ b/test_suite/tests/ui/rename/container_unknown_rename_rule.rs @@ -0,0 +1,12 @@ +#[macro_use] +extern crate serde_derive; + +#[derive(Serialize)] +#[serde(rename_all = "abc")] +struct S { + name: u8, + long_name: u8, + very_long_name: u8, +} + +fn main() {} diff --git a/test_suite/tests/ui/rename/container_unknown_rename_rule.stderr b/test_suite/tests/ui/rename/container_unknown_rename_rule.stderr new file mode 100644 index 00000000..20ad1d7a --- /dev/null +++ b/test_suite/tests/ui/rename/container_unknown_rename_rule.stderr @@ -0,0 +1,8 @@ +error: unknown rename rule for #[serde(rename_all = "abc")] + --> $DIR/container_unknown_rename_rule.rs:5:22 + | +5 | #[serde(rename_all = "abc")] + | ^^^^^ + +error: aborting due to previous error + diff --git a/test_suite/tests/ui/rename/variant_unknown_rename_rule.rs b/test_suite/tests/ui/rename/variant_unknown_rename_rule.rs new file mode 100644 index 00000000..700a56e8 --- /dev/null +++ b/test_suite/tests/ui/rename/variant_unknown_rename_rule.rs @@ -0,0 +1,14 @@ +#[macro_use] +extern crate serde_derive; + +#[derive(Serialize)] +enum S { + #[serde(rename_all = "abc")] + V { + name: u8, + long_name: u8, + very_long_name: u8, + }, +} + +fn main() {} diff --git a/test_suite/tests/ui/rename/variant_unknown_rename_rule.stderr b/test_suite/tests/ui/rename/variant_unknown_rename_rule.stderr new file mode 100644 index 00000000..079c6145 --- /dev/null +++ b/test_suite/tests/ui/rename/variant_unknown_rename_rule.stderr @@ -0,0 +1,8 @@ +error: unknown rename rule for #[serde(rename_all = "abc")] + --> $DIR/variant_unknown_rename_rule.rs:6:26 + | +6 | #[serde(rename_all = "abc")] + | ^^^^^ + +error: aborting due to previous error + diff --git a/test_suite/tests/ui/transparent/enum.rs b/test_suite/tests/ui/transparent/enum.rs new file mode 100644 index 00000000..54ce5b5d --- /dev/null +++ b/test_suite/tests/ui/transparent/enum.rs @@ -0,0 +1,8 @@ +#[macro_use] +extern crate serde_derive; + +#[derive(Serialize)] +#[serde(transparent)] +enum E {} + +fn main() {} diff --git a/test_suite/tests/ui/transparent/enum.stderr b/test_suite/tests/ui/transparent/enum.stderr new file mode 100644 index 00000000..2cdc6631 --- /dev/null +++ b/test_suite/tests/ui/transparent/enum.stderr @@ -0,0 +1,9 @@ +error: #[serde(transparent)] is not allowed on an enum + --> $DIR/enum.rs:5:1 + | +5 | / #[serde(transparent)] +6 | | enum E {} + | |_________^ + +error: aborting due to previous error + diff --git a/test_suite/tests/ui/transparent/unit_struct.rs b/test_suite/tests/ui/transparent/unit_struct.rs new file mode 100644 index 00000000..cc08d49c --- /dev/null +++ b/test_suite/tests/ui/transparent/unit_struct.rs @@ -0,0 +1,8 @@ +#[macro_use] +extern crate serde_derive; + +#[derive(Serialize)] +#[serde(transparent)] +struct S; + +fn main() {} diff --git a/test_suite/tests/ui/transparent/unit_struct.stderr b/test_suite/tests/ui/transparent/unit_struct.stderr new file mode 100644 index 00000000..0f921aaa --- /dev/null +++ b/test_suite/tests/ui/transparent/unit_struct.stderr @@ -0,0 +1,9 @@ +error: #[serde(transparent)] is not allowed on a unit struct + --> $DIR/unit_struct.rs:5:1 + | +5 | / #[serde(transparent)] +6 | | struct S; + | |_________^ + +error: aborting due to previous error + diff --git a/test_suite/tests/ui/transparent/with_from.rs b/test_suite/tests/ui/transparent/with_from.rs new file mode 100644 index 00000000..42863eb0 --- /dev/null +++ b/test_suite/tests/ui/transparent/with_from.rs @@ -0,0 +1,10 @@ +#[macro_use] +extern crate serde_derive; + +#[derive(Serialize)] +#[serde(transparent, from = "u64")] +struct S { + a: u8, +} + +fn main() {} diff --git a/test_suite/tests/ui/transparent/with_from.stderr b/test_suite/tests/ui/transparent/with_from.stderr new file mode 100644 index 00000000..40efc720 --- /dev/null +++ b/test_suite/tests/ui/transparent/with_from.stderr @@ -0,0 +1,11 @@ +error: #[serde(transparent)] is not allowed with #[serde(from = "...")] + --> $DIR/with_from.rs:5:1 + | +5 | / #[serde(transparent, from = "u64")] +6 | | struct S { +7 | | a: u8, +8 | | } + | |_^ + +error: aborting due to previous error + diff --git a/test_suite/tests/ui/transparent/with_into.rs b/test_suite/tests/ui/transparent/with_into.rs new file mode 100644 index 00000000..e9e85ce7 --- /dev/null +++ b/test_suite/tests/ui/transparent/with_into.rs @@ -0,0 +1,10 @@ +#[macro_use] +extern crate serde_derive; + +#[derive(Serialize)] +#[serde(transparent, into = "u64")] +struct S { + a: u8, +} + +fn main() {} diff --git a/test_suite/tests/ui/transparent/with_into.stderr b/test_suite/tests/ui/transparent/with_into.stderr new file mode 100644 index 00000000..057d0c9c --- /dev/null +++ b/test_suite/tests/ui/transparent/with_into.stderr @@ -0,0 +1,11 @@ +error: #[serde(transparent)] is not allowed with #[serde(into = "...")] + --> $DIR/with_into.rs:5:1 + | +5 | / #[serde(transparent, into = "u64")] +6 | | struct S { +7 | | a: u8, +8 | | } + | |_^ + +error: aborting due to previous error + diff --git a/test_suite/tests/ui/unexpected-literal/container.rs b/test_suite/tests/ui/unexpected-literal/container.rs new file mode 100644 index 00000000..be18cf66 --- /dev/null +++ b/test_suite/tests/ui/unexpected-literal/container.rs @@ -0,0 +1,8 @@ +#[macro_use] +extern crate serde_derive; + +#[derive(Serialize)] +#[serde("literal")] +struct S; + +fn main() {} diff --git a/test_suite/tests/ui/unexpected-literal/container.stderr b/test_suite/tests/ui/unexpected-literal/container.stderr new file mode 100644 index 00000000..55103726 --- /dev/null +++ b/test_suite/tests/ui/unexpected-literal/container.stderr @@ -0,0 +1,8 @@ +error: unexpected literal in serde container attribute + --> $DIR/container.rs:5:9 + | +5 | #[serde("literal")] + | ^^^^^^^^^ + +error: aborting due to previous error + diff --git a/test_suite/tests/ui/unexpected-literal/field.rs b/test_suite/tests/ui/unexpected-literal/field.rs new file mode 100644 index 00000000..94bfb16a --- /dev/null +++ b/test_suite/tests/ui/unexpected-literal/field.rs @@ -0,0 +1,10 @@ +#[macro_use] +extern crate serde_derive; + +#[derive(Serialize)] +struct S { + #[serde("literal")] + x: (), +} + +fn main() {} diff --git a/test_suite/tests/ui/unexpected-literal/field.stderr b/test_suite/tests/ui/unexpected-literal/field.stderr new file mode 100644 index 00000000..b8e7b7cb --- /dev/null +++ b/test_suite/tests/ui/unexpected-literal/field.stderr @@ -0,0 +1,8 @@ +error: unexpected literal in serde field attribute + --> $DIR/field.rs:6:13 + | +6 | #[serde("literal")] + | ^^^^^^^^^ + +error: aborting due to previous error + diff --git a/test_suite/tests/ui/unexpected-literal/variant.rs b/test_suite/tests/ui/unexpected-literal/variant.rs new file mode 100644 index 00000000..ae8b8a80 --- /dev/null +++ b/test_suite/tests/ui/unexpected-literal/variant.rs @@ -0,0 +1,10 @@ +#[macro_use] +extern crate serde_derive; + +#[derive(Serialize)] +enum E { + #[serde("literal")] + V, +} + +fn main() {} diff --git a/test_suite/tests/ui/unexpected-literal/variant.stderr b/test_suite/tests/ui/unexpected-literal/variant.stderr new file mode 100644 index 00000000..ba2c841e --- /dev/null +++ b/test_suite/tests/ui/unexpected-literal/variant.stderr @@ -0,0 +1,8 @@ +error: unexpected literal in serde variant attribute + --> $DIR/variant.rs:6:13 + | +6 | #[serde("literal")] + | ^^^^^^^^^ + +error: aborting due to previous error + diff --git a/test_suite/tests/ui/unsupported/union_de.rs b/test_suite/tests/ui/unsupported/union_de.rs new file mode 100644 index 00000000..19e0a437 --- /dev/null +++ b/test_suite/tests/ui/unsupported/union_de.rs @@ -0,0 +1,10 @@ +#[macro_use] +extern crate serde_derive; + +#[derive(Deserialize)] +union Union { + x: u8, + y: (), +} + +fn main() {} diff --git a/test_suite/tests/ui/unsupported/union_de.stderr b/test_suite/tests/ui/unsupported/union_de.stderr new file mode 100644 index 00000000..0b087062 --- /dev/null +++ b/test_suite/tests/ui/unsupported/union_de.stderr @@ -0,0 +1,11 @@ +error: Serde does not support derive for unions + --> $DIR/union_de.rs:5:1 + | +5 | / union Union { +6 | | x: u8, +7 | | y: (), +8 | | } + | |_^ + +error: aborting due to previous error + diff --git a/test_suite/tests/ui/unsupported/union_ser.rs b/test_suite/tests/ui/unsupported/union_ser.rs new file mode 100644 index 00000000..19e0a437 --- /dev/null +++ b/test_suite/tests/ui/unsupported/union_ser.rs @@ -0,0 +1,10 @@ +#[macro_use] +extern crate serde_derive; + +#[derive(Deserialize)] +union Union { + x: u8, + y: (), +} + +fn main() {} diff --git a/test_suite/tests/ui/unsupported/union_ser.stderr b/test_suite/tests/ui/unsupported/union_ser.stderr new file mode 100644 index 00000000..0d808b88 --- /dev/null +++ b/test_suite/tests/ui/unsupported/union_ser.stderr @@ -0,0 +1,11 @@ +error: Serde does not support derive for unions + --> $DIR/union_ser.rs:5:1 + | +5 | / union Union { +6 | | x: u8, +7 | | y: (), +8 | | } + | |_^ + +error: aborting due to previous error +