about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-05-02 14:03:20 +0000
committerbors <bors@rust-lang.org>2022-05-02 14:03:20 +0000
commit879fb425960798a79042b3b2a850d1262b7a91e8 (patch)
tree1d1454aa105200842e6beb2b918b5d5c5c0d07c4
parent542898328637b31412d91b882ce0dc4b85ad54e6 (diff)
parent5b5964f569ca07ba54710cb440aacaa1cf1e5c1a (diff)
downloadrust-879fb425960798a79042b3b2a850d1262b7a91e8.tar.gz
rust-879fb425960798a79042b3b2a850d1262b7a91e8.zip
Auto merge of #96431 - petrochenkov:parent, r=cjgillot
rustc: Panic by default in `DefIdTree::parent`

Only crate root def-ids don't have a parent, and in majority of cases the argument of `DefIdTree::parent` cannot be a crate root.
So we now panic by default in `parent` and introduce a new non-panicing function `opt_parent` for cases where the argument can be a crate root.

Same applies to `local_parent`/`opt_local_parent`.
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/utils.rs2
-rw-r--r--compiler/rustc_const_eval/src/const_eval/fn_queries.rs2
-rw-r--r--compiler/rustc_const_eval/src/util/call_kind.rs6
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs8
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs2
-rw-r--r--compiler/rustc_lint/src/types.rs6
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs2
-rw-r--r--compiler/rustc_middle/src/middle/stability.rs2
-rw-r--r--compiler/rustc_middle/src/ty/context.rs2
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs2
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs36
-rw-r--r--compiler/rustc_middle/src/ty/print/mod.rs4
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs4
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs2
-rw-r--r--compiler/rustc_middle/src/ty/util.rs8
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs4
-rw-r--r--compiler/rustc_monomorphize/src/partitioning/default.rs2
-rw-r--r--compiler/rustc_passes/src/dead.rs6
-rw-r--r--compiler/rustc_passes/src/entry.rs2
-rw-r--r--compiler/rustc_passes/src/liveness.rs6
-rw-r--r--compiler/rustc_passes/src/reachable.rs3
-rw-r--r--compiler/rustc_privacy/src/lib.rs10
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs2
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs4
-rw-r--r--compiler/rustc_resolve/src/imports.rs9
-rw-r--r--compiler/rustc_resolve/src/late.rs8
-rw-r--r--compiler/rustc_resolve/src/late/lifetimes.rs96
-rw-r--r--compiler/rustc_resolve/src/lib.rs3
-rw-r--r--compiler/rustc_save_analysis/src/dump_visitor.rs15
-rw-r--r--compiler/rustc_save_analysis/src/lib.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs2
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs6
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs2
-rw-r--r--compiler/rustc_typeck/src/check/method/suggest.rs2
-rw-r--r--compiler/rustc_typeck/src/collect.rs2
-rw-r--r--compiler/rustc_typeck/src/collect/type_of.rs2
-rw-r--r--src/librustdoc/clean/mod.rs10
-rw-r--r--src/librustdoc/clean/utils.rs2
-rw-r--r--src/librustdoc/html/format.rs2
-rw-r--r--src/librustdoc/passes/calculate_doc_coverage.rs2
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs18
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links/early.rs4
-rw-r--r--src/librustdoc/passes/collect_trait_impls.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_doc.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs2
50 files changed, 162 insertions, 176 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index b81360fd6aa..368c0be794b 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -90,7 +90,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         {
             if let ty::FnDef(id, _) = *literal.ty().kind() {
                 debug!("add_moved_or_invoked_closure_note: id={:?}", id);
-                if self.infcx.tcx.parent(id) == self.infcx.tcx.lang_items().fn_once_trait() {
+                if Some(self.infcx.tcx.parent(id)) == self.infcx.tcx.lang_items().fn_once_trait() {
                     let closure = match args.first() {
                         Some(Operand::Copy(ref place)) | Some(Operand::Move(ref place))
                             if target == place.local_or_deref_local() =>
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
index fe9851cfa56..8f243673907 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
@@ -46,7 +46,7 @@ pub fn DIB<'a, 'll>(cx: &'a CodegenCx<'ll, '_>) -> &'a DIBuilder<'ll> {
 }
 
 pub fn get_namespace_for_item<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll DIScope {
-    item_namespace(cx, cx.tcx.parent(def_id).expect("get_namespace_for_item: missing parent?"))
+    item_namespace(cx, cx.tcx.parent(def_id))
 }
 
 #[derive(Debug, PartialEq, Eq)]
diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
index 19a543ae777..1f291db55be 100644
--- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
@@ -17,7 +17,7 @@ pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Symbol> {
 }
 
 pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
-    let parent_id = tcx.local_parent(def_id).unwrap();
+    let parent_id = tcx.local_parent(def_id);
     tcx.def_kind(parent_id) == DefKind::Impl
         && tcx.impl_constness(parent_id) == hir::Constness::Const
 }
diff --git a/compiler/rustc_const_eval/src/util/call_kind.rs b/compiler/rustc_const_eval/src/util/call_kind.rs
index 60b45856f51..a7a480dd1d7 100644
--- a/compiler/rustc_const_eval/src/util/call_kind.rs
+++ b/compiler/rustc_const_eval/src/util/call_kind.rs
@@ -128,9 +128,9 @@ pub fn call_kind<'tcx>(
         } else {
             None
         };
-        let parent_self_ty = tcx
-            .parent(method_did)
-            .filter(|did| tcx.def_kind(*did) == rustc_hir::def::DefKind::Impl)
+        let parent_did = tcx.parent(method_did);
+        let parent_self_ty = (tcx.def_kind(parent_did) == rustc_hir::def::DefKind::Impl)
+            .then_some(parent_did)
             .and_then(|did| match tcx.type_of(did).kind() {
                 ty::Adt(def, ..) => Some(def.did()),
                 _ => None,
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index 465358de932..b1eb9f0da87 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -341,7 +341,7 @@ impl InferenceDiagnosticsData {
 
 impl InferenceDiagnosticsParentData {
     fn for_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<InferenceDiagnosticsParentData> {
-        let parent_def_id = tcx.parent(def_id)?;
+        let parent_def_id = tcx.parent(def_id);
 
         let parent_name =
             tcx.def_key(parent_def_id).disambiguated_data.data.get_opt_name()?.to_string();
@@ -854,10 +854,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         if let Some((DefKind::AssocFn, def_id)) =
             self.in_progress_typeck_results?.borrow().type_dependent_def(hir_id)
         {
-            return self
-                .tcx
-                .parent(def_id)
-                .filter(|&parent_def_id| self.tcx.is_trait(parent_def_id));
+            let parent_def_id = self.tcx.parent(def_id);
+            return self.tcx.is_trait(parent_def_id).then_some(parent_def_id);
         }
 
         None
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
index 7d3ed2ed38a..da03d944ceb 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
@@ -42,7 +42,7 @@ pub fn find_param_with_region<'tcx>(
     let (id, bound_region) = match *anon_region {
         ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region),
         ty::ReEarlyBound(ebr) => {
-            (tcx.parent(ebr.def_id).unwrap(), ty::BoundRegionKind::BrNamed(ebr.def_id, ebr.name))
+            (tcx.parent(ebr.def_id), ty::BoundRegionKind::BrNamed(ebr.def_id, ebr.name))
         }
         _ => return None, // not a free region
     };
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 437104d1aaf..dfce30171ff 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -1471,7 +1471,7 @@ impl InvalidAtomicOrdering {
             && let Some(adt) = cx.tcx.type_of(impl_did).ty_adt_def()
             // skip extension traits, only lint functions from the standard library
             && cx.tcx.trait_id_of_impl(impl_did).is_none()
-            && let Some(parent) = cx.tcx.parent(adt.did())
+            && let parent = cx.tcx.parent(adt.did())
             && cx.tcx.is_diagnostic_item(sym::atomic_mod, parent)
             && ATOMIC_TYPES.contains(&cx.tcx.item_name(adt.did()))
         {
@@ -1486,9 +1486,9 @@ impl InvalidAtomicOrdering {
         orderings.iter().any(|ordering| {
             tcx.item_name(did) == *ordering && {
                 let parent = tcx.parent(did);
-                parent == atomic_ordering
+                Some(parent) == atomic_ordering
                     // needed in case this is a ctor, not a variant
-                    || parent.map_or(false, |parent| tcx.parent(parent) == atomic_ordering)
+                    || tcx.opt_parent(parent) == atomic_ordering
             }
         })
     }
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index e0ed4022839..85e53559c29 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -546,7 +546,7 @@ impl<'hir> Map<'hir> {
         let def_kind = self.tcx.def_kind(def_id);
         match def_kind {
             DefKind::Trait | DefKind::TraitAlias => def_id,
-            DefKind::TyParam | DefKind::ConstParam => self.tcx.local_parent(def_id).unwrap(),
+            DefKind::TyParam | DefKind::ConstParam => self.tcx.local_parent(def_id),
             _ => bug!("ty_param_owner: {:?} is a {:?} not a type parameter", def_id, def_kind),
         }
     }
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
index 758658c3d8c..32041143240 100644
--- a/compiler/rustc_middle/src/middle/stability.rs
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -289,7 +289,7 @@ fn suggestion_for_allocator_api(
     feature: Symbol,
 ) -> Option<(Span, String, String, Applicability)> {
     if feature == sym::allocator_api {
-        if let Some(trait_) = tcx.parent(def_id) {
+        if let Some(trait_) = tcx.opt_parent(def_id) {
             if tcx.is_diagnostic_item(sym::Vec, trait_) {
                 let sm = tcx.sess.parse_sess.source_map();
                 let inner_types = sm.span_extend_to_prev_char(span, '<', true);
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 30fe3ffa7e3..f9ef264f68e 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -1491,7 +1491,7 @@ impl<'tcx> TyCtxt<'tcx> {
                 (free_region.scope.expect_local(), free_region.bound_region)
             }
             ty::ReEarlyBound(ref ebr) => (
-                self.parent(ebr.def_id).unwrap().expect_local(),
+                self.local_parent(ebr.def_id.expect_local()),
                 ty::BoundRegionKind::BrNamed(ebr.def_id, ebr.name),
             ),
             _ => return None, // not a free region
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index f53dc0000ca..a6717746979 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -108,7 +108,7 @@ impl<'tcx> Ty<'tcx> {
             | Placeholder(_)
             | Error(_) => false,
             Opaque(did, substs) => {
-                let parent = tcx.parent(*did).expect("opaque types always have a parent");
+                let parent = tcx.parent(*did);
                 if let hir::def::DefKind::TyAlias | hir::def::DefKind::AssocTy = tcx.def_kind(parent)
                     && let Opaque(parent_did, _) = tcx.type_of(parent).kind()
                     && parent_did == did
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index ec416722c21..af9216a990a 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -290,11 +290,28 @@ pub struct ClosureSizeProfileData<'tcx> {
 }
 
 pub trait DefIdTree: Copy {
-    fn parent(self, id: DefId) -> Option<DefId>;
+    fn opt_parent(self, id: DefId) -> Option<DefId>;
 
     #[inline]
-    fn local_parent(self, id: LocalDefId) -> Option<LocalDefId> {
-        Some(self.parent(id.to_def_id())?.expect_local())
+    #[track_caller]
+    fn parent(self, id: DefId) -> DefId {
+        match self.opt_parent(id) {
+            Some(id) => id,
+            // not `unwrap_or_else` to avoid breaking caller tracking
+            None => bug!("{id:?} doesn't have a parent"),
+        }
+    }
+
+    #[inline]
+    #[track_caller]
+    fn opt_local_parent(self, id: LocalDefId) -> Option<LocalDefId> {
+        self.opt_parent(id.to_def_id()).map(DefId::expect_local)
+    }
+
+    #[inline]
+    #[track_caller]
+    fn local_parent(self, id: LocalDefId) -> LocalDefId {
+        self.parent(id.to_def_id()).expect_local()
     }
 
     fn is_descendant_of(self, mut descendant: DefId, ancestor: DefId) -> bool {
@@ -303,7 +320,7 @@ pub trait DefIdTree: Copy {
         }
 
         while descendant != ancestor {
-            match self.parent(descendant) {
+            match self.opt_parent(descendant) {
                 Some(parent) => descendant = parent,
                 None => return false,
             }
@@ -313,7 +330,8 @@ pub trait DefIdTree: Copy {
 }
 
 impl<'tcx> DefIdTree for TyCtxt<'tcx> {
-    fn parent(self, id: DefId) -> Option<DefId> {
+    #[inline]
+    fn opt_parent(self, id: DefId) -> Option<DefId> {
         self.def_key(id).parent.map(|index| DefId { index, ..id })
     }
 }
@@ -2123,17 +2141,17 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn expect_variant_res(self, res: Res) -> &'tcx VariantDef {
         match res {
             Res::Def(DefKind::Variant, did) => {
-                let enum_did = self.parent(did).unwrap();
+                let enum_did = self.parent(did);
                 self.adt_def(enum_did).variant_with_id(did)
             }
             Res::Def(DefKind::Struct | DefKind::Union, did) => self.adt_def(did).non_enum_variant(),
             Res::Def(DefKind::Ctor(CtorOf::Variant, ..), variant_ctor_did) => {
-                let variant_did = self.parent(variant_ctor_did).unwrap();
-                let enum_did = self.parent(variant_did).unwrap();
+                let variant_did = self.parent(variant_ctor_did);
+                let enum_did = self.parent(variant_did);
                 self.adt_def(enum_did).variant_with_ctor_id(variant_ctor_did)
             }
             Res::Def(DefKind::Ctor(CtorOf::Struct, ..), ctor_did) => {
-                let struct_did = self.parent(ctor_did).expect("struct ctor has no parent");
+                let struct_did = self.parent(ctor_did);
                 self.adt_def(struct_did).non_enum_variant()
             }
             _ => bug!("expect_variant_res used with unexpected res {:?}", res),
diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs
index c74b3e9d0fc..3fe68f723ec 100644
--- a/compiler/rustc_middle/src/ty/print/mod.rs
+++ b/compiler/rustc_middle/src/ty/print/mod.rs
@@ -235,11 +235,11 @@ pub trait Printer<'tcx>: Sized {
         // as the trait.
         let in_self_mod = match characteristic_def_id_of_type(self_ty) {
             None => false,
-            Some(ty_def_id) => self.tcx().parent(ty_def_id) == Some(parent_def_id),
+            Some(ty_def_id) => self.tcx().parent(ty_def_id) == parent_def_id,
         };
         let in_trait_mod = match impl_trait_ref {
             None => false,
-            Some(trait_ref) => self.tcx().parent(trait_ref.def_id) == Some(parent_def_id),
+            Some(trait_ref) => self.tcx().parent(trait_ref.def_id) == parent_def_id,
         };
 
         if !in_self_mod && !in_trait_mod {
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 38362a4cbb9..991666908f9 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -408,7 +408,7 @@ pub trait PrettyPrinter<'tcx>:
             return Ok((self, false));
         };
 
-        let actual_parent = self.tcx().parent(def_id);
+        let actual_parent = self.tcx().opt_parent(def_id);
         debug!(
             "try_print_visible_def_path: visible_parent={:?} actual_parent={:?}",
             visible_parent, actual_parent,
@@ -643,7 +643,7 @@ pub trait PrettyPrinter<'tcx>:
                     return Ok(self);
                 }
 
-                let parent = self.tcx().parent(def_id).expect("opaque types always have a parent");
+                let parent = self.tcx().parent(def_id);
                 match self.tcx().def_kind(parent) {
                     DefKind::TyAlias | DefKind::AssocTy => {
                         if let ty::Opaque(d, _) = *self.tcx().type_of(parent).kind() {
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 1509de0e930..0d55fe3a392 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1798,7 +1798,7 @@ impl<'tcx> Region<'tcx> {
     /// function might return the `DefId` of a closure.
     pub fn free_region_binding_scope(self, tcx: TyCtxt<'_>) -> DefId {
         match *self {
-            ty::ReEarlyBound(br) => tcx.parent(br.def_id).unwrap(),
+            ty::ReEarlyBound(br) => tcx.parent(br.def_id),
             ty::ReFree(fr) => fr.scope,
             _ => bug!("free_region_binding_scope invoked on inappropriate region: {:?}", self),
         }
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 918fe49e8e3..c190eec7e5a 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -142,10 +142,10 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn res_generics_def_id(self, res: Res) -> Option<DefId> {
         match res {
             Res::Def(DefKind::Ctor(CtorOf::Variant, _), def_id) => {
-                Some(self.parent(def_id).and_then(|def_id| self.parent(def_id)).unwrap())
+                Some(self.parent(self.parent(def_id)))
             }
             Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Struct, _), def_id) => {
-                Some(self.parent(def_id).unwrap())
+                Some(self.parent(def_id))
             }
             // Other `DefKind`s don't have generics and would ICE when calling
             // `generics_of`.
@@ -500,9 +500,7 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn typeck_root_def_id(self, def_id: DefId) -> DefId {
         let mut def_id = def_id;
         while self.is_typeck_child(def_id) {
-            def_id = self.parent(def_id).unwrap_or_else(|| {
-                bug!("closure {:?} has no parent", def_id);
-            });
+            def_id = self.parent(def_id);
         }
         def_id
     }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index dbcd701c1ad..5b0aa4309a8 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -377,7 +377,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
     ) -> PatKind<'tcx> {
         let res = match res {
             Res::Def(DefKind::Ctor(CtorOf::Variant, ..), variant_ctor_id) => {
-                let variant_id = self.tcx.parent(variant_ctor_id).unwrap();
+                let variant_id = self.tcx.parent(variant_ctor_id);
                 Res::Def(DefKind::Variant, variant_id)
             }
             res => res,
@@ -385,7 +385,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
 
         let mut kind = match res {
             Res::Def(DefKind::Variant, variant_id) => {
-                let enum_id = self.tcx.parent(variant_id).unwrap();
+                let enum_id = self.tcx.parent(variant_id);
                 let adt_def = self.tcx.adt_def(enum_id);
                 if adt_def.is_enum() {
                     let substs = match ty.kind() {
diff --git a/compiler/rustc_monomorphize/src/partitioning/default.rs b/compiler/rustc_monomorphize/src/partitioning/default.rs
index bf99cd6e424..320765e7af3 100644
--- a/compiler/rustc_monomorphize/src/partitioning/default.rs
+++ b/compiler/rustc_monomorphize/src/partitioning/default.rs
@@ -352,7 +352,7 @@ fn compute_codegen_unit_name(
             cgu_def_id = None;
         }
 
-        current_def_id = tcx.parent(current_def_id).unwrap();
+        current_def_id = tcx.parent(current_def_id);
     }
 
     let cgu_def_id = cgu_def_id.unwrap();
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index 3cd18390285..991d0d45546 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -88,15 +88,15 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
             _ if self.in_pat => {}
             Res::PrimTy(..) | Res::SelfCtor(..) | Res::Local(..) => {}
             Res::Def(DefKind::Ctor(CtorOf::Variant, ..), ctor_def_id) => {
-                let variant_id = self.tcx.parent(ctor_def_id).unwrap();
-                let enum_id = self.tcx.parent(variant_id).unwrap();
+                let variant_id = self.tcx.parent(ctor_def_id);
+                let enum_id = self.tcx.parent(variant_id);
                 self.check_def_id(enum_id);
                 if !self.ignore_variant_stack.contains(&ctor_def_id) {
                     self.check_def_id(variant_id);
                 }
             }
             Res::Def(DefKind::Variant, variant_id) => {
-                let enum_id = self.tcx.parent(variant_id).unwrap();
+                let enum_id = self.tcx.parent(variant_id);
                 self.check_def_id(enum_id);
                 if !self.ignore_variant_stack.contains(&variant_id) {
                     self.check_def_id(variant_id);
diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs
index db083d0453b..f84b848e08d 100644
--- a/compiler/rustc_passes/src/entry.rs
+++ b/compiler/rustc_passes/src/entry.rs
@@ -27,7 +27,7 @@ struct EntryContext<'tcx> {
 
 impl<'tcx> ItemLikeVisitor<'tcx> for EntryContext<'tcx> {
     fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
-        let at_root = self.tcx.local_parent(item.def_id) == Some(CRATE_DEF_ID);
+        let at_root = self.tcx.opt_local_parent(item.def_id) == Some(CRATE_DEF_ID);
         find_item(item, self, at_root);
     }
 
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index 99ea73fe2fe..9eba7fb0811 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -332,9 +332,9 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
         let def_id = local_def_id.to_def_id();
 
         // Don't run unused pass for #[derive()]
-        if let Some(parent) = self.tcx.parent(def_id)
-            && let DefKind::Impl = self.tcx.def_kind(parent.expect_local())
-            && self.tcx.has_attr(parent, sym::automatically_derived)
+        let parent = self.tcx.local_parent(local_def_id);
+        if let DefKind::Impl = self.tcx.def_kind(parent)
+            && self.tcx.has_attr(parent.to_def_id(), sym::automatically_derived)
         {
             return;
         }
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index b65e3342613..b603352a9be 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -280,8 +280,7 @@ impl<'tcx> ReachableContext<'tcx> {
                     self.visit_nested_body(body);
                 }
                 hir::ImplItemKind::Fn(_, body) => {
-                    let impl_def_id =
-                        self.tcx.parent(search_item.to_def_id()).unwrap().expect_local();
+                    let impl_def_id = self.tcx.local_parent(search_item);
                     if method_might_be_inlined(self.tcx, impl_item, impl_def_id) {
                         self.visit_nested_body(body)
                     }
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 619e0d0341f..ee459d9c129 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -24,7 +24,8 @@ use rustc_middle::thir::abstract_const::Node as ACNode;
 use rustc_middle::ty::fold::TypeVisitor;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::subst::InternalSubsts;
-use rustc_middle::ty::{self, Const, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, Const, DefIdTree, GenericParamDefKind};
+use rustc_middle::ty::{TraitRef, Ty, TyCtxt, TypeFoldable};
 use rustc_session::lint;
 use rustc_span::hygiene::Transparency;
 use rustc_span::symbol::{kw, Ident};
@@ -456,9 +457,7 @@ impl<'tcx> EmbargoVisitor<'tcx> {
             return;
         }
 
-        let item_def_id = local_def_id.to_def_id();
-        let macro_module_def_id =
-            ty::DefIdTree::parent(self.tcx, item_def_id).unwrap().expect_local();
+        let macro_module_def_id = self.tcx.local_parent(local_def_id);
         if self.tcx.hir().opt_def_kind(macro_module_def_id) != Some(DefKind::Mod) {
             // The macro's parent doesn't correspond to a `mod`, return early (#63164, #65252).
             return;
@@ -477,8 +476,7 @@ impl<'tcx> EmbargoVisitor<'tcx> {
             if changed_reachability || module_def_id == CRATE_DEF_ID {
                 break;
             }
-            module_def_id =
-                ty::DefIdTree::parent(self.tcx, module_def_id.to_def_id()).unwrap().expect_local();
+            module_def_id = self.tcx.local_parent(module_def_id);
         }
     }
 
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 43c1062f32e..783ff5a3f91 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -1390,7 +1390,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
             && self
                 .r
                 .trait_impl_items
-                .contains(&ty::DefIdTree::parent(&*self.r, def_id).unwrap().expect_local()))
+                .contains(&ty::DefIdTree::local_parent(&*self.r, local_def_id)))
         {
             // Trait impl item visibility is inherited from its trait when not specified
             // explicitly. In that case we cannot determine it here in early resolve,
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 7d40ecb18b7..aef9fb57a6a 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -1321,7 +1321,7 @@ impl<'a> Resolver<'a> {
                         segms.push(ast::PathSegment::from_ident(ident));
                         let path = Path { span: name_binding.span, segments: segms, tokens: None };
                         let did = match res {
-                            Res::Def(DefKind::Ctor(..), did) => this.parent(did),
+                            Res::Def(DefKind::Ctor(..), did) => this.opt_parent(did),
                             _ => res.opt_def_id(),
                         };
 
@@ -1707,7 +1707,7 @@ impl<'a> Resolver<'a> {
             _,
         ) = binding.kind
         {
-            let def_id = self.parent(ctor_def_id).expect("no parent for a constructor");
+            let def_id = self.parent(ctor_def_id);
             let fields = self.field_names.get(&def_id)?;
             return fields.iter().map(|name| name.span).reduce(Span::to); // None for `struct Foo()`
         }
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index ef06ec356bd..3d0e2b9921d 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -13,7 +13,6 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::intern::Interned;
 use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan};
 use rustc_hir::def::{self, PartialRes};
-use rustc_hir::def_id::DefId;
 use rustc_middle::metadata::ModChild;
 use rustc_middle::span_bug;
 use rustc_middle::ty;
@@ -345,12 +344,6 @@ pub struct ImportResolver<'a, 'b> {
     pub r: &'a mut Resolver<'b>,
 }
 
-impl<'a, 'b> ty::DefIdTree for &'a ImportResolver<'a, 'b> {
-    fn parent(self, id: DefId) -> Option<DefId> {
-        self.r.parent(id)
-    }
-}
-
 impl<'a, 'b> ImportResolver<'a, 'b> {
     // Import resolution
     //
@@ -696,7 +689,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                 }
                 if !is_prelude &&
                    max_vis.get() != ty::Visibility::Invisible && // Allow empty globs.
-                   !max_vis.get().is_at_least(import.vis.get(), &*self)
+                   !max_vis.get().is_at_least(import.vis.get(), &*self.r)
                 {
                     let msg = "glob import doesn't reexport anything because no candidate is public enough";
                     self.r.lint_buffer.buffer_lint(UNUSED_IMPORTS, import.id, import.span, msg);
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index ca89f610322..b89b9c376af 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -1313,12 +1313,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             // Figure out if this is a type/trait segment,
             // which may need lifetime elision performed.
             let type_def_id = match partial_res.base_res() {
-                Res::Def(DefKind::AssocTy, def_id) if i + 2 == proj_start => {
-                    self.r.parent(def_id).unwrap()
-                }
-                Res::Def(DefKind::Variant, def_id) if i + 1 == proj_start => {
-                    self.r.parent(def_id).unwrap()
-                }
+                Res::Def(DefKind::AssocTy, def_id) if i + 2 == proj_start => self.r.parent(def_id),
+                Res::Def(DefKind::Variant, def_id) if i + 1 == proj_start => self.r.parent(def_id),
                 Res::Def(DefKind::Struct, def_id)
                 | Res::Def(DefKind::Union, def_id)
                 | Res::Def(DefKind::Enum, def_id)
diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs
index 787536d2a38..50428811fff 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_resolve/src/late/lifetimes.rs
@@ -534,21 +534,17 @@ fn is_late_bound_map<'tcx>(
 ) -> Option<(LocalDefId, &'tcx FxHashSet<LocalDefId>)> {
     match tcx.def_kind(def_id) {
         DefKind::AnonConst | DefKind::InlineConst => {
-            let mut def_id = tcx
-                .parent(def_id.to_def_id())
-                .unwrap_or_else(|| bug!("anon const or closure without a parent"));
+            let mut def_id = tcx.local_parent(def_id);
             // We search for the next outer anon const or fn here
             // while skipping closures.
             //
             // Note that for `AnonConst` we still just recurse until we
             // find a function body, but who cares :shrug:
-            while tcx.is_closure(def_id) {
-                def_id = tcx
-                    .parent(def_id)
-                    .unwrap_or_else(|| bug!("anon const or closure without a parent"));
+            while tcx.is_closure(def_id.to_def_id()) {
+                def_id = tcx.local_parent(def_id);
             }
 
-            tcx.is_late_bound_map(def_id.expect_local())
+            tcx.is_late_bound_map(def_id)
         }
         _ => resolve_lifetimes_for(tcx, def_id).late_bound.get(&def_id).map(|lt| (def_id, lt)),
     }
@@ -1864,7 +1860,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         let remove_decl = self
             .tcx
             .parent(def_id)
-            .and_then(|parent_def_id| parent_def_id.as_local())
+            .as_local()
             .and_then(|parent_def_id| self.tcx.hir().get_generics(parent_def_id))
             .and_then(|generics| self.lifetime_deletion_span(name, generics));
 
@@ -2003,37 +1999,36 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                             continue;
                         }
 
-                        if let Some(parent_def_id) = self.tcx.parent(def_id) {
-                            if let Some(def_id) = parent_def_id.as_local() {
-                                // lifetimes in `derive` expansions don't count (Issue #53738)
-                                if self
-                                    .tcx
-                                    .get_attrs(def_id.to_def_id())
-                                    .iter()
-                                    .any(|attr| attr.has_name(sym::automatically_derived))
-                                {
-                                    continue;
-                                }
+                        let parent_def_id = self.tcx.parent(def_id);
+                        if let Some(def_id) = parent_def_id.as_local() {
+                            // lifetimes in `derive` expansions don't count (Issue #53738)
+                            if self
+                                .tcx
+                                .get_attrs(def_id.to_def_id())
+                                .iter()
+                                .any(|attr| attr.has_name(sym::automatically_derived))
+                            {
+                                continue;
+                            }
 
-                                // opaque types generated when desugaring an async function can have a single
-                                // use lifetime even if it is explicitly denied (Issue #77175)
-                                if let hir::Node::Item(hir::Item {
-                                    kind: hir::ItemKind::OpaqueTy(ref opaque),
-                                    ..
-                                }) = self.tcx.hir().get_by_def_id(def_id)
-                                {
-                                    if !matches!(opaque.origin, hir::OpaqueTyOrigin::AsyncFn(..)) {
+                            // opaque types generated when desugaring an async function can have a single
+                            // use lifetime even if it is explicitly denied (Issue #77175)
+                            if let hir::Node::Item(hir::Item {
+                                kind: hir::ItemKind::OpaqueTy(ref opaque),
+                                ..
+                            }) = self.tcx.hir().get_by_def_id(def_id)
+                            {
+                                if !matches!(opaque.origin, hir::OpaqueTyOrigin::AsyncFn(..)) {
+                                    continue 'lifetimes;
+                                }
+                                // We want to do this only if the lifetime identifier is already defined
+                                // in the async function that generated this. Otherwise it could be
+                                // an opaque type defined by the developer and we still want this
+                                // lint to fail compilation
+                                for p in opaque.generics.params {
+                                    if defined_by.contains_key(&p.name) {
                                         continue 'lifetimes;
                                     }
-                                    // We want to do this only if the lifetime identifier is already defined
-                                    // in the async function that generated this. Otherwise it could be
-                                    // an opaque type defined by the developer and we still want this
-                                    // lint to fail compilation
-                                    for p in opaque.generics.params {
-                                        if defined_by.contains_key(&p.name) {
-                                            continue 'lifetimes;
-                                        }
-                                    }
                                 }
                             }
                         }
@@ -2087,20 +2082,19 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                             |lint| {
                                 let mut err = lint
                                     .build(&format!("lifetime parameter `{}` never used", name));
-                                if let Some(parent_def_id) = self.tcx.parent(def_id) {
-                                    if let Some(generics) =
-                                        self.tcx.hir().get_generics(parent_def_id.expect_local())
-                                    {
-                                        let unused_lt_span =
-                                            self.lifetime_deletion_span(name, generics);
-                                        if let Some(span) = unused_lt_span {
-                                            err.span_suggestion(
-                                                span,
-                                                "elide the unused lifetime",
-                                                String::new(),
-                                                Applicability::MachineApplicable,
-                                            );
-                                        }
+                                let parent_def_id = self.tcx.parent(def_id);
+                                if let Some(generics) =
+                                    self.tcx.hir().get_generics(parent_def_id.expect_local())
+                                {
+                                    let unused_lt_span =
+                                        self.lifetime_deletion_span(name, generics);
+                                    if let Some(span) = unused_lt_span {
+                                        err.span_suggestion(
+                                            span,
+                                            "elide the unused lifetime",
+                                            String::new(),
+                                            Applicability::MachineApplicable,
+                                        );
                                     }
                                 }
                                 err.emit();
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 92e55a0ccb2..f6109b1dc1a 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -1111,7 +1111,8 @@ impl<'a> AsMut<Resolver<'a>> for Resolver<'a> {
 }
 
 impl<'a, 'b> DefIdTree for &'a Resolver<'b> {
-    fn parent(self, id: DefId) -> Option<DefId> {
+    #[inline]
+    fn opt_parent(self, id: DefId) -> Option<DefId> {
         match id.as_local() {
             Some(id) => self.definitions.def_key(id).parent,
             None => self.cstore().def_key(id).parent,
diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs
index b4230a144f8..e1c9ecc055f 100644
--- a/compiler/rustc_save_analysis/src/dump_visitor.rs
+++ b/compiler/rustc_save_analysis/src/dump_visitor.rs
@@ -1138,8 +1138,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
                     let access = access_from!(self.save_ctxt, item.def_id);
                     let ref_id = self.lookup_def_id(item.hir_id()).map(id_from_def_id);
                     let span = self.span_from_span(sub_span);
-                    let parent =
-                        self.save_ctxt.tcx.parent(item.def_id.to_def_id()).map(id_from_def_id);
+                    let parent = self.save_ctxt.tcx.local_parent(item.def_id);
                     self.dumper.import(
                         &access,
                         Import {
@@ -1149,7 +1148,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
                             alias_span: None,
                             name: item.ident.to_string(),
                             value: String::new(),
-                            parent,
+                            parent: Some(id_from_def_id(parent.to_def_id())),
                         },
                     );
                     self.write_sub_paths_truncated(&path);
@@ -1166,8 +1165,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
                     if !self.span.filter_generated(item.span) {
                         let access = access_from!(self.save_ctxt, item.def_id);
                         let span = self.span_from_span(sub_span);
-                        let parent =
-                            self.save_ctxt.tcx.parent(item.def_id.to_def_id()).map(id_from_def_id);
+                        let parent = self.save_ctxt.tcx.local_parent(item.def_id);
                         self.dumper.import(
                             &access,
                             Import {
@@ -1177,7 +1175,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
                                 alias_span: None,
                                 name: "*".to_owned(),
                                 value: names.join(", "),
-                                parent,
+                                parent: Some(id_from_def_id(parent.to_def_id())),
                             },
                         );
                         self.write_sub_paths(&path);
@@ -1188,8 +1186,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
                 let name_span = item.ident.span;
                 if !self.span.filter_generated(name_span) {
                     let span = self.span_from_span(name_span);
-                    let parent =
-                        self.save_ctxt.tcx.parent(item.def_id.to_def_id()).map(id_from_def_id);
+                    let parent = self.save_ctxt.tcx.local_parent(item.def_id);
                     self.dumper.import(
                         &Access { public: false, reachable: false },
                         Import {
@@ -1199,7 +1196,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
                             alias_span: None,
                             name: item.ident.to_string(),
                             value: String::new(),
-                            parent,
+                            parent: Some(id_from_def_id(parent.to_def_id())),
                         },
                     );
                 }
diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs
index 582186cbd1f..5d94884e0f6 100644
--- a/compiler/rustc_save_analysis/src/lib.rs
+++ b/compiler/rustc_save_analysis/src/lib.rs
@@ -690,7 +690,7 @@ impl<'tcx> SaveContext<'tcx> {
                 // This is a reference to a tuple struct or an enum variant where the def_id points
                 // to an invisible constructor function. That is not a very useful
                 // def, so adjust to point to the tuple struct or enum variant itself.
-                let parent_def_id = self.tcx.parent(def_id).unwrap();
+                let parent_def_id = self.tcx.parent(def_id);
                 Some(Ref { kind: RefKind::Type, span, ref_id: id_from_def_id(parent_def_id) })
             }
             Res::Def(HirDefKind::Static(_) | HirDefKind::Const | HirDefKind::AssocConst, _) => {
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 446b14a17ae..a3d3c7c0cf3 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -1906,7 +1906,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                         GeneratorKind::Async(AsyncGeneratorKind::Fn) => self
                             .tcx
                             .parent(generator_did)
-                            .and_then(|parent_did| parent_did.as_local())
+                            .as_local()
                             .map(|parent_did| hir.local_def_id_to_hir_id(parent_did))
                             .and_then(|parent_hir_id| hir.opt_name(parent_hir_id))
                             .map(|name| {
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index b8422ce3208..fd1b7bfa0b1 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -1952,7 +1952,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
     ) -> Ty<'tcx> {
         let tcx = self.tcx();
 
-        let trait_def_id = tcx.parent(item_def_id).unwrap();
+        let trait_def_id = tcx.parent(item_def_id);
 
         debug!("qpath_to_ty: trait_def_id={:?}", trait_def_id);
 
@@ -2159,11 +2159,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
                     // `DefKind::Ctor` -> `DefKind::Variant`
                     if let DefKind::Ctor(..) = kind {
-                        def_id = tcx.parent(def_id).unwrap()
+                        def_id = tcx.parent(def_id);
                     }
 
                     // `DefKind::Variant` -> `DefKind::Enum`
-                    let enum_def_id = tcx.parent(def_id).unwrap();
+                    let enum_def_id = tcx.parent(def_id);
                     (enum_def_id, last - 1)
                 } else {
                     // FIXME: lint here recommending `Enum::<...>::Variant` form
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index 8feb7170983..93b0edb84c0 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -838,7 +838,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let def_kind = self.tcx.def_kind(def_id);
 
         let item_ty = if let DefKind::Variant = def_kind {
-            self.tcx.type_of(self.tcx.parent(def_id).expect("variant w/out parent"))
+            self.tcx.type_of(self.tcx.parent(def_id))
         } else {
             self.tcx.type_of(def_id)
         };
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index 640dccf66b0..634ba2baf96 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -1542,7 +1542,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let (candidates, globs): (Vec<_>, Vec<_>) = candidates.into_iter().partition(|trait_did| {
             if let Some(parent_did) = parent_map.get(trait_did) {
                 // If the item is re-exported as `_`, we should suggest a glob-import instead.
-                if Some(*parent_did) != self.tcx.parent(*trait_did)
+                if *parent_did != self.tcx.parent(*trait_did)
                     && self
                         .tcx
                         .module_children(*parent_did)
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index f85735ec57b..c1c63c46066 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -3162,7 +3162,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
 
     // #73631: closures inherit `#[target_feature]` annotations
     if tcx.features().target_feature_11 && tcx.is_closure(id) {
-        let owner_id = tcx.parent(id).expect("closure should have a parent");
+        let owner_id = tcx.parent(id);
         codegen_fn_attrs
             .target_features
             .extend(tcx.codegen_fn_attrs(owner_id).target_features.iter().copied())
diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs
index 495b8d3b4ee..75ad584f419 100644
--- a/compiler/rustc_typeck/src/collect/type_of.rs
+++ b/compiler/rustc_typeck/src/collect/type_of.rs
@@ -683,7 +683,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
         Some(hidden) => hidden.ty,
         None => {
             let span = tcx.def_span(def_id);
-            let name = tcx.item_name(tcx.parent(def_id.to_def_id()).unwrap());
+            let name = tcx.item_name(tcx.local_parent(def_id).to_def_id());
             let label = format!(
                 "`{}` must be used in combination with a concrete type within the same module",
                 name
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index d458deddae3..eea4eef9065 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -421,7 +421,7 @@ impl Clean<GenericParamDef> for ty::GenericParamDef {
                     // `self_def_id` set, we override it here.
                     // See https://github.com/rust-lang/rust/issues/85454
                     if let QPath { ref mut self_def_id, .. } = default {
-                        *self_def_id = cx.tcx.parent(self.def_id);
+                        *self_def_id = Some(cx.tcx.parent(self.def_id));
                     }
 
                     Some(default)
@@ -1068,7 +1068,7 @@ impl Clean<Item> for hir::ImplItem<'_> {
             let mut what_rustc_thinks =
                 Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx);
 
-            let impl_ref = cx.tcx.parent(local_did).and_then(|did| cx.tcx.impl_trait_ref(did));
+            let impl_ref = cx.tcx.impl_trait_ref(cx.tcx.local_parent(self.def_id));
 
             // Trait impl items always inherit the impl's visibility --
             // we don't want to show `pub`.
@@ -1260,7 +1260,7 @@ impl Clean<Item> for ty::AssocItem {
         let mut what_rustc_thinks =
             Item::from_def_id_and_parts(self.def_id, Some(self.name), kind, cx);
 
-        let impl_ref = tcx.parent(self.def_id).and_then(|did| tcx.impl_trait_ref(did));
+        let impl_ref = tcx.impl_trait_ref(tcx.parent(self.def_id));
 
         // Trait impl items always inherit the impl's visibility --
         // we don't want to show `pub`.
@@ -1742,9 +1742,7 @@ fn clean_field(def_id: DefId, name: Symbol, ty: Type, cx: &mut DocContext<'_>) -
 }
 
 fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
-    let parent = tcx
-        .parent(def_id)
-        .expect("is_field_vis_inherited can only be called on struct or variant fields");
+    let parent = tcx.parent(def_id);
     match tcx.def_kind(parent) {
         DefKind::Struct | DefKind::Union => false,
         DefKind::Variant => true,
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index abfc5b80a3e..3a2f24d719c 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -455,7 +455,7 @@ crate fn find_nearest_parent_module(tcx: TyCtxt<'_>, def_id: DefId) -> Option<De
         let mut current = def_id;
         // The immediate parent might not always be a module.
         // Find the first parent which is.
-        while let Some(parent) = tcx.parent(current) {
+        while let Some(parent) = tcx.opt_parent(current) {
             if tcx.def_kind(parent) == DefKind::Mod {
                 return Some(parent);
             }
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 118807a8286..528eb6410cb 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -563,7 +563,7 @@ crate fn href_with_root_path(
     let did = match def_kind {
         DefKind::AssocTy | DefKind::AssocFn | DefKind::AssocConst | DefKind::Variant => {
             // documented on their parent's page
-            tcx.parent(did).unwrap()
+            tcx.parent(did)
         }
         _ => did,
     };
diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs
index 33d83aa339d..0d40ef4c600 100644
--- a/src/librustdoc/passes/calculate_doc_coverage.rs
+++ b/src/librustdoc/passes/calculate_doc_coverage.rs
@@ -239,7 +239,7 @@ impl<'a, 'b> DocVisitor for CoverageCalculator<'a, 'b> {
                 let should_be_ignored = i
                     .item_id
                     .as_def_id()
-                    .and_then(|def_id| self.ctx.tcx.parent(def_id))
+                    .and_then(|def_id| self.ctx.tcx.opt_parent(def_id))
                     .and_then(|def_id| self.ctx.tcx.hir().get_if_local(def_id))
                     .map(|node| {
                         matches!(
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 84512fab269..22b2f8c0c8e 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -334,7 +334,7 @@ impl ItemFragment {
                     FragmentKind::StructField => write!(s, "structfield.{}", name),
                     FragmentKind::Variant => write!(s, "variant.{}", name),
                     FragmentKind::VariantField => {
-                        let variant = tcx.item_name(tcx.parent(def_id).unwrap());
+                        let variant = tcx.item_name(tcx.parent(def_id));
                         write!(s, "variant.{}.field.{}", variant, name)
                     }
                 }
@@ -509,10 +509,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                 | DefKind::AssocTy
                 | DefKind::Variant
                 | DefKind::Field) => {
-                    let parent_def_id = tcx.parent(def_id).expect("nested item has no parent");
+                    let parent_def_id = tcx.parent(def_id);
                     if def_kind == DefKind::Field && tcx.def_kind(parent_def_id) == DefKind::Variant
                     {
-                        tcx.parent(parent_def_id).expect("variant has no parent")
+                        tcx.parent(parent_def_id)
                     } else {
                         parent_def_id
                     }
@@ -2336,14 +2336,10 @@ fn handle_variant(
     cx: &DocContext<'_>,
     res: Res,
 ) -> Result<(Res, Option<ItemFragment>), ErrorKind<'static>> {
-    cx.tcx
-        .parent(res.def_id(cx.tcx))
-        .map(|parent| {
-            let parent_def = Res::Def(DefKind::Enum, parent);
-            let variant = cx.tcx.expect_variant_res(res.as_hir_res().unwrap());
-            (parent_def, Some(ItemFragment(FragmentKind::Variant, variant.def_id)))
-        })
-        .ok_or_else(|| ResolutionFailure::NoParentItem.into())
+    let parent = cx.tcx.parent(res.def_id(cx.tcx));
+    let parent_def = Res::Def(DefKind::Enum, parent);
+    let variant = cx.tcx.expect_variant_res(res.as_hir_res().unwrap());
+    Ok((parent_def, Some(ItemFragment(FragmentKind::Variant, variant.def_id))))
 }
 
 /// Resolve a primitive type or value.
diff --git a/src/librustdoc/passes/collect_intra_doc_links/early.rs b/src/librustdoc/passes/collect_intra_doc_links/early.rs
index 3858c1cb056..1d2ef832db7 100644
--- a/src/librustdoc/passes/collect_intra_doc_links/early.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links/early.rs
@@ -191,7 +191,7 @@ impl<'ra> EarlyDocLinkResolver<'_, 'ra> {
             return;
         }
         // FIXME: actually resolve links, not just add traits in scope.
-        if let Some(parent_id) = self.resolver.parent(scope_id) {
+        if let Some(parent_id) = self.resolver.opt_parent(scope_id) {
             self.add_traits_in_scope(parent_id);
         }
     }
@@ -286,7 +286,7 @@ impl<'ra> EarlyDocLinkResolver<'_, 'ra> {
             {
                 if let Some(def_id) = child.res.opt_def_id() && !def_id.is_local() {
                     let scope_id = match child.res {
-                        Res::Def(DefKind::Variant, ..) => self.resolver.parent(def_id).unwrap(),
+                        Res::Def(DefKind::Variant, ..) => self.resolver.parent(def_id),
                         _ => def_id,
                     };
                     self.resolve_doc_links_extern_outer(def_id, scope_id); // Outer attribute scope
diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs
index 9644e3d15fd..d245c3750ec 100644
--- a/src/librustdoc/passes/collect_trait_impls.rs
+++ b/src/librustdoc/passes/collect_trait_impls.rs
@@ -49,7 +49,7 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate
         let _prof_timer = cx.tcx.sess.prof.generic_activity("build_local_trait_impls");
         let mut attr_buf = Vec::new();
         for &impl_def_id in all_trait_impls.iter().take_while(|def_id| def_id.is_local()) {
-            let mut parent = cx.tcx.parent(impl_def_id);
+            let mut parent = Some(cx.tcx.parent(impl_def_id));
             while let Some(did) = parent {
                 attr_buf.extend(
                     cx.tcx
@@ -65,7 +65,7 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate
                         })
                         .cloned(),
                 );
-                parent = cx.tcx.parent(did);
+                parent = cx.tcx.opt_parent(did);
             }
             inline::build_impl(cx, None, impl_def_id, Some(&attr_buf), &mut new_items_local);
             attr_buf.clear();
diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
index 777ec9b75bc..aa3552001f4 100644
--- a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -193,7 +193,7 @@ fn find_sugg_for_if_let<'tcx>(
         PatKind::TupleStruct(ref qpath, [sub_pat], _) => {
             if let PatKind::Wild = sub_pat.kind {
                 let res = cx.typeck_results().qpath_res(qpath, check_pat.hir_id);
-                let Some(id) = res.opt_def_id().and_then(|ctor_id| cx.tcx.parent(ctor_id)) else { return };
+                let Some(id) = res.opt_def_id().map(|ctor_id| cx.tcx.parent(ctor_id)) else { return };
                 let lang_items = cx.tcx.lang_items();
                 if Some(id) == lang_items.result_ok_variant() {
                     ("is_ok()", try_get_generic_ty(op_ty, 0).unwrap_or(op_ty))
diff --git a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
index eec232e6d09..b88ec0963f2 100644
--- a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
@@ -42,7 +42,7 @@ pub(crate) trait BindInsteadOfMap {
 
     fn no_op_msg(cx: &LateContext<'_>) -> Option<String> {
         let variant_id = cx.tcx.lang_items().require(Self::VARIANT_LANG_ITEM).ok()?;
-        let item_id = cx.tcx.parent(variant_id)?;
+        let item_id = cx.tcx.parent(variant_id);
         Some(format!(
             "using `{}.{}({})`, which is a no-op",
             cx.tcx.item_name(item_id),
@@ -53,7 +53,7 @@ pub(crate) trait BindInsteadOfMap {
 
     fn lint_msg(cx: &LateContext<'_>) -> Option<String> {
         let variant_id = cx.tcx.lang_items().require(Self::VARIANT_LANG_ITEM).ok()?;
-        let item_id = cx.tcx.parent(variant_id)?;
+        let item_id = cx.tcx.parent(variant_id);
         Some(format!(
             "using `{}.{}(|x| {}(y))`, which is more succinctly expressed as `{}(|x| y)`",
             cx.tcx.item_name(item_id),
@@ -145,7 +145,7 @@ pub(crate) trait BindInsteadOfMap {
         if_chain! {
             if let Some(adt) = cx.typeck_results().expr_ty(recv).ty_adt_def();
             if let Ok(vid) = cx.tcx.lang_items().require(Self::VARIANT_LANG_ITEM);
-            if Some(adt.did()) == cx.tcx.parent(vid);
+            if adt.did() == cx.tcx.parent(vid);
             then {} else { return false; }
         }
 
@@ -182,7 +182,7 @@ pub(crate) trait BindInsteadOfMap {
     fn is_variant(cx: &LateContext<'_>, res: Res) -> bool {
         if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fn), id) = res {
             if let Ok(variant_id) = cx.tcx.lang_items().require(Self::VARIANT_LANG_ITEM) {
-                return cx.tcx.parent(id) == Some(variant_id);
+                return cx.tcx.parent(id) == variant_id;
             }
         }
         false
diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs b/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs
index 2cf2c5641bf..f7b79f0839b 100644
--- a/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs
@@ -19,7 +19,7 @@ pub(super) fn check(
     if_chain! {
         if let Some(args) = method_chain_args(info.chain, chain_methods);
         if let hir::ExprKind::Call(fun, [arg_char]) = info.other.kind;
-        if let Some(id) = path_def_id(cx, fun).and_then(|ctor_id| cx.tcx.parent(ctor_id));
+        if let Some(id) = path_def_id(cx, fun).map(|ctor_id| cx.tcx.parent(ctor_id));
         if Some(id) == cx.tcx.lang_items().option_some_variant();
         then {
             let mut applicability = Applicability::MachineApplicable;
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs
index 2a5ab6e625c..76bc9466ed8 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs
@@ -75,7 +75,7 @@ pub(super) fn check<'tcx>(
             let arg_snippet = snippet(cx, span, "..");
             let body = cx.tcx.hir().body(id);
                 if let Some((func, [arg_char])) = reduce_unit_expression(&body.value);
-                if let Some(id) = path_def_id(cx, func).and_then(|ctor_id| cx.tcx.parent(ctor_id));
+                if let Some(id) = path_def_id(cx, func).map(|ctor_id| cx.tcx.parent(ctor_id));
                 if Some(id) == cx.tcx.lang_items().option_some_variant();
                 then {
                     let func_snippet = snippet(cx, arg_char.span, "..");
diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs
index 5816a95dceb..a20377f320b 100644
--- a/src/tools/clippy/clippy_lints/src/missing_doc.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs
@@ -114,7 +114,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
             hir::ItemKind::Fn(..) => {
                 // ignore main()
                 if it.ident.name == sym::main {
-                    let at_root = cx.tcx.local_parent(it.def_id) == Some(CRATE_DEF_ID);
+                    let at_root = cx.tcx.local_parent(it.def_id) == CRATE_DEF_ID;
                     if at_root {
                         return;
                     }
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 74978720424..7d46952d971 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -235,7 +235,7 @@ pub fn is_lang_ctor(cx: &LateContext<'_>, qpath: &QPath<'_>, lang_item: LangItem
     if let QPath::Resolved(_, path) = qpath {
         if let Res::Def(DefKind::Ctor(..), ctor_id) = path.res {
             if let Ok(item_id) = cx.tcx.lang_items().require(lang_item) {
-                return cx.tcx.parent(ctor_id) == Some(item_id);
+                return cx.tcx.parent(ctor_id) == item_id;
             }
         }
     }