1
Fork 0

Auto merge of #120951 - matthiaskrgr:rollup-0nnm7dv, r=matthiaskrgr

Rollup of 8 pull requests

Successful merges:

 - #110483 (Create try_new function for ThinBox)
 - #120740 (Make cmath.rs a single file)
 - #120872 (hir: Refactor getters for HIR parents)
 - #120880 (add note on comparing vtables / function pointers)
 - #120885 (interpret/visitor: ensure we only see normalized types)
 - #120888 (assert_unsafe_precondition cleanup)
 - #120897 (Encode `coroutine_for_closure` for foreign crates)
 - #120937 ([docs] Update armv6k-nintendo-3ds platform docs for outdated info)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-02-12 00:34:22 +00:00
commit 084ce5bdb5
98 changed files with 524 additions and 534 deletions

View file

@ -403,8 +403,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
} }
} }
let typeck = self.infcx.tcx.typeck(self.mir_def_id()); let typeck = self.infcx.tcx.typeck(self.mir_def_id());
let hir_id = hir.parent_id(expr.hir_id); let parent = self.infcx.tcx.parent_hir_node(expr.hir_id);
let parent = self.infcx.tcx.hir_node(hir_id);
let (def_id, args, offset) = if let hir::Node::Expr(parent_expr) = parent let (def_id, args, offset) = if let hir::Node::Expr(parent_expr) = parent
&& let hir::ExprKind::MethodCall(_, _, args, _) = parent_expr.kind && let hir::ExprKind::MethodCall(_, _, args, _) = parent_expr.kind
&& let Some(def_id) = typeck.type_dependent_def_id(parent_expr.hir_id) && let Some(def_id) = typeck.type_dependent_def_id(parent_expr.hir_id)
@ -1660,8 +1659,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// Check that the parent of the closure is a method call, // Check that the parent of the closure is a method call,
// with receiver matching with local's type (modulo refs) // with receiver matching with local's type (modulo refs)
let parent = hir.parent_id(closure_expr.hir_id); if let hir::Node::Expr(parent) = tcx.parent_hir_node(closure_expr.hir_id) {
if let hir::Node::Expr(parent) = tcx.hir_node(parent) {
if let hir::ExprKind::MethodCall(_, recv, ..) = parent.kind { if let hir::ExprKind::MethodCall(_, recv, ..) = parent.kind {
let recv_ty = typeck_results.expr_ty(recv); let recv_ty = typeck_results.expr_ty(recv);

View file

@ -944,7 +944,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let hir = self.infcx.tcx.hir(); let hir = self.infcx.tcx.hir();
let closure_id = self.mir_hir_id(); let closure_id = self.mir_hir_id();
let closure_span = self.infcx.tcx.def_span(self.mir_def_id()); let closure_span = self.infcx.tcx.def_span(self.mir_def_id());
let fn_call_id = hir.parent_id(closure_id); let fn_call_id = self.infcx.tcx.parent_hir_id(closure_id);
let node = self.infcx.tcx.hir_node(fn_call_id); let node = self.infcx.tcx.hir_node(fn_call_id);
let def_id = hir.enclosing_body_owner(fn_call_id); let def_id = hir.enclosing_body_owner(fn_call_id);
let mut look_at_return = true; let mut look_at_return = true;
@ -1034,7 +1034,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
if let InstanceDef::Item(def_id) = source.instance if let InstanceDef::Item(def_id) = source.instance
&& let Some(Node::Expr(hir::Expr { hir_id, kind, .. })) = hir.get_if_local(def_id) && let Some(Node::Expr(hir::Expr { hir_id, kind, .. })) = hir.get_if_local(def_id)
&& let ExprKind::Closure(hir::Closure { kind: hir::ClosureKind::Closure, .. }) = kind && let ExprKind::Closure(hir::Closure { kind: hir::ClosureKind::Closure, .. }) = kind
&& let Some(Node::Expr(expr)) = hir.find_parent(*hir_id) && let Node::Expr(expr) = self.infcx.tcx.parent_hir_node(*hir_id)
{ {
let mut cur_expr = expr; let mut cur_expr = expr;
while let ExprKind::MethodCall(path_segment, recv, _, _) = cur_expr.kind { while let ExprKind::MethodCall(path_segment, recv, _, _) = cur_expr.kind {

View file

@ -214,8 +214,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
if let Some(id) = placeholder.bound.kind.get_id() if let Some(id) = placeholder.bound.kind.get_id()
&& let Some(placeholder_id) = id.as_local() && let Some(placeholder_id) = id.as_local()
&& let gat_hir_id = self.infcx.tcx.local_def_id_to_hir_id(placeholder_id) && let gat_hir_id = self.infcx.tcx.local_def_id_to_hir_id(placeholder_id)
&& let Some(generics_impl) = && let Some(generics_impl) = self
hir.get_parent(hir.parent_id(gat_hir_id)).generics() .infcx
.tcx
.parent_hir_node(self.infcx.tcx.parent_hir_id(gat_hir_id))
.generics()
{ {
Some((gat_hir_id, generics_impl)) Some((gat_hir_id, generics_impl))
} else { } else {

View file

@ -149,6 +149,8 @@ where
"`field` projection called on a slice -- call `index` projection instead" "`field` projection called on a slice -- call `index` projection instead"
); );
let offset = base.layout().fields.offset(field); let offset = base.layout().fields.offset(field);
// Computing the layout does normalization, so we get a normalized type out of this
// even if the field type is non-normalized (possible e.g. via associated types).
let field_layout = base.layout().field(self, field); let field_layout = base.layout().field(self, field);
// Offset may need adjustment for unsized fields. // Offset may need adjustment for unsized fields.

View file

@ -153,6 +153,16 @@ pub trait ValueVisitor<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>: Sized {
// We visited all parts of this one. // We visited all parts of this one.
return Ok(()); return Ok(());
} }
// Non-normalized types should never show up here.
ty::Param(..)
| ty::Alias(..)
| ty::Bound(..)
| ty::Placeholder(..)
| ty::Infer(..)
| ty::Error(..) => throw_inval!(TooGeneric),
// The rest is handled below.
_ => {} _ => {}
}; };

View file

@ -131,11 +131,10 @@ fn is_parent_const_stable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
let local_def_id = def_id.expect_local(); let local_def_id = def_id.expect_local();
let hir_id = tcx.local_def_id_to_hir_id(local_def_id); let hir_id = tcx.local_def_id_to_hir_id(local_def_id);
let Some(parent) = tcx.hir().opt_parent_id(hir_id) else { return false }; let parent_owner_id = tcx.parent_hir_id(hir_id).owner;
if !tcx.is_const_trait_impl_raw(parent_owner_id.to_def_id()) {
if !tcx.is_const_trait_impl_raw(parent.owner.def_id.to_def_id()) {
return false; return false;
} }
tcx.lookup_const_stability(parent.owner).is_some_and(|stab| stab.is_const_stable()) tcx.lookup_const_stability(parent_owner_id).is_some_and(|stab| stab.is_const_stable())
} }

View file

@ -3508,7 +3508,7 @@ impl<'hir> Node<'hir> {
/// ```ignore (illustrative) /// ```ignore (illustrative)
/// ctor /// ctor
/// .ctor_hir_id() /// .ctor_hir_id()
/// .and_then(|ctor_id| tcx.hir().find_parent(ctor_id)) /// .map(|ctor_id| tcx.parent_hir_node(ctor_id))
/// .and_then(|parent| parent.ident()) /// .and_then(|parent| parent.ident())
/// ``` /// ```
pub fn ident(&self) -> Option<Ident> { pub fn ident(&self) -> Option<Ident> {

View file

@ -2749,14 +2749,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
arg_idx: Option<usize>, arg_idx: Option<usize>,
) -> Option<Ty<'tcx>> { ) -> Option<Ty<'tcx>> {
let tcx = self.tcx(); let tcx = self.tcx();
let hir = tcx.hir();
let hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), ident, .. }) = let hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), ident, .. }) =
tcx.hir_node(fn_hir_id) tcx.hir_node(fn_hir_id)
else { else {
return None; return None;
}; };
let i = hir.get_parent(fn_hir_id).expect_item().expect_impl(); let i = tcx.parent_hir_node(fn_hir_id).expect_item().expect_impl();
let trait_ref = let trait_ref =
self.instantiate_mono_trait_ref(i.of_trait.as_ref()?, self.ast_ty_to_ty(i.self_ty)); self.instantiate_mono_trait_ref(i.of_trait.as_ref()?, self.ast_ty_to_ty(i.self_ty));

View file

