]> git.lizzy.rs Git - rust.git/commitdiff
auto merge of #15062 : pcwalton/rust/trailing-plus, r=brson
authorbors <bors@rust-lang.org>
Sat, 21 Jun 2014 15:36:39 +0000 (15:36 +0000)
committerbors <bors@rust-lang.org>
Sat, 21 Jun 2014 15:36:39 +0000 (15:36 +0000)
This will break code that looks like `Box<Trait+>`. Change that code to
`Box<Trait>` instead.

Closes #14925.

[breaking-change]

r? @brson

65 files changed:
src/doc/guide-unsafe.md
src/doc/rust.md
src/liballoc/lib.rs
src/libarena/lib.rs
src/libcollections/lib.rs
src/libcore/lib.rs
src/libnative/lib.rs
src/librustc/driver/driver.rs
src/librustc/front/feature_gate.rs
src/librustc/lib.rs
src/librustc/metadata/common.rs
src/librustc/metadata/csearch.rs
src/librustc/metadata/decoder.rs
src/librustc/metadata/encoder.rs
src/librustc/middle/check_match.rs
src/librustc/middle/lint.rs
src/librustc/middle/stability.rs [new file with mode: 0644]
src/librustc/middle/trans/_match.rs
src/librustc/middle/ty.rs
src/librustc/middle/typeck/check/_match.rs
src/librustrt/lib.rs
src/librustuv/lib.rs
src/libstd/lib.rs
src/libsync/lib.rs
src/libsyntax/attr.rs
src/libsyntax/lib.rs
src/libsyntax/parse/parser.rs
src/test/auxiliary/inherited_stability.rs [new file with mode: 0644]
src/test/auxiliary/issue-2526.rs
src/test/auxiliary/lint_output_format.rs [new file with mode: 0755]
src/test/bench/task-perf-alloc-unwind.rs
src/test/compile-fail/borrowck-borrowed-uniq-rvalue-2.rs
src/test/compile-fail/issue-13482.rs [new file with mode: 0644]
src/test/compile-fail/issue-2111.rs
src/test/compile-fail/issue-4321.rs [new file with mode: 0644]
src/test/compile-fail/lint-output-format.rs
src/test/compile-fail/lint-stability.rs
src/test/compile-fail/no-send-res-ports.rs
src/test/compile-fail/non-exhaustive-match-nested.rs
src/test/compile-fail/non-exhaustive-match.rs
src/test/compile-fail/non-exhaustive-pattern-witness.rs [new file with mode: 0644]
src/test/compile-fail/pinned-deep-copy.rs
src/test/compile-fail/precise-refutable-pattern-errors.rs [deleted file]
src/test/compile-fail/refutable-pattern-errors.rs [new file with mode: 0644]
src/test/compile-fail/refutable-pattern-in-fn-arg.rs
src/test/compile-fail/unique-vec-res.rs
src/test/run-fail/unwind-resource-fail3.rs
src/test/run-pass/attr-no-drop-flag-size.rs
src/test/run-pass/drop-trait-generic.rs
src/test/run-pass/init-res-into-things.rs
src/test/run-pass/issue-14393.rs [new file with mode: 0644]
src/test/run-pass/issue-15043.rs [new file with mode: 0644]
src/test/run-pass/issue-2718.rs
src/test/run-pass/issue-2735-2.rs
src/test/run-pass/issue-2735-3.rs
src/test/run-pass/issue-4252.rs
src/test/run-pass/issue-7784.rs [new file with mode: 0644]
src/test/run-pass/issue-979.rs
src/test/run-pass/newtype-struct-drop-run.rs
src/test/run-pass/option-unwrap.rs
src/test/run-pass/resource-assign-is-not-copy.rs
src/test/run-pass/resource-destruct.rs
src/test/run-pass/resource-in-struct.rs
src/test/run-pass/unwind-resource2.rs
src/test/run-pass/vec-slice-drop.rs

index 1431c8a5c9ae45be0491eefc5bd1436341576424..def96c62deb006c4e658b9984d1bf0acbe340a5f 100644 (file)
@@ -192,6 +192,8 @@ As an example, we give a reimplementation of owned boxes by wrapping
 reimplementation is as safe as the `Box` type.
 
 ```
+#![feature(unsafe_destructor)]
+
 extern crate libc;
 use libc::{c_void, size_t, malloc, free};
 use std::mem;
@@ -242,10 +244,12 @@ impl<T: Send> Unique<T> {
 // A key ingredient for safety, we associate a destructor with
 // Unique<T>, making the struct manage the raw pointer: when the
 // struct goes out of scope, it will automatically free the raw pointer.
+//
 // NB: This is an unsafe destructor, because rustc will not normally
-// allow destructors to be associated with parametrized types, due to
+// allow destructors to be associated with parameterized types, due to
 // bad interaction with managed boxes. (With the Send restriction,
-// we don't have this problem.)
+// we don't have this problem.) Note that the `#[unsafe_destructor]`
+// feature gate is required to use unsafe destructors.
 #[unsafe_destructor]
 impl<T: Send> Drop for Unique<T> {
     fn drop(&mut self) {
index 7e5e5b2e67a43be2c92e2f6d9c78d02b38d3db32..6049ffab2bf7330732a1aec7700f1af51b9b336a 100644 (file)
@@ -1940,12 +1940,13 @@ interpreted:
   enum representation in C is undefined, and this may be incorrect when the C
   code is compiled with certain flags.
 - `simd` - on certain tuple structs, derive the arithmetic operators, which
-  lower to the target's SIMD instructions, if any.
+  lower to the target's SIMD instructions, if any; the `simd` feature gate
+  is necessary to use this attribute.
 - `static_assert` - on statics whose type is `bool`, terminates compilation
   with an error if it is not initialized to `true`.
 - `unsafe_destructor` - allow implementations of the "drop" language item
   where the type it is implemented for does not implement the "send" language
-  item.
+  item; the `unsafe_destructor` feature gate is needed to use this attribute
 - `unsafe_no_drop_flag` - on structs, remove the flag that prevents
   destructors from being run twice. Destructors might be run multiple times on
   the same object with this attribute.
@@ -2300,28 +2301,43 @@ One can indicate the stability of an API using the following attributes:
 These levels are directly inspired by
 [Node.js' "stability index"](http://nodejs.org/api/documentation.html).
 
-There are lints for disallowing items marked with certain levels:
-`deprecated`, `experimental` and `unstable`; the first two will warn
-by default. Items with not marked with a stability are considered to
-be unstable for the purposes of the lint. One can give an optional
+Stability levels are inherited, so an items's stability attribute is the
+default stability for everything nested underneath it.
+
+There are lints for disallowing items marked with certain levels: `deprecated`,
+`experimental` and `unstable`. For now, only `deprecated` warns by default, but
+this will change once the standard library has been stabilized.
+Stability levels are meant to be promises at the crate
+ level, so these lints only apply when referencing
+items from an _external_ crate, not to items defined within the
+current crate. Items with no stability level are considered
+to be unstable for the purposes of the lint. One can give an optional
 string that will be displayed when the lint flags the use of an item.
 
-~~~~ {.ignore}
-#![warn(unstable)]
+For example, if we define one crate called `stability_levels`:
 
+~~~~ {.ignore}
 #[deprecated="replaced by `best`"]
-fn bad() {
+pub fn bad() {
     // delete everything
 }
 
-fn better() {
+pub fn better() {
     // delete fewer things
 }
 
 #[stable]
-fn best() {
+pub fn best() {
     // delete nothing
 }
+~~~~
+
+then the lints will work as follows for a client crate:
+
+~~~~ {.ignore}
+#![warn(unstable)]
+extern crate stability_levels;
+use stability_levels::{bad, better, best};
 
 fn main() {
     bad(); // "warning: use of deprecated item: replaced by `best`"
index e578346861e24a6b1a4fbb730b3e9e45c7043d44..53a79217241bac76cce5d349e7120550b687086e 100644 (file)
@@ -69,7 +69,8 @@
        html_root_url = "http://doc.rust-lang.org/")]
 
 #![no_std]
-#![feature(phase)]
+#![feature(phase, unsafe_destructor)]
+#![allow(unknown_features)] // NOTE: remove after a stage0 snap
 
 #[phase(plugin, link)]
 extern crate core;
index 86babb7a3d2e7e7cdeae89d9ba29cd97fe51af95..5ddb088c8c840d4a351b86fe9ddd66b1bb7cb380 100644 (file)
 #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
        html_favicon_url = "http://www.rust-lang.org/favicon.ico",
        html_root_url = "http://doc.rust-lang.org/")]
+
+#![feature(unsafe_destructor)]
 #![allow(missing_doc)]
+#![allow(unknown_features)] // NOTE: remove after a stage0 snap
 
 use std::cell::{Cell, RefCell};
 use std::cmp;
index 3abecc3fc8622e2830508fe7ef122495d1088c91..ca7de131dc212c902736c87281ac7d60a9cc9238 100644 (file)
@@ -22,7 +22,9 @@
        html_playground_url = "http://play.rust-lang.org/")]
 
 #![feature(macro_rules, managed_boxes, default_type_params, phase, globs)]
+#![feature(unsafe_destructor)]
 #![no_std]
+#![allow(unknown_features)] // NOTE: remove after a stage0 snap
 
 #[phase(plugin, link)] extern crate core;
 extern crate alloc;
index 62c34912f66ad4c1eb7acc36c56668b10a08a6e4..3d2382e6208b421f7122f8224c42c76cd846fe2b 100644 (file)
@@ -55,8 +55,9 @@
        html_playground_url = "http://play.rust-lang.org/")]
 
 #![no_std]
-#![feature(globs, macro_rules, managed_boxes, phase, simd)]
+#![feature(globs, macro_rules, managed_boxes, phase, simd, unsafe_destructor)]
 #![deny(missing_doc)]
+#![allow(unknown_features)] // NOTE: remove after a stage0 snap
 
 #[cfg(test)] extern crate realcore = "core";
 #[cfg(test)] extern crate libc;
index 24f1b9b9407db72de79d57e1dcfb0a723967354a..b44673a24ef053a84851dc975ffeb3a5d497bdd9 100644 (file)
 #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
        html_favicon_url = "http://www.rust-lang.org/favicon.ico",
        html_root_url = "http://doc.rust-lang.org/")]
+
 #![deny(unused_result, unused_must_use)]
 #![allow(non_camel_case_types)]
 #![allow(deprecated)]
+#![allow(unknown_features)] // NOTE: remove after a stage0 snap
 #![feature(default_type_params)]
 
 // NB this crate explicitly does *not* allow glob imports, please seriously
 //    consider whether they're needed before adding that feature here (the
 //    answer is that you don't need them)
-#![feature(macro_rules)]
+#![feature(macro_rules, unsafe_destructor)]
 
 extern crate alloc;
 extern crate libc;
index e767a7c84f686fb8c489ce55a5c268aa573457bf..ac6558aef651f17e015562920e42389cad24b8b7 100644 (file)
@@ -20,7 +20,7 @@
 use metadata::creader;
 use middle::cfg;
 use middle::cfg::graphviz::LabelledCFG;
-use middle::{trans, freevars, kind, ty, typeck, lint, reachable};
+use middle::{trans, freevars, stability, kind, ty, typeck, lint, reachable};
 use middle::dependency_format;
 use middle;
 use plugin::load::Plugins;
@@ -312,8 +312,11 @@ pub fn phase_3_run_analysis_passes(sess: Session,
     time(time_passes, "loop checking", (), |_|
          middle::check_loop::check_crate(&sess, krate));
 
+    let stability_index = time(time_passes, "stability index", (), |_|
+                               stability::Index::build(krate));
+
     let ty_cx = ty::mk_ctxt(sess, def_map, named_region_map, ast_map,
-                            freevars, region_map, lang_items);
+                            freevars, region_map, lang_items, stability_index);
 
     // passes are timed inside typeck
     typeck::check_crate(&ty_cx, trait_map, krate);
index 30d0c6d0564f242b7624b802eb54c496126ba92a..07926ee112d5ae70543e68943e46521c8520ce64 100644 (file)
@@ -50,6 +50,7 @@
     ("log_syntax", Active),
     ("trace_macros", Active),
     ("concat_idents", Active),
+    ("unsafe_destructor", Active),
 
     ("simd", Active),
     ("default_type_params", Active),
@@ -220,6 +221,17 @@ fn visit_item(&mut self, i: &ast::Item, _:()) {
                 }
             }
 
+            ast::ItemImpl(..) => {
+                if attr::contains_name(i.attrs.as_slice(),
+                                       "unsafe_destructor") {
+                    self.gate_feature("unsafe_destructor",
+                                      i.span,
+                                      "`#[unsafe_destructor]` allows too \
+                                       many unsafe patterns and may be \
+                                       removed in the future");
+                }
+            }
+
             _ => {}
         }
 
index 86529cf198797a82a783fd0a048837e47281f155..e311d1e9b15bb43c6436576d9d3eb5fe7a9d77e1 100644 (file)
@@ -29,8 +29,9 @@
       html_root_url = "http://doc.rust-lang.org/")]
 
 #![allow(deprecated)]
-#![feature(macro_rules, globs, struct_variant, managed_boxes, quote,
-           default_type_params, phase)]
+#![allow(unknown_features)] // NOTE: remove after a stage0 snap
+#![feature(macro_rules, globs, struct_variant, managed_boxes, quote)]
+#![feature(default_type_params, phase, unsafe_destructor)]
 
 extern crate arena;
 extern crate debug;
