about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2015-02-03 15:36:11 -0800
committerAlex Crichton <alex@alexcrichton.com>2015-02-03 20:11:20 -0800
commitd0029a47c274a2ce97641b80ba34cf6fbfa2d73e (patch)
tree25e66a127143ade43d3afe8772d85a71762d3c53 /src
parent9db593c90af04dbf8f9bebb8a3650ff9609d10f2 (diff)
parenta5ddacf001e4207efd732ecb04250783a64f36c8 (diff)
downloadrust-d0029a47c274a2ce97641b80ba34cf6fbfa2d73e.tar.gz
rust-d0029a47c274a2ce97641b80ba34cf6fbfa2d73e.zip
rollup merge of #21910: Manishearth/missing_stability
Currently, if a `#![staged_api]` crate contains an exported item without a stability marker (or inherited stability),
the item is useless.

This change introduces a check to ensure that all exported items have a defined stability.

it also introduces the `unmarked_api` feature, which lets users import unmarked features. While this PR should in theory forbid these from existing,
in practice we can't be so sure; so this lets users bypass this check instead of having to wait for the library and/or compiler to be fixed (since otherwise this is a hard error).

r? @aturon
Diffstat (limited to 'src')
-rw-r--r--src/doc/reference.md7
-rw-r--r--src/librustc/middle/stability.rs85
-rw-r--r--src/librustc_driver/driver.rs9
-rw-r--r--src/librustc_driver/test.rs3
-rw-r--r--src/libstd/thread_local/mod.rs1
-rw-r--r--src/libsyntax/feature_gate.rs6
-rw-r--r--src/test/auxiliary/lint_stability.rs13
-rw-r--r--src/test/compile-fail/lint-stability.rs32
-rw-r--r--src/test/compile-fail/missing-stability.rs33
9 files changed, 114 insertions, 75 deletions
diff --git a/src/doc/reference.md b/src/doc/reference.md
index 64ddb3ffdd3..326946837bf 100644
--- a/src/doc/reference.md
+++ b/src/doc/reference.md
@@ -2432,6 +2432,8 @@ The currently implemented features of the reference compiler are:
 * `simd` - Allows use of the `#[simd]` attribute, which is overly simple and
            not the SIMD interface we want to expose in the long term.
 
+* `staged_api` - Allows usage of stability markers and `#![staged_api]` in a crate
+
 * `struct_inherit` - Allows using struct inheritance, which is barely
                      implemented and will probably be removed. Don't use this.
 
@@ -2459,6 +2461,11 @@ The currently implemented features of the reference compiler are:
                         which is considered wildly unsafe and will be
                         obsoleted by language improvements.
 
+* `unmarked_api` - Allows use of items within a `#![staged_api]` crate
+                   which have not been marked with a stability marker.
+                   Such items should not be allowed by the compiler to exist,
+                   so if you need this there probably is a compiler bug.
+
 * `associated_types` - Allows type aliases in traits. Experimental.
 
 If a feature is promoted to a language feature, then all existing programs will
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index 5028a1322ca..3304bd4ae29 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -14,6 +14,7 @@
 use session::Session;
 use lint;
 use middle::ty;
+use middle::privacy::PublicItems;
 use metadata::csearch;
 use syntax::parse::token::InternedString;
 use syntax::codemap::{Span, DUMMY_SP};
