]> git.lizzy.rs Git - rust.git/commitdiff
Moved all functions prefixed with 'check' to a separate file
authorNicholas-Baron <nicholas.baron.ten@gmail.com>
Sat, 19 Sep 2020 20:51:59 +0000 (13:51 -0700)
committerNicholas-Baron <nicholas.baron.ten@gmail.com>
Mon, 21 Sep 2020 02:00:31 +0000 (19:00 -0700)
compiler/rustc_typeck/src/check/check.rs [new file with mode: 0644]
compiler/rustc_typeck/src/check/mod.rs

diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
new file mode 100644 (file)
index 0000000..2daa035
--- /dev/null
@@ -0,0 +1,1344 @@
+use super::coercion::CoerceMany;
+use super::compare_method::{compare_const_impl, compare_impl_method, compare_ty_impl};
+use super::*;
+
+use rustc_attr as attr;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
+use rustc_hir::lang_items::LangItem;
+use rustc_hir::{ItemKind, Node};
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::RegionVariableOrigin;
+use rustc_middle::ty::fold::TypeFoldable;
+use rustc_middle::ty::subst::GenericArgKind;
+use rustc_middle::ty::util::{Discr, IntTypeExt, Representability};
+use rustc_middle::ty::{self, RegionKind, ToPredicate, Ty, TyCtxt};
+use rustc_session::config::EntryFnType;
+use rustc_span::symbol::sym;
+use rustc_span::{self, MultiSpan, Span};
+use rustc_target::spec::abi::Abi;
+use rustc_trait_selection::traits::{self, ObligationCauseCode};
+
+pub fn check_wf_new(tcx: TyCtxt<'_>) {
+    let visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx);
+    tcx.hir().krate().par_visit_all_item_likes(&visit);
+}
+
+pub(super) fn check_abi(tcx: TyCtxt<'_>, span: Span, abi: Abi) {
+    if !tcx.sess.target.target.is_abi_supported(abi) {
+        struct_span_err!(
+            tcx.sess,
+            span,
+            E0570,
+            "The ABI `{}` is not supported for the current target",
+            abi
+        )
+        .emit()
+    }
+}
+
+/// Helper used for fns and closures. Does the grungy work of checking a function
+/// body and returns the function context used for that purpose, since in the case of a fn item
+/// there is still a bit more to do.
+///
+/// * ...
+/// * inherited: other fields inherited from the enclosing fn (if any)
+pub(super) fn check_fn<'a, 'tcx>(
+    inherited: &'a Inherited<'a, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    fn_sig: ty::FnSig<'tcx>,
+    decl: &'tcx hir::FnDecl<'tcx>,
+    fn_id: hir::HirId,
+    body: &'tcx hir::Body<'tcx>,
+    can_be_generator: Option<hir::Movability>,
+) -> (FnCtxt<'a, 'tcx>, Option<GeneratorTypes<'tcx>>) {
+    let mut fn_sig = fn_sig;
+
+    debug!("check_fn(sig={:?}, fn_id={}, param_env={:?})", fn_sig, fn_id, param_env);
+
+    // Create the function context. This is either derived from scratch or,
+    // in the case of closures, based on the outer context.
+    let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id);
+    *fcx.ps.borrow_mut() = UnsafetyState::function(fn_sig.unsafety, fn_id);
+
+    let tcx = fcx.tcx;
+    let sess = tcx.sess;
+    let hir = tcx.hir();
+
+    let declared_ret_ty = fn_sig.output();
+
+    let revealed_ret_ty =
+        fcx.instantiate_opaque_types_from_value(fn_id, &declared_ret_ty, decl.output.span());
+    debug!("check_fn: declared_ret_ty: {}, revealed_ret_ty: {}", declared_ret_ty, revealed_ret_ty);
+    fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(revealed_ret_ty)));
+    fcx.ret_type_span = Some(decl.output.span());
+    if let ty::Opaque(..) = declared_ret_ty.kind() {
+        fcx.ret_coercion_impl_trait = Some(declared_ret_ty);
+    }
+    fn_sig = tcx.mk_fn_sig(
+        fn_sig.inputs().iter().cloned(),
+        revealed_ret_ty,
+        fn_sig.c_variadic,
+        fn_sig.unsafety,
+        fn_sig.abi,
+    );
+
+    let span = body.value.span;
+
+    fn_maybe_err(tcx, span, fn_sig.abi);
+
+    if body.generator_kind.is_some() && can_be_generator.is_some() {
+        let yield_ty = fcx
+            .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span });
+        fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
+
+        // Resume type defaults to `()` if the generator has no argument.
+        let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| tcx.mk_unit());
+
+        fcx.resume_yield_tys = Some((resume_ty, yield_ty));
+    }
+
+    let outer_def_id = tcx.closure_base_def_id(hir.local_def_id(fn_id).to_def_id()).expect_local();
+    let outer_hir_id = hir.local_def_id_to_hir_id(outer_def_id);
+    GatherLocalsVisitor::new(&fcx, outer_hir_id).visit_body(body);
+
+    // C-variadic fns also have a `VaList` input that's not listed in `fn_sig`
+    // (as it's created inside the body itself, not passed in from outside).
+    let maybe_va_list = if fn_sig.c_variadic {
+        let span = body.params.last().unwrap().span;
+        let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(span));
+        let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span));
+
+        Some(tcx.type_of(va_list_did).subst(tcx, &[region.into()]))
+    } else {
+        None
+    };
+
+    // Add formal parameters.
+    let inputs_hir = hir.fn_decl_by_hir_id(fn_id).map(|decl| &decl.inputs);
+    let inputs_fn = fn_sig.inputs().iter().copied();
+    for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
+        // Check the pattern.
+        let ty_span = try { inputs_hir?.get(idx)?.span };
+        fcx.check_pat_top(&param.pat, param_ty, ty_span, false);
+
+        // Check that argument is Sized.
+        // The check for a non-trivial pattern is a hack to avoid duplicate warnings
+        // for simple cases like `fn foo(x: Trait)`,
+        // where we would error once on the parameter as a whole, and once on the binding `x`.
+        if param.pat.simple_ident().is_none() && !tcx.features().unsized_locals {
+            fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span));
+        }
+
+        fcx.write_ty(param.hir_id, param_ty);
+    }
+
+    inherited.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig);
+
+    fcx.in_tail_expr = true;
+    if let ty::Dynamic(..) = declared_ret_ty.kind() {
+        // FIXME: We need to verify that the return type is `Sized` after the return expression has
+        // been evaluated so that we have types available for all the nodes being returned, but that
+        // requires the coerced evaluated type to be stored. Moving `check_return_expr` before this
+        // causes unsized errors caused by the `declared_ret_ty` to point at the return expression,
+        // while keeping the current ordering we will ignore the tail expression's type because we
+        // don't know it yet. We can't do `check_expr_kind` while keeping `check_return_expr`
+        // because we will trigger "unreachable expression" lints unconditionally.
+        // Because of all of this, we perform a crude check to know whether the simplest `!Sized`
+        // case that a newcomer might make, returning a bare trait, and in that case we populate
+        // the tail expression's type so that the suggestion will be correct, but ignore all other
+        // possible cases.
+        fcx.check_expr(&body.value);
+        fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
+        tcx.sess.delay_span_bug(decl.output.span(), "`!Sized` return type");
+    } else {
+        fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
+        fcx.check_return_expr(&body.value);
+    }
+    fcx.in_tail_expr = false;
+
+    // We insert the deferred_generator_interiors entry after visiting the body.
+    // This ensures that all nested generators appear before the entry of this generator.
+    // resolve_generator_interiors relies on this property.
+    let gen_ty = if let (Some(_), Some(gen_kind)) = (can_be_generator, body.generator_kind) {
+        let interior = fcx
+            .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span });
+        fcx.deferred_generator_interiors.borrow_mut().push((body.id(), interior, gen_kind));
+
+        let (resume_ty, yield_ty) = fcx.resume_yield_tys.unwrap();
+        Some(GeneratorTypes {
+            resume_ty,
+            yield_ty,
+            interior,
+            movability: can_be_generator.unwrap(),
+        })
+    } else {
+        None
+    };
+
+    // Finalize the return check by taking the LUB of the return types
+    // we saw and assigning it to the expected return type. This isn't
+    // really expected to fail, since the coercions would have failed
+    // earlier when trying to find a LUB.
+    //
+    // However, the behavior around `!` is sort of complex. In the
+    // event that the `actual_return_ty` comes back as `!`, that
+    // indicates that the fn either does not return or "returns" only
+    // values of type `!`. In this case, if there is an expected
+    // return type that is *not* `!`, that should be ok. But if the
+    // return type is being inferred, we want to "fallback" to `!`:
+    //
+    //     let x = move || panic!();
+    //
+    // To allow for that, I am creating a type variable with diverging
+    // fallback. This was deemed ever so slightly better than unifying
+    // the return value with `!` because it allows for the caller to
+    // make more assumptions about the return type (e.g., they could do
+    //
+    //     let y: Option<u32> = Some(x());
+    //
+    // which would then cause this return type to become `u32`, not
+    // `!`).
+    let coercion = fcx.ret_coercion.take().unwrap().into_inner();
+    let mut actual_return_ty = coercion.complete(&fcx);
+    if actual_return_ty.is_never() {
+        actual_return_ty = fcx.next_diverging_ty_var(TypeVariableOrigin {
+            kind: TypeVariableOriginKind::DivergingFn,
+            span,
+        });
+    }
+    fcx.demand_suptype(span, revealed_ret_ty, actual_return_ty);
+
+    // Check that the main return type implements the termination trait.
+    if let Some(term_id) = tcx.lang_items().termination() {
+        if let Some((def_id, EntryFnType::Main)) = tcx.entry_fn(LOCAL_CRATE) {
+            let main_id = hir.local_def_id_to_hir_id(def_id);
+            if main_id == fn_id {
+                let substs = tcx.mk_substs_trait(declared_ret_ty, &[]);
+                let trait_ref = ty::TraitRef::new(term_id, substs);
+                let return_ty_span = decl.output.span();
+                let cause = traits::ObligationCause::new(
+                    return_ty_span,
+                    fn_id,
+                    ObligationCauseCode::MainFunctionType,
+                );
+
+                inherited.register_predicate(traits::Obligation::new(
+                    cause,
+                    param_env,
+                    trait_ref.without_const().to_predicate(tcx),
+                ));
+            }
+        }
+    }
+
+    // Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !`
+    if let Some(panic_impl_did) = tcx.lang_items().panic_impl() {
+        if panic_impl_did == hir.local_def_id(fn_id).to_def_id() {
+            if let Some(panic_info_did) = tcx.lang_items().panic_info() {
+                if *declared_ret_ty.kind() != ty::Never {
+                    sess.span_err(decl.output.span(), "return type should be `!`");
+                }
+
+                let inputs = fn_sig.inputs();
+                let span = hir.span(fn_id);
+                if inputs.len() == 1 {
+                    let arg_is_panic_info = match *inputs[0].kind() {
+                        ty::Ref(region, ty, mutbl) => match *ty.kind() {
+                            ty::Adt(ref adt, _) => {
+                                adt.did == panic_info_did
+                                    && mutbl == hir::Mutability::Not
+                                    && *region != RegionKind::ReStatic
+                            }
+                            _ => false,
+                        },
+                        _ => false,
+                    };
+
+                    if !arg_is_panic_info {
+                        sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`");
+                    }
+
+                    if let Node::Item(item) = hir.get(fn_id) {
+                        if let ItemKind::Fn(_, ref generics, _) = item.kind {
+                            if !generics.params.is_empty() {
+                                sess.span_err(span, "should have no type parameters");
+                            }
+                        }
+                    }
+                } else {
+                    let span = sess.source_map().guess_head_span(span);
+                    sess.span_err(span, "function should have one argument");
+                }
+            } else {
+                sess.err("language item required, but not found: `panic_info`");
+            }
+        }
+    }
+
+    // Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !`
+    if let Some(alloc_error_handler_did) = tcx.lang_items().oom() {
+        if alloc_error_handler_did == hir.local_def_id(fn_id).to_def_id() {
+            if let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() {
+                if *declared_ret_ty.kind() != ty::Never {
+                    sess.span_err(decl.output.span(), "return type should be `!`");
+                }
+
+                let inputs = fn_sig.inputs();
+                let span = hir.span(fn_id);
+                if inputs.len() == 1 {
+                    let arg_is_alloc_layout = match inputs[0].kind() {
+                        ty::Adt(ref adt, _) => adt.did == alloc_layout_did,
+                        _ => false,
+                    };
+
+                    if !arg_is_alloc_layout {
+                        sess.span_err(decl.inputs[0].span, "argument should be `Layout`");
+                    }
+
+                    if let Node::Item(item) = hir.get(fn_id) {
+                        if let ItemKind::Fn(_, ref generics, _) = item.kind {
+                            if !generics.params.is_empty() {
+                                sess.span_err(
+                                    span,
+                                    "`#[alloc_error_handler]` function should have no type \
+                                     parameters",
+                                );
+                            }
+                        }
+                    }
+                } else {
+                    let span = sess.source_map().guess_head_span(span);
+                    sess.span_err(span, "function should have one argument");
+                }
+            } else {
+                sess.err("language item required, but not found: `alloc_layout`");
+            }
+        }
+    }
+
+    (fcx, gen_ty)
+}
+
+pub(super) fn check_struct(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) {
+    let def_id = tcx.hir().local_def_id(id);
+    let def = tcx.adt_def(def_id);
+    def.destructor(tcx); // force the destructor to be evaluated
+    check_representable(tcx, span, def_id);
+
+    if def.repr.simd() {
+        check_simd(tcx, span, def_id);
+    }
+
+    check_transparent(tcx, span, def);
+    check_packed(tcx, span, def);
+}
+
+pub(super) fn check_union(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) {
+    let def_id = tcx.hir().local_def_id(id);
+    let def = tcx.adt_def(def_id);
+    def.destructor(tcx); // force the destructor to be evaluated
+    check_representable(tcx, span, def_id);
+    check_transparent(tcx, span, def);
+    check_union_fields(tcx, span, def_id);
+    check_packed(tcx, span, def);
+}
+
+/// When the `#![feature(untagged_unions)]` gate is active,
+/// check that the fields of the `union` does not contain fields that need dropping.
+pub(super) fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> bool {
+    let item_type = tcx.type_of(item_def_id);
+    if let ty::Adt(def, substs) = item_type.kind() {
+        assert!(def.is_union());
+        let fields = &def.non_enum_variant().fields;
+        let param_env = tcx.param_env(item_def_id);
+        for field in fields {
+            let field_ty = field.ty(tcx, substs);
+            // We are currently checking the type this field came from, so it must be local.
+            let field_span = tcx.hir().span_if_local(field.did).unwrap();
+            if field_ty.needs_drop(tcx, param_env) {
+                struct_span_err!(
+                    tcx.sess,
+                    field_span,
+                    E0740,
+                    "unions may not contain fields that need dropping"
+                )
+                .span_note(field_span, "`std::mem::ManuallyDrop` can be used to wrap the type")
+                .emit();
+                return false;
+            }
+        }
+    } else {
+        span_bug!(span, "unions must be ty::Adt, but got {:?}", item_type.kind());
+    }
+    true
+}
+
+/// Checks that an opaque type does not contain cycles and does not use `Self` or `T::Foo`
+/// projections that would result in "inheriting lifetimes".
+pub(super) fn check_opaque<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: LocalDefId,
+    substs: SubstsRef<'tcx>,
+    span: Span,
+    origin: &hir::OpaqueTyOrigin,
+) {
+    check_opaque_for_inheriting_lifetimes(tcx, def_id, span);
+    check_opaque_for_cycles(tcx, def_id, substs, span, origin);
+}
+
+/// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result
+/// in "inheriting lifetimes".
+pub(super) fn check_opaque_for_inheriting_lifetimes(
+    tcx: TyCtxt<'tcx>,
+    def_id: LocalDefId,
+    span: Span,
+) {
+    let item = tcx.hir().expect_item(tcx.hir().local_def_id_to_hir_id(def_id));
+    debug!(
+        "check_opaque_for_inheriting_lifetimes: def_id={:?} span={:?} item={:?}",
+        def_id, span, item
+    );
+
+    #[derive(Debug)]
+    struct ProhibitOpaqueVisitor<'tcx> {
+        opaque_identity_ty: Ty<'tcx>,
+        generics: &'tcx ty::Generics,
+        ty: Option<Ty<'tcx>>,
+    };
+
+    impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
+        fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
+            debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t);
+            if t != self.opaque_identity_ty && t.super_visit_with(self) {
+                self.ty = Some(t);
+                return true;
+            }
+            false
+        }
+
+        fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
+            debug!("check_opaque_for_inheriting_lifetimes: (visit_region) r={:?}", r);
+            if let RegionKind::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = r {
+                return *index < self.generics.parent_count as u32;
+            }
+
+            r.super_visit_with(self)
+        }
+
+        fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool {
+            if let ty::ConstKind::Unevaluated(..) = c.val {
+                // FIXME(#72219) We currenctly don't detect lifetimes within substs
+                // which would violate this check. Even though the particular substitution is not used
+                // within the const, this should still be fixed.
+                return false;
+            }
+            c.super_visit_with(self)
+        }
+    }
+
+    if let ItemKind::OpaqueTy(hir::OpaqueTy {
+        origin: hir::OpaqueTyOrigin::AsyncFn | hir::OpaqueTyOrigin::FnReturn,
+        ..
+    }) = item.kind
+    {
+        let mut visitor = ProhibitOpaqueVisitor {
+            opaque_identity_ty: tcx.mk_opaque(
+                def_id.to_def_id(),
+                InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
+            ),
+            generics: tcx.generics_of(def_id),
+            ty: None,
+        };
+        let prohibit_opaque = tcx
+            .predicates_of(def_id)
+            .predicates
+            .iter()
+            .any(|(predicate, _)| predicate.visit_with(&mut visitor));
+        debug!(
+            "check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor={:?}",
+            prohibit_opaque, visitor
+        );
+
+        if prohibit_opaque {
+            let is_async = match item.kind {
+                ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => match origin {
+                    hir::OpaqueTyOrigin::AsyncFn => true,
+                    _ => false,
+                },
+                _ => unreachable!(),
+            };
+
+            let mut err = struct_span_err!(
+                tcx.sess,
+                span,
+                E0760,
+                "`{}` return type cannot contain a projection or `Self` that references lifetimes from \
+             a parent scope",
+                if is_async { "async fn" } else { "impl Trait" },
+            );
+
+            if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) {
+                if snippet == "Self" {
+                    if let Some(ty) = visitor.ty {
+                        err.span_suggestion(
+                            span,
+                            "consider spelling out the type instead",
+                            format!("{:?}", ty),
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                }
+            }
+            err.emit();
+        }
+    }
+}
+
+/// Checks that an opaque type does not contain cycles.
+pub(super) fn check_opaque_for_cycles<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: LocalDefId,
+    substs: SubstsRef<'tcx>,
+    span: Span,
+    origin: &hir::OpaqueTyOrigin,
+) {
+    if let Err(partially_expanded_type) = tcx.try_expand_impl_trait_type(def_id.to_def_id(), substs)
+    {
+        match origin {
+            hir::OpaqueTyOrigin::AsyncFn => async_opaque_type_cycle_error(tcx, span),
+            hir::OpaqueTyOrigin::Binding => {
+                binding_opaque_type_cycle_error(tcx, def_id, span, partially_expanded_type)
+            }
+            _ => opaque_type_cycle_error(tcx, def_id, span),
+        }
+    }
+}
+
+pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) {
+    debug!(
+        "check_item_type(it.hir_id={}, it.name={})",
+        it.hir_id,
+        tcx.def_path_str(tcx.hir().local_def_id(it.hir_id).to_def_id())
+    );
+    let _indenter = indenter();
+    match it.kind {
+        // Consts can play a role in type-checking, so they are included here.
+        hir::ItemKind::Static(..) => {
+            let def_id = tcx.hir().local_def_id(it.hir_id);
+            tcx.ensure().typeck(def_id);
+            maybe_check_static_with_link_section(tcx, def_id, it.span);
+        }
+        hir::ItemKind::Const(..) => {
+            tcx.ensure().typeck(tcx.hir().local_def_id(it.hir_id));
+        }
+        hir::ItemKind::Enum(ref enum_definition, _) => {
+            check_enum(tcx, it.span, &enum_definition.variants, it.hir_id);
+        }
+        hir::ItemKind::Fn(..) => {} // entirely within check_item_body
+        hir::ItemKind::Impl { ref items, .. } => {
+            debug!("ItemKind::Impl {} with id {}", it.ident, it.hir_id);
+            let impl_def_id = tcx.hir().local_def_id(it.hir_id);
+            if let Some(impl_trait_ref) = tcx.impl_trait_ref(impl_def_id) {
+                check_impl_items_against_trait(tcx, it.span, impl_def_id, impl_trait_ref, items);
+                let trait_def_id = impl_trait_ref.def_id;
+                check_on_unimplemented(tcx, trait_def_id, it);
+            }
+        }
+        hir::ItemKind::Trait(_, _, _, _, ref items) => {
+            let def_id = tcx.hir().local_def_id(it.hir_id);
+            check_on_unimplemented(tcx, def_id.to_def_id(), it);
+
+            for item in items.iter() {
+                let item = tcx.hir().trait_item(item.id);
+                if let hir::TraitItemKind::Fn(sig, _) = &item.kind {
+                    let abi = sig.header.abi;
+                    fn_maybe_err(tcx, item.ident.span, abi);
+                }
+            }
+        }
+        hir::ItemKind::Struct(..) => {
+            check_struct(tcx, it.hir_id, it.span);
+        }
+        hir::ItemKind::Union(..) => {
+            check_union(tcx, it.hir_id, it.span);
+        }
+        hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => {
+            // HACK(jynelson): trying to infer the type of `impl trait` breaks documenting
+            // `async-std` (and `pub async fn` in general).
+            // Since rustdoc doesn't care about the concrete type behind `impl Trait`, just don't look at it!
+            // See https://github.com/rust-lang/rust/issues/75100
+            if !tcx.sess.opts.actually_rustdoc {
+                let def_id = tcx.hir().local_def_id(it.hir_id);
+
+                let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
+                check_opaque(tcx, def_id, substs, it.span, &origin);
+            }
+        }
+        hir::ItemKind::TyAlias(..) => {
+            let def_id = tcx.hir().local_def_id(it.hir_id);
+            let pty_ty = tcx.type_of(def_id);
+            let generics = tcx.generics_of(def_id);
+            check_type_params_are_used(tcx, &generics, pty_ty);
+        }
+        hir::ItemKind::ForeignMod(ref m) => {
+            check_abi(tcx, it.span, m.abi);
+
+            if m.abi == Abi::RustIntrinsic {
+                for item in m.items {
+                    intrinsic::check_intrinsic_type(tcx, item);
+                }
+            } else if m.abi == Abi::PlatformIntrinsic {
+                for item in m.items {
+                    intrinsic::check_platform_intrinsic_type(tcx, item);
+                }
+            } else {
+                for item in m.items {
+                    let generics = tcx.generics_of(tcx.hir().local_def_id(item.hir_id));
+                    let own_counts = generics.own_counts();
+                    if generics.params.len() - own_counts.lifetimes != 0 {
+                        let (kinds, kinds_pl, egs) = match (own_counts.types, own_counts.consts) {
+                            (_, 0) => ("type", "types", Some("u32")),
+                            // We don't specify an example value, because we can't generate
+                            // a valid value for any type.
+                            (0, _) => ("const", "consts", None),
+                            _ => ("type or const", "types or consts", None),
+                        };
+                        struct_span_err!(
+                            tcx.sess,
+                            item.span,
+                            E0044,
+                            "foreign items may not have {} parameters",
+                            kinds,
+                        )
+                        .span_label(item.span, &format!("can't have {} parameters", kinds))
+                        .help(
+                            // FIXME: once we start storing spans for type arguments, turn this
+                            // into a suggestion.
+                            &format!(
+                                "replace the {} parameters with concrete {}{}",
+                                kinds,
+                                kinds_pl,
+                                egs.map(|egs| format!(" like `{}`", egs)).unwrap_or_default(),
+                            ),
+                        )
+                        .emit();
+                    }
+
+                    if let hir::ForeignItemKind::Fn(ref fn_decl, _, _) = item.kind {
+                        require_c_abi_if_c_variadic(tcx, fn_decl, m.abi, item.span);
+                    }
+                }
+            }
+        }
+        _ => { /* nothing to do */ }
+    }
+}
+
+pub(super) fn check_on_unimplemented(tcx: TyCtxt<'_>, trait_def_id: DefId, item: &hir::Item<'_>) {
+    let item_def_id = tcx.hir().local_def_id(item.hir_id);
+    // an error would be reported if this fails.
+    let _ = traits::OnUnimplementedDirective::of_item(tcx, trait_def_id, item_def_id.to_def_id());
+}
+
+pub(super) fn check_specialization_validity<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    trait_def: &ty::TraitDef,
+    trait_item: &ty::AssocItem,
+    impl_id: DefId,
+    impl_item: &hir::ImplItem<'_>,
+) {
+    let kind = match impl_item.kind {
+        hir::ImplItemKind::Const(..) => ty::AssocKind::Const,
+        hir::ImplItemKind::Fn(..) => ty::AssocKind::Fn,
+        hir::ImplItemKind::TyAlias(_) => ty::AssocKind::Type,
+    };
+
+    let ancestors = match trait_def.ancestors(tcx, impl_id) {
+        Ok(ancestors) => ancestors,
+        Err(_) => return,
+    };
+    let mut ancestor_impls = ancestors
+        .skip(1)
+        .filter_map(|parent| {
+            if parent.is_from_trait() {
+                None
+            } else {
+                Some((parent, parent.item(tcx, trait_item.ident, kind, trait_def.def_id)))
+            }
+        })
+        .peekable();
+
+    if ancestor_impls.peek().is_none() {
+        // No parent, nothing to specialize.
+        return;
+    }
+
+    let opt_result = ancestor_impls.find_map(|(parent_impl, parent_item)| {
+        match parent_item {
+            // Parent impl exists, and contains the parent item we're trying to specialize, but
+            // doesn't mark it `default`.
+            Some(parent_item) if traits::impl_item_is_final(tcx, &parent_item) => {
+                Some(Err(parent_impl.def_id()))
+            }
+
+            // Parent impl contains item and makes it specializable.
+            Some(_) => Some(Ok(())),
+
+            // Parent impl doesn't mention the item. This means it's inherited from the
+            // grandparent. In that case, if parent is a `default impl`, inherited items use the
+            // "defaultness" from the grandparent, else they are final.
+            None => {
+                if tcx.impl_defaultness(parent_impl.def_id()).is_default() {
+                    None
+                } else {
+                    Some(Err(parent_impl.def_id()))
+                }
+            }
+        }
+    });
+
+    // If `opt_result` is `None`, we have only encountered `default impl`s that don't contain the
+    // item. This is allowed, the item isn't actually getting specialized here.
+    let result = opt_result.unwrap_or(Ok(()));
+
+    if let Err(parent_impl) = result {
+        report_forbidden_specialization(tcx, impl_item, parent_impl);
+    }
+}
+
+pub(super) fn check_impl_items_against_trait<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    full_impl_span: Span,
+    impl_id: LocalDefId,
+    impl_trait_ref: ty::TraitRef<'tcx>,
+    impl_item_refs: &[hir::ImplItemRef<'_>],
+) {
+    let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span);
+
+    // If the trait reference itself is erroneous (so the compilation is going
+    // to fail), skip checking the items here -- the `impl_item` table in `tcx`
+    // isn't populated for such impls.
+    if impl_trait_ref.references_error() {
+        return;
+    }
+
+    // Negative impls are not expected to have any items
+    match tcx.impl_polarity(impl_id) {
+        ty::ImplPolarity::Reservation | ty::ImplPolarity::Positive => {}
+        ty::ImplPolarity::Negative => {
+            if let [first_item_ref, ..] = impl_item_refs {
+                let first_item_span = tcx.hir().impl_item(first_item_ref.id).span;
+                struct_span_err!(
+                    tcx.sess,
+                    first_item_span,
+                    E0749,
+                    "negative impls cannot have any items"
+                )
+                .emit();
+            }
+            return;
+        }
+    }
+
+    // Locate trait definition and items
+    let trait_def = tcx.trait_def(impl_trait_ref.def_id);
+
+    let impl_items = || impl_item_refs.iter().map(|iiref| tcx.hir().impl_item(iiref.id));
+
+    // Check existing impl methods to see if they are both present in trait
+    // and compatible with trait signature
+    for impl_item in impl_items() {
+        let namespace = impl_item.kind.namespace();
+        let ty_impl_item = tcx.associated_item(tcx.hir().local_def_id(impl_item.hir_id));
+        let ty_trait_item = tcx
+            .associated_items(impl_trait_ref.def_id)
+            .find_by_name_and_namespace(tcx, ty_impl_item.ident, namespace, impl_trait_ref.def_id)
+            .or_else(|| {
+                // Not compatible, but needed for the error message
+                tcx.associated_items(impl_trait_ref.def_id)
+                    .filter_by_name(tcx, ty_impl_item.ident, impl_trait_ref.def_id)
+                    .next()
+            });
+
+        // Check that impl definition matches trait definition
+        if let Some(ty_trait_item) = ty_trait_item {
+            match impl_item.kind {
+                hir::ImplItemKind::Const(..) => {
+                    // Find associated const definition.
+                    if ty_trait_item.kind == ty::AssocKind::Const {
+                        compare_const_impl(
+                            tcx,
+                            &ty_impl_item,
+                            impl_item.span,
+                            &ty_trait_item,
+                            impl_trait_ref,
+                        );
+                    } else {
+                        let mut err = struct_span_err!(
+                            tcx.sess,
+                            impl_item.span,
+                            E0323,
+                            "item `{}` is an associated const, \
+                             which doesn't match its trait `{}`",
+                            ty_impl_item.ident,
+                            impl_trait_ref.print_only_trait_path()
+                        );
+                        err.span_label(impl_item.span, "does not match trait");
+                        // We can only get the spans from local trait definition
+                        // Same for E0324 and E0325
+                        if let Some(trait_span) = tcx.hir().span_if_local(ty_trait_item.def_id) {
+                            err.span_label(trait_span, "item in trait");
+                        }
+                        err.emit()
+                    }
+                }
+                hir::ImplItemKind::Fn(..) => {
+                    let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
+                    if ty_trait_item.kind == ty::AssocKind::Fn {
+                        compare_impl_method(
+                            tcx,
+                            &ty_impl_item,
+                            impl_item.span,
+                            &ty_trait_item,
+                            impl_trait_ref,
+                            opt_trait_span,
+                        );
+                    } else {
+                        let mut err = struct_span_err!(
+                            tcx.sess,
+                            impl_item.span,
+                            E0324,
+                            "item `{}` is an associated method, \
+                             which doesn't match its trait `{}`",
+                            ty_impl_item.ident,
+                            impl_trait_ref.print_only_trait_path()
+                        );
+                        err.span_label(impl_item.span, "does not match trait");
+                        if let Some(trait_span) = opt_trait_span {
+                            err.span_label(trait_span, "item in trait");
+                        }
+                        err.emit()
+                    }
+                }
+                hir::ImplItemKind::TyAlias(_) => {
+                    let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
+                    if ty_trait_item.kind == ty::AssocKind::Type {
+                        compare_ty_impl(
+                            tcx,
+                            &ty_impl_item,
+                            impl_item.span,
+                            &ty_trait_item,
+                            impl_trait_ref,
+                            opt_trait_span,
+                        );
+                    } else {
+                        let mut err = struct_span_err!(
+                            tcx.sess,
+                            impl_item.span,
+                            E0325,
+                            "item `{}` is an associated type, \
+                             which doesn't match its trait `{}`",
+                            ty_impl_item.ident,
+                            impl_trait_ref.print_only_trait_path()
+                        );
+                        err.span_label(impl_item.span, "does not match trait");
+                        if let Some(trait_span) = opt_trait_span {
+                            err.span_label(trait_span, "item in trait");
+                        }
+                        err.emit()
+                    }
+                }
+            }
+
+            check_specialization_validity(
+                tcx,
+                trait_def,
+                &ty_trait_item,
+                impl_id.to_def_id(),
+                impl_item,
+            );
+        }
+    }
+
+    // Check for missing items from trait
+    let mut missing_items = Vec::new();
+    if let Ok(ancestors) = trait_def.ancestors(tcx, impl_id.to_def_id()) {
+        for trait_item in tcx.associated_items(impl_trait_ref.def_id).in_definition_order() {
+            let is_implemented = ancestors
+                .leaf_def(tcx, trait_item.ident, trait_item.kind)
+                .map(|node_item| !node_item.defining_node.is_from_trait())
+                .unwrap_or(false);
+
+            if !is_implemented && tcx.impl_defaultness(impl_id).is_final() {
+                if !trait_item.defaultness.has_value() {
+                    missing_items.push(*trait_item);
+                }
+            }
+        }
+    }
+
+    if !missing_items.is_empty() {
+        missing_items_err(tcx, impl_span, &missing_items, full_impl_span);
+    }
+}
+
+/// Checks whether a type can be represented in memory. In particular, it
+/// identifies types that contain themselves without indirection through a
+/// pointer, which would mean their size is unbounded.
+pub(super) fn check_representable(tcx: TyCtxt<'_>, sp: Span, item_def_id: LocalDefId) -> bool {
+    let rty = tcx.type_of(item_def_id);
+
+    // Check that it is possible to represent this type. This call identifies
+    // (1) types that contain themselves and (2) types that contain a different
+    // recursive type. It is only necessary to throw an error on those that
+    // contain themselves. For case 2, there must be an inner type that will be
+    // caught by case 1.
+    match rty.is_representable(tcx, sp) {
+        Representability::SelfRecursive(spans) => {
+            recursive_type_with_infinite_size_error(tcx, item_def_id.to_def_id(), spans);
+            return false;
+        }
+        Representability::Representable | Representability::ContainsRecursive => (),
+    }
+    true
+}
+
+pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
+    let t = tcx.type_of(def_id);
+    if let ty::Adt(def, substs) = t.kind() {
+        if def.is_struct() {
+            let fields = &def.non_enum_variant().fields;
+            if fields.is_empty() {
+                struct_span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty").emit();
+                return;
+            }
+            let e = fields[0].ty(tcx, substs);
+            if !fields.iter().all(|f| f.ty(tcx, substs) == e) {
+                struct_span_err!(tcx.sess, sp, E0076, "SIMD vector should be homogeneous")
+                    .span_label(sp, "SIMD elements must have the same type")
+                    .emit();
+                return;
+            }
+            match e.kind() {
+                ty::Param(_) => { /* struct<T>(T, T, T, T) is ok */ }
+                _ if e.is_machine() => { /* struct(u8, u8, u8, u8) is ok */ }
+                _ => {
+                    struct_span_err!(
+                        tcx.sess,
+                        sp,
+                        E0077,
+                        "SIMD vector element type should be machine type"
+                    )
+                    .emit();
+                    return;
+                }
+            }
+        }
+    }
+}
+
+pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: &ty::AdtDef) {
+    let repr = def.repr;
+    if repr.packed() {
+        for attr in tcx.get_attrs(def.did).iter() {
+            for r in attr::find_repr_attrs(&tcx.sess, attr) {
+                if let attr::ReprPacked(pack) = r {
+                    if let Some(repr_pack) = repr.pack {
+                        if pack as u64 != repr_pack.bytes() {
+                            struct_span_err!(
+                                tcx.sess,
+                                sp,
+                                E0634,
+                                "type has conflicting packed representation hints"
+                            )
+                            .emit();
+                        }
+                    }
+                }
+            }
+        }
+        if repr.align.is_some() {
+            struct_span_err!(
+                tcx.sess,
+                sp,
+                E0587,
+                "type has conflicting packed and align representation hints"
+            )
+            .emit();
+        } else {
+            if let Some(def_spans) = check_packed_inner(tcx, def.did, &mut vec![]) {
+                let mut err = struct_span_err!(
+                    tcx.sess,
+                    sp,
+                    E0588,
+                    "packed type cannot transitively contain a `#[repr(align)]` type"
+                );
+
+                err.span_note(
+                    tcx.def_span(def_spans[0].0),
+                    &format!(
+                        "`{}` has a `#[repr(align)]` attribute",
+                        tcx.item_name(def_spans[0].0)
+                    ),
+                );
+
+                if def_spans.len() > 2 {
+                    let mut first = true;
+                    for (adt_def, span) in def_spans.iter().skip(1).rev() {
+                        let ident = tcx.item_name(*adt_def);
+                        err.span_note(
+                            *span,
+                            &if first {
+                                format!(
+                                    "`{}` contains a field of type `{}`",
+                                    tcx.type_of(def.did),
+                                    ident
+                                )
+                            } else {
+                                format!("...which contains a field of type `{}`", ident)
+                            },
+                        );
+                        first = false;
+                    }
+                }
+
+                err.emit();
+            }
+        }
+    }
+}
+
+pub(super) fn check_packed_inner(
+    tcx: TyCtxt<'_>,
+    def_id: DefId,
+    stack: &mut Vec<DefId>,
+) -> Option<Vec<(DefId, Span)>> {
+    if let ty::Adt(def, substs) = tcx.type_of(def_id).kind() {
+        if def.is_struct() || def.is_union() {
+            if def.repr.align.is_some() {
+                return Some(vec![(def.did, DUMMY_SP)]);
+            }
+
+            stack.push(def_id);
+            for field in &def.non_enum_variant().fields {
+                if let ty::Adt(def, _) = field.ty(tcx, substs).kind() {
+                    if !stack.contains(&def.did) {
+                        if let Some(mut defs) = check_packed_inner(tcx, def.did, stack) {
+                            defs.push((def.did, field.ident.span));
+                            return Some(defs);
+                        }
+                    }
+                }
+            }
+            stack.pop();
+        }
+    }
+
+    None
+}
+
+pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: &'tcx ty::AdtDef) {
+    if !adt.repr.transparent() {
+        return;
+    }
+    let sp = tcx.sess.source_map().guess_head_span(sp);
+
+    if adt.is_union() && !tcx.features().transparent_unions {
+        feature_err(
+            &tcx.sess.parse_sess,
+            sym::transparent_unions,
+            sp,
+            "transparent unions are unstable",
+        )
+        .emit();
+    }
+
+    if adt.variants.len() != 1 {
+        bad_variant_count(tcx, adt, sp, adt.did);
+        if adt.variants.is_empty() {
+            // Don't bother checking the fields. No variants (and thus no fields) exist.
+            return;
+        }
+    }
+
+    // For each field, figure out if it's known to be a ZST and align(1)
+    let field_infos = adt.all_fields().map(|field| {
+        let ty = field.ty(tcx, InternalSubsts::identity_for_item(tcx, field.did));
+        let param_env = tcx.param_env(field.did);
+        let layout = tcx.layout_of(param_env.and(ty));
+        // We are currently checking the type this field came from, so it must be local
+        let span = tcx.hir().span_if_local(field.did).unwrap();
+        let zst = layout.map(|layout| layout.is_zst()).unwrap_or(false);
+        let align1 = layout.map(|layout| layout.align.abi.bytes() == 1).unwrap_or(false);
+        (span, zst, align1)
+    });
+
+    let non_zst_fields =
+        field_infos.clone().filter_map(|(span, zst, _align1)| if !zst { Some(span) } else { None });
+    let non_zst_count = non_zst_fields.clone().count();
+    if non_zst_count != 1 {
+        bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, sp);
+    }
+    for (span, zst, align1) in field_infos {
+        if zst && !align1 {
+            struct_span_err!(
+                tcx.sess,
+                span,
+                E0691,
+                "zero-sized field in transparent {} has alignment larger than 1",
+                adt.descr(),
+            )
+            .span_label(span, "has alignment larger than 1")
+            .emit();
+        }
+    }
+}
+
+#[allow(trivial_numeric_casts)]
+pub fn check_enum<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    sp: Span,
+    vs: &'tcx [hir::Variant<'tcx>],
+    id: hir::HirId,
+) {
+    let def_id = tcx.hir().local_def_id(id);
+    let def = tcx.adt_def(def_id);
+    def.destructor(tcx); // force the destructor to be evaluated
+
+    if vs.is_empty() {
+        let attributes = tcx.get_attrs(def_id.to_def_id());
+        if let Some(attr) = tcx.sess.find_by_name(&attributes, sym::repr) {
+            struct_span_err!(
+                tcx.sess,
+                attr.span,
+                E0084,
+                "unsupported representation for zero-variant enum"
+            )
+            .span_label(sp, "zero-variant enum")
+            .emit();
+        }
+    }
+
+    let repr_type_ty = def.repr.discr_type().to_ty(tcx);
+    if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 {
+        if !tcx.features().repr128 {
+            feature_err(
+                &tcx.sess.parse_sess,
+                sym::repr128,
+                sp,
+                "repr with 128-bit type is unstable",
+            )
+            .emit();
+        }
+    }
+
+    for v in vs {
+        if let Some(ref e) = v.disr_expr {
+            tcx.ensure().typeck(tcx.hir().local_def_id(e.hir_id));
+        }
+    }
+
+    if tcx.adt_def(def_id).repr.int.is_none() && tcx.features().arbitrary_enum_discriminant {
+        let is_unit = |var: &hir::Variant<'_>| match var.data {
+            hir::VariantData::Unit(..) => true,
+            _ => false,
+        };
+
+        let has_disr = |var: &hir::Variant<'_>| var.disr_expr.is_some();
+        let has_non_units = vs.iter().any(|var| !is_unit(var));
+        let disr_units = vs.iter().any(|var| is_unit(&var) && has_disr(&var));
+        let disr_non_unit = vs.iter().any(|var| !is_unit(&var) && has_disr(&var));
+
+        if disr_non_unit || (disr_units && has_non_units) {
+            let mut err =
+                struct_span_err!(tcx.sess, sp, E0732, "`#[repr(inttype)]` must be specified");
+            err.emit();
+        }
+    }
+
+    let mut disr_vals: Vec<Discr<'tcx>> = Vec::with_capacity(vs.len());
+    for ((_, discr), v) in def.discriminants(tcx).zip(vs) {
+        // Check for duplicate discriminant values
+        if let Some(i) = disr_vals.iter().position(|&x| x.val == discr.val) {
+            let variant_did = def.variants[VariantIdx::new(i)].def_id;
+            let variant_i_hir_id = tcx.hir().local_def_id_to_hir_id(variant_did.expect_local());
+            let variant_i = tcx.hir().expect_variant(variant_i_hir_id);
+            let i_span = match variant_i.disr_expr {
+                Some(ref expr) => tcx.hir().span(expr.hir_id),
+                None => tcx.hir().span(variant_i_hir_id),
+            };
+            let span = match v.disr_expr {
+                Some(ref expr) => tcx.hir().span(expr.hir_id),
+                None => v.span,
+            };
+            struct_span_err!(
+                tcx.sess,
+                span,
+                E0081,
+                "discriminant value `{}` already exists",
+                disr_vals[i]
+            )
+            .span_label(i_span, format!("first use of `{}`", disr_vals[i]))
+            .span_label(span, format!("enum already has `{}`", disr_vals[i]))
+            .emit();
+        }
+        disr_vals.push(discr);
+    }
+
+    check_representable(tcx, sp, def_id);
+    check_transparent(tcx, sp, def);
+}
+
+pub(super) fn check_type_params_are_used<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    generics: &ty::Generics,
+    ty: Ty<'tcx>,
+) {
+    debug!("check_type_params_are_used(generics={:?}, ty={:?})", generics, ty);
+
+    assert_eq!(generics.parent, None);
+
+    if generics.own_counts().types == 0 {
+        return;
+    }
+
+    let mut params_used = BitSet::new_empty(generics.params.len());
+
+    if ty.references_error() {
+        // If there is already another error, do not emit
+        // an error for not using a type parameter.
+        assert!(tcx.sess.has_errors());
+        return;
+    }
+
+    for leaf in ty.walk() {
+        if let GenericArgKind::Type(leaf_ty) = leaf.unpack() {
+            if let ty::Param(param) = leaf_ty.kind() {
+                debug!("found use of ty param {:?}", param);
+                params_used.insert(param.index);
+            }
+        }
+    }
+
+    for param in &generics.params {
+        if !params_used.contains(param.index) {
+            if let ty::GenericParamDefKind::Type { .. } = param.kind {
+                let span = tcx.def_span(param.def_id);
+                struct_span_err!(
+                    tcx.sess,
+                    span,
+                    E0091,
+                    "type parameter `{}` is unused",
+                    param.name,
+                )
+                .span_label(span, "unused type parameter")
+                .emit();
+            }
+        }
+    }
+}
+
+pub(super) fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
+    tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckItemTypesVisitor { tcx });
+}
+
+pub(super) fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
+    wfcheck::check_item_well_formed(tcx, def_id);
+}
+
+pub(super) fn check_trait_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
+    wfcheck::check_trait_item(tcx, def_id);
+}
+
+pub(super) fn check_impl_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
+    wfcheck::check_impl_item(tcx, def_id);
+}
+
+fn async_opaque_type_cycle_error(tcx: TyCtxt<'tcx>, span: Span) {
+    struct_span_err!(tcx.sess, span, E0733, "recursion in an `async fn` requires boxing")
+        .span_label(span, "recursive `async fn`")
+        .note("a recursive `async fn` must be rewritten to return a boxed `dyn Future`")
+        .emit();
+}
+
+/// Emit an error for recursive opaque types.
+///
+/// If this is a return `impl Trait`, find the item's return expressions and point at them. For
+/// direct recursion this is enough, but for indirect recursion also point at the last intermediary
+/// `impl Trait`.
+///
+/// If all the return expressions evaluate to `!`, then we explain that the error will go away
+/// after changing it. This can happen when a user uses `panic!()` or similar as a placeholder.
+fn opaque_type_cycle_error(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) {
+    let mut err = struct_span_err!(tcx.sess, span, E0720, "cannot resolve opaque type");
+
+    let mut label = false;
+    if let Some((hir_id, visitor)) = get_owner_return_paths(tcx, def_id) {
+        let typeck_results = tcx.typeck(tcx.hir().local_def_id(hir_id));
+        if visitor
+            .returns
+            .iter()
+            .filter_map(|expr| typeck_results.node_type_opt(expr.hir_id))
+            .all(|ty| matches!(ty.kind(), ty::Never))
+        {
+            let spans = visitor
+                .returns
+                .iter()
+                .filter(|expr| typeck_results.node_type_opt(expr.hir_id).is_some())
+                .map(|expr| expr.span)
+                .collect::<Vec<Span>>();
+            let span_len = spans.len();
+            if span_len == 1 {
+                err.span_label(spans[0], "this returned value is of `!` type");
+            } else {
+                let mut multispan: MultiSpan = spans.clone().into();
+                for span in spans {
+                    multispan
+                        .push_span_label(span, "this returned value is of `!` type".to_string());
+                }
+                err.span_note(multispan, "these returned values have a concrete \"never\" type");
+            }
+            err.help("this error will resolve once the item's body returns a concrete type");
+        } else {
+            let mut seen = FxHashSet::default();
+            seen.insert(span);
+            err.span_label(span, "recursive opaque type");
+            label = true;
+            for (sp, ty) in visitor
+                .returns
+                .iter()
+                .filter_map(|e| typeck_results.node_type_opt(e.hir_id).map(|t| (e.span, t)))
+                .filter(|(_, ty)| !matches!(ty.kind(), ty::Never))
+            {
+                struct VisitTypes(Vec<DefId>);
+                impl<'tcx> ty::fold::TypeVisitor<'tcx> for VisitTypes {
+                    fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
+                        match *t.kind() {
+                            ty::Opaque(def, _) => {
+                                self.0.push(def);
+                                false
+                            }
+                            _ => t.super_visit_with(self),
+                        }
+                    }
+                }
+                let mut visitor = VisitTypes(vec![]);
+                ty.visit_with(&mut visitor);
+                for def_id in visitor.0 {
+                    let ty_span = tcx.def_span(def_id);
+                    if !seen.contains(&ty_span) {
+                        err.span_label(ty_span, &format!("returning this opaque type `{}`", ty));
+                        seen.insert(ty_span);
+                    }
+                    err.span_label(sp, &format!("returning here with type `{}`", ty));
+                }
+            }
+        }
+    }
+    if !label {
+        err.span_label(span, "cannot resolve opaque type");
+    }
+    err.emit();
+}
index d45b51c42eae2353b88985a00db4a76bc80535f6..04d4d8171d48aef857dec6f97e4732ca7260d462 100644 (file)
@@ -66,6 +66,7 @@
 mod autoderef;
 mod callee;
 pub mod cast;
