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