@@ -44,15 +45,16 @@ pub struct Index {
 // A private tree-walker for producing an Index.
 struct Annotator<'a> {
     sess: &'a Session,
-    index: Index,
-    parent: Option<Stability>
+    index: &'a mut Index,
+    parent: Option<Stability>,
+    export_map: &'a PublicItems,
 }
 
 impl<'a> Annotator<'a> {
     // Determine the stability for a node based on its attributes and inherited
     // stability. The stability is recorded in the index and used as the parent.
     fn annotate<F>(&mut self, id: NodeId, use_parent: bool,
-                   attrs: &Vec<Attribute>, item_sp: Span, f: F) where
+                   attrs: &Vec<Attribute>, item_sp: Span, f: F, required: bool) where
         F: FnOnce(&mut Annotator),
     {
         match attr::find_stability(self.sess.diagnostic(), attrs.as_slice(), item_sp) {
@@ -70,7 +72,14 @@ impl<'a> Annotator<'a> {
             }
             None => {
                 if use_parent {
-                    self.parent.clone().map(|stab| self.index.local.insert(id, stab));
+                    if let Some(stab) = self.parent.clone() {
+                        self.index.local.insert(id, stab);
+                    } else if self.index.staged_api && required
+                           && self.export_map.contains(&id)
+                           && !self.sess.opts.test {
+                        self.sess.span_err(item_sp,
+                                           "This node does not have a stability attribute");
+                    }
                 }
                 f(self);
             }
@@ -93,11 +102,19 @@ impl<'a, 'v> Visitor<'v> for Annotator<'a> {
             _ => true,
         };
 
-        self.annotate(i.id, use_parent, &i.attrs, i.span, |v| visit::walk_item(v, i));
+        // In case of a `pub use <mod>;`, we should not error since the stability
+        // is inherited from the module itself
+        let required = match i.node {
+            ast::ItemUse(_) => i.vis != ast::Public,
+            _ => true
+        };
+
+        self.annotate(i.id, use_parent, &i.attrs, i.span,
+                      |v| visit::walk_item(v, i), required);
 
         if let ast::ItemStruct(ref sd, _) = i.node {
             sd.ctor_id.map(|id| {
-                self.annotate(id, true, &i.attrs, i.span, |_| {})
+                self.annotate(id, true, &i.attrs, i.span, |_| {}, true)
             });
         }
     }
@@ -106,7 +123,7 @@ impl<'a, 'v> Visitor<'v> for Annotator<'a> {
                 _: &'v Block, sp: Span, _: NodeId) {
         if let FkMethod(_, _, meth) = fk {
             // Methods are not already annotated, so we annotate it
-            self.annotate(meth.id, true, &meth.attrs, sp, |_| {});
+            self.annotate(meth.id, true, &meth.attrs, sp, |_| {}, true);
         }
         // Items defined in a function body have no reason to have
         // a stability attribute, so we don't recurse.
@@ -126,27 +143,41 @@ impl<'a, 'v> Visitor<'v> for Annotator<'a> {
             TypeTraitItem(ref typedef) => (typedef.ty_param.id, &typedef.attrs,
                                            typedef.ty_param.span),
         };
-        self.annotate(id, true, attrs, sp, |v| visit::walk_trait_item(v, t));
+        self.annotate(id, true, attrs, sp, |v| visit::walk_trait_item(v, t), true);
     }
 
     fn visit_variant(&mut self, var: &Variant, g: &'v Generics) {
         self.annotate(var.node.id, true, &var.node.attrs, var.span,
-                      |v| visit::walk_variant(v, var, g))
+                      |v| visit::walk_variant(v, var, g), true)
     }
 
     fn visit_struct_field(&mut self, s: &StructField) {
         self.annotate(s.node.id, true, &s.node.attrs, s.span,
-                      |v| visit::walk_struct_field(v, s));
+                      |v| visit::walk_struct_field(v, s), true);
     }
 
     fn visit_foreign_item(&mut self, i: &ast::ForeignItem) {
-        self.annotate(i.id, true, &i.attrs, i.span, |_| {});
+        self.annotate(i.id, true, &i.attrs, i.span, |_| {}, true);
     }
 }
 
 impl Index {
     /// Construct the stability index for a crate being compiled.
-    pub fn build(sess: &Session, krate: &Crate) -> Index {
+    pub fn build(&mut self, sess: &Session, krate: &Crate, export_map: &PublicItems) {
+        if !self.staged_api {
+            return;
+        }
+        let mut annotator = Annotator {
+            sess: sess,
+            index: self,
+            parent: None,
+            export_map: export_map,
+        };
+        annotator.annotate(ast::CRATE_NODE_ID, true, &krate.attrs, krate.span,
+                           |v| visit::walk_crate(v, krate), true);
+    }
+
+    pub fn new(krate: &Crate) -> Index {
         let mut staged_api = false;
         for attr in &krate.attrs {
             if attr.name().get() == "staged_api" {
@@ -159,22 +190,11 @@ impl Index {
                 }
             }
         }
-        let index = Index {
+        Index {
             staged_api: staged_api,
             local: NodeMap(),
             extern_cache: DefIdMap()
-        };
-        if !staged_api {
-            return index;
         }
-        let mut annotator = Annotator {
-            sess: sess,
-            index: index,
-            parent: None
-        };
-        annotator.annotate(ast::CRATE_NODE_ID, true, &krate.attrs, krate.span,
-                           |v| visit::walk_crate(v, krate));
-        annotator.index
     }
 }
 
@@ -234,10 +254,19 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
             None => {
                 // This is an 'unmarked' API, which should not exist
                 // in the standard library.
-                self.tcx.sess.span_err(span, "use of unmarked library feature");
-                self.tcx.sess.span_note(span, "this is either a bug in the library you are \
-                                               using or a bug in the compiler - there is \
-                                               no way to use this feature");
+                if self.tcx.sess.features.borrow().unmarked_api {
+                    self.tcx.sess.span_warn(span, "use of unmarked library feature");
+                    self.tcx.sess.span_note(span, "this is either a bug in the library you are \
+                                                   using and a bug in the compiler - please \
+                                                   report it in both places");
+                } else {
+                    self.tcx.sess.span_err(span, "use of unmarked library feature");
+                    self.tcx.sess.span_note(span, "this is either a bug in the library you are \
+                                                   using and a bug in the compiler - please \
+                                                   report it in both places");
+                    self.tcx.sess.span_note(span, "use #![feature(unmarked_api)] in the \
+                                                   crate attributes to override this");
+                }
             }
         }
     }
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index 9b9cc14c476..8ede037594a 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -594,9 +594,6 @@ pub fn phase_3_run_analysis_passes<'tcx>(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(&sess, krate));
-
     time(time_passes, "static item recursion checking", (), |_|
          middle::check_static_recursion::check_crate(&sess, krate, &def_map, &ast_map));
 
