Skip to content

short -h conflicts with help rather than overwriting it #3403

@steveklabnik

Description

@steveklabnik

Please complete the following tasks

  • I have searched the discussions
  • I have searched the existing issues

Rust Version

1.57.0

Clap Version

3.0.14

Minimal reproducible code

use clap::IntoApp;
use clap::Parser;

#[derive(Parser)]
#[clap(name = "command")]
pub struct Args {
    #[clap(subcommand)]
    pub cmd: Subcommand,
}

#[derive(Parser)]
pub enum Subcommand {
    #[clap(external_subcommand)]
    Other(Vec<String>),
}

#[derive(Parser)]
#[clap(name = "subcommand")]
struct SubArgs {
    #[clap(short)]
    hold: bool,
}


fn main() {
    let mut clap = Args::into_app();

    let subcmd = SubArgs::into_app();

    clap = clap.subcommand(subcmd);

    let _m = clap.get_matches();
}

Steps to reproduce the bug with the above code

cargo run -- subcommand -h

Actual Behaviour

C:\Users\steve\tmp\claptest> cargo run -- subcommand -h
   Compiling claptest v0.1.0 (C:\Users\steve\tmp\claptest)
    Finished dev [unoptimized + debuginfo] target(s) in 0.55s
     Running `target\debug\claptest.exe subcommand -h`
thread 'main' panicked at 'App subcommand: Short option names must be unique for each argument, but '-h' is in use by both 'hold' and 'help'', C:\Users\steve\.cargo\registry\src\git.colasdn.top-1ecc6299db9ec823\clap-3.0.14\src\build\app\debug_asserts.rs:100:17
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
error: process didn't exit successfully: `target\debug\claptest.exe subcommand -h` (exit code: 101)

Expected Behaviour

C:\Users\steve\tmp\claptest> cargo run -- subcommand -h
    Finished release [optimized] target(s) in 0.03s
     Running `target\release\claptest.exe subcommand -h`
claptest.exe-subcommand

USAGE:
    claptest.exe subcommand [OPTIONS]

OPTIONS:
    -h
    -h, --help    Print help information

Additional Context

[dependencies.clap]
version = "3.0.14"
features = ["derive"]

#3400 (comment)

Because this is a debug assertion that fails, running with --release gives the expected behavior, which is what initially caused this bug to go unnoticed for a while.

I know that this setup might be slightly weird, this is an app I didn't originally write and there's a comment block:

    /*
     * This isn't hugely efficient, but we actually parse our arguments
     * twice: the first is with our subcommands grafted into our
     * arguments to get us a unified help and error message in the event
     * of any parsing value or request for a help message; if that works,
     * we parse our arguments again but relying on the
     * external_subcommand to directive to allow our subcommand to do any
     * parsing on its own.
     */

I recently ported this app from structopt/clapv2 to clap v3; it's possible that this comment is now irrelevant but I haven't investigated that yet.

Debug Output

     Running `target\debug\claptest.exe subcommand -h`
[            clap::build::app]  App::_do_parse
[            clap::build::app]  App::_build
[            clap::build::app]  App::_propagate:command
[            clap::build::app]  App::_check_help_and_version
[            clap::build::app]  App::_check_help_and_version: Removing generated version
[            clap::build::app]  App::_check_help_and_version: Building help subcommand
[            clap::build::app]  App::_propagate_global_args:command
[            clap::build::app]  App::_derive_display_order:command
[            clap::build::app]  App::_derive_display_order:subcommand
[            clap::build::app]  App::_derive_display_order:help
[clap::build::app::debug_asserts]       App::_debug_asserts
[clap::build::arg::debug_asserts]       Arg::_debug_asserts:help
[clap::build::app::debug_asserts]       App::_verify_positionals
[         clap::parse::parser]  Parser::get_matches_with
[         clap::parse::parser]  Parser::get_matches_with: Begin parsing 'RawOsString("subcommand")' ([115, 117, 98, 99, 111, 109, 109, 97, 110, 100])
[         clap::parse::parser]  Parser::get_matches_with: Positional counter...1
[         clap::parse::parser]  Parser::get_matches_with: Low index multiples...false
[         clap::parse::parser]  Parser::possible_subcommand: arg=RawOsStr("subcommand")
[         clap::parse::parser]  Parser::get_matches_with: sc=Some("subcommand")
[         clap::parse::parser]  Parser::parse_subcommand
[         clap::output::usage]  Usage::get_required_usage_from: incls=[], matcher=false, incl_last=true
[         clap::output::usage]  Usage::get_required_usage_from: unrolled_reqs={}
[         clap::output::usage]  Usage::get_required_usage_from: ret_val=[]
[            clap::build::app]  App::_build
[            clap::build::app]  App::_propagate:subcommand
[            clap::build::app]  App::_check_help_and_version
[            clap::build::app]  App::_check_help_and_version: Removing generated version
[            clap::build::app]  App::_propagate_global_args:subcommand
[            clap::build::app]  App::_derive_display_order:subcommand
[clap::build::app::debug_asserts]       App::_debug_asserts
[clap::build::arg::debug_asserts]       Arg::_debug_asserts:hold
thread 'main' panicked at 'App subcommand: Short option names must be unique for each argument, but '-h' is in use by both 'hold' and 'help'', C:\Users\steve\.cargo\registry\src\git.colasdn.top-1ecc6299db9ec823\clap-3.0.14\src\build\app\debug_asserts.rs:100:17
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
error: process didn't exit successfully: `target\debug\claptest.exe subcommand -h` (exit code: 101)

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-builderArea: Builder APIC-bugCategory: bugE-mediumCall for participation: Experience needed to fix: Medium / intermediate

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions