From f85e4f75b9b60e2ce4b2ade8f04e2537e48f7095 Mon Sep 17 00:00:00 2001 From: Keegan McAllister Date: Tue, 16 Sep 2014 14:47:19 -0700 Subject: [PATCH 1/2] Add a forbid-output property in cfail tests --- src/compiletest/header.rs | 15 +++++++++++++- src/compiletest/runtest.rs | 40 ++++++++++++++++++++++++++------------ 2 files changed, 42 insertions(+), 13 deletions(-) diff --git a/src/compiletest/header.rs b/src/compiletest/header.rs index 9ad2582dec8..cc765695cb7 100644 --- a/src/compiletest/header.rs +++ b/src/compiletest/header.rs @@ -42,6 +42,8 @@ pub struct TestProps { pub pretty_mode: String, // Only compare pretty output and don't try compiling pub pretty_compare_only: bool, + // Patterns which must not appear in the output of a cfail test. + pub forbid_output: Vec, } // Load any test directives embedded in the file @@ -59,6 +61,7 @@ pub fn load_props(testfile: &Path) -> TestProps { let mut no_pretty_expanded = false; let mut pretty_mode = None; let mut pretty_compare_only = false; + let mut forbid_output = Vec::new(); iter_header(testfile, |ln| { match parse_error_pattern(ln) { Some(ep) => error_patterns.push(ep), @@ -116,6 +119,11 @@ pub fn load_props(testfile: &Path) -> TestProps { None => () }; + match parse_forbid_output(ln) { + Some(of) => forbid_output.push(of), + None => (), + } + true }); @@ -132,7 +140,8 @@ pub fn load_props(testfile: &Path) -> TestProps { no_prefer_dynamic: no_prefer_dynamic, no_pretty_expanded: no_pretty_expanded, pretty_mode: pretty_mode.unwrap_or("normal".to_string()), - pretty_compare_only: pretty_compare_only + pretty_compare_only: pretty_compare_only, + forbid_output: forbid_output, } } @@ -210,6 +219,10 @@ fn parse_error_pattern(line: &str) -> Option { parse_name_value_directive(line, "error-pattern") } +fn parse_forbid_output(line: &str) -> Option { + parse_name_value_directive(line, "forbid-output") +} + fn parse_aux_build(line: &str) -> Option { parse_name_value_directive(line, "aux-build") } diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index 40acb7da175..d64d3317e2e 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -71,6 +71,14 @@ pub fn run_metrics(config: Config, testfile: String, mm: &mut MetricMap) { } } +fn get_output(props: &TestProps, proc_res: &ProcRes) -> String { + if props.check_stdout { + format!("{}{}", proc_res.stdout, proc_res.stderr) + } else { + proc_res.stderr.clone() + } +} + fn run_cfail_test(config: &Config, props: &TestProps, testfile: &Path) { let proc_res = compile_test(config, props, testfile); @@ -81,6 +89,11 @@ fn run_cfail_test(config: &Config, props: &TestProps, testfile: &Path) { check_correct_failure_status(&proc_res); + if proc_res.status.success() { + fatal("process did not return an error status"); + } + + let output_to_check = get_output(props, &proc_res); let expected_errors = errors::load_errors(&config.cfail_regex, testfile); if !expected_errors.is_empty() { if !props.error_patterns.is_empty() { @@ -88,9 +101,10 @@ fn run_cfail_test(config: &Config, props: &TestProps, testfile: &Path) { } check_expected_errors(expected_errors, testfile, &proc_res); } else { - check_error_patterns(props, testfile, &proc_res); + check_error_patterns(props, testfile, output_to_check.as_slice(), &proc_res); } check_no_compiler_crash(&proc_res); + check_forbid_output(props, output_to_check.as_slice(), &proc_res); } fn run_rfail_test(config: &Config, props: &TestProps, testfile: &Path) { @@ -112,8 +126,9 @@ fn run_rfail_test(config: &Config, props: &TestProps, testfile: &Path) { fatal_proc_rec("run-fail test isn't valgrind-clean!", &proc_res); } + let output_to_check = get_output(props, &proc_res); check_correct_failure_status(&proc_res); - check_error_patterns(props, testfile, &proc_res); + check_error_patterns(props, testfile, output_to_check.as_slice(), &proc_res); } fn check_correct_failure_status(proc_res: &ProcRes) { @@ -834,24 +849,15 @@ fn check_debugger_output(debugger_run_result: &ProcRes, check_lines: &[String]) fn check_error_patterns(props: &TestProps, testfile: &Path, + output_to_check: &str, proc_res: &ProcRes) { if props.error_patterns.is_empty() { fatal(format!("no error pattern specified in {}", testfile.display()).as_slice()); } - - if proc_res.status.success() { - fatal("process did not return an error status"); - } - let mut next_err_idx = 0u; let mut next_err_pat = &props.error_patterns[next_err_idx]; let mut done = false; - let output_to_check = if props.check_stdout { - format!("{}{}", proc_res.stdout, proc_res.stderr) - } else { - proc_res.stderr.clone() - }; for line in output_to_check.as_slice().lines() { if line.contains(next_err_pat.as_slice()) { debug!("found error pattern {}", next_err_pat); @@ -890,6 +896,16 @@ fn check_no_compiler_crash(proc_res: &ProcRes) { } } +fn check_forbid_output(props: &TestProps, + output_to_check: &str, + proc_res: &ProcRes) { + for pat in props.forbid_output.iter() { + if output_to_check.contains(pat.as_slice()) { + fatal_proc_rec("forbidden pattern found in compiler output", proc_res); + } + } +} + fn check_expected_errors(expected_errors: Vec , testfile: &Path, proc_res: &ProcRes) { From 5b42f79ff088bf3f9136f6f668a481097e22bed9 Mon Sep 17 00:00:00 2001 From: Keegan McAllister Date: Tue, 16 Sep 2014 14:18:37 -0700 Subject: [PATCH 2/2] Pop the expansion context after expanding a method macro We were leaving these on the stack, causing spurious backtraces. I've confirmed that this test fails without the fix. --- src/libsyntax/ext/expand.rs | 5 ++- .../compile-fail/method-macro-backtrace.rs | 37 +++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 src/test/compile-fail/method-macro-backtrace.rs diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 4ff9912645a..892213e684f 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -897,7 +897,10 @@ fn expand_method(m: P, fld: &mut MacroExpander) -> SmallVector or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// forbid-output: in expansion of + +#![feature(macro_rules)] + +macro_rules! make_method ( ($name:ident) => ( + fn $name(&self) { } +)) + +struct S; + +impl S { + // We had a bug where these wouldn't clean up macro backtrace frames. + make_method!(foo1) + make_method!(foo2) + make_method!(foo3) + make_method!(foo4) + make_method!(foo5) + make_method!(foo6) + make_method!(foo7) + make_method!(foo8) + + // Cause an error. It shouldn't have any macro backtrace frames. + fn bar(&self) { } + fn bar(&self) { } //~ ERROR duplicate definition +} + +fn main() { }