Merge from rustc

This commit is contained in:
Ralf Jung 2024-02-12 13:16:10 +01:00
commit c41d5b12b8
620 changed files with 19617 additions and 5971 deletions

View file

@ -322,7 +322,7 @@ jobs:
RUST_CONFIGURE_ARGS: "--enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set rust.lto=thin"
RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
MACOSX_DEPLOYMENT_TARGET: 10.12
SELECT_XCODE: /Applications/Xcode_13.4.1.app
SELECT_XCODE: /Applications/Xcode_14.3.1.app
NO_LLVM_ASSERTIONS: 1
NO_DEBUG_ASSERTIONS: 1
NO_OVERFLOW_CHECKS: 1
@ -335,7 +335,7 @@ jobs:
RUST_CONFIGURE_ARGS: "--enable-sanitizers --enable-profiler --set rust.jemalloc"
RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
MACOSX_DEPLOYMENT_TARGET: 10.12
SELECT_XCODE: /Applications/Xcode_13.4.1.app
SELECT_XCODE: /Applications/Xcode_14.3.1.app
NO_LLVM_ASSERTIONS: 1
NO_DEBUG_ASSERTIONS: 1
NO_OVERFLOW_CHECKS: 1
@ -347,6 +347,7 @@ jobs:
RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
MACOSX_DEPLOYMENT_TARGET: 10.12
MACOSX_STD_DEPLOYMENT_TARGET: 10.12
SELECT_XCODE: /Applications/Xcode_14.3.1.app
NO_LLVM_ASSERTIONS: 1
NO_DEBUG_ASSERTIONS: 1
NO_OVERFLOW_CHECKS: 1
@ -358,6 +359,7 @@ jobs:
RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
MACOSX_DEPLOYMENT_TARGET: 10.12
MACOSX_STD_DEPLOYMENT_TARGET: 10.12
SELECT_XCODE: /Applications/Xcode_14.3.1.app
NO_LLVM_ASSERTIONS: 1
NO_DEBUG_ASSERTIONS: 1
NO_OVERFLOW_CHECKS: 1
@ -367,7 +369,7 @@ jobs:
SCRIPT: "./x.py dist bootstrap --include-default-paths --host=aarch64-apple-darwin --target=aarch64-apple-darwin"
RUST_CONFIGURE_ARGS: "--enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false --set rust.lto=thin"
RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
SELECT_XCODE: /Applications/Xcode_13.4.1.app
SELECT_XCODE: /Applications/Xcode_14.3.1.app
USE_XCODE_CLANG: 1
MACOSX_DEPLOYMENT_TARGET: 11.0
MACOSX_STD_DEPLOYMENT_TARGET: 11.0
@ -381,7 +383,7 @@ jobs:
SCRIPT: "./x.py --stage 2 test --host=aarch64-apple-darwin --target=aarch64-apple-darwin"
RUST_CONFIGURE_ARGS: "--enable-sanitizers --enable-profiler --set rust.jemalloc"
RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
SELECT_XCODE: /Applications/Xcode_13.4.1.app
SELECT_XCODE: /Applications/Xcode_14.3.1.app
USE_XCODE_CLANG: 1
MACOSX_DEPLOYMENT_TARGET: 11.0
MACOSX_STD_DEPLOYMENT_TARGET: 11.0

View file

