From b9a44fc489a55ebdcc04b09067e2ab9164f30810 Mon Sep 17 00:00:00 2001 From: Ryan Thomas Date: Thu, 22 Jun 2017 19:50:56 +0100 Subject: [PATCH 01/18] Update docs for fmt::write. I reworded it slightly to make it more clear that the function only take two arguments - the output and the Arguments struct that can be generated from the format_args! macro. r? @steveklabnik --- src/libcore/fmt/mod.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 8c3d3ce7d886b..bcc6d53c81d3b 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -897,14 +897,11 @@ pub trait UpperExp { fn fmt(&self, f: &mut Formatter) -> Result; } -/// The `write` function takes an output stream, a precompiled format string, -/// and a list of arguments. The arguments will be formatted according to the -/// specified format string into the output stream provided. +/// The `write` function takes an output stream, and an `Arguments` struct +/// that can be precompiled with the `format_args!` macro. /// -/// # Arguments -/// -/// * output - the buffer to write output to -/// * args - the precompiled arguments generated by `format_args!` +/// The arguments will be formatted according to the specified format string +/// into the output stream provided. /// /// # Examples /// From c5d078fd8cf554aa1ee6e6b3a0d670ca9afa4054 Mon Sep 17 00:00:00 2001 From: Ryan Thomas Date: Thu, 22 Jun 2017 20:02:57 +0100 Subject: [PATCH 02/18] Update docs for std::fmt::format #29355. This rewords and removes the `Arguments` section from the docs for fmt::format. r? @steveklabnik --- src/liballoc/fmt.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/liballoc/fmt.rs b/src/liballoc/fmt.rs index 62a8816462191..3afce884b1183 100644 --- a/src/liballoc/fmt.rs +++ b/src/liballoc/fmt.rs @@ -498,12 +498,10 @@ pub use core::fmt::{DebugList, DebugMap, DebugSet, DebugStruct, DebugTuple}; use string; -/// The format function takes a precompiled format string and a list of -/// arguments, to return the resulting formatted string. +/// The `format` function takes an `Arguments` struct and returns the resulting +/// formatted string. /// -/// # Arguments -/// -/// * args - a structure of arguments generated via the `format_args!` macro. +/// The `Arguments` instance can be created with the `format_args!` macro. /// /// # Examples /// From 60dd83ea85853f6a31f8998eb80ce47446fdb785 Mon Sep 17 00:00:00 2001 From: Paul Woolcock Date: Wed, 24 May 2017 13:58:37 -0400 Subject: [PATCH 03/18] add `allow_fail` test attribute This change allows the user to add an `#[allow_fail]` attribute to tests that will cause the test to compile & run, but if the test fails it will not cause the entire test run to fail. The test output will show the failure, but in yellow instead of red, and also indicate that it was an allowed failure. --- src/librustdoc/html/markdown.rs | 41 +++++++++++++---------- src/librustdoc/test.rs | 3 +- src/libsyntax/feature_gate.rs | 1 + src/libsyntax/test.rs | 14 ++++++-- src/libtest/lib.rs | 23 +++++++++++-- src/test/run-pass/test-allow-fail-attr.rs | 23 +++++++++++++ src/tools/compiletest/src/main.rs | 1 + 7 files changed, 81 insertions(+), 25 deletions(-) create mode 100644 src/test/run-pass/test-allow-fail-attr.rs diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index bea13397eca4b..5a56c33b80663 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -769,7 +769,7 @@ pub fn old_find_testable_code(doc: &str, tests: &mut ::test::Collector, position block_info.should_panic, block_info.no_run, block_info.ignore, block_info.test_harness, block_info.compile_fail, block_info.error_codes, - line, filename); + line, filename, block_info.allow_fail); } else { tests.add_old_test(text, filename); } @@ -859,7 +859,7 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector, position: Sp block_info.should_panic, block_info.no_run, block_info.ignore, block_info.test_harness, block_info.compile_fail, block_info.error_codes, - line, filename); + line, filename, block_info.allow_fail); prev_offset = offset; } Event::Start(Tag::Header(level)) => { @@ -889,6 +889,7 @@ struct LangString { test_harness: bool, compile_fail: bool, error_codes: Vec, + allow_fail: bool, } impl LangString { @@ -902,6 +903,7 @@ impl LangString { test_harness: false, compile_fail: false, error_codes: Vec::new(), + allow_fail: false, } } @@ -930,6 +932,7 @@ impl LangString { } "no_run" => { data.no_run = true; seen_rust_tags = !seen_other_tags; } "ignore" => { data.ignore = true; seen_rust_tags = !seen_other_tags; } + "allow_fail" => { data.allow_fail = true; seen_rust_tags = !seen_other_tags; } "rust" => { data.rust = true; seen_rust_tags = true; } "test_harness" => { data.test_harness = true; @@ -1118,7 +1121,7 @@ mod tests { fn test_lang_string_parse() { fn t(s: &str, should_panic: bool, no_run: bool, ignore: bool, rust: bool, test_harness: bool, - compile_fail: bool, error_codes: Vec) { + compile_fail: bool, allow_fail: bool, error_codes: Vec) { assert_eq!(LangString::parse(s), LangString { should_panic: should_panic, no_run: no_run, @@ -1128,25 +1131,27 @@ mod tests { compile_fail: compile_fail, error_codes: error_codes, original: s.to_owned(), + allow_fail: allow_fail, }) } // marker | should_panic| no_run| ignore| rust | test_harness| compile_fail - // | error_codes - t("", false, false, false, true, false, false, Vec::new()); - t("rust", false, false, false, true, false, false, Vec::new()); - t("sh", false, false, false, false, false, false, Vec::new()); - t("ignore", false, false, true, true, false, false, Vec::new()); - t("should_panic", true, false, false, true, false, false, Vec::new()); - t("no_run", false, true, false, true, false, false, Vec::new()); - t("test_harness", false, false, false, true, true, false, Vec::new()); - t("compile_fail", false, true, false, true, false, true, Vec::new()); - t("{.no_run .example}", false, true, false, true, false, false, Vec::new()); - t("{.sh .should_panic}", true, false, false, false, false, false, Vec::new()); - t("{.example .rust}", false, false, false, true, false, false, Vec::new()); - t("{.test_harness .rust}", false, false, false, true, true, false, Vec::new()); - t("text, no_run", false, true, false, false, false, false, Vec::new()); - t("text,no_run", false, true, false, false, false, false, Vec::new()); + // | allow_fail | error_codes + t("", false, false, false, true, false, false, false, Vec::new()); + t("rust", false, false, false, true, false, false, false, Vec::new()); + t("sh", false, false, false, false, false, false, false, Vec::new()); + t("ignore", false, false, true, true, false, false, false, Vec::new()); + t("should_panic", true, false, false, true, false, false, false, Vec::new()); + t("no_run", false, true, false, true, false, false, false, Vec::new()); + t("test_harness", false, false, false, true, true, false, false, Vec::new()); + t("compile_fail", false, true, false, true, false, true, false, Vec::new()); + t("allow_fail", false, false, false, true, false, false, true, Vec::new()); + t("{.no_run .example}", false, true, false, true, false, false, false, Vec::new()); + t("{.sh .should_panic}", true, false, false, false, false, false, false, Vec::new()); + t("{.example .rust}", false, false, false, true, false, false, false, Vec::new()); + t("{.test_harness .rust}", false, false, false, true, true, false, false, Vec::new()); + t("text, no_run", false, true, false, false, false, false, false, Vec::new()); + t("text,no_run", false, true, false, false, false, false, false, Vec::new()); } #[test] diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index cfe2fad0fa469..4766778eed1b8 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -467,7 +467,7 @@ impl Collector { pub fn add_test(&mut self, test: String, should_panic: bool, no_run: bool, should_ignore: bool, as_test_harness: bool, compile_fail: bool, error_codes: Vec, - line: usize, filename: String) { + line: usize, filename: String, allow_fail: bool) { let name = self.generate_name(line, &filename); // to be removed when hoedown is removed if self.render_type == RenderType::Pulldown { @@ -499,6 +499,7 @@ impl Collector { ignore: should_ignore, // compiler failures are test failures should_panic: testing::ShouldPanic::No, + allow_fail: allow_fail, }, testfn: testing::DynTestFn(box move |()| { let panic = io::set_panic(None); diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index d7d3a70f3c7c5..07db5b8333132 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -534,6 +534,7 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG ("derive", Normal, Ungated), ("should_panic", Normal, Ungated), ("ignore", Normal, Ungated), + ("allow_fail", Normal, Ungated), ("no_implicit_prelude", Normal, Ungated), ("reexport_test_harness_main", Normal, Ungated), ("link_args", Normal, Ungated), diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index a0d1785c6ff14..86f5f42eac796 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -52,7 +52,8 @@ struct Test { path: Vec , bench: bool, ignore: bool, - should_panic: ShouldPanic + should_panic: ShouldPanic, + allow_fail: bool, } struct TestCtxt<'a> { @@ -133,7 +134,8 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> { path: self.cx.path.clone(), bench: is_bench_fn(&self.cx, &i), ignore: is_ignored(&i), - should_panic: should_panic(&i, &self.cx) + should_panic: should_panic(&i, &self.cx), + allow_fail: is_allowed_fail(&i), }; self.cx.testfns.push(test); self.tests.push(i.ident); @@ -383,6 +385,10 @@ fn is_ignored(i: &ast::Item) -> bool { i.attrs.iter().any(|attr| attr.check_name("ignore")) } +fn is_allowed_fail(i: &ast::Item) -> bool { + i.attrs.iter().any(|attr| attr.check_name("allow_fail")) +} + fn should_panic(i: &ast::Item, cx: &TestCtxt) -> ShouldPanic { match i.attrs.iter().find(|attr| attr.check_name("should_panic")) { Some(attr) => { @@ -668,6 +674,7 @@ fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> P { } } }; + let allow_fail_expr = ecx.expr_bool(span, test.allow_fail); // self::test::TestDesc { ... } let desc_expr = ecx.expr_struct( @@ -675,7 +682,8 @@ fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> P { test_path("TestDesc"), vec![field("name", name_expr), field("ignore", ignore_expr), - field("should_panic", fail_expr)]); + field("should_panic", fail_expr), + field("allow_fail", allow_fail_expr)]); let mut visible_path = match cx.toplevel_reexport { diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 2094fd8898d49..c68039f21ec2c 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -212,6 +212,7 @@ pub struct TestDesc { pub name: TestName, pub ignore: bool, pub should_panic: ShouldPanic, + pub allow_fail: bool, } #[derive(Clone)] @@ -523,6 +524,7 @@ pub enum TestResult { TrFailed, TrFailedMsg(String), TrIgnored, + TrAllowedFail, TrMetrics(MetricMap), TrBench(BenchSamples), } @@ -543,6 +545,7 @@ struct ConsoleTestState { passed: usize, failed: usize, ignored: usize, + allowed_fail: usize, filtered_out: usize, measured: usize, metrics: MetricMap, @@ -572,6 +575,7 @@ impl ConsoleTestState { passed: 0, failed: 0, ignored: 0, + allowed_fail: 0, filtered_out: 0, measured: 0, metrics: MetricMap::new(), @@ -594,6 +598,10 @@ impl ConsoleTestState { self.write_short_result("ignored", "i", term::color::YELLOW) } + pub fn write_allowed_fail(&mut self) -> io::Result<()> { + self.write_short_result("FAILED (allowed)", "a", term::color::YELLOW) + } + pub fn write_metric(&mut self) -> io::Result<()> { self.write_pretty("metric", term::color::CYAN) } @@ -669,6 +677,7 @@ impl ConsoleTestState { TrOk => self.write_ok(), TrFailed | TrFailedMsg(_) => self.write_failed(), TrIgnored => self.write_ignored(), + TrAllowedFail => self.write_allowed_fail(), TrMetrics(ref mm) => { self.write_metric()?; self.write_plain(&format!(": {}\n", mm.fmt_metrics())) @@ -702,6 +711,7 @@ impl ConsoleTestState { TrFailed => "failed".to_owned(), TrFailedMsg(ref msg) => format!("failed: {}", msg), TrIgnored => "ignored".to_owned(), + TrAllowedFail => "failed (allowed)".to_owned(), TrMetrics(ref mm) => mm.fmt_metrics(), TrBench(ref bs) => fmt_bench_samples(bs), }, @@ -761,7 +771,7 @@ impl ConsoleTestState { } pub fn write_run_finish(&mut self) -> io::Result { - assert!(self.passed + self.failed + self.ignored + self.measured == self.total); + assert!(self.passed + self.failed + self.ignored + self.measured + self.allowed_fail == self.total); if self.options.display_output { self.write_outputs()?; @@ -778,9 +788,10 @@ impl ConsoleTestState { } else { self.write_pretty("FAILED", term::color::RED)?; } - let s = format!(". {} passed; {} failed; {} ignored; {} measured; {} filtered out\n\n", + let s = format!(". {} passed; {} failed; {} allowed to fail; {} ignored; {} measured; {} filtered out\n\n", self.passed, self.failed, + self.allowed_fail, self.ignored, self.measured, self.filtered_out); @@ -891,6 +902,7 @@ pub fn run_tests_console(opts: &TestOpts, tests: Vec) -> io::Resu st.not_failures.push((test, stdout)); } TrIgnored => st.ignored += 1, + TrAllowedFail => st.allowed_fail += 1, TrMetrics(mm) => { let tname = test.name; let MetricMap(mm) = mm; @@ -1471,8 +1483,13 @@ fn calc_result(desc: &TestDesc, task_result: Result<(), Box>) -> Tes .unwrap_or(false) { TrOk } else { - TrFailedMsg(format!("Panic did not include expected string '{}'", msg)) + if desc.allow_fail { + TrAllowedFail + } else { + TrFailedMsg(format!("Panic did not include expected string '{}'", msg)) + } }, + _ if desc.allow_fail => TrAllowedFail, _ => TrFailed, } } diff --git a/src/test/run-pass/test-allow-fail-attr.rs b/src/test/run-pass/test-allow-fail-attr.rs new file mode 100644 index 0000000000000..7d750d51dcd1b --- /dev/null +++ b/src/test/run-pass/test-allow-fail-attr.rs @@ -0,0 +1,23 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: --test + +#[test] +#[allow_fail] +fn test1() { + panic!(); +} + +#[test] +#[allow_fail] +fn test2() { + assert!(true); +} diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index c88ffba357a70..b4663b0ee6c00 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -476,6 +476,7 @@ pub fn make_test(config: &Config, testpaths: &TestPaths) -> test::TestDescAndFn name: make_test_name(config, testpaths), ignore: ignore, should_panic: should_panic, + allow_fail: false, }, testfn: make_test_closure(config, testpaths), } From 76d605255bdb53ff879488d375299127c2490a00 Mon Sep 17 00:00:00 2001 From: Paul Woolcock Date: Thu, 25 May 2017 11:36:18 -0400 Subject: [PATCH 04/18] Shorten some lines so this can pass the tidy checks --- src/librustdoc/html/markdown.rs | 34 ++++++++++++++++++--------------- src/libtest/lib.rs | 18 +++++++++-------- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 5a56c33b80663..03da451fd9a0a 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -1135,23 +1135,27 @@ mod tests { }) } + fn v() -> Vec { + Vec::new() + } + // marker | should_panic| no_run| ignore| rust | test_harness| compile_fail // | allow_fail | error_codes - t("", false, false, false, true, false, false, false, Vec::new()); - t("rust", false, false, false, true, false, false, false, Vec::new()); - t("sh", false, false, false, false, false, false, false, Vec::new()); - t("ignore", false, false, true, true, false, false, false, Vec::new()); - t("should_panic", true, false, false, true, false, false, false, Vec::new()); - t("no_run", false, true, false, true, false, false, false, Vec::new()); - t("test_harness", false, false, false, true, true, false, false, Vec::new()); - t("compile_fail", false, true, false, true, false, true, false, Vec::new()); - t("allow_fail", false, false, false, true, false, false, true, Vec::new()); - t("{.no_run .example}", false, true, false, true, false, false, false, Vec::new()); - t("{.sh .should_panic}", true, false, false, false, false, false, false, Vec::new()); - t("{.example .rust}", false, false, false, true, false, false, false, Vec::new()); - t("{.test_harness .rust}", false, false, false, true, true, false, false, Vec::new()); - t("text, no_run", false, true, false, false, false, false, false, Vec::new()); - t("text,no_run", false, true, false, false, false, false, false, Vec::new()); + t("", false, false, false, true, false, false, false, v()); + t("rust", false, false, false, true, false, false, false, v()); + t("sh", false, false, false, false, false, false, false, v()); + t("ignore", false, false, true, true, false, false, false, v()); + t("should_panic", true, false, false, true, false, false, false, v()); + t("no_run", false, true, false, true, false, false, false, v()); + t("test_harness", false, false, false, true, true, false, false, v()); + t("compile_fail", false, true, false, true, false, true, false, v()); + t("allow_fail", false, false, false, true, false, false, true, v()); + t("{.no_run .example}", false, true, false, true, false, false, false, v()); + t("{.sh .should_panic}", true, false, false, false, false, false, false, v()); + t("{.example .rust}", false, false, false, true, false, false, false, v()); + t("{.test_harness .rust}", false, false, false, true, true, false, false, v()); + t("text, no_run", false, true, false, false, false, false, false, v()); + t("text,no_run", false, true, false, false, false, false, false, v()); } #[test] diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index c68039f21ec2c..7a09883a72ea8 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -771,7 +771,8 @@ impl ConsoleTestState { } pub fn write_run_finish(&mut self) -> io::Result { - assert!(self.passed + self.failed + self.ignored + self.measured + self.allowed_fail == self.total); + assert!(self.passed + self.failed + self.ignored + self.measured + + self.allowed_fail == self.total); if self.options.display_output { self.write_outputs()?; @@ -788,13 +789,14 @@ impl ConsoleTestState { } else { self.write_pretty("FAILED", term::color::RED)?; } - let s = format!(". {} passed; {} failed; {} allowed to fail; {} ignored; {} measured; {} filtered out\n\n", - self.passed, - self.failed, - self.allowed_fail, - self.ignored, - self.measured, - self.filtered_out); + let s = format!( + ". {} passed; {} failed ({} allowed); {} ignored; {} measured; {} filtered out\n\n", + self.passed, + self.failed, + self.allowed_fail, + self.ignored, + self.measured, + self.filtered_out); self.write_plain(&s)?; return Ok(success); } From 7ad95378128bb267885ea17001af32388d451523 Mon Sep 17 00:00:00 2001 From: Paul Woolcock Date: Thu, 25 May 2017 16:17:29 -0400 Subject: [PATCH 05/18] fix some tests i missed --- src/libtest/lib.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 7a09883a72ea8..0567be4e604a2 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -959,12 +959,14 @@ fn should_sort_failures_before_printing_them() { name: StaticTestName("a"), ignore: false, should_panic: ShouldPanic::No, + allow_fail: false, }; let test_b = TestDesc { name: StaticTestName("b"), ignore: false, should_panic: ShouldPanic::No, + allow_fail: false, }; let mut st = ConsoleTestState { @@ -976,6 +978,7 @@ fn should_sort_failures_before_printing_them() { passed: 0, failed: 0, ignored: 0, + allowed_fail: 0, filtered_out: 0, measured: 0, max_name_len: 10, @@ -1725,6 +1728,7 @@ mod tests { name: StaticTestName("whatever"), ignore: true, should_panic: ShouldPanic::No, + allow_fail: false, }, testfn: DynTestFn(Box::new(move |()| f())), }; @@ -1742,6 +1746,7 @@ mod tests { name: StaticTestName("whatever"), ignore: true, should_panic: ShouldPanic::No, + allow_fail: false, }, testfn: DynTestFn(Box::new(move |()| f())), }; @@ -1761,6 +1766,7 @@ mod tests { name: StaticTestName("whatever"), ignore: false, should_panic: ShouldPanic::Yes, + allow_fail: false, }, testfn: DynTestFn(Box::new(move |()| f())), }; @@ -1780,6 +1786,7 @@ mod tests { name: StaticTestName("whatever"), ignore: false, should_panic: ShouldPanic::YesWithMessage("error message"), + allow_fail: false, }, testfn: DynTestFn(Box::new(move |()| f())), }; @@ -1801,6 +1808,7 @@ mod tests { name: StaticTestName("whatever"), ignore: false, should_panic: ShouldPanic::YesWithMessage(expected), + allow_fail: false, }, testfn: DynTestFn(Box::new(move |()| f())), }; @@ -1818,6 +1826,7 @@ mod tests { name: StaticTestName("whatever"), ignore: false, should_panic: ShouldPanic::Yes, + allow_fail: false, }, testfn: DynTestFn(Box::new(move |()| f())), }; @@ -1851,6 +1860,7 @@ mod tests { name: StaticTestName("1"), ignore: true, should_panic: ShouldPanic::No, + allow_fail: false, }, testfn: DynTestFn(Box::new(move |()| {})), }, @@ -1859,6 +1869,7 @@ mod tests { name: StaticTestName("2"), ignore: false, should_panic: ShouldPanic::No, + allow_fail: false, }, testfn: DynTestFn(Box::new(move |()| {})), }]; @@ -1882,6 +1893,7 @@ mod tests { name: StaticTestName(name), ignore: false, should_panic: ShouldPanic::No, + allow_fail: false, }, testfn: DynTestFn(Box::new(move |()| {})) }) @@ -1963,6 +1975,7 @@ mod tests { name: DynTestName((*name).clone()), ignore: false, should_panic: ShouldPanic::No, + allow_fail: false, }, testfn: DynTestFn(Box::new(move |()| testfn())), }; From 45af6ee4fcaf4a0f0dcd72ac8a38681700590b98 Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Sat, 24 Jun 2017 18:23:39 +0300 Subject: [PATCH 06/18] Move global vars changing tests into run-pass Should fix race #42795 --- src/libstd/env.rs | 82 +-------------------------------- src/test/run-pass/env.rs | 98 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 81 deletions(-) create mode 100644 src/test/run-pass/env.rs diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 1dfae0ce83f62..f81adad3ebebf 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -949,63 +949,9 @@ mod arch { mod tests { use super::*; - use iter::repeat; - use rand::{self, Rng}; - use ffi::{OsString, OsStr}; + use ffi::OsStr; use path::{Path, PathBuf}; - fn make_rand_name() -> OsString { - let mut rng = rand::thread_rng(); - let n = format!("TEST{}", rng.gen_ascii_chars().take(10) - .collect::()); - let n = OsString::from(n); - assert!(var_os(&n).is_none()); - n - } - - fn eq(a: Option, b: Option<&str>) { - assert_eq!(a.as_ref().map(|s| &**s), b.map(OsStr::new).map(|s| &*s)); - } - - #[test] - fn test_set_var() { - let n = make_rand_name(); - set_var(&n, "VALUE"); - eq(var_os(&n), Some("VALUE")); - } - - #[test] - fn test_remove_var() { - let n = make_rand_name(); - set_var(&n, "VALUE"); - remove_var(&n); - eq(var_os(&n), None); - } - - #[test] - fn test_set_var_overwrite() { - let n = make_rand_name(); - set_var(&n, "1"); - set_var(&n, "2"); - eq(var_os(&n), Some("2")); - set_var(&n, ""); - eq(var_os(&n), Some("")); - } - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn test_var_big() { - let mut s = "".to_string(); - let mut i = 0; - while i < 100 { - s.push_str("aaaaaaaaaa"); - i += 1; - } - let n = make_rand_name(); - set_var(&n, &s); - eq(var_os(&n), Some(&s)); - } - #[test] #[cfg_attr(target_os = "emscripten", ignore)] fn test_self_exe_path() { @@ -1017,32 +963,6 @@ mod tests { assert!(path.is_absolute()); } - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn test_env_set_get_huge() { - let n = make_rand_name(); - let s = repeat("x").take(10000).collect::(); - set_var(&n, &s); - eq(var_os(&n), Some(&s)); - remove_var(&n); - eq(var_os(&n), None); - } - - #[test] - fn test_env_set_var() { - let n = make_rand_name(); - - let mut e = vars_os(); - set_var(&n, "VALUE"); - assert!(!e.any(|(k, v)| { - &*k == &*n && &*v == "VALUE" - })); - - assert!(vars_os().any(|(k, v)| { - &*k == &*n && &*v == "VALUE" - })); - } - #[test] fn test() { assert!((!Path::new("test-path").is_absolute())); diff --git a/src/test/run-pass/env.rs b/src/test/run-pass/env.rs new file mode 100644 index 0000000000000..e602fb2d7d29a --- /dev/null +++ b/src/test/run-pass/env.rs @@ -0,0 +1,98 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: --test + +#![feature(rand, std_panic)] + +use std::env::*; +use std::__rand as rand; +use std::__rand::Rng; +use std::iter::repeat; +use std::ffi::{OsString, OsStr}; + + +fn make_rand_name() -> OsString { + let mut rng = rand::thread_rng(); + let n = format!("TEST{}", rng.gen_ascii_chars().take(10) + .collect::()); + let n = OsString::from(n); + assert!(var_os(&n).is_none()); + n +} + +fn eq(a: Option, b: Option<&str>) { + assert_eq!(a.as_ref().map(|s| &**s), b.map(OsStr::new).map(|s| &*s)); +} + +#[test] +fn test_set_var() { + let n = make_rand_name(); + set_var(&n, "VALUE"); + eq(var_os(&n), Some("VALUE")); +} + +#[test] +fn test_remove_var() { + let n = make_rand_name(); + set_var(&n, "VALUE"); + remove_var(&n); + eq(var_os(&n), None); +} + +#[test] +fn test_set_var_overwrite() { + let n = make_rand_name(); + set_var(&n, "1"); + set_var(&n, "2"); + eq(var_os(&n), Some("2")); + set_var(&n, ""); + eq(var_os(&n), Some("")); +} + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn test_var_big() { + let mut s = "".to_string(); + let mut i = 0; + while i < 100 { + s.push_str("aaaaaaaaaa"); + i += 1; + } + let n = make_rand_name(); + set_var(&n, &s); + eq(var_os(&n), Some(&s)); +} + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn test_env_set_get_huge() { + let n = make_rand_name(); + let s = repeat("x").take(10000).collect::(); + set_var(&n, &s); + eq(var_os(&n), Some(&s)); + remove_var(&n); + eq(var_os(&n), None); +} + +#[test] +fn test_env_set_var() { + let n = make_rand_name(); + + let mut e = vars_os(); + set_var(&n, "VALUE"); + assert!(!e.any(|(k, v)| { + &*k == &*n && &*v == "VALUE" + })); + + assert!(vars_os().any(|(k, v)| { + &*k == &*n && &*v == "VALUE" + })); +} From 8e5a3023c9ef299be6a617bca55ad16d12ce1036 Mon Sep 17 00:00:00 2001 From: Paul Woolcock Date: Fri, 23 Jun 2017 09:43:28 -0400 Subject: [PATCH 07/18] Add a feature gate for the `#[allow_fail]` attribute --- src/libsyntax/feature_gate.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 07db5b8333132..74bf19b841e88 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -354,6 +354,9 @@ declare_features! ( // rustc internal (active, abi_thiscall, "1.19.0", None), + + // Allows a test to fail without failing the whole suite + (active, allow_fail, "1.19.0", Some(42219)), ); declare_features! ( @@ -534,7 +537,6 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG ("derive", Normal, Ungated), ("should_panic", Normal, Ungated), ("ignore", Normal, Ungated), - ("allow_fail", Normal, Ungated), ("no_implicit_prelude", Normal, Ungated), ("reexport_test_harness_main", Normal, Ungated), ("link_args", Normal, Ungated), @@ -813,6 +815,11 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG "used internally by rustc", cfg_fn!(rustc_attrs))), + ("allow_fail", Normal, Gated(Stability::Unstable, + "allow_fail", + "allow_fail attribute is currently unstable", + cfg_fn!(allow_fail))), + // Crate level attributes ("crate_name", CrateLevel, Ungated), ("crate_type", CrateLevel, Ungated), From 8edc3cae3bd853fc0d7714c2135754dce0ba10eb Mon Sep 17 00:00:00 2001 From: Paul Woolcock Date: Fri, 23 Jun 2017 11:01:41 -0400 Subject: [PATCH 08/18] Add compile-fail test for the new feature gate --- .../compile-fail/feature-gate-allow_fail.rs | 17 +++++++++++++++++ src/test/run-pass/test-allow-fail-attr.rs | 1 + 2 files changed, 18 insertions(+) create mode 100644 src/test/compile-fail/feature-gate-allow_fail.rs diff --git a/src/test/compile-fail/feature-gate-allow_fail.rs b/src/test/compile-fail/feature-gate-allow_fail.rs new file mode 100644 index 0000000000000..1124740280960 --- /dev/null +++ b/src/test/compile-fail/feature-gate-allow_fail.rs @@ -0,0 +1,17 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// check that #[allow_fail] is feature-gated + +#[allow_fail] //~ ERROR allow_fail attribute is currently unstable +fn ok_to_fail() { + assert!(false); +} + diff --git a/src/test/run-pass/test-allow-fail-attr.rs b/src/test/run-pass/test-allow-fail-attr.rs index 7d750d51dcd1b..aa9cf76617f69 100644 --- a/src/test/run-pass/test-allow-fail-attr.rs +++ b/src/test/run-pass/test-allow-fail-attr.rs @@ -9,6 +9,7 @@ // except according to those terms. // compile-flags: --test +#![feature(allow_fail)] #[test] #[allow_fail] From 4154f895d388b1a8634a95ff76892419bebe9cc3 Mon Sep 17 00:00:00 2001 From: Paul Woolcock Date: Sat, 24 Jun 2017 20:37:15 -0400 Subject: [PATCH 09/18] only show allowed failure count if there are allowed failures --- src/libtest/lib.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 0567be4e604a2..92cfb862b1669 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -789,14 +789,24 @@ impl ConsoleTestState { } else { self.write_pretty("FAILED", term::color::RED)?; } - let s = format!( + let s = if self.allowed_fail > 0 { + format!( ". {} passed; {} failed ({} allowed); {} ignored; {} measured; {} filtered out\n\n", self.passed, - self.failed, + self.failed + self.allowed_fail, self.allowed_fail, self.ignored, self.measured, - self.filtered_out); + self.filtered_out) + } else { + format!( + ". {} passed; {} failed; {} ignored; {} measured; {} filtered out\n\n", + self.passed, + self.failed, + self.ignored, + self.measured, + self.filtered_out) + }; self.write_plain(&s)?; return Ok(success); } From d24d408af387e99e7237f21e9a8d13a35552e01a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 25 Jun 2017 11:33:47 -0700 Subject: [PATCH 10/18] std: Fix implementation of `Alloc::alloc_one` This had an accidental `u8 as *mut T` where it was intended to have just a normal pointer-to-pointer cast. Closes #42827 --- src/liballoc/allocator.rs | 2 +- src/test/run-pass/allocator-alloc-one.rs | 27 ++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/allocator-alloc-one.rs diff --git a/src/liballoc/allocator.rs b/src/liballoc/allocator.rs index 9bddce29957e1..bf38629ed38a7 100644 --- a/src/liballoc/allocator.rs +++ b/src/liballoc/allocator.rs @@ -873,7 +873,7 @@ pub unsafe trait Alloc { { let k = Layout::new::(); if k.size() > 0 { - unsafe { self.alloc(k).map(|p|Unique::new(*p as *mut T)) } + unsafe { self.alloc(k).map(|p| Unique::new(p as *mut T)) } } else { Err(AllocErr::invalid_input("zero-sized type invalid for alloc_one")) } diff --git a/src/test/run-pass/allocator-alloc-one.rs b/src/test/run-pass/allocator-alloc-one.rs new file mode 100644 index 0000000000000..7cc547dcc04e2 --- /dev/null +++ b/src/test/run-pass/allocator-alloc-one.rs @@ -0,0 +1,27 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(alloc, allocator_api, heap_api, unique)] + +extern crate alloc; + +use alloc::heap::HeapAlloc; +use alloc::allocator::Alloc; + +fn main() { + unsafe { + let ptr = HeapAlloc.alloc_one::().unwrap_or_else(|e| { + HeapAlloc.oom(e) + }); + *ptr.as_ptr() = 4; + assert_eq!(*ptr.as_ptr(), 4); + HeapAlloc.dealloc_one(ptr); + } +} From 32b8579b6826091e11ea6d90a2d64f4975894032 Mon Sep 17 00:00:00 2001 From: "Zack M. Davis" Date: Mon, 26 Jun 2017 13:30:21 -0700 Subject: [PATCH 11/18] make lint on-by-default/implied-by messages appear only once From review discussion on #38103 (https://github.com/rust-lang/rust/pull/38103#discussion_r94845060). --- src/librustc/lint/context.rs | 26 +++++----- src/librustc/session/mod.rs | 60 +++++++++++++++++------- src/test/ui/lint/lint-group-style.stderr | 10 ++-- src/test/ui/path-lookahead.stderr | 2 - src/test/ui/span/issue-24690.stderr | 6 +-- 5 files changed, 63 insertions(+), 41 deletions(-) diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index a9e0ef511024f..1a0ab8c413d34 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -513,7 +513,6 @@ pub fn raw_struct_lint<'a, S>(sess: &'a Session, } let name = lint.name_lower(); - let mut def = None; // Except for possible note details, forbid behaves like deny. let effective_level = if level == Forbid { Deny } else { level }; @@ -528,7 +527,8 @@ pub fn raw_struct_lint<'a, S>(sess: &'a Session, match source { Default => { - err.note(&format!("#[{}({})] on by default", level.as_str(), name)); + sess.diag_note_once(&mut err, lint, + &format!("#[{}({})] on by default", level.as_str(), name)); }, CommandLine(lint_flag_val) => { let flag = match level { @@ -537,20 +537,24 @@ pub fn raw_struct_lint<'a, S>(sess: &'a Session, }; let hyphen_case_lint_name = name.replace("_", "-"); if lint_flag_val.as_str() == name { - err.note(&format!("requested on the command line with `{} {}`", - flag, hyphen_case_lint_name)); + sess.diag_note_once(&mut err, lint, + &format!("requested on the command line with `{} {}`", + flag, hyphen_case_lint_name)); } else { let hyphen_case_flag_val = lint_flag_val.as_str().replace("_", "-"); - err.note(&format!("`{} {}` implied by `{} {}`", - flag, hyphen_case_lint_name, flag, hyphen_case_flag_val)); + sess.diag_note_once(&mut err, lint, + &format!("`{} {}` implied by `{} {}`", + flag, hyphen_case_lint_name, flag, + hyphen_case_flag_val)); } }, Node(lint_attr_name, src) => { - def = Some(src); + sess.diag_span_note_once(&mut err, lint, src, "lint level defined here"); if lint_attr_name.as_str() != name { let level_str = level.as_str(); - err.note(&format!("#[{}({})] implied by #[{}({})]", - level_str, name, level_str, lint_attr_name)); + sess.diag_note_once(&mut err, lint, + &format!("#[{}({})] implied by #[{}({})]", + level_str, name, level_str, lint_attr_name)); } } } @@ -566,10 +570,6 @@ pub fn raw_struct_lint<'a, S>(sess: &'a Session, err.note(&citation); } - if let Some(span) = def { - sess.diag_span_note_once(&mut err, lint, span, "lint level defined here"); - } - err } diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 70c07982f83cb..fb513f573d7e2 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -79,10 +79,10 @@ pub struct Session { pub working_dir: (String, bool), pub lint_store: RefCell, pub lints: RefCell, - /// Set of (LintId, span, message) tuples tracking lint (sub)diagnostics - /// that have been set once, but should not be set again, in order to avoid - /// redundantly verbose output (Issue #24690). - pub one_time_diagnostics: RefCell>, + /// Set of (LintId, Option, message) tuples tracking lint + /// (sub)diagnostics that have been set once, but should not be set again, + /// in order to avoid redundantly verbose output (Issue #24690). + pub one_time_diagnostics: RefCell, String)>>, pub plugin_llvm_passes: RefCell>, pub plugin_attributes: RefCell>, pub crate_types: RefCell>, @@ -157,6 +157,13 @@ pub struct PerfStats { pub decode_def_path_tables_time: Cell, } +/// Enum to support dispatch of one-time diagnostics (in Session.diag_once) +enum DiagnosticBuilderMethod { + Note, + SpanNote, + // add more variants as needed to support one-time diagnostics +} + impl Session { pub fn local_crate_disambiguator(&self) -> Symbol { *self.crate_disambiguator.borrow() @@ -329,34 +336,53 @@ impl Session { &self.parse_sess.span_diagnostic } - /// Analogous to calling `.span_note` on the given DiagnosticBuilder, but - /// deduplicates on lint ID, span, and message for this `Session` if we're - /// not outputting in JSON mode. - // - // FIXME: if the need arises for one-time diagnostics other than - // `span_note`, we almost certainly want to generalize this - // "check/insert-into the one-time diagnostics map, then set message if - // it's not already there" code to accomodate all of them - pub fn diag_span_note_once<'a, 'b>(&'a self, - diag_builder: &'b mut DiagnosticBuilder<'a>, - lint: &'static lint::Lint, span: Span, message: &str) { + /// Analogous to calling methods on the given `DiagnosticBuilder`, but + /// deduplicates on lint ID, span (if any), and message for this `Session` + /// if we're not outputting in JSON mode. + fn diag_once<'a, 'b>(&'a self, + diag_builder: &'b mut DiagnosticBuilder<'a>, + method: DiagnosticBuilderMethod, + lint: &'static lint::Lint, message: &str, span: Option) { + let mut do_method = || { + match method { + DiagnosticBuilderMethod::Note => { + diag_builder.note(message); + }, + DiagnosticBuilderMethod::SpanNote => { + diag_builder.span_note(span.expect("span_note expects a span"), message); + } + } + }; + match self.opts.error_format { // when outputting JSON for tool consumption, the tool might want // the duplicates config::ErrorOutputType::Json => { - diag_builder.span_note(span, &message); + do_method() }, _ => { let lint_id = lint::LintId::of(lint); let id_span_message = (lint_id, span, message.to_owned()); let fresh = self.one_time_diagnostics.borrow_mut().insert(id_span_message); if fresh { - diag_builder.span_note(span, &message); + do_method() } } } } + pub fn diag_span_note_once<'a, 'b>(&'a self, + diag_builder: &'b mut DiagnosticBuilder<'a>, + lint: &'static lint::Lint, span: Span, message: &str) { + self.diag_once(diag_builder, DiagnosticBuilderMethod::SpanNote, lint, message, Some(span)); + } + + pub fn diag_note_once<'a, 'b>(&'a self, + diag_builder: &'b mut DiagnosticBuilder<'a>, + lint: &'static lint::Lint, message: &str) { + self.diag_once(diag_builder, DiagnosticBuilderMethod::Note, lint, message, None); + } + pub fn codemap<'a>(&'a self) -> &'a codemap::CodeMap { self.parse_sess.codemap() } diff --git a/src/test/ui/lint/lint-group-style.stderr b/src/test/ui/lint/lint-group-style.stderr index dec44c317e4b2..636370de302b6 100644 --- a/src/test/ui/lint/lint-group-style.stderr +++ b/src/test/ui/lint/lint-group-style.stderr @@ -4,12 +4,12 @@ error: function `CamelCase` should have a snake case name such as `camel_case` 14 | fn CamelCase() {} | ^^^^^^^^^^^^^^^^^ | - = note: #[deny(non_snake_case)] implied by #[deny(bad_style)] note: lint level defined here --> $DIR/lint-group-style.rs:11:9 | 11 | #![deny(bad_style)] | ^^^^^^^^^ + = note: #[deny(non_snake_case)] implied by #[deny(bad_style)] error: function `CamelCase` should have a snake case name such as `camel_case` --> $DIR/lint-group-style.rs:22:9 @@ -17,12 +17,12 @@ error: function `CamelCase` should have a snake case name such as `camel_case` 22 | fn CamelCase() {} | ^^^^^^^^^^^^^^^^^ | - = note: #[forbid(non_snake_case)] implied by #[forbid(bad_style)] note: lint level defined here --> $DIR/lint-group-style.rs:20:14 | 20 | #[forbid(bad_style)] | ^^^^^^^^^ + = note: #[forbid(non_snake_case)] implied by #[forbid(bad_style)] error: static variable `bad` should have an upper case name such as `BAD` --> $DIR/lint-group-style.rs:24:9 @@ -30,12 +30,12 @@ error: static variable `bad` should have an upper case name such as `BAD` 24 | static bad: isize = 1; | ^^^^^^^^^^^^^^^^^^^^^^ | - = note: #[forbid(non_upper_case_globals)] implied by #[forbid(bad_style)] note: lint level defined here --> $DIR/lint-group-style.rs:20:14 | 20 | #[forbid(bad_style)] | ^^^^^^^^^ + = note: #[forbid(non_upper_case_globals)] implied by #[forbid(bad_style)] warning: function `CamelCase` should have a snake case name such as `camel_case` --> $DIR/lint-group-style.rs:30:9 @@ -43,12 +43,12 @@ warning: function `CamelCase` should have a snake case name such as `camel_case` 30 | fn CamelCase() {} | ^^^^^^^^^^^^^^^^^ | - = note: #[warn(non_snake_case)] implied by #[warn(bad_style)] note: lint level defined here --> $DIR/lint-group-style.rs:28:17 | 28 | #![warn(bad_style)] | ^^^^^^^^^ + = note: #[warn(non_snake_case)] implied by #[warn(bad_style)] warning: type `snake_case` should have a camel case name such as `SnakeCase` --> $DIR/lint-group-style.rs:32:9 @@ -56,12 +56,12 @@ warning: type `snake_case` should have a camel case name such as `SnakeCase` 32 | struct snake_case; | ^^^^^^^^^^^^^^^^^^ | - = note: #[warn(non_camel_case_types)] implied by #[warn(bad_style)] note: lint level defined here --> $DIR/lint-group-style.rs:28:17 | 28 | #![warn(bad_style)] | ^^^^^^^^^ + = note: #[warn(non_camel_case_types)] implied by #[warn(bad_style)] error: aborting due to previous error(s) diff --git a/src/test/ui/path-lookahead.stderr b/src/test/ui/path-lookahead.stderr index 1e19977e84a3d..8fd1b8de68787 100644 --- a/src/test/ui/path-lookahead.stderr +++ b/src/test/ui/path-lookahead.stderr @@ -23,6 +23,4 @@ warning: function is never used: `no_parens` 20 | | return ::to_string(&arg); 21 | | } | |_^ - | - = note: #[warn(dead_code)] on by default diff --git a/src/test/ui/span/issue-24690.stderr b/src/test/ui/span/issue-24690.stderr index 598f9f5130781..edc150f65eafc 100644 --- a/src/test/ui/span/issue-24690.stderr +++ b/src/test/ui/span/issue-24690.stderr @@ -4,20 +4,18 @@ error: variable `theTwo` should have a snake case name such as `the_two` 19 | let theTwo = 2; | ^^^^^^ | - = note: #[deny(non_snake_case)] implied by #[deny(warnings)] note: lint level defined here --> $DIR/issue-24690.rs:16:9 | 16 | #![deny(warnings)] | ^^^^^^^^ + = note: #[deny(non_snake_case)] implied by #[deny(warnings)] error: variable `theOtherTwo` should have a snake case name such as `the_other_two` --> $DIR/issue-24690.rs:20:9 | 20 | let theOtherTwo = 2; | ^^^^^^^^^^^ - | - = note: #[deny(non_snake_case)] implied by #[deny(warnings)] error: unused variable: `theOtherTwo` --> $DIR/issue-24690.rs:20:9 @@ -25,12 +23,12 @@ error: unused variable: `theOtherTwo` 20 | let theOtherTwo = 2; | ^^^^^^^^^^^ | - = note: #[deny(unused_variables)] implied by #[deny(warnings)] note: lint level defined here --> $DIR/issue-24690.rs:16:9 | 16 | #![deny(warnings)] | ^^^^^^^^ + = note: #[deny(unused_variables)] implied by #[deny(warnings)] error: aborting due to previous error(s) From 330dab837fb872051b365715f1532eb8156c33ae Mon Sep 17 00:00:00 2001 From: Behnam Esfahbod Date: Mon, 26 Jun 2017 18:27:01 -0600 Subject: [PATCH 12/18] [libcore/cmp] Expand Ord/PartialOrd Derivable doc for enum types Expand Derivable docblock section for `Ord` and `PartialOrd` to cover `enum` types, in addition to the existing language explaining it for `struct` types. --- src/libcore/cmp.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 6f35d0417f18b..2e691ea4af26e 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -380,8 +380,9 @@ impl Ord for Reverse { /// /// ## Derivable /// -/// This trait can be used with `#[derive]`. When `derive`d, it will produce a lexicographic -/// ordering based on the top-to-bottom declaration order of the struct's members. +/// This trait can be used with `#[derive]`. When `derive`d on structs, it will produce a +/// lexicographic ordering based on the top-to-bottom declaration order of the struct's members. +/// When `derive`d on enums, variants are ordered by their top-to-bottom declaration order. /// /// ## How can I implement `Ord`? /// @@ -513,8 +514,9 @@ impl PartialOrd for Ordering { /// /// ## Derivable /// -/// This trait can be used with `#[derive]`. When `derive`d, it will produce a lexicographic -/// ordering based on the top-to-bottom declaration order of the struct's members. +/// This trait can be used with `#[derive]`. When `derive`d on structs, it will produce a +/// lexicographic ordering based on the top-to-bottom declaration order of the struct's members. +/// When `derive`d on enums, variants are ordered by their top-to-bottom declaration order. /// /// ## How can I implement `PartialOrd`? /// From 0dfd9c30f2c61458343e0816c66f448019e826d1 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Sat, 24 Jun 2017 18:26:04 +0000 Subject: [PATCH 13/18] syntax: allow negative integer literal expression to be interpolated as pattern --- src/librustc_lint/builtin.rs | 10 ++---- src/librustc_passes/ast_validation.rs | 26 ++++++++++++++ src/libsyntax/parse/parser.rs | 4 ++- .../compile-fail/patkind-litrange-no-expr.rs | 36 +++++++++++++++++++ src/test/run-pass/macro-pat-neg-lit.rs | 35 ++++++++++++++++++ 5 files changed, 103 insertions(+), 8 deletions(-) create mode 100644 src/test/compile-fail/patkind-litrange-no-expr.rs create mode 100644 src/test/run-pass/macro-pat-neg-lit.rs diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 9800012917c50..57843047f51a1 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -684,13 +684,9 @@ fn fl_lit_check_expr(cx: &EarlyContext, expr: &ast::Expr) { // These may occur in patterns // and can maybe contain float literals ExprKind::Unary(_, ref f) => fl_lit_check_expr(cx, f), - // These may occur in patterns - // and can't contain float literals - ExprKind::Path(..) => (), - // If something unhandled is encountered, we need to expand the - // search or ignore more ExprKinds. - _ => span_bug!(expr.span, "Unhandled expression {:?} in float lit pattern lint", - expr.node), + // Other kinds of exprs can't occur in patterns so we don't have to check them + // (ast_validation will emit an error if they occur) + _ => (), } } diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 7c443a4ac7520..6ad03186dc778 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -93,6 +93,17 @@ impl<'a> AstValidator<'a> { } } } + + /// matches '-' lit | lit (cf. parser::Parser::parse_pat_literal_maybe_minus) + fn check_expr_within_pat(&self, expr: &Expr) { + match expr.node { + ExprKind::Lit(..) | ExprKind::Path(..) => {} + ExprKind::Unary(UnOp::Neg, ref inner) + if match inner.node { ExprKind::Lit(_) => true, _ => false } => {} + _ => self.err_handler().span_err(expr.span, "arbitrary expressions aren't allowed \ + in patterns") + } + } } impl<'a> Visitor<'a> for AstValidator<'a> { @@ -308,6 +319,21 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } visit::walk_generics(self, g) } + + fn visit_pat(&mut self, pat: &'a Pat) { + match pat.node { + PatKind::Lit(ref expr) => { + self.check_expr_within_pat(expr); + } + PatKind::Range(ref start, ref end, _) => { + self.check_expr_within_pat(start); + self.check_expr_within_pat(end); + } + _ => {} + } + + visit::walk_pat(self, pat) + } } pub fn check_crate(session: &Session, krate: &Crate) { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 851a638e14842..5b0031b2f179f 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1659,8 +1659,10 @@ impl<'a> Parser<'a> { Ok(codemap::Spanned { node: lit, span: lo.to(self.prev_span) }) } - /// matches '-' lit | lit + /// matches '-' lit | lit (cf. ast_validation::AstValidator::check_expr_within_pat) pub fn parse_pat_literal_maybe_minus(&mut self) -> PResult<'a, P> { + maybe_whole_expr!(self); + let minus_lo = self.span; let minus_present = self.eat(&token::BinOp(token::Minus)); let lo = self.span; diff --git a/src/test/compile-fail/patkind-litrange-no-expr.rs b/src/test/compile-fail/patkind-litrange-no-expr.rs new file mode 100644 index 0000000000000..afb2cbb7db397 --- /dev/null +++ b/src/test/compile-fail/patkind-litrange-no-expr.rs @@ -0,0 +1,36 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +macro_rules! enum_number { + ($name:ident { $($variant:ident = $value:expr, )* }) => { + enum $name { + $($variant = $value,)* + } + + fn foo(value: i32) -> Option<$name> { + match value { + $( $value => Some($name::$variant), )* // PatKind::Lit + $( $value ... 42 => Some($name::$variant), )* // PatKind::Range + _ => None + } + } + } +} + +enum_number!(Change { + Pos = 1, + Neg = -1, + Arith = 1 + 1, //~ ERROR arbitrary expressions aren't allowed in patterns + //~^ ERROR arbitrary expressions aren't allowed in patterns + //~^^ ERROR only char and numeric types are allowed in range patterns +}); + +fn main() {} + diff --git a/src/test/run-pass/macro-pat-neg-lit.rs b/src/test/run-pass/macro-pat-neg-lit.rs new file mode 100644 index 0000000000000..43ac697edced9 --- /dev/null +++ b/src/test/run-pass/macro-pat-neg-lit.rs @@ -0,0 +1,35 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +macro_rules! enum_number { + ($name:ident { $($variant:ident = $value:expr, )* }) => { + enum $name { + $($variant = $value,)* + } + + fn foo(value: i32) -> Option<$name> { + match value { + $( $value => Some($name::$variant), )* + _ => None + } + } + } +} + +enum_number!(Change { + Down = -1, + None = 0, + Up = 1, +}); + +fn main() { + if let Some(Change::Down) = foo(-1) {} else { panic!() } +} + From 4fb67dcf8f51e0a875ec7f00a3ef2649758b9b9a Mon Sep 17 00:00:00 2001 From: Andreas Sommer Date: Wed, 28 Jun 2017 10:55:57 +0200 Subject: [PATCH 14/18] Fix link reference --- src/doc/unstable-book/src/language-features/compile-error.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/unstable-book/src/language-features/compile-error.md b/src/doc/unstable-book/src/language-features/compile-error.md index 1b25eeda3f662..4b24c0a6a0d39 100644 --- a/src/doc/unstable-book/src/language-features/compile-error.md +++ b/src/doc/unstable-book/src/language-features/compile-error.md @@ -2,7 +2,7 @@ The tracking issue for this feature is: [#40872] -[#29599]: https://github.com/rust-lang/rust/issues/40872 +[#40872]: https://github.com/rust-lang/rust/issues/40872 ------------------------ From 40dec0984ed2040532ac763f104b3bbbc13f514a Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 28 Jun 2017 23:14:06 +0300 Subject: [PATCH 15/18] Document that `/` works as separator on Windows --- src/libstd/path.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 42a54ed6d754c..472ce6bc4fe9e 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -276,7 +276,7 @@ impl<'a> Prefix<'a> { /// ``` /// use std::path; /// -/// assert!(path::is_separator('/')); +/// assert!(path::is_separator('/')); // '/' works for both Unix and Windows /// assert!(!path::is_separator('❤')); /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -1499,9 +1499,9 @@ impl AsRef for PathBuf { /// A slice of a path (akin to [`str`]). /// /// This type supports a number of operations for inspecting a path, including -/// breaking the path into its components (separated by `/` or `\`, depending on -/// the platform), extracting the file name, determining whether the path is -/// absolute, and so on. +/// breaking the path into its components (separated by `/` on Unix and by either +/// `/` or `\` on Windows), extracting the file name, determining whether the path +/// is absolute, and so on. /// /// This is an *unsized* type, meaning that it must always be used behind a /// pointer like `&` or [`Box`]. For an owned version of this type, @@ -1520,10 +1520,11 @@ impl AsRef for PathBuf { /// use std::path::Path; /// use std::ffi::OsStr; /// -/// let path = Path::new("/tmp/foo/bar.txt"); +/// // Note: this example does work on Windows +/// let path = Path::new("./foo/bar.txt"); /// /// let parent = path.parent(); -/// assert_eq!(parent, Some(Path::new("/tmp/foo"))); +/// assert_eq!(parent, Some(Path::new("./foo"))); /// /// let file_stem = path.file_stem(); /// assert_eq!(file_stem, Some(OsStr::new("bar"))); From b689e46c628ea8f71f45709c969b19c220baa49c Mon Sep 17 00:00:00 2001 From: Aidan Hobson Sayers Date: Wed, 28 Jun 2017 22:54:05 +0100 Subject: [PATCH 16/18] Stamp the whole build script --- .travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index b95196da356c8..96163c75c9d9d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -171,16 +171,16 @@ before_script: if [[ "$SKIP_BUILD" == true ]]; then export RUN_SCRIPT="echo 'skipping, not a full build'"; else - RUN_SCRIPT="stamp src/ci/init_repo.sh . $HOME/rustsrc"; + RUN_SCRIPT="src/ci/init_repo.sh . $HOME/rustsrc"; if [ "$TRAVIS_OS_NAME" = "osx" ]; then - export RUN_SCRIPT="$RUN_SCRIPT && stamp src/ci/run.sh"; + export RUN_SCRIPT="$RUN_SCRIPT && src/ci/run.sh"; else - export RUN_SCRIPT="$RUN_SCRIPT && stamp src/ci/docker/run.sh $IMAGE"; + export RUN_SCRIPT="$RUN_SCRIPT && src/ci/docker/run.sh $IMAGE"; fi fi script: - - sh -x -c "$RUN_SCRIPT" + - stamp sh -x -c "$RUN_SCRIPT" after_success: - > From 5ed38946beaaad4ece7ad43bc3d03db7e8972401 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 28 Jun 2017 11:09:00 -0700 Subject: [PATCH 17/18] Move type parameter shadowing test to `ui` --- .../shadowed-type-parameter.rs | 0 src/test/ui/shadowed-type-parameter.stderr | 28 +++++++++++++++++++ 2 files changed, 28 insertions(+) rename src/test/{compile-fail => ui}/shadowed-type-parameter.rs (100%) create mode 100644 src/test/ui/shadowed-type-parameter.stderr diff --git a/src/test/compile-fail/shadowed-type-parameter.rs b/src/test/ui/shadowed-type-parameter.rs similarity index 100% rename from src/test/compile-fail/shadowed-type-parameter.rs rename to src/test/ui/shadowed-type-parameter.rs diff --git a/src/test/ui/shadowed-type-parameter.stderr b/src/test/ui/shadowed-type-parameter.stderr new file mode 100644 index 0000000000000..d77523299bc29 --- /dev/null +++ b/src/test/ui/shadowed-type-parameter.stderr @@ -0,0 +1,28 @@ +error[E0194]: type parameter `T` shadows another type parameter of the same name + --> $DIR/shadowed-type-parameter.rs:30:27 + | +27 | trait Bar { + | - first `T` declared here +... +30 | fn shadow_in_required(&self); + | ^ shadows another type parameter + +error[E0194]: type parameter `T` shadows another type parameter of the same name + --> $DIR/shadowed-type-parameter.rs:33:27 + | +27 | trait Bar { + | - first `T` declared here +... +33 | fn shadow_in_provided(&self) {} + | ^ shadows another type parameter + +error[E0194]: type parameter `T` shadows another type parameter of the same name + --> $DIR/shadowed-type-parameter.rs:18:25 + | +17 | impl Foo { + | - first `T` declared here +18 | fn shadow_in_method(&self) {} + | ^ shadows another type parameter + +error: aborting due to previous error(s) + From 984e76468b34c6874220cc2fbce9dc2f98c6eecc Mon Sep 17 00:00:00 2001 From: Aidan Hobson Sayers Date: Wed, 28 Jun 2017 23:05:29 +0100 Subject: [PATCH 18/18] Record some details to help with possible bad clocks --- .travis.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.travis.yml b/.travis.yml index 96163c75c9d9d..21877ecb43e10 100644 --- a/.travis.yml +++ b/.travis.yml @@ -179,8 +179,14 @@ before_script: fi fi +# Log time information from this machine and an external machine for insight into possible +# clock drift. Timezones don't matter since relative deltas give all the necessary info. script: + - > + date && curl -s --head https://google.com | grep ^Date: | sed 's/Date: //g' - stamp sh -x -c "$RUN_SCRIPT" + - > + date && curl -s --head https://google.com | grep ^Date: | sed 's/Date: //g' after_success: - >