+mod check;
 mod closure;
 pub mod coercion;
 mod compare_method;
 mod wfcheck;
 pub mod writeback;
 
+use check::{
+    check_abi, check_fn, check_impl_item_well_formed, check_item_well_formed, check_mod_item_types,
+    check_trait_item_well_formed,
+};
+pub use check::{check_item_type, check_wf_new};
 pub use diverges::Diverges;
 pub use expectation::Expectation;
 pub use fn_ctxt::FnCtxt;
 
 use crate::astconv::AstConv;
 use crate::check::gather_locals::GatherLocalsVisitor;
-use rustc_attr as attr;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{pluralize, struct_span_err, Applicability};
 use rustc_hir as hir;
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
-use rustc_hir::lang_items::LangItem;
-use rustc_hir::{HirIdMap, ItemKind, Node};
+use rustc_hir::{HirIdMap, Node};
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::Idx;
-use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_infer::infer::RegionVariableOrigin;
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
-use rustc_middle::ty::util::{Discr, IntTypeExt, Representability};
 use rustc_middle::ty::WithConstness;
-use rustc_middle::ty::{self, RegionKind, ToPredicate, Ty, TyCtxt, UserType};
-use rustc_session::config::{self, EntryFnType};
+use rustc_middle::ty::{self, RegionKind, Ty, TyCtxt, UserType};
+use rustc_session::config;
 use rustc_session::parse::feature_err;
 use rustc_session::Session;
 use rustc_span::source_map::DUMMY_SP;
