diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 63c846b25ec..12e6e843056 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -634,16 +634,12 @@ impl Option { #[inline] #[unstable(feature = "option_filter", issue = "45860")] pub fn filter bool>(self, predicate: P) -> Self { - match self { - Some(x) => { - if predicate(&x) { - Some(x) - } else { - None - } + if let Some(x) = self { + if predicate(&x) { + return Some(x) } - None => None, } + None } /// Returns the option if it contains a value, otherwise returns `optb`. diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index c9b1d70e7b6..39e222230e5 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1949,7 +1949,7 @@ impl ForeignItem_ { } /// A free variable referred to in a function. -#[derive(Copy, Clone, RustcEncodable, RustcDecodable)] +#[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable)] pub struct Freevar { /// The variable being accessed free. pub def: Def, diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 0fa40f56196..cd017650633 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -267,10 +267,10 @@ impl<'tcx> Mir<'tcx> { let block = &self[location.block]; let stmts = &block.statements; let idx = location.statement_index; - if location.statement_index < stmts.len() { + if idx < stmts.len() { &stmts[idx].source_info } else { - assert!(location.statement_index == stmts.len()); + assert!(idx == stmts.len()); &block.terminator().source_info } } diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 39cf50787ef..00a91eeb9c1 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -164,11 +164,13 @@ enum DiagnosticBuilderMethod { // add more variants as needed to support one-time diagnostics } -/// Diagnostic message id - used in order to avoid emitting the same message more than once +/// Diagnostic message ID—used by `Session.one_time_diagnostics` to avoid +/// emitting the same message more than once #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum DiagnosticMessageId { + ErrorId(u16), // EXXXX error code as integer LintId(lint::LintId), - StabilityId(u32) + StabilityId(u32) // issue number } impl Session { diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index e2b23c12cf1..106b1b08656 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -36,6 +36,7 @@ use middle::const_val; use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL; use std::fmt; use syntax::ast; +use session::DiagnosticMessageId; use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; use ty::error::ExpectedFound; use ty::fast_reject; @@ -219,13 +220,19 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - let mut diag = struct_span_err!( - self.tcx.sess, obligation.cause.span, E0271, - "type mismatch resolving `{}`", predicate - ); - self.note_type_err(&mut diag, &obligation.cause, None, values, err); - self.note_obligation_cause(&mut diag, obligation); - diag.emit(); + let msg = format!("type mismatch resolving `{}`", predicate); + let error_id = (DiagnosticMessageId::ErrorId(271), + Some(obligation.cause.span), msg.clone()); + let fresh = self.tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id); + if fresh { + let mut diag = struct_span_err!( + self.tcx.sess, obligation.cause.span, E0271, + "type mismatch resolving `{}`", predicate + ); + self.note_type_err(&mut diag, &obligation.cause, None, values, err); + self.note_obligation_cause(&mut diag, obligation); + diag.emit(); + } }); } diff --git a/src/librustc_mir/borrow_check.rs b/src/librustc_mir/borrow_check.rs index d2524b306cf..b723b86776b 100644 --- a/src/librustc_mir/borrow_check.rs +++ b/src/librustc_mir/borrow_check.rs @@ -1169,8 +1169,72 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> err.emit(); } + /// Finds the span of arguments of a closure (within `maybe_closure_span`) and its usage of + /// the local assigned at `location`. + /// This is done by searching in statements succeeding `location` + /// and originating from `maybe_closure_span`. + fn find_closure_span( + &self, + maybe_closure_span: Span, + location: Location, + ) -> Option<(Span, Span)> { + use rustc::hir::ExprClosure; + use rustc::mir::AggregateKind; + + let local = if let StatementKind::Assign(Lvalue::Local(local), _) = + self.mir[location.block].statements[location.statement_index].kind + { + local + } else { + return None; + }; + + for stmt in &self.mir[location.block].statements[location.statement_index + 1..] { + if maybe_closure_span != stmt.source_info.span { + break; + } + + if let StatementKind::Assign(_, Rvalue::Aggregate(ref kind, ref lvs)) = stmt.kind { + if let AggregateKind::Closure(def_id, _) = **kind { + debug!("find_closure_span: found closure {:?}", lvs); + + return if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) { + let args_span = if let ExprClosure(_, _, _, span, _) = + self.tcx.hir.expect_expr(node_id).node + { + span + } else { + return None; + }; + + self.tcx + .with_freevars(node_id, |freevars| { + for (v, lv) in freevars.iter().zip(lvs) { + if let Operand::Consume(Lvalue::Local(l)) = *lv { + if local == l { + debug!( + "find_closure_span: found captured local {:?}", + l + ); + return Some(v.span); + } + } + } + None + }) + .map(|var_span| (args_span, var_span)) + } else { + None + }; + } + } + } + + None + } + fn report_conflicting_borrow(&mut self, - _context: Context, + context: Context, common_prefix: &Lvalue, (lvalue, span): (&Lvalue, Span), gen_borrow_kind: BorrowKind, @@ -1183,38 +1247,60 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> let issued_span = self.retrieve_borrow_span(issued_borrow); + let new_closure_span = self.find_closure_span(span, context.loc); + let span = new_closure_span.map(|(args, _)| args).unwrap_or(span); + let old_closure_span = self.find_closure_span(issued_span, issued_borrow.location); + let issued_span = old_closure_span.map(|(args, _)| args).unwrap_or(issued_span); + + let desc_lvalue = self.describe_lvalue(lvalue); + // FIXME: supply non-"" `opt_via` when appropriate let mut err = match (gen_borrow_kind, "immutable", "mutable", issued_borrow.kind, "immutable", "mutable") { (BorrowKind::Shared, lft, _, BorrowKind::Mut, _, rgt) | (BorrowKind::Mut, _, lft, BorrowKind::Shared, rgt, _) => self.tcx.cannot_reborrow_already_borrowed( - span, &self.describe_lvalue(lvalue), "", lft, issued_span, + span, &desc_lvalue, "", lft, issued_span, "it", rgt, "", end_issued_loan_span, Origin::Mir), (BorrowKind::Mut, _, _, BorrowKind::Mut, _, _) => self.tcx.cannot_mutably_borrow_multiply( - span, &self.describe_lvalue(lvalue), "", issued_span, + span, &desc_lvalue, "", issued_span, "", end_issued_loan_span, Origin::Mir), (BorrowKind::Unique, _, _, BorrowKind::Unique, _, _) => self.tcx.cannot_uniquely_borrow_by_two_closures( - span, &self.describe_lvalue(lvalue), issued_span, + span, &desc_lvalue, issued_span, end_issued_loan_span, Origin::Mir), (BorrowKind::Unique, _, _, _, _, _) => self.tcx.cannot_uniquely_borrow_by_one_closure( - span, &self.describe_lvalue(lvalue), "", + span, &desc_lvalue, "", issued_span, "it", "", end_issued_loan_span, Origin::Mir), (_, _, _, BorrowKind::Unique, _, _) => self.tcx.cannot_reborrow_already_uniquely_borrowed( - span, &self.describe_lvalue(lvalue), "it", "", + span, &desc_lvalue, "it", "", issued_span, "", end_issued_loan_span, Origin::Mir), (BorrowKind::Shared, _, _, BorrowKind::Shared, _, _) => unreachable!(), }; + + if let Some((_, var_span)) = old_closure_span { + err.span_label( + var_span, + format!("previous borrow occurs due to use of `{}` in closure", desc_lvalue), + ); + } + + if let Some((_, var_span)) = new_closure_span { + err.span_label( + var_span, + format!("borrow occurs due to use of `{}` in closure", desc_lvalue), + ); + } + err.emit(); } diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 1961acf53a6..1d2bfd001f1 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -503,31 +503,10 @@ fn link_staticlib(sess: &Session, if !all_native_libs.is_empty() { if sess.opts.prints.contains(&PrintRequest::NativeStaticLibs) { print_native_static_libs(sess, &all_native_libs); - } else { - // Fallback for backwards compatibility only - print_native_static_libs_legacy(sess, &all_native_libs); } } } -fn print_native_static_libs_legacy(sess: &Session, all_native_libs: &[NativeLibrary]) { - sess.note_without_error("link against the following native artifacts when linking against \ - this static library"); - sess.note_without_error("This list will not be printed by default. \ - Please add --print=native-static-libs if you need this information"); - - for lib in all_native_libs.iter().filter(|l| relevant_lib(sess, l)) { - let name = match lib.kind { - NativeLibraryKind::NativeStaticNobundle | - NativeLibraryKind::NativeUnknown => "library", - NativeLibraryKind::NativeFramework => "framework", - // These are included, no need to print them - NativeLibraryKind::NativeStatic => continue, - }; - sess.note_without_error(&format!("{}: {}", name, lib.name)); - } -} - fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLibrary]) { let lib_args: Vec<_> = all_native_libs.iter() .filter(|l| relevant_lib(sess, l)) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 270878dc029..69922470cff 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1690,11 +1690,11 @@ impl Path { #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated)] pub fn is_absolute(&self) -> bool { - if !cfg!(target_os = "redox") { - self.has_root() && (cfg!(unix) || self.prefix().is_some()) - } else { + if cfg!(target_os = "redox") { // FIXME: Allow Redox prefixes - has_redox_scheme(self.as_u8_slice()) + self.has_root() || has_redox_scheme(self.as_u8_slice()) + } else { + self.has_root() && (cfg!(unix) || self.prefix().is_some()) } } diff --git a/src/libstd/sys/redox/condvar.rs b/src/libstd/sys/redox/condvar.rs index fe4a89c6f3e..2a611ed7dab 100644 --- a/src/libstd/sys/redox/condvar.rs +++ b/src/libstd/sys/redox/condvar.rs @@ -9,12 +9,12 @@ // except according to those terms. use cell::UnsafeCell; -use intrinsics::{atomic_cxchg, atomic_xadd, atomic_xchg}; +use intrinsics::{atomic_cxchg, atomic_load, atomic_xadd, atomic_xchg}; use ptr; use time::Duration; use sys::mutex::{mutex_unlock, Mutex}; -use sys::syscall::{futex, FUTEX_WAIT, FUTEX_WAKE, FUTEX_REQUEUE}; +use sys::syscall::{futex, TimeSpec, FUTEX_WAIT, FUTEX_WAKE, FUTEX_REQUEUE}; pub struct Condvar { lock: UnsafeCell<*mut i32>, @@ -62,34 +62,51 @@ impl Condvar { } } + #[inline] + unsafe fn wait_inner(&self, mutex: &Mutex, timeout_ptr: *const TimeSpec) -> bool { + let lock = self.lock.get(); + let seq = self.seq.get(); + + if *lock != mutex.lock.get() { + if *lock != ptr::null_mut() { + panic!("Condvar used with more than one Mutex"); + } + + atomic_cxchg(lock as *mut usize, 0, mutex.lock.get() as usize); + } + + mutex_unlock(*lock); + + let seq_before = atomic_load(seq); + + let _ = futex(seq, FUTEX_WAIT, seq_before, timeout_ptr as usize, ptr::null_mut()); + + let seq_after = atomic_load(seq); + + while atomic_xchg(*lock, 2) != 0 { + let _ = futex(*lock, FUTEX_WAIT, 2, 0, ptr::null_mut()); + } + + seq_before != seq_after + } + #[inline] pub fn wait(&self, mutex: &Mutex) { unsafe { - let lock = self.lock.get(); - let seq = self.seq.get(); - - if *lock != mutex.lock.get() { - if *lock != ptr::null_mut() { - panic!("Condvar used with more than one Mutex"); - } - - atomic_cxchg(lock as *mut usize, 0, mutex.lock.get() as usize); - } - - mutex_unlock(*lock); - - let _ = futex(seq, FUTEX_WAIT, *seq, 0, ptr::null_mut()); - - while atomic_xchg(*lock, 2) != 0 { - let _ = futex(*lock, FUTEX_WAIT, 2, 0, ptr::null_mut()); - } + assert!(self.wait_inner(mutex, ptr::null())); } } #[inline] - pub fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool { - ::sys_common::util::dumb_print(format_args!("condvar wait_timeout\n")); - unimplemented!(); + pub fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { + unsafe { + let timeout = TimeSpec { + tv_sec: dur.as_secs() as i64, + tv_nsec: dur.subsec_nanos() as i32 + }; + + self.wait_inner(mutex, &timeout as *const TimeSpec) + } } #[inline] diff --git a/src/libstd/sys/redox/fs.rs b/src/libstd/sys/redox/fs.rs index 918893097f8..3483477d40c 100644 --- a/src/libstd/sys/redox/fs.rs +++ b/src/libstd/sys/redox/fs.rs @@ -437,8 +437,7 @@ pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> { } pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> { - ::sys_common::util::dumb_print(format_args!("Link\n")); - unimplemented!(); + Err(Error::from_raw_os_error(syscall::ENOSYS)) } pub fn stat(p: &Path) -> io::Result { diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 26e6f27e20f..69ddd560213 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -416,7 +416,7 @@ mod tests { // first one is zero: assert_eq!(i.intern("dog"), Symbol(0)); // re-use gets the same entry: - assert_eq!(i.intern ("dog"), Symbol(0)); + assert_eq!(i.intern("dog"), Symbol(0)); // different string gets a different #: assert_eq!(i.intern("cat"), Symbol(1)); assert_eq!(i.intern("cat"), Symbol(1)); diff --git a/src/test/ui/borrowck/borrowck-closures-two-mut.rs b/src/test/ui/borrowck/borrowck-closures-two-mut.rs new file mode 100644 index 00000000000..182b3d75442 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-closures-two-mut.rs @@ -0,0 +1,62 @@ +// 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. + +// Tests that two closures cannot simultaneously have mutable +// access to the variable, whether that mutable access be used +// for direct assignment or for taking mutable ref. Issue #6801. + +// compile-flags: -Z emit-end-regions -Z borrowck-mir + +#![feature(box_syntax)] + +fn to_fn_mut(f: F) -> F { f } + +fn a() { + let mut x = 3; + let c1 = to_fn_mut(|| x = 4); + let c2 = to_fn_mut(|| x = 5); //~ ERROR cannot borrow `x` as mutable more than once +} + +fn set(x: &mut isize) { + *x = 4; +} + +fn b() { + let mut x = 3; + let c1 = to_fn_mut(|| set(&mut x)); + let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once +} + +fn c() { + let mut x = 3; + let c1 = to_fn_mut(|| x = 5); + let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once +} + +fn d() { + let mut x = 3; + let c1 = to_fn_mut(|| x = 5); + let c2 = to_fn_mut(|| { let _y = to_fn_mut(|| set(&mut x)); }); // (nested closure) + //~^ ERROR cannot borrow `x` as mutable more than once +} + +fn g() { + struct Foo { + f: Box + } + + let mut x: Box<_> = box Foo { f: box 3 }; + let c1 = to_fn_mut(|| set(&mut *x.f)); + let c2 = to_fn_mut(|| set(&mut *x.f)); + //~^ ERROR cannot borrow `x` as mutable more than once +} + +fn main() { +} diff --git a/src/test/ui/borrowck/borrowck-closures-two-mut.stderr b/src/test/ui/borrowck/borrowck-closures-two-mut.stderr new file mode 100644 index 00000000000..fc8a7f2ab60 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-closures-two-mut.stderr @@ -0,0 +1,146 @@ +error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast) + --> $DIR/borrowck-closures-two-mut.rs:24:24 + | +23 | let c1 = to_fn_mut(|| x = 4); + | -- - previous borrow occurs due to use of `x` in closure + | | + | first mutable borrow occurs here +24 | let c2 = to_fn_mut(|| x = 5); //~ ERROR cannot borrow `x` as mutable more than once + | ^^ - borrow occurs due to use of `x` in closure + | | + | second mutable borrow occurs here +25 | } + | - first borrow ends here + +error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast) + --> $DIR/borrowck-closures-two-mut.rs:34:24 + | +33 | let c1 = to_fn_mut(|| set(&mut x)); + | -- - previous borrow occurs due to use of `x` in closure + | | + | first mutable borrow occurs here +34 | let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once + | ^^ - borrow occurs due to use of `x` in closure + | | + | second mutable borrow occurs here +35 | } + | - first borrow ends here + +error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast) + --> $DIR/borrowck-closures-two-mut.rs:40:24 + | +39 | let c1 = to_fn_mut(|| x = 5); + | -- - previous borrow occurs due to use of `x` in closure + | | + | first mutable borrow occurs here +40 | let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once + | ^^ - borrow occurs due to use of `x` in closure + | | + | second mutable borrow occurs here +41 | } + | - first borrow ends here + +error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast) + --> $DIR/borrowck-closures-two-mut.rs:46:24 + | +45 | let c1 = to_fn_mut(|| x = 5); + | -- - previous borrow occurs due to use of `x` in closure + | | + | first mutable borrow occurs here +46 | let c2 = to_fn_mut(|| { let _y = to_fn_mut(|| set(&mut x)); }); // (nested closure) + | ^^ - borrow occurs due to use of `x` in closure + | | + | second mutable borrow occurs here +47 | //~^ ERROR cannot borrow `x` as mutable more than once +48 | } + | - first borrow ends here + +error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast) + --> $DIR/borrowck-closures-two-mut.rs:57:24 + | +56 | let c1 = to_fn_mut(|| set(&mut *x.f)); + | -- - previous borrow occurs due to use of `x` in closure + | | + | first mutable borrow occurs here +57 | let c2 = to_fn_mut(|| set(&mut *x.f)); + | ^^ - borrow occurs due to use of `x` in closure + | | + | second mutable borrow occurs here +58 | //~^ ERROR cannot borrow `x` as mutable more than once +59 | } + | - first borrow ends here + +error[E0499]: cannot borrow `x` as mutable more than once at a time (Mir) + --> $DIR/borrowck-closures-two-mut.rs:24:24 + | +23 | let c1 = to_fn_mut(|| x = 4); + | -- - previous borrow occurs due to use of `x` in closure + | | + | first mutable borrow occurs here +24 | let c2 = to_fn_mut(|| x = 5); //~ ERROR cannot borrow `x` as mutable more than once + | ^^ - borrow occurs due to use of `x` in closure + | | + | second mutable borrow occurs here +25 | } + | - first borrow ends here + +error[E0499]: cannot borrow `x` as mutable more than once at a time (Mir) + --> $DIR/borrowck-closures-two-mut.rs:34:24 + | +33 | let c1 = to_fn_mut(|| set(&mut x)); + | -- - previous borrow occurs due to use of `x` in closure + | | + | first mutable borrow occurs here +34 | let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once + | ^^ - borrow occurs due to use of `x` in closure + | | + | second mutable borrow occurs here +35 | } + | - first borrow ends here + +error[E0499]: cannot borrow `x` as mutable more than once at a time (Mir) + --> $DIR/borrowck-closures-two-mut.rs:40:24 + | +39 | let c1 = to_fn_mut(|| x = 5); + | -- - previous borrow occurs due to use of `x` in closure + | | + | first mutable borrow occurs here +40 | let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once + | ^^ - borrow occurs due to use of `x` in closure + | | + | second mutable borrow occurs here +41 | } + | - first borrow ends here + +error[E0499]: cannot borrow `x` as mutable more than once at a time (Mir) + --> $DIR/borrowck-closures-two-mut.rs:46:24 + | +45 | let c1 = to_fn_mut(|| x = 5); + | -- - previous borrow occurs due to use of `x` in closure + | | + | first mutable borrow occurs here +46 | let c2 = to_fn_mut(|| { let _y = to_fn_mut(|| set(&mut x)); }); // (nested closure) + | ^^ - borrow occurs due to use of `x` in closure + | | + | second mutable borrow occurs here +47 | //~^ ERROR cannot borrow `x` as mutable more than once +48 | } + | - first borrow ends here + +error[E0499]: cannot borrow `x` as mutable more than once at a time (Mir) + --> $DIR/borrowck-closures-two-mut.rs:57:24 + | +56 | let c1 = to_fn_mut(|| set(&mut *x.f)); + | -- - previous borrow occurs due to use of `x` in closure + | | + | first mutable borrow occurs here +57 | let c2 = to_fn_mut(|| set(&mut *x.f)); + | ^^ - borrow occurs due to use of `x` in closure + | | + | second mutable borrow occurs here +58 | //~^ ERROR cannot borrow `x` as mutable more than once +59 | } + | - first borrow ends here + +error: aborting due to 10 previous errors + diff --git a/src/test/ui/issue-33941.rs b/src/test/ui/issue-33941.rs new file mode 100644 index 00000000000..eb111d33b99 --- /dev/null +++ b/src/test/ui/issue-33941.rs @@ -0,0 +1,15 @@ +// 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. + +use std::collections::HashMap; + +fn main() { + for _ in HashMap::new().iter().cloned() {} +} diff --git a/src/test/ui/issue-33941.stderr b/src/test/ui/issue-33941.stderr new file mode 100644 index 00000000000..5a8d1fab3f6 --- /dev/null +++ b/src/test/ui/issue-33941.stderr @@ -0,0 +1,21 @@ +error[E0271]: type mismatch resolving ` as std::iter::Iterator>::Item == &_` + --> $DIR/issue-33941.rs:14:36 + | +14 | for _ in HashMap::new().iter().cloned() {} + | ^^^^^^ expected tuple, found reference + | + = note: expected type `(&_, &_)` + found type `&_` + +error[E0271]: type mismatch resolving ` as std::iter::Iterator>::Item == &_` + --> $DIR/issue-33941.rs:14:5 + | +14 | for _ in HashMap::new().iter().cloned() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected tuple, found reference + | + = note: expected type `(&_, &_)` + found type `&_` + = note: required because of the requirements on the impl of `std::iter::Iterator` for `std::iter::Cloned>` + +error: aborting due to 2 previous errors + diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 19195838791..e03d9f89e5d 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -259,9 +259,9 @@ impl TestProps { props } - pub fn from_file(testfile: &Path, config: &Config) -> Self { + pub fn from_file(testfile: &Path, cfg: Option<&str>, config: &Config) -> Self { let mut props = TestProps::new(); - props.load_from(testfile, None, config); + props.load_from(testfile, cfg, config); props } @@ -269,10 +269,10 @@ impl TestProps { /// tied to a particular revision `foo` (indicated by writing /// `//[foo]`), then the property is ignored unless `cfg` is /// `Some("foo")`. - pub fn load_from(&mut self, - testfile: &Path, - cfg: Option<&str>, - config: &Config) { + fn load_from(&mut self, + testfile: &Path, + cfg: Option<&str>, + config: &Config) { iter_header(testfile, cfg, &mut |ln| { diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 9fb6a3f5e07..6da37df1927 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -493,6 +493,7 @@ fn stamp(config: &Config, testpaths: &TestPaths) -> PathBuf { config.stage_id); config.build_base.canonicalize() .unwrap_or_else(|_| config.build_base.clone()) + .join(&testpaths.relative_dir) .join(stamp_name) } @@ -524,6 +525,10 @@ fn up_to_date(config: &Config, testpaths: &TestPaths, props: &EarlyProps) -> boo let lib = lib.unwrap(); inputs.push(mtime(&lib.path())); } + if let Some(ref rustdoc_path) = config.rustdoc_path { + inputs.push(mtime(&rustdoc_path)); + inputs.push(mtime(&rust_src_dir.join("src/etc/htmldocck.py"))); + } inputs.iter().any(|input| *input > stamp) } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 80ca0afe72b..2ff3eb7678f 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -69,7 +69,7 @@ pub fn run(config: Config, testpaths: &TestPaths) { print!("\n\n"); } debug!("running {:?}", testpaths.file.display()); - let base_props = TestProps::from_file(&testpaths.file, &config); + let base_props = TestProps::from_file(&testpaths.file, None, &config); let base_cx = TestCx { config: &config, props: &base_props, @@ -81,8 +81,9 @@ pub fn run(config: Config, testpaths: &TestPaths) { base_cx.run_revision() } else { for revision in &base_props.revisions { - let mut revision_props = base_props.clone(); - revision_props.load_from(&testpaths.file, Some(revision), &config); + let revision_props = TestProps::from_file(&testpaths.file, + Some(revision), + &config); let rev_cx = TestCx { config: &config, props: &revision_props, @@ -2614,4 +2615,4 @@ fn read2_abbreviated(mut child: Child) -> io::Result { stdout: stdout.into_bytes(), stderr: stderr.into_bytes(), }) -} \ No newline at end of file +}