@@ -55,6 +55,15 @@ impl OverrideFile {
5555 fn is_empty ( & self ) -> bool {
5656 self . toolchain . is_empty ( )
5757 }
58+
59+ fn has_toolchain ( & self ) -> bool {
60+ self . toolchain . has_toolchain ( )
61+ }
62+
63+ /// A left-biased merge of two [`OverrideFile`]s.
64+ fn merge ( & mut self , other : Self ) {
65+ self . toolchain . merge ( other. toolchain )
66+ }
5867}
5968
6069#[ derive( Debug , Default , Deserialize , PartialEq , Eq ) ]
@@ -69,9 +78,33 @@ struct ToolchainSection {
6978impl ToolchainSection {
7079 fn is_empty ( & self ) -> bool {
7180 self . channel . is_none ( )
81+ && self . path . is_none ( )
7282 && self . components . is_none ( )
7383 && self . targets . is_none ( )
74- && self . path . is_none ( )
84+ }
85+
86+ fn has_toolchain ( & self ) -> bool {
87+ self . channel . is_some ( ) || self . path . is_some ( )
88+ }
89+
90+ /// A left-biased merge of two [`ToolchainSelection`]s.
91+ ///
92+ /// If a field appears in both operands, the one from the left-hand side is selected.
93+ fn merge ( & mut self , other : Self ) {
94+ if !self . has_toolchain ( ) {
95+ // `channel` and `path` are mutually exclusive, so they need to be updated together,
96+ // and this will happen only if `self` doesn't have a toolchain yet.
97+ ( self . channel , self . path ) = ( other. channel , other. path ) ;
98+ }
99+ if self . components . is_none ( ) {
100+ self . components = other. components ;
101+ }
102+ if self . targets . is_none ( ) {
103+ self . targets = other. targets ;
104+ }
105+ if self . profile . is_none ( ) {
106+ self . profile = other. profile ;
107+ }
75108 }
76109}
77110
@@ -96,6 +129,7 @@ impl<T: Into<String>> From<T> for OverrideFile {
96129 }
97130}
98131
132+ /// The reason for which the toolchain is overridden.
99133#[ derive( Debug ) ]
100134pub ( crate ) enum OverrideReason {
101135 Environment ,
@@ -453,31 +487,46 @@ impl Cfg {
453487 }
454488
455489 fn find_override_config ( & self , path : & Path ) -> Result < Option < ( OverrideCfg , OverrideReason ) > > {
456- let mut override_ = None ;
490+ let mut override_ = None :: < ( OverrideFile , OverrideReason ) > ;
491+
492+ let mut update_override = |file, reason| {
493+ if let Some ( ( file1, reason1) ) = & mut override_ {
494+ if file1. has_toolchain ( ) {
495+ // Update the reason only if the override file has a toolchain.
496+ * reason1 = reason
497+ }
498+ file1. merge ( file) ;
499+ } else {
500+ override_ = Some ( ( file, reason) )
501+ } ;
502+ } ;
503+
504+ // Check for all possible toolchain overrides below...
505+ // See: <https://rust-lang.github.io/rustup/overrides.html>
457506
458- // First check toolchain override from command
507+ // 1. Check toolchain override from command
459508 if let Some ( ref name) = self . toolchain_override {
460- override_ = Some ( ( name. to_string ( ) . into ( ) , OverrideReason :: CommandLine ) ) ;
509+ update_override ( name. to_string ( ) . into ( ) , OverrideReason :: CommandLine ) ;
461510 }
462511
463- // Check RUSTUP_TOOLCHAIN
512+ // 2. Check RUSTUP_TOOLCHAIN
464513 if let Some ( ref name) = self . env_override {
465514 // Because path based toolchain files exist, this has to support
466515 // custom, distributable, and absolute path toolchains otherwise
467516 // rustup's export of a RUSTUP_TOOLCHAIN when running a process will
468517 // error when a nested rustup invocation occurs
469- override_ = Some ( ( name. to_string ( ) . into ( ) , OverrideReason :: Environment ) ) ;
518+ update_override ( name. to_string ( ) . into ( ) , OverrideReason :: Environment ) ;
470519 }
471520
472- // Then walk up the directory tree from 'path' looking for either the
473- // directory in override database, or a `rust-toolchain` file.
474- if override_ . is_none ( ) {
475- self . settings_file . with ( |s| {
476- override_ = self . find_override_from_dir_walk ( path, s) ?;
477-
478- Ok ( ( ) )
479- } ) ? ;
480- }
521+ // 3. walk up the directory tree from 'path' looking for either the
522+ // directory in override database, or
523+ // 4. a `rust-toolchain` file.
524+ self . settings_file . with ( |s| {
525+ if let Some ( ( file , reason ) ) = self . find_override_from_dir_walk ( path, s) ? {
526+ update_override ( file , reason ) ;
527+ }
528+ Ok ( ( ) )
529+ } ) ? ;
481530
482531 if let Some ( ( file, reason) ) = override_ {
483532 // This is hackishly using the error chain to provide a bit of
0 commit comments