-use rustc_span::symbol::{kw, sym, Ident};
+use rustc_span::symbol::{kw, Ident};
 use rustc_span::{self, BytePos, MultiSpan, Span};
 use rustc_target::abi::VariantIdx;
 use rustc_target::spec::abi::Abi;
+use rustc_trait_selection::traits;
 use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error;
 use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
-use rustc_trait_selection::traits::{self, ObligationCauseCode};
 
 use std::cell::{Ref, RefCell, RefMut};
 
 use crate::require_c_abi_if_c_variadic;
 use crate::util::common::indenter;
 
-use self::coercion::{CoerceMany, DynamicCoerceMany};
-use self::compare_method::{compare_const_impl, compare_impl_method, compare_ty_impl};
+use self::coercion::DynamicCoerceMany;
 pub use self::Expectation::*;
 
 #[macro_export]
@@ -245,11 +245,6 @@ fn opt_find_breakable(&mut self, target_id: hir::HirId) -> Option<&mut Breakable
     }
 }
 
-pub fn check_wf_new(tcx: TyCtxt<'_>) {
-    let visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx);
-    tcx.hir().krate().par_visit_all_item_likes(&visit);
-}
-
 pub fn provide(providers: &mut Providers) {
     method::provide(providers);
     *providers = Providers {
@@ -631,19 +626,6 @@ fn typeck_with_fallback<'tcx>(
     typeck_results
 }
 
-fn check_abi(tcx: TyCtxt<'_>, span: Span, abi: Abi) {
-    if !tcx.sess.target.target.is_abi_supported(abi) {
-        struct_span_err!(
-            tcx.sess,
-            span,
-            E0570,
-            "The ABI `{}` is not supported for the current target",
-            abi
-        )
-        .emit()
-    }
-}
-
 /// When `check_fn` is invoked on a generator (i.e., a body that
 /// includes yield), it returns back some information about the yield
 /// points.
@@ -661,460 +643,6 @@ struct GeneratorTypes<'tcx> {
     movability: hir::Movability,
 }
 
