@@ -349,7 +349,7 @@ impl SplitDebuginfo {
349
349
}
350
350
351
351
/// LTO mode used for compiling rustc itself.
352
- #[ derive( Default , Clone , PartialEq ) ]
352
+ #[ derive( Default , Clone , PartialEq , Debug ) ]
353
353
pub enum RustcLto {
354
354
Off ,
355
355
#[ default]
@@ -507,29 +507,42 @@ struct TomlConfig {
507
507
profile : Option < String > ,
508
508
}
509
509
510
+ /// Describes how to handle conflicts in merging two [`TomlConfig`]
511
+ #[ derive( Copy , Clone , Debug ) ]
512
+ enum ReplaceOpt {
513
+ /// Silently ignore a duplicated value
514
+ IgnoreDuplicate ,
515
+ /// Override the current value, even if it's `Some`
516
+ Override ,
517
+ /// Exit with an error on duplicate values
518
+ ErrorOnDuplicate ,
519
+ }
520
+
510
521
trait Merge {
511
- fn merge ( & mut self , other : Self ) ;
522
+ fn merge ( & mut self , other : Self , replace : ReplaceOpt ) ;
512
523
}
513
524
514
525
impl Merge for TomlConfig {
515
526
fn merge (
516
527
& mut self ,
517
- TomlConfig { build, install, llvm, rust, dist, target, profile : _, changelog_seen : _ } : Self ,
528
+ TomlConfig { build, install, llvm, rust, dist, target, profile : _, changelog_seen } : Self ,
529
+ replace : ReplaceOpt ,
518
530
) {
519
- fn do_merge < T : Merge > ( x : & mut Option < T > , y : Option < T > ) {
531
+ fn do_merge < T : Merge > ( x : & mut Option < T > , y : Option < T > , replace : ReplaceOpt ) {
520
532
if let Some ( new) = y {
521
533
if let Some ( original) = x {
522
- original. merge ( new) ;
534
+ original. merge ( new, replace ) ;
523
535
} else {
524
536
* x = Some ( new) ;
525
537
}
526
538
}
527
539
}
528
- do_merge ( & mut self . build , build) ;
529
- do_merge ( & mut self . install , install) ;
530
- do_merge ( & mut self . llvm , llvm) ;
531
- do_merge ( & mut self . rust , rust) ;
532
- do_merge ( & mut self . dist , dist) ;
540
+ self . changelog_seen . merge ( changelog_seen, replace) ;
541
+ do_merge ( & mut self . build , build, replace) ;
542
+ do_merge ( & mut self . install , install, replace) ;
543
+ do_merge ( & mut self . llvm , llvm, replace) ;
544
+ do_merge ( & mut self . rust , rust, replace) ;
545
+ do_merge ( & mut self . dist , dist, replace) ;
533
546
assert ! ( target. is_none( ) , "merging target-specific config is not currently supported" ) ;
534
547
}
535
548
}
@@ -546,10 +559,33 @@ macro_rules! define_config {
546
559
}
547
560
548
561
impl Merge for $name {
549
- fn merge( & mut self , other: Self ) {
562
+ fn merge( & mut self , other: Self , replace : ReplaceOpt ) {
550
563
$(
551
- if !self . $field. is_some( ) {
552
- self . $field = other. $field;
564
+ match replace {
565
+ ReplaceOpt :: IgnoreDuplicate => {
566
+ if self . $field. is_none( ) {
567
+ self . $field = other. $field;
568
+ }
569
+ } ,
570
+ ReplaceOpt :: Override => {
571
+ if other. $field. is_some( ) {
572
+ self . $field = other. $field;
573
+ }
574
+ }
575
+ ReplaceOpt :: ErrorOnDuplicate => {
576
+ if other. $field. is_some( ) {
577
+ if self . $field. is_some( ) {
578
+ if cfg!( test) {
579
+ panic!( "overriding existing option" )
580
+ } else {
581
+ eprintln!( "overriding existing option: `{}`" , stringify!( $field) ) ;
582
+ crate :: detail_exit( 2 ) ;
583
+ }
584
+ } else {
585
+ self . $field = other. $field;
586
+ }
587
+ }
588
+ }
553
589
}
554
590
) *
555
591
}
@@ -622,6 +658,37 @@ macro_rules! define_config {
622
658
}
623
659
}
624
660
661
+ impl < T > Merge for Option < T > {
662
+ fn merge ( & mut self , other : Self , replace : ReplaceOpt ) {
663
+ match replace {
664
+ ReplaceOpt :: IgnoreDuplicate => {
665
+ if self . is_none ( ) {
666
+ * self = other;
667
+ }
668
+ }
669
+ ReplaceOpt :: Override => {
670
+ if other. is_some ( ) {
671
+ * self = other;
672
+ }
673
+ }
674
+ ReplaceOpt :: ErrorOnDuplicate => {
675
+ if other. is_some ( ) {
676
+ if self . is_some ( ) {
677
+ if cfg ! ( test) {
678
+ panic ! ( "overriding existing option" )
679
+ } else {
680
+ eprintln ! ( "overriding existing option" ) ;
681
+ crate :: detail_exit ( 2 ) ;
682
+ }
683
+ } else {
684
+ * self = other;
685
+ }
686
+ }
687
+ }
688
+ }
689
+ }
690
+ }
691
+
625
692
define_config ! {
626
693
/// TOML representation of various global build decisions.
627
694
#[ derive( Default ) ]
@@ -863,28 +930,27 @@ impl Config {
863
930
864
931
pub fn parse ( args : & [ String ] ) -> Config {
865
932
#[ cfg( test) ]
866
- let get_toml = |_: & _ | TomlConfig :: default ( ) ;
933
+ fn get_toml ( _: & Path ) -> TomlConfig {
934
+ TomlConfig :: default ( )
935
+ }
936
+
867
937
#[ cfg( not( test) ) ]
868
- let get_toml = | file : & Path | {
938
+ fn get_toml ( file : & Path ) -> TomlConfig {
869
939
let contents =
870
940
t ! ( fs:: read_to_string( file) , format!( "config file {} not found" , file. display( ) ) ) ;
871
941
// Deserialize to Value and then TomlConfig to prevent the Deserialize impl of
872
942
// TomlConfig and sub types to be monomorphized 5x by toml.
873
- match toml:: from_str ( & contents)
943
+ toml:: from_str ( & contents)
874
944
. and_then ( |table : toml:: Value | TomlConfig :: deserialize ( table) )
875
- {
876
- Ok ( table) => table,
877
- Err ( err) => {
878
- eprintln ! ( "failed to parse TOML configuration '{}': {}" , file. display( ) , err) ;
945
+ . unwrap_or_else ( |err| {
946
+ eprintln ! ( "failed to parse TOML configuration '{}': {err}" , file. display( ) ) ;
879
947
crate :: detail_exit ( 2 ) ;
880
- }
881
- }
882
- } ;
883
-
948
+ } )
949
+ }
884
950
Self :: parse_inner ( args, get_toml)
885
951
}
886
952
887
- fn parse_inner < ' a > ( args : & [ String ] , get_toml : impl ' a + Fn ( & Path ) -> TomlConfig ) -> Config {
953
+ fn parse_inner ( args : & [ String ] , get_toml : impl Fn ( & Path ) -> TomlConfig ) -> Config {
888
954
let mut flags = Flags :: parse ( & args) ;
889
955
let mut config = Config :: default_opts ( ) ;
890
956
@@ -997,8 +1063,40 @@ impl Config {
997
1063
include_path. push ( "defaults" ) ;
998
1064
include_path. push ( format ! ( "config.{}.toml" , include) ) ;
999
1065
let included_toml = get_toml ( & include_path) ;
1000
- toml. merge ( included_toml) ;
1066
+ toml. merge ( included_toml, ReplaceOpt :: IgnoreDuplicate ) ;
1067
+ }
1068
+
1069
+ let mut override_toml = TomlConfig :: default ( ) ;
1070
+ for option in flags. set . iter ( ) {
1071
+ fn get_table ( option : & str ) -> Result < TomlConfig , toml:: de:: Error > {
1072
+ toml:: from_str ( & option)
1073
+ . and_then ( |table : toml:: Value | TomlConfig :: deserialize ( table) )
1074
+ }
1075
+
1076
+ let mut err = match get_table ( option) {
1077
+ Ok ( v) => {
1078
+ override_toml. merge ( v, ReplaceOpt :: ErrorOnDuplicate ) ;
1079
+ continue ;
1080
+ }
1081
+ Err ( e) => e,
1082
+ } ;
1083
+ // We want to be able to set string values without quotes,
1084
+ // like in `configure.py`. Try adding quotes around the right hand side
1085
+ if let Some ( ( key, value) ) = option. split_once ( "=" ) {
1086
+ if !value. contains ( '"' ) {
1087
+ match get_table ( & format ! ( r#"{key}="{value}""# ) ) {
1088
+ Ok ( v) => {
1089
+ override_toml. merge ( v, ReplaceOpt :: ErrorOnDuplicate ) ;
1090
+ continue ;
1091
+ }
1092
+ Err ( e) => err = e,
1093
+ }
1094
+ }
1095
+ }
1096
+ eprintln ! ( "failed to parse override `{option}`: `{err}" ) ;
1097
+ crate :: detail_exit ( 2 )
1001
1098
}
1099
+ toml. merge ( override_toml, ReplaceOpt :: Override ) ;
1002
1100
1003
1101
config. changelog_seen = toml. changelog_seen ;
1004
1102
0 commit comments