From 2c1f62d4b498ddfe0d7dea339deac5d085550a37 Mon Sep 17 00:00:00 2001 From: Mingun Date: Sat, 27 May 2023 17:17:00 +0500 Subject: [PATCH] Fix incorrect count of fields passed to tuple deserialization methods This count should mean the number of fields expected in the serialized form, so if some fields are skipped, they shouldn't be counted Methods affected: - Deserializer::deserialize_tuple - Deserializer::deserialize_tuple_struct - VariantAccess::tuple_variant --- serde_derive/src/de.rs | 36 +++++++++++++++++----------- test_suite/tests/test_annotations.rs | 2 +- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index 33a976d7b..b455b3d0f 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -445,14 +445,19 @@ fn deserialize_tuple( cattrs: &attr::Container, deserializer: Option, ) -> Fragment { + assert!(!cattrs.has_flatten()); + + let field_count = fields + .iter() + .filter(|field| !field.attrs.skip_deserializing()) + .count(); + let this_type = ¶ms.this_type; let this_value = ¶ms.this_value; let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = split_with_de_lifetime(params); let delife = params.borrowed.de_lifetime(); - assert!(!cattrs.has_flatten()); - // If there are getters (implying private fields), construct the local type // and use an `Into` conversion to get the remote type. If there are no // getters then construct the target type directly. @@ -493,19 +498,18 @@ fn deserialize_tuple( } }; let dispatch = if let Some(deserializer) = deserializer { - quote!(_serde::Deserializer::deserialize_tuple(#deserializer, #nfields, #visitor_expr)) + quote!(_serde::Deserializer::deserialize_tuple(#deserializer, #field_count, #visitor_expr)) } else if is_enum { - quote!(_serde::de::VariantAccess::tuple_variant(__variant, #nfields, #visitor_expr)) + quote!(_serde::de::VariantAccess::tuple_variant(__variant, #field_count, #visitor_expr)) } else if nfields == 1 { let type_name = cattrs.name().deserialize_name(); quote!(_serde::Deserializer::deserialize_newtype_struct(__deserializer, #type_name, #visitor_expr)) } else { let type_name = cattrs.name().deserialize_name(); - quote!(_serde::Deserializer::deserialize_tuple_struct(__deserializer, #type_name, #nfields, #visitor_expr)) + quote!(_serde::Deserializer::deserialize_tuple_struct(__deserializer, #type_name, #field_count, #visitor_expr)) }; - let all_skipped = fields.iter().all(|field| field.attrs.skip_deserializing()); - let visitor_var = if all_skipped { + let visitor_var = if field_count == 0 { quote!(_) } else { quote!(mut __seq) @@ -548,13 +552,18 @@ fn deserialize_tuple_in_place( cattrs: &attr::Container, deserializer: Option, ) -> Fragment { + assert!(!cattrs.has_flatten()); + + let field_count = fields + .iter() + .filter(|field| !field.attrs.skip_deserializing()) + .count(); + let this_type = ¶ms.this_type; let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = split_with_de_lifetime(params); let delife = params.borrowed.de_lifetime(); - assert!(!cattrs.has_flatten()); - let is_enum = variant_ident.is_some(); let expecting = match variant_ident { Some(variant_ident) => format!("tuple variant {}::{}", params.type_name(), variant_ident), @@ -580,19 +589,18 @@ fn deserialize_tuple_in_place( }; let dispatch = if let Some(deserializer) = deserializer { - quote!(_serde::Deserializer::deserialize_tuple(#deserializer, #nfields, #visitor_expr)) + quote!(_serde::Deserializer::deserialize_tuple(#deserializer, #field_count, #visitor_expr)) } else if is_enum { - quote!(_serde::de::VariantAccess::tuple_variant(__variant, #nfields, #visitor_expr)) + quote!(_serde::de::VariantAccess::tuple_variant(__variant, #field_count, #visitor_expr)) } else if nfields == 1 { let type_name = cattrs.name().deserialize_name(); quote!(_serde::Deserializer::deserialize_newtype_struct(__deserializer, #type_name, #visitor_expr)) } else { let type_name = cattrs.name().deserialize_name(); - quote!(_serde::Deserializer::deserialize_tuple_struct(__deserializer, #type_name, #nfields, #visitor_expr)) + quote!(_serde::Deserializer::deserialize_tuple_struct(__deserializer, #type_name, #field_count, #visitor_expr)) }; - let all_skipped = fields.iter().all(|field| field.attrs.skip_deserializing()); - let visitor_var = if all_skipped { + let visitor_var = if field_count == 0 { quote!(_) } else { quote!(mut __seq) diff --git a/test_suite/tests/test_annotations.rs b/test_suite/tests/test_annotations.rs index 117cd3f4e..b5388c473 100644 --- a/test_suite/tests/test_annotations.rs +++ b/test_suite/tests/test_annotations.rs @@ -1533,7 +1533,7 @@ fn test_invalid_length_enum() { Token::TupleVariant { name: "InvalidLengthEnum", variant: "B", - len: 3, + len: 2, }, Token::I32(1), Token::TupleVariantEnd,