-/// Helper used for fns and closures. Does the grungy work of checking a function
-/// body and returns the function context used for that purpose, since in the case of a fn item
-/// there is still a bit more to do.
-///
-/// * ...
-/// * inherited: other fields inherited from the enclosing fn (if any)
-fn check_fn<'a, 'tcx>(
-    inherited: &'a Inherited<'a, 'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    fn_sig: ty::FnSig<'tcx>,
-    decl: &'tcx hir::FnDecl<'tcx>,
-    fn_id: hir::HirId,
-    body: &'tcx hir::Body<'tcx>,
-    can_be_generator: Option<hir::Movability>,
-) -> (FnCtxt<'a, 'tcx>, Option<GeneratorTypes<'tcx>>) {
-    let mut fn_sig = fn_sig;
-
-    debug!("check_fn(sig={:?}, fn_id={}, param_env={:?})", fn_sig, fn_id, param_env);
-
-    // Create the function context. This is either derived from scratch or,
-    // in the case of closures, based on the outer context.
-    let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id);
-    *fcx.ps.borrow_mut() = UnsafetyState::function(fn_sig.unsafety, fn_id);
-
-    let tcx = fcx.tcx;
-    let sess = tcx.sess;
-    let hir = tcx.hir();
-
-    let declared_ret_ty = fn_sig.output();
-
-    let revealed_ret_ty =
-        fcx.instantiate_opaque_types_from_value(fn_id, &declared_ret_ty, decl.output.span());
-    debug!("check_fn: declared_ret_ty: {}, revealed_ret_ty: {}", declared_ret_ty, revealed_ret_ty);
-    fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(revealed_ret_ty)));
-    fcx.ret_type_span = Some(decl.output.span());
-    if let ty::Opaque(..) = declared_ret_ty.kind() {
-        fcx.ret_coercion_impl_trait = Some(declared_ret_ty);
-    }
-    fn_sig = tcx.mk_fn_sig(
-        fn_sig.inputs().iter().cloned(),
-        revealed_ret_ty,
-        fn_sig.c_variadic,
-        fn_sig.unsafety,
-        fn_sig.abi,
-    );
-
-    let span = body.value.span;
-
-    fn_maybe_err(tcx, span, fn_sig.abi);
-
-    if body.generator_kind.is_some() && can_be_generator.is_some() {
-        let yield_ty = fcx
-            .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span });
-        fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
-
-        // Resume type defaults to `()` if the generator has no argument.
-        let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| tcx.mk_unit());
-
-        fcx.resume_yield_tys = Some((resume_ty, yield_ty));
-    }
-
-    let outer_def_id = tcx.closure_base_def_id(hir.local_def_id(fn_id).to_def_id()).expect_local();
-    let outer_hir_id = hir.local_def_id_to_hir_id(outer_def_id);
-    GatherLocalsVisitor::new(&fcx, outer_hir_id).visit_body(body);
-
-    // C-variadic fns also have a `VaList` input that's not listed in `fn_sig`
-    // (as it's created inside the body itself, not passed in from outside).
-    let maybe_va_list = if fn_sig.c_variadic {
-        let span = body.params.last().unwrap().span;
-        let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(span));
-        let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span));
-
-        Some(tcx.type_of(va_list_did).subst(tcx, &[region.into()]))
-    } else {
-        None
-    };
-
-    // Add formal parameters.
-    let inputs_hir = hir.fn_decl_by_hir_id(fn_id).map(|decl| &decl.inputs);
-    let inputs_fn = fn_sig.inputs().iter().copied();
-    for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
-        // Check the pattern.
-        let ty_span = try { inputs_hir?.get(idx)?.span };
-        fcx.check_pat_top(&param.pat, param_ty, ty_span, false);
-
-        // Check that argument is Sized.
-        // The check for a non-trivial pattern is a hack to avoid duplicate warnings
-        // for simple cases like `fn foo(x: Trait)`,
-        // where we would error once on the parameter as a whole, and once on the binding `x`.
-        if param.pat.simple_ident().is_none() && !tcx.features().unsized_locals {
-            fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span));
-        }
-
-        fcx.write_ty(param.hir_id, param_ty);
-    }
-
-    inherited.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig);
-
-    fcx.in_tail_expr = true;
-    if let ty::Dynamic(..) = declared_ret_ty.kind() {
-        // FIXME: We need to verify that the return type is `Sized` after the return expression has
-        // been evaluated so that we have types available for all the nodes being returned, but that
-        // requires the coerced evaluated type to be stored. Moving `check_return_expr` before this
-        // causes unsized errors caused by the `declared_ret_ty` to point at the return expression,
-        // while keeping the current ordering we will ignore the tail expression's type because we
-        // don't know it yet. We can't do `check_expr_kind` while keeping `check_return_expr`
-        // because we will trigger "unreachable expression" lints unconditionally.
-        // Because of all of this, we perform a crude check to know whether the simplest `!Sized`
-        // case that a newcomer might make, returning a bare trait, and in that case we populate
-        // the tail expression's type so that the suggestion will be correct, but ignore all other
-        // possible cases.
-        fcx.check_expr(&body.value);
-        fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
-        tcx.sess.delay_span_bug(decl.output.span(), "`!Sized` return type");
-    } else {
-        fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
-        fcx.check_return_expr(&body.value);
-    }
-    fcx.in_tail_expr = false;
-
-    // We insert the deferred_generator_interiors entry after visiting the body.
-    // This ensures that all nested generators appear before the entry of this generator.
-    // resolve_generator_interiors relies on this property.
-    let gen_ty = if let (Some(_), Some(gen_kind)) = (can_be_generator, body.generator_kind) {
-        let interior = fcx
-            .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span });
-        fcx.deferred_generator_interiors.borrow_mut().push((body.id(), interior, gen_kind));
-
-        let (resume_ty, yield_ty) = fcx.resume_yield_tys.unwrap();
-        Some(GeneratorTypes {
-            resume_ty,
-            yield_ty,
-            interior,
-            movability: can_be_generator.unwrap(),
-        })
-    } else {
-        None
-    };
-
-    // Finalize the return check by taking the LUB of the return types
-    // we saw and assigning it to the expected return type. This isn't
-    // really expected to fail, since the coercions would have failed
-    // earlier when trying to find a LUB.
-    //
-    // However, the behavior around `!` is sort of complex. In the
-    // event that the `actual_return_ty` comes back as `!`, that
-    // indicates that the fn either does not return or "returns" only
-    // values of type `!`. In this case, if there is an expected
-    // return type that is *not* `!`, that should be ok. But if the
-    // return type is being inferred, we want to "fallback" to `!`:
-    //
-    //     let x = move || panic!();
-    //
-    // To allow for that, I am creating a type variable with diverging
-    // fallback. This was deemed ever so slightly better than unifying
-    // the return value with `!` because it allows for the caller to
-    // make more assumptions about the return type (e.g., they could do
-    //
-    //     let y: Option<u32> = Some(x());
-    //
-    // which would then cause this return type to become `u32`, not
-    // `!`).
-    let coercion = fcx.ret_coercion.take().unwrap().into_inner();
-    let mut actual_return_ty = coercion.complete(&fcx);
-    if actual_return_ty.is_never() {
-        actual_return_ty = fcx.next_diverging_ty_var(TypeVariableOrigin {
-            kind: TypeVariableOriginKind::DivergingFn,
-            span,
-        });
-    }
-    fcx.demand_suptype(span, revealed_ret_ty, actual_return_ty);
-
-    // Check that the main return type implements the termination trait.
-    if let Some(term_id) = tcx.lang_items().termination() {
-        if let Some((def_id, EntryFnType::Main)) = tcx.entry_fn(LOCAL_CRATE) {
-            let main_id = hir.local_def_id_to_hir_id(def_id);
-            if main_id == fn_id {
-                let substs = tcx.mk_substs_trait(declared_ret_ty, &[]);
-                let trait_ref = ty::TraitRef::new(term_id, substs);
-                let return_ty_span = decl.output.span();
-                let cause = traits::ObligationCause::new(
-                    return_ty_span,
-                    fn_id,
-                    ObligationCauseCode::MainFunctionType,
-                );
-
-                inherited.register_predicate(traits::Obligation::new(
-                    cause,
-                    param_env,
-                    trait_ref.without_const().to_predicate(tcx),
-                ));
-            }
-        }
-    }
-
-    // Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !`
-    if let Some(panic_impl_did) = tcx.lang_items().panic_impl() {
-        if panic_impl_did == hir.local_def_id(fn_id).to_def_id() {
-            if let Some(panic_info_did) = tcx.lang_items().panic_info() {
-                if *declared_ret_ty.kind() != ty::Never {
-                    sess.span_err(decl.output.span(), "return type should be `!`");
-                }
-
-                let inputs = fn_sig.inputs();
-                let span = hir.span(fn_id);
-                if inputs.len() == 1 {
-                    let arg_is_panic_info = match *inputs[0].kind() {
-                        ty::Ref(region, ty, mutbl) => match *ty.kind() {
-                            ty::Adt(ref adt, _) => {
-                                adt.did == panic_info_did
-                                    && mutbl == hir::Mutability::Not
-                                    && *region != RegionKind::ReStatic
-                            }
-                            _ => false,
-                        },
-                        _ => false,
-                    };
-
-                    if !arg_is_panic_info {
-                        sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`");
-                    }
-
-                    if let Node::Item(item) = hir.get(fn_id) {
-                        if let ItemKind::Fn(_, ref generics, _) = item.kind {
-                            if !generics.params.is_empty() {
-                                sess.span_err(span, "should have no type parameters");
-                            }
-                        }
-                    }
-                } else {
-                    let span = sess.source_map().guess_head_span(span);
-                    sess.span_err(span, "function should have one argument");
-                }
-            } else {
-                sess.err("language item required, but not found: `panic_info`");
-            }
-        }
-    }
-
-    // Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !`
-    if let Some(alloc_error_handler_did) = tcx.lang_items().oom() {
-        if alloc_error_handler_did == hir.local_def_id(fn_id).to_def_id() {
-            if let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() {
-                if *declared_ret_ty.kind() != ty::Never {
-                    sess.span_err(decl.output.span(), "return type should be `!`");
-                }
-
-                let inputs = fn_sig.inputs();
-                let span = hir.span(fn_id);
-                if inputs.len() == 1 {
-                    let arg_is_alloc_layout = match inputs[0].kind() {
-                        ty::Adt(ref adt, _) => adt.did == alloc_layout_did,
-                        _ => false,
-                    };
-
-                    if !arg_is_alloc_layout {
-                        sess.span_err(decl.inputs[0].span, "argument should be `Layout`");
-                    }
-
-                    if let Node::Item(item) = hir.get(fn_id) {
-                        if let ItemKind::Fn(_, ref generics, _) = item.kind {
-                            if !generics.params.is_empty() {
-                                sess.span_err(
-                                    span,
-                                    "`#[alloc_error_handler]` function should have no type \
-                                     parameters",
-                                );
-                            }
-                        }
-                    }
-                } else {
-                    let span = sess.source_map().guess_head_span(span);
-                    sess.span_err(span, "function should have one argument");
-                }
-            } else {
-                sess.err("language item required, but not found: `alloc_layout`");
-            }
-        }
-    }
-
-    (fcx, gen_ty)
-}
-
-fn check_struct(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) {
-    let def_id = tcx.hir().local_def_id(id);
-    let def = tcx.adt_def(def_id);
-    def.destructor(tcx); // force the destructor to be evaluated
-    check_representable(tcx, span, def_id);
-
-    if def.repr.simd() {
-        check_simd(tcx, span, def_id);
-    }
-
-    check_transparent(tcx, span, def);
-    check_packed(tcx, span, def);
-}
-
-fn check_union(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) {
-    let def_id = tcx.hir().local_def_id(id);
-    let def = tcx.adt_def(def_id);
-    def.destructor(tcx); // force the destructor to be evaluated
-    check_representable(tcx, span, def_id);
-    check_transparent(tcx, span, def);
-    check_union_fields(tcx, span, def_id);
-    check_packed(tcx, span, def);
-}
-
-/// When the `#![feature(untagged_unions)]` gate is active,
-/// check that the fields of the `union` does not contain fields that need dropping.
-fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> bool {
-    let item_type = tcx.type_of(item_def_id);
-    if let ty::Adt(def, substs) = item_type.kind() {
-        assert!(def.is_union());
-        let fields = &def.non_enum_variant().fields;
-        let param_env = tcx.param_env(item_def_id);
-        for field in fields {
-            let field_ty = field.ty(tcx, substs);
-            // We are currently checking the type this field came from, so it must be local.
-            let field_span = tcx.hir().span_if_local(field.did).unwrap();
-            if field_ty.needs_drop(tcx, param_env) {
-                struct_span_err!(
-                    tcx.sess,
-                    field_span,
-                    E0740,
-                    "unions may not contain fields that need dropping"
-                )
-                .span_note(field_span, "`std::mem::ManuallyDrop` can be used to wrap the type")
-                .emit();
-                return false;
-            }
-        }
-    } else {
-        span_bug!(span, "unions must be ty::Adt, but got {:?}", item_type.kind());
-    }
-    true
-}
-
-/// Checks that an opaque type does not contain cycles and does not use `Self` or `T::Foo`
-/// projections that would result in "inheriting lifetimes".
-fn check_opaque<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    def_id: LocalDefId,
-    substs: SubstsRef<'tcx>,
-    span: Span,
-    origin: &hir::OpaqueTyOrigin,
-) {
-    check_opaque_for_inheriting_lifetimes(tcx, def_id, span);
-    check_opaque_for_cycles(tcx, def_id, substs, span, origin);
-}
-
-/// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result
-/// in "inheriting lifetimes".
-fn check_opaque_for_inheriting_lifetimes(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) {
-    let item = tcx.hir().expect_item(tcx.hir().local_def_id_to_hir_id(def_id));
-    debug!(
-        "check_opaque_for_inheriting_lifetimes: def_id={:?} span={:?} item={:?}",
-        def_id, span, item
-    );
-
-    #[derive(Debug)]
-    struct ProhibitOpaqueVisitor<'tcx> {
-        opaque_identity_ty: Ty<'tcx>,
-        generics: &'tcx ty::Generics,
-        ty: Option<Ty<'tcx>>,
-    };
-
-    impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
-        fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
-            debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t);
-            if t != self.opaque_identity_ty && t.super_visit_with(self) {
-                self.ty = Some(t);
-                return true;
-            }
-            false
-        }
-
-        fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
-            debug!("check_opaque_for_inheriting_lifetimes: (visit_region) r={:?}", r);
-            if let RegionKind::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = r {
-                return *index < self.generics.parent_count as u32;
-            }
-
-            r.super_visit_with(self)
-        }
-
-        fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool {
-            if let ty::ConstKind::Unevaluated(..) = c.val {
-                // FIXME(#72219) We currenctly don't detect lifetimes within substs
-                // which would violate this check. Even though the particular substitution is not used
-                // within the const, this should still be fixed.
-                return false;
-            }
-            c.super_visit_with(self)
-        }
-    }
-
-    if let ItemKind::OpaqueTy(hir::OpaqueTy {
-        origin: hir::OpaqueTyOrigin::AsyncFn | hir::OpaqueTyOrigin::FnReturn,
-        ..
-    }) = item.kind
-    {
-        let mut visitor = ProhibitOpaqueVisitor {
-            opaque_identity_ty: tcx.mk_opaque(
-                def_id.to_def_id(),
-                InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
-            ),
-            generics: tcx.generics_of(def_id),
-            ty: None,
-        };
-        let prohibit_opaque = tcx
-            .predicates_of(def_id)
-            .predicates
-            .iter()
-            .any(|(predicate, _)| predicate.visit_with(&mut visitor));
-        debug!(
-            "check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor={:?}",
-            prohibit_opaque, visitor
-        );
-
-        if prohibit_opaque {
-            let is_async = match item.kind {
-                ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => match origin {
-                    hir::OpaqueTyOrigin::AsyncFn => true,
-                    _ => false,
-                },
-                _ => unreachable!(),
-            };
-
-            let mut err = struct_span_err!(
-                tcx.sess,
-                span,
-                E0760,
-                "`{}` return type cannot contain a projection or `Self` that references lifetimes from \
-             a parent scope",
-                if is_async { "async fn" } else { "impl Trait" },
-            );
-
-            if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) {
-                if snippet == "Self" {
-                    if let Some(ty) = visitor.ty {
-                        err.span_suggestion(
-                            span,
-                            "consider spelling out the type instead",
-                            format!("{:?}", ty),
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
-                }
-            }
-            err.emit();
-        }
-    }
-}
-
 /// Given a `DefId` for an opaque type in return position, find its parent item's return
 /// expressions.
 fn get_owner_return_paths(
@@ -1135,86 +663,6 @@ fn get_owner_return_paths(
         })
 }
 
