Skip to content

Strange effect of conflicts_with_all() in clap_derive. #6248

@Barafu

Description

@Barafu

Please complete the following tasks

Rust Version

1.92.0

Clap Version

4.5.57

Minimal reproducible code

use clap::Parser;
use std::path::PathBuf;

/// Command line arguments
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
#[group(
    id = "install_uninstall",
    multiple = false,
    conflicts_with_all(["path"])
)]
struct CliArgs {
    /// Path to directory containing WAV files
    #[arg(long)]
    path: Option<PathBuf>,

    /// Dev-mode (hidden),makes app to write Pipewire config in /tmp instead of proper placement.
    #[arg(long, hide = true)]
    dev_mode: bool,

    /// Install the application to the system menu
    #[arg(long, group = "install_uninstall")]
    install: bool,

    /// Remove the application from the system menu
    #[arg(long, group = "install_uninstall")]
    uninstall: bool,
}

fn main() {
    let args = CliArgs::parse();
    println!("{:?}", args.path);
}

Steps to reproduce the bug with the above code

cargo run -- --path /tmp

Actual Behaviour

error: the argument '--path <PATH>' cannot be used with:
  --path <PATH>
  --dev-mode
  --install
  --uninstall

Usage: aaa [OPTIONS]

For more information, try '--help'.

Expected Behaviour

This use of conflicts_with_all somehow makes path argument to conflict with itself.
I expected path to be conflicting with install and uninstall

Additional Context

No response

Debug Output

