about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-01-08 19:46:58 +0000
committerbors <bors@rust-lang.org>2020-01-08 19:46:58 +0000
commitcaa231d998a5e853c7ba1455d7a05b500df9d63c (patch)
tree16bcf8c8c892384fc5bff9f175d4e7a5aa5b6d13
parented6468da160bd67a2ce0573427f09a98daff8c07 (diff)
parent844530e31788e4898bed66cd121aa8e7ea737ded (diff)
downloadrust-caa231d998a5e853c7ba1455d7a05b500df9d63c.tar.gz
rust-caa231d998a5e853c7ba1455d7a05b500df9d63c.zip
Auto merge of #68011 - JohnTitor:rollup-44s8twu, r=JohnTitor
Rollup of 10 pull requests

Successful merges:

 - #67774 (Try statx for all linux-gnu target.)
 - #67781 (Move `is_min_const_fn` query to librustc_mir.)
 - #67798 (Remove wrong advice about spin locks from `spin_loop_hint` docs)
 - #67849 (Add a check for swapped words when we can't find an identifier)
 - #67875 (Distinguish between private items and hidden items in rustdoc)
 - #67887 (`Option::{expect,unwrap}` and `Result::{expect, expect_err, unwrap, unwrap_err}` have `#[track_caller]`)
 - #67955 (rustdoc: Remove more `#[doc(cfg(..))]` duplicates)
 - #67977 (Updates for VxWorks)
 - #67985 (Remove insignificant notes from CStr documentation)
 - #68003 (ci: fix wrong shared.sh import for publish_toolstate)

Failed merges:

 - #67820 (Parse the syntax described in RFC 2632)
 - #67979 (Move `intravisit` => `rustc_hir` + misc cleanup)

r? @ghost
-rwxr-xr-xsrc/ci/publish_toolstate.sh2
-rw-r--r--src/libcore/option.rs6
-rw-r--r--src/libcore/result.rs5
-rw-r--r--src/libcore/sync/atomic.rs14
-rw-r--r--src/librustc/ty/constness.rs156
-rw-r--r--src/librustc/ty/mod.rs2
-rw-r--r--src/librustc_mir/const_eval.rs2
-rw-r--r--src/librustc_mir/const_eval/fn_queries.rs151
-rw-r--r--src/librustc_mir/lib.rs1
-rw-r--r--src/librustc_mir/transform/check_consts/validation.rs7
-rw-r--r--src/librustc_mir/transform/check_unsafety.rs3
-rw-r--r--src/librustc_mir/transform/promote_consts.rs5
-rw-r--r--src/librustc_mir/transform/qualify_min_const_fn.rs2
-rw-r--r--src/librustdoc/clean/cfg.rs54
-rw-r--r--src/librustdoc/clean/cfg/tests.rs52
-rw-r--r--src/librustdoc/clean/inline.rs3
-rw-r--r--src/librustdoc/clean/mod.rs5
-rw-r--r--src/librustdoc/config.rs43
-rw-r--r--src/librustdoc/core.rs26
-rw-r--r--src/librustdoc/lib.rs4
-rw-r--r--src/librustdoc/passes/calculate_doc_coverage.rs2
-rw-r--r--src/librustdoc/passes/check_code_block_syntax.rs2
-rw-r--r--src/librustdoc/passes/collapse_docs.rs2
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs2
-rw-r--r--src/librustdoc/passes/collect_trait_impls.rs2
-rw-r--r--src/librustdoc/passes/mod.rs87
-rw-r--r--src/librustdoc/passes/private_items_doc_tests.rs2
-rw-r--r--src/librustdoc/passes/propagate_doc_cfg.rs2
-rw-r--r--src/librustdoc/passes/strip_hidden.rs2
-rw-r--r--src/librustdoc/passes/strip_priv_imports.rs2
-rw-r--r--src/librustdoc/passes/strip_private.rs2
-rw-r--r--src/librustdoc/passes/unindent_comments.rs2
-rw-r--r--src/libstd/ffi/c_str.rs10
-rw-r--r--src/libstd/sys/unix/fs.rs34
-rw-r--r--src/libstd/sys/vxworks/mod.rs12
-rw-r--r--src/libstd/sys/vxworks/weak.rs56
-rw-r--r--src/libsyntax/util/lev_distance.rs33
-rw-r--r--src/libsyntax/util/lev_distance/tests.rs6
-rw-r--r--src/test/rustdoc/duplicate-cfg.rs33
-rw-r--r--src/test/rustdoc/issue-46380.rs5
-rw-r--r--src/test/rustdoc/issue-67851-both.rs8
-rw-r--r--src/test/rustdoc/issue-67851-hidden.rs8
-rw-r--r--src/test/rustdoc/issue-67851-neither.rs6
-rw-r--r--src/test/rustdoc/issue-67851-private.rs8
-rw-r--r--src/test/ui/rfc-2091-track-caller/std-panic-locations.rs38
-rw-r--r--src/test/ui/suggestions/issue-66968-suggest-sorted-words.rs4
-rw-r--r--src/test/ui/suggestions/issue-66968-suggest-sorted-words.stderr9
47 files changed, 537 insertions, 385 deletions
diff --git a/src/ci/publish_toolstate.sh b/src/ci/publish_toolstate.sh
index fb828477f98..7c43d034d8b 100755
--- a/src/ci/publish_toolstate.sh
+++ b/src/ci/publish_toolstate.sh
@@ -3,7 +3,7 @@
 set -euo pipefail
 IFS=$'\n\t'
 
-source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
+source "$(cd "$(dirname "$0")" && pwd)/shared.sh"
 
 # The following lines are also found in src/bootstrap/toolstate.rs,
 # so if updating here, please also update that file.
diff --git a/src/libcore/option.rs b/src/libcore/option.rs
index 2066a484dac..fb534586fc6 100644
--- a/src/libcore/option.rs
+++ b/src/libcore/option.rs
@@ -341,6 +341,7 @@ impl<T> Option<T> {
     /// x.expect("the world is ending"); // panics with `the world is ending`
     /// ```
     #[inline]
+    #[track_caller]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn expect(self, msg: &str) -> T {
         match self {
@@ -374,6 +375,7 @@ impl<T> Option<T> {
     /// assert_eq!(x.unwrap(), "air"); // fails
     /// ```
     #[inline]
+    #[track_caller]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn unwrap(self) -> T {
         match self {
@@ -1015,6 +1017,7 @@ impl<T: fmt::Debug> Option<T> {
     /// }
     /// ```
     #[inline]
+    #[track_caller]
     #[unstable(feature = "option_expect_none", reason = "newly added", issue = "62633")]
     pub fn expect_none(self, msg: &str) {
         if let Some(val) = self {
@@ -1057,6 +1060,7 @@ impl<T: fmt::Debug> Option<T> {
     /// }
     /// ```
     #[inline]
+    #[track_caller]
     #[unstable(feature = "option_unwrap_none", reason = "newly added", issue = "62633")]
     pub fn unwrap_none(self) {
         if let Some(val) = self {
@@ -1184,6 +1188,7 @@ impl<T, E> Option<Result<T, E>> {
 // This is a separate function to reduce the code size of .expect() itself.
 #[inline(never)]
 #[cold]
+#[track_caller]
 fn expect_failed(msg: &str) -> ! {
     panic!("{}", msg)
 }
@@ -1191,6 +1196,7 @@ fn expect_failed(msg: &str) -> ! {
 // This is a separate function to reduce the code size of .expect_none() itself.
 #[inline(never)]
 #[cold]
+#[track_caller]
 fn expect_none_failed(msg: &str, value: &dyn fmt::Debug) -> ! {
     panic!("{}: {:?}", msg, value)
 }
diff --git a/src/libcore/result.rs b/src/libcore/result.rs
index 5cfc81097dd..b39abf91785 100644
--- a/src/libcore/result.rs
+++ b/src/libcore/result.rs
@@ -957,6 +957,7 @@ impl<T, E: fmt::Debug> Result<T, E> {
     /// x.unwrap(); // panics with `emergency failure`
     /// ```
     #[inline]
+    #[track_caller]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn unwrap(self) -> T {
         match self {
@@ -984,6 +985,7 @@ impl<T, E: fmt::Debug> Result<T, E> {
     /// x.expect("Testing expect"); // panics with `Testing expect: emergency failure`
     /// ```
     #[inline]
+    #[track_caller]
     #[stable(feature = "result_expect", since = "1.4.0")]
     pub fn expect(self, msg: &str) -> T {
         match self {
@@ -1017,6 +1019,7 @@ impl<T: fmt::Debug, E> Result<T, E> {
     /// assert_eq!(x.unwrap_err(), "emergency failure");
     /// ```
     #[inline]
+    #[track_caller]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn unwrap_err(self) -> E {
         match self {
@@ -1044,6 +1047,7 @@ impl<T: fmt::Debug, E> Result<T, E> {
     /// x.expect_err("Testing expect_err"); // panics with `Testing expect_err: 10`
     /// ```
     #[inline]
+    #[track_caller]
     #[stable(feature = "result_expect_err", since = "1.17.0")]
     pub fn expect_err(self, msg: &str) -> E {
         match self {
@@ -1188,6 +1192,7 @@ impl<T, E> Result<Option<T>, E> {
 // This is a separate function to reduce the code size of the methods
 #[inline(never)]
 #[cold]
+#[track_caller]
 fn unwrap_failed(msg: &str, error: &dyn fmt::Debug) -> ! {
     panic!("{}: {:?}", msg, error)
 }
diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs
index a2352c08e73..fae95ca5cdb 100644
--- a/src/libcore/sync/atomic.rs
+++ b/src/libcore/sync/atomic.rs
@@ -134,16 +134,10 @@ use crate::hint::spin_loop;
 /// This function is different from [`std::thread::yield_now`] which directly yields to the
 /// system's scheduler, whereas `spin_loop_hint` does not interact with the operating system.
 ///
-/// Spin locks can be very efficient for short lock durations because they do not involve context
-/// switches or interaction with the operating system. For long lock durations they become wasteful
-/// however because they use CPU cycles for the entire lock duration, and using a
-/// [`std::sync::Mutex`] is likely the better approach. If actively spinning for a long time is
-/// required, e.g. because code polls a non-blocking API, calling [`std::thread::yield_now`]
-/// or [`std::thread::sleep`] may be the best option.
-///
-/// **Note**: Spin locks are based on the underlying assumption that another thread will release
-/// the lock 'soon'. In order for this to work, that other thread must run on a different CPU or
-/// core (at least potentially). Spin locks do not work efficiently on single CPU / core platforms.
+/// A common use case for `spin_loop_hint` is implementing bounded optimistic spinning in a CAS
+/// loop in synchronization primitives. To avoid problems like priority inversion, it is strongly
+/// recommended that the spin loop is terminated after a finite amount of iterations and an
+/// appropriate blocking syscall is made.
 ///
 /// **Note**: On platforms that do not support receiving spin-loop hints this function does not
 /// do anything at all.
diff --git a/src/librustc/ty/constness.rs b/src/librustc/ty/constness.rs
deleted file mode 100644
index cc5131cb217..00000000000
--- a/src/librustc/ty/constness.rs
+++ /dev/null
@@ -1,156 +0,0 @@
-use crate::hir::map::blocks::FnLikeNode;
-use crate::ty::query::Providers;
-use crate::ty::TyCtxt;
-use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
-use rustc_span::symbol::Symbol;
-use rustc_target::spec::abi::Abi;
-use syntax::attr;
-
-impl<'tcx> TyCtxt<'tcx> {
-    /// Whether the `def_id` counts as const fn in your current crate, considering all active
-    /// feature gates
-    pub fn is_const_fn(self, def_id: DefId) -> bool {
-        self.is_const_fn_raw(def_id)
-            && match self.is_unstable_const_fn(def_id) {
-                Some(feature_name) => {
-                    // has a `rustc_const_unstable` attribute, check whether the user enabled the
-                    // corresponding feature gate.
-                    self.features()
-                        .declared_lib_features
-                        .iter()
-                        .any(|&(sym, _)| sym == feature_name)
-                }
-                // functions without const stability are either stable user written
-                // const fn or the user is using feature gates and we thus don't
-                // care what they do
-                None => true,
-            }
-    }
-
-    /// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
-    pub fn is_unstable_const_fn(self, def_id: DefId) -> Option<Symbol> {
-        if self.is_const_fn_raw(def_id) {
-            let const_stab = self.lookup_const_stability(def_id)?;
-            if const_stab.level.is_unstable() { Some(const_stab.feature) } else { None }
-        } else {
-            None
-        }
-    }
-
-    /// Returns `true` if this function must conform to `min_const_fn`
-    pub fn is_min_const_fn(self, def_id: DefId) -> bool {
-        // Bail out if the signature doesn't contain `const`
-        if !self.is_const_fn_raw(def_id) {
-            return false;
-        }
-
-        if self.features().staged_api {
-            // In order for a libstd function to be considered min_const_fn
-            // it needs to be stable and have no `rustc_const_unstable` attribute.
-            match self.lookup_const_stability(def_id) {
-                // `rustc_const_unstable` functions don't need to conform.
-                Some(&attr::ConstStability { ref level, .. }) if level.is_unstable() => false,
-                None => {
-                    if let Some(stab) = self.lookup_stability(def_id) {
-                        if stab.level.is_stable() {
-                            self.sess.span_err(
-                                self.def_span(def_id),
-                                "stable const functions must have either `rustc_const_stable` or \
-                            `rustc_const_unstable` attribute",
-                            );
-                            // While we errored above, because we don't know if we need to conform, we
-                            // err on the "safe" side and require min_const_fn.
-                            true
-                        } else {
-                            // Unstable functions need not conform to min_const_fn.
-                            false
-                        }
-                    } else {
-                        // Internal functions are forced to conform to min_const_fn.
-                        // Annotate the internal function with a const stability attribute if
-                        // you need to use unstable features.
-                        // Note: this is an arbitrary choice that does not affect stability or const
-                        // safety or anything, it just changes whether we need to annotate some
-                        // internal functions with `rustc_const_stable` or with `rustc_const_unstable`
-                        true
-                    }
-                }
-                // Everything else needs to conform, because it would be callable from
-                // other `min_const_fn` functions.
-                _ => true,
-            }
-        } else {
-            // users enabling the `const_fn` feature gate can do what they want
-            !self.features().const_fn
-        }
-    }
-}
-
-pub fn provide(providers: &mut Providers<'_>) {
-    /// Const evaluability whitelist is here to check evaluability at the
-    /// top level beforehand.
-    fn is_const_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> Option<bool> {
-        match tcx.fn_sig(def_id).abi() {
-            Abi::RustIntrinsic | Abi::PlatformIntrinsic => {
-                Some(tcx.lookup_const_stability(def_id).is_some())
-            }
-            _ => None,
-        }
-    }
-
-    /// Checks whether the function has a `const` modifier or, in case it is an intrinsic, whether
-    /// said intrinsic is on the whitelist for being const callable.
-    fn is_const_fn_raw(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
-        let hir_id = tcx
-            .hir()
-            .as_local_hir_id(def_id)
-            .expect("Non-local call to local provider is_const_fn");
-
-        let node = tcx.hir().get(hir_id);
-
-        if let Some(whitelisted) = is_const_intrinsic(tcx, def_id) {
-            whitelisted
-        } else if let Some(fn_like) = FnLikeNode::from_node(node) {
-            fn_like.constness() == hir::Constness::Const
-        } else if let hir::Node::Ctor(_) = node {
-            true
-        } else {
-            false
-        }
-    }
-
-    fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
-        tcx.is_const_fn(def_id)
-            && match tcx.lookup_const_stability(def_id) {
-                Some(stab) => {
-                    if cfg!(debug_assertions) && stab.promotable {
-                        let sig = tcx.fn_sig(def_id);
-                        assert_eq!(
-                            sig.unsafety(),
-                            hir::Unsafety::Normal,
-                            "don't mark const unsafe fns as promotable",
-                            // https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682
-                        );
-                    }
-                    stab.promotable
-                }
-                None => false,
-            }
-    }
-
-    fn const_fn_is_allowed_fn_ptr(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
-        tcx.is_const_fn(def_id)
-            && tcx
-                .lookup_const_stability(def_id)
-                .map(|stab| stab.allow_const_fn_ptr)
-                .unwrap_or(false)
-    }
-
-    *providers = Providers {
-        is_const_fn_raw,
-        is_promotable_const_fn,
-        const_fn_is_allowed_fn_ptr,
-        ..*providers
-    };
-}
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 7cca12308e6..747e6e8da99 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -97,7 +97,6 @@ pub mod cast;
 #[macro_use]
 pub mod codec;
 pub mod _match;
-mod constness;
 mod erase_regions;
 pub mod error;
 pub mod fast_reject;
@@ -3318,7 +3317,6 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
     context::provide(providers);
     erase_regions::provide(providers);
     layout::provide(providers);
-    constness::provide(providers);
     *providers = ty::query::Providers {
         asyncness,
         associated_item,
diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index ac04ae28588..7b2ce7f9ac7 100644
--- a/src/librustc_mir/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -9,10 +9,12 @@ use crate::interpret::{intern_const_alloc_recursive, ConstValue, InterpCx};
 
 mod error;
 mod eval_queries;
+mod fn_queries;
 mod machine;
 
 pub use error::*;
 pub use eval_queries::*;
+pub use fn_queries::*;
 pub use machine::*;
 
 /// Extracts a field of a (variant of a) const.
diff --git a/src/librustc_mir/const_eval/fn_queries.rs b/src/librustc_mir/const_eval/fn_queries.rs
new file mode 100644
index 00000000000..2443e1e91d3
--- /dev/null
+++ b/src/librustc_mir/const_eval/fn_queries.rs
@@ -0,0 +1,151 @@
+use rustc::hir::map::blocks::FnLikeNode;
+use rustc::ty::query::Providers;
+use rustc::ty::TyCtxt;
+use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
+use rustc_span::symbol::Symbol;
+use rustc_target::spec::abi::Abi;
+use syntax::attr;
+
+/// Whether the `def_id` counts as const fn in your current crate, considering all active
+/// feature gates
+pub fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+    tcx.is_const_fn_raw(def_id)
+        && match is_unstable_const_fn(tcx, def_id) {
+            Some(feature_name) => {
+                // has a `rustc_const_unstable` attribute, check whether the user enabled the
+                // corresponding feature gate.
+                tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == feature_name)
+            }
+            // functions without const stability are either stable user written
+            // const fn or the user is using feature gates and we thus don't
+            // care what they do
+            None => true,
+        }
+}
+
+/// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
+pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Symbol> {
+    if tcx.is_const_fn_raw(def_id) {
+        let const_stab = tcx.lookup_const_stability(def_id)?;
+        if const_stab.level.is_unstable() { Some(const_stab.feature) } else { None }
+    } else {
+        None
+    }
+}
+
+/// Returns `true` if this function must conform to `min_const_fn`
+pub fn is_min_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+    // Bail out if the signature doesn't contain `const`
+    if !tcx.is_const_fn_raw(def_id) {
+        return false;
+    }
+
+    if tcx.features().staged_api {
+        // In order for a libstd function to be considered min_const_fn
+        // it needs to be stable and have no `rustc_const_unstable` attribute.
+        match tcx.lookup_const_stability(def_id) {
+            // `rustc_const_unstable` functions don't need to conform.
+            Some(&attr::ConstStability { ref level, .. }) if level.is_unstable() => false,
+            None => {
+                if let Some(stab) = tcx.lookup_stability(def_id) {
+                    if stab.level.is_stable() {
+                        tcx.sess.span_err(
+                            tcx.def_span(def_id),
+                            "stable const functions must have either `rustc_const_stable` or \
+                             `rustc_const_unstable` attribute",
+                        );
+                        // While we errored above, because we don't know if we need to conform, we
+                        // err on the "safe" side and require min_const_fn.
+                        true
+                    } else {
+                        // Unstable functions need not conform to min_const_fn.
+                        false
+                    }
+                } else {
+                    // Internal functions are forced to conform to min_const_fn.
+                    // Annotate the internal function with a const stability attribute if
+                    // you need to use unstable features.
+                    // Note: this is an arbitrary choice that does not affect stability or const
+                    // safety or anything, it just changes whether we need to annotate some
+                    // internal functions with `rustc_const_stable` or with `rustc_const_unstable`
+                    true
+                }
+            }
+            // Everything else needs to conform, because it would be callable from
+            // other `min_const_fn` functions.
+            _ => true,
+        }
+    } else {
+        // users enabling the `const_fn` feature gate can do what they want
+        !tcx.features().const_fn
+    }
+}
+
+pub fn provide(providers: &mut Providers<'_>) {
+    /// Const evaluability whitelist is here to check evaluability at the
+    /// top level beforehand.
+    fn is_const_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> Option<bool> {
+        match tcx.fn_sig(def_id).abi() {
+            Abi::RustIntrinsic | Abi::PlatformIntrinsic => {
+                Some(tcx.lookup_const_stability(def_id).is_some())
+            }
+            _ => None,
+        }
+    }
+
+    /// Checks whether the function has a `const` modifier or, in case it is an intrinsic, whether
+    /// said intrinsic is on the whitelist for being const callable.
+    fn is_const_fn_raw(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+        let hir_id = tcx
+            .hir()
+            .as_local_hir_id(def_id)
+            .expect("Non-local call to local provider is_const_fn");
+
+        let node = tcx.hir().get(hir_id);
+
+        if let Some(whitelisted) = is_const_intrinsic(tcx, def_id) {
+            whitelisted
+        } else if let Some(fn_like) = FnLikeNode::from_node(node) {
+            fn_like.constness() == hir::Constness::Const
+        } else if let hir::Node::Ctor(_) = node {
+            true
+        } else {
+            false
+        }
+    }
+
+    fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+        is_const_fn(tcx, def_id)
+            && match tcx.lookup_const_stability(def_id) {
+                Some(stab) => {
+                    if cfg!(debug_assertions) && stab.promotable {
+                        let sig = tcx.fn_sig(def_id);
+                        assert_eq!(
+                            sig.unsafety(),
+                            hir::Unsafety::Normal,
+                            "don't mark const unsafe fns as promotable",
+                            // https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682
+                        );
+                    }
+                    stab.promotable
+                }
+                None => false,
+            }
+    }
+
+    fn const_fn_is_allowed_fn_ptr(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+        is_const_fn(tcx, def_id)
+            && tcx
+                .lookup_const_stability(def_id)
+                .map(|stab| stab.allow_const_fn_ptr)
+                .unwrap_or(false)
+    }
+
+    *providers = Providers {
+        is_const_fn_raw,
+        is_promotable_const_fn,
+        const_fn_is_allowed_fn_ptr,
+        ..*providers
+    };
+}
diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs
index 9f70f1dd576..36c6568029d 100644
--- a/src/librustc_mir/lib.rs
+++ b/src/librustc_mir/lib.rs
@@ -52,6 +52,7 @@ use rustc::ty::query::Providers;
 
 pub fn provide(providers: &mut Providers<'_>) {
     borrow_check::provide(providers);
+    const_eval::provide(providers);
     shim::provide(providers);
     transform::provide(providers);
     monomorphize::partitioning::provide(providers);
diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs
index 0aa42de538d..b8183972476 100644
--- a/src/librustc_mir/transform/check_consts/validation.rs
+++ b/src/librustc_mir/transform/check_consts/validation.rs
@@ -21,6 +21,7 @@ use super::ops::{self, NonConstOp};
 use super::qualifs::{self, HasMutInterior, NeedsDrop};
 use super::resolver::FlowSensitiveAnalysis;
 use super::{is_lang_panic_fn, ConstKind, Item, Qualif};
+use crate::const_eval::{is_const_fn, is_unstable_const_fn};
 use crate::dataflow::{self as old_dataflow, generic as dataflow};
 
 pub type IndirectlyMutableResults<'mir, 'tcx> =
@@ -173,7 +174,7 @@ impl Validator<'a, 'mir, 'tcx> {
         let Item { tcx, body, def_id, const_kind, .. } = *self.item;
 
         let use_min_const_fn_checks = (const_kind == Some(ConstKind::ConstFn)
-            && tcx.is_min_const_fn(def_id))
+            && crate::const_eval::is_min_const_fn(tcx, def_id))
             && !tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you;
 
         if use_min_const_fn_checks {
@@ -560,13 +561,13 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
                 };
 
                 // At this point, we are calling a function whose `DefId` is known...
-                if self.tcx.is_const_fn(def_id) {
+                if is_const_fn(self.tcx, def_id) {
                     return;
                 }
 
                 if is_lang_panic_fn(self.tcx, def_id) {
                     self.check_op(ops::Panic);
-                } else if let Some(feature) = self.tcx.is_unstable_const_fn(def_id) {
+                } else if let Some(feature) = is_unstable_const_fn(self.tcx, def_id) {
                     // Exempt unstable const fns inside of macros with
                     // `#[allow_internal_unstable]`.
                     if !self.span.allows_unstable(feature) {
diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index 5cf5c54dd48..d07e58b7447 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -14,6 +14,7 @@ use rustc_span::symbol::{sym, Symbol};
 
 use std::ops::Bound;
 
+use crate::const_eval::{is_const_fn, is_min_const_fn};
 use crate::util;
 
 use rustc_error_codes::*;
@@ -523,7 +524,7 @@ fn unsafety_check_result(tcx: TyCtxt<'_>, def_id: DefId) -> UnsafetyCheckResult
     let id = tcx.hir().as_local_hir_id(def_id).unwrap();
     let (const_context, min_const_fn) = match tcx.hir().body_owner_kind(id) {
         hir::BodyOwnerKind::Closure => (false, false),
-        hir::BodyOwnerKind::Fn => (tcx.is_const_fn(def_id), tcx.is_min_const_fn(def_id)),
+        hir::BodyOwnerKind::Fn => (is_const_fn(tcx, def_id), is_min_const_fn(tcx, def_id)),
         hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => (true, false),
     };
     let mut checker = UnsafetyChecker::new(const_context, min_const_fn, body, tcx, param_env);
diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs
index b6656e720c5..00a39905c02 100644
--- a/src/librustc_mir/transform/promote_consts.rs
+++ b/src/librustc_mir/transform/promote_consts.rs
@@ -29,6 +29,7 @@ use rustc_target::spec::abi::Abi;
 use std::cell::Cell;
 use std::{iter, mem, usize};
 
+use crate::const_eval::{is_const_fn, is_unstable_const_fn};
 use crate::transform::check_consts::{is_lang_panic_fn, qualifs, ConstKind, Item};
 use crate::transform::{MirPass, MirSource};
 
@@ -702,8 +703,8 @@ impl<'tcx> Validator<'_, 'tcx> {
 
         let is_const_fn = match fn_ty.kind {
             ty::FnDef(def_id, _) => {
-                self.tcx.is_const_fn(def_id)
-                    || self.tcx.is_unstable_const_fn(def_id).is_some()
+                is_const_fn(self.tcx, def_id)
+                    || is_unstable_const_fn(self.tcx, def_id).is_some()
                     || is_lang_panic_fn(self.tcx, self.def_id)
             }
             _ => false,
diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs
index 9dea44e0200..fcdabb29cd0 100644
--- a/src/librustc_mir/transform/qualify_min_const_fn.rs
+++ b/src/librustc_mir/transform/qualify_min_const_fn.rs
@@ -327,7 +327,7 @@ fn check_terminator(
         TerminatorKind::Call { func, args, from_hir_call: _, destination: _, cleanup: _ } => {
             let fn_ty = func.ty(body, tcx);
             if let ty::FnDef(def_id, _) = fn_ty.kind {
-                if !tcx.is_min_const_fn(def_id) {
+                if !crate::const_eval::is_min_const_fn(tcx, def_id) {
                     return Err((
                         span,
                         format!(
diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs
index 13df1892a5f..84e6ff648a3 100644
--- a/src/librustdoc/clean/cfg.rs
+++ b/src/librustdoc/clean/cfg.rs
@@ -202,23 +202,34 @@ impl ops::Not for Cfg {
 
 impl ops::BitAndAssign for Cfg {
     fn bitand_assign(&mut self, other: Cfg) {
-        if *self == other {
-            return;
-        }
         match (self, other) {
             (&mut Cfg::False, _) | (_, Cfg::True) => {}
             (s, Cfg::False) => *s = Cfg::False,
             (s @ &mut Cfg::True, b) => *s = b,
-            (&mut Cfg::All(ref mut a), Cfg::All(ref mut b)) => a.append(b),
-            (&mut Cfg::All(ref mut a), ref mut b) => a.push(mem::replace(b, Cfg::True)),
+            (&mut Cfg::All(ref mut a), Cfg::All(ref mut b)) => {
+                for c in b.drain(..) {
+                    if !a.contains(&c) {
+                        a.push(c);
+                    }
+                }
+            }
+            (&mut Cfg::All(ref mut a), ref mut b) => {
+                if !a.contains(b) {
+                    a.push(mem::replace(b, Cfg::True));
+                }
+            }
             (s, Cfg::All(mut a)) => {
                 let b = mem::replace(s, Cfg::True);
-                a.push(b);
+                if !a.contains(&b) {
+                    a.push(b);
+                }
                 *s = Cfg::All(a);
             }
             (s, b) => {
-                let a = mem::replace(s, Cfg::True);
-                *s = Cfg::All(vec![a, b]);
+                if *s != b {
+                    let a = mem::replace(s, Cfg::True);
+                    *s = Cfg::All(vec![a, b]);
+                }
             }
         }
     }
@@ -234,23 +245,34 @@ impl ops::BitAnd for Cfg {
 
 impl ops::BitOrAssign for Cfg {
     fn bitor_assign(&mut self, other: Cfg) {
-        if *self == other {
-            return;
-        }
         match (self, other) {
             (&mut Cfg::True, _) | (_, Cfg::False) => {}
             (s, Cfg::True) => *s = Cfg::True,
             (s @ &mut Cfg::False, b) => *s = b,
-            (&mut Cfg::Any(ref mut a), Cfg::Any(ref mut b)) => a.append(b),
-            (&mut Cfg::Any(ref mut a), ref mut b) => a.push(mem::replace(b, Cfg::True)),
+            (&mut Cfg::Any(ref mut a), Cfg::Any(ref mut b)) => {
+                for c in b.drain(..) {
+                    if !a.contains(&c) {
+                        a.push(c);
+                    }
+                }
+            }
+            (&mut Cfg::Any(ref mut a), ref mut b) => {
+                if !a.contains(b) {
+                    a.push(mem::replace(b, Cfg::True));
+                }
+            }
             (s, Cfg::Any(mut a)) => {
                 let b = mem::replace(s, Cfg::True);
-                a.push(b);
+                if !a.contains(&b) {
+                    a.push(b);
+                }
                 *s = Cfg::Any(a);
             }
             (s, b) => {
-                let a = mem::replace(s, Cfg::True);
-                *s = Cfg::Any(vec![a, b]);
+                if *s != b {
+                    let a = mem::replace(s, Cfg::True);
+                    *s = Cfg::Any(vec![a, b]);
+                }
             }
         }
     }
diff --git a/src/librustdoc/clean/cfg/tests.rs b/src/librustdoc/clean/cfg/tests.rs
index 309f7204061..d090bf32503 100644
--- a/src/librustdoc/clean/cfg/tests.rs
+++ b/src/librustdoc/clean/cfg/tests.rs
@@ -87,6 +87,12 @@ fn test_cfg_and() {
         x &= word_cfg("test3");
         assert_eq!(x, word_cfg("test3"));
 
+        x &= word_cfg("test3");
+        assert_eq!(x, word_cfg("test3"));
+
+        x &= word_cfg("test4");
+        assert_eq!(x, Cfg::All(vec![word_cfg("test3"), word_cfg("test4")]));
+
         x &= word_cfg("test4");
         assert_eq!(x, Cfg::All(vec![word_cfg("test3"), word_cfg("test4")]));
 
@@ -105,6 +111,18 @@ fn test_cfg_and() {
             ])
         );
 
+        x &= Cfg::All(vec![word_cfg("test6"), word_cfg("test7")]);
+        assert_eq!(
+            x,
+            Cfg::All(vec![
+                word_cfg("test3"),
+                word_cfg("test4"),
+                word_cfg("test5"),
+                word_cfg("test6"),
+                word_cfg("test7"),
+            ])
+        );
+
         let mut y = Cfg::Any(vec![word_cfg("a"), word_cfg("b")]);
         y &= x;
         assert_eq!(
@@ -119,6 +137,14 @@ fn test_cfg_and() {
             ])
         );
 
+        let mut z = word_cfg("test8");
+        z &= Cfg::All(vec![word_cfg("test9"), word_cfg("test10")]);
+        assert_eq!(z, Cfg::All(vec![word_cfg("test9"), word_cfg("test10"), word_cfg("test8")]));
+
+        let mut z = word_cfg("test11");
+        z &= Cfg::All(vec![word_cfg("test11"), word_cfg("test12")]);
+        assert_eq!(z, Cfg::All(vec![word_cfg("test11"), word_cfg("test12")]));
+
         assert_eq!(
             word_cfg("a") & word_cfg("b") & word_cfg("c"),
             Cfg::All(vec![word_cfg("a"), word_cfg("b"), word_cfg("c")])
@@ -145,6 +171,12 @@ fn test_cfg_or() {
         x |= word_cfg("test3");
         assert_eq!(x, word_cfg("test3"));
 
+        x |= word_cfg("test3");
+        assert_eq!(x, word_cfg("test3"));
+
+        x |= word_cfg("test4");
+        assert_eq!(x, Cfg::Any(vec![word_cfg("test3"), word_cfg("test4")]));
+
         x |= word_cfg("test4");
         assert_eq!(x, Cfg::Any(vec![word_cfg("test3"), word_cfg("test4")]));
 
@@ -163,6 +195,18 @@ fn test_cfg_or() {
             ])
         );
 
+        x |= Cfg::Any(vec![word_cfg("test6"), word_cfg("test7")]);
+        assert_eq!(
+            x,
+            Cfg::Any(vec![
+                word_cfg("test3"),
+                word_cfg("test4"),
+                word_cfg("test5"),
+                word_cfg("test6"),
+                word_cfg("test7"),
+            ])
+        );
+
         let mut y = Cfg::All(vec![word_cfg("a"), word_cfg("b")]);
         y |= x;
         assert_eq!(
@@ -177,6 +221,14 @@ fn test_cfg_or() {
             ])
         );
 
+        let mut z = word_cfg("test8");
+        z |= Cfg::Any(vec![word_cfg("test9"), word_cfg("test10")]);
+        assert_eq!(z, Cfg::Any(vec![word_cfg("test9"), word_cfg("test10"), word_cfg("test8")]));
+
+        let mut z = word_cfg("test11");
+        z |= Cfg::Any(vec![word_cfg("test11"), word_cfg("test12")]);
+        assert_eq!(z, Cfg::Any(vec![word_cfg("test11"), word_cfg("test12")]));
+
         assert_eq!(
             word_cfg("a") | word_cfg("b") | word_cfg("c"),
             Cfg::Any(vec![word_cfg("a"), word_cfg("b"), word_cfg("c")])
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 2400dded666..c7e0f1e9e70 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -9,6 +9,7 @@ use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::Mutability;
 use rustc_metadata::creader::LoadedMacro;
+use rustc_mir::const_eval::is_min_const_fn;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
@@ -212,7 +213,7 @@ fn build_external_function(cx: &DocContext<'_>, did: DefId) -> clean::Function {
     let sig = cx.tcx.fn_sig(did);
 
     let constness =
-        if cx.tcx.is_min_const_fn(did) { hir::Constness::Const } else { hir::Constness::NotConst };
+        if is_min_const_fn(cx.tcx, did) { hir::Constness::Const } else { hir::Constness::NotConst };
     let asyncness = cx.tcx.asyncness(did);
     let predicates = cx.tcx.predicates_of(did);
     let (generics, decl) = clean::enter_impl_trait(cx, || {
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index bb46a15258e..be9654612f5 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -21,6 +21,7 @@ use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX};
 use rustc_index::vec::{Idx, IndexVec};
+use rustc_mir::const_eval::is_min_const_fn;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{kw, sym};
 use rustc_span::{self, Pos};
@@ -895,7 +896,7 @@ impl Clean<Item> for doctree::Function<'_> {
             enter_impl_trait(cx, || (self.generics.clean(cx), (self.decl, self.body).clean(cx)));
 
         let did = cx.tcx.hir().local_def_id(self.id);
-        let constness = if cx.tcx.is_min_const_fn(did) {
+        let constness = if is_min_const_fn(cx.tcx, did) {
             hir::Constness::Const
         } else {
             hir::Constness::NotConst
@@ -1187,7 +1188,7 @@ impl Clean<Item> for ty::AssocItem {
                 };
                 let (all_types, ret_types) = get_all_types(&generics, &decl, cx);
                 if provided {
-                    let constness = if cx.tcx.is_min_const_fn(self.def_id) {
+                    let constness = if is_min_const_fn(cx.tcx, self.def_id) {
                         hir::Constness::Const
                     } else {
                         hir::Constness::NotConst
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index 0af25efc042..26b49d2f962 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -24,7 +24,7 @@ use crate::html;
 use crate::html::markdown::IdMap;
 use crate::html::static_files;
 use crate::opts;
-use crate::passes::{self, DefaultPassOption};
+use crate::passes::{self, Condition, DefaultPassOption};
 use crate::theme;
 
 /// Configuration options for rustdoc.
@@ -98,6 +98,10 @@ pub struct Options {
     ///
     /// Be aware: This option can come both from the CLI and from crate attributes!
     pub default_passes: DefaultPassOption,
+    /// Document items that have lower than `pub` visibility.
+    pub document_private: bool,
+    /// Document items that have `doc(hidden)`.
+    pub document_hidden: bool,
     /// Any passes manually selected by the user.
     ///
     /// Be aware: This option can come both from the CLI and from crate attributes!
@@ -146,6 +150,8 @@ impl fmt::Debug for Options {
             .field("test_args", &self.test_args)
             .field("persist_doctests", &self.persist_doctests)
             .field("default_passes", &self.default_passes)
+            .field("document_private", &self.document_private)
+            .field("document_hidden", &self.document_hidden)
             .field("manual_passes", &self.manual_passes)
             .field("display_warnings", &self.display_warnings)
             .field("show_coverage", &self.show_coverage)
@@ -240,22 +246,26 @@ impl Options {
                 println!("{:>20} - {}", pass.name, pass.description);
             }
             println!("\nDefault passes for rustdoc:");
-            for pass in passes::DEFAULT_PASSES {
-                println!("{:>20}", pass.name);
-            }
-            println!("\nPasses run with `--document-private-items`:");
-            for pass in passes::DEFAULT_PRIVATE_PASSES {
-                println!("{:>20}", pass.name);
+            for p in passes::DEFAULT_PASSES {
+                print!("{:>20}", p.pass.name);
+                println_condition(p.condition);
             }
 
             if nightly_options::is_nightly_build() {
                 println!("\nPasses run with `--show-coverage`:");
-                for pass in passes::DEFAULT_COVERAGE_PASSES {
-                    println!("{:>20}", pass.name);
+                for p in passes::COVERAGE_PASSES {
+                    print!("{:>20}", p.pass.name);
+                    println_condition(p.condition);
                 }
-                println!("\nPasses run with `--show-coverage --document-private-items`:");
-                for pass in passes::PRIVATE_COVERAGE_PASSES {
-                    println!("{:>20}", pass.name);
+            }
+
+            fn println_condition(condition: Condition) {
+                use Condition::*;
+                match condition {
+                    Always => println!(),
+                    WhenDocumentPrivate => println!("  (when --document-private-items)"),
+                    WhenNotDocumentPrivate => println!("  (when not --document-private-items)"),
+                    WhenNotDocumentHidden => println!("  (when not --document-hidden-items)"),
                 }
             }
 
@@ -444,16 +454,11 @@ impl Options {
             });
 
         let show_coverage = matches.opt_present("show-coverage");
-        let document_private = matches.opt_present("document-private-items");
 
         let default_passes = if matches.opt_present("no-defaults") {
             passes::DefaultPassOption::None
-        } else if show_coverage && document_private {
-            passes::DefaultPassOption::PrivateCoverage
         } else if show_coverage {
             passes::DefaultPassOption::Coverage
-        } else if document_private {
-            passes::DefaultPassOption::Private
         } else {
             passes::DefaultPassOption::Default
         };
@@ -492,6 +497,8 @@ impl Options {
         let runtool = matches.opt_str("runtool");
         let runtool_args = matches.opt_strs("runtool-arg");
         let enable_per_target_ignores = matches.opt_present("enable-per-target-ignores");
+        let document_private = matches.opt_present("document-private-items");
+        let document_hidden = matches.opt_present("document-hidden-items");
 
         let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
 
@@ -518,6 +525,8 @@ impl Options {
             should_test,
             test_args,
             default_passes,
+            document_private,
+            document_hidden,
             manual_passes,
             display_warnings,
             show_coverage,
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 50d62027c8c..be7f7ea364f 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -33,7 +33,7 @@ use crate::clean::{AttributesExt, MAX_DEF_ID};
 use crate::config::{Options as RustdocOptions, RenderOptions};
 use crate::html::render::RenderInfo;
 
-use crate::passes;
+use crate::passes::{self, Condition::*, ConditionalPass};
 
 pub use rustc::session::config::{CodegenOptions, DebuggingOptions, Input, Options};
 pub use rustc::session::search_paths::SearchPath;
@@ -221,6 +221,8 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
         describe_lints,
         lint_cap,
         mut default_passes,
+        mut document_private,
+        document_hidden,
         mut manual_passes,
         display_warnings,
         render_options,
@@ -457,16 +459,14 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
                     }
 
                     if attr.is_word() && name == sym::document_private_items {
-                        if default_passes == passes::DefaultPassOption::Default {
-                            default_passes = passes::DefaultPassOption::Private;
-                        }
+                        document_private = true;
                     }
                 }
 
-                let passes = passes::defaults(default_passes).iter().chain(
+                let passes = passes::defaults(default_passes).iter().copied().chain(
                     manual_passes.into_iter().flat_map(|name| {
                         if let Some(pass) = passes::find_pass(&name) {
-                            Some(pass)
+                            Some(ConditionalPass::always(pass))
                         } else {
                             error!("unknown pass {}, skipping", name);
                             None
@@ -476,9 +476,17 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
 
                 info!("Executing passes");
 
-                for pass in passes {
-                    debug!("running pass {}", pass.name);
-                    krate = (pass.pass)(krate, &ctxt);
+                for p in passes {
+                    let run = match p.condition {
+                        Always => true,
+                        WhenDocumentPrivate => document_private,
+                        WhenNotDocumentPrivate => !document_private,
+                        WhenNotDocumentHidden => !document_hidden,
+                    };
+                    if run {
+                        debug!("running pass {}", p.pass.name);
+                        krate = (p.pass.run)(krate, &ctxt);
+                    }
                 }
 
                 ctxt.sess().abort_if_errors();
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index eeaac1d8c74..91150899877 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -32,6 +32,7 @@ extern crate rustc_interface;
 extern crate rustc_lexer;
 extern crate rustc_lint;
 extern crate rustc_metadata;
+extern crate rustc_mir;
 extern crate rustc_parse;
 extern crate rustc_resolve;
 extern crate rustc_span as rustc_span;
@@ -173,6 +174,9 @@ fn opts() -> Vec<RustcOptGroup> {
         stable("document-private-items", |o| {
             o.optflag("", "document-private-items", "document private items")
         }),
+        unstable("document-hidden-items", |o| {
+            o.optflag("", "document-hidden-items", "document items that have doc(hidden)")
+        }),
         stable("test", |o| o.optflag("", "test", "run code examples as tests")),
         stable("test-args", |o| {
             o.optmulti("", "test-args", "arguments to pass to the test runner", "ARGS")
diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs
index 803bcc2cfdf..7ed531c9206 100644
--- a/src/librustdoc/passes/calculate_doc_coverage.rs
+++ b/src/librustdoc/passes/calculate_doc_coverage.rs
@@ -12,7 +12,7 @@ use std::ops;
 
 pub const CALCULATE_DOC_COVERAGE: Pass = Pass {
     name: "calculate-doc-coverage",
-    pass: calculate_doc_coverage,
+    run: calculate_doc_coverage,
     description: "counts the number of items with and without documentation",
 };
 
diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs
index a4ca9010f2e..79548eb6d64 100644
--- a/src/librustdoc/passes/check_code_block_syntax.rs
+++ b/src/librustdoc/passes/check_code_block_syntax.rs
@@ -14,7 +14,7 @@ use crate::passes::Pass;
 
 pub const CHECK_CODE_BLOCK_SYNTAX: Pass = Pass {
     name: "check-code-block-syntax",
-    pass: check_code_block_syntax,
+    run: check_code_block_syntax,
     description: "validates syntax inside Rust code blocks",
 };
 
diff --git a/src/librustdoc/passes/collapse_docs.rs b/src/librustdoc/passes/collapse_docs.rs
index c6b22883e97..c2185592d14 100644
--- a/src/librustdoc/passes/collapse_docs.rs
+++ b/src/librustdoc/passes/collapse_docs.rs
@@ -8,7 +8,7 @@ use std::mem::take;
 
 pub const COLLAPSE_DOCS: Pass = Pass {
     name: "collapse-docs",
-    pass: collapse_docs,
+    run: collapse_docs,
     description: "concatenates all document attributes into one document attribute",
 };
 
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 8a3966c320b..b1cd3deecb4 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -28,7 +28,7 @@ use super::span_of_attrs;
 
 pub const COLLECT_INTRA_DOC_LINKS: Pass = Pass {
     name: "collect-intra-doc-links",
-    pass: collect_intra_doc_links,
+    run: collect_intra_doc_links,
     description: "reads a crate's documentation to resolve intra-doc-links",
 };
 
diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs
index c00e231ef70..da0e97f1075 100644
--- a/src/librustdoc/passes/collect_trait_impls.rs
+++ b/src/librustdoc/passes/collect_trait_impls.rs
@@ -9,7 +9,7 @@ use rustc_span::symbol::sym;
 
 pub const COLLECT_TRAIT_IMPLS: Pass = Pass {
     name: "collect-trait-impls",
-    pass: collect_trait_impls,
+    run: collect_trait_impls,
     description: "retrieves trait impls for items in the crate",
 };
 
diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs
index aebed9171d0..355ea15223b 100644
--- a/src/librustdoc/passes/mod.rs
+++ b/src/librustdoc/passes/mod.rs
@@ -8,6 +8,7 @@ use rustc_span::{InnerSpan, Span, DUMMY_SP};
 use std::mem;
 use std::ops::Range;
 
+use self::Condition::*;
 use crate::clean::{self, GetDefId, Item};
 use crate::core::DocContext;
 use crate::fold::{DocFolder, StripItem};
@@ -52,10 +53,29 @@ pub use self::calculate_doc_coverage::CALCULATE_DOC_COVERAGE;
 #[derive(Copy, Clone)]
 pub struct Pass {
     pub name: &'static str,
-    pub pass: fn(clean::Crate, &DocContext<'_>) -> clean::Crate,
+    pub run: fn(clean::Crate, &DocContext<'_>) -> clean::Crate,
     pub description: &'static str,
 }
 
+/// In a list of passes, a pass that may or may not need to be run depending on options.
+#[derive(Copy, Clone)]
+pub struct ConditionalPass {
+    pub pass: Pass,
+    pub condition: Condition,
+}
+
+/// How to decide whether to run a conditional pass.
+#[derive(Copy, Clone)]
+pub enum Condition {
+    Always,
+    /// When `--document-private-items` is passed.
+    WhenDocumentPrivate,
+    /// When `--document-private-items` is not passed.
+    WhenNotDocumentPrivate,
+    /// When `--document-hidden-items` is not passed.
+    WhenNotDocumentHidden,
+}
+
 /// The full list of passes.
 pub const PASSES: &[Pass] = &[
     CHECK_PRIVATE_ITEMS_DOC_TESTS,
@@ -72,63 +92,58 @@ pub const PASSES: &[Pass] = &[
 ];
 
 /// The list of passes run by default.
-pub const DEFAULT_PASSES: &[Pass] = &[
-    COLLECT_TRAIT_IMPLS,
-    COLLAPSE_DOCS,
-    UNINDENT_COMMENTS,
-    CHECK_PRIVATE_ITEMS_DOC_TESTS,
-    STRIP_HIDDEN,
-    STRIP_PRIVATE,
-    COLLECT_INTRA_DOC_LINKS,
-    CHECK_CODE_BLOCK_SYNTAX,
-    PROPAGATE_DOC_CFG,
+pub const DEFAULT_PASSES: &[ConditionalPass] = &[
+    ConditionalPass::always(COLLECT_TRAIT_IMPLS),
+    ConditionalPass::always(COLLAPSE_DOCS),
+    ConditionalPass::always(UNINDENT_COMMENTS),
+    ConditionalPass::always(CHECK_PRIVATE_ITEMS_DOC_TESTS),
+    ConditionalPass::new(STRIP_HIDDEN, WhenNotDocumentHidden),
+    ConditionalPass::new(STRIP_PRIVATE, WhenNotDocumentPrivate),
+    ConditionalPass::new(STRIP_PRIV_IMPORTS, WhenDocumentPrivate),
+    ConditionalPass::always(COLLECT_INTRA_DOC_LINKS),
+    ConditionalPass::always(CHECK_CODE_BLOCK_SYNTAX),
+    ConditionalPass::always(PROPAGATE_DOC_CFG),
 ];
 
-/// The list of default passes run with `--document-private-items` is passed to rustdoc.
-pub const DEFAULT_PRIVATE_PASSES: &[Pass] = &[
-    COLLECT_TRAIT_IMPLS,
-    COLLAPSE_DOCS,
-    UNINDENT_COMMENTS,
-    CHECK_PRIVATE_ITEMS_DOC_TESTS,
-    STRIP_PRIV_IMPORTS,
-    COLLECT_INTRA_DOC_LINKS,
-    CHECK_CODE_BLOCK_SYNTAX,
-    PROPAGATE_DOC_CFG,
+/// The list of default passes run when `--doc-coverage` is passed to rustdoc.
+pub const COVERAGE_PASSES: &[ConditionalPass] = &[
+    ConditionalPass::always(COLLECT_TRAIT_IMPLS),
+    ConditionalPass::new(STRIP_HIDDEN, WhenNotDocumentHidden),
+    ConditionalPass::new(STRIP_PRIVATE, WhenNotDocumentPrivate),
+    ConditionalPass::always(CALCULATE_DOC_COVERAGE),
 ];
 
-/// The list of default passes run when `--doc-coverage` is passed to rustdoc.
-pub const DEFAULT_COVERAGE_PASSES: &[Pass] =
-    &[COLLECT_TRAIT_IMPLS, STRIP_HIDDEN, STRIP_PRIVATE, CALCULATE_DOC_COVERAGE];
+impl ConditionalPass {
+    pub const fn always(pass: Pass) -> Self {
+        Self::new(pass, Always)
+    }
 
-/// The list of default passes run when `--doc-coverage --document-private-items` is passed to
-/// rustdoc.
-pub const PRIVATE_COVERAGE_PASSES: &[Pass] = &[COLLECT_TRAIT_IMPLS, CALCULATE_DOC_COVERAGE];
+    pub const fn new(pass: Pass, condition: Condition) -> Self {
+        ConditionalPass { pass, condition }
+    }
+}
 
 /// A shorthand way to refer to which set of passes to use, based on the presence of
-/// `--no-defaults` or `--document-private-items`.
+/// `--no-defaults` and `--show-coverage`.
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 pub enum DefaultPassOption {
     Default,
-    Private,
     Coverage,
-    PrivateCoverage,
     None,
 }
 
 /// Returns the given default set of passes.
-pub fn defaults(default_set: DefaultPassOption) -> &'static [Pass] {
+pub fn defaults(default_set: DefaultPassOption) -> &'static [ConditionalPass] {
     match default_set {
         DefaultPassOption::Default => DEFAULT_PASSES,
-        DefaultPassOption::Private => DEFAULT_PRIVATE_PASSES,
-        DefaultPassOption::Coverage => DEFAULT_COVERAGE_PASSES,
-        DefaultPassOption::PrivateCoverage => PRIVATE_COVERAGE_PASSES,
+        DefaultPassOption::Coverage => COVERAGE_PASSES,
         DefaultPassOption::None => &[],
     }
 }
 
 /// If the given name matches a known pass, returns its information.
-pub fn find_pass(pass_name: &str) -> Option<&'static Pass> {
-    PASSES.iter().find(|p| p.name == pass_name)
+pub fn find_pass(pass_name: &str) -> Option<Pass> {
+    PASSES.iter().find(|p| p.name == pass_name).copied()
 }
 
 struct Stripper<'a> {
diff --git a/src/librustdoc/passes/private_items_doc_tests.rs b/src/librustdoc/passes/private_items_doc_tests.rs
index 23e27270970..aec5a6bd4e2 100644
--- a/src/librustdoc/passes/private_items_doc_tests.rs
+++ b/src/librustdoc/passes/private_items_doc_tests.rs
@@ -5,7 +5,7 @@ use crate::passes::{look_for_tests, Pass};
 
 pub const CHECK_PRIVATE_ITEMS_DOC_TESTS: Pass = Pass {
     name: "check-private-items-doc-tests",
-    pass: check_private_items_doc_tests,
+    run: check_private_items_doc_tests,
     description: "check private items doc tests",
 };
 
diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs
index a296e73e3b5..64b0c45ba65 100644
--- a/src/librustdoc/passes/propagate_doc_cfg.rs
+++ b/src/librustdoc/passes/propagate_doc_cfg.rs
@@ -8,7 +8,7 @@ use crate::passes::Pass;
 
 pub const PROPAGATE_DOC_CFG: Pass = Pass {
     name: "propagate-doc-cfg",
-    pass: propagate_doc_cfg,
+    run: propagate_doc_cfg,
     description: "propagates `#[doc(cfg(...))]` to child items",
 };
 
diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs
index 08a88c00cb0..f82e72b488b 100644
--- a/src/librustdoc/passes/strip_hidden.rs
+++ b/src/librustdoc/passes/strip_hidden.rs
@@ -10,7 +10,7 @@ use crate::passes::{ImplStripper, Pass};
 
 pub const STRIP_HIDDEN: Pass = Pass {
     name: "strip-hidden",
-    pass: strip_hidden,
+    run: strip_hidden,
     description: "strips all doc(hidden) items from the output",
 };
 
diff --git a/src/librustdoc/passes/strip_priv_imports.rs b/src/librustdoc/passes/strip_priv_imports.rs
index af34842ad0f..35b26fb8ab0 100644
--- a/src/librustdoc/passes/strip_priv_imports.rs
+++ b/src/librustdoc/passes/strip_priv_imports.rs
@@ -5,7 +5,7 @@ use crate::passes::{ImportStripper, Pass};
 
 pub const STRIP_PRIV_IMPORTS: Pass = Pass {
     name: "strip-priv-imports",
-    pass: strip_priv_imports,
+    run: strip_priv_imports,
     description: "strips all private import statements (`use`, `extern crate`) from a crate",
 };
 
diff --git a/src/librustdoc/passes/strip_private.rs b/src/librustdoc/passes/strip_private.rs
index f4ec9cc3649..f244956e503 100644
--- a/src/librustdoc/passes/strip_private.rs
+++ b/src/librustdoc/passes/strip_private.rs
@@ -7,7 +7,7 @@ use crate::passes::{ImplStripper, ImportStripper, Pass, Stripper};
 
 pub const STRIP_PRIVATE: Pass = Pass {
     name: "strip-private",
-    pass: strip_private,
+    run: strip_private,
     description: "strips all private items from a crate which cannot be seen externally, \
         implies strip-priv-imports",
 };
diff --git a/src/librustdoc/passes/unindent_comments.rs b/src/librustdoc/passes/unindent_comments.rs
index 3212af055ef..d4e09ce47a3 100644
--- a/src/librustdoc/passes/unindent_comments.rs
+++ b/src/librustdoc/passes/unindent_comments.rs
@@ -12,7 +12,7 @@ mod tests;
 
 pub const UNINDENT_COMMENTS: Pass = Pass {
     name: "unindent-comments",
-    pass: unindent_comments,
+    run: unindent_comments,
     description: "removes excess indentation on comments in order for markdown to like it",
 };
 
diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs
index d2ee65f0a74..700e015b08e 100644
--- a/src/libstd/ffi/c_str.rs
+++ b/src/libstd/ffi/c_str.rs
@@ -1187,11 +1187,6 @@ impl CStr {
     /// function will return the corresponding [`&str`] slice. Otherwise,
     /// it will return an error with details of where UTF-8 validation failed.
     ///
-    /// > **Note**: This method is currently implemented to check for validity
-    /// > after a constant-time cast, but it is planned to alter its definition
-    /// > in the future to perform the length calculation in addition to the
-    /// > UTF-8 check whenever this method is called.
-    ///
     /// [`&str`]: ../primitive.str.html
     ///
     /// # Examples
@@ -1220,11 +1215,6 @@ impl CStr {
     /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD] and return a
     /// [`Cow`]`::`[`Owned`]`(`[`String`]`)` with the result.
     ///
-    /// > **Note**: This method is currently implemented to check for validity
-    /// > after a constant-time cast, but it is planned to alter its definition
-    /// > in the future to perform the length calculation in addition to the
-    /// > UTF-8 check whenever this method is called.
-    ///
     /// [`Cow`]: ../borrow/enum.Cow.html
     /// [`Borrowed`]: ../borrow/enum.Cow.html#variant.Borrowed
     /// [`Owned`]: ../borrow/enum.Cow.html#variant.Owned
diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs
index 4fa9095c899..ab2a871b92d 100644
--- a/src/libstd/sys/unix/fs.rs
+++ b/src/libstd/sys/unix/fs.rs
@@ -51,24 +51,14 @@ pub use crate::sys_common::fs::remove_dir_all;
 
 pub struct File(FileDesc);
 
-// FIXME: This should be available on Linux with all `target_arch` and `target_env`.
-// https://github.com/rust-lang/libc/issues/1545
+// FIXME: This should be available on Linux with all `target_env`.
+// But currently only glibc exposes `statx` fn and structs.
+// We don't want to import unverified raw C structs here directly.
+// https://github.com/rust-lang/rust/pull/67774
 macro_rules! cfg_has_statx {
     ({ $($then_tt:tt)* } else { $($else_tt:tt)* }) => {
         cfg_if::cfg_if! {
-            if #[cfg(all(target_os = "linux", target_env = "gnu", any(
-                target_arch = "x86",
-                target_arch = "arm",
-                // target_arch = "mips",
-                target_arch = "powerpc",
-                target_arch = "x86_64",
-                // target_arch = "aarch64",
-                target_arch = "powerpc64",
-                // target_arch = "mips64",
-                // target_arch = "s390x",
-                target_arch = "sparc64",
-                target_arch = "riscv64",
-            )))] {
+            if #[cfg(all(target_os = "linux", target_env = "gnu"))] {
                 $($then_tt)*
             } else {
                 $($else_tt)*
@@ -76,19 +66,7 @@ macro_rules! cfg_has_statx {
         }
     };
     ($($block_inner:tt)*) => {
-        #[cfg(all(target_os = "linux", target_env = "gnu", any(
-            target_arch = "x86",
-            target_arch = "arm",
-            // target_arch = "mips",
-            target_arch = "powerpc",
-            target_arch = "x86_64",
-            // target_arch = "aarch64",
-            target_arch = "powerpc64",
-            // target_arch = "mips64",
-            // target_arch = "s390x",
-            target_arch = "sparc64",
-            target_arch = "riscv64",
-        )))]
+        #[cfg(all(target_os = "linux", target_env = "gnu"))]
         {
             $($block_inner)*
         }
diff --git a/src/libstd/sys/vxworks/mod.rs b/src/libstd/sys/vxworks/mod.rs
index f102e4d6adf..12bbfa1d4e1 100644
--- a/src/libstd/sys/vxworks/mod.rs
+++ b/src/libstd/sys/vxworks/mod.rs
@@ -36,18 +36,10 @@ pub use crate::sys_common::os_str_bytes as os_str;
 
 #[cfg(not(test))]
 pub fn init() {
-    // By default, some platforms will send a *signal* when an EPIPE error
-    // would otherwise be delivered. This runtime doesn't install a SIGPIPE
-    // handler, causing it to kill the program, which isn't exactly what we
-    // want!
-    //
-    // Hence, we set SIGPIPE to ignore when the program starts up in order
-    // to prevent this problem.
+    // ignore SIGPIPE
     unsafe {
-        reset_sigpipe();
+        assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR);
     }
-
-    unsafe fn reset_sigpipe() {}
 }
 
 pub use libc::signal;
diff --git a/src/libstd/sys/vxworks/weak.rs b/src/libstd/sys/vxworks/weak.rs
deleted file mode 100644
index 4c6fddefd3f..00000000000
--- a/src/libstd/sys/vxworks/weak.rs
+++ /dev/null
@@ -1,56 +0,0 @@
-//! Support for "weak linkage" to symbols on Unix
-//!
-//! Some I/O operations we do in libstd require newer versions of OSes but we
-//! need to maintain binary compatibility with older releases for now. In order
-//! to use the new functionality when available we use this module for
-//! detection.
-//!
-//! One option to use here is weak linkage, but that is unfortunately only
-//! really workable on Linux. Hence, use dlsym to get the symbol value at
-//! runtime. This is also done for compatibility with older versions of glibc,
-//! and to avoid creating dependencies on GLIBC_PRIVATE symbols. It assumes that
-//! we've been dynamically linked to the library the symbol comes from, but that
-//! is currently always the case for things like libpthread/libc.
-//!
-//! A long time ago this used weak linkage for the __pthread_get_minstack
-//! symbol, but that caused Debian to detect an unnecessarily strict versioned
-//! dependency on libc6 (#23628).
-
-use crate::ffi::CStr;
-use crate::marker;
-use crate::mem;
-use crate::sync::atomic::{AtomicUsize, Ordering};
-
-pub struct Weak<F> {
-    name: &'static str,
-    addr: AtomicUsize,
-    _marker: marker::PhantomData<F>,
-}
-
-impl<F> Weak<F> {
-    pub const fn new(name: &'static str) -> Weak<F> {
-        Weak { name, addr: AtomicUsize::new(1), _marker: marker::PhantomData }
-    }
-
-    pub fn get(&self) -> Option<F> {
-        assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>());
-        unsafe {
-            if self.addr.load(Ordering::SeqCst) == 1 {
-                self.addr.store(fetch(self.name), Ordering::SeqCst);
-            }
-            match self.addr.load(Ordering::SeqCst) {
-                0 => None,
-                addr => Some(mem::transmute_copy::<usize, F>(&addr)),
-            }
-        }
-    }
-}
-
-unsafe fn fetch(name: &str) -> usize {
-    let name = match CStr::from_bytes_with_nul(name.as_bytes()) {
-        Ok(cstr) => cstr,
-        Err(..) => return 0,
-    };
-    assert!(false, "FIXME: fetch");
-    libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr()) as usize
-}
diff --git a/src/libsyntax/util/lev_distance.rs b/src/libsyntax/util/lev_distance.rs
index fc697026fe4..cce86fed989 100644
--- a/src/libsyntax/util/lev_distance.rs
+++ b/src/libsyntax/util/lev_distance.rs
@@ -54,14 +54,16 @@ where
     T: Iterator<Item = &'a Symbol>,
 {
     let max_dist = dist.map_or_else(|| cmp::max(lookup.len(), 3) / 3, |d| d);
+    let name_vec: Vec<&Symbol> = iter_names.collect();
 
-    let (case_insensitive_match, levenstein_match) = iter_names
+    let (case_insensitive_match, levenshtein_match) = name_vec
+        .iter()
         .filter_map(|&name| {
             let dist = lev_distance(lookup, &name.as_str());
             if dist <= max_dist { Some((name, dist)) } else { None }
         })
         // Here we are collecting the next structure:
-        // (case_insensitive_match, (levenstein_match, levenstein_distance))
+        // (case_insensitive_match, (levenshtein_match, levenshtein_distance))
         .fold((None, None), |result, (candidate, dist)| {
             (
                 if candidate.as_str().to_uppercase() == lookup.to_uppercase() {
@@ -75,10 +77,31 @@ where
                 },
             )
         });
-
+    // Priority of matches:
+    // 1. Exact case insensitive match
+    // 2. Levenshtein distance match
+    // 3. Sorted word match
     if let Some(candidate) = case_insensitive_match {
-        Some(candidate) // exact case insensitive match has a higher priority
+        Some(*candidate)
+    } else if levenshtein_match.is_some() {
+        levenshtein_match.map(|(candidate, _)| *candidate)
     } else {
-        levenstein_match.map(|(candidate, _)| candidate)
+        find_match_by_sorted_words(name_vec, lookup)
     }
 }
+
+fn find_match_by_sorted_words<'a>(iter_names: Vec<&'a Symbol>, lookup: &str) -> Option<Symbol> {
+    iter_names.iter().fold(None, |result, candidate| {
+        if sort_by_words(&candidate.as_str()) == sort_by_words(lookup) {
+            Some(**candidate)
+        } else {
+            result
+        }
+    })
+}
+
+fn sort_by_words(name: &str) -> String {
+    let mut split_words: Vec<&str> = name.split('_').collect();
+    split_words.sort();
+    split_words.join("_")
+}
diff --git a/src/libsyntax/util/lev_distance/tests.rs b/src/libsyntax/util/lev_distance/tests.rs
index f65f9275d03..222661687c1 100644
--- a/src/libsyntax/util/lev_distance/tests.rs
+++ b/src/libsyntax/util/lev_distance/tests.rs
@@ -46,5 +46,11 @@ fn test_find_best_match_for_name() {
             find_best_match_for_name(input.iter(), "aaaa", Some(4)),
             Some(Symbol::intern("AAAA"))
         );
+
+        let input = vec![Symbol::intern("a_longer_variable_name")];
+        assert_eq!(
+            find_best_match_for_name(input.iter(), "a_variable_longer_name", None),
+            Some(Symbol::intern("a_longer_variable_name"))
+        );
     })
 }
diff --git a/src/test/rustdoc/duplicate-cfg.rs b/src/test/rustdoc/duplicate-cfg.rs
index 505d6ee769a..9ccc5d7882e 100644
--- a/src/test/rustdoc/duplicate-cfg.rs
+++ b/src/test/rustdoc/duplicate-cfg.rs
@@ -1,15 +1,42 @@
+// ignore-tidy-linelength
+
 #![crate_name = "foo"]
 #![feature(doc_cfg)]
 
-// @has 'foo/index.html'
-// @!has '-' '//*[@class="stab portability"]' 'feature="sync" and'
-// @has '-' '//*[@class="stab portability"]' 'feature="sync"'
+// @has 'foo/struct.Foo.html'
+// @has '-' '//*[@class="stab portability"]' 'This is supported on feature="sync" only.'
 #[doc(cfg(feature = "sync"))]
 #[doc(cfg(feature = "sync"))]
 pub struct Foo;
 
+// @has 'foo/bar/struct.Bar.html'
+// @has '-' '//*[@class="stab portability"]' 'This is supported on feature="sync" only.'
 #[doc(cfg(feature = "sync"))]
 pub mod bar {
     #[doc(cfg(feature = "sync"))]
     pub struct Bar;
 }
+
+// @has 'foo/baz/struct.Baz.html'
+// @has '-' '//*[@class="stab portability"]' 'This is supported on feature="sync" and feature="send" only.'
+#[doc(cfg(all(feature = "sync", feature = "send")))]
+pub mod baz {
+    #[doc(cfg(feature = "sync"))]
+    pub struct Baz;
+}
+
+// @has 'foo/qux/struct.Qux.html'
+// @has '-' '//*[@class="stab portability"]' 'This is supported on feature="sync" and feature="send" only.'
+#[doc(cfg(feature = "sync"))]
+pub mod qux {
+    #[doc(cfg(all(feature = "sync", feature = "send")))]
+    pub struct Qux;
+}
+
+// @has 'foo/quux/struct.Quux.html'
+// @has '-' '//*[@class="stab portability"]' 'This is supported on feature="sync" and feature="send" and foo and bar only.'
+#[doc(cfg(all(feature = "sync", feature = "send", foo)))]
+pub mod quux {
+    #[doc(cfg(all(feature = "send", feature = "sync", bar)))]
+    pub struct Quux;
+}
diff --git a/src/test/rustdoc/issue-46380.rs b/src/test/rustdoc/issue-46380.rs
deleted file mode 100644
index 8837a6b463e..00000000000
--- a/src/test/rustdoc/issue-46380.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-// compile-flags: --document-private-items
-
-// @has issue_46380/struct.Hidden.html
-#[doc(hidden)]
-pub struct Hidden;
diff --git a/src/test/rustdoc/issue-67851-both.rs b/src/test/rustdoc/issue-67851-both.rs
new file mode 100644
index 00000000000..d69b9431734
--- /dev/null
+++ b/src/test/rustdoc/issue-67851-both.rs
@@ -0,0 +1,8 @@
+// compile-flags: -Zunstable-options --document-private-items --document-hidden-items
+
+// @has issue_67851_both/struct.Hidden.html
+#[doc(hidden)]
+pub struct Hidden;
+
+// @has issue_67851_both/struct.Private.html
+struct Private;
diff --git a/src/test/rustdoc/issue-67851-hidden.rs b/src/test/rustdoc/issue-67851-hidden.rs
new file mode 100644
index 00000000000..8a3cafe4c3d
--- /dev/null
+++ b/src/test/rustdoc/issue-67851-hidden.rs
@@ -0,0 +1,8 @@
+// compile-flags: -Zunstable-options --document-hidden-items
+
+// @has issue_67851_hidden/struct.Hidden.html
+#[doc(hidden)]
+pub struct Hidden;
+
+// @!has issue_67851_hidden/struct.Private.html
+struct Private;
diff --git a/src/test/rustdoc/issue-67851-neither.rs b/src/test/rustdoc/issue-67851-neither.rs
new file mode 100644
index 00000000000..4e3cd832853
--- /dev/null
+++ b/src/test/rustdoc/issue-67851-neither.rs
@@ -0,0 +1,6 @@
+// @!has issue_67851_neither/struct.Hidden.html
+#[doc(hidden)]
+pub struct Hidden;
+
+// @!has issue_67851_neither/struct.Private.html
+struct Private;
diff --git a/src/test/rustdoc/issue-67851-private.rs b/src/test/rustdoc/issue-67851-private.rs
new file mode 100644
index 00000000000..8addc7f3e4b
--- /dev/null
+++ b/src/test/rustdoc/issue-67851-private.rs
@@ -0,0 +1,8 @@
+// compile-flags: --document-private-items
+
+// @!has issue_67851_private/struct.Hidden.html
+#[doc(hidden)]
+pub struct Hidden;
+
+// @has issue_67851_private/struct.Private.html
+struct Private;
diff --git a/src/test/ui/rfc-2091-track-caller/std-panic-locations.rs b/src/test/ui/rfc-2091-track-caller/std-panic-locations.rs
new file mode 100644
index 00000000000..be13076b8af
--- /dev/null
+++ b/src/test/ui/rfc-2091-track-caller/std-panic-locations.rs
@@ -0,0 +1,38 @@
+// run-pass
+// ignore-wasm32-bare compiled with panic=abort by default
+
+#![feature(option_expect_none, option_unwrap_none)]
+
+//! Test that panic locations for `#[track_caller]` functions in std have the correct
+//! location reported.
+
+fn main() {
+    // inspect the `PanicInfo` we receive to ensure the right file is the source
+    std::panic::set_hook(Box::new(|info| {
+        let actual = info.location().unwrap();
+        if actual.file() != file!() {
+            eprintln!("expected a location in the test file, found {:?}", actual);
+            panic!();
+        }
+    }));
+
+    fn assert_panicked(f: impl FnOnce() + std::panic::UnwindSafe) {
+        std::panic::catch_unwind(f).unwrap_err();
+    }
+
+    let nope: Option<()> = None;
+    assert_panicked(|| nope.unwrap());
+    assert_panicked(|| nope.expect(""));
+
+    let yep: Option<()> = Some(());
+    assert_panicked(|| yep.unwrap_none());
+    assert_panicked(|| yep.expect_none(""));
+
+    let oops: Result<(), ()> = Err(());
+    assert_panicked(|| oops.unwrap());
+    assert_panicked(|| oops.expect(""));
+
+    let fine: Result<(), ()> = Ok(());
+    assert_panicked(|| fine.unwrap_err());
+    assert_panicked(|| fine.expect_err(""));
+}
diff --git a/src/test/ui/suggestions/issue-66968-suggest-sorted-words.rs b/src/test/ui/suggestions/issue-66968-suggest-sorted-words.rs
new file mode 100644
index 00000000000..440bb653a83
--- /dev/null
+++ b/src/test/ui/suggestions/issue-66968-suggest-sorted-words.rs
@@ -0,0 +1,4 @@
+fn main() {
+    let a_longer_variable_name = 1;
+    println!("{}", a_variable_longer_name); //~ ERROR E0425
+}
diff --git a/src/test/ui/suggestions/issue-66968-suggest-sorted-words.stderr b/src/test/ui/suggestions/issue-66968-suggest-sorted-words.stderr
new file mode 100644
index 00000000000..d7b33ea41f7
--- /dev/null
+++ b/src/test/ui/suggestions/issue-66968-suggest-sorted-words.stderr
@@ -0,0 +1,9 @@
+error[E0425]: cannot find value `a_variable_longer_name` in this scope
+  --> $DIR/issue-66968-suggest-sorted-words.rs:3:20
+   |
+LL |     println!("{}", a_variable_longer_name);
+   |                    ^^^^^^^^^^^^^^^^^^^^^^ help: a local variable with a similar name exists: `a_longer_variable_name`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.