-/// Emit an error for recursive opaque types.
-///
-/// If this is a return `impl Trait`, find the item's return expressions and point at them. For
-/// direct recursion this is enough, but for indirect recursion also point at the last intermediary
-/// `impl Trait`.
-///
-/// If all the return expressions evaluate to `!`, then we explain that the error will go away
-/// after changing it. This can happen when a user uses `panic!()` or similar as a placeholder.
-fn opaque_type_cycle_error(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) {
-    let mut err = struct_span_err!(tcx.sess, span, E0720, "cannot resolve opaque type");
-
-    let mut label = false;
-    if let Some((hir_id, visitor)) = get_owner_return_paths(tcx, def_id) {
-        let typeck_results = tcx.typeck(tcx.hir().local_def_id(hir_id));
-        if visitor
-            .returns
-            .iter()
-            .filter_map(|expr| typeck_results.node_type_opt(expr.hir_id))
-            .all(|ty| matches!(ty.kind(), ty::Never))
-        {
-            let spans = visitor
-                .returns
-                .iter()
-                .filter(|expr| typeck_results.node_type_opt(expr.hir_id).is_some())
-                .map(|expr| expr.span)
-                .collect::<Vec<Span>>();
-            let span_len = spans.len();
-            if span_len == 1 {
-                err.span_label(spans[0], "this returned value is of `!` type");
-            } else {
-                let mut multispan: MultiSpan = spans.clone().into();
-                for span in spans {
-                    multispan
-                        .push_span_label(span, "this returned value is of `!` type".to_string());
-                }
-                err.span_note(multispan, "these returned values have a concrete \"never\" type");
-            }
-            err.help("this error will resolve once the item's body returns a concrete type");
-        } else {
-            let mut seen = FxHashSet::default();
-            seen.insert(span);
-            err.span_label(span, "recursive opaque type");
-            label = true;
-            for (sp, ty) in visitor
-                .returns
-                .iter()
-                .filter_map(|e| typeck_results.node_type_opt(e.hir_id).map(|t| (e.span, t)))
-                .filter(|(_, ty)| !matches!(ty.kind(), ty::Never))
-            {
-                struct VisitTypes(Vec<DefId>);
-                impl<'tcx> ty::fold::TypeVisitor<'tcx> for VisitTypes {
-                    fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
-                        match *t.kind() {
-                            ty::Opaque(def, _) => {
-                                self.0.push(def);
-                                false
-                            }
-                            _ => t.super_visit_with(self),
-                        }
-                    }
-                }
-                let mut visitor = VisitTypes(vec![]);
-                ty.visit_with(&mut visitor);
-                for def_id in visitor.0 {
-                    let ty_span = tcx.def_span(def_id);
-                    if !seen.contains(&ty_span) {
-                        err.span_label(ty_span, &format!("returning this opaque type `{}`", ty));
-                        seen.insert(ty_span);
-                    }
-                    err.span_label(sp, &format!("returning here with type `{}`", ty));
-                }
-            }
-        }
-    }
-    if !label {
-        err.span_label(span, "cannot resolve opaque type");
-    }
-    err.emit();
-}
-
 /// Emit an error for recursive opaque types in a `let` binding.
 fn binding_opaque_type_cycle_error(
     tcx: TyCtxt<'tcx>,
@@ -1275,33 +723,6 @@ fn binding_opaque_type_cycle_error(
     err.emit();
 }
 
-fn async_opaque_type_cycle_error(tcx: TyCtxt<'tcx>, span: Span) {
-    struct_span_err!(tcx.sess, span, E0733, "recursion in an `async fn` requires boxing")
-        .span_label(span, "recursive `async fn`")
-        .note("a recursive `async fn` must be rewritten to return a boxed `dyn Future`")
-        .emit();
-}
-
-/// Checks that an opaque type does not contain cycles.
-fn check_opaque_for_cycles<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    def_id: LocalDefId,
-    substs: SubstsRef<'tcx>,
-    span: Span,
-    origin: &hir::OpaqueTyOrigin,
-) {
-    if let Err(partially_expanded_type) = tcx.try_expand_impl_trait_type(def_id.to_def_id(), substs)
-    {
-        match origin {
-            hir::OpaqueTyOrigin::AsyncFn => async_opaque_type_cycle_error(tcx, span),
-            hir::OpaqueTyOrigin::Binding => {
-                binding_opaque_type_cycle_error(tcx, def_id, span, partially_expanded_type)
-            }
-            _ => opaque_type_cycle_error(tcx, def_id, span),
-        }
-    }
-}
-
 // Forbid defining intrinsics in Rust code,
 // as they must always be defined by the compiler.
 fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) {
@@ -1310,126 +731,6 @@ fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) {
     }
 }
 
-pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) {
-    debug!(
-        "check_item_type(it.hir_id={}, it.name={})",
-        it.hir_id,
-        tcx.def_path_str(tcx.hir().local_def_id(it.hir_id).to_def_id())
-    );
-    let _indenter = indenter();
-    match it.kind {
-        // Consts can play a role in type-checking, so they are included here.
-        hir::ItemKind::Static(..) => {
-            let def_id = tcx.hir().local_def_id(it.hir_id);
-            tcx.ensure().typeck(def_id);
-            maybe_check_static_with_link_section(tcx, def_id, it.span);
-        }
-        hir::ItemKind::Const(..) => {
-            tcx.ensure().typeck(tcx.hir().local_def_id(it.hir_id));
-        }
-        hir::ItemKind::Enum(ref enum_definition, _) => {
-            check_enum(tcx, it.span, &enum_definition.variants, it.hir_id);
-        }
-        hir::ItemKind::Fn(..) => {} // entirely within check_item_body
-        hir::ItemKind::Impl { ref items, .. } => {
-            debug!("ItemKind::Impl {} with id {}", it.ident, it.hir_id);
-            let impl_def_id = tcx.hir().local_def_id(it.hir_id);
-            if let Some(impl_trait_ref) = tcx.impl_trait_ref(impl_def_id) {
-                check_impl_items_against_trait(tcx, it.span, impl_def_id, impl_trait_ref, items);
-                let trait_def_id = impl_trait_ref.def_id;
-                check_on_unimplemented(tcx, trait_def_id, it);
-            }
-        }
-        hir::ItemKind::Trait(_, _, _, _, ref items) => {
-            let def_id = tcx.hir().local_def_id(it.hir_id);
-            check_on_unimplemented(tcx, def_id.to_def_id(), it);
-
-            for item in items.iter() {
-                let item = tcx.hir().trait_item(item.id);
-                if let hir::TraitItemKind::Fn(sig, _) = &item.kind {
-                    let abi = sig.header.abi;
-                    fn_maybe_err(tcx, item.ident.span, abi);
-                }
-            }
-        }
-        hir::ItemKind::Struct(..) => {
-            check_struct(tcx, it.hir_id, it.span);
-        }
-        hir::ItemKind::Union(..) => {
-            check_union(tcx, it.hir_id, it.span);
-        }
-        hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => {
-            // HACK(jynelson): trying to infer the type of `impl trait` breaks documenting
-            // `async-std` (and `pub async fn` in general).
-            // Since rustdoc doesn't care about the concrete type behind `impl Trait`, just don't look at it!
-            // See https://github.com/rust-lang/rust/issues/75100
-            if !tcx.sess.opts.actually_rustdoc {
-                let def_id = tcx.hir().local_def_id(it.hir_id);
-
-                let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
-                check_opaque(tcx, def_id, substs, it.span, &origin);
-            }
-        }
-        hir::ItemKind::TyAlias(..) => {
-            let def_id = tcx.hir().local_def_id(it.hir_id);
-            let pty_ty = tcx.type_of(def_id);
-            let generics = tcx.generics_of(def_id);
-            check_type_params_are_used(tcx, &generics, pty_ty);
-        }
-        hir::ItemKind::ForeignMod(ref m) => {
-            check_abi(tcx, it.span, m.abi);
-
-            if m.abi == Abi::RustIntrinsic {
-                for item in m.items {
-                    intrinsic::check_intrinsic_type(tcx, item);
-                }
-            } else if m.abi == Abi::PlatformIntrinsic {
-                for item in m.items {
-                    intrinsic::check_platform_intrinsic_type(tcx, item);
-                }
-            } else {
-                for item in m.items {
-                    let generics = tcx.generics_of(tcx.hir().local_def_id(item.hir_id));
-                    let own_counts = generics.own_counts();
-                    if generics.params.len() - own_counts.lifetimes != 0 {
-                        let (kinds, kinds_pl, egs) = match (own_counts.types, own_counts.consts) {
-                            (_, 0) => ("type", "types", Some("u32")),
-                            // We don't specify an example value, because we can't generate
-                            // a valid value for any type.
-                            (0, _) => ("const", "consts", None),
-                            _ => ("type or const", "types or consts", None),
-                        };
-                        struct_span_err!(
-                            tcx.sess,
-                            item.span,
-                            E0044,
-                            "foreign items may not have {} parameters",
-                            kinds,
-                        )
-                        .span_label(item.span, &format!("can't have {} parameters", kinds))
-                        .help(
-                            // FIXME: once we start storing spans for type arguments, turn this
-                            // into a suggestion.
-                            &format!(
-                                "replace the {} parameters with concrete {}{}",
-                                kinds,
-                                kinds_pl,
-                                egs.map(|egs| format!(" like `{}`", egs)).unwrap_or_default(),
-                            ),
-                        )
-                        .emit();
-                    }
-
-                    if let hir::ForeignItemKind::Fn(ref fn_decl, _, _) = item.kind {
-                        require_c_abi_if_c_variadic(tcx, fn_decl, m.abi, item.span);
-                    }
-                }
-            }
-        }
-        _ => { /* nothing to do */ }
-    }
-}
-
 fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId, span: Span) {
     // Only restricted on wasm32 target for now
     if !tcx.sess.opts.target_triple.triple().starts_with("wasm32") {
@@ -1463,12 +764,6 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId, span: S
     }
 }
 
