diff -pruN 3.1.7-1/Cargo.toml 3.2.15-1/Cargo.toml
--- 3.1.7-1/Cargo.toml	1970-01-01 00:00:01.000000000 +0000
+++ 3.2.15-1/Cargo.toml	1970-01-01 00:00:01.000000000 +0000
@@ -10,35 +10,55 @@
 # See Cargo.toml.orig for the original contents.
 
 [package]
-edition = "2018"
+edition = "2021"
+rust-version = "1.56.1"
 name = "clap_derive"
-version = "3.1.7"
-include = ["src/**/*", "Cargo.toml", "LICENSE-*", "README.md"]
+version = "3.2.15"
+include = [
+    "build.rs",
+    "src/**/*",
+    "Cargo.toml",
+    "LICENSE*",
+    "README.md",
+    "benches/**/*",
+    "examples/**/*",
+]
 description = "Parse command line argument by defining a struct, derive crate."
-documentation = "https://docs.rs/clap_derive"
 readme = "README.md"
-keywords = ["clap", "cli", "parse", "derive", "proc_macro"]
-categories = ["command-line-interface", "development-tools::procedural-macro-helpers"]
+keywords = [
+    "clap",
+    "cli",
+    "parse",
+    "derive",
+    "proc_macro",
+]
+categories = [
+    "command-line-interface",
+    "development-tools::procedural-macro-helpers",
+]
 license = "MIT OR Apache-2.0"
 repository = "https://github.com/clap-rs/clap/tree/master/clap_derive"
+resolver = "2"
+
 [package.metadata.docs.rs]
 targets = ["x86_64-unknown-linux-gnu"]
 
 [package.metadata.release]
-dependent-version = "upgrade"
 shared-version = true
+dependent-version = "upgrade"
 tag-name = "v{{version}}"
 
 [[package.metadata.release.pre-release-replacements]]
-exactly = 2
 file = "README.md"
-prerelease = true
-replace = "github.com/clap-rs/clap/blob/{{tag_name}}/"
 search = "github.com/clap-rs/clap/blob/[^/]+/"
+replace = "github.com/clap-rs/clap/blob/{{tag_name}}/"
+exactly = 2
+prerelease = true
 
 [lib]
 bench = false
 proc-macro = true
+
 [dependencies.heck]
 version = "0.4.0"
 
@@ -58,3 +78,6 @@ features = ["full"]
 [features]
 debug = []
 default = []
+deprecated = []
+raw-deprecated = ["deprecated"]
+unstable-v4 = ["deprecated"]
diff -pruN 3.1.7-1/Cargo.toml.orig 3.2.15-1/Cargo.toml.orig
--- 3.1.7-1/Cargo.toml.orig	1973-11-29 21:33:09.000000000 +0000
+++ 3.2.15-1/Cargo.toml.orig	1973-11-29 21:33:09.000000000 +0000
@@ -1,26 +1,31 @@
 [package]
 name = "clap_derive"
-version = "3.1.7"
-edition = "2018"
-include = [
-	"src/**/*",
-	"Cargo.toml",
-	"LICENSE-*",
-	"README.md"
-]
+version = "3.2.15"
 description = "Parse command line argument by defining a struct, derive crate."
 repository = "https://github.com/clap-rs/clap/tree/master/clap_derive"
-documentation = "https://docs.rs/clap_derive"
+categories = ["command-line-interface", "development-tools::procedural-macro-helpers"]
 keywords = [
-	"clap",
-	"cli",
-	"parse",
-	"derive",
-	"proc_macro"
+  "clap",
+  "cli",
+  "parse",
+  "derive",
+  "proc_macro"
 ]
-categories = ["command-line-interface", "development-tools::procedural-macro-helpers"]
 license = "MIT OR Apache-2.0"
-readme = "README.md"
+edition = "2021"
+rust-version = "1.56.1"  # MSRV
+include = [
+  "build.rs",
+  "src/**/*",
+  "Cargo.toml",
+  "LICENSE*",
+  "README.md",
+  "benches/**/*",
+  "examples/**/*"
+]
+
+[package.metadata.docs.rs]
+targets = ["x86_64-unknown-linux-gnu"]
 
 [package.metadata.release]
 shared-version = true
@@ -44,6 +49,6 @@ proc-macro-error = "1"
 [features]
 default = []
 debug = []
-
-[package.metadata.docs.rs]
-targets = ["x86_64-unknown-linux-gnu"]
+unstable-v4 = ["deprecated"]
+deprecated = []
+raw-deprecated = ["deprecated"]
diff -pruN 3.1.7-1/.cargo_vcs_info.json 3.2.15-1/.cargo_vcs_info.json
--- 3.1.7-1/.cargo_vcs_info.json	1970-01-01 00:00:01.000000000 +0000
+++ 3.2.15-1/.cargo_vcs_info.json	1970-01-01 00:00:01.000000000 +0000
@@ -1,6 +1,6 @@
 {
   "git": {
-    "sha1": "c75d2642ef7612da7f42d599989a8228b5b44e71"
+    "sha1": "b2a8fd7f46a7480512d5af8157041f5ce4c2c2b7"
   },
   "path_in_vcs": "clap_derive"
 }
\ No newline at end of file
diff -pruN 3.1.7-1/debian/cargo-checksum.json 3.2.15-1/debian/cargo-checksum.json
--- 3.1.7-1/debian/cargo-checksum.json	2022-04-15 11:26:37.000000000 +0000
+++ 3.2.15-1/debian/cargo-checksum.json	2022-07-31 16:41:35.000000000 +0000
@@ -1 +1 @@
-{"package":"a3aab4734e083b809aaf5794e14e756d1c798d2c69c7f7de7a09a2f5214993c1","files":{}}
+{"package":"9ba52acd3b0a5c33aeada5cdaa3267cdc7c594a98731d4268cdc1532f4264cb4","files":{}}
diff -pruN 3.1.7-1/debian/changelog 3.2.15-1/debian/changelog
--- 3.1.7-1/debian/changelog	2022-04-15 11:26:37.000000000 +0000
+++ 3.2.15-1/debian/changelog	2022-07-31 16:41:35.000000000 +0000
@@ -1,3 +1,10 @@
+rust-clap-derive (3.2.15-1) unstable; urgency=medium
+
+  * Team upload.
+  * Package clap_derive 3.2.15 from crates.io using debcargo 2.5.0
+
+ -- Peter Michael Green <plugwash@debian.org>  Sun, 31 Jul 2022 16:41:35 +0000
+
 rust-clap-derive (3.1.7-1) unstable; urgency=medium
 
   * Team upload.
diff -pruN 3.1.7-1/debian/control 3.2.15-1/debian/control
--- 3.1.7-1/debian/control	2022-04-15 11:26:37.000000000 +0000
+++ 3.2.15-1/debian/control	2022-07-31 16:41:35.000000000 +0000
@@ -35,15 +35,27 @@ Depends:
 Provides:
  librust-clap-derive+debug-dev (= ${binary:Version}),
  librust-clap-derive+default-dev (= ${binary:Version}),
+ librust-clap-derive+deprecated-dev (= ${binary:Version}),
+ librust-clap-derive+raw-deprecated-dev (= ${binary:Version}),
+ librust-clap-derive+unstable-v4-dev (= ${binary:Version}),
  librust-clap-derive-3-dev (= ${binary:Version}),
  librust-clap-derive-3+debug-dev (= ${binary:Version}),
  librust-clap-derive-3+default-dev (= ${binary:Version}),
- librust-clap-derive-3.1-dev (= ${binary:Version}),
- librust-clap-derive-3.1+debug-dev (= ${binary:Version}),
- librust-clap-derive-3.1+default-dev (= ${binary:Version}),
- librust-clap-derive-3.1.7-dev (= ${binary:Version}),
- librust-clap-derive-3.1.7+debug-dev (= ${binary:Version}),
- librust-clap-derive-3.1.7+default-dev (= ${binary:Version})
+ librust-clap-derive-3+deprecated-dev (= ${binary:Version}),
+ librust-clap-derive-3+raw-deprecated-dev (= ${binary:Version}),
+ librust-clap-derive-3+unstable-v4-dev (= ${binary:Version}),
+ librust-clap-derive-3.2-dev (= ${binary:Version}),
+ librust-clap-derive-3.2+debug-dev (= ${binary:Version}),
+ librust-clap-derive-3.2+default-dev (= ${binary:Version}),
+ librust-clap-derive-3.2+deprecated-dev (= ${binary:Version}),
+ librust-clap-derive-3.2+raw-deprecated-dev (= ${binary:Version}),
+ librust-clap-derive-3.2+unstable-v4-dev (= ${binary:Version}),
+ librust-clap-derive-3.2.15-dev (= ${binary:Version}),
+ librust-clap-derive-3.2.15+debug-dev (= ${binary:Version}),
+ librust-clap-derive-3.2.15+default-dev (= ${binary:Version}),
+ librust-clap-derive-3.2.15+deprecated-dev (= ${binary:Version}),
+ librust-clap-derive-3.2.15+raw-deprecated-dev (= ${binary:Version}),
+ librust-clap-derive-3.2.15+unstable-v4-dev (= ${binary:Version})
 Description: Parse command line argument by defining a struct, derive crate - Rust source code
  This package contains the source for the Rust clap_derive crate, packaged by
  debcargo for use with cargo and dh-cargo.
diff -pruN 3.1.7-1/debian/copyright 3.2.15-1/debian/copyright
--- 3.1.7-1/debian/copyright	2022-04-15 11:26:37.000000000 +0000
+++ 3.2.15-1/debian/copyright	2022-07-31 16:41:35.000000000 +0000
@@ -6,6 +6,7 @@ Source: https://github.com/clap-rs/clap/
 Files: *
 Copyright:
  2015-2022 Kevin B. Knapp <kbknapp@gmail.com>
+ 2015-2022 Clap Contributors
  2018 Guillaume Pinot <texitoi@texitoi.eu>
  2018 Ana Hobden <operator@hoverbear.org>
 License: MIT or Apache-2.0
diff -pruN 3.1.7-1/debian/copyright.debcargo.hint 3.2.15-1/debian/copyright.debcargo.hint
--- 3.1.7-1/debian/copyright.debcargo.hint	2022-04-15 11:26:37.000000000 +0000
+++ 3.2.15-1/debian/copyright.debcargo.hint	2022-07-31 16:41:35.000000000 +0000
@@ -13,7 +13,7 @@ Comment:
  the archive.
 
 Files: ./LICENSE-MIT
-Copyright: 2015-2016 Kevin B. Knapp
+Copyright: 2015-2022 Kevin B. Knapp and Clap Contributors
 License: UNKNOWN-LICENSE; FIXME (overlay)
 Comment:
  FIXME (overlay): These notices are extracted from files. Please review them
@@ -26,42 +26,42 @@ Comment:
  FIXME (overlay): These notices are extracted from files. Please review them
  before uploading to the archive.
 
-Files: ./src/derives/arg_enum.rs
+Files: ./src/derives/args.rs
 Copyright: 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
 License: UNKNOWN-LICENSE; FIXME (overlay)
 Comment:
  FIXME (overlay): These notices are extracted from files. Please review them
  before uploading to the archive.
 
-Files: ./src/derives/args.rs
+Files: ./src/derives/into_app.rs
 Copyright: 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
 License: UNKNOWN-LICENSE; FIXME (overlay)
 Comment:
  FIXME (overlay): These notices are extracted from files. Please review them
  before uploading to the archive.
 
-Files: ./src/derives/into_app.rs
+Files: ./src/derives/mod.rs
 Copyright: 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
 License: UNKNOWN-LICENSE; FIXME (overlay)
 Comment:
  FIXME (overlay): These notices are extracted from files. Please review them
  before uploading to the archive.
 
