about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-01-05 03:06:32 +0000
committerbors <bors@rust-lang.org>2021-01-05 03:06:32 +0000
commitf412fb56b8d11c168e7ee49ee74e79c4ab2e5637 (patch)
treed18afc92b3a1abecb5bd1c21444e7c6996a7ab28
parent9919ad6e9ed113557c68c430de2e0f434e4f5b6e (diff)
parent9daac58ee9a7be95f14f29b44d0a256669b0419e (diff)
downloadrust-f412fb56b8d11c168e7ee49ee74e79c4ab2e5637.tar.gz
rust-f412fb56b8d11c168e7ee49ee74e79c4ab2e5637.zip
Auto merge of #80708 - JohnTitor:rollup-6esk027, r=JohnTitor
Rollup of 12 pull requests

Successful merges:

 - #80442 (Mention Arc::make_mut and Rc::make_mut in the documentation of Cow)
 - #80533 (bootstrap: clippy fixes)
 - #80538 (Add check for `[T;N]`/`usize` mismatch in astconv)
 - #80612 (Remove reverted change from relnotes)
 - #80627 (Builder: Warn if test file does not exist)
 - #80637 (Use Option::filter instead of open-coding it)
 - #80643 (Move variable into the only branch where it is relevant)
 - #80656 (Fixed documentation error for `std::hint::spin_loop`)
 - #80666 (Fix missing link for "fully qualified syntax")
 - #80672 (./x.py clippy: allow the most noisy lints)
 - #80677 (doc -- list edit for consistency)
 - #80696 (make sure that promoteds which fail to evaluate in dead const code behave correctly)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--Cargo.lock1
-rw-r--r--RELEASES.md2
-rw-r--r--compiler/rustc_hir/Cargo.toml1
-rw-r--r--compiler/rustc_hir/src/hir.rs8
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs28
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs15
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs9
-rw-r--r--compiler/rustc_typeck/src/astconv/generics.rs92
-rw-r--r--library/alloc/src/borrow.rs5
-rw-r--r--library/alloc/src/rc.rs1
-rw-r--r--library/core/src/hint.rs2
-rw-r--r--library/core/src/iter/adapters/zip.rs2
-rw-r--r--src/bootstrap/builder.rs2
-rw-r--r--src/bootstrap/channel.rs4
-rw-r--r--src/bootstrap/check.rs11
-rw-r--r--src/bootstrap/dist.rs8
-rw-r--r--src/bootstrap/lib.rs4
-rw-r--r--src/bootstrap/sanity.rs6
-rw-r--r--src/bootstrap/setup.rs4
-rw-r--r--src/bootstrap/test.rs16
-rw-r--r--src/test/ui/const-generics/suggest_const_for_array.rs10
-rw-r--r--src/test/ui/const-generics/suggest_const_for_array.stderr15
-rw-r--r--src/test/ui/consts/promotion.rs15
23 files changed, 173 insertions, 88 deletions
diff --git a/Cargo.lock b/Cargo.lock
index d3d3fa24a32..e82eb89ef21 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3745,6 +3745,7 @@ version = "0.0.0"
 dependencies = [
  "rustc_ast",
  "rustc_data_structures",
+ "rustc_feature",
  "rustc_index",
  "rustc_macros",
  "rustc_serialize",
diff --git a/RELEASES.md b/RELEASES.md
index 8f04980e390..4409b6ad7b1 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -45,7 +45,6 @@ Libraries
 
 - [`RangeInclusive` now checks for exhaustion when calling `contains` and indexing.][78109]
 - [`ToString::to_string` now no longer shrinks the internal buffer in the default implementation.][77997]
-- [`ops::{Index, IndexMut}` are now implemented for fixed sized arrays of any length.][74989]
 
 Stabilized APIs
 ---------------
@@ -110,7 +109,6 @@ related tools.
 [76199]: https://github.com/rust-lang/rust/pull/76199
 [76119]: https://github.com/rust-lang/rust/pull/76119
 [75914]: https://github.com/rust-lang/rust/pull/75914
-[74989]: https://github.com/rust-lang/rust/pull/74989
 [79004]: https://github.com/rust-lang/rust/pull/79004
 [78676]: https://github.com/rust-lang/rust/pull/78676
 [79904]: https://github.com/rust-lang/rust/issues/79904
diff --git a/compiler/rustc_hir/Cargo.toml b/compiler/rustc_hir/Cargo.toml
index b24c208c76a..c14165454ed 100644
--- a/compiler/rustc_hir/Cargo.toml
+++ b/compiler/rustc_hir/Cargo.toml
@@ -9,6 +9,7 @@ doctest = false
 
 [dependencies]
 rustc_target = { path = "../rustc_target" }
+rustc_feature = { path = "../rustc_feature" }
 rustc_macros = { path = "../rustc_macros" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_index = { path = "../rustc_index" }
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index ead39d70263..acd254ae85c 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -290,6 +290,14 @@ impl GenericArg<'_> {
             GenericArg::Const(_) => "const",
         }
     }
+
+    pub fn to_ord(&self, feats: &rustc_feature::Features) -> ast::ParamKindOrd {
+        match self {
+            GenericArg::Lifetime(_) => ast::ParamKindOrd::Lifetime,
+            GenericArg::Type(_) => ast::ParamKindOrd::Type,
+            GenericArg::Const(_) => ast::ParamKindOrd::Const { unordered: feats.const_generics },
+        }
+    }
 }
 
 #[derive(Debug, HashStable_Generic)]
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index 373f0a602c0..e097264ec8a 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -43,22 +43,18 @@ impl<'a, 'tcx> FindHirNodeVisitor<'a, 'tcx> {
     }
 
     fn node_ty_contains_target(&mut self, hir_id: HirId) -> Option<Ty<'tcx>> {
-        let ty_opt = self
-            .infcx
+        self.infcx
             .in_progress_typeck_results
-            .and_then(|typeck_results| typeck_results.borrow().node_type_opt(hir_id));
-        match ty_opt {
-            Some(ty) => {
-                let ty = self.infcx.resolve_vars_if_possible(ty);
-                if ty.walk().any(|inner| {
+            .and_then(|typeck_results| typeck_results.borrow().node_type_opt(hir_id))
+            .map(|ty| self.infcx.resolve_vars_if_possible(ty))
+            .filter(|ty| {
+                ty.walk().any(|inner| {
                     inner == self.target
                         || match (inner.unpack(), self.target.unpack()) {
                             (GenericArgKind::Type(inner_ty), GenericArgKind::Type(target_ty)) => {
+                                use ty::{Infer, TyVar};
                                 match (inner_ty.kind(), target_ty.kind()) {
-                                    (
-                                        &ty::Infer(ty::TyVar(a_vid)),
-                                        &ty::Infer(ty::TyVar(b_vid)),
-                                    ) => self
+                                    (&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => self
                                         .infcx
                                         .inner
                                         .borrow_mut()
@@ -69,14 +65,8 @@ impl<'a, 'tcx> FindHirNodeVisitor<'a, 'tcx> {
                             }
                             _ => false,
                         }
-                }) {
-                    Some(ty)
-                } else {
-                    None
-                }
-            }
-            None => None,
-        }
+                })
+            })
     }
 }
 
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index c94893bb3a2..6e381fd2965 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1341,15 +1341,14 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
             return &[];
         }
 
-        // Do a reverse lookup beforehand to avoid touching the crate_num
-        // hash map in the loop below.
-        let filter = match filter.map(|def_id| self.reverse_translate_def_id(def_id)) {
-            Some(Some(def_id)) => Some((def_id.krate.as_u32(), def_id.index)),
-            Some(None) => return &[],
-            None => None,
-        };
+        if let Some(def_id) = filter {
+            // Do a reverse lookup beforehand to avoid touching the crate_num
+            // hash map in the loop below.
+            let filter = match self.reverse_translate_def_id(def_id) {
+                Some(def_id) => (def_id.krate.as_u32(), def_id.index),
+                None => return &[],
+            };
 
-        if let Some(filter) = filter {
             if let Some(impls) = self.trait_impls.get(&filter) {
                 tcx.arena.alloc_from_iter(
                     impls.decode(self).map(|(idx, simplified_self_ty)| {
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 1fe1400fabe..59a3ac94634 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -801,6 +801,15 @@ impl GenericParamDefKind {
             GenericParamDefKind::Const => "constant",
         }
     }
+    pub fn to_ord(&self, tcx: TyCtxt<'_>) -> ast::ParamKindOrd {
+        match self {
+            GenericParamDefKind::Lifetime => ast::ParamKindOrd::Lifetime,
+            GenericParamDefKind::Type { .. } => ast::ParamKindOrd::Type,
+            GenericParamDefKind::Const => {
+                ast::ParamKindOrd::Const { unordered: tcx.features().const_generics }
+            }
+        }
+    }
 }
 
 #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs
index a3a2b8967c6..1100401ed12 100644
--- a/compiler/rustc_typeck/src/astconv/generics.rs
+++ b/compiler/rustc_typeck/src/astconv/generics.rs
@@ -11,7 +11,7 @@ use rustc_hir::GenericArg;
 use rustc_middle::ty::{
     self, subst, subst::SubstsRef, GenericParamDef, GenericParamDefKind, Ty, TyCtxt,
 };
-use rustc_session::{lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS, Session};
+use rustc_session::lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS;
 use rustc_span::{symbol::kw, MultiSpan, Span};
 
 use smallvec::SmallVec;
@@ -20,62 +20,72 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
     /// Report an error that a generic argument did not match the generic parameter that was
     /// expected.
     fn generic_arg_mismatch_err(
-        sess: &Session,
+        tcx: TyCtxt<'_>,
         arg: &GenericArg<'_>,
-        kind: &'static str,
+        param: &GenericParamDef,
         possible_ordering_error: bool,
         help: Option<&str>,
     ) {
+        let sess = tcx.sess;
         let mut err = struct_span_err!(
             sess,
             arg.span(),
             E0747,
             "{} provided when a {} was expected",
             arg.descr(),
-            kind,
+            param.kind.descr(),
         );
 
-        let unordered = sess.features_untracked().const_generics;
-        let kind_ord = match kind {
-            "lifetime" => ParamKindOrd::Lifetime,
-            "type" => ParamKindOrd::Type,
-            "constant" => ParamKindOrd::Const { unordered },
-            // It's more concise to match on the string representation, though it means
-            // the match is non-exhaustive.
-            _ => bug!("invalid generic parameter kind {}", kind),
-        };
-
-        if let ParamKindOrd::Const { .. } = kind_ord {
+        if let GenericParamDefKind::Const { .. } = param.kind {
             if let GenericArg::Type(hir::Ty { kind: hir::TyKind::Infer, .. }) = arg {
                 err.help("const arguments cannot yet be inferred with `_`");
             }
         }
 
-        let arg_ord = match arg {
-            GenericArg::Lifetime(_) => ParamKindOrd::Lifetime,
-            GenericArg::Type(_) => ParamKindOrd::Type,
-            GenericArg::Const(_) => ParamKindOrd::Const { unordered },
-        };
-
-        if matches!(arg, GenericArg::Type(hir::Ty { kind: hir::TyKind::Path { .. }, .. }))
-            && matches!(kind_ord, ParamKindOrd::Const { .. })
-        {
-            let suggestions = vec![
-                (arg.span().shrink_to_lo(), String::from("{ ")),
-                (arg.span().shrink_to_hi(), String::from(" }")),
-            ];
-            err.multipart_suggestion(
-                "if this generic argument was intended as a const parameter, \
+        // Specific suggestion set for diagnostics
+        match (arg, &param.kind) {
+            (
+                GenericArg::Type(hir::Ty { kind: hir::TyKind::Path { .. }, .. }),
+                GenericParamDefKind::Const { .. },
+            ) => {
+                let suggestions = vec![
+                    (arg.span().shrink_to_lo(), String::from("{ ")),
+                    (arg.span().shrink_to_hi(), String::from(" }")),
+                ];
+                err.multipart_suggestion(
+                    "if this generic argument was intended as a const parameter, \
                 try surrounding it with braces:",
-                suggestions,
-                Applicability::MaybeIncorrect,
-            );
+                    suggestions,
+                    Applicability::MaybeIncorrect,
+                );
+            }
+            (
+                GenericArg::Type(hir::Ty { kind: hir::TyKind::Array(_, len), .. }),
+                GenericParamDefKind::Const { .. },
+            ) if tcx.type_of(param.def_id) == tcx.types.usize => {
+                let snippet = sess.source_map().span_to_snippet(tcx.hir().span(len.hir_id));
+                if let Ok(snippet) = snippet {
+                    err.span_suggestion(
+                        arg.span(),
+                        "array type provided where a `usize` was expected, try",
+                        format!("{{ {} }}", snippet),
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+            }
+            _ => {}
         }
 
+        let kind_ord = param.kind.to_ord(tcx);
+        let arg_ord = arg.to_ord(&tcx.features());
+
         // This note is only true when generic parameters are strictly ordered by their kind.
         if possible_ordering_error && kind_ord.cmp(&arg_ord) != core::cmp::Ordering::Equal {
-            let (first, last) =
-                if kind_ord < arg_ord { (kind, arg.descr()) } else { (arg.descr(), kind) };
+            let (first, last) = if kind_ord < arg_ord {
+                (param.kind.descr(), arg.descr())
+            } else {
+                (arg.descr(), param.kind.descr())
+            };
             err.note(&format!("{} arguments must be provided before {} arguments", first, last));
             if let Some(help) = help {
                 err.help(help);
@@ -203,7 +213,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                                 // We expected a lifetime argument, but got a type or const
                                 // argument. That means we're inferring the lifetimes.
                                 substs.push(ctx.inferred_kind(None, param, infer_args));
-                                force_infer_lt = Some(arg);
+                                force_infer_lt = Some((arg, param));
                                 params.next();
                             }
                             (GenericArg::Lifetime(_), _, ExplicitLateBound::Yes) => {
@@ -213,7 +223,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                                 // ignore it.
                                 args.next();
                             }
-                            (_, kind, _) => {
+                            (_, _, _) => {
                                 // We expected one kind of parameter, but the user provided
                                 // another. This is an error. However, if we already know that
                                 // the arguments don't match up with the parameters, we won't issue
@@ -256,9 +266,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                                     param_types_present.dedup();
 
                                     Self::generic_arg_mismatch_err(
-                                        tcx.sess,
+                                        tcx,
                                         arg,
-                                        kind.descr(),
+                                        param,
                                         !args_iter.clone().is_sorted_by_key(|arg| match arg {
                                             GenericArg::Lifetime(_) => ParamKindOrd::Lifetime,
                                             GenericArg::Type(_) => ParamKindOrd::Type,
@@ -315,9 +325,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                         {
                             let kind = arg.descr();
                             assert_eq!(kind, "lifetime");
-                            let provided =
+                            let (provided_arg, param) =
                                 force_infer_lt.expect("lifetimes ought to have been inferred");
-                            Self::generic_arg_mismatch_err(tcx.sess, provided, kind, false, None);
+                            Self::generic_arg_mismatch_err(tcx, provided_arg, param, false, None);
                         }
 
                         break;
diff --git a/library/alloc/src/borrow.rs b/library/alloc/src/borrow.rs
index f801c1ac75b..adf996fc782 100644
--- a/library/alloc/src/borrow.rs
+++ b/library/alloc/src/borrow.rs
@@ -103,6 +103,11 @@ where
 /// is desired, `to_mut` will obtain a mutable reference to an owned
 /// value, cloning if necessary.
 ///
+/// If you need reference-counting pointers, note that
+/// [`Rc::make_mut`][crate::rc::Rc::make_mut] and
+/// [`Arc::make_mut`][crate::sync::Arc::make_mut] can provide clone-on-write
+/// functionality as well.
+///
 /// # Examples
 ///
 /// ```
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index 3115cc3d002..8183a582d33 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -238,6 +238,7 @@
 //! [downgrade]: Rc::downgrade
 //! [upgrade]: Weak::upgrade
 //! [mutability]: core::cell#introducing-mutability-inside-of-something-immutable
+//! [fully qualified syntax]: https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#fully-qualified-syntax-for-disambiguation-calling-methods-with-the-same-name
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs
index 979a5f8cf50..313729581ac 100644
--- a/library/core/src/hint.rs
+++ b/library/core/src/hint.rs
@@ -91,7 +91,7 @@ pub const unsafe fn unreachable_unchecked() -> ! {
 /// };
 ///
 /// // Back on our current thread, we wait for the value to be set
-/// while live.load(Ordering::Acquire) {
+/// while !live.load(Ordering::Acquire) {
 ///     // The spin loop is a hint to the CPU that we're waiting, but probably
 ///     // not for very long
 ///     hint::spin_loop();
diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs
index 8cd4c775231..5766fd3c887 100644
--- a/library/core/src/iter/adapters/zip.rs
+++ b/library/core/src/iter/adapters/zip.rs
@@ -397,7 +397,7 @@ impl<A: Debug + TrustedRandomAccess, B: Debug + TrustedRandomAccess> ZipFmt<A, B
 ///    only be called at most `self.size() - idx - 1` times.
 /// 4. After `get_unchecked` is called, then only the following methods will be
 ///    called on `self`:
-///     * `std::clone::Clone::clone`
+///     * `std::clone::Clone::clone()`
 ///     * `std::iter::Iterator::size_hint()`
 ///     * `std::iter::Iterator::next_back()`
 ///     * `std::iter::Iterator::__iterator_get_unchecked()`
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index c2abb01fa8c..ec9ce4c820c 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -1534,7 +1534,7 @@ impl Rustflags {
     fn arg(&mut self, arg: &str) -> &mut Self {
         assert_eq!(arg.split(' ').count(), 1);
         if !self.0.is_empty() {
-            self.0.push_str(" ");
+            self.0.push(' ');
         }
         self.0.push_str(arg);
         self
diff --git a/src/bootstrap/channel.rs b/src/bootstrap/channel.rs
index 2b82f6c30b2..6e65be93fec 100644
--- a/src/bootstrap/channel.rs
+++ b/src/bootstrap/channel.rs
@@ -74,9 +74,9 @@ impl GitInfo {
         if let Some(ref inner) = self.inner {
             version.push_str(" (");
             version.push_str(&inner.short_sha);
-            version.push_str(" ");
+            version.push(' ');
             version.push_str(&inner.commit_date);
-            version.push_str(")");
+            version.push(')');
         }
         version
     }
diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs
index f65b2b2c79f..72a979338a5 100644
--- a/src/bootstrap/check.rs
+++ b/src/bootstrap/check.rs
@@ -21,6 +21,16 @@ fn args(builder: &Builder<'_>) -> Vec<String> {
     }
 
     if let Subcommand::Clippy { fix, .. } = builder.config.cmd {
+        // disable the most spammy clippy lints
+        let ignored_lints = vec![
+            "many_single_char_names", // there are a lot in stdarch
+            "collapsible_if",
+            "type_complexity",
+            "missing_safety_doc", // almost 3K warnings
+            "too_many_arguments",
+            "needless_lifetimes", // people want to keep the lifetimes
+            "wrong_self_convention",
+        ];
         let mut args = vec![];
         if fix {
             #[rustfmt::skip]
@@ -33,6 +43,7 @@ fn args(builder: &Builder<'_>) -> Vec<String> {
             ]));
         }
         args.extend(strings(&["--", "--cap-lints", "warn"]));
+        args.extend(ignored_lints.iter().map(|lint| format!("-Aclippy::{}", lint)));
         args
     } else {
         vec![]
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index daec1656b27..e2c2e19b0bc 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -1326,17 +1326,17 @@ impl Step for Extended {
         license += &builder.read(&builder.src.join("COPYRIGHT"));
         license += &builder.read(&builder.src.join("LICENSE-APACHE"));
         license += &builder.read(&builder.src.join("LICENSE-MIT"));
-        license.push_str("\n");
-        license.push_str("\n");
+        license.push('\n');
+        license.push('\n');
 
         let rtf = r"{\rtf1\ansi\deff0{\fonttbl{\f0\fnil\fcharset0 Arial;}}\nowwrap\fs18";
         let mut rtf = rtf.to_string();
-        rtf.push_str("\n");
+        rtf.push('\n');
         for line in license.lines() {
             rtf.push_str(line);
             rtf.push_str("\\line ");
         }
-        rtf.push_str("}");
+        rtf.push('}');
 
         fn filter(contents: &str, marker: &str) -> String {
             let start = format!("tool-{}-start", marker);
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index a47ddfbcc1f..88fdcfa2d43 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -1083,7 +1083,7 @@ impl Build {
         if let Some(ref s) = self.config.description {
             version.push_str(" (");
             version.push_str(s);
-            version.push_str(")");
+            version.push(')');
         }
         version
     }
@@ -1144,7 +1144,7 @@ impl Build {
                     && (dep != "profiler_builtins"
                         || target
                             .map(|t| self.config.profiler_enabled(t))
-                            .unwrap_or(self.config.any_profiler_enabled()))
+                            .unwrap_or_else(|| self.config.any_profiler_enabled()))
                     && (dep != "rustc_codegen_llvm" || self.config.llvm_enabled())
                 {
                     list.push(*dep);
diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs
index acb941d9540..08acc3d671f 100644
--- a/src/bootstrap/sanity.rs
+++ b/src/bootstrap/sanity.rs
@@ -163,7 +163,11 @@ pub fn check(build: &mut Build) {
             panic!("the iOS target is only supported on macOS");
         }
 
-        build.config.target_config.entry(*target).or_insert(Target::from_triple(&target.triple));
+        build
+            .config
+            .target_config
+            .entry(*target)
+            .or_insert_with(|| Target::from_triple(&target.triple));
 
         if target.contains("-none-") || target.contains("nvptx") {
             if build.no_std(*target) == Some(false) {
diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs
index 2d4484c562c..725147767db 100644
--- a/src/bootstrap/setup.rs
+++ b/src/bootstrap/setup.rs
@@ -89,7 +89,7 @@ pub fn setup(src_path: &Path, profile: Profile) {
         std::process::exit(1);
     }
 
-    let path = cfg_file.unwrap_or("config.toml".into());
+    let path = cfg_file.unwrap_or_else(|| "config.toml".into());
     let settings = format!(
         "# Includes one of the default files in src/bootstrap/defaults\n\
     profile = \"{}\"\n\
@@ -156,7 +156,7 @@ pub fn interactive_path() -> io::Result<Profile> {
         io::stdout().flush()?;
         let mut input = String::new();
         io::stdin().read_line(&mut input)?;
-        if input == "" {
+        if input.is_empty() {
             eprintln!("EOF on stdin, when expecting answer to question.  Giving up.");
             std::process::exit(1);
         }
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index 33e252a63c9..2e8c574044e 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -1126,7 +1126,19 @@ note: if you're sure you want to do this, please open an issue as to why. In the
                 Ok(path) => path,
                 Err(_) => p,
             })
-            .filter(|p| p.starts_with(suite_path) && (p.is_dir() || p.is_file()))
+            .filter(|p| p.starts_with(suite_path))
+            .filter(|p| {
+                let exists = p.is_dir() || p.is_file();
+                if !exists {
+                    if let Some(p) = p.to_str() {
+                        builder.info(&format!(
+                            "Warning: Skipping \"{}\": not a regular file or directory",
+                            p
+                        ));
+                    }
+                }
+                exists
+            })
             .filter_map(|p| {
                 // Since test suite paths are themselves directories, if we don't
                 // specify a directory or file, we'll get an empty string here
@@ -1135,7 +1147,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the
                 // flag is respected, so providing an empty --test-args conflicts with
                 // any following it.
                 match p.strip_prefix(suite_path).ok().and_then(|p| p.to_str()) {
-                    Some(s) if s != "" => Some(s),
+                    Some(s) if !s.is_empty() => Some(s),
                     _ => None,
                 }
             })
diff --git a/src/test/ui/const-generics/suggest_const_for_array.rs b/src/test/ui/const-generics/suggest_const_for_array.rs
new file mode 100644
index 00000000000..f3e5a3186cd
--- /dev/null
+++ b/src/test/ui/const-generics/suggest_const_for_array.rs
@@ -0,0 +1,10 @@
+#![crate_type = "lib"]
+
+fn example<const N: usize>() {}
+
+fn other() {
+  example::<[usize; 3]>();
+  //~^ ERROR type provided when a const
+  example::<[usize; 4+5]>();
+  //~^ ERROR type provided when a const
+}
diff --git a/src/test/ui/const-generics/suggest_const_for_array.stderr b/src/test/ui/const-generics/suggest_const_for_array.stderr
new file mode 100644
index 00000000000..a617bf2bb0d
--- /dev/null
+++ b/src/test/ui/const-generics/suggest_const_for_array.stderr
@@ -0,0 +1,15 @@
+error[E0747]: type provided when a constant was expected
+  --> $DIR/suggest_const_for_array.rs:6:13
+   |
+LL |   example::<[usize; 3]>();
+   |             ^^^^^^^^^^ help: array type provided where a `usize` was expected, try: `{ 3 }`
+
+error[E0747]: type provided when a constant was expected
+  --> $DIR/suggest_const_for_array.rs:8:13
+   |
+LL |   example::<[usize; 4+5]>();
+   |             ^^^^^^^^^^^^ help: array type provided where a `usize` was expected, try: `{ 4+5 }`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0747`.
diff --git a/src/test/ui/consts/promotion.rs b/src/test/ui/consts/promotion.rs
index e6f5c3d27ca..b6e7127a9b7 100644
--- a/src/test/ui/consts/promotion.rs
+++ b/src/test/ui/consts/promotion.rs
@@ -4,12 +4,23 @@
 
 fn foo(_: &'static [&'static str]) {}
 fn bar(_: &'static [&'static str; 3]) {}
-fn baz_i32(_: &'static i32) {}
-fn baz_u32(_: &'static u32) {}
+const fn baz_i32(_: &'static i32) {}
+const fn baz_u32(_: &'static u32) {}
+
+const fn fail() -> i32 { 1/0 }
+const C: i32 = {
+    // Promoted that fails to evaluate in dead code -- this must work
+    // (for backwards compatibility reasons).
+    if false {
+        baz_i32(&fail());
+    }
+    42
+};
 
 fn main() {
     foo(&["a", "b", "c"]);
     bar(&["d", "e", "f"]);
+    assert_eq!(C, 42);
 
     // make sure that these do not cause trouble despite overflowing
     baz_u32(&(0-1));