-fn check_on_unimplemented(tcx: TyCtxt<'_>, trait_def_id: DefId, item: &hir::Item<'_>) {
-    let item_def_id = tcx.hir().local_def_id(item.hir_id);
-    // an error would be reported if this fails.
-    let _ = traits::OnUnimplementedDirective::of_item(tcx, trait_def_id, item_def_id.to_def_id());
-}
-
 fn report_forbidden_specialization(
     tcx: TyCtxt<'_>,
     impl_item: &hir::ImplItem<'_>,
@@ -1500,248 +795,6 @@ fn report_forbidden_specialization(
     err.emit();
 }
 
-fn check_specialization_validity<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    trait_def: &ty::TraitDef,
-    trait_item: &ty::AssocItem,
-    impl_id: DefId,
-    impl_item: &hir::ImplItem<'_>,
-) {
-    let kind = match impl_item.kind {
-        hir::ImplItemKind::Const(..) => ty::AssocKind::Const,
-        hir::ImplItemKind::Fn(..) => ty::AssocKind::Fn,
-        hir::ImplItemKind::TyAlias(_) => ty::AssocKind::Type,
-    };
-
-    let ancestors = match trait_def.ancestors(tcx, impl_id) {
-        Ok(ancestors) => ancestors,
-        Err(_) => return,
-    };
-    let mut ancestor_impls = ancestors
-        .skip(1)
-        .filter_map(|parent| {
-            if parent.is_from_trait() {
-                None
-            } else {
-                Some((parent, parent.item(tcx, trait_item.ident, kind, trait_def.def_id)))
-            }
-        })
-        .peekable();
-
-    if ancestor_impls.peek().is_none() {
-        // No parent, nothing to specialize.
-        return;
-    }
-
-    let opt_result = ancestor_impls.find_map(|(parent_impl, parent_item)| {
-        match parent_item {
-            // Parent impl exists, and contains the parent item we're trying to specialize, but
-            // doesn't mark it `default`.
-            Some(parent_item) if traits::impl_item_is_final(tcx, &parent_item) => {
-                Some(Err(parent_impl.def_id()))
-            }
-
-            // Parent impl contains item and makes it specializable.
-            Some(_) => Some(Ok(())),
-
-            // Parent impl doesn't mention the item. This means it's inherited from the
-            // grandparent. In that case, if parent is a `default impl`, inherited items use the
-            // "defaultness" from the grandparent, else they are final.
-            None => {
-                if tcx.impl_defaultness(parent_impl.def_id()).is_default() {
-                    None
-                } else {
-                    Some(Err(parent_impl.def_id()))
-                }
-            }
-        }
-    });
-
-    // If `opt_result` is `None`, we have only encountered `default impl`s that don't contain the
-    // item. This is allowed, the item isn't actually getting specialized here.
-    let result = opt_result.unwrap_or(Ok(()));
-
-    if let Err(parent_impl) = result {
-        report_forbidden_specialization(tcx, impl_item, parent_impl);
-    }
-}
-
-fn check_impl_items_against_trait<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    full_impl_span: Span,
-    impl_id: LocalDefId,
-    impl_trait_ref: ty::TraitRef<'tcx>,
-    impl_item_refs: &[hir::ImplItemRef<'_>],
-) {
-    let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span);
-
-    // If the trait reference itself is erroneous (so the compilation is going
-    // to fail), skip checking the items here -- the `impl_item` table in `tcx`
-    // isn't populated for such impls.
-    if impl_trait_ref.references_error() {
-        return;
-    }
-
-    // Negative impls are not expected to have any items
-    match tcx.impl_polarity(impl_id) {
-        ty::ImplPolarity::Reservation | ty::ImplPolarity::Positive => {}
-        ty::ImplPolarity::Negative => {
-            if let [first_item_ref, ..] = impl_item_refs {
-                let first_item_span = tcx.hir().impl_item(first_item_ref.id).span;
-                struct_span_err!(
-                    tcx.sess,
-                    first_item_span,
-                    E0749,
-                    "negative impls cannot have any items"
-                )
-                .emit();
-            }
-            return;
-        }
-    }
-
-    // Locate trait definition and items
-    let trait_def = tcx.trait_def(impl_trait_ref.def_id);
-
-    let impl_items = || impl_item_refs.iter().map(|iiref| tcx.hir().impl_item(iiref.id));
-
-    // Check existing impl methods to see if they are both present in trait
-    // and compatible with trait signature
-    for impl_item in impl_items() {
-        let namespace = impl_item.kind.namespace();
-        let ty_impl_item = tcx.associated_item(tcx.hir().local_def_id(impl_item.hir_id));
-        let ty_trait_item = tcx
-            .associated_items(impl_trait_ref.def_id)
-            .find_by_name_and_namespace(tcx, ty_impl_item.ident, namespace, impl_trait_ref.def_id)
-            .or_else(|| {
-                // Not compatible, but needed for the error message
-                tcx.associated_items(impl_trait_ref.def_id)
-                    .filter_by_name(tcx, ty_impl_item.ident, impl_trait_ref.def_id)
-                    .next()
-            });
-
-        // Check that impl definition matches trait definition
-        if let Some(ty_trait_item) = ty_trait_item {
-            match impl_item.kind {
-                hir::ImplItemKind::Const(..) => {
-                    // Find associated const definition.
-                    if ty_trait_item.kind == ty::AssocKind::Const {
-                        compare_const_impl(
-                            tcx,
-                            &ty_impl_item,
-                            impl_item.span,
-                            &ty_trait_item,
-                            impl_trait_ref,
-                        );
-                    } else {
-                        let mut err = struct_span_err!(
-                            tcx.sess,
-                            impl_item.span,
-                            E0323,
-                            "item `{}` is an associated const, \
-                             which doesn't match its trait `{}`",
-                            ty_impl_item.ident,
-                            impl_trait_ref.print_only_trait_path()
-                        );
-                        err.span_label(impl_item.span, "does not match trait");
-                        // We can only get the spans from local trait definition
-                        // Same for E0324 and E0325
-                        if let Some(trait_span) = tcx.hir().span_if_local(ty_trait_item.def_id) {
-                            err.span_label(trait_span, "item in trait");
-                        }
-                        err.emit()
-                    }
-                }
-                hir::ImplItemKind::Fn(..) => {
-                    let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
-                    if ty_trait_item.kind == ty::AssocKind::Fn {
-                        compare_impl_method(
-                            tcx,
-                            &ty_impl_item,
-                            impl_item.span,
-                            &ty_trait_item,
-                            impl_trait_ref,
-                            opt_trait_span,
-                        );
-                    } else {
-                        let mut err = struct_span_err!(
-                            tcx.sess,
-                            impl_item.span,
-                            E0324,
-                            "item `{}` is an associated method, \
-                             which doesn't match its trait `{}`",
-                            ty_impl_item.ident,
-                            impl_trait_ref.print_only_trait_path()
-                        );
-                        err.span_label(impl_item.span, "does not match trait");
-                        if let Some(trait_span) = opt_trait_span {
-                            err.span_label(trait_span, "item in trait");
-                        }
-                        err.emit()
-                    }
-                }
-                hir::ImplItemKind::TyAlias(_) => {
-                    let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
-                    if ty_trait_item.kind == ty::AssocKind::Type {
-                        compare_ty_impl(
-                            tcx,
-                            &ty_impl_item,
-                            impl_item.span,
-                            &ty_trait_item,
-                            impl_trait_ref,
-                            opt_trait_span,
-                        );
-                    } else {
-                        let mut err = struct_span_err!(
-                            tcx.sess,
-                            impl_item.span,
-                            E0325,
-                            "item `{}` is an associated type, \
-                             which doesn't match its trait `{}`",
-                            ty_impl_item.ident,
-                            impl_trait_ref.print_only_trait_path()
-                        );
-                        err.span_label(impl_item.span, "does not match trait");
-                        if let Some(trait_span) = opt_trait_span {
-                            err.span_label(trait_span, "item in trait");
-                        }
-                        err.emit()
-                    }
-                }
-            }
-
-            check_specialization_validity(
-                tcx,
-                trait_def,
-                &ty_trait_item,
-                impl_id.to_def_id(),
-                impl_item,
-            );
-        }
-    }
-
-    // Check for missing items from trait
-    let mut missing_items = Vec::new();
-    if let Ok(ancestors) = trait_def.ancestors(tcx, impl_id.to_def_id()) {
-        for trait_item in tcx.associated_items(impl_trait_ref.def_id).in_definition_order() {
-            let is_implemented = ancestors
-                .leaf_def(tcx, trait_item.ident, trait_item.kind)
-                .map(|node_item| !node_item.defining_node.is_from_trait())
-                .unwrap_or(false);
-
-            if !is_implemented && tcx.impl_defaultness(impl_id).is_final() {
-                if !trait_item.defaultness.has_value() {
-                    missing_items.push(*trait_item);
-                }
-            }
-        }
-    }
-
-    if !missing_items.is_empty() {
-        missing_items_err(tcx, impl_span, &missing_items, full_impl_span);
-    }
-}
-
 fn missing_items_err(
     tcx: TyCtxt<'_>,
     impl_span: Span,
@@ -1941,161 +994,6 @@ fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String {
     }
 }
 
