Skip to content

Commit

Permalink
Use proper span when emitting 'self' identifier (#210)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Aaron1011 authored and bkchr committed Jul 28, 2020
1 parent 06b5592 commit f5bdd1a
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 3 deletions.
9 changes: 6 additions & 3 deletions derive/src/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<EncOut: _parity_scale_codec::Output>(&self, dest: &mut EncOut) {
fn encode_to<EncOut: _parity_scale_codec::Output>(&#i_self, dest: &mut EncOut) {
_parity_scale_codec::Encode::encode_to(&#final_field_variable, dest)
}

fn encode(&self) -> _parity_scale_codec::alloc::vec::Vec<u8> {
fn encode(&#i_self) -> _parity_scale_codec::alloc::vec::Vec<u8> {
_parity_scale_codec::Encode::encode(&#final_field_variable)
}

fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&#i_self, f: F) -> R {
_parity_scale_codec::Encode::using_encoded(&#final_field_variable, f)
}
}
Expand Down
15 changes: 15 additions & 0 deletions tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]);
}

0 comments on commit f5bdd1a

Please sign in to comment.