]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #27192 - dotdash:inline_eq_slice, r=luqmana
authorbors <bors@rust-lang.org>
Thu, 23 Jul 2015 02:24:06 +0000 (02:24 +0000)
committerbors <bors@rust-lang.org>
Thu, 23 Jul 2015 02:24:06 +0000 (02:24 +0000)
eq_slice_() used to be a common implementation for two function that
both called it, but of those only eq_slice() is left, so we can as well
directly inline the code.

74 files changed:
mk/rt.mk
src/doc/trpl/ffi.md
src/doc/trpl/installing-rust.md
src/doc/trpl/release-channels.md
src/doc/trpl/unsafe.md
src/liballoc/lib.rs
src/libcollections/lib.rs
src/libcollections/string.rs
src/libcore/intrinsics.rs
src/libcore/iter.rs
src/liblibc/lib.rs
src/librustc/diagnostics.rs
src/librustc/middle/check_const.rs
src/librustc/middle/check_match.rs
src/librustc/middle/const_eval.rs
src/librustc/middle/intrinsicck.rs
src/librustc/middle/lang_items.rs
src/librustc/middle/resolve_lifetime.rs
src/librustc/middle/ty.rs
src/librustc/middle/weak_lang_items.rs
src/librustc_lint/builtin.rs
src/librustc_llvm/lib.rs
src/librustc_resolve/diagnostics.rs
src/librustc_trans/save/dump_csv.rs
src/librustc_trans/trans/_match.rs
src/librustc_trans/trans/build.rs
src/librustc_trans/trans/builder.rs
src/librustc_trans/trans/callee.rs
src/librustc_trans/trans/cleanup.rs
src/librustc_trans/trans/closure.rs
src/librustc_trans/trans/common.rs
src/librustc_trans/trans/consts.rs
src/librustc_trans/trans/context.rs
src/librustc_trans/trans/declare.rs
src/librustc_trans/trans/foreign.rs
src/librustc_trans/trans/intrinsic.rs
src/librustc_trans/trans/meth.rs
src/librustc_trans/trans/monomorphize.rs
src/librustc_typeck/astconv.rs
src/librustc_typeck/check/_match.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/diagnostics.rs
src/librustc_typeck/lib.rs
src/libstd/io/buffered.rs
src/libstd/io/cursor.rs
src/libstd/io/mod.rs
src/libstd/io/util.rs
src/libstd/rt/mod.rs
src/libstd/rt/unwind/gcc.rs
src/libstd/rt/unwind/mod.rs
src/libstd/rt/unwind/seh.rs
src/libstd/sys/common/thread_info.rs
src/libstd/sys/unix/thread.rs
src/libstd/sys/windows/thread.rs
src/libstd/sys/windows/thread_local.rs
src/libstd/thread/mod.rs
src/rt/rust_try.ll [deleted file]
src/rt/rust_try_msvc_32.ll [deleted file]
src/rt/rust_try_msvc_64.ll [deleted file]
src/rustllvm/RustWrapper.cpp
src/snapshots.txt
src/test/compile-fail/issue-20162.rs [new file with mode: 0644]
src/test/compile-fail/issue-21174.rs
src/test/compile-fail/lint-exceeding-bitshifts.rs
src/test/compile-fail/match-range-fail-2.rs [new file with mode: 0644]
src/test/compile-fail/match-range-fail.rs
src/test/compile-fail/repeat_count.rs
src/test/run-pass/dropck_legal_cycles.rs [new file with mode: 0644]
src/test/run-pass/issue-10436.rs [new file with mode: 0644]
src/test/run-pass/issue-14229.rs [new file with mode: 0644]
src/test/run-pass/issue-14382.rs [new file with mode: 0644]
src/test/run-pass/issue-19404.rs [new file with mode: 0644]
src/test/run-pass/issue-25343.rs [new file with mode: 0644]
src/test/run-pass/issue-26468.rs [new file with mode: 0644]

index c70f9e8a37addfd80a78855c85de180943602719..69277e774e43bf99e41f767dfd70a4c1608c53d9 100644 (file)
--- a/mk/rt.mk
+++ b/mk/rt.mk
@@ -54,15 +54,6 @@ NATIVE_DEPS_miniz_$(1) = miniz.c
 NATIVE_DEPS_rust_builtin_$(1) := rust_builtin.c \
                        rust_android_dummy.c
 NATIVE_DEPS_rustrt_native_$(1) := arch/$$(HOST_$(1))/record_sp.S
-ifeq ($$(findstring msvc,$(1)),msvc)
-ifeq ($$(findstring i686,$(1)),i686)
-NATIVE_DEPS_rustrt_native_$(1) += rust_try_msvc_32.ll
-else
-NATIVE_DEPS_rustrt_native_$(1) += rust_try_msvc_64.ll
-endif
-else
-NATIVE_DEPS_rustrt_native_$(1) += rust_try.ll
-endif
 NATIVE_DEPS_rust_test_helpers_$(1) := rust_test_helpers.c
 NATIVE_DEPS_morestack_$(1) := arch/$$(HOST_$(1))/morestack.S
 
@@ -76,14 +67,6 @@ NATIVE_DEPS_morestack_$(1) := arch/$$(HOST_$(1))/morestack.S
 
 RT_OUTPUT_DIR_$(1) := $(1)/rt
 
-$$(RT_OUTPUT_DIR_$(1))/%.o: $(S)src/rt/%.ll $$(MKFILE_DEPS) \
-           $$(LLVM_CONFIG_$$(CFG_BUILD))
-       @mkdir -p $$(@D)
-       @$$(call E, compile: $$@)
-       $$(Q)$$(LLC_$$(CFG_BUILD)) $$(CFG_LLC_FLAGS_$(1)) \
-           -filetype=obj -mtriple=$$(CFG_LLVM_TARGET_$(1)) \
-           -relocation-model=pic -o $$@ $$<
-
 $$(RT_OUTPUT_DIR_$(1))/%.o: $(S)src/rt/%.c $$(MKFILE_DEPS)
        @mkdir -p $$(@D)
        @$$(call E, compile: $$@)
@@ -122,7 +105,6 @@ define THIRD_PARTY_LIB
 OBJS_$(2)_$(1) := $$(NATIVE_DEPS_$(2)_$(1):%=$$(RT_OUTPUT_DIR_$(1))/%)
 OBJS_$(2)_$(1) := $$(OBJS_$(2)_$(1):.c=.o)
 OBJS_$(2)_$(1) := $$(OBJS_$(2)_$(1):.cpp=.o)
-OBJS_$(2)_$(1) := $$(OBJS_$(2)_$(1):.ll=.o)
 OBJS_$(2)_$(1) := $$(OBJS_$(2)_$(1):.S=.o)
 NATIVE_$(2)_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),$(2))
 $$(RT_OUTPUT_DIR_$(1))/$$(NATIVE_$(2)_$(1)): $$(OBJS_$(2)_$(1))
index cbedf863714146b8e4e8cd4ffe3b4fe4c6890219..753a5a32e8a1bfff0249e479e05ffd7292f0b998 100644 (file)
@@ -340,7 +340,7 @@ libraries:
 Note that frameworks are only available on OSX targets.
 
 The different `kind` values are meant to differentiate how the native library
-participates in linkage. From a linkage perspective, the rust compiler creates
+participates in linkage. From a linkage perspective, the Rust compiler creates
 two flavors of artifacts: partial (rlib/staticlib) and final (dylib/binary).
 Native dynamic library and framework dependencies are propagated to the final
 artifact boundary, while static library dependencies are not propagated at
@@ -350,9 +350,9 @@ artifact.
 A few examples of how this model can be used are:
 
 * A native build dependency. Sometimes some C/C++ glue is needed when writing
-  some rust code, but distribution of the C/C++ code in a library format is just
+  some Rust code, but distribution of the C/C++ code in a library format is just
   a burden. In this case, the code will be archived into `libfoo.a` and then the
-  rust crate would declare a dependency via `#[link(name = "foo", kind =
+  Rust crate would declare a dependency via `#[link(name = "foo", kind =
   "static")]`.
 
   Regardless of the flavor of output for the crate, the native static library
@@ -361,7 +361,7 @@ A few examples of how this model can be used are:
 
 * A normal dynamic dependency. Common system libraries (like `readline`) are
   available on a large number of systems, and often a static copy of these
-  libraries cannot be found. When this dependency is included in a rust crate,
+  libraries cannot be found. When this dependency is included in a Rust crate,
   partial targets (like rlibs) will not link to the library, but when the rlib
   is included in a final target (like a binary), the native library will be
   linked in.
index 39e8ea6cbd319b5c223fca780d236578ee729eec..83750ec3b01adff931f9dfc68d22bd13e526b55d 100644 (file)
@@ -2,7 +2,7 @@
 
 The first step to using Rust is to install it! There are a number of ways to
 install Rust, but the easiest is to use the `rustup` script. If you're on Linux
-or a Mac, all you need to do is this: 
+or a Mac, all you need to do is this:
 
 > Note: you don't need to type in the `$`s, they just indicate the start of
 > each command. You’ll see many tutorials and examples around the web that
@@ -25,6 +25,12 @@ $ sh rustup.sh
 [insecurity]: http://curlpipesh.tumblr.com
 
 If you're on Windows, please download the appropriate [installer][install-page].
+**NOTE:** By default, the Windows installer will not add Rust to the %PATH%
+system variable. If this is the only version of Rust you are installing and you
+want to be able to run it from the command line, click on "Advanced" on the
+install dialog and on the "Product Features" page ensure "Add to PATH" is
+installed on the local hard drive.
+
 
 [install-page]: http://www.rust-lang.org/install.html
 
@@ -87,6 +93,11 @@ rustc 1.0.0 (a59de37e9 2015-05-13)
 
 If you did, Rust has been installed successfully! Congrats!
 
+If you didn't and you're on Windows, check that Rust is in your %PATH% system
+variable. If it isn't, run the installer again, select "Change" on the "Change,
+repair, or remove installation" page and ensure "Add to PATH" is installed on
+the local hard drive.
+
 This installer also installs a copy of the documentation locally, so you can
 read it offline. On UNIX systems, `/usr/local/share/doc/rust` is the location.
 On Windows, it's in a `share/doc` directory, inside wherever you installed Rust
@@ -101,5 +112,5 @@ resources include [the user’s forum][users], and
 
 [irc]: irc://irc.mozilla.org/#rust
 [mibbit]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust
-[users]: http://users.rust-lang.org/ 
+[users]: http://users.rust-lang.org/
 [stackoverflow]: http://stackoverflow.com/questions/tagged/rust
index 03e65539a20429e4ba50c2880e63224315ff4b42..1e203c6553ee107f11cf205bab3da4062133225c 100644 (file)
@@ -43,3 +43,26 @@ This will help alert the team in case there’s an accidental regression.
 Additionally, testing against nightly can catch regressions even sooner, and so
 if you don’t mind a third build, we’d appreciate testing against all channels.
 
+As an example, many Rust programmers use [Travis](https://travis-ci.org/) to
+test their crates, which is free for open source projects. Travis [supports
+Rust directly][travis], and you can use a `.travis.yml` file like this to
+test on all channels:
+
+```yaml
+language: rust
+rust:
+  - nightly
+  - beta
+  - stable
+
+matrix:
+  allow_failures:
+    - rust: nightly
+```
+
+[travis]: http://docs.travis-ci.com/user/languages/rust/
+
+With this configuration, Travis will test all three channels, but if something
+breaks on nightly, it won’t fail your build. A similar configuration is
+recommended for any CI system, check the documentation of the one you’re
+using for more details.
index 80b0c87473fa2e23fbef395fa5aa502e442d5116..1b223365bd63ac72a15c072fc79da5a5ec3967d9 100644 (file)
@@ -100,10 +100,14 @@ that you normally can not do. Just three. Here they are:
 
 That’s it. It’s important that `unsafe` does not, for example, â€˜turn off the
 borrow checker’. Adding `unsafe` to some random Rust code doesn’t change its
-semantics, it won’t just start accepting anything.
+semantics, it won’t just start accepting anything. But it will let you write
+things that _do_ break some of the rules.
 
-But it will let you write things that _do_ break some of the rules. Let’s go
-over these three abilities in order.
+You will also encounter the `unsafe` keyword when writing bindings to foreign
+(non-Rust) interfaces. You're encouraged to write a safe, native Rust interface
+around the methods provided by the library.
+
+Let’s go over the basic three abilities listed, in order.
 
 ## Access or update a `static mut`
 
index 5c1fd2a1aa1f487661a8a88383ceb79cf8a09db6..ead0b4259a987cdf4f0357fca67e3305b1e499e7 100644 (file)
@@ -135,20 +135,3 @@ pub fn oom() -> ! {
     //                allocate.
     unsafe { core::intrinsics::abort() }
 }
-
-// FIXME(#14344): When linking liballoc with libstd, this library will be linked
-//                as an rlib (it only exists as an rlib). It turns out that an
-//                optimized standard library doesn't actually use *any* symbols
-//                from this library. Everything is inlined and optimized away.
-//                This means that linkers will actually omit the object for this
-//                file, even though it may be needed in the future.
-//
-//                To get around this for now, we define a dummy symbol which
-//                will never get inlined so the stdlib can call it. The stdlib's
-//                reference to this symbol will cause this library's object file
-//                to get linked in to libstd successfully (the linker won't
-//                optimize it out).
-#[doc(hidden)]
-#[unstable(feature = "issue_14344_fixme")]
-#[cfg(stage0)]
-pub fn fixme_14344_be_sure_to_link_to_collections() {}
index a2b2ae220f88ed1e8a6c3304d878750436b77f49..1f94838499218ee1bc22168ed3f7024c5e816c4f 100644 (file)
@@ -133,13 +133,6 @@ pub mod btree_set {
     pub use btree::set::*;
 }
 
-
-// FIXME(#14344) this shouldn't be necessary
-#[doc(hidden)]
-#[unstable(feature = "issue_14344_fixme")]
-#[cfg(stage0)]
-pub fn fixme_14344_be_sure_to_link_to_collections() {}
-
 #[cfg(not(test))]
 mod std {
     pub use core::ops;      // RangeFull
index ebff4a9126dafa2beb466067d1a0e6fb5797ac89..cc58952be600a341451a12c81af1b00b9f4379c3 100644 (file)
@@ -979,7 +979,6 @@ fn index(&self, _index: ops::RangeFull) -> &str {
     }
 }
 
-#[cfg(not(stage0))]
 #[stable(feature = "derefmut_for_string", since = "1.2.0")]
 impl ops::IndexMut<ops::Range<usize>> for String {
     #[inline]
@@ -987,7 +986,6 @@ fn index_mut(&mut self, index: ops::Range<usize>) -> &mut str {
         &mut self[..][index]
     }
 }
-#[cfg(not(stage0))]
 #[stable(feature = "derefmut_for_string", since = "1.2.0")]
 impl ops::IndexMut<ops::RangeTo<usize>> for String {
     #[inline]
@@ -995,7 +993,6 @@ fn index_mut(&mut self, index: ops::RangeTo<usize>) -> &mut str {
         &mut self[..][index]
     }
 }
-#[cfg(not(stage0))]
 #[stable(feature = "derefmut_for_string", since = "1.2.0")]
 impl ops::IndexMut<ops::RangeFrom<usize>> for String {
     #[inline]
index 74901553149abce3083c27d6c77262ad0d093b73..ef022179772c4cd4c9a60eb53a143e6d1eca9291 100644 (file)
@@ -602,4 +602,10 @@ pub fn volatile_copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T,
     /// Returns the value of the discriminant for the variant in 'v',
     /// cast to a `u64`; if `T` has no discriminant, returns 0.
     pub fn discriminant_value<T>(v: &T) -> u64;
+
+    /// Rust's "try catch" construct which invokes the function pointer `f` with
+    /// the data pointer `data`, returning the exception payload if an exception
+    /// is thrown (aka the thread panics).
+    #[cfg(not(stage0))]
+    pub fn try(f: fn(*mut u8), data: *mut u8) -> *mut u8;
 }
index 4c8511eb1902c55f0e2fec2c09ad4934530f53ea..415326a8a616e950c6464b383bc2be0796eff173 100644 (file)
@@ -2555,7 +2555,7 @@ fn idx(&mut self, index: usize) -> Option<I::Item> {
 #[unstable(feature = "iter_unfold")]
 #[derive(Clone)]
 #[deprecated(since = "1.2.0",
-             reason = "has gained enough traction to retain its position \
+             reason = "has not gained enough traction to retain its position \
                        in the standard library")]
 #[allow(deprecated)]
 pub struct Unfold<St, F> {
@@ -2567,7 +2567,7 @@ pub struct Unfold<St, F> {
 
 #[unstable(feature = "iter_unfold")]
 #[deprecated(since = "1.2.0",
-             reason = "has gained enough traction to retain its position \
+             reason = "has not gained enough traction to retain its position \
                        in the standard library")]
 #[allow(deprecated)]
 impl<A, St, F> Unfold<St, F> where F: FnMut(&mut St) -> Option<A> {
@@ -3018,7 +3018,7 @@ fn idx(&mut self, _: usize) -> Option<A> { Some(self.element.clone()) }
 /// from a given seed value.
 #[unstable(feature = "iter_iterate")]
 #[deprecated(since = "1.2.0",
-             reason = "has gained enough traction to retain its position \
+             reason = "has not gained enough traction to retain its position \
                        in the standard library")]
 #[allow(deprecated)]
 pub type Iterate<T, F> = Unfold<IterateState<T, F>, fn(&mut IterateState<T, F>) -> Option<T>>;
@@ -3027,7 +3027,7 @@ fn idx(&mut self, _: usize) -> Option<A> { Some(self.element.clone()) }
 /// repeated applications of the given function `f`.
 #[unstable(feature = "iter_iterate")]
 #[deprecated(since = "1.2.0",
-             reason = "has gained enough traction to retain its position \
+             reason = "has not gained enough traction to retain its position \
                        in the standard library")]
 #[allow(deprecated)]
 pub fn iterate<T, F>(seed: T, f: F) -> Iterate<T, F> where
index dfcd08b69907aab6a1fae17e504c7245f6f7c9c7..c229df34ccf8918ab1f51c9c16ffd35d92e5df43 100644 (file)
@@ -6535,8 +6535,4 @@ pub mod winsock {
     }
 }
 
-#[doc(hidden)]
-#[cfg(stage0)]
-pub fn issue_14344_workaround() {} // FIXME #14344 force linkage to happen correctly
-
 #[test] fn work_on_windows() { } // FIXME #10872 needed for a happy windows
index 4b77c211df9839b603790b011556cb2913667f4d..4e21efcf9eb6b12dbc9d825ea95e85d4242577ac 100644 (file)
@@ -335,6 +335,24 @@ fn main() {
 remainder of a zero divisor) in a static or constant expression.
 "##,
 
+E0030: r##"
+When matching against a range, the compiler verifies that the range is
+non-empty.  Range patterns include both end-points, so this is equivalent to
+requiring the start of the range to be less than or equal to the end of the
+range.
+
+For example:
+
+```
+match 5u32 {
+    // This range is ok, albeit pointless.
+    1 ... 1 => ...
+    // This range is empty, and the compiler can tell.
+    1000 ... 5 => ...
+}
+```
+"##,
+
 E0079: r##"
 Enum variants which contain no data can be given a custom integer
 representation. This error indicates that the value provided is not an
index 59f91a50f74212e92c9422a070f2550429ca3610..baaf6b6a0401d545355bf109e1435418983485d4 100644 (file)
@@ -26,6 +26,7 @@
 
 use middle::cast::{CastKind};
 use middle::const_eval;
+use middle::const_eval::EvalHint::ExprTypeChecked;
 use middle::def;
 use middle::expr_use_visitor as euv;
 use middle::infer;
@@ -39,6 +40,7 @@
 use syntax::visit::{self, Visitor};
 
 use std::collections::hash_map::Entry;
+use std::cmp::Ordering;
 
 // Const qualification, from partial to completely promotable.
 bitflags! {
@@ -365,6 +367,19 @@ fn visit_pat(&mut self, p: &ast::Pat) {
             ast::PatRange(ref start, ref end) => {
                 self.global_expr(Mode::Const, &**start);
                 self.global_expr(Mode::Const, &**end);
+
+                match const_eval::compare_lit_exprs(self.tcx, start, end) {
+                    Some(Ordering::Less) |
+                    Some(Ordering::Equal) => {}
+                    Some(Ordering::Greater) => {
+                        span_err!(self.tcx.sess, start.span, E0030,
+                            "lower range bound must be less than or equal to upper");
+                    }
+                    None => {
+                        self.tcx.sess.span_bug(
+                            start.span, "literals of different types in range pat");
+                    }
+                }
             }
             _ => visit::walk_pat(self, p)
         }
@@ -457,7 +472,8 @@ fn visit_expr(&mut self, ex: &ast::Expr) {
                 match node_ty.sty {
                     ty::TyUint(_) | ty::TyInt(_) if div_or_rem => {
                         if !self.qualif.intersects(ConstQualif::NOT_CONST) {
-                            match const_eval::eval_const_expr_partial(self.tcx, ex, None) {
+                            match const_eval::eval_const_expr_partial(
+                                    self.tcx, ex, ExprTypeChecked) {
                                 Ok(_) => {}
                                 Err(msg) => {
                                     span_err!(self.tcx.sess, msg.span, E0020,
index fc2444ed5b45c4771921b35f099ddc37a9fae79b..d8c2341df2d9f487c54bfd5d775f747cae47290e 100644 (file)
@@ -15,6 +15,7 @@
 use middle::const_eval::{compare_const_vals, ConstVal};
 use middle::const_eval::{eval_const_expr, eval_const_expr_partial};
 use middle::const_eval::{const_expr_to_pat, lookup_const_by_id};
+use middle::const_eval::EvalHint::ExprTypeChecked;
 use middle::def::*;
 use middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, Init};
 use middle::expr_use_visitor::{JustWrite, LoanCause, MutateMode};
@@ -263,7 +264,7 @@ fn check_for_bindings_named_the_same_as_variants(cx: &MatchCheckCtxt, pat: &Pat)
 fn check_for_static_nan(cx: &MatchCheckCtxt, pat: &Pat) {
     ast_util::walk_pat(pat, |p| {
         if let ast::PatLit(ref expr) = p.node {
-            match eval_const_expr_partial(cx.tcx, &**expr, None) {
+            match eval_const_expr_partial(cx.tcx, &**expr, ExprTypeChecked) {
                 Ok(ConstVal::Float(f)) if f.is_nan() => {
                     span_warn!(cx.tcx.sess, p.span, E0003,
                                "unmatchable NaN in pattern, \
index 0f16c06a9dbbca7b3ff2cf97ca61c1cef0a76bcc..9e2bcbaec8a6ccd83d51c08fedb15c5cbbea99b2 100644 (file)
@@ -11,8 +11,8 @@
 #![allow(non_camel_case_types)]
 
 use self::ConstVal::*;
-
 use self::ErrKind::*;
+use self::EvalHint::*;
 
 use ast_map;
 use ast_map::blocks::FnLikeNode;
@@ -271,6 +271,22 @@ pub enum ConstVal {
     Tuple(ast::NodeId),
 }
 
+impl ConstVal {
+    pub fn description(&self) -> &'static str {
+        match *self {
+            Float(_) => "float",
+            Int(i) if i < 0 => "negative integer",
+            Int(_) => "positive integer",
+            Uint(_) => "unsigned integer",
+            Str(_) => "string literal",
+            Binary(_) => "binary array",
+            Bool(_) => "boolean",
+            Struct(_) => "struct",
+            Tuple(_) => "tuple",
+        }
+    }
+}
+
 pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr, span: Span) -> P<ast::Pat> {
     let pat = match expr.node {
         ast::ExprTup(ref exprs) =>
@@ -329,7 +345,7 @@ pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr, span: Span) -> P<ast::Pat>
 }
 
 pub fn eval_const_expr(tcx: &ty::ctxt, e: &Expr) -> ConstVal {
-    match eval_const_expr_partial(tcx, e, None) {
+    match eval_const_expr_partial(tcx, e, ExprTypeChecked) {
         Ok(r) => r,
         Err(s) => tcx.sess.span_fatal(s.span, &s.description())
     }
@@ -350,16 +366,8 @@ pub enum ErrKind {
     InvalidOpForFloats(ast::BinOp_),
     InvalidOpForIntUint(ast::BinOp_),
     InvalidOpForUintInt(ast::BinOp_),
-    NegateOnString,
-    NegateOnBoolean,
-    NegateOnBinary,
-    NegateOnStruct,
-    NegateOnTuple,
-    NotOnFloat,
-    NotOnString,
-    NotOnBinary,
-    NotOnStruct,
-    NotOnTuple,
+    NegateOn(ConstVal),
+    NotOn(ConstVal),
 
     NegateWithOverflow(i64),
     AddiWithOverflow(i64, i64),
@@ -395,16 +403,8 @@ pub fn description(&self) -> Cow<str> {
             InvalidOpForFloats(_) => "can't do this op on floats".into_cow(),
             InvalidOpForIntUint(..) => "can't do this op on an isize and usize".into_cow(),
             InvalidOpForUintInt(..) => "can't do this op on a usize and isize".into_cow(),
-            NegateOnString => "negate on string".into_cow(),
-            NegateOnBoolean => "negate on boolean".into_cow(),
-            NegateOnBinary => "negate on binary literal".into_cow(),
-            NegateOnStruct => "negate on struct".into_cow(),
-            NegateOnTuple => "negate on tuple".into_cow(),
-            NotOnFloat => "not on float or string".into_cow(),
-            NotOnString => "not on float or string".into_cow(),
-            NotOnBinary => "not on binary literal".into_cow(),
-            NotOnStruct => "not on struct".into_cow(),
-            NotOnTuple => "not on tuple".into_cow(),
+            NegateOn(ref const_val) => format!("negate on {}", const_val.description()).into_cow(),
+            NotOn(ref const_val) => format!("not on {}", const_val.description()).into_cow(),
 
             NegateWithOverflow(..) => "attempted to negate with overflow".into_cow(),
             AddiWithOverflow(..) => "attempted to add with overflow".into_cow(),
@@ -434,6 +434,28 @@ pub fn description(&self) -> Cow<str> {
 pub type EvalResult = Result<ConstVal, ConstEvalErr>;
 pub type CastResult = Result<ConstVal, ErrKind>;
 
+// FIXME: Long-term, this enum should go away: trying to evaluate
+// an expression which hasn't been type-checked is a recipe for
+// disaster.  That said, it's not clear how to fix ast_ty_to_ty
+// to avoid the ordering issue.
+
+/// Hint to determine how to evaluate constant expressions which
+/// might not be type-checked.
+#[derive(Copy, Clone, Debug)]
+pub enum EvalHint<'tcx> {
+    /// We have a type-checked expression.
+    ExprTypeChecked,
+    /// We have an expression which hasn't been type-checked, but we have
+    /// an idea of what the type will be because of the context. For example,
+    /// the length of an array is always `usize`. (This is referred to as
+    /// a hint because it isn't guaranteed to be consistent with what
+    /// type-checking would compute.)
+    UncheckedExprHint(Ty<'tcx>),
+    /// We have an expression which has not yet been type-checked, and
+    /// and we have no clue what the type will be.
+    UncheckedExprNoHint,
+}
+
 #[derive(Copy, Clone, PartialEq, Debug)]
 pub enum IntTy { I8, I16, I32, I64 }
 #[derive(Copy, Clone, PartialEq, Debug)]
@@ -704,26 +726,34 @@ pub fn const_uint_checked_rem<'a>(
            uint_shift_body overflowing_shr Uint ShiftRightWithOverflow
 }}
 
-// After type checking, `eval_const_expr_partial` should always suffice. The
-// reason for providing `eval_const_expr_with_substs` is to allow
-// trait-associated consts to be evaluated *during* type checking, when the
-// substs for each expression have not been written into `tcx` yet.
+/// Evaluate a constant expression in a context where the expression isn't
+/// guaranteed to be evaluatable. `ty_hint` is usually ExprTypeChecked,
+/// but a few places need to evaluate constants during type-checking, like
+/// computing the length of an array. (See also the FIXME above EvalHint.)
 pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
                                      e: &Expr,
-                                     ty_hint: Option<Ty<'tcx>>) -> EvalResult {
-    eval_const_expr_with_substs(tcx, e, ty_hint, |id| {
-        tcx.node_id_item_substs(id).substs
-    })
-}
-
-pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>,
-                                            e: &Expr,
-                                            ty_hint: Option<Ty<'tcx>>,
-                                            get_substs: S) -> EvalResult
-        where S: Fn(ast::NodeId) -> subst::Substs<'tcx> {
+                                     ty_hint: EvalHint<'tcx>) -> EvalResult {
     fn fromb(b: bool) -> ConstVal { Int(b as i64) }
 
-    let ety = ty_hint.or_else(|| tcx.expr_ty_opt(e));
+    // Try to compute the type of the expression based on the EvalHint.
+    // (See also the definition of EvalHint, and the FIXME above EvalHint.)
+    let ety = match ty_hint {
+        ExprTypeChecked => {
+            // After type-checking, expr_ty is guaranteed to succeed.
+            Some(tcx.expr_ty(e))
+        }
+        UncheckedExprHint(ty) => {
+            // Use the type hint; it's not guaranteed to be right, but it's
+            // usually good enough.
+            Some(ty)
+        }
+        UncheckedExprNoHint => {
+            // This expression might not be type-checked, and we have no hint.
+            // Try to query the context for a type anyway; we might get lucky
+            // (for example, if the expression was imported from another crate).
+            tcx.expr_ty_opt(e)
+        }
+    };
 
     // If type of expression itself is int or uint, normalize in these
     // bindings so that isize/usize is mapped to a type with an
@@ -739,37 +769,35 @@ fn fromb(b: bool) -> ConstVal { Int(b as i64) }
 
     let result = match e.node {
       ast::ExprUnary(ast::UnNeg, ref inner) => {
-        match try!(eval_const_expr_partial(tcx, &**inner, ety)) {
+        match try!(eval_const_expr_partial(tcx, &**inner, ty_hint)) {
           Float(f) => Float(-f),
           Int(n) =>  try!(const_int_checked_neg(n, e, expr_int_type)),
           Uint(i) => {
               try!(const_uint_checked_neg(i, e, expr_uint_type))
           }
-          Str(_) => signal!(e, NegateOnString),
-          Bool(_) => signal!(e, NegateOnBoolean),
-          Binary(_) => signal!(e, NegateOnBinary),
-          Tuple(_) => signal!(e, NegateOnTuple),
-          Struct(..) => signal!(e, NegateOnStruct),
+          const_val => signal!(e, NegateOn(const_val)),
         }
       }
       ast::ExprUnary(ast::UnNot, ref inner) => {
-        match try!(eval_const_expr_partial(tcx, &**inner, ety)) {
+        match try!(eval_const_expr_partial(tcx, &**inner, ty_hint)) {
           Int(i) => Int(!i),
           Uint(i) => const_uint_not(i, expr_uint_type),
           Bool(b) => Bool(!b),
-          Str(_) => signal!(e, NotOnString),
-          Float(_) => signal!(e, NotOnFloat),
-          Binary(_) => signal!(e, NotOnBinary),
-          Tuple(_) => signal!(e, NotOnTuple),
-          Struct(..) => signal!(e, NotOnStruct),
+          const_val => signal!(e, NotOn(const_val)),
         }
       }
       ast::ExprBinary(op, ref a, ref b) => {
         let b_ty = match op.node {
-            ast::BiShl | ast::BiShr => Some(tcx.types.usize),
-            _ => ety
+            ast::BiShl | ast::BiShr => {
+                if let ExprTypeChecked = ty_hint {
+                    ExprTypeChecked
+                } else {
+                    UncheckedExprHint(tcx.types.usize)
+                }
+            }
+            _ => ty_hint
         };
-        match (try!(eval_const_expr_partial(tcx, &**a, ety)),
+        match (try!(eval_const_expr_partial(tcx, &**a, ty_hint)),
                try!(eval_const_expr_partial(tcx, &**b, b_ty))) {
           (Float(a), Float(b)) => {
             match op.node {
@@ -859,22 +887,25 @@ fn fromb(b: bool) -> ConstVal { Int(b as i64) }
         }
       }
       ast::ExprCast(ref base, ref target_ty) => {
-        // This tends to get called w/o the type actually having been
-        // populated in the ctxt, which was causing things to blow up
-        // (#5900). Fall back to doing a limited lookup to get past it.
         let ety = ety.or_else(|| ast_ty_to_prim_ty(tcx, &**target_ty))
                 .unwrap_or_else(|| {
                     tcx.sess.span_fatal(target_ty.span,
                                         "target type not found for const cast")
                 });
 
-        // Prefer known type to noop, but always have a type hint.
-        //
-        // FIXME (#23833): the type-hint can cause problems,
-        // e.g. `(i8::MAX + 1_i8) as u32` feeds in `u32` as result
-        // type to the sum, and thus no overflow is signaled.
-        let base_hint = tcx.expr_ty_opt(&**base).unwrap_or(ety);
-        let val = try!(eval_const_expr_partial(tcx, &**base, Some(base_hint)));
+        let base_hint = if let ExprTypeChecked = ty_hint {
+            ExprTypeChecked
+        } else {
+            // FIXME (#23833): the type-hint can cause problems,
+            // e.g. `(i8::MAX + 1_i8) as u32` feeds in `u32` as result
+            // type to the sum, and thus no overflow is signaled.
+            match tcx.expr_ty_opt(&base) {
+                Some(t) => UncheckedExprHint(t),
+                None => ty_hint
+            }
+        };
+
+        let val = try!(eval_const_expr_partial(tcx, &**base, base_hint));
         match cast_const(tcx, val, ety) {
             Ok(val) => val,
             Err(kind) => return Err(ConstEvalErr { span: e.span, kind: kind }),
@@ -904,12 +935,16 @@ fn fromb(b: bool) -> ConstVal { Int(b as i64) }
                           def::FromTrait(trait_id) => match tcx.map.find(def_id.node) {
                               Some(ast_map::NodeTraitItem(ti)) => match ti.node {
                                   ast::ConstTraitItem(ref ty, _) => {
-                                      let substs = get_substs(e.id);
-                                      (resolve_trait_associated_const(tcx,
-                                                                      ti,
-                                                                      trait_id,
-                                                                      substs),
-                                       Some(&**ty))
+                                      if let ExprTypeChecked = ty_hint {
+                                          let substs = tcx.node_id_item_substs(e.id).substs;
+                                          (resolve_trait_associated_const(tcx,
+                                                                          ti,
+                                                                          trait_id,
+                                                                          substs),
+                                           Some(&**ty))
+                                       } else {
+                                           (None, None)
+                                       }
                                   }
                                   _ => (None, None)
                               },
@@ -938,27 +973,42 @@ fn fromb(b: bool) -> ConstVal { Int(b as i64) }
               Some(actual_e) => actual_e,
               None => signal!(e, NonConstPath)
           };
-          let ety = ety.or_else(|| const_ty.and_then(|ty| ast_ty_to_prim_ty(tcx, ty)));
-          try!(eval_const_expr_partial(tcx, const_expr, ety))
+          let item_hint = if let UncheckedExprNoHint = ty_hint {
+              match const_ty {
+                  Some(ty) => match ast_ty_to_prim_ty(tcx, ty) {
+                      Some(ty) => UncheckedExprHint(ty),
+                      None => UncheckedExprNoHint
+                  },
+                  None => UncheckedExprNoHint
+              }
+          } else {
+              ty_hint
+          };
+          try!(eval_const_expr_partial(tcx, const_expr, item_hint))
       }
       ast::ExprLit(ref lit) => {
           lit_to_const(&**lit, ety)
       }
-      ast::ExprParen(ref e) => try!(eval_const_expr_partial(tcx, &**e, ety)),
+      ast::ExprParen(ref e) => try!(eval_const_expr_partial(tcx, &**e, ty_hint)),
       ast::ExprBlock(ref block) => {
         match block.expr {
-            Some(ref expr) => try!(eval_const_expr_partial(tcx, &**expr, ety)),
+            Some(ref expr) => try!(eval_const_expr_partial(tcx, &**expr, ty_hint)),
             None => Int(0)
         }
       }
       ast::ExprTup(_) => Tuple(e.id),
       ast::ExprStruct(..) => Struct(e.id),
       ast::ExprTupField(ref base, index) => {
-        if let Ok(c) = eval_const_expr_partial(tcx, base, None) {
+        let base_hint = if let ExprTypeChecked = ty_hint {
+            ExprTypeChecked
+        } else {
+            UncheckedExprNoHint
+        };
+        if let Ok(c) = eval_const_expr_partial(tcx, base, base_hint) {
             if let Tuple(tup_id) = c {
                 if let ast::ExprTup(ref fields) = tcx.map.expect_expr(tup_id).node {
                     if index.node < fields.len() {
-                        return eval_const_expr_partial(tcx, &fields[index.node], None)
+                        return eval_const_expr_partial(tcx, &fields[index.node], base_hint)
                     } else {
                         signal!(e, TupleIndexOutOfBounds);
                     }
@@ -974,13 +1024,18 @@ fn fromb(b: bool) -> ConstVal { Int(b as i64) }
       }
       ast::ExprField(ref base, field_name) => {
         // Get the base expression if it is a struct and it is constant
-        if let Ok(c) = eval_const_expr_partial(tcx, base, None) {
+        let base_hint = if let ExprTypeChecked = ty_hint {
+            ExprTypeChecked
+        } else {
+            UncheckedExprNoHint
+        };
+        if let Ok(c) = eval_const_expr_partial(tcx, base, base_hint) {
             if let Struct(struct_id) = c {
                 if let ast::ExprStruct(_, ref fields, _) = tcx.map.expect_expr(struct_id).node {
                     // Check that the given field exists and evaluate it
                     if let Some(f) = fields.iter().find(|f| f.ident.node.as_str()
                                                          == field_name.node.as_str()) {
-                        return eval_const_expr_partial(tcx, &*f.expr, None)
+                        return eval_const_expr_partial(tcx, &*f.expr, base_hint)
                     } else {
                         signal!(e, MissingStructField);
                     }
@@ -1156,21 +1211,17 @@ pub fn compare_const_vals(a: &ConstVal, b: &ConstVal) -> Option<Ordering> {
     })
 }
 
-pub fn compare_lit_exprs<'tcx, S>(tcx: &ty::ctxt<'tcx>,
-                                  a: &Expr,
-                                  b: &Expr,
-                                  ty_hint: Option<Ty<'tcx>>,
-                                  get_substs: S) -> Option<Ordering>
-        where S: Fn(ast::NodeId) -> subst::Substs<'tcx> {
-    let a = match eval_const_expr_with_substs(tcx, a, ty_hint,
-                                              |id| {get_substs(id)}) {
+pub fn compare_lit_exprs<'tcx>(tcx: &ty::ctxt<'tcx>,
+                               a: &Expr,
+                               b: &Expr) -> Option<Ordering> {
+    let a = match eval_const_expr_partial(tcx, a, ExprTypeChecked) {
         Ok(a) => a,
         Err(e) => {
             tcx.sess.span_err(a.span, &e.description());
             return None;
         }
     };
-    let b = match eval_const_expr_with_substs(tcx, b, ty_hint, get_substs) {
+    let b = match eval_const_expr_partial(tcx, b, ExprTypeChecked) {
         Ok(b) => b,
         Err(e) => {
             tcx.sess.span_err(b.span, &e.description());
index c5f6f0126de378eec7d6fcba1fb9ba2f8a529bfb..a10e0b8dfc29e4b8ddd360f372d9be1cb279dbf3 100644 (file)
@@ -165,7 +165,7 @@ fn check_transmute(&self, span: Span, from: Ty<'tcx>, to: Ty<'tcx>, id: ast::Nod
         if from_tc.interior_param() || to_tc.interior_param() {
             span_err!(self.tcx.sess, span, E0139,
                       "cannot transmute to or from a type that contains \
-                       type parameters in its interior");
+                       unsubstituted type parameters");
             return;
         }
 
index cf528e0c8a91423d7363da2f510290009ab75544..f7cd94f30af12e2a30643fbc25df39201109893b 100644 (file)
@@ -326,6 +326,8 @@ pub fn collect_language_items(krate: &ast::Crate,
     StartFnLangItem,                 "start",                   start_fn;
 
     EhPersonalityLangItem,           "eh_personality",          eh_personality;
+    EhPersonalityCatchLangItem,      "eh_personality_catch",    eh_personality_catch;
+    MSVCTryFilterLangItem,           "msvc_try_filter",         msvc_try_filter;
 
     ExchangeHeapLangItem,            "exchange_heap",           exchange_heap;
     OwnedBoxLangItem,                "owned_box",               owned_box;
index 9e5ad7b42f5c5b751328313a92dbc87bec3ef8e3..510f1a2a2c9d8dd0b6cecb836551141b677160b0 100644 (file)
@@ -372,6 +372,12 @@ struct GatherLabels<'a> {
 
     impl<'v, 'a> Visitor<'v> for GatherLabels<'a> {
         fn visit_expr(&mut self, ex: &'v ast::Expr) {
+            // do not recurse into closures defined in the block
+            // since they are treated as separate fns from the POV of
+            // labels_in_fn
+            if let ast::ExprClosure(..) = ex.node {
+                return
+            }
             if let Some(label) = expression_label(ex) {
                 for &(prior, prior_span) in &self.labels_in_fn[..] {
                     // FIXME (#24278): non-hygienic comparison
index ef337b416305119d785da27d57e8af4383b72264..17a76f6eed9c5af59e415b23d4791d3d81e7a973 100644 (file)
@@ -45,6 +45,7 @@
 use middle::cast;
 use middle::check_const;
 use middle::const_eval::{self, ConstVal};
+use middle::const_eval::EvalHint::UncheckedExprHint;
 use middle::def::{self, DefMap, ExportMap};
 use middle::dependency_format;
 use middle::fast_reject;
@@ -5758,20 +5759,8 @@ fn compute_enum_variants(&self,
                 Some(ref e) => {
                     debug!("disr expr, checking {}", pprust::expr_to_string(&**e));
 
-                    // check_expr (from check_const pass) doesn't guarantee
-                    // that the expression is in a form that eval_const_expr can
-                    // handle, so we may still get an internal compiler error
-                    //
-                    // pnkfelix: The above comment was transcribed from
-                    // the version of this code taken from rustc_typeck.
-                    // Presumably the implication is that we need to deal
-                    // with such ICE's as they arise.
-                    //
-                    // Since this can be called from `ty::enum_variants`
-                    // anyway, best thing is to make `eval_const_expr`
-                    // more robust (on case-by-case basis).
-
-                    match const_eval::eval_const_expr_partial(self, &**e, Some(repr_type_ty)) {
+                    let hint = UncheckedExprHint(repr_type_ty);
+                    match const_eval::eval_const_expr_partial(self, &**e, hint) {
                         Ok(ConstVal::Int(val)) => current_disr_val = val as Disr,
                         Ok(ConstVal::Uint(val)) => current_disr_val = val as Disr,
                         Ok(_) => {
@@ -6086,18 +6075,13 @@ pub fn closure_upvars<'a>(typer: &infer::InferCtxt<'a, 'tcx>,
 
     // Returns the repeat count for a repeating vector expression.
     pub fn eval_repeat_count(&self, count_expr: &ast::Expr) -> usize {
-        match const_eval::eval_const_expr_partial(self, count_expr, Some(self.types.usize)) {
+        let hint = UncheckedExprHint(self.types.usize);
+        match const_eval::eval_const_expr_partial(self, count_expr, hint) {
             Ok(val) => {
                 let found = match val {
                     ConstVal::Uint(count) => return count as usize,
                     ConstVal::Int(count) if count >= 0 => return count as usize,
-                    ConstVal::Int(_) => "negative integer",
-                    ConstVal::Float(_) => "float",
-                    ConstVal::Str(_) => "string",
-                    ConstVal::Bool(_) => "boolean",
-                    ConstVal::Binary(_) => "binary array",
-                    ConstVal::Struct(..) => "struct",
-                    ConstVal::Tuple(_) => "tuple"
+                    const_val => const_val.description(),
                 };
                 span_err!(self.sess, count_expr.span, E0306,
                     "expected positive integer for repeat count, found {}",
index 60a9ffc7d2e13b80a6e1824a55efdb6e02315504..72fda9a7ae06ac236f82eda442dc6f2c4bf42f95 100644 (file)
@@ -119,7 +119,7 @@ fn visit_foreign_item(&mut self, i: &ast::ForeignItem) {
 ) }
 
 weak_lang_items! {
-    panic_fmt,          PanicFmtLangItem,            rust_begin_unwind;
+    panic_fmt,          PanicFmtLangItem,           rust_begin_unwind;
     stack_exhausted,    StackExhaustedLangItem,     rust_stack_exhausted;
     eh_personality,     EhPersonalityLangItem,      rust_eh_personality;
 }
index 1f4014bc692a1666eb45df5d611f3084161409f0..ae95466e6e675e4fd60682262ed02f8317c0ba5e 100644 (file)
@@ -39,6 +39,7 @@
 use middle::traits;
 use middle::{def, pat_util, stability};
 use middle::const_eval::{eval_const_expr_partial, ConstVal};
+use middle::const_eval::EvalHint::ExprTypeChecked;
 use middle::cfg;
 use rustc::ast_map;
 use util::nodemap::{FnvHashMap, NodeSet};
@@ -178,7 +179,7 @@ fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
                             if let ast::LitInt(shift, _) = lit.node { shift >= bits }
                             else { false }
                         } else {
-                            match eval_const_expr_partial(cx.tcx, &**r, Some(cx.tcx.types.usize)) {
+                            match eval_const_expr_partial(cx.tcx, &**r, ExprTypeChecked) {
                                 Ok(ConstVal::Int(shift)) => { shift as u64 >= bits },
                                 Ok(ConstVal::Uint(shift)) => { shift >= bits },
                                 _ => { false }
index 7734704b021a851a66b5396343acfdbd0671b1c9..83f8619c5eeabd1e2976b976eae81da9891b3adf 100644 (file)
@@ -134,7 +134,7 @@ pub enum DLLStorageClassTypes {
 }
 
 bitflags! {
-    flags Attribute : u32 {
+    flags Attribute : u64 {
         const ZExt            = 1 << 0,
         const SExt            = 1 << 1,
         const NoReturn        = 1 << 2,
@@ -161,6 +161,7 @@ pub enum DLLStorageClassTypes {
         const ReturnsTwice    = 1 << 29,
         const UWTable         = 1 << 30,
         const NonLazyBind     = 1 << 31,
+        const OptimizeNone    = 1 << 42,
     }
 }
 
@@ -2193,7 +2194,8 @@ pub fn ConstFCmp(pred: RealPredicate, v1: ValueRef, v2: ValueRef) -> ValueRef {
 
 pub fn SetFunctionAttribute(fn_: ValueRef, attr: Attribute) {
     unsafe {
-        LLVMAddFunctionAttribute(fn_, FunctionIndex as c_uint, attr.bits() as uint64_t)
+        LLVMAddFunctionAttribute(fn_, FunctionIndex as c_uint,
+                                 attr.bits() as uint64_t)
     }
 }
 
index a0d06e5e1244a2559e3bd940f418b301f9769e58..5a941c757fc6d939543c65511daba3efff7559f5 100644 (file)
@@ -106,8 +106,7 @@ pub trait MyTrait {
 use foo::MyTrait::do_something;
 ```
 
-In general, it's not legal to directly import methods belonging to a
-trait or concrete type.
+It's illegal to directly import methods belonging to a trait or concrete type.
 "##,
 
 E0255: r##"
@@ -272,7 +271,160 @@ pub mod foo {
 on this topic:
 
 http://doc.rust-lang.org/reference.html#use-declarations
-"##
+"##,
+
+E0403: r##"
+Some type parameters have the same name. Example of erroneous code:
+
+```
+fn foo<T, T>(s: T, u: T) {} // error: the name `T` is already used for a type
+                            //        parameter in this type parameter list
+```
+
+Please verify that none of the type parameterss are misspelled, and rename any
+clashing parameters. Example:
+
+```
+fn foo<T, Y>(s: T, u: Y) {} // ok!
+```
+"##,
+
+E0404: r##"
+You tried to implement something which was not a trait on an object. Example of
+erroneous code:
+
+```
+struct Foo;
+struct Bar;
+
+impl Foo for Bar {} // error: `Foo` is not a trait
+```
+
+Please verify that you didn't misspell the trait's name or otherwise use the
+wrong identifier. Example:
+
+```
+trait Foo {
+    // some functions
+}
+struct Bar;
+
+impl Foo for Bar { // ok!
+    // functions implementation
+}
+```
+"##,
+
+E0405: r##"
+An unknown trait was implemented. Example of erroneous code:
+
+```
+struct Foo;
+
+impl SomeTrait for Foo {} // error: use of undeclared trait name `SomeTrait`
+```
+
+Please verify that the name of the trait wasn't misspelled and ensure that it
+was imported. Example:
+
+```
+// solution 1:
+use some_file::SomeTrait;
+
+// solution 2:
+trait SomeTrait {
+    // some functions
+}
+
+struct Foo;
+
+impl SomeTrait for Foo { // ok!
+    // implements functions
+}
+```
+"##,
+
+E0407: r##"
+A definition of a method not in the implemented trait was given in a trait
+implementation. Example of erroneous code:
+
+```
+trait Foo {
+    fn a();
+}
+
+struct Bar;
+
+impl Foo for Bar {
+    fn a() {}
+    fn b() {} // error: method `b` is not a member of trait `Foo`
+}
+```
+
+Please verify you didn't misspell the method name and you used the correct
+trait. First example:
+
+```
+trait Foo {
+    fn a();
+    fn b();
+}
+
+struct Bar;
+
+impl Foo for Bar {
+    fn a() {}
+    fn b() {} // ok!
+}
+```
+
+Second example:
+
+```
+trait Foo {
+    fn a();
+}
+
+struct Bar;
+
+impl Foo for Bar {
+    fn a() {}
+}
+
+impl Bar {
+    fn b() {}
+}
+```
+"##,
+
+E0428: r##"
+A type or module has been defined more than once. Example of erroneous
+code:
+
+```
+struct Bar;
+struct Bar; // error: duplicate definition of value `Bar`
+```
+
+Please verify you didn't misspell the type/module's name or remove/rename the
+duplicated one. Example:
+
+```
+struct Bar;
+struct Bar2; // ok!
+```
+"##,
+
+E0433: r##"
+Invalid import. Example of erroneous code:
+
+```
+use something_which_doesnt_exist;
+// error: unresolved import `something_which_doesnt_exist`
+```
+
+Please verify you didn't misspell the import's name.
+"##,
 
 }
 
@@ -284,11 +436,7 @@ pub mod foo {
     E0258,
     E0401, // can't use type parameters from outer function
     E0402, // cannot use an outer type parameter in this context
-    E0403, // the name `{}` is already used
-    E0404, // is not a trait
-    E0405, // use of undeclared trait name
     E0406, // undeclared associated type
-    E0407, // method is not a member of trait
     E0408, // variable from pattern #1 is not bound in pattern #
     E0409, // variable is bound with different mode in pattern # than in
            // pattern #1
@@ -313,13 +461,11 @@ pub mod foo {
     E0425, // unresolved name
     E0426, // use of undeclared label
     E0427, // cannot use `ref` binding mode with ...
-    E0428, // duplicate definition of ...
     E0429, // `self` imports are only allowed within a { } list
     E0430, // `self` import can only appear once in the list
     E0431, // `self` import can only appear in an import list with a non-empty
            // prefix
     E0432, // unresolved import
-    E0433, // failed to resolve
     E0434, // can't capture dynamic environment in a fn item
     E0435, // attempt to use a non-constant value in a constant
     E0437, // type is not a member of trait
index 680999717eae5a2f038d4116d200e34be039332e..f291413cedc7ede8ab25fdb8277f70409164ed7a 100644 (file)
@@ -478,7 +478,7 @@ fn process_struct(&mut self,
 
         let ctor_id = match def.ctor_id {
             Some(node_id) => node_id,
-            None => -1,
+            None => ast::DUMMY_NODE_ID,
         };
         let val = self.span.snippet(item.span);
         let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Struct);
@@ -536,7 +536,7 @@ fn process_enum(&mut self,
                 ast::StructVariantKind(ref struct_def) => {
                     let ctor_id = match struct_def.ctor_id {
                         Some(node_id) => node_id,
-                        None => -1,
+                        None => ast::DUMMY_NODE_ID,
                     };
                     self.fmt.struct_variant_str(variant.span,
                                                 self.span.span_for_first_ident(variant.span),
index 9a9b9c617a85392f4a2cc573f281a64be064a636..925da81d77e6bdf4d6ac00c4f7d36f7c85f8018c 100644 (file)
 
 impl<'a> ConstantExpr<'a> {
     fn eq(self, other: ConstantExpr<'a>, tcx: &ty::ctxt) -> bool {
-        match const_eval::compare_lit_exprs(tcx, self.0, other.0, None,
-                                            |id| {tcx.node_id_item_substs(id).substs}) {
+        match const_eval::compare_lit_exprs(tcx, self.0, other.0) {
             Some(result) => result == Ordering::Equal,
             None => panic!("compare_list_exprs: type mismatch"),
         }
index 3e4452a23b9f7c893460421590bb25c506cbfdea..5a3fcc8d27f3cb8bf422c6d6e8dabc579eb89d66 100644 (file)
@@ -1042,6 +1042,10 @@ pub fn LandingPad(cx: Block, ty: Type, pers_fn: ValueRef,
     B(cx).landing_pad(ty, pers_fn, num_clauses, cx.fcx.llfn)
 }
 
+pub fn AddClause(cx: Block, landing_pad: ValueRef, clause: ValueRef) {
+    B(cx).add_clause(landing_pad, clause)
+}
+
 pub fn SetCleanup(cx: Block, landing_pad: ValueRef) {
     B(cx).set_cleanup(landing_pad)
 }
index e39fc18dc7bf1140c70c5738f011b4cb37c8be69..107ae378ac4463925e70fd978af74f270b176dcf 100644 (file)
@@ -937,6 +937,12 @@ pub fn landing_pad(&self, ty: Type, pers_fn: ValueRef,
         }
     }
 
+    pub fn add_clause(&self, landing_pad: ValueRef, clause: ValueRef) {
+        unsafe {
+            llvm::LLVMAddClause(landing_pad, clause);
+        }
+    }
+
     pub fn set_cleanup(&self, landing_pad: ValueRef) {
         self.count_insn("setcleanup");
         unsafe {
index debc8dd59c04c0187547627a39f288646b93e124..7900000d3a9df1d33478acb7ad2b119721182047 100644 (file)
@@ -620,16 +620,17 @@ pub fn trans_lang_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     }, ArgVals(args), dest)
 }
 
-/// This behemoth of a function translates function calls. Unfortunately, in order to generate more
-/// efficient LLVM output at -O0, it has quite a complex signature (refactoring this into two
-/// functions seems like a good idea).
+/// This behemoth of a function translates function calls. Unfortunately, in
+/// order to generate more efficient LLVM output at -O0, it has quite a complex
+/// signature (refactoring this into two functions seems like a good idea).
 ///
-/// In particular, for lang items, it is invoked with a dest of None, and in that case the return
-/// value contains the result of the fn. The lang item must not return a structural type or else
-/// all heck breaks loose.
+/// In particular, for lang items, it is invoked with a dest of None, and in
+/// that case the return value contains the result of the fn. The lang item must
+/// not return a structural type or else all heck breaks loose.
 ///
-/// For non-lang items, `dest` is always Some, and hence the result is written into memory
-/// somewhere. Nonetheless we return the actual return value of the function.
+/// For non-lang items, `dest` is always Some, and hence the result is written
+/// into memory somewhere. Nonetheless we return the actual return value of the
+/// function.
 pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
                                            debug_loc: DebugLoc,
                                            get_callee: F,
index 1891320313a851f562a8ffb89e21083cdebfa786..37722d5a549fe7f7a693122ac241b8da0f342f96 100644 (file)
 use llvm::{BasicBlockRef, ValueRef};
 use trans::base;
 use trans::build;
-use trans::callee;
 use trans::common;
-use trans::common::{Block, FunctionContext, ExprId, NodeIdAndSpan};
+use trans::common::{Block, FunctionContext, NodeIdAndSpan};
 use trans::debuginfo::{DebugLoc, ToDebugLoc};
-use trans::declare;
 use trans::glue;
 use middle::region;
 use trans::type_::Type;
@@ -833,53 +831,7 @@ fn get_or_create_landing_pad(&'blk self) -> BasicBlockRef {
                                     &[Type::i8p(self.ccx), Type::i32(self.ccx)],
                                     false);
 
-        // The exception handling personality function.
-        //
-        // If our compilation unit has the `eh_personality` lang item somewhere
-        // within it, then we just need to translate that. Otherwise, we're
-        // building an rlib which will depend on some upstream implementation of
-        // this function, so we just codegen a generic reference to it. We don't
-        // specify any of the types for the function, we just make it a symbol
-        // that LLVM can later use.
-        //
-        // Note that MSVC is a little special here in that we don't use the
-        // `eh_personality` lang item at all. Currently LLVM has support for
-        // both Dwarf and SEH unwind mechanisms for MSVC targets and uses the
-        // *name of the personality function* to decide what kind of unwind side
-        // tables/landing pads to emit. It looks like Dwarf is used by default,
-        // injecting a dependency on the `_Unwind_Resume` symbol for resuming
-        // an "exception", but for MSVC we want to force SEH. This means that we
-        // can't actually have the personality function be our standard
-        // `rust_eh_personality` function, but rather we wired it up to the
-        // CRT's custom personality function, which forces LLVM to consider
-        // landing pads as "landing pads for SEH".
-        let target = &self.ccx.sess().target.target;
-        let llpersonality = match pad_bcx.tcx().lang_items.eh_personality() {
-            Some(def_id) if !target.options.is_like_msvc => {
-                callee::trans_fn_ref(pad_bcx.ccx(), def_id, ExprId(0),
-                                     pad_bcx.fcx.param_substs).val
-            }
-            _ => {
-                let mut personality = self.ccx.eh_personality().borrow_mut();
-                match *personality {
-                    Some(llpersonality) => llpersonality,
-                    None => {
-                        let name = if !target.options.is_like_msvc {
-                            "rust_eh_personality"
-                        } else if target.arch == "x86" {
-                            "_except_handler3"
-                        } else {
-                            "__C_specific_handler"
-                        };
-                        let fty = Type::variadic_func(&[], &Type::i32(self.ccx));
-                        let f = declare::declare_cfn(self.ccx, name, fty,
-                                                     self.ccx.tcx().types.i32);
-                        *personality = Some(f);
-                        f
-                    }
-                }
-            }
-        };
+        let llpersonality = pad_bcx.fcx.eh_personality();
 
         // The only landing pad clause will be 'cleanup'
         let llretval = build::LandingPad(pad_bcx, llretty, llpersonality, 1);
index d813e9dbf40fab9ca75b4c9d21f04697c9817557..f00029ec2ff932a8d762423017949e92f963ee36 100644 (file)
@@ -163,11 +163,10 @@ pub fn get_or_create_declaration_if_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tc
         mangle_internal_name_by_path_and_seq(path, "closure")
     });
 
-    // Currently there’s only a single user of get_or_create_declaration_if_closure and it
-    // unconditionally defines the function, therefore we use define_* here.
-    let llfn = declare::define_internal_rust_fn(ccx, &symbol[..], function_type).unwrap_or_else(||{
-        ccx.sess().bug(&format!("symbol `{}` already defined", symbol));
-    });
+    // Currently there’s only a single user of
+    // get_or_create_declaration_if_closure and it unconditionally defines the
+    // function, therefore we use define_* here.
+    let llfn = declare::define_internal_rust_fn(ccx, &symbol[..], function_type);
 
     // set an inline hint for all closures
     attributes::inline(llfn, attributes::InlineAttr::Hint);
@@ -388,11 +387,8 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
 
     // Create the by-value helper.
     let function_name = link::mangle_internal_name_by_type_and_seq(ccx, llonce_fn_ty, "once_shim");
-    let lloncefn = declare::define_internal_rust_fn(ccx, &function_name[..], llonce_fn_ty)
-        .unwrap_or_else(||{
-            ccx.sess().bug(&format!("symbol `{}` already defined", function_name));
-        });
-
+    let lloncefn = declare::define_internal_rust_fn(ccx, &function_name,
+                                                    llonce_fn_ty);
     let sig = tcx.erase_late_bound_regions(&llonce_bare_fn_ty.sig);
     let (block_arena, fcx): (TypedArena<_>, FunctionContext);
     block_arena = TypedArena::new();
index 7280c13bc5d75f67ead78f56ec78ea34895cfe4f..8ec65639b5227d6fff4c0264294ddda8319fdf15 100644 (file)
@@ -25,6 +25,7 @@
 use middle::subst::{self, Substs};
 use trans::base;
 use trans::build;
+use trans::callee;
 use trans::cleanup;
 use trans::consts;
 use trans::datum;
@@ -479,6 +480,56 @@ pub fn monomorphize<T>(&self, value: &T) -> T
     pub fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool {
         type_needs_drop_given_env(self.ccx.tcx(), ty, &self.param_env)
     }
+
+    pub fn eh_personality(&self) -> ValueRef {
+        // The exception handling personality function.
+        //
+        // If our compilation unit has the `eh_personality` lang item somewhere
+        // within it, then we just need to translate that. Otherwise, we're
+        // building an rlib which will depend on some upstream implementation of
+        // this function, so we just codegen a generic reference to it. We don't
+        // specify any of the types for the function, we just make it a symbol
+        // that LLVM can later use.
+        //
+        // Note that MSVC is a little special here in that we don't use the
+        // `eh_personality` lang item at all. Currently LLVM has support for
+        // both Dwarf and SEH unwind mechanisms for MSVC targets and uses the
+        // *name of the personality function* to decide what kind of unwind side
+        // tables/landing pads to emit. It looks like Dwarf is used by default,
+        // injecting a dependency on the `_Unwind_Resume` symbol for resuming
+        // an "exception", but for MSVC we want to force SEH. This means that we
+        // can't actually have the personality function be our standard
+        // `rust_eh_personality` function, but rather we wired it up to the
+        // CRT's custom personality function, which forces LLVM to consider
+        // landing pads as "landing pads for SEH".
+        let target = &self.ccx.sess().target.target;
+        match self.ccx.tcx().lang_items.eh_personality() {
+            Some(def_id) if !target.options.is_like_msvc => {
+                callee::trans_fn_ref(self.ccx, def_id, ExprId(0),
+                                     self.param_substs).val
+            }
+            _ => {
+                let mut personality = self.ccx.eh_personality().borrow_mut();
+                match *personality {
+                    Some(llpersonality) => llpersonality,
+                    None => {
+                        let name = if !target.options.is_like_msvc {
+                            "rust_eh_personality"
+                        } else if target.arch == "x86" {
+                            "_except_handler3"
+                        } else {
+                            "__C_specific_handler"
+                        };
+                        let fty = Type::variadic_func(&[], &Type::i32(self.ccx));
+                        let f = declare::declare_cfn(self.ccx, name, fty,
+                                                     self.ccx.tcx().types.i32);
+                        *personality = Some(f);
+                        f
+                    }
+                }
+            }
+        }
+    }
 }
 
 // Basic block context.  We create a block context for each basic block
index 242eceb8335b2c9b27e35fc2452e33ff48324171..302ef68bddc7d9943fa756d24bcbbd3e76404d71 100644 (file)
@@ -23,6 +23,8 @@
 use middle::const_eval::{const_int_checked_rem, const_uint_checked_rem};
 use middle::const_eval::{const_int_checked_shl, const_uint_checked_shl};
 use middle::const_eval::{const_int_checked_shr, const_uint_checked_shr};
+use middle::const_eval::EvalHint::ExprTypeChecked;
+use middle::const_eval::eval_const_expr_partial;
 use trans::{adt, closure, debuginfo, expr, inline, machine};
 use trans::base::{self, push_ctxt};
 use trans::common::*;
@@ -591,7 +593,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 
         ast::ExprIndex(ref base, ref index) => {
             let (bv, bt) = const_expr(cx, &**base, param_substs, fn_args);
-            let iv = match const_eval::eval_const_expr_partial(cx.tcx(), &**index, None) {
+            let iv = match eval_const_expr_partial(cx.tcx(), &index, ExprTypeChecked) {
                 Ok(ConstVal::Int(i)) => i as u64,
                 Ok(ConstVal::Uint(u)) => u,
                 _ => cx.sess().span_bug(index.span,
index 5a4bd7ff3a18468847b5bcb47ef974c1b7557ad5..760a4ae827aac66ef86adb86d07278e3d26b7f58 100644 (file)
@@ -142,6 +142,7 @@ pub struct LocalCrateContext<'tcx> {
     dbg_cx: Option<debuginfo::CrateDebugContext<'tcx>>,
 
     eh_personality: RefCell<Option<ValueRef>>,
+    rust_try_fn: RefCell<Option<ValueRef>>,
 
     intrinsics: RefCell<FnvHashMap<&'static str, ValueRef>>,
 
@@ -461,6 +462,7 @@ fn new<'a>(shared: &SharedCrateContext<'a, 'tcx>,
                 closure_vals: RefCell::new(FnvHashMap()),
                 dbg_cx: dbg_cx,
                 eh_personality: RefCell::new(None),
+                rust_try_fn: RefCell::new(None),
                 intrinsics: RefCell::new(FnvHashMap()),
                 n_llvm_insns: Cell::new(0),
                 trait_cache: RefCell::new(FnvHashMap()),
@@ -726,6 +728,10 @@ pub fn eh_personality<'a>(&'a self) -> &'a RefCell<Option<ValueRef>> {
         &self.local.eh_personality
     }
 
+    pub fn rust_try_fn<'a>(&'a self) -> &'a RefCell<Option<ValueRef>> {
+        &self.local.rust_try_fn
+    }
+
     fn intrinsics<'a>(&'a self) -> &'a RefCell<FnvHashMap<&'static str, ValueRef>> {
         &self.local.intrinsics
     }
@@ -923,6 +929,7 @@ macro_rules! mk_struct {
     ifn!("llvm.lifetime.end", fn(t_i64, i8p) -> void);
 
     ifn!("llvm.expect.i1", fn(i1, i1) -> i1);
+    ifn!("llvm.eh.typeid.for", fn(i8p) -> t_i32);
 
     // Some intrinsics were introduced in later versions of LLVM, but they have
     // fallbacks in libc or libm and such.
index b29da9d560fea89a6eda936982b4ab4f67f341f8..c802de91e38b3da452a8b09f64de196bad07fc1c 100644 (file)
@@ -176,8 +176,8 @@ pub fn define_global(ccx: &CrateContext, name: &str, ty: Type) -> Option<ValueRe
 /// return None if the name already has a definition associated with it. In that
 /// case an error should be reported to the user, because it usually happens due
 /// to user’s fault (e.g. misuse of #[no_mangle] or #[export_name] attributes).
-pub fn define_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, fn_type: Type,
-                 output: ty::FnOutput) -> Option<ValueRef> {
+pub fn define_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv,
+                 fn_type: Type, output: ty::FnOutput) -> Option<ValueRef> {
     if get_defined_value(ccx, name).is_some() {
         None
     } else {
@@ -224,20 +224,21 @@ pub fn define_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
 /// Declare a Rust function with an intention to define it.
 ///
 /// Use this function when you intend to define a function. This function will
-/// return None if the name already has a definition associated with it. In that
-/// case an error should be reported to the user, because it usually happens due
-/// to user’s fault (e.g. misuse of #[no_mangle] or #[export_name] attributes).
-pub fn define_internal_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
-                                         fn_type: ty::Ty<'tcx>) -> Option<ValueRef> {
+/// return panic if the name already has a definition associated with it. This
+/// can happen with #[no_mangle] or #[export_name], for example.
+pub fn define_internal_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+                                         name: &str,
+                                         fn_type: ty::Ty<'tcx>) -> ValueRef {
     if get_defined_value(ccx, name).is_some() {
-        None
+        ccx.sess().fatal(&format!("symbol `{}` already defined", name))
     } else {
-        Some(declare_internal_rust_fn(ccx, name, fn_type))
+        declare_internal_rust_fn(ccx, name, fn_type)
     }
 }
 
 
-/// Get defined or externally defined (AvailableExternally linkage) value by name.
+/// Get defined or externally defined (AvailableExternally linkage) value by
+/// name.
 fn get_defined_value(ccx: &CrateContext, name: &str) -> Option<ValueRef> {
     debug!("get_defined_value(name={:?})", name);
     let namebuf = CString::new(name).unwrap_or_else(|_|{
index 9e8c0189a9762722a7683480a7bc632c623684cf..e102e3cd062be220dbf886d712cbcecef7c69be7 100644 (file)
@@ -627,9 +627,7 @@ fn build_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                ccx.tcx().map.path_to_string(id),
                id, t);
 
-        let llfn = declare::define_internal_rust_fn(ccx, &ps[..], t).unwrap_or_else(||{
-            ccx.sess().bug(&format!("symbol `{}` already defined", ps));
-        });
+        let llfn = declare::define_internal_rust_fn(ccx, &ps, t);
         attributes::from_fn_attrs(ccx, attrs, llfn);
         base::trans_fn(ccx, decl, body, llfn, param_substs, id, &[]);
         llfn
index b449c3ad060b81a82f67f31657ee0067c5eaf2d5..e78218fd10dd8fab399075745aafb2ae4c117ef9 100644 (file)
@@ -10,6 +10,7 @@
 
 #![allow(non_upper_case_globals)]
 
+use arena::TypedArena;
 use llvm;
 use llvm::{SequentiallyConsistent, Acquire, Release, AtomicXchg, ValueRef, TypeKind};
 use middle::subst;
@@ -23,6 +24,7 @@
 use trans::common::*;
 use trans::datum::*;
 use trans::debuginfo::DebugLoc;
+use trans::declare;
 use trans::expr;
 use trans::glue;
 use trans::type_of::*;
@@ -31,7 +33,8 @@
 use trans::machine::llsize_of;
 use trans::type_::Type;
 use middle::ty::{self, Ty, HasTypeFlags};
-use syntax::abi::RustIntrinsic;
+use middle::subst::Substs;
+use syntax::abi::{self, RustIntrinsic};
 use syntax::ast;
 use syntax::parse::token;
 
@@ -302,6 +305,42 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
         }
     }
 
+    let call_debug_location = DebugLoc::At(call_info.id, call_info.span);
+
+    // For `try` we need some custom control flow
+    if &name[..] == "try" {
+        if let callee::ArgExprs(ref exprs) = args {
+            let (func, data) = if exprs.len() != 2 {
+                ccx.sess().bug("expected two exprs as arguments for \
+                                `try` intrinsic");
+            } else {
+                (&exprs[0], &exprs[1])
+            };
+
+            // translate arguments
+            let func = unpack_datum!(bcx, expr::trans(bcx, func));
+            let func = unpack_datum!(bcx, func.to_rvalue_datum(bcx, "func"));
+            let data = unpack_datum!(bcx, expr::trans(bcx, data));
+            let data = unpack_datum!(bcx, data.to_rvalue_datum(bcx, "data"));
+
+            let dest = match dest {
+                expr::SaveIn(d) => d,
+                expr::Ignore => alloc_ty(bcx, tcx.mk_mut_ptr(tcx.types.i8),
+                                         "try_result"),
+            };
+
+            // do the invoke
+            bcx = try_intrinsic(bcx, func.val, data.val, dest,
+                                call_debug_location);
+
+            fcx.pop_and_trans_custom_cleanup_scope(bcx, cleanup_scope);
+            return Result::new(bcx, dest);
+        } else {
+            ccx.sess().bug("expected two exprs as arguments for \
+                            `try` intrinsic");
+        }
+    }
+
     // Push the arguments.
     let mut llargs = Vec::new();
     bcx = callee::trans_args(bcx,
@@ -314,8 +353,6 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
 
     fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean();
 
-    let call_debug_location = DebugLoc::At(call_info.id, call_info.span);
-
     // These are the only intrinsic functions that diverge.
     if &name[..] == "abort" {
         let llfn = ccx.get_intrinsic(&("llvm.trap"));
@@ -989,3 +1026,304 @@ fn with_overflow_intrinsic<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         ret
     }
 }
+
+fn try_intrinsic<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+                             func: ValueRef,
+                             data: ValueRef,
+                             dest: ValueRef,
+                             dloc: DebugLoc) -> Block<'blk, 'tcx> {
+    if bcx.sess().no_landing_pads() {
+        Call(bcx, func, &[data], None, dloc);
+        Store(bcx, C_null(Type::i8p(bcx.ccx())), dest);
+        bcx
+    } else if bcx.sess().target.target.options.is_like_msvc {
+        trans_msvc_try(bcx, func, data, dest, dloc)
+    } else {
+        trans_gnu_try(bcx, func, data, dest, dloc)
+    }
+}
+
+// MSVC's definition of the `rust_try` function. The exact implementation here
+// is a little different than the GNU (standard) version below, not only because
+// of the personality function but also because of the other fiddly bits about
+// SEH. LLVM also currently requires us to structure this a very particular way
+// as explained below.
+//
+// Like with the GNU version we generate a shim wrapper
+fn trans_msvc_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+                              func: ValueRef,
+                              data: ValueRef,
+                              dest: ValueRef,
+                              dloc: DebugLoc) -> Block<'blk, 'tcx> {
+    let llfn = get_rust_try_fn(bcx.fcx, &mut |try_fn_ty, output| {
+        let ccx = bcx.ccx();
+        let dloc = DebugLoc::None;
+        let rust_try = declare::define_internal_rust_fn(ccx, "__rust_try",
+                                                         try_fn_ty);
+        let (fcx, block_arena);
+        block_arena = TypedArena::new();
+        fcx = new_fn_ctxt(ccx, rust_try, ast::DUMMY_NODE_ID, false,
+                          output, ccx.tcx().mk_substs(Substs::trans_empty()),
+                          None, &block_arena);
+        let bcx = init_function(&fcx, true, output);
+        let then = fcx.new_temp_block("then");
+        let catch = fcx.new_temp_block("catch");
+        let catch_return = fcx.new_temp_block("catch-return");
+        let catch_resume = fcx.new_temp_block("catch-resume");
+        let personality = fcx.eh_personality();
+
+        let eh_typeid_for = ccx.get_intrinsic(&"llvm.eh.typeid.for");
+        let rust_try_filter = match bcx.tcx().lang_items.msvc_try_filter() {
+            Some(did) => callee::trans_fn_ref(ccx, did, ExprId(0),
+                                              bcx.fcx.param_substs).val,
+            None => bcx.sess().bug("msvc_try_filter not defined"),
+        };
+
+        // Type indicator for the exception being thrown, not entirely sure
+        // what's going on here but it's what all the examples in LLVM use.
+        let lpad_ty = Type::struct_(ccx, &[Type::i8p(ccx), Type::i32(ccx)],
+                                    false);
+
+        llvm::SetFunctionAttribute(rust_try, llvm::Attribute::NoInline);
+        llvm::SetFunctionAttribute(rust_try, llvm::Attribute::OptimizeNone);
+        let func = llvm::get_param(rust_try, 0);
+        let data = llvm::get_param(rust_try, 1);
+
+        // Invoke the function, specifying our two temporary landing pads as the
+        // ext point. After the invoke we've terminated our basic block.
+        Invoke(bcx, func, &[data], then.llbb, catch.llbb, None, dloc);
+
+        // All the magic happens in this landing pad, and this is basically the
+        // only landing pad in rust tagged with "catch" to indicate that we're
+        // catching an exception. The other catch handlers in the GNU version
+        // below just catch *all* exceptions, but that's because most exceptions
+        // are already filtered out by the gnu personality function.
+        //
+        // For MSVC we're just using a standard personality function that we
+        // can't customize (e.g. _except_handler3 or __C_specific_handler), so
+        // we need to do the exception filtering ourselves. This is currently
+        // performed by the `__rust_try_filter` function. This function,
+        // specified in the landingpad instruction, will be invoked by Windows
+        // SEH routines and will return whether the exception in question can be
+        // caught (aka the Rust runtime is the one that threw the exception).
+        //
+        // To get this to compile (currently LLVM segfaults if it's not in this
+        // particular structure), when the landingpad is executing we test to
+        // make sure that the ID of the exception being thrown is indeed the one
+        // that we were expecting. If it's not, we resume the exception, and
+        // otherwise we return the pointer that we got Full disclosure: It's not
+        // clear to me what this `llvm.eh.typeid` stuff is doing *other* then
+        // just allowing LLVM to compile this file without segfaulting. I would
+        // expect the entire landing pad to just be:
+        //
+        //     %vals = landingpad ...
+        //     %ehptr = extractvalue { i8*, i32 } %vals, 0
+        //     ret i8* %ehptr
+        //
+        // but apparently LLVM chokes on this, so we do the more complicated
+        // thing to placate it.
+        let vals = LandingPad(catch, lpad_ty, personality, 1);
+        let rust_try_filter = BitCast(catch, rust_try_filter, Type::i8p(ccx));
+        AddClause(catch, vals, rust_try_filter);
+        let ehptr = ExtractValue(catch, vals, 0);
+        let sel = ExtractValue(catch, vals, 1);
+        let filter_sel = Call(catch, eh_typeid_for, &[rust_try_filter], None,
+                              dloc);
+        let is_filter = ICmp(catch, llvm::IntEQ, sel, filter_sel, dloc);
+        CondBr(catch, is_filter, catch_return.llbb, catch_resume.llbb, dloc);
+
+        // Our "catch-return" basic block is where we've determined that we
+        // actually need to catch this exception, in which case we just return
+        // the exception pointer.
+        Ret(catch_return, ehptr, dloc);
+
+        // The "catch-resume" block is where we're running this landing pad but
+        // we actually need to not catch the exception, so just resume the
+        // exception to return.
+        Resume(catch_resume, vals);
+
+        // On the successful branch we just return null.
+        Ret(then, C_null(Type::i8p(ccx)), dloc);
+
+        return rust_try
+    });
+
+    // Note that no invoke is used here because by definition this function
+    // can't panic (that's what it's catching).
+    let ret = Call(bcx, llfn, &[func, data], None, dloc);
+    Store(bcx, ret, dest);
+    return bcx;
+}
+
+// Definition of the standard "try" function for Rust using the GNU-like model
+// of exceptions (e.g. the normal semantics of LLVM's landingpad and invoke
+// instructions).
+//
+// This translation is a little surprising for two reasons:
+//
+// 1. We always call a shim function instead of inlining the call to `invoke`
+//    manually here. This is done because in LLVM we're only allowed to have one
+//    personality per function definition. The call to the `try` intrinsic is
+//    being inlined into the function calling it, and that function may already
+//    have other personality functions in play. By calling a shim we're
+//    guaranteed that our shim will have the right personality function.
+//
+// 2. Instead of making one shim (explained above), we make two shims! The
+//    reason for this has to do with the technical details about the
+//    implementation of unwinding in the runtime, but the tl;dr; is that the
+//    outer shim's personality function says "catch rust exceptions" and the
+//    inner shim's landing pad will not `resume` the exception being thrown.
+//    This means that the outer shim's landing pad is never run and the inner
+//    shim's return value is the return value of the whole call.
+//
+// The double-shim aspect is currently done for implementation ease on the
+// runtime side of things, and more info can be found in
+// src/libstd/rt/unwind/gcc.rs.
+fn trans_gnu_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+                             func: ValueRef,
+                             data: ValueRef,
+                             dest: ValueRef,
+                             dloc: DebugLoc) -> Block<'blk, 'tcx> {
+    let llfn = get_rust_try_fn(bcx.fcx, &mut |try_fn_ty, output| {
+        let ccx = bcx.ccx();
+        let dloc = DebugLoc::None;
+
+        // Type indicator for the exception being thrown, not entirely sure
+        // what's going on here but it's what all the examples in LLVM use.
+        let lpad_ty = Type::struct_(ccx, &[Type::i8p(ccx), Type::i32(ccx)],
+                                    false);
+
+        // Define the "inner try" shim
+        let rust_try_inner = declare::define_internal_rust_fn(ccx,
+                                                              "__rust_try_inner",
+                                                              try_fn_ty);
+        trans_rust_try(ccx, rust_try_inner, lpad_ty, bcx.fcx.eh_personality(),
+                       output, dloc, &mut |bcx, then, catch| {
+            let func = llvm::get_param(rust_try_inner, 0);
+            let data = llvm::get_param(rust_try_inner, 1);
+            Invoke(bcx, func, &[data], then.llbb, catch.llbb, None, dloc);
+            C_null(Type::i8p(ccx))
+        });
+
+        // Define the "outer try" shim.
+        let rust_try = declare::define_internal_rust_fn(ccx, "__rust_try",
+                                                        try_fn_ty);
+        let catch_pers = match bcx.tcx().lang_items.eh_personality_catch() {
+            Some(did) => callee::trans_fn_ref(ccx, did, ExprId(0),
+                                              bcx.fcx.param_substs).val,
+            None => bcx.tcx().sess.bug("eh_personality_catch not defined"),
+        };
+        trans_rust_try(ccx, rust_try, lpad_ty, catch_pers, output, dloc,
+                       &mut |bcx, then, catch| {
+            let func = llvm::get_param(rust_try, 0);
+            let data = llvm::get_param(rust_try, 1);
+            Invoke(bcx, rust_try_inner, &[func, data], then.llbb, catch.llbb,
+                   None, dloc)
+        });
+        return rust_try
+    });
+
+    // Note that no invoke is used here because by definition this function
+    // can't panic (that's what it's catching).
+    let ret = Call(bcx, llfn, &[func, data], None, dloc);
+    Store(bcx, ret, dest);
+    return bcx;
+
+    // Translates both the inner and outer shims described above. The only
+    // difference between these two is the function invoked and the personality
+    // involved, so a common routine is shared.
+    //
+    //   bcx:
+    //      invoke %func(%args...) normal %normal unwind %unwind
+    //
+    //   normal:
+    //      ret null
+    //
+    //   unwind:
+    //      (ptr, _) = landingpad
+    //      br (ptr != null), done, reraise
+    //
+    //   done:
+    //      ret ptr
+    //
+    //   reraise:
+    //      resume
+    //
+    // Note that the branch checking for `null` here isn't actually necessary,
+    // it's just an unfortunate hack to make sure that LLVM doesn't optimize too
+    // much. If this were not present, then LLVM would correctly deduce that our
+    // inner shim should be tagged with `nounwind` (as it catches all
+    // exceptions) and then the outer shim's `invoke` will be translated to just
+    // a simple call, destroying that entry for the personality function.
+    //
+    // To ensure that both shims always have an `invoke` this check against null
+    // confuses LLVM enough to the point that it won't infer `nounwind` and
+    // we'll proceed as normal.
+    fn trans_rust_try<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+                                llfn: ValueRef,
+                                lpad_ty: Type,
+                                personality: ValueRef,
+                                output: ty::FnOutput<'tcx>,
+                                dloc: DebugLoc,
+                                invoke: &mut FnMut(Block, Block, Block) -> ValueRef) {
+        let (fcx, block_arena);
+        block_arena = TypedArena::new();
+        fcx = new_fn_ctxt(ccx, llfn, ast::DUMMY_NODE_ID, false,
+                          output, ccx.tcx().mk_substs(Substs::trans_empty()),
+                          None, &block_arena);
+        let bcx = init_function(&fcx, true, output);
+        let then = bcx.fcx.new_temp_block("then");
+        let catch = bcx.fcx.new_temp_block("catch");
+        let reraise = bcx.fcx.new_temp_block("reraise");
+        let catch_return = bcx.fcx.new_temp_block("catch-return");
+
+        let invoke_ret = invoke(bcx, then, catch);
+        Ret(then, invoke_ret, dloc);
+        let vals = LandingPad(catch, lpad_ty, personality, 1);
+        AddClause(catch, vals, C_null(Type::i8p(ccx)));
+        let ptr = ExtractValue(catch, vals, 0);
+        let valid = ICmp(catch, llvm::IntNE, ptr, C_null(Type::i8p(ccx)), dloc);
+        CondBr(catch, valid, catch_return.llbb, reraise.llbb, dloc);
+        Ret(catch_return, ptr, dloc);
+        Resume(reraise, vals);
+    }
+}
+
+// Helper to generate the `Ty` associated with `rust_Try`
+fn get_rust_try_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
+                             f: &mut FnMut(Ty<'tcx>,
+                                           ty::FnOutput<'tcx>) -> ValueRef)
+                             -> ValueRef {
+    let ccx = fcx.ccx;
+    if let Some(llfn) = *ccx.rust_try_fn().borrow() {
+        return llfn
+    }
+
+    // Define the types up front for the signatures of the rust_try and
+    // rust_try_inner functions.
+    let tcx = ccx.tcx();
+    let i8p = tcx.mk_mut_ptr(tcx.types.i8);
+    let fn_ty = tcx.mk_bare_fn(ty::BareFnTy {
+        unsafety: ast::Unsafety::Unsafe,
+        abi: abi::Rust,
+        sig: ty::Binder(ty::FnSig {
+            inputs: vec![i8p],
+            output: ty::FnOutput::FnConverging(tcx.mk_nil()),
+            variadic: false,
+        }),
+    });
+    let fn_ty = tcx.mk_fn(None, fn_ty);
+    let output = ty::FnOutput::FnConverging(i8p);
+    let try_fn_ty  = tcx.mk_bare_fn(ty::BareFnTy {
+        unsafety: ast::Unsafety::Unsafe,
+        abi: abi::Rust,
+        sig: ty::Binder(ty::FnSig {
+            inputs: vec![fn_ty, i8p],
+            output: output,
+            variadic: false,
+        }),
+    });
+    let rust_try = f(tcx.mk_fn(None, try_fn_ty), output);
+    *ccx.rust_try_fn().borrow_mut() = Some(rust_try);
+    return rust_try
+}
index 1fa996f76b9a28809a2778a3ee2ac2342089abdd..8901361b27976396cfada7ff1c19b21ed4914634 100644 (file)
@@ -550,9 +550,7 @@ fn trans_object_shim<'a, 'tcx>(
     let shim_fn_ty = tcx.mk_fn(None, fty);
     let method_bare_fn_ty = tcx.mk_fn(None, method_ty);
     let function_name = link::mangle_internal_name_by_type_and_seq(ccx, shim_fn_ty, "object_shim");
-    let llfn = declare::define_internal_rust_fn(ccx, &function_name, shim_fn_ty).unwrap_or_else(||{
-        ccx.sess().bug(&format!("symbol `{}` already defined", function_name));
-    });
+    let llfn = declare::define_internal_rust_fn(ccx, &function_name, shim_fn_ty);
 
     let sig = ccx.tcx().erase_late_bound_regions(&fty.sig);
 
index 98fe57ec31446f6cfac18a613707bd4f7d6e1fd0..217181da1421aac8ac688d3a52a8091cbbfca8b9 100644 (file)
@@ -137,10 +137,9 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         let lldecl = if abi != abi::Rust {
             foreign::decl_rust_fn_with_foreign_abi(ccx, mono_ty, &s[..])
         } else {
-            // FIXME(nagisa): perhaps needs a more fine grained selection? See setup_lldecl below.
-            declare::define_internal_rust_fn(ccx, &s[..], mono_ty).unwrap_or_else(||{
-                ccx.sess().bug(&format!("symbol `{}` already defined", s));
-            })
+            // FIXME(nagisa): perhaps needs a more fine grained selection? See
+            // setup_lldecl below.
+            declare::define_internal_rust_fn(ccx, &s, mono_ty)
         };
 
         ccx.monomorphized().borrow_mut().insert(hash_id.take().unwrap(), lldecl);
index 07af1aa64ae9c0328d1708bbab20ee4199b35bbd..c448af2288a65cb37a72121d194879f1c8c9b8c4 100644 (file)
@@ -50,6 +50,7 @@
 
 use middle::astconv_util::{prim_ty_to_ty, check_path_args, NO_TPS, NO_REGIONS};
 use middle::const_eval::{self, ConstVal};
+use middle::const_eval::EvalHint::UncheckedExprHint;
 use middle::def;
 use middle::implicator::object_region_bounds;
 use middle::resolve_lifetime as rl;
@@ -58,6 +59,7 @@
 use middle::traits;
 use middle::ty::{self, RegionEscape, Ty, ToPredicate, HasTypeFlags};
 use middle::ty_fold;
+use require_c_abi_if_variadic;
 use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, ExplicitRscope,
              ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope,
              ElisionFailureInfo, ElidedLifetime};
@@ -1574,10 +1576,7 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>,
         }
         ast::TyParen(ref typ) => ast_ty_to_ty(this, rscope, &**typ),
         ast::TyBareFn(ref bf) => {
-            if bf.decl.variadic && bf.abi != abi::C {
-                span_err!(tcx.sess, ast_ty.span, E0045,
-                          "variadic function must have C calling convention");
-            }
+            require_c_abi_if_variadic(tcx, &bf.decl, bf.abi, ast_ty.span);
             let bare_fn = ty_of_bare_fn(this, bf.unsafety, bf.abi, &*bf.decl);
             tcx.mk_fn(None, tcx.mk_bare_fn(bare_fn))
         }
@@ -1623,7 +1622,8 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>,
             ty
         }
         ast::TyFixedLengthVec(ref ty, ref e) => {
-            match const_eval::eval_const_expr_partial(tcx, &**e, Some(tcx.types.usize)) {
+            let hint = UncheckedExprHint(tcx.types.usize);
+            match const_eval::eval_const_expr_partial(tcx, &e, hint) {
                 Ok(r) => {
                     match r {
                         ConstVal::Int(i) =>
index a995401cf5c81d9b7bbb1cb5da7a545b376f27fd..c4b31d578dbfdd77c0be639e51b9dd8a0ad0456b 100644 (file)
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use middle::const_eval;
 use middle::def;
 use middle::infer;
 use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding};
@@ -23,7 +22,7 @@
 use require_same_types;
 use util::nodemap::FnvHashMap;
 
-use std::cmp::{self, Ordering};
+use std::cmp;
 use std::collections::hash_map::Entry::{Occupied, Vacant};
 use syntax::ast;
 use syntax::ast_util;
@@ -130,18 +129,6 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
 
             fcx.write_ty(pat.id, common_type);
 
-            // Finally we evaluate the constants and check that the range is non-empty.
-            let get_substs = |id| fcx.item_substs()[&id].substs.clone();
-            match const_eval::compare_lit_exprs(tcx, begin, end, Some(&common_type), get_substs) {
-                Some(Ordering::Less) |
-                Some(Ordering::Equal) => {}
-                Some(Ordering::Greater) => {
-                    span_err!(tcx.sess, begin.span, E0030,
-                        "lower range bound must be less than or equal to upper");
-                }
-                None => tcx.sess.span_bug(begin.span, "literals of different types in range pat")
-            }
-
             // subtyping doesn't matter here, as the value is some kind of scalar
             demand::eqtype(fcx, pat.span, expected, lhs_ty);
         }
index a98f7a8678c22f5547ab0af564d66bd414f4f228..d77d48eea48c2d30bef7f331f6f637ce250225be 100644 (file)
@@ -97,6 +97,7 @@
 use middle::ty::{self, HasTypeFlags, RegionEscape, ToPolyTraitRef, Ty};
 use middle::ty::{MethodCall, MethodCallee};
 use middle::ty_fold::{TypeFolder, TypeFoldable};
+use require_c_abi_if_variadic;
 use rscope::{ElisionFailureInfo, RegionScope};
 use session::Session;
 use {CrateCtxt, lookup_full_def, require_same_types};
@@ -685,10 +686,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) {
                 }
 
                 if let ast::ForeignItemFn(ref fn_decl, _) = item.node {
-                    if fn_decl.variadic && m.abi != abi::C {
-                        span_err!(ccx.tcx.sess, item.span, E0045,
-                                  "variadic function must have C calling convention");
-                    }
+                    require_c_abi_if_variadic(ccx.tcx, fn_decl, m.abi, item.span);
                 }
             }
         }