@ -147,7 +147,21 @@ dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"anstyle-wincon 2.1.0",
"colorchoice",
"utf8parse",
]
[[package]]
name = "anstream"
version = "0.6.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon 3.0.2",
"colorchoice",
"utf8parse",
]
@ -186,6 +200,16 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7"
dependencies = [
"anstyle",
"windows-sys 0.52.0",
]
[[package]]
name = "anyhow"
version = "1.0.75"
@ -520,7 +544,7 @@ version = "4.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5179bb514e4d7c2051749d8fcefa2ed6d06a9f4e6d69faf3805f5d80b8cf8d56"
dependencies = [
"anstream",
"anstream 0.5.0",
"anstyle",
"clap_lex",
"strsim",
@ -558,7 +582,7 @@ checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
name = "clippy"
version = "0.1.78"
dependencies = [
"anstream",
"anstream 0.5.0",
"clippy_config",
"clippy_lints",
"clippy_utils",
@ -1234,6 +1258,16 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "env_filter"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea"
dependencies = [
"log",
"regex",
]
[[package]]
name = "env_logger"
version = "0.10.0"
@ -1247,6 +1281,19 @@ dependencies = [
"termcolor",
]
[[package]]
name = "env_logger"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05e7cf40684ae96ade6232ed84582f40ce0a66efcd43a5117aef610534f8e0b8"
dependencies = [
"anstream 0.6.11",
"anstyle",
"env_filter",
"humantime",
"log",
]
[[package]]
name = "equivalent"
version = "1.0.0"
@ -1638,9 +1685,9 @@ dependencies = [
[[package]]
name = "handlebars"
version = "4.3.7"
version = "5.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83c3372087601b532857d332f5957cbae686da52bb7810bf038c3e3c3cc2fa0d"
checksum = "ab283476b99e66691dee3f1640fea91487a8d81f50fb5ecc75538f8f8879a1e4"
dependencies = [
"log",
"pest",
@ -2227,6 +2274,7 @@ dependencies = [
name = "linkchecker"
version = "0.1.0"
dependencies = [
"html5ever",
"once_cell",
"regex",
]
@ -2335,9 +2383,9 @@ dependencies = [
[[package]]
name = "mdbook"
version = "0.4.36"
version = "0.4.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80992cb0e05f22cc052c99f8e883f1593b891014b96a8b4637fd274d7030c85e"
checksum = "0c33564061c3c640bed5ace7d6a2a1b65f2c64257d1ac930c15e94ed0fb561d3"
dependencies = [
"ammonia",
"anyhow",
@ -2345,14 +2393,13 @@ dependencies = [
"clap",
"clap_complete",
"elasticlunr-rs",
"env_logger",
"env_logger 0.11.1",
"handlebars",
"log",
"memchr",
"once_cell",
"opener",
"pathdiff",
"pulldown-cmark",
"pulldown-cmark 0.10.0",
"regex",
"serde",
"serde_json",
@ -2471,7 +2518,7 @@ dependencies = [
"aes",
"colored",
"ctrlc",
"env_logger",
"env_logger 0.10.0",
"getrandom",
"jemalloc-sys",
"lazy_static",
@ -2689,7 +2736,7 @@ dependencies = [
"camino",
"clap",
"derive_builder",
"env_logger",
"env_logger 0.10.0",
"fs_extra",
"glob",
"humansize",
@ -3012,6 +3059,24 @@ dependencies = [
"unicase",
]
[[package]]
name = "pulldown-cmark"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dce76ce678ffc8e5675b22aa1405de0b7037e2fdf8913fea40d1926c6fe1e6e7"
dependencies = [
"bitflags 2.4.1",
"memchr",
"pulldown-cmark-escape",
"unicase",
]
[[package]]
name = "pulldown-cmark-escape"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5d8f9aa0e3cbcfaf8bf00300004ee3b72f74770f9cbac93f6928771f613276b"
[[package]]
name = "punycode"
version = "0.4.1"
@ -3271,7 +3336,7 @@ name = "rustbook"
version = "0.1.0"
dependencies = [
"clap",
"env_logger",
"env_logger 0.10.0",
"mdbook",
]
@ -4427,7 +4492,7 @@ name = "rustc_resolve"
version = "0.0.0"
dependencies = [
"bitflags 2.4.1",
"pulldown-cmark",
"pulldown-cmark 0.9.6",
"rustc_arena",
"rustc_ast",
"rustc_ast_pretty",
@ -4971,9 +5036,9 @@ checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f"
[[package]]
name = "shlex"
version = "1.1.0"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "siphasher"

View file

@ -403,8 +403,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
}
let typeck = self.infcx.tcx.typeck(self.mir_def_id());
let hir_id = hir.parent_id(expr.hir_id);
let parent = self.infcx.tcx.hir_node(hir_id);
let parent = self.infcx.tcx.parent_hir_node(expr.hir_id);
let (def_id, args, offset) = if let hir::Node::Expr(parent_expr) = parent
&& let hir::ExprKind::MethodCall(_, _, args, _) = parent_expr.kind
&& 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,
// 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.hir_node(parent) {
if let hir::Node::Expr(parent) = tcx.parent_hir_node(closure_expr.hir_id) {
if let hir::ExprKind::MethodCall(_, recv, ..) = parent.kind {
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 closure_id = self.mir_hir_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 def_id = hir.enclosing_body_owner(fn_call_id);
let mut look_at_return = true;
@ -1034,7 +1034,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
if let InstanceDef::Item(def_id) = source.instance
&& 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 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;
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()
&& let Some(placeholder_id) = id.as_local()
&& let gat_hir_id = self.infcx.tcx.local_def_id_to_hir_id(placeholder_id)
&& let Some(generics_impl) =
hir.get_parent(hir.parent_id(gat_hir_id)).generics()
&& let Some(generics_impl) = self
.infcx
.tcx
.parent_hir_node(self.infcx.tcx.parent_hir_id(gat_hir_id))
.generics()
{
Some((gat_hir_id, generics_impl))
} else {

View file

@ -98,6 +98,8 @@ const_eval_error = {$error_kind ->
const_eval_exact_div_has_remainder =
exact_div: {$a} cannot be divided by {$b} without remainder
const_eval_extern_static =
cannot access extern static ({$did})
const_eval_fn_ptr_call =
function pointers need an RFC before allowed to be called in {const_eval_const_context}s
const_eval_for_loop_into_iter_non_const =
@ -172,6 +174,10 @@ const_eval_invalid_meta =
invalid metadata in wide pointer: total size is bigger than largest supported object
const_eval_invalid_meta_slice =
invalid metadata in wide pointer: slice is bigger than largest supported object
const_eval_invalid_niched_enum_variant_written =
trying to set discriminant of a {$ty} to the niched variant, but the value does not match
const_eval_invalid_str =
this string is not valid UTF-8: {$err}
const_eval_invalid_tag =
@ -298,8 +304,6 @@ const_eval_raw_ptr_to_int =
.note = at compile-time, pointers do not have an integer value
.note2 = avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
const_eval_read_extern_static =
cannot read from extern static ({$did})
const_eval_read_pointer_as_int =
unable to turn pointer into integer
const_eval_realloc_or_alloc_with_offset =

View file

@ -497,6 +497,9 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
ScalarSizeMismatch(_) => const_eval_scalar_size_mismatch,
UninhabitedEnumVariantWritten(_) => const_eval_uninhabited_enum_variant_written,
UninhabitedEnumVariantRead(_) => const_eval_uninhabited_enum_variant_read,
InvalidNichedEnumVariantWritten { .. } => {
const_eval_invalid_niched_enum_variant_written
}
AbiMismatchArgument { .. } => const_eval_incompatible_types,
AbiMismatchReturn { .. } => const_eval_incompatible_return_types,
}
@ -585,6 +588,9 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
builder.arg("target_size", info.target_size);
builder.arg("data_size", info.data_size);
}
InvalidNichedEnumVariantWritten { enum_ty } => {
builder.arg("ty", enum_ty.to_string());
}
AbiMismatchArgument { caller_ty, callee_ty }
| AbiMismatchReturn { caller_ty, callee_ty } => {
builder.arg("caller_ty", caller_ty.to_string());
@ -793,7 +799,7 @@ impl ReportErrorExt for UnsupportedOpInfo {
UnsupportedOpInfo::ReadPartialPointer(_) => const_eval_partial_pointer_copy,
UnsupportedOpInfo::ReadPointerAsInt(_) => const_eval_read_pointer_as_int,
UnsupportedOpInfo::ThreadLocalStatic(_) => const_eval_thread_local_static,
UnsupportedOpInfo::ReadExternStatic(_) => const_eval_read_extern_static,
UnsupportedOpInfo::ExternStatic(_) => const_eval_extern_static,
}
}
fn add_args<G: EmissionGuarantee>(self, _: &DiagCtxt, builder: &mut DiagnosticBuilder<'_, G>) {
@ -812,7 +818,7 @@ impl ReportErrorExt for UnsupportedOpInfo {
OverwritePartialPointer(ptr) | ReadPartialPointer(ptr) => {
builder.arg("ptr", ptr);
}
ThreadLocalStatic(did) | ReadExternStatic(did) => {
ThreadLocalStatic(did) | ExternStatic(did) => {
builder.arg("did", format!("{did:?}"));
}
}

View file

@ -415,7 +415,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
}
fn unsize_into(
pub fn unsize_into(
&mut self,
src: &OpTy<'tcx, M::Provenance>,
cast_ty: TyAndLayout<'tcx>,

View file

@ -85,6 +85,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// Write result.
let niche_dest = self.project_field(dest, tag_field)?;
self.write_immediate(*tag_val, &niche_dest)?;
} else {
// The untagged variant is implicitly encoded simply by having a value that is
// outside the niche variants. But what if the data stored here does not
// actually encode this variant? That would be bad! So let's double-check...
let actual_variant = self.read_discriminant(&dest.to_op(self)?)?;
if actual_variant != variant_index {
throw_ub!(InvalidNichedEnumVariantWritten { enum_ty: dest.layout().ty });
}
}
}
}

View file

@ -557,7 +557,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
if self.tcx.is_foreign_item(def_id) {
// This is unreachable in Miri, but can happen in CTFE where we actually *do* support
// referencing arbitrary (declared) extern statics.
throw_unsup!(ReadExternStatic(def_id));
throw_unsup!(ExternStatic(def_id));
}
// We don't give a span -- statics don't need that, they cannot be generic or associated.

View file

@ -149,6 +149,8 @@ where
"`field` projection called on a slice -- call `index` projection instead"
);
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);
// 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.
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 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 };
if !tcx.is_const_trait_impl_raw(parent.owner.def_id.to_def_id()) {
let parent_owner_id = tcx.parent_hir_id(hir_id).owner;
if !tcx.is_const_trait_impl_raw(parent_owner_id.to_def_id()) {
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

@ -516,6 +516,17 @@ impl Diagnostic {
/// Helper for pushing to `self.suggestions`, if available (not disable).
fn push_suggestion(&mut self, suggestion: CodeSuggestion) {
for subst in &suggestion.substitutions {
for part in &subst.parts {
let span = part.span;
let call_site = span.ctxt().outer_expn_data().call_site;
if span.in_derive_expansion() && span.overlaps_or_adjacent(call_site) {
// Ignore if spans is from derive macro.
return;
}
}
}
if let Ok(suggestions) = &mut self.suggestions {
suggestions.push(suggestion);
}

View file

@ -3508,7 +3508,7 @@ impl<'hir> Node<'hir> {
/// ```ignore (illustrative)
/// ctor
/// .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())
/// ```
pub fn ident(&self) -> Option<Ident> {

View file

@ -2749,14 +2749,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
arg_idx: Option<usize>,
) -> Option<Ty<'tcx>> {
let tcx = self.tcx();
let hir = tcx.hir();
let hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), ident, .. }) =
tcx.hir_node(fn_hir_id)
else {
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 =
self.instantiate_mono_trait_ref(i.of_trait.as_ref()?, self.ast_ty_to_ty(i.self_ty));

View file

@ -12,7 +12,7 @@ use rustc_errors::{codes::*, struct_span_code_err, DiagnosticMessage};
use rustc_hir as hir;
use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::symbol::{kw, sym};
use rustc_target::spec::abi::Abi;
fn equate_intrinsic_type<'tcx>(
@ -133,7 +133,17 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: DefId) -> hir
/// Remember to add all intrinsics here, in `compiler/rustc_codegen_llvm/src/intrinsic.rs`,
/// and in `library/core/src/intrinsics.rs`.
pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
let param = |n| Ty::new_param(tcx, n, Symbol::intern(&format!("P{n}")));
let generics = tcx.generics_of(it.owner_id);
let param = |n| {
if let Some(&ty::GenericParamDef {
name, kind: ty::GenericParamDefKind::Type { .. }, ..
}) = generics.opt_param_at(n as usize, tcx)
{
Ty::new_param(tcx, n, name)
} else {
Ty::new_error_with_message(tcx, tcx.def_span(it.owner_id), "expected param")
}
};
let intrinsic_id = it.owner_id.to_def_id();
let intrinsic_name = tcx.item_name(intrinsic_id);
let name_str = intrinsic_name.as_str();
@ -478,9 +488,16 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
/// Type-check `extern "platform-intrinsic" { ... }` functions.
pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
let generics = tcx.generics_of(it.owner_id);
let param = |n| {
let name = Symbol::intern(&format!("P{n}"));
Ty::new_param(tcx, n, name)
if let Some(&ty::GenericParamDef {
name, kind: ty::GenericParamDefKind::Type { .. }, ..
}) = generics.opt_param_at(n as usize, tcx)
{
Ty::new_param(tcx, n, name)
} else {
Ty::new_error_with_message(tcx, tcx.def_span(it.owner_id), "expected param")
}
};
let name = it.ident.name;

View file

@ -25,9 +25,13 @@ use rustc_trait_selection::traits::ObligationCtxt;
use rustc_trait_selection::traits::{self, ObligationCause};
use std::collections::BTreeMap;
pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) -> Result<(), ErrorGuaranteed> {
pub fn check_trait(
tcx: TyCtxt<'_>,
trait_def_id: DefId,
impl_def_id: LocalDefId,
) -> Result<(), ErrorGuaranteed> {
let lang_items = tcx.lang_items();
let checker = Checker { tcx, trait_def_id };
let checker = Checker { tcx, trait_def_id, impl_def_id };
let mut res = checker.check(lang_items.drop_trait(), visit_implementation_of_drop);
res = res.and(checker.check(lang_items.copy_trait(), visit_implementation_of_copy));
res = res.and(
@ -45,20 +49,16 @@ pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) -> Result<(), ErrorGuar
struct Checker<'tcx> {
tcx: TyCtxt<'tcx>,
trait_def_id: DefId,
impl_def_id: LocalDefId,
}
impl<'tcx> Checker<'tcx> {
fn check<F>(&self, trait_def_id: Option<DefId>, mut f: F) -> Result<(), ErrorGuaranteed>
where
F: FnMut(TyCtxt<'tcx>, LocalDefId) -> Result<(), ErrorGuaranteed>,
{
let mut res = Ok(());
if Some(self.trait_def_id) == trait_def_id {
for &impl_def_id in self.tcx.hir().trait_impls(self.trait_def_id) {
res = res.and(f(self.tcx, impl_def_id));
}
}
res
fn check(
&self,
trait_def_id: Option<DefId>,
f: impl FnOnce(TyCtxt<'tcx>, LocalDefId) -> Result<(), ErrorGuaranteed>,
) -> Result<(), ErrorGuaranteed> {
if Some(self.trait_def_id) == trait_def_id { f(self.tcx, self.impl_def_id) } else { Ok(()) }
}
}
@ -92,10 +92,10 @@ fn visit_implementation_of_copy(
debug!("visit_implementation_of_copy: self_type={:?} (free)", self_type);
let span = match tcx.hir().expect_item(impl_did).expect_impl() {
hir::Impl { polarity: hir::ImplPolarity::Negative(_), .. } => return Ok(()),
hir::Impl { self_ty, .. } => self_ty.span,
};
if let ty::ImplPolarity::Negative = tcx.impl_polarity(impl_did) {
return Ok(());
}
let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
let cause = traits::ObligationCause::misc(span, impl_did);
match type_allowed_to_implement_copy(tcx, param_env, self_type, cause) {
@ -121,10 +121,10 @@ fn visit_implementation_of_const_param_ty(
let param_env = tcx.param_env(impl_did);
let span = match tcx.hir().expect_item(impl_did).expect_impl() {
hir::Impl { polarity: hir::ImplPolarity::Negative(_), .. } => return Ok(()),
impl_ => impl_.self_ty.span,
};
if let ty::ImplPolarity::Negative = tcx.impl_polarity(impl_did) {
return Ok(());
}
let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
let cause = traits::ObligationCause::misc(span, impl_did);
match type_allowed_to_implement_const_param_ty(tcx, param_env, self_type, cause) {

View file

@ -124,22 +124,25 @@ pub fn provide(providers: &mut Providers) {
}
fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) -> Result<(), ErrorGuaranteed> {
// If there are no impls for the trait, then "all impls" are trivially coherent and we won't check anything
// anyway. Thus we bail out even before the specialization graph, avoiding the dep_graph edge.
let Some(impls) = tcx.all_local_trait_impls(()).get(&def_id) else { return Ok(()) };
// Trigger building the specialization graph for the trait. This will detect and report any
// overlap errors.
let mut res = tcx.ensure().specialization_graph_of(def_id);
let impls = tcx.hir().trait_impls(def_id);
for &impl_def_id in impls {
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity();
res = res.and(check_impl(tcx, impl_def_id, trait_ref));
res = res.and(check_object_overlap(tcx, impl_def_id, trait_ref));
res = res.and(unsafety::check_item(tcx, impl_def_id));
res = res.and(unsafety::check_item(tcx, impl_def_id, trait_ref));
res = res.and(tcx.ensure().orphan_check_impl(impl_def_id));
res = res.and(builtin::check_trait(tcx, def_id, impl_def_id));
}
res.and(builtin::check_trait(tcx, def_id))
res
}
/// Checks whether an impl overlaps with the automatic `impl Trait for dyn Trait`.

View file

@ -4,94 +4,91 @@
use rustc_errors::{codes::*, struct_span_code_err};
use rustc_hir as hir;
use rustc_hir::Unsafety;
use rustc_middle::ty::TyCtxt;
use rustc_middle::ty::{TraitRef, TyCtxt};
use rustc_span::def_id::LocalDefId;
use rustc_span::ErrorGuaranteed;
pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuaranteed> {
pub(super) fn check_item(
tcx: TyCtxt<'_>,
def_id: LocalDefId,
trait_ref: TraitRef<'_>,
) -> Result<(), ErrorGuaranteed> {
let item = tcx.hir().expect_item(def_id);
let impl_ = item.expect_impl();
if let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) {
let trait_ref = trait_ref.instantiate_identity();
let trait_def = tcx.trait_def(trait_ref.def_id);
let unsafe_attr =
impl_.generics.params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle");
match (trait_def.unsafety, unsafe_attr, impl_.unsafety, impl_.polarity) {
(Unsafety::Normal, None, Unsafety::Unsafe, hir::ImplPolarity::Positive) => {
return Err(struct_span_code_err!(
tcx.dcx(),
tcx.def_span(def_id),
E0199,
"implementing the trait `{}` is not unsafe",
trait_ref.print_trait_sugared()
)
.with_span_suggestion_verbose(
item.span.with_hi(item.span.lo() + rustc_span::BytePos(7)),
"remove `unsafe` from this trait implementation",
"",
rustc_errors::Applicability::MachineApplicable,
)
.emit());
}
(Unsafety::Unsafe, _, Unsafety::Normal, hir::ImplPolarity::Positive) => {
return Err(struct_span_code_err!(
tcx.dcx(),
tcx.def_span(def_id),
E0200,
"the trait `{}` requires an `unsafe impl` declaration",
trait_ref.print_trait_sugared()
)
.with_note(format!(
"the trait `{}` enforces invariants that the compiler can't check. \
Review the trait documentation and make sure this implementation \
upholds those invariants before adding the `unsafe` keyword",
trait_ref.print_trait_sugared()
))
.with_span_suggestion_verbose(
item.span.shrink_to_lo(),
"add `unsafe` to this trait implementation",
"unsafe ",
rustc_errors::Applicability::MaybeIncorrect,
)
.emit());
}
(Unsafety::Normal, Some(attr_name), Unsafety::Normal, hir::ImplPolarity::Positive) => {
return Err(struct_span_code_err!(
tcx.dcx(),
tcx.def_span(def_id),
E0569,
"requires an `unsafe impl` declaration due to `#[{}]` attribute",
attr_name
)
.with_note(format!(
"the trait `{}` enforces invariants that the compiler can't check. \
Review the trait documentation and make sure this implementation \
upholds those invariants before adding the `unsafe` keyword",
trait_ref.print_trait_sugared()
))
.with_span_suggestion_verbose(
item.span.shrink_to_lo(),
"add `unsafe` to this trait implementation",
"unsafe ",
rustc_errors::Applicability::MaybeIncorrect,
)
.emit());
}
(_, _, Unsafety::Unsafe, hir::ImplPolarity::Negative(_)) => {
// Reported in AST validation
tcx.dcx().span_delayed_bug(item.span, "unsafe negative impl");
}
(_, _, Unsafety::Normal, hir::ImplPolarity::Negative(_))
| (Unsafety::Unsafe, _, Unsafety::Unsafe, hir::ImplPolarity::Positive)
| (Unsafety::Normal, Some(_), Unsafety::Unsafe, hir::ImplPolarity::Positive)
| (Unsafety::Normal, None, Unsafety::Normal, _) => {
// OK
}
let trait_def = tcx.trait_def(trait_ref.def_id);
let unsafe_attr = impl_.generics.params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle");
match (trait_def.unsafety, unsafe_attr, impl_.unsafety, impl_.polarity) {
(Unsafety::Normal, None, Unsafety::Unsafe, hir::ImplPolarity::Positive) => {
return Err(struct_span_code_err!(
tcx.dcx(),
tcx.def_span(def_id),
E0199,
"implementing the trait `{}` is not unsafe",
trait_ref.print_trait_sugared()
)
.with_span_suggestion_verbose(
item.span.with_hi(item.span.lo() + rustc_span::BytePos(7)),
"remove `unsafe` from this trait implementation",
"",
rustc_errors::Applicability::MachineApplicable,
)
.emit());
}
(Unsafety::Unsafe, _, Unsafety::Normal, hir::ImplPolarity::Positive) => {
return Err(struct_span_code_err!(
tcx.dcx(),
tcx.def_span(def_id),
E0200,
"the trait `{}` requires an `unsafe impl` declaration",
trait_ref.print_trait_sugared()
)
.with_note(format!(
"the trait `{}` enforces invariants that the compiler can't check. \
Review the trait documentation and make sure this implementation \
upholds those invariants before adding the `unsafe` keyword",
trait_ref.print_trait_sugared()
))
.with_span_suggestion_verbose(
item.span.shrink_to_lo(),
"add `unsafe` to this trait implementation",
"unsafe ",
rustc_errors::Applicability::MaybeIncorrect,
)
.emit());
}
(Unsafety::Normal, Some(attr_name), Unsafety::Normal, hir::ImplPolarity::Positive) => {
return Err(struct_span_code_err!(
tcx.dcx(),
tcx.def_span(def_id),
E0569,
"requires an `unsafe impl` declaration due to `#[{}]` attribute",
attr_name
)
.with_note(format!(
"the trait `{}` enforces invariants that the compiler can't check. \
Review the trait documentation and make sure this implementation \
upholds those invariants before adding the `unsafe` keyword",
trait_ref.print_trait_sugared()
))
.with_span_suggestion_verbose(
item.span.shrink_to_lo(),
"add `unsafe` to this trait implementation",
"unsafe ",
rustc_errors::Applicability::MaybeIncorrect,
)
.emit());
}
(_, _, Unsafety::Unsafe, hir::ImplPolarity::Negative(_)) => {
// Reported in AST validation
tcx.dcx().span_delayed_bug(item.span, "unsafe negative impl");
Ok(())
}
(_, _, Unsafety::Normal, hir::ImplPolarity::Negative(_))
| (Unsafety::Unsafe, _, Unsafety::Unsafe, hir::ImplPolarity::Positive)
| (Unsafety::Normal, Some(_), Unsafety::Unsafe, hir::ImplPolarity::Positive)
| (Unsafety::Normal, None, Unsafety::Normal, _) => Ok(()),
}
Ok(())
}

View file

@ -224,11 +224,8 @@ pub(crate) fn placeholder_type_error_diag<'tcx>(
is_fn = true;
// 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!(
parent_node,
tcx.parent_hir_node(hir_ty.hir_id),
Node::Item(&hir::Item {
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, .. }) => {
// 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()
{
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.
None
} 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
&& 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())
}
} else {
let parent_node = tcx.hir().get_parent(hir_id);
let parent_node = tcx.parent_hir_node(hir_id);
match parent_node {
// HACK(eddyb) this provides the correct generics for repeat
// 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
// and the duplicated parameter, to ensure that they do not get out of sync.
if let Node::Item(&Item { kind: ItemKind::OpaqueTy(..), .. }) = node {
let opaque_ty_id = tcx.hir().parent_id(hir_id);
let opaque_ty_node = tcx.hir_node(opaque_ty_id);
let opaque_ty_node = tcx.parent_hir_node(hir_id);
let Node::Ty(&Ty { kind: TyKind::OpaqueDef(_, lifetimes, _), .. }) = opaque_ty_node else {
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 hir_id = self.tcx.local_def_id_to_hir_id(def_id);
// 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() {
struct_span_code_err!(
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 (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, .. })
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 {
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
// 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(
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,
);
if let Some(parent_node) = self.tcx.hir().opt_parent_id(self.path_segment.hir_id)
&& let hir::Node::Expr(expr) = self.tcx.hir_node(parent_node)
{
if let hir::Node::Expr(expr) = self.tcx.parent_hir_node(self.path_segment.hir_id) {
match &expr.kind {
hir::ExprKind::Path(qpath) => self
.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,
// 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 cause = self.cause(if_span, ObligationCauseCode::IfExpressionWithNoElse);
let mut error = false;
@ -396,7 +396,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let node = self.tcx.hir_node(hir_id);
if let hir::Node::Block(block) = node {
// 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(..), .. })) =
(&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 {
kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }),
..
}) = hir.get_parent(hir_id)
}) = self.tcx.parent_hir_node(hir_id)
{
fn_decl_span
} 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
// the _real_ closure...
let async_closure = hir.parent_id(parent_hir_id);
if let hir::Node::Expr(hir::Expr {
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
} else {
@ -415,8 +414,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
call_expr: &'tcx hir::Expr<'tcx>,
callee_expr: &'tcx hir::Expr<'tcx>,
) -> bool {
let hir_id = self.tcx.hir().parent_id(call_expr.hir_id);
let parent_node = self.tcx.hir_node(hir_id);
let parent_node = self.tcx.parent_hir_node(call_expr.hir_id);
if let (
hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Array(_), .. }),
hir::ExprKind::Tup(exp),

View file

@ -186,17 +186,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
let b = self.shallow_resolve(b);
debug!("Coerce.tys({:?} => {:?})", a, b);
// Just ignore error types.
if let Err(guar) = (a, b).error_reported() {
// Best-effort try to unify these types -- we're already on the error path,
// so this will have the side-effect of making sure we have no ambiguities
// due to `[type error]` and `_` not coercing together.
let _ = self.commit_if_ok(|_| {
self.at(&self.cause, self.param_env).eq(DefineOpaqueTypes::Yes, a, b)
});
return success(vec![], Ty::new_error(self.fcx.tcx, guar), vec![]);
}
// Coercing from `!` to any type is allowed:
if a.is_never() {
return success(simple(Adjust::NeverToAny)(b), b, vec![]);
@ -1605,7 +1594,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
err.span_label(cause.span, "return type is not `()`");
}
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(
cause,
expected,
@ -1796,7 +1785,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
) -> DiagnosticBuilder<'a> {
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);
if let Some(expr) = expression
&& 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 {
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 { init: Some(init), .. }) => (init.hir_id, Some(*init)),
_ => return false,
@ -445,7 +445,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
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
&& rcvr.hir_id == binding.hir_id
{
@ -557,7 +557,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let Some(TypeError::Sorts(ExpectedFound { expected, .. })) = error else {
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;
'outer: loop {
// 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;
};
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 {
continue;
};
@ -578,7 +578,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Climb the HIR tree to find the (desugared) `loop` this `break` corresponds to.
let parent = match self.tcx.hir_node(parent_id) {
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
}
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),
..
}) => {
parent_id = self.tcx.hir().parent_id(*hir_id);
parent_id = self.tcx.parent_hir_id(*hir_id);
parent
}
hir::Node::Block(_) => {
parent_id = self.tcx.hir().parent_id(parent_id);
parent_id = self.tcx.parent_hir_id(parent_id);
parent
}
_ => break,
@ -677,8 +677,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr: &hir::Expr<'_>,
error: Option<TypeError<'tcx>>,
) {
let parent = self.tcx.hir().parent_id(expr.hir_id);
match (self.tcx.hir_node(parent), error) {
match (self.tcx.parent_hir_node(expr.hir_id), error) {
(hir::Node::Local(hir::Local { ty: Some(ty), init: Some(init), .. }), _)
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) {
primary_span = pat.span;
secondary_span = pat.span;
match self.tcx.hir().find_parent(pat.hir_id) {
Some(hir::Node::Local(hir::Local { ty: Some(ty), .. })) => {
match self.tcx.parent_hir_node(pat.hir_id) {
hir::Node::Local(hir::Local { ty: Some(ty), .. }) => {
primary_span = ty.span;
post_message = " type";
}
Some(hir::Node::Local(hir::Local { init: Some(init), .. })) => {
hir::Node::Local(hir::Local { init: Some(init), .. }) => {
primary_span = init.span;
post_message = " value";
}
Some(hir::Node::Param(hir::Param { ty_span, .. })) => {
hir::Node::Param(hir::Param { ty_span, .. }) => {
primary_span = *ty_span;
post_message = " parameter type";
}
@ -787,12 +786,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr: &hir::Expr<'_>,
error: Option<TypeError<'tcx>>,
) {
let parent = self.tcx.hir().parent_id(expr.hir_id);
let Some(TypeError::Sorts(ExpectedFound { expected, .. })) = error else {
return;
};
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 {
return;
};
@ -1017,7 +1015,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
)) = expr.kind
{
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 {
kind: hir::PatKind::Binding(_, _hir_id, _, _), ..
}) = bind
@ -1088,7 +1086,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr: &hir::Expr<'_>,
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;
};
enum CallableKind {

View file

@ -1016,7 +1016,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
original_expr_id: HirId,
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 {
let node = self.tcx.hir_node(parent);
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
let expr_is_ancestor = std::iter::successors(Some(original_expr_id), |id| {
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) {`,
// Check if our original expression is a child of the condition of a while loop.
// If it is, then we have a situation like `while Some(0) = value.get(0) {`,
// 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);
}
break;
@ -1056,7 +1051,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
| hir::Node::TraitItem(_)
| 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(_))
{
// 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 { .. }, .. }) =
hir.get_parent(hir.parent_id(expr.hir_id))
self.tcx.parent_hir_node(expr.hir_id)
{
err.span_suggestion_verbose(
expr.span.shrink_to_lo(),
@ -2645,7 +2639,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.span_label(field.span, "method, not a field");
let expr_is_call =
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
} else {

View file

@ -764,7 +764,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let code = match lang_item {
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
{
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)),
Node::Expr(&hir::Expr { hir_id, kind: hir::ExprKind::Closure(..), .. })
if let Some(Node::Item(&hir::Item {
if let Node::Item(&hir::Item {
ident,
kind: hir::ItemKind::Fn(ref sig, ..),
owner_id,
..
})) = self.tcx.hir().find_parent(hir_id) =>
}) = self.tcx.parent_hir_node(hir_id) =>
{
Some((
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 {
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 {
hir::ExprKind::Assign(lhs, ..) | hir::ExprKind::AssignOp(_, lhs, ..) => {
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);
}
let hir = self.tcx.hir();
let (expr, qpath) = match self.tcx.hir_node(hir_id) {
hir::Node::Expr(expr) => {
if self.closure_span_overlaps_error(error, expr.span) {
@ -122,7 +121,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
hir_id: call_hir_id,
span: call_span,
..
}) = hir.get_parent(hir_id)
}) = self.tcx.parent_hir_node(hir_id)
&& callee.hir_id == hir_id
{
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
// is and we were expecting a Box, ergo Pin<Box<expected>>, we
// can suggest Box::pin.
let parent = self.tcx.hir().parent_id(expr.hir_id);
let Node::Expr(Expr { kind: ExprKind::Call(fn_name, _), .. }) =
self.tcx.hir_node(parent)
self.tcx.parent_hir_node(expr.hir_id)
else {
return false;
};
@ -1687,7 +1686,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return expr;
};
match self.tcx.hir_node(self.tcx.hir().parent_id(*hir_id)) {
match self.tcx.parent_hir_node(*hir_id) {
// foo.clone()
hir::Node::Local(hir::Local { init: Some(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), .. }) =
self.tcx.hir_node(self.tcx.hir().parent_id(*pat_hir_id))
self.tcx.parent_hir_node(*pat_hir_id)
else {
return expr;
};
@ -1733,7 +1732,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
call_expr_path
&& let hir::Node::Pat(hir::Pat { hir_id, .. }) = self.tcx.hir_node(*binding)
&& 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 {
kind: hir::ExprKind::Closure(hir::Closure { body: body_id, .. }),
..
@ -1899,8 +1898,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) -> bool {
let map = self.tcx.hir();
let returned = matches!(
map.find_parent(expr.hir_id),
Some(hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Ret(_), .. }))
self.tcx.parent_hir_node(expr.hir_id),
hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Ret(_), .. })
) || map.get_return_block(expr.hir_id).is_some();
if returned
&& 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.
loop {
parent = self.tcx.hir().parent_id(id);
parent = self.tcx.parent_hir_id(id);
let parent_span = self.tcx.hir().span(parent);
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
@ -2211,24 +2210,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return None;
};
let local_parent = self.tcx.hir().parent_id(local_id);
let Node::Param(hir::Param { hir_id: param_hir_id, .. }) = self.tcx.hir_node(local_parent)
let Node::Param(hir::Param { hir_id: param_hir_id, .. }) =
self.tcx.parent_hir_node(local_id)
else {
return None;
};
let param_parent = self.tcx.hir().parent_id(*param_hir_id);
let Node::Expr(hir::Expr {
hir_id: expr_hir_id,
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 {
return None;
};
let expr_parent = self.tcx.hir().parent_id(*expr_hir_id);
let hir = self.tcx.hir_node(expr_parent);
let hir = self.tcx.parent_hir_node(*expr_hir_id);
let closure_params_len = closure_fn_decl.inputs.len();
let (
Node::Expr(hir::Expr {
@ -2409,10 +2406,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
None => String::new(),
};
if let Some(hir::Node::Expr(hir::Expr {
kind: hir::ExprKind::Assign(..),
..
})) = self.tcx.hir().find_parent(expr.hir_id)
if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Assign(..), .. }) =
self.tcx.parent_hir_node(expr.hir_id)
{
if mutability.is_mut() {
// 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`
if let Some(hir::Node::Expr(hir::Expr {
if let hir::Node::Expr(hir::Expr {
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 (sugg, verbose) = make_sugg(lhs, lhs.span, "*");
@ -2602,7 +2597,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|| (checked_ty.is_box() && steps == 1)
// We can always deref a binop that takes its arguments by ref.
|| 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, ..), .. })
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`.
fn is_else_if_block(&self, expr: &hir::Expr<'_>) -> bool {
if let hir::ExprKind::If(..) = expr.kind {
let parent_id = self.tcx.hir().parent_id(expr.hir_id);
if let Node::Expr(hir::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;
}
@ -2704,7 +2698,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
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
if field.is_shorthand {
// This is a field literal
@ -3056,8 +3050,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
else {
return;
};
let parent = self.tcx.hir().parent_id(expr.hir_id);
if let hir::Node::ExprField(_) = self.tcx.hir_node(parent) {
if let hir::Node::ExprField(_) = self.tcx.parent_hir_node(expr.hir_id) {
// Ignore `Foo { field: a..Default::default() }`
return;
}
@ -3139,8 +3132,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let hir::Node::Pat(pat) = self.tcx.hir_node(hir_id) else {
return;
};
let Some(hir::Node::Local(hir::Local { ty: None, init: Some(init), .. })) =
self.tcx.hir().find_parent(pat.hir_id)
let hir::Node::Local(hir::Local { ty: None, init: Some(init), .. }) =
self.tcx.parent_hir_node(pat.hir_id)
else {
return;
};

View file

@ -220,7 +220,7 @@ fn typeck_with_fallback<'tcx>(
span,
}))
} 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), .. })
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 {
// 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 {
span
};
@ -231,9 +231,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = kind
&& let hir::def::Res::Local(hir_id) = path.res
&& 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 Some(node) = self.tcx.hir().find_parent(p.hir_id)
&& let Some(decl) = node.fn_decl()
&& let hir::Node::Param(p) = self.tcx.parent_hir_node(b.hir_id)
&& let Some(decl) = self.tcx.parent_hir_node(p.hir_id).fn_decl()
&& let Some(ty) = decl.inputs.iter().find(|ty| ty.span == p.ty_span)
&& let hir::TyKind::Ref(_, mut_ty) = &ty.kind
&& let hir::Mutability::Not = mut_ty.mutbl
@ -471,7 +470,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let SelfSource::MethodCall(rcvr_expr) = source {
self.suggest_fn_call(&mut err, rcvr_expr, rcvr_ty, |output_ty| {
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(
item_name,
output_ty,
@ -1020,7 +1019,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
rcvr_ty,
&item_segment,
span,
tcx.hir().get_parent(rcvr_expr.hir_id).expect_expr(),
tcx.parent_hir_node(rcvr_expr.hir_id).expect_expr(),
rcvr_expr,
) {
err.span_note(
@ -1254,7 +1253,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let msg = "remove this method call";
let mut fallback_span = true;
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) {
err.span_suggestion(span, msg, "", Applicability::MachineApplicable);
fallback_span = false;
@ -1753,7 +1752,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Applicability::MachineApplicable,
);
} 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) {
err.span_suggestion(
@ -1937,7 +1936,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let span = tcx.hir().span(hir_id);
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!(
"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 };
visitor.visit_body(body);
let parent = self.tcx.hir().parent_id(seg1.hir_id);
if let Node::Expr(call_expr) = self.tcx.hir_node(parent)
if let Node::Expr(call_expr) = self.tcx.parent_hir_node(seg1.hir_id)
&& let Some(expr) = visitor.result
&& 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
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 never_mention_traits = [
@ -2133,7 +2131,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let SelfSource::MethodCall(expr) = source else {
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 {
return;
@ -3250,8 +3248,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return false;
}
let parent = self.tcx.hir().parent_id(expr.hir_id);
if let Node::Expr(call_expr) = self.tcx.hir_node(parent)
if let Node::Expr(call_expr) = self.tcx.parent_hir_node(expr.hir_id)
&& let hir::ExprKind::MethodCall(
hir::PathSegment { ident: method_name, .. },
self_expr,

View file

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

View file

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

View file

@ -106,7 +106,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
p_def_id.as_local().and_then(|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))
})
});

View file

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

View file

@ -65,10 +65,10 @@ pub fn report_object_safety_error<'tcx>(
&& let hir::TyKind::TraitObject([trait_ref, ..], ..) = ty.kind
{
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;
}
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.
err.span_suggestion_verbose(
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<'_>) {
let map = cx.tcx.hir();
if matches!(map.get_parent(field.hir_id), Node::Variant(_)) {
if matches!(cx.tcx.parent_hir_node(field.hir_id), Node::Variant(_)) {
return;
}
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
&& 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,
}
&& let Some(init) = match parent_node {
@ -977,7 +977,7 @@ impl<'tcx> LateContext<'tcx> {
while let hir::ExprKind::Path(ref qpath) = expr.kind
&& 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),
_ => None,
}

View file

@ -214,8 +214,7 @@ fn is_single_call_in_arm<'tcx>(
drop_expr: &'tcx Expr<'_>,
) -> bool {
if arg.can_have_side_effects() {
let parent_node = cx.tcx.hir().find_parent(drop_expr.hir_id);
if let Some(Node::Arm(Arm { body, .. })) = &parent_node {
if let Node::Arm(Arm { body, .. }) = cx.tcx.parent_hir_node(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 {
TyKind::Path(QPath::Resolved(_, path)) => {
if lint_ty_kind_usage(cx, &path.res) {
let hir = cx.tcx.hir();
let span = match hir.find_parent(ty.hir_id) {
Some(Node::Pat(Pat {
let span = match cx.tcx.parent_hir_node(ty.hir_id) {
Node::Pat(Pat {
kind:
PatKind::Path(qpath)
| PatKind::TupleStruct(qpath, ..)
| PatKind::Struct(qpath, ..),
..
})) => {
}) => {
if let QPath::TypeRelative(qpath_ty, ..) = qpath
&& qpath_ty.hir_id == ty.hir_id
{
@ -161,7 +160,7 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
None
}
}
Some(Node::Expr(Expr { kind: ExprKind::Path(qpath), .. })) => {
Node::Expr(Expr { kind: ExprKind::Path(qpath), .. }) => {
if let QPath::TypeRelative(qpath_ty, ..) = qpath
&& 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 `&`
// 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
&& 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<'_>) {
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 {
// Only check if a new name has been introduced, to avoid warning
// on both the struct definition and this pattern.

View file

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

View file

@ -443,6 +443,7 @@ define_tables! {
asyncness: Table<DefIndex, ty::Asyncness>,
fn_arg_names: Table<DefIndex, LazyArray<Ident>>,
coroutine_kind: Table<DefIndex, hir::CoroutineKind>,
coroutine_for_closure: Table<DefIndex, RawDefId>,
trait_def: Table<DefIndex, LazyValue<ty::TraitDef>>,
trait_item_def_id: Table<DefIndex, RawDefId>,
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.
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 {
self.current_id = CRATE_HIR_ID;
@ -175,6 +175,28 @@ impl<'tcx> TyCtxt<'tcx> {
self.opt_hir_node_by_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> {
@ -217,39 +239,6 @@ impl<'hir> Map<'hir> {
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>> {
id.as_local()
.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`
/// item (possibly associated), a closure, or a `hir::AnonConst`.
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:?}");
parent
}
pub fn body_owner_def_id(self, BodyId { hir_id }: BodyId) -> LocalDefId {
let parent = self.parent_id(hir_id);
associated_body(self.tcx.hir_node(parent)).unwrap().0
associated_body(self.tcx.parent_hir_node(hir_id)).unwrap().0
}
/// 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.
pub fn is_lhs(self, id: HirId) -> bool {
match self.find_parent(id) {
Some(Node::Expr(expr)) => match expr.kind {
match self.tcx.parent_hir_node(id) {
Node::Expr(expr) => match expr.kind {
ExprKind::Assign(lhs, _rhs, _span) => lhs.hir_id == id,
_ => false,
},
@ -793,7 +781,7 @@ impl<'hir> Map<'hir> {
Node::Pat(&Pat { kind: PatKind::Binding(_, _, ident, _), .. }) => Some(ident),
// A `Ctor` doesn't have an identifier itself, but its parent
// 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::Variant(variant) => Some(variant.ident),
_ => unreachable!(),
@ -925,7 +913,7 @@ impl<'hir> Map<'hir> {
ForeignItemKind::Fn(decl, _, _) => until_within(item.span, decl.output.span()),
_ => 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 {
kind: ExprKind::Closure(Closure { fn_decl_span, .. }),
span,
@ -968,7 +956,7 @@ impl<'hir> Map<'hir> {
Node::PatField(field) => field.span,
Node::Arm(arm) => arm.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::GenericParam(param) => param.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
/// called with the HirId for the `{ ... }` anon const
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 {
def_id: param_id,
kind: GenericParamKind::Const { .. },
@ -1026,7 +1014,7 @@ impl<'hir> Map<'hir> {
_ => None,
}?;
match self.find_parent(expr.hir_id)? {
match self.tcx.parent_hir_node(expr.hir_id) {
Node::ExprField(field) => {
if field.ident.name == local.name && field.is_shorthand {
return Some(local.name);

View file

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

View file

@ -356,6 +356,8 @@ pub enum UndefinedBehaviorInfo<'tcx> {
UninhabitedEnumVariantWritten(VariantIdx),
/// An uninhabited enum variant is projected.
UninhabitedEnumVariantRead(VariantIdx),
/// Trying to set discriminant to the niched variant, but the value does not match.
InvalidNichedEnumVariantWritten { enum_ty: Ty<'tcx> },
/// ABI-incompatible argument types.
AbiMismatchArgument { caller_ty: Ty<'tcx>, callee_ty: Ty<'tcx> },
/// ABI-incompatible return types.
@ -468,7 +470,7 @@ pub enum UnsupportedOpInfo {
/// Accessing thread local statics
ThreadLocalStatic(DefId),
/// Accessing an unsupported extern static.
ReadExternStatic(DefId),
ExternStatic(DefId),
}
/// Error information for when the program exhausted the resources granted to it

View file

@ -358,11 +358,17 @@ pub fn suggest_constraining_type_params<'a>(
// trait Foo<T=()> {... }
// - insert: `where T: Zar`
if matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. }) {
// If we are here and the where clause span is of non-zero length
// it means we're dealing with an empty where clause like this:
// fn foo<X>(x: X) where { ... }
// In that case we don't want to add another "where" (Fixes #120838)
let where_prefix = if generics.where_clause_span.is_empty() { " where" } else { "" };
// Suggest a bound, but there is no existing `where` clause *and* the type param has a
// default (`<T=Foo>`), so we suggest adding `where T: Bar`.
suggestions.push((
generics.tail_span_for_predicate_suggestion(),
format!(" where {param_name}: {constraint}"),
format!("{where_prefix} {param_name}: {constraint}"),
SuggestChangingConstraintsMessage::RestrictTypeFurther { ty: param_name },
));
continue;

View file

@ -877,7 +877,24 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
ty::CoroutineClosure(did, args) => {
p!(write("{{"));
if !self.should_print_verbose() {
p!(write("coroutine-closure"));
match self.tcx().coroutine_kind(self.tcx().coroutine_for_closure(did)).unwrap()
{
hir::CoroutineKind::Desugared(
hir::CoroutineDesugaring::Async,
hir::CoroutineSource::Closure,
) => p!("async closure"),
hir::CoroutineKind::Desugared(
hir::CoroutineDesugaring::AsyncGen,
hir::CoroutineSource::Closure,
) => p!("async gen closure"),
hir::CoroutineKind::Desugared(
hir::CoroutineDesugaring::Gen,
hir::CoroutineSource::Closure,
) => p!("gen closure"),
_ => unreachable!(
"coroutine from coroutine-closure should have CoroutineSource::Closure"
),
}
// FIXME(eddyb) should use `def_span`.
if let Some(did) = did.as_local() {
if self.tcx().sess.opts.unstable_opts.span_free_formats {

View file

@ -435,7 +435,10 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
Ok(a)
}
(ty::Param(a_p), ty::Param(b_p)) if a_p.index == b_p.index => Ok(a),
(ty::Param(a_p), ty::Param(b_p)) if a_p.index == b_p.index => {
debug_assert_eq!(a_p.name, b_p.name, "param types with same index differ in name");
Ok(a)
}
(ty::Placeholder(p1), ty::Placeholder(p2)) if p1 == p2 => Ok(a),
@ -593,7 +596,10 @@ pub fn structurally_relate_consts<'tcx, R: TypeRelation<'tcx>>(
(ty::ConstKind::Error(_), _) => return Ok(a),
(_, ty::ConstKind::Error(_)) => return Ok(b),
(ty::ConstKind::Param(a_p), ty::ConstKind::Param(b_p)) => a_p.index == b_p.index,
(ty::ConstKind::Param(a_p), ty::ConstKind::Param(b_p)) if a_p.index == b_p.index => {
debug_assert_eq!(a_p.name, b_p.name, "param types with same index differ in name");
true
}
(ty::ConstKind::Placeholder(p1), ty::ConstKind::Placeholder(p2)) => p1 == p2,
(ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => a_val == b_val,

View file

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

View file

@ -2,7 +2,9 @@
//!
//! Currently, this pass only propagates scalar values.
use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, PlaceTy, Projectable};
use rustc_const_eval::interpret::{
ImmTy, Immediate, InterpCx, OpTy, PlaceTy, PointerArithmetic, Projectable,
};
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def::DefKind;
use rustc_middle::mir::interpret::{AllocId, ConstAllocation, InterpResult, Scalar};
@ -936,12 +938,50 @@ impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for Dumm
}
fn binary_ptr_op(
_ecx: &InterpCx<'mir, 'tcx, Self>,
_bin_op: BinOp,
_left: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>,
_right: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>,
ecx: &InterpCx<'mir, 'tcx, Self>,
bin_op: BinOp,
left: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>,
right: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>,
) -> interpret::InterpResult<'tcx, (ImmTy<'tcx, Self::Provenance>, bool)> {
throw_machine_stop_str!("can't do pointer arithmetic");
use rustc_middle::mir::BinOp::*;
Ok(match bin_op {
Eq | Ne | Lt | Le | Gt | Ge => {
// Types can differ, e.g. fn ptrs with different `for`.
assert_eq!(left.layout.abi, right.layout.abi);
let size = ecx.pointer_size();
// Just compare the bits. ScalarPairs are compared lexicographically.
// We thus always compare pairs and simply fill scalars up with 0.
// If the pointer has provenance, `to_bits` will return `Err` and we bail out.
let left = match **left {
Immediate::Scalar(l) => (l.to_bits(size)?, 0),
Immediate::ScalarPair(l1, l2) => (l1.to_bits(size)?, l2.to_bits(size)?),
Immediate::Uninit => panic!("we should never see uninit data here"),
};
let right = match **right {
Immediate::Scalar(r) => (r.to_bits(size)?, 0),
Immediate::ScalarPair(r1, r2) => (r1.to_bits(size)?, r2.to_bits(size)?),
Immediate::Uninit => panic!("we should never see uninit data here"),
};
let res = match bin_op {
Eq => left == right,
Ne => left != right,
Lt => left < right,
Le => left <= right,
Gt => left > right,
Ge => left >= right,
_ => bug!(),
};
(ImmTy::from_bool(res, *ecx.tcx), false)
}
// Some more operations are possible with atomics.
// The return value always has the provenance of the *left* operand.
Add | Sub | BitOr | BitAnd | BitXor => {
throw_machine_stop_str!("pointer arithmetic is not handled")
}
_ => span_bug!(ecx.cur_span(), "Invalid operator on pointers: {:?}", bin_op),
})
}
fn expose_ptr(

View file

@ -93,7 +93,6 @@ use rustc_index::IndexVec;
use rustc_middle::mir::interpret::GlobalAlloc;
use rustc_middle::mir::visit::*;
use rustc_middle::mir::*;
use rustc_middle::ty::adjustment::PointerCoercion;
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeAndMut};
use rustc_span::def_id::DefId;
@ -552,6 +551,29 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
}
value.offset(Size::ZERO, to, &self.ecx).ok()?
}
CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize) => {
let src = self.evaluated[value].as_ref()?;
let to = self.ecx.layout_of(to).ok()?;
let dest = self.ecx.allocate(to, MemoryKind::Stack).ok()?;
self.ecx.unsize_into(src, to, &dest.clone().into()).ok()?;
self.ecx
.alloc_mark_immutable(dest.ptr().provenance.unwrap().alloc_id())
.ok()?;
dest.into()
}
CastKind::FnPtrToPtr
| CastKind::PtrToPtr
| CastKind::PointerCoercion(
ty::adjustment::PointerCoercion::MutToConstPointer
| ty::adjustment::PointerCoercion::ArrayToPointer
| ty::adjustment::PointerCoercion::UnsafeFnPointer,
) => {
let src = self.evaluated[value].as_ref()?;
let src = self.ecx.read_immediate(src).ok()?;
let to = self.ecx.layout_of(to).ok()?;
let ret = self.ecx.ptr_to_ptr(&src, to).ok()?;
ret.into()
}
_ => return None,
},
};
@ -778,18 +800,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
// Operations.
Rvalue::Len(ref mut place) => return self.simplify_len(place, location),
Rvalue::Cast(kind, ref mut value, to) => {
let from = value.ty(self.local_decls, self.tcx);
let value = self.simplify_operand(value, location)?;
if let CastKind::PointerCoercion(
PointerCoercion::ReifyFnPointer | PointerCoercion::ClosureFnPointer(_),
) = kind
{
// Each reification of a generic fn may get a different pointer.
// Do not try to merge them.
return self.new_opaque();
}
Value::Cast { kind, value, from, to }
Rvalue::Cast(ref mut kind, ref mut value, to) => {
return self.simplify_cast(kind, value, to, location);
}
Rvalue::BinaryOp(op, box (ref mut lhs, ref mut rhs)) => {
let ty = lhs.ty(self.local_decls, self.tcx);
@ -1035,6 +1047,50 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
}
}
fn simplify_cast(
&mut self,
kind: &mut CastKind,
operand: &mut Operand<'tcx>,
to: Ty<'tcx>,
location: Location,
) -> Option<VnIndex> {
use rustc_middle::ty::adjustment::PointerCoercion::*;
use CastKind::*;
let mut from = operand.ty(self.local_decls, self.tcx);
let mut value = self.simplify_operand(operand, location)?;
if from == to {
return Some(value);
}
if let CastKind::PointerCoercion(ReifyFnPointer | ClosureFnPointer(_)) = kind {
// Each reification of a generic fn may get a different pointer.
// Do not try to merge them.
return self.new_opaque();
}
if let PtrToPtr | PointerCoercion(MutToConstPointer) = kind
&& let Value::Cast { kind: inner_kind, value: inner_value, from: inner_from, to: _ } =
*self.get(value)
&& let PtrToPtr | PointerCoercion(MutToConstPointer) = inner_kind
{
from = inner_from;
value = inner_value;
*kind = PtrToPtr;
if inner_from == to {
return Some(inner_value);
}
if let Some(const_) = self.try_as_constant(value) {
*operand = Operand::Constant(Box::new(const_));
} else if let Some(local) = self.try_as_local(value, location) {
*operand = Operand::Copy(local.into());
self.reused_locals.insert(local);
}
}
Some(self.insert(Value::Cast { kind: *kind, value, from, to }))
}
fn simplify_len(&mut self, place: &mut Place<'tcx>, location: Location) -> Option<VnIndex> {
// Trivial case: we are fetching a statically known length.
let place_ty = place.ty(self.local_decls, self.tcx).ty;

View file

@ -447,16 +447,13 @@ fn build_thread_local_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'t
fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Body<'tcx> {
debug!("build_clone_shim(def_id={:?})", def_id);
let param_env = tcx.param_env_reveal_all_normalized(def_id);
let mut builder = CloneShimBuilder::new(tcx, def_id, self_ty);
let is_copy = self_ty.is_copy_modulo_regions(tcx, param_env);
let dest = Place::return_place();
let src = tcx.mk_place_deref(Place::from(Local::new(1 + 0)));
match self_ty.kind() {
_ if is_copy => builder.copy_shim(),
ty::FnDef(..) | ty::FnPtr(_) => builder.copy_shim(),
ty::Closure(_, args) => builder.tuple_like_shim(dest, src, args.as_closure().upvar_tys()),
ty::Tuple(..) => builder.tuple_like_shim(dest, src, self_ty.tuple_fields()),
ty::Coroutine(coroutine_def_id, args) => {

View file

@ -666,7 +666,15 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
debug!(?def_id, ?fn_span);
for arg in args {
if let Some(too_large_size) = self.operand_size_if_too_large(limit, &arg.node) {
// Moving args into functions is typically implemented with pointer
// passing at the llvm-ir level and not by memcpy's. So always allow
// moving args into functions.
let operand: &mir::Operand<'tcx> = &arg.node;
if let mir::Operand::Move(_) = operand {
continue;
}
if let Some(too_large_size) = self.operand_size_if_too_large(limit, operand) {
self.lint_large_assignment(limit.0, too_large_size, location, arg.span);
};
}

View file

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

View file

@ -625,6 +625,13 @@ impl Span {
span.lo < other.hi && other.lo < span.hi
}
/// Returns `true` if `self` touches or adjoins `other`.
pub fn overlaps_or_adjacent(self, other: Span) -> bool {
let span = self.data();
let other = other.data();
span.lo <= other.hi && other.lo <= span.hi
}
/// Returns `true` if the spans are equal with regards to the source text.
///
/// Use this instead of `==` when either span could be generated code,

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()?);
match hir.find_parent(hir_id) {
Some(hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(local), .. })) => {
match self.tcx.parent_hir_node(hir_id) {
hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(local), .. }) => {
get_name(err, &local.pat.kind)
}
// Different to previous arm because one is `&hir::Local` and the other
// 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,
}
}
@ -1202,8 +1201,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let hir::Node::Pat(pat) = self.tcx.hir_node(hir_id) else {
return;
};
let Some(hir::Node::Local(hir::Local { ty: None, init: Some(init), .. })) =
self.tcx.hir().find_parent(pat.hir_id)
let hir::Node::Local(hir::Local { ty: None, init: Some(init), .. }) =
self.tcx.parent_hir_node(pat.hir_id)
else {
return;
};
@ -1790,7 +1789,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
&& let Res::Local(hir_id) = path.res
&& 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 Some(binding_expr) = local.init
{
@ -3188,8 +3187,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
}
ObligationCauseCode::VariableType(hir_id) => {
let parent_node = tcx.hir().parent_id(hir_id);
match tcx.hir_node(parent_node) {
match tcx.parent_hir_node(hir_id) {
Node::Local(hir::Local { ty: Some(ty), .. }) => {
err.span_suggestion_verbose(
ty.span.shrink_to_lo(),
@ -3237,8 +3235,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
types always have a known size";
if let Some(hir_id) = 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) = item.fn_decl()
&& let Some(decl) = self.tcx.parent_hir_node(hir_id).fn_decl()
&& 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,
@ -4079,8 +4076,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
&& let hir::Path { res: Res::Local(hir_id), .. } = path
&& 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.hir_node(parent_hir_id)
&& let hir::Node::Local(local) = self.tcx.parent_hir_node(binding.hir_id)
&& let Some(binding_expr) = local.init
{
// 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
&& let hir::Path { res: Res::Local(hir_id), .. } = path
&& 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...
if let hir::Node::Local(local) = parent
&& 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
&& let hir::Path { res: hir::def::Res::Local(hir_id), .. } = path
&& 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...
if let hir::Node::Local(local) = parent
&& let Some(binding_expr) = local.init

View file

@ -209,10 +209,8 @@ fn resolve_associated_item<'tcx>(
let name = tcx.item_name(trait_item_id);
if name == sym::clone {
let self_ty = trait_ref.self_ty();
let is_copy = self_ty.is_copy_modulo_regions(tcx, param_env);
match self_ty.kind() {
_ if is_copy => (),
ty::FnDef(..) | ty::FnPtr(_) => (),
ty::Coroutine(..)
| ty::CoroutineWitness(..)
| ty::Closure(..)

View file

@ -67,6 +67,26 @@ impl<T> ThinBox<T> {
let ptr = WithOpaqueHeader::new(meta, value);
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")]
@ -179,6 +199,10 @@ impl WithOpaqueHeader {
let ptr = WithHeader::new(header, value);
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> {
@ -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:
// - Assumes that either `value` can be dereferenced, or is the
// `NonNull::dangling()` we use when both `T` and `H` are ZSTs.

View file

@ -188,6 +188,10 @@
//! * `#X` - precedes the argument with a `0x`
//! * `#b` - precedes the argument with a `0b`
//! * `#o` - precedes the argument with a `0o`
//!
//! See [Formatting traits](#formatting-traits) for a description of what the `?`, `x`, `X`,
//! `b`, and `o` flags do.
//!
//! * `0` - This is used to indicate for integer formats that the padding to `width` should
//! both be done with a `0` character as well as be sign-aware. A format
//! like `{:08}` would yield `00000001` for the integer `1`, while the
@ -197,6 +201,7 @@
//! and before the digits. When used together with the `#` flag, a similar
//! rule applies: padding zeros are inserted after the prefix but before
//! the digits. The prefix is included in the total width.
//! This flag overrides the [fill character and alignment flag](#fillalignment).
//!
//! ## Precision
//!

View file

@ -237,9 +237,9 @@
use crate::cmp::Ordering;
use crate::fmt::{self, Debug, Display};
use crate::intrinsics::is_nonoverlapping;
use crate::intrinsics;
use crate::marker::{PhantomData, Unsize};
use crate::mem;
use crate::mem::{self, size_of};
use crate::ops::{CoerceUnsized, Deref, DerefMut, DispatchFromDyn};
use crate::ptr::{self, NonNull};
@ -435,11 +435,15 @@ impl<T> Cell<T> {
#[inline]
#[stable(feature = "move_cell", since = "1.17.0")]
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) {
// Swapping wouldn't change anything.
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.
panic!("`Cell::swap` on overlapping non-identical `Cell`s");
}

View file

@ -88,6 +88,7 @@ use crate::str;
// want `repr(transparent)` but we don't want it to show up in rustdoc, so we hide it under
// `cfg(doc)`. This is an ad-hoc implementation of attribute privacy.
#[cfg_attr(not(doc), repr(transparent))]
#[allow(clippy::derived_hash_with_manual_eq)]
pub struct CStr {
// FIXME: this should not be represented with a DST slice but rather with
// just a raw `c_char` along with some form of marker to make

View file

@ -56,7 +56,7 @@
use crate::marker::DiscriminantKind;
use crate::marker::Tuple;
use crate::mem::{self, align_of};
use crate::mem::align_of;
pub mod mir;
pub mod simd;
@ -1027,7 +1027,7 @@ extern "rust-intrinsic" {
/// 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_nounwind]
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.
///
/// This exists solely for [`mem::forget_unsized`]; normal `forget` uses
/// This exists solely for [`crate::mem::forget_unsized`]; normal `forget` uses
/// `ManuallyDrop` instead.
///
/// 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
/// pointer-to-integer transmutation:
/// - 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`
/// casts or [`ptr.addr()`][pointer::addr].
///
@ -2317,7 +2317,7 @@ extern "rust-intrinsic" {
/// Therefore, implementations must not require the user to uphold
/// 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_safe_intrinsic]
#[rustc_nounwind]
@ -2569,6 +2569,19 @@ extern "rust-intrinsic" {
#[rustc_nounwind]
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_safe_intrinsic]
#[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
/// [`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
/// 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.
///
/// 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
/// minimal impact on the caller's code size.
///
/// Caller should also introducing any other `let` bindings or any code outside this macro in order
/// to call it. Since the precompiled standard library is built with full debuginfo and these
/// Callers should also avoid introducing any other `let` bindings or any code outside this macro in
/// 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
/// 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
}
pub(crate) fn is_nonoverlapping_mono(
src: *const (),
dst: *const (),
size: usize,
count: usize,
) -> bool {
/// Checks whether the regions of memory starting at `src` and `dst` of size
/// `count * size` do *not* overlap.
pub(crate) fn is_nonoverlapping(src: *const (), dst: *const (), size: usize, count: usize) -> bool {
let src_usize = src.addr();
let dst_usize = dst.addr();
let Some(size) = size.checked_mul(count) else {
@ -2678,24 +2688,6 @@ pub(crate) fn is_nonoverlapping_mono(
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
/// 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(dst, align)
&& is_nonoverlapping_mono(src, dst, size, count)
&& is_nonoverlapping(src, dst, size, count)
);
copy_nonoverlapping(src, dst, count)
}

View file

@ -190,14 +190,27 @@ extern "platform-intrinsic" {
///
/// `T` must be a vector.
///
/// `U` must be a const array of `i32`s.
/// `U` must be a **const** array of `i32`s. This means it must either refer to a named
/// const or be given as an inline const expression (`const { ... }`).
///
/// `V` must be a vector with the same element type as `T` and the same length as `U`.
///
/// Concatenates `x` and `y`, then returns a new vector such that each element is selected from
/// the concatenation by the matching index in `idx`.
/// Returns a new vector such that element `i` is selected from `xy[idx[i]]`, where `xy`
/// is the concatenation of `x` and `y`. It is a compile-time error if `idx[i]` is out-of-bounds
/// of `xy`.
pub fn simd_shuffle<T, U, V>(x: T, y: T, idx: U) -> V;
/// Shuffle two vectors by const indices.
///
/// `T` must be a vector.
///
/// `U` must be a vector with the same element type as `T` and the same length as `IDX`.
///
/// Returns a new vector such that element `i` is selected from `xy[IDX[i]]`, where `xy`
/// is the concatenation of `x` and `y`. It is a compile-time error if `IDX[i]` is out-of-bounds
/// of `xy`.
pub fn simd_shuffle_generic<T, U, const IDX: &'static [u32]>(x: T, y: T) -> U;
/// Read a vector of pointers.
///
/// `T` must be a vector.
@ -232,6 +245,9 @@ extern "platform-intrinsic" {
/// corresponding value in `val` to the pointer.
/// Otherwise if the corresponding value in `mask` is `0`, do nothing.
///
/// The stores happen in left-to-right order.
/// (This is relevant in case two of the stores overlap.)
///
/// # Safety
/// Unmasked values in `T` must be writeable as if by `<ptr>::write` (e.g. aligned to the element
/// type).
@ -468,4 +484,36 @@ extern "platform-intrinsic" {
///
/// `T` must be a vector of integers.
pub fn simd_cttz<T>(x: T) -> T;
/// Round up each element to the next highest integer-valued float.
///
/// `T` must be a vector of floats.
pub fn simd_ceil<T>(x: T) -> T;
/// Round down each element to the next lowest integer-valued float.
///
/// `T` must be a vector of floats.
pub fn simd_floor<T>(x: T) -> T;
/// Round each element to the closest integer-valued float.
/// Ties are resolved by rounding away from 0.
///
/// `T` must be a vector of floats.
pub fn simd_round<T>(x: T) -> T;
/// Return the integer part of each element as an integer-valued float.
/// In other words, non-integer values are truncated towards zero.
///
/// `T` must be a vector of floats.
pub fn simd_trunc<T>(x: T) -> T;
/// Takes the square root of each element.
///
/// `T` must be a vector of floats.
pub fn simd_fsqrt<T>(x: T) -> T;
/// Computes `(x*y) + z` for each element, but without any intermediate rounding.
///
/// `T` must be a vector of floats.
pub fn simd_fma<T>(x: T, y: T, z: T) -> T;
}

View file

@ -462,6 +462,7 @@ impl f32 {
/// and target platforms isn't guaranteed.
#[stable(feature = "assoc_int_consts", since = "1.43.0")]
#[rustc_diagnostic_item = "f32_nan"]
#[allow(clippy::eq_op)]
pub const NAN: f32 = 0.0_f32 / 0.0_f32;
/// Infinity (∞).
#[stable(feature = "assoc_int_consts", since = "1.43.0")]
@ -483,6 +484,7 @@ impl f32 {
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
#[inline]
#[allow(clippy::eq_op)] // > if you intended to check if the operand is NaN, use `.is_nan()` instead :)
pub const fn is_nan(self) -> bool {
self != self
}

View file

@ -461,6 +461,7 @@ impl f64 {
/// and target platforms isn't guaranteed.
#[rustc_diagnostic_item = "f64_nan"]
#[stable(feature = "assoc_int_consts", since = "1.43.0")]
#[allow(clippy::eq_op)]
pub const NAN: f64 = 0.0_f64 / 0.0_f64;
/// Infinity (∞).
#[stable(feature = "assoc_int_consts", since = "1.43.0")]
@ -482,6 +483,7 @@ impl f64 {
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
#[inline]
#[allow(clippy::eq_op)] // > if you intended to check if the operand is NaN, use `.is_nan()` instead :)
pub const fn is_nan(self) -> bool {
self != self
}

View file

@ -567,6 +567,7 @@ use crate::{
#[rustc_diagnostic_item = "Option"]
#[lang = "Option"]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(clippy::derived_hash_with_manual_eq)] // PartialEq is specialized
pub enum Option<T> {
/// No value.
#[lang = "None"]

View file

@ -1660,6 +1660,11 @@ mod prim_ref {}
/// * [`UnwindSafe`]
/// * [`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
/// [`Pointer`]: fmt::Pointer
/// [`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
/// (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"]
pub struct DynMetadata<Dyn: ?Sized> {
vtable_ptr: &'static VTable,

View file

@ -376,12 +376,14 @@
//! [Stacked Borrows]: https://plv.mpi-sws.org/rustbelt/stacked-borrows/
#![stable(feature = "rust1", since = "1.0.0")]
// There are many unsafe functions taking pointers that don't dereference them.
#![allow(clippy::not_unsafe_ptr_arg_deref)]
use crate::cmp::Ordering;
use crate::fmt;
use crate::hash;
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;
@ -976,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(y, align)
&& is_nonoverlapping_mono(x, y, size, count)
&& is_nonoverlapping(x, y, size, count)
);
}

View file

@ -161,7 +161,7 @@ pub(super) const fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> {
// first E0 A0 80 last EF BF BF
// excluding surrogates codepoints \u{d800} to \u{dfff}
// ED A0 80 to ED BF BF
// 4-byte encoding is for codepoints \u{1000}0 to \u{10ff}ff
// 4-byte encoding is for codepoints \u{10000} to \u{10ffff}
// first F0 90 80 80 last F4 8F BF BF
//
// Use the UTF-8 syntax from the RFC

View file

@ -216,6 +216,10 @@
#![cfg_attr(not(target_has_atomic_load_store = "8"), allow(dead_code))]
#![cfg_attr(not(target_has_atomic_load_store = "8"), allow(unused_imports))]
#![rustc_diagnostic_item = "atomic_mod"]
// Clippy complains about the pattern of "safe function calling unsafe function taking pointers".
// This happens with AtomicPtr intrinsics but is fine, as the pointers clippy is concerned about
// are just normal values that get loaded/stored, but not dereferenced.
#![allow(clippy::not_unsafe_ptr_arg_deref)]
use self::Ordering::*;

View file

@ -99,6 +99,12 @@ impl RawWaker {
/// [`RawWaker`] implementation. Calling one of the contained functions using
/// 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
/// If the [`RawWaker`] will be used to construct a [`Waker`] then
/// these functions must all be thread-safe (even though [`RawWaker`] is

View file

@ -28,6 +28,14 @@ const NANOS_PER_MILLI: u32 = 1_000_000;
const NANOS_PER_MICRO: u32 = 1_000;
const MILLIS_PER_SEC: u64 = 1_000;
const MICROS_PER_SEC: u64 = 1_000_000;
#[unstable(feature = "duration_units", issue = "120301")]
const SECS_PER_MINUTE: u64 = 60;
#[unstable(feature = "duration_units", issue = "120301")]
const MINS_PER_HOUR: u64 = 60;
#[unstable(feature = "duration_units", issue = "120301")]
const HOURS_PER_DAY: u64 = 24;
#[unstable(feature = "duration_units", issue = "120301")]
const DAYS_PER_WEEK: u64 = 7;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
@ -273,6 +281,11 @@ impl Duration {
/// Creates a new `Duration` from the specified number of nanoseconds.
///
/// Note: Using this on the return value of `as_nanos()` might cause unexpected behavior:
/// `as_nanos()` returns a u128, and can return values that do not fit in u64, e.g. 585 years.
/// Instead, consider using the pattern `Duration::new(d.as_secs(), d.subsec_nanos())`
/// if you cannot copy/clone the Duration directly.
///
/// # Examples
///
/// ```
@ -291,6 +304,118 @@ impl Duration {
Duration::new(nanos / (NANOS_PER_SEC as u64), (nanos % (NANOS_PER_SEC as u64)) as u32)
}
/// Creates a new `Duration` from the specified number of weeks.
///
/// # Panics
///
/// Panics if the given number of weeks overflows the `Duration` size.
///
/// # Examples
///
/// ```
/// #![feature(duration_constructors)]
/// use std::time::Duration;
///
/// let duration = Duration::from_weeks(4);
///
/// assert_eq!(4 * 7 * 24 * 60 * 60, duration.as_secs());
/// assert_eq!(0, duration.subsec_nanos());
/// ```
#[unstable(feature = "duration_constructors", issue = "120301")]
#[must_use]
#[inline]
pub const fn from_weeks(weeks: u64) -> Duration {
if weeks > u64::MAX / (SECS_PER_MINUTE * MINS_PER_HOUR * HOURS_PER_DAY * DAYS_PER_WEEK) {
panic!("overflow in Duration::from_days");
}
Duration::from_secs(weeks * MINS_PER_HOUR * SECS_PER_MINUTE * HOURS_PER_DAY * DAYS_PER_WEEK)
}
/// Creates a new `Duration` from the specified number of days.
///
/// # Panics
///
/// Panics if the given number of days overflows the `Duration` size.
///
/// # Examples
///
/// ```
/// #![feature(duration_constructors)]
/// use std::time::Duration;
///
/// let duration = Duration::from_days(7);
///
/// assert_eq!(7 * 24 * 60 * 60, duration.as_secs());
/// assert_eq!(0, duration.subsec_nanos());
/// ```
#[unstable(feature = "duration_constructors", issue = "120301")]
#[must_use]
#[inline]
pub const fn from_days(days: u64) -> Duration {
if days > u64::MAX / (SECS_PER_MINUTE * MINS_PER_HOUR * HOURS_PER_DAY) {
panic!("overflow in Duration::from_days");
}
Duration::from_secs(days * MINS_PER_HOUR * SECS_PER_MINUTE * HOURS_PER_DAY)
}
/// Creates a new `Duration` from the specified number of hours.
///
/// # Panics
///
/// Panics if the given number of hours overflows the `Duration` size.
///
/// # Examples
///
/// ```
/// #![feature(duration_constructors)]
/// use std::time::Duration;
///
/// let duration = Duration::from_hours(6);
///
/// assert_eq!(6 * 60 * 60, duration.as_secs());
/// assert_eq!(0, duration.subsec_nanos());
/// ```
#[unstable(feature = "duration_constructors", issue = "120301")]
#[must_use]
#[inline]
pub const fn from_hours(hours: u64) -> Duration {
if hours > u64::MAX / (SECS_PER_MINUTE * MINS_PER_HOUR) {
panic!("overflow in Duration::from_hours");
}
Duration::from_secs(hours * MINS_PER_HOUR * SECS_PER_MINUTE)
}
/// Creates a new `Duration` from the specified number of minutes.
///
/// # Panics
///
/// Panics if the given number of minutes overflows the `Duration` size.
///
/// # Examples
///
/// ```
/// #![feature(duration_constructors)]
/// use std::time::Duration;
///
/// let duration = Duration::from_mins(10);
///
/// assert_eq!(10 * 60, duration.as_secs());
/// assert_eq!(0, duration.subsec_nanos());
/// ```
#[unstable(feature = "duration_constructors", issue = "120301")]
#[must_use]
#[inline]
pub const fn from_mins(mins: u64) -> Duration {
if mins > u64::MAX / SECS_PER_MINUTE {
panic!("overflow in Duration::from_mins");
}
Duration::from_secs(mins * SECS_PER_MINUTE)
}
/// Returns true if this `Duration` spans no time.
///
/// # Examples

View file

@ -154,18 +154,6 @@ macro_rules! maybe_tuple_doc {
};
}
#[inline]
const fn ordering_is_some(c: Option<Ordering>, x: Ordering) -> bool {
// FIXME: Just use `==` once that's const-stable on `Option`s.
// This is mapping `None` to 2 and then doing the comparison afterwards
// because it optimizes better (`None::<Ordering>` is represented as 2).
x as i8
== match c {
Some(c) => c as i8,
None => 2,
}
}
// Constructs an expression that performs a lexical ordering using method `$rel`.
// The values are interleaved, so the macro invocation for
// `(a1, a2, a3) < (b1, b2, b3)` would be `lexical_ord!(lt, opt_is_lt, a1, b1,
@ -176,7 +164,7 @@ const fn ordering_is_some(c: Option<Ordering>, x: Ordering) -> bool {
macro_rules! lexical_ord {
($rel: ident, $ne_rel: ident, $a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {{
let c = PartialOrd::partial_cmp(&$a, &$b);
if !ordering_is_some(c, Equal) { ordering_is_some(c, $ne_rel) }
if c != Some(Equal) { c == Some($ne_rel) }
else { lexical_ord!($rel, $ne_rel, $($rest_a, $rest_b),+) }
}};
($rel: ident, $ne_rel: ident, $a:expr, $b:expr) => {

View file

@ -32,6 +32,7 @@
#![feature(duration_abs_diff)]
#![feature(duration_consts_float)]
#![feature(duration_constants)]
#![feature(duration_constructors)]
#![feature(exact_size_is_empty)]
#![feature(extern_types)]
#![feature(flt2dec)]

View file

@ -17,6 +17,49 @@ fn new_overflow() {
let _ = Duration::new(u64::MAX, 1_000_000_000);
}
#[test]
#[should_panic]
fn from_mins_overflow() {
let overflow = u64::MAX / 60 + 1;
let _ = Duration::from_mins(overflow);
}
#[test]
#[should_panic]
fn from_hours_overflow() {
let overflow = u64::MAX / (60 * 60) + 1;
let _ = Duration::from_hours(overflow);
}
#[test]
#[should_panic]
fn from_days_overflow() {
let overflow = u64::MAX / (24 * 60 * 60) + 1;
let _ = Duration::from_days(overflow);
}
#[test]
#[should_panic]
fn from_weeks_overflow() {
let overflow = u64::MAX / (7 * 24 * 60 * 60) + 1;
let _ = Duration::from_weeks(overflow);
}
#[test]
fn constructors() {
assert_eq!(Duration::from_weeks(1), Duration::from_secs(7 * 24 * 60 * 60));
assert_eq!(Duration::from_weeks(0), Duration::ZERO);
assert_eq!(Duration::from_days(1), Duration::from_secs(86_400));
assert_eq!(Duration::from_days(0), Duration::ZERO);
assert_eq!(Duration::from_hours(1), Duration::from_secs(3_600));
assert_eq!(Duration::from_hours(0), Duration::ZERO);
assert_eq!(Duration::from_mins(1), Duration::from_secs(60));
assert_eq!(Duration::from_mins(0), Duration::ZERO);
}
#[test]
fn secs() {
assert_eq!(Duration::new(0, 0).as_secs(), 0);

View file

@ -102,6 +102,7 @@ impl Arena {
}
}
#[allow(clippy::mut_from_ref)] // arena allocator
pub(crate) fn alloc_str<'a>(&'a self, string: &str) -> &'a mut str {
let alloc = self.alloc_raw(string.len());
let bytes = MaybeUninit::write_slice(alloc, string.as_bytes());

View file

@ -201,6 +201,7 @@ impl ToString for TokenStream {
/// `TokenTree::Punct`, or `TokenTree::Literal`.
#[stable(feature = "proc_macro_lib", since = "1.15.0")]
impl fmt::Display for TokenStream {
#[allow(clippy::recursive_format_impl)] // clippy doesn't see the specialization
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.to_string())
}
@ -776,6 +777,7 @@ impl ToString for TokenTree {
/// `TokenTree::Punct`, or `TokenTree::Literal`.
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
impl fmt::Display for TokenTree {
#[allow(clippy::recursive_format_impl)] // clippy doesn't see the specialization
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.to_string())
}
@ -906,6 +908,7 @@ impl ToString for Group {
/// with `Delimiter::None` delimiters.
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
impl fmt::Display for Group {
#[allow(clippy::recursive_format_impl)] // clippy doesn't see the specialization
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.to_string())
}

View file

@ -339,12 +339,14 @@
#![feature(portable_simd)]
#![feature(prelude_2024)]
#![feature(ptr_as_uninit)]
#![feature(ptr_mask)]
#![feature(slice_internals)]
#![feature(slice_ptr_get)]
#![feature(slice_range)]
#![feature(std_internals)]
#![feature(str_internals)]
#![feature(strict_provenance)]
#![feature(strict_provenance_atomic_ptr)]
// tidy-alphabetical-end
//
// Library features (alloc):

View file

@ -288,6 +288,7 @@ impl AsFd for fs::File {
#[stable(feature = "io_safety", since = "1.63.0")]
impl From<fs::File> for OwnedFd {
/// Takes ownership of a [`File`](fs::File)'s underlying file descriptor.
#[inline]
fn from(file: fs::File) -> OwnedFd {
file.into_inner().into_inner().into_inner()
@ -296,6 +297,8 @@ impl From<fs::File> for OwnedFd {
#[stable(feature = "io_safety", since = "1.63.0")]
impl From<OwnedFd> for fs::File {
/// Returns a [`File`](fs::File) that takes ownership of the given
/// file descriptor.
#[inline]
fn from(owned_fd: OwnedFd) -> Self {
Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned_fd)))
@ -312,6 +315,7 @@ impl AsFd for crate::net::TcpStream {
#[stable(feature = "io_safety", since = "1.63.0")]
impl From<crate::net::TcpStream> for OwnedFd {
/// Takes ownership of a [`TcpStream`](crate::net::TcpStream)'s socket file descriptor.
#[inline]
fn from(tcp_stream: crate::net::TcpStream) -> OwnedFd {
tcp_stream.into_inner().into_socket().into_inner().into_inner().into()
@ -338,6 +342,7 @@ impl AsFd for crate::net::TcpListener {
#[stable(feature = "io_safety", since = "1.63.0")]
impl From<crate::net::TcpListener> for OwnedFd {
/// Takes ownership of a [`TcpListener`](crate::net::TcpListener)'s socket file descriptor.
#[inline]
fn from(tcp_listener: crate::net::TcpListener) -> OwnedFd {
tcp_listener.into_inner().into_socket().into_inner().into_inner().into()
@ -364,6 +369,7 @@ impl AsFd for crate::net::UdpSocket {
#[stable(feature = "io_safety", since = "1.63.0")]
impl From<crate::net::UdpSocket> for OwnedFd {
/// Takes ownership of a [`UdpSocket`](crate::net::UdpSocket)'s file descriptor.
#[inline]
fn from(udp_socket: crate::net::UdpSocket) -> OwnedFd {
udp_socket.into_inner().into_socket().into_inner().into_inner().into()

View file

@ -1024,6 +1024,7 @@ impl AsFd for UnixDatagram {
#[stable(feature = "io_safety", since = "1.63.0")]
impl From<UnixDatagram> for OwnedFd {
/// Takes ownership of a [`UnixDatagram`]'s socket file descriptor.
#[inline]
fn from(unix_datagram: UnixDatagram) -> OwnedFd {
unsafe { OwnedFd::from_raw_fd(unix_datagram.into_raw_fd()) }

View file

@ -346,6 +346,7 @@ impl From<OwnedFd> for UnixListener {
#[stable(feature = "io_safety", since = "1.63.0")]
impl From<UnixListener> for OwnedFd {
/// Takes ownership of a [`UnixListener`]'s socket file descriptor.
#[inline]
fn from(listener: UnixListener) -> OwnedFd {
listener.0.into_inner().into_inner()

View file

@ -752,6 +752,7 @@ impl AsFd for UnixStream {
#[stable(feature = "io_safety", since = "1.63.0")]
impl From<UnixStream> for OwnedFd {
/// Takes ownership of a [`UnixStream`]'s socket file descriptor.
#[inline]
fn from(unix_stream: UnixStream) -> OwnedFd {
unsafe { OwnedFd::from_raw_fd(unix_stream.into_raw_fd()) }

View file

@ -362,6 +362,8 @@ impl FromRawFd for process::Stdio {
#[stable(feature = "io_safety", since = "1.63.0")]
impl From<OwnedFd> for process::Stdio {
/// Takes ownership of a file descriptor and returns a [`Stdio`](process::Stdio)
/// that can attach a stream to it.
#[inline]
fn from(fd: OwnedFd) -> process::Stdio {
let fd = sys::fd::FileDesc::from_inner(fd);
@ -428,6 +430,7 @@ impl AsFd for crate::process::ChildStdin {
#[stable(feature = "io_safety", since = "1.63.0")]
impl From<crate::process::ChildStdin> for OwnedFd {
/// Takes ownership of a [`ChildStdin`](crate::process::ChildStdin)'s file descriptor.
#[inline]
fn from(child_stdin: crate::process::ChildStdin) -> OwnedFd {
child_stdin.into_inner().into_inner().into_inner()
@ -458,6 +461,7 @@ impl AsFd for crate::process::ChildStdout {
#[stable(feature = "io_safety", since = "1.63.0")]
impl From<crate::process::ChildStdout> for OwnedFd {
/// Takes ownership of a [`ChildStdout`](crate::process::ChildStdout)'s file descriptor.
#[inline]
fn from(child_stdout: crate::process::ChildStdout) -> OwnedFd {
child_stdout.into_inner().into_inner().into_inner()
@ -488,6 +492,7 @@ impl AsFd for crate::process::ChildStderr {
#[stable(feature = "io_safety", since = "1.63.0")]
impl From<crate::process::ChildStderr> for OwnedFd {
/// Takes ownership of a [`ChildStderr`](crate::process::ChildStderr)'s file descriptor.
#[inline]
fn from(child_stderr: crate::process::ChildStderr) -> OwnedFd {
child_stderr.into_inner().into_inner().into_inner()

View file

@ -502,6 +502,7 @@ impl AsHandle for fs::File {
#[stable(feature = "io_safety", since = "1.63.0")]
impl From<fs::File> for OwnedHandle {
/// Takes ownership of a [`File`](fs::File)'s underlying file handle.
#[inline]
fn from(file: fs::File) -> OwnedHandle {
file.into_inner().into_inner().into_inner()
@ -510,6 +511,7 @@ impl From<fs::File> for OwnedHandle {
#[stable(feature = "io_safety", since = "1.63.0")]
impl From<OwnedHandle> for fs::File {
/// Returns a [`File`](fs::File) that takes ownership of the given handle.
#[inline]
fn from(owned: OwnedHandle) -> Self {
Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned)))
@ -574,6 +576,7 @@ impl AsHandle for crate::process::ChildStdin {
#[stable(feature = "io_safety", since = "1.63.0")]
impl From<crate::process::ChildStdin> for OwnedHandle {
/// Takes ownership of a [`ChildStdin`](crate::process::ChildStdin)'s file handle.
#[inline]
fn from(child_stdin: crate::process::ChildStdin) -> OwnedHandle {
unsafe { OwnedHandle::from_raw_handle(child_stdin.into_raw_handle()) }
@ -590,6 +593,7 @@ impl AsHandle for crate::process::ChildStdout {
#[stable(feature = "io_safety", since = "1.63.0")]
impl From<crate::process::ChildStdout> for OwnedHandle {
/// Takes ownership of a [`ChildStdout`](crate::process::ChildStdout)'s file handle.
#[inline]
fn from(child_stdout: crate::process::ChildStdout) -> OwnedHandle {
unsafe { OwnedHandle::from_raw_handle(child_stdout.into_raw_handle()) }
@ -606,6 +610,7 @@ impl AsHandle for crate::process::ChildStderr {
#[stable(feature = "io_safety", since = "1.63.0")]
impl From<crate::process::ChildStderr> for OwnedHandle {
/// Takes ownership of a [`ChildStderr`](crate::process::ChildStderr)'s file handle.
#[inline]
fn from(child_stderr: crate::process::ChildStderr) -> OwnedHandle {
unsafe { OwnedHandle::from_raw_handle(child_stderr.into_raw_handle()) }

View file

@ -319,6 +319,7 @@ impl AsSocket for crate::net::TcpStream {
#[stable(feature = "io_safety", since = "1.63.0")]
impl From<crate::net::TcpStream> for OwnedSocket {
/// Takes ownership of a [`TcpStream`](crate::net::TcpStream)'s socket.
#[inline]
fn from(tcp_stream: crate::net::TcpStream) -> OwnedSocket {
unsafe { OwnedSocket::from_raw_socket(tcp_stream.into_raw_socket()) }
@ -343,6 +344,7 @@ impl AsSocket for crate::net::TcpListener {
#[stable(feature = "io_safety", since = "1.63.0")]
impl From<crate::net::TcpListener> for OwnedSocket {
/// Takes ownership of a [`TcpListener`](crate::net::TcpListener)'s socket.
#[inline]
fn from(tcp_listener: crate::net::TcpListener) -> OwnedSocket {
unsafe { OwnedSocket::from_raw_socket(tcp_listener.into_raw_socket()) }
@ -367,6 +369,7 @@ impl AsSocket for crate::net::UdpSocket {
#[stable(feature = "io_safety", since = "1.63.0")]
impl From<crate::net::UdpSocket> for OwnedSocket {
/// Takes ownership of a [`UdpSocket`](crate::net::UdpSocket)'s underlying socket.
#[inline]
fn from(udp_socket: crate::net::UdpSocket) -> OwnedSocket {
unsafe { OwnedSocket::from_raw_socket(udp_socket.into_raw_socket()) }

View file

@ -24,6 +24,8 @@ impl FromRawHandle for process::Stdio {
#[stable(feature = "io_safety", since = "1.63.0")]
impl From<OwnedHandle> for process::Stdio {
/// Takes ownership of a handle and returns a [`Stdio`](process::Stdio)
/// that can attach a stream to it.
fn from(handle: OwnedHandle) -> process::Stdio {
let handle = sys::handle::Handle::from_inner(handle);
let io = sys::process::Stdio::Handle(handle);
@ -56,6 +58,7 @@ impl IntoRawHandle for process::Child {
#[stable(feature = "io_safety", since = "1.63.0")]
impl From<process::Child> for OwnedHandle {
/// Takes ownership of a [`Child`](process::Child)'s process handle.
fn from(child: process::Child) -> OwnedHandle {
child.into_inner().into_handle().into_inner()
}

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::*;
}
}

Some files were not shown because too many files have changed in this diff Show more