@ -224,11 +224,8 @@ pub(crate) fn placeholder_type_error_diag<'tcx>(
is_fn = true; is_fn = true;
// Check if parent is const or static // Check if parent is const or static
let parent_id = tcx.hir().parent_id(hir_ty.hir_id);
let parent_node = tcx.hir_node(parent_id);
is_const_or_static = matches!( is_const_or_static = matches!(
parent_node, tcx.parent_hir_node(hir_ty.hir_id),
Node::Item(&hir::Item { Node::Item(&hir::Item {
kind: hir::ItemKind::Const(..) | hir::ItemKind::Static(..), kind: hir::ItemKind::Const(..) | hir::ItemKind::Static(..),
.. ..
@ -1085,7 +1082,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig<
ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), generics, .. }) => { ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), generics, .. }) => {
// Do not try to infer the return type for a impl method coming from a trait // Do not try to infer the return type for a impl method coming from a trait
if let Item(hir::Item { kind: ItemKind::Impl(i), .. }) = tcx.hir().get_parent(hir_id) if let Item(hir::Item { kind: ItemKind::Impl(i), .. }) = tcx.parent_hir_node(hir_id)
&& i.of_trait.is_some() && i.of_trait.is_some()
{ {
icx.astconv().ty_of_fn( icx.astconv().ty_of_fn(

View file

@ -51,7 +51,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
// of a const parameter type, e.g. `struct Foo<const N: usize, const M: [u8; N]>` is not allowed. // of a const parameter type, e.g. `struct Foo<const N: usize, const M: [u8; N]>` is not allowed.
None None
} else if tcx.features().generic_const_exprs { } else if tcx.features().generic_const_exprs {
let parent_node = tcx.hir().get_parent(hir_id); let parent_node = tcx.parent_hir_node(hir_id);
if let Node::Variant(Variant { disr_expr: Some(constant), .. }) = parent_node if let Node::Variant(Variant { disr_expr: Some(constant), .. }) = parent_node
&& constant.hir_id == hir_id && constant.hir_id == hir_id
{ {
@ -113,7 +113,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
Some(parent_def_id.to_def_id()) Some(parent_def_id.to_def_id())
} }
} else { } else {
let parent_node = tcx.hir().get_parent(hir_id); let parent_node = tcx.parent_hir_node(hir_id);
match parent_node { match parent_node {
// HACK(eddyb) this provides the correct generics for repeat // HACK(eddyb) this provides the correct generics for repeat
// expressions' count (i.e. `N` in `[x; N]`), and explicit // expressions' count (i.e. `N` in `[x; N]`), and explicit

View file

@ -315,8 +315,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
// We create bi-directional Outlives predicates between the original // We create bi-directional Outlives predicates between the original
// and the duplicated parameter, to ensure that they do not get out of sync. // and the duplicated parameter, to ensure that they do not get out of sync.
if let Node::Item(&Item { kind: ItemKind::OpaqueTy(..), .. }) = node { if let Node::Item(&Item { kind: ItemKind::OpaqueTy(..), .. }) = node {
let opaque_ty_id = tcx.hir().parent_id(hir_id); let opaque_ty_node = tcx.parent_hir_node(hir_id);
let opaque_ty_node = tcx.hir_node(opaque_ty_id);
let Node::Ty(&Ty { kind: TyKind::OpaqueDef(_, lifetimes, _), .. }) = opaque_ty_node else { let Node::Ty(&Ty { kind: TyKind::OpaqueDef(_, lifetimes, _), .. }) = opaque_ty_node else {
bug!("unexpected {opaque_ty_node:?}") bug!("unexpected {opaque_ty_node:?}")
}; };

View file

@ -732,7 +732,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
let Some(def_id) = def_id.as_local() else { continue }; let Some(def_id) = def_id.as_local() else { continue };
let hir_id = self.tcx.local_def_id_to_hir_id(def_id); let hir_id = self.tcx.local_def_id_to_hir_id(def_id);
// Ensure that the parent of the def is an item, not HRTB // Ensure that the parent of the def is an item, not HRTB
let parent_id = self.tcx.hir().parent_id(hir_id); let parent_id = self.tcx.parent_hir_id(hir_id);
if !parent_id.is_owner() { if !parent_id.is_owner() {
struct_span_code_err!( struct_span_code_err!(
self.tcx.dcx(), self.tcx.dcx(),

View file

@ -30,7 +30,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
); );
}; };
let parent_node_id = tcx.hir().parent_id(hir_id); let parent_node_id = tcx.parent_hir_id(hir_id);
let parent_node = tcx.hir_node(parent_node_id); let parent_node = tcx.hir_node(parent_node_id);
let (generics, arg_idx) = match parent_node { let (generics, arg_idx) = match parent_node {
@ -79,7 +79,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
} }
Node::TypeBinding(binding @ &TypeBinding { hir_id: binding_id, .. }) Node::TypeBinding(binding @ &TypeBinding { hir_id: binding_id, .. })
if let Node::TraitRef(trait_ref) = tcx.hir_node(tcx.hir().parent_id(binding_id)) => if let Node::TraitRef(trait_ref) = tcx.parent_hir_node(binding_id) =>
{ {
let Some(trait_def_id) = trait_ref.trait_def_id() else { let Some(trait_def_id) = trait_ref.trait_def_id() else {
return Ty::new_error_with_message( return Ty::new_error_with_message(

View file

@ -135,7 +135,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
// Here we check if the reference to the generic type // Here we check if the reference to the generic type
// is from the 'of_trait' field of the enclosing impl // is from the 'of_trait' field of the enclosing impl
let parent = self.tcx.hir().get_parent(self.path_segment.hir_id); let parent = self.tcx.parent_hir_node(self.path_segment.hir_id);
let parent_item = self.tcx.hir_node_by_def_id( let parent_item = self.tcx.hir_node_by_def_id(
self.tcx.hir().get_parent_item(self.path_segment.hir_id).def_id, self.tcx.hir().get_parent_item(self.path_segment.hir_id).def_id,
); );
@ -770,9 +770,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
num = num_trait_generics_except_self, num = num_trait_generics_except_self,
); );
if let Some(parent_node) = self.tcx.hir().opt_parent_id(self.path_segment.hir_id) if let hir::Node::Expr(expr) = self.tcx.parent_hir_node(self.path_segment.hir_id) {
&& let hir::Node::Expr(expr) = self.tcx.hir_node(parent_node)
{
match &expr.kind { match &expr.kind {
hir::ExprKind::Path(qpath) => self hir::ExprKind::Path(qpath) => self
.suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path( .suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path(

View file

@ -287,7 +287,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{ {
// If this `if` expr is the parent's function return expr, // If this `if` expr is the parent's function return expr,
// the cause of the type coercion is the return type, point at it. (#25228) // the cause of the type coercion is the return type, point at it. (#25228)
let hir_id = self.tcx.hir().parent_id(self.tcx.hir().parent_id(then_expr.hir_id)); let hir_id = self.tcx.parent_hir_id(self.tcx.parent_hir_id(then_expr.hir_id));
let ret_reason = self.maybe_get_coercion_reason(hir_id, if_span); let ret_reason = self.maybe_get_coercion_reason(hir_id, if_span);
let cause = self.cause(if_span, ObligationCauseCode::IfExpressionWithNoElse); let cause = self.cause(if_span, ObligationCauseCode::IfExpressionWithNoElse);
let mut error = false; let mut error = false;
@ -396,7 +396,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let node = self.tcx.hir_node(hir_id); let node = self.tcx.hir_node(hir_id);
if let hir::Node::Block(block) = node { if let hir::Node::Block(block) = node {
// check that the body's parent is an fn // check that the body's parent is an fn
let parent = self.tcx.hir().get_parent(self.tcx.hir().parent_id(block.hir_id)); let parent = self.tcx.parent_hir_node(self.tcx.parent_hir_id(block.hir_id));
if let (Some(expr), hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. })) = if let (Some(expr), hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. })) =
(&block.expr, parent) (&block.expr, parent)
{ {

View file

@ -361,7 +361,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let fn_decl_span = if let hir::Node::Expr(hir::Expr { let fn_decl_span = if let hir::Node::Expr(hir::Expr {
kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }), kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }),
.. ..
}) = hir.get_parent(hir_id) }) = self.tcx.parent_hir_node(hir_id)
{ {
fn_decl_span fn_decl_span
} else if let Some(( } else if let Some((
@ -383,11 +383,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{ {
// Actually need to unwrap one more layer of HIR to get to // Actually need to unwrap one more layer of HIR to get to
// the _real_ closure... // the _real_ closure...
let async_closure = hir.parent_id(parent_hir_id);
if let hir::Node::Expr(hir::Expr { if let hir::Node::Expr(hir::Expr {
kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }), kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }),
.. ..
}) = self.tcx.hir_node(async_closure) }) = self.tcx.parent_hir_node(parent_hir_id)
{ {
fn_decl_span fn_decl_span
} else { } else {
@ -415,8 +414,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
call_expr: &'tcx hir::Expr<'tcx>, call_expr: &'tcx hir::Expr<'tcx>,
callee_expr: &'tcx hir::Expr<'tcx>, callee_expr: &'tcx hir::Expr<'tcx>,
) -> bool { ) -> bool {
let hir_id = self.tcx.hir().parent_id(call_expr.hir_id); let parent_node = self.tcx.parent_hir_node(call_expr.hir_id);
let parent_node = self.tcx.hir_node(hir_id);
if let ( if let (
hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Array(_), .. }), hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Array(_), .. }),
hir::ExprKind::Tup(exp), hir::ExprKind::Tup(exp),

View file

@ -1594,7 +1594,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
err.span_label(cause.span, "return type is not `()`"); err.span_label(cause.span, "return type is not `()`");
} }
ObligationCauseCode::BlockTailExpression(blk_id, ..) => { ObligationCauseCode::BlockTailExpression(blk_id, ..) => {
let parent_id = fcx.tcx.hir().parent_id(blk_id); let parent_id = fcx.tcx.parent_hir_id(blk_id);
err = self.report_return_mismatched_types( err = self.report_return_mismatched_types(
cause, cause,
expected, expected,
@ -1785,7 +1785,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
) -> DiagnosticBuilder<'a> { ) -> DiagnosticBuilder<'a> {
let mut err = fcx.err_ctxt().report_mismatched_types(cause, expected, found, ty_err); let mut err = fcx.err_ctxt().report_mismatched_types(cause, expected, found, ty_err);
let parent_id = fcx.tcx.hir().parent_id(id); let parent_id = fcx.tcx.parent_hir_id(id);
let parent = fcx.tcx.hir_node(parent_id); let parent = fcx.tcx.hir_node(parent_id);
if let Some(expr) = expression if let Some(expr) = expression
&& let hir::Node::Expr(hir::Expr { && let hir::Node::Expr(hir::Expr {

View file

@ -298,7 +298,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let hir::Node::Pat(pat) = self.tcx.hir_node(local_hir_id) else { let hir::Node::Pat(pat) = self.tcx.hir_node(local_hir_id) else {
return false; return false;
}; };
let (init_ty_hir_id, init) = match hir.get_parent(pat.hir_id) { let (init_ty_hir_id, init) = match self.tcx.parent_hir_node(pat.hir_id) {
hir::Node::Local(hir::Local { ty: Some(ty), init, .. }) => (ty.hir_id, *init), hir::Node::Local(hir::Local { ty: Some(ty), init, .. }) => (ty.hir_id, *init),
hir::Node::Local(hir::Local { init: Some(init), .. }) => (init.hir_id, Some(*init)), hir::Node::Local(hir::Local { init: Some(init), .. }) => (init.hir_id, Some(*init)),
_ => return false, _ => return false,
@ -445,7 +445,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
continue; continue;
} }
if let hir::Node::Expr(parent_expr) = hir.get_parent(binding.hir_id) if let hir::Node::Expr(parent_expr) = self.tcx.parent_hir_node(binding.hir_id)
&& let hir::ExprKind::MethodCall(segment, rcvr, args, _) = parent_expr.kind && let hir::ExprKind::MethodCall(segment, rcvr, args, _) = parent_expr.kind
&& rcvr.hir_id == binding.hir_id && rcvr.hir_id == binding.hir_id
{ {
@ -557,7 +557,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let Some(TypeError::Sorts(ExpectedFound { expected, .. })) = error else { let Some(TypeError::Sorts(ExpectedFound { expected, .. })) = error else {
return; return;
}; };
let mut parent_id = self.tcx.hir().parent_id(expr.hir_id); let mut parent_id = self.tcx.parent_hir_id(expr.hir_id);
let mut parent; let mut parent;
'outer: loop { 'outer: loop {
// Climb the HIR tree to see if the current `Expr` is part of a `break;` statement. // Climb the HIR tree to see if the current `Expr` is part of a `break;` statement.
@ -568,7 +568,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
break; break;
}; };
parent = p; parent = p;
parent_id = self.tcx.hir().parent_id(parent_id); parent_id = self.tcx.parent_hir_id(parent_id);
let hir::ExprKind::Break(destination, _) = parent.kind else { let hir::ExprKind::Break(destination, _) = parent.kind else {
continue; continue;
}; };
@ -578,7 +578,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Climb the HIR tree to find the (desugared) `loop` this `break` corresponds to. // Climb the HIR tree to find the (desugared) `loop` this `break` corresponds to.
let parent = match self.tcx.hir_node(parent_id) { let parent = match self.tcx.hir_node(parent_id) {
hir::Node::Expr(&ref parent) => { hir::Node::Expr(&ref parent) => {
parent_id = self.tcx.hir().parent_id(parent.hir_id); parent_id = self.tcx.parent_hir_id(parent.hir_id);
parent parent
} }
hir::Node::Stmt(hir::Stmt { hir::Node::Stmt(hir::Stmt {
@ -586,11 +586,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
kind: hir::StmtKind::Semi(&ref parent) | hir::StmtKind::Expr(&ref parent), kind: hir::StmtKind::Semi(&ref parent) | hir::StmtKind::Expr(&ref parent),
.. ..
}) => { }) => {
parent_id = self.tcx.hir().parent_id(*hir_id); parent_id = self.tcx.parent_hir_id(*hir_id);
parent parent
} }
hir::Node::Block(_) => { hir::Node::Block(_) => {
parent_id = self.tcx.hir().parent_id(parent_id); parent_id = self.tcx.parent_hir_id(parent_id);
parent parent
} }
_ => break, _ => break,
@ -677,8 +677,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr: &hir::Expr<'_>, expr: &hir::Expr<'_>,
error: Option<TypeError<'tcx>>, error: Option<TypeError<'tcx>>,
) { ) {
let parent = self.tcx.hir().parent_id(expr.hir_id); match (self.tcx.parent_hir_node(expr.hir_id), error) {
match (self.tcx.hir_node(parent), error) {
(hir::Node::Local(hir::Local { ty: Some(ty), init: Some(init), .. }), _) (hir::Node::Local(hir::Local { ty: Some(ty), init: Some(init), .. }), _)
if init.hir_id == expr.hir_id => if init.hir_id == expr.hir_id =>
{ {
@ -724,16 +723,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let hir::Node::Pat(pat) = self.tcx.hir_node(*hir_id) { if let hir::Node::Pat(pat) = self.tcx.hir_node(*hir_id) {
primary_span = pat.span; primary_span = pat.span;
secondary_span = pat.span; secondary_span = pat.span;
match self.tcx.hir().find_parent(pat.hir_id) { match self.tcx.parent_hir_node(pat.hir_id) {
Some(hir::Node::Local(hir::Local { ty: Some(ty), .. })) => { hir::Node::Local(hir::Local { ty: Some(ty), .. }) => {
primary_span = ty.span; primary_span = ty.span;
post_message = " type"; post_message = " type";
} }
Some(hir::Node::Local(hir::Local { init: Some(init), .. })) => { hir::Node::Local(hir::Local { init: Some(init), .. }) => {
primary_span = init.span; primary_span = init.span;
post_message = " value"; post_message = " value";
} }
Some(hir::Node::Param(hir::Param { ty_span, .. })) => { hir::Node::Param(hir::Param { ty_span, .. }) => {
primary_span = *ty_span; primary_span = *ty_span;
post_message = " parameter type"; post_message = " parameter type";
} }
@ -787,12 +786,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr: &hir::Expr<'_>, expr: &hir::Expr<'_>,
error: Option<TypeError<'tcx>>, error: Option<TypeError<'tcx>>,
) { ) {
let parent = self.tcx.hir().parent_id(expr.hir_id);
let Some(TypeError::Sorts(ExpectedFound { expected, .. })) = error else { let Some(TypeError::Sorts(ExpectedFound { expected, .. })) = error else {
return; return;
}; };
let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Assign(lhs, rhs, _), .. }) = let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Assign(lhs, rhs, _), .. }) =
self.tcx.hir_node(parent) self.tcx.parent_hir_node(expr.hir_id)
else { else {
return; return;
}; };
@ -1017,7 +1015,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
)) = expr.kind )) = expr.kind
{ {
let bind = self.tcx.hir_node(*bind_hir_id); let bind = self.tcx.hir_node(*bind_hir_id);
let parent = self.tcx.hir_node(self.tcx.hir().parent_id(*bind_hir_id)); let parent = self.tcx.parent_hir_node(*bind_hir_id);
if let hir::Node::Pat(hir::Pat { if let hir::Node::Pat(hir::Pat {
kind: hir::PatKind::Binding(_, _hir_id, _, _), .. kind: hir::PatKind::Binding(_, _hir_id, _, _), ..
}) = bind }) = bind
@ -1088,7 +1086,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr: &hir::Expr<'_>, expr: &hir::Expr<'_>,
checked_ty: Ty<'tcx>, checked_ty: Ty<'tcx>,
) { ) {
let Some(hir::Node::Expr(parent_expr)) = self.tcx.hir().find_parent(expr.hir_id) else { let hir::Node::Expr(parent_expr) = self.tcx.parent_hir_node(expr.hir_id) else {
return; return;
}; };
enum CallableKind { enum CallableKind {

View file

@ -1016,7 +1016,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
original_expr_id: HirId, original_expr_id: HirId,
then: impl FnOnce(&hir::Expr<'_>), then: impl FnOnce(&hir::Expr<'_>),
) { ) {
let mut parent = self.tcx.hir().parent_id(original_expr_id); let mut parent = self.tcx.parent_hir_id(original_expr_id);
loop { loop {
let node = self.tcx.hir_node(parent); let node = self.tcx.hir_node(parent);
match node { match node {
@ -1038,15 +1038,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
), ),
.. ..
}) => { }) => {
// Check if our original expression is a child of the condition of a while loop // Check if our original expression is a child of the condition of a while loop.
let expr_is_ancestor = std::iter::successors(Some(original_expr_id), |id| { // If it is, then we have a situation like `while Some(0) = value.get(0) {`,
self.tcx.hir().opt_parent_id(*id)
})
.take_while(|id| *id != parent)
.any(|id| id == expr.hir_id);
// if it is, then we have a situation like `while Some(0) = value.get(0) {`,
// where `while let` was more likely intended. // where `while let` was more likely intended.
if expr_is_ancestor { if self.tcx.hir().parent_id_iter(original_expr_id).any(|id| id == expr.hir_id) {
then(expr); then(expr);
} }
break; break;
@ -1056,7 +1051,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
| hir::Node::TraitItem(_) | hir::Node::TraitItem(_)
| hir::Node::Crate(_) => break, | hir::Node::Crate(_) => break,
_ => { _ => {
parent = self.tcx.hir().parent_id(parent); parent = self.tcx.parent_hir_id(parent);
} }
} }
} }
@ -1199,9 +1194,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& !matches!(lhs.kind, hir::ExprKind::Lit(_)) && !matches!(lhs.kind, hir::ExprKind::Lit(_))
{ {
// Do not suggest `if let x = y` as `==` is way more likely to be the intention. // Do not suggest `if let x = y` as `==` is way more likely to be the intention.
let hir = self.tcx.hir();
if let hir::Node::Expr(hir::Expr { kind: ExprKind::If { .. }, .. }) = if let hir::Node::Expr(hir::Expr { kind: ExprKind::If { .. }, .. }) =
hir.get_parent(hir.parent_id(expr.hir_id)) self.tcx.parent_hir_node(expr.hir_id)
{ {
err.span_suggestion_verbose( err.span_suggestion_verbose(
expr.span.shrink_to_lo(), expr.span.shrink_to_lo(),
@ -2645,7 +2639,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.span_label(field.span, "method, not a field"); err.span_label(field.span, "method, not a field");
let expr_is_call = let expr_is_call =
if let hir::Node::Expr(hir::Expr { kind: ExprKind::Call(callee, _args), .. }) = if let hir::Node::Expr(hir::Expr { kind: ExprKind::Call(callee, _args), .. }) =
self.tcx.hir().get_parent(expr.hir_id) self.tcx.parent_hir_node(expr.hir_id)
{ {
expr.hir_id == callee.hir_id expr.hir_id == callee.hir_id
} else { } else {

View file

@ -764,7 +764,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let code = match lang_item { let code = match lang_item {
hir::LangItem::IntoFutureIntoFuture => { hir::LangItem::IntoFutureIntoFuture => {
if let hir::Node::Expr(into_future_call) = self.tcx.hir().get_parent(hir_id) if let hir::Node::Expr(into_future_call) = self.tcx.parent_hir_node(hir_id)
&& let hir::ExprKind::Call(_, [arg0]) = &into_future_call.kind && let hir::ExprKind::Call(_, [arg0]) = &into_future_call.kind
{ {
Some(ObligationCauseCode::AwaitableExpr(arg0.hir_id)) Some(ObligationCauseCode::AwaitableExpr(arg0.hir_id))
@ -956,12 +956,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.. ..
}) => Some((hir::HirId::make_owner(owner_id.def_id), &sig.decl, ident, false)), }) => Some((hir::HirId::make_owner(owner_id.def_id), &sig.decl, ident, false)),
Node::Expr(&hir::Expr { hir_id, kind: hir::ExprKind::Closure(..), .. }) Node::Expr(&hir::Expr { hir_id, kind: hir::ExprKind::Closure(..), .. })
if let Some(Node::Item(&hir::Item { if let Node::Item(&hir::Item {
ident, ident,
kind: hir::ItemKind::Fn(ref sig, ..), kind: hir::ItemKind::Fn(ref sig, ..),
owner_id, owner_id,
.. ..
})) = self.tcx.hir().find_parent(hir_id) => }) = self.tcx.parent_hir_node(hir_id) =>
{ {
Some(( Some((
hir::HirId::make_owner(owner_id.def_id), hir::HirId::make_owner(owner_id.def_id),
@ -1574,7 +1574,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub(in super::super) fn expr_in_place(&self, mut expr_id: hir::HirId) -> bool { pub(in super::super) fn expr_in_place(&self, mut expr_id: hir::HirId) -> bool {
let mut contained_in_place = false; let mut contained_in_place = false;
while let hir::Node::Expr(parent_expr) = self.tcx.hir().get_parent(expr_id) { while let hir::Node::Expr(parent_expr) = self.tcx.parent_hir_node(expr_id) {
match &parent_expr.kind { match &parent_expr.kind {
hir::ExprKind::Assign(lhs, ..) | hir::ExprKind::AssignOp(_, lhs, ..) => { hir::ExprKind::Assign(lhs, ..) | hir::ExprKind::AssignOp(_, lhs, ..) => {
if lhs.hir_id == expr_id { if lhs.hir_id == expr_id {

View file

@ -93,7 +93,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.find_ambiguous_parameter_in(def_id, error.root_obligation.predicate); self.find_ambiguous_parameter_in(def_id, error.root_obligation.predicate);
} }
let hir = self.tcx.hir();
let (expr, qpath) = match self.tcx.hir_node(hir_id) { let (expr, qpath) = match self.tcx.hir_node(hir_id) {
hir::Node::Expr(expr) => { hir::Node::Expr(expr) => {
if self.closure_span_overlaps_error(error, expr.span) { if self.closure_span_overlaps_error(error, expr.span) {
@ -122,7 +121,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
hir_id: call_hir_id, hir_id: call_hir_id,
span: call_span, span: call_span,
.. ..
}) = hir.get_parent(hir_id) }) = self.tcx.parent_hir_node(hir_id)
&& callee.hir_id == hir_id && callee.hir_id == hir_id
{ {
if self.closure_span_overlaps_error(error, *call_span) { if self.closure_span_overlaps_error(error, *call_span) {

View file

@ -681,9 +681,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Check if the parent expression is a call to Pin::new. If it // Check if the parent expression is a call to Pin::new. If it
// is and we were expecting a Box, ergo Pin<Box<expected>>, we // is and we were expecting a Box, ergo Pin<Box<expected>>, we
// can suggest Box::pin. // can suggest Box::pin.
let parent = self.tcx.hir().parent_id(expr.hir_id);
let Node::Expr(Expr { kind: ExprKind::Call(fn_name, _), .. }) = let Node::Expr(Expr { kind: ExprKind::Call(fn_name, _), .. }) =
self.tcx.hir_node(parent) self.tcx.parent_hir_node(expr.hir_id)
else { else {
return false; return false;
}; };
@ -1687,7 +1686,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return expr; return expr;
}; };
match self.tcx.hir_node(self.tcx.hir().parent_id(*hir_id)) { match self.tcx.parent_hir_node(*hir_id) {
// foo.clone() // foo.clone()
hir::Node::Local(hir::Local { init: Some(init), .. }) => { hir::Node::Local(hir::Local { init: Some(init), .. }) => {
self.note_type_is_not_clone_inner_expr(init) self.note_type_is_not_clone_inner_expr(init)
@ -1699,7 +1698,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.. ..
}) => { }) => {
let hir::Node::Local(hir::Local { init: Some(init), .. }) = let hir::Node::Local(hir::Local { init: Some(init), .. }) =
self.tcx.hir_node(self.tcx.hir().parent_id(*pat_hir_id)) self.tcx.parent_hir_node(*pat_hir_id)
else { else {
return expr; return expr;
}; };
@ -1733,7 +1732,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
call_expr_path call_expr_path
&& let hir::Node::Pat(hir::Pat { hir_id, .. }) = self.tcx.hir_node(*binding) && let hir::Node::Pat(hir::Pat { hir_id, .. }) = self.tcx.hir_node(*binding)
&& let hir::Node::Local(hir::Local { init: Some(init), .. }) = && let hir::Node::Local(hir::Local { init: Some(init), .. }) =
self.tcx.hir_node(self.tcx.hir().parent_id(*hir_id)) self.tcx.parent_hir_node(*hir_id)
&& let Expr { && let Expr {
kind: hir::ExprKind::Closure(hir::Closure { body: body_id, .. }), kind: hir::ExprKind::Closure(hir::Closure { body: body_id, .. }),
.. ..
@ -1899,8 +1898,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) -> bool { ) -> bool {
let map = self.tcx.hir(); let map = self.tcx.hir();
let returned = matches!( let returned = matches!(
map.find_parent(expr.hir_id), self.tcx.parent_hir_node(expr.hir_id),
Some(hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Ret(_), .. })) hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Ret(_), .. })
) || map.get_return_block(expr.hir_id).is_some(); ) || map.get_return_block(expr.hir_id).is_some();
if returned if returned
&& let ty::Adt(e, args_e) = expected.kind() && let ty::Adt(e, args_e) = expected.kind()
@ -1972,7 +1971,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Unroll desugaring, to make sure this works for `for` loops etc. // Unroll desugaring, to make sure this works for `for` loops etc.
loop { loop {
parent = self.tcx.hir().parent_id(id); parent = self.tcx.parent_hir_id(id);
let parent_span = self.tcx.hir().span(parent); let parent_span = self.tcx.hir().span(parent);
if parent_span.find_ancestor_inside(expr.span).is_some() { if parent_span.find_ancestor_inside(expr.span).is_some() {
// The parent node is part of the same span, so is the result of the // The parent node is part of the same span, so is the result of the
@ -2211,24 +2210,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return None; return None;
}; };
let local_parent = self.tcx.hir().parent_id(local_id); let Node::Param(hir::Param { hir_id: param_hir_id, .. }) =
let Node::Param(hir::Param { hir_id: param_hir_id, .. }) = self.tcx.hir_node(local_parent) self.tcx.parent_hir_node(local_id)
else { else {
return None; return None;
}; };
let param_parent = self.tcx.hir().parent_id(*param_hir_id);
let Node::Expr(hir::Expr { let Node::Expr(hir::Expr {
hir_id: expr_hir_id, hir_id: expr_hir_id,
kind: hir::ExprKind::Closure(hir::Closure { fn_decl: closure_fn_decl, .. }), kind: hir::ExprKind::Closure(hir::Closure { fn_decl: closure_fn_decl, .. }),
.. ..
}) = self.tcx.hir_node(param_parent) }) = self.tcx.parent_hir_node(*param_hir_id)
else { else {
return None; return None;
}; };
let expr_parent = self.tcx.hir().parent_id(*expr_hir_id); let hir = self.tcx.parent_hir_node(*expr_hir_id);
let hir = self.tcx.hir_node(expr_parent);
let closure_params_len = closure_fn_decl.inputs.len(); let closure_params_len = closure_fn_decl.inputs.len();
let ( let (
Node::Expr(hir::Expr { Node::Expr(hir::Expr {
@ -2409,10 +2406,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
None => String::new(), None => String::new(),
}; };
if let Some(hir::Node::Expr(hir::Expr { if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Assign(..), .. }) =
kind: hir::ExprKind::Assign(..), self.tcx.parent_hir_node(expr.hir_id)
..
})) = self.tcx.hir().find_parent(expr.hir_id)
{ {
if mutability.is_mut() { if mutability.is_mut() {
// Suppressing this diagnostic, we'll properly print it in `check_expr_assign` // Suppressing this diagnostic, we'll properly print it in `check_expr_assign`
@ -2443,10 +2438,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}; };
// Suggest dereferencing the lhs for expressions such as `&T <= T` // Suggest dereferencing the lhs for expressions such as `&T <= T`
if let Some(hir::Node::Expr(hir::Expr { if let hir::Node::Expr(hir::Expr {
kind: hir::ExprKind::Binary(_, lhs, ..), kind: hir::ExprKind::Binary(_, lhs, ..),
.. ..
})) = self.tcx.hir().find_parent(expr.hir_id) }) = self.tcx.parent_hir_node(expr.hir_id)
&& let &ty::Ref(..) = self.check_expr(lhs).kind() && let &ty::Ref(..) = self.check_expr(lhs).kind()
{ {
let (sugg, verbose) = make_sugg(lhs, lhs.span, "*"); let (sugg, verbose) = make_sugg(lhs, lhs.span, "*");
@ -2602,7 +2597,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|| (checked_ty.is_box() && steps == 1) || (checked_ty.is_box() && steps == 1)
// We can always deref a binop that takes its arguments by ref. // We can always deref a binop that takes its arguments by ref.
|| matches!( || matches!(
self.tcx.hir().get_parent(expr.hir_id), self.tcx.parent_hir_node(expr.hir_id),
hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Binary(op, ..), .. }) hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Binary(op, ..), .. })
if !op.node.is_by_value() if !op.node.is_by_value()
) )
@ -2664,10 +2659,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Returns whether the given expression is an `else if`. /// Returns whether the given expression is an `else if`.
fn is_else_if_block(&self, expr: &hir::Expr<'_>) -> bool { fn is_else_if_block(&self, expr: &hir::Expr<'_>) -> bool {
if let hir::ExprKind::If(..) = expr.kind { if let hir::ExprKind::If(..) = expr.kind {
let parent_id = self.tcx.hir().parent_id(expr.hir_id);
if let Node::Expr(hir::Expr { if let Node::Expr(hir::Expr {
kind: hir::ExprKind::If(_, _, Some(else_expr)), .. kind: hir::ExprKind::If(_, _, Some(else_expr)), ..
}) = self.tcx.hir_node(parent_id) }) = self.tcx.parent_hir_node(expr.hir_id)
{ {
return else_expr.hir_id == expr.hir_id; return else_expr.hir_id == expr.hir_id;
} }
@ -2704,7 +2698,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut sugg = vec![]; let mut sugg = vec![];
if let Some(hir::Node::ExprField(field)) = self.tcx.hir().find_parent(expr.hir_id) { if let hir::Node::ExprField(field) = self.tcx.parent_hir_node(expr.hir_id) {
// `expr` is a literal field for a struct, only suggest if appropriate // `expr` is a literal field for a struct, only suggest if appropriate
if field.is_shorthand { if field.is_shorthand {
// This is a field literal // This is a field literal
@ -3056,8 +3050,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
else { else {
return; return;
}; };
let parent = self.tcx.hir().parent_id(expr.hir_id); if let hir::Node::ExprField(_) = self.tcx.parent_hir_node(expr.hir_id) {
if let hir::Node::ExprField(_) = self.tcx.hir_node(parent) {
// Ignore `Foo { field: a..Default::default() }` // Ignore `Foo { field: a..Default::default() }`
return; return;
} }
@ -3139,8 +3132,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let hir::Node::Pat(pat) = self.tcx.hir_node(hir_id) else { let hir::Node::Pat(pat) = self.tcx.hir_node(hir_id) else {
return; return;
}; };
let Some(hir::Node::Local(hir::Local { ty: None, init: Some(init), .. })) = let hir::Node::Local(hir::Local { ty: None, init: Some(init), .. }) =
self.tcx.hir().find_parent(pat.hir_id) self.tcx.parent_hir_node(pat.hir_id)
else { else {
return; return;
}; };

View file

@ -220,7 +220,7 @@ fn typeck_with_fallback<'tcx>(
span, span,
})) }))
} else if let Node::AnonConst(_) = node { } else if let Node::AnonConst(_) = node {
match tcx.hir_node(tcx.hir().parent_id(id)) { match tcx.parent_hir_node(id) {
Node::Ty(&hir::Ty { kind: hir::TyKind::Typeof(ref anon_const), .. }) Node::Ty(&hir::Ty { kind: hir::TyKind::Typeof(ref anon_const), .. })
if anon_const.hir_id == id => if anon_const.hir_id == id =>
{ {

View file

@ -128,7 +128,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let sugg_span = if let SelfSource::MethodCall(expr) = source { let sugg_span = if let SelfSource::MethodCall(expr) = source {
// Given `foo.bar(baz)`, `expr` is `bar`, but we want to point to the whole thing. // Given `foo.bar(baz)`, `expr` is `bar`, but we want to point to the whole thing.
self.tcx.hir().expect_expr(self.tcx.hir().parent_id(expr.hir_id)).span self.tcx.hir().expect_expr(self.tcx.parent_hir_id(expr.hir_id)).span
} else { } else {
span span
}; };
@ -231,9 +231,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = kind if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = kind
&& let hir::def::Res::Local(hir_id) = path.res && let hir::def::Res::Local(hir_id) = path.res
&& let hir::Node::Pat(b) = self.tcx.hir_node(hir_id) && let hir::Node::Pat(b) = self.tcx.hir_node(hir_id)
&& let Some(hir::Node::Param(p)) = self.tcx.hir().find_parent(b.hir_id) && let hir::Node::Param(p) = self.tcx.parent_hir_node(b.hir_id)
&& let Some(node) = self.tcx.hir().find_parent(p.hir_id) && let Some(decl) = self.tcx.parent_hir_node(p.hir_id).fn_decl()
&& let Some(decl) = node.fn_decl()
&& let Some(ty) = decl.inputs.iter().find(|ty| ty.span == p.ty_span) && let Some(ty) = decl.inputs.iter().find(|ty| ty.span == p.ty_span)
&& let hir::TyKind::Ref(_, mut_ty) = &ty.kind && let hir::TyKind::Ref(_, mut_ty) = &ty.kind
&& let hir::Mutability::Not = mut_ty.mutbl && let hir::Mutability::Not = mut_ty.mutbl
@ -471,7 +470,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let SelfSource::MethodCall(rcvr_expr) = source { if let SelfSource::MethodCall(rcvr_expr) = source {
self.suggest_fn_call(&mut err, rcvr_expr, rcvr_ty, |output_ty| { self.suggest_fn_call(&mut err, rcvr_expr, rcvr_ty, |output_ty| {
let call_expr = let call_expr =
self.tcx.hir().expect_expr(self.tcx.hir().parent_id(rcvr_expr.hir_id)); self.tcx.hir().expect_expr(self.tcx.parent_hir_id(rcvr_expr.hir_id));
let probe = self.lookup_probe_for_diagnostic( let probe = self.lookup_probe_for_diagnostic(
item_name, item_name,
output_ty, output_ty,
@ -1020,7 +1019,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
rcvr_ty, rcvr_ty,
&item_segment, &item_segment,
span, span,
tcx.hir().get_parent(rcvr_expr.hir_id).expect_expr(), tcx.parent_hir_node(rcvr_expr.hir_id).expect_expr(),
rcvr_expr, rcvr_expr,
) { ) {
err.span_note( err.span_note(
@ -1254,7 +1253,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let msg = "remove this method call"; let msg = "remove this method call";
let mut fallback_span = true; let mut fallback_span = true;
if let SelfSource::MethodCall(expr) = source { if let SelfSource::MethodCall(expr) = source {
let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().parent_id(expr.hir_id)); let call_expr = self.tcx.hir().expect_expr(self.tcx.parent_hir_id(expr.hir_id));
if let Some(span) = call_expr.span.trim_start(expr.span) { if let Some(span) = call_expr.span.trim_start(expr.span) {
err.span_suggestion(span, msg, "", Applicability::MachineApplicable); err.span_suggestion(span, msg, "", Applicability::MachineApplicable);
fallback_span = false; fallback_span = false;
@ -1753,7 +1752,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
} else { } else {
let call_expr = tcx.hir().expect_expr(tcx.hir().parent_id(expr.hir_id)); let call_expr = tcx.hir().expect_expr(tcx.parent_hir_id(expr.hir_id));
if let Some(span) = call_expr.span.trim_start(item_name.span) { if let Some(span) = call_expr.span.trim_start(item_name.span) {
err.span_suggestion( err.span_suggestion(
@ -1937,7 +1936,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let span = tcx.hir().span(hir_id); let span = tcx.hir().span(hir_id);
let filename = tcx.sess.source_map().span_to_filename(span); let filename = tcx.sess.source_map().span_to_filename(span);
let parent_node = self.tcx.hir().get_parent(hir_id); let parent_node = self.tcx.parent_hir_node(hir_id);
let msg = format!( let msg = format!(
"you must specify a type for this binding, like `{concrete_type}`", "you must specify a type for this binding, like `{concrete_type}`",
); );
@ -2016,8 +2015,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut visitor = LetVisitor { result: None, ident_name: seg1.ident.name }; let mut visitor = LetVisitor { result: None, ident_name: seg1.ident.name };
visitor.visit_body(body); visitor.visit_body(body);
let parent = self.tcx.hir().parent_id(seg1.hir_id); if let Node::Expr(call_expr) = self.tcx.parent_hir_node(seg1.hir_id)
if let Node::Expr(call_expr) = self.tcx.hir_node(parent)
&& let Some(expr) = visitor.result && let Some(expr) = visitor.result
&& let Some(self_ty) = self.node_ty_opt(expr.hir_id) && let Some(self_ty) = self.node_ty_opt(expr.hir_id)
{ {
@ -2056,7 +2054,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
for (fields, args) in for (fields, args) in
self.get_field_candidates_considering_privacy(span, actual, mod_id, expr.hir_id) self.get_field_candidates_considering_privacy(span, actual, mod_id, expr.hir_id)
{ {
let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().parent_id(expr.hir_id)); let call_expr = self.tcx.hir().expect_expr(self.tcx.parent_hir_id(expr.hir_id));
let lang_items = self.tcx.lang_items(); let lang_items = self.tcx.lang_items();
let never_mention_traits = [ let never_mention_traits = [
@ -2133,7 +2131,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let SelfSource::MethodCall(expr) = source else { let SelfSource::MethodCall(expr) = source else {
return; return;
}; };
let call_expr = tcx.hir().expect_expr(tcx.hir().parent_id(expr.hir_id)); let call_expr = tcx.hir().expect_expr(tcx.parent_hir_id(expr.hir_id));
let ty::Adt(kind, args) = actual.kind() else { let ty::Adt(kind, args) = actual.kind() else {
return; return;
@ -3250,8 +3248,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return false; return false;
} }
let parent = self.tcx.hir().parent_id(expr.hir_id); if let Node::Expr(call_expr) = self.tcx.parent_hir_node(expr.hir_id)
if let Node::Expr(call_expr) = self.tcx.hir_node(parent)
&& let hir::ExprKind::MethodCall( && let hir::ExprKind::MethodCall(
hir::PathSegment { ident: method_name, .. }, hir::PathSegment { ident: method_name, .. },
self_expr, self_expr,

View file

@ -383,7 +383,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
}; };
if self.check_for_missing_semi(expr, &mut err) if self.check_for_missing_semi(expr, &mut err)
&& let hir::Node::Expr(expr) = self.tcx.hir().get_parent(expr.hir_id) && let hir::Node::Expr(expr) = self.tcx.parent_hir_node(expr.hir_id)
&& let hir::ExprKind::Assign(..) = expr.kind && let hir::ExprKind::Assign(..) = expr.kind
{ {
// We defer to the later error produced by `check_lhs_assignable`. // We defer to the later error produced by `check_lhs_assignable`.

View file

@ -720,8 +720,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let PatKind::Ref(inner, mutbl) = pat.kind if let PatKind::Ref(inner, mutbl) = pat.kind
&& let PatKind::Binding(_, _, binding, ..) = inner.kind && let PatKind::Binding(_, _, binding, ..) = inner.kind
{ {
let binding_parent_id = tcx.hir().parent_id(pat.hir_id); let binding_parent = tcx.parent_hir_node(pat.hir_id);
let binding_parent = tcx.hir_node(binding_parent_id);
debug!(?inner, ?pat, ?binding_parent); debug!(?inner, ?pat, ?binding_parent);
let mutability = match mutbl { let mutability = match mutbl {
@ -989,7 +988,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
res.descr(), res.descr(),
), ),
); );
match self.tcx.hir().get_parent(pat.hir_id) { match self.tcx.parent_hir_node(pat.hir_id) {
hir::Node::PatField(..) => { hir::Node::PatField(..) => {
e.span_suggestion_verbose( e.span_suggestion_verbose(
ident.span.shrink_to_hi(), ident.span.shrink_to_hi(),

View file

@ -862,8 +862,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
) { ) {
err.subdiagnostic(subdiag); err.subdiagnostic(subdiag);
} }
if let Some(hir::Node::Expr(m)) = self.tcx.hir().find_parent(scrut_hir_id) if let hir::Node::Expr(m) = self.tcx.parent_hir_node(scrut_hir_id)
&& let Some(hir::Node::Stmt(stmt)) = self.tcx.hir().find_parent(m.hir_id) && let hir::Node::Stmt(stmt) = self.tcx.parent_hir_node(m.hir_id)
&& let hir::StmtKind::Expr(_) = stmt.kind && let hir::StmtKind::Expr(_) = stmt.kind
{ {
err.span_suggestion_verbose( err.span_suggestion_verbose(

View file

@ -106,7 +106,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
} }
p_def_id.as_local().and_then(|id| { p_def_id.as_local().and_then(|id| {
let local_id = tcx.local_def_id_to_hir_id(id); let local_id = tcx.local_def_id_to_hir_id(id);
let generics = tcx.hir().find_parent(local_id)?.generics()?; let generics = tcx.parent_hir_node(local_id).generics()?;
Some((id, generics)) Some((id, generics))
}) })
}); });

View file

@ -735,30 +735,29 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}; };
local.pat.walk(&mut find_compatible_candidates); local.pat.walk(&mut find_compatible_candidates);
} }
match hir.find_parent(blk.hir_id) { match self.tcx.parent_hir_node(blk.hir_id) {
Some(hir::Node::Expr(hir::Expr { hir_id, .. })) => match hir.find_parent(*hir_id) { hir::Node::Expr(hir::Expr { hir_id, .. }) => match self.tcx.parent_hir_node(*hir_id) {
Some(hir::Node::Arm(hir::Arm { pat, .. })) => { hir::Node::Arm(hir::Arm { pat, .. }) => {
pat.walk(&mut find_compatible_candidates); pat.walk(&mut find_compatible_candidates);
} }
Some(
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body), .. }) hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body), .. })
| hir::Node::ImplItem(hir::ImplItem { | hir::Node::ImplItem(hir::ImplItem {
kind: hir::ImplItemKind::Fn(_, body), .. kind: hir::ImplItemKind::Fn(_, body), ..
}) })
| hir::Node::TraitItem(hir::TraitItem { | hir::Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body)), kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body)),
.. ..
}) })
| hir::Node::Expr(hir::Expr { | hir::Node::Expr(hir::Expr {
kind: hir::ExprKind::Closure(hir::Closure { body, .. }), kind: hir::ExprKind::Closure(hir::Closure { body, .. }),
.. ..
}), }) => {
) => {
for param in hir.body(*body).params { for param in hir.body(*body).params {
param.pat.walk(&mut find_compatible_candidates); param.pat.walk(&mut find_compatible_candidates);
} }
} }
Some(hir::Node::Expr(hir::Expr { hir::Node::Expr(hir::Expr {
kind: kind:
hir::ExprKind::If( hir::ExprKind::If(
hir::Expr { kind: hir::ExprKind::Let(let_), .. }, hir::Expr { kind: hir::ExprKind::Let(let_), .. },
@ -766,7 +765,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
_, _,
), ),
.. ..
})) if then_block.hir_id == *hir_id => { }) if then_block.hir_id == *hir_id => {
let_.pat.walk(&mut find_compatible_candidates); let_.pat.walk(&mut find_compatible_candidates);
} }
_ => {} _ => {}

View file

@ -65,10 +65,10 @@ pub fn report_object_safety_error<'tcx>(
&& let hir::TyKind::TraitObject([trait_ref, ..], ..) = ty.kind && let hir::TyKind::TraitObject([trait_ref, ..], ..) = ty.kind
{ {
let mut hir_id = hir_id; let mut hir_id = hir_id;
while let hir::Node::Ty(ty) = tcx.hir().get_parent(hir_id) { while let hir::Node::Ty(ty) = tcx.parent_hir_node(hir_id) {
hir_id = ty.hir_id; hir_id = ty.hir_id;
} }
if tcx.hir().get_parent(hir_id).fn_sig().is_some() { if tcx.parent_hir_node(hir_id).fn_sig().is_some() {
// Do not suggest `impl Trait` when dealing with things like super-traits. // Do not suggest `impl Trait` when dealing with things like super-traits.
err.span_suggestion_verbose( err.span_suggestion_verbose(
ty.span.until(trait_ref.span), ty.span.until(trait_ref.span),

View file

@ -1416,8 +1416,7 @@ impl<'tcx> LateLintPass<'tcx> for UnreachablePub {
} }
fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) { fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) {
let map = cx.tcx.hir(); if matches!(cx.tcx.parent_hir_node(field.hir_id), Node::Variant(_)) {
if matches!(map.get_parent(field.hir_id), Node::Variant(_)) {
return; return;
} }
self.perform_lint(cx, "field", field.def_id, field.vis_span, false); self.perform_lint(cx, "field", field.def_id, field.vis_span, false);

View file

@ -933,7 +933,7 @@ impl<'tcx> LateContext<'tcx> {
while let hir::ExprKind::Path(ref qpath) = expr.kind while let hir::ExprKind::Path(ref qpath) = expr.kind
&& let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) { && let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) {
Res::Local(hir_id) => self.tcx.hir().find_parent(hir_id), Res::Local(hir_id) => Some(self.tcx.parent_hir_node(hir_id)),
_ => None, _ => None,
} }
&& let Some(init) = match parent_node { && let Some(init) = match parent_node {
@ -977,7 +977,7 @@ impl<'tcx> LateContext<'tcx> {
while let hir::ExprKind::Path(ref qpath) = expr.kind while let hir::ExprKind::Path(ref qpath) = expr.kind
&& let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) { && let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) {
Res::Local(hir_id) => self.tcx.hir().find_parent(hir_id), Res::Local(hir_id) => Some(self.tcx.parent_hir_node(hir_id)),
Res::Def(_, def_id) => self.tcx.hir().get_if_local(def_id), Res::Def(_, def_id) => self.tcx.hir().get_if_local(def_id),
_ => None, _ => None,
} }

View file

@ -214,8 +214,7 @@ fn is_single_call_in_arm<'tcx>(
drop_expr: &'tcx Expr<'_>, drop_expr: &'tcx Expr<'_>,
) -> bool { ) -> bool {
if arg.can_have_side_effects() { if arg.can_have_side_effects() {
let parent_node = cx.tcx.hir().find_parent(drop_expr.hir_id); if let Node::Arm(Arm { body, .. }) = cx.tcx.parent_hir_node(drop_expr.hir_id) {
if let Some(Node::Arm(Arm { body, .. })) = &parent_node {
return body.hir_id == drop_expr.hir_id; return body.hir_id == drop_expr.hir_id;
} }
} }

View file

@ -144,15 +144,14 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
match &ty.kind { match &ty.kind {
TyKind::Path(QPath::Resolved(_, path)) => { TyKind::Path(QPath::Resolved(_, path)) => {
if lint_ty_kind_usage(cx, &path.res) { if lint_ty_kind_usage(cx, &path.res) {
let hir = cx.tcx.hir(); let span = match cx.tcx.parent_hir_node(ty.hir_id) {
let span = match hir.find_parent(ty.hir_id) { Node::Pat(Pat {
Some(Node::Pat(Pat {
kind: kind:
PatKind::Path(qpath) PatKind::Path(qpath)
| PatKind::TupleStruct(qpath, ..) | PatKind::TupleStruct(qpath, ..)
| PatKind::Struct(qpath, ..), | PatKind::Struct(qpath, ..),
.. ..
})) => { }) => {
if let QPath::TypeRelative(qpath_ty, ..) = qpath if let QPath::TypeRelative(qpath_ty, ..) = qpath
&& qpath_ty.hir_id == ty.hir_id && qpath_ty.hir_id == ty.hir_id
{ {
@ -161,7 +160,7 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
None None
} }
} }
Some(Node::Expr(Expr { kind: ExprKind::Path(qpath), .. })) => { Node::Expr(Expr { kind: ExprKind::Path(qpath), .. }) => {
if let QPath::TypeRelative(qpath_ty, ..) = qpath if let QPath::TypeRelative(qpath_ty, ..) = qpath
&& qpath_ty.hir_id == ty.hir_id && qpath_ty.hir_id == ty.hir_id
{ {
@ -172,7 +171,7 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
} }
// Can't unify these two branches because qpath below is `&&` and above is `&` // Can't unify these two branches because qpath below is `&&` and above is `&`
// and `A | B` paths don't play well together with adjustments, apparently. // and `A | B` paths don't play well together with adjustments, apparently.
Some(Node::Expr(Expr { kind: ExprKind::Struct(qpath, ..), .. })) => { Node::Expr(Expr { kind: ExprKind::Struct(qpath, ..), .. }) => {
if let QPath::TypeRelative(qpath_ty, ..) = qpath if let QPath::TypeRelative(qpath_ty, ..) = qpath
&& qpath_ty.hir_id == ty.hir_id && qpath_ty.hir_id == ty.hir_id
{ {

View file

@ -427,7 +427,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase {
fn check_pat(&mut self, cx: &LateContext<'_>, p: &hir::Pat<'_>) { fn check_pat(&mut self, cx: &LateContext<'_>, p: &hir::Pat<'_>) {
if let PatKind::Binding(_, hid, ident, _) = p.kind { if let PatKind::Binding(_, hid, ident, _) = p.kind {
if let hir::Node::PatField(field) = cx.tcx.hir().get_parent(hid) { if let hir::Node::PatField(field) = cx.tcx.parent_hir_node(hid) {
if !field.is_shorthand { if !field.is_shorthand {
// Only check if a new name has been introduced, to avoid warning // Only check if a new name has been introduced, to avoid warning
// on both the struct definition and this pattern. // on both the struct definition and this pattern.

View file

@ -200,8 +200,7 @@ fn lint_overflowing_range_endpoint<'tcx>(
ty: &str, ty: &str,
) -> bool { ) -> bool {
// Look past casts to support cases like `0..256 as u8` // Look past casts to support cases like `0..256 as u8`
let (expr, lit_span) = if let Node::Expr(par_expr) = let (expr, lit_span) = if let Node::Expr(par_expr) = cx.tcx.parent_hir_node(expr.hir_id)
cx.tcx.hir_node(cx.tcx.hir().parent_id(expr.hir_id))
&& let ExprKind::Cast(_, _) = par_expr.kind && let ExprKind::Cast(_, _) = par_expr.kind
{ {
(par_expr, expr.span) (par_expr, expr.span)
@ -211,9 +210,8 @@ fn lint_overflowing_range_endpoint<'tcx>(
// We only want to handle exclusive (`..`) ranges, // We only want to handle exclusive (`..`) ranges,
// which are represented as `ExprKind::Struct`. // which are represented as `ExprKind::Struct`.
let par_id = cx.tcx.hir().parent_id(expr.hir_id); let Node::ExprField(field) = cx.tcx.parent_hir_node(expr.hir_id) else { return false };
let Node::ExprField(field) = cx.tcx.hir_node(par_id) else { return false }; let Node::Expr(struct_expr) = cx.tcx.parent_hir_node(field.hir_id) else { return false };
let Node::Expr(struct_expr) = cx.tcx.hir().get_parent(field.hir_id) else { return false };
if !is_range_literal(struct_expr) { if !is_range_literal(struct_expr) {
return false; return false;
}; };
@ -496,8 +494,7 @@ fn lint_uint_literal<'tcx>(
_ => bug!(), _ => bug!(),
}; };
if lit_val < min || lit_val > max { if lit_val < min || lit_val > max {
let parent_id = cx.tcx.hir().parent_id(e.hir_id); if let Node::Expr(par_e) = cx.tcx.parent_hir_node(e.hir_id) {
if let Node::Expr(par_e) = cx.tcx.hir_node(parent_id) {
match par_e.kind { match par_e.kind {
hir::ExprKind::Cast(..) => { hir::ExprKind::Cast(..) => {
if let ty::Char = cx.typeck_results().expr_ty(par_e).kind() { if let ty::Char = cx.typeck_results().expr_ty(par_e).kind() {

View file

@ -250,6 +250,7 @@ provide! { tcx, def_id, other, cdata,
asyncness => { table_direct } asyncness => { table_direct }
fn_arg_names => { table } fn_arg_names => { table }
coroutine_kind => { table_direct } coroutine_kind => { table_direct }
coroutine_for_closure => { table }
trait_def => { table } trait_def => { table }
deduced_param_attrs => { table } deduced_param_attrs => { table }
is_type_alias_impl_trait => { is_type_alias_impl_trait => {

View file

@ -1447,6 +1447,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
{ {
self.tables.coroutine_kind.set(def_id.index, Some(coroutine_kind)) self.tables.coroutine_kind.set(def_id.index, Some(coroutine_kind))
} }
if def_kind == DefKind::Closure
&& tcx.type_of(def_id).skip_binder().is_coroutine_closure()
{
self.tables
.coroutine_for_closure
.set_some(def_id.index, self.tcx.coroutine_for_closure(def_id).into());
}
if let DefKind::Enum | DefKind::Struct | DefKind::Union = def_kind { if let DefKind::Enum | DefKind::Struct | DefKind::Union = def_kind {
self.encode_info_for_adt(local_id); self.encode_info_for_adt(local_id);
} }

View file

@ -443,6 +443,7 @@ define_tables! {
asyncness: Table<DefIndex, ty::Asyncness>, asyncness: Table<DefIndex, ty::Asyncness>,
fn_arg_names: Table<DefIndex, LazyArray<Ident>>, fn_arg_names: Table<DefIndex, LazyArray<Ident>>,
coroutine_kind: Table<DefIndex, hir::CoroutineKind>, coroutine_kind: Table<DefIndex, hir::CoroutineKind>,
coroutine_for_closure: Table<DefIndex, RawDefId>,
trait_def: Table<DefIndex, LazyValue<ty::TraitDef>>, trait_def: Table<DefIndex, LazyValue<ty::TraitDef>>,
trait_item_def_id: Table<DefIndex, RawDefId>, trait_item_def_id: Table<DefIndex, RawDefId>,
expn_that_defined: Table<DefIndex, LazyValue<ExpnId>>, expn_that_defined: Table<DefIndex, LazyValue<ExpnId>>,

View file

@ -82,7 +82,7 @@ impl<'hir> Iterator for ParentHirIterator<'hir> {
} }
// There are nodes that do not have entries, so we need to skip them. // There are nodes that do not have entries, so we need to skip them.
let parent_id = self.map.parent_id(self.current_id); let parent_id = self.map.tcx.parent_hir_id(self.current_id);
if parent_id == self.current_id { if parent_id == self.current_id {
self.current_id = CRATE_HIR_ID; self.current_id = CRATE_HIR_ID;
@ -175,6 +175,28 @@ impl<'tcx> TyCtxt<'tcx> {
self.opt_hir_node_by_def_id(id) self.opt_hir_node_by_def_id(id)
.unwrap_or_else(|| bug!("couldn't find HIR node for def id {id:?}")) .unwrap_or_else(|| bug!("couldn't find HIR node for def id {id:?}"))
} }
/// Returns `HirId` of the parent HIR node of node with this `hir_id`.
/// Returns the same `hir_id` if and only if `hir_id == CRATE_HIR_ID`.
///
/// If calling repeatedly and iterating over parents, prefer [`Map::parent_iter`].
pub fn parent_hir_id(self, hir_id: HirId) -> HirId {
let HirId { owner, local_id } = hir_id;
if local_id == ItemLocalId::from_u32(0) {
self.hir_owner_parent(owner)
} else {
let parent_local_id = self.hir_owner_nodes(owner).nodes[local_id].parent;
// HIR indexing should have checked that.
debug_assert_ne!(parent_local_id, local_id);
HirId { owner, local_id: parent_local_id }
}
}
/// Returns parent HIR node of node with this `hir_id`.
/// Returns HIR node of the same `hir_id` if and only if `hir_id == CRATE_HIR_ID`.
pub fn parent_hir_node(self, hir_id: HirId) -> Node<'tcx> {
self.hir_node(self.parent_hir_id(hir_id))
}
} }
impl<'hir> Map<'hir> { impl<'hir> Map<'hir> {
@ -217,39 +239,6 @@ impl<'hir> Map<'hir> {
self.tcx.definitions_untracked().def_path_hash(def_id) self.tcx.definitions_untracked().def_path_hash(def_id)
} }
/// Finds the id of the parent node to this one.
///
/// If calling repeatedly and iterating over parents, prefer [`Map::parent_iter`].
pub fn opt_parent_id(self, id: HirId) -> Option<HirId> {
if id.local_id == ItemLocalId::from_u32(0) {
// FIXME: This function never returns `None` right now, and the parent chain end is
// determined by checking for `parent(id) == id`. This function should return `None`
// for the crate root instead.
Some(self.tcx.hir_owner_parent(id.owner))
} else {
let owner = self.tcx.hir_owner_nodes(id.owner);
let node = &owner.nodes[id.local_id];
let hir_id = HirId { owner: id.owner, local_id: node.parent };
// HIR indexing should have checked that.
debug_assert_ne!(id.local_id, node.parent);
Some(hir_id)
}
}
#[track_caller]
pub fn parent_id(self, hir_id: HirId) -> HirId {
self.opt_parent_id(hir_id)
.unwrap_or_else(|| bug!("No parent for node {}", self.node_to_string(hir_id)))
}
pub fn get_parent(self, hir_id: HirId) -> Node<'hir> {
self.tcx.hir_node(self.parent_id(hir_id))
}
pub fn find_parent(self, hir_id: HirId) -> Option<Node<'hir>> {
Some(self.tcx.hir_node(self.opt_parent_id(hir_id)?))
}
pub fn get_if_local(self, id: DefId) -> Option<Node<'hir>> { pub fn get_if_local(self, id: DefId) -> Option<Node<'hir>> {
id.as_local() id.as_local()
.and_then(|id| Some(self.tcx.hir_node(self.tcx.opt_local_def_id_to_hir_id(id)?))) .and_then(|id| Some(self.tcx.hir_node(self.tcx.opt_local_def_id_to_hir_id(id)?)))
@ -304,14 +293,13 @@ impl<'hir> Map<'hir> {
/// which this is the body of, i.e., a `fn`, `const` or `static` /// which this is the body of, i.e., a `fn`, `const` or `static`
/// item (possibly associated), a closure, or a `hir::AnonConst`. /// item (possibly associated), a closure, or a `hir::AnonConst`.
pub fn body_owner(self, BodyId { hir_id }: BodyId) -> HirId { pub fn body_owner(self, BodyId { hir_id }: BodyId) -> HirId {
let parent = self.parent_id(hir_id); let parent = self.tcx.parent_hir_id(hir_id);
assert!(is_body_owner(self.tcx.hir_node(parent), hir_id), "{hir_id:?}"); assert!(is_body_owner(self.tcx.hir_node(parent), hir_id), "{hir_id:?}");
parent parent
} }
pub fn body_owner_def_id(self, BodyId { hir_id }: BodyId) -> LocalDefId { pub fn body_owner_def_id(self, BodyId { hir_id }: BodyId) -> LocalDefId {
let parent = self.parent_id(hir_id); associated_body(self.tcx.parent_hir_node(hir_id)).unwrap().0
associated_body(self.tcx.hir_node(parent)).unwrap().0
} }
/// Given a `LocalDefId`, returns the `BodyId` associated with it, /// Given a `LocalDefId`, returns the `BodyId` associated with it,
@ -569,8 +557,8 @@ impl<'hir> Map<'hir> {
/// Checks if the node is left-hand side of an assignment. /// Checks if the node is left-hand side of an assignment.
pub fn is_lhs(self, id: HirId) -> bool { pub fn is_lhs(self, id: HirId) -> bool {
match self.find_parent(id) { match self.tcx.parent_hir_node(id) {
Some(Node::Expr(expr)) => match expr.kind { Node::Expr(expr) => match expr.kind {
ExprKind::Assign(lhs, _rhs, _span) => lhs.hir_id == id, ExprKind::Assign(lhs, _rhs, _span) => lhs.hir_id == id,
_ => false, _ => false,
}, },
@ -793,7 +781,7 @@ impl<'hir> Map<'hir> {
Node::Pat(&Pat { kind: PatKind::Binding(_, _, ident, _), .. }) => Some(ident), Node::Pat(&Pat { kind: PatKind::Binding(_, _, ident, _), .. }) => Some(ident),
// A `Ctor` doesn't have an identifier itself, but its parent // A `Ctor` doesn't have an identifier itself, but its parent
// struct/variant does. Compare with `hir::Map::span`. // struct/variant does. Compare with `hir::Map::span`.
Node::Ctor(..) => match self.find_parent(id)? { Node::Ctor(..) => match self.tcx.parent_hir_node(id) {
Node::Item(item) => Some(item.ident), Node::Item(item) => Some(item.ident),
Node::Variant(variant) => Some(variant.ident), Node::Variant(variant) => Some(variant.ident),
_ => unreachable!(), _ => unreachable!(),
@ -925,7 +913,7 @@ impl<'hir> Map<'hir> {
ForeignItemKind::Fn(decl, _, _) => until_within(item.span, decl.output.span()), ForeignItemKind::Fn(decl, _, _) => until_within(item.span, decl.output.span()),
_ => named_span(item.span, item.ident, None), _ => named_span(item.span, item.ident, None),
}, },
Node::Ctor(_) => return self.span(self.parent_id(hir_id)), Node::Ctor(_) => return self.span(self.tcx.parent_hir_id(hir_id)),
Node::Expr(Expr { Node::Expr(Expr {
kind: ExprKind::Closure(Closure { fn_decl_span, .. }), kind: ExprKind::Closure(Closure { fn_decl_span, .. }),
span, span,
@ -968,7 +956,7 @@ impl<'hir> Map<'hir> {
Node::PatField(field) => field.span, Node::PatField(field) => field.span,
Node::Arm(arm) => arm.span, Node::Arm(arm) => arm.span,
Node::Block(block) => block.span, Node::Block(block) => block.span,
Node::Ctor(..) => self.span_with_body(self.parent_id(hir_id)), Node::Ctor(..) => self.span_with_body(self.tcx.parent_hir_id(hir_id)),
Node::Lifetime(lifetime) => lifetime.ident.span, Node::Lifetime(lifetime) => lifetime.ident.span,
Node::GenericParam(param) => param.span, Node::GenericParam(param) => param.span,
Node::Infer(i) => i.span, Node::Infer(i) => i.span,
@ -1001,7 +989,7 @@ impl<'hir> Map<'hir> {
/// Returns the HirId of `N` in `struct Foo<const N: usize = { ... }>` when /// Returns the HirId of `N` in `struct Foo<const N: usize = { ... }>` when
/// called with the HirId for the `{ ... }` anon const /// called with the HirId for the `{ ... }` anon const
pub fn opt_const_param_default_param_def_id(self, anon_const: HirId) -> Option<LocalDefId> { pub fn opt_const_param_default_param_def_id(self, anon_const: HirId) -> Option<LocalDefId> {
match self.get_parent(anon_const) { match self.tcx.parent_hir_node(anon_const) {
Node::GenericParam(GenericParam { Node::GenericParam(GenericParam {
def_id: param_id, def_id: param_id,
kind: GenericParamKind::Const { .. }, kind: GenericParamKind::Const { .. },
@ -1026,7 +1014,7 @@ impl<'hir> Map<'hir> {
_ => None, _ => None,
}?; }?;
match self.find_parent(expr.hir_id)? { match self.tcx.parent_hir_node(expr.hir_id) {
Node::ExprField(field) => { Node::ExprField(field) => {
if field.ident.name == local.name && field.is_shorthand { if field.ident.name == local.name && field.is_shorthand {
return Some(local.name); return Some(local.name);

View file

@ -136,13 +136,14 @@ pub fn provide(providers: &mut Providers) {
}; };
providers.opt_hir_owner_nodes = providers.opt_hir_owner_nodes =
|tcx, id| tcx.hir_crate(()).owners.get(id)?.as_owner().map(|i| &i.nodes); |tcx, id| tcx.hir_crate(()).owners.get(id)?.as_owner().map(|i| &i.nodes);
providers.hir_owner_parent = |tcx, id| { providers.hir_owner_parent = |tcx, owner_id| {
// Accessing the local_parent is ok since its value is hashed as part of `id`'s DefPathHash. tcx.opt_local_parent(owner_id.def_id).map_or(CRATE_HIR_ID, |parent_def_id| {
tcx.opt_local_parent(id.def_id).map_or(CRATE_HIR_ID, |parent| { let parent_owner_id = tcx.local_def_id_to_hir_id(parent_def_id).owner;
let mut parent_hir_id = tcx.local_def_id_to_hir_id(parent); HirId {
parent_hir_id.local_id = owner: parent_owner_id,
tcx.hir_crate(()).owners[parent_hir_id.owner.def_id].unwrap().parenting[&id.def_id]; local_id: tcx.hir_crate(()).owners[parent_owner_id.def_id].unwrap().parenting
parent_hir_id [&owner_id.def_id],
}
}) })
}; };
providers.hir_attrs = |tcx, id| { providers.hir_attrs = |tcx, id| {

View file

@ -792,7 +792,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
return id; return id;
} }
let next = hir.parent_id(id); let next = self.tcx.parent_hir_id(id);
if next == id { if next == id {
bug!("lint traversal reached the root of the crate"); bug!("lint traversal reached the root of the crate");
} }

View file

@ -2069,14 +2069,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
span: Span, span: Span,
target: Target, target: Target,
) -> bool { ) -> bool {
let hir = self.tcx.hir();
if let Target::ForeignFn = target if let Target::ForeignFn = target
&& let Some(parent) = hir.opt_parent_id(hir_id)
&& let hir::Node::Item(Item { && let hir::Node::Item(Item {
kind: ItemKind::ForeignMod { abi: Abi::RustIntrinsic | Abi::PlatformIntrinsic, .. }, kind: ItemKind::ForeignMod { abi: Abi::RustIntrinsic | Abi::PlatformIntrinsic, .. },
.. ..
}) = self.tcx.hir_node(parent) }) = self.tcx.parent_hir_node(hir_id)
{ {
return true; return true;
} }

View file

@ -1032,15 +1032,14 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
} }
}; };
let hir = self.tcx.hir();
let hir_id = self.tcx.local_def_id_to_hir_id(def_id.as_local()?); let hir_id = self.tcx.local_def_id_to_hir_id(def_id.as_local()?);
match hir.find_parent(hir_id) { match self.tcx.parent_hir_node(hir_id) {
Some(hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(local), .. })) => { hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(local), .. }) => {
get_name(err, &local.pat.kind) get_name(err, &local.pat.kind)
} }
// Different to previous arm because one is `&hir::Local` and the other // Different to previous arm because one is `&hir::Local` and the other
// is `P<hir::Local>`. // is `P<hir::Local>`.
Some(hir::Node::Local(local)) => get_name(err, &local.pat.kind), hir::Node::Local(local) => get_name(err, &local.pat.kind),
_ => None, _ => None,
} }
} }
@ -1202,8 +1201,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let hir::Node::Pat(pat) = self.tcx.hir_node(hir_id) else { let hir::Node::Pat(pat) = self.tcx.hir_node(hir_id) else {
return; return;
}; };
let Some(hir::Node::Local(hir::Local { ty: None, init: Some(init), .. })) = let hir::Node::Local(hir::Local { ty: None, init: Some(init), .. }) =
self.tcx.hir().find_parent(pat.hir_id) self.tcx.parent_hir_node(pat.hir_id)
else { else {
return; return;
}; };
@ -1790,7 +1789,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
&& let Res::Local(hir_id) = path.res && let Res::Local(hir_id) = path.res
&& let hir::Node::Pat(binding) = self.tcx.hir_node(hir_id) && let hir::Node::Pat(binding) = self.tcx.hir_node(hir_id)
&& let Some(hir::Node::Local(local)) = self.tcx.hir().find_parent(binding.hir_id) && let hir::Node::Local(local) = self.tcx.parent_hir_node(binding.hir_id)
&& let None = local.ty && let None = local.ty
&& let Some(binding_expr) = local.init && let Some(binding_expr) = local.init
{ {
@ -3188,8 +3187,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
} }
} }
ObligationCauseCode::VariableType(hir_id) => { ObligationCauseCode::VariableType(hir_id) => {
let parent_node = tcx.hir().parent_id(hir_id); match tcx.parent_hir_node(hir_id) {
match tcx.hir_node(parent_node) {
Node::Local(hir::Local { ty: Some(ty), .. }) => { Node::Local(hir::Local { ty: Some(ty), .. }) => {
err.span_suggestion_verbose( err.span_suggestion_verbose(
ty.span.shrink_to_lo(), ty.span.shrink_to_lo(),
@ -3237,8 +3235,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
types always have a known size"; types always have a known size";
if let Some(hir_id) = hir_id if let Some(hir_id) = hir_id
&& let hir::Node::Param(param) = self.tcx.hir_node(hir_id) && let hir::Node::Param(param) = self.tcx.hir_node(hir_id)
&& let Some(item) = self.tcx.hir().find_parent(hir_id) && let Some(decl) = self.tcx.parent_hir_node(hir_id).fn_decl()
&& let Some(decl) = item.fn_decl()
&& let Some(t) = decl.inputs.iter().find(|t| param.ty_span.contains(t.span)) && let Some(t) = decl.inputs.iter().find(|t| param.ty_span.contains(t.span))
{ {
// We use `contains` because the type might be surrounded by parentheses, // We use `contains` because the type might be surrounded by parentheses,
@ -4079,8 +4076,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
&& let hir::Path { res: Res::Local(hir_id), .. } = path && let hir::Path { res: Res::Local(hir_id), .. } = path
&& let hir::Node::Pat(binding) = self.tcx.hir_node(*hir_id) && let hir::Node::Pat(binding) = self.tcx.hir_node(*hir_id)
&& let parent_hir_id = self.tcx.hir().parent_id(binding.hir_id) && let hir::Node::Local(local) = self.tcx.parent_hir_node(binding.hir_id)
&& let hir::Node::Local(local) = self.tcx.hir_node(parent_hir_id)
&& let Some(binding_expr) = local.init && let Some(binding_expr) = local.init
{ {
// If the expression we're calling on is a binding, we want to point at the // If the expression we're calling on is a binding, we want to point at the
@ -4338,8 +4334,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
&& let hir::Path { res: Res::Local(hir_id), .. } = path && let hir::Path { res: Res::Local(hir_id), .. } = path
&& let hir::Node::Pat(binding) = self.tcx.hir_node(*hir_id) && let hir::Node::Pat(binding) = self.tcx.hir_node(*hir_id)
&& let Some(parent) = self.tcx.hir().find_parent(binding.hir_id)
{ {
let parent = self.tcx.parent_hir_node(binding.hir_id);
// We've reached the root of the method call chain... // We've reached the root of the method call chain...
if let hir::Node::Local(local) = parent if let hir::Node::Local(local) = parent
&& let Some(binding_expr) = local.init && let Some(binding_expr) = local.init

View file

@ -1162,8 +1162,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
&& let hir::Path { res: hir::def::Res::Local(hir_id), .. } = path && let hir::Path { res: hir::def::Res::Local(hir_id), .. } = path
&& let hir::Node::Pat(binding) = self.tcx.hir_node(*hir_id) && let hir::Node::Pat(binding) = self.tcx.hir_node(*hir_id)
&& let Some(parent) = self.tcx.hir().find_parent(binding.hir_id)
{ {
let parent = self.tcx.parent_hir_node(binding.hir_id);
// We've reached the root of the method call chain... // We've reached the root of the method call chain...
if let hir::Node::Local(local) = parent if let hir::Node::Local(local) = parent
&& let Some(binding_expr) = local.init && let Some(binding_expr) = local.init

View file

@ -67,6 +67,26 @@ impl<T> ThinBox<T> {
let ptr = WithOpaqueHeader::new(meta, value); let ptr = WithOpaqueHeader::new(meta, value);
ThinBox { ptr, _marker: PhantomData } ThinBox { ptr, _marker: PhantomData }
} }
/// Moves a type to the heap with its [`Metadata`] stored in the heap allocation instead of on
/// the stack. Returns an error if allocation fails, instead of aborting.
///
/// # Examples
///
/// ```
/// #![feature(allocator_api)]
/// #![feature(thin_box)]
/// use std::boxed::ThinBox;
///
/// let five = ThinBox::try_new(5)?;
/// # Ok::<(), std::alloc::AllocError>(())
/// ```
///
/// [`Metadata`]: core::ptr::Pointee::Metadata
pub fn try_new(value: T) -> Result<Self, core::alloc::AllocError> {
let meta = ptr::metadata(&value);
WithOpaqueHeader::try_new(meta, value).map(|ptr| ThinBox { ptr, _marker: PhantomData })
}
} }
#[unstable(feature = "thin_box", issue = "92791")] #[unstable(feature = "thin_box", issue = "92791")]
@ -179,6 +199,10 @@ impl WithOpaqueHeader {
let ptr = WithHeader::new(header, value); let ptr = WithHeader::new(header, value);
Self(ptr.0) Self(ptr.0)
} }
fn try_new<H, T>(header: H, value: T) -> Result<Self, core::alloc::AllocError> {
WithHeader::try_new(header, value).map(|ptr| Self(ptr.0))
}
} }
impl<H> WithHeader<H> { impl<H> WithHeader<H> {
@ -224,6 +248,46 @@ impl<H> WithHeader<H> {
} }
} }
/// Non-panicking version of `new`.
/// Any error is returned as `Err(core::alloc::AllocError)`.
fn try_new<T>(header: H, value: T) -> Result<WithHeader<H>, core::alloc::AllocError> {
let value_layout = Layout::new::<T>();
let Ok((layout, value_offset)) = Self::alloc_layout(value_layout) else {
return Err(core::alloc::AllocError);
};
unsafe {
// Note: It's UB to pass a layout with a zero size to `alloc::alloc`, so
// we use `layout.dangling()` for this case, which should have a valid
// alignment for both `T` and `H`.
let ptr = if layout.size() == 0 {
// Some paranoia checking, mostly so that the ThinBox tests are
// more able to catch issues.
debug_assert!(
value_offset == 0 && mem::size_of::<T>() == 0 && mem::size_of::<H>() == 0
);
layout.dangling()
} else {
let ptr = alloc::alloc(layout);
if ptr.is_null() {
return Err(core::alloc::AllocError);
}
// Safety:
// - The size is at least `aligned_header_size`.
let ptr = ptr.add(value_offset) as *mut _;
NonNull::new_unchecked(ptr)
};
let result = WithHeader(ptr, PhantomData);
ptr::write(result.header(), header);
ptr::write(result.value().cast(), value);
Ok(result)
}
}
// Safety: // Safety:
// - Assumes that either `value` can be dereferenced, or is the // - Assumes that either `value` can be dereferenced, or is the
// `NonNull::dangling()` we use when both `T` and `H` are ZSTs. // `NonNull::dangling()` we use when both `T` and `H` are ZSTs.

View file

@ -237,9 +237,9 @@
use crate::cmp::Ordering; use crate::cmp::Ordering;
use crate::fmt::{self, Debug, Display}; use crate::fmt::{self, Debug, Display};
use crate::intrinsics::is_nonoverlapping; use crate::intrinsics;
use crate::marker::{PhantomData, Unsize}; use crate::marker::{PhantomData, Unsize};
use crate::mem; use crate::mem::{self, size_of};
use crate::ops::{CoerceUnsized, Deref, DerefMut, DispatchFromDyn}; use crate::ops::{CoerceUnsized, Deref, DerefMut, DispatchFromDyn};
use crate::ptr::{self, NonNull}; use crate::ptr::{self, NonNull};
@ -435,11 +435,15 @@ impl<T> Cell<T> {
#[inline] #[inline]
#[stable(feature = "move_cell", since = "1.17.0")] #[stable(feature = "move_cell", since = "1.17.0")]
pub fn swap(&self, other: &Self) { pub fn swap(&self, other: &Self) {
fn is_nonoverlapping<T>(src: *const T, dst: *const T) -> bool {
intrinsics::is_nonoverlapping(src.cast(), dst.cast(), size_of::<T>(), 1)
}
if ptr::eq(self, other) { if ptr::eq(self, other) {
// Swapping wouldn't change anything. // Swapping wouldn't change anything.
return; return;
} }
if !is_nonoverlapping(self, other, 1) { if !is_nonoverlapping(self, other) {
// See <https://github.com/rust-lang/rust/issues/80778> for why we need to stop here. // See <https://github.com/rust-lang/rust/issues/80778> for why we need to stop here.
panic!("`Cell::swap` on overlapping non-identical `Cell`s"); panic!("`Cell::swap` on overlapping non-identical `Cell`s");
} }

View file

@ -56,7 +56,7 @@
use crate::marker::DiscriminantKind; use crate::marker::DiscriminantKind;
use crate::marker::Tuple; use crate::marker::Tuple;
use crate::mem::{self, align_of}; use crate::mem::align_of;
pub mod mir; pub mod mir;
pub mod simd; pub mod simd;
@ -1027,7 +1027,7 @@ extern "rust-intrinsic" {
/// The size of the referenced value in bytes. /// The size of the referenced value in bytes.
/// ///
/// The stabilized version of this intrinsic is [`mem::size_of_val`]. /// The stabilized version of this intrinsic is [`crate::mem::size_of_val`].
#[rustc_const_unstable(feature = "const_size_of_val", issue = "46571")] #[rustc_const_unstable(feature = "const_size_of_val", issue = "46571")]
#[rustc_nounwind] #[rustc_nounwind]
pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
@ -1107,7 +1107,7 @@ extern "rust-intrinsic" {
/// Moves a value out of scope without running drop glue. /// Moves a value out of scope without running drop glue.
/// ///
/// This exists solely for [`mem::forget_unsized`]; normal `forget` uses /// This exists solely for [`crate::mem::forget_unsized`]; normal `forget` uses
/// `ManuallyDrop` instead. /// `ManuallyDrop` instead.
/// ///
/// Note that, unlike most intrinsics, this is safe to call; /// Note that, unlike most intrinsics, this is safe to call;
@ -1233,7 +1233,7 @@ extern "rust-intrinsic" {
/// Depending on what the code is doing, the following alternatives are preferable to /// Depending on what the code is doing, the following alternatives are preferable to
/// pointer-to-integer transmutation: /// pointer-to-integer transmutation:
/// - If the code just wants to store data of arbitrary type in some buffer and needs to pick a /// - If the code just wants to store data of arbitrary type in some buffer and needs to pick a
/// type for that buffer, it can use [`MaybeUninit`][mem::MaybeUninit]. /// type for that buffer, it can use [`MaybeUninit`][crate::mem::MaybeUninit].
/// - If the code actually wants to work on the address the pointer points to, it can use `as` /// - If the code actually wants to work on the address the pointer points to, it can use `as`
/// casts or [`ptr.addr()`][pointer::addr]. /// casts or [`ptr.addr()`][pointer::addr].
/// ///
@ -2317,7 +2317,7 @@ extern "rust-intrinsic" {
/// Therefore, implementations must not require the user to uphold /// Therefore, implementations must not require the user to uphold
/// any safety invariants. /// any safety invariants.
/// ///
/// The to-be-stabilized version of this intrinsic is [`mem::variant_count`]. /// The to-be-stabilized version of this intrinsic is [`crate::mem::variant_count`].
#[rustc_const_unstable(feature = "variant_count", issue = "73662")] #[rustc_const_unstable(feature = "variant_count", issue = "73662")]
#[rustc_safe_intrinsic] #[rustc_safe_intrinsic]
#[rustc_nounwind] #[rustc_nounwind]
@ -2569,6 +2569,19 @@ extern "rust-intrinsic" {
#[rustc_nounwind] #[rustc_nounwind]
pub fn is_val_statically_known<T: Copy>(arg: T) -> bool; pub fn is_val_statically_known<T: Copy>(arg: T) -> bool;
/// Returns the value of `cfg!(debug_assertions)`, but after monomorphization instead of in
/// macro expansion.
///
/// This always returns `false` in const eval and Miri. The interpreter provides better
/// diagnostics than the checks that this is used to implement. However, this means
/// you should only be using this intrinsic to guard requirements that, if violated,
/// immediately lead to UB. Otherwise, const-eval and Miri will miss out on those
/// checks entirely.
///
/// Since this is evaluated after monomorphization, branching on this value can be used to
/// implement debug assertions that are included in the precompiled standard library, but can
/// be optimized out by builds that monomorphize the standard library code with debug
/// assertions disabled. This intrinsic is primarily used by [`assert_unsafe_precondition`].
#[rustc_const_unstable(feature = "delayed_debug_assertions", issue = "none")] #[rustc_const_unstable(feature = "delayed_debug_assertions", issue = "none")]
#[rustc_safe_intrinsic] #[rustc_safe_intrinsic]
#[cfg(not(bootstrap))] #[cfg(not(bootstrap))]
@ -2597,7 +2610,7 @@ pub(crate) const fn debug_assertions() -> bool {
/// These checks are behind a condition which is evaluated at codegen time, not expansion time like /// These checks are behind a condition which is evaluated at codegen time, not expansion time like
/// [`debug_assert`]. This means that a standard library built with optimizations and debug /// [`debug_assert`]. This means that a standard library built with optimizations and debug
/// assertions disabled will have these checks optimized out of its monomorphizations, but if a /// assertions disabled will have these checks optimized out of its monomorphizations, but if a
/// a caller of the standard library has debug assertions enabled and monomorphizes an expansion of /// caller of the standard library has debug assertions enabled and monomorphizes an expansion of
/// this macro, that monomorphization will contain the check. /// this macro, that monomorphization will contain the check.
/// ///
/// Since these checks cannot be optimized out in MIR, some care must be taken in both call and /// Since these checks cannot be optimized out in MIR, some care must be taken in both call and
@ -2606,8 +2619,8 @@ pub(crate) const fn debug_assertions() -> bool {
/// combination of properties ensures that the code for the checks is only compiled once, and has a /// combination of properties ensures that the code for the checks is only compiled once, and has a
/// minimal impact on the caller's code size. /// minimal impact on the caller's code size.
/// ///
/// Caller should also introducing any other `let` bindings or any code outside this macro in order /// Callers should also avoid introducing any other `let` bindings or any code outside this macro in
/// to call it. Since the precompiled standard library is built with full debuginfo and these /// order to call it. Since the precompiled standard library is built with full debuginfo and these
/// variables cannot be optimized out in MIR, an innocent-looking `let` can produce enough /// variables cannot be optimized out in MIR, an innocent-looking `let` can produce enough
/// debuginfo to have a measurable compile-time impact on debug builds. /// debuginfo to have a measurable compile-time impact on debug builds.
/// ///
@ -2659,12 +2672,9 @@ pub(crate) fn is_valid_allocation_size(size: usize, len: usize) -> bool {
len <= max_len len <= max_len
} }
pub(crate) fn is_nonoverlapping_mono( /// Checks whether the regions of memory starting at `src` and `dst` of size
src: *const (), /// `count * size` do *not* overlap.
dst: *const (), pub(crate) fn is_nonoverlapping(src: *const (), dst: *const (), size: usize, count: usize) -> bool {
size: usize,
count: usize,
) -> bool {
let src_usize = src.addr(); let src_usize = src.addr();
let dst_usize = dst.addr(); let dst_usize = dst.addr();
let Some(size) = size.checked_mul(count) else { let Some(size) = size.checked_mul(count) else {
@ -2678,24 +2688,6 @@ pub(crate) fn is_nonoverlapping_mono(
diff >= size diff >= size
} }
/// Checks whether the regions of memory starting at `src` and `dst` of size
/// `count * size_of::<T>()` do *not* overlap.
#[inline]
pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) -> bool {
let src_usize = src.addr();
let dst_usize = dst.addr();
let Some(size) = mem::size_of::<T>().checked_mul(count) else {
// Use panic_nounwind instead of Option::expect, so that this function is nounwind.
crate::panicking::panic_nounwind(
"is_nonoverlapping: `size_of::<T>() * count` overflows a usize",
)
};
let diff = src_usize.abs_diff(dst_usize);
// If the absolute distance between the ptrs is at least as big as the size of the buffer,
// they do not overlap.
diff >= size
}
/// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source /// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
/// and destination must *not* overlap. /// and destination must *not* overlap.
/// ///
@ -2809,7 +2801,7 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us
) => ) =>
is_aligned_and_not_null(src, align) is_aligned_and_not_null(src, align)
&& is_aligned_and_not_null(dst, align) && is_aligned_and_not_null(dst, align)
&& is_nonoverlapping_mono(src, dst, size, count) && is_nonoverlapping(src, dst, size, count)
); );
copy_nonoverlapping(src, dst, count) copy_nonoverlapping(src, dst, count)
} }

View file

@ -1660,6 +1660,11 @@ mod prim_ref {}
/// * [`UnwindSafe`] /// * [`UnwindSafe`]
/// * [`RefUnwindSafe`] /// * [`RefUnwindSafe`]
/// ///
/// Note that while this type implements `PartialEq`, comparing function pointers is unreliable:
/// pointers to the same function can compare inequal (because functions are duplicated in multiple
/// codegen units), and pointers to *different* functions can compare equal (since identical
/// functions can be deduplicated within a codegen unit).
///
/// [`Hash`]: hash::Hash /// [`Hash`]: hash::Hash
/// [`Pointer`]: fmt::Pointer /// [`Pointer`]: fmt::Pointer
/// [`UnwindSafe`]: panic::UnwindSafe /// [`UnwindSafe`]: panic::UnwindSafe

View file

@ -175,6 +175,11 @@ impl<T: ?Sized> Clone for PtrComponents<T> {
/// ///
/// It is possible to name this struct with a type parameter that is not a `dyn` trait object /// It is possible to name this struct with a type parameter that is not a `dyn` trait object
/// (for example `DynMetadata<u64>`) but not to obtain a meaningful value of that struct. /// (for example `DynMetadata<u64>`) but not to obtain a meaningful value of that struct.
///
/// Note that while this type implements `PartialEq`, comparing vtable pointers is unreliable:
/// pointers to vtables of the same type for the same trait can compare inequal (because vtables are
/// duplicated in multiple codegen units), and pointers to vtables of *different* types/traits can
/// compare equal (since identical vtables can be deduplicated within a codegen unit).
#[lang = "dyn_metadata"] #[lang = "dyn_metadata"]
pub struct DynMetadata<Dyn: ?Sized> { pub struct DynMetadata<Dyn: ?Sized> {
vtable_ptr: &'static VTable, vtable_ptr: &'static VTable,

View file

@ -383,7 +383,7 @@ use crate::cmp::Ordering;
use crate::fmt; use crate::fmt;
use crate::hash; use crate::hash;
use crate::intrinsics::{ use crate::intrinsics::{
self, assert_unsafe_precondition, is_aligned_and_not_null, is_nonoverlapping_mono, self, assert_unsafe_precondition, is_aligned_and_not_null, is_nonoverlapping,
}; };
use crate::marker::FnPtr; use crate::marker::FnPtr;
@ -978,7 +978,7 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
) => ) =>
is_aligned_and_not_null(x, align) is_aligned_and_not_null(x, align)
&& is_aligned_and_not_null(y, align) && is_aligned_and_not_null(y, align)
&& is_nonoverlapping_mono(x, y, size, count) && is_nonoverlapping(x, y, size, count)
); );
} }

View file

@ -99,6 +99,12 @@ impl RawWaker {
/// [`RawWaker`] implementation. Calling one of the contained functions using /// [`RawWaker`] implementation. Calling one of the contained functions using
/// any other `data` pointer will cause undefined behavior. /// any other `data` pointer will cause undefined behavior.
/// ///
/// Note that while this type implements `PartialEq`, comparing function pointers, and hence
/// comparing structs like this that contain function pointers, is unreliable: pointers to the same
/// function can compare inequal (because functions are duplicated in multiple codegen units), and
/// pointers to *different* functions can compare equal (since identical functions can be
/// deduplicated within a codegen unit).
///
/// # Thread safety /// # Thread safety
/// If the [`RawWaker`] will be used to construct a [`Waker`] then /// If the [`RawWaker`] will be used to construct a [`Waker`] then
/// these functions must all be thread-safe (even though [`RawWaker`] is /// these functions must all be thread-safe (even though [`RawWaker`] is

View file

@ -0,0 +1,88 @@
#![cfg(not(test))]
// These symbols are all defined by `libm`,
// or by `compiler-builtins` on unsupported platforms.
extern "C" {
pub fn acos(n: f64) -> f64;
pub fn asin(n: f64) -> f64;
pub fn atan(n: f64) -> f64;
pub fn atan2(a: f64, b: f64) -> f64;
pub fn cbrt(n: f64) -> f64;
pub fn cbrtf(n: f32) -> f32;
pub fn cosh(n: f64) -> f64;
pub fn expm1(n: f64) -> f64;
pub fn expm1f(n: f32) -> f32;
pub fn fdim(a: f64, b: f64) -> f64;
pub fn fdimf(a: f32, b: f32) -> f32;
#[cfg_attr(target_env = "msvc", link_name = "_hypot")]
pub fn hypot(x: f64, y: f64) -> f64;
#[cfg_attr(target_env = "msvc", link_name = "_hypotf")]
pub fn hypotf(x: f32, y: f32) -> f32;
pub fn log1p(n: f64) -> f64;
pub fn log1pf(n: f32) -> f32;
pub fn sinh(n: f64) -> f64;
pub fn tan(n: f64) -> f64;
pub fn tanh(n: f64) -> f64;
pub fn tgamma(n: f64) -> f64;
pub fn tgammaf(n: f32) -> f32;
pub fn lgamma_r(n: f64, s: &mut i32) -> f64;
pub fn lgammaf_r(n: f32, s: &mut i32) -> f32;
cfg_if::cfg_if! {
if #[cfg(not(all(target_os = "windows", target_env = "msvc", target_arch = "x86")))] {
pub fn acosf(n: f32) -> f32;
pub fn asinf(n: f32) -> f32;
pub fn atan2f(a: f32, b: f32) -> f32;
pub fn atanf(n: f32) -> f32;
pub fn coshf(n: f32) -> f32;
pub fn sinhf(n: f32) -> f32;
pub fn tanf(n: f32) -> f32;
pub fn tanhf(n: f32) -> f32;
}}
}
// On 32-bit x86 MSVC these functions aren't defined, so we just define shims
// which promote everything to f64, perform the calculation, and then demote
// back to f32. While not precisely correct should be "correct enough" for now.
cfg_if::cfg_if! {
if #[cfg(all(target_os = "windows", target_env = "msvc", target_arch = "x86"))] {
#[inline]
pub unsafe fn acosf(n: f32) -> f32 {
f64::acos(n as f64) as f32
}
#[inline]
pub unsafe fn asinf(n: f32) -> f32 {
f64::asin(n as f64) as f32
}
#[inline]
pub unsafe fn atan2f(n: f32, b: f32) -> f32 {
f64::atan2(n as f64, b as f64) as f32
}
#[inline]
pub unsafe fn atanf(n: f32) -> f32 {
f64::atan(n as f64) as f32
}
#[inline]
pub unsafe fn coshf(n: f32) -> f32 {
f64::cosh(n as f64) as f32
}
#[inline]
pub unsafe fn sinhf(n: f32) -> f32 {
f64::sinh(n as f64) as f32
}
#[inline]
pub unsafe fn tanf(n: f32) -> f32 {
f64::tan(n as f64) as f32
}
#[inline]
pub unsafe fn tanhf(n: f32) -> f32 {
f64::tanh(n as f64) as f32
}
}}

View file

@ -1,35 +0,0 @@
// These symbols are all defined by `libm`,
// or by `compiler-builtins` on unsupported platforms.
extern "C" {
pub fn acos(n: f64) -> f64;
pub fn acosf(n: f32) -> f32;
pub fn asin(n: f64) -> f64;
pub fn asinf(n: f32) -> f32;
pub fn atan(n: f64) -> f64;
pub fn atan2(a: f64, b: f64) -> f64;
pub fn atan2f(a: f32, b: f32) -> f32;
pub fn atanf(n: f32) -> f32;
pub fn cbrt(n: f64) -> f64;
pub fn cbrtf(n: f32) -> f32;
pub fn cosh(n: f64) -> f64;
pub fn coshf(n: f32) -> f32;
pub fn expm1(n: f64) -> f64;
pub fn expm1f(n: f32) -> f32;
pub fn fdim(a: f64, b: f64) -> f64;
pub fn fdimf(a: f32, b: f32) -> f32;
pub fn hypot(x: f64, y: f64) -> f64;
pub fn hypotf(x: f32, y: f32) -> f32;
pub fn log1p(n: f64) -> f64;
pub fn log1pf(n: f32) -> f32;
pub fn sinh(n: f64) -> f64;
pub fn sinhf(n: f32) -> f32;
pub fn tan(n: f64) -> f64;
pub fn tanf(n: f32) -> f32;
pub fn tanh(n: f64) -> f64;
pub fn tanhf(n: f32) -> f32;
pub fn tgamma(n: f64) -> f64;
pub fn tgammaf(n: f32) -> f32;
pub fn lgamma_r(n: f64, s: &mut i32) -> f64;
pub fn lgammaf_r(n: f32, s: &mut i32) -> f32;
}

View file

@ -1,11 +0,0 @@
#![cfg(not(test))]
cfg_if::cfg_if! {
if #[cfg(target_os = "windows")] {
mod windows;
pub use windows::*;
} else {
mod builtins;
pub use builtins::*;
}
}

View file

@ -1,94 +0,0 @@
use core::ffi::{c_double, c_float, c_int};
extern "C" {
pub fn acos(n: c_double) -> c_double;
pub fn asin(n: c_double) -> c_double;
pub fn atan(n: c_double) -> c_double;
pub fn atan2(a: c_double, b: c_double) -> c_double;
pub fn cbrt(n: c_double) -> c_double;
pub fn cbrtf(n: c_float) -> c_float;
pub fn cosh(n: c_double) -> c_double;
pub fn expm1(n: c_double) -> c_double;
pub fn expm1f(n: c_float) -> c_float;
pub fn fdim(a: c_double, b: c_double) -> c_double;
pub fn fdimf(a: c_float, b: c_float) -> c_float;
#[cfg_attr(target_env = "msvc", link_name = "_hypot")]
pub fn hypot(x: c_double, y: c_double) -> c_double;
#[cfg_attr(target_env = "msvc", link_name = "_hypotf")]
pub fn hypotf(x: c_float, y: c_float) -> c_float;
pub fn log1p(n: c_double) -> c_double;
pub fn log1pf(n: c_float) -> c_float;
pub fn sinh(n: c_double) -> c_double;
pub fn tan(n: c_double) -> c_double;
pub fn tanh(n: c_double) -> c_double;
pub fn tgamma(n: c_double) -> c_double;
pub fn tgammaf(n: c_float) -> c_float;
pub fn lgamma_r(n: c_double, s: &mut c_int) -> c_double;
pub fn lgammaf_r(n: c_float, s: &mut c_int) -> c_float;
}
pub use self::shims::*;
#[cfg(not(all(target_env = "msvc", target_arch = "x86")))]
mod shims {
use core::ffi::c_float;
extern "C" {
pub fn acosf(n: c_float) -> c_float;
pub fn asinf(n: c_float) -> c_float;
pub fn atan2f(a: c_float, b: c_float) -> c_float;
pub fn atanf(n: c_float) -> c_float;
pub fn coshf(n: c_float) -> c_float;
pub fn sinhf(n: c_float) -> c_float;
pub fn tanf(n: c_float) -> c_float;
pub fn tanhf(n: c_float) -> c_float;
}
}
// On 32-bit x86 MSVC these functions aren't defined, so we just define shims
// which promote everything to f64, perform the calculation, and then demote
// back to f32. While not precisely correct should be "correct enough" for now.
#[cfg(all(target_env = "msvc", target_arch = "x86"))]
mod shims {
use core::ffi::c_float;
#[inline]
pub unsafe fn acosf(n: c_float) -> c_float {
f64::acos(n as f64) as c_float
}
#[inline]
pub unsafe fn asinf(n: c_float) -> c_float {
f64::asin(n as f64) as c_float
}
#[inline]
pub unsafe fn atan2f(n: c_float, b: c_float) -> c_float {
f64::atan2(n as f64, b as f64) as c_float
}
#[inline]
pub unsafe fn atanf(n: c_float) -> c_float {
f64::atan(n as f64) as c_float
}
#[inline]
pub unsafe fn coshf(n: c_float) -> c_float {
f64::cosh(n as f64) as c_float
}
#[inline]
pub unsafe fn sinhf(n: c_float) -> c_float {
f64::sinh(n as f64) as c_float
}
#[inline]
pub unsafe fn tanf(n: c_float) -> c_float {
f64::tan(n as f64) as c_float
}
#[inline]
pub unsafe fn tanhf(n: c_float) -> c_float {
f64::tanh(n as f64) as c_float
}
}

View file

@ -10,6 +10,9 @@ from nor used with any official Nintendo SDK.
## Target maintainers ## Target maintainers
This target is maintained by members of the [@rust3ds](https://github.com/rust3ds)
organization:
- [@Meziu](https://github.com/Meziu) - [@Meziu](https://github.com/Meziu)
- [@AzureMarker](https://github.com/AzureMarker) - [@AzureMarker](https://github.com/AzureMarker)
- [@ian-h-chamberlain](https://github.com/ian-h-chamberlain) - [@ian-h-chamberlain](https://github.com/ian-h-chamberlain)
@ -35,8 +38,8 @@ Additionally, some helper crates provide implementations of some `libc` function
use by `std` that may otherwise be missing. These, or an alternate implementation use by `std` that may otherwise be missing. These, or an alternate implementation
of the relevant functions, are required to use `std`: of the relevant functions, are required to use `std`:
- [`pthread-3ds`](https://github.com/Meziu/pthread-3ds) provides pthread APIs for `std::thread`. - [`pthread-3ds`](https://github.com/rust3ds/pthread-3ds) provides pthread APIs for `std::thread`.
- [`linker-fix-3ds`](https://github.com/Meziu/rust-linker-fix-3ds) fulfills some other missing libc APIs. - [`shim-3ds`](https://github.com/rust3ds/shim-3ds) fulfills some other missing libc APIs (e.g. `getrandom`).
Binaries built for this target should be compatible with all variants of the Binaries built for this target should be compatible with all variants of the
3DS (and 2DS) hardware and firmware, but testing is limited and some versions may 3DS (and 2DS) hardware and firmware, but testing is limited and some versions may
@ -74,8 +77,10 @@ export CFLAGS_armv6k_nintendo_3ds="-mfloat-abi=hard -mtune=mpcore -mtp=soft -mar
Rust does not yet ship pre-compiled artifacts for this target. Rust does not yet ship pre-compiled artifacts for this target.
The recommended way to build binaries is by using the The recommended way to build binaries is by using the
[cargo-3ds](https://github.com/Meziu/cargo-3ds) tool, which uses `build-std` [cargo-3ds](https://github.com/rust3ds/cargo-3ds) tool, which uses `build-std`
and provides commands that work like the usual `cargo run`, `cargo build`, etc. and provides commands that work like the usual `cargo run`, `cargo build`, etc.
The `cargo 3ds new` will automatically set up a new project with the dependencies
needed to build a simple binary.
You can also build Rust with the target enabled (see You can also build Rust with the target enabled (see
[Building the target](#building-the-target) above). [Building the target](#building-the-target) above).
@ -83,23 +88,16 @@ You can also build Rust with the target enabled (see
As mentioned in [Requirements](#requirements), programs that use `std` must link As mentioned in [Requirements](#requirements), programs that use `std` must link
against both the devkitARM toolchain and libraries providing the `libc` APIs used against both the devkitARM toolchain and libraries providing the `libc` APIs used
in `std`. There is a general-purpose utility crate for working with nonstandard in `std`. There is a general-purpose utility crate for working with nonstandard
APIs provided by the OS: [`ctru-rs`](https://github.com/Meziu/ctru-rs). APIs provided by the OS: [`ctru-rs`](https://github.com/rust3ds/ctru-rs).
Add it to Cargo.toml to use it in your program: Add it to Cargo.toml to use it in your program:
```toml ```toml
[dependencies] [dependencies]
ctru-rs = { git = "https://github.com/Meziu/ctru-rs.git" } ctru-rs = { git = "https://github.com/rust3ds/ctru-rs.git" }
``` ```
Using this library's `init()` function ensures the symbols needed to link Depending on `ctru-rs` ensures that all the necessary symbols are available at
against `std` are present (as mentioned in [Requirements](#requirements) link time.
above), as well as providing a runtime suitable for `std`:
```rust,ignore (requires-3rd-party-library)
fn main() {
ctru::init();
}
```
## Testing ## Testing

View file

@ -46,11 +46,10 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants {
return; return;
}; };
if let ConstantSource::Constant = source if let ConstantSource::Constant = source
&& let Some(node) = cx.tcx.hir().find_parent(e.hir_id)
&& let Node::Item(Item { && let Node::Item(Item {
kind: ItemKind::Const(..), kind: ItemKind::Const(..),
.. ..
}) = node }) = cx.tcx.parent_hir_node(e.hir_id)
{ {
return; return;
} }

View file

@ -67,25 +67,20 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: &Msrv
} }
fn is_child_of_cast(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { fn is_child_of_cast(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
let map = cx.tcx.hir(); let parent = cx.tcx.parent_hir_node(expr.hir_id);
if let Some(parent_id) = map.opt_parent_id(expr.hir_id) { let expr = match parent {
let parent = cx.tcx.hir_node(parent_id); Node::Block(block) => {
let expr = match parent { if let Some(parent_expr) = block.expr {
Node::Block(block) => { parent_expr
if let Some(parent_expr) = block.expr { } else {
parent_expr return false;
} else { }
return false; },
} Node::Expr(expr) => expr,
}, _ => return false,
Node::Expr(expr) => expr, };
_ => return false,
};
matches!(expr.kind, ExprKind::Cast(..)) matches!(expr.kind, ExprKind::Cast(..))
} else {
false
}
} }
/// Returns the type T of the pointed to *const [T] or *mut [T] and the mutability of the slice if /// Returns the type T of the pointed to *const [T] or *mut [T] and the mutability of the slice if

View file

@ -65,7 +65,7 @@ pub(super) fn check<'tcx>(
&& let ExprKind::Path(qpath) = inner.kind && let ExprKind::Path(qpath) = inner.kind
&& let QPath::Resolved(None, Path { res, .. }) = qpath && let QPath::Resolved(None, Path { res, .. }) = qpath
&& let Res::Local(hir_id) = res && let Res::Local(hir_id) = res
&& let parent = cx.tcx.hir().get_parent(*hir_id) && let parent = cx.tcx.parent_hir_node(*hir_id)
&& let Node::Local(local) = parent && let Node::Local(local) = parent
{ {
if let Some(ty) = local.ty if let Some(ty) = local.ty

View file

@ -63,7 +63,7 @@ impl LateLintPass<'_> for DbgMacro {
ExprKind::Block(..) => { ExprKind::Block(..) => {
// If the `dbg!` macro is a "free" statement and not contained within other expressions, // If the `dbg!` macro is a "free" statement and not contained within other expressions,
// remove the whole statement. // remove the whole statement.
if let Some(Node::Stmt(_)) = cx.tcx.hir().find_parent(expr.hir_id) if let Node::Stmt(_) = cx.tcx.parent_hir_node(expr.hir_id)
&& let Some(semi_span) = cx.sess().source_map().mac_call_stmt_semi_span(macro_call.span) && let Some(semi_span) = cx.sess().source_map().mac_call_stmt_semi_span(macro_call.span)
{ {
(macro_call.span.to(semi_span), String::new()) (macro_call.span.to(semi_span), String::new())

View file

@ -128,8 +128,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
}, },
_, _,
) => { ) => {
if let Some(parent) = self.cx.tcx.hir().find_parent(expr.hir_id) if let Some(fn_sig) = self.cx.tcx.parent_hir_node(expr.hir_id).fn_sig()
&& let Some(fn_sig) = parent.fn_sig()
&& let FnRetTy::Return(_ty) = fn_sig.decl.output && let FnRetTy::Return(_ty) = fn_sig.decl.output
{ {
// We cannot check the exact type since it's a `hir::Ty`` which does not implement `is_numeric` // We cannot check the exact type since it's a `hir::Ty`` which does not implement `is_numeric`

View file

@ -1088,7 +1088,7 @@ fn report<'tcx>(
// //
// e.g. `&mut x.y.z` where `x` is a union, and accessing `z` requires a // e.g. `&mut x.y.z` where `x` is a union, and accessing `z` requires a
// deref through `ManuallyDrop<_>` will not compile. // deref through `ManuallyDrop<_>` will not compile.
let parent_id = cx.tcx.hir().parent_id(expr.hir_id); let parent_id = cx.tcx.parent_hir_id(expr.hir_id);
if parent_id == data.first_expr.hir_id { if parent_id == data.first_expr.hir_id {
return; return;
} }

View file

@ -131,7 +131,7 @@ fn is_argument(tcx: TyCtxt<'_>, id: HirId) -> bool {
_ => return false, _ => return false,
} }
matches!(tcx.hir().find_parent(id), Some(Node::Param(_))) matches!(tcx.parent_hir_node(id), Node::Param(_))
} }
impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
@ -156,8 +156,8 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
let map = &self.cx.tcx.hir(); let map = &self.cx.tcx.hir();
if is_argument(self.cx.tcx, cmt.hir_id) { if is_argument(self.cx.tcx, cmt.hir_id) {
// Skip closure arguments // Skip closure arguments
let parent_id = map.parent_id(cmt.hir_id); let parent_id = self.cx.tcx.parent_hir_id(cmt.hir_id);
if let Some(Node::Expr(..)) = map.find_parent(parent_id) { if let Node::Expr(..) = self.cx.tcx.parent_hir_node(parent_id) {
return; return;
} }

View file

@ -53,7 +53,7 @@ pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: &'tcx FnKind<'_>, body:
pub(super) fn check_impl_item(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) { pub(super) fn check_impl_item(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) {
if let ImplItemKind::Fn(_, body_id) = impl_item.kind if let ImplItemKind::Fn(_, body_id) = impl_item.kind
&& let hir::Node::Item(item) = cx.tcx.hir().get_parent(impl_item.hir_id()) && let hir::Node::Item(item) = cx.tcx.parent_hir_node(impl_item.hir_id())
&& let hir::ItemKind::Impl(impl_) = item.kind && let hir::ItemKind::Impl(impl_) = item.kind
&& let hir::Impl { of_trait, .. } = *impl_ && let hir::Impl { of_trait, .. } = *impl_
&& of_trait.is_none() && of_trait.is_none()
@ -72,7 +72,7 @@ pub(super) fn check_impl_item(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) {
pub(super) fn check_trait_item(cx: &LateContext<'_>, trait_item: &TraitItem<'_>, avoid_breaking_exported_api: bool) { pub(super) fn check_trait_item(cx: &LateContext<'_>, trait_item: &TraitItem<'_>, avoid_breaking_exported_api: bool) {
if !avoid_breaking_exported_api if !avoid_breaking_exported_api
&& let TraitItemKind::Fn(_, _) = trait_item.kind && let TraitItemKind::Fn(_, _) = trait_item.kind
&& let hir::Node::Item(item) = cx.tcx.hir().get_parent(trait_item.hir_id()) && let hir::Node::Item(item) = cx.tcx.parent_hir_node(trait_item.hir_id())
// ^^ (Will always be a trait) // ^^ (Will always be a trait)
&& !item.vis_span.is_empty() // Is public && !item.vis_span.is_empty() // Is public
&& !is_in_test_function(cx.tcx, trait_item.hir_id()) && !is_in_test_function(cx.tcx, trait_item.hir_id())

View file

@ -41,8 +41,8 @@ impl<'tcx> LateLintPass<'tcx> for IgnoredUnitPatterns {
return; return;
} }
match cx.tcx.hir().get_parent(pat.hir_id) { match cx.tcx.parent_hir_node(pat.hir_id) {
Node::Param(param) if matches!(cx.tcx.hir().get_parent(param.hir_id), Node::Item(_)) => { Node::Param(param) if matches!(cx.tcx.parent_hir_node(param.hir_id), Node::Item(_)) => {
// Ignore function parameters // Ignore function parameters
return; return;
}, },

View file

@ -242,12 +242,8 @@ impl<'a, 'tcx> Visitor<'tcx> for SliceIndexLintingVisitor<'a, 'tcx> {
} = *self; } = *self;
if let Some(use_info) = slice_lint_info.get_mut(&local_id) if let Some(use_info) = slice_lint_info.get_mut(&local_id)
// Check if this is even a local we're interested in
&& let map = cx.tcx.hir()
// Checking for slice indexing // Checking for slice indexing
&& let parent_id = map.parent_id(expr.hir_id) && let parent_id = cx.tcx.parent_hir_id(expr.hir_id)
&& let hir::Node::Expr(parent_expr) = cx.tcx.hir_node(parent_id) && let hir::Node::Expr(parent_expr) = cx.tcx.hir_node(parent_id)
&& let hir::ExprKind::Index(_, index_expr, _) = parent_expr.kind && let hir::ExprKind::Index(_, index_expr, _) = parent_expr.kind
&& let Some(Constant::Int(index_value)) = constant(cx, cx.typeck_results(), index_expr) && let Some(Constant::Int(index_value)) = constant(cx, cx.typeck_results(), index_expr)
@ -255,11 +251,10 @@ impl<'a, 'tcx> Visitor<'tcx> for SliceIndexLintingVisitor<'a, 'tcx> {
&& index_value < max_suggested_slice && index_value < max_suggested_slice
// Make sure that this slice index is read only // Make sure that this slice index is read only
&& let maybe_addrof_id = map.parent_id(parent_id) && let hir::Node::Expr(maybe_addrof_expr) = cx.tcx.parent_hir_node(parent_id)
&& let hir::Node::Expr(maybe_addrof_expr) = cx.tcx.hir_node(maybe_addrof_id)
&& let hir::ExprKind::AddrOf(_kind, hir::Mutability::Not, _inner_expr) = maybe_addrof_expr.kind && let hir::ExprKind::AddrOf(_kind, hir::Mutability::Not, _inner_expr) = maybe_addrof_expr.kind
{ {
use_info.index_use.push((index_value, map.span(parent_expr.hir_id))); use_info.index_use.push((index_value, cx.tcx.hir().span(parent_expr.hir_id)));
return; return;
} }

View file

@ -269,7 +269,7 @@ impl {self_ty_without_ref} {{
// } // }
let span_behind_impl = cx let span_behind_impl = cx
.tcx .tcx
.def_span(cx.tcx.hir().parent_id(item.hir_id()).owner.def_id) .def_span(cx.tcx.parent_hir_id(item.hir_id()).owner.def_id)
.shrink_to_lo(); .shrink_to_lo();
let sugg = format!( let sugg = format!(

View file

@ -285,7 +285,7 @@ fn elision_suggestions(
.iter() .iter()
.filter(|usage| named_lifetime(usage).map_or(false, |id| elidable_lts.contains(&id))) .filter(|usage| named_lifetime(usage).map_or(false, |id| elidable_lts.contains(&id)))
.map(|usage| { .map(|usage| {
match cx.tcx.hir().get_parent(usage.hir_id) { match cx.tcx.parent_hir_node(usage.hir_id) {
Node::Ty(Ty { Node::Ty(Ty {
kind: TyKind::Ref(..), .. kind: TyKind::Ref(..), ..
}) => { }) => {

View file

@ -62,8 +62,7 @@ pub(super) fn check<'tcx>(
if let Node::Pat(pat) = node if let Node::Pat(pat) = node
&& let PatKind::Binding(bind_ann, ..) = pat.kind && let PatKind::Binding(bind_ann, ..) = pat.kind
&& !matches!(bind_ann, BindingAnnotation(_, Mutability::Mut)) && !matches!(bind_ann, BindingAnnotation(_, Mutability::Mut))
&& let parent_node = cx.tcx.hir().parent_id(hir_id) && let Node::Local(parent_let_expr) = cx.tcx.parent_hir_node(hir_id)
&& let Node::Local(parent_let_expr) = cx.tcx.hir_node(parent_node)
&& let Some(init) = parent_let_expr.init && let Some(init) = parent_let_expr.init
{ {
match init.kind { match init.kind {

View file

@ -68,8 +68,8 @@ impl LateLintPass<'_> for ManualHashOne {
&& let ExprKind::MethodCall(seg, build_hasher, [], _) = init.kind && let ExprKind::MethodCall(seg, build_hasher, [], _) = init.kind
&& seg.ident.name == sym!(build_hasher) && seg.ident.name == sym!(build_hasher)
&& let Node::Stmt(local_stmt) = cx.tcx.hir().get_parent(local.hir_id) && let Node::Stmt(local_stmt) = cx.tcx.parent_hir_node(local.hir_id)
&& let Node::Block(block) = cx.tcx.hir().get_parent(local_stmt.hir_id) && let Node::Block(block) = cx.tcx.parent_hir_node(local_stmt.hir_id)
&& let mut stmts = block.stmts.iter() && let mut stmts = block.stmts.iter()
.skip_while(|stmt| stmt.hir_id != local_stmt.hir_id) .skip_while(|stmt| stmt.hir_id != local_stmt.hir_id)
@ -91,7 +91,7 @@ impl LateLintPass<'_> for ManualHashOne {
// `hasher.finish()`, may be anywhere in a statement or the trailing expr of the block // `hasher.finish()`, may be anywhere in a statement or the trailing expr of the block
&& let Some(path_expr) = local_used_once(cx, (maybe_finish_stmt, block.expr), hasher) && let Some(path_expr) = local_used_once(cx, (maybe_finish_stmt, block.expr), hasher)
&& let Node::Expr(finish_expr) = cx.tcx.hir().get_parent(path_expr.hir_id) && let Node::Expr(finish_expr) = cx.tcx.parent_hir_node(path_expr.hir_id)
&& !finish_expr.span.from_expansion() && !finish_expr.span.from_expansion()
&& let ExprKind::MethodCall(seg, _, [], _) = finish_expr.kind && let ExprKind::MethodCall(seg, _, [], _) = finish_expr.kind
&& seg.ident.name == sym!(finish) && seg.ident.name == sym!(finish)

View file

@ -79,9 +79,9 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid {
&& let Node::Pat(_) = cx.tcx.hir_node(hir_id) && let Node::Pat(_) = cx.tcx.hir_node(hir_id)
{ {
// Apply only to params or locals with annotated types // Apply only to params or locals with annotated types
match cx.tcx.hir().find_parent(hir_id) { match cx.tcx.parent_hir_node(hir_id) {
Some(Node::Param(..)) => (), Node::Param(..) => (),
Some(Node::Local(local)) => { Node::Local(local) => {
let Some(ty) = local.ty else { return }; let Some(ty) = local.ty else { return };
if matches!(ty.kind, TyKind::Infer) { if matches!(ty.kind, TyKind::Infer) {
return; return;

View file

@ -36,7 +36,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
.to_string(); .to_string();
// Do we need to add ';' to suggestion ? // Do we need to add ';' to suggestion ?
if let Node::Stmt(stmt) = cx.tcx.hir().get_parent(expr.hir_id) if let Node::Stmt(stmt) = cx.tcx.parent_hir_node(expr.hir_id)
&& let StmtKind::Expr(_) = stmt.kind && let StmtKind::Expr(_) = stmt.kind
&& match match_body.kind { && match match_body.kind {
// We don't need to add a ; to blocks, unless that block is from a macro expansion // We don't need to add a ; to blocks, unless that block is from a macro expansion
@ -146,18 +146,16 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
/// Returns true if the `ex` match expression is in a local (`let`) or assign expression /// Returns true if the `ex` match expression is in a local (`let`) or assign expression
fn opt_parent_assign_span<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option<AssignmentExpr> { fn opt_parent_assign_span<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option<AssignmentExpr> {
let map = &cx.tcx.hir(); if let Node::Expr(parent_arm_expr) = cx.tcx.parent_hir_node(ex.hir_id) {
return match cx.tcx.parent_hir_node(parent_arm_expr.hir_id) {
if let Some(Node::Expr(parent_arm_expr)) = map.find_parent(ex.hir_id) { Node::Local(parent_let_expr) => Some(AssignmentExpr::Local {
return match map.find_parent(parent_arm_expr.hir_id) {
Some(Node::Local(parent_let_expr)) => Some(AssignmentExpr::Local {
span: parent_let_expr.span, span: parent_let_expr.span,
pat_span: parent_let_expr.pat.span(), pat_span: parent_let_expr.pat.span(),
}), }),
Some(Node::Expr(Expr { Node::Expr(Expr {
kind: ExprKind::Assign(parent_assign_expr, match_expr, _), kind: ExprKind::Assign(parent_assign_expr, match_expr, _),
.. ..
})) => Some(AssignmentExpr::Assign { }) => Some(AssignmentExpr::Assign {
span: parent_assign_expr.span, span: parent_assign_expr.span,
match_span: match_expr.span, match_span: match_expr.span,
}), }),
@ -191,7 +189,7 @@ fn sugg_with_curlies<'a>(
// If the parent is already an arm, and the body is another match statement, // If the parent is already an arm, and the body is another match statement,
// we need curly braces around suggestion // we need curly braces around suggestion
if let Node::Arm(arm) = &cx.tcx.hir().get_parent(match_expr.hir_id) { if let Node::Arm(arm) = &cx.tcx.parent_hir_node(match_expr.hir_id) {
if let ExprKind::Match(..) = arm.body.kind { if let ExprKind::Match(..) = arm.body.kind {
cbrace_end = format!("\n{indent}}}"); cbrace_end = format!("\n{indent}}}");
// Fix body indent due to the match // Fix body indent due to the match

View file

@ -199,7 +199,7 @@ fn get_pat_binding<'tcx>(
return span.map(|span| PatBindingInfo { return span.map(|span| PatBindingInfo {
span, span,
byref_ident, byref_ident,
is_field: matches!(cx.tcx.hir().get_parent(local), Node::PatField(_)), is_field: matches!(cx.tcx.parent_hir_node(local), Node::PatField(_)),
}); });
} }
} }

View file

@ -4458,7 +4458,7 @@ impl Methods {
_ => {}, _ => {},
}, },
("drain", ..) => { ("drain", ..) => {
if let Node::Stmt(Stmt { hir_id: _, kind, .. }) = cx.tcx.hir().get_parent(expr.hir_id) if let Node::Stmt(Stmt { hir_id: _, kind, .. }) = cx.tcx.parent_hir_node(expr.hir_id)
&& matches!(kind, StmtKind::Semi(_)) && matches!(kind, StmtKind::Semi(_))
&& args.len() <= 1 && args.len() <= 1
{ {

View file

@ -21,9 +21,9 @@ fn is_unwrap_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, receiver: &Expr<'_>) { pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, receiver: &Expr<'_>) {
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver).peel_refs(), sym::RwLock) if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver).peel_refs(), sym::RwLock)
&& let Node::Expr(unwrap_call_expr) = cx.tcx.hir().get_parent(expr.hir_id) && let Node::Expr(unwrap_call_expr) = cx.tcx.parent_hir_node(expr.hir_id)
&& is_unwrap_call(cx, unwrap_call_expr) && is_unwrap_call(cx, unwrap_call_expr)
&& let parent = cx.tcx.hir().get_parent(unwrap_call_expr.hir_id) && let parent = cx.tcx.parent_hir_node(unwrap_call_expr.hir_id)
&& let Node::Local(local) = parent && let Node::Local(local) = parent
&& let Some(mir) = enclosing_mir(cx.tcx, expr.hir_id) && let Some(mir) = enclosing_mir(cx.tcx, expr.hir_id)
&& let Some((local, _)) = mir && let Some((local, _)) = mir

View file

@ -16,7 +16,7 @@ use super::UNNECESSARY_FOLD;
/// Changing `fold` to `sum` needs it sometimes when the return type can't be /// Changing `fold` to `sum` needs it sometimes when the return type can't be
/// inferred. This checks for some common cases where it can be safely omitted /// inferred. This checks for some common cases where it can be safely omitted
fn needs_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { fn needs_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
let parent = cx.tcx.hir().get_parent(expr.hir_id); let parent = cx.tcx.parent_hir_node(expr.hir_id);
// some common cases where turbofish isn't needed: // some common cases where turbofish isn't needed:
// - assigned to a local variable with a type annotation // - assigned to a local variable with a type annotation

View file

@ -76,7 +76,7 @@ pub(super) fn check(
(expr.span.with_lo(call_args[0].span.hi()), String::new()), (expr.span.with_lo(call_args[0].span.hi()), String::new()),
]; ];
// try to also remove the unsafe block if present // try to also remove the unsafe block if present
if let hir::Node::Block(block) = cx.tcx.hir().get_parent(expr.hir_id) if let hir::Node::Block(block) = cx.tcx.parent_hir_node(expr.hir_id)
&& let hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::UserProvided) = block.rules && let hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::UserProvided) = block.rules
{ {
suggs.extend([ suggs.extend([

View file

@ -206,10 +206,9 @@ impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> {
/// ///
/// When such a read is found, the lint is triggered. /// When such a read is found, the lint is triggered.
fn check_for_unsequenced_reads(vis: &mut ReadVisitor<'_, '_>) { fn check_for_unsequenced_reads(vis: &mut ReadVisitor<'_, '_>) {
let map = &vis.cx.tcx.hir();
let mut cur_id = vis.write_expr.hir_id; let mut cur_id = vis.write_expr.hir_id;
loop { loop {
let parent_id = map.parent_id(cur_id); let parent_id = vis.cx.tcx.parent_hir_id(cur_id);
if parent_id == cur_id { if parent_id == cur_id {
break; break;
} }

View file

@ -161,7 +161,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
}; };
// Exclude non-inherent impls // Exclude non-inherent impls
if let Some(Node::Item(item)) = cx.tcx.hir().find_parent(hir_id) { if let Node::Item(item) = cx.tcx.parent_hir_node(hir_id) {
if matches!( if matches!(
item.kind, item.kind,
ItemKind::Impl(Impl { of_trait: Some(_), .. }) | ItemKind::Trait(..) ItemKind::Impl(Impl { of_trait: Some(_), .. }) | ItemKind::Trait(..)

View file

@ -100,7 +100,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
} }
// Exclude non-inherent impls // Exclude non-inherent impls
if let Some(Node::Item(item)) = cx.tcx.hir().find_parent(hir_id) { if let Node::Item(item) = cx.tcx.parent_hir_node(hir_id) {
if matches!( if matches!(
item.kind, item.kind,
ItemKind::Impl(Impl { of_trait: Some(_), .. }) | ItemKind::Trait(..) ItemKind::Impl(Impl { of_trait: Some(_), .. }) | ItemKind::Trait(..)

View file

@ -449,7 +449,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
let mut dereferenced_expr = expr; let mut dereferenced_expr = expr;
let mut needs_check_adjustment = true; let mut needs_check_adjustment = true;
loop { loop {
let parent_id = cx.tcx.hir().parent_id(cur_expr.hir_id); let parent_id = cx.tcx.parent_hir_id(cur_expr.hir_id);
if parent_id == cur_expr.hir_id { if parent_id == cur_expr.hir_id {
break; break;
} }

View file

@ -34,7 +34,7 @@ pub(super) fn check<'tcx>(
} }
fn used_in_comparison_with_zero(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { fn used_in_comparison_with_zero(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
let Some(Node::Expr(parent_expr)) = cx.tcx.hir().find_parent(expr.hir_id) else { let Node::Expr(parent_expr) = cx.tcx.parent_hir_node(expr.hir_id) else {
return false; return false;
}; };
let ExprKind::Binary(op, lhs, rhs) = parent_expr.kind else { let ExprKind::Binary(op, lhs, rhs) = parent_expr.kind else {

View file

@ -301,7 +301,7 @@ impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue {
} }
// Exclude non-inherent impls // Exclude non-inherent impls
if let Some(Node::Item(item)) = cx.tcx.hir().find_parent(hir_id) { if let Node::Item(item) = cx.tcx.parent_hir_node(hir_id) {
if matches!( if matches!(
item.kind, item.kind,
ItemKind::Impl(Impl { of_trait: Some(_), .. }) | ItemKind::Trait(..) ItemKind::Impl(Impl { of_trait: Some(_), .. }) | ItemKind::Trait(..)

View file

@ -41,7 +41,7 @@ pub(super) fn check<'tcx>(
_ => return false, _ => return false,
}; };
if let Node::Expr(parent) = cx.tcx.hir().get_parent(e.hir_id) if let Node::Expr(parent) = cx.tcx.parent_hir_node(e.hir_id)
&& parent.precedence().order() > ExprPrecedence::Cast.order() && parent.precedence().order() > ExprPrecedence::Cast.order()
{ {
sugg = format!("({sugg})"); sugg = format!("({sugg})");

View file

@ -153,13 +153,10 @@ fn all_bindings_are_for_conv<'tcx>(
let Some(locals) = locals.iter().map(|e| path_to_local(e)).collect::<Option<Vec<_>>>() else { let Some(locals) = locals.iter().map(|e| path_to_local(e)).collect::<Option<Vec<_>>>() else {
return false; return false;
}; };
let Some(local_parents) = locals let local_parents = locals
.iter() .iter()
.map(|&l| cx.tcx.hir().find_parent(l)) .map(|l| cx.tcx.parent_hir_node(*l))
.collect::<Option<Vec<_>>>() .collect::<Vec<_>>();
else {
return false;
};
local_parents local_parents
.iter() .iter()

View file

@ -19,9 +19,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
if is_questionmark_desugar_marked_call(expr) { if is_questionmark_desugar_marked_call(expr) {
return; return;
} }
let map = &cx.tcx.hir(); if let hir::Node::Expr(parent_expr) = cx.tcx.parent_hir_node(expr.hir_id)
let opt_parent_node = map.find_parent(expr.hir_id);
if let Some(hir::Node::Expr(parent_expr)) = opt_parent_node
&& is_questionmark_desugar_marked_call(parent_expr) && is_questionmark_desugar_marked_call(parent_expr)
{ {
return; return;
@ -183,8 +181,8 @@ fn fmt_stmts_and_call(
let mut stmts_and_call_snippet = stmts_and_call.join(&format!("{}{}", ";\n", " ".repeat(call_expr_indent))); let mut stmts_and_call_snippet = stmts_and_call.join(&format!("{}{}", ";\n", " ".repeat(call_expr_indent)));
// expr is not in a block statement or result expression position, wrap in a block // expr is not in a block statement or result expression position, wrap in a block
let parent_node = cx.tcx.hir().find_parent(call_expr.hir_id); let parent_node = cx.tcx.parent_hir_node(call_expr.hir_id);
if !matches!(parent_node, Some(Node::Block(_))) && !matches!(parent_node, Some(Node::Stmt(_))) { if !matches!(parent_node, Node::Block(_)) && !matches!(parent_node, Node::Stmt(_)) {
let block_indent = call_expr_indent + 4; let block_indent = call_expr_indent + 4;
stmts_and_call_snippet = stmts_and_call_snippet =
reindent_multiline(stmts_and_call_snippet.into(), true, Some(block_indent)).into_owned(); reindent_multiline(stmts_and_call_snippet.into(), true, Some(block_indent)).into_owned();

View file

@ -116,7 +116,7 @@ impl LateLintPass<'_> for UnnecessaryBoxReturns {
fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::ImplItem<'_>) { fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::ImplItem<'_>) {
// Ignore implementations of traits, because the lint should be on the // Ignore implementations of traits, because the lint should be on the
// trait, not on the implementation of it. // trait, not on the implementation of it.
let Node::Item(parent) = cx.tcx.hir().get_parent(item.hir_id()) else { let Node::Item(parent) = cx.tcx.parent_hir_node(item.hir_id()) else {
return; return;
}; };
let ItemKind::Impl(parent) = parent.kind else { return }; let ItemKind::Impl(parent) = parent.kind else { return };

View file

@ -92,7 +92,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
// Abort if the method is implementing a trait or of it a trait method. // Abort if the method is implementing a trait or of it a trait method.
let hir_id = cx.tcx.local_def_id_to_hir_id(def_id); let hir_id = cx.tcx.local_def_id_to_hir_id(def_id);
if let Some(Node::Item(item)) = cx.tcx.hir().find_parent(hir_id) { if let Node::Item(item) = cx.tcx.parent_hir_node(hir_id) {
if matches!( if matches!(
item.kind, item.kind,
ItemKind::Impl(Impl { of_trait: Some(_), .. }) | ItemKind::Trait(..) ItemKind::Impl(Impl { of_trait: Some(_), .. }) | ItemKind::Trait(..)

View file

@ -156,7 +156,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync {
&& let Some(local_def_id) = def_id.as_local() && let Some(local_def_id) = def_id.as_local()
&& cx.tcx.def_kind(def_id) == DefKind::Fn && cx.tcx.def_kind(def_id) == DefKind::Fn
&& cx.tcx.asyncness(def_id).is_async() && cx.tcx.asyncness(def_id).is_async()
&& !is_node_func_call(cx.tcx.hir().get_parent(hir_id), path.span) && !is_node_func_call(cx.tcx.parent_hir_node(hir_id), path.span)
{ {
self.async_fns_as_value.insert(local_def_id); self.async_fns_as_value.insert(local_def_id);
} }

View file

@ -208,7 +208,7 @@ struct MutationVisitor<'tcx> {
/// (i.e. the `x` in `x.as_mut()`), and that is the reason for why we care about its parent /// (i.e. the `x` in `x.as_mut()`), and that is the reason for why we care about its parent
/// expression: that will be where the actual method call is. /// expression: that will be where the actual method call is.
fn is_option_as_mut_use(tcx: TyCtxt<'_>, expr_id: HirId) -> bool { fn is_option_as_mut_use(tcx: TyCtxt<'_>, expr_id: HirId) -> bool {
if let Node::Expr(mutating_expr) = tcx.hir().get_parent(expr_id) if let Node::Expr(mutating_expr) = tcx.parent_hir_node(expr_id)
&& let ExprKind::MethodCall(path, ..) = mutating_expr.kind && let ExprKind::MethodCall(path, ..) = mutating_expr.kind
{ {
path.ident.name.as_str() == "as_mut" path.ident.name.as_str() == "as_mut"

View file

@ -1007,9 +1007,9 @@ fn get_parent_local<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -
fn get_parent_local_hir_id<'hir>(cx: &LateContext<'hir>, hir_id: hir::HirId) -> Option<&'hir hir::Local<'hir>> { fn get_parent_local_hir_id<'hir>(cx: &LateContext<'hir>, hir_id: hir::HirId) -> Option<&'hir hir::Local<'hir>> {
let map = cx.tcx.hir(); let map = cx.tcx.hir();
match map.find_parent(hir_id) { match cx.tcx.parent_hir_node(hir_id) {
Some(hir::Node::Local(local)) => Some(local), hir::Node::Local(local) => Some(local),
Some(hir::Node::Pat(pattern)) => get_parent_local_hir_id(cx, pattern.hir_id), hir::Node::Pat(pattern) => get_parent_local_hir_id(cx, pattern.hir_id),
_ => None, _ => None,
} }
} }

View file

@ -217,8 +217,7 @@ fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Ve
match peel_hir_expr_refs(expr).0.kind { match peel_hir_expr_refs(expr).0.kind {
ExprKind::Path(ref qpath) => match cx.qpath_res(qpath, expr.hir_id) { ExprKind::Path(ref qpath) => match cx.qpath_res(qpath, expr.hir_id) {
Res::Local(hir_id) => { Res::Local(hir_id) => {
let parent_id = cx.tcx.hir().parent_id(hir_id); if let Node::Local(Local { init: Some(init), .. }) = cx.tcx.parent_hir_node(hir_id) {
if let Node::Local(Local { init: Some(init), .. }) = cx.tcx.hir_node(parent_id) {
path_to_matched_type(cx, init) path_to_matched_type(cx, init)
} else { } else {
None None

View file

@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec {
if let Some(vec_args) = higher::VecArgs::hir(cx, expr.peel_borrows()) { if let Some(vec_args) = higher::VecArgs::hir(cx, expr.peel_borrows()) {
// search for `let foo = vec![_]` expressions where all uses of `foo` // search for `let foo = vec![_]` expressions where all uses of `foo`
// adjust to slices or call a method that exist on slices (e.g. len) // adjust to slices or call a method that exist on slices (e.g. len)
if let Node::Local(local) = cx.tcx.hir().get_parent(expr.hir_id) if let Node::Local(local) = cx.tcx.parent_hir_node(expr.hir_id)
// for now ignore locals with type annotations. // for now ignore locals with type annotations.
// this is to avoid compile errors when doing the suggestion here: let _: Vec<_> = vec![..]; // this is to avoid compile errors when doing the suggestion here: let _: Vec<_> = vec![..];
&& local.ty.is_none() && local.ty.is_none()
@ -103,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec {
} }
// if the local pattern has a specified type, do not lint. // if the local pattern has a specified type, do not lint.
else if let Some(_) = higher::VecArgs::hir(cx, expr) else if let Some(_) = higher::VecArgs::hir(cx, expr)
&& let Node::Local(local) = cx.tcx.hir().get_parent(expr.hir_id) && let Node::Local(local) = cx.tcx.parent_hir_node(expr.hir_id)
&& local.ty.is_some() && local.ty.is_some()
{ {
let span = expr.span.ctxt().outer_expn_data().call_site; let span = expr.span.ctxt().outer_expn_data().call_site;

View file

@ -182,11 +182,9 @@ pub fn expr_or_init<'a, 'b, 'tcx: 'b>(cx: &LateContext<'tcx>, mut expr: &'a Expr
/// Note: If you have an expression that references a binding `x`, use `path_to_local` to get the /// Note: If you have an expression that references a binding `x`, use `path_to_local` to get the
/// canonical binding `HirId`. /// canonical binding `HirId`.
pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Expr<'tcx>> { pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Expr<'tcx>> {
let hir = cx.tcx.hir();
if let Node::Pat(pat) = cx.tcx.hir_node(hir_id) if let Node::Pat(pat) = cx.tcx.hir_node(hir_id)
&& matches!(pat.kind, PatKind::Binding(BindingAnnotation::NONE, ..)) && matches!(pat.kind, PatKind::Binding(BindingAnnotation::NONE, ..))
&& let parent = hir.parent_id(hir_id) && let Node::Local(local) = cx.tcx.parent_hir_node(hir_id)
&& let Node::Local(local) = cx.tcx.hir_node(parent)
{ {
return local.init; return local.init;
} }
@ -333,7 +331,7 @@ pub fn is_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol)
/// Checks if the `def_id` belongs to a function that is part of a trait impl. /// Checks if the `def_id` belongs to a function that is part of a trait impl.
pub fn is_def_id_trait_method(cx: &LateContext<'_>, def_id: LocalDefId) -> bool { pub fn is_def_id_trait_method(cx: &LateContext<'_>, def_id: LocalDefId) -> bool {
if let Some(hir_id) = cx.tcx.opt_local_def_id_to_hir_id(def_id) if let Some(hir_id) = cx.tcx.opt_local_def_id_to_hir_id(def_id)
&& let Node::Item(item) = cx.tcx.hir().get_parent(hir_id) && let Node::Item(item) = cx.tcx.parent_hir_node(hir_id)
&& let ItemKind::Impl(imp) = item.kind && let ItemKind::Impl(imp) = item.kind
{ {
imp.of_trait.is_some() imp.of_trait.is_some()
@ -1311,7 +1309,7 @@ pub fn contains_return<'tcx>(expr: impl Visitable<'tcx>) -> bool {
/// Gets the parent node, if any. /// Gets the parent node, if any.
pub fn get_parent_node(tcx: TyCtxt<'_>, id: HirId) -> Option<Node<'_>> { pub fn get_parent_node(tcx: TyCtxt<'_>, id: HirId) -> Option<Node<'_>> {
tcx.hir().find_parent(id) Some(tcx.parent_hir_node(id))
} }
/// Gets the parent expression, if any - this is useful to constrain a lint. /// Gets the parent expression, if any - this is useful to constrain a lint.
@ -2227,7 +2225,7 @@ pub fn is_no_core_crate(cx: &LateContext<'_>) -> bool {
/// } /// }
/// ``` /// ```
pub fn is_trait_impl_item(cx: &LateContext<'_>, hir_id: HirId) -> bool { pub fn is_trait_impl_item(cx: &LateContext<'_>, hir_id: HirId) -> bool {
if let Some(Node::Item(item)) = cx.tcx.hir().find_parent(hir_id) { if let Node::Item(item) = cx.tcx.parent_hir_node(hir_id) {
matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. })) matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }))
} else { } else {
false false

View file

@ -237,7 +237,7 @@ fn path_segment_certainty(
}, },
// `get_parent` because `hir_id` refers to a `Pat`, and we're interested in the node containing the `Pat`. // `get_parent` because `hir_id` refers to a `Pat`, and we're interested in the node containing the `Pat`.
Res::Local(hir_id) => match cx.tcx.hir().get_parent(hir_id) { Res::Local(hir_id) => match cx.tcx.parent_hir_node(hir_id) {
// An argument's type is always certain. // An argument's type is always certain.
Node::Param(..) => Certainty::Certain(None), Node::Param(..) => Certainty::Certain(None),
// A local's type is certain if its type annotation is certain or it has an initializer whose // A local's type is certain if its type annotation is certain or it has an initializer whose

View file

@ -0,0 +1,7 @@
// edition:2021
#![feature(async_closure)]
pub fn closure() -> impl async Fn() {
async || { /* Don't really need to do anything here. */ }
}

View file

@ -0,0 +1,19 @@
// aux-build:block-on.rs
// aux-build:foreign.rs
// edition:2021
// build-pass
#![feature(async_closure)]
use std::future::Future;
extern crate block_on;
extern crate foreign;
struct NoCopy;
fn main() {
block_on::block_on(async {
foreign::closure()().await;
});
}