@@ -80,6 +81,7 @@ pub mod middle {
     pub mod weak_lang_items;
     pub mod save;
     pub mod intrinsicck;
+    pub mod stability;
 }
 
 pub mod front {
index 5a974aecabcb285978201d3febd9017672933ceb..9e1d272f5da2e2ec8c4beb3a129dfe2a628b48d3 100644 (file)
@@ -210,6 +210,9 @@ pub fn from_uint(value : uint) -> Option<astencode_tag> {
 pub static tag_reachable_extern_fns: uint = 0x90;
 pub static tag_reachable_extern_fn_id: uint = 0x91;
 
+pub static tag_items_data_item_stability: uint = 0x92;
+
+
 #[deriving(Clone, Show)]
 pub struct LinkMeta {
     pub crateid: CrateId,
index 43c895a201fa687215b4e33f304ee4ffa6fc4b57..32b7df23d520add0e2fa708227f4583c0e85e263 100644 (file)
@@ -25,6 +25,7 @@
 use std::rc::Rc;
 use syntax::ast;
 use syntax::ast_map;
+use syntax::attr;
 use syntax::diagnostic::expect;
 use syntax::parse::token;
 
@@ -328,3 +329,10 @@ pub fn is_typedef(cstore: &cstore::CStore, did: ast::DefId) -> bool {
     let cdata = cstore.get_crate_data(did.krate);
     decoder::is_typedef(&*cdata, did.node)
 }
+
+pub fn get_stability(cstore: &cstore::CStore,
+                     def: ast::DefId)
+                     -> Option<attr::Stability> {
+    let cdata = cstore.get_crate_data(def.krate);
+    decoder::get_stability(&*cdata, def.node)
+}
index 68aa2bacd08e20743661c1ba8ec8ec4a534efb67..548a8c50501ddd97951fe7d7205a16cc07002a2f 100644 (file)
@@ -439,6 +439,14 @@ pub fn get_type(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt)
     }
 }
 
+pub fn get_stability(cdata: Cmd, id: ast::NodeId) -> Option<attr::Stability> {
+    let item = lookup_item(id, cdata.data());
+    reader::maybe_get_doc(item, tag_items_data_item_stability).map(|doc| {
+        let mut decoder = reader::Decoder::new(doc);
+        Decodable::decode(&mut decoder).unwrap()
+    })
+}
+
 pub fn get_impl_trait(cdata: Cmd,
                       id: ast::NodeId,
                       tcx: &ty::ctxt) -> Option<Rc<ty::TraitRef>>
index 98d9b45738fd09c138b927b2b7607463d00b9683..a94ea0b98eb6aeb307cdf69cbde723764b10778d 100644 (file)
@@ -327,6 +327,10 @@ fn encode_enum_variant_info(ecx: &EncodeContext,
         encode_parent_item(ebml_w, local_def(id));
         encode_visibility(ebml_w, variant.node.vis);
         encode_attributes(ebml_w, variant.node.attrs.as_slice());
+
+        let stab = ecx.tcx.stability.borrow().lookup_local(variant.node.id);
+        encode_stability(ebml_w, stab);
+
         match variant.node.kind {
             ast::TupleVariantKind(ref args)
                     if args.len() > 0 && generics.ty_params.len() == 0 => {
@@ -588,6 +592,7 @@ fn encode_info_for_mod(ecx: &EncodeContext,
 
     encode_path(ebml_w, path.clone());
     encode_visibility(ebml_w, vis);
+    encode_stability(ebml_w, ecx.tcx.stability.borrow().lookup_local(id));
 
     // Encode the reexports of this module, if this module is public.
     if vis == Public {
@@ -717,6 +722,8 @@ fn encode_info_for_struct_ctor(ecx: &EncodeContext,
         encode_symbol(ecx, ebml_w, ctor_id);
     }
 
+    encode_stability(ebml_w, ecx.tcx.stability.borrow().lookup_local(ctor_id));
+
     // indicate that this is a tuple struct ctor, because downstream users will normally want
     // the tuple struct definition, but without this there is no way for them to tell that
     // they actually have a ctor rather than a normal function
@@ -761,6 +768,9 @@ fn encode_info_for_method(ecx: &EncodeContext,
     encode_method_ty_fields(ecx, ebml_w, m);
     encode_parent_item(ebml_w, local_def(parent_id));
 
+    let stab = ecx.tcx.stability.borrow().lookup_local(m.def_id.node);
+    encode_stability(ebml_w, stab);
+
     // The type for methods gets encoded twice, which is unfortunate.
     let tpt = lookup_item_type(ecx.tcx, m.def_id);
     encode_bounds_and_type(ebml_w, ecx, &tpt);
@@ -880,6 +890,14 @@ fn encode_sized(ebml_w: &mut Encoder, sized: Sized) {
     ebml_w.end_tag();
 }
 
+fn encode_stability(ebml_w: &mut Encoder, stab_opt: Option<attr::Stability>) {
+    stab_opt.map(|stab| {
+        ebml_w.start_tag(tag_items_data_item_stability);
+        stab.encode(ebml_w).unwrap();
+        ebml_w.end_tag();
+    });
+}
+
 fn encode_info_for_item(ecx: &EncodeContext,
                         ebml_w: &mut Encoder,
                         item: &Item,
@@ -900,6 +918,8 @@ fn add_to_index(item: &Item, ebml_w: &Encoder,
            ecx.tcx.sess.codemap().span_to_str(item.span));
 
     let def_id = local_def(item.id);
+    let stab = tcx.stability.borrow().lookup_local(item.id);
+
     match item.node {
       ItemStatic(_, m, _) => {
         add_to_index(item, ebml_w, index);
@@ -921,6 +941,7 @@ fn add_to_index(item: &Item, ebml_w: &Encoder,
             encode_inlined_item(ecx, ebml_w, IIItemRef(item));
         }
         encode_visibility(ebml_w, vis);
+        encode_stability(ebml_w, stab);
         ebml_w.end_tag();
       }
       ItemFn(ref decl, fn_style, _, ref generics, _) => {
@@ -939,6 +960,7 @@ fn add_to_index(item: &Item, ebml_w: &Encoder,
             encode_symbol(ecx, ebml_w, item.id);
         }
         encode_visibility(ebml_w, vis);
+        encode_stability(ebml_w, stab);
         encode_method_argument_names(ebml_w, &**decl);
         ebml_w.end_tag();
       }
@@ -968,6 +990,7 @@ fn add_to_index(item: &Item, ebml_w: &Encoder,
             ebml_w.end_tag();
         }
         encode_visibility(ebml_w, vis);
+        encode_stability(ebml_w, stab);
         ebml_w.end_tag();
       }
       ItemTy(..) => {
@@ -979,6 +1002,7 @@ fn add_to_index(item: &Item, ebml_w: &Encoder,
         encode_name(ebml_w, item.ident.name);
         encode_path(ebml_w, path);
         encode_visibility(ebml_w, vis);
+        encode_stability(ebml_w, stab);
         ebml_w.end_tag();
       }
       ItemEnum(ref enum_definition, ref generics) => {
@@ -1001,6 +1025,7 @@ fn add_to_index(item: &Item, ebml_w: &Encoder,
         encode_inherent_implementations(ecx, ebml_w, def_id);
 
         encode_visibility(ebml_w, vis);
+        encode_stability(ebml_w, stab);
         ebml_w.end_tag();
 
         encode_enum_variant_info(ecx,
@@ -1035,6 +1060,7 @@ fn add_to_index(item: &Item, ebml_w: &Encoder,
         encode_name(ebml_w, item.ident.name);
         encode_attributes(ebml_w, item.attrs.as_slice());
         encode_path(ebml_w, path.clone());
+        encode_stability(ebml_w, stab);
         encode_visibility(ebml_w, vis);
 
         /* Encode def_ids for each field and method
@@ -1095,6 +1121,7 @@ fn add_to_index(item: &Item, ebml_w: &Encoder,
             encode_impl_vtables(ebml_w, ecx, &impl_vtables);
         }
         encode_path(ebml_w, path.clone());
+        encode_stability(ebml_w, stab);
         ebml_w.end_tag();
 
         // Iterate down the methods, emitting them. We rely on the
@@ -1138,6 +1165,7 @@ fn add_to_index(item: &Item, ebml_w: &Encoder,
         // should no longer need this ugly little hack either.
         encode_sized(ebml_w, sized);
         encode_visibility(ebml_w, vis);
+        encode_stability(ebml_w, stab);
         for &method_def_id in ty::trait_method_def_ids(tcx, def_id).iter() {
             ebml_w.start_tag(tag_item_trait_method);
             encode_def_id(ebml_w, method_def_id);
@@ -1176,9 +1204,11 @@ fn add_to_index(item: &Item, ebml_w: &Encoder,
             ebml_w.start_tag(tag_items_data_item);
 
             encode_method_ty_fields(ecx, ebml_w, &*method_ty);
-
             encode_parent_item(ebml_w, def_id);
 
+            let stab = tcx.stability.borrow().lookup_local(method_def_id.node);
+            encode_stability(ebml_w, stab);
+
             let elem = ast_map::PathName(method_ty.ident.name);
             encode_path(ebml_w, path.clone().chain(Some(elem).move_iter()));
 
index d8f7a97ce13ff8d67daeb57fa3fdfdf7b24ea2b8..6d8b178ba0014092bd77de97831a92279b43a2c1 100644 (file)
 
 #![allow(non_camel_case_types)]
 
-use middle::const_eval::{compare_const_vals, lookup_const_by_id};
-use middle::const_eval::{eval_const_expr, const_val, const_bool, const_float};
+use middle::const_eval::{compare_const_vals, const_bool, const_float, const_val};
+use middle::const_eval::{eval_const_expr, lookup_const_by_id};
 use middle::def::*;
 use middle::pat_util::*;
 use middle::ty::*;
 use middle::ty;
-use util::ppaux::ty_to_str;
 
-use std::cmp;
 use std::gc::{Gc, GC};
 use std::iter;
 use syntax::ast::*;
 use syntax::ast_util::{is_unguarded, walk_pat};
-use syntax::codemap::{DUMMY_SP, Span};
-use syntax::parse::token;
+use syntax::codemap::{Span, Spanned, DUMMY_SP};
+use syntax::owned_slice::OwnedSlice;
+use syntax::print::pprust::pat_to_str;
 use syntax::visit;
 use syntax::visit::{Visitor, FnKind};
+use util::ppaux::ty_to_str;
+
+type Matrix = Vec<Vec<Gc<Pat>>>;
+
+#[deriving(Clone)]
+enum Usefulness {
+    Useful(Vec<Gc<Pat>>),
+    NotUseful
+}
+
+enum WitnessPreference {
+    ConstructWitness,
+    LeaveOutWitness
+}
+
+impl Usefulness {
+    fn useful(self) -> Option<Vec<Gc<Pat>>> {
+        match self {
+            Useful(pats) => Some(pats),
+            _ => None
+        }
+    }
+}
+
+fn def_to_path(tcx: &ty::ctxt, id: DefId) -> Path {
+    ty::with_path(tcx, id, |mut path| Path {
+        global: false,
+        segments: path.last().map(|elem| PathSegment {
+            identifier: Ident::new(elem.name()),
+            lifetimes: vec!(),
+            types: OwnedSlice::empty()
+        }).move_iter().collect(),
+        span: DUMMY_SP,
+    })
+}
 
 struct MatchCheckCtxt<'a> {
     tcx: &'a ty::ctxt,
@@ -58,38 +92,39 @@ pub fn check_crate(tcx: &ty::ctxt,
 fn check_expr(cx: &mut MatchCheckCtxt, ex: &Expr) {
     visit::walk_expr(cx, ex, ());
     match ex.node {
-      ExprMatch(scrut, ref arms) => {
-        // First, check legality of move bindings.
-        for arm in arms.iter() {
-            check_legality_of_move_bindings(cx,
-                                            arm.guard.is_some(),
-                                            arm.pats.as_slice());
-        }
+        ExprMatch(scrut, ref arms) => {
+            // First, check legality of move bindings.
+            for arm in arms.iter() {
+                check_legality_of_move_bindings(cx,
+                                                arm.guard.is_some(),
+                                                arm.pats.as_slice());
+            }
 
-        check_arms(cx, arms.as_slice());
-        /* Check for exhaustiveness */
-         // Check for empty enum, because is_useful only works on inhabited
-         // types.
-       let pat_ty = node_id_to_type(cx.tcx, scrut.id);
-       if (*arms).is_empty() {
-           if !type_is_empty(cx.tcx, pat_ty) {
-               // We know the type is inhabited, so this must be wrong
-               cx.tcx.sess.span_err(ex.span, format!("non-exhaustive patterns: \
-                            type {} is non-empty",
-                            ty_to_str(cx.tcx, pat_ty)).as_slice());
-           }
-           // If the type *is* empty, it's vacuously exhaustive
-           return;
-       }
-       let m: matrix = arms
-          .iter()
-          .filter(|&arm| is_unguarded(arm))
-          .flat_map(|arm| arm.pats.iter())
-          .map(|pat| vec!(pat.clone()))
-          .collect();
-       check_exhaustive(cx, ex.span, &m);
-     }
-     _ => ()
+            // Second, check for unreachable arms.
+            check_arms(cx, arms.as_slice());
+
+            // Finally, check if the whole match expression is exhaustive.
+            // Check for empty enum, because is_useful only works on inhabited types.
+            let pat_ty = node_id_to_type(cx.tcx, scrut.id);
+            if (*arms).is_empty() {
+               if !type_is_empty(cx.tcx, pat_ty) {
+                   // We know the type is inhabited, so this must be wrong
+                   cx.tcx.sess.span_err(ex.span, format!("non-exhaustive patterns: \
+                                type {} is non-empty",
+                                ty_to_str(cx.tcx, pat_ty)).as_slice());
+               }
+               // If the type *is* empty, it's vacuously exhaustive
+               return;
+            }
+            let m: Matrix = arms
+                .iter()
+                .filter(|&arm| is_unguarded(arm))
+                .flat_map(|arm| arm.pats.iter())
+                .map(|pat| vec!(pat.clone()))
+                .collect();
+            check_exhaustive(cx, ex.span, &m);
+        },
+        _ => ()
     }
 }
 
@@ -98,7 +133,6 @@ fn check_arms(cx: &MatchCheckCtxt, arms: &[Arm]) {
     let mut seen = Vec::new();
     for arm in arms.iter() {
         for pat in arm.pats.iter() {
-
             // Check that we do not match against a static NaN (#6804)
             let pat_matches_nan: |&Pat| -> bool = |p| {
                 let opt_def = cx.tcx.def_map.borrow().find_copy(&p.id);
@@ -123,11 +157,9 @@ fn check_arms(cx: &MatchCheckCtxt, arms: &[Arm]) {
             });
 
             let v = vec!(*pat);
-            match is_useful(cx, &seen, v.as_slice()) {
-              not_useful => {
-                cx.tcx.sess.span_err(pat.span, "unreachable pattern");
-              }
-              _ => ()
+            match is_useful(cx, &seen, v.as_slice(), LeaveOutWitness) {
+                NotUseful => cx.tcx.sess.span_err(pat.span, "unreachable pattern"),
+                _ => ()
             }
             if arm.guard.is_none() { seen.push(v); }
         }
@@ -136,80 +168,163 @@ fn check_arms(cx: &MatchCheckCtxt, arms: &[Arm]) {
 
 fn raw_pat(p: Gc<Pat>) -> Gc<Pat> {
     match p.node {
-      PatIdent(_, _, Some(s)) => { raw_pat(s) }
-      _ => { p }
+        PatIdent(_, _, Some(s)) => { raw_pat(s) }
+        _ => { p }
     }
 }
 
-fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, m: &matrix) {
-    let ext = match is_useful(cx, m, [wild()]) {
-        not_useful => {
+fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, m: &Matrix) {
+    match is_useful(cx, m, [wild()], ConstructWitness) {
+        NotUseful => {
             // This is good, wildcard pattern isn't reachable
             return;
         }
-        useful_ => None,
-        useful(ty, ref ctor) => {
+        Useful(pats) => {
+            let witness = match pats.as_slice() {
+                [witness] => witness,
+                [] => wild(),
+                _ => unreachable!()
+            };
+            let msg = format!("non-exhaustive patterns: `{0}` not covered", pat_to_str(&*witness));
+            cx.tcx.sess.span_err(sp, msg.as_slice());
+        }
+    }
+}
+
+#[deriving(Clone, PartialEq)]
+enum ctor {
+    single,
+    variant(DefId /* variant */, bool /* is_structure */),
+    val(const_val),
+    range(const_val, const_val),
+    vec(uint)
+}
+
+fn const_val_to_expr(value: &const_val) -> Gc<Expr> {
+    let node = match value {
+        &const_bool(b) => LitBool(b),
+        _ => unreachable!()
+    };
+    box(GC) Expr {
+        id: 0,
+        node: ExprLit(box(GC) Spanned { node: node, span: DUMMY_SP }),
+        span: DUMMY_SP
+    }
+}
+
+fn construct_witness(cx: &MatchCheckCtxt, ctor: &ctor, pats: Vec<Gc<Pat>>, lty: ty::t) -> Gc<Pat> {
+    let pat = match ty::get(lty).sty {
+        ty::ty_tup(_) => PatTup(pats),
+
+        ty::ty_enum(cid, _) | ty::ty_struct(cid, _)  => {
+            let (vid, is_structure) = match ctor {
+                &variant(vid, is_structure) => (vid, is_structure),
+                _ => (cid, true)
+            };
+            if is_structure {
+                let fields = ty::lookup_struct_fields(cx.tcx, vid);
+                let field_pats = fields.move_iter()
+                    .zip(pats.iter())
+                    .map(|(field, pat)| FieldPat {
+                        ident: Ident::new(field.name),
+                        pat: pat.clone()
+                    }).collect();
+                PatStruct(def_to_path(cx.tcx, vid), field_pats, false)
+            } else {
+                PatEnum(def_to_path(cx.tcx, vid), Some(pats))
+            }
+        },
+
+        ty::ty_rptr(_, ty::mt { ty: ty, .. }) => {
             match ty::get(ty).sty {
-                ty::ty_bool => {
-                    match *ctor {
-                        val(const_bool(true)) => Some("true".to_string()),
-                        val(const_bool(false)) => Some("false".to_string()),
-                        _ => None
-                    }
-                }
-                ty::ty_enum(id, _) => {
-                    let vid = match *ctor {
-                        variant(id) => id,
-                        _ => fail!("check_exhaustive: non-variant ctor"),
-                    };
-                    let variants = ty::enum_variants(cx.tcx, id);
-
-                    match variants.iter().find(|v| v.id == vid) {
-                        Some(v) => {
-                            Some(token::get_ident(v.name).get()
-                                                         .to_str()
-                                                         .into_string())
-                        }
-                        None => {
-                            fail!("check_exhaustive: bad variant in ctor")
-                        }
-                    }
-                }
-                ty::ty_vec(..) | ty::ty_rptr(..) => {
-                    match *ctor {
-                        vec(n) => {
-                            Some(format!("vectors of length {}", n))
-                        }
-                        _ => None
-                    }
+                ty::ty_vec(_, None) => match ctor {
+                    &vec(_) => PatVec(pats, None, vec!()),
+                    _ => unreachable!()
+                },
+                ty::ty_str => PatWild,
+                _ => {
+                    assert_eq!(pats.len(), 1);
+                    PatRegion(pats.get(0).clone())
                 }
-                _ => None
+            }
+        },
+
+        ty::ty_box(_) => {
+            assert_eq!(pats.len(), 1);
+            PatBox(pats.get(0).clone())
+        },
+
+        _ => {
+            match ctor {
+                &vec(_) => PatVec(pats, None, vec!()),
+                &val(ref v) => PatLit(const_val_to_expr(v)),
+                _ => PatWild
             }
         }
     };
-    let msg = format!("non-exhaustive patterns{}", match ext {
-        Some(ref s) => format!(": {} not covered", *s),
-        None => "".to_string()
-    });
-    cx.tcx.sess.span_err(sp, msg.as_slice());
+
+    box(GC) Pat {
+        id: 0,
+        node: pat,
+        span: DUMMY_SP
+    }
 }
 
-type matrix = Vec<Vec<Gc<Pat>>>;
+fn missing_constructor(cx: &MatchCheckCtxt, m: &Matrix, left_ty: ty::t) -> Option<ctor> {
+    let used_constructors: Vec<ctor> = m.iter()
+        .filter_map(|r| pat_ctor_id(cx, left_ty, *r.get(0)))
+        .collect();
 
-#[deriving(Clone)]
-enum useful {
-    useful(ty::t, ctor),
-    useful_,
-    not_useful,
+    all_constructors(cx, m, left_ty)
+        .move_iter()
+        .find(|c| !used_constructors.contains(c))
 }
 
-#[deriving(Clone, PartialEq)]
-enum ctor {
-    single,
-    variant(DefId),
-    val(const_val),
-    range(const_val, const_val),
-    vec(uint)
+fn all_constructors(cx: &MatchCheckCtxt, m: &Matrix, left_ty: ty::t) -> Vec<ctor> {
+    fn vec_constructors(m: &Matrix) -> Vec<ctor> {
+        let max_vec_len = m.iter().map(|r| match r.get(0).node {
+            PatVec(ref before, _, ref after) => before.len() + after.len(),
+            _ => 0u
+        }).max().unwrap_or(0u);
+        let contains_slice = m.iter().any(|r| match r.get(0).node {
+            PatVec(_, ref slice, _) => slice.is_some(),
+            _ => false
+        });
+        let lengths = iter::range_inclusive(0u, if contains_slice {
+            max_vec_len
+        } else {
+            max_vec_len + 1
+        });
+        lengths.map(|len| vec(len)).collect()
+    }
+
+    match ty::get(left_ty).sty {
+        ty::ty_bool =>
+            [true, false].iter().map(|b| val(const_bool(*b))).collect(),
+
+        ty::ty_rptr(_, ty::mt { ty: ty, .. }) => match ty::get(ty).sty {
+            ty::ty_vec(_, None) => vec_constructors(m),
+            _ => vec!(single)
+        },
+
+        ty::ty_enum(eid, _) =>
+            ty::enum_variants(cx.tcx, eid)
+                .iter()
+                .map(|va| variant(va.id, va.arg_names.is_some()))
+                .collect(),
+
+        ty::ty_vec(_, None) =>
+            vec_constructors(m),
+
+        ty::ty_vec(_, Some(n)) =>
+            vec!(vec(n)),
+
+        ty::ty_nil if !m.iter().all(|r| is_wild(cx, *r.get(0))) =>
+            vec!(),
+
+        _ =>
+            vec!(single)
+    }
 }
 
 // Algorithm from http://moscova.inria.fr/~maranget/papers/warn/index.html
@@ -225,12 +340,13 @@ enum ctor {
 
 // Note: is_useful doesn't work on empty types, as the paper notes.
 // So it assumes that v is non-empty.
-fn is_useful(cx: &MatchCheckCtxt, m: &matrix, v: &[Gc<Pat>]) -> useful {
+fn is_useful(cx: &MatchCheckCtxt, m: &Matrix, v: &[Gc<Pat>],
+             witness: WitnessPreference) -> Usefulness {
     if m.len() == 0u {
-        return useful_;
+        return Useful(vec!());
     }
     if m.get(0).len() == 0u {
-        return not_useful
+        return NotUseful;
     }
     let real_pat = match m.iter().find(|r| r.get(0).id != 0) {
         Some(r) => {
@@ -241,310 +357,156 @@ fn is_useful(cx: &MatchCheckCtxt, m: &matrix, v: &[Gc<Pat>]) -> useful {
                 _ => *r.get(0)
             }
         }
-        None if v.len() == 0 => return not_useful,
+        None if v.len() == 0 => return NotUseful,
         None => v[0]
     };
-    let left_ty = if real_pat.id == 0 { ty::mk_nil() }
-                  else { ty::node_id_to_type(cx.tcx, real_pat.id) };
-
-    match pat_ctor_id(cx, v[0]) {
-      None => {
-        match missing_ctor(cx, m, left_ty) {
-          None => {
-            match ty::get(left_ty).sty {
-              ty::ty_bool => {
-                  match is_useful_specialized(cx, m, v,
-                                              val(const_bool(true)),
-                                              0u, left_ty){
-                      not_useful => {
-                          is_useful_specialized(cx, m, v,
-                                                val(const_bool(false)),
-                                                0u, left_ty)
-                      }
-                      u => u,
-                  }
-              }
-              ty::ty_enum(eid, _) => {
-                  for va in (*ty::enum_variants(cx.tcx, eid)).iter() {
-                      match is_useful_specialized(cx, m, v, variant(va.id),
-                                                  va.args.len(), left_ty) {
-                        not_useful => (),
-                        u => return u,
-                      }
-                  }
-                  not_useful
-              }
-              ty::ty_vec(_, Some(n)) => {
-                  is_useful_specialized(cx, m, v, vec(n), n, left_ty)
-              }
-              ty::ty_vec(..) => fail!("impossible case"),
-              ty::ty_rptr(_, ty::mt{ty: ty, ..}) | ty::ty_uniq(ty) => match ty::get(ty).sty {
-                  ty::ty_vec(_, None) => {
-                      let max_len = m.iter().rev().fold(0, |max_len, r| {
-                          match r.get(0).node {
-                              PatVec(ref before, _, ref after) => {
-                                  cmp::max(before.len() + after.len(), max_len)
-                              }
-                              _ => max_len
-                          }
-                      });
-                      for n in iter::range(0u, max_len + 1) {
-                          match is_useful_specialized(cx, m, v, vec(n), n, left_ty) {
-                              not_useful => (),
-                              u => return u,
-                          }
-                      }
-                      not_useful
-                  }
-                  _ => {
-                      let arity = ctor_arity(cx, &single, left_ty);
-                      is_useful_specialized(cx, m, v, single, arity, left_ty)
-                  }
-              },
-              _ => {
-                  let arity = ctor_arity(cx, &single, left_ty);
-                  is_useful_specialized(cx, m, v, single, arity, left_ty)
-              }
-            }
-          }
-          Some(ctor) => {
-            match is_useful(cx,
-                            &m.iter().filter_map(|r| {
-                                default(cx, r.as_slice())
-                            }).collect::<matrix>(),
-                            v.tail()) {
-              useful_ => useful(left_ty, ctor),
-              u => u,
+    let left_ty = if real_pat.id == 0 {
+        ty::mk_nil()
+    } else {
+        ty::pat_ty(cx.tcx, &*real_pat)
+    };
+
+    match pat_ctor_id(cx, left_ty, v[0]) {
+        None => match missing_constructor(cx, m, left_ty) {
+            None => {
+                all_constructors(cx, m, left_ty).move_iter().filter_map(|c| {
+                    is_useful_specialized(cx, m, v, c.clone(),
+                                          left_ty, witness).useful().map(|pats| {
+                        Useful(match witness {
+                            ConstructWitness => {
+                                let arity = constructor_arity(cx, &c, left_ty);
+                                let subpats = {
+                                    let pat_slice = pats.as_slice();
+                                    Vec::from_fn(arity, |i| {
+                                        pat_slice.get(i).map(|p| p.clone())
+                                            .unwrap_or_else(|| wild())
+                                    })
+                                };
+                                let mut result = vec!(construct_witness(cx, &c, subpats, left_ty));
+                                result.extend(pats.move_iter().skip(arity));
+                                result
+                            }
+                            LeaveOutWitness => vec!()
+                        })
+                    })
+                }).nth(0).unwrap_or(NotUseful)
+            },
+
+            Some(ctor) => {
+                let matrix = m.iter().filter_map(|r| default(cx, r.as_slice())).collect();
+                match is_useful(cx, &matrix, v.tail(), witness) {
+                    Useful(pats) => Useful(match witness {
+                        ConstructWitness => {
+                            let arity = constructor_arity(cx, &ctor, left_ty);
+                            let wild_pats = Vec::from_elem(arity, wild());
+                            let enum_pat = construct_witness(cx, &ctor, wild_pats, left_ty);
+                            (vec!(enum_pat)).append(pats.as_slice())
+                        }
+                        LeaveOutWitness => vec!()
+                    }),
+                    result => result
+                }
             }
-          }
-        }
-      }
-      Some(v0_ctor) => {
-        let arity = ctor_arity(cx, &v0_ctor, left_ty);
-        is_useful_specialized(cx, m, v, v0_ctor, arity, left_ty)
-      }
+        },
+
+        Some(v0_ctor) => is_useful_specialized(cx, m, v, v0_ctor, left_ty, witness)
     }
 }
 
-fn is_useful_specialized(cx: &MatchCheckCtxt,
-                             m: &matrix,
-                             v: &[Gc<Pat>],
-                             ctor: ctor,
-                             arity: uint,
-                             lty: ty::t)
-                             -> useful {
-    let ms = m.iter().filter_map(|r| {
-        specialize(cx, r.as_slice(), &ctor, arity, lty)
-    }).collect::<matrix>();
-    let could_be_useful = match specialize(cx, v, &ctor, arity, lty) {
-        Some(v) => is_useful(cx, &ms, v.as_slice()),
-        None => return not_useful,
-    };
-    match could_be_useful {
-      useful_ => useful(lty, ctor),
-      u => u,
+fn is_useful_specialized(cx: &MatchCheckCtxt, m: &Matrix, v: &[Gc<Pat>],
+                         ctor: ctor, lty: ty::t, witness: WitnessPreference) -> Usefulness {
+    let arity = constructor_arity(cx, &ctor, lty);
+    let matrix = m.iter().filter_map(|r| {
+        specialize(cx, r.as_slice(), &ctor, arity)
+    }).collect();
+    match specialize(cx, v, &ctor, arity) {
+        Some(v) => is_useful(cx, &matrix, v.as_slice(), witness),
+        None => NotUseful
     }
 }
 
-fn pat_ctor_id(cx: &MatchCheckCtxt, p: Gc<Pat>) -> Option<ctor> {
+fn pat_ctor_id(cx: &MatchCheckCtxt, left_ty: ty::t, p: Gc<Pat>) -> Option<ctor> {
     let pat = raw_pat(p);
     match pat.node {
-      PatWild | PatWildMulti => { None }
-      PatIdent(_, _, _) | PatEnum(_, _) => {
-        let opt_def = cx.tcx.def_map.borrow().find_copy(&pat.id);
-        match opt_def {
-          Some(DefVariant(_, id, _)) => Some(variant(id)),
-          Some(DefStatic(did, false)) => {
-            let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
-            Some(val(eval_const_expr(cx.tcx, &*const_expr)))
-          }
-          _ => None
-        }
-      }
-      PatLit(ref expr) => { Some(val(eval_const_expr(cx.tcx, &**expr))) }
-      PatRange(ref lo, ref hi) => {
-        Some(range(eval_const_expr(cx.tcx, &**lo), eval_const_expr(cx.tcx, &**hi)))
-      }
-      PatStruct(..) => {
-        match cx.tcx.def_map.borrow().find(&pat.id) {
-          Some(&DefVariant(_, id, _)) => Some(variant(id)),
-          _ => Some(single)
-        }
-      }
-      PatBox(_) | PatTup(_) | PatRegion(..) => {
-        Some(single)
-      }
-      PatVec(ref before, slice, ref after) => {
-        match slice {
-          Some(_) => None,
-          None => Some(vec(before.len() + after.len()))
-        }
-      }
-      PatMac(_) => cx.tcx.sess.bug("unexpanded macro"),
+        PatIdent(..) =>
+            match cx.tcx.def_map.borrow().find(&pat.id) {
+                Some(&DefStatic(did, false)) => {
+                    let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
+                    Some(val(eval_const_expr(cx.tcx, &*const_expr)))
+                },
+                Some(&DefVariant(_, id, is_structure)) => Some(variant(id, is_structure)),
+                _ => None
+            },
+        PatEnum(..) =>
+            match cx.tcx.def_map.borrow().find(&pat.id) {
+                Some(&DefStatic(did, false)) => {
+                    let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
+                    Some(val(eval_const_expr(cx.tcx, &*const_expr)))
+                },
+                Some(&DefVariant(_, id, is_structure)) => Some(variant(id, is_structure)),
+                _ => Some(single)
+            },
+        PatStruct(..) =>
+            match cx.tcx.def_map.borrow().find(&pat.id) {
+                Some(&DefVariant(_, id, is_structure)) => Some(variant(id, is_structure)),
+                _ => Some(single)
+            },
+        PatLit(expr) =>
+            Some(val(eval_const_expr(cx.tcx, &*expr))),
+        PatRange(lo, hi) =>
+            Some(range(eval_const_expr(cx.tcx, &*lo), eval_const_expr(cx.tcx, &*hi))),
+        PatVec(ref before, _, ref after) => match ty::get(left_ty).sty {
+            ty::ty_vec(_, Some(n)) =>
+                Some(vec(n)),
+            _ =>
+                Some(vec(before.len() + after.len()))
+        },
+        PatBox(_) | PatTup(_) | PatRegion(..) =>
+            Some(single),
+        PatWild | PatWildMulti =>
+            None,
+        PatMac(_) =>
+            cx.tcx.sess.bug("unexpanded macro")
     }
 }
 
 fn is_wild(cx: &MatchCheckCtxt, p: Gc<Pat>) -> bool {
     let pat = raw_pat(p);
     match pat.node {
-      PatWild | PatWildMulti => { true }
-      PatIdent(_, _, _) => {
-        match cx.tcx.def_map.borrow().find(&pat.id) {
-          Some(&DefVariant(_, _, _)) | Some(&DefStatic(..)) => { false }
-          _ => { true }
-        }
-      }
-      _ => { false }
-    }
-}
-
-fn missing_ctor(cx: &MatchCheckCtxt,
-                m: &matrix,
-                left_ty: ty::t)
-                -> Option<ctor> {
-    return match ty::get(left_ty).sty {
-      ty::ty_box(_) | ty::ty_tup(_) |
-      ty::ty_struct(..) => check_matrix_for_wild(cx, m),
-      ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty: ty, ..}) => match ty::get(ty).sty {
-          ty::ty_vec(_, None) => ctor_for_slice(m),
-          ty::ty_str => Some(single),
-          _ => check_matrix_for_wild(cx, m),
-      },
-      ty::ty_enum(eid, _) => {
-        let pat_ctors: Vec<ctor> = m
-          .iter()
-          .filter_map(|r| pat_ctor_id(cx, *r.get(0)))
-          .collect();
-        let variants = ty::enum_variants(cx.tcx, eid);
-        variants.iter().map(|v| variant(v.id)).find(|c| !pat_ctors.contains(c))
-      }
-      ty::ty_nil => None,
-      ty::ty_bool => {
-        let mut true_found = false;
-        let mut false_found = false;
-        for r in m.iter() {
-            match pat_ctor_id(cx, *r.get(0)) {
-              None => (),
-              Some(val(const_bool(true))) => true_found = true,
-              Some(val(const_bool(false))) => false_found = true,
-              _ => fail!("impossible case")
+        PatWild | PatWildMulti => true,
+        PatIdent(_, _, _) => {
+            match cx.tcx.def_map.borrow().find(&pat.id) {
+                Some(&DefVariant(_, _, _)) | Some(&DefStatic(..)) => false,
+                _ => true
             }
         }
-        if true_found && false_found { None }
-        else if true_found { Some(val(const_bool(false))) }
-        else { Some(val(const_bool(true))) }
-      }
-      ty::ty_vec(_, Some(n)) => {
-        let mut missing = true;
-        let mut wrong = false;
-        for r in m.iter() {
-          match r.get(0).node {
-            PatVec(ref before, ref slice, ref after) => {
-              let count = before.len() + after.len();
-              if (count < n && slice.is_none()) || count > n {
-                wrong = true;
-              }
-              if count == n || (count < n && slice.is_some()) {
-                missing = false;
-              }
-            }
-            _ => {}
-          }
-        }
-        match (wrong, missing) {
-          (true, _) => Some(vec(n)), // should be compile-time error
-          (_, true) => Some(vec(n)),
-          _         => None
-        }
-      }
-      ty::ty_vec(..) => fail!("impossible case"),
-      _ => Some(single)
-    };
-
-    fn check_matrix_for_wild(cx: &MatchCheckCtxt, m: &matrix) -> Option<ctor> {
-        for r in m.iter() {
-            if !is_wild(cx, *r.get(0)) { return None; }
-        }
-        return Some(single);
-    }
-
-    // For slice and ~[T].
-    fn ctor_for_slice(m: &matrix) -> Option<ctor> {
-        // Find the lengths and slices of all vector patterns.
-        let mut vec_pat_lens = m.iter().filter_map(|r| {
-            match r.get(0).node {
-                PatVec(ref before, ref slice, ref after) => {
-                    Some((before.len() + after.len(), slice.is_some()))
-                }
-                _ => None
-            }
-        }).collect::<Vec<(uint, bool)> >();
-
-        // Sort them by length such that for patterns of the same length,
-        // those with a destructured slice come first.
-        vec_pat_lens.sort_by(|&(len1, slice1), &(len2, slice2)| {
-                    if len1 == len2 {
-                        slice2.cmp(&slice1)
-                    } else {
-                        len1.cmp(&len2)
-                    }
-                });
-        vec_pat_lens.dedup();
-
-        let mut found_slice = false;
-        let mut next = 0;
-        let mut missing = None;
-        for &(length, slice) in vec_pat_lens.iter() {
-            if length != next {
-                missing = Some(next);
-                break;
-            }
-            if slice {
-                found_slice = true;
-                break;
-            }
-            next += 1;
-        }
-
-        // We found patterns of all lengths within <0, next), yet there was no
-        // pattern with a slice - therefore, we report vec(next) as missing.
-        if !found_slice {
-            missing = Some(next);
-        }
-        match missing {
-          Some(k) => Some(vec(k)),
-          None => None
-        }
+        _ => false
     }
 }
 
-fn ctor_arity(cx: &MatchCheckCtxt, ctor: &ctor, ty: ty::t) -> uint {
-    fn vec_ctor_arity(ctor: &ctor) -> uint {
-        match *ctor {
-            vec(n) => n,
-            _ => 0u
-        }
-    }
-
+fn constructor_arity(cx: &MatchCheckCtxt, ctor: &ctor, ty: ty::t) -> uint {
     match ty::get(ty).sty {
         ty::ty_tup(ref fs) => fs.len(),
-        ty::ty_box(_) => 1u,
-        ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty: ty, ..}) => match ty::get(ty).sty {
-            ty::ty_vec(_, None) => vec_ctor_arity(ctor),
-            _ => 1u,
+        ty::ty_box(_) | ty::ty_uniq(_) => 1u,
+        ty::ty_rptr(_, ty::mt { ty: ty, .. }) => match ty::get(ty).sty {
+            ty::ty_vec(_, None) => match *ctor {
+                vec(n) => n,
+                _ => 0u
+            },
+            ty::ty_str => 0u,
+            _ => 1u
         },
         ty::ty_enum(eid, _) => {
-            let id = match *ctor {
-                variant(id) => id,
-                _ => fail!("impossible case")
-            };
-            match ty::enum_variants(cx.tcx, eid).iter().find(|v| v.id == id ) {
-                Some(v) => v.args.len(),
-                None => fail!("impossible case")
+            match *ctor {
+                variant(id, _) => enum_variant_with_id(cx.tcx, eid, id).args.len(),
+                _ => unreachable!()
             }
         }
         ty::ty_struct(cid, _) => ty::lookup_struct_fields(cx.tcx, cid).len(),
-        ty::ty_vec(_, Some(_)) => vec_ctor_arity(ctor),
+        ty::ty_vec(_, _) => match *ctor {
+            vec(n) => n,
+            _ => 0u
+        },
         _ => 0u
     }
 }
@@ -553,10 +515,6 @@ fn wild() -> Gc<Pat> {
     box(GC) Pat {id: 0, node: PatWild, span: DUMMY_SP}
 }
 
-fn wild_multi() -> Gc<Pat> {
-    box(GC) Pat {id: 0, node: PatWildMulti, span: DUMMY_SP}
-}
-
 fn range_covered_by_constructor(ctor_id: &ctor, from: &const_val, to: &const_val) -> Option<bool> {
     let (c_from, c_to) = match *ctor_id {
         val(ref value)          => (value, value),
@@ -572,164 +530,150 @@ fn range_covered_by_constructor(ctor_id: &ctor, from: &const_val, to: &const_val
     }
 }
 
-fn specialize(cx: &MatchCheckCtxt,
-                  r: &[Gc<Pat>],
-                  ctor_id: &ctor,
-                  arity: uint,
-                  left_ty: ty::t)
-               -> Option<Vec<Gc<Pat>>> {
-    let &Pat{id: ref pat_id, node: ref n, span: ref pat_span} = &(*raw_pat(r[0]));
+fn specialize(cx: &MatchCheckCtxt, r: &[Gc<Pat>],
+              ctor_id: &ctor, arity: uint) -> Option<Vec<Gc<Pat>>> {
+    let &Pat {
+        id: ref pat_id, node: ref n, span: ref pat_span
+    } = &(*raw_pat(r[0]));
     let head: Option<Vec<Gc<Pat>>> = match n {
-            &PatWild => {
-                Some(Vec::from_elem(arity, wild()))
-            }
-            &PatWildMulti => {
-                Some(Vec::from_elem(arity, wild_multi()))
-            }
-            &PatIdent(_, _, _) => {
-                let opt_def = cx.tcx.def_map.borrow().find_copy(pat_id);
-                match opt_def {
-                    Some(DefVariant(_, id, _)) => {
-                        if variant(id) == *ctor_id {
-                            Some(vec!())
-                        } else {
+        &PatWild => {
+            Some(Vec::from_elem(arity, wild()))
+        }
+        &PatWildMulti => {
+            Some(Vec::from_elem(arity, wild()))
+        }
+        &PatIdent(_, _, _) => {
+            let opt_def = cx.tcx.def_map.borrow().find_copy(pat_id);
+            match opt_def {
+                Some(DefVariant(_, id, _)) => match *ctor_id {
+                    variant(vid, _) if vid == id => Some(vec!()),
+                    _ => None
+                },
+                Some(DefStatic(did, _)) => {
+                    let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
+                    let e_v = eval_const_expr(cx.tcx, &*const_expr);
+                    match range_covered_by_constructor(ctor_id, &e_v, &e_v) {
+                        Some(true) => Some(vec!()),
+                        Some(false) => None,
+                        None => {
+                            cx.tcx.sess.span_err(*pat_span, "mismatched types between arms");
                             None
                         }
                     }
-                    Some(DefStatic(did, _)) => {
-                        let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
-                        let e_v = eval_const_expr(cx.tcx, &*const_expr);
-                        match range_covered_by_constructor(ctor_id, &e_v, &e_v) {
-                           Some(true) => Some(vec!()),
-                           Some(false) => None,
-                           None => {
-                              cx.tcx.sess.span_err(*pat_span, "mismatched types between arms");
-                              None
-                           }
-                        }
-                    }
-                    _ => {
-                        Some(Vec::from_elem(arity, wild()))
-                    }
+                }
+                _ => {
+                    Some(Vec::from_elem(arity, wild()))
                 }
             }
-            &PatEnum(_, ref args) => {
-                let def = cx.tcx.def_map.borrow().get_copy(pat_id);
-                match def {
-                    DefStatic(did, _) => {
-                        let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
-                        let e_v = eval_const_expr(cx.tcx, &*const_expr);
-                        match range_covered_by_constructor(ctor_id, &e_v, &e_v) {
-                           Some(true) => Some(vec!()),
-                           Some(false) => None,
-                           None => {
-                              cx.tcx.sess.span_err(*pat_span, "mismatched types between arms");
-                              None
-                           }
+        }
+        &PatEnum(_, ref args) => {
+            let def = cx.tcx.def_map.borrow().get_copy(pat_id);
+            match def {
+                DefStatic(did, _) => {
+                    let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
+                    let e_v = eval_const_expr(cx.tcx, &*const_expr);
+                    match range_covered_by_constructor(ctor_id, &e_v, &e_v) {
+                        Some(true) => Some(vec!()),
+                        Some(false) => None,
+                        None => {
+                            cx.tcx.sess.span_err(*pat_span, "mismatched types between arms");
+                            None
                         }
                     }
-                    DefVariant(_, id, _) if variant(id) != *ctor_id => None,
-                    DefVariant(..) | DefFn(..) | DefStruct(..) => {
-                        Some(match args {
-                            &Some(ref args) => args.clone(),
-                            &None => Vec::from_elem(arity, wild())
-                        })
-                    }
-                    _ => None
                 }
+                DefVariant(_, id, _) if variant(id, false) != *ctor_id => None,
+                DefVariant(..) | DefFn(..) | DefStruct(..) => {
+                    Some(match args {
+                        &Some(ref args) => args.clone(),
+                        &None => Vec::from_elem(arity, wild())
+                    })
+                }
+                _ => None
             }
-            &PatStruct(_, ref pattern_fields, _) => {
-                // Is this a struct or an enum variant?
-                let def = cx.tcx.def_map.borrow().get_copy(pat_id);
-                let class_id = match def {
-                    DefVariant(_, variant_id, _) => {
-                      if variant(variant_id) == *ctor_id {
-                        Some(variant_id)
-                      } else {
-                        None
-                      }
-                    }
-                    _ => {
-                        match ty::get(left_ty).sty {
-                            ty::ty_struct(cid, _) => Some(cid),
-                            _ => {
-                                cx.tcx.sess.span_bug(
-                                    *pat_span,
-                                    format!("struct pattern resolved to {}, \
-                                          not a struct",
-                                         ty_to_str(cx.tcx,
-                                                   left_ty)).as_slice());
-                            }
-                        }
+        }
+
+        &PatStruct(_, ref pattern_fields, _) => {
+            // Is this a struct or an enum variant?
+            let def = cx.tcx.def_map.borrow().get_copy(pat_id);
+            let class_id = match def {
+                DefVariant(_, variant_id, _) => if *ctor_id == variant(variant_id, true) {
+                    Some(variant_id)
+                } else {
+                    None
+                },
+                DefStruct(struct_id) => Some(struct_id),
+                _ => None
+            };
+            class_id.map(|variant_id| {
+                let struct_fields = ty::lookup_struct_fields(cx.tcx, variant_id);
+                let args = struct_fields.iter().map(|sf| {
+                    match pattern_fields.iter().find(|f| f.ident.name == sf.name) {
+                        Some(f) => f.pat,
+                        _ => wild()
                     }
-                };
-                class_id.map(|variant_id| {
-                  let struct_fields = ty::lookup_struct_fields(cx.tcx, variant_id);
-                  let args = struct_fields.iter().map(|sf| {
-                      match pattern_fields.iter().find(|f| f.ident.name == sf.name) {
-                          Some(f) => f.pat,
-                          _ => wild()
-                      }
-                  }).collect();
-                  args
-                })
+                }).collect();
+                args
+            })
+        }
 
-            }
-            &PatTup(ref args) => {
-                Some(args.clone())
-            }
-            &PatBox(ref inner) | &PatRegion(ref inner) => {
-                Some(vec!(inner.clone()))
-            }
-            &PatLit(ref expr) => {
-              let expr_value = eval_const_expr(cx.tcx, &**expr);
-              match range_covered_by_constructor(ctor_id, &expr_value, &expr_value) {
-                 Some(true) => Some(vec!()),
-                 Some(false) => None,
-                 None => {
+        &PatTup(ref args) =>
+            Some(args.clone()),
+
+        &PatBox(ref inner) | &PatRegion(ref inner) =>
+            Some(vec!(inner.clone())),
+
+        &PatLit(ref expr) => {
+            let expr_value = eval_const_expr(cx.tcx, &**expr);
+            match range_covered_by_constructor(ctor_id, &expr_value, &expr_value) {
+                Some(true) => Some(vec!()),
+                Some(false) => None,
+                None => {
                     cx.tcx.sess.span_err(*pat_span, "mismatched types between arms");
                     None
-                 }
-              }
+                }
             }
-            &PatRange(ref from, ref to) => {
-              let from_value = eval_const_expr(cx.tcx, &**from);
-              let to_value = eval_const_expr(cx.tcx, &**to);
-              match range_covered_by_constructor(ctor_id, &from_value, &to_value) {
-                 Some(true) => Some(vec!()),
-                 Some(false) => None,
-                 None => {
+        }
+
+        &PatRange(ref from, ref to) => {
+            let from_value = eval_const_expr(cx.tcx, &**from);
+            let to_value = eval_const_expr(cx.tcx, &**to);
+            match range_covered_by_constructor(ctor_id, &from_value, &to_value) {
+                Some(true) => Some(vec!()),
+                Some(false) => None,
+                None => {
                     cx.tcx.sess.span_err(*pat_span, "mismatched types between arms");
                     None
-                 }
-              }
+                }
             }
-            &PatVec(ref before, ref slice, ref after) => {
-                match *ctor_id {
-                    vec(_) => {
-                        let num_elements = before.len() + after.len();
-                        if num_elements < arity && slice.is_some() {
-                            let mut result = Vec::new();
-                            result.push_all(before.as_slice());
-                            result.grow_fn(arity - num_elements, |_| wild());
-                            result.push_all(after.as_slice());
-                            Some(result)
-                        } else if num_elements == arity {
-                            let mut result = Vec::new();
-                            result.push_all(before.as_slice());
-                            result.push_all(after.as_slice());
-                            Some(result)
-                        } else {
-                            None
-                        }
+        }
+
+        &PatVec(ref before, ref slice, ref after) => {
+            match *ctor_id {
+                vec(_) => {
+                    let num_elements = before.len() + after.len();
+                    if num_elements < arity && slice.is_some() {
+                        let mut result = Vec::new();
+                        result.push_all(before.as_slice());
+                        result.grow_fn(arity - num_elements, |_| wild());
+                        result.push_all(after.as_slice());
+                        Some(result)
+                    } else if num_elements == arity {
+                        let mut result = Vec::new();
+                        result.push_all(before.as_slice());
+                        result.push_all(after.as_slice());
+                        Some(result)
+                    } else {
+                        None
                     }
-                    _ => None
                 }
+                _ => None
             }
-            &PatMac(_) => {
-                cx.tcx.sess.span_err(*pat_span, "unexpanded macro");
-                None
-            }
+        }
+
+        &PatMac(_) => {
+            cx.tcx.sess.span_err(*pat_span, "unexpanded macro");
+            None
+        }
     };
     head.map(|head| head.append(r.tail()))
 }
@@ -750,12 +694,15 @@ fn check_local(cx: &mut MatchCheckCtxt, loc: &Local) {
         LocalFor => "`for` loop"
     };
 
-    let mut spans = vec![];
-    find_refutable(cx, &*loc.pat, &mut spans);
-
-    for span in spans.iter() {
-        cx.tcx.sess.span_err(*span,
-                             format!("refutable pattern in {} binding", name).as_slice());
+    match is_refutable(cx, loc.pat) {
+        Some(pat) => {
+            let msg = format!(
+                "refutable pattern in {} binding: `{}` not covered",
+                name, pat_to_str(&*pat)
+            );
+            cx.tcx.sess.span_err(loc.pat.span, msg.as_slice());
+        },
+        None => ()
     }
 
     // Check legality of move bindings.
@@ -769,67 +716,27 @@ fn check_fn(cx: &mut MatchCheckCtxt,
             sp: Span) {
     visit::walk_fn(cx, kind, decl, body, sp, ());
     for input in decl.inputs.iter() {
-        let mut spans = vec![];
-        find_refutable(cx, &*input.pat, &mut spans);
-
-        for span in spans.iter() {
-            cx.tcx.sess.span_err(*span,
-                                 "refutable pattern in function argument");
+        match is_refutable(cx, input.pat) {
+            Some(pat) => {
+                let msg = format!(
+                    "refutable pattern in function argument: `{}` not covered",
+                    pat_to_str(&*pat)
+                );
+                cx.tcx.sess.span_err(input.pat.span, msg.as_slice());
+            },
+            None => ()
         }
     }
 }
 
-fn find_refutable(cx: &MatchCheckCtxt, pat: &Pat, spans: &mut Vec<Span>) {
-    macro_rules! this_pattern {
-        () => {
-            {
-                spans.push(pat.span);
-                return
-            }
-        }
-    }
-    let opt_def = cx.tcx.def_map.borrow().find_copy(&pat.id);
-    match opt_def {
-      Some(DefVariant(enum_id, _, _)) => {
-        if ty::enum_variants(cx.tcx, enum_id).len() != 1u {
-            this_pattern!()
-        }
-      }
-      Some(DefStatic(..)) => this_pattern!(),
-      _ => ()
-    }
-
-    match pat.node {
-      PatBox(ref sub) | PatRegion(ref sub) | PatIdent(_, _, Some(ref sub)) => {
-        find_refutable(cx, &**sub, spans)
-      }
-      PatWild | PatWildMulti | PatIdent(_, _, None) => {}
-      PatLit(lit) => {
-          match lit.node {
-            ExprLit(lit) => {
-                match lit.node {
-                    LitNil => {}    // `()`
-                    _ => this_pattern!(),
-                }
-            }
-            _ => this_pattern!(),
-          }
-      }
-      PatRange(_, _) => { this_pattern!() }
-      PatStruct(_, ref fields, _) => {
-          for f in fields.iter() {
-              find_refutable(cx, &*f.pat, spans);
-          }
-      }
-      PatTup(ref elts) | PatEnum(_, Some(ref elts))=> {
-          for elt in elts.iter() {
-              find_refutable(cx, &**elt, spans)
-          }
-      }
-      PatEnum(_,_) => {}
-      PatVec(..) => { this_pattern!() }
-      PatMac(_) => cx.tcx.sess.bug("unexpanded macro"),
-    }
+fn is_refutable(cx: &MatchCheckCtxt, pat: Gc<Pat>) -> Option<Gc<Pat>> {
+    let pats = vec!(vec!(pat));
+    is_useful(cx, &pats, [wild()], ConstructWitness)
+        .useful()
+        .map(|pats| {
+            assert_eq!(pats.len(), 1);
+            pats.get(0).clone()
+        })
 }
 
 // Legality of move bindings checking
index bf42f76f1a2769853ddeb928313d3b96bdd86813..c2a19bb43c8337ab3895ad7f19e354896360d05b 100644 (file)
@@ -372,7 +372,8 @@ pub enum LintSource {
      LintSpec {
         lint: Experimental,
         desc: "detects use of #[experimental] items",
-        default: Warn
+        // FIXME #6875: Change to Warn after std library stabilization is complete
+        default: Allow
     }),
 
     ("unstable",
@@ -1661,6 +1662,8 @@ fn check_missing_doc_variant(cx: &Context, v: &ast::Variant) {
 /// Checks for use of items with #[deprecated], #[experimental] and
 /// #[unstable] (or none of them) attributes.
 fn check_stability(cx: &Context, e: &ast::Expr) {
+    let tcx = cx.tcx;
+
     let id = match e.node {
         ast::ExprPath(..) | ast::ExprStruct(..) => {
             match cx.tcx.def_map.borrow().find(&e.id) {
@@ -1670,7 +1673,7 @@ fn check_stability(cx: &Context, e: &ast::Expr) {
         }
         ast::ExprMethodCall(..) => {
             let method_call = typeck::MethodCall::expr(e.id);
-            match cx.tcx.method_map.borrow().find(&method_call) {
+            match tcx.method_map.borrow().find(&method_call) {
                 Some(method) => {
                     match method.origin {
                         typeck::MethodStatic(def_id) => {
@@ -1678,8 +1681,8 @@ fn check_stability(cx: &Context, e: &ast::Expr) {
                             // of the method inside trait definition.
                             // Otherwise, use the current def_id (which refers
                             // to the method inside impl).
-                            ty::trait_method_of_method(
-                                cx.tcx, def_id).unwrap_or(def_id)
+                            ty::trait_method_of_method(cx.tcx, def_id)
+                               .unwrap_or(def_id)
                         }
                         typeck::MethodParam(typeck::MethodParam {
                             trait_id: trait_id,
@@ -1699,32 +1702,11 @@ fn check_stability(cx: &Context, e: &ast::Expr) {
         _ => return
     };
 
-    let stability = if ast_util::is_local(id) {
-        // this crate
-        let s = cx.tcx.map.with_attrs(id.node, |attrs| {
-            attrs.map(|a| attr::find_stability(a.as_slice()))
-        });
-        match s {
-            Some(s) => s,
+    // stability attributes are promises made across crates; do not
+    // check anything for crate-local usage.
+    if ast_util::is_local(id) { return }
 
-            // no possibility of having attributes
-            // (e.g. it's a local variable), so just
-            // ignore it.
-            None => return
-        }
-    } else {
-        // cross-crate
-
-        let mut s = None;
-        // run through all the attributes and take the first
-        // stability one.
-        csearch::get_item_attrs(&cx.tcx.sess.cstore, id, |attrs| {
-            if s.is_none() {
-                s = attr::find_stability(attrs.as_slice())
-            }
-        });
-        s
-    };
+    let stability = tcx.stability.borrow_mut().lookup(&tcx.sess.cstore, id);
 
     let (lint, label) = match stability {
         // no stability attributes == Unstable
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
new file mode 100644 (file)
index 0000000..fc76648
--- /dev/null
@@ -0,0 +1,125 @@
+// Copyright 2014 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.
+
+//! A pass that annotates every item and method with its stability level,
+//! propagating default levels lexically from parent to children ast nodes.
+
+use util::nodemap::{NodeMap, DefIdMap};
+use syntax::codemap::Span;
+use syntax::{attr, visit};
+use syntax::ast::{Attribute, Block, Crate, DefId, FnDecl, NodeId, Variant};
+use syntax::ast::{Item, Required, Provided, TraitMethod, TypeMethod, Method};
+use syntax::ast::{Generics, StructDef, Ident};
+use syntax::ast_util::is_local;
+use syntax::attr::Stability;
+use syntax::visit::{FnKind, FkMethod, Visitor};
+use metadata::{cstore, csearch};
+
+/// A stability index, giving the stability level for items and methods.
+pub struct Index {
+    // stability for crate-local items; unmarked stability == no entry
+    local: NodeMap<Stability>,
+    // cache for extern-crate items; unmarked stability == entry with None
+    extern_cache: DefIdMap<Option<Stability>>
+}
+
+// A private tree-walker for producing an Index.
+struct Annotator {
+    index: Index
+}
+
+impl Annotator {
+    // Determine the stability for a node based on its attributes and inherited
+    // stability. The stability is recorded in the index and returned.
+    fn annotate(&mut self, id: NodeId, attrs: &[Attribute],
+                parent: Option<Stability>) -> Option<Stability> {
+        match attr::find_stability(attrs).or(parent) {
+            Some(stab) => {
+                self.index.local.insert(id, stab.clone());
+                Some(stab)
+            }
+            None => None
+        }
+    }
+}
+
+impl Visitor<Option<Stability>> for Annotator {
+    fn visit_item(&mut self, i: &Item, parent: Option<Stability>) {
+        let stab = self.annotate(i.id, i.attrs.as_slice(), parent);
+        visit::walk_item(self, i, stab)
+    }
+
+    fn visit_fn(&mut self, fk: &FnKind, fd: &FnDecl, b: &Block,
+                s: Span, _: NodeId, parent: Option<Stability>) {
+        let stab = match *fk {
+            FkMethod(_, _, meth) =>
+                self.annotate(meth.id, meth.attrs.as_slice(), parent),
+            _ => parent
+        };
+        visit::walk_fn(self, fk, fd, b, s, stab)
+    }
+
+    fn visit_trait_method(&mut self, t: &TraitMethod, parent: Option<Stability>) {
+        let stab = match *t {
+            Required(TypeMethod {attrs: ref attrs, id: id, ..}) =>
+                self.annotate(id, attrs.as_slice(), parent),
+
+            // work around lack of pattern matching for @ types
+            Provided(method) => match *method {
+                Method {attrs: ref attrs, id: id, ..} =>
+                    self.annotate(id, attrs.as_slice(), parent)
+            }
+        };
+        visit::walk_trait_method(self, t, stab)
+    }
+
+    fn visit_variant(&mut self, v: &Variant, g: &Generics, parent: Option<Stability>) {
+        let stab = self.annotate(v.node.id, v.node.attrs.as_slice(), parent);
+        visit::walk_variant(self, v, g, stab)
+    }
+
+    fn visit_struct_def(&mut self, s: &StructDef, _: Ident, _: &Generics,
+                        _: NodeId, parent: Option<Stability>) {
+        s.ctor_id.map(|id| self.annotate(id, &[], parent.clone()));
+        visit::walk_struct_def(self, s, parent)
+    }
+}
+
+impl Index {
+    /// Construct the stability index for a crate being compiled.
+    pub fn build(krate: &Crate) -> Index {
+        let mut annotator = Annotator {
+            index: Index {
+                local: NodeMap::new(),
+                extern_cache: DefIdMap::new()
+            }
+        };
+        visit::walk_crate(&mut annotator, krate,
+                          attr::find_stability(krate.attrs.as_slice()));
+        annotator.index
+    }
+
+    /// Lookup the stability for a node, loading external crate
+    /// metadata as necessary.
+    pub fn lookup(&mut self, cstore: &cstore::CStore, id: DefId) -> Option<Stability> {
+        if is_local(id) {
+            self.lookup_local(id.node)
+        } else {
+            let stab = csearch::get_stability(cstore, id);
+            self.extern_cache.insert(id, stab.clone());
+            stab
+        }
+    }
+
+    /// Lookup the stability for a local node without loading any external crates
+    pub fn lookup_local(&self, id: NodeId) -> Option<Stability> {
+        self.local.find_copy(&id)
+    }
+}
index ffd29ffeb8fb42797b013d5430aea9bc402d6226..5b9c89f6250931f4f8a8713263bebcaeb776e1e4 100644 (file)
@@ -988,8 +988,7 @@ fn extract_vec_elems<'a>(
                      pat_id: ast::NodeId,
                      elem_count: uint,
                      slice: Option<uint>,
-                     val: ValueRef,
-                     count: ValueRef)
+                     val: ValueRef)
                      -> ExtractedBlock<'a> {
     let _icx = push_ctxt("match::extract_vec_elems");
     let vec_datum = match_datum(bcx, val, pat_id);
@@ -1003,7 +1002,7 @@ fn extract_vec_elems<'a>(
             Some(n) if i < n => GEPi(bcx, base, [i]),
             Some(n) if i > n => {
                 InBoundsGEP(bcx, base, [
-                    Sub(bcx, count,
+                    Sub(bcx, len,
                         C_int(bcx.ccx(), (elem_count - i) as int))])
             }
             _ => unsafe { llvm::LLVMGetUndef(vt.llunit_ty.to_ref()) }
@@ -1765,7 +1764,7 @@ fn compile_submatch_continue<'a, 'b>(
                     vec_len_eq => (n, None)
                 };
                 let args = extract_vec_elems(opt_cx, pat_id, n,
-                                             slice, val, test_val);
+                                             slice, val);
                 size = args.vals.len();
                 unpacked = args.vals.clone();
                 opt_cx = args.bcx;
@@ -2264,9 +2263,21 @@ fn bind_irrefutable_pat<'a>(
             let loaded_val = Load(bcx, val);
             bcx = bind_irrefutable_pat(bcx, inner, loaded_val, binding_mode, cleanup_scope);
         }
-        ast::PatVec(..) => {
-            bcx.sess().span_bug(pat.span,
-                                "vector patterns are never irrefutable!");
+        ast::PatVec(ref before, ref slice, ref after) => {
+            let extracted = extract_vec_elems(
+                bcx, pat.id, before.len() + 1u + after.len(),
+                slice.map(|_| before.len()), val
+            );
+            bcx = before
+                .iter().map(|v| Some(*v))
+                .chain(Some(*slice).move_iter())
+                .chain(after.iter().map(|v| Some(*v)))
+                .zip(extracted.vals.iter())
+                .fold(bcx, |bcx, (inner, elem)| {
+                    inner.map_or(bcx, |inner| {
+                        bind_irrefutable_pat(bcx, inner, *elem, binding_mode, cleanup_scope)
+                    })
+                });
         }
         ast::PatMac(..) => {
             bcx.sess().span_bug(pat.span, "unexpanded macro");
index c4e48bea85e0a49a6fad948a8b7b8b77aba6b2f0..c5e84b8e0c8f01736bce5e0348e970132193fa87 100644 (file)
@@ -25,6 +25,7 @@
 use middle::resolve_lifetime;
 use middle::subst;
 use middle::subst::{Subst, Substs, VecPerParamSpace};
+use middle::stability;
 use middle::ty;
 use middle::typeck;
 use middle::typeck::MethodCall;
@@ -373,6 +374,9 @@ pub struct ctxt {
     /// to be valid. We gather up these restrictions in the intrinsicck pass
     /// and check them in trans.
     pub transmute_restrictions: RefCell<Vec<TransmuteRestriction>>,
+
+    /// Maps any item's def-id to its stability index.
+    pub stability: RefCell<stability::Index>,
 }
 
 pub enum tbox_flag {
@@ -1065,7 +1069,8 @@ pub fn mk_ctxt(s: Session,
                map: ast_map::Map,
                freevars: freevars::freevar_map,
                region_maps: middle::region::RegionMaps,
-               lang_items: middle::lang_items::LanguageItems)
+               lang_items: middle::lang_items::LanguageItems,
+               stability: stability::Index)
             -> ctxt {
     ctxt {
         named_region_map: named_region_map,
@@ -1119,6 +1124,7 @@ pub fn mk_ctxt(s: Session,
         dependency_formats: RefCell::new(HashMap::new()),
         node_lint_levels: RefCell::new(HashMap::new()),
         transmute_restrictions: RefCell::new(Vec::new()),
+        stability: RefCell::new(stability)
     }
 }
 
index edb77e04b30786825ab507c5a5af0a9e58747cd2..e198653165a61a5e1216ae67cd66ee83a7e9e766 100644 (file)
@@ -632,9 +632,9 @@ pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) {
             fcx.infcx().next_region_var(
                 infer::PatternRegion(pat.span));
 
-        let check_err = || {
-            for elt in before.iter() {
-                check_pat(pcx, &**elt, ty::mk_err());
+        let check_err = |found: String| {
+            for &elt in before.iter() {
+                check_pat(pcx, &*elt, ty::mk_err());
             }
             for elt in slice.iter() {
                 check_pat(pcx, &**elt, ty::mk_err());
@@ -653,15 +653,16 @@ pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) {
                     })
                 },
                 Some(expected),
-                "a vector pattern".to_string(),
+                found,
                 None);
             fcx.write_error(pat.id);
         };
 
-        let (elt_type, region_var, mutbl) = match *structure_of(fcx,
+        let (elt_type, region_var, mutbl, fixed) = match *structure_of(fcx,
                                                                 pat.span,
                                                                 expected) {
-          ty::ty_vec(mt, Some(_)) => (mt.ty, default_region_var, ast::MutImmutable),
+          ty::ty_vec(mt, Some(fixed)) =>
+            (mt.ty, default_region_var, ast::MutImmutable, Some(fixed)),
           ty::ty_uniq(t) => match ty::get(t).sty {
               ty::ty_vec(mt, None) => {
                   fcx.type_error_message(pat.span,
@@ -671,25 +672,37 @@ pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) {
                                          },
                                          expected,
                                          None);
-                  (mt.ty, default_region_var, ast::MutImmutable)
+                  (mt.ty, default_region_var, ast::MutImmutable, None)
               }
               _ => {
-                  check_err();
+                  check_err("a vector pattern".to_string());
                   return;
               }
           },
           ty::ty_rptr(r, mt) => match ty::get(mt.ty).sty {
-              ty::ty_vec(mt, None) => (mt.ty, r, mt.mutbl),
+              ty::ty_vec(mt, None) => (mt.ty, r, mt.mutbl, None),
               _ => {
-                  check_err();
+                  check_err("a vector pattern".to_string());
                   return;
               }
           },
           _ => {
-              check_err();
+              check_err("a vector pattern".to_string());
               return;
           }
         };
+
+        let min_len = before.len() + after.len();
+        fixed.and_then(|count| match slice {
+            Some(_) if count < min_len =>
+                Some(format!("a fixed vector pattern of size at least {}", min_len)),
+
+            None if count != min_len =>
+                Some(format!("a fixed vector pattern of size {}", min_len)),
+
+            _ => None
+        }).map(check_err);
+
         for elt in before.iter() {
             check_pat(pcx, &**elt, elt_type);
         }
index c461dccceff025b7c2a090570cf162ec6f960344..f5521886f52df2e70b9b15b374497f94f60d2564 100644 (file)
 #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
        html_favicon_url = "http://www.rust-lang.org/favicon.ico",
        html_root_url = "http://doc.rust-lang.org/")]
-#![feature(macro_rules, phase, globs, thread_local, managed_boxes, asm,
-           linkage)]
+
+#![feature(macro_rules, phase, globs, thread_local, managed_boxes, asm)]
+#![feature(linkage, unsafe_destructor)]
 #![no_std]
 #![experimental]
+#![allow(unknown_features)] // NOTE: remove after a stage0 snap
 
 #[phase(plugin, link)] extern crate core;
 extern crate alloc;
index dae94acb6f0af6b1e780d1a8d5ba2caa285a991e..74caf86a6310242832f360dbb893eb7a61792cc7 100644 (file)
@@ -40,7 +40,7 @@
 #![crate_type = "rlib"]
 #![crate_type = "dylib"]
 
-#![feature(macro_rules)]
+#![feature(macro_rules, unsafe_destructor)]
 #![deny(unused_result, unused_must_use)]
 #![allow(visible_private_types)]
 
index 695c61efcf07a75e9dabc704caac553c334b9e06..a99fa016aef1d3cff0cfe3d1d96742f8fdc2e424 100644 (file)
        html_favicon_url = "http://www.rust-lang.org/favicon.ico",
        html_root_url = "http://doc.rust-lang.org/",
        html_playground_url = "http://play.rust-lang.org/")]
-#![feature(macro_rules, globs, managed_boxes,
-           linkage, default_type_params, phase)]
+
+#![feature(macro_rules, globs, managed_boxes)]
+#![feature(linkage, default_type_params, phase, unsafe_destructor)]
 
 // Don't link to std. We are std.
 #![no_std]
 
 #![allow(deprecated)]
 #![deny(missing_doc)]
+#![allow(unknown_features)] // NOTE: remove after a stage0 snap
 
 // When testing libstd, bring in libuv as the I/O backend so tests can print
 // things and all of the std::io tests have an I/O interface to run on top
index 1336ea48d31501225d4e41ea503651f7665af9fa..a2f22bcaa681682ff43ce01cbf27c195688a139c 100644 (file)
        html_favicon_url = "http://www.rust-lang.org/favicon.ico",
        html_root_url = "http://doc.rust-lang.org/",
        html_playground_url = "http://play.rust-lang.org/")]
-#![feature(phase, globs, macro_rules)]
 
+#![feature(phase, globs, macro_rules, unsafe_destructor)]
 #![deny(missing_doc)]
 #![no_std]
+#![allow(unknown_features)] // NOTE: remove after a stage0 snap
 
 #[phase(plugin, link)] extern crate core;
 extern crate alloc;
index 18a91fe465ec53bc37d0bd40a145a76da08f6fcc..a037c0ac07e0e14864a0612ac902c60ec8208f6a 100644 (file)
@@ -361,13 +361,14 @@ pub fn test_cfg<AM: AttrMetaMethods, It: Iterator<AM>>
 }
 
 /// Represents the #[deprecated="foo"] and friends attributes.
+#[deriving(Encodable,Decodable,Clone,Show)]
 pub struct Stability {
     pub level: StabilityLevel,
     pub text: Option<InternedString>
 }
 
 /// The available stability levels.
-#[deriving(PartialEq,PartialOrd,Clone,Show)]
+#[deriving(Encodable,Decodable,PartialEq,PartialOrd,Clone,Show)]
 pub enum StabilityLevel {
     Deprecated,
     Experimental,
index b18e3a221f9f359576ac8bd46433875a7bb6a582..1fbc6e41e55c9b032a728fad75dab0f42bfc3d78 100644 (file)
        html_favicon_url = "http://www.rust-lang.org/favicon.ico",
        html_root_url = "http://doc.rust-lang.org/")]
 
-#![feature(macro_rules, globs, managed_boxes, default_type_params, phase,
-           quote)]
+#![feature(macro_rules, globs, managed_boxes, default_type_params, phase)]
+#![feature(quote, unsafe_destructor)]
 #![allow(deprecated)]
+#![allow(unknown_features)] // NOTE: remove after a stage0 snap
 
 extern crate serialize;
 extern crate term;
index 158a8c5a11607a849ebc8469419a267dec8b5719..043ce3bf5b07e75650366bc80b56f7a46044743e 100644 (file)
@@ -706,6 +706,16 @@ pub fn expect_gt(&mut self) {
                 let lo = span.lo + BytePos(1);
                 self.replace_token(token::GT, lo, span.hi)
             }
+            token::BINOPEQ(token::SHR) => {
+                let span = self.span;
+                let lo = span.lo + BytePos(1);
+                self.replace_token(token::GE, lo, span.hi)
+            }
+            token::GE => {
+                let span = self.span;
+                let lo = span.lo + BytePos(1);
+                self.replace_token(token::EQ, lo, span.hi)
+            }
             _ => {
                 let gt_str = Parser::token_to_str(&token::GT);
                 let this_token_str = self.this_token_to_str();
@@ -726,7 +736,9 @@ pub fn parse_seq_to_before_gt<T>(
         let mut first = true;
         let mut v = Vec::new();
         while self.token != token::GT
-            && self.token != token::BINOP(token::SHR) {
+            && self.token != token::BINOP(token::SHR)
+            && self.token != token::GE
+            && self.token != token::BINOPEQ(token::SHR) {
             match sep {
               Some(ref t) => {
                 if first { first = false; }
diff --git a/src/test/auxiliary/inherited_stability.rs b/src/test/auxiliary/inherited_stability.rs
new file mode 100644 (file)
index 0000000..af3dd94
--- /dev/null
@@ -0,0 +1,51 @@
+// Copyright 2014 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.
+#![crate_id="inherited_stability#0.1"]
+#![crate_type = "lib"]
+#![experimental]
+
+pub fn experimental() {}
+
+#[stable]
+pub fn stable() {}
+
+#[stable]
+pub mod stable_mod {
+    #[experimental]
+    pub fn experimental() {}
+
+    pub fn stable() {}
+}
+
+pub mod experimental_mod {
+    pub fn experimental() {}
+
+    #[stable]
+    pub fn stable() {}
+}
+
+#[stable]
+pub trait Stable {
+    #[experimental]
+    fn experimental(&self);
+
+    fn stable(&self);
+}
+
+impl Stable for uint {
+    fn experimental(&self) {}
+    fn stable(&self) {}
+}
+
+pub enum Experimental {
+    ExperimentalVariant,
+    #[stable]
+    StableVariant
+}
index 8d096a9b7e793a6a7b069ddd4e239b9730b66e5c..c6ca0f3ed7bdda799a50543bcc6d27a6a24f17d5 100644 (file)
@@ -11,6 +11,8 @@
 #![crate_id="issue_2526#0.2"]
 #![crate_type = "lib"]
 
+#![feature(unsafe_destructor)]
+
 struct arc_destruct<T> {
   _data: int,
 }
diff --git a/src/test/auxiliary/lint_output_format.rs b/src/test/auxiliary/lint_output_format.rs
new file mode 100755 (executable)
index 0000000..00500da
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2014 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.
+
+#![crate_id="lint_output_format#0.1"]
+#![crate_type = "lib"]
+
+#[deprecated]
+pub fn foo() -> uint {
+    20
+}
+
+#[experimental]
+pub fn bar() -> uint {
+    40
+}
+
+#[unstable]
+pub fn baz() -> uint {
+    30
+}
index 037a326880f004de41eabc2480802ca9ea56d377..a3d788238161da439dd0dbde797c8d7a92000a55 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(managed_boxes)]
+#![feature(managed_boxes, unsafe_destructor)]
 
 extern crate collections;
 extern crate time;
index 6f385a8d1eb5e71282cc66f7492cd46cc5c5f1ed..081dc61d9fc974438f12efe04a46d96ab960d032 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(unsafe_destructor)]
+
 extern crate debug;
 
 struct defer<'a> {
diff --git a/src/test/compile-fail/issue-13482.rs b/src/test/compile-fail/issue-13482.rs
new file mode 100644 (file)
index 0000000..2b769b9
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2014 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() {
+  let x = [1,2];
+  let y = match x {
+    [] => None,
+//~^ ERROR expected `[<generic integer #1>, .. 2]` but found a fixed vector pattern of size 0
+    [a,_] => Some(a)
+  };
+}
index 40010b203aa9bc46393640cc93f56339cc99ec3c..3d9c7401ded24d92d4acc5c3dc511b086b0c8e51 100644 (file)
@@ -9,7 +9,8 @@
 // except according to those terms.
 
 fn foo(a: Option<uint>, b: Option<uint>) {
-  match (a,b) { //~ ERROR: non-exhaustive patterns: None not covered
+  match (a,b) {
+  //~^ ERROR: non-exhaustive patterns: `(None, None)` not covered
     (Some(a), Some(b)) if a == b => { }
     (Some(_), None) |
     (None, Some(_)) => { }
diff --git a/src/test/compile-fail/issue-4321.rs b/src/test/compile-fail/issue-4321.rs
new file mode 100644 (file)
index 0000000..d589680
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2014 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() {
+    let tup = (true, true);
+    println!("foo {:}", match tup { //~ ERROR non-exhaustive patterns: `(true, false)` not covered
+        (false, false) => "foo",
+        (false, true) => "bar",
+        (true, true) => "baz"
+    });
+}
index ba4cf5d17fb070036be4af4bfabaa9f266e7530b..db60002b468e11ae48a3fd358b7777383becd975 100644 (file)
@@ -9,21 +9,10 @@
 // except according to those terms.
 
 // compile-flags:-F experimental -D unstable
+// aux-build:lint_output_format.rs
 
-#[deprecated]
-fn foo() -> uint {
-    20
-}
-
-#[experimental]
-fn bar() -> uint {
-    40
-}
-
-#[unstable]
-fn baz() -> uint {
-    30
-}
+extern crate lint_output_format;
+use lint_output_format::{foo, bar, baz};
 
 fn main() {
     let _x = foo(); //~ WARNING #[warn(deprecated)] on by default
index 8509afc983284f16edf91a7c2db678842f383d21..5d06ad79c9bdfe5e33d394ecaf16e4bbf4bd2357 100644 (file)
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // aux-build:lint_stability.rs
+// aux-build:inherited_stability.rs
 
 #![feature(globs)]
 #![deny(unstable)]
@@ -21,7 +22,6 @@ mod cross_crate {
     use self::lint_stability::*;
 
     fn test() {
-        // FIXME: attributes on methods are not encoded cross crate.
         let foo = MethodTester;
 
         deprecated(); //~ ERROR use of deprecated item
@@ -133,6 +133,29 @@ fn test_method_object(foo: &Trait) {
     }
 }
 
+mod inheritance {
+    extern crate inherited_stability;
+    use self::inherited_stability::*;
+
+    fn test_inheritance() {
+        experimental(); //~ ERROR use of experimental item
+        stable();
+
+        stable_mod::experimental(); //~ ERROR use of experimental item
+        stable_mod::stable();
+
+        experimental_mod::experimental(); //~ ERROR use of experimental item
+        experimental_mod::stable();
+
+        let _ = ExperimentalVariant; //~ ERROR use of experimental item
+        let _ = StableVariant;
+
+        let x: uint = 0;
+        x.experimental(); //~ ERROR use of experimental item
+        x.stable();
+    }
+}
+
 mod this_crate {
     #[deprecated]
     pub fn deprecated() {}
@@ -299,35 +322,39 @@ pub enum Enum {
     pub struct LockedTupleStruct(int);
 
     fn test() {
+        // None of the following should generate errors, because
+        // stability attributes now have meaning only *across* crates,
+        // not within a single crate.
+
         let foo = MethodTester;
 
-        deprecated(); //~ ERROR use of deprecated item
-        foo.method_deprecated(); //~ ERROR use of deprecated item
-        foo.trait_deprecated(); //~ ERROR use of deprecated item
+        deprecated();
+        foo.method_deprecated();
+        foo.trait_deprecated();
 
-        deprecated_text(); //~ ERROR use of deprecated item: text
-        foo.method_deprecated_text(); //~ ERROR use of deprecated item: text
-        foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
+        deprecated_text();
+        foo.method_deprecated_text();
+        foo.trait_deprecated_text();
 
-        experimental(); //~ ERROR use of experimental item
-        foo.method_experimental(); //~ ERROR use of experimental item
-        foo.trait_experimental(); //~ ERROR use of experimental item
+        experimental();
+        foo.method_experimental();
+        foo.trait_experimental();
 
-        experimental_text(); //~ ERROR use of experimental item: text
-        foo.method_experimental_text(); //~ ERROR use of experimental item: text
-        foo.trait_experimental_text(); //~ ERROR use of experimental item: text
+        experimental_text();
+        foo.method_experimental_text();
+        foo.trait_experimental_text();
 
-        unstable(); //~ ERROR use of unstable item
-        foo.method_unstable(); //~ ERROR use of unstable item
-        foo.trait_unstable(); //~ ERROR use of unstable item
+        unstable();
+        foo.method_unstable();
+        foo.trait_unstable();
 
-        unstable_text(); //~ ERROR use of unstable item: text
-        foo.method_unstable_text(); //~ ERROR use of unstable item: text
-        foo.trait_unstable_text(); //~ ERROR use of unstable item: text
+        unstable_text();
+        foo.method_unstable_text();
+        foo.trait_unstable_text();
 
-        unmarked(); //~ ERROR use of unmarked item
-        foo.method_unmarked(); //~ ERROR use of unmarked item
-        foo.trait_unmarked(); //~ ERROR use of unmarked item
+        unmarked();
+        foo.method_unmarked();
+        foo.trait_unmarked();
 
         stable();
         foo.method_stable();
@@ -354,58 +381,58 @@ fn test() {
         foo.trait_locked_text();
 
 
-        let _ = DeprecatedStruct { i: 0 }; //~ ERROR use of deprecated item
-        let _ = ExperimentalStruct { i: 0 }; //~ ERROR use of experimental item
-        let _ = UnstableStruct { i: 0 }; //~ ERROR use of unstable item
-        let _ = UnmarkedStruct { i: 0 }; //~ ERROR use of unmarked item
+        let _ = DeprecatedStruct { i: 0 };
+        let _ = ExperimentalStruct { i: 0 };
+        let _ = UnstableStruct { i: 0 };
+        let _ = UnmarkedStruct { i: 0 };
         let _ = StableStruct { i: 0 };
         let _ = FrozenStruct { i: 0 };
         let _ = LockedStruct { i: 0 };
 
-        let _ = DeprecatedUnitStruct; //~ ERROR use of deprecated item
-        let _ = ExperimentalUnitStruct; //~ ERROR use of experimental item
-        let _ = UnstableUnitStruct; //~ ERROR use of unstable item
-        let _ = UnmarkedUnitStruct; //~ ERROR use of unmarked item
+        let _ = DeprecatedUnitStruct;
+        let _ = ExperimentalUnitStruct;
+        let _ = UnstableUnitStruct;
+        let _ = UnmarkedUnitStruct;
         let _ = StableUnitStruct;
         let _ = FrozenUnitStruct;
         let _ = LockedUnitStruct;
 
-        let _ = DeprecatedVariant; //~ ERROR use of deprecated item
-        let _ = ExperimentalVariant; //~ ERROR use of experimental item
-        let _ = UnstableVariant; //~ ERROR use of unstable item
-        let _ = UnmarkedVariant; //~ ERROR use of unmarked item
+        let _ = DeprecatedVariant;
+        let _ = ExperimentalVariant;
+        let _ = UnstableVariant;
+        let _ = UnmarkedVariant;
         let _ = StableVariant;
         let _ = FrozenVariant;
         let _ = LockedVariant;
 
-        let _ = DeprecatedTupleStruct (1); //~ ERROR use of deprecated item
-        let _ = ExperimentalTupleStruct (1); //~ ERROR use of experimental item
-        let _ = UnstableTupleStruct (1); //~ ERROR use of unstable item
-        let _ = UnmarkedTupleStruct (1); //~ ERROR use of unmarked item
+        let _ = DeprecatedTupleStruct (1);
+        let _ = ExperimentalTupleStruct (1);
+        let _ = UnstableTupleStruct (1);
+        let _ = UnmarkedTupleStruct (1);
         let _ = StableTupleStruct (1);
         let _ = FrozenTupleStruct (1);
         let _ = LockedTupleStruct (1);
     }
 
     fn test_method_param<F: Trait>(foo: F) {
-        foo.trait_deprecated(); //~ ERROR use of deprecated item
-        foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
-        foo.trait_experimental(); //~ ERROR use of experimental item
-        foo.trait_experimental_text(); //~ ERROR use of experimental item: text
-        foo.trait_unstable(); //~ ERROR use of unstable item
-        foo.trait_unstable_text(); //~ ERROR use of unstable item: text
-        foo.trait_unmarked(); //~ ERROR use of unmarked item
+        foo.trait_deprecated();
+        foo.trait_deprecated_text();
+        foo.trait_experimental();
+        foo.trait_experimental_text();
+        foo.trait_unstable();
+        foo.trait_unstable_text();
+        foo.trait_unmarked();
         foo.trait_stable();
     }
 
     fn test_method_object(foo: &Trait) {
-        foo.trait_deprecated(); //~ ERROR use of deprecated item
-        foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
-        foo.trait_experimental(); //~ ERROR use of experimental item
-        foo.trait_experimental_text(); //~ ERROR use of experimental item: text
-        foo.trait_unstable(); //~ ERROR use of unstable item
-        foo.trait_unstable_text(); //~ ERROR use of unstable item: text
-        foo.trait_unmarked(); //~ ERROR use of unmarked item
+        foo.trait_deprecated();
+        foo.trait_deprecated_text();
+        foo.trait_experimental();
+        foo.trait_experimental_text();
+        foo.trait_unstable();
+        foo.trait_unstable_text();
+        foo.trait_unmarked();
         foo.trait_stable();
     }
 }
index 20edd17556064d061fdf4d473b101a48e7d7f63e..c086f44d08b9009052e902f0cc0926d2bf255dbd 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(managed_boxes)]
+#![feature(managed_boxes, unsafe_destructor)]
 
 extern crate debug;
 
index 102772f79d57f80fd5eedda824855ce4f493f9c0..483168bb8bcfa1ed1585feb453b5506a3d2fdad8 100644 (file)
@@ -8,13 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// error-pattern: non-exhaustive patterns
 enum t { a(u), b }
 enum u { c, d }
 
 fn main() {
   let x = a(c);
-  match x {
+  match x { //~ ERROR non-exhaustive patterns: `a(c)` not covered
       a(d) => { fail!("hello"); }
       b => { fail!("goodbye"); }
     }
index a07fec853fc52b57076040f87c86793616439478..cd78419439a96952db491d31ac1cfeb00be9850d 100644 (file)
@@ -12,21 +12,21 @@ enum t { a, b, }
 
 fn main() {
     let x = a;
-    match x { b => { } } //~ ERROR non-exhaustive patterns
-    match true { //~ ERROR non-exhaustive patterns
+    match x { b => { } } //~ ERROR non-exhaustive patterns: `a` not covered
+    match true { //~ ERROR non-exhaustive patterns: `false` not covered
       true => {}
     }
-    match Some(10) { //~ ERROR non-exhaustive patterns
+    match Some(10) { //~ ERROR non-exhaustive patterns: `Some(_)` not covered
       None => {}
     }
-    match (2, 3, 4) { //~ ERROR non-exhaustive patterns
+    match (2, 3, 4) { //~ ERROR non-exhaustive patterns: `(_, _, _)` not covered
       (_, _, 4) => {}
     }
-    match (a, a) { //~ ERROR non-exhaustive patterns
+    match (a, a) { //~ ERROR non-exhaustive patterns: `(a, a)` not covered
       (a, b) => {}
       (b, a) => {}
     }
-    match a { //~ ERROR b not covered
+    match a { //~ ERROR non-exhaustive patterns: `b` not covered
       a => {}
     }
     // This is exhaustive, though the algorithm got it wrong at one point
@@ -37,8 +37,7 @@ fn main() {
     }
     let vec = vec!(Some(42), None, Some(21));
     let vec: &[Option<int>] = vec.as_slice();
-    match vec {
-        //~^ ERROR non-exhaustive patterns: vectors of length 0 not covered
+    match vec { //~ ERROR non-exhaustive patterns: `[]` not covered
         [Some(..), None, ..tail] => {}
         [Some(..), Some(..), ..tail] => {}
         [None] => {}
@@ -51,7 +50,7 @@ fn main() {
     }
     let vec = vec!(0.5);
     let vec: &[f32] = vec.as_slice();
-    match vec { //~ ERROR non-exhaustive patterns: vectors of length 4 not covered
+    match vec { //~ ERROR non-exhaustive patterns: `[_, _, _, _]` not covered
         [0.1, 0.2, 0.3] => (),
         [0.1, 0.2] => (),
         [0.1] => (),
diff --git a/src/test/compile-fail/non-exhaustive-pattern-witness.rs b/src/test/compile-fail/non-exhaustive-pattern-witness.rs
new file mode 100644 (file)
index 0000000..22e93d7
--- /dev/null
@@ -0,0 +1,74 @@
+// Copyright 2014 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(struct_variant)]
+
+struct Foo {
+    first: bool,
+    second: Option<[uint, ..4]>
+}
+
+enum Color {
+    Red,
+    Green,
+    CustomRGBA { a: bool, r: u8, g: u8, b: u8 }
+}
+
+fn struct_with_a_nested_enum_and_vector() {
+    match Foo { first: true, second: None } {
+    //~^ ERROR non-exhaustive patterns: `Foo{first: false, second: Some([_, _, _, _])}` not covered
+        Foo { first: true, second: None } => (),
+        Foo { first: true, second: Some(_) } => (),
+        Foo { first: false, second: None } => (),
+        Foo { first: false, second: Some([1u, 2u, 3u, 4u]) } => ()
+    }
+}
+
+fn enum_with_multiple_missing_variants() {
+    match Red {
+    //~^ ERROR non-exhaustive patterns: `Red` not covered
+        CustomRGBA { .. } => ()
+    }
+}
+
+fn enum_struct_variant() {
+    match Red {
+    //~^ ERROR non-exhaustive patterns: `CustomRGBA{a: true, r: _, g: _, b: _}` not covered
+        Red => (),
+        Green => (),
+        CustomRGBA { a: false, r: _, g: _, b: 0 } => (),
+        CustomRGBA { a: false, r: _, g: _, b: _ } => ()
+    }
+}
+
+enum Enum {
+    First,
+    Second(bool)
+}
+
+fn vectors_with_nested_enums() {
+    let x: &'static [Enum] = [First, Second(false)];
+    match x {
+    //~^ ERROR non-exhaustive patterns: `[Second(true), Second(false)]` not covered
+        [] => (),
+        [_] => (),
+        [First, _] => (),
+        [Second(true), First] => (),
+        [Second(true), Second(true)] => (),
+        [Second(false), _] => (),
+        [_, _, ..tail, _] => ()
+    }
+}
+
+fn main() {
+    struct_with_a_nested_enum_and_vector();
+    enum_with_multiple_missing_variants();
+    enum_struct_variant();
+}
\ No newline at end of file
index aaa09de826b2c158aa73ee9f2612c39e49a54171..d6e8507d0200bc979b7818016c800e708b3fb850 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(managed_boxes)]
+#![feature(managed_boxes, unsafe_destructor)]
 
 extern crate debug;
 
diff --git a/src/test/compile-fail/precise-refutable-pattern-errors.rs b/src/test/compile-fail/precise-refutable-pattern-errors.rs
deleted file mode 100644 (file)
index efa2dba..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2014 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 func(
-    (
-        1, //~ ERROR refutable pattern in function argument
-        (
-            Some( //~ ERROR refutable pattern in function argument
-                1), // nested, so no warning.
-            2..3 //~ ERROR refutable pattern in function argument
-            )
-        ): (int, (Option<int>, int))
-        ) {}
-
-fn main() {
-    let (
-        1, //~ ERROR refutable pattern in local binding
-        (
-            Some( //~ ERROR refutable pattern in local binding
-                1), // nested, so no warning.
-            2..3 //~ ERROR refutable pattern in local binding
-            )
-        ) = (1, (None, 2));
-}
diff --git a/src/test/compile-fail/refutable-pattern-errors.rs b/src/test/compile-fail/refutable-pattern-errors.rs
new file mode 100644 (file)
index 0000000..9128ee6
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2014 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 func((1, (Some(1), 2..3)): (int, (Option<int>, int))) { }
+//~^ ERROR refutable pattern in function argument: `(_, _)` not covered
+
+fn main() {
+    let (1, (Some(1), 2..3)) = (1, (None, 2));
+    //~^ ERROR refutable pattern in local binding: `(_, _)` not covered
+}
index d5489b6a852e444232206a7bb84b0a4d817e9126..954d4b23e30faa942734b7a752d885591b0116d4 100644 (file)
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 fn main() {
-    let f = |3: int| println!("hello");  //~ ERROR refutable pattern
+    let f = |3: int| println!("hello");
+    //~^ ERROR refutable pattern in function argument: `_` not covered
     f(4);
 }
index 4d10537aa4d0412e6036ce2c3a2b57bd92ac2925..a2adb55a2dd09b68081b5f6aaf55826b03934fbe 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(managed_boxes)]
+#![feature(managed_boxes, unsafe_destructor)]
 
 extern crate debug;
 use std::cell::Cell;
index 6252944973d651586927ffe24b81d4e364e8db12..8186c6263ca74fa3d268cb4ca238e086b0fdcf63 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(managed_boxes)]
+#![feature(managed_boxes, unsafe_destructor)]
 
 // error-pattern:quux
 
index 48768a1c6fd27600f7c7707842d93a2bd3240162..b3fb162790072d2168e0a37aea7f68b6b551d422 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(unsafe_destructor)]
+
 use std::mem::size_of;
 
 #[unsafe_no_drop_flag]
index 977bd474d177d012c39fdaca98f2c9e55f060c08..4ba3aa70dfcdfbdf04521319e6c5d2edea109245 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(unsafe_destructor)]
+
 struct S<T> {
     x: T
 }
index 4c05103973f499843dd55dcde3b2e10bc25abf3b..5e0aeeb6bed7612a37f1ecb0eb4e3d41e3a08cee 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(managed_boxes)]
+#![feature(managed_boxes, unsafe_destructor)]
 
 use std::cell::Cell;
 use std::gc::{Gc, GC};
diff --git a/src/test/run-pass/issue-14393.rs b/src/test/run-pass/issue-14393.rs
new file mode 100644 (file)
index 0000000..8710829
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2014 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.
+
+// ignore-win32: FIXME #13793
+
+fn main() {
+    match ("", 1u) {
+        (_, 42u) => (),
+        ("", _) => (),
+        _ => ()
+    }
+}
diff --git a/src/test/run-pass/issue-15043.rs b/src/test/run-pass/issue-15043.rs
new file mode 100644 (file)
index 0000000..edca9cb
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2014 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(warnings)]
+
+struct S<T>(T);
+
+static s1: S<S<uint>>=S(S(0));
+static s2: S<uint>=S(0);
+
+fn main() {
+    let foo: S<S<uint>>=S(S(0));
+    let foo: S<uint>=S(0);
+}
index 5f180f13ffa2adb41f1081b143c45035444679dc..5eb9453134dea74705ea791c013ebe818377ffeb 100644 (file)
@@ -9,6 +9,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(unsafe_destructor)]
+
 pub type Task = int;
 
 // tjc: I don't know why
index b62905634ad09d315b66ef52d5d47421fc9f289a..744ab45adc4596c96d7a07692a184e4ccece3022 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(managed_boxes)]
+#![feature(managed_boxes, unsafe_destructor)]
 
 use std::cell::Cell;
 use std::gc::{Gc, GC};
index f59c143c46fdadb351c302baa3d01d74fe4fde73..a69ec1dac7270b41c51ca1384f000123e6c82bcc 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(managed_boxes)]
+#![feature(managed_boxes, unsafe_destructor)]
 
 use std::cell::Cell;
 use std::gc::{Gc, GC};
index 151d00eb2d02b0619e5ff24f87bf608ecc5785d5..186dd0363eeb65d0bbc090c382a0a7a3b1017609 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(unsafe_destructor)]
+
 extern crate debug;
 
 trait X {
diff --git a/src/test/run-pass/issue-7784.rs b/src/test/run-pass/issue-7784.rs
new file mode 100644 (file)
index 0000000..52c2d57
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright 2014 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 foo<T: Add<T, T> + Clone>([x, y, z]: [T, ..3]) -> (T, T, T) {
+    (x.clone(), x.clone() + y.clone(), x + y + z)
+}
+fn bar(a: &'static str, b: &'static str) -> [&'static str, ..4] {
+    [a, b, b, a]
+}
+
+fn main() {
+    assert_eq!(foo([1, 2, 3]), (1, 3, 6));
+
+    let [a, b, c, d] = bar("foo", "bar");
+    assert_eq!(a, "foo");
+    assert_eq!(b, "bar");
+    assert_eq!(c, "bar");
+    assert_eq!(d, "foo");
+
+    let [a, _, _, d] = bar("baz", "foo");
+    assert_eq!(a, "baz");
+    assert_eq!(d, "baz");
+
+    let out = bar("baz", "foo");
+    let [a, ..xs, d] = out;
+    assert_eq!(a, "baz");
+    assert!(xs == ["foo", "foo"]);
+    assert_eq!(d, "baz");
+}
\ No newline at end of file
index 39b81d16519182ab16bdc1da6d6238049de975e6..fc29299a4a97ef4097fd2e5edd7d73a453a1c169 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(managed_boxes)]
+#![feature(managed_boxes, unsafe_destructor)]
 
 use std::cell::Cell;
 use std::gc::{GC, Gc};
index 3821efcb1bcf789607ec1e7f72abf7812006bc4a..efa151c6606c3062751345ac74866e9caa60ec5a 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(managed_boxes)]
+#![feature(managed_boxes, unsafe_destructor)]
 
 // Make sure the destructor is run for newtype structs.
 
index eea5296d7e4879a690b69bea5217563a75b829f1..e9df731fbbf3cb1af07ecb71847c7d81c62b3667 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(managed_boxes)]
+#![feature(managed_boxes, unsafe_destructor)]
 
 use std::cell::Cell;
 use std::gc::{GC, Gc};
index 7f266ec912abb90aaaf9ffb98d5267e0c6289880..dc6dac15bb2b1fb8547802e00c5b7c2f62f3101b 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(managed_boxes)]
+#![feature(managed_boxes, unsafe_destructor)]
 
 extern crate debug;
 
index 85750899259c25987e27d3f89eae89e3f0bcda24..60526faef509bf577919232dd775de68dbe1349c 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(managed_boxes)]
+#![feature(managed_boxes, unsafe_destructor)]
 
 use std::cell::Cell;
 use std::gc::{GC, Gc};
index 88edefdfe29a039847411a3198fd2662e84aba65..253a2c0c7123e8bef7820d9dd4e6b5d7c13d7163 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(managed_boxes)]
+#![feature(managed_boxes, unsafe_destructor)]
 
 // Ensures that class dtors run if the object is inside an enum
 // variant
index b1669dea7b216f0f743d938c267113a573d44ad0..2739b898f9f4f46e70bef4aec950e8e7d7513963 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(managed_boxes)]
+#![feature(managed_boxes, unsafe_destructor)]
 
 use std::task;
 use std::gc::{Gc, GC};
index 3c0a9abec144af49c38eded1e279e397e9293283..9e5fc6d0518d17b60352d95014573da5ddb49515 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(managed_boxes)]
+#![feature(managed_boxes, unsafe_destructor)]
 
 use std::cell::Cell;
 use std::gc::{Gc, GC};