about summary refs log tree commit diff
diff options
context:
space:
mode:
authorManish Goregaokar <manishsmail@gmail.com>2015-02-27 11:42:29 +0530
committerManish Goregaokar <manishsmail@gmail.com>2015-02-27 20:37:36 +0530
commit5d4e01766bd0b3b171149d41effe5564caf0a38b (patch)
treeed4f5374ed8114ef813c415f8bfb6ca6e33de3a9
parentbd0d8e47e53f25bbd50418a0f117973c366c1b08 (diff)
parent060661d2b4a323c83a1bf043234eae8a344ff6aa (diff)
downloadrust-5d4e01766bd0b3b171149d41effe5564caf0a38b.tar.gz
rust-5d4e01766bd0b3b171149d41effe5564caf0a38b.zip
Rollup merge of #22803 - huonw:field-stability, r=alexcrichton
 We were recording stability attributes applied to fields in the
compiler, and even annotating it in the libs, but the compiler didn't
actually do the checks to give errors/warnings in user crates.

Details in the commit messages.
-rw-r--r--src/libcore/str/mod.rs1
-rw-r--r--src/librustc/lint/builtin.rs5
-rw-r--r--src/librustc/middle/stability.rs121
-rw-r--r--src/librustc/middle/ty.rs3
-rw-r--r--src/librustc_privacy/lib.rs10
-rw-r--r--src/libstd/old_io/mem.rs1
-rw-r--r--src/libstd/sync/mpsc/mod.rs2
-rw-r--r--src/libstd/thread_local/mod.rs2
-rw-r--r--src/test/auxiliary/lint_stability.rs24
-rw-r--r--src/test/auxiliary/lint_stability_fields.rs60
-rw-r--r--src/test/compile-fail/lint-stability-fields.rs346
-rw-r--r--src/test/compile-fail/lint-stability.rs12
12 files changed, 575 insertions, 12 deletions
diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs
index 7e51f8e8503..b354116993c 100644
--- a/src/libcore/str/mod.rs
+++ b/src/libcore/str/mod.rs
@@ -939,6 +939,7 @@ impl<'a, P: Pattern<'a>> Iterator for SplitStr<'a, P> {
     type Item = &'a str;
 
     #[inline]
+    #[allow(deprecated)]
     fn next(&mut self) -> Option<&'a str> {
         Iterator::next(&mut self.0)
     }
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index a4f69e651df..0bd7f83b959 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -1771,6 +1771,11 @@ impl LintPass for Stability {
         stability::check_path(cx.tcx, path, id,
                               &mut |id, sp, stab| self.lint(cx, id, sp, stab));
     }
