Skip to content

Commit 353db2c

Browse files
authored
Use proper span when emitting 'self' identifier (#210)
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.
1 parent 6a60350 commit 353db2c

File tree

2 files changed

+21
-3
lines changed

2 files changed

+21
-3
lines changed

derive/src/encode.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,16 +70,19 @@ fn encode_single_field(
7070
}
7171
};
7272

73+
// This may have different hygiene than the field span
74+
let i_self = quote! { self };
75+
7376
quote_spanned! { field.span() =>
74-
fn encode_to<EncOut: _parity_scale_codec::Output>(&self, dest: &mut EncOut) {
77+
fn encode_to<EncOut: _parity_scale_codec::Output>(&#i_self, dest: &mut EncOut) {
7578
_parity_scale_codec::Encode::encode_to(&#final_field_variable, dest)
7679
}
7780

78-
fn encode(&self) -> _parity_scale_codec::alloc::vec::Vec<u8> {
81+
fn encode(&#i_self) -> _parity_scale_codec::alloc::vec::Vec<u8> {
7982
_parity_scale_codec::Encode::encode(&#final_field_variable)
8083
}
8184

82-
fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
85+
fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&#i_self, f: F) -> R {
8386
_parity_scale_codec::Encode::using_encoded(&#final_field_variable, f)
8487
}
8588
}

tests/mod.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,3 +526,18 @@ fn crafted_input_for_vec_t() {
526526
);
527527
}
528528

529+
#[test]
530+
fn weird_derive() {
531+
// Tests that compilation succeeds when the macro invocation
532+
// hygiene context is different from the field hygiene context.
533+
macro_rules! make_struct {
534+
(#[$attr:meta]) => (
535+
#[$attr]
536+
pub struct MyStruct {
537+
field: u8
538+
}
539+
)
540+
}
541+
542+
make_struct!(#[derive(Encode, Decode)]);
543+
}

0 commit comments

Comments
 (0)