about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-05-16 00:44:57 +0000
committerbors <bors@rust-lang.org>2020-05-16 00:44:57 +0000
commit163445ac80225090c81e7ff1b185fb5dca52e3b2 (patch)
tree2b4e970433a44f7b014097600a3d2ed087475a79
parented084b0b8341c974769a0328f61851b0e1fc17fa (diff)
parenta27b1b68edae0662190e9bd546b9a22ffabfb48b (diff)
downloadrust-163445ac80225090c81e7ff1b185fb5dca52e3b2.tar.gz
rust-163445ac80225090c81e7ff1b185fb5dca52e3b2.zip
Auto merge of #72251 - Dylan-DPC:rollup-4mik3o7, r=Dylan-DPC
Rollup of 9 pull requests

Successful merges:

 - #71662 (Implement FromStr for OsString)
 - #71677 (Add explicit references to the BuildHasher trait)
 - #71724 (Doc alias improvements)
 - #71948 (Suggest to await future before ? operator)
 - #72090 (rustc_driver: factor out computing the exit code)
 - #72206 (Cleanup stale 'FIXME(#64197)')
 - #72218 (make sure even unleashed miri does not do pointer stuff)
 - #72220 ([const-prop] Don't replace Rvalues that are already constants)
 - #72224 (doc: add links to rotate_(left|right))

Failed merges:

r? @ghost
-rw-r--r--src/libcore/num/mod.rs16
-rw-r--r--src/librustc_driver/lib.rs23
-rw-r--r--src/librustc_expand/parse/lexer/tests.rs4
-rw-r--r--src/librustc_middle/hir/map/mod.rs6
-rw-r--r--src/librustc_middle/query/mod.rs6
-rw-r--r--src/librustc_middle/ty/query/keys.rs12
-rw-r--r--src/librustc_mir/transform/const_prop.rs7
-rw-r--r--src/librustc_parse/lexer/mod.rs7
-rw-r--r--src/librustc_trait_selection/traits/error_reporting/mod.rs1
-rw-r--r--src/librustc_trait_selection/traits/error_reporting/suggestions.rs101
-rw-r--r--src/librustc_trait_selection/traits/mod.rs42
-rw-r--r--src/librustc_typeck/check/mod.rs24
-rw-r--r--src/librustdoc/clean/types.rs9
-rw-r--r--src/librustdoc/html/layout.rs1
-rw-r--r--src/librustdoc/html/render.rs43
-rw-r--r--src/librustdoc/html/render/cache.rs64
-rw-r--r--src/librustdoc/html/static/main.js136
-rw-r--r--src/libstd/collections/hash/map.rs10
-rw-r--r--src/libstd/collections/hash/set.rs10
-rw-r--r--src/libstd/ffi/os_str.rs10
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable/rustc.main.ConstProp.diff3
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable_aggregate/rustc.main.ConstProp.diff3
-rw-r--r--src/test/mir-opt/copy_propagation_arg/rustc.arg_src.CopyPropagation.diff2
-rw-r--r--src/test/mir-opt/copy_propagation_arg/rustc.bar.CopyPropagation.diff2
-rw-r--r--src/test/rustdoc-js-std/alias-2.js4
-rw-r--r--src/test/rustdoc-js/doc-alias.js263
-rw-r--r--src/test/rustdoc-js/doc-alias.rs79
-rw-r--r--src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr5
-rw-r--r--src/test/ui/async-await/issue-61076.rs32
-rw-r--r--src/test/ui/async-await/issue-61076.stderr27
-rw-r--r--src/test/ui/async-await/try-on-option-in-async.rs3
-rw-r--r--src/test/ui/async-await/try-on-option-in-async.stderr6
-rw-r--r--src/test/ui/consts/miri_unleashed/ptr_arith.rs29
-rw-r--r--src/test/ui/consts/miri_unleashed/ptr_arith.stderr39
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/mod.rs18
-rw-r--r--src/tools/clippy/src/driver.rs4
-rw-r--r--src/tools/rustdoc-js/tester.js105
37 files changed, 946 insertions, 210 deletions
diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs
index 9b4872f5d9f..9e1971c9a94 100644
--- a/src/libcore/num/mod.rs
+++ b/src/libcore/num/mod.rs
@@ -1499,8 +1499,8 @@ any high-order bits of `rhs` that would cause the shift to exceed the bitwidth o
 
 Note that this is *not* the same as a rotate-left; the RHS of a wrapping shift-left is restricted to
 the range of the type, rather than the bits shifted out of the LHS being returned to the other end.
-The primitive integer types all implement a `rotate_left` function, which may be what you want
-instead.
+The primitive integer types all implement a `[`rotate_left`](#method.rotate_left) function,
+which may be what you want instead.
 
 # Examples
 
@@ -1531,8 +1531,8 @@ removes any high-order bits of `rhs` that would cause the shift to exceed the bi
 
 Note that this is *not* the same as a rotate-right; the RHS of a wrapping shift-right is restricted
 to the range of the type, rather than the bits shifted out of the LHS being returned to the other
-end. The primitive integer types all implement a `rotate_right` function, which may be what you want
-instead.
+end. The primitive integer types all implement a [`rotate_right`](#method.rotate_right) function,
+which may be what you want instead.
 
 # Examples
 
@@ -3610,8 +3610,8 @@ Note that this is *not* the same as a rotate-left; the
 RHS of a wrapping shift-left is restricted to the range
 of the type, rather than the bits shifted out of the LHS
 being returned to the other end. The primitive integer
-types all implement a `rotate_left` function, which may
-be what you want instead.
+types all implement a [`rotate_left`](#method.rotate_left) function,
+which may be what you want instead.
 
 # Examples
 
@@ -3644,8 +3644,8 @@ Note that this is *not* the same as a rotate-right; the
 RHS of a wrapping shift-right is restricted to the range
 of the type, rather than the bits shifted out of the LHS
 being returned to the other end. The primitive integer
-types all implement a `rotate_right` function, which may
-be what you want instead.
+types all implement a [`rotate_right`](#method.rotate_right) function,
+which may be what you want instead.
 
 # Examples
 
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 913ccf8e680..6847b175e60 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -1138,6 +1138,16 @@ pub fn catch_fatal_errors<F: FnOnce() -> R, R>(f: F) -> Result<R, ErrorReported>
     })
 }
 
+/// Variant of `catch_fatal_errors` for the `interface::Result` return type
+/// that also computes the exit code.
+pub fn catch_with_exit_code(f: impl FnOnce() -> interface::Result<()>) -> i32 {
+    let result = catch_fatal_errors(f).and_then(|result| result);
+    match result {
+        Ok(()) => EXIT_SUCCESS,
+        Err(_) => EXIT_FAILURE,
+    }
+}
+
 lazy_static! {
     static ref DEFAULT_HOOK: Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static> = {
         let hook = panic::take_hook();
@@ -1228,12 +1238,12 @@ pub fn init_rustc_env_logger() {
     env_logger::init_from_env("RUSTC_LOG");
 }
 
-pub fn main() {
+pub fn main() -> ! {
     let start = Instant::now();
     init_rustc_env_logger();
     let mut callbacks = TimePassesCallbacks::default();
     install_ice_hook();
-    let result = catch_fatal_errors(|| {
+    let exit_code = catch_with_exit_code(|| {
         let args = env::args_os()
             .enumerate()
             .map(|(i, arg)| {
@@ -1246,13 +1256,8 @@ pub fn main() {
             })
             .collect::<Vec<_>>();
         run_compiler(&args, &mut callbacks, None, None)
-    })
-    .and_then(|result| result);
-    let exit_code = match result {
-        Ok(_) => EXIT_SUCCESS,
-        Err(_) => EXIT_FAILURE,
-    };
+    });
     // The extra `\t` is necessary to align this label with the others.
     print_time_passes_entry(callbacks.time_passes, "\ttotal", start.elapsed());
-    process::exit(exit_code);
+    process::exit(exit_code)
 }
diff --git a/src/librustc_expand/parse/lexer/tests.rs b/src/librustc_expand/parse/lexer/tests.rs
index 2cb6267e0f6..2932475430b 100644
--- a/src/librustc_expand/parse/lexer/tests.rs
+++ b/src/librustc_expand/parse/lexer/tests.rs
@@ -50,13 +50,13 @@ fn t1() {
         assert_eq!(string_reader.next_token(), token::Whitespace);
         // Read another token.
         let tok3 = string_reader.next_token();
-        assert_eq!(string_reader.pos.clone(), BytePos(28));
+        assert_eq!(string_reader.pos(), BytePos(28));
         let tok4 = Token::new(mk_ident("main"), Span::with_root_ctxt(BytePos(24), BytePos(28)));
         assert_eq!(tok3.kind, tok4.kind);
         assert_eq!(tok3.span, tok4.span);
 
         assert_eq!(string_reader.next_token(), token::OpenDelim(token::Paren));
-        assert_eq!(string_reader.pos.clone(), BytePos(29))
+        assert_eq!(string_reader.pos(), BytePos(29))
     })
 }
 
diff --git a/src/librustc_middle/hir/map/mod.rs b/src/librustc_middle/hir/map/mod.rs
index de0373c1384..b823516d64f 100644
--- a/src/librustc_middle/hir/map/mod.rs
+++ b/src/librustc_middle/hir/map/mod.rs
@@ -390,11 +390,7 @@ impl<'hir> Map<'hir> {
     /// Given a `HirId`, returns the `BodyId` associated with it,
     /// if the node is a body owner, otherwise returns `None`.
     pub fn maybe_body_owned_by(&self, hir_id: HirId) -> Option<BodyId> {
-        if let Some(node) = self.find(hir_id) {
-            associated_body(node)
-        } else {
-            bug!("no entry for id `{}`", hir_id)
-        }
+        self.find(hir_id).map(associated_body).flatten()
     }
 
     /// Given a body owner's id, returns the `BodyId` associated with it.
diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs
index 2ceba519494..13cf9a934b7 100644
--- a/src/librustc_middle/query/mod.rs
+++ b/src/librustc_middle/query/mod.rs
@@ -1164,6 +1164,12 @@ rustc_queries! {
             desc { "evaluating trait selection obligation `{}`", goal.value }
         }
 
+        query type_implements_trait(
+            key: (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>, )
+        ) -> bool {
+            desc { "evaluating `type_implements_trait` `{:?}`", key }
+        }
+
         /// Do not call this query directly: part of the `Eq` type-op
         query type_op_ascribe_user_type(
             goal: CanonicalTypeOpAscribeUserTypeGoal<'tcx>
diff --git a/src/librustc_middle/ty/query/keys.rs b/src/librustc_middle/ty/query/keys.rs
index 239691dbd17..4acf766f033 100644
--- a/src/librustc_middle/ty/query/keys.rs
+++ b/src/librustc_middle/ty/query/keys.rs
@@ -295,3 +295,15 @@ impl Key for (Symbol, u32, u32) {
         DUMMY_SP
     }
 }
+
+impl<'tcx> Key for (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>) {
+    type CacheSelector = DefaultCacheSelector;
+
+    fn query_crate(&self) -> CrateNum {
+        LOCAL_CRATE
+    }
+
+    fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
+        DUMMY_SP
+    }
+}
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index e898f22ec23..bdf2193c6af 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -616,6 +616,13 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         value: OpTy<'tcx>,
         source_info: SourceInfo,
     ) {
+        if let Rvalue::Use(Operand::Constant(c)) = rval {
+            if !matches!(c.literal.val, ConstKind::Unevaluated(..)) {
+                trace!("skipping replace of Rvalue::Use({:?} because it is already a const", c);
+                return;
+            }
+        }
+
         trace!("attepting to replace {:?} with {:?}", rval, value);
         if let Err(e) = self.ecx.const_validate_operand(
             value,
diff --git a/src/librustc_parse/lexer/mod.rs b/src/librustc_parse/lexer/mod.rs
index f676a34a1d1..aa048d682c2 100644
--- a/src/librustc_parse/lexer/mod.rs
+++ b/src/librustc_parse/lexer/mod.rs
@@ -31,8 +31,7 @@ pub struct StringReader<'a> {
     /// Initial position, read-only.
     start_pos: BytePos,
     /// The absolute offset within the source_map of the current character.
-    // FIXME(#64197): `pub` is needed by tests for now.
-    pub pos: BytePos,
+    pos: BytePos,
     /// Stop reading src at this index.
     end_src_index: usize,
     /// Source text to tokenize.
@@ -436,6 +435,10 @@ impl<'a> StringReader<'a> {
         }
     }
 
+    pub fn pos(&self) -> BytePos {
+        self.pos
+    }
+
     #[inline]
     fn src_index(&self, pos: BytePos) -> usize {
         (pos - self.start_pos).to_usize()
diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs
index 5a63a693652..6bd4455e1e3 100644
--- a/src/librustc_trait_selection/traits/error_reporting/mod.rs
+++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs
@@ -402,6 +402,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                         self.suggest_remove_reference(&obligation, &mut err, &trait_ref);
                         self.suggest_semicolon_removal(&obligation, &mut err, span, &trait_ref);
                         self.note_version_mismatch(&mut err, &trait_ref);
+                        self.suggest_await_before_try(&mut err, &obligation, &trait_ref, span);
                         if self.suggest_impl_trait(&mut err, span, &obligation, &trait_ref) {
                             err.emit();
                             return;
diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
index 5c4ba40bf38..503daf56b49 100644
--- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
+++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
@@ -1,14 +1,17 @@
 use super::{
     EvaluationResult, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation,
+    SelectionContext,
 };
 
 use crate::infer::InferCtxt;
+use crate::traits::normalize_projection_type;
 
 use rustc_errors::{error_code, struct_span_err, Applicability, DiagnosticBuilder, Style};
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
+use rustc_hir::lang_items;
 use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
 use rustc_middle::ty::TypeckTables;
 use rustc_middle::ty::{
@@ -150,6 +153,15 @@ pub trait InferCtxtExt<'tcx> {
         T: fmt::Display;
 
     fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder<'_>);
+
+    /// Suggest to await before try: future? => future.await?
+    fn suggest_await_before_try(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        obligation: &PredicateObligation<'tcx>,
+        trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
+        span: Span,
+    );
 }
 
 fn predicate_constraint(generics: &hir::Generics<'_>, pred: String) -> (Span, String) {
@@ -1822,6 +1834,95 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             suggested_limit, self.tcx.crate_name,
         ));
     }
+
+    fn suggest_await_before_try(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        obligation: &PredicateObligation<'tcx>,
+        trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
+        span: Span,
+    ) {
+        debug!(
+            "suggest_await_befor_try: obligation={:?}, span={:?}, trait_ref={:?}, trait_ref_self_ty={:?}",
+            obligation,
+            span,
+            trait_ref,
+            trait_ref.self_ty()
+        );
+        let body_hir_id = obligation.cause.body_id;
+        let item_id = self.tcx.hir().get_parent_node(body_hir_id);
+
+        if let Some(body_id) = self.tcx.hir().maybe_body_owned_by(item_id) {
+            let body = self.tcx.hir().body(body_id);
+            if let Some(hir::GeneratorKind::Async(_)) = body.generator_kind {
+                let future_trait =
+                    self.tcx.require_lang_item(lang_items::FutureTraitLangItem, None);
+
+                let self_ty = self.resolve_vars_if_possible(&trait_ref.self_ty());
+
+                let impls_future = self.tcx.type_implements_trait((
+                    future_trait,
+                    self_ty,
+                    ty::List::empty(),
+                    obligation.param_env,
+                ));
+
+                let item_def_id = self
+                    .tcx
+                    .associated_items(future_trait)
+                    .in_definition_order()
+                    .next()
+                    .unwrap()
+                    .def_id;
+                // `<T as Future>::Output`
+                let projection_ty = ty::ProjectionTy {
+                    // `T`
+                    substs: self.tcx.mk_substs_trait(
+                        trait_ref.self_ty(),
+                        self.fresh_substs_for_item(span, item_def_id),
+                    ),
+                    // `Future::Output`
+                    item_def_id,
+                };
+
+                let mut selcx = SelectionContext::new(self);
+
+                let mut obligations = vec![];
+                let normalized_ty = normalize_projection_type(
+                    &mut selcx,
+                    obligation.param_env,
+                    projection_ty,
+                    obligation.cause.clone(),
+                    0,
+                    &mut obligations,
+                );
+
+                debug!(
+                    "suggest_await_befor_try: normalized_projection_type {:?}",
+                    self.resolve_vars_if_possible(&normalized_ty)
+                );
+                let try_obligation = self.mk_obligation_for_def_id(
+                    trait_ref.def_id(),
+                    normalized_ty,
+                    obligation.cause.clone(),
+                    obligation.param_env,
+                );
+                debug!("suggest_await_befor_try: try_trait_obligation {:?}", try_obligation);
+                if self.predicate_may_hold(&try_obligation) && impls_future {
+                    if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
+                        if snippet.ends_with('?') {
+                            err.span_suggestion(
+                                span,
+                                "consider using `.await` here",
+                                format!("{}.await?", snippet.trim_end_matches('?')),
+                                Applicability::MaybeIncorrect,
+                            );
+                        }
+                    }
+                }
+            }
+        }
+    }
 }
 
 /// Collect all the returned expressions within the input expression.
diff --git a/src/librustc_trait_selection/traits/mod.rs b/src/librustc_trait_selection/traits/mod.rs
index 778430fc2ca..9592f93ce2e 100644
--- a/src/librustc_trait_selection/traits/mod.rs
+++ b/src/librustc_trait_selection/traits/mod.rs
@@ -31,7 +31,9 @@ use rustc_hir::def_id::DefId;
 use rustc_middle::middle::region;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
-use rustc_middle::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, WithConstness};
+use rustc_middle::ty::{
+    self, GenericParamDefKind, ParamEnv, ToPredicate, Ty, TyCtxt, WithConstness,
+};
 use rustc_span::Span;
 
 use std::fmt::Debug;
@@ -523,6 +525,43 @@ fn vtable_methods<'tcx>(
     }))
 }
 
+/// Check whether a `ty` implements given trait(trait_def_id).
+///
+/// NOTE: Always return `false` for a type which needs inference.
+fn type_implements_trait<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    key: (
+        DefId,    // trait_def_id,
+        Ty<'tcx>, // type
+        SubstsRef<'tcx>,
+        ParamEnv<'tcx>,
+    ),
+) -> bool {
+    let (trait_def_id, ty, params, param_env) = key;
+
+    debug!(
+        "type_implements_trait: trait_def_id={:?}, type={:?}, params={:?}, param_env={:?}",
+        trait_def_id, ty, params, param_env
+    );
+
+    // Do not check on infer_types to avoid panic in evaluate_obligation.
+    if ty.has_infer_types() {
+        return false;
+    }
+
+    let ty = tcx.erase_regions(&ty);
+
+    let trait_ref = ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(ty, params) };
+
+    let obligation = Obligation {
+        cause: ObligationCause::dummy(),
+        param_env,
+        recursion_depth: 0,
+        predicate: trait_ref.without_const().to_predicate(),
+    };
+    tcx.infer_ctxt().enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation))
+}
+
 pub fn provide(providers: &mut ty::query::Providers<'_>) {
     object_safety::provide(providers);
     *providers = ty::query::Providers {
@@ -531,6 +570,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
         codegen_fulfill_obligation: codegen::codegen_fulfill_obligation,
         vtable_methods,
         substitute_normalize_and_test_predicates,
+        type_implements_trait,
         ..*providers
     };
 }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 79dde84b8b1..226c187e3cf 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -5282,6 +5282,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expected: Ty<'tcx>,
         found: Ty<'tcx>,
     ) {
+        debug!("suggest_missing_await: expr={:?} expected={:?}, found={:?}", expr, expected, found);
         // `.await` is not permitted outside of `async` bodies, so don't bother to suggest if the
         // body isn't `async`.
         let item_id = self.tcx().hir().get_parent_node(self.body_id);
@@ -5299,22 +5300,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     .next()
                     .unwrap()
                     .def_id;
+                // `<T as Future>::Output`
+                let projection_ty = ty::ProjectionTy {
+                    // `T`
+                    substs: self
+                        .tcx
+                        .mk_substs_trait(found, self.fresh_substs_for_item(sp, item_def_id)),
+                    // `Future::Output`
+                    item_def_id,
+                };
+
                 let predicate =
                     ty::Predicate::Projection(ty::Binder::bind(ty::ProjectionPredicate {
-                        // `<T as Future>::Output`
-                        projection_ty: ty::ProjectionTy {
-                            // `T`
-                            substs: self.tcx.mk_substs_trait(
-                                found,
-                                self.fresh_substs_for_item(sp, item_def_id),
-                            ),
-                            // `Future::Output`
-                            item_def_id,
-                        },
+                        projection_ty,
                         ty: expected,
                     }));
                 let obligation = traits::Obligation::new(self.misc(sp), self.param_env, predicate);
+
                 debug!("suggest_missing_await: trying obligation {:?}", obligation);
+
                 if self.infcx.predicate_may_hold(&obligation) {
                     debug!("suggest_missing_await: obligation held: {:?}", obligation);
                     if let Ok(code) = self.sess().source_map().span_to_snippet(sp) {
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 8bf811877a6..38123816527 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -643,6 +643,15 @@ impl Attributes {
             })
             .collect()
     }
+
+    pub fn get_doc_aliases(&self) -> FxHashSet<String> {
+        self.other_attrs
+            .lists(sym::doc)
+            .filter(|a| a.check_name(sym::alias))
+            .filter_map(|a| a.value_str().map(|s| s.to_string().replace("\"", "")))
+            .filter(|v| !v.is_empty())
+            .collect::<FxHashSet<_>>()
+    }
 }
 
 impl PartialEq for Attributes {
diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs
index 0922c8cdd12..ea65b390527 100644
--- a/src/librustdoc/html/layout.rs
+++ b/src/librustdoc/html/layout.rs
@@ -114,7 +114,6 @@ pub fn render<T: Print, S: Print>(
         window.rootPath = \"{root_path}\";\
         window.currentCrate = \"{krate}\";\
     </script>\
-    <script src=\"{root_path}aliases{suffix}.js\"></script>\
     <script src=\"{static_root_path}main{suffix}.js\"></script>\
     {static_extra_scripts}\
     {extra_scripts}\
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 00c9e46570a..646c663ad9c 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -293,7 +293,12 @@ impl Serialize for IndexItem {
     where
         S: Serializer,
     {
-        assert_eq!(self.parent.is_some(), self.parent_idx.is_some());
+        assert_eq!(
+            self.parent.is_some(),
+            self.parent_idx.is_some(),
+            "`{}` is missing idx",
+            self.name
+        );
 
         (self.ty, &self.name, &self.path, &self.desc, self.parent_idx, &self.search_type)
             .serialize(serializer)
@@ -819,42 +824,6 @@ themePicker.onblur = handleThemeButtonsBlur;
         Ok((ret, krates))
     }
 
-    fn show_item(item: &IndexItem, krate: &str) -> String {
-        format!(
-            "{{'crate':'{}','ty':{},'name':'{}','desc':'{}','p':'{}'{}}}",
-            krate,
-            item.ty as usize,
-            item.name,
-            item.desc.replace("'", "\\'"),
-            item.path,
-            if let Some(p) = item.parent_idx { format!(",'parent':{}", p) } else { String::new() }
-        )
-    }
-
-    let dst = cx.dst.join(&format!("aliases{}.js", cx.shared.resource_suffix));
-    {
-        let (mut all_aliases, _) = try_err!(collect(&dst, &krate.name, "ALIASES"), &dst);
-        let mut output = String::with_capacity(100);
-        for (alias, items) in &cx.cache.aliases {
-            if items.is_empty() {
-                continue;
-            }
-            output.push_str(&format!(
-                "\"{}\":[{}],",
-                alias,
-                items.iter().map(|v| show_item(v, &krate.name)).collect::<Vec<_>>().join(",")
-            ));
-        }
-        all_aliases.push(format!("ALIASES[\"{}\"] = {{{}}};", krate.name, output));
-        all_aliases.sort();
-        let mut v = Buffer::html();
-        writeln!(&mut v, "var ALIASES = {{}};");
-        for aliases in &all_aliases {
-            writeln!(&mut v, "{}", aliases);
-        }
-        cx.shared.fs.write(&dst, v.into_inner().into_bytes())?;
-    }
-
     use std::ffi::OsString;
 
     #[derive(Debug)]
diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs
index 5b090291227..57d385de320 100644
--- a/src/librustdoc/html/render/cache.rs
+++ b/src/librustdoc/html/render/cache.rs
@@ -120,7 +120,7 @@ crate struct Cache {
 
     /// Aliases added through `#[doc(alias = "...")]`. Since a few items can have the same alias,
     /// we need the alias element to have an array of items.
-    pub(super) aliases: FxHashMap<String, Vec<IndexItem>>,
+    pub(super) aliases: BTreeMap<String, Vec<usize>>,
 }
 
 impl Cache {
@@ -311,7 +311,7 @@ impl DocFolder for Cache {
             };
 
             match parent {
-                (parent, Some(path)) if is_inherent_impl_item || (!self.stripped_mod) => {
+                (parent, Some(path)) if is_inherent_impl_item || !self.stripped_mod => {
                     debug_assert!(!item.is_stripped());
 
                     // A crate has a module at its root, containing all items,
@@ -327,6 +327,13 @@ impl DocFolder for Cache {
                             parent_idx: None,
                             search_type: get_index_search_type(&item),
                         });
+
+                        for alias in item.attrs.get_doc_aliases() {
+                            self.aliases
+                                .entry(alias.to_lowercase())
+                                .or_insert(Vec::new())
+                                .push(self.search_index.len() - 1);
+                        }
                     }
                 }
                 (Some(parent), None) if is_inherent_impl_item => {
@@ -376,11 +383,8 @@ impl DocFolder for Cache {
                 {
                     self.paths.insert(item.def_id, (self.stack.clone(), item.type_()));
                 }
-                self.add_aliases(&item);
             }
-
             clean::PrimitiveItem(..) => {
-                self.add_aliases(&item);
                 self.paths.insert(item.def_id, (self.stack.clone(), item.type_()));
             }
 
@@ -488,40 +492,6 @@ impl DocFolder for Cache {
     }
 }
 
-impl Cache {
-    fn add_aliases(&mut self, item: &clean::Item) {
-        if item.def_id.index == CRATE_DEF_INDEX {
-            return;
-        }
-        if let Some(ref item_name) = item.name {
-            let path = self
-                .paths
-                .get(&item.def_id)
-                .map(|p| p.0[..p.0.len() - 1].join("::"))
-                .unwrap_or("std".to_owned());
-            for alias in item
-                .attrs
-                .lists(sym::doc)
-                .filter(|a| a.check_name(sym::alias))
-                .filter_map(|a| a.value_str().map(|s| s.to_string().replace("\"", "")))
-                .filter(|v| !v.is_empty())
-                .collect::<FxHashSet<_>>()
-                .into_iter()
-            {
-                self.aliases.entry(alias).or_insert(Vec::with_capacity(1)).push(IndexItem {
-                    ty: item.type_(),
-                    name: item_name.to_string(),
-                    path: path.clone(),
-                    desc: shorten(plain_summary_line(item.doc_value())),
-                    parent: None,
-                    parent_idx: None,
-                    search_type: get_index_search_type(&item),
-                });
-            }
-        }
-    }
-}
-
 /// Attempts to find where an external crate is located, given that we're
 /// rendering in to the specified source destination.
 fn extern_location(
@@ -567,7 +537,8 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String {
     let mut crate_items = Vec::with_capacity(cache.search_index.len());
     let mut crate_paths = vec![];
 
-    let Cache { ref mut search_index, ref orphan_impl_items, ref paths, .. } = *cache;
+    let Cache { ref mut search_index, ref orphan_impl_items, ref paths, ref mut aliases, .. } =
+        *cache;
 
     // Attach all orphan items to the type's definition if the type
     // has since been learned.
@@ -582,6 +553,12 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String {
                 parent_idx: None,
                 search_type: get_index_search_type(&item),
             });
+            for alias in item.attrs.get_doc_aliases() {
+                aliases
+                    .entry(alias.to_lowercase())
+                    .or_insert(Vec::new())
+                    .push(search_index.len() - 1);
+            }
         }
     }
 
@@ -630,6 +607,12 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String {
         items: Vec<&'a IndexItem>,
         #[serde(rename = "p")]
         paths: Vec<(ItemType, String)>,
+        // The String is alias name and the vec is the list of the elements with this alias.
+        //
+        // To be noted: the `usize` elements are indexes to `items`.
+        #[serde(rename = "a")]
+        #[serde(skip_serializing_if = "BTreeMap::is_empty")]
+        aliases: &'a BTreeMap<String, Vec<usize>>,
     }
 
     // Collect the index into a string
@@ -640,6 +623,7 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String {
             doc: crate_doc,
             items: crate_items,
             paths: crate_paths,
+            aliases,
         })
         .expect("failed serde conversion")
         // All these `replace` calls are because we have to go through JS string for JSON content.
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js
index a023d5a2d95..9b498d66249 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -531,6 +531,7 @@ function getSearchElement() {
         var OUTPUT_DATA = 1;
         var NO_TYPE_FILTER = -1;
         var currentResults, index, searchIndex;
+        var ALIASES = {};
         var params = getQueryStringParams();
 
         // Populate search bar with query string search term when provided,
@@ -963,6 +964,72 @@ function getSearchElement() {
                 return itemTypes[ty.ty] + ty.path + ty.name;
             }
 
+            function createAliasFromItem(item) {
+                return {
+                    crate: item.crate,
+                    name: item.name,
+                    path: item.path,
+                    desc: item.desc,
+                    ty: item.ty,
+                    parent: item.parent,
+                    type: item.type,
+                    is_alias: true,
+                };
+            }
+
+            function handleAliases(ret, query, filterCrates) {
+                // We separate aliases and crate aliases because we want to have current crate
+                // aliases to be before the others in the displayed results.
+                var aliases = [];
+                var crateAliases = [];
+                var i;
+                if (filterCrates !== undefined &&
+                        ALIASES[filterCrates] &&
+                        ALIASES[filterCrates][query.search]) {
+                    for (i = 0; i < ALIASES[crate][query.search].length; ++i) {
+                        aliases.push(
+                            createAliasFromItem(searchIndex[ALIASES[filterCrates][query.search]]));
+                    }
+                } else {
+                    Object.keys(ALIASES).forEach(function(crate) {
+                        if (ALIASES[crate][query.search]) {
+                            var pushTo = crate === window.currentCrate ? crateAliases : aliases;
+                            for (i = 0; i < ALIASES[crate][query.search].length; ++i) {
+                                pushTo.push(
+                                    createAliasFromItem(
+                                        searchIndex[ALIASES[crate][query.search][i]]));
+                            }
+                        }
+                    });
+                }
+
+                var sortFunc = function(aaa, bbb) {
+                    if (aaa.path < bbb.path) {
+                        return 1;
+                    } else if (aaa.path === bbb.path) {
+                        return 0;
+                    }
+                    return -1;
+                };
+                crateAliases.sort(sortFunc);
+                aliases.sort(sortFunc);
+
+                var pushFunc = function(alias) {
+                    alias.alias = query.raw;
+                    var res = buildHrefAndPath(alias);
+                    alias.displayPath = pathSplitter(res[0]);
+                    alias.fullPath = alias.displayPath + alias.name;
+                    alias.href = res[1];
+
+                    ret.others.unshift(alias);
+                    if (ret.others.length > MAX_RESULTS) {
+                        ret.others.pop();
+                    }
+                };
+                onEach(aliases, pushFunc);
+                onEach(crateAliases, pushFunc);
+            }
+
             // quoted values mean literal search
             var nSearchWords = searchWords.length;
             var i;
@@ -1190,23 +1257,7 @@ function getSearchElement() {
                 "returned": sortResults(results_returned, true),
                 "others": sortResults(results),
             };
-            if (ALIASES && ALIASES[window.currentCrate] &&
-                    ALIASES[window.currentCrate][query.raw]) {
-                var aliases = ALIASES[window.currentCrate][query.raw];
-                for (i = 0; i < aliases.length; ++i) {
-                    aliases[i].is_alias = true;
-                    aliases[i].alias = query.raw;
-                    aliases[i].path = aliases[i].p;
-                    var res = buildHrefAndPath(aliases[i]);
-                    aliases[i].displayPath = pathSplitter(res[0]);
-                    aliases[i].fullPath = aliases[i].displayPath + aliases[i].name;
-                    aliases[i].href = res[1];
-                    ret.others.unshift(aliases[i]);
-                    if (ret.others.length > MAX_RESULTS) {
-                        ret.others.pop();
-                    }
-                }
-            }
+            handleAliases(ret, query, filterCrates);
             return ret;
         }
 
@@ -1599,13 +1650,12 @@ function getSearchElement() {
                     "returned": mergeArrays(results.returned),
                     "others": mergeArrays(results.others),
                 };
-            } else {
-                return {
-                    "in_args": results.in_args[0],
-                    "returned": results.returned[0],
-                    "others": results.others[0],
-                };
             }
+            return {
+                "in_args": results.in_args[0],
+                "returned": results.returned[0],
+                "others": results.others[0],
+            };
         }
 
         function getFilterCrates() {
@@ -1656,10 +1706,13 @@ function getSearchElement() {
             searchIndex = [];
             var searchWords = [];
             var i;
+            var currentIndex = 0;
 
             for (var crate in rawSearchIndex) {
                 if (!rawSearchIndex.hasOwnProperty(crate)) { continue; }
 
+                var crateSize = 0;
+
                 searchWords.push(crate);
                 searchIndex.push({
                     crate: crate,
@@ -1669,6 +1722,7 @@ function getSearchElement() {
                     desc: rawSearchIndex[crate].doc,
                     type: null,
                 });
+                currentIndex += 1;
 
                 // an array of [(Number) item type,
                 //              (String) name,
@@ -1680,6 +1734,9 @@ function getSearchElement() {
                 // an array of [(Number) item type,
                 //              (String) name]
                 var paths = rawSearchIndex[crate].p;
+                // a array of [(String) alias name
+                //             [Number] index to items]
+                var aliases = rawSearchIndex[crate].a;
 
                 // convert `rawPaths` entries into object form
                 var len = paths.length;
@@ -1698,9 +1755,18 @@ function getSearchElement() {
                 var lastPath = "";
                 for (i = 0; i < len; ++i) {
                     var rawRow = items[i];
-                    var row = {crate: crate, ty: rawRow[0], name: rawRow[1],
-                               path: rawRow[2] || lastPath, desc: rawRow[3],
-                               parent: paths[rawRow[4]], type: rawRow[5]};
+                    if (!rawRow[2]) {
+                        rawRow[2] = lastPath;
+                    }
+                    var row = {
+                        crate: crate,
+                        ty: rawRow[0],
+                        name: rawRow[1],
+                        path: rawRow[2],
+                        desc: rawRow[3],
+                        parent: paths[rawRow[4]],
+                        type: rawRow[5],
+                    };
                     searchIndex.push(row);
                     if (typeof row.name === "string") {
                         var word = row.name.toLowerCase();
@@ -1709,7 +1775,25 @@ function getSearchElement() {
                         searchWords.push("");
                     }
                     lastPath = row.path;
+                    crateSize += 1;
+                }
+
+                if (aliases) {
+                    ALIASES[crate] = {};
+                    var j, local_aliases;
+                    for (var alias_name in aliases) {
+                        if (!aliases.hasOwnProperty(alias_name)) { continue; }
+
+                        if (!ALIASES[crate].hasOwnProperty(alias_name)) {
+                            ALIASES[crate][alias_name] = [];
+                        }
+                        local_aliases = aliases[alias_name];
+                        for (j = 0; j < local_aliases.length; ++j) {
+                            ALIASES[crate][alias_name].push(local_aliases[j] + currentIndex);
+                        }
+                    }
                 }
+                currentIndex += crateSize;
             }
             return searchWords;
         }
diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs
index e6da7426eb4..56cf9be3391 100644
--- a/src/libstd/collections/hash/map.rs
+++ b/src/libstd/collections/hash/map.rs
@@ -251,6 +251,9 @@ impl<K, V, S> HashMap<K, V, S> {
     /// cause many collisions and very poor performance. Setting it
     /// manually using this function can expose a DoS attack vector.
     ///
+    /// The `hash_builder` passed should implement the [`BuildHasher`] trait for
+    /// the HashMap to be useful, see its documentation for details.
+    ///
     /// # Examples
     ///
     /// ```
@@ -261,6 +264,8 @@ impl<K, V, S> HashMap<K, V, S> {
     /// let mut map = HashMap::with_hasher(s);
     /// map.insert(1, 2);
     /// ```
+    ///
+    /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html
     #[inline]
     #[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
     pub fn with_hasher(hash_builder: S) -> HashMap<K, V, S> {
@@ -278,6 +283,9 @@ impl<K, V, S> HashMap<K, V, S> {
     /// cause many collisions and very poor performance. Setting it
     /// manually using this function can expose a DoS attack vector.
     ///
+    /// The `hash_builder` passed should implement the [`BuildHasher`] trait for
+    /// the HashMap to be useful, see its documentation for details.
+    ///
     /// # Examples
     ///
     /// ```
@@ -288,6 +296,8 @@ impl<K, V, S> HashMap<K, V, S> {
     /// let mut map = HashMap::with_capacity_and_hasher(10, s);
     /// map.insert(1, 2);
     /// ```
+    ///
+    /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html
     #[inline]
     #[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
     pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> HashMap<K, V, S> {
diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs
index c1a57f2ce61..ca06457291c 100644
--- a/src/libstd/collections/hash/set.rs
+++ b/src/libstd/collections/hash/set.rs
@@ -273,6 +273,9 @@ impl<T, S> HashSet<T, S> {
     /// cause many collisions and very poor performance. Setting it
     /// manually using this function can expose a DoS attack vector.
     ///
+    /// The `hash_builder` passed should implement the [`BuildHasher`] trait for
+    /// the HashMap to be useful, see its documentation for details.
+    ///
     /// # Examples
     ///
     /// ```
@@ -283,6 +286,8 @@ impl<T, S> HashSet<T, S> {
     /// let mut set = HashSet::with_hasher(s);
     /// set.insert(2);
     /// ```
+    ///
+    /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html
     #[inline]
     #[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
     pub fn with_hasher(hasher: S) -> HashSet<T, S> {
@@ -300,6 +305,9 @@ impl<T, S> HashSet<T, S> {
     /// cause many collisions and very poor performance. Setting it
     /// manually using this function can expose a DoS attack vector.
     ///
+    /// The `hash_builder` passed should implement the [`BuildHasher`] trait for
+    /// the HashMap to be useful, see its documentation for details.
+    ///
     /// # Examples
     ///
     /// ```
@@ -310,6 +318,8 @@ impl<T, S> HashSet<T, S> {
     /// let mut set = HashSet::with_capacity_and_hasher(10, s);
     /// set.insert(1);
     /// ```
+    ///
+    /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html
     #[inline]
     #[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
     pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> HashSet<T, S> {
diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs
index 4fde3316973..7a05aaf71f2 100644
--- a/src/libstd/ffi/os_str.rs
+++ b/src/libstd/ffi/os_str.rs
@@ -4,6 +4,7 @@ use crate::fmt;
 use crate::hash::{Hash, Hasher};
 use crate::ops;
 use crate::rc::Rc;
+use crate::str::FromStr;
 use crate::sync::Arc;
 
 use crate::sys::os_str::{Buf, Slice};
@@ -1174,6 +1175,15 @@ impl AsInner<Slice> for OsStr {
     }
 }
 
+#[stable(feature = "osstring_from_str", since = "1.45.0")]
+impl FromStr for OsString {
+    type Err = core::convert::Infallible;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        Ok(OsString::from(s))
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
diff --git a/src/test/mir-opt/const_prop/mutable_variable/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable/rustc.main.ConstProp.diff
index c6c5b0cf726..187c1745435 100644
--- a/src/test/mir-opt/const_prop/mutable_variable/rustc.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/mutable_variable/rustc.main.ConstProp.diff
@@ -26,8 +26,7 @@
                                            // + ty: i32
                                            // + val: Value(Scalar(0x00000063))
                                            // mir::Constant
--                                          // + span: $DIR/mutable_variable.rs:6:9: 6:11
-+                                          // + span: $DIR/mutable_variable.rs:6:5: 6:11
+                                           // + span: $DIR/mutable_variable.rs:6:9: 6:11
                                            // + literal: Const { ty: i32, val: Value(Scalar(0x00000063)) }
           StorageLive(_2);                 // scope 1 at $DIR/mutable_variable.rs:7:9: 7:10
 -         _2 = _1;                         // scope 1 at $DIR/mutable_variable.rs:7:13: 7:14
diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_aggregate/rustc.main.ConstProp.diff
index 26f0250d94c..cf432b2acc1 100644
--- a/src/test/mir-opt/const_prop/mutable_variable_aggregate/rustc.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate/rustc.main.ConstProp.diff
@@ -34,8 +34,7 @@
                                            // + ty: i32
                                            // + val: Value(Scalar(0x00000063))
                                            // mir::Constant
--                                          // + span: $DIR/mutable_variable_aggregate.rs:6:11: 6:13
-+                                          // + span: $DIR/mutable_variable_aggregate.rs:6:5: 6:13
+                                           // + span: $DIR/mutable_variable_aggregate.rs:6:11: 6:13
                                            // + literal: Const { ty: i32, val: Value(Scalar(0x00000063)) }
           StorageLive(_2);                 // scope 1 at $DIR/mutable_variable_aggregate.rs:7:9: 7:10
 -         _2 = _1;                         // scope 1 at $DIR/mutable_variable_aggregate.rs:7:13: 7:14
diff --git a/src/test/mir-opt/copy_propagation_arg/rustc.arg_src.CopyPropagation.diff b/src/test/mir-opt/copy_propagation_arg/rustc.arg_src.CopyPropagation.diff
index b976449ca6d..1e0271a560f 100644
--- a/src/test/mir-opt/copy_propagation_arg/rustc.arg_src.CopyPropagation.diff
+++ b/src/test/mir-opt/copy_propagation_arg/rustc.arg_src.CopyPropagation.diff
@@ -17,7 +17,7 @@
                                            // + ty: i32
                                            // + val: Value(Scalar(0x0000007b))
                                            // mir::Constant
-                                           // + span: $DIR/copy_propagation_arg.rs:29:5: 29:12
+                                           // + span: $DIR/copy_propagation_arg.rs:29:9: 29:12
                                            // + literal: Const { ty: i32, val: Value(Scalar(0x0000007b)) }
           _0 = _2;                         // scope 1 at $DIR/copy_propagation_arg.rs:30:5: 30:6
           StorageDead(_2);                 // scope 0 at $DIR/copy_propagation_arg.rs:31:1: 31:2
diff --git a/src/test/mir-opt/copy_propagation_arg/rustc.bar.CopyPropagation.diff b/src/test/mir-opt/copy_propagation_arg/rustc.bar.CopyPropagation.diff
index 26f8068f674..b875bbea67b 100644
--- a/src/test/mir-opt/copy_propagation_arg/rustc.bar.CopyPropagation.diff
+++ b/src/test/mir-opt/copy_propagation_arg/rustc.bar.CopyPropagation.diff
@@ -28,7 +28,7 @@
                                            // + ty: u8
                                            // + val: Value(Scalar(0x05))
                                            // mir::Constant
-                                           // + span: $DIR/copy_propagation_arg.rs:17:5: 17:10
+                                           // + span: $DIR/copy_propagation_arg.rs:17:9: 17:10
                                            // + literal: Const { ty: u8, val: Value(Scalar(0x05)) }
           _0 = const ();                   // scope 0 at $DIR/copy_propagation_arg.rs:15:19: 18:2
                                            // ty::Const
diff --git a/src/test/rustdoc-js-std/alias-2.js b/src/test/rustdoc-js-std/alias-2.js
index f3c6713692b..798fa29efbd 100644
--- a/src/test/rustdoc-js-std/alias-2.js
+++ b/src/test/rustdoc-js-std/alias-2.js
@@ -1,10 +1,10 @@
-// ignore-order
-
 const QUERY = '+';
 
 const EXPECTED = {
     'others': [
         { 'path': 'std::ops', 'name': 'AddAssign' },
         { 'path': 'std::ops', 'name': 'Add' },
+        { 'path': 'core::ops', 'name': 'AddAssign' },
+        { 'path': 'core::ops', 'name': 'Add' },
     ],
 };
diff --git a/src/test/rustdoc-js/doc-alias.js b/src/test/rustdoc-js/doc-alias.js
new file mode 100644
index 00000000000..896808d4157
--- /dev/null
+++ b/src/test/rustdoc-js/doc-alias.js
@@ -0,0 +1,263 @@
+// exact-check
+
+const QUERY = [
+    'StructItem',
+    'StructFieldItem',
+    'StructMethodItem',
+    'ImplTraitItem',
+    'ImplAssociatedConstItem',
+    'ImplTraitFunction',
+    'EnumItem',
+    'VariantItem',
+    'EnumMethodItem',
+    'TypedefItem',
+    'TraitItem',
+    'TraitTypeItem',
+    'AssociatedConstItem',
+    'TraitFunctionItem',
+    'FunctionItem',
+    'ModuleItem',
+    'ConstItem',
+    'StaticItem',
+    'UnionItem',
+    'UnionFieldItem',
+    'UnionMethodItem',
+    'MacroItem',
+];
+
+const EXPECTED = [
+    {
+        'others': [
+            {
+                'path': 'doc_alias',
+                'name': 'Struct',
+                'alias': 'StructItem',
+                'href': '../doc_alias/struct.Struct.html',
+                'is_alias': true
+            },
+        ],
+    },
+    {
+        'others': [
+            {
+                'path': 'doc_alias::Struct',
+                'name': 'field',
+                'alias': 'StructFieldItem',
+                'href': '../doc_alias/struct.Struct.html#structfield.field',
+                'is_alias': true
+            },
+        ],
+    },
+    {
+        'others': [
+            {
+                'path': 'doc_alias::Struct',
+                'name': 'method',
+                'alias': 'StructMethodItem',
+                'href': '../doc_alias/struct.Struct.html#method.method',
+                'is_alias': true
+            },
+        ],
+    },
+    {
+        // ImplTraitItem
+        'others': [],
+    },
+    {
+        // ImplAssociatedConstItem
+        'others': [],
+    },
+    {
+        'others': [
+            {
+                'path': 'doc_alias::Struct',
+                'name': 'function',
+                'alias': 'ImplTraitFunction',
+                'href': '../doc_alias/struct.Struct.html#method.function',
+                'is_alias': true
+            },
+        ],
+    },
+    {
+        'others': [
+            {
+                'path': 'doc_alias',
+                'name': 'Enum',
+                'alias': 'EnumItem',
+                'href': '../doc_alias/enum.Enum.html',
+                'is_alias': true
+            },
+        ],
+    },
+    {
+        'others': [
+            {
+                'path': 'doc_alias::Enum',
+                'name': 'Variant',
+                'alias': 'VariantItem',
+                'href': '../doc_alias/enum.Enum.html#variant.Variant',
+                'is_alias': true
+            },
+        ],
+    },
+    {
+        'others': [
+            {
+                'path': 'doc_alias::Enum',
+                'name': 'method',
+                'alias': 'EnumMethodItem',
+                'href': '../doc_alias/enum.Enum.html#method.method',
+                'is_alias': true
+            },
+        ],
+    },
+    {
+        'others': [
+            {
+                'path': 'doc_alias',
+                'name': 'Typedef',
+                'alias': 'TypedefItem',
+                'href': '../doc_alias/type.Typedef.html',
+                'is_alias': true
+            },
+        ],
+    },
+    {
+        'others': [
+            {
+                'path': 'doc_alias',
+                'name': 'Trait',
+                'alias': 'TraitItem',
+                'href': '../doc_alias/trait.Trait.html',
+                'is_alias': true
+            },
+        ],
+    },
+    {
+        'others': [
+            {
+                'path': 'doc_alias::Trait',
+                'name': 'Target',
+                'alias': 'TraitTypeItem',
+                'href': '../doc_alias/trait.Trait.html#associatedtype.Target',
+                'is_alias': true
+            },
+        ],
+    },
+    {
+        'others': [
+            {
+                'path': 'doc_alias::Trait',
+                'name': 'AssociatedConst',
+                'alias': 'AssociatedConstItem',
+                'href': '../doc_alias/trait.Trait.html#associatedconstant.AssociatedConst',
+                'is_alias': true
+            },
+        ],
+    },
+    {
+        'others': [
+            {
+                'path': 'doc_alias::Trait',
+                'name': 'function',
+                'alias': 'TraitFunctionItem',
+                'href': '../doc_alias/trait.Trait.html#tymethod.function',
+                'is_alias': true
+            },
+        ],
+    },
+    {
+        'others': [
+            {
+                'path': 'doc_alias',
+                'name': 'function',
+                'alias': 'FunctionItem',
+                'href': '../doc_alias/fn.function.html',
+                'is_alias': true
+            },
+        ],
+    },
+    {
+        'others': [
+            {
+                'path': 'doc_alias',
+                'name': 'Module',
+                'alias': 'ModuleItem',
+                'href': '../doc_alias/Module/index.html',
+                'is_alias': true
+            },
+        ],
+    },
+    {
+        'others': [
+            {
+                'path': 'doc_alias',
+                'name': 'Const',
+                'alias': 'ConstItem',
+                'href': '../doc_alias/constant.Const.html',
+                'is_alias': true
+            },
+        ],
+    },
+    {
+        'others': [
+            {
+                'path': 'doc_alias',
+                'name': 'Static',
+                'alias': 'StaticItem',
+                'href': '../doc_alias/static.Static.html',
+                'is_alias': true
+            },
+        ],
+    },
+    {
+        'others': [
+            {
+                'path': 'doc_alias',
+                'name': 'Union',
+                'alias': 'UnionItem',
+                'href': '../doc_alias/union.Union.html',
+                'is_alias': true
+            },
+            // Not an alias!
+            {
+                'path': 'doc_alias::Union',
+                'name': 'union_item',
+                'href': '../doc_alias/union.Union.html#structfield.union_item'
+            },
+        ],
+    },
+    {
+        'others': [
+            {
+                'path': 'doc_alias::Union',
+                'name': 'union_item',
+                'alias': 'UnionFieldItem',
+                'href': '../doc_alias/union.Union.html#structfield.union_item',
+                'is_alias': true
+            },
+        ],
+    },
+    {
+        'others': [
+            {
+                'path': 'doc_alias::Union',
+                'name': 'method',
+                'alias': 'UnionMethodItem',
+                'href': '../doc_alias/union.Union.html#method.method',
+                'is_alias': true
+            },
+        ],
+    },
+    {
+        'others': [
+            {
+                'path': 'doc_alias',
+                'name': 'Macro',
+                'alias': 'MacroItem',
+                'href': '../doc_alias/macro.Macro.html',
+                'is_alias': true
+            },
+        ],
+    },
+];
diff --git a/src/test/rustdoc-js/doc-alias.rs b/src/test/rustdoc-js/doc-alias.rs
new file mode 100644
index 00000000000..84c638a1995
--- /dev/null
+++ b/src/test/rustdoc-js/doc-alias.rs
@@ -0,0 +1,79 @@
+#![feature(doc_alias)]
+
+#[doc(alias = "StructItem")]
+pub struct Struct {
+    #[doc(alias = "StructFieldItem")]
+    pub field: u32,
+}
+
+impl Struct {
+    #[doc(alias = "StructMethodItem")]
+    pub fn method(&self) {}
+}
+
+impl Trait for Struct {
+    // Shouldn't be listed in aliases!
+    #[doc(alias = "ImplTraitItem")]
+    type Target = u32;
+    // Shouldn't be listed in aliases!
+    #[doc(alias = "ImplAssociatedConstItem")]
+    const AssociatedConst: i32 = 12;
+
+    #[doc(alias = "ImplTraitFunction")]
+    fn function() -> Self::Target { 0 }
+}
+
+#[doc(alias = "EnumItem")]
+pub enum Enum {
+    #[doc(alias = "VariantItem")]
+    Variant,
+}
+
+impl Enum {
+    #[doc(alias = "EnumMethodItem")]
+    pub fn method(&self) {}
+}
+
+#[doc(alias = "TypedefItem")]
+pub type Typedef = i32;
+
+#[doc(alias = "TraitItem")]
+pub trait Trait {
+    #[doc(alias = "TraitTypeItem")]
+    type Target;
+    #[doc(alias = "AssociatedConstItem")]
+    const AssociatedConst: i32;
+
+    #[doc(alias = "TraitFunctionItem")]
+    fn function() -> Self::Target;
+}
+
+#[doc(alias = "FunctionItem")]
+pub fn function() {}
+
+#[doc(alias = "ModuleItem")]
+pub mod Module {}
+
+#[doc(alias = "ConstItem")]
+pub const Const: u32 = 0;
+
+#[doc(alias = "StaticItem")]
+pub static Static: u32 = 0;
+
+#[doc(alias = "UnionItem")]
+pub union Union {
+    #[doc(alias = "UnionFieldItem")]
+    pub union_item: u32,
+    pub y: f32,
+}
+
+impl Union {
+    #[doc(alias = "UnionMethodItem")]
+    pub fn method(&self) {}
+}
+
+#[doc(alias = "MacroItem")]
+#[macro_export]
+macro_rules! Macro {
+    () => {}
+}
diff --git a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr
index 61f2570b2ff..96158fc0e04 100644
--- a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr
+++ b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr
@@ -237,7 +237,10 @@ error[E0277]: the `?` operator can only be applied to values that implement `std
   --> $DIR/incorrect-syntax-suggestions.rs:16:19
    |
 LL |     let _ = await bar()?;
-   |                   ^^^^^^ the `?` operator cannot be applied to type `impl std::future::Future`
+   |                   ^^^^^^
+   |                   |
+   |                   the `?` operator cannot be applied to type `impl std::future::Future`
+   |                   help: consider using `.await` here: `bar().await?`
    |
    = help: the trait `std::ops::Try` is not implemented for `impl std::future::Future`
    = note: required by `std::ops::Try::into_result`
diff --git a/src/test/ui/async-await/issue-61076.rs b/src/test/ui/async-await/issue-61076.rs
new file mode 100644
index 00000000000..13b45df64ea
--- /dev/null
+++ b/src/test/ui/async-await/issue-61076.rs
@@ -0,0 +1,32 @@
+// edition:2018
+
+use core::future::Future;
+use core::pin::Pin;
+use core::task::{Context, Poll};
+
+struct T;
+
+impl Future for T {
+    type Output = Result<(), ()>;
+
+    fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Self::Output> {
+        Poll::Pending
+    }
+}
+
+async fn foo() -> Result<(), ()> {
+    Ok(())
+}
+
+async fn bar() -> Result<(), ()> {
+    foo()?; //~ ERROR the `?` operator can only be applied to values that implement `std::ops::Try`
+    Ok(())
+}
+
+async fn baz() -> Result<(), ()> {
+    let t = T;
+    t?; //~ ERROR the `?` operator can only be applied to values that implement `std::ops::Try`
+    Ok(())
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/issue-61076.stderr b/src/test/ui/async-await/issue-61076.stderr
new file mode 100644
index 00000000000..e71f4e7136d
--- /dev/null
+++ b/src/test/ui/async-await/issue-61076.stderr
@@ -0,0 +1,27 @@
+error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try`
+  --> $DIR/issue-61076.rs:22:5
+   |
+LL |     foo()?;
+   |     ^^^^^^
+   |     |
+   |     the `?` operator cannot be applied to type `impl std::future::Future`
+   |     help: consider using `.await` here: `foo().await?`
+   |
+   = help: the trait `std::ops::Try` is not implemented for `impl std::future::Future`
+   = note: required by `std::ops::Try::into_result`
+
+error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try`
+  --> $DIR/issue-61076.rs:28:5
+   |
+LL |     t?;
+   |     ^^
+   |     |
+   |     the `?` operator cannot be applied to type `T`
+   |     help: consider using `.await` here: `t.await?`
+   |
+   = help: the trait `std::ops::Try` is not implemented for `T`
+   = note: required by `std::ops::Try::into_result`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/async-await/try-on-option-in-async.rs b/src/test/ui/async-await/try-on-option-in-async.rs
index 51ac522017c..c520a07abc1 100644
--- a/src/test/ui/async-await/try-on-option-in-async.rs
+++ b/src/test/ui/async-await/try-on-option-in-async.rs
@@ -7,7 +7,8 @@ async fn an_async_block() -> u32 {
         let x: Option<u32> = None;
         x?; //~ ERROR the `?` operator
         22
-    }.await
+    }
+    .await
 }
 
 async fn async_closure_containing_fn() -> u32 {
diff --git a/src/test/ui/async-await/try-on-option-in-async.stderr b/src/test/ui/async-await/try-on-option-in-async.stderr
index 46f8f41076b..700296d6747 100644
--- a/src/test/ui/async-await/try-on-option-in-async.stderr
+++ b/src/test/ui/async-await/try-on-option-in-async.stderr
@@ -7,14 +7,14 @@ LL | |         let x: Option<u32> = None;
 LL | |         x?;
    | |         ^^ cannot use the `?` operator in an async block that returns `{integer}`
 LL | |         22
-LL | |     }.await
+LL | |     }
    | |_____- this function should return `Result` or `Option` to accept `?`
    |
    = help: the trait `std::ops::Try` is not implemented for `{integer}`
    = note: required by `std::ops::Try::from_error`
 
 error[E0277]: the `?` operator can only be used in an async closure that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
-  --> $DIR/try-on-option-in-async.rs:16:9
+  --> $DIR/try-on-option-in-async.rs:17:9
    |
 LL |       let async_closure = async || {
    |  __________________________________-
@@ -29,7 +29,7 @@ LL | |     };
    = note: required by `std::ops::Try::from_error`
 
 error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
-  --> $DIR/try-on-option-in-async.rs:25:5
+  --> $DIR/try-on-option-in-async.rs:26:5
    |
 LL |   async fn an_async_function() -> u32 {
    |  _____________________________________-
diff --git a/src/test/ui/consts/miri_unleashed/ptr_arith.rs b/src/test/ui/consts/miri_unleashed/ptr_arith.rs
new file mode 100644
index 00000000000..81985f9f625
--- /dev/null
+++ b/src/test/ui/consts/miri_unleashed/ptr_arith.rs
@@ -0,0 +1,29 @@
+// compile-flags: -Zunleash-the-miri-inside-of-you
+#![feature(core_intrinsics)]
+#![allow(const_err)]
+
+// A test demonstrating that we prevent doing even trivial
+// pointer arithmetic or comparison during CTFE.
+
+static CMP: () = {
+    let x = &0 as *const _;
+    let _v = x == x;
+    //~^ ERROR could not evaluate static initializer
+    //~| NOTE pointer arithmetic or comparison
+};
+
+static INT_PTR_ARITH: () = unsafe {
+    let x: usize = std::mem::transmute(&0);
+    let _v = x + 0;
+    //~^ ERROR could not evaluate static initializer
+    //~| NOTE pointer-to-integer cast
+};
+
+static PTR_ARITH: () = unsafe {
+    let x = &0 as *const _;
+    let _v = core::intrinsics::offset(x, 0);
+    //~^ ERROR could not evaluate static initializer
+    //~| NOTE calling intrinsic `offset`
+};
+
+fn main() {}
diff --git a/src/test/ui/consts/miri_unleashed/ptr_arith.stderr b/src/test/ui/consts/miri_unleashed/ptr_arith.stderr
new file mode 100644
index 00000000000..5bd534a16b8
--- /dev/null
+++ b/src/test/ui/consts/miri_unleashed/ptr_arith.stderr
@@ -0,0 +1,39 @@
+error[E0080]: could not evaluate static initializer
+  --> $DIR/ptr_arith.rs:10:14
+   |
+LL |     let _v = x == x;
+   |              ^^^^^^ "pointer arithmetic or comparison" needs an rfc before being allowed inside constants
+
+error[E0080]: could not evaluate static initializer
+  --> $DIR/ptr_arith.rs:17:14
+   |
+LL |     let _v = x + 0;
+   |              ^^^^^ "pointer-to-integer cast" needs an rfc before being allowed inside constants
+
+error[E0080]: could not evaluate static initializer
+  --> $DIR/ptr_arith.rs:24:14
+   |
+LL |     let _v = core::intrinsics::offset(x, 0);
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ "calling intrinsic `offset`" needs an rfc before being allowed inside constants
+
+warning: skipping const checks
+   |
+help: skipping check for `const_compare_raw_pointers` feature
+  --> $DIR/ptr_arith.rs:10:14
+   |
+LL |     let _v = x == x;
+   |              ^^^^^^
+help: skipping check that does not even have a feature gate
+  --> $DIR/ptr_arith.rs:16:20
+   |
+LL |     let x: usize = std::mem::transmute(&0);
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^
+help: skipping check that does not even have a feature gate
+  --> $DIR/ptr_arith.rs:24:14
+   |
+LL |     let _v = core::intrinsics::offset(x, 0);
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs
index 3b8ef18bfab..438a9f42ccd 100644
--- a/src/tools/clippy/clippy_lints/src/utils/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs
@@ -40,15 +40,12 @@ use rustc_hir::{
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, Level, Lint, LintContext};
 use rustc_middle::hir::map::Map;
-use rustc_middle::traits;
 use rustc_middle::ty::{self, layout::IntegerExt, subst::GenericArg, Binder, Ty, TyCtxt, TypeFoldable};
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::source_map::original_sp;
 use rustc_span::symbol::{self, kw, Symbol};
 use rustc_span::{BytePos, Pos, Span, DUMMY_SP};
 use rustc_target::abi::Integer;
-use rustc_trait_selection::traits::predicate_for_trait_def;
-use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use rustc_trait_selection::traits::query::normalize::AtExt;
 use smallvec::SmallVec;
 
@@ -326,19 +323,8 @@ pub fn implements_trait<'a, 'tcx>(
     trait_id: DefId,
     ty_params: &[GenericArg<'tcx>],
 ) -> bool {
-    let ty = cx.tcx.erase_regions(&ty);
-    let obligation = predicate_for_trait_def(
-        cx.tcx,
-        cx.param_env,
-        traits::ObligationCause::dummy(),
-        trait_id,
-        0,
-        ty,
-        ty_params,
-    );
-    cx.tcx
-        .infer_ctxt()
-        .enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation))
+    let ty_params = cx.tcx.mk_substs(ty_params.iter());
+    cx.tcx.type_implements_trait((trait_id, ty, ty_params, cx.param_env))
 }
 
 /// Gets the `hir::TraitRef` of the trait the given method is implemented for.
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index 2c699998ea9..1ce0300f239 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -296,7 +296,7 @@ pub fn main() {
     rustc_driver::init_rustc_env_logger();
     lazy_static::initialize(&ICE_HOOK);
     exit(
-        rustc_driver::catch_fatal_errors(move || {
+        rustc_driver::catch_with_exit_code(move || {
             let mut orig_args: Vec<String> = env::args().collect();
 
             if orig_args.iter().any(|a| a == "--version" || a == "-V") {
@@ -411,7 +411,5 @@ pub fn main() {
                 if clippy_enabled { &mut clippy } else { &mut default };
             rustc_driver::run_compiler(&args, callbacks, None, None)
         })
-        .and_then(|result| result)
-        .is_err() as i32,
     )
 }
diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js
index 03f06fc1c6c..1fa46ce99f5 100644
--- a/src/tools/rustdoc-js/tester.js
+++ b/src/tools/rustdoc-js/tester.js
@@ -181,7 +181,7 @@ function loadThings(thingsToLoad, kindOfLoad, funcToCall, fileContent) {
     for (var i = 0; i < thingsToLoad.length; ++i) {
         var tmp = funcToCall(fileContent, thingsToLoad[i]);
         if (tmp === null) {
-            console.error('unable to find ' + kindOfLoad + ' "' + thingsToLoad[i] + '"');
+            console.log('unable to find ' + kindOfLoad + ' "' + thingsToLoad[i] + '"');
             process.exit(1);
         }
         content += tmp;
@@ -218,12 +218,13 @@ function lookForEntry(entry, data) {
     return null;
 }
 
-function loadMainJsAndIndex(mainJs, aliases, searchIndex, crate) {
+function loadMainJsAndIndex(mainJs, searchIndex, storageJs, crate) {
     if (searchIndex[searchIndex.length - 1].length === 0) {
         searchIndex.pop();
     }
     searchIndex.pop();
-    searchIndex = loadContent(searchIndex.join("\n") + '\nexports.searchIndex = searchIndex;');
+    var fullSearchIndex = searchIndex.join("\n") + '\nexports.rawSearchIndex = searchIndex;';
+    searchIndex = loadContent(fullSearchIndex);
     var finalJS = "";
 
     var arraysToLoad = ["itemTypes"];
@@ -235,34 +236,28 @@ function loadMainJsAndIndex(mainJs, aliases, searchIndex, crate) {
     // execQuery last parameter is built in buildIndex.
     // buildIndex requires the hashmap from search-index.
     var functionsToLoad = ["buildHrefAndPath", "pathSplitter", "levenshtein", "validateResult",
-                           "getQuery", "buildIndex", "execQuery", "execSearch"];
+                           "handleAliases", "getQuery", "buildIndex", "execQuery", "execSearch"];
 
+    ALIASES = {};
     finalJS += 'window = { "currentCrate": "' + crate + '" };\n';
     finalJS += 'var rootPath = "../";\n';
-    finalJS += aliases;
+    finalJS += loadThings(["onEach"], 'function', extractFunction, storageJs);
     finalJS += loadThings(arraysToLoad, 'array', extractArrayVariable, mainJs);
     finalJS += loadThings(variablesToLoad, 'variable', extractVariable, mainJs);
     finalJS += loadThings(functionsToLoad, 'function', extractFunction, mainJs);
 
     var loaded = loadContent(finalJS);
-    var index = loaded.buildIndex(searchIndex.searchIndex);
+    var index = loaded.buildIndex(searchIndex.rawSearchIndex);
 
     return [loaded, index];
 }
 
-function runChecks(testFile, loaded, index) {
-    var errors = 0;
-    var loadedFile = loadContent(
-        readFile(testFile) + 'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;');
-
-    const expected = loadedFile.EXPECTED;
-    const query = loadedFile.QUERY;
+function runSearch(query, expected, index, loaded, loadedFile, queryName) {
     const filter_crate = loadedFile.FILTER_CRATE;
     const ignore_order = loadedFile.ignore_order;
     const exact_check = loadedFile.exact_check;
-    const should_fail = loadedFile.should_fail;
 
-    var results = loaded.execSearch(loaded.getQuery(query), index);
+    var results = loaded.execSearch(loaded.getQuery(query), index, filter_crate);
     var error_text = [];
 
     for (var key in expected) {
@@ -278,41 +273,77 @@ function runChecks(testFile, loaded, index) {
         for (var i = 0; i < entry.length; ++i) {
             var entry_pos = lookForEntry(entry[i], results[key]);
             if (entry_pos === null) {
-                error_text.push("==> Result not found in '" + key + "': '" +
+                error_text.push(queryName + "==> Result not found in '" + key + "': '" +
                                 JSON.stringify(entry[i]) + "'");
             } else if (exact_check === true && prev_pos + 1 !== entry_pos) {
-                error_text.push("==> Exact check failed at position " + (prev_pos + 1) + ": " +
-                                "expected '" + JSON.stringify(entry[i]) + "' but found '" +
+                error_text.push(queryName + "==> Exact check failed at position " + (prev_pos + 1) +
+                                ": expected '" + JSON.stringify(entry[i]) + "' but found '" +
                                 JSON.stringify(results[key][i]) + "'");
             } else if (ignore_order === false && entry_pos < prev_pos) {
-                error_text.push("==> '" + JSON.stringify(entry[i]) + "' was supposed to be " +
-                                " before '" + JSON.stringify(results[key][entry_pos]) + "'");
+                error_text.push(queryName + "==> '" + JSON.stringify(entry[i]) + "' was supposed " +
+                                "to be before '" + JSON.stringify(results[key][entry_pos]) + "'");
             } else {
                 prev_pos = entry_pos;
             }
         }
     }
-    if (error_text.length === 0 && should_fail === true) {
-        errors += 1;
-        console.error("FAILED");
-        console.error("==> Test was supposed to fail but all items were found...");
-    } else if (error_text.length !== 0 && should_fail === false) {
-        errors += 1;
-        console.error("FAILED");
-        console.error(error_text.join("\n"));
+    return error_text;
+}
+
+function checkResult(error_text, loadedFile, displaySuccess) {
+    if (error_text.length === 0 && loadedFile.should_fail === true) {
+        console.log("FAILED");
+        console.log("==> Test was supposed to fail but all items were found...");
+    } else if (error_text.length !== 0 && loadedFile.should_fail === false) {
+        console.log("FAILED");
+        console.log(error_text.join("\n"));
     } else {
+        if (displaySuccess) {
+            console.log("OK");
+        }
+        return 0;
+    }
+    return 1;
+}
+
+function runChecks(testFile, loaded, index) {
+    var loadedFile = loadContent(
+        readFile(testFile) + 'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;');
+
+    const expected = loadedFile.EXPECTED;
+    const query = loadedFile.QUERY;
+
+    if (Array.isArray(query)) {
+        if (!Array.isArray(expected)) {
+            console.log("FAILED");
+            console.log("==> If QUERY variable is an array, EXPECTED should be an array too");
+            return 1;
+        } else if (query.length !== expected.length) {
+            console.log("FAILED");
+            console.log("==> QUERY variable should have the same length as EXPECTED");
+            return 1;
+        }
+        for (var i = 0; i < query.length; ++i) {
+            var error_text = runSearch(query[i], expected[i], index, loaded, loadedFile,
+                "[ query `" + query[i] + "`]");
+            if (checkResult(error_text, loadedFile, false) !== 0) {
+                return 1;
+            }
+        }
         console.log("OK");
+        return 0;
     }
-    return errors;
+    var error_text = runSearch(query, expected, index, loaded, loadedFile, "");
+    return checkResult(error_text, loadedFile, true);
 }
 
 function load_files(doc_folder, resource_suffix, crate) {
     var mainJs = readFile(path.join(doc_folder, "main" + resource_suffix + ".js"));
-    var aliases = readFile(path.join(doc_folder, "aliases" + resource_suffix + ".js"));
+    var storageJs = readFile(path.join(doc_folder, "storage" + resource_suffix + ".js"));
     var searchIndex = readFile(
         path.join(doc_folder, "search-index" + resource_suffix + ".js")).split("\n");
 
-    return loadMainJsAndIndex(mainJs, aliases, searchIndex, crate);
+    return loadMainJsAndIndex(mainJs, searchIndex, storageJs, crate);
 }
 
 function showHelp() {
@@ -349,7 +380,7 @@ function parseOptions(args) {
             || args[i] === "--crate-name") {
             i += 1;
             if (i >= args.length) {
-                console.error("Missing argument after `" + args[i - 1] + "` option.");
+                console.log("Missing argument after `" + args[i - 1] + "` option.");
                 return null;
             }
             opts[correspondances[args[i - 1]]] = args[i];
@@ -357,17 +388,17 @@ function parseOptions(args) {
             showHelp();
             process.exit(0);
         } else {
-            console.error("Unknown option `" + args[i] + "`.");
-            console.error("Use `--help` to see the list of options");
+            console.log("Unknown option `" + args[i] + "`.");
+            console.log("Use `--help` to see the list of options");
             return null;
         }
     }
     if (opts["doc_folder"].length < 1) {
-        console.error("Missing `--doc-folder` option.");
+        console.log("Missing `--doc-folder` option.");
     } else if (opts["crate_name"].length < 1) {
-        console.error("Missing `--crate-name` option.");
+        console.log("Missing `--crate-name` option.");
     } else if (opts["test_folder"].length < 1 && opts["test_file"].length < 1) {
-        console.error("At least one of `--test-folder` or `--test-file` option is required.");
+        console.log("At least one of `--test-folder` or `--test-file` option is required.");
     } else {
         return opts;
     }