+
+    fn check_pat(&mut self, cx: &Context, pat: &ast::Pat) {
+        stability::check_pat(cx.tcx, pat,
+                             &mut |id, sp, stab| self.lint(cx, id, sp, stab))
+    }
 }
 
 declare_lint! {
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index f67e470ee54..ddac6cc7514 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -58,8 +58,10 @@ impl<'a> Annotator<'a> {
                    attrs: &Vec<Attribute>, item_sp: Span, f: F, required: bool) where
         F: FnOnce(&mut Annotator),
     {
+        debug!("annotate(id = {:?}, attrs = {:?})", id, attrs);
         match attr::find_stability(self.sess.diagnostic(), attrs, item_sp) {
             Some(stab) => {
+                debug!("annotate: found {:?}", stab);
                 self.index.local.insert(id, stab.clone());
 
                 // Don't inherit #[stable(feature = "rust1", since = "1.0.0")]
@@ -72,6 +74,8 @@ impl<'a> Annotator<'a> {
                 }
             }
             None => {
+                debug!("annotate: not found, use_parent = {:?}, parent = {:?}",
+                       use_parent, self.parent);
                 if use_parent {
                     if let Some(stab) = self.parent.clone() {
                         self.index.local.insert(id, stab);
@@ -299,6 +303,12 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> {
                    &mut |id, sp, stab| self.check(id, sp, stab));
         visit::walk_path(self, path)
     }
+
+    fn visit_pat(&mut self, pat: &ast::Pat) {
+        check_pat(self.tcx, pat,
+                  &mut |id, sp, stab| self.check(id, sp, stab));
+        visit::walk_pat(self, pat)
+    }
 }
 
 /// Helper for discovering nodes to check for stability
@@ -385,6 +395,76 @@ pub fn check_expr(tcx: &ty::ctxt, e: &ast::Expr,
                 None => return
             }
         }
+        ast::ExprField(ref base_e, ref field) => {
+            span = field.span;
+            match ty::expr_ty_adjusted(tcx, base_e).sty {
+                ty::ty_struct(did, _) => {
+                    ty::lookup_struct_fields(tcx, did)
+                        .iter()
+                        .find(|f| f.name == field.node.name)
+                        .unwrap_or_else(|| {
+                            tcx.sess.span_bug(field.span,
+                                              "stability::check_expr: unknown named field access")
+                        })
+                        .id
+                }
+                _ => tcx.sess.span_bug(e.span,
+                                       "stability::check_expr: named field access on non-struct")
+            }
+        }
+        ast::ExprTupField(ref base_e, ref field) => {
+            span = field.span;
+            match ty::expr_ty_adjusted(tcx, base_e).sty {
+                ty::ty_struct(did, _) => {
+                    ty::lookup_struct_fields(tcx, did)
+                        .get(field.node)
+                        .unwrap_or_else(|| {
+                            tcx.sess.span_bug(field.span,
+                                              "stability::check_expr: unknown unnamed field access")
+                        })
+                        .id
+                }
+                ty::ty_tup(..) => return,
+                _ => tcx.sess.span_bug(e.span,
+                                       "stability::check_expr: unnamed field access on \
+                                        something other than a tuple or struct")
+            }
+        }
+        ast::ExprStruct(_, ref expr_fields, _) => {
+            let type_ = ty::expr_ty(tcx, e);
+            match type_.sty {
+                ty::ty_struct(did, _) => {
+                    let struct_fields = ty::lookup_struct_fields(tcx, did);
+                    // check the stability of each field that appears
+                    // in the construction expression.
+                    for field in expr_fields {
+                        let did = struct_fields
+                            .iter()
+                            .find(|f| f.name == field.ident.node.name)
+                            .unwrap_or_else(|| {
+                                tcx.sess.span_bug(field.span,
+                                                  "stability::check_expr: unknown named \
+                                                   field access")
+                            })
+                            .id;
+                        maybe_do_stability_check(tcx, did, field.span, cb);
+                    }
+
+                    // we're done.
+                    return
+                }
+                // we don't look at stability attributes on
+                // struct-like enums (yet...), but it's definitely not
+                // a bug to have construct one.
+                ty::ty_enum(..) => return,
+                _ => {
+                    tcx.sess.span_bug(e.span,
+                                      &format!("stability::check_expr: struct construction \
+                                                of non-struct, type {:?}",
+                                               type_.repr(tcx)));
+                }
+            }
+        }
         _ => return
     };
 
@@ -403,6 +483,47 @@ pub fn check_path(tcx: &ty::ctxt, path: &ast::Path, id: ast::NodeId,
 
 }
 
+pub fn check_pat(tcx: &ty::ctxt, pat: &ast::Pat,
+                 cb: &mut FnMut(ast::DefId, Span, &Option<Stability>)) {
+    debug!("check_pat(pat = {:?})", pat);
+    if is_internal(tcx, pat.span) { return; }
+
+    let did = match ty::pat_ty_opt(tcx, pat) {
+        Some(&ty::TyS { sty: ty::ty_struct(did, _), .. }) => did,
+        Some(_) | None => return,
+    };
+    let struct_fields = ty::lookup_struct_fields(tcx, did);
+    match pat.node {
+        // Foo(a, b, c)
+        ast::PatEnum(_, Some(ref pat_fields)) => {
+            for (field, struct_field) in pat_fields.iter().zip(struct_fields.iter()) {
+                // a .. pattern is fine, but anything positional is
+                // not.
+                if let ast::PatWild(ast::PatWildMulti) = field.node {
+                    continue
+                }
+                maybe_do_stability_check(tcx, struct_field.id, field.span, cb)
+            }
+        }
+        // Foo { a, b, c }
+        ast::PatStruct(_, ref pat_fields, _) => {
+            for field in pat_fields {
+                let did = struct_fields
+                    .iter()
+                    .find(|f| f.name == field.node.ident.name)
+                    .unwrap_or_else(|| {
+                        tcx.sess.span_bug(field.span,
+                                          "stability::check_pat: unknown named field access")
+                    })
+                    .id;
+                maybe_do_stability_check(tcx, did, field.span, cb);
+            }
+        }
+        // everything else is fine.
+        _ => {}
+    }
+}
+
 fn maybe_do_stability_check(tcx: &ty::ctxt, id: ast::DefId, span: Span,
                             cb: &mut FnMut(ast::DefId, Span, &Option<Stability>)) {
     if !is_staged_api(tcx, id) { return  }
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 78b8d4f7b1e..17ac7605741 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -4298,6 +4298,9 @@ pub fn free_region_from_def(outlives_extent: region::DestructionScopeData,
 pub fn pat_ty<'tcx>(cx: &ctxt<'tcx>, pat: &ast::Pat) -> Ty<'tcx> {
     return node_id_to_type(cx, pat.id);
 }
+pub fn pat_ty_opt<'tcx>(cx: &ctxt<'tcx>, pat: &ast::Pat) -> Option<Ty<'tcx>> {
+    return node_id_to_type_opt(cx, pat.id);
+}
 
 
 // Returns the type of an expression as a monotype.
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 436a826687e..46729988bb6 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -233,6 +233,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
             ast::ItemEnum(ref def, _) if public_first => {
                 for variant in &def.variants {
                     self.exported_items.insert(variant.node.id);
+                    self.public_items.insert(variant.node.id);
                 }
             }
 
