Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions serde_derive/src/internals/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) {
check_adjacent_tag_conflict(cx, cont);
check_transparent(cx, cont, derive);
check_from_and_try_from(cx, cont);
check_enum_untagged(cx, cont, derive);
}

// If some field of a tuple struct is marked #[serde(default)] then all fields
Expand Down Expand Up @@ -475,3 +476,36 @@ fn check_from_and_try_from(cx: &Ctxt, cont: &mut Container) {
);
}
}

/// Checks that untagged enum has only one unit variant, because we cannot distinguish between
/// different variants when deserializing
fn check_enum_untagged(cx: &Ctxt, cont: &mut Container, derive: Derive) {
// We allow serialization of enums with multiple units, because new units could
// be added to maintain backward compatibility
if let Derive::Serialize = derive {
return;
}
let variants = match &cont.data {
Data::Enum(variants) => variants,
Data::Struct(_, _) => return,
};
if !matches!(cont.attrs.tag(), TagType::None) {
return;
}

let mut unit = None;
for variant in variants {
if variant.attrs.skip_deserializing() {
continue;
}
if let Style::Unit = variant.style {
if unit.is_some() {
cx.error_spanned_by(
variant.original,
"untagged enums can contain only one unit variant. Use #[serde(skip_deserializing)] if you really want several unit variants",
);
}
unit = Some(variant);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use serde_derive::{Deserialize, Serialize};

#[derive(Deserialize)]
#[serde(untagged)]
enum E1 {
Unit1,
Tuple1(usize),
Unit2,
Struct {},
#[serde(skip_serializing)]
Unit3,
#[serde(skip_deserializing)]
Unit4,
}

#[derive(Serialize)]
#[serde(untagged)]
enum E2 {
Unit1,
Tuple1(usize),
Unit2,
Struct {},
#[serde(skip_serializing)]
Unit3,
#[serde(skip_deserializing)]
Unit4,
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
error: untagged enums can contain only one unit variant. Use #[serde(skip_deserializing)] if you really want several unit variants
--> tests/ui/enum-representation/untagged-with-muliple-units.rs:8:5
|
8 | Unit2,
| ^^^^^

error: untagged enums can contain only one unit variant. Use #[serde(skip_deserializing)] if you really want several unit variants
--> tests/ui/enum-representation/untagged-with-muliple-units.rs:10:5
|
10 | / #[serde(skip_serializing)]
11 | | Unit3,
| |_________^
Loading