@@ -22,6 +22,7 @@ use std::path::Path;
2222
2323use regex:: Regex ;
2424
25+ use crate :: diagnostics:: { DiagCtx , RunningCheck } ;
2526use crate :: walk:: { filter_dirs, walk, walk_many} ;
2627
2728const ERROR_CODES_PATH : & str = "compiler/rustc_error_codes/src/lib.rs" ;
@@ -35,71 +36,50 @@ const IGNORE_DOCTEST_CHECK: &[&str] = &["E0464", "E0570", "E0601", "E0602", "E07
3536const IGNORE_UI_TEST_CHECK : & [ & str ] =
3637 & [ "E0461" , "E0465" , "E0514" , "E0554" , "E0640" , "E0717" , "E0729" ] ;
3738
38- macro_rules! verbose_print {
39- ( $verbose: expr, $( $fmt: tt) * ) => {
40- if $verbose {
41- println!( "{}" , format_args!( $( $fmt) * ) ) ;
42- }
43- } ;
44- }
45-
46- pub fn check (
47- root_path : & Path ,
48- search_paths : & [ & Path ] ,
49- verbose : bool ,
50- ci_info : & crate :: CiInfo ,
51- bad : & mut bool ,
52- ) {
53- let mut errors = Vec :: new ( ) ;
39+ pub fn check ( root_path : & Path , search_paths : & [ & Path ] , ci_info : & crate :: CiInfo , diag_ctx : DiagCtx ) {
40+ let mut check = diag_ctx. start_check ( "error_codes" ) ;
5441
5542 // Check that no error code explanation was removed.
56- check_removed_error_code_explanation ( ci_info, bad ) ;
43+ check_removed_error_code_explanation ( ci_info, & mut check ) ;
5744
5845 // Stage 1: create list
59- let error_codes = extract_error_codes ( root_path, & mut errors) ;
60- if verbose {
61- println ! ( "Found {} error codes" , error_codes. len( ) ) ;
62- println ! ( "Highest error code: `{}`" , error_codes. iter( ) . max( ) . unwrap( ) ) ;
63- }
46+ let error_codes = extract_error_codes ( root_path, & mut check) ;
47+ check. verbose_msg ( format ! ( "Found {} error codes" , error_codes. len( ) ) ) ;
48+ check. verbose_msg ( format ! ( "Highest error code: `{}`" , error_codes. iter( ) . max( ) . unwrap( ) ) ) ;
6449
6550 // Stage 2: check list has docs
66- let no_longer_emitted = check_error_codes_docs ( root_path, & error_codes, & mut errors , verbose ) ;
51+ let no_longer_emitted = check_error_codes_docs ( root_path, & error_codes, & mut check ) ;
6752
6853 // Stage 3: check list has UI tests
69- check_error_codes_tests ( root_path, & error_codes, & mut errors , verbose , & no_longer_emitted) ;
54+ check_error_codes_tests ( root_path, & error_codes, & mut check , & no_longer_emitted) ;
7055
7156 // Stage 4: check list is emitted by compiler
72- check_error_codes_used ( search_paths, & error_codes, & mut errors, & no_longer_emitted, verbose) ;
73-
74- // Print any errors.
75- for error in errors {
76- tidy_error ! ( bad, "{}" , error) ;
77- }
57+ check_error_codes_used ( search_paths, & error_codes, & mut check, & no_longer_emitted) ;
7858}
7959
80- fn check_removed_error_code_explanation ( ci_info : & crate :: CiInfo , bad : & mut bool ) {
60+ fn check_removed_error_code_explanation ( ci_info : & crate :: CiInfo , check : & mut RunningCheck ) {
8161 let Some ( base_commit) = & ci_info. base_commit else {
82- eprintln ! ( "Skipping error code explanation removal check" ) ;
62+ check . verbose_msg ( "Skipping error code explanation removal check" ) ;
8363 return ;
8464 } ;
8565 let Some ( diff) = crate :: git_diff ( base_commit, "--name-status" ) else {
86- * bad = true ;
87- eprintln ! ( "removed error code explanation tidy check: Failed to run git diff" ) ;
66+ check. error ( format ! ( "removed error code explanation: Failed to run git diff" ) ) ;
8867 return ;
8968 } ;
9069 if diff. lines ( ) . any ( |line| {
9170 line. starts_with ( 'D' ) && line. contains ( "compiler/rustc_error_codes/src/error_codes/" )
9271 } ) {
93- * bad = true ;
94- eprintln ! ( "tidy check error: Error code explanations should never be removed!" ) ;
95- eprintln ! ( "Take a look at E0001 to see how to handle it." ) ;
72+ check. error ( format ! (
73+ r#"Error code explanations should never be removed!
74+ Take a look at E0001 to see how to handle it."#
75+ ) ) ;
9676 return ;
9777 }
98- println ! ( "No error code explanation was removed!" ) ;
78+ check . verbose_msg ( "No error code explanation was removed!" ) ;
9979}
10080
10181/// Stage 1: Parses a list of error codes from `error_codes.rs`.
102- fn extract_error_codes ( root_path : & Path , errors : & mut Vec < String > ) -> Vec < String > {
82+ fn extract_error_codes ( root_path : & Path , check : & mut RunningCheck ) -> Vec < String > {
10383 let path = root_path. join ( Path :: new ( ERROR_CODES_PATH ) ) ;
10484 let file =
10585 fs:: read_to_string ( & path) . unwrap_or_else ( |e| panic ! ( "failed to read `{path:?}`: {e}" ) ) ;
@@ -117,7 +97,7 @@ fn extract_error_codes(root_path: &Path, errors: &mut Vec<String>) -> Vec<String
11797 // Extract the error code from the line. Emit a fatal error if it is not in the correct
11898 // format.
11999 let Some ( split_line) = split_line else {
120- errors . push ( format ! (
100+ check . error ( format ! (
121101 "{path}:{line_index}: Expected a line with the format `Eabcd: abcd, \
122102 but got \" {line}\" without a `:` delimiter",
123103 ) ) ;
@@ -128,8 +108,9 @@ fn extract_error_codes(root_path: &Path, errors: &mut Vec<String>) -> Vec<String
128108
129109 // If this is a duplicate of another error code, emit a fatal error.
130110 if error_codes. contains ( & err_code) {
131- errors
132- . push ( format ! ( "{path}:{line_index}: Found duplicate error code: `{err_code}`" ) ) ;
111+ check. error ( format ! (
112+ "{path}:{line_index}: Found duplicate error code: `{err_code}`"
113+ ) ) ;
133114 continue ;
134115 }
135116
@@ -140,14 +121,14 @@ fn extract_error_codes(root_path: &Path, errors: &mut Vec<String>) -> Vec<String
140121 // Ensure that the line references the correct markdown file.
141122 let rest = split_line. 1 . split_once ( ',' ) ;
142123 let Some ( rest) = rest else {
143- errors . push ( format ! (
124+ check . error ( format ! (
144125 "{path}:{line_index}: Expected a line with the format `Eabcd: abcd, \
145126 but got \" {line}\" without a `,` delimiter",
146127 ) ) ;
147128 continue ;
148129 } ;
149130 if error_num_as_str != rest. 0 . trim ( ) {
150- errors . push ( format ! (
131+ check . error ( format ! (
151132 "{path}:{line_index}: `{}:` should be followed by `{},` but instead found `{}` in \
152133 `compiler/rustc_error_codes/src/lib.rs`",
153134 err_code,
@@ -157,7 +138,7 @@ fn extract_error_codes(root_path: &Path, errors: &mut Vec<String>) -> Vec<String
157138 continue ;
158139 }
159140 if !rest. 1 . trim ( ) . is_empty ( ) && !rest. 1 . trim ( ) . starts_with ( "//" ) {
160- errors . push ( format ! ( "{path}:{line_index}: should only have one error per line" ) ) ;
141+ check . error ( format ! ( "{path}:{line_index}: should only have one error per line" ) ) ;
161142 continue ;
162143 }
163144
@@ -172,8 +153,7 @@ fn extract_error_codes(root_path: &Path, errors: &mut Vec<String>) -> Vec<String
172153fn check_error_codes_docs (
173154 root_path : & Path ,
174155 error_codes : & [ String ] ,
175- errors : & mut Vec < String > ,
176- verbose : bool ,
156+ check : & mut RunningCheck ,
177157) -> Vec < String > {
178158 let docs_path = root_path. join ( Path :: new ( ERROR_DOCS_PATH ) ) ;
179159
@@ -184,7 +164,7 @@ fn check_error_codes_docs(
184164
185165 // Error if the file isn't markdown.
186166 if path. extension ( ) != Some ( OsStr :: new ( "md" ) ) {
187- errors . push ( format ! (
167+ check . error ( format ! (
188168 "Found unexpected non-markdown file in error code docs directory: {}" ,
189169 path. display( )
190170 ) ) ;
@@ -196,7 +176,7 @@ fn check_error_codes_docs(
196176 let err_code = filename. unwrap ( ) . 0 ; // `unwrap` is ok because we know the filename is in the correct format.
197177
198178 if error_codes. iter ( ) . all ( |e| e != err_code) {
199- errors . push ( format ! (
179+ check . error ( format ! (
200180 "Found valid file `{}` in error code docs directory without corresponding \
201181 entry in `rustc_error_codes/src/lib.rs`",
202182 path. display( )
@@ -208,36 +188,34 @@ fn check_error_codes_docs(
208188 check_explanation_has_doctest ( contents, err_code) ;
209189
210190 if emit_ignore_warning {
211- verbose_print ! (
212- verbose,
191+ check. verbose_msg ( format ! (
213192 "warning: Error code `{err_code}` uses the ignore header. This should not be used, add the error code to the \
214193 `IGNORE_DOCTEST_CHECK` constant instead."
215- ) ;
194+ ) ) ;
216195 }
217196
218197 if no_longer_emitted {
219198 no_longer_emitted_codes. push ( err_code. to_owned ( ) ) ;
220199 }
221200
222201 if !found_code_example {
223- verbose_print ! (
224- verbose,
202+ check. verbose_msg ( format ! (
225203 "warning: Error code `{err_code}` doesn't have a code example, all error codes are expected to have one \
226204 (even if untested)."
227- ) ;
205+ ) ) ;
228206 return ;
229207 }
230208
231209 let test_ignored = IGNORE_DOCTEST_CHECK . contains ( & err_code) ;
232210
233211 // Check that the explanation has a doctest, and if it shouldn't, that it doesn't
234212 if !found_proper_doctest && !test_ignored {
235- errors . push ( format ! (
213+ check . error ( format ! (
236214 "`{}` doesn't use its own error code in compile_fail example" ,
237215 path. display( ) ,
238216 ) ) ;
239217 } else if found_proper_doctest && test_ignored {
240- errors . push ( format ! (
218+ check . error ( format ! (
241219 "`{}` has a compile_fail doctest with its own error code, it shouldn't \
242220 be listed in `IGNORE_DOCTEST_CHECK`",
243221 path. display( ) ,
@@ -289,8 +267,7 @@ fn check_explanation_has_doctest(explanation: &str, err_code: &str) -> (bool, bo
289267fn check_error_codes_tests (
290268 root_path : & Path ,
291269 error_codes : & [ String ] ,
292- errors : & mut Vec < String > ,
293- verbose : bool ,
270+ check : & mut RunningCheck ,
294271 no_longer_emitted : & [ String ] ,
295272) {
296273 let tests_path = root_path. join ( Path :: new ( ERROR_TESTS_PATH ) ) ;
@@ -299,15 +276,14 @@ fn check_error_codes_tests(
299276 let test_path = tests_path. join ( format ! ( "{code}.stderr" ) ) ;
300277
301278 if !test_path. exists ( ) && !IGNORE_UI_TEST_CHECK . contains ( & code. as_str ( ) ) {
302- verbose_print ! (
303- verbose,
279+ check. verbose_msg ( format ! (
304280 "warning: Error code `{code}` needs to have at least one UI test in the `tests/error-codes/` directory`!"
305- ) ;
281+ ) ) ;
306282 continue ;
307283 }
308284 if IGNORE_UI_TEST_CHECK . contains ( & code. as_str ( ) ) {
309285 if test_path. exists ( ) {
310- errors . push ( format ! (
286+ check . error ( format ! (
311287 "Error code `{code}` has a UI test in `tests/ui/error-codes/{code}.rs`, it shouldn't be listed in `EXEMPTED_FROM_TEST`!"
312288 ) ) ;
313289 }
@@ -317,11 +293,10 @@ fn check_error_codes_tests(
317293 let file = match fs:: read_to_string ( & test_path) {
318294 Ok ( file) => file,
319295 Err ( err) => {
320- verbose_print ! (
321- verbose,
296+ check. verbose_msg ( format ! (
322297 "warning: Failed to read UI test file (`{}`) for `{code}` but the file exists. The test is assumed to work:\n {err}" ,
323298 test_path. display( )
324- ) ;
299+ ) ) ;
325300 continue ;
326301 }
327302 } ;
@@ -343,10 +318,9 @@ fn check_error_codes_tests(
343318 }
344319
345320 if !found_code {
346- verbose_print ! (
347- verbose,
321+ check. verbose_msg ( format ! (
348322 "warning: Error code `{code}` has a UI test file, but doesn't contain its own error code!"
349- ) ;
323+ ) ) ;
350324 }
351325 }
352326}
@@ -355,9 +329,8 @@ fn check_error_codes_tests(
355329fn check_error_codes_used (
356330 search_paths : & [ & Path ] ,
357331 error_codes : & [ String ] ,
358- errors : & mut Vec < String > ,
332+ check : & mut RunningCheck ,
359333 no_longer_emitted : & [ String ] ,
360- verbose : bool ,
361334) {
362335 // Search for error codes in the form `E0123`.
363336 let regex = Regex :: new ( r#"\bE\d{4}\b"# ) . unwrap ( ) ;
@@ -384,7 +357,7 @@ fn check_error_codes_used(
384357
385358 if !error_codes. contains ( & error_code) {
386359 // This error code isn't properly defined, we must error.
387- errors . push ( format ! ( "Error code `{error_code}` is used in the compiler but not defined and documented in `compiler/rustc_error_codes/src/lib.rs`." ) ) ;
360+ check . error ( format ! ( "Error code `{error_code}` is used in the compiler but not defined and documented in `compiler/rustc_error_codes/src/lib.rs`." ) ) ;
388361 continue ;
389362 }
390363
@@ -397,7 +370,7 @@ fn check_error_codes_used(
397370
398371 for code in error_codes {
399372 if !found_codes. contains ( code) && !no_longer_emitted. contains ( code) {
400- errors . push ( format ! (
373+ check . error ( format ! (
401374 "Error code `{code}` exists, but is not emitted by the compiler!\n \
402375 Please mark the code as no longer emitted by adding the following note to the top of the `EXXXX.md` file:\n \
403376 `#### Note: this error code is no longer emitted by the compiler`\n \
@@ -406,10 +379,9 @@ fn check_error_codes_used(
406379 }
407380
408381 if found_codes. contains ( code) && no_longer_emitted. contains ( code) {
409- verbose_print ! (
410- verbose,
382+ check. verbose_msg ( format ! (
411383 "warning: Error code `{code}` is used when it's marked as \" no longer emitted\" "
412- ) ;
384+ ) ) ;
413385 }
414386 }
415387}
0 commit comments