@@ -15,7 +15,7 @@ use regex::bytes::Regex;
15
15
use rustc_stderr:: { Level , Message } ;
16
16
use std:: collections:: VecDeque ;
17
17
use std:: ffi:: OsString ;
18
- use std:: fmt:: { Display , Write as _ } ;
18
+ use std:: fmt:: Display ;
19
19
use std:: io:: Write as _;
20
20
use std:: num:: NonZeroUsize ;
21
21
use std:: path:: { Path , PathBuf } ;
@@ -488,28 +488,22 @@ fn parse_and_test_file(path: PathBuf, config: &Config) -> Vec<TestRun> {
488
488
} ]
489
489
}
490
490
} ;
491
- // Ignore file if only/ignore rules do (not) apply
492
- if !test_file_conditions ( & comments, config) {
493
- return vec ! [ TestRun {
494
- result: TestResult :: Ignored ,
495
- path,
496
- revision: "" . into( ) ,
497
- } ] ;
498
- }
499
491
// Run the test for all revisions
500
492
comments
501
493
. revisions
502
494
. clone ( )
503
495
. unwrap_or_else ( || vec ! [ String :: new( ) ] )
504
496
. into_iter ( )
505
497
. map ( |revision| {
506
- let ( command, errors, stderr) = run_test ( & path, config, & revision, & comments) ;
507
-
508
- // Using a single `eprintln!` to prevent messages from threads from getting intermingled.
509
- let mut msg = format ! ( "{}" , path. display( ) ) ;
510
- if !revision. is_empty ( ) {
511
- write ! ( msg, " (revision `{revision}`) " ) . unwrap ( ) ;
498
+ // Ignore file if only/ignore rules do (not) apply
499
+ if !test_file_conditions ( & comments, config, & revision) {
500
+ return TestRun {
501
+ result : TestResult :: Ignored ,
502
+ path : path. clone ( ) ,
503
+ revision,
504
+ } ;
512
505
}
506
+ let ( command, errors, stderr) = run_test ( & path, config, & revision, & comments) ;
513
507
let result = if errors. is_empty ( ) {
514
508
TestResult :: Ok
515
509
} else {
@@ -569,11 +563,19 @@ fn build_command(path: &Path, config: &Config, revision: &str, comments: &Commen
569
563
if !revision. is_empty ( ) {
570
564
cmd. arg ( format ! ( "--cfg={revision}" ) ) ;
571
565
}
572
- for arg in & comments. compile_flags {
566
+ for arg in comments
567
+ . for_revision ( revision)
568
+ . flat_map ( |r| r. compile_flags . iter ( ) )
569
+ {
573
570
cmd. arg ( arg) ;
574
571
}
575
572
cmd. args ( config. trailing_args . iter ( ) ) ;
576
- cmd. envs ( comments. env_vars . iter ( ) . map ( |( k, v) | ( k, v) ) ) ;
573
+ cmd. envs (
574
+ comments
575
+ . for_revision ( revision)
576
+ . flat_map ( |r| r. env_vars . iter ( ) )
577
+ . map ( |( k, v) | ( k, v) ) ,
578
+ ) ;
577
579
578
580
cmd
579
581
}
@@ -627,6 +629,7 @@ fn check_test_result(
627
629
& config. stderr_filters ,
628
630
config,
629
631
comments,
632
+ revision,
630
633
) ;
631
634
check_output (
632
635
stdout,
@@ -636,6 +639,7 @@ fn check_test_result(
636
639
& config. stdout_filters ,
637
640
config,
638
641
comments,
642
+ revision,
639
643
) ;
640
644
// Check error annotations in the source against output
641
645
check_annotations (
@@ -659,7 +663,17 @@ fn check_annotations(
659
663
revision : & str ,
660
664
comments : & Comments ,
661
665
) {
662
- if let Some ( ( ref error_pattern, definition_line) ) = comments. error_pattern {
666
+ let error_pattern = comments. find_one_for_revision (
667
+ revision,
668
+ |r| r. error_pattern . as_ref ( ) ,
669
+ |( _, line) | {
670
+ errors. push ( Error :: InvalidComment {
671
+ msg : "same revision defines pattern twice" . into ( ) ,
672
+ line : * line,
673
+ } )
674
+ } ,
675
+ ) ;
676
+ if let Some ( ( error_pattern, definition_line) ) = error_pattern {
663
677
// first check the diagnostics messages outside of our file. We check this first, so that
664
678
// you can mix in-file annotations with //@error-pattern annotations, even if there is overlap
665
679
// in the messages.
@@ -671,7 +685,7 @@ fn check_annotations(
671
685
} else {
672
686
errors. push ( Error :: PatternNotFound {
673
687
pattern : error_pattern. clone ( ) ,
674
- definition_line,
688
+ definition_line : * definition_line ,
675
689
} ) ;
676
690
}
677
691
}
@@ -680,20 +694,17 @@ fn check_annotations(
680
694
// We will ensure that *all* diagnostics of level at least `lowest_annotation_level`
681
695
// are matched.
682
696
let mut lowest_annotation_level = Level :: Error ;
697
+ let mut seen_error_match = false ;
683
698
for & ErrorMatch {
684
699
ref pattern,
685
- revision : ref rev,
686
700
definition_line,
687
701
line,
688
702
level,
689
- } in & comments. error_matches
703
+ } in comments
704
+ . for_revision ( revision)
705
+ . flat_map ( |r| r. error_matches . iter ( ) )
690
706
{
691
- if let Some ( rev) = rev {
692
- if rev != revision {
693
- continue ;
694
- }
695
- }
696
-
707
+ seen_error_match = true ;
697
708
// If we found a diagnostic with a level annotation, make sure that all
698
709
// diagnostics of that level have annotations, even if we don't end up finding a matching diagnostic
699
710
// for this pattern.
@@ -715,18 +726,21 @@ fn check_annotations(
715
726
} ) ;
716
727
}
717
728
718
- let filter = |msgs : Vec < Message > | -> Vec < _ > {
719
- msgs. into_iter ( )
720
- . filter ( |msg| {
721
- msg. level
722
- >= comments
723
- . require_annotations_for_level
724
- . unwrap_or ( lowest_annotation_level)
729
+ let filter = |mut msgs : Vec < Message > , errors : & mut Vec < _ > | -> Vec < _ > {
730
+ let error = |_| {
731
+ errors. push ( Error :: InvalidComment {
732
+ msg : "`require_annotations_for_level` specified twice for same revision" . into ( ) ,
733
+ line : 0 ,
725
734
} )
726
- . collect ( )
735
+ } ;
736
+ let required_annotation_level = comments
737
+ . find_one_for_revision ( revision, |r| r. require_annotations_for_level , error)
738
+ . unwrap_or ( lowest_annotation_level) ;
739
+ msgs. retain ( |msg| msg. level >= required_annotation_level) ;
740
+ msgs
727
741
} ;
728
742
729
- let messages_from_unknown_file_or_line = filter ( messages_from_unknown_file_or_line) ;
743
+ let messages_from_unknown_file_or_line = filter ( messages_from_unknown_file_or_line, errors ) ;
730
744
if !messages_from_unknown_file_or_line. is_empty ( ) {
731
745
errors. push ( Error :: ErrorsWithoutPattern {
732
746
path : None ,
@@ -735,7 +749,7 @@ fn check_annotations(
735
749
}
736
750
737
751
for ( line, msgs) in messages. into_iter ( ) . enumerate ( ) {
738
- let msgs = filter ( msgs) ;
752
+ let msgs = filter ( msgs, errors ) ;
739
753
if !msgs. is_empty ( ) {
740
754
errors. push ( Error :: ErrorsWithoutPattern {
741
755
path : Some ( ( path. to_path_buf ( ) , line) ) ,
@@ -744,10 +758,7 @@ fn check_annotations(
744
758
}
745
759
}
746
760
747
- match (
748
- config. mode ,
749
- comments. error_pattern . is_some ( ) || !comments. error_matches . is_empty ( ) ,
750
- ) {
761
+ match ( config. mode , error_pattern. is_some ( ) || seen_error_match) {
751
762
( Mode :: Pass , true ) | ( Mode :: Panic , true ) => errors. push ( Error :: PatternFoundInPassTest ) ,
752
763
(
753
764
Mode :: Fail {
@@ -767,10 +778,11 @@ fn check_output(
767
778
filters : & Filter ,
768
779
config : & Config ,
769
780
comments : & Comments ,
781
+ revision : & str ,
770
782
) {
771
783
let target = config. target . as_ref ( ) . unwrap ( ) ;
772
- let output = normalize ( path, output, filters, comments) ;
773
- let path = output_path ( path, comments, kind, target) ;
784
+ let output = normalize ( path, output, filters, comments, revision ) ;
785
+ let path = output_path ( path, comments, kind, target, revision ) ;
774
786
match config. output_conflict_handling {
775
787
OutputConflictHandling :: Bless => {
776
788
if output. is_empty ( ) {
@@ -793,8 +805,17 @@ fn check_output(
793
805
}
794
806
}
795
807
796
- fn output_path ( path : & Path , comments : & Comments , kind : String , target : & str ) -> PathBuf {
797
- if comments. stderr_per_bitwidth {
808
+ fn output_path (
809
+ path : & Path ,
810
+ comments : & Comments ,
811
+ kind : String ,
812
+ target : & str ,
813
+ revision : & str ,
814
+ ) -> PathBuf {
815
+ if comments
816
+ . for_revision ( revision)
817
+ . any ( |r| r. stderr_per_bitwidth )
818
+ {
798
819
return path. with_extension ( format ! ( "{}bit.{kind}" , get_pointer_width( target) ) ) ;
799
820
}
800
821
path. with_extension ( kind)
@@ -810,11 +831,18 @@ fn test_condition(condition: &Condition, config: &Config) -> bool {
810
831
}
811
832
812
833
/// Returns whether according to the in-file conditions, this file should be run.
813
- fn test_file_conditions ( comments : & Comments , config : & Config ) -> bool {
814
- if comments. ignore . iter ( ) . any ( |c| test_condition ( c, config) ) {
834
+ fn test_file_conditions ( comments : & Comments , config : & Config , revision : & str ) -> bool {
835
+ if comments
836
+ . for_revision ( revision)
837
+ . flat_map ( |r| r. ignore . iter ( ) )
838
+ . any ( |c| test_condition ( c, config) )
839
+ {
815
840
return false ;
816
841
}
817
- comments. only . iter ( ) . all ( |c| test_condition ( c, config) )
842
+ comments
843
+ . for_revision ( revision)
844
+ . flat_map ( |r| r. only . iter ( ) )
845
+ . all ( |c| test_condition ( c, config) )
818
846
}
819
847
820
848
// Taken 1:1 from compiletest-rs
@@ -830,7 +858,13 @@ fn get_pointer_width(triple: &str) -> u8 {
830
858
}
831
859
}
832
860
833
- fn normalize ( path : & Path , text : & [ u8 ] , filters : & Filter , comments : & Comments ) -> Vec < u8 > {
861
+ fn normalize (
862
+ path : & Path ,
863
+ text : & [ u8 ] ,
864
+ filters : & Filter ,
865
+ comments : & Comments ,
866
+ revision : & str ,
867
+ ) -> Vec < u8 > {
834
868
// Useless paths
835
869
let mut text = text. replace ( & path. parent ( ) . unwrap ( ) . display ( ) . to_string ( ) , "$DIR" ) ;
836
870
if let Some ( lib_path) = option_env ! ( "RUSTC_LIB_PATH" ) {
@@ -841,7 +875,10 @@ fn normalize(path: &Path, text: &[u8], filters: &Filter, comments: &Comments) ->
841
875
text = regex. replace_all ( & text, * replacement) . into_owned ( ) ;
842
876
}
843
877
844
- for ( from, to) in & comments. normalize_stderr {
878
+ for ( from, to) in comments
879
+ . for_revision ( revision)
880
+ . flat_map ( |r| r. normalize_stderr . iter ( ) )
881
+ {
845
882
text = from. replace_all ( & text, to) . into_owned ( ) ;
846
883
}
847
884
text
0 commit comments