@@ -608,7 +605,7 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
                             freevars,
                             region_map,
                             lang_items,
-                            stability_index);
+                            stability::Index::new(krate));
 
     // passes are timed inside typeck
     typeck::check_crate(&ty_cx, trait_map);
@@ -628,6 +625,10 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
             time(time_passes, "privacy checking", maps, |(a, b)|
                  rustc_privacy::check_crate(&ty_cx, &export_map, a, b));
 
+    // Do not move this check past lint
+    time(time_passes, "stability index", (), |_|
+         ty_cx.stability.borrow_mut().build(&ty_cx.sess, krate, &public_items));
+
     time(time_passes, "intrinsic checking", (), |_|
          middle::intrinsicck::check_crate(&ty_cx));
 
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index 20bf77190be..7dc0d9be539 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -125,7 +125,6 @@ fn test_env<F>(source_string: &str,
         resolve::resolve_crate(&sess, &ast_map, &lang_items, krate, resolve::MakeGlobMap::No);
     let named_region_map = resolve_lifetime::krate(&sess, krate, &def_map);
     let region_map = region::resolve_crate(&sess, krate);
-    let stability_index = stability::Index::build(&sess, krate);
     let tcx = ty::mk_ctxt(sess,
                           &arenas,
                           def_map,
@@ -134,7 +133,7 @@ fn test_env<F>(source_string: &str,
                           freevars,
                           region_map,
                           lang_items,
-                          stability_index);
+                          stability::Index::new(krate));
     let infcx = infer::new_infer_ctxt(&tcx);
     body(Env { infcx: &infcx });
     infcx.resolve_regions_and_report_errors(ast::CRATE_NODE_ID);
diff --git a/src/libstd/thread_local/mod.rs b/src/libstd/thread_local/mod.rs
index d4d777789dd..9de5fd1c770 100644
--- a/src/libstd/thread_local/mod.rs
+++ b/src/libstd/thread_local/mod.rs
@@ -45,6 +45,7 @@ pub mod scoped;
 
 // Sure wish we had macro hygiene, no?
 #[doc(hidden)]
+#[stable(feature = "rust1", since = "1.0.0")]
 pub mod __impl {
     pub use super::imp::Key as KeyInner;
     pub use super::imp::destroy_value;
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 4e76359e930..d7a51e1149f 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -119,6 +119,9 @@ static KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[
 
     // Allows use of #[staged_api]
     ("staged_api", "1.0.0", Active),
+
+    // Allows using items which are missing stability attributes
+    ("unmarked_api", "1.0.0", Active)
 ];
 
 enum Status {
@@ -145,6 +148,7 @@ pub struct Features {
     pub quote: bool,
     pub old_orphan_check: bool,
     pub simd_ffi: bool,
+    pub unmarked_api: bool,
     pub lib_features: Vec<(InternedString, Span)>
 }
 
@@ -157,6 +161,7 @@ impl Features {
             quote: false,
             old_orphan_check: false,
             simd_ffi: false,
+            unmarked_api: false,
             lib_features: Vec::new()
         }
     }
@@ -566,6 +571,7 @@ fn check_crate_inner<F>(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::C
         quote: cx.has_feature("quote"),
         old_orphan_check: cx.has_feature("old_orphan_check"),
         simd_ffi: cx.has_feature("simd_ffi"),
+        unmarked_api: cx.has_feature("unmarked_api"),
         lib_features: unknown_features
     }
 }
diff --git a/src/test/auxiliary/lint_stability.rs b/src/test/auxiliary/lint_stability.rs
index 3679557d06b..7ac3925fb24 100644
--- a/src/test/auxiliary/lint_stability.rs
+++ b/src/test/auxiliary/lint_stability.rs
@@ -11,6 +11,7 @@
 #![crate_type = "lib"]
 #![feature(staged_api)]
 #![staged_api]
+#![stable(feature = "lint_stability", since = "1.0.0")]
 
 #[stable(feature = "test_feature", since = "1.0.0")]
 #[deprecated(since = "1.0.0")]
@@ -31,8 +32,6 @@ pub fn unstable() {}
 #[unstable(feature = "test_feature", reason = "text")]
 pub fn unstable_text() {}
 
-pub fn unmarked() {}
-
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn stable() {}
 #[stable(feature = "rust1", since = "1.0.0", reason = "text")]
@@ -61,8 +60,6 @@ impl MethodTester {
     #[unstable(feature = "test_feature", reason = "text")]
     pub fn method_unstable_text(&self) {}
 
-    pub fn method_unmarked(&self) {}
-
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn method_stable(&self) {}
     #[stable(feature = "rust1", since = "1.0.0", reason = "text")]
@@ -79,6 +76,7 @@ impl MethodTester {
     pub fn method_frozen_text(&self) {}
 }
 
+#[stable(feature = "test_feature", since = "1.0.0")]
 pub trait Trait {
     #[stable(feature = "test_feature", since = "1.0.0")]
     #[deprecated(since = "1.0.0")]
@@ -99,8 +97,6 @@ pub trait Trait {
     #[unstable(feature = "test_feature", reason = "text")]
     fn trait_unstable_text(&self) {}
 
-    fn trait_unmarked(&self) {}
-
     #[stable(feature = "rust1", since = "1.0.0")]
     fn trait_stable(&self) {}
     #[stable(feature = "rust1", since = "1.0.0", reason = "text")]
@@ -130,7 +126,6 @@ pub struct DeprecatedStruct { pub i: int }
 pub struct DeprecatedUnstableStruct { pub i: int }
 #[unstable(feature = "test_feature")]
 pub struct UnstableStruct { pub i: int }
-pub struct UnmarkedStruct { pub i: int }
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct StableStruct { pub i: int }
 
@@ -142,10 +137,10 @@ pub struct DeprecatedUnitStruct;
 pub struct DeprecatedUnstableUnitStruct;
 #[unstable(feature = "test_feature")]
 pub struct UnstableUnitStruct;
-pub struct UnmarkedUnitStruct;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct StableUnitStruct;
 
+#[stable(feature = "test_feature", since = "1.0.0")]
 pub enum Enum {
     #[stable(feature = "test_feature", since = "1.0.0")]
     #[deprecated(since = "1.0.0")]
@@ -156,7 +151,6 @@ pub enum Enum {
     #[unstable(feature = "test_feature")]
     UnstableVariant,
 
-    UnmarkedVariant,
     #[stable(feature = "rust1", since = "1.0.0")]
     StableVariant,
 }
@@ -169,7 +163,6 @@ pub struct DeprecatedTupleStruct(pub int);
 pub struct DeprecatedUnstableTupleStruct(pub int);
 #[unstable(feature = "test_feature")]
 pub struct UnstableTupleStruct(pub int);
-pub struct UnmarkedTupleStruct(pub int);
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct StableTupleStruct(pub int);
 
diff --git a/src/test/compile-fail/lint-stability.rs b/src/test/compile-fail/lint-stability.rs
index 5b093a8556c..4cf75bf15de 100644
--- a/src/test/compile-fail/lint-stability.rs
+++ b/src/test/compile-fail/lint-stability.rs
@@ -20,7 +20,7 @@
 #![staged_api]
 
 #[macro_use]
-extern crate lint_stability; //~ ERROR: use of unmarked library feature
+extern crate lint_stability;
 
 mod cross_crate {
     extern crate stability_cfg1;
@@ -61,10 +61,6 @@ mod cross_crate {
         foo.method_unstable_text(); //~ WARNING use of unstable library feature 'test_feature': text
         foo.trait_unstable_text(); //~ WARNING use of unstable library feature 'test_feature': text
 
-        unmarked(); //~ ERROR use of unmarked library feature
-        foo.method_unmarked(); //~ ERROR use of unmarked library feature
-        foo.trait_unmarked(); //~ ERROR use of unmarked library feature
-
         stable();
         foo.method_stable();
         foo.trait_stable();
@@ -77,28 +73,24 @@ mod cross_crate {
         let _ = DeprecatedUnstableStruct { i: 0 }; //~ ERROR use of deprecated item
         //~^ WARNING use of unstable library feature
         let _ = UnstableStruct { i: 0 }; //~ WARNING use of unstable library feature
-        let _ = UnmarkedStruct { i: 0 }; //~ ERROR use of unmarked library feature
         let _ = StableStruct { i: 0 };
 
         let _ = DeprecatedUnitStruct; //~ ERROR use of deprecated item
         let _ = DeprecatedUnstableUnitStruct; //~ ERROR use of deprecated item
         //~^ WARNING use of unstable library feature
         let _ = UnstableUnitStruct; //~ WARNING use of unstable library feature
-        let _ = UnmarkedUnitStruct; //~ ERROR use of unmarked library feature
         let _ = StableUnitStruct;
 
         let _ = Enum::DeprecatedVariant; //~ ERROR use of deprecated item
         let _ = Enum::DeprecatedUnstableVariant; //~ ERROR use of deprecated item
         //~^ WARNING use of unstable library feature
         let _ = Enum::UnstableVariant; //~ WARNING use of unstable library feature
-        let _ = Enum::UnmarkedVariant; //~ ERROR use of unmarked library feature
         let _ = Enum::StableVariant;
 
         let _ = DeprecatedTupleStruct (1); //~ ERROR use of deprecated item
         let _ = DeprecatedUnstableTupleStruct (1); //~ ERROR use of deprecated item
         //~^ WARNING use of unstable library feature
         let _ = UnstableTupleStruct (1); //~ WARNING use of unstable library feature
-        let _ = UnmarkedTupleStruct (1); //~ ERROR use of unmarked library feature
         let _ = StableTupleStruct (1);
 
         // At the moment, the lint checker only checks stability in
@@ -123,7 +115,6 @@ mod cross_crate {
         //~^ WARNING use of unstable library feature
         foo.trait_unstable(); //~ WARNING use of unstable library feature
         foo.trait_unstable_text(); //~ WARNING use of unstable library feature 'test_feature': text
-        foo.trait_unmarked(); //~ ERROR use of unmarked library feature
         foo.trait_stable();
     }
 
@@ -136,7 +127,6 @@ mod cross_crate {
         //~^ WARNING use of unstable library feature
         foo.trait_unstable(); //~ WARNING use of unstable library feature
         foo.trait_unstable_text(); //~ WARNING use of unstable library feature 'test_feature': text
-        foo.trait_unmarked(); //~ ERROR use of unmarked library feature
         foo.trait_stable();
     }
 
@@ -183,8 +173,6 @@ mod this_crate {
     #[unstable(feature = "test_feature", reason = "text")]
     pub fn unstable_text() {}
 
-    pub fn unmarked() {}
-
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn stable() {}
     #[stable(feature = "rust1", since = "1.0.0", reason = "text")]
@@ -206,8 +194,6 @@ mod this_crate {
         #[unstable(feature = "test_feature", reason = "text")]
         pub fn method_unstable_text(&self) {}
 
-        pub fn method_unmarked(&self) {}
-
         #[stable(feature = "rust1", since = "1.0.0")]
         pub fn method_stable(&self) {}
         #[stable(feature = "rust1", since = "1.0.0", reason = "text")]
@@ -227,8 +213,6 @@ mod this_crate {
         #[unstable(feature = "test_feature", reason = "text")]
         fn trait_unstable_text(&self) {}
 
-        fn trait_unmarked(&self) {}
-
         #[stable(feature = "rust1", since = "1.0.0")]
         fn trait_stable(&self) {}
         #[stable(feature = "rust1", since = "1.0.0", reason = "text")]
@@ -242,7 +226,6 @@ mod this_crate {
     pub struct DeprecatedStruct { i: isize }
     #[unstable(feature = "test_feature")]
     pub struct UnstableStruct { i: isize }
-    pub struct UnmarkedStruct { i: isize }
     #[stable(feature = "rust1", since = "1.0.0")]
     pub struct StableStruct { i: isize }
 
@@ -251,7 +234,6 @@ mod this_crate {
     pub struct DeprecatedUnitStruct;
     #[unstable(feature = "test_feature")]
     pub struct UnstableUnitStruct;
-    pub struct UnmarkedUnitStruct;
     #[stable(feature = "rust1", since = "1.0.0")]
     pub struct StableUnitStruct;
 
@@ -262,7 +244,6 @@ mod this_crate {
         #[unstable(feature = "test_feature")]
         UnstableVariant,
 
-        UnmarkedVariant,
         #[stable(feature = "rust1", since = "1.0.0")]
         StableVariant,
     }
@@ -272,7 +253,6 @@ mod this_crate {
     pub struct DeprecatedTupleStruct(isize);
     #[unstable(feature = "test_feature")]
     pub struct UnstableTupleStruct(isize);
-    pub struct UnmarkedTupleStruct(isize);
     #[stable(feature = "rust1", since = "1.0.0")]
     pub struct StableTupleStruct(isize);
 
@@ -299,10 +279,6 @@ mod this_crate {
         foo.method_unstable_text();
         foo.trait_unstable_text();
 
-        unmarked();
-        foo.method_unmarked();
-        foo.trait_unmarked();
-
         stable();
         foo.method_stable();
         foo.trait_stable();
@@ -313,22 +289,18 @@ mod this_crate {
 
         let _ = DeprecatedStruct { i: 0 }; //~ ERROR use of deprecated item
         let _ = UnstableStruct { i: 0 };
-        let _ = UnmarkedStruct { i: 0 };
         let _ = StableStruct { i: 0 };
 
         let _ = DeprecatedUnitStruct; //~ ERROR use of deprecated item
         let _ = UnstableUnitStruct;
-        let _ = UnmarkedUnitStruct;
         let _ = StableUnitStruct;
 
         let _ = Enum::DeprecatedVariant; //~ ERROR use of deprecated item
         let _ = Enum::UnstableVariant;
-        let _ = Enum::UnmarkedVariant;
         let _ = Enum::StableVariant;
 
         let _ = DeprecatedTupleStruct (1); //~ ERROR use of deprecated item
         let _ = UnstableTupleStruct (1);
-        let _ = UnmarkedTupleStruct (1);
         let _ = StableTupleStruct (1);
     }
 
@@ -337,7 +309,6 @@ mod this_crate {
         foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
         foo.trait_unstable();
         foo.trait_unstable_text();
-        foo.trait_unmarked();
         foo.trait_stable();
     }
 
@@ -346,7 +317,6 @@ mod this_crate {
         foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
         foo.trait_unstable();
         foo.trait_unstable_text();
-        foo.trait_unmarked();
         foo.trait_stable();
     }
 
diff --git a/src/test/compile-fail/missing-stability.rs b/src/test/compile-fail/missing-stability.rs
new file mode 100644
index 00000000000..14dd983161b
--- /dev/null
+++ b/src/test/compile-fail/missing-stability.rs
@@ -0,0 +1,33 @@
+// 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.
+
+// Checks that exported items without stability attributes cause an error
+
+#![crate_type="lib"]
+#![feature(staged_api)]
+#![staged_api]
+
+pub fn unmarked() {
+    //~^ ERROR This node does not have a stability attribute
+    ()
+}
+
+#[unstable(feature = "foo")]
+pub mod foo {
+    // #[unstable] is inherited
+    pub fn unmarked() {}
+}
+
+#[stable(feature = "bar", since="1.0.0")]
+pub mod bar {
+    // #[stable] is not inherited
+    pub fn unmarked() {}
+    //~^ ERROR This node does not have a stability attribute
+}
\ No newline at end of file