Skip to content

Commit

Permalink
Use proc_macro2::Span::call_site for all quotes
Browse files Browse the repository at this point in the history
This avoids breakage when deriving `StructOpt` when `proc_macro2`'s nightly
feature is enabled. See dtolnay/proc-macro2#67
for details.
  • Loading branch information
fitzgen committed Mar 1, 2018
1 parent f26ce8b commit a3409f2
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 66 deletions.
6 changes: 6 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,11 @@ rust:
- beta
- nightly
matrix:
include:
- rust: nightly
env: FEATURES="--features testing_only_proc_macro2_nightly"
allow_failures:
- rust: nightly

script:
- cargo test $FEATURES
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# Unreleased

* Work around breakage when `proc-macro2`'s nightly feature is enabled. ([#77](https://github.com/Texitoi/structopt/pull/77) and [proc-macro2#67](https://github.com/alexcrichton/proc-macro2/issues/67))

# v0.2.4 (2018-02-25)

* Fix compilation with `#![deny(missig_docs]` ([#74](https://github.com/TeXitoi/structopt/issues/74)) by [@TeXitoi](https://github.com/TeXitoi)
Expand Down
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,7 @@ travis-ci = { repository = "TeXitoi/structopt" }
clap = { version = "2.20", default-features = false }
structopt-derive = { path = "structopt-derive", version = "0.2.4" }

[features]
testing_only_proc_macro2_nightly = ["structopt-derive/testing_only_proc_macro2_nightly"]

[workspace]
3 changes: 3 additions & 0 deletions structopt-derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,8 @@ syn = "0.12"
quote = "0.4"
proc-macro2 = "0.2"

[features]
testing_only_proc_macro2_nightly = ["proc-macro2/nightly"]

[lib]
proc-macro = true
42 changes: 21 additions & 21 deletions structopt-derive/src/attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ impl Attrs {
Attrs {
name: name,
methods: vec![],
parser: (Parser::TryFromStr, quote!(::std::str::FromStr::from_str)),
parser: (Parser::TryFromStr, my_quote!(::std::str::FromStr::from_str)),
has_custom_parser: false,
is_subcommand: false,
}
Expand All @@ -67,7 +67,7 @@ impl Attrs {
("name", new_name) => self.name = new_name.into(),
(name, arg) => self.methods.push(Method {
name: name.to_string(),
args: quote!(#arg),
args: my_quote!(#arg),
}),
}
}
Expand All @@ -79,21 +79,21 @@ impl Attrs {
let iter = attrs.iter()
.filter_map(|attr| {
let path = &attr.path;
match quote!(#path) == quote!(structopt) {
match my_quote!(#path) == my_quote!(structopt) {
true => Some(
attr.interpret_meta()
.expect(&format!("invalid structopt syntax: {}", quote!(attr)))
.expect(&format!("invalid structopt syntax: {}", my_quote!(attr)))
),
false => None,
}
}).
flat_map(|m| match m {
List(l) => l.nested,
tokens => panic!("unsupported syntax: {}", quote!(#tokens).to_string()),
tokens => panic!("unsupported syntax: {}", my_quote!(#tokens).to_string()),
})
.map(|m| match m {
Meta(m) => m,
ref tokens => panic!("unsupported syntax: {}", quote!(#tokens).to_string()),
ref tokens => panic!("unsupported syntax: {}", my_quote!(#tokens).to_string()),
});
for attr in iter {
match attr {
Expand All @@ -102,7 +102,7 @@ impl Attrs {
NameValue(MetaNameValue { ident, lit, .. }) => {
self.methods.push(Method {
name: ident.to_string(),
args: quote!(#lit),
args: my_quote!(#lit),
})
}
List(MetaList { ident, ref nested, .. }) if ident == "parse" => {
Expand All @@ -114,51 +114,51 @@ impl Attrs {
Meta(NameValue(MetaNameValue { ident, lit: Str(ref v), .. })) => {
let function: syn::Path = v.parse().expect("parser function path");
let parser = ident.as_ref().parse().unwrap();
(parser, quote!(#function))
(parser, my_quote!(#function))
}
Meta(Word(ref i)) => {
use Parser::*;
let parser = i.as_ref().parse().unwrap();
let function = match parser {
FromStr => quote!(::std::convert::From::from),
TryFromStr => quote!(::std::str::FromStr::from_str),
FromOsStr => quote!(::std::convert::From::from),
FromStr => my_quote!(::std::convert::From::from),
TryFromStr => my_quote!(::std::str::FromStr::from_str),
FromOsStr => my_quote!(::std::convert::From::from),
TryFromOsStr => panic!("cannot omit parser function name with `try_from_os_str`"),
FromOccurrences => quote!({|v| v as _}),
FromOccurrences => my_quote!({|v| v as _}),
};
(parser, function)
}
ref l @ _ => panic!("unknown value parser specification: {}", quote!(#l)),
ref l @ _ => panic!("unknown value parser specification: {}", my_quote!(#l)),
};
}
List(MetaList { ident, ref nested, .. }) if ident == "raw" => {
for method in nested {
match *method {
Meta(NameValue(MetaNameValue { ident, lit: Str(ref v), .. })) =>
self.push_raw_method(ident.as_ref(), v),
ref mi @ _ => panic!("unsupported raw entry: {}", quote!(#mi)),
ref mi @ _ => panic!("unsupported raw entry: {}", my_quote!(#mi)),
}
}
}
Word(ref w) if w == "subcommand" => self.is_subcommand = true,
ref i @ List(..) | ref i @ Word(..) =>
panic!("unsupported option: {}", quote!(#i)),
panic!("unsupported option: {}", my_quote!(#i)),
}
}
}
fn push_raw_method(&mut self, name: &str, args: &LitStr) {
let ts: ::proc_macro2::TokenStream = args.value().parse()
.expect(&format!("bad parameter {} = {}: the parameter must be valid rust code", name, quote!(#args)));
.expect(&format!("bad parameter {} = {}: the parameter must be valid rust code", name, my_quote!(#args)));
self.methods.push(Method {
name: name.to_string(),
args: quote!(#(#ts)*),
args: my_quote!(#(#ts)*),
})
}
fn push_doc_comment(&mut self, attrs: &[Attribute], name: &str) {
let doc_comments: Vec<_> = attrs.iter()
.filter_map(|attr| {
let path = &attr.path;
match quote!(#path) == quote!(doc) {
match my_quote!(#path) == my_quote!(doc) {
true => attr.interpret_meta(),
false => None,
}
Expand Down Expand Up @@ -195,7 +195,7 @@ impl Attrs {
.join("\n");
self.methods.push(Method {
name: name.to_string(),
args: quote!(#arg),
args: my_quote!(#arg),
});
}
pub fn from_struct(attrs: &[Attribute], name: String) -> Attrs {
Expand Down Expand Up @@ -243,9 +243,9 @@ impl Attrs {
pub fn methods(&self) -> Tokens {
let methods = self.methods.iter().map(|&Method { ref name, ref args }| {
let name: ::syn::Ident = name.as_str().into();
quote!( .#name(#args) )
my_quote!( .#name(#args) )
});
quote!( #(#methods)* )
my_quote!( #(#methods)* )
}
pub fn name(&self) -> &str {
&self.name
Expand Down
Loading

0 comments on commit a3409f2

Please sign in to comment.