-/// Checks whether a type can be represented in memory. In particular, it
-/// identifies types that contain themselves without indirection through a
-/// pointer, which would mean their size is unbounded.
-fn check_representable(tcx: TyCtxt<'_>, sp: Span, item_def_id: LocalDefId) -> bool {
-    let rty = tcx.type_of(item_def_id);
-
-    // Check that it is possible to represent this type. This call identifies
-    // (1) types that contain themselves and (2) types that contain a different
-    // recursive type. It is only necessary to throw an error on those that
-    // contain themselves. For case 2, there must be an inner type that will be
-    // caught by case 1.
-    match rty.is_representable(tcx, sp) {
-        Representability::SelfRecursive(spans) => {
-            recursive_type_with_infinite_size_error(tcx, item_def_id.to_def_id(), spans);
-            return false;
-        }
-        Representability::Representable | Representability::ContainsRecursive => (),
-    }
-    true
-}
-
-pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
-    let t = tcx.type_of(def_id);
-    if let ty::Adt(def, substs) = t.kind() {
-        if def.is_struct() {
-            let fields = &def.non_enum_variant().fields;
-            if fields.is_empty() {
-                struct_span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty").emit();
-                return;
-            }
-            let e = fields[0].ty(tcx, substs);
-            if !fields.iter().all(|f| f.ty(tcx, substs) == e) {
-                struct_span_err!(tcx.sess, sp, E0076, "SIMD vector should be homogeneous")
-                    .span_label(sp, "SIMD elements must have the same type")
-                    .emit();
-                return;
-            }
-            match e.kind() {
-                ty::Param(_) => { /* struct<T>(T, T, T, T) is ok */ }
-                _ if e.is_machine() => { /* struct(u8, u8, u8, u8) is ok */ }
-                _ => {
-                    struct_span_err!(
-                        tcx.sess,
-                        sp,
-                        E0077,
-                        "SIMD vector element type should be machine type"
-                    )
-                    .emit();
-                    return;
-                }
-            }
-        }
-    }
-}
-
-fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: &ty::AdtDef) {
-    let repr = def.repr;
-    if repr.packed() {
-        for attr in tcx.get_attrs(def.did).iter() {
-            for r in attr::find_repr_attrs(&tcx.sess, attr) {
-                if let attr::ReprPacked(pack) = r {
-                    if let Some(repr_pack) = repr.pack {
-                        if pack as u64 != repr_pack.bytes() {
-                            struct_span_err!(
-                                tcx.sess,
-                                sp,
-                                E0634,
-                                "type has conflicting packed representation hints"
-                            )
-                            .emit();
-                        }
-                    }
-                }
-            }
-        }
-        if repr.align.is_some() {
-            struct_span_err!(
-                tcx.sess,
-                sp,
-                E0587,
-                "type has conflicting packed and align representation hints"
-            )
-            .emit();
-        } else {
-            if let Some(def_spans) = check_packed_inner(tcx, def.did, &mut vec![]) {
-                let mut err = struct_span_err!(
-                    tcx.sess,
-                    sp,
-                    E0588,
-                    "packed type cannot transitively contain a `#[repr(align)]` type"
-                );
-
-                err.span_note(
-                    tcx.def_span(def_spans[0].0),
-                    &format!(
-                        "`{}` has a `#[repr(align)]` attribute",
-                        tcx.item_name(def_spans[0].0)
-                    ),
-                );
-
-                if def_spans.len() > 2 {
-                    let mut first = true;
-                    for (adt_def, span) in def_spans.iter().skip(1).rev() {
-                        let ident = tcx.item_name(*adt_def);
-                        err.span_note(
-                            *span,
-                            &if first {
-                                format!(
-                                    "`{}` contains a field of type `{}`",
-                                    tcx.type_of(def.did),
-                                    ident
-                                )
-                            } else {
-                                format!("...which contains a field of type `{}`", ident)
-                            },
-                        );
-                        first = false;
-                    }
-                }
-
-                err.emit();
-            }
-        }
-    }
-}
-
-fn check_packed_inner(
-    tcx: TyCtxt<'_>,
-    def_id: DefId,
-    stack: &mut Vec<DefId>,
-) -> Option<Vec<(DefId, Span)>> {
-    if let ty::Adt(def, substs) = tcx.type_of(def_id).kind() {
-        if def.is_struct() || def.is_union() {
-            if def.repr.align.is_some() {
-                return Some(vec![(def.did, DUMMY_SP)]);
-            }
-
-            stack.push(def_id);
-            for field in &def.non_enum_variant().fields {
-                if let ty::Adt(def, _) = field.ty(tcx, substs).kind() {
-                    if !stack.contains(&def.did) {
-                        if let Some(mut defs) = check_packed_inner(tcx, def.did, stack) {
-                            defs.push((def.did, field.ident.span));
-                            return Some(defs);
-                        }
-                    }
-                }
-            }
-            stack.pop();
-        }
-    }
-
-    None
-}
-
 /// Emit an error when encountering more or less than one variant in a transparent enum.
 fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: &'tcx ty::AdtDef, sp: Span, did: DefId) {
     let variant_spans: Vec<_> = adt
@@ -2141,158 +1039,6 @@ fn bad_non_zero_sized_fields<'tcx>(
     err.emit();
 }
 
-fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: &'tcx ty::AdtDef) {
-    if !adt.repr.transparent() {
-        return;
-    }
-    let sp = tcx.sess.source_map().guess_head_span(sp);
-
-    if adt.is_union() && !tcx.features().transparent_unions {
-        feature_err(
-            &tcx.sess.parse_sess,
-            sym::transparent_unions,
-            sp,
-            "transparent unions are unstable",
-        )
-        .emit();
-    }
-
-    if adt.variants.len() != 1 {
-        bad_variant_count(tcx, adt, sp, adt.did);
-        if adt.variants.is_empty() {
-            // Don't bother checking the fields. No variants (and thus no fields) exist.
-            return;
-        }
-    }
-
-    // For each field, figure out if it's known to be a ZST and align(1)
-    let field_infos = adt.all_fields().map(|field| {
-        let ty = field.ty(tcx, InternalSubsts::identity_for_item(tcx, field.did));
-        let param_env = tcx.param_env(field.did);
-        let layout = tcx.layout_of(param_env.and(ty));
-        // We are currently checking the type this field came from, so it must be local
-        let span = tcx.hir().span_if_local(field.did).unwrap();
-        let zst = layout.map(|layout| layout.is_zst()).unwrap_or(false);
-        let align1 = layout.map(|layout| layout.align.abi.bytes() == 1).unwrap_or(false);
-        (span, zst, align1)
-    });
-
-    let non_zst_fields =
-        field_infos.clone().filter_map(|(span, zst, _align1)| if !zst { Some(span) } else { None });
-    let non_zst_count = non_zst_fields.clone().count();
-    if non_zst_count != 1 {
-        bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, sp);
-    }
-    for (span, zst, align1) in field_infos {
-        if zst && !align1 {
-            struct_span_err!(
-                tcx.sess,
-                span,
-                E0691,
-                "zero-sized field in transparent {} has alignment larger than 1",
-                adt.descr(),
-            )
-            .span_label(span, "has alignment larger than 1")
-            .emit();
-        }
-    }
-}
-
-#[allow(trivial_numeric_casts)]
-pub fn check_enum<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    sp: Span,
-    vs: &'tcx [hir::Variant<'tcx>],
-    id: hir::HirId,
-) {
-    let def_id = tcx.hir().local_def_id(id);
-    let def = tcx.adt_def(def_id);
-    def.destructor(tcx); // force the destructor to be evaluated
-
-    if vs.is_empty() {
-        let attributes = tcx.get_attrs(def_id.to_def_id());
-        if let Some(attr) = tcx.sess.find_by_name(&attributes, sym::repr) {
-            struct_span_err!(
-                tcx.sess,
-                attr.span,
-                E0084,
-                "unsupported representation for zero-variant enum"
-            )
-            .span_label(sp, "zero-variant enum")
-            .emit();
-        }
-    }
-
-    let repr_type_ty = def.repr.discr_type().to_ty(tcx);
-    if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 {
-        if !tcx.features().repr128 {
-            feature_err(
-                &tcx.sess.parse_sess,
-                sym::repr128,
-                sp,
-                "repr with 128-bit type is unstable",
-            )
-            .emit();
-        }
-    }
-
-    for v in vs {
-        if let Some(ref e) = v.disr_expr {
-            tcx.ensure().typeck(tcx.hir().local_def_id(e.hir_id));
-        }
-    }
-
-    if tcx.adt_def(def_id).repr.int.is_none() && tcx.features().arbitrary_enum_discriminant {
-        let is_unit = |var: &hir::Variant<'_>| match var.data {
-            hir::VariantData::Unit(..) => true,
-            _ => false,
-        };
-
-        let has_disr = |var: &hir::Variant<'_>| var.disr_expr.is_some();
-        let has_non_units = vs.iter().any(|var| !is_unit(var));
-        let disr_units = vs.iter().any(|var| is_unit(&var) && has_disr(&var));
-        let disr_non_unit = vs.iter().any(|var| !is_unit(&var) && has_disr(&var));
-
-        if disr_non_unit || (disr_units && has_non_units) {
-            let mut err =
-                struct_span_err!(tcx.sess, sp, E0732, "`#[repr(inttype)]` must be specified");
-            err.emit();
-        }
-    }
-
-    let mut disr_vals: Vec<Discr<'tcx>> = Vec::with_capacity(vs.len());
-    for ((_, discr), v) in def.discriminants(tcx).zip(vs) {
-        // Check for duplicate discriminant values
-        if let Some(i) = disr_vals.iter().position(|&x| x.val == discr.val) {
-            let variant_did = def.variants[VariantIdx::new(i)].def_id;
-            let variant_i_hir_id = tcx.hir().local_def_id_to_hir_id(variant_did.expect_local());
-            let variant_i = tcx.hir().expect_variant(variant_i_hir_id);
-            let i_span = match variant_i.disr_expr {
-                Some(ref expr) => tcx.hir().span(expr.hir_id),
-                None => tcx.hir().span(variant_i_hir_id),
-            };
-            let span = match v.disr_expr {
-                Some(ref expr) => tcx.hir().span(expr.hir_id),
-                None => v.span,
-            };
-            struct_span_err!(
-                tcx.sess,
-                span,
-                E0081,
-                "discriminant value `{}` already exists",
-                disr_vals[i]
-            )
-            .span_label(i_span, format!("first use of `{}`", disr_vals[i]))
-            .span_label(span, format!("enum already has `{}`", disr_vals[i]))
-            .emit();
-        }
-        disr_vals.push(discr);
-    }
-
-    check_representable(tcx, sp, def_id);
-    check_transparent(tcx, sp, def);
-}
-
 fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, span: Span) {
     struct_span_err!(
         tcx.sess,
@@ -2337,51 +1083,6 @@ enum FallbackMode {
     All,
 }
 
-fn check_type_params_are_used<'tcx>(tcx: TyCtxt<'tcx>, generics: &ty::Generics, ty: Ty<'tcx>) {
-    debug!("check_type_params_are_used(generics={:?}, ty={:?})", generics, ty);
-
-    assert_eq!(generics.parent, None);
-
-    if generics.own_counts().types == 0 {
-        return;
-    }
-
-    let mut params_used = BitSet::new_empty(generics.params.len());
-
-    if ty.references_error() {
-        // If there is already another error, do not emit
-        // an error for not using a type parameter.
-        assert!(tcx.sess.has_errors());
-        return;
-    }
-
-    for leaf in ty.walk() {
-        if let GenericArgKind::Type(leaf_ty) = leaf.unpack() {
-            if let ty::Param(param) = leaf_ty.kind() {
-                debug!("found use of ty param {:?}", param);
-                params_used.insert(param.index);
-            }
-        }
-    }
-
-    for param in &generics.params {
-        if !params_used.contains(param.index) {
-            if let ty::GenericParamDefKind::Type { .. } = param.kind {
-                let span = tcx.def_span(param.def_id);
-                struct_span_err!(
-                    tcx.sess,
-                    span,
-                    E0091,
-                    "type parameter `{}` is unused",
-                    param.name,
-                )
-                .span_label(span, "unused type parameter")
-                .emit();
-            }
-        }
-    }
-}
-
 /// A wrapper for `InferCtxt`'s `in_progress_typeck_results` field.
 #[derive(Copy, Clone)]
 struct MaybeInProgressTables<'a, 'tcx> {
@@ -2420,22 +1121,6 @@ fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem<'tcx>) {}
     fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem<'tcx>) {}
 }
 
-fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
-    tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckItemTypesVisitor { tcx });
-}
-
-fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
-    wfcheck::check_item_well_formed(tcx, def_id);
-}
-
-fn check_trait_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
-    wfcheck::check_trait_item(tcx, def_id);
-}
-
-fn check_impl_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
-    wfcheck::check_impl_item(tcx, def_id);
-}
-
 fn typeck_item_bodies(tcx: TyCtxt<'_>, crate_num: CrateNum) {
     debug_assert!(crate_num == LOCAL_CRATE);
     tcx.par_body_owners(|body_owner_def_id| {