about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--mk/cfg/arm-unknown-linux-gnueabi.mk4
-rw-r--r--mk/cfg/arm-unknown-linux-gnueabihf.mk4
-rw-r--r--src/doc/book/patterns.md2
-rw-r--r--src/librustc/lib.rs4
-rw-r--r--src/librustc/lint/builtin.rs7
-rw-r--r--src/librustc/middle/lang_items.rs7
-rw-r--r--src/librustc/session/config.rs181
-rw-r--r--src/librustc_driver/lib.rs150
-rw-r--r--src/librustc_lint/lib.rs4
-rw-r--r--src/librustc_privacy/lib.rs16
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs12
-rw-r--r--src/librustc_resolve/lib.rs47
-rw-r--r--src/librustc_resolve/resolve_imports.rs31
-rw-r--r--src/librustc_trans/lib.rs2
-rw-r--r--src/librustc_unicode/char.rs12
-rw-r--r--src/librustdoc/clean/mod.rs9
-rw-r--r--src/librustdoc/html/render.rs34
-rw-r--r--src/libstd/sys/unix/net.rs2
-rw-r--r--src/libsyntax/parse/parser.rs7
-rw-r--r--src/test/auxiliary/privacy_reexport.rs1
-rw-r--r--src/test/compile-fail/duplicate_entry_error.rs (renamed from src/test/compile-fail/warn-pub-extern-crate.rs)14
-rw-r--r--src/test/compile-fail/extern-crate-visibility.rs34
-rw-r--r--src/test/compile-fail/private-variant-and-crate-reexport.rs (renamed from src/test/compile-fail/private-variant-reexport.rs)4
-rw-r--r--src/test/run-pass/privacy-reexport.rs3
-rw-r--r--src/test/rustdoc/issue-26995.rs (renamed from src/test/compile-fail/no-extern-crate-in-glob-import.rs)19
-rw-r--r--src/test/rustdoc/issue-31808.rs23
26 files changed, 441 insertions, 192 deletions
diff --git a/mk/cfg/arm-unknown-linux-gnueabi.mk b/mk/cfg/arm-unknown-linux-gnueabi.mk
index 9244cc43650..f66ad04eefe 100644
--- a/mk/cfg/arm-unknown-linux-gnueabi.mk
+++ b/mk/cfg/arm-unknown-linux-gnueabi.mk
@@ -8,8 +8,8 @@ CFG_LIB_NAME_arm-unknown-linux-gnueabi=lib$(1).so
 CFG_STATIC_LIB_NAME_arm-unknown-linux-gnueabi=lib$(1).a
 CFG_LIB_GLOB_arm-unknown-linux-gnueabi=lib$(1)-*.so
 CFG_LIB_DSYM_GLOB_arm-unknown-linux-gnueabi=lib$(1)-*.dylib.dSYM
-CFG_JEMALLOC_CFLAGS_arm-unknown-linux-gnueabi := -D__arm__ -mfloat-abi=soft $(CFLAGS)
-CFG_GCCISH_CFLAGS_arm-unknown-linux-gnueabi := -Wall -g -fPIC -D__arm__ -mfloat-abi=soft $(CFLAGS)
+CFG_JEMALLOC_CFLAGS_arm-unknown-linux-gnueabi := -D__arm__ -mfloat-abi=soft $(CFLAGS) -march=armv6 -marm
+CFG_GCCISH_CFLAGS_arm-unknown-linux-gnueabi := -Wall -g -fPIC -D__arm__ -mfloat-abi=soft $(CFLAGS) -march=armv6 -marm
 CFG_GCCISH_CXXFLAGS_arm-unknown-linux-gnueabi := -fno-rtti $(CXXFLAGS)
 CFG_GCCISH_LINK_FLAGS_arm-unknown-linux-gnueabi := -shared -fPIC -g
 CFG_GCCISH_DEF_FLAG_arm-unknown-linux-gnueabi := -Wl,--export-dynamic,--dynamic-list=
diff --git a/mk/cfg/arm-unknown-linux-gnueabihf.mk b/mk/cfg/arm-unknown-linux-gnueabihf.mk
index 0bd661ea00d..defe0dc3e70 100644
--- a/mk/cfg/arm-unknown-linux-gnueabihf.mk
+++ b/mk/cfg/arm-unknown-linux-gnueabihf.mk
@@ -8,8 +8,8 @@ CFG_LIB_NAME_arm-unknown-linux-gnueabihf=lib$(1).so
 CFG_STATIC_LIB_NAME_arm-unknown-linux-gnueabihf=lib$(1).a
 CFG_LIB_GLOB_arm-unknown-linux-gnueabihf=lib$(1)-*.so
 CFG_LIB_DSYM_GLOB_arm-unknown-linux-gnueabihf=lib$(1)-*.dylib.dSYM
-CFG_JEMALLOC_CFLAGS_arm-unknown-linux-gnueabihf := -D__arm__ $(CFLAGS)
-CFG_GCCISH_CFLAGS_arm-unknown-linux-gnueabihf := -Wall -g -fPIC -D__arm__ $(CFLAGS)
+CFG_JEMALLOC_CFLAGS_arm-unknown-linux-gnueabihf := -D__arm__ $(CFLAGS) -march=armv6 -marm
+CFG_GCCISH_CFLAGS_arm-unknown-linux-gnueabihf := -Wall -g -fPIC -D__arm__ $(CFLAGS) -march=armv6 -marm
 CFG_GCCISH_CXXFLAGS_arm-unknown-linux-gnueabihf := -fno-rtti $(CXXFLAGS)
 CFG_GCCISH_LINK_FLAGS_arm-unknown-linux-gnueabihf := -shared -fPIC -g
 CFG_GCCISH_DEF_FLAG_arm-unknown-linux-gnueabihf := -Wl,--export-dynamic,--dynamic-list=
diff --git a/src/doc/book/patterns.md b/src/doc/book/patterns.md
index 6fd7f4cd475..7325d448962 100644
--- a/src/doc/book/patterns.md
+++ b/src/doc/book/patterns.md
@@ -303,7 +303,7 @@ struct Person {
 }
 
 let name = "Steve".to_string();
-let mut x: Option<Person> = Some(Person { name: Some(name) });
+let x: Option<Person> = Some(Person { name: Some(name) });
 match x {
     Some(Person { name: ref a @ Some(_), .. }) => println!("{:?}", a),
     _ => {}
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index 53fd867e7fd..bd256d19b67 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -51,7 +51,7 @@ extern crate getopts;
 extern crate graphviz;
 extern crate libc;
 extern crate rbml;
-extern crate rustc_llvm;
+pub extern crate rustc_llvm as llvm;
 extern crate rustc_back;
 extern crate rustc_front;
 extern crate rustc_data_structures;
@@ -66,8 +66,6 @@ extern crate serialize as rustc_serialize; // used by deriving
 #[cfg(test)]
 extern crate test;
 
-pub use rustc_llvm as llvm;
-
 #[macro_use]
 mod macros;
 
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index 99fea59e28d..4bb69a2688a 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -125,6 +125,12 @@ declare_lint! {
 }
 
 declare_lint! {
+    pub INACCESSIBLE_EXTERN_CRATE,
+    Warn,
+    "use of inaccessible extern crate erroneously allowed"
+}
+
+declare_lint! {
     pub INVALID_TYPE_PARAM_DEFAULT,
     Warn,
     "type parameter default erroneously allowed in invalid location"
@@ -167,6 +173,7 @@ impl LintPass for HardwiredLints {
             TRIVIAL_CASTS,
             TRIVIAL_NUMERIC_CASTS,
             PRIVATE_IN_PUBLIC,
+            INACCESSIBLE_EXTERN_CRATE,
             INVALID_TYPE_PARAM_DEFAULT,
             MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT,
             CONST_ERR,
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index a22ad7a0707..6cbb90627ea 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -184,10 +184,13 @@ impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> {
         // Check for duplicates.
         match self.items.items[item_index] {
             Some(original_def_id) if original_def_id != item_def_id => {
+                let cstore = &self.session.cstore;
                 span_err!(self.session, span, E0152,
-                    "duplicate entry for `{}`", LanguageItems::item_name(item_index));
+                          "duplicate entry for `{}`, first definition found in `{}`",
+                          LanguageItems::item_name(item_index),
+                          cstore.crate_name(item_def_id.krate));
             }
-            Some(_) | None => {
+            _ => {
                 // OK.
             }
         }
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index f835613cfcb..ea08bf021fb 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -749,24 +749,20 @@ pub fn build_target_config(opts: &Options, sp: &Handler) -> Config {
     }
 }
 
-/// Returns the "short" subset of the stable rustc command line options.
-pub fn short_optgroups() -> Vec<getopts::OptGroup> {
-    rustc_short_optgroups().into_iter()
-        .filter(|g|g.is_stable())
-        .map(|g|g.opt_group)
-        .collect()
-}
-
-/// Returns all of the stable rustc command line options.
-pub fn optgroups() -> Vec<getopts::OptGroup> {
-    rustc_optgroups().into_iter()
-        .filter(|g|g.is_stable())
-        .map(|g|g.opt_group)
-        .collect()
-}
-
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub enum OptionStability { Stable, Unstable }
+pub enum OptionStability {
+    Stable,
+
+    // FIXME: historically there were some options which were either `-Z` or
+    //        required the `-Z unstable-options` flag, which were all intended
+    //        to be unstable. Unfortunately we didn't actually gate usage of
+    //        these options on the stable compiler, so we still allow them there
+    //        today. There are some warnings printed out about this in the
+    //        driver.
+    UnstableButNotReally,
+
+    Unstable,
+}
 
 #[derive(Clone, PartialEq, Eq)]
 pub struct RustcOptGroup {
@@ -783,9 +779,17 @@ impl RustcOptGroup {
         RustcOptGroup { opt_group: g, stability: OptionStability::Stable }
     }
 
+    #[allow(dead_code)] // currently we have no "truly unstable" options
     fn unstable(g: getopts::OptGroup) -> RustcOptGroup {
         RustcOptGroup { opt_group: g, stability: OptionStability::Unstable }
     }
+
+    fn unstable_bnr(g: getopts::OptGroup) -> RustcOptGroup {
+        RustcOptGroup {
+            opt_group: g,
+            stability: OptionStability::UnstableButNotReally,
+        }
+    }
 }
 
 // The `opt` local module holds wrappers around the `getopts` API that
@@ -807,24 +811,57 @@ mod opt {
 
     fn stable(g: getopts::OptGroup) -> R { RustcOptGroup::stable(g) }
     fn unstable(g: getopts::OptGroup) -> R { RustcOptGroup::unstable(g) }
+    fn unstable_bnr(g: getopts::OptGroup) -> R { RustcOptGroup::unstable_bnr(g) }
 
-    // FIXME (pnkfelix): We default to stable since the current set of
-    // options is defacto stable.  However, it would be good to revise the
-    // code so that a stable option is the thing that takes extra effort
-    // to encode.
-
-    pub fn     opt(a: S, b: S, c: S, d: S) -> R { stable(getopts::optopt(a, b, c, d)) }
-    pub fn   multi(a: S, b: S, c: S, d: S) -> R { stable(getopts::optmulti(a, b, c, d)) }
-    pub fn    flag(a: S, b: S, c: S)       -> R { stable(getopts::optflag(a, b, c)) }
-    pub fn flagopt(a: S, b: S, c: S, d: S) -> R { stable(getopts::optflagopt(a, b, c, d)) }
-    pub fn flagmulti(a: S, b: S, c: S)     -> R { stable(getopts::optflagmulti(a, b, c)) }
+    pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
+        stable(getopts::optopt(a, b, c, d))
+    }
+    pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
+        stable(getopts::optmulti(a, b, c, d))
+    }
+    pub fn flag_s(a: S, b: S, c: S) -> R {
+        stable(getopts::optflag(a, b, c))
+    }
+    pub fn flagopt_s(a: S, b: S, c: S, d: S) -> R {
+        stable(getopts::optflagopt(a, b, c, d))
+    }
+    pub fn flagmulti_s(a: S, b: S, c: S) -> R {
+        stable(getopts::optflagmulti(a, b, c))
+    }
 
+    pub fn opt(a: S, b: S, c: S, d: S) -> R {
+        unstable(getopts::optopt(a, b, c, d))
+    }
+    pub fn multi(a: S, b: S, c: S, d: S) -> R {
+        unstable(getopts::optmulti(a, b, c, d))
+    }
+    pub fn flag(a: S, b: S, c: S) -> R {
+        unstable(getopts::optflag(a, b, c))
+    }
+    pub fn flagopt(a: S, b: S, c: S, d: S) -> R {
+        unstable(getopts::optflagopt(a, b, c, d))
+    }
+    pub fn flagmulti(a: S, b: S, c: S) -> R {
+        unstable(getopts::optflagmulti(a, b, c))
+    }
 
-    pub fn     opt_u(a: S, b: S, c: S, d: S) -> R { unstable(getopts::optopt(a, b, c, d)) }
-    pub fn   multi_u(a: S, b: S, c: S, d: S) -> R { unstable(getopts::optmulti(a, b, c, d)) }
-    pub fn    flag_u(a: S, b: S, c: S)       -> R { unstable(getopts::optflag(a, b, c)) }
-    pub fn flagopt_u(a: S, b: S, c: S, d: S) -> R { unstable(getopts::optflagopt(a, b, c, d)) }
-    pub fn flagmulti_u(a: S, b: S, c: S)     -> R { unstable(getopts::optflagmulti(a, b, c)) }
+    // Do not use these functions for any new options added to the compiler, all
+    // new options should use the `*_u` variants above to be truly unstable.
+    pub fn opt_ubnr(a: S, b: S, c: S, d: S) -> R {
+        unstable_bnr(getopts::optopt(a, b, c, d))
+    }
+    pub fn multi_ubnr(a: S, b: S, c: S, d: S) -> R {
+        unstable_bnr(getopts::optmulti(a, b, c, d))
+    }
+    pub fn flag_ubnr(a: S, b: S, c: S) -> R {
+        unstable_bnr(getopts::optflag(a, b, c))
+    }
+    pub fn flagopt_ubnr(a: S, b: S, c: S, d: S) -> R {
+        unstable_bnr(getopts::optflagopt(a, b, c, d))
+    }
+    pub fn flagmulti_ubnr(a: S, b: S, c: S) -> R {
+        unstable_bnr(getopts::optflagmulti(a, b, c))
+    }
 }
 
 /// Returns the "short" subset of the rustc command line options,
@@ -832,44 +869,44 @@ mod opt {
 /// part of the stable long-term interface for rustc.
 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
     vec![
-        opt::flag("h", "help", "Display this message"),
-        opt::multi("", "cfg", "Configure the compilation environment", "SPEC"),
-        opt::multi("L", "",   "Add a directory to the library search path",
+        opt::flag_s("h", "help", "Display this message"),
+        opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
+        opt::multi_s("L", "",   "Add a directory to the library search path",
                    "[KIND=]PATH"),
-        opt::multi("l", "",   "Link the generated crate(s) to the specified native
+        opt::multi_s("l", "",   "Link the generated crate(s) to the specified native
                              library NAME. The optional KIND can be one of,
                              static, dylib, or framework. If omitted, dylib is
                              assumed.", "[KIND=]NAME"),
-        opt::multi("", "crate-type", "Comma separated list of types of crates
+        opt::multi_s("", "crate-type", "Comma separated list of types of crates
                                     for the compiler to emit",
                    "[bin|lib|rlib|dylib|staticlib]"),
-        opt::opt("", "crate-name", "Specify the name of the crate being built",
+        opt::opt_s("", "crate-name", "Specify the name of the crate being built",
                "NAME"),
-        opt::multi("", "emit", "Comma separated list of types of output for \
+        opt::multi_s("", "emit", "Comma separated list of types of output for \
                               the compiler to emit",
                  "[asm|llvm-bc|llvm-ir|obj|link|dep-info]"),
-        opt::multi("", "print", "Comma separated list of compiler information to \
+        opt::multi_s("", "print", "Comma separated list of compiler information to \
                                print on stdout",
                  "[crate-name|file-names|sysroot|target-list]"),
-        opt::flagmulti("g",  "",  "Equivalent to -C debuginfo=2"),
-        opt::flagmulti("O", "", "Equivalent to -C opt-level=2"),
-        opt::opt("o", "", "Write output to <filename>", "FILENAME"),
-        opt::opt("",  "out-dir", "Write output to compiler-chosen filename \
+        opt::flagmulti_s("g",  "",  "Equivalent to -C debuginfo=2"),
+        opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
+        opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
+        opt::opt_s("",  "out-dir", "Write output to compiler-chosen filename \
                                 in <dir>", "DIR"),
-        opt::opt("", "explain", "Provide a detailed explanation of an error \
+        opt::opt_s("", "explain", "Provide a detailed explanation of an error \
                                message", "OPT"),
-        opt::flag("", "test", "Build a test harness"),
-        opt::opt("", "target", "Target triple for which the code is compiled", "TARGET"),
-        opt::multi("W", "warn", "Set lint warnings", "OPT"),
-        opt::multi("A", "allow", "Set lint allowed", "OPT"),
-        opt::multi("D", "deny", "Set lint denied", "OPT"),
-        opt::multi("F", "forbid", "Set lint forbidden", "OPT"),
-        opt::multi("", "cap-lints", "Set the most restrictive lint level. \
+        opt::flag_s("", "test", "Build a test harness"),
+        opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
+        opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
+        opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
+        opt::multi_s("D", "deny", "Set lint denied", "OPT"),
+        opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
+        opt::multi_s("", "cap-lints", "Set the most restrictive lint level. \
                                      More restrictive lints are capped at this \
                                      level", "LEVEL"),
-        opt::multi("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
-        opt::flag("V", "version", "Print version info and exit"),
-        opt::flag("v", "verbose", "Use verbose output"),
+        opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
+        opt::flag_s("V", "version", "Print version info and exit"),
+        opt::flag_s("v", "verbose", "Use verbose output"),
     ]
 }
 
@@ -879,24 +916,26 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
     let mut opts = rustc_short_optgroups();
     opts.extend_from_slice(&[
-        opt::multi("", "extern", "Specify where an external rust library is \
+        opt::multi_s("", "extern", "Specify where an external rust library is \
                                 located",
                  "NAME=PATH"),
-        opt::opt("", "sysroot", "Override the system root", "PATH"),
-        opt::multi("Z", "", "Set internal debugging options", "FLAG"),
-        opt::opt_u("", "error-format", "How errors and other messages are produced", "human|json"),
-        opt::opt("", "color", "Configure coloring of output:
+        opt::opt_s("", "sysroot", "Override the system root", "PATH"),
+        opt::multi_ubnr("Z", "", "Set internal debugging options", "FLAG"),
+        opt::opt_ubnr("", "error-format",
+                      "How errors and other messages are produced",
+                      "human|json"),
+        opt::opt_s("", "color", "Configure coloring of output:
             auto   = colorize, if output goes to a tty (default);
             always = always colorize output;
             never  = never colorize output", "auto|always|never"),
 
-        opt::flagopt_u("", "pretty",
+        opt::flagopt_ubnr("", "pretty",
                    "Pretty-print the input instead of compiling;
                    valid types are: `normal` (un-annotated source),
                    `expanded` (crates expanded), or
                    `expanded,identified` (fully parenthesized, AST nodes with IDs).",
                  "TYPE"),
-        opt::flagopt_u("", "unpretty",
+        opt::flagopt_ubnr("", "unpretty",
                      "Present the input source, unstable (and less-pretty) variants;
                       valid types are any of the types for `--pretty`, as well as:
                       `flowgraph=<nodeid>` (graphviz formatted flowgraph for node),
@@ -904,6 +943,14 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
                       `hir` (the HIR), `hir,identified`, or
                       `hir,typed` (HIR with types for each node).",
                      "TYPE"),
+
+        // new options here should **not** use the `_ubnr` functions, all new
+        // unstable options should use the short variants to indicate that they
+        // are truly unstable. All `_ubnr` flags are just that way because they
+        // were so historically.
+        //
+        // You may also wish to keep this comment at the bottom of this list to
+        // ensure that others see it.
     ]);
     opts
 }
@@ -1242,15 +1289,21 @@ impl fmt::Display for CrateType {
 #[cfg(test)]
 mod tests {
     use middle::cstore::DummyCrateStore;
-    use session::config::{build_configuration, optgroups, build_session_options};
+    use session::config::{build_configuration, build_session_options};
     use session::build_session;
 
     use std::rc::Rc;
-    use getopts::getopts;
+    use getopts::{getopts, OptGroup};
     use syntax::attr;
     use syntax::attr::AttrMetaMethods;
     use syntax::diagnostics;
 
+    fn optgroups() -> Vec<OptGroup> {
+        super::rustc_optgroups().into_iter()
+                                .map(|a| a.opt_group)
+                                .collect()
+    }
+
     // When the user supplies --test we should implicitly supply --cfg test
     #[test]
     fn test_switch_implies_cfg_test() {
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index e7766309110..d0f86cfcb46 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -65,6 +65,7 @@ use rustc_trans::back::link;
 use rustc_trans::save;
 use rustc::session::{config, Session, build_session, CompileResult};
 use rustc::session::config::{Input, PrintRequest, OutputType, ErrorOutputType};
+use rustc::session::config::{get_unstable_features_setting, OptionStability};
 use rustc::middle::cstore::CrateStore;
 use rustc::lint::Lint;
 use rustc::lint;
@@ -85,7 +86,7 @@ use std::str;
 use std::sync::{Arc, Mutex};
 use std::thread;
 
-use rustc::session::early_error;
+use rustc::session::{early_error, early_warn};
 
 use syntax::ast;
 use syntax::parse;
@@ -93,6 +94,7 @@ use syntax::errors;
 use syntax::errors::emitter::Emitter;
 use syntax::diagnostics;
 use syntax::parse::token;
+use syntax::feature_gate::UnstableFeatures;
 
 #[cfg(test)]
 pub mod test;
@@ -819,8 +821,31 @@ fn print_flag_list<T>(cmdline_opt: &str,
 }
 
 /// Process command line options. Emits messages as appropriate. If compilation
-/// should continue, returns a getopts::Matches object parsed from args, otherwise
-/// returns None.
+/// should continue, returns a getopts::Matches object parsed from args,
+/// otherwise returns None.
+///
+/// The compiler's handling of options is a little complication as it ties into
+/// our stability story, and it's even *more* complicated by historical
+/// accidents. The current intention of each compiler option is to have one of
+/// three modes:
+///
+/// 1. An option is stable and can be used everywhere.
+/// 2. An option is unstable, but was historically allowed on the stable
+///    channel.
+/// 3. An option is unstable, and can only be used on nightly.
+///
+/// Like unstable library and language features, however, unstable options have
+/// always required a form of "opt in" to indicate that you're using them. This
+/// provides the easy ability to scan a code base to check to see if anything
+/// unstable is being used. Currently, this "opt in" is the `-Z` "zed" flag.
+///
+/// All options behind `-Z` are considered unstable by default. Other top-level
+/// options can also be considered unstable, and they were unlocked through the
+/// `-Z unstable-options` flag. Note that `-Z` remains to be the root of
+/// instability in both cases, though.
+///
+/// So with all that in mind, the comments below have some more detail about the
+/// contortions done here to get things to work out correctly.
 pub fn handle_options(mut args: Vec<String>) -> Option<getopts::Matches> {
     // Throw away the first argument, the name of the binary
     let _binary = args.remove(0);
@@ -832,62 +857,83 @@ pub fn handle_options(mut args: Vec<String>) -> Option<getopts::Matches> {
         return None;
     }
 
-    fn allows_unstable_options(matches: &getopts::Matches) -> bool {
-        let r = matches.opt_strs("Z");
-        r.iter().any(|x| *x == "unstable-options")
-    }
+    // Parse with *all* options defined in the compiler, we don't worry about
+    // option stability here we just want to parse as much as possible.
+    let all_groups: Vec<getopts::OptGroup> = config::rustc_optgroups()
+                                                 .into_iter()
+                                                 .map(|x| x.opt_group)
+                                                 .collect();
+    let matches = match getopts::getopts(&args[..], &all_groups) {
+        Ok(m) => m,
+        Err(f) => early_error(ErrorOutputType::default(), &f.to_string()),
+    };
 
-    fn parse_all_options(args: &Vec<String>) -> getopts::Matches {
-        let all_groups: Vec<getopts::OptGroup> = config::rustc_optgroups()
-                                                     .into_iter()
-                                                     .map(|x| x.opt_group)
-                                                     .collect();
-        match getopts::getopts(&args[..], &all_groups) {
-            Ok(m) => {
-                if !allows_unstable_options(&m) {
-                    // If -Z unstable-options was not specified, verify that
-                    // no unstable options were present.
-                    for opt in config::rustc_optgroups().into_iter().filter(|x| !x.is_stable()) {
-                        let opt_name = if !opt.opt_group.long_name.is_empty() {
-                            &opt.opt_group.long_name
-                        } else {
-                            &opt.opt_group.short_name
-                        };
-                        if m.opt_present(opt_name) {
-                            early_error(ErrorOutputType::default(),
-                                        &format!("use of unstable option '{}' requires -Z \
-                                                  unstable-options",
-                                                 opt_name));
-                        }
-                    }
-                }
-                m
-            }
-            Err(f) => early_error(ErrorOutputType::default(), &f.to_string()),
+    // For all options we just parsed, we check a few aspects:
+    //
+    // * If the option is stable, we're all good
+    // * If the option wasn't passed, we're all good
+    // * If `-Z unstable-options` wasn't passed (and we're not a -Z option
+    //   ourselves), then we require the `-Z unstable-options` flag to unlock
+    //   this option that was passed.
+    // * If we're a nightly compiler, then unstable options are now unlocked, so
+    //   we're good to go.
+    // * Otherwise, if we're a truly unstable option then we generate an error
+    //   (unstable option being used on stable)
+    // * If we're a historically stable-but-should-be-unstable option then we
+    //   emit a warning that we're going to turn this into an error soon.
+    let has_z_unstable_options = matches.opt_strs("Z")
+                                        .iter()
+                                        .any(|x| *x == "unstable-options");
+    let really_allows_unstable_options = match get_unstable_features_setting() {
+        UnstableFeatures::Disallow => false,
+        _ => true,
+    };
+    for opt in config::rustc_optgroups() {
+        if opt.stability == OptionStability::Stable {
+            continue
         }
-    }
-
-    // As a speed optimization, first try to parse the command-line using just
-    // the stable options.
-    let matches = match getopts::getopts(&args[..], &config::optgroups()) {
-        Ok(ref m) if allows_unstable_options(m) => {
-            // If -Z unstable-options was specified, redo parsing with the
-            // unstable options to ensure that unstable options are defined
-            // in the returned getopts::Matches.
-            parse_all_options(&args)
+        let opt_name = if !opt.opt_group.long_name.is_empty() {
+            &opt.opt_group.long_name
+        } else {
+            &opt.opt_group.short_name
+        };
+        if !matches.opt_present(opt_name) {
+            continue
         }
-        Ok(m) => m,
-        Err(_) => {
-            // redo option parsing, including unstable options this time,
-            // in anticipation that the mishandled option was one of the
-            // unstable ones.
-            parse_all_options(&args)
+        if opt_name != "Z" && !has_z_unstable_options {
+            let msg = format!("the `-Z unstable-options` flag must also be \
+                               passed to enable the flag `{}`", opt_name);
+            early_error(ErrorOutputType::default(), &msg);
         }
-    };
+        if really_allows_unstable_options {
+            continue
+        }
+        match opt.stability {
+            OptionStability::Unstable => {
+                let msg = format!("the option `{}` is only accepted on the \
+                                   nightly compiler", opt_name);
+                early_error(ErrorOutputType::default(), &msg);
+            }
+            OptionStability::UnstableButNotReally => {
+                let msg = format!("the option `{}` is is unstable and should \
+                                   only be used on the nightly compiler, but \
+                                   it is currently accepted for backwards \
+                                   compatibility; this will soon change, \
+                                   see issue #31847 for more details",
+                                  opt_name);
+                early_warn(ErrorOutputType::default(), &msg);
+            }
+            OptionStability::Stable => {}
+        }
+    }
 
     if matches.opt_present("h") || matches.opt_present("help") {
+        // Only show unstable options in --help if we *really* accept unstable
+        // options, which catches the case where we got `-Z unstable-options` on
+        // the stable channel of Rust which was accidentally allowed
+        // historically.
         usage(matches.opt_present("verbose"),
-              allows_unstable_options(&matches));
+              has_z_unstable_options && really_allows_unstable_options);
         return None;
     }
 
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index 6868b4f2ab7..1cf0339c086 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -159,6 +159,10 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
             reference: "the explanation for E0446 (`--explain E0446`)",
         },
         FutureIncompatibleInfo {
+            id: LintId::of(INACCESSIBLE_EXTERN_CRATE),
+            reference: "PR 31362 <https://github.com/rust-lang/rust/pull/31362>",
+        },
+        FutureIncompatibleInfo {
             id: LintId::of(INVALID_TYPE_PARAM_DEFAULT),
             reference: "PR 30742 <https://github.com/rust-lang/rust/pull/30724>",
         },
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index f0786b9b1fa..8908dac7a36 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -743,6 +743,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
                      source_did: Option<DefId>,
                      msg: &str)
                      -> CheckResult {
+        use rustc_front::hir::Item_::ItemExternCrate;
         debug!("ensure_public(span={:?}, to_check={:?}, source_did={:?}, msg={:?})",
                span, to_check, source_did, msg);
         let def_privacy = self.def_privacy(to_check);
@@ -763,6 +764,21 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
         // be local.)
         let def_id = source_did.unwrap_or(to_check);
         let node_id = self.tcx.map.as_local_node_id(def_id);
+
+        // Warn when using a inaccessible extern crate.
+        if let Some(node_id) = self.tcx.map.as_local_node_id(to_check) {
+            match self.tcx.map.get(node_id) {
+                ast_map::Node::NodeItem(&hir::Item { node: ItemExternCrate(_), name, .. }) => {
+                    self.tcx.sess.add_lint(lint::builtin::INACCESSIBLE_EXTERN_CRATE,
+                                           node_id,
+                                           span,
+                                           format!("extern crate `{}` is private", name));
+                    return None;
+                }
+                _ => {}
+            }
+        }
+
         let (err_span, err_msg) = if Some(id) == node_id {
             return Some((span, format!("{} is private", msg), None));
         } else {
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index a25968174fd..385fae46cba 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -293,9 +293,19 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
                     self.external_exports.insert(def_id);
                     let parent_link = ModuleParentLink(parent, name);
                     let def = Def::Mod(def_id);
-                    let external_module = self.new_extern_crate_module(parent_link, def);
+                    let local_def_id = self.ast_map.local_def_id(item.id);
+                    let external_module =
+                        self.new_extern_crate_module(parent_link, def, is_public, local_def_id);
                     self.define(parent, name, TypeNS, (external_module, sp));
 
+                    if is_public {
+                        let export = Export { name: name, def_id: def_id };
+                        if let Some(def_id) = parent.def_id() {
+                            let node_id = self.resolver.ast_map.as_local_node_id(def_id).unwrap();
+                            self.export_map.entry(node_id).or_insert(Vec::new()).push(export);
+                        }
+                    }
+
                     self.build_reduced_graph_for_external_crate(external_module);
                 }
                 parent
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 11c51522b67..3e2837f023d 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -806,7 +806,10 @@ pub struct ModuleS<'a> {
     parent_link: ParentLink<'a>,
     def: Option<Def>,
     is_public: bool,
-    is_extern_crate: bool,
+
+    // If the module is an extern crate, `def` is root of the external crate and `extern_crate_did`
+    // is the DefId of the local `extern crate` item (otherwise, `extern_crate_did` is None).
+    extern_crate_did: Option<DefId>,
 
     resolutions: RefCell<HashMap<(Name, Namespace), NameResolution<'a>>>,
     unresolved_imports: RefCell<Vec<ImportDirective>>,
@@ -853,7 +856,7 @@ impl<'a> ModuleS<'a> {
             parent_link: parent_link,
             def: def,
             is_public: is_public,
-            is_extern_crate: false,
+            extern_crate_did: None,
             resolutions: RefCell::new(HashMap::new()),
             unresolved_imports: RefCell::new(Vec::new()),
             module_children: RefCell::new(NodeMap()),
@@ -917,6 +920,16 @@ impl<'a> ModuleS<'a> {
         self.def.as_ref().map(Def::def_id)
     }
 
+    // This returns the DefId of the crate local item that controls this module's visibility.
+    // It is only used to compute `LastPrivate` data, and it differs from `def_id` only for extern
+    // crates, whose `def_id` is the external crate's root, not the local `extern crate` item.
+    fn local_def_id(&self) -> Option<DefId> {
+        match self.extern_crate_did {
+            Some(def_id) => Some(def_id),
+            None => self.def_id(),
+        }
+    }
+
     fn is_normal(&self) -> bool {
         match self.def {
             Some(Def::Mod(_)) | Some(Def::ForeignMod(_)) => true,
@@ -1027,6 +1040,14 @@ impl<'a> NameBinding<'a> {
         }
     }
 
+    fn local_def_id(&self) -> Option<DefId> {
+        match self.kind {
+            NameBindingKind::Def(def) => Some(def.def_id()),
+            NameBindingKind::Module(ref module) => module.local_def_id(),
+            NameBindingKind::Import { binding, .. } => binding.local_def_id(),
+        }
+    }
+
     fn defined_with(&self, modifiers: DefModifiers) -> bool {
         self.modifiers.contains(modifiers)
     }
@@ -1038,11 +1059,12 @@ impl<'a> NameBinding<'a> {
     fn def_and_lp(&self) -> (Def, LastPrivate) {
         let def = self.def().unwrap();
         if let Def::Err = def { return (def, LastMod(AllPublic)) }
-        (def, LastMod(if self.is_public() { AllPublic } else { DependsOn(def.def_id()) }))
+        let lp = if self.is_public() { AllPublic } else { DependsOn(self.local_def_id().unwrap()) };
+        (def, LastMod(lp))
     }
 
     fn is_extern_crate(&self) -> bool {
-        self.module().map(|module| module.is_extern_crate).unwrap_or(false)
+        self.module().and_then(|module| module.extern_crate_did).is_some()
     }
 
     fn is_import(&self) -> bool {
@@ -1236,9 +1258,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         self.arenas.name_bindings.alloc(name_binding)
     }
 
-    fn new_extern_crate_module(&self, parent_link: ParentLink<'a>, def: Def) -> Module<'a> {
-        let mut module = ModuleS::new(parent_link, Some(def), false, true);
-        module.is_extern_crate = true;
+    fn new_extern_crate_module(&self,
+                               parent_link: ParentLink<'a>,
+                               def: Def,
+                               is_public: bool,
+                               local_def: DefId)
+                               -> Module<'a> {
+        let mut module = ModuleS::new(parent_link, Some(def), false, is_public);
+        module.extern_crate_did = Some(local_def);
         self.arenas.modules.alloc(module)
     }
 
@@ -1357,7 +1384,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         // Keep track of the closest private module used
                         // when resolving this import chain.
                         if !binding.is_public() {
-                            if let Some(did) = search_module.def_id() {
+                            if let Some(did) = search_module.local_def_id() {
                                 closest_private = LastMod(DependsOn(did));
                             }
                         }
@@ -1462,7 +1489,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             Success(PrefixFound(ref containing_module, index)) => {
                 search_module = containing_module;
                 start_index = index;
-                last_private = LastMod(DependsOn(containing_module.def_id()
+                last_private = LastMod(DependsOn(containing_module.local_def_id()
                                                                   .unwrap()));
             }
         }
@@ -3571,7 +3598,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
 
                     if !in_module_is_extern || name_binding.is_public() {
                         // add the module to the lookup
-                        let is_extern = in_module_is_extern || module.is_extern_crate;
+                        let is_extern = in_module_is_extern || name_binding.is_extern_crate();
                         worklist.push((module, path_segments, is_extern));
                     }
                 }
diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs
index 9c6e51c647c..c068ff258b0 100644
--- a/src/librustc_resolve/resolve_imports.rs
+++ b/src/librustc_resolve/resolve_imports.rs
@@ -394,7 +394,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
                                            directive.is_public &&
                                            !name_binding.is_public() => {
                 let msg = format!("`{}` is private, and cannot be reexported", source);
-                let note_msg = format!("Consider marking `{}` as `pub` in the imported module",
+                let note_msg = format!("consider marking `{}` as `pub` in the imported module",
                                         source);
                 struct_span_err!(self.resolver.session, directive.span, E0364, "{}", &msg)
                     .span_note(directive.span, &note_msg)
@@ -403,12 +403,22 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
 
             (_, &Success(name_binding)) if !name_binding.is_import() && directive.is_public => {
                 if !name_binding.is_public() {
-                    let msg = format!("`{}` is private, and cannot be reexported", source);
-                    let note_msg =
-                        format!("Consider declaring type or module `{}` with `pub`", source);
-                    struct_span_err!(self.resolver.session, directive.span, E0365, "{}", &msg)
-                        .span_note(directive.span, &note_msg)
-                        .emit();
+                    if name_binding.is_extern_crate() {
+                        let msg = format!("extern crate `{}` is private, and cannot be reexported \
+                                           (error E0364), consider declaring with `pub`",
+                                           source);
+                        self.resolver.session.add_lint(lint::builtin::PRIVATE_IN_PUBLIC,
+                                                       directive.id,
+                                                       directive.span,
+                                                       msg);
+                    } else {
+                        let msg = format!("`{}` is private, and cannot be reexported", source);
+                        let note_msg =
+                            format!("consider declaring type or module `{}` with `pub`", source);
+                        struct_span_err!(self.resolver.session, directive.span, E0365, "{}", &msg)
+                            .span_note(directive.span, &note_msg)
+                            .emit();
+                    }
                 } else if name_binding.defined_with(DefModifiers::PRIVATE_VARIANT) {
                     let msg = format!("variant `{}` is private, and cannot be reexported \
                                        (error E0364), consider declaring its enum as `pub`",
@@ -441,9 +451,9 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
         module_.decrement_outstanding_references_for(target, TypeNS);
 
         let def_and_priv = |binding: &NameBinding| {
-            let def = binding.def().unwrap();
-            let last_private = if binding.is_public() { lp } else { DependsOn(def.def_id()) };
-            (def, last_private)
+            let last_private =
+                if binding.is_public() { lp } else { DependsOn(binding.local_def_id().unwrap()) };
+            (binding.def().unwrap(), last_private)
         };
         let value_def_and_priv = value_result.success().map(&def_and_priv);
         let type_def_and_priv = type_result.success().map(&def_and_priv);
@@ -493,7 +503,6 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
         build_reduced_graph::populate_module_if_necessary(self.resolver, target_module);
         target_module.for_each_child(|name, ns, binding| {
             if !binding.defined_with(DefModifiers::IMPORTABLE | DefModifiers::PUBLIC) { return }
-            if binding.is_extern_crate() { return }
             self.define(module_, name, ns, directive.import(binding));
 
             if ns == TypeNS && directive.is_public &&
diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs
index 27d6dbae28a..6f596b15b92 100644
--- a/src/librustc_trans/lib.rs
+++ b/src/librustc_trans/lib.rs
@@ -46,7 +46,7 @@ extern crate rustc;
 extern crate rustc_back;
 extern crate rustc_data_structures;
 extern crate rustc_front;
-extern crate rustc_llvm as llvm;
+pub extern crate rustc_llvm as llvm;
 extern crate rustc_mir;
 extern crate rustc_platform_intrinsics as intrinsics;
 extern crate serialize;
diff --git a/src/librustc_unicode/char.rs b/src/librustc_unicode/char.rs
index a489b4991f4..11500286755 100644
--- a/src/librustc_unicode/char.rs
+++ b/src/librustc_unicode/char.rs
@@ -457,16 +457,16 @@ impl char {
     ///
     /// # Examples
     ///
-    /// In both of these examples, 'ß' takes one `u16` to encode.
+    /// In both of these examples, '𝕊' takes two `u16`s to encode.
     ///
     /// ```
     /// #![feature(unicode)]
     ///
-    /// let mut b = [0; 1];
+    /// let mut b = [0; 2];
     ///
-    /// let result = 'ß'.encode_utf16(&mut b);
+    /// let result = '𝕊'.encode_utf16(&mut b);
     ///
-    /// assert_eq!(result, Some(1));
+    /// assert_eq!(result, Some(2));
     /// ```
     ///
     /// A buffer that's too small:
@@ -474,9 +474,9 @@ impl char {
     /// ```
     /// #![feature(unicode)]
     ///
-    /// let mut b = [0; 0];
+    /// let mut b = [0; 1];
     ///
-    /// let result = 'ß'.encode_utf8(&mut b);
+    /// let result = '𝕊'.encode_utf16(&mut b);
     ///
     /// assert_eq!(result, None);
     /// ```
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 7072f1b498b..1ff88f1d127 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -48,6 +48,7 @@ use std::collections::HashMap;
 use std::path::PathBuf;
 use std::rc::Rc;
 use std::u32;
+use std::env::current_dir;
 
 use core::DocContext;
 use doctree;
@@ -201,7 +202,13 @@ impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
         }
 
         let src = match cx.input {
-            Input::File(ref path) => path.clone(),
+            Input::File(ref path) => {
+                if path.is_absolute() {
+                    path.clone()
+                } else {
+                    current_dir().unwrap().join(path)
+                }
+            },
             Input::Str(_) => PathBuf::new() // FIXME: this is wrong
         };
 
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 1b97b3865d4..d7100f9f220 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -46,7 +46,7 @@ use std::io::prelude::*;
 use std::io::{self, BufWriter, BufReader};
 use std::iter::repeat;
 use std::mem;
-use std::path::{PathBuf, Path};
+use std::path::{PathBuf, Path, Component};
 use std::str;
 use std::sync::Arc;
 
@@ -243,6 +243,7 @@ pub struct Cache {
 
     stack: Vec<String>,
     parent_stack: Vec<DefId>,
+    parent_is_trait_impl: bool,
     search_index: Vec<IndexItem>,
     privmod: bool,
     remove_priv: bool,
@@ -487,6 +488,7 @@ pub fn run(mut krate: clean::Crate,
         stack: Vec::new(),
         parent_stack: Vec::new(),
         search_index: Vec::new(),
+        parent_is_trait_impl: false,
         extern_locations: HashMap::new(),
         primitive_locations: HashMap::new(),
         remove_priv: cx.passes.contains("strip-private"),
@@ -810,16 +812,17 @@ fn clean_srcpath<F>(src_root: &Path, p: &Path, keep_filename: bool, mut f: F) wh
     // make it relative, if possible
     let p = p.strip_prefix(src_root).unwrap_or(p);
 
-    let mut iter = p.iter().map(|x| x.to_str().unwrap()).peekable();
+    let mut iter = p.components().peekable();
+
     while let Some(c) = iter.next() {
         if !keep_filename && iter.peek().is_none() {
             break;
         }
 
-        if ".." == c {
-            f("up");
-        } else {
-            f(c)
+        match c {
+            Component::ParentDir => f("up"),
+            Component::Normal(c) => f(c.to_str().unwrap()),
+            _ => continue,
         }
     }
 }
@@ -871,7 +874,7 @@ impl<'a> DocFolder for SourceCollector<'a> {
             // entire crate. The other option is maintaining this mapping on a
             // per-file basis, but that's probably not worth it...
             self.cx
-                .include_sources = match self.emit_source(&item.source .filename) {
+                .include_sources = match self.emit_source(&item.source.filename) {
                 Ok(()) => true,
                 Err(e) => {
                     println!("warning: source code was requested to be rendered, \
@@ -995,6 +998,11 @@ impl DocFolder for Cache {
         // Index this method for searching later on
         if let Some(ref s) = item.name {
             let (parent, is_method) = match item.inner {
+                clean::AssociatedConstItem(..) |
+                clean::TypedefItem(_, true) if self.parent_is_trait_impl => {
+                    // skip associated items in trait impls
+                    ((None, None), false)
+                }
                 clean::AssociatedTypeItem(..) |
                 clean::AssociatedConstItem(..) |
                 clean::TyMethodItem(..) |
@@ -1026,10 +1034,6 @@ impl DocFolder for Cache {
                         ((Some(*last), path), true)
                     }
                 }
-                clean::TypedefItem(_, true) => {
-                    // skip associated types in impls
-                    ((None, None), false)
-                }
                 _ => ((None, Some(&*self.stack)), false)
             };
             let hidden_field = match item.inner {
@@ -1115,12 +1119,15 @@ impl DocFolder for Cache {
         }
 
         // Maintain the parent stack
+        let orig_parent_is_trait_impl = self.parent_is_trait_impl;
         let parent_pushed = match item.inner {
             clean::TraitItem(..) | clean::EnumItem(..) | clean::StructItem(..) => {
                 self.parent_stack.push(item.def_id);
+                self.parent_is_trait_impl = false;
                 true
             }
             clean::ImplItem(ref i) => {
+                self.parent_is_trait_impl = i.trait_.is_some();
                 match i.for_ {
                     clean::ResolvedPath{ did, .. } => {
                         self.parent_stack.push(did);
@@ -1201,6 +1208,7 @@ impl DocFolder for Cache {
         if pushed { self.stack.pop().unwrap(); }
         if parent_pushed { self.parent_stack.pop().unwrap(); }
         self.privmod = orig_privmod;
+        self.parent_is_trait_impl = orig_parent_is_trait_impl;
         return ret;
     }
 }
@@ -1489,9 +1497,11 @@ impl<'a> Item<'a> {
                           true, |component| {
                 path.push(component.to_string());
             });
+
             // If the span points into an external macro the
             // source-file will be bogus, i.e `<foo macros>`
-            if Path::new(&self.item.source.filename).is_file() {
+            let filename = &self.item.source.filename;
+            if !(filename.starts_with("<") && filename.ends_with("macros>")) {
                 Some(format!("{root}src/{krate}/{path}.html#{href}",
                              root = self.cx.root_path,
                              krate = self.cx.layout.krate,
diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs
index 507cc0f4ea4..16c369674f0 100644
--- a/src/libstd/sys/unix/net.rs
+++ b/src/libstd/sys/unix/net.rs
@@ -21,7 +21,7 @@ use sys_common::net::{getsockopt, setsockopt};
 use time::Duration;
 
 pub use sys::{cvt, cvt_r};
-pub use libc as netc;
+pub extern crate libc as netc;
 
 pub type wrlen_t = size_t;
 
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index d65a5e56b90..b5d29a0d6db 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -5487,13 +5487,6 @@ impl<'a> Parser<'a> {
         try!(self.expect(&token::Semi));
 
         let last_span = self.last_span;
-
-        if visibility == ast::Visibility::Public {
-            self.span_warn(mk_sp(lo, last_span.hi),
-                           "`pub extern crate` does not work as expected and should not be used. \
-                            Likely to become an error. Prefer `extern crate` and `pub use`.");
-        }
-
         Ok(self.mk_item(lo,
                         last_span.hi,
                         ident,
diff --git a/src/test/auxiliary/privacy_reexport.rs b/src/test/auxiliary/privacy_reexport.rs
index e60dbb290b0..fd97f210a55 100644
--- a/src/test/auxiliary/privacy_reexport.rs
+++ b/src/test/auxiliary/privacy_reexport.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+pub extern crate core;
 pub use foo as bar;
 
 pub mod foo {
diff --git a/src/test/compile-fail/warn-pub-extern-crate.rs b/src/test/compile-fail/duplicate_entry_error.rs
index de3cc27c49b..d39553a7267 100644
--- a/src/test/compile-fail/warn-pub-extern-crate.rs
+++ b/src/test/compile-fail/duplicate_entry_error.rs
@@ -8,9 +8,15 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(rustc_attrs)]
+// Test for issue #31788
 
-pub extern crate core; //~WARN `pub extern crate` does not work
+// error-pattern: duplicate entry for `panic_fmt`, first definition found in `std`
 
-#[rustc_error]
-fn main() {} //~ ERROR: compilation successful
+#![feature(lang_items)]
+
+#[lang = "panic_fmt"]
+fn panic_fmt() -> ! {
+    loop {}
+}
+
+fn main() {}
\ No newline at end of file
diff --git a/src/test/compile-fail/extern-crate-visibility.rs b/src/test/compile-fail/extern-crate-visibility.rs
new file mode 100644
index 00000000000..56a41a15ab3
--- /dev/null
+++ b/src/test/compile-fail/extern-crate-visibility.rs
@@ -0,0 +1,34 @@
+// Copyright 2016 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(rustc_attrs)]
+#![allow(dead_code)]
+#![allow(unused_imports)]
+
+mod foo {
+    extern crate core;
+}
+
+// Check that private crates can be used from outside their modules, albeit with warnings
+use foo::core; //~ WARN extern crate `core` is private
+//~^ WARN this was previously accepted by the compiler but is being phased out
+use foo::core::cell; //~ WARN extern crate `core` is private
+//~^ WARN this was previously accepted by the compiler but is being phased out
+
+fn f() {
+    foo::core::cell::Cell::new(0); //~ WARN extern crate `core` is private
+    //~^ WARN this was previously accepted by the compiler but is being phased out
+
+    use foo::*;
+    mod core {} // Check that private crates are not glob imported
+}
+
+#[rustc_error]
+fn main() {} //~ ERROR compilation successful
diff --git a/src/test/compile-fail/private-variant-reexport.rs b/src/test/compile-fail/private-variant-and-crate-reexport.rs
index 06f08dc13c6..5811d82681e 100644
--- a/src/test/compile-fail/private-variant-reexport.rs
+++ b/src/test/compile-fail/private-variant-and-crate-reexport.rs
@@ -11,6 +11,10 @@
 #![feature(rustc_attrs)]
 #![allow(dead_code)]
 
+extern crate core;
+pub use core as reexported_core; //~ WARN extern crate `core` is private, and cannot be reexported
+//~^ WARNING hard error
+
 mod m1 {
     pub use ::E::V; //~ WARN variant `V` is private, and cannot be reexported
     //~^ WARNING hard error
diff --git a/src/test/run-pass/privacy-reexport.rs b/src/test/run-pass/privacy-reexport.rs
index d9d107d900b..15c977afe2a 100644
--- a/src/test/run-pass/privacy-reexport.rs
+++ b/src/test/run-pass/privacy-reexport.rs
@@ -15,5 +15,8 @@
 extern crate privacy_reexport;
 
 pub fn main() {
+    // Check that public extern crates are visible to outside crates
+    privacy_reexport::core::cell::Cell::new(0);
+
     privacy_reexport::bar::frob();
 }
diff --git a/src/test/compile-fail/no-extern-crate-in-glob-import.rs b/src/test/rustdoc/issue-26995.rs
index 75882c5e981..bfb440a1839 100644
--- a/src/test/compile-fail/no-extern-crate-in-glob-import.rs
+++ b/src/test/rustdoc/issue-26995.rs
@@ -1,4 +1,4 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -8,15 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// Check that extern crate declarations are excluded from glob imports.
+// ignore-windows
+// compile-flags: --no-defaults
 
-#![feature(core)]
-extern crate core;
-
-mod T {
-    pub use super::*;
-}
-
-fn main() {
-    use T::core; //~ ERROR unresolved import `T::core`
-}
+// @has src/issue_26995/dev/null.html
+// @has issue_26995/null/index.html '//a/@href' '../../src/issue_26995/dev/null.html'
+#[path="/dev/null"]
+pub mod null;
diff --git a/src/test/rustdoc/issue-31808.rs b/src/test/rustdoc/issue-31808.rs
new file mode 100644
index 00000000000..46be8229d7c
--- /dev/null
+++ b/src/test/rustdoc/issue-31808.rs
@@ -0,0 +1,23 @@
+// Copyright 2016 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(associated_consts, associated_types)]
+
+// Test that associated item impls on primitive types don't crash rustdoc
+
+pub trait Foo {
+    const BAR: usize;
+    type BAZ;
+}
+
+impl Foo for () {
+    const BAR: usize = 0;
+    type BAZ = usize;
+}