@@ -5086,6 +5084,21 @@ fn param<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, n: u32) -> Ty<'tcx> {
                                                                   ty::BrAnon(0))),
                                     param(ccx, 0))], tcx.types.u64),
 
+            "try" => {
+                let mut_u8 = tcx.mk_mut_ptr(tcx.types.u8);
+                let fn_ty = ty::BareFnTy {
+                    unsafety: ast::Unsafety::Normal,
+                    abi: abi::Rust,
+                    sig: ty::Binder(FnSig {
+                        inputs: vec![mut_u8],
+                        output: ty::FnOutput::FnConverging(tcx.mk_nil()),
+                        variadic: false,
+                    }),
+                };
+                let fn_ty = tcx.mk_bare_fn(fn_ty);
+                (0, vec![tcx.mk_fn(None, fn_ty), mut_u8], mut_u8)
+            }
+
             ref other => {
                 span_err!(tcx.sess, it.span, E0093,
                     "unrecognized intrinsic function: `{}`", *other);
index a002ed311e8c52a94d732247f0473b58777e38c5..f865de522b28aa0611eee697e87d930d9c487d73 100644 (file)
@@ -169,24 +169,6 @@ struct Dog {
 ```
 "##,
 
-E0030: r##"
-When matching against a range, the compiler verifies that the range is
-non-empty.  Range patterns include both end-points, so this is equivalent to
-requiring the start of the range to be less than or equal to the end of the
-range.
-
-For example:
-
-```
-match 5u32 {
-    // This range is ok, albeit pointless.
-    1 ... 1 => ...
-    // This range is empty, and the compiler can tell.
-    1000 ... 5 => ...
-}
-```
-"##,
-
 E0033: r##"
 This error indicates that a pointer to a trait type cannot be implicitly
 dereferenced by a pattern. Every trait defines a type, but because the
@@ -1476,6 +1458,33 @@ struct Foo {
 diverging function (such as `panic!()`).
 "##,
 
+E0172: r##"
+This error means that an attempt was made to specify the type of a variable with
+a combination of a concrete type and a trait. Consider the following example:
+
+```
+fn foo(bar: i32+std::fmt::Display) {}
+```
+
+The code is trying to specify that we want to receive a signed 32-bit integer
+which also implements `Display`. This doesn't make sense: when we pass `i32`, a
+concrete type, it implicitly includes all of the traits that it implements.
+This includes `Display`, `Debug`, `Clone`, and a host of others.
+
+If `i32` implements the trait we desire, there's no need to specify the trait
+separately. If it does not, then we need to `impl` the trait for `i32` before
+passing it into `foo`. Either way, a fixed definition for `foo` will look like
+the following:
+
+```
+fn foo(bar: i32) {}
+```
+
+To learn more about traits, take a look at the Book:
+
+https://doc.rust-lang.org/book/traits.html
+"##,
+
 E0178: r##"
 In types, the `+` type operator has low precedence, so it is often necessary
 to use parentheses.
@@ -2196,7 +2205,6 @@ struct Foo<'a, T: 'a> {
     E0164,
     E0167,
     E0168,
-    E0172,
     E0173, // manual implementations of unboxed closure traits are experimental
     E0174, // explicit use of unboxed closure methods are experimental
     E0182,
index 4260791e38458ab9aa8a503e917358be710cd5ca..9c0e121e156f9ea3259e68516b517587d4035050 100644 (file)
@@ -176,6 +176,16 @@ fn lookup_full_def(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) -> def::Def {
     }
 }
 
+fn require_c_abi_if_variadic(tcx: &ty::ctxt,
+                             decl: &ast::FnDecl,
+                             abi: abi::Abi,
+                             span: Span) {
+    if decl.variadic && abi != abi::C {
+        span_err!(tcx.sess, span, E0045,
+                  "variadic function must have C calling convention");
+    }
+}
+
 fn require_same_types<'a, 'tcx, M>(tcx: &ty::ctxt<'tcx>,
                                    maybe_infcx: Option<&infer::InferCtxt<'a, 'tcx>>,
                                    t1_is_expected: bool,
index d6561ebb489d7487437ed674011be3e7393c3062..c25aa35ffbe3b339d9045ea47a6c15a6bd904f4d 100644 (file)
@@ -252,14 +252,49 @@ fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
     }
 }
 
-/// Wraps a Writer and buffers output to it.
+/// Wraps a writer and buffers its output.
 ///
-/// It can be excessively inefficient to work directly with a `Write`. For
-/// example, every call to `write` on `TcpStream` results in a system call. A
-/// `BufWriter` keeps an in memory buffer of data and writes it to the
-/// underlying `Write` in large, infrequent batches.
+/// It can be excessively inefficient to work directly with something that
+/// implements `Write`. For example, every call to `write` on `TcpStream`
+/// results in a system call. A `BufWriter` keeps an in-memory buffer of data
+/// and writes it to an underlying writer in large, infrequent batches.
 ///
 /// The buffer will be written out when the writer is dropped.
+///
+/// # Examples
+///
+/// Let's write the numbers one through ten to a `TcpStream`:
+///
+/// ```no_run
+/// use std::io::prelude::*;
+/// use std::net::TcpStream;
+///
+/// let mut stream = TcpStream::connect("127.0.0.1:34254").unwrap();
+///
+/// for i in 1..10 {
+///     stream.write(&[i]).unwrap();
+/// }
+/// ```
+///
+/// Because we're not buffering, we write each one in turn, incurring the
+/// overhead of a system call per byte written. We can fix this with a
+/// `BufWriter`:
+///
+/// ```no_run
+/// use std::io::prelude::*;
+/// use std::io::BufWriter;
+/// use std::net::TcpStream;
+///
+/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+///
+/// for i in 1..10 {
+///     stream.write(&[i]).unwrap();
+/// }
+/// ```
+///
+/// By wrapping the stream with a `BufWriter`, these ten writes are all grouped
+/// together by the buffer, and will all be written out in one system call when
+/// the `stream` is dropped.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct BufWriter<W: Write> {
     inner: Option<W>,
@@ -269,18 +304,60 @@ pub struct BufWriter<W: Write> {
 /// An error returned by `into_inner` which combines an error that
 /// happened while writing out the buffer, and the buffered writer object
 /// which may be used to recover from the condition.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::io::BufWriter;
+/// use std::net::TcpStream;
+///
+/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+///
+/// // do stuff with the stream
+///
+/// // we want to get our `TcpStream` back, so let's try:
+///
+/// let stream = match stream.into_inner() {
+///     Ok(s) => s,
+///     Err(e) => {
+///         // Here, e is an IntoInnerError
+///         panic!("An error occurred");
+///     }
+/// };
+/// ```
 #[derive(Debug)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct IntoInnerError<W>(W, Error);
 
 impl<W: Write> BufWriter<W> {
     /// Creates a new `BufWriter` with a default buffer capacity.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufWriter;
+    /// use std::net::TcpStream;
+    ///
+    /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn new(inner: W) -> BufWriter<W> {
         BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner)
     }
 
     /// Creates a new `BufWriter` with the specified buffer capacity.
+    ///
+    /// # Examples
+    ///
+    /// Creating a buffer with a buffer of a hundred bytes.
+    ///
+    /// ```no_run
+    /// use std::io::BufWriter;
+    /// use std::net::TcpStream;
+    ///
+    /// let stream = TcpStream::connect("127.0.0.1:34254").unwrap();
+    /// let mut buffer = BufWriter::with_capacity(100, stream);
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn with_capacity(cap: usize, inner: W) -> BufWriter<W> {
         BufWriter {
@@ -313,6 +390,18 @@ fn flush_buf(&mut self) -> io::Result<()> {
     }
 
     /// Gets a reference to the underlying writer.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufWriter;
+    /// use std::net::TcpStream;
+    ///
+    /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+    ///
+    /// // we can use reference just like buffer
+    /// let reference = buffer.get_ref();
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn get_ref(&self) -> &W { self.inner.as_ref().unwrap() }
 
@@ -321,12 +410,36 @@ pub fn get_ref(&self) -> &W { self.inner.as_ref().unwrap() }
     /// # Warning
     ///
     /// It is inadvisable to directly write to the underlying writer.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufWriter;
+    /// use std::net::TcpStream;
+    ///
+    /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+    ///
+    /// // we can use reference just like buffer
+    /// let reference = buffer.get_mut();
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn get_mut(&mut self) -> &mut W { self.inner.as_mut().unwrap() }
 
     /// Unwraps this `BufWriter`, returning the underlying writer.
     ///
     /// The buffer is written out before returning the writer.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufWriter;
+    /// use std::net::TcpStream;
+    ///
+    /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+    ///
+    /// // unwrap the TcpStream and flush the buffer
+    /// let stream = buffer.into_inner().unwrap();
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn into_inner(mut self) -> Result<W, IntoInnerError<BufWriter<W>>> {
         match self.flush_buf() {
@@ -384,9 +497,34 @@ fn drop(&mut self) {
 }
 
 impl<W> IntoInnerError<W> {
-    /// Returns the error which caused the call to `into_inner` to fail.
+    /// Returns the error which caused the call to `into_inner()` to fail.
     ///
     /// This error was returned when attempting to write the internal buffer.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufWriter;
+    /// use std::net::TcpStream;
+    ///
+    /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+    ///
+    /// // do stuff with the stream
+    ///
+    /// // we want to get our `TcpStream` back, so let's try:
+    ///
+    /// let stream = match stream.into_inner() {
+    ///     Ok(s) => s,
+    ///     Err(e) => {
+    ///         // Here, e is an IntoInnerError, let's log the inner error.
+    ///         //
+    ///         // We'll just 'log' to stdout for this example.
+    ///         println!("{}", e.error());
+    ///
+    ///         panic!("An unexpected error occurred.");
+    ///     }
+    /// };
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn error(&self) -> &Error { &self.1 }
 
@@ -394,6 +532,32 @@ pub fn error(&self) -> &Error { &self.1 }
     ///
     /// The returned object can be used for error recovery, such as
     /// re-inspecting the buffer.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufWriter;
+    /// use std::net::TcpStream;
+    ///
+    /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+    ///
+    /// // do stuff with the stream
+    ///
+    /// // we want to get our `TcpStream` back, so let's try:
+    ///
+    /// let stream = match stream.into_inner() {
+    ///     Ok(s) => s,
+    ///     Err(e) => {
+    ///         // Here, e is a IntoInnerError, let's re-examine the buffer:
+    ///         let buffer = e.into_inner();
+    ///
+    ///         // do stuff to try to recover
+    ///
+    ///         // afterwards, let's just return the stream
+    ///         buffer.into_inner().unwrap()
+    ///     }
+    /// };
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn into_inner(self) -> W { self.0 }
 }
@@ -417,17 +581,74 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-/// Wraps a Writer and buffers output to it, flushing whenever a newline
+/// Wraps a writer and buffers output to it, flushing whenever a newline
 /// (`0x0a`, `'\n'`) is detected.
 ///
-/// The buffer will be written out when the writer is dropped.
+/// The [`BufWriter`][bufwriter] struct wraps a writer and buffers its output.
+/// But it only does this batched write when it goes out of scope, or when the
+/// internal buffer is full. Sometimes, you'd prefer to write each line as it's
+/// completed, rather than the entire buffer at once. Enter `LineWriter`. It
+/// does exactly that.
+///
+/// [bufwriter]: struct.BufWriter.html
+///
+/// If there's still a partial line in the buffer when the `LineWriter` is
+/// dropped, it will flush those contents.
+///
+/// # Examples
+///
+/// We can use `LineWriter` to write one line at a time, significantly
+/// reducing the number of actual writes to the file.
+///
+/// ```
+/// use std::fs::File;
+/// use std::io::prelude::*;
+/// use std::io::LineWriter;
+///
+/// # fn foo() -> std::io::Result<()> {
+/// let road_not_taken = b"I shall be telling this with a sigh
+/// Somewhere ages and ages hence:
+/// Two roads diverged in a wood, and I -
+/// I took the one less traveled by,
+/// And that has made all the difference.";
+///
+/// let file = try!(File::create("poem.txt"));
+/// let mut file = LineWriter::new(file);
+///
+/// for &byte in road_not_taken.iter() {
+///    file.write(&[byte]).unwrap();
+/// }
+///
+/// // let's check we did the right thing.
+/// let mut file = try!(File::open("poem.txt"));
+/// let mut contents = String::new();
+///
+/// try!(file.read_to_string(&mut contents));
+///
+/// assert_eq!(contents.as_bytes(), &road_not_taken[..]);
+/// # Ok(())
+/// # }
+/// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct LineWriter<W: Write> {
     inner: BufWriter<W>,
 }
 
 impl<W: Write> LineWriter<W> {
-    /// Creates a new `LineWriter`
+    /// Creates a new `LineWriter`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::fs::File;
+    /// use std::io::LineWriter;
+    ///
+    /// # fn foo() -> std::io::Result<()> {
+    /// let file = try!(File::create("poem.txt"));
+    /// let file = LineWriter::new(file);
+    /// # Ok(())
+    /// # }
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn new(inner: W) -> LineWriter<W> {
         // Lines typically aren't that long, don't use a giant buffer
@@ -436,12 +657,40 @@ pub fn new(inner: W) -> LineWriter<W> {
 
     /// Creates a new `LineWriter` with a specified capacity for the internal
     /// buffer.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::fs::File;
+    /// use std::io::LineWriter;
+    ///
+    /// # fn foo() -> std::io::Result<()> {
+    /// let file = try!(File::create("poem.txt"));
+    /// let file = LineWriter::with_capacity(100, file);
+    /// # Ok(())
+    /// # }
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn with_capacity(cap: usize, inner: W) -> LineWriter<W> {
         LineWriter { inner: BufWriter::with_capacity(cap, inner) }
     }
 
     /// Gets a reference to the underlying writer.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::fs::File;
+    /// use std::io::LineWriter;
+    ///
+    /// # fn foo() -> std::io::Result<()> {
+    /// let file = try!(File::create("poem.txt"));
+    /// let file = LineWriter::new(file);
+    ///
+    /// let reference = file.get_ref();
+    /// # Ok(())
+    /// # }
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn get_ref(&self) -> &W { self.inner.get_ref() }
 
@@ -449,12 +698,44 @@ pub fn get_ref(&self) -> &W { self.inner.get_ref() }
     ///
     /// Caution must be taken when calling methods on the mutable reference
     /// returned as extra writes could corrupt the output stream.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::fs::File;
+    /// use std::io::LineWriter;
+    ///
+    /// # fn foo() -> std::io::Result<()> {
+    /// let file = try!(File::create("poem.txt"));
+    /// let mut file = LineWriter::new(file);
+    ///
+    /// // we can use reference just like file
+    /// let reference = file.get_mut();
+    /// # Ok(())
+    /// # }
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn get_mut(&mut self) -> &mut W { self.inner.get_mut() }
 
     /// Unwraps this `LineWriter`, returning the underlying writer.
     ///
     /// The internal buffer is written out before returning the writer.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::fs::File;
+    /// use std::io::LineWriter;
+    ///
+    /// # fn foo() -> std::io::Result<()> {
+    /// let file = try!(File::create("poem.txt"));
+    ///
+    /// let writer: LineWriter<File> = LineWriter::new(file);
+    ///
+    /// let file: File = try!(writer.into_inner());
+    /// # Ok(())
+    /// # }
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn into_inner(self) -> Result<W, IntoInnerError<LineWriter<W>>> {
         self.inner.into_inner().map_err(|IntoInnerError(buf, e)| {
index f059b24baf6a4f74fd787559a9da9af905300fa0..4bb7d2ebd1963ef7fe1dad775895d3c9523c4a1b 100644 (file)
 use io::{self, SeekFrom, Error, ErrorKind};
 use slice;
 
-/// A `Cursor` is a type which wraps a non-I/O object to provide a `Seek`
+/// A `Cursor` wraps another type and provides it with a [`Seek`][seek]
 /// implementation.
 ///
-/// Cursors are typically used with memory buffer objects in order to allow
-/// `Seek`, `Read`, and `Write` implementations. For example, common cursor types
-/// include `Cursor<Vec<u8>>` and `Cursor<&[u8]>`.
+/// [seek]: trait.Seek.html
 ///
-/// Implementations of the I/O traits for `Cursor<T>` are currently not generic
-/// over `T` itself. Instead, specific implementations are provided for various
-/// in-memory buffer types like `Vec<u8>` and `&[u8]`.
+/// Cursors are typically used with in-memory buffers to allow them to
+/// implement `Read` and/or `Write`, allowing these buffers to be used
+/// anywhere you might use a reader or writer that does actual I/O.
+///
+/// The standard library implements some I/O traits on various types which
+/// are commonly used as a buffer, like `Cursor<Vec<u8>>` and `Cursor<&[u8]>`.
+///
+/// # Examples
+///
+/// We may want to write bytes to a [`File`][file] in our production
+/// code, but use an in-memory buffer in our tests. We can do this with
+/// `Cursor`:
+///
+/// [file]: ../fs/struct.File.html
+///
+/// ```no_run
+/// use std::io::prelude::*;
+/// use std::io::{self, SeekFrom};
+/// use std::fs::File;
+///
+/// // a library function we've written
+/// fn write_ten_bytes_at_end<W: Write + Seek>(writer: &mut W) -> io::Result<()> {
+///     try!(writer.seek(SeekFrom::End(-10)));
+///
+///     for i in 0..10 {
+///         try!(writer.write(&[i]));
+///     }
+///
+///     // all went well
+///     Ok(())
+/// }
+///
+/// # fn foo() -> io::Result<()> {
+/// // Here's some code that uses this library function.
+/// //
+/// // We might want to use a BufReader here for efficiency, but let's
+/// // keep this example focused.
+/// let mut file = try!(File::create("foo.txt"));
+///
+/// try!(write_ten_bytes_at_end(&mut file));
+/// # Ok(())
+/// # }
+///
+/// // now let's write a test
+/// #[test]
+/// fn test_writes_bytes() {
+///     // setting up a real File is much more slow than an in-memory buffer,
+///     // let's use a cursor instead
+///     use std::io::Cursor;
+///     let mut buff = Cursor::new(vec![0; 15]);
+///
+///     write_ten_bytes(&mut buff).unwrap();
+///
+///     assert_eq!(&buff.get_ref()[5..15], &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
+/// }
+/// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 #[derive(Clone, Debug)]
 pub struct Cursor<T> {
@@ -34,16 +85,50 @@ pub struct Cursor<T> {
 
 impl<T> Cursor<T> {
     /// Creates a new cursor wrapping the provided underlying I/O object.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::io::Cursor;
+    ///
+    /// let buff = Cursor::new(Vec::new());
+    /// # fn force_inference(_: &Cursor<Vec<u8>>) {}
+    /// # force_inference(&buff);
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn new(inner: T) -> Cursor<T> {
         Cursor { pos: 0, inner: inner }
     }
 
     /// Consumes this cursor, returning the underlying value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::io::Cursor;
+    ///
+    /// let buff = Cursor::new(Vec::new());
+    /// # fn force_inference(_: &Cursor<Vec<u8>>) {}
+    /// # force_inference(&buff);
+    ///
+    /// let vec = buff.into_inner();
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn into_inner(self) -> T { self.inner }
 
     /// Gets a reference to the underlying value in this cursor.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::io::Cursor;
+    ///
+    /// let buff = Cursor::new(Vec::new());
+    /// # fn force_inference(_: &Cursor<Vec<u8>>) {}
+    /// # force_inference(&buff);
+    ///
+    /// let reference = buff.get_ref();
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn get_ref(&self) -> &T { &self.inner }
 
@@ -51,14 +136,60 @@ pub fn get_ref(&self) -> &T { &self.inner }
     ///
     /// Care should be taken to avoid modifying the internal I/O state of the
     /// underlying value as it may corrupt this cursor's position.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::io::Cursor;
+    ///
+    /// let mut buff = Cursor::new(Vec::new());
+    /// # fn force_inference(_: &Cursor<Vec<u8>>) {}
+    /// # force_inference(&buff);
+    ///
+    /// let reference = buff.get_mut();
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn get_mut(&mut self) -> &mut T { &mut self.inner }
 
-    /// Returns the current value of this cursor
+    /// Returns the current position of this cursor.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::io::Cursor;
+    /// use std::io::prelude::*;
+    /// use std::io::SeekFrom;
+    ///
+    /// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]);
+    ///
+    /// assert_eq!(buff.position(), 0);
+    ///
+    /// buff.seek(SeekFrom::Current(2)).unwrap();
+    /// assert_eq!(buff.position(), 2);
+    ///
+    /// buff.seek(SeekFrom::Current(-1)).unwrap();
+    /// assert_eq!(buff.position(), 1);
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn position(&self) -> u64 { self.pos }
 
-    /// Sets the value of this cursor
+    /// Sets the position of this cursor.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::io::Cursor;
+    ///
+    /// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]);
+    ///
+    /// assert_eq!(buff.position(), 0);
+    ///
+    /// buff.set_position(2);
+    /// assert_eq!(buff.position(), 2);
+    ///
+    /// buff.set_position(4);
+    /// assert_eq!(buff.position(), 4);
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn set_position(&mut self, pos: u64) { self.pos = pos; }
 }
index 3016cfa8fe5e359c0e8247874d54aec1fd3cbbfe..fbdfdeaaef4f286bbe9aeef2ef5ca8535991778e 100644 (file)
@@ -1396,7 +1396,10 @@ fn lines(self) -> Lines<Self> where Self: Sized {
 
 /// A `Write` adaptor which will write data to multiple locations.
 ///
-/// For more information, see `Write::broadcast`.
+/// This struct is generally created by calling [`broadcast()`][broadcast] on a
+/// writer. Please see the documentation of `broadcast()` for more details.
+///
+/// [broadcast]: trait.Write.html#method.broadcast
 #[unstable(feature = "io", reason = "awaiting stability of Write::broadcast")]
 pub struct Broadcast<T, U> {
     first: T,
@@ -1417,9 +1420,12 @@ fn flush(&mut self) -> Result<()> {
     }
 }
 
-/// Adaptor to chain together two instances of `Read`.
+/// Adaptor to chain together two readers.
+///
+/// This struct is generally created by calling [`chain()`][chain] on a reader.
+/// Please see the documentation of `chain()` for more details.
 ///
-/// For more information, see `Read::chain`.
+/// [chain]: trait.Read.html#method.chain
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Chain<T, U> {
     first: T,
@@ -1442,7 +1448,10 @@ fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
 
 /// Reader adaptor which limits the bytes read from an underlying reader.
 ///
-/// For more information, see `Read::take`.
+/// This struct is generally created by calling [`take()`][take] on a reader.
+/// Please see the documentation of `take()` for more details.
+///
+/// [take]: trait.Read.html#method.take
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Take<T> {
     inner: T,
@@ -1495,7 +1504,10 @@ fn consume(&mut self, amt: usize) {
 
 /// An adaptor which will emit all read data to a specified writer as well.
 ///
-/// For more information see `Read::tee`
+/// This struct is generally created by calling [`tee()`][tee] on a reader.
+/// Please see the documentation of `tee()` for more details.
+///
+/// [tee]: trait.Read.html#method.tee
 #[unstable(feature = "io", reason = "awaiting stability of Read::tee")]
 pub struct Tee<R, W> {
     reader: R,
@@ -1512,9 +1524,12 @@ fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
     }
 }
 
-/// A bridge from implementations of `Read` to an `Iterator` of `u8`.
+/// An iterator over `u8` values of a reader.
 ///
-/// See `Read::bytes` for more information.
+/// This struct is generally created by calling [`bytes()`][bytes] on a reader.
+/// Please see the documentation of `bytes()` for more details.
+///
+/// [bytes]: trait.Read.html#method.bytes
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Bytes<R> {
     inner: R,
@@ -1534,9 +1549,12 @@ fn next(&mut self) -> Option<Result<u8>> {
     }
 }
 
-/// A bridge from implementations of `Read` to an `Iterator` of `char`.
+/// An iterator over the `char`s of a reader.
+///
+/// This struct is generally created by calling [`chars()`][chars] on a reader.
+/// Please see the documentation of `chars()` for more details.
 ///
-/// See `Read::chars` for more information.
+/// [chars]: trait.Read.html#method.chars
 #[unstable(feature = "io", reason = "awaiting stability of Read::chars")]
 pub struct Chars<R> {
     inner: R,
@@ -1618,7 +1636,10 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 /// An iterator over the contents of an instance of `BufRead` split on a
 /// particular byte.
 ///
-/// See `BufRead::split` for more information.
+/// This struct is generally created by calling [`split()`][split] on a
+/// `BufRead`. Please see the documentation of `split()` for more details.
+///
+/// [split]: trait.BufRead.html#method.split
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Split<B> {
     buf: B,
@@ -1644,10 +1665,12 @@ fn next(&mut self) -> Option<Result<Vec<u8>>> {
     }
 }
 
-/// An iterator over the lines of an instance of `BufRead` split on a newline
-/// byte.
+/// An iterator over the lines of an instance of `BufRead`.
+///
+/// This struct is generally created by calling [`lines()`][lines] on a
+/// `BufRead`. Please see the documentation of `lines()` for more details.
 ///
-/// See `BufRead::lines` for more information.
+/// [lines]: trait.BufRead.html#method.lines
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Lines<B> {
     buf: B,
index c0bced26beffafce9c5c78483aaaa3c2efaf0fe1..dc29811ed5ba11c1cdbf9b0c794bee3943ac98b7 100644 (file)
@@ -61,6 +61,11 @@ pub fn copy<R: Read, W: Write>(reader: &mut R, writer: &mut W) -> io::Result<u64
 }
 
 /// A reader which is always at EOF.
+///
+/// This struct is generally created by calling [`empty()`][empty]. Please see
+/// the documentation of `empty()` for more details.
+///
+/// [empty]: fn.empty.html
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Empty { _priv: () }
 
@@ -95,7 +100,12 @@ fn fill_buf(&mut self) -> io::Result<&[u8]> { Ok(&[]) }
     fn consume(&mut self, _n: usize) {}
 }
 
-/// A reader which infinitely yields one byte.
+/// A reader which yields one byte over and over and over and over and over and...
+///
+/// This struct is generally created by calling [`repeat()`][repeat]. Please
+/// see the documentation of `repeat()` for more details.
+///
+/// [empty]: fn.repeat.html
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Repeat { byte: u8 }
 
@@ -117,6 +127,11 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
 }
 
 /// A writer which will move data into the void.
+///
+/// This struct is generally created by calling [`sink()`][sink]. Please
+/// see the documentation of `sink()` for more details.
+///
+/// [empty]: fn.sink.html
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Sink { _priv: () }
 
index 1729d20da205c686d5763195b8988432f38a65ee..0ac0d03e19d404b87059f5e48b4167f6738aefad 100644 (file)
@@ -96,7 +96,7 @@ fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize {
         // own fault handlers if we hit it.
         sys_common::stack::record_os_managed_stack_bounds(my_stack_bottom,
                                                           my_stack_top);
-        sys::thread::guard::init();
+        let main_guard = sys::thread::guard::init();
         sys::stack_overflow::init();
 
         // Next, set up the current Thread with the guard information we just
@@ -104,7 +104,7 @@ fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize {
         // but we just do this to name the main thread and to give it correct
         // info about the stack bounds.
         let thread: Thread = NewThread::new(Some("<main>".to_string()));
-        thread_info::set(sys::thread::guard::main(), thread);
+        thread_info::set(main_guard, thread);
 
         // By default, some platforms will send a *signal* when a EPIPE error
         // would otherwise be delivered. This runtime doesn't install a SIGPIPE
index 84c6d6864a9e5d592aee14b45adf29d46daa331c..87941e79b2f7d79e6d2aa87b1454172ea9035be9 100644 (file)
@@ -8,10 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![allow(private_no_mangle_fns)]
+
 use prelude::v1::*;
 
 use any::Any;
-use libc::c_void;
 use rt::libunwind as uw;
 
 struct Exception {
@@ -41,7 +42,7 @@ pub unsafe fn panic(data: Box<Any + Send + 'static>) -> ! {
     }
 }
 
-pub unsafe fn cleanup(ptr: *mut c_void) -> Box<Any + Send + 'static> {
+pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send + 'static> {
     let my_ep = ptr as *mut Exception;
     rtdebug!("caught {}", (*my_ep).uwe.exception_class);
     let cause = (*my_ep).cause.take();
@@ -89,7 +90,7 @@ pub mod eabi {
     use rt::libunwind as uw;
     use libc::c_int;
 
-    extern "C" {
+    extern {
         fn __gcc_personality_v0(version: c_int,
                                 actions: uw::_Unwind_Action,
                                 exception_class: uw::_Unwind_Exception_Class,
@@ -98,9 +99,8 @@ fn __gcc_personality_v0(version: c_int,
             -> uw::_Unwind_Reason_Code;
     }
 
-    #[lang="eh_personality"]
-    #[no_mangle] // referenced from rust_try.ll
-    #[allow(private_no_mangle_fns)]
+    #[lang = "eh_personality"]
+    #[no_mangle]
     extern fn rust_eh_personality(
         version: c_int,
         actions: uw::_Unwind_Action,
@@ -115,8 +115,9 @@ fn __gcc_personality_v0(version: c_int,
         }
     }
 
-    #[no_mangle] // referenced from rust_try.ll
-    pub extern "C" fn rust_eh_personality_catch(
+    #[cfg_attr(not(stage0), lang = "eh_personality_catch")]
+    #[no_mangle]
+    pub extern fn rust_eh_personality_catch(
         _version: c_int,
         actions: uw::_Unwind_Action,
         _exception_class: uw::_Unwind_Exception_Class,
@@ -142,7 +143,7 @@ pub mod eabi {
     use rt::libunwind as uw;
     use libc::c_int;
 
-    extern "C" {
+    extern {
         fn __gcc_personality_sj0(version: c_int,
                                 actions: uw::_Unwind_Action,
                                 exception_class: uw::_Unwind_Exception_Class,
@@ -151,9 +152,9 @@ fn __gcc_personality_sj0(version: c_int,
             -> uw::_Unwind_Reason_Code;
     }
 
-    #[lang="eh_personality"]
-    #[no_mangle] // referenced from rust_try.ll
-    pub extern "C" fn rust_eh_personality(
+    #[lang = "eh_personality"]
+    #[no_mangle]
+    pub extern fn rust_eh_personality(
         version: c_int,
         actions: uw::_Unwind_Action,
         exception_class: uw::_Unwind_Exception_Class,
@@ -167,8 +168,9 @@ pub extern "C" fn rust_eh_personality(
         }
     }
 
-    #[no_mangle] // referenced from rust_try.ll
-    pub extern "C" fn rust_eh_personality_catch(
+    #[cfg_attr(not(stage0), lang = "eh_personality_catch")]
+    #[no_mangle]
+    pub extern fn rust_eh_personality_catch(
         _version: c_int,
         actions: uw::_Unwind_Action,
         _exception_class: uw::_Unwind_Exception_Class,
@@ -196,17 +198,16 @@ pub mod eabi {
     use rt::libunwind as uw;
     use libc::c_int;
 
-    extern "C" {
+    extern {
         fn __gcc_personality_v0(state: uw::_Unwind_State,
                                 ue_header: *mut uw::_Unwind_Exception,
                                 context: *mut uw::_Unwind_Context)
             -> uw::_Unwind_Reason_Code;
     }
 
-    #[lang="eh_personality"]
-    #[no_mangle] // referenced from rust_try.ll
-    #[allow(private_no_mangle_fns)]
-    extern "C" fn rust_eh_personality(
+    #[lang = "eh_personality"]
+    #[no_mangle]
+    extern fn rust_eh_personality(
         state: uw::_Unwind_State,
         ue_header: *mut uw::_Unwind_Exception,
         context: *mut uw::_Unwind_Context
@@ -217,8 +218,9 @@ extern "C" fn rust_eh_personality(
         }
     }
 
-    #[no_mangle] // referenced from rust_try.ll
-    pub extern "C" fn rust_eh_personality_catch(
+    #[cfg_attr(not(stage0), lang = "eh_personality_catch")]
+    #[no_mangle]
+    pub extern fn rust_eh_personality_catch(
         state: uw::_Unwind_State,
         _ue_header: *mut uw::_Unwind_Exception,
         _context: *mut uw::_Unwind_Context
@@ -266,7 +268,7 @@ pub enum EXCEPTION_DISPOSITION {
     }
 
     type _Unwind_Personality_Fn =
-        extern "C" fn(
+        extern fn(
             version: c_int,
             actions: uw::_Unwind_Action,
             exception_class: uw::_Unwind_Exception_Class,
@@ -274,7 +276,7 @@ pub enum EXCEPTION_DISPOSITION {
             context: *mut uw::_Unwind_Context
         ) -> uw::_Unwind_Reason_Code;
 
-    extern "C" {
+    extern {
         fn __gcc_personality_seh0(
             exceptionRecord: *mut EXCEPTION_RECORD,
             establisherFrame: *mut c_void,
@@ -291,10 +293,9 @@ fn _GCC_specific_handler(
         ) -> EXCEPTION_DISPOSITION;
     }
 
-    #[lang="eh_personality"]
-    #[no_mangle] // referenced from rust_try.ll
-    #[allow(private_no_mangle_fns)]
-    extern "C" fn rust_eh_personality(
+    #[lang = "eh_personality"]
+    #[no_mangle]
+    extern fn rust_eh_personality(
         exceptionRecord: *mut EXCEPTION_RECORD,
         establisherFrame: *mut c_void,
         contextRecord: *mut CONTEXT,
@@ -307,15 +308,16 @@ extern "C" fn rust_eh_personality(
         }
     }
 
-    #[no_mangle] // referenced from rust_try.ll
-    pub extern "C" fn rust_eh_personality_catch(
+    #[cfg_attr(not(stage0), lang = "eh_personality_catch")]
+    #[no_mangle]
+    pub extern fn rust_eh_personality_catch(
         exceptionRecord: *mut EXCEPTION_RECORD,
         establisherFrame: *mut c_void,
         contextRecord: *mut CONTEXT,
         dispatcherContext: *mut DISPATCHER_CONTEXT
     ) -> EXCEPTION_DISPOSITION
     {
-        extern "C" fn inner(
+        extern fn inner(
                 _version: c_int,
                 actions: uw::_Unwind_Action,
                 _exception_class: uw::_Unwind_Exception_Class,
index c403976745aa4769af0e9ad3730d0714ab572a10..db2310ba361b342d9c436f523943e7aa57beef2c 100644 (file)
@@ -69,7 +69,6 @@
 use panicking;
 use fmt;
 use intrinsics;
-use libc::c_void;
 use mem;
 use sync::atomic::{self, Ordering};
 use sys_common::mutex::Mutex;
 ///   run.
 pub unsafe fn try<F: FnOnce()>(f: F) -> Result<(), Box<Any + Send>> {
     let mut f = Some(f);
-    return inner_try(try_fn::<F>, &mut f as *mut _ as *mut c_void);
+    return inner_try(try_fn::<F>, &mut f as *mut _ as *mut u8);
 
     // If an inner function were not used here, then this generic function `try`
     // uses the native symbol `rust_try`, for which the code is statically
@@ -140,11 +139,12 @@ pub unsafe fn try<F: FnOnce()>(f: F) -> Result<(), Box<Any + Send>> {
     // `dllexport`, but it's easier to not have conditional `src/rt/rust_try.ll`
     // files and instead just have this non-generic shim the compiler can take
     // care of exposing correctly.
-    unsafe fn inner_try(f: extern fn(*mut c_void), data: *mut c_void)
+    #[cfg(not(stage0))]
+    unsafe fn inner_try(f: fn(*mut u8), data: *mut u8)
                         -> Result<(), Box<Any + Send>> {
         let prev = PANICKING.with(|s| s.get());
         PANICKING.with(|s| s.set(false));
-        let ep = rust_try(f, data);
+        let ep = intrinsics::try(f, data);
         PANICKING.with(|s| s.set(prev));
         if ep.is_null() {
             Ok(())
@@ -152,8 +152,13 @@ unsafe fn inner_try(f: extern fn(*mut c_void), data: *mut c_void)
             Err(imp::cleanup(ep))
         }
     }
+    #[cfg(stage0)]
+    unsafe fn inner_try(f: fn(*mut u8), data: *mut u8)
+                        -> Result<(), Box<Any + Send>> {
+        Ok(f(data))
+    }
 
-    extern fn try_fn<F: FnOnce()>(opt_closure: *mut c_void) {
+    fn try_fn<F: FnOnce()>(opt_closure: *mut u8) {
         let opt_closure = opt_closure as *mut Option<F>;
         unsafe { (*opt_closure).take().unwrap()(); }
     }
@@ -163,8 +168,8 @@ unsafe fn inner_try(f: extern fn(*mut c_void), data: *mut c_void)
         // When f(...) returns normally, the return value is null.
         // When f(...) throws, the return value is a pointer to the caught
         // exception object.
-        fn rust_try(f: extern fn(*mut c_void),
-                    data: *mut c_void) -> *mut c_void;
+        fn rust_try(f: extern fn(*mut u8),
+                    data: *mut u8) -> *mut u8;
     }
 }
 
index 632ab4f8e253750c23028b7d71fe2f1dabfa5ad4..ed44f9a8bda9499b0bfa7835295503afd999eb18 100644 (file)
@@ -102,7 +102,7 @@ pub unsafe fn panic(data: Box<Any + Send + 'static>) -> ! {
     rtabort!("could not unwind stack");
 }
 
-pub unsafe fn cleanup(ptr: *mut c_void) -> Box<Any + Send + 'static> {
+pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send + 'static> {
     // The `ptr` here actually corresponds to the code of the exception, and our
     // real data is stored in our thread local.
     rtassert!(ptr as DWORD == RUST_PANIC);
@@ -135,8 +135,9 @@ fn rust_eh_personality() {
 // to ensure that it's code is RUST_PANIC, which was set by the call to
 // `RaiseException` above in the `panic` function.
 #[no_mangle]
+#[lang = "msvc_try_filter"]
 pub extern fn __rust_try_filter(eh_ptrs: *mut EXCEPTION_POINTERS,
-                                _rbp: *mut c_void) -> i32 {
+                                _rbp: *mut u8) -> i32 {
     unsafe {
         ((*(*eh_ptrs).ExceptionRecord).ExceptionCode == RUST_PANIC) as i32
     }
index ae55bae37aa884e3870e7b43315f745e425a927d..bb47c946e49934bc5d0f65b14dac84cc1f4e7064 100644 (file)
@@ -18,7 +18,7 @@
 use thread::LocalKeyState;
 
 struct ThreadInfo {
-    stack_guard: usize,
+    stack_guard: Option<usize>,
     thread: Thread,
 }
 
@@ -33,7 +33,7 @@ fn with<R, F>(f: F) -> Option<R> where F: FnOnce(&mut ThreadInfo) -> R {
         THREAD_INFO.with(move |c| {
             if c.borrow().is_none() {
                 *c.borrow_mut() = Some(ThreadInfo {
-                    stack_guard: 0,
+                    stack_guard: None,
                     thread: NewThread::new(None),
                 })
             }
@@ -47,10 +47,10 @@ pub fn current_thread() -> Option<Thread> {
 }
 
 pub fn stack_guard() -> Option<usize> {
-    ThreadInfo::with(|info| info.stack_guard)
+    ThreadInfo::with(|info| info.stack_guard).and_then(|o| o)
 }
 
-pub fn set(stack_guard: usize, thread: Thread) {
+pub fn set(stack_guard: Option<usize>, thread: Thread) {
     THREAD_INFO.with(|c| assert!(c.borrow().is_none()));
     THREAD_INFO.with(move |c| *c.borrow_mut() = Some(ThreadInfo{
         stack_guard: stack_guard,
index 17804c8d81ffbbd2744e9a5edfac82a86258094e..6be61f069266f59a6d1eaec9c4c09d3d4af08141 100644 (file)
@@ -166,9 +166,10 @@ fn drop(&mut self) {
           not(target_os = "netbsd"),
           not(target_os = "openbsd")))]
 pub mod guard {
-    pub unsafe fn current() -> usize { 0 }
-    pub unsafe fn main() -> usize { 0 }
-    pub unsafe fn init() {}
+    use prelude::v1::*;
+
+    pub unsafe fn current() -> Option<usize> { None }
+    pub unsafe fn init() -> Option<usize> { None }
 }
 
 
@@ -179,6 +180,8 @@ pub unsafe fn init() {}
           target_os = "openbsd"))]
 #[allow(unused_imports)]
 pub mod guard {
+    use prelude::v1::*;
+
     use libc::{self, pthread_t};
     use libc::funcs::posix88::mman::mmap;
     use libc::consts::os::posix88::{PROT_NONE,
@@ -191,31 +194,38 @@ pub mod guard {
     use super::{pthread_self, pthread_attr_destroy};
     use sys::os;
 
-    // These are initialized in init() and only read from after
-    static mut GUARD_PAGE: usize = 0;
-
     #[cfg(any(target_os = "macos",
               target_os = "bitrig",
               target_os = "netbsd",
               target_os = "openbsd"))]
-    unsafe fn get_stack_start() -> *mut libc::c_void {
-        current() as *mut libc::c_void
+    unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
+        current().map(|s| s as *mut libc::c_void)
     }
 
     #[cfg(any(target_os = "linux", target_os = "android"))]
-    unsafe fn get_stack_start() -> *mut libc::c_void {
+    unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
+        use super::pthread_attr_init;
+
+        let mut ret = None;
         let mut attr: libc::pthread_attr_t = mem::zeroed();
-        assert_eq!(pthread_getattr_np(pthread_self(), &mut attr), 0);
-        let mut stackaddr = ptr::null_mut();
-        let mut stacksize = 0;
-        assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize), 0);
+        assert_eq!(pthread_attr_init(&mut attr), 0);
+        if pthread_getattr_np(pthread_self(), &mut attr) == 0 {
+            let mut stackaddr = ptr::null_mut();
+            let mut stacksize = 0;
+            assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr,
+                                             &mut stacksize), 0);
+            ret = Some(stackaddr);
+        }
         assert_eq!(pthread_attr_destroy(&mut attr), 0);
-        stackaddr
+        ret
     }
 
-    pub unsafe fn init() {
+    pub unsafe fn init() -> Option<usize> {
         let psize = os::page_size();
-        let mut stackaddr = get_stack_start();
+        let mut stackaddr = match get_stack_start() {
+            Some(addr) => addr,
+            None => return None,
+        };
 
         // Ensure stackaddr is page aligned! A parent process might
         // have reset RLIMIT_STACK to be non-page aligned. The
@@ -245,25 +255,21 @@ pub unsafe fn init() {
 
         let offset = if cfg!(target_os = "linux") {2} else {1};
 
-        GUARD_PAGE = stackaddr as usize + offset * psize;
-    }
-
-    pub unsafe fn main() -> usize {
-        GUARD_PAGE
+        Some(stackaddr as usize + offset * psize)
     }
 
     #[cfg(target_os = "macos")]
-    pub unsafe fn current() -> usize {
+    pub unsafe fn current() -> Option<usize> {
         extern {
             fn pthread_get_stackaddr_np(thread: pthread_t) -> *mut libc::c_void;
             fn pthread_get_stacksize_np(thread: pthread_t) -> libc::size_t;
         }
-        (pthread_get_stackaddr_np(pthread_self()) as libc::size_t -
-         pthread_get_stacksize_np(pthread_self())) as usize
+        Some((pthread_get_stackaddr_np(pthread_self()) as libc::size_t -
+              pthread_get_stacksize_np(pthread_self())) as usize)
     }
 
     #[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "bitrig"))]
-    pub unsafe fn current() -> usize {
+    pub unsafe fn current() -> Option<usize> {
         #[repr(C)]
         struct stack_t {
             ss_sp: *mut libc::c_void,
@@ -280,30 +286,36 @@ fn pthread_stackseg_np(thread: pthread_t,
         assert_eq!(pthread_stackseg_np(pthread_self(), &mut current_stack), 0);
 
         let extra = if cfg!(target_os = "bitrig") {3} else {1} * os::page_size();
-        if pthread_main_np() == 1 {
+        Some(if pthread_main_np() == 1 {
             // main thread
             current_stack.ss_sp as usize - current_stack.ss_size as usize + extra
         } else {
             // new thread
             current_stack.ss_sp as usize - current_stack.ss_size as usize
-        }
+        })
     }
 
     #[cfg(any(target_os = "linux", target_os = "android"))]
-    pub unsafe fn current() -> usize {
+    pub unsafe fn current() -> Option<usize> {
+        use super::pthread_attr_init;
+
+        let mut ret = None;
         let mut attr: libc::pthread_attr_t = mem::zeroed();
-        assert_eq!(pthread_getattr_np(pthread_self(), &mut attr), 0);
-        let mut guardsize = 0;
-        assert_eq!(pthread_attr_getguardsize(&attr, &mut guardsize), 0);
-        if guardsize == 0 {
-            panic!("there is no guard page");
+        assert_eq!(pthread_attr_init(&mut attr), 0);
+        if pthread_getattr_np(pthread_self(), &mut attr) == 0 {
+            let mut guardsize = 0;
+            assert_eq!(pthread_attr_getguardsize(&attr, &mut guardsize), 0);
+            if guardsize == 0 {
+                panic!("there is no guard page");
+            }
+            let mut stackaddr = ptr::null_mut();
+            let mut size = 0;
+            assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr, &mut size), 0);
+
+            ret = Some(stackaddr as usize + guardsize as usize);
         }
-        let mut stackaddr = ptr::null_mut();
-        let mut size = 0;
-        assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr, &mut size), 0);
         assert_eq!(pthread_attr_destroy(&mut attr), 0);
-
-        stackaddr as usize + guardsize as usize
+        return ret
     }
 
     #[cfg(any(target_os = "linux", target_os = "android"))]
index 50dfee4ab1011d6a58581404da327ac151c123d9..42805c2ac52c450bbc328d6189ac42035e15f81d 100644 (file)
@@ -86,7 +86,8 @@ pub fn sleep(dur: Duration) {
 }
 
 pub mod guard {
-    pub unsafe fn main() -> usize { 0 }
-    pub unsafe fn current() -> usize { 0 }
-    pub unsafe fn init() {}
+    use prelude::v1::*;
+
+    pub unsafe fn current() -> Option<usize> { None }
+    pub unsafe fn init() -> Option<usize> { None }
 }
index a2dbb0f8342433524f6937daede9689abfc16768..7550b7ce6c35259f434722d6e703ed631854a066 100644 (file)
@@ -231,9 +231,12 @@ unsafe fn unregister_dtor(key: Key) -> bool {
                                                         LPVOID) =
         on_tls_callback;
 
-#[cfg(target_env = "msvc")]
+#[cfg(all(target_env = "msvc", target_pointer_width = "64"))]
 #[link_args = "/INCLUDE:_tls_used"]
 extern {}
+#[cfg(all(target_env = "msvc", target_pointer_width = "32"))]
+#[link_args = "/INCLUDE:__tls_used"]
+extern {}
 
 #[allow(warnings)]
 unsafe extern "system" fn on_tls_callback(h: LPVOID,
index dbb7d3233bc39a95086ee4f5048461123af725d1..3299c848ba72404ae863f0d28ca185e825b09d9b 100644 (file)
@@ -508,9 +508,25 @@ pub fn sleep(dur: Duration) {
     imp::Thread::sleep(dur)
 }
 
-/// Blocks unless or until the current thread's token is made available (may wake spuriously).
+/// Blocks unless or until the current thread's token is made available.
 ///
-/// See the module doc for more detail.
+/// Every thread is equipped with some basic low-level blocking support, via
+/// the `park()` function and the [`unpark()`][unpark] method. These can be
+/// used as a more CPU-efficient implementation of a spinlock.
+///
+/// [unpark]: struct.Thread.html#method.unpark
+///
+/// The API is typically used by acquiring a handle to the current thread,
+/// placing that handle in a shared data structure so that other threads can
+/// find it, and then parking (in a loop with a check for the token actually
+/// being acquired).
+///
+/// A call to `park` does not guarantee that the thread will remain parked
+/// forever, and callers should be prepared for this possibility.
+///
+/// See the [module documentation][thread] for more detail.
+///
+/// [thread]: index.html
 //
 // The implementation currently uses the trivial strategy of a Mutex+Condvar
 // with wakeup flag, which does not actually allow spurious wakeups. In the
diff --git a/src/rt/rust_try.ll b/src/rt/rust_try.ll
deleted file mode 100644 (file)
index 8643131..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-; Copyright 2013 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 <LICENSE-APACHE or
-; http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-; <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-; option. This file may not be copied, modified, or distributed
-; except according to those terms.
-
-; Rust's try-catch
-; When f(...) returns normally, the return value is null.
-; When f(...) throws, the return value is a pointer to the caught exception object.
-
-; See also: libstd/rt/unwind/mod.rs
-
-define i8* @rust_try(void (i8*)* %f, i8* %env)
-    personality i8* bitcast (i32 (...)* @rust_eh_personality_catch to i8*)
-{
-
-    %1 = invoke i8* @rust_try_inner(void (i8*)* %f, i8* %env)
-        to label %normal
-        unwind label %catch
-
-normal:
-    ret i8* %1
-
-catch:
-    landingpad { i8*, i32 } catch i8* null
-    ; rust_try_inner's landing pad does not resume unwinds, so execution will
-    ; never reach here
-    ret i8* null
-}
-
-define internal i8* @rust_try_inner(void (i8*)* %f, i8* %env)
-    personality i8* bitcast (i32 (...)* @rust_eh_personality to i8*)
-{
-
-    invoke void %f(i8* %env)
-        to label %normal
-        unwind label %catch
-
-normal:
-    ret i8* null
-
-catch:
-    %1 = landingpad { i8*, i32 } catch i8* null
-    ; extract and return pointer to the exception object
-    %2 = extractvalue { i8*, i32 } %1, 0
-    ret i8* %2
-}
-
-declare i32 @rust_eh_personality(...)
-declare i32 @rust_eh_personality_catch(...)
diff --git a/src/rt/rust_try_msvc_32.ll b/src/rt/rust_try_msvc_32.ll
deleted file mode 100644 (file)
index bdee53b..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-; 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 <LICENSE-APACHE or
-; http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-; <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-; option. This file may not be copied, modified, or distributed
-; except according to those terms.
-
-; For more comments about what's going on here see rust_try_msvc_64.ll. The only
-; difference between that and this file is the personality function used as it's
-; different for 32-bit MSVC than it is for 64-bit.
-
-define i8* @rust_try(void (i8*)* %f, i8* %env)
-    personality i8* bitcast (i32 (...)* @_except_handler3 to i8*)
-{
-    invoke void %f(i8* %env)
-        to label %normal
-        unwind label %catch
-
-normal:
-    ret i8* null
-catch:
-    %vals = landingpad { i8*, i32 }
-              catch i8* bitcast (i32 (i8*, i8*)* @__rust_try_filter to i8*)
-    %ehptr = extractvalue { i8*, i32 } %vals, 0
-    %sel = extractvalue { i8*, i32 } %vals, 1
-    %filter_sel = call i32 @llvm.eh.typeid.for(i8* bitcast (i32 (i8*, i8*)* @__rust_try_filter to i8*))
-    %is_filter = icmp eq i32 %sel, %filter_sel
-    br i1 %is_filter, label %catch-return, label %catch-resume
-
-catch-return:
-    ret i8* %ehptr
-
-catch-resume:
-    resume { i8*, i32 } %vals
-}
-
-declare i32 @_except_handler3(...)
-declare i32 @__rust_try_filter(i8*, i8*)
-declare i32 @llvm.eh.typeid.for(i8*) readnone nounwind
diff --git a/src/rt/rust_try_msvc_64.ll b/src/rt/rust_try_msvc_64.ll
deleted file mode 100644 (file)
index c38e608..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-; 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 <LICENSE-APACHE or
-; http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-; <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-; option. This file may not be copied, modified, or distributed
-; except according to those terms.
-
-; 64-bit MSVC's definition of the `rust_try` function. This function can't be
-; defined in Rust as it's a "try-catch" block that's not expressible in Rust's
-; syntax, so we're using LLVM to produce an object file with the associated
-; handler.
-;
-; To use the correct system implementation details, this file is separate from
-; the standard rust_try.ll as we need specifically use the __C_specific_handler
-; personality function or otherwise LLVM doesn't emit SEH handling tables.
-; There's also a few fiddly bits about SEH right now in LLVM that require us to
-; structure this a fairly particular way!
-;
-; See also: src/libstd/rt/unwind/seh.rs
-
-define i8* @rust_try(void (i8*)* %f, i8* %env)
-    personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
-{
-    invoke void %f(i8* %env)
-        to label %normal
-        unwind label %catch
-
-normal:
-    ret i8* null
-
-; Here's where most of the magic happens, this is the only landing pad in rust
-; tagged with "catch" to indicate that we're catching an exception. The other
-; catch handlers in rust_try.ll just catch *all* exceptions, but that's because
-; most exceptions are already filtered out by their personality function.
-;
-; For MSVC we're just using a standard personality function that we can't
-; customize, so we need to do the exception filtering ourselves, and this is
-; currently performed by the `__rust_try_filter` function. This function,
-; specified in the landingpad instruction, will be invoked by Windows SEH
-; routines and will return whether the exception in question can be caught (aka
-; the Rust runtime is the one that threw the exception).
-;
-; To get this to compile (currently LLVM segfaults if it's not in this
-; particular structure), when the landingpad is executing we test to make sure
-; that the ID of the exception being thrown is indeed the one that we were
-; expecting. If it's not, we resume the exception, and otherwise we return the
-; pointer that we got
-;
-; Full disclosure: It's not clear to me what this `llvm.eh.typeid` stuff is
-; doing *other* then just allowing LLVM to compile this file without
-; segfaulting. I would expect the entire landing pad to just be:
-;
-;     %vals = landingpad ...
-;     %ehptr = extractvalue { i8*, i32 } %vals, 0
-;     ret i8* %ehptr
-;
-; but apparently LLVM chokes on this, so we do the more complicated thing to
-; placate it.
-catch:
-    %vals = landingpad { i8*, i32 }
-              catch i8* bitcast (i32 (i8*, i8*)* @__rust_try_filter to i8*)
-    %ehptr = extractvalue { i8*, i32 } %vals, 0
-    %sel = extractvalue { i8*, i32 } %vals, 1
-    %filter_sel = call i32 @llvm.eh.typeid.for(i8* bitcast (i32 (i8*, i8*)* @__rust_try_filter to i8*))
-    %is_filter = icmp eq i32 %sel, %filter_sel
-    br i1 %is_filter, label %catch-return, label %catch-resume
-
-catch-return:
-    ret i8* %ehptr
-
-catch-resume:
-    resume { i8*, i32 } %vals
-}
-
-declare i32 @__C_specific_handler(...)
-declare i32 @__rust_try_filter(i8*, i8*)
-declare i32 @llvm.eh.typeid.for(i8*) readnone nounwind
index 163e95b890f4b25ab2a513a9d3774cd98e679fbc..5007af0e777b84bc080f71ebb74cf9945edb1895 100644 (file)
@@ -120,7 +120,8 @@ extern "C" void LLVMAddDereferenceableCallSiteAttr(LLVMValueRef Instr, unsigned
                                                          idx, B)));
 }
 
-extern "C" void LLVMAddFunctionAttribute(LLVMValueRef Fn, unsigned index, uint64_t Val) {
+extern "C" void LLVMAddFunctionAttribute(LLVMValueRef Fn, unsigned index,
+                                         uint64_t Val) {
   Function *A = unwrap<Function>(Fn);
   AttrBuilder B;
   B.addRawValue(Val);
index 1b2613d8c5045f21c655da2af1a5ac900bbdd71c..cb5790b34f4d365f6ae6a4b51a4493d5ec544189 100644 (file)
@@ -1,3 +1,11 @@
+S 2015-07-17 d4432b3
+  linux-i386 93f6216a35d3bed3cedf244c9aff4cd716336bd9
+  linux-x86_64 d8f4967fc71a153c925faecf95a7feadf7e463a4
+  macos-i386 29852c4d4b5a851f16d627856a279cae5bf9bd01
+  macos-x86_64 1a20259899321062a0325edb1d22990f05d18708
+  winnt-i386 df50210f41db9a6f2968be5773b8e3bae32bb823
+  winnt-x86_64 d7774b724988485652781a804bdf8e05d28ead48
+
 S 2015-05-24 ba0e1cd
   bitrig-x86_64 2a710e16e3e3ef3760df1f724d66b3af34c1ef3f
   freebsd-x86_64 370db40613f5c08563ed7e38357826dd42d4e0f8
diff --git a/src/test/compile-fail/issue-20162.rs b/src/test/compile-fail/issue-20162.rs
new file mode 100644 (file)
index 0000000..d3a8768
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct X { x: i32 }
+
+fn main() {
+    let mut b: Vec<X> = vec![];
+    b.sort();
+    //~^ ERROR the trait `core::cmp::Ord` is not implemented for the type `X`
+}
index ec258449cb161a72c1154e80c388316cf9473d5a..30fd2eb4d2f9aeb6cfa527f04d3e5c2150b41adc 100644 (file)
@@ -15,7 +15,7 @@ trait Trait<'a> {
 
 fn foo<'a, T: Trait<'a>>(value: T::A) {
     let new: T::B = unsafe { std::mem::transmute(value) };
-//~^ ERROR: cannot transmute to or from a type that contains type parameters in its interior [E0139]
+//~^ ERROR: cannot transmute to or from a type that contains unsubstituted type parameters [E0139]
 }
 
 fn main() { }
index 5867bc2f09deb273967b0c986178d108acfb0bf2..160551b81cb2edfdbaa819424ad7bd07805df760 100644 (file)
@@ -8,11 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(negate_unsigned)]
 #![deny(exceeding_bitshifts)]
 #![allow(unused_variables)]
 #![allow(dead_code)]
-#![feature(num_bits_bytes, negate_unsigned)]
+#![feature(num_bits_bytes)]
 
 fn main() {
       let n = 1u8 << 7;
@@ -60,4 +59,7 @@ fn main() {
 
       let n = 1_isize << std::isize::BITS; //~ ERROR: bitshift exceeds the type's number of bits
       let n = 1_usize << std::usize::BITS; //~ ERROR: bitshift exceeds the type's number of bits
+
+
+      let n = 1i8<<(1isize+-1);
 }
diff --git a/src/test/compile-fail/match-range-fail-2.rs b/src/test/compile-fail/match-range-fail-2.rs
new file mode 100644 (file)
index 0000000..e30f783
--- /dev/null
@@ -0,0 +1,23 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+    match 5 {
+        6 ... 1 => { }
+        _ => { }
+    };
+    //~^^^ ERROR lower range bound must be less than or equal to upper
+
+    match 5u64 {
+        0xFFFF_FFFF_FFFF_FFFF ... 1 => { }
+        _ => { }
+    };
+    //~^^^ ERROR lower range bound must be less than or equal to upper
+}
index 234b74f76d1e05eb39916d06434236140aca929e..05b870b8f41ccef1fa017f000e299055f293521f 100644 (file)
@@ -9,12 +9,6 @@
 // except according to those terms.
 
 fn main() {
-    match 5 {
-        6 ... 1 => { }
-        _ => { }
-    };
-    //~^^^ ERROR lower range bound must be less than or equal to upper
-
     match "wow" {
         "bar" ... "foo" => { }
     };
index 121581412202cdc882e168f51372689d7803408e..7a0623ba44f0240c2713d3dd644ffa5917ad6d77 100644 (file)
 
 fn main() {
     let n = 1;
-    let a = [0; n]; //~ ERROR expected constant integer for repeat count, found variable
+    let a = [0; n];
+    //~^ ERROR expected constant integer for repeat count, found variable [E0307]
     let b = [0; ()];
-//~^ ERROR mismatched types
-//~| expected `usize`
-//~| found `()`
-//~| expected usize
-//~| found ()
-//~| ERROR expected positive integer for repeat count, found tuple
+    //~^ ERROR mismatched types
+    //~| expected `usize`
+    //~| found `()`
+    //~| expected usize
+    //~| found ()) [E0308]
+    //~| ERROR expected positive integer for repeat count, found tuple [E0306]
     let c = [0; true];
     //~^ ERROR mismatched types
     //~| expected `usize`
     //~| found `bool`
     //~| expected usize
-    //~| found bool
-    //~| ERROR expected positive integer for repeat count, found boolean
+    //~| found bool) [E0308]
+    //~| ERROR expected positive integer for repeat count, found boolean [E0306]
     let d = [0; 0.5];
     //~^ ERROR mismatched types
     //~| expected `usize`
     //~| found `_`
     //~| expected usize
-    //~| found floating-point variable
-    //~| ERROR expected positive integer for repeat count, found float
+    //~| found floating-point variable) [E0308]
+    //~| ERROR expected positive integer for repeat count, found float [E0306]
     let e = [0; "foo"];
     //~^ ERROR mismatched types
     //~| expected `usize`
     //~| found `&'static str`
     //~| expected usize
-    //~| found &-ptr
-    //~| ERROR expected positive integer for repeat count, found string
+    //~| found &-ptr) [E0308]
+    //~| ERROR expected positive integer for repeat count, found string literal [E0306]
     let f = [0; -4_isize];
     //~^ ERROR mismatched types
     //~| expected `usize`
     //~| found `isize`
     //~| expected usize
-    //~| found isize
-    //~| ERROR expected positive integer for repeat count, found negative integer
+    //~| found isize) [E0308]
+    //~| ERROR expected positive integer for repeat count, found negative integer [E0306]
     let f = [0_usize; -1_isize];
     //~^ ERROR mismatched types
     //~| expected `usize`
     //~| found `isize`
     //~| expected usize
-    //~| found isize
-    //~| ERROR expected positive integer for repeat count, found negative integer
+    //~| found isize) [E0308]
+    //~| ERROR expected positive integer for repeat count, found negative integer [E0306]
+    struct G {
+        g: (),
+    }
+    let g = [0; G { g: () }];
+    //~^ ERROR mismatched types
+    //~| expected `usize`
+    //~| found `main::G`
+    //~| expected usize
+    //~| found struct `main::G`) [E0308]
+    //~| ERROR expected positive integer for repeat count, found struct [E0306]
 }
diff --git a/src/test/run-pass/dropck_legal_cycles.rs b/src/test/run-pass/dropck_legal_cycles.rs
new file mode 100644 (file)
index 0000000..b4f9b3f
--- /dev/null
@@ -0,0 +1,759 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This test exercises cases where cyclic structure is legal,
+// including when the cycles go through data-structures such
+// as `Vec` or `TypedArena`.
+//
+// The intent is to cover as many such cases as possible, ensuring
+// that if the compiler did not complain circa Rust 1.x (1.2 as of
+// this writing), then it will continue to not complain in the future.
+//
+// Note that while some of the tests are only exercising using the
+// given collection as a "backing store" for a set of nodes that hold
+// the actual cycle (and thus the cycle does not go through the
+// collection itself in such cases), in general we *do* want to make
+// sure to have at least one example exercising a cycle that goes
+// through the collection, for every collection type that supports
+// this.
+
+#![feature(vecmap)]
+
+use std::cell::Cell;
+use std::cmp::Ordering;
+use std::collections::BinaryHeap;
+use std::collections::HashMap;
+use std::collections::LinkedList;
+use std::collections::VecDeque;
+use std::collections::VecMap;
+use std::collections::btree_map::BTreeMap;
+use std::collections::btree_set::BTreeSet;
+use std::hash::{Hash, Hasher};
+
+const PRINT: bool = false;
+
+pub fn main() {
+    let c_orig = ContextData {
+        curr_depth: 0,
+        max_depth: 3,
+        visited: 0,
+        max_visits: 1000,
+        skipped: 0,
+        curr_mark: 0,
+        saw_prev_marked: false,
+    };
+
+    // Cycle 1: { v[0] -> v[1], v[1] -> v[0] };
+    // does not exercise `v` itself
+    let v: Vec<S> = vec![Named::new("s0"),
+                         Named::new("s1")];
+    v[0].next.set(Some(&v[1]));
+    v[1].next.set(Some(&v[0]));
+
+    let mut c = c_orig.clone();
+    c.curr_mark = 10;
+    assert!(!c.saw_prev_marked);
+    v[0].for_each_child(&mut c);
+    assert!(c.saw_prev_marked);
+
+    if PRINT { println!(""); }
+
+    // Cycle 2: { v[0] -> v, v[1] -> v }
+    let v: V = Named::new("v");
+    v.contents[0].set(Some(&v));
+    v.contents[1].set(Some(&v));
+
+    let mut c = c_orig.clone();
+    c.curr_mark = 20;
+    assert!(!c.saw_prev_marked);
+    v.for_each_child(&mut c);
+    assert!(c.saw_prev_marked);
+
+    if PRINT { println!(""); }
+
+    // Cycle 3: { hk0 -> hv0, hv0 -> hk0, hk1 -> hv1, hv1 -> hk1 };
+    // does not exercise `h` itself
+
+    let mut h: HashMap<H,H> = HashMap::new();
+    h.insert(Named::new("hk0"), Named::new("hv0"));
+    h.insert(Named::new("hk1"), Named::new("hv1"));
+    for (key, val) in h.iter() {
+        val.next.set(Some(key));
+        key.next.set(Some(val));
+    }
+
+    let mut c = c_orig.clone();
+    c.curr_mark = 30;
+    for (key, _) in h.iter() {
+        c.curr_mark += 1;
+        c.saw_prev_marked = false;
+        key.for_each_child(&mut c);
+        assert!(c.saw_prev_marked);
+    }
+
+    if PRINT { println!(""); }
+
+    // Cycle 4: { h -> (hmk0,hmv0,hmk1,hmv1), {hmk0,hmv0,hmk1,hmv1} -> h }
+
+    let mut h: HashMap<HM,HM> = HashMap::new();
+    h.insert(Named::new("hmk0"), Named::new("hmv0"));
+    h.insert(Named::new("hmk0"), Named::new("hmv0"));
+    for (key, val) in h.iter() {
+        val.contents.set(Some(&h));
+        key.contents.set(Some(&h));
+    }
+
+    let mut c = c_orig.clone();
+    c.max_depth = 2;
+    c.curr_mark = 40;
+    for (key, _) in h.iter() {
+        c.curr_mark += 1;
+        c.saw_prev_marked = false;
+        key.for_each_child(&mut c);
+        assert!(c.saw_prev_marked);
+        // break;
+    }
+
+    if PRINT { println!(""); }
+
+    // Cycle 5: { vd[0] -> vd[1], vd[1] -> vd[0] };
+    // does not exercise vd itself
+    let mut vd: VecDeque<S> = VecDeque::new();
+    vd.push_back(Named::new("d0"));
+    vd.push_back(Named::new("d1"));
+    vd[0].next.set(Some(&vd[1]));
+    vd[1].next.set(Some(&vd[0]));
+
+    let mut c = c_orig.clone();
+    c.curr_mark = 50;
+    assert!(!c.saw_prev_marked);
+    vd[0].for_each_child(&mut c);
+    assert!(c.saw_prev_marked);
+
+    if PRINT { println!(""); }
+
+    // Cycle 6: { vd -> (vd0, vd1), {vd0, vd1} -> vd }
+    let mut vd: VecDeque<VD> = VecDeque::new();
+    vd.push_back(Named::new("vd0"));
+    vd.push_back(Named::new("vd1"));
+    vd[0].contents.set(Some(&vd));
+    vd[1].contents.set(Some(&vd));
+
+    let mut c = c_orig.clone();
+    c.curr_mark = 60;
+    assert!(!c.saw_prev_marked);
+    vd[0].for_each_child(&mut c);
+    assert!(c.saw_prev_marked);
+
+    if PRINT { println!(""); }
+
+    // Cycle 7: { vm -> (vm0, vm1), {vm0, vm1} -> vm }
+    let mut vm: VecMap<VM> = VecMap::new();
+    vm.insert(0, Named::new("vm0"));
+    vm.insert(1, Named::new("vm1"));
+    vm[0].contents.set(Some(&vm));
+    vm[1].contents.set(Some(&vm));
+
+    let mut c = c_orig.clone();
+    c.curr_mark = 70;
+    assert!(!c.saw_prev_marked);
+    vm[0].for_each_child(&mut c);
+    assert!(c.saw_prev_marked);
+
+    if PRINT { println!(""); }
+
+    // Cycle 8: { ll -> (ll0, ll1), {ll0, ll1} -> ll }
+    let mut ll: LinkedList<LL> = LinkedList::new();
+    ll.push_back(Named::new("ll0"));
+    ll.push_back(Named::new("ll1"));
+    for e in &ll {
+        e.contents.set(Some(&ll));
+    }
+
+    let mut c = c_orig.clone();
+    c.curr_mark = 80;
+    for e in &ll {
+        c.curr_mark += 1;
+        c.saw_prev_marked = false;
+        e.for_each_child(&mut c);
+        assert!(c.saw_prev_marked);
+        // break;
+    }
+
+    if PRINT { println!(""); }
+
+    // Cycle 9: { bh -> (bh0, bh1), {bh0, bh1} -> bh }
+    let mut bh: BinaryHeap<BH> = BinaryHeap::new();
+    bh.push(Named::new("bh0"));
+    bh.push(Named::new("bh1"));
+    for b in bh.iter() {
+        b.contents.set(Some(&bh));
+    }
+
+    let mut c = c_orig.clone();
+    c.curr_mark = 90;
+    for b in &bh {
+        c.curr_mark += 1;
+        c.saw_prev_marked = false;
+        b.for_each_child(&mut c);
+        assert!(c.saw_prev_marked);
+        // break;
+    }
+
+    if PRINT { println!(""); }
+
+    // Cycle 10: { btm -> (btk0, btv1), {bt0, bt1} -> btm }
+    let mut btm: BTreeMap<BTM, BTM> = BTreeMap::new();
+    btm.insert(Named::new("btk0"), Named::new("btv0"));
+    btm.insert(Named::new("btk1"), Named::new("btv1"));
+    for (k, v) in btm.iter() {
+        k.contents.set(Some(&btm));
+        v.contents.set(Some(&btm));
+    }
+
+    let mut c = c_orig.clone();
+    c.curr_mark = 100;
+    for (k, _) in &btm {
+        c.curr_mark += 1;
+        c.saw_prev_marked = false;
+        k.for_each_child(&mut c);
+        assert!(c.saw_prev_marked);
+        // break;
+    }
+
+    if PRINT { println!(""); }
+
+    // Cycle 10: { bts -> (bts0, bts1), {bts0, bts1} -> btm }
+    let mut bts: BTreeSet<BTS> = BTreeSet::new();
+    bts.insert(Named::new("bts0"));
+    bts.insert(Named::new("bts1"));
+    for v in bts.iter() {
+        v.contents.set(Some(&bts));
+    }
+
+    let mut c = c_orig.clone();
+    c.curr_mark = 100;
+    for b in &bts {
+        c.curr_mark += 1;
+        c.saw_prev_marked = false;
+        b.for_each_child(&mut c);
+        assert!(c.saw_prev_marked);
+        // break;
+    }
+}
+
+trait Named {
+    fn new(&'static str) -> Self;
+    fn name(&self) -> &str;
+}
+
+trait Marked<M> {
+    fn mark(&self) -> M;
+    fn set_mark(&self, mark: M);
+}
+
+struct S<'a> {
+    name: &'static str,
+    mark: Cell<u32>,
+    next: Cell<Option<&'a S<'a>>>,
+}
+
+impl<'a> Named for S<'a> {
+    fn new<'b>(name: &'static str) -> S<'b> {
+        S { name: name, mark: Cell::new(0), next: Cell::new(None) }
+    }
+    fn name(&self) -> &str { self.name }
+}
+
+impl<'a> Marked<u32> for S<'a> {
+    fn mark(&self) -> u32 { self.mark.get() }
+    fn set_mark(&self, mark: u32) { self.mark.set(mark); }
+}
+
+struct V<'a> {
+    name: &'static str,
+    mark: Cell<u32>,
+    contents: Vec<Cell<Option<&'a V<'a>>>>,
+}
+
+impl<'a> Named for V<'a> {
+    fn new<'b>(name: &'static str) -> V<'b> {
+        V { name: name,
+            mark: Cell::new(0),
+            contents: vec![Cell::new(None), Cell::new(None)]
+        }
+    }
+    fn name(&self) -> &str { self.name }
+}
+
+impl<'a> Marked<u32> for V<'a> {
+    fn mark(&self) -> u32 { self.mark.get() }
+    fn set_mark(&self, mark: u32) { self.mark.set(mark); }
+}
+
+#[derive(Eq)]
+struct H<'a> {
+    name: &'static str,
+    mark: Cell<u32>,
+    next: Cell<Option<&'a H<'a>>>,
+}
+
+impl<'a> Named for H<'a> {
+    fn new<'b>(name: &'static str) -> H<'b> {
+        H { name: name, mark: Cell::new(0), next: Cell::new(None) }
+    }
+    fn name(&self) -> &str { self.name }
+}
+
+impl<'a> Marked<u32> for H<'a> {
+    fn mark(&self) -> u32 { self.mark.get() }
+    fn set_mark(&self, mark: u32) { self.mark.set(mark); }
+}
+
+impl<'a> PartialEq for H<'a> {
+    fn eq(&self, rhs: &H<'a>) -> bool {
+        self.name == rhs.name
+    }
+}
+
+impl<'a> Hash for H<'a> {
+    fn hash<H: Hasher>(&self, state: &mut H) {
+        self.name.hash(state)
+    }
+}
+
+#[derive(Eq)]
+struct HM<'a> {
+    name: &'static str,
+    mark: Cell<u32>,
+    contents: Cell<Option<&'a HashMap<HM<'a>, HM<'a>>>>,
+}
+
+impl<'a> Named for HM<'a> {
+    fn new<'b>(name: &'static str) -> HM<'b> {
+        HM { name: name,
+             mark: Cell::new(0),
+             contents: Cell::new(None)
+        }
+    }
+    fn name(&self) -> &str { self.name }
+}
+
+impl<'a> Marked<u32> for HM<'a> {
+    fn mark(&self) -> u32 { self.mark.get() }
+    fn set_mark(&self, mark: u32) { self.mark.set(mark); }
+}
+
+impl<'a> PartialEq for HM<'a> {
+    fn eq(&self, rhs: &HM<'a>) -> bool {
+        self.name == rhs.name
+    }
+}
+
+impl<'a> Hash for HM<'a> {
+    fn hash<H: Hasher>(&self, state: &mut H) {
+        self.name.hash(state)
+    }
+}
+
+
+struct VD<'a> {
+    name: &'static str,
+    mark: Cell<u32>,
+    contents: Cell<Option<&'a VecDeque<VD<'a>>>>,
+}
+
+impl<'a> Named for VD<'a> {
+    fn new<'b>(name: &'static str) -> VD<'b> {
+        VD { name: name,
+             mark: Cell::new(0),
+             contents: Cell::new(None)
+        }
+    }
+    fn name(&self) -> &str { self.name }
+}
+
+impl<'a> Marked<u32> for VD<'a> {
+    fn mark(&self) -> u32 { self.mark.get() }
+    fn set_mark(&self, mark: u32) { self.mark.set(mark); }
+}
+
+struct VM<'a> {
+    name: &'static str,
+    mark: Cell<u32>,
+    contents: Cell<Option<&'a VecMap<VM<'a>>>>,
+}
+
+impl<'a> Named for VM<'a> {
+    fn new<'b>(name: &'static str) -> VM<'b> {
+        VM { name: name,
+             mark: Cell::new(0),
+             contents: Cell::new(None)
+        }
+    }
+    fn name(&self) -> &str { self.name }
+}
+
+impl<'a> Marked<u32> for VM<'a> {
+    fn mark(&self) -> u32 { self.mark.get() }
+    fn set_mark(&self, mark: u32) { self.mark.set(mark); }
+}
+
+struct LL<'a> {
+    name: &'static str,
+    mark: Cell<u32>,
+    contents: Cell<Option<&'a LinkedList<LL<'a>>>>,
+}
+
+impl<'a> Named for LL<'a> {
+    fn new<'b>(name: &'static str) -> LL<'b> {
+        LL { name: name,
+             mark: Cell::new(0),
+             contents: Cell::new(None)
+        }
+    }
+    fn name(&self) -> &str { self.name }
+}
+
+impl<'a> Marked<u32> for LL<'a> {
+    fn mark(&self) -> u32 { self.mark.get() }
+    fn set_mark(&self, mark: u32) { self.mark.set(mark); }
+}
+
+struct BH<'a> {
+    name: &'static str,
+    mark: Cell<u32>,
+    contents: Cell<Option<&'a BinaryHeap<BH<'a>>>>,
+}
+
+impl<'a> Named for BH<'a> {
+    fn new<'b>(name: &'static str) -> BH<'b> {
+        BH { name: name,
+             mark: Cell::new(0),
+             contents: Cell::new(None)
+        }
+    }
+    fn name(&self) -> &str { self.name }
+}
+
+impl<'a> Marked<u32> for BH<'a> {
+    fn mark(&self) -> u32 { self.mark.get() }
+    fn set_mark(&self, mark: u32) { self.mark.set(mark); }
+}
+
+impl<'a> Eq for BH<'a> { }
+
+impl<'a> PartialEq for BH<'a> {
+    fn eq(&self, rhs: &BH<'a>) -> bool {
+        self.name == rhs.name
+    }
+}
+
+impl<'a> PartialOrd for BH<'a> {
+    fn partial_cmp(&self, rhs: &BH<'a>) -> Option<Ordering> {
+        Some(self.cmp(rhs))
+    }
+}
+
+impl<'a> Ord for BH<'a> {
+    fn cmp(&self, rhs: &BH<'a>) -> Ordering {
+        self.name.cmp(rhs.name)
+    }
+}
+
+struct BTM<'a> {
+    name: &'static str,
+    mark: Cell<u32>,
+    contents: Cell<Option<&'a BTreeMap<BTM<'a>, BTM<'a>>>>,
+}
+
+impl<'a> Named for BTM<'a> {
+    fn new<'b>(name: &'static str) -> BTM<'b> {
+        BTM { name: name,
+             mark: Cell::new(0),
+             contents: Cell::new(None)
+        }
+    }
+    fn name(&self) -> &str { self.name }
+}
+
+impl<'a> Marked<u32> for BTM<'a> {
+    fn mark(&self) -> u32 { self.mark.get() }
+    fn set_mark(&self, mark: u32) { self.mark.set(mark); }
+}
+
+impl<'a> Eq for BTM<'a> { }
+
+impl<'a> PartialEq for BTM<'a> {
+    fn eq(&self, rhs: &BTM<'a>) -> bool {
+        self.name == rhs.name
+    }
+}
+
+impl<'a> PartialOrd for BTM<'a> {
+    fn partial_cmp(&self, rhs: &BTM<'a>) -> Option<Ordering> {
+        Some(self.cmp(rhs))
+    }
+}
+
+impl<'a> Ord for BTM<'a> {
+    fn cmp(&self, rhs: &BTM<'a>) -> Ordering {
+        self.name.cmp(rhs.name)
+    }
+}
+
+struct BTS<'a> {
+    name: &'static str,
+    mark: Cell<u32>,
+    contents: Cell<Option<&'a BTreeSet<BTS<'a>>>>,
+}
+
+impl<'a> Named for BTS<'a> {
+    fn new<'b>(name: &'static str) -> BTS<'b> {
+        BTS { name: name,
+             mark: Cell::new(0),
+             contents: Cell::new(None)
+        }
+    }
+    fn name(&self) -> &str { self.name }
+}
+
+impl<'a> Marked<u32> for BTS<'a> {
+    fn mark(&self) -> u32 { self.mark.get() }
+    fn set_mark(&self, mark: u32) { self.mark.set(mark); }
+}
+
+impl<'a> Eq for BTS<'a> { }
+
+impl<'a> PartialEq for BTS<'a> {
+    fn eq(&self, rhs: &BTS<'a>) -> bool {
+        self.name == rhs.name
+    }
+}
+
+impl<'a> PartialOrd for BTS<'a> {
+    fn partial_cmp(&self, rhs: &BTS<'a>) -> Option<Ordering> {
+        Some(self.cmp(rhs))
+    }
+}
+
+impl<'a> Ord for BTS<'a> {
+    fn cmp(&self, rhs: &BTS<'a>) -> Ordering {
+        self.name.cmp(rhs.name)
+    }
+}
+
+
+trait Context {
+    fn should_act(&self) -> bool;
+    fn increase_visited(&mut self);
+    fn increase_skipped(&mut self);
+    fn increase_depth(&mut self);
+    fn decrease_depth(&mut self);
+}
+
+trait PrePost<T> {
+    fn pre(&mut self, &T);
+    fn post(&mut self, &T);
+    fn hit_limit(&mut self, &T);
+}
+
+trait Children<'a> {
+    fn for_each_child<C>(&self, context: &mut C)
+        where C: Context + PrePost<Self>, Self: Sized;
+
+    fn descend_into_self<C>(&self, context: &mut C)
+        where C: Context + PrePost<Self>, Self: Sized
+    {
+        context.pre(self);
+        if context.should_act() {
+            context.increase_visited();
+            context.increase_depth();
+            self.for_each_child(context);
+            context.decrease_depth();
+        } else {
+            context.hit_limit(self);
+            context.increase_skipped();
+        }
+        context.post(self);
+    }
+
+    fn descend<'b, C>(&self, c: &Cell<Option<&'b Self>>, context: &mut C)
+        where C: Context + PrePost<Self>, Self: Sized
+    {
+        if let Some(r) = c.get() {
+            r.descend_into_self(context);
+        }
+    }
+}
+
+impl<'a> Children<'a> for S<'a> {
+    fn for_each_child<C>(&self, context: &mut C)
+        where C: Context + PrePost<S<'a>>
+    {
+        self.descend(&self.next, context);
+    }
+}
+
+impl<'a> Children<'a> for V<'a> {
+    fn for_each_child<C>(&self, context: &mut C)
+        where C: Context + PrePost<V<'a>>
+    {
+        for r in &self.contents {
+            self.descend(r, context);
+        }
+    }
+}
+
+impl<'a> Children<'a> for H<'a> {
+    fn for_each_child<C>(&self, context: &mut C)
+        where C: Context + PrePost<H<'a>>
+    {
+        self.descend(&self.next, context);
+    }
+}
+
+impl<'a> Children<'a> for HM<'a> {
+    fn for_each_child<C>(&self, context: &mut C)
+        where C: Context + PrePost<HM<'a>>
+    {
+        if let Some(ref hm) = self.contents.get() {
+            for (k, v) in hm.iter() {
+                for r in &[k, v] {
+                    r.descend_into_self(context);
+                }
+            }
+        }
+    }
+}
+
+impl<'a> Children<'a> for VD<'a> {
+    fn for_each_child<C>(&self, context: &mut C)
+        where C: Context + PrePost<VD<'a>>
+    {
+        if let Some(ref vd) = self.contents.get() {
+            for r in vd.iter() {
+                r.descend_into_self(context);
+            }
+        }
+    }
+}
+
+impl<'a> Children<'a> for VM<'a> {
+    fn for_each_child<C>(&self, context: &mut C)
+        where C: Context + PrePost<VM<'a>>
+    {
+        if let Some(ref vd) = self.contents.get() {
+            for (_idx, r) in vd.iter() {
+                r.descend_into_self(context);
+            }
+        }
+    }
+}
+
+impl<'a> Children<'a> for LL<'a> {
+    fn for_each_child<C>(&self, context: &mut C)
+        where C: Context + PrePost<LL<'a>>
+    {
+        if let Some(ref ll) = self.contents.get() {
+            for r in ll.iter() {
+                r.descend_into_self(context);
+            }
+        }
+    }
+}
+
+impl<'a> Children<'a> for BH<'a> {
+    fn for_each_child<C>(&self, context: &mut C)
+        where C: Context + PrePost<BH<'a>>
+    {
+        if let Some(ref bh) = self.contents.get() {
+            for r in bh.iter() {
+                r.descend_into_self(context);
+            }
+        }
+    }
+}
+
+impl<'a> Children<'a> for BTM<'a> {
+    fn for_each_child<C>(&self, context: &mut C)
+        where C: Context + PrePost<BTM<'a>>
+    {
+        if let Some(ref bh) = self.contents.get() {
+            for (k, v) in bh.iter() {
+                for r in &[k, v] {
+                    r.descend_into_self(context);
+                }
+            }
+        }
+    }
+}
+
+impl<'a> Children<'a> for BTS<'a> {
+    fn for_each_child<C>(&self, context: &mut C)
+        where C: Context + PrePost<BTS<'a>>
+    {
+        if let Some(ref bh) = self.contents.get() {
+            for r in bh.iter() {
+                r.descend_into_self(context);
+            }
+        }
+    }
+}
+
+#[derive(Copy, Clone)]
+struct ContextData {
+    curr_depth: usize,
+    max_depth: usize,
+    visited: usize,
+    max_visits: usize,
+    skipped: usize,
+    curr_mark: u32,
+    saw_prev_marked: bool,
+}
+
+impl Context for ContextData {
+    fn should_act(&self) -> bool {
+        self.curr_depth < self.max_depth && self.visited < self.max_visits
+    }
+    fn increase_visited(&mut self) { self.visited += 1; }
+    fn increase_skipped(&mut self) { self.skipped += 1; }
+    fn increase_depth(&mut self) {  self.curr_depth += 1; }
+    fn decrease_depth(&mut self) {  self.curr_depth -= 1; }
+}
+
+impl<T:Named+Marked<u32>> PrePost<T> for ContextData {
+    fn pre(&mut self, t: &T) {
+        for _ in 0..self.curr_depth {
+            if PRINT { print!(" "); }
+        }
+        if PRINT { println!("prev {}", t.name()); }
+        if t.mark() == self.curr_mark {
+            for _ in 0..self.curr_depth {
+                if PRINT { print!(" "); }
+            }
+            if PRINT { println!("(probably previously marked)"); }
+            self.saw_prev_marked = true;
+        }
+        t.set_mark(self.curr_mark);
+    }
+    fn post(&mut self, t: &T) {
+        for _ in 0..self.curr_depth {
+            if PRINT { print!(" "); }
+        }
+        if PRINT { println!("post {}", t.name()); }
+    }
+    fn hit_limit(&mut self, t: &T) {
+        for _ in 0..self.curr_depth {
+            if PRINT { print!(" "); }
+        }
+        if PRINT { println!("LIMIT {}", t.name()); }
+    }
+}
diff --git a/src/test/run-pass/issue-10436.rs b/src/test/run-pass/issue-10436.rs
new file mode 100644 (file)
index 0000000..81a955b
--- /dev/null
@@ -0,0 +1,20 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn works<T>(x: T) -> Vec<T> { vec![x] }
+
+fn also_works<T: Clone>(x: T) -> Vec<T> { vec![x] }
+
+fn main() {
+    let _: Vec<usize> = works(0);
+    let _: Vec<usize> = also_works(0);
+    let _ = works(0);
+    let _ = also_works(0);
+}
diff --git a/src/test/run-pass/issue-14229.rs b/src/test/run-pass/issue-14229.rs
new file mode 100644 (file)
index 0000000..ee2bbe6
--- /dev/null
@@ -0,0 +1,30 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Foo: Sized {
+    fn foo(self) {}
+}
+
+trait Bar: Sized {
+    fn bar(self) {}
+}
+
+struct S;
+
+impl<'l> Foo for &'l S {}
+
+impl<T: Foo> Bar for T {}
+
+fn main() {
+    let s = S;
+    s.foo();
+    (&s).bar();
+    s.bar();
+}
diff --git a/src/test/run-pass/issue-14382.rs b/src/test/run-pass/issue-14382.rs
new file mode 100644 (file)
index 0000000..cdb44f6
--- /dev/null
@@ -0,0 +1,24 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[derive(Debug)]
+struct Matrix4<S>(S);
+trait POrd<S> {}
+
+fn translate<S: POrd<S>>(s: S) -> Matrix4<S> { Matrix4(s) }
+
+impl POrd<f32> for f32 {}
+impl POrd<f64> for f64 {}
+
+fn main() {
+    let x = 1.0;
+    let m : Matrix4<f32> = translate(x);
+    println!("m: {:?}", m);
+}
diff --git a/src/test/run-pass/issue-19404.rs b/src/test/run-pass/issue-19404.rs
new file mode 100644 (file)
index 0000000..0eea6ba
--- /dev/null
@@ -0,0 +1,47 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(reflect_marker)]
+
+use std::any::TypeId;
+use std::marker::Reflect;
+use std::rc::Rc;
+
+type Fp<T> = Rc<T>;
+
+struct Engine;
+
+trait Component: 'static + Reflect {}
+impl Component for Engine {}
+
+trait Env {
+    fn get_component_type_id(&self, type_id: TypeId) -> Option<Fp<Component>>;
+}
+
+impl<'a> Env+'a {
+    fn get_component<T: Component>(&self) -> Option<Fp<T>> {
+        let x = self.get_component_type_id(TypeId::of::<T>());
+        None
+    }
+}
+
+trait Figment {
+    fn init(&mut self, env: &Env);
+}
+
+struct MyFigment;
+
+impl Figment for MyFigment {
+    fn init(&mut self, env: &Env) {
+        let engine = env.get_component::<Engine>();
+    }
+}
+
+fn main() {}
diff --git a/src/test/run-pass/issue-25343.rs b/src/test/run-pass/issue-25343.rs
new file mode 100644 (file)
index 0000000..9e01d57
--- /dev/null
@@ -0,0 +1,16 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+    || {
+        'label: loop {
+        }
+    };
+}
diff --git a/src/test/run-pass/issue-26468.rs b/src/test/run-pass/issue-26468.rs
new file mode 100644 (file)
index 0000000..9fb8675
--- /dev/null
@@ -0,0 +1,38 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(dead_code)]
+
+enum FooMode {
+    Check = 0x1001,
+}
+
+enum BarMode {
+    Check = 0x2001,
+}
+
+enum Mode {
+    Foo(FooMode),
+    Bar(BarMode),
+}
+
+#[inline(never)]
+fn broken(mode: &Mode) -> u32 {
+    for _ in 0..1 {
+        if let Mode::Foo(FooMode::Check) = *mode { return 17 }
+        if let Mode::Bar(BarMode::Check) = *mode { return 19 }
+    }
+    return 42;
+}
+
+fn main() {
+    let mode = Mode::Bar(BarMode::Check);
+    assert_eq!(broken(&mode), 19);
+}