Repository: clap-rs/clap
Pull request #1681 (2020-02-08 17:10:13)

WIP: Extract subcommands into separate trait
Not-yet-working-but-almost-there "multiple traits" approach. More or less done, what's left is to catch some bugs and adapt tests/examples.

For the record: it took so long because of RL stuff (who would have thought?) and because [there was a detailed description of the experience I've had here, but it was deleted because it contained a lot of profanity and emotional notes]. 

As the only person alive that understands how the derive works (if you won't blow your own horn, nobody will do it for you, yeah), I'd like to made a statement: we Do need the refactoring.

pksunkara: Conflicts? And yeah, I think it will take me a bit of time to check this.

I don't know about the other traits we were talking about, but I was pretty sure we didn't need subcommand trait.
CreepySkeleton: I've splited the PR into separate commit so it's hopefully easier to review :)

A separate trait for subcommands was the whole point. It allows us to check that `#[clap(subcommand)]` is applied to enum and not to struct. It also moves unrelated functions into separate, unrelated traits, which is easier to maintain than one giant trait. I was also thinking about `Flattened` trait but figured that `intoApp` will depen on it one way or another and so the trait will be virtually useless.
CreepySkeleton: People, I think I've found a bug in the derive which has become yet another example of "this is not a bug anymore, but a feature". Two related bugs, actually. The `is_subcommand` methods exists solely to  support this bugs.

Consider this code:
```rust
#[derive(Clap)]
struct Foo {
    // we should have used `subcommand` here
    // this is an error
    #[clap(flatten)]
    sub: Sub
}

#[derive(Subcommand)]
enum Sub { /* whatev */ }
```

Do you think it would fail to compile? Or, maybe panic with `unwrapped None`? Hell no! It works perfectly, effectively making `flatten` alias to `subcommand`. There's no mentioning in strustopt docs about it. @TeXitoi did you intend it to work this way?

The second problem is more subtle.

```rust
enum Foo {
    // this is supposed to work as `flatten` 
    // https://docs.rs/structopt/0.3.9/structopt/#subcommands
    Foo(Ext)
}

// This is supposed to be a struct
enum Ext {}
```

This is how the snippet was *supposed* to be written, according to the docs:
```rust
enum Foo {
    // flattening struct, all good
    Foo(Ext)
}

struct Ext {
    #[clap(subcommand)]
    sub: ExtSub
}

enum ExtSub {}
```

But it works, miraculously. `structopt` tries to "figure out what's on the other side" via `is_subcommand`.

Instead of these "magical" solutions, I propose the alternative
```rust
enum Foo {
    // no attr = flatten, backcompat
    Foo(Ext),
   
    // tell derive that ExtFlat is struct and it must be flattened 
   #[clap(flatten)]
   Bar(ExtFlat),

   // tell derive that ExtSub is enum and it must be used as subcommands set
   #[clap(subcommand)]
   Bar(ExtSub),

   // synonym for current #[structopt(flatten)]
   // see https://github.com/TeXitoi/structopt/issues/327
   #[clap(subcommand(flatten))]
   Zog(ExtSubFlat)
}
```
CreepySkeleton: > 
> 
> I don't like this commit. We should just have the users do `derive(Clap)` and our library should be smart to assume `Subcommand` since it's an enum.

Could you please elaborate on that? I've got a strong feeling we're talking about different things here.
pksunkara: > Could you please elaborate on that? I've got a strong feeling we're talking about different things here.

It is related to https://github.com/clap-rs/clap/pull/1681#discussion_r376729816
CreepySkeleton: @pksunkara Let's make sure we're talking about the same thing.

`trait Clap` is a set of functions that work on top of `IntoApp + FromArgMatches`. Users should derive it *for an enum` only if they want to use something like
```rust
#[derive(Clap)]
enum Foo { }

let args = Foo::parse();
```

`Subcommand` is to support `#[clap(subcommand)]`. Users use it if they only want the enum to be `#[clap(subcommand)]`ed. 

You're proposing to make `#[derive(Clap)]` on enum also implement `Subcommand`. Is that right?
pksunkara: Yes. What I am trying to aim for here is for the user to just simply do `derive(Clap)` and we handle everything for him.

Patch:
diff --git a/.gitignore b/.gitignore
index fb7ecb01..9260a3ed 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,3 +28,5 @@ clap-rs.iml
 
 # Auxiliary files
 test-results.test
+expanded.rs
+clap_derive/expanded.rs
diff --git a/Cargo.toml b/Cargo.toml
index ecbafd3b..610a5b50 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -2,10 +2,7 @@
 name = "clap"
 version = "3.0.0-beta.1"
 edition = "2018"
-authors = [
-	"Kevin K. <kbknapp@gmail.com>",
-	"Clap Maintainers"
-]
+authors = ["Kevin K. <kbknapp@gmail.com>"]
 include = [
 	"src/**/*",
 	"Cargo.toml",
diff --git a/README.md b/README.md
index dec22a2e..ba74f3f2 100644
--- a/README.md
+++ b/README.md
@@ -14,16 +14,6 @@ It is a simple-to-use, efficient, and full-featured library for parsing command
 * [website](https://clap.rs/)
 * [video tutorials](https://www.youtube.com/playlist?list=PLza5oFLQGTl2Z5T8g1pRkIynR3E0_pc7U)
 
-> **IMPORTANT!**
-> This readme describes `clap v3.0.0` which is still under development and will be published soon-ish. 
-> It was not published on crates.io yet, and if you want to use this preview anyway, use 
-> ```toml,no_sync
-> clap = { git = "https://github.com/clap-rs/clap/" }
-> ```
-> 
-> If you're looking for the readme for `clap v2.33` - find it on [github](https://github.com/clap-rs/clap/tree/v2.33.0), [crates.io](https://crates.io/crates/clap/2.33.0), [docs.rs](https://docs.rs/clap/2.33.0/clap/).
-
-
 Table of Contents
 =================
 
diff --git a/clap_derive/Cargo.toml b/clap_derive/Cargo.toml
index 54d28e64..a4734eef 100644
--- a/clap_derive/Cargo.toml
+++ b/clap_derive/Cargo.toml
@@ -4,7 +4,8 @@ version = "3.0.0-beta.1"
 edition = "2018"
 authors = [
 	"Guillaume Pinot <texitoi@texitoi.eu>",
-	"Clap Maintainers"
+	"Kevin K. <kbknapp@gmail.com>",
+	"hoverbear <andrew@hoverbear.org>"
 ]
 include = [
 	"src/**/*",
@@ -43,7 +44,7 @@ proc-macro-error = "0.4.3"
 
 [dev-dependencies]
 clap = { path = "../", version = "3.0.0-beta.1" }
-trybuild = "1.0"
+trybuild = "1.0.5"
 rustversion = "1"
 version-sync = "0.8"
 
diff --git a/clap_derive/src/derives/attrs.rs b/clap_derive/src/derives/attrs.rs
index 4791d09a..9d984235 100644
--- a/clap_derive/src/derives/attrs.rs
+++ b/clap_derive/src/derives/attrs.rs
@@ -104,10 +104,7 @@ pub struct Attrs {
 /// The output of a generation method is not only the stream of new tokens but also the attribute
 /// information of the current element. These attribute information may contain valuable information
 /// for any kind of child arguments.
-pub struct GenOutput {
-    pub tokens: proc_macro2::TokenStream,
-    pub attrs: Attrs,
-}
+pub type GenOutput = (proc_macro2::TokenStream, Attrs);
 
 impl Method {
     pub fn new(name: Ident, args: TokenStream) -> Self {
diff --git a/clap_derive/src/derives/clap.rs b/clap_derive/src/derives/clap.rs
index bee22813..fc81e7f9 100644
--- a/clap_derive/src/derives/clap.rs
+++ b/clap_derive/src/derives/clap.rs
@@ -11,486 +11,53 @@
 // This work was derived from Structopt (https://github.com/TeXitoi/structopt)
 // commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the
 // MIT/Apache 2.0 license.
-use proc_macro2::Span;
-use proc_macro_error::{abort, abort_call_site, set_dummy};
-use quote::{quote, quote_spanned};
-use syn::{self, punctuated, spanned::Spanned, token, FieldsUnnamed, Ident};
 
-use super::{from_argmatches, into_app, sub_type, Attrs, Kind, Name, ParserKind, Ty};
+use super::{from_argmatches, into_app, subcommand};
+use proc_macro2::Ident;
+use proc_macro_error::abort_call_site;
+use quote::quote;
+use syn::{self, punctuated, token, Attribute, DataEnum};
 
-/// Generate a block of code to add arguments/subcommands corresponding to
-/// the `fields` to an app.
-fn gen_app_augmentation(
-    fields: &punctuated::Punctuated<syn::Field, token::Comma>,
-    app_var: &syn::Ident,
-    parent_attribute: &Attrs,
-) -> proc_macro2::TokenStream {
-    let mut subcmds = fields.iter().filter_map(|field| {
-        let attrs = Attrs::from_field(
-            &field,
-            parent_attribute.casing(),
-            parent_attribute.env_casing(),
-        );
-        let kind = attrs.kind();
-        if let Kind::Subcommand(ty) = &*kind {
-            let subcmd_type = match (**ty, sub_type(&field.ty)) {
-                (Ty::Option, Some(sub_type)) => sub_type,
-                _ => &field.ty,
-            };
-            let required = if **ty == Ty::Option {
-                quote!()
-            } else {
-                quote_spanned! { kind.span()=>
-                    let #app_var = #app_var.setting(
-                        ::clap::AppSettings::SubcommandRequiredElseHelp
-                    );
-                }
-            };
-
-            let span = field.span();
-            let ts = quote! {
-                let #app_var = <#subcmd_type>::augment_app( #app_var );
-                #required
-            };
-            Some((span, ts))
-        } else {
-            None
-        }
-    });
-    let subcmd = subcmds.next().map(|(_, ts)| ts);
-    if let Some((span, _)) = subcmds.next() {
-        abort!(
-            span,
-            "multiple subcommand sets are not allowed, that's the second"
-        );
-    }
-
-    let args = fields.iter().filter_map(|field| {
-        let attrs = Attrs::from_field(
-            field,
-            parent_attribute.casing(),
-            parent_attribute.env_casing(),
-        );
-        let kind = attrs.kind();
-        match &*kind {
-            Kind::Subcommand(_) | Kind::Skip(_) => None,
-            Kind::Flatten => {
-                let ty = &field.ty;
-                Some(quote_spanned! { kind.span()=>
-                    let #app_var = <#ty>::augment_app(#app_var);
-                    let #app_var = if <#ty>::is_subcommand() {
-                        #app_var.setting(::clap::AppSettings::SubcommandRequiredElseHelp)
-                    } else {
-                        #app_var
-                    };
-                })
-            }
-            Kind::Arg(ty) => {
-                let convert_type = match **ty {
-                    Ty::Vec | Ty::Option => sub_type(&field.ty).unwrap_or(&field.ty),
-                    Ty::OptionOption | Ty::OptionVec => {
-                        sub_type(&field.ty).and_then(sub_type).unwrap_or(&field.ty)
-                    }
-                    _ => &field.ty,
-                };
-
-                let occurrences = *attrs.parser().kind == ParserKind::FromOccurrences;
-                let flag = *attrs.parser().kind == ParserKind::FromFlag;
-
-                let parser = attrs.parser();
-                let func = &parser.func;
-                let validator = match *parser.kind {
-                    ParserKind::TryFromStr => quote_spanned! { func.span()=>
-                        .validator(|s| {
-                            #func(s.as_str())
-                            .map(|_: #convert_type| ())
-                            .map_err(|e| e.to_string())
-                        })
-                    },
-                    ParserKind::TryFromOsStr => quote_spanned! { func.span()=>
-                        .validator_os(|s| #func(&s).map(|_: #convert_type| ()))
-                    },
-                    _ => quote!(),
-                };
-
-                let modifier = match **ty {
-                    Ty::Bool => quote!(),
-
-                    Ty::Option => quote_spanned! { ty.span()=>
-                        .takes_value(true)
-                        #validator
-                    },
-
-                    Ty::OptionOption => quote_spanned! { ty.span()=>
-                        .takes_value(true)
-                        .multiple(false)
-                        .min_values(0)
-                        .max_values(1)
-                        #validator
-                    },
-
-                    Ty::OptionVec => quote_spanned! { ty.span()=>
-                        .takes_value(true)
-                        .multiple(true)
-                        .min_values(0)
-                        #validator
-                    },
-
-                    Ty::Vec => quote_spanned! { ty.span()=>
-                        .takes_value(true)
-                        .multiple(true)
-                        #validator
-                    },
-
-                    Ty::Other if occurrences => quote_spanned! { ty.span()=>
-                        .multiple_occurrences(true)
-                    },
-
-                    Ty::Other if flag => quote_spanned! { ty.span()=>
-                        .takes_value(false)
-                        .multiple(false)
-                    },
-
-                    Ty::Other => {
-                        let required = !attrs.has_method("default_value");
-                        quote_spanned! { ty.span()=>
-                            .takes_value(true)
-                            .required(#required)
-                            #validator
-                        }
-                    }
-                };
-
-                let name = attrs.cased_name();
-                let methods = attrs.field_methods();
-
-                Some(quote_spanned! { field.span()=>
-                    let #app_var = #app_var.arg(
-                        ::clap::Arg::with_name(#name)
-                            #modifier
-                            #methods
-                    );
-                })
-            }
-        }
-    });
-
-    let app_methods = parent_attribute.top_level_methods();
-    let version = parent_attribute.version();
-    quote! {{
-        let #app_var = #app_var#app_methods;
-        #( #args )*
-        #subcmd
-        #app_var#version
-    }}
-}
-
-fn gen_augment_app_fn(
-    fields: &punctuated::Punctuated<syn::Field, token::Comma>,
-    parent_attribute: &Attrs,
-) -> proc_macro2::TokenStream {
-    let app_var = syn::Ident::new("app", proc_macro2::Span::call_site());
-    let augmentation = gen_app_augmentation(fields, &app_var, parent_attribute);
-    quote! {
-        pub fn augment_app<'b>(
-            #app_var: ::clap::App<'b>
-        ) -> ::clap::App<'b> {
-            #augmentation
-        }
-    }
-}
-
-fn gen_augment_app_for_enum(
-    variants: &punctuated::Punctuated<syn::Variant, token::Comma>,
-    parent_attribute: &Attrs,
-) -> proc_macro2::TokenStream {
-    use syn::Fields::*;
-
-    let subcommands = variants.iter().map(|variant| {
-        let attrs = Attrs::from_struct(
-            variant.span(),
-            &variant.attrs,
-            Name::Derived(variant.ident.clone()),
-            parent_attribute.casing(),
-            parent_attribute.env_casing(),
-        );
-        let kind = attrs.kind();
-        match &*kind {
-            Kind::Flatten => match variant.fields {
-                Unnamed(FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => {
-                    let ty = &unnamed[0];
-                    quote! {
-                        let app = <#ty>::augment_app(app);
-                    }
-                }
-                _ => abort!(
-                    variant.span(),
-                    "`flatten` is usable only with single-typed tuple variants"
-                ),
-            },
-            _ => {
-                let app_var = Ident::new("subcommand", Span::call_site());
-                let arg_block = match variant.fields {
-                    Named(ref fields) => gen_app_augmentation(&fields.named, &app_var, &attrs),
-                    Unit => quote!( #app_var ),
-                    Unnamed(FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => {
-                        let ty = &unnamed[0];
-                        quote_spanned! { ty.span()=>
-                            {
-                                let #app_var = <#ty>::augment_app(
-                                    #app_var
-                                );
-                                if <#ty>::is_subcommand() {
-                                    #app_var.setting(
-                                        ::clap::AppSettings::SubcommandRequiredElseHelp
-                                    )
-                                } else {
-                                    #app_var
-                                }
-                            }
-                        }
-                    }
-                    Unnamed(..) => abort!(
-                        variant.span(),
-                        "non single-typed tuple enums are not supported"
-                    ),
-                };
-
-                let name = attrs.cased_name();
-                let from_attrs = attrs.top_level_methods();
-                let version = attrs.version();
-                quote! {
-                    let app = app.subcommand({
-                        let #app_var = ::clap::App::new(#name);
-                        let #app_var = #arg_block;
-                        #app_var#from_attrs#version
-                    });
-                }
-            }
-        }
-    });
-
-    let app_methods = parent_attribute.top_level_methods();
-    let version = parent_attribute.version();
-    quote! {
-       pub fn augment_app<'b>(
-            app: ::clap::App<'b>
-        ) -> ::clap::App<'b> {
-            let app = app #app_methods;
-            #( #subcommands )*;
-            app #version
-        }
-    }
-}
-
-fn gen_from_subcommand(
-    name: &syn::Ident,
-    variants: &punctuated::Punctuated<syn::Variant, token::Comma>,
-    parent_attribute: &Attrs,
-) -> proc_macro2::TokenStream {
-    use syn::Fields::*;
-    let (flatten_variants, variants): (Vec<_>, Vec<_>) = variants
-        .iter()
-        .map(|variant| {
-            let attrs = Attrs::from_struct(
-                variant.span(),
-                &variant.attrs,
-                Name::Derived(variant.ident.clone()),
-                parent_attribute.casing(),
-                parent_attribute.env_casing(),
-            );
-            (variant, attrs)
-        })
-        .partition(|(_, attrs)| {
-            let kind = attrs.kind();
-            match &*kind {
-                Kind::Flatten => true,
-                _ => false,
-            }
-        });
-
-    let match_arms = variants.iter().map(|(variant, attrs)| {
-        let sub_name = attrs.cased_name();
-        let variant_name = &variant.ident;
-        let constructor_block = match variant.fields {
-            Named(ref fields) => from_argmatches::gen_constructor(&fields.named, &attrs),
-            Unit => quote!(),
-            Unnamed(ref fields) if fields.unnamed.len() == 1 => {
-                let ty = &fields.unnamed[0];
-                quote!( ( <#ty as ::clap::FromArgMatches>::from_argmatches(matches) ) )
-            }
-            Unnamed(..) => abort_call_site!("{}: tuple enums are not supported", variant.ident),
-        };
+pub fn derive_clap(input: &syn::DeriveInput) -> proc_macro2::TokenStream {
+    use syn::Data::*;
 
-        quote! {
-            (#sub_name, Some(matches)) => {
-                Some(#name :: #variant_name #constructor_block)
-            }
-        }
-    });
-    let child_subcommands = flatten_variants.iter().map(|(variant, _attrs)| {
-        let variant_name = &variant.ident;
-        match variant.fields {
-            Unnamed(ref fields) if fields.unnamed.len() == 1 => {
-                let ty = &fields.unnamed[0];
-                quote! {
-                    if let Some(res) = <#ty>::from_subcommand(other) {
-                        return Some(#name :: #variant_name (res));
-                    }
-                }
-            }
-            _ => abort!(
-                variant.span(),
-                "`flatten` is usable only with single-typed tuple variants"
-            ),
-        }
-    });
+    let ident = &input.ident;
 
-    quote! {
-        pub fn from_subcommand<'b>(
-            sub: (&'b str, Option<&'b ::clap::ArgMatches>)
-        ) -> Option<Self> {
-            match sub {
-                #( #match_arms ),*,
-                other => {
-                    #( #child_subcommands )*;
-                    None
-                }
-            }
-        }
+    match input.data {
+        Struct(syn::DataStruct {
+            fields: syn::Fields::Named(ref fields),
+            ..
+        }) => gen_for_struct(ident, &fields.named, &input.attrs),
+        Enum(ref e) => gen_for_enum(ident, &input.attrs, e),
+        _ => abort_call_site!("`#[derive(Clap)]` only supports non-tuple structs and enums"),
     }
 }
 
-fn clap_impl_for_struct(
+fn gen_for_struct(
     name: &syn::Ident,
     fields: &punctuated::Punctuated<syn::Field, token::Comma>,
     attrs: &[syn::Attribute],
 ) -> proc_macro2::TokenStream {
-    let into_app_impl = into_app::gen_into_app_impl_for_struct(name, attrs);
-    let into_app_impl_tokens = into_app_impl.tokens;
-    let augment_app_fn = gen_augment_app_fn(fields, &into_app_impl.attrs);
-    let from_argmatches_impl =
-        from_argmatches::gen_from_argmatches_impl_for_struct(name, fields, &into_app_impl.attrs);
-    let parse_fns = gen_parse_fns(name);
+    let (into_app, attrs) = into_app::gen_for_struct(name, fields, attrs);
+    let from_arg_matches = from_argmatches::gen_for_struct(name, fields, &attrs);
 
     quote! {
-        #[allow(unused_variables)]
-        impl ::clap::Clap for #name { }
-
-        #into_app_impl_tokens
-
-        #from_argmatches_impl
-
-        #[allow(dead_code, unreachable_code)]
-        #[doc(hidden)]
-        impl #name {
-            #augment_app_fn
-
-            #parse_fns
+        impl ::clap::Clap for #name {}
 
-            pub fn is_subcommand() -> bool { false }
-        }
+        #into_app
+        #from_arg_matches
     }
 }
 
-fn clap_impl_for_enum(
-    name: &syn::Ident,
-    variants: &punctuated::Punctuated<syn::Variant, token::Comma>,
-    attrs: &[syn::Attribute],
-) -> proc_macro2::TokenStream {
-    let into_app_impl = into_app::gen_into_app_impl_for_enum(name, attrs);
-    let into_app_impl_tokens = into_app_impl.tokens;
-    let augment_app_fn = gen_augment_app_for_enum(variants, &into_app_impl.attrs);
-    let from_argmatches_impl = from_argmatches::gen_from_argmatches_impl_for_enum(name);
-    let from_subcommand = gen_from_subcommand(name, variants, &into_app_impl.attrs);
-    let parse_fns = gen_parse_fns(name);
-
+fn gen_for_enum(name: &Ident, attrs: &[Attribute], e: &DataEnum) -> proc_macro2::TokenStream {
+    let into_app = into_app::gen_for_enum(name);
+    let from_arg_matches = from_argmatches::gen_for_enum(name);
+    let subcommand = subcommand::gen_for_enum(name, attrs, e);
     quote! {
-        #[allow(unused_variables)]
         impl ::clap::Clap for #name { }
 
-        #into_app_impl_tokens
-
-        #from_argmatches_impl
-
-        #[allow(unused_variables, dead_code, unreachable_code)]
-        #[doc(hidden)]
-        impl #name {
-            #augment_app_fn
-
-            #from_subcommand
-
-            #parse_fns
-
-            pub fn is_subcommand() -> bool { true }
-        }
-    }
-}
-
-pub fn derive_clap(input: &syn::DeriveInput) -> proc_macro2::TokenStream {
-    use syn::Data::*;
-
-    let struct_name = &input.ident;
-
-    set_dummy(quote! {
-        impl ::clap::Clap for #struct_name {}
-
-        impl ::clap::IntoApp for #struct_name {
-            fn into_app<'b>() -> ::clap::App<'b> {
-                unimplemented!()
-            }
-        }
-
-        impl ::clap::FromArgMatches for #struct_name {
-            fn from_argmatches(m: &::clap::ArgMatches) -> Self {
-                unimplemented!()
-            }
-        }
-
-        impl #struct_name {
-           pub fn parse() -> Self {
-                unimplemented!();
-            }
-        }
-    });
-
-    match input.data {
-        Struct(syn::DataStruct {
-            fields: syn::Fields::Named(ref fields),
-            ..
-        }) => clap_impl_for_struct(struct_name, &fields.named, &input.attrs),
-        Enum(ref e) => clap_impl_for_enum(struct_name, &e.variants, &input.attrs),
-        _ => abort_call_site!("clap_derive only supports non-tuple structs and enums"),
-    }
-}
-
-fn gen_parse_fns(name: &syn::Ident) -> proc_macro2::TokenStream {
-    quote! {
-        #[allow(unreachable_pub)]
-        pub fn parse() -> #name {
-            use ::clap::{FromArgMatches, IntoApp};
-            #name::from_argmatches(&#name::into_app().get_matches())
-        }
-        #[allow(unreachable_pub)]
-        pub fn try_parse() -> ::std::result::Result<#name, ::clap::Error> {
-            use ::clap::{FromArgMatches, IntoApp};
-            Ok(#name::from_argmatches(&#name::into_app().try_get_matches()?))
-        }
-        #[allow(unreachable_pub)]
-        pub fn parse_from<I, T>(itr: I) -> #name
-        where
-            I: ::std::iter::IntoIterator<Item = T>,
-            T: Into<::std::ffi::OsString> + Clone {
-            use ::clap::{FromArgMatches, IntoApp};
-            #name::from_argmatches(&#name::into_app().get_matches_from(itr))
-        }
-        #[allow(unreachable_pub)]
-        pub fn try_parse_from<I, T>(itr: I) -> ::std::result::Result<#name, ::clap::Error>
-        where
-            I: ::std::iter::IntoIterator<Item = T>,
-            T: Into<::std::ffi::OsString> + Clone {
-            use ::clap::{FromArgMatches, IntoApp};
-            Ok(#name::from_argmatches(&#name::into_app().try_get_matches_from(itr)?))
-        }
+        #into_app
+        #from_arg_matches
+        #subcommand
     }
 }
diff --git a/clap_derive/src/derives/from_argmatches.rs b/clap_derive/src/derives/from_argmatches.rs
index fe12628f..1052cebf 100644
--- a/clap_derive/src/derives/from_argmatches.rs
+++ b/clap_derive/src/derives/from_argmatches.rs
@@ -13,10 +13,9 @@
 // MIT/Apache 2.0 license.
 use std::env;
 
-use proc_macro2;
+use proc_macro_error::abort_call_site;
 use quote::{quote, quote_spanned};
-use syn::spanned::Spanned as _;
-use syn::{punctuated, token};
+use syn::{punctuated::Punctuated, spanned::Spanned, Token};
 
 use super::{
     spanned::Sp, sub_type, Attrs, Kind, Name, ParserKind, Ty, DEFAULT_CASING, DEFAULT_ENV_CASING,
@@ -26,14 +25,12 @@ pub fn derive_from_argmatches(input: &syn::DeriveInput) -> proc_macro2::TokenStr
     use syn::Data::*;
 
     let struct_name = &input.ident;
-    let inner_impl = match input.data {
+    match input.data {
         Struct(syn::DataStruct {
             fields: syn::Fields::Named(ref fields),
             ..
         }) => {
-            let name = env::var("CARGO_PKG_NAME")
-                .ok()
-                .unwrap_or_else(String::default);
+            let name = env::var("CARGO_PKG_NAME").ok().unwrap_or_default();
 
             let attrs = Attrs::from_struct(
                 proc_macro2::Span::call_site(),
@@ -43,54 +40,17 @@ pub fn derive_from_argmatches(input: &syn::DeriveInput) -> proc_macro2::TokenStr
                 Sp::call_site(DEFAULT_ENV_CASING),
             );
 
-            gen_from_argmatches_impl_for_struct(struct_name, &fields.named, &attrs)
+            gen_for_struct(struct_name, &fields.named, &attrs)
         }
-        // Enum(ref e) => clap_for_enum_impl(struct_name, &e.variants, &input.attrs),
-        _ => panic!("clap_derive only supports non-tuple structs"), // and enums"),
-    };
-
-    quote!(#inner_impl)
-}
-
-pub fn gen_from_argmatches_impl_for_struct(
-    name: &syn::Ident,
-    fields: &punctuated::Punctuated<syn::Field, token::Comma>,
-    parent_attribute: &Attrs,
-) -> proc_macro2::TokenStream {
-    let from_argmatches_fn = gen_from_argmatches_fn_for_struct(name, fields, parent_attribute);
-
-    quote! {
-        impl ::clap::FromArgMatches for #name {
-            #from_argmatches_fn
-        }
-
-        impl From<::clap::ArgMatches> for #name {
-            fn from(m: ::clap::ArgMatches) -> Self {
-                use ::clap::FromArgMatches;
-                <Self as ::clap::FromArgMatches>::from_argmatches(&m)
-            }
-        }
-
-        // @TODO impl TryFrom once stable
-    }
-}
-
-pub fn gen_from_argmatches_fn_for_struct(
-    struct_name: &syn::Ident,
-    fields: &punctuated::Punctuated<syn::Field, token::Comma>,
-    parent_attribute: &Attrs,
-) -> proc_macro2::TokenStream {
-    let field_block = gen_constructor(fields, parent_attribute);
-
-    quote! {
-        fn from_argmatches(matches: &::clap::ArgMatches) -> Self {
-            #struct_name #field_block
+        Enum(_) => gen_for_enum(struct_name),
+        _ => {
+            abort_call_site!("#[derive(FromArgMatches)] only supports non-tuple structs and enums")
         }
     }
 }
 
 pub fn gen_constructor(
-    fields: &punctuated::Punctuated<syn::Field, token::Comma>,
+    fields: &Punctuated<syn::Field, Token![,]>,
     parent_attribute: &Attrs,
 ) -> proc_macro2::TokenStream {
     let fields = fields.iter().map(|field| {
@@ -112,12 +72,19 @@ pub fn gen_constructor(
                     _ => quote_spanned!( ty.span()=> .unwrap() ),
                 };
                 quote_spanned! { kind.span()=>
-                    #field_name: <#subcmd_type>::from_subcommand(matches.subcommand())#unwrapper
+                    #field_name: {
+                        let (name, subcmd) = matches.subcommand();
+                        <#subcmd_type as ::clap::Subcommand>::from_subcommand(
+                            name,
+                            subcmd
+                        )
+                        #unwrapper
+                    }
                 }
             }
 
             Kind::Flatten => quote_spanned! { kind.span()=>
-                #field_name: ::clap::FromArgMatches::from_argmatches(matches)
+                #field_name: ::clap::FromArgMatches::from_arg_matches(matches)
             },
 
             Kind::Skip(val) => match val {
@@ -222,22 +189,30 @@ pub fn gen_constructor(
     }}
 }
 
-pub fn gen_from_argmatches_impl_for_enum(name: &syn::Ident) -> proc_macro2::TokenStream {
+pub fn gen_for_struct(
+    struct_name: &syn::Ident,
+    fields: &Punctuated<syn::Field, Token![,]>,
+    parent_attribute: &Attrs,
+) -> proc_macro2::TokenStream {
+    let constructor = gen_constructor(fields, parent_attribute);
+
     quote! {
-        impl ::clap::FromArgMatches for #name {
-            fn from_argmatches(matches: &::clap::ArgMatches) -> Self {
-                <#name>::from_subcommand(matches.subcommand())
-                    .unwrap()
+        impl ::clap::FromArgMatches for #struct_name {
+            fn from_arg_matches(matches: &::clap::ArgMatches) -> Self {
+                #struct_name #constructor
             }
         }
+    }
+}
 
-        impl From<::clap::ArgMatches> for #name {
-            fn from(m: ::clap::ArgMatches) -> Self {
-                use ::clap::FromArgMatches;
-                <Self as ::clap::FromArgMatches>::from_argmatches(&m)
+pub fn gen_for_enum(name: &syn::Ident) -> proc_macro2::TokenStream {
+    quote! {
+        impl ::clap::FromArgMatches for #name {
+            fn from_arg_matches(matches: &::clap::ArgMatches) -> Self {
+                let (name, subcmd) = matches.subcommand();
+                <#name as ::clap::Subcommand>::from_subcommand(name, subcmd)
+                    .unwrap()
             }
         }
-
-        // @TODO: impl TryFrom once stable
     }
 }
diff --git a/clap_derive/src/derives/into_app.rs b/clap_derive/src/derives/into_app.rs
index b7949d45..5f44c4d0 100644
--- a/clap_derive/src/derives/into_app.rs
+++ b/clap_derive/src/derives/into_app.rs
@@ -11,124 +11,261 @@
 // This work was derived from Structopt (https://github.com/TeXitoi/structopt)
 // commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the
 // MIT/Apache 2.0 license.
+
 use std::env;
 
-use proc_macro2;
-use quote::quote;
-use syn;
+use proc_macro2::TokenStream;
+use proc_macro_error::{abort, abort_call_site};
+use quote::{quote, quote_spanned};
+use syn::{punctuated::Punctuated, spanned::Spanned, Token};
 
-use super::{spanned::Sp, Attrs, GenOutput, Name, DEFAULT_CASING, DEFAULT_ENV_CASING};
+use super::{
+    spanned::Sp, ty::Ty, Attrs, GenOutput, Kind, Name, ParserKind, DEFAULT_CASING,
+    DEFAULT_ENV_CASING,
+};
+use crate::derives::ty::sub_type;
 
 pub fn derive_into_app(input: &syn::DeriveInput) -> proc_macro2::TokenStream {
     use syn::Data::*;
 
-    let struct_name = &input.ident;
-    let inner_impl = match input.data {
-        Struct(syn::DataStruct { .. }) => {
-            gen_into_app_impl_for_struct(struct_name, &input.attrs).tokens
-        }
-        // @TODO impl into_app for enums?
-        // Enum(ref e) => clap_for_enum_impl(struct_name, &e.variants, &input.attrs),
-        _ => panic!("clap_derive only supports non-tuple structs"), // and enums"),
-    };
-
-    quote!(#inner_impl)
+    match input.data {
+        Struct(syn::DataStruct {
+            fields: syn::Fields::Named(ref fields),
+            ..
+        }) => gen_for_struct(&input.ident, &fields.named, &input.attrs).0,
+        Enum(_) => gen_for_enum(&input.ident),
+        _ => abort_call_site!("#[derive(IntoApp)] only supports non-tuple structs and enums"),
+    }
 }
 
-pub fn gen_into_app_impl_for_struct(name: &syn::Ident, attrs: &[syn::Attribute]) -> GenOutput {
-    let into_app_fn = gen_into_app_fn_for_struct(attrs);
-    let into_app_fn_tokens = into_app_fn.tokens;
+pub fn gen_for_struct(
+    struct_name: &syn::Ident,
+    fields: &Punctuated<syn::Field, Token![,]>,
+    attrs: &[syn::Attribute],
+) -> GenOutput {
+    let (into_app, attrs) = gen_into_app_fn(attrs);
+    let augment_clap = gen_augment_clap_fn(fields, &attrs);
 
     let tokens = quote! {
-        impl ::clap::IntoApp for #name {
-            #into_app_fn_tokens
-        }
-
-        impl<'b> Into<::clap::App<'b>> for #name {
-            fn into(self) -> ::clap::App<'b> {
-                use ::clap::IntoApp;
-                <#name as ::clap::IntoApp>::into_app()
-            }
+        impl ::clap::IntoApp for #struct_name {
+            #into_app
+            #augment_clap
         }
     };
 
-    GenOutput {
-        tokens,
-        attrs: into_app_fn.attrs,
-    }
+    (tokens, attrs)
 }
 
-pub fn gen_into_app_fn_for_struct(struct_attrs: &[syn::Attribute]) -> GenOutput {
-    let gen = gen_app_builder(struct_attrs);
-    let app_tokens = gen.tokens;
+pub fn gen_for_enum(name: &syn::Ident) -> TokenStream {
+    let app_name = env::var("CARGO_PKG_NAME").ok().unwrap_or_default();
 
-    let tokens = quote! {
-        fn into_app<'b>() -> ::clap::App<'b> {
-            Self::augment_app(#app_tokens)
-        }
-    };
+    quote! {
+        impl ::clap::IntoApp for #name {
+            fn into_app<'b>() -> ::clap::App<'b> {
+                let app = ::clap::App::new(#app_name)
+                    .setting(::clap::AppSettings::SubcommandRequiredElseHelp);
+                <#name as ::clap::IntoApp>::augment_clap(app)
+            }
 
-    GenOutput {
-        tokens,
-        attrs: gen.attrs,
+            fn augment_clap<'b>(app: ::clap::App<'b>) -> ::clap::App<'b> {
+                <#name as ::clap::Subcommand>::augment_subcommands(app)
+            }
+        }
     }
 }
 
-pub fn gen_app_builder(attrs: &[syn::Attribute]) -> GenOutput {
-    let name = env::var("CARGO_PKG_NAME").ok().unwrap_or_default();
+fn gen_into_app_fn(attrs: &[syn::Attribute]) -> GenOutput {
+    let app_name = env::var("CARGO_PKG_NAME").ok().unwrap_or_default();
 
     let attrs = Attrs::from_struct(
         proc_macro2::Span::call_site(),
         attrs,
-        Name::Assigned(quote!(#name)),
+        Name::Assigned(quote!(#app_name)),
         Sp::call_site(DEFAULT_CASING),
         Sp::call_site(DEFAULT_ENV_CASING),
     );
-    let tokens = {
-        let name = attrs.cased_name();
-        quote!(::clap::App::new(#name))
+    let name = attrs.cased_name();
+
+    let tokens = quote! {
+        fn into_app<'b>() -> ::clap::App<'b> {
+            Self::augment_clap(::clap::App::new(#name))
+        }
     };
 
-    GenOutput { tokens, attrs }
+    (tokens, attrs)
 }
 
-pub fn gen_into_app_impl_for_enum(name: &syn::Ident, attrs: &[syn::Attribute]) -> GenOutput {
-    let into_app_fn = gen_into_app_fn_for_enum(attrs);
-    let into_app_fn_tokens = into_app_fn.tokens;
+fn gen_augment_clap_fn(
+    fields: &Punctuated<syn::Field, Token![,]>,
+    parent_attribute: &Attrs,
+) -> proc_macro2::TokenStream {
+    let app_var = syn::Ident::new("app", proc_macro2::Span::call_site());
+    let augmentation = gen_app_augmentation(fields, &app_var, parent_attribute);
+    quote! {
+        fn augment_clap<'b>(#app_var: ::clap::App<'b>) -> ::clap::App<'b> {
+            #augmentation
+        }
+    }
+}
 
-    let tokens = quote! {
-        impl ::clap::IntoApp for #name {
-            #into_app_fn_tokens
+/// Generate a block of code to add arguments/subcommands corresponding to
+/// the `fields` to an app.
+pub fn gen_app_augmentation(
+    fields: &Punctuated<syn::Field, Token![,]>,
+    app_var: &syn::Ident,
+    parent_attribute: &Attrs,
+) -> proc_macro2::TokenStream {
+    let mut subcmds = fields.iter().filter_map(|field| {
+        let attrs = Attrs::from_field(
+            &field,
+            parent_attribute.casing(),
+            parent_attribute.env_casing(),
+        );
+        let kind = attrs.kind();
+        if let Kind::Subcommand(ty) = &*kind {
+            let subcmd_type = match (**ty, sub_type(&field.ty)) {
+                (Ty::Option, Some(sub_type)) => sub_type,
+                _ => &field.ty,
+            };
+            let required = if **ty == Ty::Option {
+                quote!()
+            } else {
+                quote_spanned! { kind.span()=>
+                    let #app_var = #app_var.setting(
+                        ::clap::AppSettings::SubcommandRequiredElseHelp
+                    );
+                }
+            };
+
+            let span = field.span();
+            let ts = quote! {
+                let #app_var = <#subcmd_type as ::clap::Subcommand>::augment_subcommands( #app_var );
+                #required
+            };
+            Some((span, ts))
+        } else {
+            None
         }
+    });
+    let subcmd = subcmds.next().map(|(_, ts)| ts);
+    if let Some((span, _)) = subcmds.next() {
+        abort!(
+            span,
+            "multiple subcommand sets are not allowed, that's the second"
+        );
+    }
 
-        impl<'b> Into<::clap::App<'b>> for #name {
-            fn into(self) -> ::clap::App<'b> {
-                use ::clap::IntoApp;
-                <#name as ::clap::IntoApp>::into_app()
+    let args = fields.iter().filter_map(|field| {
+        let attrs = Attrs::from_field(
+            field,
+            parent_attribute.casing(),
+            parent_attribute.env_casing(),
+        );
+        let kind = attrs.kind();
+        match &*kind {
+            Kind::Subcommand(_) | Kind::Skip(_) => None,
+            Kind::Flatten => {
+                let ty = &field.ty;
+                Some(quote_spanned! { kind.span()=>
+                    let #app_var = <#ty as ::clap::IntoApp>::augment_clap(#app_var);
+                })
             }
-        }
-    };
+            Kind::Arg(ty) => {
+                let convert_type = match **ty {
+                    Ty::Vec | Ty::Option => sub_type(&field.ty).unwrap_or(&field.ty),
+                    Ty::OptionOption | Ty::OptionVec => {
+                        sub_type(&field.ty).and_then(sub_type).unwrap_or(&field.ty)
+                    }
+                    _ => &field.ty,
+                };
 
-    GenOutput {
-        tokens,
-        attrs: into_app_fn.attrs,
-    }
-}
+                let occurrences = *attrs.parser().kind == ParserKind::FromOccurrences;
+                let flag = *attrs.parser().kind == ParserKind::FromFlag;
 
-pub fn gen_into_app_fn_for_enum(enum_attrs: &[syn::Attribute]) -> GenOutput {
-    let gen = gen_app_builder(enum_attrs);
-    let app_tokens = gen.tokens;
+                let parser = attrs.parser();
+                let func = &parser.func;
+                let validator = match *parser.kind {
+                    ParserKind::TryFromStr => quote_spanned! { func.span()=>
+                        .validator(|s| {
+                            #func(s.as_str())
+                            .map(|_: #convert_type| ())
+                            .map_err(|e| e.to_string())
+                        })
+                    },
+                    ParserKind::TryFromOsStr => quote_spanned! { func.span()=>
+                        .validator_os(|s| #func(&s).map(|_: #convert_type| ()))
+                    },
+                    _ => quote!(),
+                };
 
-    let tokens = quote! {
-        fn into_app<'b>() -> ::clap::App<'b> {
-            let app = #app_tokens
-                .setting(::clap::AppSettings::SubcommandRequiredElseHelp);
-            Self::augment_app(app)
+                let modifier = match **ty {
+                    Ty::Bool => quote!(),
+
+                    Ty::Option => quote_spanned! { ty.span()=>
+                        .takes_value(true)
+                        #validator
+                    },
+
+                    Ty::OptionOption => quote_spanned! { ty.span()=>
+                        .takes_value(true)
+                        .multiple(false)
+                        .min_values(0)
+                        .max_values(1)
+                        #validator
+                    },
+
+                    Ty::OptionVec => quote_spanned! { ty.span()=>
+                        .takes_value(true)
+                        .multiple(true)
+                        .min_values(0)
+                        #validator
+                    },
+
+                    Ty::Vec => quote_spanned! { ty.span()=>
+                        .takes_value(true)
+                        .multiple(true)
+                        #validator
+                    },
+
+                    Ty::Other if occurrences => quote_spanned! { ty.span()=>
+                        .multiple_occurrences(true)
+                    },
+
+                    Ty::Other if flag => quote_spanned! { ty.span()=>
+                        .takes_value(false)
+                        .multiple(false)
+                    },
+
+                    Ty::Other => {
+                        let required = !attrs.has_method("default_value");
+                        quote_spanned! { ty.span()=>
+                            .takes_value(true)
+                            .required(#required)
+                            #validator
+                        }
+                    }
+                };
+
+                let name = attrs.cased_name();
+                let methods = attrs.field_methods();
+
+                Some(quote_spanned! { field.span()=>
+                    let #app_var = #app_var.arg(
+                        ::clap::Arg::with_name(#name)
+                            #modifier
+                            #methods
+                    );
+                })
+            }
         }
-    };
+    });
 
-    GenOutput {
-        tokens,
-        attrs: gen.attrs,
-    }
+    let app_methods = parent_attribute.top_level_methods();
+    let version = parent_attribute.version();
+    quote! {{
+        let #app_var = #app_var#app_methods;
+        #( #args )*
+        #subcmd
+        #app_var#version
+    }}
 }
diff --git a/clap_derive/src/derives/mod.rs b/clap_derive/src/derives/mod.rs
index ad411238..ce4ceb3b 100644
--- a/clap_derive/src/derives/mod.rs
+++ b/clap_derive/src/derives/mod.rs
@@ -19,6 +19,7 @@ mod from_argmatches;
 mod into_app;
 pub mod parse;
 pub mod spanned;
+mod subcommand;
 pub mod ty;
 
 // pub use self::arg_enum::derive_arg_enum;
@@ -29,4 +30,5 @@ pub use self::attrs::{
 pub use self::clap::derive_clap;
 pub use self::from_argmatches::derive_from_argmatches;
 pub use self::into_app::derive_into_app;
+pub use self::subcommand::derive_subcommand;
 pub use self::ty::{sub_type, Ty};
diff --git a/clap_derive/src/derives/spanned.rs b/clap_derive/src/derives/spanned.rs
index 8abe3052..adde02dd 100644
--- a/clap_derive/src/derives/spanned.rs
+++ b/clap_derive/src/derives/spanned.rs
@@ -1,8 +1,9 @@
 use proc_macro2::{Ident, Span, TokenStream};
 use quote::ToTokens;
-use std::ops::{Deref, DerefMut};
 use syn::LitStr;
 
+use std::ops::{Deref, DerefMut};
+
 /// An entity with a span attached.
 #[derive(Debug, Clone)]
 pub struct Sp<T> {
diff --git a/clap_derive/src/derives/subcommand.rs b/clap_derive/src/derives/subcommand.rs
new file mode 100644
index 00000000..79d6dcc8
--- /dev/null
+++ b/clap_derive/src/derives/subcommand.rs
@@ -0,0 +1,211 @@
+use crate::derives::attrs::{Attrs, Kind, Name, DEFAULT_CASING, DEFAULT_ENV_CASING};
+use crate::derives::{from_argmatches, into_app, spanned::Sp};
+
+use proc_macro2::{Ident, Span, TokenStream};
+use proc_macro_error::{abort, abort_call_site, set_dummy};
+use quote::{quote, quote_spanned};
+use syn::{
+    punctuated::Punctuated, spanned::Spanned, Attribute, Data, DataEnum, FieldsUnnamed, Token,
+    Variant,
+};
+
+pub fn derive_subcommand(input: &syn::DeriveInput) -> TokenStream {
+    let name = &input.ident;
+
+    set_dummy(quote! {
+        impl ::clap::Subcommand for #name {
+            fn from_subcommand<'b>(
+                name: &str,
+                matches: ::std::option::Option<&::clap::ArgMatches>
+            ) -> Option<Self> {
+                unimplemented!()
+            }
+
+            fn augment_subcommands<'b>(app: ::clap::App<'b>) -> ::clap::App<'b> {
+                unimplemented!()
+            }
+        }
+    });
+
+    match input.data {
+        Data::Enum(ref e) => gen_for_enum(name, &input.attrs, e),
+        _ => abort_call_site!(
+            "`#[derive(Subcommand)]` supports only enums";
+            hint = "use `#[derive(Clap)]` for structs";
+        ),
+    }
+}
+
+pub fn gen_for_enum(name: &Ident, attrs: &[Attribute], e: &DataEnum) -> TokenStream {
+    let attrs = Attrs::from_struct(
+        Span::call_site(),
+        attrs,
+        Name::Derived(name.clone()),
+        Sp::call_site(DEFAULT_CASING),
+        Sp::call_site(DEFAULT_ENV_CASING),
+    );
+
+    let from_subcommand = gen_from_subcommand(name, &e.variants, &attrs);
+    let augment_subcommands = gen_augment_subcommands(&e.variants, &attrs);
+
+    quote! {
+        impl ::clap::Subcommand for #name {
+            #augment_subcommands
+            #from_subcommand
+        }
+    }
+}
+
+fn gen_augment_subcommands(
+    variants: &Punctuated<syn::Variant, Token![,]>,
+    parent_attribute: &Attrs,
+) -> proc_macro2::TokenStream {
+    use syn::Fields::*;
+
+    let subcommands = variants.iter().map(|variant| {
+        let attrs = Attrs::from_struct(
+            variant.span(),
+            &variant.attrs,
+            Name::Derived(variant.ident.clone()),
+            parent_attribute.casing(),
+            parent_attribute.env_casing(),
+        );
+        let kind = attrs.kind();
+        match &*kind {
+            Kind::Flatten => match variant.fields {
+                Unnamed(FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => {
+                    let ty = &unnamed[0];
+                    quote! {
+                        let app = <#ty as ::clap::Subcommand>::augment_subcommands(app);
+                    }
+                }
+                _ => abort!(
+                    variant.span(),
+                    "`flatten` is usable only with single-typed tuple variants"
+                ),
+            },
+
+            _ => {
+                let app_var = Ident::new("subcommand", Span::call_site());
+                let arg_block = match variant.fields {
+                    Named(ref fields) => {
+                        into_app::gen_app_augmentation(&fields.named, &app_var, &attrs)
+                    }
+                    Unit => quote!( #app_var ),
+                    Unnamed(FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => {
+                        let ty = &unnamed[0];
+                        quote_spanned! { ty.span()=>
+                            {
+                                <#ty as ::clap::IntoApp>::augment_clap(#app_var)
+                            }
+                        }
+                    }
+                    Unnamed(..) => abort!(
+                        variant.span(),
+                        "non single-typed tuple enums are not supported"
+                    ),
+                };
+
+                let name = attrs.cased_name();
+                let from_attrs = attrs.top_level_methods();
+                let version = attrs.version();
+                quote! {
+                    let app = app.subcommand({
+                        let #app_var = ::clap::App::new(#name);
+                        let #app_var = #arg_block;
+                        #app_var#from_attrs#version
+                    });
+                }
+            }
+        }
+    });
+
+    let app_methods = parent_attribute.top_level_methods();
+    let version = parent_attribute.version();
+    quote! {
+        fn augment_subcommands<'b>(app: ::clap::App<'b>) -> ::clap::App<'b> {
+            let app = app #app_methods;
+            #( #subcommands )*;
+            app #version
+        }
+    }
+}
+
+fn gen_from_subcommand(
+    name: &syn::Ident,
+    variants: &Punctuated<Variant, Token![,]>,
+    parent_attribute: &Attrs,
+) -> proc_macro2::TokenStream {
+    use syn::Fields::*;
+    let (flatten_variants, variants): (Vec<_>, Vec<_>) = variants
+        .iter()
+        .map(|variant| {
+            let attrs = Attrs::from_struct(
+                variant.span(),
+                &variant.attrs,
+                Name::Derived(variant.ident.clone()),
+                parent_attribute.casing(),
+                parent_attribute.env_casing(),
+            );
+            (variant, attrs)
+        })
+        .partition(|(_, attrs)| {
+            let kind = attrs.kind();
+            match &*kind {
+                Kind::Flatten => true,
+                _ => false,
+            }
+        });
+
+    let match_arms = variants.iter().map(|(variant, attrs)| {
+        let sub_name = attrs.cased_name();
+        let variant_name = &variant.ident;
+        let constructor_block = match variant.fields {
+            Named(ref fields) => from_argmatches::gen_constructor(&fields.named, &attrs),
+            Unit => quote!(),
+            Unnamed(ref fields) if fields.unnamed.len() == 1 => {
+                let ty = &fields.unnamed[0];
+                quote!( ( <#ty as ::clap::FromArgMatches>::from_arg_matches(matches) ) )
+            }
+            Unnamed(..) => abort_call_site!("{}: tuple enums are not supported", variant.ident),
+        };
+
+        quote! {
+            (#sub_name, Some(matches)) => {
+                Some(#name :: #variant_name #constructor_block)
+            }
+        }
+    });
+    let child_subcommands = flatten_variants.iter().map(|(variant, _attrs)| {
+        let variant_name = &variant.ident;
+        match variant.fields {
+            Unnamed(ref fields) if fields.unnamed.len() == 1 => {
+                let ty = &fields.unnamed[0];
+                quote! {
+                    if let Some(res) = <#ty as ::clap::Subcommand>::from_subcommand(other.0, other.1) {
+                        return Some(#name :: #variant_name (res));
+                    }
+                }
+            }
+            _ => abort!(
+                variant.span(),
+                "`flatten` is usable only with single-typed tuple variants"
+            ),
+        }
+    });
+
+    quote! {
+        fn from_subcommand<'b>(
+            name: &'b str,
+            sub: Option<&'b ::clap::ArgMatches>) -> Option<Self>
+        {
+            match (name, sub) {
+                #( #match_arms ),*,
+                other => {
+                    #( #child_subcommands )*;
+                    None
+                }
+            }
+        }
+    }
+}
diff --git a/clap_derive/src/lib.rs b/clap_derive/src/lib.rs
index 78cb3c65..a906bba3 100644
--- a/clap_derive/src/lib.rs
+++ b/clap_derive/src/lib.rs
@@ -15,12 +15,11 @@
 //! This crate is custom derive for clap. It should not be used
 //! directly. See [clap documentation](https://docs.rs/clap)
 //! for the usage of `#[derive(Clap)]`.
-#![recursion_limit = "256"]
 
 extern crate proc_macro;
 
-use proc_macro_error::proc_macro_error;
-use syn;
+use proc_macro_error::{proc_macro_error, set_dummy};
+use quote::quote;
 
 mod derives;
 
@@ -35,7 +34,8 @@ mod derives;
 #[proc_macro_derive(Clap, attributes(clap))]
 #[proc_macro_error]
 pub fn clap(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
-    let input: syn::DeriveInput = syn::parse(input).unwrap();
+    let input: syn::DeriveInput = syn::parse_macro_input!(input);
+    set_dummy_clap_impl(&input.ident);
     derives::derive_clap(&input).into()
 }
 
@@ -43,14 +43,45 @@ pub fn clap(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
 #[proc_macro_derive(IntoApp, attributes(clap))]
 #[proc_macro_error]
 pub fn into_app(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
-    let input: syn::DeriveInput = syn::parse(input).unwrap();
+    let input: syn::DeriveInput = syn::parse_macro_input!(input);
+    set_dummy_clap_impl(&input.ident);
     derives::derive_into_app(&input).into()
 }
 
 /// Generates the `FromArgMatches` impl.
-#[proc_macro_derive(FromArgMatches)]
+#[proc_macro_derive(FromArgMatches, attributes(clap))]
 #[proc_macro_error]
-pub fn from_argmatches(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
-    let input: syn::DeriveInput = syn::parse(input).unwrap();
+pub fn from_arg_matches(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+    let input: syn::DeriveInput = syn::parse_macro_input!(input);
+    set_dummy_clap_impl(&input.ident);
     derives::derive_from_argmatches(&input).into()
 }
+
+/// Generates the `Subcommand` impl.
+#[proc_macro_derive(Subcommand, attributes(clap))]
+#[proc_macro_error]
+pub fn subcommand(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+    let input: syn::DeriveInput = syn::parse_macro_input!(input);
+    derives::derive_subcommand(&input).into()
+}
+
+fn set_dummy_clap_impl(struct_name: &syn::Ident) {
+    set_dummy(quote! {
+        impl ::clap::Clap for #struct_name {}
+
+        impl ::clap::IntoApp for #struct_name {
+            fn into_app<'b>() -> ::clap::App<'b> {
+                unimplemented!()
+            }
+            fn augment_clap<'b>(app: ::clap::App<'b>) -> ::clap::App<'b> {
+                unimplemented!()
+            }
+        }
+
+        impl ::clap::FromArgMatches for #struct_name {
+            fn from_arg_matches(m: &::clap::ArgMatches) -> Self {
+                unimplemented!()
+            }
+        }
+    });
+}
diff --git a/clap_generate/Cargo.toml b/clap_generate/Cargo.toml
index f6cc343b..e7caa6c1 100644
--- a/clap_generate/Cargo.toml
+++ b/clap_generate/Cargo.toml
@@ -4,7 +4,7 @@ version = "3.0.0-beta.1"
 edition = "2018"
 authors = [
 	"Kevin K. <kbknapp@gmail.com>",
-	"Clap Maintainers"
+	"Pavan Kumar Sunkara <pavan.sss1991@gmail.com>",
 ]
 include = [
 	"src/**/*",
diff --git a/clap_generate/src/generators/mod.rs b/clap_generate/src/generators/mod.rs
index 483b920e..3dd8fe18 100644
--- a/clap_generate/src/generators/mod.rs
+++ b/clap_generate/src/generators/mod.rs
@@ -4,7 +4,7 @@ mod shells;
 use std::io::Write;
 
 // Internal
-use clap::{find_subcmd, flags, match_alias, subcommands, App, AppSettings, Arg};
+use clap::*;
 pub use shells::*;
 
 /// Generator trait which can be used to write generators
@@ -265,7 +265,7 @@ mod tests {
     #[test]
     fn test_find_subcommand_with_path() {
         let app = common();
-        let sc_app = Foo::find_subcommand_with_path(&app, "test config".split(' ').collect());
+        let sc_app = Foo::find_subcommand_with_path(&app, "test config".split(" ").collect());
 
         assert_eq!(sc_app.name, "config");
     }
diff --git a/clap_generate/src/lib.rs b/clap_generate/src/lib.rs
index dfa625bf..bd6b4925 100644
--- a/clap_generate/src/lib.rs
+++ b/clap_generate/src/lib.rs
@@ -107,11 +107,9 @@ pub use generators::Generator;
 ///     };
 ///
 ///     let mut app = build_cli();
-///     generate_to::<Bash, _, _>(
-///         &mut app,     // We need to specify what generator to use
-///         "myapp",      // We need to specify the bin name manually
-///         outdir,       // We need to specify where to write to
-///     );
+///     generate_to::<Bash, _>(&mut app,     // We need to specify what generator to use
+///                            "myapp",      // We need to specify the bin name manually
+///                            outdir);      // We need to specify where to write to
 /// }
 /// ```
 ///
diff --git a/src/build/app/mod.rs b/src/build/app/mod.rs
index dc835e5d..10a488ed 100644
--- a/src/build/app/mod.rs
+++ b/src/build/app/mod.rs
@@ -1461,31 +1461,6 @@ impl<'b> App<'b> {
         debug_assert!(self._app_debug_asserts());
         self.args._build();
         self.settings.set(AppSettings::Built);
-        Self::_panic_on_missing_help(&self, self.g_settings.is_set(AppSettings::HelpRequired));
-    }
-
-    #[cfg(not(debug_assertions))]
-    fn _panic_on_missing_help(app: &App, help_required_globally: bool) {}
-
-    #[cfg(debug_assertions)]
-    fn _panic_on_missing_help(app: &App, help_required_globally: bool) {
-        if app.is_set(AppSettings::HelpRequired) || help_required_globally {
-            let args_missing_help: Vec<String> = app
-                .args
-                .args
-                .iter()
-                .filter(|arg| arg.help.is_none() && arg.long_help.is_none())
-                .map(|arg| String::from(arg.name))
-                .collect();
-
-            if !args_missing_help.is_empty() {
-                let abort_message = format!("AppSettings::HelpRequired is enabled for the App {}, but at least one of its arguments does not have either `help` or `long_help` set. List of such arguments: {}", app.name, args_missing_help.join(", "));
-                panic!(abort_message);
-            }
-        }
-        for sub_app in &app.subcommands {
-            Self::_panic_on_missing_help(&sub_app, help_required_globally);
-        }
     }
 
     // Perform some expensive assertions on the Parser itself
diff --git a/src/build/app/settings.rs b/src/build/app/settings.rs
index 24336a35..3e3bfa3e 100644
--- a/src/build/app/settings.rs
+++ b/src/build/app/settings.rs
@@ -46,7 +46,6 @@ bitflags! {
         const INFER_SUBCOMMANDS    = 1 << 37;
         const CONTAINS_LAST        = 1 << 38;
         const ARGS_OVERRIDE_SELF   = 1 << 39;
-        const HELP_REQUIRED        = 1 << 40;
     }
 }
 
@@ -113,8 +112,6 @@ impl_settings! { AppSettings, AppFlags,
         => Flags::GLOBAL_VERSION,
     HidePossibleValuesInHelp("hidepossiblevaluesinhelp")
         => Flags::NO_POS_VALUES,
-    HelpRequired("helprequired")
-        => Flags::HELP_REQUIRED,
     Hidden("hidden")
         => Flags::HIDDEN,
     LowIndexMultiplePositional("lowindexmultiplepositional")
@@ -658,37 +655,6 @@ pub enum AppSettings {
     /// This can be useful if there are many values, or they are explained elsewhere.
     HidePossibleValuesInHelp,
 
-    /// Tells `clap` to panic if help strings are omitted
-    ///  
-    /// # Examples
-    ///
-    /// ```rust
-    /// # use clap::{App, Arg, AppSettings};
-    /// App::new("myprog")
-    ///     .setting(AppSettings::HelpRequired)
-    ///     .arg(
-    ///         Arg::with_name("foo").help("It does foo stuff")
-    ///         // As required via AppSettings::HelpRequired, a help message was supplied
-    ///      )
-    /// #    .get_matches();
-    /// ```
-    ///
-    /// # Panics
-    ///
-    /// ```rust,should_panic
-    /// # use clap::{App, Arg, AppSettings};
-    /// App::new("myapp")
-    ///     .setting(AppSettings::HelpRequired)
-    ///     .arg(
-    ///         Arg::with_name("foo")
-    ///         // Someone forgot to put .help("...") here
-    ///         // Since the setting AppSettings::HelpRequired is activated, this will lead to
-    ///         // a panic (if you are in debug mode)
-    ///     )
-    /// #   .get_matches();
-    ///```
-    HelpRequired,
-
     /// Tries to match unknown args to partial [`subcommands`] or their [aliases]. For example to
     /// match a subcommand named `test`, one could use `t`, `te`, `tes`, and `test`.
     ///
@@ -1062,10 +1028,6 @@ mod test {
             "hidepossiblevaluesinhelp".parse::<AppSettings>().unwrap(),
             AppSettings::HidePossibleValuesInHelp
         );
-        assert_eq!(
-            "helprequired".parse::<AppSettings>().unwrap(),
-            AppSettings::HelpRequired
-        );
         assert_eq!(
             "lowindexmultiplePositional".parse::<AppSettings>().unwrap(),
             AppSettings::LowIndexMultiplePositional
diff --git a/src/derive.rs b/src/derive.rs
new file mode 100644
index 00000000..28a7afc1
--- /dev/null
+++ b/src/derive.rs
@@ -0,0 +1,68 @@
+//! This module contains traits that are usable with `#[derive(...)].`
+
+use crate::{App, ArgMatches, Error};
+use std::ffi::OsString;
+
+/// This trait is just a convenience on top of FromArgMatches + IntoApp
+pub trait Clap: FromArgMatches + IntoApp + Sized {
+    /// Parse from `std::env::args()`, exit on error
+    fn parse() -> Self {
+        let matches = <Self as IntoApp>::into_app().get_matches();
+        <Self as FromArgMatches>::from_arg_matches(&matches)
+    }
+
+    /// Parse from `std::env::args()`, return Err on error.
+    fn try_parse() -> Result<Self, Error> {
+        let matches = <Self as IntoApp>::into_app().try_get_matches()?;
+        Ok(<Self as FromArgMatches>::from_arg_matches(&matches))
+    }
+
+    /// Parse from iterator, exit on error
+    fn parse_from<I, T>(itr: I) -> Self
+    where
+        I: IntoIterator<Item = T>,
+        // TODO (@CreepySkeleton): discover a way to avoid cloning here
+        T: Into<OsString> + Clone,
+    {
+        let matches = <Self as IntoApp>::into_app().get_matches_from(itr);
+        <Self as FromArgMatches>::from_arg_matches(&matches)
+    }
+
+    /// Parse from `std::env::args()`, return Err on error.
+    fn try_parse_from<I, T>(itr: I) -> Result<Self, Error>
+    where
+        I: IntoIterator<Item = T>,
+        // TODO (@CreepySkeleton): discover a way to avoid cloning here
+        T: Into<OsString> + Clone,
+    {
+        let matches = <Self as IntoApp>::into_app().try_get_matches_from(itr)?;
+        Ok(<Self as FromArgMatches>::from_arg_matches(&matches))
+    }
+}
+
+/// Build an App according to the struct
+///
+/// Also serves for flattening
+pub trait IntoApp: Sized {
+    /// @TODO @release @docs
+    fn into_app<'b>() -> App<'b>;
+    /// @TODO @release @docs
+    fn augment_clap(app: App<'_>) -> App<'_>;
+}
+
+/// Extract values from ArgMatches into the struct.
+pub trait FromArgMatches: Sized {
+    /// @TODO @release @docs
+    fn from_arg_matches(matches: &ArgMatches) -> Self;
+}
+
+/// @TODO @release @docs
+pub trait Subcommand: Sized {
+    /// @TODO @release @docs
+    fn from_subcommand(name: &str, matches: Option<&ArgMatches>) -> Option<Self>;
+    /// @TODO @release @docs
+    fn augment_subcommands(app: App<'_>) -> App<'_>;
+}
+
+/// @TODO @release @docs
+pub trait ArgEnum {}
diff --git a/src/lib.rs b/src/lib.rs
index 83cd3747..83a74612 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -448,6 +448,7 @@
 compile_error!("`std` feature is currently required to build this crate");
 
 pub use crate::build::{App, AppSettings, Arg, ArgGroup, ArgSettings, Propagation};
+pub use crate::derive::{Clap, FromArgMatches, IntoApp, Subcommand};
 pub use crate::output::fmt::Format;
 pub use crate::parse::errors::{Error, ErrorKind, Result};
 pub use crate::parse::{ArgMatches, OsValues, SubCommand, Values};
@@ -462,46 +463,21 @@ pub use clap_derive::{self, *};
 #[cfg_attr(feature = "derive", doc(hidden))]
 pub use lazy_static;
 
-use std::result::Result as StdResult;
+#[doc(hidden)]
+pub use mkeymap::KeyType;
 
 #[macro_use]
 #[allow(missing_docs)]
 pub mod macros;
 
+pub mod derive;
+
 mod build;
 mod mkeymap;
 mod output;
 mod parse;
 mod util;
 
-#[doc(hidden)]
-pub use mkeymap::KeyType;
-
 const INTERNAL_ERROR_MSG: &str = "Fatal internal error. Please consider filing a bug \
                                   report at https://github.com/clap-rs/clap/issues";
 const INVALID_UTF8: &str = "unexpected invalid UTF-8 code point";
-
-/// @TODO @release @docs
-pub trait Clap: From<ArgMatches> + IntoApp + Sized {}
-
-/// @TODO @release @docs
-pub trait FromArgMatches: Sized {
-    /// @TODO @release @docs
-    fn from_argmatches(matches: &crate::parse::ArgMatches) -> Self;
-
-    /// @TODO @release @docs
-    fn try_from_argmatches(
-        matches: &crate::parse::ArgMatches,
-    ) -> StdResult<Self, crate::parse::errors::Error> {
-        Ok(<Self as FromArgMatches>::from_argmatches(matches))
-    }
-}
-
-/// @TODO @release @docs
-pub trait IntoApp: Sized {
-    /// @TODO @release @docs
-    fn into_app<'b>() -> crate::build::App<'b>;
-}
-
-/// @TODO @release @docs
-pub trait ArgEnum {}
diff --git a/src/util/osstringext.rs b/src/util/osstringext.rs
index d4ceb6ce..0af52ffd 100644
--- a/src/util/osstringext.rs
+++ b/src/util/osstringext.rs
@@ -22,6 +22,7 @@ pub trait OsStrExt2 {
 
 #[cfg(target_os = "windows")]
 impl OsStrExt3 for OsStr {
+    #[allow(clippy::transmute_ptr_to_ptr)]
     fn from_bytes(b: &[u8]) -> &Self {
         use std::mem;
         unsafe { mem::transmute(b) }


Test patch:
diff --git a/clap_derive/tests/author_version_about.rs b/clap_derive/tests/author_version_about.rs
index e9850f7c..051315d4 100644
--- a/clap_derive/tests/author_version_about.rs
+++ b/clap_derive/tests/author_version_about.rs
@@ -35,7 +35,7 @@ fn use_env() {
 
     let output = get_long_help::<Opt>();
     assert!(output.starts_with("clap_derive"));
-    assert!(output.contains("Guillaume Pinot <texitoi@texitoi.eu>, Clap Maintainers"));
+    assert!(output.contains("Guillaume Pinot <texitoi@texitoi.eu>, Kevin K. <kbknapp@gmail.com>"));
     assert!(output.contains("Parse command line argument by defining a struct, derive crate"));
 }
 
diff --git a/clap_derive/tests/deny-warnings.rs b/clap_derive/tests/deny-warnings.rs
index 75e88765..a6987c7e 100644
--- a/clap_derive/tests/deny-warnings.rs
+++ b/clap_derive/tests/deny-warnings.rs
@@ -22,7 +22,7 @@ fn try_str(s: &str) -> Result<String, std::convert::Infallible> {
 
 #[test]
 fn warning_never_struct() {
-    #[derive(Debug, PartialEq, Clap)]
+    #[derive(Clap, Debug, PartialEq)]
     struct Opt {
         #[clap(parse(try_from_str = try_str))]
         s: String,
@@ -37,7 +37,7 @@ fn warning_never_struct() {
 
 #[test]
 fn warning_never_enum() {
-    #[derive(Debug, PartialEq, Clap)]
+    #[derive(Clap, Debug, PartialEq)]
     enum Opt {
         Foo {
             #[clap(parse(try_from_str = try_str))]
diff --git a/clap_derive/tests/issues.rs b/clap_derive/tests/issues.rs
index 95e71a5f..dfe9b0e2 100644
--- a/clap_derive/tests/issues.rs
+++ b/clap_derive/tests/issues.rs
@@ -3,7 +3,7 @@
 mod utils;
 use utils::*;
 
-use clap::{ArgGroup, Clap};
+use clap::{AppSettings, ArgGroup, Clap};
 
 #[test]
 fn issue_151() {
@@ -31,8 +31,6 @@ fn issue_151() {
 
 #[test]
 fn issue_289() {
-    use clap::{AppSettings, Clap};
-
     #[derive(Clap)]
     #[clap(setting = AppSettings::InferSubcommands)]
     enum Args {
@@ -40,6 +38,8 @@ fn issue_289() {
         AnotherCommand,
     }
 
+    // FIXME (@CreepySkeleton): current implementation requires us to
+    // derive IntoApp here while we don't really need it
     #[derive(Clap)]
     #[clap(setting = AppSettings::InferSubcommands)]
     enum SubSubCommand {
diff --git a/clap_derive/tests/privacy.rs b/clap_derive/tests/privacy.rs
index d6692960..6a36b953 100644
--- a/clap_derive/tests/privacy.rs
+++ b/clap_derive/tests/privacy.rs
@@ -23,9 +23,9 @@ mod options {
 }
 
 mod subcommands {
-    use clap::Clap;
+    use clap::Subcommand;
 
-    #[derive(Debug, Clap)]
+    #[derive(Debug, Subcommand)]
     pub enum SubCommand {
         /// foo
         Foo {
diff --git a/clap_derive/tests/subcommands.rs b/clap_derive/tests/subcommands.rs
index fa4256a9..f012b3a5 100644
--- a/clap_derive/tests/subcommands.rs
+++ b/clap_derive/tests/subcommands.rs
@@ -161,47 +161,52 @@ fn test_tuple_commands() {
     assert!(!output.contains("Not shown"));
 }
 
-#[test]
-fn enum_in_enum_subsubcommand() {
-    #[derive(Clap, Debug, PartialEq)]
-    pub enum Opt {
-        Daemon(DaemonCommand),
-    }
-
-    #[derive(Clap, Debug, PartialEq)]
-    pub enum DaemonCommand {
-        Start,
-        Stop,
-    }
-
-    let result = Opt::try_parse_from(&["test"]);
-    assert!(result.is_err());
-
-    let result = Opt::try_parse_from(&["test", "daemon"]);
-    assert!(result.is_err());
-
-    let result = Opt::parse_from(&["test", "daemon", "start"]);
-    assert_eq!(Opt::Daemon(DaemonCommand::Start), result);
-}
-
-#[test]
-fn flatten_enum() {
-    #[derive(Clap, Debug, PartialEq)]
-    struct Opt {
-        #[clap(flatten)]
-        sub_cmd: SubCmd,
-    }
-    #[derive(Clap, Debug, PartialEq)]
-    enum SubCmd {
-        Foo,
-        Bar,
-    }
-
-    assert!(Opt::try_parse_from(&["test"]).is_err());
-    assert_eq!(
-        Opt::parse_from(&["test", "foo"]),
-        Opt {
-            sub_cmd: SubCmd::Foo
-        }
-    );
-}
+// #[test]
+// #[ignore] // FIXME (@CreepySkeleton)
+// fn enum_in_enum_subsubcommand() {
+//     #[derive(Clap, Debug, PartialEq)]
+//     pub enum Opt {
+//         Daemon(DaemonCommand),
+//     }
+
+//     #[derive(Clap, Debug, PartialEq)]
+//     pub enum DaemonCommand {
+//         Start,
+//         Stop,
+//     }
+
+//     let result = Opt::try_parse_from(&["test"]);
+//     assert!(result.is_err());
+
+//     let result = Opt::try_parse_from(&["test", "daemon"]);
+//     assert!(result.is_err());
+
+//     let result = Opt::parse_from(&["test", "daemon", "start"]);
+//     assert_eq!(Opt::Daemon(DaemonCommand::Start), result);
+// }
+
+// WTF??? It tests that `flatten` is essentially a synonym
+// for `subcommand`. It's not documented and I doubt it was supposed to
+// work this way.
+// #[test]
+// #[ignore]
+// fn flatten_enum() {
+//     #[derive(Clap, Debug, PartialEq)]
+//     struct Opt {
+//         #[clap(flatten)]
+//         sub_cmd: SubCmd,
+//     }
+//     #[derive(Clap, Debug, PartialEq)]
+//     enum SubCmd {
+//         Foo,
+//         Bar,
+//     }
+
+//     assert!(Opt::try_parse_from(&["test"]).is_err());
+//     assert_eq!(
+//         Opt::parse_from(&["test", "foo"]),
+//         Opt {
+//             sub_cmd: SubCmd::Foo
+//         }
+//     );
+// }
diff --git a/clap_derive/tests/ui/bool_default_value.stderr b/clap_derive/tests/ui/bool_default_value.stderr
index 33521d76..d989d13b 100644
--- a/clap_derive/tests/ui/bool_default_value.stderr
+++ b/clap_derive/tests/ui/bool_default_value.stderr
@@ -3,9 +3,3 @@ error: default_value is meaningless for bool
    |
 14 |     #[clap(short, default_value = true)]
    |                   ^^^^^^^^^^^^^
-
-error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
-  --> $DIR/bool_default_value.rs:11:10
-   |
-11 | #[derive(Clap, Debug)]
-   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/bool_required.stderr b/clap_derive/tests/ui/bool_required.stderr
index b95bcb30..adbbb3c2 100644
--- a/clap_derive/tests/ui/bool_required.stderr
+++ b/clap_derive/tests/ui/bool_required.stderr
@@ -3,9 +3,3 @@ error: required is meaningless for bool
    |
 14 |     #[clap(short, required = true)]
    |                   ^^^^^^^^
-
-error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
-  --> $DIR/bool_required.rs:11:10
-   |
-11 | #[derive(Clap, Debug)]
-   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/clap_empty_attr.rs b/clap_derive/tests/ui/clap_empty_attr.rs
index 326f2696..8d4477f7 100644
--- a/clap_derive/tests/ui/clap_empty_attr.rs
+++ b/clap_derive/tests/ui/clap_empty_attr.rs
@@ -7,10 +7,10 @@ struct Opt {}
 #[derive(Clap, Debug)]
 struct Opt1 {
     #[clap = "short"]
-    foo: u32
+    foo: u32,
 }
 
 fn main() {
-    let opt = Opt::from_args();
+    let opt = Opt::parse();
     println!("{:?}", opt);
 }
diff --git a/clap_derive/tests/ui/clap_empty_attr.stderr b/clap_derive/tests/ui/clap_empty_attr.stderr
index 27a90859..62f8e0da 100644
--- a/clap_derive/tests/ui/clap_empty_attr.stderr
+++ b/clap_derive/tests/ui/clap_empty_attr.stderr
@@ -9,15 +9,3 @@ error: expected parentheses: #[clap(...)]
   |
 9 |     #[clap = "short"]
   |            ^
-
-error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
- --> $DIR/clap_empty_attr.rs:3:10
-  |
-3 | #[derive(Clap, Debug)]
-  |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
-
-error[E0277]: the trait bound `Opt1: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
- --> $DIR/clap_empty_attr.rs:7:10
-  |
-7 | #[derive(Clap, Debug)]
-  |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt1`
diff --git a/clap_derive/tests/ui/enum_flatten.rs b/clap_derive/tests/ui/enum_flatten.rs
index 0c5f3742..bf91b9ac 100644
--- a/clap_derive/tests/ui/enum_flatten.rs
+++ b/clap_derive/tests/ui/enum_flatten.rs
@@ -16,6 +16,6 @@ enum Opt {
 }
 
 fn main() {
-    let opt = Opt::from_args();
+    let opt = Opt::parse();
     println!("{:?}", opt);
 }
diff --git a/clap_derive/tests/ui/enum_flatten.stderr b/clap_derive/tests/ui/enum_flatten.stderr
index 30e6cac8..30acd20a 100644
--- a/clap_derive/tests/ui/enum_flatten.stderr
+++ b/clap_derive/tests/ui/enum_flatten.stderr
@@ -3,9 +3,3 @@ error: `flatten` is usable only with single-typed tuple variants
    |
 14 |     #[clap(flatten)]
    |     ^
-
-error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
-  --> $DIR/enum_flatten.rs:11:10
-   |
-11 | #[derive(Clap, Debug)]
-   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/flatten_and_doc.stderr b/clap_derive/tests/ui/flatten_and_doc.stderr
index f9b3d8e5..fec9a79b 100644
--- a/clap_derive/tests/ui/flatten_and_doc.stderr
+++ b/clap_derive/tests/ui/flatten_and_doc.stderr
@@ -3,9 +3,3 @@ error: methods and doc comments are not allowed for flattened entry
    |
 23 |     #[clap(flatten)]
    |            ^^^^^^^
-
-error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
-  --> $DIR/flatten_and_doc.rs:19:10
-   |
-19 | #[derive(Clap, Debug)]
-   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/flatten_and_methods.stderr b/clap_derive/tests/ui/flatten_and_methods.stderr
index 20c84815..0b86ceed 100644
--- a/clap_derive/tests/ui/flatten_and_methods.stderr
+++ b/clap_derive/tests/ui/flatten_and_methods.stderr
@@ -3,9 +3,3 @@ error: methods and doc comments are not allowed for flattened entry
    |
 22 |     #[clap(short, flatten)]
    |                   ^^^^^^^
-
-error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
-  --> $DIR/flatten_and_methods.rs:19:10
-   |
-19 | #[derive(Clap, Debug)]
-   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/flatten_and_parse.stderr b/clap_derive/tests/ui/flatten_and_parse.stderr
index 76b7ec7c..93aa6751 100644
--- a/clap_derive/tests/ui/flatten_and_parse.stderr
+++ b/clap_derive/tests/ui/flatten_and_parse.stderr
@@ -3,9 +3,3 @@ error: parse attribute is not allowed for flattened entry
    |
 22 |     #[clap(flatten, parse(from_occurrences))]
    |                     ^^^^^
-
-error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
-  --> $DIR/flatten_and_parse.rs:19:10
-   |
-19 | #[derive(Clap, Debug)]
-   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/opt_opt_nonpositional.stderr b/clap_derive/tests/ui/opt_opt_nonpositional.stderr
index a0800498..586bf7a5 100644
--- a/clap_derive/tests/ui/opt_opt_nonpositional.stderr
+++ b/clap_derive/tests/ui/opt_opt_nonpositional.stderr
@@ -3,9 +3,3 @@ error: Option<Option<T>> type is meaningless for positional argument
    |
 14 |     n: Option<Option<u32>>,
    |        ^^^^^^
-
-error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
-  --> $DIR/opt_opt_nonpositional.rs:11:10
-   |
-11 | #[derive(Clap, Debug)]
-   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/opt_vec_nonpositional.stderr b/clap_derive/tests/ui/opt_vec_nonpositional.stderr
index 055196b7..6f01de56 100644
--- a/clap_derive/tests/ui/opt_vec_nonpositional.stderr
+++ b/clap_derive/tests/ui/opt_vec_nonpositional.stderr
@@ -3,9 +3,3 @@ error: Option<Vec<T>> type is meaningless for positional argument
    |
 14 |     n: Option<Vec<u32>>,
    |        ^^^^^^
-
-error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
-  --> $DIR/opt_vec_nonpositional.rs:11:10
-   |
-11 | #[derive(Clap, Debug)]
-   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/option_default_value.stderr b/clap_derive/tests/ui/option_default_value.stderr
index e06fa477..28550bef 100644
--- a/clap_derive/tests/ui/option_default_value.stderr
+++ b/clap_derive/tests/ui/option_default_value.stderr
@@ -3,9 +3,3 @@ error: default_value is meaningless for Option
    |
 14 |     #[clap(short, default_value = 1)]
    |                   ^^^^^^^^^^^^^
-
-error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
-  --> $DIR/option_default_value.rs:11:10
-   |
-11 | #[derive(Clap, Debug)]
-   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/option_required.stderr b/clap_derive/tests/ui/option_required.stderr
index 66e470c3..4bbdc61d 100644
--- a/clap_derive/tests/ui/option_required.stderr
+++ b/clap_derive/tests/ui/option_required.stderr
@@ -3,9 +3,3 @@ error: required is meaningless for Option
    |
 14 |     #[clap(short, required = true)]
    |                   ^^^^^^^^
-
-error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
-  --> $DIR/option_required.rs:11:10
-   |
-11 | #[derive(Clap, Debug)]
-   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/parse_empty_try_from_os.stderr b/clap_derive/tests/ui/parse_empty_try_from_os.stderr
index b102ea63..91095809 100644
--- a/clap_derive/tests/ui/parse_empty_try_from_os.stderr
+++ b/clap_derive/tests/ui/parse_empty_try_from_os.stderr
@@ -3,9 +3,3 @@ error: you must set parser for `try_from_os_str` explicitly
    |
 14 |     #[clap(parse(try_from_os_str))]
    |                  ^^^^^^^^^^^^^^^
-
-error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
-  --> $DIR/parse_empty_try_from_os.rs:11:10
-   |
-11 | #[derive(Clap, Debug)]
-   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/parse_function_is_not_path.stderr b/clap_derive/tests/ui/parse_function_is_not_path.stderr
index ae59a092..230bdb33 100644
--- a/clap_derive/tests/ui/parse_function_is_not_path.stderr
+++ b/clap_derive/tests/ui/parse_function_is_not_path.stderr
@@ -3,9 +3,3 @@ error: `parse` argument must be a function path
    |
 14 |     #[clap(parse(from_str = "2"))]
    |                             ^^^
-
-error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
-  --> $DIR/parse_function_is_not_path.rs:11:10
-   |
-11 | #[derive(Clap, Debug)]
-   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/parse_literal_spec.stderr b/clap_derive/tests/ui/parse_literal_spec.stderr
index fb2e7203..a5bf187b 100644
--- a/clap_derive/tests/ui/parse_literal_spec.stderr
+++ b/clap_derive/tests/ui/parse_literal_spec.stderr
@@ -3,9 +3,3 @@ error: parser specification must start with identifier
    |
 14 |     #[clap(parse("from_str"))]
    |                  ^^^^^^^^^^
-
-error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
-  --> $DIR/parse_literal_spec.rs:11:10
-   |
-11 | #[derive(Clap, Debug)]
-   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/parse_not_zero_args.stderr b/clap_derive/tests/ui/parse_not_zero_args.stderr
index a8bf2caf..534188db 100644
--- a/clap_derive/tests/ui/parse_not_zero_args.stderr
+++ b/clap_derive/tests/ui/parse_not_zero_args.stderr
@@ -3,9 +3,3 @@ error: parse must have exactly one argument
    |
 14 |     #[clap(parse(from_str, from_str))]
    |            ^^^^^
-
-error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
-  --> $DIR/parse_not_zero_args.rs:11:10
-   |
-11 | #[derive(Clap, Debug)]
-   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/positional_bool.stderr b/clap_derive/tests/ui/positional_bool.stderr
index 7341ec89..ef3ef9f2 100644
--- a/clap_derive/tests/ui/positional_bool.stderr
+++ b/clap_derive/tests/ui/positional_bool.stderr
@@ -8,9 +8,3 @@ error: `bool` cannot be used as positional parameter with default parser
   |
 5 |     verbose: bool,
   |              ^^^^
-
-error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
- --> $DIR/positional_bool.rs:3:10
-  |
-3 | #[derive(Clap, Debug)]
-  |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/raw.stderr b/clap_derive/tests/ui/raw.stderr
index c21c0083..122bef22 100644
--- a/clap_derive/tests/ui/raw.stderr
+++ b/clap_derive/tests/ui/raw.stderr
@@ -17,15 +17,3 @@ error: `#[clap(raw(...))` attributes are removed, they are replaced with raw met
    |
 19 |     #[clap(raw(requires_if = r#""one", "two""#))]
    |            ^^^
-
-error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
-  --> $DIR/raw.rs:11:10
-   |
-11 | #[derive(Clap, Debug)]
-   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
-
-error[E0277]: the trait bound `Opt2: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
-  --> $DIR/raw.rs:17:10
-   |
-17 | #[derive(Clap, Debug)]
-   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt2`
diff --git a/clap_derive/tests/ui/rename_all_wrong_casing.stderr b/clap_derive/tests/ui/rename_all_wrong_casing.stderr
index 84d4eae9..06af3213 100644
--- a/clap_derive/tests/ui/rename_all_wrong_casing.stderr
+++ b/clap_derive/tests/ui/rename_all_wrong_casing.stderr
@@ -3,9 +3,3 @@ error: unsupported casing: `fail`
    |
 12 | #[clap(name = "basic", rename_all = "fail")]
    |                                     ^^^^^^
-
-error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
-  --> $DIR/rename_all_wrong_casing.rs:11:10
-   |
-11 | #[derive(Clap, Debug)]
-   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/skip_flatten.stderr b/clap_derive/tests/ui/skip_flatten.stderr
index ac131454..e5230c0d 100644
--- a/clap_derive/tests/ui/skip_flatten.stderr
+++ b/clap_derive/tests/ui/skip_flatten.stderr
@@ -3,9 +3,3 @@ error: subcommand, flatten and skip cannot be used together
    |
 17 |     #[clap(skip, flatten)]
    |                  ^^^^^^^
-
-error[E0277]: the trait bound `MakeCookie: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
-  --> $DIR/skip_flatten.rs:11:10
-   |
-11 | #[derive(Clap, Debug)]
-   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `MakeCookie`
diff --git a/clap_derive/tests/ui/skip_subcommand.stderr b/clap_derive/tests/ui/skip_subcommand.stderr
index 164605c1..fff8796a 100644
--- a/clap_derive/tests/ui/skip_subcommand.stderr
+++ b/clap_derive/tests/ui/skip_subcommand.stderr
@@ -3,9 +3,3 @@ error: subcommand, flatten and skip cannot be used together
    |
 17 |     #[clap(subcommand, skip)]
    |                        ^^^^
-
-error[E0277]: the trait bound `MakeCookie: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
-  --> $DIR/skip_subcommand.rs:11:10
-   |
-11 | #[derive(Clap, Debug)]
-   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `MakeCookie`
diff --git a/clap_derive/tests/ui/skip_with_other_options.stderr b/clap_derive/tests/ui/skip_with_other_options.stderr
index 7aa4667d..bbf87067 100644
--- a/clap_derive/tests/ui/skip_with_other_options.stderr
+++ b/clap_derive/tests/ui/skip_with_other_options.stderr
@@ -3,9 +3,3 @@ error: methods are not allowed for skipped fields
   |
 8 |     #[clap(skip, long)]
   |            ^^^^
-
-error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
- --> $DIR/skip_with_other_options.rs:3:10
-  |
-3 | #[derive(Clap, Debug)]
-  |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/struct_parse.stderr b/clap_derive/tests/ui/struct_parse.stderr
index 9dc07f59..c21df6be 100644
--- a/clap_derive/tests/ui/struct_parse.stderr
+++ b/clap_derive/tests/ui/struct_parse.stderr
@@ -3,9 +3,3 @@ error: `parse` attribute is only allowed on fields
    |
 12 | #[clap(name = "basic", parse(from_str))]
    |                        ^^^^^
-
-error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
-  --> $DIR/struct_parse.rs:11:10
-   |
-11 | #[derive(Clap, Debug)]
-   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/struct_subcommand.stderr b/clap_derive/tests/ui/struct_subcommand.stderr
index b1dd3eed..e8b806bb 100644
--- a/clap_derive/tests/ui/struct_subcommand.stderr
+++ b/clap_derive/tests/ui/struct_subcommand.stderr
@@ -3,9 +3,3 @@ error: subcommand is only allowed on fields
    |
 12 | #[clap(name = "basic", subcommand)]
    |                        ^^^^^^^^^^
-
-error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
-  --> $DIR/struct_subcommand.rs:11:10
-   |
-11 | #[derive(Clap, Debug)]
-   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/subcommand_and_flatten.stderr b/clap_derive/tests/ui/subcommand_and_flatten.stderr
index 91c005fe..b509b737 100644
--- a/clap_derive/tests/ui/subcommand_and_flatten.stderr
+++ b/clap_derive/tests/ui/subcommand_and_flatten.stderr
@@ -3,9 +3,3 @@ error: subcommand, flatten and skip cannot be used together
    |
 16 |     #[clap(subcommand, flatten)]
    |                        ^^^^^^^
-
-error[E0277]: the trait bound `MakeCookie: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
-  --> $DIR/subcommand_and_flatten.rs:11:10
-   |
-11 | #[derive(Clap, Debug)]
-   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `MakeCookie`
diff --git a/clap_derive/tests/ui/subcommand_and_methods.stderr b/clap_derive/tests/ui/subcommand_and_methods.stderr
index e565a28e..04585d8a 100644
--- a/clap_derive/tests/ui/subcommand_and_methods.stderr
+++ b/clap_derive/tests/ui/subcommand_and_methods.stderr
@@ -3,9 +3,3 @@ error: methods in attributes are not allowed for subcommand
    |
 16 |     #[clap(subcommand, long)]
    |            ^^^^^^^^^^
-
-error[E0277]: the trait bound `MakeCookie: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
-  --> $DIR/subcommand_and_methods.rs:11:10
-   |
-11 | #[derive(Clap, Debug)]
-   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `MakeCookie`
diff --git a/clap_derive/tests/ui/subcommand_and_parse.stderr b/clap_derive/tests/ui/subcommand_and_parse.stderr
index 1de015d2..86705ca0 100644
--- a/clap_derive/tests/ui/subcommand_and_parse.stderr
+++ b/clap_derive/tests/ui/subcommand_and_parse.stderr
@@ -3,9 +3,3 @@ error: parse attribute is not allowed for subcommand
    |
 16 |     #[clap(subcommand, parse(from_occurrences))]
    |                        ^^^^^
-
-error[E0277]: the trait bound `MakeCookie: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
-  --> $DIR/subcommand_and_parse.rs:11:10
-   |
-11 | #[derive(Clap, Debug)]
-   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `MakeCookie`
diff --git a/clap_derive/tests/ui/subcommand_opt_opt.stderr b/clap_derive/tests/ui/subcommand_opt_opt.stderr
index 9c7a7123..feb33a4e 100644
--- a/clap_derive/tests/ui/subcommand_opt_opt.stderr
+++ b/clap_derive/tests/ui/subcommand_opt_opt.stderr
@@ -3,9 +3,3 @@ error: Option<Option<T>> type is not allowed for subcommand
    |
 17 |     cmd: Option<Option<Command>>,
    |          ^^^^^^
-
-error[E0277]: the trait bound `MakeCookie: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
-  --> $DIR/subcommand_opt_opt.rs:11:10
-   |
-11 | #[derive(Clap, Debug)]
-   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `MakeCookie`
diff --git a/clap_derive/tests/ui/subcommand_opt_vec.stderr b/clap_derive/tests/ui/subcommand_opt_vec.stderr
index 8a77dbb9..9cb4af9e 100644
--- a/clap_derive/tests/ui/subcommand_opt_vec.stderr
+++ b/clap_derive/tests/ui/subcommand_opt_vec.stderr
@@ -3,9 +3,3 @@ error: Option<Vec<T>> type is not allowed for subcommand
    |
 17 |     cmd: Option<Vec<Command>>,
    |          ^^^^^^
-
-error[E0277]: the trait bound `MakeCookie: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
-  --> $DIR/subcommand_opt_vec.rs:11:10
-   |
-11 | #[derive(Clap, Debug)]
-   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `MakeCookie`
diff --git a/clap_derive/tests/ui/tuple_struct.stderr b/clap_derive/tests/ui/tuple_struct.stderr
index 51ab78ca..29ee8c89 100644
--- a/clap_derive/tests/ui/tuple_struct.stderr
+++ b/clap_derive/tests/ui/tuple_struct.stderr
@@ -1,11 +1,5 @@
-error: clap_derive only supports non-tuple structs and enums
+error: `#[derive(Clap)]` only supports non-tuple structs and enums
   --> $DIR/tuple_struct.rs:11:10
    |
 11 | #[derive(Clap, Debug)]
    |          ^^^^
-
-error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
-  --> $DIR/tuple_struct.rs:11:10
-   |
-11 | #[derive(Clap, Debug)]
-   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/utils.rs b/clap_derive/tests/utils.rs
index 8d39a273..1deb2809 100644
--- a/clap_derive/tests/utils.rs
+++ b/clap_derive/tests/utils.rs
@@ -1,3 +1,10 @@
+// Hi, future me (or whoever you are)!
+//
+// Yes, we do need this attr.
+// No, the warnings cannot be fixed otherwise.
+// Accept and endure. Do not touch.
+#![allow(unused)]
+
 use clap::IntoApp;
 
 pub fn get_help<T: IntoApp>() -> String {
diff --git a/tests/app_from_crate.rs b/tests/app_from_crate.rs
index 91ab0e67..2129a0dd 100644
--- a/tests/app_from_crate.rs
+++ b/tests/app_from_crate.rs
@@ -1,7 +1,7 @@
 use clap::{app_from_crate, ErrorKind};
 
 static EVERYTHING: &str = "clap {{version}}
-Kevin K. <kbknapp@gmail.com>:Clap Maintainers
+Kevin K. <kbknapp@gmail.com>
 A simple to use, efficient, and full-featured Command Line Argument Parser
 
 USAGE:
diff --git a/tests/cargo.rs b/tests/cargo.rs
index daf94d02..9fe2234e 100644
--- a/tests/cargo.rs
+++ b/tests/cargo.rs
@@ -12,7 +12,7 @@ FLAGS:
 ";
 
 static AUTHORS_ONLY: &str = "prog 1
-Kevin K. <kbknapp@gmail.com>:Clap Maintainers
+Kevin K. <kbknapp@gmail.com>
 
 USAGE:
     prog
diff --git a/tests/help.rs b/tests/help.rs
index 2ab68747..d7f9f92d 100644
--- a/tests/help.rs
+++ b/tests/help.rs
@@ -1568,86 +1568,3 @@ fn issue_1487() {
             .required(true));
     assert!(utils::compare_output(app, "ctest -h", ISSUE_1487, false));
 }
-
-#[test]
-#[should_panic]
-fn help_required_but_not_given() {
-    App::new("myapp")
-        .setting(AppSettings::HelpRequired)
-        .arg(Arg::with_name("foo"))
-        .get_matches();
-}
-
-#[test]
-#[should_panic]
-fn help_required_but_not_given_settings_after_args() {
-    App::new("myapp")
-        .arg(Arg::with_name("foo"))
-        .setting(AppSettings::HelpRequired)
-        .get_matches();
-}
-
-#[test]
-#[should_panic]
-fn help_required_but_not_given_for_one_of_two_arguments() {
-    App::new("myapp")
-        .setting(AppSettings::HelpRequired)
-        .arg(Arg::with_name("foo"))
-        .arg(Arg::with_name("bar").help("It does bar stuff"))
-        .get_matches();
-}
-
-#[test]
-fn help_required_locally_but_not_given_for_subcommand() {
-    App::new("myapp")
-        .setting(AppSettings::HelpRequired)
-        .arg(Arg::with_name("foo").help("It does foo stuff"))
-        .subcommand(
-            App::new("bar")
-                .arg(Arg::with_name("create").help("creates bar"))
-                .arg(Arg::with_name("delete")),
-        )
-        .get_matches();
-}
-
-#[test]
-#[should_panic]
-fn help_required_globally_but_not_given_for_subcommand() {
-    App::new("myapp")
-        .global_setting(AppSettings::HelpRequired)
-        .arg(Arg::with_name("foo").help("It does foo stuff"))
-        .subcommand(
-            App::new("bar")
-                .arg(Arg::with_name("create").help("creates bar"))
-                .arg(Arg::with_name("delete")),
-        )
-        .get_matches();
-}
-
-#[test]
-fn help_required_and_given_for_subcommand() {
-    App::new("myapp")
-        .setting(AppSettings::HelpRequired)
-        .arg(Arg::with_name("foo").help("It does foo stuff"))
-        .subcommand(
-            App::new("bar")
-                .arg(Arg::with_name("create").help("creates bar"))
-                .arg(Arg::with_name("delete").help("deletes bar")),
-        )
-        .get_matches();
-}
-
-#[test]
-fn help_required_and_given() {
-    App::new("myapp")
-        .setting(AppSettings::HelpRequired)
-        .arg(Arg::with_name("foo").help("It does foo stuff"))
-        .get_matches();
-}
-
-#[test]
-fn help_required_and_no_args() {
-    App::new("myapp")
-        .setting(AppSettings::HelpRequired)
-        .get_matches();
-}