The documentation doesn't really talk about what the attribute does if no value is specified, so I ran some simple code through cargo-expand to see what changed if I added the attribute
You can expand the macros on the playground under Tools > Expand macros. Just add , action and re-run it if you want to see the before and after.
Looking at the diff I think the most relevant changes are in the impl clap::Args for App. The calls to required and value_parser are where the changes are in both methods. I'm not familiar enough with clap's internals to say what the precise semantic difference is, but it looks to me like adding action is opting in to newer behavior that may be breaking for some old code. Notably the StoreValue variant of ArgAction is documented as deprecated, and that's what the non-action expansion uses.
Before
#[deny(clippy::correctness)]
impl clap::Args for App {
fn augment_args<'b>(__clap_app: clap::Command<'b>) -> clap::Command<'b> {
{
let __clap_app = __clap_app;
let __clap_app = __clap_app.arg({
#[allow(deprecated)]
let arg = clap::Arg::new("value")
.takes_value(true)
.value_name("VALUE")
.required(true && clap::ArgAction::StoreValue.takes_values())
.validator(|s| ::std::str::FromStr::from_str(s).map(|_: String| ()))
.value_parser(clap::builder::ValueParser::string())
.action(clap::ArgAction::StoreValue);
let arg = arg.long("value");
arg
});
__clap_app
}
}
fn augment_args_for_update<'b>(__clap_app: clap::Command<'b>) -> clap::Command<'b> {
{
let __clap_app = __clap_app;
let __clap_app = __clap_app.arg({
#[allow(deprecated)]
let arg = clap::Arg::new("value")
.takes_value(true)
.value_name("VALUE")
.required(false && clap::ArgAction::StoreValue.takes_values())
.validator(|s| ::std::str::FromStr::from_str(s).map(|_: String| ()))
.value_parser(clap::builder::ValueParser::string())
.action(clap::ArgAction::StoreValue);
let arg = arg.long("value");
arg
});
__clap_app
}
}
}
After
#[deny(clippy::correctness)]
impl clap::Args for App {
fn augment_args<'b>(__clap_app: clap::Command<'b>) -> clap::Command<'b> {
{
let __clap_app = __clap_app;
let __clap_app = __clap_app.arg({
#[allow(deprecated)]
let arg = clap::Arg::new("value")
.takes_value(true)
.value_name("VALUE")
.required(true && clap::ArgAction::Set.takes_values())
.value_parser({
use ::clap::builder::via_prelude::*;
let auto = ::clap::builder::_AutoValueParser::<String>::new();
(&&&auto).value_parser()
})
.action(clap::ArgAction::Set);
let arg = arg.long("value");
arg
});
__clap_app
}
}
fn augment_args_for_update<'b>(__clap_app: clap::Command<'b>) -> clap::Command<'b> {
{
let __clap_app = __clap_app;
let __clap_app = __clap_app.arg({
#[allow(deprecated)]
let arg = clap::Arg::new("value")
.takes_value(true)
.value_name("VALUE")
.required(false && clap::ArgAction::Set.takes_values())
.value_parser({
use ::clap::builder::via_prelude::*;
let auto = ::clap::builder::_AutoValueParser::<String>::new();
(&&&auto).value_parser()
})
.action(clap::ArgAction::Set);
let arg = arg.long("value");
arg
});
__clap_app
}
}
}