@@ -228,8 +228,10 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send))
228228
229229 let args = args:: arg_expand_all( & default_early_dcx, at_args) ;
230230
231- let Some ( matches) = handle_options( & default_early_dcx, & args) else {
232- return ;
231+ let ( matches, help_only) = match handle_options( & default_early_dcx, & args) {
232+ HandledOptions :: None => return ,
233+ HandledOptions :: Normal ( matches) => ( matches, false ) ,
234+ HandledOptions :: HelpOnly ( matches) => ( matches, true ) ,
233235 } ;
234236
235237 let sopts = config:: build_session_options( & mut default_early_dcx, & matches) ;
@@ -291,6 +293,11 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send))
291293 return early_exit( ) ;
292294 }
293295
296+ // We have now handled all help options, exit
297+ if help_only {
298+ return early_exit( ) ;
299+ }
300+
294301 if print_crate_info( codegen_backend, sess, has_input) == Compilation :: Stop {
295302 return early_exit( ) ;
296303 }
@@ -1092,7 +1099,7 @@ pub fn describe_flag_categories(early_dcx: &EarlyDiagCtxt, matches: &Matches) ->
10921099 // Don't handle -W help here, because we might first load additional lints.
10931100 let debug_flags = matches. opt_strs( "Z" ) ;
10941101 if debug_flags. iter( ) . any( |x| * x == "help" ) {
1095- describe_debug_flags ( ) ;
1102+ describe_unstable_flags ( ) ;
10961103 return true ;
10971104 }
10981105
@@ -1131,8 +1138,8 @@ fn get_backend_from_raw_matches(
11311138 get_codegen_backend( early_dcx, & sysroot, backend_name, & target)
11321139}
11331140
1134- fn describe_debug_flags ( ) {
1135- safe_println!( "\n Available options:\n " ) ;
1141+ fn describe_unstable_flags ( ) {
1142+ safe_println!( "\n Available unstable options:\n " ) ;
11361143 print_flag_list( "-Z" , config:: Z_OPTIONS ) ;
11371144}
11381145
@@ -1156,6 +1163,16 @@ fn print_flag_list<T>(cmdline_opt: &str, flag_list: &[OptionDesc<T>]) {
11561163 }
11571164}
11581165
1166+ pub enum HandledOptions {
1167+ /// Parsing failed, or we parsed a flag causing an early exit
1168+ None ,
1169+ /// Successful parsing
1170+ Normal ( getopts:: Matches ) ,
1171+ /// Parsing succeeded, but we received one or more 'help' flags
1172+ /// The compiler should proceed only until a possible `-W help` flag has been processed
1173+ HelpOnly ( getopts:: Matches ) ,
1174+ }
1175+
11591176/// Process command line options. Emits messages as appropriate. If compilation
11601177/// should continue, returns a getopts::Matches object parsed from args,
11611178/// otherwise returns `None`.
@@ -1183,7 +1200,7 @@ fn print_flag_list<T>(cmdline_opt: &str, flag_list: &[OptionDesc<T>]) {
11831200/// This does not need to be `pub` for rustc itself, but @chaosite needs it to
11841201/// be public when using rustc as a library, see
11851202/// <https://github.com/rust-lang/rust/commit/2b4c33817a5aaecabf4c6598d41e190080ec119e>
1186- pub fn handle_options( early_dcx: & EarlyDiagCtxt , args: & [ String ] ) -> Option <getopts :: Matches > {
1203+ pub fn handle_options( early_dcx: & EarlyDiagCtxt , args: & [ String ] ) -> HandledOptions {
11871204 // Parse with *all* options defined in the compiler, we don't worry about
11881205 // option stability here we just want to parse as much as possible.
11891206 let mut options = getopts:: Options :: new( ) ;
@@ -1229,26 +1246,69 @@ pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option<geto
12291246 // (unstable option being used on stable)
12301247 nightly_options:: check_nightly_options( early_dcx, & matches, & config:: rustc_optgroups( ) ) ;
12311248
1232- if args. is_empty( ) || matches. opt_present( "h" ) || matches. opt_present( "help" ) {
1233- // Only show unstable options in --help if we accept unstable options.
1234- let unstable_enabled = nightly_options:: is_unstable_enabled( & matches) ;
1235- let nightly_build = nightly_options:: match_is_nightly_build( & matches) ;
1236- usage( matches. opt_present( "verbose" ) , unstable_enabled, nightly_build) ;
1237- return None ;
1249+ // Handle the special case of -Wall.
1250+ let wall = matches. opt_strs( "W" ) ;
1251+ if wall. iter( ) . any( |x| * x == "all" ) {
1252+ print_wall_help( ) ;
1253+ return HandledOptions :: None ;
12381254 }
12391255
1240- if describe_flag_categories( early_dcx, & matches) {
1241- return None ;
1256+ if handle_help( & matches, args) {
1257+ return HandledOptions :: HelpOnly ( matches) ;
1258+ }
1259+
1260+ if matches. opt_strs( "C" ) . iter( ) . any( |x| x == "passes=list" ) {
1261+ get_backend_from_raw_matches( early_dcx, & matches) . print_passes( ) ;
1262+ return HandledOptions :: None ;
12421263 }
12431264
12441265 if matches. opt_present( "version" ) {
12451266 version!( early_dcx, "rustc" , & matches) ;
1246- return None ;
1267+ return HandledOptions :: None ;
12471268 }
12481269
12491270 warn_on_confusing_output_filename_flag( early_dcx, & matches, args) ;
12501271
1251- Some ( matches)
1272+ HandledOptions :: Normal ( matches)
1273+ }
1274+
1275+ /// Handle help options in the order they are provided, ignoring other flags. Returns if any options were handled
1276+ /// Handled options:
1277+ /// - `-h`/`--help`/empty arguments
1278+ /// - `-Z help`
1279+ /// - `-C help`
1280+ /// NOTE: `-W help` is NOT handled here, as additional lints may be loaded.
1281+ pub fn handle_help( matches: & getopts:: Matches , args: & [ String ] ) -> bool {
1282+ let opt_pos = |opt| matches. opt_positions( opt) . first( ) . copied( ) ;
1283+ let opt_help_pos = |opt| {
1284+ matches
1285+ . opt_strs_pos( opt)
1286+ . iter( )
1287+ . filter_map( |( pos, oval) | if oval == "help" { Some ( * pos) } else { None } )
1288+ . next( )
1289+ } ;
1290+ let help_pos = if args. is_empty( ) { Some ( 0 ) } else { opt_pos( "h" ) . or_else( || opt_pos( "help" ) ) } ;
1291+ let zhelp_pos = opt_help_pos( "Z" ) ;
1292+ let chelp_pos = opt_help_pos( "C" ) ;
1293+ let print_help = || {
1294+ // Only show unstable options in --help if we accept unstable options.
1295+ let unstable_enabled = nightly_options:: is_unstable_enabled( & matches) ;
1296+ let nightly_build = nightly_options:: match_is_nightly_build( & matches) ;
1297+ usage( matches. opt_present( "verbose" ) , unstable_enabled, nightly_build) ;
1298+ } ;
1299+
1300+ let mut helps = [
1301+ ( help_pos, & print_help as & dyn Fn ( ) ) ,
1302+ ( zhelp_pos, & describe_unstable_flags) ,
1303+ ( chelp_pos, & describe_codegen_flags) ,
1304+ ] ;
1305+ helps. sort_by_key( |( pos, _) | pos. clone( ) ) ;
1306+ let mut printed_any = false ;
1307+ for printer in helps. iter( ) . filter_map( |( pos, func) | pos. is_some( ) . then_some( func) ) {
1308+ printer( ) ;
1309+ printed_any = true ;
1310+ }
1311+ printed_any
12521312}
12531313
12541314/// Warn if `-o` is used without a space between the flag name and the value
0 commit comments