From 8ae8bc2808bd3b5e125b72a44bfdcd24353e5211 Mon Sep 17 00:00:00 2001
From: Matthew Jasper <mjjasper1@gmail.com>
Date: Mon, 5 Aug 2019 23:06:02 +0100
Subject: [PATCH 01/16] Fix various issues with making items reachable through
 macros

* Allow items to be accessible through private modules and fields when a
  macro can access them.
* Don't mark type-private items as reachable.
* Never make items exported/public via macros
---
 src/librustc_privacy/lib.rs                   | 190 +++++++++++++++---
 .../auxiliary/field-method-macro.rs           |  23 +++
 .../auxiliary/nested-fn-macro.rs              |  11 +
 .../auxiliary/private-use-macro.rs            |  11 +
 .../ui/definition-reachable/field-method.rs   |  11 +
 src/test/ui/definition-reachable/nested-fn.rs |  11 +
 .../definition-reachable/private-non-types.rs |  21 ++
 .../ui/definition-reachable/private-types.rs  |  19 ++
 .../ui/definition-reachable/private-use.rs    |  10 +
 9 files changed, 276 insertions(+), 31 deletions(-)
 create mode 100644 src/test/ui/definition-reachable/auxiliary/field-method-macro.rs
 create mode 100644 src/test/ui/definition-reachable/auxiliary/nested-fn-macro.rs
 create mode 100644 src/test/ui/definition-reachable/auxiliary/private-use-macro.rs
 create mode 100644 src/test/ui/definition-reachable/field-method.rs
 create mode 100644 src/test/ui/definition-reachable/nested-fn.rs
 create mode 100644 src/test/ui/definition-reachable/private-non-types.rs
 create mode 100644 src/test/ui/definition-reachable/private-types.rs
 create mode 100644 src/test/ui/definition-reachable/private-use.rs

diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index ac18f0e440b78..330370e3803dd 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -229,6 +229,13 @@ fn def_id_visibility<'tcx>(
             let vis = match tcx.hir().get(hir_id) {
                 Node::Item(item) => &item.vis,
                 Node::ForeignItem(foreign_item) => &foreign_item.vis,
+                Node::MacroDef(macro_def) => {
+                    if attr::contains_name(&macro_def.attrs, sym::macro_export) {
+                        return (ty::Visibility::Public, macro_def.span, "public");
+                    } else {
+                        &macro_def.vis
+                    }
+                },
                 Node::TraitItem(..) | Node::Variant(..) => {
                     return def_id_visibility(tcx, tcx.hir().get_parent_did(hir_id));
                 }
@@ -433,11 +440,24 @@ impl VisibilityLike for Option<AccessLevel> {
 struct EmbargoVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
 
-    // Accessibility levels for reachable nodes.
+    /// Accessibility levels for reachable nodes.
     access_levels: AccessLevels,
-    // Previous accessibility level; `None` means unreachable.
+    /// A set of pairs corresponding to modules, where the first module is
+    /// reachable via a macro that's defined in the second module. This cannot
+    /// be represented as reachable because it can't handle the following case:
+    ///
+    /// pub mod n {                         // Should be `Public`
+    ///     pub(crate) mod p {              // Should *not* be accessible
+    ///         pub fn f() -> i32 { 12 }    // Must be `Reachable`
+    ///     }
+    /// }
+    /// pub macro m() {
+    ///     n::p::f()
+    /// }
+    macro_reachable: FxHashSet<(hir::HirId, DefId)>,
+    /// Previous accessibility level; `None` means unreachable.
     prev_level: Option<AccessLevel>,
-    // Has something changed in the level map?
+    /// Has something changed in the level map?
     changed: bool,
 }
 
@@ -452,7 +472,7 @@ impl EmbargoVisitor<'tcx> {
         self.access_levels.map.get(&id).cloned()
     }
 
-    // Updates node level and returns the updated level.
+    /// Updates node level and returns the updated level.
     fn update(&mut self, id: hir::HirId, level: Option<AccessLevel>) -> Option<AccessLevel> {
         let old_level = self.get(id);
         // Accessibility levels can only grow.
@@ -477,6 +497,127 @@ impl EmbargoVisitor<'tcx> {
         }
     }
 
+    /// Updates the item as being reachable through a macro defined in the given
+    /// module. Returns `true` if the level has changed.
+    fn update_macro_reachable(&mut self, reachable_mod: hir::HirId, defining_mod: DefId) -> bool {
+        if self.macro_reachable.insert((reachable_mod, defining_mod)) {
+            self.update_macro_reachable_mod(reachable_mod, defining_mod);
+            true
+        } else {
+            false
+        }
+    }
+
+    fn update_macro_reachable_mod(
+        &mut self,
+        reachable_mod: hir::HirId,
+        defining_mod: DefId,
+    ) {
+        let module_def_id = self.tcx.hir().local_def_id(reachable_mod);
+        let module = self.tcx.hir().get_module(module_def_id).0;
+        for item_id in &module.item_ids {
+            let hir_id = item_id.id;
+            let item_def_id = self.tcx.hir().local_def_id(hir_id);
+            if let Some(def_kind) = self.tcx.def_kind(item_def_id) {
+                let item = self.tcx.hir().expect_item(hir_id);
+                let vis = ty::Visibility::from_hir(&item.vis, hir_id, self.tcx);
+                self.update_macro_reachable_def(hir_id, def_kind, vis, defining_mod);
+            }
+        }
+
+        if let Some(exports) = self.tcx.module_exports(module_def_id) {
+            for export in exports {
+                if export.vis.is_accessible_from(defining_mod, self.tcx) {
+                    if let Res::Def(def_kind, def_id) = export.res {
+                        let vis = def_id_visibility(self.tcx, def_id).0;
+                        if let Some(hir_id) = self.tcx.hir().as_local_hir_id(def_id) {
+                            self.update_macro_reachable_def(
+                                hir_id,
+                                def_kind,
+                                vis,
+                                defining_mod,
+                            );
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    fn update_macro_reachable_def(
+        &mut self,
+        hir_id: hir::HirId,
+        def_kind: DefKind,
+        vis: ty::Visibility,
+        module: DefId,
+    ) {
+        let level = Some(AccessLevel::Reachable);
+        if let ty::Visibility::Public = vis {
+            self.update(hir_id, level);
+        }
+        match def_kind {
+            // No type privacy, so can be directly marked as reachable.
+            DefKind::Const
+            | DefKind::Macro(_)
+            | DefKind::Static
+            | DefKind::TraitAlias
+            | DefKind::TyAlias => {
+                if vis.is_accessible_from(module, self.tcx) {
+                    self.update(hir_id, level);
+                }
+            },
+
+            // We can't use a module name as the final segment of a path, except
+            // in use statements. Since re-export checking doesn't consider
+            // hygiene these don't need to be marked reachable. The contents of
+            // the module, however may be reachable.
+            DefKind::Mod => {
+                if vis.is_accessible_from(module, self.tcx) {
+                    self.update_macro_reachable(hir_id, module);
+                }
+            }
+
+            DefKind::Struct | DefKind::Union => {
+                // While structs and unions have type privacy, their fields do
+                // not.
+                if let ty::Visibility::Public = vis {
+                    let item = self.tcx.hir().expect_item(hir_id);
+                    if let hir::ItemKind::Struct(ref struct_def, _)
+                        | hir::ItemKind::Union(ref struct_def, _) = item.node
+                    {
+                        for field in struct_def.fields() {
+                            let field_vis = ty::Visibility::from_hir(
+                                &field.vis,
+                                field.hir_id,
+                                self.tcx,
+                            );
+                            if field_vis.is_accessible_from(module, self.tcx) {
+                                self.reach(field.hir_id, level).ty();
+                            }
+                        }
+                    } else {
+                        bug!("item {:?} with DefKind {:?}", item, def_kind);
+                    }
+                }
+            }
+
+            // These have type privacy, so are not reachable unless they're
+            // public
+            DefKind::AssocConst
+            | DefKind::AssocTy
+            | DefKind::AssocOpaqueTy
+            | DefKind::ConstParam
+            | DefKind::Ctor(_, _)
+            | DefKind::Enum
+            | DefKind::ForeignTy
+            | DefKind::Fn
+            | DefKind::OpaqueTy
+            | DefKind::Method
+            | DefKind::Trait
+            | DefKind::TyParam
+            | DefKind::Variant => (),
+        }
+    }
 
     /// Given the path segments of a `ItemKind::Use`, then we need
     /// to update the visibility of the intermediate use so that it isn't linted
@@ -746,40 +887,21 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> {
             return
         }
 
-        let module_did = ty::DefIdTree::parent(
+        let macro_module_def_id = ty::DefIdTree::parent(
             self.tcx,
             self.tcx.hir().local_def_id(md.hir_id)
         ).unwrap();
-        let mut module_id = self.tcx.hir().as_local_hir_id(module_did).unwrap();
+        let mut module_id = self.tcx.hir().as_local_hir_id(macro_module_def_id).unwrap();
         let level = if md.vis.node.is_pub() { self.get(module_id) } else { None };
-        let level = self.update(md.hir_id, level);
-        if level.is_none() {
+        let new_level = self.update(md.hir_id, level);
+        if new_level.is_none() {
             return
         }
 
         loop {
-            let module = if module_id == hir::CRATE_HIR_ID {
-                &self.tcx.hir().krate().module
-            } else if let hir::ItemKind::Mod(ref module) =
-                          self.tcx.hir().expect_item(module_id).node {
-                module
-            } else {
-                unreachable!()
-            };
-            for id in &module.item_ids {
-                self.update(id.id, level);
-            }
-            let def_id = self.tcx.hir().local_def_id(module_id);
-            if let Some(exports) = self.tcx.module_exports(def_id) {
-                for export in exports.iter() {
-                    if let Some(hir_id) = self.tcx.hir().as_local_hir_id(export.res.def_id()) {
-                        self.update(hir_id, level);
-                    }
-                }
-            }
-
-            if module_id == hir::CRATE_HIR_ID {
-                break
+            let changed_reachability = self.update_macro_reachable(module_id, macro_module_def_id);
+            if changed_reachability || module_id == hir::CRATE_HIR_ID {
+                break;
             }
             module_id = self.tcx.hir().get_parent_node(module_id);
         }
@@ -826,7 +948,12 @@ impl DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
     fn tcx(&self) -> TyCtxt<'tcx> { self.ev.tcx }
     fn visit_def_id(&mut self, def_id: DefId, _kind: &str, _descr: &dyn fmt::Display) -> bool {
         if let Some(hir_id) = self.ev.tcx.hir().as_local_hir_id(def_id) {
-            self.ev.update(hir_id, self.access_level);
+            if let ((ty::Visibility::Public, ..), _)
+                | (_, Some(AccessLevel::ReachableFromImplTrait))
+                = (def_id_visibility(self.tcx(), def_id), self.access_level)
+            {
+                self.ev.update(hir_id, self.access_level);
+            }
         }
         false
     }
@@ -1860,6 +1987,7 @@ fn privacy_access_levels(tcx: TyCtxt<'_>, krate: CrateNum) -> &AccessLevels {
     let mut visitor = EmbargoVisitor {
         tcx,
         access_levels: Default::default(),
+        macro_reachable: Default::default(),
         prev_level: Some(AccessLevel::Public),
         changed: false,
     };
diff --git a/src/test/ui/definition-reachable/auxiliary/field-method-macro.rs b/src/test/ui/definition-reachable/auxiliary/field-method-macro.rs
new file mode 100644
index 0000000000000..30ba70bdfeb66
--- /dev/null
+++ b/src/test/ui/definition-reachable/auxiliary/field-method-macro.rs
@@ -0,0 +1,23 @@
+#![feature(decl_macro)]
+
+mod n {
+    pub struct B(pub(crate) p::C);
+    impl B {
+        pub fn new() -> Self {
+            B(p::C)
+        }
+    }
+    mod p {
+        pub struct C;
+
+        impl C {
+            pub fn foo(&self) -> i32 {
+                33
+            }
+        }
+    }
+}
+
+pub macro m() {
+    n::B::new().0.foo()
+}
diff --git a/src/test/ui/definition-reachable/auxiliary/nested-fn-macro.rs b/src/test/ui/definition-reachable/auxiliary/nested-fn-macro.rs
new file mode 100644
index 0000000000000..a39e8c986c391
--- /dev/null
+++ b/src/test/ui/definition-reachable/auxiliary/nested-fn-macro.rs
@@ -0,0 +1,11 @@
+#![feature(decl_macro)]
+
+mod n {
+    pub(crate) mod p {
+        pub fn f() -> i32 { 12 }
+    }
+}
+
+pub macro m() {
+    n::p::f()
+}
diff --git a/src/test/ui/definition-reachable/auxiliary/private-use-macro.rs b/src/test/ui/definition-reachable/auxiliary/private-use-macro.rs
new file mode 100644
index 0000000000000..4f283d9c19c04
--- /dev/null
+++ b/src/test/ui/definition-reachable/auxiliary/private-use-macro.rs
@@ -0,0 +1,11 @@
+#![feature(decl_macro)]
+
+mod n {
+    pub static S: i32 = 57;
+}
+
+use n::S;
+
+pub macro m() {
+    S
+}
diff --git a/src/test/ui/definition-reachable/field-method.rs b/src/test/ui/definition-reachable/field-method.rs
new file mode 100644
index 0000000000000..60e895a2f9a07
--- /dev/null
+++ b/src/test/ui/definition-reachable/field-method.rs
@@ -0,0 +1,11 @@
+// Check that functions accessible through a field visible to a macro are
+// considered reachable
+
+// aux-build:nested-fn-macro.rs
+// run-pass
+
+extern crate nested_fn_macro;
+
+fn main() {
+    assert_eq!(nested_fn_macro::m!(), 12);
+}
diff --git a/src/test/ui/definition-reachable/nested-fn.rs b/src/test/ui/definition-reachable/nested-fn.rs
new file mode 100644
index 0000000000000..b596ba8936a43
--- /dev/null
+++ b/src/test/ui/definition-reachable/nested-fn.rs
@@ -0,0 +1,11 @@
+// Check that functions visible to macros through paths with >2 segements are
+// considered reachable
+
+// aux-build:field-method-macro.rs
+// run-pass
+
+extern crate field_method_macro;
+
+fn main() {
+    assert_eq!(field_method_macro::m!(), 33);
+}
diff --git a/src/test/ui/definition-reachable/private-non-types.rs b/src/test/ui/definition-reachable/private-non-types.rs
new file mode 100644
index 0000000000000..a601dabcb0b3f
--- /dev/null
+++ b/src/test/ui/definition-reachable/private-non-types.rs
@@ -0,0 +1,21 @@
+// Check that we don't require stability annotations for private modules,
+// imports and fields that are accessible to opaque macros.
+
+// check-pass
+
+#![feature(decl_macro, staged_api)]
+#![stable(feature = "test", since = "1.0.0")]
+
+extern crate std as local_std;
+use local_std::marker::Copy as LocalCopy;
+mod private_mod {
+    #[stable(feature = "test", since = "1.0.0")]
+    pub struct A {
+        pub(crate) f: i32,
+    }
+}
+
+#[stable(feature = "test", since = "1.0.0")]
+pub macro m() {}
+
+fn main() {}
diff --git a/src/test/ui/definition-reachable/private-types.rs b/src/test/ui/definition-reachable/private-types.rs
new file mode 100644
index 0000000000000..02c1224f4e142
--- /dev/null
+++ b/src/test/ui/definition-reachable/private-types.rs
@@ -0,0 +1,19 @@
+// Check that type privacy is taken into account when considering reachability
+
+// check-pass
+
+#![feature(decl_macro, staged_api)]
+#![stable(feature = "test", since = "1.0.0")]
+
+// Type privacy should prevent use of these in other crates, so we shouldn't
+// need a stability annotation.
+fn private_function() {}
+struct PrivateStruct { f: () }
+enum PrivateEnum { V }
+union PrivateUnion { g: () }
+trait PrivateTrait {}
+
+#[stable(feature = "test", since = "1.0.0")]
+pub macro m() {}
+
+fn main() {}
diff --git a/src/test/ui/definition-reachable/private-use.rs b/src/test/ui/definition-reachable/private-use.rs
new file mode 100644
index 0000000000000..02cff0475e586
--- /dev/null
+++ b/src/test/ui/definition-reachable/private-use.rs
@@ -0,0 +1,10 @@
+// Check that private use statements can be used by
+
+// run-pass
+// aux-build:private-use-macro.rs
+
+extern crate private_use_macro;
+
+fn main() {
+    assert_eq!(private_use_macro::m!(), 57);
+}

From 7b41fd215893c06110c7f650be47efed3910d90b Mon Sep 17 00:00:00 2001
From: Matthew Jasper <mjjasper1@gmail.com>
Date: Mon, 5 Aug 2019 23:06:40 +0100
Subject: [PATCH 02/16] Make some items in core::unicode private

They were reachable through opaque macros defined in `core`
---
 src/libcore/unicode/tables.rs  | 32 ++++++++++++++++----------------
 src/libcore/unicode/unicode.py |  8 ++++----
 2 files changed, 20 insertions(+), 20 deletions(-)

diff --git a/src/libcore/unicode/tables.rs b/src/libcore/unicode/tables.rs
index bfe784afaa47d..3fae3a46ada6b 100644
--- a/src/libcore/unicode/tables.rs
+++ b/src/libcore/unicode/tables.rs
@@ -14,8 +14,8 @@ pub const UNICODE_VERSION: UnicodeVersion = UnicodeVersion {
     micro: 0,
     _priv: (),
 };
-pub mod general_category {
-    pub const Cc_table: &super::SmallBoolTrie = &super::SmallBoolTrie {
+pub(crate) mod general_category {
+    const Cc_table: &super::SmallBoolTrie = &super::SmallBoolTrie {
         r1: &[
             0, 1, 0
         ],
@@ -28,7 +28,7 @@ pub mod general_category {
         Cc_table.lookup(c)
     }
 
-    pub const N_table: &super::BoolTrie = &super::BoolTrie {
+    const N_table: &super::BoolTrie = &super::BoolTrie {
         r1: [
             0x03ff000000000000, 0x0000000000000000, 0x720c000000000000, 0x0000000000000000,
             0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
@@ -141,8 +141,8 @@ pub mod general_category {
 
 }
 
-pub mod derived_property {
-    pub const Alphabetic_table: &super::BoolTrie = &super::BoolTrie {
+pub(crate) mod derived_property {
+    const Alphabetic_table: &super::BoolTrie = &super::BoolTrie {
         r1: [
             0x0000000000000000, 0x07fffffe07fffffe, 0x0420040000000000, 0xff7fffffff7fffff,
             0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
@@ -327,7 +327,7 @@ pub mod derived_property {
         Alphabetic_table.lookup(c)
     }
 
-    pub const Case_Ignorable_table: &super::BoolTrie = &super::BoolTrie {
+    const Case_Ignorable_table: &super::BoolTrie = &super::BoolTrie {
         r1: [
             0x0400408000000000, 0x0000000140000000, 0x0190a10000000000, 0x0000000000000000,
             0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
@@ -464,7 +464,7 @@ pub mod derived_property {
         Case_Ignorable_table.lookup(c)
     }
 
-    pub const Cased_table: &super::BoolTrie = &super::BoolTrie {
+    const Cased_table: &super::BoolTrie = &super::BoolTrie {
         r1: [
             0x0000000000000000, 0x07fffffe07fffffe, 0x0420040000000000, 0xff7fffffff7fffff,
             0xffffffffffffffff, 0xffffffffffffffff, 0xf7ffffffffffffff, 0xfffffffffffffff0,
@@ -565,7 +565,7 @@ pub mod derived_property {
         Cased_table.lookup(c)
     }
 
-    pub const Grapheme_Extend_table: &super::BoolTrie = &super::BoolTrie {
+    const Grapheme_Extend_table: &super::BoolTrie = &super::BoolTrie {
         r1: [
             0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
             0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
@@ -689,7 +689,7 @@ pub mod derived_property {
         Grapheme_Extend_table.lookup(c)
     }
 
-    pub const Lowercase_table: &super::BoolTrie = &super::BoolTrie {
+    const Lowercase_table: &super::BoolTrie = &super::BoolTrie {
         r1: [
             0x0000000000000000, 0x07fffffe00000000, 0x0420040000000000, 0xff7fffff80000000,
             0x55aaaaaaaaaaaaaa, 0xd4aaaaaaaaaaab55, 0xe6512d2a4e243129, 0xaa29aaaab5555240,
@@ -789,7 +789,7 @@ pub mod derived_property {
         Lowercase_table.lookup(c)
     }
 
-    pub const Uppercase_table: &super::BoolTrie = &super::BoolTrie {
+    const Uppercase_table: &super::BoolTrie = &super::BoolTrie {
         r1: [
             0x0000000000000000, 0x0000000007fffffe, 0x0000000000000000, 0x000000007f7fffff,
             0xaa55555555555555, 0x2b555555555554aa, 0x11aed2d5b1dbced6, 0x55d255554aaaa490,
@@ -890,7 +890,7 @@ pub mod derived_property {
         Uppercase_table.lookup(c)
     }
 
-    pub const XID_Continue_table: &super::BoolTrie = &super::BoolTrie {
+    const XID_Continue_table: &super::BoolTrie = &super::BoolTrie {
         r1: [
             0x03ff000000000000, 0x07fffffe87fffffe, 0x04a0040000000000, 0xff7fffffff7fffff,
             0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
@@ -1068,7 +1068,7 @@ pub mod derived_property {
         XID_Continue_table.lookup(c)
     }
 
-    pub const XID_Start_table: &super::BoolTrie = &super::BoolTrie {
+    const XID_Start_table: &super::BoolTrie = &super::BoolTrie {
         r1: [
             0x0000000000000000, 0x07fffffe07fffffe, 0x0420040000000000, 0xff7fffffff7fffff,
             0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
@@ -1250,8 +1250,8 @@ pub mod derived_property {
 
 }
 
-pub mod property {
-    pub const Pattern_White_Space_table: &super::SmallBoolTrie = &super::SmallBoolTrie {
+pub(crate) mod property {
+    const Pattern_White_Space_table: &super::SmallBoolTrie = &super::SmallBoolTrie {
         r1: &[
             0, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@@ -1268,7 +1268,7 @@ pub mod property {
         Pattern_White_Space_table.lookup(c)
     }
 
-    pub const White_Space_table: &super::SmallBoolTrie = &super::SmallBoolTrie {
+    const White_Space_table: &super::SmallBoolTrie = &super::SmallBoolTrie {
         r1: &[
             0, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@@ -1290,7 +1290,7 @@ pub mod property {
 
 }
 
-pub mod conversions {
+pub(crate) mod conversions {
     pub fn to_lower(c: char) -> [char; 3] {
         match bsearch_case_table(c, to_lowercase_table) {
             None        => [c, '\0', '\0'],
diff --git a/src/libcore/unicode/unicode.py b/src/libcore/unicode/unicode.py
index 5389d1cf80383..6de5d9e033b93 100755
--- a/src/libcore/unicode/unicode.py
+++ b/src/libcore/unicode/unicode.py
@@ -606,7 +606,7 @@ def compute_trie(raw_data, chunk_size):
     return root, child_data
 
 
-def generate_bool_trie(name, codepoint_ranges, is_pub=True):
+def generate_bool_trie(name, codepoint_ranges, is_pub=False):
     # type: (str, List[Tuple[int, int]], bool) -> Iterator[str]
     """
     Generate Rust code for BoolTrie struct.
@@ -681,7 +681,7 @@ def generate_bool_trie(name, codepoint_ranges, is_pub=True):
     yield "    };\n\n"
 
 
-def generate_small_bool_trie(name, codepoint_ranges, is_pub=True):
+def generate_small_bool_trie(name, codepoint_ranges, is_pub=False):
     # type: (str, List[Tuple[int, int]], bool) -> Iterator[str]
     """
     Generate Rust code for `SmallBoolTrie` struct.
@@ -726,7 +726,7 @@ def generate_property_module(mod, grouped_categories, category_subset):
     Generate Rust code for module defining properties.
     """
 
-    yield "pub mod %s {\n" % mod
+    yield "pub(crate) mod %s {\n" % mod
     for cat in sorted(category_subset):
         if cat in ("Cc", "White_Space", "Pattern_White_Space"):
             generator = generate_small_bool_trie("%s_table" % cat, grouped_categories[cat])
@@ -749,7 +749,7 @@ def generate_conversions_module(unicode_data):
     Generate Rust code for module defining conversions.
     """
 
-    yield "pub mod conversions {"
+    yield "pub(crate) mod conversions {"
     yield """
     pub fn to_lower(c: char) -> [char; 3] {
         match bsearch_case_table(c, to_lowercase_table) {

From d9d9246418ae884cb67feb3574832696660b8e2e Mon Sep 17 00:00:00 2001
From: Matthew Jasper <mjjasper1@gmail.com>
Date: Mon, 5 Aug 2019 23:10:32 +0100
Subject: [PATCH 03/16] Remove gensym from format_args

---
 src/libcore/macros.rs              |  2 --
 src/libsyntax_ext/format.rs        |  4 ++--
 src/test/ui/format-hygiene.rs      |  8 --------
 src/test/ui/hygiene/format-args.rs | 12 ++++++++++++
 4 files changed, 14 insertions(+), 12 deletions(-)
 delete mode 100644 src/test/ui/format-hygiene.rs
 create mode 100644 src/test/ui/hygiene/format-args.rs

diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs
index 37cc71bff62b4..6a2c3bff4ddca 100644
--- a/src/libcore/macros.rs
+++ b/src/libcore/macros.rs
@@ -767,7 +767,6 @@ pub(crate) mod builtin {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[allow_internal_unstable(fmt_internals)]
     #[rustc_builtin_macro]
-    #[rustc_macro_transparency = "semitransparent"]
     pub macro format_args {
         ($fmt:expr) => ({ /* compiler built-in */ }),
         ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ })
@@ -779,7 +778,6 @@ pub(crate) mod builtin {
                          language use and is subject to change")]
     #[allow_internal_unstable(fmt_internals)]
     #[rustc_builtin_macro]
-    #[rustc_macro_transparency = "semitransparent"]
     pub macro format_args_nl {
         ($fmt:expr) => ({ /* compiler built-in */ }),
         ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ })
diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs
index fe9cad1e32fca..1dfcc14021c3b 100644
--- a/src/libsyntax_ext/format.rs
+++ b/src/libsyntax_ext/format.rs
@@ -646,7 +646,7 @@ impl<'a, 'b> Context<'a, 'b> {
         let mut heads = Vec::with_capacity(self.args.len());
 
         let names_pos: Vec<_> = (0..self.args.len())
-            .map(|i| self.ecx.ident_of(&format!("arg{}", i)).gensym())
+            .map(|i| ast::Ident::from_str_and_span(&format!("arg{}", i), self.macsp))
             .collect();
 
         // First, build up the static array which will become our precompiled
@@ -843,7 +843,7 @@ pub fn expand_preparsed_format_args(
     let arg_unique_types: Vec<_> = (0..args.len()).map(|_| Vec::new()).collect();
 
     let mut macsp = ecx.call_site();
-    macsp = macsp.apply_mark(ecx.current_expansion.id);
+    macsp = macsp.with_ctxt(ecx.backtrace());
 
     let msg = "format argument must be a string literal";
     let fmt_sp = efmt.span;
diff --git a/src/test/ui/format-hygiene.rs b/src/test/ui/format-hygiene.rs
deleted file mode 100644
index 6bf5ae8beaddb..0000000000000
--- a/src/test/ui/format-hygiene.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-// run-pass
-
-#![allow(non_upper_case_globals)]
-pub const arg0: u8 = 1;
-
-pub fn main() {
-    format!("{}", 1);
-}
diff --git a/src/test/ui/hygiene/format-args.rs b/src/test/ui/hygiene/format-args.rs
new file mode 100644
index 0000000000000..d74889b95cc12
--- /dev/null
+++ b/src/test/ui/hygiene/format-args.rs
@@ -0,0 +1,12 @@
+// check-pass
+
+#![allow(non_upper_case_globals)]
+#![feature(format_args_nl)]
+
+static arg0: () = ();
+
+fn main() {
+    static arg1: () = ();
+    format_args!("{} {:?}", 0, 1);
+    format_args_nl!("{} {:?}", 0, 1);
+}

From 642ee709427ada3711fb27dba9d26bbdaee6a3da Mon Sep 17 00:00:00 2001
From: Yuki Okushi <huyuumi.dev@gmail.com>
Date: Fri, 9 Aug 2019 08:37:40 +0900
Subject: [PATCH 04/16] Add test for issue-43623

---
 src/test/ui/issues/issue-43623.rs     | 19 ++++++++++++
 src/test/ui/issues/issue-43623.stderr | 42 +++++++++++++++++++++++++++
 2 files changed, 61 insertions(+)
 create mode 100644 src/test/ui/issues/issue-43623.rs
 create mode 100644 src/test/ui/issues/issue-43623.stderr

diff --git a/src/test/ui/issues/issue-43623.rs b/src/test/ui/issues/issue-43623.rs
new file mode 100644
index 0000000000000..b259e9e269d06
--- /dev/null
+++ b/src/test/ui/issues/issue-43623.rs
@@ -0,0 +1,19 @@
+pub trait Trait<'a> {
+    type Assoc;
+}
+
+pub struct Type;
+
+impl<'a> Trait<'a> for Type {
+    type Assoc = ();
+}
+
+pub fn break_me<T, F>(f: F)
+where T: for<'b> Trait<'b>,
+      F: for<'b> FnMut(<T as Trait<'b>>::Assoc) {
+    break_me::<Type, fn(_)>;
+    //~^ ERROR: type mismatch in function arguments
+    //~| ERROR: type mismatch resolving
+}
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-43623.stderr b/src/test/ui/issues/issue-43623.stderr
new file mode 100644
index 0000000000000..b5674105f75d2
--- /dev/null
+++ b/src/test/ui/issues/issue-43623.stderr
@@ -0,0 +1,42 @@
+error[E0631]: type mismatch in function arguments
+  --> $DIR/issue-43623.rs:14:5
+   |
+LL |     break_me::<Type, fn(_)>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+   |     |
+   |     expected signature of `for<'b> fn(<Type as Trait<'b>>::Assoc) -> _`
+   |     found signature of `fn(_) -> _`
+   |
+note: required by `break_me`
+  --> $DIR/issue-43623.rs:11:1
+   |
+LL | / pub fn break_me<T, F>(f: F)
+LL | | where T: for<'b> Trait<'b>,
+LL | |       F: for<'b> FnMut(<T as Trait<'b>>::Assoc) {
+LL | |     break_me::<Type, fn(_)>;
+LL | |
+LL | |
+LL | | }
+   | |_^
+
+error[E0271]: type mismatch resolving `for<'b> <fn(_) as std::ops::FnOnce<(<Type as Trait<'b>>::Assoc,)>>::Output == ()`
+  --> $DIR/issue-43623.rs:14:5
+   |
+LL |     break_me::<Type, fn(_)>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'b, found concrete lifetime
+   |
+note: required by `break_me`
+  --> $DIR/issue-43623.rs:11:1
+   |
+LL | / pub fn break_me<T, F>(f: F)
+LL | | where T: for<'b> Trait<'b>,
+LL | |       F: for<'b> FnMut(<T as Trait<'b>>::Assoc) {
+LL | |     break_me::<Type, fn(_)>;
+LL | |
+LL | |
+LL | | }
+   | |_^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0271`.

From 55f15d765565773e95c60e7e14b956bfeed30157 Mon Sep 17 00:00:00 2001
From: Yuki Okushi <huyuumi.dev@gmail.com>
Date: Fri, 9 Aug 2019 08:37:55 +0900
Subject: [PATCH 05/16] Add test for issue-44405

---
 src/test/ui/issues/issue-44405.rs     | 22 ++++++++++++++++++++++
 src/test/ui/issues/issue-44405.stderr | 11 +++++++++++
 2 files changed, 33 insertions(+)
 create mode 100644 src/test/ui/issues/issue-44405.rs
 create mode 100644 src/test/ui/issues/issue-44405.stderr

diff --git a/src/test/ui/issues/issue-44405.rs b/src/test/ui/issues/issue-44405.rs
new file mode 100644
index 0000000000000..d404b9044dd6f
--- /dev/null
+++ b/src/test/ui/issues/issue-44405.rs
@@ -0,0 +1,22 @@
+use std::ops::Index;
+
+struct Test;
+struct Container(Test);
+
+impl Test {
+    fn test(&mut self) {}
+}
+
+impl<'a> Index<&'a bool> for Container {
+    type Output = Test;
+
+    fn index(&self, _index: &'a bool) -> &Test {
+        &self.0
+    }
+}
+
+fn main() {
+    let container = Container(Test);
+    let mut val = true;
+    container[&mut val].test(); //~ ERROR: cannot borrow data
+}
diff --git a/src/test/ui/issues/issue-44405.stderr b/src/test/ui/issues/issue-44405.stderr
new file mode 100644
index 0000000000000..1fd69f6e77799
--- /dev/null
+++ b/src/test/ui/issues/issue-44405.stderr
@@ -0,0 +1,11 @@
+error[E0596]: cannot borrow data in an index of `Container` as mutable
+  --> $DIR/issue-44405.rs:21:5
+   |
+LL |     container[&mut val].test();
+   |     ^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
+   |
+   = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `Container`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.

From fd7ac6b17ef98f63438f59edca40562c400d4128 Mon Sep 17 00:00:00 2001
From: BO41 <botbob@disroot.org>
Date: Sun, 23 Jun 2019 12:19:46 +0000
Subject: [PATCH 06/16] Deprecate `try!` macro

Co-Authored-By: Mazdak Farrokhzad <twingoow@gmail.com>
Co-Authored-By: Oliver Middleton <olliemail27@gmail.com>
---
 src/libcore/macros.rs                             | 1 +
 src/libstd/lib.rs                                 | 5 ++++-
 src/test/ui/associated-types/cache/chrono-scan.rs | 2 +-
 src/test/ui/derived-errors/issue-31997.rs         | 2 +-
 src/test/ui/derived-errors/issue-31997.stderr     | 6 +++---
 src/test/ui/lint/lint-qualification.rs            | 2 +-
 src/test/ui/macros/macro-comma-support-rpass.rs   | 2 ++
 src/test/ui/macros/try-macro.rs                   | 1 +
 src/test/ui/rust-2018/try-macro.fixed             | 1 +
 src/test/ui/rust-2018/try-macro.rs                | 1 +
 src/test/ui/rust-2018/try-macro.stderr            | 2 +-
 11 files changed, 17 insertions(+), 8 deletions(-)

diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs
index 09d2331b60fed..ba641f7dc5c12 100644
--- a/src/libcore/macros.rs
+++ b/src/libcore/macros.rs
@@ -300,6 +300,7 @@ macro_rules! debug_assert_ne {
 ///     Ok(())
 /// }
 /// ```
+#[rustc_deprecated(since = "1.38.0", reason = "use the `?` operator instead")]
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(alias = "?")]
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index cfee49a7b555c..34956fc839450 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -330,7 +330,10 @@ use prelude::v1::*;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::{assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne};
 #[stable(feature = "rust1", since = "1.0.0")]
-pub use core::{unreachable, unimplemented, write, writeln, r#try, todo};
+pub use core::{unreachable, unimplemented, write, writeln, todo};
+#[allow(deprecated)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::r#try;
 
 #[allow(unused_imports)] // macros from `alloc` are not used on all platforms
 #[macro_use]
diff --git a/src/test/ui/associated-types/cache/chrono-scan.rs b/src/test/ui/associated-types/cache/chrono-scan.rs
index 8ddd347ff3607..5c05240552761 100644
--- a/src/test/ui/associated-types/cache/chrono-scan.rs
+++ b/src/test/ui/associated-types/cache/chrono-scan.rs
@@ -18,7 +18,7 @@ pub fn timezone_offset_zulu<F>(s: &str, colon: F) -> ParseResult<(&str, i32)>
 pub fn parse<'a, I>(mut s: &str, items: I) -> ParseResult<()>
         where I: Iterator<Item=Item<'a>> {
     macro_rules! try_consume {
-        ($e:expr) => ({ let (s_, v) = try!($e); s = s_; v })
+        ($e:expr) => ({ let (s_, v) = $e?; s = s_; v })
     }
     let offset = try_consume!(timezone_offset_zulu(s.trim_start(), colon_or_space));
     let offset = try_consume!(timezone_offset_zulu(s.trim_start(), colon_or_space));
diff --git a/src/test/ui/derived-errors/issue-31997.rs b/src/test/ui/derived-errors/issue-31997.rs
index cfdee26c5599c..6d7d21e367322 100644
--- a/src/test/ui/derived-errors/issue-31997.rs
+++ b/src/test/ui/derived-errors/issue-31997.rs
@@ -10,7 +10,7 @@ fn closure<F, T>(x: F) -> Result<T, ()>
 }
 
 fn foo() -> Result<(), ()> {
-    try!(closure(|| bar(core::ptr::null_mut()))); //~ ERROR cannot find function `bar` in this scope
+    closure(|| bar(core::ptr::null_mut()))?; //~ ERROR cannot find function `bar` in this scope
     Ok(())
 }
 
diff --git a/src/test/ui/derived-errors/issue-31997.stderr b/src/test/ui/derived-errors/issue-31997.stderr
index e9fe0d3971ee6..d9260f79f2742 100644
--- a/src/test/ui/derived-errors/issue-31997.stderr
+++ b/src/test/ui/derived-errors/issue-31997.stderr
@@ -1,8 +1,8 @@
 error[E0425]: cannot find function `bar` in this scope
-  --> $DIR/issue-31997.rs:13:21
+  --> $DIR/issue-31997.rs:13:16
    |
-LL |     try!(closure(|| bar(core::ptr::null_mut())));
-   |                     ^^^ not found in this scope
+LL |     closure(|| bar(core::ptr::null_mut()))?;
+   |                ^^^ not found in this scope
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/lint/lint-qualification.rs b/src/test/ui/lint/lint-qualification.rs
index 2aa4526b8169b..d458c31dc4926 100644
--- a/src/test/ui/lint/lint-qualification.rs
+++ b/src/test/ui/lint/lint-qualification.rs
@@ -9,7 +9,7 @@ fn main() {
     foo::bar(); //~ ERROR: unnecessary qualification
     bar();
 
-    let _ = || -> Result<(), ()> { try!(Ok(())); Ok(()) }; // issue #37345
+    let _ = || -> Result<(), ()> { Ok(())?; Ok(()) }; // issue #37345
 
     macro_rules! m { () => {
         $crate::foo::bar(); // issue #37357
diff --git a/src/test/ui/macros/macro-comma-support-rpass.rs b/src/test/ui/macros/macro-comma-support-rpass.rs
index 12a612c153ad6..17c27b7cda473 100644
--- a/src/test/ui/macros/macro-comma-support-rpass.rs
+++ b/src/test/ui/macros/macro-comma-support-rpass.rs
@@ -261,7 +261,9 @@ fn thread_local() {
 #[test]
 fn try() {
     fn inner() -> Result<(), ()> {
+        #[allow(deprecated)]
         try!(Ok(()));
+        #[allow(deprecated)]
         try!(Ok(()),);
         Ok(())
     }
diff --git a/src/test/ui/macros/try-macro.rs b/src/test/ui/macros/try-macro.rs
index 83b30a8b7ba11..643312654493a 100644
--- a/src/test/ui/macros/try-macro.rs
+++ b/src/test/ui/macros/try-macro.rs
@@ -1,4 +1,5 @@
 // run-pass
+#[allow(deprecated)]
 use std::num::{ParseFloatError, ParseIntError};
 
 fn main() {
diff --git a/src/test/ui/rust-2018/try-macro.fixed b/src/test/ui/rust-2018/try-macro.fixed
index 7c1692fd7fb13..a7b7d3faf5ee9 100644
--- a/src/test/ui/rust-2018/try-macro.fixed
+++ b/src/test/ui/rust-2018/try-macro.fixed
@@ -6,6 +6,7 @@
 #![warn(rust_2018_compatibility)]
 #![allow(unused_variables)]
 #![allow(dead_code)]
+#![allow(deprecated)]
 
 fn foo() -> Result<usize, ()> {
     let x: Result<usize, ()> = Ok(22);
diff --git a/src/test/ui/rust-2018/try-macro.rs b/src/test/ui/rust-2018/try-macro.rs
index 2089d367be698..986e158eb644e 100644
--- a/src/test/ui/rust-2018/try-macro.rs
+++ b/src/test/ui/rust-2018/try-macro.rs
@@ -6,6 +6,7 @@
 #![warn(rust_2018_compatibility)]
 #![allow(unused_variables)]
 #![allow(dead_code)]
+#![allow(deprecated)]
 
 fn foo() -> Result<usize, ()> {
     let x: Result<usize, ()> = Ok(22);
diff --git a/src/test/ui/rust-2018/try-macro.stderr b/src/test/ui/rust-2018/try-macro.stderr
index eb65d4150642a..fad1bb9f1b068 100644
--- a/src/test/ui/rust-2018/try-macro.stderr
+++ b/src/test/ui/rust-2018/try-macro.stderr
@@ -1,5 +1,5 @@
 warning: `try` is a keyword in the 2018 edition
-  --> $DIR/try-macro.rs:12:5
+  --> $DIR/try-macro.rs:13:5
    |
 LL |     try!(x);
    |     ^^^ help: you can use a raw identifier to stay compatible: `r#try`

From 90fa7901b98367d04857cb96366b2eedf70693e2 Mon Sep 17 00:00:00 2001
From: Lzu Tao <taolzu@gmail.com>
Date: Mon, 15 Jul 2019 17:42:08 +0000
Subject: [PATCH 07/16] Postpone deprecating try! until 1.39.0

---
 src/libcore/macros.rs | 2 +-
 src/libstd/lib.rs     | 3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs
index ba641f7dc5c12..aa661078e7176 100644
--- a/src/libcore/macros.rs
+++ b/src/libcore/macros.rs
@@ -300,9 +300,9 @@ macro_rules! debug_assert_ne {
 ///     Ok(())
 /// }
 /// ```
-#[rustc_deprecated(since = "1.38.0", reason = "use the `?` operator instead")]
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_deprecated(since = "1.39.0", reason = "use the `?` operator instead")]
 #[doc(alias = "?")]
 macro_rules! r#try {
     ($expr:expr) => (match $expr {
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 34956fc839450..54abf72d3075a 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -331,7 +331,8 @@ use prelude::v1::*;
 pub use core::{assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne};
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::{unreachable, unimplemented, write, writeln, todo};
-#[allow(deprecated)]
+// FIXME: change this to `#[allow(deprecated)]` when we update nightly compiler.
+#[allow(deprecated_in_future)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::r#try;
 

From 6842316f6ff4586465e6412edce5e6808cfcd396 Mon Sep 17 00:00:00 2001
From: Lzu Tao <taolzu@gmail.com>
Date: Sun, 14 Jul 2019 08:16:46 +0000
Subject: [PATCH 08/16] Allow deprecated try macro in test crates

---
 src/test/ui/associated-types/cache/chrono-scan.rs | 4 +++-
 src/test/ui/derived-errors/issue-31997.rs         | 3 ++-
 src/test/ui/derived-errors/issue-31997.stderr     | 6 +++---
 src/test/ui/lint/lint-qualification.rs            | 3 ++-
 src/test/ui/lint/lint-qualification.stderr        | 2 +-
 src/test/ui/macros/macro-comma-support-rpass.rs   | 3 +--
 src/test/ui/macros/try-macro.rs                   | 2 +-
 7 files changed, 13 insertions(+), 10 deletions(-)

diff --git a/src/test/ui/associated-types/cache/chrono-scan.rs b/src/test/ui/associated-types/cache/chrono-scan.rs
index 5c05240552761..964ddc9b625de 100644
--- a/src/test/ui/associated-types/cache/chrono-scan.rs
+++ b/src/test/ui/associated-types/cache/chrono-scan.rs
@@ -1,5 +1,7 @@
 // check-pass
 
+#![allow(deprecated)]
+
 pub type ParseResult<T> = Result<T, ()>;
 
 pub enum Item<'a> {
@@ -18,7 +20,7 @@ pub fn timezone_offset_zulu<F>(s: &str, colon: F) -> ParseResult<(&str, i32)>
 pub fn parse<'a, I>(mut s: &str, items: I) -> ParseResult<()>
         where I: Iterator<Item=Item<'a>> {
     macro_rules! try_consume {
-        ($e:expr) => ({ let (s_, v) = $e?; s = s_; v })
+        ($e:expr) => ({ let (s_, v) = try!($e); s = s_; v })
     }
     let offset = try_consume!(timezone_offset_zulu(s.trim_start(), colon_or_space));
     let offset = try_consume!(timezone_offset_zulu(s.trim_start(), colon_or_space));
diff --git a/src/test/ui/derived-errors/issue-31997.rs b/src/test/ui/derived-errors/issue-31997.rs
index 6d7d21e367322..ff619313afb5b 100644
--- a/src/test/ui/derived-errors/issue-31997.rs
+++ b/src/test/ui/derived-errors/issue-31997.rs
@@ -1,5 +1,6 @@
 // Test that the resolve failure does not lead to downstream type errors.
 // See issue #31997.
+#![allow(deprecated)]
 
 trait TheTrait { }
 
@@ -10,7 +11,7 @@ fn closure<F, T>(x: F) -> Result<T, ()>
 }
 
 fn foo() -> Result<(), ()> {
-    closure(|| bar(core::ptr::null_mut()))?; //~ ERROR cannot find function `bar` in this scope
+    try!(closure(|| bar(core::ptr::null_mut()))); //~ ERROR cannot find function `bar` in this scope
     Ok(())
 }
 
diff --git a/src/test/ui/derived-errors/issue-31997.stderr b/src/test/ui/derived-errors/issue-31997.stderr
index d9260f79f2742..b53c0cda8de4d 100644
--- a/src/test/ui/derived-errors/issue-31997.stderr
+++ b/src/test/ui/derived-errors/issue-31997.stderr
@@ -1,8 +1,8 @@
 error[E0425]: cannot find function `bar` in this scope
-  --> $DIR/issue-31997.rs:13:16
+  --> $DIR/issue-31997.rs:14:21
    |
-LL |     closure(|| bar(core::ptr::null_mut()))?;
-   |                ^^^ not found in this scope
+LL |     try!(closure(|| bar(core::ptr::null_mut())));
+   |                     ^^^ not found in this scope
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/lint/lint-qualification.rs b/src/test/ui/lint/lint-qualification.rs
index d458c31dc4926..1b24191a111c2 100644
--- a/src/test/ui/lint/lint-qualification.rs
+++ b/src/test/ui/lint/lint-qualification.rs
@@ -1,4 +1,5 @@
 #![deny(unused_qualifications)]
+#[allow(deprecated)]
 
 mod foo {
     pub fn bar() {}
@@ -9,7 +10,7 @@ fn main() {
     foo::bar(); //~ ERROR: unnecessary qualification
     bar();
 
-    let _ = || -> Result<(), ()> { Ok(())?; Ok(()) }; // issue #37345
+    let _ = || -> Result<(), ()> { try!(Ok(())); Ok(()) }; // issue #37345
 
     macro_rules! m { () => {
         $crate::foo::bar(); // issue #37357
diff --git a/src/test/ui/lint/lint-qualification.stderr b/src/test/ui/lint/lint-qualification.stderr
index 78f7e32a30cd1..125aeb3db0366 100644
--- a/src/test/ui/lint/lint-qualification.stderr
+++ b/src/test/ui/lint/lint-qualification.stderr
@@ -1,5 +1,5 @@
 error: unnecessary qualification
-  --> $DIR/lint-qualification.rs:9:5
+  --> $DIR/lint-qualification.rs:10:5
    |
 LL |     foo::bar();
    |     ^^^^^^^^
diff --git a/src/test/ui/macros/macro-comma-support-rpass.rs b/src/test/ui/macros/macro-comma-support-rpass.rs
index 17c27b7cda473..50c0ef3451d3d 100644
--- a/src/test/ui/macros/macro-comma-support-rpass.rs
+++ b/src/test/ui/macros/macro-comma-support-rpass.rs
@@ -15,6 +15,7 @@
 
 #![cfg_attr(core, no_std)]
 
+#![allow(deprecated)] // for deprecated `try!()` macro
 #![feature(concat_idents)]
 
 #[cfg(std)] use std::fmt;
@@ -261,9 +262,7 @@ fn thread_local() {
 #[test]
 fn try() {
     fn inner() -> Result<(), ()> {
-        #[allow(deprecated)]
         try!(Ok(()));
-        #[allow(deprecated)]
         try!(Ok(()),);
         Ok(())
     }
diff --git a/src/test/ui/macros/try-macro.rs b/src/test/ui/macros/try-macro.rs
index 643312654493a..824c77d9de528 100644
--- a/src/test/ui/macros/try-macro.rs
+++ b/src/test/ui/macros/try-macro.rs
@@ -1,5 +1,5 @@
 // run-pass
-#[allow(deprecated)]
+#![allow(deprecated)] // for deprecated `try!()` macro
 use std::num::{ParseFloatError, ParseIntError};
 
 fn main() {

From e9ee2cbc53af43dc007bfd81054fb20e57d5da67 Mon Sep 17 00:00:00 2001
From: Sayan Nandan <17377258+sntdevco@users.noreply.github.com>
Date: Fri, 9 Aug 2019 12:47:27 +0530
Subject: [PATCH 09/16] Improve test output for libcore/time

---
 src/libcore/tests/time.rs | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/src/libcore/tests/time.rs b/src/libcore/tests/time.rs
index 09aae4583482f..fac70c468c89d 100644
--- a/src/libcore/tests/time.rs
+++ b/src/libcore/tests/time.rs
@@ -2,7 +2,7 @@ use core::time::Duration;
 
 #[test]
 fn creation() {
-    assert!(Duration::from_secs(1) != Duration::from_secs(0));
+    assert_ne!(Duration::from_secs(1), Duration::from_secs(0));
     assert_eq!(Duration::from_secs(1) + Duration::from_secs(2),
                Duration::from_secs(3));
     assert_eq!(Duration::from_millis(10) + Duration::from_secs(4),
@@ -107,14 +107,12 @@ fn checked_sub() {
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn sub_bad1() {
     let _ = Duration::new(0, 0) - Duration::new(0, 1);
 }
 
 #[test]
 #[should_panic]
-#[cfg(not(miri))] // Miri does not support panics
 fn sub_bad2() {
     let _ = Duration::new(0, 0) - Duration::new(1, 0);
 }

From 623debfe9dcbb70bcb5fd891db2e861d91e1b8a9 Mon Sep 17 00:00:00 2001
From: Sayan Nandan <17377258+sntdevco@users.noreply.github.com>
Date: Fri, 9 Aug 2019 12:51:34 +0530
Subject: [PATCH 10/16] Improve tests for libcore/slice

---
 src/libcore/tests/slice.rs | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs
index 31d16e0e32057..c036dd8d92f22 100644
--- a/src/libcore/tests/slice.rs
+++ b/src/libcore/tests/slice.rs
@@ -3,19 +3,19 @@ use core::result::Result::{Ok, Err};
 #[test]
 fn test_position() {
     let b = [1, 2, 3, 5, 5];
-    assert!(b.iter().position(|&v| v == 9) == None);
-    assert!(b.iter().position(|&v| v == 5) == Some(3));
-    assert!(b.iter().position(|&v| v == 3) == Some(2));
-    assert!(b.iter().position(|&v| v == 0) == None);
+    assert_eq!(b.iter().position(|&v| v == 9), None);
+    assert_eq!(b.iter().position(|&v| v == 5), Some(3));
+    assert_eq!(b.iter().position(|&v| v == 3), Some(2));
+    assert_eq!(b.iter().position(|&v| v == 0), None);
 }
 
 #[test]
 fn test_rposition() {
     let b = [1, 2, 3, 5, 5];
-    assert!(b.iter().rposition(|&v| v == 9) == None);
-    assert!(b.iter().rposition(|&v| v == 5) == Some(4));
-    assert!(b.iter().rposition(|&v| v == 3) == Some(2));
-    assert!(b.iter().rposition(|&v| v == 0) == None);
+    assert_eq!(b.iter().rposition(|&v| v == 9), None);
+    assert_eq!(b.iter().rposition(|&v| v == 5), Some(4));
+    assert_eq!(b.iter().rposition(|&v| v == 3), Some(2));
+    assert_eq!(b.iter().rposition(|&v| v == 0), None);
 }
 
 #[test]

From 33445aea509cadcd715009c79795d289268daa7c Mon Sep 17 00:00:00 2001
From: Sayan Nandan <17377258+sntdevco@users.noreply.github.com>
Date: Fri, 9 Aug 2019 12:53:14 +0530
Subject: [PATCH 11/16] Improve tests for liballoc/btree/set

---
 src/liballoc/tests/btree/set.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/liballoc/tests/btree/set.rs b/src/liballoc/tests/btree/set.rs
index 4f5168f1ce572..9e03137594961 100644
--- a/src/liballoc/tests/btree/set.rs
+++ b/src/liballoc/tests/btree/set.rs
@@ -10,7 +10,7 @@ fn test_clone_eq() {
     m.insert(1);
     m.insert(2);
 
-    assert!(m.clone() == m);
+    assert_eq!(m.clone(), m);
 }
 
 #[test]
@@ -28,7 +28,7 @@ fn test_hash() {
     y.insert(2);
     y.insert(1);
 
-    assert!(hash(&x) == hash(&y));
+    assert_eq!(hash(&x), hash(&y));
 }
 
 fn check<F>(a: &[i32], b: &[i32], expected: &[i32], f: F)

From c5687e3940faaa398843e8e9e9c8f9a00a267b0b Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Fri, 9 Aug 2019 10:07:59 +0200
Subject: [PATCH 12/16] enable flt2dec tests in Miri

---
 src/libcore/tests/num/flt2dec/estimator.rs    |  7 +++++-
 src/libcore/tests/num/flt2dec/mod.rs          | 16 +++++++++++--
 src/libcore/tests/num/flt2dec/random.rs       | 23 +++++++++++++++----
 .../tests/num/flt2dec/strategy/dragon.rs      |  1 +
 .../tests/num/flt2dec/strategy/grisu.rs       |  1 +
 5 files changed, 41 insertions(+), 7 deletions(-)

diff --git a/src/libcore/tests/num/flt2dec/estimator.rs b/src/libcore/tests/num/flt2dec/estimator.rs
index 2dbb8e3a5f06e..50fe61b5e2267 100644
--- a/src/libcore/tests/num/flt2dec/estimator.rs
+++ b/src/libcore/tests/num/flt2dec/estimator.rs
@@ -42,7 +42,12 @@ fn test_estimate_scaling_factor() {
     assert_almost_eq!(estimate_scaling_factor(1, -1074), -323);
     assert_almost_eq!(estimate_scaling_factor(0x1fffffffffffff, 971), 309);
 
-    for i in -1074..972 {
+    #[cfg(not(miri))] // Miri is too slow
+    let iter = -1074..972;
+    #[cfg(miri)]
+    let iter = (-1074..972).step_by(11);
+
+    for i in iter {
         let expected = super::ldexp_f64(1.0, i).log10().ceil();
         assert_almost_eq!(estimate_scaling_factor(1, i as i16), expected as i16);
     }
diff --git a/src/libcore/tests/num/flt2dec/mod.rs b/src/libcore/tests/num/flt2dec/mod.rs
index f42f500c2df1d..c41d35efced6c 100644
--- a/src/libcore/tests/num/flt2dec/mod.rs
+++ b/src/libcore/tests/num/flt2dec/mod.rs
@@ -1,5 +1,3 @@
-#![cfg(not(miri))] // Miri does not implement ldexp, which most tests here need
-
 use std::prelude::v1::*;
 use std::{str, i16, f32, f64, fmt};
 
@@ -257,6 +255,7 @@ pub fn f32_shortest_sanity_test<F>(mut f: F) where F: FnMut(&Decoded, &mut [u8])
     check_shortest!(f(minf32) => b"1", -44);
 }
 
+#[cfg(not(miri))] // Miri is too slow
 pub fn f32_exact_sanity_test<F>(mut f: F)
         where F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16) {
     let minf32 = ldexp_f32(1.0, -149);
@@ -362,6 +361,7 @@ pub fn f64_shortest_sanity_test<F>(mut f: F) where F: FnMut(&Decoded, &mut [u8])
     check_shortest!(f(minf64) => b"5", -323);
 }
 
+#[cfg(not(miri))] // Miri is too slow
 pub fn f64_exact_sanity_test<F>(mut f: F)
         where F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16) {
     let minf64 = ldexp_f64(1.0, -1074);
@@ -553,6 +553,10 @@ pub fn to_shortest_str_test<F>(mut f_: F)
     assert_eq!(to_string(f, minf64, Minus, 324, false), format!("0.{:0>323}5", ""));
     assert_eq!(to_string(f, minf64, Minus, 325, false), format!("0.{:0>323}50", ""));
 
+    if cfg!(miri) { // Miri is too slow
+        return;
+    }
+
     // very large output
     assert_eq!(to_string(f, 1.1, Minus, 80000, false), format!("1.1{:0>79999}", ""));
 }
@@ -807,6 +811,10 @@ pub fn to_exact_exp_str_test<F>(mut f_: F)
                "1.401298464324817070923729583289916131280261941876515771757068283\
                  8897910826858606014866381883621215820312500000000000000000000000e-45");
 
+    if cfg!(miri) { // Miri is too slow
+        return;
+    }
+
     assert_eq!(to_string(f, f64::MAX, Minus,   1, false), "2e308");
     assert_eq!(to_string(f, f64::MAX, Minus,   2, false), "1.8e308");
     assert_eq!(to_string(f, f64::MAX, Minus,   4, false), "1.798e308");
@@ -1040,6 +1048,10 @@ pub fn to_exact_fixed_str_test<F>(mut f_: F)
     assert_eq!(to_string(f, f32::MAX, Minus, 2, false),
                "340282346638528859811704183484516925440.00");
 
+    if cfg!(miri) { // Miri is too slow
+        return;
+    }
+
     let minf32 = ldexp_f32(1.0, -149);
     assert_eq!(to_string(f, minf32, Minus,   0, false), "0");
     assert_eq!(to_string(f, minf32, Minus,   1, false), "0.0");
diff --git a/src/libcore/tests/num/flt2dec/random.rs b/src/libcore/tests/num/flt2dec/random.rs
index d56787b2819a7..3db5b4c84fc3b 100644
--- a/src/libcore/tests/num/flt2dec/random.rs
+++ b/src/libcore/tests/num/flt2dec/random.rs
@@ -109,8 +109,13 @@ pub fn f32_exhaustive_equivalence_test<F, G>(f: F, g: G, k: usize)
 #[test]
 fn shortest_random_equivalence_test() {
     use core::num::flt2dec::strategy::dragon::format_shortest as fallback;
-    f64_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 10_000);
-    f32_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 10_000);
+    #[cfg(not(miri))] // Miri is too slow
+    const N: usize = 10_000;
+    #[cfg(miri)]
+    const N: usize = 20;
+
+    f64_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, N);
+    f32_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, N);
 }
 
 #[test] #[ignore] // it is too expensive
@@ -138,17 +143,27 @@ fn shortest_f64_hard_random_equivalence_test() {
 #[test]
 fn exact_f32_random_equivalence_test() {
     use core::num::flt2dec::strategy::dragon::format_exact as fallback;
+    #[cfg(not(miri))] // Miri is too slow
+    const N: usize = 1_000;
+    #[cfg(miri)]
+    const N: usize = 10;
+
     for k in 1..21 {
         f32_random_equivalence_test(|d, buf| format_exact_opt(d, buf, i16::MIN),
-                                             |d, buf| fallback(d, buf, i16::MIN), k, 1_000);
+                                             |d, buf| fallback(d, buf, i16::MIN), k, N);
     }
 }
 
 #[test]
 fn exact_f64_random_equivalence_test() {
     use core::num::flt2dec::strategy::dragon::format_exact as fallback;
+    #[cfg(not(miri))] // Miri is too slow
+    const N: usize = 1_000;
+    #[cfg(miri)]
+    const N: usize = 5;
+
     for k in 1..21 {
         f64_random_equivalence_test(|d, buf| format_exact_opt(d, buf, i16::MIN),
-                                             |d, buf| fallback(d, buf, i16::MIN), k, 1_000);
+                                             |d, buf| fallback(d, buf, i16::MIN), k, N);
     }
 }
diff --git a/src/libcore/tests/num/flt2dec/strategy/dragon.rs b/src/libcore/tests/num/flt2dec/strategy/dragon.rs
index 5e4cc23d33c8c..dc4d78bfae109 100644
--- a/src/libcore/tests/num/flt2dec/strategy/dragon.rs
+++ b/src/libcore/tests/num/flt2dec/strategy/dragon.rs
@@ -23,6 +23,7 @@ fn shortest_sanity_test() {
 }
 
 #[test]
+#[cfg(not(miri))] // Miri is too slow
 fn exact_sanity_test() {
     // This test ends up running what I can only assume is some corner-ish case
     // of the `exp2` library function, defined in whatever C runtime we're
diff --git a/src/libcore/tests/num/flt2dec/strategy/grisu.rs b/src/libcore/tests/num/flt2dec/strategy/grisu.rs
index f1afd7d4bf86f..f8bdddfe2e410 100644
--- a/src/libcore/tests/num/flt2dec/strategy/grisu.rs
+++ b/src/libcore/tests/num/flt2dec/strategy/grisu.rs
@@ -36,6 +36,7 @@ fn shortest_sanity_test() {
 }
 
 #[test]
+#[cfg(not(miri))] // Miri is too slow
 fn exact_sanity_test() {
     // See comments in dragon.rs's exact_sanity_test for why this test is
     // ignored on MSVC

From c7e16c5f47ac86877ab6c52db61709349e4cf276 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= <matti@marinelayer.io>
Date: Tue, 6 Aug 2019 14:55:57 +0200
Subject: [PATCH 13/16] Check links on all platforms when running locally

---
 src/bootstrap/tool.rs                     | 26 ++++++++++++++++++++---
 src/ci/docker/x86_64-gnu-tools/Dockerfile |  3 +++
 src/tools/rustbook/Cargo.toml             |  7 +++---
 src/tools/rustbook/src/main.rs            | 13 ++++++------
 4 files changed, 36 insertions(+), 13 deletions(-)

diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs
index 15a329a5b9152..df7eb7c455d02 100644
--- a/src/bootstrap/tool.rs
+++ b/src/bootstrap/tool.rs
@@ -9,7 +9,7 @@ use build_helper::t;
 use crate::Mode;
 use crate::Compiler;
 use crate::builder::{Step, RunConfig, ShouldRun, Builder};
-use crate::util::{exe, add_lib_path};
+use crate::util::{exe, add_lib_path, CiEnv};
 use crate::compile;
 use crate::channel::GitInfo;
 use crate::channel;
@@ -279,11 +279,26 @@ pub fn prepare_tool_cargo(
     cargo
 }
 
+fn rustbook_features() -> Vec<String> {
+    let mut features = Vec::new();
+
+    // Due to CI budged and risk of spurious failures we want to limit jobs running this check.
+    // At same time local builds should run it regardless of the platform.
+    // `CiEnv::None` means it's local build and `CHECK_LINKS` is defined in x86_64-gnu-tools to
+    // explicitly enable it on single job
+    if CiEnv::current() == CiEnv::None || env::var("CHECK_LINKS").is_ok() {
+        features.push("linkcheck".to_string());
+    }
+
+    features
+}
+
 macro_rules! bootstrap_tool {
     ($(
         $name:ident, $path:expr, $tool_name:expr
         $(,llvm_tools = $llvm:expr)*
         $(,is_external_tool = $external:expr)*
+        $(,features = $features:expr)*
         ;
     )+) => {
         #[derive(Copy, PartialEq, Eq, Clone)]
@@ -350,7 +365,12 @@ macro_rules! bootstrap_tool {
                     } else {
                         SourceType::InTree
                     },
-                    extra_features: Vec::new(),
+                    extra_features: {
+                        // FIXME(#60643): avoid this lint by using `_`
+                        let mut _tmp = Vec::new();
+                        $(_tmp.extend($features);)*
+                        _tmp
+                    },
                 }).expect("expected to build -- essential tool")
             }
         }
@@ -359,7 +379,7 @@ macro_rules! bootstrap_tool {
 }
 
 bootstrap_tool!(
-    Rustbook, "src/tools/rustbook", "rustbook";
+    Rustbook, "src/tools/rustbook", "rustbook", features = rustbook_features();
     UnstableBookGen, "src/tools/unstable-book-gen", "unstable-book-gen";
     Tidy, "src/tools/tidy", "tidy";
     Linkchecker, "src/tools/linkchecker", "linkchecker";
diff --git a/src/ci/docker/x86_64-gnu-tools/Dockerfile b/src/ci/docker/x86_64-gnu-tools/Dockerfile
index f11ae7a34cb91..8035195c6ed0a 100644
--- a/src/ci/docker/x86_64-gnu-tools/Dockerfile
+++ b/src/ci/docker/x86_64-gnu-tools/Dockerfile
@@ -21,6 +21,9 @@ COPY x86_64-gnu-tools/checkregression.py /tmp/
 COPY x86_64-gnu-tools/checktools.sh /tmp/
 COPY x86_64-gnu-tools/repo.sh /tmp/
 
+# Run rustbook with `linkcheck` feature enabled
+ENV CHECK_LINKS 1
+
 ENV RUST_CONFIGURE_ARGS \
   --build=x86_64-unknown-linux-gnu \
   --save-toolstates=/tmp/toolstates.json
diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml
index bb10d06851b5a..a7188f0d11eac 100644
--- a/src/tools/rustbook/Cargo.toml
+++ b/src/tools/rustbook/Cargo.toml
@@ -5,14 +5,15 @@ version = "0.1.0"
 license = "MIT OR Apache-2.0"
 edition = "2018"
 
+[features]
+linkcheck = ["mdbook-linkcheck"]
+
 [dependencies]
 clap = "2.25.0"
 failure = "0.1"
+mdbook-linkcheck = { version = "0.3.0", optional = true }
 
 [dependencies.mdbook]
 version = "0.3.0"
 default-features = false
 features = ["search"]
-
-[target.'cfg(all(target_arch = "x86_64", target_os = "linux"))'.dependencies]
-mdbook-linkcheck = "0.3.0"
diff --git a/src/tools/rustbook/src/main.rs b/src/tools/rustbook/src/main.rs
index 6bce7c3a978eb..95530b210afd6 100644
--- a/src/tools/rustbook/src/main.rs
+++ b/src/tools/rustbook/src/main.rs
@@ -8,10 +8,9 @@ use clap::{App, ArgMatches, SubCommand, AppSettings};
 use mdbook::MDBook;
 use mdbook::errors::{Result as Result3};
 
-#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
+#[cfg(feature = "linkcheck")]
 use mdbook::renderer::RenderContext;
-
-#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
+#[cfg(feature = "linkcheck")]
 use mdbook_linkcheck::{self, errors::BrokenLinks};
 use failure::Error;
 
@@ -52,7 +51,7 @@ fn main() {
             if let Err(err) = linkcheck(sub_matches) {
                 eprintln!("Error: {}", err);
 
-                #[cfg(all(target_arch = "x86_64", target_os = "linux"))]
+                #[cfg(feature = "linkcheck")]
                 {
                     if let Ok(broken_links) = err.downcast::<BrokenLinks>() {
                         for cause in broken_links.links().iter() {
@@ -68,7 +67,7 @@ fn main() {
     };
 }
 
-#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
+#[cfg(feature = "linkcheck")]
 pub fn linkcheck(args: &ArgMatches<'_>) -> Result<(), Error> {
     let book_dir = get_book_dir(args);
     let book = MDBook::load(&book_dir).unwrap();
@@ -78,9 +77,9 @@ pub fn linkcheck(args: &ArgMatches<'_>) -> Result<(), Error> {
     mdbook_linkcheck::check_links(&render_ctx)
 }
 
-#[cfg(not(all(target_arch = "x86_64", target_os = "linux")))]
+#[cfg(not(feature = "linkcheck"))]
 pub fn linkcheck(_args: &ArgMatches<'_>) -> Result<(), Error> {
-    println!("mdbook-linkcheck only works on x86_64 linux targets.");
+    println!("mdbook-linkcheck is disabled.");
     Ok(())
 }
 

From 29ca428ffa753a300b880ee11e132ead54f4dbb7 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Fri, 9 Aug 2019 11:18:17 +0200
Subject: [PATCH 14/16] Miri is really slow

---
 src/libcore/tests/num/dec2flt/mod.rs       | 1 +
 src/libcore/tests/num/flt2dec/estimator.rs | 2 +-
 src/libcore/tests/num/flt2dec/random.rs    | 6 +++---
 3 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/src/libcore/tests/num/dec2flt/mod.rs b/src/libcore/tests/num/dec2flt/mod.rs
index 0e71426c64108..46eacb4200acc 100644
--- a/src/libcore/tests/num/dec2flt/mod.rs
+++ b/src/libcore/tests/num/dec2flt/mod.rs
@@ -77,6 +77,7 @@ fn infinity() {
 fn zero() {
     test_literal!(0.0);
     test_literal!(1e-325);
+    #[cfg(not(miri))] // Miri is too slow
     test_literal!(1e-326);
     #[cfg(not(miri))] // Miri is too slow
     test_literal!(1e-500);
diff --git a/src/libcore/tests/num/flt2dec/estimator.rs b/src/libcore/tests/num/flt2dec/estimator.rs
index 50fe61b5e2267..c51451708f3ce 100644
--- a/src/libcore/tests/num/flt2dec/estimator.rs
+++ b/src/libcore/tests/num/flt2dec/estimator.rs
@@ -45,7 +45,7 @@ fn test_estimate_scaling_factor() {
     #[cfg(not(miri))] // Miri is too slow
     let iter = -1074..972;
     #[cfg(miri)]
-    let iter = (-1074..972).step_by(11);
+    let iter = (-1074..972).step_by(37);
 
     for i in iter {
         let expected = super::ldexp_f64(1.0, i).log10().ceil();
diff --git a/src/libcore/tests/num/flt2dec/random.rs b/src/libcore/tests/num/flt2dec/random.rs
index 3db5b4c84fc3b..d9543793397bf 100644
--- a/src/libcore/tests/num/flt2dec/random.rs
+++ b/src/libcore/tests/num/flt2dec/random.rs
@@ -112,7 +112,7 @@ fn shortest_random_equivalence_test() {
     #[cfg(not(miri))] // Miri is too slow
     const N: usize = 10_000;
     #[cfg(miri)]
-    const N: usize = 20;
+    const N: usize = 10;
 
     f64_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, N);
     f32_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, N);
@@ -146,7 +146,7 @@ fn exact_f32_random_equivalence_test() {
     #[cfg(not(miri))] // Miri is too slow
     const N: usize = 1_000;
     #[cfg(miri)]
-    const N: usize = 10;
+    const N: usize = 3;
 
     for k in 1..21 {
         f32_random_equivalence_test(|d, buf| format_exact_opt(d, buf, i16::MIN),
@@ -160,7 +160,7 @@ fn exact_f64_random_equivalence_test() {
     #[cfg(not(miri))] // Miri is too slow
     const N: usize = 1_000;
     #[cfg(miri)]
-    const N: usize = 5;
+    const N: usize = 3;
 
     for k in 1..21 {
         f64_random_equivalence_test(|d, buf| format_exact_opt(d, buf, i16::MIN),

From 73edef7fdc1caa72fbceb773743a2c4b31162601 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Fri, 9 Aug 2019 11:43:25 +0200
Subject: [PATCH 15/16] reduce some test sizes in Miri

---
 src/liballoc/tests/btree/map.rs |  3 +++
 src/liballoc/tests/btree/set.rs | 24 ++++++++++++++++++++++++
 2 files changed, 27 insertions(+)

diff --git a/src/liballoc/tests/btree/map.rs b/src/liballoc/tests/btree/map.rs
index 844afe870766b..266a0d055d5bc 100644
--- a/src/liballoc/tests/btree/map.rs
+++ b/src/liballoc/tests/btree/map.rs
@@ -689,7 +689,10 @@ fn test_split_off_empty_left() {
 
 #[test]
 fn test_split_off_large_random_sorted() {
+    #[cfg(not(miri))] // Miri is too slow
     let mut data = rand_data(1529);
+    #[cfg(miri)]
+    let mut data = rand_data(529);
     // special case with maximum height.
     data.sort();
 
diff --git a/src/liballoc/tests/btree/set.rs b/src/liballoc/tests/btree/set.rs
index 989beb3b1bfd9..b3e85ce186082 100644
--- a/src/liballoc/tests/btree/set.rs
+++ b/src/liballoc/tests/btree/set.rs
@@ -69,6 +69,11 @@ fn test_intersection() {
     check_intersection(&[11, 1, 3, 77, 103, 5, -5],
                        &[2, 11, 77, -9, -42, 5, 3],
                        &[3, 5, 11, 77]);
+
+    if cfg!(miri) { // Miri is too slow
+        return;
+    }
+
     let large = (0..1000).collect::<Vec<_>>();
     check_intersection(&[], &large, &[]);
     check_intersection(&large, &[], &[]);
@@ -98,6 +103,11 @@ fn test_difference() {
     check_difference(&[-5, 11, 22, 33, 40, 42],
                      &[-12, -5, 14, 23, 34, 38, 39, 50],
                      &[11, 22, 33, 40, 42]);
+
+    if cfg!(miri) { // Miri is too slow
+        return;
+    }
+
     let large = (0..1000).collect::<Vec<_>>();
     check_difference(&[], &large, &[]);
     check_difference(&[-1], &large, &[-1]);
@@ -166,6 +176,17 @@ fn test_is_subset() {
     assert_eq!(is_subset(&[1, 2], &[1]), false);
     assert_eq!(is_subset(&[1, 2], &[1, 2]), true);
     assert_eq!(is_subset(&[1, 2], &[2, 3]), false);
+    assert_eq!(is_subset(&[-5, 11, 22, 33, 40, 42],
+                         &[-12, -5, 14, 23, 11, 34, 22, 38, 33, 42, 39, 40]),
+               true);
+    assert_eq!(is_subset(&[-5, 11, 22, 33, 40, 42],
+                         &[-12, -5, 14, 23, 34, 38, 22, 11]),
+               false);
+
+    if cfg!(miri) { // Miri is too slow
+        return;
+    }
+
     let large = (0..1000).collect::<Vec<_>>();
     assert_eq!(is_subset(&[], &large), true);
     assert_eq!(is_subset(&large, &[]), false);
@@ -371,7 +392,10 @@ fn test_split_off_empty_left() {
 
 #[test]
 fn test_split_off_large_random_sorted() {
+    #[cfg(not(miri))] // Miri is too slow
     let mut data = rand_data(1529);
+    #[cfg(miri)]
+    let mut data = rand_data(529);
     // special case with maximum height.
     data.sort();
 

From 78caca00d7112c0216c52e86833e93a63085dcd1 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Fri, 9 Aug 2019 13:55:22 +0200
Subject: [PATCH 16/16] explain Miri disabling

---
 src/libcore/tests/slice.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs
index 1ef77f87ab7e2..a0426c0d4fe8a 100644
--- a/src/libcore/tests/slice.rs
+++ b/src/libcore/tests/slice.rs
@@ -1153,7 +1153,7 @@ fn test_rotate_right() {
 }
 
 #[test]
-#[cfg(not(miri))]
+#[cfg(not(miri))] // Miri is too slow
 fn brute_force_rotate_test_0() {
     // In case of edge cases involving multiple algorithms
     let n = 300;