cargo run -- --path /tmp
Finished dev profile [unoptimized + debuginfo] target(s) in 0.02s
Running target/debug/aaa --path /tmp
[clap_builder::builder::command]Command::_do_parse
[clap_builder::builder::command]Command::_build: name="aaa"
[clap_builder::builder::command]Command::_propagate:aaa
[clap_builder::builder::command]Command::_check_help_and_version:aaa expand_help_tree=false
[clap_builder::builder::command]Command::long_help_exists
[clap_builder::builder::command]Command::_check_help_and_version: Building default --help
[clap_builder::builder::command]Command::_check_help_and_version: Building default --version
[clap_builder::builder::command]Command::_propagate_global_args:aaa
[clap_builder::builder::debug_asserts]Command::_debug_asserts
[clap_builder::builder::debug_asserts]Arg::_debug_asserts:path
[clap_builder::builder::debug_asserts]Arg::_debug_asserts:dev_mode
[clap_builder::builder::debug_asserts]Arg::_debug_asserts:install
[clap_builder::builder::debug_asserts]Arg::_debug_asserts:uninstall
[clap_builder::builder::debug_asserts]Arg::_debug_asserts:help
[clap_builder::builder::debug_asserts]Arg::_debug_asserts:version
[clap_builder::builder::debug_asserts]Command::_verify_positionals
[clap_builder::parser::parser]Parser::get_matches_with
[clap_builder::parser::parser]Parser::parse
[clap_builder::parser::parser]Parser::get_matches_with: Begin parsing '"--path"'
[clap_builder::parser::parser]Parser::possible_subcommand: arg=Ok("--path")
[clap_builder::parser::parser]Parser::get_matches_with: sc=None
[clap_builder::parser::parser]Parser::parse_long_arg
[clap_builder::parser::parser]Parser::parse_long_arg: Does it contain '='...
[clap_builder::parser::parser]Parser::parse_long_arg: Found valid arg or flag '--path '
[clap_builder::parser::parser]Parser::parse_long_arg("path"): Found an arg with value 'None'
[clap_builder::parser::parser]Parser::parse_opt_value; arg=path, val=None, has_eq=false
[clap_builder::parser::parser]Parser::parse_opt_value; arg.settings=ArgFlags(0)
[clap_builder::parser::parser]Parser::parse_opt_value; Checking for val...
[clap_builder::parser::parser]Parser::parse_opt_value: More arg vals required...
[clap_builder::parser::parser]Parser::get_matches_with: After parse_long_arg Opt("path")
[clap_builder::parser::parser]Parser::get_matches_with: Begin parsing '"/tmp"'
[clap_builder::parser::arg_matcher]ArgMatcher::needs_more_vals: o=path, pending=1
[clap_builder::parser::arg_matcher]ArgMatcher::needs_more_vals: expected=1, actual=1
[clap_builder::parser::parser]Parser::resolve_pending: id="path"
[clap_builder::parser::parser]Parser::react action=Set, identifier=Some(Long), source=CommandLine
[clap_builder::parser::parser]Parser::react: cur_idx:=1
[clap_builder::parser::parser]Parser::remove_overrides: id="path"
[clap_builder::parser::arg_matcher]ArgMatcher::start_custom_arg: id="path", source=CommandLine
[clap_builder::builder::command]Command::groups_for_arg: id="path"
[clap_builder::parser::arg_matcher]ArgMatcher::start_custom_arg: id="install_uninstall", source=CommandLine
[clap_builder::parser::parser]Parser::push_arg_values: ["/tmp"]
[clap_builder::parser::parser]Parser::add_single_val_to_arg: cur_idx:=2
[clap_builder::parser::arg_matcher]ArgMatcher::needs_more_vals: o=path, pending=0
[clap_builder::parser::arg_matcher]ArgMatcher::needs_more_vals: expected=1, actual=0
[clap_builder::parser::parser]Parser::react not enough values passed in, leaving it to the validator to complain
[clap_builder::parser::parser]Parser::add_defaults
[clap_builder::parser::parser]Parser::add_defaults:iter:path:
[clap_builder::parser::parser]Parser::add_default_value: doesn't have conditional defaults
[clap_builder::parser::parser]Parser::add_default_value:iter:path: doesn't have default vals
[clap_builder::parser::parser]Parser::add_defaults:iter:dev_mode:
[clap_builder::parser::parser]Parser::add_default_value: doesn't have conditional defaults
[clap_builder::parser::parser]Parser::add_default_value:iter:dev_mode: has default vals
[clap_builder::parser::parser]Parser::add_default_value:iter:dev_mode: wasn't used
[clap_builder::parser::parser]Parser::react action=SetTrue, identifier=None, source=DefaultValue
[clap_builder::parser::arg_matcher]ArgMatcher::start_custom_arg: id="dev_mode", source=DefaultValue
[clap_builder::parser::parser]Parser::push_arg_values: ["false"]
[clap_builder::parser::parser]Parser::add_single_val_to_arg: cur_idx:=3
[clap_builder::parser::parser]Parser::add_defaults:iter:install:
[clap_builder::parser::parser]Parser::add_default_value: doesn't have conditional defaults
[clap_builder::parser::parser]Parser::add_default_value:iter:install: has default vals
[clap_builder::parser::parser]Parser::add_default_value:iter:install: wasn't used
[clap_builder::parser::parser]Parser::react action=SetTrue, identifier=None, source=DefaultValue
[clap_builder::parser::arg_matcher]ArgMatcher::start_custom_arg: id="install", source=DefaultValue
[clap_builder::parser::parser]Parser::push_arg_values: ["false"]
[clap_builder::parser::parser]Parser::add_single_val_to_arg: cur_idx:=4
[clap_builder::parser::parser]Parser::add_defaults:iter:uninstall:
[clap_builder::parser::parser]Parser::add_default_value: doesn't have conditional defaults
[clap_builder::parser::parser]Parser::add_default_value:iter:uninstall: has default vals
[clap_builder::parser::parser]Parser::add_default_value:iter:uninstall: wasn't used
[clap_builder::parser::parser]Parser::react action=SetTrue, identifier=None, source=DefaultValue
[clap_builder::parser::arg_matcher]ArgMatcher::start_custom_arg: id="uninstall", source=DefaultValue
[clap_builder::parser::parser]Parser::push_arg_values: ["false"]
[clap_builder::parser::parser]Parser::add_single_val_to_arg: cur_idx:=5
[clap_builder::parser::parser]Parser::add_defaults:iter:help:
[clap_builder::parser::parser]Parser::add_default_value: doesn't have conditional defaults
[clap_builder::parser::parser]Parser::add_default_value:iter:help: doesn't have default vals
[clap_builder::parser::parser]Parser::add_defaults:iter:version:
[clap_builder::parser::parser]Parser::add_default_value: doesn't have conditional defaults
[clap_builder::parser::parser]Parser::add_default_value:iter:version: doesn't have default vals
[clap_builder::parser::validator]Validator::validate
[clap_builder::builder::command]Command::groups_for_arg: id="path"
[clap_builder::parser::validator]Conflicts::gather_direct_conflicts id="path", conflicts=["path", "dev_mode", "install", "uninstall", "install", "uninstall"]
[clap_builder::parser::validator]Conflicts::gather_direct_conflicts id="install_uninstall", conflicts=["path"]
[clap_builder::parser::validator]Validator::validate_conflicts
[clap_builder::parser::validator]Validator::validate_exclusive
[clap_builder::parser::validator]Validator::validate_conflicts::iter: id="path"
[clap_builder::parser::validator]Conflicts::gather_conflicts: arg="path"
[clap_builder::parser::validator]Conflicts::gather_conflicts: conflicts=["install_uninstall"]
[clap_builder::parser::validator]Validator::build_conflict_err: name="path"
[clap_builder::builder::command]Command::unroll_args_in_group: group="install_uninstall"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="path"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="dev_mode"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="install"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="uninstall"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="install"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="uninstall"
[ clap_builder::output::usage]Usage::create_usage_with_title
[ clap_builder::output::usage]Usage::create_usage_no_title
[ clap_builder::output::usage]Usage::write_help_usage
[ clap_builder::output::usage]Usage::write_arg_usage; incl_reqs=true
[ clap_builder::output::usage]Usage::needs_options_tag
[ clap_builder::output::usage]Usage::needs_options_tag:iter: f=path
[clap_builder::builder::command]Command::groups_for_arg: id="path"
[ clap_builder::output::usage]Usage::needs_options_tag:iter:iter: grp_s="install_uninstall"
[ clap_builder::output::usage]Usage::needs_options_tag:iter: [OPTIONS] required
[ clap_builder::output::usage]Usage::write_args: incls=[]
[ clap_builder::output::usage]Usage::get_args: unrolled_reqs=[]
[ clap_builder::output::usage]Usage::write_subcommand_usage
[ clap_builder::output::usage]Usage::create_usage_with_title: usage=Usage: aaa [OPTIONS]
[clap_builder::builder::command]Command::color: Color setting...
[clap_builder::builder::command]Auto
[clap_builder::builder::command]Command::color: Color setting...
[clap_builder::builder::command]Auto
error: the argument '--path ' cannot be used with:
--path
--dev-mode
--install
--uninstall

Usage: aaa [OPTIONS]

For more information, try '--help'.

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: bugS-triageStatus: New; needs maintainer attention.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions