diff --git a/serde_derive/Cargo.toml b/serde_derive/Cargo.toml index 3db348079..1164ed7fd 100644 --- a/serde_derive/Cargo.toml +++ b/serde_derive/Cargo.toml @@ -24,7 +24,7 @@ proc-macro = true [dependencies] proc-macro2 = "1.0" quote = "1.0" -syn = "1.0.90" +syn = "1.0.104" [dev-dependencies] serde = { version = "1.0", path = "../serde" } diff --git a/serde_derive/src/internals/check.rs b/serde_derive/src/internals/check.rs index 0e2484a79..eb1297aa7 100644 --- a/serde_derive/src/internals/check.rs +++ b/serde_derive/src/internals/check.rs @@ -6,6 +6,7 @@ use syn::{Member, Type}; /// Cross-cutting checks that require looking at more than a single attrs /// object. Simpler checks should happen when parsing and building the attrs. pub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) { + check_remote_generic(cx, cont); check_getter(cx, cont); check_flatten(cx, cont); check_identifier(cx, cont); @@ -16,6 +17,28 @@ pub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) { check_from_and_try_from(cx, cont); } +/// Remote derive definition type must have either all of the generics of the +/// remote type: +/// +/// #[serde(remote = "Generic")] +/// struct Generic {…} +/// +/// or none of them, i.e. defining impls for one concrete instantiation of the +/// remote type only: +/// +/// #[serde(remote = "Generic")] +/// struct ConcreteDef {…} +/// +fn check_remote_generic(cx: &Ctxt, cont: &Container) { + if let Some(remote) = cont.attrs.remote() { + let local_has_generic = !cont.generics.params.is_empty(); + let remote_has_generic = !remote.segments.last().unwrap().arguments.is_none(); + if local_has_generic && remote_has_generic { + cx.error_spanned_by(remote, "remove generic parameters from this path"); + } + } +} + /// Getters are only allowed inside structs (not enums) with the `remote` /// attribute. fn check_getter(cx: &Ctxt, cont: &Container) { diff --git a/serde_derive_internals/Cargo.toml b/serde_derive_internals/Cargo.toml index f84a3f52d..ee22aa1fe 100644 --- a/serde_derive_internals/Cargo.toml +++ b/serde_derive_internals/Cargo.toml @@ -17,7 +17,7 @@ path = "lib.rs" [dependencies] proc-macro2 = "1.0" quote = "1.0" -syn = { version = "1.0.90", default-features = false, features = ["derive", "parsing", "printing", "clone-impls"] } +syn = { version = "1.0.104", default-features = false, features = ["derive", "parsing", "printing", "clone-impls"] } [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/test_suite/tests/ui/remote/double_generic.rs b/test_suite/tests/ui/remote/double_generic.rs new file mode 100644 index 000000000..0e286a91e --- /dev/null +++ b/test_suite/tests/ui/remote/double_generic.rs @@ -0,0 +1,17 @@ +use serde_derive::{Deserialize, Serialize}; + +mod remote { + pub struct Struct { + pub t: T, + pub u: U, + } +} + +#[derive(Serialize, Deserialize)] +#[serde(remote = "remote::StructGeneric")] +struct StructDef { + t: u8, + u: U, +} + +fn main() {} diff --git a/test_suite/tests/ui/remote/double_generic.stderr b/test_suite/tests/ui/remote/double_generic.stderr new file mode 100644 index 000000000..4188b44a2 --- /dev/null +++ b/test_suite/tests/ui/remote/double_generic.stderr @@ -0,0 +1,5 @@ +error: remove generic parameters from this path + --> tests/ui/remote/double_generic.rs:11:18 + | +11 | #[serde(remote = "remote::StructGeneric")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^