@@ -321,6 +322,15 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
                     Some(id) => { self.exported_items.insert(id); }
                     None => {}
                 }
+                // fields can be public or private, so lets check
+                for field in &def.fields {
+                    let vis = match field.node.kind {
+                        ast::NamedField(_, vis) | ast::UnnamedField(vis) => vis
+                    };
+                    if vis == ast::Public {
+                        self.public_items.insert(field.node.id);
+                    }
+                }
             }
 
             ast::ItemTy(ref ty, _) if public_first => {
diff --git a/src/libstd/old_io/mem.rs b/src/libstd/old_io/mem.rs
index c08a2c1f477..e6a8b90ea33 100644
--- a/src/libstd/old_io/mem.rs
+++ b/src/libstd/old_io/mem.rs
@@ -102,6 +102,7 @@ impl MemWriter {
 
 impl Writer for MemWriter {
     #[inline]
+    #[allow(deprecated)]
     fn write_all(&mut self, buf: &[u8]) -> IoResult<()> {
         self.buf.push_all(buf);
         Ok(())
diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs
index 7bd1f3542eb..1310d476f8e 100644
--- a/src/libstd/sync/mpsc/mod.rs
+++ b/src/libstd/sync/mpsc/mod.rs
@@ -384,7 +384,7 @@ impl<T> !Sync for SyncSender<T> {}
 /// contains the data being sent as a payload so it can be recovered.
 #[stable(feature = "rust1", since = "1.0.0")]
 #[derive(PartialEq, Eq, Clone, Copy)]
-pub struct SendError<T>(pub T);
+pub struct SendError<T>(#[stable(feature = "rust1", since = "1.0.0")] pub T);
 
 /// An error returned from the `recv` function on a `Receiver`.
 ///
diff --git a/src/libstd/thread_local/mod.rs b/src/libstd/thread_local/mod.rs
index d65156dae96..764c7d730cb 100644
--- a/src/libstd/thread_local/mod.rs
+++ b/src/libstd/thread_local/mod.rs
@@ -105,10 +105,12 @@ pub struct Key<T> {
     // This is trivially devirtualizable by LLVM because we never store anything
     // to this field and rustc can declare the `static` as constant as well.
     #[doc(hidden)]
+    #[unstable(feature = "thread_local_internals")]
     pub inner: fn() -> &'static __impl::KeyInner<UnsafeCell<Option<T>>>,
 
     // initialization routine to invoke to create a value
     #[doc(hidden)]
+    #[unstable(feature = "thread_local_internals")]
     pub init: fn() -> T,
 }
 
diff --git a/src/test/auxiliary/lint_stability.rs b/src/test/auxiliary/lint_stability.rs
index fb535eb8336..d47575403e1 100644
--- a/src/test/auxiliary/lint_stability.rs
+++ b/src/test/auxiliary/lint_stability.rs
@@ -100,14 +100,22 @@ pub trait UnstableTrait { fn dummy(&self) { } }
 
 #[stable(feature = "test_feature", since = "1.0.0")]
 #[deprecated(since = "1.0.0")]
-pub struct DeprecatedStruct { pub i: int }
+pub struct DeprecatedStruct {
+    #[stable(feature = "test_feature", since = "1.0.0")] pub i: int
+}
 #[unstable(feature = "test_feature")]
 #[deprecated(since = "1.0.0")]
-pub struct DeprecatedUnstableStruct { pub i: int }
+pub struct DeprecatedUnstableStruct {
+    #[stable(feature = "test_feature", since = "1.0.0")] pub i: int
+}
 #[unstable(feature = "test_feature")]
-pub struct UnstableStruct { pub i: int }
+pub struct UnstableStruct {
+    #[stable(feature = "test_feature", since = "1.0.0")] pub i: int
+}
 #[stable(feature = "rust1", since = "1.0.0")]
-pub struct StableStruct { pub i: int }
+pub struct StableStruct {
+    #[stable(feature = "test_feature", since = "1.0.0")] pub i: int
+}
 
 #[stable(feature = "test_feature", since = "1.0.0")]
 #[deprecated(since = "1.0.0")]
@@ -137,14 +145,14 @@ pub enum Enum {
 
 #[stable(feature = "test_feature", since = "1.0.0")]
 #[deprecated(since = "1.0.0")]
-pub struct DeprecatedTupleStruct(pub int);
+pub struct DeprecatedTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub int);
 #[unstable(feature = "test_feature")]
 #[deprecated(since = "1.0.0")]
-pub struct DeprecatedUnstableTupleStruct(pub int);
+pub struct DeprecatedUnstableTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub int);
 #[unstable(feature = "test_feature")]
-pub struct UnstableTupleStruct(pub int);
+pub struct UnstableTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub int);
 #[stable(feature = "rust1", since = "1.0.0")]
-pub struct StableTupleStruct(pub int);
+pub struct StableTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub int);
 
 #[macro_export]
 macro_rules! macro_test {
diff --git a/src/test/auxiliary/lint_stability_fields.rs b/src/test/auxiliary/lint_stability_fields.rs
new file mode 100644
index 00000000000..66940ee0081
--- /dev/null
+++ b/src/test/auxiliary/lint_stability_fields.rs
@@ -0,0 +1,60 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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(staged_api)]
+#![staged_api]
+#![stable(feature = "rust1", since = "1.0.0")]
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Stable {
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub inherit: u8, // it's a lie (stable doesn't inherit)
+    #[unstable(feature = "test_feature")]
+    pub override1: u8,
+    #[deprecated(since = "1.0.0")]
+    #[unstable(feature = "test_feature")]
+    pub override2: u8,
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Stable2(#[stable(feature = "rust1", since = "1.0.0")] pub u8,
+                   #[unstable(feature = "test_feature")] pub u8,
+                   #[unstable(feature = "test_feature")] #[deprecated(since = "1.0.0")] pub u8);
+
+#[unstable(feature = "test_feature")]
+pub struct Unstable {
+    pub inherit: u8,
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub override1: u8,
+    #[deprecated(since = "1.0.0")]
+    #[unstable(feature = "test_feature")]
+    pub override2: u8,
+}
+
+#[unstable(feature = "test_feature")]
+pub struct Unstable2(pub u8,
+                     #[stable(feature = "rust1", since = "1.0.0")] pub u8,
+                     #[unstable(feature = "test_feature")] #[deprecated(since = "1.0.0")] pub u8);
+
+#[unstable(feature = "test_feature")]
+#[deprecated(feature = "rust1", since = "1.0.0")]
+pub struct Deprecated {
+    pub inherit: u8,
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub override1: u8,
+    #[unstable(feature = "test_feature")]
+    pub override2: u8,
+}
+
+#[unstable(feature = "test_feature")]
+#[deprecated(feature = "rust1", since = "1.0.0")]
+pub struct Deprecated2(pub u8,
+                       #[stable(feature = "rust1", since = "1.0.0")] pub u8,
+                       #[unstable(feature = "test_feature")] pub u8);
diff --git a/src/test/compile-fail/lint-stability-fields.rs b/src/test/compile-fail/lint-stability-fields.rs
new file mode 100644
index 00000000000..c43ff198925
--- /dev/null
+++ b/src/test/compile-fail/lint-stability-fields.rs
@@ -0,0 +1,346 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+// aux-build:lint_stability_fields.rs
+#![deny(deprecated)]
+#![allow(dead_code)]
+#![feature(staged_api)]
+#![staged_api]
+
+mod cross_crate {
+    extern crate lint_stability_fields;
+
+    use self::lint_stability_fields::*;
+
+    pub fn foo() {
+        let x = Stable {
+            inherit: 1,
+            override1: 2, //~ WARN use of unstable
+            override2: 3,
+            //~^ ERROR use of deprecated item
+            //~^^ WARN use of unstable
+        };
+
+        let _ = x.inherit;
+        let _ = x.override1; //~ WARN use of unstable
+        let _ = x.override2;
+        //~^ ERROR use of deprecated item
+        //~^^ WARN use of unstable
+
+        let Stable {
+            inherit: _,
+            override1: _, //~ WARN use of unstable
+            override2: _
+            //~^ ERROR use of deprecated item
+            //~^^ WARN use of unstable
+        } = x;
+        // all fine
+        let Stable { .. } = x;
+
+        let x = Stable2(1, 2, 3);
+
+        let _ = x.0;
+        let _ = x.1; //~ WARN use of unstable
+        let _ = x.2;
+        //~^ ERROR use of deprecated item
+        //~^^ WARN use of unstable
+
+        let Stable2(_,
+                   _, //~ WARN use of unstable
+                   _)
+            //~^ ERROR use of deprecated item
+            //~^^ WARN use of unstable
+            = x;
+        // all fine
+        let Stable2(..) = x;
+
+
+        let x = Unstable { //~ WARN use of unstable
+            inherit: 1, //~ WARN use of unstable
+            override1: 2,
+            override2: 3,
+            //~^ ERROR use of deprecated item
+            //~^^ WARN use of unstable
+        };
+
+        let _ = x.inherit; //~ WARN use of unstable
+        let _ = x.override1;
+        let _ = x.override2;
+        //~^ ERROR use of deprecated item
+        //~^^ WARN use of unstable
+
+        let Unstable { //~ WARN use of unstable
+            inherit: _, //~ WARN use of unstable
+            override1: _,
+            override2: _
+            //~^ ERROR use of deprecated item
+            //~^^ WARN use of unstable
+        } = x;
+
+        let Unstable  //~ WARN use of unstable
+            // the patterns are all fine:
+            { .. } = x;
+
+
+        let x = Unstable2(1, 2, 3); //~ WARN use of unstable
+
+        let _ = x.0; //~ WARN use of unstable
+        let _ = x.1;
+        let _ = x.2;
+        //~^ ERROR use of deprecated item
+        //~^^ WARN use of unstable
+
+        let Unstable2  //~ WARN use of unstable
+            (_, //~ WARN use of unstable
+             _,
+             _)
+            //~^ ERROR use of deprecated item
+            //~^^ WARN use of unstable
+            = x;
+        let Unstable2 //~ WARN use of unstable
+            // the patterns are all fine:
+            (..) = x;
+
+
+        let x = Deprecated {
+            //~^ ERROR use of deprecated item
+            //~^^ WARN use of unstable
+            inherit: 1,
+            //~^ ERROR use of deprecated item
+            //~^^ WARN use of unstable
+            override1: 2,
+            override2: 3, //~ WARN use of unstable
+        };
+
+        let _ = x.inherit;
+        //~^ ERROR use of deprecated item
+        //~^^ WARN use of unstable
+        let _ = x.override1;
+        let _ = x.override2; //~ WARN use of unstable
+
+        let Deprecated {
+            //~^ ERROR use of deprecated item
+            //~^^ WARN use of unstable
+            inherit: _,
+            //~^ ERROR use of deprecated item
+            //~^^ WARN use of unstable
+            override1: _,
+            override2: _ //~ WARN use of unstable
+        } = x;
+
+        let Deprecated
+            //~^ ERROR use of deprecated item
+            //~^^ WARN use of unstable
+            // the patterns are all fine:
+            { .. } = x;
+
+        let x = Deprecated2(1, 2, 3);
+        //~^ ERROR use of deprecated item
+        //~^^ WARN use of unstable
+
+        let _ = x.0;
+        //~^ ERROR use of deprecated item
+        //~^^ WARN use of unstable
+        let _ = x.1;
+        let _ = x.2; //~ WARN use of unstable
+
+        let Deprecated2
+        //~^ ERROR use of deprecated item
+        //~^^ WARN use of unstable
+            (_,
+             //~^ ERROR use of deprecated item
+             //~^^ WARN use of unstable
+             _,
+             _) //~ WARN use of unstable
+            = x;
+        let Deprecated2
+        //~^ ERROR use of deprecated item
+        //~^^ WARN use of unstable
+            // the patterns are all fine:
+            (..) = x;
+    }
+}
+
+mod this_crate {
+    #[stable(feature = "rust1", since = "1.0.0")]
+    struct Stable {
+        inherit: u8,
+        #[unstable(feature = "test_feature")]
+        override1: u8,
+        #[deprecated(since = "1.0.0")]
+        #[unstable(feature = "test_feature")]
+        override2: u8,
+    }
+
+    #[stable(feature = "rust1", since = "1.0.0")]
+    struct Stable2(u8,
+                   #[stable(feature = "rust1", since = "1.0.0")] u8,
+                   #[unstable(feature = "test_feature")] #[deprecated(since = "1.0.0")] u8);
+
+    #[unstable(feature = "test_feature")]
+    struct Unstable {
+        inherit: u8,
+        #[stable(feature = "rust1", since = "1.0.0")]
+        override1: u8,
+        #[deprecated(since = "1.0.0")]
+        #[unstable(feature = "test_feature")]
+        override2: u8,
+    }
+
+    #[unstable(feature = "test_feature")]
+    struct Unstable2(u8,
+                     #[stable(feature = "rust1", since = "1.0.0")] u8,
+                     #[unstable(feature = "test_feature")] #[deprecated(since = "1.0.0")] u8);
+
+    #[unstable(feature = "test_feature")]
+    #[deprecated(feature = "rust1", since = "1.0.0")]
+    struct Deprecated {
+        inherit: u8,
+        #[stable(feature = "rust1", since = "1.0.0")]
+        override1: u8,
+        #[unstable(feature = "test_feature")]
+        override2: u8,
+    }
+
+    #[unstable(feature = "test_feature")]
+    #[deprecated(feature = "rust1", since = "1.0.0")]
+    struct Deprecated2(u8,
+                       #[stable(feature = "rust1", since = "1.0.0")] u8,
+                       #[unstable(feature = "test_feature")] u8);
+
+    pub fn foo() {
+        let x = Stable {
+            inherit: 1,
+            override1: 2,
+            override2: 3,
+            //~^ ERROR use of deprecated item
+        };
+
+        let _ = x.inherit;
+        let _ = x.override1;
+        let _ = x.override2;
+        //~^ ERROR use of deprecated item
+
+        let Stable {
+            inherit: _,
+            override1: _,
+            override2: _
+            //~^ ERROR use of deprecated item
+        } = x;
+        // all fine
+        let Stable { .. } = x;
+
+        let x = Stable2(1, 2, 3);
+
+        let _ = x.0;
+        let _ = x.1;
+        let _ = x.2;
+        //~^ ERROR use of deprecated item
+
+        let Stable2(_,
+                   _,
+                   _)
+            //~^ ERROR use of deprecated item
+            = x;
+        // all fine
+        let Stable2(..) = x;
+
+
+        let x = Unstable {
+            inherit: 1,
+            override1: 2,
+            override2: 3,
+            //~^ ERROR use of deprecated item
+        };
+
+        let _ = x.inherit;
+        let _ = x.override1;
+        let _ = x.override2;
+        //~^ ERROR use of deprecated item
+
+        let Unstable {
+            inherit: _,
+            override1: _,
+            override2: _
+            //~^ ERROR use of deprecated item
+        } = x;
+
+        let Unstable
+            // the patterns are all fine:
+            { .. } = x;
+
+
+        let x = Unstable2(1, 2, 3);
+
+        let _ = x.0;
+        let _ = x.1;
+        let _ = x.2;
+        //~^ ERROR use of deprecated item
+
+        let Unstable2
+            (_,
+             _,
+             _)
+            //~^ ERROR use of deprecated item
+            = x;
+        let Unstable2
+            // the patterns are all fine:
+            (..) = x;
+
+
+        let x = Deprecated {
+            //~^ ERROR use of deprecated item
+            inherit: 1,
+            //~^ ERROR use of deprecated item
+            override1: 2,
+            override2: 3,
+        };
+
+        let _ = x.inherit;
+        //~^ ERROR use of deprecated item
+        let _ = x.override1;
+        let _ = x.override2;
+
+        let Deprecated {
+            //~^ ERROR use of deprecated item
+            inherit: _,
+            //~^ ERROR use of deprecated item
+            override1: _,
+            override2: _
+        } = x;
+
+        let Deprecated
+            //~^ ERROR use of deprecated item
+            // the patterns are all fine:
+            { .. } = x;
+
+        let x = Deprecated2(1, 2, 3);
+        //~^ ERROR use of deprecated item
+
+        let _ = x.0;
+        //~^ ERROR use of deprecated item
+        let _ = x.1;
+        let _ = x.2;
+
+        let Deprecated2
+        //~^ ERROR use of deprecated item
+            (_,
+             //~^ ERROR use of deprecated item
+             _,
+             _)
+            = x;
+        let Deprecated2
+        //~^ ERROR use of deprecated item
+            // the patterns are all fine:
+            (..) = x;
+    }
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/lint-stability.rs b/src/test/compile-fail/lint-stability.rs
index 90792848855..12548c45396 100644
--- a/src/test/compile-fail/lint-stability.rs
+++ b/src/test/compile-fail/lint-stability.rs
@@ -317,11 +317,17 @@ mod this_crate {
 
     #[unstable(feature = "test_feature")]
     #[deprecated(since = "1.0.0")]
-    pub struct DeprecatedStruct { i: isize }
+    pub struct DeprecatedStruct {
+        #[stable(feature = "test_feature", since = "1.0.0")] i: isize
+    }
     #[unstable(feature = "test_feature")]
-    pub struct UnstableStruct { i: isize }
+    pub struct UnstableStruct {
+        #[stable(feature = "test_feature", since = "1.0.0")] i: isize
+    }
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub struct StableStruct { i: isize }
+    pub struct StableStruct {
+        #[stable(feature = "test_feature", since = "1.0.0")] i: isize
+    }
 
     #[unstable(feature = "test_feature")]
     #[deprecated(since = "1.0.0")]