diff --git a/src/doc/reference.md b/src/doc/reference.md index 781b40be768c..87130c08991c 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -302,7 +302,7 @@ nonzero_dec: '1' | '2' | '3' | '4' A _character literal_ is a single Unicode character enclosed within two `U+0027` (single-quote) characters, with the exception of `U+0027` itself, -which must be _escaped_ by a preceding U+005C character (`\`). +which must be _escaped_ by a preceding `U+005C` character (`\`). ##### String literals @@ -311,6 +311,19 @@ A _string literal_ is a sequence of any Unicode characters enclosed within two which must be _escaped_ by a preceding `U+005C` character (`\`), or a _raw string literal_. +A multi-line string literal may be defined by terminating each line with a +`U+005C` character (`\`) immediately before the newline. This causes the +`U+005C` character, the newline, and all whitespace at the beginning of the +next line to be ignored. + +```rust +let a = "foobar"; +let b = "foo\ + bar"; + +assert_eq!(a,b); +``` + ##### Character escapes Some additional _escapes_ are available in either character or non-raw string diff --git a/src/doc/trpl/hello-cargo.md b/src/doc/trpl/hello-cargo.md index 5eb6cd7c5cd3..587da69d4a6f 100644 --- a/src/doc/trpl/hello-cargo.md +++ b/src/doc/trpl/hello-cargo.md @@ -18,13 +18,15 @@ the Cargo README](https://github.com/rust-lang/cargo#installing-cargo-from-nightlies) for specific instructions about installing it. +## Converting to Cargo + Let's convert Hello World to Cargo. To Cargo-ify our project, we need to do two things: Make a `Cargo.toml` configuration file, and put our source file in the right place. Let's do that part first: -```{bash} +```bash $ mkdir src $ mv main.rs src/main.rs ``` @@ -36,7 +38,7 @@ place for everything, and everything in its place. Next, our configuration file: -```{bash} +```bash $ editor Cargo.toml ``` @@ -73,7 +75,7 @@ well as what it is named. Once you have this file in place, we should be ready to build! Try this: -```{bash} +```bash $ cargo build Compiling hello_world v0.0.1 (file:///home/yourname/projects/hello_world) $ ./target/hello_world @@ -103,6 +105,62 @@ That's it! We've successfully built `hello_world` with Cargo. Even though our program is simple, it's using much of the real tooling that you'll use for the rest of your Rust career. +## A New Project + +You don't have to go through this whole process every time you want to start a new +project! Cargo has the ability to make a bare-bones project directory in which you +can start developing right away. + +To start a new project with Cargo, use `cargo new`: + +```bash +$ cargo new hello_world --bin +``` + +We're passing `--bin` because we're making a binary program: if we +were making a library, we'd leave it off. + +Let's check out what Cargo has generated for us: + +```bash +$ cd hello_world +$ tree . +. +├── Cargo.toml +└── src + └── main.rs + +1 directory, 2 files +``` + +If you don't have the `tree` command, you can probably get it from your distro's package +manager. It's not necessary, but it's certainly useful. + +This is all we need to get started. First, let's check out `Cargo.toml`: + +```toml +[package] + +name = "hello_world" +version = "0.0.1" +authors = ["Your Name "] +``` + +Cargo has populated this file with reasonable defaults based off the arguments you gave +it and your `git` global configuration. You may notice that Cargo has also initialized +the `hello_world` directory as a `git` repository. + +Here's what's in `src/main.rs`: + +```rust +fn main() { + println!("Hello, world!"); +} +``` + +Cargo has generated a "Hello World!" for us, and you're ready to start coding! A +much more in-depth guide to Cargo can be found [here](http://doc.crates.io/guide.html). + Now that you've got the tools down, let's actually learn more about the Rust language itself. These are the basics that will serve you well through the rest -of your time with Rust. +of your time with Rust. \ No newline at end of file diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index d3d86270d1e9..726d5c8a23b7 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -300,7 +300,7 @@ mod imp { libc::realloc(ptr as *mut libc::c_void, size as libc::size_t) as *mut u8 } else { let new_ptr = allocate(size, align); - ptr::copy_memory(new_ptr, ptr, cmp::min(size, old_size)); + ptr::copy(new_ptr, ptr, cmp::min(size, old_size)); deallocate(ptr, old_size, align); new_ptr } diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index d4c537396861..a2924f8fe530 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -2663,7 +2663,7 @@ mod tests { let (left, right) = values.split_at_mut(2); { let left: &[_] = left; - assert!(left[..left.len()] == [1, 2][]); + assert!(left[..left.len()] == [1, 2]); } for p in left { *p += 1; @@ -2671,7 +2671,7 @@ mod tests { { let right: &[_] = right; - assert!(right[..right.len()] == [3, 4, 5][]); + assert!(right[..right.len()] == [3, 4, 5]); } for p in right { *p += 2; diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index e18fa8c3082d..78ab9b6ab9ba 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -2093,7 +2093,7 @@ mod tests { let (left, right) = values.split_at_mut(2); { let left: &[_] = left; - assert!(&left[..left.len()] == &[1, 2][]); + assert!(&left[..left.len()] == &[1, 2]); } for p in left { *p += 1; @@ -2101,7 +2101,7 @@ mod tests { { let right: &[_] = right; - assert!(&right[..right.len()] == &[3, 4, 5][]); + assert!(&right[..right.len()] == &[3, 4, 5]); } for p in right { *p += 2; diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index e7af0be88a08..1ca243134cc6 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -241,7 +241,12 @@ extern "rust-intrinsic" { /// will trigger a compiler error. pub fn return_address() -> *const u8; - /// Returns `true` if a type requires drop glue. + /// Returns `true` if the actual type given as `T` requires drop + /// glue; returns `false` if the actual type provided for `T` + /// implements `Copy`. + /// + /// If the actual type neither requires drop glue nor implements + /// `Copy`, then may return `true` or `false`. pub fn needs_drop() -> bool; /// Returns `true` if a type is managed (will be allocated on the local heap) diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 8f767e62678e..94cc933d844f 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -171,8 +171,7 @@ pub trait IteratorExt: Iterator + Sized { self.fold(0, |cnt, _x| cnt + 1) } - /// Loops through the entire iterator, returning the last element of the - /// iterator. + /// Loops through the entire iterator, returning the last element. /// /// # Examples /// @@ -637,8 +636,8 @@ pub trait IteratorExt: Iterator + Sized { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - fn all(self, mut f: F) -> bool where F: FnMut(Self::Item) -> bool { - for x in self { if !f(x) { return false; } } + fn all(&mut self, mut f: F) -> bool where F: FnMut(Self::Item) -> bool { + for x in self.by_ref() { if !f(x) { return false; } } true } @@ -1637,8 +1636,6 @@ impl Iterator for Filter where P: FnMut(&I::Item) -> bool for x in self.iter.by_ref() { if (self.predicate)(&x) { return Some(x); - } else { - continue } } None diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 6c934a998de2..868a671b9560 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -275,7 +275,13 @@ macro_rules! impls{ /// any methods, but instead is used to gate access to data. /// /// FIXME. Better documentation needed here! -pub trait MarkerTrait : PhantomFn { } +pub trait MarkerTrait : PhantomFn { } +// ~~~~~ <-- FIXME(#22806)? +// +// Marker trait has been made invariant so as to avoid inf recursion, +// but we should ideally solve the underlying problem. That's a bit +// complicated. + impl MarkerTrait for T { } /// `PhantomFn` is a marker trait for use with traits that contain diff --git a/src/libcore/result.rs b/src/libcore/result.rs index bca73782491b..b8271562d2e6 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -641,9 +641,9 @@ impl Result { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn or(self, res: Result) -> Result { + pub fn or(self, res: Result) -> Result { match self { - Ok(_) => self, + Ok(v) => Ok(v), Err(_) => res, } } diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 7e51f8e8503b..b354116993c2 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -939,6 +939,7 @@ impl<'a, P: Pattern<'a>> Iterator for SplitStr<'a, P> { type Item = &'a str; #[inline] + #[allow(deprecated)] fn next(&mut self) -> Option<&'a str> { Iterator::next(&mut self.0) } diff --git a/src/libcoretest/result.rs b/src/libcoretest/result.rs index ab7b5101e726..10cc3ad64242 100644 --- a/src/libcoretest/result.rs +++ b/src/libcoretest/result.rs @@ -36,10 +36,10 @@ pub fn test_and_then() { #[test] pub fn test_or() { - assert_eq!(op1().or(Ok(667)).unwrap(), 666); + assert_eq!(op1().or(Ok::<_, &'static str>(667)).unwrap(), 666); assert_eq!(op1().or(Err("bad")).unwrap(), 666); - assert_eq!(op2().or(Ok(667)).unwrap(), 667); + assert_eq!(op2().or(Ok::<_, &'static str>(667)).unwrap(), 667); assert_eq!(op2().or(Err("bad")).unwrap_err(), "bad"); } diff --git a/src/libcoretest/slice.rs b/src/libcoretest/slice.rs index 46c7730cc647..fe73b3b44079 100644 --- a/src/libcoretest/slice.rs +++ b/src/libcoretest/slice.rs @@ -59,16 +59,16 @@ fn iterator_to_slice() { let mut iter = data.iter_mut(); assert_eq!(&iter[..], &other_data[..]); // mutability: - assert!(&mut iter[] == other_data); + assert!(&mut iter[..] == other_data); iter.next(); assert_eq!(&iter[..], &other_data[1..]); - assert!(&mut iter[] == &mut other_data[1..]); + assert!(&mut iter[..] == &mut other_data[1..]); iter.next_back(); assert_eq!(&iter[..], &other_data[1..2]); - assert!(&mut iter[] == &mut other_data[1..2]); + assert!(&mut iter[..] == &mut other_data[1..2]); let s = iter.into_slice(); assert!(s == &mut other_data[1..2]); diff --git a/src/librand/reseeding.rs b/src/librand/reseeding.rs index f4d3e975b75b..068289114714 100644 --- a/src/librand/reseeding.rs +++ b/src/librand/reseeding.rs @@ -134,11 +134,7 @@ pub trait Reseeder { /// Reseed an RNG using a `Default` instance. This reseeds by /// replacing the RNG with the result of a `Default::default` call. #[derive(Copy)] -pub struct ReseedWithDefault { __hack: [u8; 0] } -// FIXME(#21721) used to be an unit struct but that can cause -// certain LLVM versions to abort during optimizations. -#[allow(non_upper_case_globals)] -pub const ReseedWithDefault: ReseedWithDefault = ReseedWithDefault { __hack: [] }; +pub struct ReseedWithDefault; impl Reseeder for ReseedWithDefault { fn reseed(&mut self, rng: &mut R) { diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index a4f69e651df6..0bd7f83b9595 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -1771,6 +1771,11 @@ impl LintPass for Stability { stability::check_path(cx.tcx, path, id, &mut |id, sp, stab| self.lint(cx, id, sp, stab)); } + + fn check_pat(&mut self, cx: &Context, pat: &ast::Pat) { + stability::check_pat(cx.tcx, pat, + &mut |id, sp, stab| self.lint(cx, id, sp, stab)) + } } declare_lint! { diff --git a/src/librustc/middle/astconv_util.rs b/src/librustc/middle/astconv_util.rs index 17fd80ceaea4..0f98b3c33fb8 100644 --- a/src/librustc/middle/astconv_util.rs +++ b/src/librustc/middle/astconv_util.rs @@ -68,7 +68,7 @@ pub fn ast_ty_to_prim_ty<'tcx>(tcx: &ty::ctxt<'tcx>, ast_ty: &ast::Ty) Some(d) => d.full_def() }; if let def::DefPrimTy(nty) = def { - Some(prim_ty_to_ty(tcx, &path.segments[], nty)) + Some(prim_ty_to_ty(tcx, &path.segments, nty)) } else { None } @@ -76,4 +76,3 @@ pub fn ast_ty_to_prim_ty<'tcx>(tcx: &ty::ctxt<'tcx>, ast_ty: &ast::Ty) None } } - diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index f67e470ee549..ddac6cc75143 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -58,8 +58,10 @@ impl<'a> Annotator<'a> { attrs: &Vec, item_sp: Span, f: F, required: bool) where F: FnOnce(&mut Annotator), { + debug!("annotate(id = {:?}, attrs = {:?})", id, attrs); match attr::find_stability(self.sess.diagnostic(), attrs, item_sp) { Some(stab) => { + debug!("annotate: found {:?}", stab); self.index.local.insert(id, stab.clone()); // Don't inherit #[stable(feature = "rust1", since = "1.0.0")] @@ -72,6 +74,8 @@ impl<'a> Annotator<'a> { } } None => { + debug!("annotate: not found, use_parent = {:?}, parent = {:?}", + use_parent, self.parent); if use_parent { if let Some(stab) = self.parent.clone() { self.index.local.insert(id, stab); @@ -299,6 +303,12 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> { &mut |id, sp, stab| self.check(id, sp, stab)); visit::walk_path(self, path) } + + fn visit_pat(&mut self, pat: &ast::Pat) { + check_pat(self.tcx, pat, + &mut |id, sp, stab| self.check(id, sp, stab)); + visit::walk_pat(self, pat) + } } /// Helper for discovering nodes to check for stability @@ -385,6 +395,76 @@ pub fn check_expr(tcx: &ty::ctxt, e: &ast::Expr, None => return } } + ast::ExprField(ref base_e, ref field) => { + span = field.span; + match ty::expr_ty_adjusted(tcx, base_e).sty { + ty::ty_struct(did, _) => { + ty::lookup_struct_fields(tcx, did) + .iter() + .find(|f| f.name == field.node.name) + .unwrap_or_else(|| { + tcx.sess.span_bug(field.span, + "stability::check_expr: unknown named field access") + }) + .id + } + _ => tcx.sess.span_bug(e.span, + "stability::check_expr: named field access on non-struct") + } + } + ast::ExprTupField(ref base_e, ref field) => { + span = field.span; + match ty::expr_ty_adjusted(tcx, base_e).sty { + ty::ty_struct(did, _) => { + ty::lookup_struct_fields(tcx, did) + .get(field.node) + .unwrap_or_else(|| { + tcx.sess.span_bug(field.span, + "stability::check_expr: unknown unnamed field access") + }) + .id + } + ty::ty_tup(..) => return, + _ => tcx.sess.span_bug(e.span, + "stability::check_expr: unnamed field access on \ + something other than a tuple or struct") + } + } + ast::ExprStruct(_, ref expr_fields, _) => { + let type_ = ty::expr_ty(tcx, e); + match type_.sty { + ty::ty_struct(did, _) => { + let struct_fields = ty::lookup_struct_fields(tcx, did); + // check the stability of each field that appears + // in the construction expression. + for field in expr_fields { + let did = struct_fields + .iter() + .find(|f| f.name == field.ident.node.name) + .unwrap_or_else(|| { + tcx.sess.span_bug(field.span, + "stability::check_expr: unknown named \ + field access") + }) + .id; + maybe_do_stability_check(tcx, did, field.span, cb); + } + + // we're done. + return + } + // we don't look at stability attributes on + // struct-like enums (yet...), but it's definitely not + // a bug to have construct one. + ty::ty_enum(..) => return, + _ => { + tcx.sess.span_bug(e.span, + &format!("stability::check_expr: struct construction \ + of non-struct, type {:?}", + type_.repr(tcx))); + } + } + } _ => return }; @@ -403,6 +483,47 @@ pub fn check_path(tcx: &ty::ctxt, path: &ast::Path, id: ast::NodeId, } +pub fn check_pat(tcx: &ty::ctxt, pat: &ast::Pat, + cb: &mut FnMut(ast::DefId, Span, &Option)) { + debug!("check_pat(pat = {:?})", pat); + if is_internal(tcx, pat.span) { return; } + + let did = match ty::pat_ty_opt(tcx, pat) { + Some(&ty::TyS { sty: ty::ty_struct(did, _), .. }) => did, + Some(_) | None => return, + }; + let struct_fields = ty::lookup_struct_fields(tcx, did); + match pat.node { + // Foo(a, b, c) + ast::PatEnum(_, Some(ref pat_fields)) => { + for (field, struct_field) in pat_fields.iter().zip(struct_fields.iter()) { + // a .. pattern is fine, but anything positional is + // not. + if let ast::PatWild(ast::PatWildMulti) = field.node { + continue + } + maybe_do_stability_check(tcx, struct_field.id, field.span, cb) + } + } + // Foo { a, b, c } + ast::PatStruct(_, ref pat_fields, _) => { + for field in pat_fields { + let did = struct_fields + .iter() + .find(|f| f.name == field.node.ident.name) + .unwrap_or_else(|| { + tcx.sess.span_bug(field.span, + "stability::check_pat: unknown named field access") + }) + .id; + maybe_do_stability_check(tcx, did, field.span, cb); + } + } + // everything else is fine. + _ => {} + } +} + fn maybe_do_stability_check(tcx: &ty::ctxt, id: ast::DefId, span: Span, cb: &mut FnMut(ast::DefId, Span, &Option)) { if !is_staged_api(tcx, id) { return } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 78b8d4f7b1e2..635ec09d3394 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -3896,7 +3896,7 @@ pub fn is_type_representable<'tcx>(cx: &ctxt<'tcx>, sp: Span, ty: Ty<'tcx>) let types_a = substs_a.types.get_slice(subst::TypeSpace); let types_b = substs_b.types.get_slice(subst::TypeSpace); - let pairs = types_a.iter().zip(types_b.iter()); + let mut pairs = types_a.iter().zip(types_b.iter()); pairs.all(|(&a, &b)| same_type(a, b)) } @@ -4298,6 +4298,9 @@ pub fn free_region_from_def(outlives_extent: region::DestructionScopeData, pub fn pat_ty<'tcx>(cx: &ctxt<'tcx>, pat: &ast::Pat) -> Ty<'tcx> { return node_id_to_type(cx, pat.id); } +pub fn pat_ty_opt<'tcx>(cx: &ctxt<'tcx>, pat: &ast::Pat) -> Option> { + return node_id_to_type_opt(cx, pat.id); +} // Returns the type of an expression as a monotype. diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 436a826687e1..46729988bb6b 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -233,6 +233,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { ast::ItemEnum(ref def, _) if public_first => { for variant in &def.variants { self.exported_items.insert(variant.node.id); + self.public_items.insert(variant.node.id); } } @@ -321,6 +322,15 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { Some(id) => { self.exported_items.insert(id); } None => {} } + // fields can be public or private, so lets check + for field in &def.fields { + let vis = match field.node.kind { + ast::NamedField(_, vis) | ast::UnnamedField(vis) => vis + }; + if vis == ast::Public { + self.public_items.insert(field.node.id); + } + } } ast::ItemTy(ref ty, _) if public_first => { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 95523be68c3b..78ce9abe07d9 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2985,7 +2985,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } else { let msg = format!("use of undeclared trait name `{}`", self.path_names_to_string(trait_path, path_depth)); - self.resolve_error(trait_path.span, &msg[]); + self.resolve_error(trait_path.span, &msg); Err(()) } } diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index 9a121a8830b2..48ff4c833202 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -1499,6 +1499,7 @@ pub fn store_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, fn create_dummy_locals<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, pat: &ast::Pat) -> Block<'blk, 'tcx> { + let _icx = push_ctxt("create_dummy_locals"); // create dummy memory for the variables if we have no // value to store into them immediately let tcx = bcx.tcx(); diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index 59fcd5492ebd..4f234fac9a4a 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -734,7 +734,7 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, }; if !is_rust_fn || type_of::return_uses_outptr(ccx, ret_ty) || - common::type_needs_drop(bcx.tcx(), ret_ty) { + bcx.fcx.type_needs_drop(ret_ty) { // Push the out-pointer if we use an out-pointer for this // return type, otherwise push "undef". if common::type_is_zero_size(ccx, ret_ty) { diff --git a/src/librustc_trans/trans/cleanup.rs b/src/librustc_trans/trans/cleanup.rs index a3705a67cdc5..ad07f3953ccc 100644 --- a/src/librustc_trans/trans/cleanup.rs +++ b/src/librustc_trans/trans/cleanup.rs @@ -386,7 +386,7 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> { cleanup_scope: ScopeId, val: ValueRef, ty: Ty<'tcx>) { - if !common::type_needs_drop(self.ccx.tcx(), ty) { return; } + if !self.type_needs_drop(ty) { return; } let drop = box DropValue { is_immediate: false, must_unwind: common::type_needs_unwind_cleanup(self.ccx, ty), @@ -408,7 +408,8 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> { cleanup_scope: ScopeId, val: ValueRef, ty: Ty<'tcx>) { - if !common::type_needs_drop(self.ccx.tcx(), ty) { return; } + if !self.type_needs_drop(ty) { return; } + let drop = box DropValue { is_immediate: false, must_unwind: common::type_needs_unwind_cleanup(self.ccx, ty), @@ -432,7 +433,7 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> { val: ValueRef, ty: Ty<'tcx>) { - if !common::type_needs_drop(self.ccx.tcx(), ty) { return; } + if !self.type_needs_drop(ty) { return; } let drop = box DropValue { is_immediate: true, must_unwind: common::type_needs_unwind_cleanup(self.ccx, ty), @@ -1007,6 +1008,7 @@ impl<'tcx> Cleanup<'tcx> for DropValue<'tcx> { bcx: Block<'blk, 'tcx>, debug_loc: DebugLoc) -> Block<'blk, 'tcx> { + let _icx = base::push_ctxt("::trans"); let bcx = if self.is_immediate { glue::drop_ty_immediate(bcx, self.val, self.ty, debug_loc) } else { diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index d8fc6df2685d..ec7ed2fe8901 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -213,8 +213,43 @@ pub fn type_needs_unwind_cleanup<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty< } } +/// If `type_needs_drop` returns true, then `ty` is definitely +/// non-copy and *might* have a destructor attached; if it returns +/// false, then `ty` definitely has no destructor (i.e. no drop glue). +/// +/// (Note that this implies that if `ty` has a destructor attached, +/// then `type_needs_drop` will definitely return `true` for `ty`.) pub fn type_needs_drop<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { - ty::type_contents(cx, ty).needs_drop(cx) + type_needs_drop_given_env(cx, ty, &ty::empty_parameter_environment(cx)) +} + +/// Core implementation of type_needs_drop, potentially making use of +/// and/or updating caches held in the `param_env`. +fn type_needs_drop_given_env<'a,'tcx>(cx: &ty::ctxt<'tcx>, + ty: Ty<'tcx>, + param_env: &ty::ParameterEnvironment<'a,'tcx>) -> bool { + // Issue #22536: We first query type_moves_by_default. It sees a + // normalized version of the type, and therefore will definitely + // know whether the type implements Copy (and thus needs no + // cleanup/drop/zeroing) ... + let implements_copy = !ty::type_moves_by_default(¶m_env, DUMMY_SP, ty); + + if implements_copy { return false; } + + // ... (issue #22536 continued) but as an optimization, still use + // prior logic of asking if the `needs_drop` bit is set; we need + // not zero non-Copy types if they have no destructor. + + // FIXME(#22815): Note that calling `ty::type_contents` is a + // conservative heuristic; it may report that `needs_drop` is set + // when actual type does not actually have a destructor associated + // with it. But since `ty` absolutely did not have the `Copy` + // bound attached (see above), it is sound to treat it as having a + // destructor (e.g. zero its memory on move). + + let contents = ty::type_contents(cx, ty); + debug!("type_needs_drop ty={} contents={:?}", ty.repr(cx), contents); + contents.needs_drop(cx) } fn type_is_newtype_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool { @@ -534,6 +569,12 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> { self.param_substs, value) } + + /// This is the same as `common::type_needs_drop`, except that it + /// may use or update caches within this `FunctionContext`. + pub fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool { + type_needs_drop_given_env(self.ccx.tcx(), ty, &self.param_env) + } } // Basic block context. We create a block context for each basic block diff --git a/src/librustc_trans/trans/controlflow.rs b/src/librustc_trans/trans/controlflow.rs index ad96c506c9dd..85d0bc0319f3 100644 --- a/src/librustc_trans/trans/controlflow.rs +++ b/src/librustc_trans/trans/controlflow.rs @@ -77,7 +77,7 @@ pub fn trans_stmt_semi<'blk, 'tcx>(cx: Block<'blk, 'tcx>, e: &ast::Expr) -> Block<'blk, 'tcx> { let _icx = push_ctxt("trans_stmt_semi"); let ty = expr_ty(cx, e); - if type_needs_drop(cx.tcx(), ty) { + if cx.fcx.type_needs_drop(ty) { expr::trans_to_lvalue(cx, e, "stmt").bcx } else { expr::trans_into(cx, e, expr::Ignore) diff --git a/src/librustc_trans/trans/datum.rs b/src/librustc_trans/trans/datum.rs index 8262dbf55dda..6ca71254868f 100644 --- a/src/librustc_trans/trans/datum.rs +++ b/src/librustc_trans/trans/datum.rs @@ -311,7 +311,8 @@ impl KindOps for Lvalue { val: ValueRef, ty: Ty<'tcx>) -> Block<'blk, 'tcx> { - if type_needs_drop(bcx.tcx(), ty) { + let _icx = push_ctxt("::post_store"); + if bcx.fcx.type_needs_drop(ty) { // cancel cleanup of affine values by zeroing out let () = zero_mem(bcx, val, ty); bcx @@ -656,7 +657,7 @@ impl<'tcx, K: KindOps + fmt::Debug> Datum<'tcx, K> { /// scalar-ish (like an int or a pointer) which (1) does not require drop glue and (2) is /// naturally passed around by value, and not by reference. pub fn to_llscalarish<'blk>(self, bcx: Block<'blk, 'tcx>) -> ValueRef { - assert!(!type_needs_drop(bcx.tcx(), self.ty)); + assert!(!bcx.fcx.type_needs_drop(self.ty)); assert!(self.appropriate_rvalue_mode(bcx.ccx()) == ByValue); if self.kind.is_by_ref() { load_ty(bcx, self.val, self.ty) diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 5cc1baf66c62..27f9b9506a58 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -974,7 +974,7 @@ fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let src_datum = unpack_datum!(bcx, trans(bcx, &**src)); let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, &**dst, "assign")); - if type_needs_drop(bcx.tcx(), dst_datum.ty) { + if bcx.fcx.type_needs_drop(dst_datum.ty) { // If there are destructors involved, make sure we // are copying from an rvalue, since that cannot possible // alias an lvalue. We are concerned about code like: @@ -1498,7 +1498,7 @@ pub fn trans_adt<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, assert_eq!(discr, 0); match ty::expr_kind(bcx.tcx(), &*base.expr) { - ty::RvalueDpsExpr | ty::RvalueDatumExpr if !type_needs_drop(bcx.tcx(), ty) => { + ty::RvalueDpsExpr | ty::RvalueDatumExpr if !bcx.fcx.type_needs_drop(ty) => { bcx = trans_into(bcx, &*base.expr, SaveIn(addr)); }, ty::RvalueStmtExpr => bcx.tcx().sess.bug("unexpected expr kind for struct base expr"), @@ -2116,7 +2116,7 @@ fn trans_assign_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // Evaluate LHS (destination), which should be an lvalue let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, dst, "assign_op")); - assert!(!type_needs_drop(bcx.tcx(), dst_datum.ty)); + assert!(!bcx.fcx.type_needs_drop(dst_datum.ty)); let dst_ty = dst_datum.ty; let dst = load_ty(bcx, dst_datum.val, dst_datum.ty); diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index c14683aeade0..9491c8377a65 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -99,6 +99,16 @@ pub fn get_drop_glue_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, if !type_is_sized(tcx, t) { return t } + + // FIXME (#22815): note that type_needs_drop conservatively + // approximates in some cases and may say a type expression + // requires drop glue when it actually does not. + // + // (In this case it is not clear whether any harm is done, i.e. + // erroneously returning `t` in some cases where we could have + // returned `tcx.types.i8` does not appear unsound. The impact on + // code quality is unknown at this time.) + if !type_needs_drop(tcx, t) { return tcx.types.i8; } @@ -125,7 +135,7 @@ pub fn drop_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // NB: v is an *alias* of type t here, not a direct value. debug!("drop_ty(t={})", t.repr(bcx.tcx())); let _icx = push_ctxt("drop_ty"); - if type_needs_drop(bcx.tcx(), t) { + if bcx.fcx.type_needs_drop(t) { let ccx = bcx.ccx(); let glue = get_drop_glue(ccx, t); let glue_type = get_drop_glue_type(ccx, t); @@ -480,7 +490,7 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, t: Ty<'tcx>) }, _ => { assert!(type_is_sized(bcx.tcx(), t)); - if type_needs_drop(bcx.tcx(), t) && ty::type_is_structural(t) { + if bcx.fcx.type_needs_drop(t) && ty::type_is_structural(t) { iter_structural_ty(bcx, v0, t, diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index 993c9eae45bf..54644c92869c 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -156,6 +156,8 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, let ccx = fcx.ccx; let tcx = bcx.tcx(); + let _icx = push_ctxt("trans_intrinsic_call"); + let ret_ty = match callee_ty.sty { ty::ty_bare_fn(_, ref f) => { ty::erase_late_bound_regions(bcx.tcx(), &f.sig.output()) @@ -376,7 +378,8 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } (_, "needs_drop") => { let tp_ty = *substs.types.get(FnSpace, 0); - C_bool(ccx, type_needs_drop(ccx.tcx(), tp_ty)) + + C_bool(ccx, bcx.fcx.type_needs_drop(tp_ty)) } (_, "owns_managed") => { let tp_ty = *substs.types.get(FnSpace, 0); diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index 3411f12886d2..4423cd277444 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -454,7 +454,7 @@ fn trans_trait_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let self_datum = unpack_datum!( bcx, expr::trans(bcx, self_expr)); - let llval = if type_needs_drop(bcx.tcx(), self_datum.ty) { + let llval = if bcx.fcx.type_needs_drop(self_datum.ty) { let self_datum = unpack_datum!( bcx, self_datum.to_rvalue_datum(bcx, "trait_callee")); diff --git a/src/librustc_trans/trans/tvec.rs b/src/librustc_trans/trans/tvec.rs index d3acd23e6416..a5c3923336ae 100644 --- a/src/librustc_trans/trans/tvec.rs +++ b/src/librustc_trans/trans/tvec.rs @@ -53,11 +53,10 @@ pub fn make_drop_glue_unboxed<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let not_null = IsNotNull(bcx, vptr); with_cond(bcx, not_null, |bcx| { let ccx = bcx.ccx(); - let tcx = bcx.tcx(); let _icx = push_ctxt("tvec::make_drop_glue_unboxed"); let dataptr = get_dataptr(bcx, vptr); - let bcx = if type_needs_drop(tcx, unit_ty) { + let bcx = if bcx.fcx.type_needs_drop(unit_ty) { let len = get_len(bcx, vptr); iter_vec_raw(bcx, dataptr, diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 844635117b5e..d9dc050aebf1 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -991,6 +991,17 @@ fn trait_ref_to_object_type<'tcx>(this: &AstConv<'tcx>, result } +fn report_ambiguous_associated_type(tcx: &ty::ctxt, + span: Span, + type_str: &str, + trait_str: &str, + name: &str) { + span_err!(tcx.sess, span, E0223, + "ambiguous associated type; specify the type using the syntax \ + `<{} as {}>::{}`", + type_str, trait_str, name); +} + fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, span: Span, ty: Ty<'tcx>, @@ -1011,10 +1022,8 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, let ty_param_node_id = if is_param { ty_path_def.local_node_id() } else { - span_err!(tcx.sess, span, E0223, - "ambiguous associated type; specify the type using the syntax \ - `<{} as Trait>::{}`", - ty.user_string(tcx), token::get_name(assoc_name)); + report_ambiguous_associated_type( + tcx, span, &ty.user_string(tcx), "Trait", &token::get_name(assoc_name)); return (tcx.types.err, ty_path_def); }; @@ -1109,10 +1118,8 @@ fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>, ty } else { let path_str = ty::item_path_str(tcx, trait_def_id); - span_err!(tcx.sess, span, E0223, - "ambiguous associated type; specify the type using the syntax \ - `::{}`", - path_str, &token::get_ident(item_segment.identifier)); + report_ambiguous_associated_type( + tcx, span, "Type", &path_str, &token::get_ident(item_segment.identifier)); return tcx.types.err; }; diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index 05d4e0f59fef..14930f91c915 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -3945,9 +3945,7 @@ mod tests { #[test] fn test_encode_hashmap_with_arbitrary_key() { - use std::old_io::Writer; use std::collections::HashMap; - use std::fmt; #[derive(PartialEq, Eq, Hash, RustcEncodable)] struct ArbitraryType(uint); let mut hm: HashMap = HashMap::new(); diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index f6cb4a8c9f36..b1779587528c 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -173,7 +173,7 @@ mod tests { assert_eq!(writer.write(&[1, 2, 3]), Ok(3)); assert_eq!(writer.write(&[4, 5, 6, 7]), Ok(4)); let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7]; - assert_eq!(&writer.get_ref()[], b); + assert_eq!(&writer.get_ref()[..], b); } #[test] @@ -369,28 +369,28 @@ mod tests { assert_eq!(writer.write(&[4, 5, 6, 7]), Ok(4)); assert_eq!(writer.position(), 8); let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7]; - assert_eq!(&writer.get_ref()[], b); + assert_eq!(&writer.get_ref()[..], b); assert_eq!(writer.seek(SeekFrom::Start(0)), Ok(0)); assert_eq!(writer.position(), 0); assert_eq!(writer.write(&[3, 4]), Ok(2)); let b: &[_] = &[3, 4, 2, 3, 4, 5, 6, 7]; - assert_eq!(&writer.get_ref()[], b); + assert_eq!(&writer.get_ref()[..], b); assert_eq!(writer.seek(SeekFrom::Current(1)), Ok(3)); assert_eq!(writer.write(&[0, 1]), Ok(2)); let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 7]; - assert_eq!(&writer.get_ref()[], b); + assert_eq!(&writer.get_ref()[..], b); assert_eq!(writer.seek(SeekFrom::End(-1)), Ok(7)); assert_eq!(writer.write(&[1, 2]), Ok(2)); let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2]; - assert_eq!(&writer.get_ref()[], b); + assert_eq!(&writer.get_ref()[..], b); assert_eq!(writer.seek(SeekFrom::End(1)), Ok(10)); assert_eq!(writer.write(&[1]), Ok(1)); let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2, 0, 1]; - assert_eq!(&writer.get_ref()[], b); + assert_eq!(&writer.get_ref()[..], b); } #[test] diff --git a/src/libstd/old_io/mem.rs b/src/libstd/old_io/mem.rs index c08a2c1f477b..e6a8b90ea333 100644 --- a/src/libstd/old_io/mem.rs +++ b/src/libstd/old_io/mem.rs @@ -102,6 +102,7 @@ impl MemWriter { impl Writer for MemWriter { #[inline] + #[allow(deprecated)] fn write_all(&mut self, buf: &[u8]) -> IoResult<()> { self.buf.push_all(buf); Ok(()) diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 7bd1f3542eb1..1310d476f8ee 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -384,7 +384,7 @@ impl !Sync for SyncSender {} /// contains the data being sent as a payload so it can be recovered. #[stable(feature = "rust1", since = "1.0.0")] #[derive(PartialEq, Eq, Clone, Copy)] -pub struct SendError(pub T); +pub struct SendError(#[stable(feature = "rust1", since = "1.0.0")] pub T); /// An error returned from the `recv` function on a `Receiver`. /// diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 1c28d629d40f..71b6214460f4 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -291,29 +291,14 @@ fn mkstat(stat: &libc::stat) -> FileStat { // FileStat times are in milliseconds fn mktime(secs: u64, nsecs: u64) -> u64 { secs * 1000 + nsecs / 1000000 } - #[cfg(target_os = "bitrig")] - fn ctime(stat: &libc::stat) -> u64 { - mktime(stat.st_ctim.tv_sec as u64, stat.st_ctim.tv_nsec as u64) - } - #[cfg(not(target_os = "bitrig"))] fn ctime(stat: &libc::stat) -> u64 { mktime(stat.st_ctime as u64, stat.st_ctime_nsec as u64) } - #[cfg(target_os = "bitrig")] - fn atime(stat: &libc::stat) -> u64 { - mktime(stat.st_atim.tv_sec as u64, stat.st_atim.tv_nsec as u64) - } - #[cfg(not(target_os = "bitrig"))] fn atime(stat: &libc::stat) -> u64 { mktime(stat.st_atime as u64, stat.st_atime_nsec as u64) } - #[cfg(target_os = "bitrig")] - fn mtime(stat: &libc::stat) -> u64 { - mktime(stat.st_mtim.tv_sec as u64, stat.st_mtim.tv_nsec as u64) - } - #[cfg(not(target_os = "bitrig"))] fn mtime(stat: &libc::stat) -> u64 { mktime(stat.st_mtime as u64, stat.st_mtime_nsec as u64) } diff --git a/src/libstd/sys/unix/process2.rs b/src/libstd/sys/unix/process2.rs index b7a1b002f559..a7d0a864a08a 100644 --- a/src/libstd/sys/unix/process2.rs +++ b/src/libstd/sys/unix/process2.rs @@ -439,6 +439,7 @@ fn translate_status(status: c_int) -> ExitStatus { target_os = "ios", target_os = "freebsd", target_os = "dragonfly", + target_os = "bitrig", target_os = "openbsd"))] mod imp { pub fn WIFEXITED(status: i32) -> bool { (status & 0x7f) == 0 } diff --git a/src/libstd/sys/windows/time.rs b/src/libstd/sys/windows/time.rs index 20ceff0aa693..209460df10b7 100644 --- a/src/libstd/sys/windows/time.rs +++ b/src/libstd/sys/windows/time.rs @@ -12,6 +12,8 @@ use ops::Sub; use time::Duration; use sync::{Once, ONCE_INIT}; +const NANOS_PER_SEC: i64 = 1_000_000_000; + pub struct SteadyTime { t: libc::LARGE_INTEGER, } @@ -24,7 +26,7 @@ impl SteadyTime { } pub fn ns(&self) -> u64 { - self.t as u64 * 1_000_000_000 / frequency() as u64 + mul_div_i64(self.t as i64, NANOS_PER_SEC, frequency() as i64) as u64 } } @@ -45,6 +47,27 @@ impl<'a> Sub for &'a SteadyTime { fn sub(self, other: &SteadyTime) -> Duration { let diff = self.t as i64 - other.t as i64; - Duration::microseconds(diff * 1_000_000 / frequency() as i64) + Duration::nanoseconds(mul_div_i64(diff, NANOS_PER_SEC, frequency() as i64)) } } + +// Computes (value*numer)/denom without overflow, as long as both +// (numer*denom) and the overall result fit into i64 (which is the case +// for our time conversions). +fn mul_div_i64(value: i64, numer: i64, denom: i64) -> i64 { + let q = value / denom; + let r = value % denom; + // Decompose value as (value/denom*denom + value%denom), + // substitute into (value*numer)/denom and simplify. + // r < denom, so (denom*numer) is the upper bound of (r*numer) + q * numer + r * numer / denom +} + +#[test] +fn test_muldiv() { + assert_eq!(mul_div_i64( 1_000_000_000_001, 1_000_000_000, 1_000_000), 1_000_000_000_001_000); + assert_eq!(mul_div_i64(-1_000_000_000_001, 1_000_000_000, 1_000_000), -1_000_000_000_001_000); + assert_eq!(mul_div_i64(-1_000_000_000_001,-1_000_000_000, 1_000_000), 1_000_000_000_001_000); + assert_eq!(mul_div_i64( 1_000_000_000_001, 1_000_000_000,-1_000_000), -1_000_000_000_001_000); + assert_eq!(mul_div_i64( 1_000_000_000_001,-1_000_000_000,-1_000_000), 1_000_000_000_001_000); +} diff --git a/src/libstd/thread_local/mod.rs b/src/libstd/thread_local/mod.rs index d65156dae960..764c7d730cb0 100644 --- a/src/libstd/thread_local/mod.rs +++ b/src/libstd/thread_local/mod.rs @@ -105,10 +105,12 @@ pub struct Key { // This is trivially devirtualizable by LLVM because we never store anything // to this field and rustc can declare the `static` as constant as well. #[doc(hidden)] + #[unstable(feature = "thread_local_internals")] pub inner: fn() -> &'static __impl::KeyInner>>, // initialization routine to invoke to create a value #[doc(hidden)] + #[unstable(feature = "thread_local_internals")] pub init: fn() -> T, } diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 79f0433761da..264e05f5c8d3 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -760,13 +760,13 @@ mod test { #[test] fn idents_name_eq_test() { assert!(segments_name_eq( &[Ident{name:Name(3),ctxt:4}, Ident{name:Name(78),ctxt:82}] - .iter().map(ident_to_segment).collect::>()[], + .iter().map(ident_to_segment).collect::>(), &[Ident{name:Name(3),ctxt:104}, Ident{name:Name(78),ctxt:182}] - .iter().map(ident_to_segment).collect::>()[])); + .iter().map(ident_to_segment).collect::>())); assert!(!segments_name_eq( &[Ident{name:Name(3),ctxt:4}, Ident{name:Name(78),ctxt:82}] - .iter().map(ident_to_segment).collect::>()[], + .iter().map(ident_to_segment).collect::>(), &[Ident{name:Name(3),ctxt:104}, Ident{name:Name(77),ctxt:182}] - .iter().map(ident_to_segment).collect::>()[])); + .iter().map(ident_to_segment).collect::>())); } } diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index fa6d934a4575..67011ad21a6d 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -334,6 +334,10 @@ fn check_matcher<'a, I>(cx: &mut ExtCtxt, matcher: I, follow: &Token) let tok = if let TtToken(_, ref tok) = *token { tok } else { unreachable!() }; // If T' is in the set FOLLOW(NT), continue. Else, reject. match (&next_token, is_in_follow(cx, &next_token, frag_spec.as_str())) { + (_, Err(msg)) => { + cx.span_err(sp, &msg); + continue + } (&Eof, _) => return Some((sp, tok.clone())), (_, Ok(true)) => continue, (next, Ok(false)) => { @@ -343,10 +347,6 @@ fn check_matcher<'a, I>(cx: &mut ExtCtxt, matcher: I, follow: &Token) token_to_string(next))); continue }, - (_, Err(msg)) => { - cx.span_err(sp, &msg); - continue - } } }, TtSequence(sp, ref seq) => { diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 82c1a4b1195c..7c7f1fd478aa 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -506,16 +506,25 @@ impl ConsoleTestState { if self.use_color { try!(term.reset()); } - Ok(()) + term.flush() + } + Raw(ref mut stdout) => { + try!(stdout.write_all(word.as_bytes())); + stdout.flush() } - Raw(ref mut stdout) => stdout.write_all(word.as_bytes()) } } pub fn write_plain(&mut self, s: &str) -> old_io::IoResult<()> { match self.out { - Pretty(ref mut term) => term.write_all(s.as_bytes()), - Raw(ref mut stdout) => stdout.write_all(s.as_bytes()) + Pretty(ref mut term) => { + try!(term.write_all(s.as_bytes())); + term.flush() + }, + Raw(ref mut stdout) => { + try!(stdout.write_all(s.as_bytes())); + stdout.flush() + }, } } diff --git a/src/rustbook/book.rs b/src/rustbook/book.rs index 3c116aa860bc..8900b60d1913 100644 --- a/src/rustbook/book.rs +++ b/src/rustbook/book.rs @@ -114,12 +114,12 @@ pub fn parse_summary(input: R, src: &Path) -> Result i, None => continue }; + let star_idx = match line.find("*") { Some(i) => i, None => continue }; - let start_bracket = star_idx + line[star_idx..].find_str("[").unwrap(); - let end_bracket = start_bracket + line[start_bracket..].find_str("](").unwrap(); + let start_bracket = star_idx + line[star_idx..].find("[").unwrap(); + let end_bracket = start_bracket + line[start_bracket..].find("](").unwrap(); let start_paren = end_bracket + 1; - let end_paren = start_paren + line[start_paren..].find_str(")").unwrap(); + let end_paren = start_paren + line[start_paren..].find(")").unwrap(); let given_path = &line[start_paren + 1 .. end_paren]; let title = line[start_bracket + 1..end_bracket].to_string(); diff --git a/src/test/auxiliary/lint_stability.rs b/src/test/auxiliary/lint_stability.rs index fb535eb8336f..d47575403e17 100644 --- a/src/test/auxiliary/lint_stability.rs +++ b/src/test/auxiliary/lint_stability.rs @@ -100,14 +100,22 @@ pub trait UnstableTrait { fn dummy(&self) { } } #[stable(feature = "test_feature", since = "1.0.0")] #[deprecated(since = "1.0.0")] -pub struct DeprecatedStruct { pub i: int } +pub struct DeprecatedStruct { + #[stable(feature = "test_feature", since = "1.0.0")] pub i: int +} #[unstable(feature = "test_feature")] #[deprecated(since = "1.0.0")] -pub struct DeprecatedUnstableStruct { pub i: int } +pub struct DeprecatedUnstableStruct { + #[stable(feature = "test_feature", since = "1.0.0")] pub i: int +} #[unstable(feature = "test_feature")] -pub struct UnstableStruct { pub i: int } +pub struct UnstableStruct { + #[stable(feature = "test_feature", since = "1.0.0")] pub i: int +} #[stable(feature = "rust1", since = "1.0.0")] -pub struct StableStruct { pub i: int } +pub struct StableStruct { + #[stable(feature = "test_feature", since = "1.0.0")] pub i: int +} #[stable(feature = "test_feature", since = "1.0.0")] #[deprecated(since = "1.0.0")] @@ -137,14 +145,14 @@ pub enum Enum { #[stable(feature = "test_feature", since = "1.0.0")] #[deprecated(since = "1.0.0")] -pub struct DeprecatedTupleStruct(pub int); +pub struct DeprecatedTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub int); #[unstable(feature = "test_feature")] #[deprecated(since = "1.0.0")] -pub struct DeprecatedUnstableTupleStruct(pub int); +pub struct DeprecatedUnstableTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub int); #[unstable(feature = "test_feature")] -pub struct UnstableTupleStruct(pub int); +pub struct UnstableTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub int); #[stable(feature = "rust1", since = "1.0.0")] -pub struct StableTupleStruct(pub int); +pub struct StableTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub int); #[macro_export] macro_rules! macro_test { diff --git a/src/test/auxiliary/lint_stability_fields.rs b/src/test/auxiliary/lint_stability_fields.rs new file mode 100644 index 000000000000..66940ee0081b --- /dev/null +++ b/src/test/auxiliary/lint_stability_fields.rs @@ -0,0 +1,60 @@ +// 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. + +#![feature(staged_api)] +#![staged_api] +#![stable(feature = "rust1", since = "1.0.0")] + +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Stable { + #[stable(feature = "rust1", since = "1.0.0")] + pub inherit: u8, // it's a lie (stable doesn't inherit) + #[unstable(feature = "test_feature")] + pub override1: u8, + #[deprecated(since = "1.0.0")] + #[unstable(feature = "test_feature")] + pub override2: u8, +} + +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Stable2(#[stable(feature = "rust1", since = "1.0.0")] pub u8, + #[unstable(feature = "test_feature")] pub u8, + #[unstable(feature = "test_feature")] #[deprecated(since = "1.0.0")] pub u8); + +#[unstable(feature = "test_feature")] +pub struct Unstable { + pub inherit: u8, + #[stable(feature = "rust1", since = "1.0.0")] + pub override1: u8, + #[deprecated(since = "1.0.0")] + #[unstable(feature = "test_feature")] + pub override2: u8, +} + +#[unstable(feature = "test_feature")] +pub struct Unstable2(pub u8, + #[stable(feature = "rust1", since = "1.0.0")] pub u8, + #[unstable(feature = "test_feature")] #[deprecated(since = "1.0.0")] pub u8); + +#[unstable(feature = "test_feature")] +#[deprecated(feature = "rust1", since = "1.0.0")] +pub struct Deprecated { + pub inherit: u8, + #[stable(feature = "rust1", since = "1.0.0")] + pub override1: u8, + #[unstable(feature = "test_feature")] + pub override2: u8, +} + +#[unstable(feature = "test_feature")] +#[deprecated(feature = "rust1", since = "1.0.0")] +pub struct Deprecated2(pub u8, + #[stable(feature = "rust1", since = "1.0.0")] pub u8, + #[unstable(feature = "test_feature")] pub u8); diff --git a/src/test/auxiliary/static-methods-crate.rs b/src/test/auxiliary/static-methods-crate.rs index d84ded25702f..e61fb49add5b 100644 --- a/src/test/auxiliary/static-methods-crate.rs +++ b/src/test/auxiliary/static-methods-crate.rs @@ -11,14 +11,12 @@ #![crate_name="static_methods_crate"] #![crate_type = "lib"] -use std::int; - pub trait read { fn readMaybe(s: String) -> Option; } -impl read for int { - fn readMaybe(s: String) -> Option { +impl read for isize { + fn readMaybe(s: String) -> Option { s.parse().ok() } } diff --git a/src/test/bench/task-perf-alloc-unwind.rs b/src/test/bench/task-perf-alloc-unwind.rs index 6b412c47cd7f..896b0ee57a04 100644 --- a/src/test/bench/task-perf-alloc-unwind.rs +++ b/src/test/bench/task-perf-alloc-unwind.rs @@ -40,9 +40,7 @@ fn run(repeat: int, depth: int) { } } -// FIXME(#21721) used to be `List<()>` but that can cause -// certain LLVM versions to abort during optimizations. -type nillist = List<[u8; 0]>; +type nillist = List<()>; // Filled with things that have to be unwound @@ -83,11 +81,11 @@ fn recurse_or_panic(depth: int, st: Option) { } Some(st) => { let mut v = st.vec.clone(); - v.push_all(&[box List::Cons([], st.vec.last().unwrap().clone())]); + v.push_all(&[box List::Cons((), st.vec.last().unwrap().clone())]); State { - unique: box List::Cons([], box *st.unique), + unique: box List::Cons((), box *st.unique), vec: v, - res: r(box List::Cons([], st.res._l.clone())), + res: r(box List::Cons((), st.res._l.clone())), } } }; diff --git a/src/test/compile-fail/lint-stability-fields.rs b/src/test/compile-fail/lint-stability-fields.rs new file mode 100644 index 000000000000..c43ff1989250 --- /dev/null +++ b/src/test/compile-fail/lint-stability-fields.rs @@ -0,0 +1,346 @@ +// 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. + +// aux-build:lint_stability_fields.rs +#![deny(deprecated)] +#![allow(dead_code)] +#![feature(staged_api)] +#![staged_api] + +mod cross_crate { + extern crate lint_stability_fields; + + use self::lint_stability_fields::*; + + pub fn foo() { + let x = Stable { + inherit: 1, + override1: 2, //~ WARN use of unstable + override2: 3, + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + }; + + let _ = x.inherit; + let _ = x.override1; //~ WARN use of unstable + let _ = x.override2; + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + + let Stable { + inherit: _, + override1: _, //~ WARN use of unstable + override2: _ + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + } = x; + // all fine + let Stable { .. } = x; + + let x = Stable2(1, 2, 3); + + let _ = x.0; + let _ = x.1; //~ WARN use of unstable + let _ = x.2; + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + + let Stable2(_, + _, //~ WARN use of unstable + _) + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + = x; + // all fine + let Stable2(..) = x; + + + let x = Unstable { //~ WARN use of unstable + inherit: 1, //~ WARN use of unstable + override1: 2, + override2: 3, + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + }; + + let _ = x.inherit; //~ WARN use of unstable + let _ = x.override1; + let _ = x.override2; + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + + let Unstable { //~ WARN use of unstable + inherit: _, //~ WARN use of unstable + override1: _, + override2: _ + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + } = x; + + let Unstable //~ WARN use of unstable + // the patterns are all fine: + { .. } = x; + + + let x = Unstable2(1, 2, 3); //~ WARN use of unstable + + let _ = x.0; //~ WARN use of unstable + let _ = x.1; + let _ = x.2; + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + + let Unstable2 //~ WARN use of unstable + (_, //~ WARN use of unstable + _, + _) + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + = x; + let Unstable2 //~ WARN use of unstable + // the patterns are all fine: + (..) = x; + + + let x = Deprecated { + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + inherit: 1, + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + override1: 2, + override2: 3, //~ WARN use of unstable + }; + + let _ = x.inherit; + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + let _ = x.override1; + let _ = x.override2; //~ WARN use of unstable + + let Deprecated { + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + inherit: _, + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + override1: _, + override2: _ //~ WARN use of unstable + } = x; + + let Deprecated + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + // the patterns are all fine: + { .. } = x; + + let x = Deprecated2(1, 2, 3); + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + + let _ = x.0; + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + let _ = x.1; + let _ = x.2; //~ WARN use of unstable + + let Deprecated2 + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + (_, + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + _, + _) //~ WARN use of unstable + = x; + let Deprecated2 + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + // the patterns are all fine: + (..) = x; + } +} + +mod this_crate { + #[stable(feature = "rust1", since = "1.0.0")] + struct Stable { + inherit: u8, + #[unstable(feature = "test_feature")] + override1: u8, + #[deprecated(since = "1.0.0")] + #[unstable(feature = "test_feature")] + override2: u8, + } + + #[stable(feature = "rust1", since = "1.0.0")] + struct Stable2(u8, + #[stable(feature = "rust1", since = "1.0.0")] u8, + #[unstable(feature = "test_feature")] #[deprecated(since = "1.0.0")] u8); + + #[unstable(feature = "test_feature")] + struct Unstable { + inherit: u8, + #[stable(feature = "rust1", since = "1.0.0")] + override1: u8, + #[deprecated(since = "1.0.0")] + #[unstable(feature = "test_feature")] + override2: u8, + } + + #[unstable(feature = "test_feature")] + struct Unstable2(u8, + #[stable(feature = "rust1", since = "1.0.0")] u8, + #[unstable(feature = "test_feature")] #[deprecated(since = "1.0.0")] u8); + + #[unstable(feature = "test_feature")] + #[deprecated(feature = "rust1", since = "1.0.0")] + struct Deprecated { + inherit: u8, + #[stable(feature = "rust1", since = "1.0.0")] + override1: u8, + #[unstable(feature = "test_feature")] + override2: u8, + } + + #[unstable(feature = "test_feature")] + #[deprecated(feature = "rust1", since = "1.0.0")] + struct Deprecated2(u8, + #[stable(feature = "rust1", since = "1.0.0")] u8, + #[unstable(feature = "test_feature")] u8); + + pub fn foo() { + let x = Stable { + inherit: 1, + override1: 2, + override2: 3, + //~^ ERROR use of deprecated item + }; + + let _ = x.inherit; + let _ = x.override1; + let _ = x.override2; + //~^ ERROR use of deprecated item + + let Stable { + inherit: _, + override1: _, + override2: _ + //~^ ERROR use of deprecated item + } = x; + // all fine + let Stable { .. } = x; + + let x = Stable2(1, 2, 3); + + let _ = x.0; + let _ = x.1; + let _ = x.2; + //~^ ERROR use of deprecated item + + let Stable2(_, + _, + _) + //~^ ERROR use of deprecated item + = x; + // all fine + let Stable2(..) = x; + + + let x = Unstable { + inherit: 1, + override1: 2, + override2: 3, + //~^ ERROR use of deprecated item + }; + + let _ = x.inherit; + let _ = x.override1; + let _ = x.override2; + //~^ ERROR use of deprecated item + + let Unstable { + inherit: _, + override1: _, + override2: _ + //~^ ERROR use of deprecated item + } = x; + + let Unstable + // the patterns are all fine: + { .. } = x; + + + let x = Unstable2(1, 2, 3); + + let _ = x.0; + let _ = x.1; + let _ = x.2; + //~^ ERROR use of deprecated item + + let Unstable2 + (_, + _, + _) + //~^ ERROR use of deprecated item + = x; + let Unstable2 + // the patterns are all fine: + (..) = x; + + + let x = Deprecated { + //~^ ERROR use of deprecated item + inherit: 1, + //~^ ERROR use of deprecated item + override1: 2, + override2: 3, + }; + + let _ = x.inherit; + //~^ ERROR use of deprecated item + let _ = x.override1; + let _ = x.override2; + + let Deprecated { + //~^ ERROR use of deprecated item + inherit: _, + //~^ ERROR use of deprecated item + override1: _, + override2: _ + } = x; + + let Deprecated + //~^ ERROR use of deprecated item + // the patterns are all fine: + { .. } = x; + + let x = Deprecated2(1, 2, 3); + //~^ ERROR use of deprecated item + + let _ = x.0; + //~^ ERROR use of deprecated item + let _ = x.1; + let _ = x.2; + + let Deprecated2 + //~^ ERROR use of deprecated item + (_, + //~^ ERROR use of deprecated item + _, + _) + = x; + let Deprecated2 + //~^ ERROR use of deprecated item + // the patterns are all fine: + (..) = x; + } +} + +fn main() {} diff --git a/src/test/compile-fail/lint-stability.rs b/src/test/compile-fail/lint-stability.rs index 907928488557..12548c453961 100644 --- a/src/test/compile-fail/lint-stability.rs +++ b/src/test/compile-fail/lint-stability.rs @@ -317,11 +317,17 @@ mod this_crate { #[unstable(feature = "test_feature")] #[deprecated(since = "1.0.0")] - pub struct DeprecatedStruct { i: isize } + pub struct DeprecatedStruct { + #[stable(feature = "test_feature", since = "1.0.0")] i: isize + } #[unstable(feature = "test_feature")] - pub struct UnstableStruct { i: isize } + pub struct UnstableStruct { + #[stable(feature = "test_feature", since = "1.0.0")] i: isize + } #[stable(feature = "rust1", since = "1.0.0")] - pub struct StableStruct { i: isize } + pub struct StableStruct { + #[stable(feature = "test_feature", since = "1.0.0")] i: isize + } #[unstable(feature = "test_feature")] #[deprecated(since = "1.0.0")] diff --git a/src/test/compile-fail/unused-macro-with-bad-frag-spec.rs b/src/test/compile-fail/unused-macro-with-bad-frag-spec.rs new file mode 100644 index 000000000000..b868b79365d9 --- /dev/null +++ b/src/test/compile-fail/unused-macro-with-bad-frag-spec.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. + +// Issue #21370 + +macro_rules! test { + ($wrong:t_ty) => () //~ ERROR invalid fragment specifier `t_ty` +} + +fn main() { } diff --git a/src/test/compile-fail/unused-macro-with-follow-violation.rs b/src/test/compile-fail/unused-macro-with-follow-violation.rs new file mode 100644 index 000000000000..e9d09bb6ad9c --- /dev/null +++ b/src/test/compile-fail/unused-macro-with-follow-violation.rs @@ -0,0 +1,15 @@ +// 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. + +macro_rules! test { + ($e:expr +) => () //~ ERROR not allowed for `expr` fragments +} + +fn main() { } diff --git a/src/test/run-pass/deriving-primitive.rs b/src/test/run-pass/deriving-primitive.rs index eb3cb30594ea..6b365c348f78 100644 --- a/src/test/run-pass/deriving-primitive.rs +++ b/src/test/run-pass/deriving-primitive.rs @@ -9,18 +9,18 @@ // except according to those terms. use std::num::FromPrimitive; -use std::int; +use std::isize; #[derive(PartialEq, FromPrimitive, Debug)] enum A { - Foo = int::MAX, + Foo = isize::MAX, Bar = 1, Baz = 3, Qux, } pub fn main() { - let x: Option = FromPrimitive::from_int(int::MAX); + let x: Option = FromPrimitive::from_int(isize::MAX); assert_eq!(x, Some(A::Foo)); let x: Option = FromPrimitive::from_int(1); diff --git a/src/test/run-pass/issue-17216.rs b/src/test/run-pass/issue-17216.rs index ce5a0aa96e3d..aa53a7658e12 100644 --- a/src/test/run-pass/issue-17216.rs +++ b/src/test/run-pass/issue-17216.rs @@ -25,9 +25,7 @@ fn main() { let mut dropped = false; { let leak = Leak { dropped: &mut dropped }; - // FIXME(#21721) "hack" used to be () but that can cause - // certain LLVM versions to abort during optimizations. - for (_, leaked) in Some(("hack", leak)).into_iter() {} + for ((), leaked) in Some(((), leak)).into_iter() {} } assert!(dropped); diff --git a/src/test/run-pass/issue-21721.rs b/src/test/run-pass/issue-21721.rs new file mode 100644 index 000000000000..fee14061c566 --- /dev/null +++ b/src/test/run-pass/issue-21721.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. + +fn main() { + static NONE: Option<((), &'static u8)> = None; + let ptr = unsafe { + *(&NONE as *const _ as *const *const u8) + }; + assert!(ptr.is_null()); +} diff --git a/src/test/run-pass/issue-22536-copy-mustnt-zero.rs b/src/test/run-pass/issue-22536-copy-mustnt-zero.rs new file mode 100644 index 000000000000..b3492180a582 --- /dev/null +++ b/src/test/run-pass/issue-22536-copy-mustnt-zero.rs @@ -0,0 +1,34 @@ +// 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. + +// Regression test for Issue #22536: If a type implements Copy, then +// moving it must not zero the original memory. + +trait Resources { + type Buffer: Copy; + fn foo(&self) {} +} + +struct BufferHandle { + raw: ::Buffer, +} +impl Copy for BufferHandle {} + +enum Res {} +impl Resources for Res { + type Buffer = u32; +} +impl Copy for Res { } + +fn main() { + let b: BufferHandle = BufferHandle { raw: 1 }; + let c = b; + assert_eq!(c.raw, b.raw) +} diff --git a/src/test/run-pass/match-with-ret-arm.rs b/src/test/run-pass/match-with-ret-arm.rs index 05c6aac90e39..d2e27fc822ee 100644 --- a/src/test/run-pass/match-with-ret-arm.rs +++ b/src/test/run-pass/match-with-ret-arm.rs @@ -8,13 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::uint; - pub fn main() { // sometimes we have had trouble finding // the right type for f, as we unified // bot and u32 here - let f = match "1234".parse::().ok() { + let f = match "1234".parse::().ok() { None => return (), Some(num) => num as u32 }; diff --git a/src/test/run-pass/traits-issue-22655.rs b/src/test/run-pass/traits-issue-22655.rs new file mode 100644 index 000000000000..18c7cfb0850c --- /dev/null +++ b/src/test/run-pass/traits-issue-22655.rs @@ -0,0 +1,29 @@ +// 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. + +// Regression test for issue #22655: This test should not lead to +// infinite recursion. + +unsafe impl Send for Unique { } + +pub struct Unique { + pointer: *const T, +} + +pub struct Node { + vals: V, + edges: Unique>, +} + +fn is_send() {} + +fn main() { + is_send::>(); +}