Skip to content

Reject struct field names that collide with #[serde(tag)] - #3095

Open
SebTardif wants to merge 2 commits into
serde-rs:masterfrom
SebTardif:fix/struct-internal-tag-field-conflict
Open

Reject struct field names that collide with #[serde(tag)]#3095
SebTardif wants to merge 2 commits into
serde-rs:masterfrom
SebTardif:fix/struct-internal-tag-field-conflict

Conversation

@SebTardif

Copy link
Copy Markdown

Summary

Reject named-struct field (and alias) names that collide with #[serde(tag = "...")], matching the existing check for enum struct variants.

Problem

Enums with an internal tag already error at derive time when a field serialize name or alias equals the tag:

error: variant field name `conflict` conflicts with internal tag

Named structs with the same attribute skipped that check. Serialize injects the type name under the tag key, then also emits the colliding field, which produces duplicate keys and breaks round-trips.

#[derive(Serialize)]
#[serde(tag = "type")]
struct S {
    #[serde(rename = "type")]
    x: i32,
}
// Was: {"type":"S","type":0}
// Deserialize of that JSON fails: invalid type string for i32

This early return for structs has been present since the internal-tag field conflict check was introduced (2018).

Change

  • Extend check_internal_tag_field_name_conflict to named structs (Style::Struct)
  • Skip flattened fields (they never appear under their own name; e.g. tag = "data" with #[serde(flatten)] data)
  • Share the rename/alias comparison helper with the enum path
  • UI tests: internal-tag-struct.rs and internal-tag-struct-alias.rs next to the existing enum cases

Validation

+ Red: without the fix, colliding struct derives successfully (bug present)
+ Green: with the fix, derive errors with `field name \`conflict\` conflicts with internal tag`
+ cargo +nightly test --test compiletest ui  (120 UI cases, including new ones)
+ cargo +nightly test --test test_macros test_internally_tagged_struct_with_flattened_field

Flatten + tag with a matching field name still compiles (regression covered by the flatten skip).

Named structs with #[serde(tag = "...")] inject a type-name field under
that key on serialize. Enums already rejected a field (or alias) whose
serialize name equals the tag. Structs skipped that check, so a field
renamed to the same key produced duplicate map keys and failed to
round-trip.

Mirror the enum conflict check for named structs, skip flattened fields
(they never appear under their own name), and add UI tests matching the
existing enum coverage.

Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
Documentation failed downloading cargo-docs-rs (curl 503/56), not
doc content. External contributors cannot gh run rerun --failed.

Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant