about summary refs log tree commit diff
path: root/src/librustc
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-08-15 00:32:05 +0000
committerbors <bors@rust-lang.org>2019-08-15 00:32:05 +0000
commit9e9a136fcec5eb78f09a14dfd072a51ae2550269 (patch)
treeb193fe082d78583740df368de6f546ca35890cbb /src/librustc
parent082cf2f9d136166cd1d552d3fb5abb1c46c99a14 (diff)
parent78cd9d1fd5cd59fbab62325b1bcb4bb21c2cb30a (diff)
downloadrust-9e9a136fcec5eb78f09a14dfd072a51ae2550269.tar.gz
rust-9e9a136fcec5eb78f09a14dfd072a51ae2550269.zip
Auto merge of #63575 - Centril:rollup-anlv9g5, r=Centril
Rollup of 11 pull requests

Successful merges:

 - #62984 (Add lint for excess trailing semicolons)
 - #63075 (Miri: Check that a ptr is aligned and inbounds already when evaluating `*`)
 - #63490 (libsyntax: cleanup and refactor `pat.rs`)
 - #63507 (When needing type annotations in local bindings, account for impl Trait and closures)
 - #63509 (Point at the right enclosing scope when using `await` in non-async fn)
 - #63528 (syntax: Remove `DummyResult::expr_only`)
 - #63537 (expand: Unimplement `MutVisitor` on `MacroExpander`)
 - #63542 (Add NodeId for Arm, Field and FieldPat)
 - #63543 (Merge Variant and Variant_)
 - #63560 (move test that shouldn't be in test/run-pass/)
 - #63570 (Adjust tracking issues for `MaybeUninit<T>` gates)

Failed merges:

r? @ghost
Diffstat (limited to 'src/librustc')
-rw-r--r--src/librustc/hir/check_attr.rs2
-rw-r--r--src/librustc/hir/intravisit.rs12
-rw-r--r--src/librustc/hir/lowering/expr.rs5
-rw-r--r--src/librustc/hir/lowering/item.rs14
-rw-r--r--src/librustc/hir/map/collector.rs8
-rw-r--r--src/librustc/hir/map/def_collector.rs6
-rw-r--r--src/librustc/hir/map/mod.rs42
-rw-r--r--src/librustc/hir/mod.rs8
-rw-r--r--src/librustc/hir/print.rs6
-rw-r--r--src/librustc/ich/impls_hir.rs2
-rw-r--r--src/librustc/infer/error_reporting/need_type_info.rs212
-rw-r--r--src/librustc/lint/context.rs4
-rw-r--r--src/librustc/lint/mod.rs2
-rw-r--r--src/librustc/middle/dead.rs12
-rw-r--r--src/librustc/middle/stability.rs8
-rw-r--r--src/librustc/mir/interpret/pointer.rs5
-rw-r--r--src/librustc/ty/sty.rs3
17 files changed, 245 insertions, 106 deletions
diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs
index 22124d4ee41..eae956c978a 100644
--- a/src/librustc/hir/check_attr.rs
+++ b/src/librustc/hir/check_attr.rs
@@ -336,7 +336,7 @@ impl Visitor<'tcx> for CheckAttrVisitor<'tcx> {
 fn is_c_like_enum(item: &hir::Item) -> bool {
     if let hir::ItemKind::Enum(ref def, _) = item.node {
         for variant in &def.variants {
-            match variant.node.data {
+            match variant.data {
                 hir::VariantData::Unit(..) => { /* continue */ }
                 _ => { return false; }
             }
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index b5c760bc9a0..71d7464540a 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -577,15 +577,15 @@ pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V,
                                         variant: &'v Variant,
                                         generics: &'v Generics,
                                         parent_item_id: HirId) {
-    visitor.visit_ident(variant.node.ident);
-    visitor.visit_id(variant.node.id);
-    visitor.visit_variant_data(&variant.node.data,
-                               variant.node.ident.name,
+    visitor.visit_ident(variant.ident);
+    visitor.visit_id(variant.id);
+    visitor.visit_variant_data(&variant.data,
+                               variant.ident.name,
                                generics,
                                parent_item_id,
                                variant.span);
-    walk_list!(visitor, visit_anon_const, &variant.node.disr_expr);
-    walk_list!(visitor, visit_attribute, &variant.node.attrs);
+    walk_list!(visitor, visit_anon_const, &variant.disr_expr);
+    walk_list!(visitor, visit_attribute, &variant.attrs);
 }
 
 pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
diff --git a/src/librustc/hir/lowering/expr.rs b/src/librustc/hir/lowering/expr.rs
index d273006fbe0..e3a5400942d 100644
--- a/src/librustc/hir/lowering/expr.rs
+++ b/src/librustc/hir/lowering/expr.rs
@@ -677,6 +677,7 @@ impl LoweringContext<'_> {
         let fn_decl = self.lower_fn_decl(decl, None, false, None);
 
         self.with_new_scopes(|this| {
+            let prev = this.current_item;
             this.current_item = Some(fn_decl_span);
             let mut generator_kind = None;
             let body_id = this.lower_fn_body(decl, |this| {
@@ -690,8 +691,10 @@ impl LoweringContext<'_> {
                 generator_kind,
                 movability,
             );
+            let capture_clause = this.lower_capture_clause(capture_clause);
+            this.current_item = prev;
             hir::ExprKind::Closure(
-                this.lower_capture_clause(capture_clause),
+                capture_clause,
                 fn_decl,
                 body_id,
                 fn_decl_span,
diff --git a/src/librustc/hir/lowering/item.rs b/src/librustc/hir/lowering/item.rs
index dd95d99d4e1..51a0c4184f9 100644
--- a/src/librustc/hir/lowering/item.rs
+++ b/src/librustc/hir/lowering/item.rs
@@ -757,14 +757,12 @@ impl LoweringContext<'_> {
     }
 
     fn lower_variant(&mut self, v: &Variant) -> hir::Variant {
-        Spanned {
-            node: hir::VariantKind {
-                ident: v.node.ident,
-                id: self.lower_node_id(v.node.id),
-                attrs: self.lower_attrs(&v.node.attrs),
-                data: self.lower_variant_data(&v.node.data),
-                disr_expr: v.node.disr_expr.as_ref().map(|e| self.lower_anon_const(e)),
-            },
+        hir::Variant {
+            attrs: self.lower_attrs(&v.attrs),
+            data: self.lower_variant_data(&v.data),
+            disr_expr: v.disr_expr.as_ref().map(|e| self.lower_anon_const(e)),
+            id: self.lower_node_id(v.id),
+            ident: v.ident,
             span: v.span,
         }
     }
diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs
index b6807f7d3bb..effe2c0cc6a 100644
--- a/src/librustc/hir/map/collector.rs
+++ b/src/librustc/hir/map/collector.rs
@@ -544,11 +544,11 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
     }
 
     fn visit_variant(&mut self, v: &'hir Variant, g: &'hir Generics, item_id: HirId) {
-        self.insert(v.span, v.node.id, Node::Variant(v));
-        self.with_parent(v.node.id, |this| {
+        self.insert(v.span, v.id, Node::Variant(v));
+        self.with_parent(v.id, |this| {
             // Register the constructor of this variant.
-            if let Some(ctor_hir_id) = v.node.data.ctor_hir_id() {
-                this.insert(v.span, ctor_hir_id, Node::Ctor(&v.node.data));
+            if let Some(ctor_hir_id) = v.data.ctor_hir_id() {
+                this.insert(v.span, ctor_hir_id, Node::Ctor(&v.data));
             }
             intravisit::walk_variant(this, v, g, item_id);
         });
diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs
index 2964b130ddd..df9bd3a35a6 100644
--- a/src/librustc/hir/map/def_collector.rs
+++ b/src/librustc/hir/map/def_collector.rs
@@ -155,11 +155,11 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
     }
 
     fn visit_variant(&mut self, v: &'a Variant, g: &'a Generics, item_id: NodeId) {
-        let def = self.create_def(v.node.id,
-                                  DefPathData::TypeNs(v.node.ident.as_interned_str()),
+        let def = self.create_def(v.id,
+                                  DefPathData::TypeNs(v.ident.as_interned_str()),
                                   v.span);
         self.with_parent(def, |this| {
-            if let Some(ctor_hir_id) = v.node.data.ctor_id() {
+            if let Some(ctor_hir_id) = v.data.ctor_id() {
                 this.create_def(ctor_hir_id, DefPathData::Ctor, v.span);
             }
             visit::walk_variant(this, v, g, item_id)
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index b85738dd29a..7292428ec37 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -649,12 +649,34 @@ impl<'hir> Map<'hir> {
         }
     }
 
-    pub fn is_const_scope(&self, hir_id: HirId) -> bool {
-        self.walk_parent_nodes(hir_id, |node| match *node {
-            Node::Item(Item { node: ItemKind::Const(_, _), .. }) => true,
-            Node::Item(Item { node: ItemKind::Fn(_, header, _, _), .. }) => header.is_const(),
+    /// Whether the expression pointed at by `hir_id` belongs to a `const` evaluation context.
+    /// Used exclusively for diagnostics, to avoid suggestion function calls.
+    pub fn is_const_context(&self, hir_id: HirId) -> bool {
+        let parent_id = self.get_parent_item(hir_id);
+        match self.get(parent_id) {
+            Node::Item(&Item {
+                node: ItemKind::Const(..),
+                ..
+            })
+            | Node::TraitItem(&TraitItem {
+                node: TraitItemKind::Const(..),
+                ..
+            })
+            | Node::ImplItem(&ImplItem {
+                node: ImplItemKind::Const(..),
+                ..
+            })
+            | Node::AnonConst(_)
+            | Node::Item(&Item {
+                node: ItemKind::Static(..),
+                ..
+            }) => true,
+            Node::Item(&Item {
+                node: ItemKind::Fn(_, header, ..),
+                ..
+            }) => header.constness == Constness::Const,
             _ => false,
-        }, |_| false).map(|id| id != CRATE_HIR_ID).unwrap_or(false)
+        }
     }
 
     /// If there is some error when walking the parents (e.g., a node does not
@@ -885,7 +907,7 @@ impl<'hir> Map<'hir> {
                     _ => bug!("struct ID bound to non-struct {}", self.node_to_string(id))
                 }
             }
-            Some(Node::Variant(variant)) => &variant.node.data,
+            Some(Node::Variant(variant)) => &variant.data,
             Some(Node::Ctor(data)) => data,
             _ => bug!("expected struct or variant, found {}", self.node_to_string(id))
         }
@@ -918,7 +940,7 @@ impl<'hir> Map<'hir> {
             Node::ForeignItem(fi) => fi.ident.name,
             Node::ImplItem(ii) => ii.ident.name,
             Node::TraitItem(ti) => ti.ident.name,
-            Node::Variant(v) => v.node.ident.name,
+            Node::Variant(v) => v.ident.name,
             Node::Field(f) => f.ident.name,
             Node::Lifetime(lt) => lt.name.ident().name,
             Node::GenericParam(param) => param.name.ident().name,
@@ -939,7 +961,7 @@ impl<'hir> Map<'hir> {
             Some(Node::ForeignItem(fi)) => Some(&fi.attrs[..]),
             Some(Node::TraitItem(ref ti)) => Some(&ti.attrs[..]),
             Some(Node::ImplItem(ref ii)) => Some(&ii.attrs[..]),
-            Some(Node::Variant(ref v)) => Some(&v.node.attrs[..]),
+            Some(Node::Variant(ref v)) => Some(&v.attrs[..]),
             Some(Node::Field(ref f)) => Some(&f.attrs[..]),
             Some(Node::Expr(ref e)) => Some(&*e.attrs),
             Some(Node::Stmt(ref s)) => Some(s.node.attrs()),
@@ -1133,7 +1155,7 @@ impl<T:Named> Named for Spanned<T> { fn name(&self) -> Name { self.node.name() }
 
 impl Named for Item { fn name(&self) -> Name { self.ident.name } }
 impl Named for ForeignItem { fn name(&self) -> Name { self.ident.name } }
-impl Named for VariantKind { fn name(&self) -> Name { self.ident.name } }
+impl Named for Variant { fn name(&self) -> Name { self.ident.name } }
 impl Named for StructField { fn name(&self) -> Name { self.ident.name } }
 impl Named for TraitItem { fn name(&self) -> Name { self.ident.name } }
 impl Named for ImplItem { fn name(&self) -> Name { self.ident.name } }
@@ -1310,7 +1332,7 @@ fn hir_id_to_string(map: &Map<'_>, id: HirId, include_id: bool) -> String {
         }
         Some(Node::Variant(ref variant)) => {
             format!("variant {} in {}{}",
-                    variant.node.ident,
+                    variant.ident,
                     path_str(), id_str)
         }
         Some(Node::Field(ref field)) => {
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 3d049fe4ccd..dccc2774f52 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -1541,7 +1541,7 @@ pub enum ExprKind {
     Match(P<Expr>, HirVec<Arm>, MatchSource),
     /// A closure (e.g., `move |a, b, c| {a + b + c}`).
     ///
-    /// The final span is the span of the argument block `|...|`.
+    /// The `Span` is the argument block `|...|`.
     ///
     /// This may also be a generator literal or an `async block` as indicated by the
     /// `Option<GeneratorMovability>`.
@@ -2193,7 +2193,7 @@ pub struct EnumDef {
 }
 
 #[derive(RustcEncodable, RustcDecodable, Debug, HashStable)]
-pub struct VariantKind {
+pub struct Variant {
     /// Name of the variant.
     #[stable_hasher(project(name))]
     pub ident: Ident,
@@ -2205,10 +2205,10 @@ pub struct VariantKind {
     pub data: VariantData,
     /// Explicit discriminant (e.g., `Foo = 1`).
     pub disr_expr: Option<AnonConst>,
+    /// Span
+    pub span: Span
 }
 
-pub type Variant = Spanned<VariantKind>;
-
 #[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable)]
 pub enum UseKind {
     /// One import, e.g., `use foo::bar` or `use foo::bar as baz`.
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 11ba5120530..0cbfe4d75f1 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -737,7 +737,7 @@ impl<'a> State<'a> {
         for v in variants {
             self.space_if_not_bol();
             self.maybe_print_comment(v.span.lo());
-            self.print_outer_attributes(&v.node.attrs);
+            self.print_outer_attributes(&v.attrs);
             self.ibox(INDENT_UNIT);
             self.print_variant(v);
             self.s.word(",");
@@ -829,8 +829,8 @@ impl<'a> State<'a> {
     pub fn print_variant(&mut self, v: &hir::Variant) {
         self.head("");
         let generics = hir::Generics::empty();
-        self.print_struct(&v.node.data, &generics, v.node.ident.name, v.span, false);
-        if let Some(ref d) = v.node.disr_expr {
+        self.print_struct(&v.data, &generics, v.ident.name, v.span, false);
+        if let Some(ref d) = v.disr_expr {
             self.s.space();
             self.word_space("=");
             self.print_anon_const(d);
diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs
index 30d76f240d1..1fd4e00de49 100644
--- a/src/librustc/ich/impls_hir.rs
+++ b/src/librustc/ich/impls_hir.rs
@@ -304,7 +304,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for hir::Mod {
     }
 }
 
-impl_stable_hash_for_spanned!(hir::VariantKind);
+impl_stable_hash_for_spanned!(hir::Variant);
 
 
 impl<'a> HashStable<StableHashingContext<'a>> for hir::Item {
diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs
index 770d5155777..3267505708b 100644
--- a/src/librustc/infer/error_reporting/need_type_info.rs
+++ b/src/librustc/infer/error_reporting/need_type_info.rs
@@ -1,5 +1,5 @@
 use crate::hir::def::Namespace;
-use crate::hir::{self, Local, Pat, Body, HirId};
+use crate::hir::{self, Body, FunctionRetTy, Expr, ExprKind, HirId, Local, Pat};
 use crate::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use crate::infer::InferCtxt;
 use crate::infer::type_variable::TypeVariableOriginKind;
@@ -7,7 +7,7 @@ use crate::ty::{self, Ty, Infer, TyVar};
 use crate::ty::print::Print;
 use syntax::source_map::DesugaringKind;
 use syntax_pos::Span;
-use errors::DiagnosticBuilder;
+use errors::{Applicability, DiagnosticBuilder};
 
 struct FindLocalByTypeVisitor<'a, 'tcx> {
     infcx: &'a InferCtxt<'a, 'tcx>,
@@ -16,9 +16,26 @@ struct FindLocalByTypeVisitor<'a, 'tcx> {
     found_local_pattern: Option<&'tcx Pat>,
     found_arg_pattern: Option<&'tcx Pat>,
     found_ty: Option<Ty<'tcx>>,
+    found_closure: Option<&'tcx ExprKind>,
 }
 
 impl<'a, 'tcx> FindLocalByTypeVisitor<'a, 'tcx> {
+    fn new(
+        infcx: &'a InferCtxt<'a, 'tcx>,
+        target_ty: Ty<'tcx>,
+        hir_map: &'a hir::map::Map<'tcx>,
+    ) -> Self {
+        Self {
+            infcx,
+            target_ty,
+            hir_map,
+            found_local_pattern: None,
+            found_arg_pattern: None,
+            found_ty: None,
+            found_closure: None,
+        }
+    }
+
     fn node_matches_type(&mut self, hir_id: HirId) -> Option<Ty<'tcx>> {
         let ty_opt = self.infcx.in_progress_tables.and_then(|tables| {
             tables.borrow().node_type_opt(hir_id)
@@ -72,6 +89,60 @@ impl<'a, 'tcx> Visitor<'tcx> for FindLocalByTypeVisitor<'a, 'tcx> {
         }
         intravisit::walk_body(self, body);
     }
+
+    fn visit_expr(&mut self, expr: &'tcx Expr) {
+        if let (ExprKind::Closure(_, _fn_decl, _id, _sp, _), Some(_)) = (
+            &expr.node,
+            self.node_matches_type(expr.hir_id),
+        ) {
+            self.found_closure = Some(&expr.node);
+        }
+        intravisit::walk_expr(self, expr);
+    }
+}
+
+/// Suggest giving an appropriate return type to a closure expression.
+fn closure_return_type_suggestion(
+    span: Span,
+    err: &mut DiagnosticBuilder<'_>,
+    output: &FunctionRetTy,
+    body: &Body,
+    name: &str,
+    ret: &str,
+) {
+    let (arrow, post) = match output {
+        FunctionRetTy::DefaultReturn(_) => ("-> ", " "),
+        _ => ("", ""),
+    };
+    let suggestion = match body.value.node {
+        ExprKind::Block(..) => {
+            vec![(output.span(), format!("{}{}{}", arrow, ret, post))]
+        }
+        _ => {
+            vec![
+                (output.span(), format!("{}{}{}{{ ", arrow, ret, post)),
+                (body.value.span.shrink_to_hi(), " }".to_string()),
+            ]
+        }
+    };
+    err.multipart_suggestion(
+        "give this closure an explicit return type without `_` placeholders",
+        suggestion,
+        Applicability::HasPlaceholders,
+    );
+    err.span_label(span, InferCtxt::missing_type_msg(&name));
+}
+
+/// Given a closure signature, return a `String` containing a list of all its argument types.
+fn closure_args(fn_sig: &ty::PolyFnSig<'_>) -> String {
+    fn_sig.inputs()
+        .skip_binder()
+        .iter()
+        .next()
+        .map(|args| args.tuple_fields()
+            .map(|arg| arg.to_string())
+            .collect::<Vec<_>>().join(", "))
+        .unwrap_or_default()
 }
 
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
@@ -106,16 +177,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         let ty = self.resolve_vars_if_possible(&ty);
         let name = self.extract_type_name(&ty, None);
 
-        let mut err_span = span;
-
-        let mut local_visitor = FindLocalByTypeVisitor {
-            infcx: &self,
-            target_ty: ty,
-            hir_map: &self.tcx.hir(),
-            found_local_pattern: None,
-            found_arg_pattern: None,
-            found_ty: None,
-        };
+        let mut local_visitor = FindLocalByTypeVisitor::new(&self, ty, &self.tcx.hir());
         let ty_to_string = |ty: Ty<'tcx>| -> String {
             let mut s = String::new();
             let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
@@ -136,6 +198,31 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             let expr = self.tcx.hir().expect_expr(body_id.hir_id);
             local_visitor.visit_expr(expr);
         }
+        let err_span = if let Some(pattern) = local_visitor.found_arg_pattern {
+            pattern.span
+        } else {
+            span
+        };
+
+        let is_named_and_not_impl_trait = |ty: Ty<'_>| {
+            &ty.to_string() != "_" &&
+                // FIXME: Remove this check after `impl_trait_in_bindings` is stabilized. #63527
+                (!ty.is_impl_trait() || self.tcx.features().impl_trait_in_bindings)
+        };
+
+        let ty_msg = match local_visitor.found_ty {
+            Some(ty::TyS { sty: ty::Closure(def_id, substs), .. }) => {
+                let fn_sig = substs.closure_sig(*def_id, self.tcx);
+                let args = closure_args(&fn_sig);
+                let ret = fn_sig.output().skip_binder().to_string();
+                format!(" for the closure `fn({}) -> {}`", args, ret)
+            }
+            Some(ty) if is_named_and_not_impl_trait(ty) => {
+                let ty = ty_to_string(ty);
+                format!(" for `{}`", ty)
+            }
+            _ => String::new(),
+        };
 
         // When `name` corresponds to a type argument, show the path of the full type we're
         // trying to infer. In the following example, `ty_msg` contains
@@ -150,27 +237,58 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         //   |         consider giving `b` the explicit type `std::result::Result<i32, E>`, where
         //   |         the type parameter `E` is specified
         // ```
-        let (ty_msg, suffix) = match &local_visitor.found_ty {
-            Some(ty) if &ty.to_string() != "_" && name == "_" => {
+        let mut err = struct_span_err!(
+            self.tcx.sess,
+            err_span,
+            E0282,
+            "type annotations needed{}",
+            ty_msg,
+        );
+
+        let suffix = match local_visitor.found_ty {
+            Some(ty::TyS { sty: ty::Closure(def_id, substs), .. }) => {
+                let fn_sig = substs.closure_sig(*def_id, self.tcx);
+                let ret = fn_sig.output().skip_binder().to_string();
+
+                if let Some(ExprKind::Closure(_, decl, body_id, ..)) = local_visitor.found_closure {
+                    if let Some(body) = self.tcx.hir().krate().bodies.get(body_id) {
+                        closure_return_type_suggestion(
+                            span,
+                            &mut err,
+                            &decl.output,
+                            &body,
+                            &name,
+                            &ret,
+                        );
+                        // We don't want to give the other suggestions when the problem is the
+                        // closure return type.
+                        return err;
+                    }
+                }
+
+                // This shouldn't be reachable, but just in case we leave a reasonable fallback.
+                let args = closure_args(&fn_sig);
+                // This suggestion is incomplete, as the user will get further type inference
+                // errors due to the `_` placeholders and the introduction of `Box`, but it does
+                // nudge them in the right direction.
+                format!("a boxed closure type like `Box<dyn Fn({}) -> {}>`", args, ret)
+            }
+            Some(ty) if is_named_and_not_impl_trait(ty) && name == "_" => {
                 let ty = ty_to_string(ty);
-                (format!(" for `{}`", ty),
-                 format!("the explicit type `{}`, with the type parameters specified", ty))
+                format!("the explicit type `{}`, with the type parameters specified", ty)
             }
-            Some(ty) if &ty.to_string() != "_" && ty.to_string() != name => {
+            Some(ty) if is_named_and_not_impl_trait(ty) && ty.to_string() != name => {
                 let ty = ty_to_string(ty);
-                (format!(" for `{}`", ty),
-                 format!(
-                     "the explicit type `{}`, where the type parameter `{}` is specified",
+                format!(
+                    "the explicit type `{}`, where the type parameter `{}` is specified",
                     ty,
                     name,
-                 ))
+                )
             }
-            _ => (String::new(), "a type".to_owned()),
+            _ => "a type".to_string(),
         };
-        let mut labels = vec![(span, InferCtxt::missing_type_msg(&name))];
 
         if let Some(pattern) = local_visitor.found_arg_pattern {
-            err_span = pattern.span;
             // We don't want to show the default label for closures.
             //
             // So, before clearing, the output would look something like this:
@@ -187,39 +305,31 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             //          ^ consider giving this closure parameter the type `[_; 0]`
             //            with the type parameter `_` specified
             // ```
-            labels.clear();
-            labels.push((
+            err.span_label(
                 pattern.span,
                 format!("consider giving this closure parameter {}", suffix),
-            ));
+            );
         } else if let Some(pattern) = local_visitor.found_local_pattern {
-            if let Some(simple_ident) = pattern.simple_ident() {
+            let msg = if let Some(simple_ident) = pattern.simple_ident() {
                 match pattern.span.desugaring_kind() {
-                    None => labels.push((
-                        pattern.span,
-                        format!("consider giving `{}` {}", simple_ident, suffix),
-                    )),
-                    Some(DesugaringKind::ForLoop) => labels.push((
-                        pattern.span,
-                        "the element type for this iterator is not specified".to_owned(),
-                    )),
-                    _ => {}
+                    None => {
+                        format!("consider giving `{}` {}", simple_ident, suffix)
+                    }
+                    Some(DesugaringKind::ForLoop) => {
+                        "the element type for this iterator is not specified".to_string()
+                    }
+                    _ => format!("this needs {}", suffix),
                 }
             } else {
-                labels.push((pattern.span, format!("consider giving this pattern {}", suffix)));
-            }
-        };
-
-        let mut err = struct_span_err!(
-            self.tcx.sess,
-            err_span,
-            E0282,
-            "type annotations needed{}",
-            ty_msg,
-        );
-
-        for (target_span, label_message) in labels {
-            err.span_label(target_span, label_message);
+                format!("consider giving this pattern {}", suffix)
+            };
+            err.span_label(pattern.span, msg);
+        }
+        if !err.span.span_labels().iter().any(|span_label| {
+                span_label.label.is_some() && span_label.span == span
+            }) && local_visitor.found_arg_pattern.is_none()
+        { // Avoid multiple labels pointing at `span`.
+            err.span_label(span, InferCtxt::missing_type_msg(&name));
         }
 
         err
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index 3584a128290..1b73361dcd4 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -1060,7 +1060,7 @@ for LateContextAndPass<'a, 'tcx, T> {
                      v: &'tcx hir::Variant,
                      g: &'tcx hir::Generics,
                      item_id: hir::HirId) {
-        self.with_lint_attrs(v.node.id, &v.node.attrs, |cx| {
+        self.with_lint_attrs(v.id, &v.attrs, |cx| {
             lint_callback!(cx, check_variant, v, g);
             hir_visit::walk_variant(cx, v, g, item_id);
             lint_callback!(cx, check_variant_post, v, g);
@@ -1236,7 +1236,7 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
     }
 
     fn visit_variant(&mut self, v: &'a ast::Variant, g: &'a ast::Generics, item_id: ast::NodeId) {
-        self.with_lint_attrs(item_id, &v.node.attrs, |cx| {
+        self.with_lint_attrs(item_id, &v.attrs, |cx| {
             run_early_pass!(cx, check_variant, v, g);
             ast_visit::walk_variant(cx, v, g, item_id);
             run_early_pass!(cx, check_variant_post, v, g);
diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs
index 8ddf4603490..8cb5b1e26d9 100644
--- a/src/librustc/lint/mod.rs
+++ b/src/librustc/lint/mod.rs
@@ -846,7 +846,7 @@ impl intravisit::Visitor<'tcx> for LintLevelMapBuilder<'tcx> {
                      v: &'tcx hir::Variant,
                      g: &'tcx hir::Generics,
                      item_id: hir::HirId) {
-        self.with_lint_attrs(v.node.id, &v.node.attrs, |builder| {
+        self.with_lint_attrs(v.id, &v.attrs, |builder| {
             intravisit::walk_variant(builder, v, g, item_id);
         })
     }
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index 55fa261f1ed..1f3adf00923 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -366,12 +366,12 @@ impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> {
         match item.node {
             hir::ItemKind::Enum(ref enum_def, _) => {
                 if allow_dead_code {
-                    self.worklist.extend(enum_def.variants.iter().map(|variant| variant.node.id));
+                    self.worklist.extend(enum_def.variants.iter().map(|variant| variant.id));
                 }
 
                 for variant in &enum_def.variants {
-                    if let Some(ctor_hir_id) = variant.node.data.ctor_hir_id() {
-                        self.struct_constructors.insert(ctor_hir_id, variant.node.id);
+                    if let Some(ctor_hir_id) = variant.data.ctor_hir_id() {
+                        self.struct_constructors.insert(ctor_hir_id, variant.id);
                     }
                 }
             }
@@ -497,7 +497,7 @@ impl DeadVisitor<'tcx> {
             && !has_allow_dead_code_or_lang_attr(self.tcx, field.hir_id, &field.attrs)
     }
 
-    fn should_warn_about_variant(&mut self, variant: &hir::VariantKind) -> bool {
+    fn should_warn_about_variant(&mut self, variant: &hir::Variant) -> bool {
         !self.symbol_is_live(variant.id)
             && !has_allow_dead_code_or_lang_attr(self.tcx,
                                                  variant.id,
@@ -596,8 +596,8 @@ impl Visitor<'tcx> for DeadVisitor<'tcx> {
                      variant: &'tcx hir::Variant,
                      g: &'tcx hir::Generics,
                      id: hir::HirId) {
-        if self.should_warn_about_variant(&variant.node) {
-            self.warn_dead_code(variant.node.id, variant.span, variant.node.ident.name,
+        if self.should_warn_about_variant(&variant) {
+            self.warn_dead_code(variant.id, variant.span, variant.ident.name,
                                 "variant", "constructed");
         } else {
             intravisit::walk_variant(self, variant, g, id);
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index 5ab762ab225..d02259bf301 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -290,10 +290,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
     }
 
     fn visit_variant(&mut self, var: &'tcx Variant, g: &'tcx Generics, item_id: HirId) {
-        self.annotate(var.node.id, &var.node.attrs, var.span, AnnotationKind::Required,
+        self.annotate(var.id, &var.attrs, var.span, AnnotationKind::Required,
             |v| {
-                if let Some(ctor_hir_id) = var.node.data.ctor_hir_id() {
-                    v.annotate(ctor_hir_id, &var.node.attrs, var.span, AnnotationKind::Required,
+                if let Some(ctor_hir_id) = var.data.ctor_hir_id() {
+                    v.annotate(ctor_hir_id, &var.attrs, var.span, AnnotationKind::Required,
                                |_| {});
                 }
 
@@ -372,7 +372,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'a, 'tcx> {
     }
 
     fn visit_variant(&mut self, var: &'tcx Variant, g: &'tcx Generics, item_id: HirId) {
-        self.check_missing_stability(var.node.id, var.span, "variant");
+        self.check_missing_stability(var.id, var.span, "variant");
         intravisit::walk_variant(self, var, g, item_id);
     }
 
diff --git a/src/librustc/mir/interpret/pointer.rs b/src/librustc/mir/interpret/pointer.rs
index 0a998513379..b55e6bc54bc 100644
--- a/src/librustc/mir/interpret/pointer.rs
+++ b/src/librustc/mir/interpret/pointer.rs
@@ -189,8 +189,11 @@ impl<'tcx, Tag> Pointer<Tag> {
         Pointer { alloc_id: self.alloc_id, offset: self.offset, tag: () }
     }
 
+    /// Test if the pointer is "inbounds" of an allocation of the given size.
+    /// A pointer is "inbounds" even if its offset is equal to the size; this is
+    /// a "one-past-the-end" pointer.
     #[inline(always)]
-    pub fn check_in_alloc(
+    pub fn check_inbounds_alloc(
         self,
         allocation_size: Size,
         msg: CheckInAllocMsg,
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index 42e367b8518..42390c209d6 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -2068,6 +2068,9 @@ impl<'tcx> TyS<'tcx> {
             Error => {  // ignore errors (#54954)
                 ty::Binder::dummy(FnSig::fake())
             }
+            Closure(..) => bug!(
+                "to get the signature of a closure, use `closure_sig()` not `fn_sig()`",
+            ),
             _ => bug!("Ty::fn_sig() called on non-fn type: {:?}", self)
         }
     }