Merge from rustc
This commit is contained in:
commit
c41d5b12b8
620 changed files with 19617 additions and 5971 deletions
10
.github/workflows/ci.yml
vendored
10
.github/workflows/ci.yml
vendored
|
|
@ -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
|
||||
|
|
|
|||
97
Cargo.lock
97
Cargo.lock
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 =
|
||||
|
|
|
|||
|
|
@ -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:?}"));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
|
|||
|
|
@ -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 });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
_ => {}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:?}")
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 =>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
})
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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 => {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>>,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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| {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) => {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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(..)
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
//!
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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::*;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) => {
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()) }
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()) }
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()) }
|
||||
|
|
|
|||
|
|
@ -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()) }
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
88
library/std/src/sys/cmath.rs
Normal file
88
library/std/src/sys/cmath.rs
Normal 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
|
||||
}
|
||||
}}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue