From 2431f7eab274dddebea9d094e060fbadd2751b00 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 30 May 2020 17:48:38 -0400 Subject: [PATCH] Use proper span when emitting 'self' identifier Normally, the span of a field has the same hygiene context as `Span::call_site`. However, it's possible for a struct definition to be 'constructed' via a `macro_rules` macro such that the field has a different hygiene context. This will cause the expanded code to be unable to resolve any references to `self`, resulting in a compilation error. This pull request uses `quote!` instead of `quote_spanned!` when emitting a 'self' identifier. `quote_spanned!` is still used for everything else in the emitted method, meaning that error messages will still point to the proper field. I've included a test case which triggers this issue on Rust 1.43.1. It's current difficult to hit this issue other than in this artificial case, but that will change once rust-lang/rust#72622 is re-landed. --- derive/src/encode.rs | 9 ++++++--- tests/mod.rs | 15 +++++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/derive/src/encode.rs b/derive/src/encode.rs index 834d389b..d55b87c6 100644 --- a/derive/src/encode.rs +++ b/derive/src/encode.rs @@ -70,16 +70,19 @@ fn encode_single_field( } }; + // This may have different hygiene than the field span + let i_self = quote! { self }; + quote_spanned! { field.span() => - fn encode_to(&self, dest: &mut EncOut) { + fn encode_to(&#i_self, dest: &mut EncOut) { _parity_scale_codec::Encode::encode_to(&#final_field_variable, dest) } - fn encode(&self) -> _parity_scale_codec::alloc::vec::Vec { + fn encode(&#i_self) -> _parity_scale_codec::alloc::vec::Vec { _parity_scale_codec::Encode::encode(&#final_field_variable) } - fn using_encoded R>(&self, f: F) -> R { + fn using_encoded R>(&#i_self, f: F) -> R { _parity_scale_codec::Encode::using_encoded(&#final_field_variable, f) } } diff --git a/tests/mod.rs b/tests/mod.rs index f60064f2..1de00f31 100644 --- a/tests/mod.rs +++ b/tests/mod.rs @@ -526,3 +526,18 @@ fn crafted_input_for_vec_t() { ); } +#[test] +fn weird_derive() { + // Tests that compilation succeeds when the macro invocation + // hygiene context is different from the field hygiene context. + macro_rules! make_struct { + (#[$attr:meta]) => ( + #[$attr] + pub struct MyStruct { + field: u8 + } + ) + } + + make_struct!(#[derive(Encode, Decode)]); +}