11use std:: collections:: { BTreeMap , BTreeSet , HashMap , HashSet } ;
22use std:: path:: { Path , PathBuf } ;
33use std:: sync:: Arc ;
4- use std:: { env, fs} ;
4+ use std:: { env, fmt , fs} ;
55
66use crate :: core:: compiler:: { CompileKind , DefaultExecutor , Executor , UnitOutput } ;
77use crate :: core:: { Dependency , Edition , Package , PackageId , SourceId , Target , Workspace } ;
@@ -14,12 +14,14 @@ use crate::util::errors::CargoResult;
1414use crate :: util:: { Filesystem , GlobalContext , Rustc } ;
1515use crate :: { drop_println, ops} ;
1616
17+ use annotate_snippets:: Level ;
1718use anyhow:: { Context as _, bail} ;
1819use cargo_util:: paths;
1920use cargo_util_schemas:: core:: PartialVersion ;
2021use itertools:: Itertools ;
2122use semver:: VersionReq ;
2223use tempfile:: Builder as TempFileBuilder ;
24+ use tracing:: debug;
2325
2426struct Transaction {
2527 bins : Vec < PathBuf > ,
@@ -39,6 +41,42 @@ impl Drop for Transaction {
3941 }
4042}
4143
44+ enum RustupToolchainSource {
45+ Default ,
46+ Environment ,
47+ CommandLine ,
48+ OverrideDB ,
49+ ToolchainFile ,
50+ Other ( String ) ,
51+ }
52+
53+ #[ allow( dead_code) ]
54+ impl RustupToolchainSource {
55+ fn is_implicit_override ( & self ) -> Option < bool > {
56+ match self {
57+ Self :: Default => Some ( false ) ,
58+ Self :: Environment => Some ( true ) ,
59+ Self :: CommandLine => Some ( false ) ,
60+ Self :: OverrideDB => Some ( true ) ,
61+ Self :: ToolchainFile => Some ( true ) ,
62+ Self :: Other ( _) => None ,
63+ }
64+ }
65+ }
66+
67+ impl fmt:: Display for RustupToolchainSource {
68+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
69+ f. write_str ( match self {
70+ Self :: Default => "default" ,
71+ Self :: Environment => "environment variable" ,
72+ Self :: CommandLine => "command line" ,
73+ Self :: OverrideDB => "rustup directory override" ,
74+ Self :: ToolchainFile => "rustup toolchain file" ,
75+ Self :: Other ( other) => other,
76+ } )
77+ }
78+ }
79+
4280struct InstallablePackage < ' gctx > {
4381 gctx : & ' gctx GlobalContext ,
4482 opts : ops:: CompileOptions ,
@@ -316,6 +354,31 @@ impl<'gctx> InstallablePackage<'gctx> {
316354 fn install_one ( mut self , dry_run : bool ) -> CargoResult < bool > {
317355 self . gctx . shell ( ) . status ( "Installing" , & self . pkg ) ?;
318356
357+ if let Some ( source) = get_rustup_toolchain_source ( )
358+ && source. is_implicit_override ( ) . unwrap_or_else ( || {
359+ debug ! ( "ignoring unrecognized rustup toolchain source `{source}`" ) ;
360+ false
361+ } )
362+ {
363+ #[ expect( clippy:: disallowed_methods, reason = "consistency with rustup" ) ]
364+ let maybe_toolchain = env:: var ( "RUSTUP_TOOLCHAIN" )
365+ . ok ( )
366+ . map ( |toolchain| format ! ( " with `{toolchain}`" ) )
367+ . unwrap_or_default ( ) ;
368+ let report = & [ Level :: WARNING
369+ . secondary_title ( format ! (
370+ "default toolchain implicitly overridden{maybe_toolchain} by {source}"
371+ ) )
372+ . element ( Level :: HELP . message ( format ! (
373+ "use `cargo +stable install` if you meant to use the stable toolchain"
374+ ) ) )
375+ . element ( Level :: NOTE . message ( format ! (
376+ "rustup selects the toolchain based on the parent environment and not the \
377+ environment of the package being installed"
378+ ) ) ) ] ;
379+ self . gctx . shell ( ) . print_report ( report, false ) ?;
380+ }
381+
319382 // Normalize to absolute path for consistency throughout.
320383 // See: https://github.com/rust-lang/cargo/issues/16023
321384 let dst = self . root . join ( "bin" ) . into_path_unlocked ( ) ;
@@ -611,6 +674,20 @@ impl<'gctx> InstallablePackage<'gctx> {
611674 }
612675}
613676
677+ fn get_rustup_toolchain_source ( ) -> Option < RustupToolchainSource > {
678+ #[ expect( clippy:: disallowed_methods, reason = "consistency with rustup" ) ]
679+ let source = std:: env:: var ( "RUSTUP_TOOLCHAIN_SOURCE" ) . ok ( ) ?;
680+ let source = match source. as_str ( ) {
681+ "default" => RustupToolchainSource :: Default ,
682+ "env" => RustupToolchainSource :: Environment ,
683+ "cli" => RustupToolchainSource :: CommandLine ,
684+ "path-override" => RustupToolchainSource :: OverrideDB ,
685+ "toolchain-file" => RustupToolchainSource :: ToolchainFile ,
686+ other => RustupToolchainSource :: Other ( other. to_owned ( ) ) ,
687+ } ;
688+ Some ( source)
689+ }
690+
614691fn make_warning_about_missing_features ( binaries : & [ & Target ] ) -> String {
615692 let max_targets_listed = 7 ;
616693 let target_features_message = binaries
0 commit comments