Skip to content

Commit a4f9846

Browse files
committed
Use proper span when generating matches token
In `struct-opt-derive`, a function is generated with a parameter named `matches`. Since `quote!` is used to generate the function, the `matches` token will be resolved using `Span::call_site`. However, the literal identifier `matches` is also used inside several `quote_spanned!` expressions. Such a `matches` identifier will be resolved using the `Span` passed to `quote_spanned!`, which may not be the same as `Span::call_site`. Currently, this is difficult to observe in practice, due to rust-lang/rust#43081 . However, once PR rust-lang/rust#73084 is merged, proc macros will see properly spanned tokens in more cases, which will cause these incorrect uses of `quote_spanned!` to break. This PR uses `quote! { matches }` to generate a correctly spanned `matches` token, which is then include in the `quote_spanned!` expressions using `#matches`.
1 parent 2b2d941 commit a4f9846

File tree

1 file changed

+13
-12
lines changed

1 file changed

+13
-12
lines changed

structopt-derive/src/lib.rs

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ fn gen_constructor(fields: &Punctuated<Field, Comma>, parent_attribute: &Attrs)
248248
);
249249
let field_name = field.ident.as_ref().unwrap();
250250
let kind = attrs.kind();
251+
let matches = quote! { matches };
251252
match &*kind {
252253
Kind::ExternalSubcommand => abort!(
253254
kind.span(),
@@ -265,13 +266,13 @@ fn gen_constructor(fields: &Punctuated<Field, Comma>, parent_attribute: &Attrs)
265266
};
266267
quote_spanned! { kind.span()=>
267268
#field_name: <#subcmd_type as ::structopt::StructOptInternal>::from_subcommand(
268-
matches.subcommand())
269+
#matches.subcommand())
269270
#unwrapper
270271
}
271272
}
272273

273274
Kind::Flatten => quote_spanned! { kind.span()=>
274-
#field_name: ::structopt::StructOpt::from_clap(matches)
275+
#field_name: ::structopt::StructOpt::from_clap(#matches)
275276
},
276277

277278
Kind::Skip(val) => match val {
@@ -318,45 +319,45 @@ fn gen_constructor(fields: &Punctuated<Field, Comma>, parent_attribute: &Attrs)
318319
let occurrences = *attrs.parser().kind == ParserKind::FromOccurrences;
319320
let name = attrs.cased_name();
320321
let field_value = match **ty {
321-
Ty::Bool => quote_spanned!(ty.span()=> matches.is_present(#name)),
322+
Ty::Bool => quote_spanned!(ty.span()=> #matches.is_present(#name)),
322323

323324
Ty::Option => quote_spanned! { ty.span()=>
324-
matches.#value_of(#name)
325+
#matches.#value_of(#name)
325326
.map(#parse)
326327
},
327328

328329
Ty::OptionOption => quote_spanned! { ty.span()=>
329-
if matches.is_present(#name) {
330-
Some(matches.#value_of(#name).map(#parse))
330+
if #matches.is_present(#name) {
331+
Some(#matches.#value_of(#name).map(#parse))
331332
} else {
332333
None
333334
}
334335
},
335336

336337
Ty::OptionVec => quote_spanned! { ty.span()=>
337-
if matches.is_present(#name) {
338-
Some(matches.#values_of(#name)
338+
if #matches.is_present(#name) {
339+
Some(#matches.#values_of(#name)
339340
.map_or_else(Vec::new, |v| v.map(#parse).collect()))
340341
} else {
341342
None
342343
}
343344
},
344345

345346
Ty::Vec => quote_spanned! { ty.span()=>
346-
matches.#values_of(#name)
347+
#matches.#values_of(#name)
347348
.map_or_else(Vec::new, |v| v.map(#parse).collect())
348349
},
349350

350351
Ty::Other if occurrences => quote_spanned! { ty.span()=>
351-
#parse(matches.#value_of(#name))
352+
#parse(#matches.#value_of(#name))
352353
},
353354

354355
Ty::Other if flag => quote_spanned! { ty.span()=>
355-
#parse(matches.is_present(#name))
356+
#parse(#matches.is_present(#name))
356357
},
357358

358359
Ty::Other => quote_spanned! { ty.span()=>
359-
matches.#value_of(#name)
360+
#matches.#value_of(#name)
360361
.map(#parse)
361362
.unwrap()
362363
},

0 commit comments

Comments
 (0)