diff --git a/.travis.yml b/.travis.yml index b95196da356c8..21877ecb43e10 100644 --- a/.travis.yml +++ b/.travis.yml @@ -171,16 +171,22 @@ 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 +# 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: - - sh -x -c "$RUN_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: - > 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 ------------------------ 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/liballoc/fmt.rs b/src/liballoc/fmt.rs index 1bd95fb82aa4d..4847b21c0b3b5 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 /// diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 33d2f729e1a1d..7882a8ce5c8ec 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -379,8 +379,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`? /// @@ -512,8 +513,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`? /// 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 /// diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 466d163854f1d..8202c6106d147 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -510,7 +510,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 }; @@ -525,7 +524,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 { @@ -534,20 +534,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)); } } } @@ -563,10 +567,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/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index ad154f9b81531..2b33150902532 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/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index bea13397eca4b..03da451fd9a0a 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,31 @@ mod tests { compile_fail: compile_fail, error_codes: error_codes, original: s.to_owned(), + allow_fail: allow_fail, }) } + fn v() -> Vec { + Vec::new() + } + // 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, 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/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/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/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"))); diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index d7d3a70f3c7c5..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! ( @@ -812,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), 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/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..92cfb862b1669 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,8 @@ 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,12 +789,24 @@ impl ConsoleTestState { } else { self.write_pretty("FAILED", term::color::RED)?; } - let s = format!(". {} passed; {} failed; {} ignored; {} measured; {} filtered out\n\n", - self.passed, - self.failed, - self.ignored, - self.measured, - self.filtered_out); + let s = if self.allowed_fail > 0 { + format!( + ". {} passed; {} failed ({} allowed); {} ignored; {} measured; {} filtered out\n\n", + self.passed, + self.failed + self.allowed_fail, + self.allowed_fail, + self.ignored, + self.measured, + 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); } @@ -891,6 +914,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; @@ -945,12 +969,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 { @@ -962,6 +988,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, @@ -1471,8 +1498,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, } } @@ -1706,6 +1738,7 @@ mod tests { name: StaticTestName("whatever"), ignore: true, should_panic: ShouldPanic::No, + allow_fail: false, }, testfn: DynTestFn(Box::new(move |()| f())), }; @@ -1723,6 +1756,7 @@ mod tests { name: StaticTestName("whatever"), ignore: true, should_panic: ShouldPanic::No, + allow_fail: false, }, testfn: DynTestFn(Box::new(move |()| f())), }; @@ -1742,6 +1776,7 @@ mod tests { name: StaticTestName("whatever"), ignore: false, should_panic: ShouldPanic::Yes, + allow_fail: false, }, testfn: DynTestFn(Box::new(move |()| f())), }; @@ -1761,6 +1796,7 @@ mod tests { name: StaticTestName("whatever"), ignore: false, should_panic: ShouldPanic::YesWithMessage("error message"), + allow_fail: false, }, testfn: DynTestFn(Box::new(move |()| f())), }; @@ -1782,6 +1818,7 @@ mod tests { name: StaticTestName("whatever"), ignore: false, should_panic: ShouldPanic::YesWithMessage(expected), + allow_fail: false, }, testfn: DynTestFn(Box::new(move |()| f())), }; @@ -1799,6 +1836,7 @@ mod tests { name: StaticTestName("whatever"), ignore: false, should_panic: ShouldPanic::Yes, + allow_fail: false, }, testfn: DynTestFn(Box::new(move |()| f())), }; @@ -1832,6 +1870,7 @@ mod tests { name: StaticTestName("1"), ignore: true, should_panic: ShouldPanic::No, + allow_fail: false, }, testfn: DynTestFn(Box::new(move |()| {})), }, @@ -1840,6 +1879,7 @@ mod tests { name: StaticTestName("2"), ignore: false, should_panic: ShouldPanic::No, + allow_fail: false, }, testfn: DynTestFn(Box::new(move |()| {})), }]; @@ -1863,6 +1903,7 @@ mod tests { name: StaticTestName(name), ignore: false, should_panic: ShouldPanic::No, + allow_fail: false, }, testfn: DynTestFn(Box::new(move |()| {})) }) @@ -1944,6 +1985,7 @@ mod tests { name: DynTestName((*name).clone()), ignore: false, should_panic: ShouldPanic::No, + allow_fail: false, }, testfn: DynTestFn(Box::new(move |()| testfn())), }; 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/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/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); + } +} 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" + })); +} 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!() } +} + 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..aa9cf76617f69 --- /dev/null +++ b/src/test/run-pass/test-allow-fail-attr.rs @@ -0,0 +1,24 @@ +// 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 +#![feature(allow_fail)] + +#[test] +#[allow_fail] +fn test1() { + panic!(); +} + +#[test] +#[allow_fail] +fn test2() { + assert!(true); +} 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/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) + 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) 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), }