-Files: ./src/derives/mod.rs
+Files: ./src/derives/parser.rs
 Copyright: 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
 License: UNKNOWN-LICENSE; FIXME (overlay)
 Comment:
  FIXME (overlay): These notices are extracted from files. Please review them
  before uploading to the archive.
 
-Files: ./src/derives/parser.rs
+Files: ./src/derives/subcommand.rs
 Copyright: 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
 License: UNKNOWN-LICENSE; FIXME (overlay)
 Comment:
  FIXME (overlay): These notices are extracted from files. Please review them
  before uploading to the archive.
 
-Files: ./src/derives/subcommand.rs
+Files: ./src/derives/value_enum.rs
 Copyright: 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
 License: UNKNOWN-LICENSE; FIXME (overlay)
 Comment:
diff -pruN 3.1.7-1/debian/tests/control 3.2.15-1/debian/tests/control
--- 3.1.7-1/debian/tests/control	2022-04-15 11:26:37.000000000 +0000
+++ 3.2.15-1/debian/tests/control	2022-07-31 16:41:35.000000000 +0000
@@ -1,19 +1,34 @@
-Test-Command: /usr/share/cargo/bin/cargo-auto-test clap_derive 3.1.7 --all-targets --all-features
+Test-Command: /usr/share/cargo/bin/cargo-auto-test clap_derive 3.2.15 --all-targets --all-features
 Features: test-name=rust-clap-derive:@
 Depends: dh-cargo (>= 18), @
 Restrictions: allow-stderr, skip-not-installable
 
-Test-Command: /usr/share/cargo/bin/cargo-auto-test clap_derive 3.1.7 --all-targets --no-default-features --features debug
+Test-Command: /usr/share/cargo/bin/cargo-auto-test clap_derive 3.2.15 --all-targets --no-default-features --features debug
 Features: test-name=librust-clap-derive-dev:debug
 Depends: dh-cargo (>= 18), @
 Restrictions: allow-stderr, skip-not-installable
 
-Test-Command: /usr/share/cargo/bin/cargo-auto-test clap_derive 3.1.7 --all-targets 
+Test-Command: /usr/share/cargo/bin/cargo-auto-test clap_derive 3.2.15 --all-targets 
 Features: test-name=librust-clap-derive-dev:default
 Depends: dh-cargo (>= 18), @
 Restrictions: allow-stderr, skip-not-installable
 
-Test-Command: /usr/share/cargo/bin/cargo-auto-test clap_derive 3.1.7 --all-targets --no-default-features
+Test-Command: /usr/share/cargo/bin/cargo-auto-test clap_derive 3.2.15 --all-targets --no-default-features --features deprecated
+Features: test-name=librust-clap-derive-dev:deprecated
+Depends: dh-cargo (>= 18), @
+Restrictions: allow-stderr, skip-not-installable
+
+Test-Command: /usr/share/cargo/bin/cargo-auto-test clap_derive 3.2.15 --all-targets --no-default-features --features raw-deprecated
+Features: test-name=librust-clap-derive-dev:raw-deprecated
+Depends: dh-cargo (>= 18), @
+Restrictions: allow-stderr, skip-not-installable
+
+Test-Command: /usr/share/cargo/bin/cargo-auto-test clap_derive 3.2.15 --all-targets --no-default-features --features unstable-v4
+Features: test-name=librust-clap-derive-dev:unstable-v4
+Depends: dh-cargo (>= 18), @
+Restrictions: allow-stderr, skip-not-installable
+
+Test-Command: /usr/share/cargo/bin/cargo-auto-test clap_derive 3.2.15 --all-targets --no-default-features
 Features: test-name=librust-clap-derive-dev:
 Depends: dh-cargo (>= 18), @
 Restrictions: allow-stderr, skip-not-installable
diff -pruN 3.1.7-1/LICENSE-MIT 3.2.15-1/LICENSE-MIT
--- 3.1.7-1/LICENSE-MIT	1973-11-29 21:33:09.000000000 +0000
+++ 3.2.15-1/LICENSE-MIT	1973-11-29 21:33:09.000000000 +0000
@@ -1,6 +1,6 @@
 The MIT License (MIT)
 
-Copyright (c) 2015-2016 Kevin B. Knapp
+Copyright (c) 2015-2022 Kevin B. Knapp and Clap Contributors
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
diff -pruN 3.1.7-1/README.md 3.2.15-1/README.md
--- 3.1.7-1/README.md	1973-11-29 21:33:09.000000000 +0000
+++ 3.2.15-1/README.md	1973-11-29 21:33:09.000000000 +0000
@@ -3,8 +3,8 @@
 Macro implementation for clap's derives.
 
 [docs.rs](https://docs.rs/clap)
-- [Derive Tutorial](https://github.com/clap-rs/clap/blob/v3.1.7/examples/tutorial_derive/README.md)
-- [Derive Reference](https://github.com/clap-rs/clap/blob/v3.1.7/examples/derive_ref/README.md)
+- [Derive Tutorial](https://github.com/clap-rs/clap/blob/v3.2.15/examples/tutorial_derive/README.md)
+- [Derive Reference](https://github.com/clap-rs/clap/blob/v3.2.15/examples/derive_ref/README.md)
 
 ## License
 
diff -pruN 3.1.7-1/src/attrs.rs 3.2.15-1/src/attrs.rs
--- 3.1.7-1/src/attrs.rs	1973-11-29 21:33:09.000000000 +0000
+++ 3.2.15-1/src/attrs.rs	1973-11-29 21:33:09.000000000 +0000
@@ -14,7 +14,7 @@
 
 use crate::{
     parse::*,
-    utils::{process_doc_comment, Sp, Ty},
+    utils::{inner_type, is_simple_ty, process_doc_comment, Sp, Ty},
 };
 
 use std::env;
@@ -42,13 +42,15 @@ pub struct Attrs {
     ty: Option<Type>,
     doc_comment: Vec<Method>,
     methods: Vec<Method>,
-    parser: Sp<Parser>,
+    value_parser: Option<ValueParser>,
+    action: Option<Action>,
+    parser: Option<Sp<Parser>>,
     verbatim_doc_comment: Option<Ident>,
     next_display_order: Option<Method>,
     next_help_heading: Option<Method>,
     help_heading: Option<Method>,
     is_enum: bool,
-    has_custom_parser: bool,
+    is_positional: bool,
     kind: Sp<Kind>,
 }
 
@@ -64,12 +66,21 @@ impl Attrs {
         res.push_attrs(attrs);
         res.push_doc_comment(attrs, "about");
 
-        if res.has_custom_parser {
+        if let Some(value_parser) = res.value_parser.as_ref() {
             abort!(
-                res.parser.span(),
-                "`parse` attribute is only allowed on fields"
+                value_parser.span(),
+                "`value_parser` attribute is only allowed on fields"
             );
         }
+        if let Some(action) = res.action.as_ref() {
+            abort!(
+                action.span(),
+                "`action` attribute is only allowed on fields"
+            );
+        }
+        if let Some(parser) = res.parser.as_ref() {
+            abort!(parser.span(), "`parse` attribute is only allowed on fields");
+        }
         match &*res.kind {
             Kind::Subcommand(_) => abort!(res.kind.span(), "subcommand is only allowed on fields"),
             Kind::Skip(_) => abort!(res.kind.span(), "skip is only allowed on fields"),
@@ -101,9 +112,21 @@ impl Attrs {
 
         match &*res.kind {
             Kind::Flatten => {
-                if res.has_custom_parser {
+                if let Some(value_parser) = res.value_parser.as_ref() {
+                    abort!(
+                        value_parser.span(),
+                        "`value_parser` attribute is not allowed for flattened entry"
+                    );
+                }
+                if let Some(action) = res.action.as_ref() {
                     abort!(
-                        res.parser.span(),
+                        action.span(),
+                        "`action` attribute is not allowed for flattened entry"
+                    );
+                }
+                if let Some(parser) = res.parser.as_ref() {
+                    abort!(
+                        parser.span(),
                         "parse attribute is not allowed for flattened entry"
                     );
                 }
@@ -121,9 +144,21 @@ impl Attrs {
             Kind::ExternalSubcommand => (),
 
             Kind::Subcommand(_) => {
-                if res.has_custom_parser {
+                if let Some(value_parser) = res.value_parser.as_ref() {
+                    abort!(
+                        value_parser.span(),
+                        "`value_parser` attribute is not allowed for subcommand"
+                    );
+                }
+                if let Some(action) = res.action.as_ref() {
                     abort!(
-                        res.parser.span(),
+                        action.span(),
+                        "`action` attribute is not allowed for subcommand"
+                    );
+                }
+                if let Some(parser) = res.parser.as_ref() {
+                    abort!(
+                        parser.span(),
                         "parse attribute is not allowed for subcommand"
                     );
                 }
@@ -174,7 +209,7 @@ impl Attrs {
         res
     }
 
-    pub fn from_arg_enum_variant(
+    pub fn from_value_enum_variant(
         variant: &Variant,
         argument_casing: Sp<CasingStyle>,
         env_casing: Sp<CasingStyle>,
@@ -189,12 +224,21 @@ impl Attrs {
         res.push_attrs(&variant.attrs);
         res.push_doc_comment(&variant.attrs, "help");
 
-        if res.has_custom_parser {
+        if let Some(value_parser) = res.value_parser.as_ref() {
+            abort!(
+                value_parser.span(),
+                "`value_parser` attribute is only allowed on fields"
+            );
+        }
+        if let Some(action) = res.action.as_ref() {
             abort!(
-                res.parser.span(),
-                "`parse` attribute is only allowed on fields"
+                action.span(),
+                "`action` attribute is only allowed on fields"
             );
         }
+        if let Some(parser) = res.parser.as_ref() {
+            abort!(parser.span(), "`parse` attribute is only allowed on fields");
+        }
         match &*res.kind {
             Kind::Subcommand(_) => abort!(res.kind.span(), "subcommand is only allowed on fields"),
             Kind::Skip(_) => res,
@@ -226,9 +270,21 @@ impl Attrs {
 
         match &*res.kind {
             Kind::Flatten => {
-                if res.has_custom_parser {
+                if let Some(value_parser) = res.value_parser.as_ref() {
+                    abort!(
+                        value_parser.span(),
+                        "`value_parser` attribute is not allowed for flattened entry"
+                    );
+                }
+                if let Some(action) = res.action.as_ref() {
+                    abort!(
+                        action.span(),
+                        "`action` attribute is not allowed for flattened entry"
+                    );
+                }
+                if let Some(parser) = res.parser.as_ref() {
                     abort!(
-                        res.parser.span(),
+                        parser.span(),
                         "parse attribute is not allowed for flattened entry"
                     );
                 }
@@ -250,9 +306,21 @@ impl Attrs {
             }
 
             Kind::Subcommand(_) => {
-                if res.has_custom_parser {
+                if let Some(value_parser) = res.value_parser.as_ref() {
+                    abort!(
+                        value_parser.span(),
+                        "`value_parser` attribute is not allowed for subcommand"
+                    );
+                }
+                if let Some(action) = res.action.as_ref() {
+                    abort!(
+                        action.span(),
+                        "`action` attribute is not allowed for subcommand"
+                    );
+                }
+                if let Some(parser) = res.parser.as_ref() {
                     abort!(
-                        res.parser.span(),
+                        parser.span(),
                         "parse attribute is not allowed for subcommand"
                     );
                 }
@@ -294,9 +362,21 @@ impl Attrs {
                 let ty = Ty::from_syn_ty(&field.ty);
                 res.kind = Sp::new(Kind::FromGlobal(ty), orig_ty.span());
             }
-            Kind::Arg(orig_ty) => {
+            Kind::Arg(_) => {
                 let mut ty = Ty::from_syn_ty(&field.ty);
-                if res.has_custom_parser {
+                if res.parser.is_some() {
+                    if let Some(value_parser) = res.value_parser.as_ref() {
+                        abort!(
+                            value_parser.span(),
+                            "`value_parser` attribute conflicts with `parse` attribute"
+                        );
+                    }
+                    if let Some(action) = res.action.as_ref() {
+                        abort!(
+                            action.span(),
+                            "`action` attribute conflicts with `parse` attribute"
+                        );
+                    }
                     match *ty {
                         Ty::Option | Ty::Vec | Ty::OptionVec => (),
                         _ => ty = Sp::new(Ty::Other, ty.span()),
@@ -304,26 +384,6 @@ impl Attrs {
                 }
 
                 match *ty {
-                    Ty::Bool => {
-                        if res.is_positional() && !res.has_custom_parser {
-                            abort!(field.ty,
-                                "`bool` cannot be used as positional parameter with default parser";
-                                help = "if you want to create a flag add `long` or `short`";
-                                help = "If you really want a boolean parameter \
-                                    add an explicit parser, for example `parse(try_from_str)`";
-                                note = "see also https://github.com/clap-rs/clap/blob/master/examples/derive_ref/custom-bool.md";
-                            )
-                        }
-                        if res.is_enum {
-                            abort!(field.ty, "`arg_enum` is meaningless for bool")
-                        }
-                        if let Some(m) = res.find_default_method() {
-                            abort!(m.name, "default_value is meaningless for bool")
-                        }
-                        if let Some(m) = res.find_method("required") {
-                            abort!(m.name, "required is meaningless for bool")
-                        }
-                    }
                     Ty::Option => {
                         if let Some(m) = res.find_default_method() {
                             abort!(m.name, "default_value is meaningless for Option")
@@ -348,7 +408,14 @@ impl Attrs {
 
                     _ => (),
                 }
-                res.kind = Sp::new(Kind::Arg(ty), orig_ty.span());
+                res.kind = Sp::new(
+                    Kind::Arg(ty),
+                    field
+                        .ident
+                        .as_ref()
+                        .map(|i| i.span())
+                        .unwrap_or_else(|| field.ty.span()),
+                );
             }
         }
 
@@ -369,13 +436,15 @@ impl Attrs {
             env_casing,
             doc_comment: vec![],
             methods: vec![],
-            parser: Parser::default_spanned(default_span),
+            value_parser: None,
+            action: None,
+            parser: None,
             verbatim_doc_comment: None,
             next_display_order: None,
             next_help_heading: None,
             help_heading: None,
             is_enum: false,
-            has_custom_parser: false,
+            is_positional: true,
             kind: Sp::new(Kind::Arg(Sp::new(Ty::Other, default_span)), default_span),
         }
     }
@@ -383,7 +452,14 @@ impl Attrs {
     fn push_method(&mut self, name: Ident, arg: impl ToTokens) {
         if name == "name" {
             self.name = Name::Assigned(quote!(#arg));
+        } else if name == "value_parser" {
+            self.value_parser = Some(ValueParser::Explicit(Method::new(name, quote!(#arg))));
+        } else if name == "action" {
+            self.action = Some(Action::Explicit(Method::new(name, quote!(#arg))));
         } else {
+            if name == "short" || name == "long" {
+                self.is_positional = false;
+            }
             self.methods.push(Method::new(name, quote!(#arg)));
         }
     }
@@ -403,11 +479,21 @@ impl Attrs {
                     self.push_method(ident, self.name.clone().translate(*self.casing));
                 }
 
+                ValueParser(ident) => {
+                    use crate::attrs::ValueParser;
+                    self.value_parser = Some(ValueParser::Implicit(ident));
+                }
+
+                Action(ident) => {
+                    use crate::attrs::Action;
+                    self.action = Some(Action::Implicit(ident));
+                }
+
                 Env(ident) => {
                     self.push_method(ident, self.name.clone().translate(*self.env_casing));
                 }
 
-                ArgEnum(_) => self.is_enum = true,
+                ValueEnum(_) => self.is_enum = true,
 
                 FromGlobal(ident) => {
                     let ty = Sp::call_site(Ty::Other);
@@ -457,23 +543,20 @@ impl Attrs {
                         quote!(<#ty as ::std::default::Default>::default())
                     };
 
-                    let val = if parsed.iter().any(|a| matches!(a, ArgEnum(_))) {
+                    let val = if parsed.iter().any(|a| matches!(a, ValueEnum(_))) {
                         quote_spanned!(ident.span()=> {
                             {
                                 let val: #ty = #val;
-                                clap::ArgEnum::to_possible_value(&val).unwrap().get_name()
+                                clap::ValueEnum::to_possible_value(&val).unwrap().get_name()
                             }
                         })
                     } else {
                         quote_spanned!(ident.span()=> {
-                            clap::lazy_static::lazy_static! {
-                                static ref DEFAULT_VALUE: &'static str = {
-                                    let val: #ty = #val;
-                                    let s = ::std::string::ToString::to_string(&val);
-                                    ::std::boxed::Box::leak(s.into_boxed_str())
-                                };
-                            }
-                            *DEFAULT_VALUE
+                            static DEFAULT_VALUE: clap::__macro_refs::once_cell::sync::Lazy<String> = clap::__macro_refs::once_cell::sync::Lazy::new(|| {
+                                let val: #ty = #val;
+                                ::std::string::ToString::to_string(&val)
+                            });
+                            &*DEFAULT_VALUE
                         })
                     };
 
@@ -481,6 +564,81 @@ impl Attrs {
                     self.methods.push(Method::new(raw_ident, val));
                 }
 
+                DefaultValuesT(ident, expr) => {
+                    let ty = if let Some(ty) = self.ty.as_ref() {
+                        ty
+                    } else {
+                        abort!(
+                            ident,
+                            "#[clap(default_values_t)] (without an argument) can be used \
+                            only on field level";
+
+                            note = "see \
+                                https://github.com/clap-rs/clap/blob/master/examples/derive_ref/README.md#magic-attributes")
+                    };
+
+                    let container_type = Ty::from_syn_ty(ty);
+                    if *container_type != Ty::Vec {
+                        abort!(
+                            ident,
+                            "#[clap(default_values_t)] can be used only on Vec types";
+
+                            note = "see \
+                                https://github.com/clap-rs/clap/blob/master/examples/derive_ref/README.md#magic-attributes")
+                    }
+                    let inner_type = inner_type(ty);
+
+                    // Use `Borrow<#inner_type>` so we accept `&Vec<#inner_type>` and
+                    // `Vec<#inner_type>`.
+                    let val = if parsed.iter().any(|a| matches!(a, ValueEnum(_))) {
+                        quote_spanned!(ident.span()=> {
+                            {
+                                fn iter_to_vals<T>(iterable: impl IntoIterator<Item = T>) -> Vec<&'static str>
+                                where
+                                    T: ::std::borrow::Borrow<#inner_type>
+                                {
+                                    iterable
+                                        .into_iter()
+                                        .map(|val| {
+                                            clap::ValueEnum::to_possible_value(val.borrow()).unwrap().get_name()
+                                        })
+                                        .collect()
+
+                                }
+
+                                static DEFAULT_VALUES: clap::__macro_refs::once_cell::sync::Lazy<Vec<&str>> = clap::__macro_refs::once_cell::sync::Lazy::new(|| {
+                                    iter_to_vals(#expr)
+                                });
+                                &*DEFAULT_VALUES.as_slice()
+                            }
+                        })
+                    } else {
+                        quote_spanned!(ident.span()=> {
+                            {
+                                fn iter_to_vals<T>(iterable: impl IntoIterator<Item = T>) -> Vec<String>
+                                where
+                                    T: ::std::borrow::Borrow<#inner_type>
+                                {
+                                    iterable.into_iter().map(|val| val.borrow().to_string()).collect()
+
+                                }
+
+                                static DEFAULT_STRINGS: clap::__macro_refs::once_cell::sync::Lazy<Vec<::std::string::String>> = clap::__macro_refs::once_cell::sync::Lazy::new(|| {
+                                    iter_to_vals(#expr)
+                                });
+
+                                static DEFAULT_VALUES: clap::__macro_refs::once_cell::sync::Lazy<Vec<&str>> = clap::__macro_refs::once_cell::sync::Lazy::new(|| {
+                                    DEFAULT_STRINGS.iter().map(::std::string::String::as_str).collect()
+                                });
+                                &*DEFAULT_VALUES.as_slice()
+                            }
+                        })
+                    };
+
+                    self.methods
+                        .push(Method::new(Ident::new("default_values", ident.span()), val));
+                }
+
                 DefaultValueOsT(ident, expr) => {
                     let ty = if let Some(ty) = self.ty.as_ref() {
                         ty
@@ -500,23 +658,20 @@ impl Attrs {
                         quote!(<#ty as ::std::default::Default>::default())
                     };
 
-                    let val = if parsed.iter().any(|a| matches!(a, ArgEnum(_))) {
+                    let val = if parsed.iter().any(|a| matches!(a, ValueEnum(_))) {
                         quote_spanned!(ident.span()=> {
                             {
                                 let val: #ty = #val;
-                                clap::ArgEnum::to_possible_value(&val).unwrap().get_name()
+                                clap::ValueEnum::to_possible_value(&val).unwrap().get_name()
                             }
                         })
                     } else {
                         quote_spanned!(ident.span()=> {
-                            clap::lazy_static::lazy_static! {
-                                static ref DEFAULT_VALUE: &'static ::std::ffi::OsStr = {
-                                    let val: #ty = #val;
-                                    let s: ::std::ffi::OsString = val.into();
-                                    ::std::boxed::Box::leak(s.into_boxed_os_str())
-                                };
-                            }
-                            *DEFAULT_VALUE
+                            static DEFAULT_VALUE: clap::__macro_refs::once_cell::sync::Lazy<::std::ffi::OsString> = clap::__macro_refs::once_cell::sync::Lazy::new(|| {
+                                let val: #ty = #val;
+                                ::std::ffi::OsString::from(val)
+                            });
+                            &*DEFAULT_VALUE
                         })
                     };
 
@@ -524,6 +679,84 @@ impl Attrs {
                     self.methods.push(Method::new(raw_ident, val));
                 }
 
+                DefaultValuesOsT(ident, expr) => {
+                    let ty = if let Some(ty) = self.ty.as_ref() {
+                        ty
+                    } else {
+                        abort!(
+                            ident,
+                            "#[clap(default_values_os_t)] (without an argument) can be used \
+                            only on field level";
+
+                            note = "see \
+                                https://github.com/clap-rs/clap/blob/master/examples/derive_ref/README.md#magic-attributes")
+                    };
+
+                    let container_type = Ty::from_syn_ty(ty);
+                    if *container_type != Ty::Vec {
+                        abort!(
+                            ident,
+                            "#[clap(default_values_os_t)] can be used only on Vec types";
+
+                            note = "see \
+                                https://github.com/clap-rs/clap/blob/master/examples/derive_ref/README.md#magic-attributes")
+                    }
+                    let inner_type = inner_type(ty);
+
+                    // Use `Borrow<#inner_type>` so we accept `&Vec<#inner_type>` and
+                    // `Vec<#inner_type>`.
+                    let val = if parsed.iter().any(|a| matches!(a, ValueEnum(_))) {
+                        quote_spanned!(ident.span()=> {
+                            {
+                                fn iter_to_vals<T>(iterable: impl IntoIterator<Item = T>) -> Vec<&'static ::std::ffi::OsStr>
+                                where
+                                    T: ::std::borrow::Borrow<#inner_type>
+                                {
+                                    iterable
+                                        .into_iter()
+                                        .map(|val| {
+                                            clap::ValueEnum::to_possible_value(val.borrow()).unwrap().get_name()
+                                        })
+                                        .map(::std::ffi::OsStr::new)
+                                        .collect()
+
+                                }
+
+                                static DEFAULT_VALUES: clap::__macro_refs::once_cell::sync::Lazy<Vec<&::std::ffi::OsStr>> = clap::__macro_refs::once_cell::sync::Lazy::new(|| {
+                                    iter_to_vals(#expr)
+                                });
+                                &*DEFAULT_VALUES.as_slice()
+                            }
+                        })
+                    } else {
+                        quote_spanned!(ident.span()=> {
+                            {
+                                fn iter_to_vals<T>(iterable: impl IntoIterator<Item = T>) -> Vec<::std::ffi::OsString>
+                                where
+                                    T: ::std::borrow::Borrow<#inner_type>
+                                {
+                                    iterable.into_iter().map(|val| val.borrow().into()).collect()
+
+                                }
+
+                                static DEFAULT_OS_STRINGS: clap::__macro_refs::once_cell::sync::Lazy<Vec<::std::ffi::OsString>> = clap::__macro_refs::once_cell::sync::Lazy::new(|| {
+                                    iter_to_vals(#expr)
+                                });
+
+                                static DEFAULT_VALUES: clap::__macro_refs::once_cell::sync::Lazy<Vec<&::std::ffi::OsStr>> = clap::__macro_refs::once_cell::sync::Lazy::new(|| {
+                                    DEFAULT_OS_STRINGS.iter().map(::std::ffi::OsString::as_os_str).collect()
+                                });
+                                &*DEFAULT_VALUES.as_slice()
+                            }
+                        })
+                    };
+
+                    self.methods.push(Method::new(
+                        Ident::new("default_values_os", ident.span()),
+                        val,
+                    ));
+                }
+
                 NextDisplayOrder(ident, expr) => {
                     self.next_display_order = Some(Method::new(ident, quote!(#expr)));
                 }
@@ -572,8 +805,7 @@ impl Attrs {
                 }
 
                 Parse(ident, spec) => {
-                    self.has_custom_parser = true;
-                    self.parser = Parser::from_spec(ident, spec);
+                    self.parser = Some(Parser::from_spec(ident, spec));
                 }
             }
         }
@@ -671,6 +903,16 @@ impl Attrs {
         quote!( #(#next_help_heading)*  #(#help_heading)* )
     }
 
+    #[cfg(feature = "unstable-v4")]
+    pub fn id(&self) -> TokenStream {
+        self.name.clone().raw()
+    }
+
+    #[cfg(not(feature = "unstable-v4"))]
+    pub fn id(&self) -> TokenStream {
+        self.cased_name()
+    }
+
     pub fn cased_name(&self) -> TokenStream {
         self.name.clone().translate(*self.casing)
     }
@@ -679,8 +921,71 @@ impl Attrs {
         self.name.clone().translate(CasingStyle::ScreamingSnake)
     }
 
-    pub fn parser(&self) -> &Sp<Parser> {
-        &self.parser
+    pub fn value_parser(&self, field_type: &Type) -> Method {
+        self.value_parser
+            .clone()
+            .map(|p| {
+                let inner_type = inner_type(field_type);
+                p.resolve(inner_type)
+            })
+            .unwrap_or_else(|| {
+                if let Some(action) = self.action.as_ref() {
+                    let inner_type = inner_type(field_type);
+                    let span = action.span();
+                    default_value_parser(inner_type, span)
+                } else if !self.ignore_parser() || cfg!(not(feature = "unstable-v4")) {
+                    self.parser(field_type).value_parser()
+                } else {
+                    let inner_type = inner_type(field_type);
+                    let span = self
+                        .action
+                        .as_ref()
+                        .map(|a| a.span())
+                        .unwrap_or_else(|| self.kind.span());
+                    default_value_parser(inner_type, span)
+                }
+            })
+    }
+
+    pub fn action(&self, field_type: &Type) -> Method {
+        self.action
+            .clone()
+            .map(|p| p.resolve(field_type))
+            .unwrap_or_else(|| {
+                if let Some(value_parser) = self.value_parser.as_ref() {
+                    let span = value_parser.span();
+                    default_action(field_type, span)
+                } else if !self.ignore_parser() || cfg!(not(feature = "unstable-v4")) {
+                    self.parser(field_type).action()
+                } else {
+                    let span = self
+                        .value_parser
+                        .as_ref()
+                        .map(|a| a.span())
+                        .unwrap_or_else(|| self.kind.span());
+                    default_action(field_type, span)
+                }
+            })
+    }
+
+    #[cfg(feature = "unstable-v4")]
+    pub fn ignore_parser(&self) -> bool {
+        self.parser.is_none()
+    }
+
+    #[cfg(not(feature = "unstable-v4"))]
+    pub fn ignore_parser(&self) -> bool {
+        self.value_parser.is_some() || self.action.is_some()
+    }
+
+    pub fn explicit_parser(&self) -> bool {
+        self.parser.is_some()
+    }
+
+    pub fn parser(&self, field_type: &Type) -> Sp<Parser> {
+        self.parser
+            .clone()
+            .unwrap_or_else(|| Parser::from_type(field_type, self.kind.span()))
     }
 
     pub fn kind(&self) -> Sp<Kind> {
@@ -691,6 +996,10 @@ impl Attrs {
         self.is_enum
     }
 
+    pub fn is_positional(&self) -> bool {
+        self.is_positional
+    }
+
     pub fn ignore_case(&self) -> TokenStream {
         let method = self.find_method("ignore_case");
 
@@ -709,12 +1018,6 @@ impl Attrs {
         self.env_casing.clone()
     }
 
-    pub fn is_positional(&self) -> bool {
-        self.methods
-            .iter()
-            .all(|m| m.name != "long" && m.name != "short")
-    }
-
     pub fn has_explicit_methods(&self) -> bool {
         self.methods
             .iter()
@@ -722,6 +1025,90 @@ impl Attrs {
     }
 }
 
+#[derive(Clone)]
+enum ValueParser {
+    Explicit(Method),
+    Implicit(Ident),
+}
+
+impl ValueParser {
+    fn resolve(self, inner_type: &Type) -> Method {
+        match self {
+            Self::Explicit(method) => method,
+            Self::Implicit(ident) => default_value_parser(inner_type, ident.span()),
+        }
+    }
+
+    fn span(&self) -> Span {
+        match self {
+            Self::Explicit(method) => method.name.span(),
+            Self::Implicit(ident) => ident.span(),
+        }
+    }
+}
+
+fn default_value_parser(inner_type: &Type, span: Span) -> Method {
+    let func = Ident::new("value_parser", span);
+    Method::new(
+        func,
+        quote_spanned! { span=>
+            clap::value_parser!(#inner_type)
+        },
+    )
+}
+
+#[derive(Clone)]
+pub enum Action {
+    Explicit(Method),
+    Implicit(Ident),
+}
+
+impl Action {
+    pub fn resolve(self, field_type: &Type) -> Method {
+        match self {
+            Self::Explicit(method) => method,
+            Self::Implicit(ident) => default_action(field_type, ident.span()),
+        }
+    }
+
+    pub fn span(&self) -> Span {
+        match self {
+            Self::Explicit(method) => method.name.span(),
+            Self::Implicit(ident) => ident.span(),
+        }
+    }
+}
+
+fn default_action(field_type: &Type, span: Span) -> Method {
+    let ty = Ty::from_syn_ty(field_type);
+    let args = match *ty {
+        Ty::Vec | Ty::OptionVec => {
+            quote_spanned! { span=>
+                clap::ArgAction::Append
+            }
+        }
+        Ty::Option | Ty::OptionOption => {
+            quote_spanned! { span=>
+                clap::ArgAction::Set
+            }
+        }
+        _ => {
+            if is_simple_ty(field_type, "bool") {
+                quote_spanned! { span=>
+                    clap::ArgAction::SetTrue
+                }
+            } else {
+                quote_spanned! { span=>
+                    clap::ArgAction::Set
+                }
+            }
+        }
+    };
+
+    let func = Ident::new("action", span);
+    Method::new(func, args)
+}
+
 #[allow(clippy::large_enum_variant)]
 #[derive(Clone)]
 pub enum Kind {
@@ -768,6 +1155,10 @@ impl Method {
 
         Some(Method::new(ident, quote!(#lit)))
     }
+
+    pub(crate) fn args(&self) -> &TokenStream {
+        &self.args
+    }
 }
 
 impl ToTokens for Method {
@@ -812,10 +1203,16 @@ pub struct Parser {
 }
 
 impl Parser {
-    fn default_spanned(span: Span) -> Sp<Self> {
-        let kind = Sp::new(ParserKind::TryFromStr, span);
-        let func = quote_spanned!(span=> ::std::str::FromStr::from_str);
-        Sp::new(Parser { kind, func }, span)
+    fn from_type(field_type: &Type, span: Span) -> Sp<Self> {
+        if is_simple_ty(field_type, "bool") {
+            let kind = Sp::new(ParserKind::FromFlag, span);
+            let func = quote_spanned!(span=> ::std::convert::From::from);
+            Sp::new(Parser { kind, func }, span)
+        } else {
+            let kind = Sp::new(ParserKind::TryFromStr, span);
+            let func = quote_spanned!(span=> ::std::str::FromStr::from_str);
+            Sp::new(Parser { kind, func }, span)
+        }
     }
 
     fn from_spec(parse_ident: Ident, spec: ParserSpec) -> Sp<Self> {
@@ -855,9 +1252,49 @@ impl Parser {
         let parser = Parser { kind, func };
         Sp::new(parser, parse_ident.span())
     }
+
+    fn value_parser(&self) -> Method {
+        let func = Ident::new("value_parser", self.kind.span());
+        match *self.kind {
+            ParserKind::FromStr | ParserKind::TryFromStr => Method::new(
+                func,
+                quote_spanned! { self.kind.span()=>
+                clap::builder::ValueParser::string()},
+            ),
+            ParserKind::FromOsStr | ParserKind::TryFromOsStr => Method::new(
+                func,
+                quote_spanned! { self.kind.span()=> clap::builder::ValueParser::os_string()},
+            ),
+            ParserKind::FromOccurrences => Method::new(
+                func,
+                quote_spanned! { self.kind.span()=> clap::value_parser!(u64)},
+            ),
+            ParserKind::FromFlag => Method::new(
+                func,
+                quote_spanned! { self.kind.span()=> clap::builder::ValueParser::bool()},
+            ),
+        }
+    }
+
+    fn action(&self) -> Method {
+        let func = Ident::new("action", self.kind.span());
+        match *self.kind {
+            ParserKind::FromStr
+            | ParserKind::TryFromStr
+            | ParserKind::FromOsStr
+            | ParserKind::TryFromOsStr => Method::new(
+                func,
+                quote_spanned! { self.kind.span()=> clap::ArgAction::StoreValue},
+            ),
+            ParserKind::FromOccurrences | ParserKind::FromFlag => Method::new(
+                func,
+                quote_spanned! { self.kind.span()=> clap::ArgAction::IncOccurrence},
+            ),
+        }
+    }
 }
 
-#[derive(Debug, PartialEq, Clone)]
+#[derive(Debug, PartialEq, Clone, Copy)]
 pub enum ParserKind {
     FromStr,
     TryFromStr,
@@ -916,6 +1353,17 @@ pub enum Name {
 }
 
 impl Name {
+    #[cfg(feature = "unstable-v4")]
+    pub fn raw(self) -> TokenStream {
+        match self {
+            Name::Assigned(tokens) => tokens,
+            Name::Derived(ident) => {
+                let s = ident.unraw().to_string();
+                quote_spanned!(ident.span()=> #s)
+            }
+        }
+    }
+
     pub fn translate(self, style: CasingStyle) -> TokenStream {
         use CasingStyle::*;
 
diff -pruN 3.1.7-1/src/derives/arg_enum.rs 3.2.15-1/src/derives/arg_enum.rs
--- 3.1.7-1/src/derives/arg_enum.rs	1973-11-29 21:33:09.000000000 +0000
+++ 3.2.15-1/src/derives/arg_enum.rs	1970-01-01 00:00:00.000000000 +0000
@@ -1,123 +0,0 @@
-// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
-// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
-// Ana Hobden (@hoverbear) <operator@hoverbear.org>
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use crate::{
-    attrs::{Attrs, Kind, Name, DEFAULT_CASING, DEFAULT_ENV_CASING},
-    dummies,
-    utils::Sp,
-};
-
-use proc_macro2::{Span, TokenStream};
-use proc_macro_error::{abort, abort_call_site};
-use quote::quote;
-use syn::{
-    punctuated::Punctuated, spanned::Spanned, token::Comma, Attribute, Data, DataEnum, DeriveInput,
-    Fields, Ident, Variant,
-};
-
-pub fn derive_arg_enum(input: &DeriveInput) -> TokenStream {
-    let ident = &input.ident;
-
-    dummies::arg_enum(ident);
-
-    match input.data {
-        Data::Enum(ref e) => gen_for_enum(ident, &input.attrs, e),
-        _ => abort_call_site!("`#[derive(ArgEnum)]` only supports enums"),
-    }
-}
-
-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 lits = lits(&e.variants, &attrs);
-    let value_variants = gen_value_variants(&lits);
-    let to_possible_value = gen_to_possible_value(&lits);
-
-    quote! {
-        #[allow(dead_code, unreachable_code, unused_variables, unused_braces)]
-        #[allow(
-            clippy::style,
-            clippy::complexity,
-            clippy::pedantic,
-            clippy::restriction,
-            clippy::perf,
-            clippy::deprecated,
-            clippy::nursery,
-            clippy::cargo,
-            clippy::suspicious_else_formatting,
-        )]
-        #[deny(clippy::correctness)]
-        impl clap::ArgEnum for #name {
-            #value_variants
-            #to_possible_value
-        }
-    }
-}
-
-fn lits(
-    variants: &Punctuated<Variant, Comma>,
-    parent_attribute: &Attrs,
-) -> Vec<(TokenStream, Ident)> {
-    variants
-        .iter()
-        .filter_map(|variant| {
-            let attrs = Attrs::from_arg_enum_variant(
-                variant,
-                parent_attribute.casing(),
-                parent_attribute.env_casing(),
-            );
-            if let Kind::Skip(_) = &*attrs.kind() {
-                None
-            } else {
-                if !matches!(variant.fields, Fields::Unit) {
-                    abort!(variant.span(), "`#[derive(ArgEnum)]` only supports non-unit variants, unless they are skipped");
-                }
-                let fields = attrs.field_methods(false);
-                let name = attrs.cased_name();
-                Some((
-                    quote! {
-                        clap::PossibleValue::new(#name)
-                        #fields
-                    },
-                    variant.ident.clone(),
-                ))
-            }
-        })
-        .collect::<Vec<_>>()
-}
-
-fn gen_value_variants(lits: &[(TokenStream, Ident)]) -> TokenStream {
-    let lit = lits.iter().map(|l| &l.1).collect::<Vec<_>>();
-
-    quote! {
-        fn value_variants<'a>() -> &'a [Self]{
-            &[#(Self::#lit),*]
-        }
-    }
-}
-
-fn gen_to_possible_value(lits: &[(TokenStream, Ident)]) -> TokenStream {
-    let (lit, variant): (Vec<TokenStream>, Vec<Ident>) = lits.iter().cloned().unzip();
-
-    quote! {
-        fn to_possible_value<'a>(&self) -> ::std::option::Option<clap::PossibleValue<'a>> {
-            match self {
-                #(Self::#variant => Some(#lit),)*
-                _ => None
-            }
-        }
-    }
-}
diff -pruN 3.1.7-1/src/derives/args.rs 3.2.15-1/src/derives/args.rs
--- 3.1.7-1/src/derives/args.rs	1973-11-29 21:33:09.000000000 +0000
+++ 3.2.15-1/src/derives/args.rs	1973-11-29 21:33:09.000000000 +0000
@@ -15,7 +15,7 @@
 use crate::{
     attrs::{Attrs, Kind, Name, ParserKind, DEFAULT_CASING, DEFAULT_ENV_CASING},
     dummies,
-    utils::{inner_type, sub_type, Sp, Ty},
+    utils::{inner_type, is_simple_ty, sub_type, Sp, Ty},
 };
 
 use proc_macro2::{Ident, Span, TokenStream};
@@ -113,6 +113,7 @@ pub fn gen_from_arg_matches_for_struct(
 
     let constructor = gen_constructor(fields, &attrs);
     let updater = gen_updater(fields, &attrs, true);
+    let raw_deprecated = raw_deprecated();
 
     let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
 
@@ -132,11 +133,21 @@ pub fn gen_from_arg_matches_for_struct(
         #[deny(clippy::correctness)]
         impl #impl_generics clap::FromArgMatches for #struct_name #ty_generics #where_clause {
             fn from_arg_matches(__clap_arg_matches: &clap::ArgMatches) -> ::std::result::Result<Self, clap::Error> {
+                Self::from_arg_matches_mut(&mut __clap_arg_matches.clone())
+            }
+
+            fn from_arg_matches_mut(__clap_arg_matches: &mut clap::ArgMatches) -> ::std::result::Result<Self, clap::Error> {
+                #raw_deprecated
                 let v = #struct_name #constructor;
                 ::std::result::Result::Ok(v)
             }
 
             fn update_from_arg_matches(&mut self, __clap_arg_matches: &clap::ArgMatches) -> ::std::result::Result<(), clap::Error> {
+                self.update_from_arg_matches_mut(&mut __clap_arg_matches.clone())
+            }
+
+            fn update_from_arg_matches_mut(&mut self, __clap_arg_matches: &mut clap::ArgMatches) -> ::std::result::Result<(), clap::Error> {
+                #raw_deprecated
                 #updater
                 ::std::result::Result::Ok(())
             }
@@ -233,16 +244,18 @@ pub fn gen_augment(
                 }
             }
             Kind::Arg(ty) => {
-                let convert_type = inner_type(**ty, &field.ty);
+                let convert_type = inner_type(&field.ty);
 
-                let occurrences = *attrs.parser().kind == ParserKind::FromOccurrences;
-                let flag = *attrs.parser().kind == ParserKind::FromFlag;
+                let parser = attrs.parser(&field.ty);
 
-                let parser = attrs.parser();
+                let value_parser = attrs.value_parser(&field.ty);
+                let action = attrs.action(&field.ty);
                 let func = &parser.func;
 
+                let mut occurrences = false;
+                let mut flag = false;
                 let validator = match *parser.kind {
-                    _ if attrs.is_enum() => quote!(),
+                    _ if attrs.ignore_parser() || attrs.is_enum() => quote!(),
                     ParserKind::TryFromStr => quote_spanned! { func.span()=>
                         .validator(|s| {
                             #func(s)
@@ -252,41 +265,72 @@ pub fn gen_augment(
                     ParserKind::TryFromOsStr => quote_spanned! { func.span()=>
                         .validator_os(|s| #func(s).map(|_: #convert_type| ()))
                     },
-                    ParserKind::FromStr
-                    | ParserKind::FromOsStr
-                    | ParserKind::FromFlag
-                    | ParserKind::FromOccurrences => quote!(),
+                    ParserKind::FromStr | ParserKind::FromOsStr => quote!(),
+                    ParserKind::FromFlag => {
+                        flag = true;
+                        quote!()
+                    }
+                    ParserKind::FromOccurrences => {
+                        occurrences = true;
+                        quote!()
+                    }
                 };
-                let allow_invalid_utf8 = match *parser.kind {
-                    _ if attrs.is_enum() => quote!(),
-                    ParserKind::FromOsStr | ParserKind::TryFromOsStr => {
-                        quote_spanned! { func.span()=>
-                            .allow_invalid_utf8(true)
+                let parse_deprecation = match *parser.kind {
+                    _ if !attrs.explicit_parser() || cfg!(not(feature = "deprecated")) => quote!(),
+                    ParserKind::FromStr => quote_spanned! { func.span()=>
+                        #[deprecated(since = "3.2.0", note = "Replaced with `#[clap(value_parser = ...)]`")]
+                        fn parse_from_str() {
                         }
-                    }
-                    ParserKind::FromStr
-                    | ParserKind::TryFromStr
-                    | ParserKind::FromFlag
-                    | ParserKind::FromOccurrences => quote!(),
+                        parse_from_str();
+                    },
+                    ParserKind::TryFromStr => quote_spanned! { func.span()=>
+                        #[deprecated(since = "3.2.0", note = "Replaced with `#[clap(value_parser = ...)]`")]
+                        fn parse_try_from_str() {
+                        }
+                        parse_try_from_str();
+                    },
+                    ParserKind::FromOsStr => quote_spanned! { func.span()=>
+                        #[deprecated(since = "3.2.0", note = "Replaced with `#[clap(value_parser)]` for `PathBuf` or `#[clap(value_parser = ...)]` with a custom `TypedValueParser`")]
+                        fn parse_from_os_str() {
+                        }
+                        parse_from_os_str();
+                    },
+                    ParserKind::TryFromOsStr => quote_spanned! { func.span()=>
+                        #[deprecated(since = "3.2.0", note = "Replaced with `#[clap(value_parser = ...)]` with a custom `TypedValueParser`")]
+                        fn parse_try_from_os_str() {
+                        }
+                        parse_try_from_os_str();
+                    },
+                    ParserKind::FromFlag => quote_spanned! { func.span()=>
+                        #[deprecated(since = "3.2.0", note = "Replaced with `#[clap(action = ArgAction::SetTrue)]`")]
+                        fn parse_from_flag() {
+                        }
+                        parse_from_flag();
+                    },
+                    ParserKind::FromOccurrences => quote_spanned! { func.span()=>
+                        #[deprecated(since = "3.2.0", note = "Replaced with `#[clap(action = ArgAction::Count)]` with a field type of `u8`")]
+                        fn parse_from_occurrences() {
+                        }
+                        parse_from_occurrences();
+                    },
                 };
 
                 let value_name = attrs.value_name();
-                let possible_values = if attrs.is_enum() {
-                    gen_arg_enum_possible_values(convert_type)
+                let possible_values = if attrs.is_enum() && !attrs.ignore_parser() {
+                    gen_value_enum_possible_values(convert_type)
                 } else {
                     quote!()
                 };
 
-                let modifier = match **ty {
-                    Ty::Bool => quote!(),
-
+                let implicit_methods = match **ty {
                     Ty::Option => {
                         quote_spanned! { ty.span()=>
                             .takes_value(true)
                             .value_name(#value_name)
                             #possible_values
                             #validator
-                            #allow_invalid_utf8
+                            #value_parser
+                            #action
                         }
                     }
 
@@ -298,26 +342,77 @@ pub fn gen_augment(
                         .multiple_values(false)
                         #possible_values
                         #validator
-                        #allow_invalid_utf8
+                        #value_parser
+                        #action
                     },
 
-                    Ty::OptionVec => quote_spanned! { ty.span()=>
-                        .takes_value(true)
-                        .value_name(#value_name)
-                        .multiple_occurrences(true)
-                        #possible_values
-                        #validator
-                        #allow_invalid_utf8
-                    },
+                    Ty::OptionVec => {
+                        if attrs.ignore_parser() {
+                            if attrs.is_positional() {
+                                quote_spanned! { ty.span()=>
+                                    .takes_value(true)
+                                    .value_name(#value_name)
+                                    .multiple_values(true)  // action won't be sufficient for getting multiple
+                                    #possible_values
+                                    #validator
+                                    #value_parser
+                                    #action
+                                }
+                            } else {
+                                quote_spanned! { ty.span()=>
+                                    .takes_value(true)
+                                    .value_name(#value_name)
+                                    #possible_values
+                                    #validator
+                                    #value_parser
+                                    #action
+                                }
+                            }
+                        } else {
+                            quote_spanned! { ty.span()=>
+                                .takes_value(true)
+                                .value_name(#value_name)
+                                .multiple_occurrences(true)
+                                #possible_values
+                                #validator
+                                #value_parser
+                                #action
+                            }
+                        }
+                    }
 
                     Ty::Vec => {
-                        quote_spanned! { ty.span()=>
-                            .takes_value(true)
-                            .value_name(#value_name)
-                            .multiple_occurrences(true)
-                            #possible_values
-                            #validator
-                            #allow_invalid_utf8
+                        if attrs.ignore_parser() {
+                            if attrs.is_positional() {
+                                quote_spanned! { ty.span()=>
+                                    .takes_value(true)
+                                    .value_name(#value_name)
+                                    .multiple_values(true)  // action won't be sufficient for getting multiple
+                                    #possible_values
+                                    #validator
+                                    #value_parser
+                                    #action
+                                }
+                            } else {
+                                quote_spanned! { ty.span()=>
+                                    .takes_value(true)
+                                    .value_name(#value_name)
+                                    #possible_values
+                                    #validator
+                                    #value_parser
+                                    #action
+                                }
+                            }
+                        } else {
+                            quote_spanned! { ty.span()=>
+                                .takes_value(true)
+                                .value_name(#value_name)
+                                .multiple_occurrences(true)
+                                #possible_values
+                                #validator
+                                #value_parser
+                                #action
+                            }
                         }
                     }
 
@@ -331,26 +426,37 @@ pub fn gen_augment(
 
                     Ty::Other => {
                         let required = attrs.find_default_method().is_none() && !override_required;
+                        // `ArgAction::takes_values` is assuming `ArgAction::default_value` will be
+                        // set though that won't always be true but this should be good enough,
+                        // otherwise we'll report an "arg required" error when unwrapping.
+                        let action_value = action.args();
                         quote_spanned! { ty.span()=>
                             .takes_value(true)
                             .value_name(#value_name)
-                            .required(#required)
+                            .required(#required && #action_value.takes_values())
                             #possible_values
                             #validator
-                            #allow_invalid_utf8
+                            #value_parser
+                            #action
                         }
                     }
                 };
 
-                let name = attrs.cased_name();
-                let methods = attrs.field_methods(true);
+                let id = attrs.id();
+                let explicit_methods = attrs.field_methods(true);
 
                 Some(quote_spanned! { field.span()=>
-                    let #app_var = #app_var.arg(
-                        clap::Arg::new(#name)
-                            #modifier
-                            #methods
-                    );
+                    let #app_var = #app_var.arg({
+                        #parse_deprecation
+
+                        #[allow(deprecated)]
+                        let arg = clap::Arg::new(#id)
+                            #implicit_methods;
+
+                        let arg = arg
+                            #explicit_methods;
+                        arg
+                    });
                 })
             }
         }
@@ -366,9 +472,9 @@ pub fn gen_augment(
     }}
 }
 
-fn gen_arg_enum_possible_values(ty: &Type) -> TokenStream {
+fn gen_value_enum_possible_values(ty: &Type) -> TokenStream {
     quote_spanned! { ty.span()=>
-        .possible_values(<#ty as clap::ArgEnum>::value_variants().iter().filter_map(clap::ArgEnum::to_possible_value))
+        .possible_values(<#ty as clap::ValueEnum>::value_variants().iter().filter_map(clap::ValueEnum::to_possible_value))
     }
 }
 
@@ -398,7 +504,7 @@ pub fn gen_constructor(fields: &Punctuat
                         quote_spanned! { kind.span()=>
                             #field_name: {
                                 if #arg_matches.subcommand_name().map(<#subcmd_type as clap::Subcommand>::has_subcommand).unwrap_or(false) {
-                                    Some(<#subcmd_type as clap::FromArgMatches>::from_arg_matches(#arg_matches)?)
+                                    Some(<#subcmd_type as clap::FromArgMatches>::from_arg_matches_mut(#arg_matches)?)
                                 } else {
                                     None
                                 }
@@ -408,7 +514,7 @@ pub fn gen_constructor(fields: &Punctuat
                     _ => {
                         quote_spanned! { kind.span()=>
                             #field_name: {
-                                <#subcmd_type as clap::FromArgMatches>::from_arg_matches(#arg_matches)?
+                                <#subcmd_type as clap::FromArgMatches>::from_arg_matches_mut(#arg_matches)?
                             }
                         }
                     },
@@ -416,7 +522,7 @@ pub fn gen_constructor(fields: &Punctuat
             }
 
             Kind::Flatten => quote_spanned! { kind.span()=>
-                #field_name: clap::FromArgMatches::from_arg_matches(#arg_matches)?
+                #field_name: clap::FromArgMatches::from_arg_matches_mut(#arg_matches)?
             },
 
             Kind::Skip(val) => match val {
@@ -472,7 +578,7 @@ pub fn gen_updater(
                 };
 
                 let updater = quote_spanned! { ty.span()=>
-                    <#subcmd_type as clap::FromArgMatches>::update_from_arg_matches(#field_name, #arg_matches)?;
+                    <#subcmd_type as clap::FromArgMatches>::update_from_arg_matches_mut(#field_name, #arg_matches)?;
                 };
 
                 let updater = match **ty {
@@ -480,7 +586,7 @@ pub fn gen_updater(
                         if let Some(#field_name) = #field_name.as_mut() {
                             #updater
                         } else {
-                            *#field_name = Some(<#subcmd_type as clap::FromArgMatches>::from_arg_matches(
+                            *#field_name = Some(<#subcmd_type as clap::FromArgMatches>::from_arg_matches_mut(
                                 #arg_matches
                             )?);
                         }
@@ -500,7 +606,7 @@ pub fn gen_updater(
 
             Kind::Flatten => quote_spanned! { kind.span()=> {
                     #access
-                    clap::FromArgMatches::update_from_arg_matches(#field_name, #arg_matches)?;
+                    clap::FromArgMatches::update_from_arg_matches_mut(#field_name, #arg_matches)?;
                 }
             },
 
@@ -524,87 +630,102 @@ fn gen_parsers(
 ) -> TokenStream {
     use self::ParserKind::*;
 
-    let parser = attrs.parser();
+    let parser = attrs.parser(&field.ty);
     let func = &parser.func;
     let span = parser.kind.span();
-    let convert_type = inner_type(**ty, &field.ty);
-    let name = attrs.cased_name();
-    let (value_of, values_of, mut parse) = match *parser.kind {
+    let convert_type = inner_type(&field.ty);
+    let id = attrs.id();
+    let mut flag = false;
+    let mut occurrences = false;
+    let (get_one, get_many, deref, mut parse) = match *parser.kind {
+        _ if attrs.ignore_parser() => (
+            quote_spanned!(span=> remove_one::<#convert_type>),
+            quote_spanned!(span=> remove_many::<#convert_type>),
+            quote!(|s| s),
+            quote_spanned!(func.span()=> |s| ::std::result::Result::Ok::<_, clap::Error>(s)),
+        ),
+        FromOccurrences => {
+            occurrences = true;
+            (
+                quote_spanned!(span=> occurrences_of),
+                quote!(),
+                quote!(|s| ::std::ops::Deref::deref(s)),
+                func.clone(),
+            )
+        }
+        FromFlag => {
+            flag = true;
+            (
+                quote!(),
+                quote!(),
+                quote!(|s| ::std::ops::Deref::deref(s)),
+                func.clone(),
+            )
+        }
         FromStr => (
-            quote_spanned!(span=> value_of),
-            quote_spanned!(span=> values_of),
+            quote_spanned!(span=> get_one::<String>),
+            quote_spanned!(span=> get_many::<String>),
+            quote!(|s| ::std::ops::Deref::deref(s)),
             quote_spanned!(func.span()=> |s| ::std::result::Result::Ok::<_, clap::Error>(#func(s))),
         ),
         TryFromStr => (
-            quote_spanned!(span=> value_of),
-            quote_spanned!(span=> values_of),
-            quote_spanned!(func.span()=> |s| #func(s).map_err(|err| clap::Error::raw(clap::ErrorKind::ValueValidation, format!("Invalid value for {}: {}", #name, err)))),
+            quote_spanned!(span=> get_one::<String>),
+            quote_spanned!(span=> get_many::<String>),
+            quote!(|s| ::std::ops::Deref::deref(s)),
+            quote_spanned!(func.span()=> |s| #func(s).map_err(|err| clap::Error::raw(clap::ErrorKind::ValueValidation, format!("Invalid value for {}: {}", #id, err)))),
         ),
         FromOsStr => (
-            quote_spanned!(span=> value_of_os),
-            quote_spanned!(span=> values_of_os),
+            quote_spanned!(span=> get_one::<::std::ffi::OsString>),
+            quote_spanned!(span=> get_many::<::std::ffi::OsString>),
+            quote!(|s| ::std::ops::Deref::deref(s)),
             quote_spanned!(func.span()=> |s| ::std::result::Result::Ok::<_, clap::Error>(#func(s))),
         ),
         TryFromOsStr => (
-            quote_spanned!(span=> value_of_os),
-            quote_spanned!(span=> values_of_os),
-            quote_spanned!(func.span()=> |s| #func(s).map_err(|err| clap::Error::raw(clap::ErrorKind::ValueValidation, format!("Invalid value for {}: {}", #name, err)))),
+            quote_spanned!(span=> get_one::<::std::ffi::OsString>),
+            quote_spanned!(span=> get_many::<::std::ffi::OsString>),
+            quote!(|s| ::std::ops::Deref::deref(s)),
+            quote_spanned!(func.span()=> |s| #func(s).map_err(|err| clap::Error::raw(clap::ErrorKind::ValueValidation, format!("Invalid value for {}: {}", #id, err)))),
         ),
-        FromOccurrences => (
-            quote_spanned!(span=> occurrences_of),
-            quote!(),
-            func.clone(),
-        ),
-        FromFlag => (quote!(), quote!(), func.clone()),
     };
-    if attrs.is_enum() {
+    if attrs.is_enum() && !attrs.ignore_parser() {
         let ci = attrs.ignore_case();
 
         parse = quote_spanned! { convert_type.span()=>
-            |s| <#convert_type as clap::ArgEnum>::from_str(s, #ci).map_err(|err| clap::Error::raw(clap::ErrorKind::ValueValidation, format!("Invalid value for {}: {}", #name, err)))
+            |s| <#convert_type as clap::ValueEnum>::from_str(s, #ci).map_err(|err| clap::Error::raw(clap::ErrorKind::ValueValidation, format!("Invalid value for {}: {}", #id, err)))
         }
     }
 
-    let flag = *attrs.parser().kind == ParserKind::FromFlag;
-    let occurrences = *attrs.parser().kind == ParserKind::FromOccurrences;
     // Give this identifier the same hygiene
     // as the `arg_matches` parameter definition. This
     // allows us to refer to `arg_matches` within a `quote_spanned` block
     let arg_matches = format_ident!("__clap_arg_matches");
 
     let field_value = match **ty {
-        Ty::Bool => {
-            if update.is_some() {
-                quote_spanned! { ty.span()=>
-                    *#field_name || #arg_matches.is_present(#name)
-                }
-            } else {
-                quote_spanned! { ty.span()=>
-                    #arg_matches.is_present(#name)
-                }
-            }
-        }
-
         Ty::Option => {
             quote_spanned! { ty.span()=>
-                #arg_matches.#value_of(#name)
+                #arg_matches.#get_one(#id)
+                    .map(#deref)
                     .map(#parse)
                     .transpose()?
             }
         }
 
         Ty::OptionOption => quote_spanned! { ty.span()=>
-            if #arg_matches.is_present(#name) {
-                Some(#arg_matches.#value_of(#name).map(#parse).transpose()?)
+            if #arg_matches.contains_id(#id) {
+                Some(
+                    #arg_matches.#get_one(#id)
+                        .map(#deref)
+                        .map(#parse).transpose()?
+                )
             } else {
                 None
             }
         },
 
         Ty::OptionVec => quote_spanned! { ty.span()=>
-            if #arg_matches.is_present(#name) {
-                Some(#arg_matches.#values_of(#name)
-                    .map(|v| v.map::<::std::result::Result<#convert_type, clap::Error>, _>(#parse).collect::<::std::result::Result<Vec<_>, clap::Error>>())
+            if #arg_matches.contains_id(#id) {
+                Some(#arg_matches.#get_many(#id)
+                    .map(|v| v.map(#deref).map::<::std::result::Result<#convert_type, clap::Error>, _>(#parse).collect::<::std::result::Result<Vec<_>, clap::Error>>())
                     .transpose()?
                     .unwrap_or_else(Vec::new))
             } else {
@@ -614,25 +735,36 @@ fn gen_parsers(
 
         Ty::Vec => {
             quote_spanned! { ty.span()=>
-                #arg_matches.#values_of(#name)
-                    .map(|v| v.map::<::std::result::Result<#convert_type, clap::Error>, _>(#parse).collect::<::std::result::Result<Vec<_>, clap::Error>>())
+                #arg_matches.#get_many(#id)
+                    .map(|v| v.map(#deref).map::<::std::result::Result<#convert_type, clap::Error>, _>(#parse).collect::<::std::result::Result<Vec<_>, clap::Error>>())
                     .transpose()?
                     .unwrap_or_else(Vec::new)
             }
         }
 
         Ty::Other if occurrences => quote_spanned! { ty.span()=>
-            #parse(#arg_matches.#value_of(#name))
+            #parse(
+                #arg_matches.#get_one(#id)
+            )
         },
 
-        Ty::Other if flag => quote_spanned! { ty.span()=>
-            #parse(#arg_matches.is_present(#name))
-        },
+        Ty::Other if flag => {
+            if update.is_some() && is_simple_ty(&field.ty, "bool") {
+                quote_spanned! { ty.span()=>
+                    *#field_name || #arg_matches.is_present(#id)
+                }
+            } else {
+                quote_spanned! { ty.span()=>
+                    #parse(#arg_matches.is_present(#id))
+                }
+            }
+        }
 
         Ty::Other => {
             quote_spanned! { ty.span()=>
-                #arg_matches.#value_of(#name)
-                    .ok_or_else(|| clap::Error::raw(clap::ErrorKind::MissingRequiredArgument, format!("The following required argument was not provided: {}", #name)))
+                #arg_matches.#get_one(#id)
+                    .map(#deref)
+                    .ok_or_else(|| clap::Error::raw(clap::ErrorKind::MissingRequiredArgument, format!("The following required argument was not provided: {}", #id)))
                     .and_then(#parse)?
             }
         }
@@ -640,7 +772,7 @@ fn gen_parsers(
 
     if let Some(access) = update {
         quote_spanned! { field.span()=>
-            if #arg_matches.is_present(#name) {
+            if #arg_matches.contains_id(#id) {
                 #access
                 *#field_name = #field_value
             }
@@ -649,3 +781,16 @@ fn gen_parsers(
         quote_spanned!(field.span()=> #field_name: #field_value )
     }
 }
+
+#[cfg(feature = "raw-deprecated")]
+pub fn raw_deprecated() -> TokenStream {
+    quote! {}
+}
+
+#[cfg(not(feature = "raw-deprecated"))]
+pub fn raw_deprecated() -> TokenStream {
+    quote! {
+        #![allow(deprecated)]  // Assuming any deprecation in here will be related to a deprecation in `Args`
+
+    }
+}
diff -pruN 3.1.7-1/src/derives/mod.rs 3.2.15-1/src/derives/mod.rs
--- 3.1.7-1/src/derives/mod.rs	1973-11-29 21:33:09.000000000 +0000
+++ 3.2.15-1/src/derives/mod.rs	1973-11-29 21:33:09.000000000 +0000
@@ -11,13 +11,13 @@
 // This work was derived from Structopt (https://github.com/TeXitoi/structopt)
 // commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the
 // MIT/Apache 2.0 license.
-mod arg_enum;
 mod args;
 mod into_app;
 mod parser;
 mod subcommand;
+mod value_enum;
 
 pub use self::parser::derive_parser;
-pub use arg_enum::derive_arg_enum;
 pub use args::derive_args;
 pub use subcommand::derive_subcommand;
+pub use value_enum::derive_value_enum;
diff -pruN 3.1.7-1/src/derives/subcommand.rs 3.2.15-1/src/derives/subcommand.rs
--- 3.1.7-1/src/derives/subcommand.rs	1973-11-29 21:33:09.000000000 +0000
+++ 3.2.15-1/src/derives/subcommand.rs	1973-11-29 21:33:09.000000000 +0000
@@ -122,7 +122,15 @@ fn gen_from_arg_matches_for_enum(
         )]
         #[deny(clippy::correctness)]
         impl #impl_generics clap::FromArgMatches for #name #ty_generics #where_clause {
+            fn from_arg_matches(__clap_arg_matches: &clap::ArgMatches) -> ::std::result::Result<Self, clap::Error> {
+                Self::from_arg_matches_mut(&mut __clap_arg_matches.clone())
+            }
+
             #from_arg_matches
+
+            fn update_from_arg_matches(&mut self, __clap_arg_matches: &clap::ArgMatches) -> ::std::result::Result<(), clap::Error> {
+                self.update_from_arg_matches_mut(&mut __clap_arg_matches.clone())
+            }
             #update_from_arg_matches
         }
     }
@@ -400,7 +408,7 @@ fn gen_from_arg_matches(
     let mut ext_subcmd = None;
 
     let subcommand_name_var = format_ident!("__clap_name");
-    let sub_arg_matches_var = format_ident!("__clap_sub_arg_matches");
+    let sub_arg_matches_var = format_ident!("__clap_arg_matches");
     let (flatten_variants, variants): (Vec<_>, Vec<_>) = variants
         .iter()
         .filter_map(|variant| {
@@ -430,20 +438,12 @@ fn gen_from_arg_matches(
                     ),
                 };
 
-                let (span, str_ty, values_of) = match subty_if_name(ty, "Vec") {
+                let (span, str_ty) = match subty_if_name(ty, "Vec") {
                     Some(subty) => {
                         if is_simple_ty(subty, "String") {
-                            (
-                                subty.span(),
-                                quote!(::std::string::String),
-                                quote!(values_of),
-                            )
+                            (subty.span(), quote!(::std::string::String))
                         } else if is_simple_ty(subty, "OsString") {
-                            (
-                                subty.span(),
-                                quote!(::std::ffi::OsString),
-                                quote!(values_of_os),
-                            )
+                            (subty.span(), quote!(::std::ffi::OsString))
                         } else {
                             abort!(
                                 ty.span(),
@@ -460,7 +460,7 @@ fn gen_from_arg_matches(
                     ),
                 };
 
-                ext_subcmd = Some((span, &variant.ident, str_ty, values_of));
+                ext_subcmd = Some((span, &variant.ident, str_ty));
                 None
             } else {
                 Some((variant, attrs))
@@ -479,14 +479,22 @@ fn gen_from_arg_matches(
             Unit => quote!(),
             Unnamed(ref fields) if fields.unnamed.len() == 1 => {
                 let ty = &fields.unnamed[0];
-                quote!( ( <#ty as clap::FromArgMatches>::from_arg_matches(__clap_arg_matches)? ) )
+                quote!( ( <#ty as clap::FromArgMatches>::from_arg_matches_mut(__clap_arg_matches)? ) )
             }
             Unnamed(..) => abort_call_site!("{}: tuple enums are not supported", variant.ident),
         };
 
-        quote! {
-            if #sub_name == #subcommand_name_var {
-                return ::std::result::Result::Ok(#name :: #variant_name #constructor_block)
+        if cfg!(feature = "unstable-v4") {
+            quote! {
+                if #sub_name == #subcommand_name_var && !#sub_arg_matches_var.contains_id("") {
+                    return ::std::result::Result::Ok(#name :: #variant_name #constructor_block)
+                }
+            }
+        } else {
+            quote! {
+                if #sub_name == #subcommand_name_var {
+                    return ::std::result::Result::Ok(#name :: #variant_name #constructor_block)
+                }
             }
         }
     });
@@ -496,8 +504,12 @@ fn gen_from_arg_matches(
             Unnamed(ref fields) if fields.unnamed.len() == 1 => {
                 let ty = &fields.unnamed[0];
                 quote! {
-                    if <#ty as clap::Subcommand>::has_subcommand(__clap_name) {
-                        let __clap_res = <#ty as clap::FromArgMatches>::from_arg_matches(__clap_arg_matches)?;
+                    if __clap_arg_matches
+                        .subcommand_name()
+                        .map(|__clap_name| <#ty as clap::Subcommand>::has_subcommand(__clap_name))
+                        .unwrap_or_default()
+                    {
+                        let __clap_res = <#ty as clap::FromArgMatches>::from_arg_matches_mut(__clap_arg_matches)?;
                         return ::std::result::Result::Ok(#name :: #variant_name (__clap_res));
                     }
                 }
@@ -510,11 +522,14 @@ fn gen_from_arg_matches(
     });
 
     let wildcard = match ext_subcmd {
-        Some((span, var_name, str_ty, values_of)) => quote_spanned! { span=>
+        Some((span, var_name, str_ty)) => quote_spanned! { span=>
                 ::std::result::Result::Ok(#name::#var_name(
                     ::std::iter::once(#str_ty::from(#subcommand_name_var))
                     .chain(
-                        #sub_arg_matches_var.#values_of("").into_iter().flatten().map(#str_ty::from)
+                        #sub_arg_matches_var
+                            .remove_many::<#str_ty>("")
+                            .into_iter().flatten()  // `""` isn't present, bug in `unstable-v4`
+                            .map(#str_ty::from)
                     )
                     .collect::<::std::vec::Vec<_>>()
                 ))
@@ -525,15 +540,16 @@ fn gen_from_arg_matches(
         },
     };
 
+    let raw_deprecated = args::raw_deprecated();
     quote! {
-        fn from_arg_matches(__clap_arg_matches: &clap::ArgMatches) -> ::std::result::Result<Self, clap::Error> {
-            if let Some((#subcommand_name_var, #sub_arg_matches_var)) = __clap_arg_matches.subcommand() {
-                {
-                    let __clap_arg_matches = #sub_arg_matches_var;
-                    #( #subcommands )*
-                }
+        fn from_arg_matches_mut(__clap_arg_matches: &mut clap::ArgMatches) -> ::std::result::Result<Self, clap::Error> {
+            #raw_deprecated
 
-                #( #child_subcommands )else*
+            #( #child_subcommands )else*
+
+            if let Some((#subcommand_name_var, mut __clap_arg_sub_matches)) = __clap_arg_matches.remove_subcommand() {
+                let #sub_arg_matches_var = &mut __clap_arg_sub_matches;
+                #( #subcommands )*
 
                 #wildcard
             } else {
@@ -560,7 +576,7 @@ fn gen_update_from_arg_matches(
             );
 
             match &*attrs.kind() {
-                // Fallback to `from_arg_matches`
+                // Fallback to `from_arg_matches_mut`
                 Kind::ExternalSubcommand => None,
                 _ => Some((variant, attrs)),
             }
@@ -598,9 +614,9 @@ fn gen_update_from_arg_matches(
                 if fields.unnamed.len() == 1 {
                     (
                         quote!((ref mut __clap_arg)),
-                        quote!(clap::FromArgMatches::update_from_arg_matches(
+                        quote!(clap::FromArgMatches::update_from_arg_matches_mut(
                             __clap_arg,
-                            __clap_sub_arg_matches
+                            __clap_arg_matches
                         )?),
                     )
                 } else {
@@ -611,7 +627,8 @@ fn gen_update_from_arg_matches(
 
         quote! {
             #name :: #variant_name #pattern if #sub_name == __clap_name => {
-                let __clap_arg_matches = __clap_sub_arg_matches;
+                let (_, mut __clap_arg_sub_matches) = __clap_arg_matches.remove_subcommand().unwrap();
+                let __clap_arg_matches = &mut __clap_arg_sub_matches;
                 #updater
             }
         }
@@ -625,7 +642,7 @@ fn gen_update_from_arg_matches(
                 quote! {
                     if <#ty as clap::Subcommand>::has_subcommand(__clap_name) {
                         if let #name :: #variant_name (child) = s {
-                            <#ty as clap::FromArgMatches>::update_from_arg_matches(child, __clap_arg_matches)?;
+                            <#ty as clap::FromArgMatches>::update_from_arg_matches_mut(child, __clap_arg_matches)?;
                             return ::std::result::Result::Ok(());
                         }
                     }
@@ -638,17 +655,20 @@ fn gen_update_from_arg_matches(
         }
     });
 
+    let raw_deprecated = args::raw_deprecated();
     quote! {
-        fn update_from_arg_matches<'b>(
+        fn update_from_arg_matches_mut<'b>(
             &mut self,
-            __clap_arg_matches: &clap::ArgMatches,
+            __clap_arg_matches: &mut clap::ArgMatches,
         ) -> ::std::result::Result<(), clap::Error> {
-            if let Some((__clap_name, __clap_sub_arg_matches)) = __clap_arg_matches.subcommand() {
+            #raw_deprecated
+
+            if let Some(__clap_name) = __clap_arg_matches.subcommand_name() {
                 match self {
                     #( #subcommands ),*
                     s => {
                         #( #child_subcommands )*
-                        *s = <Self as clap::FromArgMatches>::from_arg_matches(__clap_arg_matches)?;
+                        *s = <Self as clap::FromArgMatches>::from_arg_matches_mut(__clap_arg_matches)?;
                     }
                 }
             }
diff -pruN 3.1.7-1/src/derives/value_enum.rs 3.2.15-1/src/derives/value_enum.rs
--- 3.1.7-1/src/derives/value_enum.rs	1970-01-01 00:00:00.000000000 +0000
+++ 3.2.15-1/src/derives/value_enum.rs	1973-11-29 21:33:09.000000000 +0000
@@ -0,0 +1,124 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
+// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
+// Ana Hobden (@hoverbear) <operator@hoverbear.org>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use crate::{
+    attrs::{Attrs, Kind, Name, DEFAULT_CASING, DEFAULT_ENV_CASING},
+    dummies,
+    utils::Sp,
+};
+
+use proc_macro2::{Span, TokenStream};
+use proc_macro_error::{abort, abort_call_site};
+use quote::quote;
+use quote::quote_spanned;
+use syn::{
+    punctuated::Punctuated, spanned::Spanned, token::Comma, Attribute, Data, DataEnum, DeriveInput,
+    Fields, Ident, Variant,
+};
+
+pub fn derive_value_enum(input: &DeriveInput) -> TokenStream {
+    let ident = &input.ident;
+
+    dummies::value_enum(ident);
+
+    match input.data {
+        Data::Enum(ref e) => gen_for_enum(ident, &input.attrs, e),
+        _ => abort_call_site!("`#[derive(ValueEnum)]` only supports enums"),
+    }
+}
+
+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 lits = lits(&e.variants, &attrs);
+    let value_variants = gen_value_variants(&lits);
+    let to_possible_value = gen_to_possible_value(&lits);
+
+    quote! {
+        #[allow(dead_code, unreachable_code, unused_variables, unused_braces)]
+        #[allow(
+            clippy::style,
+            clippy::complexity,
+            clippy::pedantic,
+            clippy::restriction,
+            clippy::perf,
+            clippy::deprecated,
+            clippy::nursery,
+            clippy::cargo,
+            clippy::suspicious_else_formatting,
+        )]
+        #[deny(clippy::correctness)]
+        impl clap::ValueEnum for #name {
+            #value_variants
+            #to_possible_value
+        }
+    }
+}
+
+fn lits(
+    variants: &Punctuated<Variant, Comma>,
+    parent_attribute: &Attrs,
+) -> Vec<(TokenStream, Ident)> {
+    variants
+        .iter()
+        .filter_map(|variant| {
+            let attrs = Attrs::from_value_enum_variant(
+                variant,
+                parent_attribute.casing(),
+                parent_attribute.env_casing(),
+            );
+            if let Kind::Skip(_) = &*attrs.kind() {
+                None
+            } else {
+                if !matches!(variant.fields, Fields::Unit) {
+                    abort!(variant.span(), "`#[derive(ValueEnum)]` only supports non-unit variants, unless they are skipped");
+                }
+                let fields = attrs.field_methods(false);
+                let name = attrs.cased_name();
+                Some((
+                    quote_spanned! { variant.span()=>
+                        clap::PossibleValue::new(#name)
+                        #fields
+                    },
+                    variant.ident.clone(),
+                ))
+            }
+        })
+        .collect::<Vec<_>>()
+}
+
+fn gen_value_variants(lits: &[(TokenStream, Ident)]) -> TokenStream {
+    let lit = lits.iter().map(|l| &l.1).collect::<Vec<_>>();
+
+    quote! {
+        fn value_variants<'a>() -> &'a [Self]{
+            &[#(Self::#lit),*]
+        }
+    }
+}
+
+fn gen_to_possible_value(lits: &[(TokenStream, Ident)]) -> TokenStream {
+    let (lit, variant): (Vec<TokenStream>, Vec<Ident>) = lits.iter().cloned().unzip();
+
+    quote! {
+        fn to_possible_value<'a>(&self) -> ::std::option::Option<clap::PossibleValue<'a>> {
+            match self {
+                #(Self::#variant => Some(#lit),)*
+                _ => None
+            }
+        }
+    }
+}
diff -pruN 3.1.7-1/src/dummies.rs 3.2.15-1/src/dummies.rs
--- 3.1.7-1/src/dummies.rs	1973-11-29 21:33:09.000000000 +0000
+++ 3.2.15-1/src/dummies.rs	1973-11-29 21:33:09.000000000 +0000
@@ -74,9 +74,9 @@ pub fn args(name: &Ident) {
     });
 }
 
-pub fn arg_enum(name: &Ident) {
+pub fn value_enum(name: &Ident) {
     append_dummy(quote! {
-        impl clap::ArgEnum for #name {
+        impl clap::ValueEnum for #name {
             fn value_variants<'a>() -> &'a [Self]{
                 unimplemented!()
             }
diff -pruN 3.1.7-1/src/lib.rs 3.2.15-1/src/lib.rs
--- 3.1.7-1/src/lib.rs	1973-11-29 21:33:09.000000000 +0000
+++ 3.2.15-1/src/lib.rs	1973-11-29 21:33:09.000000000 +0000
@@ -28,12 +28,20 @@ mod dummies;
 mod parse;
 mod utils;
 
-/// Generates the `ArgEnum` impl.
+/// Generates the `ValueEnum` impl.
+#[proc_macro_derive(ValueEnum, attributes(clap))]
+#[proc_macro_error]
+pub fn value_enum(input: TokenStream) -> TokenStream {
+    let input: DeriveInput = parse_macro_input!(input);
+    derives::derive_value_enum(&input).into()
+}
+
+/// Generates the `ValueEnum` impl.
 #[proc_macro_derive(ArgEnum, attributes(clap))]
 #[proc_macro_error]
 pub fn arg_enum(input: TokenStream) -> TokenStream {
     let input: DeriveInput = parse_macro_input!(input);
-    derives::derive_arg_enum(&input).into()
+    derives::derive_value_enum(&input).into()
 }
 
 /// Generates the `Parser` implementation.
diff -pruN 3.1.7-1/src/parse.rs 3.2.15-1/src/parse.rs
--- 3.1.7-1/src/parse.rs	1973-11-29 21:33:09.000000000 +0000
+++ 3.2.15-1/src/parse.rs	1973-11-29 21:33:09.000000000 +0000
@@ -26,9 +26,11 @@ pub enum ClapAttr {
     // single-identifier attributes
     Short(Ident),
     Long(Ident),
+    ValueParser(Ident),
+    Action(Ident),
     Env(Ident),
     Flatten(Ident),
-    ArgEnum(Ident),
+    ValueEnum(Ident),
     FromGlobal(Ident),
     Subcommand(Ident),
     VerbatimDocComment(Ident),
@@ -51,7 +53,9 @@ pub enum ClapAttr {
     // ident = arbitrary_expr
     NameExpr(Ident, Expr),
     DefaultValueT(Ident, Option<Expr>),
+    DefaultValuesT(Ident, Expr),
     DefaultValueOsT(Ident, Option<Expr>),
+    DefaultValuesOsT(Ident, Expr),
     NextDisplayOrder(Ident, Expr),
     NextHelpHeading(Ident, Expr),
     HelpHeading(Ident, Expr),
@@ -120,7 +124,9 @@ impl Parse for ClapAttr {
                     Ok(expr) => match &*name_str {
                         "skip" => Ok(Skip(name, Some(expr))),
                         "default_value_t" => Ok(DefaultValueT(name, Some(expr))),
+                        "default_values_t" => Ok(DefaultValuesT(name, expr)),
                         "default_value_os_t" => Ok(DefaultValueOsT(name, Some(expr))),
+                        "default_values_os_t" => Ok(DefaultValuesOsT(name, expr)),
                         "next_display_order" => Ok(NextDisplayOrder(name, expr)),
                         "next_help_heading" => Ok(NextHelpHeading(name, expr)),
                         "help_heading" => Ok(HelpHeading(name, expr)),
@@ -182,9 +188,12 @@ impl Parse for ClapAttr {
             match name_str.as_ref() {
                 "long" => Ok(Long(name)),
                 "short" => Ok(Short(name)),
+                "value_parser" => Ok(ValueParser(name)),
+                "action" => Ok(Action(name)),
                 "env" => Ok(Env(name)),
                 "flatten" => Ok(Flatten(name)),
-                "arg_enum" => Ok(ArgEnum(name)),
+                "arg_enum" => Ok(ValueEnum(name)),
+                "value_enum" => Ok(ValueEnum(name)),
                 "from_global" => Ok(FromGlobal(name)),
                 "subcommand" => Ok(Subcommand(name)),
                 "external_subcommand" => Ok(ExternalSubcommand(name)),
diff -pruN 3.1.7-1/src/utils/ty.rs 3.2.15-1/src/utils/ty.rs
--- 3.1.7-1/src/utils/ty.rs	1973-11-29 21:33:09.000000000 +0000
+++ 3.2.15-1/src/utils/ty.rs	1973-11-29 21:33:09.000000000 +0000
@@ -9,7 +9,6 @@ use syn::{
 
 #[derive(Copy, Clone, PartialEq, Debug)]
 pub enum Ty {
-    Bool,
     Vec,
     Option,
     OptionOption,
@@ -22,9 +21,7 @@ impl Ty {
         use self::Ty::*;
         let t = |kind| Sp::new(kind, ty.span());
 
-        if is_simple_ty(ty, "bool") {
-            t(Bool)
-        } else if is_generic_ty(ty, "Vec") {
+        if is_generic_ty(ty, "Vec") {
             t(Vec)
         } else if let Some(subty) = subty_if_name(ty, "Option") {
             if is_generic_ty(subty, "Option") {
@@ -40,8 +37,9 @@ impl Ty {
     }
 }
 
-pub fn inner_type(ty: Ty, field_ty: &syn::Type) -> &syn::Type {
-    match ty {
+pub fn inner_type(field_ty: &syn::Type) -> &syn::Type {
+    let ty = Ty::from_syn_ty(field_ty);
+    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)
